@analogjs/vite-plugin-angular 3.0.0-alpha.5 → 3.0.0-alpha.51

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 (194) hide show
  1. package/README.md +30 -0
  2. package/migrations/migrate-setup-vitest/migrate-setup-vitest.d.ts +2 -0
  3. package/migrations/migrate-setup-vitest/migrate-setup-vitest.js +49 -0
  4. package/migrations/migrate-setup-vitest/migrate-setup-vitest.js.map +1 -0
  5. package/migrations/migration.json +7 -1
  6. package/migrations/migrations.json +9 -0
  7. package/migrations/update-3-0-0/migrate-setup-vitest.d.ts +2 -0
  8. package/migrations/update-3-0-0/migrate-setup-vitest.js +36 -0
  9. package/migrations/update-3-0-0/migrate-setup-vitest.js.map +1 -0
  10. package/package.json +41 -12
  11. package/src/index.d.ts +3 -2
  12. package/src/index.js +6 -2
  13. package/src/index.js.map +1 -1
  14. package/src/lib/angular-build-optimizer-plugin.d.ts +4 -4
  15. package/src/lib/angular-build-optimizer-plugin.js +48 -62
  16. package/src/lib/angular-build-optimizer-plugin.js.map +1 -1
  17. package/src/lib/angular-jit-plugin.d.ts +3 -3
  18. package/src/lib/angular-jit-plugin.js +39 -37
  19. package/src/lib/angular-jit-plugin.js.map +1 -1
  20. package/src/lib/angular-pending-tasks.plugin.d.ts +7 -7
  21. package/src/lib/angular-pending-tasks.plugin.js +17 -18
  22. package/src/lib/angular-pending-tasks.plugin.js.map +1 -1
  23. package/src/lib/angular-vite-plugin.d.ts +180 -44
  24. package/src/lib/angular-vite-plugin.js +1233 -969
  25. package/src/lib/angular-vite-plugin.js.map +1 -1
  26. package/src/lib/angular-vitest-plugin.d.ts +19 -15
  27. package/src/lib/angular-vitest-plugin.js +99 -114
  28. package/src/lib/angular-vitest-plugin.js.map +1 -1
  29. package/src/lib/compilation-api/compilation-api-plugin.d.ts +29 -0
  30. package/src/lib/compilation-api/compilation-api-plugin.js +480 -0
  31. package/src/lib/compilation-api/compilation-api-plugin.js.map +1 -0
  32. package/src/lib/compilation-api/index.d.ts +1 -0
  33. package/src/lib/compilation-api/index.js +1 -0
  34. package/src/lib/compiler/angular-version.d.ts +19 -0
  35. package/src/lib/compiler/angular-version.js +16 -0
  36. package/src/lib/compiler/angular-version.js.map +1 -0
  37. package/src/lib/compiler/class-field-lowering.d.ts +23 -0
  38. package/src/lib/compiler/class-field-lowering.js +131 -0
  39. package/src/lib/compiler/class-field-lowering.js.map +1 -0
  40. package/src/lib/compiler/compile.d.ts +44 -0
  41. package/src/lib/compiler/compile.js +731 -0
  42. package/src/lib/compiler/compile.js.map +1 -0
  43. package/src/lib/compiler/constants.d.ts +18 -0
  44. package/src/lib/compiler/constants.js +52 -0
  45. package/src/lib/compiler/constants.js.map +1 -0
  46. package/src/lib/compiler/debug.d.ts +22 -0
  47. package/src/lib/compiler/debug.js +20 -0
  48. package/src/lib/compiler/debug.js.map +1 -0
  49. package/src/lib/compiler/defer.d.ts +57 -0
  50. package/src/lib/compiler/defer.js +154 -0
  51. package/src/lib/compiler/defer.js.map +1 -0
  52. package/src/lib/compiler/dts-reader.d.ts +35 -0
  53. package/src/lib/compiler/dts-reader.js +365 -0
  54. package/src/lib/compiler/dts-reader.js.map +1 -0
  55. package/src/lib/compiler/hmr.d.ts +16 -0
  56. package/src/lib/compiler/hmr.js +69 -0
  57. package/src/lib/compiler/hmr.js.map +1 -0
  58. package/src/lib/compiler/index.d.ts +7 -0
  59. package/src/lib/compiler/index.js +7 -0
  60. package/src/lib/compiler/jit-metadata.d.ts +14 -0
  61. package/src/lib/compiler/jit-metadata.js +146 -0
  62. package/src/lib/compiler/jit-metadata.js.map +1 -0
  63. package/src/lib/compiler/jit-transform.d.ts +24 -0
  64. package/src/lib/compiler/jit-transform.js +200 -0
  65. package/src/lib/compiler/jit-transform.js.map +1 -0
  66. package/src/lib/compiler/js-emitter.d.ts +10 -0
  67. package/src/lib/compiler/js-emitter.js +445 -0
  68. package/src/lib/compiler/js-emitter.js.map +1 -0
  69. package/src/lib/compiler/metadata.d.ts +45 -0
  70. package/src/lib/compiler/metadata.js +633 -0
  71. package/src/lib/compiler/metadata.js.map +1 -0
  72. package/src/lib/compiler/registry.d.ts +49 -0
  73. package/src/lib/compiler/registry.js +164 -0
  74. package/src/lib/compiler/registry.js.map +1 -0
  75. package/src/lib/compiler/resource-inliner.d.ts +21 -0
  76. package/src/lib/compiler/resource-inliner.js +152 -0
  77. package/src/lib/compiler/resource-inliner.js.map +1 -0
  78. package/src/lib/compiler/style-ast.d.ts +8 -0
  79. package/src/lib/compiler/style-ast.js +54 -0
  80. package/src/lib/compiler/style-ast.js.map +1 -0
  81. package/src/lib/compiler/styles.d.ts +13 -0
  82. package/src/lib/compiler/test-helpers.d.ts +7 -0
  83. package/src/lib/compiler/type-elision.d.ts +26 -0
  84. package/src/lib/compiler/type-elision.js +211 -0
  85. package/src/lib/compiler/type-elision.js.map +1 -0
  86. package/src/lib/compiler/utils.d.ts +10 -0
  87. package/src/lib/compiler/utils.js +35 -0
  88. package/src/lib/compiler/utils.js.map +1 -0
  89. package/src/lib/compiler-plugin.d.ts +11 -11
  90. package/src/lib/compiler-plugin.js +43 -44
  91. package/src/lib/compiler-plugin.js.map +1 -1
  92. package/src/lib/component-resolvers.d.ts +23 -5
  93. package/src/lib/component-resolvers.js +153 -63
  94. package/src/lib/component-resolvers.js.map +1 -1
  95. package/src/lib/encapsulation-plugin.d.ts +13 -0
  96. package/src/lib/encapsulation-plugin.js +48 -0
  97. package/src/lib/encapsulation-plugin.js.map +1 -0
  98. package/src/lib/fast-compile-plugin.d.ts +28 -0
  99. package/src/lib/fast-compile-plugin.js +289 -0
  100. package/src/lib/fast-compile-plugin.js.map +1 -0
  101. package/src/lib/host.d.ts +10 -8
  102. package/src/lib/host.js +113 -101
  103. package/src/lib/host.js.map +1 -1
  104. package/src/lib/live-reload-plugin.d.ts +5 -5
  105. package/src/lib/live-reload-plugin.js +61 -62
  106. package/src/lib/live-reload-plugin.js.map +1 -1
  107. package/src/lib/models.d.ts +9 -9
  108. package/src/lib/nx-folder-plugin.d.ts +5 -5
  109. package/src/lib/nx-folder-plugin.js +18 -16
  110. package/src/lib/nx-folder-plugin.js.map +1 -1
  111. package/src/lib/plugins/file-replacements.plugin.d.ts +4 -4
  112. package/src/lib/plugins/file-replacements.plugin.js +40 -62
  113. package/src/lib/plugins/file-replacements.plugin.js.map +1 -1
  114. package/src/lib/router-plugin.d.ts +1 -1
  115. package/src/lib/router-plugin.js +23 -23
  116. package/src/lib/router-plugin.js.map +1 -1
  117. package/src/lib/style-pipeline.d.ts +15 -0
  118. package/src/lib/style-pipeline.js +31 -0
  119. package/src/lib/style-pipeline.js.map +1 -0
  120. package/src/lib/style-preprocessor.d.ts +35 -0
  121. package/src/lib/style-preprocessor.js +35 -0
  122. package/src/lib/style-preprocessor.js.map +1 -0
  123. package/src/lib/stylesheet-registry.d.ts +73 -0
  124. package/src/lib/stylesheet-registry.js +168 -0
  125. package/src/lib/stylesheet-registry.js.map +1 -0
  126. package/src/lib/tailwind-plugin.d.ts +34 -0
  127. package/src/lib/tailwind-plugin.js +116 -0
  128. package/src/lib/tailwind-plugin.js.map +1 -0
  129. package/src/lib/template-class-binding-guard-plugin.d.ts +30 -0
  130. package/src/lib/template-class-binding-guard-plugin.js +237 -0
  131. package/src/lib/template-class-binding-guard-plugin.js.map +1 -0
  132. package/src/lib/tools/package.json +2 -7
  133. package/src/lib/tools/src/builders/vite/vite-build.impl.js +31 -38
  134. package/src/lib/tools/src/builders/vite/vite-build.impl.js.map +1 -1
  135. package/src/lib/tools/src/builders/vite-dev-server/dev-server.impl.js +51 -62
  136. package/src/lib/tools/src/builders/vite-dev-server/dev-server.impl.js.map +1 -1
  137. package/src/lib/tools/src/index.js +0 -2
  138. package/src/lib/utils/compilation-shared.d.ts +58 -0
  139. package/src/lib/utils/compilation-shared.js +133 -0
  140. package/src/lib/utils/compilation-shared.js.map +1 -0
  141. package/src/lib/utils/compiler-plugin-options.d.ts +11 -11
  142. package/src/lib/utils/debug-harness.d.ts +23 -0
  143. package/src/lib/utils/debug-harness.js +88 -0
  144. package/src/lib/utils/debug-harness.js.map +1 -0
  145. package/src/lib/utils/debug-log-file.d.ts +5 -0
  146. package/src/lib/utils/debug-log-file.js +56 -0
  147. package/src/lib/utils/debug-log-file.js.map +1 -0
  148. package/src/lib/utils/debug.d.ts +28 -0
  149. package/src/lib/utils/debug.js +39 -0
  150. package/src/lib/utils/debug.js.map +1 -0
  151. package/src/lib/utils/devkit.d.ts +6 -6
  152. package/src/lib/utils/devkit.js +34 -38
  153. package/src/lib/utils/devkit.js.map +1 -1
  154. package/src/lib/utils/hmr-candidates.d.ts +28 -28
  155. package/src/lib/utils/plugin-config.d.ts +37 -0
  156. package/src/lib/utils/plugin-config.js +71 -0
  157. package/src/lib/utils/plugin-config.js.map +1 -0
  158. package/src/lib/utils/rolldown.d.ts +2 -0
  159. package/src/lib/utils/rolldown.js +12 -0
  160. package/src/lib/utils/rolldown.js.map +1 -0
  161. package/src/lib/utils/safe-module-paths.d.ts +16 -0
  162. package/src/lib/utils/safe-module-paths.js +29 -0
  163. package/src/lib/utils/safe-module-paths.js.map +1 -0
  164. package/src/lib/utils/source-file-cache.d.ts +8 -15
  165. package/src/lib/utils/source-file-cache.js +35 -37
  166. package/src/lib/utils/source-file-cache.js.map +1 -1
  167. package/src/lib/utils/tailwind-reference.d.ts +12 -0
  168. package/src/lib/utils/tailwind-reference.js +99 -0
  169. package/src/lib/utils/tailwind-reference.js.map +1 -0
  170. package/src/lib/utils/tsconfig-resolver.d.ts +28 -0
  171. package/src/lib/utils/tsconfig-resolver.js +191 -0
  172. package/src/lib/utils/tsconfig-resolver.js.map +1 -0
  173. package/src/lib/utils/virtual-ids.d.ts +4 -0
  174. package/src/lib/utils/virtual-ids.js +23 -0
  175. package/src/lib/utils/virtual-ids.js.map +1 -0
  176. package/src/lib/utils/virtual-resources.d.ts +19 -0
  177. package/src/lib/utils/virtual-resources.js +38 -0
  178. package/src/lib/utils/virtual-resources.js.map +1 -0
  179. package/src/lib/virtual-modules-plugin.d.ts +5 -0
  180. package/src/lib/virtual-modules-plugin.js +23 -0
  181. package/src/lib/virtual-modules-plugin.js.map +1 -0
  182. package/src/test-setup.d.ts +2 -0
  183. package/setup-vitest.d.ts +0 -4
  184. package/setup-vitest.js +0 -215
  185. package/setup-vitest.js.map +0 -1
  186. package/src/lib/models.js +0 -1
  187. package/src/lib/models.js.map +0 -1
  188. package/src/lib/tools/README.md +0 -3
  189. package/src/lib/tools/src/index.d.ts +0 -0
  190. package/src/lib/tools/src/index.js.map +0 -1
  191. package/src/lib/utils/compiler-plugin-options.js +0 -1
  192. package/src/lib/utils/compiler-plugin-options.js.map +0 -1
  193. package/src/lib/utils/hmr-candidates.js +0 -272
  194. package/src/lib/utils/hmr-candidates.js.map +0 -1
@@ -0,0 +1,34 @@
1
+ import { Plugin, ResolvedConfig } from "vite";
2
+ import type { StylePreprocessor } from "./style-preprocessor.js";
3
+ import type { AngularStylePipelineOptions } from "./style-pipeline.js";
4
+ export interface TailwindCssOptions {
5
+ rootStylesheet: string;
6
+ prefixes?: string[];
7
+ }
8
+ export interface TailwindReferencePluginOptions {
9
+ tailwindCss?: TailwindCssOptions;
10
+ }
11
+ export declare function tailwindReferencePlugin(options: TailwindReferencePluginOptions): Plugin;
12
+ /**
13
+ * Builds a resolved stylePreprocessor function from plugin options.
14
+ *
15
+ * When `tailwindCss` is configured, creates an injector that prepends
16
+ * `@reference "<rootStylesheet>"` into component CSS that uses Tailwind
17
+ * utilities. Uses absolute paths because Angular's externalRuntimeStyles
18
+ * serves component CSS as virtual modules (hash-based IDs) with no
19
+ * meaningful directory — relative paths can't resolve from a hash.
20
+ *
21
+ * If both `tailwindCss` and `stylePreprocessor` are provided, they are
22
+ * chained: Tailwind reference injection runs first, then the user's
23
+ * custom preprocessor.
24
+ */
25
+ export declare function buildStylePreprocessor(options?: {
26
+ stylePreprocessor?: StylePreprocessor;
27
+ stylePipeline?: AngularStylePipelineOptions;
28
+ tailwindCss?: TailwindCssOptions;
29
+ }): StylePreprocessor | undefined;
30
+ /**
31
+ * Validates the Tailwind CSS integration configuration and emits actionable
32
+ * warnings for common misconfigurations that cause silent failures.
33
+ */
34
+ export declare function validateTailwindConfig(tailwindCss: TailwindCssOptions | undefined, config: ResolvedConfig, isWatchMode: boolean): void;
@@ -0,0 +1,116 @@
1
+ import { debugTailwind, debugTailwindV } from "./utils/debug.js";
2
+ import { inspectCssTailwindDirectives, throwTailwindReferenceTextError } from "./utils/tailwind-reference.js";
3
+ import { composeStylePreprocessors } from "./style-preprocessor.js";
4
+ import { stylePipelinePreprocessorFromPlugins } from "./style-pipeline.js";
5
+ import { existsSync, readFileSync } from "node:fs";
6
+ import { basename, dirname, isAbsolute } from "node:path";
7
+ import { normalizePath } from "vite";
8
+ //#region packages/vite-plugin-angular/src/lib/tailwind-plugin.ts
9
+ /**
10
+ * Core injection logic shared by both the Vite pre-transform plugin and the
11
+ * Angular style preprocessor. Returns the `@reference`-prepended CSS when
12
+ * injection is needed, or `undefined` when the file should be left alone.
13
+ */
14
+ function injectTailwindReference(code, opts) {
15
+ const directiveState = inspectCssTailwindDirectives(code);
16
+ if (directiveState.hasReferenceDirective || directiveState.hasTailwindImportDirective) return;
17
+ if (!(opts.prefixes ? opts.prefixes.some((p) => directiveState.commentlessCode.includes(p)) : directiveState.commentlessCode.includes("@apply"))) return;
18
+ if (directiveState.hasReferenceText) throwTailwindReferenceTextError(opts.fileId, opts.rootStylesheet);
19
+ return `@reference "${opts.rootStylesheet.replace(/\\/g, "/")}";\n${code}`;
20
+ }
21
+ function tailwindReferencePlugin(options) {
22
+ return {
23
+ name: "@analogjs/vite-plugin-angular:tailwind-reference",
24
+ enforce: "pre",
25
+ transform(code, id) {
26
+ const tw = options.tailwindCss;
27
+ if (!tw || !id.includes(".css")) return;
28
+ if (id.split("?")[0] === tw.rootStylesheet) return;
29
+ const rootBasename = basename(tw.rootStylesheet);
30
+ if (inspectCssTailwindDirectives(code).commentlessCode.includes(rootBasename)) return;
31
+ const result = injectTailwindReference(code, {
32
+ rootStylesheet: tw.rootStylesheet,
33
+ prefixes: tw.prefixes,
34
+ fileId: id
35
+ });
36
+ if (result) debugTailwind("injected @reference via pre-transform", { id: id.split("/").slice(-2).join("/") });
37
+ return result;
38
+ }
39
+ };
40
+ }
41
+ /**
42
+ * Builds a resolved stylePreprocessor function from plugin options.
43
+ *
44
+ * When `tailwindCss` is configured, creates an injector that prepends
45
+ * `@reference "<rootStylesheet>"` into component CSS that uses Tailwind
46
+ * utilities. Uses absolute paths because Angular's externalRuntimeStyles
47
+ * serves component CSS as virtual modules (hash-based IDs) with no
48
+ * meaningful directory — relative paths can't resolve from a hash.
49
+ *
50
+ * If both `tailwindCss` and `stylePreprocessor` are provided, they are
51
+ * chained: Tailwind reference injection runs first, then the user's
52
+ * custom preprocessor.
53
+ */
54
+ function buildStylePreprocessor(options) {
55
+ const userPreprocessor = options?.stylePreprocessor;
56
+ const stylePipelinePreprocessor = stylePipelinePreprocessorFromPlugins(options?.stylePipeline);
57
+ const tw = options?.tailwindCss;
58
+ if (!tw && !userPreprocessor && !stylePipelinePreprocessor) return;
59
+ let tailwindPreprocessor;
60
+ if (tw) {
61
+ const rootStylesheet = tw.rootStylesheet;
62
+ const prefixes = tw.prefixes;
63
+ debugTailwind("configured", {
64
+ rootStylesheet,
65
+ prefixes
66
+ });
67
+ 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.`);
68
+ tailwindPreprocessor = (code, filename) => {
69
+ const result = injectTailwindReference(code, {
70
+ rootStylesheet,
71
+ prefixes,
72
+ fileId: filename
73
+ });
74
+ if (result) {
75
+ debugTailwind("injected @reference via preprocessor", { filename });
76
+ return result;
77
+ }
78
+ debugTailwindV("skip (no injection needed)", { filename });
79
+ return code;
80
+ };
81
+ }
82
+ if (tailwindPreprocessor && (stylePipelinePreprocessor || userPreprocessor)) debugTailwind("chained with style pipeline or user stylePreprocessor");
83
+ return composeStylePreprocessors([
84
+ tailwindPreprocessor,
85
+ stylePipelinePreprocessor,
86
+ userPreprocessor
87
+ ]);
88
+ }
89
+ /**
90
+ * Validates the Tailwind CSS integration configuration and emits actionable
91
+ * warnings for common misconfigurations that cause silent failures.
92
+ */
93
+ function validateTailwindConfig(tailwindCss, config, isWatchMode) {
94
+ const PREFIX = "[@analogjs/vite-plugin-angular]";
95
+ const tw = tailwindCss;
96
+ if (!tw) return;
97
+ 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.`);
98
+ const hasTailwindPlugin = config.plugins.some((p) => p.name.startsWith("@tailwindcss/vite") || p.name.startsWith("tailwindcss"));
99
+ 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`);
100
+ if (isWatchMode && tw.rootStylesheet) {
101
+ const projectRoot = normalizePath(config.root);
102
+ const normalizedRootStylesheet = normalizePath(tw.rootStylesheet);
103
+ if (!normalizedRootStylesheet.startsWith(projectRoot)) {
104
+ 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`);
105
+ }
106
+ }
107
+ 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`);
108
+ if (existsSync(tw.rootStylesheet)) try {
109
+ const rootContent = readFileSync(tw.rootStylesheet, "utf-8");
110
+ 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`);
111
+ } catch {}
112
+ }
113
+ //#endregion
114
+ export { buildStylePreprocessor, tailwindReferencePlugin, validateTailwindConfig };
115
+
116
+ //# sourceMappingURL=tailwind-plugin.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tailwind-plugin.js","names":[],"sources":["../../../src/lib/tailwind-plugin.ts"],"sourcesContent":["import { existsSync, readFileSync } from 'node:fs';\nimport { basename, dirname, isAbsolute } from 'node:path';\nimport { normalizePath, Plugin, ResolvedConfig } from 'vite';\nimport {\n inspectCssTailwindDirectives,\n throwTailwindReferenceTextError,\n} from './utils/tailwind-reference.js';\nimport { debugTailwind, debugTailwindV } from './utils/debug.js';\nimport { composeStylePreprocessors } from './style-preprocessor.js';\nimport type { StylePreprocessor } from './style-preprocessor.js';\nimport { stylePipelinePreprocessorFromPlugins } from './style-pipeline.js';\nimport type { AngularStylePipelineOptions } from './style-pipeline.js';\n\nexport interface TailwindCssOptions {\n rootStylesheet: string;\n prefixes?: string[];\n}\n\nexport interface TailwindReferencePluginOptions {\n tailwindCss?: TailwindCssOptions;\n}\n\n/**\n * Core injection logic shared by both the Vite pre-transform plugin and the\n * Angular style preprocessor. Returns the `@reference`-prepended CSS when\n * injection is needed, or `undefined` when the file should be left alone.\n */\nfunction injectTailwindReference(\n code: string,\n opts: {\n rootStylesheet: string;\n prefixes?: string[];\n fileId: string;\n },\n): string | undefined {\n const directiveState = inspectCssTailwindDirectives(code);\n\n if (\n directiveState.hasReferenceDirective ||\n directiveState.hasTailwindImportDirective\n ) {\n return undefined;\n }\n\n const needsRef = opts.prefixes\n ? opts.prefixes.some((p) => directiveState.commentlessCode.includes(p))\n : directiveState.commentlessCode.includes('@apply');\n\n if (!needsRef) {\n return undefined;\n }\n\n if (directiveState.hasReferenceText) {\n throwTailwindReferenceTextError(opts.fileId, opts.rootStylesheet);\n }\n\n return `@reference \"${opts.rootStylesheet.replace(/\\\\/g, '/')}\";\\n${code}`;\n}\n\nexport function tailwindReferencePlugin(\n options: TailwindReferencePluginOptions,\n): Plugin {\n return {\n name: '@analogjs/vite-plugin-angular:tailwind-reference',\n enforce: 'pre',\n transform(code: string, id: string) {\n const tw = options.tailwindCss;\n if (!tw || !id.includes('.css')) return;\n\n const cleanId = id.split('?')[0];\n if (cleanId === tw.rootStylesheet) return;\n\n // Skip entry stylesheets that @import the root config\n const rootBasename = basename(tw.rootStylesheet);\n const directiveState = inspectCssTailwindDirectives(code);\n if (directiveState.commentlessCode.includes(rootBasename)) return;\n\n const result = injectTailwindReference(code, {\n rootStylesheet: tw.rootStylesheet,\n prefixes: tw.prefixes,\n fileId: id,\n });\n\n if (result) {\n debugTailwind('injected @reference via pre-transform', {\n id: id.split('/').slice(-2).join('/'),\n });\n }\n\n return result;\n },\n };\n}\n\n/**\n * Builds a resolved stylePreprocessor function from plugin options.\n *\n * When `tailwindCss` is configured, creates an injector that prepends\n * `@reference \"<rootStylesheet>\"` into component CSS that uses Tailwind\n * utilities. Uses absolute paths because Angular's externalRuntimeStyles\n * serves component CSS as virtual modules (hash-based IDs) with no\n * meaningful directory — relative paths can't resolve from a hash.\n *\n * If both `tailwindCss` and `stylePreprocessor` are provided, they are\n * chained: Tailwind reference injection runs first, then the user's\n * custom preprocessor.\n */\nexport function buildStylePreprocessor(options?: {\n stylePreprocessor?: StylePreprocessor;\n stylePipeline?: AngularStylePipelineOptions;\n tailwindCss?: TailwindCssOptions;\n}): StylePreprocessor | undefined {\n const userPreprocessor = options?.stylePreprocessor;\n const stylePipelinePreprocessor = stylePipelinePreprocessorFromPlugins(\n options?.stylePipeline,\n );\n const tw = options?.tailwindCss;\n\n if (!tw && !userPreprocessor && !stylePipelinePreprocessor) {\n return undefined;\n }\n\n let tailwindPreprocessor:\n | ((code: string, filename: string) => string)\n | undefined;\n\n if (tw) {\n const rootStylesheet = tw.rootStylesheet;\n const prefixes = tw.prefixes;\n debugTailwind('configured', { rootStylesheet, prefixes });\n\n if (!existsSync(rootStylesheet)) {\n console.warn(\n `[@analogjs/vite-plugin-angular] tailwindCss.rootStylesheet not found ` +\n `at \"${rootStylesheet}\". @reference directives will point to a ` +\n `non-existent file, which will cause Tailwind CSS errors. ` +\n `Ensure the path is absolute and the file exists.`,\n );\n }\n\n tailwindPreprocessor = (code: string, filename: string): string => {\n const result = injectTailwindReference(code, {\n rootStylesheet,\n prefixes,\n fileId: filename,\n });\n\n if (result) {\n debugTailwind('injected @reference via preprocessor', { filename });\n return result;\n }\n\n debugTailwindV('skip (no injection needed)', { filename });\n return code;\n };\n }\n\n if (tailwindPreprocessor && (stylePipelinePreprocessor || userPreprocessor)) {\n debugTailwind('chained with style pipeline or user stylePreprocessor');\n }\n\n return composeStylePreprocessors([\n tailwindPreprocessor,\n stylePipelinePreprocessor,\n userPreprocessor,\n ]);\n}\n\n/**\n * Validates the Tailwind CSS integration configuration and emits actionable\n * warnings for common misconfigurations that cause silent failures.\n */\nexport function validateTailwindConfig(\n tailwindCss: TailwindCssOptions | undefined,\n config: ResolvedConfig,\n isWatchMode: boolean,\n): void {\n const PREFIX = '[@analogjs/vite-plugin-angular]';\n const tw = tailwindCss;\n\n if (!tw) return;\n\n if (!isAbsolute(tw.rootStylesheet)) {\n console.warn(\n `${PREFIX} tailwindCss.rootStylesheet must be an absolute path. ` +\n `Got: \"${tw.rootStylesheet}\". Use path.resolve(__dirname, '...') ` +\n `in your vite.config to convert it.`,\n );\n }\n\n const resolvedPlugins = config.plugins;\n const hasTailwindPlugin = resolvedPlugins.some(\n (p) =>\n p.name.startsWith('@tailwindcss/vite') ||\n p.name.startsWith('tailwindcss'),\n );\n\n if (isWatchMode && !hasTailwindPlugin) {\n throw new Error(\n `${PREFIX} tailwindCss is configured but no @tailwindcss/vite ` +\n `plugin was found. Component CSS with @apply directives will ` +\n `not be processed.\\n\\n` +\n ` Fix: npm install @tailwindcss/vite --save-dev\\n` +\n ` Then add tailwindcss() to your vite.config plugins array.\\n`,\n );\n }\n\n if (isWatchMode && tw.rootStylesheet) {\n const projectRoot = normalizePath(config.root);\n const normalizedRootStylesheet = normalizePath(tw.rootStylesheet);\n if (!normalizedRootStylesheet.startsWith(projectRoot)) {\n const fsAllow = config.server?.fs?.allow ?? [];\n const isAllowed = fsAllow.some((allowed) =>\n normalizedRootStylesheet.startsWith(normalizePath(allowed)),\n );\n if (!isAllowed) {\n console.warn(\n `${PREFIX} tailwindCss.rootStylesheet is outside the Vite ` +\n `project root. The dev server may reject it with 403.\\n\\n` +\n ` Root: ${projectRoot}\\n` +\n ` Stylesheet: ${tw.rootStylesheet}\\n\\n` +\n ` Fix: server.fs.allow: ['${dirname(tw.rootStylesheet)}']\\n`,\n );\n }\n }\n }\n\n if (tw.prefixes !== undefined && tw.prefixes.length === 0) {\n console.warn(\n `${PREFIX} tailwindCss.prefixes is an empty array. No component ` +\n `stylesheets will receive @reference injection. Either remove ` +\n `the prefixes option (to use @apply detection) or specify your ` +\n `prefixes: ['tw:']\\n`,\n );\n }\n\n if (existsSync(tw.rootStylesheet)) {\n try {\n const rootContent = readFileSync(tw.rootStylesheet, 'utf-8');\n if (\n !rootContent.includes('@import \"tailwindcss\"') &&\n !rootContent.includes(\"@import 'tailwindcss'\")\n ) {\n console.warn(\n `${PREFIX} tailwindCss.rootStylesheet does not contain ` +\n `@import \"tailwindcss\". The @reference directive will ` +\n `point to a file without Tailwind configuration.\\n\\n` +\n ` File: ${tw.rootStylesheet}\\n`,\n );\n }\n } catch {\n // Silently skip — existence check already warned in buildStylePreprocessor.\n }\n }\n}\n"],"mappings":"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"}
@@ -0,0 +1,30 @@
1
+ import { Plugin } from "vite";
2
+ import { StyleUrlsResolver } from "./component-resolvers.js";
3
+ export interface ActiveGraphComponentRecord {
4
+ file: string;
5
+ className: string;
6
+ selector?: string;
7
+ }
8
+ export interface StyleOwnerRecord {
9
+ sourcePath: string;
10
+ ownerFile: string;
11
+ }
12
+ interface TemplateClassBindingIssue {
13
+ line: number;
14
+ column: number;
15
+ snippet: string;
16
+ }
17
+ export interface TemplateClassBindingGuardContext {
18
+ styleUrlsResolver: StyleUrlsResolver;
19
+ activeGraphComponentMetadata: Map<string, ActiveGraphComponentRecord[]>;
20
+ selectorOwners: Map<string, Set<string>>;
21
+ classNameOwners: Map<string, Set<string>>;
22
+ transformedStyleOwnerMetadata: Map<string, StyleOwnerRecord[]>;
23
+ styleSourceOwners: Map<string, Set<string>>;
24
+ }
25
+ export declare function templateClassBindingGuardPlugin(ctx: TemplateClassBindingGuardContext): Plugin;
26
+ export declare function removeActiveGraphMetadata(ctx: TemplateClassBindingGuardContext, file: string): void;
27
+ export declare function removeStyleOwnerMetadata(ctx: TemplateClassBindingGuardContext, file: string): void;
28
+ export declare function findStaticClassAndBoundClassConflicts(template: string): TemplateClassBindingIssue[];
29
+ export declare function findBoundClassAndNgClassConflicts(template: string): TemplateClassBindingIssue[];
30
+ export {};
@@ -0,0 +1,237 @@
1
+ import { debugHmrV } from "./utils/debug.js";
2
+ import { getAngularComponentMetadata } from "./component-resolvers.js";
3
+ import { TS_EXT_REGEX } from "./utils/plugin-config.js";
4
+ import { normalizePath } from "vite";
5
+ //#region packages/vite-plugin-angular/src/lib/template-class-binding-guard-plugin.ts
6
+ function templateClassBindingGuardPlugin(ctx) {
7
+ return {
8
+ name: "@analogjs/vite-plugin-angular:template-class-binding-guard",
9
+ enforce: "pre",
10
+ transform(code, id) {
11
+ if (id.includes("node_modules")) return;
12
+ const cleanId = id.split("?")[0];
13
+ if (/\.(html|htm)$/i.test(cleanId)) {
14
+ const staticClassIssue = findStaticClassAndBoundClassConflicts(code)[0];
15
+ if (staticClassIssue) throwTemplateClassBindingConflict(cleanId, staticClassIssue);
16
+ const mixedClassIssue = findBoundClassAndNgClassConflicts(code)[0];
17
+ if (mixedClassIssue) this.warn([
18
+ "[Analog Angular] Conflicting class composition.",
19
+ `File: ${cleanId}:${mixedClassIssue.line}:${mixedClassIssue.column}`,
20
+ "This element mixes `[class]` and `[ngClass]`.",
21
+ "Prefer a single class-binding strategy so class merging stays predictable.",
22
+ "Use one `[ngClass]` expression or explicit `[class.foo]` bindings.",
23
+ `Snippet: ${mixedClassIssue.snippet}`
24
+ ].join("\n"));
25
+ return;
26
+ }
27
+ if (TS_EXT_REGEX.test(cleanId)) {
28
+ const rawStyleUrls = ctx.styleUrlsResolver.resolve(code, cleanId);
29
+ registerStyleOwnerMetadata(ctx, cleanId, rawStyleUrls);
30
+ debugHmrV("component stylesheet owner metadata registered", {
31
+ file: cleanId,
32
+ styleUrlCount: rawStyleUrls.length,
33
+ styleUrls: rawStyleUrls,
34
+ ownerSources: [...ctx.transformedStyleOwnerMetadata.get(cleanId)?.map((record) => record.sourcePath) ?? []]
35
+ });
36
+ const components = getAngularComponentMetadata(code);
37
+ const inlineTemplateIssue = components.flatMap((component) => component.inlineTemplates.flatMap((template) => findStaticClassAndBoundClassConflicts(template)))[0];
38
+ if (inlineTemplateIssue) throwTemplateClassBindingConflict(cleanId, inlineTemplateIssue);
39
+ const mixedInlineClassIssue = components.flatMap((component) => component.inlineTemplates.flatMap((template) => findBoundClassAndNgClassConflicts(template)))[0];
40
+ if (mixedInlineClassIssue) this.warn([
41
+ "[Analog Angular] Conflicting class composition.",
42
+ `File: ${cleanId}:${mixedInlineClassIssue.line}:${mixedInlineClassIssue.column}`,
43
+ "This element mixes `[class]` and `[ngClass]`.",
44
+ "Prefer a single class-binding strategy so class merging stays predictable.",
45
+ "Use one `[ngClass]` expression or explicit `[class.foo]` bindings.",
46
+ `Snippet: ${mixedInlineClassIssue.snippet}`
47
+ ].join("\n"));
48
+ registerActiveGraphMetadata(ctx, cleanId, components.map((component) => ({
49
+ file: cleanId,
50
+ className: component.className,
51
+ selector: component.selector
52
+ })));
53
+ for (const component of components) {
54
+ if (!component.selector && !isLikelyPageOnlyComponent(cleanId)) throw new Error([
55
+ "[Analog Angular] Selectorless component detected.",
56
+ `File: ${cleanId}`,
57
+ `Component: ${component.className}`,
58
+ "This component has no `selector`, so Angular will render it as `ng-component`.",
59
+ "That increases the chance of component ID collisions and makes diagnostics harder to interpret.",
60
+ "Add an explicit selector for reusable components.",
61
+ "Selectorless components are only supported for page and route-only files."
62
+ ].join("\n"));
63
+ if (component.selector) {
64
+ const selectorEntries = ctx.selectorOwners.get(component.selector);
65
+ if (selectorEntries && selectorEntries.size > 1) throw new Error([
66
+ "[Analog Angular] Duplicate component selector detected.",
67
+ `Selector: ${component.selector}`,
68
+ "Multiple components in the active application graph use the same selector.",
69
+ "Selectors must be unique within the active graph to avoid ambiguous rendering and confusing diagnostics.",
70
+ `Locations:\n${formatActiveGraphLocations(selectorEntries)}`
71
+ ].join("\n"));
72
+ }
73
+ const classNameEntries = ctx.classNameOwners.get(component.className);
74
+ if (classNameEntries && classNameEntries.size > 1) this.warn([
75
+ "[Analog Angular] Duplicate component class name detected.",
76
+ `Class name: ${component.className}`,
77
+ "Two or more Angular components in the active graph share the same exported class name.",
78
+ "Rename one of them to keep HMR, stack traces, and compiler diagnostics unambiguous.",
79
+ `Locations:\n${formatActiveGraphLocations(classNameEntries)}`
80
+ ].join("\n"));
81
+ }
82
+ }
83
+ }
84
+ };
85
+ }
86
+ function removeActiveGraphMetadata(ctx, file) {
87
+ const previous = ctx.activeGraphComponentMetadata.get(file);
88
+ if (!previous) return;
89
+ for (const record of previous) {
90
+ const location = `${record.file}#${record.className}`;
91
+ if (record.selector) {
92
+ const selectorSet = ctx.selectorOwners.get(record.selector);
93
+ selectorSet?.delete(location);
94
+ if (selectorSet?.size === 0) ctx.selectorOwners.delete(record.selector);
95
+ }
96
+ const classNameSet = ctx.classNameOwners.get(record.className);
97
+ classNameSet?.delete(location);
98
+ if (classNameSet?.size === 0) ctx.classNameOwners.delete(record.className);
99
+ }
100
+ ctx.activeGraphComponentMetadata.delete(file);
101
+ }
102
+ function registerActiveGraphMetadata(ctx, file, records) {
103
+ removeActiveGraphMetadata(ctx, file);
104
+ if (records.length === 0) return;
105
+ ctx.activeGraphComponentMetadata.set(file, records);
106
+ for (const record of records) {
107
+ const location = `${record.file}#${record.className}`;
108
+ if (record.selector) {
109
+ let selectorSet = ctx.selectorOwners.get(record.selector);
110
+ if (!selectorSet) {
111
+ selectorSet = /* @__PURE__ */ new Set();
112
+ ctx.selectorOwners.set(record.selector, selectorSet);
113
+ }
114
+ selectorSet.add(location);
115
+ }
116
+ let classNameSet = ctx.classNameOwners.get(record.className);
117
+ if (!classNameSet) {
118
+ classNameSet = /* @__PURE__ */ new Set();
119
+ ctx.classNameOwners.set(record.className, classNameSet);
120
+ }
121
+ classNameSet.add(location);
122
+ }
123
+ }
124
+ function removeStyleOwnerMetadata(ctx, file) {
125
+ const previous = ctx.transformedStyleOwnerMetadata.get(file);
126
+ if (!previous) return;
127
+ for (const record of previous) {
128
+ const owners = ctx.styleSourceOwners.get(record.sourcePath);
129
+ owners?.delete(record.ownerFile);
130
+ if (owners?.size === 0) ctx.styleSourceOwners.delete(record.sourcePath);
131
+ }
132
+ ctx.transformedStyleOwnerMetadata.delete(file);
133
+ }
134
+ function registerStyleOwnerMetadata(ctx, file, styleUrls) {
135
+ removeStyleOwnerMetadata(ctx, file);
136
+ const records = styleUrls.map((urlSet) => {
137
+ const [, absoluteFileUrl] = urlSet.split("|");
138
+ return absoluteFileUrl ? {
139
+ ownerFile: file,
140
+ sourcePath: normalizePath(absoluteFileUrl)
141
+ } : void 0;
142
+ }).filter((record) => !!record);
143
+ if (records.length === 0) return;
144
+ ctx.transformedStyleOwnerMetadata.set(file, records);
145
+ for (const record of records) {
146
+ let owners = ctx.styleSourceOwners.get(record.sourcePath);
147
+ if (!owners) {
148
+ owners = /* @__PURE__ */ new Set();
149
+ ctx.styleSourceOwners.set(record.sourcePath, owners);
150
+ }
151
+ owners.add(record.ownerFile);
152
+ }
153
+ }
154
+ function isLikelyPageOnlyComponent(id) {
155
+ return id.includes("/pages/") || /\.page\.[cm]?[jt]sx?$/i.test(id) || /\([^/]+\)\.page\.[cm]?[jt]sx?$/i.test(id);
156
+ }
157
+ function findStaticClassAndBoundClassConflicts(template) {
158
+ const issues = [];
159
+ for (const { index, snippet } of findOpeningTagSnippets(template)) {
160
+ if (!snippet.includes("[class]")) continue;
161
+ const hasStaticClass = /\sclass\s*=\s*(['"])(?:(?!\1)[\s\S])*\1/.test(snippet);
162
+ const hasBoundClass = /\s\[class\]\s*=\s*(['"])(?:(?!\1)[\s\S])*\1/.test(snippet);
163
+ if (hasStaticClass && hasBoundClass) {
164
+ const prefix = template.slice(0, index);
165
+ const line = prefix.split("\n").length;
166
+ const column = index - prefix.lastIndexOf("\n");
167
+ issues.push({
168
+ line,
169
+ column,
170
+ snippet: snippet.replace(/\s+/g, " ").trim()
171
+ });
172
+ }
173
+ }
174
+ return issues;
175
+ }
176
+ function findBoundClassAndNgClassConflicts(template) {
177
+ const issues = [];
178
+ if (!/\[class\]\s*=/.test(template) || !template.includes("[ngClass]")) return issues;
179
+ for (const { index, snippet } of findOpeningTagSnippets(template)) {
180
+ if (!/\[class\]\s*=/.test(snippet) || !snippet.includes("[ngClass]")) continue;
181
+ const prefix = template.slice(0, index);
182
+ const line = prefix.split("\n").length;
183
+ const column = index - prefix.lastIndexOf("\n");
184
+ issues.push({
185
+ line,
186
+ column,
187
+ snippet: snippet.replace(/\s+/g, " ").trim()
188
+ });
189
+ }
190
+ return issues;
191
+ }
192
+ function throwTemplateClassBindingConflict(id, issue) {
193
+ throw new Error([
194
+ "[Analog Angular] Invalid template class binding.",
195
+ `File: ${id}:${issue.line}:${issue.column}`,
196
+ "The same element uses both a static `class=\"...\"` attribute and a whole-element `[class]=\"...\"` binding.",
197
+ "That pattern can replace or conflict with static Tailwind classes, which makes styles appear to stop applying.",
198
+ "Use `[ngClass]` or explicit `[class.foo]` bindings instead of `[class]` when the element also has static classes.",
199
+ `Snippet: ${issue.snippet}`
200
+ ].join("\n"));
201
+ }
202
+ function findOpeningTagSnippets(template) {
203
+ const matches = [];
204
+ for (let index = 0; index < template.length; index++) {
205
+ if (template[index] !== "<") continue;
206
+ const tagStart = template[index + 1];
207
+ if (!tagStart || !/[a-zA-Z]/.test(tagStart)) continue;
208
+ let quote = null;
209
+ for (let end = index + 1; end < template.length; end++) {
210
+ const char = template[end];
211
+ if (quote) {
212
+ if (char === quote) quote = null;
213
+ continue;
214
+ }
215
+ if (char === "\"" || char === "'") {
216
+ quote = char;
217
+ continue;
218
+ }
219
+ if (char === ">") {
220
+ matches.push({
221
+ index,
222
+ snippet: template.slice(index, end + 1)
223
+ });
224
+ index = end;
225
+ break;
226
+ }
227
+ }
228
+ }
229
+ return matches;
230
+ }
231
+ function formatActiveGraphLocations(entries) {
232
+ return [...entries].sort().map((entry) => `- ${entry}`).join("\n");
233
+ }
234
+ //#endregion
235
+ export { findBoundClassAndNgClassConflicts, findStaticClassAndBoundClassConflicts, removeActiveGraphMetadata, removeStyleOwnerMetadata, templateClassBindingGuardPlugin };
236
+
237
+ //# sourceMappingURL=template-class-binding-guard-plugin.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"template-class-binding-guard-plugin.js","names":[],"sources":["../../../src/lib/template-class-binding-guard-plugin.ts"],"sourcesContent":["import { normalizePath, Plugin } from 'vite';\nimport {\n getAngularComponentMetadata,\n StyleUrlsResolver,\n} from './component-resolvers.js';\nimport { debugHmrV } from './utils/debug.js';\nimport { TS_EXT_REGEX } from './utils/plugin-config.js';\n\nexport interface ActiveGraphComponentRecord {\n file: string;\n className: string;\n selector?: string;\n}\n\nexport interface StyleOwnerRecord {\n sourcePath: string;\n ownerFile: string;\n}\n\ninterface TemplateClassBindingIssue {\n line: number;\n column: number;\n snippet: string;\n}\n\nexport interface TemplateClassBindingGuardContext {\n styleUrlsResolver: StyleUrlsResolver;\n activeGraphComponentMetadata: Map<string, ActiveGraphComponentRecord[]>;\n selectorOwners: Map<string, Set<string>>;\n classNameOwners: Map<string, Set<string>>;\n transformedStyleOwnerMetadata: Map<string, StyleOwnerRecord[]>;\n styleSourceOwners: Map<string, Set<string>>;\n}\n\nexport function templateClassBindingGuardPlugin(\n ctx: TemplateClassBindingGuardContext,\n): Plugin {\n return {\n name: '@analogjs/vite-plugin-angular:template-class-binding-guard',\n enforce: 'pre',\n transform(code: string, id: string) {\n if (id.includes('node_modules')) {\n return;\n }\n\n const cleanId = id.split('?')[0];\n\n if (/\\.(html|htm)$/i.test(cleanId)) {\n const staticClassIssue = findStaticClassAndBoundClassConflicts(code)[0];\n if (staticClassIssue) {\n throwTemplateClassBindingConflict(cleanId, staticClassIssue);\n }\n\n const mixedClassIssue = findBoundClassAndNgClassConflicts(code)[0];\n if (mixedClassIssue) {\n this.warn(\n [\n '[Analog Angular] Conflicting class composition.',\n `File: ${cleanId}:${mixedClassIssue.line}:${mixedClassIssue.column}`,\n 'This element mixes `[class]` and `[ngClass]`.',\n 'Prefer a single class-binding strategy so class merging stays predictable.',\n 'Use one `[ngClass]` expression or explicit `[class.foo]` bindings.',\n `Snippet: ${mixedClassIssue.snippet}`,\n ].join('\\n'),\n );\n }\n return;\n }\n\n if (TS_EXT_REGEX.test(cleanId)) {\n const rawStyleUrls = ctx.styleUrlsResolver.resolve(code, cleanId);\n registerStyleOwnerMetadata(ctx, cleanId, rawStyleUrls);\n debugHmrV('component stylesheet owner metadata registered', {\n file: cleanId,\n styleUrlCount: rawStyleUrls.length,\n styleUrls: rawStyleUrls,\n ownerSources: [\n ...(ctx.transformedStyleOwnerMetadata\n .get(cleanId)\n ?.map((record) => record.sourcePath) ?? []),\n ],\n });\n\n const components = getAngularComponentMetadata(code);\n\n const inlineTemplateIssue = components.flatMap((component) =>\n component.inlineTemplates.flatMap((template) =>\n findStaticClassAndBoundClassConflicts(template),\n ),\n )[0];\n\n if (inlineTemplateIssue) {\n throwTemplateClassBindingConflict(cleanId, inlineTemplateIssue);\n }\n\n const mixedInlineClassIssue = components.flatMap((component) =>\n component.inlineTemplates.flatMap((template) =>\n findBoundClassAndNgClassConflicts(template),\n ),\n )[0];\n\n if (mixedInlineClassIssue) {\n this.warn(\n [\n '[Analog Angular] Conflicting class composition.',\n `File: ${cleanId}:${mixedInlineClassIssue.line}:${mixedInlineClassIssue.column}`,\n 'This element mixes `[class]` and `[ngClass]`.',\n 'Prefer a single class-binding strategy so class merging stays predictable.',\n 'Use one `[ngClass]` expression or explicit `[class.foo]` bindings.',\n `Snippet: ${mixedInlineClassIssue.snippet}`,\n ].join('\\n'),\n );\n }\n\n const activeGraphRecords = components.map((component) => ({\n file: cleanId,\n className: component.className,\n selector: component.selector,\n }));\n\n registerActiveGraphMetadata(ctx, cleanId, activeGraphRecords);\n\n for (const component of components) {\n if (!component.selector && !isLikelyPageOnlyComponent(cleanId)) {\n throw new Error(\n [\n '[Analog Angular] Selectorless component detected.',\n `File: ${cleanId}`,\n `Component: ${component.className}`,\n 'This component has no `selector`, so Angular will render it as `ng-component`.',\n 'That increases the chance of component ID collisions and makes diagnostics harder to interpret.',\n 'Add an explicit selector for reusable components.',\n 'Selectorless components are only supported for page and route-only files.',\n ].join('\\n'),\n );\n }\n\n if (component.selector) {\n const selectorEntries = ctx.selectorOwners.get(component.selector);\n if (selectorEntries && selectorEntries.size > 1) {\n throw new Error(\n [\n '[Analog Angular] Duplicate component selector detected.',\n `Selector: ${component.selector}`,\n 'Multiple components in the active application graph use the same selector.',\n 'Selectors must be unique within the active graph to avoid ambiguous rendering and confusing diagnostics.',\n `Locations:\\n${formatActiveGraphLocations(selectorEntries)}`,\n ].join('\\n'),\n );\n }\n }\n\n const classNameEntries = ctx.classNameOwners.get(component.className);\n if (classNameEntries && classNameEntries.size > 1) {\n this.warn(\n [\n '[Analog Angular] Duplicate component class name detected.',\n `Class name: ${component.className}`,\n 'Two or more Angular components in the active graph share the same exported class name.',\n 'Rename one of them to keep HMR, stack traces, and compiler diagnostics unambiguous.',\n `Locations:\\n${formatActiveGraphLocations(classNameEntries)}`,\n ].join('\\n'),\n );\n }\n }\n }\n },\n };\n}\n\nexport function removeActiveGraphMetadata(\n ctx: TemplateClassBindingGuardContext,\n file: string,\n): void {\n const previous = ctx.activeGraphComponentMetadata.get(file);\n if (!previous) {\n return;\n }\n\n for (const record of previous) {\n const location = `${record.file}#${record.className}`;\n if (record.selector) {\n const selectorSet = ctx.selectorOwners.get(record.selector);\n selectorSet?.delete(location);\n if (selectorSet?.size === 0) {\n ctx.selectorOwners.delete(record.selector);\n }\n }\n\n const classNameSet = ctx.classNameOwners.get(record.className);\n classNameSet?.delete(location);\n if (classNameSet?.size === 0) {\n ctx.classNameOwners.delete(record.className);\n }\n }\n\n ctx.activeGraphComponentMetadata.delete(file);\n}\n\nfunction registerActiveGraphMetadata(\n ctx: TemplateClassBindingGuardContext,\n file: string,\n records: ActiveGraphComponentRecord[],\n) {\n removeActiveGraphMetadata(ctx, file);\n\n if (records.length === 0) {\n return;\n }\n\n ctx.activeGraphComponentMetadata.set(file, records);\n\n for (const record of records) {\n const location = `${record.file}#${record.className}`;\n\n if (record.selector) {\n let selectorSet = ctx.selectorOwners.get(record.selector);\n if (!selectorSet) {\n selectorSet = new Set<string>();\n ctx.selectorOwners.set(record.selector, selectorSet);\n }\n selectorSet.add(location);\n }\n\n let classNameSet = ctx.classNameOwners.get(record.className);\n if (!classNameSet) {\n classNameSet = new Set<string>();\n ctx.classNameOwners.set(record.className, classNameSet);\n }\n classNameSet.add(location);\n }\n}\n\nexport function removeStyleOwnerMetadata(\n ctx: TemplateClassBindingGuardContext,\n file: string,\n): void {\n const previous = ctx.transformedStyleOwnerMetadata.get(file);\n if (!previous) {\n return;\n }\n\n for (const record of previous) {\n const owners = ctx.styleSourceOwners.get(record.sourcePath);\n owners?.delete(record.ownerFile);\n if (owners?.size === 0) {\n ctx.styleSourceOwners.delete(record.sourcePath);\n }\n }\n\n ctx.transformedStyleOwnerMetadata.delete(file);\n}\n\nfunction registerStyleOwnerMetadata(\n ctx: TemplateClassBindingGuardContext,\n file: string,\n styleUrls: string[],\n) {\n removeStyleOwnerMetadata(ctx, file);\n\n const records = styleUrls\n .map((urlSet) => {\n const [, absoluteFileUrl] = urlSet.split('|');\n return absoluteFileUrl\n ? {\n ownerFile: file,\n sourcePath: normalizePath(absoluteFileUrl),\n }\n : undefined;\n })\n .filter((record): record is StyleOwnerRecord => !!record);\n\n if (records.length === 0) {\n return;\n }\n\n ctx.transformedStyleOwnerMetadata.set(file, records);\n\n for (const record of records) {\n let owners = ctx.styleSourceOwners.get(record.sourcePath);\n if (!owners) {\n owners = new Set<string>();\n ctx.styleSourceOwners.set(record.sourcePath, owners);\n }\n owners.add(record.ownerFile);\n }\n}\n\nfunction isLikelyPageOnlyComponent(id: string): boolean {\n return (\n id.includes('/pages/') ||\n /\\.page\\.[cm]?[jt]sx?$/i.test(id) ||\n /\\([^/]+\\)\\.page\\.[cm]?[jt]sx?$/i.test(id)\n );\n}\n\nexport function findStaticClassAndBoundClassConflicts(\n template: string,\n): TemplateClassBindingIssue[] {\n const issues: TemplateClassBindingIssue[] = [];\n\n for (const { index, snippet } of findOpeningTagSnippets(template)) {\n if (!snippet.includes('[class]')) {\n continue;\n }\n\n const hasStaticClass = /\\sclass\\s*=\\s*(['\"])(?:(?!\\1)[\\s\\S])*\\1/.test(\n snippet,\n );\n const hasBoundClass = /\\s\\[class\\]\\s*=\\s*(['\"])(?:(?!\\1)[\\s\\S])*\\1/.test(\n snippet,\n );\n\n if (hasStaticClass && hasBoundClass) {\n const prefix = template.slice(0, index);\n const line = prefix.split('\\n').length;\n const lastNewline = prefix.lastIndexOf('\\n');\n const column = index - lastNewline;\n issues.push({\n line,\n column,\n snippet: snippet.replace(/\\s+/g, ' ').trim(),\n });\n }\n }\n\n return issues;\n}\n\nexport function findBoundClassAndNgClassConflicts(\n template: string,\n): TemplateClassBindingIssue[] {\n const issues: TemplateClassBindingIssue[] = [];\n const hasWholeElementClassBinding = /\\[class\\]\\s*=/.test(template);\n\n if (!hasWholeElementClassBinding || !template.includes('[ngClass]')) {\n return issues;\n }\n\n for (const { index, snippet } of findOpeningTagSnippets(template)) {\n if (!/\\[class\\]\\s*=/.test(snippet) || !snippet.includes('[ngClass]')) {\n continue;\n }\n\n const prefix = template.slice(0, index);\n const line = prefix.split('\\n').length;\n const lastNewline = prefix.lastIndexOf('\\n');\n const column = index - lastNewline;\n issues.push({\n line,\n column,\n snippet: snippet.replace(/\\s+/g, ' ').trim(),\n });\n }\n\n return issues;\n}\n\nfunction throwTemplateClassBindingConflict(\n id: string,\n issue: TemplateClassBindingIssue,\n): never {\n throw new Error(\n [\n '[Analog Angular] Invalid template class binding.',\n `File: ${id}:${issue.line}:${issue.column}`,\n 'The same element uses both a static `class=\"...\"` attribute and a whole-element `[class]=\"...\"` binding.',\n 'That pattern can replace or conflict with static Tailwind classes, which makes styles appear to stop applying.',\n 'Use `[ngClass]` or explicit `[class.foo]` bindings instead of `[class]` when the element also has static classes.',\n `Snippet: ${issue.snippet}`,\n ].join('\\n'),\n );\n}\n\nfunction findOpeningTagSnippets(\n template: string,\n): Array<{ index: number; snippet: string }> {\n const matches: Array<{ index: number; snippet: string }> = [];\n\n for (let index = 0; index < template.length; index++) {\n if (template[index] !== '<') {\n continue;\n }\n\n const tagStart = template[index + 1];\n if (!tagStart || !/[a-zA-Z]/.test(tagStart)) {\n continue;\n }\n\n let quote: '\"' | \"'\" | null = null;\n\n for (let end = index + 1; end < template.length; end++) {\n const char = template[end];\n\n if (quote) {\n if (char === quote) {\n quote = null;\n }\n continue;\n }\n\n if (char === '\"' || char === \"'\") {\n quote = char;\n continue;\n }\n\n if (char === '>') {\n matches.push({\n index,\n snippet: template.slice(index, end + 1),\n });\n index = end;\n break;\n }\n }\n }\n\n return matches;\n}\n\nfunction formatActiveGraphLocations(entries: Iterable<string>): string {\n return [...entries]\n .sort()\n .map((entry) => `- ${entry}`)\n .join('\\n');\n}\n"],"mappings":"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"}
@@ -1,8 +1,3 @@
1
1
  {
2
- "name": "@analogjs/vite-plugin-angular-tools",
3
- "version": "0.0.1",
4
- "main": "src/index.js",
5
- "types": "./src/index.d.ts",
6
- "module": "./src/index.js",
7
- "type": "module"
8
- }
2
+ "type": "commonjs"
3
+ }
@@ -1,41 +1,34 @@
1
- import { createBuilder, targetFromTargetString, } from '@angular-devkit/architect';
1
+ let _angular_devkit_architect = require("@angular-devkit/architect");
2
+ //#region packages/vite-plugin-angular-tools/src/builders/vite/vite-build.impl.ts
2
3
  async function viteBuilder(options, context) {
3
- const { createBuilder } = await Function('return import("vite")')();
4
- if (!context.target) {
5
- throw new Error('Builder must be executed with a target');
6
- }
7
- const projectConfig = await context.getProjectMetadata(context.target);
8
- const projectName = context.target.project;
9
- const configuration = context.target.configuration || 'production';
10
- const buildTargetSpecifier = `::${configuration}`;
11
- const buildTarget = targetFromTargetString(buildTargetSpecifier, projectName, 'build');
12
- const browserBuilderName = await context.getBuilderNameForTarget(buildTarget);
13
- const rawBuildOptions = await context.getTargetOptions(buildTarget);
14
- const buildOptions = await context.validateOptions(rawBuildOptions, browserBuilderName);
15
- const buildConfig = {
16
- configFile: options.configFile,
17
- root: projectConfig.root,
18
- mode: (process.env.NODE_ENV ??
19
- buildOptions.mode ??
20
- configuration),
21
- build: {
22
- outDir: options.outputPath,
23
- sourcemap: !!buildOptions.sourcemap,
24
- },
25
- };
26
- try {
27
- const builder = await createBuilder(buildConfig, false);
28
- await builder.buildApp();
29
- return {
30
- success: true,
31
- };
32
- }
33
- catch (e) {
34
- console.error(e);
35
- return {
36
- success: false,
37
- };
38
- }
4
+ const { createBuilder } = await Function("return import(\"vite\")")();
5
+ if (!context.target) throw new Error("Builder must be executed with a target");
6
+ const projectConfig = await context.getProjectMetadata(context.target);
7
+ const projectName = context.target.project;
8
+ const configuration = context.target.configuration || "production";
9
+ const buildTarget = (0, _angular_devkit_architect.targetFromTargetString)(`::${configuration}`, projectName, "build");
10
+ const browserBuilderName = await context.getBuilderNameForTarget(buildTarget);
11
+ const rawBuildOptions = await context.getTargetOptions(buildTarget);
12
+ const buildOptions = await context.validateOptions(rawBuildOptions, browserBuilderName);
13
+ const buildConfig = {
14
+ configFile: options.configFile,
15
+ root: projectConfig.root,
16
+ mode: process.env.NODE_ENV ?? buildOptions.mode ?? configuration,
17
+ build: {
18
+ outDir: options.outputPath,
19
+ sourcemap: !!buildOptions.sourcemap
20
+ }
21
+ };
22
+ try {
23
+ await (await createBuilder(buildConfig, false)).buildApp();
24
+ return { success: true };
25
+ } catch (e) {
26
+ console.error(e);
27
+ return { success: false };
28
+ }
39
29
  }
40
- export default createBuilder(viteBuilder);
30
+ var vite_build_impl_default = (0, _angular_devkit_architect.createBuilder)(viteBuilder);
31
+ //#endregion
32
+ module.exports = vite_build_impl_default;
33
+
41
34
  //# sourceMappingURL=vite-build.impl.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"vite-build.impl.js","sourceRoot":"","sources":["../../../../../../../../../packages/vite-plugin-angular-tools/src/builders/vite/vite-build.impl.ts"],"names":[],"mappings":"AAAA,OAAO,EAGL,aAAa,EACb,sBAAsB,GACvB,MAAM,2BAA2B,CAAC;AAInC,KAAK,UAAU,WAAW,CACxB,OAAwB,EACxB,OAAuB;IAEvB,MAAM,EAAE,aAAa,EAAE,GAAG,MAAM,QAAQ,CAAC,uBAAuB,CAAC,EAAE,CAAC;IACpE,IAAI,CAAC,OAAO,CAAC,MAAM,EAAE,CAAC;QACpB,MAAM,IAAI,KAAK,CAAC,wCAAwC,CAAC,CAAC;IAC5D,CAAC;IACD,MAAM,aAAa,GAAG,MAAM,OAAO,CAAC,kBAAkB,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC;IACvE,MAAM,WAAW,GAAG,OAAO,CAAC,MAAM,CAAC,OAAO,CAAC;IAC3C,MAAM,aAAa,GAAG,OAAO,CAAC,MAAM,CAAC,aAAa,IAAI,YAAY,CAAC;IACnE,MAAM,oBAAoB,GAAG,KAAK,aAAa,EAAE,CAAC;IAClD,MAAM,WAAW,GAAG,sBAAsB,CACxC,oBAAoB,EACpB,WAAW,EACX,OAAO,CACR,CAAC;IAEF,MAAM,kBAAkB,GAAG,MAAM,OAAO,CAAC,uBAAuB,CAAC,WAAW,CAAC,CAAC;IAC9E,MAAM,eAAe,GAAG,MAAM,OAAO,CAAC,gBAAgB,CAAC,WAAW,CAAC,CAAC;IACpE,MAAM,YAAY,GAAG,MAAM,OAAO,CAAC,eAAe,CAChD,eAAe,EACf,kBAAkB,CACnB,CAAC;IAEF,MAAM,WAAW,GAAiB;QAChC,UAAU,EAAE,OAAO,CAAC,UAAU;QAC9B,IAAI,EAAE,aAAa,CAAC,IAAc;QAClC,IAAI,EAAE,CAAC,OAAO,CAAC,GAAG,CAAC,QAAQ;YACzB,YAAY,CAAC,IAAI;YACjB,aAAa,CAAW;QAC1B,KAAK,EAAE;YACL,MAAM,EAAE,OAAO,CAAC,UAAU;YAC1B,SAAS,EAAE,CAAC,CAAC,YAAY,CAAC,SAAS;SACpC;KACF,CAAC;IAEF,IAAI,CAAC;QACH,MAAM,OAAO,GAAG,MAAM,aAAa,CAAC,WAAW,EAAE,KAAK,CAAC,CAAC;QACxD,MAAM,OAAO,CAAC,QAAQ,EAAE,CAAC;QAEzB,OAAO;YACL,OAAO,EAAE,IAAI;SACd,CAAC;IACJ,CAAC;IAAC,OAAO,CAAC,EAAE,CAAC;QACX,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;QACjB,OAAO;YACL,OAAO,EAAE,KAAK;SACf,CAAC;IACJ,CAAC;AACH,CAAC;AAED,eAAe,aAAa,CAAC,WAAW,CAAQ,CAAC"}
1
+ {"version":3,"file":"vite-build.impl.js","names":[],"sources":["../../../../../../../../vite-plugin-angular-tools/src/builders/vite/vite-build.impl.ts"],"sourcesContent":["import {\n BuilderContext,\n BuilderOutput,\n createBuilder,\n targetFromTargetString,\n} from '@angular-devkit/architect';\nimport type { InlineConfig } from 'vite';\nimport { ViteBuildSchema } from './schema';\n\nasync function viteBuilder(\n options: ViteBuildSchema,\n context: BuilderContext,\n): Promise<BuilderOutput> {\n const { createBuilder } = await Function('return import(\"vite\")')();\n if (!context.target) {\n throw new Error('Builder must be executed with a target');\n }\n const projectConfig = await context.getProjectMetadata(context.target);\n const projectName = context.target.project;\n const configuration = context.target.configuration || 'production';\n const buildTargetSpecifier = `::${configuration}`;\n const buildTarget = targetFromTargetString(\n buildTargetSpecifier,\n projectName,\n 'build',\n );\n\n const browserBuilderName = await context.getBuilderNameForTarget(buildTarget);\n const rawBuildOptions = await context.getTargetOptions(buildTarget);\n const buildOptions = await context.validateOptions(\n rawBuildOptions,\n browserBuilderName,\n );\n\n const buildConfig: InlineConfig = {\n configFile: options.configFile,\n root: projectConfig.root as string,\n mode: (process.env.NODE_ENV ??\n buildOptions.mode ??\n configuration) as string,\n build: {\n outDir: options.outputPath,\n sourcemap: !!buildOptions.sourcemap,\n },\n };\n\n try {\n const builder = await createBuilder(buildConfig, false);\n await builder.buildApp();\n\n return {\n success: true,\n };\n } catch (e) {\n console.error(e);\n return {\n success: false,\n };\n }\n}\n\nexport default createBuilder(viteBuilder) as any;\n"],"mappings":";;AASA,eAAe,YACb,SACA,SACwB;CACxB,MAAM,EAAE,kBAAkB,MAAM,SAAS,0BAAwB,EAAE;AACnE,KAAI,CAAC,QAAQ,OACX,OAAM,IAAI,MAAM,yCAAyC;CAE3D,MAAM,gBAAgB,MAAM,QAAQ,mBAAmB,QAAQ,OAAO;CACtE,MAAM,cAAc,QAAQ,OAAO;CACnC,MAAM,gBAAgB,QAAQ,OAAO,iBAAiB;CAEtD,MAAM,eAAA,GAAA,0BAAA,wBADuB,KAAK,iBAGhC,aACA,QACD;CAED,MAAM,qBAAqB,MAAM,QAAQ,wBAAwB,YAAY;CAC7E,MAAM,kBAAkB,MAAM,QAAQ,iBAAiB,YAAY;CACnE,MAAM,eAAe,MAAM,QAAQ,gBACjC,iBACA,mBACD;CAED,MAAM,cAA4B;EAChC,YAAY,QAAQ;EACpB,MAAM,cAAc;EACpB,MAAA,QAAA,IAAA,YACE,aAAa,QACb;EACF,OAAO;GACL,QAAQ,QAAQ;GAChB,WAAW,CAAC,CAAC,aAAa;GAC3B;EACF;AAED,KAAI;AAEF,SADgB,MAAM,cAAc,aAAa,MAAM,EACzC,UAAU;AAExB,SAAO,EACL,SAAS,MACV;UACM,GAAG;AACV,UAAQ,MAAM,EAAE;AAChB,SAAO,EACL,SAAS,OACV;;;AAIL,IAAA,2BAAA,GAAA,0BAAA,eAA6B,YAAY"}