annotask 0.0.0 → 0.0.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.
- package/LICENSE +21 -0
- package/README.md +45 -3
- package/dist/chunk-GHDLRMQG.js +61 -0
- package/dist/chunk-GHDLRMQG.js.map +1 -0
- package/dist/chunk-HW7MHAEC.js +832 -0
- package/dist/chunk-HW7MHAEC.js.map +1 -0
- package/dist/chunk-JLOSPIJ4.js +340 -0
- package/dist/chunk-JLOSPIJ4.js.map +1 -0
- package/dist/chunk-JPNMDGZN.js +61 -0
- package/dist/chunk-JPNMDGZN.js.map +1 -0
- package/dist/chunk-R6P4MMZW.js +340 -0
- package/dist/chunk-R6P4MMZW.js.map +1 -0
- package/dist/chunk-TUINPVDZ.js +894 -0
- package/dist/chunk-TUINPVDZ.js.map +1 -0
- package/dist/chunk-VI4NPM6C.js +888 -0
- package/dist/chunk-VI4NPM6C.js.map +1 -0
- package/dist/chunk-VU7Z7EZA.js +362 -0
- package/dist/chunk-VU7Z7EZA.js.map +1 -0
- package/dist/chunk-X72ZX6VB.js +835 -0
- package/dist/chunk-X72ZX6VB.js.map +1 -0
- package/dist/chunk-XLNGAH3S.js +29 -0
- package/dist/chunk-XLNGAH3S.js.map +1 -0
- package/dist/cli.js +38 -10
- package/dist/index.d.ts +11 -0
- package/dist/index.js +19 -16
- package/dist/index.js.map +1 -1
- package/dist/server.d.ts +4 -1
- package/dist/server.js +1 -1
- package/dist/shell/assets/{index-BD3nZNWX.js → index-BcsdXOsJ.js} +25 -25
- package/dist/shell/favicon.ico +0 -0
- package/dist/shell/index.html +2 -1
- package/dist/standalone.js +3 -3
- package/dist/webpack-loader.js +1 -1
- package/dist/webpack.js +6 -8
- package/dist/webpack.js.map +1 -1
- package/package.json +3 -1
- package/skills/annotask-apply/SKILL.md +8 -0
- package/skills/annotask-watch/SKILL.md +1 -1
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/plugin/toggle-button.ts","../src/plugin/bridge-client.ts"],"sourcesContent":["/**\n * Tiny script injected into the user's page that renders a floating\n * Annotask toggle button in the bottom-right corner.\n * Clicking it opens /__annotask/ in a new tab.\n */\nexport function toggleButtonScript(serverUrl?: string): string {\n const annotaskUrl = serverUrl ? `${serverUrl}/__annotask/` : '/__annotask/'\n return `\n(function() {\n // Don't inject inside the Annotask shell itself\n if (window.location.pathname.startsWith('/__annotask')) return;\n\n const btn = document.createElement('button');\n btn.innerHTML = \\`<svg width=\"20\" height=\"20\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><rect x=\"3\" y=\"3\" width=\"18\" height=\"18\" rx=\"2\"/><path d=\"M3 9h18\"/><path d=\"M9 21V9\"/></svg>\\`;\n btn.title = 'Open Annotask';\n btn.setAttribute('aria-label', 'Open Annotask design tool');\n\n Object.assign(btn.style, {\n position: 'fixed',\n bottom: '16px',\n right: '16px',\n zIndex: '2147483647',\n width: '40px',\n height: '40px',\n borderRadius: '10px',\n border: 'none',\n background: '#18181b',\n color: '#fafafa',\n cursor: 'pointer',\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'center',\n boxShadow: '0 2px 8px rgba(0,0,0,0.3)',\n transition: 'transform 0.15s, box-shadow 0.15s',\n opacity: '0.8',\n });\n\n btn.addEventListener('mouseenter', () => {\n btn.style.transform = 'scale(1.1)';\n btn.style.opacity = '1';\n btn.style.boxShadow = '0 4px 16px rgba(0,0,0,0.4)';\n });\n btn.addEventListener('mouseleave', () => {\n btn.style.transform = 'scale(1)';\n btn.style.opacity = '0.8';\n btn.style.boxShadow = '0 2px 8px rgba(0,0,0,0.3)';\n });\n\n btn.addEventListener('click', () => {\n var appOrigin = window.location.origin;\n var url = '${annotaskUrl}' + '?appUrl=' + encodeURIComponent(appOrigin + '/');\n window.open(url, '_blank');\n });\n\n document.body.appendChild(btn);\n})();\n`.trim()\n}\n","/**\n * Client bridge script injected into the user's app.\n * Communicates with the Annotask shell via postMessage.\n * Handles all DOM interactions: hover, click, style reads/writes,\n * element resolution, layout scanning, etc.\n *\n * Returned as an inline string (same pattern as toggle-button.ts).\n */\nexport function bridgeClientScript(): string {\n return `\n(function() {\n // Don't run inside the Annotask shell\n if (window.location.pathname.startsWith('/__annotask')) return;\n // Don't run if already initialized\n if (window.__ANNOTASK_BRIDGE__) return;\n window.__ANNOTASK_BRIDGE__ = true;\n\n // ── Element Registry ──────────────────────────────────\n var eidCounter = 0;\n var eidMap = new Map(); // eid string → WeakRef<Element>\n var elToEid = new WeakMap(); // Element → eid string\n\n function getEid(el) {\n if (!el) return null;\n var existing = elToEid.get(el);\n if (existing) return existing;\n eidCounter++;\n var eid = 'e-' + eidCounter;\n eidMap.set(eid, new WeakRef(el));\n elToEid.set(el, eid);\n return eid;\n }\n\n function getEl(eid) {\n var ref = eidMap.get(eid);\n return ref ? ref.deref() || null : null;\n }\n\n // ── PostMessage Helpers ───────────────────────────────\n var shellOrigin = '*'; // Will be tightened on first shell message\n\n function sendToShell(type, payload, id) {\n var msg = { type: type, payload: payload || {}, source: 'annotask-client' };\n if (id) msg.id = id;\n window.parent.postMessage(msg, shellOrigin);\n }\n\n function respond(id, payload) {\n sendToShell(null, payload, id);\n // type is not needed for responses — shell matches by id\n }\n\n // ── Source Element Resolution ─────────────────────────\n function hasSourceAttr(el) {\n return el.hasAttribute && (el.hasAttribute('data-annotask-file') || el.hasAttribute('data-astro-source-file'));\n }\n\n function findSourceElement(el) {\n var c = el;\n while (c) {\n if (hasSourceAttr(c)) return { sourceEl: c, targetEl: el };\n c = c.parentElement;\n }\n return { sourceEl: el, targetEl: el };\n }\n\n function getSourceData(el) {\n // Prefer data-annotask-* attributes, fall back to data-astro-source-* (Astro framework)\n var file = el.getAttribute('data-annotask-file') || '';\n var line = el.getAttribute('data-annotask-line') || '';\n var component = el.getAttribute('data-annotask-component') || '';\n\n if (!file && el.getAttribute('data-astro-source-file')) {\n var astroFile = el.getAttribute('data-astro-source-file') || '';\n // Convert absolute path to project-relative by finding src/ prefix\n var srcIdx = astroFile.indexOf('/src/');\n file = srcIdx !== -1 ? astroFile.slice(srcIdx + 1) : astroFile;\n }\n if ((!line || line === '0') && el.getAttribute('data-astro-source-loc')) {\n // data-astro-source-loc format: \"line:col\"\n line = (el.getAttribute('data-astro-source-loc') || '').split(':')[0];\n }\n if (!component && file) {\n // Derive component name from file path\n var parts = file.split('/');\n var fileName = parts[parts.length - 1] || '';\n component = fileName.replace(/\\.[^.]+$/, '');\n }\n\n var mfe = el.getAttribute('data-annotask-mfe') || '';\n\n return { file: file, line: line, component: component, mfe: mfe };\n }\n\n function getRect(el) {\n var r = el.getBoundingClientRect();\n return { x: r.x, y: r.y, width: r.width, height: r.height };\n }\n\n // ── Interaction Mode ──────────────────────────────────\n var currentMode = 'select';\n var inspectModes = { select: true, pin: true };\n\n // ── Event Handlers ────────────────────────────────────\n var lastHoverEid = null;\n var rafPending = false;\n var pendingHoverData = null;\n\n function onMouseOver(e) {\n if (!inspectModes[currentMode]) return;\n var el = e.target;\n if (!el || el === document.documentElement || el === document.body) return;\n var eid = getEid(el);\n if (eid === lastHoverEid) return;\n lastHoverEid = eid;\n\n var source = findSourceElement(el);\n var data = getSourceData(source.sourceEl);\n\n pendingHoverData = {\n eid: eid,\n tag: el.tagName.toLowerCase(),\n file: data.file,\n component: data.component,\n rect: getRect(el)\n };\n\n if (!rafPending) {\n rafPending = true;\n requestAnimationFrame(function() {\n rafPending = false;\n if (pendingHoverData) sendToShell('hover:enter', pendingHoverData);\n });\n }\n }\n\n function onMouseOut(e) {\n if (!inspectModes[currentMode]) return;\n // Only fire leave when truly leaving all elements\n if (e.relatedTarget && e.relatedTarget !== document.documentElement) return;\n lastHoverEid = null;\n pendingHoverData = null;\n sendToShell('hover:leave', {});\n }\n\n function onClick(e) {\n if (!inspectModes[currentMode]) return;\n e.preventDefault();\n e.stopPropagation();\n\n var el = e.target;\n if (!el) return;\n\n var source = findSourceElement(el);\n var data = getSourceData(source.sourceEl);\n var targetEl = source.targetEl;\n var classes = typeof targetEl.className === 'string' ? targetEl.className : '';\n\n sendToShell('click:element', {\n eid: getEid(targetEl),\n sourceEid: getEid(source.sourceEl),\n file: data.file,\n line: data.line,\n component: data.component,\n mfe: data.mfe,\n tag: targetEl.tagName.toLowerCase(),\n classes: classes,\n rect: getRect(targetEl),\n shiftKey: e.shiftKey,\n clientX: e.clientX,\n clientY: e.clientY\n });\n }\n\n function onMouseDown(e) {\n if (!inspectModes[currentMode]) return;\n e.stopPropagation();\n }\n\n function onMouseUp(e) {\n if (currentMode !== 'highlight') return;\n var sel = document.getSelection();\n var text = sel ? sel.toString().trim() : '';\n if (!text || text.length < 2) return;\n var anchorEl = sel.anchorNode ? sel.anchorNode.parentElement : null;\n if (!anchorEl) return;\n var source = findSourceElement(anchorEl);\n var data = getSourceData(source.sourceEl);\n\n sendToShell('selection:text', {\n text: text,\n eid: getEid(anchorEl),\n file: data.file,\n line: parseInt(data.line) || 0,\n component: data.component,\n mfe: data.mfe,\n tag: anchorEl.tagName.toLowerCase()\n });\n }\n\n function onContextMenu(e) {\n if (currentMode === 'interact') return;\n e.preventDefault();\n var el = e.target;\n if (!el) return;\n var source = findSourceElement(el);\n var data = getSourceData(source.sourceEl);\n var targetEl = source.targetEl;\n var classes = typeof targetEl.className === 'string' ? targetEl.className : '';\n\n sendToShell('contextmenu:element', {\n eid: getEid(targetEl),\n sourceEid: getEid(source.sourceEl),\n file: data.file,\n line: data.line,\n component: data.component,\n mfe: data.mfe,\n tag: targetEl.tagName.toLowerCase(),\n classes: classes,\n rect: getRect(targetEl),\n shiftKey: false,\n clientX: e.clientX,\n clientY: e.clientY\n });\n }\n\n function onKeyDown(e) {\n if ((e.ctrlKey || e.metaKey) && e.key === 'z' && !e.shiftKey) {\n e.preventDefault();\n sendToShell('keydown', { key: e.key, ctrlKey: e.ctrlKey, metaKey: e.metaKey, shiftKey: e.shiftKey });\n }\n }\n\n // Install event listeners\n document.addEventListener('mouseover', onMouseOver, { capture: true });\n document.addEventListener('mouseout', onMouseOut, { capture: true });\n document.addEventListener('mousedown', onMouseDown, { capture: true });\n document.addEventListener('click', onClick, { capture: true });\n document.addEventListener('mouseup', onMouseUp, { capture: true });\n document.addEventListener('keydown', onKeyDown, { capture: true });\n document.addEventListener('contextmenu', onContextMenu, { capture: true });\n\n // ── Route Tracking ────────────────────────────────────\n var lastRoute = window.location.pathname;\n\n function checkRoute() {\n var path = window.location.pathname;\n if (path !== lastRoute) {\n lastRoute = path;\n sendToShell('route:changed', { path: path });\n }\n }\n\n window.addEventListener('popstate', checkRoute);\n window.addEventListener('hashchange', checkRoute);\n setInterval(checkRoute, 2000); // safety net for pushState\n\n // ── Message Handler ───────────────────────────────────\n window.addEventListener('message', function(event) {\n var msg = event.data;\n if (!msg || msg.source !== 'annotask-shell') return;\n // Tighten origin on first shell message\n if (shellOrigin === '*' && event.origin) shellOrigin = event.origin;\n\n var type = msg.type;\n var payload = msg.payload || {};\n var id = msg.id;\n\n // ── Mode ──\n if (type === 'mode:set') {\n currentMode = payload.mode || 'select';\n return;\n }\n\n // ── Ping ──\n if (type === 'bridge:ping') {\n respond(id, {});\n return;\n }\n\n // ── Element Resolution ──\n if (type === 'resolve:at-point') {\n var el = document.elementFromPoint(payload.x, payload.y);\n if (!el || el === document.documentElement || el === document.body) {\n respond(id, null);\n return;\n }\n var src = findSourceElement(el);\n var srcData = getSourceData(src.sourceEl);\n respond(id, {\n eid: getEid(src.targetEl),\n file: srcData.file,\n line: srcData.line,\n component: srcData.component,\n mfe: srcData.mfe,\n tag: src.sourceEl.tagName.toLowerCase(),\n rect: getRect(src.sourceEl),\n classes: typeof src.targetEl.className === 'string' ? src.targetEl.className : ''\n });\n return;\n }\n\n if (type === 'resolve:template-group') {\n var all = document.querySelectorAll(\n '[data-annotask-file=\"' + payload.file + '\"][data-annotask-line=\"' + payload.line + '\"]'\n );\n // Also check Astro source attributes\n if (all.length === 0 && payload.file && payload.line) {\n // Try matching by astro source attributes (absolute path ends with file, loc starts with line)\n var astroAll = document.querySelectorAll('[data-astro-source-file]');\n var matched = [];\n for (var ai = 0; ai < astroAll.length; ai++) {\n var af = astroAll[ai].getAttribute('data-astro-source-file') || '';\n var al = (astroAll[ai].getAttribute('data-astro-source-loc') || '').split(':')[0];\n if (af.endsWith('/' + payload.file) && al === payload.line) matched.push(astroAll[ai]);\n }\n if (matched.length > 0) all = matched;\n }\n var eids = [];\n var rects = [];\n for (var i = 0; i < all.length; i++) {\n if (all[i].tagName.toLowerCase() === payload.tagName) {\n eids.push(getEid(all[i]));\n rects.push(getRect(all[i]));\n }\n }\n respond(id, { eids: eids, rects: rects });\n return;\n }\n\n if (type === 'resolve:rect') {\n var rEl = getEl(payload.eid);\n respond(id, rEl ? { rect: getRect(rEl) } : null);\n return;\n }\n\n if (type === 'resolve:rects') {\n var results = [];\n for (var j = 0; j < payload.eids.length; j++) {\n var re = getEl(payload.eids[j]);\n results.push(re ? getRect(re) : null);\n }\n respond(id, { rects: results });\n return;\n }\n\n // ── Style Operations ──\n if (type === 'style:get-computed') {\n var sEl = getEl(payload.eid);\n if (!sEl) { respond(id, { styles: {} }); return; }\n var cs = window.getComputedStyle(sEl);\n var styles = {};\n for (var k = 0; k < payload.properties.length; k++) {\n styles[payload.properties[k]] = cs.getPropertyValue(payload.properties[k]);\n }\n respond(id, { styles: styles });\n return;\n }\n\n if (type === 'style:apply') {\n var aEl = getEl(payload.eid);\n if (!aEl) { respond(id, { before: '' }); return; }\n var before = window.getComputedStyle(aEl).getPropertyValue(payload.property);\n aEl.style.setProperty(payload.property, payload.value);\n respond(id, { before: before });\n return;\n }\n\n if (type === 'style:apply-batch') {\n var befores = [];\n for (var m = 0; m < payload.eids.length; m++) {\n var bEl = getEl(payload.eids[m]);\n if (bEl) {\n befores.push(window.getComputedStyle(bEl).getPropertyValue(payload.property));\n bEl.style.setProperty(payload.property, payload.value);\n } else {\n befores.push('');\n }\n }\n respond(id, { befores: befores });\n return;\n }\n\n if (type === 'style:undo') {\n var uEl = getEl(payload.eid);\n if (uEl) {\n if (payload.value) uEl.style.setProperty(payload.property, payload.value);\n else uEl.style.removeProperty(payload.property);\n }\n respond(id, {});\n return;\n }\n\n if (type === 'class:get') {\n var cEl = getEl(payload.eid);\n respond(id, { classes: cEl ? (typeof cEl.className === 'string' ? cEl.className : '') : '' });\n return;\n }\n\n if (type === 'class:set') {\n var csEl = getEl(payload.eid);\n if (!csEl) { respond(id, { before: '' }); return; }\n var classBefore = typeof csEl.className === 'string' ? csEl.className : '';\n csEl.className = payload.classes;\n respond(id, { before: classBefore });\n return;\n }\n\n if (type === 'class:set-batch') {\n var classBefores = [];\n for (var n = 0; n < payload.eids.length; n++) {\n var cbEl = getEl(payload.eids[n]);\n if (cbEl) {\n classBefores.push(typeof cbEl.className === 'string' ? cbEl.className : '');\n cbEl.className = payload.classes;\n } else {\n classBefores.push('');\n }\n }\n respond(id, { befores: classBefores });\n return;\n }\n\n if (type === 'class:undo') {\n var cuEl = getEl(payload.eid);\n if (cuEl) cuEl.className = payload.classes;\n respond(id, {});\n return;\n }\n\n // ── Classification ──\n if (type === 'classify:element') {\n var clEl = getEl(payload.eid);\n if (!clEl) { respond(id, null); return; }\n var tag = clEl.tagName.toLowerCase();\n var clCs = window.getComputedStyle(clEl);\n var display = clCs.display;\n var childCount = clEl.children.length;\n var isFlex = display.includes('flex');\n var isGrid = display.includes('grid');\n var semanticContainers = ['section','main','aside','nav','header','footer','article'];\n var role = 'content';\n if (clEl.hasAttribute('data-annotask-component')) {\n var comp = clEl.getAttribute('data-annotask-component') || '';\n if (comp && comp[0] === comp[0].toUpperCase() && comp[0] !== comp[0].toLowerCase()) {\n role = 'component';\n }\n }\n if (role !== 'component' && (isFlex || isGrid) && childCount > 0) role = 'container';\n if (role !== 'component' && role !== 'container' && semanticContainers.indexOf(tag) >= 0 && childCount > 0) role = 'container';\n\n respond(id, {\n role: role,\n display: display,\n isFlexContainer: isFlex,\n isGridContainer: isGrid,\n flexDirection: isFlex ? clCs.flexDirection : undefined,\n childCount: childCount,\n isComponentUnit: role === 'component'\n });\n return;\n }\n\n // ── Layout Scan ──\n if (type === 'layout:scan') {\n var layoutResults = [];\n var allEls = document.querySelectorAll('*');\n for (var li = 0; li < allEls.length; li++) {\n var lEl = allEls[li];\n if (lEl.nodeType !== 1) continue;\n var lCs = window.getComputedStyle(lEl);\n var lDisplay = lCs.display;\n if (!lDisplay.includes('flex') && !lDisplay.includes('grid')) continue;\n var lRect = lEl.getBoundingClientRect();\n if (lRect.width < 20 || lRect.height < 20) continue;\n var lIsGrid = lDisplay.includes('grid');\n var entry = {\n eid: getEid(lEl),\n display: lIsGrid ? 'grid' : 'flex',\n direction: lIsGrid ? 'grid' : lCs.flexDirection,\n rect: { x: lRect.x, y: lRect.y, width: lRect.width, height: lRect.height },\n columnGap: parseFloat(lCs.columnGap) || 0,\n rowGap: parseFloat(lCs.rowGap) || 0\n };\n if (lIsGrid) {\n var cols = lCs.gridTemplateColumns;\n var rows = lCs.gridTemplateRows;\n entry.templateColumns = cols;\n entry.templateRows = rows;\n if (cols && cols !== 'none') {\n entry.columns = cols.split(/\\\\s+/).map(function(s) { return parseFloat(s) || 0; }).filter(function(v) { return v > 0; });\n }\n if (rows && rows !== 'none') {\n entry.rows = rows.split(/\\\\s+/).map(function(s) { return parseFloat(s) || 0; }).filter(function(v) { return v > 0; });\n }\n }\n layoutResults.push(entry);\n }\n respond(id, { containers: layoutResults });\n return;\n }\n\n if (type === 'layout:add-track') {\n var ltEl = getEl(payload.eid);\n if (!ltEl) { respond(id, { property: '', before: '', after: '' }); return; }\n var ltCs = window.getComputedStyle(ltEl);\n var cssProp = payload.axis === 'col' ? 'grid-template-columns' : 'grid-template-rows';\n var ltBefore = ltCs.getPropertyValue(cssProp) || '';\n var ltAfter = ltBefore && ltBefore !== 'none' ? ltBefore + ' 1fr' : '1fr';\n ltEl.style.setProperty(cssProp, ltAfter);\n respond(id, { property: cssProp, before: ltBefore, after: ltAfter });\n return;\n }\n\n if (type === 'layout:add-child') {\n var lcEl = getEl(payload.eid);\n if (!lcEl) { respond(id, { childEid: '' }); return; }\n var child = document.createElement('div');\n child.style.minWidth = '60px';\n child.style.minHeight = '40px';\n child.style.border = '2px dashed #a855f7';\n child.style.borderRadius = '4px';\n child.style.background = 'rgba(168,85,247,0.05)';\n child.setAttribute('data-annotask-placeholder', 'true');\n lcEl.appendChild(child);\n respond(id, { childEid: getEid(child) });\n return;\n }\n\n // ── Theme ──\n if (type === 'theme:inject-css') {\n var existing = document.getElementById(payload.styleId);\n if (existing) {\n existing.textContent = payload.css;\n } else {\n var style = document.createElement('style');\n style.id = payload.styleId;\n style.textContent = payload.css;\n document.head.appendChild(style);\n }\n respond(id, {});\n return;\n }\n\n if (type === 'theme:remove-css') {\n var toRemove = document.getElementById(payload.styleId);\n if (toRemove) toRemove.remove();\n respond(id, {});\n return;\n }\n\n // ── Color Palette ──\n if (type === 'palette:scan-vars') {\n var swatches = [];\n try {\n var rootStyles = window.getComputedStyle(document.documentElement);\n var sheets = document.styleSheets;\n for (var si = 0; si < sheets.length; si++) {\n try {\n var rules = sheets[si].cssRules;\n for (var ri = 0; ri < rules.length; ri++) {\n var rule = rules[ri];\n if (rule.selectorText === ':root' || rule.selectorText === ':root, :host') {\n for (var pi = 0; pi < rule.style.length; pi++) {\n var prop = rule.style[pi];\n if (prop.startsWith('--')) {\n var val = rootStyles.getPropertyValue(prop).trim();\n if (val && isColor(val)) {\n swatches.push({ name: prop, value: val });\n }\n }\n }\n }\n }\n } catch(e) { /* cross-origin stylesheet */ }\n }\n } catch(e) {}\n respond(id, { swatches: swatches });\n return;\n }\n\n // ── Source Mapping Check ──\n if (type === 'check:source-mapping') {\n respond(id, { hasMapping: !!(document.querySelector('[data-annotask-file]') || document.querySelector('[data-astro-source-file]')) });\n return;\n }\n\n // ── Insert Placeholder ──\n if (type === 'insert:placeholder') {\n var ipTarget = getEl(payload.targetEid);\n if (!ipTarget) { respond(id, { placeholderEid: '' }); return; }\n var ipEl = createPlaceholder(payload);\n var ipRef = ipTarget;\n switch (payload.position) {\n case 'before': ipRef.parentElement && ipRef.parentElement.insertBefore(ipEl, ipRef); break;\n case 'after': ipRef.parentElement && ipRef.parentElement.insertBefore(ipEl, ipRef.nextSibling); break;\n case 'append': ipRef.appendChild(ipEl); break;\n case 'prepend': ipRef.insertBefore(ipEl, ipRef.firstChild); break;\n }\n // Match sibling sizes in flex/grid\n var insertParent = (payload.position === 'append' || payload.position === 'prepend') ? ipRef : ipRef.parentElement;\n if (insertParent) {\n var pCs = window.getComputedStyle(insertParent);\n if (pCs.display.includes('flex') || pCs.display.includes('grid')) {\n if (!ipEl.style.width) {\n var isRow = pCs.flexDirection === 'row' || pCs.flexDirection === 'row-reverse' || pCs.display.includes('grid');\n if (isRow) ipEl.style.flex = '1';\n }\n }\n }\n respond(id, { placeholderEid: getEid(ipEl) });\n return;\n }\n\n if (type === 'insert:remove') {\n var irEl = getEl(payload.eid);\n if (irEl) {\n var unmount = irEl.__annotask_unmount;\n if (unmount) unmount();\n irEl.remove();\n }\n respond(id, {});\n return;\n }\n\n if (type === 'move:element') {\n var meEl = getEl(payload.eid);\n var meTarget = getEl(payload.targetEid);\n if (meEl && meTarget) {\n switch (payload.position) {\n case 'before': meTarget.parentElement && meTarget.parentElement.insertBefore(meEl, meTarget); break;\n case 'after': meTarget.parentElement && meTarget.parentElement.insertBefore(meEl, meTarget.nextSibling); break;\n case 'append': meTarget.appendChild(meEl); break;\n case 'prepend': meTarget.insertBefore(meEl, meTarget.firstChild); break;\n }\n }\n respond(id, {});\n return;\n }\n\n if (type === 'insert:vue-component' || type === 'insert:component') {\n var vcTarget = getEl(payload.targetEid);\n if (!vcTarget) { respond(id, { eid: '', mounted: false }); return; }\n var vcContainer = document.createElement('div');\n vcContainer.setAttribute('data-annotask-placeholder', 'true');\n switch (payload.position) {\n case 'before': vcTarget.parentElement && vcTarget.parentElement.insertBefore(vcContainer, vcTarget); break;\n case 'after': vcTarget.parentElement && vcTarget.parentElement.insertBefore(vcContainer, vcTarget.nextSibling); break;\n case 'append': vcTarget.appendChild(vcContainer); break;\n case 'prepend': vcTarget.insertBefore(vcContainer, vcTarget.firstChild); break;\n }\n var mounted = tryMountComponent(vcContainer, payload.componentName, payload.props);\n respond(id, { eid: getEid(vcContainer), mounted: mounted });\n return;\n }\n\n // ── Get source data for an eid ──\n if (type === 'resolve:source') {\n var rsEl = getEl(payload.eid);\n if (!rsEl) { respond(id, null); return; }\n var rsSrc = findSourceElement(rsEl);\n var rsData = getSourceData(rsSrc.sourceEl);\n respond(id, {\n sourceEid: getEid(rsSrc.sourceEl),\n file: rsData.file,\n line: rsData.line,\n component: rsData.component,\n tag: rsSrc.sourceEl.tagName.toLowerCase()\n });\n return;\n }\n\n // ── Route ──\n if (type === 'route:current') {\n respond(id, { path: window.location.pathname });\n return;\n }\n });\n\n // ── Helpers ───────────────────────────────────────────\n function isColor(val) {\n if (val.startsWith('#') || val.startsWith('rgb') || val.startsWith('hsl')) return true;\n // Named colors — quick check with canvas\n try {\n var ctx = document.createElement('canvas').getContext('2d');\n ctx.fillStyle = '#000000';\n ctx.fillStyle = val;\n return ctx.fillStyle !== '#000000' || val === 'black' || val === '#000000';\n } catch(e) { return false; }\n }\n\n function createPlaceholder(payload) {\n var el = document.createElement(payload.tag);\n el.setAttribute('data-annotask-placeholder', 'true');\n if (payload.classes) el.className = payload.classes;\n var tag = payload.tag.toLowerCase();\n var isComponent = payload.tag.includes('-') || (payload.tag[0] === payload.tag[0].toUpperCase() && payload.tag[0] !== payload.tag[0].toLowerCase());\n\n if (tag === 'button') {\n el.textContent = payload.textContent || 'Button';\n el.style.cssText = 'padding:8px 16px;border-radius:6px;font-size:14px;font-weight:500;cursor:pointer;border:1px solid currentColor;background:var(--accent,#3b82f6);color:white;';\n } else if (tag === 'input') {\n el.type = 'text'; el.placeholder = 'Input field...';\n el.style.cssText = 'padding:8px 12px;border:1px solid #ccc;border-radius:6px;font-size:14px;width:100%;max-width:300px;background:white;color:#333;';\n } else if (tag === 'textarea') {\n el.placeholder = 'Text area...';\n el.style.cssText = 'padding:8px 12px;border:1px solid #ccc;border-radius:6px;font-size:14px;width:100%;min-height:60px;background:white;color:#333;resize:vertical;';\n } else if (tag === 'img') {\n el.style.cssText = 'width:200px;height:120px;background:#e5e7eb;border-radius:8px;display:flex;align-items:center;justify-content:center;';\n } else if (['h1','h2','h3','h4','h5','h6'].indexOf(tag) >= 0) {\n el.textContent = payload.textContent || 'Heading';\n var sizes = { h1:'2em', h2:'1.5em', h3:'1.25em', h4:'1.1em', h5:'1em', h6:'0.9em' };\n el.style.cssText = 'font-size:' + (sizes[tag]||'1em') + ';font-weight:700;margin:0.5em 0;';\n } else if (tag === 'p') {\n el.textContent = payload.textContent || 'Paragraph text goes here.';\n el.style.cssText = 'margin:0.5em 0;line-height:1.5;';\n } else if (tag === 'a') {\n el.textContent = payload.textContent || 'Link';\n el.style.cssText = 'color:var(--accent,#3b82f6);text-decoration:underline;cursor:pointer;';\n } else if (tag === 'section' || tag === 'div' || tag === 'nav' || tag === 'header' || tag === 'footer' || tag === 'aside' || tag === 'main') {\n if (!payload.classes && !payload.textContent) {\n el.style.cssText = 'min-height:40px;padding:12px;border:1.5px dashed rgba(59,130,246,0.3);border-radius:6px;background:rgba(59,130,246,0.03);';\n } else if (payload.textContent) {\n el.textContent = payload.textContent;\n }\n if (payload.category === 'layout-preset') {\n el.style.minHeight = '60px';\n el.style.padding = el.style.padding || '12px';\n el.style.border = '1.5px dashed rgba(34,197,94,0.3)';\n el.style.borderRadius = '6px';\n el.style.background = 'rgba(34,197,94,0.03)';\n }\n } else if (isComponent) {\n var vcMounted = tryMountComponent(el, payload.tag, payload.defaultProps);\n if (!vcMounted) {\n el.style.cssText = 'min-height:80px;padding:16px;border:1px solid rgba(168,85,247,0.2);border-radius:8px;background:rgba(168,85,247,0.03);display:flex;flex-direction:column;gap:8px;overflow:hidden;';\n var hdr = document.createElement('div');\n hdr.style.cssText = 'display:flex;align-items:center;gap:6px;margin-bottom:4px;';\n var dot = document.createElement('span');\n dot.style.cssText = 'width:6px;height:6px;border-radius:50%;background:#a855f7;';\n hdr.appendChild(dot);\n var tagLabel = document.createElement('span');\n tagLabel.style.cssText = 'font-size:11px;font-weight:600;color:#a855f7;';\n tagLabel.textContent = payload.tag;\n hdr.appendChild(tagLabel);\n el.appendChild(hdr);\n }\n } else {\n el.textContent = payload.textContent || '';\n }\n return el;\n }\n\n function tryMountComponent(container, componentName, props) {\n // Try Vue\n if (window.__ANNOTASK_VUE__) {\n var mounted = tryMountVueComponent(container, componentName, props);\n if (mounted) return true;\n }\n // Try React\n if (window.__ANNOTASK_REACT__) {\n var mounted = tryMountReactComponent(container, componentName, props);\n if (mounted) return true;\n }\n // Try Svelte\n if (window.__ANNOTASK_SVELTE__) {\n var mounted = tryMountSvelteComponent(container, componentName, props);\n if (mounted) return true;\n }\n return false;\n }\n\n function tryMountVueComponent(container, componentName, props) {\n try {\n var appEl = document.querySelector('#app');\n var vueApp = appEl && appEl.__vue_app__;\n if (!vueApp) return false;\n var annotaskVue = window.__ANNOTASK_VUE__;\n if (!annotaskVue || !annotaskVue.createApp || !annotaskVue.h) return false;\n var component = vueApp._context.components[componentName] || (window.__ANNOTASK_COMPONENTS__ && window.__ANNOTASK_COMPONENTS__[componentName]);\n if (!component) return false;\n var mountPoint = document.createElement('div');\n container.appendChild(mountPoint);\n var miniApp = annotaskVue.createApp({\n render: function() { return annotaskVue.h(component, props || {}); }\n });\n miniApp._context = vueApp._context;\n miniApp.mount(mountPoint);\n container.setAttribute('data-annotask-mounted', 'true');\n container.__annotask_unmount = function() { try { miniApp.unmount(); } catch(e) {} };\n return true;\n } catch(e) { return false; }\n }\n\n function tryMountReactComponent(container, componentName, props) {\n try {\n var annotaskReact = window.__ANNOTASK_REACT__;\n if (!annotaskReact || !annotaskReact.createElement || !annotaskReact.createRoot) return false;\n var component = window.__ANNOTASK_COMPONENTS__ && window.__ANNOTASK_COMPONENTS__[componentName];\n if (!component) return false;\n var mountPoint = document.createElement('div');\n container.appendChild(mountPoint);\n var root = annotaskReact.createRoot(mountPoint);\n root.render(annotaskReact.createElement(component, props || {}));\n container.setAttribute('data-annotask-mounted', 'true');\n container.__annotask_unmount = function() { try { root.unmount(); } catch(e) {} };\n return true;\n } catch(e) { return false; }\n }\n\n function tryMountSvelteComponent(container, componentName, props) {\n try {\n var annotaskSvelte = window.__ANNOTASK_SVELTE__;\n if (!annotaskSvelte || !annotaskSvelte.mount) return false;\n var component = window.__ANNOTASK_COMPONENTS__ && window.__ANNOTASK_COMPONENTS__[componentName];\n if (!component) return false;\n var mountPoint = document.createElement('div');\n container.appendChild(mountPoint);\n var instance = annotaskSvelte.mount(component, { target: mountPoint, props: props || {} });\n container.setAttribute('data-annotask-mounted', 'true');\n container.__annotask_unmount = function() {\n try {\n if (annotaskSvelte.unmount) annotaskSvelte.unmount(instance);\n } catch(e) {}\n };\n return true;\n } catch(e) { return false; }\n }\n\n // ── Ready ─────────────────────────────────────────────\n sendToShell('bridge:ready', { version: '1.0' });\n})();\n`.trim()\n}\n"],"mappings":";AAKO,SAAS,mBAAmB,WAA4B;AAC7D,QAAM,cAAc,YAAY,GAAG,SAAS,iBAAiB;AAC7D,SAAO;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,iBA2CQ,WAAW;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAM1B,KAAK;AACP;;;ACjDO,SAAS,qBAA6B;AAC3C,SAAO;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAuzBP,KAAK;AACP;","names":[]}
|
|
@@ -0,0 +1,362 @@
|
|
|
1
|
+
// src/plugin/transform.ts
|
|
2
|
+
function transformFile(code, filePath, projectRoot, mfe) {
|
|
3
|
+
if (filePath.endsWith(".vue")) return transformVueSFC(code, filePath, projectRoot, mfe);
|
|
4
|
+
if (filePath.endsWith(".svelte")) return transformSvelte(code, filePath, projectRoot, mfe);
|
|
5
|
+
if (/\.[jt]sx$/.test(filePath)) return transformJSX(code, filePath, projectRoot, mfe);
|
|
6
|
+
if (filePath.endsWith(".html")) return transformHTML(code, filePath, projectRoot, mfe);
|
|
7
|
+
if (filePath.endsWith(".astro")) return transformAstro(code, filePath, projectRoot, mfe);
|
|
8
|
+
return null;
|
|
9
|
+
}
|
|
10
|
+
function transformVueSFC(code, filePath, projectRoot, mfe) {
|
|
11
|
+
if (!code.includes("<template")) return null;
|
|
12
|
+
const templateMatch = code.match(/<template(\s[^>]*)?>/);
|
|
13
|
+
if (!templateMatch) return null;
|
|
14
|
+
const templateStart = code.indexOf(templateMatch[0]);
|
|
15
|
+
const templateEnd = code.lastIndexOf("</template>");
|
|
16
|
+
if (templateEnd === -1) return null;
|
|
17
|
+
const templateOpenTagEnd = templateStart + templateMatch[0].length;
|
|
18
|
+
const templateContent = code.slice(templateOpenTagEnd, templateEnd);
|
|
19
|
+
const relativeFile = relativePath(filePath, projectRoot);
|
|
20
|
+
const componentName = extractComponentName(filePath);
|
|
21
|
+
const templateStartLine = code.slice(0, templateOpenTagEnd).split("\n").length;
|
|
22
|
+
const injected = injectAttributes(templateContent, relativeFile, componentName, templateStartLine, { mfe });
|
|
23
|
+
if (!injected) return null;
|
|
24
|
+
return code.slice(0, templateOpenTagEnd) + injected + code.slice(templateEnd);
|
|
25
|
+
}
|
|
26
|
+
function transformSvelte(code, filePath, projectRoot, mfe) {
|
|
27
|
+
const relativeFile = relativePath(filePath, projectRoot);
|
|
28
|
+
const componentName = extractComponentName(filePath);
|
|
29
|
+
const blockRanges = findBlockRanges(code, ["script", "style"]);
|
|
30
|
+
const markupRegions = getMarkupRegions(code, blockRanges);
|
|
31
|
+
if (markupRegions.length === 0) return null;
|
|
32
|
+
let result = "";
|
|
33
|
+
let lastIndex = 0;
|
|
34
|
+
let changed = false;
|
|
35
|
+
for (const region of markupRegions) {
|
|
36
|
+
result += code.slice(lastIndex, region.start);
|
|
37
|
+
const regionContent = code.slice(region.start, region.end);
|
|
38
|
+
const regionStartLine = code.slice(0, region.start).split("\n").length;
|
|
39
|
+
const injected = injectAttributes(
|
|
40
|
+
regionContent,
|
|
41
|
+
relativeFile,
|
|
42
|
+
componentName,
|
|
43
|
+
regionStartLine,
|
|
44
|
+
{ skipTags: SVELTE_SKIP_TAGS, mfe }
|
|
45
|
+
);
|
|
46
|
+
if (injected) {
|
|
47
|
+
result += injected;
|
|
48
|
+
changed = true;
|
|
49
|
+
} else {
|
|
50
|
+
result += regionContent;
|
|
51
|
+
}
|
|
52
|
+
lastIndex = region.end;
|
|
53
|
+
}
|
|
54
|
+
if (!changed) return null;
|
|
55
|
+
result += code.slice(lastIndex);
|
|
56
|
+
return result;
|
|
57
|
+
}
|
|
58
|
+
var SVELTE_SKIP_TAGS = /* @__PURE__ */ new Set([
|
|
59
|
+
"script",
|
|
60
|
+
"style",
|
|
61
|
+
"svelte:head",
|
|
62
|
+
"svelte:window",
|
|
63
|
+
"svelte:document",
|
|
64
|
+
"svelte:body",
|
|
65
|
+
"svelte:options",
|
|
66
|
+
"svelte:fragment",
|
|
67
|
+
"svelte:self",
|
|
68
|
+
"svelte:component",
|
|
69
|
+
"svelte:element",
|
|
70
|
+
"svelte:boundary"
|
|
71
|
+
]);
|
|
72
|
+
function transformJSX(code, filePath, projectRoot, mfe) {
|
|
73
|
+
const relativeFile = relativePath(filePath, projectRoot);
|
|
74
|
+
const componentName = extractComponentName(filePath);
|
|
75
|
+
const injected = injectAttributes(code, relativeFile, componentName, 1, {
|
|
76
|
+
jsxMode: true,
|
|
77
|
+
skipTags: JSX_SKIP_TAGS,
|
|
78
|
+
mfe
|
|
79
|
+
});
|
|
80
|
+
return injected;
|
|
81
|
+
}
|
|
82
|
+
var JSX_SKIP_TAGS = /* @__PURE__ */ new Set(["script", "style"]);
|
|
83
|
+
function transformHTML(code, filePath, projectRoot, mfe) {
|
|
84
|
+
const bodyMatch = code.match(/<body(\s[^>]*)?>/);
|
|
85
|
+
if (!bodyMatch) return null;
|
|
86
|
+
const bodyStart = code.indexOf(bodyMatch[0]);
|
|
87
|
+
const bodyEnd = code.lastIndexOf("</body>");
|
|
88
|
+
if (bodyEnd === -1) return null;
|
|
89
|
+
const bodyOpenTagEnd = bodyStart + bodyMatch[0].length;
|
|
90
|
+
const bodyContent = code.slice(bodyOpenTagEnd, bodyEnd);
|
|
91
|
+
const relativeFile = relativePath(filePath, projectRoot);
|
|
92
|
+
const componentName = extractComponentName(filePath);
|
|
93
|
+
const bodyStartLine = code.slice(0, bodyOpenTagEnd).split("\n").length;
|
|
94
|
+
const injected = injectAttributes(bodyContent, relativeFile, componentName, bodyStartLine, {
|
|
95
|
+
skipTags: HTML_SKIP_TAGS,
|
|
96
|
+
mfe
|
|
97
|
+
});
|
|
98
|
+
if (!injected) return null;
|
|
99
|
+
return code.slice(0, bodyOpenTagEnd) + injected + code.slice(bodyEnd);
|
|
100
|
+
}
|
|
101
|
+
var HTML_SKIP_TAGS = /* @__PURE__ */ new Set(["script", "style"]);
|
|
102
|
+
function transformAstro(code, filePath, projectRoot, mfe) {
|
|
103
|
+
const relativeFile = relativePath(filePath, projectRoot);
|
|
104
|
+
const componentName = extractComponentName(filePath);
|
|
105
|
+
const frontmatterRanges = [];
|
|
106
|
+
const fmStart = code.indexOf("---");
|
|
107
|
+
if (fmStart !== -1) {
|
|
108
|
+
const fmEnd = code.indexOf("---", fmStart + 3);
|
|
109
|
+
if (fmEnd !== -1) {
|
|
110
|
+
frontmatterRanges.push({ start: fmStart, end: fmEnd + 3 });
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
const blockRanges = [
|
|
114
|
+
...frontmatterRanges,
|
|
115
|
+
...findBlockRanges(code, ["script", "style"])
|
|
116
|
+
];
|
|
117
|
+
blockRanges.sort((a, b) => a.start - b.start);
|
|
118
|
+
const markupRegions = getMarkupRegions(code, blockRanges);
|
|
119
|
+
if (markupRegions.length === 0) return null;
|
|
120
|
+
let result = "";
|
|
121
|
+
let lastIndex = 0;
|
|
122
|
+
let changed = false;
|
|
123
|
+
for (const region of markupRegions) {
|
|
124
|
+
result += code.slice(lastIndex, region.start);
|
|
125
|
+
const regionContent = code.slice(region.start, region.end);
|
|
126
|
+
const regionStartLine = code.slice(0, region.start).split("\n").length;
|
|
127
|
+
const injected = injectAttributes(regionContent, relativeFile, componentName, regionStartLine, {
|
|
128
|
+
jsxMode: true,
|
|
129
|
+
skipTags: ASTRO_SKIP_TAGS,
|
|
130
|
+
mfe
|
|
131
|
+
});
|
|
132
|
+
if (injected) {
|
|
133
|
+
result += injected;
|
|
134
|
+
changed = true;
|
|
135
|
+
} else {
|
|
136
|
+
result += regionContent;
|
|
137
|
+
}
|
|
138
|
+
lastIndex = region.end;
|
|
139
|
+
}
|
|
140
|
+
if (!changed) return null;
|
|
141
|
+
result += code.slice(lastIndex);
|
|
142
|
+
return result;
|
|
143
|
+
}
|
|
144
|
+
var ASTRO_SKIP_TAGS = /* @__PURE__ */ new Set([
|
|
145
|
+
"script",
|
|
146
|
+
"style",
|
|
147
|
+
"Fragment"
|
|
148
|
+
]);
|
|
149
|
+
var TS_GENERIC_NAMES = /* @__PURE__ */ new Set([
|
|
150
|
+
"Array",
|
|
151
|
+
"Map",
|
|
152
|
+
"Set",
|
|
153
|
+
"WeakMap",
|
|
154
|
+
"WeakSet",
|
|
155
|
+
"Promise",
|
|
156
|
+
"Generator",
|
|
157
|
+
"AsyncGenerator",
|
|
158
|
+
"Iterable",
|
|
159
|
+
"AsyncIterable",
|
|
160
|
+
"Iterator",
|
|
161
|
+
"Record",
|
|
162
|
+
"Partial",
|
|
163
|
+
"Required",
|
|
164
|
+
"Readonly",
|
|
165
|
+
"Pick",
|
|
166
|
+
"Omit",
|
|
167
|
+
"Exclude",
|
|
168
|
+
"Extract",
|
|
169
|
+
"NonNullable",
|
|
170
|
+
"ReturnType",
|
|
171
|
+
"Parameters",
|
|
172
|
+
"InstanceType",
|
|
173
|
+
"ConstructorParameters",
|
|
174
|
+
"Awaited",
|
|
175
|
+
"ReadonlyArray",
|
|
176
|
+
"ReadonlyMap",
|
|
177
|
+
"ReadonlySet",
|
|
178
|
+
"Uppercase",
|
|
179
|
+
"Lowercase",
|
|
180
|
+
"Capitalize",
|
|
181
|
+
"Uncapitalize"
|
|
182
|
+
]);
|
|
183
|
+
function extractComponentName(filePath) {
|
|
184
|
+
const fileName = filePath.split("/").pop() || "";
|
|
185
|
+
return fileName.replace(/\.(vue|svelte|astro|html|[jt]sx?)$/, "");
|
|
186
|
+
}
|
|
187
|
+
function relativePath(filePath, projectRoot) {
|
|
188
|
+
return filePath.startsWith(projectRoot) ? filePath.slice(projectRoot.length).replace(/^\//, "") : filePath;
|
|
189
|
+
}
|
|
190
|
+
function injectAttributes(template, file, componentName, templateStartLine, options) {
|
|
191
|
+
const skipTags = options?.skipTags ?? DEFAULT_SKIP_TAGS;
|
|
192
|
+
const jsxMode = options?.jsxMode ?? false;
|
|
193
|
+
const mfe = options?.mfe;
|
|
194
|
+
let result = "";
|
|
195
|
+
let lastIndex = 0;
|
|
196
|
+
let changed = false;
|
|
197
|
+
let i = 0;
|
|
198
|
+
while (i < template.length) {
|
|
199
|
+
if (template.startsWith("<!--", i)) {
|
|
200
|
+
const end = template.indexOf("-->", i + 4);
|
|
201
|
+
i = end === -1 ? template.length : end + 3;
|
|
202
|
+
continue;
|
|
203
|
+
}
|
|
204
|
+
if (template.startsWith("</", i)) {
|
|
205
|
+
const end = template.indexOf(">", i + 2);
|
|
206
|
+
i = end === -1 ? template.length : end + 1;
|
|
207
|
+
continue;
|
|
208
|
+
}
|
|
209
|
+
if (template[i] === "<" && i + 1 < template.length && /[a-zA-Z]/.test(template[i + 1])) {
|
|
210
|
+
const tagStart = i;
|
|
211
|
+
i++;
|
|
212
|
+
const nameStart = i;
|
|
213
|
+
while (i < template.length && /[a-zA-Z0-9\-:]/.test(template[i])) i++;
|
|
214
|
+
const tagName = template.slice(nameStart, i);
|
|
215
|
+
if (jsxMode && TS_GENERIC_NAMES.has(tagName)) {
|
|
216
|
+
i = skipGeneric(template, i);
|
|
217
|
+
continue;
|
|
218
|
+
}
|
|
219
|
+
if (jsxMode && isTypeContext(template, tagStart)) {
|
|
220
|
+
i = skipGeneric(template, i);
|
|
221
|
+
continue;
|
|
222
|
+
}
|
|
223
|
+
if (skipTags.has(tagName) || skipTags.has(tagName.toLowerCase())) {
|
|
224
|
+
i = findTagEnd(template, i, jsxMode);
|
|
225
|
+
continue;
|
|
226
|
+
}
|
|
227
|
+
const tagEndIndex = findTagEnd(template, i, jsxMode);
|
|
228
|
+
const tagSource = template.slice(tagStart, tagEndIndex);
|
|
229
|
+
if (tagSource.includes("data-annotask-file")) {
|
|
230
|
+
i = tagEndIndex;
|
|
231
|
+
continue;
|
|
232
|
+
}
|
|
233
|
+
const lineInFile = templateStartLine + template.slice(0, tagStart).split("\n").length - 1;
|
|
234
|
+
const injection = ` data-annotask-file="${file}" data-annotask-line="${lineInFile}" data-annotask-component="${componentName}"${mfe ? ` data-annotask-mfe="${mfe}"` : ""}`;
|
|
235
|
+
let insertAt = tagEndIndex - 1;
|
|
236
|
+
if (insertAt > 0 && template[insertAt - 1] === "/") insertAt--;
|
|
237
|
+
result += template.slice(lastIndex, insertAt);
|
|
238
|
+
result += injection;
|
|
239
|
+
result += template.slice(insertAt, tagEndIndex);
|
|
240
|
+
lastIndex = tagEndIndex;
|
|
241
|
+
changed = true;
|
|
242
|
+
i = tagEndIndex;
|
|
243
|
+
continue;
|
|
244
|
+
}
|
|
245
|
+
i++;
|
|
246
|
+
}
|
|
247
|
+
if (!changed) return null;
|
|
248
|
+
result += template.slice(lastIndex);
|
|
249
|
+
return result;
|
|
250
|
+
}
|
|
251
|
+
var DEFAULT_SKIP_TAGS = /* @__PURE__ */ new Set(["script", "style", "template", "slot"]);
|
|
252
|
+
function findTagEnd(template, i, jsxMode = false) {
|
|
253
|
+
let inQuote = null;
|
|
254
|
+
let braceDepth = 0;
|
|
255
|
+
while (i < template.length) {
|
|
256
|
+
const ch = template[i];
|
|
257
|
+
if (inQuote === "`") {
|
|
258
|
+
if (ch === "`" && braceDepth === 0) {
|
|
259
|
+
inQuote = null;
|
|
260
|
+
} else if (ch === "$" && i + 1 < template.length && template[i + 1] === "{") {
|
|
261
|
+
braceDepth++;
|
|
262
|
+
i++;
|
|
263
|
+
} else if (ch === "}" && braceDepth > 0) {
|
|
264
|
+
braceDepth--;
|
|
265
|
+
}
|
|
266
|
+
} else if (inQuote) {
|
|
267
|
+
if (ch === inQuote) inQuote = null;
|
|
268
|
+
} else {
|
|
269
|
+
if (ch === '"' || ch === "'" || ch === "`") {
|
|
270
|
+
inQuote = ch;
|
|
271
|
+
} else if (jsxMode && ch === "{") {
|
|
272
|
+
braceDepth++;
|
|
273
|
+
} else if (jsxMode && ch === "}" && braceDepth > 0) {
|
|
274
|
+
braceDepth--;
|
|
275
|
+
} else if (ch === ">" && braceDepth === 0) {
|
|
276
|
+
return i + 1;
|
|
277
|
+
}
|
|
278
|
+
}
|
|
279
|
+
i++;
|
|
280
|
+
}
|
|
281
|
+
return i;
|
|
282
|
+
}
|
|
283
|
+
function findBlockRanges(code, tagNames) {
|
|
284
|
+
const ranges = [];
|
|
285
|
+
for (const tag of tagNames) {
|
|
286
|
+
const openRegex = new RegExp(`<${tag}(\\s[^>]*)?>`, "gi");
|
|
287
|
+
let match;
|
|
288
|
+
while ((match = openRegex.exec(code)) !== null) {
|
|
289
|
+
const start = match.index;
|
|
290
|
+
const closeTag = `</${tag}>`;
|
|
291
|
+
const closeIndex = code.indexOf(closeTag, start + match[0].length);
|
|
292
|
+
if (closeIndex !== -1) {
|
|
293
|
+
ranges.push({ start, end: closeIndex + closeTag.length });
|
|
294
|
+
}
|
|
295
|
+
}
|
|
296
|
+
}
|
|
297
|
+
ranges.sort((a, b) => a.start - b.start);
|
|
298
|
+
return ranges;
|
|
299
|
+
}
|
|
300
|
+
function getMarkupRegions(code, blockRanges) {
|
|
301
|
+
const regions = [];
|
|
302
|
+
let cursor = 0;
|
|
303
|
+
for (const block of blockRanges) {
|
|
304
|
+
if (block.start > cursor) {
|
|
305
|
+
const region = code.slice(cursor, block.start);
|
|
306
|
+
if (region.trim().length > 0) {
|
|
307
|
+
regions.push({ start: cursor, end: block.start });
|
|
308
|
+
}
|
|
309
|
+
}
|
|
310
|
+
cursor = block.end;
|
|
311
|
+
}
|
|
312
|
+
if (cursor < code.length) {
|
|
313
|
+
const region = code.slice(cursor);
|
|
314
|
+
if (region.trim().length > 0) {
|
|
315
|
+
regions.push({ start: cursor, end: code.length });
|
|
316
|
+
}
|
|
317
|
+
}
|
|
318
|
+
return regions;
|
|
319
|
+
}
|
|
320
|
+
function isTypeContext(code, tagStart) {
|
|
321
|
+
let j = tagStart - 1;
|
|
322
|
+
while (j >= 0 && (code[j] === " " || code[j] === " " || code[j] === "\n" || code[j] === "\r")) j--;
|
|
323
|
+
if (j < 0) return false;
|
|
324
|
+
const ch = code[j];
|
|
325
|
+
if (ch === ":" || ch === "<" || ch === ".") return true;
|
|
326
|
+
if (/[a-zA-Z0-9_$]/.test(ch)) {
|
|
327
|
+
let wordEnd = j + 1;
|
|
328
|
+
while (j >= 0 && /[a-zA-Z0-9_$]/.test(code[j])) j--;
|
|
329
|
+
const word = code.slice(j + 1, wordEnd);
|
|
330
|
+
const jsxKeywords = /* @__PURE__ */ new Set(["return", "yield", "case", "default", "throw", "new", "in", "of", "else"]);
|
|
331
|
+
if (jsxKeywords.has(word)) return false;
|
|
332
|
+
return true;
|
|
333
|
+
}
|
|
334
|
+
const typeKeywords = ["as", "extends", "implements", "typeof", "keyof", "infer", "type"];
|
|
335
|
+
for (const kw of typeKeywords) {
|
|
336
|
+
if (j >= kw.length - 1) {
|
|
337
|
+
const slice = code.slice(j - kw.length + 1, j + 1);
|
|
338
|
+
if (slice === kw) {
|
|
339
|
+
const before = j - kw.length;
|
|
340
|
+
if (before < 0 || /\s|[,;({[<>|&=!?+\-*/]/.test(code[before])) {
|
|
341
|
+
return true;
|
|
342
|
+
}
|
|
343
|
+
}
|
|
344
|
+
}
|
|
345
|
+
}
|
|
346
|
+
return false;
|
|
347
|
+
}
|
|
348
|
+
function skipGeneric(code, i) {
|
|
349
|
+
let depth = 1;
|
|
350
|
+
while (i < code.length && depth > 0) {
|
|
351
|
+
if (code[i] === "<") depth++;
|
|
352
|
+
else if (code[i] === ">") depth--;
|
|
353
|
+
i++;
|
|
354
|
+
}
|
|
355
|
+
return i;
|
|
356
|
+
}
|
|
357
|
+
|
|
358
|
+
export {
|
|
359
|
+
transformFile,
|
|
360
|
+
transformHTML
|
|
361
|
+
};
|
|
362
|
+
//# sourceMappingURL=chunk-VU7Z7EZA.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/plugin/transform.ts"],"sourcesContent":["/**\n * Source file transform — injects data-annotask-* attributes on HTML elements.\n *\n * Supports Vue SFC (.vue), React JSX (.jsx/.tsx), Svelte (.svelte),\n * Astro (.astro), Lit/Web Components (html`` in .ts/.js), and plain HTML.\n * The core HTML scanner (injectAttributes + findTagEnd) is shared across\n * all frameworks. Each framework has its own extraction logic to locate\n * the markup regions within a source file.\n */\n\n/**\n * Top-level dispatcher. Detects framework by file extension and delegates\n * to the appropriate transform function.\n */\nexport function transformFile(\n code: string,\n filePath: string,\n projectRoot: string,\n mfe?: string\n): string | null {\n if (filePath.endsWith('.vue')) return transformVueSFC(code, filePath, projectRoot, mfe)\n if (filePath.endsWith('.svelte')) return transformSvelte(code, filePath, projectRoot, mfe)\n if (/\\.[jt]sx$/.test(filePath)) return transformJSX(code, filePath, projectRoot, mfe)\n if (filePath.endsWith('.html')) return transformHTML(code, filePath, projectRoot, mfe)\n if (filePath.endsWith('.astro')) return transformAstro(code, filePath, projectRoot, mfe)\n return null\n}\n\n// ── Vue SFC ─────────────────────────────────────────────\n\n/**\n * Transform a Vue SFC's raw source to inject data-annotask-* attributes\n * on every element in the <template> block.\n */\nexport function transformVueSFC(\n code: string,\n filePath: string,\n projectRoot: string,\n mfe?: string\n): string | null {\n if (!code.includes('<template')) return null\n\n const templateMatch = code.match(/<template(\\s[^>]*)?>/)\n if (!templateMatch) return null\n\n const templateStart = code.indexOf(templateMatch[0])\n const templateEnd = code.lastIndexOf('</template>')\n if (templateEnd === -1) return null\n\n const templateOpenTagEnd = templateStart + templateMatch[0].length\n const templateContent = code.slice(templateOpenTagEnd, templateEnd)\n\n const relativeFile = relativePath(filePath, projectRoot)\n const componentName = extractComponentName(filePath)\n const templateStartLine = code.slice(0, templateOpenTagEnd).split('\\n').length\n\n const injected = injectAttributes(templateContent, relativeFile, componentName, templateStartLine, { mfe })\n if (!injected) return null\n\n return code.slice(0, templateOpenTagEnd) + injected + code.slice(templateEnd)\n}\n\n/** @deprecated Use transformVueSFC instead */\nexport const transformSFC = transformVueSFC\n\n// ── Svelte ──────────────────────────────────────────────\n\n/**\n * Transform a Svelte component. Markup in .svelte files is everything\n * NOT inside <script> or <style> blocks.\n */\nexport function transformSvelte(\n code: string,\n filePath: string,\n projectRoot: string,\n mfe?: string\n): string | null {\n const relativeFile = relativePath(filePath, projectRoot)\n const componentName = extractComponentName(filePath)\n\n // Find all <script> and <style> block ranges (including their tags)\n const blockRanges = findBlockRanges(code, ['script', 'style'])\n\n // Collect markup regions (gaps between blocks)\n const markupRegions = getMarkupRegions(code, blockRanges)\n\n if (markupRegions.length === 0) return null\n\n let result = ''\n let lastIndex = 0\n let changed = false\n\n for (const region of markupRegions) {\n // Add everything before this region (script/style blocks)\n result += code.slice(lastIndex, region.start)\n\n const regionContent = code.slice(region.start, region.end)\n const regionStartLine = code.slice(0, region.start).split('\\n').length\n\n const injected = injectAttributes(\n regionContent,\n relativeFile,\n componentName,\n regionStartLine,\n { skipTags: SVELTE_SKIP_TAGS, mfe }\n )\n\n if (injected) {\n result += injected\n changed = true\n } else {\n result += regionContent\n }\n\n lastIndex = region.end\n }\n\n if (!changed) return null\n\n result += code.slice(lastIndex)\n return result\n}\n\nconst SVELTE_SKIP_TAGS = new Set([\n 'script', 'style',\n 'svelte:head', 'svelte:window', 'svelte:document', 'svelte:body',\n 'svelte:options', 'svelte:fragment', 'svelte:self', 'svelte:component',\n 'svelte:element', 'svelte:boundary',\n])\n\n// ── React JSX ───────────────────────────────────────────\n\n/**\n * Transform a React JSX/TSX file. JSX is interleaved with JavaScript,\n * so we scan the full file with brace-depth tracking enabled.\n */\nexport function transformJSX(\n code: string,\n filePath: string,\n projectRoot: string,\n mfe?: string\n): string | null {\n const relativeFile = relativePath(filePath, projectRoot)\n const componentName = extractComponentName(filePath)\n\n const injected = injectAttributes(code, relativeFile, componentName, 1, {\n jsxMode: true,\n skipTags: JSX_SKIP_TAGS,\n mfe,\n })\n\n return injected\n}\n\n/** Tags to skip in JSX mode. Fragments have empty tag names and are handled separately. */\nconst JSX_SKIP_TAGS = new Set(['script', 'style'])\n\n// ── HTML ───────────────────────────────────────────────\n\n/**\n * Transform a plain HTML file. Injects data-annotask-* attributes on\n * every element inside the <body> block.\n */\nexport function transformHTML(\n code: string,\n filePath: string,\n projectRoot: string,\n mfe?: string\n): string | null {\n const bodyMatch = code.match(/<body(\\s[^>]*)?>/)\n if (!bodyMatch) return null\n\n const bodyStart = code.indexOf(bodyMatch[0])\n const bodyEnd = code.lastIndexOf('</body>')\n if (bodyEnd === -1) return null\n\n const bodyOpenTagEnd = bodyStart + bodyMatch[0].length\n const bodyContent = code.slice(bodyOpenTagEnd, bodyEnd)\n\n const relativeFile = relativePath(filePath, projectRoot)\n const componentName = extractComponentName(filePath)\n const bodyStartLine = code.slice(0, bodyOpenTagEnd).split('\\n').length\n\n const injected = injectAttributes(bodyContent, relativeFile, componentName, bodyStartLine, {\n skipTags: HTML_SKIP_TAGS,\n mfe,\n })\n if (!injected) return null\n\n return code.slice(0, bodyOpenTagEnd) + injected + code.slice(bodyEnd)\n}\n\nconst HTML_SKIP_TAGS = new Set(['script', 'style'])\n\n// ── Astro ──────────────────────────────────────────────\n\n/**\n * Transform an Astro component. Markup is everything NOT inside the\n * --- frontmatter ---, <script>, or <style> blocks. Astro uses JSX-like\n * {expressions} in its template, so we enable jsxMode.\n */\nexport function transformAstro(\n code: string,\n filePath: string,\n projectRoot: string,\n mfe?: string\n): string | null {\n const relativeFile = relativePath(filePath, projectRoot)\n const componentName = extractComponentName(filePath)\n\n // Find frontmatter block (--- ... ---)\n const frontmatterRanges: Range[] = []\n const fmStart = code.indexOf('---')\n if (fmStart !== -1) {\n const fmEnd = code.indexOf('---', fmStart + 3)\n if (fmEnd !== -1) {\n frontmatterRanges.push({ start: fmStart, end: fmEnd + 3 })\n }\n }\n\n const blockRanges = [\n ...frontmatterRanges,\n ...findBlockRanges(code, ['script', 'style']),\n ]\n blockRanges.sort((a, b) => a.start - b.start)\n\n const markupRegions = getMarkupRegions(code, blockRanges)\n if (markupRegions.length === 0) return null\n\n let result = ''\n let lastIndex = 0\n let changed = false\n\n for (const region of markupRegions) {\n result += code.slice(lastIndex, region.start)\n\n const regionContent = code.slice(region.start, region.end)\n const regionStartLine = code.slice(0, region.start).split('\\n').length\n\n const injected = injectAttributes(regionContent, relativeFile, componentName, regionStartLine, {\n jsxMode: true,\n skipTags: ASTRO_SKIP_TAGS,\n mfe,\n })\n\n if (injected) {\n result += injected\n changed = true\n } else {\n result += regionContent\n }\n\n lastIndex = region.end\n }\n\n if (!changed) return null\n result += code.slice(lastIndex)\n return result\n}\n\nconst ASTRO_SKIP_TAGS = new Set([\n 'script', 'style', 'Fragment',\n])\n\n/**\n * Known TypeScript/JS generic type names that should NOT be treated as JSX tags.\n * When the scanner sees `<Array` or `<Promise` etc., it skips them.\n */\nconst TS_GENERIC_NAMES = new Set([\n 'Array', 'Map', 'Set', 'WeakMap', 'WeakSet', 'Promise', 'Generator',\n 'AsyncGenerator', 'Iterable', 'AsyncIterable', 'Iterator',\n 'Record', 'Partial', 'Required', 'Readonly', 'Pick', 'Omit',\n 'Exclude', 'Extract', 'NonNullable', 'ReturnType', 'Parameters',\n 'InstanceType', 'ConstructorParameters', 'Awaited',\n 'ReadonlyArray', 'ReadonlyMap', 'ReadonlySet',\n 'Uppercase', 'Lowercase', 'Capitalize', 'Uncapitalize',\n])\n\n// ── Shared Utilities ────────────────────────────────────\n\nexport function extractComponentName(filePath: string): string {\n const fileName = filePath.split('/').pop() || ''\n return fileName.replace(/\\.(vue|svelte|astro|html|[jt]sx?)$/, '')\n}\n\nfunction relativePath(filePath: string, projectRoot: string): string {\n return filePath.startsWith(projectRoot)\n ? filePath.slice(projectRoot.length).replace(/^\\//, '')\n : filePath\n}\n\ninterface InjectOptions {\n /** Enable JSX mode: track {} brace depth, skip TS generics */\n jsxMode?: boolean\n /** Tags to skip (won't have attributes injected) */\n skipTags?: Set<string>\n /** MFE identity for multi-project setups */\n mfe?: string\n}\n\n/**\n * Walk through HTML/JSX markup and inject data-annotask-* attributes on\n * every element's opening tag.\n *\n * Uses a character-level scanner that is quote-aware, so `>` inside\n * attribute values does not prematurely close the tag.\n */\nexport function injectAttributes(\n template: string,\n file: string,\n componentName: string,\n templateStartLine: number,\n options?: InjectOptions,\n): string | null {\n const skipTags = options?.skipTags ?? DEFAULT_SKIP_TAGS\n const jsxMode = options?.jsxMode ?? false\n const mfe = options?.mfe\n\n let result = ''\n let lastIndex = 0\n let changed = false\n let i = 0\n\n while (i < template.length) {\n // Skip comments\n if (template.startsWith('<!--', i)) {\n const end = template.indexOf('-->', i + 4)\n i = end === -1 ? template.length : end + 3\n continue\n }\n\n // Skip closing tags\n if (template.startsWith('</', i)) {\n const end = template.indexOf('>', i + 2)\n i = end === -1 ? template.length : end + 1\n continue\n }\n\n // Check for opening tag\n if (template[i] === '<' && i + 1 < template.length && /[a-zA-Z]/.test(template[i + 1])) {\n const tagStart = i\n i++ // past '<'\n\n // Read tag name (including namespaced tags like svelte:head)\n const nameStart = i\n while (i < template.length && /[a-zA-Z0-9\\-:]/.test(template[i])) i++\n const tagName = template.slice(nameStart, i)\n\n // In JSX mode, skip React fragments (empty tag name won't reach here,\n // but <> starts with < followed by > which isn't [a-zA-Z])\n // Skip known TypeScript generics\n if (jsxMode && TS_GENERIC_NAMES.has(tagName)) {\n // This is a TS generic like Array<string>, not a JSX tag\n // Find the closing > accounting for nested generics\n i = skipGeneric(template, i)\n continue\n }\n\n // In JSX mode, check if this looks like a type context\n // (preceded by : or as or extends or implements)\n if (jsxMode && isTypeContext(template, tagStart)) {\n i = skipGeneric(template, i)\n continue\n }\n\n // Skip tags we don't want to instrument\n if (skipTags.has(tagName) || skipTags.has(tagName.toLowerCase())) {\n i = findTagEnd(template, i, jsxMode)\n continue\n }\n\n // Scan past attributes to find the closing > or />\n const tagEndIndex = findTagEnd(template, i, jsxMode)\n\n const tagSource = template.slice(tagStart, tagEndIndex)\n\n // Skip if already instrumented\n if (tagSource.includes('data-annotask-file')) {\n i = tagEndIndex\n continue\n }\n\n // Calculate file-relative line number\n const lineInFile = templateStartLine + template.slice(0, tagStart).split('\\n').length - 1\n\n const injection = ` data-annotask-file=\"${file}\" data-annotask-line=\"${lineInFile}\" data-annotask-component=\"${componentName}\"${mfe ? ` data-annotask-mfe=\"${mfe}\"` : ''}`\n\n // Find the insertion point: right before '>' or '/>'\n let insertAt = tagEndIndex - 1 // the '>'\n if (insertAt > 0 && template[insertAt - 1] === '/') insertAt-- // before '/>'\n\n result += template.slice(lastIndex, insertAt)\n result += injection\n result += template.slice(insertAt, tagEndIndex)\n lastIndex = tagEndIndex\n changed = true\n i = tagEndIndex\n\n continue\n }\n\n i++\n }\n\n if (!changed) return null\n\n result += template.slice(lastIndex)\n return result\n}\n\nconst DEFAULT_SKIP_TAGS = new Set(['script', 'style', 'template', 'slot'])\n\n/**\n * Starting from position `i` (after the tag name), scan forward past\n * all attributes and find the closing `>`. Handles quoted strings\n * so that `>` inside `\"...\"`, `'...'`, or `` `...` `` doesn't end the tag.\n *\n * In JSX mode, also tracks `{}` brace depth so that `>` inside\n * JSX expression attributes (e.g., `{x > 5}`) doesn't end the tag.\n */\nexport function findTagEnd(template: string, i: number, jsxMode = false): number {\n let inQuote: string | null = null\n let braceDepth = 0\n\n while (i < template.length) {\n const ch = template[i]\n\n if (inQuote === '`') {\n if (ch === '`' && braceDepth === 0) {\n inQuote = null\n } else if (ch === '$' && i + 1 < template.length && template[i + 1] === '{') {\n braceDepth++\n i++ // skip past '{'\n } else if (ch === '}' && braceDepth > 0) {\n braceDepth--\n }\n } else if (inQuote) {\n if (ch === inQuote) inQuote = null\n } else {\n if (ch === '\"' || ch === \"'\" || ch === '`') {\n inQuote = ch\n } else if (jsxMode && ch === '{') {\n braceDepth++\n } else if (jsxMode && ch === '}' && braceDepth > 0) {\n braceDepth--\n } else if (ch === '>' && braceDepth === 0) {\n return i + 1\n }\n }\n i++\n }\n\n return i\n}\n\n// ── Svelte helpers ──────────────────────────────────────\n\ninterface Range { start: number; end: number }\n\n/**\n * Find all ranges of the given block-level tags (e.g., script, style)\n * including their opening and closing tags.\n */\nfunction findBlockRanges(code: string, tagNames: string[]): Range[] {\n const ranges: Range[] = []\n for (const tag of tagNames) {\n // Match opening tags like <script>, <script context=\"module\">, <style lang=\"scss\">\n const openRegex = new RegExp(`<${tag}(\\\\s[^>]*)?>`, 'gi')\n let match\n while ((match = openRegex.exec(code)) !== null) {\n const start = match.index\n const closeTag = `</${tag}>`\n const closeIndex = code.indexOf(closeTag, start + match[0].length)\n if (closeIndex !== -1) {\n ranges.push({ start, end: closeIndex + closeTag.length })\n }\n }\n }\n // Sort by start position\n ranges.sort((a, b) => a.start - b.start)\n return ranges\n}\n\n/**\n * Given sorted block ranges, return the markup regions (gaps between blocks).\n */\nfunction getMarkupRegions(code: string, blockRanges: Range[]): Range[] {\n const regions: Range[] = []\n let cursor = 0\n\n for (const block of blockRanges) {\n if (block.start > cursor) {\n const region = code.slice(cursor, block.start)\n // Only include regions that have actual markup (not just whitespace)\n if (region.trim().length > 0) {\n regions.push({ start: cursor, end: block.start })\n }\n }\n cursor = block.end\n }\n\n // Region after the last block\n if (cursor < code.length) {\n const region = code.slice(cursor)\n if (region.trim().length > 0) {\n regions.push({ start: cursor, end: code.length })\n }\n }\n\n return regions\n}\n\n// ── JSX helpers ─────────────────────────────────────────\n\n/**\n * Check if the `<` at position `tagStart` is in a TypeScript type/generic\n * context rather than JSX.\n *\n * Key insight: In JSX, `<` is always preceded by whitespace, an operator,\n * punctuation, or a JSX-context keyword (return, yield, etc.).\n * In generics, `<` immediately follows an identifier: `Array<string>`,\n * `foo<T>()`, `Promise<void>`.\n */\nfunction isTypeContext(code: string, tagStart: number): boolean {\n // Walk backward past whitespace to find the preceding token\n let j = tagStart - 1\n while (j >= 0 && (code[j] === ' ' || code[j] === '\\t' || code[j] === '\\n' || code[j] === '\\r')) j--\n if (j < 0) return false\n\n const ch = code[j]\n\n // Preceded by : (type annotation), < (nested generic), . (member access in type)\n if (ch === ':' || ch === '<' || ch === '.') return true\n\n // If preceded by an identifier character, it's likely a generic: Array<T>, foo<T>\n // Exception: JSX-context keywords like return, yield, case, etc.\n if (/[a-zA-Z0-9_$]/.test(ch)) {\n // Read the full preceding word\n let wordEnd = j + 1\n while (j >= 0 && /[a-zA-Z0-9_$]/.test(code[j])) j--\n const word = code.slice(j + 1, wordEnd)\n\n // These keywords can precede JSX: return <div>, yield <X />, etc.\n const jsxKeywords = new Set(['return', 'yield', 'case', 'default', 'throw', 'new', 'in', 'of', 'else'])\n if (jsxKeywords.has(word)) return false\n\n // Any other identifier before < means it's a generic\n return true\n }\n\n // Check for keyword tokens that signal type context\n // (already handled above via identifier check, but keep for safety)\n const typeKeywords = ['as', 'extends', 'implements', 'typeof', 'keyof', 'infer', 'type']\n for (const kw of typeKeywords) {\n if (j >= kw.length - 1) {\n const slice = code.slice(j - kw.length + 1, j + 1)\n if (slice === kw) {\n const before = j - kw.length\n if (before < 0 || /\\s|[,;({[<>|&=!?+\\-*/]/.test(code[before])) {\n return true\n }\n }\n }\n }\n\n return false\n}\n\n/**\n * Skip past a TypeScript generic expression like `<string>` or `<T extends U>`.\n * Tracks nested `<>` depth.\n */\nfunction skipGeneric(code: string, i: number): number {\n let depth = 1\n while (i < code.length && depth > 0) {\n if (code[i] === '<') depth++\n else if (code[i] === '>') depth--\n i++\n }\n return i\n}\n"],"mappings":"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","names":[]}
|