angular-rust-plugins 0.5.0 → 0.7.0

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/README.md CHANGED
@@ -309,6 +309,28 @@ The compiler now achieves full feature parity with the standard Angular compiler
309
309
  | HMR update | ~50ms | ~200ms |
310
310
  | Memory usage | ~100MB | ~500MB |
311
311
 
312
+ ## 🌍 Platform & Framework Support
313
+
314
+ ### Angular Compatibility
315
+
316
+ Fully compatible with **Angular 16.0.0+**. Older versions (View Engine) are not supported.
317
+
318
+ ### Bundler Compatibility
319
+
320
+ | Bundler | Status | Notes |
321
+ |---------|--------|-------|
322
+ | **Vite** | ✅ Stable | Recommended for development |
323
+ | **Rolldown** | 🚀 Beta | Extremely fast, future default |
324
+ | **Esbuild** | ✅ Stable | Solid for production builds |
325
+ | **Webpack** | ⏳ Planned | Coming in v1.0 |
326
+
327
+ ### Operating Systems
328
+
329
+ Pre-compiled binaries are provided for:
330
+ - **macOS**: x64, arm64
331
+ - **Windows**: x64, arm64
332
+ - **Linux**: x64, arm64 (glibc & musl/Alpine)
333
+
312
334
  ## 🔧 Development
313
335
 
314
336
  ```bash
@@ -3,22 +3,19 @@
3
3
 
4
4
  /* auto-generated by NAPI-RS */
5
5
 
6
- export declare function linkFile(sourceCode: string, filename: string): string
7
6
  export interface Diagnostic {
8
- file?: string
9
- message: string
10
- code: number
11
- start?: number
12
- length?: number
7
+ file?: string;
8
+ message: string;
9
+ code: number;
10
+ start?: number;
11
+ length?: number;
13
12
  }
14
13
  export interface CompileResult {
15
- code: string
16
- diagnostics: Array<Diagnostic>
14
+ code: string;
15
+ diagnostics: Array<Diagnostic>;
17
16
  }
18
17
  export declare class Compiler {
19
- constructor()
20
- compile(filename: string, content: string): string
21
- constructor()
22
- compile(filename: string, content: string): CompileResult
23
- linkFile(filename: string, sourceCode: string): string
18
+ constructor();
19
+ compile(filename: string, content: string): CompileResult;
20
+ linkFile(filename: string, sourceCode: string): string;
24
21
  }
@@ -30,6 +30,49 @@ var import_path = require("path");
30
30
  var import_url = require("url");
31
31
  var import_meta = {};
32
32
  var compilerInstance = null;
33
+ var RED = "\x1B[31m";
34
+ var YELLOW = "\x1B[33m";
35
+ var CYAN = "\x1B[36m";
36
+ var BOLD = "\x1B[1m";
37
+ var RESET = "\x1B[0m";
38
+ function formatDiagnostic(diag, sourceCode) {
39
+ const level = "WARNING";
40
+ const codeStr = `NG${diag.code}`;
41
+ const file = diag.file || "unknown";
42
+ let line = 1;
43
+ let col = 0;
44
+ let lineStartPos = 0;
45
+ if (diag.start !== void 0 && diag.start !== null) {
46
+ for (let i = 0; i < diag.start && i < sourceCode.length; i++) {
47
+ if (sourceCode[i] === "\n") {
48
+ line++;
49
+ col = 0;
50
+ lineStartPos = i + 1;
51
+ } else {
52
+ col++;
53
+ }
54
+ }
55
+ }
56
+ let output = `
57
+ ${BOLD}${YELLOW}\u25B2 [${level}] ${RED}${codeStr}${RESET}${BOLD}: ${diag.message}${RESET} ${YELLOW}[plugin rust-ngc-plugin]${RESET}
58
+ `;
59
+ const lineStr = line.toString();
60
+ const colStr = (col + 1).toString();
61
+ output += `
62
+ ${CYAN}${file}:${lineStr}:${colStr}:${RESET}
63
+ `;
64
+ let lineEndPos = sourceCode.indexOf("\n", lineStartPos);
65
+ if (lineEndPos === -1) lineEndPos = sourceCode.length;
66
+ const lineContent = sourceCode.substring(lineStartPos, lineEndPos);
67
+ output += ` ${BOLD}${lineStr} \u2502 ${RESET}${lineContent}
68
+ `;
69
+ const gutterWidth = lineStr.length + 3;
70
+ const gutterEmpty = " ".repeat(gutterWidth);
71
+ const length = diag.length || 1;
72
+ const underline = "~".repeat(length);
73
+ output += ` ${gutterEmpty}${" ".repeat(col)}${RED}${underline}${RESET}`;
74
+ return output;
75
+ }
33
76
  function getCompiler(options) {
34
77
  if (compilerInstance) {
35
78
  return compilerInstance;
@@ -84,9 +127,26 @@ function angularCompilerVitePlugin(options) {
84
127
  compiler = getCompiler(options);
85
128
  }
86
129
  if (id.includes("node_modules")) {
130
+ if (id.includes("@angular") && code.includes("\u0275\u0275ngDeclare")) {
131
+ const cleanId2 = id.split("?")[0];
132
+ if (cleanId2.endsWith(".mjs") || cleanId2.endsWith(".js")) {
133
+ try {
134
+ const result = compiler.linkFile(id, code);
135
+ if (result.startsWith("/* Linker Error")) {
136
+ if (debug) console.error(`[Linker Error] ${id}: ${result}`);
137
+ return null;
138
+ }
139
+ return { code: result, map: null };
140
+ } catch (e) {
141
+ if (debug) console.error(`Linker failed for ${id}:`, e);
142
+ return null;
143
+ }
144
+ }
145
+ }
87
146
  return null;
88
147
  }
89
- if (!id.endsWith(".ts") || id.endsWith(".d.ts")) {
148
+ const cleanId = id.split("?")[0];
149
+ if (!cleanId.endsWith(".ts") || cleanId.endsWith(".d.ts")) {
90
150
  return null;
91
151
  }
92
152
  if (debug) {
@@ -94,15 +154,21 @@ function angularCompilerVitePlugin(options) {
94
154
  }
95
155
  try {
96
156
  const result = compiler.compile(id, code);
97
- if (result.startsWith("/* Error")) {
157
+ const { code: compiledCode, diagnostics } = result;
158
+ if (compiledCode.startsWith("/* Error")) {
98
159
  console.error(`[Angular Compiler Error] ${id}:
99
- ${result}`);
160
+ ${compiledCode}`);
100
161
  throw new Error(`Rust Compilation Failed for ${id}`);
101
162
  }
163
+ if (diagnostics && diagnostics.length > 0) {
164
+ diagnostics.forEach((diag) => {
165
+ console.warn(formatDiagnostic(diag, code));
166
+ });
167
+ }
102
168
  if (debug) {
103
169
  console.log(`[Angular Compiler] Successfully compiled: ${id}`);
104
170
  }
105
- return { code: result, map: null };
171
+ return { code: compiledCode, map: null };
106
172
  } catch (e) {
107
173
  console.error(`[Angular Compiler Failed] ${id}:`, e);
108
174
  throw e;
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/compiler/index.ts","../../src/compiler/vite.ts"],"sourcesContent":["/**\n * Angular Compiler Plugins - Index\n *\n * Re-exports all compiler plugins for different bundlers.\n */\n\nexport { angularCompilerVitePlugin } from \"./vite\";\nexport type { CompilerOptions } from \"./vite\";\nexport type { CompilerBinding } from \"./types\";\n","/**\n * Angular Compiler Plugin for Vite\n *\n * This plugin compiles Angular TypeScript files using the Rust-based Angular compiler.\n * Use with the linker plugin for a complete Angular build solution.\n *\n * @example\n * ```js\n * import { angularCompilerVitePlugin } from 'angular-rust-plugins/compiler/vite';\n * import { angularLinkerVitePlugin } from 'angular-rust-plugins/linker/vite';\n * import { defineConfig } from 'vite';\n *\n * export default defineConfig({\n * plugins: [\n * angularLinkerVitePlugin(),\n * angularCompilerVitePlugin(),\n * ],\n * });\n * ```\n */\n\nimport type { Plugin, HmrContext } from \"vite\";\nimport { createRequire } from \"module\";\nimport { dirname, join } from \"path\";\nimport { fileURLToPath } from \"url\";\nimport type { CompilerBinding } from \"./types\";\n\nlet compilerInstance: CompilerBinding | null = null;\n\nexport interface CompilerOptions {\n /**\n * Enable debug logging\n * @default false\n */\n debug?: boolean;\n\n /**\n * Custom path to the Angular Rust binding package\n */\n bindingPath?: string;\n}\n\nfunction getCompiler(options?: CompilerOptions): CompilerBinding {\n if (compilerInstance) {\n return compilerInstance;\n }\n\n try {\n let binding: { Compiler: new () => CompilerBinding };\n\n if (options?.bindingPath) {\n const require = createRequire(import.meta.url);\n binding = require(options.bindingPath);\n } else {\n // Load from bundled binding directory\n // Use import.meta.url to get the actual location of this file\n const currentFileUrl = import.meta.url;\n const currentFilePath = fileURLToPath(currentFileUrl);\n const currentDir = dirname(currentFilePath);\n const require = createRequire(currentFileUrl);\n\n // Try multiple possible binding locations\n const possiblePaths = [\n join(currentDir, \"..\", \"binding\"), // dist/compiler/../binding\n join(currentDir, \"..\", \"..\", \"binding\"), // in case of deeper nesting\n join(currentDir, \"binding\"), // same directory\n ];\n\n let loadedBinding: { Compiler: new () => CompilerBinding } | null = null;\n let lastError: unknown = null;\n\n for (const bindingPath of possiblePaths) {\n try {\n loadedBinding = require(bindingPath);\n break;\n } catch (e) {\n lastError = e;\n }\n }\n\n if (!loadedBinding) {\n throw (\n lastError ||\n new Error(\"Could not find binding in any expected location\")\n );\n }\n\n binding = loadedBinding;\n }\n\n compilerInstance = new binding.Compiler();\n return compilerInstance;\n } catch (e) {\n throw new Error(`Failed to load Angular Rust binding. Error: ${e}`);\n }\n}\n\n/**\n * Creates a Vite plugin for Angular Rust compiler\n * Compiles .ts files (except .d.ts) using the Rust compiler\n */\nexport function angularCompilerVitePlugin(options?: CompilerOptions): Plugin {\n const debug = options?.debug ?? false;\n let compiler: CompilerBinding;\n\n return {\n name: \"angular-rust-compiler\",\n enforce: \"pre\",\n\n transform(code: string, id: string) {\n // Lazy initialize compiler\n if (!compiler) {\n compiler = getCompiler(options);\n }\n\n // Skip node_modules - those are handled by linker, not compiler\n if (id.includes(\"node_modules\")) {\n return null;\n }\n\n // Only process TypeScript files, skip declaration files\n if (!id.endsWith(\".ts\") || id.endsWith(\".d.ts\")) {\n return null;\n }\n\n if (debug) {\n console.log(`[Angular Compiler] Compiling: ${id}`);\n }\n\n try {\n const result = compiler.compile(id, code);\n\n if (result.startsWith(\"/* Error\")) {\n console.error(`[Angular Compiler Error] ${id}:\\n${result}`);\n throw new Error(`Rust Compilation Failed for ${id}`);\n }\n\n if (debug) {\n console.log(`[Angular Compiler] Successfully compiled: ${id}`);\n }\n\n return { code: result, map: null };\n } catch (e) {\n console.error(`[Angular Compiler Failed] ${id}:`, e);\n throw e;\n }\n },\n\n handleHotUpdate({ file, server }: HmrContext) {\n // When HTML template changes, invalidate the corresponding TS file\n if (file.endsWith(\".html\")) {\n const tsFile = file.replace(/\\.html$/, \".ts\");\n\n if (debug) {\n console.log(`[HMR] HTML changed: ${file}`);\n console.log(`[HMR] Invalidating TS: ${tsFile}`);\n }\n\n const mod = server.moduleGraph.getModuleById(tsFile);\n if (mod) {\n server.moduleGraph.invalidateModule(mod);\n server.ws.send({ type: \"full-reload\", path: \"*\" });\n return [];\n } else {\n server.ws.send({ type: \"full-reload\", path: \"*\" });\n return [];\n }\n }\n },\n };\n}\n\nexport default angularCompilerVitePlugin;\n"],"mappings":";;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;;;ACsBA,oBAA8B;AAC9B,kBAA8B;AAC9B,iBAA8B;AAxB9B;AA2BA,IAAI,mBAA2C;AAe/C,SAAS,YAAY,SAA4C;AAC/D,MAAI,kBAAkB;AACpB,WAAO;AAAA,EACT;AAEA,MAAI;AACF,QAAI;AAEJ,QAAI,SAAS,aAAa;AACxB,YAAMA,eAAU,6BAAc,YAAY,GAAG;AAC7C,gBAAUA,SAAQ,QAAQ,WAAW;AAAA,IACvC,OAAO;AAGL,YAAM,iBAAiB,YAAY;AACnC,YAAM,sBAAkB,0BAAc,cAAc;AACpD,YAAM,iBAAa,qBAAQ,eAAe;AAC1C,YAAMA,eAAU,6BAAc,cAAc;AAG5C,YAAM,gBAAgB;AAAA,YACpB,kBAAK,YAAY,MAAM,SAAS;AAAA;AAAA,YAChC,kBAAK,YAAY,MAAM,MAAM,SAAS;AAAA;AAAA,YACtC,kBAAK,YAAY,SAAS;AAAA;AAAA,MAC5B;AAEA,UAAI,gBAAgE;AACpE,UAAI,YAAqB;AAEzB,iBAAW,eAAe,eAAe;AACvC,YAAI;AACF,0BAAgBA,SAAQ,WAAW;AACnC;AAAA,QACF,SAAS,GAAG;AACV,sBAAY;AAAA,QACd;AAAA,MACF;AAEA,UAAI,CAAC,eAAe;AAClB,cACE,aACA,IAAI,MAAM,iDAAiD;AAAA,MAE/D;AAEA,gBAAU;AAAA,IACZ;AAEA,uBAAmB,IAAI,QAAQ,SAAS;AACxC,WAAO;AAAA,EACT,SAAS,GAAG;AACV,UAAM,IAAI,MAAM,+CAA+C,CAAC,EAAE;AAAA,EACpE;AACF;AAMO,SAAS,0BAA0B,SAAmC;AAC3E,QAAM,QAAQ,SAAS,SAAS;AAChC,MAAI;AAEJ,SAAO;AAAA,IACL,MAAM;AAAA,IACN,SAAS;AAAA,IAET,UAAU,MAAc,IAAY;AAElC,UAAI,CAAC,UAAU;AACb,mBAAW,YAAY,OAAO;AAAA,MAChC;AAGA,UAAI,GAAG,SAAS,cAAc,GAAG;AAC/B,eAAO;AAAA,MACT;AAGA,UAAI,CAAC,GAAG,SAAS,KAAK,KAAK,GAAG,SAAS,OAAO,GAAG;AAC/C,eAAO;AAAA,MACT;AAEA,UAAI,OAAO;AACT,gBAAQ,IAAI,iCAAiC,EAAE,EAAE;AAAA,MACnD;AAEA,UAAI;AACF,cAAM,SAAS,SAAS,QAAQ,IAAI,IAAI;AAExC,YAAI,OAAO,WAAW,UAAU,GAAG;AACjC,kBAAQ,MAAM,4BAA4B,EAAE;AAAA,EAAM,MAAM,EAAE;AAC1D,gBAAM,IAAI,MAAM,+BAA+B,EAAE,EAAE;AAAA,QACrD;AAEA,YAAI,OAAO;AACT,kBAAQ,IAAI,6CAA6C,EAAE,EAAE;AAAA,QAC/D;AAEA,eAAO,EAAE,MAAM,QAAQ,KAAK,KAAK;AAAA,MACnC,SAAS,GAAG;AACV,gBAAQ,MAAM,6BAA6B,EAAE,KAAK,CAAC;AACnD,cAAM;AAAA,MACR;AAAA,IACF;AAAA,IAEA,gBAAgB,EAAE,MAAM,OAAO,GAAe;AAE5C,UAAI,KAAK,SAAS,OAAO,GAAG;AAC1B,cAAM,SAAS,KAAK,QAAQ,WAAW,KAAK;AAE5C,YAAI,OAAO;AACT,kBAAQ,IAAI,uBAAuB,IAAI,EAAE;AACzC,kBAAQ,IAAI,0BAA0B,MAAM,EAAE;AAAA,QAChD;AAEA,cAAM,MAAM,OAAO,YAAY,cAAc,MAAM;AACnD,YAAI,KAAK;AACP,iBAAO,YAAY,iBAAiB,GAAG;AACvC,iBAAO,GAAG,KAAK,EAAE,MAAM,eAAe,MAAM,IAAI,CAAC;AACjD,iBAAO,CAAC;AAAA,QACV,OAAO;AACL,iBAAO,GAAG,KAAK,EAAE,MAAM,eAAe,MAAM,IAAI,CAAC;AACjD,iBAAO,CAAC;AAAA,QACV;AAAA,MACF;AAAA,IACF;AAAA,EACF;AACF;","names":["require"]}
1
+ {"version":3,"sources":["../../src/compiler/index.ts","../../src/compiler/vite.ts"],"sourcesContent":["/**\n * Angular Compiler Plugins - Index\n *\n * Re-exports all compiler plugins for different bundlers.\n */\n\nexport { angularCompilerVitePlugin } from \"./vite\";\nexport type { CompilerOptions } from \"./vite\";\n","/**\n * Angular Compiler Plugin for Vite\n *\n * This plugin compiles Angular TypeScript files using the Rust-based Angular compiler.\n * Use with the linker plugin for a complete Angular build solution.\n *\n * @example\n * ```js\n * import { angularCompilerVitePlugin } from 'angular-rust-plugins/compiler/vite';\n * import { angularLinkerVitePlugin } from 'angular-rust-plugins/linker/vite';\n * import { defineConfig } from 'vite';\n *\n * export default defineConfig({\n * plugins: [\n * angularLinkerVitePlugin(),\n * angularCompilerVitePlugin(),\n * ],\n * });\n * ```\n */\n\nimport type { Plugin, HmrContext } from \"vite\";\nimport { createRequire } from \"module\";\nimport { dirname, join } from \"path\";\nimport { fileURLToPath } from \"url\";\nimport { Compiler } from \"../binding\";\n\nlet compilerInstance: Compiler | null = null;\n\nexport interface CompilerOptions {\n /**\n * Enable debug logging\n * @default false\n */\n debug?: boolean;\n\n /**\n * Custom path to the Angular Rust binding package\n */\n bindingPath?: string;\n}\n\n// ============ Diagnostic Formatting ============\nconst RED = '\\x1b[31m';\nconst YELLOW = '\\x1b[33m';\nconst CYAN = '\\x1b[36m';\nconst BOLD = '\\x1b[1m';\nconst RESET = '\\x1b[0m';\n\nfunction formatDiagnostic(diag: any, sourceCode: string): string {\n const level = 'WARNING';\n const codeStr = `NG${diag.code}`;\n const file = diag.file || 'unknown';\n\n let line = 1;\n let col = 0;\n let lineStartPos = 0;\n\n if (diag.start !== undefined && diag.start !== null) {\n for (let i = 0; i < diag.start && i < sourceCode.length; i++) {\n if (sourceCode[i] === '\\n') {\n line++;\n col = 0;\n lineStartPos = i + 1;\n } else {\n col++;\n }\n }\n }\n\n let output = `\\n${BOLD}${YELLOW}▲ [${level}] ${RED}${codeStr}${RESET}${BOLD}: ${diag.message}${RESET} ${YELLOW}[plugin rust-ngc-plugin]${RESET}\\n`;\n\n const lineStr = line.toString();\n const colStr = (col + 1).toString();\n output += `\\n ${CYAN}${file}:${lineStr}:${colStr}:${RESET}\\n`;\n\n let lineEndPos = sourceCode.indexOf('\\n', lineStartPos);\n if (lineEndPos === -1) lineEndPos = sourceCode.length;\n const lineContent = sourceCode.substring(lineStartPos, lineEndPos);\n\n output += ` ${BOLD}${lineStr} │ ${RESET}${lineContent}\\n`;\n\n const gutterWidth = lineStr.length + 3;\n const gutterEmpty = ' '.repeat(gutterWidth);\n const length = diag.length || 1;\n const underline = '~'.repeat(length);\n\n output += ` ${gutterEmpty}${' '.repeat(col)}${RED}${underline}${RESET}`;\n\n return output;\n}\n\nfunction getCompiler(options?: CompilerOptions): Compiler {\n if (compilerInstance) {\n return compilerInstance;\n }\n\n try {\n let binding: { Compiler: new () => Compiler };\n\n if (options?.bindingPath) {\n const require = createRequire(import.meta.url);\n binding = require(options.bindingPath);\n } else {\n // Load from bundled binding directory\n // Use import.meta.url to get the actual location of this file\n const currentFileUrl = import.meta.url;\n const currentFilePath = fileURLToPath(currentFileUrl);\n const currentDir = dirname(currentFilePath);\n const require = createRequire(currentFileUrl);\n\n // Try multiple possible binding locations\n const possiblePaths = [\n join(currentDir, \"..\", \"binding\"), // dist/compiler/../binding\n join(currentDir, \"..\", \"..\", \"binding\"), // in case of deeper nesting\n join(currentDir, \"binding\"), // same directory\n ];\n\n let loadedBinding: { Compiler: new () => Compiler } | null = null;\n let lastError: unknown = null;\n\n for (const bindingPath of possiblePaths) {\n try {\n loadedBinding = require(bindingPath);\n break;\n } catch (e) {\n lastError = e;\n }\n }\n\n if (!loadedBinding) {\n throw (\n lastError ||\n new Error(\"Could not find binding in any expected location\")\n );\n }\n\n binding = loadedBinding;\n }\n\n compilerInstance = new binding.Compiler();\n return compilerInstance;\n } catch (e) {\n throw new Error(`Failed to load Angular Rust binding. Error: ${e}`);\n }\n}\n\n/**\n * Creates a Vite plugin for Angular Rust compiler\n * Compiles .ts files (except .d.ts) using the Rust compiler\n */\nexport function angularCompilerVitePlugin(options?: CompilerOptions): Plugin {\n const debug = options?.debug ?? false;\n let compiler: Compiler;\n\n return {\n name: \"angular-rust-compiler\",\n enforce: \"pre\",\n\n transform(code: string, id: string) {\n // Lazy initialize compiler\n if (!compiler) {\n compiler = getCompiler(options);\n }\n\n // Skip node_modules but check for Angular packages that need linking\n if (id.includes('node_modules')) {\n if (id.includes('@angular') && code.includes('ɵɵngDeclare')) {\n const cleanId = id.split('?')[0];\n if (cleanId.endsWith('.mjs') || cleanId.endsWith('.js')) {\n try {\n const result = compiler.linkFile(id, code);\n if (result.startsWith('/* Linker Error')) {\n if (debug) console.error(`[Linker Error] ${id}: ${result}`);\n return null;\n }\n return { code: result, map: null };\n } catch (e) {\n if (debug) console.error(`Linker failed for ${id}:`, e);\n return null;\n }\n }\n }\n return null;\n }\n\n // Only process TypeScript files, skip declaration files\n const cleanId = id.split('?')[0];\n if (!cleanId.endsWith('.ts') || cleanId.endsWith('.d.ts')) {\n return null;\n }\n\n if (debug) {\n console.log(`[Angular Compiler] Compiling: ${id}`);\n }\n\n try {\n const result = compiler.compile(id, code);\n\n // Handle structured result\n const { code: compiledCode, diagnostics } = result;\n\n if (compiledCode.startsWith('/* Error')) {\n console.error(`[Angular Compiler Error] ${id}:\\n${compiledCode}`);\n throw new Error(`Rust Compilation Failed for ${id}`);\n }\n\n if (diagnostics && diagnostics.length > 0) {\n diagnostics.forEach((diag: any) => {\n console.warn(formatDiagnostic(diag, code));\n });\n }\n\n if (debug) {\n console.log(`[Angular Compiler] Successfully compiled: ${id}`);\n }\n\n return { code: compiledCode, map: null };\n } catch (e) {\n console.error(`[Angular Compiler Failed] ${id}:`, e);\n throw e;\n }\n },\n\n handleHotUpdate({ file, server }: HmrContext) {\n // When HTML template changes, invalidate the corresponding TS file\n if (file.endsWith(\".html\")) {\n const tsFile = file.replace(/\\.html$/, \".ts\");\n\n if (debug) {\n console.log(`[HMR] HTML changed: ${file}`);\n console.log(`[HMR] Invalidating TS: ${tsFile}`);\n }\n\n const mod = server.moduleGraph.getModuleById(tsFile);\n if (mod) {\n server.moduleGraph.invalidateModule(mod);\n server.ws.send({ type: \"full-reload\", path: \"*\" });\n return [];\n } else {\n server.ws.send({ type: \"full-reload\", path: \"*\" });\n return [];\n }\n }\n },\n };\n}\n\nexport default angularCompilerVitePlugin;\n"],"mappings":"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","names":["require","cleanId"]}
@@ -1,12 +1,2 @@
1
1
  export { CompilerOptions, default as angularCompilerVitePlugin } from './vite.cjs';
2
2
  import 'vite';
3
-
4
- /**
5
- * Compiler Types
6
- */
7
- interface CompilerBinding {
8
- compile(filePath: string, code: string): string;
9
- linkFile(filePath: string, code: string): string;
10
- }
11
-
12
- export type { CompilerBinding };
@@ -1,12 +1,2 @@
1
1
  export { CompilerOptions, default as angularCompilerVitePlugin } from './vite.js';
2
2
  import 'vite';
3
-
4
- /**
5
- * Compiler Types
6
- */
7
- interface CompilerBinding {
8
- compile(filePath: string, code: string): string;
9
- linkFile(filePath: string, code: string): string;
10
- }
11
-
12
- export type { CompilerBinding };
package/compiler/index.js CHANGED
@@ -3,6 +3,49 @@ import { createRequire } from "module";
3
3
  import { dirname, join } from "path";
4
4
  import { fileURLToPath } from "url";
5
5
  var compilerInstance = null;
6
+ var RED = "\x1B[31m";
7
+ var YELLOW = "\x1B[33m";
8
+ var CYAN = "\x1B[36m";
9
+ var BOLD = "\x1B[1m";
10
+ var RESET = "\x1B[0m";
11
+ function formatDiagnostic(diag, sourceCode) {
12
+ const level = "WARNING";
13
+ const codeStr = `NG${diag.code}`;
14
+ const file = diag.file || "unknown";
15
+ let line = 1;
16
+ let col = 0;
17
+ let lineStartPos = 0;
18
+ if (diag.start !== void 0 && diag.start !== null) {
19
+ for (let i = 0; i < diag.start && i < sourceCode.length; i++) {
20
+ if (sourceCode[i] === "\n") {
21
+ line++;
22
+ col = 0;
23
+ lineStartPos = i + 1;
24
+ } else {
25
+ col++;
26
+ }
27
+ }
28
+ }
29
+ let output = `
30
+ ${BOLD}${YELLOW}\u25B2 [${level}] ${RED}${codeStr}${RESET}${BOLD}: ${diag.message}${RESET} ${YELLOW}[plugin rust-ngc-plugin]${RESET}
31
+ `;
32
+ const lineStr = line.toString();
33
+ const colStr = (col + 1).toString();
34
+ output += `
35
+ ${CYAN}${file}:${lineStr}:${colStr}:${RESET}
36
+ `;
37
+ let lineEndPos = sourceCode.indexOf("\n", lineStartPos);
38
+ if (lineEndPos === -1) lineEndPos = sourceCode.length;
39
+ const lineContent = sourceCode.substring(lineStartPos, lineEndPos);
40
+ output += ` ${BOLD}${lineStr} \u2502 ${RESET}${lineContent}
41
+ `;
42
+ const gutterWidth = lineStr.length + 3;
43
+ const gutterEmpty = " ".repeat(gutterWidth);
44
+ const length = diag.length || 1;
45
+ const underline = "~".repeat(length);
46
+ output += ` ${gutterEmpty}${" ".repeat(col)}${RED}${underline}${RESET}`;
47
+ return output;
48
+ }
6
49
  function getCompiler(options) {
7
50
  if (compilerInstance) {
8
51
  return compilerInstance;
@@ -57,9 +100,26 @@ function angularCompilerVitePlugin(options) {
57
100
  compiler = getCompiler(options);
58
101
  }
59
102
  if (id.includes("node_modules")) {
103
+ if (id.includes("@angular") && code.includes("\u0275\u0275ngDeclare")) {
104
+ const cleanId2 = id.split("?")[0];
105
+ if (cleanId2.endsWith(".mjs") || cleanId2.endsWith(".js")) {
106
+ try {
107
+ const result = compiler.linkFile(id, code);
108
+ if (result.startsWith("/* Linker Error")) {
109
+ if (debug) console.error(`[Linker Error] ${id}: ${result}`);
110
+ return null;
111
+ }
112
+ return { code: result, map: null };
113
+ } catch (e) {
114
+ if (debug) console.error(`Linker failed for ${id}:`, e);
115
+ return null;
116
+ }
117
+ }
118
+ }
60
119
  return null;
61
120
  }
62
- if (!id.endsWith(".ts") || id.endsWith(".d.ts")) {
121
+ const cleanId = id.split("?")[0];
122
+ if (!cleanId.endsWith(".ts") || cleanId.endsWith(".d.ts")) {
63
123
  return null;
64
124
  }
65
125
  if (debug) {
@@ -67,15 +127,21 @@ function angularCompilerVitePlugin(options) {
67
127
  }
68
128
  try {
69
129
  const result = compiler.compile(id, code);
70
- if (result.startsWith("/* Error")) {
130
+ const { code: compiledCode, diagnostics } = result;
131
+ if (compiledCode.startsWith("/* Error")) {
71
132
  console.error(`[Angular Compiler Error] ${id}:
72
- ${result}`);
133
+ ${compiledCode}`);
73
134
  throw new Error(`Rust Compilation Failed for ${id}`);
74
135
  }
136
+ if (diagnostics && diagnostics.length > 0) {
137
+ diagnostics.forEach((diag) => {
138
+ console.warn(formatDiagnostic(diag, code));
139
+ });
140
+ }
75
141
  if (debug) {
76
142
  console.log(`[Angular Compiler] Successfully compiled: ${id}`);
77
143
  }
78
- return { code: result, map: null };
144
+ return { code: compiledCode, map: null };
79
145
  } catch (e) {
80
146
  console.error(`[Angular Compiler Failed] ${id}:`, e);
81
147
  throw e;
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/compiler/vite.ts"],"sourcesContent":["/**\n * Angular Compiler Plugin for Vite\n *\n * This plugin compiles Angular TypeScript files using the Rust-based Angular compiler.\n * Use with the linker plugin for a complete Angular build solution.\n *\n * @example\n * ```js\n * import { angularCompilerVitePlugin } from 'angular-rust-plugins/compiler/vite';\n * import { angularLinkerVitePlugin } from 'angular-rust-plugins/linker/vite';\n * import { defineConfig } from 'vite';\n *\n * export default defineConfig({\n * plugins: [\n * angularLinkerVitePlugin(),\n * angularCompilerVitePlugin(),\n * ],\n * });\n * ```\n */\n\nimport type { Plugin, HmrContext } from \"vite\";\nimport { createRequire } from \"module\";\nimport { dirname, join } from \"path\";\nimport { fileURLToPath } from \"url\";\nimport type { CompilerBinding } from \"./types\";\n\nlet compilerInstance: CompilerBinding | null = null;\n\nexport interface CompilerOptions {\n /**\n * Enable debug logging\n * @default false\n */\n debug?: boolean;\n\n /**\n * Custom path to the Angular Rust binding package\n */\n bindingPath?: string;\n}\n\nfunction getCompiler(options?: CompilerOptions): CompilerBinding {\n if (compilerInstance) {\n return compilerInstance;\n }\n\n try {\n let binding: { Compiler: new () => CompilerBinding };\n\n if (options?.bindingPath) {\n const require = createRequire(import.meta.url);\n binding = require(options.bindingPath);\n } else {\n // Load from bundled binding directory\n // Use import.meta.url to get the actual location of this file\n const currentFileUrl = import.meta.url;\n const currentFilePath = fileURLToPath(currentFileUrl);\n const currentDir = dirname(currentFilePath);\n const require = createRequire(currentFileUrl);\n\n // Try multiple possible binding locations\n const possiblePaths = [\n join(currentDir, \"..\", \"binding\"), // dist/compiler/../binding\n join(currentDir, \"..\", \"..\", \"binding\"), // in case of deeper nesting\n join(currentDir, \"binding\"), // same directory\n ];\n\n let loadedBinding: { Compiler: new () => CompilerBinding } | null = null;\n let lastError: unknown = null;\n\n for (const bindingPath of possiblePaths) {\n try {\n loadedBinding = require(bindingPath);\n break;\n } catch (e) {\n lastError = e;\n }\n }\n\n if (!loadedBinding) {\n throw (\n lastError ||\n new Error(\"Could not find binding in any expected location\")\n );\n }\n\n binding = loadedBinding;\n }\n\n compilerInstance = new binding.Compiler();\n return compilerInstance;\n } catch (e) {\n throw new Error(`Failed to load Angular Rust binding. Error: ${e}`);\n }\n}\n\n/**\n * Creates a Vite plugin for Angular Rust compiler\n * Compiles .ts files (except .d.ts) using the Rust compiler\n */\nexport function angularCompilerVitePlugin(options?: CompilerOptions): Plugin {\n const debug = options?.debug ?? false;\n let compiler: CompilerBinding;\n\n return {\n name: \"angular-rust-compiler\",\n enforce: \"pre\",\n\n transform(code: string, id: string) {\n // Lazy initialize compiler\n if (!compiler) {\n compiler = getCompiler(options);\n }\n\n // Skip node_modules - those are handled by linker, not compiler\n if (id.includes(\"node_modules\")) {\n return null;\n }\n\n // Only process TypeScript files, skip declaration files\n if (!id.endsWith(\".ts\") || id.endsWith(\".d.ts\")) {\n return null;\n }\n\n if (debug) {\n console.log(`[Angular Compiler] Compiling: ${id}`);\n }\n\n try {\n const result = compiler.compile(id, code);\n\n if (result.startsWith(\"/* Error\")) {\n console.error(`[Angular Compiler Error] ${id}:\\n${result}`);\n throw new Error(`Rust Compilation Failed for ${id}`);\n }\n\n if (debug) {\n console.log(`[Angular Compiler] Successfully compiled: ${id}`);\n }\n\n return { code: result, map: null };\n } catch (e) {\n console.error(`[Angular Compiler Failed] ${id}:`, e);\n throw e;\n }\n },\n\n handleHotUpdate({ file, server }: HmrContext) {\n // When HTML template changes, invalidate the corresponding TS file\n if (file.endsWith(\".html\")) {\n const tsFile = file.replace(/\\.html$/, \".ts\");\n\n if (debug) {\n console.log(`[HMR] HTML changed: ${file}`);\n console.log(`[HMR] Invalidating TS: ${tsFile}`);\n }\n\n const mod = server.moduleGraph.getModuleById(tsFile);\n if (mod) {\n server.moduleGraph.invalidateModule(mod);\n server.ws.send({ type: \"full-reload\", path: \"*\" });\n return [];\n } else {\n server.ws.send({ type: \"full-reload\", path: \"*\" });\n return [];\n }\n }\n },\n };\n}\n\nexport default angularCompilerVitePlugin;\n"],"mappings":";AAsBA,SAAS,qBAAqB;AAC9B,SAAS,SAAS,YAAY;AAC9B,SAAS,qBAAqB;AAG9B,IAAI,mBAA2C;AAe/C,SAAS,YAAY,SAA4C;AAC/D,MAAI,kBAAkB;AACpB,WAAO;AAAA,EACT;AAEA,MAAI;AACF,QAAI;AAEJ,QAAI,SAAS,aAAa;AACxB,YAAMA,WAAU,cAAc,YAAY,GAAG;AAC7C,gBAAUA,SAAQ,QAAQ,WAAW;AAAA,IACvC,OAAO;AAGL,YAAM,iBAAiB,YAAY;AACnC,YAAM,kBAAkB,cAAc,cAAc;AACpD,YAAM,aAAa,QAAQ,eAAe;AAC1C,YAAMA,WAAU,cAAc,cAAc;AAG5C,YAAM,gBAAgB;AAAA,QACpB,KAAK,YAAY,MAAM,SAAS;AAAA;AAAA,QAChC,KAAK,YAAY,MAAM,MAAM,SAAS;AAAA;AAAA,QACtC,KAAK,YAAY,SAAS;AAAA;AAAA,MAC5B;AAEA,UAAI,gBAAgE;AACpE,UAAI,YAAqB;AAEzB,iBAAW,eAAe,eAAe;AACvC,YAAI;AACF,0BAAgBA,SAAQ,WAAW;AACnC;AAAA,QACF,SAAS,GAAG;AACV,sBAAY;AAAA,QACd;AAAA,MACF;AAEA,UAAI,CAAC,eAAe;AAClB,cACE,aACA,IAAI,MAAM,iDAAiD;AAAA,MAE/D;AAEA,gBAAU;AAAA,IACZ;AAEA,uBAAmB,IAAI,QAAQ,SAAS;AACxC,WAAO;AAAA,EACT,SAAS,GAAG;AACV,UAAM,IAAI,MAAM,+CAA+C,CAAC,EAAE;AAAA,EACpE;AACF;AAMO,SAAS,0BAA0B,SAAmC;AAC3E,QAAM,QAAQ,SAAS,SAAS;AAChC,MAAI;AAEJ,SAAO;AAAA,IACL,MAAM;AAAA,IACN,SAAS;AAAA,IAET,UAAU,MAAc,IAAY;AAElC,UAAI,CAAC,UAAU;AACb,mBAAW,YAAY,OAAO;AAAA,MAChC;AAGA,UAAI,GAAG,SAAS,cAAc,GAAG;AAC/B,eAAO;AAAA,MACT;AAGA,UAAI,CAAC,GAAG,SAAS,KAAK,KAAK,GAAG,SAAS,OAAO,GAAG;AAC/C,eAAO;AAAA,MACT;AAEA,UAAI,OAAO;AACT,gBAAQ,IAAI,iCAAiC,EAAE,EAAE;AAAA,MACnD;AAEA,UAAI;AACF,cAAM,SAAS,SAAS,QAAQ,IAAI,IAAI;AAExC,YAAI,OAAO,WAAW,UAAU,GAAG;AACjC,kBAAQ,MAAM,4BAA4B,EAAE;AAAA,EAAM,MAAM,EAAE;AAC1D,gBAAM,IAAI,MAAM,+BAA+B,EAAE,EAAE;AAAA,QACrD;AAEA,YAAI,OAAO;AACT,kBAAQ,IAAI,6CAA6C,EAAE,EAAE;AAAA,QAC/D;AAEA,eAAO,EAAE,MAAM,QAAQ,KAAK,KAAK;AAAA,MACnC,SAAS,GAAG;AACV,gBAAQ,MAAM,6BAA6B,EAAE,KAAK,CAAC;AACnD,cAAM;AAAA,MACR;AAAA,IACF;AAAA,IAEA,gBAAgB,EAAE,MAAM,OAAO,GAAe;AAE5C,UAAI,KAAK,SAAS,OAAO,GAAG;AAC1B,cAAM,SAAS,KAAK,QAAQ,WAAW,KAAK;AAE5C,YAAI,OAAO;AACT,kBAAQ,IAAI,uBAAuB,IAAI,EAAE;AACzC,kBAAQ,IAAI,0BAA0B,MAAM,EAAE;AAAA,QAChD;AAEA,cAAM,MAAM,OAAO,YAAY,cAAc,MAAM;AACnD,YAAI,KAAK;AACP,iBAAO,YAAY,iBAAiB,GAAG;AACvC,iBAAO,GAAG,KAAK,EAAE,MAAM,eAAe,MAAM,IAAI,CAAC;AACjD,iBAAO,CAAC;AAAA,QACV,OAAO;AACL,iBAAO,GAAG,KAAK,EAAE,MAAM,eAAe,MAAM,IAAI,CAAC;AACjD,iBAAO,CAAC;AAAA,QACV;AAAA,MACF;AAAA,IACF;AAAA,EACF;AACF;","names":["require"]}
1
+ {"version":3,"sources":["../../src/compiler/vite.ts"],"sourcesContent":["/**\n * Angular Compiler Plugin for Vite\n *\n * This plugin compiles Angular TypeScript files using the Rust-based Angular compiler.\n * Use with the linker plugin for a complete Angular build solution.\n *\n * @example\n * ```js\n * import { angularCompilerVitePlugin } from 'angular-rust-plugins/compiler/vite';\n * import { angularLinkerVitePlugin } from 'angular-rust-plugins/linker/vite';\n * import { defineConfig } from 'vite';\n *\n * export default defineConfig({\n * plugins: [\n * angularLinkerVitePlugin(),\n * angularCompilerVitePlugin(),\n * ],\n * });\n * ```\n */\n\nimport type { Plugin, HmrContext } from \"vite\";\nimport { createRequire } from \"module\";\nimport { dirname, join } from \"path\";\nimport { fileURLToPath } from \"url\";\nimport { Compiler } from \"../binding\";\n\nlet compilerInstance: Compiler | null = null;\n\nexport interface CompilerOptions {\n /**\n * Enable debug logging\n * @default false\n */\n debug?: boolean;\n\n /**\n * Custom path to the Angular Rust binding package\n */\n bindingPath?: string;\n}\n\n// ============ Diagnostic Formatting ============\nconst RED = '\\x1b[31m';\nconst YELLOW = '\\x1b[33m';\nconst CYAN = '\\x1b[36m';\nconst BOLD = '\\x1b[1m';\nconst RESET = '\\x1b[0m';\n\nfunction formatDiagnostic(diag: any, sourceCode: string): string {\n const level = 'WARNING';\n const codeStr = `NG${diag.code}`;\n const file = diag.file || 'unknown';\n\n let line = 1;\n let col = 0;\n let lineStartPos = 0;\n\n if (diag.start !== undefined && diag.start !== null) {\n for (let i = 0; i < diag.start && i < sourceCode.length; i++) {\n if (sourceCode[i] === '\\n') {\n line++;\n col = 0;\n lineStartPos = i + 1;\n } else {\n col++;\n }\n }\n }\n\n let output = `\\n${BOLD}${YELLOW}▲ [${level}] ${RED}${codeStr}${RESET}${BOLD}: ${diag.message}${RESET} ${YELLOW}[plugin rust-ngc-plugin]${RESET}\\n`;\n\n const lineStr = line.toString();\n const colStr = (col + 1).toString();\n output += `\\n ${CYAN}${file}:${lineStr}:${colStr}:${RESET}\\n`;\n\n let lineEndPos = sourceCode.indexOf('\\n', lineStartPos);\n if (lineEndPos === -1) lineEndPos = sourceCode.length;\n const lineContent = sourceCode.substring(lineStartPos, lineEndPos);\n\n output += ` ${BOLD}${lineStr} │ ${RESET}${lineContent}\\n`;\n\n const gutterWidth = lineStr.length + 3;\n const gutterEmpty = ' '.repeat(gutterWidth);\n const length = diag.length || 1;\n const underline = '~'.repeat(length);\n\n output += ` ${gutterEmpty}${' '.repeat(col)}${RED}${underline}${RESET}`;\n\n return output;\n}\n\nfunction getCompiler(options?: CompilerOptions): Compiler {\n if (compilerInstance) {\n return compilerInstance;\n }\n\n try {\n let binding: { Compiler: new () => Compiler };\n\n if (options?.bindingPath) {\n const require = createRequire(import.meta.url);\n binding = require(options.bindingPath);\n } else {\n // Load from bundled binding directory\n // Use import.meta.url to get the actual location of this file\n const currentFileUrl = import.meta.url;\n const currentFilePath = fileURLToPath(currentFileUrl);\n const currentDir = dirname(currentFilePath);\n const require = createRequire(currentFileUrl);\n\n // Try multiple possible binding locations\n const possiblePaths = [\n join(currentDir, \"..\", \"binding\"), // dist/compiler/../binding\n join(currentDir, \"..\", \"..\", \"binding\"), // in case of deeper nesting\n join(currentDir, \"binding\"), // same directory\n ];\n\n let loadedBinding: { Compiler: new () => Compiler } | null = null;\n let lastError: unknown = null;\n\n for (const bindingPath of possiblePaths) {\n try {\n loadedBinding = require(bindingPath);\n break;\n } catch (e) {\n lastError = e;\n }\n }\n\n if (!loadedBinding) {\n throw (\n lastError ||\n new Error(\"Could not find binding in any expected location\")\n );\n }\n\n binding = loadedBinding;\n }\n\n compilerInstance = new binding.Compiler();\n return compilerInstance;\n } catch (e) {\n throw new Error(`Failed to load Angular Rust binding. Error: ${e}`);\n }\n}\n\n/**\n * Creates a Vite plugin for Angular Rust compiler\n * Compiles .ts files (except .d.ts) using the Rust compiler\n */\nexport function angularCompilerVitePlugin(options?: CompilerOptions): Plugin {\n const debug = options?.debug ?? false;\n let compiler: Compiler;\n\n return {\n name: \"angular-rust-compiler\",\n enforce: \"pre\",\n\n transform(code: string, id: string) {\n // Lazy initialize compiler\n if (!compiler) {\n compiler = getCompiler(options);\n }\n\n // Skip node_modules but check for Angular packages that need linking\n if (id.includes('node_modules')) {\n if (id.includes('@angular') && code.includes('ɵɵngDeclare')) {\n const cleanId = id.split('?')[0];\n if (cleanId.endsWith('.mjs') || cleanId.endsWith('.js')) {\n try {\n const result = compiler.linkFile(id, code);\n if (result.startsWith('/* Linker Error')) {\n if (debug) console.error(`[Linker Error] ${id}: ${result}`);\n return null;\n }\n return { code: result, map: null };\n } catch (e) {\n if (debug) console.error(`Linker failed for ${id}:`, e);\n return null;\n }\n }\n }\n return null;\n }\n\n // Only process TypeScript files, skip declaration files\n const cleanId = id.split('?')[0];\n if (!cleanId.endsWith('.ts') || cleanId.endsWith('.d.ts')) {\n return null;\n }\n\n if (debug) {\n console.log(`[Angular Compiler] Compiling: ${id}`);\n }\n\n try {\n const result = compiler.compile(id, code);\n\n // Handle structured result\n const { code: compiledCode, diagnostics } = result;\n\n if (compiledCode.startsWith('/* Error')) {\n console.error(`[Angular Compiler Error] ${id}:\\n${compiledCode}`);\n throw new Error(`Rust Compilation Failed for ${id}`);\n }\n\n if (diagnostics && diagnostics.length > 0) {\n diagnostics.forEach((diag: any) => {\n console.warn(formatDiagnostic(diag, code));\n });\n }\n\n if (debug) {\n console.log(`[Angular Compiler] Successfully compiled: ${id}`);\n }\n\n return { code: compiledCode, map: null };\n } catch (e) {\n console.error(`[Angular Compiler Failed] ${id}:`, e);\n throw e;\n }\n },\n\n handleHotUpdate({ file, server }: HmrContext) {\n // When HTML template changes, invalidate the corresponding TS file\n if (file.endsWith(\".html\")) {\n const tsFile = file.replace(/\\.html$/, \".ts\");\n\n if (debug) {\n console.log(`[HMR] HTML changed: ${file}`);\n console.log(`[HMR] Invalidating TS: ${tsFile}`);\n }\n\n const mod = server.moduleGraph.getModuleById(tsFile);\n if (mod) {\n server.moduleGraph.invalidateModule(mod);\n server.ws.send({ type: \"full-reload\", path: \"*\" });\n return [];\n } else {\n server.ws.send({ type: \"full-reload\", path: \"*\" });\n return [];\n }\n }\n },\n };\n}\n\nexport default angularCompilerVitePlugin;\n"],"mappings":"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","names":["require","cleanId"]}
package/compiler/vite.cjs CHANGED
@@ -29,6 +29,49 @@ var import_path = require("path");
29
29
  var import_url = require("url");
30
30
  var import_meta = {};
31
31
  var compilerInstance = null;
32
+ var RED = "\x1B[31m";
33
+ var YELLOW = "\x1B[33m";
34
+ var CYAN = "\x1B[36m";
35
+ var BOLD = "\x1B[1m";
36
+ var RESET = "\x1B[0m";
37
+ function formatDiagnostic(diag, sourceCode) {
38
+ const level = "WARNING";
39
+ const codeStr = `NG${diag.code}`;
40
+ const file = diag.file || "unknown";
41
+ let line = 1;
42
+ let col = 0;
43
+ let lineStartPos = 0;
44
+ if (diag.start !== void 0 && diag.start !== null) {
45
+ for (let i = 0; i < diag.start && i < sourceCode.length; i++) {
46
+ if (sourceCode[i] === "\n") {
47
+ line++;
48
+ col = 0;
49
+ lineStartPos = i + 1;
50
+ } else {
51
+ col++;
52
+ }
53
+ }
54
+ }
55
+ let output = `
56
+ ${BOLD}${YELLOW}\u25B2 [${level}] ${RED}${codeStr}${RESET}${BOLD}: ${diag.message}${RESET} ${YELLOW}[plugin rust-ngc-plugin]${RESET}
57
+ `;
58
+ const lineStr = line.toString();
59
+ const colStr = (col + 1).toString();
60
+ output += `
61
+ ${CYAN}${file}:${lineStr}:${colStr}:${RESET}
62
+ `;
63
+ let lineEndPos = sourceCode.indexOf("\n", lineStartPos);
64
+ if (lineEndPos === -1) lineEndPos = sourceCode.length;
65
+ const lineContent = sourceCode.substring(lineStartPos, lineEndPos);
66
+ output += ` ${BOLD}${lineStr} \u2502 ${RESET}${lineContent}
67
+ `;
68
+ const gutterWidth = lineStr.length + 3;
69
+ const gutterEmpty = " ".repeat(gutterWidth);
70
+ const length = diag.length || 1;
71
+ const underline = "~".repeat(length);
72
+ output += ` ${gutterEmpty}${" ".repeat(col)}${RED}${underline}${RESET}`;
73
+ return output;
74
+ }
32
75
  function getCompiler(options) {
33
76
  if (compilerInstance) {
34
77
  return compilerInstance;
@@ -83,9 +126,26 @@ function angularCompilerVitePlugin(options) {
83
126
  compiler = getCompiler(options);
84
127
  }
85
128
  if (id.includes("node_modules")) {
129
+ if (id.includes("@angular") && code.includes("\u0275\u0275ngDeclare")) {
130
+ const cleanId2 = id.split("?")[0];
131
+ if (cleanId2.endsWith(".mjs") || cleanId2.endsWith(".js")) {
132
+ try {
133
+ const result = compiler.linkFile(id, code);
134
+ if (result.startsWith("/* Linker Error")) {
135
+ if (debug) console.error(`[Linker Error] ${id}: ${result}`);
136
+ return null;
137
+ }
138
+ return { code: result, map: null };
139
+ } catch (e) {
140
+ if (debug) console.error(`Linker failed for ${id}:`, e);
141
+ return null;
142
+ }
143
+ }
144
+ }
86
145
  return null;
87
146
  }
88
- if (!id.endsWith(".ts") || id.endsWith(".d.ts")) {
147
+ const cleanId = id.split("?")[0];
148
+ if (!cleanId.endsWith(".ts") || cleanId.endsWith(".d.ts")) {
89
149
  return null;
90
150
  }
91
151
  if (debug) {
@@ -93,15 +153,21 @@ function angularCompilerVitePlugin(options) {
93
153
  }
94
154
  try {
95
155
  const result = compiler.compile(id, code);
96
- if (result.startsWith("/* Error")) {
156
+ const { code: compiledCode, diagnostics } = result;
157
+ if (compiledCode.startsWith("/* Error")) {
97
158
  console.error(`[Angular Compiler Error] ${id}:
98
- ${result}`);
159
+ ${compiledCode}`);
99
160
  throw new Error(`Rust Compilation Failed for ${id}`);
100
161
  }
162
+ if (diagnostics && diagnostics.length > 0) {
163
+ diagnostics.forEach((diag) => {
164
+ console.warn(formatDiagnostic(diag, code));
165
+ });
166
+ }
101
167
  if (debug) {
102
168
  console.log(`[Angular Compiler] Successfully compiled: ${id}`);
103
169
  }
104
- return { code: result, map: null };
170
+ return { code: compiledCode, map: null };
105
171
  } catch (e) {
106
172
  console.error(`[Angular Compiler Failed] ${id}:`, e);
107
173
  throw e;
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/compiler/vite.ts"],"sourcesContent":["/**\n * Angular Compiler Plugin for Vite\n *\n * This plugin compiles Angular TypeScript files using the Rust-based Angular compiler.\n * Use with the linker plugin for a complete Angular build solution.\n *\n * @example\n * ```js\n * import { angularCompilerVitePlugin } from 'angular-rust-plugins/compiler/vite';\n * import { angularLinkerVitePlugin } from 'angular-rust-plugins/linker/vite';\n * import { defineConfig } from 'vite';\n *\n * export default defineConfig({\n * plugins: [\n * angularLinkerVitePlugin(),\n * angularCompilerVitePlugin(),\n * ],\n * });\n * ```\n */\n\nimport type { Plugin, HmrContext } from \"vite\";\nimport { createRequire } from \"module\";\nimport { dirname, join } from \"path\";\nimport { fileURLToPath } from \"url\";\nimport type { CompilerBinding } from \"./types\";\n\nlet compilerInstance: CompilerBinding | null = null;\n\nexport interface CompilerOptions {\n /**\n * Enable debug logging\n * @default false\n */\n debug?: boolean;\n\n /**\n * Custom path to the Angular Rust binding package\n */\n bindingPath?: string;\n}\n\nfunction getCompiler(options?: CompilerOptions): CompilerBinding {\n if (compilerInstance) {\n return compilerInstance;\n }\n\n try {\n let binding: { Compiler: new () => CompilerBinding };\n\n if (options?.bindingPath) {\n const require = createRequire(import.meta.url);\n binding = require(options.bindingPath);\n } else {\n // Load from bundled binding directory\n // Use import.meta.url to get the actual location of this file\n const currentFileUrl = import.meta.url;\n const currentFilePath = fileURLToPath(currentFileUrl);\n const currentDir = dirname(currentFilePath);\n const require = createRequire(currentFileUrl);\n\n // Try multiple possible binding locations\n const possiblePaths = [\n join(currentDir, \"..\", \"binding\"), // dist/compiler/../binding\n join(currentDir, \"..\", \"..\", \"binding\"), // in case of deeper nesting\n join(currentDir, \"binding\"), // same directory\n ];\n\n let loadedBinding: { Compiler: new () => CompilerBinding } | null = null;\n let lastError: unknown = null;\n\n for (const bindingPath of possiblePaths) {\n try {\n loadedBinding = require(bindingPath);\n break;\n } catch (e) {\n lastError = e;\n }\n }\n\n if (!loadedBinding) {\n throw (\n lastError ||\n new Error(\"Could not find binding in any expected location\")\n );\n }\n\n binding = loadedBinding;\n }\n\n compilerInstance = new binding.Compiler();\n return compilerInstance;\n } catch (e) {\n throw new Error(`Failed to load Angular Rust binding. Error: ${e}`);\n }\n}\n\n/**\n * Creates a Vite plugin for Angular Rust compiler\n * Compiles .ts files (except .d.ts) using the Rust compiler\n */\nexport function angularCompilerVitePlugin(options?: CompilerOptions): Plugin {\n const debug = options?.debug ?? false;\n let compiler: CompilerBinding;\n\n return {\n name: \"angular-rust-compiler\",\n enforce: \"pre\",\n\n transform(code: string, id: string) {\n // Lazy initialize compiler\n if (!compiler) {\n compiler = getCompiler(options);\n }\n\n // Skip node_modules - those are handled by linker, not compiler\n if (id.includes(\"node_modules\")) {\n return null;\n }\n\n // Only process TypeScript files, skip declaration files\n if (!id.endsWith(\".ts\") || id.endsWith(\".d.ts\")) {\n return null;\n }\n\n if (debug) {\n console.log(`[Angular Compiler] Compiling: ${id}`);\n }\n\n try {\n const result = compiler.compile(id, code);\n\n if (result.startsWith(\"/* Error\")) {\n console.error(`[Angular Compiler Error] ${id}:\\n${result}`);\n throw new Error(`Rust Compilation Failed for ${id}`);\n }\n\n if (debug) {\n console.log(`[Angular Compiler] Successfully compiled: ${id}`);\n }\n\n return { code: result, map: null };\n } catch (e) {\n console.error(`[Angular Compiler Failed] ${id}:`, e);\n throw e;\n }\n },\n\n handleHotUpdate({ file, server }: HmrContext) {\n // When HTML template changes, invalidate the corresponding TS file\n if (file.endsWith(\".html\")) {\n const tsFile = file.replace(/\\.html$/, \".ts\");\n\n if (debug) {\n console.log(`[HMR] HTML changed: ${file}`);\n console.log(`[HMR] Invalidating TS: ${tsFile}`);\n }\n\n const mod = server.moduleGraph.getModuleById(tsFile);\n if (mod) {\n server.moduleGraph.invalidateModule(mod);\n server.ws.send({ type: \"full-reload\", path: \"*\" });\n return [];\n } else {\n server.ws.send({ type: \"full-reload\", path: \"*\" });\n return [];\n }\n }\n },\n };\n}\n\nexport default angularCompilerVitePlugin;\n"],"mappings":"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","names":["require"]}
1
+ {"version":3,"sources":["../../src/compiler/vite.ts"],"sourcesContent":["/**\n * Angular Compiler Plugin for Vite\n *\n * This plugin compiles Angular TypeScript files using the Rust-based Angular compiler.\n * Use with the linker plugin for a complete Angular build solution.\n *\n * @example\n * ```js\n * import { angularCompilerVitePlugin } from 'angular-rust-plugins/compiler/vite';\n * import { angularLinkerVitePlugin } from 'angular-rust-plugins/linker/vite';\n * import { defineConfig } from 'vite';\n *\n * export default defineConfig({\n * plugins: [\n * angularLinkerVitePlugin(),\n * angularCompilerVitePlugin(),\n * ],\n * });\n * ```\n */\n\nimport type { Plugin, HmrContext } from \"vite\";\nimport { createRequire } from \"module\";\nimport { dirname, join } from \"path\";\nimport { fileURLToPath } from \"url\";\nimport { Compiler } from \"../binding\";\n\nlet compilerInstance: Compiler | null = null;\n\nexport interface CompilerOptions {\n /**\n * Enable debug logging\n * @default false\n */\n debug?: boolean;\n\n /**\n * Custom path to the Angular Rust binding package\n */\n bindingPath?: string;\n}\n\n// ============ Diagnostic Formatting ============\nconst RED = '\\x1b[31m';\nconst YELLOW = '\\x1b[33m';\nconst CYAN = '\\x1b[36m';\nconst BOLD = '\\x1b[1m';\nconst RESET = '\\x1b[0m';\n\nfunction formatDiagnostic(diag: any, sourceCode: string): string {\n const level = 'WARNING';\n const codeStr = `NG${diag.code}`;\n const file = diag.file || 'unknown';\n\n let line = 1;\n let col = 0;\n let lineStartPos = 0;\n\n if (diag.start !== undefined && diag.start !== null) {\n for (let i = 0; i < diag.start && i < sourceCode.length; i++) {\n if (sourceCode[i] === '\\n') {\n line++;\n col = 0;\n lineStartPos = i + 1;\n } else {\n col++;\n }\n }\n }\n\n let output = `\\n${BOLD}${YELLOW}▲ [${level}] ${RED}${codeStr}${RESET}${BOLD}: ${diag.message}${RESET} ${YELLOW}[plugin rust-ngc-plugin]${RESET}\\n`;\n\n const lineStr = line.toString();\n const colStr = (col + 1).toString();\n output += `\\n ${CYAN}${file}:${lineStr}:${colStr}:${RESET}\\n`;\n\n let lineEndPos = sourceCode.indexOf('\\n', lineStartPos);\n if (lineEndPos === -1) lineEndPos = sourceCode.length;\n const lineContent = sourceCode.substring(lineStartPos, lineEndPos);\n\n output += ` ${BOLD}${lineStr} │ ${RESET}${lineContent}\\n`;\n\n const gutterWidth = lineStr.length + 3;\n const gutterEmpty = ' '.repeat(gutterWidth);\n const length = diag.length || 1;\n const underline = '~'.repeat(length);\n\n output += ` ${gutterEmpty}${' '.repeat(col)}${RED}${underline}${RESET}`;\n\n return output;\n}\n\nfunction getCompiler(options?: CompilerOptions): Compiler {\n if (compilerInstance) {\n return compilerInstance;\n }\n\n try {\n let binding: { Compiler: new () => Compiler };\n\n if (options?.bindingPath) {\n const require = createRequire(import.meta.url);\n binding = require(options.bindingPath);\n } else {\n // Load from bundled binding directory\n // Use import.meta.url to get the actual location of this file\n const currentFileUrl = import.meta.url;\n const currentFilePath = fileURLToPath(currentFileUrl);\n const currentDir = dirname(currentFilePath);\n const require = createRequire(currentFileUrl);\n\n // Try multiple possible binding locations\n const possiblePaths = [\n join(currentDir, \"..\", \"binding\"), // dist/compiler/../binding\n join(currentDir, \"..\", \"..\", \"binding\"), // in case of deeper nesting\n join(currentDir, \"binding\"), // same directory\n ];\n\n let loadedBinding: { Compiler: new () => Compiler } | null = null;\n let lastError: unknown = null;\n\n for (const bindingPath of possiblePaths) {\n try {\n loadedBinding = require(bindingPath);\n break;\n } catch (e) {\n lastError = e;\n }\n }\n\n if (!loadedBinding) {\n throw (\n lastError ||\n new Error(\"Could not find binding in any expected location\")\n );\n }\n\n binding = loadedBinding;\n }\n\n compilerInstance = new binding.Compiler();\n return compilerInstance;\n } catch (e) {\n throw new Error(`Failed to load Angular Rust binding. Error: ${e}`);\n }\n}\n\n/**\n * Creates a Vite plugin for Angular Rust compiler\n * Compiles .ts files (except .d.ts) using the Rust compiler\n */\nexport function angularCompilerVitePlugin(options?: CompilerOptions): Plugin {\n const debug = options?.debug ?? false;\n let compiler: Compiler;\n\n return {\n name: \"angular-rust-compiler\",\n enforce: \"pre\",\n\n transform(code: string, id: string) {\n // Lazy initialize compiler\n if (!compiler) {\n compiler = getCompiler(options);\n }\n\n // Skip node_modules but check for Angular packages that need linking\n if (id.includes('node_modules')) {\n if (id.includes('@angular') && code.includes('ɵɵngDeclare')) {\n const cleanId = id.split('?')[0];\n if (cleanId.endsWith('.mjs') || cleanId.endsWith('.js')) {\n try {\n const result = compiler.linkFile(id, code);\n if (result.startsWith('/* Linker Error')) {\n if (debug) console.error(`[Linker Error] ${id}: ${result}`);\n return null;\n }\n return { code: result, map: null };\n } catch (e) {\n if (debug) console.error(`Linker failed for ${id}:`, e);\n return null;\n }\n }\n }\n return null;\n }\n\n // Only process TypeScript files, skip declaration files\n const cleanId = id.split('?')[0];\n if (!cleanId.endsWith('.ts') || cleanId.endsWith('.d.ts')) {\n return null;\n }\n\n if (debug) {\n console.log(`[Angular Compiler] Compiling: ${id}`);\n }\n\n try {\n const result = compiler.compile(id, code);\n\n // Handle structured result\n const { code: compiledCode, diagnostics } = result;\n\n if (compiledCode.startsWith('/* Error')) {\n console.error(`[Angular Compiler Error] ${id}:\\n${compiledCode}`);\n throw new Error(`Rust Compilation Failed for ${id}`);\n }\n\n if (diagnostics && diagnostics.length > 0) {\n diagnostics.forEach((diag: any) => {\n console.warn(formatDiagnostic(diag, code));\n });\n }\n\n if (debug) {\n console.log(`[Angular Compiler] Successfully compiled: ${id}`);\n }\n\n return { code: compiledCode, map: null };\n } catch (e) {\n console.error(`[Angular Compiler Failed] ${id}:`, e);\n throw e;\n }\n },\n\n handleHotUpdate({ file, server }: HmrContext) {\n // When HTML template changes, invalidate the corresponding TS file\n if (file.endsWith(\".html\")) {\n const tsFile = file.replace(/\\.html$/, \".ts\");\n\n if (debug) {\n console.log(`[HMR] HTML changed: ${file}`);\n console.log(`[HMR] Invalidating TS: ${tsFile}`);\n }\n\n const mod = server.moduleGraph.getModuleById(tsFile);\n if (mod) {\n server.moduleGraph.invalidateModule(mod);\n server.ws.send({ type: \"full-reload\", path: \"*\" });\n return [];\n } else {\n server.ws.send({ type: \"full-reload\", path: \"*\" });\n return [];\n }\n }\n },\n };\n}\n\nexport default angularCompilerVitePlugin;\n"],"mappings":";;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAsBA,oBAA8B;AAC9B,kBAA8B;AAC9B,iBAA8B;AAxB9B;AA2BA,IAAI,mBAAoC;AAgBxC,IAAM,MAAM;AACZ,IAAM,SAAS;AACf,IAAM,OAAO;AACb,IAAM,OAAO;AACb,IAAM,QAAQ;AAEd,SAAS,iBAAiB,MAAW,YAA4B;AAC/D,QAAM,QAAQ;AACd,QAAM,UAAU,KAAK,KAAK,IAAI;AAC9B,QAAM,OAAO,KAAK,QAAQ;AAE1B,MAAI,OAAO;AACX,MAAI,MAAM;AACV,MAAI,eAAe;AAEnB,MAAI,KAAK,UAAU,UAAa,KAAK,UAAU,MAAM;AACnD,aAAS,IAAI,GAAG,IAAI,KAAK,SAAS,IAAI,WAAW,QAAQ,KAAK;AAC5D,UAAI,WAAW,CAAC,MAAM,MAAM;AAC1B;AACA,cAAM;AACN,uBAAe,IAAI;AAAA,MACrB,OAAO;AACL;AAAA,MACF;AAAA,IACF;AAAA,EACF;AAEA,MAAI,SAAS;AAAA,EAAK,IAAI,GAAG,MAAM,WAAM,KAAK,KAAK,GAAG,GAAG,OAAO,GAAG,KAAK,GAAG,IAAI,KAAK,KAAK,OAAO,GAAG,KAAK,IAAI,MAAM,2BAA2B,KAAK;AAAA;AAE9I,QAAM,UAAU,KAAK,SAAS;AAC9B,QAAM,UAAU,MAAM,GAAG,SAAS;AAClC,YAAU;AAAA,MAAS,IAAI,GAAG,IAAI,IAAI,OAAO,IAAI,MAAM,IAAI,KAAK;AAAA;AAE5D,MAAI,aAAa,WAAW,QAAQ,MAAM,YAAY;AACtD,MAAI,eAAe,GAAI,cAAa,WAAW;AAC/C,QAAM,cAAc,WAAW,UAAU,cAAc,UAAU;AAEjE,YAAU,SAAS,IAAI,GAAG,OAAO,WAAM,KAAK,GAAG,WAAW;AAAA;AAE1D,QAAM,cAAc,QAAQ,SAAS;AACrC,QAAM,cAAc,IAAI,OAAO,WAAW;AAC1C,QAAM,SAAS,KAAK,UAAU;AAC9B,QAAM,YAAY,IAAI,OAAO,MAAM;AAEnC,YAAU,SAAS,WAAW,GAAG,IAAI,OAAO,GAAG,CAAC,GAAG,GAAG,GAAG,SAAS,GAAG,KAAK;AAE1E,SAAO;AACT;AAEA,SAAS,YAAY,SAAqC;AACxD,MAAI,kBAAkB;AACpB,WAAO;AAAA,EACT;AAEA,MAAI;AACF,QAAI;AAEJ,QAAI,SAAS,aAAa;AACxB,YAAMA,eAAU,6BAAc,YAAY,GAAG;AAC7C,gBAAUA,SAAQ,QAAQ,WAAW;AAAA,IACvC,OAAO;AAGL,YAAM,iBAAiB,YAAY;AACnC,YAAM,sBAAkB,0BAAc,cAAc;AACpD,YAAM,iBAAa,qBAAQ,eAAe;AAC1C,YAAMA,eAAU,6BAAc,cAAc;AAG5C,YAAM,gBAAgB;AAAA,YACpB,kBAAK,YAAY,MAAM,SAAS;AAAA;AAAA,YAChC,kBAAK,YAAY,MAAM,MAAM,SAAS;AAAA;AAAA,YACtC,kBAAK,YAAY,SAAS;AAAA;AAAA,MAC5B;AAEA,UAAI,gBAAyD;AAC7D,UAAI,YAAqB;AAEzB,iBAAW,eAAe,eAAe;AACvC,YAAI;AACF,0BAAgBA,SAAQ,WAAW;AACnC;AAAA,QACF,SAAS,GAAG;AACV,sBAAY;AAAA,QACd;AAAA,MACF;AAEA,UAAI,CAAC,eAAe;AAClB,cACE,aACA,IAAI,MAAM,iDAAiD;AAAA,MAE/D;AAEA,gBAAU;AAAA,IACZ;AAEA,uBAAmB,IAAI,QAAQ,SAAS;AACxC,WAAO;AAAA,EACT,SAAS,GAAG;AACV,UAAM,IAAI,MAAM,+CAA+C,CAAC,EAAE;AAAA,EACpE;AACF;AAMO,SAAS,0BAA0B,SAAmC;AAC3E,QAAM,QAAQ,SAAS,SAAS;AAChC,MAAI;AAEJ,SAAO;AAAA,IACL,MAAM;AAAA,IACN,SAAS;AAAA,IAET,UAAU,MAAc,IAAY;AAElC,UAAI,CAAC,UAAU;AACb,mBAAW,YAAY,OAAO;AAAA,MAChC;AAGA,UAAI,GAAG,SAAS,cAAc,GAAG;AAC/B,YAAI,GAAG,SAAS,UAAU,KAAK,KAAK,SAAS,uBAAa,GAAG;AAC3D,gBAAMC,WAAU,GAAG,MAAM,GAAG,EAAE,CAAC;AAC/B,cAAIA,SAAQ,SAAS,MAAM,KAAKA,SAAQ,SAAS,KAAK,GAAG;AACvD,gBAAI;AACF,oBAAM,SAAS,SAAS,SAAS,IAAI,IAAI;AACzC,kBAAI,OAAO,WAAW,iBAAiB,GAAG;AACvC,oBAAI,MAAO,SAAQ,MAAM,kBAAkB,EAAE,KAAK,MAAM,EAAE;AAC1D,uBAAO;AAAA,cACV;AACA,qBAAO,EAAE,MAAM,QAAQ,KAAK,KAAK;AAAA,YACnC,SAAS,GAAG;AACT,kBAAI,MAAO,SAAQ,MAAM,qBAAqB,EAAE,KAAK,CAAC;AACvD,qBAAO;AAAA,YACT;AAAA,UACF;AAAA,QACF;AACA,eAAO;AAAA,MACT;AAGA,YAAM,UAAU,GAAG,MAAM,GAAG,EAAE,CAAC;AAC/B,UAAI,CAAC,QAAQ,SAAS,KAAK,KAAK,QAAQ,SAAS,OAAO,GAAG;AACzD,eAAO;AAAA,MACT;AAEA,UAAI,OAAO;AACT,gBAAQ,IAAI,iCAAiC,EAAE,EAAE;AAAA,MACnD;AAEA,UAAI;AACF,cAAM,SAAS,SAAS,QAAQ,IAAI,IAAI;AAGxC,cAAM,EAAE,MAAM,cAAc,YAAY,IAAI;AAE5C,YAAI,aAAa,WAAW,UAAU,GAAG;AACvC,kBAAQ,MAAM,4BAA4B,EAAE;AAAA,EAAM,YAAY,EAAE;AAChE,gBAAM,IAAI,MAAM,+BAA+B,EAAE,EAAE;AAAA,QACrD;AAEA,YAAI,eAAe,YAAY,SAAS,GAAG;AACzC,sBAAY,QAAQ,CAAC,SAAc;AACjC,oBAAQ,KAAK,iBAAiB,MAAM,IAAI,CAAC;AAAA,UAC3C,CAAC;AAAA,QACH;AAEA,YAAI,OAAO;AACT,kBAAQ,IAAI,6CAA6C,EAAE,EAAE;AAAA,QAC/D;AAEA,eAAO,EAAE,MAAM,cAAc,KAAK,KAAK;AAAA,MACzC,SAAS,GAAG;AACV,gBAAQ,MAAM,6BAA6B,EAAE,KAAK,CAAC;AACnD,cAAM;AAAA,MACR;AAAA,IACF;AAAA,IAEA,gBAAgB,EAAE,MAAM,OAAO,GAAe;AAE5C,UAAI,KAAK,SAAS,OAAO,GAAG;AAC1B,cAAM,SAAS,KAAK,QAAQ,WAAW,KAAK;AAE5C,YAAI,OAAO;AACT,kBAAQ,IAAI,uBAAuB,IAAI,EAAE;AACzC,kBAAQ,IAAI,0BAA0B,MAAM,EAAE;AAAA,QAChD;AAEA,cAAM,MAAM,OAAO,YAAY,cAAc,MAAM;AACnD,YAAI,KAAK;AACP,iBAAO,YAAY,iBAAiB,GAAG;AACvC,iBAAO,GAAG,KAAK,EAAE,MAAM,eAAe,MAAM,IAAI,CAAC;AACjD,iBAAO,CAAC;AAAA,QACV,OAAO;AACL,iBAAO,GAAG,KAAK,EAAE,MAAM,eAAe,MAAM,IAAI,CAAC;AACjD,iBAAO,CAAC;AAAA,QACV;AAAA,MACF;AAAA,IACF;AAAA,EACF;AACF;AAEA,IAAO,eAAQ;","names":["require","cleanId"]}
package/compiler/vite.js CHANGED
@@ -3,6 +3,49 @@ import { createRequire } from "module";
3
3
  import { dirname, join } from "path";
4
4
  import { fileURLToPath } from "url";
5
5
  var compilerInstance = null;
6
+ var RED = "\x1B[31m";
7
+ var YELLOW = "\x1B[33m";
8
+ var CYAN = "\x1B[36m";
9
+ var BOLD = "\x1B[1m";
10
+ var RESET = "\x1B[0m";
11
+ function formatDiagnostic(diag, sourceCode) {
12
+ const level = "WARNING";
13
+ const codeStr = `NG${diag.code}`;
14
+ const file = diag.file || "unknown";
15
+ let line = 1;
16
+ let col = 0;
17
+ let lineStartPos = 0;
18
+ if (diag.start !== void 0 && diag.start !== null) {
19
+ for (let i = 0; i < diag.start && i < sourceCode.length; i++) {
20
+ if (sourceCode[i] === "\n") {
21
+ line++;
22
+ col = 0;
23
+ lineStartPos = i + 1;
24
+ } else {
25
+ col++;
26
+ }
27
+ }
28
+ }
29
+ let output = `
30
+ ${BOLD}${YELLOW}\u25B2 [${level}] ${RED}${codeStr}${RESET}${BOLD}: ${diag.message}${RESET} ${YELLOW}[plugin rust-ngc-plugin]${RESET}
31
+ `;
32
+ const lineStr = line.toString();
33
+ const colStr = (col + 1).toString();
34
+ output += `
35
+ ${CYAN}${file}:${lineStr}:${colStr}:${RESET}
36
+ `;
37
+ let lineEndPos = sourceCode.indexOf("\n", lineStartPos);
38
+ if (lineEndPos === -1) lineEndPos = sourceCode.length;
39
+ const lineContent = sourceCode.substring(lineStartPos, lineEndPos);
40
+ output += ` ${BOLD}${lineStr} \u2502 ${RESET}${lineContent}
41
+ `;
42
+ const gutterWidth = lineStr.length + 3;
43
+ const gutterEmpty = " ".repeat(gutterWidth);
44
+ const length = diag.length || 1;
45
+ const underline = "~".repeat(length);
46
+ output += ` ${gutterEmpty}${" ".repeat(col)}${RED}${underline}${RESET}`;
47
+ return output;
48
+ }
6
49
  function getCompiler(options) {
7
50
  if (compilerInstance) {
8
51
  return compilerInstance;
@@ -57,9 +100,26 @@ function angularCompilerVitePlugin(options) {
57
100
  compiler = getCompiler(options);
58
101
  }
59
102
  if (id.includes("node_modules")) {
103
+ if (id.includes("@angular") && code.includes("\u0275\u0275ngDeclare")) {
104
+ const cleanId2 = id.split("?")[0];
105
+ if (cleanId2.endsWith(".mjs") || cleanId2.endsWith(".js")) {
106
+ try {
107
+ const result = compiler.linkFile(id, code);
108
+ if (result.startsWith("/* Linker Error")) {
109
+ if (debug) console.error(`[Linker Error] ${id}: ${result}`);
110
+ return null;
111
+ }
112
+ return { code: result, map: null };
113
+ } catch (e) {
114
+ if (debug) console.error(`Linker failed for ${id}:`, e);
115
+ return null;
116
+ }
117
+ }
118
+ }
60
119
  return null;
61
120
  }
62
- if (!id.endsWith(".ts") || id.endsWith(".d.ts")) {
121
+ const cleanId = id.split("?")[0];
122
+ if (!cleanId.endsWith(".ts") || cleanId.endsWith(".d.ts")) {
63
123
  return null;
64
124
  }
65
125
  if (debug) {
@@ -67,15 +127,21 @@ function angularCompilerVitePlugin(options) {
67
127
  }
68
128
  try {
69
129
  const result = compiler.compile(id, code);
70
- if (result.startsWith("/* Error")) {
130
+ const { code: compiledCode, diagnostics } = result;
131
+ if (compiledCode.startsWith("/* Error")) {
71
132
  console.error(`[Angular Compiler Error] ${id}:
72
- ${result}`);
133
+ ${compiledCode}`);
73
134
  throw new Error(`Rust Compilation Failed for ${id}`);
74
135
  }
136
+ if (diagnostics && diagnostics.length > 0) {
137
+ diagnostics.forEach((diag) => {
138
+ console.warn(formatDiagnostic(diag, code));
139
+ });
140
+ }
75
141
  if (debug) {
76
142
  console.log(`[Angular Compiler] Successfully compiled: ${id}`);
77
143
  }
78
- return { code: result, map: null };
144
+ return { code: compiledCode, map: null };
79
145
  } catch (e) {
80
146
  console.error(`[Angular Compiler Failed] ${id}:`, e);
81
147
  throw e;