@askdepth/react 0.1.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.
@@ -0,0 +1,252 @@
1
+ 'use strict';
2
+
3
+ var unplugin = require('unplugin');
4
+ var crypto = require('crypto');
5
+ var fs = require('fs');
6
+ var path = require('path');
7
+ var parser = require('@babel/parser');
8
+ var generateModule = require('@babel/generator');
9
+ var traverseModule = require('@babel/traverse');
10
+ var t = require('@babel/types');
11
+
12
+ function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
13
+
14
+ function _interopNamespace(e) {
15
+ if (e && e.__esModule) return e;
16
+ var n = Object.create(null);
17
+ if (e) {
18
+ Object.keys(e).forEach(function (k) {
19
+ if (k !== 'default') {
20
+ var d = Object.getOwnPropertyDescriptor(e, k);
21
+ Object.defineProperty(n, k, d.get ? d : {
22
+ enumerable: true,
23
+ get: function () { return e[k]; }
24
+ });
25
+ }
26
+ });
27
+ }
28
+ n.default = e;
29
+ return Object.freeze(n);
30
+ }
31
+
32
+ var generateModule__default = /*#__PURE__*/_interopDefault(generateModule);
33
+ var traverseModule__default = /*#__PURE__*/_interopDefault(traverseModule);
34
+ var t__namespace = /*#__PURE__*/_interopNamespace(t);
35
+
36
+ // src/plugin/index.ts
37
+ function writePrivateComponentMap(filename, source, result, options = {}) {
38
+ const buildId = options.buildId ?? process.env.ASKDEPTH_BUILD_ID ?? process.env.GITHUB_SHA ?? `local-${process.pid}`;
39
+ if (!/^[A-Za-z0-9_-][A-Za-z0-9._-]*$/.test(buildId) || buildId === "..") {
40
+ throw new Error("Invalid Askdepth build ID");
41
+ }
42
+ const mappingDir = options.mappingDir ?? process.env.ASKDEPTH_COMPONENT_MAP_DIR ?? path.join(process.cwd(), ".askdepth", "component-maps");
43
+ const directory = path.resolve(mappingDir, buildId);
44
+ fs.mkdirSync(directory, { recursive: true });
45
+ const fileId = crypto.createHash("sha256").update(filename).update("\0").update(source).digest("hex");
46
+ const target = path.join(directory, `${fileId}.json`);
47
+ const temporary = path.join(directory, `${fileId}.${process.pid}.${crypto.randomUUID()}.tmp`);
48
+ fs.writeFileSync(temporary, JSON.stringify({ buildId, locations: result.locations }));
49
+ fs.renameSync(temporary, target);
50
+ }
51
+
52
+ // src/constants.ts
53
+ var ASKDEPTH_SRC_ATTR = "data-askdepth-src";
54
+ var ASKDEPTH_ID_ATTR = "data-askdepth-id";
55
+
56
+ // src/plugin/transformers/jsx-attribute.ts
57
+ function unwrap(mod) {
58
+ if (typeof mod === "function") return mod;
59
+ if (mod && typeof mod === "object" && "default" in mod) {
60
+ return mod.default;
61
+ }
62
+ return mod;
63
+ }
64
+ var traverse = unwrap(traverseModule__default.default);
65
+ var generate = unwrap(generateModule__default.default);
66
+ var JSX_RUNTIME = /* @__PURE__ */ new Set(["react/jsx-runtime", "react/jsx-dev-runtime"]);
67
+ function containsJsx(code) {
68
+ return code.includes("jsx-runtime") || code.includes("jsx-dev-runtime") || code.includes("react/jsx") || code.includes("</") || code.includes("<>") || /<[A-Za-z_$][\w.-]*(?:\s|>|\/)/.test(code);
69
+ }
70
+ function shouldTransform(id, code) {
71
+ const clean = id.split("?")[0]?.split("#")[0] ?? id;
72
+ if (!clean || clean.includes("\0") || clean.includes("node_modules")) return false;
73
+ if (/\.(tsx|jsx)$/.test(clean)) return true;
74
+ if (/\.(js|mjs|cjs)$/.test(clean)) {
75
+ if (code !== void 0) {
76
+ return containsJsx(code);
77
+ }
78
+ return true;
79
+ }
80
+ return false;
81
+ }
82
+ function sourceLabel(filename, line, column) {
83
+ const clean = filename.split("?")[0]?.split("#")[0] ?? filename;
84
+ const file = path.isAbsolute(clean) ? path.relative(process.cwd(), clean) : clean;
85
+ return `${file.split("\\").join("/")}:${line}:${column}`;
86
+ }
87
+ function hashComponentId(label) {
88
+ return `cmp_${crypto.createHash("sha256").update(label).digest("hex").slice(0, 8)}`;
89
+ }
90
+ function marker(filename, line, column, production) {
91
+ const label = sourceLabel(filename, line, column);
92
+ if (production) return { name: ASKDEPTH_ID_ATTR, value: hashComponentId(label) };
93
+ return { name: ASKDEPTH_SRC_ATTR, value: label };
94
+ }
95
+ function isFragmentName(path) {
96
+ const name = path.node.name;
97
+ if (t__namespace.isJSXIdentifier(name)) {
98
+ const binding2 = path.scope.getBinding(name.name);
99
+ if (!binding2?.path.isImportSpecifier()) return false;
100
+ const imported = binding2.path.node.imported;
101
+ return (t__namespace.isIdentifier(imported) ? imported.name : imported.value) === "Fragment" && !!binding2.path.parent && t__namespace.isImportDeclaration(binding2.path.parent) && binding2.path.parent.source.value === "react";
102
+ }
103
+ if (!t__namespace.isJSXMemberExpression(name) || !t__namespace.isJSXIdentifier(name.object) || name.property.name !== "Fragment") return false;
104
+ const binding = path.scope.getBinding(name.object.name);
105
+ if (!binding) return name.object.name === "React";
106
+ return (binding.path.isImportDefaultSpecifier() || binding.path.isImportNamespaceSpecifier()) && !!binding.path.parent && t__namespace.isImportDeclaration(binding.path.parent) && binding.path.parent.source.value === "react";
107
+ }
108
+ function isCompiledFragment(path) {
109
+ const type = path.node.arguments[0];
110
+ if (!type || !t__namespace.isIdentifier(type)) return false;
111
+ const binding = path.scope.getBinding(type.name);
112
+ if (!binding?.path.isImportSpecifier()) return false;
113
+ const imported = binding.path.node.imported;
114
+ return (t__namespace.isIdentifier(imported) ? imported.name : imported.value) === "Fragment" && !!binding.path.parent && t__namespace.isImportDeclaration(binding.path.parent) && JSX_RUNTIME.has(binding.path.parent.source.value);
115
+ }
116
+ function hasJsxAttribute(opening, name) {
117
+ return opening.attributes.some(
118
+ (attr) => t__namespace.isJSXAttribute(attr) && t__namespace.isJSXIdentifier(attr.name) && attr.name.name === name
119
+ );
120
+ }
121
+ function hasObjectProperty(object, name) {
122
+ return object.properties.some(
123
+ (prop) => t__namespace.isObjectProperty(prop) && (t__namespace.isIdentifier(prop.key) && prop.key.name === name || t__namespace.isStringLiteral(prop.key) && prop.key.value === name)
124
+ );
125
+ }
126
+ function jsxRuntimeSource(path) {
127
+ const callee = path.node.callee;
128
+ if (!t__namespace.isIdentifier(callee)) return null;
129
+ const binding = path.scope.getBinding(callee.name);
130
+ const parent = binding?.path.parent;
131
+ if (!parent || !t__namespace.isImportDeclaration(parent)) return null;
132
+ return JSX_RUNTIME.has(parent.source.value) ? parent.source.value : null;
133
+ }
134
+ function locationOf(node, filename, path) {
135
+ if (path && jsxRuntimeSource(path) === "react/jsx-dev-runtime" && path.node.arguments[4] && t__namespace.isObjectExpression(path.node.arguments[4])) {
136
+ const source = path.node.arguments[4];
137
+ const line = numericProp(source, "lineNumber");
138
+ const column = numericProp(source, "columnNumber");
139
+ if (line !== null) return { line, column: column ?? 1 };
140
+ }
141
+ if (!node.loc) return null;
142
+ return { line: node.loc.start.line, column: node.loc.start.column + 1 };
143
+ }
144
+ function numericProp(object, name) {
145
+ for (const prop of object.properties) {
146
+ if (!t__namespace.isObjectProperty(prop)) continue;
147
+ const key = t__namespace.isIdentifier(prop.key) ? prop.key.name : t__namespace.isStringLiteral(prop.key) ? prop.key.value : null;
148
+ if (key === name && t__namespace.isNumericLiteral(prop.value)) return prop.value.value;
149
+ }
150
+ return null;
151
+ }
152
+ function transformJsxSource(code, filename, options) {
153
+ if (!shouldTransform(filename, code)) return null;
154
+ let ast;
155
+ try {
156
+ ast = parser.parse(code, {
157
+ sourceType: "module",
158
+ sourceFilename: filename,
159
+ plugins: ["jsx", "typescript"]
160
+ });
161
+ } catch {
162
+ return null;
163
+ }
164
+ let changed = false;
165
+ const locations = {};
166
+ const file = filename.split("?")[0]?.split("#")[0] ?? filename;
167
+ traverse(ast, {
168
+ JSXOpeningElement(path) {
169
+ if (isFragmentName(path)) return;
170
+ const loc = locationOf(path.node, file, null);
171
+ if (!loc) return;
172
+ const attr = marker(file, loc.line, loc.column, options.production);
173
+ if (hasJsxAttribute(path.node, attr.name)) return;
174
+ path.node.attributes.push(t__namespace.jsxAttribute(t__namespace.jsxIdentifier(attr.name), t__namespace.stringLiteral(attr.value)));
175
+ if (options.production) locations[attr.value] = sourceLabel(file, loc.line, loc.column);
176
+ changed = true;
177
+ },
178
+ CallExpression(path) {
179
+ if (!jsxRuntimeSource(path)) return;
180
+ if (isCompiledFragment(path)) return;
181
+ const props = path.node.arguments[1];
182
+ if (!props || !t__namespace.isObjectExpression(props)) return;
183
+ const loc = locationOf(path.node, file, path);
184
+ if (!loc) return;
185
+ const attr = marker(file, loc.line, loc.column, options.production);
186
+ if (hasObjectProperty(props, attr.name)) return;
187
+ props.properties.push(t__namespace.objectProperty(t__namespace.stringLiteral(attr.name), t__namespace.stringLiteral(attr.value)));
188
+ if (options.production) locations[attr.value] = sourceLabel(file, loc.line, loc.column);
189
+ changed = true;
190
+ }
191
+ });
192
+ if (!changed) return null;
193
+ const generated = generate(ast, { sourceMaps: true, sourceFileName: file, comments: true }, code);
194
+ return { code: generated.code, map: generated.map ?? null, locations };
195
+ }
196
+
197
+ // src/plugin/next.ts
198
+ function withAskdepth(nextConfig) {
199
+ const base = nextConfig ?? {};
200
+ const previous = base.webpack;
201
+ return {
202
+ ...base,
203
+ webpack(config, context) {
204
+ const result = previous ? previous(config, context) : config;
205
+ result.plugins.push(
206
+ askdepthWebpackPlugin({ environment: context.dev ? "development" : "production" })
207
+ );
208
+ return result;
209
+ }
210
+ };
211
+ }
212
+
213
+ // src/plugin/index.ts
214
+ function createAskdepthPlugin(options = {}) {
215
+ const production = (options.environment ?? process.env.NODE_ENV) === "production";
216
+ return {
217
+ name: "askdepth:react",
218
+ enforce: "pre",
219
+ transformInclude(id) {
220
+ return shouldTransform(id);
221
+ },
222
+ transform(code, id) {
223
+ const result = transformJsxSource(code, id, { production });
224
+ if (!result) return null;
225
+ if (production) writePrivateComponentMap(id, code, result, options);
226
+ return { code: result.code, map: result.map ?? void 0 };
227
+ }
228
+ };
229
+ }
230
+ var askdepthUnplugin = unplugin.createUnplugin(
231
+ (options) => createAskdepthPlugin(options ?? {})
232
+ );
233
+ function askdepthVitePlugin(options) {
234
+ return askdepthUnplugin.vite(options);
235
+ }
236
+ function askdepthWebpackPlugin(options) {
237
+ return askdepthUnplugin.webpack(options);
238
+ }
239
+ function askdepthRspackPlugin(options) {
240
+ return askdepthUnplugin.rspack(options);
241
+ }
242
+
243
+ exports.askdepthRspackPlugin = askdepthRspackPlugin;
244
+ exports.askdepthUnplugin = askdepthUnplugin;
245
+ exports.askdepthVitePlugin = askdepthVitePlugin;
246
+ exports.askdepthWebpackPlugin = askdepthWebpackPlugin;
247
+ exports.createAskdepthPlugin = createAskdepthPlugin;
248
+ exports.shouldTransform = shouldTransform;
249
+ exports.transformJsxSource = transformJsxSource;
250
+ exports.withAskdepth = withAskdepth;
251
+ //# sourceMappingURL=index.cjs.map
252
+ //# sourceMappingURL=index.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/plugin/component-map.ts","../../src/constants.ts","../../src/plugin/transformers/jsx-attribute.ts","../../src/plugin/next.ts","../../src/plugin/index.ts"],"names":["join","resolve","mkdirSync","createHash","randomUUID","writeFileSync","renameSync","traverseModule","generateModule","isAbsolute","relative","t","binding","parse","createUnplugin"],"mappings":"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","file":"index.cjs","sourcesContent":["import { createHash, randomUUID } from 'node:crypto';\nimport { mkdirSync, renameSync, writeFileSync } from 'node:fs';\nimport { join, resolve } from 'node:path';\nimport type { JsxTransformResult } from './transformers/jsx-attribute.js';\n\nexport interface ComponentMapOptions {\n /** Deployment or build identifier used to locate the private lookup files. */\n buildId?: string;\n /** Private output directory. Keep this outside publicly served assets. */\n mappingDir?: string;\n}\n\nexport function writePrivateComponentMap(\n filename: string,\n source: string,\n result: JsxTransformResult,\n options: ComponentMapOptions = {},\n): void {\n const buildId = options.buildId ?? process.env.ASKDEPTH_BUILD_ID ?? process.env.GITHUB_SHA ?? `local-${process.pid}`;\n if (!/^[A-Za-z0-9_-][A-Za-z0-9._-]*$/.test(buildId) || buildId === '..') {\n throw new Error('Invalid Askdepth build ID');\n }\n const mappingDir = options.mappingDir ?? process.env.ASKDEPTH_COMPONENT_MAP_DIR ?? join(process.cwd(), '.askdepth', 'component-maps');\n const directory = resolve(mappingDir, buildId);\n mkdirSync(directory, { recursive: true });\n const fileId = createHash('sha256').update(filename).update('\\0').update(source).digest('hex');\n const target = join(directory, `${fileId}.json`);\n const temporary = join(directory, `${fileId}.${process.pid}.${randomUUID()}.tmp`);\n writeFileSync(temporary, JSON.stringify({ buildId, locations: result.locations }));\n renameSync(temporary, target);\n}\n","export const ASKDEPTH_SRC_ATTR = 'data-askdepth-src';\nexport const ASKDEPTH_ID_ATTR = 'data-askdepth-id';\nexport const FIBER_KEY_PREFIX = '__reactFiber$';\nexport const LEGACY_FIBER_KEY_PREFIX = '__reactInternalInstance$';\nexport const PAGE_VIEW_EVENT = 'page_view';\nexport const ERROR_CLICK_EVENT = 'ERROR_CLICK';\n\n/** Function, Class, Indeterminate, ForwardRef, Memo, SimpleMemo, Lazy. */\nexport const COMPOSITE_FIBER_TAGS = new Set([0, 1, 2, 11, 14, 15, 16]);\n","import { createHash } from 'node:crypto';\nimport { isAbsolute, relative } from 'node:path';\nimport { parse } from '@babel/parser';\nimport generateModule from '@babel/generator';\nimport traverseModule from '@babel/traverse';\nimport * as t from '@babel/types';\nimport type { NodePath } from '@babel/traverse';\nimport { ASKDEPTH_ID_ATTR, ASKDEPTH_SRC_ATTR } from '../../constants.js';\n\nexport interface JsxTransformOptions {\n production: boolean;\n}\n\nexport interface JsxTransformResult {\n code: string;\n map: ReturnType<typeof import('@babel/generator').default>['map'] | null;\n locations: Record<string, string>;\n}\n\ntype Traverse = {\n (parent: t.Node, opts: Record<string, unknown>): void;\n};\n\nfunction unwrap<T>(mod: T): T extends { default: infer D } ? D : T {\n if (typeof mod === 'function') return mod as T extends { default: infer D } ? D : T;\n if (mod && typeof mod === 'object' && 'default' in mod) {\n return (mod as { default: T extends { default: infer D } ? D : T }).default;\n }\n return mod as T extends { default: infer D } ? D : T;\n}\n\nconst traverse = unwrap(traverseModule) as unknown as Traverse;\nconst generate = unwrap(generateModule) as unknown as typeof import('@babel/generator').default;\n\nconst JSX_RUNTIME = new Set(['react/jsx-runtime', 'react/jsx-dev-runtime']);\n\nfunction containsJsx(code: string): boolean {\n return (\n code.includes('jsx-runtime') ||\n code.includes('jsx-dev-runtime') ||\n code.includes('react/jsx') ||\n code.includes('</') ||\n code.includes('<>') ||\n /<[A-Za-z_$][\\w.-]*(?:\\s|>|\\/)/.test(code)\n );\n}\n\nexport function shouldTransform(id: string, code?: string): boolean {\n const clean = id.split('?')[0]?.split('#')[0] ?? id;\n if (!clean || clean.includes('\\0') || clean.includes('node_modules')) return false;\n if (/\\.(tsx|jsx)$/.test(clean)) return true;\n if (/\\.(js|mjs|cjs)$/.test(clean)) {\n if (code !== undefined) {\n return containsJsx(code);\n }\n return true;\n }\n return false;\n}\n\nexport function sourceLabel(filename: string, line: number, column: number): string {\n const clean = filename.split('?')[0]?.split('#')[0] ?? filename;\n const file = isAbsolute(clean) ? relative(process.cwd(), clean) : clean;\n return `${file.split('\\\\').join('/')}:${line}:${column}`;\n}\n\nexport function hashComponentId(label: string): string {\n return `cmp_${createHash('sha256').update(label).digest('hex').slice(0, 8)}`;\n}\n\nfunction marker(filename: string, line: number, column: number, production: boolean): { name: string; value: string } {\n const label = sourceLabel(filename, line, column);\n if (production) return { name: ASKDEPTH_ID_ATTR, value: hashComponentId(label) };\n return { name: ASKDEPTH_SRC_ATTR, value: label };\n}\n\nfunction isFragmentName(path: NodePath<t.JSXOpeningElement>): boolean {\n const name = path.node.name;\n if (t.isJSXIdentifier(name)) {\n const binding = path.scope.getBinding(name.name);\n if (!binding?.path.isImportSpecifier()) return false;\n const imported = binding.path.node.imported;\n return (t.isIdentifier(imported) ? imported.name : imported.value) === 'Fragment' &&\n !!binding.path.parent && t.isImportDeclaration(binding.path.parent) && binding.path.parent.source.value === 'react';\n }\n if (!t.isJSXMemberExpression(name) || !t.isJSXIdentifier(name.object) || name.property.name !== 'Fragment') return false;\n const binding = path.scope.getBinding(name.object.name);\n if (!binding) return name.object.name === 'React';\n return (binding.path.isImportDefaultSpecifier() || binding.path.isImportNamespaceSpecifier()) &&\n !!binding.path.parent && t.isImportDeclaration(binding.path.parent) && binding.path.parent.source.value === 'react';\n}\n\nfunction isCompiledFragment(path: NodePath<t.CallExpression>): boolean {\n const type = path.node.arguments[0];\n if (!type || !t.isIdentifier(type)) return false;\n const binding = path.scope.getBinding(type.name);\n if (!binding?.path.isImportSpecifier()) return false;\n const imported = binding.path.node.imported;\n return (t.isIdentifier(imported) ? imported.name : imported.value) === 'Fragment' &&\n !!binding.path.parent && t.isImportDeclaration(binding.path.parent) && JSX_RUNTIME.has(binding.path.parent.source.value);\n}\n\nfunction hasJsxAttribute(opening: t.JSXOpeningElement, name: string): boolean {\n return opening.attributes.some(\n (attr) => t.isJSXAttribute(attr) && t.isJSXIdentifier(attr.name) && attr.name.name === name,\n );\n}\n\nfunction hasObjectProperty(object: t.ObjectExpression, name: string): boolean {\n return object.properties.some(\n (prop) =>\n t.isObjectProperty(prop) &&\n ((t.isIdentifier(prop.key) && prop.key.name === name) ||\n (t.isStringLiteral(prop.key) && prop.key.value === name)),\n );\n}\n\nfunction jsxRuntimeSource(path: NodePath<t.CallExpression>): string | null {\n const callee = path.node.callee;\n if (!t.isIdentifier(callee)) return null;\n const binding = path.scope.getBinding(callee.name);\n const parent = binding?.path.parent;\n if (!parent || !t.isImportDeclaration(parent)) return null;\n return JSX_RUNTIME.has(parent.source.value) ? parent.source.value : null;\n}\n\nfunction locationOf(node: t.Node, filename: string, path: NodePath<t.CallExpression> | null): { line: number; column: number } | null {\n if (path && jsxRuntimeSource(path) === 'react/jsx-dev-runtime' && path.node.arguments[4] && t.isObjectExpression(path.node.arguments[4])) {\n const source = path.node.arguments[4];\n const line = numericProp(source, 'lineNumber');\n const column = numericProp(source, 'columnNumber');\n if (line !== null) return { line, column: column ?? 1 };\n }\n if (!node.loc) return null;\n return { line: node.loc.start.line, column: node.loc.start.column + 1 };\n}\n\nfunction numericProp(object: t.ObjectExpression, name: string): number | null {\n for (const prop of object.properties) {\n if (!t.isObjectProperty(prop)) continue;\n const key = t.isIdentifier(prop.key) ? prop.key.name : t.isStringLiteral(prop.key) ? prop.key.value : null;\n if (key === name && t.isNumericLiteral(prop.value)) return prop.value.value;\n }\n return null;\n}\n\nexport function transformJsxSource(code: string, filename: string, options: JsxTransformOptions): JsxTransformResult | null {\n if (!shouldTransform(filename, code)) return null;\n let ast: t.File;\n try {\n ast = parse(code, {\n sourceType: 'module',\n sourceFilename: filename,\n plugins: ['jsx', 'typescript'],\n });\n } catch {\n return null;\n }\n\n let changed = false;\n const locations: Record<string, string> = {};\n const file = filename.split('?')[0]?.split('#')[0] ?? filename;\n\n traverse(ast, {\n JSXOpeningElement(path: NodePath<t.JSXOpeningElement>) {\n if (isFragmentName(path)) return;\n const loc = locationOf(path.node, file, null);\n if (!loc) return;\n const attr = marker(file, loc.line, loc.column, options.production);\n if (hasJsxAttribute(path.node, attr.name)) return;\n path.node.attributes.push(t.jsxAttribute(t.jsxIdentifier(attr.name), t.stringLiteral(attr.value)));\n if (options.production) locations[attr.value] = sourceLabel(file, loc.line, loc.column);\n changed = true;\n },\n CallExpression(path: NodePath<t.CallExpression>) {\n if (!jsxRuntimeSource(path)) return;\n if (isCompiledFragment(path)) return;\n const props = path.node.arguments[1];\n if (!props || !t.isObjectExpression(props)) return;\n const loc = locationOf(path.node, file, path);\n if (!loc) return;\n const attr = marker(file, loc.line, loc.column, options.production);\n if (hasObjectProperty(props, attr.name)) return;\n props.properties.push(t.objectProperty(t.stringLiteral(attr.name), t.stringLiteral(attr.value)));\n if (options.production) locations[attr.value] = sourceLabel(file, loc.line, loc.column);\n changed = true;\n },\n });\n\n if (!changed) return null;\n const generated = generate(ast, { sourceMaps: true, sourceFileName: file, comments: true }, code);\n return { code: generated.code, map: generated.map ?? null, locations };\n}\n","import { askdepthWebpackPlugin } from './index.js';\n\nexport interface AskdepthNextWebpackContext {\n isServer: boolean;\n dev: boolean;\n}\n\nexport interface AskdepthWebpackConfig {\n plugins: unknown[];\n}\n\nexport interface AskdepthNextConfig {\n webpack?: (config: AskdepthWebpackConfig, context: AskdepthNextWebpackContext) => AskdepthWebpackConfig;\n}\n\nexport function withAskdepth<T extends AskdepthNextConfig>(\n nextConfig?: T,\n): T & {\n webpack: (config: AskdepthWebpackConfig, context: AskdepthNextWebpackContext) => AskdepthWebpackConfig;\n} {\n const base = (nextConfig ?? {}) as T;\n const previous = base.webpack;\n return {\n ...base,\n webpack(config, context) {\n const result = previous ? previous(config, context) : config;\n result.plugins.push(\n askdepthWebpackPlugin({ environment: context.dev ? 'development' : 'production' }),\n );\n return result;\n },\n };\n}\n","import { createUnplugin } from 'unplugin';\nimport { writePrivateComponentMap } from './component-map.js';\nimport type { ComponentMapOptions } from './component-map.js';\nimport { shouldTransform, transformJsxSource } from './transformers/jsx-attribute.js';\n\nexport interface AskdepthPluginOptions extends ComponentMapOptions {\n /** `production` hashes file locations. Any other value keeps `path:line:column`. */\n environment?: string;\n}\n\nexport { shouldTransform, transformJsxSource };\n\nexport function createAskdepthPlugin(options: AskdepthPluginOptions = {}) {\n const production = (options.environment ?? process.env.NODE_ENV) === 'production';\n return {\n name: 'askdepth:react',\n enforce: 'pre' as const,\n transformInclude(id: string) {\n return shouldTransform(id);\n },\n transform(code: string, id: string) {\n const result = transformJsxSource(code, id, { production });\n if (!result) return null;\n if (production) writePrivateComponentMap(id, code, result, options);\n return { code: result.code, map: result.map ?? undefined };\n },\n };\n}\n\nexport const askdepthUnplugin = createUnplugin<AskdepthPluginOptions | undefined>((options) =>\n createAskdepthPlugin(options ?? {}),\n);\n\nexport function askdepthVitePlugin(options?: AskdepthPluginOptions) {\n return askdepthUnplugin.vite(options);\n}\n\nexport function askdepthWebpackPlugin(options?: AskdepthPluginOptions) {\n return askdepthUnplugin.webpack(options);\n}\n\nexport function askdepthRspackPlugin(options?: AskdepthPluginOptions) {\n return askdepthUnplugin.rspack(options);\n}\n\nexport { withAskdepth } from './next.js';\nexport type { AskdepthNextConfig, AskdepthNextWebpackContext, AskdepthWebpackConfig } from './next.js';\n"]}
@@ -0,0 +1,53 @@
1
+ import * as unplugin from 'unplugin';
2
+ export { s as shouldTransform, t as transformJsxSource } from '../jsx-attribute-Dl6s88lp.cjs';
3
+ import '@babel/generator';
4
+
5
+ interface ComponentMapOptions {
6
+ /** Deployment or build identifier used to locate the private lookup files. */
7
+ buildId?: string;
8
+ /** Private output directory. Keep this outside publicly served assets. */
9
+ mappingDir?: string;
10
+ }
11
+
12
+ interface AskdepthNextWebpackContext {
13
+ isServer: boolean;
14
+ dev: boolean;
15
+ }
16
+ interface AskdepthWebpackConfig {
17
+ plugins: unknown[];
18
+ }
19
+ interface AskdepthNextConfig {
20
+ webpack?: (config: AskdepthWebpackConfig, context: AskdepthNextWebpackContext) => AskdepthWebpackConfig;
21
+ }
22
+ declare function withAskdepth<T extends AskdepthNextConfig>(nextConfig?: T): T & {
23
+ webpack: (config: AskdepthWebpackConfig, context: AskdepthNextWebpackContext) => AskdepthWebpackConfig;
24
+ };
25
+
26
+ interface AskdepthPluginOptions extends ComponentMapOptions {
27
+ /** `production` hashes file locations. Any other value keeps `path:line:column`. */
28
+ environment?: string;
29
+ }
30
+
31
+ declare function createAskdepthPlugin(options?: AskdepthPluginOptions): {
32
+ name: string;
33
+ enforce: "pre";
34
+ transformInclude(id: string): boolean;
35
+ transform(code: string, id: string): {
36
+ code: string;
37
+ map: {
38
+ version: number;
39
+ sources: string[];
40
+ names: string[];
41
+ sourceRoot?: string | undefined;
42
+ sourcesContent?: string[] | undefined;
43
+ mappings: string;
44
+ file: string;
45
+ } | undefined;
46
+ } | null;
47
+ };
48
+ declare const askdepthUnplugin: unplugin.UnpluginInstance<AskdepthPluginOptions | undefined, boolean>;
49
+ declare function askdepthVitePlugin(options?: AskdepthPluginOptions): unplugin.VitePlugin<any> | unplugin.VitePlugin<any>[];
50
+ declare function askdepthWebpackPlugin(options?: AskdepthPluginOptions): WebpackPluginInstance;
51
+ declare function askdepthRspackPlugin(options?: AskdepthPluginOptions): RspackPluginInstance;
52
+
53
+ export { type AskdepthNextConfig, type AskdepthNextWebpackContext, type AskdepthPluginOptions, type AskdepthWebpackConfig, askdepthRspackPlugin, askdepthUnplugin, askdepthVitePlugin, askdepthWebpackPlugin, createAskdepthPlugin, withAskdepth };
@@ -0,0 +1,53 @@
1
+ import * as unplugin from 'unplugin';
2
+ export { s as shouldTransform, t as transformJsxSource } from '../jsx-attribute-Dl6s88lp.js';
3
+ import '@babel/generator';
4
+
5
+ interface ComponentMapOptions {
6
+ /** Deployment or build identifier used to locate the private lookup files. */
7
+ buildId?: string;
8
+ /** Private output directory. Keep this outside publicly served assets. */
9
+ mappingDir?: string;
10
+ }
11
+
12
+ interface AskdepthNextWebpackContext {
13
+ isServer: boolean;
14
+ dev: boolean;
15
+ }
16
+ interface AskdepthWebpackConfig {
17
+ plugins: unknown[];
18
+ }
19
+ interface AskdepthNextConfig {
20
+ webpack?: (config: AskdepthWebpackConfig, context: AskdepthNextWebpackContext) => AskdepthWebpackConfig;
21
+ }
22
+ declare function withAskdepth<T extends AskdepthNextConfig>(nextConfig?: T): T & {
23
+ webpack: (config: AskdepthWebpackConfig, context: AskdepthNextWebpackContext) => AskdepthWebpackConfig;
24
+ };
25
+
26
+ interface AskdepthPluginOptions extends ComponentMapOptions {
27
+ /** `production` hashes file locations. Any other value keeps `path:line:column`. */
28
+ environment?: string;
29
+ }
30
+
31
+ declare function createAskdepthPlugin(options?: AskdepthPluginOptions): {
32
+ name: string;
33
+ enforce: "pre";
34
+ transformInclude(id: string): boolean;
35
+ transform(code: string, id: string): {
36
+ code: string;
37
+ map: {
38
+ version: number;
39
+ sources: string[];
40
+ names: string[];
41
+ sourceRoot?: string | undefined;
42
+ sourcesContent?: string[] | undefined;
43
+ mappings: string;
44
+ file: string;
45
+ } | undefined;
46
+ } | null;
47
+ };
48
+ declare const askdepthUnplugin: unplugin.UnpluginInstance<AskdepthPluginOptions | undefined, boolean>;
49
+ declare function askdepthVitePlugin(options?: AskdepthPluginOptions): unplugin.VitePlugin<any> | unplugin.VitePlugin<any>[];
50
+ declare function askdepthWebpackPlugin(options?: AskdepthPluginOptions): WebpackPluginInstance;
51
+ declare function askdepthRspackPlugin(options?: AskdepthPluginOptions): RspackPluginInstance;
52
+
53
+ export { type AskdepthNextConfig, type AskdepthNextWebpackContext, type AskdepthPluginOptions, type AskdepthWebpackConfig, askdepthRspackPlugin, askdepthUnplugin, askdepthVitePlugin, askdepthWebpackPlugin, createAskdepthPlugin, withAskdepth };
@@ -0,0 +1,219 @@
1
+ import { createUnplugin } from 'unplugin';
2
+ import { createHash, randomUUID } from 'crypto';
3
+ import { mkdirSync, writeFileSync, renameSync } from 'fs';
4
+ import { join, resolve, isAbsolute, relative } from 'path';
5
+ import { parse } from '@babel/parser';
6
+ import generateModule from '@babel/generator';
7
+ import traverseModule from '@babel/traverse';
8
+ import * as t from '@babel/types';
9
+
10
+ // src/plugin/index.ts
11
+ function writePrivateComponentMap(filename, source, result, options = {}) {
12
+ const buildId = options.buildId ?? process.env.ASKDEPTH_BUILD_ID ?? process.env.GITHUB_SHA ?? `local-${process.pid}`;
13
+ if (!/^[A-Za-z0-9_-][A-Za-z0-9._-]*$/.test(buildId) || buildId === "..") {
14
+ throw new Error("Invalid Askdepth build ID");
15
+ }
16
+ const mappingDir = options.mappingDir ?? process.env.ASKDEPTH_COMPONENT_MAP_DIR ?? join(process.cwd(), ".askdepth", "component-maps");
17
+ const directory = resolve(mappingDir, buildId);
18
+ mkdirSync(directory, { recursive: true });
19
+ const fileId = createHash("sha256").update(filename).update("\0").update(source).digest("hex");
20
+ const target = join(directory, `${fileId}.json`);
21
+ const temporary = join(directory, `${fileId}.${process.pid}.${randomUUID()}.tmp`);
22
+ writeFileSync(temporary, JSON.stringify({ buildId, locations: result.locations }));
23
+ renameSync(temporary, target);
24
+ }
25
+
26
+ // src/constants.ts
27
+ var ASKDEPTH_SRC_ATTR = "data-askdepth-src";
28
+ var ASKDEPTH_ID_ATTR = "data-askdepth-id";
29
+
30
+ // src/plugin/transformers/jsx-attribute.ts
31
+ function unwrap(mod) {
32
+ if (typeof mod === "function") return mod;
33
+ if (mod && typeof mod === "object" && "default" in mod) {
34
+ return mod.default;
35
+ }
36
+ return mod;
37
+ }
38
+ var traverse = unwrap(traverseModule);
39
+ var generate = unwrap(generateModule);
40
+ var JSX_RUNTIME = /* @__PURE__ */ new Set(["react/jsx-runtime", "react/jsx-dev-runtime"]);
41
+ function containsJsx(code) {
42
+ return code.includes("jsx-runtime") || code.includes("jsx-dev-runtime") || code.includes("react/jsx") || code.includes("</") || code.includes("<>") || /<[A-Za-z_$][\w.-]*(?:\s|>|\/)/.test(code);
43
+ }
44
+ function shouldTransform(id, code) {
45
+ const clean = id.split("?")[0]?.split("#")[0] ?? id;
46
+ if (!clean || clean.includes("\0") || clean.includes("node_modules")) return false;
47
+ if (/\.(tsx|jsx)$/.test(clean)) return true;
48
+ if (/\.(js|mjs|cjs)$/.test(clean)) {
49
+ if (code !== void 0) {
50
+ return containsJsx(code);
51
+ }
52
+ return true;
53
+ }
54
+ return false;
55
+ }
56
+ function sourceLabel(filename, line, column) {
57
+ const clean = filename.split("?")[0]?.split("#")[0] ?? filename;
58
+ const file = isAbsolute(clean) ? relative(process.cwd(), clean) : clean;
59
+ return `${file.split("\\").join("/")}:${line}:${column}`;
60
+ }
61
+ function hashComponentId(label) {
62
+ return `cmp_${createHash("sha256").update(label).digest("hex").slice(0, 8)}`;
63
+ }
64
+ function marker(filename, line, column, production) {
65
+ const label = sourceLabel(filename, line, column);
66
+ if (production) return { name: ASKDEPTH_ID_ATTR, value: hashComponentId(label) };
67
+ return { name: ASKDEPTH_SRC_ATTR, value: label };
68
+ }
69
+ function isFragmentName(path) {
70
+ const name = path.node.name;
71
+ if (t.isJSXIdentifier(name)) {
72
+ const binding2 = path.scope.getBinding(name.name);
73
+ if (!binding2?.path.isImportSpecifier()) return false;
74
+ const imported = binding2.path.node.imported;
75
+ return (t.isIdentifier(imported) ? imported.name : imported.value) === "Fragment" && !!binding2.path.parent && t.isImportDeclaration(binding2.path.parent) && binding2.path.parent.source.value === "react";
76
+ }
77
+ if (!t.isJSXMemberExpression(name) || !t.isJSXIdentifier(name.object) || name.property.name !== "Fragment") return false;
78
+ const binding = path.scope.getBinding(name.object.name);
79
+ if (!binding) return name.object.name === "React";
80
+ return (binding.path.isImportDefaultSpecifier() || binding.path.isImportNamespaceSpecifier()) && !!binding.path.parent && t.isImportDeclaration(binding.path.parent) && binding.path.parent.source.value === "react";
81
+ }
82
+ function isCompiledFragment(path) {
83
+ const type = path.node.arguments[0];
84
+ if (!type || !t.isIdentifier(type)) return false;
85
+ const binding = path.scope.getBinding(type.name);
86
+ if (!binding?.path.isImportSpecifier()) return false;
87
+ const imported = binding.path.node.imported;
88
+ return (t.isIdentifier(imported) ? imported.name : imported.value) === "Fragment" && !!binding.path.parent && t.isImportDeclaration(binding.path.parent) && JSX_RUNTIME.has(binding.path.parent.source.value);
89
+ }
90
+ function hasJsxAttribute(opening, name) {
91
+ return opening.attributes.some(
92
+ (attr) => t.isJSXAttribute(attr) && t.isJSXIdentifier(attr.name) && attr.name.name === name
93
+ );
94
+ }
95
+ function hasObjectProperty(object, name) {
96
+ return object.properties.some(
97
+ (prop) => t.isObjectProperty(prop) && (t.isIdentifier(prop.key) && prop.key.name === name || t.isStringLiteral(prop.key) && prop.key.value === name)
98
+ );
99
+ }
100
+ function jsxRuntimeSource(path) {
101
+ const callee = path.node.callee;
102
+ if (!t.isIdentifier(callee)) return null;
103
+ const binding = path.scope.getBinding(callee.name);
104
+ const parent = binding?.path.parent;
105
+ if (!parent || !t.isImportDeclaration(parent)) return null;
106
+ return JSX_RUNTIME.has(parent.source.value) ? parent.source.value : null;
107
+ }
108
+ function locationOf(node, filename, path) {
109
+ if (path && jsxRuntimeSource(path) === "react/jsx-dev-runtime" && path.node.arguments[4] && t.isObjectExpression(path.node.arguments[4])) {
110
+ const source = path.node.arguments[4];
111
+ const line = numericProp(source, "lineNumber");
112
+ const column = numericProp(source, "columnNumber");
113
+ if (line !== null) return { line, column: column ?? 1 };
114
+ }
115
+ if (!node.loc) return null;
116
+ return { line: node.loc.start.line, column: node.loc.start.column + 1 };
117
+ }
118
+ function numericProp(object, name) {
119
+ for (const prop of object.properties) {
120
+ if (!t.isObjectProperty(prop)) continue;
121
+ const key = t.isIdentifier(prop.key) ? prop.key.name : t.isStringLiteral(prop.key) ? prop.key.value : null;
122
+ if (key === name && t.isNumericLiteral(prop.value)) return prop.value.value;
123
+ }
124
+ return null;
125
+ }
126
+ function transformJsxSource(code, filename, options) {
127
+ if (!shouldTransform(filename, code)) return null;
128
+ let ast;
129
+ try {
130
+ ast = parse(code, {
131
+ sourceType: "module",
132
+ sourceFilename: filename,
133
+ plugins: ["jsx", "typescript"]
134
+ });
135
+ } catch {
136
+ return null;
137
+ }
138
+ let changed = false;
139
+ const locations = {};
140
+ const file = filename.split("?")[0]?.split("#")[0] ?? filename;
141
+ traverse(ast, {
142
+ JSXOpeningElement(path) {
143
+ if (isFragmentName(path)) return;
144
+ const loc = locationOf(path.node, file, null);
145
+ if (!loc) return;
146
+ const attr = marker(file, loc.line, loc.column, options.production);
147
+ if (hasJsxAttribute(path.node, attr.name)) return;
148
+ path.node.attributes.push(t.jsxAttribute(t.jsxIdentifier(attr.name), t.stringLiteral(attr.value)));
149
+ if (options.production) locations[attr.value] = sourceLabel(file, loc.line, loc.column);
150
+ changed = true;
151
+ },
152
+ CallExpression(path) {
153
+ if (!jsxRuntimeSource(path)) return;
154
+ if (isCompiledFragment(path)) return;
155
+ const props = path.node.arguments[1];
156
+ if (!props || !t.isObjectExpression(props)) return;
157
+ const loc = locationOf(path.node, file, path);
158
+ if (!loc) return;
159
+ const attr = marker(file, loc.line, loc.column, options.production);
160
+ if (hasObjectProperty(props, attr.name)) return;
161
+ props.properties.push(t.objectProperty(t.stringLiteral(attr.name), t.stringLiteral(attr.value)));
162
+ if (options.production) locations[attr.value] = sourceLabel(file, loc.line, loc.column);
163
+ changed = true;
164
+ }
165
+ });
166
+ if (!changed) return null;
167
+ const generated = generate(ast, { sourceMaps: true, sourceFileName: file, comments: true }, code);
168
+ return { code: generated.code, map: generated.map ?? null, locations };
169
+ }
170
+
171
+ // src/plugin/next.ts
172
+ function withAskdepth(nextConfig) {
173
+ const base = nextConfig ?? {};
174
+ const previous = base.webpack;
175
+ return {
176
+ ...base,
177
+ webpack(config, context) {
178
+ const result = previous ? previous(config, context) : config;
179
+ result.plugins.push(
180
+ askdepthWebpackPlugin({ environment: context.dev ? "development" : "production" })
181
+ );
182
+ return result;
183
+ }
184
+ };
185
+ }
186
+
187
+ // src/plugin/index.ts
188
+ function createAskdepthPlugin(options = {}) {
189
+ const production = (options.environment ?? process.env.NODE_ENV) === "production";
190
+ return {
191
+ name: "askdepth:react",
192
+ enforce: "pre",
193
+ transformInclude(id) {
194
+ return shouldTransform(id);
195
+ },
196
+ transform(code, id) {
197
+ const result = transformJsxSource(code, id, { production });
198
+ if (!result) return null;
199
+ if (production) writePrivateComponentMap(id, code, result, options);
200
+ return { code: result.code, map: result.map ?? void 0 };
201
+ }
202
+ };
203
+ }
204
+ var askdepthUnplugin = createUnplugin(
205
+ (options) => createAskdepthPlugin(options ?? {})
206
+ );
207
+ function askdepthVitePlugin(options) {
208
+ return askdepthUnplugin.vite(options);
209
+ }
210
+ function askdepthWebpackPlugin(options) {
211
+ return askdepthUnplugin.webpack(options);
212
+ }
213
+ function askdepthRspackPlugin(options) {
214
+ return askdepthUnplugin.rspack(options);
215
+ }
216
+
217
+ export { askdepthRspackPlugin, askdepthUnplugin, askdepthVitePlugin, askdepthWebpackPlugin, createAskdepthPlugin, shouldTransform, transformJsxSource, withAskdepth };
218
+ //# sourceMappingURL=index.mjs.map
219
+ //# sourceMappingURL=index.mjs.map