@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.
@@ -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 {};