mirror of
https://github.com/harttle/liquidjs.git
synced 2026-09-18 05:50:43 -07:00
feat: static variable analysis (#770)
* feat: static variable analysis * Accept any iterable from `children`, `arguments`, etc. * Test analysis of standard tags * Use `TagToken.tokenizer` instead of creating a new one * Test analysis of netsted tags * Group variables by their root value * Test analysis of nested globals and locals * Analyze included and rendered templates WIP * Use existing tokenizer when constructing `Hash` * Improve test coverage * Analyze variables from `layout` and `block` tags * Test analysis of Jekyll style includes * Handle variables that start with a nested variable * Async analysis * Test non-standard tag end to end * Implement convenience analysis methods on the `Liquid` class * More analysis convenience methods * Accept string or template array * Draft static analysis docs * Deduplicate variables names * Fix isolated scope global variable map * Coerce variables to strings instead of extending String * Private map instead of extending Map * Fix e2e test * Tentatively implement analysis of aliased variables * Fix nested variable segments array * Update docs sidebar
This commit is contained in:
+90
-2
@@ -1,6 +1,6 @@
|
||||
import { Context } from './context'
|
||||
import { toPromise, toValueSync, isFunction, forOwn } from './util'
|
||||
import { TagClass, createTagClass, TagImplOptions, FilterImplOptions, Template, Value } from './template'
|
||||
import { toPromise, toValueSync, isFunction, forOwn, isString, strictUniq } from './util'
|
||||
import { TagClass, createTagClass, TagImplOptions, FilterImplOptions, Template, Value, StaticAnalysisOptions, StaticAnalysis, analyze, analyzeSync, SegmentArray } from './template'
|
||||
import { LookupType } from './fs/loader'
|
||||
import { Render } from './render'
|
||||
import { Parser } from './parser'
|
||||
@@ -122,4 +122,92 @@ export class Liquid {
|
||||
self.renderFile(filePath, ctx).then(html => callback(null, html) as any, callback as any)
|
||||
}
|
||||
}
|
||||
|
||||
public async analyze (template: Template[], options: StaticAnalysisOptions = {}): Promise<StaticAnalysis> {
|
||||
return analyze(template, options)
|
||||
}
|
||||
|
||||
public analyzeSync (template: Template[], options: StaticAnalysisOptions = {}): StaticAnalysis {
|
||||
return analyzeSync(template, options)
|
||||
}
|
||||
|
||||
public async parseAndAnalyze (html: string, filename?: string, options: StaticAnalysisOptions = {}): Promise<StaticAnalysis> {
|
||||
return analyze(this.parse(html, filename), options)
|
||||
}
|
||||
|
||||
public parseAndAnalyzeSync (html: string, filename?: string, options: StaticAnalysisOptions = {}): StaticAnalysis {
|
||||
return analyzeSync(this.parse(html, filename), options)
|
||||
}
|
||||
|
||||
/** Return an array of all variables without their properties. */
|
||||
public async variables (template: string | Template[], options: StaticAnalysisOptions = {}): Promise<string[]> {
|
||||
const analysis = await analyze(isString(template) ? this.parse(template) : template, options)
|
||||
return Object.keys(analysis.variables)
|
||||
}
|
||||
|
||||
/** Return an array of all variables without their properties. */
|
||||
public variablesSync (template: string | Template[], options: StaticAnalysisOptions = {}): string[] {
|
||||
const analysis = analyzeSync(isString(template) ? this.parse(template) : template, options)
|
||||
return Object.keys(analysis.variables)
|
||||
}
|
||||
|
||||
/** Return an array of all variables including their properties/paths. */
|
||||
public async fullVariables (template: string | Template[], options: StaticAnalysisOptions = {}): Promise<string[]> {
|
||||
const analysis = await analyze(isString(template) ? this.parse(template) : template, options)
|
||||
return Array.from(new Set(Object.values(analysis.variables).flatMap((a) => a.map((v) => String(v)))))
|
||||
}
|
||||
|
||||
/** Return an array of all variables including their properties/paths. */
|
||||
public fullVariablesSync (template: string | Template[], options: StaticAnalysisOptions = {}): string[] {
|
||||
const analysis = analyzeSync(isString(template) ? this.parse(template) : template, options)
|
||||
return Array.from(new Set(Object.values(analysis.variables).flatMap((a) => a.map((v) => String(v)))))
|
||||
}
|
||||
|
||||
/** Return an array of all variables, each as an array of properties/segments. */
|
||||
public async variableSegments (template: string | Template[], options: StaticAnalysisOptions = {}): Promise<Array<SegmentArray>> {
|
||||
const analysis = await analyze(isString(template) ? this.parse(template) : template, options)
|
||||
return Array.from(strictUniq(Object.values(analysis.variables).flatMap((a) => a.map((v) => v.toArray()))))
|
||||
}
|
||||
|
||||
/** Return an array of all variables, each as an array of properties/segments. */
|
||||
public variableSegmentsSync (template: string | Template[], options: StaticAnalysisOptions = {}): Array<SegmentArray> {
|
||||
const analysis = analyzeSync(isString(template) ? this.parse(template) : template, options)
|
||||
return Array.from(strictUniq(Object.values(analysis.variables).flatMap((a) => a.map((v) => v.toArray()))))
|
||||
}
|
||||
|
||||
/** Return an array of all expected context variables without their properties. */
|
||||
public async globalVariables (template: string | Template[], options: StaticAnalysisOptions = {}): Promise<string[]> {
|
||||
const analysis = await analyze(isString(template) ? this.parse(template) : template, options)
|
||||
return Object.keys(analysis.globals)
|
||||
}
|
||||
|
||||
/** Return an array of all expected context variables without their properties. */
|
||||
public globalVariablesSync (template: string | Template[], options: StaticAnalysisOptions = {}): string[] {
|
||||
const analysis = analyzeSync(isString(template) ? this.parse(template) : template, options)
|
||||
return Object.keys(analysis.globals)
|
||||
}
|
||||
|
||||
/** Return an array of all expected context variables including their properties/paths. */
|
||||
public async globalFullVariables (template: string | Template[], options: StaticAnalysisOptions = {}): Promise<string[]> {
|
||||
const analysis = await analyze(isString(template) ? this.parse(template) : template, options)
|
||||
return Array.from(new Set(Object.values(analysis.globals).flatMap((a) => a.map((v) => String(v)))))
|
||||
}
|
||||
|
||||
/** Return an array of all expected context variables including their properties/paths. */
|
||||
public globalFullVariablesSync (template: string | Template[], options: StaticAnalysisOptions = {}): string[] {
|
||||
const analysis = analyzeSync(isString(template) ? this.parse(template) : template, options)
|
||||
return Array.from(new Set(Object.values(analysis.globals).flatMap((a) => a.map((v) => String(v)))))
|
||||
}
|
||||
|
||||
/** Return an array of all expected context variables, each as an array of properties/segments. */
|
||||
public async globalVariableSegments (template: string | Template[], options: StaticAnalysisOptions = {}): Promise<Array<SegmentArray>> {
|
||||
const analysis = await analyze(isString(template) ? this.parse(template) : template, options)
|
||||
return Array.from(strictUniq(Object.values(analysis.globals).flatMap((a) => a.map((v) => v.toArray()))))
|
||||
}
|
||||
|
||||
/** Return an array of all expected context variables, each as an array of properties/segments. */
|
||||
public globalVariableSegmentsSync (template: string | Template[], options: StaticAnalysisOptions = {}): Array<SegmentArray> {
|
||||
const analysis = analyzeSync(isString(template) ? this.parse(template) : template, options)
|
||||
return Array.from(strictUniq(Object.values(analysis.globals).flatMap((a) => a.map((v) => v.toArray()))))
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user