@samuelbines/nunjucks 0.0.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +26 -0
- package/README.md +55 -0
- package/dist/scripts/smoke.d.ts +1 -0
- package/dist/scripts/smoke.js +95 -0
- package/dist/src/compiler.d.ts +12 -0
- package/dist/src/compiler.js +1050 -0
- package/dist/src/environment.d.ts +103 -0
- package/dist/src/environment.js +621 -0
- package/dist/src/express-app.d.ts +2 -0
- package/dist/src/express-app.js +33 -0
- package/dist/src/filters.d.ts +44 -0
- package/dist/src/filters.js +424 -0
- package/dist/src/globals.d.ts +14 -0
- package/dist/src/globals.js +342 -0
- package/dist/src/index.d.ts +28 -0
- package/dist/src/index.js +116 -0
- package/dist/src/interpreter.d.ts +16 -0
- package/dist/src/interpreter.js +489 -0
- package/dist/src/lexer.d.ts +72 -0
- package/dist/src/lexer.js +480 -0
- package/dist/src/lib.d.ts +74 -0
- package/dist/src/lib.js +237 -0
- package/dist/src/loader.d.ts +80 -0
- package/dist/src/loader.js +175 -0
- package/dist/src/nodes.d.ts +362 -0
- package/dist/src/nodes.js +894 -0
- package/dist/src/parser.d.ts +66 -0
- package/dist/src/parser.js +1068 -0
- package/dist/src/precompile.d.ts +15 -0
- package/dist/src/precompile.js +108 -0
- package/dist/src/runtime.d.ts +33 -0
- package/dist/src/runtime.js +314 -0
- package/dist/src/transformer.d.ts +3 -0
- package/dist/src/transformer.js +161 -0
- package/dist/src/types.d.ts +27 -0
- package/dist/src/types.js +2 -0
- package/dist/tests/compiler.test.d.ts +1 -0
- package/dist/tests/compiler.test.js +201 -0
- package/dist/tests/enviornment.test.d.ts +1 -0
- package/dist/tests/enviornment.test.js +279 -0
- package/dist/tests/express.test.d.ts +1 -0
- package/dist/tests/express.test.js +86 -0
- package/dist/tests/filters.test.d.ts +13 -0
- package/dist/tests/filters.test.js +286 -0
- package/dist/tests/globals.test.d.ts +1 -0
- package/dist/tests/globals.test.js +579 -0
- package/dist/tests/interpreter.test.d.ts +1 -0
- package/dist/tests/interpreter.test.js +208 -0
- package/dist/tests/lexer.test.d.ts +1 -0
- package/dist/tests/lexer.test.js +249 -0
- package/dist/tests/lib.test.d.ts +1 -0
- package/dist/tests/lib.test.js +236 -0
- package/dist/tests/loader.test.d.ts +1 -0
- package/dist/tests/loader.test.js +301 -0
- package/dist/tests/nodes.test.d.ts +1 -0
- package/dist/tests/nodes.test.js +137 -0
- package/dist/tests/parser.test.d.ts +1 -0
- package/dist/tests/parser.test.js +294 -0
- package/dist/tests/precompile.test.d.ts +1 -0
- package/dist/tests/precompile.test.js +224 -0
- package/dist/tests/runtime.test.d.ts +1 -0
- package/dist/tests/runtime.test.js +237 -0
- package/dist/tests/transformer.test.d.ts +1 -0
- package/dist/tests/transformer.test.js +125 -0
- package/dist/tsconfig.tsbuildinfo +1 -0
- package/package.json +59 -0
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { Environment, Template } from './environment';
|
|
2
|
+
type IPrecompileOpts = {
|
|
3
|
+
isString?: boolean;
|
|
4
|
+
isFunction?: boolean;
|
|
5
|
+
force?: boolean;
|
|
6
|
+
env?: Environment;
|
|
7
|
+
wrapper?: (templates: Template[], opts?: {
|
|
8
|
+
isFunction: boolean;
|
|
9
|
+
}) => string;
|
|
10
|
+
name?: string;
|
|
11
|
+
include?: string[];
|
|
12
|
+
exclude?: string[];
|
|
13
|
+
};
|
|
14
|
+
export declare function precompile(input: any, opts?: IPrecompileOpts): string;
|
|
15
|
+
export {};
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.precompile = precompile;
|
|
7
|
+
// DONE: Sat Jan 3
|
|
8
|
+
const fs_1 = __importDefault(require("fs"));
|
|
9
|
+
const path_1 = __importDefault(require("path"));
|
|
10
|
+
const lib_1 = require("./lib");
|
|
11
|
+
const compiler_1 = require("./compiler");
|
|
12
|
+
const environment_1 = require("./environment");
|
|
13
|
+
const globals_1 = require("./globals");
|
|
14
|
+
// Default
|
|
15
|
+
const initPrecompileOpts = {
|
|
16
|
+
isString: true,
|
|
17
|
+
isFunction: false,
|
|
18
|
+
force: false,
|
|
19
|
+
wrapper: globals_1.precompileGlobal,
|
|
20
|
+
env: new environment_1.Environment(),
|
|
21
|
+
exclude: [],
|
|
22
|
+
include: [],
|
|
23
|
+
};
|
|
24
|
+
function match(filename, patterns) {
|
|
25
|
+
if (!Array.isArray(patterns)) {
|
|
26
|
+
return false;
|
|
27
|
+
}
|
|
28
|
+
return patterns.some((pattern) => filename.match(pattern));
|
|
29
|
+
}
|
|
30
|
+
function _precompile(src, name, env = new environment_1.Environment()) {
|
|
31
|
+
const asyncFilters = env.asyncFilters;
|
|
32
|
+
const extensions = env.extensionsList;
|
|
33
|
+
let template;
|
|
34
|
+
name = name.replace(/\\/g, '/');
|
|
35
|
+
try {
|
|
36
|
+
template = (0, compiler_1.compile)(src, asyncFilters, extensions, name, {
|
|
37
|
+
throwOnUndefined: env.throwOnUndefined,
|
|
38
|
+
});
|
|
39
|
+
}
|
|
40
|
+
catch (err) {
|
|
41
|
+
lib_1.p.err('_precompile :', err);
|
|
42
|
+
throw (0, lib_1._prettifyError)(name, false, (0, lib_1.TemplateError)(err));
|
|
43
|
+
}
|
|
44
|
+
return {
|
|
45
|
+
name: name,
|
|
46
|
+
template: template,
|
|
47
|
+
};
|
|
48
|
+
}
|
|
49
|
+
function precompileString(str, opts) {
|
|
50
|
+
const _out = {
|
|
51
|
+
...initPrecompileOpts,
|
|
52
|
+
...opts,
|
|
53
|
+
};
|
|
54
|
+
if (!_precompile.name) {
|
|
55
|
+
throw new Error('the "name" option is required when compiling a string');
|
|
56
|
+
}
|
|
57
|
+
// @ts-ignore TODO: fix this
|
|
58
|
+
return _out?.wrapper([_precompile(str, opts.name, opts.env)], opts);
|
|
59
|
+
}
|
|
60
|
+
function precompile(input, opts) {
|
|
61
|
+
const env = opts?.env || new environment_1.Environment();
|
|
62
|
+
const wrapper = opts?.wrapper || globals_1.precompileGlobal;
|
|
63
|
+
if (opts?.isString) {
|
|
64
|
+
return precompileString(input, opts);
|
|
65
|
+
}
|
|
66
|
+
const pathStats = fs_1.default.statSync(input);
|
|
67
|
+
const precompiled = [];
|
|
68
|
+
const templates = [];
|
|
69
|
+
function addTemplates(dir) {
|
|
70
|
+
fs_1.default.readdirSync(dir).forEach((file) => {
|
|
71
|
+
const filepath = path_1.default.join(dir, file);
|
|
72
|
+
let subpath = filepath.substr(path_1.default.join(input, '/')?.length);
|
|
73
|
+
const stat = fs_1.default.statSync(filepath);
|
|
74
|
+
if (stat && stat.isDirectory()) {
|
|
75
|
+
subpath += '/';
|
|
76
|
+
if (!match(subpath, opts?.exclude)) {
|
|
77
|
+
addTemplates(filepath);
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
else if (match(subpath, opts?.include)) {
|
|
81
|
+
templates?.push(filepath);
|
|
82
|
+
}
|
|
83
|
+
});
|
|
84
|
+
}
|
|
85
|
+
if (pathStats.isFile()) {
|
|
86
|
+
precompiled?.push(_precompile(fs_1.default.readFileSync(input, 'utf-8'), opts.name || input, env));
|
|
87
|
+
}
|
|
88
|
+
else if (pathStats.isDirectory()) {
|
|
89
|
+
addTemplates(input);
|
|
90
|
+
for (let i = 0; i < templates?.length; i++) {
|
|
91
|
+
const name = templates[i].replace(path_1.default.join(input, '/'), '');
|
|
92
|
+
try {
|
|
93
|
+
precompiled?.push(_precompile(fs_1.default.readFileSync(templates[i], 'utf-8'), name, env));
|
|
94
|
+
}
|
|
95
|
+
catch (e) {
|
|
96
|
+
if (opts.force) {
|
|
97
|
+
// Don't stop generating the output if we're
|
|
98
|
+
// forcing compilation.
|
|
99
|
+
console.error(e); // eslint-disable-line no-console
|
|
100
|
+
}
|
|
101
|
+
else {
|
|
102
|
+
throw e;
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
return wrapper(precompiled, opts);
|
|
108
|
+
}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { Context } from './environment';
|
|
2
|
+
import { EscapeChar } from './lib';
|
|
3
|
+
import { Callback } from './types';
|
|
4
|
+
export declare class Frame {
|
|
5
|
+
parent: Frame | null;
|
|
6
|
+
isolateWrites: boolean;
|
|
7
|
+
topLevel: boolean;
|
|
8
|
+
variables: Record<string, any>;
|
|
9
|
+
constructor(parent?: Frame | null, isolateWrites?: boolean);
|
|
10
|
+
set(name: string, val: any, resolveUp?: boolean): void;
|
|
11
|
+
get(name: string): any;
|
|
12
|
+
lookup(name: string): Frame;
|
|
13
|
+
resolve(name: string, forWrite: boolean): Frame | null | undefined;
|
|
14
|
+
push(isolateWrites?: boolean): Frame;
|
|
15
|
+
pop(): Frame;
|
|
16
|
+
}
|
|
17
|
+
export declare function makeMacro(argNames: string[], kwargNames: string[], func: Function): (this: any, ...macroArgs: any[]) => any;
|
|
18
|
+
export declare function makeKeywordArgs(obj: any): any;
|
|
19
|
+
export declare const isKeywordArgs: (obj: object) => any;
|
|
20
|
+
export declare function getKeywordArgs(args: any[]): any;
|
|
21
|
+
export declare function numArgs(args: any[]): number;
|
|
22
|
+
export declare function copySafeness(dest: any, target: string): string;
|
|
23
|
+
export declare function markSafe(val: any): any;
|
|
24
|
+
export declare function suppressValue(val: EscapeChar, autoescape: boolean): string;
|
|
25
|
+
export declare function ensureDefined(val: any, lineno?: number, colno?: number): any;
|
|
26
|
+
export declare function memberLookup(obj: Record<string, any>, val: string, own?: boolean): any;
|
|
27
|
+
export declare function callWrap(obj: any, name: string, context: Context, args: any[]): any;
|
|
28
|
+
export declare function contextOrFrameLookup(context: Context, frame: Frame, name: string): any;
|
|
29
|
+
export declare function handleError(error: any, lineno?: number, colno?: number): any;
|
|
30
|
+
export declare function asyncEach(arr: any[], dimen: number, iter: Function, cb: Callback): void;
|
|
31
|
+
export declare function asyncAll(this: any, arr: any[], dimen: number, func: Function, cb: Callback): void;
|
|
32
|
+
export declare function fromIterator(arr: any[]): any[];
|
|
33
|
+
export declare function inOperator(key: string, val: any): boolean;
|
|
@@ -0,0 +1,314 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.isKeywordArgs = exports.Frame = void 0;
|
|
4
|
+
exports.makeMacro = makeMacro;
|
|
5
|
+
exports.makeKeywordArgs = makeKeywordArgs;
|
|
6
|
+
exports.getKeywordArgs = getKeywordArgs;
|
|
7
|
+
exports.numArgs = numArgs;
|
|
8
|
+
exports.copySafeness = copySafeness;
|
|
9
|
+
exports.markSafe = markSafe;
|
|
10
|
+
exports.suppressValue = suppressValue;
|
|
11
|
+
exports.ensureDefined = ensureDefined;
|
|
12
|
+
exports.memberLookup = memberLookup;
|
|
13
|
+
exports.callWrap = callWrap;
|
|
14
|
+
exports.contextOrFrameLookup = contextOrFrameLookup;
|
|
15
|
+
exports.handleError = handleError;
|
|
16
|
+
exports.asyncEach = asyncEach;
|
|
17
|
+
exports.asyncAll = asyncAll;
|
|
18
|
+
exports.fromIterator = fromIterator;
|
|
19
|
+
exports.inOperator = inOperator;
|
|
20
|
+
const lib_1 = require("./lib");
|
|
21
|
+
const supportsIterators = typeof Symbol === 'function' &&
|
|
22
|
+
Symbol.iterator &&
|
|
23
|
+
typeof Array.from === 'function';
|
|
24
|
+
// Frames keep track of scoping both at compile-time and run-time so
|
|
25
|
+
// we know how to access variables. Block tags can introduce special
|
|
26
|
+
// variables, for example.
|
|
27
|
+
class Frame {
|
|
28
|
+
parent;
|
|
29
|
+
isolateWrites;
|
|
30
|
+
topLevel = true;
|
|
31
|
+
variables;
|
|
32
|
+
constructor(parent = null, isolateWrites = false) {
|
|
33
|
+
this.parent = parent;
|
|
34
|
+
this.isolateWrites = isolateWrites;
|
|
35
|
+
this.variables = Object.create(null);
|
|
36
|
+
this.parent = parent;
|
|
37
|
+
this.topLevel = parent === null;
|
|
38
|
+
// if this is true, writes (set) should never propagate upwards past
|
|
39
|
+
// this frame to its parent (though reads may).
|
|
40
|
+
this.isolateWrites = isolateWrites;
|
|
41
|
+
}
|
|
42
|
+
set(name, val, resolveUp = false) {
|
|
43
|
+
// Allow variables with dots by automatically creating the
|
|
44
|
+
// nested structure
|
|
45
|
+
let parts = name.split('.');
|
|
46
|
+
let obj = this.variables;
|
|
47
|
+
let frame = this;
|
|
48
|
+
if (resolveUp) {
|
|
49
|
+
if (frame == this.resolve(parts[0], true)) {
|
|
50
|
+
frame.set(name, val);
|
|
51
|
+
return;
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
for (let i = 0; i < parts?.length - 1; i++) {
|
|
55
|
+
const id = parts[i];
|
|
56
|
+
if (!obj[id]) {
|
|
57
|
+
obj[id] = {};
|
|
58
|
+
}
|
|
59
|
+
obj = obj[id];
|
|
60
|
+
}
|
|
61
|
+
obj[parts[parts?.length - 1]] = val;
|
|
62
|
+
}
|
|
63
|
+
get(name) {
|
|
64
|
+
let val = this.variables[name];
|
|
65
|
+
if (val !== undefined) {
|
|
66
|
+
return val;
|
|
67
|
+
}
|
|
68
|
+
return null;
|
|
69
|
+
}
|
|
70
|
+
lookup(name) {
|
|
71
|
+
let pt = this.parent;
|
|
72
|
+
let val = this.variables[name];
|
|
73
|
+
lib_1.p.debug(pt, val, name, this.variables);
|
|
74
|
+
if (val !== undefined) {
|
|
75
|
+
return val;
|
|
76
|
+
}
|
|
77
|
+
return pt && pt.lookup(name);
|
|
78
|
+
}
|
|
79
|
+
resolve(name, forWrite) {
|
|
80
|
+
const p = forWrite && this.isolateWrites ? undefined : this.parent;
|
|
81
|
+
const val = this.variables[name];
|
|
82
|
+
if (!val) {
|
|
83
|
+
return this;
|
|
84
|
+
}
|
|
85
|
+
return p && p.resolve(name, forWrite);
|
|
86
|
+
}
|
|
87
|
+
push(isolateWrites = false) {
|
|
88
|
+
return new Frame(this, isolateWrites);
|
|
89
|
+
}
|
|
90
|
+
pop() {
|
|
91
|
+
return this.parent;
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
exports.Frame = Frame;
|
|
95
|
+
function makeMacro(argNames, kwargNames, func) {
|
|
96
|
+
return function macro(...macroArgs) {
|
|
97
|
+
var argCount = numArgs(macroArgs);
|
|
98
|
+
var args;
|
|
99
|
+
var kwargs = getKeywordArgs(macroArgs);
|
|
100
|
+
if (argCount > argNames?.length) {
|
|
101
|
+
args = macroArgs.slice(0, argNames?.length);
|
|
102
|
+
// Positional arguments that should be passed in as
|
|
103
|
+
// keyword arguments (essentially default values)
|
|
104
|
+
macroArgs.slice(args?.length, argCount).forEach((val, i) => {
|
|
105
|
+
if (i < kwargNames?.length) {
|
|
106
|
+
kwargs[kwargNames[i]] = val;
|
|
107
|
+
}
|
|
108
|
+
});
|
|
109
|
+
args?.push(kwargs);
|
|
110
|
+
}
|
|
111
|
+
else if (argCount < argNames?.length) {
|
|
112
|
+
args = macroArgs.slice(0, argCount);
|
|
113
|
+
for (let i = argCount; i < argNames?.length; i++) {
|
|
114
|
+
const arg = argNames[i];
|
|
115
|
+
// Keyword arguments that should be passed as
|
|
116
|
+
// positional arguments, i.e. the caller explicitly
|
|
117
|
+
// used the name of a positional arg
|
|
118
|
+
args?.push(kwargs[arg]);
|
|
119
|
+
delete kwargs[arg];
|
|
120
|
+
}
|
|
121
|
+
args?.push(kwargs);
|
|
122
|
+
}
|
|
123
|
+
else {
|
|
124
|
+
args = macroArgs;
|
|
125
|
+
}
|
|
126
|
+
return func.apply(this, args);
|
|
127
|
+
};
|
|
128
|
+
}
|
|
129
|
+
function makeKeywordArgs(obj) {
|
|
130
|
+
obj.__keywords = true;
|
|
131
|
+
return obj;
|
|
132
|
+
}
|
|
133
|
+
const isKeywordArgs = (obj) => obj && Object.prototype.hasOwnProperty.call(obj, '__keywords');
|
|
134
|
+
exports.isKeywordArgs = isKeywordArgs;
|
|
135
|
+
function getKeywordArgs(args) {
|
|
136
|
+
let len = args?.length;
|
|
137
|
+
if (len) {
|
|
138
|
+
const lastArg = args[len - 1];
|
|
139
|
+
if ((0, exports.isKeywordArgs)(lastArg)) {
|
|
140
|
+
return lastArg;
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
return {};
|
|
144
|
+
}
|
|
145
|
+
function numArgs(args) {
|
|
146
|
+
const len = args?.length;
|
|
147
|
+
if (len === 0)
|
|
148
|
+
return 0;
|
|
149
|
+
const lastArg = args[len - 1];
|
|
150
|
+
if ((0, exports.isKeywordArgs)(lastArg)) {
|
|
151
|
+
return len - 1;
|
|
152
|
+
}
|
|
153
|
+
return len;
|
|
154
|
+
}
|
|
155
|
+
function copySafeness(dest, target) {
|
|
156
|
+
if ((0, lib_1.isString)(dest)) {
|
|
157
|
+
return target;
|
|
158
|
+
}
|
|
159
|
+
return target.toString();
|
|
160
|
+
}
|
|
161
|
+
function markSafe(val) {
|
|
162
|
+
const type = typeof val;
|
|
163
|
+
if (type === 'string') {
|
|
164
|
+
return val.toString();
|
|
165
|
+
}
|
|
166
|
+
else if (type !== 'function') {
|
|
167
|
+
return val;
|
|
168
|
+
}
|
|
169
|
+
else {
|
|
170
|
+
return function wrapSafe(args) {
|
|
171
|
+
var ret = val.apply(this, arguments);
|
|
172
|
+
if (typeof ret === 'string') {
|
|
173
|
+
return ret.toString();
|
|
174
|
+
}
|
|
175
|
+
return ret;
|
|
176
|
+
};
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
function suppressValue(val, autoescape) {
|
|
180
|
+
if (autoescape) {
|
|
181
|
+
return (0, lib_1.escape)(val);
|
|
182
|
+
}
|
|
183
|
+
return val;
|
|
184
|
+
}
|
|
185
|
+
function ensureDefined(val, lineno = 0, colno = 0) {
|
|
186
|
+
if (val === null || val === undefined) {
|
|
187
|
+
lib_1.p.err('attempted to output null or undefined value');
|
|
188
|
+
throw (0, lib_1.TemplateError)('attempted to output null or undefined value', lineno + 1, colno + 1);
|
|
189
|
+
}
|
|
190
|
+
return val;
|
|
191
|
+
}
|
|
192
|
+
function memberLookup(obj, val, own = false) {
|
|
193
|
+
if (!obj)
|
|
194
|
+
return undefined;
|
|
195
|
+
if (typeof obj[val] === 'function') {
|
|
196
|
+
return (...args) => obj[val].apply(obj, args);
|
|
197
|
+
}
|
|
198
|
+
return obj[val];
|
|
199
|
+
}
|
|
200
|
+
function callWrap(obj, name, context, args) {
|
|
201
|
+
if (!obj) {
|
|
202
|
+
throw new Error('Unable to call `' + name + '`, which is undefined or falsey');
|
|
203
|
+
}
|
|
204
|
+
else if (typeof obj !== 'function') {
|
|
205
|
+
throw new Error('Unable to call `' + name + '`, which is not a function');
|
|
206
|
+
}
|
|
207
|
+
return obj.apply(context, args);
|
|
208
|
+
}
|
|
209
|
+
function contextOrFrameLookup(context, frame, name) {
|
|
210
|
+
let val = frame.lookup(name);
|
|
211
|
+
return val ? val : context.lookup(name);
|
|
212
|
+
}
|
|
213
|
+
function handleError(error, lineno = 0, colno = 0) {
|
|
214
|
+
if (error?.lineno)
|
|
215
|
+
return error;
|
|
216
|
+
return (0, lib_1.TemplateError)(error, lineno, colno);
|
|
217
|
+
}
|
|
218
|
+
function asyncEach(arr, dimen, iter, cb) {
|
|
219
|
+
if (Array.isArray(arr)) {
|
|
220
|
+
const len = arr?.length;
|
|
221
|
+
// TODO: confirm types here
|
|
222
|
+
(0, lib_1.asyncIter)(arr, function iterCallback(item, i, next) {
|
|
223
|
+
switch (dimen) {
|
|
224
|
+
case 1:
|
|
225
|
+
iter(item, i, len, next);
|
|
226
|
+
break;
|
|
227
|
+
case 2:
|
|
228
|
+
iter(item[0], item[1], i, len, next);
|
|
229
|
+
break;
|
|
230
|
+
case 3:
|
|
231
|
+
iter(item[0], item[1], item[2], i, len, next);
|
|
232
|
+
break;
|
|
233
|
+
default:
|
|
234
|
+
item?.push(i, len, next);
|
|
235
|
+
iter.apply(this, item);
|
|
236
|
+
}
|
|
237
|
+
}, cb);
|
|
238
|
+
}
|
|
239
|
+
else {
|
|
240
|
+
(0, lib_1.asyncFor)(arr, function iterCallback(key, val, i, len, next) {
|
|
241
|
+
iter(key, val, i, len, next);
|
|
242
|
+
}, cb);
|
|
243
|
+
}
|
|
244
|
+
}
|
|
245
|
+
function asyncAll(arr, dimen, func, cb) {
|
|
246
|
+
let finished = 0;
|
|
247
|
+
let len = 0;
|
|
248
|
+
let outputArr = [];
|
|
249
|
+
function done(i, output) {
|
|
250
|
+
finished++;
|
|
251
|
+
outputArr[i] = output;
|
|
252
|
+
if (finished === len) {
|
|
253
|
+
cb(null, outputArr.join(''));
|
|
254
|
+
}
|
|
255
|
+
}
|
|
256
|
+
if (Array.isArray(arr)) {
|
|
257
|
+
len = arr?.length;
|
|
258
|
+
outputArr = new Array(len);
|
|
259
|
+
if (len === 0) {
|
|
260
|
+
cb(null, '');
|
|
261
|
+
}
|
|
262
|
+
else {
|
|
263
|
+
for (let i = 0; i < arr?.length; i++) {
|
|
264
|
+
const item = arr[i];
|
|
265
|
+
switch (dimen) {
|
|
266
|
+
case 1:
|
|
267
|
+
func(item, i, len, done);
|
|
268
|
+
break;
|
|
269
|
+
case 2:
|
|
270
|
+
func(item[0], item[1], i, len, done);
|
|
271
|
+
break;
|
|
272
|
+
case 3:
|
|
273
|
+
func(item[0], item[1], item[2], i, len, done);
|
|
274
|
+
break;
|
|
275
|
+
default:
|
|
276
|
+
item?.push(i, len, done);
|
|
277
|
+
func.apply(this, item);
|
|
278
|
+
}
|
|
279
|
+
}
|
|
280
|
+
}
|
|
281
|
+
}
|
|
282
|
+
else {
|
|
283
|
+
const keys = Object.keys(arr || {});
|
|
284
|
+
len = keys?.length;
|
|
285
|
+
outputArr = new Array(len);
|
|
286
|
+
if (len === 0) {
|
|
287
|
+
cb(null, '');
|
|
288
|
+
}
|
|
289
|
+
else {
|
|
290
|
+
for (let i = 0; i < keys?.length; i++) {
|
|
291
|
+
const k = keys[i];
|
|
292
|
+
func(k, arr[k], i, len, done);
|
|
293
|
+
}
|
|
294
|
+
}
|
|
295
|
+
}
|
|
296
|
+
}
|
|
297
|
+
function fromIterator(arr) {
|
|
298
|
+
if (typeof arr !== 'object' || arr === null || Array.isArray(arr)) {
|
|
299
|
+
return arr;
|
|
300
|
+
}
|
|
301
|
+
else if (supportsIterators && Symbol.iterator in arr) {
|
|
302
|
+
return Array.from(arr);
|
|
303
|
+
}
|
|
304
|
+
return arr;
|
|
305
|
+
}
|
|
306
|
+
function inOperator(key, val) {
|
|
307
|
+
if (Array.isArray(val) || (0, lib_1.isString)(val)) {
|
|
308
|
+
return val.indexOf(key) !== -1;
|
|
309
|
+
}
|
|
310
|
+
else if ((0, lib_1.isObject)(val)) {
|
|
311
|
+
return key in val;
|
|
312
|
+
}
|
|
313
|
+
throw new Error('Cannot use "in" operator to search for "' + key + '" in unexpected types.');
|
|
314
|
+
}
|
|
@@ -0,0 +1,161 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.collectBlocks = collectBlocks;
|
|
4
|
+
exports.transform = transform;
|
|
5
|
+
// DONE: Sun 4th Jan 2026
|
|
6
|
+
const nodes_1 = require("./nodes");
|
|
7
|
+
let sym = 0;
|
|
8
|
+
const gensym = () => 'hole_' + sym++;
|
|
9
|
+
function mapCOW(arr, func) {
|
|
10
|
+
let res = null;
|
|
11
|
+
for (let i = 0; i < arr?.length; i++) {
|
|
12
|
+
const item = func(arr[i]);
|
|
13
|
+
if (item !== arr[i]) {
|
|
14
|
+
if (!res) {
|
|
15
|
+
res = arr.slice();
|
|
16
|
+
}
|
|
17
|
+
res[i] = item;
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
return res || arr;
|
|
21
|
+
}
|
|
22
|
+
function walk(ast, func, depthFirst = false) {
|
|
23
|
+
if (!(ast instanceof nodes_1.Node))
|
|
24
|
+
return ast;
|
|
25
|
+
let node = ast;
|
|
26
|
+
if (!depthFirst) {
|
|
27
|
+
const nodeT = func(node);
|
|
28
|
+
if (nodeT && nodeT !== node) {
|
|
29
|
+
return nodeT;
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
if (node instanceof nodes_1.NodeList) {
|
|
33
|
+
const children = mapCOW(node.children, (child) => walk(child, func, depthFirst));
|
|
34
|
+
if (children !== node.children) {
|
|
35
|
+
node = new ((0, nodes_1.NodeCreator)(node?.typename))(node.lineno, node?.colno, children);
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
else if (node instanceof nodes_1.CallExtension) {
|
|
39
|
+
const args = walk(node.args, func, depthFirst);
|
|
40
|
+
const contentArgs = mapCOW(node.contentArgs, (node) => walk(node, func, depthFirst));
|
|
41
|
+
if (args !== node.args || contentArgs !== node.contentArgs) {
|
|
42
|
+
node = new ((0, nodes_1.NodeCreator)(node?.typename))(node.lineno, node?.colno, node.extname, node.prop, args, contentArgs);
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
else {
|
|
46
|
+
const props = node.fields.map((field) => node[field]);
|
|
47
|
+
const propsT = mapCOW(props, (prop) => walk(prop, func, depthFirst));
|
|
48
|
+
if (propsT !== props) {
|
|
49
|
+
node = new ((0, nodes_1.NodeCreator)(node?.typename))(node.lineno, node?.colno);
|
|
50
|
+
propsT.forEach((prop, i) => {
|
|
51
|
+
node[node.fields[i]] = prop;
|
|
52
|
+
});
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
return depthFirst ? func(node) || node : node;
|
|
56
|
+
}
|
|
57
|
+
function collectBlocks(root) {
|
|
58
|
+
const blocks = [];
|
|
59
|
+
walk(root, (n) => {
|
|
60
|
+
if (n instanceof nodes_1.Block)
|
|
61
|
+
blocks.push(n);
|
|
62
|
+
});
|
|
63
|
+
return blocks;
|
|
64
|
+
}
|
|
65
|
+
function liftFilters(ast, asyncFilters = []) {
|
|
66
|
+
function _liftFilters(node, asyncFilters, key) {
|
|
67
|
+
const children = [];
|
|
68
|
+
const walked = walk(key ? node[key] : node, (descNode) => {
|
|
69
|
+
let symbol;
|
|
70
|
+
if (descNode instanceof nodes_1.Block) {
|
|
71
|
+
return descNode;
|
|
72
|
+
}
|
|
73
|
+
const isAsyncFilter = descNode instanceof nodes_1.Filter &&
|
|
74
|
+
asyncFilters.indexOf(descNode.name.value) !== -1;
|
|
75
|
+
if (isAsyncFilter || descNode instanceof nodes_1.CallExtensionAsync) {
|
|
76
|
+
symbol = new nodes_1.Symbol(descNode.lineno, descNode?.colno, gensym());
|
|
77
|
+
children?.push(new nodes_1.FilterAsync(descNode.lineno, descNode?.colno, descNode.name, descNode.args, symbol));
|
|
78
|
+
}
|
|
79
|
+
return symbol;
|
|
80
|
+
}, true);
|
|
81
|
+
if (key) {
|
|
82
|
+
node[key] = walked;
|
|
83
|
+
}
|
|
84
|
+
else {
|
|
85
|
+
node = walked;
|
|
86
|
+
}
|
|
87
|
+
if (children?.length) {
|
|
88
|
+
children?.push(node);
|
|
89
|
+
return new nodes_1.NodeList(node.lineno, node?.colno, children);
|
|
90
|
+
}
|
|
91
|
+
return node;
|
|
92
|
+
}
|
|
93
|
+
return walk(ast, (node) => {
|
|
94
|
+
if (node instanceof nodes_1.Output) {
|
|
95
|
+
return _liftFilters(node, asyncFilters);
|
|
96
|
+
}
|
|
97
|
+
else if (node instanceof Set) {
|
|
98
|
+
return _liftFilters(node, asyncFilters, 'value');
|
|
99
|
+
}
|
|
100
|
+
else if (node instanceof nodes_1.For) {
|
|
101
|
+
return _liftFilters(node, asyncFilters, 'arr');
|
|
102
|
+
}
|
|
103
|
+
else if (node instanceof nodes_1.If) {
|
|
104
|
+
return _liftFilters(node, asyncFilters, 'cond');
|
|
105
|
+
}
|
|
106
|
+
else if (node instanceof nodes_1.CallExtension) {
|
|
107
|
+
return _liftFilters(node, asyncFilters, 'args');
|
|
108
|
+
}
|
|
109
|
+
return undefined;
|
|
110
|
+
}, true);
|
|
111
|
+
}
|
|
112
|
+
function liftSuper(ast) {
|
|
113
|
+
return walk(ast, (block) => {
|
|
114
|
+
if (!(block instanceof nodes_1.Block))
|
|
115
|
+
return;
|
|
116
|
+
let hasSuper = false;
|
|
117
|
+
const symbol = gensym();
|
|
118
|
+
block.body = walk(block.body, (node) => {
|
|
119
|
+
if (node instanceof nodes_1.FunCall && node.name?.typename === 'Super') {
|
|
120
|
+
hasSuper = true;
|
|
121
|
+
return new nodes_1.Symbol(node.lineno, node?.colno, symbol);
|
|
122
|
+
}
|
|
123
|
+
});
|
|
124
|
+
if (hasSuper) {
|
|
125
|
+
block.body.children.unshift(new nodes_1.Super(0, 0, block.name, new nodes_1.Symbol(0, 0, symbol)));
|
|
126
|
+
}
|
|
127
|
+
});
|
|
128
|
+
return ast;
|
|
129
|
+
}
|
|
130
|
+
function convertStatements(ast) {
|
|
131
|
+
return walk(ast, (node) => {
|
|
132
|
+
if (!(node instanceof nodes_1.If) && !(node instanceof nodes_1.For)) {
|
|
133
|
+
return undefined;
|
|
134
|
+
}
|
|
135
|
+
let isAsync = false;
|
|
136
|
+
walk(node, (child) => {
|
|
137
|
+
if (child instanceof nodes_1.FilterAsync ||
|
|
138
|
+
child instanceof nodes_1.IfAsync ||
|
|
139
|
+
child instanceof nodes_1.AsyncEach ||
|
|
140
|
+
child instanceof nodes_1.AsyncAll ||
|
|
141
|
+
child instanceof nodes_1.CallExtensionAsync) {
|
|
142
|
+
isAsync = true;
|
|
143
|
+
// Stop iterating by returning the node
|
|
144
|
+
return child;
|
|
145
|
+
}
|
|
146
|
+
return undefined;
|
|
147
|
+
});
|
|
148
|
+
if (isAsync) {
|
|
149
|
+
if (node instanceof nodes_1.If) {
|
|
150
|
+
return new nodes_1.IfAsync(node.lineno, node?.colno, node.cond, node.body, node.else_);
|
|
151
|
+
}
|
|
152
|
+
else if (node instanceof nodes_1.For && !(node instanceof nodes_1.AsyncAll)) {
|
|
153
|
+
return new nodes_1.AsyncEach(node.lineno, node?.colno, node.arr, node.name, node.body, node.else_);
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
return undefined;
|
|
157
|
+
}, true);
|
|
158
|
+
}
|
|
159
|
+
function transform(ast, asyncFilters = []) {
|
|
160
|
+
return convertStatements(liftSuper(liftFilters(ast, asyncFilters)));
|
|
161
|
+
}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
export type Callback<E = unknown, R = unknown> = (err?: E | null, res?: R) => void;
|
|
2
|
+
type TokenType = string;
|
|
3
|
+
export interface Token {
|
|
4
|
+
type: TokenType;
|
|
5
|
+
value?: any;
|
|
6
|
+
lineno?: number;
|
|
7
|
+
colno?: number;
|
|
8
|
+
}
|
|
9
|
+
export interface TokenStream {
|
|
10
|
+
nextToken(): Token | null;
|
|
11
|
+
_extractRegex(re: RegExp): RegExpExecArray | null;
|
|
12
|
+
backN(n: number): void;
|
|
13
|
+
tags: {
|
|
14
|
+
VARIABLE_START: string;
|
|
15
|
+
VARIABLE_END: string;
|
|
16
|
+
BLOCK_START: string;
|
|
17
|
+
BLOCK_END: string;
|
|
18
|
+
COMMENT_START: string;
|
|
19
|
+
COMMENT_END: string;
|
|
20
|
+
};
|
|
21
|
+
}
|
|
22
|
+
export interface ParserExtension<P> {
|
|
23
|
+
tags?: string[];
|
|
24
|
+
parse(parser: P, nodes: typeof import('./nodes'), lexer: typeof import('./lexer')): Node;
|
|
25
|
+
preprocess?: (src: string) => string;
|
|
26
|
+
}
|
|
27
|
+
export {};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|