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.
@@ -1,13 +1,10 @@
1
- import { createClassKey, normalizeImportPath, walkSync } from "../core/utils.js";
2
- import { IdentifierResolver } from "../core/identifier-resolver.js";
3
- import { generateContainerModule, generateContainerTypeDefinition, generateManifestTypeDefinition } from "../core/codegen.js";
4
- import { createDiscoveryStore } from "../core/discovery-store.js";
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 discovery = createDiscoveryStore();
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.file;
77
- const inAnyGraph = Object.values(ctx.server.environments).some((env) => env.moduleGraph.getModulesByFile(file)?.size);
78
- if (ctx.type === "delete" || !inAnyGraph) {
79
- const removed = discovery.removeFile(file);
80
- if (removed.previousMetas) for (const meta of removed.previousMetas) discoveredClasses.delete(createClassKey(meta.filePath, meta.className));
81
- if (removed.previousLazyClassKeys) for (const key of removed.previousLazyClassKeys) lazyReferencedClassKeys.delete(key);
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 ctx.modules;
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
- discovery.clear();
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
- processUpdate(file, fs.readFileSync(file, "utf-8"));
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
- const metas = Array.from(discoveredClasses.values());
100
- for (const meta of metas) {
101
- const normalizedMetaPath = normalizeImportPath(meta.filePath);
102
- const trimmedNormalizedMetaPath = normalizedMetaPath.replaceAll(/^\/+/g, "");
103
- const looksRootRelative = normalizedMetaPath === "/src" || normalizedMetaPath.startsWith("/src/");
104
- let relPath = path.relative(resolvedRoot, meta.filePath);
105
- if (path.sep === "\\") relPath = relPath.split(path.sep).join("/");
106
- if (looksRootRelative || !relPath || relPath.startsWith("..") || relPath.startsWith("\\")) relPath = trimmedNormalizedMetaPath || normalizedMetaPath.replaceAll(/^\/+/g, "");
107
- meta.identifierKey = `alloy:${packageName}/${relPath}#${meta.className}`;
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 = manifestSchema.safeParse(manifest);
41
- if (!parsed.success) continue;
42
- loadedManifests.push({
43
- packageName: parsed.data.packageName,
44
- services: parsed.data.services,
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
- for (const depName of svc.deps ?? []) {
102
- const targetMeta = selectMetaForDep(metasByName, depName, svc.importPath);
103
- if (targetMeta) {
104
- const expression = resolver.resolve(targetMeta.className, targetMeta.filePath);
105
- deps.push({
106
- expression,
107
- referencedIdentifiers: [expression],
108
- isLazy: false
109
- });
110
- } else deps.push({
111
- expression: depName,
112
- referencedIdentifiers: [depName],
113
- isLazy: false
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
- const importer = `() => import('${lazy.importPath}').then(m => m.${lazy.exportName})`;
130
- let expr;
131
- if (lazy.retry) {
132
- const opts = [`retries: ${lazy.retry.retries}`];
133
- if (typeof lazy.retry.backoffMs === "number") opts.push(`backoffMs: ${lazy.retry.backoffMs}`);
134
- if (typeof lazy.retry.factor === "number") opts.push(`factor: ${lazy.retry.factor}`);
135
- expr = `Lazy(${importer}, { ${opts.join(", ")} })`;
136
- } else expr = `Lazy(${importer})`;
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: expr,
139
- referencedIdentifiers: [],
140
- isLazy: true
200
+ expression: dep.exportName,
201
+ referencedIdentifiers: [dep.exportName],
202
+ isLazy: false
141
203
  });
142
- lazySet.add(createClassKey(lazy.importPath, lazy.exportName));
204
+ referencedImports.push({
205
+ name: dep.exportName,
206
+ path: dep.importPath,
207
+ originalName: dep.exportName
208
+ });
209
+ return;
143
210
  }
144
- const metadata = {
145
- scope: svc.scope,
146
- dependencies: deps
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
- className: svc.exportName,
150
- filePath: svc.importPath,
151
- identifierKey: svc.symbolKey,
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 discoveredNames = new Set(localMetas.map((m) => m.className));
204
- return manifestServices.filter((svc) => discoveredNames.has(svc.exportName)).map((d) => ({
205
- exportName: d.exportName,
206
- localPaths: localMetas.filter((m) => m.className === d.exportName).map((m) => normalizeImportPath(m.filePath)),
207
- manifestImport: d.importPath
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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "alloy-di",
3
- "version": "1.2.0",
3
+ "version": "1.2.3",
4
4
  "description": "A compile-time dependency injection plugin for Vite",
5
5
  "keywords": [
6
6
  "dependency-injection",