@samuelbines/nunjucks 0.0.3 → 0.0.4
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/package.json +1 -1
- package/dist/tests/compiler.test.d.ts +0 -1
- package/dist/tests/compiler.test.js +0 -201
- package/dist/tests/enviornment.test.d.ts +0 -1
- package/dist/tests/enviornment.test.js +0 -279
- package/dist/tests/express.test.d.ts +0 -1
- package/dist/tests/express.test.js +0 -86
- package/dist/tests/filters.test.d.ts +0 -13
- package/dist/tests/filters.test.js +0 -286
- package/dist/tests/globals.test.d.ts +0 -1
- package/dist/tests/globals.test.js +0 -579
- package/dist/tests/interpreter.test.d.ts +0 -1
- package/dist/tests/interpreter.test.js +0 -208
- package/dist/tests/lexer.test.d.ts +0 -1
- package/dist/tests/lexer.test.js +0 -249
- package/dist/tests/lib.test.d.ts +0 -1
- package/dist/tests/lib.test.js +0 -236
- package/dist/tests/loader.test.d.ts +0 -1
- package/dist/tests/loader.test.js +0 -301
- package/dist/tests/nodes.test.d.ts +0 -1
- package/dist/tests/nodes.test.js +0 -137
- package/dist/tests/parser.test.d.ts +0 -1
- package/dist/tests/parser.test.js +0 -294
- package/dist/tests/precompile.test.d.ts +0 -1
- package/dist/tests/precompile.test.js +0 -224
- package/dist/tests/runtime.test.d.ts +0 -1
- package/dist/tests/runtime.test.js +0 -237
- package/dist/tests/transformer.test.d.ts +0 -1
- package/dist/tests/transformer.test.js +0 -125
|
@@ -1,579 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
const vitest_1 = require("vitest");
|
|
4
|
-
const globals_1 = require("../src/globals");
|
|
5
|
-
(0, vitest_1.describe)('globals()', () => {
|
|
6
|
-
(0, vitest_1.it)('returns a fresh object each call (no shared state)', () => {
|
|
7
|
-
const g1 = (0, globals_1.globals)();
|
|
8
|
-
const g2 = (0, globals_1.globals)();
|
|
9
|
-
(0, vitest_1.expect)(g1).not.toBe(g2);
|
|
10
|
-
(0, vitest_1.expect)(g1.range).not.toBe(g2.range); // methods are new per object literal
|
|
11
|
-
});
|
|
12
|
-
(0, vitest_1.describe)('range()', () => {
|
|
13
|
-
(0, vitest_1.it)('creates a range from 0..stop-1 when called with one arg', () => {
|
|
14
|
-
const { range } = (0, globals_1.globals)();
|
|
15
|
-
// TS signature says stop is required, but runtime supports one-arg call
|
|
16
|
-
(0, vitest_1.expect)(range(5)).toEqual([0, 1, 2, 3, 4]);
|
|
17
|
-
});
|
|
18
|
-
(0, vitest_1.it)('creates a range from start..stop-1 with positive step', () => {
|
|
19
|
-
const { range } = (0, globals_1.globals)();
|
|
20
|
-
(0, vitest_1.expect)(range(2, 7, 2)).toEqual([2, 4, 6]);
|
|
21
|
-
(0, vitest_1.expect)(range(2, 3, 1)).toEqual([2]);
|
|
22
|
-
(0, vitest_1.expect)(range(2, 2, 1)).toEqual([]);
|
|
23
|
-
});
|
|
24
|
-
(0, vitest_1.it)('creates a descending range when step is negative', () => {
|
|
25
|
-
const { range } = (0, globals_1.globals)();
|
|
26
|
-
(0, vitest_1.expect)(range(5, 0, -2)).toEqual([5, 3, 1]);
|
|
27
|
-
(0, vitest_1.expect)(range(5, 5, -1)).toEqual([]);
|
|
28
|
-
});
|
|
29
|
-
(0, vitest_1.it)('defaults step to 1 if not provided (2-arg call)', () => {
|
|
30
|
-
const { range } = (0, globals_1.globals)();
|
|
31
|
-
(0, vitest_1.expect)(range(3, 6)).toEqual([3, 4, 5]);
|
|
32
|
-
});
|
|
33
|
-
});
|
|
34
|
-
(0, vitest_1.describe)('cycler()', () => {
|
|
35
|
-
(0, vitest_1.it)('cycles through items and updates current', () => {
|
|
36
|
-
const { cycler } = (0, globals_1.globals)();
|
|
37
|
-
const c = cycler('a', 'b', 'c');
|
|
38
|
-
(0, vitest_1.expect)(c.current).toBeNull();
|
|
39
|
-
(0, vitest_1.expect)(c.next()).toBe('a');
|
|
40
|
-
(0, vitest_1.expect)(c.current).toBe('a');
|
|
41
|
-
(0, vitest_1.expect)(c.next()).toBe('b');
|
|
42
|
-
(0, vitest_1.expect)(c.current).toBe('b');
|
|
43
|
-
(0, vitest_1.expect)(c.next()).toBe('c');
|
|
44
|
-
(0, vitest_1.expect)(c.current).toBe('c');
|
|
45
|
-
// wraps
|
|
46
|
-
(0, vitest_1.expect)(c.next()).toBe('a');
|
|
47
|
-
(0, vitest_1.expect)(c.current).toBe('a');
|
|
48
|
-
});
|
|
49
|
-
(0, vitest_1.it)('reset() clears state', () => {
|
|
50
|
-
const { cycler } = (0, globals_1.globals)();
|
|
51
|
-
const c = cycler(1, 2);
|
|
52
|
-
c.next();
|
|
53
|
-
(0, vitest_1.expect)(c.current).toBe(1);
|
|
54
|
-
c.reset();
|
|
55
|
-
(0, vitest_1.expect)(c.current).toBeNull();
|
|
56
|
-
(0, vitest_1.expect)(c.next()).toBe(1);
|
|
57
|
-
(0, vitest_1.expect)(c.current).toBe(1);
|
|
58
|
-
});
|
|
59
|
-
(0, vitest_1.it)('empty cycler always returns null and current stays null', () => {
|
|
60
|
-
const { cycler } = (0, globals_1.globals)();
|
|
61
|
-
const c = cycler();
|
|
62
|
-
(0, vitest_1.expect)(c.current).toBeNull();
|
|
63
|
-
(0, vitest_1.expect)(c.next()).toBeNull();
|
|
64
|
-
(0, vitest_1.expect)(c.next()).toBeNull();
|
|
65
|
-
(0, vitest_1.expect)(c.current).toBeNull();
|
|
66
|
-
});
|
|
67
|
-
(0, vitest_1.it)('each cycler instance has independent state', () => {
|
|
68
|
-
const { cycler } = (0, globals_1.globals)();
|
|
69
|
-
const a = cycler('x', 'y');
|
|
70
|
-
const b = cycler('x', 'y');
|
|
71
|
-
(0, vitest_1.expect)(a.next()).toBe('x');
|
|
72
|
-
(0, vitest_1.expect)(a.current).toBe('x');
|
|
73
|
-
(0, vitest_1.expect)(b.current).toBeNull();
|
|
74
|
-
(0, vitest_1.expect)(b.next()).toBe('x');
|
|
75
|
-
(0, vitest_1.expect)(b.current).toBe('x');
|
|
76
|
-
(0, vitest_1.expect)(a.next()).toBe('y');
|
|
77
|
-
(0, vitest_1.expect)(b.next()).toBe('y');
|
|
78
|
-
});
|
|
79
|
-
});
|
|
80
|
-
(0, vitest_1.describe)('joiner()', () => {
|
|
81
|
-
(0, vitest_1.it)("returns '' the first time, then the separator afterwards", () => {
|
|
82
|
-
const { joiner } = (0, globals_1.globals)();
|
|
83
|
-
const j = joiner(',');
|
|
84
|
-
(0, vitest_1.expect)(j()).toBe('');
|
|
85
|
-
(0, vitest_1.expect)(j()).toBe(',');
|
|
86
|
-
(0, vitest_1.expect)(j()).toBe(',');
|
|
87
|
-
});
|
|
88
|
-
(0, vitest_1.it)("defaults separator to ','", () => {
|
|
89
|
-
const { joiner } = (0, globals_1.globals)();
|
|
90
|
-
const j = joiner();
|
|
91
|
-
(0, vitest_1.expect)(j()).toBe('');
|
|
92
|
-
(0, vitest_1.expect)(j()).toBe(',');
|
|
93
|
-
});
|
|
94
|
-
(0, vitest_1.it)('each joiner has independent state', () => {
|
|
95
|
-
const { joiner } = (0, globals_1.globals)();
|
|
96
|
-
const a = joiner('-');
|
|
97
|
-
const b = joiner('-');
|
|
98
|
-
(0, vitest_1.expect)(a()).toBe('');
|
|
99
|
-
(0, vitest_1.expect)(a()).toBe('-');
|
|
100
|
-
(0, vitest_1.expect)(b()).toBe('');
|
|
101
|
-
(0, vitest_1.expect)(b()).toBe('-');
|
|
102
|
-
});
|
|
103
|
-
});
|
|
104
|
-
});
|
|
105
|
-
(0, vitest_1.describe)('precompileGlobal()', () => {
|
|
106
|
-
(0, vitest_1.it)('produces a string that registers templates on window.nunjucksPrecompiled', () => {
|
|
107
|
-
const out = (0, globals_1.precompileGlobal)([
|
|
108
|
-
{ name: 'a.njk', template: 'return { root: function(){} }' },
|
|
109
|
-
{ name: 'b.njk', template: 'return { root: function(){} }' },
|
|
110
|
-
]);
|
|
111
|
-
(0, vitest_1.expect)(typeof out).toBe('string');
|
|
112
|
-
// basic structure checks
|
|
113
|
-
(0, vitest_1.expect)(out).toContain('window.nunjucksPrecompiled');
|
|
114
|
-
(0, vitest_1.expect)(out).toContain('["a.njk"]');
|
|
115
|
-
(0, vitest_1.expect)(out).toContain('["b.njk"]');
|
|
116
|
-
(0, vitest_1.expect)(out).toContain('(function()');
|
|
117
|
-
(0, vitest_1.expect)(out).toContain('})();');
|
|
118
|
-
});
|
|
119
|
-
(0, vitest_1.it)('embeds the template source and invokes it via an IIFE', () => {
|
|
120
|
-
const tpl = "return { root: function(){ return 'ok' } }";
|
|
121
|
-
const out = (0, globals_1.precompileGlobal)([{ name: 'x', template: tpl }]);
|
|
122
|
-
(0, vitest_1.expect)(out).toContain(tpl);
|
|
123
|
-
(0, vitest_1.expect)(out).toContain('] = (function() {');
|
|
124
|
-
(0, vitest_1.expect)(out).toContain('\n})();\n'); // template IIFE close
|
|
125
|
-
});
|
|
126
|
-
(0, vitest_1.it)('includes a render wrapper when opts.isFunction is true', () => {
|
|
127
|
-
const out = (0, globals_1.precompileGlobal)([{ name: 'x', template: 'return { root: function(){} }' }], { isFunction: true });
|
|
128
|
-
(0, vitest_1.expect)(out).toContain('return function(ctx, cb)');
|
|
129
|
-
(0, vitest_1.expect)(out).toContain('nunjucks.render(');
|
|
130
|
-
(0, vitest_1.expect)(out).toContain('"x"');
|
|
131
|
-
});
|
|
132
|
-
(0, vitest_1.it)('does not include the render wrapper when opts.isFunction is false/omitted', () => {
|
|
133
|
-
const out1 = (0, globals_1.precompileGlobal)([{ name: 'x', template: 'return {}' }]);
|
|
134
|
-
const out2 = (0, globals_1.precompileGlobal)([{ name: 'x', template: 'return {}' }], {
|
|
135
|
-
isFunction: false,
|
|
136
|
-
});
|
|
137
|
-
(0, vitest_1.expect)(out1).not.toContain('return function(ctx, cb)');
|
|
138
|
-
(0, vitest_1.expect)(out2).not.toContain('return function(ctx, cb)');
|
|
139
|
-
});
|
|
140
|
-
(0, vitest_1.it)('JSON stringifies template names (handles quotes safely)', () => {
|
|
141
|
-
const name = 'weird"name';
|
|
142
|
-
const out = (0, globals_1.precompileGlobal)([{ name, template: 'return {}' }]);
|
|
143
|
-
// JSON.stringify adds escaping
|
|
144
|
-
(0, vitest_1.expect)(out).toContain(JSON.stringify(name));
|
|
145
|
-
});
|
|
146
|
-
});
|
|
147
|
-
function makeThisEnv(overrides) {
|
|
148
|
-
const runtime = {
|
|
149
|
-
contextOrFrameLookup: vitest_1.vi.fn((_ctx, _frame, key) => {
|
|
150
|
-
// simulate "not found" by default
|
|
151
|
-
if (key === 'existing')
|
|
152
|
-
return 123;
|
|
153
|
-
return undefined;
|
|
154
|
-
}),
|
|
155
|
-
memberLookup: vitest_1.vi.fn((obj, val) => {
|
|
156
|
-
// default behavior: just property access (like a basic runtime)
|
|
157
|
-
return obj?.[val];
|
|
158
|
-
}),
|
|
159
|
-
};
|
|
160
|
-
const lib = {
|
|
161
|
-
isObject: (o) => o !== null && typeof o === 'object' && !Array.isArray(o),
|
|
162
|
-
keys: (o) => Object.keys(o),
|
|
163
|
-
};
|
|
164
|
-
// "slim" mode by default for tests unless explicitly enabled
|
|
165
|
-
const base = {
|
|
166
|
-
runtime,
|
|
167
|
-
lib,
|
|
168
|
-
compiler: { Compiler: undefined },
|
|
169
|
-
parser: { Parser: undefined },
|
|
170
|
-
nodes: undefined,
|
|
171
|
-
lexer: {
|
|
172
|
-
TOKEN_LEFT_BRACKET: 'left-bracket',
|
|
173
|
-
TOKEN_RIGHT_BRACKET: 'right-bracket',
|
|
174
|
-
TOKEN_COLON: 'colon',
|
|
175
|
-
},
|
|
176
|
-
};
|
|
177
|
-
return Object.assign(base, overrides ?? {});
|
|
178
|
-
}
|
|
179
|
-
(0, vitest_1.describe)('installCompat', () => {
|
|
180
|
-
const ORIGINAL_BUILD_TYPE = process.env.BUILD_TYPE;
|
|
181
|
-
(0, vitest_1.afterEach)(() => {
|
|
182
|
-
process.env.BUILD_TYPE = ORIGINAL_BUILD_TYPE;
|
|
183
|
-
});
|
|
184
|
-
(0, vitest_1.it)('patches runtime.contextOrFrameLookup to support True/False/None when original returns undefined', () => {
|
|
185
|
-
const env = makeThisEnv();
|
|
186
|
-
const uninstall = globals_1.installCompat.call(env, { lib: env.lib });
|
|
187
|
-
(0, vitest_1.expect)(env.runtime.contextOrFrameLookup({}, {}, 'existing')).toBe(123);
|
|
188
|
-
(0, vitest_1.expect)(env.runtime.contextOrFrameLookup({}, {}, 'True')).toBe(true);
|
|
189
|
-
(0, vitest_1.expect)(env.runtime.contextOrFrameLookup({}, {}, 'False')).toBe(false);
|
|
190
|
-
(0, vitest_1.expect)(env.runtime.contextOrFrameLookup({}, {}, 'None')).toBe(null);
|
|
191
|
-
// unknown stays undefined
|
|
192
|
-
(0, vitest_1.expect)(env.runtime.contextOrFrameLookup({}, {}, 'whatever')).toBe(undefined);
|
|
193
|
-
uninstall();
|
|
194
|
-
// original restored
|
|
195
|
-
(0, vitest_1.expect)(env.runtime.contextOrFrameLookup).toBe(env.runtime.contextOrFrameLookup);
|
|
196
|
-
});
|
|
197
|
-
(0, vitest_1.it)('returns an uninstall function that restores original runtime hooks', () => {
|
|
198
|
-
const env = makeThisEnv();
|
|
199
|
-
const origLookup = env.runtime.contextOrFrameLookup;
|
|
200
|
-
const origMember = env.runtime.memberLookup;
|
|
201
|
-
const uninstall = globals_1.installCompat.call(env, { lib: env.lib });
|
|
202
|
-
(0, vitest_1.expect)(env.runtime.contextOrFrameLookup).not.toBe(origLookup);
|
|
203
|
-
(0, vitest_1.expect)(env.runtime.memberLookup).not.toBe(origMember);
|
|
204
|
-
uninstall();
|
|
205
|
-
(0, vitest_1.expect)(env.runtime.contextOrFrameLookup).toBe(origLookup);
|
|
206
|
-
(0, vitest_1.expect)(env.runtime.memberLookup).toBe(origMember);
|
|
207
|
-
});
|
|
208
|
-
(0, vitest_1.describe)('memberLookup: array python-ish members', () => {
|
|
209
|
-
let env;
|
|
210
|
-
let uninstall;
|
|
211
|
-
(0, vitest_1.beforeEach)(() => {
|
|
212
|
-
env = makeThisEnv();
|
|
213
|
-
uninstall = globals_1.installCompat.call(env, { lib: env.lib });
|
|
214
|
-
});
|
|
215
|
-
(0, vitest_1.afterEach)(() => uninstall());
|
|
216
|
-
(0, vitest_1.it)('array.append pushes and returns new length', () => {
|
|
217
|
-
const arr = [1, 2];
|
|
218
|
-
const append = env.runtime.memberLookup(arr, 'append', false);
|
|
219
|
-
(0, vitest_1.expect)(typeof append).toBe('function');
|
|
220
|
-
const out = append(3);
|
|
221
|
-
(0, vitest_1.expect)(out).toBe(3);
|
|
222
|
-
(0, vitest_1.expect)(arr).toEqual([1, 2, 3]);
|
|
223
|
-
});
|
|
224
|
-
(0, vitest_1.it)('array.pop() without index pops last', () => {
|
|
225
|
-
const arr = [1, 2, 3];
|
|
226
|
-
const pop = env.runtime.memberLookup(arr, 'pop', false);
|
|
227
|
-
(0, vitest_1.expect)(pop()).toBe(3);
|
|
228
|
-
(0, vitest_1.expect)(arr).toEqual([1, 2]);
|
|
229
|
-
});
|
|
230
|
-
(0, vitest_1.it)('array.pop(index) removes element at index and returns removed array (splice)', () => {
|
|
231
|
-
const arr = [10, 20, 30];
|
|
232
|
-
const pop = env.runtime.memberLookup(arr, 'pop', false);
|
|
233
|
-
(0, vitest_1.expect)(pop(1)).toEqual([20]);
|
|
234
|
-
(0, vitest_1.expect)(arr).toEqual([10, 30]);
|
|
235
|
-
});
|
|
236
|
-
(0, vitest_1.it)('array.pop(index) throws KeyError when out of bounds', () => {
|
|
237
|
-
const arr = [1];
|
|
238
|
-
const pop = env.runtime.memberLookup(arr, 'pop', false);
|
|
239
|
-
(0, vitest_1.expect)(() => pop(99)).toThrow(/KeyError/);
|
|
240
|
-
(0, vitest_1.expect)(() => pop(-1)).toThrow(/KeyError/);
|
|
241
|
-
});
|
|
242
|
-
(0, vitest_1.it)('array.remove(element) removes first match else throws ValueError', () => {
|
|
243
|
-
const arr = [1, 2, 2, 3];
|
|
244
|
-
const remove = env.runtime.memberLookup(arr, 'remove', false);
|
|
245
|
-
(0, vitest_1.expect)(remove(2)).toEqual([2]);
|
|
246
|
-
(0, vitest_1.expect)(arr).toEqual([1, 2, 3]);
|
|
247
|
-
(0, vitest_1.expect)(() => remove(999)).toThrow(/ValueError/);
|
|
248
|
-
});
|
|
249
|
-
(0, vitest_1.it)('array.count(element) returns occurrences', () => {
|
|
250
|
-
const arr = [1, 2, 2, 3];
|
|
251
|
-
const count = env.runtime.memberLookup(arr, 'count', false);
|
|
252
|
-
(0, vitest_1.expect)(count(2)).toBe(2);
|
|
253
|
-
(0, vitest_1.expect)(count(9)).toBe(0);
|
|
254
|
-
});
|
|
255
|
-
(0, vitest_1.it)('array.index(element) returns first index else throws ValueError', () => {
|
|
256
|
-
const arr = ['a', 'b'];
|
|
257
|
-
const index = env.runtime.memberLookup(arr, 'index', false);
|
|
258
|
-
(0, vitest_1.expect)(index('b')).toBe(1);
|
|
259
|
-
(0, vitest_1.expect)(() => index('x')).toThrow(/ValueError/);
|
|
260
|
-
});
|
|
261
|
-
(0, vitest_1.it)('array.find(element) returns index or -1', () => {
|
|
262
|
-
const arr = ['a', 'b'];
|
|
263
|
-
const find = env.runtime.memberLookup(arr, 'find', false);
|
|
264
|
-
(0, vitest_1.expect)(find('b')).toBe(1);
|
|
265
|
-
(0, vitest_1.expect)(find('x')).toBe(-1);
|
|
266
|
-
});
|
|
267
|
-
(0, vitest_1.it)('array.insert(index, elem) splices and returns []', () => {
|
|
268
|
-
const arr = [1, 3];
|
|
269
|
-
const insert = env.runtime.memberLookup(arr, 'insert', false);
|
|
270
|
-
(0, vitest_1.expect)(insert(1, 2)).toEqual([]);
|
|
271
|
-
(0, vitest_1.expect)(arr).toEqual([1, 2, 3]);
|
|
272
|
-
});
|
|
273
|
-
});
|
|
274
|
-
(0, vitest_1.describe)('memberLookup: object python-ish members', () => {
|
|
275
|
-
let env;
|
|
276
|
-
let uninstall;
|
|
277
|
-
(0, vitest_1.beforeEach)(() => {
|
|
278
|
-
env = makeThisEnv();
|
|
279
|
-
uninstall = globals_1.installCompat.call(env, { lib: env.lib });
|
|
280
|
-
});
|
|
281
|
-
(0, vitest_1.afterEach)(() => uninstall());
|
|
282
|
-
(0, vitest_1.it)('object.items/values/keys', () => {
|
|
283
|
-
const obj = { a: 1, b: 2 };
|
|
284
|
-
const items = env.runtime.memberLookup(obj, 'items', false);
|
|
285
|
-
const values = env.runtime.memberLookup(obj, 'values', false);
|
|
286
|
-
const keys = env.runtime.memberLookup(obj, 'keys', false);
|
|
287
|
-
(0, vitest_1.expect)(items()).toEqual([
|
|
288
|
-
['a', 1],
|
|
289
|
-
['b', 2],
|
|
290
|
-
]);
|
|
291
|
-
(0, vitest_1.expect)(values()).toEqual([1, 2]);
|
|
292
|
-
(0, vitest_1.expect)(keys()).toEqual(['a', 'b']);
|
|
293
|
-
});
|
|
294
|
-
(0, vitest_1.it)('object iter* aliases (iteritems/itervalues/iterkeys)', () => {
|
|
295
|
-
const obj = { a: 1 };
|
|
296
|
-
(0, vitest_1.expect)(env.runtime.memberLookup(obj, 'iteritems', false)()).toEqual([
|
|
297
|
-
['a', 1],
|
|
298
|
-
]);
|
|
299
|
-
(0, vitest_1.expect)(env.runtime.memberLookup(obj, 'itervalues', false)()).toEqual([1]);
|
|
300
|
-
(0, vitest_1.expect)(env.runtime.memberLookup(obj, 'iterkeys', false)()).toEqual(['a']);
|
|
301
|
-
});
|
|
302
|
-
(0, vitest_1.it)('object.get(key, def) returns def when missing', () => {
|
|
303
|
-
const obj = { a: 1 };
|
|
304
|
-
const get = env.runtime.memberLookup(obj, 'get', false);
|
|
305
|
-
(0, vitest_1.expect)(get('a', 9)).toBe(1);
|
|
306
|
-
(0, vitest_1.expect)(get('missing', 9)).toBe(9);
|
|
307
|
-
(0, vitest_1.expect)(get('missing', undefined)).toBe(undefined);
|
|
308
|
-
});
|
|
309
|
-
(0, vitest_1.it)('object.has_key checks own props only', () => {
|
|
310
|
-
const obj = Object.create({ inherited: 1 });
|
|
311
|
-
obj.own = 2;
|
|
312
|
-
const hasKey = env.runtime.memberLookup(obj, 'has_key', false);
|
|
313
|
-
(0, vitest_1.expect)(hasKey('own')).toBe(true);
|
|
314
|
-
(0, vitest_1.expect)(hasKey('inherited')).toBe(false);
|
|
315
|
-
});
|
|
316
|
-
(0, vitest_1.it)('object.pop(key, def) deletes and returns or throws KeyError', () => {
|
|
317
|
-
const obj = { a: 1 };
|
|
318
|
-
const pop = env.runtime.memberLookup(obj, 'pop', false);
|
|
319
|
-
(0, vitest_1.expect)(pop('a')).toBe(1);
|
|
320
|
-
(0, vitest_1.expect)('a' in obj).toBe(false);
|
|
321
|
-
(0, vitest_1.expect)(pop('missing', 7)).toBe(7);
|
|
322
|
-
(0, vitest_1.expect)(() => pop('missing2')).toThrow(/KeyError/);
|
|
323
|
-
});
|
|
324
|
-
(0, vitest_1.it)('object.popitem removes and returns a [k,v] pair or throws KeyError when empty', () => {
|
|
325
|
-
const obj = { a: 1, b: 2 };
|
|
326
|
-
const popitem = env.runtime.memberLookup(obj, 'popitem', false);
|
|
327
|
-
const [k, v] = popitem();
|
|
328
|
-
(0, vitest_1.expect)(['a', 'b']).toContain(k);
|
|
329
|
-
(0, vitest_1.expect)(v).toBe(1 === v ? 1 : 2);
|
|
330
|
-
(0, vitest_1.expect)(obj[k]).toBeUndefined();
|
|
331
|
-
const empty = {};
|
|
332
|
-
const popitemEmpty = env.runtime.memberLookup(empty, 'popitem', false);
|
|
333
|
-
(0, vitest_1.expect)(() => popitemEmpty()).toThrow(/KeyError/);
|
|
334
|
-
});
|
|
335
|
-
(0, vitest_1.it)('object.setdefault sets when missing, returns existing when present', () => {
|
|
336
|
-
const obj = { a: 1 };
|
|
337
|
-
const setdefault = env.runtime.memberLookup(obj, 'setdefault', false);
|
|
338
|
-
(0, vitest_1.expect)(setdefault('a', 9)).toBe(1);
|
|
339
|
-
(0, vitest_1.expect)(obj.a).toBe(1);
|
|
340
|
-
(0, vitest_1.expect)(setdefault('b', 9)).toBe(9);
|
|
341
|
-
(0, vitest_1.expect)(obj.b).toBe(9);
|
|
342
|
-
// default default is null
|
|
343
|
-
(0, vitest_1.expect)(setdefault('c')).toBe(null);
|
|
344
|
-
(0, vitest_1.expect)(obj.c).toBe(null);
|
|
345
|
-
});
|
|
346
|
-
(0, vitest_1.it)('object.update assigns and returns null', () => {
|
|
347
|
-
const obj = { a: 1 };
|
|
348
|
-
const update = env.runtime.memberLookup(obj, 'update', false);
|
|
349
|
-
const out = update({ b: 2, a: 9 });
|
|
350
|
-
(0, vitest_1.expect)(out).toBe(null);
|
|
351
|
-
(0, vitest_1.expect)(obj).toEqual({ a: 9, b: 2 });
|
|
352
|
-
});
|
|
353
|
-
});
|
|
354
|
-
(0, vitest_1.describe)('memberLookup: sliceLookup (arguments.length === 4)', () => {
|
|
355
|
-
let env;
|
|
356
|
-
let uninstall;
|
|
357
|
-
(0, vitest_1.beforeEach)(() => {
|
|
358
|
-
env = makeThisEnv({
|
|
359
|
-
runtime: {
|
|
360
|
-
// memberLookup will be overwritten by installCompat, but
|
|
361
|
-
// sliceLookup uses runtime.memberLookup to access indexes.
|
|
362
|
-
contextOrFrameLookup: vitest_1.vi.fn(() => undefined),
|
|
363
|
-
memberLookup: vitest_1.vi.fn((obj, idx) => obj?.[idx]),
|
|
364
|
-
},
|
|
365
|
-
});
|
|
366
|
-
uninstall = globals_1.installCompat.call(env, { lib: env.lib });
|
|
367
|
-
});
|
|
368
|
-
(0, vitest_1.afterEach)(() => uninstall());
|
|
369
|
-
(0, vitest_1.it)('positive step slice: start..stop', () => {
|
|
370
|
-
const arr = ['a', 'b', 'c', 'd', 'e'];
|
|
371
|
-
// call memberLookup with 4 args to trigger sliceLookup(obj,start,stop,step)
|
|
372
|
-
const res = env.runtime.memberLookup(arr, 1, 4, 1);
|
|
373
|
-
(0, vitest_1.expect)(res).toEqual(['b', 'c', 'd']);
|
|
374
|
-
});
|
|
375
|
-
(0, vitest_1.it)('negative indices and negative step', () => {
|
|
376
|
-
const arr = ['a', 'b', 'c', 'd', 'e'];
|
|
377
|
-
// start=null => last element; stop=null => -1; step=-1 => reverse full
|
|
378
|
-
const res = env.runtime.memberLookup(arr, null, null, -1);
|
|
379
|
-
(0, vitest_1.expect)(res).toEqual(['e', 'd', 'c', 'b', 'a']);
|
|
380
|
-
});
|
|
381
|
-
(0, vitest_1.it)('stop < 0 adjusts by length', () => {
|
|
382
|
-
const arr = [0, 1, 2, 3, 4, 5];
|
|
383
|
-
const res = env.runtime.memberLookup(arr, 0, -2, 1); // stop becomes len-2 => 4
|
|
384
|
-
(0, vitest_1.expect)(res).toEqual([0, 1, 2, 3]);
|
|
385
|
-
});
|
|
386
|
-
(0, vitest_1.it)('start < 0 adjusts by length', () => {
|
|
387
|
-
const arr = [0, 1, 2, 3, 4];
|
|
388
|
-
const res = env.runtime.memberLookup(arr, -3, null, 1); // start becomes 2
|
|
389
|
-
(0, vitest_1.expect)(res).toEqual([2, 3, 4]);
|
|
390
|
-
});
|
|
391
|
-
});
|
|
392
|
-
(0, vitest_1.describe)('non-slim (BUILD_TYPE !== SLIM) parser/compiler patching', () => {
|
|
393
|
-
// These tests focus on: assertType ignores Slice; parseAggregate fallback attempts slice parsing.
|
|
394
|
-
// We keep it minimal by stubbing the shapes installCompat uses.
|
|
395
|
-
const prev = process.env.BUILD_TYPE;
|
|
396
|
-
(0, vitest_1.beforeEach)(() => {
|
|
397
|
-
process.env.BUILD_TYPE = 'FULL';
|
|
398
|
-
});
|
|
399
|
-
(0, vitest_1.afterEach)(() => {
|
|
400
|
-
process.env.BUILD_TYPE = prev;
|
|
401
|
-
});
|
|
402
|
-
(0, vitest_1.it)('patches Compiler.prototype.assertType to ignore Slice instances', () => {
|
|
403
|
-
// minimal nodes system: Node.extend + Literal + Array
|
|
404
|
-
class Node {
|
|
405
|
-
static extend(_name, def) {
|
|
406
|
-
const Parent = this;
|
|
407
|
-
return class Slice extends Parent {
|
|
408
|
-
static fields = def.fields;
|
|
409
|
-
fields = def.fields;
|
|
410
|
-
start;
|
|
411
|
-
stop;
|
|
412
|
-
step;
|
|
413
|
-
parent(l, c, start, stop, step) {
|
|
414
|
-
this.lineno = l;
|
|
415
|
-
this.colno = c;
|
|
416
|
-
this.start = start;
|
|
417
|
-
this.stop = stop;
|
|
418
|
-
this.step = step;
|
|
419
|
-
}
|
|
420
|
-
constructor(...args) {
|
|
421
|
-
super();
|
|
422
|
-
def.init.apply(this, args);
|
|
423
|
-
}
|
|
424
|
-
};
|
|
425
|
-
}
|
|
426
|
-
}
|
|
427
|
-
class Literal extends Node {
|
|
428
|
-
lineno;
|
|
429
|
-
colno;
|
|
430
|
-
value;
|
|
431
|
-
constructor(lineno, colno, value) {
|
|
432
|
-
super();
|
|
433
|
-
this.lineno = lineno;
|
|
434
|
-
this.colno = colno;
|
|
435
|
-
this.value = value;
|
|
436
|
-
}
|
|
437
|
-
}
|
|
438
|
-
class ArrayNode extends Node {
|
|
439
|
-
lineno;
|
|
440
|
-
colno;
|
|
441
|
-
children;
|
|
442
|
-
constructor(lineno, colno, children) {
|
|
443
|
-
super();
|
|
444
|
-
this.lineno = lineno;
|
|
445
|
-
this.colno = colno;
|
|
446
|
-
this.children = children;
|
|
447
|
-
}
|
|
448
|
-
}
|
|
449
|
-
class Compiler {
|
|
450
|
-
assertType(node) {
|
|
451
|
-
// original throws for unknown types
|
|
452
|
-
if (!node || node.__type !== 'ok')
|
|
453
|
-
throw new Error('bad type');
|
|
454
|
-
}
|
|
455
|
-
}
|
|
456
|
-
const env = makeThisEnv({
|
|
457
|
-
nodes: { Node, Literal, Array: ArrayNode },
|
|
458
|
-
compiler: { Compiler },
|
|
459
|
-
parser: { Parser: class Parser {
|
|
460
|
-
} },
|
|
461
|
-
});
|
|
462
|
-
const uninstall = globals_1.installCompat.call(env, { lib: env.lib });
|
|
463
|
-
const c = new env.compiler.Compiler();
|
|
464
|
-
// @ts-expect-error - the Slice class is created inside installCompat
|
|
465
|
-
const Slice = env.nodes.Node.extend; // not directly accessible; so we validate behavior indirectly:
|
|
466
|
-
// We can still ensure patched assertType does NOT throw when node is instance of Slice by:
|
|
467
|
-
// - creating a Slice by invoking parseAggregate fallback? too heavy here.
|
|
468
|
-
// Instead, just verify that assertType was replaced (function identity changed),
|
|
469
|
-
// and that calling it with a "bad type" still throws, implying original is still used for others.
|
|
470
|
-
(0, vitest_1.expect)(c.assertType).toBeTypeOf('function');
|
|
471
|
-
(0, vitest_1.expect)(() => c.assertType({ __type: 'nope' })).toThrow(/bad type/);
|
|
472
|
-
uninstall();
|
|
473
|
-
});
|
|
474
|
-
(0, vitest_1.it)('Parser.parseAggregate fallback: returns nodes.Array([Slice]) when it detects a slice', () => {
|
|
475
|
-
// Minimal nodes
|
|
476
|
-
class Node {
|
|
477
|
-
static extend(_name, def) {
|
|
478
|
-
const Parent = this;
|
|
479
|
-
return class Slice extends Parent {
|
|
480
|
-
static fields = def.fields;
|
|
481
|
-
fields = def.fields;
|
|
482
|
-
start;
|
|
483
|
-
stop;
|
|
484
|
-
step;
|
|
485
|
-
parent(l, c, start, stop, step) {
|
|
486
|
-
this.lineno = l;
|
|
487
|
-
this.colno = c;
|
|
488
|
-
this.start = start;
|
|
489
|
-
this.stop = stop;
|
|
490
|
-
this.step = step;
|
|
491
|
-
}
|
|
492
|
-
constructor(...args) {
|
|
493
|
-
super();
|
|
494
|
-
def.init.apply(this, args);
|
|
495
|
-
}
|
|
496
|
-
};
|
|
497
|
-
}
|
|
498
|
-
}
|
|
499
|
-
class Literal extends Node {
|
|
500
|
-
lineno;
|
|
501
|
-
colno;
|
|
502
|
-
value;
|
|
503
|
-
constructor(lineno, colno, value) {
|
|
504
|
-
super();
|
|
505
|
-
this.lineno = lineno;
|
|
506
|
-
this.colno = colno;
|
|
507
|
-
this.value = value;
|
|
508
|
-
}
|
|
509
|
-
}
|
|
510
|
-
class ArrayNode extends Node {
|
|
511
|
-
lineno;
|
|
512
|
-
colno;
|
|
513
|
-
children;
|
|
514
|
-
constructor(lineno, colno, children) {
|
|
515
|
-
super();
|
|
516
|
-
this.lineno = lineno;
|
|
517
|
-
this.colno = colno;
|
|
518
|
-
this.children = children;
|
|
519
|
-
}
|
|
520
|
-
}
|
|
521
|
-
// Token stream stub
|
|
522
|
-
const tokens = { index: 1, lineno: 0, colno: 1 };
|
|
523
|
-
// Parser stub: original parseAggregate always throws (to trigger fallback)
|
|
524
|
-
class Parser {
|
|
525
|
-
tokens = { ...tokens };
|
|
526
|
-
peeked = false;
|
|
527
|
-
parseAggregate() {
|
|
528
|
-
throw new Error('orig parseAggregate fail');
|
|
529
|
-
}
|
|
530
|
-
peekToken() {
|
|
531
|
-
// After reset, compat expects LEFT_BRACKET
|
|
532
|
-
return { type: 'left-bracket', lineno: 0, colno: 0 };
|
|
533
|
-
}
|
|
534
|
-
nextToken() {
|
|
535
|
-
return this.peekToken();
|
|
536
|
-
}
|
|
537
|
-
skip(type) {
|
|
538
|
-
// simulate parsing: "[ : ]"
|
|
539
|
-
// first iteration sees COLON then later RIGHT_BRACKET
|
|
540
|
-
if (!this.__state)
|
|
541
|
-
this.__state = 0;
|
|
542
|
-
this.__state++;
|
|
543
|
-
// state 1: after entering loop, first skip(COLON) true
|
|
544
|
-
if (this.__state === 1 && type === 'colon')
|
|
545
|
-
return true;
|
|
546
|
-
// state 2: then skip(RIGHT_BRACKET) true to end
|
|
547
|
-
if (this.__state === 2 && type === 'right-bracket')
|
|
548
|
-
return true;
|
|
549
|
-
return false;
|
|
550
|
-
}
|
|
551
|
-
parseExpression() {
|
|
552
|
-
// should not be called for the ":"-only slice
|
|
553
|
-
throw new Error('parseExpression should not run');
|
|
554
|
-
}
|
|
555
|
-
fail(msg) {
|
|
556
|
-
throw new Error(msg);
|
|
557
|
-
}
|
|
558
|
-
}
|
|
559
|
-
class Compiler {
|
|
560
|
-
}
|
|
561
|
-
const env = makeThisEnv({
|
|
562
|
-
nodes: { Node, Literal, Array: ArrayNode },
|
|
563
|
-
compiler: { Compiler },
|
|
564
|
-
parser: { Parser },
|
|
565
|
-
});
|
|
566
|
-
const uninstall = globals_1.installCompat.call(env, { lib: env.lib });
|
|
567
|
-
const p = new env.parser.Parser();
|
|
568
|
-
const out = p.parseAggregate();
|
|
569
|
-
(0, vitest_1.expect)(out).toBeInstanceOf(env.nodes.Array);
|
|
570
|
-
(0, vitest_1.expect)(out.children).toHaveLength(1);
|
|
571
|
-
const sliceNode = out.children[0];
|
|
572
|
-
// sliceNode should have start/stop/step literals by default
|
|
573
|
-
(0, vitest_1.expect)(sliceNode.start.value).toBe(null);
|
|
574
|
-
(0, vitest_1.expect)(sliceNode.stop.value).toBe(null);
|
|
575
|
-
(0, vitest_1.expect)(sliceNode.step.value).toBe(1);
|
|
576
|
-
uninstall();
|
|
577
|
-
});
|
|
578
|
-
});
|
|
579
|
-
});
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export {};
|