@ontrails/source 1.0.0-beta.41

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/src/nodes.ts ADDED
@@ -0,0 +1,650 @@
1
+ /** Shared curated AST node types, guards, and field accessors. */
2
+
3
+ export interface AstNode {
4
+ readonly type: string;
5
+ readonly start: number;
6
+ readonly end: number;
7
+ readonly parent?: AstNode | null;
8
+ readonly key?: unknown;
9
+ readonly value?: unknown;
10
+ readonly body?: AstNode | readonly AstNode[];
11
+ readonly [key: string]: unknown;
12
+ }
13
+
14
+ export interface ProgramNode extends AstNode {
15
+ readonly type: 'Program';
16
+ readonly body?: readonly AstNode[];
17
+ }
18
+
19
+ export interface IdentifierNode extends AstNode {
20
+ readonly type: 'Identifier';
21
+ readonly name?: string;
22
+ }
23
+
24
+ export interface StringLiteralNode extends AstNode {
25
+ readonly type: 'Literal' | 'StringLiteral';
26
+ readonly value?: unknown;
27
+ }
28
+
29
+ export interface CallExpressionNode extends AstNode {
30
+ readonly type: 'CallExpression' | 'NewExpression';
31
+ readonly arguments?: readonly AstNode[];
32
+ readonly callee?: AstNode;
33
+ }
34
+
35
+ export interface MemberExpressionNode extends AstNode {
36
+ readonly type: 'MemberExpression' | 'StaticMemberExpression';
37
+ readonly computed?: boolean;
38
+ readonly object?: AstNode;
39
+ readonly property?: AstNode;
40
+ }
41
+
42
+ export interface ImportDeclarationNode extends AstNode {
43
+ readonly importKind?: string;
44
+ readonly type: 'ImportDeclaration';
45
+ readonly source?: AstNode;
46
+ readonly specifiers?: readonly AstNode[];
47
+ }
48
+
49
+ export interface ImportSpecifierNode extends AstNode {
50
+ readonly importKind?: string;
51
+ readonly type:
52
+ | 'ImportDefaultSpecifier'
53
+ | 'ImportNamespaceSpecifier'
54
+ | 'ImportSpecifier';
55
+ readonly imported?: AstNode;
56
+ readonly local?: AstNode;
57
+ }
58
+
59
+ export interface ExportDeclarationNode extends AstNode {
60
+ readonly type:
61
+ | 'ExportAllDeclaration'
62
+ | 'ExportDefaultDeclaration'
63
+ | 'ExportNamedDeclaration';
64
+ readonly declaration?: AstNode;
65
+ readonly source?: AstNode;
66
+ readonly specifiers?: readonly AstNode[];
67
+ }
68
+
69
+ export interface ExportSpecifierNode extends AstNode {
70
+ readonly type: 'ExportSpecifier';
71
+ readonly exportKind?: string;
72
+ readonly exported?: AstNode;
73
+ readonly local?: AstNode;
74
+ }
75
+
76
+ export interface VariableDeclarationNode extends AstNode {
77
+ readonly type: 'VariableDeclaration';
78
+ readonly declarations?: readonly AstNode[];
79
+ readonly kind?: string;
80
+ }
81
+
82
+ export interface VariableDeclaratorNode extends AstNode {
83
+ readonly type: 'VariableDeclarator';
84
+ readonly id?: AstNode;
85
+ readonly init?: AstNode;
86
+ }
87
+
88
+ export interface DeclarationWithIdNode extends AstNode {
89
+ readonly type:
90
+ | 'ClassDeclaration'
91
+ | 'EnumDeclaration'
92
+ | 'FunctionDeclaration'
93
+ | 'InterfaceDeclaration'
94
+ | 'TSInterfaceDeclaration'
95
+ | 'TSEnumDeclaration'
96
+ | 'TSTypeAliasDeclaration';
97
+ readonly id?: AstNode;
98
+ }
99
+
100
+ export interface ClassMemberNode extends AstNode {
101
+ readonly type: 'MethodDefinition' | 'PropertyDefinition';
102
+ readonly computed?: boolean;
103
+ readonly key?: AstNode;
104
+ readonly value?: AstNode;
105
+ }
106
+
107
+ export interface ArrayExpressionNode extends AstNode {
108
+ readonly type: 'ArrayExpression';
109
+ readonly elements?: readonly (AstNode | null)[];
110
+ }
111
+
112
+ export interface ObjectExpressionNode extends AstNode {
113
+ readonly type: 'ObjectExpression' | 'ObjectPattern';
114
+ readonly properties?: readonly AstNode[];
115
+ }
116
+
117
+ export interface PropertyNode extends AstNode {
118
+ readonly type: 'Property';
119
+ readonly computed?: boolean;
120
+ readonly key?: AstNode;
121
+ readonly value?: AstNode;
122
+ }
123
+
124
+ export interface RestElementNode extends AstNode {
125
+ readonly type: 'RestElement';
126
+ readonly argument?: AstNode;
127
+ }
128
+
129
+ export interface AssignmentPatternNode extends AstNode {
130
+ readonly type: 'AssignmentPattern';
131
+ readonly left?: AstNode;
132
+ readonly right?: AstNode;
133
+ }
134
+
135
+ export interface ExpressionStatementNode extends AstNode {
136
+ readonly type: 'ExpressionStatement';
137
+ readonly expression?: AstNode;
138
+ }
139
+
140
+ export interface UnaryExpressionNode extends AstNode {
141
+ readonly type: 'AwaitExpression' | 'ChainExpression' | 'UnaryExpression';
142
+ readonly argument?: AstNode;
143
+ }
144
+
145
+ export interface BinaryExpressionNode extends AstNode {
146
+ readonly type:
147
+ | 'AssignmentExpression'
148
+ | 'BinaryExpression'
149
+ | 'ConditionalExpression'
150
+ | 'LogicalExpression';
151
+ readonly alternate?: AstNode;
152
+ readonly consequent?: AstNode;
153
+ readonly left?: AstNode;
154
+ readonly operator?: string;
155
+ readonly right?: AstNode;
156
+ readonly test?: AstNode;
157
+ }
158
+
159
+ export interface FunctionLikeNode extends AstNode {
160
+ readonly type:
161
+ | 'ArrowFunctionExpression'
162
+ | 'FunctionDeclaration'
163
+ | 'FunctionExpression';
164
+ readonly body?: AstNode;
165
+ readonly params?: readonly AstNode[];
166
+ }
167
+
168
+ export interface BlockStatementNode extends AstNode {
169
+ readonly type: 'BlockStatement' | 'StaticBlock';
170
+ readonly body?: readonly AstNode[];
171
+ }
172
+
173
+ export interface ReturnStatementNode extends AstNode {
174
+ readonly type: 'ReturnStatement';
175
+ readonly argument?: AstNode;
176
+ }
177
+
178
+ export type CuratedAstNode =
179
+ | ArrayExpressionNode
180
+ | AssignmentPatternNode
181
+ | BinaryExpressionNode
182
+ | BlockStatementNode
183
+ | CallExpressionNode
184
+ | ClassMemberNode
185
+ | DeclarationWithIdNode
186
+ | ExportDeclarationNode
187
+ | ExportSpecifierNode
188
+ | ExpressionStatementNode
189
+ | FunctionLikeNode
190
+ | IdentifierNode
191
+ | ImportDeclarationNode
192
+ | ImportSpecifierNode
193
+ | MemberExpressionNode
194
+ | ObjectExpressionNode
195
+ | ProgramNode
196
+ | PropertyNode
197
+ | RestElementNode
198
+ | ReturnStatementNode
199
+ | StringLiteralNode
200
+ | UnaryExpressionNode
201
+ | VariableDeclarationNode
202
+ | VariableDeclaratorNode;
203
+
204
+ export interface AstParentContext {
205
+ readonly index: number | null;
206
+ readonly key: string | number | symbol | null | undefined;
207
+ readonly parent: AstNode | null;
208
+ }
209
+
210
+ export interface AstScopeDeclaration {
211
+ readonly end: number;
212
+ readonly node: AstNode;
213
+ readonly start: number;
214
+ readonly type: string;
215
+ }
216
+
217
+ export interface AstScopeContext extends AstParentContext {
218
+ readonly currentScope: string;
219
+ readonly getDeclaration: (name: string) => AstScopeDeclaration | null;
220
+ readonly isDeclared: (name: string) => boolean;
221
+ readonly isCurrentScopeUnder: (scope: string) => boolean;
222
+ }
223
+
224
+ export interface SourceEdit {
225
+ readonly end: number;
226
+ readonly replacement: string;
227
+ readonly start: number;
228
+ }
229
+
230
+ export interface SourceLocation {
231
+ readonly column: number;
232
+ readonly line: number;
233
+ }
234
+
235
+ export interface AstParseDiagnosticLabel {
236
+ readonly end: number;
237
+ readonly message: string | null;
238
+ readonly start: number;
239
+ }
240
+
241
+ export interface AstParseDiagnostic {
242
+ readonly helpMessage: string | null;
243
+ readonly labels: readonly AstParseDiagnosticLabel[];
244
+ readonly message: string;
245
+ readonly severity: string;
246
+ }
247
+
248
+ export interface AstParseResult {
249
+ readonly ast: AstNode | null;
250
+ readonly diagnostics: readonly AstParseDiagnostic[];
251
+ }
252
+
253
+ export interface AstFieldProjection {
254
+ readonly alternate?: AstNode;
255
+ readonly argument?: AstNode;
256
+ readonly arguments?: readonly AstNode[];
257
+ readonly body?: AstNode | readonly AstNode[];
258
+ readonly callee?: AstNode;
259
+ readonly cases?: readonly AstNode[];
260
+ readonly computed?: boolean;
261
+ readonly consequent?: AstNode;
262
+ readonly declaration?: AstNode;
263
+ readonly declarations?: readonly AstNode[];
264
+ readonly discriminant?: AstNode;
265
+ readonly elements?: readonly (AstNode | null)[];
266
+ readonly exportKind?: string;
267
+ readonly exported?: AstNode;
268
+ readonly expression?: AstNode;
269
+ readonly id?: AstNode;
270
+ readonly imported?: AstNode;
271
+ readonly importKind?: string;
272
+ readonly init?: AstNode;
273
+ readonly key?: AstNode;
274
+ readonly kind?: string;
275
+ readonly left?: AstNode;
276
+ readonly local?: AstNode;
277
+ readonly name?: string;
278
+ readonly object?: AstNode;
279
+ readonly operator?: string;
280
+ readonly param?: AstNode;
281
+ readonly params?: readonly AstNode[];
282
+ readonly properties?: readonly AstNode[];
283
+ readonly property?: AstNode;
284
+ readonly returnType?: AstNode;
285
+ readonly right?: AstNode;
286
+ readonly source?: AstNode;
287
+ readonly specifiers?: readonly AstNode[];
288
+ readonly superClass?: AstNode;
289
+ readonly test?: AstNode;
290
+ readonly typeAnnotation?: AstNode;
291
+ readonly value?: unknown;
292
+ }
293
+
294
+ export const isAstNode = (value: unknown): value is AstNode =>
295
+ Boolean(value && typeof value === 'object' && (value as AstNode).type);
296
+
297
+ const isNodeType = <TNode extends CuratedAstNode>(
298
+ node: AstNode | null | undefined,
299
+ types: readonly string[]
300
+ ): node is TNode =>
301
+ node !== null && node !== undefined && types.includes(node.type);
302
+
303
+ export const isProgram = (
304
+ node: AstNode | null | undefined
305
+ ): node is ProgramNode => isNodeType<ProgramNode>(node, ['Program']);
306
+
307
+ export const isIdentifier = (
308
+ node: AstNode | null | undefined
309
+ ): node is IdentifierNode => isNodeType<IdentifierNode>(node, ['Identifier']);
310
+
311
+ export const isCallExpression = (
312
+ node: AstNode | null | undefined
313
+ ): node is CallExpressionNode =>
314
+ isNodeType<CallExpressionNode>(node, ['CallExpression', 'NewExpression']);
315
+
316
+ export const isMemberExpression = (
317
+ node: AstNode | null | undefined
318
+ ): node is MemberExpressionNode =>
319
+ isNodeType<MemberExpressionNode>(node, [
320
+ 'MemberExpression',
321
+ 'StaticMemberExpression',
322
+ ]);
323
+
324
+ export const isImportDeclaration = (
325
+ node: AstNode | null | undefined
326
+ ): node is ImportDeclarationNode =>
327
+ isNodeType<ImportDeclarationNode>(node, ['ImportDeclaration']);
328
+
329
+ export const isImportSpecifier = (
330
+ node: AstNode | null | undefined
331
+ ): node is ImportSpecifierNode =>
332
+ isNodeType<ImportSpecifierNode>(node, [
333
+ 'ImportDefaultSpecifier',
334
+ 'ImportNamespaceSpecifier',
335
+ 'ImportSpecifier',
336
+ ]);
337
+
338
+ export const isExportDeclaration = (
339
+ node: AstNode | null | undefined
340
+ ): node is ExportDeclarationNode =>
341
+ isNodeType<ExportDeclarationNode>(node, [
342
+ 'ExportAllDeclaration',
343
+ 'ExportDefaultDeclaration',
344
+ 'ExportNamedDeclaration',
345
+ ]);
346
+
347
+ export const isExportNamedDeclaration = (
348
+ node: AstNode | null | undefined
349
+ ): node is ExportDeclarationNode & {
350
+ readonly type: 'ExportNamedDeclaration';
351
+ } =>
352
+ isNodeType<
353
+ ExportDeclarationNode & { readonly type: 'ExportNamedDeclaration' }
354
+ >(node, ['ExportNamedDeclaration']);
355
+
356
+ export const isExportDefaultDeclaration = (
357
+ node: AstNode | null | undefined
358
+ ): node is ExportDeclarationNode & {
359
+ readonly type: 'ExportDefaultDeclaration';
360
+ } =>
361
+ isNodeType<
362
+ ExportDeclarationNode & { readonly type: 'ExportDefaultDeclaration' }
363
+ >(node, ['ExportDefaultDeclaration']);
364
+
365
+ export const isExportAllDeclaration = (
366
+ node: AstNode | null | undefined
367
+ ): node is ExportDeclarationNode & { readonly type: 'ExportAllDeclaration' } =>
368
+ isNodeType<ExportDeclarationNode & { readonly type: 'ExportAllDeclaration' }>(
369
+ node,
370
+ ['ExportAllDeclaration']
371
+ );
372
+
373
+ export const isExportSpecifier = (
374
+ node: AstNode | null | undefined
375
+ ): node is ExportSpecifierNode =>
376
+ isNodeType<ExportSpecifierNode>(node, ['ExportSpecifier']);
377
+
378
+ export const isVariableDeclaration = (
379
+ node: AstNode | null | undefined
380
+ ): node is VariableDeclarationNode =>
381
+ isNodeType<VariableDeclarationNode>(node, ['VariableDeclaration']);
382
+
383
+ export const isVariableDeclarator = (
384
+ node: AstNode | null | undefined
385
+ ): node is VariableDeclaratorNode =>
386
+ isNodeType<VariableDeclaratorNode>(node, ['VariableDeclarator']);
387
+
388
+ export const isDeclarationWithId = (
389
+ node: AstNode | null | undefined
390
+ ): node is DeclarationWithIdNode =>
391
+ isNodeType<DeclarationWithIdNode>(node, [
392
+ 'ClassDeclaration',
393
+ 'EnumDeclaration',
394
+ 'FunctionDeclaration',
395
+ 'InterfaceDeclaration',
396
+ 'TSInterfaceDeclaration',
397
+ 'TSEnumDeclaration',
398
+ 'TSTypeAliasDeclaration',
399
+ ]);
400
+
401
+ export const isClassMember = (
402
+ node: AstNode | null | undefined
403
+ ): node is ClassMemberNode =>
404
+ isNodeType<ClassMemberNode>(node, ['MethodDefinition', 'PropertyDefinition']);
405
+
406
+ export const isArrayExpression = (
407
+ node: AstNode | null | undefined
408
+ ): node is ArrayExpressionNode =>
409
+ isNodeType<ArrayExpressionNode>(node, ['ArrayExpression']);
410
+
411
+ export const isObjectExpression = (
412
+ node: AstNode | null | undefined
413
+ ): node is ObjectExpressionNode =>
414
+ isNodeType<ObjectExpressionNode>(node, ['ObjectExpression', 'ObjectPattern']);
415
+
416
+ export const isProperty = (
417
+ node: AstNode | null | undefined
418
+ ): node is PropertyNode => isNodeType<PropertyNode>(node, ['Property']);
419
+
420
+ export const isRestElement = (
421
+ node: AstNode | null | undefined
422
+ ): node is RestElementNode =>
423
+ isNodeType<RestElementNode>(node, ['RestElement']);
424
+
425
+ export const isAssignmentPattern = (
426
+ node: AstNode | null | undefined
427
+ ): node is AssignmentPatternNode =>
428
+ isNodeType<AssignmentPatternNode>(node, ['AssignmentPattern']);
429
+
430
+ export const isExpressionStatement = (
431
+ node: AstNode | null | undefined
432
+ ): node is ExpressionStatementNode =>
433
+ isNodeType<ExpressionStatementNode>(node, ['ExpressionStatement']);
434
+
435
+ export const isUnaryExpression = (
436
+ node: AstNode | null | undefined
437
+ ): node is UnaryExpressionNode =>
438
+ isNodeType<UnaryExpressionNode>(node, [
439
+ 'AwaitExpression',
440
+ 'ChainExpression',
441
+ 'UnaryExpression',
442
+ ]);
443
+
444
+ export const isBinaryExpression = (
445
+ node: AstNode | null | undefined
446
+ ): node is BinaryExpressionNode =>
447
+ isNodeType<BinaryExpressionNode>(node, [
448
+ 'AssignmentExpression',
449
+ 'BinaryExpression',
450
+ 'ConditionalExpression',
451
+ 'LogicalExpression',
452
+ ]);
453
+
454
+ export const isFunctionLike = (
455
+ node: AstNode | null | undefined
456
+ ): node is FunctionLikeNode =>
457
+ isNodeType<FunctionLikeNode>(node, [
458
+ 'ArrowFunctionExpression',
459
+ 'FunctionDeclaration',
460
+ 'FunctionExpression',
461
+ ]);
462
+
463
+ export const isBlockStatement = (
464
+ node: AstNode | null | undefined
465
+ ): node is BlockStatementNode =>
466
+ isNodeType<BlockStatementNode>(node, ['BlockStatement', 'StaticBlock']);
467
+
468
+ export const isReturnStatement = (
469
+ node: AstNode | null | undefined
470
+ ): node is ReturnStatementNode =>
471
+ isNodeType<ReturnStatementNode>(node, ['ReturnStatement']);
472
+
473
+ const projectAstFields = (
474
+ node: AstNode | null | undefined
475
+ ): AstFieldProjection | null => (node ? (node as AstFieldProjection) : null);
476
+
477
+ export const getNodeAlternate = (
478
+ node: AstNode | null | undefined
479
+ ): AstNode | undefined => projectAstFields(node)?.alternate;
480
+
481
+ export const getNodeArgument = (
482
+ node: AstNode | null | undefined
483
+ ): AstNode | undefined => projectAstFields(node)?.argument;
484
+
485
+ export const getNodeArguments = (
486
+ node: AstNode | null | undefined
487
+ ): readonly AstNode[] => (isCallExpression(node) ? (node.arguments ?? []) : []);
488
+
489
+ export const getNodeBody = (
490
+ node: AstNode | null | undefined
491
+ ): AstNode | readonly AstNode[] | undefined => projectAstFields(node)?.body;
492
+
493
+ export const getNodeBodyNode = (
494
+ node: AstNode | null | undefined
495
+ ): AstNode | undefined => {
496
+ const body = getNodeBody(node);
497
+ return isAstNode(body) ? body : undefined;
498
+ };
499
+
500
+ export const getNodeBodyStatements = (
501
+ node: AstNode | null | undefined
502
+ ): readonly AstNode[] => {
503
+ const body = getNodeBody(node);
504
+ return Array.isArray(body) ? body : [];
505
+ };
506
+
507
+ export const getNodeCallee = (
508
+ node: AstNode | null | undefined
509
+ ): AstNode | undefined => (isCallExpression(node) ? node.callee : undefined);
510
+
511
+ export const getNodeCases = (
512
+ node: AstNode | null | undefined
513
+ ): readonly AstNode[] => projectAstFields(node)?.cases ?? [];
514
+
515
+ export const getNodeComputed = (
516
+ node: AstNode | null | undefined
517
+ ): boolean | undefined => projectAstFields(node)?.computed;
518
+
519
+ export const getNodeConsequent = (
520
+ node: AstNode | null | undefined
521
+ ): AstNode | undefined => projectAstFields(node)?.consequent;
522
+
523
+ export const getNodeDeclaration = (
524
+ node: AstNode | null | undefined
525
+ ): AstNode | undefined => projectAstFields(node)?.declaration;
526
+
527
+ export const getNodeDeclarations = (
528
+ node: AstNode | null | undefined
529
+ ): readonly AstNode[] =>
530
+ isVariableDeclaration(node) ? (node.declarations ?? []) : [];
531
+
532
+ export const getNodeDiscriminant = (
533
+ node: AstNode | null | undefined
534
+ ): AstNode | undefined => projectAstFields(node)?.discriminant;
535
+
536
+ export const getNodeElements = (
537
+ node: AstNode | null | undefined
538
+ ): readonly (AstNode | null)[] => projectAstFields(node)?.elements ?? [];
539
+
540
+ export const getNodeExported = (
541
+ node: AstNode | null | undefined
542
+ ): AstNode | undefined => projectAstFields(node)?.exported;
543
+
544
+ export const getNodeExportKind = (
545
+ node: AstNode | null | undefined
546
+ ): string | undefined => projectAstFields(node)?.exportKind;
547
+
548
+ export const getNodeExpression = (
549
+ node: AstNode | null | undefined
550
+ ): AstNode | undefined => projectAstFields(node)?.expression;
551
+
552
+ export const getNodeId = (
553
+ node: AstNode | null | undefined
554
+ ): AstNode | undefined => projectAstFields(node)?.id;
555
+
556
+ export const getNodeImported = (
557
+ node: AstNode | null | undefined
558
+ ): AstNode | undefined => projectAstFields(node)?.imported;
559
+
560
+ export const getNodeImportKind = (
561
+ node: AstNode | null | undefined
562
+ ): string | undefined => projectAstFields(node)?.importKind;
563
+
564
+ export const getNodeInit = (
565
+ node: AstNode | null | undefined
566
+ ): AstNode | undefined => projectAstFields(node)?.init;
567
+
568
+ export const getNodeKey = (
569
+ node: AstNode | null | undefined
570
+ ): AstNode | undefined => projectAstFields(node)?.key;
571
+
572
+ export const getNodeKind = (
573
+ node: AstNode | null | undefined
574
+ ): string | undefined => projectAstFields(node)?.kind;
575
+
576
+ export const getNodeLeft = (
577
+ node: AstNode | null | undefined
578
+ ): AstNode | undefined => projectAstFields(node)?.left;
579
+
580
+ export const getNodeLocal = (
581
+ node: AstNode | null | undefined
582
+ ): AstNode | undefined => projectAstFields(node)?.local;
583
+
584
+ export const getNodeName = (
585
+ node: AstNode | null | undefined
586
+ ): string | undefined => projectAstFields(node)?.name;
587
+
588
+ export const getNodeObject = (
589
+ node: AstNode | null | undefined
590
+ ): AstNode | undefined => (isMemberExpression(node) ? node.object : undefined);
591
+
592
+ export const getNodeOperator = (
593
+ node: AstNode | null | undefined
594
+ ): string | undefined => projectAstFields(node)?.operator;
595
+
596
+ export const getNodeParam = (
597
+ node: AstNode | null | undefined
598
+ ): AstNode | undefined => projectAstFields(node)?.param;
599
+
600
+ export const getNodeParams = (
601
+ node: AstNode | null | undefined
602
+ ): readonly AstNode[] => (isFunctionLike(node) ? (node.params ?? []) : []);
603
+
604
+ export const getNodeProperties = (
605
+ node: AstNode | null | undefined
606
+ ): readonly AstNode[] =>
607
+ isObjectExpression(node) ? (node.properties ?? []) : [];
608
+
609
+ export const getNodeProperty = (
610
+ node: AstNode | null | undefined
611
+ ): AstNode | undefined =>
612
+ isMemberExpression(node) ? node.property : undefined;
613
+
614
+ export const getNodeReturnType = (
615
+ node: AstNode | null | undefined
616
+ ): AstNode | undefined => projectAstFields(node)?.returnType;
617
+
618
+ export const getNodeRight = (
619
+ node: AstNode | null | undefined
620
+ ): AstNode | undefined => projectAstFields(node)?.right;
621
+
622
+ export const getNodeSource = (
623
+ node: AstNode | null | undefined
624
+ ): AstNode | undefined => projectAstFields(node)?.source;
625
+
626
+ export const getNodeSpecifiers = (
627
+ node: AstNode | null | undefined
628
+ ): readonly AstNode[] => projectAstFields(node)?.specifiers ?? [];
629
+
630
+ export const getNodeSuperClass = (
631
+ node: AstNode | null | undefined
632
+ ): AstNode | undefined => projectAstFields(node)?.superClass;
633
+
634
+ export const getNodeTest = (
635
+ node: AstNode | null | undefined
636
+ ): AstNode | undefined => projectAstFields(node)?.test;
637
+
638
+ export const getNodeTypeAnnotation = (
639
+ node: AstNode | null | undefined
640
+ ): AstNode | undefined => projectAstFields(node)?.typeAnnotation;
641
+
642
+ export const getNodeValue = (node: AstNode | null | undefined): unknown =>
643
+ projectAstFields(node)?.value;
644
+
645
+ export const getNodeValueNode = (
646
+ node: AstNode | null | undefined
647
+ ): AstNode | undefined => {
648
+ const value = getNodeValue(node);
649
+ return isAstNode(value) ? value : undefined;
650
+ };
package/src/parse.ts ADDED
@@ -0,0 +1,55 @@
1
+ /** Shared OXC parser facade. */
2
+
3
+ import { parseSync } from 'oxc-parser';
4
+
5
+ import type { AstNode, AstParseResult } from './nodes.js';
6
+
7
+ /** Parse TypeScript source into an AST. Returns null on parse failure. */
8
+ export const parse = (filePath: string, sourceCode: string): AstNode | null => {
9
+ try {
10
+ const result = parseSync(filePath, sourceCode, { sourceType: 'module' });
11
+ return result.program as unknown as AstNode;
12
+ } catch {
13
+ return null;
14
+ }
15
+ };
16
+
17
+ /**
18
+ * Parse TypeScript source and surface parser diagnostics. OXC can recover a
19
+ * partial program for malformed input, so rewrite tooling should use this
20
+ * helper when applying edits would be unsafe after syntax errors.
21
+ */
22
+ export const parseWithDiagnostics = (
23
+ filePath: string,
24
+ sourceCode: string
25
+ ): AstParseResult => {
26
+ try {
27
+ const result = parseSync(filePath, sourceCode, { sourceType: 'module' });
28
+ return {
29
+ ast: result.program as unknown as AstNode,
30
+ diagnostics: result.errors.map((error) => ({
31
+ helpMessage: error.helpMessage,
32
+ labels: error.labels.map((label) => ({
33
+ end: label.end,
34
+ message: label.message,
35
+ start: label.start,
36
+ })),
37
+ message: error.message,
38
+ severity: error.severity,
39
+ })),
40
+ };
41
+ } catch (error) {
42
+ return {
43
+ ast: null,
44
+ diagnostics: [
45
+ {
46
+ helpMessage: null,
47
+ labels: [],
48
+ message:
49
+ error instanceof Error ? error.message : 'Unable to parse source.',
50
+ severity: 'Error',
51
+ },
52
+ ],
53
+ };
54
+ }
55
+ };