Skip to content

Add Yaml.stringify and Yaml.stringifyAll - #10272

Closed
effect-bot wants to merge 10 commits into
agent/nelson-effect-bot/eff-3232-stage5-core-tagsfrom
agent/architect-effect-bot/6a52aa9988ae
Closed

effect-bot wants to merge 10 commits into
agent/nelson-effect-bot/eff-3232-stage5-core-tagsfrom
agent/architect-effect-bot/6a52aa9988ae

Conversation

@effect-bot

@effect-bot effect-bot commented Nov 1, 2026 •

Copy link
Copy Markdown
Contributor

Adds a value-oriented YAML printer to effect/encoding/Yaml, stage 2 of the YAML expansion plan.

API

Yaml.stringify(value: unknown, options?: { readonly indent?: number | undefined }): Result<string, EncodingError>
Yaml.stringifyAll(values: Iterable<unknown>, options?: { readonly indent?: number | undefined }): Result<string, EncodingError>

Contract

  • null, booleans, numbers, strings, arrays, and plain objects. Block style, insertion-order keys, {} and [] for empty collections, output ends in one newline.
  • A string prints plain only when parse and the YAML 1.2 core schema both read it back as the same string; otherwise it is double-quoted with YAML escapes. Keys follow the same rule, so "true": and "1": stay strings.
  • Multiline strings print as |, |-, or |+ literal block scalars when no line has surrounding whitespace or control characters; otherwise double-quoted.
  • .inf, -.inf, .nan, and -0.0 round-trip, including the sign of zero.
  • Like JSON.stringify: toJSON is applied first, undefined properties are omitted, undefined items print null, symbol keys are ignored.
  • Unlike JSON.stringify, nothing is silently dropped or turned into {}: bigints, functions, symbols, objects with a non-plain prototype and no toJSON, and cycles fail with an EncodingError whose message names the path (value.items[0], value[1].id in a stream).
  • Nested sequences print in the two-line form (- then an indented - item) because the current parser does not read - - item; shared references print inline each time, no anchors.

Integration with the parser stack

The printer commits were written on v4/next-minor before the parser stages landed. The last commit on this branch merges them into the stage 5 head (#10285), so this PR's diff shows the printer as it fits on the finished parser. The merge had two conflicts, both from the two sides adding code next to each other:

  • The Yaml.ts module header and the end of the file keep the parser stack's text, then add the printer code. The printer branch's older parse definition was dropped because the parser stack already has the current one.
  • The Yaml.test.ts stringify tests follow the parser tests.

Validation

  • vitest packages/effect/test/encoding/Yaml.test.ts: 195 passed (35 new printer tests, committed in the tests-first run, plus the existing 160).
  • Every printer output in the test file is also checked against the yaml 2.9.1 reference parser, added as a devDependency of packages/effect for that purpose.
  • Ad hoc: 49 representative values at indents 1, 2, and 4 round-trip through Yaml.parse unchanged.
  • tsc for packages/effect, oxlint, dprint, pnpm jsdocs --check, doctests for the module, and pnpm circular all pass.

Stack

These PRs form one stack. Each targets the PR before it, so its diff shows only its own stage. Merge them in this order:

  1. Add Yaml.parseAll and return Result from Yaml.parse #10271: Yaml.parseAll and Result from Yaml.parse (merged)
  2. Reject Yaml tags and explicit keys, resolve alias keys, and keep non-space white space #10276: parser hardening, based on v4/next-minor
  3. Parse Yaml compact nested sequences and multiline quoted flow scalars #10279: compact nested sequences and multiline quoted flow scalars, based on Reject Yaml tags and explicit keys, resolve alias keys, and keep non-space white space #10276
  4. Treat a tab after a Yaml sequence dash as separation #10282: tab after a sequence dash, based on Parse Yaml compact nested sequences and multiline quoted flow scalars #10279
  5. Accept escaped literal tabs in Yaml double-quoted scalars #10283: escaped literal tabs, based on Treat a tab after a Yaml sequence dash as separation #10282
  6. Reject Yaml flow plain scalars starting with a dash and separation #10284: flow plain scalars starting with a dash, based on Accept escaped literal tabs in Yaml double-quoted scalars #10283
  7. Resolve Yaml core schema tags #10285: core schema tags, based on Reject Yaml flow plain scalars starting with a dash and separation #10284
  8. Add Yaml.stringify and Yaml.stringifyAll #10272: Yaml.stringify and Yaml.stringifyAll, based on Resolve Yaml core schema tags #10285 (this PR)
  9. Harden and extend Yaml parsing and add Yaml.stringify #10287: printer round-trip through Yaml.parse, based on Add Yaml.stringify and Yaml.stringifyAll #10272

After a PR in the stack is squash-merged, the next one has to be rebased onto the squash commit and retargeted to v4/next-minor before it can merge.

Closes EFF-3232

@changeset-bot

changeset-bot Bot commented Nov 1, 2026 •

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: 3b465fb

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 33 packages
Name Type
effect Minor
@effect/opentelemetry Minor
@effect/vitest Minor
@effect/ai-anthropic Minor
@effect/ai-cloudflare Minor
@effect/ai-openai-compat Minor
@effect/ai-openai Minor
@effect/ai-openrouter Minor
@effect/ai-typesafe Minor
@effect/atom-react Minor
@effect/atom-solid Minor
@effect/atom-vue Minor
@effect/platform-browser Minor
@effect/platform-bun Minor
@effect/platform-deno Minor
@effect/platform-node-shared Minor
@effect/platform-node Minor
@effect/sql-clickhouse Minor
@effect/sql-d1 Minor
@effect/sql-libsql Minor
@effect/sql-mssql Minor
@effect/sql-mysql2 Minor
@effect/sql-pg Minor
@effect/sql-pglite Minor
@effect/sql-sqlite-bun Minor
@effect/sql-sqlite-do Minor
@effect/sql-sqlite-node Minor
@effect/sql-sqlite-react-native Minor
@effect/sql-sqlite-wasm Minor
@effect/docgen Minor
@effect/doctest Minor
@effect/graphql-generator Minor
@effect/openapi-generator Minor

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@effect-bot
effect-bot changed the base branch from main to v4/next-minor November 1, 2026 23:19
@github-actions

github-actions Bot commented Nov 1, 2026 •

Copy link
Copy Markdown
Contributor

Bundle Size Analysis

Generated from PR build output; treat the content below as untrusted.

File Name Current Size Previous Size Difference
arbitrary-combinators.ts 39.41 KB 39.41 KB 0.00 KB (0.00%)
basic.ts 7.23 KB 7.23 KB 0.00 KB (0.00%)
batching.ts 11.08 KB 11.08 KB 0.00 KB (0.00%)
brand.ts 6.87 KB 6.87 KB 0.00 KB (0.00%)
cache.ts 11.54 KB 11.54 KB 0.00 KB (0.00%)
config.ts 22.84 KB 22.84 KB 0.00 KB (0.00%)
differ.ts 22.00 KB 22.00 KB 0.00 KB (0.00%)
http-client.ts 27.12 KB 27.12 KB 0.00 KB (0.00%)
http-router.ts 37.04 KB 37.04 KB 0.00 KB (0.00%)
logger.ts 12.01 KB 12.01 KB 0.00 KB (0.00%)
metric.ts 9.47 KB 9.47 KB 0.00 KB (0.00%)
optic.ts 7.10 KB 7.10 KB 0.00 KB (0.00%)
pubsub.ts 16.02 KB 16.02 KB 0.00 KB (0.00%)
queue.ts 12.89 KB 12.89 KB 0.00 KB (0.00%)
schedule.ts 11.80 KB 11.80 KB 0.00 KB (0.00%)
schema-bigdecimal.ts 14.14 KB 14.14 KB 0.00 KB (0.00%)
schema-binary.ts 41.99 KB 41.99 KB 0.00 KB (0.00%)
schema-class.ts 21.73 KB 21.73 KB 0.00 KB (0.00%)
schema-fromJsonSchemaDocument.ts 29.60 KB 29.60 KB 0.00 KB (0.00%)
schema-representation-roundtrip.ts 27.99 KB 27.99 KB 0.00 KB (0.00%)
schema-string-transformation.ts 15.35 KB 15.35 KB 0.00 KB (0.00%)
schema-string.ts 12.34 KB 12.34 KB 0.00 KB (0.00%)
schema-template-literal.ts 16.27 KB 16.27 KB 0.00 KB (0.00%)
schema-toArbitrary.ts 38.95 KB 38.95 KB 0.00 KB (0.00%)
schema-toCodeDocument.ts 26.15 KB 26.15 KB 0.00 KB (0.00%)
schema-toCodecJson.ts 20.90 KB 20.90 KB 0.00 KB (0.00%)
schema-toEquivalence.ts 21.05 KB 21.05 KB 0.00 KB (0.00%)
schema-toFormatter.ts 21.14 KB 21.14 KB 0.00 KB (0.00%)
schema-toJsonSchemaDocument.ts 26.17 KB 26.17 KB 0.00 KB (0.00%)
schema-toRepresentation.ts 21.23 KB 21.23 KB 0.00 KB (0.00%)
schema.ts 20.82 KB 20.82 KB 0.00 KB (0.00%)
stm.ts 14.20 KB 14.20 KB 0.00 KB (0.00%)
stream.ts 10.38 KB 10.38 KB 0.00 KB (0.00%)

@effect-bot
effect-bot force-pushed the agent/architect-effect-bot/6a52aa9988ae branch from 8521c14 to a57986d Compare November 1, 2026 23:46
@effect-bot
effect-bot force-pushed the v4/next-minor branch 7 times, most recently from 97a1ee1 to 10d44ad Compare November 3, 2026 22:52
@effect-bot
effect-bot force-pushed the agent/architect-effect-bot/6a52aa9988ae branch from 8943cbc to dc389f2 Compare November 3, 2026 23:14
@effect-bot
effect-bot changed the base branch from v4/next-minor to agent/nelson-effect-bot/eff-3232-stage5-core-tags November 3, 2026 23:40
@effect-bot
effect-bot changed the base branch from agent/nelson-effect-bot/eff-3232-stage5-core-tags to v4/next-minor November 3, 2026 23:40
@effect-bot
effect-bot changed the base branch from v4/next-minor to agent/nelson-effect-bot/eff-3232-stage5-core-tags November 3, 2026 23:42
Tests-first run for stage 2 of EFF-3232. Specifies the value-oriented
printer contract: Result<string, EncodingError>, re-parse based quoting,
literal block scalars, non-finite numbers, undefined/toJSON handling,
indent option, document streams, and path-carrying errors for cycles and
unsupported values. Adds yaml as a dev-only oracle for packages/effect.
Value-oriented YAML printer returning Result<string, EncodingError>.
Strings print plain only when parse reads them back unchanged, multiline
strings use literal block scalars, toJSON/undefined follow JSON.stringify,
and bigints, functions, symbols, non-plain objects, and cycles fail with
the path of the offending value.
Merge key quoting, sparse array positions, non-printable character
escaping, and the 1024-character implicit key limit.
Quote the merge key in key position, keep sparse array positions, escape
every non-printable character before choosing plain or block style, and
fail for keys longer than the 1024-character implicit key limit.
Iterate double-quoted output by code point instead of tracking surrogate
pairs by hand, check block scalar lines with trim, derive the prototype
name with optional chaining, and share one Result wrapper between
stringify and stringifyAll.
…ings

Non-iterable stream inputs must fail, and an unsupported prototype with a
non-string constructor name must still report the offending path.
@effect-bot
effect-bot force-pushed the agent/nelson-effect-bot/eff-3232-stage5-core-tags branch from 7f10be2 to 3dfbaab Compare November 3, 2026 23:43
@effect-bot
effect-bot force-pushed the agent/architect-effect-bot/6a52aa9988ae branch from 7a672f9 to 3b465fb Compare November 3, 2026 23:43
@effect-bot

Copy link
Copy Markdown
Contributor Author

Superseded by #10287, which now holds the rest of the YAML expansion as one PR against v4/next-minor. This PR's commits are included there unchanged.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant