UNPKG

sensai

Version:

Because even AI needs a master

479 lines (478 loc) 18.6 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); const _nodetest = require("node:test"); const _nodeassert = /*#__PURE__*/ _interop_require_default(require("node:assert")); const _nodestream = require("node:stream"); const _template = /*#__PURE__*/ _interop_require_wildcard(require("./template")); function _interop_require_default(obj) { return obj && obj.__esModule ? obj : { default: obj }; } function _getRequireWildcardCache(nodeInterop) { if (typeof WeakMap !== "function") return null; var cacheBabelInterop = new WeakMap(); var cacheNodeInterop = new WeakMap(); return (_getRequireWildcardCache = function(nodeInterop) { return nodeInterop ? cacheNodeInterop : cacheBabelInterop; })(nodeInterop); } function _interop_require_wildcard(obj, nodeInterop) { if (!nodeInterop && obj && obj.__esModule) { return obj; } if (obj === null || typeof obj !== "object" && typeof obj !== "function") { return { default: obj }; } var cache = _getRequireWildcardCache(nodeInterop); if (cache && cache.has(obj)) { return cache.get(obj); } var newObj = { __proto__: null }; var hasPropertyDescriptor = Object.defineProperty && Object.getOwnPropertyDescriptor; for(var key in obj){ if (key !== "default" && Object.prototype.hasOwnProperty.call(obj, key)) { var desc = hasPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : null; if (desc && (desc.get || desc.set)) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } newObj.default = obj; if (cache) { cache.set(obj, newObj); } return newObj; } console.log("*****", (0, _template.compile)("Hello #{name + child.age}!")[2]); (0, _nodetest.describe)("template", ()=>{ (0, _nodetest.it)("Basic string template", async (t)=>{ const render = (0, _template.default)("Hello #{name}!"); const result = await render({ name: "World" }); _nodeassert.default.strictEqual(result, "Hello World!"); }); (0, _nodetest.it)("Template literal syntax", async (t)=>{ const name = "World"; const result = await (0, _template.default)`Hello ${name}!`; _nodeassert.default.strictEqual(result, "Hello World!"); }); (0, _nodetest.it)("Multiple placeholders", async (t)=>{ const render = (0, _template.default)("Hello #{firstName} #{lastName}!"); const result = await render({ firstName: "John", lastName: "Doe" }); _nodeassert.default.strictEqual(result, "Hello John Doe!"); }); (0, _nodetest.it)("Expression evaluation", async (t)=>{ const render = (0, _template.default)("The answer is #{a + b}!"); const result = await render({ a: 20, b: 22 }); _nodeassert.default.strictEqual(result, "The answer is 42!"); }); (0, _nodetest.it)("Using array index", async (t)=>{ const render = (0, _template.default)("First item: #{items[0]}"); const result = await render({ items: [ "apple", "banana", "cherry" ] }); _nodeassert.default.strictEqual(result, "First item: apple"); }); (0, _nodetest.it)("Nested properties", async (t)=>{ const render = (0, _template.default)("Welcome, #{user.profile.name}!"); const result = await render({ user: { profile: { name: "Alice" } } }); _nodeassert.default.strictEqual(result, "Welcome, Alice!"); }); (0, _nodetest.it)("Function execution", async (t)=>{ const render = (0, _template.default)("Calculated: #{calculate()}"); const result = await render({ calculate: ()=>100 * 2 }); _nodeassert.default.strictEqual(result, "Calculated: 200"); }); (0, _nodetest.it)("Missing data should render empty string", async (t)=>{ const render = (0, _template.default)("Value: #{missing}!"); const result = await render({}); _nodeassert.default.strictEqual(result, "Value: !"); }); (0, _nodetest.it)("Streaming capability - pipe to another stream", async (t)=>{ const render = (0, _template.default)("Hello #{name}!"); const stream = render({ name: "Stream" }); // Create a writable stream to collect data let collected = ""; const writable = new _nodestream.Writable({ write (chunk, encoding, callback) { collected += chunk.toString(); callback(); } }); // Pipe and wait for completion stream.pipe(writable); await new Promise((resolve)=>stream.on("end", resolve)); _nodeassert.default.strictEqual(collected, "Hello Stream!"); }); (0, _nodetest.it)("Stream as a placeholder value", async (t)=>{ const render = (0, _template.default)("Content: #{content}"); const contentStream = new _nodestream.Readable({ read () { this.push("streamed content"); this.push(null); } }); const result = await render({ content: contentStream }); _nodeassert.default.strictEqual(result, "Content: streamed content"); }); (0, _nodetest.it)("Promise as a placeholder value", async (t)=>{ const render = (0, _template.default)("Async value: #{asyncValue}"); const result = await render({ asyncValue: Promise.resolve("resolved") }); _nodeassert.default.strictEqual(result, "Async value: resolved"); }); (0, _nodetest.it)("Numbers, booleans, and null values", async (t)=>{ const render = (0, _template.default)("Number: #{num}, Boolean: #{bool}, Null: #{nil}"); const result = await render({ num: 42, bool: true, nil: null }); _nodeassert.default.strictEqual(result, "Number: 42, Boolean: true, Null: "); }); (0, _nodetest.it)("Complex expressions", async (t)=>{ const render = (0, _template.default)("Result: #{a * 2 + (b > 10 ? 100 : 0)}"); await t.test("Branch one", async ()=>{ const result = await render({ a: 5, b: 15 }); _nodeassert.default.strictEqual(result, "Result: 110"); }); await t.test("Branch two", async ()=>{ const result = await render({ a: 5, b: 5 }); _nodeassert.default.strictEqual(result, "Result: 10"); }); }); (0, _nodetest.it)("Template with no placeholders", async (t)=>{ const render = (0, _template.default)("Static content"); const result = await render(); _nodeassert.default.strictEqual(result, "Static content"); }); // TODO should we trigger error or comsider a?.missing?.property? // it('Error in expression evaluation', async (t) => { // const render = template('Bad: #{a.missing.property}') // await assert.rejects(async () => { // await render({ a: {} }) // }, { // name: 'TypeError' // }) // }) (0, _nodetest.it)("Using string literals in expressions", async (t)=>{ const render = (0, _template.default)('With quotes: #{name + " " + "quoted"}'); const result = await render({ name: "String" }); _nodeassert.default.strictEqual(result, "With quotes: String quoted"); }); (0, _nodetest.it)("Object method invocation in template", async (t)=>{ const render = (0, _template.default)("Uppercase: #{name.toUpperCase()}"); const result = await render({ name: "convert" }); _nodeassert.default.strictEqual(result, "Uppercase: CONVERT"); }); (0, _nodetest.it)("Multiple template renderings with same engine", async (t)=>{ const render = (0, _template.default)("Hello #{name}!"); const result1 = await render({ name: "First" }); _nodeassert.default.strictEqual(result1, "Hello First!"); const result2 = await render({ name: "Second" }); _nodeassert.default.strictEqual(result2, "Hello Second!"); }); (0, _nodetest.it)("Empty template string", async (t)=>{ const render = (0, _template.default)(""); const result = await render(); _nodeassert.default.strictEqual(result, ""); }); // TODO this should work // it('Sequential placeholders', async (t) => { // const render = template('#{a}#{b}#{c}') // const result = await render({ a: 'Hello', b: ' ', c: 'World' }) // assert.strictEqual(result, 'Hello World') // }) (0, _nodetest.it)("Function returning another stream as placeholder", async (t)=>{ const render = (0, _template.default)("Content: #{getContent()}"); const result = await render({ getContent: ()=>{ return new _nodestream.Readable({ read () { this.push("nested stream"); this.push(null); } }); } }); _nodeassert.default.strictEqual(result, "Content: nested stream"); }); // TODO this should work // it('Math expressions', async (t) => { // const render = template('Math: #{Math.floor(3.14159)}') // const result = await render({}) // assert.strictEqual(result, 'Math: 3') // }) (0, _nodetest.it)("Data object is optional", async (t)=>{ const render = (0, _template.default)("Static #{1 + 1}"); const result = await render(); // No data object passed _nodeassert.default.strictEqual(result, "Static 2"); }); // it('Advanced stream handling', async (t) => { // await t.test('Nested streams', async () => { // const render = template('Nested: #{outer}') // const innerStream = new Readable({ // read() { // this.push('inner content') // this.push(null) // } // }) // const outerStream = new Readable({ // read() { // this.push('begin-') // this.push(innerStream) // this.push('-end') // this.push(null) // } // }) // // This test will fail unless the template engine properly handles // // stream objects within streams, which isn't typical behavior // try { // const result = await render({ outer: outerStream }) // console.log('RESULT', result) // assert.strictEqual(result, 'Nested: begin-inner content-end') // } catch (err) { // // Alternatively, check that it fails predictably // assert.strictEqual(err.code, 'ERR_INVALID_ARG_TYPE') // } // }) // await t.test('Transform stream as placeholder', async () => { // const render = template('Transformed: #{transformer}') // const transformer = new Transform({ // transform(chunk, encoding, callback) { // this.push(chunk.toString().toUpperCase()) // callback() // } // }) // // Write to the transform stream after setting it as a placeholder // setTimeout(() => { // transformer.write('lowercase') // transformer.end() // }, 10) // const result = await render({ transformer }) // assert.strictEqual(result, 'Transformed: LOWERCASE') // }) // }) // it('Error handling', async (t) => { // await t.test('Function throwing error', async () => { // const render = template('Error: #{throwError()}') // await assert.rejects(async () => { // await render({ // throwError: () => { throw new Error('Test error') } // }) // }, { // message: 'Test error' // }) // }) // await t.test('Stream emitting error', async () => { // const render = template('Stream error: #{errorStream}') // const errorStream = new Readable({ // read() { // this.emit('error', new Error('Stream error')) // } // }) // await assert.rejects(async () => { // await render({ errorStream }) // }, { // message: 'Stream error' // }) // }) // await t.test('Promise rejection', async () => { // const render = template('Promise rejection: #{failingPromise}') // await assert.rejects(async () => { // await render({ // failingPromise: Promise.reject(new Error('Promise failed')) // }) // }, { // message: 'Promise failed' // }) // }) // }) // it('Edge cases', async (t) => { // await t.test('Extremely large template', async () => { // // Create a large template with many placeholders // const placeholders = 1000 // let largeTemplate = '' // let expectedResult = '' // for (let i = 0; i < placeholders; i++) { // largeTemplate += `#{n${i}}` // expectedResult += i.toString() // } // // Create data object with all placeholders // const data = {} // for (let i = 0; i < placeholders; i++) { // data[`n${i}`] = i // } // const render = template(largeTemplate) // const result = await render(data) // assert.strictEqual(result, expectedResult) // }) // await t.test('Circular references in data', async () => { // const render = template('Value: #{obj.value}') // const data = { obj: { value: 'test' } } // // Create circular reference // data.obj.self = data.obj // const result = await render(data) // assert.strictEqual(result, 'Value: test') // }) // await t.test('Unicode characters', async () => { // const render = template('Unicode: #{text}') // const result = await render({ // text: '你好 👋 こんにちは' // }) // assert.strictEqual(result, 'Unicode: 你好 👋 こんにちは') // }) // await t.test('Escaping placeholders', async () => { // // The engine doesn't have native support for escaping. // // This test documents expected behavior. // const render = template('Literal #{: #{value}') // const result = await render({ value: 'test' }) // // Current behavior would try to evaluate '{: #{value' as an expression // // This might error or produce unexpected results // try { // assert.ok(result.includes('test') || result.includes('error')) // } catch (err) { // // Expected to potentially fail // assert.ok(err) // } // }) // }) // it('Performance benchmark', async (t) => { // const render = template('#{value}') // // Measure time for 1000 renderings // const start = performance.now() // for (let i = 0; i < 1000; i++) { // await render({ value: 'test' }) // } // const duration = performance.now() - start // // This is not a strict test, just informational // console.log(`Performed 1000 renderings in ${duration}ms (${duration/1000}ms per render)`) // assert.ok(true) // Just to have an assertion // }) // it('Template literal placeholder injection', async (t) => { // await t.test('Template literals with expressions', async () => { // const x = 10 // const y = 5 // const tmpl = template`Sum: ${x + y}, Product: ${x * y}` // const result = await tmpl // assert.strictEqual(result, 'Sum: 15, Product: 50') // }) // await t.test('Template literals with functions', async () => { // const getGreeting = () => 'Hello' // const getName = () => 'Template' // const tmpl = template`${getGreeting()} ${getName()}!` // const result = await tmpl // assert.strictEqual(result, 'Hello Template!') // }) // await t.test('Template literals with nested templates', async () => { // const innerTemplate = template`inner` // const outerTemplate = template`outer ${await innerTemplate}` // const result = await outerTemplate // assert.strictEqual(result, 'outer inner') // }) // }) // it('Parse function tests', async (t) => { // // These tests are intended to verify the behavior of the internal parse function // await t.test('Parsing dot notation', async () => { // const render = template('Test: #{a.b.c}') // const result = await render({ a: { b: { c: 'nested' } } }) // assert.strictEqual(result, 'Test: nested') // }) // await t.test('Parsing array access', async () => { // const render = template('Test: #{arr[0][1]}') // const result = await render({ arr: [['a', 'b'], ['c', 'd']] }) // assert.strictEqual(result, 'Test: b') // }) // await t.test('Parsing string literals', async () => { // const render = template('Test: #{"static string"}') // const result = await render({}) // assert.strictEqual(result, 'Test: static string') // }) // await t.test('Parsing with regex', async () => { // // Current implementation doesn't handle regex patterns in expressions // // This test documents expected behavior // const render = template('Test: #{/test/.it(value)}') // try { // const result = await render({ value: 'test' }) // assert.strictEqual(result, 'Test: true') // } catch (err) { // // If it fails, that's the current implementation limitation // assert.ok(err) // } // }) // }) // it('Using the template engine in different ways', async (t) => { // await t.test('Streaming to file', async () => { // const render = template('File content with #{value}') // const stream = render({ value: 'data' }) // // Simulate writing to file with a proper Writable stream // let fileContent = '' // const { Writable } = await import('node:stream') // const fileStream = new Writable({ // write(chunk, encoding, callback) { // fileContent += chunk.toString() // callback() // } // }) // stream.pipe(fileStream) // await new Promise(resolve => stream.on('end', resolve)) // assert.strictEqual(fileContent, 'File content with data') // }) // await t.test('Async iteration of template result', async () => { // const render = template('Before #{middle} after') // const stream = render({ middle: 'content' }) // let result = '' // for await (const chunk of stream) { // result += chunk // } // assert.strictEqual(result, 'Before content after') // }) // }) });