@frmwrkd/snag-anchor 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.
Files changed (75) hide show
  1. package/LICENSE +19 -0
  2. package/README.md +305 -0
  3. package/dist/babel/component-name.d.ts +42 -0
  4. package/dist/babel/component-name.d.ts.map +1 -0
  5. package/dist/babel/component-name.js +107 -0
  6. package/dist/babel/component-name.js.map +1 -0
  7. package/dist/babel/plugin.d.ts +69 -0
  8. package/dist/babel/plugin.d.ts.map +1 -0
  9. package/dist/babel/plugin.js +272 -0
  10. package/dist/babel/plugin.js.map +1 -0
  11. package/dist/babel/walk.d.ts +8 -0
  12. package/dist/babel/walk.d.ts.map +1 -0
  13. package/dist/babel/walk.js +50 -0
  14. package/dist/babel/walk.js.map +1 -0
  15. package/dist/devtools-json.d.ts +45 -0
  16. package/dist/devtools-json.d.ts.map +1 -0
  17. package/dist/devtools-json.js +117 -0
  18. package/dist/devtools-json.js.map +1 -0
  19. package/dist/esbuild.d.ts +3 -0
  20. package/dist/esbuild.d.ts.map +1 -0
  21. package/dist/esbuild.js +11 -0
  22. package/dist/esbuild.js.map +1 -0
  23. package/dist/index.d.ts +31 -0
  24. package/dist/index.d.ts.map +1 -0
  25. package/dist/index.js +90 -0
  26. package/dist/index.js.map +1 -0
  27. package/dist/loader.cjs +44 -0
  28. package/dist/loader.cjs.map +1 -0
  29. package/dist/loader.d.cts +2 -0
  30. package/dist/loader.d.cts.map +1 -0
  31. package/dist/magic-string.d.ts +23 -0
  32. package/dist/magic-string.d.ts.map +1 -0
  33. package/dist/magic-string.js +23 -0
  34. package/dist/magic-string.js.map +1 -0
  35. package/dist/nuxt.d.ts +14 -0
  36. package/dist/nuxt.d.ts.map +1 -0
  37. package/dist/nuxt.js +29 -0
  38. package/dist/nuxt.js.map +1 -0
  39. package/dist/options.d.ts +101 -0
  40. package/dist/options.d.ts.map +1 -0
  41. package/dist/options.js +122 -0
  42. package/dist/options.js.map +1 -0
  43. package/dist/rollup.d.ts +3 -0
  44. package/dist/rollup.d.ts.map +1 -0
  45. package/dist/rollup.js +11 -0
  46. package/dist/rollup.js.map +1 -0
  47. package/dist/root.d.ts +38 -0
  48. package/dist/root.d.ts.map +1 -0
  49. package/dist/root.js +101 -0
  50. package/dist/root.js.map +1 -0
  51. package/dist/rspack.d.ts +3 -0
  52. package/dist/rspack.d.ts.map +1 -0
  53. package/dist/rspack.js +11 -0
  54. package/dist/rspack.js.map +1 -0
  55. package/dist/stamp.d.ts +66 -0
  56. package/dist/stamp.d.ts.map +1 -0
  57. package/dist/stamp.js +28 -0
  58. package/dist/stamp.js.map +1 -0
  59. package/dist/transform.d.ts +14 -0
  60. package/dist/transform.d.ts.map +1 -0
  61. package/dist/transform.js +54 -0
  62. package/dist/transform.js.map +1 -0
  63. package/dist/vite.d.ts +3 -0
  64. package/dist/vite.d.ts.map +1 -0
  65. package/dist/vite.js +11 -0
  66. package/dist/vite.js.map +1 -0
  67. package/dist/vue/transform.d.ts +50 -0
  68. package/dist/vue/transform.d.ts.map +1 -0
  69. package/dist/vue/transform.js +188 -0
  70. package/dist/vue/transform.js.map +1 -0
  71. package/dist/webpack.d.ts +3 -0
  72. package/dist/webpack.d.ts.map +1 -0
  73. package/dist/webpack.js +15 -0
  74. package/dist/webpack.js.map +1 -0
  75. package/package.json +84 -0
package/dist/index.js ADDED
@@ -0,0 +1,90 @@
1
+ /**
2
+ * `@frmwrkd/snag-anchor` — the unplugin that stamps `data-snag="path:line:col"` onto
3
+ * DOM elements at build time.
4
+ *
5
+ * ```html
6
+ * <button data-snag="src/checkout/PromoField.tsx:42:7" data-snag-cmp="PromoField">
7
+ * ```
8
+ *
9
+ * Two attributes, self-contained — **no global registry, no indirection**
10
+ * (doc 02 §2.1). This matters because only `data-*` attributes cross the
11
+ * ISOLATED-world boundary: expando properties the page attaches to DOM nodes
12
+ * (`__reactFiber$*`, `__svelte_meta`) are invisible to an ISOLATED content
13
+ * script. Tier 0 is therefore the only resolution path with no `postMessage`
14
+ * round trip — one `getAttribute` and you're done.
15
+ *
16
+ * ```ts
17
+ * // vite.config.ts
18
+ * import snagAnchor from '@frmwrkd/snag-anchor/vite';
19
+ * export default defineConfig({ plugins: [snagAnchor()] });
20
+ * ```
21
+ */
22
+ import { createUnplugin } from 'unplugin';
23
+ import { createDevtoolsJsonMiddleware, DEVTOOLS_JSON_PATH } from './devtools-json.js';
24
+ import { resolveOptions } from './options.js';
25
+ import { transformSource } from './transform.js';
26
+ export const ANCHOR_ATTRIBUTE = 'data-snag';
27
+ export const COMPONENT_ATTRIBUTE = 'data-snag-cmp';
28
+ export { createFilter, DEFAULT_ATTRIBUTE, DEFAULT_COMPONENT_ATTRIBUTE, DEFAULT_EXCLUDE, DEFAULT_INCLUDE, isProductionEnv, normaliseId, resolveMode, resolveOptions, } from './options.js';
29
+ export { findGitRoot, resolveRoot, toPosix, toRepoRelative } from './root.js';
30
+ export { buildAttributes, escapeAttributeValue, renderAttributes } from './stamp.js';
31
+ export { transformSource, stampContextFor } from './transform.js';
32
+ export { default as snagAnchorBabelPlugin, stampJsx } from './babel/plugin.js';
33
+ export { resolveComponentName } from './babel/component-name.js';
34
+ export { stampVue, sfcComponentName } from './vue/transform.js';
35
+ export { createDevtoolsJsonMiddleware, devtoolsJson, devtoolsWorkspaceUuid, DEVTOOLS_JSON_PATH, uuidV5, } from './devtools-json.js';
36
+ export const unpluginFactory = (rawOptions) => {
37
+ const userOptions = rawOptions ?? {};
38
+ let options = resolveOptions(userOptions);
39
+ const attachDevtoolsJson = (server) => {
40
+ if (!options.devtoolsJson)
41
+ return;
42
+ // Registered unmounted on purpose — see `createDevtoolsJsonMiddleware`.
43
+ server.middlewares.use(createDevtoolsJsonMiddleware(options.root));
44
+ };
45
+ return {
46
+ name: 'snag-anchor',
47
+ // `pre` so the stamp lands in the source *before* the framework plugin
48
+ // compiles it: `@vitejs/plugin-vue` must see a `.vue` file that already
49
+ // carries the attributes, and the React plugin must still see real JSX.
50
+ enforce: 'pre',
51
+ transformInclude(id) {
52
+ return options.mode !== 'off' && options.filter(id);
53
+ },
54
+ transform(code, id) {
55
+ const result = transformSource(code, id, options);
56
+ if (result === null)
57
+ return null;
58
+ return { code: result.code, map: result.map };
59
+ },
60
+ vite: {
61
+ configResolved(config) {
62
+ // Fail closed: if Vite says this is a production build we believe it,
63
+ // even when NODE_ENV was never set. `forceProduction` can only ever
64
+ // reduce what is emitted (doc 02 §2.3).
65
+ options = resolveOptions(userOptions, {
66
+ cwd: config.root ?? process.cwd(),
67
+ forceProduction: config.isProduction === true,
68
+ });
69
+ },
70
+ configureServer(server) {
71
+ attachDevtoolsJson(server);
72
+ },
73
+ configurePreviewServer(server) {
74
+ attachDevtoolsJson(server);
75
+ },
76
+ },
77
+ };
78
+ };
79
+ export const unplugin = createUnplugin(unpluginFactory);
80
+ export default unplugin;
81
+ /**
82
+ * `emitRepoMap` (doc 02 §2.3, "run @frmwrkd/snag-repomap after build") is accepted and
83
+ * carried on `ResolvedAnchorOptions`, but nothing is wired to it yet:
84
+ * `@frmwrkd/snag-repomap` is milestone M3 and is not a dependency of this package. The
85
+ * option exists so a user's config does not have to change when it lands.
86
+ */
87
+ export const EMIT_REPO_MAP_IS_WIRED = false;
88
+ /** Re-exported so integrators can assert the endpoint without importing the module path. */
89
+ export const DEVTOOLS_JSON_ENDPOINT = DEVTOOLS_JSON_PATH;
90
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,44 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ let modulePromise;
4
+ function loadAnchor() {
5
+ modulePromise ??= import('./index.js');
6
+ return modulePromise;
7
+ }
8
+ function readOptions(context) {
9
+ let raw;
10
+ try {
11
+ raw = typeof context.getOptions === 'function' ? context.getOptions() : context.query;
12
+ }
13
+ catch {
14
+ raw = undefined;
15
+ }
16
+ if (typeof raw !== 'object' || raw === null || Array.isArray(raw))
17
+ return {};
18
+ return raw;
19
+ }
20
+ function snagAnchorLoader(source) {
21
+ const callback = this.async();
22
+ if (typeof this.cacheable === 'function')
23
+ this.cacheable(true);
24
+ const resourcePath = this.resourcePath ?? this.resource ?? '';
25
+ const options = readOptions(this);
26
+ const emitWarning = this.emitWarning?.bind(this);
27
+ loadAnchor()
28
+ .then((anchor) => {
29
+ const resolved = anchor.resolveOptions(options);
30
+ const result = anchor.transformSource(source, resourcePath, resolved);
31
+ if (result === null) {
32
+ callback(null, source);
33
+ return;
34
+ }
35
+ callback(null, result.code, result.map);
36
+ })
37
+ .catch((error) => {
38
+ const reason = error instanceof Error ? error : new Error(String(error));
39
+ emitWarning?.(new Error(`[snag-anchor] skipped ${resourcePath}: ${reason.message}`));
40
+ callback(null, source);
41
+ });
42
+ }
43
+ module.exports = snagAnchorLoader;
44
+ //# sourceMappingURL=loader.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"loader.cjs","sourceRoot":"","sources":["../src/loader.cts"],"names":[],"mappings":";;AA8DA,IAAI,aAAgD,CAAC;AAErD,SAAS,UAAU;IACjB,aAAa,KAAK,MAAM,CAAC,YAAY,CAAC,CAAC;IACvC,OAAO,aAAa,CAAC;AACvB,CAAC;AAED,SAAS,WAAW,CAAC,OAA6B;IAChD,IAAI,GAAY,CAAC;IACjB,IAAI,CAAC;QACH,GAAG,GAAG,OAAO,OAAO,CAAC,UAAU,KAAK,UAAU,CAAC,CAAC,CAAC,OAAO,CAAC,UAAU,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,KAAK,CAAC;IACxF,CAAC;IAAC,MAAM,CAAC;QACP,GAAG,GAAG,SAAS,CAAC;IAClB,CAAC;IACD,IAAI,OAAO,GAAG,KAAK,QAAQ,IAAI,GAAG,KAAK,IAAI,IAAI,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC;QAAE,OAAO,EAAE,CAAC;IAC7E,OAAO,GAAoB,CAAC;AAC9B,CAAC;AAED,SAAS,gBAAgB,CAA6B,MAAc;IAClE,MAAM,QAAQ,GAAG,IAAI,CAAC,KAAK,EAAE,CAAC;IAC9B,IAAI,OAAO,IAAI,CAAC,SAAS,KAAK,UAAU;QAAE,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC;IAE/D,MAAM,YAAY,GAAG,IAAI,CAAC,YAAY,IAAI,IAAI,CAAC,QAAQ,IAAI,EAAE,CAAC;IAC9D,MAAM,OAAO,GAAG,WAAW,CAAC,IAAI,CAAC,CAAC;IAClC,MAAM,WAAW,GAAG,IAAI,CAAC,WAAW,EAAE,IAAI,CAAC,IAAI,CAAC,CAAC;IAEjD,UAAU,EAAE;SACT,IAAI,CAAC,CAAC,MAAM,EAAE,EAAE;QACf,MAAM,QAAQ,GAAG,MAAM,CAAC,cAAc,CAAC,OAAO,CAAC,CAAC;QAChD,MAAM,MAAM,GAAG,MAAM,CAAC,eAAe,CAAC,MAAM,EAAE,YAAY,EAAE,QAAQ,CAAC,CAAC;QACtE,IAAI,MAAM,KAAK,IAAI,EAAE,CAAC;YACpB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC;YACvB,OAAO;QACT,CAAC;QACD,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC,IAAI,EAAE,MAAM,CAAC,GAAG,CAAC,CAAC;IAC1C,CAAC,CAAC;SACD,KAAK,CAAC,CAAC,KAAc,EAAE,EAAE;QACxB,MAAM,MAAM,GAAG,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,KAAK,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC;QACzE,WAAW,EAAE,CAAC,IAAI,KAAK,CAAC,yBAAyB,YAAY,KAAK,MAAM,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC;QACrF,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC;IACzB,CAAC,CAAC,CAAC;AACP,CAAC;AAED,MAAM,CAAC,OAAO,GAAG,gBAAgB,CAAC"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=loader.d.cts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"loader.d.cts","sourceRoot":"","sources":["../src/loader.cts"],"names":[],"mappings":""}
@@ -0,0 +1,23 @@
1
+ /**
2
+ * `MagicString`, re-exported from a package we already depend on.
3
+ *
4
+ * Every transform in this package is a *splice*, never a re-print: we parse,
5
+ * work out where the attribute goes, and insert that one string. We never hand
6
+ * the file to a code generator. That matters for three reasons:
7
+ *
8
+ * 1. **Correctness.** Re-printing a `.tsx` file through `@babel/generator`
9
+ * round-trips syntax this plugin has no business touching (decorators,
10
+ * `satisfies`, whatever TypeScript ships next). A splice cannot corrupt
11
+ * what it does not read.
12
+ * 2. **Line accuracy.** The whole product rests on the emitted line number
13
+ * pointing at the element's opening tag *in the original file*. An
14
+ * insertion that never contains a newline cannot move a line.
15
+ * 3. **Build overhead.** doc 02 §2.6 criterion 4 caps overhead at 8%. Parse +
16
+ * splice is a fraction of parse + generate.
17
+ *
18
+ * `magic-string` itself is not a direct dependency of `@frmwrkd/snag-anchor` — it is
19
+ * re-exported by `@vue/compiler-sfc`, which is. It should be promoted to a
20
+ * direct dependency the next time the lockfile can be regenerated.
21
+ */
22
+ export { MagicString } from '@vue/compiler-sfc';
23
+ //# sourceMappingURL=magic-string.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"magic-string.d.ts","sourceRoot":"","sources":["../src/magic-string.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC"}
@@ -0,0 +1,23 @@
1
+ /**
2
+ * `MagicString`, re-exported from a package we already depend on.
3
+ *
4
+ * Every transform in this package is a *splice*, never a re-print: we parse,
5
+ * work out where the attribute goes, and insert that one string. We never hand
6
+ * the file to a code generator. That matters for three reasons:
7
+ *
8
+ * 1. **Correctness.** Re-printing a `.tsx` file through `@babel/generator`
9
+ * round-trips syntax this plugin has no business touching (decorators,
10
+ * `satisfies`, whatever TypeScript ships next). A splice cannot corrupt
11
+ * what it does not read.
12
+ * 2. **Line accuracy.** The whole product rests on the emitted line number
13
+ * pointing at the element's opening tag *in the original file*. An
14
+ * insertion that never contains a newline cannot move a line.
15
+ * 3. **Build overhead.** doc 02 §2.6 criterion 4 caps overhead at 8%. Parse +
16
+ * splice is a fraction of parse + generate.
17
+ *
18
+ * `magic-string` itself is not a direct dependency of `@frmwrkd/snag-anchor` — it is
19
+ * re-exported by `@vue/compiler-sfc`, which is. It should be promoted to a
20
+ * direct dependency the next time the lockfile can be regenerated.
21
+ */
22
+ export { MagicString } from '@vue/compiler-sfc';
23
+ //# sourceMappingURL=magic-string.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"magic-string.js","sourceRoot":"","sources":["../src/magic-string.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC"}
package/dist/nuxt.d.ts ADDED
@@ -0,0 +1,14 @@
1
+ import type { AnchorOptions } from './options.js';
2
+ interface PluginContainer {
3
+ plugins?: unknown[] | undefined;
4
+ }
5
+ interface NuxtLike {
6
+ options: {
7
+ vite?: PluginContainer | undefined;
8
+ };
9
+ hook(name: 'vite:extendConfig', fn: (config: PluginContainer) => void): void;
10
+ hook(name: 'webpack:config', fn: (configs: PluginContainer[]) => void): void;
11
+ }
12
+ export default function snagAnchorNuxtModule(options: AnchorOptions | undefined, nuxt: NuxtLike): void;
13
+ export {};
14
+ //# sourceMappingURL=nuxt.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"nuxt.d.ts","sourceRoot":"","sources":["../src/nuxt.ts"],"names":[],"mappings":"AAeA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AAKlD,UAAU,eAAe;IACvB,OAAO,CAAC,EAAE,OAAO,EAAE,GAAG,SAAS,CAAC;CACjC;AAED,UAAU,QAAQ;IAChB,OAAO,EAAE;QAAE,IAAI,CAAC,EAAE,eAAe,GAAG,SAAS,CAAA;KAAE,CAAC;IAChD,IAAI,CAAC,IAAI,EAAE,mBAAmB,EAAE,EAAE,EAAE,CAAC,MAAM,EAAE,eAAe,KAAK,IAAI,GAAG,IAAI,CAAC;IAC7E,IAAI,CAAC,IAAI,EAAE,gBAAgB,EAAE,EAAE,EAAE,CAAC,OAAO,EAAE,eAAe,EAAE,KAAK,IAAI,GAAG,IAAI,CAAC;CAC9E;AAED,MAAM,CAAC,OAAO,UAAU,oBAAoB,CAC1C,OAAO,EAAE,aAAa,GAAG,SAAS,EAClC,IAAI,EAAE,QAAQ,GACb,IAAI,CAYN"}
package/dist/nuxt.js ADDED
@@ -0,0 +1,29 @@
1
+ /**
2
+ * Nuxt module.
3
+ *
4
+ * ```ts
5
+ * // nuxt.config.ts
6
+ * export default defineNuxtConfig({ modules: ['@frmwrkd/snag-anchor/nuxt'] });
7
+ * ```
8
+ *
9
+ * Written against Nuxt's hooks rather than `@nuxt/kit`'s `addVitePlugin` /
10
+ * `addWebpackPlugin`, so `@nuxt/kit` does not become a dependency of a package
11
+ * that most users install for React.
12
+ */
13
+ import { createVitePlugin, createWebpackPlugin } from 'unplugin';
14
+ import { unpluginFactory } from './index.js';
15
+ const vitePlugin = createVitePlugin(unpluginFactory);
16
+ const webpackPlugin = createWebpackPlugin(unpluginFactory);
17
+ export default function snagAnchorNuxtModule(options, nuxt) {
18
+ nuxt.hook('vite:extendConfig', (config) => {
19
+ config.plugins ??= [];
20
+ config.plugins.push(vitePlugin(options));
21
+ });
22
+ nuxt.hook('webpack:config', (configs) => {
23
+ for (const config of configs) {
24
+ config.plugins ??= [];
25
+ config.plugins.push(webpackPlugin(options));
26
+ }
27
+ });
28
+ }
29
+ //# sourceMappingURL=nuxt.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"nuxt.js","sourceRoot":"","sources":["../src/nuxt.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AACH,OAAO,EAAE,gBAAgB,EAAE,mBAAmB,EAAE,MAAM,UAAU,CAAC;AAEjE,OAAO,EAAE,eAAe,EAAE,MAAM,YAAY,CAAC;AAG7C,MAAM,UAAU,GAAG,gBAAgB,CAAC,eAAe,CAAC,CAAC;AACrD,MAAM,aAAa,GAAG,mBAAmB,CAAC,eAAe,CAAC,CAAC;AAY3D,MAAM,CAAC,OAAO,UAAU,oBAAoB,CAC1C,OAAkC,EAClC,IAAc;IAEd,IAAI,CAAC,IAAI,CAAC,mBAAmB,EAAE,CAAC,MAAM,EAAE,EAAE;QACxC,MAAM,CAAC,OAAO,KAAK,EAAE,CAAC;QACtB,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC,UAAU,CAAC,OAAO,CAAC,CAAC,CAAC;IAC3C,CAAC,CAAC,CAAC;IAEH,IAAI,CAAC,IAAI,CAAC,gBAAgB,EAAE,CAAC,OAAO,EAAE,EAAE;QACtC,KAAK,MAAM,MAAM,IAAI,OAAO,EAAE,CAAC;YAC7B,MAAM,CAAC,OAAO,KAAK,EAAE,CAAC;YACtB,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC,aAAa,CAAC,OAAO,CAAC,CAAC,CAAC;QAC9C,CAAC;IACH,CAAC,CAAC,CAAC;AACL,CAAC"}
@@ -0,0 +1,101 @@
1
+ /** doc 02 §2.3. Field-for-field, including the defaults in the comments. */
2
+ export interface AnchorOptions {
3
+ /** default: `process.env.NODE_ENV !== 'production'` */
4
+ enabled?: boolean;
5
+ /** default `'data-snag'` */
6
+ attribute?: string;
7
+ /** default `'data-snag-cmp'` */
8
+ componentAttribute?: string;
9
+ /** default: git root; paths are relative to this */
10
+ root?: string;
11
+ /** default `['**\/*.{jsx,tsx,vue}']` — Svelte needs no injection (§2.2) */
12
+ include?: string[];
13
+ /** default `['**\/node_modules/**','**\/*.test.*','**\/*.stories.*']` */
14
+ exclude?: string[];
15
+ /** default true — stamp DOM elements, not component tags */
16
+ intrinsicOnly?: boolean;
17
+ /** default true — run @frmwrkd/snag-repomap after build */
18
+ emitRepoMap?: boolean;
19
+ /** default true — serve the well-known project-root file */
20
+ devtoolsJson?: boolean;
21
+ /** `'minimal'` = component name only, no path */
22
+ production?: false | 'minimal';
23
+ }
24
+ export declare const DEFAULT_ATTRIBUTE = "data-snag";
25
+ export declare const DEFAULT_COMPONENT_ATTRIBUTE = "data-snag-cmp";
26
+ /**
27
+ * `.svelte` is deliberately absent. Svelte 5 already attaches
28
+ * `element.__svelte_meta = { loc: { file, line, column } }` in dev and resolver
29
+ * tier 1 reads it straight off the node — injecting there would be duplicated
30
+ * work that can only disagree with the framework. doc 02 §2.2.
31
+ */
32
+ export declare const DEFAULT_INCLUDE: readonly string[];
33
+ export declare const DEFAULT_EXCLUDE: readonly string[];
34
+ export declare const DEFAULT_INTRINSIC_ONLY = true;
35
+ export declare const DEFAULT_EMIT_REPO_MAP = true;
36
+ export declare const DEFAULT_DEVTOOLS_JSON = true;
37
+ export declare const DEFAULT_PRODUCTION: false | 'minimal';
38
+ /**
39
+ * `'off'` — emit nothing at all.
40
+ * `'full'` — `data-snag="path:line:col"` + `data-snag-cmp="Name"`.
41
+ * `'minimal'` — `data-snag-cmp="Name"` only. Never a path.
42
+ */
43
+ export type AnchorMode = 'off' | 'full' | 'minimal';
44
+ export interface ResolvedAnchorOptions {
45
+ mode: AnchorMode;
46
+ enabled: boolean;
47
+ isProduction: boolean;
48
+ attribute: string;
49
+ componentAttribute: string;
50
+ /** Absolute and POSIX-normalised. */
51
+ root: string;
52
+ include: readonly string[];
53
+ exclude: readonly string[];
54
+ intrinsicOnly: boolean;
55
+ emitRepoMap: boolean;
56
+ devtoolsJson: boolean;
57
+ production: false | 'minimal';
58
+ /** `true` when this module id should be transformed. */
59
+ filter: (id: string) => boolean;
60
+ }
61
+ export interface ResolveOptionsContext {
62
+ /** Where root detection starts. Defaults to `process.cwd()`. */
63
+ cwd?: string;
64
+ /** Injected for tests; defaults to `process.env`. */
65
+ env?: Record<string, string | undefined>;
66
+ /**
67
+ * Fail-closed override. Vite's `configResolved` reports `config.isProduction`
68
+ * independently of `NODE_ENV`; when the bundler says "this is production" we
69
+ * believe it even if `NODE_ENV` was never set. This can only ever *reduce*
70
+ * what is emitted.
71
+ */
72
+ forceProduction?: boolean;
73
+ }
74
+ export declare function isProductionEnv(env?: Record<string, string | undefined>): boolean;
75
+ /**
76
+ * The whole production gate, in one place so it can be tested as a matrix.
77
+ *
78
+ * | NODE_ENV | enabled | production | mode |
79
+ * |--------------|-------------|-------------|-----------|
80
+ * | development | (default) | (default) | full |
81
+ * | production | (default) | (default) | off |
82
+ * | production | (default) | 'minimal' | off | ← `enabled` defaults false in prod
83
+ * | production | true | (default) | off |
84
+ * | production | true | 'minimal' | minimal |
85
+ * | development | false | anything | off |
86
+ */
87
+ export declare function resolveMode(options: AnchorOptions, isProduction: boolean): AnchorMode;
88
+ export declare function resolveOptions(options?: AnchorOptions, context?: ResolveOptionsContext): ResolvedAnchorOptions;
89
+ /**
90
+ * Bundler module ids are not plain paths. Vite appends query strings
91
+ * (`/src/App.vue?vue&type=template&lang.js`), prefixes virtual modules with a
92
+ * NUL byte, and passes through `http:` ids for remote modules. Normalise to a
93
+ * bare POSIX filesystem path or return `null` for "this is not a file".
94
+ */
95
+ export declare function normaliseId(id: string): string | null;
96
+ /**
97
+ * `exclude` beats `include`, always. A `.stories.tsx` under a matching include
98
+ * glob is still excluded.
99
+ */
100
+ export declare function createFilter(include: readonly string[], exclude: readonly string[]): (id: string) => boolean;
101
+ //# sourceMappingURL=options.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"options.d.ts","sourceRoot":"","sources":["../src/options.ts"],"names":[],"mappings":"AAuBA,4EAA4E;AAC5E,MAAM,WAAW,aAAa;IAC5B,uDAAuD;IACvD,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,4BAA4B;IAC5B,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,gCAAgC;IAChC,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAC5B,oDAAoD;IACpD,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,2EAA2E;IAC3E,OAAO,CAAC,EAAE,MAAM,EAAE,CAAC;IACnB,yEAAyE;IACzE,OAAO,CAAC,EAAE,MAAM,EAAE,CAAC;IACnB,4DAA4D;IAC5D,aAAa,CAAC,EAAE,OAAO,CAAC;IACxB,2DAA2D;IAC3D,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,4DAA4D;IAC5D,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB,iDAAiD;IACjD,UAAU,CAAC,EAAE,KAAK,GAAG,SAAS,CAAC;CAChC;AAED,eAAO,MAAM,iBAAiB,cAAc,CAAC;AAC7C,eAAO,MAAM,2BAA2B,kBAAkB,CAAC;AAE3D;;;;;GAKG;AACH,eAAO,MAAM,eAAe,EAAE,SAAS,MAAM,EAA2B,CAAC;AACzE,eAAO,MAAM,eAAe,EAAE,SAAS,MAAM,EAI5C,CAAC;AACF,eAAO,MAAM,sBAAsB,OAAO,CAAC;AAC3C,eAAO,MAAM,qBAAqB,OAAO,CAAC;AAC1C,eAAO,MAAM,qBAAqB,OAAO,CAAC;AAC1C,eAAO,MAAM,kBAAkB,EAAE,KAAK,GAAG,SAAiB,CAAC;AAE3D;;;;GAIG;AACH,MAAM,MAAM,UAAU,GAAG,KAAK,GAAG,MAAM,GAAG,SAAS,CAAC;AAEpD,MAAM,WAAW,qBAAqB;IACpC,IAAI,EAAE,UAAU,CAAC;IACjB,OAAO,EAAE,OAAO,CAAC;IACjB,YAAY,EAAE,OAAO,CAAC;IACtB,SAAS,EAAE,MAAM,CAAC;IAClB,kBAAkB,EAAE,MAAM,CAAC;IAC3B,qCAAqC;IACrC,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,SAAS,MAAM,EAAE,CAAC;IAC3B,OAAO,EAAE,SAAS,MAAM,EAAE,CAAC;IAC3B,aAAa,EAAE,OAAO,CAAC;IACvB,WAAW,EAAE,OAAO,CAAC;IACrB,YAAY,EAAE,OAAO,CAAC;IACtB,UAAU,EAAE,KAAK,GAAG,SAAS,CAAC;IAC9B,wDAAwD;IACxD,MAAM,EAAE,CAAC,EAAE,EAAE,MAAM,KAAK,OAAO,CAAC;CACjC;AAED,MAAM,WAAW,qBAAqB;IACpC,gEAAgE;IAChE,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,qDAAqD;IACrD,GAAG,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC,CAAC;IACzC;;;;;OAKG;IACH,eAAe,CAAC,EAAE,OAAO,CAAC;CAC3B;AAED,wBAAgB,eAAe,CAAC,GAAG,GAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CAAe,GAAG,OAAO,CAE9F;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,WAAW,CAAC,OAAO,EAAE,aAAa,EAAE,YAAY,EAAE,OAAO,GAAG,UAAU,CAKrF;AAED,wBAAgB,cAAc,CAC5B,OAAO,GAAE,aAAkB,EAC3B,OAAO,GAAE,qBAA0B,GAClC,qBAAqB,CAqBvB;AAED;;;;;GAKG;AACH,wBAAgB,WAAW,CAAC,EAAE,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAWrD;AAED;;;GAGG;AACH,wBAAgB,YAAY,CAC1B,OAAO,EAAE,SAAS,MAAM,EAAE,EAC1B,OAAO,EAAE,SAAS,MAAM,EAAE,GACzB,CAAC,EAAE,EAAE,MAAM,KAAK,OAAO,CAUzB"}
@@ -0,0 +1,122 @@
1
+ /**
2
+ * `AnchorOptions` — doc 02 §2.3, verbatim, with the documented defaults.
3
+ *
4
+ * ## Production is opt-in and defaults off
5
+ *
6
+ * doc 02 §2.3: "Never emit full source paths to a public production build
7
+ * without the user explicitly choosing it." Emitting `src/checkout/Promo.tsx`
8
+ * into a public bundle is an information-disclosure bug — it publishes your
9
+ * directory layout, your internal component names, and (with a repo map) a
10
+ * decent sketch of your architecture, to anyone with DevTools.
11
+ *
12
+ * So the gate is deliberately two-layered:
13
+ *
14
+ * - `enabled` defaults to `process.env.NODE_ENV !== 'production'`, which
15
+ * switches the whole plugin off in a production build.
16
+ * - Even with `enabled: true` forced on, a production build can only ever
17
+ * reach `'minimal'` (component name, no path). The `production` option's
18
+ * type is `false | 'minimal'` — there is no value that means "full paths in
19
+ * production", by design.
20
+ */
21
+ import picomatch from 'picomatch';
22
+ import { resolveRoot, toPosix } from './root.js';
23
+ export const DEFAULT_ATTRIBUTE = 'data-snag';
24
+ export const DEFAULT_COMPONENT_ATTRIBUTE = 'data-snag-cmp';
25
+ /**
26
+ * `.svelte` is deliberately absent. Svelte 5 already attaches
27
+ * `element.__svelte_meta = { loc: { file, line, column } }` in dev and resolver
28
+ * tier 1 reads it straight off the node — injecting there would be duplicated
29
+ * work that can only disagree with the framework. doc 02 §2.2.
30
+ */
31
+ export const DEFAULT_INCLUDE = ['**/*.{jsx,tsx,vue}'];
32
+ export const DEFAULT_EXCLUDE = [
33
+ '**/node_modules/**',
34
+ '**/*.test.*',
35
+ '**/*.stories.*',
36
+ ];
37
+ export const DEFAULT_INTRINSIC_ONLY = true;
38
+ export const DEFAULT_EMIT_REPO_MAP = true;
39
+ export const DEFAULT_DEVTOOLS_JSON = true;
40
+ export const DEFAULT_PRODUCTION = false;
41
+ export function isProductionEnv(env = process.env) {
42
+ return env['NODE_ENV'] === 'production';
43
+ }
44
+ /**
45
+ * The whole production gate, in one place so it can be tested as a matrix.
46
+ *
47
+ * | NODE_ENV | enabled | production | mode |
48
+ * |--------------|-------------|-------------|-----------|
49
+ * | development | (default) | (default) | full |
50
+ * | production | (default) | (default) | off |
51
+ * | production | (default) | 'minimal' | off | ← `enabled` defaults false in prod
52
+ * | production | true | (default) | off |
53
+ * | production | true | 'minimal' | minimal |
54
+ * | development | false | anything | off |
55
+ */
56
+ export function resolveMode(options, isProduction) {
57
+ const enabled = options.enabled ?? !isProduction;
58
+ if (!enabled)
59
+ return 'off';
60
+ if (isProduction)
61
+ return options.production === 'minimal' ? 'minimal' : 'off';
62
+ return 'full';
63
+ }
64
+ export function resolveOptions(options = {}, context = {}) {
65
+ const env = context.env ?? process.env;
66
+ const isProduction = context.forceProduction === true || isProductionEnv(env);
67
+ const include = options.include ?? DEFAULT_INCLUDE;
68
+ const exclude = options.exclude ?? DEFAULT_EXCLUDE;
69
+ return {
70
+ mode: resolveMode(options, isProduction),
71
+ enabled: options.enabled ?? !isProduction,
72
+ isProduction,
73
+ attribute: options.attribute ?? DEFAULT_ATTRIBUTE,
74
+ componentAttribute: options.componentAttribute ?? DEFAULT_COMPONENT_ATTRIBUTE,
75
+ root: resolveRoot(options.root, context.cwd ?? process.cwd()),
76
+ include,
77
+ exclude,
78
+ intrinsicOnly: options.intrinsicOnly ?? DEFAULT_INTRINSIC_ONLY,
79
+ emitRepoMap: options.emitRepoMap ?? DEFAULT_EMIT_REPO_MAP,
80
+ devtoolsJson: options.devtoolsJson ?? DEFAULT_DEVTOOLS_JSON,
81
+ production: options.production ?? DEFAULT_PRODUCTION,
82
+ filter: createFilter(include, exclude),
83
+ };
84
+ }
85
+ /**
86
+ * Bundler module ids are not plain paths. Vite appends query strings
87
+ * (`/src/App.vue?vue&type=template&lang.js`), prefixes virtual modules with a
88
+ * NUL byte, and passes through `http:` ids for remote modules. Normalise to a
89
+ * bare POSIX filesystem path or return `null` for "this is not a file".
90
+ */
91
+ export function normaliseId(id) {
92
+ if (id === '')
93
+ return null;
94
+ // Rollup/Vite virtual module convention.
95
+ if (id.startsWith('\0') || id.includes('\0'))
96
+ return null;
97
+ // A real scheme (`http://`, `data:`), never a Windows drive letter (`C:/`).
98
+ if (/^[a-zA-Z][a-zA-Z\d+\-.]*:\/\//.test(id) || id.startsWith('data:'))
99
+ return null;
100
+ const queryAt = id.search(/[?#]/);
101
+ const bare = queryAt === -1 ? id : id.slice(0, queryAt);
102
+ if (bare === '')
103
+ return null;
104
+ return toPosix(bare);
105
+ }
106
+ /**
107
+ * `exclude` beats `include`, always. A `.stories.tsx` under a matching include
108
+ * glob is still excluded.
109
+ */
110
+ export function createFilter(include, exclude) {
111
+ const isIncluded = include.length > 0 ? picomatch(include, { dot: true }) : () => false;
112
+ const isExcluded = exclude.length > 0 ? picomatch(exclude, { dot: true }) : () => false;
113
+ return (id) => {
114
+ const file = normaliseId(id);
115
+ if (file === null)
116
+ return false;
117
+ if (isExcluded(file))
118
+ return false;
119
+ return isIncluded(file);
120
+ };
121
+ }
122
+ //# sourceMappingURL=options.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"options.js","sourceRoot":"","sources":["../src/options.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,3 @@
1
+ declare const _default: (options?: import("./options.js").AnchorOptions | undefined) => import("rollup").Plugin<any> | import("rollup").Plugin<any>[];
2
+ export default _default;
3
+ //# sourceMappingURL=rollup.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"rollup.d.ts","sourceRoot":"","sources":["../src/rollup.ts"],"names":[],"mappings":";AAUA,wBAAmD"}
package/dist/rollup.js ADDED
@@ -0,0 +1,11 @@
1
+ /**
2
+ * ```ts
3
+ * // rollup.config.js
4
+ * import snagAnchor from '@frmwrkd/snag-anchor/rollup';
5
+ * export default { plugins: [snagAnchor()] };
6
+ * ```
7
+ */
8
+ import { createRollupPlugin } from 'unplugin';
9
+ import { unpluginFactory } from './index.js';
10
+ export default createRollupPlugin(unpluginFactory);
11
+ //# sourceMappingURL=rollup.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"rollup.js","sourceRoot":"","sources":["../src/rollup.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AACH,OAAO,EAAE,kBAAkB,EAAE,MAAM,UAAU,CAAC;AAC9C,OAAO,EAAE,eAAe,EAAE,MAAM,YAAY,CAAC;AAE7C,eAAe,kBAAkB,CAAC,eAAe,CAAC,CAAC"}
package/dist/root.d.ts ADDED
@@ -0,0 +1,38 @@
1
+ /**
2
+ * Backslashes → forward slashes. Applied to every path this package emits.
3
+ *
4
+ * Note this is deliberately *not* `path.posix.normalize` — we do not want to
5
+ * collapse `..` segments or otherwise rewrite a path the caller gave us, only
6
+ * to make the separator identical on every platform.
7
+ */
8
+ export declare function toPosix(p: string): string;
9
+ /** Test seam — the caches are process-global and would otherwise leak between tests. */
10
+ export declare function clearRootCaches(): void;
11
+ /**
12
+ * Nearest ancestor directory containing `.git`.
13
+ *
14
+ * `.git` is tested with `existsSync`, not `isDirectory`, on purpose: in a git
15
+ * worktree or a submodule `.git` is a *file* containing a `gitdir:` pointer.
16
+ * Treating it as "not a repo" would push the root up to the parent checkout and
17
+ * every emitted path would gain a bogus prefix.
18
+ */
19
+ export declare function findGitRoot(startDir: string): string | undefined;
20
+ /** Nearest ancestor directory containing `package.json`. Fallback when there is no git repo. */
21
+ export declare function findManifestDir(startDir: string): string | undefined;
22
+ /**
23
+ * The project root every emitted path is relative to.
24
+ *
25
+ * Precedence: explicit `root` option → git root → nearest `package.json` →
26
+ * the working directory. Always absolute and always POSIX-normalised.
27
+ */
28
+ export declare function resolveRoot(explicitRoot?: string, cwd?: string): string;
29
+ /**
30
+ * `/Users/theo/dev/app/src/App.tsx` + root `/Users/theo/dev/app` →
31
+ * `src/App.tsx`.
32
+ *
33
+ * A file outside the root keeps its `../` prefix rather than being silently
34
+ * rewritten — `root + '/' + '../lib/x.tsx'` still resolves to the right file,
35
+ * and inventing a path is the one failure mode doc 00 §3 forbids outright.
36
+ */
37
+ export declare function toRepoRelative(absoluteFile: string, root: string): string;
38
+ //# sourceMappingURL=root.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"root.d.ts","sourceRoot":"","sources":["../src/root.ts"],"names":[],"mappings":"AAsBA;;;;;;GAMG;AACH,wBAAgB,OAAO,CAAC,CAAC,EAAE,MAAM,GAAG,MAAM,CAEzC;AAMD,wFAAwF;AACxF,wBAAgB,eAAe,IAAI,IAAI,CAGtC;AAoBD;;;;;;;GAOG;AACH,wBAAgB,WAAW,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAEhE;AAED,gGAAgG;AAChG,wBAAgB,eAAe,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAEpE;AAED;;;;;GAKG;AACH,wBAAgB,WAAW,CAAC,YAAY,CAAC,EAAE,MAAM,EAAE,GAAG,GAAE,MAAsB,GAAG,MAAM,CAMtF;AAED;;;;;;;GAOG;AACH,wBAAgB,cAAc,CAAC,YAAY,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,MAAM,CAKzE"}