@analogjs/vite-plugin-angular 3.0.0-alpha.6 → 3.0.0-alpha.60

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 (200) 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 +51 -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 +178 -70
  24. package/src/lib/angular-vite-plugin.js +1261 -1085
  25. package/src/lib/angular-vite-plugin.js.map +1 -1
  26. package/src/lib/angular-vitest-plugin.d.ts +26 -17
  27. package/src/lib/angular-vitest-plugin.js +105 -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 +488 -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 +31 -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 +50 -0
  41. package/src/lib/compiler/compile.js +814 -0
  42. package/src/lib/compiler/compile.js.map +1 -0
  43. package/src/lib/compiler/constants.d.ts +24 -0
  44. package/src/lib/compiler/constants.js +59 -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 +45 -0
  53. package/src/lib/compiler/dts-reader.js +395 -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 +8 -0
  59. package/src/lib/compiler/index.js +8 -0
  60. package/src/lib/compiler/jit-metadata.d.ts +14 -0
  61. package/src/lib/compiler/jit-metadata.js +168 -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 +204 -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 +36 -0
  70. package/src/lib/compiler/metadata.js +710 -0
  71. package/src/lib/compiler/metadata.js.map +1 -0
  72. package/src/lib/compiler/registry.d.ts +56 -0
  73. package/src/lib/compiler/registry.js +176 -0
  74. package/src/lib/compiler/registry.js.map +1 -0
  75. package/src/lib/compiler/resource-inliner.d.ts +43 -0
  76. package/src/lib/compiler/resource-inliner.js +230 -0
  77. package/src/lib/compiler/resource-inliner.js.map +1 -0
  78. package/src/lib/compiler/style-ast.d.ts +9 -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 +28 -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 +40 -0
  87. package/src/lib/compiler/utils.js +76 -0
  88. package/src/lib/compiler/utils.js.map +1 -0
  89. package/src/lib/compiler-plugin.d.ts +13 -12
  90. package/src/lib/compiler-plugin.js +40 -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 +152 -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 +414 -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 -63
  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 +35 -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 +74 -0
  124. package/src/lib/stylesheet-registry.js +174 -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 +62 -0
  139. package/src/lib/utils/compilation-shared.js +138 -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/css-extension-resolver.d.ts +32 -0
  143. package/src/lib/utils/css-extension-resolver.js +73 -0
  144. package/src/lib/utils/css-extension-resolver.js.map +1 -0
  145. package/src/lib/utils/debug-harness.d.ts +23 -0
  146. package/src/lib/utils/debug-harness.js +88 -0
  147. package/src/lib/utils/debug-harness.js.map +1 -0
  148. package/src/lib/utils/debug-log-file.d.ts +5 -0
  149. package/src/lib/utils/debug-log-file.js +56 -0
  150. package/src/lib/utils/debug-log-file.js.map +1 -0
  151. package/src/lib/utils/debug.d.ts +28 -0
  152. package/src/lib/utils/debug.js +39 -0
  153. package/src/lib/utils/debug.js.map +1 -0
  154. package/src/lib/utils/devkit.d.ts +6 -6
  155. package/src/lib/utils/devkit.js +34 -38
  156. package/src/lib/utils/devkit.js.map +1 -1
  157. package/src/lib/utils/hmr-candidates.d.ts +28 -28
  158. package/src/lib/utils/plugin-config.d.ts +34 -0
  159. package/src/lib/utils/plugin-config.js +71 -0
  160. package/src/lib/utils/plugin-config.js.map +1 -0
  161. package/src/lib/utils/rolldown.d.ts +2 -0
  162. package/src/lib/utils/rolldown.js +12 -0
  163. package/src/lib/utils/rolldown.js.map +1 -0
  164. package/src/lib/utils/safe-module-paths.d.ts +16 -0
  165. package/src/lib/utils/safe-module-paths.js +29 -0
  166. package/src/lib/utils/safe-module-paths.js.map +1 -0
  167. package/src/lib/utils/source-file-cache.d.ts +8 -15
  168. package/src/lib/utils/source-file-cache.js +35 -37
  169. package/src/lib/utils/source-file-cache.js.map +1 -1
  170. package/src/lib/utils/tailwind-reference.d.ts +12 -0
  171. package/src/lib/utils/tailwind-reference.js +99 -0
  172. package/src/lib/utils/tailwind-reference.js.map +1 -0
  173. package/src/lib/utils/transform-cache.d.ts +43 -0
  174. package/src/lib/utils/transform-cache.js +97 -0
  175. package/src/lib/utils/transform-cache.js.map +1 -0
  176. package/src/lib/utils/tsconfig-resolver.d.ts +28 -0
  177. package/src/lib/utils/tsconfig-resolver.js +191 -0
  178. package/src/lib/utils/tsconfig-resolver.js.map +1 -0
  179. package/src/lib/utils/virtual-ids.d.ts +4 -0
  180. package/src/lib/utils/virtual-ids.js +23 -0
  181. package/src/lib/utils/virtual-ids.js.map +1 -0
  182. package/src/lib/utils/virtual-resources.d.ts +19 -0
  183. package/src/lib/utils/virtual-resources.js +38 -0
  184. package/src/lib/utils/virtual-resources.js.map +1 -0
  185. package/src/lib/virtual-modules-plugin.d.ts +5 -0
  186. package/src/lib/virtual-modules-plugin.js +23 -0
  187. package/src/lib/virtual-modules-plugin.js.map +1 -0
  188. package/src/test-setup.d.ts +2 -0
  189. package/setup-vitest.d.ts +0 -4
  190. package/setup-vitest.js +0 -215
  191. package/setup-vitest.js.map +0 -1
  192. package/src/lib/models.js +0 -1
  193. package/src/lib/models.js.map +0 -1
  194. package/src/lib/tools/README.md +0 -3
  195. package/src/lib/tools/src/index.d.ts +0 -0
  196. package/src/lib/tools/src/index.js.map +0 -1
  197. package/src/lib/utils/compiler-plugin-options.js +0 -1
  198. package/src/lib/utils/compiler-plugin-options.js.map +0 -1
  199. package/src/lib/utils/hmr-candidates.js +0 -272
  200. package/src/lib/utils/hmr-candidates.js.map +0 -1
@@ -0,0 +1 @@
1
+ {"version":3,"file":"type-elision.js","names":[],"sources":["../../../../src/lib/compiler/type-elision.ts"],"sourcesContent":["import MagicString from 'magic-string';\nimport { parseSync } from 'oxc-parser';\n\n// ── Type-only import elision via OXC AST ────────────────────────────────\n\n/**\n * AST property keys that represent type-only positions in TypeScript.\n * Identifiers found only under these keys are never emitted as runtime values.\n */\nconst TYPE_POSITION_KEYS = new Set([\n 'typeAnnotation',\n 'typeParameters',\n 'superTypeParameters',\n 'implements',\n 'returnType',\n 'typeArguments',\n]);\n\n/**\n * AST node types that represent type-level constructs.\n * Any identifier nested inside one of these nodes is in a type position.\n */\nconst TYPE_NODE_TYPES = new Set([\n 'TSTypeAnnotation',\n 'TSTypeReference',\n 'TSTypeParameterInstantiation',\n 'TSTypeParameterDeclaration',\n 'TSInterfaceDeclaration',\n 'TSTypeAliasDeclaration',\n 'TSAsExpression',\n 'TSSatisfiesExpression',\n 'TSUnionType',\n 'TSIntersectionType',\n 'TSArrayType',\n 'TSTupleType',\n 'TSFunctionType',\n 'TSConstructorType',\n 'TSMappedType',\n 'TSConditionalType',\n 'TSIndexedAccessType',\n 'TSTypeQuery',\n 'TSTypeLiteral',\n 'TSQualifiedName',\n 'TSInterfaceBody',\n]);\n\n/**\n * Internal helper: parse code and return both the AST and the set of\n * type-only imported names. Avoids double-parsing when both are needed.\n */\nfunction analyzeTypeOnlyImports(\n code: string,\n program?: ReturnType<typeof parseSync>['program'],\n): {\n ast: any;\n typeOnlyNames: Set<string>;\n} {\n const ast = program ?? parseSync('file.ts', code).program;\n\n // Step 1 – collect all value-imported names (skip `import type` / `{ type X }`)\n // Namespace imports (`import * as ns`) are intentionally skipped — they are\n // always value imports in TypeScript and cannot be type-only at the\n // declaration level.\n const importedNames = new Set<string>();\n for (const node of (ast as any).body) {\n if (node.type !== 'ImportDeclaration') continue;\n if (node.importKind === 'type') continue; // already type-only\n for (const spec of node.specifiers ?? []) {\n if (spec.importKind === 'type') continue; // already type-only\n importedNames.add(spec.local.name);\n }\n }\n if (importedNames.size === 0) return { ast, typeOnlyNames: new Set() };\n\n // Step 2 – walk AST and collect names referenced in value positions\n const valueReferenced = new Set<string>();\n\n // Pre-pass: constructor parameter types of decorated classes are DI tokens\n // and must be preserved as runtime values, even though they appear in\n // type-annotation positions. Without this, `constructor(svc: MyService)`\n // would erase the `MyService` import and `extractConstructorDeps` would\n // emit `ɵɵinvalidFactory()`.\n collectConstructorDiTokens(ast, importedNames, valueReferenced);\n\n function walk(node: any, inTypePosition: boolean): void {\n if (!node || typeof node !== 'object') return;\n if (Array.isArray(node)) {\n for (const item of node) walk(item, inTypePosition);\n return;\n }\n\n // Short-circuit: if we found every imported name in a value position, stop\n if (valueReferenced.size === importedNames.size) return;\n\n // If this node's type itself marks a type construct, everything below is type-only\n // Exception: TSAsExpression/TSSatisfiesExpression have a value `expression`\n // child that is NOT in a type position — only the type annotation is.\n if (!inTypePosition && TYPE_NODE_TYPES.has(node.type)) {\n if (\n node.type === 'TSAsExpression' ||\n node.type === 'TSSatisfiesExpression'\n ) {\n // Walk the expression child in value context, type annotation in type context\n walk(node.expression, false);\n walk(node.typeAnnotation, true);\n return;\n }\n inTypePosition = true;\n }\n\n // Type-only exports: `export type { Foo }` or `export { type Foo }`\n // Identifiers inside type-only export specifiers are not value references.\n if (\n !inTypePosition &&\n node.type === 'ExportNamedDeclaration' &&\n !node.source\n ) {\n // Walk the declaration (if any) in value context\n if (node.declaration) walk(node.declaration, false);\n // Walk each specifier, skipping type-only ones\n for (const spec of node.specifiers ?? []) {\n if (node.exportKind === 'type' || spec.exportKind === 'type') continue;\n walk(spec, false);\n }\n return;\n }\n\n if (\n !inTypePosition &&\n node.type === 'Identifier' &&\n importedNames.has(node.name)\n ) {\n valueReferenced.add(node.name);\n return;\n }\n\n for (const key of Object.keys(node)) {\n if (\n key === 'type' ||\n key === 'start' ||\n key === 'end' ||\n key === 'range' ||\n key === 'loc'\n )\n continue;\n const isTypePos = inTypePosition || TYPE_POSITION_KEYS.has(key);\n walk(node[key], isTypePos);\n }\n }\n\n for (const node of (ast as any).body) {\n // Skip import declarations themselves – we already processed them\n if (node.type !== 'ImportDeclaration') {\n walk(node, false);\n }\n }\n\n // Step 3 – names that were imported but never value-referenced are type-only\n const typeOnly = new Set<string>();\n for (const name of importedNames) {\n if (!valueReferenced.has(name)) typeOnly.add(name);\n }\n return { ast, typeOnlyNames: typeOnly };\n}\n\n/**\n * Walk the program looking for decorated classes with constructors and add\n * the type names from constructor parameter annotations to `valueReferenced`.\n *\n * Constructor parameter types are TypeScript type positions, but for decorated\n * classes they double as runtime DI tokens — Angular's compiler reads them\n * via `compileFactoryFunction` to wire `ɵɵdirectiveInject(...)` calls. The\n * import of the type therefore must NOT be elided as type-only.\n */\nfunction collectConstructorDiTokens(\n ast: any,\n importedNames: Set<string>,\n valueReferenced: Set<string>,\n): void {\n for (const stmt of (ast as any).body || []) {\n const classNode =\n stmt.type === 'ExportNamedDeclaration' ||\n stmt.type === 'ExportDefaultDeclaration'\n ? (stmt as any).declaration\n : stmt;\n if (\n !classNode ||\n (classNode.type !== 'ClassDeclaration' &&\n classNode.type !== 'ClassExpression')\n ) {\n continue;\n }\n if (!classNode.decorators?.length) continue;\n\n const ctor = (classNode.body?.body || []).find(\n (m: any) => m.type === 'MethodDefinition' && m.kind === 'constructor',\n );\n if (!ctor) continue;\n\n const params: any[] = ctor.value?.params?.items || ctor.value?.params || [];\n for (const param of params) {\n const actualParam =\n param.type === 'TSParameterProperty' ? param.parameter : param;\n const typeAnn =\n actualParam?.typeAnnotation?.typeAnnotation ??\n param?.typeAnnotation?.typeAnnotation;\n if (!typeAnn) continue;\n collectTypeReferenceNames(typeAnn, importedNames, valueReferenced);\n }\n }\n}\n\n/**\n * Recursively extract identifier names from a TS type expression and mark\n * any that match an imported name as value-referenced.\n */\nfunction collectTypeReferenceNames(\n typeNode: any,\n importedNames: Set<string>,\n valueReferenced: Set<string>,\n): void {\n if (!typeNode || typeof typeNode !== 'object') return;\n if (typeNode.type === 'TSTypeReference' && typeNode.typeName) {\n const name = typeNode.typeName.name;\n if (name && importedNames.has(name)) {\n valueReferenced.add(name);\n }\n // Walk type arguments too (e.g. Foo<Bar>)\n if (typeNode.typeArguments) {\n collectTypeReferenceNames(\n typeNode.typeArguments,\n importedNames,\n valueReferenced,\n );\n }\n } else if (\n typeNode.type === 'TSUnionType' ||\n typeNode.type === 'TSIntersectionType'\n ) {\n for (const t of typeNode.types || []) {\n collectTypeReferenceNames(t, importedNames, valueReferenced);\n }\n } else if (Array.isArray(typeNode)) {\n for (const t of typeNode) {\n collectTypeReferenceNames(t, importedNames, valueReferenced);\n }\n } else if (typeNode.params) {\n // TSTypeParameterInstantiation\n for (const t of typeNode.params) {\n collectTypeReferenceNames(t, importedNames, valueReferenced);\n }\n }\n}\n\n/**\n * Analyse compiled TypeScript source and return the set of imported names\n * that are only referenced in type positions (type annotations, implements\n * clauses, generics, etc.) and can safely be elided.\n *\n * Uses oxc-parser for fast, Rust-based AST analysis — no type-checker needed.\n */\nexport function detectTypeOnlyImportNames(\n code: string,\n program?: ReturnType<typeof parseSync>['program'],\n): Set<string> {\n return analyzeTypeOnlyImports(code, program).typeOnlyNames;\n}\n\n/**\n * Apply import elision edits to a MagicString instance using positions from\n * a parsed AST. Shared logic for both the string-based and MagicString APIs.\n */\nfunction applyElisionEdits(\n ms: MagicString,\n ast: any,\n src: string,\n typeOnlyNames: Set<string>,\n): boolean {\n let edited = false;\n\n for (const node of (ast as any).body) {\n if (node.type !== 'ImportDeclaration') continue;\n if (node.importKind === 'type') continue;\n\n const allSpecs = node.specifiers ?? [];\n\n // Separate default and named specifiers\n const defaultSpec = allSpecs.find(\n (s: any) => s.type === 'ImportDefaultSpecifier',\n );\n const namedSpecs = allSpecs.filter(\n (s: any) => s.type === 'ImportSpecifier' && s.importKind !== 'type',\n );\n\n const elideDefault =\n defaultSpec && typeOnlyNames.has(defaultSpec.local.name);\n const keptNamed = namedSpecs.filter(\n (s: any) => !typeOnlyNames.has(s.local.name),\n );\n const removingNamed = namedSpecs.length - keptNamed.length;\n\n // Nothing to elide from this declaration\n if (!elideDefault && removingNamed === 0) continue;\n\n // Find the end of the declaration including trailing newline\n let declEnd = node.end;\n while (\n declEnd < src.length &&\n (src[declEnd] === '\\n' || src[declEnd] === '\\r')\n )\n declEnd++;\n\n const keepDefault = defaultSpec && !elideDefault;\n const hasKeptNamed = keptNamed.length > 0;\n\n if (!keepDefault && !hasKeptNamed) {\n // Remove entire import declaration\n ms.remove(node.start, declEnd);\n edited = true;\n } else {\n // Rebuild with only the kept specifiers\n const parts: string[] = [];\n if (keepDefault) parts.push(defaultSpec.local.name);\n if (hasKeptNamed) {\n const namedList = keptNamed.map((s: any) => {\n const imported = s.imported?.name ?? s.local.name;\n return imported === s.local.name\n ? s.local.name\n : `${imported} as ${s.local.name}`;\n });\n parts.push(`{ ${namedList.join(', ')} }`);\n }\n const source = node.source.value;\n const quote = src[node.source.start]; // preserve original quote style\n ms.overwrite(\n node.start,\n node.end,\n `import ${parts.join(', ')} from ${quote}${source}${quote};`,\n );\n edited = true;\n }\n }\n\n return edited;\n}\n\n/**\n * Elide import specifiers (or entire import declarations) for names that are\n * only used in type positions. Operates on the compiler's TypeScript output\n * (before OXC strips remaining TS syntax).\n *\n * Returns the modified source code, or the original if nothing was elided.\n */\nexport function elideTypeOnlyImports(code: string): string {\n const { ast, typeOnlyNames } = analyzeTypeOnlyImports(code);\n if (typeOnlyNames.size === 0) return code;\n\n const ms = new MagicString(code);\n const edited = applyElisionEdits(ms, ast, code, typeOnlyNames);\n return edited ? ms.toString() : code;\n}\n\n/**\n * Elide type-only imports directly on a MagicString instance, so that\n * subsequent `ms.generateMap()` calls produce an accurate sourcemap.\n *\n * Detects type-only names from `ms.toString()` (the fully-mutated code),\n * but reads import positions from `ms.original` (the coordinate system\n * MagicString expects). `originalProgram`, when provided, must be a parse\n * of `ms.original` — never of the mutated text.\n */\nexport function elideTypeOnlyImportsMagicString(\n ms: MagicString,\n originalProgram?: ReturnType<typeof parseSync>['program'],\n): void {\n const typeOnlyNames = detectTypeOnlyImportNames(ms.toString());\n if (typeOnlyNames.size === 0) return;\n\n // Parse the original source to get positions in MagicString's coordinate system\n const ast = originalProgram ?? parseSync('file.ts', ms.original).program;\n applyElisionEdits(ms, ast, ms.original, typeOnlyNames);\n}\n"],"mappings":"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"}
@@ -0,0 +1,40 @@
1
+ import * as ts from "typescript";
2
+ /** Collect type-only imported names: `import type { X }` and `import { type X }`. */
3
+ export declare function collectTypeOnlyImports(sf: ts.SourceFile): Set<string>;
4
+ /** Recursively find all class declarations in a source file, including nested scopes. */
5
+ export declare function findAllClasses(sf: ts.SourceFile): ts.ClassDeclaration[];
6
+ /** Unwrap forwardRef(() => X) to X. Returns the original node if not a forwardRef call. */
7
+ export declare function unwrapForwardRef(node: ts.Expression): ts.Expression;
8
+ /** Unwrap forwardRef(() => X) to X for OXC AST nodes. Returns the original node if not a forwardRef call. */
9
+ export declare function unwrapForwardRefOxc(node: any): any;
10
+ /**
11
+ * Resolve the module specifier to use for a synthetic import of a registry
12
+ * declaration referenced from `currentFileName`.
13
+ *
14
+ * Order of preference:
15
+ * 1. `entry.sourcePackage` — external packages scanned from `.d.ts` resolve
16
+ * via their package name (proper barrel exports).
17
+ * 2. A relative path derived from `currentFileName` to `entry.fileName` — for
18
+ * local workspace classes scanned from real source files. This is what
19
+ * NgModule/tuple export expansion must use: the class lives in its own
20
+ * file, not the module/barrel file that re-exports it, so importing from
21
+ * the module specifier fails with
22
+ * `"X" is not exported by ".../the.module.ts"`.
23
+ * 3. `fallbackSpecifier` — the import path of the module/tuple itself, used
24
+ * for `.d.ts` entries (whose file path is not a usable import target) and
25
+ * when the registry has no file location for the class.
26
+ *
27
+ * Returns `undefined` when the class is declared in `currentFileName` itself
28
+ * (already in scope — no synthetic import needed).
29
+ */
30
+ export declare function resolveSyntheticImportSpecifier(currentFileName: string, entry: {
31
+ sourcePackage?: string;
32
+ fileName?: string;
33
+ }, fallbackSpecifier: string | undefined): string | undefined;
34
+ /**
35
+ * Derive a relative module specifier from `fromFile` to `toFile`, suitable for
36
+ * a synthetic `import { … } from '…'` statement: strips the file extension,
37
+ * normalizes to POSIX separators, and ensures an explicit `./` prefix.
38
+ */
39
+ export declare function deriveRelativeImportPath(fromFile: string, toFile: string): string;
40
+ export { ANGULAR_DECORATORS } from "./constants.js";
@@ -0,0 +1,76 @@
1
+ import "./constants.js";
2
+ import * as path$1 from "node:path";
3
+ import * as ts from "typescript";
4
+ //#region packages/vite-plugin-angular/src/lib/compiler/utils.ts
5
+ /** Recursively find all class declarations in a source file, including nested scopes. */
6
+ function findAllClasses(sf) {
7
+ const result = [];
8
+ function walk(node) {
9
+ if (ts.isClassDeclaration(node)) result.push(node);
10
+ ts.forEachChild(node, walk);
11
+ }
12
+ walk(sf);
13
+ return result;
14
+ }
15
+ /** Unwrap forwardRef(() => X) to X for OXC AST nodes. Returns the original node if not a forwardRef call. */
16
+ function unwrapForwardRefOxc(node) {
17
+ if (node?.type === "CallExpression" && node.callee?.type === "Identifier" && node.callee.name === "forwardRef") {
18
+ const arg = node.arguments?.[0];
19
+ if (arg?.type === "ArrowFunctionExpression") if (arg.body?.type === "FunctionBody" || arg.body?.type === "BlockStatement") {
20
+ const stmt = (arg.body.statements || arg.body.body || [])[0];
21
+ if (stmt?.type === "ReturnStatement" && stmt.argument) return stmt.argument;
22
+ } else return arg.body;
23
+ if (arg?.type === "FunctionExpression") {
24
+ const stmts = arg.body?.statements || arg.body?.body || [];
25
+ if (stmts.length === 1) {
26
+ const stmt = stmts[0];
27
+ if (stmt?.type === "ReturnStatement" && stmt.argument) return stmt.argument;
28
+ }
29
+ }
30
+ }
31
+ return node;
32
+ }
33
+ /**
34
+ * Resolve the module specifier to use for a synthetic import of a registry
35
+ * declaration referenced from `currentFileName`.
36
+ *
37
+ * Order of preference:
38
+ * 1. `entry.sourcePackage` — external packages scanned from `.d.ts` resolve
39
+ * via their package name (proper barrel exports).
40
+ * 2. A relative path derived from `currentFileName` to `entry.fileName` — for
41
+ * local workspace classes scanned from real source files. This is what
42
+ * NgModule/tuple export expansion must use: the class lives in its own
43
+ * file, not the module/barrel file that re-exports it, so importing from
44
+ * the module specifier fails with
45
+ * `"X" is not exported by ".../the.module.ts"`.
46
+ * 3. `fallbackSpecifier` — the import path of the module/tuple itself, used
47
+ * for `.d.ts` entries (whose file path is not a usable import target) and
48
+ * when the registry has no file location for the class.
49
+ *
50
+ * Returns `undefined` when the class is declared in `currentFileName` itself
51
+ * (already in scope — no synthetic import needed).
52
+ */
53
+ function resolveSyntheticImportSpecifier(currentFileName, entry, fallbackSpecifier) {
54
+ if (entry.sourcePackage) return entry.sourcePackage;
55
+ if (entry.fileName && !entry.fileName.endsWith(".d.ts")) {
56
+ if (entry.fileName === currentFileName) return void 0;
57
+ return deriveRelativeImportPath(currentFileName, entry.fileName);
58
+ }
59
+ return fallbackSpecifier;
60
+ }
61
+ /**
62
+ * Derive a relative module specifier from `fromFile` to `toFile`, suitable for
63
+ * a synthetic `import { … } from '…'` statement: strips the file extension,
64
+ * normalizes to POSIX separators, and ensures an explicit `./` prefix.
65
+ */
66
+ function deriveRelativeImportPath(fromFile, toFile) {
67
+ let rel = path$1.relative(path$1.dirname(fromFile), toFile);
68
+ rel = rel.replace(/\.[cm]?[jt]sx?$/, "");
69
+ rel = rel.split(path$1.sep).join("/");
70
+ if (!rel.startsWith(".")) rel = "./" + rel;
71
+ return rel;
72
+ }
73
+ //#endregion
74
+ export { findAllClasses, resolveSyntheticImportSpecifier, unwrapForwardRefOxc };
75
+
76
+ //# sourceMappingURL=utils.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"utils.js","names":[],"sources":["../../../../src/lib/compiler/utils.ts"],"sourcesContent":["import * as ts from 'typescript';\nimport * as path from 'node:path';\n\n/** Collect type-only imported names: `import type { X }` and `import { type X }`. */\nexport function collectTypeOnlyImports(sf: ts.SourceFile): Set<string> {\n const result = new Set<string>();\n for (const stmt of sf.statements) {\n if (!ts.isImportDeclaration(stmt) || !stmt.importClause) continue;\n const clause = stmt.importClause;\n if (clause.isTypeOnly) {\n if (clause.namedBindings && ts.isNamedImports(clause.namedBindings)) {\n for (const el of clause.namedBindings.elements)\n result.add(el.name.text);\n }\n if (clause.name) result.add(clause.name.text);\n } else if (\n clause.namedBindings &&\n ts.isNamedImports(clause.namedBindings)\n ) {\n for (const el of clause.namedBindings.elements) {\n if (el.isTypeOnly) result.add(el.name.text);\n }\n }\n }\n return result;\n}\n\n/** Recursively find all class declarations in a source file, including nested scopes. */\nexport function findAllClasses(sf: ts.SourceFile): ts.ClassDeclaration[] {\n const result: ts.ClassDeclaration[] = [];\n function walk(node: ts.Node) {\n if (ts.isClassDeclaration(node)) result.push(node);\n ts.forEachChild(node, walk);\n }\n walk(sf);\n return result;\n}\n\n/** Unwrap forwardRef(() => X) to X. Returns the original node if not a forwardRef call. */\nexport function unwrapForwardRef(node: ts.Expression): ts.Expression {\n if (\n ts.isCallExpression(node) &&\n ts.isIdentifier(node.expression) &&\n node.expression.text === 'forwardRef'\n ) {\n const arg = node.arguments[0];\n if (arg && ts.isArrowFunction(arg)) {\n if (ts.isBlock(arg.body)) {\n const stmt = arg.body.statements[0];\n if (stmt && ts.isReturnStatement(stmt) && stmt.expression)\n return stmt.expression;\n } else {\n return arg.body;\n }\n }\n if (\n arg &&\n ts.isFunctionExpression(arg) &&\n arg.body.statements.length === 1\n ) {\n const stmt = arg.body.statements[0];\n if (ts.isReturnStatement(stmt) && stmt.expression) return stmt.expression;\n }\n }\n return node;\n}\n\n/** Unwrap forwardRef(() => X) to X for OXC AST nodes. Returns the original node if not a forwardRef call. */\nexport function unwrapForwardRefOxc(node: any): any {\n if (\n node?.type === 'CallExpression' &&\n node.callee?.type === 'Identifier' &&\n node.callee.name === 'forwardRef'\n ) {\n const arg = node.arguments?.[0];\n if (arg?.type === 'ArrowFunctionExpression') {\n if (\n arg.body?.type === 'FunctionBody' ||\n arg.body?.type === 'BlockStatement'\n ) {\n const stmts = arg.body.statements || arg.body.body || [];\n const stmt = stmts[0];\n if (stmt?.type === 'ReturnStatement' && stmt.argument)\n return stmt.argument;\n } else {\n // Expression body: forwardRef(() => X)\n return arg.body;\n }\n }\n if (arg?.type === 'FunctionExpression') {\n const stmts = arg.body?.statements || arg.body?.body || [];\n if (stmts.length === 1) {\n const stmt = stmts[0];\n if (stmt?.type === 'ReturnStatement' && stmt.argument)\n return stmt.argument;\n }\n }\n }\n return node;\n}\n\n/**\n * Resolve the module specifier to use for a synthetic import of a registry\n * declaration referenced from `currentFileName`.\n *\n * Order of preference:\n * 1. `entry.sourcePackage` — external packages scanned from `.d.ts` resolve\n * via their package name (proper barrel exports).\n * 2. A relative path derived from `currentFileName` to `entry.fileName` — for\n * local workspace classes scanned from real source files. This is what\n * NgModule/tuple export expansion must use: the class lives in its own\n * file, not the module/barrel file that re-exports it, so importing from\n * the module specifier fails with\n * `\"X\" is not exported by \".../the.module.ts\"`.\n * 3. `fallbackSpecifier` — the import path of the module/tuple itself, used\n * for `.d.ts` entries (whose file path is not a usable import target) and\n * when the registry has no file location for the class.\n *\n * Returns `undefined` when the class is declared in `currentFileName` itself\n * (already in scope — no synthetic import needed).\n */\nexport function resolveSyntheticImportSpecifier(\n currentFileName: string,\n entry: { sourcePackage?: string; fileName?: string },\n fallbackSpecifier: string | undefined,\n): string | undefined {\n if (entry.sourcePackage) return entry.sourcePackage;\n // `.d.ts` entries come from scanning external package type declarations;\n // their file path is not a usable relative import target, so defer to the\n // module/tuple specifier the consumer already imports from.\n if (entry.fileName && !entry.fileName.endsWith('.d.ts')) {\n if (entry.fileName === currentFileName) return undefined;\n return deriveRelativeImportPath(currentFileName, entry.fileName);\n }\n return fallbackSpecifier;\n}\n\n/**\n * Derive a relative module specifier from `fromFile` to `toFile`, suitable for\n * a synthetic `import { … } from '…'` statement: strips the file extension,\n * normalizes to POSIX separators, and ensures an explicit `./` prefix.\n */\nexport function deriveRelativeImportPath(\n fromFile: string,\n toFile: string,\n): string {\n let rel = path.relative(path.dirname(fromFile), toFile);\n rel = rel.replace(/\\.[cm]?[jt]sx?$/, '');\n rel = rel.split(path.sep).join('/');\n if (!rel.startsWith('.')) rel = './' + rel;\n return rel;\n}\n\nexport { ANGULAR_DECORATORS } from './constants.js';\n"],"mappings":";;;;;AA4BA,SAAgB,eAAe,IAA0C;CACvE,MAAM,SAAgC,EAAE;CACxC,SAAS,KAAK,MAAe;AAC3B,MAAI,GAAG,mBAAmB,KAAK,CAAE,QAAO,KAAK,KAAK;AAClD,KAAG,aAAa,MAAM,KAAK;;AAE7B,MAAK,GAAG;AACR,QAAO;;;AAiCT,SAAgB,oBAAoB,MAAgB;AAClD,KACE,MAAM,SAAS,oBACf,KAAK,QAAQ,SAAS,gBACtB,KAAK,OAAO,SAAS,cACrB;EACA,MAAM,MAAM,KAAK,YAAY;AAC7B,MAAI,KAAK,SAAS,0BAChB,KACE,IAAI,MAAM,SAAS,kBACnB,IAAI,MAAM,SAAS,kBACnB;GAEA,MAAM,QADQ,IAAI,KAAK,cAAc,IAAI,KAAK,QAAQ,EAAE,EACrC;AACnB,OAAI,MAAM,SAAS,qBAAqB,KAAK,SAC3C,QAAO,KAAK;QAGd,QAAO,IAAI;AAGf,MAAI,KAAK,SAAS,sBAAsB;GACtC,MAAM,QAAQ,IAAI,MAAM,cAAc,IAAI,MAAM,QAAQ,EAAE;AAC1D,OAAI,MAAM,WAAW,GAAG;IACtB,MAAM,OAAO,MAAM;AACnB,QAAI,MAAM,SAAS,qBAAqB,KAAK,SAC3C,QAAO,KAAK;;;;AAIpB,QAAO;;;;;;;;;;;;;;;;;;;;;;AAuBT,SAAgB,gCACd,iBACA,OACA,mBACoB;AACpB,KAAI,MAAM,cAAe,QAAO,MAAM;AAItC,KAAI,MAAM,YAAY,CAAC,MAAM,SAAS,SAAS,QAAQ,EAAE;AACvD,MAAI,MAAM,aAAa,gBAAiB,QAAO,KAAA;AAC/C,SAAO,yBAAyB,iBAAiB,MAAM,SAAS;;AAElE,QAAO;;;;;;;AAQT,SAAgB,yBACd,UACA,QACQ;CACR,IAAI,MAAM,OAAK,SAAS,OAAK,QAAQ,SAAS,EAAE,OAAO;AACvD,OAAM,IAAI,QAAQ,mBAAmB,GAAG;AACxC,OAAM,IAAI,MAAM,OAAK,IAAI,CAAC,KAAK,IAAI;AACnC,KAAI,CAAC,IAAI,WAAW,IAAI,CAAE,OAAM,OAAO;AACvC,QAAO"}
@@ -1,14 +1,15 @@
1
1
  /**
2
- * @license
3
- * Copyright Google LLC All Rights Reserved.
4
- *
5
- * Use of this source code is governed by an MIT-style license that can be
6
- * found in the LICENSE file at https://angular.dev/license
7
- */
8
- import type { DepOptimizationConfig, Rolldown } from 'vite';
9
- import { CompilerPluginOptions } from './utils/devkit.js';
10
- type EsbuildOptions = NonNullable<DepOptimizationConfig['esbuildOptions']>;
11
- type EsbuildPlugin = NonNullable<EsbuildOptions['plugins']>[number];
12
- export declare function createCompilerPlugin(pluginOptions: CompilerPluginOptions, isTest: boolean, closeTransformer: boolean): EsbuildPlugin;
13
- export declare function createRolldownCompilerPlugin(pluginOptions: CompilerPluginOptions): Rolldown.Plugin;
2
+ * @license
3
+ * Copyright Google LLC All Rights Reserved.
4
+ *
5
+ * Use of this source code is governed by an MIT-style license that can be
6
+ * found in the LICENSE file at https://angular.dev/license
7
+ */
8
+ import type { DepOptimizationConfig, Rolldown } from "vite";
9
+ import { CompilerPluginOptions } from "./utils/devkit.js";
10
+ import type { TransformCacheStore } from "./utils/transform-cache.js";
11
+ type EsbuildOptions = NonNullable<DepOptimizationConfig["esbuildOptions"]>;
12
+ type EsbuildPlugin = NonNullable<EsbuildOptions["plugins"]>[number];
13
+ export declare function createCompilerPlugin(pluginOptions: CompilerPluginOptions, isTest: boolean, closeTransformer: boolean, cache?: TransformCacheStore): EsbuildPlugin;
14
+ export declare function createRolldownCompilerPlugin(pluginOptions: CompilerPluginOptions, isTest: boolean, closeTransformer: boolean, cache?: TransformCacheStore): Rolldown.Plugin;
14
15
  export {};
@@ -1,47 +1,43 @@
1
- /**
2
- * @license
3
- * Copyright Google LLC All Rights Reserved.
4
- *
5
- * Use of this source code is governed by an MIT-style license that can be
6
- * found in the LICENSE file at https://angular.dev/license
7
- */
8
- import { JavaScriptTransformer, } from './utils/devkit.js';
9
- export function createCompilerPlugin(pluginOptions, isTest, closeTransformer) {
10
- const javascriptTransformer = new JavaScriptTransformer({ ...pluginOptions, jit: true }, 1);
11
- return {
12
- name: 'analogjs-angular-esbuild-deps-optimizer-plugin',
13
- async setup(build) {
14
- if (!isTest) {
15
- build.onLoad({ filter: /\.[cm]?js$/ }, async (args) => {
16
- const contents = await javascriptTransformer.transformFile(args.path);
17
- return {
18
- contents,
19
- loader: 'js',
20
- };
21
- });
22
- }
23
- if (closeTransformer) {
24
- build.onEnd(() => javascriptTransformer.close());
25
- }
26
- },
27
- };
1
+ import { jt } from "./utils/devkit.js";
2
+ //#region packages/vite-plugin-angular/src/lib/compiler-plugin.ts
3
+ function createCompilerPlugin(pluginOptions, isTest, closeTransformer, cache) {
4
+ const javascriptTransformer = new jt({
5
+ ...pluginOptions,
6
+ jit: true
7
+ }, 1, cache);
8
+ return {
9
+ name: "analogjs-angular-esbuild-deps-optimizer-plugin",
10
+ async setup(build) {
11
+ if (!isTest) build.onLoad({ filter: /\.[cm]?js$/ }, async (args) => {
12
+ return {
13
+ contents: await javascriptTransformer.transformFile(args.path),
14
+ loader: "js"
15
+ };
16
+ });
17
+ if (closeTransformer) build.onEnd(() => javascriptTransformer.close());
18
+ }
19
+ };
28
20
  }
29
- export function createRolldownCompilerPlugin(pluginOptions) {
30
- const javascriptTransformer = new JavaScriptTransformer({ ...pluginOptions, jit: true }, 1);
31
- return {
32
- name: 'analogjs-rolldown-deps-optimizer-plugin',
33
- load: {
34
- filter: {
35
- id: /\.[cm]?js$/,
36
- },
37
- async handler(id) {
38
- const contents = await javascriptTransformer.transformFile(id);
39
- return {
40
- code: Buffer.from(contents).toString('utf-8'),
41
- loader: 'js',
42
- };
43
- },
44
- },
45
- };
21
+ function createRolldownCompilerPlugin(pluginOptions, isTest, closeTransformer, cache) {
22
+ const javascriptTransformer = new jt({
23
+ ...pluginOptions,
24
+ jit: true
25
+ }, 1, cache);
26
+ const plugin = { name: "analogjs-rolldown-deps-optimizer-plugin" };
27
+ if (!isTest) plugin.load = {
28
+ filter: { id: /\.[cm]?js$/ },
29
+ async handler(id) {
30
+ const contents = await javascriptTransformer.transformFile(id);
31
+ return {
32
+ code: Buffer.from(contents).toString("utf-8"),
33
+ loader: "js"
34
+ };
35
+ }
36
+ };
37
+ if (closeTransformer) plugin.buildEnd = () => javascriptTransformer.close();
38
+ return plugin;
46
39
  }
40
+ //#endregion
41
+ export { createCompilerPlugin, createRolldownCompilerPlugin };
42
+
47
43
  //# sourceMappingURL=compiler-plugin.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"compiler-plugin.js","sourceRoot":"","sources":["../../../../../packages/vite-plugin-angular/src/lib/compiler-plugin.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAKH,OAAO,EAEL,qBAAqB,GACtB,MAAM,mBAAmB,CAAC;AAK3B,MAAM,UAAU,oBAAoB,CAClC,aAAoC,EACpC,MAAe,EACf,gBAAyB;IAEzB,MAAM,qBAAqB,GAAG,IAAI,qBAAqB,CACrD,EAAE,GAAG,aAAa,EAAE,GAAG,EAAE,IAAI,EAAE,EAC/B,CAAC,CACF,CAAC;IAEF,OAAO;QACL,IAAI,EAAE,gDAAgD;QACtD,KAAK,CAAC,KAAK,CAAC,KAAkB;YAC5B,IAAI,CAAC,MAAM,EAAE,CAAC;gBACZ,KAAK,CAAC,MAAM,CAAC,EAAE,MAAM,EAAE,YAAY,EAAE,EAAE,KAAK,EAAE,IAAI,EAAE,EAAE;oBACpD,MAAM,QAAQ,GAAG,MAAM,qBAAqB,CAAC,aAAa,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;oBAEtE,OAAO;wBACL,QAAQ;wBACR,MAAM,EAAE,IAAI;qBACb,CAAC;gBACJ,CAAC,CAAC,CAAC;YACL,CAAC;YAED,IAAI,gBAAgB,EAAE,CAAC;gBACrB,KAAK,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,qBAAqB,CAAC,KAAK,EAAE,CAAC,CAAC;YACnD,CAAC;QACH,CAAC;KACF,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,4BAA4B,CAC1C,aAAoC;IAEpC,MAAM,qBAAqB,GAAG,IAAI,qBAAqB,CACrD,EAAE,GAAG,aAAa,EAAE,GAAG,EAAE,IAAI,EAAE,EAC/B,CAAC,CACF,CAAC;IACF,OAAO;QACL,IAAI,EAAE,yCAAyC;QAC/C,IAAI,EAAE;YACJ,MAAM,EAAE;gBACN,EAAE,EAAE,YAAY;aACjB;YACD,KAAK,CAAC,OAAO,CAAC,EAAE;gBACd,MAAM,QAAQ,GAAG,MAAM,qBAAqB,CAAC,aAAa,CAAC,EAAE,CAAC,CAAC;gBAE/D,OAAO;oBACL,IAAI,EAAE,MAAM,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,QAAQ,CAAC,OAAO,CAAC;oBAC7C,MAAM,EAAE,IAAI;iBACN,CAAC;YACX,CAAC;SACF;KACF,CAAC;AACJ,CAAC"}
1
+ {"version":3,"file":"compiler-plugin.js","names":[],"sources":["../../../src/lib/compiler-plugin.ts"],"sourcesContent":["/**\n * @license\n * Copyright Google LLC All Rights Reserved.\n *\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://angular.dev/license\n */\n\nimport type { DepOptimizationConfig, Rolldown } from 'vite';\nimport type { PluginBuild } from 'esbuild';\n\nimport {\n CompilerPluginOptions,\n JavaScriptTransformer,\n} from './utils/devkit.js';\nimport type { TransformCacheStore } from './utils/transform-cache.js';\n\ntype EsbuildOptions = NonNullable<DepOptimizationConfig['esbuildOptions']>;\ntype EsbuildPlugin = NonNullable<EsbuildOptions['plugins']>[number];\n\nexport function createCompilerPlugin(\n pluginOptions: CompilerPluginOptions,\n isTest: boolean,\n closeTransformer: boolean,\n cache?: TransformCacheStore,\n): EsbuildPlugin {\n const javascriptTransformer = new JavaScriptTransformer(\n { ...pluginOptions, jit: true },\n 1,\n cache,\n );\n\n return {\n name: 'analogjs-angular-esbuild-deps-optimizer-plugin',\n async setup(build: PluginBuild) {\n if (!isTest) {\n build.onLoad({ filter: /\\.[cm]?js$/ }, async (args) => {\n const contents = await javascriptTransformer.transformFile(args.path);\n\n return {\n contents,\n loader: 'js',\n };\n });\n }\n\n if (closeTransformer) {\n build.onEnd(() => javascriptTransformer.close());\n }\n },\n };\n}\n\nexport function createRolldownCompilerPlugin(\n pluginOptions: CompilerPluginOptions,\n isTest: boolean,\n closeTransformer: boolean,\n cache?: TransformCacheStore,\n): Rolldown.Plugin {\n const javascriptTransformer = new JavaScriptTransformer(\n { ...pluginOptions, jit: true },\n 1,\n cache,\n );\n\n const plugin: Rolldown.Plugin = {\n name: 'analogjs-rolldown-deps-optimizer-plugin',\n };\n\n if (!isTest) {\n plugin.load = {\n filter: {\n id: /\\.[cm]?js$/,\n },\n async handler(id) {\n const contents = await javascriptTransformer.transformFile(id);\n\n return {\n code: Buffer.from(contents).toString('utf-8'),\n loader: 'js',\n } as any;\n },\n };\n }\n\n if (closeTransformer) {\n plugin.buildEnd = () => javascriptTransformer.close();\n }\n\n return plugin;\n}\n"],"mappings":";;AAoBA,SAAgB,qBACd,eACA,QACA,kBACA,OACe;CACf,MAAM,wBAAwB,IAAI,GAChC;EAAE,GAAG;EAAe,KAAK;EAAM,EAC/B,GACA,MACD;AAED,QAAO;EACL,MAAM;EACN,MAAM,MAAM,OAAoB;AAC9B,OAAI,CAAC,OACH,OAAM,OAAO,EAAE,QAAQ,cAAc,EAAE,OAAO,SAAS;AAGrD,WAAO;KACL,UAHe,MAAM,sBAAsB,cAAc,KAAK,KAAK;KAInE,QAAQ;KACT;KACD;AAGJ,OAAI,iBACF,OAAM,YAAY,sBAAsB,OAAO,CAAC;;EAGrD;;AAGH,SAAgB,6BACd,eACA,QACA,kBACA,OACiB;CACjB,MAAM,wBAAwB,IAAI,GAChC;EAAE,GAAG;EAAe,KAAK;EAAM,EAC/B,GACA,MACD;CAED,MAAM,SAA0B,EAC9B,MAAM,2CACP;AAED,KAAI,CAAC,OACH,QAAO,OAAO;EACZ,QAAQ,EACN,IAAI,cACL;EACD,MAAM,QAAQ,IAAI;GAChB,MAAM,WAAW,MAAM,sBAAsB,cAAc,GAAG;AAE9D,UAAO;IACL,MAAM,OAAO,KAAK,SAAS,CAAC,SAAS,QAAQ;IAC7C,QAAQ;IACT;;EAEJ;AAGH,KAAI,iBACF,QAAO,iBAAiB,sBAAsB,OAAO;AAGvD,QAAO"}
@@ -1,10 +1,28 @@
1
- export declare class StyleUrlsResolver {
2
- private readonly styleUrlsCache;
3
- resolve(code: string, id: string): string[];
1
+ export interface AngularComponentMetadata {
2
+ className: string;
3
+ selector?: string;
4
+ styleUrls: string[];
5
+ templateUrls: string[];
6
+ inlineTemplates: string[];
4
7
  }
8
+ /**
9
+ * Extract Angular component identities from raw source code before Angular's
10
+ * compilation pipeline strips decorators. This is used for dev-time
11
+ * diagnostics such as duplicate selectors, duplicate component class names,
12
+ * selectorless shared components, and inline-template validation.
13
+ */
14
+ export declare function getAngularComponentMetadata(code: string): AngularComponentMetadata[];
15
+ /** Extract all `styleUrl` / `styleUrls` values from Angular component source. */
5
16
  export declare function getStyleUrls(code: string): string[];
17
+ /** Extract all `templateUrl` values from Angular component source. */
6
18
  export declare function getTemplateUrls(code: string): string[];
19
+ /** Extract inline `template` strings from Angular component source. */
20
+ export declare function getInlineTemplates(code: string): string[];
21
+ export declare class StyleUrlsResolver {
22
+ private readonly styleUrlsCache;
23
+ resolve(code: string, id: string): string[];
24
+ }
7
25
  export declare class TemplateUrlsResolver {
8
- private readonly templateUrlsCache;
9
- resolve(code: string, id: string): string[];
26
+ private readonly templateUrlsCache;
27
+ resolve(code: string, id: string): string[];
10
28
  }
@@ -1,69 +1,158 @@
1
- import { dirname, resolve } from 'node:path';
2
- import { Project, SyntaxKind, } from 'ts-morph';
3
- import { normalizePath } from 'vite';
4
- export class StyleUrlsResolver {
5
- // These resolvers may be called multiple times during the same
6
- // compilation for the same files. Caching is required because these
7
- // resolvers use synchronous system calls to the filesystem, which can
8
- // degrade performance when running compilations for multiple files.
9
- styleUrlsCache = new Map();
10
- resolve(code, id) {
11
- // Given the code is the following:
12
- // @Component({
13
- // styleUrls: [
14
- // './app.component.scss'
15
- // ]
16
- // })
17
- // The `matchedStyleUrls` would result in: `styleUrls: [\n './app.component.scss'\n ]`.
18
- const matchedStyleUrls = getStyleUrls(code);
19
- const entry = this.styleUrlsCache.get(id);
20
- // We're using `matchedStyleUrls` as a key because the code may be changing continuously,
21
- // resulting in the resolver being called multiple times. While the code changes, the
22
- // `styleUrls` may remain constant, which means we should always return the previously
23
- // resolved style URLs.
24
- if (entry && entry.matchedStyleUrls === matchedStyleUrls) {
25
- return entry.styleUrls;
26
- }
27
- const styleUrls = matchedStyleUrls.map((styleUrlPath) => {
28
- return `${styleUrlPath}|${normalizePath(resolve(dirname(id), styleUrlPath))}`;
29
- });
30
- this.styleUrlsCache.set(id, { styleUrls, matchedStyleUrls });
31
- return styleUrls;
32
- }
1
+ import { dirname, resolve } from "node:path";
2
+ import { normalizePath } from "vite";
3
+ import { parseSync } from "oxc-parser";
4
+ import { Visitor } from "rolldown/utils";
5
+ //#region packages/vite-plugin-angular/src/lib/component-resolvers.ts
6
+ /**
7
+ * Extracts a string value from an ESTree AST node.
8
+ *
9
+ * Handles three forms that Angular decorators may use:
10
+ * - `Literal` with a string value → `'./foo.css'` / `"./foo.css"`
11
+ * - `StringLiteral` (OXC-specific) → same representation
12
+ * - `TemplateLiteral` with zero expressions → `` `./foo.css` ``
13
+ *
14
+ * Uses `any` because OXC's AST mixes standard ESTree nodes with
15
+ * OXC-specific variants (e.g. `StringLiteral`), and the project's
16
+ * tsconfig enforces `noPropertyAccessFromIndexSignature`.
17
+ */
18
+ function getStringValue(node) {
19
+ if (!node) return void 0;
20
+ if (node.type === "Literal" && typeof node.value === "string") return node.value;
21
+ if (node.type === "StringLiteral") return node.value;
22
+ if (node.type === "TemplateLiteral" && node.expressions.length === 0 && node.quasis.length === 1) return node.quasis[0].value.cooked ?? node.quasis[0].value.raw;
33
23
  }
34
- function getTextByProperty(name, properties) {
35
- return properties
36
- .filter((property) => property.getName() === name)
37
- .map((property) => property.getInitializer()?.getText().replace(/['"`]/g, ''))
38
- .filter((url) => url !== undefined);
24
+ /**
25
+ * Parses TypeScript/JS source with OXC and collects `styleUrl`, `styleUrls`,
26
+ * and `templateUrl` property values from Angular `@Component()` decorators
27
+ * in a single AST pass.
28
+ *
29
+ * This replaces the previous ts-morph implementation — OXC parses natively
30
+ * via Rust NAPI bindings, avoiding the overhead of spinning up a full
31
+ * TypeScript `Project` for each file.
32
+ */
33
+ function collectComponentUrls(code) {
34
+ const { program } = parseSync("cmp.ts", code);
35
+ const styleUrls = [];
36
+ const templateUrls = [];
37
+ const inlineTemplates = [];
38
+ new Visitor({ ClassDeclaration(node) {
39
+ const decorators = node.decorators ?? [];
40
+ for (const decorator of decorators) {
41
+ const expression = decorator.expression;
42
+ if (expression?.type !== "CallExpression" || expression.callee?.type !== "Identifier" || expression.callee.name !== "Component") continue;
43
+ const componentArg = expression.arguments?.[0];
44
+ if (componentArg?.type !== "ObjectExpression") continue;
45
+ for (const property of componentArg.properties ?? []) {
46
+ if (property?.type !== "Property" || property.key?.type !== "Identifier") continue;
47
+ const name = property.key.name;
48
+ if (name === "styleUrls" && property.value?.type === "ArrayExpression") for (const el of property.value.elements) {
49
+ const val = getStringValue(el);
50
+ if (val !== void 0) styleUrls.push(val);
51
+ }
52
+ if (name === "styleUrl") {
53
+ const val = getStringValue(property.value);
54
+ if (val !== void 0) styleUrls.push(val);
55
+ }
56
+ if (name === "templateUrl") {
57
+ const val = getStringValue(property.value);
58
+ if (val !== void 0) templateUrls.push(val);
59
+ }
60
+ if (name === "template") {
61
+ const val = getStringValue(property.value);
62
+ if (val !== void 0) inlineTemplates.push(val);
63
+ }
64
+ }
65
+ }
66
+ } }).visit(program);
67
+ return {
68
+ styleUrls,
69
+ templateUrls,
70
+ inlineTemplates
71
+ };
39
72
  }
40
- export function getStyleUrls(code) {
41
- const project = new Project({ useInMemoryFileSystem: true });
42
- const sourceFile = project.createSourceFile('cmp.ts', code);
43
- const properties = sourceFile.getDescendantsOfKind(SyntaxKind.PropertyAssignment);
44
- const styleUrl = getTextByProperty('styleUrl', properties);
45
- const styleUrls = properties
46
- .filter((property) => property.getName() === 'styleUrls')
47
- .map((property) => property.getInitializer())
48
- .flatMap((array) => array.getElements().map((el) => el.getText().replace(/['"`]/g, '')));
49
- return [...styleUrls, ...styleUrl];
73
+ /**
74
+ * Extract Angular component identities from raw source code before Angular's
75
+ * compilation pipeline strips decorators. This is used for dev-time
76
+ * diagnostics such as duplicate selectors, duplicate component class names,
77
+ * selectorless shared components, and inline-template validation.
78
+ */
79
+ function getAngularComponentMetadata(code) {
80
+ const { program } = parseSync("cmp.ts", code);
81
+ const components = [];
82
+ new Visitor({ ClassDeclaration(node) {
83
+ const decorators = node.decorators ?? [];
84
+ for (const decorator of decorators) {
85
+ const expression = decorator.expression;
86
+ if (expression?.type !== "CallExpression" || expression.callee?.type !== "Identifier" || expression.callee.name !== "Component") continue;
87
+ const componentArg = expression.arguments?.[0];
88
+ if (componentArg?.type !== "ObjectExpression") continue;
89
+ const metadata = {
90
+ className: node.id?.name ?? "(anonymous)",
91
+ styleUrls: [],
92
+ templateUrls: [],
93
+ inlineTemplates: []
94
+ };
95
+ for (const property of componentArg.properties ?? []) {
96
+ if (property?.type !== "Property" || property.key?.type !== "Identifier") continue;
97
+ const name = property.key.name;
98
+ if (name === "selector") metadata.selector = getStringValue(property.value);
99
+ else if (name === "styleUrl") {
100
+ const val = getStringValue(property.value);
101
+ if (val !== void 0) metadata.styleUrls.push(val);
102
+ } else if (name === "styleUrls" && property.value?.type === "ArrayExpression") for (const el of property.value.elements ?? []) {
103
+ const val = getStringValue(el);
104
+ if (val !== void 0) metadata.styleUrls.push(val);
105
+ }
106
+ else if (name === "templateUrl") {
107
+ const val = getStringValue(property.value);
108
+ if (val !== void 0) metadata.templateUrls.push(val);
109
+ } else if (name === "template") {
110
+ const val = getStringValue(property.value);
111
+ if (val !== void 0) metadata.inlineTemplates.push(val);
112
+ }
113
+ }
114
+ components.push(metadata);
115
+ }
116
+ } }).visit(program);
117
+ return components;
50
118
  }
51
- export function getTemplateUrls(code) {
52
- const project = new Project({ useInMemoryFileSystem: true });
53
- const sourceFile = project.createSourceFile('cmp.ts', code);
54
- const properties = sourceFile.getDescendantsOfKind(SyntaxKind.PropertyAssignment);
55
- return getTextByProperty('templateUrl', properties);
119
+ /** Extract all `styleUrl` / `styleUrls` values from Angular component source. */
120
+ function getStyleUrls(code) {
121
+ return collectComponentUrls(code).styleUrls;
56
122
  }
57
- export class TemplateUrlsResolver {
58
- templateUrlsCache = new Map();
59
- resolve(code, id) {
60
- const entry = this.templateUrlsCache.get(id);
61
- if (entry?.code === code) {
62
- return entry.templateUrlPaths;
63
- }
64
- const templateUrlPaths = getTemplateUrls(code).map((url) => `${url}|${normalizePath(resolve(dirname(id), url))}`);
65
- this.templateUrlsCache.set(id, { code, templateUrlPaths });
66
- return templateUrlPaths;
67
- }
123
+ /** Extract all `templateUrl` values from Angular component source. */
124
+ function getTemplateUrls(code) {
125
+ return collectComponentUrls(code).templateUrls;
68
126
  }
127
+ var StyleUrlsResolver = class {
128
+ styleUrlsCache = /* @__PURE__ */ new Map();
129
+ resolve(code, id) {
130
+ const entry = this.styleUrlsCache.get(id);
131
+ if (entry?.code === code) return entry.styleUrls;
132
+ const styleUrls = getStyleUrls(code).map((styleUrlPath) => {
133
+ return `${styleUrlPath}|${normalizePath(resolve(dirname(id), styleUrlPath))}`;
134
+ });
135
+ this.styleUrlsCache.set(id, {
136
+ code,
137
+ styleUrls
138
+ });
139
+ return styleUrls;
140
+ }
141
+ };
142
+ var TemplateUrlsResolver = class {
143
+ templateUrlsCache = /* @__PURE__ */ new Map();
144
+ resolve(code, id) {
145
+ const entry = this.templateUrlsCache.get(id);
146
+ if (entry?.code === code) return entry.templateUrlPaths;
147
+ const templateUrlPaths = getTemplateUrls(code).map((url) => `${url}|${normalizePath(resolve(dirname(id), url))}`);
148
+ this.templateUrlsCache.set(id, {
149
+ code,
150
+ templateUrlPaths
151
+ });
152
+ return templateUrlPaths;
153
+ }
154
+ };
155
+ //#endregion
156
+ export { StyleUrlsResolver, TemplateUrlsResolver, getAngularComponentMetadata };
157
+
69
158
  //# sourceMappingURL=component-resolvers.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"component-resolvers.js","sourceRoot":"","sources":["../../../../../packages/vite-plugin-angular/src/lib/component-resolvers.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"component-resolvers.js","names":[],"sources":["../../../src/lib/component-resolvers.ts"],"sourcesContent":["import { dirname, resolve } from 'node:path';\n// OXC parser (native Rust, NAPI-RS) replaces ts-morph for AST extraction.\n// It is ~10-50x faster for the narrow task of pulling property values from\n// Angular component decorators. The Visitor helper from Rolldown walks the\n// ESTree-compatible AST that OXC produces.\nimport { parseSync } from 'oxc-parser';\nimport { Visitor } from 'rolldown/utils';\nimport { normalizePath } from 'vite';\n\n// ---------------------------------------------------------------------------\n// AST helpers\n// ---------------------------------------------------------------------------\n\n/**\n * Extracts a string value from an ESTree AST node.\n *\n * Handles three forms that Angular decorators may use:\n * - `Literal` with a string value → `'./foo.css'` / `\"./foo.css\"`\n * - `StringLiteral` (OXC-specific) → same representation\n * - `TemplateLiteral` with zero expressions → `` `./foo.css` ``\n *\n * Uses `any` because OXC's AST mixes standard ESTree nodes with\n * OXC-specific variants (e.g. `StringLiteral`), and the project's\n * tsconfig enforces `noPropertyAccessFromIndexSignature`.\n */\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nfunction getStringValue(node: any): string | undefined {\n if (!node) return undefined;\n // Standard ESTree Literal (string value)\n if (node.type === 'Literal' && typeof node.value === 'string') {\n return node.value;\n }\n // OXC-specific StringLiteral node\n if (node.type === 'StringLiteral') {\n return node.value;\n }\n // Template literal with no interpolation (e.g., `./foo.css`)\n if (\n node.type === 'TemplateLiteral' &&\n node.expressions.length === 0 &&\n node.quasis.length === 1\n ) {\n return node.quasis[0].value.cooked ?? node.quasis[0].value.raw;\n }\n return undefined;\n}\n\n/**\n * Parses TypeScript/JS source with OXC and collects `styleUrl`, `styleUrls`,\n * and `templateUrl` property values from Angular `@Component()` decorators\n * in a single AST pass.\n *\n * This replaces the previous ts-morph implementation — OXC parses natively\n * via Rust NAPI bindings, avoiding the overhead of spinning up a full\n * TypeScript `Project` for each file.\n */\nfunction collectComponentUrls(code: string): {\n styleUrls: string[];\n templateUrls: string[];\n inlineTemplates: string[];\n} {\n const { program } = parseSync('cmp.ts', code);\n const styleUrls: string[] = [];\n const templateUrls: string[] = [];\n const inlineTemplates: string[] = [];\n\n const visitor = new Visitor({\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n ClassDeclaration(node: any) {\n const decorators = node.decorators ?? [];\n for (const decorator of decorators) {\n const expression = decorator.expression;\n if (\n expression?.type !== 'CallExpression' ||\n expression.callee?.type !== 'Identifier' ||\n expression.callee.name !== 'Component'\n ) {\n continue;\n }\n\n const componentArg = expression.arguments?.[0];\n if (componentArg?.type !== 'ObjectExpression') {\n continue;\n }\n\n for (const property of componentArg.properties ?? []) {\n if (\n property?.type !== 'Property' ||\n property.key?.type !== 'Identifier'\n ) {\n continue;\n }\n\n const name = property.key.name;\n\n if (\n name === 'styleUrls' &&\n property.value?.type === 'ArrayExpression'\n ) {\n for (const el of property.value.elements) {\n const val = getStringValue(el);\n if (val !== undefined) styleUrls.push(val);\n }\n }\n\n if (name === 'styleUrl') {\n const val = getStringValue(property.value);\n if (val !== undefined) styleUrls.push(val);\n }\n\n if (name === 'templateUrl') {\n const val = getStringValue(property.value);\n if (val !== undefined) templateUrls.push(val);\n }\n\n if (name === 'template') {\n const val = getStringValue(property.value);\n if (val !== undefined) inlineTemplates.push(val);\n }\n }\n }\n },\n });\n visitor.visit(program);\n\n return { styleUrls, templateUrls, inlineTemplates };\n}\n\nexport interface AngularComponentMetadata {\n className: string;\n selector?: string;\n styleUrls: string[];\n templateUrls: string[];\n inlineTemplates: string[];\n}\n\n/**\n * Extract Angular component identities from raw source code before Angular's\n * compilation pipeline strips decorators. This is used for dev-time\n * diagnostics such as duplicate selectors, duplicate component class names,\n * selectorless shared components, and inline-template validation.\n */\nexport function getAngularComponentMetadata(\n code: string,\n): AngularComponentMetadata[] {\n const { program } = parseSync('cmp.ts', code);\n const components: AngularComponentMetadata[] = [];\n\n const visitor = new Visitor({\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n ClassDeclaration(node: any) {\n const decorators = node.decorators ?? [];\n for (const decorator of decorators) {\n const expression = decorator.expression;\n if (\n expression?.type !== 'CallExpression' ||\n expression.callee?.type !== 'Identifier' ||\n expression.callee.name !== 'Component'\n ) {\n continue;\n }\n\n const componentArg = expression.arguments?.[0];\n if (componentArg?.type !== 'ObjectExpression') {\n continue;\n }\n\n const metadata: AngularComponentMetadata = {\n className: node.id?.name ?? '(anonymous)',\n styleUrls: [],\n templateUrls: [],\n inlineTemplates: [],\n };\n\n for (const property of componentArg.properties ?? []) {\n if (\n property?.type !== 'Property' ||\n property.key?.type !== 'Identifier'\n ) {\n continue;\n }\n\n const name = property.key.name;\n if (name === 'selector') {\n metadata.selector = getStringValue(property.value);\n } else if (name === 'styleUrl') {\n const val = getStringValue(property.value);\n if (val !== undefined) {\n metadata.styleUrls.push(val);\n }\n } else if (\n name === 'styleUrls' &&\n property.value?.type === 'ArrayExpression'\n ) {\n for (const el of property.value.elements ?? []) {\n const val = getStringValue(el);\n if (val !== undefined) {\n metadata.styleUrls.push(val);\n }\n }\n } else if (name === 'templateUrl') {\n const val = getStringValue(property.value);\n if (val !== undefined) {\n metadata.templateUrls.push(val);\n }\n } else if (name === 'template') {\n const val = getStringValue(property.value);\n if (val !== undefined) {\n metadata.inlineTemplates.push(val);\n }\n }\n }\n\n components.push(metadata);\n }\n },\n });\n visitor.visit(program);\n\n return components;\n}\n\n/** Extract all `styleUrl` / `styleUrls` values from Angular component source. */\nexport function getStyleUrls(code: string): string[] {\n return collectComponentUrls(code).styleUrls;\n}\n\n/** Extract all `templateUrl` values from Angular component source. */\nexport function getTemplateUrls(code: string): string[] {\n return collectComponentUrls(code).templateUrls;\n}\n\n/** Extract inline `template` strings from Angular component source. */\nexport function getInlineTemplates(code: string): string[] {\n return collectComponentUrls(code).inlineTemplates;\n}\n\n// ---------------------------------------------------------------------------\n// Resolver caches\n// ---------------------------------------------------------------------------\n\ninterface StyleUrlsCacheEntry {\n code: string;\n styleUrls: string[];\n}\n\nexport class StyleUrlsResolver {\n // These resolvers may be called multiple times during the same\n // compilation for the same files. Caching is required because these\n // resolvers use synchronous system calls to the filesystem, which can\n // degrade performance when running compilations for multiple files.\n private readonly styleUrlsCache = new Map<string, StyleUrlsCacheEntry>();\n\n resolve(code: string, id: string): string[] {\n const entry = this.styleUrlsCache.get(id);\n if (entry?.code === code) {\n return entry.styleUrls;\n }\n\n const styleUrls = getStyleUrls(code).map((styleUrlPath) => {\n return `${styleUrlPath}|${normalizePath(\n resolve(dirname(id), styleUrlPath),\n )}`;\n });\n\n this.styleUrlsCache.set(id, { code, styleUrls });\n return styleUrls;\n }\n}\n\ninterface TemplateUrlsCacheEntry {\n code: string;\n templateUrlPaths: string[];\n}\n\nexport class TemplateUrlsResolver {\n private readonly templateUrlsCache = new Map<\n string,\n TemplateUrlsCacheEntry\n >();\n\n resolve(code: string, id: string): string[] {\n const entry = this.templateUrlsCache.get(id);\n if (entry?.code === code) {\n return entry.templateUrlPaths;\n }\n\n const templateUrlPaths = getTemplateUrls(code).map(\n (url) => `${url}|${normalizePath(resolve(dirname(id), url))}`,\n );\n\n this.templateUrlsCache.set(id, { code, templateUrlPaths });\n return templateUrlPaths;\n }\n}\n"],"mappings":"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"}
@@ -0,0 +1,13 @@
1
+ import { Plugin } from "vite";
2
+ export declare function isComponentStyleSheet(id: string): boolean;
3
+ export declare function getComponentStyleSheetMeta(id: string): {
4
+ componentId: string;
5
+ encapsulation: "emulated" | "shadow" | "none";
6
+ };
7
+ /**
8
+ * Encapsulation runs in enforce: 'post' so that @tailwindcss/vite
9
+ * (enforce: 'pre') fully resolves @apply directives — including those
10
+ * inside :host {} — before Angular's ShadowCss rewrites selectors.
11
+ * (#2293)
12
+ */
13
+ export declare function encapsulationPlugin(shouldExternalizeStyles: () => boolean): Plugin;