@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.
Files changed (40) hide show
  1. package/README.md +78 -7
  2. package/Yaml.js +87 -39
  3. package/YamlDocument.js +25 -6
  4. package/YamlFormat.js +171 -20
  5. package/YamlLint.js +239 -0
  6. package/YamlLintRule.js +36 -0
  7. package/YamlNode.js +36 -2
  8. package/YamlToken.js +139 -0
  9. package/YamlVisitor.js +40 -5
  10. package/index.d.ts +439 -12
  11. package/index.js +4 -1
  12. package/internal/composer/anchors.js +2 -27
  13. package/internal/composer/block.js +246 -58
  14. package/internal/composer/comments.js +187 -0
  15. package/internal/composer/document.js +49 -12
  16. package/internal/composer/flow.js +82 -9
  17. package/internal/composer/scalars.js +77 -28
  18. package/internal/composer/state.js +16 -2
  19. package/internal/cst-parser.js +11 -2
  20. package/internal/diagnostics.js +12 -3
  21. package/internal/fold.js +22 -10
  22. package/internal/lexer.js +23 -17
  23. package/internal/rules/catalog.js +39 -0
  24. package/internal/rules/colon-spacing.js +77 -0
  25. package/internal/rules/comments-spacing.js +68 -0
  26. package/internal/rules/document-end.js +65 -0
  27. package/internal/rules/document-start.js +64 -0
  28. package/internal/rules/empty-lines.js +70 -0
  29. package/internal/rules/eof-newline.js +33 -0
  30. package/internal/rules/hyphen-spacing.js +52 -0
  31. package/internal/rules/indentation.js +103 -0
  32. package/internal/rules/key-duplicates.js +49 -0
  33. package/internal/rules/line-length.js +36 -0
  34. package/internal/rules/parse-validity.js +33 -0
  35. package/internal/rules/quoted-strings.js +81 -0
  36. package/internal/rules/trailing-spaces.js +39 -0
  37. package/internal/rules/truthy.js +84 -0
  38. package/internal/rules/util.js +92 -0
  39. package/internal/stringifier.js +285 -69
  40. 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,