@stream44.studio/encapsulate 0.4.0-rc.14 → 0.4.0-rc.16
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/package.json
CHANGED
|
@@ -204,6 +204,23 @@ class MembraneContractCapsuleInstanceFactory extends ContractCapsuleInstanceFact
|
|
|
204
204
|
}
|
|
205
205
|
}
|
|
206
206
|
|
|
207
|
+
// Separate nested capsule-name-targeted options from own options
|
|
208
|
+
// Keys starting with '#' are own options for the mapped capsule
|
|
209
|
+
// Non-'#' keys are matched against capsule names in the mapping tree
|
|
210
|
+
let ownMappingOptions: Record<string, any> | undefined = undefined
|
|
211
|
+
let nestedCapsuleOptions: Record<string, any> | undefined = undefined
|
|
212
|
+
if (mappingOptions) {
|
|
213
|
+
for (const [key, value] of Object.entries(mappingOptions)) {
|
|
214
|
+
if (key.startsWith('#')) {
|
|
215
|
+
if (!ownMappingOptions) ownMappingOptions = {}
|
|
216
|
+
ownMappingOptions[key] = value
|
|
217
|
+
} else {
|
|
218
|
+
if (!nestedCapsuleOptions) nestedCapsuleOptions = {}
|
|
219
|
+
nestedCapsuleOptions[key] = value
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
|
|
207
224
|
// Transform overrides if this mapping has a propertyContractDelegate
|
|
208
225
|
let mappedOverrides = overrides
|
|
209
226
|
if (property.definition.propertyContractDelegate) {
|
|
@@ -229,9 +246,21 @@ class MembraneContractCapsuleInstanceFactory extends ContractCapsuleInstanceFact
|
|
|
229
246
|
}
|
|
230
247
|
}
|
|
231
248
|
|
|
249
|
+
// Merge nested capsule-name-targeted options into overrides
|
|
250
|
+
// These will be picked up when child capsules with matching names are instantiated
|
|
251
|
+
if (nestedCapsuleOptions) {
|
|
252
|
+
mappedOverrides = { ...mappedOverrides }
|
|
253
|
+
for (const [capsuleNameKey, capsuleOptions] of Object.entries(nestedCapsuleOptions)) {
|
|
254
|
+
mappedOverrides[capsuleNameKey] = {
|
|
255
|
+
...(mappedOverrides[capsuleNameKey] || {}),
|
|
256
|
+
...capsuleOptions
|
|
257
|
+
}
|
|
258
|
+
}
|
|
259
|
+
}
|
|
260
|
+
|
|
232
261
|
const mappedCapsuleInstance = await mappedCapsule.makeInstance({
|
|
233
262
|
overrides: mappedOverrides,
|
|
234
|
-
options:
|
|
263
|
+
options: ownMappingOptions,
|
|
235
264
|
runtimeSpineContracts: this.runtimeSpineContracts,
|
|
236
265
|
rootCapsule: this.capsuleInstance?.rootCapsule
|
|
237
266
|
})
|
|
@@ -214,6 +214,23 @@ export class ContractCapsuleInstanceFactory {
|
|
|
214
214
|
}
|
|
215
215
|
}
|
|
216
216
|
|
|
217
|
+
// Separate nested capsule-name-targeted options from own options
|
|
218
|
+
// Keys starting with '#' are own options for the mapped capsule
|
|
219
|
+
// Non-'#' keys are matched against capsule names in the mapping tree
|
|
220
|
+
let ownMappingOptions: Record<string, any> | undefined = undefined
|
|
221
|
+
let nestedCapsuleOptions: Record<string, any> | undefined = undefined
|
|
222
|
+
if (mappingOptions) {
|
|
223
|
+
for (const [key, value] of Object.entries(mappingOptions)) {
|
|
224
|
+
if (key.startsWith('#')) {
|
|
225
|
+
if (!ownMappingOptions) ownMappingOptions = {}
|
|
226
|
+
ownMappingOptions[key] = value
|
|
227
|
+
} else {
|
|
228
|
+
if (!nestedCapsuleOptions) nestedCapsuleOptions = {}
|
|
229
|
+
nestedCapsuleOptions[key] = value
|
|
230
|
+
}
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
|
|
217
234
|
// Transform overrides if this mapping has a propertyContractDelegate
|
|
218
235
|
let mappedOverrides = overrides
|
|
219
236
|
if (property.definition.propertyContractDelegate) {
|
|
@@ -238,10 +255,22 @@ export class ContractCapsuleInstanceFactory {
|
|
|
238
255
|
}
|
|
239
256
|
}
|
|
240
257
|
|
|
258
|
+
// Merge nested capsule-name-targeted options into overrides
|
|
259
|
+
// These will be picked up when child capsules with matching names are instantiated
|
|
260
|
+
if (nestedCapsuleOptions) {
|
|
261
|
+
mappedOverrides = { ...mappedOverrides }
|
|
262
|
+
for (const [capsuleNameKey, capsuleOptions] of Object.entries(nestedCapsuleOptions)) {
|
|
263
|
+
mappedOverrides[capsuleNameKey] = {
|
|
264
|
+
...(mappedOverrides[capsuleNameKey] || {}),
|
|
265
|
+
...capsuleOptions
|
|
266
|
+
}
|
|
267
|
+
}
|
|
268
|
+
}
|
|
269
|
+
|
|
241
270
|
const apiTarget = this.getApiTarget({ property })
|
|
242
271
|
const mappedInstance = await mappedCapsule.makeInstance({
|
|
243
272
|
overrides: mappedOverrides,
|
|
244
|
-
options:
|
|
273
|
+
options: ownMappingOptions,
|
|
245
274
|
runtimeSpineContracts: this.runtimeSpineContracts,
|
|
246
275
|
rootCapsule: this.capsuleInstance?.rootCapsule
|
|
247
276
|
})
|
|
@@ -849,7 +849,7 @@ function extractModuleLocalCode(
|
|
|
849
849
|
}
|
|
850
850
|
}
|
|
851
851
|
|
|
852
|
-
// Also collect functions from the
|
|
852
|
+
// Also collect functions and variables from the enclosing scope around the call node
|
|
853
853
|
if (callNode) {
|
|
854
854
|
let currentNode: ts.Node | undefined = callNode
|
|
855
855
|
while (currentNode) {
|
|
@@ -859,6 +859,13 @@ function extractModuleLocalCode(
|
|
|
859
859
|
if (ts.isFunctionDeclaration(statement) && statement.name) {
|
|
860
860
|
moduleLocalFunctions.set(statement.name.text, statement)
|
|
861
861
|
}
|
|
862
|
+
if (ts.isVariableStatement(statement)) {
|
|
863
|
+
for (const decl of statement.declarationList.declarations) {
|
|
864
|
+
if (ts.isIdentifier(decl.name)) {
|
|
865
|
+
moduleLocalVariables.set(decl.name.text, decl)
|
|
866
|
+
}
|
|
867
|
+
}
|
|
868
|
+
}
|
|
862
869
|
}
|
|
863
870
|
}
|
|
864
871
|
break
|
|
@@ -925,7 +932,6 @@ function extractModuleLocalCode(
|
|
|
925
932
|
if (varDecl) {
|
|
926
933
|
// Analyze the variable to see if it's self-contained
|
|
927
934
|
const varDependencies = analyzeVariableDependencies(varDecl, sourceFile, importMap, assignmentMap, moduleLocalFunctions, moduleLocalVariables)
|
|
928
|
-
|
|
929
935
|
if (varDependencies.isContained) {
|
|
930
936
|
// Mark this as module-local in ambient references
|
|
931
937
|
refTyped.type = 'module-local'
|
|
@@ -939,6 +945,14 @@ function extractModuleLocalCode(
|
|
|
939
945
|
// Fallback to just the declaration
|
|
940
946
|
moduleLocalCode[name] = varDecl.getText(sourceFile)
|
|
941
947
|
}
|
|
948
|
+
|
|
949
|
+
// Recursively collect transitive variable dependencies
|
|
950
|
+
// (e.g., if appDir = join(baseDir, 'x'), also collect baseDir)
|
|
951
|
+
collectTransitiveVariableDependencies(
|
|
952
|
+
varDecl, sourceFile, importMap, assignmentMap,
|
|
953
|
+
moduleLocalFunctions, moduleLocalVariables,
|
|
954
|
+
ambientReferences, moduleLocalCode
|
|
955
|
+
)
|
|
942
956
|
}
|
|
943
957
|
}
|
|
944
958
|
}
|
|
@@ -962,6 +976,122 @@ function extractModuleLocalCode(
|
|
|
962
976
|
return moduleLocalCode
|
|
963
977
|
}
|
|
964
978
|
|
|
979
|
+
// Recursively collect transitive variable dependencies from a variable's initializer.
|
|
980
|
+
// When a module-local variable references another module-local variable, collect that
|
|
981
|
+
// dependency's code and add it to ambientReferences and moduleLocalCode.
|
|
982
|
+
function collectTransitiveVariableDependencies(
|
|
983
|
+
varDecl: ts.VariableDeclaration,
|
|
984
|
+
sourceFile: ts.SourceFile,
|
|
985
|
+
importMap: Map<string, { importSpecifier: string, moduleUri: string }>,
|
|
986
|
+
assignmentMap: Map<string, { importSpecifier: string, moduleUri: string }>,
|
|
987
|
+
moduleLocalFunctions: Map<string, ts.FunctionDeclaration>,
|
|
988
|
+
moduleLocalVariables: Map<string, ts.VariableDeclaration>,
|
|
989
|
+
ambientReferences: Record<string, any>,
|
|
990
|
+
moduleLocalCode: Record<string, string>
|
|
991
|
+
): void {
|
|
992
|
+
if (!varDecl.initializer) return
|
|
993
|
+
|
|
994
|
+
function visit(node: ts.Node) {
|
|
995
|
+
if (ts.isTypeNode(node)) return
|
|
996
|
+
|
|
997
|
+
if (ts.isIdentifier(node)) {
|
|
998
|
+
const name = node.text
|
|
999
|
+
|
|
1000
|
+
// Skip special keywords
|
|
1001
|
+
if (name === 'this' || name === 'undefined' || name === 'null' || name === 'arguments') return
|
|
1002
|
+
|
|
1003
|
+
// Skip property access names and property assignments
|
|
1004
|
+
const parent = node.parent
|
|
1005
|
+
if (parent && ts.isPropertyAccessExpression(parent) && parent.name === node) return
|
|
1006
|
+
if (parent && ts.isPropertyAssignment(parent) && parent.name === node) return
|
|
1007
|
+
if (parent && ts.isBindingElement(parent) && parent.propertyName === node) return
|
|
1008
|
+
|
|
1009
|
+
// Skip if already tracked
|
|
1010
|
+
if (ambientReferences[name] || moduleLocalCode[name]) return
|
|
1011
|
+
|
|
1012
|
+
// Skip builtins
|
|
1013
|
+
if (MODULE_GLOBAL_BUILTINS.has(name)) return
|
|
1014
|
+
|
|
1015
|
+
// Check if it's an import — add to ambient refs
|
|
1016
|
+
const importInfo = importMap.get(name)
|
|
1017
|
+
if (importInfo) {
|
|
1018
|
+
if (!ambientReferences[name]) {
|
|
1019
|
+
ambientReferences[name] = {
|
|
1020
|
+
type: 'import',
|
|
1021
|
+
importSpecifier: importInfo.importSpecifier,
|
|
1022
|
+
moduleUri: importInfo.moduleUri
|
|
1023
|
+
}
|
|
1024
|
+
}
|
|
1025
|
+
return
|
|
1026
|
+
}
|
|
1027
|
+
|
|
1028
|
+
// Check if it's an assignment from import
|
|
1029
|
+
const assignmentInfo = assignmentMap.get(name)
|
|
1030
|
+
if (assignmentInfo) {
|
|
1031
|
+
if (!ambientReferences[name]) {
|
|
1032
|
+
ambientReferences[name] = {
|
|
1033
|
+
type: 'assigned',
|
|
1034
|
+
importSpecifier: assignmentInfo.importSpecifier,
|
|
1035
|
+
moduleUri: assignmentInfo.moduleUri
|
|
1036
|
+
}
|
|
1037
|
+
}
|
|
1038
|
+
return
|
|
1039
|
+
}
|
|
1040
|
+
|
|
1041
|
+
// Check if it's another module-local variable — recursively collect
|
|
1042
|
+
const depVarDecl = moduleLocalVariables.get(name)
|
|
1043
|
+
if (depVarDecl) {
|
|
1044
|
+
const depDependencies = analyzeVariableDependencies(depVarDecl, sourceFile, importMap, assignmentMap, moduleLocalFunctions, moduleLocalVariables)
|
|
1045
|
+
if (depDependencies.isContained) {
|
|
1046
|
+
ambientReferences[name] = { type: 'module-local' }
|
|
1047
|
+
|
|
1048
|
+
const depVarStatement = depVarDecl.parent?.parent
|
|
1049
|
+
if (depVarStatement && ts.isVariableStatement(depVarStatement)) {
|
|
1050
|
+
moduleLocalCode[name] = depVarStatement.getText(sourceFile)
|
|
1051
|
+
} else {
|
|
1052
|
+
moduleLocalCode[name] = depVarDecl.getText(sourceFile)
|
|
1053
|
+
}
|
|
1054
|
+
|
|
1055
|
+
// Add import dependencies
|
|
1056
|
+
for (const [depName, depInfo] of depDependencies.importDependencies) {
|
|
1057
|
+
if (!ambientReferences[depName]) {
|
|
1058
|
+
ambientReferences[depName] = {
|
|
1059
|
+
type: 'import',
|
|
1060
|
+
importSpecifier: depInfo.importSpecifier,
|
|
1061
|
+
moduleUri: depInfo.moduleUri
|
|
1062
|
+
}
|
|
1063
|
+
}
|
|
1064
|
+
}
|
|
1065
|
+
|
|
1066
|
+
// Recurse into this dependency's initializer
|
|
1067
|
+
collectTransitiveVariableDependencies(
|
|
1068
|
+
depVarDecl, sourceFile, importMap, assignmentMap,
|
|
1069
|
+
moduleLocalFunctions, moduleLocalVariables,
|
|
1070
|
+
ambientReferences, moduleLocalCode
|
|
1071
|
+
)
|
|
1072
|
+
}
|
|
1073
|
+
return
|
|
1074
|
+
}
|
|
1075
|
+
|
|
1076
|
+
// Check if it's a module-local function
|
|
1077
|
+
if (moduleLocalFunctions.has(name)) {
|
|
1078
|
+
if (!ambientReferences[name]) {
|
|
1079
|
+
ambientReferences[name] = { type: 'module-local' }
|
|
1080
|
+
}
|
|
1081
|
+
if (!moduleLocalCode[name]) {
|
|
1082
|
+
const funcDecl = moduleLocalFunctions.get(name)!
|
|
1083
|
+
moduleLocalCode[name] = funcDecl.getText(sourceFile)
|
|
1084
|
+
}
|
|
1085
|
+
return
|
|
1086
|
+
}
|
|
1087
|
+
}
|
|
1088
|
+
|
|
1089
|
+
ts.forEachChild(node, visit)
|
|
1090
|
+
}
|
|
1091
|
+
|
|
1092
|
+
visit(varDecl.initializer)
|
|
1093
|
+
}
|
|
1094
|
+
|
|
965
1095
|
// Analyze if a function is self-contained (only depends on other module-local functions or builtins)
|
|
966
1096
|
function analyzeFunctionDependencies(
|
|
967
1097
|
funcDecl: ts.FunctionDeclaration,
|
|
@@ -1250,7 +1380,7 @@ function extractCapsuleAmbientReferences(
|
|
|
1250
1380
|
}
|
|
1251
1381
|
}
|
|
1252
1382
|
|
|
1253
|
-
// Find enclosing function and collect its parameters and local functions
|
|
1383
|
+
// Find enclosing function and collect its parameters, local variables, and local functions
|
|
1254
1384
|
let currentNode: ts.Node | undefined = call
|
|
1255
1385
|
let enclosingBlock: ts.Block | undefined
|
|
1256
1386
|
while (currentNode) {
|
|
@@ -1259,7 +1389,7 @@ function extractCapsuleAmbientReferences(
|
|
|
1259
1389
|
for (const param of currentNode.parameters) {
|
|
1260
1390
|
extractParameterNames(param.name, invocationParameters)
|
|
1261
1391
|
}
|
|
1262
|
-
// Get the function body to collect local functions
|
|
1392
|
+
// Get the function body to collect local functions and variables
|
|
1263
1393
|
if (currentNode.body && ts.isBlock(currentNode.body)) {
|
|
1264
1394
|
enclosingBlock = currentNode.body
|
|
1265
1395
|
}
|
|
@@ -1268,12 +1398,19 @@ function extractCapsuleAmbientReferences(
|
|
|
1268
1398
|
currentNode = currentNode.parent
|
|
1269
1399
|
}
|
|
1270
1400
|
|
|
1271
|
-
// Collect function declarations from the enclosing block
|
|
1401
|
+
// Collect function declarations and variable declarations from the enclosing block
|
|
1272
1402
|
if (enclosingBlock) {
|
|
1273
1403
|
for (const statement of enclosingBlock.statements) {
|
|
1274
1404
|
if (ts.isFunctionDeclaration(statement) && statement.name) {
|
|
1275
1405
|
moduleLocalFunctions.set(statement.name.text, statement)
|
|
1276
1406
|
}
|
|
1407
|
+
if (ts.isVariableStatement(statement)) {
|
|
1408
|
+
for (const decl of statement.declarationList.declarations) {
|
|
1409
|
+
if (ts.isIdentifier(decl.name)) {
|
|
1410
|
+
moduleLocalVariables.set(decl.name.text, decl)
|
|
1411
|
+
}
|
|
1412
|
+
}
|
|
1413
|
+
}
|
|
1277
1414
|
}
|
|
1278
1415
|
}
|
|
1279
1416
|
|
|
@@ -1541,7 +1678,7 @@ function extractAndValidateAmbientReferences(
|
|
|
1541
1678
|
const localIdentifiers = new Set<string>()
|
|
1542
1679
|
const invocationParameters = new Set<string>()
|
|
1543
1680
|
|
|
1544
|
-
// Find enclosing function and collect its parameters as invocation arguments and local functions
|
|
1681
|
+
// Find enclosing function and collect its parameters as invocation arguments and local functions/variables
|
|
1545
1682
|
let currentNode: ts.Node | undefined = fn
|
|
1546
1683
|
let enclosingBlock: ts.Block | undefined
|
|
1547
1684
|
while (currentNode) {
|
|
@@ -1551,7 +1688,7 @@ function extractAndValidateAmbientReferences(
|
|
|
1551
1688
|
for (const param of currentNode.parameters) {
|
|
1552
1689
|
extractParameterNamesForInvocation(param.name, invocationParameters)
|
|
1553
1690
|
}
|
|
1554
|
-
// Get the function body to collect local functions
|
|
1691
|
+
// Get the function body to collect local functions and variables
|
|
1555
1692
|
if (currentNode.body && ts.isBlock(currentNode.body)) {
|
|
1556
1693
|
enclosingBlock = currentNode.body
|
|
1557
1694
|
}
|
|
@@ -1561,12 +1698,19 @@ function extractAndValidateAmbientReferences(
|
|
|
1561
1698
|
currentNode = currentNode.parent
|
|
1562
1699
|
}
|
|
1563
1700
|
|
|
1564
|
-
// Collect function declarations from the enclosing block
|
|
1701
|
+
// Collect function declarations and variable declarations from the enclosing block
|
|
1565
1702
|
if (enclosingBlock) {
|
|
1566
1703
|
for (const statement of enclosingBlock.statements) {
|
|
1567
1704
|
if (ts.isFunctionDeclaration(statement) && statement.name) {
|
|
1568
1705
|
moduleLocalFunctions.set(statement.name.text, statement)
|
|
1569
1706
|
}
|
|
1707
|
+
if (ts.isVariableStatement(statement)) {
|
|
1708
|
+
for (const decl of statement.declarationList.declarations) {
|
|
1709
|
+
if (ts.isIdentifier(decl.name)) {
|
|
1710
|
+
moduleLocalVariables.set(decl.name.text, decl)
|
|
1711
|
+
}
|
|
1712
|
+
}
|
|
1713
|
+
}
|
|
1570
1714
|
}
|
|
1571
1715
|
}
|
|
1572
1716
|
|