behavior-contracts 0.1.3 → 0.2.0

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.
Files changed (62) hide show
  1. package/README.md +8 -2
  2. package/dist/authoring.d.ts +202 -0
  3. package/dist/authoring.d.ts.map +1 -0
  4. package/dist/authoring.js +787 -0
  5. package/dist/authoring.js.map +1 -0
  6. package/dist/behavior.d.ts +201 -0
  7. package/dist/behavior.d.ts.map +1 -0
  8. package/dist/behavior.js +373 -0
  9. package/dist/behavior.js.map +1 -0
  10. package/dist/builder.d.ts +154 -0
  11. package/dist/builder.d.ts.map +1 -0
  12. package/dist/builder.js +574 -0
  13. package/dist/builder.js.map +1 -0
  14. package/dist/generator/core.d.ts +89 -0
  15. package/dist/generator/core.d.ts.map +1 -0
  16. package/dist/generator/core.js +124 -0
  17. package/dist/generator/core.js.map +1 -0
  18. package/dist/generator/emit-go.d.ts +19 -0
  19. package/dist/generator/emit-go.d.ts.map +1 -0
  20. package/dist/generator/emit-go.js +79 -0
  21. package/dist/generator/emit-go.js.map +1 -0
  22. package/dist/generator/emit-php.d.ts +20 -0
  23. package/dist/generator/emit-php.d.ts.map +1 -0
  24. package/dist/generator/emit-php.js +76 -0
  25. package/dist/generator/emit-php.js.map +1 -0
  26. package/dist/generator/emit-python.d.ts +10 -0
  27. package/dist/generator/emit-python.d.ts.map +1 -0
  28. package/dist/generator/emit-python.js +75 -0
  29. package/dist/generator/emit-python.js.map +1 -0
  30. package/dist/generator/emit-rust.d.ts +25 -0
  31. package/dist/generator/emit-rust.d.ts.map +1 -0
  32. package/dist/generator/emit-rust.js +125 -0
  33. package/dist/generator/emit-rust.js.map +1 -0
  34. package/dist/generator/emit-typescript.d.ts +11 -0
  35. package/dist/generator/emit-typescript.d.ts.map +1 -0
  36. package/dist/generator/emit-typescript.js +68 -0
  37. package/dist/generator/emit-typescript.js.map +1 -0
  38. package/dist/generator/fingerprint.d.ts +14 -0
  39. package/dist/generator/fingerprint.d.ts.map +1 -0
  40. package/dist/generator/fingerprint.js +74 -0
  41. package/dist/generator/fingerprint.js.map +1 -0
  42. package/dist/generator/index.d.ts +9 -0
  43. package/dist/generator/index.d.ts.map +1 -0
  44. package/dist/generator/index.js +25 -0
  45. package/dist/generator/index.js.map +1 -0
  46. package/dist/generator/literal.d.ts +8 -0
  47. package/dist/generator/literal.d.ts.map +1 -0
  48. package/dist/generator/literal.js +191 -0
  49. package/dist/generator/literal.js.map +1 -0
  50. package/dist/guard.d.ts +18 -0
  51. package/dist/guard.d.ts.map +1 -1
  52. package/dist/guard.js +130 -0
  53. package/dist/guard.js.map +1 -1
  54. package/dist/index.d.ts +14 -3
  55. package/dist/index.d.ts.map +1 -1
  56. package/dist/index.js +15 -2
  57. package/dist/index.js.map +1 -1
  58. package/dist/plan.d.ts +36 -0
  59. package/dist/plan.d.ts.map +1 -1
  60. package/dist/plan.js +152 -14
  61. package/dist/plan.js.map +1 -1
  62. package/package.json +4 -1
@@ -0,0 +1,125 @@
1
+ import { emitDocLiteral } from "./literal.js";
2
+ function rustStrLit(s) {
3
+ // 識別子・fingerprint 用(ASCII 前提だが JSON エスケープで安全側に倒す)。
4
+ return JSON.stringify(s);
5
+ }
6
+ /** rustfmt の fits-on-one-line 規則を模倣した COMPONENT_NAMES 配列 emit。 */
7
+ function componentNamesConst(names) {
8
+ const items = names.map(rustStrLit);
9
+ const oneLine = `pub const COMPONENT_NAMES: [&str; ${names.length}] = [${items.join(", ")}];`;
10
+ if (oneLine.length <= 100)
11
+ return oneLine;
12
+ return `pub const COMPONENT_NAMES: [&str; ${names.length}] = [\n${items.map((s) => ` ${s},`).join("\n")}\n];`;
13
+ }
14
+ function emit(ctx) {
15
+ const { fingerprint, specVersions, componentNames, runtimeImport } = ctx;
16
+ const irLiteral = emitDocLiteral(ctx.ir, "rust", 1);
17
+ return `// GENERATED by behavior-contracts common generator (bc#13) — DO NOT EDIT.
18
+ // Input: portable component-graph IR only (scp-ir-architecture.md §5/§7.4).
19
+ // This module is the codegen endpoint (§7.3 endpoint 3): the IR is embedded as
20
+ // NATIVE json! constructor code (compile-time checked; no JSON-text parsing at
21
+ // runtime) and handed to the EXISTING runtime core (run_behavior) — no execution
22
+ // logic is generated. Handlers are ALWAYS injected at the boundary
23
+ // (IR + {effects,config,hooks} — concept.md §4.4); they are never generated.
24
+ //
25
+ // Const deviation (documented): serde_json::Value is not const-constructible, so
26
+ // the IR is built ONCE on first use behind std::sync::LazyLock (requires Rust
27
+ // >= 1.80). The first-use fail-closed checks (#208 prepared-artifact discipline)
28
+ // run inside the initializer: a spec-version skew or fingerprint mismatch panics
29
+ // LOUDLY before any behavior can run.
30
+ // irFingerprint: ${fingerprint}
31
+
32
+ use ${runtimeImport}::{
33
+ fingerprint_component_graph, run_behavior, BehaviorError, ComponentExec, SpecVersions, Value,
34
+ };
35
+ use serde_json::{json, Value as J};
36
+ use std::sync::LazyLock;
37
+
38
+ /// Spec versions baked at generation time (fail-closed comparison on first use).
39
+ pub const EXPECTED_SPEC_VERSIONS: [(&str, i64); 3] =
40
+ [("behavior", ${specVersions.behavior}), ("expression", ${specVersions.expression}), ("plan", ${specVersions.plan})];
41
+
42
+ /// FNV-1a 64 fingerprint of the source portable IR (canonical_json discipline, #208).
43
+ pub const IR_FINGERPRINT: &str = ${rustStrLit(fingerprint)};
44
+
45
+ /// Component names exposed by bind(), in IR declaration order.
46
+ ${componentNamesConst(componentNames)}
47
+
48
+ /// The portable component-graph IR, built once on first use from native json!
49
+ /// constructor code (no JSON-text parsing at runtime; see the const-deviation
50
+ /// note in the module header).
51
+ pub static IR: LazyLock<J> = LazyLock::new(|| {
52
+ let ir = json!(${irLiteral});
53
+ check_generated_module(&ir);
54
+ ir
55
+ });
56
+
57
+ fn runtime_spec_version(key: &str) -> i64 {
58
+ match key {
59
+ "behavior" => SpecVersions::BEHAVIOR,
60
+ "expression" => SpecVersions::EXPRESSION,
61
+ "plan" => SpecVersions::PLAN,
62
+ other => {
63
+ panic!("behavior-contracts generated module: unknown spec key '{other}' (fail-closed)")
64
+ }
65
+ }
66
+ }
67
+
68
+ // First-use fail-closed checks (#208 prepared-artifact discipline).
69
+ fn check_generated_module(ir: &J) {
70
+ for (key, want) in EXPECTED_SPEC_VERSIONS {
71
+ let got = runtime_spec_version(key);
72
+ if got != want {
73
+ panic!("behavior-contracts generated module: spec-version skew for '{key}' (generated={want}, runtime={got}) — regenerate against this runtime (fail-closed)");
74
+ }
75
+ }
76
+ for name in COMPONENT_NAMES {
77
+ let found = ir["components"]
78
+ .as_array()
79
+ .is_some_and(|cs| cs.iter().any(|c| c["name"] == name));
80
+ if !found {
81
+ panic!("behavior-contracts generated module: component '{name}' missing from the embedded IR — the generated code was modified or corrupted (fail-closed)");
82
+ }
83
+ }
84
+ let got_fp = fingerprint_component_graph(ir).unwrap_or_else(|e| {
85
+ panic!(
86
+ "behavior-contracts generated module: fingerprint recompute failed: {e} (fail-closed)"
87
+ )
88
+ });
89
+ if got_fp != IR_FINGERPRINT {
90
+ panic!("behavior-contracts generated module: IR fingerprint mismatch (baked={IR_FINGERPRINT}, embedded literal={got_fp}) — the generated code was modified or corrupted (fail-closed)");
91
+ }
92
+ }
93
+
94
+ /// Injected-handler accessor over the embedded IR (see [\`bind\`]). Rust ownership
95
+ /// makes a map of per-component closures sharing one \`&mut handlers\` impractical,
96
+ /// so the per-component executor surface is \`call(name, input)\` with the
97
+ /// component name checked against [\`COMPONENT_NAMES\`] by the runtime core.
98
+ pub struct Bound<H: ComponentExec> {
99
+ handlers: H,
100
+ }
101
+
102
+ /// bind — inject handlers (boundary injection; catalog name → implementation)
103
+ /// and get an executor over the embedded IR. Each \`call\` delegates to the
104
+ /// runtime core's run_behavior (dynamic-path equivalent — §7.3). Forces the
105
+ /// first-use fail-closed checks.
106
+ pub fn bind<H: ComponentExec>(handlers: H) -> Bound<H> {
107
+ LazyLock::force(&IR);
108
+ Bound { handlers }
109
+ }
110
+
111
+ impl<H: ComponentExec> Bound<H> {
112
+ pub fn call(&mut self, name: &str, input: &[(String, Value)]) -> Result<Value, BehaviorError> {
113
+ run_behavior(&IR, &mut self.handlers, input, Some(name))
114
+ }
115
+ }
116
+ `;
117
+ }
118
+ export const rustEmitter = {
119
+ language: "rust",
120
+ fileExtension: ".rs",
121
+ defaultRuntimeImport: "behavior_contracts",
122
+ filenameHint: "behaviors_generated.rs",
123
+ emit,
124
+ };
125
+ //# sourceMappingURL=emit-rust.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"emit-rust.js","sourceRoot":"","sources":["../../src/generator/emit-rust.ts"],"names":[],"mappings":"AAuBA,OAAO,EAAE,cAAc,EAAE,MAAM,cAAc,CAAC;AAE9C,SAAS,UAAU,CAAC,CAAS;IAC3B,mDAAmD;IACnD,OAAO,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC;AAC3B,CAAC;AAED,kEAAkE;AAClE,SAAS,mBAAmB,CAAC,KAAe;IAC1C,MAAM,KAAK,GAAG,KAAK,CAAC,GAAG,CAAC,UAAU,CAAC,CAAC;IACpC,MAAM,OAAO,GAAG,qCAAqC,KAAK,CAAC,MAAM,QAAQ,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC;IAC9F,IAAI,OAAO,CAAC,MAAM,IAAI,GAAG;QAAE,OAAO,OAAO,CAAC;IAC1C,OAAO,qCAAqC,KAAK,CAAC,MAAM,UAAU,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC;AACnH,CAAC;AAED,SAAS,IAAI,CAAC,GAAgB;IAC5B,MAAM,EAAE,WAAW,EAAE,YAAY,EAAE,cAAc,EAAE,aAAa,EAAE,GAAG,GAAG,CAAC;IACzE,MAAM,SAAS,GAAG,cAAc,CAAC,GAAG,CAAC,EAAE,EAAE,MAAM,EAAE,CAAC,CAAC,CAAC;IACpD,OAAO;;;;;;;;;;;;;oBAaW,WAAW;;MAEzB,aAAa;;;;;;;;oBAQC,YAAY,CAAC,QAAQ,qBAAqB,YAAY,CAAC,UAAU,eAAe,YAAY,CAAC,IAAI;;;mCAGlF,UAAU,CAAC,WAAW,CAAC;;;EAGxD,mBAAmB,CAAC,cAAc,CAAC;;;;;;qBAMhB,SAAS;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAgE7B,CAAC;AACF,CAAC;AAED,MAAM,CAAC,MAAM,WAAW,GAAkB;IACxC,QAAQ,EAAE,MAAM;IAChB,aAAa,EAAE,KAAK;IACpB,oBAAoB,EAAE,oBAAoB;IAC1C,YAAY,EAAE,wBAAwB;IACtC,IAAI;CACL,CAAC"}
@@ -0,0 +1,11 @@
1
+ /**
2
+ * emit-typescript.ts — TS emitter(共通 Generator, bc#13 SP1)。
3
+ *
4
+ * 生成物: 可搬 IR を **型付き const リテラル**(`ComponentGraphIR`)として埋め込み、
5
+ * runtime-core の `runBehavior` / `runBehaviorAsync` に handler 注入で渡す薄い accessor
6
+ * (`bind` / `bindAsync`)を公開する TS モジュール。実行ロジックは一切生成しない。
7
+ * 型付けにより runtime API / IR / generator のドリフトはコンパイルエラーになる(目的2)。
8
+ */
9
+ import type { EmitterPlugin } from "./core.js";
10
+ export declare const typescriptEmitter: EmitterPlugin;
11
+ //# sourceMappingURL=emit-typescript.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"emit-typescript.d.ts","sourceRoot":"","sources":["../../src/generator/emit-typescript.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AACH,OAAO,KAAK,EAAe,aAAa,EAAE,MAAM,WAAW,CAAC;AAgE5D,eAAO,MAAM,iBAAiB,EAAE,aAK/B,CAAC"}
@@ -0,0 +1,68 @@
1
+ import { emitDocLiteral } from "./literal.js";
2
+ function emit(ctx) {
3
+ const { fingerprint, specVersions, componentNames, runtimeImport } = ctx;
4
+ const spec = runtimeImport;
5
+ const names = componentNames.map((n) => JSON.stringify(n)).join(", ");
6
+ const irLiteral = emitDocLiteral(ctx.ir, "ts");
7
+ return `// GENERATED by behavior-contracts common generator (bc#13) — DO NOT EDIT.
8
+ // Input: portable component-graph IR only (scp-ir-architecture.md §5/§7.4).
9
+ // This module is the codegen endpoint (§7.3 endpoint 3): the IR is embedded as a
10
+ // typed native literal and handed to the EXISTING runtime core (runBehavior) —
11
+ // no execution logic is generated. Handlers are ALWAYS injected at the boundary
12
+ // (IR + {effects,config,hooks} — concept.md §4.4); they are never generated.
13
+ // irFingerprint: ${fingerprint}
14
+ import { SPEC_VERSIONS, fingerprintComponentGraph, runBehavior, runBehaviorAsync } from ${JSON.stringify(spec)};
15
+ import type { AsyncHandlers, ComponentGraphIR, Handlers, Scope, Value } from ${JSON.stringify(spec)};
16
+
17
+ /** Spec versions baked at generation time (fail-closed constant comparison at load). */
18
+ export const EXPECTED_SPEC_VERSIONS = { behavior: ${specVersions.behavior}, expression: ${specVersions.expression}, plan: ${specVersions.plan} } as const;
19
+
20
+ /** FNV-1a 64 fingerprint of the source portable IR (canonicalJson discipline, #208). */
21
+ export const IR_FINGERPRINT = ${JSON.stringify(fingerprint)};
22
+
23
+ /** Component names exposed by bind()/bindAsync(), in IR declaration order. */
24
+ export const COMPONENT_NAMES: readonly string[] = [${names}];
25
+
26
+ /** The portable component-graph IR, embedded as a typed native literal (no JSON parse at runtime). */
27
+ export const IR: ComponentGraphIR = ${irLiteral};
28
+
29
+ // ── load-time fail-closed checks (#208 prepared-artifact discipline) ─────────
30
+ for (const [k, want] of Object.entries(EXPECTED_SPEC_VERSIONS)) {
31
+ const got = (SPEC_VERSIONS as Record<string, number>)[k];
32
+ if (got !== want)
33
+ throw new Error(
34
+ \`behavior-contracts generated module: spec-version skew for '\${k}' (generated=\${want}, runtime=\${got}) — regenerate against this runtime (fail-closed)\`,
35
+ );
36
+ }
37
+ if (fingerprintComponentGraph(IR) !== IR_FINGERPRINT)
38
+ throw new Error(
39
+ \`behavior-contracts generated module: IR fingerprint mismatch (baked=\${IR_FINGERPRINT}, embedded literal=\${fingerprintComponentGraph(IR)}) — the generated code was modified or corrupted (fail-closed)\`,
40
+ );
41
+
42
+ /**
43
+ * bind — inject handlers (boundary injection; catalog name → implementation) and
44
+ * get one callable per component. Each call delegates to the runtime core's
45
+ * runBehavior over the embedded IR (dynamic-path equivalent — §7.3).
46
+ */
47
+ export function bind(handlers: Handlers): Record<string, (input?: Scope) => Value> {
48
+ const bound: Record<string, (input?: Scope) => Value> = {};
49
+ for (const name of COMPONENT_NAMES) bound[name] = (input: Scope = {}) => runBehavior(IR, handlers, input, name);
50
+ return bound;
51
+ }
52
+
53
+ /** bindAsync — as bind, over runBehaviorAsync (bounded stage parallelism per plan.concurrency). */
54
+ export function bindAsync(handlers: AsyncHandlers): Record<string, (input?: Scope) => Promise<Value>> {
55
+ const bound: Record<string, (input?: Scope) => Promise<Value>> = {};
56
+ for (const name of COMPONENT_NAMES)
57
+ bound[name] = (input: Scope = {}) => runBehaviorAsync(IR, handlers, input, name);
58
+ return bound;
59
+ }
60
+ `;
61
+ }
62
+ export const typescriptEmitter = {
63
+ language: "typescript",
64
+ fileExtension: ".ts",
65
+ defaultRuntimeImport: "behavior-contracts",
66
+ emit,
67
+ };
68
+ //# sourceMappingURL=emit-typescript.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"emit-typescript.js","sourceRoot":"","sources":["../../src/generator/emit-typescript.ts"],"names":[],"mappings":"AASA,OAAO,EAAE,cAAc,EAAE,MAAM,cAAc,CAAC;AAE9C,SAAS,IAAI,CAAC,GAAgB;IAC5B,MAAM,EAAE,WAAW,EAAE,YAAY,EAAE,cAAc,EAAE,aAAa,EAAE,GAAG,GAAG,CAAC;IACzE,MAAM,IAAI,GAAG,aAAa,CAAC;IAC3B,MAAM,KAAK,GAAG,cAAc,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IACtE,MAAM,SAAS,GAAG,cAAc,CAAC,GAAG,CAAC,EAAE,EAAE,IAAI,CAAC,CAAC;IAC/C,OAAO;;;;;;oBAMW,WAAW;0FAC2D,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC;+EAC/B,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC;;;oDAG/C,YAAY,CAAC,QAAQ,iBAAiB,YAAY,CAAC,UAAU,WAAW,YAAY,CAAC,IAAI;;;gCAG7G,IAAI,CAAC,SAAS,CAAC,WAAW,CAAC;;;qDAGN,KAAK;;;sCAGpB,SAAS;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAiC9C,CAAC;AACF,CAAC;AAED,MAAM,CAAC,MAAM,iBAAiB,GAAkB;IAC9C,QAAQ,EAAE,YAAY;IACtB,aAAa,EAAE,KAAK;IACpB,oBAAoB,EAAE,oBAAoB;IAC1C,IAAI;CACL,CAAC"}
@@ -0,0 +1,14 @@
1
+ /** fingerprint 入力の不変条件違反(fail-closed)。 */
2
+ export declare class FingerprintFailure extends Error {
3
+ code: "UNSAFE_NUMBER" | "INVALID_VALUE";
4
+ constructor(code: "UNSAFE_NUMBER" | "INVALID_VALUE", message: string);
5
+ }
6
+ /**
7
+ * fingerprintComponentGraph — 可搬 IR ドキュメントの決定的 fingerprint。
8
+ *
9
+ * `"fnv1a64:<16hex>"` を返す。同一構造の IR(キー順・整数/整数値float の表記差を除く)は
10
+ * 言語(TS/Python)を跨いで同一の fingerprint になる。生成モジュールのロード時
11
+ * 自己検査・consumer 側の「live IR ↔ 生成コード」照合(#208 の prepared-loader と同型)に使う。
12
+ */
13
+ export declare function fingerprintComponentGraph(doc: unknown): string;
14
+ //# sourceMappingURL=fingerprint.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"fingerprint.d.ts","sourceRoot":"","sources":["../../src/generator/fingerprint.ts"],"names":[],"mappings":"AAuBA,0CAA0C;AAC1C,qBAAa,kBAAmB,SAAQ,KAAK;IAC3C,IAAI,EAAE,eAAe,GAAG,eAAe,CAAC;gBAC5B,IAAI,EAAE,eAAe,GAAG,eAAe,EAAE,OAAO,EAAE,MAAM;CAKrE;AA8DD;;;;;;GAMG;AACH,wBAAgB,yBAAyB,CAAC,GAAG,EAAE,OAAO,GAAG,MAAM,CAG9D"}
@@ -0,0 +1,74 @@
1
+ import { canonicalJson } from "../canonical.js";
2
+ /** fingerprint 入力の不変条件違反(fail-closed)。 */
3
+ export class FingerprintFailure extends Error {
4
+ code;
5
+ constructor(code, message) {
6
+ super(message);
7
+ this.code = code;
8
+ this.name = "FingerprintFailure";
9
+ }
10
+ }
11
+ /**
12
+ * JSON ドキュメント → Value ドメイン(整数値 number は int=bigint へ正準化)。
13
+ * canonicalJson の値モデル(bigint=int / number=float)に合わせる。
14
+ */
15
+ function toValueDomain(doc, path) {
16
+ if (doc === null || typeof doc === "boolean" || typeof doc === "string")
17
+ return doc;
18
+ if (typeof doc === "number") {
19
+ if (Number.isInteger(doc) && !Object.is(doc, -0)) {
20
+ if (Math.abs(doc) >= 2 ** 53)
21
+ throw new FingerprintFailure("UNSAFE_NUMBER", `integral number ${doc} at ${path} exceeds float64-exact range; portable IR must use {int:"..."} (fail-closed)`);
22
+ return BigInt(doc);
23
+ }
24
+ return doc; // 非整数 / -0.0 は float(canonicalJson が pyFloatRepr で直列化)
25
+ }
26
+ if (Array.isArray(doc))
27
+ return doc.map((v, i) => toValueDomain(v, `${path}[${i}]`));
28
+ if (typeof doc === "object") {
29
+ const out = {};
30
+ for (const [k, v] of Object.entries(doc))
31
+ out[k] = toValueDomain(v, `${path}.${k}`);
32
+ return out;
33
+ }
34
+ throw new FingerprintFailure("INVALID_VALUE", `value of type ${typeof doc} at ${path} cannot appear in a portable IR document (fail-closed)`);
35
+ }
36
+ /** UTF-8 エンコード(依存ゼロ・決定的。lib 制約により TextEncoder を使わない)。 */
37
+ function utf8Bytes(s) {
38
+ const out = [];
39
+ for (const ch of s) {
40
+ const cp = ch.codePointAt(0);
41
+ if (cp <= 0x7f)
42
+ out.push(cp);
43
+ else if (cp <= 0x7ff)
44
+ out.push(0xc0 | (cp >> 6), 0x80 | (cp & 0x3f));
45
+ else if (cp <= 0xffff)
46
+ out.push(0xe0 | (cp >> 12), 0x80 | ((cp >> 6) & 0x3f), 0x80 | (cp & 0x3f));
47
+ else
48
+ out.push(0xf0 | (cp >> 18), 0x80 | ((cp >> 12) & 0x3f), 0x80 | ((cp >> 6) & 0x3f), 0x80 | (cp & 0x3f));
49
+ }
50
+ return out;
51
+ }
52
+ /** FNV-1a 64(offset 0xcbf29ce484222325, prime 0x100000001b3)→ 16桁小文字 hex。 */
53
+ function fnv1a64(bytes) {
54
+ let h = 0xcbf29ce484222325n;
55
+ const prime = 0x100000001b3n;
56
+ const mask = 0xffffffffffffffffn;
57
+ for (const b of bytes) {
58
+ h ^= BigInt(b);
59
+ h = (h * prime) & mask;
60
+ }
61
+ return h.toString(16).padStart(16, "0");
62
+ }
63
+ /**
64
+ * fingerprintComponentGraph — 可搬 IR ドキュメントの決定的 fingerprint。
65
+ *
66
+ * `"fnv1a64:<16hex>"` を返す。同一構造の IR(キー順・整数/整数値float の表記差を除く)は
67
+ * 言語(TS/Python)を跨いで同一の fingerprint になる。生成モジュールのロード時
68
+ * 自己検査・consumer 側の「live IR ↔ 生成コード」照合(#208 の prepared-loader と同型)に使う。
69
+ */
70
+ export function fingerprintComponentGraph(doc) {
71
+ const s = canonicalJson(toValueDomain(doc, "$"));
72
+ return "fnv1a64:" + fnv1a64(utf8Bytes(s));
73
+ }
74
+ //# sourceMappingURL=fingerprint.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"fingerprint.js","sourceRoot":"","sources":["../../src/generator/fingerprint.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,9 @@
1
+ export { generateModule, registerEmitter, registeredLanguages, GeneratorFailure, } from "./core.js";
2
+ export type { GenerateOptions, GeneratedModule, EmitContext, EmitterPlugin, GeneratorFailureCode, } from "./core.js";
3
+ export { fingerprintComponentGraph, FingerprintFailure } from "./fingerprint.js";
4
+ export { typescriptEmitter } from "./emit-typescript.js";
5
+ export { pythonEmitter } from "./emit-python.js";
6
+ export { goEmitter } from "./emit-go.js";
7
+ export { rustEmitter } from "./emit-rust.js";
8
+ export { phpEmitter } from "./emit-php.js";
9
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/generator/index.ts"],"names":[],"mappings":"AAmBA,OAAO,EACL,cAAc,EACd,eAAe,EACf,mBAAmB,EACnB,gBAAgB,GACjB,MAAM,WAAW,CAAC;AACnB,YAAY,EACV,eAAe,EACf,eAAe,EACf,WAAW,EACX,aAAa,EACb,oBAAoB,GACrB,MAAM,WAAW,CAAC;AACnB,OAAO,EAAE,yBAAyB,EAAE,kBAAkB,EAAE,MAAM,kBAAkB,CAAC;AACjF,OAAO,EAAE,iBAAiB,EAAE,MAAM,sBAAsB,CAAC;AACzD,OAAO,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAC;AACjD,OAAO,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC;AACzC,OAAO,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAC;AAC7C,OAAO,EAAE,UAAU,EAAE,MAAM,eAAe,CAAC"}
@@ -0,0 +1,25 @@
1
+ /**
2
+ * generator/index.ts — 共通 Generator の公開面(bc#13 SP1 + SP2)。
3
+ *
4
+ * 組み込み emitter(typescript / python / go / rust / php)を登録して公開する。
5
+ * 追加言語は emitter plugin を登録するだけでよい(core は言語中立)。
6
+ */
7
+ import { registerEmitter } from "./core.js";
8
+ import { typescriptEmitter } from "./emit-typescript.js";
9
+ import { pythonEmitter } from "./emit-python.js";
10
+ import { goEmitter } from "./emit-go.js";
11
+ import { rustEmitter } from "./emit-rust.js";
12
+ import { phpEmitter } from "./emit-php.js";
13
+ registerEmitter(typescriptEmitter);
14
+ registerEmitter(pythonEmitter);
15
+ registerEmitter(goEmitter);
16
+ registerEmitter(rustEmitter);
17
+ registerEmitter(phpEmitter);
18
+ export { generateModule, registerEmitter, registeredLanguages, GeneratorFailure, } from "./core.js";
19
+ export { fingerprintComponentGraph, FingerprintFailure } from "./fingerprint.js";
20
+ export { typescriptEmitter } from "./emit-typescript.js";
21
+ export { pythonEmitter } from "./emit-python.js";
22
+ export { goEmitter } from "./emit-go.js";
23
+ export { rustEmitter } from "./emit-rust.js";
24
+ export { phpEmitter } from "./emit-php.js";
25
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/generator/index.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,OAAO,EAAE,eAAe,EAAE,MAAM,WAAW,CAAC;AAC5C,OAAO,EAAE,iBAAiB,EAAE,MAAM,sBAAsB,CAAC;AACzD,OAAO,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAC;AACjD,OAAO,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC;AACzC,OAAO,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAC;AAC7C,OAAO,EAAE,UAAU,EAAE,MAAM,eAAe,CAAC;AAE3C,eAAe,CAAC,iBAAiB,CAAC,CAAC;AACnC,eAAe,CAAC,aAAa,CAAC,CAAC;AAC/B,eAAe,CAAC,SAAS,CAAC,CAAC;AAC3B,eAAe,CAAC,WAAW,CAAC,CAAC;AAC7B,eAAe,CAAC,UAAU,CAAC,CAAC;AAE5B,OAAO,EACL,cAAc,EACd,eAAe,EACf,mBAAmB,EACnB,gBAAgB,GACjB,MAAM,WAAW,CAAC;AAQnB,OAAO,EAAE,yBAAyB,EAAE,kBAAkB,EAAE,MAAM,kBAAkB,CAAC;AACjF,OAAO,EAAE,iBAAiB,EAAE,MAAM,sBAAsB,CAAC;AACzD,OAAO,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAC;AACjD,OAAO,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC;AACzC,OAAO,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAC;AAC7C,OAAO,EAAE,UAAU,EAAE,MAAM,eAAe,CAAC"}
@@ -0,0 +1,8 @@
1
+ export type LiteralStyle = "ts" | "py" | "go" | "rust" | "php";
2
+ /**
3
+ * emitDocLiteral — ドキュメントを言語ネイティブのリテラル式として emit する。
4
+ * インデント 1 段 = dialect の indentUnit(ts/py 2 space・go tab・rust/php 4 space)・
5
+ * 複数行(JSON.stringify(v, null, indent) と同じレイアウト規則)。
6
+ */
7
+ export declare function emitDocLiteral(doc: unknown, style: LiteralStyle, indent?: number, path?: string): string;
8
+ //# sourceMappingURL=literal.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"literal.d.ts","sourceRoot":"","sources":["../../src/generator/literal.ts"],"names":[],"mappings":"AA6BA,MAAM,MAAM,YAAY,GAAG,IAAI,GAAG,IAAI,GAAG,IAAI,GAAG,MAAM,GAAG,KAAK,CAAC;AAoJ/D;;;;GAIG;AACH,wBAAgB,cAAc,CAAC,GAAG,EAAE,OAAO,EAAE,KAAK,EAAE,YAAY,EAAE,MAAM,SAAI,EAAE,IAAI,SAAM,GAAG,MAAM,CA0BhG"}
@@ -0,0 +1,191 @@
1
+ /**
2
+ * literal.ts — 可搬 IR ドキュメントの決定的ネイティブリテラル emit(共通 Generator 内部)。
3
+ *
4
+ * 決定性の規律: 入力ドキュメントの**キー順を保存**したまま(ソートしない — port 式の
5
+ * 評価順序は宣言順が規範で、並べ替えは §7.3 の経路等価を壊し得る)、同一入力から
6
+ * byte-identical なリテラル文字列を出す。JSON.parse 済みドキュメントが入力なので、
7
+ * キー順は JSON テキストの順(JS の integer-like キー正規化を含む)で既に決定的。
8
+ * キーソートは fingerprint 側だけで行う(SP1 audit の SP2 指針 (a))。
9
+ *
10
+ * スカラ規律(クロス言語):
11
+ * - 文字列: 言語別エスケープ(ts/py/go は JSON エスケープで合法。rust は \u{...} 形、
12
+ * php は double-quote + $ エスケープ)。
13
+ * - 整数値 number: 整数リテラル(Python は int / Go は json.Number("…") — dynamic 経路の
14
+ * パーサ出力と一致)。|n| >= 2^53 は fail-closed(fingerprint.ts と同じ規律)。
15
+ * - 非整数 number: shortest round-trip 10進(`String(n)` — 全対象言語で合法なリテラル)。
16
+ * - -0.0: `-0.0` と emit(JSON.parse は -0 を保存する — 落とすと canonical 出力が発散)。
17
+ * - true/false/null: 言語別トークン。
18
+ * - undefined / 関数等: fail-closed(JSON.stringify の「黙って落とす」を許さない)。
19
+ *
20
+ * 言語別の複合リテラル形(各 emitter の実行 IF に合わせる):
21
+ * - ts: `{...}` / `[...]`(ComponentGraphIR 型付き const)
22
+ * - py: dict / list
23
+ * - go: `dslcontracts.JObjOf("k", v, …)` / `[]dslcontracts.JNode{…}` / `json.Number("…")`
24
+ * (RunBehavior の消費する JNode ドメイン。インデントは gofmt 規範の tab)
25
+ * - rust: serde_json `json!({...})` の中身(JSON 形。トークンは Rust 字句で合法)
26
+ * - php: `(object) [...]` / `[...]`(Behavior::runBehavior の stdClass/array ドメイン)
27
+ */
28
+ import { FingerprintFailure } from "./fingerprint.js";
29
+ // ── 言語別文字列エスケープ ─────────────────────────────────────────────────────
30
+ /** Rust 文字列リテラル(\b/\f/\uXXXX は Rust に無いので \u{…} を使う。非 ASCII は素通し)。 */
31
+ function rustStr(s) {
32
+ let out = '"';
33
+ for (const ch of s) {
34
+ const cp = ch.codePointAt(0);
35
+ if (ch === '"')
36
+ out += '\\"';
37
+ else if (ch === "\\")
38
+ out += "\\\\";
39
+ else if (ch === "\n")
40
+ out += "\\n";
41
+ else if (ch === "\r")
42
+ out += "\\r";
43
+ else if (ch === "\t")
44
+ out += "\\t";
45
+ else if (cp < 0x20)
46
+ out += `\\u{${cp.toString(16)}}`;
47
+ else
48
+ out += ch;
49
+ }
50
+ return out + '"';
51
+ }
52
+ /** PHP double-quote 文字列リテラル($ は補間を防ぐためエスケープ。制御は \u{…})。 */
53
+ function phpStr(s) {
54
+ let out = '"';
55
+ for (const ch of s) {
56
+ const cp = ch.codePointAt(0);
57
+ if (ch === '"')
58
+ out += '\\"';
59
+ else if (ch === "\\")
60
+ out += "\\\\";
61
+ else if (ch === "$")
62
+ out += "\\$";
63
+ else if (ch === "\n")
64
+ out += "\\n";
65
+ else if (ch === "\r")
66
+ out += "\\r";
67
+ else if (ch === "\t")
68
+ out += "\\t";
69
+ else if (cp < 0x20)
70
+ out += `\\u{${cp.toString(16)}}`;
71
+ else
72
+ out += ch;
73
+ }
74
+ return out + '"';
75
+ }
76
+ const jsonishArr = (open, close) => (items, pad, padIn) => `${open}\n${items.map((v) => padIn + v).join(",\n")}\n${pad}${close}`;
77
+ const DIALECTS = {
78
+ ts: {
79
+ indentUnit: " ",
80
+ null: "null",
81
+ true: "true",
82
+ false: "false",
83
+ str: (s) => JSON.stringify(s),
84
+ int: (t) => t,
85
+ float: (t) => t,
86
+ emptyArr: "[]",
87
+ emptyObj: "{}",
88
+ arr: jsonishArr("[", "]"),
89
+ obj: (entries, pad, padIn) => `{\n${entries.map(([k, v]) => `${padIn}${JSON.stringify(k)}: ${v}`).join(",\n")}\n${pad}}`,
90
+ },
91
+ py: {
92
+ indentUnit: " ",
93
+ null: "None",
94
+ true: "True",
95
+ false: "False",
96
+ str: (s) => JSON.stringify(s),
97
+ int: (t) => t,
98
+ float: (t) => t,
99
+ emptyArr: "[]",
100
+ emptyObj: "{}",
101
+ arr: jsonishArr("[", "]"),
102
+ obj: (entries, pad, padIn) => `{\n${entries.map(([k, v]) => `${padIn}${JSON.stringify(k)}: ${v}`).join(",\n")}\n${pad}}`,
103
+ },
104
+ go: {
105
+ indentUnit: "\t",
106
+ null: "nil",
107
+ true: "true",
108
+ false: "false",
109
+ str: (s) => JSON.stringify(s), // JSON エスケープは Go 文字列リテラルとして合法
110
+ int: (t) => `json.Number("${t}")`,
111
+ float: (t) => `json.Number("${t}")`,
112
+ emptyArr: "[]dslcontracts.JNode{}",
113
+ emptyObj: "dslcontracts.JObjOf()",
114
+ arr: (items, pad, padIn) => `[]dslcontracts.JNode{\n${items.map((v) => `${padIn}${v},`).join("\n")}\n${pad}}`,
115
+ obj: (entries, pad, padIn) => `dslcontracts.JObjOf(\n${entries.map(([k, v]) => `${padIn}${JSON.stringify(k)}, ${v},`).join("\n")}\n${pad})`,
116
+ },
117
+ rust: {
118
+ indentUnit: " ",
119
+ null: "null", // json! マクロ内の JSON トークン
120
+ true: "true",
121
+ false: "false",
122
+ str: rustStr,
123
+ int: (t) => t,
124
+ float: (t) => t,
125
+ emptyArr: "[]",
126
+ emptyObj: "{}",
127
+ arr: jsonishArr("[", "]"),
128
+ obj: (entries, pad, padIn) => `{\n${entries.map(([k, v]) => `${padIn}${rustStr(k)}: ${v}`).join(",\n")}\n${pad}}`,
129
+ },
130
+ php: {
131
+ indentUnit: " ",
132
+ null: "null",
133
+ true: "true",
134
+ false: "false",
135
+ str: phpStr,
136
+ int: (t) => t,
137
+ float: (t) => t,
138
+ emptyArr: "[]",
139
+ emptyObj: "(object) []",
140
+ arr: (items, pad, padIn) => `[\n${items.map((v) => `${padIn}${v},`).join("\n")}\n${pad}]`,
141
+ obj: (entries, pad, padIn) => `(object) [\n${entries.map(([k, v]) => `${padIn}${phpStr(k)} => ${v},`).join("\n")}\n${pad}]`,
142
+ },
143
+ };
144
+ function scalarNumber(n, path, d) {
145
+ if (!Number.isFinite(n))
146
+ throw new FingerprintFailure("INVALID_VALUE", `non-finite number at ${path} cannot be emitted (fail-closed)`);
147
+ if (Object.is(n, -0))
148
+ return d.float("-0.0");
149
+ if (Number.isInteger(n)) {
150
+ if (Math.abs(n) >= 2 ** 53)
151
+ throw new FingerprintFailure("UNSAFE_NUMBER", `integral number ${n} at ${path} exceeds float64-exact range; portable IR must use {int:"..."} (fail-closed)`);
152
+ return d.int(String(n));
153
+ }
154
+ return d.float(String(n)); // shortest round-trip("0.1" / "1e-7" — 全対象言語で合法)
155
+ }
156
+ /**
157
+ * emitDocLiteral — ドキュメントを言語ネイティブのリテラル式として emit する。
158
+ * インデント 1 段 = dialect の indentUnit(ts/py 2 space・go tab・rust/php 4 space)・
159
+ * 複数行(JSON.stringify(v, null, indent) と同じレイアウト規則)。
160
+ */
161
+ export function emitDocLiteral(doc, style, indent = 0, path = "$") {
162
+ const d = DIALECTS[style];
163
+ const pad = d.indentUnit.repeat(indent);
164
+ const padIn = d.indentUnit.repeat(indent + 1);
165
+ if (doc === null)
166
+ return d.null;
167
+ if (typeof doc === "boolean")
168
+ return doc ? d.true : d.false;
169
+ if (typeof doc === "string")
170
+ return d.str(doc);
171
+ if (typeof doc === "number")
172
+ return scalarNumber(doc, path, d);
173
+ if (Array.isArray(doc)) {
174
+ if (doc.length === 0)
175
+ return d.emptyArr;
176
+ const items = doc.map((v, i) => emitDocLiteral(v, style, indent + 1, `${path}[${i}]`));
177
+ return d.arr(items, pad, padIn);
178
+ }
179
+ if (typeof doc === "object") {
180
+ const entries = Object.entries(doc);
181
+ if (entries.length === 0)
182
+ return d.emptyObj;
183
+ const emitted = entries.map(([k, v]) => [
184
+ k,
185
+ emitDocLiteral(v, style, indent + 1, `${path}.${k}`),
186
+ ]);
187
+ return d.obj(emitted, pad, padIn);
188
+ }
189
+ throw new FingerprintFailure("INVALID_VALUE", `value of type ${typeof doc} at ${path} cannot be emitted as a portable IR literal (fail-closed)`);
190
+ }
191
+ //# sourceMappingURL=literal.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"literal.js","sourceRoot":"","sources":["../../src/generator/literal.ts"],"names":[],"mappings":"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"}
package/dist/guard.d.ts CHANGED
@@ -24,4 +24,22 @@ export declare class PortabilityError extends Error {
24
24
  * @throws {PortabilityError} non-portable な値を検出したとき。
25
25
  */
26
26
  export declare function assertPortable(value: unknown, path?: string): void;
27
+ /**
28
+ * 可搬 IR で許可される Expression IR オペレータの閉集合(expression-ir.md §3)。
29
+ * `assertPortableComponentGraph` はこの集合外の単一キーオブジェクトノードを未知 operator
30
+ * として fail-closed で拒否する(component-graph の port 式・output・map.over/cond に適用)。
31
+ */
32
+ export declare const PORTABLE_EXPR_OPERATORS: ReadonlySet<string>;
33
+ /**
34
+ * assertPortableComponentGraph — component-graph IR(scp-ir-architecture.md §5)の
35
+ * 可搬性 Guard(P0-2)。generic な {@link assertPortable}(関数/Date/Promise 残存禁止)に加え、
36
+ * SCP 汎用層に固有の不変条件を fail-closed で強制する:
37
+ * 1. `component` フィールド(componentRef / map)は **文字列参照のみ**(catalog 名)。
38
+ * 2. port 式・output・map.over・cond に現れる Expression IR ノードは **既知 operator の閉集合のみ**
39
+ * (PORTABLE_EXPR_OPERATORS 外の単一キーオブジェクトは未知 operator として拒否)。
40
+ * 3. 関数残存禁止(generic guard を全域に適用)。
41
+ *
42
+ * @throws {PortabilityError} 非可搬な構造を検出したとき。
43
+ */
44
+ export declare function assertPortableComponentGraph(ir: unknown, path?: string): void;
27
45
  //# sourceMappingURL=guard.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"guard.d.ts","sourceRoot":"","sources":["../src/guard.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAEH,qBAAa,gBAAiB,SAAQ,KAAK;IACzC,IAAI,EAAE,MAAM,CAAC;gBACD,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM;CAK1C;AAED;;;;;;;GAOG;AACH,wBAAgB,cAAc,CAAC,KAAK,EAAE,OAAO,EAAE,IAAI,SAAM,GAAG,IAAI,CAa/D"}
1
+ {"version":3,"file":"guard.d.ts","sourceRoot":"","sources":["../src/guard.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAIH,qBAAa,gBAAiB,SAAQ,KAAK;IACzC,IAAI,EAAE,MAAM,CAAC;gBACD,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM;CAK1C;AAED;;;;;;;GAOG;AACH,wBAAgB,cAAc,CAAC,KAAK,EAAE,OAAO,EAAE,IAAI,SAAM,GAAG,IAAI,CAa/D;AAED;;;;GAIG;AACH,eAAO,MAAM,uBAAuB,EAAE,WAAW,CAAC,MAAM,CAKtD,CAAC;AAEH;;;;;;;;;;GAUG;AACH,wBAAgB,4BAA4B,CAAC,EAAE,EAAE,OAAO,EAAE,IAAI,SAAM,GAAG,IAAI,CAQ1E"}