@doki-land/dejavu-engine 0.0.14 → 0.0.15

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.
@@ -0,0 +1,15 @@
1
+ /**
2
+ * Structured runtime error for generated AOT modules.
3
+ *
4
+ * Generated code never throws a bare `Error`: every failure carries the stable
5
+ * diagnostic `code`, the `render` stage, structured `args` and a human-readable
6
+ * message so hosts can classify errors without parsing `message`.
7
+ */
8
+ export declare class DejavuRuntimeError extends Error {
9
+ readonly code: string;
10
+ readonly stage = "render";
11
+ readonly args: Record<string, unknown>;
12
+ constructor(code: string, detail?: string, args?: Record<string, unknown>);
13
+ }
14
+ /** Build a structured render error. */
15
+ export declare function runtimeError(code: string, detail?: string, args?: Record<string, unknown>): DejavuRuntimeError;
@@ -0,0 +1,22 @@
1
+ /**
2
+ * Structured runtime error for generated AOT modules.
3
+ *
4
+ * Generated code never throws a bare `Error`: every failure carries the stable
5
+ * diagnostic `code`, the `render` stage, structured `args` and a human-readable
6
+ * message so hosts can classify errors without parsing `message`.
7
+ */
8
+ export class DejavuRuntimeError extends Error {
9
+ code;
10
+ stage = "render";
11
+ args;
12
+ constructor(code, detail, args) {
13
+ super(detail ? `${code}: ${detail}` : code);
14
+ this.name = "DejavuRuntimeError";
15
+ this.code = code;
16
+ this.args = args ?? {};
17
+ }
18
+ }
19
+ /** Build a structured render error. */
20
+ export function runtimeError(code, detail, args) {
21
+ return new DejavuRuntimeError(code, detail, args);
22
+ }
@@ -1,4 +1,5 @@
1
1
  import { htmlEscape } from "./escape.js";
2
+ import { runtimeError } from "./errors.js";
2
3
  import { valueToString } from "./value.js";
3
4
  /** 与 Rust `dejavu_ir::registry::FILTERS` 同序同构的静态描述。 */
4
5
  export const FILTERS = [
@@ -20,11 +21,16 @@ export function filterSpec(name) {
20
21
  export function applyFilter(name, value, args) {
21
22
  const spec = filterSpec(name);
22
23
  if (!spec) {
23
- throw new Error(`dejavu.template.unknown-filter: ${name}`);
24
+ throw runtimeError("dejavu.template.unknown-filter", name, { filter: name });
24
25
  }
25
26
  if (args.length < spec.minArgs || args.length > spec.maxArgs) {
26
- throw new Error(`dejavu.template.filter-arity: ${spec.name} expects ` +
27
- `${spec.minArgs}..${spec.maxArgs} argument(s), got ${args.length}`);
27
+ throw runtimeError("dejavu.template.filter-arity", `${spec.name} expects ` +
28
+ `${spec.minArgs}..${spec.maxArgs} argument(s), got ${args.length}`, {
29
+ filter: spec.name,
30
+ minArgs: spec.minArgs,
31
+ maxArgs: spec.maxArgs,
32
+ got: args.length,
33
+ });
28
34
  }
29
35
  switch (name) {
30
36
  case "escape":
@@ -77,7 +83,7 @@ export function applyFilter(name, value, args) {
77
83
  return slugify(valueToString(value));
78
84
  default:
79
85
  // Unreachable: `filterSpec` already rejected unknown names.
80
- throw new Error(`dejavu.template.unknown-filter: ${name}`);
86
+ throw runtimeError("dejavu.template.unknown-filter", name);
81
87
  }
82
88
  }
83
89
  /**
@@ -9,6 +9,7 @@ export interface FunctionSpec {
9
9
  aliases: string[];
10
10
  minArgs: number;
11
11
  maxArgs: number;
12
+ capability: string;
12
13
  }
13
14
  /** 与 Rust `dejavu_ir::registry::FUNCTIONS` 同序同构的静态描述。 */
14
15
  export declare const FUNCTIONS: readonly FunctionSpec[];
@@ -4,11 +4,12 @@
4
4
  * 与 Rust `dejavu_ir::registry::FUNCTIONS` 和 `builtins::call_function` 对齐。
5
5
  * 仅允许 `name(args)` 形式的裸标识符调用;成员调用与未知名字一律报错。
6
6
  */
7
+ import { runtimeError } from "./errors.js";
7
8
  /** 与 Rust `dejavu_ir::registry::FUNCTIONS` 同序同构的静态描述。 */
8
9
  export const FUNCTIONS = [
9
- { name: "range", aliases: [], minArgs: 2, maxArgs: 3 },
10
- { name: "min", aliases: [], minArgs: 2, maxArgs: 2 },
11
- { name: "max", aliases: [], minArgs: 2, maxArgs: 2 },
10
+ { name: "range", aliases: [], minArgs: 2, maxArgs: 3, capability: "pure" },
11
+ { name: "min", aliases: [], minArgs: 2, maxArgs: 2, capability: "pure" },
12
+ { name: "max", aliases: [], minArgs: 2, maxArgs: 2, capability: "pure" },
12
13
  ];
13
14
  /** `range` 允许产出的最大元素数,与 Rust `RANGE_LIMIT` 一致。 */
14
15
  const RANGE_LIMIT = 10_000;
@@ -18,11 +19,16 @@ export function functionSpec(name) {
18
19
  export function callFunction(name, args) {
19
20
  const spec = functionSpec(name);
20
21
  if (!spec) {
21
- throw new Error(`dejavu.template.unknown-function: ${name}`);
22
+ throw runtimeError("dejavu.template.unknown-function", name, { function: name });
22
23
  }
23
24
  if (args.length < spec.minArgs || args.length > spec.maxArgs) {
24
- throw new Error(`dejavu.template.function-arity: ${spec.name} expects ` +
25
- `${spec.minArgs}..${spec.maxArgs} argument(s), got ${args.length}`);
25
+ throw runtimeError("dejavu.template.function-arity", `${spec.name} expects ` +
26
+ `${spec.minArgs}..${spec.maxArgs} argument(s), got ${args.length}`, {
27
+ function: spec.name,
28
+ minArgs: spec.minArgs,
29
+ maxArgs: spec.maxArgs,
30
+ got: args.length,
31
+ });
26
32
  }
27
33
  switch (spec.name) {
28
34
  case "range":
@@ -33,7 +39,7 @@ export function callFunction(name, args) {
33
39
  return numericPair(args, false);
34
40
  default:
35
41
  // Unreachable: `functionSpec` already rejected unknown names.
36
- throw new Error(`dejavu.template.unknown-function: ${name}`);
42
+ throw runtimeError("dejavu.template.unknown-function", name);
37
43
  }
38
44
  }
39
45
  /** `range(start, stop, step=1)`,非法输入按值模型规则返回 null。 */
@@ -5,6 +5,7 @@
5
5
  * 与 Rust `dejavu-codegen` Node stub 以及 `dejavu-types` 的 filter 系统语义一致。
6
6
  */
7
7
  export { htmlEscape } from "./escape.js";
8
+ export { DejavuRuntimeError, runtimeError } from "./errors.js";
8
9
  export { valueToString, isTruthy, valuesEqual } from "./value.js";
9
10
  export { applyFilter } from "./filter.js";
10
11
  export { FUNCTIONS, functionSpec, callFunction } from "./function.js";
@@ -5,6 +5,7 @@
5
5
  * 与 Rust `dejavu-codegen` Node stub 以及 `dejavu-types` 的 filter 系统语义一致。
6
6
  */
7
7
  export { htmlEscape } from "./escape.js";
8
+ export { DejavuRuntimeError, runtimeError } from "./errors.js";
8
9
  export { valueToString, isTruthy, valuesEqual } from "./value.js";
9
10
  export { applyFilter } from "./filter.js";
10
11
  export { FUNCTIONS, functionSpec, callFunction } from "./function.js";
@@ -10,6 +10,7 @@ export interface TestSpec {
10
10
  aliases: string[];
11
11
  minArgs: number;
12
12
  maxArgs: number;
13
+ capability: string;
13
14
  }
14
15
  /** 与 Rust `dejavu_ir::registry::TESTS` 同序同构的静态描述。 */
15
16
  export declare const TESTS: readonly TestSpec[];
@@ -5,19 +5,20 @@
5
5
  * 语法为 `expr is name` / `expr is not name` / `expr is name(args)`,
6
6
  * 本文件只负责对已求值的左值执行谓词。
7
7
  */
8
+ import { runtimeError } from "./errors.js";
8
9
  import { isTruthy } from "./value.js";
9
10
  /** 与 Rust `dejavu_ir::registry::TESTS` 同序同构的静态描述。 */
10
11
  export const TESTS = [
11
- { name: "null", aliases: ["none"], minArgs: 0, maxArgs: 0 },
12
- { name: "truthy", aliases: [], minArgs: 0, maxArgs: 0 },
13
- { name: "empty", aliases: [], minArgs: 0, maxArgs: 0 },
14
- { name: "array", aliases: [], minArgs: 0, maxArgs: 0 },
15
- { name: "object", aliases: [], minArgs: 0, maxArgs: 0 },
16
- { name: "string", aliases: [], minArgs: 0, maxArgs: 0 },
17
- { name: "number", aliases: [], minArgs: 0, maxArgs: 0 },
18
- { name: "boolean", aliases: [], minArgs: 0, maxArgs: 0 },
19
- { name: "even", aliases: [], minArgs: 0, maxArgs: 0 },
20
- { name: "odd", aliases: [], minArgs: 0, maxArgs: 0 },
12
+ { name: "null", aliases: ["none"], minArgs: 0, maxArgs: 0, capability: "pure" },
13
+ { name: "truthy", aliases: [], minArgs: 0, maxArgs: 0, capability: "pure" },
14
+ { name: "empty", aliases: [], minArgs: 0, maxArgs: 0, capability: "pure" },
15
+ { name: "array", aliases: [], minArgs: 0, maxArgs: 0, capability: "pure" },
16
+ { name: "object", aliases: [], minArgs: 0, maxArgs: 0, capability: "pure" },
17
+ { name: "string", aliases: [], minArgs: 0, maxArgs: 0, capability: "pure" },
18
+ { name: "number", aliases: [], minArgs: 0, maxArgs: 0, capability: "pure" },
19
+ { name: "boolean", aliases: [], minArgs: 0, maxArgs: 0, capability: "pure" },
20
+ { name: "even", aliases: [], minArgs: 0, maxArgs: 0, capability: "pure" },
21
+ { name: "odd", aliases: [], minArgs: 0, maxArgs: 0, capability: "pure" },
21
22
  ];
22
23
  export function testSpec(name) {
23
24
  return TESTS.find((spec) => spec.name === name || spec.aliases.includes(name));
@@ -26,11 +27,16 @@ export function testSpec(name) {
26
27
  export function applyTest(name, value, args, negated = false) {
27
28
  const spec = testSpec(name);
28
29
  if (!spec) {
29
- throw new Error(`dejavu.template.unknown-test: ${name}`);
30
+ throw runtimeError("dejavu.template.unknown-test", name, { test: name });
30
31
  }
31
32
  if (args.length < spec.minArgs || args.length > spec.maxArgs) {
32
- throw new Error(`dejavu.template.test-arity: ${spec.name} expects ` +
33
- `${spec.minArgs}..${spec.maxArgs} argument(s), got ${args.length}`);
33
+ throw runtimeError("dejavu.template.test-arity", `${spec.name} expects ` +
34
+ `${spec.minArgs}..${spec.maxArgs} argument(s), got ${args.length}`, {
35
+ test: spec.name,
36
+ minArgs: spec.minArgs,
37
+ maxArgs: spec.maxArgs,
38
+ got: args.length,
39
+ });
34
40
  }
35
41
  let result;
36
42
  switch (spec.name) {
@@ -69,7 +75,7 @@ export function applyTest(name, value, args, negated = false) {
69
75
  break;
70
76
  default:
71
77
  // Unreachable: `testSpec` already rejected unknown names.
72
- throw new Error(`dejavu.template.unknown-test: ${name}`);
78
+ throw runtimeError("dejavu.template.unknown-test", name);
73
79
  }
74
80
  return result !== negated;
75
81
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@doki-land/dejavu-engine",
3
- "version": "0.0.14",
3
+ "version": "0.0.15",
4
4
  "description": "Dejavu pure TypeScript AOT runtime — generated template modules depend on this package",
5
5
  "type": "module",
6
6
  "license": "MPL-2.0",