@pulse-compute/wasm-compiler 1.0.0-beta.1 → 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 +4 -3
- package/package.json +11 -11
- package/src/canonical-api-compiler.js +28 -4
- package/src/canonical-native-plan.js +3 -2
- package/src/canonical-project-compiler.js +11 -5
- package/src/project/router-module-linker.js +2 -2
- package/src/spine/async-surface-normalizer.js +16 -0
- package/src/spine/canonical-handler-ir.js +1 -0
- package/src/spine/handler-ir-emitter.js +3 -2
- package/src/spine/handler-ir-managed.js +1 -0
- package/src/spine/handler-surface-authority.js +6 -3
- package/src/spine/plain-handler-frontend.js +8 -0
- package/src/spine/router-handler-frontend.js +1 -0
- package/src/spine/router-topology-frontend.js +4 -1
package/README.md
CHANGED
|
@@ -6,10 +6,11 @@
|
|
|
6
6
|
> **Install directly:** No for application projects; use the pulse CLI.<br>
|
|
7
7
|
> **Supported entry points:** `None for application authors.`<br>
|
|
8
8
|
> **Stability:** Internal compiler interface; no application-author compatibility guarantee.<br>
|
|
9
|
+
> **npm:** [`@pulse-compute/wasm-compiler`](https://www.npmjs.com/package/@pulse-compute/wasm-compiler)<br>
|
|
9
10
|
> **Canonical replacement:** `@pulse-compute/cli`<br>
|
|
10
|
-
> **Canonical documentation:** [Package guide](https://pulsecompute.io/v1.0.0-beta.
|
|
11
|
+
> **Canonical documentation:** [Package guide](https://pulsecompute.io/v1.0.0-beta.2/packages/implementation-packages/)
|
|
11
12
|
>
|
|
12
|
-
> This release-status block is generated from the synchronized `Pulse 1.0.0-beta.
|
|
13
|
+
> This release-status block is generated from the synchronized `Pulse 1.0.0-beta.2` package policy.
|
|
13
14
|
<!-- pulse-package-status:end -->
|
|
14
15
|
|
|
15
16
|
Whole-project compiler implementation used by the `pulse` workflow. Application projects should use `@pulse-compute/cli`, not import this package directly.
|
|
@@ -51,4 +52,4 @@ The package exports its root implementation plus focused compiler, CLI, extracto
|
|
|
51
52
|
|
|
52
53
|
Compiler changes should be covered by focused static/lowering tests, canonical project inspection, provider-plan parity, packed-package discovery where relevant, and the release documentation gates.
|
|
53
54
|
|
|
54
|
-
See the installed [implementation package guide](https://pulsecompute.io/v1.0.0-beta.
|
|
55
|
+
See the installed [implementation package guide](https://pulsecompute.io/v1.0.0-beta.2/packages/implementation-packages/) and [compilation concepts](https://pulsecompute.io/v1.0.0-beta.2/concepts/compilation-and-lowering/).
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@pulse-compute/wasm-compiler",
|
|
3
|
-
"version": "1.0.0-beta.
|
|
3
|
+
"version": "1.0.0-beta.2",
|
|
4
4
|
"license": "Apache-2.0",
|
|
5
5
|
"description": "PulseWasm compiler package inside the Pulse monorepo.",
|
|
6
6
|
"type": "commonjs",
|
|
@@ -9,15 +9,15 @@
|
|
|
9
9
|
"pulsewasm": "./bin/pulsewasm-extract.js"
|
|
10
10
|
},
|
|
11
11
|
"dependencies": {
|
|
12
|
-
"@pulse-compute/provider-fastly": "1.0.0-beta.
|
|
13
|
-
"@pulse-compute/provider-node": "1.0.0-beta.
|
|
14
|
-
"@pulse-compute/wasm-build-support": "1.0.0-beta.
|
|
15
|
-
"@pulse-compute/wasm-contracts": "1.0.0-beta.
|
|
16
|
-
"@pulse-compute/wasm-guest-link": "1.0.0-beta.
|
|
17
|
-
"@pulse-compute/wasm-host-runtime": "1.0.0-beta.
|
|
18
|
-
"@pulse-compute/wasm-library-kit": "1.0.0-beta.
|
|
19
|
-
"@pulse-compute/wasm-runtime-core-as": "1.0.0-beta.
|
|
20
|
-
"@pulse-compute/wasm-schema-json": "1.0.0-beta.
|
|
12
|
+
"@pulse-compute/provider-fastly": "1.0.0-beta.2",
|
|
13
|
+
"@pulse-compute/provider-node": "1.0.0-beta.2",
|
|
14
|
+
"@pulse-compute/wasm-build-support": "1.0.0-beta.2",
|
|
15
|
+
"@pulse-compute/wasm-contracts": "1.0.0-beta.2",
|
|
16
|
+
"@pulse-compute/wasm-guest-link": "1.0.0-beta.2",
|
|
17
|
+
"@pulse-compute/wasm-host-runtime": "1.0.0-beta.2",
|
|
18
|
+
"@pulse-compute/wasm-library-kit": "1.0.0-beta.2",
|
|
19
|
+
"@pulse-compute/wasm-runtime-core-as": "1.0.0-beta.2",
|
|
20
|
+
"@pulse-compute/wasm-schema-json": "1.0.0-beta.2",
|
|
21
21
|
"assemblyscript": "0.28.18",
|
|
22
22
|
"json-as": "1.5.0",
|
|
23
23
|
"typescript": "5.9.3"
|
|
@@ -58,7 +58,7 @@
|
|
|
58
58
|
"url": "git+https://github.com/pulse-compute/pulse.git",
|
|
59
59
|
"directory": "wasm/packages/compiler"
|
|
60
60
|
},
|
|
61
|
-
"homepage": "https://pulsecompute.io/v1.0.0-beta.
|
|
61
|
+
"homepage": "https://pulsecompute.io/v1.0.0-beta.2/packages/implementation-packages/",
|
|
62
62
|
"bugs": {
|
|
63
63
|
"url": "https://github.com/pulse-compute/pulse/issues"
|
|
64
64
|
},
|
|
@@ -52,9 +52,8 @@ function stableSourceName(file, options = {}) {
|
|
|
52
52
|
return relative && !relative.startsWith('../') ? relative : path.basename(absolute);
|
|
53
53
|
}
|
|
54
54
|
|
|
55
|
-
function emitCanonicalProgramFromHandlerIr(ir) {
|
|
55
|
+
function emitCanonicalProgramFromHandlerIr(ir, options = {}) {
|
|
56
56
|
const payload = payloadForCanonicalHandlerIr(ir);
|
|
57
|
-
const emitted = emitCanonicalHandlerGenerator(payload.operationIr);
|
|
58
57
|
const sourceFile = payload.sourceFile;
|
|
59
58
|
const schemaBundle = payload.schemaBundle;
|
|
60
59
|
const explicitParallelCount = ir.continuationSites.filter((site) => site.kind === 'parallel-group').length;
|
|
@@ -100,9 +99,23 @@ function emitCanonicalProgramFromHandlerIr(ir) {
|
|
|
100
99
|
compilerPreludeHash: ir.compilerPreludeHash,
|
|
101
100
|
userAuthoredAsync: ir.invariants.userAuthoredAsync,
|
|
102
101
|
promiseSemantics: ir.invariants.promiseSemantics,
|
|
103
|
-
asyncify: ir.invariants.asyncify
|
|
102
|
+
asyncify: ir.invariants.asyncify,
|
|
103
|
+
...(options.target === 'javascript' ? { target: 'javascript', promiseSemantics: true } : {})
|
|
104
|
+
});
|
|
105
|
+
|
|
106
|
+
// JavaScript executes the original module graph through its provider. The
|
|
107
|
+
// normalized IR describes recognized Pulse behavior only; erased awaits and
|
|
108
|
+
// source-runtime imports must never become an executable generator.
|
|
109
|
+
if (options.target === 'javascript') return Object.freeze({
|
|
110
|
+
ok: true,
|
|
111
|
+
version: CANONICAL_API_COMPILER_VERSION,
|
|
112
|
+
target: 'javascript',
|
|
113
|
+
metadata,
|
|
114
|
+
schemaBundle,
|
|
115
|
+
diagnostics: Object.freeze([])
|
|
104
116
|
});
|
|
105
117
|
|
|
118
|
+
const emitted = emitCanonicalHandlerGenerator(payload.operationIr);
|
|
106
119
|
const printer = ts.createPrinter({ newLine: ts.NewLineKind.LineFeed });
|
|
107
120
|
const generatorText = printer.printNode(ts.EmitHint.Unspecified, emitted.generator, sourceFile);
|
|
108
121
|
const metadataSource = JSON.stringify(metadata, null, 2);
|
|
@@ -171,8 +184,16 @@ const PLAIN_HANDLER_IMPLEMENTATION = Object.freeze({
|
|
|
171
184
|
emitCanonicalProgram: emitCanonicalProgramFromHandlerIr
|
|
172
185
|
});
|
|
173
186
|
|
|
187
|
+
const JAVASCRIPT_HANDLER_INSPECTION = Object.freeze({
|
|
188
|
+
...PLAIN_HANDLER_IMPLEMENTATION,
|
|
189
|
+
emitCanonicalProgram: (ir) => emitCanonicalProgramFromHandlerIr(ir, { target: 'javascript' })
|
|
190
|
+
});
|
|
191
|
+
|
|
174
192
|
function compileCanonicalSource(sourceText, options = {}) {
|
|
175
|
-
|
|
193
|
+
if (options.target !== undefined && !['native', 'javascript'].includes(options.target)) throw new TypeError('target must be native or javascript.');
|
|
194
|
+
return executeCanonicalSourceSpine(sourceText, options, options.target === 'javascript'
|
|
195
|
+
? JAVASCRIPT_HANDLER_INSPECTION
|
|
196
|
+
: PLAIN_HANDLER_IMPLEMENTATION);
|
|
176
197
|
}
|
|
177
198
|
|
|
178
199
|
function compileCanonicalFile(file, options = {}) {
|
|
@@ -191,6 +212,9 @@ function loadCanonicalModule(compiled, options = {}) {
|
|
|
191
212
|
}
|
|
192
213
|
|
|
193
214
|
function writeCanonicalBuild(compiled, outDir, options = {}) {
|
|
215
|
+
if (!compiled || compiled.ok !== true || typeof compiled.generatedSource !== 'string') {
|
|
216
|
+
throw new TypeError('writeCanonicalBuild requires an executable canonical compilation; JavaScript projects use provider source packaging.');
|
|
217
|
+
}
|
|
194
218
|
const target = path.resolve(outDir);
|
|
195
219
|
fs.mkdirSync(target, { recursive: true });
|
|
196
220
|
const handlerFile = path.join(target, options.handlerFile || 'canonical-handler.cjs');
|
|
@@ -222,6 +222,7 @@ function resultKindForEffect(site, decoder, continuation, resultMode) {
|
|
|
222
222
|
if (site.kind === 'config.get' || site.kind === 'secret.get') return 'string-or-undefined';
|
|
223
223
|
if (site.kind === 'kv.get') return 'json-or-undefined';
|
|
224
224
|
if (site.kind === 'kv.put') return 'ack';
|
|
225
|
+
if (['kv.getVersioned', 'kv.insertIfAbsent', 'kv.compareAndSwap'].includes(site.kind)) return 'json';
|
|
225
226
|
if (site.kind === 'event.emit') return 'ack';
|
|
226
227
|
return 'unknown';
|
|
227
228
|
}
|
|
@@ -1309,10 +1310,10 @@ function assertCanonicalNativePlan(plan) {
|
|
|
1309
1310
|
fail('plan crypto realization evidence is invalid', { crypto: plan.crypto });
|
|
1310
1311
|
} else {
|
|
1311
1312
|
const knownRealizations = new Map(
|
|
1312
|
-
cryptoContract.CRYPTO_REALIZATIONS.map((entry) => [entry.id
|
|
1313
|
+
cryptoContract.CRYPTO_REALIZATIONS.map((entry) => [`${entry.id}:${entry.algorithm}`, entry])
|
|
1313
1314
|
);
|
|
1314
1315
|
for (const entry of plan.crypto.algorithms) {
|
|
1315
|
-
const known = entry && knownRealizations.get(entry.realization);
|
|
1316
|
+
const known = entry && knownRealizations.get(`${entry.realization}:${entry.algorithm}`);
|
|
1316
1317
|
if (
|
|
1317
1318
|
!known
|
|
1318
1319
|
|| known.algorithm !== entry.algorithm
|
|
@@ -304,7 +304,7 @@ function planCanonicalProjectCrypto(options, entryFile, recognizedRequirements =
|
|
|
304
304
|
declaration: metadata.crypto && metadata.crypto.declaration,
|
|
305
305
|
packageRequirements,
|
|
306
306
|
targetDescriptor: options.packageTargetDescriptor,
|
|
307
|
-
target: options.packageTarget || metadata.target || null,
|
|
307
|
+
target: options.target || options.packageTarget || metadata.target || null,
|
|
308
308
|
profile,
|
|
309
309
|
profileSelectionSource: selected && typeof selected === 'object'
|
|
310
310
|
? selected.source
|
|
@@ -324,7 +324,7 @@ function planCanonicalProjectCrypto(options, entryFile, recognizedRequirements =
|
|
|
324
324
|
}
|
|
325
325
|
|
|
326
326
|
function assertGraphPreflight(graphBuild, entryFile, options = {}) {
|
|
327
|
-
const nativeEligibilityMode = options.nativeEligibilityMode || 'enforce';
|
|
327
|
+
const nativeEligibilityMode = options.nativeEligibilityMode || (options.target === 'javascript' ? 'record' : 'enforce');
|
|
328
328
|
if (!['enforce', 'record'].includes(nativeEligibilityMode)) {
|
|
329
329
|
throw new TypeError('nativeEligibilityMode must be enforce or record.');
|
|
330
330
|
}
|
|
@@ -957,8 +957,10 @@ function attachPackageSchemaReferences(compiled, recognition) {
|
|
|
957
957
|
return Object.freeze({
|
|
958
958
|
...compiled,
|
|
959
959
|
metadata,
|
|
960
|
-
|
|
961
|
-
|
|
960
|
+
...(compiled.target !== 'javascript' ? {
|
|
961
|
+
generatedSource: replaceGeneratedMetadata(compiled.generatedSource, metadata, 'commonjs'),
|
|
962
|
+
generatedEsmSource: replaceGeneratedMetadata(compiled.generatedEsmSource, metadata, 'esm')
|
|
963
|
+
} : {})
|
|
962
964
|
});
|
|
963
965
|
}
|
|
964
966
|
|
|
@@ -1046,9 +1048,10 @@ function compileCanonicalProjectLegacy(entryFile, options = {}) {
|
|
|
1046
1048
|
if (multiModule) {
|
|
1047
1049
|
try {
|
|
1048
1050
|
linkedProjectModules = root.kind === 'router'
|
|
1049
|
-
? linkProjectRouterModules(graphBuild, { rootDir })
|
|
1051
|
+
? linkProjectRouterModules(graphBuild, { rootDir, target: options.target })
|
|
1050
1052
|
: linkProjectPlainHandler(graphBuild, {
|
|
1051
1053
|
rootDir,
|
|
1054
|
+
target: options.target,
|
|
1052
1055
|
consumedRuntimeImports: managedHandlerRuntimeImportKeys(packageOperationRecognition.managedHandlers)
|
|
1053
1056
|
});
|
|
1054
1057
|
} catch (error) {
|
|
@@ -1199,6 +1202,9 @@ function compileCanonicalProjectLegacy(entryFile, options = {}) {
|
|
|
1199
1202
|
}
|
|
1200
1203
|
|
|
1201
1204
|
function compileCanonicalProject(entryFile, options = {}) {
|
|
1205
|
+
if (options.target !== undefined && !['native', 'javascript'].includes(options.target)) {
|
|
1206
|
+
throw new TypeError('target must be native or javascript.');
|
|
1207
|
+
}
|
|
1202
1208
|
return executeCanonicalProjectSpine(entryFile, options, compileCanonicalProjectLegacy);
|
|
1203
1209
|
}
|
|
1204
1210
|
|
|
@@ -563,7 +563,7 @@ function linkProjectRouterModules(graphBuild, options = {}) {
|
|
|
563
563
|
|
|
564
564
|
const rootGlobalName = routerSymbols.get(`${root.module.path}:${root.localName}`);
|
|
565
565
|
const ordered = orderLinkedRouters(routers, rootGlobalName);
|
|
566
|
-
validateRuntimeProjectImports(context, consumedImports, diagnostics);
|
|
566
|
+
if (options.target !== 'javascript') validateRuntimeProjectImports(context, consumedImports, diagnostics);
|
|
567
567
|
const combinedIr = Object.freeze({
|
|
568
568
|
source: entryModule.path,
|
|
569
569
|
routerIR: Object.freeze(ordered.routers),
|
|
@@ -652,7 +652,7 @@ function linkProjectPlainHandler(graphBuild, options = {}) {
|
|
|
652
652
|
{ resolvedKind: root && root.kind || 'unknown' }
|
|
653
653
|
));
|
|
654
654
|
}
|
|
655
|
-
validateRuntimeProjectImports(context, consumedImports, diagnostics);
|
|
655
|
+
if (options.target !== 'javascript') validateRuntimeProjectImports(context, consumedImports, diagnostics);
|
|
656
656
|
if (diagnostics.some((entry) => entry.severity !== 'warning')) {
|
|
657
657
|
throw new RouterModuleLinkError(`Project plain-handler linking failed with ${diagnostics.length} diagnostic(s).`, diagnostics, { entry: entryModule.path });
|
|
658
658
|
}
|
|
@@ -6,6 +6,7 @@ const {
|
|
|
6
6
|
} = require('@pulse-compute/wasm-contracts/handler/surface-contract');
|
|
7
7
|
const {
|
|
8
8
|
recognizeHandlerSurface,
|
|
9
|
+
extractKvNamespaceDeclaration,
|
|
9
10
|
unwrapExpression
|
|
10
11
|
} = require('./handler-surface-authority.js');
|
|
11
12
|
const {
|
|
@@ -92,6 +93,7 @@ function normalizeManagedHandler(functionNode, options = {}) {
|
|
|
92
93
|
const diagnostics = [];
|
|
93
94
|
const warnings = [];
|
|
94
95
|
const changes = [];
|
|
96
|
+
let kvAliases = new Map();
|
|
95
97
|
const awaitedRoots = new WeakSet();
|
|
96
98
|
const parallelMemberRoots = new WeakSet();
|
|
97
99
|
const userAuthoredAsync = (functionNode.modifiers || []).some((modifier) => modifier.kind === ts.SyntaxKind.AsyncKeyword);
|
|
@@ -115,6 +117,7 @@ function normalizeManagedHandler(functionNode, options = {}) {
|
|
|
115
117
|
function surfaceFor(node, position) {
|
|
116
118
|
return recognizeHandlerSurface(node, {
|
|
117
119
|
ctxName,
|
|
120
|
+
kvAliases,
|
|
118
121
|
nextName,
|
|
119
122
|
role: options.role,
|
|
120
123
|
strict,
|
|
@@ -126,6 +129,15 @@ function normalizeManagedHandler(functionNode, options = {}) {
|
|
|
126
129
|
|
|
127
130
|
const transformer = (context) => {
|
|
128
131
|
function visit(node) {
|
|
132
|
+
if (ts.isBlock(node)) {
|
|
133
|
+
const inherited = kvAliases; kvAliases = new Map(inherited);
|
|
134
|
+
try { return ts.visitEachChild(node, visit, context); } finally { kvAliases = inherited; }
|
|
135
|
+
}
|
|
136
|
+
if (ts.isVariableStatement(node)) {
|
|
137
|
+
const namespace = extractKvNamespaceDeclaration(node, ctxName, { unwrap: true });
|
|
138
|
+
for (const declaration of node.declarationList.declarations) if (ts.isIdentifier(declaration.name)) kvAliases.delete(declaration.name.text);
|
|
139
|
+
if (namespace) kvAliases.set(namespace.variableName, namespace.store);
|
|
140
|
+
}
|
|
129
141
|
if (node !== functionNode && ts.isFunctionLike(node)) {
|
|
130
142
|
const nestedAsync = (node.modifiers || []).some((modifier) => modifier.kind === ts.SyntaxKind.AsyncKeyword);
|
|
131
143
|
if (nestedAsync) diagnostics.push(createHandlerDiagnostic({
|
|
@@ -142,6 +154,10 @@ function normalizeManagedHandler(functionNode, options = {}) {
|
|
|
142
154
|
const inner = unwrapExpression(node.expression);
|
|
143
155
|
const surface = surfaceFor(inner, 'await-expression');
|
|
144
156
|
if (!surface || surface.surfaceId === 'javascript.await' || surface.class === 'javascript-only') {
|
|
157
|
+
// The explicit JavaScript project path uses this normalized tree only
|
|
158
|
+
// for inspection. Its original async source executes through the
|
|
159
|
+
// application loader; Native compilation still rejects this boundary.
|
|
160
|
+
if (options.target === 'javascript') return ts.visitNode(node.expression, visit);
|
|
145
161
|
diagnostics.push(createHandlerDiagnostic({
|
|
146
162
|
frontend,
|
|
147
163
|
issue: 'handler.await.native-unsupported',
|
|
@@ -61,10 +61,11 @@ function providerEffectExpression(factory, sourceFile, site, providerOperation)
|
|
|
61
61
|
if (site.groupKey !== undefined) properties.push(literalProperty(factory, 'groupKey', stringLiteral(factory, site.groupKey)));
|
|
62
62
|
if (providerOperation.kind === 'config.get' || providerOperation.kind === 'secret.get') {
|
|
63
63
|
properties.push(literalProperty(factory, 'name', providerOperation.name));
|
|
64
|
-
} else if (providerOperation.
|
|
64
|
+
} else if (providerOperation.providerKind === 'kv') {
|
|
65
65
|
properties.push(literalProperty(factory, 'store', providerOperation.store));
|
|
66
66
|
properties.push(literalProperty(factory, 'key', providerOperation.key));
|
|
67
|
-
if (providerOperation.
|
|
67
|
+
if (providerOperation.generation) properties.push(literalProperty(factory, 'generation', providerOperation.generation));
|
|
68
|
+
if (providerOperation.value) properties.push(literalProperty(factory, 'value', providerOperation.value));
|
|
68
69
|
} else if (providerOperation.kind === 'event.emit') {
|
|
69
70
|
properties.push(literalProperty(factory, 'type', providerOperation.type));
|
|
70
71
|
properties.push(literalProperty(factory, 'emission', providerOperation.emission));
|
|
@@ -979,6 +979,7 @@ function compileHandler(resolved, graphBuild, allResolved, diagnostics, packageR
|
|
|
979
979
|
} else if (provider.providerKind === 'kv') {
|
|
980
980
|
add('store', provider.store || provider.resource);
|
|
981
981
|
add('key', provider.key);
|
|
982
|
+
add('generation', provider.generation);
|
|
982
983
|
add('value', provider.value);
|
|
983
984
|
} else if (provider.providerKind === 'event') {
|
|
984
985
|
add('type', provider.type);
|
|
@@ -182,7 +182,7 @@ function extractProviderCall(expression, ctxName, kvAliases = new Map(), options
|
|
|
182
182
|
}
|
|
183
183
|
}
|
|
184
184
|
|
|
185
|
-
if (['get', 'put'].includes(method)) {
|
|
185
|
+
if (['get', 'put', 'getVersioned', 'insertIfAbsent', 'compareAndSwap'].includes(method)) {
|
|
186
186
|
let store;
|
|
187
187
|
if (receiver && ts.isCallExpression(receiver) && isPropertyAccessNamed(receiver.expression, ctxName, 'kv', options) && receiver.arguments.length === 1) {
|
|
188
188
|
store = receiver.arguments[0];
|
|
@@ -190,7 +190,9 @@ function extractProviderCall(expression, ctxName, kvAliases = new Map(), options
|
|
|
190
190
|
store = kvAliases.get(receiver.text);
|
|
191
191
|
}
|
|
192
192
|
if (store) {
|
|
193
|
-
|
|
193
|
+
if (['getVersioned', 'insertIfAbsent', 'compareAndSwap'].includes(method)
|
|
194
|
+
&& !ts.isStringLiteral(store) && !ts.isNoSubstitutionTemplateLiteral(store)) return undefined;
|
|
195
|
+
const expected = method === 'compareAndSwap' ? 3 : ['get', 'getVersioned'].includes(method) ? 1 : 2;
|
|
194
196
|
if (current.arguments.length === expected) {
|
|
195
197
|
return Object.freeze({
|
|
196
198
|
call: current,
|
|
@@ -202,7 +204,8 @@ function extractProviderCall(expression, ctxName, kvAliases = new Map(), options
|
|
|
202
204
|
resource: store,
|
|
203
205
|
store,
|
|
204
206
|
key: current.arguments[0],
|
|
205
|
-
value: current.arguments[1],
|
|
207
|
+
value: current.arguments[method === 'compareAndSwap' ? 2 : 1],
|
|
208
|
+
generation: method === 'compareAndSwap' ? current.arguments[1] : undefined,
|
|
206
209
|
args: Object.freeze([...current.arguments])
|
|
207
210
|
});
|
|
208
211
|
}
|
|
@@ -375,6 +375,13 @@ function analyzeHandler(sourceFile, handler, ctxName, diagnostics, schemaBundleI
|
|
|
375
375
|
|
|
376
376
|
function findCanonicalHandler(sourceFile, diagnostics, options = {}) {
|
|
377
377
|
const allowedRuntimeImports = new Set([...ALLOWED_IMPORTS, ...(options.allowedRuntimeImports || []).map(String)]);
|
|
378
|
+
if (options.target === 'javascript') {
|
|
379
|
+
// The project graph owns import resolution and containment. These remain
|
|
380
|
+
// source-runtime imports, never lowerer grants.
|
|
381
|
+
for (const statement of sourceFile.statements) {
|
|
382
|
+
if (ts.isImportDeclaration(statement) && ts.isStringLiteral(statement.moduleSpecifier)) allowedRuntimeImports.add(statement.moduleSpecifier.text);
|
|
383
|
+
}
|
|
384
|
+
}
|
|
378
385
|
for (const statement of sourceFile.statements) {
|
|
379
386
|
if (!ts.isImportDeclaration(statement)) continue;
|
|
380
387
|
const moduleName = statement.moduleSpecifier && ts.isStringLiteral(statement.moduleSpecifier) ? statement.moduleSpecifier.text : '';
|
|
@@ -486,6 +493,7 @@ function preparePlainHandlerSource(sourceText, options = {}, recognition) {
|
|
|
486
493
|
role: 'handler',
|
|
487
494
|
strict: options.strict === true,
|
|
488
495
|
frontend: 'canonical-source',
|
|
496
|
+
target: options.target,
|
|
489
497
|
handlerAuthoring: options.handlerAuthoring,
|
|
490
498
|
requireAsync: options.requireAsync === true,
|
|
491
499
|
requireEffectAwait: options.requireEffectAwait === true,
|
|
@@ -193,6 +193,7 @@ function normalizeRouterHandler(topology, descriptor, recognition, classificatio
|
|
|
193
193
|
role,
|
|
194
194
|
strict: Boolean(topology.options && topology.options.strict === true),
|
|
195
195
|
frontend: 'canonical-router',
|
|
196
|
+
target: topology.options && topology.options.target,
|
|
196
197
|
handlerAuthoring: topology.options && topology.options.handlerAuthoring,
|
|
197
198
|
requireAsync: topology.options && topology.options.requireAsync === true,
|
|
198
199
|
requireEffectAwait: topology.options && topology.options.requireEffectAwait === true,
|
|
@@ -19,6 +19,7 @@ const { buildDispatchTable } = require('../dispatch-table.js');
|
|
|
19
19
|
const { buildExecutionPlan } = require('../execution-plan.js');
|
|
20
20
|
const { buildEventTopology } = require('../events/event-topology.js');
|
|
21
21
|
const { analyzeEventEmitHandlers } = require('../events/event-emit.js');
|
|
22
|
+
const { ROUTER_API_DEFINITIONS } = require('../definitions/router-api.js');
|
|
22
23
|
|
|
23
24
|
const ROUTER_TOPOLOGY_FRONTEND_VERSION = 'pulse.router-topology-frontend.v1';
|
|
24
25
|
const CANONICAL_ROUTER_COMPILER_VERSION = 'pulse.canonical-router-compiler.v2';
|
|
@@ -28,7 +29,9 @@ const ROUTER_IMPORT = '@pulse-compute/runtime';
|
|
|
28
29
|
const ROUTER_CLASS = 'Router';
|
|
29
30
|
const PULSE_IMPORT = '@pulse-compute/pulse';
|
|
30
31
|
const PULSE_CLASS = 'Pulse';
|
|
31
|
-
const SUPPORTED_ROUTE_METHODS = new Set(
|
|
32
|
+
const SUPPORTED_ROUTE_METHODS = new Set(ROUTER_API_DEFINITIONS
|
|
33
|
+
.filter((definition) => definition.kind === 'route')
|
|
34
|
+
.map((definition) => definition.method));
|
|
32
35
|
const DISALLOWED_OPERATION_KINDS = new Map([
|
|
33
36
|
['lifecycle', 'realtime lifecycle handlers'],
|
|
34
37
|
['channel', 'realtime channel registration'],
|