diff --git a/src/declaration.ts b/src/declaration.ts index e8a167f..b413b9f 100644 --- a/src/declaration.ts +++ b/src/declaration.ts @@ -1,4 +1,3 @@ -import type { Example } from "./example.js"; import { definedValue, Maybe, undefinedValue } from "./maybe.js"; export type Declaration> = { @@ -12,7 +11,6 @@ export type Value< export type Options = { readonly default?: T; - readonly examples?: Example[]; readonly isSensitive?: boolean; }; diff --git a/src/declaration/big-integer.ts b/src/declaration/big-integer.ts index 59edcf0..c30bfb4 100644 --- a/src/declaration/big-integer.ts +++ b/src/declaration/big-integer.ts @@ -12,12 +12,17 @@ import { } from "../declaration.js"; import { registerVariable } from "../environment.js"; import { normalize } from "../error.js"; -import { type Example } from "../example.js"; +import { + marshalExamples, + type DeclarationExampleOptions, + type VariableExample, +} from "../example.js"; import { resolve } from "../maybe.js"; import { ScalarSchema, createScalar, toString } from "../schema.js"; import { SpecError } from "../variable.js"; export type Options = DeclarationOptions & + DeclarationExampleOptions & Partial>; export function bigInteger( @@ -36,7 +41,7 @@ export function bigInteger( default: def, isSensitive, schema, - examples: examples ?? buildExamples(), + examples: examples ? marshalExamples(schema, examples) : buildExamples(), }); return { @@ -68,7 +73,7 @@ function createSchema(name: string, options: Options): ScalarSchema { return createScalar("big integer", toString, unmarshal, constraints); } -function buildExamples(): Example[] { +function buildExamples(): VariableExample[] { return [ { value: "123456", diff --git a/src/declaration/binary.ts b/src/declaration/binary.ts index 3883ba1..d349ced 100644 --- a/src/declaration/binary.ts +++ b/src/declaration/binary.ts @@ -12,7 +12,11 @@ import { } from "../declaration.js"; import { registerVariable } from "../environment.js"; import { normalize } from "../error.js"; -import { type Example } from "../example.js"; +import { + marshalExamples, + type DeclarationExampleOptions, + type VariableExample, +} from "../example.js"; import { resolve } from "../maybe.js"; import { ScalarSchema, createScalar } from "../schema.js"; import { SpecError } from "../variable.js"; @@ -22,10 +26,11 @@ const PATTERNS: Partial> = { hex: /^[0-9a-fA-F]*$/, } as const; -export type Options = DeclarationOptions & { - readonly encoding?: BufferEncoding; - readonly length?: LengthConstraintSpec; -}; +export type Options = DeclarationOptions & + DeclarationExampleOptions & { + readonly encoding?: BufferEncoding; + readonly length?: LengthConstraintSpec; + }; export function binary( name: string, @@ -48,7 +53,9 @@ export function binary( default: def, isSensitive, schema, - examples: examples ?? buildExamples(encoding, schema), + examples: examples + ? marshalExamples(schema, examples) + : buildExamples(encoding, schema), }); return { @@ -105,7 +112,7 @@ function createUnmarshal( function buildExamples( encoding: BufferEncoding, schema: ScalarSchema, -): Example[] { +): VariableExample[] { return [ { value: schema.marshal(Buffer.from("conquistador", "utf-8")), diff --git a/src/declaration/boolean.ts b/src/declaration/boolean.ts index a06cd0e..fac35c5 100644 --- a/src/declaration/boolean.ts +++ b/src/declaration/boolean.ts @@ -6,14 +6,19 @@ import { type ExactOptions, } from "../declaration.js"; import { registerVariable } from "../environment.js"; -import { type Example } from "../example.js"; +import { + marshalExamples, + type DeclarationExampleOptions, + type VariableExample, +} from "../example.js"; import { resolve } from "../maybe.js"; import { EnumSchema, InvalidEnumError, createEnum } from "../schema.js"; import { SpecError } from "../variable.js"; -export type Options = DeclarationOptions & { - readonly literals?: Literals; -}; +export type Options = DeclarationOptions & + DeclarationExampleOptions & { + readonly literals?: Literals; + }; export type Literals = Record; @@ -38,7 +43,9 @@ export function boolean( default: def, isSensitive, schema, - examples: examples ?? buildExamples(literals), + examples: examples + ? marshalExamples(schema, examples) + : buildExamples(literals), }); return { @@ -83,7 +90,7 @@ function findLiteral( throw new MissingLiteralError(name, native); } -function buildExamples(literals: Literals): Example[] { +function buildExamples(literals: Literals): VariableExample[] { return Object.entries(literals).map(([literal, native]) => ({ value: literal, description: String(native), diff --git a/src/declaration/duration.ts b/src/declaration/duration.ts index 350ce0b..ef3912e 100644 --- a/src/declaration/duration.ts +++ b/src/declaration/duration.ts @@ -13,7 +13,11 @@ import { } from "../declaration.js"; import { registerVariable } from "../environment.js"; import { normalize } from "../error.js"; -import { type Example } from "../example.js"; +import { + marshalExamples, + type DeclarationExampleOptions, + type VariableExample, +} from "../example.js"; import { resolve } from "../maybe.js"; import { ScalarSchema, createScalar, toString } from "../schema.js"; import { SpecError } from "../variable.js"; @@ -22,6 +26,7 @@ const { Duration } = Temporal; type Duration = Temporal.Duration; export type Options = DeclarationOptions & + DeclarationExampleOptions & Partial>; export function duration( @@ -40,7 +45,7 @@ export function duration( default: def, isSensitive, schema, - examples: examples ?? buildExamples(), + examples: examples ? marshalExamples(schema, examples) : buildExamples(), }); return { @@ -72,7 +77,7 @@ function createSchema(name: string, options: Options): ScalarSchema { return createScalar("ISO 8601 duration", toString, unmarshal, constraints); } -function buildExamples(): Example[] { +function buildExamples(): VariableExample[] { return [ { value: Duration.from({ minutes: 1, seconds: 30 }).toString(), diff --git a/src/declaration/enumeration.ts b/src/declaration/enumeration.ts index cdc4529..35af5ab 100644 --- a/src/declaration/enumeration.ts +++ b/src/declaration/enumeration.ts @@ -6,7 +6,11 @@ import { type ExactOptions, } from "../declaration.js"; import { registerVariable } from "../environment.js"; -import { type Example } from "../example.js"; +import { + marshalExamples, + type DeclarationExampleOptions, + type VariableExample, +} from "../example.js"; import { resolve } from "../maybe.js"; import { EnumSchema, InvalidEnumError, createEnum } from "../schema.js"; import { SpecError } from "../variable.js"; @@ -18,7 +22,7 @@ export type Member = { readonly description: string; }; -export type Options = DeclarationOptions; +export type Options = DeclarationOptions & DeclarationExampleOptions; export function enumeration>( name: string, @@ -37,7 +41,9 @@ export function enumeration>( default: def, isSensitive, schema, - examples: examples ?? buildExamples(members), + examples: examples + ? marshalExamples(schema, examples) + : buildExamples(members), }); return { @@ -75,7 +81,7 @@ function createSchema(name: string, members: Members): EnumSchema { return createEnum(schemaMembers, marshal, unmarshal, []); } -function buildExamples(members: Members): Example[] { +function buildExamples(members: Members): VariableExample[] { return Object.entries(members).map(([literal, { description }]) => ({ value: literal, description, diff --git a/src/declaration/integer.ts b/src/declaration/integer.ts index 448658f..2cdf25b 100644 --- a/src/declaration/integer.ts +++ b/src/declaration/integer.ts @@ -14,12 +14,17 @@ import { } from "../declaration.js"; import { registerVariable } from "../environment.js"; import { normalize } from "../error.js"; -import { type Example } from "../example.js"; +import { + marshalExamples, + type DeclarationExampleOptions, + type VariableExample, +} from "../example.js"; import { resolve } from "../maybe.js"; import { ScalarSchema, createScalar, toString } from "../schema.js"; import { SpecError } from "../variable.js"; export type Options = DeclarationOptions & + DeclarationExampleOptions & Partial>; export function integer( @@ -38,7 +43,7 @@ export function integer( default: def, isSensitive, schema, - examples: examples ?? buildExamples(), + examples: examples ? marshalExamples(schema, examples) : buildExamples(), }); return { @@ -67,7 +72,7 @@ function createSchema(name: string, options: Options): ScalarSchema { return createScalar("integer", toString, unmarshal, constraints); } -function buildExamples(): Example[] { +function buildExamples(): VariableExample[] { return [ { value: "123456", diff --git a/src/declaration/kubernetes-address.ts b/src/declaration/kubernetes-address.ts index 5a1d260..b97be54 100644 --- a/src/declaration/kubernetes-address.ts +++ b/src/declaration/kubernetes-address.ts @@ -9,7 +9,10 @@ import { } from "../declaration.js"; import { registerVariable } from "../environment.js"; import { normalize } from "../error.js"; -import { type Example } from "../example.js"; +import { + type DeclarationExampleOptions, + type VariableExample, +} from "../example.js"; import { Maybe, map, resolve } from "../maybe.js"; import { ScalarSchema, @@ -24,9 +27,10 @@ export type KubernetesAddress = { readonly port: number; }; -export type Options = DeclarationOptions & { - readonly portName?: string; -}; +export type Options = DeclarationOptions & + DeclarationExampleOptions & { + readonly portName?: string; + }; export function kubernetesAddress( name: string, @@ -80,7 +84,7 @@ function registerHost( }); } -function buildHostExamples(): Example[] { +function buildHostExamples(): VariableExample[] { return [ { value: "service.example.org", @@ -146,7 +150,7 @@ function createPortSchema(): ScalarSchema { ]); } -function buildPortExamples(): Example[] { +function buildPortExamples(): VariableExample[] { return [ { value: "12345", diff --git a/src/declaration/network-port-number.ts b/src/declaration/network-port-number.ts index 591de6e..3e8765a 100644 --- a/src/declaration/network-port-number.ts +++ b/src/declaration/network-port-number.ts @@ -14,12 +14,17 @@ import { } from "../declaration.js"; import { registerVariable } from "../environment.js"; import { normalize } from "../error.js"; -import { type Example } from "../example.js"; +import { + marshalExamples, + type DeclarationExampleOptions, + type VariableExample, +} from "../example.js"; import { resolve } from "../maybe.js"; import { ScalarSchema, createScalar, toString } from "../schema.js"; import { SpecError } from "../variable.js"; export type Options = DeclarationOptions & + DeclarationExampleOptions & Partial>; export function networkPortNumber( @@ -38,7 +43,7 @@ export function networkPortNumber( default: def, isSensitive, schema, - examples: examples ?? buildExamples(), + examples: examples ? marshalExamples(schema, examples) : buildExamples(), }); return { @@ -72,7 +77,7 @@ function createSchema(name: string, options: Options): ScalarSchema { return createScalar("port number", toString, unmarshal, constraints); } -function buildExamples(): Example[] { +function buildExamples(): VariableExample[] { return [ { value: "12345", diff --git a/src/declaration/number.ts b/src/declaration/number.ts index 108e392..5303c5a 100644 --- a/src/declaration/number.ts +++ b/src/declaration/number.ts @@ -12,12 +12,17 @@ import { } from "../declaration.js"; import { registerVariable } from "../environment.js"; import { normalize } from "../error.js"; -import { type Example } from "../example.js"; +import { + marshalExamples, + type DeclarationExampleOptions, + type VariableExample, +} from "../example.js"; import { resolve } from "../maybe.js"; import { ScalarSchema, createScalar, toString } from "../schema.js"; import { SpecError } from "../variable.js"; export type Options = DeclarationOptions & + DeclarationExampleOptions & Partial>; export function number( @@ -36,7 +41,7 @@ export function number( default: def, isSensitive, schema, - examples: examples ?? buildExamples(), + examples: examples ? marshalExamples(schema, examples) : buildExamples(), }); return { @@ -68,7 +73,7 @@ function createSchema(name: string, options: Options): ScalarSchema { return createScalar("number", toString, unmarshal, constraints); } -function buildExamples(): Example[] { +function buildExamples(): VariableExample[] { return [ { value: "123456", diff --git a/src/declaration/string.ts b/src/declaration/string.ts index 530aef0..7232faa 100644 --- a/src/declaration/string.ts +++ b/src/declaration/string.ts @@ -11,14 +11,19 @@ import { } from "../declaration.js"; import { registerVariable } from "../environment.js"; import { normalize } from "../error.js"; -import { type Example } from "../example.js"; +import { + marshalExamples, + type DeclarationExampleOptions, + type VariableExample, +} from "../example.js"; import { resolve } from "../maybe.js"; import { createString } from "../schema.js"; import { SpecError } from "../variable.js"; -export type Options = DeclarationOptions & { - readonly length?: LengthConstraintSpec; -}; +export type Options = DeclarationOptions & + DeclarationExampleOptions & { + readonly length?: LengthConstraintSpec; + }; export function string( name: string, @@ -46,7 +51,7 @@ export function string( default: def, isSensitive, schema, - examples: examples ?? buildExamples(), + examples: examples ? marshalExamples(schema, examples) : buildExamples(), }); return { @@ -56,7 +61,7 @@ export function string( }; } -function buildExamples(): Example[] { +function buildExamples(): VariableExample[] { return [ { value: "conquistador", diff --git a/src/declaration/url.ts b/src/declaration/url.ts index 7f00ab7..d589b30 100644 --- a/src/declaration/url.ts +++ b/src/declaration/url.ts @@ -9,7 +9,11 @@ import { } from "../declaration.js"; import { registerVariable } from "../environment.js"; import { normalize } from "../error.js"; -import { Example } from "../example.js"; +import { + VariableExample, + marshalExamples, + type DeclarationExampleOptions, +} from "../example.js"; import { resolve } from "../maybe.js"; import { createURL, toString, type URLSchema } from "../schema.js"; import { SpecError } from "../variable.js"; @@ -17,10 +21,11 @@ import { SpecError } from "../variable.js"; // as per https://www.rfc-editor.org/rfc/rfc3986#section-3.1 const VALID_PROTOCOL_PATTERN = /^[a-zA-Z][a-zA-Z0-9.+-]*:$/; -export type Options = DeclarationOptions & { - readonly base?: URL; - readonly protocols?: string[]; -}; +export type Options = DeclarationOptions & + DeclarationExampleOptions & { + readonly base?: URL; + readonly protocols?: string[]; + }; export function url( name: string, @@ -43,7 +48,9 @@ export function url( default: def, isSensitive, schema, - examples: examples ?? buildExamples(base, protocols), + examples: examples + ? marshalExamples(schema, examples) + : buildExamples(base, protocols), }); return { @@ -113,8 +120,8 @@ function createSchema( function buildExamples( base: URL | undefined, protocols: string[] | undefined, -): Example[] { - const examples: Example[] = +): VariableExample[] { + const examples: VariableExample[] = protocols == null ? [ { diff --git a/src/example.ts b/src/example.ts index 11e2172..b242641 100644 --- a/src/example.ts +++ b/src/example.ts @@ -1,16 +1,35 @@ import { applyConstraints } from "./constraint.js"; import type { Schema } from "./schema.js"; -export type Example = { +export type DeclarationExampleOptions = { + readonly examples?: DeclarationExample[]; +}; + +export type DeclarationExample = { + readonly value: T; + readonly description: string; +}; + +export type VariableExample = { readonly value: string; readonly description: string; }; +export function marshalExamples( + schema: Schema, + examples: DeclarationExample[], +): VariableExample[] { + return examples.map((example) => ({ + value: schema.marshal(example.value), + description: example.description, + })); +} + export function removeInvalidExamples( schema: Schema, - examples: Example[], -): Example[] { - const filtered: Example[] = []; + examples: VariableExample[], +): VariableExample[] { + const filtered: VariableExample[] = []; for (const example of examples) { try { diff --git a/src/variable.ts b/src/variable.ts index 66656c7..546b187 100644 --- a/src/variable.ts +++ b/src/variable.ts @@ -1,7 +1,7 @@ import { applyConstraints } from "./constraint.js"; import { readVariable } from "./environment.js"; import { normalize } from "./error.js"; -import { removeInvalidExamples, type Example } from "./example.js"; +import { removeInvalidExamples, type VariableExample } from "./example.js"; import { Maybe, definedValue, map, undefinedValue } from "./maybe.js"; import { Schema } from "./schema.js"; import { quote } from "./shell.js"; @@ -12,7 +12,7 @@ export type VariableSpec = { readonly default: Maybe; readonly isSensitive: boolean; readonly schema: Schema; - readonly examples: Example[]; + readonly examples: VariableExample[]; }; export type Variable = { diff --git a/test/suite/specification.spec.ts b/test/suite/specification.spec.ts index 302ce7d..8024a2d 100644 --- a/test/suite/specification.spec.ts +++ b/test/suite/specification.spec.ts @@ -760,11 +760,11 @@ describe("Specification documents", () => { bigInteger("AUSTENITE_INTEGER_BIG", "example big integer", { examples: [ { - value: "12345678901234567890", + value: 12345678901234567890n, description: "", }, { - value: "98765432109876543210", + value: 98765432109876543210n, description: "", }, ], @@ -772,11 +772,11 @@ describe("Specification documents", () => { binary("AUSTENITE_BINARY", "example binary", { examples: [ { - value: "QmVlcCBib29wIQ==", + value: Buffer.from("Beep boop!", "utf-8"), description: "", }, { - value: "Qm9vcCBiZWVwIQ==", + value: Buffer.from("Boop beep!", "utf-8"), description: "", }, ], @@ -784,11 +784,11 @@ describe("Specification documents", () => { boolean("AUSTENITE_BOOLEAN", "example boolean", { examples: [ { - value: "true", + value: true, description: "", }, { - value: "false", + value: false, description: "", }, ], @@ -796,11 +796,11 @@ describe("Specification documents", () => { duration("AUSTENITE_DURATION", "example duration", { examples: [ { - value: "PT10S", + value: Duration.from("PT10S"), description: "", }, { - value: "PT20S", + value: Duration.from("PT20S"), description: "", }, ], @@ -838,11 +838,11 @@ describe("Specification documents", () => { integer("AUSTENITE_INTEGER", "example integer", { examples: [ { - value: "123456", + value: 123456, description: "", }, { - value: "654321", + value: 654321, description: "", }, ], @@ -851,11 +851,11 @@ describe("Specification documents", () => { networkPortNumber("AUSTENITE_PORT_NUMBER", "example port number", { examples: [ { - value: "123", + value: 123, description: "", }, { - value: "234", + value: 234, description: "", }, ], @@ -863,11 +863,11 @@ describe("Specification documents", () => { number("AUSTENITE_NUMBER", "example number", { examples: [ { - value: "123.456", + value: 123.456, description: "", }, { - value: "654.321", + value: 654.321, description: "", }, ], @@ -887,11 +887,11 @@ describe("Specification documents", () => { url("AUSTENITE_URL", "example URL", { examples: [ { - value: "https://example.org/path/to/resource", + value: new URL("https://example.org/path/to/resource"), description: "", }, { - value: "https://example.com/path/to/resource", + value: new URL("https://example.com/path/to/resource"), description: "", }, ],