sensai
Version:
Because even AI needs a master
479 lines (478 loc) • 18.6 kB
JavaScript
"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')
// })
// })
});