@stream44.studio/encapsulate 0.4.0-rc.29 → 0.4.0-rc.31
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
package/src/encapsulate.ts
CHANGED
|
@@ -731,12 +731,20 @@ async function encapsulate(definition: TCapsuleDefinition, options: TCapsuleOpti
|
|
|
731
731
|
const ownSelf = merge({}, defaultInstance, defaultPropertyValues, ...Object.values(mergedValuesByContract))
|
|
732
732
|
|
|
733
733
|
// Convert relative paths to absolute for metadata exposure
|
|
734
|
+
// When a CST exists with a source moduleFilepath, use it to derive the absolute path.
|
|
735
|
+
// This ensures that projected capsules (loaded from .~o/encapsulate.dev/caps/...)
|
|
736
|
+
// still expose the original source filepath, not the projected filepath.
|
|
737
|
+
const originalAbsoluteModuleFilepath = cst?.source?.moduleFilepath
|
|
738
|
+
? (cst.source.moduleFilepath.startsWith('/')
|
|
739
|
+
? cst.source.moduleFilepath
|
|
740
|
+
: join(spine.spineOptions.spineFilesystemRoot || '', cst.source.moduleFilepath))
|
|
741
|
+
: absoluteModuleFilepath
|
|
734
742
|
const absoluteCapsuleSourceLineRef = `${absoluteModuleFilepath}:${importStackLine}`
|
|
735
743
|
const capsuleMetadataStruct: Record<string, any> = {
|
|
736
744
|
capsuleName: encapsulateOptions.capsuleName,
|
|
737
745
|
capsuleSourceLineRef: absoluteCapsuleSourceLineRef,
|
|
738
746
|
capsuleSourceNameRefHash: cst?.capsuleSourceNameRefHash,
|
|
739
|
-
moduleFilepath:
|
|
747
|
+
moduleFilepath: originalAbsoluteModuleFilepath,
|
|
740
748
|
// Root capsule metadata will be populated after extends chain is resolved
|
|
741
749
|
rootCapsule: {
|
|
742
750
|
capsuleName: undefined as string | undefined,
|
|
@@ -854,7 +862,7 @@ async function encapsulate(definition: TCapsuleDefinition, options: TCapsuleOpti
|
|
|
854
862
|
const resolvedRootCapsule = rootCapsule || {
|
|
855
863
|
capsuleName: encapsulateOptions.capsuleName!,
|
|
856
864
|
capsuleSourceLineRef: absoluteCapsuleSourceLineRef,
|
|
857
|
-
moduleFilepath:
|
|
865
|
+
moduleFilepath: originalAbsoluteModuleFilepath
|
|
858
866
|
}
|
|
859
867
|
capsuleMetadataStruct.rootCapsule.capsuleName = resolvedRootCapsule.capsuleName
|
|
860
868
|
capsuleMetadataStruct.rootCapsule.capsuleSourceLineRef = resolvedRootCapsule.capsuleSourceLineRef
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
import { CapsulePropertyTypes } from "../../encapsulate"
|
|
2
2
|
import { ContractCapsuleInstanceFactory, CapsuleInstanceRegistry } from "./Static.v0"
|
|
3
|
+
import { readFileSync, existsSync } from "node:fs"
|
|
4
|
+
import { dirname, relative, join } from "node:path"
|
|
3
5
|
|
|
4
6
|
type CallerContext = {
|
|
5
7
|
capsuleSourceLineRef: string
|
|
@@ -8,9 +10,9 @@ type CallerContext = {
|
|
|
8
10
|
capsuleSourceNameRefHash?: string
|
|
9
11
|
capsuleSourceUriLineRefInstanceId?: string
|
|
10
12
|
prop?: string
|
|
11
|
-
|
|
13
|
+
fileUri?: string
|
|
12
14
|
line?: number
|
|
13
|
-
stack?: Array<{ function?: string,
|
|
15
|
+
stack?: Array<{ function?: string, fileUri?: string, line?: number, column?: number }>
|
|
14
16
|
}
|
|
15
17
|
|
|
16
18
|
function CapsuleMembrane(target: Record<string, any>, hooks?: {
|
|
@@ -185,7 +187,7 @@ class MembraneContractCapsuleInstanceFactory extends ContractCapsuleInstanceFact
|
|
|
185
187
|
const stackFrames = parseCallerFromStack(stackStr, this.spineFilesystemRoot)
|
|
186
188
|
if (stackFrames.length > 0) {
|
|
187
189
|
const callerInfo = extractCallerInfo(stackFrames, 3)
|
|
188
|
-
callerCtx.
|
|
190
|
+
callerCtx.fileUri = callerInfo.fileUri
|
|
189
191
|
callerCtx.line = callerInfo.line
|
|
190
192
|
callerCtx.stack = stackFrames
|
|
191
193
|
}
|
|
@@ -312,7 +314,7 @@ class MembraneContractCapsuleInstanceFactory extends ContractCapsuleInstanceFact
|
|
|
312
314
|
const stackFrames = parseCallerFromStack(stackStr, this.spineFilesystemRoot)
|
|
313
315
|
if (stackFrames.length > 0) {
|
|
314
316
|
const callerInfo = extractCallerInfo(stackFrames, 3)
|
|
315
|
-
callerCtx.
|
|
317
|
+
callerCtx.fileUri = callerInfo.fileUri
|
|
316
318
|
callerCtx.line = callerInfo.line
|
|
317
319
|
callerCtx.stack = stackFrames
|
|
318
320
|
}
|
|
@@ -375,7 +377,7 @@ class MembraneContractCapsuleInstanceFactory extends ContractCapsuleInstanceFact
|
|
|
375
377
|
const stackFrames = parseCallerFromStack(stackStr, this.spineFilesystemRoot)
|
|
376
378
|
if (stackFrames.length > 0) {
|
|
377
379
|
const callerInfo = extractCallerInfo(stackFrames, 3)
|
|
378
|
-
callerCtx.
|
|
380
|
+
callerCtx.fileUri = callerInfo.fileUri
|
|
379
381
|
callerCtx.line = callerInfo.line
|
|
380
382
|
callerCtx.stack = stackFrames
|
|
381
383
|
}
|
|
@@ -878,8 +880,8 @@ class MembraneContractCapsuleInstanceFactory extends ContractCapsuleInstanceFact
|
|
|
878
880
|
if (callerCtx.prop) {
|
|
879
881
|
event.caller.prop = callerCtx.prop
|
|
880
882
|
}
|
|
881
|
-
if (callerCtx.
|
|
882
|
-
event.caller.
|
|
883
|
+
if (callerCtx.fileUri) {
|
|
884
|
+
event.caller.fileUri = callerCtx.fileUri
|
|
883
885
|
}
|
|
884
886
|
if (callerCtx.line) {
|
|
885
887
|
event.caller.line = callerCtx.line
|
|
@@ -975,9 +977,67 @@ CapsuleSpineContract['#'] = '@stream44.studio/encapsulate/spine-contracts/Capsul
|
|
|
975
977
|
|
|
976
978
|
|
|
977
979
|
|
|
978
|
-
|
|
980
|
+
// Cache for synchronous npm URI lookups (directory -> package name or null)
|
|
981
|
+
const npmUriCache = new Map<string, string | null>()
|
|
982
|
+
|
|
983
|
+
function constructNpmUriSync(absoluteFilepath: string): string | null {
|
|
984
|
+
// Only process absolute paths — skip V8 internal markers like "native", "node:*", etc.
|
|
985
|
+
if (!absoluteFilepath.startsWith('/')) {
|
|
986
|
+
return null
|
|
987
|
+
}
|
|
988
|
+
|
|
989
|
+
// Check for /node_modules/ in the path — use the last occurrence to handle nested node_modules
|
|
990
|
+
const nodeModulesMarker = '/node_modules/'
|
|
991
|
+
const lastIdx = absoluteFilepath.lastIndexOf(nodeModulesMarker)
|
|
992
|
+
if (lastIdx !== -1) {
|
|
993
|
+
return absoluteFilepath.substring(lastIdx + nodeModulesMarker.length)
|
|
994
|
+
}
|
|
995
|
+
|
|
996
|
+
let currentDir = dirname(absoluteFilepath)
|
|
997
|
+
const maxDepth = 20
|
|
998
|
+
|
|
999
|
+
for (let i = 0; i < maxDepth; i++) {
|
|
1000
|
+
if (npmUriCache.has(currentDir)) {
|
|
1001
|
+
const cachedName = npmUriCache.get(currentDir)
|
|
1002
|
+
if (cachedName) {
|
|
1003
|
+
const relativeFromPackage = relative(currentDir, absoluteFilepath)
|
|
1004
|
+
return `${cachedName}/${relativeFromPackage}`
|
|
1005
|
+
}
|
|
1006
|
+
// null means no package.json with name found at this level, continue up
|
|
1007
|
+
const parentDir = dirname(currentDir)
|
|
1008
|
+
if (parentDir === currentDir) break
|
|
1009
|
+
currentDir = parentDir
|
|
1010
|
+
continue
|
|
1011
|
+
}
|
|
1012
|
+
|
|
1013
|
+
const packageJsonPath = join(currentDir, 'package.json')
|
|
1014
|
+
try {
|
|
1015
|
+
if (existsSync(packageJsonPath)) {
|
|
1016
|
+
const packageJson = JSON.parse(readFileSync(packageJsonPath, 'utf-8'))
|
|
1017
|
+
const packageName = packageJson.name
|
|
1018
|
+
npmUriCache.set(currentDir, packageName || null)
|
|
1019
|
+
if (packageName) {
|
|
1020
|
+
const relativeFromPackage = relative(currentDir, absoluteFilepath)
|
|
1021
|
+
return `${packageName}/${relativeFromPackage}`
|
|
1022
|
+
}
|
|
1023
|
+
} else {
|
|
1024
|
+
npmUriCache.set(currentDir, null)
|
|
1025
|
+
}
|
|
1026
|
+
} catch {
|
|
1027
|
+
npmUriCache.set(currentDir, null)
|
|
1028
|
+
}
|
|
1029
|
+
|
|
1030
|
+
const parentDir = dirname(currentDir)
|
|
1031
|
+
if (parentDir === currentDir) break
|
|
1032
|
+
currentDir = parentDir
|
|
1033
|
+
}
|
|
1034
|
+
|
|
1035
|
+
return null
|
|
1036
|
+
}
|
|
1037
|
+
|
|
1038
|
+
function parseCallerFromStack(stack: string, spineFilesystemRoot?: string): Array<{ function?: string, fileUri?: string, line?: number, column?: number }> {
|
|
979
1039
|
const lines = stack.split('\n')
|
|
980
|
-
const result: Array<{ function?: string,
|
|
1040
|
+
const result: Array<{ function?: string, fileUri?: string, line?: number, column?: number }> = []
|
|
981
1041
|
|
|
982
1042
|
// Skip first line (Error message), then collect ALL frames
|
|
983
1043
|
for (let i = 1; i < lines.length; i++) {
|
|
@@ -989,9 +1049,11 @@ function parseCallerFromStack(stack: string, spineFilesystemRoot?: string): Arra
|
|
|
989
1049
|
// "at functionName (file:line:column)"
|
|
990
1050
|
const match = line.match(/at\s+(.+)/)
|
|
991
1051
|
if (match) {
|
|
992
|
-
const frame: { function?: string,
|
|
1052
|
+
const frame: { function?: string, fileUri?: string, line?: number, column?: number } = {}
|
|
993
1053
|
const content = match[1]
|
|
994
1054
|
|
|
1055
|
+
let rawFilepath: string | undefined
|
|
1056
|
+
|
|
995
1057
|
// Try to extract function name and location
|
|
996
1058
|
const funcMatch = content.match(/^(.+?)\s+\((.+)\)$/)
|
|
997
1059
|
if (funcMatch) {
|
|
@@ -1004,7 +1066,7 @@ function parseCallerFromStack(stack: string, spineFilesystemRoot?: string): Arra
|
|
|
1004
1066
|
const location = funcMatch[2]
|
|
1005
1067
|
const locMatch = location.match(/^(.+):(\d+):(\d+)$/)
|
|
1006
1068
|
if (locMatch) {
|
|
1007
|
-
|
|
1069
|
+
rawFilepath = locMatch[1]
|
|
1008
1070
|
frame.line = parseInt(locMatch[2], 10)
|
|
1009
1071
|
frame.column = parseInt(locMatch[3], 10)
|
|
1010
1072
|
}
|
|
@@ -1012,25 +1074,32 @@ function parseCallerFromStack(stack: string, spineFilesystemRoot?: string): Arra
|
|
|
1012
1074
|
// No function name: "/path/to/file:line:column"
|
|
1013
1075
|
const locMatch = content.match(/^(.+):(\d+):(\d+)$/)
|
|
1014
1076
|
if (locMatch) {
|
|
1015
|
-
|
|
1077
|
+
rawFilepath = locMatch[1]
|
|
1016
1078
|
frame.line = parseInt(locMatch[2], 10)
|
|
1017
1079
|
frame.column = parseInt(locMatch[3], 10)
|
|
1018
1080
|
}
|
|
1019
1081
|
}
|
|
1020
1082
|
|
|
1021
|
-
// Convert absolute
|
|
1022
|
-
if (
|
|
1023
|
-
|
|
1024
|
-
|
|
1025
|
-
//
|
|
1026
|
-
|
|
1027
|
-
|
|
1083
|
+
// Convert absolute filepaths to npm URIs
|
|
1084
|
+
if (rawFilepath) {
|
|
1085
|
+
const npmUri = constructNpmUriSync(rawFilepath)
|
|
1086
|
+
if (npmUri) {
|
|
1087
|
+
// Strip file extension from URI for consistency
|
|
1088
|
+
frame.fileUri = npmUri.replace(/\.(ts|tsx|js|jsx)$/, '')
|
|
1089
|
+
} else if (spineFilesystemRoot && rawFilepath.startsWith(spineFilesystemRoot)) {
|
|
1090
|
+
// Fallback: use relative path from spine root if npm URI not resolvable
|
|
1091
|
+
let relativePath = rawFilepath.slice(spineFilesystemRoot.length)
|
|
1092
|
+
if (relativePath.startsWith('/')) {
|
|
1093
|
+
relativePath = relativePath.slice(1)
|
|
1028
1094
|
}
|
|
1095
|
+
frame.fileUri = relativePath
|
|
1096
|
+
} else {
|
|
1097
|
+
frame.fileUri = rawFilepath
|
|
1029
1098
|
}
|
|
1030
1099
|
}
|
|
1031
1100
|
|
|
1032
1101
|
// Include all frames, even if incomplete
|
|
1033
|
-
if (frame.
|
|
1102
|
+
if (frame.fileUri || frame.function) {
|
|
1034
1103
|
result.push(frame)
|
|
1035
1104
|
}
|
|
1036
1105
|
}
|
|
@@ -1038,14 +1107,14 @@ function parseCallerFromStack(stack: string, spineFilesystemRoot?: string): Arra
|
|
|
1038
1107
|
return result
|
|
1039
1108
|
}
|
|
1040
1109
|
|
|
1041
|
-
function extractCallerInfo(stack: Array<{ function?: string,
|
|
1110
|
+
function extractCallerInfo(stack: Array<{ function?: string, fileUri?: string, line?: number, column?: number }>, offset: number = 0) {
|
|
1042
1111
|
// Use offset to skip frames in the stack
|
|
1043
1112
|
// offset 0 = first frame, offset 1 = second frame, etc.
|
|
1044
1113
|
|
|
1045
1114
|
if (offset < stack.length) {
|
|
1046
1115
|
const frame = stack[offset]
|
|
1047
1116
|
return {
|
|
1048
|
-
|
|
1117
|
+
fileUri: frame.fileUri,
|
|
1049
1118
|
line: frame.line
|
|
1050
1119
|
}
|
|
1051
1120
|
}
|
|
@@ -1053,7 +1122,7 @@ function extractCallerInfo(stack: Array<{ function?: string, filepath?: string,
|
|
|
1053
1122
|
// Fallback to first frame if offset is out of bounds
|
|
1054
1123
|
if (stack.length > 0) {
|
|
1055
1124
|
return {
|
|
1056
|
-
|
|
1125
|
+
fileUri: stack[0].fileUri,
|
|
1057
1126
|
line: stack[0].line
|
|
1058
1127
|
}
|
|
1059
1128
|
}
|
|
@@ -397,7 +397,7 @@ Both implement the same property mapping logic. The difference is observability.
|
|
|
397
397
|
| `call` | Function invoked | `{ target, args, eventIndex }` |
|
|
398
398
|
| `call-result` | Function returns | `{ target, result, callEventIndex }` |
|
|
399
399
|
|
|
400
|
-
Events include `caller` context (source capsule, property,
|
|
400
|
+
Events include `caller` context (source capsule, property, fileUri, line) when `enableCallerStackInference` is enabled. Memoized results are tagged with `memoized: true`.
|
|
401
401
|
|
|
402
402
|
### SpineRuntime & run()
|
|
403
403
|
|
|
@@ -1006,7 +1006,7 @@ function extractModuleLocalCode(
|
|
|
1006
1006
|
if (funcDecl) {
|
|
1007
1007
|
// Analyze the function to see if it's self-contained
|
|
1008
1008
|
const dependencies = new Set<string>()
|
|
1009
|
-
const isContained = analyzeFunctionDependencies(funcDecl, sourceFile, importMap, assignmentMap, moduleLocalFunctions, dependencies)
|
|
1009
|
+
const isContained = analyzeFunctionDependencies(funcDecl, sourceFile, importMap, assignmentMap, moduleLocalFunctions, dependencies, moduleLocalVariables)
|
|
1010
1010
|
|
|
1011
1011
|
if (isContained) {
|
|
1012
1012
|
// Mark this as module-local in ambient references
|
|
@@ -1034,9 +1034,33 @@ function extractModuleLocalCode(
|
|
|
1034
1034
|
// Collect the main function
|
|
1035
1035
|
collectFunction(name)
|
|
1036
1036
|
|
|
1037
|
-
// Collect all dependencies
|
|
1037
|
+
// Collect all dependencies (functions and variables)
|
|
1038
1038
|
for (const dep of dependencies) {
|
|
1039
1039
|
collectFunction(dep)
|
|
1040
|
+
|
|
1041
|
+
// Also collect module-local variable dependencies
|
|
1042
|
+
const depVarDecl = moduleLocalVariables.get(dep)
|
|
1043
|
+
if (depVarDecl && !processed.has(dep)) {
|
|
1044
|
+
processed.add(dep)
|
|
1045
|
+
const varStatement = depVarDecl.parent?.parent
|
|
1046
|
+
if (varStatement && ts.isVariableStatement(varStatement)) {
|
|
1047
|
+
const varCode = varStatement.getText(sourceFile)
|
|
1048
|
+
collectedCode.push(varCode)
|
|
1049
|
+
if (!moduleLocalCode[dep]) {
|
|
1050
|
+
moduleLocalCode[dep] = varCode
|
|
1051
|
+
}
|
|
1052
|
+
}
|
|
1053
|
+
// Mark the variable dependency in ambient references
|
|
1054
|
+
if (!ambientReferences[dep]) {
|
|
1055
|
+
ambientReferences[dep] = { type: 'module-local' }
|
|
1056
|
+
}
|
|
1057
|
+
// Recursively collect transitive variable dependencies
|
|
1058
|
+
collectTransitiveVariableDependencies(
|
|
1059
|
+
depVarDecl, sourceFile, importMap, assignmentMap,
|
|
1060
|
+
moduleLocalFunctions, moduleLocalVariables,
|
|
1061
|
+
ambientReferences, moduleLocalCode
|
|
1062
|
+
)
|
|
1063
|
+
}
|
|
1040
1064
|
}
|
|
1041
1065
|
|
|
1042
1066
|
// Store the collected code (main function with all dependencies)
|
|
@@ -1087,7 +1111,7 @@ function extractModuleLocalCode(
|
|
|
1087
1111
|
|
|
1088
1112
|
// Analyze if it's self-contained
|
|
1089
1113
|
const dependencies = new Set<string>()
|
|
1090
|
-
const isContained = analyzeFunctionDependencies(funcDecl, sourceFile, importMap, assignmentMap, moduleLocalFunctions, dependencies)
|
|
1114
|
+
const isContained = analyzeFunctionDependencies(funcDecl, sourceFile, importMap, assignmentMap, moduleLocalFunctions, dependencies, moduleLocalVariables)
|
|
1091
1115
|
|
|
1092
1116
|
if (isContained) {
|
|
1093
1117
|
// Add this function to moduleLocalCode
|
|
@@ -1214,14 +1238,15 @@ function collectTransitiveVariableDependencies(
|
|
|
1214
1238
|
visit(varDecl.initializer)
|
|
1215
1239
|
}
|
|
1216
1240
|
|
|
1217
|
-
// Analyze if a function is self-contained (only depends on other module-local functions or builtins)
|
|
1241
|
+
// Analyze if a function is self-contained (only depends on other module-local functions, variables, or builtins)
|
|
1218
1242
|
function analyzeFunctionDependencies(
|
|
1219
1243
|
funcDecl: ts.FunctionDeclaration,
|
|
1220
1244
|
sourceFile: ts.SourceFile,
|
|
1221
1245
|
importMap: Map<string, { importSpecifier: string, moduleUri: string }>,
|
|
1222
1246
|
assignmentMap: Map<string, { importSpecifier: string, moduleUri: string }>,
|
|
1223
1247
|
moduleLocalFunctions: Map<string, ts.FunctionDeclaration>,
|
|
1224
|
-
dependencies: Set<string
|
|
1248
|
+
dependencies: Set<string>,
|
|
1249
|
+
moduleLocalVariables?: Map<string, ts.VariableDeclaration>
|
|
1225
1250
|
): boolean {
|
|
1226
1251
|
const localIdentifiers = new Set<string>()
|
|
1227
1252
|
const nestedFunctionScopes = new Map<ts.Node, Set<string>>()
|
|
@@ -1348,6 +1373,12 @@ function analyzeFunctionDependencies(
|
|
|
1348
1373
|
return
|
|
1349
1374
|
}
|
|
1350
1375
|
|
|
1376
|
+
// Check if it's a module-local variable - add as dependency
|
|
1377
|
+
if (moduleLocalVariables?.has(identifierName)) {
|
|
1378
|
+
dependencies.add(identifierName)
|
|
1379
|
+
return
|
|
1380
|
+
}
|
|
1381
|
+
|
|
1351
1382
|
// Check if it's a module-global builtin - allowed
|
|
1352
1383
|
if (MODULE_GLOBAL_BUILTINS.has(identifierName)) {
|
|
1353
1384
|
return
|
|
@@ -1681,7 +1712,7 @@ function extractCapsuleAmbientReferences(
|
|
|
1681
1712
|
if (funcDecl) {
|
|
1682
1713
|
// Analyze if it's self-contained
|
|
1683
1714
|
const dependencies = new Set<string>()
|
|
1684
|
-
const isContained = analyzeFunctionDependencies(funcDecl, sourceFile, importMap, assignmentMap, moduleLocalFunctions, dependencies)
|
|
1715
|
+
const isContained = analyzeFunctionDependencies(funcDecl, sourceFile, importMap, assignmentMap, moduleLocalFunctions, dependencies, moduleLocalVariables)
|
|
1685
1716
|
|
|
1686
1717
|
if (isContained) {
|
|
1687
1718
|
// Mark as module-local
|
|
@@ -1689,7 +1720,7 @@ function extractCapsuleAmbientReferences(
|
|
|
1689
1720
|
type: 'module-local'
|
|
1690
1721
|
}
|
|
1691
1722
|
|
|
1692
|
-
// Add import dependencies from the function's body
|
|
1723
|
+
// Add import/variable dependencies from the function's body
|
|
1693
1724
|
for (const depName of dependencies) {
|
|
1694
1725
|
if (!ambientRefs[depName]) {
|
|
1695
1726
|
const depImportInfo = importMap.get(depName)
|
|
@@ -1707,6 +1738,14 @@ function extractCapsuleAmbientReferences(
|
|
|
1707
1738
|
importSpecifier: depAssignmentInfo.importSpecifier,
|
|
1708
1739
|
moduleUri: depAssignmentInfo.moduleUri
|
|
1709
1740
|
}
|
|
1741
|
+
} else if (moduleLocalVariables.has(depName)) {
|
|
1742
|
+
ambientRefs[depName] = {
|
|
1743
|
+
type: 'module-local'
|
|
1744
|
+
}
|
|
1745
|
+
} else if (moduleLocalFunctions.has(depName)) {
|
|
1746
|
+
ambientRefs[depName] = {
|
|
1747
|
+
type: 'module-local'
|
|
1748
|
+
}
|
|
1710
1749
|
}
|
|
1711
1750
|
}
|
|
1712
1751
|
}
|
|
@@ -2053,7 +2092,7 @@ function extractAndValidateAmbientReferences(
|
|
|
2053
2092
|
if (funcDecl) {
|
|
2054
2093
|
// Analyze if it's self-contained
|
|
2055
2094
|
const dependencies = new Set<string>()
|
|
2056
|
-
const isContained = analyzeFunctionDependencies(funcDecl, sourceFile, importMap, assignmentMap, moduleLocalFunctions, dependencies)
|
|
2095
|
+
const isContained = analyzeFunctionDependencies(funcDecl, sourceFile, importMap, assignmentMap, moduleLocalFunctions, dependencies, moduleLocalVariables)
|
|
2057
2096
|
|
|
2058
2097
|
if (isContained) {
|
|
2059
2098
|
// Mark as module-local
|
|
@@ -2061,7 +2100,7 @@ function extractAndValidateAmbientReferences(
|
|
|
2061
2100
|
type: 'module-local'
|
|
2062
2101
|
}
|
|
2063
2102
|
|
|
2064
|
-
// Add import dependencies from the function's body
|
|
2103
|
+
// Add import/variable dependencies from the function's body
|
|
2065
2104
|
for (const depName of dependencies) {
|
|
2066
2105
|
if (!ambientRefs[depName]) {
|
|
2067
2106
|
const depImportInfo = importMap.get(depName)
|
|
@@ -2079,6 +2118,14 @@ function extractAndValidateAmbientReferences(
|
|
|
2079
2118
|
importSpecifier: depAssignmentInfo.importSpecifier,
|
|
2080
2119
|
moduleUri: depAssignmentInfo.moduleUri
|
|
2081
2120
|
}
|
|
2121
|
+
} else if (moduleLocalVariables.has(depName)) {
|
|
2122
|
+
ambientRefs[depName] = {
|
|
2123
|
+
type: 'module-local'
|
|
2124
|
+
}
|
|
2125
|
+
} else if (moduleLocalFunctions.has(depName)) {
|
|
2126
|
+
ambientRefs[depName] = {
|
|
2127
|
+
type: 'module-local'
|
|
2128
|
+
}
|
|
2082
2129
|
}
|
|
2083
2130
|
}
|
|
2084
2131
|
}
|