@stream44.studio/encapsulate 0.4.0-rc.11 → 0.4.0-rc.12
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/.dockerignore +3 -0
- package/.github/workflows/test.yaml +1 -1
- package/Dockerfile +15 -0
- package/README.md +9 -1
- package/package.json +4 -3
- package/scripts/test-docker.sh +17 -0
- package/src/capsule-projectors/CapsuleModuleProjector.v0.ts +37 -27
- package/src/encapsulate.ts +114 -20
- package/src/spine-contracts/CapsuleSpineContract.v0/Membrane.v0.ts +16 -5
- package/src/spine-contracts/CapsuleSpineContract.v0/Static.v0.ts +10 -5
- package/src/spine-factories/CapsuleSpineFactory.v0.ts +7 -1
- package/src/static-analyzer.v0.ts +13 -4
package/.dockerignore
ADDED
package/Dockerfile
ADDED
package/README.md
CHANGED
|
@@ -4,6 +4,8 @@
|
|
|
4
4
|
|
|
5
5
|
⚠️ **Disclaimer:** Under active development. Code has not been audited, APIs and interfaces are subject to change.
|
|
6
6
|
|
|
7
|
+
[](https://github.com/Stream44/encapsulate/actions/workflows/tests.yaml?query=branch%3Amain)
|
|
8
|
+
|
|
7
9
|
encapsulate
|
|
8
10
|
===
|
|
9
11
|
|
|
@@ -27,6 +29,12 @@ Notes
|
|
|
27
29
|
- The first spine contract is defined and implemented here: [src/spine-contracts/CapsuleSpineContract.v0/](src/spine-contracts/CapsuleSpineContract.v0/)
|
|
28
30
|
- Projector reference implementations are here: [github.com/Stream44/ink-component-projector](https://github.com/Stream44/ink-component-projector)
|
|
29
31
|
|
|
32
|
+
Roadmap
|
|
33
|
+
---
|
|
34
|
+
|
|
35
|
+
- [ ] Document [src/spine-contracts/CapsuleSpineContract.v0/](src/spine-contracts/CapsuleSpineContract.v0/)
|
|
36
|
+
- [ ] Private properties
|
|
37
|
+
|
|
30
38
|
|
|
31
39
|
Provenance
|
|
32
40
|
===
|
|
@@ -45,4 +53,4 @@ Repository DID: `did:repo:412cd408c657737343a6089ed6d5f0668a8bfb05`
|
|
|
45
53
|
</tr>
|
|
46
54
|
</table>
|
|
47
55
|
|
|
48
|
-
(c) 2026 [Christoph.diy](https://christoph.diy) • Code: `
|
|
56
|
+
(c) 2026 [Christoph.diy](https://christoph.diy) • Code: `BSD-2-Clause-Patent` • Text: `CC-BY` • Created with [Stream44.Studio](https://Stream44.Studio)
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@stream44.studio/encapsulate",
|
|
3
|
-
"version": "0.4.0-rc.
|
|
4
|
-
"license": "
|
|
3
|
+
"version": "0.4.0-rc.12",
|
|
4
|
+
"license": "BSD-2-Clause-Patent",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
7
7
|
"url": "git+https://github.com/Stream44/encapsulate.git"
|
|
@@ -17,7 +17,8 @@
|
|
|
17
17
|
"./structs/Capsule": "./structs/Capsule.ts"
|
|
18
18
|
},
|
|
19
19
|
"scripts": {
|
|
20
|
-
"test": "bun test"
|
|
20
|
+
"test": "bun test",
|
|
21
|
+
"test:docker": "./scripts/test-docker.sh"
|
|
21
22
|
},
|
|
22
23
|
"dependencies": {
|
|
23
24
|
"typescript": "^5.9.3",
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
set -e
|
|
3
|
+
|
|
4
|
+
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
5
|
+
PACKAGE_DIR="$(dirname "$SCRIPT_DIR")"
|
|
6
|
+
|
|
7
|
+
cd "$PACKAGE_DIR"
|
|
8
|
+
|
|
9
|
+
IMAGE_NAME="encapsulate-test"
|
|
10
|
+
|
|
11
|
+
echo "Building Docker image..."
|
|
12
|
+
docker build -t "$IMAGE_NAME" .
|
|
13
|
+
|
|
14
|
+
echo "Running tests in Docker..."
|
|
15
|
+
docker run --rm "$IMAGE_NAME"
|
|
16
|
+
|
|
17
|
+
echo "Tests completed successfully!"
|
|
@@ -457,24 +457,22 @@ export function CapsuleModuleProjector({
|
|
|
457
457
|
if (capsule.cst.source.capsuleName) {
|
|
458
458
|
// Use capsuleName as the path - NO line number
|
|
459
459
|
let capsuleNamePath = capsule.cst.source.capsuleName
|
|
460
|
-
// Strip @ prefix
|
|
461
460
|
if (capsuleNamePath.startsWith('@')) {
|
|
462
461
|
capsuleNamePath = capsuleNamePath.substring(1)
|
|
463
462
|
}
|
|
464
463
|
// Just capsuleName + extension, NO line number
|
|
465
|
-
projectedPath = `.~caps/${capsuleNamePath}${sourceExtension}`
|
|
464
|
+
projectedPath = `.~o/encapsulate.dev/caps/${capsuleNamePath}${sourceExtension}`
|
|
466
465
|
} else if (capsule.cst.capsuleSourceUriLineRef) {
|
|
467
466
|
// Use capsuleSourceUriLineRef which already has format: uri:line
|
|
468
467
|
let uriPath = capsule.cst.capsuleSourceUriLineRef
|
|
469
|
-
// Strip @ prefix
|
|
470
468
|
if (uriPath.startsWith('@')) {
|
|
471
469
|
uriPath = uriPath.substring(1)
|
|
472
470
|
}
|
|
473
471
|
// Add extension after the line number: uri:line.ext
|
|
474
|
-
projectedPath = `.~caps/${uriPath}${sourceExtension}`
|
|
472
|
+
projectedPath = `.~o/encapsulate.dev/caps/${uriPath}${sourceExtension}`
|
|
475
473
|
} else {
|
|
476
474
|
// Fallback to hash if neither exists
|
|
477
|
-
projectedPath = `.~caps/${capsule.cst.capsuleSourceNameRefHash.substring(0, 8)}${sourceExtension}`
|
|
475
|
+
projectedPath = `.~o/encapsulate.dev/caps/${capsule.cst.capsuleSourceNameRefHash.substring(0, 8)}${sourceExtension}`
|
|
478
476
|
}
|
|
479
477
|
|
|
480
478
|
return {
|
|
@@ -826,16 +824,20 @@ export function CapsuleModuleProjector({
|
|
|
826
824
|
const refTyped = ref as any
|
|
827
825
|
if (refTyped.type === 'capsule') {
|
|
828
826
|
const snapshot = await buildCapsuleSnapshotForReference(refTyped, capsules, spineContractUri)
|
|
829
|
-
|
|
830
|
-
|
|
827
|
+
|
|
828
|
+
// Use dynamic spineContractUri instead of hardcoded URI
|
|
829
|
+
const contractData = snapshot.spineContracts?.[spineContractUri]
|
|
830
|
+
const structKey = Object.keys(contractData || {}).find(k => k.includes('/structs/Capsule'))
|
|
831
|
+
const capsuleName = structKey ? contractData[structKey]?.capsuleName : undefined
|
|
832
|
+
const projectedFilepath = structKey ? contractData[structKey]?.projectedCapsuleFilepath : undefined
|
|
831
833
|
|
|
832
834
|
if (capsuleName && projectedFilepath) {
|
|
833
835
|
allCapsuleUris.add(capsuleName)
|
|
834
836
|
|
|
835
837
|
// Build import path from projected filepath
|
|
836
838
|
const importName = `_capsule_${capsuleName.replace(/[^a-zA-Z0-9]/g, '_')}`
|
|
837
|
-
// Remove .~caps/ prefix and strip extension
|
|
838
|
-
const importPath = projectedFilepath.replace(/^\.~caps\//, '').replace(/\.(ts|tsx)$/, '')
|
|
839
|
+
// Remove .~o/encapsulate.dev/caps/ prefix and strip extension
|
|
840
|
+
const importPath = projectedFilepath.replace(/^\.~o\/encapsulate\.dev\/caps\//, '').replace(/\.(ts|tsx)$/, '')
|
|
839
841
|
|
|
840
842
|
capsuleDeps.push({ uri: capsuleName, importName, importPath })
|
|
841
843
|
}
|
|
@@ -843,13 +845,13 @@ export function CapsuleModuleProjector({
|
|
|
843
845
|
}
|
|
844
846
|
|
|
845
847
|
// Generate static imports for all capsule dependencies
|
|
846
|
-
// Compute relative path from projected file to
|
|
848
|
+
// Compute relative path from projected file to caps directory
|
|
847
849
|
let importPrefix: string
|
|
848
850
|
if (capsuleModuleProjectionPackage) {
|
|
849
851
|
importPrefix = capsuleModuleProjectionPackage
|
|
850
852
|
} else {
|
|
851
853
|
const projectedFileDir = dirname(filepath)
|
|
852
|
-
const capsDir = '.~caps'
|
|
854
|
+
const capsDir = '.~o/encapsulate.dev/caps'
|
|
853
855
|
const relativePathToCaps = relative(projectedFileDir, capsDir)
|
|
854
856
|
importPrefix = relativePathToCaps.startsWith('.') ? relativePathToCaps : './' + relativePathToCaps
|
|
855
857
|
}
|
|
@@ -983,7 +985,9 @@ export default function({ onMembraneEvent }: { onMembraneEvent?: (event: any) =>
|
|
|
983
985
|
const refTyped = ref as any
|
|
984
986
|
if (refTyped.type === 'capsule') {
|
|
985
987
|
const snapshot = await buildCapsuleSnapshotForReference(refTyped, capsules, spineContractUri)
|
|
986
|
-
const
|
|
988
|
+
const contractData = snapshot.spineContracts?.[spineContractUri]
|
|
989
|
+
const structKey = Object.keys(contractData || {}).find(k => k.includes('/structs/Capsule'))
|
|
990
|
+
const capsuleName = structKey ? contractData[structKey]?.capsuleName : undefined
|
|
987
991
|
if (capsuleName) {
|
|
988
992
|
allCapsuleUris.add(capsuleName)
|
|
989
993
|
}
|
|
@@ -1007,13 +1011,15 @@ export default function({ onMembraneEvent }: { onMembraneEvent?: (event: any) =>
|
|
|
1007
1011
|
|
|
1008
1012
|
if (capsuleRef) {
|
|
1009
1013
|
const snapshot = await buildCapsuleSnapshotForReference(capsuleRef, capsules, spineContractUri)
|
|
1010
|
-
const
|
|
1014
|
+
const contractData = snapshot.spineContracts?.[spineContractUri]
|
|
1015
|
+
const structKey = Object.keys(contractData || {}).find(k => k.includes('/structs/Capsule'))
|
|
1016
|
+
const projectedFilepath = structKey ? contractData[structKey]?.projectedCapsuleFilepath : undefined
|
|
1011
1017
|
|
|
1012
1018
|
if (projectedFilepath) {
|
|
1013
1019
|
// Build import path from projected filepath
|
|
1014
1020
|
const importName = `_capsule_${uri.replace(/[^a-zA-Z0-9]/g, '_')}`
|
|
1015
|
-
// Remove .~caps/ prefix and strip extension
|
|
1016
|
-
const importPath = projectedFilepath.replace(/^\.~caps\//, '').replace(/\.(ts|tsx)$/, '')
|
|
1021
|
+
// Remove .~o/encapsulate.dev/caps/ prefix and strip extension
|
|
1022
|
+
const importPath = projectedFilepath.replace(/^\.~o\/encapsulate\.dev\/caps\//, '').replace(/\.(ts|tsx)$/, '')
|
|
1017
1023
|
|
|
1018
1024
|
capsuleDeps.push({ uri, importName, importPath })
|
|
1019
1025
|
}
|
|
@@ -1021,13 +1027,13 @@ export default function({ onMembraneEvent }: { onMembraneEvent?: (event: any) =>
|
|
|
1021
1027
|
}
|
|
1022
1028
|
|
|
1023
1029
|
// Generate static imports for all capsule dependencies
|
|
1024
|
-
// Compute relative path from projected file to
|
|
1030
|
+
// Compute relative path from projected file to caps directory
|
|
1025
1031
|
let importPrefix: string
|
|
1026
1032
|
if (capsuleModuleProjectionPackage) {
|
|
1027
1033
|
importPrefix = capsuleModuleProjectionPackage
|
|
1028
1034
|
} else {
|
|
1029
1035
|
const projectedFileDir = dirname(filepath)
|
|
1030
|
-
const capsDir = '.~caps'
|
|
1036
|
+
const capsDir = '.~o/encapsulate.dev/caps'
|
|
1031
1037
|
const relativePathToCaps = relative(projectedFileDir, capsDir)
|
|
1032
1038
|
importPrefix = relativePathToCaps.startsWith('.') ? relativePathToCaps : './' + relativePathToCaps
|
|
1033
1039
|
}
|
|
@@ -1321,7 +1327,9 @@ ${defaultExport}
|
|
|
1321
1327
|
const refTyped = ref as any
|
|
1322
1328
|
if (refTyped.type === 'capsule') {
|
|
1323
1329
|
const snapshot = await buildCapsuleSnapshotForReference(refTyped, capsules, spineContractUri)
|
|
1324
|
-
const
|
|
1330
|
+
const contractData = snapshot.spineContracts?.[spineContractUri]
|
|
1331
|
+
const structKey = Object.keys(contractData || {}).find(k => k.includes('/structs/Capsule'))
|
|
1332
|
+
const capsuleName = structKey ? contractData[structKey]?.capsuleName : undefined
|
|
1325
1333
|
if (capsuleName) {
|
|
1326
1334
|
allMappedCapsuleUris.add(capsuleName)
|
|
1327
1335
|
}
|
|
@@ -1332,19 +1340,19 @@ ${defaultExport}
|
|
|
1332
1340
|
const mappedCapsuleDeps: Array<{ uri: string, importName: string, importPath: string }> = []
|
|
1333
1341
|
for (const uri of allMappedCapsuleUris) {
|
|
1334
1342
|
const importName = `_capsule_${uri.replace(/[^a-zA-Z0-9]/g, '_')}`
|
|
1335
|
-
// Strip leading @
|
|
1343
|
+
// Strip leading @ to match caps filesystem paths
|
|
1336
1344
|
const importPath = uri.startsWith('@') ? uri.substring(1) : uri
|
|
1337
1345
|
mappedCapsuleDeps.push({ uri, importName, importPath })
|
|
1338
1346
|
}
|
|
1339
1347
|
|
|
1340
1348
|
// Generate static imports for all capsule dependencies
|
|
1341
|
-
// Compute relative path from projected file to
|
|
1349
|
+
// Compute relative path from projected file to caps directory
|
|
1342
1350
|
let importPrefix: string
|
|
1343
1351
|
if (capsuleModuleProjectionPackage) {
|
|
1344
1352
|
importPrefix = capsuleModuleProjectionPackage
|
|
1345
1353
|
} else {
|
|
1346
1354
|
const projectedFileDir = dirname(mapped.projectionPath)
|
|
1347
|
-
const capsDir = '.~caps'
|
|
1355
|
+
const capsDir = '.~o/encapsulate.dev/caps'
|
|
1348
1356
|
const relativePathToCaps = relative(projectedFileDir, capsDir)
|
|
1349
1357
|
importPrefix = relativePathToCaps.startsWith('.') ? relativePathToCaps : './' + relativePathToCaps
|
|
1350
1358
|
}
|
|
@@ -1475,7 +1483,9 @@ export default function({ onMembraneEvent }: { onMembraneEvent?: (event: any) =>
|
|
|
1475
1483
|
const refTyped = ref as any
|
|
1476
1484
|
if (refTyped.type === 'capsule') {
|
|
1477
1485
|
const snapshot = await buildCapsuleSnapshotForReference(refTyped, capsules, spineContractUri)
|
|
1478
|
-
const
|
|
1486
|
+
const contractData = snapshot.spineContracts?.[spineContractUri]
|
|
1487
|
+
const structKey = Object.keys(contractData || {}).find(k => k.includes('/structs/Capsule'))
|
|
1488
|
+
const capsuleName = structKey ? contractData[structKey]?.capsuleName : undefined
|
|
1479
1489
|
if (capsuleName) {
|
|
1480
1490
|
allMappedCapsuleUris.add(capsuleName)
|
|
1481
1491
|
}
|
|
@@ -1486,19 +1496,19 @@ export default function({ onMembraneEvent }: { onMembraneEvent?: (event: any) =>
|
|
|
1486
1496
|
const mappedCapsuleDeps: Array<{ uri: string, importName: string, importPath: string }> = []
|
|
1487
1497
|
for (const uri of allMappedCapsuleUris) {
|
|
1488
1498
|
const importName = `_capsule_${uri.replace(/[^a-zA-Z0-9]/g, '_')}`
|
|
1489
|
-
// Strip leading @
|
|
1499
|
+
// Strip leading @ to match caps filesystem paths
|
|
1490
1500
|
const importPath = uri.startsWith('@') ? uri.substring(1) : uri
|
|
1491
1501
|
mappedCapsuleDeps.push({ uri, importName, importPath })
|
|
1492
1502
|
}
|
|
1493
1503
|
|
|
1494
1504
|
// Generate static imports for all capsule dependencies
|
|
1495
|
-
// Compute relative path from projected file to
|
|
1505
|
+
// Compute relative path from projected file to caps directory
|
|
1496
1506
|
let importPrefix: string
|
|
1497
1507
|
if (capsuleModuleProjectionPackage) {
|
|
1498
1508
|
importPrefix = capsuleModuleProjectionPackage
|
|
1499
1509
|
} else {
|
|
1500
1510
|
const projectedFileDir = dirname(mapped.projectionPath)
|
|
1501
|
-
const capsDir = '.~caps'
|
|
1511
|
+
const capsDir = '.~o/encapsulate.dev/caps'
|
|
1502
1512
|
const relativePathToCaps = relative(projectedFileDir, capsDir)
|
|
1503
1513
|
importPrefix = relativePathToCaps.startsWith('.') ? relativePathToCaps : './' + relativePathToCaps
|
|
1504
1514
|
}
|
|
@@ -1628,7 +1638,7 @@ ${mappedDefaultExport}
|
|
|
1628
1638
|
}
|
|
1629
1639
|
}
|
|
1630
1640
|
|
|
1631
|
-
// Write projection cache AND project ALL capsules in the registry to .~caps
|
|
1641
|
+
// Write projection cache AND project ALL capsules in the registry to .~o/encapsulate.dev/caps
|
|
1632
1642
|
// This includes struct definitions, property contract capsules, and any other capsules
|
|
1633
1643
|
if (projectionCacheStore?.writeFile && capsules) {
|
|
1634
1644
|
for (const [capsuleKey, registryCapsule] of Object.entries(capsules)) {
|
|
@@ -1655,7 +1665,7 @@ ${mappedDefaultExport}
|
|
|
1655
1665
|
}
|
|
1656
1666
|
await projectionCacheStore.writeFile(capsuleCacheFilename, JSON.stringify(capsuleCacheData, null, 2))
|
|
1657
1667
|
|
|
1658
|
-
// Also project the capsule to .~caps
|
|
1668
|
+
// Also project the capsule to .~o/encapsulate.dev/caps
|
|
1659
1669
|
const projectedPath = capsuleCacheData.snapshotData.spineContracts[spineContractUri]['#@stream44.studio/encapsulate/structs/Capsule'].projectedCapsuleFilepath
|
|
1660
1670
|
|
|
1661
1671
|
// Generate the capsule file content with proper imports and ambient reference loading
|
package/src/encapsulate.ts
CHANGED
|
@@ -1,4 +1,8 @@
|
|
|
1
1
|
|
|
2
|
+
// CACHE_BUST_VERSION: Increment this whenever CST cache must be invalidated due to structural changes
|
|
3
|
+
// This ensures projected capsules are regenerated when the CST format changes
|
|
4
|
+
const CACHE_BUST_VERSION = 9
|
|
5
|
+
|
|
2
6
|
type TSpineOptions = {
|
|
3
7
|
spineFilesystemRoot?: string,
|
|
4
8
|
spineContracts: Record<string, any>,
|
|
@@ -32,7 +36,7 @@ type TSpineRuntimeOptions = {
|
|
|
32
36
|
spineContracts?: Record<string, any>,
|
|
33
37
|
snapshot?: TSpineSnapshot,
|
|
34
38
|
capsules?: Record<string, any>,
|
|
35
|
-
loadCapsule?: (options: { capsuleSourceLineRef: string, capsuleSnapshot: any, capsuleName?: string }) => Promise<any>
|
|
39
|
+
loadCapsule?: (options: { capsuleSourceLineRef: string, capsuleSnapshot: any, capsuleName?: string, cacheBustVersion?: number }) => Promise<any>
|
|
36
40
|
}
|
|
37
41
|
|
|
38
42
|
type TCapsuleSnapshot = {
|
|
@@ -44,7 +48,12 @@ type TCapsuleMakeInstanceOptions = {
|
|
|
44
48
|
overrides?: Record<string, any>,
|
|
45
49
|
options?: Record<string, any>,
|
|
46
50
|
runtimeSpineContracts?: Record<string, any>,
|
|
47
|
-
sharedSelf?: Record<string, any
|
|
51
|
+
sharedSelf?: Record<string, any>,
|
|
52
|
+
rootCapsule?: {
|
|
53
|
+
capsuleName: string,
|
|
54
|
+
capsuleSourceLineRef: string,
|
|
55
|
+
moduleFilepath: string
|
|
56
|
+
}
|
|
48
57
|
}
|
|
49
58
|
|
|
50
59
|
type TCapsule = {
|
|
@@ -97,6 +106,7 @@ export const CapsulePropertyTypes = {
|
|
|
97
106
|
String: 'String' as const,
|
|
98
107
|
Mapping: 'Mapping' as const,
|
|
99
108
|
Literal: 'Literal' as const,
|
|
109
|
+
Constant: 'Constant' as const,
|
|
100
110
|
StructInit: 'StructInit' as const,
|
|
101
111
|
}
|
|
102
112
|
|
|
@@ -299,9 +309,19 @@ export async function SpineRuntime(options: TSpineRuntimeOptions): Promise<TSpin
|
|
|
299
309
|
const capsule = await options.loadCapsule!({
|
|
300
310
|
capsuleSourceLineRef,
|
|
301
311
|
capsuleSnapshot,
|
|
302
|
-
capsuleName
|
|
312
|
+
capsuleName,
|
|
313
|
+
cacheBustVersion: CACHE_BUST_VERSION
|
|
303
314
|
})
|
|
304
315
|
|
|
316
|
+
// If loadCapsule returns null, it means cache bust version mismatch - regenerate the capsule
|
|
317
|
+
if (capsule === null) {
|
|
318
|
+
throw new Error(
|
|
319
|
+
`Cache bust version mismatch for capsule '${capsuleSourceLineRef}'. ` +
|
|
320
|
+
`Expected version ${CACHE_BUST_VERSION} but found ${(capsuleSnapshot as any).cst?.cacheBustVersion}. ` +
|
|
321
|
+
`Please delete the cache directory and regenerate capsules.`
|
|
322
|
+
)
|
|
323
|
+
}
|
|
324
|
+
|
|
305
325
|
loadedCapsules[capsuleSourceLineRef] = await capsule({
|
|
306
326
|
encapsulate: spine.encapsulate,
|
|
307
327
|
CapsulePropertyTypes,
|
|
@@ -392,28 +412,59 @@ async function encapsulate(definition: TCapsuleDefinition, options: TCapsuleOpti
|
|
|
392
412
|
if (!options.importMeta && !options.moduleFilepath) throw new Error(`'options.importMeta' nor 'options.moduleFilepath' not specified!`)
|
|
393
413
|
if (!options.importStack && !options.importStackLine) throw new Error(`'options.importStack' nor 'options.importStackLine' specified!`)
|
|
394
414
|
|
|
395
|
-
|
|
415
|
+
// Use relative path for internal processing, but store absolute path for metadata
|
|
416
|
+
const providedPath = options.moduleFilepath || options.importMeta!.url.replace(/^file:\/\//, '')
|
|
417
|
+
const spineRoot = spine.spineOptions.spineFilesystemRoot || ''
|
|
418
|
+
|
|
419
|
+
// Determine if we need to make the path absolute
|
|
420
|
+
let absoluteModuleFilepath: string
|
|
421
|
+
if (providedPath.startsWith('/')) {
|
|
422
|
+
// Already an absolute path (starts with /)
|
|
423
|
+
absoluteModuleFilepath = providedPath
|
|
424
|
+
} else if (spineRoot) {
|
|
425
|
+
// Relative path - make it absolute by joining with spine root
|
|
426
|
+
absoluteModuleFilepath = join(spineRoot, providedPath)
|
|
427
|
+
} else {
|
|
428
|
+
// No spine root and path is relative - use as-is (will remain relative)
|
|
429
|
+
// Note: This happens when SpineRuntime doesn't pass spineFilesystemRoot through
|
|
430
|
+
absoluteModuleFilepath = providedPath
|
|
431
|
+
}
|
|
432
|
+
|
|
433
|
+
const moduleFilepath = relative(spineRoot, absoluteModuleFilepath)
|
|
396
434
|
const importStackLine = options.importStackLine || formatImportStackFrame(options.importStack!)
|
|
397
435
|
|
|
398
436
|
if (typeof importStackLine !== 'number') throw new Error(`Could not determine importStackLine from options`)
|
|
399
437
|
|
|
400
|
-
const
|
|
401
|
-
moduleFilepath,
|
|
402
|
-
importStackLine,
|
|
403
|
-
capsuleName: options.capsuleName,
|
|
404
|
-
ambientReferences: options.ambientReferences,
|
|
405
|
-
extendsCapsule: options.extendsCapsule,
|
|
406
|
-
capsuleSourceLineRef: `${moduleFilepath}:${importStackLine}`
|
|
407
|
-
}
|
|
438
|
+
const capsuleSourceLineRef = `${moduleFilepath}:${importStackLine}`
|
|
408
439
|
|
|
409
440
|
spine.spineOptions.timing?.record(`Encapsulate: Start for ${moduleFilepath}`)
|
|
410
441
|
|
|
411
442
|
const { csts, crts } = await spine.spineOptions.staticAnalyzer?.parseModule({
|
|
412
443
|
spineOptions: spine.spineOptions,
|
|
413
|
-
encapsulateOptions
|
|
444
|
+
encapsulateOptions: {
|
|
445
|
+
moduleFilepath,
|
|
446
|
+
importStackLine,
|
|
447
|
+
capsuleSourceLineRef,
|
|
448
|
+
capsuleName: options.capsuleName,
|
|
449
|
+
ambientReferences: options.ambientReferences,
|
|
450
|
+
cacheBustVersion: CACHE_BUST_VERSION
|
|
451
|
+
}
|
|
414
452
|
}) || {
|
|
415
|
-
csts: options.cst ? { [
|
|
416
|
-
crts: options.crt ? { [
|
|
453
|
+
csts: options.cst ? { [capsuleSourceLineRef]: options.cst } : undefined,
|
|
454
|
+
crts: options.crt ? { [capsuleSourceLineRef]: options.crt } : undefined
|
|
455
|
+
}
|
|
456
|
+
|
|
457
|
+
// Get capsuleName from options first, then fall back to CST if available
|
|
458
|
+
const cst = csts?.[capsuleSourceLineRef]
|
|
459
|
+
const capsuleName = options.capsuleName || cst?.source?.capsuleName
|
|
460
|
+
|
|
461
|
+
const encapsulateOptions: TEncapsulateOptions = {
|
|
462
|
+
moduleFilepath,
|
|
463
|
+
importStackLine,
|
|
464
|
+
capsuleName,
|
|
465
|
+
ambientReferences: options.ambientReferences,
|
|
466
|
+
extendsCapsule: options.extendsCapsule,
|
|
467
|
+
capsuleSourceLineRef
|
|
417
468
|
}
|
|
418
469
|
|
|
419
470
|
const defaultInstance: Record<string, any> = {}
|
|
@@ -431,9 +482,9 @@ async function encapsulate(definition: TCapsuleDefinition, options: TCapsuleOpti
|
|
|
431
482
|
capsuleSourceLineRef: encapsulateOptions.capsuleSourceLineRef,
|
|
432
483
|
definition,
|
|
433
484
|
encapsulateOptions,
|
|
434
|
-
cst
|
|
435
|
-
crt: crts?.[
|
|
436
|
-
makeInstance: async ({ overrides = {}, options = {}, runtimeSpineContracts, sharedSelf }: TCapsuleMakeInstanceOptions = {}) => {
|
|
485
|
+
cst,
|
|
486
|
+
crt: crts?.[capsuleSourceLineRef],
|
|
487
|
+
makeInstance: async ({ overrides = {}, options = {}, runtimeSpineContracts, sharedSelf, rootCapsule }: TCapsuleMakeInstanceOptions = {}) => {
|
|
437
488
|
|
|
438
489
|
// Create cache key based on parameters
|
|
439
490
|
// When sharedSelf is provided, we must NOT cache because each extending capsule
|
|
@@ -593,6 +644,22 @@ async function encapsulate(definition: TCapsuleDefinition, options: TCapsuleOpti
|
|
|
593
644
|
// The selfProxy in spine contracts will expose this as 'self' property
|
|
594
645
|
const ownSelf = merge({}, defaultInstance, defaultPropertyValues, ...Object.values(mergedValuesByContract))
|
|
595
646
|
|
|
647
|
+
// Capsule metadata struct will be set on self/ownSelf AFTER spine contract processing
|
|
648
|
+
// to avoid being overwritten by the empty struct marker in the definition
|
|
649
|
+
// Convert relative paths to absolute for metadata exposure
|
|
650
|
+
const absoluteCapsuleSourceLineRef = `${absoluteModuleFilepath}:${importStackLine}`
|
|
651
|
+
const capsuleMetadataStruct = {
|
|
652
|
+
capsuleName: encapsulateOptions.capsuleName,
|
|
653
|
+
capsuleSourceLineRef: absoluteCapsuleSourceLineRef,
|
|
654
|
+
moduleFilepath: absoluteModuleFilepath,
|
|
655
|
+
// Root capsule metadata will be populated after extends chain is resolved
|
|
656
|
+
rootCapsule: {
|
|
657
|
+
capsuleName: undefined as string | undefined,
|
|
658
|
+
capsuleSourceLineRef: undefined as string | undefined,
|
|
659
|
+
moduleFilepath: undefined as string | undefined
|
|
660
|
+
}
|
|
661
|
+
}
|
|
662
|
+
|
|
596
663
|
// Initialize extended capsule instance if this capsule extends another
|
|
597
664
|
// Pass our self so extended capsule's functions bind to the same context
|
|
598
665
|
let extendedCapsuleInstance: any = undefined
|
|
@@ -657,16 +724,34 @@ async function encapsulate(definition: TCapsuleDefinition, options: TCapsuleOpti
|
|
|
657
724
|
overrides,
|
|
658
725
|
options,
|
|
659
726
|
runtimeSpineContracts,
|
|
660
|
-
sharedSelf: self
|
|
727
|
+
sharedSelf: self,
|
|
728
|
+
rootCapsule: rootCapsule || {
|
|
729
|
+
capsuleName: encapsulateOptions.capsuleName!,
|
|
730
|
+
capsuleSourceLineRef: absoluteCapsuleSourceLineRef,
|
|
731
|
+
moduleFilepath: absoluteModuleFilepath
|
|
732
|
+
}
|
|
661
733
|
})
|
|
662
734
|
}
|
|
663
735
|
|
|
736
|
+
// Resolve the root capsule for this instance:
|
|
737
|
+
// If rootCapsule was passed down from a parent, use it (preserves the first capsule in the chain).
|
|
738
|
+
// Otherwise this capsule IS the root.
|
|
739
|
+
const resolvedRootCapsule = rootCapsule || {
|
|
740
|
+
capsuleName: encapsulateOptions.capsuleName!,
|
|
741
|
+
capsuleSourceLineRef: absoluteCapsuleSourceLineRef,
|
|
742
|
+
moduleFilepath: absoluteModuleFilepath
|
|
743
|
+
}
|
|
744
|
+
capsuleMetadataStruct.rootCapsule.capsuleName = resolvedRootCapsule.capsuleName
|
|
745
|
+
capsuleMetadataStruct.rootCapsule.capsuleSourceLineRef = resolvedRootCapsule.capsuleSourceLineRef
|
|
746
|
+
capsuleMetadataStruct.rootCapsule.moduleFilepath = resolvedRootCapsule.moduleFilepath
|
|
747
|
+
|
|
664
748
|
const capsuleInstance: any = {
|
|
665
749
|
api: encapsulatedApi,
|
|
666
750
|
spineContractCapsuleInstances,
|
|
667
751
|
extendedCapsuleInstance,
|
|
668
752
|
structInitFunctions: [] as Array<() => any>,
|
|
669
|
-
mappedCapsuleInstances: [] as Array<any
|
|
753
|
+
mappedCapsuleInstances: [] as Array<any>,
|
|
754
|
+
rootCapsule: resolvedRootCapsule
|
|
670
755
|
}
|
|
671
756
|
|
|
672
757
|
// Use runtime spine contracts if provided, otherwise fall back to encapsulation spine contracts
|
|
@@ -715,6 +800,15 @@ async function encapsulate(definition: TCapsuleDefinition, options: TCapsuleOpti
|
|
|
715
800
|
}
|
|
716
801
|
}
|
|
717
802
|
|
|
803
|
+
// Set capsule metadata struct on self/ownSelf AFTER spine contract processing
|
|
804
|
+
// to avoid being overwritten by the empty struct marker in the definition
|
|
805
|
+
if (!self['#@stream44.studio/encapsulate/structs/Capsule'] ||
|
|
806
|
+
typeof self['#@stream44.studio/encapsulate/structs/Capsule'] !== 'object' ||
|
|
807
|
+
!self['#@stream44.studio/encapsulate/structs/Capsule'].capsuleName) {
|
|
808
|
+
self['#@stream44.studio/encapsulate/structs/Capsule'] = capsuleMetadataStruct
|
|
809
|
+
}
|
|
810
|
+
ownSelf['#@stream44.studio/encapsulate/structs/Capsule'] = capsuleMetadataStruct
|
|
811
|
+
|
|
718
812
|
// Collect StructInit functions and mapped capsule instances from all spine contract capsule instances
|
|
719
813
|
for (const spineContractCapsuleInstance of Object.values(spineContractCapsuleInstances)) {
|
|
720
814
|
const sci = spineContractCapsuleInstance as any
|
|
@@ -80,7 +80,8 @@ class MembraneContractCapsuleInstanceFactory extends ContractCapsuleInstanceFact
|
|
|
80
80
|
currentCallerContext,
|
|
81
81
|
runtimeSpineContracts,
|
|
82
82
|
instanceRegistry,
|
|
83
|
-
extendedCapsuleInstance
|
|
83
|
+
extendedCapsuleInstance,
|
|
84
|
+
capsuleInstance
|
|
84
85
|
}: {
|
|
85
86
|
spineContractUri: string
|
|
86
87
|
capsule: any
|
|
@@ -100,8 +101,9 @@ class MembraneContractCapsuleInstanceFactory extends ContractCapsuleInstanceFact
|
|
|
100
101
|
runtimeSpineContracts?: Record<string, any>
|
|
101
102
|
instanceRegistry?: CapsuleInstanceRegistry
|
|
102
103
|
extendedCapsuleInstance?: any
|
|
104
|
+
capsuleInstance?: any
|
|
103
105
|
}) {
|
|
104
|
-
super({ spineContractUri, capsule, self, ownSelf, encapsulatedApi, resolve, importCapsule, spineFilesystemRoot, freezeCapsule, instanceRegistry, extendedCapsuleInstance })
|
|
106
|
+
super({ spineContractUri, capsule, self, ownSelf, encapsulatedApi, resolve, importCapsule, spineFilesystemRoot, freezeCapsule, instanceRegistry, extendedCapsuleInstance, capsuleInstance })
|
|
105
107
|
this.getEventIndex = getEventIndex
|
|
106
108
|
this.incrementEventIndex = incrementEventIndex
|
|
107
109
|
this.currentCallerContext = currentCallerContext
|
|
@@ -230,7 +232,8 @@ class MembraneContractCapsuleInstanceFactory extends ContractCapsuleInstanceFact
|
|
|
230
232
|
const mappedCapsuleInstance = await mappedCapsule.makeInstance({
|
|
231
233
|
overrides: mappedOverrides,
|
|
232
234
|
options: mappingOptions,
|
|
233
|
-
runtimeSpineContracts: this.runtimeSpineContracts
|
|
235
|
+
runtimeSpineContracts: this.runtimeSpineContracts,
|
|
236
|
+
rootCapsule: this.capsuleInstance?.rootCapsule
|
|
234
237
|
})
|
|
235
238
|
|
|
236
239
|
// Register the instance (replaces null pre-registration marker)
|
|
@@ -344,6 +347,8 @@ class MembraneContractCapsuleInstanceFactory extends ContractCapsuleInstanceFact
|
|
|
344
347
|
}
|
|
345
348
|
|
|
346
349
|
protected mapLiteralProperty({ property }: { property: any }) {
|
|
350
|
+
// Constant properties are read-only and throw on set
|
|
351
|
+
const isConstant = property.definition.type === CapsulePropertyTypes.Constant
|
|
347
352
|
|
|
348
353
|
const value = typeof this.self[property.name] !== 'undefined'
|
|
349
354
|
? this.self[property.name]
|
|
@@ -388,6 +393,11 @@ class MembraneContractCapsuleInstanceFactory extends ContractCapsuleInstanceFact
|
|
|
388
393
|
return currentValue
|
|
389
394
|
},
|
|
390
395
|
set: (newValue) => {
|
|
396
|
+
// Constant properties cannot be set
|
|
397
|
+
if (isConstant) {
|
|
398
|
+
throw new Error(`Cannot set constant property '${property.name}'`)
|
|
399
|
+
}
|
|
400
|
+
|
|
391
401
|
const event: any = {
|
|
392
402
|
event: 'set',
|
|
393
403
|
eventIndex: this.incrementEventIndex(),
|
|
@@ -585,7 +595,7 @@ export function CapsuleSpineContract({
|
|
|
585
595
|
return {
|
|
586
596
|
'#': CapsuleSpineContract['#'],
|
|
587
597
|
instanceRegistry,
|
|
588
|
-
makeContractCapsuleInstance: ({ encapsulateOptions, spineContractUri, self, ownSelf, capsule, encapsulatedApi, runtimeSpineContracts, extendedCapsuleInstance }: { encapsulateOptions: any, spineContractUri: string, self: any, ownSelf?: any, capsule?: any, encapsulatedApi: Record<string, any>, runtimeSpineContracts?: Record<string, any>, extendedCapsuleInstance?: any }) => {
|
|
598
|
+
makeContractCapsuleInstance: ({ encapsulateOptions, spineContractUri, self, ownSelf, capsule, encapsulatedApi, runtimeSpineContracts, extendedCapsuleInstance, capsuleInstance }: { encapsulateOptions: any, spineContractUri: string, self: any, ownSelf?: any, capsule?: any, encapsulatedApi: Record<string, any>, runtimeSpineContracts?: Record<string, any>, extendedCapsuleInstance?: any, capsuleInstance?: any }) => {
|
|
589
599
|
return new MembraneContractCapsuleInstanceFactory({
|
|
590
600
|
spineContractUri,
|
|
591
601
|
capsule,
|
|
@@ -604,7 +614,8 @@ export function CapsuleSpineContract({
|
|
|
604
614
|
currentCallerContext,
|
|
605
615
|
runtimeSpineContracts,
|
|
606
616
|
instanceRegistry,
|
|
607
|
-
extendedCapsuleInstance
|
|
617
|
+
extendedCapsuleInstance,
|
|
618
|
+
capsuleInstance
|
|
608
619
|
})
|
|
609
620
|
},
|
|
610
621
|
hydrate: ({ capsuleSnapshot }: { capsuleSnapshot: any }): any => {
|
|
@@ -17,10 +17,11 @@ export class ContractCapsuleInstanceFactory {
|
|
|
17
17
|
protected extendedCapsuleInstance?: any
|
|
18
18
|
protected ownSelf?: any
|
|
19
19
|
protected runtimeSpineContracts?: Record<string, any>
|
|
20
|
+
protected capsuleInstance?: any
|
|
20
21
|
public structInitFunctions: Array<() => any> = []
|
|
21
22
|
public mappedCapsuleInstances: Array<any> = []
|
|
22
23
|
|
|
23
|
-
constructor({ spineContractUri, capsule, self, ownSelf, encapsulatedApi, resolve, importCapsule, spineFilesystemRoot, freezeCapsule, instanceRegistry, extendedCapsuleInstance, runtimeSpineContracts }: { spineContractUri: string, capsule: any, self: any, ownSelf?: any, encapsulatedApi: Record<string, any>, resolve?: (uri: string, parentFilepath: string) => Promise<string>, importCapsule?: (filepath: string) => Promise<any>, spineFilesystemRoot?: string, freezeCapsule?: (capsule: any) => Promise<any>, instanceRegistry?: CapsuleInstanceRegistry, extendedCapsuleInstance?: any, runtimeSpineContracts?: Record<string, any
|
|
24
|
+
constructor({ spineContractUri, capsule, self, ownSelf, encapsulatedApi, resolve, importCapsule, spineFilesystemRoot, freezeCapsule, instanceRegistry, extendedCapsuleInstance, runtimeSpineContracts, capsuleInstance }: { spineContractUri: string, capsule: any, self: any, ownSelf?: any, encapsulatedApi: Record<string, any>, resolve?: (uri: string, parentFilepath: string) => Promise<string>, importCapsule?: (filepath: string) => Promise<any>, spineFilesystemRoot?: string, freezeCapsule?: (capsule: any) => Promise<any>, instanceRegistry?: CapsuleInstanceRegistry, extendedCapsuleInstance?: any, runtimeSpineContracts?: Record<string, any>, capsuleInstance?: any }) {
|
|
24
25
|
this.spineContractUri = spineContractUri
|
|
25
26
|
this.capsule = capsule
|
|
26
27
|
this.self = self
|
|
@@ -33,6 +34,7 @@ export class ContractCapsuleInstanceFactory {
|
|
|
33
34
|
this.instanceRegistry = instanceRegistry
|
|
34
35
|
this.extendedCapsuleInstance = extendedCapsuleInstance
|
|
35
36
|
this.runtimeSpineContracts = runtimeSpineContracts
|
|
37
|
+
this.capsuleInstance = capsuleInstance
|
|
36
38
|
}
|
|
37
39
|
|
|
38
40
|
async mapProperty({ overrides, options, property }: { overrides: any, options: any, property: any }) {
|
|
@@ -40,7 +42,8 @@ export class ContractCapsuleInstanceFactory {
|
|
|
40
42
|
await this.mapMappingProperty({ overrides, options, property })
|
|
41
43
|
} else if (
|
|
42
44
|
property.definition.type === CapsulePropertyTypes.String ||
|
|
43
|
-
property.definition.type === CapsulePropertyTypes.Literal
|
|
45
|
+
property.definition.type === CapsulePropertyTypes.Literal ||
|
|
46
|
+
property.definition.type === CapsulePropertyTypes.Constant
|
|
44
47
|
) {
|
|
45
48
|
this.mapLiteralProperty({ property })
|
|
46
49
|
} else if (property.definition.type === CapsulePropertyTypes.Function) {
|
|
@@ -226,7 +229,8 @@ export class ContractCapsuleInstanceFactory {
|
|
|
226
229
|
const mappedInstance = await mappedCapsule.makeInstance({
|
|
227
230
|
overrides: mappedOverrides,
|
|
228
231
|
options: mappingOptions,
|
|
229
|
-
runtimeSpineContracts: this.runtimeSpineContracts
|
|
232
|
+
runtimeSpineContracts: this.runtimeSpineContracts,
|
|
233
|
+
rootCapsule: this.capsuleInstance?.rootCapsule
|
|
230
234
|
})
|
|
231
235
|
|
|
232
236
|
// Register the instance (replaces null pre-registration marker)
|
|
@@ -369,7 +373,7 @@ export function CapsuleSpineContract({ freezeCapsule, resolve, importCapsule, sp
|
|
|
369
373
|
return {
|
|
370
374
|
'#': CapsuleSpineContract['#'],
|
|
371
375
|
instanceRegistry,
|
|
372
|
-
makeContractCapsuleInstance: ({ spineContractUri, capsule, self, ownSelf, encapsulatedApi, extendedCapsuleInstance, runtimeSpineContracts }: { spineContractUri: string, capsule: any, self: any, ownSelf?: any, encapsulatedApi: Record<string, any>, extendedCapsuleInstance?: any, runtimeSpineContracts?: Record<string, any
|
|
376
|
+
makeContractCapsuleInstance: ({ spineContractUri, capsule, self, ownSelf, encapsulatedApi, extendedCapsuleInstance, runtimeSpineContracts, capsuleInstance }: { spineContractUri: string, capsule: any, self: any, ownSelf?: any, encapsulatedApi: Record<string, any>, extendedCapsuleInstance?: any, runtimeSpineContracts?: Record<string, any>, capsuleInstance?: any }) => {
|
|
373
377
|
return new ContractCapsuleInstanceFactory({
|
|
374
378
|
spineContractUri,
|
|
375
379
|
capsule,
|
|
@@ -382,7 +386,8 @@ export function CapsuleSpineContract({ freezeCapsule, resolve, importCapsule, sp
|
|
|
382
386
|
freezeCapsule,
|
|
383
387
|
instanceRegistry,
|
|
384
388
|
extendedCapsuleInstance,
|
|
385
|
-
runtimeSpineContracts
|
|
389
|
+
runtimeSpineContracts,
|
|
390
|
+
capsuleInstance
|
|
386
391
|
})
|
|
387
392
|
},
|
|
388
393
|
hydrate: ({ capsuleSnapshot }: { capsuleSnapshot: any }): any => {
|
|
@@ -499,7 +499,7 @@ export async function CapsuleSpineFactory({
|
|
|
499
499
|
|
|
500
500
|
timing?.recordMajor('CAPSULE SPINE FACTORY: READY')
|
|
501
501
|
|
|
502
|
-
const loadCapsule = async ({ capsuleSnapshot }: { capsuleSourceLineRef: string, capsuleSnapshot: any }) => {
|
|
502
|
+
const loadCapsule = async ({ capsuleSnapshot, cacheBustVersion }: { capsuleSourceLineRef: string, capsuleSnapshot: any, cacheBustVersion?: number }) => {
|
|
503
503
|
|
|
504
504
|
if (!capsuleModuleProjectionRoot) {
|
|
505
505
|
throw new Error('capsuleModuleProjectionRoot must be provided to enable dynamic loading of capsules')
|
|
@@ -509,6 +509,11 @@ export async function CapsuleSpineFactory({
|
|
|
509
509
|
|
|
510
510
|
if (!filepath) throw new Error(`Cannot load capsule. No 'filepath' found at 'spineContracts["#@stream44.studio/encapsulate/spine-contracts/CapsuleSpineContract.v0"]["#@stream44.studio/encapsulate/structs/Capsule"].projectedCapsuleFilepath'!`)
|
|
511
511
|
|
|
512
|
+
// Check cache bust version - if it doesn't match, return null to trigger regeneration
|
|
513
|
+
if (cacheBustVersion !== undefined && capsuleSnapshot.cst?.cacheBustVersion !== cacheBustVersion) {
|
|
514
|
+
return null
|
|
515
|
+
}
|
|
516
|
+
|
|
512
517
|
const { capsule } = await import(join(capsuleModuleProjectionRoot, filepath))
|
|
513
518
|
|
|
514
519
|
return capsule
|
|
@@ -529,6 +534,7 @@ export async function CapsuleSpineFactory({
|
|
|
529
534
|
|
|
530
535
|
const result = await SpineRuntime({
|
|
531
536
|
snapshot,
|
|
537
|
+
spineFilesystemRoot,
|
|
532
538
|
spineContracts: spineContractInstances.runtime,
|
|
533
539
|
loadCapsule
|
|
534
540
|
})
|
|
@@ -235,10 +235,18 @@ export function StaticAnalyzer({
|
|
|
235
235
|
])
|
|
236
236
|
|
|
237
237
|
if (cstsContent && crtsContent) {
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
238
|
+
const cachedCsts = JSON.parse(cstsContent)
|
|
239
|
+
|
|
240
|
+
// Check cache bust version - if mismatch, regenerate
|
|
241
|
+
const cachedVersion = cachedCsts?.[capsuleSourceLineRef]?.cacheBustVersion
|
|
242
|
+
if (encapsulateOptions.cacheBustVersion !== undefined && cachedVersion !== encapsulateOptions.cacheBustVersion) {
|
|
243
|
+
timing?.record(timing?.chalk?.red?.(`StaticAnalyzer: Cache BUST (version mismatch: ${cachedVersion} !== ${encapsulateOptions.cacheBustVersion}) for ${encapsulateOptions.moduleFilepath}`))
|
|
244
|
+
} else {
|
|
245
|
+
timing?.record(`StaticAnalyzer: Cache HIT for ${encapsulateOptions.moduleFilepath}`)
|
|
246
|
+
return {
|
|
247
|
+
csts: cachedCsts,
|
|
248
|
+
crts: JSON.parse(crtsContent)
|
|
249
|
+
}
|
|
242
250
|
}
|
|
243
251
|
}
|
|
244
252
|
}
|
|
@@ -340,6 +348,7 @@ export function StaticAnalyzer({
|
|
|
340
348
|
)
|
|
341
349
|
|
|
342
350
|
const cst: any = {
|
|
351
|
+
cacheBustVersion: encapsulateOptions.cacheBustVersion || 1,
|
|
343
352
|
capsuleSourceLineRef,
|
|
344
353
|
capsuleSourceNameRef,
|
|
345
354
|
capsuleSourceNameRefHash,
|