@speclynx/apidom-parser-adapter-yaml-1-2 6.0.6 → 6.1.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/CHANGELOG.md +41 -0
- package/dist/apidom-parser-adapter-yaml-1-2.browser.js +399 -1166
- package/dist/apidom-parser-adapter-yaml-1-2.browser.min.js +1 -1
- package/package.json +5 -6
- package/src/tree-sitter/lexical-analysis/index.cjs +1 -1
- package/src/tree-sitter/lexical-analysis/index.mjs +1 -1
- package/src/tree-sitter/syntactic-analysis/CstTransformer.cjs +113 -9
- package/src/tree-sitter/syntactic-analysis/CstTransformer.mjs +113 -9
- package/src/tree-sitter/syntactic-analysis/YamlAstTransformer.cjs +99 -18
- package/src/tree-sitter/syntactic-analysis/YamlAstTransformer.mjs +99 -18
- package/src/tree-sitter/syntactic-analysis/ast/anchors-aliases/ReferenceManager.cjs +17 -1
- package/src/tree-sitter/syntactic-analysis/ast/anchors-aliases/ReferenceManager.mjs +17 -1
- package/src/tree-sitter/syntactic-analysis/ast/nodes/YamlScalar.cjs +3 -0
- package/src/tree-sitter/syntactic-analysis/ast/nodes/YamlScalar.mjs +3 -0
- package/src/tree-sitter/syntactic-analysis/ast/nodes/YamlStream.cjs +3 -0
- package/src/tree-sitter/syntactic-analysis/ast/nodes/YamlStream.mjs +3 -0
- package/src/tree-sitter/syntactic-analysis/ast/schemas/canonical-format.cjs +144 -51
- package/src/tree-sitter/syntactic-analysis/ast/schemas/canonical-format.mjs +146 -53
|
@@ -22,6 +22,7 @@ var _YamlSequence = _interopRequireDefault(require("./ast/nodes/YamlSequence.cjs
|
|
|
22
22
|
var _YamlStream = _interopRequireDefault(require("./ast/nodes/YamlStream.cjs"));
|
|
23
23
|
var _YamlTag = _interopRequireWildcard(require("./ast/nodes/YamlTag.cjs"));
|
|
24
24
|
var _YamlStyle = require("./ast/nodes/YamlStyle.cjs");
|
|
25
|
+
var _predicates = require("./ast/nodes/predicates.cjs");
|
|
25
26
|
const getCursorInfo = cursor => ({
|
|
26
27
|
type: cursor.nodeType,
|
|
27
28
|
startPosition: cursor.startPosition,
|
|
@@ -35,6 +36,15 @@ const getCursorInfo = cursor => ({
|
|
|
35
36
|
fieldName: cursor.currentFieldName
|
|
36
37
|
});
|
|
37
38
|
|
|
39
|
+
// TreeCursor#copy() in web-tree-sitter 0.27.1 doesn't marshal the cursor it's called on, so it
|
|
40
|
+
// copies whichever cursor or node was marshalled last; resetTo() marshals both cursors
|
|
41
|
+
// https://github.com/tree-sitter/tree-sitter/issues/6045
|
|
42
|
+
const copyCursor = cursor => {
|
|
43
|
+
const copy = cursor.currentNode.tree.walk();
|
|
44
|
+
copy.resetTo(cursor);
|
|
45
|
+
return copy;
|
|
46
|
+
};
|
|
47
|
+
|
|
38
48
|
// Flat position properties extracted from CursorInfo
|
|
39
49
|
|
|
40
50
|
const toPositionProps = info => ({
|
|
@@ -242,6 +252,8 @@ const createTransformers = transformerMap => ({
|
|
|
242
252
|
...toPositionProps(info),
|
|
243
253
|
isMissing: info.isMissing
|
|
244
254
|
});
|
|
255
|
+
const lineBreak = info.text.match(/\r?\n/);
|
|
256
|
+
if (lineBreak) stream.lineBreak = lineBreak[0];
|
|
245
257
|
return new _ParseResult.default({
|
|
246
258
|
children: [stream]
|
|
247
259
|
});
|
|
@@ -325,14 +337,18 @@ const createTransformers = transformerMap => ({
|
|
|
325
337
|
return children;
|
|
326
338
|
},
|
|
327
339
|
flow_node(cursor, ctx, siblings) {
|
|
328
|
-
// Check if there's a kind node (scalar, mapping, or
|
|
340
|
+
// Check if there's a kind node (scalar, mapping, sequence or alias)
|
|
329
341
|
let hasKindNode = false;
|
|
330
342
|
let lastChildInfo = null;
|
|
343
|
+
let tagInfo;
|
|
344
|
+
let anchorInfo;
|
|
331
345
|
if (cursor.gotoFirstChild()) {
|
|
332
346
|
do {
|
|
333
347
|
const childInfo = getCursorInfo(cursor);
|
|
334
348
|
lastChildInfo = childInfo;
|
|
335
|
-
if (childInfo.type
|
|
349
|
+
if (childInfo.type === 'tag') tagInfo = childInfo;
|
|
350
|
+
if (childInfo.type === 'anchor') anchorInfo = childInfo;
|
|
351
|
+
if (childInfo.type.endsWith('scalar') || childInfo.type.endsWith('mapping') || childInfo.type.endsWith('sequence') || childInfo.type === 'alias') {
|
|
336
352
|
hasKindNode = true;
|
|
337
353
|
}
|
|
338
354
|
} while (cursor.gotoNextSibling());
|
|
@@ -345,10 +361,15 @@ const createTransformers = transformerMap => ({
|
|
|
345
361
|
|
|
346
362
|
// No kind node - create empty scalar
|
|
347
363
|
if (lastChildInfo) {
|
|
364
|
+
const emptyAnchorInfo = anchorInfo ?? siblings.anchor;
|
|
348
365
|
const emptyScalarNode = new _YamlScalar.default({
|
|
349
366
|
content: '',
|
|
350
|
-
|
|
351
|
-
|
|
367
|
+
// the anchor and tag of an empty node are children of the flow node, not siblings
|
|
368
|
+
anchor: emptyAnchorInfo ? toYamlAnchor(emptyAnchorInfo) : undefined,
|
|
369
|
+
tag: toYamlTag({
|
|
370
|
+
...lastChildInfo,
|
|
371
|
+
type: 'plain_scalar'
|
|
372
|
+
}, tagInfo ?? siblings.tag),
|
|
352
373
|
startLine: lastChildInfo.endPosition.row,
|
|
353
374
|
startCharacter: lastChildInfo.endPosition.column,
|
|
354
375
|
startOffset: lastChildInfo.endIndex,
|
|
@@ -447,8 +468,39 @@ const createTransformers = transformerMap => ({
|
|
|
447
468
|
const tag = toYamlTag(info, siblings.tag);
|
|
448
469
|
const anchor = siblings.anchor ? toYamlAnchor(siblings.anchor) : undefined;
|
|
449
470
|
const children = processChildren(cursor, ctx, transformerMap);
|
|
471
|
+
|
|
472
|
+
// an entry with only a key (e.g. { a }) has an empty value (YAML 1.2 §7.4.2); the CST has no
|
|
473
|
+
// flow_pair for it, so the pair is made here
|
|
474
|
+
const toPair = child => {
|
|
475
|
+
if (!(0, _predicates.isScalar)(child) && !(0, _predicates.isMapping)(child) && !(0, _predicates.isSequence)(child)) return child;
|
|
476
|
+
const emptyValue = new _YamlScalar.default({
|
|
477
|
+
content: '',
|
|
478
|
+
startLine: child.endLine,
|
|
479
|
+
startCharacter: child.endCharacter,
|
|
480
|
+
startOffset: child.endOffset,
|
|
481
|
+
endLine: child.endLine,
|
|
482
|
+
endCharacter: child.endCharacter,
|
|
483
|
+
endOffset: child.endOffset,
|
|
484
|
+
tag: new _YamlTag.default({
|
|
485
|
+
explicitName: '?',
|
|
486
|
+
kind: _YamlTag.YamlNodeKind.Scalar
|
|
487
|
+
}),
|
|
488
|
+
styleGroup: _YamlStyle.YamlStyleGroup.Flow,
|
|
489
|
+
style: _YamlStyle.YamlStyle.Plain
|
|
490
|
+
});
|
|
491
|
+
return new _YamlKeyValuePair.default({
|
|
492
|
+
children: [child, emptyValue],
|
|
493
|
+
startLine: child.startLine,
|
|
494
|
+
startCharacter: child.startCharacter,
|
|
495
|
+
startOffset: child.startOffset,
|
|
496
|
+
endLine: child.endLine,
|
|
497
|
+
endCharacter: child.endCharacter,
|
|
498
|
+
endOffset: child.endOffset,
|
|
499
|
+
styleGroup: _YamlStyle.YamlStyleGroup.Flow
|
|
500
|
+
});
|
|
501
|
+
};
|
|
450
502
|
const mappingNode = new _YamlMapping.default({
|
|
451
|
-
children: children.flat().filter(c => c !== null),
|
|
503
|
+
children: children.flat().filter(c => c !== null).map(toPair),
|
|
452
504
|
...toPositionProps(info),
|
|
453
505
|
anchor,
|
|
454
506
|
tag,
|
|
@@ -567,8 +619,30 @@ const createTransformers = transformerMap => ({
|
|
|
567
619
|
const tag = toYamlTag(info, siblings.tag);
|
|
568
620
|
const anchor = siblings.anchor ? toYamlAnchor(siblings.anchor) : undefined;
|
|
569
621
|
const children = processChildren(cursor, ctx, transformerMap);
|
|
622
|
+
|
|
623
|
+
// a single pair as a flow sequence entry (e.g. [a: 1]) is a mapping with that one pair
|
|
624
|
+
// (YAML 1.2 §7.4.1); the CST has the flow_pair directly in the flow_sequence
|
|
625
|
+
const toSinglePairMapping = child => {
|
|
626
|
+
if (!(0, _predicates.isKeyValuePair)(child)) return child;
|
|
627
|
+
const mappingNode = new _YamlMapping.default({
|
|
628
|
+
children: [child],
|
|
629
|
+
startLine: child.startLine,
|
|
630
|
+
startCharacter: child.startCharacter,
|
|
631
|
+
startOffset: child.startOffset,
|
|
632
|
+
endLine: child.endLine,
|
|
633
|
+
endCharacter: child.endCharacter,
|
|
634
|
+
endOffset: child.endOffset,
|
|
635
|
+
tag: new _YamlTag.default({
|
|
636
|
+
explicitName: '!',
|
|
637
|
+
kind: _YamlTag.YamlNodeKind.Mapping
|
|
638
|
+
}),
|
|
639
|
+
styleGroup: _YamlStyle.YamlStyleGroup.Flow,
|
|
640
|
+
style: _YamlStyle.YamlStyle.SinglePair
|
|
641
|
+
});
|
|
642
|
+
return ctx.schema.resolve(mappingNode);
|
|
643
|
+
};
|
|
570
644
|
const sequenceNode = new _YamlSequence.default({
|
|
571
|
-
children: children.flat().filter(c => c !== null),
|
|
645
|
+
children: children.flat().filter(c => c !== null).map(toSinglePairMapping),
|
|
572
646
|
...toPositionProps(info),
|
|
573
647
|
anchor,
|
|
574
648
|
tag,
|
|
@@ -631,15 +705,44 @@ const createTransformers = transformerMap => ({
|
|
|
631
705
|
const tag = toYamlTag(info, siblings.tag);
|
|
632
706
|
const anchor = siblings.anchor ? toYamlAnchor(siblings.anchor) : undefined;
|
|
633
707
|
const style = info.text.startsWith('|') ? _YamlStyle.YamlStyle.Literal : info.text.startsWith('>') ? _YamlStyle.YamlStyle.Folded : _YamlStyle.YamlStyle.Plain;
|
|
708
|
+
|
|
709
|
+
// trailing lines belong to the block scalar, but the CST node ends at its last content
|
|
710
|
+
// character when another node follows; the lines up to the line of the next node in
|
|
711
|
+
// source order are taken from the text of the node holding both
|
|
712
|
+
let trailingLines = '';
|
|
713
|
+
if (!info.text.endsWith('\n')) {
|
|
714
|
+
// a cursor copy walks up in constant time per step, unlike Node#parent
|
|
715
|
+
const following = copyCursor(cursor);
|
|
716
|
+
let hasNext = following.gotoNextSibling();
|
|
717
|
+
while (!hasNext && following.gotoParent()) {
|
|
718
|
+
hasNext = following.gotoNextSibling();
|
|
719
|
+
}
|
|
720
|
+
// without a next node the scalar ends the input, so there are no lines to add
|
|
721
|
+
if (hasNext) {
|
|
722
|
+
const nextIndex = following.startIndex;
|
|
723
|
+
following.gotoParent();
|
|
724
|
+
const gap = following.nodeText.slice(info.endIndex - following.startIndex, nextIndex - following.startIndex);
|
|
725
|
+
trailingLines = gap.slice(0, gap.lastIndexOf('\n') + 1);
|
|
726
|
+
}
|
|
727
|
+
following.delete();
|
|
728
|
+
}
|
|
729
|
+
|
|
730
|
+
// an explicit indentation indicator is relative to the parent node's indentation: the
|
|
731
|
+
// column of the mapping pair or sequence item holding the block node (0 at top level);
|
|
732
|
+
// content lines are rebased to it so that the indicator can be applied to them as is
|
|
733
|
+
const holder = cursor.currentNode.parent?.parent;
|
|
734
|
+
const parentIndentation = holder?.type === 'block_mapping_pair' || holder?.type === 'block_sequence_item' ? holder.startPosition.column : 0;
|
|
735
|
+
const rebased = (info.text + trailingLines).replace(new RegExp(`\n {0,${parentIndentation}}`, 'g'), '\n');
|
|
634
736
|
const scalarNode = new _YamlScalar.default({
|
|
635
|
-
content:
|
|
737
|
+
content: rebased,
|
|
636
738
|
anchor,
|
|
637
739
|
tag,
|
|
638
740
|
...toPositionProps(info),
|
|
639
741
|
styleGroup: _YamlStyle.YamlStyleGroup.Block,
|
|
640
742
|
style
|
|
641
743
|
});
|
|
642
|
-
|
|
744
|
+
// the block's source text, rebased to its parent's indentation and with its trailing lines
|
|
745
|
+
scalarNode.rawContent = rebased;
|
|
643
746
|
registerAnchor(scalarNode, ctx);
|
|
644
747
|
return ctx.schema.resolve(scalarNode);
|
|
645
748
|
},
|
|
@@ -653,7 +756,8 @@ const createTransformers = transformerMap => ({
|
|
|
653
756
|
alias(cursor, ctx) {
|
|
654
757
|
const info = getCursorInfo(cursor);
|
|
655
758
|
const alias = new _YamlAlias.default({
|
|
656
|
-
content: info.text
|
|
759
|
+
content: info.text,
|
|
760
|
+
...toPositionProps(info)
|
|
657
761
|
});
|
|
658
762
|
return ctx.referenceManager.resolveAlias(alias);
|
|
659
763
|
},
|
|
@@ -14,6 +14,7 @@ import YamlSequence from "./ast/nodes/YamlSequence.mjs";
|
|
|
14
14
|
import YamlStream from "./ast/nodes/YamlStream.mjs";
|
|
15
15
|
import YamlTag, { YamlNodeKind } from "./ast/nodes/YamlTag.mjs";
|
|
16
16
|
import { YamlStyle, YamlStyleGroup } from "./ast/nodes/YamlStyle.mjs";
|
|
17
|
+
import { isKeyValuePair, isMapping, isScalar, isSequence } from "./ast/nodes/predicates.mjs";
|
|
17
18
|
const getCursorInfo = cursor => ({
|
|
18
19
|
type: cursor.nodeType,
|
|
19
20
|
startPosition: cursor.startPosition,
|
|
@@ -27,6 +28,15 @@ const getCursorInfo = cursor => ({
|
|
|
27
28
|
fieldName: cursor.currentFieldName
|
|
28
29
|
});
|
|
29
30
|
|
|
31
|
+
// TreeCursor#copy() in web-tree-sitter 0.27.1 doesn't marshal the cursor it's called on, so it
|
|
32
|
+
// copies whichever cursor or node was marshalled last; resetTo() marshals both cursors
|
|
33
|
+
// https://github.com/tree-sitter/tree-sitter/issues/6045
|
|
34
|
+
const copyCursor = cursor => {
|
|
35
|
+
const copy = cursor.currentNode.tree.walk();
|
|
36
|
+
copy.resetTo(cursor);
|
|
37
|
+
return copy;
|
|
38
|
+
};
|
|
39
|
+
|
|
30
40
|
// Flat position properties extracted from CursorInfo
|
|
31
41
|
|
|
32
42
|
const toPositionProps = info => ({
|
|
@@ -234,6 +244,8 @@ const createTransformers = transformerMap => ({
|
|
|
234
244
|
...toPositionProps(info),
|
|
235
245
|
isMissing: info.isMissing
|
|
236
246
|
});
|
|
247
|
+
const lineBreak = info.text.match(/\r?\n/);
|
|
248
|
+
if (lineBreak) stream.lineBreak = lineBreak[0];
|
|
237
249
|
return new ParseResult({
|
|
238
250
|
children: [stream]
|
|
239
251
|
});
|
|
@@ -317,14 +329,18 @@ const createTransformers = transformerMap => ({
|
|
|
317
329
|
return children;
|
|
318
330
|
},
|
|
319
331
|
flow_node(cursor, ctx, siblings) {
|
|
320
|
-
// Check if there's a kind node (scalar, mapping, or
|
|
332
|
+
// Check if there's a kind node (scalar, mapping, sequence or alias)
|
|
321
333
|
let hasKindNode = false;
|
|
322
334
|
let lastChildInfo = null;
|
|
335
|
+
let tagInfo;
|
|
336
|
+
let anchorInfo;
|
|
323
337
|
if (cursor.gotoFirstChild()) {
|
|
324
338
|
do {
|
|
325
339
|
const childInfo = getCursorInfo(cursor);
|
|
326
340
|
lastChildInfo = childInfo;
|
|
327
|
-
if (childInfo.type
|
|
341
|
+
if (childInfo.type === 'tag') tagInfo = childInfo;
|
|
342
|
+
if (childInfo.type === 'anchor') anchorInfo = childInfo;
|
|
343
|
+
if (childInfo.type.endsWith('scalar') || childInfo.type.endsWith('mapping') || childInfo.type.endsWith('sequence') || childInfo.type === 'alias') {
|
|
328
344
|
hasKindNode = true;
|
|
329
345
|
}
|
|
330
346
|
} while (cursor.gotoNextSibling());
|
|
@@ -337,10 +353,15 @@ const createTransformers = transformerMap => ({
|
|
|
337
353
|
|
|
338
354
|
// No kind node - create empty scalar
|
|
339
355
|
if (lastChildInfo) {
|
|
356
|
+
const emptyAnchorInfo = anchorInfo ?? siblings.anchor;
|
|
340
357
|
const emptyScalarNode = new YamlScalar({
|
|
341
358
|
content: '',
|
|
342
|
-
|
|
343
|
-
|
|
359
|
+
// the anchor and tag of an empty node are children of the flow node, not siblings
|
|
360
|
+
anchor: emptyAnchorInfo ? toYamlAnchor(emptyAnchorInfo) : undefined,
|
|
361
|
+
tag: toYamlTag({
|
|
362
|
+
...lastChildInfo,
|
|
363
|
+
type: 'plain_scalar'
|
|
364
|
+
}, tagInfo ?? siblings.tag),
|
|
344
365
|
startLine: lastChildInfo.endPosition.row,
|
|
345
366
|
startCharacter: lastChildInfo.endPosition.column,
|
|
346
367
|
startOffset: lastChildInfo.endIndex,
|
|
@@ -439,8 +460,39 @@ const createTransformers = transformerMap => ({
|
|
|
439
460
|
const tag = toYamlTag(info, siblings.tag);
|
|
440
461
|
const anchor = siblings.anchor ? toYamlAnchor(siblings.anchor) : undefined;
|
|
441
462
|
const children = processChildren(cursor, ctx, transformerMap);
|
|
463
|
+
|
|
464
|
+
// an entry with only a key (e.g. { a }) has an empty value (YAML 1.2 §7.4.2); the CST has no
|
|
465
|
+
// flow_pair for it, so the pair is made here
|
|
466
|
+
const toPair = child => {
|
|
467
|
+
if (!isScalar(child) && !isMapping(child) && !isSequence(child)) return child;
|
|
468
|
+
const emptyValue = new YamlScalar({
|
|
469
|
+
content: '',
|
|
470
|
+
startLine: child.endLine,
|
|
471
|
+
startCharacter: child.endCharacter,
|
|
472
|
+
startOffset: child.endOffset,
|
|
473
|
+
endLine: child.endLine,
|
|
474
|
+
endCharacter: child.endCharacter,
|
|
475
|
+
endOffset: child.endOffset,
|
|
476
|
+
tag: new YamlTag({
|
|
477
|
+
explicitName: '?',
|
|
478
|
+
kind: YamlNodeKind.Scalar
|
|
479
|
+
}),
|
|
480
|
+
styleGroup: YamlStyleGroup.Flow,
|
|
481
|
+
style: YamlStyle.Plain
|
|
482
|
+
});
|
|
483
|
+
return new YamlKeyValuePair({
|
|
484
|
+
children: [child, emptyValue],
|
|
485
|
+
startLine: child.startLine,
|
|
486
|
+
startCharacter: child.startCharacter,
|
|
487
|
+
startOffset: child.startOffset,
|
|
488
|
+
endLine: child.endLine,
|
|
489
|
+
endCharacter: child.endCharacter,
|
|
490
|
+
endOffset: child.endOffset,
|
|
491
|
+
styleGroup: YamlStyleGroup.Flow
|
|
492
|
+
});
|
|
493
|
+
};
|
|
442
494
|
const mappingNode = new YamlMapping({
|
|
443
|
-
children: children.flat().filter(c => c !== null),
|
|
495
|
+
children: children.flat().filter(c => c !== null).map(toPair),
|
|
444
496
|
...toPositionProps(info),
|
|
445
497
|
anchor,
|
|
446
498
|
tag,
|
|
@@ -559,8 +611,30 @@ const createTransformers = transformerMap => ({
|
|
|
559
611
|
const tag = toYamlTag(info, siblings.tag);
|
|
560
612
|
const anchor = siblings.anchor ? toYamlAnchor(siblings.anchor) : undefined;
|
|
561
613
|
const children = processChildren(cursor, ctx, transformerMap);
|
|
614
|
+
|
|
615
|
+
// a single pair as a flow sequence entry (e.g. [a: 1]) is a mapping with that one pair
|
|
616
|
+
// (YAML 1.2 §7.4.1); the CST has the flow_pair directly in the flow_sequence
|
|
617
|
+
const toSinglePairMapping = child => {
|
|
618
|
+
if (!isKeyValuePair(child)) return child;
|
|
619
|
+
const mappingNode = new YamlMapping({
|
|
620
|
+
children: [child],
|
|
621
|
+
startLine: child.startLine,
|
|
622
|
+
startCharacter: child.startCharacter,
|
|
623
|
+
startOffset: child.startOffset,
|
|
624
|
+
endLine: child.endLine,
|
|
625
|
+
endCharacter: child.endCharacter,
|
|
626
|
+
endOffset: child.endOffset,
|
|
627
|
+
tag: new YamlTag({
|
|
628
|
+
explicitName: '!',
|
|
629
|
+
kind: YamlNodeKind.Mapping
|
|
630
|
+
}),
|
|
631
|
+
styleGroup: YamlStyleGroup.Flow,
|
|
632
|
+
style: YamlStyle.SinglePair
|
|
633
|
+
});
|
|
634
|
+
return ctx.schema.resolve(mappingNode);
|
|
635
|
+
};
|
|
562
636
|
const sequenceNode = new YamlSequence({
|
|
563
|
-
children: children.flat().filter(c => c !== null),
|
|
637
|
+
children: children.flat().filter(c => c !== null).map(toSinglePairMapping),
|
|
564
638
|
...toPositionProps(info),
|
|
565
639
|
anchor,
|
|
566
640
|
tag,
|
|
@@ -623,15 +697,44 @@ const createTransformers = transformerMap => ({
|
|
|
623
697
|
const tag = toYamlTag(info, siblings.tag);
|
|
624
698
|
const anchor = siblings.anchor ? toYamlAnchor(siblings.anchor) : undefined;
|
|
625
699
|
const style = info.text.startsWith('|') ? YamlStyle.Literal : info.text.startsWith('>') ? YamlStyle.Folded : YamlStyle.Plain;
|
|
700
|
+
|
|
701
|
+
// trailing lines belong to the block scalar, but the CST node ends at its last content
|
|
702
|
+
// character when another node follows; the lines up to the line of the next node in
|
|
703
|
+
// source order are taken from the text of the node holding both
|
|
704
|
+
let trailingLines = '';
|
|
705
|
+
if (!info.text.endsWith('\n')) {
|
|
706
|
+
// a cursor copy walks up in constant time per step, unlike Node#parent
|
|
707
|
+
const following = copyCursor(cursor);
|
|
708
|
+
let hasNext = following.gotoNextSibling();
|
|
709
|
+
while (!hasNext && following.gotoParent()) {
|
|
710
|
+
hasNext = following.gotoNextSibling();
|
|
711
|
+
}
|
|
712
|
+
// without a next node the scalar ends the input, so there are no lines to add
|
|
713
|
+
if (hasNext) {
|
|
714
|
+
const nextIndex = following.startIndex;
|
|
715
|
+
following.gotoParent();
|
|
716
|
+
const gap = following.nodeText.slice(info.endIndex - following.startIndex, nextIndex - following.startIndex);
|
|
717
|
+
trailingLines = gap.slice(0, gap.lastIndexOf('\n') + 1);
|
|
718
|
+
}
|
|
719
|
+
following.delete();
|
|
720
|
+
}
|
|
721
|
+
|
|
722
|
+
// an explicit indentation indicator is relative to the parent node's indentation: the
|
|
723
|
+
// column of the mapping pair or sequence item holding the block node (0 at top level);
|
|
724
|
+
// content lines are rebased to it so that the indicator can be applied to them as is
|
|
725
|
+
const holder = cursor.currentNode.parent?.parent;
|
|
726
|
+
const parentIndentation = holder?.type === 'block_mapping_pair' || holder?.type === 'block_sequence_item' ? holder.startPosition.column : 0;
|
|
727
|
+
const rebased = (info.text + trailingLines).replace(new RegExp(`\n {0,${parentIndentation}}`, 'g'), '\n');
|
|
626
728
|
const scalarNode = new YamlScalar({
|
|
627
|
-
content:
|
|
729
|
+
content: rebased,
|
|
628
730
|
anchor,
|
|
629
731
|
tag,
|
|
630
732
|
...toPositionProps(info),
|
|
631
733
|
styleGroup: YamlStyleGroup.Block,
|
|
632
734
|
style
|
|
633
735
|
});
|
|
634
|
-
|
|
736
|
+
// the block's source text, rebased to its parent's indentation and with its trailing lines
|
|
737
|
+
scalarNode.rawContent = rebased;
|
|
635
738
|
registerAnchor(scalarNode, ctx);
|
|
636
739
|
return ctx.schema.resolve(scalarNode);
|
|
637
740
|
},
|
|
@@ -645,7 +748,8 @@ const createTransformers = transformerMap => ({
|
|
|
645
748
|
alias(cursor, ctx) {
|
|
646
749
|
const info = getCursorInfo(cursor);
|
|
647
750
|
const alias = new YamlAlias({
|
|
648
|
-
content: info.text
|
|
751
|
+
content: info.text,
|
|
752
|
+
...toPositionProps(info)
|
|
649
753
|
});
|
|
650
754
|
return ctx.referenceManager.resolveAlias(alias);
|
|
651
755
|
},
|
|
@@ -134,7 +134,13 @@ const applyComments = (elements, comments) => {
|
|
|
134
134
|
const detectFlowPadding = node => {
|
|
135
135
|
const firstChild = (node.children || [])[0];
|
|
136
136
|
if (firstChild && typeof node.startCharacter === 'number' && typeof firstChild.startCharacter === 'number') {
|
|
137
|
-
|
|
137
|
+
// a sequence item starts with its tag or anchor, which aren't part of its node's position
|
|
138
|
+
const {
|
|
139
|
+
tag,
|
|
140
|
+
anchor
|
|
141
|
+
} = firstChild;
|
|
142
|
+
const firstStart = Math.min(firstChild.startCharacter, tag?.startCharacter ?? Infinity, anchor?.startCharacter ?? Infinity);
|
|
143
|
+
return firstStart - node.startCharacter > 1;
|
|
138
144
|
}
|
|
139
145
|
return true;
|
|
140
146
|
};
|
|
@@ -148,12 +154,25 @@ const buildYamlStyle = (node, ctx, extras) => {
|
|
|
148
154
|
if (ctx.flowCollectionPadding !== null) {
|
|
149
155
|
yamlStyle.flowCollectionPadding = ctx.flowCollectionPadding;
|
|
150
156
|
}
|
|
157
|
+
if (ctx.indentSeq !== null) {
|
|
158
|
+
yamlStyle.indentSeq = ctx.indentSeq;
|
|
159
|
+
}
|
|
151
160
|
if (node.comment) {
|
|
152
161
|
yamlStyle.comment = node.comment;
|
|
153
162
|
}
|
|
154
163
|
if (node.commentBefore) {
|
|
155
164
|
yamlStyle.commentBefore = node.commentBefore;
|
|
156
165
|
}
|
|
166
|
+
// an untagged node has the non-specific tag '?' when it's a plain scalar and '!' otherwise
|
|
167
|
+
// (YAML 1.2 §6.9.1); an explicit '!' on any other node means the same as no tag
|
|
168
|
+
const tag = node.tag?.explicitName;
|
|
169
|
+
if (tag !== undefined && tag !== (node.style === _YamlStyle.YamlStyle.Plain ? '?' : '!')) {
|
|
170
|
+
yamlStyle.tag = tag;
|
|
171
|
+
}
|
|
172
|
+
// the anchor's name, without the & indicator
|
|
173
|
+
if (node.anchor) {
|
|
174
|
+
yamlStyle.anchor = node.anchor.name.slice(1);
|
|
175
|
+
}
|
|
157
176
|
if (extras) {
|
|
158
177
|
for (const [key, value] of Object.entries(extras)) {
|
|
159
178
|
if (value !== undefined) yamlStyle[key] = value;
|
|
@@ -247,13 +266,35 @@ const transformChildren = (children, ctx) => {
|
|
|
247
266
|
|
|
248
267
|
// stream comments that precede the first document, joined; null when there are none
|
|
249
268
|
// (stream children are in source order, so everything before the document node qualifies)
|
|
250
|
-
|
|
251
|
-
|
|
269
|
+
// stream comments around the first document: before it, on its last line and on the lines after it,
|
|
270
|
+
// up to the next document
|
|
271
|
+
const collectStreamComments = node => {
|
|
272
|
+
const comments = {
|
|
273
|
+
before: [],
|
|
274
|
+
inline: [],
|
|
275
|
+
after: []
|
|
276
|
+
};
|
|
277
|
+
let root;
|
|
278
|
+
const collect = comment => {
|
|
279
|
+
const text = stripCommentHash(comment.content);
|
|
280
|
+
if (!root) comments.before.push(text);else if (comment.startLine === root.endLine) comments.inline.push(text);else comments.after.push(text);
|
|
281
|
+
};
|
|
252
282
|
for (const child of node.children) {
|
|
253
|
-
if ((0, _predicates.isDocument)(child))
|
|
254
|
-
|
|
283
|
+
if ((0, _predicates.isDocument)(child)) {
|
|
284
|
+
if (root) break;
|
|
285
|
+
// comments after an explicit document start (---) or before an explicit document end (...)
|
|
286
|
+
// are the document's own children, around its root node
|
|
287
|
+
const children = child.children || [];
|
|
288
|
+
const rootIndex = children.findIndex(c => !(0, _predicates.isComment)(c));
|
|
289
|
+
if (rootIndex === -1) break;
|
|
290
|
+
children.slice(0, rootIndex).filter(_predicates.isComment).forEach(collect);
|
|
291
|
+
root = children[rootIndex];
|
|
292
|
+
children.slice(rootIndex + 1).filter(_predicates.isComment).forEach(collect);
|
|
293
|
+
} else if ((0, _predicates.isComment)(child)) {
|
|
294
|
+
collect(child);
|
|
295
|
+
}
|
|
255
296
|
}
|
|
256
|
-
return
|
|
297
|
+
return comments;
|
|
257
298
|
};
|
|
258
299
|
|
|
259
300
|
// Stream: Wraps transformed children in ParseResultElement
|
|
@@ -278,13 +319,32 @@ const transformStream = (node, ctx) => {
|
|
|
278
319
|
const resultElement = elements[0];
|
|
279
320
|
resultElement.classes.push('result');
|
|
280
321
|
|
|
281
|
-
// stream comments before the first document belong above the result element
|
|
282
|
-
// capture them
|
|
322
|
+
// stream comments before the first document belong above the result element, ones on its last
|
|
323
|
+
// line to it and ones on later lines to the document; capture them so style round-trips can
|
|
324
|
+
// re-emit them
|
|
283
325
|
if (ctx.style) {
|
|
284
|
-
const
|
|
285
|
-
|
|
326
|
+
const {
|
|
327
|
+
before,
|
|
328
|
+
inline,
|
|
329
|
+
after
|
|
330
|
+
} = collectStreamComments(node);
|
|
331
|
+
if (before.length > 0) {
|
|
286
332
|
const existing = getYamlStyleProp(resultElement, 'commentBefore');
|
|
287
|
-
|
|
333
|
+
const text = before.join('\n');
|
|
334
|
+
setYamlStyleProp(resultElement, 'commentBefore', typeof existing === 'string' ? `${text}\n${existing}` : text);
|
|
335
|
+
}
|
|
336
|
+
if (inline.length > 0 && typeof getYamlStyleProp(resultElement, 'comment') !== 'string') {
|
|
337
|
+
setYamlStyleProp(resultElement, 'comment', inline.join('\n'));
|
|
338
|
+
}
|
|
339
|
+
// comments promoted out of the root's last nested collection have no next sibling to precede
|
|
340
|
+
// and end the root, so they come before the stream comments after it
|
|
341
|
+
after.unshift(...ctx.promotedComments);
|
|
342
|
+
if (after.length > 0) {
|
|
343
|
+
setYamlStyleProp(resultElement, 'documentComment', after.join('\n'));
|
|
344
|
+
}
|
|
345
|
+
// line breaks other than LF, which the YAML library writes
|
|
346
|
+
if (node.lineBreak === '\r\n') {
|
|
347
|
+
setYamlStyleProp(resultElement, 'lineBreak', node.lineBreak);
|
|
288
348
|
}
|
|
289
349
|
}
|
|
290
350
|
}
|
|
@@ -331,7 +391,9 @@ const transformCollection = (element, node, ctx) => {
|
|
|
331
391
|
element._content = childElements; // eslint-disable-line @typescript-eslint/no-explicit-any
|
|
332
392
|
applyComments(childElements, comments);
|
|
333
393
|
element.style = buildYamlStyle(node, ctx, {
|
|
334
|
-
comment: comments.trailing
|
|
394
|
+
comment: comments.trailing,
|
|
395
|
+
// a single pair written directly in a flow sequence (e.g. [a: 1])
|
|
396
|
+
singlePair: node.style === _YamlStyle.YamlStyle.SinglePair || undefined
|
|
335
397
|
});
|
|
336
398
|
if (comments.outOfScope.length > 0) {
|
|
337
399
|
ctx.promotedComments.push(...comments.outOfScope);
|
|
@@ -352,12 +414,24 @@ const transformMapping = (node, ctx) => {
|
|
|
352
414
|
// KeyValuePair: Transforms to MemberElement
|
|
353
415
|
const transformKeyValuePair = (node, ctx) => {
|
|
354
416
|
const element = new _apidomDatamodel.MemberElement();
|
|
417
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
418
|
+
const {
|
|
419
|
+
key,
|
|
420
|
+
value
|
|
421
|
+
} = node;
|
|
422
|
+
if (ctx.style && ctx.indentSeq === null && value?.type === 'sequence') {
|
|
423
|
+
const {
|
|
424
|
+
styleGroup,
|
|
425
|
+
startCharacter
|
|
426
|
+
} = value;
|
|
427
|
+
if (styleGroup === _YamlStyle.YamlStyleGroup.Block) {
|
|
428
|
+
ctx.indentSeq = startCharacter > node.startCharacter;
|
|
429
|
+
}
|
|
430
|
+
}
|
|
355
431
|
|
|
356
432
|
// Transform key and value (these are dynamically defined properties)
|
|
357
|
-
|
|
358
|
-
const
|
|
359
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
360
|
-
const valueResult = transform(node.value, ctx);
|
|
433
|
+
const keyResult = transform(key, ctx);
|
|
434
|
+
const valueResult = transform(value, ctx);
|
|
361
435
|
|
|
362
436
|
// @ts-ignore
|
|
363
437
|
element.content.key = keyResult;
|
|
@@ -387,8 +461,11 @@ const transformSequence = (node, ctx) => {
|
|
|
387
461
|
const transformScalar = (node, ctx) => {
|
|
388
462
|
const element = ctx.namespace.toElement(node.content);
|
|
389
463
|
|
|
390
|
-
// Translate style information about empty nodes
|
|
391
|
-
|
|
464
|
+
// Translate style information about empty nodes; an empty node (YAML 1.2 §7.2) is a null unless
|
|
465
|
+
// a tag other than the null tag makes it something else (e.g. !!str makes it an empty string)
|
|
466
|
+
const tag = node.tag?.explicitName;
|
|
467
|
+
const isEmptyNode = node.content === '' && node.style === _YamlStyle.YamlStyle.Plain && [undefined, '?', '!!null', '!<tag:yaml.org,2002:null>'].includes(tag);
|
|
468
|
+
if (isEmptyNode) {
|
|
392
469
|
element.classes.push('yaml-e-node');
|
|
393
470
|
element.classes.push('yaml-e-scalar');
|
|
394
471
|
}
|
|
@@ -399,6 +476,9 @@ const transformScalar = (node, ctx) => {
|
|
|
399
476
|
if (node.rawContent !== undefined) {
|
|
400
477
|
extras.rawContent = node.rawContent;
|
|
401
478
|
}
|
|
479
|
+
if (node.alias !== undefined) {
|
|
480
|
+
extras.alias = node.alias;
|
|
481
|
+
}
|
|
402
482
|
element.style = buildYamlStyle(node, ctx, extras);
|
|
403
483
|
}
|
|
404
484
|
maybeAddSourceMap(node, element, ctx);
|
|
@@ -476,6 +556,7 @@ const transformYamlAstToApiDOM = (yamlAst, {
|
|
|
476
556
|
processedDocumentCount: 0,
|
|
477
557
|
indent: 2,
|
|
478
558
|
flowCollectionPadding: null,
|
|
559
|
+
indentSeq: null,
|
|
479
560
|
promotedComments: []
|
|
480
561
|
};
|
|
481
562
|
const rootNode = yamlAst.rootNode;
|