FS FormScript
Package@formscript/conformance
Specification17.2, 18, 18.1, 18.2, 18.3, 18.4, 18.5
Depends onanalyzer, ast, decimal, engine, errors, evaluator, lexer, parser, types

@formscript/conformance

The conformance suite of the FormScript Language Specification 1.0.0 , §18 — and the runner that executes it.

§18 is not a description of a suite; it is the suite, written in the specification. This package extracts those rows from the specification text and runs them against the reference implementation, so the claim "the suite is executed, not asserted" is a fact with a test result behind it.

The five sections

Section What it checks How
§18.1 Documents that must parse The lexer and the parser produce no diagnostic
§18.2 Documents that must be rejected The reported set contains the expected code
§18.3 Evaluation semantics The value and the static type
§18.4 Documents that must compile The lexer, the parser and the analyzer are all clean
§18.5 The §17.2 flagship document One output document, end to end

Two rows that are easy to get wrong

§18.3 distinguishes result type from result value. The row 1 + 1 → 2 and the row 1 + 1.0 → 2.0 have the same value and different types. The runner therefore compares the value with strictEquals and the static type with the analyzer's inferType. A runner that only checked the value would pass a runtime that computed integers where decimals were required.

§18.5 asserts the keys that must be absent. The flagship's output document omits an inapplicable entity, so the expected result names postcode, guarantor.guarantor_name and guarantor.guarantor_consent as absent (Spec-4.35). A runtime that emitted an inapplicable field as null would fail this row.

The flagship's inputs are raw text

FLAGSHIP_ASSIGNMENTS assigns '30000', not 30000. The engine rejects a JavaScript double for a number field, which is correct for a decimal data plane: the input of a form is text, and Spec-5.3 governs its coercion.

Public API

ts
const suite = readSuite('FormScript-Language-Specification.md');
const report = runSuite(suite);

report.passed;    // 101
report.failed;    // 0
report.totals;    // { '18.1': { passed: 46, failed: 0 }, ... }
report.failures;  // one entry per failing row

Also exported: extractSuite, parseEvaluationTable, parseRejectTable, splitDocuments, diagnose, reportedDiagnostics, literalValue, runEvaluationCase, runFlagship, flattenOutput, FLAGSHIP_ASSIGNMENTS, FLAGSHIP_OUTPUT, FLAGSHIP_ABSENT_KEYS and FLAGSHIP_OUTPUT_KEYS.

Running it

bash
npm run conformance
# or, through the command line, with the same output:
npm run formscript -- conformance

The runner reports each section, then the failures with the expected and the actual result, and exits non-zero if any row failed.

Judgement calls

  1. The rows are read from the specification, not duplicated here. A row added to §18.3 of the specification is picked up by the next run; there is no second copy to keep in step.
  2. §18.2 checks that the expected code is among the reported codes, not that it is the only one. The specification's rows each isolate a defect, but a document that also trips an unrelated rule still demonstrates the behaviour the row claims to test.
  3. The stage order of Spec-2.5 is applied to the §18.2 rows. The reported set is the errors of the earliest non-empty stage plus every warning, so a lexical error is not masked by a semantic one further down.
  4. The §18.5 fixture is the §17.2 document verbatim. It is extracted from the specification, so the flagship that is tested is the flagship that is published.

Public API

33 exported symbols.

asDocument re-export
ConformanceFailure interface
ConformanceReport interface
ConformanceSuite interface
diagnose re-export
EvaluationBinding interface

A name bound to an absence, as the §18.3 rows declare them.

EvaluationCase interface
EvaluationExpectation type
EvaluationOutcome interface
extractSuite re-export
FLAGSHIP_ABSENT_KEYS const

The output keys that must be **absent**: their entity is inapplicable, so they were never asked (Spec-4.35).

FLAGSHIP_ASSIGNMENTS const

The input sequence the fixture is run with, as the raw text a user would type.

FLAGSHIP_OUTPUT const

The output document the fixture must produce. A `number` is carried as its canonical decimal text (Spec-4.36); an applicable but unanswered field is an expli…

FLAGSHIP_OUTPUT_KEYS const

The keys the §17.2 `output` block declares.

FlagshipOutcome interface
flattenOutput function

Flattens a nested output document into dotted keys (Spec-4.35).

isPrimaryDiagnostic function

Spec-18.2/Spec-18.3: the stated code must be the first error reported for the row, not merely one of them. "First" means the first diagnostic of the stage-fi…

literalValue function

The value a §18.3 literal denotes.

MustParseCase interface
MustRejectCase interface
parseDiagnostics function

The lexical and syntactic diagnostics only — what §18.1 constrains.

parseEvaluationTable re-export
parseRejectTable re-export
readSuite re-export
reportedDiagnostics re-export
runEvaluationCase function

Runs one §18.3 row.

runFlagship function

Runs the flagship document through the pipeline of §18.5.

runMustReject re-export
runSuite re-export
sectionBody function

The body of a section, up to the next heading of any level. Stopping only at `## ` would swallow every `### ` subsection that follows, and a table from the n…

splitCells function

Splits a markdown table row into its cells. A pipe inside a code span is part of the cell, not a delimiter — the row `value = 1 || 2` has four pipes in it an…

splitDocuments re-export
UnreadableRow interface