@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
@@ -0,0 +1,84 @@
1
+ import { YamlEdit } from "../../YamlEdit.js";
2
+ import { YamlLintDiagnostic, YamlLintSeverity } from "../../YamlLintRule.js";
3
+ import { positionAt, walkScalars } from "./util.js";
4
+ import { Schema } from "effect";
5
+
6
+ //#region src/internal/rules/truthy.ts
7
+ /**
8
+ * Options for `truthy`: the `allowed` boolean spellings (default
9
+ * `["true", "false"]`) and whether mapping keys are checked (`checkKeys`,
10
+ * default `true` — the workflow `on:` key is the point).
11
+ */
12
+ const truthyOptions = Schema.Struct({
13
+ severity: Schema.optionalKey(YamlLintSeverity),
14
+ allowed: Schema.optionalKey(Schema.Array(Schema.String)),
15
+ checkKeys: Schema.optionalKey(Schema.Boolean)
16
+ });
17
+ /** The YAML 1.1 boolean family, per spelling case the 1.1 grammar admits. */
18
+ const TRUTHY = /* @__PURE__ */ new Set([
19
+ "yes",
20
+ "Yes",
21
+ "YES",
22
+ "no",
23
+ "No",
24
+ "NO",
25
+ "on",
26
+ "On",
27
+ "ON",
28
+ "off",
29
+ "Off",
30
+ "OFF",
31
+ "true",
32
+ "True",
33
+ "TRUE",
34
+ "false",
35
+ "False",
36
+ "FALSE"
37
+ ]);
38
+ const TRUE_SET = /* @__PURE__ */ new Set([
39
+ "yes",
40
+ "on",
41
+ "true"
42
+ ]);
43
+ /** YAML 1.1 truthy spellings outside the allowed list. */
44
+ const truthy = {
45
+ id: "truthy",
46
+ check: (ctx, options) => {
47
+ const opts = options ?? {};
48
+ const allowed = new Set(opts.allowed ?? ["true", "false"]);
49
+ const checkKeys = opts.checkKeys ?? true;
50
+ const out = [];
51
+ walkScalars(ctx.document.contents, "root", (scalar, role) => {
52
+ if (role === "key" && !checkKeys) return;
53
+ if (scalar.style !== "plain" || scalar.tag !== void 0) return;
54
+ const raw = ctx.text.slice(scalar.offset, scalar.offset + scalar.length);
55
+ if (!TRUTHY.has(raw) || allowed.has(raw)) return;
56
+ const pos = positionAt(ctx.lines, scalar.offset);
57
+ const isBool = typeof scalar.value === "boolean";
58
+ const respell = TRUE_SET.has(raw.toLowerCase()) ? "true" : "false";
59
+ const fix = isBool ? allowed.has(respell) ? YamlEdit.make({
60
+ offset: scalar.offset,
61
+ length: scalar.length,
62
+ content: respell
63
+ }) : void 0 : YamlEdit.make({
64
+ offset: scalar.offset,
65
+ length: scalar.length,
66
+ content: `"${raw}"`
67
+ });
68
+ out.push(new YamlLintDiagnostic({
69
+ rule: "truthy",
70
+ severity: "error",
71
+ message: `Truthy value "${raw}" is not in the allowed spellings`,
72
+ offset: scalar.offset,
73
+ length: scalar.length,
74
+ line: pos.line,
75
+ character: pos.character,
76
+ ...fix !== void 0 ? { fix } : {}
77
+ }));
78
+ });
79
+ return out;
80
+ }
81
+ };
82
+
83
+ //#endregion
84
+ export { truthy, truthyOptions };
@@ -0,0 +1,92 @@
1
+ import { YamlMap, YamlScalar, YamlSeq } from "../../YamlNode.js";
2
+ import { Schema } from "effect";
3
+
4
+ //#region src/internal/rules/util.ts
5
+ /**
6
+ * A non-negative integer — the shape every numeric rule option takes.
7
+ * Rejects NaN, negatives and fractions with a message naming the constraint;
8
+ * the config layer's wrapper names the rule and the field.
9
+ */
10
+ const nonNegativeIntegerOption = Schema.Number.check(Schema.makeFilter((n) => Number.isInteger(n) && n >= 0 ? void 0 : "Expected a non-negative integer"));
11
+ /**
12
+ * A positive integer — for the `maxSpacesAfter` options, where `0` would make
13
+ * the fix delete the separation space after an indicator and fuse it with its
14
+ * content (`- item` → `-item`, `a: val` → `a:val` — different tokens, not a
15
+ * spacing change).
16
+ */
17
+ const positiveIntegerOption = Schema.Number.check(Schema.makeFilter((n) => Number.isInteger(n) && n >= 1 ? void 0 : "Expected an integer greater than or equal to 1"));
18
+ /** Depth-first walk over every scalar node with its structural role. */
19
+ function walkScalars(node, role, visit) {
20
+ if (node === null) return;
21
+ if (node instanceof YamlScalar) {
22
+ visit(node, role);
23
+ return;
24
+ }
25
+ if (node instanceof YamlMap) {
26
+ for (const pair of node.items) {
27
+ walkScalars(pair.key, "key", visit);
28
+ walkScalars(pair.value, "value", visit);
29
+ }
30
+ return;
31
+ }
32
+ if (node instanceof YamlSeq) for (const item of node.items) walkScalars(item, "item", visit);
33
+ }
34
+ /**
35
+ * True when the first content of a line is the CONTINUATION of a scalar
36
+ * token that began on an earlier line — block-scalar bodies and multi-line
37
+ * plain/quoted scalars. The indentation rule skips such lines: their layout
38
+ * is the value's, not block structure's.
39
+ */
40
+ function isScalarContinuationLine(tokens, lineOffset, probeOffset) {
41
+ const token = coveringToken(tokens, probeOffset);
42
+ return token !== void 0 && token.kind === "scalar" && token.offset < lineOffset;
43
+ }
44
+ /** The token whose span covers `offset`, when one does. */
45
+ function coveringToken(tokens, offset) {
46
+ let lo = 0;
47
+ let hi = tokens.length - 1;
48
+ while (lo <= hi) {
49
+ const mid = lo + hi >> 1;
50
+ const token = tokens[mid];
51
+ if (offset < token.offset) hi = mid - 1;
52
+ else if (offset >= token.offset + token.length) lo = mid + 1;
53
+ else return token;
54
+ }
55
+ }
56
+ /**
57
+ * True when `offset` falls inside a scalar token's span. Layout rules use
58
+ * this to stay off scalar CONTENT — trailing whitespace or blank lines
59
+ * inside a block scalar are part of the parsed value, and a lint layer that
60
+ * edits content under the banner of layout is corrupting, not fixing.
61
+ */
62
+ function insideScalarSpan(tokens, offset) {
63
+ return coveringToken(tokens, offset)?.kind === "scalar";
64
+ }
65
+ /**
66
+ * The line containing `offset` and the character index within it — a binary
67
+ * search over the ordered `LintLine` array (lines are ordered by `offset`,
68
+ * the same invariant {@link coveringToken} rests on for tokens).
69
+ */
70
+ function positionAt(lines, offset) {
71
+ let lo = 0;
72
+ let hi = lines.length - 1;
73
+ let found;
74
+ while (lo <= hi) {
75
+ const mid = lo + hi >> 1;
76
+ const line = lines[mid];
77
+ if (line.offset <= offset) {
78
+ found = line;
79
+ lo = mid + 1;
80
+ } else hi = mid - 1;
81
+ }
82
+ return found === void 0 ? {
83
+ line: 0,
84
+ character: 0
85
+ } : {
86
+ line: found.number,
87
+ character: offset - found.offset
88
+ };
89
+ }
90
+
91
+ //#endregion
92
+ export { coveringToken, insideScalarSpan, isScalarContinuationLine, nonNegativeIntegerOption, positionAt, positiveIntegerOption, walkScalars };