litedbmodel 1.2.10 → 2.0.1
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.
- package/README.md +1 -1
- package/dist/DBModel.d.ts.map +1 -1
- package/dist/DBModel.js +6 -0
- package/dist/DBModel.js.map +1 -1
- package/dist/scp/authoring-sql.d.ts +134 -0
- package/dist/scp/authoring-sql.d.ts.map +1 -0
- package/dist/scp/authoring-sql.js +191 -0
- package/dist/scp/authoring-sql.js.map +1 -0
- package/dist/scp/authoring.d.ts +155 -0
- package/dist/scp/authoring.d.ts.map +1 -0
- package/dist/scp/authoring.js +162 -0
- package/dist/scp/authoring.js.map +1 -0
- package/dist/scp/catalog.d.ts +91 -0
- package/dist/scp/catalog.d.ts.map +1 -0
- package/dist/scp/catalog.js +230 -0
- package/dist/scp/catalog.js.map +1 -0
- package/dist/scp/codegen.d.ts +95 -0
- package/dist/scp/codegen.d.ts.map +1 -0
- package/dist/scp/codegen.js +94 -0
- package/dist/scp/codegen.js.map +1 -0
- package/dist/scp/dialect.d.ts +141 -0
- package/dist/scp/dialect.d.ts.map +1 -0
- package/dist/scp/dialect.js +194 -0
- package/dist/scp/dialect.js.map +1 -0
- package/dist/scp/errors.d.ts +36 -0
- package/dist/scp/errors.d.ts.map +1 -0
- package/dist/scp/errors.js +72 -0
- package/dist/scp/errors.js.map +1 -0
- package/dist/scp/find-filter-guard.d.ts +68 -0
- package/dist/scp/find-filter-guard.d.ts.map +1 -0
- package/dist/scp/find-filter-guard.js +88 -0
- package/dist/scp/find-filter-guard.js.map +1 -0
- package/dist/scp/fragment/assemble.d.ts +61 -0
- package/dist/scp/fragment/assemble.d.ts.map +1 -0
- package/dist/scp/fragment/assemble.js +148 -0
- package/dist/scp/fragment/assemble.js.map +1 -0
- package/dist/scp/fragment/compile-pg.d.ts +107 -0
- package/dist/scp/fragment/compile-pg.d.ts.map +1 -0
- package/dist/scp/fragment/compile-pg.js +142 -0
- package/dist/scp/fragment/compile-pg.js.map +1 -0
- package/dist/scp/fragment/index.d.ts +16 -0
- package/dist/scp/fragment/index.d.ts.map +1 -0
- package/dist/scp/fragment/index.js +34 -0
- package/dist/scp/fragment/index.js.map +1 -0
- package/dist/scp/fragment/model.d.ts +119 -0
- package/dist/scp/fragment/model.d.ts.map +1 -0
- package/dist/scp/fragment/model.js +66 -0
- package/dist/scp/fragment/model.js.map +1 -0
- package/dist/scp/fragment/pg-array-type.d.ts +13 -0
- package/dist/scp/fragment/pg-array-type.d.ts.map +1 -0
- package/dist/scp/fragment/pg-array-type.js +34 -0
- package/dist/scp/fragment/pg-array-type.js.map +1 -0
- package/dist/scp/guard.d.ts +43 -0
- package/dist/scp/guard.d.ts.map +1 -0
- package/dist/scp/guard.js +134 -0
- package/dist/scp/guard.js.map +1 -0
- package/dist/scp/index.cjs +12202 -0
- package/dist/scp/index.d.ts +64 -0
- package/dist/scp/index.d.ts.map +1 -0
- package/dist/scp/index.js +238 -0
- package/dist/scp/index.js.map +1 -0
- package/dist/scp/index.mjs +4819 -0
- package/dist/scp/makesql/authoring-compile.d.ts +90 -0
- package/dist/scp/makesql/authoring-compile.d.ts.map +1 -0
- package/dist/scp/makesql/authoring-compile.js +494 -0
- package/dist/scp/makesql/authoring-compile.js.map +1 -0
- package/dist/scp/makesql/compile-crud.d.ts +133 -0
- package/dist/scp/makesql/compile-crud.d.ts.map +1 -0
- package/dist/scp/makesql/compile-crud.js +288 -0
- package/dist/scp/makesql/compile-crud.js.map +1 -0
- package/dist/scp/makesql/compile-relation.d.ts +157 -0
- package/dist/scp/makesql/compile-relation.d.ts.map +1 -0
- package/dist/scp/makesql/compile-relation.js +425 -0
- package/dist/scp/makesql/compile-relation.js.map +1 -0
- package/dist/scp/makesql/compile-select.d.ts +45 -0
- package/dist/scp/makesql/compile-select.d.ts.map +1 -0
- package/dist/scp/makesql/compile-select.js +58 -0
- package/dist/scp/makesql/compile-select.js.map +1 -0
- package/dist/scp/makesql/compile.d.ts +63 -0
- package/dist/scp/makesql/compile.d.ts.map +1 -0
- package/dist/scp/makesql/compile.js +99 -0
- package/dist/scp/makesql/compile.js.map +1 -0
- package/dist/scp/makesql/handler.d.ts +58 -0
- package/dist/scp/makesql/handler.d.ts.map +1 -0
- package/dist/scp/makesql/handler.js +113 -0
- package/dist/scp/makesql/handler.js.map +1 -0
- package/dist/scp/makesql/index.d.ts +33 -0
- package/dist/scp/makesql/index.d.ts.map +1 -0
- package/dist/scp/makesql/index.js +114 -0
- package/dist/scp/makesql/index.js.map +1 -0
- package/dist/scp/makesql/ir.d.ts +42 -0
- package/dist/scp/makesql/ir.d.ts.map +1 -0
- package/dist/scp/makesql/ir.js +66 -0
- package/dist/scp/makesql/ir.js.map +1 -0
- package/dist/scp/makesql/json-array.d.ts +84 -0
- package/dist/scp/makesql/json-array.d.ts.map +1 -0
- package/dist/scp/makesql/json-array.js +118 -0
- package/dist/scp/makesql/json-array.js.map +1 -0
- package/dist/scp/makesql/json-batch.d.ts +102 -0
- package/dist/scp/makesql/json-batch.d.ts.map +1 -0
- package/dist/scp/makesql/json-batch.js +269 -0
- package/dist/scp/makesql/json-batch.js.map +1 -0
- package/dist/scp/makesql/makesql.d.ts +99 -0
- package/dist/scp/makesql/makesql.d.ts.map +1 -0
- package/dist/scp/makesql/makesql.js +122 -0
- package/dist/scp/makesql/makesql.js.map +1 -0
- package/dist/scp/makesql/pool-executor.d.ts +47 -0
- package/dist/scp/makesql/pool-executor.d.ts.map +1 -0
- package/dist/scp/makesql/pool-executor.js +50 -0
- package/dist/scp/makesql/pool-executor.js.map +1 -0
- package/dist/scp/makesql/static-bundle.d.ts +185 -0
- package/dist/scp/makesql/static-bundle.d.ts.map +1 -0
- package/dist/scp/makesql/static-bundle.js +1024 -0
- package/dist/scp/makesql/static-bundle.js.map +1 -0
- package/dist/scp/makesql/tx.d.ts +216 -0
- package/dist/scp/makesql/tx.d.ts.map +1 -0
- package/dist/scp/makesql/tx.js +743 -0
- package/dist/scp/makesql/tx.js.map +1 -0
- package/dist/scp/relation.d.ts +148 -0
- package/dist/scp/relation.d.ts.map +1 -0
- package/dist/scp/relation.js +257 -0
- package/dist/scp/relation.js.map +1 -0
- package/dist/scp/runtime.d.ts +231 -0
- package/dist/scp/runtime.d.ts.map +1 -0
- package/dist/scp/runtime.js +381 -0
- package/dist/scp/runtime.js.map +1 -0
- package/dist/scp/typed-object.d.ts +99 -0
- package/dist/scp/typed-object.d.ts.map +1 -0
- package/dist/scp/typed-object.js +184 -0
- package/dist/scp/typed-object.js.map +1 -0
- package/dist/scp/writes.d.ts +251 -0
- package/dist/scp/writes.d.ts.map +1 -0
- package/dist/scp/writes.js +176 -0
- package/dist/scp/writes.js.map +1 -0
- package/docs/proposal/contracts-architecture-feasibility.md +328 -0
- package/docs/proposal/contracts-architecture.md +579 -0
- package/docs/proposal/litedbmodel-v2-scp-architecture.md +382 -0
- package/docs/proposal/sql-dynamic-expansion-spec.md +175 -0
- package/docs/proposal/v0-coverage-matrix.md +157 -0
- package/docs/proposal/v2-completeness-plan.md +90 -0
- package/docs/proposal/v2-sql-parity-checklist.md +162 -0
- package/package.json +27 -5
- package/docs/README_REVIEW.md +0 -23
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* litedbmodel v2 SCP — the MINIMAL fragment model (epic #43 reset).
|
|
4
|
+
*
|
|
5
|
+
* ## The locked vocabulary (owner-specified — nothing else exists here)
|
|
6
|
+
*
|
|
7
|
+
* The portable artifact is ONLY a combination of **fragments**. There is NO
|
|
8
|
+
* abstract "Expression IR", NO relation-op / operator kinds for SQL structure,
|
|
9
|
+
* NO `FragmentTree` connector algebra, NO `{where}` splice marker. SQL structure
|
|
10
|
+
* (`= ANY`, `CROSS JOIN LATERAL`, `UNNEST`, subquery, cast, batch shapes) lives
|
|
11
|
+
* ENTIRELY as TEXT inside `sql`.
|
|
12
|
+
*
|
|
13
|
+
* fragment = { sql: string, params: Param[], skip?: PresenceCondition }
|
|
14
|
+
*
|
|
15
|
+
* - A query is an ordered list of fragments.
|
|
16
|
+
* - Assembling = concatenate the `sql` of every PRESENT fragment, and concatenate
|
|
17
|
+
* their `params` in order. If a fragment's `skip` is satisfied, BOTH its `sql`
|
|
18
|
+
* and its `params` are omitted.
|
|
19
|
+
*
|
|
20
|
+
* Param = EITHER
|
|
21
|
+
* (a) a **value-spec** — how to compute the bound value from input at runtime:
|
|
22
|
+
* an input-ref / wire-ref / a small closed value-expression
|
|
23
|
+
* (e.g. `coalesce(input.limit, 20)`). This computes the VALUE only.
|
|
24
|
+
* OR
|
|
25
|
+
* (b) a **nested fragment** — a raw SQL sub-piece with its own params. This is
|
|
26
|
+
* how subqueries / sub-expressions are represented: NOT as IR constructs,
|
|
27
|
+
* just a nested { sql, params }.
|
|
28
|
+
*
|
|
29
|
+
* Array-parameter placeholder expansion is DRIVER-side, not modeled here. On
|
|
30
|
+
* PostgreSQL an array param binds directly (`= ANY(?::int[])`), so the text is
|
|
31
|
+
* static and the array is ONE param. On MySQL/SQLite (no array binding) the DRIVER
|
|
32
|
+
* expands an array param into `(?, ?, …)` at bind time. The bundle stays
|
|
33
|
+
* "string + params" regardless.
|
|
34
|
+
*
|
|
35
|
+
* The whole model is plain JSON / serializable so a thin runtime in any language
|
|
36
|
+
* reads it identically.
|
|
37
|
+
*/
|
|
38
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
39
|
+
exports.isFragment = isFragment;
|
|
40
|
+
exports.isWhereGroup = isWhereGroup;
|
|
41
|
+
exports.isInputRef = isInputRef;
|
|
42
|
+
exports.isWireRef = isWireRef;
|
|
43
|
+
exports.isLiteral = isLiteral;
|
|
44
|
+
exports.isValueExpr = isValueExpr;
|
|
45
|
+
// ============================================================================
|
|
46
|
+
// Type guards (structural — a nested-fragment param has `sql`; value-specs don't)
|
|
47
|
+
// ============================================================================
|
|
48
|
+
function isFragment(p) {
|
|
49
|
+
return typeof p.sql === 'string';
|
|
50
|
+
}
|
|
51
|
+
function isWhereGroup(n) {
|
|
52
|
+
return Array.isArray(n.where);
|
|
53
|
+
}
|
|
54
|
+
function isInputRef(v) {
|
|
55
|
+
return Array.isArray(v.input);
|
|
56
|
+
}
|
|
57
|
+
function isWireRef(v) {
|
|
58
|
+
return Array.isArray(v.wire);
|
|
59
|
+
}
|
|
60
|
+
function isLiteral(v) {
|
|
61
|
+
return 'literal' in v;
|
|
62
|
+
}
|
|
63
|
+
function isValueExpr(v) {
|
|
64
|
+
return typeof v.op === 'string' && Array.isArray(v.args);
|
|
65
|
+
}
|
|
66
|
+
//# sourceMappingURL=model.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"model.js","sourceRoot":"","sources":["../../../src/scp/fragment/model.ts"],"names":[],"mappings":";AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAmCG;;AAyGH,gCAEC;AAED,oCAEC;AAED,gCAEC;AACD,8BAEC;AACD,8BAEC;AACD,kCAEC;AAvBD,+EAA+E;AAC/E,kFAAkF;AAClF,+EAA+E;AAE/E,SAAgB,UAAU,CAAC,CAAe;IACxC,OAAO,OAAQ,CAAc,CAAC,GAAG,KAAK,QAAQ,CAAC;AACjD,CAAC;AAED,SAAgB,YAAY,CAAC,CAAO;IAClC,OAAO,KAAK,CAAC,OAAO,CAAE,CAAgB,CAAC,KAAK,CAAC,CAAC;AAChD,CAAC;AAED,SAAgB,UAAU,CAAC,CAAY;IACrC,OAAO,KAAK,CAAC,OAAO,CAAE,CAAc,CAAC,KAAK,CAAC,CAAC;AAC9C,CAAC;AACD,SAAgB,SAAS,CAAC,CAAY;IACpC,OAAO,KAAK,CAAC,OAAO,CAAE,CAAa,CAAC,IAAI,CAAC,CAAC;AAC5C,CAAC;AACD,SAAgB,SAAS,CAAC,CAAY;IACpC,OAAO,SAAS,IAAK,CAAkB,CAAC;AAC1C,CAAC;AACD,SAAgB,WAAW,CAAC,CAAY;IACtC,OAAO,OAAQ,CAAe,CAAC,EAAE,KAAK,QAAQ,IAAI,KAAK,CAAC,OAAO,CAAE,CAAe,CAAC,IAAI,CAAC,CAAC;AACzF,CAAC"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* PostgreSQL array-type inference for compile-time cast text.
|
|
3
|
+
*
|
|
4
|
+
* VERBATIM reuse of the ORIGINAL `LazyRelation.inferPgArrayType` logic so the
|
|
5
|
+
* `?::<type>[]` cast text a fragment carries is byte-identical to the tuned
|
|
6
|
+
* builder. sqlCast (from the target column's metadata) wins; otherwise the element
|
|
7
|
+
* type is inferred from the compile-time sample values.
|
|
8
|
+
*
|
|
9
|
+
* (This is TEXT chosen at build time; it is NOT an IR "kind". The array itself is
|
|
10
|
+
* bound as ONE param on PostgreSQL.)
|
|
11
|
+
*/
|
|
12
|
+
export declare function inferPgArrayTypeForCompile(values: unknown[], sqlCast?: string): string;
|
|
13
|
+
//# sourceMappingURL=pg-array-type.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"pg-array-type.d.ts","sourceRoot":"","sources":["../../../src/scp/fragment/pg-array-type.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AACH,wBAAgB,0BAA0B,CAAC,MAAM,EAAE,OAAO,EAAE,EAAE,OAAO,CAAC,EAAE,MAAM,GAAG,MAAM,CAYtF"}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.inferPgArrayTypeForCompile = inferPgArrayTypeForCompile;
|
|
4
|
+
/**
|
|
5
|
+
* PostgreSQL array-type inference for compile-time cast text.
|
|
6
|
+
*
|
|
7
|
+
* VERBATIM reuse of the ORIGINAL `LazyRelation.inferPgArrayType` logic so the
|
|
8
|
+
* `?::<type>[]` cast text a fragment carries is byte-identical to the tuned
|
|
9
|
+
* builder. sqlCast (from the target column's metadata) wins; otherwise the element
|
|
10
|
+
* type is inferred from the compile-time sample values.
|
|
11
|
+
*
|
|
12
|
+
* (This is TEXT chosen at build time; it is NOT an IR "kind". The array itself is
|
|
13
|
+
* bound as ONE param on PostgreSQL.)
|
|
14
|
+
*/
|
|
15
|
+
function inferPgArrayTypeForCompile(values, sqlCast) {
|
|
16
|
+
if (sqlCast)
|
|
17
|
+
return `${sqlCast}[]`;
|
|
18
|
+
if (values.length === 0)
|
|
19
|
+
return 'text[]';
|
|
20
|
+
const sample = values[0];
|
|
21
|
+
if (typeof sample === 'number') {
|
|
22
|
+
if (values.every((v) => Number.isInteger(v)))
|
|
23
|
+
return 'int[]';
|
|
24
|
+
return 'numeric[]';
|
|
25
|
+
}
|
|
26
|
+
if (typeof sample === 'bigint')
|
|
27
|
+
return 'bigint[]';
|
|
28
|
+
if (typeof sample === 'boolean')
|
|
29
|
+
return 'boolean[]';
|
|
30
|
+
if (sample instanceof Date)
|
|
31
|
+
return 'timestamp[]';
|
|
32
|
+
return 'text[]';
|
|
33
|
+
}
|
|
34
|
+
//# sourceMappingURL=pg-array-type.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"pg-array-type.js","sourceRoot":"","sources":["../../../src/scp/fragment/pg-array-type.ts"],"names":[],"mappings":";;AAWA,gEAYC;AAvBD;;;;;;;;;;GAUG;AACH,SAAgB,0BAA0B,CAAC,MAAiB,EAAE,OAAgB;IAC5E,IAAI,OAAO;QAAE,OAAO,GAAG,OAAO,IAAI,CAAC;IACnC,IAAI,MAAM,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,QAAQ,CAAC;IACzC,MAAM,MAAM,GAAG,MAAM,CAAC,CAAC,CAAC,CAAC;IACzB,IAAI,OAAO,MAAM,KAAK,QAAQ,EAAE,CAAC;QAC/B,IAAI,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC;YAAE,OAAO,OAAO,CAAC;QAC7D,OAAO,WAAW,CAAC;IACrB,CAAC;IACD,IAAI,OAAO,MAAM,KAAK,QAAQ;QAAE,OAAO,UAAU,CAAC;IAClD,IAAI,OAAO,MAAM,KAAK,SAAS;QAAE,OAAO,WAAW,CAAC;IACpD,IAAI,MAAM,YAAY,IAAI;QAAE,OAAO,aAAa,CAAC;IACjD,OAAO,QAAQ,CAAC;AAClB,CAAC"}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* litedbmodel v2 SCP — param/fragment portability guard (WS1, #21).
|
|
3
|
+
*
|
|
4
|
+
* Fail-closed enforcement of the hard rule: every Expression IR node this backend emits
|
|
5
|
+
* (param slots, fragment `when` guards) uses ONLY bc's closed operator set
|
|
6
|
+
* (`PORTABLE_EXPR_OPERATORS`). A single-key object whose key is not a known operator is
|
|
7
|
+
* an un-lowerable construct — it must go through the Raw SQL escape hatch (spec §13), NOT
|
|
8
|
+
* a fake opcode. This wraps bc's `assertPortable` (no functions/Date/Promise residue)
|
|
9
|
+
* plus the operator-set check.
|
|
10
|
+
*/
|
|
11
|
+
import { type Component, type ComponentGraphIR } from 'behavior-contracts';
|
|
12
|
+
/** A bc Expression IR node (closed operator set). Structural alias — a JSON expression tree. */
|
|
13
|
+
export type ExprNode = unknown;
|
|
14
|
+
/**
|
|
15
|
+
* Assert one Expression IR node is portable: no residue (functions/Date/…) and every
|
|
16
|
+
* operator-node key is in bc's closed set. Literals (number/string/bool/null) and arrays
|
|
17
|
+
* pass structurally.
|
|
18
|
+
*
|
|
19
|
+
* A single-key object is an OPERATOR node only when its key is a known operator
|
|
20
|
+
* (∈ {@link PORTABLE_EXPR_OPERATORS}); its value is then recursed as operator args. A
|
|
21
|
+
* single-key object whose key is NOT a known operator is a real portability violation and
|
|
22
|
+
* is rejected fail-closed (an un-lowerable pseudo-opcode → must use the Raw SQL escape
|
|
23
|
+
* hatch, spec §13). This mirrors bc's `assertPortableComponentGraph` operator-position
|
|
24
|
+
* semantics exactly — see {@link walkExpr} for the `obj` field-map special case.
|
|
25
|
+
*/
|
|
26
|
+
export declare function assertExprPortable(node: ExprNode, path?: string): void;
|
|
27
|
+
/**
|
|
28
|
+
* Assert every Expression IR node in ONE lowered component's port wiring is portable
|
|
29
|
+
* (WS2 AC). Walks every `componentRef`/`map` node's `ports` (and `map.over` / `map.when`)
|
|
30
|
+
* and every `cond` node's `if`/`then`/`else`, applying {@link assertExprPortable} — so any
|
|
31
|
+
* operator outside bc's closed set is rejected fail-closed at compile time. This is the
|
|
32
|
+
* litedbmodel-owned portability layer the authoring lower path auto-applies, over and
|
|
33
|
+
* above bc's own `assertPortableComponentGraph` self-check.
|
|
34
|
+
*/
|
|
35
|
+
export declare function assertComponentPortable(component: Component): void;
|
|
36
|
+
/**
|
|
37
|
+
* Assert every component of a lowered Component-graph IR is portable (WS2 AC). The
|
|
38
|
+
* authoring lower path ({@link publishBehaviors} / {@link compileEager}) invokes this
|
|
39
|
+
* automatically so a non-portable opcode anywhere in the emitted IR is a fail-closed
|
|
40
|
+
* compile error. Throws {@link PortabilityError} on the first violation.
|
|
41
|
+
*/
|
|
42
|
+
export declare function assertComponentGraphPortable(ir: ComponentGraphIR): void;
|
|
43
|
+
//# sourceMappingURL=guard.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"guard.d.ts","sourceRoot":"","sources":["../../src/scp/guard.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,OAAO,EAAmF,KAAK,SAAS,EAAE,KAAK,gBAAgB,EAAE,MAAM,oBAAoB,CAAC;AAE5J,gGAAgG;AAChG,MAAM,MAAM,QAAQ,GAAG,OAAO,CAAC;AAE/B;;;;;;;;;;;GAWG;AACH,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,QAAQ,EAAE,IAAI,SAAM,GAAG,IAAI,CAGnE;AAgDD;;;;;;;GAOG;AACH,wBAAgB,uBAAuB,CAAC,SAAS,EAAE,SAAS,GAAG,IAAI,CAgBlE;AAoBD;;;;;GAKG;AACH,wBAAgB,4BAA4B,CAAC,EAAE,EAAE,gBAAgB,GAAG,IAAI,CAEvE"}
|
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* litedbmodel v2 SCP — param/fragment portability guard (WS1, #21).
|
|
4
|
+
*
|
|
5
|
+
* Fail-closed enforcement of the hard rule: every Expression IR node this backend emits
|
|
6
|
+
* (param slots, fragment `when` guards) uses ONLY bc's closed operator set
|
|
7
|
+
* (`PORTABLE_EXPR_OPERATORS`). A single-key object whose key is not a known operator is
|
|
8
|
+
* an un-lowerable construct — it must go through the Raw SQL escape hatch (spec §13), NOT
|
|
9
|
+
* a fake opcode. This wraps bc's `assertPortable` (no functions/Date/Promise residue)
|
|
10
|
+
* plus the operator-set check.
|
|
11
|
+
*/
|
|
12
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
13
|
+
exports.assertExprPortable = assertExprPortable;
|
|
14
|
+
exports.assertComponentPortable = assertComponentPortable;
|
|
15
|
+
exports.assertComponentGraphPortable = assertComponentGraphPortable;
|
|
16
|
+
const behavior_contracts_1 = require("behavior-contracts");
|
|
17
|
+
/**
|
|
18
|
+
* Assert one Expression IR node is portable: no residue (functions/Date/…) and every
|
|
19
|
+
* operator-node key is in bc's closed set. Literals (number/string/bool/null) and arrays
|
|
20
|
+
* pass structurally.
|
|
21
|
+
*
|
|
22
|
+
* A single-key object is an OPERATOR node only when its key is a known operator
|
|
23
|
+
* (∈ {@link PORTABLE_EXPR_OPERATORS}); its value is then recursed as operator args. A
|
|
24
|
+
* single-key object whose key is NOT a known operator is a real portability violation and
|
|
25
|
+
* is rejected fail-closed (an un-lowerable pseudo-opcode → must use the Raw SQL escape
|
|
26
|
+
* hatch, spec §13). This mirrors bc's `assertPortableComponentGraph` operator-position
|
|
27
|
+
* semantics exactly — see {@link walkExpr} for the `obj` field-map special case.
|
|
28
|
+
*/
|
|
29
|
+
function assertExprPortable(node, path = '$') {
|
|
30
|
+
(0, behavior_contracts_1.assertPortable)(node, path);
|
|
31
|
+
walkExpr(node, path);
|
|
32
|
+
}
|
|
33
|
+
function walkExpr(node, path) {
|
|
34
|
+
if (node === null || typeof node !== 'object')
|
|
35
|
+
return;
|
|
36
|
+
if (Array.isArray(node)) {
|
|
37
|
+
node.forEach((el, i) => walkExpr(el, `${path}[${i}]`));
|
|
38
|
+
return;
|
|
39
|
+
}
|
|
40
|
+
const keys = Object.keys(node);
|
|
41
|
+
if (keys.length === 1) {
|
|
42
|
+
// Single-key object = OPERATOR-position node. The key must be a known opcode
|
|
43
|
+
// (fail-closed on unknown opcodes — a real portability violation).
|
|
44
|
+
const op = keys[0];
|
|
45
|
+
if (!behavior_contracts_1.PORTABLE_EXPR_OPERATORS.has(op)) {
|
|
46
|
+
throw new behavior_contracts_1.PortabilityError(path, `Portability Guard: '${op}' is not a portable Expression IR operator (closed set: ${[...behavior_contracts_1.PORTABLE_EXPR_OPERATORS].join(', ')})`);
|
|
47
|
+
}
|
|
48
|
+
const arg = node[op];
|
|
49
|
+
// `obj` is the construction node: its arg is a FIELD MAP whose KEYS are data field
|
|
50
|
+
// names (NOT opcodes) and whose VALUES are ExprNodes. Recurse into the values ONLY —
|
|
51
|
+
// never apply the operator heuristic to the field map itself (aligns with bc's
|
|
52
|
+
// assertPortableExpr / evaluate() so a single-field {obj:{one:…}} is not misread as an
|
|
53
|
+
// unknown opcode). See behavior-contracts guard.ts `op === "obj"` branch.
|
|
54
|
+
if (op === 'obj') {
|
|
55
|
+
if (arg === null || typeof arg !== 'object' || Array.isArray(arg)) {
|
|
56
|
+
throw new behavior_contracts_1.PortabilityError(`${path}.obj`, `Portability Guard: {obj: ...} expects an object (at ${path}.obj)`);
|
|
57
|
+
}
|
|
58
|
+
for (const [k, v] of Object.entries(arg)) {
|
|
59
|
+
// Static fail-closed (defense-in-depth): own key "__proto__" is rejected here as it
|
|
60
|
+
// is by bc's guard/evaluator (prototype pollution / cross-language divergence).
|
|
61
|
+
if (k === behavior_contracts_1.FORBIDDEN_OBJECT_KEY) {
|
|
62
|
+
throw new behavior_contracts_1.PortabilityError(`${path}.obj`, `Portability Guard: object key "${behavior_contracts_1.FORBIDDEN_OBJECT_KEY}" is forbidden (fail-closed) at ${path}.obj`);
|
|
63
|
+
}
|
|
64
|
+
walkExpr(v, `${path}.obj.${k}`);
|
|
65
|
+
}
|
|
66
|
+
return;
|
|
67
|
+
}
|
|
68
|
+
// Any other operator: recurse its arg (array of args or a nested expr node).
|
|
69
|
+
walkExpr(arg, `${path}.${op}`);
|
|
70
|
+
return;
|
|
71
|
+
}
|
|
72
|
+
// Multi-key objects are not operator nodes (operator nodes are single-key). Recurse each
|
|
73
|
+
// value structurally so nested operator nodes are still checked (assertPortable above has
|
|
74
|
+
// already rejected any function/Date/Promise residue across the whole subtree).
|
|
75
|
+
for (const k of keys)
|
|
76
|
+
walkExpr(node[k], `${path}.${k}`);
|
|
77
|
+
}
|
|
78
|
+
// ── Authoring→IR lower guard (WS2, #22 — auto-applied on the single compile path) ─────
|
|
79
|
+
/**
|
|
80
|
+
* Assert every Expression IR node in ONE lowered component's port wiring is portable
|
|
81
|
+
* (WS2 AC). Walks every `componentRef`/`map` node's `ports` (and `map.over` / `map.when`)
|
|
82
|
+
* and every `cond` node's `if`/`then`/`else`, applying {@link assertExprPortable} — so any
|
|
83
|
+
* operator outside bc's closed set is rejected fail-closed at compile time. This is the
|
|
84
|
+
* litedbmodel-owned portability layer the authoring lower path auto-applies, over and
|
|
85
|
+
* above bc's own `assertPortableComponentGraph` self-check.
|
|
86
|
+
*/
|
|
87
|
+
function assertComponentPortable(component) {
|
|
88
|
+
const at = `component '${component.name}'`;
|
|
89
|
+
for (const n of component.body) {
|
|
90
|
+
if ('map' in n) {
|
|
91
|
+
assertExprPortable(n.map.over, `${at}/${n.id}.map.over`);
|
|
92
|
+
assertPortsPortable(n.map.ports, `${at}/${n.id}.map.ports`);
|
|
93
|
+
if (n.map.when !== undefined)
|
|
94
|
+
assertExprPortable(n.map.when, `${at}/${n.id}.map.when`);
|
|
95
|
+
}
|
|
96
|
+
else if ('cond' in n) {
|
|
97
|
+
assertExprPortable(n.cond.if, `${at}/${n.id}.cond.if`);
|
|
98
|
+
assertExprPortable(n.cond.then, `${at}/${n.id}.cond.then`);
|
|
99
|
+
assertExprPortable(n.cond.else, `${at}/${n.id}.cond.else`);
|
|
100
|
+
}
|
|
101
|
+
else {
|
|
102
|
+
assertPortsPortable(n.ports, `${at}/${n.id}.ports`);
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
assertExprPortable(component.output, `${at}.output`);
|
|
106
|
+
}
|
|
107
|
+
/**
|
|
108
|
+
* A component node's `ports` (and a `map.ports`) is a FIELD MAP — port NAME → ExprNode — not an
|
|
109
|
+
* Expression node itself. Walk each port VALUE as an expression, never the ports object as a whole:
|
|
110
|
+
* a SINGLE-port node (`{ table: 'posts' }`, e.g. a `Count` with only `table`) would otherwise be
|
|
111
|
+
* misread by {@link walkExpr}'s single-key = OPERATOR heuristic as an unknown-opcode `{table:…}`
|
|
112
|
+
* node. Recursing the values sidesteps that (same rationale bc's guard applies to `{obj:{…}}`).
|
|
113
|
+
*/
|
|
114
|
+
function assertPortsPortable(ports, path) {
|
|
115
|
+
if (ports === null || typeof ports !== 'object' || Array.isArray(ports)) {
|
|
116
|
+
// Not a ports map (shouldn't happen for a well-formed node) — defer to the expr walker.
|
|
117
|
+
assertExprPortable(ports, path);
|
|
118
|
+
return;
|
|
119
|
+
}
|
|
120
|
+
for (const [name, value] of Object.entries(ports)) {
|
|
121
|
+
assertExprPortable(value, `${path}.${name}`);
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
/**
|
|
125
|
+
* Assert every component of a lowered Component-graph IR is portable (WS2 AC). The
|
|
126
|
+
* authoring lower path ({@link publishBehaviors} / {@link compileEager}) invokes this
|
|
127
|
+
* automatically so a non-portable opcode anywhere in the emitted IR is a fail-closed
|
|
128
|
+
* compile error. Throws {@link PortabilityError} on the first violation.
|
|
129
|
+
*/
|
|
130
|
+
function assertComponentGraphPortable(ir) {
|
|
131
|
+
for (const c of ir.components)
|
|
132
|
+
assertComponentPortable(c);
|
|
133
|
+
}
|
|
134
|
+
//# sourceMappingURL=guard.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"guard.js","sourceRoot":"","sources":["../../src/scp/guard.ts"],"names":[],"mappings":"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"}
|