lawspec 0.9.0 → 0.11.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 (46) hide show
  1. package/API-MIGRATION.md +78 -2
  2. package/HASKELL.md +1 -0
  3. package/KOTLIN.md +5 -0
  4. package/LANGUAGE.md +70 -11
  5. package/NATIVE-BINDINGS.md +1049 -0
  6. package/PRIMITIVES.md +1 -1
  7. package/README.md +86 -23
  8. package/REFINEMENTS.md +6 -1
  9. package/RELEASE-0.10.md +60 -0
  10. package/RELEASE-0.11.md +62 -0
  11. package/api.mjs +23 -3
  12. package/bin/lawspec.mjs +17 -4
  13. package/build.json +60 -38
  14. package/core.wasm +0 -0
  15. package/examples/native-payments/go/example/payments/domain.go +38 -0
  16. package/examples/native-payments/go/example/payments/native_generators_test.go +13 -0
  17. package/examples/native-payments/go/lawspec.json +136 -0
  18. package/examples/native-payments/haskell/lawspec.json +149 -0
  19. package/examples/native-payments/haskell/src/PaymentsDomain.hs +21 -0
  20. package/examples/native-payments/haskell/test/PaymentGenerators.hs +12 -0
  21. package/examples/native-payments/java/lawspec.json +165 -0
  22. package/examples/native-payments/java/src/main/java/domain/PaymentsDomain.java +32 -0
  23. package/examples/native-payments/java/src/test/java/domain/PaymentGenerators.java +16 -0
  24. package/examples/native-payments/javascript/lawspec.json +149 -0
  25. package/examples/native-payments/javascript/src/payments_domain.mjs +44 -0
  26. package/examples/native-payments/javascript/test/lawspec_generators.mjs +6 -0
  27. package/examples/native-payments/kotlin/lawspec.json +165 -0
  28. package/examples/native-payments/kotlin/src/main/kotlin/domain/PaymentsDomain.kt +17 -0
  29. package/examples/native-payments/kotlin/src/test/kotlin/domain/PaymentGenerators.kt +12 -0
  30. package/examples/native-payments/python/lawspec.json +149 -0
  31. package/examples/native-payments/python/src/payments_domain.py +60 -0
  32. package/examples/native-payments/python/tests/lawspec_generators.py +15 -0
  33. package/examples/native-payments/rust/lawspec.json +167 -0
  34. package/examples/native-payments/rust/src/domain.rs +37 -0
  35. package/examples/native-payments/rust/src/lib.rs +2 -0
  36. package/examples/native-payments/rust/tests/support/lawspec_generators.rs +11 -0
  37. package/examples/native-payments/typescript/lawspec.json +149 -0
  38. package/examples/native-payments/typescript/src/payments_domain.ts +42 -0
  39. package/examples/native-payments/typescript/test/lawspec_generators.ts +8 -0
  40. package/examples/specs/indexed_families.lawspec +59 -0
  41. package/examples/specs/payments.lawspec +76 -0
  42. package/examples-command.mjs +5 -0
  43. package/files.mjs +6 -6
  44. package/index.d.ts +53 -2
  45. package/native-examples.mjs +81 -0
  46. package/package.json +2 -2
package/PRIMITIVES.md CHANGED
@@ -1,4 +1,4 @@
1
- # LawSpec scalar reference (0.9.0)
1
+ # LawSpec scalar reference (0.11.0)
2
2
 
3
3
  A scalar has a declared domain, checked literals, equality, property inputs, and
4
4
  boundary fixtures. General collections, objects, pointers, and type-only constructs
package/README.md CHANGED
@@ -2,7 +2,7 @@
2
2
 
3
3
  **State the law once. Check it everywhere.**
4
4
 
5
- LawSpec 0.9 compiles reusable laws into native property tests, executable examples,
5
+ LawSpec 0.11 compiles reusable laws into native property tests, executable examples,
6
6
  and implementation adapters. The compiler is Haskell, distributed as prebuilt
7
7
  WebAssembly with a Node CLI and an asynchronous, typed JavaScript API.
8
8
 
@@ -36,12 +36,40 @@ Compiler API consumers should read the [schema v3 migration guide](API-MIGRATION
36
36
  Scalar values use tagged, lossless encodings; generated runtime placement is
37
37
  separate from artifact ownership. Java 25+ and Python 3.13+ baselines are unchanged.
38
38
 
39
+ ## Native domain bindings in 0.10
40
+
41
+ LawSpec 0.10 adds configuration for existing application products and sums,
42
+ function bindings, checked conversion hooks, and native property-generator
43
+ factories on all eight targets. Generators retain their framework's shrinkers;
44
+ explicit examples, boundaries, and finite-domain checks remain independent.
45
+ See the [native-binding reference and acceptance status](NATIVE-BINDINGS.md),
46
+ the [release notes](RELEASE-0.10.md), and
47
+ [schema 4 migration notes](API-MIGRATION.md#schema-4-native-bindings).
48
+ Existing specifications without bindings retain their behavior.
49
+
50
+ ## Natural-indexed families in 0.11
51
+
52
+ LawSpec 0.11 adds data indexed by natural numbers, such as length-indexed
53
+ vectors and size-indexed trees. Each constructor states its index equation;
54
+ the compiler elaborates the family to ordinary native data, a checked measure,
55
+ and a refinement. Dependent signatures like
56
+ `append :: (xs :: Vec n a) -> (ys :: Vec m a) -> (r :: Vec (n + m) a)` become
57
+ checked adapter contracts, and generators construct values with a required
58
+ index instead of filtering for it. See the
59
+ [language reference](LANGUAGE.md#natural-indexed-families), the
60
+ [indexed example](examples/specs/indexed_families.lawspec), and the
61
+ [release notes](RELEASE-0.11.md).
62
+
39
63
  ## Install and try it
40
64
 
65
+ LawSpec has its own [syntax-highlighting grammar and VS Code extension](editors/vscode/README.md)
66
+ for keywords, types, refinements, literals, and law names. GitHub needs upstream Linguist
67
+ support to use it; GitHub currently uses the Haskell fallback.
68
+
41
69
  Install [LawSpec from npm](https://www.npmjs.com/package/lawspec):
42
70
 
43
71
  ```sh
44
- npm install --save-dev lawspec@0.9.0
72
+ npm install --save-dev lawspec@0.11.0
45
73
  npx lawspec --version
46
74
  ```
47
75
 
@@ -55,8 +83,8 @@ local dependencies so LawSpec can create its `package.json` and test script:
55
83
  ```sh
56
84
  mkdir lawspec-example
57
85
  cd lawspec-example
58
- npm exec --package=lawspec@0.9.0 -- lawspec init --target javascript
59
- npm install --save-dev lawspec@0.9.0
86
+ npm exec --package=lawspec@0.11.0 -- lawspec init --target javascript
87
+ npm install --save-dev lawspec@0.11.0
60
88
  npx lawspec check
61
89
  npx lawspec explain 'example.atoi_codec::itoa and then atoi yields a'
62
90
  npx lawspec doctor
@@ -192,11 +220,13 @@ Reusable laws can declare typed unary function parameters and `requires Eq a`, n
192
220
  [parameterized refinements and executable contracts](REFINEMENTS.md).
193
221
  Definitions support law application, function application/composition, universal
194
222
  quantification, `implies`, Boolean predicates, scalar literals, and equality.
195
- Function signatures and quantified inputs support the [scalar catalog](PRIMITIVES.md),
196
- including mixed and multiple inputs. Generic variables are supported in reusable
197
- laws. Scalar types can also be intermediate or compared results. Functions are synchronous and support curried signatures with any positive
198
- number of scalar arguments. Text literals are double-quoted, with escapes such as `\"`, `\\`,
199
- `\n`, and `\t`; examples must bind each input to a literal of its declared type.
223
+ Function signatures and quantified inputs support the [scalar catalog](PRIMITIVES.md)
224
+ and [structural types](LANGUAGE.md), including mixed and multiple inputs.
225
+ Generic variables are supported in reusable laws. Scalar and structural values
226
+ can also be intermediate or compared results. Functions are synchronous and
227
+ support curried signatures with any positive number of arguments. Text literals
228
+ are double-quoted, with escapes such as `\"`, `\\`, `\n`, and `\t`; examples must
229
+ bind each input to a concrete value of its declared type.
200
230
  Text values contain Unicode scalar values; surrogate code points are rejected.
201
231
 
202
232
  Examples refer to the expanded input names, including names inherited from the
@@ -206,9 +236,10 @@ produce literal braces. Law blocks use this order:
206
236
  definition, optional description, optional rationale, examples, optional references.
207
237
  `--` starts a line comment. Names that cannot be emitted portably are diagnosed.
208
238
 
209
- General collections, external law packages, cross-unit imports beyond the
210
- prelude, async functions, direct existing-symbol binding and browser hosting are
211
- outside this release.
239
+ Collections beyond `List`, external law packages, cross-unit imports beyond the
240
+ prelude, async functions and browser hosting remain outside the language.
241
+ Direct existing-symbol bindings are part of LawSpec 0.10 described
242
+ above; the published 0.9 release uses implementation adapters.
212
243
 
213
244
  ## Algebra and currying (0.6)
214
245
 
@@ -263,7 +294,7 @@ reusable laws accept these curried functions, their partial applications, and
263
294
  scalar parameters. Quantified test inputs remain scalar.
264
295
 
265
296
  The prelude defines the following laws. Every row has an executable example in
266
- [algebra.lawspec](https://github.com/brain-fuel/lawspec/blob/v0.9.0/examples/specs/algebra.lawspec), including both sides of every
297
+ [algebra.lawspec](https://github.com/brain-fuel/lawspec/blob/v0.11.0/examples/specs/algebra.lawspec), including both sides of every
267
298
  combined law. `f` and `g` are binary operations, `inverse` is unary, and `e` and
268
299
  `zero` are scalar parameters. All these laws require equality of the element type.
269
300
 
@@ -331,7 +362,7 @@ their entire consequence. Every conjunct is type-checked and emitted. As with
331
362
  existing assertions, the first failure stops that individual test. `and` is now
332
363
  a reserved word.
333
364
 
334
- [Currying examples](https://github.com/brain-fuel/lawspec/blob/v0.9.0/examples/specs/currying.lawspec) demonstrate a four-argument
365
+ [Currying examples](https://github.com/brain-fuel/lawspec/blob/v0.11.0/examples/specs/currying.lawspec) demonstrate a four-argument
335
366
  function partially applied twice, a formatter with four heterogeneous arguments,
336
367
  and composition after partial application. Each example states its exact outputs.
337
368
  Run `node npm/bin/lawspec.mjs examples` after rebuilding to inspect all nine units
@@ -383,7 +414,7 @@ law `valid ports round trip` is
383
414
  end
384
415
  ```
385
416
 
386
- The [complete port example](https://github.com/brain-fuel/lawspec/blob/v0.9.0/examples/specs/parse_port.lawspec)
417
+ The [complete port example](https://github.com/brain-fuel/lawspec/blob/v0.11.0/examples/specs/parse_port.lawspec)
387
418
  defines valid ports as 1–65535, and covers both endpoints, ordinary ports, zero,
388
419
  negative values, and 65536. All explicit `expect` assertions run regardless of
389
420
  the law's condition. A false condition skips only the consequence: invalid ports
@@ -401,7 +432,7 @@ The prelude includes `satisfies predicate` (the predicate holds for every input)
401
432
  and `left inverse when predicate parse render` (the guarded round trip above).
402
433
  These reusable laws preserve the condition and its lexical bindings when expanded.
403
434
  `equivalent` can also compare two predicates, since `Bool` supports equality.
404
- The [Boolean flags example](https://github.com/brain-fuel/lawspec/blob/v0.9.0/examples/specs/boolean_flags.lawspec)
435
+ The [Boolean flags example](https://github.com/brain-fuel/lawspec/blob/v0.11.0/examples/specs/boolean_flags.lawspec)
405
436
  checks that flipping twice restores both `false` and `true`; all targets generate
406
437
  Boolean property inputs and explicit tests for both Boolean boundary values. Java caps Boolean-only JetCheck runs at the number of
407
438
  possible input combinations (up to 100), avoiding generator exhaustion.
@@ -480,7 +511,7 @@ This expands to `for all (x :: Int32) . render (x) = referenceRender (x)`.
480
511
  The example inherits the input name `x` from the prelude. Both functions are
481
512
  user-owned adapter functions; either may delegate to your existing code.
482
513
 
483
- [The complete example](https://github.com/brain-fuel/lawspec/blob/v0.9.0/examples/specs/equivalent.lawspec) compares decimal
514
+ [The complete example](https://github.com/brain-fuel/lawspec/blob/v0.11.0/examples/specs/equivalent.lawspec) compares decimal
484
515
  renderers and two implementations that clamp negative integers to zero. For
485
516
  JavaScript, their adapters can be:
486
517
 
@@ -517,7 +548,7 @@ law `normalizers agree` is
517
548
  end
518
549
  ```
519
550
 
520
- The [slug example](https://github.com/brain-fuel/lawspec/blob/v0.9.0/examples/specs/slug.lawspec)
551
+ The [slug example](https://github.com/brain-fuel/lawspec/blob/v0.11.0/examples/specs/slug.lawspec)
521
552
  compares two implementations of ASCII-space replacement. It includes empty,
522
553
  Unicode and escaped text. Each target uses its native string generator:
523
554
  JetCheck `Generator.stringsOf(Generator.asciiPrintableChars())`, Hypothesis `st.text()`, fast-check `fc.string()`,
@@ -544,7 +575,7 @@ law `canonicalization reaches a fixed point` is
544
575
  end
545
576
  ```
546
577
 
547
- The [canonical URL example](https://github.com/brain-fuel/lawspec/blob/v0.9.0/examples/specs/canonical_url.lawspec)
578
+ The [canonical URL example](https://github.com/brain-fuel/lawspec/blob/v0.11.0/examples/specs/canonical_url.lawspec)
548
579
  uses removal of **all trailing slashes** as a small fixed-point demonstration,
549
580
  not a complete URL canonicalization algorithm. For JavaScript:
550
581
 
@@ -553,13 +584,31 @@ export const canonicalize = value => value.replace(/\/+$/, "");
553
584
  ```
554
585
 
555
586
  Removing just one trailing slash fails the supplied repeated-slash example.
556
- The [mixed-input example](https://github.com/brain-fuel/lawspec/blob/v0.9.0/examples/specs/mixed_inputs.lawspec)
587
+ The [mixed-input example](https://github.com/brain-fuel/lawspec/blob/v0.11.0/examples/specs/mixed_inputs.lawspec)
557
588
  shows `Text` and `Int32` in the same quantified property and executable example.
558
- The JavaScript API represents input bindings and expected values as `number | string | boolean`.
559
- Each example includes `expectations: { actual: Expr; expected: number | string | boolean }[]`.
589
+ The JavaScript API represents example bindings as typed records whose values use
590
+ `DataValue`: lossless tagged scalar payloads or structural constructors. Expected results are
591
+ typed expressions inside `Assertion` trees, not untyped JavaScript primitives.
592
+ See the [API migration guide](API-MIGRATION.md) for their wire representation.
560
593
 
561
594
  ## Generate all example artifacts
562
595
 
596
+ To use native domain bindings, export the runnable payment
597
+ example (omit `--target` to export all eight languages):
598
+
599
+ ```sh
600
+ lawspec examples --example payments --target rust --output native_payments
601
+ cd native_payments/rust
602
+ # Install the dependencies listed in README.md, then:
603
+ lawspec check
604
+ lawspec generate
605
+ cargo test
606
+ ```
607
+
608
+ These projects include application-owned types, native generators, binding
609
+ configuration, and build files. Re-exporting preserves edits and leaves the
610
+ compiler's generation manifest separate from the example export manifest.
611
+
563
612
  ```sh
564
613
  npx lawspec examples
565
614
  # Or select a target and a relative output directory:
@@ -618,7 +667,7 @@ by the JS shim.
618
667
  ## Build and verify
619
668
 
620
669
  For contributors working from a repository checkout, build a local archive with
621
- `npm pack ./npm` and install it with `npm install --save-dev ./lawspec-0.9.0.tgz`.
670
+ `npm pack ./npm` and install it with `npm install --save-dev ./lawspec-0.11.0.tgz`.
622
671
  The package payload lives in `npm/`.
623
672
 
624
673
  ```sh
@@ -657,6 +706,20 @@ unchanged. Arguments select individual targets. `LAWSPEC_PYTHON=3.14` selects th
657
706
  additional Python reference environment. CI also exercises Node 22/24/26 and packs
658
707
  and installs the npm archive. Registry publication is a separate release action.
659
708
 
709
+ The native-binding acceptance command uses the installed npm archive, public CLI,
710
+ and the selected target's normal test command:
711
+
712
+ ```sh
713
+ node tools/native-example-integration.mjs rust
714
+ LAWSPEC_MACHINE_BITS=32 LAWSPEC_MINIFY=1 node tools/native-example-integration.mjs rust
715
+ ```
716
+
717
+ Replace `rust` with any supported target. It exports the payment project, verifies
718
+ correct behavior, rejects an incorrect fee, and checks regeneration. Per-command
719
+ logs live in `.artifacts/native-example-integration/`. See the
720
+ [acceptance reference](NATIVE-BINDINGS.md) for dependency overrides and remaining
721
+ verification gates.
722
+
660
723
 
661
724
  Refinement predicates can depend on earlier inputs. Generated tests backtrack from
662
725
  impossible prefixes, preserve the domain during shrinking, and validate function
package/REFINEMENTS.md CHANGED
@@ -1,4 +1,4 @@
1
- # Refinements and abstract integers (0.9.0)
1
+ # Refinements and abstract integers (0.11.0)
2
2
 
3
3
  A refinement restricts a scalar domain with a pure Boolean expression. LawSpec
4
4
  checks concrete examples, generates satisfying input tuples, and checks adapter
@@ -154,6 +154,11 @@ seeds direct comparison values and boundaries, and checks the complete predicate
154
154
  Predicates outside that analysis use bounded sampling. Small finite base-domain
155
155
  products are enumerated exhaustively, retaining only satisfying tuples.
156
156
 
157
+ A refinement `m x == e` over declared data, where `m` is a linear structural
158
+ measure (each branch is a constant plus `m` of that branch's fields), is solved
159
+ rather than sampled: values are constructed with measure exactly `e`. Indexed
160
+ families rely on this; see [natural-indexed families](LANGUAGE.md#natural-indexed-families).
161
+
157
162
  Shrinking checks refinements again and repairs dependent later inputs when an
158
163
  earlier value changes. An overflowing counterexample can shrink to `(1, 127)`;
159
164
  it cannot shrink to `(0, 127)` because that pair is outside the domain.
@@ -0,0 +1,60 @@
1
+ # LawSpec 0.10.0
2
+
3
+ ## Existing application models
4
+
5
+ Native bindings connect LawSpec products and sums to existing application types
6
+ on Java, Python, JavaScript, TypeScript, Go, Haskell, Kotlin and Rust. Configure
7
+ constructor and field mappings, bind adapter declarations to existing functions,
8
+ or supply paired conversion hooks for representations requiring custom code.
9
+ Bindings resolve against typed declaration identities; they do not change the
10
+ meaning of arithmetic, equality, definitions or refinements.
11
+
12
+ Checked bridges compose through generic and recursive types and the built-in
13
+ containers. They preserve exact numeric values, Symbol identity and distinct
14
+ absence states. Invalid native inputs, results, generator samples and shrink
15
+ candidates fail with context.
16
+
17
+ ## Native generators
18
+
19
+ Factories return their framework's generator: JetCheck, Hypothesis, fast-check,
20
+ Rapid, Hedgehog, Kotest or Proptest. Generic factories receive child generators.
21
+ Composition retains native shrinking. Explicit examples, deterministic boundaries
22
+ and finite-domain enumeration still run when the factory's distribution excludes
23
+ those values.
24
+
25
+ A factory can ignore an uninhabited parameter, as in `Phantom Empty`. Requesting a
26
+ value from that parameter fails generation; it cannot turn a property into a
27
+ vacuous success. Finite inhabited containers such as `List Empty` still enumerate.
28
+
29
+ Optional `stub: true` generator bindings create user-owned implementation files.
30
+ Regeneration preserves edits and reports changed factory signatures for review.
31
+
32
+ ## API and migration
33
+
34
+ Native binding requests negotiate schema 4. Schema 3 remains supported for
35
+ specifications without bindings. Structured native references and strict
36
+ configuration validation prevent older compilers from silently ignoring mappings.
37
+ Go additionally supports explicit import aliases; Rust binds tests to the
38
+ application library's type identities.
39
+
40
+ Existing adapter files cannot be overwritten by adopting a binding. Move their
41
+ implementations into the application module and save the old adapters before
42
+ generation. Generated source bridges, test helpers and user-owned application
43
+ files retain separate placement and ownership. See the
44
+ [migration guide](API-MIGRATION.md#schema-4-native-bindings) and
45
+ [ownership instructions](NATIVE-BINDINGS.md#ownership-regeneration-and-migration).
46
+
47
+ ## Runnable payment projects
48
+
49
+ `lawspec examples --example payments` exports a project for every target; use
50
+ `--target rust` or another language to select one. Each project includes an
51
+ application model, native generator, configuration, build files and instructions.
52
+ The shared specification checks exact fees, currency preservation, sum payloads,
53
+ ordered archives, duplicates and absence. Re-exporting preserves application
54
+ edits and the separate compiler generation manifest.
55
+
56
+ Both 32-bit and 64-bit logical machine profiles and readable/compact output are
57
+ covered by the acceptance matrices. Java 25+, Python 3.13+ and the other published
58
+ toolchain baselines remain unchanged. Python output follows PEP 8.
59
+
60
+ GADTs, dependent indices and cross-unit packages remain subsequent work.
@@ -0,0 +1,62 @@
1
+ # LawSpec 0.11.0
2
+
3
+ ## Natural-indexed families
4
+
5
+ Data declarations may take `Natural` parameters, and each constructor states
6
+ its index equation:
7
+
8
+ ```lawspec
9
+ type Vec (n :: Natural) (a :: Type) is
10
+ | VNil where n = 0
11
+ | VCons head :: a tail :: Vec m a where n = m + 1
12
+ end
13
+
14
+ append :: (xs :: Vec n Int8) -> (ys :: Vec m Int8) -> (r :: Vec (n + m) Int8)
15
+ ```
16
+
17
+ A family elaborates before inference into ordinary erased data, a checked
18
+ structural measure per index (`nOfVec`), and a refinement relating the measure
19
+ to the index. Core and all eight emitters are unchanged. Native code works with
20
+ the erased type, and every index claim is evidence checked at test time: a
21
+ dependent result such as `Vec (n + m) Int8` is an adapter postcondition.
22
+
23
+ An index variable that is otherwise unbound is implicit. The first binder whose
24
+ family type mentions it determines it, and later occurrences read that binder's
25
+ measure. Index expressions are sums of natural literals and index variables.
26
+ `Natural` is also available as a value type. Diagnostics use the `indexed` code.
27
+
28
+ ## Index-directed generation
29
+
30
+ A quantifier constrained by a linear structural measure, including a fixed index
31
+ (`Vec 3 Int8`) or a shared one (`zip`'s second argument), is generated by solving
32
+ the constructor equations backwards instead of filtering. Multi-field equations
33
+ such as `Bin … where n = l + r + 1` split the remaining index across fields.
34
+ Python, JavaScript, TypeScript, Java, Kotlin, Go, Haskell and Rust construct these
35
+ values natively, and framework shrinking stays within the index. The same
36
+ planning applies to user-written linear measures over declared data.
37
+
38
+ `examples/specs/indexed_families.lawspec` runs on all eight targets through
39
+ `tools/indexed-integration.mjs`. Correct adapters pass free, fixed and shared
40
+ index laws; mutants that add, drop or lose elements fail their dependent
41
+ contracts.
42
+
43
+ ## Tower-polymorphic Integer results restored
44
+
45
+ 0.9 had narrowed Kotlin and Haskell adapters whose result is the abstract
46
+ `Integer` to `BigInteger` and `Integer`. They again return `Number` (Kotlin) and
47
+ `LS.IntegerValue` (Haskell), as in 0.8 and as Java always did. `Integer` is the top
48
+ of the integral tower: an implementation may return any integral native value,
49
+ and the result bridge rejects non-integral values and checks the logical domain.
50
+ Adapters written against 0.9 or 0.10 stubs that return `BigInteger` or `Integer`
51
+ still compile, because both are integral.
52
+
53
+ This regression had kept the Kotlin and Haskell CI target jobs failing since
54
+ 0.9. Those jobs, and the scalar mutation fixtures, now pass with the documented
55
+ typed Symbol, Decimal, Utf16Text and Optional representations.
56
+
57
+ ## Compatibility
58
+
59
+ Specifications without indexed families generate the same code as 0.10, apart
60
+ from the Integer result signatures above. API schemas 3 and 4 are unchanged.
61
+ GADTs that refine type arguments, non-linear indices and index equalities between
62
+ sibling fields remain future work.
package/api.mjs CHANGED
@@ -4,9 +4,29 @@ import {loadCore} from './launcher.mjs';
4
4
  export async function createCompiler() {
5
5
  const call = await loadCore();
6
6
  return {
7
- check: (input) => call({schemaVersion: 3, ...input, method: 'check'}),
8
- expand: (input) => call({schemaVersion: 3, ...input, method: 'expand'}),
7
+ check: (input) =>
8
+ call(
9
+ {
10
+ schemaVersion: input.nativeBindings === undefined ? 3 : 4,
11
+ ...input,
12
+ method: 'check',
13
+ }
14
+ ),
15
+ expand: (input) =>
16
+ call(
17
+ {
18
+ schemaVersion: input.nativeBindings === undefined ? 3 : 4,
19
+ ...input,
20
+ method: 'expand',
21
+ }
22
+ ),
9
23
  planGeneration: (input) =>
10
- call({schemaVersion: 3, ...input, method: 'planGeneration'}),
24
+ call(
25
+ {
26
+ schemaVersion: input.nativeBindings === undefined ? 3 : 4,
27
+ ...input,
28
+ method: 'planGeneration',
29
+ }
30
+ ),
11
31
  };
12
32
  }
package/bin/lawspec.mjs CHANGED
@@ -19,7 +19,7 @@ const options = {};
19
19
  const positional = [];
20
20
  for (let i = 0; i < args.length; i++) {
21
21
  const arg = args[i];
22
- if (["--target", "--project", "--config", "--output", "--machine-bits"].includes(arg)) {
22
+ if (["--target", "--project", "--config", "--output", "--machine-bits", "--example"].includes(arg)) {
23
23
  if (!args[i + 1] || args[i + 1].startsWith("--"))
24
24
  throw new Error(`Missing value for ${arg}`);
25
25
  options[arg.slice(2)] = args[++i];
@@ -173,13 +173,13 @@ async function main() {
173
173
  }
174
174
  if (!verb || ["help", "--help", "-h"].includes(verb)) {
175
175
  output(
176
- "LawSpec 0.9.0\nUsage: lawspec init --target <language> [--project <directory>] [--minify]\n lawspec check | doctor | explain <unit>::<law> | generate\n lawspec examples [--target <language>] [--output example_artifacts]\nOptions: --config <path>, --target <language>, --machine-bits <32|64>, --json\nGeneration: --dry-run, --check, --minify\nTargets: " +
176
+ "LawSpec 0.11.0\nUsage: lawspec init --target <language> [--project <directory>] [--minify]\n lawspec check | doctor | explain <unit>::<law> | generate\n lawspec examples [--example payments] [--target <language>] [--output <directory>]\nOptions: --config <path>, --target <language>, --machine-bits <32|64>, --json\nGeneration: --dry-run, --check, --minify\nTargets: " +
177
177
  targets.join(", "),
178
178
  );
179
179
  return;
180
180
  }
181
181
  if (verb === "--version") {
182
- output("0.9.0");
182
+ output("0.11.0");
183
183
  return;
184
184
  }
185
185
  if (positional.length > (verb === "explain" ? 1 : 0))
@@ -191,8 +191,15 @@ async function main() {
191
191
  options["dry-run"] ||
192
192
  options.check
193
193
  )
194
- throw new Error("examples supports --target, --output, --json and --minify only");
194
+ throw new Error("examples supports --example, --target, --output, --machine-bits, --json and --minify only");
195
195
  const result = await generateExamples(options);
196
+ if (options.example) {
197
+ output(options.json ? result : result.map(r =>
198
+ `${r.target}: payment project in ${r.directory}; ${r.preservedAdapters.length} user files preserved.` +
199
+ (r.adapterUpdates.length ? `\nReview changed example files: ${r.adapterUpdates.map(a => a.path).join(", ")}` : "")
200
+ ).join("\n") + "\nOpen each project's README.md, run lawspec generate, then its native test command.");
201
+ return;
202
+ }
196
203
  output(
197
204
  options.json
198
205
  ? result
@@ -207,6 +214,7 @@ async function main() {
207
214
  return;
208
215
  }
209
216
  if (options.output) throw new Error("--output is only supported by examples");
217
+ if (options.example) throw new Error("--example is only supported by examples");
210
218
  if (options.minify && !["init", "generate", "examples"].includes(verb))
211
219
  throw new Error("--minify applies to init, generate and examples");
212
220
  if (verb === "init") return init();
@@ -251,6 +259,10 @@ async function main() {
251
259
  const compiler = await createCompiler();
252
260
  if (verb === "check") {
253
261
  const result = diagnostics(await compiler.check(input));
262
+ for (const target of selected) {
263
+ if (target.nativeBindings !== undefined)
264
+ diagnostics(await compiler.check({...input, nativeBindings: target.nativeBindings}));
265
+ }
254
266
  output(
255
267
  options.json
256
268
  ? result
@@ -289,6 +301,7 @@ async function main() {
289
301
  target: target.language,
290
302
  sourceDir: target.sourceDir,
291
303
  testDir: target.testDir,
304
+ nativeBindings: target.nativeBindings,
292
305
  minify: options.minify === true,
293
306
  }),
294
307
  ).files,