@analogjs/platform 3.0.0-alpha.33 → 3.0.0-alpha.34

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@analogjs/platform",
3
- "version": "3.0.0-alpha.33",
3
+ "version": "3.0.0-alpha.34",
4
4
  "description": "The fullstack meta-framework for Angular",
5
5
  "type": "module",
6
6
  "author": "Brandon Roberts <robertsbt@gmail.com>",
@@ -45,8 +45,8 @@
45
45
  "es-toolkit": "^1.45.1",
46
46
  "tinyglobby": "^0.2.15",
47
47
  "nitro": "3.0.260311-beta",
48
- "@analogjs/vite-plugin-angular": "3.0.0-alpha.33",
49
- "@analogjs/vite-plugin-nitro": "3.0.0-alpha.33",
48
+ "@analogjs/vite-plugin-angular": "3.0.0-alpha.34",
49
+ "@analogjs/vite-plugin-nitro": "3.0.0-alpha.34",
50
50
  "rolldown": "^1.0.0-rc.13",
51
51
  "obug": "^2.1.1",
52
52
  "vitefu": "^1.1.2"
@@ -1,9 +1,9 @@
1
1
  export declare const V18_X_NX_DEVKIT = "^20.0.0";
2
2
  export declare const V18_X_NX_ANGULAR = "^20.0.0";
3
- export declare const V18_X_ANALOG_JS_CONTENT = "^3.0.0-alpha.33";
4
- export declare const V18_X_ANALOG_JS_ROUTER = "^3.0.0-alpha.33";
5
- export declare const V18_X_ANALOG_JS_VITE_PLUGIN_ANGULAR = "^3.0.0-alpha.33";
6
- export declare const V18_X_ANALOG_JS_VITEST_ANGULAR = "^3.0.0-alpha.33";
3
+ export declare const V18_X_ANALOG_JS_CONTENT = "^3.0.0-alpha.34";
4
+ export declare const V18_X_ANALOG_JS_ROUTER = "^3.0.0-alpha.34";
5
+ export declare const V18_X_ANALOG_JS_VITE_PLUGIN_ANGULAR = "^3.0.0-alpha.34";
6
+ export declare const V18_X_ANALOG_JS_VITEST_ANGULAR = "^3.0.0-alpha.34";
7
7
  export declare const V18_X_FRONT_MATTER = "^4.0.2";
8
8
  export declare const V18_X_MARKED = "^18.0.0";
9
9
  export declare const V18_X_MARKED_GFM_HEADING_ID = "^4.1.1";
@@ -15,7 +15,7 @@ export declare const V18_X_TAILWINDCSS = "^4.2.2";
15
15
  export declare const V18_X_TAILWINDCSS_POSTCSS = "^4.2.2";
16
16
  export declare const V18_X_TAILWINDCSS_VITE = "^4.2.2";
17
17
  export declare const V18_X_POSTCSS = "^8.5.6";
18
- export declare const V18_X_ANALOG_JS_PLATFORM = "^3.0.0-alpha.33";
18
+ export declare const V18_X_ANALOG_JS_PLATFORM = "^3.0.0-alpha.34";
19
19
  export declare const V18_X_ANGULAR_DEVKIT_BUILD_ANGULAR = "^19.0.0";
20
20
  export declare const V18_X_NX_VITE = "^21.0.0";
21
21
  export declare const V18_X_NX_LINTER = "^21.0.0";
@@ -1 +1 @@
1
- {"version":3,"file":"versions.js","names":[],"sources":["../../../../../../../../../../nx-plugin/src/generators/app/versions/nx_18_X/versions.ts"],"sourcesContent":["// V18_X\n// dependencies\nexport const V18_X_NX_DEVKIT = '^20.0.0';\nexport const V18_X_NX_ANGULAR = '^20.0.0';\nexport const V18_X_ANALOG_JS_CONTENT = '^3.0.0-alpha.33';\nexport const V18_X_ANALOG_JS_ROUTER = '^3.0.0-alpha.33';\nexport const V18_X_ANALOG_JS_VITE_PLUGIN_ANGULAR = '^3.0.0-alpha.33';\nexport const V18_X_ANALOG_JS_VITEST_ANGULAR = '^3.0.0-alpha.33';\nexport const V18_X_FRONT_MATTER = '^4.0.2';\nexport const V18_X_MARKED = '^18.0.0';\nexport const V18_X_MARKED_GFM_HEADING_ID = '^4.1.1';\nexport const V18_X_MARKED_HIGHLIGHT = '^2.2.1';\nexport const V18_X_MARKED_MANGLE = '^1.1.10';\nexport const V18_X_MERMAID = '^10.2.4';\nexport const V18_X_PRISMJS = '^1.29.0';\nexport const V18_X_TAILWINDCSS = '^4.2.2';\nexport const V18_X_TAILWINDCSS_POSTCSS = '^4.2.2';\nexport const V18_X_TAILWINDCSS_VITE = '^4.2.2';\nexport const V18_X_POSTCSS = '^8.5.6';\n\n// devDependencies\nexport const V18_X_ANALOG_JS_PLATFORM = '^3.0.0-alpha.33';\nexport const V18_X_ANGULAR_DEVKIT_BUILD_ANGULAR = '^19.0.0';\nexport const V18_X_NX_VITE = '^21.0.0';\nexport const V18_X_NX_LINTER = '^21.0.0';\nexport const V18_X_JSDOM = '^22.1.0';\nexport const V18_X_VITE = '^8.0.0';\nexport const V18_X_VITE_TSCONFIG_PATHS = '^4.2.0';\nexport const V18_X_VITEST = '^4.0.0';\nexport const V18_X_ZOD = '^3.21.4';\n"],"mappings":";AAeA,IAAa,oBAAoB;AACjC,IAAa,4BAA4B;AACzC,IAAa,yBAAyB;AACtC,IAAa,gBAAgB"}
1
+ {"version":3,"file":"versions.js","names":[],"sources":["../../../../../../../../../../nx-plugin/src/generators/app/versions/nx_18_X/versions.ts"],"sourcesContent":["// V18_X\n// dependencies\nexport const V18_X_NX_DEVKIT = '^20.0.0';\nexport const V18_X_NX_ANGULAR = '^20.0.0';\nexport const V18_X_ANALOG_JS_CONTENT = '^3.0.0-alpha.34';\nexport const V18_X_ANALOG_JS_ROUTER = '^3.0.0-alpha.34';\nexport const V18_X_ANALOG_JS_VITE_PLUGIN_ANGULAR = '^3.0.0-alpha.34';\nexport const V18_X_ANALOG_JS_VITEST_ANGULAR = '^3.0.0-alpha.34';\nexport const V18_X_FRONT_MATTER = '^4.0.2';\nexport const V18_X_MARKED = '^18.0.0';\nexport const V18_X_MARKED_GFM_HEADING_ID = '^4.1.1';\nexport const V18_X_MARKED_HIGHLIGHT = '^2.2.1';\nexport const V18_X_MARKED_MANGLE = '^1.1.10';\nexport const V18_X_MERMAID = '^10.2.4';\nexport const V18_X_PRISMJS = '^1.29.0';\nexport const V18_X_TAILWINDCSS = '^4.2.2';\nexport const V18_X_TAILWINDCSS_POSTCSS = '^4.2.2';\nexport const V18_X_TAILWINDCSS_VITE = '^4.2.2';\nexport const V18_X_POSTCSS = '^8.5.6';\n\n// devDependencies\nexport const V18_X_ANALOG_JS_PLATFORM = '^3.0.0-alpha.34';\nexport const V18_X_ANGULAR_DEVKIT_BUILD_ANGULAR = '^19.0.0';\nexport const V18_X_NX_VITE = '^21.0.0';\nexport const V18_X_NX_LINTER = '^21.0.0';\nexport const V18_X_JSDOM = '^22.1.0';\nexport const V18_X_VITE = '^8.0.0';\nexport const V18_X_VITE_TSCONFIG_PATHS = '^4.2.0';\nexport const V18_X_VITEST = '^4.0.0';\nexport const V18_X_ZOD = '^3.21.4';\n"],"mappings":";AAeA,IAAa,oBAAoB;AACjC,IAAa,4BAA4B;AACzC,IAAa,yBAAyB;AACtC,IAAa,gBAAgB"}
@@ -1,13 +1,13 @@
1
- export declare const V19_X_ANALOG_JS_ROUTER = "^3.0.0-alpha.33";
2
- export declare const V19_X_ANALOG_JS_CONTENT = "^3.0.0-alpha.33";
1
+ export declare const V19_X_ANALOG_JS_ROUTER = "^3.0.0-alpha.34";
2
+ export declare const V19_X_ANALOG_JS_CONTENT = "^3.0.0-alpha.34";
3
3
  export declare const V19_X_MARKED = "^18.0.0";
4
4
  export declare const V19_X_MARKED_GFM_HEADING_ID = "^4.1.1";
5
5
  export declare const V19_X_MARKED_HIGHLIGHT = "^2.2.1";
6
6
  export declare const V19_X_MARKED_MANGLE = "^1.1.10";
7
7
  export declare const V19_X_PRISMJS = "^1.29.0";
8
- export declare const V19_X_ANALOG_JS_PLATFORM = "^3.0.0-alpha.33";
9
- export declare const V19_X_ANALOG_JS_VITE_PLUGIN_ANGULAR = "^3.0.0-alpha.33";
10
- export declare const V19_X_ANALOG_JS_VITEST_ANGULAR = "^3.0.0-alpha.33";
8
+ export declare const V19_X_ANALOG_JS_PLATFORM = "^3.0.0-alpha.34";
9
+ export declare const V19_X_ANALOG_JS_VITE_PLUGIN_ANGULAR = "^3.0.0-alpha.34";
10
+ export declare const V19_X_ANALOG_JS_VITEST_ANGULAR = "^3.0.0-alpha.34";
11
11
  export declare const V19_X_NX_ANGULAR = "^22.0.0";
12
12
  export declare const V19_X_NX_VITE = "^22.0.0";
13
13
  export declare const V19_X_JSDOM = "^22.0.0";
@@ -1,14 +1,14 @@
1
1
  //#region packages/nx-plugin/src/utils/versions/ng_19_X/versions.ts
2
- var V19_X_ANALOG_JS_ROUTER = "^3.0.0-alpha.33";
3
- var V19_X_ANALOG_JS_CONTENT = "^3.0.0-alpha.33";
2
+ var V19_X_ANALOG_JS_ROUTER = "^3.0.0-alpha.34";
3
+ var V19_X_ANALOG_JS_CONTENT = "^3.0.0-alpha.34";
4
4
  var V19_X_MARKED = "^18.0.0";
5
5
  var V19_X_MARKED_GFM_HEADING_ID = "^4.1.1";
6
6
  var V19_X_MARKED_HIGHLIGHT = "^2.2.1";
7
7
  var V19_X_MARKED_MANGLE = "^1.1.10";
8
8
  var V19_X_PRISMJS = "^1.29.0";
9
- var V19_X_ANALOG_JS_PLATFORM = "^3.0.0-alpha.33";
10
- var V19_X_ANALOG_JS_VITE_PLUGIN_ANGULAR = "^3.0.0-alpha.33";
11
- var V19_X_ANALOG_JS_VITEST_ANGULAR = "^3.0.0-alpha.33";
9
+ var V19_X_ANALOG_JS_PLATFORM = "^3.0.0-alpha.34";
10
+ var V19_X_ANALOG_JS_VITE_PLUGIN_ANGULAR = "^3.0.0-alpha.34";
11
+ var V19_X_ANALOG_JS_VITEST_ANGULAR = "^3.0.0-alpha.34";
12
12
  var V19_X_NX_VITE = "^22.0.0";
13
13
  var V19_X_JSDOM = "^22.0.0";
14
14
  var V19_X_VITE_TSCONFIG_PATHS = "^4.2.0";
@@ -1 +1 @@
1
- {"version":3,"file":"versions.js","names":[],"sources":["../../../../../../../../../nx-plugin/src/utils/versions/ng_19_X/versions.ts"],"sourcesContent":["// V19_X\nexport const V19_X_ANALOG_JS_ROUTER = '^3.0.0-alpha.33';\nexport const V19_X_ANALOG_JS_CONTENT = '^3.0.0-alpha.33';\nexport const V19_X_MARKED = '^18.0.0';\nexport const V19_X_MARKED_GFM_HEADING_ID = '^4.1.1';\nexport const V19_X_MARKED_HIGHLIGHT = '^2.2.1';\nexport const V19_X_MARKED_MANGLE = '^1.1.10';\nexport const V19_X_PRISMJS = '^1.29.0';\n\n// devDependencies\nexport const V19_X_ANALOG_JS_PLATFORM = '^3.0.0-alpha.33';\nexport const V19_X_ANALOG_JS_VITE_PLUGIN_ANGULAR = '^3.0.0-alpha.33';\nexport const V19_X_ANALOG_JS_VITEST_ANGULAR = '^3.0.0-alpha.33';\nexport const V19_X_NX_ANGULAR = '^22.0.0';\nexport const V19_X_NX_VITE = '^22.0.0';\nexport const V19_X_JSDOM = '^22.0.0';\nexport const V19_X_VITE_TSCONFIG_PATHS = '^4.2.0';\nexport const V19_X_VITEST = '^3.0.0';\nexport const V19_X_VITE = '^6.0.0';\nexport const NX_X_LATEST_VITE = '^8.0.0';\nexport const NX_X_LATEST_VITEST = '^4.0.0';\n"],"mappings":";AACA,IAAa,yBAAyB;AACtC,IAAa,0BAA0B;AACvC,IAAa,eAAe;AAC5B,IAAa,8BAA8B;AAC3C,IAAa,yBAAyB;AACtC,IAAa,sBAAsB;AACnC,IAAa,gBAAgB;AAG7B,IAAa,2BAA2B;AACxC,IAAa,sCAAsC;AACnD,IAAa,iCAAiC;AAE9C,IAAa,gBAAgB;AAC7B,IAAa,cAAc;AAC3B,IAAa,4BAA4B;AACzC,IAAa,eAAe;AAC5B,IAAa,aAAa;AAC1B,IAAa,mBAAmB;AAChC,IAAa,qBAAqB"}
1
+ {"version":3,"file":"versions.js","names":[],"sources":["../../../../../../../../../nx-plugin/src/utils/versions/ng_19_X/versions.ts"],"sourcesContent":["// V19_X\nexport const V19_X_ANALOG_JS_ROUTER = '^3.0.0-alpha.34';\nexport const V19_X_ANALOG_JS_CONTENT = '^3.0.0-alpha.34';\nexport const V19_X_MARKED = '^18.0.0';\nexport const V19_X_MARKED_GFM_HEADING_ID = '^4.1.1';\nexport const V19_X_MARKED_HIGHLIGHT = '^2.2.1';\nexport const V19_X_MARKED_MANGLE = '^1.1.10';\nexport const V19_X_PRISMJS = '^1.29.0';\n\n// devDependencies\nexport const V19_X_ANALOG_JS_PLATFORM = '^3.0.0-alpha.34';\nexport const V19_X_ANALOG_JS_VITE_PLUGIN_ANGULAR = '^3.0.0-alpha.34';\nexport const V19_X_ANALOG_JS_VITEST_ANGULAR = '^3.0.0-alpha.34';\nexport const V19_X_NX_ANGULAR = '^22.0.0';\nexport const V19_X_NX_VITE = '^22.0.0';\nexport const V19_X_JSDOM = '^22.0.0';\nexport const V19_X_VITE_TSCONFIG_PATHS = '^4.2.0';\nexport const V19_X_VITEST = '^3.0.0';\nexport const V19_X_VITE = '^6.0.0';\nexport const NX_X_LATEST_VITE = '^8.0.0';\nexport const NX_X_LATEST_VITEST = '^4.0.0';\n"],"mappings":";AACA,IAAa,yBAAyB;AACtC,IAAa,0BAA0B;AACvC,IAAa,eAAe;AAC5B,IAAa,8BAA8B;AAC3C,IAAa,yBAAyB;AACtC,IAAa,sBAAsB;AACnC,IAAa,gBAAgB;AAG7B,IAAa,2BAA2B;AACxC,IAAa,sCAAsC;AACnD,IAAa,iCAAiC;AAE9C,IAAa,gBAAgB;AAC7B,IAAa,cAAc;AAC3B,IAAa,4BAA4B;AACzC,IAAa,eAAe;AAC5B,IAAa,aAAa;AAC1B,IAAa,mBAAmB;AAChC,IAAa,qBAAqB"}
@@ -2,6 +2,100 @@ import { debugTailwind } from "./utils/debug.js";
2
2
  import path from "node:path";
3
3
  import { readFileSync } from "node:fs";
4
4
  //#region packages/platform/src/lib/tailwind-preprocessor.ts
5
+ var PLATFORM_TAILWIND_PREFIX = "[@analogjs/platform]";
6
+ var CSS_REFERENCE_DIRECTIVE_REGEX = /(^|[;}\n\r])\s*@reference\b/m;
7
+ var CSS_TAILWIND_IMPORT_REGEX = /(^|[;}\n\r])\s*@import\s+["']tailwindcss["']/m;
8
+ function stripCssBlockComments(code) {
9
+ let result = "";
10
+ let quote = null;
11
+ for (let index = 0; index < code.length; index++) {
12
+ const character = code[index];
13
+ const nextCharacter = code[index + 1];
14
+ if (quote) {
15
+ if (character === "\\" && nextCharacter) {
16
+ result += character;
17
+ result += nextCharacter;
18
+ index++;
19
+ continue;
20
+ }
21
+ if (character === quote) quote = null;
22
+ result += character;
23
+ continue;
24
+ }
25
+ if (character === "\"" || character === "'" || character === "`") {
26
+ quote = character;
27
+ result += character;
28
+ continue;
29
+ }
30
+ if (character === "/" && nextCharacter === "*") {
31
+ result += " ";
32
+ index += 2;
33
+ while (index < code.length) {
34
+ const commentCharacter = code[index];
35
+ const commentNextCharacter = code[index + 1];
36
+ if (commentCharacter === "*" && commentNextCharacter === "/") {
37
+ result += " ";
38
+ index++;
39
+ break;
40
+ }
41
+ result += commentCharacter === "\n" || commentCharacter === "\r" ? commentCharacter : " ";
42
+ index++;
43
+ }
44
+ continue;
45
+ }
46
+ result += character;
47
+ }
48
+ return result;
49
+ }
50
+ function hasReferenceTextInComments(code) {
51
+ let quote = null;
52
+ for (let index = 0; index < code.length; index++) {
53
+ const character = code[index];
54
+ const nextCharacter = code[index + 1];
55
+ if (quote) {
56
+ if (character === "\\" && nextCharacter) {
57
+ index++;
58
+ continue;
59
+ }
60
+ if (character === quote) quote = null;
61
+ continue;
62
+ }
63
+ if (character === "\"" || character === "'" || character === "`") {
64
+ quote = character;
65
+ continue;
66
+ }
67
+ if (character === "/" && nextCharacter === "*") {
68
+ const commentStart = index + 2;
69
+ index += 2;
70
+ while (index < code.length) {
71
+ const commentCharacter = code[index];
72
+ const commentNextCharacter = code[index + 1];
73
+ if (commentCharacter === "*" && commentNextCharacter === "/") break;
74
+ index++;
75
+ }
76
+ if (code.slice(commentStart, index).includes("@reference")) return true;
77
+ }
78
+ }
79
+ return false;
80
+ }
81
+ function inspectCssTailwindDirectives(code) {
82
+ const commentlessCode = stripCssBlockComments(code);
83
+ return {
84
+ commentlessCode,
85
+ hasReferenceDirective: CSS_REFERENCE_DIRECTIVE_REGEX.test(commentlessCode),
86
+ hasReferenceText: hasReferenceTextInComments(code),
87
+ hasTailwindImportDirective: CSS_TAILWIND_IMPORT_REGEX.test(commentlessCode)
88
+ };
89
+ }
90
+ function toReferenceSpecifier(filename, tailwindRootCss) {
91
+ const fromDir = path.posix.dirname(filename.replace(/\\/g, "/"));
92
+ const toFile = tailwindRootCss.replace(/\\/g, "/");
93
+ const relativePath = path.posix.relative(fromDir, toFile);
94
+ return relativePath.startsWith(".") ? relativePath : `./${relativePath}`;
95
+ }
96
+ function throwTailwindReferenceTextError(filename, referenceSpecifier) {
97
+ throw new Error(`${PLATFORM_TAILWIND_PREFIX} Tailwind @reference auto-injection was blocked for "${filename}" because the stylesheet contains the text "@reference" but does not contain a real @reference directive.\n\nThis is usually caused by a CSS comment such as "/* ... @reference ... */".\n\nFix one of:\n - Reword the comment so it does not contain "@reference"\n - Add a real @reference "${referenceSpecifier}"; directive\n`);
98
+ }
5
99
  /**
6
100
  * Creates a stylesheet preprocessor that injects Tailwind v4 `@reference`
7
101
  * directives into Angular component styles when needed. The Tailwind prefix is
@@ -15,7 +109,8 @@ function tailwindPreprocessor(options) {
15
109
  mode: modeOption
16
110
  });
17
111
  return (code, filename) => {
18
- if (code.includes("@reference")) {
112
+ const directiveState = inspectCssTailwindDirectives(code);
113
+ if (directiveState.hasReferenceDirective) {
19
114
  debugTailwind("skip (already has @reference)", { filename });
20
115
  return code;
21
116
  }
@@ -25,8 +120,8 @@ function tailwindPreprocessor(options) {
25
120
  return code;
26
121
  }
27
122
  const resolvedPrefix = typeof resolvedMode === "object" ? resolvedMode.prefix : getRootPrefix();
28
- const isRootFile = path.resolve(filename) === path.resolve(tailwindRootCss) || /@import\s+["']tailwindcss["']/.test(code);
29
- const hasTailwindUsage = resolvedPrefix ? code.includes(`${resolvedPrefix}:`) : false;
123
+ const isRootFile = path.resolve(filename) === path.resolve(tailwindRootCss) || directiveState.hasTailwindImportDirective;
124
+ const hasTailwindUsage = resolvedPrefix ? directiveState.commentlessCode.includes(`${resolvedPrefix}:`) : false;
30
125
  if (!(shouldInject ? shouldInject(code, filename, resolvedPrefix) : hasTailwindUsage && !isRootFile) || !resolvedPrefix) {
31
126
  debugTailwind("skip (no injection needed)", {
32
127
  filename,
@@ -36,7 +131,8 @@ function tailwindPreprocessor(options) {
36
131
  });
37
132
  return code;
38
133
  }
39
- const refPath = path.relative(path.dirname(filename), tailwindRootCss).replace(/\\/g, "/");
134
+ const refPath = toReferenceSpecifier(filename, tailwindRootCss);
135
+ if (directiveState.hasReferenceText) throwTailwindReferenceTextError(filename, refPath);
40
136
  debugTailwind("injected @reference", {
41
137
  filename,
42
138
  refPath
@@ -1 +1 @@
1
- {"version":3,"file":"tailwind-preprocessor.js","names":[],"sources":["../../../src/lib/tailwind-preprocessor.ts"],"sourcesContent":["import { readFileSync } from 'node:fs';\nimport path from 'node:path';\n\nimport type { StylePreprocessor } from './style-preprocessor.js';\nimport { debugTailwind } from './utils/debug.js';\n\nexport type TailwindPreprocessorMode = 'auto' | 'disabled' | { prefix: string };\n\nexport interface TailwindPreprocessorOptions {\n /** Absolute path to the Tailwind root CSS file that imports `tailwindcss`. */\n tailwindRootCss: string;\n\n /**\n * Controls whether the preprocessor auto-detects, disables, or manually\n * overrides the Tailwind prefix for a given file.\n */\n mode?:\n | TailwindPreprocessorMode\n | ((filename: string) => TailwindPreprocessorMode);\n\n /**\n * Optional predicate to override the default `@reference` injection behavior.\n */\n shouldInject?: (\n code: string,\n filename: string,\n resolvedPrefix: string | null,\n ) => boolean;\n}\n\n/**\n * Creates a stylesheet preprocessor that injects Tailwind v4 `@reference`\n * directives into Angular component styles when needed. The Tailwind prefix is\n * detected from the configured root CSS file.\n */\nexport function tailwindPreprocessor(\n options: TailwindPreprocessorOptions,\n): StylePreprocessor {\n const { tailwindRootCss, mode: modeOption = 'auto', shouldInject } = options;\n let rootPrefix: string | undefined;\n\n debugTailwind('configured', { tailwindRootCss, mode: modeOption });\n\n return (code: string, filename: string): string => {\n if (code.includes('@reference')) {\n debugTailwind('skip (already has @reference)', { filename });\n return code;\n }\n\n const resolvedMode =\n typeof modeOption === 'function' ? modeOption(filename) : modeOption;\n\n if (resolvedMode === 'disabled') {\n debugTailwind('skip (mode disabled)', { filename });\n return code;\n }\n\n const resolvedPrefix =\n typeof resolvedMode === 'object' ? resolvedMode.prefix : getRootPrefix();\n const isRootFile =\n path.resolve(filename) === path.resolve(tailwindRootCss) ||\n /@import\\s+[\"']tailwindcss[\"']/.test(code);\n const hasTailwindUsage = resolvedPrefix\n ? code.includes(`${resolvedPrefix}:`)\n : false;\n const shouldAddReference = shouldInject\n ? shouldInject(code, filename, resolvedPrefix)\n : hasTailwindUsage && !isRootFile;\n\n if (!shouldAddReference || !resolvedPrefix) {\n debugTailwind('skip (no injection needed)', {\n filename,\n resolvedPrefix,\n isRootFile,\n hasTailwindUsage,\n });\n return code;\n }\n\n const refPath = path\n .relative(path.dirname(filename), tailwindRootCss)\n .replace(/\\\\/g, '/');\n debugTailwind('injected @reference', { filename, refPath });\n\n return `@reference \"${refPath}\";\\n${code}`;\n };\n\n function getRootPrefix(): string | null {\n if (rootPrefix === undefined) {\n rootPrefix = extractTailwindPrefix(\n readFileSync(tailwindRootCss, 'utf-8'),\n );\n }\n\n return rootPrefix;\n }\n}\n\nfunction extractTailwindPrefix(code: string): string | null {\n const prefixMatch = code.match(\n /@import\\s+[\"']tailwindcss[\"']\\s+prefix\\(\\s*([^)\\s;]+)\\s*\\)/i,\n );\n\n return prefixMatch?.[1]?.trim() ?? null;\n}\n"],"mappings":";;;;;;;;;AAmCA,SAAgB,qBACd,SACmB;CACnB,MAAM,EAAE,iBAAiB,MAAM,aAAa,QAAQ,iBAAiB;CACrE,IAAI;AAEJ,eAAc,cAAc;EAAE;EAAiB,MAAM;EAAY,CAAC;AAElE,SAAQ,MAAc,aAA6B;AACjD,MAAI,KAAK,SAAS,aAAa,EAAE;AAC/B,iBAAc,iCAAiC,EAAE,UAAU,CAAC;AAC5D,UAAO;;EAGT,MAAM,eACJ,OAAO,eAAe,aAAa,WAAW,SAAS,GAAG;AAE5D,MAAI,iBAAiB,YAAY;AAC/B,iBAAc,wBAAwB,EAAE,UAAU,CAAC;AACnD,UAAO;;EAGT,MAAM,iBACJ,OAAO,iBAAiB,WAAW,aAAa,SAAS,eAAe;EAC1E,MAAM,aACJ,KAAK,QAAQ,SAAS,KAAK,KAAK,QAAQ,gBAAgB,IACxD,gCAAgC,KAAK,KAAK;EAC5C,MAAM,mBAAmB,iBACrB,KAAK,SAAS,GAAG,eAAe,GAAG,GACnC;AAKJ,MAAI,EAJuB,eACvB,aAAa,MAAM,UAAU,eAAe,GAC5C,oBAAoB,CAAC,eAEE,CAAC,gBAAgB;AAC1C,iBAAc,8BAA8B;IAC1C;IACA;IACA;IACA;IACD,CAAC;AACF,UAAO;;EAGT,MAAM,UAAU,KACb,SAAS,KAAK,QAAQ,SAAS,EAAE,gBAAgB,CACjD,QAAQ,OAAO,IAAI;AACtB,gBAAc,uBAAuB;GAAE;GAAU;GAAS,CAAC;AAE3D,SAAO,eAAe,QAAQ,MAAM;;CAGtC,SAAS,gBAA+B;AACtC,MAAI,eAAe,KAAA,EACjB,cAAa,sBACX,aAAa,iBAAiB,QAAQ,CACvC;AAGH,SAAO;;;AAIX,SAAS,sBAAsB,MAA6B;AAK1D,QAJoB,KAAK,MACvB,8DACD,GAEoB,IAAI,MAAM,IAAI"}
1
+ {"version":3,"file":"tailwind-preprocessor.js","names":[],"sources":["../../../src/lib/tailwind-preprocessor.ts"],"sourcesContent":["import { readFileSync } from 'node:fs';\nimport path from 'node:path';\n\nimport type { StylePreprocessor } from './style-preprocessor.js';\nimport { debugTailwind } from './utils/debug.js';\n\nexport type TailwindPreprocessorMode = 'auto' | 'disabled' | { prefix: string };\nconst PLATFORM_TAILWIND_PREFIX = '[@analogjs/platform]';\nconst CSS_REFERENCE_DIRECTIVE_REGEX = /(^|[;}\\n\\r])\\s*@reference\\b/m;\nconst CSS_TAILWIND_IMPORT_REGEX =\n /(^|[;}\\n\\r])\\s*@import\\s+[\"']tailwindcss[\"']/m;\n\ninterface CssTailwindDirectiveState {\n commentlessCode: string;\n hasReferenceDirective: boolean;\n hasReferenceText: boolean;\n hasTailwindImportDirective: boolean;\n}\n\n// Mask real block comments while preserving quoted CSS content. This keeps\n// prose like `/* add @reference here */` from disabling injection without\n// mistaking `/* ... */` sequences inside strings for real comments.\nfunction stripCssBlockComments(code: string): string {\n let result = '';\n let quote: '\"' | \"'\" | '`' | null = null;\n\n for (let index = 0; index < code.length; index++) {\n const character = code[index];\n const nextCharacter = code[index + 1];\n\n if (quote) {\n if (character === '\\\\' && nextCharacter) {\n result += character;\n result += nextCharacter;\n index++;\n continue;\n }\n if (character === quote) {\n quote = null;\n }\n result += character;\n continue;\n }\n\n if (character === '\"' || character === \"'\" || character === '`') {\n quote = character;\n result += character;\n continue;\n }\n\n if (character === '/' && nextCharacter === '*') {\n result += ' ';\n index += 2;\n\n while (index < code.length) {\n const commentCharacter = code[index];\n const commentNextCharacter = code[index + 1];\n\n if (commentCharacter === '*' && commentNextCharacter === '/') {\n result += ' ';\n index++;\n break;\n }\n\n result +=\n commentCharacter === '\\n' || commentCharacter === '\\r'\n ? commentCharacter\n : ' ';\n index++;\n }\n continue;\n }\n\n result += character;\n }\n\n return result;\n}\n\nfunction hasReferenceTextInComments(code: string): boolean {\n let quote: '\"' | \"'\" | '`' | null = null;\n\n for (let index = 0; index < code.length; index++) {\n const character = code[index];\n const nextCharacter = code[index + 1];\n\n if (quote) {\n if (character === '\\\\' && nextCharacter) {\n index++;\n continue;\n }\n if (character === quote) {\n quote = null;\n }\n continue;\n }\n\n if (character === '\"' || character === \"'\" || character === '`') {\n quote = character;\n continue;\n }\n\n if (character === '/' && nextCharacter === '*') {\n const commentStart = index + 2;\n index += 2;\n\n while (index < code.length) {\n const commentCharacter = code[index];\n const commentNextCharacter = code[index + 1];\n\n if (commentCharacter === '*' && commentNextCharacter === '/') {\n break;\n }\n index++;\n }\n\n if (code.slice(commentStart, index).includes('@reference')) {\n return true;\n }\n }\n }\n\n return false;\n}\n\nfunction inspectCssTailwindDirectives(code: string): CssTailwindDirectiveState {\n const commentlessCode = stripCssBlockComments(code);\n\n return {\n commentlessCode,\n hasReferenceDirective: CSS_REFERENCE_DIRECTIVE_REGEX.test(commentlessCode),\n hasReferenceText: hasReferenceTextInComments(code),\n hasTailwindImportDirective: CSS_TAILWIND_IMPORT_REGEX.test(commentlessCode),\n };\n}\n\nfunction toReferenceSpecifier(\n filename: string,\n tailwindRootCss: string,\n): string {\n const fromDir = path.posix.dirname(filename.replace(/\\\\/g, '/'));\n const toFile = tailwindRootCss.replace(/\\\\/g, '/');\n const relativePath = path.posix.relative(fromDir, toFile);\n\n return relativePath.startsWith('.') ? relativePath : `./${relativePath}`;\n}\n\nfunction throwTailwindReferenceTextError(\n filename: string,\n referenceSpecifier: string,\n): never {\n throw new Error(\n `${PLATFORM_TAILWIND_PREFIX} Tailwind @reference auto-injection was ` +\n `blocked for \"${filename}\" because the stylesheet contains the ` +\n `text \"@reference\" but does not contain a real @reference ` +\n `directive.\\n\\n` +\n `This is usually caused by a CSS comment such as ` +\n `\"/* ... @reference ... */\".\\n\\n` +\n `Fix one of:\\n` +\n ` - Reword the comment so it does not contain \"@reference\"\\n` +\n ` - Add a real @reference \"${referenceSpecifier}\"; directive\\n`,\n );\n}\n\nexport interface TailwindPreprocessorOptions {\n /** Absolute path to the Tailwind root CSS file that imports `tailwindcss`. */\n tailwindRootCss: string;\n\n /**\n * Controls whether the preprocessor auto-detects, disables, or manually\n * overrides the Tailwind prefix for a given file.\n */\n mode?:\n | TailwindPreprocessorMode\n | ((filename: string) => TailwindPreprocessorMode);\n\n /**\n * Optional predicate to override the default `@reference` injection behavior.\n */\n shouldInject?: (\n code: string,\n filename: string,\n resolvedPrefix: string | null,\n ) => boolean;\n}\n\n/**\n * Creates a stylesheet preprocessor that injects Tailwind v4 `@reference`\n * directives into Angular component styles when needed. The Tailwind prefix is\n * detected from the configured root CSS file.\n */\nexport function tailwindPreprocessor(\n options: TailwindPreprocessorOptions,\n): StylePreprocessor {\n const { tailwindRootCss, mode: modeOption = 'auto', shouldInject } = options;\n let rootPrefix: string | undefined;\n\n debugTailwind('configured', { tailwindRootCss, mode: modeOption });\n\n return (code: string, filename: string): string => {\n const directiveState = inspectCssTailwindDirectives(code);\n\n if (directiveState.hasReferenceDirective) {\n debugTailwind('skip (already has @reference)', { filename });\n return code;\n }\n\n const resolvedMode =\n typeof modeOption === 'function' ? modeOption(filename) : modeOption;\n\n if (resolvedMode === 'disabled') {\n debugTailwind('skip (mode disabled)', { filename });\n return code;\n }\n\n const resolvedPrefix =\n typeof resolvedMode === 'object' ? resolvedMode.prefix : getRootPrefix();\n const isRootFile =\n path.resolve(filename) === path.resolve(tailwindRootCss) ||\n directiveState.hasTailwindImportDirective;\n const hasTailwindUsage = resolvedPrefix\n ? directiveState.commentlessCode.includes(`${resolvedPrefix}:`)\n : false;\n const shouldAddReference = shouldInject\n ? shouldInject(code, filename, resolvedPrefix)\n : hasTailwindUsage && !isRootFile;\n\n if (!shouldAddReference || !resolvedPrefix) {\n debugTailwind('skip (no injection needed)', {\n filename,\n resolvedPrefix,\n isRootFile,\n hasTailwindUsage,\n });\n return code;\n }\n\n const refPath = toReferenceSpecifier(filename, tailwindRootCss);\n if (directiveState.hasReferenceText) {\n throwTailwindReferenceTextError(filename, refPath);\n }\n\n debugTailwind('injected @reference', { filename, refPath });\n\n return `@reference \"${refPath}\";\\n${code}`;\n };\n\n function getRootPrefix(): string | null {\n if (rootPrefix === undefined) {\n rootPrefix = extractTailwindPrefix(\n readFileSync(tailwindRootCss, 'utf-8'),\n );\n }\n\n return rootPrefix;\n }\n}\n\nfunction extractTailwindPrefix(code: string): string | null {\n const prefixMatch = code.match(\n /@import\\s+[\"']tailwindcss[\"']\\s+prefix\\(\\s*([^)\\s;]+)\\s*\\)/i,\n );\n\n return prefixMatch?.[1]?.trim() ?? null;\n}\n"],"mappings":"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"}