@prover-coder-ai/component-tagger 1.0.25 → 1.0.27

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/babel.cjs CHANGED
@@ -22,6 +22,7 @@
22
22
 
23
23
  const path = require("node:path")
24
24
 
25
+ const babelPluginName = "component-path-babel-tagger"
25
26
  const componentPathAttributeName = "data-path"
26
27
  const jsxFilePattern = /\.(tsx|jsx)(\?.*)?$/u
27
28
 
@@ -37,7 +38,7 @@ const attrExists = (node, attrName, t) =>
37
38
 
38
39
  module.exports = function componentTaggerBabelPlugin({ types: t }) {
39
40
  return {
40
- name: "component-path-babel-tagger",
41
+ name: babelPluginName,
41
42
  visitor: {
42
43
  JSXOpeningElement(nodePath, state) {
43
44
  const { node } = nodePath
@@ -1,3 +1,19 @@
1
+ export declare const babelPluginName = "component-path-babel-tagger";
2
+ /**
3
+ * Normalizes a module ID by stripping query parameters.
4
+ *
5
+ * Vite and other bundlers may append query parameters to module IDs
6
+ * (e.g., "src/App.tsx?import" or "src/App.tsx?v=123"). This function
7
+ * returns the clean file path without query string.
8
+ *
9
+ * @param id - Module ID (may include query parameters).
10
+ * @returns Clean path without query string.
11
+ *
12
+ * @pure true
13
+ * @invariant ∀ id: normalizeModuleId(id) does not contain '?'
14
+ * @complexity O(n) time / O(1) space where n = |id|
15
+ */
16
+ export declare const normalizeModuleId: (id: string) => string;
1
17
  export declare const componentPathAttributeName = "data-path";
2
18
  /**
3
19
  * Checks whether the Vite id represents a JSX or TSX module.
@@ -1,4 +1,43 @@
1
1
  const jsxFilePattern = /\.(tsx|jsx)(\?.*)?$/u;
2
+ // CHANGE: define canonical Babel plugin name for component path tagging.
3
+ // WHY: eliminate magic string duplication across plugin implementations.
4
+ // QUOTE(ТЗ): "Вынести строки имён плагинов в константы (чтобы не дублировать \"component-path-babel-tagger\")."
5
+ // REF: issue-19
6
+ // SOURCE: n/a
7
+ // FORMAT THEOREM: forall p in PluginName: p = "component-path-babel-tagger"
8
+ // PURITY: CORE
9
+ // EFFECT: n/a
10
+ // INVARIANT: plugin name remains stable across all implementations
11
+ // COMPLEXITY: O(1)/O(1)
12
+ export const babelPluginName = "component-path-babel-tagger";
13
+ /**
14
+ * Normalizes a module ID by stripping query parameters.
15
+ *
16
+ * Vite and other bundlers may append query parameters to module IDs
17
+ * (e.g., "src/App.tsx?import" or "src/App.tsx?v=123"). This function
18
+ * returns the clean file path without query string.
19
+ *
20
+ * @param id - Module ID (may include query parameters).
21
+ * @returns Clean path without query string.
22
+ *
23
+ * @pure true
24
+ * @invariant ∀ id: normalizeModuleId(id) does not contain '?'
25
+ * @complexity O(n) time / O(1) space where n = |id|
26
+ */
27
+ // CHANGE: centralize query stripping as a pure function in core.
28
+ // WHY: unify module ID normalization in one place as requested in issue #18.
29
+ // QUOTE(ТЗ): "Вынести stripQuery() (или normalizeModuleId()) в core, использовать в Vite и (при желании) в isJsxFile."
30
+ // REF: REQ-18 (issue #18)
31
+ // SOURCE: n/a
32
+ // FORMAT THEOREM: ∀ id: normalizeModuleId(id) = id.split('?')[0]
33
+ // PURITY: CORE
34
+ // EFFECT: n/a
35
+ // INVARIANT: result contains no query string
36
+ // COMPLEXITY: O(n)/O(1)
37
+ export const normalizeModuleId = (id) => {
38
+ const queryIndex = id.indexOf("?");
39
+ return queryIndex === -1 ? id : id.slice(0, queryIndex);
40
+ };
2
41
  // CHANGE: rename attribute from "path" to "data-path" for HTML5 compliance.
3
42
  // WHY: data-* attributes are standard HTML5 custom data attributes, improving compatibility.
4
43
  // QUOTE(issue-14): "Rename attribute path → data-path (breaking change)"
@@ -22,7 +61,7 @@ export const componentPathAttributeName = "data-path";
22
61
  */
23
62
  // CHANGE: centralize JSX file detection as a pure predicate.
24
63
  // WHY: keep file filtering in the functional core for testability.
25
- // QUOTE(TZ): "\u0421\u0430\u043c \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442 \u0434\u043e\u043b\u0436\u0435\u043d \u0431\u044b\u0442\u044c \u0432 \u0442\u0435\u043a\u0443\u0449\u0435\u043c app \u043d\u043e \u0432\u043e\u0442 \u0447\u0442\u043e \u0431\u044b \u0435\u0433\u043e \u043f\u0440\u043e\u0442\u0435\u0441\u0442\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u043d\u0430\u0434\u043e \u0441\u043e\u0437\u0434\u0430\u0442\u044c \u0435\u0449\u0451 \u043e\u0434\u0438\u043d \u043f\u0440\u043e\u0435\u043a\u0442 \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u043d\u0430\u0448 \u0442\u0435\u043a\u0443\u0449\u0438\u0439 \u0430\u043f\u043f \u0431\u0443\u0434\u0435\u0442 \u043f\u043e\u0434\u043a\u043b\u044e\u0447\u0430\u0442\u044c"
64
+ // QUOTE(TZ): "Сам компонент должен быть в текущем app но вот что бы его протестировать надо создать ещё один проект который наш текущий апп будет подключать"
26
65
  // REF: user-2026-01-14-frontend-consumer
27
66
  // SOURCE: n/a
28
67
  // FORMAT THEOREM: forall id in ModuleId: isJsxFile(id) -> matches(id, jsxFilePattern)
@@ -45,7 +84,7 @@ export const isJsxFile = (id) => jsxFilePattern.test(id);
45
84
  */
46
85
  // CHANGE: provide a pure formatter for component location payloads.
47
86
  // WHY: reuse a single, deterministic encoding for UI metadata.
48
- // QUOTE(TZ): "\u0421\u0430\u043c \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442 \u0434\u043e\u043b\u0436\u0435\u043d \u0431\u044b\u0442\u044c \u0432 \u0442\u0435\u043a\u0443\u0449\u0435\u043c app \u043d\u043e \u0432\u043e\u0442 \u0447\u0442\u043e \u0431\u044b \u0435\u0433\u043e \u043f\u0440\u043e\u0442\u0435\u0441\u0442\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u043d\u0430\u0434\u043e \u0441\u043e\u0437\u0434\u0430\u0442\u044c \u0435\u0449\u0451 \u043e\u0434\u0438\u043d \u043f\u0440\u043e\u0435\u043a\u0442 \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u043d\u0430\u0448 \u0442\u0435\u043a\u0443\u0449\u0438\u0439 \u0430\u043f\u043f \u0431\u0443\u0434\u0435\u0442 \u043f\u043e\u0434\u043a\u043b\u044e\u0447\u0430\u0442\u044c"
87
+ // QUOTE(TZ): "Сам компонент должен быть в текущем app но вот что бы его протестировать надо создать ещё один проект который наш текущий апп будет подключать"
49
88
  // REF: user-2026-01-14-frontend-consumer
50
89
  // SOURCE: n/a
51
90
  // FORMAT THEOREM: forall p,l,c: formatComponentPathValue(p,l,c) = concat(p, ":", l, ":", c)
package/dist/index.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- export { componentPathAttributeName, formatComponentPathValue, isJsxFile } from "./core/component-path.js";
1
+ export { componentPathAttributeName, formatComponentPathValue, isJsxFile, normalizeModuleId } from "./core/component-path.js";
2
2
  export { attrExists, createJsxTaggerVisitor, createPathAttribute, type JsxTaggerContext, processJsxElement } from "./core/jsx-tagger.js";
3
3
  export { componentTaggerBabelPlugin, type ComponentTaggerBabelPluginOptions } from "./shell/babel-plugin.js";
4
4
  export { componentTagger, type ComponentTaggerOptions } from "./shell/component-tagger.js";
package/dist/index.js CHANGED
@@ -8,7 +8,7 @@
8
8
  // EFFECT: n/a
9
9
  // INVARIANT: exports remain stable for consumers
10
10
  // COMPLEXITY: O(1)/O(1)
11
- export { componentPathAttributeName, formatComponentPathValue, isJsxFile } from "./core/component-path.js";
11
+ export { componentPathAttributeName, formatComponentPathValue, isJsxFile, normalizeModuleId } from "./core/component-path.js";
12
12
  export { attrExists, createJsxTaggerVisitor, createPathAttribute, processJsxElement } from "./core/jsx-tagger.js";
13
13
  export { componentTaggerBabelPlugin } from "./shell/babel-plugin.js";
14
14
  export { componentTagger } from "./shell/component-tagger.js";
@@ -1,5 +1,5 @@
1
1
  import { types as t } from "@babel/core";
2
- import { componentPathAttributeName, isJsxFile } from "../core/component-path.js";
2
+ import { babelPluginName, componentPathAttributeName, isJsxFile } from "../core/component-path.js";
3
3
  import { createJsxTaggerVisitor } from "../core/jsx-tagger.js";
4
4
  import { computeRelativePath } from "../core/path-service.js";
5
5
  /**
@@ -83,7 +83,7 @@ const getContextFromState = (state) => {
83
83
  // INVARIANT: each JSX opening element has at most one path attribute
84
84
  // COMPLEXITY: O(n)/O(1)
85
85
  export const componentTaggerBabelPlugin = () => ({
86
- name: "component-path-babel-tagger",
86
+ name: babelPluginName,
87
87
  visitor: createJsxTaggerVisitor(getContextFromState, t)
88
88
  });
89
89
  /**
@@ -1,6 +1,6 @@
1
1
  import { transformAsync, types as t } from "@babel/core";
2
2
  import { Effect, pipe } from "effect";
3
- import { componentPathAttributeName, isJsxFile } from "../core/component-path.js";
3
+ import { babelPluginName, componentPathAttributeName, isJsxFile, normalizeModuleId } from "../core/component-path.js";
4
4
  import { createJsxTaggerVisitor } from "../core/jsx-tagger.js";
5
5
  import { NodePathLayer, relativeFromRoot } from "../core/path-service.js";
6
6
  class ComponentTaggerError extends Error {
@@ -11,10 +11,6 @@ class ComponentTaggerError extends Error {
11
11
  this.cause = cause;
12
12
  }
13
13
  }
14
- const stripQuery = (id) => {
15
- const queryIndex = id.indexOf("?");
16
- return queryIndex === -1 ? id : id.slice(0, queryIndex);
17
- };
18
14
  const toViteResult = (result) => {
19
15
  if (result === null || result.code === null || result.code === undefined) {
20
16
  return null;
@@ -25,10 +21,20 @@ const toViteResult = (result) => {
25
21
  map: result.map ?? null
26
22
  };
27
23
  };
24
+ // CHANGE: use unified JSX tagger visitor from core module.
25
+ // WHY: share business logic between Vite and Babel plugins as requested.
26
+ // QUOTE(TZ): "А ты можешь сделать что бы бизнес логика оставалось одной? Ну типо переиспользуй код с vite версии на babel"
27
+ // REF: issue-12-comment (unified interface request)
28
+ // SOURCE: n/a
29
+ // FORMAT THEOREM: forall f in JSXOpeningElement: rendered(f) -> annotated(f)
30
+ // PURITY: SHELL
31
+ // EFFECT: Babel AST transformation
32
+ // INVARIANT: each JSX opening element has at most one path attribute
33
+ // COMPLEXITY: O(n)/O(1), n = number of JSX elements
28
34
  const makeBabelTagger = (relativeFilename, attributeName) => {
29
35
  const context = { relativeFilename, attributeName };
30
36
  return {
31
- name: "component-path-babel-tagger",
37
+ name: babelPluginName,
32
38
  visitor: createJsxTaggerVisitor(() => context, t)
33
39
  };
34
40
  };
@@ -55,7 +61,7 @@ const makeBabelTagger = (relativeFilename, attributeName) => {
55
61
  // INVARIANT: errors are surfaced as ComponentTaggerError only
56
62
  // COMPLEXITY: O(n)/O(1)
57
63
  const runTransform = (code, id, rootDir, attributeName) => {
58
- const cleanId = stripQuery(id);
64
+ const cleanId = normalizeModuleId(id);
59
65
  return pipe(relativeFromRoot(rootDir, cleanId), Effect.flatMap((relative) => Effect.tryPromise({
60
66
  try: () => transformAsync(code, {
61
67
  filename: cleanId,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@prover-coder-ai/component-tagger",
3
- "version": "1.0.25",
3
+ "version": "1.0.27",
4
4
  "description": "Component tagger Vite plugin and Babel plugin for JSX metadata",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",