@effected/yaml 0.6.1 → 0.8.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 +78 -7
- package/Yaml.js +87 -39
- package/YamlDocument.js +25 -6
- package/YamlFormat.js +171 -20
- package/YamlLint.js +239 -0
- package/YamlLintRule.js +36 -0
- package/YamlNode.js +36 -2
- package/YamlToken.js +139 -0
- package/YamlVisitor.js +40 -5
- package/index.d.ts +439 -12
- package/index.js +4 -1
- package/internal/composer/anchors.js +2 -27
- package/internal/composer/block.js +246 -58
- package/internal/composer/comments.js +187 -0
- package/internal/composer/document.js +49 -12
- package/internal/composer/flow.js +82 -9
- package/internal/composer/scalars.js +77 -28
- package/internal/composer/state.js +16 -2
- package/internal/cst-parser.js +11 -2
- package/internal/diagnostics.js +12 -3
- package/internal/fold.js +22 -10
- package/internal/lexer.js +23 -17
- package/internal/rules/catalog.js +39 -0
- package/internal/rules/colon-spacing.js +77 -0
- package/internal/rules/comments-spacing.js +68 -0
- package/internal/rules/document-end.js +65 -0
- package/internal/rules/document-start.js +64 -0
- package/internal/rules/empty-lines.js +70 -0
- package/internal/rules/eof-newline.js +33 -0
- package/internal/rules/hyphen-spacing.js +52 -0
- package/internal/rules/indentation.js +103 -0
- package/internal/rules/key-duplicates.js +49 -0
- package/internal/rules/line-length.js +36 -0
- package/internal/rules/parse-validity.js +33 -0
- package/internal/rules/quoted-strings.js +81 -0
- package/internal/rules/trailing-spaces.js +39 -0
- package/internal/rules/truthy.js +84 -0
- package/internal/rules/util.js +92 -0
- package/internal/stringifier.js +285 -69
- package/package.json +4 -3
package/YamlToken.js
ADDED
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
import { lexAll } from "./internal/lexer.js";
|
|
2
|
+
import { Result, Schema, Stream } from "effect";
|
|
3
|
+
|
|
4
|
+
//#region src/YamlToken.ts
|
|
5
|
+
/**
|
|
6
|
+
* The 22 lexical token kinds produced by the YAML tokenizer.
|
|
7
|
+
*
|
|
8
|
+
* @public
|
|
9
|
+
*/
|
|
10
|
+
const YamlTokenKind = Schema.Literals([
|
|
11
|
+
"document-start",
|
|
12
|
+
"document-end",
|
|
13
|
+
"directive",
|
|
14
|
+
"tag",
|
|
15
|
+
"anchor",
|
|
16
|
+
"alias",
|
|
17
|
+
"scalar",
|
|
18
|
+
"block-map-start",
|
|
19
|
+
"block-map-key",
|
|
20
|
+
"block-map-value",
|
|
21
|
+
"block-seq-start",
|
|
22
|
+
"block-seq-entry",
|
|
23
|
+
"flow-map-start",
|
|
24
|
+
"flow-map-end",
|
|
25
|
+
"flow-seq-start",
|
|
26
|
+
"flow-seq-end",
|
|
27
|
+
"flow-separator",
|
|
28
|
+
"newline",
|
|
29
|
+
"whitespace",
|
|
30
|
+
"comment",
|
|
31
|
+
"byte-order-mark",
|
|
32
|
+
"error"
|
|
33
|
+
]);
|
|
34
|
+
/**
|
|
35
|
+
* A single positioned YAML lexical token.
|
|
36
|
+
*
|
|
37
|
+
* - `kind` — the {@link (YamlTokenKind:type)}.
|
|
38
|
+
* - `text` — the raw source slice the token covers; the position-fidelity
|
|
39
|
+
* invariant is `source.slice(offset, offset + length) === text`.
|
|
40
|
+
* - `offset` / `length` — the token's span in UTF-16 code units.
|
|
41
|
+
* - `line` / `character` — the zero-based position of the token's start,
|
|
42
|
+
* matching the `YamlDiagnostic` position vocabulary.
|
|
43
|
+
*
|
|
44
|
+
* @public
|
|
45
|
+
*/
|
|
46
|
+
var YamlToken = class extends Schema.Class("YamlToken")({
|
|
47
|
+
kind: YamlTokenKind,
|
|
48
|
+
text: Schema.String,
|
|
49
|
+
offset: Schema.Number,
|
|
50
|
+
length: Schema.Number,
|
|
51
|
+
line: Schema.Number,
|
|
52
|
+
character: Schema.Number
|
|
53
|
+
}) {};
|
|
54
|
+
/**
|
|
55
|
+
* Promote the internal lexer tokens to the public shape.
|
|
56
|
+
*
|
|
57
|
+
* `line`/`character` are DERIVED from each token's offset against a
|
|
58
|
+
* line-start index rather than copied from the internal token: the internal
|
|
59
|
+
* `column` is a CST-parser vocabulary that carries the construct's INDENT on
|
|
60
|
+
* the synthetic `block-map-start`/`block-seq-start` markers, not the token's
|
|
61
|
+
* own position — the public surface promises the position. `text` is the RAW
|
|
62
|
+
* source slice for the same reason: the internal `value` is the PROCESSED
|
|
63
|
+
* form on quoted scalars (content without the quotes), while the public
|
|
64
|
+
* contract is byte fidelity — the corpus conformance suite pins the tokens
|
|
65
|
+
* tiling the source exactly.
|
|
66
|
+
*/
|
|
67
|
+
const promoteAll = (text, tokens) => {
|
|
68
|
+
const lineStarts = [0];
|
|
69
|
+
for (let i = 0; i < text.length; i++) if (text[i] === "\n") lineStarts.push(i + 1);
|
|
70
|
+
let line = 0;
|
|
71
|
+
return tokens.map((token) => {
|
|
72
|
+
if (token.offset < lineStarts[line]) line = 0;
|
|
73
|
+
while (line + 1 < lineStarts.length && lineStarts[line + 1] <= token.offset) line++;
|
|
74
|
+
return new YamlToken({
|
|
75
|
+
kind: token.kind,
|
|
76
|
+
text: text.slice(token.offset, token.offset + token.length),
|
|
77
|
+
offset: token.offset,
|
|
78
|
+
length: token.length,
|
|
79
|
+
line,
|
|
80
|
+
character: token.offset - lineStarts[line]
|
|
81
|
+
});
|
|
82
|
+
});
|
|
83
|
+
};
|
|
84
|
+
/**
|
|
85
|
+
* Tokenizer statics. Not instantiable.
|
|
86
|
+
*
|
|
87
|
+
* @public
|
|
88
|
+
*/
|
|
89
|
+
var YamlTokens = class YamlTokens {
|
|
90
|
+
constructor() {}
|
|
91
|
+
/**
|
|
92
|
+
* Tokenize YAML text into the full positioned token array — the sync
|
|
93
|
+
* `Result` primitive (tokenizing is a pure batch transform; the
|
|
94
|
+
* {@link YamlTokens.stream} form is derived from this one, per the kit's
|
|
95
|
+
* sync-primitive policy).
|
|
96
|
+
*
|
|
97
|
+
* @remarks
|
|
98
|
+
* The failure channel is **reserved** (for future input-hardening guards)
|
|
99
|
+
* and never fires today: the lexer is total, and lexical errors surface as
|
|
100
|
+
* `"error"`-kind tokens **in the success array** so that linting can run
|
|
101
|
+
* on malformed input — the `parse-validity` lint rule exists precisely for
|
|
102
|
+
* documents that do not parse. Do not "fix" this method to fail on
|
|
103
|
+
* `"error"` tokens; that would make malformed documents unlintable.
|
|
104
|
+
*
|
|
105
|
+
* @example
|
|
106
|
+
* ```ts
|
|
107
|
+
* import { YamlTokens } from "@effected/yaml";
|
|
108
|
+
* import { Result } from "effect";
|
|
109
|
+
*
|
|
110
|
+
* const result = YamlTokens.tokenize("a: 1\n");
|
|
111
|
+
* if (Result.isSuccess(result)) {
|
|
112
|
+
* result.success.map((t) => t.kind); // ["scalar", "block-map-start", ...]
|
|
113
|
+
* }
|
|
114
|
+
* ```
|
|
115
|
+
*/
|
|
116
|
+
static tokenize(text) {
|
|
117
|
+
return Result.succeed(promoteAll(text, lexAll(text)));
|
|
118
|
+
}
|
|
119
|
+
/**
|
|
120
|
+
* Tokenize YAML text as a lazy `Stream` of tokens — the derived form of
|
|
121
|
+
* {@link YamlTokens.tokenize} for genuinely incremental (SAX-style)
|
|
122
|
+
* consumers, parallel to `YamlVisitor.visit`.
|
|
123
|
+
*
|
|
124
|
+
* @remarks
|
|
125
|
+
* Derived from the sync primitive, so it shares its contract: lexical
|
|
126
|
+
* errors arrive as `"error"`-kind tokens in the stream, never as a stream
|
|
127
|
+
* failure. (The primitive's reserved failure channel would surface as a
|
|
128
|
+
* defect here; it never fires today.)
|
|
129
|
+
*/
|
|
130
|
+
static stream(text) {
|
|
131
|
+
return Stream.suspend(() => Result.match(YamlTokens.tokenize(text), {
|
|
132
|
+
onSuccess: (tokens) => Stream.fromIterable(tokens),
|
|
133
|
+
onFailure: (error) => Stream.die(error)
|
|
134
|
+
}));
|
|
135
|
+
}
|
|
136
|
+
};
|
|
137
|
+
|
|
138
|
+
//#endregion
|
|
139
|
+
export { YamlToken, YamlTokenKind, YamlTokens };
|
package/YamlVisitor.js
CHANGED
|
@@ -79,9 +79,16 @@ function* walkDocument(doc, text) {
|
|
|
79
79
|
if (doc.comment !== void 0) yield YamlVisitorEvent.Comment({
|
|
80
80
|
path,
|
|
81
81
|
depth,
|
|
82
|
-
text: doc.comment
|
|
82
|
+
text: doc.comment,
|
|
83
|
+
placement: "leading"
|
|
83
84
|
});
|
|
84
85
|
if (doc.contents !== null) yield* walkNode(doc.contents, path, depth);
|
|
86
|
+
if (doc.commentAfter !== void 0) yield YamlVisitorEvent.Comment({
|
|
87
|
+
path,
|
|
88
|
+
depth,
|
|
89
|
+
text: doc.commentAfter,
|
|
90
|
+
placement: "trailing"
|
|
91
|
+
});
|
|
85
92
|
yield YamlVisitorEvent.DocumentEnd({
|
|
86
93
|
path,
|
|
87
94
|
depth
|
|
@@ -89,10 +96,17 @@ function* walkDocument(doc, text) {
|
|
|
89
96
|
}
|
|
90
97
|
function* walkNode(node, path, depth) {
|
|
91
98
|
if (node instanceof YamlScalar) {
|
|
99
|
+
if (node.commentBefore !== void 0) yield YamlVisitorEvent.Comment({
|
|
100
|
+
path,
|
|
101
|
+
depth,
|
|
102
|
+
text: node.commentBefore,
|
|
103
|
+
placement: "leading"
|
|
104
|
+
});
|
|
92
105
|
if (node.comment !== void 0) yield YamlVisitorEvent.Comment({
|
|
93
106
|
path,
|
|
94
107
|
depth,
|
|
95
|
-
text: node.comment
|
|
108
|
+
text: node.comment,
|
|
109
|
+
placement: "trailing"
|
|
96
110
|
});
|
|
97
111
|
yield YamlVisitorEvent.Scalar({
|
|
98
112
|
path,
|
|
@@ -108,10 +122,17 @@ function* walkNode(node, path, depth) {
|
|
|
108
122
|
name: node.name
|
|
109
123
|
});
|
|
110
124
|
else if (node instanceof YamlMap) {
|
|
125
|
+
if (node.commentBefore !== void 0) yield YamlVisitorEvent.Comment({
|
|
126
|
+
path,
|
|
127
|
+
depth,
|
|
128
|
+
text: node.commentBefore,
|
|
129
|
+
placement: "leading"
|
|
130
|
+
});
|
|
111
131
|
if (node.comment !== void 0) yield YamlVisitorEvent.Comment({
|
|
112
132
|
path,
|
|
113
133
|
depth,
|
|
114
|
-
text: node.comment
|
|
134
|
+
text: node.comment,
|
|
135
|
+
placement: "trailing"
|
|
115
136
|
});
|
|
116
137
|
yield YamlVisitorEvent.MapStart({
|
|
117
138
|
path,
|
|
@@ -126,10 +147,17 @@ function* walkNode(node, path, depth) {
|
|
|
126
147
|
depth
|
|
127
148
|
});
|
|
128
149
|
} else if (node instanceof YamlSeq) {
|
|
150
|
+
if (node.commentBefore !== void 0) yield YamlVisitorEvent.Comment({
|
|
151
|
+
path,
|
|
152
|
+
depth,
|
|
153
|
+
text: node.commentBefore,
|
|
154
|
+
placement: "leading"
|
|
155
|
+
});
|
|
129
156
|
if (node.comment !== void 0) yield YamlVisitorEvent.Comment({
|
|
130
157
|
path,
|
|
131
158
|
depth,
|
|
132
|
-
text: node.comment
|
|
159
|
+
text: node.comment,
|
|
160
|
+
placement: "trailing"
|
|
133
161
|
});
|
|
134
162
|
yield YamlVisitorEvent.SeqStart({
|
|
135
163
|
path,
|
|
@@ -153,10 +181,17 @@ function* walkPair(pair, parentPath, depth) {
|
|
|
153
181
|
const resolvedValue = pair.value instanceof YamlScalar ? pair.value.value : null;
|
|
154
182
|
const keySegment = typeof resolvedKey === "string" ? resolvedKey : typeof resolvedKey === "number" ? resolvedKey : String(resolvedKey);
|
|
155
183
|
const pairPath = [...parentPath, keySegment];
|
|
184
|
+
if (pair.commentBefore !== void 0) yield YamlVisitorEvent.Comment({
|
|
185
|
+
path: pairPath,
|
|
186
|
+
depth,
|
|
187
|
+
text: pair.commentBefore,
|
|
188
|
+
placement: "leading"
|
|
189
|
+
});
|
|
156
190
|
if (pair.comment !== void 0) yield YamlVisitorEvent.Comment({
|
|
157
191
|
path: pairPath,
|
|
158
192
|
depth,
|
|
159
|
-
text: pair.comment
|
|
193
|
+
text: pair.comment,
|
|
194
|
+
placement: "trailing"
|
|
160
195
|
});
|
|
161
196
|
yield YamlVisitorEvent.Pair({
|
|
162
197
|
path: pairPath,
|