typebox 1.1.6 → 1.1.8

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 (36) hide show
  1. package/build/type/engine/call/distribute-arguments.d.mts +10 -0
  2. package/build/type/engine/call/distribute-arguments.mjs +27 -0
  3. package/build/type/engine/call/instantiate.d.mts +9 -6
  4. package/build/type/engine/call/instantiate.mjs +33 -23
  5. package/build/type/engine/evaluate/broaden.d.mts +1 -1
  6. package/build/type/engine/evaluate/broaden.mjs +7 -8
  7. package/build/type/script/token/bigint.d.mts +1 -1
  8. package/build/type/script/token/bigint.mjs +3 -9
  9. package/build/type/script/token/ident.mjs +4 -13
  10. package/build/type/script/token/index.d.mts +3 -0
  11. package/build/type/script/token/index.mjs +3 -0
  12. package/build/type/script/token/integer.d.mts +5 -13
  13. package/build/type/script/token/integer.mjs +7 -33
  14. package/build/type/script/token/internal/many.mjs +4 -7
  15. package/build/type/script/token/internal/match.d.mts +6 -0
  16. package/build/type/script/token/internal/match.mjs +11 -0
  17. package/build/type/script/token/internal/optional.mjs +2 -5
  18. package/build/type/script/token/internal/take.mjs +23 -8
  19. package/build/type/script/token/number.d.mts +5 -14
  20. package/build/type/script/token/number.mjs +7 -53
  21. package/build/type/script/token/rest.d.mts +4 -0
  22. package/build/type/script/token/rest.mjs +9 -0
  23. package/build/type/script/token/span.d.mts +3 -2
  24. package/build/type/script/token/span.mjs +8 -19
  25. package/build/type/script/token/string.mjs +2 -6
  26. package/build/type/script/token/unsigned_integer.d.mts +16 -0
  27. package/build/type/script/token/unsigned_integer.mjs +26 -0
  28. package/build/type/script/token/unsigned_number.d.mts +17 -0
  29. package/build/type/script/token/unsigned_number.mjs +38 -0
  30. package/build/type/script/token/until.d.mts +3 -2
  31. package/build/type/script/token/until.mjs +11 -8
  32. package/build/type/script/token/until_1.mjs +4 -8
  33. package/package.json +29 -29
  34. package/readme.md +18 -50
  35. package/build/type/script/token/internal/result.d.mts +0 -2
  36. package/build/type/script/token/internal/result.mjs +0 -7
@@ -0,0 +1,10 @@
1
+ import { type TSchema } from '../../types/schema.mjs';
2
+ import { type TUnion } from '../../types/union.mjs';
3
+ import { type TDeferred } from '../../types/deferred.mjs';
4
+ type TExpand<Type extends TSchema> = (Type extends TUnion<infer Types extends TSchema[]> ? [...Types] : [Type]);
5
+ type TAppend<Current extends TSchema[][], Type extends TSchema, Result extends TSchema[][] = []> = (Current extends [infer Left extends TSchema[], ...infer Right extends TSchema[][]] ? TAppend<Right, Type, [...Result, [...Left, Type]]> : Result);
6
+ type TCross<Current extends TSchema[][], Variants extends TSchema[], Result extends TSchema[][] = []> = (Variants extends [infer Left extends TSchema, ...infer Right extends TSchema[]] ? TCross<Current, Right, [...Result, ...TAppend<Current, Left>]> : Result);
7
+ type TDistribute<Types extends TSchema[], Result extends TSchema[][] = [[]]> = (Types extends [infer Left extends TSchema, ...infer Right extends TSchema[]] ? TDistribute<Right, TCross<Result, TExpand<Left>>> : Result);
8
+ export type TDistributeArguments<Arguments extends TSchema[], Expression extends TSchema, Result extends TSchema[][] = Expression extends TDeferred<'Conditional', TSchema[]> ? TDistribute<Arguments> : [Arguments]> = Result;
9
+ export declare function DistributedArguments<Arguments extends TSchema[], Expression extends TSchema>(arguments_: [...Arguments], expression: Expression): TDistributeArguments<Arguments, Expression>;
10
+ export {};
@@ -0,0 +1,27 @@
1
+ // deno-fmt-ignore-file
2
+ import { Guard } from '../../../guard/index.mjs';
3
+ import { IsUnion } from '../../types/union.mjs';
4
+ import { IsDeferred } from '../../types/deferred.mjs';
5
+ function Expand(type) {
6
+ return (IsUnion(type)
7
+ ? [...type.anyOf]
8
+ : [type]);
9
+ }
10
+ function Append(current, type) {
11
+ return current.reduce((result, left) => [...result, [...left, type]], []);
12
+ }
13
+ function Cross(current, variants) {
14
+ return variants.reduce((result, left) => {
15
+ return [...result, ...Append(current, left)];
16
+ }, []);
17
+ }
18
+ function Distribute(types) {
19
+ return types.reduce((result, type) => {
20
+ return Cross(result, Expand(type));
21
+ }, [[]]);
22
+ }
23
+ export function DistributedArguments(arguments_, expression) {
24
+ return (IsDeferred(expression) && Guard.IsEqual(expression.action, 'Conditional')
25
+ ? Distribute(arguments_)
26
+ : [arguments_]);
27
+ }
@@ -4,17 +4,20 @@ import { type TCallConstruct } from '../../types/call.mjs';
4
4
  import { type TRef } from '../../types/ref.mjs';
5
5
  import { type TGeneric } from '../../types/generic.mjs';
6
6
  import { type TProperties } from '../../types/properties.mjs';
7
+ import { type TEvaluateUnion } from '../evaluate/index.mjs';
7
8
  import { type TState } from '../instantiate.mjs';
8
9
  import { type TInstantiateType } from '../instantiate.mjs';
9
10
  import { type TInstantiateTypes } from '../instantiate.mjs';
11
+ import { type TDistributeArguments } from './distribute-arguments.mjs';
10
12
  import { type TResolveTarget } from './resolve-target.mjs';
11
13
  import { type TResolveArgumentsContext } from './resolve-arguments.mjs';
12
- type TPeek<CallStack extends string[], Result extends string = CallStack extends [infer Left extends string, ...infer _ extends string[]] ? Left : ''> = Result;
13
- type TDeferredCall<Context extends TProperties, State extends TState, Target extends TSchema, Arguments extends TSchema[], InstantiatedArguments extends TSchema[] = TInstantiateTypes<Context, State, Arguments>, DeferredCall extends TSchema = TCallConstruct<Target, InstantiatedArguments>> = DeferredCall;
14
- type TTailCall<Context extends TProperties, State extends TState, Name extends string, Arguments extends TSchema[], DeferredCall extends TSchema = TDeferredCall<Context, State, TRef<Name>, Arguments>> = DeferredCall;
15
- type THeadCall<Context extends TProperties, State extends TState, Name extends string, Parameters extends TParameter[], Expression extends TSchema, Arguments extends TSchema[], InstantiatedArguments extends TSchema[] = TInstantiateTypes<Context, State, Arguments>, ArgumentsContext extends TProperties = TResolveArgumentsContext<Context, State, Parameters, InstantiatedArguments>, ReturnType extends TSchema = TInstantiateType<ArgumentsContext, {
16
- callstack: [...State['callstack'], Name];
14
+ type TPeek<State extends TState, Result extends string = State['callstack'] extends [...infer _ extends string[], infer Top extends string] ? Top : ''> = Result;
15
+ type TIsTailCall<State extends TState, Name extends string, Result extends boolean = TPeek<State> extends Name ? true : false> = Result;
16
+ type TCallDispatch<Context extends TProperties, State extends TState, Target extends TRef, Parameters extends TParameter[], Expression extends TSchema, Arguments extends TSchema[], ArgumentsContext extends TProperties = TResolveArgumentsContext<Context, State, Parameters, Arguments>, ReturnType extends TSchema = TInstantiateType<ArgumentsContext, {
17
+ callstack: [...State['callstack'], Target['$ref']];
17
18
  }, Expression>> = TInstantiateType<Context, State, ReturnType>;
18
- export type TCallInstantiate<Context extends TProperties, State extends TState, Target extends TSchema, Arguments extends TSchema[], Resolved extends [string, TSchema] = TResolveTarget<Context, Target, Arguments>, Name extends string = Resolved[0], Type extends TSchema = Resolved[1], Result extends TSchema = (Type extends TGeneric<infer Parameters extends TParameter[], infer Expression extends TSchema> ? TPeek<State['callstack']> extends Name ? TTailCall<Context, State, Name, Arguments> : THeadCall<Context, State, Name, Parameters, Expression, Arguments> : TDeferredCall<Context, State, Target, Arguments>)> = Result;
19
+ type TCallDistributed<Context extends TProperties, State extends TState, Target extends TRef, Parameters extends TParameter[], Expression extends TSchema, DistributedArguments extends TSchema[][], Result extends TSchema[] = []> = (DistributedArguments extends [infer Arguments extends TSchema[], ...infer DistributedArguments extends TSchema[][]] ? TCallDispatch<Context, State, Target, Parameters, Expression, Arguments> extends infer ReturnType extends TSchema ? TCallDistributed<Context, State, Target, Parameters, Expression, DistributedArguments, [...Result, ReturnType]> : never : Result);
20
+ type TCallImmediate<Context extends TProperties, State extends TState, Target extends TRef, Parameters extends TParameter[], Expression extends TSchema, InstantiatedArguments extends TSchema[], DistributedArguments extends TSchema[][] = TDistributeArguments<InstantiatedArguments, Expression>, ReturnTypes extends TSchema[] = TCallDistributed<Context, State, Target, Parameters, Expression, DistributedArguments>, Result extends TSchema = ReturnTypes['length'] extends 1 ? ReturnTypes[0] : TEvaluateUnion<ReturnTypes>> = Result;
21
+ export type TCallInstantiate<Context extends TProperties, State extends TState, Target extends TSchema, Arguments extends TSchema[], InstantiatedArguments extends TSchema[] = TInstantiateTypes<Context, State, Arguments>, Resolved extends [string, TSchema] = TResolveTarget<Context, Target, Arguments>, Name extends string = Resolved[0], Type extends TSchema = Resolved[1], Result extends TSchema = (Type extends TGeneric<infer Parameters extends TParameter[], infer Expression extends TSchema> ? TIsTailCall<State, Name> extends true ? TCallConstruct<TRef<Name>, InstantiatedArguments> : TCallImmediate<Context, State, TRef<Name>, Parameters, Expression, InstantiatedArguments> : TCallConstruct<Target, InstantiatedArguments>)> = Result;
19
22
  export declare function CallInstantiate<Context extends TProperties, State extends TState, Target extends TSchema, Arguments extends TSchema[]>(context: Context, state: State, target: Target, arguments_: [...Arguments]): TCallInstantiate<Context, State, Target, Arguments>;
20
23
  export {};
@@ -3,36 +3,46 @@ import { Guard } from '../../../guard/index.mjs';
3
3
  import { CallConstruct } from '../../types/call.mjs';
4
4
  import { Ref } from '../../types/ref.mjs';
5
5
  import { IsGeneric } from '../../types/generic.mjs';
6
+ import { EvaluateUnion } from '../evaluate/index.mjs';
6
7
  import { InstantiateType } from '../instantiate.mjs';
7
8
  import { InstantiateTypes } from '../instantiate.mjs';
8
- // ----------------------------------------------------------------------------
9
- // Call: Infrastructure
10
- // ----------------------------------------------------------------------------
9
+ // ------------------------------------------------------------------
10
+ // Infrastructure
11
+ // ------------------------------------------------------------------
12
+ import { DistributedArguments } from './distribute-arguments.mjs';
11
13
  import { ResolveTarget } from './resolve-target.mjs';
12
14
  import { ResolveArgumentsContext } from './resolve-arguments.mjs';
13
- function Peek(callstack) {
14
- return (Guard.IsGreaterThan(callstack.length, 0) ? callstack[0] : '');
15
+ function Peek(state) {
16
+ const result = Guard.IsGreaterThan(state.callstack.length, 0) ? state.callstack[state.callstack.length - 1] : '';
17
+ return result;
15
18
  }
16
- function DeferredCall(context, state, target, arguments_) {
17
- const instantiatedArguments = InstantiateTypes(context, state, arguments_);
18
- const deferredCall = CallConstruct(target, instantiatedArguments);
19
- return deferredCall;
20
- }
21
- function TailCall(context, state, name, arguments_) {
22
- const deferredCall = DeferredCall(context, state, Ref(name), arguments_);
23
- return deferredCall;
19
+ function IsTailCall(state, name) {
20
+ const result = Guard.IsEqual(Peek(state), name);
21
+ return result;
24
22
  }
25
- function HeadCall(context, state, name, parameters, expression, arguments_) {
26
- const instantiatedArguments = InstantiateTypes(context, state, arguments_);
27
- const argumentsContext = ResolveArgumentsContext(context, state, parameters, instantiatedArguments);
28
- const returnType = InstantiateType(argumentsContext, { callstack: [...state.callstack, name] }, expression);
23
+ function CallDispatch(context, state, target, parameters, expression, arguments_) {
24
+ const argumentsContext = ResolveArgumentsContext(context, state, parameters, arguments_);
25
+ const returnType = InstantiateType(argumentsContext, { callstack: [...state.callstack, target.$ref] }, expression);
29
26
  return InstantiateType(context, state, returnType);
30
27
  }
28
+ function CallDistributed(context, state, target, parameters, expression, distributedArguments) {
29
+ return distributedArguments.reduce((result, arguments_) => [...result, CallDispatch(context, state, target, parameters, expression, arguments_)], []);
30
+ }
31
+ function CallImmediate(context, state, target, parameters, expression, arguments_) {
32
+ const distributedArguments = DistributedArguments(arguments_, expression);
33
+ const returnTypes = CallDistributed(context, state, target, parameters, expression, distributedArguments);
34
+ const result = returnTypes.length === 1 ? returnTypes[0] : EvaluateUnion(returnTypes);
35
+ return result;
36
+ }
31
37
  export function CallInstantiate(context, state, target, arguments_) {
32
- const [name, type] = ResolveTarget(context, target, arguments_);
33
- return (IsGeneric(type)
34
- ? Guard.IsEqual(Peek(state.callstack), name)
35
- ? TailCall(context, state, name, arguments_)
36
- : HeadCall(context, state, name, type.parameters, type.expression, arguments_)
37
- : DeferredCall(context, state, target, arguments_));
38
+ const instantiatedArguments = InstantiateTypes(context, state, arguments_);
39
+ const resolved = ResolveTarget(context, target, arguments_);
40
+ const name = resolved[0];
41
+ const type = resolved[1];
42
+ const result = (IsGeneric(type)
43
+ ? IsTailCall(state, name)
44
+ ? CallConstruct(Ref(name), instantiatedArguments)
45
+ : CallImmediate(context, state, Ref(name), type.parameters, type.expression, instantiatedArguments)
46
+ : CallConstruct(target, instantiatedArguments));
47
+ return result;
38
48
  }
@@ -9,7 +9,7 @@ import { type TEvaluateType } from './evaluate.mjs';
9
9
  type TBroadFilter<Type extends TSchema, Types extends TSchema[], Result extends TSchema[] = []> = (Types extends [infer Left extends TSchema, ...infer Right extends TSchema[]] ? TCompare<Type, Left> extends typeof ResultRightInside ? TBroadFilter<Type, Right, [...Result]> : TBroadFilter<Type, Right, [...Result, Left]> : Result);
10
10
  type TIsBroadestType<Type extends TSchema, Types extends TSchema[]> = (Types extends [infer Left extends TSchema, ...infer Right extends TSchema[]] ? TCompare<Type, Left> extends typeof ResultLeftInside | typeof ResultEqual ? false : TIsBroadestType<Type, Right> : true);
11
11
  type TBroadenType<Type extends TSchema, Types extends TSchema[], Evaluated extends TSchema = TEvaluateType<Type>, Result extends TSchema[] = (Evaluated extends TAny ? [Evaluated] : TIsBroadestType<Evaluated, Types> extends true ? [...TBroadFilter<Evaluated, Types>, Evaluated] : Types)> = Result;
12
- type TBroadenTypes<Types extends TSchema[], Result extends TSchema[] = []> = (Types extends [infer Left extends TSchema, ...infer Right extends TSchema[]] ? Left extends TObject ? TBroadenTypes<Right, [...Result, Left]> : TBroadenTypes<Right, TBroadenType<Left, Result>> : Result);
12
+ type TBroadenTypes<Types extends TSchema[], Result extends TSchema[] = []> = (Types extends [infer Left extends TSchema, ...infer Right extends TSchema[]] ? (Left extends TObject ? TBroadenTypes<Right, [...Result, Left]> : Left extends TNever ? TBroadenTypes<Right, Result> : TBroadenTypes<Right, TBroadenType<Left, Result>>) : Result);
13
13
  export type TBroaden<Types extends TSchema[], Broadened extends TSchema[] = TBroadenTypes<Types>, Flattened extends TSchema[] = TFlatten<Broadened>, Result extends TSchema = (Flattened extends [] ? TNever : Flattened extends [infer Type extends TSchema] ? Type : TUnion<Flattened>)> = Result;
14
14
  /** Broadens a set of types and returns either the most broad type, or union or disjoint types. */
15
15
  export declare function Broaden<Types extends TSchema[]>(types: [...Types]): TBroaden<Types>;
@@ -1,8 +1,7 @@
1
1
  // deno-fmt-ignore-file
2
2
  import { Guard } from '../../../guard/index.mjs';
3
- import { IsSchema } from '../../types/schema.mjs';
4
3
  import { IsAny } from '../../types/any.mjs';
5
- import { Never } from '../../types/never.mjs';
4
+ import { Never, IsNever } from '../../types/never.mjs';
6
5
  import { IsObject } from '../../types/object.mjs';
7
6
  import { Union } from '../../types/union.mjs';
8
7
  import { Compare, ResultRightInside, ResultLeftInside, ResultEqual } from './compare.mjs';
@@ -30,12 +29,12 @@ function BroadenType(type, types) {
30
29
  : types);
31
30
  }
32
31
  function BroadenTypes(types, result = []) {
33
- const [left, ...right] = types;
34
- return (IsSchema(left)
35
- ? IsObject(left)
36
- ? BroadenTypes(right, [...result, left]) // special: push object type
37
- : BroadenTypes(right, BroadenType(left, result))
38
- : result);
32
+ return types.reduce((result, left) => {
33
+ return (IsObject(left) ? [...result, left] : // push
34
+ IsNever(left) ? result : // ignore
35
+ BroadenType(left, result) // broaden
36
+ );
37
+ }, []);
39
38
  }
40
39
  /** Broadens a set of types and returns either the most broad type, or union or disjoint types. */
41
40
  export function Broaden(types) {
@@ -1,6 +1,6 @@
1
1
  import { type TTake } from './internal/take.mjs';
2
2
  import { type TInteger } from './integer.mjs';
3
- type TTakeBigInt<Input extends string> = (TInteger<Input> extends [infer Integer extends string, infer IntegerRest extends string] ? TTake<['n'], IntegerRest> extends [infer N extends string, infer NRest extends string] ? [`${Integer}`, NRest] : [] : []);
3
+ type TTakeBigInt<Input extends string> = (TInteger<Input> extends [infer Integer extends string, infer IntegerRest extends string] ? TTake<['n'], IntegerRest> extends [infer _N extends string, infer NRest extends string] ? [`${Integer}`, NRest] : [] : []);
4
4
  /** Matches if next is a Integer literal with trailing 'n'. Trailing 'n' is omitted in result. */
5
5
  export type TBigInt<Input extends string> = (TTakeBigInt<Input>);
6
6
  /** Matches if next is a Integer literal with trailing 'n'. Trailing 'n' is omitted in result. */
@@ -1,17 +1,11 @@
1
1
  // deno-coverage-ignore-start - parsebox tested
2
2
  // deno-fmt-ignore-file
3
- import { IsResult } from './internal/result.mjs';
3
+ import { Match } from './internal/match.mjs';
4
4
  import { Take } from './internal/take.mjs';
5
5
  import { Integer } from './integer.mjs';
6
6
  function TakeBigInt(input) {
7
- const integer = Integer(input);
8
- return (IsResult(integer) ? (() => {
9
- const n = Take(['n'], integer[1]);
10
- return IsResult(n)
11
- ? [`${integer[0]}`, n[1]]
12
- : []; // fail: did not match 'n'
13
- })() : [] // fail: did not match Integer
14
- );
7
+ return Match(Integer(input), (Integer, IntegerRest) => Match(Take(['n'], IntegerRest), (_N, NRest) => [`${Integer}`, NRest], () => []), // fail: did not match 'n'
8
+ () => []); // fail: did not match Integer
15
9
  }
16
10
  /** Matches if next is a Integer literal with trailing 'n'. Trailing 'n' is omitted in result. */
17
11
  export function BigInt(input) {
@@ -1,6 +1,6 @@
1
1
  // deno-coverage-ignore-start - parsebox tested
2
2
  // deno-fmt-ignore-file
3
- import { IsResult } from './internal/result.mjs';
3
+ import { Match } from './internal/match.mjs';
4
4
  import { Trim } from './internal/trim.mjs';
5
5
  import { Take } from './internal/take.mjs';
6
6
  import { Alpha } from './internal/char.mjs';
@@ -13,20 +13,11 @@ function TakeInitial(input) {
13
13
  }
14
14
  const Remaining = [...Initial, ...Digit];
15
15
  function TakeRemaining(input, result = '') {
16
- const remaining = Take(Remaining, input);
17
- return (IsResult(remaining)
18
- ? TakeRemaining(remaining[1], `${result}${remaining[0]}`)
19
- : [result, input]);
16
+ return Match(Take(Remaining, input), (Remaining, RemainingRest) => TakeRemaining(RemainingRest, `${result}${Remaining}`), () => [result, input]);
20
17
  }
21
18
  function TakeIdent(input) {
22
- const initial = TakeInitial(input);
23
- return (IsResult(initial) ? (() => {
24
- const remaining = TakeRemaining(initial[1]);
25
- return IsResult(remaining)
26
- ? [`${initial[0]}${remaining[0]}`, remaining[1]]
27
- : []; // fail: did not match Remaining
28
- })() : [] // fail: did not match Initial
29
- );
19
+ return Match(TakeInitial(input), (Initial, InitialRest) => Match(TakeRemaining(InitialRest), (Remaining, RemainingRest) => [`${Initial}${Remaining}`, RemainingRest], () => []), // fail: did not match Remaining
20
+ () => []); // fail: did not match Initial
30
21
  }
31
22
  /** Matches if next is an Ident */
32
23
  export function Ident(input) {
@@ -3,7 +3,10 @@ export * from './const.mjs';
3
3
  export * from './ident.mjs';
4
4
  export * from './integer.mjs';
5
5
  export * from './number.mjs';
6
+ export * from './rest.mjs';
6
7
  export * from './span.mjs';
7
8
  export * from './string.mjs';
9
+ export * from './unsigned_integer.mjs';
10
+ export * from './unsigned_number.mjs';
8
11
  export * from './until_1.mjs';
9
12
  export * from './until.mjs';
@@ -3,7 +3,10 @@ export * from './const.mjs';
3
3
  export * from './ident.mjs';
4
4
  export * from './integer.mjs';
5
5
  export * from './number.mjs';
6
+ export * from './rest.mjs';
6
7
  export * from './span.mjs';
7
8
  export * from './string.mjs';
9
+ export * from './unsigned_integer.mjs';
10
+ export * from './unsigned_number.mjs';
8
11
  export * from './until_1.mjs';
9
12
  export * from './until.mjs';
@@ -1,19 +1,11 @@
1
1
  import { type TTrim } from './internal/trim.mjs';
2
- import { type TTake } from './internal/take.mjs';
3
- import { type TMany } from './internal/many.mjs';
4
2
  import { type TOptional } from './internal/optional.mjs';
5
- import { type TDigit } from './internal/char.mjs';
6
3
  import { type THyphen } from './internal/char.mjs';
7
- import { type TZero } from './internal/char.mjs';
8
- import { type TNonZero } from './internal/char.mjs';
9
- import { type TUnderScore } from './internal/char.mjs';
4
+ import { type TUnsignedInteger } from './unsigned_integer.mjs';
10
5
  type TTakeSign<Input extends string> = (TOptional<THyphen, Input>);
11
- type TTakeNonZero<Input extends string> = (TTake<TNonZero, Input>);
12
- type TAllowedDigits = [...TDigit, TUnderScore];
13
- type TTakeDigits<Input extends string> = (TMany<TAllowedDigits, [TUnderScore], Input>);
14
- type TTakeInteger<Input extends string> = (TTakeSign<Input> extends [infer Sign extends string, infer SignRest extends string] ? TTake<[TZero], SignRest> extends [infer Zero extends string, infer ZeroRest extends string] ? [`${Sign}${Zero}`, ZeroRest] : TTakeNonZero<SignRest> extends [infer NonZero extends string, infer NonZeroRest extends string] ? TTakeDigits<NonZeroRest> extends [infer Digits extends string, infer DigitsRest extends string] ? [`${Sign}${NonZero}${Digits}`, DigitsRest] : [] : [] : []);
15
- /** Matches if next is a Integer */
16
- export type TInteger<Input extends string> = (TTakeInteger<TTrim<Input>>);
17
- /** Matches if next is a Integer */
6
+ type TTakeSignedInteger<Input extends string> = (TTakeSign<Input> extends [infer Sign extends string, infer SignRest extends string] ? TUnsignedInteger<SignRest> extends [infer UnsignedInteger extends string, infer UnsignedIntegerRest extends string] ? [`${Sign}${UnsignedInteger}`, UnsignedIntegerRest] : [] : []);
7
+ /** Matches if next is a signed or unsigned Integer */
8
+ export type TInteger<Input extends string> = (TTakeSignedInteger<TTrim<Input>>);
9
+ /** Matches if next is a signed or unsigned Integer */
18
10
  export declare function Integer<Input extends string>(input: Input): TInteger<Input>;
19
11
  export {};
@@ -1,45 +1,19 @@
1
1
  // deno-coverage-ignore-start - parsebox tested
2
2
  // deno-fmt-ignore-file
3
- import { IsResult } from './internal/result.mjs';
3
+ import { Match } from './internal/match.mjs';
4
4
  import { Trim } from './internal/trim.mjs';
5
- import { Take } from './internal/take.mjs';
6
- import { Many } from './internal/many.mjs';
7
5
  import { Optional } from './internal/optional.mjs';
8
- import { Digit } from './internal/char.mjs';
9
6
  import { Hyphen } from './internal/char.mjs';
10
- import { Zero } from './internal/char.mjs';
11
- import { NonZero } from './internal/char.mjs';
12
- import { UnderScore } from './internal/char.mjs';
7
+ import { UnsignedInteger } from './unsigned_integer.mjs';
13
8
  function TakeSign(input) {
14
9
  return Optional(Hyphen, input);
15
10
  }
16
- function TakeNonZero(input) {
17
- return Take(NonZero, input);
11
+ function TakeSignedInteger(input) {
12
+ return Match(TakeSign(input), (Sign, SignRest) => Match(UnsignedInteger(SignRest), (UnsignedInteger, UnsignedIntegerRest) => [`${Sign}${UnsignedInteger}`, UnsignedIntegerRest], () => []), // fail: did not match unsigned integer
13
+ () => []); // fail: did not match Sign
18
14
  }
19
- const AllowedDigits = [...Digit, UnderScore];
20
- function TakeDigits(input) {
21
- return Many(AllowedDigits, [UnderScore], input);
22
- }
23
- function TakeInteger(input) {
24
- const sign = TakeSign(input);
25
- return (IsResult(sign) ? (() => {
26
- const zero = Take([Zero], sign[1]);
27
- return IsResult(zero)
28
- ? [`${sign[0]}${zero[0]}`, zero[1]]
29
- : (() => {
30
- const nonZero = TakeNonZero(sign[1]);
31
- return IsResult(nonZero) ? (() => {
32
- const digits = TakeDigits(nonZero[1]);
33
- return IsResult(digits)
34
- ? [`${sign[0]}${nonZero[0]}${digits[0]}`, digits[1]]
35
- : []; // fail: did not match Digits
36
- })() : []; // fail: did not match NonZero
37
- })();
38
- })() : [] // fail: did not match Sign
39
- );
40
- }
41
- /** Matches if next is a Integer */
15
+ /** Matches if next is a signed or unsigned Integer */
42
16
  export function Integer(input) {
43
- return TakeInteger(Trim(input));
17
+ return TakeSignedInteger(Trim(input));
44
18
  }
45
19
  // deno-coverage-ignore-stop
@@ -1,17 +1,14 @@
1
1
  // deno-coverage-ignore-start - parsebox tested
2
2
  // deno-fmt-ignore-file
3
- import { IsResult } from './result.mjs';
3
+ import { Match } from './match.mjs';
4
4
  import { Take } from './take.mjs';
5
5
  function IsDiscard(discard, input) {
6
6
  return discard.includes(input);
7
7
  }
8
8
  /** Takes characters from the Input until no-match. The Discard set is used to omit characters from the match */
9
9
  export function Many(allowed, discard, input, result = '') {
10
- const takeResult = Take(allowed, input);
11
- return (IsResult(takeResult)
12
- ? IsDiscard(discard, takeResult[0])
13
- ? Many(allowed, discard, takeResult[1], result)
14
- : Many(allowed, discard, takeResult[1], `${result}${takeResult[0]}`)
15
- : [result, input]);
10
+ return Match(Take(allowed, input), (Char, Rest) => IsDiscard(discard, Char)
11
+ ? Many(allowed, discard, Rest, result)
12
+ : Many(allowed, discard, Rest, `${result}${Char}`), () => [result, input]);
16
13
  }
17
14
  // deno-coverage-ignore-stop
@@ -0,0 +1,6 @@
1
+ type TResult = [string, string] | [];
2
+ /** Checks the value is a Tuple-2 [string, string] result */
3
+ export declare function IsMatch(value: TResult): value is [string, string];
4
+ /** Matches on a result and dispatches either left or right arm */
5
+ export declare function Match(input: TResult, ok: (value: string, rest: string) => TResult, fail: () => TResult): TResult;
6
+ export {};
@@ -0,0 +1,11 @@
1
+ // deno-coverage-ignore-start - parsebox tested
2
+ import { IsEqual } from './guard.mjs';
3
+ /** Checks the value is a Tuple-2 [string, string] result */
4
+ export function IsMatch(value) {
5
+ return IsEqual(value.length, 2);
6
+ }
7
+ /** Matches on a result and dispatches either left or right arm */
8
+ export function Match(input, ok, fail) {
9
+ return IsMatch(input) ? ok(input[0], input[1]) : fail();
10
+ }
11
+ // deno-coverage-ignore-stop
@@ -1,12 +1,9 @@
1
1
  // deno-coverage-ignore-start - parsebox tested
2
2
  // deno-fmt-ignore-file
3
- import { IsResult } from './result.mjs';
3
+ import { Match } from './match.mjs';
4
4
  import { Take } from './take.mjs';
5
5
  /** Matches the given Value or empty string if no match. This function never fails */
6
6
  export function Optional(value, input) {
7
- const result = Take([value], input);
8
- return (IsResult(result)
9
- ? result
10
- : ['', input]);
7
+ return Match(Take([value], input), (Optional, Rest) => [Optional, Rest], () => ['', input]);
11
8
  }
12
9
  // deno-coverage-ignore-stop
@@ -1,6 +1,7 @@
1
1
  // deno-coverage-ignore-start - parsebox tested
2
2
  // deno-fmt-ignore-file
3
- import { IsEqual, IsString } from './guard.mjs';
3
+ import { IsMatch } from './match.mjs';
4
+ import { IsEqual } from './guard.mjs';
4
5
  function TakeVariant(variant, input) {
5
6
  return (IsEqual(input.indexOf(variant), 0)
6
7
  ? [variant, input.slice(variant.length)]
@@ -8,12 +9,26 @@ function TakeVariant(variant, input) {
8
9
  }
9
10
  /** Takes one of the given variants or fail */
10
11
  export function Take(variants, input) {
11
- const [left, ...right] = variants;
12
- return (IsString(left)
13
- ? (() => {
14
- const result = TakeVariant(left, input);
15
- return IsEqual(result.length, 2) ? result : Take(right, input);
16
- })()
17
- : []);
12
+ // ----------------------------------------------------------------
13
+ // Symmetric
14
+ // ----------------------------------------------------------------
15
+ // const [left, ...right] = variants
16
+ // return (
17
+ // IsString(left)
18
+ // ? (() => {
19
+ // const result = TakeVariant(left, input)
20
+ // return IsEqual(result.length, 2) ? result : Take(right, input)
21
+ // })()
22
+ // : []
23
+ // ) as never
24
+ // ----------------------------------------------------------------
25
+ // Inline
26
+ // ----------------------------------------------------------------
27
+ for (let i = 0; i < variants.length; i++) {
28
+ const result = TakeVariant(variants[i], input);
29
+ if (IsMatch(result))
30
+ return result;
31
+ }
32
+ return [];
18
33
  }
19
34
  // deno-coverage-ignore-stop
@@ -1,20 +1,11 @@
1
1
  import { type TTrim } from './internal/trim.mjs';
2
- import { type TTake } from './internal/take.mjs';
3
- import { type TMany } from './internal/many.mjs';
4
2
  import { type TOptional } from './internal/optional.mjs';
5
- import { type TDigit, TUnderScore } from './internal/char.mjs';
6
- import { type TDot } from './internal/char.mjs';
7
3
  import { type THyphen } from './internal/char.mjs';
8
- import { type TInteger } from './integer.mjs';
9
- type TAllowedDigits = [...TDigit, TUnderScore];
4
+ import { type TUnsignedNumber } from './unsigned_number.mjs';
10
5
  type TTakeSign<Input extends string> = (TOptional<THyphen, Input>);
11
- type TIsLeadingDot<Input extends string> = (TTake<[TDot], Input> extends [string, string] ? true : false);
12
- type TTakeFractional<Input extends string> = (TMany<TAllowedDigits, [TUnderScore], Input> extends [infer Digits extends string, infer Rest extends string] ? Digits extends '' ? [] : [Digits, Rest] : []);
13
- type TLeadingDot<Sign extends string, Input extends string> = (TTake<[TDot], Input> extends [infer Dot extends string, infer Rest extends string] ? TTakeFractional<Rest> extends [infer Fractional extends string, infer Rest extends string] ? [`${Sign}0${Dot}${Fractional}`, Rest] : [] : []);
14
- type TLeadingInteger<Sign extends string, Input extends string> = (TInteger<Input> extends [infer Integer extends string, infer IntegerRest extends string] ? TTake<[TDot], IntegerRest> extends [infer Dot extends string, infer DotRest extends string] ? TTakeFractional<DotRest> extends [infer Fractional extends string, infer FractionalRest extends string] ? [`${Sign}${Integer}${Dot}${Fractional}`, FractionalRest] : [`${Sign}${Integer}`, DotRest] : [`${Sign}${Integer}`, IntegerRest] : []);
15
- type TTakeNumber<Input extends string> = (TTakeSign<Input> extends [infer Sign extends string, infer SignRest extends string] ? TIsLeadingDot<SignRest> extends true ? TLeadingDot<Sign, SignRest> : TLeadingInteger<Sign, SignRest> : []);
16
- /** Matches if next is a literal Number */
17
- export type TNumber<Input extends string> = (TTakeNumber<TTrim<Input>>);
18
- /** Matches if next is a literal Number */
6
+ type TTakeSignedNumber<Input extends string> = (TTakeSign<Input> extends [infer Sign extends string, infer SignRest extends string] ? TUnsignedNumber<SignRest> extends [infer UnsignedInteger extends string, infer UnsignedIntegerRest extends string] ? [`${Sign}${UnsignedInteger}`, UnsignedIntegerRest] : [] : []);
7
+ /** Matches if next is a signed or unsigned Number */
8
+ export type TNumber<Input extends string> = (TTakeSignedNumber<TTrim<Input>>);
9
+ /** Matches if next is a signed or unsigned Number */
19
10
  export declare function Number<Input extends string>(input: Input): TNumber<Input>;
20
11
  export {};
@@ -1,65 +1,19 @@
1
1
  // deno-coverage-ignore-start - parsebox tested
2
2
  // deno-fmt-ignore-file
3
- import { IsEqual } from './internal/guard.mjs';
4
- import { IsResult } from './internal/result.mjs';
3
+ import { Match } from './internal/match.mjs';
5
4
  import { Trim } from './internal/trim.mjs';
6
- import { Take } from './internal/take.mjs';
7
- import { Many } from './internal/many.mjs';
8
5
  import { Optional } from './internal/optional.mjs';
9
- import { Digit, UnderScore } from './internal/char.mjs';
10
- import { Dot } from './internal/char.mjs';
11
6
  import { Hyphen } from './internal/char.mjs';
12
- import { Integer } from './integer.mjs';
13
- const AllowedDigits = [...Digit, UnderScore];
7
+ import { UnsignedNumber } from './unsigned_number.mjs';
14
8
  function TakeSign(input) {
15
9
  return Optional(Hyphen, input);
16
10
  }
17
- function IsLeadingDot(input) {
18
- return IsResult(Take([Dot], input));
11
+ function TakeSignedNumber(input) {
12
+ return Match(TakeSign(input), (Sign, SignRest) => Match(UnsignedNumber(SignRest), (UnsignedInteger, UnsignedIntegerRest) => [`${Sign}${UnsignedInteger}`, UnsignedIntegerRest], () => []), // fail: did not match unsigned integer
13
+ () => []); // fail: did not match Sign
19
14
  }
20
- function TakeFractional(input) {
21
- const digits = Many(AllowedDigits, [UnderScore], input);
22
- return (IsResult(digits)
23
- ? IsEqual(digits[0], '')
24
- ? [] // fail: no Digits
25
- : [digits[0], digits[1]]
26
- : [] // fail: did not match Digits
27
- );
28
- }
29
- function LeadingDot(sign, input) {
30
- const dot = Take([Dot], input);
31
- return (IsResult(dot) ? (() => {
32
- const fractional = TakeFractional(dot[1]);
33
- return IsResult(fractional)
34
- ? [`${sign}0${dot[0]}${fractional[0]}`, fractional[1]]
35
- : []; // fail: did not match Fractional
36
- })() : [] // fail: did not match Dot
37
- );
38
- }
39
- function LeadingInteger(sign, input) {
40
- const integer = Integer(input);
41
- return (IsResult(integer) ? (() => {
42
- const dot = Take([Dot], integer[1]);
43
- return IsResult(dot) ? (() => {
44
- const fractional = TakeFractional(dot[1]);
45
- return IsResult(fractional)
46
- ? [`${sign}${integer[0]}${dot[0]}${fractional[0]}`, fractional[1]]
47
- : [`${sign}${integer[0]}`, dot[1]]; // fail: did not match Fractional, use Integer
48
- })() : [`${sign}${integer[0]}`, integer[1]]; // fail: did not match Dot, use Integer
49
- })() : [] // fail: did not match Integer
50
- );
51
- }
52
- function TakeNumber(input) {
53
- const sign = TakeSign(input);
54
- return (IsResult(sign)
55
- ? IsLeadingDot(sign[1])
56
- ? LeadingDot(sign[0], sign[1])
57
- : LeadingInteger(sign[0], sign[1])
58
- : [] // fail: did not match Sign
59
- );
60
- }
61
- /** Matches if next is a literal Number */
15
+ /** Matches if next is a signed or unsigned Number */
62
16
  export function Number(input) {
63
- return TakeNumber(Trim(input));
17
+ return TakeSignedNumber(Trim(input));
64
18
  }
65
19
  // deno-coverage-ignore-stop
@@ -0,0 +1,4 @@
1
+ /** Match remaining characters in the buffer until end. If no characters are in buffer, no match */
2
+ export type TRest<Input extends string> = (Input extends '' ? [] : [Input, '']);
3
+ /** Match remaining characters in the buffer until end. If no characters are in buffer, no match */
4
+ export declare function Rest<Input extends string>(input: Input): TRest<Input>;
@@ -0,0 +1,9 @@
1
+ // deno-coverage-ignore-start - parsebox tested
2
+ // deno-fmt-ignore-file
3
+ import { IsEqual } from './internal/guard.mjs';
4
+ /** Match remaining characters in the buffer until end. If no characters are in buffer, no match */
5
+ export function Rest(input) {
6
+ const result = IsEqual(input, '') ? [] : [input, ''];
7
+ return result;
8
+ }
9
+ // deno-coverage-ignore-stop
@@ -1,8 +1,9 @@
1
1
  import { type TTrim } from './internal/trim.mjs';
2
2
  import { type TNewLine } from './internal/char.mjs';
3
+ import { type TTake } from './internal/take.mjs';
3
4
  import { type TUntil } from './until.mjs';
4
- type TMultiLine<Start extends string, End extends string, Input extends string> = (Input extends `${Start}${infer Rest extends string}` ? TUntil<[End], Rest> extends [infer Until extends string, infer UntilRest extends string] ? UntilRest extends `${End}${infer Rest extends string}` ? [`${Until}`, Rest] : [] : [] : []);
5
- type TSingleLine<Start extends string, End extends string, Input extends string> = (Input extends `${Start}${infer Rest extends string}` ? TUntil<[TNewLine, End], Rest> extends [infer Until extends string, infer UntilRest extends string] ? UntilRest extends `${End}${infer EndRest extends string}` ? [`${Until}`, EndRest] : [] : [] : []);
5
+ type TMultiLine<Start extends string, End extends string, Input extends string> = (TTake<[Start], Input> extends [infer _, infer Rest extends string] ? TUntil<[End], Rest> extends [infer Until extends string, infer UntilRest extends string] ? TTake<[End], UntilRest> extends [infer _ extends string, infer Rest extends string] ? [`${Until}`, Rest] : [] : [] : []);
6
+ type TSingleLine<Start extends string, End extends string, Input extends string> = (TTake<[Start], Input> extends [infer _ extends string, infer Rest extends string] ? TUntil<[TNewLine, End], Rest> extends [infer Until extends string, infer UntilRest extends string] ? TTake<[End], UntilRest> extends [infer _ extends string, infer EndRest extends string] ? [`${Until}`, EndRest] : [] : [] : []);
6
7
  /** Matches from Start and End capturing everything in-between. Start and End are consumed. */
7
8
  export type TSpan<Start extends string, End extends string, MultiLine extends boolean, Input extends string> = (MultiLine extends true ? TMultiLine<Start, End, TTrim<Input>> : TSingleLine<Start, End, TTrim<Input>>);
8
9
  /** Matches from Start and End capturing everything in-between. Start and End are consumed. */
@@ -1,30 +1,19 @@
1
1
  // deno-coverage-ignore-start - parsebox tested
2
2
  // deno-fmt-ignore-file
3
- import { IsResult } from './internal/result.mjs';
3
+ import { Match } from './internal/match.mjs';
4
4
  import { Trim } from './internal/trim.mjs';
5
5
  import { NewLine } from './internal/char.mjs';
6
+ import { Take } from './internal/take.mjs';
6
7
  import { Until } from './until.mjs';
7
8
  function MultiLine(start, end, input) {
8
- return (input.startsWith(start) ? (() => {
9
- const until = Until([end], input.slice(start.length));
10
- return IsResult(until) ? (() => {
11
- return until[1].startsWith(end)
12
- ? [`${until[0]}`, until[1].slice(end.length)]
13
- : []; // fail: did not match End
14
- })() : []; // fail: did not match Until
15
- })() : [] // fail: did not match Start
16
- );
9
+ return Match(Take([start], input), (_, Rest) => Match(Until([end], Rest), (Until, UntilRest) => Match(Take([end], UntilRest), (_, Rest) => [`${Until}`, Rest], () => []), // fail: did not match End
10
+ () => []), // fail: did not match Until
11
+ () => []); // fail: did not match Start
17
12
  }
18
13
  function SingleLine(start, end, input) {
19
- return (input.startsWith(start) ? (() => {
20
- const until = Until([NewLine, end], input.slice(start.length));
21
- return IsResult(until) ? (() => {
22
- return until[1].startsWith(end)
23
- ? [`${until[0]}`, until[1].slice(end.length)]
24
- : []; // fail: did not match End
25
- })() : []; // fail: did not match Until
26
- })() : [] // fail: not match Start
27
- );
14
+ return Match(Take([start], input), (_, Rest) => Match(Until([NewLine, end], Rest), (Until, UntilRest) => Match(Take([end], UntilRest), (_, EndRest) => [`${Until}`, EndRest], () => []), // fail: did not match End
15
+ () => []), // fail: did not match Until
16
+ () => []); // fail: not match Start
28
17
  }
29
18
  /** Matches from Start and End capturing everything in-between. Start and End are consumed. */
30
19
  export function Span(start, end, multiLine, input) {
@@ -1,6 +1,6 @@
1
1
  // deno-coverage-ignore-start - parsebox tested
2
2
  // deno-fmt-ignore-file
3
- import { IsResult } from './internal/result.mjs';
3
+ import { Match } from './internal/match.mjs';
4
4
  import { Take } from './internal/take.mjs';
5
5
  import { Trim } from './internal/trim.mjs';
6
6
  import { Span } from './span.mjs';
@@ -11,11 +11,7 @@ function TakeSpan(quote, input) {
11
11
  return Span(quote, quote, false, input);
12
12
  }
13
13
  function TakeString(quotes, input) {
14
- const initial = TakeInitial(quotes, input);
15
- return (IsResult(initial)
16
- ? TakeSpan(initial[0], `${initial[0]}${initial[1]}`)
17
- : [] // fail: did not match Initial
18
- );
14
+ return Match(TakeInitial(quotes, input), (Initial, InitialRest) => TakeSpan(Initial, `${Initial}${InitialRest}`), () => []); // fail: did not match Initial
19
15
  }
20
16
  /** Matches a literal String with the given quotes */
21
17
  export function String(quotes, input) {
@@ -0,0 +1,16 @@
1
+ import { type TTrim } from './internal/trim.mjs';
2
+ import { type TTake } from './internal/take.mjs';
3
+ import { type TMany } from './internal/many.mjs';
4
+ import { type TDigit } from './internal/char.mjs';
5
+ import { type TZero } from './internal/char.mjs';
6
+ import { type TNonZero } from './internal/char.mjs';
7
+ import { type TUnderScore } from './internal/char.mjs';
8
+ type TTakeNonZero<Input extends string> = (TTake<TNonZero, Input>);
9
+ type TAllowedDigits = [...TDigit, TUnderScore];
10
+ type TTakeDigits<Input extends string> = (TMany<TAllowedDigits, [TUnderScore], Input>);
11
+ type TTakeUnsignedInteger<Input extends string> = (TTake<[TZero], Input> extends [infer Zero extends string, infer ZeroRest extends string] ? [Zero, ZeroRest] : TTakeNonZero<Input> extends [infer NonZero extends string, infer NonZeroRest extends string] ? TTakeDigits<NonZeroRest> extends [infer Digits extends string, infer DigitsRest extends string] ? [`${NonZero}${Digits}`, DigitsRest] : [] : []);
12
+ /** Matches if next is a UnsignedInteger */
13
+ export type TUnsignedInteger<Input extends string> = (TTakeUnsignedInteger<TTrim<Input>>);
14
+ /** Matches if next is a UnsignedInteger */
15
+ export declare function UnsignedInteger<Input extends string>(input: Input): TUnsignedInteger<Input>;
16
+ export {};
@@ -0,0 +1,26 @@
1
+ // deno-coverage-ignore-start - parsebox tested
2
+ // deno-fmt-ignore-file
3
+ import { Match } from './internal/match.mjs';
4
+ import { Trim } from './internal/trim.mjs';
5
+ import { Take } from './internal/take.mjs';
6
+ import { Many } from './internal/many.mjs';
7
+ import { Digit } from './internal/char.mjs';
8
+ import { Zero } from './internal/char.mjs';
9
+ import { NonZero } from './internal/char.mjs';
10
+ import { UnderScore } from './internal/char.mjs';
11
+ function TakeNonZero(input) {
12
+ return Take(NonZero, input);
13
+ }
14
+ const AllowedDigits = [...Digit, UnderScore];
15
+ function TakeDigits(input) {
16
+ return Many(AllowedDigits, [UnderScore], input);
17
+ }
18
+ function TakeUnsignedInteger(input) {
19
+ return Match(Take([Zero], input), (Zero, ZeroRest) => [Zero, ZeroRest], () => Match(TakeNonZero(input), (NonZero, NonZeroRest) => Match(TakeDigits(NonZeroRest), (Digits, DigitsRest) => [`${NonZero}${Digits}`, DigitsRest], () => []), // fail: did not match Digits
20
+ () => [])); // fail: did not match NonZero
21
+ }
22
+ /** Matches if next is a UnsignedInteger */
23
+ export function UnsignedInteger(input) {
24
+ return TakeUnsignedInteger(Trim(input));
25
+ }
26
+ // deno-coverage-ignore-stop
@@ -0,0 +1,17 @@
1
+ import { type TTrim } from './internal/trim.mjs';
2
+ import { type TTake } from './internal/take.mjs';
3
+ import { type TMany } from './internal/many.mjs';
4
+ import { type TDigit, type TUnderScore } from './internal/char.mjs';
5
+ import { type TDot } from './internal/char.mjs';
6
+ import { type TUnsignedInteger } from './unsigned_integer.mjs';
7
+ type TAllowedDigits = [...TDigit, TUnderScore];
8
+ type TIsLeadingDot<Input extends string> = (TTake<[TDot], Input> extends [string, string] ? true : false);
9
+ type TTakeFractional<Input extends string> = (TMany<TAllowedDigits, [TUnderScore], Input> extends [infer Digits extends string, infer DigitsRest extends string] ? Digits extends '' ? [] : [Digits, DigitsRest] : []);
10
+ type TLeadingDot<Input extends string> = (TTake<[TDot], Input> extends [infer Dot extends string, infer DotRest extends string] ? TTakeFractional<DotRest> extends [infer Fractional extends string, infer FractionalRest extends string] ? [`0${Dot}${Fractional}`, FractionalRest] : [] : []);
11
+ type TLeadingInteger<Input extends string> = (TUnsignedInteger<Input> extends [infer Integer extends string, infer IntegerRest extends string] ? TTake<[TDot], IntegerRest> extends [infer Dot extends string, infer DotRest extends string] ? TTakeFractional<DotRest> extends [infer Fractional extends string, infer FractionalRest extends string] ? [`${Integer}${Dot}${Fractional}`, FractionalRest] : [`${Integer}`, DotRest] : [`${Integer}`, IntegerRest] : []);
12
+ type TTakeUnsignedNumber<Input extends string> = (TIsLeadingDot<Input> extends true ? TLeadingDot<Input> : TLeadingInteger<Input>);
13
+ /** Matches if next is a UnsignedNumber */
14
+ export type TUnsignedNumber<Input extends string> = (TTakeUnsignedNumber<TTrim<Input>>);
15
+ /** Matches if next is a UnsignedNumber */
16
+ export declare function UnsignedNumber<Input extends string>(input: Input): TUnsignedNumber<Input>;
17
+ export {};
@@ -0,0 +1,38 @@
1
+ // deno-coverage-ignore-start - parsebox tested
2
+ // deno-fmt-ignore-file
3
+ import { IsEqual } from './internal/guard.mjs';
4
+ import { IsMatch, Match } from './internal/match.mjs';
5
+ import { Trim } from './internal/trim.mjs';
6
+ import { Take } from './internal/take.mjs';
7
+ import { Many } from './internal/many.mjs';
8
+ import { Digit, UnderScore } from './internal/char.mjs';
9
+ import { Dot } from './internal/char.mjs';
10
+ import { UnsignedInteger } from './unsigned_integer.mjs';
11
+ const AllowedDigits = [...Digit, UnderScore];
12
+ function IsLeadingDot(input) {
13
+ return IsMatch(Take([Dot], input));
14
+ }
15
+ function TakeFractional(input) {
16
+ return Match(Many(AllowedDigits, [UnderScore], input), (Digits, DigitsRest) => IsEqual(Digits, '')
17
+ ? [] // fail: no Digits
18
+ : [Digits, DigitsRest], () => []); // fail: did not match Digits
19
+ }
20
+ function LeadingDot(input) {
21
+ return Match(Take([Dot], input), (Dot, DotRest) => Match(TakeFractional(DotRest), (Fractional, FractionalRest) => [`0${Dot}${Fractional}`, FractionalRest], () => []), // fail: did not match Fractional
22
+ () => []); // fail: did not match Dot
23
+ }
24
+ function LeadingInteger(input) {
25
+ return Match(UnsignedInteger(input), (Integer, IntegerRest) => Match(Take([Dot], IntegerRest), (Dot, DotRest) => Match(TakeFractional(DotRest), (Fractional, FractionalRest) => [`${Integer}${Dot}${Fractional}`, FractionalRest], () => [`${Integer}`, DotRest]), // fail: did not match Fractional, use Integer
26
+ () => [`${Integer}`, IntegerRest]), // fail: did not match Dot, use Integer
27
+ () => []); // fail: did not match Integer
28
+ }
29
+ function TakeUnsignedNumber(input) {
30
+ return (IsLeadingDot(input)
31
+ ? LeadingDot(input)
32
+ : LeadingInteger(input));
33
+ }
34
+ /** Matches if next is a UnsignedNumber */
35
+ export function UnsignedNumber(input) {
36
+ return TakeUnsignedNumber(Trim(input));
37
+ }
38
+ // deno-coverage-ignore-stop
@@ -1,6 +1,7 @@
1
- type TIsEnd<End extends string[], Input extends string> = (End extends [infer Left extends string, ...infer Right extends string[]] ? Input extends `${Left}${string}` ? true : TIsEnd<Right, Input> : false);
1
+ type TTakeOne<Input extends string> = (Input extends `${infer Left extends string}${infer Right extends string}` ? [Left, Right] : []);
2
+ type TIsInputMatchSentinal<End extends string[], Input extends string> = (End extends [infer Left extends string, ...infer Right extends string[]] ? Input extends `${Left}${string}` ? true : TIsInputMatchSentinal<Right, Input> : false);
2
3
  /** Match Input until but not including End. No match if End not found. */
3
- export type TUntil<End extends string[], Input extends string, Result extends string = ''> = (Input extends `` ? [] : TIsEnd<End, Input> extends true ? [Result, Input] : Input extends `${infer Left extends string}${infer Right extends string}` ? TUntil<End, Right, `${Result}${Left}`> : []);
4
+ export type TUntil<End extends string[], Input extends string, Result extends string = ''> = (TTakeOne<Input> extends [infer One extends string, infer Rest extends string] ? TIsInputMatchSentinal<End, Input> extends true ? [Result, Input] : TUntil<End, Rest, `${Result}${One}`> : []);
4
5
  /** Match Input until but not including End. No match if End not found. */
5
6
  export declare function Until<End extends string[], Input extends string>(end: [...End], input: Input, result?: string): TUntil<End, Input>;
6
7
  export {};
@@ -1,21 +1,24 @@
1
1
  // deno-coverage-ignore-start - parsebox tested
2
2
  // deno-fmt-ignore-file
3
+ import { Match } from './internal/match.mjs';
3
4
  import { IsEqual, IsString } from './internal/guard.mjs';
4
- function IsEnd(end, input) {
5
+ function TakeOne(input) {
6
+ const result = IsEqual(input, '') ? [] : [input.slice(0, 1), input.slice(1)];
7
+ return result;
8
+ }
9
+ function IsInputMatchSentinal(end, input) {
5
10
  const [left, ...right] = end;
6
11
  return (IsString(left)
7
12
  ? input.startsWith(left)
8
13
  ? true
9
- : IsEnd(right, input)
14
+ : IsInputMatchSentinal(right, input)
10
15
  : false);
11
16
  }
12
17
  /** Match Input until but not including End. No match if End not found. */
13
18
  export function Until(end, input, result = '') {
14
- return (IsEqual(input, '')
15
- ? [] // fail: Input is empty
16
- : IsEnd(end, input) ? [result, input] : (() => {
17
- const [left, right] = [input.slice(0, 1), input.slice(1)];
18
- return Until(end, right, `${result}${left}`);
19
- })());
19
+ return Match(TakeOne(input), (One, Rest) => IsInputMatchSentinal(end, input)
20
+ ? [result, input] // ok: at sentinal
21
+ : Until(end, Rest, `${result}${One}`) // fail: advance + 1
22
+ , () => []);
20
23
  }
21
24
  // deno-coverage-ignore-stop
@@ -1,16 +1,12 @@
1
1
  // deno-coverage-ignore-start - parsebox tested
2
2
  // deno-fmt-ignore-file
3
3
  import { IsEqual } from './internal/guard.mjs';
4
- import { IsResult } from './internal/result.mjs';
4
+ import { Match } from './internal/match.mjs';
5
5
  import { Until } from './until.mjs';
6
6
  /** Match Input until but not including End. No match if End not found or match is zero-length. */
7
7
  export function Until_1(end, input) {
8
- const until = Until(end, input);
9
- return (IsResult(until)
10
- ? IsEqual(until[0], '')
11
- ? [] // fail: match has no characters
12
- : until
13
- : [] // fail: did not match Until
14
- );
8
+ return Match(Until(end, input), (Until, UntilRest) => IsEqual(Until, '')
9
+ ? [] // fail: match has no characters
10
+ : [Until, UntilRest], () => []); // fail: did not match Until
15
11
  }
16
12
  // deno-coverage-ignore-stop
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "typebox",
3
3
  "description": "Json Schema Type Builder with Static Type Resolution for TypeScript",
4
- "version": "1.1.6",
4
+ "version": "1.1.8",
5
5
  "keywords": [
6
6
  "typescript",
7
7
  "jsonschema"
@@ -16,38 +16,38 @@
16
16
  "types": "./build/index.d.mts",
17
17
  "module": "./build/index.mjs",
18
18
  "exports": {
19
- "./type": {
20
- "import": "./build/type/index.mjs",
21
- "default": "./build/type/index.mjs"
22
- },
23
- "./value": {
24
- "import": "./build/value/index.mjs",
25
- "default": "./build/value/index.mjs"
26
- },
27
- "./guard": {
28
- "import": "./build/guard/index.mjs",
29
- "default": "./build/guard/index.mjs"
30
- },
31
19
  "./system": {
32
20
  "import": "./build/system/index.mjs",
33
21
  "default": "./build/system/index.mjs"
34
22
  },
35
- "./format": {
36
- "import": "./build/format/index.mjs",
37
- "default": "./build/format/index.mjs"
38
- },
39
23
  "./compile": {
40
24
  "import": "./build/compile/index.mjs",
41
25
  "default": "./build/compile/index.mjs"
42
26
  },
27
+ "./value": {
28
+ "import": "./build/value/index.mjs",
29
+ "default": "./build/value/index.mjs"
30
+ },
43
31
  "./error": {
44
32
  "import": "./build/error/index.mjs",
45
33
  "default": "./build/error/index.mjs"
46
34
  },
35
+ "./guard": {
36
+ "import": "./build/guard/index.mjs",
37
+ "default": "./build/guard/index.mjs"
38
+ },
47
39
  "./schema": {
48
40
  "import": "./build/schema/index.mjs",
49
41
  "default": "./build/schema/index.mjs"
50
42
  },
43
+ "./format": {
44
+ "import": "./build/format/index.mjs",
45
+ "default": "./build/format/index.mjs"
46
+ },
47
+ "./type": {
48
+ "import": "./build/type/index.mjs",
49
+ "default": "./build/type/index.mjs"
50
+ },
51
51
  ".": {
52
52
  "import": "./build/index.mjs",
53
53
  "default": "./build/index.mjs"
@@ -55,30 +55,30 @@
55
55
  },
56
56
  "typesVersions": {
57
57
  "*": {
58
- "type": [
59
- "./build/type/index.d.mts"
60
- ],
61
- "value": [
62
- "./build/value/index.d.mts"
63
- ],
64
- "guard": [
65
- "./build/guard/index.d.mts"
66
- ],
67
58
  "system": [
68
59
  "./build/system/index.d.mts"
69
60
  ],
70
- "format": [
71
- "./build/format/index.d.mts"
72
- ],
73
61
  "compile": [
74
62
  "./build/compile/index.d.mts"
75
63
  ],
64
+ "value": [
65
+ "./build/value/index.d.mts"
66
+ ],
76
67
  "error": [
77
68
  "./build/error/index.d.mts"
78
69
  ],
70
+ "guard": [
71
+ "./build/guard/index.d.mts"
72
+ ],
79
73
  "schema": [
80
74
  "./build/schema/index.d.mts"
81
75
  ],
76
+ "format": [
77
+ "./build/format/index.d.mts"
78
+ ],
79
+ "type": [
80
+ "./build/type/index.d.mts"
81
+ ],
82
82
  ".": [
83
83
  "./build/index.d.mts"
84
84
  ]
package/readme.md CHANGED
@@ -57,12 +57,11 @@ License: MIT
57
57
 
58
58
  ## Contents
59
59
 
60
-
61
60
  - [Type](#Type)
62
61
  - [Value](#Value)
63
62
  - [Script](#Script)
64
63
  - [Schema](#Schema)
65
- - [Legacy](#Legacy)
64
+ - [Versions](#Versions)
66
65
  - [Contribute](#Contribute)
67
66
 
68
67
 
@@ -70,7 +69,7 @@ License: MIT
70
69
 
71
70
  ## Type
72
71
 
73
- [Documentation](https://sinclairzx81.github.io/typebox/#/docs/type/overview) | [Example](https://tsplay.dev/NaMoBN)
72
+ [Documentation](https://sinclairzx81.github.io/typebox/#/docs/type/overview)
74
73
 
75
74
  TypeBox provides many functions to create JSON Schema types. Each function returns a small JSON Schema fragment that can be composed into more complex types. TypeBox includes a set of functions that are used to construct JSON Schema compliant schematics as well as a set of extended functions that return schematics for constructs native to JavaScript.
76
75
 
@@ -117,7 +116,7 @@ const S = Type.Number({ // const S = {
117
116
 
118
117
  ## Value
119
118
 
120
- [Documentation](https://sinclairzx81.github.io/typebox/#/docs/value/overview) | [Example](https://tsplay.dev/W4YE1w)
119
+ [Documentation](https://sinclairzx81.github.io/typebox/#/docs/value/overview)
121
120
 
122
121
  The Value submodule provides functions for validation and other typed operations on JavaScript values. It includes functions such as Check, Parse, Clone, Encode, and Decode, as well as advanced functions for performing structural Diff and Patch operations on dynamic JavaScript values.
123
122
 
@@ -145,7 +144,7 @@ const A = Value.Parse(T, { // const A: {
145
144
 
146
145
  ## Script
147
146
 
148
- [Documentation](https://sinclairzx81.github.io/typebox/#/docs/script/overview) | [Example 1](https://tsplay.dev/N9rQ8m) | [Example 2](https://tsplay.dev/NnrJoN)
147
+ [Documentation](https://sinclairzx81.github.io/typebox/#/docs/script/overview)
149
148
 
150
149
  TypeBox includes a runtime TypeScript DSL engine that can transform TypeScript syntax into JSON Schema. The engine is implemented at runtime and within the TypeScript type system.
151
150
 
@@ -223,62 +222,31 @@ const R = C.Parse({ x: 0, y: 0, z: 0 }) // const R: {
223
222
  // } = ...
224
223
  ```
225
224
 
226
- ## Legacy
227
-
228
- If upgrading from `@sinclair/typebox` 0.34.x refer to the 1.0 migration guide at the following URL.
229
-
230
- [Migration Guide](https://github.com/sinclairzx81/typebox/blob/main/changelog/1.0.0-migration.md)
225
+ <a name="Versions"></a>
231
226
 
232
- Most types created with 0.34.x are compatible with V1, and it is possible to run both `typebox` and `@sinclair/typebox` packages side by side.
233
-
234
- [Compatibility](https://tsplay.dev/Wzr2rW)
235
-
236
- ```typescript
237
- import { Type } from '@sinclair/typebox' // TB: 0.34.x
238
- import { Static } from 'typebox' // TB: 1.0.0
227
+ ## Versions
239
228
 
240
- // ----------------------------------------------------------
241
- // Legacy Types
242
- // ----------------------------------------------------------
243
- const A = Type.Object({
244
- x: Type.Number(),
245
- y: Type.Number(),
246
- z: Type.Number()
247
- })
229
+ TypeBox provides two distinct versions that span two generations of the TypeScript compiler.
248
230
 
249
- const B = Type.Object({
250
- a: Type.Number(),
251
- b: Type.Number(),
252
- c: Type.Number()
253
- })
231
+ ### Version 0.x
254
232
 
255
- const C = Type.Composite([A, B])
233
+ ```bash
234
+ $ npm install @sinclair/typebox # 0.x - LTS | TS 4-6
235
+ ```
256
236
 
257
- // ----------------------------------------------------------
258
- // Modern Inference
259
- // ----------------------------------------------------------
260
- type C = Static<typeof C> // type C = {
261
- // x: number;
262
- // y: number;
263
- // z: number;
264
- // a: number;
265
- // b: number;
266
- // c: number;
267
- // }
237
+ Developed against TypeScript 4-6 and maintained under Long Term Support (LTS) for existing infrastructure on the 0.x revision line. ESM and CJS compatible.
268
238
 
269
- // ----------------------------------------------------------
270
- // Modern Compile
271
- // ----------------------------------------------------------
272
- import Schema from 'typebox/schema'
239
+ ### Version 1.x
273
240
 
274
- const R = Schema.Compile(C).Check({ ... })
241
+ ```bash
242
+ $ npm install typebox # 1.x - Latest | TS 7 Native
275
243
  ```
276
244
 
277
- Revision 0.34.x is actively maintained at the following URL.
245
+ Developed against the TypeScript 7 native compiler with advanced type inference and JSON Schema 2020-12 compliant validation, with backwards compatibility for `0.x` types. ESM only.
278
246
 
279
- [TypeBox 0.34.x](https://github.com/sinclairzx81/typebox-legacy)
247
+ ### Additional
280
248
 
281
- Please submit non-1.0 issues to this repository.
249
+ The `1.x` version is recommended for most new projects and is the active development line that targets optimizations enabled by the TypeScript 7 native compiler. The `0.x` version is maintained under LTS for environments requiring CJS and ESM compatibility as well as support for older TypeScript compiler versions. For issues relating to `0.x` please submit them to the [TypeBox 0.x](https://github.com/sinclairzx81/sinclair-typebox) repository.
282
250
 
283
251
  ## Contribute
284
252
 
@@ -1,2 +0,0 @@
1
- /** Checks the value is a Tuple-2 [string, string] result */
2
- export declare function IsResult(value: unknown): value is [string, string];
@@ -1,7 +0,0 @@
1
- // deno-coverage-ignore-start - parsebox tested
2
- import { IsArray, IsEqual } from './guard.mjs';
3
- /** Checks the value is a Tuple-2 [string, string] result */
4
- export function IsResult(value) {
5
- return IsArray(value) && IsEqual(value.length, 2);
6
- }
7
- // deno-coverage-ignore-stop