espolar 0.1.6 → 0.2.1

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 CHANGED
@@ -75,8 +75,8 @@ Main entry point. Returns `PrintResult<Data>`.
75
75
  | --------------------- | ---------------------------------- | ------------------------------------------------------------------------------------------ |
76
76
  | `source` | `string` | The original source code (required) |
77
77
  | `isUntouched` | `(node) => boolean \| SourceRange` | Determine if a node should be preserved from source. Default: checks `range`/`start`/`end` |
78
- | `getMappingData` | `(node?) => Data` | Extract data for each mapping entry. Default: `() => ({})` |
79
- | `combineMappingData` | `(left, right) => Data` | Merge data when adjacent mappings are combined. Default: returns `right` |
78
+ | `getMappingData` | `(node?) => Data` | Extract data for each mapping entry. Default: `() => undefined` |
79
+ | `combineMappingData` | `(left, right) => Data` | Merge data when adjacent mappings are combined. Default: throws if `left !== right` |
80
80
  | `printers` | `Printers<Data>` | Override printers for specific `AST_NODE_TYPES` |
81
81
  | `getLeadingComments` | `(node) => Comment[] \| undefined` | Return comments to print before a touched node |
82
82
  | `getTrailingComments` | `(node) => Comment[] \| undefined` | Return comments to print after a touched node |
package/dist/index.d.ts CHANGED
@@ -62,10 +62,9 @@ interface PrintResult<Data> {
62
62
  code: string;
63
63
  mappings: Mapping<Data>[];
64
64
  }
65
- interface PrintOptions<Data> {
65
+ interface PrintOptionsBase<Data> {
66
66
  source: string;
67
67
  isUntouched?: (node: AST.Node) => boolean | SourceRange;
68
- getMappingData?: (node?: AST.Node | null) => Data;
69
68
  combineMappingData?: (left: Data, right: Data) => Data;
70
69
  printers?: Printers<Data>;
71
70
  getLeadingComments?: (node: AST.Node) => Comment[] | undefined;
@@ -81,6 +80,11 @@ interface PrintOptions<Data> {
81
80
  */
82
81
  experimentalGetLeftParenSourceRange?: (node: AST.CallExpression | AST.NewExpression) => SourceRange | undefined;
83
82
  }
83
+ interface MappingDataOptions<Data> {
84
+ getMappingData: (node?: AST.Node | null) => Data;
85
+ }
86
+ type MappingDataUndefinedOptions = { [K in keyof MappingDataOptions<0>]?: undefined };
87
+ type PrintOptions<Data> = PrintOptionsBase<Data> & ([Data] extends [undefined] ? MappingDataUndefinedOptions : MappingDataOptions<Data>);
84
88
  interface PrinterContext<Data = any> {
85
89
  readonly options: PrintOptions<Data>;
86
90
  readonly source: string;
@@ -93,6 +97,8 @@ interface PrinterContext<Data = any> {
93
97
  writeSource(start: number, end: number, data?: Data): void;
94
98
  writePreservedNode(node: AST.Node): void;
95
99
  appendMapping(sourceRange: SourceRange, generatedStart: number, generatedEnd: number, data?: Data): void;
100
+ /** Extra mappings that won't be merged automatically */
101
+ createExtraMapping(sourceRange: SourceRange, generatedStart: number, generatedEnd: number, data?: Data): void;
96
102
  }
97
103
  type NodePrinter<Key extends AST_NODE_TYPES, Data> = (node: Extract<AST.Node, {
98
104
  type: Key;
@@ -100,12 +106,11 @@ type NodePrinter<Key extends AST_NODE_TYPES, Data> = (node: Extract<AST.Node, {
100
106
  type Printers<Data> = { [K in AST_NODE_TYPES]?: NodePrinter<K, Data> };
101
107
  //#endregion
102
108
  //#region src/printer.d.ts
103
- declare function print<Data>(node: AST.Node, options: PrintOptions<Data>): PrintResult<Data>;
104
- declare function print<Data>(node: import("estree").Node, options: PrintOptions<Data>): PrintResult<Data>;
105
- declare function print<Data>(node: NodeLike, options: PrintOptions<Data>): PrintResult<Data>;
109
+ declare function print<Data = undefined>(node: AST.Node, options: PrintOptions<Data>): PrintResult<Data>;
110
+ declare function print<Data = undefined>(node: import("estree").Node, options: PrintOptions<Data>): PrintResult<Data>;
111
+ declare function print<Data = undefined>(node: NodeLike, options: PrintOptions<Data>): PrintResult<Data>;
106
112
  declare function defaultIsUntouched(node: AST.Node): boolean | SourceRange;
107
- declare function defaultGetMappingData(node?: AST.Node | null): unknown;
108
- declare function defaultCombineMappingData(left: unknown, right: unknown): unknown;
113
+ declare function defaultCombineMappingData<T>(left: T, right: T): T;
109
114
  //#endregion
110
115
  //#region src/printers.d.ts
111
116
  declare const defaultPrinters: {
@@ -385,4 +390,4 @@ declare function printKeywordType(node: Extract<AST.Node, {
385
390
  type: `${string}Keyword`;
386
391
  }>, context: PrinterContext): void;
387
392
  //#endregion
388
- export { type AST, type Comment, type NodeLike, type NodePrinter, type PrintOptions, type PrintResult, type PrinterContext, type SourceRange, defaultCombineMappingData, defaultGetMappingData, defaultIsUntouched, defaultPrinters, print };
393
+ export { type AST, type Comment, type NodeLike, type NodePrinter, type PrintOptions, type PrintResult, type PrinterContext, type SourceRange, defaultCombineMappingData, defaultIsUntouched, defaultPrinters, print };
package/dist/index.js CHANGED
@@ -1383,19 +1383,18 @@ function print(node, options) {
1383
1383
  function defaultIsUntouched(node) {
1384
1384
  return getNodeRange(node) || false;
1385
1385
  }
1386
- function defaultGetMappingData(node) {
1387
- return {};
1388
- }
1389
1386
  function defaultCombineMappingData(left, right) {
1390
- return right;
1387
+ if (left === right) return left;
1388
+ throw new Error("Cannot combine mapping data with different values when no custom combineMappingData function is provided");
1391
1389
  }
1392
1390
  function createPrinterContext(options) {
1393
1391
  const chunks = [];
1394
1392
  const mappings = [];
1393
+ const extraMappings = [];
1395
1394
  let generatedOffset = 0;
1396
1395
  const isUntouched = options.isUntouched ?? defaultIsUntouched;
1397
- const getMappingData = options.getMappingData ?? defaultGetMappingData;
1398
- const combineMappingData = options.combineMappingData ?? (options.getMappingData ? (left) => left : defaultCombineMappingData);
1396
+ const getMappingData = options.getMappingData ?? (() => void 0);
1397
+ const combineMappingData = options.combineMappingData ?? defaultCombineMappingData;
1399
1398
  const printers = {
1400
1399
  ...defaultPrinters,
1401
1400
  ...options.printers
@@ -1492,14 +1491,23 @@ function createPrinterContext(options) {
1492
1491
  context.writeSource(range.start, range.end, getMappingData(node));
1493
1492
  },
1494
1493
  appendMapping,
1494
+ createExtraMapping(sourceRange, generatedStart, generatedEnd, data) {
1495
+ extraMappings.push({
1496
+ sourceStart: sourceRange.start,
1497
+ sourceEnd: sourceRange.end,
1498
+ generatedStart,
1499
+ generatedEnd,
1500
+ data
1501
+ });
1502
+ },
1495
1503
  result() {
1496
1504
  return {
1497
1505
  code: chunks.join(""),
1498
- mappings: mappings.map(toVolarMapping)
1506
+ mappings: [...mappings, ...extraMappings].map(toVolarMapping)
1499
1507
  };
1500
1508
  }
1501
1509
  };
1502
1510
  return context;
1503
1511
  }
1504
1512
  //#endregion
1505
- export { defaultCombineMappingData, defaultGetMappingData, defaultIsUntouched, defaultPrinters, print };
1513
+ export { defaultCombineMappingData, defaultIsUntouched, defaultPrinters, print };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "espolar",
3
- "version": "0.1.6",
3
+ "version": "0.2.1",
4
4
  "type": "module",
5
5
  "types": "./dist/index.d.ts",
6
6
  "exports": {
@@ -11,7 +11,8 @@
11
11
  }
12
12
  },
13
13
  "files": [
14
- "dist"
14
+ "dist",
15
+ "src"
15
16
  ],
16
17
  "license": "MIT",
17
18
  "repository": {
package/src/api.ts ADDED
@@ -0,0 +1,88 @@
1
+ import type { Mapping } from "@volar/source-map";
2
+ import type { AST, AST_NODE_TYPES, Comment } from "./types.ts";
3
+ import type { SourceRange } from "./mappings.ts";
4
+
5
+ export interface PrintResult<Data> {
6
+ code: string;
7
+ mappings: Mapping<Data>[];
8
+ }
9
+
10
+ export interface PrintOptionsBase<Data> {
11
+ source: string;
12
+ isUntouched?: (node: AST.Node) => boolean | SourceRange;
13
+ combineMappingData?: (left: Data, right: Data) => Data;
14
+ printers?: Printers<Data>;
15
+ getLeadingComments?: (node: AST.Node) => Comment[] | undefined;
16
+ getTrailingComments?: (node: AST.Node) => Comment[] | undefined;
17
+ /**
18
+ * Provide additional source range for the left parenthesis of `CallExpression` and `NewExpression`.
19
+ * This is useful for language tools that want to provide signature hints when user enter `(`.
20
+ *
21
+ * @notes This hook will not interact with parentheses around the callee.
22
+ *
23
+ * @param node The `CallExpression` or `NewExpression` node.
24
+ * @returns The source range of the left parenthesis, `undefined` if not available.
25
+ */
26
+ experimentalGetLeftParenSourceRange?: (
27
+ node: AST.CallExpression | AST.NewExpression,
28
+ ) => SourceRange | undefined;
29
+ }
30
+
31
+ export interface MappingDataOptions<Data> {
32
+ getMappingData: (node?: AST.Node | null) => Data;
33
+ }
34
+
35
+ type MappingDataUndefinedOptions = {
36
+ [K in keyof MappingDataOptions<0>]?: undefined;
37
+ };
38
+
39
+ export type PrintOptions<Data> = PrintOptionsBase<Data> &
40
+ ([Data] extends [undefined]
41
+ ? MappingDataUndefinedOptions
42
+ : MappingDataOptions<Data>);
43
+
44
+ export interface PrinterContext<Data = any> {
45
+ readonly options: PrintOptions<Data>;
46
+ readonly source: string;
47
+ readonly generatedOffset: number;
48
+ write(text: string): void;
49
+ writeMapped(
50
+ text: string,
51
+ sourceStart: number,
52
+ sourceEnd: number,
53
+ data?: Data,
54
+ ): void;
55
+ writeNode(node: AST.Node | null | undefined): void;
56
+ writeNodeList(
57
+ nodes: readonly (AST.Node | null | undefined)[],
58
+ separator: string,
59
+ ): void;
60
+ writeNodeListWithSourceGaps(
61
+ nodes: readonly (AST.Node | null | undefined)[],
62
+ fallbackSeparator: string,
63
+ ): void;
64
+ writeSource(start: number, end: number, data?: Data): void;
65
+ writePreservedNode(node: AST.Node): void;
66
+ appendMapping(
67
+ sourceRange: SourceRange,
68
+ generatedStart: number,
69
+ generatedEnd: number,
70
+ data?: Data,
71
+ ): void;
72
+ /** Extra mappings that won't be merged automatically */
73
+ createExtraMapping(
74
+ sourceRange: SourceRange,
75
+ generatedStart: number,
76
+ generatedEnd: number,
77
+ data?: Data,
78
+ ): void;
79
+ }
80
+
81
+ export type NodePrinter<Key extends AST_NODE_TYPES, Data> = (
82
+ node: Extract<AST.Node, { type: Key }>,
83
+ context: PrinterContext<Data>,
84
+ ) => void;
85
+
86
+ export type Printers<Data> = {
87
+ [K in AST_NODE_TYPES]?: NodePrinter<K, Data>;
88
+ };
package/src/index.ts ADDED
@@ -0,0 +1,14 @@
1
+ export {
2
+ defaultCombineMappingData,
3
+ defaultIsUntouched,
4
+ print,
5
+ } from "./printer.ts";
6
+ export { defaultPrinters } from "./printers.ts";
7
+ export type {
8
+ NodePrinter,
9
+ PrintOptions,
10
+ PrintResult,
11
+ PrinterContext,
12
+ } from "./api.ts";
13
+ export type { AST, NodeLike, Comment } from "./types.ts";
14
+ export type { SourceRange } from "./mappings.ts";
@@ -0,0 +1,85 @@
1
+ import type { Mapping } from "@volar/source-map";
2
+ import type { AST } from "./types.ts";
3
+
4
+ export interface InternalMapping<Data = unknown> {
5
+ sourceStart: number;
6
+ sourceEnd: number;
7
+ generatedStart: number;
8
+ generatedEnd: number;
9
+ data: Data;
10
+ }
11
+
12
+ export interface SourceRange {
13
+ start: number;
14
+ end: number;
15
+ }
16
+
17
+ export function getNodeRange(node: AST.Node): SourceRange | undefined {
18
+ if (Array.isArray(node.range) && node.range.length === 2) {
19
+ const [start, end] = node.range;
20
+ if (Number.isInteger(start) && Number.isInteger(end) && start <= end) {
21
+ return { start, end };
22
+ }
23
+ }
24
+ const { start, end } = node;
25
+ if (
26
+ typeof start === "number" &&
27
+ typeof end === "number" &&
28
+ Number.isInteger(start) &&
29
+ Number.isInteger(end) &&
30
+ start <= end
31
+ ) {
32
+ return { start, end };
33
+ }
34
+
35
+ return undefined;
36
+ }
37
+
38
+ export function pushMapping<Data>(
39
+ mappings: InternalMapping<Data>[],
40
+ mapping: InternalMapping<Data>,
41
+ combineMappingData: (left: Data, right: Data) => Data,
42
+ ): void {
43
+ const previous = mappings.at(-1);
44
+ if (previous && canMerge(previous, mapping)) {
45
+ previous.sourceEnd = mapping.sourceEnd;
46
+ previous.generatedEnd = mapping.generatedEnd;
47
+ previous.data = combineMappingData(previous.data, mapping.data);
48
+ return;
49
+ }
50
+
51
+ mappings.push(mapping);
52
+ }
53
+
54
+ /**
55
+ * Two adjacent mappings with identical lengths can be merged into one mapping.
56
+ * @param left
57
+ * @param right
58
+ * @returns
59
+ */
60
+ function canMerge<Data>(
61
+ left: InternalMapping<Data>,
62
+ right: InternalMapping<Data>,
63
+ ): boolean {
64
+ return (
65
+ left.sourceEnd - left.sourceStart === left.generatedEnd - left.generatedStart &&
66
+ right.sourceEnd - right.sourceStart === right.generatedEnd - right.generatedStart &&
67
+ left.sourceEnd === right.sourceStart &&
68
+ left.generatedEnd === right.generatedStart
69
+ );
70
+ }
71
+
72
+ export function toVolarMapping<Data>(
73
+ mapping: InternalMapping<Data>,
74
+ ): Mapping<Data> {
75
+ const sourceLength = mapping.sourceEnd - mapping.sourceStart;
76
+ const generatedLength = mapping.generatedEnd - mapping.generatedStart;
77
+ return {
78
+ sourceOffsets: [mapping.sourceStart],
79
+ generatedOffsets: [mapping.generatedStart],
80
+ lengths: [sourceLength],
81
+ generatedLengths:
82
+ generatedLength !== sourceLength ? [generatedLength] : undefined,
83
+ data: mapping.data,
84
+ };
85
+ }
package/src/printer.ts ADDED
@@ -0,0 +1,284 @@
1
+ import type {
2
+ NodePrinter,
3
+ PrintOptions,
4
+ PrintResult,
5
+ PrinterContext,
6
+ Printers,
7
+ } from "./api.ts";
8
+ import { defaultPrinters } from "./printers.ts";
9
+ import type { AST, AST_NODE_TYPES, Comment, NodeLike } from "./types.ts";
10
+ import {
11
+ getNodeRange,
12
+ pushMapping,
13
+ toVolarMapping,
14
+ type InternalMapping,
15
+ type SourceRange,
16
+ } from "./mappings.ts";
17
+
18
+ interface InternalPrinterContext extends PrinterContext<any> {
19
+ // make typescript happy about complex types
20
+ options: any;
21
+ result(): PrintResult<any>;
22
+ }
23
+
24
+ function writeComment(context: InternalPrinterContext, comment: Comment): void {
25
+ if (comment.type === "Line") {
26
+ context.write("//" + comment.value + "\n");
27
+ } else {
28
+ context.write("/*" + comment.value + "*/");
29
+ if (comment.value.includes("\n")) {
30
+ context.write("\n");
31
+ }
32
+ }
33
+ }
34
+
35
+ export function print<Data = undefined>(
36
+ node: AST.Node,
37
+ options: PrintOptions<Data>,
38
+ ): PrintResult<Data>;
39
+ export function print<Data = undefined>(
40
+ node: import("estree").Node,
41
+ options: PrintOptions<Data>,
42
+ ): PrintResult<Data>;
43
+ export function print<Data = undefined>(
44
+ node: NodeLike,
45
+ options: PrintOptions<Data>,
46
+ ): PrintResult<Data>;
47
+ export function print<Data = undefined>(
48
+ node: unknown,
49
+ options: PrintOptions<Data>,
50
+ ): PrintResult<Data> {
51
+ const context = createPrinterContext(options);
52
+ context.writeNode(node as AST.Node);
53
+ return context.result();
54
+ }
55
+
56
+ export function defaultIsUntouched(node: AST.Node): boolean | SourceRange {
57
+ return getNodeRange(node) || false;
58
+ }
59
+
60
+ export function defaultCombineMappingData<T>(left: T, right: T): T {
61
+ if (left === right) {
62
+ return left;
63
+ }
64
+ throw new Error(
65
+ "Cannot combine mapping data with different values when no custom combineMappingData function is provided",
66
+ );
67
+ }
68
+
69
+ function createPrinterContext<Data>(
70
+ options: PrintOptions<Data>,
71
+ ): InternalPrinterContext {
72
+ const chunks: string[] = [];
73
+ const mappings: InternalMapping<Data>[] = [];
74
+ const extraMappings: InternalMapping<Data>[] = [];
75
+ let generatedOffset = 0;
76
+
77
+ const isUntouched = options.isUntouched ?? defaultIsUntouched;
78
+ const getMappingData = options.getMappingData ?? ((): any => undefined);
79
+ const combineMappingData =
80
+ options.combineMappingData ?? defaultCombineMappingData;
81
+ const printers: Printers<Data> = {
82
+ ...defaultPrinters,
83
+ ...options.printers,
84
+ };
85
+
86
+ const appendMapping = (
87
+ sourceRange: SourceRange,
88
+ generatedStart: number,
89
+ generatedEnd: number,
90
+ data: Data,
91
+ ) => {
92
+ pushMapping(
93
+ mappings,
94
+ {
95
+ sourceStart: sourceRange.start,
96
+ sourceEnd: sourceRange.end,
97
+ generatedStart,
98
+ generatedEnd,
99
+ data,
100
+ },
101
+ combineMappingData,
102
+ );
103
+ };
104
+
105
+ const context: InternalPrinterContext = {
106
+ options: options,
107
+ source: options.source,
108
+ get generatedOffset() {
109
+ return generatedOffset;
110
+ },
111
+ write(text) {
112
+ if (text.length === 0) {
113
+ return;
114
+ }
115
+ chunks.push(text);
116
+ generatedOffset += text.length;
117
+ },
118
+ writeMapped(text, sourceStart, sourceEnd, data) {
119
+ if (text.length === 0 || sourceEnd < sourceStart) {
120
+ return;
121
+ }
122
+ const generatedStart = generatedOffset;
123
+ context.write(text);
124
+ appendMapping(
125
+ { start: sourceStart, end: sourceEnd },
126
+ generatedStart,
127
+ generatedOffset,
128
+ data ?? getMappingData(null),
129
+ );
130
+ },
131
+ writeNode(node) {
132
+ if (!node) {
133
+ return;
134
+ }
135
+
136
+ const range = getNodeRange(node);
137
+ const untouchedRet = isUntouched(node);
138
+ if (untouchedRet) {
139
+ const sourceRange = untouchedRet === true ? range : untouchedRet;
140
+ if (!sourceRange) {
141
+ throw new Error(
142
+ `Node of type ${node.type} is marked as untouched but does not have valid source offsets`,
143
+ );
144
+ }
145
+ context.writeSource(
146
+ sourceRange.start,
147
+ sourceRange.end,
148
+ getMappingData(node),
149
+ );
150
+ return;
151
+ }
152
+
153
+ const printer = printers[node.type] as
154
+ | NodePrinter<AST_NODE_TYPES, Data>
155
+ | undefined;
156
+ if (!printer) {
157
+ throw new Error(`No printer registered for node type ${node.type}`);
158
+ }
159
+
160
+ const leadingComments = options.getLeadingComments?.(node);
161
+ if (leadingComments) {
162
+ for (const c of leadingComments) {
163
+ writeComment(context, c);
164
+ }
165
+ }
166
+
167
+ const generatedStart = generatedOffset;
168
+ printer(node, context);
169
+ const generatedEnd = generatedOffset;
170
+
171
+ const trailingComments = options.getTrailingComments?.(node);
172
+ if (trailingComments) {
173
+ for (const c of trailingComments) {
174
+ writeComment(context, c);
175
+ }
176
+ }
177
+ // If children nodes don't emit any mapping but the parent node itself
178
+ // can produce mapping, add that mapping
179
+ const lastMappingGeneratedEnd = mappings.at(-1)?.generatedEnd ?? 0;
180
+ if (range && lastMappingGeneratedEnd <= generatedStart) {
181
+ appendMapping(
182
+ range,
183
+ generatedStart,
184
+ generatedEnd,
185
+ getMappingData(node),
186
+ );
187
+ }
188
+ },
189
+ writeNodeList(nodes, separator) {
190
+ let needsSeparator = false;
191
+ for (const node of nodes) {
192
+ if (!node) {
193
+ if (needsSeparator) {
194
+ context.write(separator);
195
+ }
196
+ continue;
197
+ }
198
+
199
+ if (needsSeparator) {
200
+ context.write(separator);
201
+ }
202
+ context.writeNode(node);
203
+ needsSeparator = true;
204
+ }
205
+ },
206
+ writeNodeListWithSourceGaps(nodes, fallbackSeparator) {
207
+ let lastRangeEnd: number | undefined;
208
+ let wroteNode = false;
209
+
210
+ for (const node of nodes) {
211
+ if (!node) {
212
+ continue;
213
+ }
214
+
215
+ const range = getNodeRange(node);
216
+ if (wroteNode) {
217
+ if (
218
+ lastRangeEnd !== undefined &&
219
+ range &&
220
+ range.start >= lastRangeEnd
221
+ ) {
222
+ context.writeSource(
223
+ lastRangeEnd,
224
+ range.start,
225
+ getMappingData(null),
226
+ );
227
+ } else {
228
+ context.write(fallbackSeparator);
229
+ }
230
+ }
231
+
232
+ context.writeNode(node);
233
+ wroteNode = true;
234
+
235
+ if (range) {
236
+ lastRangeEnd = range.end;
237
+ } else {
238
+ lastRangeEnd = undefined;
239
+ }
240
+ }
241
+ },
242
+ writeSource(start, end, data) {
243
+ if (end < start) {
244
+ return;
245
+ }
246
+
247
+ const generatedStart = generatedOffset;
248
+ context.write(options.source.slice(start, end));
249
+ appendMapping(
250
+ { start, end },
251
+ generatedStart,
252
+ generatedOffset,
253
+ data ?? getMappingData(null),
254
+ );
255
+ },
256
+ writePreservedNode(node) {
257
+ const range = getNodeRange(node);
258
+ if (!range) {
259
+ throw new Error(
260
+ `Cannot preserve node ${node.type} without source offsets`,
261
+ );
262
+ }
263
+ context.writeSource(range.start, range.end, getMappingData(node));
264
+ },
265
+ appendMapping,
266
+ createExtraMapping(sourceRange, generatedStart, generatedEnd, data) {
267
+ extraMappings.push({
268
+ sourceStart: sourceRange.start,
269
+ sourceEnd: sourceRange.end,
270
+ generatedStart,
271
+ generatedEnd,
272
+ data,
273
+ });
274
+ },
275
+ result() {
276
+ return {
277
+ code: chunks.join(""),
278
+ mappings: [...mappings, ...extraMappings].map(toVolarMapping),
279
+ };
280
+ },
281
+ };
282
+
283
+ return context;
284
+ }