import.meta.location 0.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md ADDED
@@ -0,0 +1,93 @@
1
+ # import.meta.location
2
+
3
+ `import.meta.location` becomes a plain object with the source file location
4
+ baked in at build time:
5
+
6
+ ```ts
7
+ const here = import.meta.location;
8
+ ```
9
+
10
+ becomes:
11
+
12
+ ```ts
13
+ const here = { line: 1, col: 14, file: "entry.ts" };
14
+ ```
15
+
16
+ Property access works too:
17
+
18
+ ```ts
19
+ console.log(import.meta.location.file);
20
+ ```
21
+
22
+ ## Install
23
+
24
+ ```sh
25
+ npm install --save-dev import.meta.location
26
+ ```
27
+
28
+ ## Babel
29
+
30
+ Add the plugin:
31
+
32
+ ```js
33
+ // babel.config.js
34
+ module.exports = {
35
+ plugins: ["import.meta.location"],
36
+ };
37
+ ```
38
+
39
+ The package also exposes the same plugin at `import.meta.location/plugin`.
40
+
41
+ ### Options
42
+
43
+ ```js
44
+ [
45
+ "import.meta.location",
46
+ {
47
+ // Override the filename in generated objects. By default the plugin
48
+ // uses the basename of Babel's current filename.
49
+ filename: "entry.ts",
50
+ },
51
+ ];
52
+ ```
53
+
54
+ ## Bun
55
+
56
+ For code run directly with Bun, use the preload entry:
57
+
58
+ ```toml
59
+ # bunfig.toml
60
+ preload = ["import.meta.location/bun/preload"]
61
+ ```
62
+
63
+ For custom setup:
64
+
65
+ ```ts
66
+ import { importMetaLocationPlugin } from "import.meta.location/bun";
67
+
68
+ Bun.plugin(importMetaLocationPlugin());
69
+ ```
70
+
71
+ ## TypeScript
72
+
73
+ Ambient typings are available at:
74
+
75
+ ```ts
76
+ /// <reference types="import.meta.location/types" />
77
+ ```
78
+
79
+ They add:
80
+
81
+ ```ts
82
+ interface ImportMeta {
83
+ readonly location: {
84
+ readonly line: number;
85
+ readonly col: number;
86
+ readonly file: string;
87
+ };
88
+ }
89
+ ```
90
+
91
+ ## License
92
+
93
+ MIT.
@@ -0,0 +1,8 @@
1
+ //#region src/bun/index.d.ts
2
+ type BunPlugin = Bun.BunPlugin;
3
+ type BunPluginOptions = {
4
+ /** Glob-ish filter for files to transform. Defaults to JS/TS source outside node_modules. */filter?: RegExp;
5
+ };
6
+ declare const importMetaLocationPlugin: (options?: BunPluginOptions) => BunPlugin;
7
+ //#endregion
8
+ export { BunPluginOptions, importMetaLocationPlugin as default, importMetaLocationPlugin };
@@ -0,0 +1,2 @@
1
+ import { t as importMetaLocationPlugin } from "../bun-Bn5rpU4O.mjs";
2
+ export { importMetaLocationPlugin as default, importMetaLocationPlugin };
@@ -0,0 +1 @@
1
+ export { };
@@ -0,0 +1,5 @@
1
+ import { t as importMetaLocationPlugin } from "../bun-Bn5rpU4O.mjs";
2
+ //#region src/bun/preload.ts
3
+ Bun.plugin(importMetaLocationPlugin());
4
+ //#endregion
5
+ export {};
@@ -0,0 +1,216 @@
1
+ //#region src/bun/transform.ts
2
+ /**
3
+ * Zero-dependency source transform for Bun's loader path.
4
+ *
5
+ * It rewrites real `import.meta.location` occurrences, skipping strings,
6
+ * comments and regex literals, into object literals containing the original
7
+ * file/line/column.
8
+ */
9
+ const NEEDLE$1 = "import.meta.location";
10
+ const isWs = (ch) => ch === " " || ch === " " || ch === "\n" || ch === "\r" || ch === "\f" || ch === "\v";
11
+ const isIdentPart = (ch) => ch >= "a" && ch <= "z" || ch >= "A" && ch <= "Z" || ch >= "0" && ch <= "9" || ch === "$" || ch === "_";
12
+ const regexAllowedBefore = (src, index) => {
13
+ let i = index - 1;
14
+ while (i >= 0 && isWs(src[i])) i--;
15
+ if (i < 0) return true;
16
+ const ch = src[i];
17
+ if (isIdentPart(ch) || ch === ")" || ch === "]" || ch === "}") {
18
+ if (isIdentPart(ch)) {
19
+ let j = i;
20
+ while (j >= 0 && isIdentPart(src[j])) j--;
21
+ const word = src.slice(j + 1, i + 1);
22
+ return new Set([
23
+ "return",
24
+ "typeof",
25
+ "instanceof",
26
+ "in",
27
+ "of",
28
+ "new",
29
+ "delete",
30
+ "void",
31
+ "do",
32
+ "else",
33
+ "yield",
34
+ "await",
35
+ "case"
36
+ ]).has(word);
37
+ }
38
+ return false;
39
+ }
40
+ return true;
41
+ };
42
+ const findOccurrences = (src) => {
43
+ const out = [];
44
+ let line = 1;
45
+ let column = 0;
46
+ const len = src.length;
47
+ const advance = (from, count) => {
48
+ for (let k = 0; k < count; k++) if (src[from + k] === "\n") {
49
+ line++;
50
+ column = 0;
51
+ } else column++;
52
+ };
53
+ let i = 0;
54
+ while (i < len) {
55
+ const ch = src[i];
56
+ if (ch === "/" && src[i + 1] === "/") {
57
+ while (i < len && src[i] !== "\n") {
58
+ advance(i, 1);
59
+ i++;
60
+ }
61
+ continue;
62
+ }
63
+ if (ch === "/" && src[i + 1] === "*") {
64
+ advance(i, 2);
65
+ i += 2;
66
+ while (i < len && !(src[i] === "*" && src[i + 1] === "/")) {
67
+ advance(i, 1);
68
+ i++;
69
+ }
70
+ advance(i, 2);
71
+ i += 2;
72
+ continue;
73
+ }
74
+ if (ch === "\"" || ch === "'") {
75
+ const quote = ch;
76
+ advance(i, 1);
77
+ i++;
78
+ while (i < len && src[i] !== quote) {
79
+ if (src[i] === "\\") {
80
+ advance(i, 2);
81
+ i += 2;
82
+ continue;
83
+ }
84
+ advance(i, 1);
85
+ i++;
86
+ }
87
+ advance(i, 1);
88
+ i++;
89
+ continue;
90
+ }
91
+ if (ch === "`") {
92
+ advance(i, 1);
93
+ i++;
94
+ while (i < len && src[i] !== "`") {
95
+ if (src[i] === "\\") {
96
+ advance(i, 2);
97
+ i += 2;
98
+ continue;
99
+ }
100
+ if (src[i] === "$" && src[i + 1] === "{") {
101
+ advance(i, 2);
102
+ i += 2;
103
+ let depth = 1;
104
+ while (i < len && depth > 0) {
105
+ if (src.startsWith(NEEDLE$1, i) && !isIdentPart(src[i - 1] ?? " ") && !isIdentPart(src[i + 20] ?? " ")) {
106
+ out.push({
107
+ index: i,
108
+ line,
109
+ column
110
+ });
111
+ advance(i, 20);
112
+ i += 20;
113
+ continue;
114
+ }
115
+ if (src[i] === "{") depth++;
116
+ else if (src[i] === "}") depth--;
117
+ advance(i, 1);
118
+ i++;
119
+ }
120
+ continue;
121
+ }
122
+ advance(i, 1);
123
+ i++;
124
+ }
125
+ advance(i, 1);
126
+ i++;
127
+ continue;
128
+ }
129
+ if (ch === "/" && regexAllowedBefore(src, i)) {
130
+ advance(i, 1);
131
+ i++;
132
+ let inClass = false;
133
+ while (i < len) {
134
+ const c = src[i];
135
+ if (c === "\\") {
136
+ advance(i, 2);
137
+ i += 2;
138
+ continue;
139
+ }
140
+ if (c === "[") inClass = true;
141
+ else if (c === "]") inClass = false;
142
+ else if (c === "/" && !inClass) break;
143
+ else if (c === "\n") break;
144
+ advance(i, 1);
145
+ i++;
146
+ }
147
+ advance(i, 1);
148
+ i++;
149
+ continue;
150
+ }
151
+ if (src.startsWith(NEEDLE$1, i) && !isIdentPart(src[i - 1] ?? " ") && !isIdentPart(src[i + 20] ?? " ")) {
152
+ out.push({
153
+ index: i,
154
+ line,
155
+ column
156
+ });
157
+ advance(i, 20);
158
+ i += 20;
159
+ continue;
160
+ }
161
+ advance(i, 1);
162
+ i++;
163
+ }
164
+ return out;
165
+ };
166
+ const locationObject = (filename, line, column) => `({ line: ${line}, col: ${column}, file: ${JSON.stringify(filename)} })`;
167
+ const transform = (source, options) => {
168
+ if (!source.includes(NEEDLE$1)) return;
169
+ const occurrences = findOccurrences(source);
170
+ if (occurrences.length === 0) return;
171
+ const edits = occurrences.map((occ) => ({
172
+ start: occ.index,
173
+ end: occ.index + 20,
174
+ text: locationObject(options.filename, occ.line, occ.column + 1)
175
+ }));
176
+ edits.sort((a, b) => b.start - a.start);
177
+ let out = source;
178
+ for (const edit of edits) out = out.slice(0, edit.start) + edit.text + out.slice(edit.end);
179
+ return out;
180
+ };
181
+ //#endregion
182
+ //#region src/bun/index.ts
183
+ const DEFAULT_FILTER = /^(?:(?!node_modules).)*\.(?:mjs|mts|jsx?|tsx?)$/;
184
+ const NEEDLE = "import.meta.location";
185
+ const loaderFor = (path) => {
186
+ if (path.endsWith(".tsx")) return "tsx";
187
+ if (path.endsWith(".ts") || path.endsWith(".mts")) return "ts";
188
+ if (path.endsWith(".jsx")) return "jsx";
189
+ return "js";
190
+ };
191
+ const importMetaLocationPlugin = (options = {}) => {
192
+ const filter = options.filter ?? DEFAULT_FILTER;
193
+ return {
194
+ name: "import.meta.location",
195
+ setup(build) {
196
+ build.onLoad({ filter }, async ({ path }) => {
197
+ const source = await Bun.file(path).text();
198
+ const loader = loaderFor(path);
199
+ if (!source.includes(NEEDLE)) return {
200
+ contents: source,
201
+ loader
202
+ };
203
+ return {
204
+ contents: transform(source, { filename: basename(path) }) ?? source,
205
+ loader
206
+ };
207
+ });
208
+ }
209
+ };
210
+ };
211
+ const basename = (path) => {
212
+ const slash = Math.max(path.lastIndexOf("/"), path.lastIndexOf("\\"));
213
+ return slash === -1 ? path : path.slice(slash + 1);
214
+ };
215
+ //#endregion
216
+ export { importMetaLocationPlugin as t };
@@ -0,0 +1,54 @@
1
+ let node_path = require("node:path");
2
+ //#region src/plugin/index.ts
3
+ /**
4
+ * Babel plugin: rewrites `import.meta.location` into an object literal with
5
+ * the source location baked in at build time.
6
+ *
7
+ * import.meta.location
8
+ *
9
+ * becomes:
10
+ *
11
+ * ({ line: 12, col: 3, file: "entry.ts" })
12
+ */
13
+ const NEEDLE = "import.meta.location";
14
+ const resolveFilename = (state, override) => {
15
+ if (override !== void 0 && override !== "") return override;
16
+ const { filename } = state;
17
+ if (filename === void 0 || filename === "") return;
18
+ return (0, node_path.basename)(filename);
19
+ };
20
+ const isImportMetaLocation = (node) => {
21
+ if (node.type !== "MemberExpression" && node.type !== "OptionalMemberExpression") return false;
22
+ if (node.computed || node.property.type !== "Identifier" || node.property.name !== "location") return false;
23
+ const obj = node.object;
24
+ return obj.type === "MetaProperty" && obj.meta.name === "import" && obj.property.name === "meta";
25
+ };
26
+ const createLocationObject = (t, filename, line, column) => t.objectExpression([
27
+ t.objectProperty(t.identifier("line"), t.numericLiteral(line)),
28
+ t.objectProperty(t.identifier("col"), t.numericLiteral(column)),
29
+ t.objectProperty(t.identifier("file"), t.stringLiteral(filename))
30
+ ]);
31
+ const plugin = ({ types: t }) => ({
32
+ name: "transform-import-meta-location",
33
+ visitor: { Program(programPath, state) {
34
+ const source = state.file.code;
35
+ if (typeof source !== "string" || !source.includes(NEEDLE)) return;
36
+ const filename = resolveFilename(state, (state.opts ?? {}).filename);
37
+ if (filename === void 0) return;
38
+ const rewrite = (locationPath) => {
39
+ const { node } = locationPath;
40
+ if (!isImportMetaLocation(node) || !node.loc) return;
41
+ locationPath.replaceWith(createLocationObject(t, filename, node.loc.start.line, node.loc.start.column + 1));
42
+ };
43
+ programPath.traverse({
44
+ MemberExpression(path) {
45
+ rewrite(path);
46
+ },
47
+ OptionalMemberExpression(path) {
48
+ rewrite(path);
49
+ }
50
+ });
51
+ } }
52
+ });
53
+ //#endregion
54
+ module.exports = plugin;