UNPKG

vite-vue-tagger

Version:

112 lines 3.84 kB
"use strict"; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.default = ComponentTagger; // src/index.ts const compiler_sfc_1 = require("@vue/compiler-sfc"); const compiler_dom_1 = require("@vue/compiler-dom"); const magic_string_1 = __importDefault(require("magic-string")); const crypto_1 = require("crypto"); const DEFAULT_OPTIONS = { mode: 'development', hashSalt: 'vite-vue-tagger', minify: false, include: /\.(vue|tsx|jsx)$/, exclude: /node_modules/, }; function ComponentTagger(options) { const opts = { ...DEFAULT_OPTIONS, ...options }; return { name: 'vite-vue-tagger', enforce: 'pre', async transform(code, id) { if (opts.mode === 'production') return; if (opts.exclude.test(id)) return; if (!opts.include.test(id)) return; try { const s = await processCode(code, id, opts); return { code: opts.minify ? minifyAttributes(s.toString()) : s.toString(), map: s.generateMap({ source: id }), }; } catch (e) { const errorMessage = e instanceof Error ? e.message : String(e); console.error(`[vue-tagger] Error processing ${id}:\n${errorMessage}`); } }, }; } async function processCode(code, id, opts) { const s = new magic_string_1.default(code); const { descriptor } = (0, compiler_sfc_1.parse)(code, { sourceMap: true }); if (!descriptor.template) return s; const template = descriptor.template; const ast = (0, compiler_dom_1.parse)(template.content, { parseMode: 'html', isNativeTag: () => true, // 假设全部为原生标签 }); ast.children.forEach((node) => { if (node.type === 1) { // ElementNode processElement(node, template.loc.start.line, s, id, opts); } }); return s; } function processElement(node, lineOffset, s, id, opts) { const source = { line: node.loc.start.line + lineOffset, column: node.loc.start.column, tag: node.tag, }; const attrs = [ `data-lov-id="${id}:${source.line}:${source.column}"`, `data-lov-name="${node.tag}"`, `data-component-path="${id}"`, `data-component-file="${id.split('/').pop()}"`, `data-component-line="${source.line}"`, `data-component-name="${getComponentName(id)}"`, `data-component-content="${encodeContent(node, opts)}"`, ].join(' '); s.appendLeft(node.loc.start.offset + 1, // 在标签名后插入 ` ${attrs} `); } function getComponentName(filePath) { return (filePath .split('/') .pop() ?.replace(/\.(vue|tsx|jsx)$/, '') ?.replace(/([a-z])([A-Z])/g, '$1 $2') // 驼峰转空格 ?.replace(/[-_]/g, ' ') || 'Anonymous'); } function encodeContent(node, opts) { const props = extractProps(node); const contentHash = (0, crypto_1.createHash)('sha256') .update(opts.hashSalt + node.loc.source) .digest('hex') .substr(0, 8); return encodeURIComponent(JSON.stringify({ props, hash: contentHash, })); } function extractProps(node) { return node.props.reduce((acc, prop) => { if (prop.type === 6) { // 属性节点 acc[prop.name] = prop.value?.content || ''; } return acc; }, {}); } function minifyAttributes(code) { return code.replace(/\s+data-[\w-]+="[^"]*"/g, (match) => match.replace(/\s+/g, ' ').trim()); } //# sourceMappingURL=index.js.map