@kungfu-tech/buildchain 4.1.3 → 4.1.4-alpha.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.
- package/AGENTS.md +11 -13
- package/CONTRIBUTING.md +32 -9
- package/README.md +56 -140
- package/actions/release/promotion/ref/README.md +1 -1
- package/architecture/action-taxonomy.json +1 -1
- package/architecture/agent-change-map.md +32 -45
- package/architecture/build-orchestration.json +1 -1
- package/architecture/capability-state-machine-manifest.json +5 -5
- package/architecture/ci-lane-change-budget.json +92 -92
- package/architecture/code-layout.json +2 -12
- package/architecture/core-mechanisms.json +38 -39
- package/architecture/cross-platform-adopter-qualification.json +1 -1
- package/architecture/dev-delivery-orchestration.json +2 -2
- package/architecture/floating-consumer-policy.json +3 -3
- package/architecture/internal-capabilities.json +27 -28
- package/architecture/maintainability-debt.json +60 -94
- package/architecture/maintainability-policy.json +7 -13
- package/architecture/minimal-consumer-migration.json +43 -5014
- package/architecture/platform-stage-checkpoints.json +1 -1
- package/architecture/release-tail-contract.json +2 -2
- package/architecture/release-topology.json +31 -25
- package/architecture/stage-capsule-qualification.json +1 -1
- package/architecture/universal-workflow-bootstrap.json +60 -60
- package/architecture/universal-workflow-capability-policy.json +3 -3
- package/architecture/universal-workflow-fault-campaign.json +7 -7
- package/architecture/workflow-taxonomy.json +59 -60
- package/contracts/fixtures/v4-tail-reseal-v1/valid.json +1 -1
- package/dist/site/buildchain-contract.json +138 -66
- package/dist/site/buildchain-site.json +257 -331
- package/dist/site/capability-registry.json +4 -4
- package/dist/site/cli-registry.json +6 -142
- package/dist/site/controller-registry.json +19 -19
- package/dist/site/kfd-claims.json +481 -529
- package/dist/site/kfd-upstream-aggregate.json +1 -1
- package/dist/site/manual-registry.json +22 -22
- package/dist/site/node-api-registry.json +82 -339
- package/dist/site/page-registry.json +229 -304
- package/dist/site/public-surface-audit.json +544 -754
- package/dist/site/publication-authority-registry.json +316 -316
- package/dist/site/publication-registry.json +1 -1
- package/dist/site/site-manifest.json +23 -23
- package/dist/site/workflow-registry.json +1071 -1027
- package/docs/MAP.md +28 -20
- package/docs/auditable-demo.md +17 -49
- package/docs/bootstrap-recovery.md +46 -37
- package/docs/cli-reference.md +2 -46
- package/docs/cli.md +97 -186
- package/docs/code-organization.md +7 -5
- package/docs/dev-alpha-candidate-patrol.md +19 -42
- package/docs/dev-delivery-orchestration.md +15 -11
- package/docs/dev-delivery-qualification-landing-adr.md +10 -9
- package/docs/dev-delivery-warrant.md +17 -16
- package/docs/dev-qualification-patrol.md +25 -20
- package/docs/getting-started.md +80 -139
- package/docs/github-artifact-attestation.md +31 -81
- package/docs/install.md +66 -30
- package/docs/lifecycle-protocol.md +19 -57
- package/docs/migration-inventory.md +17 -45
- package/docs/next-development-transition.md +13 -13
- package/docs/node-api-reference.md +122 -138
- package/docs/oci-publication.md +13 -10
- package/docs/publication-artifacts.md +128 -486
- package/docs/publication-authority.md +15 -45
- package/docs/publish-transaction.md +13 -11
- package/docs/release-candidate.md +126 -355
- package/docs/release-discussions.md +36 -67
- package/docs/release-flow.md +80 -339
- package/docs/release-governance.md +114 -962
- package/docs/release-promotion-request.md +45 -43
- package/docs/release-propagation.md +13 -27
- package/docs/release-tail-provider-plane.md +38 -65
- package/docs/reusable-build-surface.md +78 -196
- package/docs/runtime-train-validation.md +8 -6
- package/docs/stable-candidate-patrol.md +13 -66
- package/docs/v4-adopter-delivery.md +15 -15
- package/docs/v4-declarative-release-tail-migration.md +19 -17
- package/docs/v4-production-release.md +11 -6
- package/docs/v4-publication-rehearsal.md +12 -27
- package/docs/v4-stage-capsule.md +14 -20
- package/docs/v4-tail-reseal.md +34 -20
- package/docs/web-surface-deployments.md +26 -264
- package/docs/workflow-catalog.md +31 -31
- package/docs/workflow-path-migration.md +10 -4
- package/package.json +5 -4
- package/packages/core/adoption/buildchain-kfd-claims.js +7 -7
- package/packages/core/adoption/cli/output.mjs +1 -9
- package/packages/core/adoption/cli/product-gate.mjs +1 -15
- package/packages/core/adoption/cli/project.mjs +9 -10
- package/packages/core/adoption/cli/standards.mjs +1 -14
- package/packages/core/adoption/cli/support.mjs +0 -2
- package/packages/core/adoption/cli/surface-register.mjs +0 -2
- package/packages/core/adoption/commands/init-repo.mjs +77 -485
- package/packages/core/adoption/consumer-init.js +279 -0
- package/packages/core/adoption/qualification/admission.js +1 -1
- package/packages/core/build/cli/cache.mjs +0 -2
- package/packages/core/build/cli/facts.mjs +0 -3
- package/packages/core/build/cli/homebrew.mjs +0 -4
- package/packages/core/build/cli/lifecycle.mjs +0 -3
- package/packages/core/build/github-artifact-attestation.js +2 -2
- package/packages/core/build/platform-stage-checkpoints.js +1 -1
- package/packages/core/build/signing/dispatch.js +1 -1
- package/packages/core/consumer/buildchain-config.js +9 -0
- package/packages/core/consumer/contract/inspection.js +351 -9
- package/packages/core/consumer/contract/javascript-syntax.js +439 -0
- package/packages/core/consumer/contract/javascript-values.js +61 -0
- package/packages/core/consumer/contract/javascript.js +555 -0
- package/packages/core/consumer/contract/local-validation.js +84 -0
- package/packages/core/contracts/buildchain-contract.js +39 -8
- package/packages/core/contracts/cli/introspection.mjs +1 -9
- package/packages/core/contracts/public-surface-cli.js +0 -1
- package/packages/core/dev-delivery/dev-delivery-contract-surface.js +2 -2
- package/packages/core/governance/buildchain-publication-authority.js +24 -24
- package/packages/core/governance/cli/doctor.mjs +58 -42
- package/packages/core/governance/commands/architecture.mjs +6 -1
- package/packages/core/governance/commands/audit-publication-control-plane.mjs +1 -1
- package/packages/core/governance/commands/workflow-friction-report.mjs +1 -1
- package/packages/core/governance/github-governance-authority.js +2 -2
- package/packages/core/governance/publication/collection.js +1 -1
- package/packages/core/index.js +1 -3
- package/packages/core/observability/cli/candidate.mjs +0 -2
- package/packages/core/observability/cli/context.mjs +0 -5
- package/packages/core/observability/cli/diagnostics.mjs +0 -7
- package/packages/core/observability/cli/events.mjs +2 -10
- package/packages/core/paper/commands/paper-work-fleet-cli.mjs +1 -1
- package/packages/core/paper/commands/paper.mjs +33 -422
- package/packages/core/paper/consumer-status.js +72 -0
- package/packages/core/paper/operations/identity.js +0 -3
- package/packages/core/paper/operations/migration.js +460 -0
- package/packages/core/paper/operations/preflight-checks.js +8 -68
- package/packages/core/paper/operations/scaffold.js +16 -326
- package/packages/core/paper/operations/status.js +27 -53
- package/packages/core/paper/paper-agent-entry.js +36 -147
- package/packages/core/paper/paper-fleet.js +24 -39
- package/packages/core/paper/paper-repository.js +16 -0
- package/packages/core/paper/paper-runtime-channels.js +1 -1
- package/packages/core/paper/paper-scaffold-content.js +153 -162
- package/packages/core/paper/paper-work.js +3 -10
- package/packages/core/paper/paper.js +43 -5
- package/packages/core/providers/github/artifact-attestation.js +1 -1
- package/packages/core/providers/github/pipeline-context-artifacts.js +172 -0
- package/packages/core/publication/authority/control-plane.js +2 -2
- package/packages/core/publication/authority/seal.js +1 -1
- package/packages/core/publication/cli/dispatch.mjs +1 -12
- package/packages/core/publication/pipeline/actions.js +16 -9
- package/packages/core/publication/pipeline/apply.js +17 -9
- package/packages/core/publication/pipeline/context.js +29 -0
- package/packages/core/publication/pipeline/prepare.js +15 -6
- package/packages/core/publication/pipeline/recovery-materials.js +63 -1
- package/packages/core/publication/pipeline/recovery-prepare.js +21 -9
- package/packages/core/publication/pipeline/stable-entry.js +12 -7
- package/packages/core/publication/pipeline/stable-products.js +21 -19
- package/packages/core/publication/pipeline/version-actions.js +15 -6
- package/packages/core/publication/publication-rehearsal-projection.js +0 -9
- package/packages/core/release/cli/dispatch.mjs +1 -4
- package/packages/core/release/cli/inspection-handlers.mjs +1 -33
- package/packages/core/release/cli/release-handlers.mjs +2 -19
- package/packages/core/release/cli/verification-handlers.mjs +4 -25
- package/packages/core/release/next-development-projection.js +13 -13
- package/packages/core/release/passport/locations.js +13 -8
- package/packages/core/release/release-passport.js +70 -5
- package/packages/core/web/cli/badges.mjs +0 -4
- package/packages/core/web/publication-admission.js +1 -1
- package/packages/core/web/publication-capability.js +1 -1
- package/packages/core/web/readme-badges.js +1 -1
- package/packages/core/workflow/cli/main.mjs +1 -4
- package/packages/core/workflow/cli/process.mjs +1 -1
- package/packages/core/workflow/commands/buildchain-cli-help.mjs +2 -8
- package/packages/core/workflow/engine/conformance.js +1 -1
- package/packages/core/workflow/pipeline/build.js +21 -1
- package/packages/core/workflow/pipeline/delivery-observation.js +6 -2
- package/packages/core/workflow/workflow-taxonomy.mjs +61 -17
- package/scripts/check-code-layout.mjs +2 -0
- package/scripts/check-core-mechanism-inventory.mjs +29 -13
- package/scripts/check-floating-consumer-policy-contract.mjs +3 -3
- package/scripts/check-inventory.mjs +27 -27
- package/scripts/check-maintainability.mjs +28 -5
- package/scripts/check-public-dogfood-contract.mjs +3 -3
- package/scripts/check-release-topology.mjs +1 -1
- package/scripts/check-self-consumer-contract.mjs +7 -7
- package/scripts/check-universal-workflow-bootstrap.mjs +1 -1
- package/scripts/generate-channel-promotion-workflow.mjs +1 -1
- package/scripts/generate-minimal-consumer-contract.mjs +21 -1
- package/scripts/generate-site-bundle.mjs +2 -1
- package/scripts/generate-tail-reseal-fixture.mjs +3 -3
- package/scripts/inventory/promotion.mjs +1 -1
- package/scripts/next-development-self-dogfood-harness.mjs +1 -1
- package/scripts/next-development-self-dogfood.mjs +4 -4
- package/scripts/site-capability-metadata.mjs +2 -6
- package/scripts/source-metric-lineage.mjs +62 -7
- package/scripts/verify-golden-path.mjs +31 -35
- package/templates/native-dev-delivery.yml +1 -1
- package/templates/universal-buildchain-bootstrap.yml +1 -1
- package/packages/core/paper/operations/bootstrap.js +0 -75
- package/packages/core/paper/operations/plans.js +0 -213
- package/packages/core/paper/operations/provisioning.js +0 -113
- package/packages/core/paper/operations/scaffold-config.js +0 -77
- package/packages/core/paper/operations/scaffold-workflows.js +0 -116
- package/packages/core/paper/operations/workspace.js +0 -60
- package/packages/core/paper/paper-npm-bootstrap.js +0 -492
|
@@ -0,0 +1,439 @@
|
|
|
1
|
+
import { UNKNOWN, TAG, tagged, namespace } from "./javascript-values.js";
|
|
2
|
+
|
|
3
|
+
function expressionLiteral(ctx, node, scope) {
|
|
4
|
+
return node.value;
|
|
5
|
+
}
|
|
6
|
+
function expressionIdentifier(ctx, node, scope) {
|
|
7
|
+
const { get } = ctx;
|
|
8
|
+
return get(scope, node.name);
|
|
9
|
+
}
|
|
10
|
+
function expressionFunctionExpression(ctx, node, scope) {
|
|
11
|
+
return tagged("function", { node, scope });
|
|
12
|
+
}
|
|
13
|
+
function expressionArrayExpression(ctx, node, scope) {
|
|
14
|
+
const { expression } = ctx;
|
|
15
|
+
return node.elements.map((item) => expression(item, scope));
|
|
16
|
+
}
|
|
17
|
+
function expressionObjectExpression(ctx, node, scope) {
|
|
18
|
+
const { expression, report, get } = ctx;
|
|
19
|
+
{
|
|
20
|
+
const value = Object.create(null);
|
|
21
|
+
for (const property of node.properties) {
|
|
22
|
+
if (property.type === "SpreadElement") {
|
|
23
|
+
expression(property.argument, scope);
|
|
24
|
+
report(
|
|
25
|
+
property,
|
|
26
|
+
"unsupported-spread",
|
|
27
|
+
"Object spread requires resolved property execution",
|
|
28
|
+
);
|
|
29
|
+
continue;
|
|
30
|
+
}
|
|
31
|
+
if (property.kind === "get" || property.kind === "set")
|
|
32
|
+
report(
|
|
33
|
+
property,
|
|
34
|
+
"unsupported-accessor",
|
|
35
|
+
"Accessor execution must be resolved explicitly",
|
|
36
|
+
);
|
|
37
|
+
const key = property.computed
|
|
38
|
+
? expression(property.key, scope)
|
|
39
|
+
: (property.key.name ?? property.key.value);
|
|
40
|
+
if (typeof key !== "string" && typeof key !== "number") {
|
|
41
|
+
report(
|
|
42
|
+
property,
|
|
43
|
+
"unresolved-property",
|
|
44
|
+
"Computed property must resolve",
|
|
45
|
+
);
|
|
46
|
+
expression(property.value, scope);
|
|
47
|
+
continue;
|
|
48
|
+
}
|
|
49
|
+
value[key] = expression(property.value, scope);
|
|
50
|
+
}
|
|
51
|
+
return value;
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
function expressionMemberExpression(ctx, node, scope) {
|
|
55
|
+
const { member, expression, report } = ctx;
|
|
56
|
+
{
|
|
57
|
+
const object = expression(node.object, scope),
|
|
58
|
+
key = node.computed
|
|
59
|
+
? expression(node.property, scope)
|
|
60
|
+
: node.property.name;
|
|
61
|
+
if (["constructor", "prototype", "__proto__"].includes(key))
|
|
62
|
+
report(
|
|
63
|
+
node,
|
|
64
|
+
"dynamic-prototype",
|
|
65
|
+
"Prototype execution is outside the static invocation subset",
|
|
66
|
+
);
|
|
67
|
+
return member(object, key);
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
function expressionCallExpression(ctx, node, scope) {
|
|
71
|
+
const { invoke, expression } = ctx;
|
|
72
|
+
const result = invoke(
|
|
73
|
+
node,
|
|
74
|
+
expression(node.callee, scope),
|
|
75
|
+
node.arguments.map((argument) => expression(argument, scope)),
|
|
76
|
+
);
|
|
77
|
+
if (node.type === "NewExpression") {
|
|
78
|
+
ctx.report(
|
|
79
|
+
node,
|
|
80
|
+
"unsupported-construction",
|
|
81
|
+
"Constructor result and prototype behavior must be resolved explicitly",
|
|
82
|
+
);
|
|
83
|
+
return UNKNOWN;
|
|
84
|
+
}
|
|
85
|
+
return result;
|
|
86
|
+
}
|
|
87
|
+
function expressionImportExpression(ctx, node, scope) {
|
|
88
|
+
const { imported, expression } = ctx;
|
|
89
|
+
return imported(node, expression(node.source, scope));
|
|
90
|
+
}
|
|
91
|
+
function expressionAwaitExpression(ctx, node, scope) {
|
|
92
|
+
const { invoke, expression, report } = ctx;
|
|
93
|
+
{
|
|
94
|
+
const value = expression(node.argument, scope);
|
|
95
|
+
if (value && typeof value === "object" && !value[TAG])
|
|
96
|
+
report(
|
|
97
|
+
node,
|
|
98
|
+
"unresolved-await",
|
|
99
|
+
"Await may invoke a user-defined thenable",
|
|
100
|
+
);
|
|
101
|
+
return value;
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
function expressionChainExpression(ctx, node, scope) {
|
|
105
|
+
const { expression } = ctx;
|
|
106
|
+
return expression(node.argument || node.expression, scope);
|
|
107
|
+
}
|
|
108
|
+
function expressionBinaryExpression(ctx, node, scope) {
|
|
109
|
+
const { expression, data, checkCoercion } = ctx;
|
|
110
|
+
{
|
|
111
|
+
const left = expression(node.left, scope),
|
|
112
|
+
right = expression(node.right, scope);
|
|
113
|
+
if (
|
|
114
|
+
node.operator === "+" &&
|
|
115
|
+
[left, right].every((value) =>
|
|
116
|
+
["string", "number"].includes(typeof value),
|
|
117
|
+
)
|
|
118
|
+
)
|
|
119
|
+
return left + right;
|
|
120
|
+
if (
|
|
121
|
+
left !== UNKNOWN &&
|
|
122
|
+
right !== UNKNOWN &&
|
|
123
|
+
!left?.[TAG] &&
|
|
124
|
+
!right?.[TAG] &&
|
|
125
|
+
["===", "!=="].includes(node.operator)
|
|
126
|
+
)
|
|
127
|
+
return node.operator === "===" ? left === right : left !== right;
|
|
128
|
+
if (!["===", "!=="].includes(node.operator))
|
|
129
|
+
checkCoercion(node, [left, right]);
|
|
130
|
+
return data();
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
function expressionTemplateLiteral(ctx, node, scope) {
|
|
134
|
+
const { expression, data, checkCoercion } = ctx;
|
|
135
|
+
{
|
|
136
|
+
const values = node.expressions.map((value) => expression(value, scope));
|
|
137
|
+
checkCoercion(node, values);
|
|
138
|
+
return values.every((value) => ["string", "number"].includes(typeof value))
|
|
139
|
+
? node.quasis
|
|
140
|
+
.map(
|
|
141
|
+
(part, index) =>
|
|
142
|
+
part.value.cooked + (index < values.length ? values[index] : ""),
|
|
143
|
+
)
|
|
144
|
+
.join("")
|
|
145
|
+
: data();
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
function expressionConditionalExpression(ctx, node, scope) {
|
|
149
|
+
const { expression, report } = ctx;
|
|
150
|
+
{
|
|
151
|
+
const value = expression(node.test || node.left, scope);
|
|
152
|
+
if (value === UNKNOWN || value?.[TAG]) {
|
|
153
|
+
report(
|
|
154
|
+
node,
|
|
155
|
+
"unresolved-condition",
|
|
156
|
+
"Conditional expression requires a resolved condition",
|
|
157
|
+
);
|
|
158
|
+
expression(node.consequent || node.right, scope);
|
|
159
|
+
if (node.alternate) expression(node.alternate, scope);
|
|
160
|
+
return UNKNOWN;
|
|
161
|
+
}
|
|
162
|
+
if (node.test)
|
|
163
|
+
return expression(value ? node.consequent : node.alternate, scope);
|
|
164
|
+
const useRight =
|
|
165
|
+
node.operator === "&&"
|
|
166
|
+
? Boolean(value)
|
|
167
|
+
: node.operator === "||"
|
|
168
|
+
? !value
|
|
169
|
+
: value == null;
|
|
170
|
+
return useRight ? expression(node.right, scope) : value;
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
function expressionAssignmentExpression(ctx, node, scope) {
|
|
174
|
+
const { expression, data, report, get, checkCoercion } = ctx;
|
|
175
|
+
{
|
|
176
|
+
const value = expression(node.right, scope);
|
|
177
|
+
if (node.left.type !== "Identifier" || !scope.has(node.left.name)) {
|
|
178
|
+
report(
|
|
179
|
+
node,
|
|
180
|
+
"unsupported-assignment",
|
|
181
|
+
"Assignment requires a resolved lexical binding",
|
|
182
|
+
);
|
|
183
|
+
return UNKNOWN;
|
|
184
|
+
}
|
|
185
|
+
const previous = get(scope, node.left.name);
|
|
186
|
+
let assigned = value;
|
|
187
|
+
if (node.operator === "+=") {
|
|
188
|
+
checkCoercion(node, [previous, value]);
|
|
189
|
+
assigned = [previous, value].every((item) =>
|
|
190
|
+
["string", "number"].includes(typeof item),
|
|
191
|
+
)
|
|
192
|
+
? previous + value
|
|
193
|
+
: data();
|
|
194
|
+
} else if (node.operator !== "=") {
|
|
195
|
+
report(
|
|
196
|
+
node,
|
|
197
|
+
"unsupported-assignment",
|
|
198
|
+
`Unsupported assignment operator: ${node.operator}`,
|
|
199
|
+
);
|
|
200
|
+
assigned = UNKNOWN;
|
|
201
|
+
}
|
|
202
|
+
scope.get(node.left.name).value = assigned;
|
|
203
|
+
return assigned;
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
function expressionSequenceExpression(ctx, node, scope) {
|
|
207
|
+
const { expression } = ctx;
|
|
208
|
+
return node.expressions.map((value) => expression(value, scope)).at(-1);
|
|
209
|
+
}
|
|
210
|
+
function expressionUnaryExpression(ctx, node, scope) {
|
|
211
|
+
const { expression, report, checkCoercion } = ctx;
|
|
212
|
+
checkCoercion(node, [expression(node.argument, scope)]);
|
|
213
|
+
report(
|
|
214
|
+
node,
|
|
215
|
+
"unsupported-operator",
|
|
216
|
+
`Unsupported unary operator: ${node.operator}`,
|
|
217
|
+
);
|
|
218
|
+
return UNKNOWN;
|
|
219
|
+
}
|
|
220
|
+
function expressionUnknown(ctx, node, scope) {
|
|
221
|
+
const { expression, report } = ctx;
|
|
222
|
+
report(
|
|
223
|
+
node,
|
|
224
|
+
"unsupported-expression",
|
|
225
|
+
`Unsupported executable syntax: ${node.type}`,
|
|
226
|
+
);
|
|
227
|
+
return UNKNOWN;
|
|
228
|
+
}
|
|
229
|
+
const expressionHandlers = {
|
|
230
|
+
Literal: expressionLiteral,
|
|
231
|
+
Identifier: expressionIdentifier,
|
|
232
|
+
FunctionExpression: expressionFunctionExpression,
|
|
233
|
+
ArrowFunctionExpression: expressionFunctionExpression,
|
|
234
|
+
ArrayExpression: expressionArrayExpression,
|
|
235
|
+
ObjectExpression: expressionObjectExpression,
|
|
236
|
+
MemberExpression: expressionMemberExpression,
|
|
237
|
+
CallExpression: expressionCallExpression,
|
|
238
|
+
NewExpression: expressionCallExpression,
|
|
239
|
+
ImportExpression: expressionImportExpression,
|
|
240
|
+
AwaitExpression: expressionAwaitExpression,
|
|
241
|
+
ChainExpression: expressionChainExpression,
|
|
242
|
+
BinaryExpression: expressionBinaryExpression,
|
|
243
|
+
TemplateLiteral: expressionTemplateLiteral,
|
|
244
|
+
ConditionalExpression: expressionConditionalExpression,
|
|
245
|
+
LogicalExpression: expressionConditionalExpression,
|
|
246
|
+
AssignmentExpression: expressionAssignmentExpression,
|
|
247
|
+
SequenceExpression: expressionSequenceExpression,
|
|
248
|
+
UnaryExpression: expressionUnaryExpression,
|
|
249
|
+
UpdateExpression: expressionUnaryExpression,
|
|
250
|
+
};
|
|
251
|
+
export function evaluateExpression(ctx, node, scope) {
|
|
252
|
+
if (!node) return undefined;
|
|
253
|
+
ctx.visit();
|
|
254
|
+
return (expressionHandlers[node.type] || expressionUnknown)(ctx, node, scope);
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
function statementsFunctionDeclaration(ctx, node, scope) {}
|
|
258
|
+
function statementsImportDeclaration(ctx, node, scope) {
|
|
259
|
+
const { member, imported, declare } = ctx;
|
|
260
|
+
{
|
|
261
|
+
imported(node, node.source.value);
|
|
262
|
+
for (const item of node.specifiers)
|
|
263
|
+
declare(
|
|
264
|
+
scope,
|
|
265
|
+
item.local.name,
|
|
266
|
+
item.type === "ImportSpecifier"
|
|
267
|
+
? member(
|
|
268
|
+
namespace(node.source.value),
|
|
269
|
+
item.imported.name ?? item.imported.value,
|
|
270
|
+
)
|
|
271
|
+
: item.type === "ImportDefaultSpecifier" &&
|
|
272
|
+
node.source.value.startsWith(".")
|
|
273
|
+
? member(namespace(node.source.value), "default")
|
|
274
|
+
: namespace(node.source.value),
|
|
275
|
+
);
|
|
276
|
+
return;
|
|
277
|
+
}
|
|
278
|
+
}
|
|
279
|
+
function statementsVariableDeclaration(ctx, node, scope) {
|
|
280
|
+
const { bind, expression } = ctx;
|
|
281
|
+
for (const item of node.declarations)
|
|
282
|
+
bind(item.id, expression(item.init, scope), scope);
|
|
283
|
+
}
|
|
284
|
+
function statementsExpressionStatement(ctx, node, scope) {
|
|
285
|
+
const { expression } = ctx;
|
|
286
|
+
expression(node.expression, scope);
|
|
287
|
+
}
|
|
288
|
+
function statementsReturnStatement(ctx, node, scope) {
|
|
289
|
+
const { expression } = ctx;
|
|
290
|
+
return { returned: true, value: expression(node.argument, scope) };
|
|
291
|
+
}
|
|
292
|
+
function statementsThrowStatement(ctx, node, scope) {
|
|
293
|
+
const { expression } = ctx;
|
|
294
|
+
expression(node.argument, scope);
|
|
295
|
+
}
|
|
296
|
+
function statementsBlockStatement(ctx, node, scope) {
|
|
297
|
+
const { statements } = ctx;
|
|
298
|
+
{
|
|
299
|
+
const result = statements(node.body, new Map(scope));
|
|
300
|
+
if (result.returned) return result;
|
|
301
|
+
return;
|
|
302
|
+
}
|
|
303
|
+
}
|
|
304
|
+
function statementsIfStatement(ctx, node, scope) {
|
|
305
|
+
const { expression, statements, report } = ctx;
|
|
306
|
+
{
|
|
307
|
+
const value = expression(node.test, scope);
|
|
308
|
+
if (value === UNKNOWN || value?.[TAG])
|
|
309
|
+
report(
|
|
310
|
+
node,
|
|
311
|
+
"unresolved-condition",
|
|
312
|
+
"Conditional execution requires a resolved condition",
|
|
313
|
+
);
|
|
314
|
+
const branches =
|
|
315
|
+
value === UNKNOWN || value?.[TAG]
|
|
316
|
+
? [node.consequent, node.alternate]
|
|
317
|
+
: [value ? node.consequent : node.alternate];
|
|
318
|
+
const results = branches
|
|
319
|
+
.filter(Boolean)
|
|
320
|
+
.map((branch) => statements([branch], new Map(scope)));
|
|
321
|
+
if (
|
|
322
|
+
results.length &&
|
|
323
|
+
results.every((result) => result.returned) &&
|
|
324
|
+
results.every((result) => result.value === results[0].value)
|
|
325
|
+
)
|
|
326
|
+
return results[0];
|
|
327
|
+
return;
|
|
328
|
+
}
|
|
329
|
+
}
|
|
330
|
+
function statementsForStatement(ctx, node, scope) {
|
|
331
|
+
const { bind, expression, statements, report } = ctx;
|
|
332
|
+
{
|
|
333
|
+
const loop = new Map(scope);
|
|
334
|
+
if (node.type === "ForOfStatement") {
|
|
335
|
+
const values = expression(node.right, scope);
|
|
336
|
+
if (!Array.isArray(values) || values.length > 1000)
|
|
337
|
+
report(
|
|
338
|
+
node,
|
|
339
|
+
"unresolved-iteration",
|
|
340
|
+
"Iteration requires a bounded resolved array",
|
|
341
|
+
);
|
|
342
|
+
else
|
|
343
|
+
for (const value of values) {
|
|
344
|
+
const iteration = new Map(scope);
|
|
345
|
+
bind(node.left.declarations?.[0]?.id || node.left, value, iteration);
|
|
346
|
+
const result = statements([node.body], iteration);
|
|
347
|
+
if (result.returned) return result;
|
|
348
|
+
}
|
|
349
|
+
return;
|
|
350
|
+
}
|
|
351
|
+
report(node, "unresolved-iteration", "Loop expansion is not resolved");
|
|
352
|
+
if (node.init?.type === "VariableDeclaration")
|
|
353
|
+
statements([node.init], loop);
|
|
354
|
+
else expression(node.init, loop);
|
|
355
|
+
if (node.left?.type === "VariableDeclaration")
|
|
356
|
+
for (const item of node.left.declarations) bind(item.id, UNKNOWN, loop);
|
|
357
|
+
expression(node.right || node.test, loop);
|
|
358
|
+
statements([node.body], loop);
|
|
359
|
+
expression(node.update, loop);
|
|
360
|
+
return;
|
|
361
|
+
}
|
|
362
|
+
}
|
|
363
|
+
function statementsTryStatement(ctx, node, scope) {
|
|
364
|
+
const { statements } = ctx;
|
|
365
|
+
ctx.report(
|
|
366
|
+
node,
|
|
367
|
+
"unresolved-exception-path",
|
|
368
|
+
"Exception paths cannot share a resolved mutable environment",
|
|
369
|
+
);
|
|
370
|
+
statements([node.block], new Map(scope));
|
|
371
|
+
if (node.handler) statements([node.handler.body], new Map(scope));
|
|
372
|
+
if (node.finalizer) statements([node.finalizer], new Map(scope));
|
|
373
|
+
}
|
|
374
|
+
function statementsExportNamedDeclaration(ctx, node, scope) {
|
|
375
|
+
const { imported, expression, statements, get, declare, exports } = ctx;
|
|
376
|
+
{
|
|
377
|
+
if (node.declaration?.type === "FunctionDeclaration") {
|
|
378
|
+
const name = node.declaration.id?.name || "default",
|
|
379
|
+
value = tagged("function", { node: node.declaration, scope });
|
|
380
|
+
declare(scope, name, value);
|
|
381
|
+
exports.set(
|
|
382
|
+
node.type === "ExportDefaultDeclaration" ? "default" : name,
|
|
383
|
+
value,
|
|
384
|
+
);
|
|
385
|
+
} else if (node.declaration?.type === "VariableDeclaration") {
|
|
386
|
+
statements([node.declaration], scope);
|
|
387
|
+
for (const item of node.declaration.declarations)
|
|
388
|
+
if (item.id.type === "Identifier")
|
|
389
|
+
exports.set(item.id.name, get(scope, item.id.name));
|
|
390
|
+
} else if (node.declaration)
|
|
391
|
+
exports.set("default", expression(node.declaration, scope));
|
|
392
|
+
if (node.source) imported(node, node.source.value);
|
|
393
|
+
for (const item of node.specifiers || [])
|
|
394
|
+
exports.set(item.exported.name, get(scope, item.local.name));
|
|
395
|
+
return;
|
|
396
|
+
}
|
|
397
|
+
}
|
|
398
|
+
function statementsUnknown(ctx, node, scope) {
|
|
399
|
+
const { report } = ctx;
|
|
400
|
+
report(
|
|
401
|
+
node,
|
|
402
|
+
"unsupported-statement",
|
|
403
|
+
`Unsupported executable syntax: ${node.type}`,
|
|
404
|
+
);
|
|
405
|
+
}
|
|
406
|
+
const statementsHandlers = {
|
|
407
|
+
FunctionDeclaration: statementsFunctionDeclaration,
|
|
408
|
+
EmptyStatement: statementsFunctionDeclaration,
|
|
409
|
+
ImportDeclaration: statementsImportDeclaration,
|
|
410
|
+
VariableDeclaration: statementsVariableDeclaration,
|
|
411
|
+
ExpressionStatement: statementsExpressionStatement,
|
|
412
|
+
ReturnStatement: statementsReturnStatement,
|
|
413
|
+
ThrowStatement: statementsThrowStatement,
|
|
414
|
+
BlockStatement: statementsBlockStatement,
|
|
415
|
+
IfStatement: statementsIfStatement,
|
|
416
|
+
ForStatement: statementsForStatement,
|
|
417
|
+
ForOfStatement: statementsForStatement,
|
|
418
|
+
ForInStatement: statementsForStatement,
|
|
419
|
+
WhileStatement: statementsForStatement,
|
|
420
|
+
DoWhileStatement: statementsForStatement,
|
|
421
|
+
TryStatement: statementsTryStatement,
|
|
422
|
+
ExportNamedDeclaration: statementsExportNamedDeclaration,
|
|
423
|
+
ExportDefaultDeclaration: statementsExportNamedDeclaration,
|
|
424
|
+
};
|
|
425
|
+
export function evaluateStatements(ctx, nodes, scope) {
|
|
426
|
+
for (const node of nodes)
|
|
427
|
+
if (node.type === "FunctionDeclaration")
|
|
428
|
+
ctx.declare(scope, node.id.name, tagged("function", { node, scope }));
|
|
429
|
+
for (const node of nodes) {
|
|
430
|
+
ctx.visit();
|
|
431
|
+
const result = (statementsHandlers[node.type] || statementsUnknown)(
|
|
432
|
+
ctx,
|
|
433
|
+
node,
|
|
434
|
+
scope,
|
|
435
|
+
);
|
|
436
|
+
if (result?.returned) return result;
|
|
437
|
+
}
|
|
438
|
+
return { returned: false, value: undefined };
|
|
439
|
+
}
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
export const UNKNOWN = Symbol("unresolved value"),
|
|
2
|
+
TAG = Symbol("analyzer value");
|
|
3
|
+
export const tagged = (kind, value) => ({ [TAG]: kind, ...value });
|
|
4
|
+
export const namespace = (specifier) => tagged("namespace", { specifier });
|
|
5
|
+
|
|
6
|
+
// Edges cross module boundaries as data, never as interpreter objects. A
|
|
7
|
+
// callback or opaque runtime value requires analysis at its real call site.
|
|
8
|
+
export function concreteArguments(values, seen = new Set()) {
|
|
9
|
+
if (values === null || values === undefined) return true;
|
|
10
|
+
if (["string", "number", "boolean", "bigint"].includes(typeof values))
|
|
11
|
+
return true;
|
|
12
|
+
if (typeof values !== "object" || values[TAG] || seen.has(values))
|
|
13
|
+
return false;
|
|
14
|
+
seen.add(values);
|
|
15
|
+
const result = Object.values(values).every((value) =>
|
|
16
|
+
concreteArguments(value, seen),
|
|
17
|
+
);
|
|
18
|
+
seen.delete(values);
|
|
19
|
+
return result;
|
|
20
|
+
}
|
|
21
|
+
export const processCalls = new Set([
|
|
22
|
+
"exec",
|
|
23
|
+
"execSync",
|
|
24
|
+
"execFile",
|
|
25
|
+
"execFileSync",
|
|
26
|
+
"spawn",
|
|
27
|
+
"spawnSync",
|
|
28
|
+
"fork",
|
|
29
|
+
]);
|
|
30
|
+
export const inertModules = new Set([
|
|
31
|
+
"fs",
|
|
32
|
+
"fs/promises",
|
|
33
|
+
"assert",
|
|
34
|
+
"assert/strict",
|
|
35
|
+
"buffer",
|
|
36
|
+
"crypto",
|
|
37
|
+
"os",
|
|
38
|
+
"util",
|
|
39
|
+
"events",
|
|
40
|
+
"stream",
|
|
41
|
+
"zlib",
|
|
42
|
+
"url",
|
|
43
|
+
"path",
|
|
44
|
+
"path/posix",
|
|
45
|
+
"path/win32",
|
|
46
|
+
]);
|
|
47
|
+
export const inertGlobals = new Set([
|
|
48
|
+
"String",
|
|
49
|
+
"Number",
|
|
50
|
+
"Boolean",
|
|
51
|
+
"BigInt",
|
|
52
|
+
"Object",
|
|
53
|
+
"Array",
|
|
54
|
+
"JSON",
|
|
55
|
+
"Math",
|
|
56
|
+
"Buffer",
|
|
57
|
+
"console",
|
|
58
|
+
"Error",
|
|
59
|
+
"TypeError",
|
|
60
|
+
"RangeError",
|
|
61
|
+
]);
|