vue3-vite-component-tagger-plugin 1.0.0

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/README.md ADDED
@@ -0,0 +1,71 @@
1
+ # Vue 3 Vite Component Tagger
2
+
3
+ A Vite plugin that automatically adds `data-soeasy-id` and `data-soeasy-name` attributes to your Vue 3 components. This is useful for identifying components in the DOM, for example for testing or analytics.
4
+
5
+ ## Installation
6
+
7
+ ```bash
8
+ npm install vue3-vite-component-tagger
9
+ # or
10
+ yarn add vue3-vite-component-tagger
11
+ # or
12
+ pnpm add vue3-vite-component-tagger
13
+ ```
14
+
15
+ ## Usage
16
+
17
+ Add the plugin to your `vite.config.ts` file:
18
+
19
+ ```ts
20
+ import { defineConfig } from "vite";
21
+ import vue from "@vitejs/plugin-vue";
22
+ import componentTagger from "vue3-vite-component-tagger";
23
+
24
+ // https://vitejs.dev/config/
25
+ export default defineConfig({
26
+ plugins: [vue(), componentTagger()],
27
+ });
28
+ ```
29
+
30
+ The plugin will automatically add `data-soeasy-id` and `data-soeasy-name` to all your Vue components in development mode.
31
+
32
+ ### Example
33
+
34
+ Given a Vue component:
35
+
36
+ ```vue
37
+ <template>
38
+ <div>
39
+ <header>
40
+ <h1>Welcome</h1>
41
+ </header>
42
+ <button @click="handleClick">Click me</button>
43
+ </div>
44
+ </template>
45
+ ```
46
+
47
+ The plugin will transform it to:
48
+
49
+ ```vue
50
+ <template>
51
+ <div data-soeasy-id="src/App.vue:2:3" data-soeasy-name="div">
52
+ <header data-soeasy-id="src/App.vue:3:5" data-soeasy-name="header">
53
+ <h1 data-soeasy-id="src/App.vue:4:7" data-soeasy-name="h1">Welcome</h1>
54
+ </header>
55
+ <button data-soeasy-id="src/App.vue:6:5" data-soeasy-name="button" @click="handleClick">Click me</button>
56
+ </div>
57
+ </template>
58
+ ```
59
+
60
+ The `data-soeasy-id` will be a unique identifier for each component instance, in the format `path/to/file.vue:line:column`.
61
+
62
+ The `data-soeasy-name` will be the tag name of the element.
63
+
64
+ ## Features
65
+
66
+ - Automatically tags all Vue template elements in `.vue` files
67
+ - Adds unique `data-soeasy-id` based on file path and location
68
+ - Adds `data-soeasy-name` with the element's tag name
69
+ - Only runs in development mode (`serve`)
70
+ - Skips elements that already have `data-soeasy-id`
71
+ - Ignores `node_modules` files
package/dist/index.cjs ADDED
@@ -0,0 +1,97 @@
1
+ "use strict";
2
+ var __create = Object.create;
3
+ var __defProp = Object.defineProperty;
4
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
5
+ var __getOwnPropNames = Object.getOwnPropertyNames;
6
+ var __getProtoOf = Object.getPrototypeOf;
7
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
8
+ var __export = (target, all) => {
9
+ for (var name in all)
10
+ __defProp(target, name, { get: all[name], enumerable: true });
11
+ };
12
+ var __copyProps = (to, from, except, desc) => {
13
+ if (from && typeof from === "object" || typeof from === "function") {
14
+ for (let key of __getOwnPropNames(from))
15
+ if (!__hasOwnProp.call(to, key) && key !== except)
16
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
17
+ }
18
+ return to;
19
+ };
20
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
21
+ // If the importer is in node compatibility mode or this is not an ESM
22
+ // file that has been converted to a CommonJS file using a Babel-
23
+ // compatible transform (i.e. "__esModule" has not been set), then set
24
+ // "default" to the CommonJS "module.exports" for node compatibility.
25
+ isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
26
+ mod
27
+ ));
28
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
29
+
30
+ // src/index.ts
31
+ var index_exports = {};
32
+ __export(index_exports, {
33
+ default: () => dyadTagger
34
+ });
35
+ module.exports = __toCommonJS(index_exports);
36
+ var import_compiler_sfc = require("@vue/compiler-sfc");
37
+ var import_magic_string = __toESM(require("magic-string"), 1);
38
+ var import_node_path = __toESM(require("path"), 1);
39
+ var VALID_EXTENSIONS = /* @__PURE__ */ new Set([".vue"]);
40
+ function dyadTagger(options = {}) {
41
+ const { idAttribute = "data-soeasy-id", nameAttribute = "data-soeasy-name" } = options;
42
+ return {
43
+ name: "vite-plugin-vue-dyad-tagger",
44
+ apply: "serve",
45
+ enforce: "pre",
46
+ async transform(code, id) {
47
+ try {
48
+ if (!VALID_EXTENSIONS.has(import_node_path.default.extname(id)) || id.includes("node_modules"))
49
+ return null;
50
+ const { descriptor } = (0, import_compiler_sfc.parse)(code, { filename: id });
51
+ if (!descriptor.template) {
52
+ return null;
53
+ }
54
+ const templateContent = descriptor.template.content;
55
+ const templateStart = descriptor.template.loc.start.offset;
56
+ const tagRegex = /<([a-zA-Z][a-zA-Z0-9-]*(?:\.[a-zA-Z][a-zA-Z0-9-]*)*)(\s+[^>]*?)?(\s*\/)?>/g;
57
+ const ms = new import_magic_string.default(code);
58
+ let match;
59
+ let processedTags = 0;
60
+ while ((match = tagRegex.exec(templateContent)) !== null) {
61
+ const [, tagName, attributes = ""] = match;
62
+ const tagStartInTemplate = match.index;
63
+ if (attributes.includes(idAttribute)) {
64
+ continue;
65
+ }
66
+ if (tagName === "template") {
67
+ continue;
68
+ }
69
+ const tagPositionInFile = templateStart + tagStartInTemplate;
70
+ const lines = code.substring(0, tagPositionInFile).split("\n");
71
+ const line = lines.length;
72
+ const column = lines[lines.length - 1].length + 1;
73
+ const elementId = `${id}:${line}:${column}`;
74
+ let insertPosition = templateStart + tagStartInTemplate + 1 + tagName.length;
75
+ const charAfterTagName = code[insertPosition];
76
+ const needsSpace = charAfterTagName !== " " && charAfterTagName !== "\n" && charAfterTagName !== " ";
77
+ const attributesToAdd = needsSpace ? ` ${idAttribute}="${elementId}" ${nameAttribute}="${tagName}"` : ` ${idAttribute}="${elementId}" ${nameAttribute}="${tagName}"`;
78
+ ms.appendLeft(insertPosition, attributesToAdd);
79
+ processedTags++;
80
+ }
81
+ if (processedTags === 0) {
82
+ return null;
83
+ }
84
+ return {
85
+ code: ms.toString(),
86
+ map: ms.generateMap({ hires: true })
87
+ };
88
+ } catch (error) {
89
+ console.warn(
90
+ `[vue-dyad-tagger] Warning: Failed to transform ${id}:`,
91
+ error
92
+ );
93
+ return null;
94
+ }
95
+ }
96
+ };
97
+ }
@@ -0,0 +1,9 @@
1
+ import { Plugin } from 'vite';
2
+
3
+ interface DyadTaggerOptions {
4
+ idAttribute?: string;
5
+ nameAttribute?: string;
6
+ }
7
+ declare function dyadTagger(options?: DyadTaggerOptions): Plugin;
8
+
9
+ export { dyadTagger as default };
@@ -0,0 +1,9 @@
1
+ import { Plugin } from 'vite';
2
+
3
+ interface DyadTaggerOptions {
4
+ idAttribute?: string;
5
+ nameAttribute?: string;
6
+ }
7
+ declare function dyadTagger(options?: DyadTaggerOptions): Plugin;
8
+
9
+ export { dyadTagger as default };
package/dist/index.js ADDED
@@ -0,0 +1,66 @@
1
+ // src/index.ts
2
+ import { parse } from "@vue/compiler-sfc";
3
+ import MagicString from "magic-string";
4
+ import path from "path";
5
+ var VALID_EXTENSIONS = /* @__PURE__ */ new Set([".vue"]);
6
+ function dyadTagger(options = {}) {
7
+ const { idAttribute = "data-soeasy-id", nameAttribute = "data-soeasy-name" } = options;
8
+ return {
9
+ name: "vite-plugin-vue-dyad-tagger",
10
+ apply: "serve",
11
+ enforce: "pre",
12
+ async transform(code, id) {
13
+ try {
14
+ if (!VALID_EXTENSIONS.has(path.extname(id)) || id.includes("node_modules"))
15
+ return null;
16
+ const { descriptor } = parse(code, { filename: id });
17
+ if (!descriptor.template) {
18
+ return null;
19
+ }
20
+ const templateContent = descriptor.template.content;
21
+ const templateStart = descriptor.template.loc.start.offset;
22
+ const tagRegex = /<([a-zA-Z][a-zA-Z0-9-]*(?:\.[a-zA-Z][a-zA-Z0-9-]*)*)(\s+[^>]*?)?(\s*\/)?>/g;
23
+ const ms = new MagicString(code);
24
+ let match;
25
+ let processedTags = 0;
26
+ while ((match = tagRegex.exec(templateContent)) !== null) {
27
+ const [, tagName, attributes = ""] = match;
28
+ const tagStartInTemplate = match.index;
29
+ if (attributes.includes(idAttribute)) {
30
+ continue;
31
+ }
32
+ if (tagName === "template") {
33
+ continue;
34
+ }
35
+ const tagPositionInFile = templateStart + tagStartInTemplate;
36
+ const lines = code.substring(0, tagPositionInFile).split("\n");
37
+ const line = lines.length;
38
+ const column = lines[lines.length - 1].length + 1;
39
+ const elementId = `${id}:${line}:${column}`;
40
+ let insertPosition = templateStart + tagStartInTemplate + 1 + tagName.length;
41
+ const charAfterTagName = code[insertPosition];
42
+ const needsSpace = charAfterTagName !== " " && charAfterTagName !== "\n" && charAfterTagName !== " ";
43
+ const attributesToAdd = needsSpace ? ` ${idAttribute}="${elementId}" ${nameAttribute}="${tagName}"` : ` ${idAttribute}="${elementId}" ${nameAttribute}="${tagName}"`;
44
+ ms.appendLeft(insertPosition, attributesToAdd);
45
+ processedTags++;
46
+ }
47
+ if (processedTags === 0) {
48
+ return null;
49
+ }
50
+ return {
51
+ code: ms.toString(),
52
+ map: ms.generateMap({ hires: true })
53
+ };
54
+ } catch (error) {
55
+ console.warn(
56
+ `[vue-dyad-tagger] Warning: Failed to transform ${id}:`,
57
+ error
58
+ );
59
+ return null;
60
+ }
61
+ }
62
+ };
63
+ }
64
+ export {
65
+ dyadTagger as default
66
+ };
package/package.json ADDED
@@ -0,0 +1,43 @@
1
+ {
2
+ "name": "vue3-vite-component-tagger-plugin",
3
+ "version": "1.0.0",
4
+ "description": "A Vite plugin that automatically adds data attributes to your Vue 3 components.",
5
+ "main": "dist/index.js",
6
+ "module": "dist/index.mjs",
7
+ "types": "dist/index.d.ts",
8
+ "type": "module",
9
+ "files": [
10
+ "dist"
11
+ ],
12
+ "scripts": {
13
+ "build": "tsup src/index.ts --format cjs,esm --dts",
14
+ "dev": "npm run build -- --watch",
15
+ "lint": "eslint . --max-warnings 0",
16
+ "prepublishOnly": "npm run build"
17
+ },
18
+ "keywords": [
19
+ "vite",
20
+ "vite-plugin",
21
+ "vue",
22
+ "vue3"
23
+ ],
24
+ "author": "Yaob1990",
25
+ "license": "Apache-2.0",
26
+ "peerDependencies": {
27
+ "vite": "^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0"
28
+ },
29
+ "dependencies": {
30
+ "@vue/compiler-sfc": "^3.4.0",
31
+ "magic-string": "^0.30.5"
32
+ },
33
+ "devDependencies": {
34
+ "@types/node": "^20.8.9",
35
+ "eslint": "^8.52.0",
36
+ "tsup": "^8.0.2",
37
+ "typescript": "^5.2.2",
38
+ "vite": "^5.0.0"
39
+ },
40
+ "publishConfig": {
41
+ "access": "public"
42
+ }
43
+ }