esrap 1.4.8 → 2.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 +91 -14
- package/package.json +11 -3
- package/src/context.js +150 -0
- package/src/index.js +92 -91
- package/src/languages/ts/index.js +1876 -0
- package/src/languages/ts/public.d.ts +2 -0
- package/src/languages/tsx/index.js +139 -0
- package/src/languages/tsx/public.d.ts +2 -0
- package/src/languages/types.d.ts +22 -0
- package/src/public.d.ts +1 -1
- package/src/types.d.ts +21 -36
- package/types/index.d.ts +153 -5
- package/types/index.d.ts.map +24 -3
- package/src/handlers.js +0 -1669
package/README.md
CHANGED
|
@@ -6,8 +6,9 @@ Parse in reverse. AST goes in, code comes out.
|
|
|
6
6
|
|
|
7
7
|
```js
|
|
8
8
|
import { print } from 'esrap';
|
|
9
|
+
import ts from 'esrap/languages/ts';
|
|
9
10
|
|
|
10
|
-
const
|
|
11
|
+
const ast = {
|
|
11
12
|
type: 'Program',
|
|
12
13
|
body: [
|
|
13
14
|
{
|
|
@@ -26,19 +27,105 @@ const { code, map } = print({
|
|
|
26
27
|
}
|
|
27
28
|
}
|
|
28
29
|
]
|
|
29
|
-
}
|
|
30
|
+
};
|
|
31
|
+
|
|
32
|
+
const { code, map } = print(ast, ts());
|
|
30
33
|
|
|
31
34
|
console.log(code); // alert('hello world!');
|
|
32
35
|
```
|
|
33
36
|
|
|
34
37
|
If the nodes of the input AST have `loc` properties (e.g. the AST was generated with [`acorn`](https://github.com/acornjs/acorn/tree/master/acorn/#interface) with the `locations` option set), sourcemap mappings will be created.
|
|
35
38
|
|
|
39
|
+
## Built-in languages
|
|
40
|
+
|
|
41
|
+
`esrap` ships with two built-in languages — `ts()` and `tsx()` (considered experimental at present!) — which can print ASTs conforming to [`@typescript-eslint/types`](https://www.npmjs.com/package/@typescript-eslint/types) (which extends [ESTree](https://github.com/estree/estree)):
|
|
42
|
+
|
|
43
|
+
```js
|
|
44
|
+
import ts from 'esrap/languages/ts';
|
|
45
|
+
import tsx from 'esrap/languages/tsx'; // experimental!
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
Both languages accept an options object:
|
|
49
|
+
|
|
50
|
+
```js
|
|
51
|
+
const { code, map } = print(
|
|
52
|
+
ast,
|
|
53
|
+
ts({
|
|
54
|
+
// how string literals should be quoted — `single` (the default) or `double`
|
|
55
|
+
quotes: 'single',
|
|
56
|
+
|
|
57
|
+
// an array of `{ type: 'Line' | 'Block', value: string, loc: { start, end } }` objects
|
|
58
|
+
comments: []
|
|
59
|
+
})
|
|
60
|
+
);
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
You can generate the `comments` array by, for example, using [Acorn's](https://github.com/acornjs/acorn/tree/master/acorn/#interface) `onComment` option.
|
|
64
|
+
|
|
65
|
+
## Custom languages
|
|
66
|
+
|
|
67
|
+
You can also create your own languages:
|
|
68
|
+
|
|
69
|
+
```ts
|
|
70
|
+
import { print, type Visitors } from 'esrap';
|
|
71
|
+
|
|
72
|
+
const language: Visitors<MyNodeType> = {
|
|
73
|
+
_(node, context, visit) {
|
|
74
|
+
// the `_` visitor handles any node type
|
|
75
|
+
context.write('[');
|
|
76
|
+
visit(node);
|
|
77
|
+
context.write(']');
|
|
78
|
+
},
|
|
79
|
+
List(node, context) {
|
|
80
|
+
// node.type === 'List'
|
|
81
|
+
for (const child of node.children) {
|
|
82
|
+
context.visit(child);
|
|
83
|
+
}
|
|
84
|
+
},
|
|
85
|
+
Foo(node, context) {
|
|
86
|
+
// node.type === 'Foo'
|
|
87
|
+
context.write('foo');
|
|
88
|
+
},
|
|
89
|
+
Bar(node, context) {
|
|
90
|
+
// node.type === 'Bar'
|
|
91
|
+
context.write('bar');
|
|
92
|
+
}
|
|
93
|
+
};
|
|
94
|
+
|
|
95
|
+
const ast: MyNodeType = {
|
|
96
|
+
type: 'List',
|
|
97
|
+
children: [{ type: 'Foo' }, { type: 'Bar' }]
|
|
98
|
+
};
|
|
99
|
+
|
|
100
|
+
const { code, map } = print(ast, language);
|
|
101
|
+
|
|
102
|
+
code; // `[[foo][bar]]`
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
The `context` API has several methods:
|
|
106
|
+
|
|
107
|
+
- `context.write(data: string, node?: BaseNode)` — add a string. If `node` is provided and has a standard `loc` property (with `start` and `end` properties each with a `line` and `column`), a sourcemap mapping will be created
|
|
108
|
+
- `context.indent()` — increase the indentation level, typically before adding a newline
|
|
109
|
+
- `context.newline()` — self-explanatory
|
|
110
|
+
- `context.margin()` — causes the next newline to be repeated (consecutive newlines are otherwise merged into one)
|
|
111
|
+
- `context.dedent()` — decrease the indentation level (again, typically before adding a newline)
|
|
112
|
+
- `context.visit(node: BaseNode)` — calls the visitor corresponding to `node.type`
|
|
113
|
+
- `context.location(line: number, column: number)` — insert a sourcemap mapping _without_ calling `context.write(...)`
|
|
114
|
+
- `context.measure()` — returns the number of characters contained in `context`
|
|
115
|
+
- `context.empty()` — returns true if the context has no content
|
|
116
|
+
- `context.new()` — creates a child context
|
|
117
|
+
- `context.append(child)` — appends a child context
|
|
118
|
+
|
|
119
|
+
In addition, `context.multiline` is `true` if the context has multiline content. (This is useful for knowing, for example, when to insert newlines between nodes.)
|
|
120
|
+
|
|
121
|
+
To understand how to wield these methods effectively, read the source code for the built-in languages.
|
|
122
|
+
|
|
36
123
|
## Options
|
|
37
124
|
|
|
38
125
|
You can pass the following options:
|
|
39
126
|
|
|
40
127
|
```js
|
|
41
|
-
const { code, map } = print(ast, {
|
|
128
|
+
const { code, map } = print(ast, ts(), {
|
|
42
129
|
// Populate the `sources` field of the resulting sourcemap
|
|
43
130
|
// (note that the AST is assumed to come from a single file)
|
|
44
131
|
sourceMapSource: 'input.js',
|
|
@@ -51,20 +138,10 @@ const { code, map } = print(ast, {
|
|
|
51
138
|
sourceMapEncodeMappings: false,
|
|
52
139
|
|
|
53
140
|
// String to use for indentation — defaults to '\t'
|
|
54
|
-
indent: ' '
|
|
55
|
-
|
|
56
|
-
// Whether to wrap strings in single or double quotes — defaults to 'single'.
|
|
57
|
-
// This only applies to string literals with no `raw` value, which generally
|
|
58
|
-
// means the AST node was generated programmatically, rather than parsed
|
|
59
|
-
// from an original source
|
|
60
|
-
quotes: 'single'
|
|
141
|
+
indent: ' '
|
|
61
142
|
});
|
|
62
143
|
```
|
|
63
144
|
|
|
64
|
-
## TypeScript
|
|
65
|
-
|
|
66
|
-
`esrap` can also print TypeScript nodes, assuming they match the ESTree-like [`@typescript-eslint/types`](https://www.npmjs.com/package/@typescript-eslint/types).
|
|
67
|
-
|
|
68
145
|
## Why not just use Prettier?
|
|
69
146
|
|
|
70
147
|
Because it's ginormous.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "esrap",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "2.0.0",
|
|
4
4
|
"description": "Parse in reverse",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
@@ -15,6 +15,14 @@
|
|
|
15
15
|
".": {
|
|
16
16
|
"types": "./types/index.d.ts",
|
|
17
17
|
"default": "./src/index.js"
|
|
18
|
+
},
|
|
19
|
+
"./languages/ts": {
|
|
20
|
+
"types": "./types/index.d.ts",
|
|
21
|
+
"default": "./src/languages/ts/index.js"
|
|
22
|
+
},
|
|
23
|
+
"./languages/tsx": {
|
|
24
|
+
"types": "./types/index.d.ts",
|
|
25
|
+
"default": "./src/languages/tsx/index.js"
|
|
18
26
|
}
|
|
19
27
|
},
|
|
20
28
|
"types": "./types/index.d.ts",
|
|
@@ -23,8 +31,8 @@
|
|
|
23
31
|
"@sveltejs/acorn-typescript": "^1.0.5",
|
|
24
32
|
"@typescript-eslint/types": "^8.2.0",
|
|
25
33
|
"@vitest/ui": "^2.1.1",
|
|
26
|
-
"acorn": "^8.
|
|
27
|
-
"dts-buddy": "^0.
|
|
34
|
+
"acorn": "^8.15.0",
|
|
35
|
+
"dts-buddy": "^0.6.2",
|
|
28
36
|
"prettier": "^3.0.3",
|
|
29
37
|
"typescript": "^5.7.2",
|
|
30
38
|
"vitest": "^2.1.1",
|
package/src/context.js
ADDED
|
@@ -0,0 +1,150 @@
|
|
|
1
|
+
/** @import { TSESTree } from '@typescript-eslint/types' */
|
|
2
|
+
/** @import { BaseNode, Command, Visitors } from './types' */
|
|
3
|
+
|
|
4
|
+
export const margin = 0;
|
|
5
|
+
export const newline = 1;
|
|
6
|
+
export const indent = 2;
|
|
7
|
+
export const dedent = 3;
|
|
8
|
+
|
|
9
|
+
export class Context {
|
|
10
|
+
#visitors;
|
|
11
|
+
#commands;
|
|
12
|
+
|
|
13
|
+
multiline = false;
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
*
|
|
17
|
+
* @param {Visitors} visitors
|
|
18
|
+
* @param {Command[]} commands
|
|
19
|
+
*/
|
|
20
|
+
constructor(visitors, commands = []) {
|
|
21
|
+
this.#visitors = visitors;
|
|
22
|
+
this.#commands = commands;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
indent() {
|
|
26
|
+
this.#commands.push(indent);
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
dedent() {
|
|
30
|
+
this.#commands.push(dedent);
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
margin() {
|
|
34
|
+
this.#commands.push(margin);
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
newline() {
|
|
38
|
+
this.multiline = true;
|
|
39
|
+
this.#commands.push(newline);
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* @param {Context} context
|
|
44
|
+
*/
|
|
45
|
+
append(context) {
|
|
46
|
+
this.#commands.push(context.#commands);
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
*
|
|
51
|
+
* @param {string} content
|
|
52
|
+
* @param {BaseNode} [node]
|
|
53
|
+
*/
|
|
54
|
+
write(content, node) {
|
|
55
|
+
if (node?.loc) {
|
|
56
|
+
this.location(node.loc.start.line, node.loc.start.column);
|
|
57
|
+
this.#commands.push(content);
|
|
58
|
+
this.location(node.loc.end.line, node.loc.end.column);
|
|
59
|
+
} else {
|
|
60
|
+
this.#commands.push(content);
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
/**
|
|
65
|
+
*
|
|
66
|
+
* @param {number} line
|
|
67
|
+
* @param {number} column
|
|
68
|
+
*/
|
|
69
|
+
location(line, column) {
|
|
70
|
+
this.#commands.push({ type: 'Location', line, column });
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
/**
|
|
74
|
+
* @param {{ type: string }} node
|
|
75
|
+
*/
|
|
76
|
+
visit(node) {
|
|
77
|
+
const visitor = this.#visitors[node.type];
|
|
78
|
+
|
|
79
|
+
if (!visitor) {
|
|
80
|
+
let message = `Not implemented: ${node.type}`;
|
|
81
|
+
|
|
82
|
+
if (node.type.includes('TS')) {
|
|
83
|
+
message += ` (consider using 'esrap/languages/ts')`;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
if (node.type.includes('JSX')) {
|
|
87
|
+
message += ` (consider using 'esrap/languages/tsx')`;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
throw new Error(message);
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
if (this.#visitors._) {
|
|
94
|
+
// @ts-ignore
|
|
95
|
+
this.#visitors._(node, this, (node) => visitor(node, this));
|
|
96
|
+
} else {
|
|
97
|
+
// @ts-ignore
|
|
98
|
+
visitor(node, this);
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
empty() {
|
|
103
|
+
return !this.#commands.some(has_content);
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
measure() {
|
|
107
|
+
return measure(this.#commands);
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
new() {
|
|
111
|
+
return new Context(this.#visitors);
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
/**
|
|
116
|
+
*
|
|
117
|
+
* @param {Command[]} commands
|
|
118
|
+
* @param {number} [from]
|
|
119
|
+
* @param {number} [to]
|
|
120
|
+
*/
|
|
121
|
+
function measure(commands, from = 0, to = commands.length) {
|
|
122
|
+
let total = 0;
|
|
123
|
+
|
|
124
|
+
for (let i = from; i < to; i += 1) {
|
|
125
|
+
const command = commands[i];
|
|
126
|
+
|
|
127
|
+
if (typeof command === 'string') {
|
|
128
|
+
total += command.length;
|
|
129
|
+
} else if (Array.isArray(command)) {
|
|
130
|
+
total += measure(command);
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
return total;
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
/**
|
|
138
|
+
* @param {Command} command
|
|
139
|
+
*/
|
|
140
|
+
function has_content(command) {
|
|
141
|
+
if (Array.isArray(command)) {
|
|
142
|
+
return command.some(has_content);
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
if (typeof command === 'string') {
|
|
146
|
+
return command.length > 0;
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
return false;
|
|
150
|
+
}
|
package/src/index.js
CHANGED
|
@@ -1,7 +1,6 @@
|
|
|
1
|
-
/** @import {
|
|
2
|
-
/** @import { Command, PrintOptions, State } from './types' */
|
|
3
|
-
import { handle } from './handlers.js';
|
|
1
|
+
/** @import { BaseNode, Command, Visitors, PrintOptions } from './types' */
|
|
4
2
|
import { encode } from '@jridgewell/sourcemap-codec';
|
|
3
|
+
import { Context, dedent, indent, margin, newline } from './context.js';
|
|
5
4
|
|
|
6
5
|
/** @type {(str: string) => string} str */
|
|
7
6
|
let btoa = () => {
|
|
@@ -10,38 +9,56 @@ let btoa = () => {
|
|
|
10
9
|
|
|
11
10
|
if (typeof window !== 'undefined' && typeof window.btoa === 'function') {
|
|
12
11
|
btoa = (str) => window.btoa(unescape(encodeURIComponent(str)));
|
|
13
|
-
// @ts-expect-error
|
|
14
12
|
} else if (typeof Buffer === 'function') {
|
|
15
|
-
// @ts-expect-error
|
|
16
13
|
btoa = (str) => Buffer.from(str, 'utf-8').toString('base64');
|
|
17
14
|
}
|
|
18
15
|
|
|
16
|
+
class SourceMap {
|
|
17
|
+
version = 3;
|
|
18
|
+
|
|
19
|
+
/** @type {string[]} */
|
|
20
|
+
names = [];
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* @param {[number, number, number, number][][]} mappings
|
|
24
|
+
* @param {PrintOptions} opts
|
|
25
|
+
*/
|
|
26
|
+
constructor(mappings, opts) {
|
|
27
|
+
this.sources = [opts.sourceMapSource || null];
|
|
28
|
+
this.sourcesContent = [opts.sourceMapContent || null];
|
|
29
|
+
this.mappings = opts.sourceMapEncodeMappings === false ? mappings : encode(mappings);
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* Returns a JSON representation suitable for saving as a `*.map` file
|
|
34
|
+
*/
|
|
35
|
+
toString() {
|
|
36
|
+
return JSON.stringify(this);
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* Returns a base64-encoded JSON representation suitable for inlining at the bottom of a file with `//# sourceMappingURL={...}`
|
|
41
|
+
*/
|
|
42
|
+
toUrl() {
|
|
43
|
+
return 'data:application/json;charset=utf-8;base64,' + btoa(this.toString());
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
|
|
19
47
|
/**
|
|
20
|
-
* @
|
|
48
|
+
* @template {BaseNode} [T=BaseNode]
|
|
49
|
+
* @param {T} node
|
|
50
|
+
* @param {Visitors<T>} visitors
|
|
21
51
|
* @param {PrintOptions} opts
|
|
22
52
|
* @returns {{ code: string, map: any }} // TODO
|
|
23
53
|
*/
|
|
24
|
-
export function print(node, opts = {}) {
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
{
|
|
28
|
-
type: 'Program',
|
|
29
|
-
body: node,
|
|
30
|
-
sourceType: 'module'
|
|
31
|
-
},
|
|
32
|
-
opts
|
|
33
|
-
);
|
|
34
|
-
}
|
|
54
|
+
export function print(node, visitors, opts = {}) {
|
|
55
|
+
/** @type {Command[]} */
|
|
56
|
+
const commands = [];
|
|
35
57
|
|
|
36
|
-
|
|
37
|
-
const
|
|
38
|
-
commands: [],
|
|
39
|
-
comments: [],
|
|
40
|
-
multiline: false,
|
|
41
|
-
quote: opts.quotes === 'double' ? '"' : "'"
|
|
42
|
-
};
|
|
58
|
+
// @ts-expect-error some nonsense I don't understand
|
|
59
|
+
const context = new Context(visitors, commands);
|
|
43
60
|
|
|
44
|
-
|
|
61
|
+
context.visit(node);
|
|
45
62
|
|
|
46
63
|
/** @typedef {[number, number, number, number]} Segment */
|
|
47
64
|
|
|
@@ -69,16 +86,14 @@ export function print(node, opts = {}) {
|
|
|
69
86
|
}
|
|
70
87
|
}
|
|
71
88
|
|
|
72
|
-
let
|
|
73
|
-
const
|
|
89
|
+
let current_newline = '\n';
|
|
90
|
+
const indent_str = opts.indent ?? '\t';
|
|
91
|
+
|
|
92
|
+
let needs_newline = false;
|
|
93
|
+
let needs_margin = false;
|
|
74
94
|
|
|
75
95
|
/** @param {Command} command */
|
|
76
96
|
function run(command) {
|
|
77
|
-
if (typeof command === 'string') {
|
|
78
|
-
append(command);
|
|
79
|
-
return;
|
|
80
|
-
}
|
|
81
|
-
|
|
82
97
|
if (Array.isArray(command)) {
|
|
83
98
|
for (let i = 0; i < command.length; i += 1) {
|
|
84
99
|
run(command[i]);
|
|
@@ -86,74 +101,60 @@ export function print(node, opts = {}) {
|
|
|
86
101
|
return;
|
|
87
102
|
}
|
|
88
103
|
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
104
|
+
if (typeof command === 'number') {
|
|
105
|
+
if (command === newline) {
|
|
106
|
+
needs_newline = true;
|
|
107
|
+
} else if (command === margin) {
|
|
108
|
+
needs_margin = true;
|
|
109
|
+
} else if (command === indent) {
|
|
110
|
+
current_newline += indent_str;
|
|
111
|
+
} else if (command === dedent) {
|
|
112
|
+
current_newline = current_newline.slice(0, -indent_str.length);
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
return;
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
if (needs_newline) {
|
|
119
|
+
append(needs_margin ? '\n' + current_newline : current_newline);
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
needs_margin = needs_newline = false;
|
|
123
|
+
|
|
124
|
+
if (typeof command === 'string') {
|
|
125
|
+
append(command);
|
|
126
|
+
return;
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
if (command.type === 'Location') {
|
|
130
|
+
current_line.push([
|
|
131
|
+
current_column,
|
|
132
|
+
0, // source index is always zero
|
|
133
|
+
command.line - 1,
|
|
134
|
+
command.column
|
|
135
|
+
]);
|
|
119
136
|
}
|
|
120
137
|
}
|
|
121
138
|
|
|
122
|
-
for (let i = 0; i <
|
|
123
|
-
run(
|
|
139
|
+
for (let i = 0; i < commands.length; i += 1) {
|
|
140
|
+
run(commands[i]);
|
|
124
141
|
}
|
|
125
142
|
|
|
126
143
|
mappings.push(current_line);
|
|
127
144
|
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
/** @type {string[]} */
|
|
131
|
-
names: [],
|
|
132
|
-
sources: [opts.sourceMapSource || null],
|
|
133
|
-
sourcesContent: [opts.sourceMapContent || null],
|
|
134
|
-
mappings:
|
|
135
|
-
opts.sourceMapEncodeMappings == undefined || opts.sourceMapEncodeMappings
|
|
136
|
-
? encode(mappings)
|
|
137
|
-
: mappings
|
|
138
|
-
};
|
|
139
|
-
|
|
140
|
-
Object.defineProperties(map, {
|
|
141
|
-
toString: {
|
|
142
|
-
enumerable: false,
|
|
143
|
-
value: function toString() {
|
|
144
|
-
return JSON.stringify(this);
|
|
145
|
-
}
|
|
146
|
-
},
|
|
147
|
-
toUrl: {
|
|
148
|
-
enumerable: false,
|
|
149
|
-
value: function toUrl() {
|
|
150
|
-
return 'data:application/json;charset=utf-8;base64,' + btoa(this.toString());
|
|
151
|
-
}
|
|
152
|
-
}
|
|
153
|
-
});
|
|
145
|
+
/** @type {SourceMap} */
|
|
146
|
+
let map;
|
|
154
147
|
|
|
155
148
|
return {
|
|
156
149
|
code,
|
|
157
|
-
|
|
150
|
+
// create sourcemap lazily in case we don't need it
|
|
151
|
+
get map() {
|
|
152
|
+
return (map ??= new SourceMap(mappings, opts));
|
|
153
|
+
}
|
|
158
154
|
};
|
|
159
155
|
}
|
|
156
|
+
|
|
157
|
+
// it sucks that we have to export the class rather than just
|
|
158
|
+
// re-exporting it via public.d.ts, but otherwise TypeScript
|
|
159
|
+
// gets confused about private fields because it is really dumb!
|
|
160
|
+
export { Context };
|