@maizzle/framework 6.1.0 → 6.1.2

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 (63) hide show
  1. package/dist/build.js +2 -1
  2. package/dist/build.js.map +1 -1
  3. package/dist/config/index.js.map +1 -1
  4. package/dist/plugins/postcss/mergeMediaQueries.js +2 -1
  5. package/dist/plugins/postcss/mergeMediaQueries.js.map +1 -1
  6. package/dist/plugins/postcss/resolveMaizzleImports.js.map +1 -1
  7. package/dist/render/buildTemplate.js +4 -2
  8. package/dist/render/buildTemplate.js.map +1 -1
  9. package/dist/render/createRenderer.d.ts +7 -0
  10. package/dist/render/createRenderer.d.ts.map +1 -1
  11. package/dist/render/createRenderer.js +46 -3
  12. package/dist/render/createRenderer.js.map +1 -1
  13. package/dist/serve.js +19 -10
  14. package/dist/serve.js.map +1 -1
  15. package/dist/server/compatibility.js +2 -1
  16. package/dist/server/compatibility.js.map +1 -1
  17. package/dist/server/linter.js +2 -1
  18. package/dist/server/linter.js.map +1 -1
  19. package/dist/server/sfc-utils.js.map +1 -1
  20. package/dist/server/ui/.vite/deps/@lucide_vue.js +6845 -6285
  21. package/dist/server/ui/.vite/deps/@lucide_vue.js.map +1 -1
  22. package/dist/server/ui/.vite/deps/@vueuse_core.js +2 -6
  23. package/dist/server/ui/.vite/deps/@vueuse_core.js.map +1 -1
  24. package/dist/server/ui/.vite/deps/@vueuse_shared.js +1 -1
  25. package/dist/server/ui/.vite/deps/@vueuse_shared.js.map +1 -1
  26. package/dist/server/ui/.vite/deps/_metadata.json +15 -15
  27. package/dist/server/ui/.vite/deps/culori.js +8 -6
  28. package/dist/server/ui/.vite/deps/culori.js.map +1 -1
  29. package/dist/server/ui/.vite/deps/reka-ui.js +63 -73
  30. package/dist/server/ui/.vite/deps/reka-ui.js.map +1 -1
  31. package/dist/server/ui/.vite/deps/tailwind-merge.js.map +1 -1
  32. package/dist/server/ui/.vite/deps/vue-router.js +5 -13
  33. package/dist/server/ui/.vite/deps/vue-router.js.map +1 -1
  34. package/dist/server/ui/.vite/deps/vue.js +1 -1
  35. package/dist/server/ui/.vite/deps/{vue.runtime.esm-bundler-BHD3r-bP.js → vue.runtime.esm-bundler-S54atuNJ.js} +323 -259
  36. package/dist/server/ui/.vite/deps/{vue.runtime.esm-bundler-BHD3r-bP.js.map → vue.runtime.esm-bundler-S54atuNJ.js.map} +1 -1
  37. package/dist/transformers/format.js +2 -1
  38. package/dist/transformers/format.js.map +1 -1
  39. package/dist/transformers/index.d.ts +1 -1
  40. package/dist/transformers/index.d.ts.map +1 -1
  41. package/dist/transformers/index.js +4 -4
  42. package/dist/transformers/index.js.map +1 -1
  43. package/dist/transformers/inlineCss.js +3 -2
  44. package/dist/transformers/inlineCss.js.map +1 -1
  45. package/dist/transformers/inlineLink.js +2 -1
  46. package/dist/transformers/inlineLink.js.map +1 -1
  47. package/dist/transformers/minify.js +2 -1
  48. package/dist/transformers/minify.js.map +1 -1
  49. package/dist/transformers/tailwindComponent.d.ts +1 -1
  50. package/dist/transformers/tailwindComponent.d.ts.map +1 -1
  51. package/dist/transformers/tailwindComponent.js +26 -7
  52. package/dist/transformers/tailwindComponent.js.map +1 -1
  53. package/dist/transformers/tailwindcss.d.ts +10 -3
  54. package/dist/transformers/tailwindcss.d.ts.map +1 -1
  55. package/dist/transformers/tailwindcss.js +30 -14
  56. package/dist/transformers/tailwindcss.js.map +1 -1
  57. package/dist/transformers/urlQuery.js +2 -1
  58. package/dist/transformers/urlQuery.js.map +1 -1
  59. package/dist/types/config.d.ts +11 -0
  60. package/dist/types/config.d.ts.map +1 -1
  61. package/dist/utils/cssBox.js +2 -6
  62. package/dist/utils/cssBox.js.map +1 -1
  63. package/package.json +2 -2
@@ -1 +1 @@
1
- {"version":3,"file":"linter.js","names":[],"sources":["../../src/server/linter.ts"],"sourcesContent":["import { readFileSync } from 'node:fs'\nimport { resolve } from 'node:path'\nimport { parseSfcBlocks, findComponentTags, buildComponentMap, isFrameworkComponent } from './sfc-utils.ts'\nimport type { MaizzleConfig } from '../types/index.ts'\nimport type { NormalizedComponentSource } from '../utils/componentSources.ts'\n\nexport interface LintIssue {\n type: 'error' | 'warning'\n title: string\n message: string\n /** Which tab this lands in when merged into the Checks panel. */\n category: 'css' | 'html' | 'image' | 'others'\n /** Optional caniemail slug for URL enrichment (e.g. \"html-html\"). */\n slug?: string\n line?: number\n file: string\n}\n\ninterface Presence {\n html: boolean\n head: boolean\n body: boolean\n}\n\n/**\n * Maizzle auto-adds role=\"none\" to every <table> by default via the\n * addAttributes transformer. Warn about missing role only when that won't\n * happen:\n * - useTransformers: false → whole pipeline off\n * - html.attributes.add: false → auto-add disabled globally\n * - add.table: false → table selector opted out\n * - add.table.role: false → role attribute specifically opted out\n * An empty `add.table: {}` still inherits role via defu merge, so it's fine.\n */\nfunction tableRoleAutoAdded(config: MaizzleConfig): boolean {\n if (config.useTransformers === false) return false\n const add = config.html?.attributes?.add\n if (add === false) return false\n if (!add || typeof add !== 'object') return true\n const table = (add as any).table\n if (table === false) return false\n if (table && typeof table === 'object' && table.role === false) return false\n return true\n}\n\nexport async function scanLint(\n rootFile: string,\n config: MaizzleConfig,\n componentDirs: NormalizedComponentSource[],\n): Promise<LintIssue[]> {\n const root = config.root ?? process.cwd()\n const componentMap = await buildComponentMap(root, componentDirs)\n const visited = new Set<string>()\n const presence: Presence = { html: false, head: false, body: false }\n const checkTableRole = !tableRoleAutoAdded(config)\n const issues = checkFile(rootFile, componentMap, visited, presence, checkTableRole)\n\n if (!presence.html) issues.push({ type: 'warning', category: 'html', title: 'Missing <html>', message: 'Root <html> tag not found in the template or any of its components.', slug: 'html-html', line: 1, file: rootFile })\n if (!presence.head) issues.push({ type: 'warning', category: 'html', title: 'Missing <head>', message: 'Root <head> tag not found in the template or any of its components.', slug: 'html-head', line: 1, file: rootFile })\n if (!presence.body) issues.push({ type: 'warning', category: 'html', title: 'Missing <body>', message: 'Root <body> tag not found in the template or any of its components.', slug: 'html-body', line: 1, file: rootFile })\n\n return issues\n}\n\nexport async function serveLint(url: string, res: any, config: MaizzleConfig, componentDirs: NormalizedComponentSource[]) {\n const filePath = url.replace('/__maizzle/lint/', '').replace(/\\?.*$/, '')\n\n try {\n const absolutePath = resolve(filePath)\n const issues = (await scanLint(absolutePath, config, componentDirs))\n .filter(i => !isFrameworkComponent(i.file))\n\n // Sort: errors first, then warnings, then by line\n issues.sort((a, b) => {\n if (a.type !== b.type) return a.type === 'error' ? -1 : 1\n return (a.line ?? 0) - (b.line ?? 0)\n })\n\n res.setHeader('Content-Type', 'application/json')\n res.end(JSON.stringify(issues))\n } catch (error: any) {\n res.statusCode = 500\n res.end(JSON.stringify({ error: error.message }))\n }\n}\n\nfunction checkFile(\n filePath: string,\n componentMap: Map<string, string>,\n visited: Set<string>,\n presence: Presence,\n checkTableRole: boolean,\n): LintIssue[] {\n if (visited.has(filePath)) return []\n visited.add(filePath)\n\n let source: string\n try {\n source = readFileSync(filePath, 'utf-8')\n } catch {\n return []\n }\n\n const { template } = parseSfcBlocks(source)\n const issues: LintIssue[] = []\n\n if (template) {\n issues.push(...lintHtml(template.content, template.offset, filePath, presence, checkTableRole))\n\n // Recurse into components\n const componentTags = findComponentTags(template.content)\n for (const tag of componentTags) {\n const componentPath = componentMap.get(tag.toLowerCase())\n if (componentPath) {\n issues.push(...checkFile(componentPath, componentMap, visited, presence, checkTableRole))\n }\n }\n }\n\n return issues\n}\n\nfunction lineAt(html: string, offset: number, lineOffset: number): number {\n return html.slice(0, offset).split('\\n').length + lineOffset\n}\n\n/**\n * True if the <img> tag has a width defined via any of:\n * - `width` attribute\n * - inline `style` with a `width` property\n * - class attribute with a Tailwind `w-` utility (any variant prefix like\n * sm:, hover:), or an arbitrary `[width:…]` utility\n */\nfunction hasWidthDefined(imgTag: string): boolean {\n if (/\\bwidth\\s*=/i.test(imgTag)) return true\n\n const styleMatch = imgTag.match(/\\bstyle\\s*=\\s*[\"']([^\"']*)[\"']/i)\n if (styleMatch && /(^|[;\\s])width\\s*:/i.test(styleMatch[1])) return true\n\n const classMatch = imgTag.match(/\\bclass\\s*=\\s*[\"']([^\"']*)[\"']/i)\n if (classMatch) {\n const classes = classMatch[1]\n if (/(?:^|\\s)(?:[a-z0-9-]+:)*w-\\S+/i.test(classes)) return true\n if (/\\[width:/i.test(classes)) return true\n }\n return false\n}\n\nfunction lintHtml(html: string, lineOffset: number, filePath: string, presence: Presence, checkTableRole: boolean): LintIssue[] {\n const issues: LintIssue[] = []\n\n // Match all tags (multiline) — [^>] doesn't cross > so use [\\s\\S] with lazy quantifier\n const tagRe = /<([a-zA-Z][a-zA-Z0-9]*)\\b([\\s\\S]*?)>/g\n\n for (const m of Array.from(html.matchAll(tagRe))) {\n const tag = m[0]\n const tagName = m[1].toLowerCase()\n const line = lineAt(html, m.index!, lineOffset)\n\n if (tagName === 'html') presence.html = true\n else if (tagName === 'head') presence.head = true\n else if (tagName === 'body') presence.body = true\n\n /**\n * Layout tables — accessibility requires role=\"none\" so screen readers\n * skip the table structure. Only surface the warning when the user\n * has disabled Maizzle's auto-role-add; otherwise every build\n * step output already has role=\"none\" set.\n */\n if (checkTableRole && tagName === 'table') {\n const roleMatch = tag.match(/\\brole\\s*=\\s*[\"']([^\"']*)[\"']/i)\n if (!roleMatch) {\n const tableEndIdx = html.indexOf('</table>', m.index!)\n const inner = tableEndIdx >= 0 ? html.slice(m.index!, tableEndIdx) : ''\n const isDataTable = /<th\\b/i.test(inner) || /<caption\\b/i.test(inner)\n if (!isDataTable) {\n issues.push({ type: 'warning', category: 'html', title: 'Layout table missing role', message: 'Add role=\"none\" so screen readers skip this layout table.', slug: 'html-role', line, file: filePath })\n }\n }\n }\n\n // Images\n if (tagName === 'img') {\n if (!/\\balt\\s*=/i.test(tag)) {\n issues.push({ type: 'warning', category: 'image', title: 'Missing alt text', message: 'Image is missing the alt attribute', line, file: filePath })\n }\n\n const srcMatch = tag.match(/\\bsrc\\s*=\\s*[\"']([^\"']*)[\"']/i)\n if (!srcMatch) {\n issues.push({ type: 'error', category: 'image', title: 'Missing image src', message: 'Image tag has no src attribute', line, file: filePath })\n } else if (!srcMatch[1].trim()) {\n issues.push({ type: 'error', category: 'image', title: 'Empty image src', message: 'Image src attribute is empty', line, file: filePath })\n } else if (srcMatch[1].trim().startsWith('http:')) {\n issues.push({ type: 'warning', category: 'image', title: 'Insecure image src', message: 'Image loads over HTTP instead of HTTPS', line, file: filePath })\n }\n\n if (!hasWidthDefined(tag)) {\n issues.push({ type: 'warning', category: 'image', title: 'Missing image width', message: 'Use a `width=\"\"` attribute for best results in Outlook', line, file: filePath })\n }\n }\n\n // Any tag with href — skip resource tags handled below\n if (!['link', 'script', 'source'].includes(tagName)) {\n const hrefMatch = tag.match(/\\bhref\\s*=\\s*[\"']([^\"']*)[\"']/i)\n if (hrefMatch) {\n const href = hrefMatch[1].trim()\n if (!href) {\n issues.push({ type: 'error', category: 'html', title: 'Empty link href', message: 'Link href attribute is empty', line, file: filePath })\n } else if (href === '#' || href === '/') {\n issues.push({ type: 'error', category: 'html', title: 'Placeholder link', message: `Link href is \"${href}\"`, line, file: filePath })\n } else if (href.startsWith('http:')) {\n issues.push({ type: 'warning', category: 'html', title: 'Insecure link', message: 'Link uses HTTP instead of HTTPS', line, file: filePath })\n } else if (href.startsWith('http') && !/^https?:\\/\\/.+\\..+/i.test(href)) {\n issues.push({ type: 'error', category: 'html', title: 'Invalid link', message: `Link href \"${href}\" looks malformed`, line, file: filePath })\n }\n }\n }\n\n // Insecure resources (<link>, <script>, <source>)\n if (['link', 'script', 'source'].includes(tagName)) {\n const attrMatch = tag.match(/\\b(?:href|src)\\s*=\\s*[\"']([^\"']*)[\"']/i)\n if (attrMatch && attrMatch[1].trim().startsWith('http:')) {\n issues.push({ type: 'warning', category: 'html', title: 'Insecure resource', message: 'Resource loads over HTTP instead of HTTPS', line, file: filePath })\n }\n }\n }\n\n // Insecure CSS url() references\n for (const m of Array.from(html.matchAll(/url\\s*\\(\\s*[\"']?(http:[^\"')]+)[\"']?\\s*\\)/gi))) {\n issues.push({ type: 'warning', category: 'css', title: 'Insecure CSS url()', message: 'CSS url() loads over HTTP instead of HTTPS', line: lineAt(html, m.index!, lineOffset), file: filePath })\n }\n\n // Check for unclosed tags (block-level and common inline elements)\n const voidElements = new Set([\n 'area', 'base', 'br', 'col', 'embed', 'hr', 'img', 'input',\n 'link', 'meta', 'param', 'source', 'track', 'wbr',\n ])\n\n const trackedTags = new Set([\n 'a', 'b', 'body', 'div', 'em', 'h1', 'h2', 'h3', 'h4', 'h5', 'h6',\n 'head', 'html', 'i', 'li', 'ol', 'p', 'span', 'strong', 'style',\n 'table', 'tbody', 'td', 'tfoot', 'th', 'thead', 'title', 'tr', 'u', 'ul',\n ])\n\n const stack: Array<{ tag: string, line: number }> = []\n\n // Strip comments and content inside <style>/<script> to avoid false matches\n const stripped = html\n .replace(/<!--[\\s\\S]*?-->/g, (m) => '\\n'.repeat((m.match(/\\n/g) || []).length))\n .replace(/<(style|script)\\b[^>]*>[\\s\\S]*?<\\/\\1>/gi, (m) => '\\n'.repeat((m.match(/\\n/g) || []).length))\n\n const strippedLines = stripped.split('\\n')\n\n for (let i = 0; i < strippedLines.length; i++) {\n const line = strippedLines[i]\n const tagRegex = /<\\/?([a-zA-Z][a-zA-Z0-9]*)\\b[^>]*\\/?>/g\n let m\n\n while ((m = tagRegex.exec(line)) !== null) {\n const fullMatch = m[0]\n const tagName = m[1].toLowerCase()\n\n if (!trackedTags.has(tagName) || voidElements.has(tagName)) continue\n if (fullMatch.endsWith('/>')) continue\n\n if (fullMatch.startsWith('</')) {\n // Closing tag\n let lastOpen = -1\n for (let j = stack.length - 1; j >= 0; j--) {\n if (stack[j].tag === tagName) { lastOpen = j; break }\n }\n if (lastOpen !== -1) {\n stack.splice(lastOpen, 1)\n }\n } else {\n // Opening tag\n stack.push({ tag: tagName, line: i + 1 + lineOffset })\n }\n }\n }\n\n for (const unclosed of stack) {\n issues.push({\n type: 'error',\n category: 'html',\n title: 'Unclosed tag',\n message: `<${unclosed.tag}> tag is not closed`,\n line: unclosed.line,\n file: filePath,\n })\n }\n\n return issues\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"linter.js","names":[],"sources":["../../src/server/linter.ts"],"sourcesContent":["import { readFileSync } from 'node:fs'\nimport { resolve } from 'node:path'\nimport { parseSfcBlocks, findComponentTags, buildComponentMap, isFrameworkComponent } from './sfc-utils.ts'\nimport type { MaizzleConfig } from '../types/index.ts'\nimport type { NormalizedComponentSource } from '../utils/componentSources.ts'\n\nexport interface LintIssue {\n type: 'error' | 'warning'\n title: string\n message: string\n /** Which tab this lands in when merged into the Checks panel. */\n category: 'css' | 'html' | 'image' | 'others'\n /** Optional caniemail slug for URL enrichment (e.g. \"html-html\"). */\n slug?: string\n line?: number\n file: string\n}\n\ninterface Presence {\n html: boolean\n head: boolean\n body: boolean\n}\n\n/**\n * Maizzle auto-adds role=\"none\" to every <table> by default via the\n * addAttributes transformer. Warn about missing role only when that won't\n * happen:\n * - useTransformers: false → whole pipeline off\n * - html.attributes.add: false → auto-add disabled globally\n * - add.table: false → table selector opted out\n * - add.table.role: false → role attribute specifically opted out\n * An empty `add.table: {}` still inherits role via defu merge, so it's fine.\n */\nfunction tableRoleAutoAdded(config: MaizzleConfig): boolean {\n if (config.useTransformers === false) return false\n const add = config.html?.attributes?.add\n if (add === false) return false\n if (!add || typeof add !== 'object') return true\n const table = (add as any).table\n if (table === false) return false\n if (table && typeof table === 'object' && table.role === false) return false\n return true\n}\n\nexport async function scanLint(\n rootFile: string,\n config: MaizzleConfig,\n componentDirs: NormalizedComponentSource[],\n): Promise<LintIssue[]> {\n const root = config.root ?? process.cwd()\n const componentMap = await buildComponentMap(root, componentDirs)\n const visited = new Set<string>()\n const presence: Presence = { html: false, head: false, body: false }\n const checkTableRole = !tableRoleAutoAdded(config)\n const issues = checkFile(rootFile, componentMap, visited, presence, checkTableRole)\n\n if (!presence.html) issues.push({ type: 'warning', category: 'html', title: 'Missing <html>', message: 'Root <html> tag not found in the template or any of its components.', slug: 'html-html', line: 1, file: rootFile })\n if (!presence.head) issues.push({ type: 'warning', category: 'html', title: 'Missing <head>', message: 'Root <head> tag not found in the template or any of its components.', slug: 'html-head', line: 1, file: rootFile })\n if (!presence.body) issues.push({ type: 'warning', category: 'html', title: 'Missing <body>', message: 'Root <body> tag not found in the template or any of its components.', slug: 'html-body', line: 1, file: rootFile })\n\n return issues\n}\n\nexport async function serveLint(url: string, res: any, config: MaizzleConfig, componentDirs: NormalizedComponentSource[]) {\n const filePath = url.replace('/__maizzle/lint/', '').replace(/\\?.*$/, '')\n\n try {\n const absolutePath = resolve(filePath)\n const issues = (await scanLint(absolutePath, config, componentDirs))\n .filter(i => !isFrameworkComponent(i.file))\n\n // Sort: errors first, then warnings, then by line\n issues.sort((a, b) => {\n if (a.type !== b.type) return a.type === 'error' ? -1 : 1\n return (a.line ?? 0) - (b.line ?? 0)\n })\n\n res.setHeader('Content-Type', 'application/json')\n res.end(JSON.stringify(issues))\n } catch (error: any) {\n res.statusCode = 500\n res.end(JSON.stringify({ error: error.message }))\n }\n}\n\nfunction checkFile(\n filePath: string,\n componentMap: Map<string, string>,\n visited: Set<string>,\n presence: Presence,\n checkTableRole: boolean,\n): LintIssue[] {\n if (visited.has(filePath)) return []\n visited.add(filePath)\n\n let source: string\n try {\n source = readFileSync(filePath, 'utf-8')\n } catch {\n return []\n }\n\n const { template } = parseSfcBlocks(source)\n const issues: LintIssue[] = []\n\n if (template) {\n issues.push(...lintHtml(template.content, template.offset, filePath, presence, checkTableRole))\n\n // Recurse into components\n const componentTags = findComponentTags(template.content)\n for (const tag of componentTags) {\n const componentPath = componentMap.get(tag.toLowerCase())\n if (componentPath) {\n issues.push(...checkFile(componentPath, componentMap, visited, presence, checkTableRole))\n }\n }\n }\n\n return issues\n}\n\nfunction lineAt(html: string, offset: number, lineOffset: number): number {\n return html.slice(0, offset).split('\\n').length + lineOffset\n}\n\n/**\n * True if the <img> tag has a width defined via any of:\n * - `width` attribute\n * - inline `style` with a `width` property\n * - class attribute with a Tailwind `w-` utility (any variant prefix like\n * sm:, hover:), or an arbitrary `[width:…]` utility\n */\nfunction hasWidthDefined(imgTag: string): boolean {\n if (/\\bwidth\\s*=/i.test(imgTag)) return true\n\n const styleMatch = imgTag.match(/\\bstyle\\s*=\\s*[\"']([^\"']*)[\"']/i)\n if (styleMatch && /(^|[;\\s])width\\s*:/i.test(styleMatch[1])) return true\n\n const classMatch = imgTag.match(/\\bclass\\s*=\\s*[\"']([^\"']*)[\"']/i)\n if (classMatch) {\n const classes = classMatch[1]\n if (/(?:^|\\s)(?:[a-z0-9-]+:)*w-\\S+/i.test(classes)) return true\n if (/\\[width:/i.test(classes)) return true\n }\n return false\n}\n\nfunction lintHtml(html: string, lineOffset: number, filePath: string, presence: Presence, checkTableRole: boolean): LintIssue[] {\n const issues: LintIssue[] = []\n\n // Match all tags (multiline) — [^>] doesn't cross > so use [\\s\\S] with lazy quantifier\n const tagRe = /<([a-zA-Z][a-zA-Z0-9]*)\\b([\\s\\S]*?)>/g\n\n for (const m of Array.from(html.matchAll(tagRe))) {\n const tag = m[0]\n const tagName = m[1].toLowerCase()\n const line = lineAt(html, m.index!, lineOffset)\n\n if (tagName === 'html') presence.html = true\n else if (tagName === 'head') presence.head = true\n else if (tagName === 'body') presence.body = true\n\n /**\n * Layout tables — accessibility requires role=\"none\" so screen readers\n * skip the table structure. Only surface the warning when the user\n * has disabled Maizzle's auto-role-add; otherwise every build\n * step output already has role=\"none\" set.\n */\n if (checkTableRole && tagName === 'table') {\n const roleMatch = tag.match(/\\brole\\s*=\\s*[\"']([^\"']*)[\"']/i)\n if (!roleMatch) {\n const tableEndIdx = html.indexOf('</table>', m.index!)\n const inner = tableEndIdx >= 0 ? html.slice(m.index!, tableEndIdx) : ''\n const isDataTable = /<th\\b/i.test(inner) || /<caption\\b/i.test(inner)\n if (!isDataTable) {\n issues.push({ type: 'warning', category: 'html', title: 'Layout table missing role', message: 'Add role=\"none\" so screen readers skip this layout table.', slug: 'html-role', line, file: filePath })\n }\n }\n }\n\n // Images\n if (tagName === 'img') {\n if (!/\\balt\\s*=/i.test(tag)) {\n issues.push({ type: 'warning', category: 'image', title: 'Missing alt text', message: 'Image is missing the alt attribute', line, file: filePath })\n }\n\n const srcMatch = tag.match(/\\bsrc\\s*=\\s*[\"']([^\"']*)[\"']/i)\n if (!srcMatch) {\n issues.push({ type: 'error', category: 'image', title: 'Missing image src', message: 'Image tag has no src attribute', line, file: filePath })\n } else if (!srcMatch[1].trim()) {\n issues.push({ type: 'error', category: 'image', title: 'Empty image src', message: 'Image src attribute is empty', line, file: filePath })\n } else if (srcMatch[1].trim().startsWith('http:')) {\n issues.push({ type: 'warning', category: 'image', title: 'Insecure image src', message: 'Image loads over HTTP instead of HTTPS', line, file: filePath })\n }\n\n if (!hasWidthDefined(tag)) {\n issues.push({ type: 'warning', category: 'image', title: 'Missing image width', message: 'Use a `width=\"\"` attribute for best results in Outlook', line, file: filePath })\n }\n }\n\n // Any tag with href — skip resource tags handled below\n if (!['link', 'script', 'source'].includes(tagName)) {\n const hrefMatch = tag.match(/\\bhref\\s*=\\s*[\"']([^\"']*)[\"']/i)\n if (hrefMatch) {\n const href = hrefMatch[1].trim()\n if (!href) {\n issues.push({ type: 'error', category: 'html', title: 'Empty link href', message: 'Link href attribute is empty', line, file: filePath })\n } else if (href === '#' || href === '/') {\n issues.push({ type: 'error', category: 'html', title: 'Placeholder link', message: `Link href is \"${href}\"`, line, file: filePath })\n } else if (href.startsWith('http:')) {\n issues.push({ type: 'warning', category: 'html', title: 'Insecure link', message: 'Link uses HTTP instead of HTTPS', line, file: filePath })\n } else if (href.startsWith('http') && !/^https?:\\/\\/.+\\..+/i.test(href)) {\n issues.push({ type: 'error', category: 'html', title: 'Invalid link', message: `Link href \"${href}\" looks malformed`, line, file: filePath })\n }\n }\n }\n\n // Insecure resources (<link>, <script>, <source>)\n if (['link', 'script', 'source'].includes(tagName)) {\n const attrMatch = tag.match(/\\b(?:href|src)\\s*=\\s*[\"']([^\"']*)[\"']/i)\n if (attrMatch && attrMatch[1].trim().startsWith('http:')) {\n issues.push({ type: 'warning', category: 'html', title: 'Insecure resource', message: 'Resource loads over HTTP instead of HTTPS', line, file: filePath })\n }\n }\n }\n\n // Insecure CSS url() references\n for (const m of Array.from(html.matchAll(/url\\s*\\(\\s*[\"']?(http:[^\"')]+)[\"']?\\s*\\)/gi))) {\n issues.push({ type: 'warning', category: 'css', title: 'Insecure CSS url()', message: 'CSS url() loads over HTTP instead of HTTPS', line: lineAt(html, m.index!, lineOffset), file: filePath })\n }\n\n // Check for unclosed tags (block-level and common inline elements)\n const voidElements = new Set([\n 'area', 'base', 'br', 'col', 'embed', 'hr', 'img', 'input',\n 'link', 'meta', 'param', 'source', 'track', 'wbr',\n ])\n\n const trackedTags = new Set([\n 'a', 'b', 'body', 'div', 'em', 'h1', 'h2', 'h3', 'h4', 'h5', 'h6',\n 'head', 'html', 'i', 'li', 'ol', 'p', 'span', 'strong', 'style',\n 'table', 'tbody', 'td', 'tfoot', 'th', 'thead', 'title', 'tr', 'u', 'ul',\n ])\n\n const stack: Array<{ tag: string, line: number }> = []\n\n // Strip comments and content inside <style>/<script> to avoid false matches\n const stripped = html\n .replace(/<!--[\\s\\S]*?-->/g, (m) => '\\n'.repeat((m.match(/\\n/g) || []).length))\n .replace(/<(style|script)\\b[^>]*>[\\s\\S]*?<\\/\\1>/gi, (m) => '\\n'.repeat((m.match(/\\n/g) || []).length))\n\n const strippedLines = stripped.split('\\n')\n\n for (let i = 0; i < strippedLines.length; i++) {\n const line = strippedLines[i]\n const tagRegex = /<\\/?([a-zA-Z][a-zA-Z0-9]*)\\b[^>]*\\/?>/g\n let m\n\n while ((m = tagRegex.exec(line)) !== null) {\n const fullMatch = m[0]\n const tagName = m[1].toLowerCase()\n\n if (!trackedTags.has(tagName) || voidElements.has(tagName)) continue\n if (fullMatch.endsWith('/>')) continue\n\n if (fullMatch.startsWith('</')) {\n // Closing tag\n let lastOpen = -1\n for (let j = stack.length - 1; j >= 0; j--) {\n if (stack[j].tag === tagName) { lastOpen = j; break }\n }\n if (lastOpen !== -1) {\n stack.splice(lastOpen, 1)\n }\n } else {\n // Opening tag\n stack.push({ tag: tagName, line: i + 1 + lineOffset })\n }\n }\n }\n\n for (const unclosed of stack) {\n issues.push({\n type: 'error',\n category: 'html',\n title: 'Unclosed tag',\n message: `<${unclosed.tag}> tag is not closed`,\n line: unclosed.line,\n file: filePath,\n })\n }\n\n return issues\n}\n"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"sfc-utils.js","names":[],"sources":["../../src/server/sfc-utils.ts"],"sourcesContent":["import { existsSync } from 'node:fs'\nimport { resolve, dirname } from 'node:path'\nimport { fileURLToPath } from 'node:url'\nimport { glob } from 'tinyglobby'\nimport { componentNameFromPath, type NormalizedComponentSource } from '../utils/componentSources.ts'\n\nconst __dirname = dirname(fileURLToPath(import.meta.url))\n\n/**\n * Built-in framework components Maizzle ships internally. Issues raised\n * against these files are framework-owned, not the user's responsibility,\n * so the dev UI's Checks tab filters them out.\n */\nconst FRAMEWORK_COMPONENTS_DIR = resolve(__dirname, '../components').replace(/\\\\/g, '/') + '/'\n\nexport function isFrameworkComponent(file: string): boolean {\n return file.replace(/\\\\/g, '/').startsWith(FRAMEWORK_COMPONENTS_DIR)\n}\n\nexport interface SfcBlock {\n content: string\n offset: number\n}\n\nexport function parseSfcBlocks(source: string): { template: SfcBlock | null, styles: SfcBlock[] } {\n let template: SfcBlock | null = null\n const styles: SfcBlock[] = []\n\n const templateMatch = source.match(/<template\\b[^>]*>([\\s\\S]*)<\\/template>/)\n if (templateMatch) {\n const contentStart = source.indexOf(templateMatch[0]) + templateMatch[0].indexOf(templateMatch[1])\n const offset = source.slice(0, contentStart).split('\\n').length - 1\n template = { content: templateMatch[1], offset }\n }\n\n const styleRe = /<style\\b([^>]*)>([\\s\\S]*?)<\\/style>/g\n let m\n while ((m = styleRe.exec(source)) !== null) {\n // Skip preprocessor styles (scss, less, etc.) — caniemail only parses plain CSS\n if (/\\blang\\s*=\\s*[\"'](?!css)/i.test(m[1])) continue\n\n const contentStart = m.index + m[0].indexOf(m[2])\n const offset = source.slice(0, contentStart).split('\\n').length - 1\n styles.push({ content: m[2], offset })\n }\n\n return { template, styles }\n}\n\n/**\n * Standard HTML elements — anything not in this set is treated as a component.\n */\nexport const HTML_ELEMENTS = new Set([\n 'a', 'abbr', 'address', 'area', 'article', 'aside', 'audio', 'b', 'base',\n 'bdi', 'bdo', 'blockquote', 'body', 'br', 'button', 'canvas', 'caption',\n 'cite', 'code', 'col', 'colgroup', 'data', 'datalist', 'dd', 'del',\n 'details', 'dfn', 'dialog', 'div', 'dl', 'dt', 'em', 'embed', 'fieldset',\n 'figcaption', 'figure', 'footer', 'form', 'h1', 'h2', 'h3', 'h4', 'h5',\n 'h6', 'head', 'header', 'hgroup', 'hr', 'html', 'i', 'iframe', 'img',\n 'input', 'ins', 'kbd', 'label', 'legend', 'li', 'link', 'main', 'map',\n 'mark', 'menu', 'meta', 'meter', 'nav', 'noscript', 'object', 'ol',\n 'optgroup', 'option', 'output', 'p', 'picture', 'pre', 'progress', 'q',\n 'rp', 'rt', 'ruby', 's', 'samp', 'script', 'search', 'section', 'select',\n 'slot', 'small', 'source', 'span', 'strong', 'style', 'sub', 'summary',\n 'sup', 'table', 'tbody', 'td', 'template', 'textarea', 'tfoot', 'th',\n 'thead', 'time', 'title', 'tr', 'track', 'u', 'ul', 'var', 'video', 'wbr',\n])\n\nexport function findComponentTags(templateContent: string): string[] {\n const tags = new Set<string>()\n\n // PascalCase tags like <Section>, <Button>\n const pascalRe = /<([A-Z][a-zA-Z0-9]*)\\b/g\n let m\n while ((m = pascalRe.exec(templateContent)) !== null) {\n tags.add(m[1])\n }\n\n // kebab-case tags like <my-component>\n const kebabRe = /<([a-z][a-z0-9]*(?:-[a-z0-9]+)+)\\b/g\n while ((m = kebabRe.exec(templateContent)) !== null) {\n if (!HTML_ELEMENTS.has(m[1])) {\n tags.add(m[1])\n }\n }\n\n return [...tags]\n}\n\nexport async function buildComponentMap(\n root: string,\n componentDirs: NormalizedComponentSource[],\n): Promise<Map<string, string>> {\n const map = new Map<string, string>()\n\n /**\n * Built-in framework components + the user's default `components/` dir\n * use unplugin's directoryAsNamespace + collapseSamePrefixes\n * behavior — i.e. no explicit prefix, folder name becomes\n * the namespace.\n */\n const implicitDirs = [\n resolve(__dirname, '../components'),\n resolve(root, 'components'),\n ].filter(existsSync)\n\n const allSources: NormalizedComponentSource[] = [\n ...implicitDirs.map(path => ({ path, prefix: undefined, pathPrefix: true })),\n ...componentDirs.filter(s => existsSync(s.path)),\n ]\n\n for (const source of allSources) {\n const files = await glob(['**/*.vue'], { cwd: source.path, absolute: true })\n for (const file of files) {\n const name = componentNameFromPath({\n filePath: file,\n dirRoot: source.path,\n prefix: source.prefix,\n pathPrefix: source.pathPrefix,\n })\n // Lowercased for case-insensitive lookups in the linter/compat scanners.\n map.set(name.toLowerCase(), file)\n }\n }\n\n return map\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"sfc-utils.js","names":[],"sources":["../../src/server/sfc-utils.ts"],"sourcesContent":["import { existsSync } from 'node:fs'\nimport { resolve, dirname } from 'node:path'\nimport { fileURLToPath } from 'node:url'\nimport { glob } from 'tinyglobby'\nimport { componentNameFromPath, type NormalizedComponentSource } from '../utils/componentSources.ts'\n\nconst __dirname = dirname(fileURLToPath(import.meta.url))\n\n/**\n * Built-in framework components Maizzle ships internally. Issues raised\n * against these files are framework-owned, not the user's responsibility,\n * so the dev UI's Checks tab filters them out.\n */\nconst FRAMEWORK_COMPONENTS_DIR = resolve(__dirname, '../components').replace(/\\\\/g, '/') + '/'\n\nexport function isFrameworkComponent(file: string): boolean {\n return file.replace(/\\\\/g, '/').startsWith(FRAMEWORK_COMPONENTS_DIR)\n}\n\nexport interface SfcBlock {\n content: string\n offset: number\n}\n\nexport function parseSfcBlocks(source: string): { template: SfcBlock | null, styles: SfcBlock[] } {\n let template: SfcBlock | null = null\n const styles: SfcBlock[] = []\n\n const templateMatch = source.match(/<template\\b[^>]*>([\\s\\S]*)<\\/template>/)\n if (templateMatch) {\n const contentStart = source.indexOf(templateMatch[0]) + templateMatch[0].indexOf(templateMatch[1])\n const offset = source.slice(0, contentStart).split('\\n').length - 1\n template = { content: templateMatch[1], offset }\n }\n\n const styleRe = /<style\\b([^>]*)>([\\s\\S]*?)<\\/style>/g\n let m\n while ((m = styleRe.exec(source)) !== null) {\n // Skip preprocessor styles (scss, less, etc.) — caniemail only parses plain CSS\n if (/\\blang\\s*=\\s*[\"'](?!css)/i.test(m[1])) continue\n\n const contentStart = m.index + m[0].indexOf(m[2])\n const offset = source.slice(0, contentStart).split('\\n').length - 1\n styles.push({ content: m[2], offset })\n }\n\n return { template, styles }\n}\n\n/**\n * Standard HTML elements — anything not in this set is treated as a component.\n */\nexport const HTML_ELEMENTS = new Set([\n 'a', 'abbr', 'address', 'area', 'article', 'aside', 'audio', 'b', 'base',\n 'bdi', 'bdo', 'blockquote', 'body', 'br', 'button', 'canvas', 'caption',\n 'cite', 'code', 'col', 'colgroup', 'data', 'datalist', 'dd', 'del',\n 'details', 'dfn', 'dialog', 'div', 'dl', 'dt', 'em', 'embed', 'fieldset',\n 'figcaption', 'figure', 'footer', 'form', 'h1', 'h2', 'h3', 'h4', 'h5',\n 'h6', 'head', 'header', 'hgroup', 'hr', 'html', 'i', 'iframe', 'img',\n 'input', 'ins', 'kbd', 'label', 'legend', 'li', 'link', 'main', 'map',\n 'mark', 'menu', 'meta', 'meter', 'nav', 'noscript', 'object', 'ol',\n 'optgroup', 'option', 'output', 'p', 'picture', 'pre', 'progress', 'q',\n 'rp', 'rt', 'ruby', 's', 'samp', 'script', 'search', 'section', 'select',\n 'slot', 'small', 'source', 'span', 'strong', 'style', 'sub', 'summary',\n 'sup', 'table', 'tbody', 'td', 'template', 'textarea', 'tfoot', 'th',\n 'thead', 'time', 'title', 'tr', 'track', 'u', 'ul', 'var', 'video', 'wbr',\n])\n\nexport function findComponentTags(templateContent: string): string[] {\n const tags = new Set<string>()\n\n // PascalCase tags like <Section>, <Button>\n const pascalRe = /<([A-Z][a-zA-Z0-9]*)\\b/g\n let m\n while ((m = pascalRe.exec(templateContent)) !== null) {\n tags.add(m[1])\n }\n\n // kebab-case tags like <my-component>\n const kebabRe = /<([a-z][a-z0-9]*(?:-[a-z0-9]+)+)\\b/g\n while ((m = kebabRe.exec(templateContent)) !== null) {\n if (!HTML_ELEMENTS.has(m[1])) {\n tags.add(m[1])\n }\n }\n\n return [...tags]\n}\n\nexport async function buildComponentMap(\n root: string,\n componentDirs: NormalizedComponentSource[],\n): Promise<Map<string, string>> {\n const map = new Map<string, string>()\n\n /**\n * Built-in framework components + the user's default `components/` dir\n * use unplugin's directoryAsNamespace + collapseSamePrefixes\n * behavior — i.e. no explicit prefix, folder name becomes\n * the namespace.\n */\n const implicitDirs = [\n resolve(__dirname, '../components'),\n resolve(root, 'components'),\n ].filter(existsSync)\n\n const allSources: NormalizedComponentSource[] = [\n ...implicitDirs.map(path => ({ path, prefix: undefined, pathPrefix: true })),\n ...componentDirs.filter(s => existsSync(s.path)),\n ]\n\n for (const source of allSources) {\n const files = await glob(['**/*.vue'], { cwd: source.path, absolute: true })\n for (const file of files) {\n const name = componentNameFromPath({\n filePath: file,\n dirRoot: source.path,\n prefix: source.prefix,\n pathPrefix: source.pathPrefix,\n })\n // Lowercased for case-insensitive lookups in the linter/compat scanners.\n map.set(name.toLowerCase(), file)\n }\n }\n\n return map\n}\n"],"mappings":";;;;;;AAMA,MAAM,YAAY,QAAQ,cAAc,YAAY,GAAG,CAAC;;;;;;AAOxD,MAAM,2BAA2B,QAAQ,WAAW,eAAe,CAAC,CAAC,QAAQ,OAAO,GAAG,IAAI;AAE3F,SAAgB,qBAAqB,MAAuB;CAC1D,OAAO,KAAK,QAAQ,OAAO,GAAG,CAAC,CAAC,WAAW,wBAAwB;AACrE;AAOA,SAAgB,eAAe,QAAmE;CAChG,IAAI,WAA4B;CAChC,MAAM,SAAqB,CAAC;CAE5B,MAAM,gBAAgB,OAAO,MAAM,wCAAwC;CAC3E,IAAI,eAAe;EACjB,MAAM,eAAe,OAAO,QAAQ,cAAc,EAAE,IAAI,cAAc,EAAE,CAAC,QAAQ,cAAc,EAAE;EACjG,MAAM,SAAS,OAAO,MAAM,GAAG,YAAY,CAAC,CAAC,MAAM,IAAI,CAAC,CAAC,SAAS;EAClE,WAAW;GAAE,SAAS,cAAc;GAAI;EAAO;CACjD;CAEA,MAAM,UAAU;CAChB,IAAI;CACJ,QAAQ,IAAI,QAAQ,KAAK,MAAM,OAAO,MAAM;EAE1C,IAAI,4BAA4B,KAAK,EAAE,EAAE,GAAG;EAE5C,MAAM,eAAe,EAAE,QAAQ,EAAE,EAAE,CAAC,QAAQ,EAAE,EAAE;EAChD,MAAM,SAAS,OAAO,MAAM,GAAG,YAAY,CAAC,CAAC,MAAM,IAAI,CAAC,CAAC,SAAS;EAClE,OAAO,KAAK;GAAE,SAAS,EAAE;GAAI;EAAO,CAAC;CACvC;CAEA,OAAO;EAAE;EAAU;CAAO;AAC5B;;;;AAKA,MAAa,gCAAgB,IAAI,IAAI;CACnC;CAAK;CAAQ;CAAW;CAAQ;CAAW;CAAS;CAAS;CAAK;CAClE;CAAO;CAAO;CAAc;CAAQ;CAAM;CAAU;CAAU;CAC9D;CAAQ;CAAQ;CAAO;CAAY;CAAQ;CAAY;CAAM;CAC7D;CAAW;CAAO;CAAU;CAAO;CAAM;CAAM;CAAM;CAAS;CAC9D;CAAc;CAAU;CAAU;CAAQ;CAAM;CAAM;CAAM;CAAM;CAClE;CAAM;CAAQ;CAAU;CAAU;CAAM;CAAQ;CAAK;CAAU;CAC/D;CAAS;CAAO;CAAO;CAAS;CAAU;CAAM;CAAQ;CAAQ;CAChE;CAAQ;CAAQ;CAAQ;CAAS;CAAO;CAAY;CAAU;CAC9D;CAAY;CAAU;CAAU;CAAK;CAAW;CAAO;CAAY;CACnE;CAAM;CAAM;CAAQ;CAAK;CAAQ;CAAU;CAAU;CAAW;CAChE;CAAQ;CAAS;CAAU;CAAQ;CAAU;CAAS;CAAO;CAC7D;CAAO;CAAS;CAAS;CAAM;CAAY;CAAY;CAAS;CAChE;CAAS;CAAQ;CAAS;CAAM;CAAS;CAAK;CAAM;CAAO;CAAS;AACtE,CAAC;AAED,SAAgB,kBAAkB,iBAAmC;CACnE,MAAM,uBAAO,IAAI,IAAY;CAG7B,MAAM,WAAW;CACjB,IAAI;CACJ,QAAQ,IAAI,SAAS,KAAK,eAAe,OAAO,MAC9C,KAAK,IAAI,EAAE,EAAE;CAIf,MAAM,UAAU;CAChB,QAAQ,IAAI,QAAQ,KAAK,eAAe,OAAO,MAC7C,IAAI,CAAC,cAAc,IAAI,EAAE,EAAE,GACzB,KAAK,IAAI,EAAE,EAAE;CAIjB,OAAO,CAAC,GAAG,IAAI;AACjB;AAEA,eAAsB,kBACpB,MACA,eAC8B;CAC9B,MAAM,sBAAM,IAAI,IAAoB;CAapC,MAAM,aAA0C,CAC9C,GANmB,CACnB,QAAQ,WAAW,eAAe,GAClC,QAAQ,MAAM,YAAY,CAC5B,CAAC,CAAC,OAAO,UAGO,CAAC,CAAC,KAAI,UAAS;EAAE;EAAM,QAAQ,KAAA;EAAW,YAAY;CAAK,EAAE,GAC3E,GAAG,cAAc,QAAO,MAAK,WAAW,EAAE,IAAI,CAAC,CACjD;CAEA,KAAK,MAAM,UAAU,YAAY;EAC/B,MAAM,QAAQ,MAAM,KAAK,CAAC,UAAU,GAAG;GAAE,KAAK,OAAO;GAAM,UAAU;EAAK,CAAC;EAC3E,KAAK,MAAM,QAAQ,OAAO;GACxB,MAAM,OAAO,sBAAsB;IACjC,UAAU;IACV,SAAS,OAAO;IAChB,QAAQ,OAAO;IACf,YAAY,OAAO;GACrB,CAAC;GAED,IAAI,IAAI,KAAK,YAAY,GAAG,IAAI;EAClC;CACF;CAEA,OAAO;AACT"}