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 +93 -0
- package/dist/bun/index.d.mts +8 -0
- package/dist/bun/index.mjs +2 -0
- package/dist/bun/preload.d.mts +1 -0
- package/dist/bun/preload.mjs +5 -0
- package/dist/bun-Bn5rpU4O.mjs +216 -0
- package/dist/plugin/index.cjs +54 -0
- package/dist/plugin/index.d.cts +2571 -0
- package/dist/plugin/index.d.mts +2571 -0
- package/dist/plugin/index.mjs +54 -0
- package/package.json +124 -0
- package/src/types/index.d.ts +17 -0
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 @@
|
|
|
1
|
+
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;
|