alloy-di 1.2.0 → 1.2.3
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/container.d.ts +10 -2
- package/dist/lib/container.js +30 -17
- package/dist/lib/decorators.js +33 -0
- package/dist/lib/service-identifiers.d.ts +5 -2
- package/dist/lib/service-identifiers.js +6 -2
- package/dist/plugins/core/codegen.js +160 -51
- package/dist/plugins/core/lazy.js +54 -7
- package/dist/plugins/core/scanner.js +96 -9
- package/dist/plugins/core/types.d.ts +33 -14
- package/dist/plugins/core/utils.js +1 -1
- package/dist/plugins/rollup-plugin/index.js +68 -39
- package/dist/plugins/vite-plugin/container-loader.js +95 -0
- package/dist/plugins/vite-plugin/discovery-runtime.js +76 -0
- package/dist/plugins/vite-plugin/index.d.ts +1 -11
- package/dist/plugins/vite-plugin/index.js +37 -124
- package/dist/plugins/vite-plugin/manifest-utils.js +174 -75
- package/dist/plugins/vite-plugin/visualization-utils.d.ts +15 -0
- package/dist/plugins/vite-plugin/visualization-utils.js +28 -0
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/package.json +1 -1
|
@@ -1,13 +1,10 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
import { augmentFactoryLazyServices, collectEagerReferencedNames, findDuplicateManifestServices, groupMetasByName, readManifests, reconcileLazySet, toMetaFromManifest } from "./manifest-utils.js";
|
|
6
|
-
import { generateMermaidDiagram } from "./visualizer.js";
|
|
1
|
+
import { normalizeImportPath, walkSync } from "../core/utils.js";
|
|
2
|
+
import { resolveVisualizationOptions } from "./visualization-utils.js";
|
|
3
|
+
import { loadVirtualContainerModule } from "./container-loader.js";
|
|
4
|
+
import { createDiscoveryRuntime, invalidateContainerModule, isDiscoverableFile } from "./discovery-runtime.js";
|
|
7
5
|
import path from "node:path";
|
|
8
6
|
import fs from "node:fs";
|
|
9
7
|
//#region src/plugins/vite-plugin/index.ts
|
|
10
|
-
const DEFAULT_MERMAID_FILENAME = "alloy-di.mmd";
|
|
11
8
|
function toLazyServiceKey(identifier) {
|
|
12
9
|
const description = identifier.description;
|
|
13
10
|
if (!description || !description.startsWith("alloy:")) throw new Error("[alloy] lazyServices entries must be serviceIdentifiers exported by Alloy manifests.");
|
|
@@ -26,18 +23,10 @@ function alloy(options = {}) {
|
|
|
26
23
|
let packageName = "UNKNOWN_PACKAGE";
|
|
27
24
|
let resolvedVisualization = null;
|
|
28
25
|
const lazyServiceKeys = new Set((options.lazyServices ?? []).map(toLazyServiceKey));
|
|
29
|
-
const
|
|
30
|
-
const discoveredClasses = /* @__PURE__ */ new Map();
|
|
31
|
-
const lazyReferencedClassKeys = /* @__PURE__ */ new Set();
|
|
32
|
-
const processUpdate = (id, code) => {
|
|
33
|
-
const { metas, lazyClassKeys, previousMetas, previousLazyClassKeys } = discovery.updateFile(id, code);
|
|
34
|
-
if (previousMetas) for (const meta of previousMetas) discoveredClasses.delete(createClassKey(meta.filePath, meta.className));
|
|
35
|
-
for (const meta of metas) discoveredClasses.set(createClassKey(meta.filePath, meta.className), meta);
|
|
36
|
-
if (previousLazyClassKeys) for (const key of previousLazyClassKeys) lazyReferencedClassKeys.delete(key);
|
|
37
|
-
if (lazyClassKeys.size) for (const key of lazyClassKeys) lazyReferencedClassKeys.add(key);
|
|
38
|
-
};
|
|
26
|
+
const discoveryRuntime = createDiscoveryRuntime();
|
|
39
27
|
return {
|
|
40
28
|
name: "vite-plugin-alloy",
|
|
29
|
+
enforce: "pre",
|
|
41
30
|
configResolved(config) {
|
|
42
31
|
resolvedRoot = config.root ?? process.cwd();
|
|
43
32
|
try {
|
|
@@ -67,133 +56,57 @@ function alloy(options = {}) {
|
|
|
67
56
|
exclude: [/\.d\.ts$/i, /node_modules/]
|
|
68
57
|
} },
|
|
69
58
|
handler(code, id) {
|
|
70
|
-
processUpdate(id, code);
|
|
59
|
+
discoveryRuntime.processUpdate(id, code);
|
|
71
60
|
return null;
|
|
72
61
|
}
|
|
73
62
|
},
|
|
74
|
-
hotUpdate(ctx) {
|
|
63
|
+
async hotUpdate(ctx) {
|
|
75
64
|
if (this.environment.name !== "client") return;
|
|
76
|
-
const file = ctx
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
65
|
+
const { file } = ctx;
|
|
66
|
+
if (!isDiscoverableFile(file)) return;
|
|
67
|
+
let discoveryChanged;
|
|
68
|
+
if (ctx.type === "delete") discoveryChanged = discoveryRuntime.removeDiscoveredFile(file);
|
|
69
|
+
else {
|
|
70
|
+
let code;
|
|
71
|
+
try {
|
|
72
|
+
code = await ctx.read();
|
|
73
|
+
} catch {
|
|
74
|
+
return;
|
|
75
|
+
}
|
|
76
|
+
discoveryChanged = discoveryRuntime.processUpdate(file, code);
|
|
82
77
|
}
|
|
83
|
-
return
|
|
78
|
+
if (!discoveryChanged) return;
|
|
79
|
+
invalidateContainerModule(ctx.server, resolvedVirtualModuleId);
|
|
80
|
+
this.environment.hot.send({ type: "full-reload" });
|
|
81
|
+
return [];
|
|
84
82
|
},
|
|
85
83
|
buildStart() {
|
|
86
|
-
|
|
87
|
-
discoveredClasses.clear();
|
|
88
|
-
lazyReferencedClassKeys.clear();
|
|
84
|
+
discoveryRuntime.clear();
|
|
89
85
|
for (const ref of providerModuleRefs) this.addWatchFile(ref.absPath);
|
|
90
86
|
const files = walkSync(path.join(resolvedRoot, "src"));
|
|
91
87
|
for (const file of files) if (/\.(tsx?|ts)$/i.test(file) && !file.endsWith(".d.ts")) try {
|
|
92
|
-
|
|
88
|
+
const code = fs.readFileSync(file, "utf-8");
|
|
89
|
+
discoveryRuntime.processUpdate(file, code);
|
|
93
90
|
} catch {}
|
|
94
91
|
},
|
|
95
92
|
load: {
|
|
96
93
|
filter: { id: { include: [/^\0virtual:alloy-container$/] } },
|
|
97
94
|
async handler(id) {
|
|
98
95
|
if (id !== resolvedVirtualModuleId) return;
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
const manifestData = await readManifests(options.manifests ?? []);
|
|
110
|
-
const manifestServices = manifestData.services;
|
|
111
|
-
const loadedManifests = manifestData.loadedManifests;
|
|
112
|
-
if (metas.length && manifestServices.length) {
|
|
113
|
-
const duplicates = findDuplicateManifestServices(metas, manifestServices);
|
|
114
|
-
if (duplicates.length) {
|
|
115
|
-
const details = duplicates.map((d) => `- ${d.exportName}: local [${d.localPaths.join(", ")}] vs manifest '${d.manifestImport}'`).join("\n");
|
|
116
|
-
throw new Error([
|
|
117
|
-
"[alloy] Duplicate service registrations detected.",
|
|
118
|
-
details,
|
|
119
|
-
"Resolve by removing one source (local or manifest) to avoid ambiguous DI keys."
|
|
120
|
-
].join("\n"));
|
|
121
|
-
}
|
|
122
|
-
}
|
|
123
|
-
const combinedMetas = [...metas, ...manifestServices.map((svc) => ({
|
|
124
|
-
className: svc.exportName,
|
|
125
|
-
filePath: svc.importPath,
|
|
126
|
-
metadata: {
|
|
127
|
-
scope: svc.scope,
|
|
128
|
-
dependencies: []
|
|
129
|
-
}
|
|
130
|
-
}))];
|
|
131
|
-
const resolver = new IdentifierResolver(combinedMetas);
|
|
132
|
-
const metasByName = groupMetasByName(combinedMetas);
|
|
133
|
-
for (const svc of manifestServices) metas.push(toMetaFromManifest(svc, metasByName, resolver, lazyReferencedClassKeys));
|
|
134
|
-
const providerImports = Array.from(new Set([...providerModuleRefs.map((ref) => ref.importPath), ...manifestData.providers]));
|
|
135
|
-
reconcileLazySet(metas, lazyReferencedClassKeys, collectEagerReferencedNames(metas));
|
|
136
|
-
augmentFactoryLazyServices(metas, lazyServiceKeys);
|
|
137
|
-
const code = generateContainerModule(metas, new Set(lazyReferencedClassKeys), providerImports);
|
|
138
|
-
const dtsDir = path.resolve(resolvedRoot, options.containerDeclarationDir ?? "./src");
|
|
139
|
-
const dtsContent = generateContainerTypeDefinition(metas, (filePath) => {
|
|
140
|
-
if (path.isAbsolute(filePath)) {
|
|
141
|
-
let rel = path.relative(dtsDir, filePath);
|
|
142
|
-
rel = rel.split(path.sep).join(path.posix.sep);
|
|
143
|
-
if (!rel.startsWith(".")) rel = "./" + rel;
|
|
144
|
-
return rel;
|
|
145
|
-
}
|
|
146
|
-
return filePath;
|
|
96
|
+
return loadVirtualContainerModule({
|
|
97
|
+
localMetas: Array.from(discoveryRuntime.discoveredClasses.values()),
|
|
98
|
+
lazyReferencedClassKeys: discoveryRuntime.lazyReferencedClassKeys,
|
|
99
|
+
manifests: options.manifests ?? [],
|
|
100
|
+
providerImportPaths: providerModuleRefs.map((ref) => ref.importPath),
|
|
101
|
+
lazyServiceKeys,
|
|
102
|
+
packageName,
|
|
103
|
+
resolvedRoot,
|
|
104
|
+
containerDeclarationDir: options.containerDeclarationDir,
|
|
105
|
+
resolvedVisualization
|
|
147
106
|
});
|
|
148
|
-
if (!fs.existsSync(dtsDir)) fs.mkdirSync(dtsDir, { recursive: true });
|
|
149
|
-
const dtsPath = path.join(dtsDir, "alloy-container.d.ts");
|
|
150
|
-
fs.writeFileSync(dtsPath, dtsContent);
|
|
151
|
-
if (loadedManifests && loadedManifests.length > 0) {
|
|
152
|
-
const manifestsDts = generateManifestTypeDefinition(loadedManifests.map((m) => ({
|
|
153
|
-
packageName: m.packageName,
|
|
154
|
-
services: m.services
|
|
155
|
-
})));
|
|
156
|
-
const manifestsDtsPath = path.join(dtsDir, "alloy-manifests.d.ts");
|
|
157
|
-
fs.writeFileSync(manifestsDtsPath, manifestsDts);
|
|
158
|
-
}
|
|
159
|
-
if (resolvedVisualization) {
|
|
160
|
-
const artifact = generateMermaidDiagram({
|
|
161
|
-
metas,
|
|
162
|
-
lazyClassKeys: new Set(lazyReferencedClassKeys),
|
|
163
|
-
options: resolvedVisualization.mermaidOptions
|
|
164
|
-
});
|
|
165
|
-
ensureDirectoryForFile(resolvedVisualization.outputPath);
|
|
166
|
-
fs.writeFileSync(resolvedVisualization.outputPath, `${artifact.diagram}\n`);
|
|
167
|
-
}
|
|
168
|
-
return {
|
|
169
|
-
code,
|
|
170
|
-
moduleType: "js"
|
|
171
|
-
};
|
|
172
107
|
}
|
|
173
108
|
}
|
|
174
109
|
};
|
|
175
110
|
}
|
|
176
|
-
function resolveVisualizationOptions(input, projectRoot) {
|
|
177
|
-
if (!input) return null;
|
|
178
|
-
if (typeof input === "boolean") return {
|
|
179
|
-
outputPath: path.resolve(projectRoot, DEFAULT_MERMAID_FILENAME),
|
|
180
|
-
mermaidOptions: void 0
|
|
181
|
-
};
|
|
182
|
-
const mermaidConfig = input.mermaid;
|
|
183
|
-
if (!mermaidConfig) return null;
|
|
184
|
-
if (mermaidConfig === true) return {
|
|
185
|
-
outputPath: path.resolve(projectRoot, DEFAULT_MERMAID_FILENAME),
|
|
186
|
-
mermaidOptions: void 0
|
|
187
|
-
};
|
|
188
|
-
const { outputPath, ...rest } = mermaidConfig;
|
|
189
|
-
return {
|
|
190
|
-
outputPath: path.resolve(projectRoot, outputPath ?? DEFAULT_MERMAID_FILENAME),
|
|
191
|
-
mermaidOptions: Object.keys(rest).length > 0 ? rest : void 0
|
|
192
|
-
};
|
|
193
|
-
}
|
|
194
|
-
function ensureDirectoryForFile(filePath) {
|
|
195
|
-
const dir = path.dirname(filePath);
|
|
196
|
-
if (!fs.existsSync(dir)) fs.mkdirSync(dir, { recursive: true });
|
|
197
|
-
}
|
|
198
111
|
//#endregion
|
|
199
112
|
export { alloy };
|
|
@@ -7,45 +7,72 @@ import { z } from "zod";
|
|
|
7
7
|
* @param inputs Direct manifest objects.
|
|
8
8
|
* @returns Aggregated arrays of service descriptors and provider specifiers.
|
|
9
9
|
*/
|
|
10
|
+
const retrySchema = z.object({
|
|
11
|
+
retries: z.number(),
|
|
12
|
+
backoffMs: z.number().optional(),
|
|
13
|
+
factor: z.number().optional()
|
|
14
|
+
});
|
|
15
|
+
const manifestServiceSchemaV1 = z.object({
|
|
16
|
+
importPath: z.string(),
|
|
17
|
+
exportName: z.string(),
|
|
18
|
+
symbolKey: z.string(),
|
|
19
|
+
scope: z.enum(["singleton", "transient"]),
|
|
20
|
+
deps: z.array(z.string()).default([]),
|
|
21
|
+
tokenDeps: z.array(z.object({
|
|
22
|
+
exportName: z.string(),
|
|
23
|
+
importPath: z.string()
|
|
24
|
+
})).default([]),
|
|
25
|
+
lazyDeps: z.array(z.object({
|
|
26
|
+
importPath: z.string(),
|
|
27
|
+
exportName: z.string(),
|
|
28
|
+
retry: retrySchema.optional()
|
|
29
|
+
})).default([])
|
|
30
|
+
});
|
|
31
|
+
const manifestServiceSchemaV2 = z.object({
|
|
32
|
+
importPath: z.string(),
|
|
33
|
+
exportName: z.string(),
|
|
34
|
+
symbolKey: z.string(),
|
|
35
|
+
scope: z.enum(["singleton", "transient"]),
|
|
36
|
+
deps: z.array(z.discriminatedUnion("kind", [
|
|
37
|
+
z.object({
|
|
38
|
+
kind: z.literal("class"),
|
|
39
|
+
exportName: z.string()
|
|
40
|
+
}),
|
|
41
|
+
z.object({
|
|
42
|
+
kind: z.literal("token"),
|
|
43
|
+
exportName: z.string(),
|
|
44
|
+
importPath: z.string()
|
|
45
|
+
}),
|
|
46
|
+
z.object({
|
|
47
|
+
kind: z.literal("lazy"),
|
|
48
|
+
exportName: z.string(),
|
|
49
|
+
importPath: z.string(),
|
|
50
|
+
retry: retrySchema.optional()
|
|
51
|
+
})
|
|
52
|
+
])).default([])
|
|
53
|
+
});
|
|
54
|
+
const manifestSchemaV1 = z.object({
|
|
55
|
+
schemaVersion: z.number().optional(),
|
|
56
|
+
packageName: z.string(),
|
|
57
|
+
services: z.array(manifestServiceSchemaV1).default([]),
|
|
58
|
+
providers: z.array(z.string()).default([])
|
|
59
|
+
});
|
|
60
|
+
const manifestSchemaV2 = z.object({
|
|
61
|
+
schemaVersion: z.literal(2),
|
|
62
|
+
packageName: z.string(),
|
|
63
|
+
services: z.array(manifestServiceSchemaV2).default([]),
|
|
64
|
+
providers: z.array(z.string()).default([])
|
|
65
|
+
});
|
|
10
66
|
async function readManifests(inputs) {
|
|
11
67
|
const services = [];
|
|
12
68
|
const providers = [];
|
|
13
69
|
const loadedManifests = [];
|
|
14
|
-
const manifestSchema = z.object({
|
|
15
|
-
schemaVersion: z.number().optional(),
|
|
16
|
-
packageName: z.string(),
|
|
17
|
-
services: z.array(z.object({
|
|
18
|
-
importPath: z.string(),
|
|
19
|
-
exportName: z.string(),
|
|
20
|
-
symbolKey: z.string(),
|
|
21
|
-
scope: z.enum(["singleton", "transient"]),
|
|
22
|
-
deps: z.array(z.string()).default([]),
|
|
23
|
-
tokenDeps: z.array(z.object({
|
|
24
|
-
exportName: z.string(),
|
|
25
|
-
importPath: z.string()
|
|
26
|
-
})).default([]),
|
|
27
|
-
lazyDeps: z.array(z.object({
|
|
28
|
-
importPath: z.string(),
|
|
29
|
-
exportName: z.string(),
|
|
30
|
-
retry: z.object({
|
|
31
|
-
retries: z.number(),
|
|
32
|
-
backoffMs: z.number().optional(),
|
|
33
|
-
factor: z.number().optional()
|
|
34
|
-
}).optional()
|
|
35
|
-
})).default([])
|
|
36
|
-
})).default([]),
|
|
37
|
-
providers: z.array(z.string()).default([])
|
|
38
|
-
});
|
|
39
70
|
for (const manifest of inputs) {
|
|
40
|
-
const parsed =
|
|
41
|
-
if (!parsed
|
|
42
|
-
loadedManifests.push(
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
providers: parsed.data.providers
|
|
46
|
-
});
|
|
47
|
-
for (const svc of parsed.data.services) services.push(svc);
|
|
48
|
-
for (const p of parsed.data.providers) providers.push(p);
|
|
71
|
+
const parsed = readManifestByVersion(manifest);
|
|
72
|
+
if (!parsed) continue;
|
|
73
|
+
loadedManifests.push(parsed);
|
|
74
|
+
for (const svc of parsed.services) services.push(svc);
|
|
75
|
+
for (const p of parsed.providers) providers.push(p);
|
|
49
76
|
}
|
|
50
77
|
return Promise.resolve({
|
|
51
78
|
services,
|
|
@@ -53,6 +80,35 @@ async function readManifests(inputs) {
|
|
|
53
80
|
loadedManifests
|
|
54
81
|
});
|
|
55
82
|
}
|
|
83
|
+
function readManifestByVersion(manifest) {
|
|
84
|
+
return (manifest.schemaVersion ?? 1) === 2 ? readManifestV2(manifest) : readManifestV1(manifest);
|
|
85
|
+
}
|
|
86
|
+
function readManifestV1(manifest) {
|
|
87
|
+
const parsed = manifestSchemaV1.safeParse(manifest);
|
|
88
|
+
if (!parsed.success) return null;
|
|
89
|
+
return {
|
|
90
|
+
schemaVersion: 1,
|
|
91
|
+
packageName: parsed.data.packageName,
|
|
92
|
+
services: parsed.data.services.map((svc) => ({
|
|
93
|
+
...svc,
|
|
94
|
+
schemaVersion: 1
|
|
95
|
+
})),
|
|
96
|
+
providers: parsed.data.providers
|
|
97
|
+
};
|
|
98
|
+
}
|
|
99
|
+
function readManifestV2(manifest) {
|
|
100
|
+
const parsed = manifestSchemaV2.safeParse(manifest);
|
|
101
|
+
if (!parsed.success) return null;
|
|
102
|
+
return {
|
|
103
|
+
schemaVersion: 2,
|
|
104
|
+
packageName: parsed.data.packageName,
|
|
105
|
+
services: parsed.data.services.map((svc) => ({
|
|
106
|
+
...svc,
|
|
107
|
+
schemaVersion: 2
|
|
108
|
+
})),
|
|
109
|
+
providers: parsed.data.providers
|
|
110
|
+
};
|
|
111
|
+
}
|
|
56
112
|
/**
|
|
57
113
|
* Groups metas by class name to support resolving dependencies that reference classes with collisions.
|
|
58
114
|
*
|
|
@@ -98,21 +154,22 @@ function selectMetaForDep(metasByName, depName, currentImportPath) {
|
|
|
98
154
|
function toMetaFromManifest(svc, metasByName, resolver, lazySet) {
|
|
99
155
|
const deps = [];
|
|
100
156
|
const referencedImports = [];
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
157
|
+
if (svc.schemaVersion === 2) appendDependenciesFromManifestV2(svc, deps, referencedImports, metasByName, resolver, lazySet);
|
|
158
|
+
else appendDependenciesFromManifestV1(svc, deps, referencedImports, metasByName, resolver, lazySet);
|
|
159
|
+
const metadata = {
|
|
160
|
+
scope: svc.scope,
|
|
161
|
+
dependencies: deps
|
|
162
|
+
};
|
|
163
|
+
return {
|
|
164
|
+
className: svc.exportName,
|
|
165
|
+
filePath: svc.importPath,
|
|
166
|
+
identifierKey: svc.symbolKey,
|
|
167
|
+
metadata,
|
|
168
|
+
referencedImports
|
|
169
|
+
};
|
|
170
|
+
}
|
|
171
|
+
function appendDependenciesFromManifestV1(svc, deps, referencedImports, metasByName, resolver, lazySet) {
|
|
172
|
+
for (const depName of svc.deps ?? []) deps.push(createClassOrTokenDependency(depName, svc.importPath, metasByName, resolver));
|
|
116
173
|
if (Array.isArray(svc.tokenDeps)) for (const tok of svc.tokenDeps) {
|
|
117
174
|
deps.push({
|
|
118
175
|
expression: tok.exportName,
|
|
@@ -126,31 +183,63 @@ function toMetaFromManifest(svc, metasByName, resolver, lazySet) {
|
|
|
126
183
|
});
|
|
127
184
|
}
|
|
128
185
|
for (const lazy of svc.lazyDeps ?? []) {
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
186
|
+
deps.push(createLazyDependencyDescriptor(lazy));
|
|
187
|
+
lazySet.add(createClassKey(lazy.importPath, lazy.exportName));
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
function appendDependenciesFromManifestV2(svc, deps, referencedImports, metasByName, resolver, lazySet) {
|
|
191
|
+
for (const dep of svc.deps) appendV2Dependency(dep, svc.importPath, deps, referencedImports, metasByName, resolver, lazySet);
|
|
192
|
+
}
|
|
193
|
+
function appendV2Dependency(dep, currentImportPath, deps, referencedImports, metasByName, resolver, lazySet) {
|
|
194
|
+
if (dep.kind === "class") {
|
|
195
|
+
deps.push(createClassOrTokenDependency(dep.exportName, currentImportPath, metasByName, resolver));
|
|
196
|
+
return;
|
|
197
|
+
}
|
|
198
|
+
if (dep.kind === "token") {
|
|
137
199
|
deps.push({
|
|
138
|
-
expression:
|
|
139
|
-
referencedIdentifiers: [],
|
|
140
|
-
isLazy:
|
|
200
|
+
expression: dep.exportName,
|
|
201
|
+
referencedIdentifiers: [dep.exportName],
|
|
202
|
+
isLazy: false
|
|
141
203
|
});
|
|
142
|
-
|
|
204
|
+
referencedImports.push({
|
|
205
|
+
name: dep.exportName,
|
|
206
|
+
path: dep.importPath,
|
|
207
|
+
originalName: dep.exportName
|
|
208
|
+
});
|
|
209
|
+
return;
|
|
143
210
|
}
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
211
|
+
deps.push(createLazyDependencyDescriptor(dep));
|
|
212
|
+
lazySet.add(createClassKey(dep.importPath, dep.exportName));
|
|
213
|
+
}
|
|
214
|
+
function createClassOrTokenDependency(depName, currentImportPath, metasByName, resolver) {
|
|
215
|
+
const targetMeta = selectMetaForDep(metasByName, depName, currentImportPath);
|
|
216
|
+
if (targetMeta) {
|
|
217
|
+
const expression = resolver.resolve(targetMeta.className, targetMeta.filePath);
|
|
218
|
+
return {
|
|
219
|
+
expression,
|
|
220
|
+
referencedIdentifiers: [expression],
|
|
221
|
+
isLazy: false
|
|
222
|
+
};
|
|
223
|
+
}
|
|
224
|
+
return {
|
|
225
|
+
expression: depName,
|
|
226
|
+
referencedIdentifiers: [depName],
|
|
227
|
+
isLazy: false
|
|
147
228
|
};
|
|
229
|
+
}
|
|
230
|
+
function createLazyDependencyDescriptor(lazy) {
|
|
231
|
+
const importer = `() => import('${lazy.importPath}').then(m => m.${lazy.exportName})`;
|
|
232
|
+
let expression = `Lazy(${importer})`;
|
|
233
|
+
if (lazy.retry) {
|
|
234
|
+
const opts = [`retries: ${lazy.retry.retries}`];
|
|
235
|
+
if (typeof lazy.retry.backoffMs === "number") opts.push(`backoffMs: ${lazy.retry.backoffMs}`);
|
|
236
|
+
if (typeof lazy.retry.factor === "number") opts.push(`factor: ${lazy.retry.factor}`);
|
|
237
|
+
expression = `Lazy(${importer}, { ${opts.join(", ")} })`;
|
|
238
|
+
}
|
|
148
239
|
return {
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
metadata,
|
|
153
|
-
referencedImports
|
|
240
|
+
expression,
|
|
241
|
+
referencedIdentifiers: [],
|
|
242
|
+
isLazy: true
|
|
154
243
|
};
|
|
155
244
|
}
|
|
156
245
|
/**
|
|
@@ -200,12 +289,22 @@ function augmentFactoryLazyServices(metas, lazyServiceKeys) {
|
|
|
200
289
|
* Returns structured info for error reporting.
|
|
201
290
|
*/
|
|
202
291
|
function findDuplicateManifestServices(localMetas, manifestServices) {
|
|
203
|
-
const
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
292
|
+
const localMetasByIdentifier = /* @__PURE__ */ new Map();
|
|
293
|
+
for (const meta of localMetas) {
|
|
294
|
+
const identifierKey = meta.identifierKey ?? createSymbolKey(meta.filePath, meta.className);
|
|
295
|
+
const matches = localMetasByIdentifier.get(identifierKey) ?? [];
|
|
296
|
+
matches.push(meta);
|
|
297
|
+
localMetasByIdentifier.set(identifierKey, matches);
|
|
298
|
+
}
|
|
299
|
+
return manifestServices.flatMap((svc) => {
|
|
300
|
+
const matches = localMetasByIdentifier.get(svc.symbolKey);
|
|
301
|
+
if (!matches?.length) return [];
|
|
302
|
+
return [{
|
|
303
|
+
exportName: svc.exportName,
|
|
304
|
+
localPaths: matches.map((m) => normalizeImportPath(m.filePath)),
|
|
305
|
+
manifestImport: svc.importPath
|
|
306
|
+
}];
|
|
307
|
+
});
|
|
209
308
|
}
|
|
210
309
|
//#endregion
|
|
211
310
|
export { augmentFactoryLazyServices, collectEagerReferencedNames, findDuplicateManifestServices, groupMetasByName, readManifests, reconcileLazySet, toMetaFromManifest };
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { MermaidDiagramOptions } from "./visualizer.js";
|
|
2
|
+
|
|
3
|
+
//#region src/plugins/vite-plugin/visualization-utils.d.ts
|
|
4
|
+
interface AlloyMermaidVisualizerOptions extends MermaidDiagramOptions {
|
|
5
|
+
outputPath?: string;
|
|
6
|
+
}
|
|
7
|
+
interface AlloyVisualizationOptions {
|
|
8
|
+
/**
|
|
9
|
+
* Configure Mermaid diagram emission. Use `true` for defaults or provide
|
|
10
|
+
* overrides for layout, colors, or output path.
|
|
11
|
+
*/
|
|
12
|
+
mermaid?: boolean | AlloyMermaidVisualizerOptions;
|
|
13
|
+
}
|
|
14
|
+
//#endregion
|
|
15
|
+
export { AlloyMermaidVisualizerOptions, AlloyVisualizationOptions };
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import path from "node:path";
|
|
2
|
+
import fs from "node:fs";
|
|
3
|
+
//#region src/plugins/vite-plugin/visualization-utils.ts
|
|
4
|
+
const DEFAULT_MERMAID_FILENAME = "alloy-di.mmd";
|
|
5
|
+
function resolveVisualizationOptions(input, projectRoot) {
|
|
6
|
+
if (!input) return null;
|
|
7
|
+
if (typeof input === "boolean") return {
|
|
8
|
+
outputPath: path.resolve(projectRoot, DEFAULT_MERMAID_FILENAME),
|
|
9
|
+
mermaidOptions: void 0
|
|
10
|
+
};
|
|
11
|
+
const mermaidConfig = input.mermaid;
|
|
12
|
+
if (!mermaidConfig) return null;
|
|
13
|
+
if (mermaidConfig === true) return {
|
|
14
|
+
outputPath: path.resolve(projectRoot, DEFAULT_MERMAID_FILENAME),
|
|
15
|
+
mermaidOptions: void 0
|
|
16
|
+
};
|
|
17
|
+
const { outputPath, ...rest } = mermaidConfig;
|
|
18
|
+
return {
|
|
19
|
+
outputPath: path.resolve(projectRoot, outputPath ?? "alloy-di.mmd"),
|
|
20
|
+
mermaidOptions: Object.keys(rest).length > 0 ? rest : void 0
|
|
21
|
+
};
|
|
22
|
+
}
|
|
23
|
+
function ensureDirectoryForFile(filePath) {
|
|
24
|
+
const dir = path.dirname(filePath);
|
|
25
|
+
if (!fs.existsSync(dir)) fs.mkdirSync(dir, { recursive: true });
|
|
26
|
+
}
|
|
27
|
+
//#endregion
|
|
28
|
+
export { ensureDirectoryForFile, resolveVisualizationOptions };
|
|
@@ -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-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/scanner.test.ts","../src/plugins/core/scanner.ts","../src/plugins/core/types.ts","../src/plugins/core/utils.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/codegen.specifier.test.ts","../src/plugins/vite-plugin/duplicate-registrations.test.ts","../src/plugins/vite-plugin/fixture-subpaths.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/manifest-utils.ts","../src/plugins/vite-plugin/manifest-utils.validation.test.ts","../src/plugins/vite-plugin/module-generation.test.ts","../src/plugins/vite-plugin/test-utils.ts","../src/plugins/vite-plugin/transform-guards.test.ts","../src/plugins/vite-plugin/visualization-option.test.ts","../src/plugins/vite-plugin/visualizer.test.ts","../src/plugins/vite-plugin/visualizer.ts"],"version":"6.0.3"}
|
|
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-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/scanner.test.ts","../src/plugins/core/scanner.ts","../src/plugins/core/types.ts","../src/plugins/core/utils.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/codegen.specifier.test.ts","../src/plugins/vite-plugin/container-loader.test.ts","../src/plugins/vite-plugin/container-loader.ts","../src/plugins/vite-plugin/discovery-runtime.ts","../src/plugins/vite-plugin/duplicate-registrations.test.ts","../src/plugins/vite-plugin/fixture-subpaths.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/manifest-utils.ts","../src/plugins/vite-plugin/manifest-utils.validation.test.ts","../src/plugins/vite-plugin/module-generation.test.ts","../src/plugins/vite-plugin/test-utils.ts","../src/plugins/vite-plugin/transform-guards.test.ts","../src/plugins/vite-plugin/visualization-option.test.ts","../src/plugins/vite-plugin/visualization-utils.ts","../src/plugins/vite-plugin/visualizer.test.ts","../src/plugins/vite-plugin/visualizer.ts"],"version":"6.0.3"}
|