alloy-di 1.2.3 → 1.3.0
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/dist/lib/env-detection.d.ts +24 -0
- package/dist/lib/env-detection.js +22 -9
- package/dist/plugins/core/codegen.js +81 -13
- package/dist/plugins/{vite-plugin → core}/container-loader.js +8 -8
- package/dist/plugins/{vite-plugin → core}/discovery-runtime.js +4 -14
- package/dist/plugins/core/discovery-store.js +15 -0
- package/dist/plugins/{vite-plugin → core}/manifest-utils.js +14 -4
- package/dist/plugins/core/scanner.js +12 -0
- package/dist/plugins/core/utils.js +45 -8
- package/dist/plugins/{vite-plugin → core}/visualization-utils.d.ts +1 -1
- package/dist/plugins/{vite-plugin → core}/visualization-utils.js +1 -1
- package/dist/plugins/{vite-plugin → core}/visualizer.d.ts +1 -1
- package/dist/plugins/{vite-plugin → core}/visualizer.js +24 -16
- package/dist/plugins/vite-plugin/index.d.ts +1 -1
- package/dist/plugins/vite-plugin/index.js +8 -4
- package/dist/plugins/vite-plugin/module-invalidation.js +13 -0
- package/dist/runtime.d.ts +2 -1
- package/dist/runtime.js +2 -1
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/package.json +1 -1
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
//#region src/lib/env-detection.d.ts
|
|
2
|
+
type ImportMetaEnvShape = {
|
|
3
|
+
MODE?: string;
|
|
4
|
+
PROD?: boolean;
|
|
5
|
+
NODE_ENV?: string;
|
|
6
|
+
[key: string]: unknown;
|
|
7
|
+
};
|
|
8
|
+
type EnvDetectionOverrides = {
|
|
9
|
+
/**
|
|
10
|
+
* Explicit import.meta.env replacement. Use `null` to force "no env" behavior.
|
|
11
|
+
*/
|
|
12
|
+
importMetaEnv?: ImportMetaEnvShape | null;
|
|
13
|
+
/**
|
|
14
|
+
* Explicit NODE_ENV replacement. Use `null` to ignore process.env.
|
|
15
|
+
*/
|
|
16
|
+
nodeEnv?: string | null;
|
|
17
|
+
/**
|
|
18
|
+
* Short-circuit the entire detection logic with a predetermined boolean.
|
|
19
|
+
*/
|
|
20
|
+
isDev?: boolean;
|
|
21
|
+
};
|
|
22
|
+
declare function setEnvDetectionOverrides(overrides: EnvDetectionOverrides | undefined): void;
|
|
23
|
+
//#endregion
|
|
24
|
+
export { EnvDetectionOverrides, setEnvDetectionOverrides };
|
|
@@ -2,11 +2,20 @@
|
|
|
2
2
|
function isRecord(value) {
|
|
3
3
|
return typeof value === "object" && value !== null;
|
|
4
4
|
}
|
|
5
|
+
/**
|
|
6
|
+
* Build-time-injected detection overrides.
|
|
7
|
+
*
|
|
8
|
+
* The Vite plugin emits a `setEnvDetectionOverrides({ isDev: ... })` call
|
|
9
|
+
* into the generated container module so detection in plugin-driven setups
|
|
10
|
+
* uses the bundler's authoritative mode instead of runtime sniffing.
|
|
11
|
+
*/
|
|
12
|
+
let injectedOverrides;
|
|
13
|
+
function setEnvDetectionOverrides(overrides) {
|
|
14
|
+
injectedOverrides = overrides;
|
|
15
|
+
}
|
|
5
16
|
function readImportMetaEnvFromRuntime() {
|
|
6
17
|
if (typeof import.meta === "undefined") return;
|
|
7
|
-
const
|
|
8
|
-
if (!isRecord(candidate) || !("env" in candidate)) return;
|
|
9
|
-
const envValue = candidate.env;
|
|
18
|
+
const envValue = import.meta.env;
|
|
10
19
|
if (!isRecord(envValue)) return;
|
|
11
20
|
const env = {};
|
|
12
21
|
if (typeof envValue.MODE === "string") env.MODE = envValue.MODE;
|
|
@@ -15,8 +24,11 @@ function readImportMetaEnvFromRuntime() {
|
|
|
15
24
|
return env;
|
|
16
25
|
}
|
|
17
26
|
function readProcessNodeEnv() {
|
|
18
|
-
|
|
19
|
-
|
|
27
|
+
try {
|
|
28
|
+
return "development";
|
|
29
|
+
} catch {
|
|
30
|
+
return;
|
|
31
|
+
}
|
|
20
32
|
}
|
|
21
33
|
function getImportMetaEnv(overrides) {
|
|
22
34
|
if (overrides?.importMetaEnv === null) return;
|
|
@@ -29,14 +41,15 @@ function getNodeEnv(overrides) {
|
|
|
29
41
|
return readProcessNodeEnv();
|
|
30
42
|
}
|
|
31
43
|
function isDevEnvironment(overrides) {
|
|
32
|
-
|
|
33
|
-
|
|
44
|
+
const effective = overrides ?? injectedOverrides;
|
|
45
|
+
if (typeof effective?.isDev === "boolean") return effective.isDev;
|
|
46
|
+
const nodeEnv = getNodeEnv(effective);
|
|
34
47
|
if (typeof nodeEnv === "string") return nodeEnv !== "production";
|
|
35
|
-
const importMetaEnv = getImportMetaEnv(
|
|
48
|
+
const importMetaEnv = getImportMetaEnv(effective);
|
|
36
49
|
if (typeof importMetaEnv?.PROD === "boolean") return !importMetaEnv.PROD;
|
|
37
50
|
if (typeof importMetaEnv?.MODE === "string") return importMetaEnv.MODE !== "production";
|
|
38
51
|
if (typeof importMetaEnv?.NODE_ENV === "string") return importMetaEnv.NODE_ENV !== "production";
|
|
39
52
|
return true;
|
|
40
53
|
}
|
|
41
54
|
//#endregion
|
|
42
|
-
export { isDevEnvironment };
|
|
55
|
+
export { isDevEnvironment, setEnvDetectionOverrides };
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { createClassKey, createSymbolKey, hashString, normalizeImportPath } from "./utils.js";
|
|
2
2
|
import { IdentifierResolver } from "./identifier-resolver.js";
|
|
3
3
|
import path from "node:path";
|
|
4
|
+
import ts from "typescript";
|
|
4
5
|
//#region src/plugins/core/codegen.ts
|
|
5
6
|
function escapeSingleQuotes(value) {
|
|
6
7
|
return value.replaceAll("'", "\\'");
|
|
@@ -91,12 +92,72 @@ function resolveDependencyImports(metas, pool, serviceBindings, runtimeImports)
|
|
|
91
92
|
importMap
|
|
92
93
|
};
|
|
93
94
|
}
|
|
95
|
+
/**
|
|
96
|
+
* True when an identifier occupies a name position rather than referencing a
|
|
97
|
+
* binding: property-access names (`ns.Api`), object keys — including method
|
|
98
|
+
* and accessor keys (`{ Api() {} }`, `{ get Api() {} }`) — class member
|
|
99
|
+
* names, qualified names, and destructuring property names.
|
|
100
|
+
*/
|
|
101
|
+
function isNonReferencePosition(node) {
|
|
102
|
+
const parent = node.parent;
|
|
103
|
+
if (ts.isPropertyAccessExpression(parent)) return parent.name === node;
|
|
104
|
+
if (ts.isQualifiedName(parent)) return parent.right === node;
|
|
105
|
+
if (ts.isBindingElement(parent)) return parent.propertyName === node;
|
|
106
|
+
if (ts.isPropertyAssignment(parent) || ts.isMethodDeclaration(parent) || ts.isGetAccessorDeclaration(parent) || ts.isSetAccessorDeclaration(parent) || ts.isPropertyDeclaration(parent) || ts.isMethodSignature(parent) || ts.isPropertySignature(parent)) return parent.name === node;
|
|
107
|
+
return false;
|
|
108
|
+
}
|
|
109
|
+
/**
|
|
110
|
+
* Decide how to rewrite one identifier node, or skip it.
|
|
111
|
+
*
|
|
112
|
+
* Only binding references are rewritten: name positions and string/comment
|
|
113
|
+
* content keep their text. Shorthand properties expand
|
|
114
|
+
* (`{ Api }` -> `{ Api: Api_1 }`) so the key survives the rename.
|
|
115
|
+
*/
|
|
116
|
+
function createIdentifierEdit(node, source, replacement) {
|
|
117
|
+
const parent = node.parent;
|
|
118
|
+
if (isNonReferencePosition(node)) return;
|
|
119
|
+
const start = node.getStart(source);
|
|
120
|
+
if (ts.isShorthandPropertyAssignment(parent) && parent.name === node) return {
|
|
121
|
+
start,
|
|
122
|
+
end: node.end,
|
|
123
|
+
text: `${node.text}: ${replacement}`
|
|
124
|
+
};
|
|
125
|
+
return {
|
|
126
|
+
start,
|
|
127
|
+
end: node.end,
|
|
128
|
+
text: replacement
|
|
129
|
+
};
|
|
130
|
+
}
|
|
131
|
+
/**
|
|
132
|
+
* Rewrite identifier references inside a reconstructed dependency expression.
|
|
133
|
+
*
|
|
134
|
+
* The expression is parsed and identifier nodes are replaced by position, so
|
|
135
|
+
* `$`-prefixed names rewrite correctly and occurrences inside string literals
|
|
136
|
+
* (e.g. lazy `import('/src/Api')` specifiers) and comments are untouched —
|
|
137
|
+
* the previous `\b`-regex text replacement got both wrong.
|
|
138
|
+
*/
|
|
139
|
+
function rewriteReferencedIdentifiers(expression, referenced, rewriter) {
|
|
140
|
+
const wrapped = `(${expression});`;
|
|
141
|
+
const source = ts.createSourceFile("alloy-dependency-expression.ts", wrapped, ts.ScriptTarget.ESNext, true);
|
|
142
|
+
const edits = [];
|
|
143
|
+
const visit = (node) => {
|
|
144
|
+
if (ts.isIdentifier(node) && referenced.has(node.text)) {
|
|
145
|
+
const replacement = rewriter(node.text);
|
|
146
|
+
if (replacement && replacement !== node.text) {
|
|
147
|
+
const edit = createIdentifierEdit(node, source, replacement);
|
|
148
|
+
if (edit) edits.push(edit);
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
ts.forEachChild(node, visit);
|
|
152
|
+
};
|
|
153
|
+
visit(source);
|
|
154
|
+
let result = wrapped;
|
|
155
|
+
for (const edit of edits.toSorted((a, b) => b.start - a.start)) result = result.slice(0, edit.start) + edit.text + result.slice(edit.end);
|
|
156
|
+
return result.slice(1, -2);
|
|
157
|
+
}
|
|
94
158
|
function reconstructDependencyExpression(dep, rewriter, contextDir) {
|
|
95
159
|
let expr = dep.expression;
|
|
96
|
-
|
|
97
|
-
const replacement = rewriter(ident);
|
|
98
|
-
if (replacement && replacement !== ident) expr = expr.replaceAll(new RegExp(`\\b${ident}\\b`, "g"), replacement);
|
|
99
|
-
}
|
|
160
|
+
if (dep.referencedIdentifiers.length > 0) expr = rewriteReferencedIdentifiers(expr, new Set(dep.referencedIdentifiers), rewriter);
|
|
100
161
|
if (dep.isLazy) expr = expr.replaceAll(/import\s*\(\s*(['"])(.+?)\1\s*\)/g, (match, quote, importPath) => {
|
|
101
162
|
if (importPath.startsWith(".")) return `import(${quote}${normalizeImportPath(path.resolve(contextDir, importPath))}${quote})`;
|
|
102
163
|
return match;
|
|
@@ -128,11 +189,11 @@ function reconstructOptionsText(meta, importMap, serviceRenames) {
|
|
|
128
189
|
if (parts.length === 0) return "{}";
|
|
129
190
|
return `{ ${parts.join(", ")} }`;
|
|
130
191
|
}
|
|
131
|
-
function buildImportsAndRegistrations(metas, lazyReferencedClassKeys, providerModulePaths) {
|
|
192
|
+
function buildImportsAndRegistrations(metas, lazyReferencedClassKeys, providerModulePaths, options) {
|
|
132
193
|
const hasProviderModules = providerModulePaths.length > 0;
|
|
133
194
|
const activeMetas = filterActiveMetas(metas, lazyReferencedClassKeys);
|
|
134
195
|
const resolver = new IdentifierResolver(activeMetas);
|
|
135
|
-
const runtimeImports = computeRuntimeImports(activeMetas, hasProviderModules);
|
|
196
|
+
const runtimeImports = computeRuntimeImports(activeMetas, hasProviderModules, options?.isDev !== void 0);
|
|
136
197
|
const pool = createNamePool([
|
|
137
198
|
...runtimeImports,
|
|
138
199
|
"registrations",
|
|
@@ -189,8 +250,9 @@ function enrichRegistrations(activeMetas, naming) {
|
|
|
189
250
|
};
|
|
190
251
|
});
|
|
191
252
|
}
|
|
192
|
-
function computeRuntimeImports(activeMetas, hasProviderModules) {
|
|
253
|
+
function computeRuntimeImports(activeMetas, hasProviderModules, hasEnvOverrides = false) {
|
|
193
254
|
const imports = new Set(["Container", "dependenciesRegistry"]);
|
|
255
|
+
if (hasEnvOverrides) imports.add("setEnvDetectionOverrides");
|
|
194
256
|
const needsLazyImport = activeMetas.some((m) => m.metadata.dependencies.some((d) => d.isLazy) || !!m.metadata.factory);
|
|
195
257
|
if (hasProviderModules) imports.add("applyProviders");
|
|
196
258
|
if (needsLazyImport) imports.add("Lazy");
|
|
@@ -257,9 +319,10 @@ function createIdentifierExports(registrations) {
|
|
|
257
319
|
* @param lazyReferencedClassKeys - Set of service keys that are referenced ONLY lazily (and thus should not be imported/registered eagerly in this bundle).
|
|
258
320
|
* @param providerModulePaths - List of provider modules to import and apply.
|
|
259
321
|
*/
|
|
260
|
-
function generateContainerModule(metas, lazyReferencedClassKeys, providerModulePaths) {
|
|
322
|
+
function generateContainerModule(metas, lazyReferencedClassKeys, providerModulePaths, options) {
|
|
261
323
|
const hasProviderModules = providerModulePaths.length > 0;
|
|
262
|
-
const { runtimeImportStatement, registrationsBlock, stubsBlock, identifierExportBlock } = buildImportsAndRegistrations(metas, lazyReferencedClassKeys, providerModulePaths);
|
|
324
|
+
const { runtimeImportStatement, registrationsBlock, stubsBlock, identifierExportBlock } = buildImportsAndRegistrations(metas, lazyReferencedClassKeys, providerModulePaths, options);
|
|
325
|
+
const envOverridesBlock = options?.isDev === void 0 ? "" : `\nsetEnvDetectionOverrides({ isDev: ${options.isDev} });\n`;
|
|
263
326
|
let providerImportBlock = "";
|
|
264
327
|
let providerInvocationBlock = "";
|
|
265
328
|
if (hasProviderModules) {
|
|
@@ -268,7 +331,7 @@ function generateContainerModule(metas, lazyReferencedClassKeys, providerModuleP
|
|
|
268
331
|
providerInvocationBlock = `\nconst providerDefinitions = [${aliasNames.join(", ")}];\nfor (const definition of providerDefinitions) {\n applyProviders(container, definition);\n}\n`;
|
|
269
332
|
}
|
|
270
333
|
return `
|
|
271
|
-
${runtimeImportStatement}${stubsBlock}
|
|
334
|
+
${runtimeImportStatement}${envOverridesBlock}${stubsBlock}
|
|
272
335
|
${providerImportBlock}
|
|
273
336
|
${registrationsBlock}
|
|
274
337
|
|
|
@@ -281,6 +344,11 @@ ${providerInvocationBlock}${identifierExportBlock}
|
|
|
281
344
|
export default container;
|
|
282
345
|
`;
|
|
283
346
|
}
|
|
347
|
+
const GENERATED_FILE_NOTICE = "This file was auto-generated by Alloy. Manual changes will be overwritten.";
|
|
348
|
+
const GENERATED_FILE_HEADER = `/**
|
|
349
|
+
* ${GENERATED_FILE_NOTICE}
|
|
350
|
+
*/
|
|
351
|
+
`;
|
|
284
352
|
/**
|
|
285
353
|
* Generates the TypeScript declaration definition (`.d.ts`) for the virtual container module.
|
|
286
354
|
* It exports the `ServiceIdentifiers` interface matching the runtime exports.
|
|
@@ -305,7 +373,7 @@ function generateContainerTypeDefinition(metas, pathResolver) {
|
|
|
305
373
|
const exportKey = createIdentifierExportKey(meta, resolver);
|
|
306
374
|
interfaceMembers.push(`${exportKey}: ServiceIdentifier<${importName}>;`);
|
|
307
375
|
}
|
|
308
|
-
return
|
|
376
|
+
return `${GENERATED_FILE_HEADER}
|
|
309
377
|
declare module "virtual:alloy-container" {
|
|
310
378
|
import { Container, ServiceIdentifier } from "alloy-di/runtime";
|
|
311
379
|
${imports.length ? imports.join("\n") + "\n" : ""}
|
|
@@ -329,7 +397,7 @@ declare module "virtual:alloy-container" {
|
|
|
329
397
|
* @param manifests - List of loaded manifest info (packageName and services).
|
|
330
398
|
*/
|
|
331
399
|
function generateManifestTypeDefinition(manifests) {
|
|
332
|
-
return manifests.map((m) => {
|
|
400
|
+
return GENERATED_FILE_HEADER + manifests.map((m) => {
|
|
333
401
|
const serviceIdentifiers = m.services.map((s) => ` export const ${s.exportName}Identifier: ServiceIdentifier;`).join("\n");
|
|
334
402
|
return `
|
|
335
403
|
declare module "${m.packageName}/manifest" {
|
|
@@ -420,4 +488,4 @@ ${serviceIdentifiers}
|
|
|
420
488
|
}).join("\n");
|
|
421
489
|
}
|
|
422
490
|
//#endregion
|
|
423
|
-
export { generateContainerModule, generateContainerTypeDefinition, generateManifestTypeDefinition };
|
|
491
|
+
export { GENERATED_FILE_NOTICE, generateContainerModule, generateContainerTypeDefinition, generateManifestTypeDefinition };
|
|
@@ -1,12 +1,12 @@
|
|
|
1
|
-
import { normalizeImportPath } from "
|
|
2
|
-
import { IdentifierResolver } from "
|
|
3
|
-
import { generateContainerModule, generateContainerTypeDefinition, generateManifestTypeDefinition } from "
|
|
1
|
+
import { normalizeImportPath, writeFileIfChanged } from "./utils.js";
|
|
2
|
+
import { IdentifierResolver } from "./identifier-resolver.js";
|
|
3
|
+
import { GENERATED_FILE_NOTICE, generateContainerModule, generateContainerTypeDefinition, generateManifestTypeDefinition } from "./codegen.js";
|
|
4
4
|
import { augmentFactoryLazyServices, collectEagerReferencedNames, findDuplicateManifestServices, groupMetasByName, readManifests, reconcileLazySet, toMetaFromManifest } from "./manifest-utils.js";
|
|
5
5
|
import { generateMermaidDiagram } from "./visualizer.js";
|
|
6
6
|
import { ensureDirectoryForFile } from "./visualization-utils.js";
|
|
7
7
|
import path from "node:path";
|
|
8
8
|
import fs from "node:fs";
|
|
9
|
-
//#region src/plugins/
|
|
9
|
+
//#region src/plugins/core/container-loader.ts
|
|
10
10
|
async function loadVirtualContainerModule(options) {
|
|
11
11
|
const metas = options.localMetas.map((meta) => ({
|
|
12
12
|
...meta,
|
|
@@ -32,7 +32,7 @@ async function loadVirtualContainerModule(options) {
|
|
|
32
32
|
const providerImports = Array.from(new Set([...options.providerImportPaths, ...manifestData.providers]));
|
|
33
33
|
reconcileLazySet(metas, lazyClassKeys, collectEagerReferencedNames(metas));
|
|
34
34
|
augmentFactoryLazyServices(metas, options.lazyServiceKeys);
|
|
35
|
-
const code = generateContainerModule(metas, lazyClassKeys, providerImports);
|
|
35
|
+
const code = generateContainerModule(metas, lazyClassKeys, providerImports, { isDev: options.isDevMode });
|
|
36
36
|
writeTypeDefinitions(metas, loadedManifests, options.resolvedRoot, options.containerDeclarationDir);
|
|
37
37
|
writeVisualizationArtifact(metas, lazyClassKeys, options.resolvedVisualization);
|
|
38
38
|
return {
|
|
@@ -66,13 +66,13 @@ function writeTypeDefinitions(metas, loadedManifests, resolvedRoot, containerDec
|
|
|
66
66
|
const dtsDir = path.resolve(resolvedRoot, containerDeclarationDir ?? "./src");
|
|
67
67
|
const dtsContent = generateContainerTypeDefinition(metas, (filePath) => resolveDeclarationImportPath(dtsDir, filePath));
|
|
68
68
|
if (!fs.existsSync(dtsDir)) fs.mkdirSync(dtsDir, { recursive: true });
|
|
69
|
-
|
|
69
|
+
writeFileIfChanged(path.join(dtsDir, "alloy-container.d.ts"), dtsContent);
|
|
70
70
|
if (loadedManifests.length === 0) return;
|
|
71
71
|
const manifestsDts = generateManifestTypeDefinition(loadedManifests.map((m) => ({
|
|
72
72
|
packageName: m.packageName,
|
|
73
73
|
services: m.services
|
|
74
74
|
})));
|
|
75
|
-
|
|
75
|
+
writeFileIfChanged(path.join(dtsDir, "alloy-manifests.d.ts"), manifestsDts);
|
|
76
76
|
}
|
|
77
77
|
function resolveDeclarationImportPath(dtsDir, filePath) {
|
|
78
78
|
if (!path.isAbsolute(filePath)) return filePath;
|
|
@@ -89,7 +89,7 @@ function writeVisualizationArtifact(metas, lazyReferencedClassKeys, resolvedVisu
|
|
|
89
89
|
options: resolvedVisualization.mermaidOptions
|
|
90
90
|
});
|
|
91
91
|
ensureDirectoryForFile(resolvedVisualization.outputPath);
|
|
92
|
-
|
|
92
|
+
writeFileIfChanged(resolvedVisualization.outputPath, `%% ${GENERATED_FILE_NOTICE}\n${artifact.diagram}\n`);
|
|
93
93
|
}
|
|
94
94
|
//#endregion
|
|
95
95
|
export { loadVirtualContainerModule };
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { createClassKey } from "
|
|
2
|
-
import { createDiscoveryStore } from "
|
|
3
|
-
//#region src/plugins/
|
|
1
|
+
import { createClassKey } from "./utils.js";
|
|
2
|
+
import { createDiscoveryStore } from "./discovery-store.js";
|
|
3
|
+
//#region src/plugins/core/discovery-runtime.ts
|
|
4
4
|
/** Files the discovery scanner processes (mirrors the transform hook filter). */
|
|
5
5
|
function isDiscoverableFile(file) {
|
|
6
6
|
return /\.tsx?$/i.test(file) && !/\.d\.ts$/i.test(file) && !file.includes("node_modules");
|
|
@@ -62,15 +62,5 @@ function createDiscoveryRuntime() {
|
|
|
62
62
|
}
|
|
63
63
|
};
|
|
64
64
|
}
|
|
65
|
-
/**
|
|
66
|
-
* Invalidate the generated container module in every environment's module
|
|
67
|
-
* graph so its `load` hook re-runs and regenerates from current discovery.
|
|
68
|
-
*/
|
|
69
|
-
function invalidateContainerModule(server, resolvedVirtualModuleId) {
|
|
70
|
-
for (const environment of Object.values(server.environments)) {
|
|
71
|
-
const mod = environment.moduleGraph.getModuleById(resolvedVirtualModuleId);
|
|
72
|
-
if (mod) environment.moduleGraph.invalidateModule(mod);
|
|
73
|
-
}
|
|
74
|
-
}
|
|
75
65
|
//#endregion
|
|
76
|
-
export { createDiscoveryRuntime,
|
|
66
|
+
export { createDiscoveryRuntime, isDiscoverableFile };
|
|
@@ -1,10 +1,14 @@
|
|
|
1
1
|
import { scanSource } from "./scanner.js";
|
|
2
|
+
import crypto from "node:crypto";
|
|
2
3
|
//#region src/plugins/core/discovery-store.ts
|
|
3
4
|
/**
|
|
4
5
|
* Maintains a per-file cache of discovered DI metadata, lazy references, and
|
|
5
6
|
* optionally source snapshots to drive incremental recompilation inside the
|
|
6
7
|
* Alloy discovery pipeline.
|
|
7
8
|
*/
|
|
9
|
+
function hashContent(code) {
|
|
10
|
+
return crypto.createHash("sha1").update(code).digest("hex");
|
|
11
|
+
}
|
|
8
12
|
/**
|
|
9
13
|
* Creates a file-scoped discovery store that caches scanner output and
|
|
10
14
|
* optionally the original source for diagnostics or incremental rebuilds.
|
|
@@ -15,6 +19,7 @@ import { scanSource } from "./scanner.js";
|
|
|
15
19
|
function createDiscoveryStore(options = {}) {
|
|
16
20
|
const fileMetas = /* @__PURE__ */ new Map();
|
|
17
21
|
const fileLazyRefs = /* @__PURE__ */ new Map();
|
|
22
|
+
const fileContentHashes = /* @__PURE__ */ new Map();
|
|
18
23
|
const fileSources = options.trackSources ? /* @__PURE__ */ new Map() : void 0;
|
|
19
24
|
/**
|
|
20
25
|
* Scan and cache the latest metadata for a file, returning both the fresh
|
|
@@ -26,6 +31,14 @@ function createDiscoveryStore(options = {}) {
|
|
|
26
31
|
function updateFile(id, code) {
|
|
27
32
|
const previousMetas = fileMetas.get(id);
|
|
28
33
|
const previousLazyClassKeys = fileLazyRefs.get(id);
|
|
34
|
+
const contentHash = hashContent(code);
|
|
35
|
+
if (fileContentHashes.get(id) === contentHash) return {
|
|
36
|
+
metas: previousMetas ?? [],
|
|
37
|
+
lazyClassKeys: new Set(previousLazyClassKeys),
|
|
38
|
+
previousMetas,
|
|
39
|
+
previousLazyClassKeys
|
|
40
|
+
};
|
|
41
|
+
fileContentHashes.set(id, contentHash);
|
|
29
42
|
if (fileSources) fileSources.set(id, code);
|
|
30
43
|
const { metas, lazyClassKeys } = scanSource(code, id);
|
|
31
44
|
if (metas.length) fileMetas.set(id, metas);
|
|
@@ -49,6 +62,7 @@ function createDiscoveryStore(options = {}) {
|
|
|
49
62
|
const previousLazyClassKeys = fileLazyRefs.get(id);
|
|
50
63
|
fileMetas.delete(id);
|
|
51
64
|
fileLazyRefs.delete(id);
|
|
65
|
+
fileContentHashes.delete(id);
|
|
52
66
|
if (fileSources) fileSources.delete(id);
|
|
53
67
|
return {
|
|
54
68
|
previousMetas,
|
|
@@ -61,6 +75,7 @@ function createDiscoveryStore(options = {}) {
|
|
|
61
75
|
function clear() {
|
|
62
76
|
fileMetas.clear();
|
|
63
77
|
fileLazyRefs.clear();
|
|
78
|
+
fileContentHashes.clear();
|
|
64
79
|
fileSources?.clear();
|
|
65
80
|
}
|
|
66
81
|
return {
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { createClassKey, createSymbolKey, normalizeImportPath } from "
|
|
1
|
+
import { createClassKey, createSymbolKey, normalizeImportPath } from "./utils.js";
|
|
2
2
|
import { z } from "zod";
|
|
3
|
-
//#region src/plugins/
|
|
3
|
+
//#region src/plugins/core/manifest-utils.ts
|
|
4
4
|
/**
|
|
5
5
|
* Reads a list of manifest objects and returns aggregated service + provider module specifiers.
|
|
6
6
|
*
|
|
@@ -83,9 +83,16 @@ async function readManifests(inputs) {
|
|
|
83
83
|
function readManifestByVersion(manifest) {
|
|
84
84
|
return (manifest.schemaVersion ?? 1) === 2 ? readManifestV2(manifest) : readManifestV1(manifest);
|
|
85
85
|
}
|
|
86
|
+
function warnInvalidManifest(manifest, error) {
|
|
87
|
+
const packageName = typeof manifest.packageName === "string" && manifest.packageName ? manifest.packageName : "<unknown package>";
|
|
88
|
+
console.warn(`[alloy] Ignoring invalid manifest "${packageName}" — its services and providers will not be registered:\n${z.prettifyError(error)}`);
|
|
89
|
+
}
|
|
86
90
|
function readManifestV1(manifest) {
|
|
87
91
|
const parsed = manifestSchemaV1.safeParse(manifest);
|
|
88
|
-
if (!parsed.success)
|
|
92
|
+
if (!parsed.success) {
|
|
93
|
+
warnInvalidManifest(manifest, parsed.error);
|
|
94
|
+
return null;
|
|
95
|
+
}
|
|
89
96
|
return {
|
|
90
97
|
schemaVersion: 1,
|
|
91
98
|
packageName: parsed.data.packageName,
|
|
@@ -98,7 +105,10 @@ function readManifestV1(manifest) {
|
|
|
98
105
|
}
|
|
99
106
|
function readManifestV2(manifest) {
|
|
100
107
|
const parsed = manifestSchemaV2.safeParse(manifest);
|
|
101
|
-
if (!parsed.success)
|
|
108
|
+
if (!parsed.success) {
|
|
109
|
+
warnInvalidManifest(manifest, parsed.error);
|
|
110
|
+
return null;
|
|
111
|
+
}
|
|
102
112
|
return {
|
|
103
113
|
schemaVersion: 2,
|
|
104
114
|
packageName: parsed.data.packageName,
|
|
@@ -36,7 +36,19 @@ function collectFileImports(sourceFile) {
|
|
|
36
36
|
}
|
|
37
37
|
return imports;
|
|
38
38
|
}
|
|
39
|
+
/**
|
|
40
|
+
* Cheap pre-filter that avoids the TS parse for files that cannot contribute
|
|
41
|
+
* discovery results: decorators require an `@` and lazy references require
|
|
42
|
+
* the `Lazy` identifier.
|
|
43
|
+
*/
|
|
44
|
+
function mayContainDiscoverableSyntax(code) {
|
|
45
|
+
return code.includes("@") || code.includes("Lazy");
|
|
46
|
+
}
|
|
39
47
|
function scanSource(code, id) {
|
|
48
|
+
if (!mayContainDiscoverableSyntax(code)) return {
|
|
49
|
+
metas: [],
|
|
50
|
+
lazyClassKeys: /* @__PURE__ */ new Set()
|
|
51
|
+
};
|
|
40
52
|
const sourceFile = ts.createSourceFile(id, code, ts.ScriptTarget.ESNext, true);
|
|
41
53
|
const discovered = /* @__PURE__ */ new Map();
|
|
42
54
|
const lazyRefs = /* @__PURE__ */ new Set();
|
|
@@ -30,14 +30,51 @@ function createAliasName(className, filePath) {
|
|
|
30
30
|
function createSymbolKey(filePath, className) {
|
|
31
31
|
return `alloy:${normalizeImportPath(filePath)}#${className}`;
|
|
32
32
|
}
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
33
|
+
const lastWrittenContent = /* @__PURE__ */ new Map();
|
|
34
|
+
/**
|
|
35
|
+
* Write a generated artifact only when its content actually changed.
|
|
36
|
+
*
|
|
37
|
+
* @returns true when the file was written, false when it already matched.
|
|
38
|
+
*/
|
|
39
|
+
function writeFileIfChanged(filePath, content) {
|
|
40
|
+
if (lastWrittenContent.get(filePath) === content) return false;
|
|
41
|
+
try {
|
|
42
|
+
if (fs.readFileSync(filePath, "utf-8") === content) {
|
|
43
|
+
lastWrittenContent.set(filePath, content);
|
|
44
|
+
return false;
|
|
45
|
+
}
|
|
46
|
+
} catch {}
|
|
47
|
+
fs.writeFileSync(filePath, content);
|
|
48
|
+
lastWrittenContent.set(filePath, content);
|
|
49
|
+
return true;
|
|
50
|
+
}
|
|
51
|
+
function walkSync(dir, fileList = [], visitedDirs) {
|
|
52
|
+
const visited = visitedDirs ?? /* @__PURE__ */ new Set();
|
|
53
|
+
let realDir;
|
|
54
|
+
try {
|
|
55
|
+
realDir = fs.realpathSync(dir);
|
|
56
|
+
} catch {
|
|
57
|
+
return fileList;
|
|
58
|
+
}
|
|
59
|
+
if (visited.has(realDir)) return fileList;
|
|
60
|
+
visited.add(realDir);
|
|
61
|
+
for (const entry of fs.readdirSync(dir, { withFileTypes: true })) {
|
|
62
|
+
if (entry.name.startsWith(".")) continue;
|
|
63
|
+
const filePath = path.join(dir, entry.name);
|
|
64
|
+
if (entry.isDirectory()) walkSync(filePath, fileList, visited);
|
|
65
|
+
else if (entry.isFile()) fileList.push(filePath);
|
|
66
|
+
else if (entry.isSymbolicLink()) {
|
|
67
|
+
let stat;
|
|
68
|
+
try {
|
|
69
|
+
stat = fs.statSync(filePath);
|
|
70
|
+
} catch {
|
|
71
|
+
continue;
|
|
72
|
+
}
|
|
73
|
+
if (stat.isDirectory()) walkSync(filePath, fileList, visited);
|
|
74
|
+
else if (stat.isFile()) fileList.push(filePath);
|
|
75
|
+
}
|
|
76
|
+
}
|
|
40
77
|
return fileList;
|
|
41
78
|
}
|
|
42
79
|
//#endregion
|
|
43
|
-
export { createAliasName, createClassKey, createSymbolKey, hashString, normalizeImportPath, walkSync };
|
|
80
|
+
export { createAliasName, createClassKey, createSymbolKey, hashString, normalizeImportPath, walkSync, writeFileIfChanged };
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { MermaidDiagramOptions } from "./visualizer.js";
|
|
2
2
|
|
|
3
|
-
//#region src/plugins/
|
|
3
|
+
//#region src/plugins/core/visualization-utils.d.ts
|
|
4
4
|
interface AlloyMermaidVisualizerOptions extends MermaidDiagramOptions {
|
|
5
5
|
outputPath?: string;
|
|
6
6
|
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import path from "node:path";
|
|
2
2
|
import fs from "node:fs";
|
|
3
|
-
//#region src/plugins/
|
|
3
|
+
//#region src/plugins/core/visualization-utils.ts
|
|
4
4
|
const DEFAULT_MERMAID_FILENAME = "alloy-di.mmd";
|
|
5
5
|
function resolveVisualizationOptions(input, projectRoot) {
|
|
6
6
|
if (!input) return null;
|
|
@@ -1,22 +1,22 @@
|
|
|
1
|
-
import { createClassKey, createSymbolKey, hashString, normalizeImportPath } from "
|
|
1
|
+
import { createClassKey, createSymbolKey, hashString, normalizeImportPath } from "./utils.js";
|
|
2
2
|
import path from "node:path";
|
|
3
|
-
//#region src/plugins/
|
|
3
|
+
//#region src/plugins/core/visualizer.ts
|
|
4
4
|
const DEFAULT_SCOPE_COLORS = {
|
|
5
|
-
singleton: "#
|
|
6
|
-
transient: "#
|
|
5
|
+
singleton: "#3b6ea5",
|
|
6
|
+
transient: "#2a7d73"
|
|
7
7
|
};
|
|
8
8
|
const DEFAULT_OPTIONS = {
|
|
9
9
|
direction: "LR",
|
|
10
10
|
includeLegend: true,
|
|
11
11
|
scopeColors: DEFAULT_SCOPE_COLORS,
|
|
12
|
-
lazyNodeFill: "#
|
|
13
|
-
factoryNodeFill: "#
|
|
14
|
-
tokenNodeFill: "#
|
|
15
|
-
nodeStrokeColor: "#
|
|
16
|
-
nodeTextColor: "#
|
|
17
|
-
lazyEdgeColor: "#
|
|
18
|
-
eagerEdgeColor: "#
|
|
19
|
-
factoryEdgeColor: "#
|
|
12
|
+
lazyNodeFill: "#6c5cb8",
|
|
13
|
+
factoryNodeFill: "#9c6516",
|
|
14
|
+
tokenNodeFill: "#4b5c6b",
|
|
15
|
+
nodeStrokeColor: "#5a7488",
|
|
16
|
+
nodeTextColor: "#ffffff",
|
|
17
|
+
lazyEdgeColor: "#9385d6",
|
|
18
|
+
eagerEdgeColor: "#7c93a6",
|
|
19
|
+
factoryEdgeColor: "#c2922e"
|
|
20
20
|
};
|
|
21
21
|
const RESERVED_IDENTIFIERS = new Set([
|
|
22
22
|
"Lazy",
|
|
@@ -95,7 +95,7 @@ function generateMermaidDiagram({ metas, lazyClassKeys, options }) {
|
|
|
95
95
|
edges.push({
|
|
96
96
|
from: sourceNode,
|
|
97
97
|
to: target,
|
|
98
|
-
label: describeEdge(sourceNode, target
|
|
98
|
+
label: describeEdge(sourceNode, target),
|
|
99
99
|
isLazy: dep.isLazy,
|
|
100
100
|
stroke: selectEdgeColor(dep.isLazy, target, mergedOptions)
|
|
101
101
|
});
|
|
@@ -106,6 +106,7 @@ function generateMermaidDiagram({ metas, lazyClassKeys, options }) {
|
|
|
106
106
|
if (mergedOptions.includeLegend) {
|
|
107
107
|
lines.push(` %% Legend: singleton=${mergedOptions.scopeColors.singleton}, transient=${mergedOptions.scopeColors.transient}, lazy-only=${mergedOptions.lazyNodeFill}, factory=${mergedOptions.factoryNodeFill}, token=${mergedOptions.tokenNodeFill}`);
|
|
108
108
|
lines.push(` %% Edge colors: eager=${mergedOptions.eagerEdgeColor}, lazy=${mergedOptions.lazyEdgeColor}, factory=${mergedOptions.factoryEdgeColor}`);
|
|
109
|
+
lines.push(` %% Edge labels: Si=singleton, Tr=transient, Tk=token; solid=eager, dotted=lazy`);
|
|
109
110
|
}
|
|
110
111
|
const allNodes = [...serviceNodes, ...Array.from(tokenNodes.values())];
|
|
111
112
|
for (const node of allNodes) {
|
|
@@ -155,11 +156,18 @@ function sanitizeMermaidId(source, fallbackIndex) {
|
|
|
155
156
|
function escapeMermaidLabel(label) {
|
|
156
157
|
return label.replaceAll("\"", "\\\"").replaceAll("|", "/");
|
|
157
158
|
}
|
|
159
|
+
/** Single-token code for a node's scope/kind: Si, Tr, or Tk (token). */
|
|
160
|
+
function scopeCode(node) {
|
|
161
|
+
if (node.type === "token") return "Tk";
|
|
162
|
+
return node.scope === "transient" ? "Tr" : "Si";
|
|
163
|
+
}
|
|
158
164
|
/**
|
|
159
|
-
* Builds a
|
|
165
|
+
* Builds a compact edge label as a `source→target` scope transition (e.g.
|
|
166
|
+
* `Si→Tr`). Eager/lazy is conveyed by the arrow style and the target kind by
|
|
167
|
+
* node color, so they are intentionally omitted from the text. See the legend.
|
|
160
168
|
*/
|
|
161
|
-
function describeEdge(from, to
|
|
162
|
-
return `${
|
|
169
|
+
function describeEdge(from, to) {
|
|
170
|
+
return `${scopeCode(from)}→${scopeCode(to)}`;
|
|
163
171
|
}
|
|
164
172
|
/**
|
|
165
173
|
* Determines the fill color for a node based on its type, scope, and lazy/factory flags.
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { ServiceIdentifier } from "../../lib/service-identifiers.js";
|
|
2
2
|
import { AlloyManifest } from "../core/types.js";
|
|
3
|
-
import { AlloyMermaidVisualizerOptions, AlloyVisualizationOptions } from "
|
|
3
|
+
import { AlloyMermaidVisualizerOptions, AlloyVisualizationOptions } from "../core/visualization-utils.js";
|
|
4
4
|
import { Plugin } from "vite";
|
|
5
5
|
|
|
6
6
|
//#region src/plugins/vite-plugin/index.d.ts
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import { normalizeImportPath, walkSync } from "../core/utils.js";
|
|
2
|
-
import { resolveVisualizationOptions } from "
|
|
3
|
-
import { loadVirtualContainerModule } from "
|
|
4
|
-
import { createDiscoveryRuntime,
|
|
2
|
+
import { resolveVisualizationOptions } from "../core/visualization-utils.js";
|
|
3
|
+
import { loadVirtualContainerModule } from "../core/container-loader.js";
|
|
4
|
+
import { createDiscoveryRuntime, isDiscoverableFile } from "../core/discovery-runtime.js";
|
|
5
|
+
import { invalidateContainerModule } from "./module-invalidation.js";
|
|
5
6
|
import path from "node:path";
|
|
6
7
|
import fs from "node:fs";
|
|
7
8
|
//#region src/plugins/vite-plugin/index.ts
|
|
@@ -22,6 +23,7 @@ function alloy(options = {}) {
|
|
|
22
23
|
let resolvedRoot = process.cwd();
|
|
23
24
|
let packageName = "UNKNOWN_PACKAGE";
|
|
24
25
|
let resolvedVisualization = null;
|
|
26
|
+
let isDevMode;
|
|
25
27
|
const lazyServiceKeys = new Set((options.lazyServices ?? []).map(toLazyServiceKey));
|
|
26
28
|
const discoveryRuntime = createDiscoveryRuntime();
|
|
27
29
|
return {
|
|
@@ -29,6 +31,7 @@ function alloy(options = {}) {
|
|
|
29
31
|
enforce: "pre",
|
|
30
32
|
configResolved(config) {
|
|
31
33
|
resolvedRoot = config.root ?? process.cwd();
|
|
34
|
+
isDevMode = !config.isProduction;
|
|
32
35
|
try {
|
|
33
36
|
const pkgPath = path.resolve(resolvedRoot, "package.json");
|
|
34
37
|
const pkg = JSON.parse(fs.readFileSync(pkgPath, "utf-8"));
|
|
@@ -102,7 +105,8 @@ function alloy(options = {}) {
|
|
|
102
105
|
packageName,
|
|
103
106
|
resolvedRoot,
|
|
104
107
|
containerDeclarationDir: options.containerDeclarationDir,
|
|
105
|
-
resolvedVisualization
|
|
108
|
+
resolvedVisualization,
|
|
109
|
+
isDevMode
|
|
106
110
|
});
|
|
107
111
|
}
|
|
108
112
|
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
//#region src/plugins/vite-plugin/module-invalidation.ts
|
|
2
|
+
/**
|
|
3
|
+
* Invalidate the generated container module in every environment's module
|
|
4
|
+
* graph so its `load` hook re-runs and regenerates from current discovery.
|
|
5
|
+
*/
|
|
6
|
+
function invalidateContainerModule(server, resolvedVirtualModuleId) {
|
|
7
|
+
for (const environment of Object.values(server.environments)) {
|
|
8
|
+
const mod = environment.moduleGraph.getModuleById(resolvedVirtualModuleId);
|
|
9
|
+
if (mod) environment.moduleGraph.invalidateModule(mod);
|
|
10
|
+
}
|
|
11
|
+
}
|
|
12
|
+
//#endregion
|
|
13
|
+
export { invalidateContainerModule };
|
package/dist/runtime.d.ts
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import { Newable, Token, createToken } from "./lib/types.js";
|
|
2
2
|
import { ServiceIdentifier, clearServiceIdentifierRegistry, getConstructorByIdentifier, getServiceIdentifier, registerServiceIdentifier } from "./lib/service-identifiers.js";
|
|
3
3
|
import { Container } from "./lib/container.js";
|
|
4
|
+
import { EnvDetectionOverrides, setEnvDetectionOverrides } from "./lib/env-detection.js";
|
|
4
5
|
import { LAZY_IDENTIFIER, Lazy } from "./lib/lazy.js";
|
|
5
6
|
import { Injectable, Singleton, assertDeps, dependenciesRegistry, deps } from "./lib/decorators.js";
|
|
6
7
|
import { ProviderDefinitions, applyProviders, asClass, asLazyClass, asValue, defineProviders, lifecycle } from "./lib/providers.js";
|
|
7
|
-
export { Container, Injectable, LAZY_IDENTIFIER, Lazy, type Lazy as LazyInterface, type Newable, type ProviderDefinitions, type ServiceIdentifier, Singleton, type Token, applyProviders, asClass, asLazyClass, asValue, assertDeps, clearServiceIdentifierRegistry, createToken, defineProviders, dependenciesRegistry, deps, getConstructorByIdentifier, getServiceIdentifier, lifecycle, registerServiceIdentifier };
|
|
8
|
+
export { Container, type EnvDetectionOverrides, Injectable, LAZY_IDENTIFIER, Lazy, type Lazy as LazyInterface, type Newable, type ProviderDefinitions, type ServiceIdentifier, Singleton, type Token, applyProviders, asClass, asLazyClass, asValue, assertDeps, clearServiceIdentifierRegistry, createToken, defineProviders, dependenciesRegistry, deps, getConstructorByIdentifier, getServiceIdentifier, lifecycle, registerServiceIdentifier, setEnvDetectionOverrides };
|
package/dist/runtime.js
CHANGED
|
@@ -2,6 +2,7 @@ import { createToken } from "./lib/types.js";
|
|
|
2
2
|
import { LAZY_IDENTIFIER, Lazy } from "./lib/lazy.js";
|
|
3
3
|
import { Injectable, Singleton, assertDeps, dependenciesRegistry, deps } from "./lib/decorators.js";
|
|
4
4
|
import { clearServiceIdentifierRegistry, getConstructorByIdentifier, getServiceIdentifier, registerServiceIdentifier } from "./lib/service-identifiers.js";
|
|
5
|
+
import { setEnvDetectionOverrides } from "./lib/env-detection.js";
|
|
5
6
|
import { Container } from "./lib/container.js";
|
|
6
7
|
import { applyProviders, asClass, asLazyClass, asValue, defineProviders, lifecycle } from "./lib/providers.js";
|
|
7
|
-
export { Container, Injectable, LAZY_IDENTIFIER, Lazy, Singleton, applyProviders, asClass, asLazyClass, asValue, assertDeps, clearServiceIdentifierRegistry, createToken, defineProviders, dependenciesRegistry, deps, getConstructorByIdentifier, getServiceIdentifier, lifecycle, registerServiceIdentifier };
|
|
8
|
+
export { Container, Injectable, LAZY_IDENTIFIER, Lazy, Singleton, applyProviders, asClass, asLazyClass, asValue, assertDeps, clearServiceIdentifierRegistry, createToken, defineProviders, dependenciesRegistry, deps, getConstructorByIdentifier, getServiceIdentifier, lifecycle, registerServiceIdentifier, setEnvDetectionOverrides };
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"root":["../src/entry-points.test.ts","../src/rollup.ts","../src/runtime.ts","../src/test.ts","../src/vite.ts","../src/lib/container.identifiers.test.ts","../src/lib/container.internals.test.ts","../src/lib/container.test.ts","../src/lib/container.testing-features.test.ts","../src/lib/container.ts","../src/lib/decorators.runtime.test.ts","../src/lib/decorators.test-d.ts","../src/lib/decorators.ts","../src/lib/dependency-error.ts","../src/lib/env-detection.test.ts","../src/lib/env-detection.ts","../src/lib/lazy-retry.test.ts","../src/lib/lazy.ts","../src/lib/providers.test.ts","../src/lib/providers.ts","../src/lib/scope.ts","../src/lib/service-identifiers.test.ts","../src/lib/service-identifiers.ts","../src/lib/tokens.test.ts","../src/lib/types.ts","../src/lib/testing/mocking.test.ts","../src/lib/testing/mocking.ts","../src/lib/testing/registry.test.ts","../src/lib/testing/registry.ts","../src/plugins/core/codegen.test.ts","../src/plugins/core/codegen.ts","../src/plugins/core/decorators.helpers.test.ts","../src/plugins/core/decorators.ts","../src/plugins/core/discovery-
|
|
1
|
+
{"root":["../src/entry-points.test.ts","../src/fixture-subpaths.test.ts","../src/rollup.ts","../src/runtime.ts","../src/test.ts","../src/vite.ts","../src/lib/container.identifiers.test.ts","../src/lib/container.internals.test.ts","../src/lib/container.test.ts","../src/lib/container.testing-features.test.ts","../src/lib/container.ts","../src/lib/decorators.runtime.test.ts","../src/lib/decorators.test-d.ts","../src/lib/decorators.ts","../src/lib/dependency-error.ts","../src/lib/env-detection.test.ts","../src/lib/env-detection.ts","../src/lib/lazy-retry.test.ts","../src/lib/lazy.ts","../src/lib/providers.test.ts","../src/lib/providers.ts","../src/lib/scope.ts","../src/lib/service-identifiers.test.ts","../src/lib/service-identifiers.ts","../src/lib/tokens.test.ts","../src/lib/types.ts","../src/lib/testing/mocking.test.ts","../src/lib/testing/mocking.ts","../src/lib/testing/registry.test.ts","../src/lib/testing/registry.ts","../src/plugins/core/codegen.test.ts","../src/plugins/core/codegen.ts","../src/plugins/core/container-loader.test.ts","../src/plugins/core/container-loader.ts","../src/plugins/core/decorators.helpers.test.ts","../src/plugins/core/decorators.ts","../src/plugins/core/discovery-runtime.ts","../src/plugins/core/discovery-store.test.ts","../src/plugins/core/discovery-store.ts","../src/plugins/core/identifier-resolver.test.ts","../src/plugins/core/identifier-resolver.ts","../src/plugins/core/lazy-utils.ts","../src/plugins/core/lazy.helpers.test.ts","../src/plugins/core/lazy.ts","../src/plugins/core/manifest-utils.ts","../src/plugins/core/manifest-utils.validation.test.ts","../src/plugins/core/scanner.test.ts","../src/plugins/core/scanner.ts","../src/plugins/core/types.ts","../src/plugins/core/utils.ts","../src/plugins/core/utils.walk.test.ts","../src/plugins/core/utils.write.test.ts","../src/plugins/core/visualization-utils.ts","../src/plugins/core/visualizer.test.ts","../src/plugins/core/visualizer.ts","../src/plugins/rollup-plugin/build-utils.ts","../src/plugins/rollup-plugin/index.ts","../src/plugins/rollup-plugin/rollup-plugin.test.ts","../src/plugins/vite-plugin/duplicate-registrations.test.ts","../src/plugins/vite-plugin/index.ts","../src/plugins/vite-plugin/lazy-services.test.ts","../src/plugins/vite-plugin/lifecycle-and-hmr.test.ts","../src/plugins/vite-plugin/module-generation.test.ts","../src/plugins/vite-plugin/module-invalidation.ts","../src/plugins/vite-plugin/test-utils.ts","../src/plugins/vite-plugin/transform-guards.test.ts","../src/plugins/vite-plugin/visualization-option.test.ts"],"version":"6.0.3"}
|