macaly-tagger 1.1.0 → 1.2.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 CHANGED
@@ -8,7 +8,8 @@ A webpack loader that adds location metadata to JSX elements for development deb
8
8
  - 🚀 **Zero runtime overhead**: Only runs in development mode
9
9
  - 🔧 **Easy integration**: Simple webpack configuration
10
10
  - 📦 **TypeScript support**: Works with both `.jsx` and `.tsx` files
11
- - 🚫 **Smart filtering**: Automatically excludes `node_modules`
11
+ - 🚫 **Smart filtering**: Automatically excludes `node_modules`, React Fragments, and non-DOM elements
12
+ - 🎮 **Custom renderer support**: Compatible with React Three Fiber and other custom renderers via `ignorePackages` option
12
13
 
13
14
  ## Installation
14
15
 
@@ -195,6 +196,10 @@ You can pass options to the loader:
195
196
  options: {
196
197
  debug: true, // Enable debug logging
197
198
  disableSourceMaps: true, // Disable source map generation (useful for Turbopack)
199
+ ignorePackages: [ // Skip components imported from these packages
200
+ '@react-three/fiber',
201
+ '@react-three/drei',
202
+ ],
198
203
  },
199
204
  }
200
205
  ```
@@ -203,6 +208,56 @@ You can pass options to the loader:
203
208
  |--------|------|---------|-------------|
204
209
  | `debug` | `boolean` | `false` | Enable detailed console logging for debugging |
205
210
  | `disableSourceMaps` | `boolean` | `false` | Disable source map generation (recommended for Turbopack to avoid crashes) |
211
+ | `ignorePackages` | `string[]` | `[]` | List of package names whose imports should not be tagged |
212
+
213
+ ### Custom Renderers (React Three Fiber, etc.)
214
+
215
+ If you're using custom React renderers like [React Three Fiber](https://github.com/pmndrs/react-three-fiber), you may encounter errors because these renderers use components that don't support DOM attributes.
216
+
217
+ Use the `ignorePackages` option to skip tagging components imported from these packages:
218
+
219
+ ```js
220
+ {
221
+ loader: 'macaly-tagger',
222
+ options: {
223
+ ignorePackages: [
224
+ '@react-three/fiber',
225
+ '@react-three/drei',
226
+ '@react-three/postprocessing',
227
+ 'three',
228
+ ],
229
+ },
230
+ }
231
+ ```
232
+
233
+ This will automatically skip tagging any component imported from these packages:
234
+
235
+ ```jsx
236
+ import { Canvas } from '@react-three/fiber'; // Canvas will NOT be tagged
237
+ import { OrbitControls, Html } from '@react-three/drei'; // OrbitControls, Html will NOT be tagged
238
+ import * as Fiber from '@react-three/fiber'; // Fiber.* will NOT be tagged
239
+
240
+ function Scene() {
241
+ return (
242
+ <div> {/* ✓ Tagged (HTML element) */}
243
+ <Canvas> {/* ✗ Skipped (imported from @react-three/fiber) */}
244
+ <OrbitControls /> {/* ✗ Skipped (imported from @react-three/drei) */}
245
+ <Html> {/* ✗ Skipped (imported from @react-three/drei) */}
246
+ <span>Label</span> {/* ✓ Tagged (HTML element) */}
247
+ </Html>
248
+ <mesh> {/* ✗ Skipped (lowercase non-HTML element) */}
249
+ <boxGeometry /> {/* ✗ Skipped (lowercase non-HTML element) */}
250
+ </mesh>
251
+ </Canvas>
252
+ </div>
253
+ );
254
+ }
255
+ ```
256
+
257
+ The loader handles all import styles:
258
+ - **Named imports**: `import { Canvas } from '...'`
259
+ - **Default imports**: `import Drei from '...'` (skips `Drei.Something`)
260
+ - **Namespace imports**: `import * as Fiber from '...'` (skips `Fiber.Something`)
206
261
 
207
262
  ## Attributes Added
208
263
 
@@ -271,6 +326,13 @@ MIT License - see LICENSE file for details.
271
326
 
272
327
  ## Changelog
273
328
 
329
+ ### 1.2.0
330
+
331
+ - Added `ignorePackages` option to skip tagging components imported from specified packages
332
+ - Added automatic filtering for React Fragments (`<Fragment>`, `<React.Fragment>`)
333
+ - Added smart element filtering: only tags HTML/SVG elements and React components, skips unknown lowercase elements (custom renderer elements like R3F's `<mesh>`, `<boxGeometry>`, etc.)
334
+ - Improved compatibility with React Three Fiber and other custom renderers
335
+
274
336
  ### 1.1.0
275
337
 
276
338
  - Added `disableSourceMaps` option to prevent Turbopack crashes
@@ -0,0 +1,4 @@
1
+ export declare const HTML_ELEMENTS: Set<string>;
2
+ export declare const SVG_ELEMENTS: Set<string>;
3
+ export declare function shouldTagElement(tagName: string): boolean;
4
+ //# sourceMappingURL=dom-elements.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"dom-elements.d.ts","sourceRoot":"","sources":["../src/dom-elements.ts"],"names":[],"mappings":"AAGA,eAAO,MAAM,aAAa,aAiHxB,CAAC;AAKH,eAAO,MAAM,YAAY,aA8DvB,CAAC;AAiBH,wBAAgB,gBAAgB,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAgBzD"}
@@ -0,0 +1,191 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.SVG_ELEMENTS = exports.HTML_ELEMENTS = void 0;
4
+ exports.shouldTagElement = shouldTagElement;
5
+ exports.HTML_ELEMENTS = new Set([
6
+ 'a',
7
+ 'abbr',
8
+ 'address',
9
+ 'area',
10
+ 'article',
11
+ 'aside',
12
+ 'audio',
13
+ 'b',
14
+ 'base',
15
+ 'bdi',
16
+ 'bdo',
17
+ 'blockquote',
18
+ 'body',
19
+ 'br',
20
+ 'button',
21
+ 'canvas',
22
+ 'caption',
23
+ 'cite',
24
+ 'code',
25
+ 'col',
26
+ 'colgroup',
27
+ 'data',
28
+ 'datalist',
29
+ 'dd',
30
+ 'del',
31
+ 'details',
32
+ 'dfn',
33
+ 'dialog',
34
+ 'div',
35
+ 'dl',
36
+ 'dt',
37
+ 'em',
38
+ 'embed',
39
+ 'fieldset',
40
+ 'figcaption',
41
+ 'figure',
42
+ 'footer',
43
+ 'form',
44
+ 'h1',
45
+ 'h2',
46
+ 'h3',
47
+ 'h4',
48
+ 'h5',
49
+ 'h6',
50
+ 'head',
51
+ 'header',
52
+ 'hgroup',
53
+ 'hr',
54
+ 'html',
55
+ 'i',
56
+ 'iframe',
57
+ 'img',
58
+ 'input',
59
+ 'ins',
60
+ 'kbd',
61
+ 'label',
62
+ 'legend',
63
+ 'li',
64
+ 'link',
65
+ 'main',
66
+ 'map',
67
+ 'mark',
68
+ 'menu',
69
+ 'meta',
70
+ 'meter',
71
+ 'nav',
72
+ 'noscript',
73
+ 'object',
74
+ 'ol',
75
+ 'optgroup',
76
+ 'option',
77
+ 'output',
78
+ 'p',
79
+ 'picture',
80
+ 'pre',
81
+ 'progress',
82
+ 'q',
83
+ 'rp',
84
+ 'rt',
85
+ 'ruby',
86
+ 's',
87
+ 'samp',
88
+ 'script',
89
+ 'search',
90
+ 'section',
91
+ 'select',
92
+ 'slot',
93
+ 'small',
94
+ 'source',
95
+ 'span',
96
+ 'strong',
97
+ 'style',
98
+ 'sub',
99
+ 'summary',
100
+ 'sup',
101
+ 'table',
102
+ 'tbody',
103
+ 'td',
104
+ 'template',
105
+ 'textarea',
106
+ 'tfoot',
107
+ 'th',
108
+ 'thead',
109
+ 'time',
110
+ 'title',
111
+ 'tr',
112
+ 'track',
113
+ 'u',
114
+ 'ul',
115
+ 'var',
116
+ 'video',
117
+ 'wbr',
118
+ ]);
119
+ exports.SVG_ELEMENTS = new Set([
120
+ 'svg',
121
+ 'a',
122
+ 'animate',
123
+ 'animateMotion',
124
+ 'animateTransform',
125
+ 'circle',
126
+ 'clipPath',
127
+ 'defs',
128
+ 'desc',
129
+ 'ellipse',
130
+ 'feBlend',
131
+ 'feColorMatrix',
132
+ 'feComponentTransfer',
133
+ 'feComposite',
134
+ 'feConvolveMatrix',
135
+ 'feDiffuseLighting',
136
+ 'feDisplacementMap',
137
+ 'feDistantLight',
138
+ 'feDropShadow',
139
+ 'feFlood',
140
+ 'feFuncA',
141
+ 'feFuncB',
142
+ 'feFuncG',
143
+ 'feFuncR',
144
+ 'feGaussianBlur',
145
+ 'feImage',
146
+ 'feMerge',
147
+ 'feMergeNode',
148
+ 'feMorphology',
149
+ 'feOffset',
150
+ 'fePointLight',
151
+ 'feSpecularLighting',
152
+ 'feSpotLight',
153
+ 'feTile',
154
+ 'feTurbulence',
155
+ 'filter',
156
+ 'foreignObject',
157
+ 'g',
158
+ 'image',
159
+ 'line',
160
+ 'linearGradient',
161
+ 'marker',
162
+ 'mask',
163
+ 'metadata',
164
+ 'mpath',
165
+ 'path',
166
+ 'pattern',
167
+ 'polygon',
168
+ 'polyline',
169
+ 'radialGradient',
170
+ 'rect',
171
+ 'set',
172
+ 'stop',
173
+ 'switch',
174
+ 'symbol',
175
+ 'text',
176
+ 'textPath',
177
+ 'title',
178
+ 'tspan',
179
+ 'use',
180
+ 'view',
181
+ ]);
182
+ function shouldTagElement(tagName) {
183
+ if (tagName === 'Fragment' || tagName.endsWith('.Fragment')) {
184
+ return false;
185
+ }
186
+ const firstChar = tagName[0];
187
+ if (firstChar && firstChar !== firstChar.toLowerCase()) {
188
+ return true;
189
+ }
190
+ return exports.HTML_ELEMENTS.has(tagName) || exports.SVG_ELEMENTS.has(tagName);
191
+ }
@@ -0,0 +1,8 @@
1
+ export interface IgnoredImports {
2
+ namedImports: Set<string>;
3
+ namespaceImports: Set<string>;
4
+ }
5
+ export declare function createEmptyIgnoredImports(): IgnoredImports;
6
+ export declare function collectIgnoredImports(ast: any, ignorePackages: string[]): IgnoredImports;
7
+ export declare function isIgnoredImport(tagName: string, ignoredImports: IgnoredImports): boolean;
8
+ //# sourceMappingURL=import-collector.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"import-collector.d.ts","sourceRoot":"","sources":["../src/import-collector.ts"],"names":[],"mappings":"AAMA,MAAM,WAAW,cAAc;IAK7B,YAAY,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC;IAO1B,gBAAgB,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC;CAC/B;AAKD,wBAAgB,yBAAyB,IAAI,cAAc,CAK1D;AAcD,wBAAgB,qBAAqB,CAAC,GAAG,EAAE,GAAG,EAAE,cAAc,EAAE,MAAM,EAAE,GAAG,cAAc,CA+CxF;AASD,wBAAgB,eAAe,CAAC,OAAO,EAAE,MAAM,EAAE,cAAc,EAAE,cAAc,GAAG,OAAO,CAexF"}
@@ -0,0 +1,56 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.createEmptyIgnoredImports = createEmptyIgnoredImports;
4
+ exports.collectIgnoredImports = collectIgnoredImports;
5
+ exports.isIgnoredImport = isIgnoredImport;
6
+ const estree_walker_1 = require("estree-walker");
7
+ function createEmptyIgnoredImports() {
8
+ return {
9
+ namedImports: new Set(),
10
+ namespaceImports: new Set(),
11
+ };
12
+ }
13
+ function collectIgnoredImports(ast, ignorePackages) {
14
+ const result = createEmptyIgnoredImports();
15
+ if (!ignorePackages || ignorePackages.length === 0) {
16
+ return result;
17
+ }
18
+ const packagesSet = new Set(ignorePackages);
19
+ (0, estree_walker_1.walk)(ast, {
20
+ enter: (node) => {
21
+ if (node.type !== 'ImportDeclaration')
22
+ return;
23
+ const importNode = node;
24
+ const source = importNode.source.value;
25
+ if (typeof source !== 'string' || !packagesSet.has(source)) {
26
+ return;
27
+ }
28
+ for (const specifier of importNode.specifiers || []) {
29
+ switch (specifier.type) {
30
+ case 'ImportSpecifier':
31
+ result.namedImports.add(specifier.local.name);
32
+ break;
33
+ case 'ImportDefaultSpecifier':
34
+ result.namespaceImports.add(specifier.local.name);
35
+ break;
36
+ case 'ImportNamespaceSpecifier':
37
+ result.namespaceImports.add(specifier.local.name);
38
+ break;
39
+ }
40
+ }
41
+ },
42
+ });
43
+ return result;
44
+ }
45
+ function isIgnoredImport(tagName, ignoredImports) {
46
+ if (ignoredImports.namedImports.has(tagName)) {
47
+ return true;
48
+ }
49
+ if (tagName.includes('.')) {
50
+ const prefix = tagName.split('.')[0];
51
+ if (prefix && ignoredImports.namespaceImports.has(prefix)) {
52
+ return true;
53
+ }
54
+ }
55
+ return false;
56
+ }
@@ -1 +1 @@
1
- {"version":3,"file":"macaly-tagger-loader.d.ts","sourceRoot":"","sources":["../src/macaly-tagger-loader.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EACV,kBAAkB,EAInB,MAAM,SAAS,CAAC;AAgGjB,QAAA,MAAM,kBAAkB,EAAE,kBAqIzB,CAAC;AAEF,eAAe,kBAAkB,CAAC"}
1
+ {"version":3,"file":"macaly-tagger-loader.d.ts","sourceRoot":"","sources":["../src/macaly-tagger-loader.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EACV,kBAAkB,EAInB,MAAM,SAAS,CAAC;AAuGjB,QAAA,MAAM,kBAAkB,EAAE,kBAiKzB,CAAC;AAEF,eAAe,kBAAkB,CAAC"}
@@ -40,6 +40,8 @@ const parser_1 = require("@babel/parser");
40
40
  const magic_string_1 = __importDefault(require("magic-string"));
41
41
  const path = __importStar(require("path"));
42
42
  const estree_walker_1 = require("estree-walker");
43
+ const dom_elements_1 = require("./dom-elements");
44
+ const import_collector_1 = require("./import-collector");
43
45
  const VALID_EXTENSIONS = new Set(['.jsx', '.tsx']);
44
46
  function getMemberExpressionName(memberExpression) {
45
47
  if (memberExpression.type === 'JSXIdentifier') {
@@ -128,8 +130,17 @@ const macalyTaggerLoader = function (code) {
128
130
  const ms = new magic_string_1.default(code);
129
131
  const fileRelative = path.relative(this.rootContext || process.cwd(), this.resourcePath);
130
132
  let transformCount = 0;
133
+ const ignoredImports = options.ignorePackages?.length
134
+ ? (0, import_collector_1.collectIgnoredImports)(ast, options.ignorePackages)
135
+ : (0, import_collector_1.createEmptyIgnoredImports)();
131
136
  if (options.debug) {
132
137
  console.log('[macaly-tagger] File relative path:', fileRelative);
138
+ if (ignoredImports.namedImports.size > 0 || ignoredImports.namespaceImports.size > 0) {
139
+ console.log('[macaly-tagger] Ignored imports:', {
140
+ named: Array.from(ignoredImports.namedImports),
141
+ namespaces: Array.from(ignoredImports.namespaceImports),
142
+ });
143
+ }
133
144
  }
134
145
  (0, estree_walker_1.walk)(ast, {
135
146
  enter: (node) => {
@@ -150,6 +161,18 @@ const macalyTaggerLoader = function (code) {
150
161
  if (!elementInfo)
151
162
  return;
152
163
  const { tagName, insertPosition, location } = elementInfo;
164
+ if ((0, import_collector_1.isIgnoredImport)(tagName, ignoredImports)) {
165
+ if (options.debug) {
166
+ console.log('[macaly-tagger] Skipping ignored import:', tagName);
167
+ }
168
+ return;
169
+ }
170
+ if (!(0, dom_elements_1.shouldTagElement)(tagName)) {
171
+ if (options.debug) {
172
+ console.log('[macaly-tagger] Skipping element:', tagName);
173
+ }
174
+ return;
175
+ }
153
176
  const macalyLoc = `${fileRelative}:${location.line}:${location.column}`;
154
177
  if (options.debug) {
155
178
  console.log('[macaly-tagger] Adding attributes to:', tagName, 'at', macalyLoc);
package/dist/types.d.ts CHANGED
@@ -2,6 +2,7 @@ import { LoaderDefinitionFunction } from 'webpack';
2
2
  export interface MacalyTaggerLoaderOptions {
3
3
  debug?: boolean;
4
4
  disableSourceMaps?: boolean;
5
+ ignorePackages?: string[];
5
6
  }
6
7
  export interface SourceLocation {
7
8
  line: number;
@@ -1 +1 @@
1
- {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,wBAAwB,EAAE,MAAM,SAAS,CAAC;AAEnD,MAAM,WAAW,yBAAyB;IACxC,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,iBAAiB,CAAC,EAAE,OAAO,CAAC;CAC7B;AAED,MAAM,WAAW,cAAc;IAC7B,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,cAAc;IAC7B,OAAO,EAAE,MAAM,CAAC;IAChB,cAAc,EAAE,MAAM,CAAC;IACvB,QAAQ,EAAE,cAAc,CAAC;CAC1B;AAED,MAAM,WAAW,eAAe;IAC9B,IAAI,EAAE,MAAM,CAAC;IACb,GAAG,EAAE,GAAG,GAAG,IAAI,CAAC;CACjB;AAED,MAAM,MAAM,kBAAkB,GAAG,wBAAwB,CAAC,yBAAyB,CAAC,CAAC"}
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,wBAAwB,EAAE,MAAM,SAAS,CAAC;AAEnD,MAAM,WAAW,yBAAyB;IACxC,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,iBAAiB,CAAC,EAAE,OAAO,CAAC;IAS5B,cAAc,CAAC,EAAE,MAAM,EAAE,CAAC;CAC3B;AAED,MAAM,WAAW,cAAc;IAC7B,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,cAAc;IAC7B,OAAO,EAAE,MAAM,CAAC;IAChB,cAAc,EAAE,MAAM,CAAC;IACvB,QAAQ,EAAE,cAAc,CAAC;CAC1B;AAED,MAAM,WAAW,eAAe;IAC9B,IAAI,EAAE,MAAM,CAAC;IACb,GAAG,EAAE,GAAG,GAAG,IAAI,CAAC;CACjB;AAED,MAAM,MAAM,kBAAkB,GAAG,wBAAwB,CAAC,yBAAyB,CAAC,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "macaly-tagger",
3
- "version": "1.1.0",
3
+ "version": "1.2.0",
4
4
  "description": "A webpack loader that adds location metadata to JSX elements for development debugging",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
@@ -13,6 +13,22 @@
13
13
  },
14
14
  "./package.json": "./package.json"
15
15
  },
16
+ "scripts": {
17
+ "build": "tsc -p tsconfig.build.json",
18
+ "build:watch": "tsc -p tsconfig.build.json --watch",
19
+ "clean": "rimraf dist",
20
+ "dev": "tsc -p tsconfig.build.json --watch",
21
+ "lint": "eslint src --ext .ts,.tsx",
22
+ "lint:fix": "eslint src --ext .ts,.tsx --fix",
23
+ "format": "prettier --write \"src/**/*.{ts,tsx}\"",
24
+ "format:check": "prettier --check \"src/**/*.{ts,tsx}\"",
25
+ "test": "vitest run",
26
+ "test:watch": "vitest",
27
+ "test:coverage": "vitest run --coverage",
28
+ "type-check": "tsc --noEmit",
29
+ "prepublishOnly": "npm run clean && npm run build && npm run test && npm run lint",
30
+ "prepack": "npm run build"
31
+ },
16
32
  "keywords": [
17
33
  "webpack",
18
34
  "loader",
@@ -33,8 +49,8 @@
33
49
  "license": "MIT",
34
50
  "dependencies": {
35
51
  "@babel/parser": "^7.24.0",
36
- "magic-string": "^0.30.0",
37
- "estree-walker": "^2.0.2"
52
+ "estree-walker": "^2.0.2",
53
+ "magic-string": "^0.30.0"
38
54
  },
39
55
  "devDependencies": {
40
56
  "@babel/types": "^7.24.0",
@@ -45,10 +61,10 @@
45
61
  "eslint": "^8.57.0",
46
62
  "eslint-config-prettier": "^9.1.0",
47
63
  "eslint-plugin-prettier": "^5.1.3",
48
- "vitest": "^1.4.0",
49
64
  "prettier": "^3.2.5",
50
65
  "rimraf": "^5.0.5",
51
- "typescript": "^5.4.2"
66
+ "typescript": "^5.4.2",
67
+ "vitest": "^4.0.17"
52
68
  },
53
69
  "peerDependencies": {
54
70
  "webpack": ">=4.0.0"
@@ -69,18 +85,5 @@
69
85
  "url": "https://github.com/langtail/macaly-tagger/issues"
70
86
  },
71
87
  "homepage": "https://github.com/langtail/macaly-tagger#readme",
72
- "scripts": {
73
- "build": "tsc -p tsconfig.build.json",
74
- "build:watch": "tsc -p tsconfig.build.json --watch",
75
- "clean": "rimraf dist",
76
- "dev": "tsc -p tsconfig.build.json --watch",
77
- "lint": "eslint src --ext .ts,.tsx",
78
- "lint:fix": "eslint src --ext .ts,.tsx --fix",
79
- "format": "prettier --write \"src/**/*.{ts,tsx}\"",
80
- "format:check": "prettier --check \"src/**/*.{ts,tsx}\"",
81
- "test": "vitest run",
82
- "test:watch": "vitest",
83
- "test:coverage": "vitest run --coverage",
84
- "type-check": "tsc --noEmit"
85
- }
86
- }
88
+ "packageManager": "pnpm@9.15.9+sha512.68046141893c66fad01c079231128e9afb89ef87e2691d69e4d40eee228988295fd4682181bae55b58418c3a253bde65a505ec7c5f9403ece5cc3cd37dcf2531"
89
+ }