@analogjs/vite-plugin-angular 3.0.0-alpha.70 → 3.0.0-alpha.71

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.
@@ -1 +0,0 @@
1
- {"version":3,"file":"template-class-binding-guard-plugin.js","names":[],"sources":["../../../src/lib/template-class-binding-guard-plugin.ts"],"sourcesContent":["import { normalizePath, Plugin } from 'vite';\nimport {\n getAngularComponentMetadata,\n StyleUrlsResolver,\n} from './component-resolvers.js';\nimport { debugHmrV } from './utils/debug.js';\nimport { TS_EXT_REGEX } from './utils/plugin-config.js';\n\nexport interface ActiveGraphComponentRecord {\n file: string;\n className: string;\n selector?: string;\n}\n\nexport interface StyleOwnerRecord {\n sourcePath: string;\n ownerFile: string;\n}\n\ninterface TemplateClassBindingIssue {\n line: number;\n column: number;\n snippet: string;\n}\n\nexport interface TemplateClassBindingGuardContext {\n styleUrlsResolver: StyleUrlsResolver;\n activeGraphComponentMetadata: Map<string, ActiveGraphComponentRecord[]>;\n selectorOwners: Map<string, Set<string>>;\n classNameOwners: Map<string, Set<string>>;\n transformedStyleOwnerMetadata: Map<string, StyleOwnerRecord[]>;\n styleSourceOwners: Map<string, Set<string>>;\n}\n\nexport function templateClassBindingGuardPlugin(\n ctx: TemplateClassBindingGuardContext,\n): Plugin {\n return {\n name: '@analogjs/vite-plugin-angular:template-class-binding-guard',\n enforce: 'pre',\n transform(code: string, id: string) {\n if (id.includes('node_modules')) {\n return;\n }\n\n const cleanId = id.split('?')[0];\n\n if (/\\.(html|htm)$/i.test(cleanId)) {\n const staticClassIssue = findStaticClassAndBoundClassConflicts(code)[0];\n if (staticClassIssue) {\n throwTemplateClassBindingConflict(cleanId, staticClassIssue);\n }\n\n const mixedClassIssue = findBoundClassAndNgClassConflicts(code)[0];\n if (mixedClassIssue) {\n this.warn(\n [\n '[Analog Angular] Conflicting class composition.',\n `File: ${cleanId}:${mixedClassIssue.line}:${mixedClassIssue.column}`,\n 'This element mixes `[class]` and `[ngClass]`.',\n 'Prefer a single class-binding strategy so class merging stays predictable.',\n 'Use one `[ngClass]` expression or explicit `[class.foo]` bindings.',\n `Snippet: ${mixedClassIssue.snippet}`,\n ].join('\\n'),\n );\n }\n return;\n }\n\n if (TS_EXT_REGEX.test(cleanId)) {\n const rawStyleUrls = ctx.styleUrlsResolver.resolve(code, cleanId);\n registerStyleOwnerMetadata(ctx, cleanId, rawStyleUrls);\n debugHmrV('component stylesheet owner metadata registered', {\n file: cleanId,\n styleUrlCount: rawStyleUrls.length,\n styleUrls: rawStyleUrls,\n ownerSources: [\n ...(ctx.transformedStyleOwnerMetadata\n .get(cleanId)\n ?.map((record) => record.sourcePath) ?? []),\n ],\n });\n\n const components = getAngularComponentMetadata(code);\n\n const inlineTemplateIssue = components.flatMap((component) =>\n component.inlineTemplates.flatMap((template) =>\n findStaticClassAndBoundClassConflicts(template),\n ),\n )[0];\n\n if (inlineTemplateIssue) {\n throwTemplateClassBindingConflict(cleanId, inlineTemplateIssue);\n }\n\n const mixedInlineClassIssue = components.flatMap((component) =>\n component.inlineTemplates.flatMap((template) =>\n findBoundClassAndNgClassConflicts(template),\n ),\n )[0];\n\n if (mixedInlineClassIssue) {\n this.warn(\n [\n '[Analog Angular] Conflicting class composition.',\n `File: ${cleanId}:${mixedInlineClassIssue.line}:${mixedInlineClassIssue.column}`,\n 'This element mixes `[class]` and `[ngClass]`.',\n 'Prefer a single class-binding strategy so class merging stays predictable.',\n 'Use one `[ngClass]` expression or explicit `[class.foo]` bindings.',\n `Snippet: ${mixedInlineClassIssue.snippet}`,\n ].join('\\n'),\n );\n }\n\n const activeGraphRecords = components.map((component) => ({\n file: cleanId,\n className: component.className,\n selector: component.selector,\n }));\n\n registerActiveGraphMetadata(ctx, cleanId, activeGraphRecords);\n\n for (const component of components) {\n if (!component.selector && !isLikelyPageOnlyComponent(cleanId)) {\n throw new Error(\n [\n '[Analog Angular] Selectorless component detected.',\n `File: ${cleanId}`,\n `Component: ${component.className}`,\n 'This component has no `selector`, so Angular will render it as `ng-component`.',\n 'That increases the chance of component ID collisions and makes diagnostics harder to interpret.',\n 'Add an explicit selector for reusable components.',\n 'Selectorless components are only supported for page and route-only files.',\n ].join('\\n'),\n );\n }\n\n if (component.selector) {\n const selectorEntries = ctx.selectorOwners.get(component.selector);\n if (selectorEntries && selectorEntries.size > 1) {\n throw new Error(\n [\n '[Analog Angular] Duplicate component selector detected.',\n `Selector: ${component.selector}`,\n 'Multiple components in the active application graph use the same selector.',\n 'Selectors must be unique within the active graph to avoid ambiguous rendering and confusing diagnostics.',\n `Locations:\\n${formatActiveGraphLocations(selectorEntries)}`,\n ].join('\\n'),\n );\n }\n }\n\n const classNameEntries = ctx.classNameOwners.get(component.className);\n if (classNameEntries && classNameEntries.size > 1) {\n this.warn(\n [\n '[Analog Angular] Duplicate component class name detected.',\n `Class name: ${component.className}`,\n 'Two or more Angular components in the active graph share the same exported class name.',\n 'Rename one of them to keep HMR, stack traces, and compiler diagnostics unambiguous.',\n `Locations:\\n${formatActiveGraphLocations(classNameEntries)}`,\n ].join('\\n'),\n );\n }\n }\n }\n },\n };\n}\n\nexport function removeActiveGraphMetadata(\n ctx: TemplateClassBindingGuardContext,\n file: string,\n): void {\n const previous = ctx.activeGraphComponentMetadata.get(file);\n if (!previous) {\n return;\n }\n\n for (const record of previous) {\n const location = `${record.file}#${record.className}`;\n if (record.selector) {\n const selectorSet = ctx.selectorOwners.get(record.selector);\n selectorSet?.delete(location);\n if (selectorSet?.size === 0) {\n ctx.selectorOwners.delete(record.selector);\n }\n }\n\n const classNameSet = ctx.classNameOwners.get(record.className);\n classNameSet?.delete(location);\n if (classNameSet?.size === 0) {\n ctx.classNameOwners.delete(record.className);\n }\n }\n\n ctx.activeGraphComponentMetadata.delete(file);\n}\n\nfunction registerActiveGraphMetadata(\n ctx: TemplateClassBindingGuardContext,\n file: string,\n records: ActiveGraphComponentRecord[],\n) {\n removeActiveGraphMetadata(ctx, file);\n\n if (records.length === 0) {\n return;\n }\n\n ctx.activeGraphComponentMetadata.set(file, records);\n\n for (const record of records) {\n const location = `${record.file}#${record.className}`;\n\n if (record.selector) {\n let selectorSet = ctx.selectorOwners.get(record.selector);\n if (!selectorSet) {\n selectorSet = new Set<string>();\n ctx.selectorOwners.set(record.selector, selectorSet);\n }\n selectorSet.add(location);\n }\n\n let classNameSet = ctx.classNameOwners.get(record.className);\n if (!classNameSet) {\n classNameSet = new Set<string>();\n ctx.classNameOwners.set(record.className, classNameSet);\n }\n classNameSet.add(location);\n }\n}\n\nexport function removeStyleOwnerMetadata(\n ctx: TemplateClassBindingGuardContext,\n file: string,\n): void {\n const previous = ctx.transformedStyleOwnerMetadata.get(file);\n if (!previous) {\n return;\n }\n\n for (const record of previous) {\n const owners = ctx.styleSourceOwners.get(record.sourcePath);\n owners?.delete(record.ownerFile);\n if (owners?.size === 0) {\n ctx.styleSourceOwners.delete(record.sourcePath);\n }\n }\n\n ctx.transformedStyleOwnerMetadata.delete(file);\n}\n\nfunction registerStyleOwnerMetadata(\n ctx: TemplateClassBindingGuardContext,\n file: string,\n styleUrls: string[],\n) {\n removeStyleOwnerMetadata(ctx, file);\n\n const records = styleUrls\n .map((urlSet) => {\n const [, absoluteFileUrl] = urlSet.split('|');\n return absoluteFileUrl\n ? {\n ownerFile: file,\n sourcePath: normalizePath(absoluteFileUrl),\n }\n : undefined;\n })\n .filter((record): record is StyleOwnerRecord => !!record);\n\n if (records.length === 0) {\n return;\n }\n\n ctx.transformedStyleOwnerMetadata.set(file, records);\n\n for (const record of records) {\n let owners = ctx.styleSourceOwners.get(record.sourcePath);\n if (!owners) {\n owners = new Set<string>();\n ctx.styleSourceOwners.set(record.sourcePath, owners);\n }\n owners.add(record.ownerFile);\n }\n}\n\nfunction isLikelyPageOnlyComponent(id: string): boolean {\n return (\n id.includes('/pages/') ||\n /\\.page\\.[cm]?[jt]sx?$/i.test(id) ||\n /\\([^/]+\\)\\.page\\.[cm]?[jt]sx?$/i.test(id)\n );\n}\n\nexport function findStaticClassAndBoundClassConflicts(\n template: string,\n): TemplateClassBindingIssue[] {\n const issues: TemplateClassBindingIssue[] = [];\n\n for (const { index, snippet } of findOpeningTagSnippets(template)) {\n if (!snippet.includes('[class]')) {\n continue;\n }\n\n const hasStaticClass = /\\sclass\\s*=\\s*(['\"])(?:(?!\\1)[\\s\\S])*\\1/.test(\n snippet,\n );\n const hasBoundClass = /\\s\\[class\\]\\s*=\\s*(['\"])(?:(?!\\1)[\\s\\S])*\\1/.test(\n snippet,\n );\n\n if (hasStaticClass && hasBoundClass) {\n const prefix = template.slice(0, index);\n const line = prefix.split('\\n').length;\n const lastNewline = prefix.lastIndexOf('\\n');\n const column = index - lastNewline;\n issues.push({\n line,\n column,\n snippet: snippet.replace(/\\s+/g, ' ').trim(),\n });\n }\n }\n\n return issues;\n}\n\nexport function findBoundClassAndNgClassConflicts(\n template: string,\n): TemplateClassBindingIssue[] {\n const issues: TemplateClassBindingIssue[] = [];\n const hasWholeElementClassBinding = /\\[class\\]\\s*=/.test(template);\n\n if (!hasWholeElementClassBinding || !template.includes('[ngClass]')) {\n return issues;\n }\n\n for (const { index, snippet } of findOpeningTagSnippets(template)) {\n if (!/\\[class\\]\\s*=/.test(snippet) || !snippet.includes('[ngClass]')) {\n continue;\n }\n\n const prefix = template.slice(0, index);\n const line = prefix.split('\\n').length;\n const lastNewline = prefix.lastIndexOf('\\n');\n const column = index - lastNewline;\n issues.push({\n line,\n column,\n snippet: snippet.replace(/\\s+/g, ' ').trim(),\n });\n }\n\n return issues;\n}\n\nfunction throwTemplateClassBindingConflict(\n id: string,\n issue: TemplateClassBindingIssue,\n): never {\n throw new Error(\n [\n '[Analog Angular] Invalid template class binding.',\n `File: ${id}:${issue.line}:${issue.column}`,\n 'The same element uses both a static `class=\"...\"` attribute and a whole-element `[class]=\"...\"` binding.',\n 'That pattern can replace or conflict with static Tailwind classes, which makes styles appear to stop applying.',\n 'Use `[ngClass]` or explicit `[class.foo]` bindings instead of `[class]` when the element also has static classes.',\n `Snippet: ${issue.snippet}`,\n ].join('\\n'),\n );\n}\n\nfunction findOpeningTagSnippets(\n template: string,\n): Array<{ index: number; snippet: string }> {\n const matches: Array<{ index: number; snippet: string }> = [];\n\n for (let index = 0; index < template.length; index++) {\n if (template[index] !== '<') {\n continue;\n }\n\n const tagStart = template[index + 1];\n if (!tagStart || !/[a-zA-Z]/.test(tagStart)) {\n continue;\n }\n\n let quote: '\"' | \"'\" | null = null;\n\n for (let end = index + 1; end < template.length; end++) {\n const char = template[end];\n\n if (quote) {\n if (char === quote) {\n quote = null;\n }\n continue;\n }\n\n if (char === '\"' || char === \"'\") {\n quote = char;\n continue;\n }\n\n if (char === '>') {\n matches.push({\n index,\n snippet: template.slice(index, end + 1),\n });\n index = end;\n break;\n }\n }\n }\n\n return matches;\n}\n\nfunction formatActiveGraphLocations(entries: Iterable<string>): string {\n return [...entries]\n .sort()\n .map((entry) => `- ${entry}`)\n .join('\\n');\n}\n"],"mappings":"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"}