Files
inline-schema/docs/syntax-rework-plan.md
T
hypercross c969c7f6fc refactor: enforce mandatory brackets for composite values
Implements Phase 1 and 2 of the syntax rework plan:
- Brackets `[]` are now mandatory for all tuple and array values.
- Removed the `[Type][]` array syntax; arrays now only use `Type[]`.
- `[single]` is now strictly a 1-tuple rather than an array.
- Updated documentation and test fixtures to reflect these breaking
  changes.
2026-08-06 09:19:39 +08:00

5.5 KiB
Raw Blame History

Implementation Plan: Syntax Clarity & Parser Robustness

Status: In progress — Phases 1 & 2 applied (Phases 36 not yet done)

Goals

  1. Eliminate the backtracking heuristics in the value parser by making the value grammar context-free.
  2. Remove redundant/ambiguous syntax forms.
  3. Make union resolution deterministic and structural (not error-message-driven).
  4. Address the csv-parse quote conflict.
  5. Keep the ; separator (forced by CSV constraints — not the source of ambiguity).

All changes are breaking to the DSL → bump to 2.0.0, update README + csv-loader.md, add a migration note.


Phase 1 — Mandatory brackets for composite values Applied

Files: src/value-parser.ts, src/index.test.ts, src/csv-loader/reference-resolver.ts

  • Removed the allowOmitBrackets parameter from parseValue, parseTupleValue, parseArrayValue.
  • Deleted the elementIsTupleOrArray disambiguation block and all savedPos restore logic in parseArrayValue.
  • Dropped the allowOmitBrackets = schema.type === "tuple" || "array" special case in top-level parseValue — brackets are always required.
  • Array references (@table[] values) now also require brackets, for consistency.
  • Values must now be fully bracketed: [a; 1]; [b; 2] (no more [a; 1]; [b; 2] without outer brackets).

Decision: Full mandatory brackets (no carve-out).


Phase 2 — Single array form Type[] Applied

Files: src/parser.ts, src/index.test.ts

  • Removed the [Type][] array syntax from parseSchemaInternal. Kept only Type[].
  • [string] is now a 1-tuple (previously it collapsed to an array). The tuple branch always returns { type: "tuple", elements }.
  • Updated schemaToTypeString in src/type-utils.ts — the array case no longer special-cases tuple elements; arrays are always elementType[] (kept the (union)[] paren wrapping).

Tests updated: index.test.ts bracket-optional tests, encounter.csv / enemy_intents.csv fixtures, and parseCsv-typeDeclarations.test.ts array-of-tuple values.


Phase 3 — Deterministic union resolution

Files: src/csv-loader/reference-resolver.ts, src/validator.ts (via type-utils.ts), src/csv-loader/module-gen.ts

  • Rule: In a union, always try non-reference members before reference members, regardless of author order. This makes fallback structural instead of error-message-driven.
  • In parseValueWithReferences and resolveNestedReferences, replace the /not found|Circular reference|Failed to load/ error-message inspection with a fixed ordering: partition members into nonRef / ref, try nonRef first, then ref.
  • In module-gen.ts generateSchemaResolutionCode union case, apply the same ordering so generated code matches runtime behavior.
  • Document the rule in README (union member ordering is currently "first match wins" per AGENTS.md).

Note: This changes behavior for @users[] | stringstring would now win for plain strings. Flag as a deliberate semantic change.


Phase 4 — Quote conflict resolution

Files: src/parser.ts, src/csv-loader/loader.ts, README, csv-loader.md

Options (pick one):

  • (a) Standardize on single-quoted literals only — minimal change, but leaves a footgun.
  • (b) Quote the entire schema cell so csv-parse treats it as one field — requires loader-side handling to strip the outer quotes before parsing.
  • (c) Drop quotes entirely — use bare-token literals (e.g. on / off as identifiers). Most robust, largest change.

Recommendation: (b) — it's the only option that fixes the root cause (schema cells containing " break csv-parse) without redesigning the literal syntax. Requires: in loader.ts, detect schema-row cells that are fully quoted and unwrap before parseSchema.


Phase 5 — Cleanup & consistency

Files: src/csv-loader/reference-resolver.ts, src/csv-loader/loader.ts, src/csv-loader/module-gen.ts

  • Reverse-reference performance: resolveReverseReference does refTable.filter(...) per row. Build a Map<fk, rows[]> lookup once per referenced table (mirroring what module-gen.ts already generates) and reuse it. Cache the lookup alongside the parsed table in referenceTableCache.
  • Remove the , stop-character in parseReferenceValue (value parser has a , stop char the schema parser doesn't — drift). Make reference ID parsing consistent with the rest of the value grammar.
  • int/float/numbernumber: document the collapse in README (type-level collapse is intentional; parse-time distinction remains).

Phase 6 — Docs & migration

Files: README.md, csv-loader.md, AGENTS.md

  • Update all syntax tables and examples for mandatory brackets + single array form.
  • Add a Migration section listing the breaking changes:
    1. Composite values must be fully bracketed.
    2. [Type][] array form removed — use Type[].
    3. [single] is now a 1-tuple, not an array.
    4. Union resolution now prefers non-reference members.
    5. (If Phase 4b) schema cells may be fully quoted.
  • Update AGENTS.md gotchas: union ordering rule, quote handling.

Validation

  • npm run typecheck
  • npm run test (update src/index.test.ts, src/csv-loader/*.test.ts first)
  • Manually verify the integration fixture (user_rev.csv / order_rev.csv) still resolves.

Suggested execution order

Phases 1 → 2 are tightly coupled (both touch bracket parsing) — do them together. Phase 3 is independent. Phase 4 is independent. Phases 56 are cleanup/docs and can go last.