@samuelbines/nunjucks 0.0.3 → 0.0.5

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,236 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- const vitest_1 = require("vitest");
4
- const index_1 = require("../index");
5
- (0, vitest_1.describe)('lib()', () => {
6
- (0, vitest_1.describe)('isFunction/isArray/isString/isObject', () => {
7
- (0, vitest_1.test)('isFunction()', () => {
8
- (0, vitest_1.expect)(index_1.lib.isFunction(() => { })).toBe(true);
9
- (0, vitest_1.expect)(index_1.lib.isFunction(function () { })).toBe(true);
10
- (0, vitest_1.expect)(index_1.lib.isFunction(async () => { })).toBe(true);
11
- (0, vitest_1.expect)(index_1.lib.isFunction(null)).toBe(false);
12
- (0, vitest_1.expect)(index_1.lib.isFunction({})).toBe(false);
13
- (0, vitest_1.expect)(index_1.lib.isFunction('fn')).toBe(false);
14
- });
15
- (0, vitest_1.test)('isArray()', () => {
16
- (0, vitest_1.expect)(Array.isArray([])).toBe(true);
17
- (0, vitest_1.expect)(Array.isArray([1, 2])).toBe(true);
18
- (0, vitest_1.expect)(Array.isArray(new Array(3))).toBe(true);
19
- (0, vitest_1.expect)(Array.isArray({ length: 1 })).toBe(false);
20
- (0, vitest_1.expect)(Array.isArray('[]')).toBe(false);
21
- (0, vitest_1.expect)(Array.isArray(null)).toBe(false);
22
- });
23
- (0, vitest_1.test)('isString()', () => {
24
- (0, vitest_1.expect)(index_1.lib.isString('hello')).toBe(true);
25
- (0, vitest_1.expect)(index_1.lib.isString(String('x'))).toBe(true);
26
- // string object is NOT typeof "string"
27
- (0, vitest_1.expect)(index_1.lib.isString(new String('x'))).toBe(false);
28
- (0, vitest_1.expect)(index_1.lib.isString(123)).toBe(false);
29
- (0, vitest_1.expect)(index_1.lib.isString(null)).toBe(false);
30
- });
31
- (0, vitest_1.test)('isObject() only matches plain objects', () => {
32
- (0, vitest_1.expect)(index_1.lib.isObject({})).toBe(true);
33
- (0, vitest_1.expect)(index_1.lib.isObject({ a: 1 })).toBe(true);
34
- (0, vitest_1.expect)(index_1.lib.isObject([])).toBe(false);
35
- (0, vitest_1.expect)(index_1.lib.isObject(() => { })).toBe(false);
36
- (0, vitest_1.expect)(index_1.lib.isObject(new Date())).toBe(false);
37
- (0, vitest_1.expect)(index_1.lib.isObject(null)).toBe(false);
38
- });
39
- });
40
- (0, vitest_1.describe)('_prepareAttributeParts()', () => {
41
- (0, vitest_1.test)('splits dotted strings', () => {
42
- (0, vitest_1.expect)(index_1.lib._prepareAttributeParts('a.b.c')).toEqual(['a', 'b', 'c']);
43
- });
44
- (0, vitest_1.test)('wraps numbers as array', () => {
45
- (0, vitest_1.expect)(index_1.lib._prepareAttributeParts(12)).toEqual([12]);
46
- });
47
- });
48
- (0, vitest_1.describe)('getAttrGetter()', () => {
49
- (0, vitest_1.test)('gets nested attributes safely', () => {
50
- const get = index_1.lib.getAttrGetter('a.b.c');
51
- (0, vitest_1.expect)(get({ a: { b: { c: 42 } } })).toBe(42);
52
- });
53
- (0, vitest_1.test)('returns undefined for missing path', () => {
54
- const get = index_1.lib.getAttrGetter('a.b.c');
55
- (0, vitest_1.expect)(get({ a: { b: {} } })).toBeUndefined();
56
- (0, vitest_1.expect)(get({})).toBeUndefined();
57
- });
58
- (0, vitest_1.test)('works for single-level attribute', () => {
59
- const get = index_1.lib.getAttrGetter('x');
60
- (0, vitest_1.expect)(get({ x: 'ok' })).toBe('ok');
61
- });
62
- });
63
- (0, vitest_1.describe)('groupBy()', () => {
64
- (0, vitest_1.test)('groups by attribute name', () => {
65
- const list = [
66
- { t: 'a', n: 1 },
67
- { t: 'b', n: 2 },
68
- { t: 'a', n: 3 },
69
- ];
70
- const out = index_1.lib.groupBy(list, 't', false);
71
- (0, vitest_1.expect)(Object.keys(out).sort()).toEqual(['a', 'b']);
72
- (0, vitest_1.expect)(out.a.map((x) => x.n)).toEqual([1, 3]);
73
- (0, vitest_1.expect)(out.b.map((x) => x.n)).toEqual([2]);
74
- });
75
- (0, vitest_1.test)('throws when key is undefined and throwOnUndefined=true', () => {
76
- const list = [{ t: 'a' }, { nope: 123 }];
77
- (0, vitest_1.expect)(() => index_1.lib.groupBy(list, 't', true)).toThrow(/resolved to undefined/i);
78
- });
79
- (0, vitest_1.test)('groups by iterator function', () => {
80
- const list = [{ n: 1 }, { n: 2 }, { n: 3 }];
81
- const out = index_1.lib.groupBy(list, (x) => (x.n % 2 ? 'odd' : 'even'), false);
82
- (0, vitest_1.expect)(out.odd.map((x) => x.n)).toEqual([1, 3]);
83
- (0, vitest_1.expect)(out.even.map((x) => x.n)).toEqual([2]);
84
- });
85
- });
86
- (0, vitest_1.describe)('toArray()', () => {
87
- (0, vitest_1.test)('converts array-like objects', () => {
88
- const arrLike = { 0: 'a', 1: 'b', length: 2 };
89
- (0, vitest_1.expect)(index_1.lib.toArray(arrLike)).toEqual(['a', 'b']);
90
- });
91
- (0, vitest_1.test)('converts arguments object', () => {
92
- function f() {
93
- return index_1.lib.toArray(arguments);
94
- }
95
- (0, vitest_1.expect)(f('x', 'y')).toEqual(['x', 'y']);
96
- });
97
- });
98
- (0, vitest_1.describe)('without()', () => {
99
- (0, vitest_1.test)('removes values from array', () => {
100
- (0, vitest_1.expect)(index_1.lib.without([1, 2, 3, 2], 2)).toEqual([1, 3]);
101
- });
102
- (0, vitest_1.test)('does nothing if contains is empty', () => {
103
- (0, vitest_1.expect)(index_1.lib.without([1, 2, 3])).toEqual([1, 2, 3]);
104
- });
105
- (0, vitest_1.test)('works with strings', () => {
106
- (0, vitest_1.expect)(index_1.lib.without(['a', 'b', 'a'], 'a')).toEqual(['b']);
107
- });
108
- });
109
- (0, vitest_1.describe)('repeat()', () => {
110
- (0, vitest_1.test)('repeats character n times', () => {
111
- (0, vitest_1.expect)(index_1.lib.repeat('a', 0)).toBe('');
112
- (0, vitest_1.expect)(index_1.lib.repeat('a', 3)).toBe('aaa');
113
- (0, vitest_1.expect)(index_1.lib.repeat('🤚🏼', 2)).toBe('🤚🏼🤚🏼');
114
- });
115
- });
116
- (0, vitest_1.describe)('each()', () => {
117
- (0, vitest_1.test)('iterates arrays using native forEach', () => {
118
- const seen = [];
119
- index_1.lib.each([1, 2, 3], (x) => seen.push(x), null);
120
- (0, vitest_1.expect)(seen).toEqual([1, 2, 3]);
121
- });
122
- (0, vitest_1.test)('iterates array-like objects', () => {
123
- const seen = [];
124
- const arrLike = { 0: 'a', 1: 'b', length: 2 };
125
- index_1.lib.each(arrLike, function (v) {
126
- seen.push(v);
127
- }, null);
128
- (0, vitest_1.expect)(seen).toEqual(['a', 'b']);
129
- });
130
- (0, vitest_1.test)('does nothing for falsy obj', () => {
131
- (0, vitest_1.expect)(() => index_1.lib.each(null, () => { }, null)).not.toThrow();
132
- });
133
- });
134
- (0, vitest_1.describe)('asyncIter()', () => {
135
- (0, vitest_1.test)('calls iter for each item then cb', () => {
136
- const calls = [];
137
- const done = vitest_1.vi.fn();
138
- index_1.lib.asyncIter([1, 2, 3], (val, i, next) => {
139
- calls.push(`${i}:${val}`);
140
- next();
141
- }, done);
142
- (0, vitest_1.expect)(calls).toEqual(['0:1', '1:2', '2:3']);
143
- (0, vitest_1.expect)(done).toHaveBeenCalledTimes(1);
144
- });
145
- (0, vitest_1.test)('iter can early-fail via cb (4th arg) if you use it', () => {
146
- const done = vitest_1.vi.fn();
147
- const iter = vitest_1.vi.fn((val, i, next, cb) => {
148
- if (val === 2)
149
- return cb(new Error('stop'));
150
- next();
151
- });
152
- index_1.lib.asyncIter([1, 2, 3], iter, done);
153
- (0, vitest_1.expect)(done).toHaveBeenCalledTimes(1);
154
- // depending on your intended semantics, done might get (err) or no args.
155
- // current implementation calls cb() directly, so it WILL receive the error.
156
- (0, vitest_1.expect)(done.mock.calls[0][0]).toBeInstanceOf(Error);
157
- });
158
- });
159
- (0, vitest_1.describe)('asyncFor()', () => {
160
- (0, vitest_1.test)('iterates object keys then calls cb', () => {
161
- const obj = { a: 1, b: 2 };
162
- const seen = [];
163
- const done = vitest_1.vi.fn();
164
- index_1.lib.asyncFor(obj, (k, v, i, len, next) => {
165
- seen.push(`${k}:${v}:${i}/${len}`);
166
- next();
167
- }, done);
168
- // order is insertion order in JS engines for string keys
169
- (0, vitest_1.expect)(seen).toEqual(['a:1:0/2', 'b:2:1/2']);
170
- (0, vitest_1.expect)(done).toHaveBeenCalledTimes(1);
171
- });
172
- (0, vitest_1.test)('handles empty object', () => {
173
- const done = vitest_1.vi.fn();
174
- index_1.lib.asyncFor({}, (_k, _v, _i, _len, next) => next(), done);
175
- (0, vitest_1.expect)(done).toHaveBeenCalledTimes(1);
176
- });
177
- });
178
- (0, vitest_1.describe)('inOperator()', () => {
179
- (0, vitest_1.test)('works for arrays (uses indexOf)', () => {
180
- (0, vitest_1.expect)(index_1.lib.inOperator('a', ['a', 'b'])).toBe(true);
181
- (0, vitest_1.expect)(index_1.lib.inOperator('x', ['a', 'b'])).toBe(false);
182
- });
183
- (0, vitest_1.test)('works for strings (substring search)', () => {
184
- (0, vitest_1.expect)(index_1.lib.inOperator('cat', 'concatenate')).toBe(true);
185
- (0, vitest_1.expect)(index_1.lib.inOperator('dog', 'concatenate')).toBe(false);
186
- });
187
- (0, vitest_1.test)('works for plain objects (property in)', () => {
188
- (0, vitest_1.expect)(index_1.lib.inOperator('a', { a: 1 })).toBe(true);
189
- (0, vitest_1.expect)(index_1.lib.inOperator('b', { a: 1 })).toBe(false);
190
- });
191
- (0, vitest_1.test)('throws for unsupported types', () => {
192
- (0, vitest_1.expect)(() => index_1.lib.inOperator('a', 123)).toThrow(/unexpected types/i);
193
- (0, vitest_1.expect)(() => index_1.lib.inOperator('a', null)).toThrow();
194
- });
195
- });
196
- (0, vitest_1.describe)('TemplateError + _prettifyError()', () => {
197
- (0, vitest_1.test)('TemplateError stores lineno/colno and supports update()', () => {
198
- const err = index_1.lib.TemplateError('boom', 10, 2);
199
- (0, vitest_1.expect)(err.name).toBe('Template render error');
200
- (0, vitest_1.expect)(err.lineno).toBe(10);
201
- (0, vitest_1.expect)(err.colno).toBe(2);
202
- err.update('file.njk');
203
- (0, vitest_1.expect)(err.message).toContain('(file.njk)');
204
- (0, vitest_1.expect)(err.message).toContain('Line 10');
205
- (0, vitest_1.expect)(err.message).toContain('Column 2');
206
- });
207
- (0, vitest_1.test)('_prettifyError wraps non-TemplateErr errors', () => {
208
- const raw = new Error('nope');
209
- const pretty = index_1.lib._prettifyError('x.njk', true, raw);
210
- (0, vitest_1.expect)(pretty.name).toBe('Template render error');
211
- (0, vitest_1.expect)(pretty.message).toContain('(x.njk)');
212
- });
213
- (0, vitest_1.test)('_prettifyError uses existing update when present', () => {
214
- const err = index_1.lib.TemplateError('boom', 1, 1);
215
- const pretty = index_1.lib._prettifyError('y.njk', true, err);
216
- (0, vitest_1.expect)(pretty.message).toContain('(y.njk)');
217
- });
218
- });
219
- (0, vitest_1.describe)('hasOwnProp()', () => {
220
- (0, vitest_1.test)('works for existing keys', () => {
221
- const obj = { a: 1, 1: 'x' };
222
- (0, vitest_1.expect)(index_1.lib.hasOwnProp(obj, 'a')).toBe(true);
223
- (0, vitest_1.expect)(index_1.lib.hasOwnProp(obj, 1)).toBe(true);
224
- });
225
- (0, vitest_1.test)('returns false for missing keys', () => {
226
- const obj = { a: 1 };
227
- (0, vitest_1.expect)(index_1.lib.hasOwnProp(obj, 'b')).toBe(false);
228
- });
229
- (0, vitest_1.test)('throws for null/undefined key (because `in` operator)', () => {
230
- const obj = { a: 1 };
231
- // [Function anonymous]
232
- (0, vitest_1.expect)(() => index_1.lib.hasOwnProp(obj, undefined)).toBe(false);
233
- (0, vitest_1.expect)(() => index_1.lib.hasOwnProp(obj, null)).toBe(false);
234
- });
235
- });
236
- });
@@ -1 +0,0 @@
1
- export {};
@@ -1,301 +0,0 @@
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
- const events_1 = __importDefault(require("events"));
7
- const vitest_1 = require("vitest");
8
- const node_fs_1 = __importDefault(require("node:fs"));
9
- const node_path_1 = __importDefault(require("node:path"));
10
- const node_os_1 = __importDefault(require("node:os"));
11
- // IMPORTANT: update to the path where loader.ts exports these
12
- const loader_1 = require("../src/loader");
13
- function mkTmpDir() {
14
- return node_fs_1.default.mkdtempSync(node_path_1.default.join(node_os_1.default.tmpdir(), 'njk-loader-'));
15
- }
16
- function write(p, content) {
17
- node_fs_1.default.mkdirSync(node_path_1.default.dirname(p), { recursive: true });
18
- node_fs_1.default.writeFileSync(p, content, 'utf8');
19
- }
20
- (0, vitest_1.describe)('Obj / EmitterObj extend + parentWrap', () => {
21
- (0, vitest_1.it)('Obj.extend supports this.parent() calling the overridden method', () => {
22
- class Base extends loader_1.Loader {
23
- hello() {
24
- return 'base';
25
- }
26
- }
27
- class Sub extends Base {
28
- hello() {
29
- // parentWrap makes this.parent point to Base.prototype.hello
30
- return super.hello() + ':sub';
31
- }
32
- }
33
- const s = new Sub();
34
- (0, vitest_1.expect)(s.hello()).toBe('base:sub');
35
- (0, vitest_1.expect)(s.typename).toBe('Sub');
36
- });
37
- (0, vitest_1.it)('EmitterObj.extend supports this.parent() and emits events', () => {
38
- class Base extends events_1.default {
39
- get typename() {
40
- return this.constructor.name;
41
- }
42
- ping() {
43
- return 'pong';
44
- }
45
- }
46
- class Sub extends Base {
47
- ping() {
48
- return super.ping() + '!';
49
- }
50
- }
51
- const s = new Sub();
52
- (0, vitest_1.expect)(s.ping()).toBe('pong!');
53
- (0, vitest_1.expect)(s.typename).toBe('Sub');
54
- const fn = vitest_1.vi.fn();
55
- s.on('evt', fn);
56
- s.emit('evt', 1, 2);
57
- (0, vitest_1.expect)(fn).toHaveBeenCalledWith(1, 2);
58
- });
59
- });
60
- (0, vitest_1.describe)('Loader base class', () => {
61
- (0, vitest_1.it)('resolve resolves relative to dirname(from)', () => {
62
- const l = new loader_1.Loader();
63
- const out = l.resolve('/a/b/c.njk', './d.njk');
64
- (0, vitest_1.expect)(out).toBe(node_path_1.default.resolve('/a/b', './d.njk'));
65
- });
66
- (0, vitest_1.it)('isRelative detects ./ and ../ only', () => {
67
- const l = new loader_1.Loader();
68
- (0, vitest_1.expect)(l.isRelative('./x.njk')).toBe(true);
69
- (0, vitest_1.expect)(l.isRelative('../x.njk')).toBe(true);
70
- (0, vitest_1.expect)(l.isRelative('x.njk')).toBe(false);
71
- (0, vitest_1.expect)(l.isRelative('/abs/x.njk')).toBe(false);
72
- });
73
- });
74
- (0, vitest_1.describe)('PrecompiledLoader', () => {
75
- (0, vitest_1.it)('getSource returns code src when template exists', () => {
76
- const compiled = {
77
- 'a.njk': { root() { } },
78
- };
79
- const l = new loader_1.PrecompiledLoader(compiled);
80
- const src = l.getSource('a.njk');
81
- (0, vitest_1.expect)(src).toEqual({
82
- src: { type: 'code', obj: compiled['a.njk'] },
83
- path: 'a.njk',
84
- });
85
- });
86
- (0, vitest_1.it)('getSource returns null when missing', () => {
87
- const l = new loader_1.PrecompiledLoader({});
88
- (0, vitest_1.expect)(l.getSource('missing.njk')).toBeNull();
89
- });
90
- });
91
- (0, vitest_1.describe)('WebLoader', () => {
92
- const originalWindow = globalThis.window;
93
- const originalFetch = globalThis.fetch;
94
- (0, vitest_1.afterEach)(() => {
95
- globalThis.window = originalWindow;
96
- globalThis.fetch = originalFetch;
97
- vitest_1.vi.restoreAllMocks();
98
- });
99
- (0, vitest_1.it)('resolve throws (relative templates unsupported)', () => {
100
- const l = new loader_1.WebLoader('.');
101
- (0, vitest_1.expect)(() => l.resolve('a', 'b')).toThrow(/relative templates not support/i);
102
- });
103
- (0, vitest_1.it)('getSource throws if called without cb (fetch is async)', () => {
104
- globalThis.window = {}; // allow fetch path
105
- globalThis.fetch = vitest_1.vi.fn();
106
- const l = new loader_1.WebLoader('https://example.com', { useCache: false });
107
- (0, vitest_1.expect)(() => l.getSource('a.njk')).toThrow(/without a callback/i);
108
- });
109
- (0, vitest_1.it)('fetch throws on server (no window)', () => {
110
- globalThis.window = undefined;
111
- const l = new loader_1.WebLoader('https://example.com');
112
- (0, vitest_1.expect)(() => l.fetch('https://x', vitest_1.vi.fn())).toThrow(/only by used in a browser/i);
113
- });
114
- (0, vitest_1.it)('getSource calls fetch and emits load (noCache when useCache=false)', async () => {
115
- globalThis.window = {};
116
- globalThis.fetch = vitest_1.vi.fn(async () => ({
117
- ok: true,
118
- status: 200,
119
- text: async () => 'TEMPLATE',
120
- }));
121
- const l = new loader_1.WebLoader('https://example.com/base/', { useCache: false });
122
- const onLoad = vitest_1.vi.fn();
123
- l.on('load', onLoad);
124
- const res = await new Promise((resolve, reject) => {
125
- l.getSource('a.njk', (err, out) => (err ? reject(err) : resolve(out)));
126
- });
127
- (0, vitest_1.expect)(res).toEqual({
128
- src: 'TEMPLATE',
129
- path: 'a.njk',
130
- noCache: true,
131
- });
132
- (0, vitest_1.expect)(onLoad).toHaveBeenCalledTimes(1);
133
- (0, vitest_1.expect)(onLoad.mock.calls[0][0]).toBe('a.njk');
134
- (0, vitest_1.expect)(onLoad.mock.calls[0][1]).toMatchObject({
135
- path: 'a.njk',
136
- src: 'TEMPLATE',
137
- });
138
- // url should be baseURL joined with name, and include cache-bust query
139
- (0, vitest_1.expect)(globalThis.fetch).toHaveBeenCalledTimes(1);
140
- const calledUrl = globalThis.fetch.mock.calls[0][0];
141
- (0, vitest_1.expect)(calledUrl).toMatch(/^https:\/\/example\.com\/base\/a\.njk\?/);
142
- (0, vitest_1.expect)(calledUrl).toMatch(/(\?|&)s=\d+/);
143
- });
144
- (0, vitest_1.it)('useCache=true caches results and returns cached value on next call (no fetch)', async () => {
145
- globalThis.window = {};
146
- const fetchSpy = vitest_1.vi.fn(async () => ({
147
- ok: true,
148
- status: 200,
149
- text: async () => 'ONE',
150
- }));
151
- globalThis.fetch = fetchSpy;
152
- const l = new loader_1.WebLoader('https://example.com', { useCache: true });
153
- const first = await new Promise((resolve, reject) => {
154
- l.getSource('a.njk', (err, out) => (err ? reject(err) : resolve(out)));
155
- });
156
- (0, vitest_1.expect)(first.noCache).toBe(false);
157
- (0, vitest_1.expect)(first.src).toBe('ONE');
158
- (0, vitest_1.expect)(fetchSpy).toHaveBeenCalledTimes(1);
159
- // Change fetch response; should not be called
160
- globalThis.fetch = vitest_1.vi.fn(async () => ({
161
- ok: true,
162
- status: 200,
163
- text: async () => 'TWO',
164
- }));
165
- const second = await new Promise((resolve, reject) => {
166
- l.getSource('a.njk', (err, out) => (err ? reject(err) : resolve(out)));
167
- });
168
- (0, vitest_1.expect)(second).toBe(first);
169
- });
170
- (0, vitest_1.it)('404 from fetch maps to cb(null, null)', async () => {
171
- globalThis.window = {};
172
- globalThis.fetch = vitest_1.vi.fn(async () => ({
173
- ok: false,
174
- status: 404,
175
- text: async () => 'not found',
176
- }));
177
- const l = new loader_1.WebLoader('https://example.com', { useCache: false });
178
- const out = await new Promise((resolve) => {
179
- l.getSource('missing.njk', (_err, res) => resolve(res));
180
- });
181
- (0, vitest_1.expect)(out).toBeNull();
182
- });
183
- (0, vitest_1.it)('non-404 fetch error yields cb(err, null)', async () => {
184
- globalThis.window = {};
185
- globalThis.fetch = vitest_1.vi.fn(async () => ({
186
- ok: false,
187
- status: 500,
188
- text: async () => 'boom',
189
- }));
190
- const l = new loader_1.WebLoader('https://example.com', { useCache: false });
191
- const [err, res] = await new Promise((resolve) => {
192
- l.getSource('a.njk', (e, r) => resolve([e, r]));
193
- });
194
- (0, vitest_1.expect)(res).toBeNull();
195
- (0, vitest_1.expect)(err).toMatchObject({ status: 500, content: 'boom' });
196
- });
197
- });
198
- (0, vitest_1.describe)('FileSystemLoader', () => {
199
- let dir;
200
- (0, vitest_1.beforeEach)(() => {
201
- dir = mkTmpDir();
202
- });
203
- (0, vitest_1.afterEach)(() => {
204
- node_fs_1.default.rmSync(dir, { recursive: true, force: true });
205
- });
206
- (0, vitest_1.it)('getSource finds template within searchPaths, reads file, emits load', () => {
207
- const file = node_path_1.default.join(dir, 'views', 'a.njk');
208
- write(file, 'HELLO');
209
- const l = new loader_1.FileSystemLoader([node_path_1.default.join(dir, 'views')], {
210
- watch: false,
211
- noCache: false,
212
- });
213
- const onLoad = vitest_1.vi.fn();
214
- l.on('load', onLoad);
215
- const res = l.getSource('a.njk');
216
- (0, vitest_1.expect)(res).toEqual({
217
- src: 'HELLO',
218
- path: node_path_1.default.resolve(file),
219
- noCache: false,
220
- });
221
- (0, vitest_1.expect)(onLoad).toHaveBeenCalledTimes(1);
222
- (0, vitest_1.expect)(onLoad).toHaveBeenCalledWith('a.njk', vitest_1.expect.objectContaining({ src: 'HELLO' }));
223
- });
224
- (0, vitest_1.it)('returns null when not found', () => {
225
- const l = new loader_1.FileSystemLoader([node_path_1.default.join(dir, 'views')], {
226
- watch: false,
227
- noCache: false,
228
- });
229
- (0, vitest_1.expect)(l.getSource('missing.njk')).toBeNull();
230
- });
231
- (0, vitest_1.it)('prevents directory traversal by basePath prefix check', () => {
232
- // create a "secret" outside views
233
- const views = node_path_1.default.join(dir, 'views');
234
- const secret = node_path_1.default.join(dir, 'secret.txt');
235
- write(secret, 'NOPE');
236
- node_fs_1.default.mkdirSync(views, { recursive: true });
237
- const l = new loader_1.FileSystemLoader([views], { watch: false, noCache: false });
238
- // try to escape
239
- const res = l.getSource('../secret.txt');
240
- (0, vitest_1.expect)(res).toBeNull();
241
- });
242
- (0, vitest_1.it)('sets pathsToNames mapping after successful load', () => {
243
- const file = node_path_1.default.join(dir, 'views', 'a.njk');
244
- write(file, 'HELLO');
245
- const l = new loader_1.FileSystemLoader([node_path_1.default.join(dir, 'views')], {
246
- watch: false,
247
- noCache: false,
248
- });
249
- const res = l.getSource('a.njk');
250
- (0, vitest_1.expect)(l.pathsToNames[res.path]).toBe('a.njk');
251
- });
252
- });
253
- // describe('NodeResolveLoader', () => {
254
- // let dir: string;
255
- // let modDir: string;
256
- // let modPath: string;
257
- // beforeEach(() => {
258
- // dir = mkTmpDir();
259
- // modDir = path.join(dir, 'node_modules', 'my-njk-pkg');
260
- // modPath = path.join(modDir, 'index.njk');
261
- // write(modPath, 'PKG_TEMPLATE');
262
- // // Make it resolvable
263
- // write(
264
- // path.join(modDir, 'package.json'),
265
- // JSON.stringify({ name: 'my-njk-pkg', main: 'index.njk' })
266
- // );
267
- // // Ensure node can resolve from this temp dir
268
- // process.env.NODE_PATH = path.join(dir, 'node_modules');
269
- // require('module').Module._initPaths();
270
- // });
271
- // afterEach(() => {
272
- // fs.rmSync(dir, { recursive: true, force: true });
273
- // });
274
- // // it('rejects filesystem traversal names', () => {
275
- // // const l = new NodeResolveLoader({ watch: false, noCache: false });
276
- // // expect(l.getSource('../x')).toBeNull();
277
- // // expect(l.getSource('./x')).toBeNull();
278
- // // // windows drive letter
279
- // // expect(l.getSource('C:\\x')).toBeNull();
280
- // // });
281
- // // it('getSource resolves module, reads it, emits load', () => {
282
- // // const l = new NodeResolveLoader({ watch: false, noCache: true });
283
- // // const onLoad = vi.fn();
284
- // // l.on('load', onLoad);
285
- // // const res = l.getSource('my-njk-pkg');
286
- // // expect(res).toEqual({
287
- // // src: 'PKG_TEMPLATE',
288
- // // path: path.resolve(modPath),
289
- // // noCache: true,
290
- // // });
291
- // // expect(onLoad).toHaveBeenCalledTimes(1);
292
- // // expect(onLoad).toHaveBeenCalledWith(
293
- // // 'my-njk-pkg',
294
- // // expect.objectContaining({ src: 'PKG_TEMPLATE' })
295
- // // );
296
- // // });
297
- // // it('returns null when require.resolve fails', () => {
298
- // // const l = new NodeResolveLoader({ watch: false, noCache: false });
299
- // // expect(l.getSource('definitely-not-a-real-package-xyz')).toBeNull();
300
- // // });
301
- // });
@@ -1 +0,0 @@
1
- export {};