@analogjs/vite-plugin-angular 3.0.0-alpha.41 → 3.0.0-alpha.43

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.
Files changed (37) hide show
  1. package/package.json +1 -1
  2. package/src/lib/angular-jit-plugin.js +1 -1
  3. package/src/lib/angular-vite-plugin.d.ts +3 -77
  4. package/src/lib/angular-vite-plugin.js +77 -1012
  5. package/src/lib/angular-vite-plugin.js.map +1 -1
  6. package/src/lib/compilation-api/compilation-api-plugin.d.ts +29 -0
  7. package/src/lib/compilation-api/compilation-api-plugin.js +468 -0
  8. package/src/lib/compilation-api/compilation-api-plugin.js.map +1 -0
  9. package/src/lib/compilation-api/index.d.ts +1 -0
  10. package/src/lib/compilation-api/index.js +1 -0
  11. package/src/lib/compiler/compile.js +2 -2
  12. package/src/lib/compiler/defer.js +1 -1
  13. package/src/lib/compiler/js-emitter.js +1 -1
  14. package/src/lib/encapsulation-plugin.d.ts +13 -0
  15. package/src/lib/encapsulation-plugin.js +48 -0
  16. package/src/lib/encapsulation-plugin.js.map +1 -0
  17. package/src/lib/fast-compile-plugin.js +2 -28
  18. package/src/lib/fast-compile-plugin.js.map +1 -1
  19. package/src/lib/host.js +1 -1
  20. package/src/lib/stylesheet-registry.js +1 -1
  21. package/src/lib/tailwind-plugin.d.ts +34 -0
  22. package/src/lib/tailwind-plugin.js +116 -0
  23. package/src/lib/tailwind-plugin.js.map +1 -0
  24. package/src/lib/template-class-binding-guard-plugin.d.ts +30 -0
  25. package/src/lib/template-class-binding-guard-plugin.js +237 -0
  26. package/src/lib/template-class-binding-guard-plugin.js.map +1 -0
  27. package/src/lib/utils/compilation-shared.d.ts +58 -0
  28. package/src/lib/utils/compilation-shared.js +133 -0
  29. package/src/lib/utils/compilation-shared.js.map +1 -0
  30. package/src/lib/utils/tsconfig-resolver.d.ts +28 -0
  31. package/src/lib/utils/tsconfig-resolver.js +191 -0
  32. package/src/lib/utils/tsconfig-resolver.js.map +1 -0
  33. package/src/lib/utils/virtual-resources.js +4 -31
  34. package/src/lib/utils/virtual-resources.js.map +1 -1
  35. package/src/lib/virtual-modules-plugin.d.ts +5 -0
  36. package/src/lib/virtual-modules-plugin.js +50 -0
  37. package/src/lib/virtual-modules-plugin.js.map +1 -0
@@ -1,51 +1,38 @@
1
- import { angularFullVersion, cjt, createAngularCompilation, sourceFileCache } from "./utils/devkit.js";
1
+ import { angularFullVersion, cjt, sourceFileCache } from "./utils/devkit.js";
2
2
  import { getJsTransformConfigKey, isRolldown } from "./utils/rolldown.js";
3
3
  import { buildOptimizerPlugin } from "./angular-build-optimizer-plugin.js";
4
- import { activateDeferredDebug, applyDebugOption, debugCompilationApi, debugCompiler, debugCompilerV, debugEmit, debugEmitV, debugHmr, debugHmrV, debugStyles, debugStylesV, debugTailwind, debugTailwindV } from "./utils/debug.js";
5
- import { inspectCssTailwindDirectives, isTailwindReferenceError, throwTailwindReferenceTextError } from "./utils/tailwind-reference.js";
4
+ import { activateDeferredDebug, applyDebugOption, debugCompiler, debugCompilerV, debugEmit, debugEmitV, debugHmr, debugHmrV, debugStyles, debugStylesV } from "./utils/debug.js";
6
5
  import { toVirtualRawId, toVirtualStyleId } from "./utils/virtual-ids.js";
7
- import { loadVirtualRawModule, loadVirtualStyleModule, shouldPreprocessTestCss } from "./utils/virtual-resources.js";
8
6
  import { jitPlugin } from "./angular-jit-plugin.js";
9
7
  import { createCompilerPlugin, createRolldownCompilerPlugin } from "./compiler-plugin.js";
10
8
  import { StyleUrlsResolver, TemplateUrlsResolver, getAngularComponentMetadata } from "./component-resolvers.js";
11
- import { composeStylePreprocessors, normalizeStylesheetDependencies } from "./style-preprocessor.js";
12
- import { AnalogStylesheetRegistry, preprocessStylesheet, preprocessStylesheetResult, registerStylesheetContent, rewriteRelativeCssImports } from "./stylesheet-registry.js";
9
+ import { AnalogStylesheetRegistry, preprocessStylesheet, rewriteRelativeCssImports } from "./stylesheet-registry.js";
13
10
  import { augmentHostWithCaching, augmentHostWithResources, augmentProgramWithVersioning, mergeTransformers } from "./host.js";
14
11
  import { TS_EXT_REGEX, createTsConfigGetter, getTsConfigPath } from "./utils/plugin-config.js";
12
+ import { TsconfigResolver } from "./utils/tsconfig-resolver.js";
13
+ import { configureStylePipelineRegistry } from "./style-pipeline.js";
14
+ import { describeStylesheetContent, injectViteIgnoreForHmrMetadata, isIgnoredHmrFile, isTestWatchMode, refreshStylesheetRegistryForFile } from "./utils/compilation-shared.js";
15
+ import { compilationAPIPlugin } from "./compilation-api/compilation-api-plugin.js";
16
+ import "./compilation-api/index.js";
15
17
  import { fastCompilePlugin } from "./fast-compile-plugin.js";
18
+ import { removeActiveGraphMetadata, removeStyleOwnerMetadata, templateClassBindingGuardPlugin } from "./template-class-binding-guard-plugin.js";
19
+ import { buildStylePreprocessor, tailwindReferencePlugin, validateTailwindConfig } from "./tailwind-plugin.js";
20
+ import { encapsulationPlugin, getComponentStyleSheetMeta, isComponentStyleSheet } from "./encapsulation-plugin.js";
21
+ import { virtualModulesPlugin } from "./virtual-modules-plugin.js";
16
22
  import { angularVitestPlugins } from "./angular-vitest-plugin.js";
17
23
  import { pendingTasksPlugin } from "./angular-pending-tasks.plugin.js";
18
24
  import { liveReloadPlugin } from "./live-reload-plugin.js";
19
25
  import { nxFolderPlugin } from "./nx-folder-plugin.js";
20
26
  import { replaceFiles } from "./plugins/file-replacements.plugin.js";
21
27
  import { routerPlugin } from "./router-plugin.js";
22
- import { configureStylePipelineRegistry, stylePipelinePreprocessorFromPlugins } from "./style-pipeline.js";
23
28
  import { union } from "es-toolkit";
24
- import { createHash } from "node:crypto";
25
- import { existsSync, mkdirSync, promises, readFileSync, statSync, writeFileSync } from "node:fs";
26
- import { basename, dirname, isAbsolute, join, relative, resolve } from "node:path";
29
+ import { existsSync, mkdirSync, readFileSync, statSync, writeFileSync } from "node:fs";
30
+ import { basename, dirname, join, relative, resolve } from "node:path";
27
31
  import * as compilerCli from "@angular/compiler-cli";
28
32
  import { createRequire } from "node:module";
29
- import * as ngCompiler from "@angular/compiler";
30
- import { globSync } from "tinyglobby";
31
33
  import { defaultClientConditions, normalizePath, preprocessCSS } from "vite";
32
34
  //#region packages/vite-plugin-angular/src/lib/angular-vite-plugin.ts
33
35
  var require = createRequire(import.meta.url);
34
- var DiagnosticModes = /* @__PURE__ */ function(DiagnosticModes) {
35
- DiagnosticModes[DiagnosticModes["None"] = 0] = "None";
36
- DiagnosticModes[DiagnosticModes["Option"] = 1] = "Option";
37
- DiagnosticModes[DiagnosticModes["Syntactic"] = 2] = "Syntactic";
38
- DiagnosticModes[DiagnosticModes["Semantic"] = 4] = "Semantic";
39
- DiagnosticModes[DiagnosticModes["All"] = 7] = "All";
40
- return DiagnosticModes;
41
- }({});
42
- function normalizeIncludeGlob(workspaceRoot, glob) {
43
- const normalizedWorkspaceRoot = normalizePath(resolve(workspaceRoot));
44
- const normalizedGlob = normalizePath(glob);
45
- if (normalizedGlob === normalizedWorkspaceRoot || normalizedGlob.startsWith(`${normalizedWorkspaceRoot}/`)) return normalizedGlob;
46
- if (normalizedGlob.startsWith("/")) return `${normalizedWorkspaceRoot}${normalizedGlob}`;
47
- return normalizePath(resolve(normalizedWorkspaceRoot, normalizedGlob));
48
- }
49
36
  var classNames = /* @__PURE__ */ new Map();
50
37
  function evictDeletedFileMetadata(file, { removeActiveGraphMetadata, removeStyleOwnerMetadata, classNamesMap, fileTransformMap }) {
51
38
  const normalizedFile = normalizePath(file.split("?")[0]);
@@ -54,63 +41,6 @@ function evictDeletedFileMetadata(file, { removeActiveGraphMetadata, removeStyle
54
41
  classNamesMap.delete(normalizedFile);
55
42
  fileTransformMap.delete(normalizedFile);
56
43
  }
57
- function injectViteIgnoreForHmrMetadata(code) {
58
- let patched = code.replace(/\bimport\(([a-zA-Z_$][\w$]*\.\u0275\u0275getReplaceMetadataURL)/g, "import(/* @vite-ignore */ $1");
59
- if (patched === code) patched = patched.replace(/import\((\S+getReplaceMetadataURL)/g, "import(/* @vite-ignore */ $1");
60
- return patched;
61
- }
62
- function isIgnoredHmrFile(file) {
63
- return file.endsWith(".tsbuildinfo");
64
- }
65
- /**
66
- * Builds a resolved stylePreprocessor function from plugin options.
67
- *
68
- * When `tailwindCss` is configured, creates an injector that prepends
69
- * `@reference "<rootStylesheet>"` into component CSS that uses Tailwind
70
- * utilities. Uses absolute paths because Angular's externalRuntimeStyles
71
- * serves component CSS as virtual modules (hash-based IDs) with no
72
- * meaningful directory — relative paths can't resolve from a hash.
73
- *
74
- * If both `tailwindCss` and `stylePreprocessor` are provided, they are
75
- * chained: Tailwind reference injection runs first, then the user's
76
- * custom preprocessor.
77
- */
78
- function buildStylePreprocessor(options) {
79
- const userPreprocessor = options?.stylePreprocessor;
80
- const stylePipelinePreprocessor = stylePipelinePreprocessorFromPlugins(options?.stylePipeline);
81
- const tw = options?.tailwindCss;
82
- if (!tw && !userPreprocessor && !stylePipelinePreprocessor) return;
83
- let tailwindPreprocessor;
84
- if (tw) {
85
- const rootStylesheet = tw.rootStylesheet;
86
- const prefixes = tw.prefixes;
87
- debugTailwind("configured", {
88
- rootStylesheet,
89
- prefixes
90
- });
91
- if (!existsSync(rootStylesheet)) console.warn(`[@analogjs/vite-plugin-angular] tailwindCss.rootStylesheet not found at "${rootStylesheet}". @reference directives will point to a non-existent file, which will cause Tailwind CSS errors. Ensure the path is absolute and the file exists.`);
92
- tailwindPreprocessor = (code, filename) => {
93
- const directiveState = inspectCssTailwindDirectives(code);
94
- if (directiveState.hasReferenceDirective || directiveState.hasTailwindImportDirective) {
95
- debugTailwindV("skip (already has @reference or is root)", { filename });
96
- return code;
97
- }
98
- if (!(prefixes ? prefixes.some((prefix) => directiveState.commentlessCode.includes(prefix)) : directiveState.commentlessCode.includes("@apply"))) {
99
- debugTailwindV("skip (no Tailwind usage detected)", { filename });
100
- return code;
101
- }
102
- if (directiveState.hasReferenceText) throwTailwindReferenceTextError(filename, rootStylesheet);
103
- debugTailwind("injected @reference via preprocessor", { filename });
104
- return `@reference "${rootStylesheet.replace(/\\/g, "/")}";\n${code}`;
105
- };
106
- }
107
- if (tailwindPreprocessor && (stylePipelinePreprocessor || userPreprocessor)) debugTailwind("chained with style pipeline or user stylePreprocessor");
108
- return composeStylePreprocessors([
109
- tailwindPreprocessor,
110
- stylePipelinePreprocessor,
111
- userPreprocessor
112
- ]);
113
- }
114
44
  function angular(options) {
115
45
  applyDebugOption(options?.debug, options?.workspaceRoot);
116
46
  const liveReload = options?.liveReload ?? true;
@@ -146,17 +76,21 @@ function angular(options) {
146
76
  const ts = require("typescript");
147
77
  let builder;
148
78
  let nextProgram;
149
- const tsconfigOptionsCache = /* @__PURE__ */ new Map();
150
- const tsconfigGraphRootCache = /* @__PURE__ */ new Map();
151
79
  let cachedHost;
152
80
  let cachedHostKey;
153
- let includeCache = [];
81
+ const isTest = process.env.NODE_ENV === "test" || !!process.env["VITEST"];
82
+ const tsconfigResolver = new TsconfigResolver({
83
+ workspaceRoot: pluginOptions.workspaceRoot,
84
+ include: pluginOptions.include,
85
+ liveReload: pluginOptions.liveReload,
86
+ hasTailwindCss: pluginOptions.hasTailwindCss,
87
+ isTest
88
+ });
154
89
  function invalidateFsCaches() {
155
- includeCache = [];
90
+ tsconfigResolver.invalidateIncludeCache();
156
91
  }
157
92
  function invalidateTsconfigCaches() {
158
- tsconfigOptionsCache.clear();
159
- tsconfigGraphRootCache.clear();
93
+ tsconfigResolver.invalidateTsconfigCaches();
160
94
  cachedHost = void 0;
161
95
  cachedHostKey = void 0;
162
96
  }
@@ -193,140 +127,26 @@ function angular(options) {
193
127
  if (!(isTest ? testWatchMode : watchMode)) return false;
194
128
  return !!(shouldEnableLiveReload() || pluginOptions.hasTailwindCss);
195
129
  }
196
- /**
197
- * Validates the Tailwind CSS integration configuration and emits actionable
198
- * warnings for common misconfigurations that cause silent failures.
199
- *
200
- * Called once during `configResolved` when `tailwindCss` is configured.
201
- */
202
- function validateTailwindConfig(config, isWatchMode) {
203
- const PREFIX = "[@analogjs/vite-plugin-angular]";
204
- const tw = pluginOptions.tailwindCss;
205
- if (!tw) return;
206
- if (!isAbsolute(tw.rootStylesheet)) console.warn(`${PREFIX} tailwindCss.rootStylesheet must be an absolute path. Got: "${tw.rootStylesheet}". Use path.resolve(__dirname, '...') in your vite.config to convert it.`);
207
- const resolvedPlugins = config.plugins;
208
- const hasTailwindPlugin = resolvedPlugins.some((p) => p.name.startsWith("@tailwindcss/vite") || p.name.startsWith("tailwindcss"));
209
- if (isWatchMode && !hasTailwindPlugin) throw new Error(`${PREFIX} tailwindCss is configured but no @tailwindcss/vite plugin was found. Component CSS with @apply directives will not be processed.\n\n Fix: npm install @tailwindcss/vite --save-dev\n Then add tailwindcss() to your vite.config plugins array.\n`);
210
- if (isWatchMode && tw.rootStylesheet) {
211
- const projectRoot = normalizePath(config.root);
212
- const normalizedRootStylesheet = normalizePath(tw.rootStylesheet);
213
- if (!normalizedRootStylesheet.startsWith(projectRoot)) {
214
- if (!(config.server?.fs?.allow ?? []).some((allowed) => normalizedRootStylesheet.startsWith(normalizePath(allowed)))) console.warn(`${PREFIX} tailwindCss.rootStylesheet is outside the Vite project root. The dev server may reject it with 403.\n\n Root: ${projectRoot}\n Stylesheet: ${tw.rootStylesheet}\n\n Fix: server.fs.allow: ['${dirname(tw.rootStylesheet)}']\n`);
215
- }
216
- }
217
- if (tw.prefixes !== void 0 && tw.prefixes.length === 0) console.warn(`${PREFIX} tailwindCss.prefixes is an empty array. No component stylesheets will receive @reference injection. Either remove the prefixes option (to use @apply detection) or specify your prefixes: ['tw:']\n`);
218
- /**
219
- * Duplicate analog() registrations are a real bug for the non-SSR/client
220
- * build because each plugin instance creates its own component-style state.
221
- *
222
- * That state includes the style maps/registries used to:
223
- * - track transformed component styles
224
- * - map owner components back to stylesheet requests
225
- * - coordinate Tailwind/@reference processing and style reload behavior
226
- *
227
- * If two plugin instances are active for the same client build, one
228
- * instance can record stylesheet metadata while the other services the
229
- * request. The result is "missing" component CSS even though compilation
230
- * appeared to succeed.
231
- *
232
- * SSR is different. Analog's Nitro/SSR build path reuses the already
233
- * resolved plugin graph and then runs an additional `build.ssr === true`
234
- * pass for the server bundle. In that flow Vite can expose multiple
235
- * `@analogjs/vite-plugin-angular` entries in `config.plugins`, but that is
236
- * not the same failure mode as a duplicated client build. The server build
237
- * does not rely on the client-side style maps that this guard is protecting.
238
- *
239
- * Because of that, we only throw for duplicate registrations on non-SSR
240
- * builds. Throwing during SSR would be a false positive that breaks valid
241
- * Analog SSR/Nitro builds.
242
- */
243
- const analogInstances = resolvedPlugins.filter((p) => p.name === "@analogjs/vite-plugin-angular");
244
- if (analogInstances.length > 1 && !config.build?.ssr) throw new Error(`${PREFIX} analog() is registered ${analogInstances.length} times. Each instance creates separate style maps, causing component styles to be lost. Remove duplicate registrations.`);
245
- if (existsSync(tw.rootStylesheet)) try {
246
- const rootContent = readFileSync(tw.rootStylesheet, "utf-8");
247
- if (!rootContent.includes("@import \"tailwindcss\"") && !rootContent.includes("@import 'tailwindcss'")) console.warn(`${PREFIX} tailwindCss.rootStylesheet does not contain @import "tailwindcss". The @reference directive will point to a file without Tailwind configuration.\n\n File: ${tw.rootStylesheet}\n`);
248
- } catch {}
249
- }
250
- function isLikelyPageOnlyComponent(id) {
251
- return id.includes("/pages/") || /\.page\.[cm]?[jt]sx?$/i.test(id) || /\([^/]+\)\.page\.[cm]?[jt]sx?$/i.test(id);
252
- }
253
- function removeActiveGraphMetadata(file) {
254
- const previous = activeGraphComponentMetadata.get(file);
255
- if (!previous) return;
256
- for (const record of previous) {
257
- const location = `${record.file}#${record.className}`;
258
- if (record.selector) {
259
- const selectorSet = selectorOwners.get(record.selector);
260
- selectorSet?.delete(location);
261
- if (selectorSet?.size === 0) selectorOwners.delete(record.selector);
262
- }
263
- const classNameSet = classNameOwners.get(record.className);
264
- classNameSet?.delete(location);
265
- if (classNameSet?.size === 0) classNameOwners.delete(record.className);
266
- }
267
- activeGraphComponentMetadata.delete(file);
268
- }
269
- function registerActiveGraphMetadata(file, records) {
270
- removeActiveGraphMetadata(file);
271
- if (records.length === 0) return;
272
- activeGraphComponentMetadata.set(file, records);
273
- for (const record of records) {
274
- const location = `${record.file}#${record.className}`;
275
- if (record.selector) {
276
- let selectorSet = selectorOwners.get(record.selector);
277
- if (!selectorSet) {
278
- selectorSet = /* @__PURE__ */ new Set();
279
- selectorOwners.set(record.selector, selectorSet);
280
- }
281
- selectorSet.add(location);
282
- }
283
- let classNameSet = classNameOwners.get(record.className);
284
- if (!classNameSet) {
285
- classNameSet = /* @__PURE__ */ new Set();
286
- classNameOwners.set(record.className, classNameSet);
287
- }
288
- classNameSet.add(location);
289
- }
290
- }
291
- function removeStyleOwnerMetadata(file) {
292
- const previous = transformedStyleOwnerMetadata.get(file);
293
- if (!previous) return;
294
- for (const record of previous) {
295
- const owners = styleSourceOwners.get(record.sourcePath);
296
- owners?.delete(record.ownerFile);
297
- if (owners?.size === 0) styleSourceOwners.delete(record.sourcePath);
298
- }
299
- transformedStyleOwnerMetadata.delete(file);
300
- }
301
- function registerStyleOwnerMetadata(file, styleUrls) {
302
- removeStyleOwnerMetadata(file);
303
- const records = styleUrls.map((urlSet) => {
304
- const [, absoluteFileUrl] = urlSet.split("|");
305
- return absoluteFileUrl ? {
306
- ownerFile: file,
307
- sourcePath: normalizePath(absoluteFileUrl)
308
- } : void 0;
309
- }).filter((record) => !!record);
310
- if (records.length === 0) return;
311
- transformedStyleOwnerMetadata.set(file, records);
312
- for (const record of records) {
313
- let owners = styleSourceOwners.get(record.sourcePath);
314
- if (!owners) {
315
- owners = /* @__PURE__ */ new Set();
316
- styleSourceOwners.set(record.sourcePath, owners);
317
- }
318
- owners.add(record.ownerFile);
319
- }
130
+ function validateNoDuplicateAnalogPlugins(config) {
131
+ const analogInstances = (config.plugins ?? []).filter((p) => p.name === "@analogjs/vite-plugin-angular");
132
+ if (analogInstances.length > 1 && !config.build?.ssr) throw new Error(`[@analogjs/vite-plugin-angular] analog() is registered ${analogInstances.length} times. Each instance creates separate style maps, causing component styles to be lost. Remove duplicate registrations.`);
320
133
  }
321
134
  let stylesheetRegistry;
322
135
  const sourceFileCache$1 = new sourceFileCache();
323
- const isTest = process.env.NODE_ENV === "test" || !!process.env["VITEST"];
324
136
  const isVitestVscode = !!process.env["VITEST_VSCODE"];
325
137
  const isStackBlitz = !!process.versions["webcontainer"];
326
138
  const isAstroIntegration = process.env["ANALOG_ASTRO"] === "true";
327
139
  const jit = typeof pluginOptions?.jit !== "undefined" ? pluginOptions.jit : isTest;
328
140
  let viteServer;
329
141
  const styleUrlsResolver = new StyleUrlsResolver();
142
+ const guardContext = {
143
+ styleUrlsResolver,
144
+ activeGraphComponentMetadata,
145
+ selectorOwners,
146
+ classNameOwners,
147
+ transformedStyleOwnerMetadata,
148
+ styleSourceOwners
149
+ };
330
150
  const templateUrlsResolver = new TemplateUrlsResolver();
331
151
  let outputFile;
332
152
  const outputFiles = /* @__PURE__ */ new Map();
@@ -367,7 +187,6 @@ function angular(options) {
367
187
  let styleTransform;
368
188
  let pendingCompilation;
369
189
  let compilationLock = Promise.resolve();
370
- let angularCompilation;
371
190
  function angularPlugin() {
372
191
  let isProd = false;
373
192
  if (angularFullVersion < 19e4 && pluginOptions.liveReload) {
@@ -385,11 +204,6 @@ function angular(options) {
385
204
  isTest
386
205
  });
387
206
  }
388
- if (pluginOptions.useAngularCompilationAPI) if (angularFullVersion < 200100) {
389
- pluginOptions.useAngularCompilationAPI = false;
390
- debugCompilationApi("disabled: Angular version %s < 20.1", angularFullVersion);
391
- console.warn("[@analogjs/vite-plugin-angular]: The Angular Compilation API is only available with Angular v20.1 and later");
392
- } else debugCompilationApi("enabled (Angular %s)", angularFullVersion);
393
207
  return {
394
208
  name: "@analogjs/vite-plugin-angular",
395
209
  async config(config, { command }) {
@@ -402,9 +216,8 @@ function angular(options) {
402
216
  isLib: !!config?.build?.lib
403
217
  };
404
218
  const preliminaryTsConfigPath = resolveTsConfigPath();
405
- const esbuild = pluginOptions.useAngularCompilationAPI ? void 0 : config.esbuild ?? false;
406
- const oxc = pluginOptions.useAngularCompilationAPI ? void 0 : config.oxc ?? false;
407
- if (pluginOptions.useAngularCompilationAPI) debugCompilationApi("esbuild/oxc disabled, Angular handles transforms");
219
+ const esbuild = config.esbuild ?? false;
220
+ const oxc = config.oxc ?? false;
408
221
  const defineOptions = {
409
222
  ngJitMode: "false",
410
223
  ngI18nClosureMode: "false",
@@ -446,11 +259,16 @@ function angular(options) {
446
259
  },
447
260
  configResolved(config) {
448
261
  resolvedConfig = config;
449
- if (pluginOptions.hasTailwindCss) validateTailwindConfig(config, watchMode);
450
- if (pluginOptions.useAngularCompilationAPI) {
451
- stylesheetRegistry = new AnalogStylesheetRegistry();
452
- configureStylePipelineRegistry(pluginOptions.stylePipeline, stylesheetRegistry, { workspaceRoot: pluginOptions.workspaceRoot });
453
- debugStyles("stylesheet registry initialized (Angular Compilation API)");
262
+ if (config.logger?.warnOnce) {
263
+ const originalWarnOnce = config.logger.warnOnce;
264
+ config.logger.warnOnce = (msg, options) => {
265
+ if (typeof msg === "string" && msg.includes("Sourcemap") && msg.includes("node_modules")) return;
266
+ originalWarnOnce(msg, options);
267
+ };
268
+ }
269
+ if (pluginOptions.hasTailwindCss) {
270
+ validateTailwindConfig(pluginOptions.tailwindCss, config, watchMode);
271
+ validateNoDuplicateAnalogPlugins(config);
454
272
  }
455
273
  if (!jit) styleTransform = (code, filename) => preprocessCSS(code, filename, config);
456
274
  if (isTest) testWatchMode = !(config.server.watch === null) || config.test?.watch === true || testWatchMode;
@@ -461,8 +279,8 @@ function angular(options) {
461
279
  server.watcher.on("add", invalidateCompilationOnFsChange);
462
280
  server.watcher.on("unlink", (file) => {
463
281
  evictDeletedFileMetadata(file, {
464
- removeActiveGraphMetadata,
465
- removeStyleOwnerMetadata,
282
+ removeActiveGraphMetadata: (f) => removeActiveGraphMetadata(guardContext, f),
283
+ removeStyleOwnerMetadata: (f) => removeStyleOwnerMetadata(guardContext, f),
466
284
  classNamesMap: classNames,
467
285
  fileTransformMap
468
286
  });
@@ -773,24 +591,7 @@ function angular(options) {
773
591
  classNames.clear();
774
592
  return ctx.modules;
775
593
  },
776
- resolveId(id, importer) {
777
- if (id.startsWith("virtual:@analogjs/vite-plugin-angular:inline-style:") || id.startsWith("virtual:@analogjs/vite-plugin-angular:raw:")) return `\0${id}`;
778
- if (jit && id.startsWith("angular:jit:")) {
779
- const path = id.split(";")[1];
780
- const resolved = normalizePath(resolve(dirname(importer), path));
781
- if (id.includes(":style")) return toVirtualStyleId(resolved);
782
- return toVirtualRawId(resolved);
783
- }
784
- if (id.includes(".html?raw")) {
785
- const filePath = id.split("?")[0];
786
- const resolved = isAbsolute(filePath) ? normalizePath(filePath) : importer ? normalizePath(resolve(dirname(importer), filePath)) : void 0;
787
- if (resolved) return toVirtualRawId(resolved);
788
- }
789
- if (/\.(css|scss|sass|less)\?inline$/.test(id)) {
790
- const filePath = id.split("?")[0];
791
- const resolved = isAbsolute(filePath) ? normalizePath(filePath) : importer ? normalizePath(resolve(dirname(importer), filePath)) : void 0;
792
- if (resolved) return toVirtualStyleId(resolved);
793
- }
594
+ resolveId(id) {
794
595
  if (isComponentStyleSheet(id)) {
795
596
  const filename = getFilenameFromPath(id);
796
597
  if (stylesheetRegistry?.hasServed(filename)) {
@@ -813,17 +614,6 @@ function angular(options) {
813
614
  }
814
615
  },
815
616
  async load(id) {
816
- const styleModule = await loadVirtualStyleModule(this, id, resolvedConfig);
817
- if (styleModule !== void 0) return styleModule;
818
- const rawModule = await loadVirtualRawModule(this, id);
819
- if (rawModule !== void 0) return rawModule;
820
- if (/\.(css|scss|sass|less)\?inline$/.test(id)) {
821
- const filePath = id.split("?")[0];
822
- const code = await promises.readFile(filePath, "utf-8");
823
- if (!shouldPreprocessTestCss(resolvedConfig, filePath)) return `export default ${JSON.stringify(code)}`;
824
- const result = await preprocessCSS(code, filePath, resolvedConfig);
825
- return `export default ${JSON.stringify(result.code)}`;
826
- }
827
617
  if (isComponentStyleSheet(id)) {
828
618
  const filename = getFilenameFromPath(id);
829
619
  const componentStyles = stylesheetRegistry?.getServedContent(filename);
@@ -859,12 +649,6 @@ function angular(options) {
859
649
  * Check for options.transformFilter
860
650
  */
861
651
  if (options?.transformFilter && !(options?.transformFilter(code, id) ?? true)) return;
862
- if (pluginOptions.useAngularCompilationAPI) {
863
- if (!/(Component|Directive|Pipe|Injectable|NgModule)\(/.test(code)) {
864
- debugCompilationApi("transform skip (non-Angular file)", { id });
865
- return;
866
- }
867
- }
868
652
  /**
869
653
  * Skip transforming content files
870
654
  */
@@ -961,12 +745,29 @@ function angular(options) {
961
745
  mkdirSync(declarationFileDir, { recursive: true });
962
746
  writeFileSync(declarationPath, data, "utf-8");
963
747
  });
964
- angularCompilation?.close?.();
965
- angularCompilation = void 0;
966
748
  }
967
749
  };
968
750
  }
969
- const compilationPlugin = pluginOptions.fastCompile ? fastCompilePlugin({
751
+ const compilationPlugin = pluginOptions.useAngularCompilationAPI ? compilationAPIPlugin({
752
+ tsconfigGetter: pluginOptions.tsconfigGetter,
753
+ workspaceRoot: pluginOptions.workspaceRoot,
754
+ inlineStylesExtension: pluginOptions.inlineStylesExtension,
755
+ jit,
756
+ liveReload: pluginOptions.liveReload,
757
+ disableTypeChecking: pluginOptions.disableTypeChecking,
758
+ supportedBrowsers: pluginOptions.supportedBrowsers,
759
+ transformFilter: options?.transformFilter,
760
+ fileReplacements: pluginOptions.fileReplacements,
761
+ stylePreprocessor: pluginOptions.stylePreprocessor,
762
+ stylePipeline: options?.stylePipeline,
763
+ hasTailwindCss: pluginOptions.hasTailwindCss,
764
+ tailwindCss: pluginOptions.tailwindCss,
765
+ isTest,
766
+ isAstroIntegration,
767
+ include: pluginOptions.include,
768
+ additionalContentDirs: pluginOptions.additionalContentDirs,
769
+ debug: options?.debug
770
+ }) : pluginOptions.fastCompile ? fastCompilePlugin({
970
771
  tsconfigGetter: pluginOptions.tsconfigGetter,
971
772
  workspaceRoot: pluginOptions.workspaceRoot,
972
773
  inlineStylesExtension: pluginOptions.inlineStylesExtension,
@@ -980,104 +781,9 @@ function angular(options) {
980
781
  }) : angularPlugin();
981
782
  return [
982
783
  replaceFiles(pluginOptions.fileReplacements, pluginOptions.workspaceRoot),
983
- {
984
- name: "@analogjs/vite-plugin-angular:template-class-binding-guard",
985
- enforce: "pre",
986
- transform(code, id) {
987
- if (id.includes("node_modules")) return;
988
- const cleanId = id.split("?")[0];
989
- if (/\.(html|htm)$/i.test(cleanId)) {
990
- const staticClassIssue = findStaticClassAndBoundClassConflicts(code)[0];
991
- if (staticClassIssue) throwTemplateClassBindingConflict(cleanId, staticClassIssue);
992
- const mixedClassIssue = findBoundClassAndNgClassConflicts(code)[0];
993
- if (mixedClassIssue) this.warn([
994
- "[Analog Angular] Conflicting class composition.",
995
- `File: ${cleanId}:${mixedClassIssue.line}:${mixedClassIssue.column}`,
996
- "This element mixes `[class]` and `[ngClass]`.",
997
- "Prefer a single class-binding strategy so class merging stays predictable.",
998
- "Use one `[ngClass]` expression or explicit `[class.foo]` bindings.",
999
- `Snippet: ${mixedClassIssue.snippet}`
1000
- ].join("\n"));
1001
- return;
1002
- }
1003
- if (TS_EXT_REGEX.test(cleanId)) {
1004
- const rawStyleUrls = styleUrlsResolver.resolve(code, cleanId);
1005
- registerStyleOwnerMetadata(cleanId, rawStyleUrls);
1006
- debugHmrV("component stylesheet owner metadata registered", {
1007
- file: cleanId,
1008
- styleUrlCount: rawStyleUrls.length,
1009
- styleUrls: rawStyleUrls,
1010
- ownerSources: [...transformedStyleOwnerMetadata.get(cleanId)?.map((record) => record.sourcePath) ?? []]
1011
- });
1012
- const components = getAngularComponentMetadata(code);
1013
- const inlineTemplateIssue = components.flatMap((component) => component.inlineTemplates.flatMap((template) => findStaticClassAndBoundClassConflicts(template)))[0];
1014
- if (inlineTemplateIssue) throwTemplateClassBindingConflict(cleanId, inlineTemplateIssue);
1015
- const mixedInlineClassIssue = components.flatMap((component) => component.inlineTemplates.flatMap((template) => findBoundClassAndNgClassConflicts(template)))[0];
1016
- if (mixedInlineClassIssue) this.warn([
1017
- "[Analog Angular] Conflicting class composition.",
1018
- `File: ${cleanId}:${mixedInlineClassIssue.line}:${mixedInlineClassIssue.column}`,
1019
- "This element mixes `[class]` and `[ngClass]`.",
1020
- "Prefer a single class-binding strategy so class merging stays predictable.",
1021
- "Use one `[ngClass]` expression or explicit `[class.foo]` bindings.",
1022
- `Snippet: ${mixedInlineClassIssue.snippet}`
1023
- ].join("\n"));
1024
- registerActiveGraphMetadata(cleanId, components.map((component) => ({
1025
- file: cleanId,
1026
- className: component.className,
1027
- selector: component.selector
1028
- })));
1029
- for (const component of components) {
1030
- if (!component.selector && !isLikelyPageOnlyComponent(cleanId)) throw new Error([
1031
- "[Analog Angular] Selectorless component detected.",
1032
- `File: ${cleanId}`,
1033
- `Component: ${component.className}`,
1034
- "This component has no `selector`, so Angular will render it as `ng-component`.",
1035
- "That increases the chance of component ID collisions and makes diagnostics harder to interpret.",
1036
- "Add an explicit selector for reusable components.",
1037
- "Selectorless components are only supported for page and route-only files."
1038
- ].join("\n"));
1039
- if (component.selector) {
1040
- const selectorEntries = selectorOwners.get(component.selector);
1041
- if (selectorEntries && selectorEntries.size > 1) throw new Error([
1042
- "[Analog Angular] Duplicate component selector detected.",
1043
- `Selector: ${component.selector}`,
1044
- "Multiple components in the active application graph use the same selector.",
1045
- "Selectors must be unique within the active graph to avoid ambiguous rendering and confusing diagnostics.",
1046
- `Locations:\n${formatActiveGraphLocations(selectorEntries)}`
1047
- ].join("\n"));
1048
- }
1049
- const classNameEntries = classNameOwners.get(component.className);
1050
- if (classNameEntries && classNameEntries.size > 1) this.warn([
1051
- "[Analog Angular] Duplicate component class name detected.",
1052
- `Class name: ${component.className}`,
1053
- "Two or more Angular components in the active graph share the same exported class name.",
1054
- "Rename one of them to keep HMR, stack traces, and compiler diagnostics unambiguous.",
1055
- `Locations:\n${formatActiveGraphLocations(classNameEntries)}`
1056
- ].join("\n"));
1057
- }
1058
- }
1059
- }
1060
- },
1061
- pluginOptions.hasTailwindCss && {
1062
- name: "@analogjs/vite-plugin-angular:tailwind-reference",
1063
- enforce: "pre",
1064
- transform(code, id) {
1065
- const tw = pluginOptions.tailwindCss;
1066
- if (!tw || !id.includes(".css")) return;
1067
- if (id.split("?")[0] === tw.rootStylesheet) return;
1068
- const directiveState = inspectCssTailwindDirectives(code);
1069
- if (directiveState.hasReferenceDirective || directiveState.hasTailwindImportDirective) return;
1070
- const rootBasename = basename(tw.rootStylesheet);
1071
- if (directiveState.commentlessCode.includes(rootBasename)) return;
1072
- const prefixes = tw.prefixes;
1073
- const needsRef = prefixes ? prefixes.some((p) => directiveState.commentlessCode.includes(p)) : directiveState.commentlessCode.includes("@apply");
1074
- if (needsRef && directiveState.hasReferenceText) throwTailwindReferenceTextError(id, tw.rootStylesheet);
1075
- if (needsRef) {
1076
- debugTailwind("injected @reference via pre-transform", { id: id.split("/").slice(-2).join("/") });
1077
- return `@reference "${tw.rootStylesheet.replace(/\\/g, "/")}";\n${code}`;
1078
- }
1079
- }
1080
- },
784
+ virtualModulesPlugin({ jit }),
785
+ templateClassBindingGuardPlugin(guardContext),
786
+ pluginOptions.hasTailwindCss && tailwindReferencePlugin({ tailwindCss: pluginOptions.tailwindCss }),
1081
787
  angularPlugin(),
1082
788
  pluginOptions.liveReload && liveReloadPlugin({
1083
789
  classNames,
@@ -1097,457 +803,12 @@ function angular(options) {
1097
803
  routerPlugin(),
1098
804
  angularFullVersion < 190004 && pendingTasksPlugin(),
1099
805
  nxFolderPlugin(),
1100
- {
1101
- name: "@analogjs/vite-plugin-angular:encapsulation",
1102
- enforce: "post",
1103
- transform(code, id) {
1104
- if (shouldExternalizeStyles() && isComponentStyleSheet(id)) {
1105
- const { encapsulation, componentId } = getComponentStyleSheetMeta(id);
1106
- if (encapsulation === "emulated" && componentId) {
1107
- debugStylesV("applying emulated view encapsulation (post)", {
1108
- stylesheet: id.split("?")[0],
1109
- componentId
1110
- });
1111
- return {
1112
- code: ngCompiler.encapsulateStyle(code, componentId),
1113
- map: null
1114
- };
1115
- }
1116
- }
1117
- }
1118
- }
806
+ encapsulationPlugin(shouldExternalizeStyles)
1119
807
  ].filter(Boolean);
1120
- function findIncludes() {
1121
- const globs = pluginOptions.include.map((glob) => normalizeIncludeGlob(pluginOptions.workspaceRoot, glob));
1122
- const files = globSync(globs, {
1123
- dot: true,
1124
- absolute: true
1125
- });
1126
- debugEmit("include discovery", {
1127
- patternCount: globs.length,
1128
- fileCount: files.length
1129
- });
1130
- debugEmitV("include discovery files", {
1131
- globs,
1132
- files: files.map((file) => normalizePath(file))
1133
- });
1134
- return files;
1135
- }
1136
- function ensureIncludeCache() {
1137
- if (pluginOptions.include.length > 0 && includeCache.length === 0) {
1138
- includeCache = findIncludes();
1139
- debugEmit("include cache populated", { fileCount: includeCache.length });
1140
- }
1141
- return includeCache;
1142
- }
1143
- function getTsconfigCacheKey(resolvedTsConfigPath, config) {
1144
- return [
1145
- resolvedTsConfigPath,
1146
- config.mode === "production" ? "prod" : "dev",
1147
- isTest ? "test" : "app",
1148
- config.build?.lib ? "lib" : "nolib",
1149
- pluginOptions.liveReload ? "live-reload" : "no-live-reload",
1150
- pluginOptions.hasTailwindCss ? "tw" : "notw"
1151
- ].join("|");
1152
- }
1153
- function readAngularTsconfigConfiguration(resolvedTsConfigPath, config) {
1154
- const isProd = config.mode === "production";
1155
- return compilerCli.readConfiguration(resolvedTsConfigPath, {
1156
- suppressOutputPathCheck: true,
1157
- outDir: void 0,
1158
- sourceMap: false,
1159
- inlineSourceMap: !isProd,
1160
- inlineSources: !isProd,
1161
- declaration: false,
1162
- declarationMap: false,
1163
- allowEmptyCodegenFiles: false,
1164
- annotationsAs: "decorators",
1165
- enableResourceInlining: false,
1166
- noEmitOnError: false,
1167
- mapRoot: void 0,
1168
- sourceRoot: void 0,
1169
- supportTestBed: false,
1170
- supportJitMode: false
1171
- });
1172
- }
1173
- function getCachedTsconfigOptions(resolvedTsConfigPath, config) {
1174
- const tsconfigKey = getTsconfigCacheKey(resolvedTsConfigPath, config);
1175
- let cached = tsconfigOptionsCache.get(tsconfigKey);
1176
- if (!cached) {
1177
- const read = readAngularTsconfigConfiguration(resolvedTsConfigPath, config);
1178
- cached = {
1179
- options: read.options,
1180
- rootNames: read.rootNames
1181
- };
1182
- tsconfigOptionsCache.set(tsconfigKey, cached);
1183
- debugEmit("tsconfig root names loaded", {
1184
- resolvedTsConfigPath,
1185
- rootNameCount: read.rootNames.length
1186
- });
1187
- debugEmitV("tsconfig root names", {
1188
- resolvedTsConfigPath,
1189
- rootNames: read.rootNames.map((file) => normalizePath(file))
1190
- });
1191
- }
1192
- return cached;
1193
- }
1194
- function resolveReferenceTsconfigPath(referencePath, ownerTsconfigPath) {
1195
- const ownerDir = dirname(ownerTsconfigPath);
1196
- const resolvedReference = normalizePath(isAbsolute(referencePath) ? referencePath : resolve(ownerDir, referencePath));
1197
- if (existsSync(resolvedReference)) {
1198
- try {
1199
- if (statSync(resolvedReference).isDirectory()) {
1200
- const nestedTsconfig = join(resolvedReference, "tsconfig.json");
1201
- return existsSync(nestedTsconfig) ? normalizePath(nestedTsconfig) : void 0;
1202
- }
1203
- } catch {
1204
- return;
1205
- }
1206
- return resolvedReference;
1207
- }
1208
- if (!resolvedReference.endsWith(".json")) {
1209
- const asJson = `${resolvedReference}.json`;
1210
- if (existsSync(asJson)) return normalizePath(asJson);
1211
- const nestedTsconfig = join(resolvedReference, "tsconfig.json");
1212
- if (existsSync(nestedTsconfig)) return normalizePath(nestedTsconfig);
1213
- }
1214
- }
1215
- function collectTsconfigPathRoots(resolvedTsConfigPath, options, rawTsconfig) {
1216
- const tsPaths = rawTsconfig.compilerOptions?.paths ?? options.paths;
1217
- if (!tsPaths) return [];
1218
- const tsconfigDir = dirname(resolvedTsConfigPath);
1219
- const configuredBaseUrl = typeof options.baseUrl === "string" ? options.baseUrl : typeof rawTsconfig.compilerOptions?.baseUrl === "string" ? rawTsconfig.compilerOptions.baseUrl : void 0;
1220
- const resolvedBaseUrl = configuredBaseUrl ? isAbsolute(configuredBaseUrl) ? configuredBaseUrl : resolve(tsconfigDir, configuredBaseUrl) : tsconfigDir;
1221
- const discoveredRoots = /* @__PURE__ */ new Set();
1222
- for (const targets of Object.values(tsPaths)) for (const target of targets) {
1223
- const resolvedTarget = normalizePath(isAbsolute(target) ? target : resolve(resolvedBaseUrl, target));
1224
- if (target.includes("*")) {
1225
- for (const match of globSync(resolvedTarget, {
1226
- dot: true,
1227
- absolute: true
1228
- })) discoveredRoots.add(normalizePath(match));
1229
- continue;
1230
- }
1231
- if (existsSync(resolvedTarget)) discoveredRoots.add(resolvedTarget);
1232
- }
1233
- return [...discoveredRoots];
1234
- }
1235
- function collectExpandedTsconfigRoots(resolvedTsConfigPath, config, visited = /* @__PURE__ */ new Set()) {
1236
- const normalizedTsConfigPath = normalizePath(resolvedTsConfigPath);
1237
- if (visited.has(normalizedTsConfigPath)) return [];
1238
- const tsconfigKey = `${getTsconfigCacheKey(normalizedTsConfigPath, config)}|graph`;
1239
- const cached = tsconfigGraphRootCache.get(tsconfigKey);
1240
- if (cached) return cached;
1241
- visited.add(normalizedTsConfigPath);
1242
- const read = readAngularTsconfigConfiguration(normalizedTsConfigPath, config);
1243
- const rawTsconfig = ts.readConfigFile(normalizedTsConfigPath, ts.sys.readFile).config ?? {};
1244
- const expandedRoots = new Set(read.rootNames.map((file) => normalizePath(file)));
1245
- const pathRoots = collectTsconfigPathRoots(normalizedTsConfigPath, read.options, rawTsconfig);
1246
- for (const pathRoot of pathRoots) expandedRoots.add(pathRoot);
1247
- const referenceConfigs = (rawTsconfig.references ?? []).flatMap((reference) => typeof reference.path === "string" ? [resolveReferenceTsconfigPath(reference.path, normalizedTsConfigPath)] : []).filter((reference) => !!reference);
1248
- for (const referenceConfig of referenceConfigs) for (const referenceRoot of collectExpandedTsconfigRoots(referenceConfig, config, visited)) expandedRoots.add(referenceRoot);
1249
- const expandedRootList = [...expandedRoots];
1250
- tsconfigGraphRootCache.set(tsconfigKey, expandedRootList);
1251
- debugEmit("expanded tsconfig graph roots", {
1252
- resolvedTsConfigPath: normalizedTsConfigPath,
1253
- directRootNameCount: read.rootNames.length,
1254
- pathRootCount: pathRoots.length,
1255
- referenceConfigCount: referenceConfigs.length,
1256
- expandedRootCount: expandedRootList.length
1257
- });
1258
- debugEmitV("expanded tsconfig graph root files", {
1259
- resolvedTsConfigPath: normalizedTsConfigPath,
1260
- pathRoots,
1261
- referenceConfigs,
1262
- rootNames: expandedRootList
1263
- });
1264
- return expandedRootList;
1265
- }
1266
- function resolveCompilationApiTsConfigPath(resolvedTsConfigPath, config) {
1267
- const includedFiles = ensureIncludeCache();
1268
- const cached = getCachedTsconfigOptions(resolvedTsConfigPath, config);
1269
- const expandedGraphRoots = collectExpandedTsconfigRoots(resolvedTsConfigPath, config);
1270
- const mergedRootNames = union(cached.rootNames, expandedGraphRoots, includedFiles).map((file) => normalizePath(file));
1271
- if (mergedRootNames.length === cached.rootNames.length) return resolvedTsConfigPath;
1272
- const wrapperDir = join(isAbsolute(config.cacheDir) ? config.cacheDir : resolve(config.root, config.cacheDir), "analog-angular", "compilation-api");
1273
- const rawTsconfig = ts.readConfigFile(resolvedTsConfigPath, ts.sys.readFile).config ?? {};
1274
- const wrapperPayload = {
1275
- extends: normalizePath(resolvedTsConfigPath),
1276
- files: [...mergedRootNames].sort(),
1277
- ...rawTsconfig.references ? { references: rawTsconfig.references } : {}
1278
- };
1279
- const wrapperPath = join(wrapperDir, `tsconfig.includes.${createHash("sha1").update(JSON.stringify(wrapperPayload)).digest("hex").slice(0, 12)}.json`);
1280
- mkdirSync(wrapperDir, { recursive: true });
1281
- if (!existsSync(wrapperPath)) writeFileSync(wrapperPath, `${JSON.stringify(wrapperPayload, null, 2)}\n`, "utf-8");
1282
- debugCompilationApi("generated include wrapper tsconfig", {
1283
- originalTsconfig: resolvedTsConfigPath,
1284
- wrapperTsconfig: wrapperPath,
1285
- includeCount: includedFiles.length,
1286
- rootNameCount: mergedRootNames.length
1287
- });
1288
- debugEmit("wrapper tsconfig root merge", {
1289
- originalTsconfig: resolvedTsConfigPath,
1290
- wrapperTsconfig: wrapperPath,
1291
- baseRootNameCount: cached.rootNames.length,
1292
- expandedGraphRootCount: expandedGraphRoots.length,
1293
- includeCount: includedFiles.length,
1294
- mergedRootNameCount: mergedRootNames.length,
1295
- referenceCount: rawTsconfig.references?.length ?? 0
1296
- });
1297
- debugEmitV("wrapper tsconfig root names", {
1298
- wrapperTsconfig: wrapperPath,
1299
- rootNames: mergedRootNames
1300
- });
1301
- return wrapperPath;
1302
- }
1303
808
  function resolveTsConfigPath() {
1304
809
  const tsconfigValue = pluginOptions.tsconfigGetter();
1305
810
  return getTsConfigPath(tsConfigResolutionContext.root, tsconfigValue, tsConfigResolutionContext.isProd, isTest, tsConfigResolutionContext.isLib);
1306
811
  }
1307
- /**
1308
- * Perform compilation using Angular's private Compilation API.
1309
- *
1310
- * Key differences from the standard `performCompilation` path:
1311
- * 1. The compilation instance is reused across rebuilds (nullish-coalescing
1312
- * assignment below) so Angular retains prior state and can diff it to
1313
- * produce `templateUpdates` for HMR.
1314
- * 2. `ids` (modified files) are forwarded to both the source-file cache and
1315
- * `angularCompilation.update()` so that incremental re-analysis is
1316
- * scoped to what actually changed.
1317
- * 3. `fileReplacements` are converted and passed into Angular's host via
1318
- * `toAngularCompilationFileReplacements`.
1319
- * 4. `templateUpdates` from the compilation result are mapped back to
1320
- * file-level HMR metadata (`hmrUpdateCode`, `hmrEligible`, `classNames`).
1321
- */
1322
- async function performAngularCompilation(config, ids) {
1323
- const compilation = angularCompilation ??= await createAngularCompilation(!!pluginOptions.jit, false);
1324
- const modifiedFiles = ids?.length ? new Set(ids.map((file) => normalizePath(file))) : void 0;
1325
- if (modifiedFiles?.size) sourceFileCache$1.invalidate(modifiedFiles);
1326
- if (modifiedFiles?.size && compilation.update) {
1327
- debugCompilationApi("incremental update", { files: [...modifiedFiles] });
1328
- await compilation.update(modifiedFiles);
1329
- }
1330
- const resolvedTsConfigPath = resolveTsConfigPath();
1331
- const compilationApiTsConfigPath = resolveCompilationApiTsConfigPath(resolvedTsConfigPath, config);
1332
- debugEmit("compilation initialize", {
1333
- resolvedTsConfigPath,
1334
- compilationApiTsConfigPath,
1335
- modifiedFileCount: modifiedFiles?.size ?? 0
1336
- });
1337
- const compilationResult = await compilation.initialize(compilationApiTsConfigPath, {
1338
- fileReplacements: toAngularCompilationFileReplacements(pluginOptions.fileReplacements, pluginOptions.workspaceRoot),
1339
- modifiedFiles,
1340
- async transformStylesheet(data, containingFile, resourceFile, order, className) {
1341
- const filename = resourceFile ?? containingFile.replace(".ts", `.${pluginOptions.inlineStylesExtension}`);
1342
- const preprocessed = preprocessStylesheetResult(data, filename, pluginOptions.stylePreprocessor, {
1343
- filename,
1344
- containingFile,
1345
- resourceFile,
1346
- className,
1347
- order,
1348
- inline: !resourceFile
1349
- });
1350
- if (shouldEnableLiveReload() && className && containingFile) classNames.set(normalizePath(containingFile), className);
1351
- if (shouldExternalizeStyles()) {
1352
- const stylesheetId = registerStylesheetContent(stylesheetRegistry, {
1353
- code: preprocessed.code,
1354
- dependencies: normalizeStylesheetDependencies(preprocessed.dependencies),
1355
- diagnostics: preprocessed.diagnostics,
1356
- tags: preprocessed.tags,
1357
- containingFile,
1358
- className,
1359
- order,
1360
- inlineStylesExtension: pluginOptions.inlineStylesExtension,
1361
- resourceFile: resourceFile ?? void 0
1362
- });
1363
- debugStyles("stylesheet deferred to Vite pipeline", {
1364
- stylesheetId,
1365
- resourceFile: resourceFile ?? "(inline)"
1366
- });
1367
- debugStylesV("stylesheet deferred content snapshot", {
1368
- stylesheetId,
1369
- filename,
1370
- resourceFile: resourceFile ?? "(inline)",
1371
- dependencies: preprocessed.dependencies,
1372
- diagnostics: preprocessed.diagnostics,
1373
- tags: preprocessed.tags,
1374
- ...describeStylesheetContent(preprocessed.code)
1375
- });
1376
- return stylesheetId;
1377
- }
1378
- debugStyles("stylesheet processed inline via preprocessCSS", {
1379
- filename,
1380
- resourceFile: resourceFile ?? "(inline)",
1381
- dataLength: preprocessed.code.length
1382
- });
1383
- if (!shouldPreprocessTestCss(resolvedConfig, filename)) return "";
1384
- let stylesheetResult;
1385
- try {
1386
- stylesheetResult = await preprocessCSS(preprocessed.code, `${filename}?direct`, resolvedConfig);
1387
- } catch (e) {
1388
- if (isTailwindReferenceError(e)) throw e;
1389
- debugStyles("preprocessCSS error", {
1390
- filename,
1391
- resourceFile: resourceFile ?? "(inline)",
1392
- error: String(e)
1393
- });
1394
- }
1395
- return stylesheetResult?.code || "";
1396
- },
1397
- processWebWorker(workerFile, containingFile) {
1398
- return "";
1399
- }
1400
- }, (tsCompilerOptions) => {
1401
- if (shouldExternalizeStyles()) tsCompilerOptions["externalRuntimeStyles"] = true;
1402
- if (shouldEnableLiveReload()) {
1403
- tsCompilerOptions["_enableHmr"] = true;
1404
- tsCompilerOptions["supportTestBed"] = true;
1405
- }
1406
- debugCompiler("tsCompilerOptions (compilation API)", {
1407
- liveReload: pluginOptions.liveReload,
1408
- viteHmr: hasViteHmrTransport(),
1409
- hasTailwindCss: pluginOptions.hasTailwindCss,
1410
- watchMode,
1411
- shouldExternalize: shouldExternalizeStyles(),
1412
- externalRuntimeStyles: !!tsCompilerOptions["externalRuntimeStyles"],
1413
- hmrEnabled: !!tsCompilerOptions["_enableHmr"]
1414
- });
1415
- if (tsCompilerOptions.compilationMode === "partial") {
1416
- tsCompilerOptions["supportTestBed"] = true;
1417
- tsCompilerOptions["supportJitMode"] = true;
1418
- }
1419
- if (!isTest && config.build?.lib) {
1420
- tsCompilerOptions["declaration"] = true;
1421
- tsCompilerOptions["declarationMap"] = watchMode;
1422
- tsCompilerOptions["inlineSources"] = true;
1423
- }
1424
- if (isTest) tsCompilerOptions["supportTestBed"] = true;
1425
- return tsCompilerOptions;
1426
- });
1427
- debugStyles("external stylesheets from compilation API", {
1428
- count: compilationResult.externalStylesheets?.size ?? 0,
1429
- hasPreprocessor: !!pluginOptions.stylePreprocessor,
1430
- hasInlineMap: !!stylesheetRegistry
1431
- });
1432
- const preprocessStats = {
1433
- total: 0,
1434
- injected: 0,
1435
- skipped: 0,
1436
- errors: 0
1437
- };
1438
- for (const [key, value] of compilationResult.externalStylesheets ?? []) {
1439
- preprocessStats.total++;
1440
- const angularHash = `${value}.css`;
1441
- stylesheetRegistry?.registerExternalRequest(angularHash, key);
1442
- if (stylesheetRegistry && pluginOptions.stylePreprocessor && existsSync(key)) try {
1443
- const rawCss = readFileSync(key, "utf-8");
1444
- const preprocessed = preprocessStylesheetResult(rawCss, key, pluginOptions.stylePreprocessor);
1445
- debugStylesV("external stylesheet raw snapshot", {
1446
- angularHash,
1447
- resolvedPath: key,
1448
- mtimeMs: safeStatMtimeMs(key),
1449
- ...describeStylesheetContent(rawCss)
1450
- });
1451
- const servedCss = rewriteRelativeCssImports(preprocessed.code, key);
1452
- stylesheetRegistry.registerServedStylesheet({
1453
- publicId: angularHash,
1454
- sourcePath: key,
1455
- originalCode: rawCss,
1456
- normalizedCode: servedCss,
1457
- dependencies: normalizeStylesheetDependencies(preprocessed.dependencies),
1458
- diagnostics: preprocessed.diagnostics,
1459
- tags: preprocessed.tags
1460
- }, [
1461
- key,
1462
- normalizePath(key),
1463
- basename(key),
1464
- key.replace(/^\//, "")
1465
- ]);
1466
- if (servedCss && servedCss !== rawCss) {
1467
- preprocessStats.injected++;
1468
- debugStylesV("preprocessed external stylesheet for Tailwind @reference", {
1469
- angularHash,
1470
- resolvedPath: key,
1471
- mtimeMs: safeStatMtimeMs(key),
1472
- raw: describeStylesheetContent(rawCss),
1473
- served: describeStylesheetContent(servedCss),
1474
- dependencies: preprocessed.dependencies,
1475
- diagnostics: preprocessed.diagnostics,
1476
- tags: preprocessed.tags
1477
- });
1478
- } else {
1479
- preprocessStats.skipped++;
1480
- debugStylesV("external stylesheet unchanged after preprocessing", {
1481
- angularHash,
1482
- resolvedPath: key,
1483
- mtimeMs: safeStatMtimeMs(key),
1484
- raw: describeStylesheetContent(rawCss),
1485
- served: describeStylesheetContent(servedCss),
1486
- dependencies: preprocessed.dependencies,
1487
- diagnostics: preprocessed.diagnostics,
1488
- tags: preprocessed.tags,
1489
- hint: "Registry mapping is still registered so Angular component stylesheet HMR can track and refresh this file even when preprocessing makes no textual changes."
1490
- });
1491
- }
1492
- } catch (e) {
1493
- preprocessStats.errors++;
1494
- console.warn(`[@analogjs/vite-plugin-angular] failed to preprocess external stylesheet: ${key}: ${e}`);
1495
- }
1496
- else {
1497
- preprocessStats.skipped++;
1498
- debugStylesV("external stylesheet preprocessing skipped", {
1499
- filename: angularHash,
1500
- resolvedPath: key,
1501
- reason: !stylesheetRegistry ? "no stylesheetRegistry" : !pluginOptions.stylePreprocessor ? "no stylePreprocessor" : "file not found on disk"
1502
- });
1503
- }
1504
- debugStylesV("external stylesheet registered for resolveId mapping", {
1505
- filename: angularHash,
1506
- resolvedPath: key
1507
- });
1508
- }
1509
- debugStyles("external stylesheet preprocessing complete", preprocessStats);
1510
- const diagnostics = await compilation.diagnoseFiles(pluginOptions.disableTypeChecking ? DiagnosticModes.All & ~DiagnosticModes.Semantic : DiagnosticModes.All);
1511
- const errors = diagnostics.errors?.length ? diagnostics.errors : [];
1512
- const warnings = diagnostics.warnings?.length ? diagnostics.warnings : [];
1513
- debugEmit("compilation diagnostics", {
1514
- errorCount: errors.length,
1515
- warningCount: warnings.length
1516
- });
1517
- const templateUpdates = mapTemplateUpdatesToFiles(compilationResult.templateUpdates);
1518
- if (templateUpdates.size > 0) debugHmr("compilation API template updates", {
1519
- count: templateUpdates.size,
1520
- files: [...templateUpdates.keys()]
1521
- });
1522
- const affectedFiles = await compilation.emitAffectedFiles();
1523
- debugEmit("emitAffectedFiles summary", {
1524
- count: affectedFiles.length,
1525
- templateUpdateCount: templateUpdates.size,
1526
- knownOutputCountBefore: outputFiles.size
1527
- });
1528
- debugEmitV("emitAffectedFiles files", { files: affectedFiles.map((file) => normalizePath(file.filename)) });
1529
- for (const file of affectedFiles) {
1530
- const normalizedFilename = normalizePath(file.filename);
1531
- const templateUpdate = templateUpdates.get(normalizedFilename);
1532
- if (templateUpdate) classNames.set(normalizedFilename, templateUpdate.className);
1533
- outputFiles.set(normalizedFilename, {
1534
- content: file.contents,
1535
- dependencies: [],
1536
- errors: errors.map((error) => error.text || ""),
1537
- warnings: warnings.map((warning) => warning.text || ""),
1538
- hmrUpdateCode: templateUpdate?.code,
1539
- hmrEligible: !!templateUpdate?.code
1540
- });
1541
- debugEmitV("registered compilation API output", {
1542
- filename: normalizedFilename,
1543
- ...describeEmitMarkers(file.contents),
1544
- hasTemplateUpdate: !!templateUpdate,
1545
- errorCount: errors.length,
1546
- warningCount: warnings.length,
1547
- knownOutputCount: outputFiles.size
1548
- });
1549
- }
1550
- }
1551
812
  async function performCompilation(config, ids) {
1552
813
  let resolve;
1553
814
  const previousLock = compilationLock;
@@ -1566,16 +827,12 @@ function angular(options) {
1566
827
  * It should not be called concurrently. Use `performCompilation` which wraps this method in a lock to ensure only one compilation runs at a time.
1567
828
  */
1568
829
  async function _doPerformCompilation(config, ids) {
1569
- if (pluginOptions.useAngularCompilationAPI) {
1570
- debugCompilationApi("using compilation API path", { modifiedFiles: ids?.length ?? 0 });
1571
- await performAngularCompilation(config, ids);
1572
- return;
1573
- }
1574
830
  const isProd = config.mode === "production";
1575
831
  const modifiedFiles = new Set(ids ?? []);
1576
832
  sourceFileCache$1.invalidate(modifiedFiles);
1577
833
  if (ids?.length) for (const id of ids || []) fileTransformMap.delete(id);
1578
- const cached = getCachedTsconfigOptions(resolveTsConfigPath(), config);
834
+ const resolvedTsConfigPath = resolveTsConfigPath();
835
+ const cached = tsconfigResolver.getCachedTsconfigOptions(resolvedTsConfigPath, config);
1579
836
  const tsCompilerOptions = { ...cached.options };
1580
837
  let rootNames = [...cached.rootNames];
1581
838
  if (shouldExternalizeStyles()) tsCompilerOptions["externalRuntimeStyles"] = true;
@@ -1601,7 +858,7 @@ function angular(options) {
1601
858
  }
1602
859
  if (isTest) tsCompilerOptions["supportTestBed"] = true;
1603
860
  const replacements = pluginOptions.fileReplacements.map((rp) => join(pluginOptions.workspaceRoot, rp.ssr || rp.with));
1604
- rootNames = union(rootNames, ensureIncludeCache(), replacements);
861
+ rootNames = union(rootNames, tsconfigResolver.ensureIncludeCache(), replacements);
1605
862
  const hostKey = JSON.stringify(tsCompilerOptions);
1606
863
  let host;
1607
864
  if (cachedHost && cachedHostKey === hostKey) host = cachedHost;
@@ -1716,47 +973,6 @@ function createFsWatcherCacheInvalidator(invalidateFsCaches, invalidateTsconfigC
1716
973
  };
1717
974
  }
1718
975
  /**
1719
- * Convert Analog/Angular CLI-style file replacements into the flat record
1720
- * expected by `AngularHostOptions.fileReplacements`.
1721
- *
1722
- * Only browser replacements (`{ replace, with }`) are converted. SSR-only
1723
- * replacements (`{ replace, ssr }`) are left for the Vite runtime plugin to
1724
- * handle — they should not be baked into the Angular compilation host because
1725
- * that would apply them to both browser and server builds.
1726
- *
1727
- * Relative paths are resolved against `workspaceRoot` so that the host
1728
- * receives the same absolute paths it would get from the Angular CLI.
1729
- */
1730
- function toAngularCompilationFileReplacements(replacements, workspaceRoot) {
1731
- const mappedReplacements = replacements.flatMap((replacement) => {
1732
- if (!("with" in replacement)) return [];
1733
- return [[isAbsolute(replacement.replace) ? replacement.replace : resolve(workspaceRoot, replacement.replace), isAbsolute(replacement.with) ? replacement.with : resolve(workspaceRoot, replacement.with)]];
1734
- });
1735
- return mappedReplacements.length ? Object.fromEntries(mappedReplacements) : void 0;
1736
- }
1737
- /**
1738
- * Map Angular's `templateUpdates` (keyed by `encodedFilePath@ClassName`)
1739
- * back to absolute file paths with their associated HMR code and component
1740
- * class name.
1741
- *
1742
- * Angular's private Compilation API emits template update keys in the form
1743
- * `encodeURIComponent(relativePath + '@' + className)`. We decode and resolve
1744
- * them so the caller can look up updates by the same normalized absolute path
1745
- * used elsewhere in the plugin (`outputFiles`, `classNames`, etc.).
1746
- */
1747
- function mapTemplateUpdatesToFiles(templateUpdates) {
1748
- const updatesByFile = /* @__PURE__ */ new Map();
1749
- templateUpdates?.forEach((code, encodedUpdateId) => {
1750
- const [file, className = ""] = decodeURIComponent(encodedUpdateId).split("@");
1751
- const resolvedFile = normalizePath(resolve(process.cwd(), file));
1752
- updatesByFile.set(resolvedFile, {
1753
- className,
1754
- code
1755
- });
1756
- });
1757
- return updatesByFile;
1758
- }
1759
- /**
1760
976
  * Returns every live Vite module that can legitimately represent a changed
1761
977
  * Angular resource file.
1762
978
  *
@@ -1805,13 +1021,6 @@ function isModuleForChangedResource(mod, changedFile, stylesheetRegistry) {
1805
1021
  const requestPath = getFilenameFromPath(mod.id);
1806
1022
  return normalizePath((stylesheetRegistry?.resolveExternalSource(requestPath) ?? stylesheetRegistry?.resolveExternalSource(requestPath.replace(/^\//, "")) ?? "").split("?")[0]) === normalizedChangedFile;
1807
1023
  }
1808
- function describeStylesheetContent(code) {
1809
- return {
1810
- length: code.length,
1811
- digest: createHash("sha256").update(code).digest("hex").slice(0, 12),
1812
- preview: code.replace(/\s+/g, " ").trim().slice(0, 160)
1813
- };
1814
- }
1815
1024
  function safeStatMtimeMs(file) {
1816
1025
  try {
1817
1026
  return statSync(file).mtimeMs;
@@ -1819,50 +1028,6 @@ function safeStatMtimeMs(file) {
1819
1028
  return;
1820
1029
  }
1821
1030
  }
1822
- /**
1823
- * Refreshes any already-served stylesheet records that map back to a changed
1824
- * source file.
1825
- *
1826
- * This is the critical bridge for externalized Angular component styles during
1827
- * HMR. Angular's resource watcher can notice that `/src/...component.css`
1828
- * changed before Angular recompilation has had a chance to repopulate the
1829
- * stylesheet registry. If we emit a CSS update against the existing virtual
1830
- * stylesheet id without first refreshing the registry content, the browser gets
1831
- * a hot update containing stale CSS. By rewriting the existing served records
1832
- * from disk up front, HMR always pushes the latest source content.
1833
- */
1834
- function refreshStylesheetRegistryForFile(file, stylesheetRegistry, stylePreprocessor) {
1835
- const normalizedFile = normalizePath(file.split("?")[0]);
1836
- if (!stylesheetRegistry || !existsSync(normalizedFile)) return;
1837
- const publicIds = stylesheetRegistry.getPublicIdsForSource(normalizedFile);
1838
- if (publicIds.length === 0) return;
1839
- const rawCss = readFileSync(normalizedFile, "utf-8");
1840
- const preprocessed = preprocessStylesheetResult(rawCss, normalizedFile, stylePreprocessor);
1841
- const servedCss = rewriteRelativeCssImports(preprocessed.code, normalizedFile);
1842
- for (const publicId of publicIds) stylesheetRegistry.registerServedStylesheet({
1843
- publicId,
1844
- sourcePath: normalizedFile,
1845
- originalCode: rawCss,
1846
- normalizedCode: servedCss,
1847
- dependencies: normalizeStylesheetDependencies(preprocessed.dependencies),
1848
- diagnostics: preprocessed.diagnostics,
1849
- tags: preprocessed.tags
1850
- }, [
1851
- normalizedFile,
1852
- normalizePath(normalizedFile),
1853
- basename(normalizedFile),
1854
- normalizedFile.replace(/^\//, "")
1855
- ]);
1856
- debugStylesV("stylesheet registry refreshed from source file", {
1857
- file: normalizedFile,
1858
- publicIds,
1859
- dependencies: preprocessed.dependencies,
1860
- diagnostics: preprocessed.diagnostics,
1861
- tags: preprocessed.tags,
1862
- source: describeStylesheetContent(rawCss),
1863
- served: describeStylesheetContent(servedCss)
1864
- });
1865
- }
1866
1031
  function diagnoseComponentStylesheetPipeline(changedFile, directModule, stylesheetRegistry, wrapperModules, stylePreprocessor) {
1867
1032
  const normalizedFile = normalizePath(changedFile.split("?")[0]);
1868
1033
  const sourceExists = existsSync(normalizedFile);
@@ -1996,83 +1161,6 @@ function resolveComponentClassNamesForStyleOwner(ownerFile, sourcePath) {
1996
1161
  const normalizedSourcePath = normalizePath(sourcePath);
1997
1162
  return components.filter((component) => component.styleUrls.some((styleUrl) => normalizePath(resolve(dirname(ownerFile), styleUrl)) === normalizedSourcePath)).map((component) => component.className);
1998
1163
  }
1999
- function findStaticClassAndBoundClassConflicts(template) {
2000
- const issues = [];
2001
- for (const { index, snippet } of findOpeningTagSnippets(template)) {
2002
- if (!snippet.includes("[class]")) continue;
2003
- const hasStaticClass = /\sclass\s*=\s*(['"])(?:(?!\1)[\s\S])*\1/.test(snippet);
2004
- const hasBoundClass = /\s\[class\]\s*=\s*(['"])(?:(?!\1)[\s\S])*\1/.test(snippet);
2005
- if (hasStaticClass && hasBoundClass) {
2006
- const prefix = template.slice(0, index);
2007
- const line = prefix.split("\n").length;
2008
- const column = index - prefix.lastIndexOf("\n");
2009
- issues.push({
2010
- line,
2011
- column,
2012
- snippet: snippet.replace(/\s+/g, " ").trim()
2013
- });
2014
- }
2015
- }
2016
- return issues;
2017
- }
2018
- function throwTemplateClassBindingConflict(id, issue) {
2019
- throw new Error([
2020
- "[Analog Angular] Invalid template class binding.",
2021
- `File: ${id}:${issue.line}:${issue.column}`,
2022
- "The same element uses both a static `class=\"...\"` attribute and a whole-element `[class]=\"...\"` binding.",
2023
- "That pattern can replace or conflict with static Tailwind classes, which makes styles appear to stop applying.",
2024
- "Use `[ngClass]` or explicit `[class.foo]` bindings instead of `[class]` when the element also has static classes.",
2025
- `Snippet: ${issue.snippet}`
2026
- ].join("\n"));
2027
- }
2028
- function findBoundClassAndNgClassConflicts(template) {
2029
- const issues = [];
2030
- if (!/\[class\]\s*=/.test(template) || !template.includes("[ngClass]")) return issues;
2031
- for (const { index, snippet } of findOpeningTagSnippets(template)) {
2032
- if (!/\[class\]\s*=/.test(snippet) || !snippet.includes("[ngClass]")) continue;
2033
- const prefix = template.slice(0, index);
2034
- const line = prefix.split("\n").length;
2035
- const column = index - prefix.lastIndexOf("\n");
2036
- issues.push({
2037
- line,
2038
- column,
2039
- snippet: snippet.replace(/\s+/g, " ").trim()
2040
- });
2041
- }
2042
- return issues;
2043
- }
2044
- function findOpeningTagSnippets(template) {
2045
- const matches = [];
2046
- for (let index = 0; index < template.length; index++) {
2047
- if (template[index] !== "<") continue;
2048
- const tagStart = template[index + 1];
2049
- if (!tagStart || !/[a-zA-Z]/.test(tagStart)) continue;
2050
- let quote = null;
2051
- for (let end = index + 1; end < template.length; end++) {
2052
- const char = template[end];
2053
- if (quote) {
2054
- if (char === quote) quote = null;
2055
- continue;
2056
- }
2057
- if (char === "\"" || char === "'") {
2058
- quote = char;
2059
- continue;
2060
- }
2061
- if (char === ">") {
2062
- matches.push({
2063
- index,
2064
- snippet: template.slice(index, end + 1)
2065
- });
2066
- index = end;
2067
- break;
2068
- }
2069
- }
2070
- }
2071
- return matches;
2072
- }
2073
- function formatActiveGraphLocations(entries) {
2074
- return [...entries].sort().map((entry) => `- ${entry}`).join("\n");
2075
- }
2076
1164
  function logComponentStylesheetHmrOutcome(details) {
2077
1165
  const pitfalls = [];
2078
1166
  const rejectedPreferredPaths = [];
@@ -2188,20 +1276,6 @@ function markModuleSelfAccepting(mod) {
2188
1276
  isSelfAccepting: true
2189
1277
  };
2190
1278
  }
2191
- function isComponentStyleSheet(id) {
2192
- return id.includes("ngcomp=");
2193
- }
2194
- function getComponentStyleSheetMeta(id) {
2195
- const params = new URL(id, "http://localhost").searchParams;
2196
- return {
2197
- componentId: params.get("ngcomp"),
2198
- encapsulation: {
2199
- "0": "emulated",
2200
- "2": "none",
2201
- "3": "shadow"
2202
- }[params.get("e")]
2203
- };
2204
- }
2205
1279
  /**
2206
1280
  * Removes leading / and query string from a url path
2207
1281
  * e.g. /foo.scss?direct&ngcomp=ng-c3153525609&e=0 returns foo.scss
@@ -2219,15 +1293,6 @@ function getFilenameFromPath(id) {
2219
1293
  * Checks for vitest run from the command line
2220
1294
  * @returns boolean
2221
1295
  */
2222
- function isTestWatchMode(args = process.argv) {
2223
- if (args.find((arg) => arg.includes("--run"))) return false;
2224
- if (args.find((arg) => arg.includes("--no-run"))) return true;
2225
- const hasWatch = args.find((arg) => arg.includes("watch"));
2226
- if (hasWatch && ["false", "no"].some((neg) => hasWatch.includes(neg))) return false;
2227
- const watchArg = args[args.findIndex((arg) => arg.includes("watch")) + 1];
2228
- if (watchArg && watchArg === "false") return false;
2229
- return true;
2230
- }
2231
1296
  //#endregion
2232
1297
  export { angular };
2233
1298