@pulse-compute/wasm-compiler 0.0.0 → 1.0.0-beta.2
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 +53 -1
- package/bin/provider-proof-composition.js +34 -0
- package/bin/pulsewasm-extract.js +20 -0
- package/package.json +60 -5
- package/src/artifacts-dir.js +13 -0
- package/src/ast-json.js +52 -0
- package/src/build-manifest.js +354 -0
- package/src/canonical-api-compiler.js +269 -0
- package/src/canonical-native-compiler.js +411 -0
- package/src/canonical-native-plan.js +1478 -0
- package/src/canonical-project-compiler.js +1224 -0
- package/src/canonical-router-compiler.js +25 -0
- package/src/cli-intents.js +1235 -0
- package/src/cli.js +1927 -0
- package/src/codegen/assemblyscript-compile.js +3 -0
- package/src/codegen/assemblyscript-core.js +3 -0
- package/src/codegen/assemblyscript-shape.js +3 -0
- package/src/codegen/assemblyscript-wasm-smoke.js +3 -0
- package/src/codegen/backend-capabilities.js +3 -0
- package/src/codegen/channel-broadcaster.js +3 -0
- package/src/codegen/compiled-handlers.js +3 -0
- package/src/codegen/compiled-wasm-runtime.js +3 -0
- package/src/codegen/config-references.js +248 -0
- package/src/codegen/dispatch-ts.js +145 -0
- package/src/codegen/effect-composition.js +331 -0
- package/src/codegen/effect-runtime.js +418 -0
- package/src/codegen/execution-harness-ts.js +467 -0
- package/src/codegen/handler-bindings-ts.js +298 -0
- package/src/codegen/handler-library-contracts.js +3 -0
- package/src/codegen/host-capabilities.js +3 -0
- package/src/codegen/host-runtime-kernel.js +3 -0
- package/src/codegen/integrated-compiled-app.js +3 -0
- package/src/codegen/json-body.js +3 -0
- package/src/codegen/library-sidecars.js +3 -0
- package/src/codegen/local-harness-ts.js +453 -0
- package/src/codegen/pulse-wrapper.js +217 -0
- package/src/codegen/request-result-headers.js +3 -0
- package/src/codegen/schema-json-compile.js +3 -0
- package/src/codegen/schema-json-sidecar-v2.js +3 -0
- package/src/codegen/schema-json-sidecar.js +3 -0
- package/src/codegen/streaming-passthrough.js +3 -0
- package/src/codegen/wasm-host-abi.js +3 -0
- package/src/codegen/wasm-host-bridge.js +3 -0
- package/src/compiled-wasm-host-runtime-kv.js +3 -0
- package/src/config-resolver.js +813 -0
- package/src/crypto-requirement-planner.js +89 -0
- package/src/definitions/config-schema.js +14 -0
- package/src/definitions/handler-roles.js +14 -0
- package/src/definitions/path-grammar.js +14 -0
- package/src/definitions/router-api.js +14 -0
- package/src/diagnostics/codes.js +14 -0
- package/src/diagnostics/reporter.js +14 -0
- package/src/diagnostics.js +14 -0
- package/src/dispatch-table.js +400 -0
- package/src/events/event-emit.js +265 -0
- package/src/events/event-topology.js +127 -0
- package/src/execution-plan.js +463 -0
- package/src/extractor.js +2816 -0
- package/src/handler-eval.js +1154 -0
- package/src/handler-table.js +326 -0
- package/src/index.js +19 -0
- package/src/javascript-application-plan.js +181 -0
- package/src/kv-provider.js +3 -0
- package/src/path-table.js +60 -0
- package/src/path.js +14 -0
- package/src/patterns/config-define.js +30 -0
- package/src/patterns/dependency-call.js +18 -0
- package/src/patterns/env-lookup.js +13 -0
- package/src/patterns/handler-reference.js +29 -0
- package/src/patterns/path-literal.js +35 -0
- package/src/patterns/result.js +15 -0
- package/src/patterns/router-chain-call.js +50 -0
- package/src/patterns/router-construction.js +19 -0
- package/src/project/package-reachability.js +782 -0
- package/src/project/reachable-graph-builder.js +992 -0
- package/src/project/reachable-graph-contract.js +54 -0
- package/src/project/reachable-graph-implementation.js +36 -0
- package/src/project/router-module-linker.js +710 -0
- package/src/project-config-compiler.js +222 -0
- package/src/project-target-support.js +500 -0
- package/src/provider-toolchain.js +299 -0
- package/src/spine/async-surface-normalizer.js +328 -0
- package/src/spine/canonical-handler-ir.js +336 -0
- package/src/spine/canonical-native-module.js +87 -0
- package/src/spine/canonical-native-plan.js +89 -0
- package/src/spine/canonical-project.js +76 -0
- package/src/spine/canonical-router.js +155 -0
- package/src/spine/canonical-source.js +165 -0
- package/src/spine/diagnostic-authority.js +290 -0
- package/src/spine/equivalence.js +262 -0
- package/src/spine/guest-unit-stage.js +87 -0
- package/src/spine/handler-ir-emitter.js +455 -0
- package/src/spine/handler-ir-managed.js +1598 -0
- package/src/spine/handler-ir.js +797 -0
- package/src/spine/handler-surface-authority.js +588 -0
- package/src/spine/package-operation-seam.js +1015 -0
- package/src/spine/pipeline.js +202 -0
- package/src/spine/plain-handler-frontend.js +545 -0
- package/src/spine/provider-requirement-authority.js +208 -0
- package/src/spine/router-control-contract.js +17 -0
- package/src/spine/router-handler-frontend.js +514 -0
- package/src/spine/router-handler-ir.js +372 -0
- package/src/spine/router-topology-frontend.js +638 -0
- package/src/stable-id.js +14 -0
|
@@ -0,0 +1,222 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const ts = require('typescript');
|
|
4
|
+
const {
|
|
5
|
+
createConfigScope,
|
|
6
|
+
normalizeProjectDeclaration,
|
|
7
|
+
selectProfilePlan
|
|
8
|
+
} = require('@pulse-compute/wasm-contracts/project/config-plan');
|
|
9
|
+
|
|
10
|
+
const PROJECT_CONFIG_COMPILER_VERSION = 'pulse.project-config-compiler.v1';
|
|
11
|
+
const CONFIG_PACKAGE = '@pulse-compute/pulse';
|
|
12
|
+
const UNSAFE_KEYS = new Set(['__proto__', 'prototype', 'constructor']);
|
|
13
|
+
|
|
14
|
+
class PulseProjectConfigCompileError extends Error {
|
|
15
|
+
constructor(code, message, detail = {}) {
|
|
16
|
+
super(message);
|
|
17
|
+
this.name = 'PulseProjectConfigCompileError';
|
|
18
|
+
this.code = code;
|
|
19
|
+
this.detail = Object.freeze({ ...detail });
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
function scriptKind(file) {
|
|
24
|
+
if (/\.tsx$/i.test(file)) return ts.ScriptKind.TSX;
|
|
25
|
+
if (/\.jsx$/i.test(file)) return ts.ScriptKind.JSX;
|
|
26
|
+
if (/\.js$/i.test(file) || /\.cjs$/i.test(file) || /\.mjs$/i.test(file)) return ts.ScriptKind.JS;
|
|
27
|
+
return ts.ScriptKind.TS;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
function location(sourceFile, node) {
|
|
31
|
+
const start = node.getStart(sourceFile);
|
|
32
|
+
const point = sourceFile.getLineAndCharacterOfPosition(start);
|
|
33
|
+
return Object.freeze({
|
|
34
|
+
file: sourceFile.fileName,
|
|
35
|
+
line: point.line + 1,
|
|
36
|
+
column: point.character + 1,
|
|
37
|
+
start,
|
|
38
|
+
end: node.end
|
|
39
|
+
});
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
function fail(sourceFile, node, code, message, detail = {}) {
|
|
43
|
+
throw new PulseProjectConfigCompileError(code, message, {
|
|
44
|
+
...detail,
|
|
45
|
+
source: location(sourceFile, node)
|
|
46
|
+
});
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
function unwrap(node) {
|
|
50
|
+
let current = node;
|
|
51
|
+
while (
|
|
52
|
+
ts.isParenthesizedExpression(current)
|
|
53
|
+
|| ts.isAsExpression(current)
|
|
54
|
+
|| ts.isTypeAssertionExpression(current)
|
|
55
|
+
|| ts.isSatisfiesExpression(current)
|
|
56
|
+
|| ts.isNonNullExpression(current)
|
|
57
|
+
) current = current.expression;
|
|
58
|
+
return current;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
function propertyName(sourceFile, node) {
|
|
62
|
+
if (ts.isIdentifier(node) || ts.isStringLiteralLike(node) || ts.isNumericLiteral(node)) return String(node.text);
|
|
63
|
+
fail(sourceFile, node, 'PULSE_CONFIG_PROPERTY_NAME_UNSUPPORTED', 'Pulse config property names must be static identifiers or literals.');
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
function factoryBodyExpression(sourceFile, factory) {
|
|
67
|
+
if (ts.isExpression(factory.body)) return unwrap(factory.body);
|
|
68
|
+
const statements = factory.body.statements.filter((entry) => !ts.isEmptyStatement(entry));
|
|
69
|
+
if (statements.length !== 1 || !ts.isReturnStatement(statements[0]) || !statements[0].expression) {
|
|
70
|
+
fail(sourceFile, factory.body, 'PULSE_CONFIG_FACTORY_BODY_UNSUPPORTED', 'Pulse config factory must be an expression body or contain exactly one return statement.');
|
|
71
|
+
}
|
|
72
|
+
return unwrap(statements[0].expression);
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
function evaluateExpression(sourceFile, node, context, path = 'config') {
|
|
76
|
+
const value = unwrap(node);
|
|
77
|
+
if (ts.isStringLiteralLike(value)) return value.text;
|
|
78
|
+
if (ts.isNumericLiteral(value)) return Number(value.text);
|
|
79
|
+
if (value.kind === ts.SyntaxKind.TrueKeyword) return true;
|
|
80
|
+
if (value.kind === ts.SyntaxKind.FalseKeyword) return false;
|
|
81
|
+
if (value.kind === ts.SyntaxKind.NullKeyword) return null;
|
|
82
|
+
if (ts.isPrefixUnaryExpression(value) && (value.operator === ts.SyntaxKind.MinusToken || value.operator === ts.SyntaxKind.PlusToken)) {
|
|
83
|
+
const operand = unwrap(value.operand);
|
|
84
|
+
if (!ts.isNumericLiteral(operand)) fail(sourceFile, value, 'PULSE_CONFIG_VALUE_UNSUPPORTED', `${path} supports unary +/- only for numeric literals.`);
|
|
85
|
+
const number = Number(operand.text);
|
|
86
|
+
return value.operator === ts.SyntaxKind.MinusToken ? -number : number;
|
|
87
|
+
}
|
|
88
|
+
if (ts.isArrayLiteralExpression(value)) {
|
|
89
|
+
return value.elements.map((entry, index) => {
|
|
90
|
+
if (ts.isSpreadElement(entry)) fail(sourceFile, entry, 'PULSE_CONFIG_SPREAD_UNSUPPORTED', 'Pulse config arrays do not support spread elements.');
|
|
91
|
+
return evaluateExpression(sourceFile, entry, context, `${path}[${index}]`);
|
|
92
|
+
});
|
|
93
|
+
}
|
|
94
|
+
if (ts.isObjectLiteralExpression(value)) {
|
|
95
|
+
const out = Object.create(null);
|
|
96
|
+
for (const member of value.properties) {
|
|
97
|
+
if (ts.isSpreadAssignment(member)) fail(sourceFile, member, 'PULSE_CONFIG_SPREAD_UNSUPPORTED', 'Pulse config objects do not support spread properties.');
|
|
98
|
+
if (!ts.isPropertyAssignment(member)) {
|
|
99
|
+
fail(sourceFile, member, 'PULSE_CONFIG_PROPERTY_UNSUPPORTED', 'Pulse config objects support only explicit property assignments.');
|
|
100
|
+
}
|
|
101
|
+
if (member.name && ts.isComputedPropertyName(member.name)) {
|
|
102
|
+
fail(sourceFile, member.name, 'PULSE_CONFIG_COMPUTED_KEY_UNSUPPORTED', 'Pulse config objects do not support computed property names.');
|
|
103
|
+
}
|
|
104
|
+
const key = propertyName(sourceFile, member.name);
|
|
105
|
+
if (UNSAFE_KEYS.has(key)) fail(sourceFile, member.name, 'PULSE_CONFIG_UNSAFE_KEY', `Pulse config property ${key} is not allowed.`, { key });
|
|
106
|
+
if (Object.prototype.hasOwnProperty.call(out, key)) fail(sourceFile, member.name, 'PULSE_CONFIG_DUPLICATE_KEY', `Pulse config property ${key} is duplicated.`, { key });
|
|
107
|
+
out[key] = evaluateExpression(sourceFile, member.initializer, context, `${path}.${key}`);
|
|
108
|
+
}
|
|
109
|
+
return out;
|
|
110
|
+
}
|
|
111
|
+
if (ts.isCallExpression(value)) {
|
|
112
|
+
const callee = unwrap(value.expression);
|
|
113
|
+
if (
|
|
114
|
+
ts.isPropertyAccessExpression(callee)
|
|
115
|
+
&& ts.isIdentifier(callee.expression)
|
|
116
|
+
&& callee.expression.text === context.scopeName
|
|
117
|
+
&& (callee.name.text === 'config' || callee.name.text === 'secret')
|
|
118
|
+
) {
|
|
119
|
+
if (value.arguments.length !== 1 || !ts.isStringLiteralLike(unwrap(value.arguments[0]))) {
|
|
120
|
+
fail(sourceFile, value, 'PULSE_CONFIG_SCOPE_LITERAL_REQUIRED', `scope.${callee.name.text} requires one string literal name.`);
|
|
121
|
+
}
|
|
122
|
+
const name = unwrap(value.arguments[0]).text;
|
|
123
|
+
return context.scope[callee.name.text](name);
|
|
124
|
+
}
|
|
125
|
+
fail(sourceFile, value, 'PULSE_CONFIG_CALL_UNSUPPORTED', 'Pulse config factories allow calls only to direct scope.config() and scope.secret() members.');
|
|
126
|
+
}
|
|
127
|
+
if (ts.isIdentifier(value) && value.text === 'undefined') {
|
|
128
|
+
fail(sourceFile, value, 'PULSE_CONFIG_UNDEFINED_UNSUPPORTED', `${path} cannot contain undefined.`);
|
|
129
|
+
}
|
|
130
|
+
fail(sourceFile, value, 'PULSE_CONFIG_VALUE_UNSUPPORTED', `${path} contains unsupported executable syntax.`, {
|
|
131
|
+
kind: ts.SyntaxKind[value.kind],
|
|
132
|
+
text: value.getText(sourceFile)
|
|
133
|
+
});
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
function findConfigFactory(sourceFile) {
|
|
137
|
+
let defineImport = null;
|
|
138
|
+
let exportExpression = null;
|
|
139
|
+
for (const statement of sourceFile.statements) {
|
|
140
|
+
if (ts.isImportDeclaration(statement)) {
|
|
141
|
+
if (!ts.isStringLiteralLike(statement.moduleSpecifier) || statement.moduleSpecifier.text !== CONFIG_PACKAGE) {
|
|
142
|
+
fail(sourceFile, statement, 'PULSE_CONFIG_IMPORT_UNSUPPORTED', `Conventional Pulse config may import only defineConfig from ${CONFIG_PACKAGE}.`);
|
|
143
|
+
}
|
|
144
|
+
const clause = statement.importClause;
|
|
145
|
+
if (!clause || clause.isTypeOnly || clause.name || !clause.namedBindings || !ts.isNamedImports(clause.namedBindings)) {
|
|
146
|
+
fail(sourceFile, statement, 'PULSE_CONFIG_IMPORT_SHAPE_UNSUPPORTED', `Import defineConfig as a direct named import from ${CONFIG_PACKAGE}.`);
|
|
147
|
+
}
|
|
148
|
+
if (defineImport) fail(sourceFile, statement, 'PULSE_CONFIG_IMPORT_DUPLICATE', 'Pulse config may contain only one import declaration.');
|
|
149
|
+
const elements = clause.namedBindings.elements;
|
|
150
|
+
if (elements.length !== 1 || elements[0].propertyName || elements[0].name.text !== 'defineConfig') {
|
|
151
|
+
fail(sourceFile, statement, 'PULSE_CONFIG_IMPORT_SHAPE_UNSUPPORTED', `Import only the unaliased defineConfig symbol from ${CONFIG_PACKAGE}.`);
|
|
152
|
+
}
|
|
153
|
+
defineImport = elements[0].name.text;
|
|
154
|
+
continue;
|
|
155
|
+
}
|
|
156
|
+
if (ts.isExportAssignment(statement) && !statement.isExportEquals) {
|
|
157
|
+
if (exportExpression) fail(sourceFile, statement, 'PULSE_CONFIG_EXPORT_DUPLICATE', 'Pulse config must contain one default export.');
|
|
158
|
+
exportExpression = statement.expression;
|
|
159
|
+
continue;
|
|
160
|
+
}
|
|
161
|
+
if (ts.isEmptyStatement(statement)) continue;
|
|
162
|
+
fail(sourceFile, statement, 'PULSE_CONFIG_TOP_LEVEL_UNSUPPORTED', 'Conventional Pulse config permits only its defineConfig import and one default export.');
|
|
163
|
+
}
|
|
164
|
+
if (!defineImport) fail(sourceFile, sourceFile, 'PULSE_CONFIG_DEFINE_IMPORT_REQUIRED', `Pulse config must import defineConfig from ${CONFIG_PACKAGE}.`);
|
|
165
|
+
if (!exportExpression) fail(sourceFile, sourceFile, 'PULSE_CONFIG_DEFAULT_EXPORT_REQUIRED', 'Pulse config must default-export defineConfig((scope) => ({ ... })).');
|
|
166
|
+
const call = unwrap(exportExpression);
|
|
167
|
+
if (!ts.isCallExpression(call) || !ts.isIdentifier(unwrap(call.expression)) || unwrap(call.expression).text !== defineImport || call.arguments.length !== 1) {
|
|
168
|
+
fail(sourceFile, exportExpression, 'PULSE_CONFIG_FACTORY_REQUIRED', 'Pulse config must default-export one direct defineConfig(factory) call.');
|
|
169
|
+
}
|
|
170
|
+
const factory = unwrap(call.arguments[0]);
|
|
171
|
+
if (!ts.isArrowFunction(factory) && !ts.isFunctionExpression(factory)) {
|
|
172
|
+
fail(sourceFile, factory, 'PULSE_CONFIG_FACTORY_REQUIRED', 'defineConfig requires one inline configuration factory.');
|
|
173
|
+
}
|
|
174
|
+
if (factory.modifiers && factory.modifiers.some((entry) => entry.kind === ts.SyntaxKind.AsyncKeyword)) {
|
|
175
|
+
fail(sourceFile, factory, 'PULSE_CONFIG_FACTORY_ASYNC_UNSUPPORTED', 'Pulse config factories must be synchronous.');
|
|
176
|
+
}
|
|
177
|
+
if (factory.asteriskToken) fail(sourceFile, factory, 'PULSE_CONFIG_FACTORY_GENERATOR_UNSUPPORTED', 'Pulse config factories cannot be generators.');
|
|
178
|
+
if (factory.parameters.length !== 1 || !ts.isIdentifier(factory.parameters[0].name)) {
|
|
179
|
+
fail(sourceFile, factory, 'PULSE_CONFIG_SCOPE_PARAMETER_REQUIRED', 'Pulse config factory requires exactly one identifier parameter for its symbolic scope.');
|
|
180
|
+
}
|
|
181
|
+
return { factory, scopeName: factory.parameters[0].name.text };
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
function compileProjectConfigSource(source, options = {}) {
|
|
185
|
+
const file = String(options.file || '.pulse/config.ts');
|
|
186
|
+
const sourceFile = ts.createSourceFile(file, String(source), ts.ScriptTarget.ES2022, true, scriptKind(file));
|
|
187
|
+
const parseErrors = sourceFile.parseDiagnostics || [];
|
|
188
|
+
if (parseErrors.length > 0) {
|
|
189
|
+
const first = parseErrors[0];
|
|
190
|
+
const node = first.start == null ? sourceFile : sourceFile.getChildAt(first.start, sourceFile);
|
|
191
|
+
fail(sourceFile, node || sourceFile, 'PULSE_CONFIG_PARSE_FAILED', ts.flattenDiagnosticMessageText(first.messageText, '\n'), { typescriptCode: first.code });
|
|
192
|
+
}
|
|
193
|
+
const found = findConfigFactory(sourceFile);
|
|
194
|
+
const raw = evaluateExpression(sourceFile, factoryBodyExpression(sourceFile, found.factory), {
|
|
195
|
+
scopeName: found.scopeName,
|
|
196
|
+
scope: createConfigScope()
|
|
197
|
+
});
|
|
198
|
+
const declaration = normalizeProjectDeclaration(raw, { source: options.source || file });
|
|
199
|
+
const result = {
|
|
200
|
+
version: PROJECT_CONFIG_COMPILER_VERSION,
|
|
201
|
+
file,
|
|
202
|
+
declaration
|
|
203
|
+
};
|
|
204
|
+
const selection = options.selection || ((options.cliProfile !== undefined || options.environmentProfile !== undefined || options.profile !== undefined)
|
|
205
|
+
? { cliProfile: options.cliProfile, environmentProfile: options.environmentProfile, name: options.profile, source: options.profileSource }
|
|
206
|
+
: null);
|
|
207
|
+
if (selection) result.plan = selectProfilePlan(declaration, selection);
|
|
208
|
+
return Object.freeze(result);
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
function compileProjectConfigFile(file, options = {}) {
|
|
212
|
+
const fs = require('node:fs');
|
|
213
|
+
return compileProjectConfigSource(fs.readFileSync(file, 'utf8'), { ...options, file });
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
module.exports = Object.freeze({
|
|
217
|
+
PROJECT_CONFIG_COMPILER_VERSION,
|
|
218
|
+
CONFIG_PACKAGE,
|
|
219
|
+
PulseProjectConfigCompileError,
|
|
220
|
+
compileProjectConfigSource,
|
|
221
|
+
compileProjectConfigFile
|
|
222
|
+
});
|