diff --git a/.vscode/settings.json b/.vscode/settings.json index dc01a7b..fd4665b 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -4,5 +4,6 @@ "node_modules": true, "package-lock.json": true }, - "deno.enable": true + "deno.enable": true, + "deno.lint": false, } \ No newline at end of file diff --git a/deno.json b/deno.json deleted file mode 100644 index b27ba6c..0000000 --- a/deno.json +++ /dev/null @@ -1,23 +0,0 @@ -{ - "tasks": { - "clean": "deno run -A tasks.ts clean", - "format": "deno run -A tasks.ts format", - "start": "deno run -A tasks.ts start", - "test": "deno run -A tasks.ts test", - "build": "deno run -A tasks.ts build", - "publish": "deno run -A tasks.ts publish" - }, - "imports": { - "@sinclair/parsebox": "./src/index.ts" - }, - "fmt": { - "lineWidth": 240, - "semiColons": false - }, - "exclude": [ - "target/**" - ], - "compilerOptions": { - "strict": true - } -} \ No newline at end of file diff --git a/deno.jsonc b/deno.jsonc new file mode 100644 index 0000000..f0db3c0 --- /dev/null +++ b/deno.jsonc @@ -0,0 +1,30 @@ +{ + "tasks": { + "clean": "deno run -A tasks.ts clean", + "format": "deno run -A tasks.ts format", + "start": "deno run -A tasks.ts start", + "test": "deno run -A tasks.ts test", + "report": "deno run -A tasks.ts report", + "build": "deno run -A tasks.ts build", + "publish": "deno run -A tasks.ts publish" + }, + "imports": { + // -------------------------------------------------------------- + // Tasksmith + // -------------------------------------------------------------- + "tasksmith": "https://raw.githubusercontent.com/sinclairzx81/tasksmith/0.8.5/src/index.ts", + "test": "./test/common/index.ts", + // -------------------------------------------------------------- + // ParseBox + // -------------------------------------------------------------- + "@sinclair/parsebox": "./src/index.ts" + }, + "fmt": { + "lineWidth": 240, + "semiColons": false, + "singleQuote": true + }, + "compilerOptions": { + "strict": true + } +} \ No newline at end of file diff --git a/deno.lock b/deno.lock index afce2bc..a77b2cd 100644 --- a/deno.lock +++ b/deno.lock @@ -4,7 +4,8 @@ "jsr:@std/assert@*": "1.0.12", "jsr:@std/internal@^1.0.6": "1.0.6", "jsr:@std/path@1.0.8": "1.0.8", - "npm:@sinclair/typebox@*": "0.34.33" + "npm:@sinclair/typebox@*": "0.34.33", + "npm:@types/node@*": "22.15.15" }, "jsr": { "@std/assert@1.0.12": { @@ -23,6 +24,15 @@ "npm": { "@sinclair/typebox@0.34.33": { "integrity": "sha512-5HAV9exOMcXRUxo+9iYB5n09XxzCXnfy4VTNW4xnDv+FgjzAGY989C28BIdljKqmF+ZltUwujE3aossvcVtq6g==" + }, + "@types/node@22.15.15": { + "integrity": "sha512-R5muMcZob3/Jjchn5LcO8jdKwSCbzqmPB6ruBxMcf9kbxtniZHP327s6C37iOfuw8mbKK3cAQa7sEl7afLrQ8A==", + "dependencies": [ + "undici-types" + ] + }, + "undici-types@6.21.0": { + "integrity": "sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==" } }, "remote": { @@ -98,6 +108,67 @@ "https://raw.githubusercontent.com/sinclairzx81/tasksmith/0.8.2/src/shell/shell.ts": "736ae813e84a300650af3fbcb632518b6978bf0a0f2d32f0b69a7248310ab1f2", "https://raw.githubusercontent.com/sinclairzx81/tasksmith/0.8.2/src/task.ts": "8346009a1032f4ffcf44b2d587db562c7949e74694cf9367b10db6489085d5f3", "https://raw.githubusercontent.com/sinclairzx81/tasksmith/0.8.2/src/tsc/index.ts": "c8b602ebe53807b894852c07a461b4b5cbf4dd54f728d82c57f64b207c4819ce", - "https://raw.githubusercontent.com/sinclairzx81/tasksmith/0.8.2/src/tsc/tsc.ts": "890cac855658225d3dbcd57658ab44f65932446fe5632cb1818b1095f5c1e936" + "https://raw.githubusercontent.com/sinclairzx81/tasksmith/0.8.2/src/tsc/tsc.ts": "890cac855658225d3dbcd57658ab44f65932446fe5632cb1818b1095f5c1e936", + "https://raw.githubusercontent.com/sinclairzx81/tasksmith/0.8.5/src/attw/attw.ts": "b38274f4ff1e4f0ee5b9b5eba37f90422db7f05472864c2a0659b3e94bc175e5", + "https://raw.githubusercontent.com/sinclairzx81/tasksmith/0.8.5/src/attw/index.ts": "a76b99adbfaee3416ea98f2a5908b76c846e0fbf0768876ed93d1e8aa21a8cff", + "https://raw.githubusercontent.com/sinclairzx81/tasksmith/0.8.5/src/browser/browser.ts": "42b3060763be9ce26b262ddf4a80b570319a1c511be39a5403e1f95b098b5589", + "https://raw.githubusercontent.com/sinclairzx81/tasksmith/0.8.5/src/browser/index.ts": "4f3c2075e4337f76b83b0a60dec0e7df8b35cb4676d459bb49661ba7d4486789", + "https://raw.githubusercontent.com/sinclairzx81/tasksmith/0.8.5/src/browser/open.ts": "21ca30d157f320c3d2523f82a334a9239d2c40f495b8948d2591743fc21ab3cf", + "https://raw.githubusercontent.com/sinclairzx81/tasksmith/0.8.5/src/build/build.ts": "4cdd0a451316cba2daeb250b5b2fe7f51b9ae6d84442c94324cd19f933eceb18", + "https://raw.githubusercontent.com/sinclairzx81/tasksmith/0.8.5/src/build/common/build-additional.ts": "fe002fcf75846eb7b4503d7d10bfbd3d8d1b5b276dde1b5bba67541c334f147f", + "https://raw.githubusercontent.com/sinclairzx81/tasksmith/0.8.5/src/build/common/build-clean.ts": "622b2b852ab3210c6bba4664033719c1cb9222d6d05a009ad0eb558158dc70f6", + "https://raw.githubusercontent.com/sinclairzx81/tasksmith/0.8.5/src/build/common/build-pack.ts": "66ca147340ee33b9e5f5dc16dc6a0469abb6597a190841564a529750a0389436", + "https://raw.githubusercontent.com/sinclairzx81/tasksmith/0.8.5/src/build/dual/build-check.ts": "304f714a1ff14e2f08e70dd222bbab08fec57c1be8dfbe06d4295763cddc7bf0", + "https://raw.githubusercontent.com/sinclairzx81/tasksmith/0.8.5/src/build/dual/build-cjs.ts": "4a0fb1400b127774e1dd607aaa53eb717505c42c2f176abd3cb412fe387409cd", + "https://raw.githubusercontent.com/sinclairzx81/tasksmith/0.8.5/src/build/dual/build-esm.ts": "a6708e42dea7ab61eccf7181f1b9335e7140608e027568ed4f859273de2b1faa", + "https://raw.githubusercontent.com/sinclairzx81/tasksmith/0.8.5/src/build/dual/build-package-json.ts": "b2e71910f94826ce95eb4b92499fd874ded50680dd97c654f020da8b45a1a5f8", + "https://raw.githubusercontent.com/sinclairzx81/tasksmith/0.8.5/src/build/dual/dual.ts": "c525f1020a2d7e479cc9a7d9fce3fd107bfe500a2b107957546ba1f1f3e9d013", + "https://raw.githubusercontent.com/sinclairzx81/tasksmith/0.8.5/src/build/dual/folder.ts": "90576e23137a57677ed7a7dc994e49f1feb0f40a7507b5422168c7f143777cca", + "https://raw.githubusercontent.com/sinclairzx81/tasksmith/0.8.5/src/build/esm/build-check.ts": "eafa882e505886dec2675524c280375947be5c4a79972777951434df19ece111", + "https://raw.githubusercontent.com/sinclairzx81/tasksmith/0.8.5/src/build/esm/build-esm.ts": "416aaba959e185dd98fc2a4fb4dd93e142bef66a22405fbb229466d161d5f6c6", + "https://raw.githubusercontent.com/sinclairzx81/tasksmith/0.8.5/src/build/esm/build-package-json.ts": "9a5e41e78bb358e71735bd104de493b3ccef305633aaa5c89efb2bc6f001abac", + "https://raw.githubusercontent.com/sinclairzx81/tasksmith/0.8.5/src/build/esm/esm.ts": "1cc0988bffac3ae673781dde2a2bc13f2ddfb616a6e56bb19f567f1bbb50a94a", + "https://raw.githubusercontent.com/sinclairzx81/tasksmith/0.8.5/src/build/esm/folder.ts": "90576e23137a57677ed7a7dc994e49f1feb0f40a7507b5422168c7f143777cca", + "https://raw.githubusercontent.com/sinclairzx81/tasksmith/0.8.5/src/build/index.ts": "d0f163948e4e8b56451a0fd1e137bcf1b74440ea213335443c9abd38a6d1f3cb", + "https://raw.githubusercontent.com/sinclairzx81/tasksmith/0.8.5/src/build/options.ts": "3849cd3144e482197b3bcfe5e325340be8cf62abae20b66140b62081d0501648", + "https://raw.githubusercontent.com/sinclairzx81/tasksmith/0.8.5/src/compress/compress.ts": "04389003328eb5a94c32e3044ca45a4bc2730059437464afe732535cbc9424dd", + "https://raw.githubusercontent.com/sinclairzx81/tasksmith/0.8.5/src/compress/format-size.ts": "e05a7e2ed57d4addcbc517dd92ff90d9e1fb7df3c7cc437b7658ff59cf0a36a3", + "https://raw.githubusercontent.com/sinclairzx81/tasksmith/0.8.5/src/compress/gzip-size.ts": "02f15c90b8afebee7f6fc3f7d409238db70544bf509e2359411defc68d07ec7d", + "https://raw.githubusercontent.com/sinclairzx81/tasksmith/0.8.5/src/compress/index.ts": "f644b71cbb6c4b72e00018c25c40fc2b575cf28f2a24d1d23cbac2b5f2c095c4", + "https://raw.githubusercontent.com/sinclairzx81/tasksmith/0.8.5/src/esbuild/esbuild.ts": "11aca47ea1815cf328229243e800029c62a09a0ab55f97b4691116dafeb1bfc4", + "https://raw.githubusercontent.com/sinclairzx81/tasksmith/0.8.5/src/esbuild/index.ts": "9238dbf4eb63926dd9def11010f96636dc875a9175619c2929360ce307f9ee21", + "https://raw.githubusercontent.com/sinclairzx81/tasksmith/0.8.5/src/file/append.ts": "ad45bc669a04e381e28323b7177f2fefbf28bca7e11ddafa5765f34729f9cf51", + "https://raw.githubusercontent.com/sinclairzx81/tasksmith/0.8.5/src/file/create.ts": "4af6c8d6c7e5611df9b137de65da0e3eb23a15e4ad4f00ac886d71c576f96ae3", + "https://raw.githubusercontent.com/sinclairzx81/tasksmith/0.8.5/src/file/delete.ts": "a27567be0020f7463a7a91d99d2be1d2e11d9e3ea8e9f20a2ae684b47540aab4", + "https://raw.githubusercontent.com/sinclairzx81/tasksmith/0.8.5/src/file/file.ts": "b84ee4d26d965554c72e03098af84e0f398ac96d0a7d1c15c9cfdfb76357176a", + "https://raw.githubusercontent.com/sinclairzx81/tasksmith/0.8.5/src/file/index.ts": "3593d9aa518ce79e373daa2d794a44179b74cfabb027f75a202204488b482677", + "https://raw.githubusercontent.com/sinclairzx81/tasksmith/0.8.5/src/file/read.ts": "8a68e6377271ced84462a6ac3ff37d7282dcb164ca5aef383cf3162f3fd6d193", + "https://raw.githubusercontent.com/sinclairzx81/tasksmith/0.8.5/src/file/replace.ts": "2f8caebc51df8c6d1e70125ee08df18a840e2bab95ca8feae3dc67f9b978f2d0", + "https://raw.githubusercontent.com/sinclairzx81/tasksmith/0.8.5/src/file/write.ts": "666a7d38fac527d3259dadb83734eec90acfaf8773184cc4c00dc70e7b833882", + "https://raw.githubusercontent.com/sinclairzx81/tasksmith/0.8.5/src/folder/add.ts": "5020f85ae9f14348ad149c2e96149af63e3599efb6a15bd17591744bc698400c", + "https://raw.githubusercontent.com/sinclairzx81/tasksmith/0.8.5/src/folder/create.ts": "cd3408f58c371cba106d0d73d43c289f174bcf91df7ebdc94deed723f3b335bc", + "https://raw.githubusercontent.com/sinclairzx81/tasksmith/0.8.5/src/folder/delete.ts": "3df9b415ac57a12d847a18f007ac9443ea6c885e990646eff8d70a0a1765b82c", + "https://raw.githubusercontent.com/sinclairzx81/tasksmith/0.8.5/src/folder/folder.ts": "43ccb82e2e76e2e6d972b82a426551f4368a0c8d74ad0a9d099e17cd64f4bdd5", + "https://raw.githubusercontent.com/sinclairzx81/tasksmith/0.8.5/src/folder/index-list.ts": "9c6b2a08534d3651534ae2ad66ed6d6f7f3f88de8a8bdcc53df1729430493e93", + "https://raw.githubusercontent.com/sinclairzx81/tasksmith/0.8.5/src/folder/index.ts": "e72bd528ede06ac325beead47f80efcaa551e2f16e986bde0957944142da2c93", + "https://raw.githubusercontent.com/sinclairzx81/tasksmith/0.8.5/src/index.ts": "69cde5035a9995ecb6ae9c12530367e5c58ca674ad8222d451a98e9089c2922c", + "https://raw.githubusercontent.com/sinclairzx81/tasksmith/0.8.5/src/path/index.ts": "b7086f87edd0ccd26e319c5cbbd83b1cc9a5c4cb6b3e6648fd8065e75d7cc8e2", + "https://raw.githubusercontent.com/sinclairzx81/tasksmith/0.8.5/src/path/path.ts": "bc195ba415472b3002484e1645bc1e27dc7318591b8a27a137c14955ccec1320", + "https://raw.githubusercontent.com/sinclairzx81/tasksmith/0.8.5/src/run/index.ts": "715694d98fdc06702e1fa5cf27a6e86c1f99f8331c038763eced52752a403edb", + "https://raw.githubusercontent.com/sinclairzx81/tasksmith/0.8.5/src/run/run.ts": "180bd2e3fa744dda77c51beccccc4958a9246bc40ddeae874bb13974d22b9a1f", + "https://raw.githubusercontent.com/sinclairzx81/tasksmith/0.8.5/src/serve/index.ts": "5e567c92f580570c4af8d92519f5e18c5cad4efff9106afa68432504dbc1d9c8", + "https://raw.githubusercontent.com/sinclairzx81/tasksmith/0.8.5/src/serve/serve.ts": "bab47805b788dec15b12494e9604c32b634e456b59a0f3293d4bfafabca09a84", + "https://raw.githubusercontent.com/sinclairzx81/tasksmith/0.8.5/src/settings/index.ts": "b4966703f2736afd29509a05a740c80bdd1fd950a89c65648bf9f1d8676003ae", + "https://raw.githubusercontent.com/sinclairzx81/tasksmith/0.8.5/src/settings/settings.ts": "7c8c5cbc055266b7af45252854f8c3c17abc6d4093e2cc4c779d70cba0a7c2c1", + "https://raw.githubusercontent.com/sinclairzx81/tasksmith/0.8.5/src/shell/index.ts": "e0c82a5e70578d6b9ee8c3d03bc729f87ebc66d219c56336f84a4e33e30e373b", + "https://raw.githubusercontent.com/sinclairzx81/tasksmith/0.8.5/src/shell/shell.ts": "4590fad5c47e1184e3138c545371a7275cc40573754e912c62c6c306b754a4b9", + "https://raw.githubusercontent.com/sinclairzx81/tasksmith/0.8.5/src/task.ts": "7d9c273406b3618330833bfd2475be2968f33942ce99063f76dbc4c67c60069a", + "https://raw.githubusercontent.com/sinclairzx81/tasksmith/0.8.5/src/test/index.ts": "dfa63a9d1deec8e440b752131aa4d253dd02024798a9b8ec1cff31edd3749def", + "https://raw.githubusercontent.com/sinclairzx81/tasksmith/0.8.5/src/test/manifest.ts": "63625b8d3cd42d12936aa7a2845b7ac1d9ec7e92bba3ef1320c0e5802807d7e1", + "https://raw.githubusercontent.com/sinclairzx81/tasksmith/0.8.5/src/test/report.ts": "959d516300c35cf263690060e401e334ea506ae72eda9d7e1e6aa79b016e4592", + "https://raw.githubusercontent.com/sinclairzx81/tasksmith/0.8.5/src/test/run.ts": "e93e8568ffe08642e70f7fbeffa5c6833d384a2005789c95d9e931850d01090a", + "https://raw.githubusercontent.com/sinclairzx81/tasksmith/0.8.5/src/test/test.ts": "894650a3af2f7c0c8e4e4f0930d6f3e7bfc5187c5c66ce869c0429b942a51c2d", + "https://raw.githubusercontent.com/sinclairzx81/tasksmith/0.8.5/src/tsc/index.ts": "ef3fd7538b1f3d85e102f4b6317ad92e2f1dc007df6d7d7cceb283913e71117d", + "https://raw.githubusercontent.com/sinclairzx81/tasksmith/0.8.5/src/tsc/tsc.ts": "2d84d6b8bf155811eec128a03095dbad9f15feb7602c7fc3c6a9e0c36dc38602" } } diff --git a/example/binary/binary.ts b/example/binary/binary.ts new file mode 100644 index 0000000..b74b329 --- /dev/null +++ b/example/binary/binary.ts @@ -0,0 +1,158 @@ +/*-------------------------------------------------------------------------- + +ParseBox + +The MIT License (MIT) + +Copyright (c) 2024-2025 Haydn Paterson + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +---------------------------------------------------------------------------*/ + +// deno-fmt-ignore-file + +// ------------------------------------------------------------------ +// +// Future: Binary Numeric Decoding +// +// ------------------------------------------------------------------ + + +type D = '0' | '1' | '2' | '3' | '4' | '5' | '6' | '7' | '8' | '9' +type C = '0' | '1' + +// ------------------------------------------------------------------ +// ReverseString +// ------------------------------------------------------------------ +type ReverseString = S extends `${infer F}${infer Rest}` ? ReverseString : R + +// ------------------------------------------------------------------ +// DoubleDigit: Double a single digit with incoming carry -> [carryOut, outDigit] +// ------------------------------------------------------------------ +type DoubleDigit = CarryIn extends '0' ? DIG extends '0' ? ['0', '0'] + : DIG extends '1' ? ['0', '2'] + : DIG extends '2' ? ['0', '4'] + : DIG extends '3' ? ['0', '6'] + : DIG extends '4' ? ['0', '8'] + : DIG extends '5' ? ['1', '0'] + : DIG extends '6' ? ['1', '2'] + : DIG extends '7' ? ['1', '4'] + : DIG extends '8' ? ['1', '6'] + : ['1', '8'] + : DIG extends '0' ? ['0', '1'] + : DIG extends '1' ? ['0', '3'] + : DIG extends '2' ? ['0', '5'] + : DIG extends '3' ? ['0', '7'] + : DIG extends '4' ? ['0', '9'] + : DIG extends '5' ? ['1', '1'] + : DIG extends '6' ? ['1', '3'] + : DIG extends '7' ? ['1', '5'] + : DIG extends '8' ? ['1', '7'] + : ['1', '9'] + +// ------------------------------------------------------------------ +// DoubleStringLR +// ------------------------------------------------------------------ +type DoubleStringLR = S extends `${infer F extends D}${infer Rest}` + ? DoubleDigit extends [infer CarryOut extends C, infer Out extends D] ? DoubleStringLR + : never + : CarryIn extends '1' ? `${R}1` + : R + +// ------------------------------------------------------------------ +// TrimLeadingZeros +// ------------------------------------------------------------------ +type TrimLeadingZeros = S extends '' ? '0' + : S extends `0${infer R}` ? TrimLeadingZeros + : S + +// ------------------------------------------------------------------ +// DoubleString +// ------------------------------------------------------------------ +export type DoubleString = TrimLeadingZeros>>> + +// ------------------------------------------------------------------ +// DoubleString: Tests +// ------------------------------------------------------------------ +type D1 = DoubleString<'0'> // "0" +type D2 = DoubleString<'1'> // "2" +type D3 = DoubleString<'9'> // "18" +type D4 = DoubleString<'10'> // "20" +type D5 = DoubleString<'99'> // "198" +type D6 = DoubleString<'123456789'> // "246913578" +type D7 = DoubleString<'0000'> // "0" +type D8 = DoubleString<'0001'> // "2" +type D9 = DoubleString<'500'> // "1000" + +// ------------------------------------------------------------------ +// AddOneLR +// ------------------------------------------------------------------ +type AddOneLR = S extends `${infer F extends D}${infer Rest}` ? Carry extends '0' ? `${R}${F}${Rest}` // No carry, append rest as-is + : F extends '0' ? AddOneLR + : F extends '1' ? AddOneLR + : F extends '2' ? AddOneLR + : F extends '3' ? AddOneLR + : F extends '4' ? AddOneLR + : F extends '5' ? AddOneLR + : F extends '6' ? AddOneLR + : F extends '7' ? AddOneLR + : F extends '8' ? AddOneLR + : /* 9 */ AddOneLR // 9+1 = 10, carry + : Carry extends '1' ? `${R}1` + : R + +// ------------------------------------------------------------------ +// AddOne +// ------------------------------------------------------------------ +type AddOne = ReverseString>> + +// ------------------------------------------------------------------ +// AddOne: Tests +// ------------------------------------------------------------------ +type A1 = AddOne<'0'> // "1" +type A2 = AddOne<'1'> // "2" +type A3 = AddOne<'9'> // "10" +type A4 = AddOne<'99'> // "100" +type A5 = AddOne<'123'> // "124" +type A6 = AddOne<'999'> // "1000" + +// ------------------------------------------------------------------ +// BinaryToDecimal +// ------------------------------------------------------------------ +type BinaryToDecimal< + B extends string, + Result extends string = '0', +> = B extends `${infer F extends '0' | '1'}${infer Rest}` + ? F extends '0' + ? BinaryToDecimal> + : BinaryToDecimal>> + : Result + +// ------------------------------------------------------------------ +// BinaryToDecimal: Test +// ------------------------------------------------------------------ +type N0 = BinaryToDecimal<'0'> // "0" +type N1 = BinaryToDecimal<'1'> // "1" +type N2 = BinaryToDecimal<'10'> // "2" +type N3 = BinaryToDecimal<'11'> // "3" +type N4 = BinaryToDecimal<'1010'> // "10" +type N5 = BinaryToDecimal<'11111111'> // "255" +type N6 = BinaryToDecimal<'11111111111111'> // "16383" + diff --git a/example/ebnf/index.ts b/example/ebnf/index.ts index 0f007e2..8a1eb7f 100644 --- a/example/ebnf/index.ts +++ b/example/ebnf/index.ts @@ -1,10 +1,10 @@ /*-------------------------------------------------------------------------- -@sinclair/parsebox +ParseBox The MIT License (MIT) -Copyright (c) 2024-2025 Haydn Paterson (sinclair) +Copyright (c) 2024-2025 Haydn Paterson Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/example/ebnf/parse.ts b/example/ebnf/parse.ts index de36a52..e3709b7 100644 --- a/example/ebnf/parse.ts +++ b/example/ebnf/parse.ts @@ -1,10 +1,10 @@ /*-------------------------------------------------------------------------- -@sinclair/parsebox +ParseBox The MIT License (MIT) -Copyright (c) 2024 Haydn Paterson (sinclair) (haydn.developer@gmail.com) +Copyright (c) 2024-2025 Haydn Paterson Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/example/ebnf/runtime.ts b/example/ebnf/runtime.ts index d1a8200..7448304 100644 --- a/example/ebnf/runtime.ts +++ b/example/ebnf/runtime.ts @@ -1,10 +1,10 @@ /*-------------------------------------------------------------------------- -@sinclair/parsebox +ParseBox The MIT License (MIT) -Copyright (c) 2024-2025 Haydn Paterson (sinclair) +Copyright (c) 2024-2025 Haydn Paterson Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/example/ebnf/static.ts b/example/ebnf/static.ts index d933c8a..8abf04e 100644 --- a/example/ebnf/static.ts +++ b/example/ebnf/static.ts @@ -1,10 +1,10 @@ /*-------------------------------------------------------------------------- -@sinclair/parsebox +ParseBox The MIT License (MIT) -Copyright (c) 2024-2025 Haydn Paterson (sinclair) +Copyright (c) 2024-2025 Haydn Paterson Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/example/index.ts b/example/index.ts index 0924537..c1a7d66 100644 --- a/example/index.ts +++ b/example/index.ts @@ -1,96 +1,96 @@ // deno-fmt-ignore-file -import { Static, Runtime, Compile } from '@sinclair/parsebox' +import { Static, Runtime, Build } from '@sinclair/parsebox' import { ParseJson } from './json/index.ts' import { ParseEbnf } from './ebnf/index.ts' -// ------------------------------------------------------------------ -// -// Example: Ebnf | Interpreted -// -// ------------------------------------------------------------------ -const Ebnf = ParseEbnf(` - - Operand ::= Ident ; - - Factor ::= "(" Expr ")" - | Operand ; - - TermTail ::= ("*" Factor TermTail) - | ("/" Factor TermTail) - | e ; - - ExprTail ::= ("+" Term ExprTail) - | ("-" Term ExprTail) - | e ; - - Term ::= Factor TermTail ; - - Expr ::= Term ExprTail ; - -`) - -const Result = Ebnf.Parse('Expr', `X * (Y + Z)`) - -console.dir(Result, { depth: 100 }) - -// ------------------------------------------------------------------ -// -// Example: Json | Interpreted -// -// ------------------------------------------------------------------ -const Json = ParseJson(`{ - "x": 1, - "y": 2, - "z": 3 -}`) - -console.log(Json) - -// ------------------------------------------------------------------ -// -// Example: Expression | Interpreted -// -// ------------------------------------------------------------------ -{ - type Result = Static.Parse // hover - - type BinaryReduce = ( - Right extends [infer Operator, infer Right, infer Rest extends unknown[]] - ? { left: Left; operator: Operator; right: BinaryReduce } - : Left - ) - interface BinaryMapping extends Static.IMapping { - output: this['input'] extends [infer Left, infer Right extends unknown[]] - ? BinaryReduce - : never - } - interface FactorMapping extends Static.IMapping { - output: ( - this['input'] extends ['(', infer Expr, ')'] ? Expr : - this['input'] extends [infer Operand] ? Operand : - never - ) - } - type Operand = Static.Ident - type Factor = Static.Union<[ - Static.Tuple<[Static.Const<'('>, Expr, Static.Const<')'>]>, - Static.Tuple<[Operand]> - ], FactorMapping> - - type TermTail = Static.Union<[ - Static.Tuple<[Static.Const<'*'>, Factor, TermTail]>, - Static.Tuple<[Static.Const<'/'>, Factor, TermTail]>, - Static.Tuple<[]> - ]> - type ExprTail = Static.Union<[ - Static.Tuple<[Static.Const<'+'>, Term, ExprTail]>, - Static.Tuple<[Static.Const<'-'>, Term, ExprTail]>, - Static.Tuple<[]> - ]> - type Term = Static.Tuple<[Factor, TermTail], BinaryMapping> - type Expr = Static.Tuple<[Term, ExprTail], BinaryMapping> -} +// // ------------------------------------------------------------------ +// // +// // Example: Ebnf | Interpreted +// // +// // ------------------------------------------------------------------ +// const Ebnf = ParseEbnf(` + +// Operand ::= Ident ; + +// Factor ::= "(" Expr ")" +// | Operand ; + +// TermTail ::= ("*" Factor TermTail) +// | ("/" Factor TermTail) +// | e ; + +// ExprTail ::= ("+" Term ExprTail) +// | ("-" Term ExprTail) +// | e ; + +// Term ::= Factor TermTail ; + +// Expr ::= Term ExprTail ; + +// `) + +// const Result = Ebnf.Parse('Expr', `X * (Y + Z)`) + +// console.dir(Result, { depth: 100 }) + +// // ------------------------------------------------------------------ +// // +// // Example: Json | Interpreted +// // +// // ------------------------------------------------------------------ +// const Json = ParseJson(`{ +// "x": 1, +// "y": 2, +// "z": 3 +// }`) + +// console.log(Json) + +// // ------------------------------------------------------------------ +// // +// // Example: Expression | Interpreted +// // +// // ------------------------------------------------------------------ +// { +// type Result = Static.Parse // hover + +// type BinaryReduce = ( +// Right extends [infer Operator, infer Right, infer Rest extends unknown[]] +// ? { left: Left; operator: Operator; right: BinaryReduce } +// : Left +// ) +// interface BinaryMapping extends Static.IMapping { +// output: this['input'] extends [infer Left, infer Right extends unknown[]] +// ? BinaryReduce +// : never +// } +// interface FactorMapping extends Static.IMapping { +// output: ( +// this['input'] extends ['(', infer Expr, ')'] ? Expr : +// this['input'] extends [infer Operand] ? Operand : +// never +// ) +// } +// type Operand = Static.Ident +// type Factor = Static.Union<[ +// Static.Tuple<[Static.Const<'('>, Expr, Static.Const<')'>]>, +// Static.Tuple<[Operand]> +// ], FactorMapping> + +// type TermTail = Static.Union<[ +// Static.Tuple<[Static.Const<'*'>, Factor, TermTail]>, +// Static.Tuple<[Static.Const<'/'>, Factor, TermTail]>, +// Static.Tuple<[]> +// ]> +// type ExprTail = Static.Union<[ +// Static.Tuple<[Static.Const<'+'>, Term, ExprTail]>, +// Static.Tuple<[Static.Const<'-'>, Term, ExprTail]>, +// Static.Tuple<[]> +// ]> +// type Term = Static.Tuple<[Factor, TermTail], BinaryMapping> +// type Expr = Static.Tuple<[Term, ExprTail], BinaryMapping> +// } // ------------------------------------------------------------------ // // Example: Compiled Parser @@ -115,10 +115,8 @@ console.log(Json) Runtime.Tuple([]), ]) }) - const project = Compile.Project(ListModule, { - mappingPath: './mapping', - mappingImports: [], - parserImports: [] + const project = Build.Project(ListModule, { + mappingPath: './mapping.ts', }) console.log(project.parser) // parser file content console.log(project.mapping) // semantic mapping file content diff --git a/example/json/index.ts b/example/json/index.ts index 0f007e2..8a1eb7f 100644 --- a/example/json/index.ts +++ b/example/json/index.ts @@ -1,10 +1,10 @@ /*-------------------------------------------------------------------------- -@sinclair/parsebox +ParseBox The MIT License (MIT) -Copyright (c) 2024-2025 Haydn Paterson (sinclair) +Copyright (c) 2024-2025 Haydn Paterson Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/example/json/parse.ts b/example/json/parse.ts index 1c99bd1..7abd3ae 100644 --- a/example/json/parse.ts +++ b/example/json/parse.ts @@ -1,10 +1,10 @@ /*-------------------------------------------------------------------------- -@sinclair/parsebox +ParseBox The MIT License (MIT) -Copyright (c) 2024 Haydn Paterson (sinclair) (haydn.developer@gmail.com) +Copyright (c) 2024-2025 Haydn Paterson Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/example/json/runtime.ts b/example/json/runtime.ts index 6523dfb..3b95391 100644 --- a/example/json/runtime.ts +++ b/example/json/runtime.ts @@ -1,10 +1,10 @@ /*-------------------------------------------------------------------------- -@sinclair/parsebox +ParseBox The MIT License (MIT) -Copyright (c) 2024 Haydn Paterson (sinclair) (haydn.developer@gmail.com) +Copyright (c) 2024-2025 Haydn Paterson Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/example/json/static.ts b/example/json/static.ts index d6ed60e..5a91868 100644 --- a/example/json/static.ts +++ b/example/json/static.ts @@ -1,10 +1,10 @@ /*-------------------------------------------------------------------------- -@sinclair/parsebox +ParseBox The MIT License (MIT) -Copyright (c) 2024-2025 Haydn Paterson (sinclair) +Copyright (c) 2024-2025 Haydn Paterson Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/license b/license index 425308d..0fb61ac 100644 --- a/license +++ b/license @@ -1,10 +1,8 @@ -@sinclair/parsebox - -Parser Combinators in the TypeScript Type System +ParseBox The MIT License (MIT) -Copyright (c) 2024-2025 Haydn Paterson (sinclair) +Copyright (c) 2024-2025 Haydn Paterson Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/readme.md b/readme.md index 64bbffa..36139e9 100644 --- a/readme.md +++ b/readme.md @@ -71,12 +71,11 @@ License: MIT - [Array](#Array) - [Optional](#Optional) - [Epsilon](#Epsilon) -- [Range](#Range) - - [Until](#Until) - - [UntilNonEmpty](#UntilNonEmpty) -- [Terminals](#Terminals) +- [Token](#Token) - [Number](#Number) + - [Integer](#Integer) - [String](#String) + - [BigInt](#BigInt) - [Ident](#Ident) - [Mapping](#Mapping) - [Modules](#Modules) @@ -236,77 +235,44 @@ const R1 = Runtime.Parse(T, 'X Y Z') // const R1 = [['X', 'Y'], ' const R2 = Runtime.Parse(T, 'Y Z') // const R2 = [[], 'Y Z'] ``` -## Range Combinators +## Token -ParseBox range combinators match character sequences up to one or more terminating sentinel strings. These combinators are used to match arbituary Unicode (UTF-16) sequences. +ParseBox provides built-in combinators with optimized implementations for commonly used literal forms such as numbers, strings, and identifiers. +### Number -### Until - -The Until combinator parses characters up to (but not including) one of the specified sentinel string values. It captures all characters encountered before the sentinel. If a sentinel value is not found in the input, parsing fails. Until succeeds even if it matches a zero-length string. This occurs if a sentinel is found immediately at the current parsing position. - -**BNF** - -```bnf - ::= ? any character sequence (0 or more) until 'Z' ? -``` - -**TypeScript** +Parses a number with fractional parts ```typescript -const T = Runtime.Until(['Z']) // const T = { - // type: 'Until', - // values: ['Z'] - // } - -const R = Runtime.Parse(T, 'X Y Z') // const R = ['X Y ', 'Z'] -``` - -### UntilNonEmpty - -The UntilNonEmpty combinator works the same as Until, but it fails if the parsed content yields a zero-length string. - -**BNF** - -```bnf - ::= ? any character sequence (1 or more) until 'Z'. fails on zero length ? -``` +const T = Runtime.Number() -**TypeScript** +// ... -```typescript -const T = Runtime.UntilNonEmpty(['Z']) // const T = { - // type: 'UntilNonEmpty', - // values: ['Z'] - // } +const R1 = Runtime.Parse(T, '1') // const R1 = ['1', ''] -const R1 = Runtime.Parse(T, 'X Y Z') // const R1 = ['X Y ', 'Z'] +const R2 = Runtime.Parse(T, '3.14') // const R2 = ['3.14', ''] -const R2 = Runtime.Parse(T, ' Z') // const R2 = [' ', 'Z'] +const R3 = Runtime.Parse(T, '.1') // const R3 = ['.1', ''] -const R3 = Runtime.Parse(T, 'Z') // const R3 = [] +const E = Runtime.Parse(T, '01') // const E = ['0', '1'] ``` -## Terminal Combinators - -ParseBox provides combinators for parsing common lexical tokens, such as numbers, identifiers, and strings, enabling static, optimized parsing of typical JavaScript constructs. - -### Number +### Integer -Parses numeric literals, including integers, decimals, and floating-point numbers. Invalid formats, like leading zeroes, are not matched. +Parses a literal integer ```typescript -const T = Runtime.Number() +const T = Runtime.Integer() // ... const R1 = Runtime.Parse(T, '1') // const R1 = ['1', ''] -const R2 = Runtime.Parse(T, '3.14') // const R2 = ['3.14', ''] +const R2 = Runtime.Parse(T, '3.14') // const R2 = ['3', '.14'] -const R3 = Runtime.Parse(T, '.1') // const R3 = ['.1', ''] +const R3 = Runtime.Parse(T, '.1') // const R3 = [] -const E = Runtime.Parse(T, '01') // const E = [] +const E = Runtime.Parse(T, '01') // const E = ['0', '1'] ``` ### String @@ -321,22 +287,35 @@ const T = Runtime.String(['"']) const R = Runtime.Parse(T, '"hello"') // const R = ['hello', ''] ``` -### Ident +### BigInt -Parses valid JavaScript identifiers, typically used to extract variable or function names. The following example demonstrates parsing a `let` statement. +Parses a literal bigint number. This combinator will succeed if the number is integer and trailed by a `n`. The `n` is omitted from the result. -```bnf - ::= "let" "=" +```typescript +const T = Runtime.BigInt() + +// ... + +const R1 = Runtime.Parse(T, '1n') // const R1 = ['1', ''] + +const R2 = Runtime.Parse(T, '1n2') // const R2 = ['1', '2'] + +const R3 = Runtime.Parse(T, '.1n') // const R3 = [] + +const E = Runtime.Parse(T, '01n') // const E = [] ``` -```typescript -const Expression = Runtime.Number() // const Expression = { type: 'Number' } +### Ident + +Parses an identifier + +```typescript const Let = Runtime.Tuple([ // const Let = { Runtime.Const('let'), // type: 'Tuple', - Runtime.Ident(), // parsers: [ + Runtime.Ident(), /* here */ // parsers: [ Runtime.Const('='), // { type: 'Const', value: 'let' }, - Expression // { type: 'Ident' }, + Runtime.Number() // { type: 'Ident' }, ]) // { type: 'Const', value: '=' }, // { type: 'Number' }, // ] diff --git a/src/compile/common/comment.ts b/src/build/common/comment.ts similarity index 71% rename from src/compile/common/comment.ts rename to src/build/common/comment.ts index 0f308e6..8bae1a5 100644 --- a/src/compile/common/comment.ts +++ b/src/build/common/comment.ts @@ -1,10 +1,10 @@ /*-------------------------------------------------------------------------- -@sinclair/parsebox +ParseBox The MIT License (MIT) -Copyright (c) 2024-2025 Haydn Paterson (sinclair) +Copyright (c) 2024-2025 Haydn Paterson Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal @@ -27,21 +27,26 @@ THE SOFTWARE. ---------------------------------------------------------------------------*/ // deno-fmt-ignore-file -// deno-lint-ignore-file -import { Runtime } from '../../runtime/index.ts' -import { Unreachable } from './unreachable.ts' +import { Unreachable } from '../../system/unreachable/index.ts' +import * as Runtime from '../../runtime/index.ts' import { Escape } from './escape.ts' function FromArray(parser: Runtime.IArray): string { return `${FromParser(parser.parser)}[]` } function FromConst(parser: Runtime.IConst): string { - return `'${Escape(parser.value)}'` + return `'${Escape(parser.const)}'` +} +function FromBigInt(parser: Runtime.IBigInt): string { + return `` } function FromIdent(parser: Runtime.IIdent): string { return `` } +function FromInteger(parser: Runtime.IInteger): string { + return `` +} function FromNumber(parser: Runtime.INumber): string { return `` } @@ -60,26 +65,28 @@ function FromTuple(parser: Runtime.ITuple): string { function FromUnion(parser: Runtime.IUnion): string { return parser.parsers.map((parser) => `${FromParser(parser)}`).join(' | ') } -function FromUntil(parser: Runtime.IUntil): string { +function FromUntil_1(parser: Runtime.IUntil_1): string { return `string` } -function FromUntilNonEmpty(parser: Runtime.IUntilNonEmpty): string { +function FromUntil(parser: Runtime.IUntil): string { return `string` } function FromParser(parser: Runtime.IParser): string { return ( Runtime.IsArray(parser) ? FromArray(parser) : - Runtime.IsConst(parser) ? FromConst(parser) : - Runtime.IsIdent(parser) ? FromIdent(parser) : - Runtime.IsNumber(parser) ? FromNumber(parser) : - Runtime.IsOptional(parser) ? FromOptional(parser) : - Runtime.IsRef(parser) ? FromRef(parser) : - Runtime.IsString(parser) ? FromString(parser) : - Runtime.IsTuple(parser) ? FromTuple(parser) : - Runtime.IsUnion(parser) ? FromUnion(parser) : - Runtime.IsUntil(parser) ? FromUntil(parser) : - Runtime.IsUntilNonEmpty(parser) ? FromUntilNonEmpty(parser) : - Unreachable(parser) + Runtime.IsBigInt(parser) ? FromBigInt(parser) : + Runtime.IsConst(parser) ? FromConst(parser) : + Runtime.IsInteger(parser) ? FromInteger(parser) : + Runtime.IsIdent(parser) ? FromIdent(parser) : + Runtime.IsNumber(parser) ? FromNumber(parser) : + Runtime.IsOptional(parser) ? FromOptional(parser) : + Runtime.IsRef(parser) ? FromRef(parser) : + Runtime.IsString(parser) ? FromString(parser) : + Runtime.IsTuple(parser) ? FromTuple(parser) : + Runtime.IsUnion(parser) ? FromUnion(parser) : + Runtime.IsUntil_1(parser) ? FromUntil_1(parser) : + Runtime.IsUntil(parser) ? FromUntil(parser) : + Unreachable(parser) ) } export function CompileComment(name: string, parser: Runtime.IParser): string { diff --git a/src/compile/common/escape.ts b/src/build/common/escape.ts similarity index 93% rename from src/compile/common/escape.ts rename to src/build/common/escape.ts index 964332e..52ff37b 100644 --- a/src/compile/common/escape.ts +++ b/src/build/common/escape.ts @@ -1,10 +1,10 @@ /*-------------------------------------------------------------------------- -@sinclair/parsebox +ParseBox The MIT License (MIT) -Copyright (c) 2024-2025 Haydn Paterson (sinclair) +Copyright (c) 2024-2025 Haydn Paterson Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/src/compile/common/index.ts b/src/build/common/index.ts similarity index 90% rename from src/compile/common/index.ts rename to src/build/common/index.ts index 5820b01..966b0a1 100644 --- a/src/compile/common/index.ts +++ b/src/build/common/index.ts @@ -1,10 +1,10 @@ /*-------------------------------------------------------------------------- -@sinclair/parsebox +ParseBox The MIT License (MIT) -Copyright (c) 2024-2025 Haydn Paterson (sinclair) +Copyright (c) 2024-2025 Haydn Paterson Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal @@ -29,4 +29,3 @@ THE SOFTWARE. export * from './comment.ts' export * from './escape.ts' export * from './infer.ts' -export * from './unreachable.ts' diff --git a/src/compile/common/infer.ts b/src/build/common/infer.ts similarity index 67% rename from src/compile/common/infer.ts rename to src/build/common/infer.ts index 3efd2cc..ca17043 100644 --- a/src/compile/common/infer.ts +++ b/src/build/common/infer.ts @@ -1,10 +1,10 @@ /*-------------------------------------------------------------------------- -@sinclair/parsebox +ParseBox The MIT License (MIT) -Copyright (c) 2024-2025 Haydn Paterson (sinclair) +Copyright (c) 2024-2025 Haydn Paterson Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal @@ -29,14 +29,23 @@ THE SOFTWARE. // deno-fmt-ignore-file // deno-lint-ignore-file no-unused-vars -import { Runtime } from '../../runtime/index.ts' -import { Unreachable } from './unreachable.ts' +import { Unreachable } from '../../system/unreachable/index.ts' +import * as Runtime from '../../runtime/index.ts' function InferArray(parser: Runtime.IParser): string { return `(${Infer(parser)})[]` } function InferConst(parser: Runtime.IConst) { - return `'${parser.value}'` + return `'${parser.const}'` +} +function InferBigInt(parser: Runtime.IBigInt) { + return `string` +} +function InferIdent(parser: Runtime.IIdent) { + return `string` +} +function InferInteger(parser: Runtime.IInteger) { + return `string` } function InferOptional(parser: Runtime.IParser) { return `([${Infer(parser)}] | [])` @@ -50,34 +59,33 @@ function InferString(parser: Runtime.IString) { function InferRef(parser: Runtime.IRef) { return `unknown` } -function InferIdent(parser: Runtime.IIdent) { - return `string` -} function InferNumber(parser: Runtime.INumber) { return `string` } function InferTuple(parsers: Runtime.IParser[]): string { return `[${parsers.map(() => 'unknown').join(', ')}]` } -function InferUntil(parser: Runtime.IUntil) { +function InferUntil_1(parser: Runtime.IUntil_1) { return `string` } -function InferUntilNonEmpty(parser: Runtime.IUntilNonEmpty) { +function InferUntil(parser: Runtime.IUntil) { return `string` } export function Infer(parser: Runtime.IParser): string { return ( Runtime.IsArray(parser) ? InferArray(parser.parser) : - Runtime.IsConst(parser) ? InferConst(parser) : - Runtime.IsIdent(parser) ? InferIdent(parser) : - Runtime.IsNumber(parser) ? InferNumber(parser) : - Runtime.IsOptional(parser) ? InferOptional(parser.parser) : - Runtime.IsRef(parser) ? InferRef(parser) : - Runtime.IsString(parser) ? InferString(parser) : - Runtime.IsTuple(parser) ? InferTuple(parser.parsers) : - Runtime.IsUnion(parser) ? InferUnion(parser.parsers) : - Runtime.IsUntil(parser) ? InferUntil(parser) : - Runtime.IsUntilNonEmpty(parser) ? InferUntilNonEmpty(parser) : - Unreachable(parser) + Runtime.IsBigInt(parser) ? InferBigInt(parser) : + Runtime.IsConst(parser) ? InferConst(parser) : + Runtime.IsInteger(parser) ? InferInteger(parser) : + Runtime.IsIdent(parser) ? InferIdent(parser) : + Runtime.IsNumber(parser) ? InferNumber(parser) : + Runtime.IsOptional(parser) ? InferOptional(parser.parser) : + Runtime.IsRef(parser) ? InferRef(parser) : + Runtime.IsString(parser) ? InferString(parser) : + Runtime.IsTuple(parser) ? InferTuple(parser.parsers) : + Runtime.IsUnion(parser) ? InferUnion(parser.parsers) : + Runtime.IsUntil_1(parser) ? InferUntil_1(parser) : + Runtime.IsUntil(parser) ? InferUntil(parser) : + Unreachable(parser) ) } diff --git a/src/compile/index.ts b/src/build/index.ts similarity index 90% rename from src/compile/index.ts rename to src/build/index.ts index 86db31b..219054e 100644 --- a/src/compile/index.ts +++ b/src/build/index.ts @@ -1,10 +1,10 @@ /*-------------------------------------------------------------------------- -@sinclair/parsebox +ParseBox The MIT License (MIT) -Copyright (c) 2024-2025 Haydn Paterson (sinclair) +Copyright (c) 2024-2025 Haydn Paterson Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal @@ -26,5 +26,5 @@ THE SOFTWARE. ---------------------------------------------------------------------------*/ -export * as Compile from './compile.ts' export * from './options.ts' +export * from './project.ts' diff --git a/src/compile/options.ts b/src/build/options.ts similarity index 92% rename from src/compile/options.ts rename to src/build/options.ts index 26aef5c..0ed27d6 100644 --- a/src/compile/options.ts +++ b/src/build/options.ts @@ -1,10 +1,10 @@ /*-------------------------------------------------------------------------- -@sinclair/parsebox +ParseBox The MIT License (MIT) -Copyright (c) 2024-2025 Haydn Paterson (sinclair) +Copyright (c) 2024-2025 Haydn Paterson Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal @@ -39,7 +39,7 @@ export interface Options { /** Default Compiler Options */ export function DefaultOptions(): Options { return { - mappingPath: "./mapping", + mappingPath: './mapping.ts', mappingImports: [], parserImports: [], } diff --git a/src/compile/compile.ts b/src/build/project.ts similarity index 81% rename from src/compile/compile.ts rename to src/build/project.ts index 8250f40..ec7f175 100644 --- a/src/compile/compile.ts +++ b/src/build/project.ts @@ -1,10 +1,10 @@ /*-------------------------------------------------------------------------- -@sinclair/parsebox +ParseBox The MIT License (MIT) -Copyright (c) 2024-2025 Haydn Paterson (sinclair) +Copyright (c) 2024-2025 Haydn Paterson Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal @@ -28,9 +28,9 @@ THE SOFTWARE. // deno-fmt-ignore-file -import { Runtime } from '../runtime/index.ts' -import { CompileType, CompileTypeMap } from './type/index.ts' -import { CompileFunc, CompileFuncMap } from './func/index.ts' +import * as Runtime from '../runtime/index.ts' +import { BuildStaticParse, BuildStaticMapping } from './static/index.ts' +import { BuildRuntimeParse, BuildRuntimeMapping } from './runtime/index.ts' import { CompileComment } from './common/index.ts' import { DefaultOptions, Options } from './options.ts' @@ -43,7 +43,7 @@ export interface HeaderResult { ifExpression: string } function Header(options: Options): HeaderResult { - const imports = [`import { Runtime, Static } from '@sinclair/parsebox'`].join('\n') + const imports = [`import { Token } from '@sinclair/parsebox'`].join('\n') const importSemantics = `import * as S from '${options.mappingPath}'` const ifExpression = `const If = (result: [unknown, string] | [], left: (input: [unknown, string]) => [unknown, string] | [], right: () => [unknown, string] | [] = () => []): [unknown, string] | [] => result.length === 2 ? left(result) : right()` return { imports, importSemantics, ifExpression } @@ -70,10 +70,10 @@ export function Types(module: Runtime.Module, options: Options = DefaultOptions( const types: Type[] = Object.entries(module.parsers).map(([key, parser]) => { return { comment: CompileComment(key, parser), - funcMap: CompileFuncMap(key, parser), - typeMap: CompileTypeMap(key, parser), - type: CompileType(key, parser), - func: CompileFunc(key, parser), + funcMap: BuildRuntimeMapping(key, parser), + typeMap: BuildStaticMapping(key, parser), + type: BuildStaticParse(key, parser), + func: BuildRuntimeParse(key, parser), } }) return { header, types } @@ -85,19 +85,20 @@ export interface ProjectResult { parser: string mapping: string } -export function Project(module: Runtime.Module, options: Options = DefaultOptions()): ProjectResult { - const types = Types(module, options) +export function Project(module: Runtime.Module, options: Partial = {}): ProjectResult { + const options_ = { ...DefaultOptions(), ...options } + const types = Types(module, options_) // ---------------------------------------------------------------- // File: Parser // ---------------------------------------------------------------- - const parserHeader = [types.header.imports, ...options.parserImports, types.header.importSemantics].join('\n') + const parserHeader = [types.header.imports, ...options_.parserImports, types.header.importSemantics].join('\n') const parserTypes = types.types.reduce((result, type) => [result, type.type].join('\n'), '') const parserFuncs = types.types.reduce((result, type) => [result, type.func].join('\n'), '') const parser = [parserHeader, parserTypes, types.header.ifExpression, parserFuncs].join('\n') // ---------------------------------------------------------------- // File: Mapping // ---------------------------------------------------------------- - const semanticsHeader = [...options.mappingImports].join('\n') + const semanticsHeader = [...options_.mappingImports].join('\n') const semanticsBody = types.types.reduce((result, type) => [result, type.comment, type.typeMap, type.funcMap].join('\n'), '') const semantics = [semanticsHeader, semanticsBody].join('\n') return { parser, mapping: semantics } diff --git a/src/compile/func/index.ts b/src/build/runtime/index.ts similarity index 89% rename from src/compile/func/index.ts rename to src/build/runtime/index.ts index e2faa7d..4433f86 100644 --- a/src/compile/func/index.ts +++ b/src/build/runtime/index.ts @@ -1,10 +1,10 @@ /*-------------------------------------------------------------------------- -@sinclair/parsebox +ParseBox The MIT License (MIT) -Copyright (c) 2024-2025 Haydn Paterson (sinclair) +Copyright (c) 2024-2025 Haydn Paterson Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal @@ -26,5 +26,5 @@ THE SOFTWARE. ---------------------------------------------------------------------------*/ -export * from './func.ts' -export * from './map.ts' +export * from './parse.ts' +export * from './mapping.ts' diff --git a/src/compile/func/map.ts b/src/build/runtime/mapping.ts similarity index 78% rename from src/compile/func/map.ts rename to src/build/runtime/mapping.ts index cdf7cf6..e1e89d9 100644 --- a/src/compile/func/map.ts +++ b/src/build/runtime/mapping.ts @@ -1,10 +1,10 @@ /*-------------------------------------------------------------------------- -@sinclair/parsebox +ParseBox The MIT License (MIT) -Copyright (c) 2024-2025 Haydn Paterson (sinclair) +Copyright (c) 2024-2025 Haydn Paterson Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal @@ -28,9 +28,10 @@ THE SOFTWARE. // deno-fmt-ignore-file -import { Runtime } from '../../runtime/index.ts' +import * as Runtime from '../../runtime/index.ts' import { Infer } from '../common/index.ts' +import { Name } from './name.ts' -export function CompileFuncMap(name: string, parser: Runtime.IParser): string { - return [`export function ${name}Mapping(input: ${Infer(parser)}): unknown {`, ` return input`, `}`].join('\n') +export function BuildRuntimeMapping(name: string, parser: Runtime.IParser): string { + return [`export function ${Name(name)}Mapping(input: ${Infer(parser)}): unknown {`, ` return input`, `}`].join('\n') } diff --git a/src/build/runtime/name.ts b/src/build/runtime/name.ts new file mode 100644 index 0000000..ebcd044 --- /dev/null +++ b/src/build/runtime/name.ts @@ -0,0 +1,31 @@ +/*-------------------------------------------------------------------------- + +ParseBox + +The MIT License (MIT) + +Copyright (c) 2024-2025 Haydn Paterson + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +---------------------------------------------------------------------------*/ + +export function Name(name: string) { + return `${name}` +} diff --git a/src/compile/func/func.ts b/src/build/runtime/parse.ts similarity index 69% rename from src/compile/func/func.ts rename to src/build/runtime/parse.ts index 2c8ab20..96709d4 100644 --- a/src/compile/func/func.ts +++ b/src/build/runtime/parse.ts @@ -1,10 +1,10 @@ /*-------------------------------------------------------------------------- -@sinclair/parsebox +ParseBox The MIT License (MIT) -Copyright (c) 2024-2025 Haydn Paterson (sinclair) +Copyright (c) 2024-2025 Haydn Paterson Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal @@ -29,8 +29,10 @@ THE SOFTWARE. // deno-fmt-ignore-file // deno-lint-ignore-file -import { Runtime } from '../../runtime/index.ts' -import { Infer, Escape, Unreachable } from '../common/index.ts' +import { Unreachable } from '../../system/unreachable/index.ts' +import * as Runtime from '../../runtime/index.ts' +import { Infer, Escape } from '../common/index.ts' +import { Name } from './name.ts' // ------------------------------------------------------------------ // CompileState @@ -41,7 +43,7 @@ const state = { reducers: new Set() } // Array // ------------------------------------------------------------------ function FromArrayReducer(name: string, parser: Runtime.IParser): string { - const reducer_name = `${name}_${state.reducers.size}` + const reducer_name = `${Name(name)}_${state.reducers.size}` const reducer = `export const ${reducer_name} = (input: string, result: unknown[] = []): [unknown[], string] => If(${FromParser(reducer_name, parser)}, ([_0, input]) => ${reducer_name}(input, [...result, _0]), () => [result, input]) as [unknown[], string]` state.reducers.add(reducer) return reducer_name @@ -53,20 +55,32 @@ function FromArray(name: string, parser: Runtime.IParser): string { // ------------------------------------------------------------------ // Const // ------------------------------------------------------------------ -function FromConst(name: string, value: string): string { - return `Runtime.Token.Const('${Escape(value)}', input)` +function FromConst(name: string, const_: string): string { + return `Token.Const('${Escape(const_)}', input)` +} +// ------------------------------------------------------------------ +// BigInt +// ------------------------------------------------------------------ +function FromBigInt(name: string): string { + return `Token.BigInt(input)` } // ------------------------------------------------------------------ // Ident // ------------------------------------------------------------------ function FromIdent(name: string): string { - return `Runtime.Token.Ident(input)` + return `Token.Ident(input)` +} +// ------------------------------------------------------------------ +// Integer +// ------------------------------------------------------------------ +function FromInteger(name: string): string { + return `Token.Integer(input)` } // ------------------------------------------------------------------ // Number // ------------------------------------------------------------------ function FromNumber(name: string): string { - return `Runtime.Token.Number(input)` + return `Token.Number(input)` } // ------------------------------------------------------------------ // Optional @@ -83,9 +97,9 @@ function FromRef(name: string, ref: string): string { // ------------------------------------------------------------------ // String // ------------------------------------------------------------------ -function FromString(name: string, string_options: string[]): string { - const _options = string_options.map((option) => `'${Escape(option)}'`).join(', ') - return `Runtime.Token.String([${_options}], input)` +function FromString(name: string, quotes: string[]): string { + const _quotes = quotes.map((option) => `'${Escape(option)}'`).join(', ') + return `Token.String([${_quotes}], input)` } // ------------------------------------------------------------------ // Tuple @@ -102,18 +116,18 @@ function FromUnion(name: string, parsers: Runtime.IParser[]): string { return parsers.length === 0 ? '[]' : parsers.reduceRight((result, right) => `If(${FromParser(name, right)}, ([_0, input]) => [_0, input], () => ${result})`, '[]') } // ------------------------------------------------------------------ -// Until +// Until_1 // ------------------------------------------------------------------ -function FromUntil(name: string, values: string[]): string { - const escaped = values.map(value => `'${Escape(value)}'`) - return `Runtime.Token.Until([${escaped.join(', ')}], input)` +function FromUntil_1(name: string, end: string[]): string { + const escaped = end.map(value => `'${Escape(value)}'`) + return `Token.Until_1([${escaped.join(', ')}], input)` } // ------------------------------------------------------------------ -// UntilNonEmpty +// Until // ------------------------------------------------------------------ -function FromUntilNonEmpty(name: string, values: string[]): string { - const escaped = values.map(value => `'${Escape(value)}'`) - return `Runtime.Token.UntilNonEmpty([${escaped.join(', ')}], input)` +function FromUntil(name: string, end: string[]): string { + const escaped = end.map(value => `'${Escape(value)}'`) + return `Token.Until([${escaped.join(', ')}], input)` } // ------------------------------------------------------------------ // Parser @@ -121,23 +135,25 @@ function FromUntilNonEmpty(name: string, values: string[]): string { function FromParser(name: string, parser: Runtime.IParser): string { return ( Runtime.IsArray(parser) ? FromArray(name, parser.parser) : - Runtime.IsConst(parser) ? FromConst(name, parser.value) : - Runtime.IsIdent(parser) ? FromIdent(name) : - Runtime.IsNumber(parser) ? FromNumber(name) : - Runtime.IsOptional(parser) ? FromOptional(name, parser) : - Runtime.IsRef(parser) ? FromRef(name, parser.ref) : - Runtime.IsString(parser) ? FromString(name, parser.options) : - Runtime.IsTuple(parser) ? FromTuple(name, parser.parsers) : - Runtime.IsUnion(parser) ? FromUnion(name, parser.parsers) : - Runtime.IsUntil(parser) ? FromUntil(name, parser.values) : - Runtime.IsUntilNonEmpty(parser) ? FromUntilNonEmpty(name, parser.values) : - Unreachable(parser) + Runtime.IsBigInt(parser) ? FromBigInt(name) : + Runtime.IsConst(parser) ? FromConst(name, parser.const) : + Runtime.IsIdent(parser) ? FromIdent(name) : + Runtime.IsInteger(parser) ? FromInteger(name) : + Runtime.IsNumber(parser) ? FromNumber(name) : + Runtime.IsOptional(parser) ? FromOptional(name, parser) : + Runtime.IsRef(parser) ? FromRef(name, parser.ref) : + Runtime.IsString(parser) ? FromString(name, parser.quotes) : + Runtime.IsTuple(parser) ? FromTuple(name, parser.parsers) : + Runtime.IsUnion(parser) ? FromUnion(name, parser.parsers) : + Runtime.IsUntil_1(parser) ? FromUntil_1(name, parser.end) : + Runtime.IsUntil(parser) ? FromUntil(name, parser.end) : + Unreachable(parser) ) } // ------------------------------------------------------------------ -// Func +// CompileRuntimeParse // ------------------------------------------------------------------ -export function CompileFunc(name: string, parser: Runtime.IParser): string { +export function BuildRuntimeParse(name: string, parser: Runtime.IParser): string { state.reducers.clear() const semanticsFunc = `S.${name}Mapping` const type = `export const ${name} = (input: string): [unknown, string] | [] => If(${FromParser(name, parser)}, ([_0, input]) => [${semanticsFunc}(_0 as ${Infer(parser)}), input])` diff --git a/src/compile/type/index.ts b/src/build/static/index.ts similarity index 89% rename from src/compile/type/index.ts rename to src/build/static/index.ts index dfb55a3..4433f86 100644 --- a/src/compile/type/index.ts +++ b/src/build/static/index.ts @@ -1,10 +1,10 @@ /*-------------------------------------------------------------------------- -@sinclair/parsebox +ParseBox The MIT License (MIT) -Copyright (c) 2024-2025 Haydn Paterson (sinclair) +Copyright (c) 2024-2025 Haydn Paterson Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal @@ -26,5 +26,5 @@ THE SOFTWARE. ---------------------------------------------------------------------------*/ -export * from './type.ts' -export * from './map.ts' +export * from './parse.ts' +export * from './mapping.ts' diff --git a/src/compile/type/map.ts b/src/build/static/mapping.ts similarity index 86% rename from src/compile/type/map.ts rename to src/build/static/mapping.ts index e5baa90..b53ee07 100644 --- a/src/compile/type/map.ts +++ b/src/build/static/mapping.ts @@ -1,10 +1,10 @@ /*-------------------------------------------------------------------------- -@sinclair/parsebox +ParseBox The MIT License (MIT) -Copyright (c) 2024-2025 Haydn Paterson (sinclair) +Copyright (c) 2024-2025 Haydn Paterson Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal @@ -28,10 +28,10 @@ THE SOFTWARE. // deno-fmt-ignore-file -import { Runtime } from '../../runtime/index.ts' +import * as Runtime from '../../runtime/index.ts' import { Infer } from '../common/index.ts' import { Name } from './name.ts' -export function CompileTypeMap(name: string, parser: Runtime.IParser): string { +export function BuildStaticMapping(name: string, parser: Runtime.IParser): string { return [`export type ${Name(name)}Mapping`, ` = Input`].join('\n') } diff --git a/src/compile/type/name.ts b/src/build/static/name.ts similarity index 92% rename from src/compile/type/name.ts rename to src/build/static/name.ts index 76fe787..eaa0a2b 100644 --- a/src/compile/type/name.ts +++ b/src/build/static/name.ts @@ -1,10 +1,10 @@ /*-------------------------------------------------------------------------- -@sinclair/parsebox +ParseBox The MIT License (MIT) -Copyright (c) 2024-2025 Haydn Paterson (sinclair) +Copyright (c) 2024-2025 Haydn Paterson Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/src/compile/type/type.ts b/src/build/static/parse.ts similarity index 71% rename from src/compile/type/type.ts rename to src/build/static/parse.ts index f582b32..066cd2a 100644 --- a/src/compile/type/type.ts +++ b/src/build/static/parse.ts @@ -1,10 +1,10 @@ /*-------------------------------------------------------------------------- -@sinclair/parsebox +ParseBox The MIT License (MIT) -Copyright (c) 2024-2025 Haydn Paterson (sinclair) +Copyright (c) 2024-2025 Haydn Paterson Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal @@ -27,10 +27,11 @@ THE SOFTWARE. ---------------------------------------------------------------------------*/ // deno-fmt-ignore-file -// deno-lint-ignore-file no-unused-vars +// deno-lint-ignore-file -import { Runtime } from '../../runtime/index.ts' -import { Infer, Escape, Unreachable } from '../common/index.ts' +import { Unreachable } from '../../system/unreachable/index.ts' +import * as Runtime from '../../runtime/index.ts' +import { Infer, Escape } from '../common/index.ts' import { Name } from './name.ts' // ------------------------------------------------------------------ @@ -54,20 +55,32 @@ function FromArray(name: string, parser: Runtime.IParser): string { // ------------------------------------------------------------------ // Const // ------------------------------------------------------------------ -function FromConst(name: string, value: string): string { - return `Static.Token.Const<'${Escape(value)}', Input>` +function FromConst(name: string, const_: string): string { + return `Token.TConst<'${Escape(const_)}', Input>` +} +// ------------------------------------------------------------------ +// BigInt +// ------------------------------------------------------------------ +function FromBigInt(name: string): string { + return `Token.TBigInt` } // ------------------------------------------------------------------ // Ident // ------------------------------------------------------------------ function FromIdent(name: string): string { - return `Static.Token.Ident` + return `Token.TIdent` +} +// ------------------------------------------------------------------ +// Integer +// ------------------------------------------------------------------ +function FromInteger(name: string): string { + return `Token.TInteger` } // ------------------------------------------------------------------ // Number // ------------------------------------------------------------------ function FromNumber(name: string): string { - return `Static.Token.Number` + return `Token.TNumber` } // ------------------------------------------------------------------ // Optional @@ -84,9 +97,9 @@ function FromRef(name: string, ref: string): string { // ------------------------------------------------------------------ // String // ------------------------------------------------------------------ -function FromString(name: string, string_options: string[]): string { - const _options = string_options.map((option) => `'${Escape(option)}'`).join(', ') - return `Static.Token.String<[${_options}], Input>` +function FromString(name: string, quotes: string[]): string { + const _quotes = quotes.map((option) => `'${Escape(option)}'`).join(', ') + return `Token.TString<[${_quotes}], Input>` } // ------------------------------------------------------------------ // Tuple @@ -102,18 +115,18 @@ function FromUnion(name: string, parsers: Runtime.IParser[]): string { return parsers.length === 0 ? '[]' : `(${parsers.reduceRight((result, right) => `${FromParser(name, right)} extends [infer _0, infer Input extends string] ? [_0, Input] : ${result}`, '[]')})` } // ------------------------------------------------------------------ -// Until +// Until_1 // ------------------------------------------------------------------ -function FromUntil(name: string, values: string[]): string { - const escaped = values.map(value => `'${Escape(value)}'`) - return `Static.Token.Until<[${escaped.join(', ')}], Input>` +function FromUntil_1(name: string, end: string[]): string { + const escaped = end.map(value => `'${Escape(value)}'`) + return `Token.TUntil_1<[${escaped.join(', ')}], Input>` } // ------------------------------------------------------------------ -// UntilNonEmpty +// Until // ------------------------------------------------------------------ -function FromUntilNonEmpty(name: string, values: string[]): string { - const escaped = values.map(value => `'${Escape(value)}'`) - return `Static.Token.UntilNonEmpty<[${escaped.join(', ')}], Input>` +function FromUntil(name: string, end: string[]): string { + const escaped = end.map(value => `'${Escape(value)}'`) + return `Token.TUntil<[${escaped.join(', ')}], Input>` } // ------------------------------------------------------------------ // Parser @@ -121,23 +134,25 @@ function FromUntilNonEmpty(name: string, values: string[]): string { function FromParser(name: string, parser: Runtime.IParser): string { return ( Runtime.IsArray(parser) ? FromArray(name, parser.parser) : - Runtime.IsConst(parser) ? FromConst(name, parser.value) : - Runtime.IsIdent(parser) ? FromIdent(name) : - Runtime.IsNumber(parser) ? FromNumber(name) : - Runtime.IsOptional(parser) ? FromOptional(name, parser) : - Runtime.IsRef(parser) ? FromRef(name, parser.ref) : - Runtime.IsString(parser) ? FromString(name, parser.options) : - Runtime.IsTuple(parser) ? FromTuple(name, parser.parsers) : - Runtime.IsUnion(parser) ? FromUnion(name, parser.parsers) : - Runtime.IsUntil(parser) ? FromUntil(name, parser.values) : - Runtime.IsUntilNonEmpty(parser) ? FromUntilNonEmpty(name, parser.values) : - Unreachable(parser) + Runtime.IsBigInt(parser) ? FromBigInt(name) : + Runtime.IsConst(parser) ? FromConst(name, parser.const) : + Runtime.IsInteger(parser) ? FromInteger(name) : + Runtime.IsIdent(parser) ? FromIdent(name) : + Runtime.IsNumber(parser) ? FromNumber(name) : + Runtime.IsOptional(parser) ? FromOptional(name, parser) : + Runtime.IsRef(parser) ? FromRef(name, parser.ref) : + Runtime.IsString(parser) ? FromString(name, parser.quotes) : + Runtime.IsTuple(parser) ? FromTuple(name, parser.parsers) : + Runtime.IsUnion(parser) ? FromUnion(name, parser.parsers) : + Runtime.IsUntil_1(parser) ? FromUntil_1(name, parser.end) : + Runtime.IsUntil(parser) ? FromUntil(name, parser.end) : + Unreachable(parser) ) } // ------------------------------------------------------------------ // Type // ------------------------------------------------------------------ -export function CompileType(name: string, parser: Runtime.IParser): string { +export function BuildStaticParse(name: string, parser: Runtime.IParser): string { state.reducers.clear() const semanticsType = `S.${Name(name)}Mapping` const type = `export type ${Name(name)} = ${FromParser(name, parser)} extends [infer _0 extends ${Infer(parser)}, infer Input extends string] ? [${semanticsType}<_0>, Input] : []` diff --git a/src/guard/guard.ts b/src/guard/guard.ts index 489b06d..91c3fb7 100644 --- a/src/guard/guard.ts +++ b/src/guard/guard.ts @@ -1,10 +1,10 @@ /*-------------------------------------------------------------------------- -@sinclair/parsebox +ParseBox The MIT License (MIT) -Copyright (c) 2024-2025 Haydn Paterson (sinclair) +Copyright (c) 2024-2025 Haydn Paterson Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal @@ -26,20 +26,35 @@ THE SOFTWARE. ---------------------------------------------------------------------------*/ -// deno-fmt-ignore-file - -export function IsEqual(left: unknown, right: unknown): boolean { - return left === right +// -------------------------------------------------------------------------- +// Guards +// -------------------------------------------------------------------------- +/** Returns true if this value is an array */ +export function IsArray(value: unknown): value is unknown[] { + return Array.isArray(value) } -export function HasPropertyKey(value: Record, key: Key): value is Record & { [_ in Key]: unknown } { - return key in value +/** Returns true if this value is null */ +export function IsNull(value: unknown): value is null { + return IsEqual(value, null) } +/** Returns true if this value is an object */ export function IsObject(value: unknown): value is Record { - return typeof value === 'object' && value !== null -} -export function IsArray(value: unknown): value is unknown[] { - return globalThis.Array.isArray(value) + return IsEqual(typeof value, 'object') && !(IsNull(value)) } +/** Returns true if this value is string */ export function IsString(value: unknown): value is string { - return typeof value === 'string' -} \ No newline at end of file + return IsEqual(typeof value, 'string') +} +// -------------------------------------------------------------------------- +// Relational +// -------------------------------------------------------------------------- +export function IsEqual(left: unknown, right: unknown): boolean { + return left === right +} +// -------------------------------------------------------------------------- +// Object +// -------------------------------------------------------------------------- +/** Returns true if this value has this property key */ +export function HasPropertyKey(value: object, key: Key): value is { [_ in Key]: unknown } { + return Object.prototype.hasOwnProperty.call(value, key) +} diff --git a/src/guard/index.ts b/src/guard/index.ts index 517f3d5..8b5079a 100644 --- a/src/guard/index.ts +++ b/src/guard/index.ts @@ -1,10 +1,10 @@ /*-------------------------------------------------------------------------- -@sinclair/parsebox +ParseBox The MIT License (MIT) -Copyright (c) 2024-2025 Haydn Paterson (sinclair) +Copyright (c) 2024-2025 Haydn Paterson Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal @@ -26,4 +26,4 @@ THE SOFTWARE. ---------------------------------------------------------------------------*/ -export * as Guard from './guard.ts' \ No newline at end of file +export * as Guard from './guard.ts' diff --git a/src/index.ts b/src/index.ts index c042578..1d3e1c7 100644 --- a/src/index.ts +++ b/src/index.ts @@ -26,6 +26,8 @@ THE SOFTWARE. ---------------------------------------------------------------------------*/ -export * from './compile/index.ts' -export * from './runtime/index.ts' -export * from './static/index.ts' +export * as Build from './build/index.ts' +export * as Runtime from './runtime/index.ts' +export * as Static from './static/index.ts' +export * as System from './system/index.ts' +export * as Token from './token/index.ts' diff --git a/src/runtime/array.ts b/src/runtime/array.ts new file mode 100644 index 0000000..30ee5d2 --- /dev/null +++ b/src/runtime/array.ts @@ -0,0 +1,87 @@ +/*-------------------------------------------------------------------------- + +ParseBox + +The MIT License (MIT) + +Copyright (c) 2024-2025 Haydn Paterson + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +---------------------------------------------------------------------------*/ + +// deno-fmt-ignore-file + +import { Arguments } from '../system/arguments/index.ts' +import { Guard } from '../guard/index.ts' +import { type StaticParser, type StaticEnsure } from './static.ts' +import { type IParser, type IProperties, type IMapping, Identity } from './parser.ts' + +import { ParseParser } from './parse.ts' + +// ------------------------------------------------------------------ +// Static +// ------------------------------------------------------------------ +export type StaticArray = StaticEnsure< + StaticParser[] +> +// ------------------------------------------------------------------ +// Type +// ------------------------------------------------------------------ +export interface IArray extends IParser { + type: 'Array' + parser: IParser +} +// ------------------------------------------------------------------ +// Factory +// ------------------------------------------------------------------ +export function Array>>(parser: Parser, mapping: Mapping): IArray> +export function Array(parser: Parser): IArray> +export function Array(...args: unknown[]): never { + const [parser, mapping] = Arguments.Match<[IParser, IMapping]>(args, { + 2: (parser, mapping) => [parser, mapping], + 1: (parser) => [parser, Identity] + }) + return { type: 'Array', parser, mapping } as never +} +// ------------------------------------------------------------------ +// Guard +// ------------------------------------------------------------------ +/** True if the value is a Array parser */ +export function IsArray(value: unknown): value is IArray { + return Guard.IsObject(value) + && Guard.HasPropertyKey(value, 'type') + && Guard.HasPropertyKey(value, 'parser') + && Guard.IsEqual(value.type, 'Array') + && Guard.IsObject(value.parser) +} +// ------------------------------------------------------------------ +// Parse +// ------------------------------------------------------------------ +export function ParseArray(context: Context, parser: Parser, input: string): unknown[] { + const buffer = [] as unknown[] + let rest = input + while (rest.length > 0) { + const result = ParseParser(context, parser, rest) + if (result.length === 0) return [buffer, rest] + buffer.push(result[0]) + rest = result[1] + } + return [buffer, rest] +} \ No newline at end of file diff --git a/src/runtime/bigint.ts b/src/runtime/bigint.ts new file mode 100644 index 0000000..2015f9d --- /dev/null +++ b/src/runtime/bigint.ts @@ -0,0 +1,68 @@ +/*-------------------------------------------------------------------------- + +ParseBox + +The MIT License (MIT) + +Copyright (c) 2024-2025 Haydn Paterson + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +---------------------------------------------------------------------------*/ + +// deno-fmt-ignore-file + +import * as Token from '../token/index.ts' + +import { Arguments } from '../system/arguments/index.ts' +import { Guard } from '../guard/index.ts' +import { type IParser, type IMapping, Identity } from './parser.ts' + +// ------------------------------------------------------------------ +// Type +// ------------------------------------------------------------------ +export interface IBigInt extends IParser { + type: 'BigInt' +} +// ------------------------------------------------------------------ +// Factory +// ------------------------------------------------------------------ +export function BigInt>(mapping: Mapping): IBigInt> +export function BigInt(): IBigInt +export function BigInt(...args: unknown[]): never { + const [mapping] = Arguments.Match<[IParser, IMapping]>(args, { + 1: (mapping) => [mapping], + 0: () => [Identity] + }) + return { type: 'BigInt', mapping } as never +} +// ------------------------------------------------------------------ +// Guard +// ------------------------------------------------------------------ +export function IsBigInt(value: unknown): value is IBigInt { + return Guard.IsObject(value) + && Guard.HasPropertyKey(value, 'type') + && Guard.IsEqual(value.type, 'BigInt') +} +// ------------------------------------------------------------------ +// Parse +// ------------------------------------------------------------------ +export function ParseBigInt(input: string): [] | [string, string] { + return Token.BigInt(input) +} \ No newline at end of file diff --git a/src/runtime/const.ts b/src/runtime/const.ts new file mode 100644 index 0000000..94f518e --- /dev/null +++ b/src/runtime/const.ts @@ -0,0 +1,71 @@ +/*-------------------------------------------------------------------------- + +ParseBox + +The MIT License (MIT) + +Copyright (c) 2024-2025 Haydn Paterson + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +---------------------------------------------------------------------------*/ + +// deno-fmt-ignore-file + +import * as Token from '../token/index.ts' + +import { Arguments } from '../system/arguments/index.ts' +import { Guard } from '../guard/index.ts' +import { type IParser, type IMapping, Identity } from './parser.ts' + +// ------------------------------------------------------------------ +// Type +// ------------------------------------------------------------------ +export interface IConst extends IParser { + type: 'Const' + const: string +} +// ------------------------------------------------------------------ +// Factory +// ------------------------------------------------------------------ +export function Const>(value: Value, mapping: Mapping): IConst> +export function Const(value: Value): IConst +export function Const(...args: unknown[]): never { + const [const_, mapping] = Arguments.Match<[string, IMapping]>(args, { + 2: (const_, mapping) => [const_, mapping], + 1: (const_) => [const_, Identity] + }) + return { type: 'Const', const: const_, mapping } as never +} +// ------------------------------------------------------------------ +// Guard +// ------------------------------------------------------------------ +export function IsConst(value: unknown): value is IConst { + return Guard.IsObject(value) + && Guard.HasPropertyKey(value, 'type') + && Guard.HasPropertyKey(value, 'const') + && Guard.IsEqual(value.type, 'Const') + && Guard.IsString(value.const) +} +// ------------------------------------------------------------------ +// Parse +// ------------------------------------------------------------------ +export function ParseConst(const_: Const, input: string): [] | [Const, string] { + return Token.Const(const_, input) as never +} \ No newline at end of file diff --git a/src/runtime/ident.ts b/src/runtime/ident.ts new file mode 100644 index 0000000..f9918d2 --- /dev/null +++ b/src/runtime/ident.ts @@ -0,0 +1,68 @@ +/*-------------------------------------------------------------------------- + +ParseBox + +The MIT License (MIT) + +Copyright (c) 2024-2025 Haydn Paterson + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +---------------------------------------------------------------------------*/ + +// deno-fmt-ignore-file + +import * as Token from '../token/index.ts' + +import { Arguments } from '../system/arguments/index.ts' +import { Guard } from '../guard/index.ts' +import { type IParser, type IMapping, Identity } from './parser.ts' + +// ------------------------------------------------------------------ +// Type +// ------------------------------------------------------------------ +export interface IIdent extends IParser { + type: 'Ident' +} +// ------------------------------------------------------------------ +// Factory +// ------------------------------------------------------------------ +export function Ident>(mapping: Mapping): IIdent> +export function Ident(): IIdent +export function Ident(...args: unknown[]): never { + const [mapping] = Arguments.Match<[IParser, IMapping]>(args, { + 1: (mapping) => [mapping], + 0: () => [Identity] + }) + return { type: 'Ident', mapping } as never +} +// ------------------------------------------------------------------ +// Guard +// ------------------------------------------------------------------ +export function IsIdent(value: unknown): value is IIdent { + return Guard.IsObject(value) + && Guard.HasPropertyKey(value, 'type') + && Guard.IsEqual(value.type, 'Ident') +} +// ------------------------------------------------------------------ +// Parse +// ------------------------------------------------------------------ +export function ParseIdent(input: string): [] | [string, string] { + return Token.Ident(input) +} \ No newline at end of file diff --git a/src/runtime/index.ts b/src/runtime/index.ts index 9bcd763..0ec2dfc 100644 --- a/src/runtime/index.ts +++ b/src/runtime/index.ts @@ -1,10 +1,10 @@ /*-------------------------------------------------------------------------- -@sinclair/parsebox +ParseBox The MIT License (MIT) -Copyright (c) 2024-2025 Haydn Paterson (sinclair) +Copyright (c) 2024-2025 Haydn Paterson Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal @@ -26,4 +26,21 @@ THE SOFTWARE. ---------------------------------------------------------------------------*/ -export * as Runtime from './runtime.ts' +// deno-fmt-ignore-file + +export { type IArray, Array, IsArray } from './array.ts' +export { type IBigInt, BigInt, IsBigInt } from './bigint.ts' +export { type IConst, Const, IsConst } from './const.ts' +export { type IIdent, Ident, IsIdent } from './ident.ts' +export { type IInteger, Integer, IsInteger } from './integer.ts' +export { Module } from './module.ts' +export { type INumber, IsNumber, Number } from './number.ts' +export { type IOptional, IsOptional, Optional } from './optional.ts' +export { Parse } from './parse.ts' +export { type IParser, type IProperties, type IMapping, As, Identity } from './parser.ts' +export { type IRef, Ref, IsRef, } from './ref.ts' +export { type IString, IsString, String } from './string.ts' +export { type ITuple, IsTuple, Tuple } from './tuple.ts' +export { type IUnion, IsUnion, Union } from './union.ts' +export { type IUntil_1, IsUntil_1, Until_1 } from './until_1.ts' +export { type IUntil, IsUntil, Until } from './until.ts' diff --git a/src/runtime/integer.ts b/src/runtime/integer.ts new file mode 100644 index 0000000..029992c --- /dev/null +++ b/src/runtime/integer.ts @@ -0,0 +1,68 @@ +/*-------------------------------------------------------------------------- + +ParseBox + +The MIT License (MIT) + +Copyright (c) 2024-2025 Haydn Paterson + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +---------------------------------------------------------------------------*/ + +// deno-fmt-ignore-file + +import * as Token from '../token/index.ts' + +import { Arguments } from '../system/arguments/index.ts' +import { Guard } from '../guard/index.ts' +import { type IParser, type IMapping, Identity } from './parser.ts' + +// ------------------------------------------------------------------ +// Type +// ------------------------------------------------------------------ +export interface IInteger extends IParser { + type: 'Integer' +} +// ------------------------------------------------------------------ +// Factory +// ------------------------------------------------------------------ +export function Integer>(mapping: Mapping): IInteger> +export function Integer(): IInteger +export function Integer(...args: unknown[]): never { + const [mapping] = Arguments.Match<[IParser, IMapping]>(args, { + 1: (mapping) => [mapping], + 0: () => [Identity] + }) + return { type: 'Integer', mapping } as never +} +// ------------------------------------------------------------------ +// Guard +// ------------------------------------------------------------------ +export function IsInteger(value: unknown): value is IInteger { + return Guard.IsObject(value) + && Guard.HasPropertyKey(value, 'type') + && Guard.IsEqual(value.type, 'Integer') +} +// ------------------------------------------------------------------ +// Parse +// ------------------------------------------------------------------ +export function ParseInteger(input: string): [] | [string, string] { + return Token.Integer(input) +} \ No newline at end of file diff --git a/src/runtime/module.ts b/src/runtime/module.ts index 3c5e6f4..c029b69 100644 --- a/src/runtime/module.ts +++ b/src/runtime/module.ts @@ -1,10 +1,10 @@ /*-------------------------------------------------------------------------- -@sinclair/parsebox +ParseBox The MIT License (MIT) -Copyright (c) 2024-2025 Haydn Paterson (sinclair) +Copyright (c) 2024-2025 Haydn Paterson Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal @@ -28,19 +28,18 @@ THE SOFTWARE. // deno-fmt-ignore-file -import * as Types from './types.ts' +import { type IProperties } from './parser.ts' +import { type StaticParser } from './static.ts' import { Parse } from './parse.ts' // ------------------------------------------------------------------ // Module // ------------------------------------------------------------------ -export class Module { +export class Module { constructor(public readonly parsers: Properties) { } + /** Parses using one of the parsers defined on this instance */ - public Parse(key: Key, content: string): [] | [Types.StaticParser, string] - /** Parses using one of the parsers defined on this instance */ - public Parse(...args: never[]): never { - const [key, content] = [args[0], args[1]] - return Parse(this.parsers, this.parsers[key], content) as never + public Parse(key: Key, input: string): [] | [StaticParser, string] { + return Parse(this.parsers, this.parsers[key], input) as never } } diff --git a/src/runtime/number.ts b/src/runtime/number.ts new file mode 100644 index 0000000..381e570 --- /dev/null +++ b/src/runtime/number.ts @@ -0,0 +1,68 @@ +/*-------------------------------------------------------------------------- + +ParseBox + +The MIT License (MIT) + +Copyright (c) 2024-2025 Haydn Paterson + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +---------------------------------------------------------------------------*/ + +// deno-fmt-ignore-file + +import * as Token from '../token/index.ts' + +import { Arguments } from '../system/arguments/index.ts' +import { Guard } from '../guard/index.ts' +import { type IParser, type IMapping, Identity } from './parser.ts' + +// ------------------------------------------------------------------ +// Type +// ------------------------------------------------------------------ +export interface INumber extends IParser { + type: 'Number' +} +// ------------------------------------------------------------------ +// Factory +// ------------------------------------------------------------------ +export function Number>(mapping: Mapping): INumber> +export function Number(): INumber +export function Number(...args: unknown[]): never { + const [mapping] = Arguments.Match<[IParser, IMapping]>(args, { + 1: (mapping) => [mapping], + 0: () => [Identity] + }) + return { type: 'Number', mapping } as never +} +// ------------------------------------------------------------------ +// Guard +// ------------------------------------------------------------------ +export function IsNumber(value: unknown): value is INumber { + return Guard.IsObject(value) + && Guard.HasPropertyKey(value, 'type') + && Guard.IsEqual(value.type, 'Number') +} +// ------------------------------------------------------------------ +// Parse +// ------------------------------------------------------------------ +export function ParseNumber(input: string): [] | [string, string] { + return Token.Number(input) +} \ No newline at end of file diff --git a/src/runtime/optional.ts b/src/runtime/optional.ts new file mode 100644 index 0000000..0c09581 --- /dev/null +++ b/src/runtime/optional.ts @@ -0,0 +1,83 @@ +/*-------------------------------------------------------------------------- + +ParseBox + +The MIT License (MIT) + +Copyright (c) 2024-2025 Haydn Paterson + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +---------------------------------------------------------------------------*/ + +// deno-fmt-ignore-file + +import { Arguments } from '../system/arguments/index.ts' +import { Guard } from '../guard/index.ts' + +import { type StaticParser } from './static.ts' +import { type IParser, type IProperties, type IMapping, Identity } from './parser.ts' +import { ParseParser } from './parse.ts' + +// ------------------------------------------------------------------ +// Static +// ------------------------------------------------------------------ +export type StaticOptional] | []> = ( + Result +) +// ------------------------------------------------------------------ +// Type +// ------------------------------------------------------------------ +export interface IOptional extends IParser { + type: 'Optional' + parser: IParser +} +// ------------------------------------------------------------------ +// Factory +// ------------------------------------------------------------------ +export function Optional>>(parser: Parser, mapping: Mapping): IOptional> +export function Optional(parser: Parser): IOptional> +export function Optional(...args: unknown[]): never { + const [parser, mapping] = Arguments.Match<[IParser, IMapping]>(args, { + 2: (parser, mapping) => [parser, mapping], + 1: (parser) => [parser, Identity] + }) + return { type: 'Optional', parser, mapping } as never +} +// ------------------------------------------------------------------ +// Guard +// ------------------------------------------------------------------ +export function IsOptional(value: unknown): value is IOptional { + return Guard.IsObject(value) + && Guard.HasPropertyKey(value, 'type') + && Guard.HasPropertyKey(value, 'parser') + && Guard.IsEqual(value.type, 'Optional') + && Guard.IsObject(value.parser) +} +// ------------------------------------------------------------------ +// Optional +// ------------------------------------------------------------------ +export function ParseOptional(context: Context, parser: Parser, input: string): [] | [[unknown] | [], unknown] { + const result = ParseParser(context, parser, input) + return ( + Guard.IsEqual(result.length, 2) + ? [[result[0]], result[1]] + : [[], input] + ) as never +} \ No newline at end of file diff --git a/src/runtime/parse.ts b/src/runtime/parse.ts index 3d39ca4..96b7980 100644 --- a/src/runtime/parse.ts +++ b/src/runtime/parse.ts @@ -1,10 +1,10 @@ /*-------------------------------------------------------------------------- -@sinclair/parsebox +ParseBox The MIT License (MIT) -Copyright (c) 2024-2025 Haydn Paterson (sinclair) +Copyright (c) 2024-2025 Haydn Paterson Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal @@ -27,137 +27,61 @@ THE SOFTWARE. ---------------------------------------------------------------------------*/ // deno-fmt-ignore-file -// deno-lint-ignore-file -import * as Token from './token.ts' -import * as Types from './types.ts' +import { Guard } from '../guard/index.ts' +import { Arguments } from '../system/arguments/index.ts' -export function Throw(message: string): never { - throw new Error(message) -} -// ------------------------------------------------------------------ -// Array -// ------------------------------------------------------------------ -function ParseArray(moduleProperties: ModuleProperties, parser: Parser, input: string): unknown[] { - const buffer = [] as unknown[] - let rest = input - while (rest.length > 0) { - const result = ParseParser(moduleProperties, parser, rest) - if (result.length === 0) return [buffer, rest] - buffer.push(result[0]) - rest = result[1] - } - return [buffer, rest] -} +import { type StaticParser } from './static.ts' +import { type IParser, type IProperties } from './parser.ts' + +import { ParseArray, IsArray } from './array.ts' +import { ParseBigInt, IsBigInt } from './bigint.ts' +import { ParseConst, IsConst } from './const.ts' +import { ParseIdent, IsIdent } from './ident.ts' +import { ParseInteger, IsInteger } from './integer.ts' +import { ParseNumber, IsNumber } from './number.ts' +import { ParseOptional, IsOptional } from './optional.ts' +import { ParseRef, IsRef } from './ref.ts' +import { ParseString, IsString } from './string.ts' +import { ParseTuple, IsTuple } from './tuple.ts' +import { ParseUnion, IsUnion } from './union.ts' +import { ParseUntil_1, IsUntil_1 } from './until_1.ts' +import { ParseUntil, IsUntil } from './until.ts' // ------------------------------------------------------------------ -// Const -// ------------------------------------------------------------------ -function ParseConst(value: Value, input: string): [] | [Value, string] { - return Token.Const(value, input) as never -} -// ------------------------------------------------------------------ -// Ident -// ------------------------------------------------------------------ -function ParseIdent(input: string): [] | [string, string] { - return Token.Ident(input) -} -// ------------------------------------------------------------------ -// Number -// ------------------------------------------------------------------ -function ParseNumber(input: string): [] | [string, string] { - return Token.Number(input) -} -// ------------------------------------------------------------------ -// Optional -// ------------------------------------------------------------------ -function ParseOptional(moduleProperties: ModuleProperties, parser: Parser, input: string): [] | [[unknown] | [], unknown] { - const result = ParseParser(moduleProperties, parser, input) - return (result.length === 2 ? [[result[0]], result[1]] : [[], input]) as never -} -// ------------------------------------------------------------------ -// Ref -// ------------------------------------------------------------------ -function ParseRef(moduleProperties: ModuleProperties, ref: Ref, input: string): [] | [string, string] { - const parser = ref in moduleProperties ? moduleProperties[ref] : Throw(`Cannot dereference Parser '${ref}'`) - return ParseParser(moduleProperties, parser, input) as never -} -// ------------------------------------------------------------------ -// String -// ------------------------------------------------------------------ -function ParseString(options: string[], code: string): [] | [string, string] { - return Token.String(options, code) -} -// ------------------------------------------------------------------ -// Tuple -// ------------------------------------------------------------------ -function ParseTuple(moduleProperties: ModuleProperties, parsers: [...Parsers], input: string): [] | [unknown[], string] { - const buffer = [] as unknown[] - let rest = input - for (const parser of parsers) { - const result = ParseParser(moduleProperties, parser, rest) - if (result.length === 0) return [] - buffer.push(result[0]) - rest = result[1] - } - return [buffer, rest] -} -// ------------------------------------------------------------------ -// Union -// ------------------------------------------------------------------ -function ParseUnion(moduleProperties: ModuleProperties, parsers: [...Parsers], input: string): [] | [unknown, string] { - for (const parser of parsers) { - const result = ParseParser(moduleProperties, parser, input) - if (result.length === 0) continue - return result - } - return [] -} -// ------------------------------------------------------------------ -// Until -// ------------------------------------------------------------------ -function ParseUntil(values: [...Values], input: string): [] | [string, string] { - return Token.Until(values, input) as never -} -// ------------------------------------------------------------------ -// Until -// ------------------------------------------------------------------ -function ParseUntilNonEmpty(values: [...Values], code: string): [] | [string, string] { - return Token.UntilNonEmpty(values, code) as never -} -// ------------------------------------------------------------------ -// Parser +// ParseParser // ------------------------------------------------------------------ -function ParseParser(moduleProperties: Types.IModuleProperties, parser: Parser, input: string): [] | [Types.StaticParser, string] { +export function ParseParser(context: IProperties, parser: Parser, input: string): [] | [StaticParser, string] { const result = ( - Types.IsArray(parser) ? ParseArray(moduleProperties, parser.parser, input) : - Types.IsConst(parser) ? ParseConst(parser.value, input) : - Types.IsIdent(parser) ? ParseIdent(input) : - Types.IsNumber(parser) ? ParseNumber(input) : - Types.IsOptional(parser) ? ParseOptional(moduleProperties, parser.parser, input) : - Types.IsRef(parser) ? ParseRef(moduleProperties, parser.ref, input) : - Types.IsString(parser) ? ParseString(parser.options, input) : - Types.IsTuple(parser) ? ParseTuple(moduleProperties, parser.parsers, input) : - Types.IsUnion(parser) ? ParseUnion(moduleProperties, parser.parsers, input) : - Types.IsUntil(parser) ? ParseUntil(parser.values, input) : - Types.IsUntilNonEmpty(parser) ? ParseUntilNonEmpty(parser.values, input) : - [] + IsArray(parser) ? ParseArray(context, parser.parser, input) : + IsBigInt(parser) ? ParseBigInt(input) : + IsConst(parser) ? ParseConst(parser.const, input) : + IsIdent(parser) ? ParseIdent(input) : + IsInteger(parser) ? ParseInteger(input) : + IsNumber(parser) ? ParseNumber(input) : + IsOptional(parser) ? ParseOptional(context, parser.parser, input) : + IsRef(parser) ? ParseRef(context, parser.ref, input) : + IsString(parser) ? ParseString(parser.quotes, input) : + IsTuple(parser) ? ParseTuple(context, parser.parsers, input) : + IsUnion(parser) ? ParseUnion(context, parser.parsers, input) : + IsUntil(parser) ? ParseUntil(parser.end, input) : + IsUntil_1(parser) ? ParseUntil_1(parser.end, input) : + [] ) - return (result.length === 2 ? [parser.mapping(result[0]), result[1]] : result) as never + return (Guard.IsEqual(result.length, 2) ? [parser.mapping(result[0]), result[1]] : result) as never } - // ------------------------------------------------------------------ // Parse // ------------------------------------------------------------------ -/** Parses content using the given Parser */ -export function Parse(moduleProperties: Types.IModuleProperties, parser: Parser, input: string): [] | [Types.StaticParser, string] -/** Parses content using the given Parser */ -export function Parse(parser: Parser, content: string): [] | [Types.StaticParser, string] -/** Parses content using the given parser */ +/** Parses input using the given Parser */ +export function Parse(context: IProperties, parser: Parser, input: string): [] | [StaticParser, string] +/** Parses input using the given Parser */ +export function Parse(parser: Parser, content: string): [] | [StaticParser, string] +/** Parses input using the given Parser */ export function Parse(...args: any[]): never { - const withModuleProperties = typeof args[1] === 'string' ? false : true - const [moduleProperties, parser, input] = withModuleProperties - ? [args[0], args[1], args[2]] - : [{}, args[0], args[1]] - return ParseParser(moduleProperties, parser, input) as never + const [context, parser, input] = Arguments.Match<[IProperties, IParser, string]>(args, { + 3: (context, parser, input) => [context, parser, input], + 2: (parser, input) => [{}, parser, input] + }) + return ParseParser(context, parser, input) as never } diff --git a/src/runtime/parser.ts b/src/runtime/parser.ts new file mode 100644 index 0000000..84e12fa --- /dev/null +++ b/src/runtime/parser.ts @@ -0,0 +1,51 @@ +/*-------------------------------------------------------------------------- + +ParseBox + +The MIT License (MIT) + +Copyright (c) 2024-2025 Haydn Paterson + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +---------------------------------------------------------------------------*/ + +// deno-fmt-ignore-file + +export type IProperties = Record + +// ------------------------------------------------------------------ +// Mapping +// ------------------------------------------------------------------ +export type IMapping = (input: Input) => Output + +/** Maps input to output. This is the default Mapping */ +export const Identity = (value: unknown) => value + +/** Maps the output as the given parameter T */ +export function As(mapping: T): ((value: unknown) => T) { + return (_: unknown) => mapping +} +// ------------------------------------------------------------------ +// Parser +// ------------------------------------------------------------------ +export interface IParser { + type: string + mapping: IMapping +} \ No newline at end of file diff --git a/src/runtime/ref.ts b/src/runtime/ref.ts new file mode 100644 index 0000000..8a4c083 --- /dev/null +++ b/src/runtime/ref.ts @@ -0,0 +1,71 @@ +/*-------------------------------------------------------------------------- + +ParseBox + +The MIT License (MIT) + +Copyright (c) 2024-2025 Haydn Paterson + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +---------------------------------------------------------------------------*/ + +// deno-fmt-ignore-file + +import { Arguments } from '../system/arguments/index.ts' +import { Guard } from '../guard/index.ts' +import { type IParser, type IProperties, type IMapping, Identity } from './parser.ts' +import { ParseParser } from './parse.ts' + +// ------------------------------------------------------------------ +// Type +// ------------------------------------------------------------------ +export interface IRef extends IParser { + type: 'Ref' + ref: string +} +// ------------------------------------------------------------------ +// Factory +// ------------------------------------------------------------------ +export function Ref>(ref: string, mapping: Mapping): IRef> +export function Ref(ref: string): IRef +export function Ref(...args: unknown[]): never { + const [ref, mapping] = Arguments.Match<[string, IMapping]>(args, { + 2: (ref, mapping) => [ref, mapping], + 1: (ref) => [ref, Identity] + }) + return { type: 'Ref', ref, mapping } as never +} +// ------------------------------------------------------------------ +// Guard +// ------------------------------------------------------------------ +export function IsRef(value: unknown): value is IRef { + return Guard.IsObject(value) + && Guard.HasPropertyKey(value, 'type') + && Guard.HasPropertyKey(value, 'ref') + && Guard.IsEqual(value.type, 'Ref') + && Guard.IsString(value.ref) +} +// ------------------------------------------------------------------ +// Parse +// ------------------------------------------------------------------ +export function ParseRef(context: Context, ref: Ref, input: string): [] | [string, string] { + const parser = Guard.HasPropertyKey(context, ref) ? context[ref] : (() => { throw new Error(`Cannot dereference Parser '${ref}'`) })() + return ParseParser(context, parser, input) as never +} \ No newline at end of file diff --git a/src/runtime/runtime.ts b/src/runtime/runtime.ts deleted file mode 100644 index 42c69cf..0000000 --- a/src/runtime/runtime.ts +++ /dev/null @@ -1,32 +0,0 @@ -/*-------------------------------------------------------------------------- - -@sinclair/parsebox - -The MIT License (MIT) - -Copyright (c) 2024-2025 Haydn Paterson (sinclair) - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -THE SOFTWARE. - ----------------------------------------------------------------------------*/ - -export * as Token from './token.ts' -export * from './types.ts' -export * from './module.ts' -export * from './parse.ts' diff --git a/src/static/static.ts b/src/runtime/static.ts similarity index 68% rename from src/static/static.ts rename to src/runtime/static.ts index a3ae55b..094f550 100644 --- a/src/static/static.ts +++ b/src/runtime/static.ts @@ -1,10 +1,10 @@ /*-------------------------------------------------------------------------- -@sinclair/parsebox +ParseBox The MIT License (MIT) -Copyright (c) 2024-2025 Haydn Paterson (sinclair) +Copyright (c) 2024-2025 Haydn Paterson Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal @@ -26,6 +26,21 @@ THE SOFTWARE. ---------------------------------------------------------------------------*/ -export * as Token from './token.ts' -export * from './parse.ts' -export * from './types.ts' +// deno-fmt-ignore-file + +import { type IParser } from './parser.ts' + +// ------------------------------------------------------------------ +// Static +// ------------------------------------------------------------------ + +/** Force output static type evaluation for Arrays */ +export type StaticEnsure = T extends infer R ? R : never + +/** Infers the Output Parameter for a Parser */ +export type StaticParser = ( + Parser extends IParser + ? Output + : unknown +) + diff --git a/src/runtime/string.ts b/src/runtime/string.ts new file mode 100644 index 0000000..b98566d --- /dev/null +++ b/src/runtime/string.ts @@ -0,0 +1,71 @@ +/*-------------------------------------------------------------------------- + +ParseBox + +The MIT License (MIT) + +Copyright (c) 2024-2025 Haydn Paterson + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +---------------------------------------------------------------------------*/ + +// deno-fmt-ignore-file + +import * as Token from '../token/index.ts' +import { Arguments } from '../system/arguments/index.ts' +import { Guard } from '../guard/index.ts' +import { type IParser, type IMapping, Identity } from './parser.ts' + +// ------------------------------------------------------------------ +// Type +// ------------------------------------------------------------------ +export interface IString extends IParser { + type: 'String' + quotes: string[] +} +// ------------------------------------------------------------------ +// Factory +// ------------------------------------------------------------------ +export function String>(quotes: [...Quotes], mapping: Mapping): IString> +export function String(quotes: [...Quotes]): IString +export function String(...args: unknown[]): never { + const [quotes, mapping] = Arguments.Match<[string[], IMapping]>(args, { + 2: (quotes, mapping) => [quotes, mapping], + 1: (quotes) => [quotes, Identity] + }) + return { type: 'String', quotes, mapping } as never +} +// ------------------------------------------------------------------ +// Guard +// ------------------------------------------------------------------ +export function IsString(value: unknown): value is IString { + return Guard.IsObject(value) + && Guard.HasPropertyKey(value, 'type') + && Guard.HasPropertyKey(value, 'quotes') + && Guard.IsEqual(value.type, 'String') + && Guard.IsArray(value.quotes) + && value.quotes.every((value) => Guard.IsString(value)) +} +// ------------------------------------------------------------------ +// Parse +// ------------------------------------------------------------------ +export function ParseString(quotes: string[], input: string): [] | [string, string] { + return Token.String(quotes, input) +} \ No newline at end of file diff --git a/src/runtime/token.ts b/src/runtime/token.ts deleted file mode 100644 index 07626a0..0000000 --- a/src/runtime/token.ts +++ /dev/null @@ -1,265 +0,0 @@ -/*-------------------------------------------------------------------------- - -@sinclair/parsebox - -The MIT License (MIT) - -Copyright (c) 2024-2025 Haydn Paterson (sinclair) - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -THE SOFTWARE. - ----------------------------------------------------------------------------*/ - -// deno-fmt-ignore-file -// deno-lint-ignore-file - -// ------------------------------------------------------------------ -// Chars -// ------------------------------------------------------------------ -/** Returns true if the char code is a whitespace */ -export function IsWhitespace(charCode: number): boolean { - return charCode === 32 -} -/** Returns true if the char code is a newline */ -export function IsNewline(charCode: number): boolean { - return charCode === 10 -} -/** Returns true if the char code is a alpha */ -export function IsAlpha(charCode: number): boolean { - return ( - (charCode >= 65 && charCode <= 90) || // A-Z - (charCode >= 97 && charCode <= 122) // a-z - ) -} -/** Returns true if the char code is zero */ -export function IsZero(charCode: number): boolean { - return charCode === 48 -} -/** Returns true if the char code is non-zero */ -export function IsNonZero(charCode: number): boolean { - return charCode >= 49 && charCode <= 57 -} -/** Returns true if the char code is a digit */ -export function IsDigit(charCode: number): boolean { - return ( - IsNonZero(charCode) || - IsZero(charCode) - ) -} -/** Returns true if the char code is a dot */ -export function IsDot(charCode: number): boolean { - return charCode === 46 -} -/** Returns true if this char code is a underscore */ -export function IsUnderscore(charCode: number): boolean { - return charCode === 95 -} -/** Returns true if this char code is a dollar sign */ -export function IsDollarSign(charCode: number): boolean { - return charCode === 36 -} - -// ------------------------------------------------------------------ -// Trim -// ------------------------------------------------------------------ -/** Trims Whitespace and retains Newline, Tabspaces, etc. */ -export function TrimWhitespaceOnly(input: string): string { - for (let i = 0; i < input.length; i++) { - if (IsWhitespace(input.charCodeAt(i))) continue - return input.slice(i) - } - return input -} -/** Trims Whitespace including Newline, Tabspaces, etc. */ -export function TrimAll(input: string): string { - return input.trimStart() -} -// ------------------------------------------------------------------ -// Const -// ------------------------------------------------------------------ -/** Checks the value matches the next string */ -function NextTokenCheck(value: string, input: string): boolean { - if (value.length > input.length) return false - for (let i = 0; i < value.length; i++) { - if (value.charCodeAt(i) !== input.charCodeAt(i)) return false - } - return true -} -/** Gets the next constant string value or empty if no match */ -function NextConst(value: string, input: string, ): [] | [string, string] { - return NextTokenCheck(value, input) - ? [input.slice(0, value.length), input.slice(value.length)] - : [] -} -/** Takes the next constant string value skipping any whitespace */ -export function Const(value: string, input: string): [] | [string, string] { - if(value.length === 0) return ['', input] - const char_0 = value.charCodeAt(0) - return ( - IsNewline(char_0) ? NextConst(value, TrimWhitespaceOnly(input)) : - IsWhitespace(char_0) ? NextConst(value, input) : - NextConst(value, TrimAll(input)) - ) -} -// ------------------------------------------------------------------ -// Ident -// ------------------------------------------------------------------ -function IdentIsFirst(charCode: number) { - return ( - IsAlpha(charCode) || - IsDollarSign(charCode) || - IsUnderscore(charCode) - ) -} -function IdentIsRest(charCode: number) { - return ( - IsAlpha(charCode) || - IsDigit(charCode) || - IsDollarSign(charCode) || - IsUnderscore(charCode) - ) -} -function NextIdent(input: string): [] | [string, string] { - if (!IdentIsFirst(input.charCodeAt(0))) return [] - for (let i = 1; i < input.length; i++) { - const char = input.charCodeAt(i) - if (IdentIsRest(char)) continue - const slice = input.slice(0, i) - const rest = input.slice(i) - return [slice, rest] - } - return [input, ''] -} -/** Scans for the next Ident token */ -export function Ident(input: string): [] | [string, string] { - return NextIdent(TrimAll(input)) -} -// ------------------------------------------------------------------ -// Number -// ------------------------------------------------------------------ -/** Checks that the next number is not a leading zero */ -function NumberLeadingZeroCheck(input: string, index: number) { - const char_0 = input.charCodeAt(index + 0) - const char_1 = input.charCodeAt(index + 1) - return ( - ( - // 1-9 - IsNonZero(char_0) - ) || ( - // 0 - IsZero(char_0) && - !IsDigit(char_1) - ) || ( - // 0. - IsZero(char_0) && - IsDot(char_1) - ) || ( - // .0 - IsDot(char_0) && - IsDigit(char_1) - ) - ) -} -/** Gets the next number token */ -function NextNumber(input: string): [] | [string, string] { - const negated = input.charAt(0) === '-' - const index = negated ? 1 : 0 - if (!NumberLeadingZeroCheck(input, index)) { - return [] - } - const dash = negated ? '-' : '' - let hasDot = false - for (let i = index; i < input.length; i++) { - const char_i = input.charCodeAt(i) - if (IsDigit(char_i)) { - continue - } - if (IsDot(char_i)) { - if (hasDot) { - const slice = input.slice(index, i) - const rest = input.slice(i) - return [`${dash}${slice}`, rest] - } - hasDot = true - continue - } - const slice = input.slice(index, i) - const rest = input.slice(i) - return [`${dash}${slice}`, rest] - } - return [input, ''] -} -/** Scans for the next number token */ -export function Number(code: string) { - return NextNumber(TrimAll(code)) -} -// ------------------------------------------------------------------ -// String -// ------------------------------------------------------------------ -function NextString(options: string[], input: string): [] | [string, string] { - const first = input.charAt(0) - if(!options.includes(first)) return [] - const quote = first - for(let i = 1; i < input.length; i++) { - const char = input.charAt(i) - if(char === quote) { - const slice = input.slice(1, i) - const rest = input.slice(i + 1) - return [slice, rest] - } - } - return [] -} -/** Scans the next Literal String value */ -export function String(options: string[], input: string) { - return NextString(options, TrimAll(input)) -} -// ------------------------------------------------------------------ -// Until -// ------------------------------------------------------------------ -function UntilStartsWith(value: string[], input: string): boolean { - const [left, ...right] = value - return (typeof left === 'string') - ? input.startsWith(left) - ? true - : UntilStartsWith(right, input) - : false -} -export function Until(value: string[], input: string, result: string = ''): [] | [string, string] { - return ( - input === '' ? [] : - UntilStartsWith(value, input) - ? [result, input] - : (() => { - const [left, right] = [input.slice(0, 1), input.slice(1)] - return Until(value, right, `${result}${left}`) - })() - ) -} -// ------------------------------------------------------------------ -// UntilNonEmpty -// ------------------------------------------------------------------ -export function UntilNonEmpty(value: string[], input: string): [] | [string, string] { - const result = Until(value, input) - return ( - result.length === 2 - ? result[0].length === 0 ? []: result - : [] - ) -} \ No newline at end of file diff --git a/src/runtime/tuple.ts b/src/runtime/tuple.ts new file mode 100644 index 0000000..a63558a --- /dev/null +++ b/src/runtime/tuple.ts @@ -0,0 +1,88 @@ +/*-------------------------------------------------------------------------- + +ParseBox + +The MIT License (MIT) + +Copyright (c) 2024-2025 Haydn Paterson + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +---------------------------------------------------------------------------*/ + +// deno-fmt-ignore-file + +import { Arguments } from '../system/arguments/index.ts' +import { Guard } from '../guard/index.ts' +import { type StaticParser, type StaticEnsure } from './static.ts' +import { type IParser, type IProperties, type IMapping, Identity } from './parser.ts' +import { ParseParser } from './parse.ts' + +// ------------------------------------------------------------------ +// Static +// ------------------------------------------------------------------ +export type StaticTuple = StaticEnsure< + Parsers extends [infer Left extends IParser, ...infer Right extends IParser[]] + ? StaticTuple>]> + : Result +> +// ------------------------------------------------------------------ +// Type +// ------------------------------------------------------------------ +export interface ITuple extends IParser { + type: 'Tuple' + parsers: IParser[] +} +// ------------------------------------------------------------------ +// Factory +// ------------------------------------------------------------------ +export function Tuple>>(parsers: [...Parsers], mapping: Mapping): ITuple> +export function Tuple(parsers: [...Parsers]): ITuple> +export function Tuple(...args: unknown[]): never { + const [parsers, mapping] = Arguments.Match<[IParser[], IMapping]>(args, { + 2: (parsers, mapping) => [parsers, mapping], + 1: (parsers) => [parsers, Identity] + }) + return { type: 'Tuple', parsers, mapping } as never +} +// ------------------------------------------------------------------ +// Guard +// ------------------------------------------------------------------ +/** True if the value is a Tuple parser */ +export function IsTuple(value: unknown): value is ITuple { + return Guard.IsObject(value) + && Guard.HasPropertyKey(value, 'type') + && Guard.HasPropertyKey(value, 'parsers') + && Guard.IsEqual(value.type, 'Tuple') + && Guard.IsArray(value.parsers) +} +// ------------------------------------------------------------------ +// Tuple +// ------------------------------------------------------------------ +export function ParseTuple(context: Context, parsers: [...Parsers], input: string): [] | [unknown[], string] { + const buffer = [] as unknown[] + let rest = input + for (const parser of parsers) { + const result = ParseParser(context, parser, rest) + if (result.length === 0) return [] + buffer.push(result[0]) + rest = result[1] + } + return [buffer, rest] +} \ No newline at end of file diff --git a/src/runtime/types.ts b/src/runtime/types.ts deleted file mode 100644 index 2be832a..0000000 --- a/src/runtime/types.ts +++ /dev/null @@ -1,339 +0,0 @@ -/*-------------------------------------------------------------------------- - -@sinclair/parsebox - -The MIT License (MIT) - -Copyright (c) 2024-2025 Haydn Paterson (sinclair) - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -THE SOFTWARE. - ----------------------------------------------------------------------------*/ - -// deno-lint-ignore-file -// deno-fmt-ignore-file - -import { Guard } from '../guard/index.ts' - -export type IModuleProperties = Record - -// ------------------------------------------------------------------ -// Static -// ------------------------------------------------------------------ - -/** Force output static type evaluation for Arrays */ -export type StaticEnsure = T extends infer R ? R : never - -/** Infers the Output Parameter for a Parser */ -export type StaticParser = Parser extends IParser ? Output : unknown - -// ------------------------------------------------------------------ -// Mapping -// ------------------------------------------------------------------ -export type IMapping = (input: Input) => Output - -/** Maps input to output. This is the default Mapping */ -export const Identity = (value: unknown) => value - -/** Maps the output as the given parameter T */ -export function As(mapping: T): ((value: unknown) => T) { - return (_: unknown) => mapping -} - -// ------------------------------------------------------------------ -// Parser -// ------------------------------------------------------------------ -export interface IParser { - type: string - mapping: IMapping -} -// ------------------------------------------------------------------ -// Array -// ------------------------------------------------------------------ -export type ArrayParameter = StaticEnsure< - StaticParser[] -> -export interface IArray extends IParser { - type: 'Array' - parser: IParser -} -/** `[EBNF]` Creates an Array Parser */ -export function Array>>(parser: Parser, mapping: Mapping): IArray> -/** `[EBNF]` Creates an Array Parser */ -export function Array(parser: Parser): IArray> -/** `[EBNF]` Creates an Array Parser */ -export function Array(...args: unknown[]): never { - const [parser, mapping] = args.length === 2 ? [args[0], args[1]] : [args[0], Identity] - return { type: 'Array', parser, mapping } as never -} -/** Returns true if the value is a Array Parser */ -export function IsArray(value: unknown): value is IArray { - return Guard.IsObject(value) - && Guard.HasPropertyKey(value, 'type') - && Guard.HasPropertyKey(value, 'parser') - && Guard.IsEqual(value.type, 'Array') - && Guard.IsObject(value.parser) -} -// ------------------------------------------------------------------ -// Const -// ------------------------------------------------------------------ -export interface IConst extends IParser { - type: 'Const' - value: string -} -/** `[TERM]` Creates a Const Parser */ -export function Const>(value: Value, mapping: Mapping): IConst> -/** `[TERM]` Creates a Const Parser */ -export function Const(value: Value): IConst -/** `[TERM]` Creates a Const Parser */ -export function Const(...args: unknown[]): never { - const [value, mapping] = args.length === 2 ? [args[0], args[1]] : [args[0], Identity] - return { type: 'Const', value, mapping } as never -} -/** Returns true if the value is a Const Parser */ -export function IsConst(value: unknown): value is IConst { - return Guard.IsObject(value) - && Guard.HasPropertyKey(value, 'type') - && Guard.HasPropertyKey(value, 'value') - && Guard.IsEqual(value.type, 'Const') - && Guard.IsString(value.value) -} -// ------------------------------------------------------------------ -// Ref -// ------------------------------------------------------------------ -export interface IRef extends IParser { - type: 'Ref' - ref: string -} -/** `[BNF]` Creates a Ref Parser. This Parser can only be used in the context of a Module */ -export function Ref>(ref: string, mapping: Mapping): IRef> -/** `[BNF]` Creates a Ref Parser. This Parser can only be used in the context of a Module */ -export function Ref(ref: string): IRef -/** `[BNF]` Creates a Ref Parser. This Parser can only be used in the context of a Module */ -export function Ref(...args: unknown[]): never { - const [ref, mapping] = args.length === 2 ? [args[0], args[1]] : [args[0], Identity] - return { type: 'Ref', ref, mapping } as never -} -/** Returns true if the value is a Ref Parser */ -export function IsRef(value: unknown): value is IRef { - return Guard.IsObject(value) - && Guard.HasPropertyKey(value, 'type') - && Guard.HasPropertyKey(value, 'ref') - && Guard.IsEqual(value.type, 'Ref') - && Guard.IsString(value.ref) -} -// ------------------------------------------------------------------ -// String -// ------------------------------------------------------------------ -export interface IString extends IParser { - type: 'String' - options: string[] -} -/** `[TERM]` Creates a String Parser. Options are an array of permissable quote characters */ -export function String>(options: string[], mapping: Mapping): IString> -/** `[TERM]` Creates a String Parser. Options are an array of permissable quote characters */ -export function String(options: string[]): IString -/** `[TERM]` Creates a String Parser. Options are an array of permissable quote characters */ -export function String(...params: unknown[]): never { - const [options, mapping] = params.length === 2 ? [params[0], params[1]] : [params[0], Identity] - return { type: 'String', options, mapping } as never -} -/** Returns true if the value is a String Parser */ -export function IsString(value: unknown): value is IString { - return Guard.IsObject(value) - && Guard.HasPropertyKey(value, 'type') - && Guard.IsEqual(value.type, 'String') - && Guard.HasPropertyKey(value, 'options') - && Guard.IsArray(value.options) -} -// ------------------------------------------------------------------ -// Ident -// ------------------------------------------------------------------ -export interface IIdent extends IParser { - type: 'Ident' -} -/** `[TERM]` Creates an Ident Parser where Ident matches any valid JavaScript identifier */ -export function Ident>(mapping: Mapping): IIdent> -/** `[TERM]` Creates an Ident Parser where Ident matches any valid JavaScript identifier */ -export function Ident(): IIdent -/** `[TERM]` Creates an Ident Parser where Ident matches any valid JavaScript identifier */ -export function Ident(...params: unknown[]): never { - const mapping = params.length === 1 ? params[0] : Identity - return { type: 'Ident', mapping } as never -} -/** Returns true if the value is a Ident Parser */ -export function IsIdent(value: unknown): value is IIdent { - return Guard.IsObject(value) - && Guard.HasPropertyKey(value, 'type') - && Guard.IsEqual(value.type, 'Ident') -} -// ------------------------------------------------------------------ -// Number -// ------------------------------------------------------------------ -export interface INumber extends IParser { - type: 'Number' -} -/** `[TERM]` Creates an Number Parser */ -export function Number>(mapping: Mapping): INumber> -/** `[TERM]` Creates an Number Parser */ -export function Number(): INumber -/** `[TERM]` Creates an Number Parser */ -export function Number(...params: unknown[]): never { - const mapping = params.length === 1 ? params[0] : Identity - return { type: 'Number', mapping } as never -} -/** Returns true if the value is a Number Parser */ -export function IsNumber(value: unknown): value is INumber { - return Guard.IsObject(value) - && Guard.HasPropertyKey(value, 'type') - && Guard.IsEqual(value.type, 'Number') -} -// ------------------------------------------------------------------ -// Optional -// ------------------------------------------------------------------ -export type OptionalParameter] | []> = ( - Result -) -export interface IOptional extends IParser { - type: 'Optional' - parser: IParser -} -/** `[EBNF]` Creates an Optional Parser */ -export function Optional>>(parser: Parser, mapping: Mapping): IOptional> -/** `[EBNF]` Creates an Optional Parser */ -export function Optional(parser: Parser): IOptional> -/** `[EBNF]` Creates an Optional Parser */ -export function Optional(...args: unknown[]): never { - const [parser, mapping] = args.length === 2 ? [args[0], args[1]] : [args[0], Identity] - return { type: 'Optional', parser, mapping } as never -} -/** Returns true if the value is a Optional Parser */ -export function IsOptional(value: unknown): value is IOptional { - return Guard.IsObject(value) - && Guard.HasPropertyKey(value, 'type') - && Guard.HasPropertyKey(value, 'parser') - && Guard.IsEqual(value.type, 'Optional') - && Guard.IsObject(value.parser) -} -// ------------------------------------------------------------------ -// Tuple -// ------------------------------------------------------------------ -export type TupleParameter = StaticEnsure< - Parsers extends [infer Left extends IParser, ...infer Right extends IParser[]] - ? TupleParameter>]> - : Result -> -export interface ITuple extends IParser { - type: 'Tuple' - parsers: IParser[] -} -/** `[BNF]` Creates a Tuple Parser */ -export function Tuple>>(parsers: [...Parsers], mapping: Mapping): ITuple> -/** `[BNF]` Creates a Tuple Parser */ -export function Tuple(parsers: [...Parsers]): ITuple> -/** `[BNF]` Creates a Tuple Parser */ -export function Tuple(...args: unknown[]): never { - const [parsers, mapping] = args.length === 2 ? [args[0], args[1]] : [args[0], Identity] - return { type: 'Tuple', parsers, mapping } as never -} -/** Returns true if the value is a Tuple Parser */ -export function IsTuple(value: unknown): value is ITuple { - return Guard.IsObject(value) - && Guard.HasPropertyKey(value, 'type') - && Guard.HasPropertyKey(value, 'parsers') - && Guard.IsEqual(value.type, 'Tuple') - && Guard.IsArray(value.parsers) -} -// ------------------------------------------------------------------ -// Union -// ------------------------------------------------------------------ -export type UnionParameter = StaticEnsure< - Parsers extends [infer Left extends IParser, ...infer Right extends IParser[]] - ? UnionParameter> - : Result -> -export interface IUnion extends IParser { - type: 'Union' - parsers: IParser[] -} -/** `[BNF]` Creates a Union parser */ -export function Union>>(parsers: [...Parsers], mapping: Mapping): IUnion> -/** `[BNF]` Creates a Union parser */ -export function Union(parsers: [...Parsers]): IUnion> -/** `[BNF]` Creates a Union parser */ -export function Union(...args: unknown[]): never { - const [parsers, mapping] = args.length === 2 ? [args[0], args[1]] : [args[0], Identity] - return { type: 'Union', parsers, mapping } as never -} -/** Returns true if the value is a Union Parser */ -export function IsUnion(value: unknown): value is IUnion { - return Guard.IsObject(value) - && Guard.HasPropertyKey(value, 'type') - && Guard.HasPropertyKey(value, 'parsers') - && Guard.IsEqual(value.type, 'Union') - && Guard.IsArray(value.parsers) -} -// ------------------------------------------------------------------ -// Until -// ------------------------------------------------------------------ -export interface IUntil extends IParser { - type: 'Until' - values: string[] -} -/** Creates a Until Parser */ -export function Until>(values: string[], mapping: Mapping): IUntil -/** Creates a Until Parser */ -export function Until(values: string[]): IUntil -/** Creates a Until Parser */ -export function Until(...args: unknown[]): never { - const [values, mapping] = args.length === 2 ? [args[0], args[1]] : [args[0], Identity] - return { type: 'Until', values, mapping } as never -} -/** Returns true if the value is a Until Parser */ -export function IsUntil(value: unknown): value is IUntil { - return Guard.IsObject(value) - && Guard.HasPropertyKey(value, 'type') - && Guard.HasPropertyKey(value, 'values') - && Guard.IsEqual(value.type, 'Until') - && Guard.IsArray(value.values) -} -// ------------------------------------------------------------------ -// UntilNonEmpty -// ------------------------------------------------------------------ -export interface IUntilNonEmpty extends IParser { - type: 'UntilNonEmpty' - values: string[] -} -/** Creates a UntilNonEmpty Parser */ -export function UntilNonEmpty>(values: string[], mapping: Mapping): IUntilNonEmpty -/** Creates a UntilNonEmpty Parser */ -export function UntilNonEmpty(values: string[]): IUntilNonEmpty -/** Creates a UntilNonEmpty Parser */ -export function UntilNonEmpty(...args: unknown[]): never { - const [values, mapping] = args.length === 2 ? [args[0], args[1]] : [args[0], Identity] - return { type: 'UntilNonEmpty', values, mapping } as never -} -/** Returns true if the value is a UntilNonEmpty Parser */ -export function IsUntilNonEmpty(value: unknown): value is IUntilNonEmpty { - return Guard.IsObject(value) - && Guard.HasPropertyKey(value, 'type') - && Guard.HasPropertyKey(value, 'values') - && Guard.IsEqual(value.type, 'UntilNonEmpty') - && Guard.IsArray(value.values) -} \ No newline at end of file diff --git a/src/runtime/union.ts b/src/runtime/union.ts new file mode 100644 index 0000000..136b126 --- /dev/null +++ b/src/runtime/union.ts @@ -0,0 +1,86 @@ +/*-------------------------------------------------------------------------- + +ParseBox + +The MIT License (MIT) + +Copyright (c) 2024-2025 Haydn Paterson + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +---------------------------------------------------------------------------*/ + +// deno-fmt-ignore-file + +import { Arguments } from '../system/arguments/index.ts' +import { Guard } from '../guard/index.ts' +import { type StaticParser, type StaticEnsure } from './static.ts' +import { type IParser, type IProperties, type IMapping, Identity } from './parser.ts' +import { ParseParser } from './parse.ts' + +// ------------------------------------------------------------------ +// Static +// ------------------------------------------------------------------ +export type StaticUnion = StaticEnsure< + Parsers extends [infer Left extends IParser, ...infer Right extends IParser[]] + ? StaticUnion> + : Result +> +// ------------------------------------------------------------------ +// Type +// ------------------------------------------------------------------ +export interface IUnion extends IParser { + type: 'Union' + parsers: IParser[] +} +// ------------------------------------------------------------------ +// Factory +// ------------------------------------------------------------------ +export function Union>>(parsers: [...Parsers], mapping: Mapping): IUnion> +export function Union(parsers: [...Parsers]): IUnion> +export function Union(...args: unknown[]): never { + const [parsers, mapping] = Arguments.Match<[IParser[], IMapping]>(args, { + 2: (parsers, mapping) => [parsers, mapping], + 1: (parsers) => [parsers, Identity] + }) + return { type: 'Union', parsers, mapping } as never +} +// ------------------------------------------------------------------ +// Guard +// ------------------------------------------------------------------ +/** True if the value is a Union parser */ +export function IsUnion(value: unknown): value is IUnion { + return Guard.IsObject(value) + && Guard.HasPropertyKey(value, 'type') + && Guard.HasPropertyKey(value, 'parsers') + && Guard.IsEqual(value.type, 'Union') + && Guard.IsArray(value.parsers) +} +// ------------------------------------------------------------------ +// Parse +// ------------------------------------------------------------------ +export function ParseUnion + (context: Context, parsers: [...Parsers], input: string): [] | [unknown, string] { + for (const parser of parsers) { + const result = ParseParser(context, parser, input) + if (result.length === 0) continue + return result + } + return [] +} \ No newline at end of file diff --git a/src/runtime/until.ts b/src/runtime/until.ts new file mode 100644 index 0000000..d22bca3 --- /dev/null +++ b/src/runtime/until.ts @@ -0,0 +1,70 @@ +/*-------------------------------------------------------------------------- + +ParseBox + +The MIT License (MIT) + +Copyright (c) 2024-2025 Haydn Paterson + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +---------------------------------------------------------------------------*/ + +// deno-fmt-ignore-file + +import * as Token from '../token/index.ts' +import { Arguments } from '../system/arguments/index.ts' +import { Guard } from '../guard/index.ts' +import { type IParser, type IMapping, Identity } from './parser.ts' + +// ------------------------------------------------------------------ +// Type +// ------------------------------------------------------------------ +export interface IUntil extends IParser { + type: 'Until' + end: string[] +} +// ------------------------------------------------------------------ +// Factory +// ------------------------------------------------------------------ +export function Until>(end: string[], mapping: Mapping): IUntil +export function Until(end: string[]): IUntil +export function Until(...args: unknown[]): never { + const [end, mapping] = Arguments.Match<[string[], IMapping]>(args, { + 2: (end, mapping) => [end, mapping], + 1: (end) => [end, Identity] + }) + return { type: 'Until', end, mapping } as never +} +// ------------------------------------------------------------------ +// Guard +// ------------------------------------------------------------------ +export function IsUntil(value: unknown): value is IUntil { + return Guard.IsObject(value) + && Guard.HasPropertyKey(value, 'type') + && Guard.HasPropertyKey(value, 'end') + && Guard.IsEqual(value.type, 'Until') + && Guard.IsArray(value.end) +} +// ------------------------------------------------------------------ +// Parse +// ------------------------------------------------------------------ +export function ParseUntil(end: [...End], input: string): [] | [string, string] { + return Token.Until(end, input) as never +} diff --git a/src/runtime/until_1.ts b/src/runtime/until_1.ts new file mode 100644 index 0000000..153e1b8 --- /dev/null +++ b/src/runtime/until_1.ts @@ -0,0 +1,71 @@ +/*-------------------------------------------------------------------------- + +ParseBox + +The MIT License (MIT) + +Copyright (c) 2024-2025 Haydn Paterson + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +---------------------------------------------------------------------------*/ + +// deno-fmt-ignore-file + +import * as Token from '../token/index.ts' + +import { Arguments } from '../system/arguments/index.ts' +import { Guard } from '../guard/index.ts' +import { type IParser, type IMapping, Identity } from './parser.ts' + +// ------------------------------------------------------------------ +// Type +// ------------------------------------------------------------------ +export interface IUntil_1 extends IParser { + type: 'Until_1' + end: string[] +} +// ------------------------------------------------------------------ +// Type +// ------------------------------------------------------------------ +export function Until_1>(values: string[], mapping: Mapping): IUntil_1 +export function Until_1(values: string[]): IUntil_1 +export function Until_1(...args: unknown[]): never { + const [end, mapping] = Arguments.Match<[string[], IMapping]>(args, { + 2: (end, mapping) => [end, mapping], + 1: (end) => [end, Identity] + }) + return { type: 'Until_1', end, mapping } as never +} +// ------------------------------------------------------------------ +// Guard +// ------------------------------------------------------------------ +export function IsUntil_1(value: unknown): value is IUntil_1 { + return Guard.IsObject(value) + && Guard.HasPropertyKey(value, 'type') + && Guard.HasPropertyKey(value, 'end') + && Guard.IsEqual(value.type, 'Until_1') + && Guard.IsArray(value.end) +} +// ------------------------------------------------------------------ +// Parse +// ------------------------------------------------------------------ +export function ParseUntil_1(end: [...End], input: string): [] | [string, string] { + return Token.Until_1(end, input) as never +} diff --git a/src/static/array.ts b/src/static/array.ts new file mode 100644 index 0000000..d0e5cbb --- /dev/null +++ b/src/static/array.ts @@ -0,0 +1,48 @@ +/*-------------------------------------------------------------------------- + +ParseBox + +The MIT License (MIT) + +Copyright (c) 2024-2025 Haydn Paterson + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +---------------------------------------------------------------------------*/ + +// deno-fmt-ignore-file + +import type { Identity, IMapping, IParser } from './parser.ts' +import type { Parse } from './parse.ts' + +// ------------------------------------------------------------------ +// Type +// ------------------------------------------------------------------ +export interface Array extends IParser { + type: 'Array' + parser: Parser +} +// ------------------------------------------------------------------ +// Parse +// ------------------------------------------------------------------ +export type ParseArray = ( + Parse extends [infer Element extends unknown, infer InputRest extends string] + ? ParseArray + : [Result, Input] +) diff --git a/src/static/bigint.ts b/src/static/bigint.ts new file mode 100644 index 0000000..a582bd8 --- /dev/null +++ b/src/static/bigint.ts @@ -0,0 +1,45 @@ +/*-------------------------------------------------------------------------- + +ParseBox + +The MIT License (MIT) + +Copyright (c) 2024-2025 Haydn Paterson + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +---------------------------------------------------------------------------*/ + +// deno-fmt-ignore-file + +import type { Identity, IMapping, IParser } from './parser.ts' +import * as Token from '../token/index.ts' + +// ------------------------------------------------------------------ +// Type +// ------------------------------------------------------------------ +export interface BigInt extends IParser { + type: 'BigInt' +} +// ------------------------------------------------------------------ +// Parse +// ------------------------------------------------------------------ +export type ParseBigInt = ( + Token.TBigInt +) diff --git a/src/static/const.ts b/src/static/const.ts new file mode 100644 index 0000000..1188c82 --- /dev/null +++ b/src/static/const.ts @@ -0,0 +1,46 @@ +/*-------------------------------------------------------------------------- + +ParseBox + +The MIT License (MIT) + +Copyright (c) 2024-2025 Haydn Paterson + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +---------------------------------------------------------------------------*/ + +// deno-fmt-ignore-file + +import type { Identity, IMapping, IParser } from './parser.ts' +import * as Token from '../token/index.ts' + +// ------------------------------------------------------------------ +// Type +// ------------------------------------------------------------------ +export interface Const extends IParser { + type: 'Const' + const: Const +} +// ------------------------------------------------------------------ +// Parse +// ------------------------------------------------------------------ +export type ParseConst = ( + Token.TConst +) diff --git a/src/static/ident.ts b/src/static/ident.ts new file mode 100644 index 0000000..4860fcf --- /dev/null +++ b/src/static/ident.ts @@ -0,0 +1,45 @@ +/*-------------------------------------------------------------------------- + +ParseBox + +The MIT License (MIT) + +Copyright (c) 2024-2025 Haydn Paterson + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +---------------------------------------------------------------------------*/ + +// deno-fmt-ignore-file + +import type { Identity, IMapping, IParser } from './parser.ts' +import * as Token from '../token/index.ts' + +// ------------------------------------------------------------------ +// Type +// ------------------------------------------------------------------ +export interface Ident extends IParser { + type: 'Ident' +} +// ------------------------------------------------------------------ +// Parse +// ------------------------------------------------------------------ +export type ParseIdent = ( + Token.TIdent +) diff --git a/src/static/index.ts b/src/static/index.ts index 86dcaf6..019c081 100644 --- a/src/static/index.ts +++ b/src/static/index.ts @@ -1,10 +1,10 @@ /*-------------------------------------------------------------------------- -@sinclair/parsebox +ParseBox The MIT License (MIT) -Copyright (c) 2024-2025 Haydn Paterson (sinclair) +Copyright (c) 2024-2025 Haydn Paterson Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal @@ -26,4 +26,17 @@ THE SOFTWARE. ---------------------------------------------------------------------------*/ -export * as Static from './static.ts' +export type { Array } from './array.ts' +export type { BigInt } from './bigint.ts' +export type { Const } from './const.ts' +export type { Ident } from './ident.ts' +export type { Integer } from './integer.ts' +export type { Number } from './number.ts' +export type { Optional } from './optional.ts' +export type { Parse } from './parse.ts' +export type { As, Identity, IMapping, IParser } from './parser.ts' +export type { String } from './string.ts' +export type { Tuple } from './tuple.ts' +export type { Union } from './union.ts' +export type { Until_1 } from './until_1.ts' +export type { Until } from './until.ts' diff --git a/src/static/integer.ts b/src/static/integer.ts new file mode 100644 index 0000000..a65d94b --- /dev/null +++ b/src/static/integer.ts @@ -0,0 +1,45 @@ +/*-------------------------------------------------------------------------- + +ParseBox + +The MIT License (MIT) + +Copyright (c) 2024-2025 Haydn Paterson + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +---------------------------------------------------------------------------*/ + +// deno-fmt-ignore-file + +import type { Identity, IMapping, IParser } from './parser.ts' +import * as Token from '../token/index.ts' + +// ------------------------------------------------------------------ +// Type +// ------------------------------------------------------------------ +export interface Integer extends IParser { + type: 'Integer' +} +// ------------------------------------------------------------------ +// Parse +// ------------------------------------------------------------------ +export type ParseInteger = ( + Token.TInteger +) diff --git a/src/static/number.ts b/src/static/number.ts new file mode 100644 index 0000000..d457a44 --- /dev/null +++ b/src/static/number.ts @@ -0,0 +1,45 @@ +/*-------------------------------------------------------------------------- + +ParseBox + +The MIT License (MIT) + +Copyright (c) 2024-2025 Haydn Paterson + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +---------------------------------------------------------------------------*/ + +// deno-fmt-ignore-file + +import type { Identity, IMapping, IParser } from './parser.ts' +import * as Token from '../token/index.ts' + +// ------------------------------------------------------------------ +// Type +// ------------------------------------------------------------------ +export interface Number extends IParser { + type: 'Number' +} +// ------------------------------------------------------------------ +// Parse +// ------------------------------------------------------------------ +export type ParseNumber = ( + Token.TNumber +) diff --git a/src/static/optional.ts b/src/static/optional.ts new file mode 100644 index 0000000..769ff73 --- /dev/null +++ b/src/static/optional.ts @@ -0,0 +1,48 @@ +/*-------------------------------------------------------------------------- + +ParseBox + +The MIT License (MIT) + +Copyright (c) 2024-2025 Haydn Paterson + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +---------------------------------------------------------------------------*/ + +// deno-fmt-ignore-file + +import type { Identity, IMapping, IParser } from './parser.ts' +import type { Parse } from './parse.ts' + +// ------------------------------------------------------------------ +// Type +// ------------------------------------------------------------------ +export interface Optional extends IParser { + type: 'Optional' + parser: Parser +} +// ------------------------------------------------------------------ +// Optional +// ------------------------------------------------------------------ +export type ParseOptional = ( + Parse extends [infer Result extends unknown, infer Rest extends string] + ? [[Result], Rest] + : [[], Input] +) diff --git a/src/static/parse.ts b/src/static/parse.ts index 7199655..509df6a 100644 --- a/src/static/parse.ts +++ b/src/static/parse.ts @@ -1,10 +1,10 @@ /*-------------------------------------------------------------------------- -@sinclair/parsebox +ParseBox The MIT License (MIT) -Copyright (c) 2024-2025 Haydn Paterson (sinclair) +Copyright (c) 2024-2025 Haydn Paterson Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal @@ -28,115 +28,51 @@ THE SOFTWARE. // deno-fmt-ignore-file -import * as Tokens from './token.ts' -import * as Types from './types.ts' +import type { Array, ParseArray } from './array.ts' +import type { BigInt, ParseBigInt } from './bigint.ts' +import type { Const, ParseConst } from './const.ts' +import type { Ident, ParseIdent } from './ident.ts' +import type { Integer, ParseInteger } from './integer.ts' +import type { Number, ParseNumber } from './number.ts' +import type { Optional, ParseOptional } from './optional.ts' +import type { ParseString, String } from './string.ts' +import type { ParseTuple, Tuple } from './tuple.ts' +import type { ParseUnion, Union } from './union.ts' +import type { ParseUntil_1, Until_1 } from './until_1.ts' +import type { ParseUntil, Until } from './until.ts' + +import type { IParser } from './parser.ts' // ------------------------------------------------------------------ -// Array -// ------------------------------------------------------------------ -type ArrayParser = ( - Parse extends [infer Value1 extends unknown, infer Rest extends string] - ? ArrayParser - : [Result, Input] -) -// ------------------------------------------------------------------ -// Const -// ------------------------------------------------------------------ -type ConstParser = ( - Tokens.Const extends [infer Match extends Value, infer Rest extends string] - ? [Match, Rest] - : [] -) -// ------------------------------------------------------------------ -// Ident -// ------------------------------------------------------------------ -type IdentParser = ( - Tokens.Ident extends [infer Match extends string, infer Rest extends string] - ? [Match, Rest] - : [] -) -// ------------------------------------------------------------------ -// Number -// ------------------------------------------------------------------ -type NumberParser = ( - Tokens.Number extends [infer Match extends string, infer Rest extends string] - ? [Match, Rest] - : [] -) -// ------------------------------------------------------------------ -// Optional -// ------------------------------------------------------------------ -type OptionalParser = ( - Parse extends [infer Value extends unknown, infer Rest extends string] - ? [[Value], Rest] - : [[], Input] -) -// ------------------------------------------------------------------ -// String -// ------------------------------------------------------------------ -type StringParser = ( - Tokens.String extends [infer Match extends string, infer Rest extends string] - ? [Match, Rest] - : [] -) -// ------------------------------------------------------------------ -// Tuple -// ------------------------------------------------------------------ -type TupleParser = ( - Parsers extends [infer Left extends Types.IParser, ...infer Right extends Types.IParser[]] - ? Parse extends [infer Value extends unknown, infer Rest extends string] - ? TupleParser - : [] - : [Result, Input] -) -// ------------------------------------------------------------------ -// Union -// ------------------------------------------------------------------ -type UnionParser = ( - Parsers extends [infer Left extends Types.IParser, ...infer Right extends Types.IParser[]] - ? Parse extends [infer Value extends unknown, infer Rest extends string] - ? [Value, Rest] - : UnionParser - : [] -) -// ------------------------------------------------------------------ -// Until -// ------------------------------------------------------------------ -type UntilParser = ( - Tokens.Until extends [infer Match extends string, infer Rest extends string] - ? [Match, Rest] - : [] +// ParseInput +// ------------------------------------------------------------------ +type ParseInput = ( + Parser extends Array ? ParseArray : + Parser extends BigInt ? ParseBigInt : + Parser extends Const ? ParseConst : + Parser extends Ident ? ParseIdent : + Parser extends Integer ? ParseInteger : + Parser extends Number ? ParseNumber : + Parser extends Optional ? ParseOptional : + Parser extends String ? ParseString : + Parser extends Tuple ? ParseTuple : + Parser extends Union ? ParseUnion : + Parser extends Until ? ParseUntil : + Parser extends Until_1 ? ParseUntil_1 + : [] ) // ------------------------------------------------------------------ -// UntilNonEmpty +// ParseMapping // ------------------------------------------------------------------ -type UntilNonEmptyParser = ( - Tokens.UntilNonEmpty extends [infer Match extends string, infer Rest extends string] - ? [Match, Rest] - : [] +type ParseMapping = (( + Parser['mapping'] & { input: ParseResult })['output'] ) // ------------------------------------------------------------------ // Parse // ------------------------------------------------------------------ -type ParseCode = ( - Parser extends Types.Array ? ArrayParser : - Parser extends Types.Const ? ConstParser : - Parser extends Types.Ident ? IdentParser : - Parser extends Types.Number ? NumberParser : - Parser extends Types.Optional ? OptionalParser : - Parser extends Types.String ? StringParser : - Parser extends Types.Tuple ? TupleParser : - Parser extends Types.Union ? UnionParser : - Parser extends Types.Until ? UntilParser : - Parser extends Types.UntilNonEmpty ? UntilNonEmptyParser : - [] -) -type ParseMapping = ( - (Parser['mapping'] & { input: Result })['output'] -) /** Parses code with the given parser */ -export type Parse = ( - ParseCode extends [infer Code extends unknown, infer Rest extends string] - ? [ParseMapping, Rest] +export type Parse = ( + ParseInput extends [infer ParseResult extends unknown, infer InputRest extends string] + ? [ParseMapping, InputRest] : [] ) diff --git a/src/static/parser.ts b/src/static/parser.ts new file mode 100644 index 0000000..40ee57a --- /dev/null +++ b/src/static/parser.ts @@ -0,0 +1,48 @@ +/*-------------------------------------------------------------------------- + +ParseBox + +The MIT License (MIT) + +Copyright (c) 2024-2025 Haydn Paterson + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +---------------------------------------------------------------------------*/ + +// deno-fmt-ignore-file + +export interface IMapping { + context: unknown + input: unknown + output: unknown +} +/** Default inference mapping. */ +export interface Identity extends IMapping { + output: this['input'] +} +/** Maps the given argument `T` as the mapping output */ +export interface As extends IMapping { + output: T +} +/** Base type Parser implemented by all other parsers */ +export interface IParser { + type: string + mapping: Mapping +} diff --git a/src/static/string.ts b/src/static/string.ts new file mode 100644 index 0000000..c60493a --- /dev/null +++ b/src/static/string.ts @@ -0,0 +1,46 @@ +/*-------------------------------------------------------------------------- + +ParseBox + +The MIT License (MIT) + +Copyright (c) 2024-2025 Haydn Paterson + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +---------------------------------------------------------------------------*/ + +// deno-fmt-ignore-file + +import type { Identity, IMapping, IParser } from './parser.ts' +import * as Token from '../token/index.ts' + +// ------------------------------------------------------------------ +// Type +// ------------------------------------------------------------------ +export interface String extends IParser { + type: 'String' + quotes: Quotes +} +// ------------------------------------------------------------------ +// Parse +// ------------------------------------------------------------------ +export type ParseString = ( + Token.TString +) diff --git a/src/static/token.ts b/src/static/token.ts deleted file mode 100644 index 281ed8f..0000000 --- a/src/static/token.ts +++ /dev/null @@ -1,229 +0,0 @@ -/*-------------------------------------------------------------------------- - -@sinclair/parsebox - -The MIT License (MIT) - -Copyright (c) 2024-2025 Haydn Paterson (sinclair) - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -THE SOFTWARE. - ----------------------------------------------------------------------------*/ - -// deno-fmt-ignore-file -// deno-lint-ignore-file no-namespace - -// ------------------------------------------------------------------ -// Chars -// ------------------------------------------------------------------ -namespace Chars { - export type Empty = '' - export type Space = ' ' - export type Newline = '\n' - export type Dot = '.' - export type Hyphen = '-' - export type Digit = [ - '0', '1', '2', '3', '4', '5', '6', '7', '8', '9' - ] - export type Alpha = [ - 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', - 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', - 'u', 'v', 'w', 'x', 'y', 'z', 'A', 'B', 'C', 'D', - 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', - 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', - 'Y', 'Z' - ] -} -// ------------------------------------------------------------------ -// Trim -// ------------------------------------------------------------------ -namespace Trim { - // ------------------------------------------------------------------ - // Whitespace Filters - // ------------------------------------------------------------------ - type W9 = `${W8}${W8}` // 512 - type W8 = `${W7}${W7}` // 256 - type W7 = `${W6}${W6}` // 128 - type W6 = `${W5}${W5}` // 64 - type W5 = `${W4}${W4}` // 32 - type W4 = `${W3}${W3}` // 16 - type W3 = `${W2}${W2}` // 8 - type W2 = `${W1}${W1}` // 4 - type W1 = `${W0}${W0}` // 2 - type W0 = ` ` // 1 - // ------------------------------------------------------------------ - // TrimWhitespace - // ------------------------------------------------------------------ - /** Trims whitespace only */ - export type TrimWhitespace = ( - Code extends `${W4}${infer Rest extends string}` ? TrimWhitespace : - Code extends `${W3}${infer Rest extends string}` ? TrimWhitespace : - Code extends `${W1}${infer Rest extends string}` ? TrimWhitespace : - Code extends `${W0}${infer Rest extends string}` ? TrimWhitespace : - Code - ) - // ------------------------------------------------------------------ - // Trim - // ------------------------------------------------------------------ - /** Trims Whitespace and Newline */ - export type TrimAll = ( - Code extends `${W4}${infer Rest extends string}` ? TrimAll : - Code extends `${W3}${infer Rest extends string}` ? TrimAll : - Code extends `${W1}${infer Rest extends string}` ? TrimAll : - Code extends `${W0}${infer Rest extends string}` ? TrimAll : - Code extends `${Chars.Newline}${infer Rest extends string}` ? TrimAll : - Code - ) -} -// ------------------------------------------------------------------ -// Union -// ------------------------------------------------------------------ -/** Scans for the next match union */ - -type NextUnion = ( - Variants extends [infer Variant extends string, ...infer Rest1 extends string[]] - ? NextConst extends [infer Match extends string, infer Rest2 extends string] - ? [Match, Rest2] - : NextUnion - : [] -) -// ------------------------------------------------------------------ -// Const -// ------------------------------------------------------------------ - -type NextConst = ( - Code extends `${Value}${infer Rest extends string}` - ? [Value, Rest] - : [] -) -/** Scans for the next constant value */ -export type Const = ( - Value extends '' ? ['', Code] : - Value extends `${infer First extends string}${string}` - ? ( - First extends Chars.Newline ? NextConst> : - First extends Chars.Space ? NextConst : - NextConst> - ) : never -) -// ------------------------------------------------------------------ -// Number -// ------------------------------------------------------------------ -type NextNumberNegate = ( - Code extends `${Chars.Hyphen}${infer Rest extends string}` - ? [Chars.Hyphen, Rest] - : [Chars.Empty, Code] -) -type NextNumberZeroCheck = ( - Code extends `0${infer Rest}` - ? NextUnion extends [string, string] ? false : true - : true -) -type NextNumberScan = ( - NextUnion<[...Chars.Digit, Chars.Dot], Code> extends [infer Char extends string, infer Rest extends string] - ? Char extends Chars.Dot - ? HasDecimal extends false - ? NextNumberScan - : [Result, `.${Rest}`] - : NextNumberScan - : [Result, Code] -) -export type NextNumber = ( - NextNumberNegate extends [infer Negate extends string, infer Rest extends string] - ? NextNumberZeroCheck extends true - ? NextNumberScan extends [infer Number extends string, infer Rest2 extends string] - ? Number extends Chars.Empty - ? [] - : [`${Negate}${Number}`, Rest2] - : [] - : [] - : [] -) -/** Scans for the next literal number */ -export type Number = NextNumber> -// ------------------------------------------------------------------ -// String -// ------------------------------------------------------------------ -type NextStringQuote = NextUnion - -type NextStringBody = ( - Code extends `${infer Char extends string}${infer Rest extends string}` - ? Char extends Quote - ? [Result, Rest] - : NextStringBody - : [] -) - -type NextString = ( - NextStringQuote extends [infer Quote extends string, infer Rest extends string] - ? NextStringBody extends [infer String extends string, infer Rest extends string] - ? [String, Rest] - : [] - : [] -) -/** Scans for the next literal string */ -export type String = NextString> -// ------------------------------------------------------------------ -// Ident -// ------------------------------------------------------------------ -type IdentLeft = [...Chars.Alpha, '_', '$'] // permissable first characters -type IdentRight = [...Chars.Digit, ...IdentLeft] // permissible subsequent characters - -type NextIdentScan = ( - NextUnion extends [infer Char extends string, infer Rest extends string] - ? NextIdentScan - : [Result, Code] -) - -type NextIdent = ( - NextUnion extends [infer Left extends string, infer Rest1 extends string] - ? NextIdentScan extends [infer Right extends string, infer Rest2 extends string] - ? [`${Left}${Right}`, Rest2] - : [] - : [] -) -/** Scans for the next Ident */ -export type Ident = NextIdent> - -// ------------------------------------------------------------------ -// Until -// ------------------------------------------------------------------ -type UntilStartsWith = ( - Values extends [infer Left extends string, ...infer Right extends string[]] - ? Input extends `${Left}${string}` - ? true - : UntilStartsWith - : false -) -export type Until = ( - Input extends `` ? [] : - UntilStartsWith extends true - ? [Result, Input] - : Input extends `${infer Left extends string}${infer Right extends string}` - ? Until - : never -) -// ------------------------------------------------------------------ -// UntilNonEmpty -// ------------------------------------------------------------------ -export type UntilNonEmpty = ( - Until extends [infer Left extends string, infer Right extends string] - ? Left extends '' ? [] : [Left, Right] - : [] -) \ No newline at end of file diff --git a/src/static/tuple.ts b/src/static/tuple.ts new file mode 100644 index 0000000..7fc4854 --- /dev/null +++ b/src/static/tuple.ts @@ -0,0 +1,50 @@ +/*-------------------------------------------------------------------------- + +ParseBox + +The MIT License (MIT) + +Copyright (c) 2024-2025 Haydn Paterson + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +---------------------------------------------------------------------------*/ + +// deno-fmt-ignore-file + +import type { Identity, IMapping, IParser } from './parser.ts' +import type { Parse } from './parse.ts' + +// ------------------------------------------------------------------ +// Type +// ------------------------------------------------------------------ +export interface Tuple extends IParser { + type: 'Tuple' + parsers: [...Parsers] +} +// ------------------------------------------------------------------ +// Parse +// ------------------------------------------------------------------ +export type ParseTuple = ( + Parsers extends [infer Left extends IParser, ...infer Right extends IParser[]] + ? Parse extends [infer Element extends unknown, infer Rest extends string] + ? ParseTuple + : [] + : [Result, Input] +) diff --git a/src/static/types.ts b/src/static/types.ts deleted file mode 100644 index 4c845c8..0000000 --- a/src/static/types.ts +++ /dev/null @@ -1,139 +0,0 @@ -/*-------------------------------------------------------------------------- - -@sinclair/parsebox - -The MIT License (MIT) - -Copyright (c) 2024-2025 Haydn Paterson (sinclair) - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -THE SOFTWARE. - ----------------------------------------------------------------------------*/ - -// deno-fmt-ignore-file - -// ------------------------------------------------------------------ -// Mapping -// ------------------------------------------------------------------ -/** - * `[ACTION]` Inference mapping base type. Used to specify semantic actions for - * Parser productions. This type is implemented as a higher-kinded type where - * productions are received on the `input` property with mapping assigned - * the `output` property. The parsing context is available on the `context` - * property. - */ -export interface IMapping { - context: unknown - input: unknown - output: unknown -} -/** `[ACTION]` Default inference mapping. */ -export interface Identity extends IMapping { - output: this['input'] -} -/** `[ACTION]` Maps the given argument `T` as the mapping output */ -export interface As extends IMapping { - output: T -} -// ------------------------------------------------------------------ -// Parser -// ------------------------------------------------------------------ -/** Base type Parser implemented by all other parsers */ -export interface IParser { - type: string - mapping: Mapping -} -// ------------------------------------------------------------------ -// Array -// ------------------------------------------------------------------ -/** `[EBNF]` Creates an Array Parser */ -export interface Array extends IParser { - type: 'Array' - parser: Parser -} -// ------------------------------------------------------------------ -// Const -// ------------------------------------------------------------------ -/** `[TERM]` Creates a Const Parser */ -export interface Const extends IParser { - type: 'Const' - value: Value -} -// ------------------------------------------------------------------ -// Ident -// ------------------------------------------------------------------ -/** Creates an Ident Parser */ -export interface Ident extends IParser { - type: 'Ident' -} -// ------------------------------------------------------------------ -// Number -// ------------------------------------------------------------------ -/** Creates a Number Parser */ -export interface Number extends IParser { - type: 'Number' -} -// ------------------------------------------------------------------ -// Optional -// ------------------------------------------------------------------ -/** `[EBNF]` Creates a Optional Parser */ -export interface Optional extends IParser { - type: 'Optional' - parser: Parser -} -// ------------------------------------------------------------------ -// String -// ------------------------------------------------------------------ -/** `[TERM]` Creates a String Parser. Options are an array of permissable quote characters */ -export interface String extends IParser { - type: 'String' - quote: Options -} -// ------------------------------------------------------------------ -// Tuple -// ------------------------------------------------------------------ -/** `[BNF]` Creates a Tuple Parser */ -export interface Tuple extends IParser { - type: 'Tuple' - parsers: [...Parsers] -} -// ------------------------------------------------------------------ -// Union -// ------------------------------------------------------------------ -/** `[BNF]` Creates a Union Parser */ -export interface Union extends IParser { - type: 'Union' - parsers: [...Parsers] -} -// ------------------------------------------------------------------ -// Until -// ------------------------------------------------------------------ -/** Creates a Until Parser */ -export interface Until extends IParser { - type: 'Until' - values: Values -} -// ------------------------------------------------------------------ -// UntilNonEmpty -// ------------------------------------------------------------------ -/** Creates a UntilNonEmpty Parser */ -export interface UntilNonEmpty extends IParser { - type: 'UntilNonEmpty' - values: Values -} \ No newline at end of file diff --git a/src/static/union.ts b/src/static/union.ts new file mode 100644 index 0000000..2015ccb --- /dev/null +++ b/src/static/union.ts @@ -0,0 +1,50 @@ +/*-------------------------------------------------------------------------- + +ParseBox + +The MIT License (MIT) + +Copyright (c) 2024-2025 Haydn Paterson + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +---------------------------------------------------------------------------*/ + +// deno-fmt-ignore-file + +import type { Identity, IMapping, IParser } from './parser.ts' +import type { Parse } from './parse.ts' + +// ------------------------------------------------------------------ +// Type +// ------------------------------------------------------------------ +export interface Union extends IParser { + type: 'Union' + parsers: [...Parsers] +} +// ------------------------------------------------------------------ +// Parse +// ------------------------------------------------------------------ +export type ParseUnion = ( + Parsers extends [infer Left extends IParser, ...infer Right extends IParser[]] + ? Parse extends [infer Value extends unknown, infer Rest extends string] + ? [Value, Rest] + : ParseUnion + : [] +) diff --git a/src/static/until.ts b/src/static/until.ts new file mode 100644 index 0000000..30709c8 --- /dev/null +++ b/src/static/until.ts @@ -0,0 +1,46 @@ +/*-------------------------------------------------------------------------- + +ParseBox + +The MIT License (MIT) + +Copyright (c) 2024-2025 Haydn Paterson + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +---------------------------------------------------------------------------*/ + +// deno-fmt-ignore-file + +import type { Identity, IMapping, IParser } from './parser.ts' +import * as Token from '../token/index.ts' + +// ------------------------------------------------------------------ +// Type +// ------------------------------------------------------------------ +export interface Until extends IParser { + type: 'Until' + values: End +} +// ------------------------------------------------------------------ +// Parse +// ------------------------------------------------------------------ +export type ParseUntil = ( + Token.TUntil +) \ No newline at end of file diff --git a/src/static/until_1.ts b/src/static/until_1.ts new file mode 100644 index 0000000..b20f185 --- /dev/null +++ b/src/static/until_1.ts @@ -0,0 +1,46 @@ +/*-------------------------------------------------------------------------- + +ParseBox + +The MIT License (MIT) + +Copyright (c) 2024-2025 Haydn Paterson + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +---------------------------------------------------------------------------*/ + +// deno-fmt-ignore-file + +import type { Identity, IMapping, IParser } from './parser.ts' +import * as Token from '../token/index.ts' + +// ------------------------------------------------------------------ +// Type +// ------------------------------------------------------------------ +export interface Until_1 extends IParser { + type: 'Until_1' + values: End +} +// ------------------------------------------------------------------ +// Parse +// ------------------------------------------------------------------ +export type ParseUntil_1 = ( + Token.TUntil_1 +) diff --git a/src/system/arguments/arguments.ts b/src/system/arguments/arguments.ts new file mode 100644 index 0000000..5f5a48b --- /dev/null +++ b/src/system/arguments/arguments.ts @@ -0,0 +1,39 @@ +/*-------------------------------------------------------------------------- + +TypeBox + +The MIT License (MIT) + +Copyright (c) 2017-2025 Haydn Paterson + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +---------------------------------------------------------------------------*/ + +/** + * Match arguments for overloaded functions that use the `...args: unknown[]` pattern. Arguments + * are parsed using argument length only. + */ +export function Match(args: unknown[], match: Record unknown>): Result { + return ( + match[args.length]?.(...args) ?? (() => { + throw Error('Invalid Arguments') + })() + ) as never +} diff --git a/src/system/arguments/index.ts b/src/system/arguments/index.ts new file mode 100644 index 0000000..a2dadc4 --- /dev/null +++ b/src/system/arguments/index.ts @@ -0,0 +1,29 @@ +/*-------------------------------------------------------------------------- + +TypeBox + +The MIT License (MIT) + +Copyright (c) 2017-2025 Haydn Paterson + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +---------------------------------------------------------------------------*/ + +export * as Arguments from './arguments.ts' diff --git a/src/system/index.ts b/src/system/index.ts new file mode 100644 index 0000000..9c877d7 --- /dev/null +++ b/src/system/index.ts @@ -0,0 +1,30 @@ +/*-------------------------------------------------------------------------- + +ParseBox + +The MIT License (MIT) + +Copyright (c) 2024-2025 Haydn Paterson + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +---------------------------------------------------------------------------*/ + +export * from './arguments/index.ts' +export * from './unreachable/index.ts' diff --git a/src/system/unreachable/index.ts b/src/system/unreachable/index.ts new file mode 100644 index 0000000..5d151cc --- /dev/null +++ b/src/system/unreachable/index.ts @@ -0,0 +1,29 @@ +/*-------------------------------------------------------------------------- + +ParseBox + +The MIT License (MIT) + +Copyright (c) 2024-2025 Haydn Paterson + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +---------------------------------------------------------------------------*/ + +export * from './unreachable.ts' diff --git a/src/compile/common/unreachable.ts b/src/system/unreachable/unreachable.ts similarity index 75% rename from src/compile/common/unreachable.ts rename to src/system/unreachable/unreachable.ts index 5aff288..37e15f5 100644 --- a/src/compile/common/unreachable.ts +++ b/src/system/unreachable/unreachable.ts @@ -1,10 +1,10 @@ /*-------------------------------------------------------------------------- -@sinclair/parsebox +ParseBox The MIT License (MIT) -Copyright (c) 2024-2025 Haydn Paterson (sinclair) +Copyright (c) 2024-2025 Haydn Paterson Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal @@ -26,16 +26,13 @@ THE SOFTWARE. ---------------------------------------------------------------------------*/ -// deno-fmt-ignore-file +// deno-coverage-ignore-start - unreachable by definition -import { Runtime } from '../../runtime/index.ts' +export type TUnreachable = never -export class UnreachableError extends Error { - constructor(public parser: Runtime.IParser) { - super('unreachable') - } +export function Unreachable(cause: unknown = undefined): TUnreachable { + // @ts-ignore - cause unknown to .d.ts + throw new Error('Unreachable', { cause }) } -export function Unreachable(parser: Runtime.IParser): never { - throw new UnreachableError(parser) -} \ No newline at end of file +// deno-coverage-ignore-stop diff --git a/src/token/bigint.ts b/src/token/bigint.ts new file mode 100644 index 0000000..c397d3c --- /dev/null +++ b/src/token/bigint.ts @@ -0,0 +1,66 @@ +/*-------------------------------------------------------------------------- + +ParseBox + +The MIT License (MIT) + +Copyright (c) 2024-2025 Haydn Paterson + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +---------------------------------------------------------------------------*/ + +// deno-fmt-ignore-file + +import { IsResult } from './internal/result.ts' +import { type TTake, Take } from './internal/take.ts' +import { type TInteger, Integer } from './integer.ts' + +// ------------------------------------------------------------------ +// TakeBigInt +// ------------------------------------------------------------------ +type TTakeBigInt = ( + TInteger extends [infer Integer extends string, infer IntegerRest extends string] + ? TTake<['n'], IntegerRest> extends [infer N extends string, infer NRest extends string] + ? [`${Integer}`, NRest] + : [] // fail: did not match 'n' + : [] // fail: did not match Integer +) +function TakeBigInt(input: Input): TTakeBigInt { + const integer = Integer(input) + return ( + IsResult(integer) ? (() => { + const n = Take(['n'], integer[1]) + return IsResult(n) + ? [`${integer[0]}`, n[1]] + : [] // fail: did not match 'n' + })() : [] // fail: did not match Integer + ) as never +} +// ------------------------------------------------------------------ +// BigInt +// ------------------------------------------------------------------ +/** Matches if next is a Integer literal with trailing 'n'. Trailing 'n' is omitted in result. */ +export type TBigInt = ( + TTakeBigInt +) +/** Matches if next is a Integer literal with trailing 'n'. Trailing 'n' is omitted in result. */ +export function BigInt(input: Input): TBigInt { + return TakeBigInt(input) as never +} \ No newline at end of file diff --git a/src/token/const.ts b/src/token/const.ts new file mode 100644 index 0000000..d424ccc --- /dev/null +++ b/src/token/const.ts @@ -0,0 +1,69 @@ +/*-------------------------------------------------------------------------- + +ParseBox + +The MIT License (MIT) + +Copyright (c) 2024-2025 Haydn Paterson + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +---------------------------------------------------------------------------*/ + +// deno-fmt-ignore-file + +import { IsEqual } from './internal/guard.ts' +import { type TTrimWhitespace, TrimWhitespace } from './internal/trim.ts' +import { type TTrim, Trim } from './internal/trim.ts' +import { type TTake, Take } from './internal/take.ts' + +import { type TNewLine, NewLine } from './internal/char.ts' +import { type TWhiteSpace, WhiteSpace } from './internal/char.ts' + +// ------------------------------------------------------------------ +// TakeConst +// ------------------------------------------------------------------ +type TTakeConst = ( + TTake<[Const], Input> +) +function TakeConst(const_: Const, input: Input): TTakeConst { + return Take([const_], input) as never +} +// ------------------------------------------------------------------ +// Const +// ------------------------------------------------------------------ +/** Matches if next is the given Const value */ +export type TConst = ( + Const extends '' ? ['', Input] : + Const extends `${infer First extends string}${string}` ? ( + First extends TNewLine ? TTakeConst> : + First extends TWhiteSpace ? TTakeConst : + TTakeConst> + ) : never +) +/** Matches if next is the given Const value */ +export function Const(const_: Const, input: Input): TConst { + return ( + IsEqual(const_, '') ? ['', input] : ( + const_.startsWith(NewLine) ? TakeConst(const_, TrimWhitespace(input)) : + const_.startsWith(WhiteSpace) ? TakeConst(const_, input) : + TakeConst(const_, Trim(input)) + ) + ) as never +} diff --git a/src/token/ident.ts b/src/token/ident.ts new file mode 100644 index 0000000..eedc472 --- /dev/null +++ b/src/token/ident.ts @@ -0,0 +1,102 @@ +/*-------------------------------------------------------------------------- + +ParseBox + +The MIT License (MIT) + +Copyright (c) 2024-2025 Haydn Paterson + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +---------------------------------------------------------------------------*/ + +// deno-fmt-ignore-file + +import { IsResult } from './internal/result.ts' +import { type TTrim, Trim } from './internal/trim.ts' +import { type TTake, Take } from './internal/take.ts' + +import { type TAlpha, Alpha } from './internal/char.ts' +import { type TDigit, Digit } from './internal/char.ts' +import { type TUnderScore, UnderScore } from './internal/char.ts' +import { type TDollarSign, DollarSign } from './internal/char.ts' + +// ------------------------------------------------------------------ +// TakeInitial +// ------------------------------------------------------------------ +type TInitial = [...TAlpha, TUnderScore, TDollarSign] +const Initial = [...Alpha, UnderScore, DollarSign] + +type TTakeInitial = ( + TTake +) +function TakeInitial(input: Input): TTakeInitial { + return Take(Initial, input) as never +} +// ------------------------------------------------------------------ +// TakeRemaining +// ------------------------------------------------------------------ +type TRemaining = [...TInitial, ...TDigit] +const Remaining = [...Initial, ...Digit] + +type TTakeRemaining = ( + TTake extends [infer Remaining extends string, infer RemainingRest extends string] + ? TTakeRemaining + : [Result, Input] +) +function TakeRemaining(input: Input, result: string = ''): TTakeRemaining { + const remaining = Take(Remaining, input) as string[] + return ( + IsResult(remaining) + ? TakeRemaining(remaining[1], `${result}${remaining[0]}`) + : [result, input] + ) as never +} +// ------------------------------------------------------------------ +// TakeIdent +// ------------------------------------------------------------------ +type TTakeIdent = ( + TTakeInitial extends [infer Initial extends string, infer InitialRest extends string] + ? TTakeRemaining extends [infer Remaining extends string, infer RemainingRest extends string] + ? [`${Initial}${Remaining}`, RemainingRest] + : [] // fail: did not match Remaining + : [] // fail: did not match Initial +) +function TakeIdent(input: Input): TTakeIdent { + const initial = TakeInitial(input) as string[] + return ( + IsResult(initial) ? (() => { + const remaining = TakeRemaining(initial[1]) + return IsResult(remaining) + ? [`${initial[0]}${remaining[0]}`, remaining[1]] + : [] // fail: did not match Remaining + })() : [] // fail: did not match Initial + ) as never +} +// ------------------------------------------------------------------ +// Ident +// ------------------------------------------------------------------ +/** Matches if next is an Ident */ +export type TIdent = ( + TTakeIdent> +) +/** Matches if next is an Ident */ +export function Ident(input: Input): TIdent { + return TakeIdent(Trim(input)) as never +} \ No newline at end of file diff --git a/src/token/index.ts b/src/token/index.ts new file mode 100644 index 0000000..03def4c --- /dev/null +++ b/src/token/index.ts @@ -0,0 +1,37 @@ +/*-------------------------------------------------------------------------- + +ParseBox + +The MIT License (MIT) + +Copyright (c) 2024-2025 Haydn Paterson + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +---------------------------------------------------------------------------*/ + +export * from './bigint.ts' +export * from './const.ts' +export * from './ident.ts' +export * from './integer.ts' +export * from './number.ts' +export * from './span.ts' +export * from './string.ts' +export * from './until_1.ts' +export * from './until.ts' diff --git a/src/token/integer.ts b/src/token/integer.ts new file mode 100644 index 0000000..008c4dd --- /dev/null +++ b/src/token/integer.ts @@ -0,0 +1,117 @@ +/*-------------------------------------------------------------------------- + +ParseBox + +The MIT License (MIT) + +Copyright (c) 2024-2025 Haydn Paterson + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +---------------------------------------------------------------------------*/ + +// deno-fmt-ignore-file + +import { IsResult } from './internal/result.ts' +import { type TTrim, Trim } from './internal/trim.ts' +import { type TTake, Take } from './internal/take.ts' +import { type TMany, Many } from './internal/many.ts' +import { type TOptional, Optional } from './internal/optional.ts' + +import { type TDigit, Digit } from './internal/char.ts' +import { type THyphen, Hyphen } from './internal/char.ts' +import { type TZero, Zero } from './internal/char.ts' +import { type TNonZero, NonZero } from './internal/char.ts' +import { type TUnderScore, UnderScore } from './internal/char.ts' + +// ------------------------------------------------------------------ +// TakeSign +// ------------------------------------------------------------------ +type TTakeSign = ( + TOptional +) +function TakeSign(input: Input): TTakeSign { + return Optional(Hyphen, input) as never +} +// ------------------------------------------------------------------ +// TakeNonZero +// ------------------------------------------------------------------ +type TTakeNonZero = ( + TTake +) +function TakeNonZero(input: Input): TTakeNonZero { + return Take(NonZero, input) +} +// ------------------------------------------------------------------ +// TakeDigits +// ------------------------------------------------------------------ +type TAllowedDigits = [...TDigit, TUnderScore] +const AllowedDigits = [...Digit, UnderScore] as TAllowedDigits +// ... +type TTakeDigits = ( + TMany +) +function TakeDigits(input: Input): TTakeDigits { + return Many(AllowedDigits, [UnderScore], input) as never +} +// ------------------------------------------------------------------ +// TakeInteger +// ------------------------------------------------------------------ +type TTakeInteger = ( + TTakeSign 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 extends [infer NonZero extends string, infer NonZeroRest extends string] + ? TTakeDigits extends [infer Digits extends string, infer DigitsRest extends string] + ? [`${Sign}${NonZero}${Digits}`, DigitsRest] + : [] // fail: did not match Digits + : [] // fail: did not match NonZero + : [] // fail: did not match Sign +) +function TakeInteger(input: Input): TTakeInteger { + const sign = TakeSign(input) + return ( + IsResult(sign) ? (() => { + const zero = Take([Zero], sign[1]) + return IsResult(zero) + ? [`${sign[0]}${zero[0]}`, zero[1]] + : (() => { + const nonZero = TakeNonZero(sign[1]) + return IsResult(nonZero) ? (() => { + const digits = TakeDigits(nonZero[1]) + return IsResult(digits) + ? [`${sign[0]}${nonZero[0]}${digits[0]}`, digits[1]] + : [] // fail: did not match Digits + })() : [] // fail: did not match NonZero + })() + })() : [] // fail: did not match Sign + ) as never +} +// ------------------------------------------------------------------ +// Integer +// ------------------------------------------------------------------ +/** Matches if next is a Integer */ +export type TInteger = ( + TTakeInteger> +) +/** Matches if next is a Integer */ +export function Integer(input: Input): TInteger { + return TakeInteger(Trim(input)) as never +} + diff --git a/src/token/internal/char.ts b/src/token/internal/char.ts new file mode 100644 index 0000000..d1913f4 --- /dev/null +++ b/src/token/internal/char.ts @@ -0,0 +1,80 @@ +/*-------------------------------------------------------------------------- + +ParseBox + +The MIT License (MIT) + +Copyright (c) 2024-2025 Haydn Paterson + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +---------------------------------------------------------------------------*/ + +// deno-fmt-ignore-file + +// ------------------------------------------------------------------ +// Range +// ------------------------------------------------------------------ +function Range(start: number, end: number): string[] { + return Array.from({ length: end - start + 1 }, (_, i) => String.fromCharCode(start + i)) +} +// ------------------------------------------------------------------ +// Alphas +// ------------------------------------------------------------------ +export type TAlpha = [ + 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', + 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', + 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', + 'y', 'z', 'A', 'B', 'C', 'D', 'E', 'F', + 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', + 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', + 'W', 'X', 'Y', 'Z', +] +export const Alpha = [ + ...Range(97, 122), // Lowercase + ...Range(65, 90) // Uppercase +] as TAlpha + +// ------------------------------------------------------------------ +// Digits +// ------------------------------------------------------------------ +export type TZero = typeof Zero +export type TNonZero = ['1', '2', '3', '4', '5', '6', '7', '8', '9'] +export type TDigit = [TZero, ...TNonZero] + +export const Zero = '0' +export const NonZero = Range(49, 57) as TNonZero // 1 - 9 +export const Digit = [Zero, ...NonZero] as TDigit + +// ------------------------------------------------------------------ +// Characters +// ------------------------------------------------------------------ +export const WhiteSpace = ' ' +export const NewLine = '\n' +export const UnderScore = '_' +export const Dot = '.' +export const DollarSign = '$' +export const Hyphen = '-' + +export type TWhiteSpace = typeof WhiteSpace +export type TNewLine = typeof NewLine +export type TUnderScore = typeof UnderScore +export type TDot = typeof Dot +export type TDollarSign = typeof DollarSign +export type THyphen = typeof Hyphen diff --git a/src/runtime/guard.ts b/src/token/internal/guard.ts similarity index 72% rename from src/runtime/guard.ts rename to src/token/internal/guard.ts index 489b06d..497a86d 100644 --- a/src/runtime/guard.ts +++ b/src/token/internal/guard.ts @@ -1,10 +1,10 @@ /*-------------------------------------------------------------------------- -@sinclair/parsebox +ParseBox The MIT License (MIT) -Copyright (c) 2024-2025 Haydn Paterson (sinclair) +Copyright (c) 2024-2025 Haydn Paterson Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal @@ -26,20 +26,15 @@ THE SOFTWARE. ---------------------------------------------------------------------------*/ -// deno-fmt-ignore-file - -export function IsEqual(left: unknown, right: unknown): boolean { - return left === right -} -export function HasPropertyKey(value: Record, key: Key): value is Record & { [_ in Key]: unknown } { - return key in value -} -export function IsObject(value: unknown): value is Record { - return typeof value === 'object' && value !== null -} +// ------------------------------------------------------------------ +// Internal Guards to ensure Token is portable. +// ------------------------------------------------------------------ export function IsArray(value: unknown): value is unknown[] { - return globalThis.Array.isArray(value) + return Array.isArray(value) } export function IsString(value: unknown): value is string { - return typeof value === 'string' -} \ No newline at end of file + return IsEqual(typeof value, 'string') +} +export function IsEqual(left: unknown, right: unknown): boolean { + return left === right +} diff --git a/src/token/internal/many.ts b/src/token/internal/many.ts new file mode 100644 index 0000000..2c42153 --- /dev/null +++ b/src/token/internal/many.ts @@ -0,0 +1,72 @@ +/*-------------------------------------------------------------------------- + +ParseBox + +The MIT License (MIT) + +Copyright (c) 2024-2025 Haydn Paterson + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +---------------------------------------------------------------------------*/ + +// deno-fmt-ignore-file + +import { IsResult } from './result.ts' +import { type TTake, Take } from './take.ts' + +// ------------------------------------------------------------------ +// IsDiscard +// ------------------------------------------------------------------ +type TIsDiscard = ( + Discard extends [infer Left extends string, ...infer Right extends string[]] + ? Input extends Left + ? true + : TIsDiscard + : false +) +function IsDiscard + (discard: [...Discard], input: Input): + TIsDiscard { + return discard.includes(input) as never +} +// ------------------------------------------------------------------ +// Many +// ------------------------------------------------------------------ +/** Takes characters from the Input until no-match. The Discard set is used to omit characters from the match */ +export type TMany = ( + TTake extends [infer Char extends string, infer Rest extends string] + ? TIsDiscard extends true + ? TMany + : TMany + : [Result, Input] +) +/** Takes characters from the Input until no-match. The Discard set is used to omit characters from the match */ +export function Many + (allowed: [...Allowed], discard: [...Discard], input: Input, result: string = ''): + TMany { + const takeResult = Take(allowed, input) as [string, string] + return ( + IsResult(takeResult) + ? IsDiscard(discard, takeResult[0]) + ? Many(allowed, discard, takeResult[1], result) + : Many(allowed, discard, takeResult[1], `${result}${takeResult[0]}`) + : [result, input] + ) as never +} \ No newline at end of file diff --git a/src/token/internal/optional.ts b/src/token/internal/optional.ts new file mode 100644 index 0000000..2f019c0 --- /dev/null +++ b/src/token/internal/optional.ts @@ -0,0 +1,49 @@ +/*-------------------------------------------------------------------------- + +ParseBox + +The MIT License (MIT) + +Copyright (c) 2024-2025 Haydn Paterson + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +---------------------------------------------------------------------------*/ + +// deno-fmt-ignore-file + +import { IsResult } from './result.ts' +import { type TTake, Take } from './take.ts' + +/** Matches the given Value or empty string if no match. This function never fails */ +export type TOptional = ( + TTake<[Value], Input> extends [infer Optional extends string, infer Rest extends string] + ? [Optional, Rest] + : ['', Input] +) +/** Matches the given Value or empty string if no match. This function never fails */ +export function Optional + (value: Value, input: Input): TOptional { + const result = Take([value], input) + return ( + IsResult(result) + ? result + : ['', input] + ) as never +} \ No newline at end of file diff --git a/src/token/internal/result.ts b/src/token/internal/result.ts new file mode 100644 index 0000000..4b9a3b8 --- /dev/null +++ b/src/token/internal/result.ts @@ -0,0 +1,34 @@ +/*-------------------------------------------------------------------------- + +ParseBox + +The MIT License (MIT) + +Copyright (c) 2024-2025 Haydn Paterson + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +---------------------------------------------------------------------------*/ + +import { IsArray, IsEqual } from './guard.ts' + +/** Checks the value is a Tuple-2 [string, string] result */ +export function IsResult(value: unknown): value is [string, string] { + return IsArray(value) && IsEqual(value.length, 2) +} diff --git a/src/token/internal/take.ts b/src/token/internal/take.ts new file mode 100644 index 0000000..f55d389 --- /dev/null +++ b/src/token/internal/take.ts @@ -0,0 +1,70 @@ +/*-------------------------------------------------------------------------- + +ParseBox + +The MIT License (MIT) + +Copyright (c) 2024-2025 Haydn Paterson + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +---------------------------------------------------------------------------*/ + +// deno-fmt-ignore-file + +import { IsEqual, IsString } from './guard.ts' + +// ------------------------------------------------------------------ +// TakeString +// ------------------------------------------------------------------ +type TTakeVariant = ( + Input extends `${Variant}${infer Rest extends string}` + ? [Variant, Rest] + : [] +) +function TakeVariant(variant: Variant, input: Input): TTakeVariant { + return ( + IsEqual(input.indexOf(variant), 0) + ? [variant, input.slice(variant.length)] + : [] + ) as never +} +// ------------------------------------------------------------------ +// Take +// ------------------------------------------------------------------ +/** Takes one of the given variants or fail */ +export type TTake = ( + Variants extends [infer ValueLeft extends string, ...infer ValueRight extends string[]] + ? TTakeVariant extends [infer Take extends string, infer Rest extends string] + ? [Take, Rest] + : TTake + : [] +) +/** Takes one of the given variants or fail */ +export function Take(variants: [...Variants], input: Input): TTake { + const [left, ...right] = variants + return ( + IsString(left) + ? (() => { + const result = TakeVariant(left, input) + return IsEqual(result.length, 2) ? result : Take(right, input) + })() + : [] + ) as never +} diff --git a/src/token/internal/trim.ts b/src/token/internal/trim.ts new file mode 100644 index 0000000..c6b8015 --- /dev/null +++ b/src/token/internal/trim.ts @@ -0,0 +1,123 @@ +/*-------------------------------------------------------------------------- + +ParseBox + +The MIT License (MIT) + +Copyright (c) 2024-2025 Haydn Paterson + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +---------------------------------------------------------------------------*/ + +// deno-fmt-ignore-file + +import { IsEqual } from './guard.ts' +import * as Char from './char.ts' + +// ------------------------------------------------------------------ +// Comments +// ------------------------------------------------------------------ +type LineComment = typeof LineComment +type OpenComment = typeof OpenComment +type CloseComment = typeof CloseComment + +const LineComment = '//' +const OpenComment = '/*' +const CloseComment = '*/' + +// ------------------------------------------------------------------ +// DiscardMultiLineComment +// ------------------------------------------------------------------ +type TDiscardMultiLineComment = ( + Input extends `${string}${CloseComment}${infer Rest extends string}` ? Rest : + '' +) +function DiscardMultilineComment(input: Input): TDiscardMultiLineComment { + const index = input.indexOf(CloseComment) + const result = IsEqual(index, -1) ? '' : input.slice(index + 2) + return result as never +} +// ------------------------------------------------------------------ +// DiscardLineComment +// ------------------------------------------------------------------ +type TDiscardLineComment = ( + Input extends `${string}${Char.TNewLine}${infer Rest extends string}` + ? TTrimWhitespace<`${Char.TNewLine}${Rest}`> + : '' +) +function DiscardLineComment(input: Input): TDiscardLineComment { + const index = input.indexOf(Char.NewLine) + const result = IsEqual(index, -1) ? '' : input.slice(index) + return result as never +} +// ------------------------------------------------------------------ +// Whitespace Filters +// ------------------------------------------------------------------ +type W4 = `${W3}${W3}` // 16 +type W3 = `${W2}${W2}` // 8 +type W2 = `${W1}${W1}` // 4 +type W1 = `${W0}${W0}` // 2 +type W0 = ` ` // 1 +// ------------------------------------------------------------------ +// TrimWhitespace +// ------------------------------------------------------------------ +export type TTrimWhitespace = ( + Input extends `${OpenComment}${infer Rest extends string}` ? TTrimWhitespace> : + Input extends `${LineComment}${infer Rest extends string}` ? TTrimWhitespace> : + Input extends `${W4}${infer Rest extends string}` ? TTrimWhitespace : + Input extends `${W3}${infer Rest extends string}` ? TTrimWhitespace : + Input extends `${W1}${infer Rest extends string}` ? TTrimWhitespace : + Input extends `${W0}${infer Rest extends string}` ? TTrimWhitespace : + Input +) +// ... +function TrimStartUntilNewline(input: string): string { + return input.replace(/^[ \t\r\f\v]+/, '') +} +export function TrimWhitespace(input: Input): TTrimWhitespace { + const trimmed = TrimStartUntilNewline(input) + return ( + trimmed.startsWith(OpenComment) ? TrimWhitespace(DiscardMultilineComment(trimmed.slice(2))) : + trimmed.startsWith(LineComment) ? TrimWhitespace(DiscardLineComment(trimmed.slice(2))) : + trimmed + ) as never +} +// ------------------------------------------------------------------ +// Trim +// ------------------------------------------------------------------ +export type TTrim = ( + Input extends `${OpenComment}${infer Rest extends string}` ? TTrim> : + Input extends `${LineComment}${infer Rest extends string}` ? TTrim> : + Input extends `${Char.TNewLine}${infer Rest extends string}` ? TTrim : + Input extends `${W4}${infer Rest extends string}` ? TTrim : + Input extends `${W3}${infer Rest extends string}` ? TTrim : + Input extends `${W1}${infer Rest extends string}` ? TTrim : + Input extends `${W0}${infer Rest extends string}` ? TTrim : + Input +) +export function Trim(input: Input): TTrim { + const trimmed = input.trimStart() + return ( + trimmed.startsWith(OpenComment) ? Trim(DiscardMultilineComment(trimmed.slice(2))) : + trimmed.startsWith(LineComment) ? Trim(DiscardLineComment(trimmed.slice(2))) : + trimmed + ) as never +} + diff --git a/src/token/number.ts b/src/token/number.ts new file mode 100644 index 0000000..2de08df --- /dev/null +++ b/src/token/number.ts @@ -0,0 +1,168 @@ +/*-------------------------------------------------------------------------- + +ParseBox + +The MIT License (MIT) + +Copyright (c) 2024-2025 Haydn Paterson + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +---------------------------------------------------------------------------*/ + +// deno-fmt-ignore-file + +import { IsEqual } from './internal/guard.ts' +import { IsResult } from './internal/result.ts' +import { type TTrim, Trim } from './internal/trim.ts' +import { type TTake, Take } from './internal/take.ts' +import { type TMany, Many } from './internal/many.ts' +import { type TOptional, Optional } from './internal/optional.ts' + +import { type TDigit, Digit, TUnderScore, UnderScore } from './internal/char.ts' +import { type TDot, Dot } from './internal/char.ts' +import { type THyphen, Hyphen } from './internal/char.ts' +import { type TInteger, Integer } from './integer.ts' + +// ------------------------------------------------------------------ +// AllowedDigits +// ------------------------------------------------------------------ +type TAllowedDigits = [...TDigit, TUnderScore] +const AllowedDigits = [...Digit, UnderScore] as TAllowedDigits + +// ------------------------------------------------------------------ +// TakeSign +// ------------------------------------------------------------------ +type TTakeSign = ( + TOptional +) +function TakeSign(input: Input): TTakeSign { + return Optional(Hyphen, input) as never +} +// ------------------------------------------------------------------ +// IsLeadingDot +// ------------------------------------------------------------------ +type TIsLeadingDot = ( + TTake<[TDot], Input> extends [string, string] ? true : false +) +function IsLeadingDot(input: Input): TIsLeadingDot { + return IsResult(Take([Dot], input)) as never +} +// ------------------------------------------------------------------ +// TakeFractional +// ------------------------------------------------------------------ +type TTakeFractional = ( + TMany extends [infer Digits extends string, infer Rest extends string] + ? Digits extends '' + ? [] // fail: no Digits + : [Digits, Rest] + : [] // fail: did not match Digits +) +function TakeFractional(input: Input): TTakeFractional { + const digits = Many(AllowedDigits, [UnderScore], input) + return ( + IsResult(digits) + ? IsEqual(digits[0], '') + ? [] // fail: no Digits + : [digits[0], digits[1]] + : [] // fail: did not match Digits + ) as never +} +// ------------------------------------------------------------------ +// LeadingDot +// ------------------------------------------------------------------ +type TLeadingDot = ( + TTake<[TDot], Input> extends [infer Dot extends string, infer Rest extends string] + ? TTakeFractional extends [infer Fractional extends string, infer Rest extends string] + ? [`${Sign}0${Dot}${Fractional}`, Rest] + : [] // fail: did not match Fractional + : [] // fail: did not match Dot +) +function LeadingDot + (sign: Sign, input: Input): + TLeadingDot { + const dot = Take([Dot], input) + return ( + IsResult(dot) ? (() => { + const fractional = TakeFractional(dot[1]) + return IsResult(fractional) + ? [`${sign}0${dot[0]}${fractional[0]}`, fractional[1]] + : [] // fail: did not match Fractional + })() : [] // fail: did not match Dot + ) as never +} +// ------------------------------------------------------------------ +// TakeLeadingInteger +// ------------------------------------------------------------------ +type TLeadingInteger = ( + TInteger extends [infer Integer extends string, infer IntegerRest extends string] + ? TTake<[TDot], IntegerRest> extends [infer Dot extends string, infer DotRest extends string] + ? TTakeFractional extends [infer Fractional extends string, infer FractionalRest extends string] + ? [`${Sign}${Integer}${Dot}${Fractional}`, FractionalRest] + : [`${Sign}${Integer}`, DotRest] // fail: did not match Fractional, use Integer + : [`${Sign}${Integer}`, IntegerRest] // fail: did not match Dot, use Integer + : [] // fail: did not match Integer +) +function LeadingInteger + (sign: Sign, input: Input): + TLeadingInteger { + const integer = Integer(input) + return ( + IsResult(integer) ? (() => { + const dot = Take([Dot], integer[1]) + return IsResult(dot) ? (() => { + const fractional = TakeFractional(dot[1]) + return IsResult(fractional) + ? [`${sign}${integer[0]}${dot[0]}${fractional[0]}`, fractional[1]] + : [`${sign}${integer[0]}`, dot[1]] // fail: did not match Fractional, use Integer + })() : [`${sign}${integer[0]}`, integer[1]] // fail: did not match Dot, use Integer + })() : [] // fail: did not match Integer + ) as never +} +// ------------------------------------------------------------------ +// TakeNumber +// ------------------------------------------------------------------ +type TTakeNumber = ( + TTakeSign extends [infer Sign extends string, infer SignRest extends string] + ? TIsLeadingDot extends true + ? TLeadingDot + : TLeadingInteger + : [] // fail: did not match Sign +) +function TakeNumber(input: Input): TTakeNumber{ + const sign = TakeSign(input) + return ( + IsResult(sign) + ? IsLeadingDot(sign[1]) + ? LeadingDot(sign[0], sign[1]) + : LeadingInteger(sign[0], sign[1]) + : [] // fail: did not match Sign + ) as never +} +// ------------------------------------------------------------------ +// Number +// ------------------------------------------------------------------ +/** Matches if next is a literal Number */ +export type TNumber = ( + TTakeNumber> +) +/** Matches if next is a literal Number */ +export function Number(input: Input): TNumber { + return TakeNumber(Trim(input)) as never +} \ No newline at end of file diff --git a/src/token/span.ts b/src/token/span.ts new file mode 100644 index 0000000..6dc7470 --- /dev/null +++ b/src/token/span.ts @@ -0,0 +1,106 @@ +/*-------------------------------------------------------------------------- + +ParseBox + +The MIT License (MIT) + +Copyright (c) 2024-2025 Haydn Paterson + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +---------------------------------------------------------------------------*/ + +// deno-fmt-ignore-file + +import { IsResult } from './internal/result.ts' +import { type TTrim, Trim } from './internal/trim.ts' +import { type TNewLine, NewLine } from './internal/char.ts' +import { type TUntil, Until } from './until.ts' + +// ------------------------------------------------------------------ +// MultiLine +// ------------------------------------------------------------------ +type TMultiLine = ( + 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] + : [] // fail: did not match End + : [] // fail: did not match Until + : [] // fail: did not match Start +) +function MultiLine + (start: Start, end: End, input: Input): + TMultiLine { + return ( + input.startsWith(start) ? (() => { + const until = Until([end], input.slice(start.length)) + return IsResult(until) ? (() => { + return until[1].startsWith(end) + ? [`${until[0]}`, until[1].slice(end.length)] + : [] // fail: did not match End + })() : [] // fail: did not match Until + })() : [] // fail: did not match Start + ) as never +} +// ------------------------------------------------------------------ +// SingleLine +// ------------------------------------------------------------------ +type TSingleLine = ( + 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] + : [] // fail: did not match End + : [] // fail: did not match Until + : [] // fail: not match Start +) +function SingleLine + (start: Start, end: End, input: Input): + TSingleLine { + return ( + input.startsWith(start) ? (() => { + const until = Until([NewLine, end], input.slice(start.length)) + return IsResult(until) ? (() => { + return until[1].startsWith(end) + ? [`${until[0]}`, until[1].slice(end.length)] + : [] // fail: did not match End + })() : [] // fail: did not match Until + })() : [] // fail: not match Start + ) as never +} +// ------------------------------------------------------------------ +// Span +// ------------------------------------------------------------------ +/** Matches from Start and End capturing everything in-between. Start and End are consumed. */ +export type TSpan = ( + MultiLine extends true + ? TMultiLine> + : TSingleLine> +) +/** Matches from Start and End capturing everything in-between. Start and End are consumed. */ +export function Span + (start: Start, end: End, multiLine: MultiLine, input: Input): + TSpan { + return ( + multiLine + ? MultiLine(start, end, Trim(input)) + : SingleLine(start, end, Trim(input)) + ) as never +} \ No newline at end of file diff --git a/src/token/string.ts b/src/token/string.ts new file mode 100644 index 0000000..8c93207 --- /dev/null +++ b/src/token/string.ts @@ -0,0 +1,77 @@ +/*-------------------------------------------------------------------------- + +ParseBox + +The MIT License (MIT) + +Copyright (c) 2024-2025 Haydn Paterson + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +---------------------------------------------------------------------------*/ + +// deno-fmt-ignore-file + +import { IsResult } from './internal/result.ts' +import { type TTake, Take } from './internal/take.ts' +import { type TTrim, Trim } from './internal/trim.ts' +import { type TSpan, Span } from './span.ts' + +// ------------------------------------------------------------------ +// TakeInitial +// ------------------------------------------------------------------ +type TTakeInitial = ( + TTake +) +function TakeInitial(quotes: [...Quotes], input: Input): TTakeInitial { + return Take(quotes, input) +} +// ------------------------------------------------------------------ +// TakeSpan +// ------------------------------------------------------------------ +type TTakeSpan = ( + TSpan +) +function TakeSpan(quote: Quote, input: Input): TTakeSpan { + return Span(quote, quote, false, input) as never +} +// ------------------------------------------------------------------ +// TakeString +// ------------------------------------------------------------------ +type TTakeString = ( + TTakeInitial extends [infer Initial extends string, infer InitialRest extends string] + ? TTakeSpan + : [] // fail: did not match Initial +) +function TakeString(quotes: [...Quotes], input: Input): TTakeString { + const initial = TakeInitial(quotes, input) + return ( + IsResult(initial) + ? TakeSpan(initial[0], `${initial[0]}${initial[1]}`) + : [] // fail: did not match Initial + ) as never +} +/** Matches a literal String with the given quotes */ +export type TString = ( + TTakeString> +) +/** Matches a literal String with the given quotes */ +export function String(quotes: [...Quotes], input: Input): TString { + return TakeString(quotes, Trim(input)) as never +} \ No newline at end of file diff --git a/src/token/until.ts b/src/token/until.ts new file mode 100644 index 0000000..f3431c0 --- /dev/null +++ b/src/token/until.ts @@ -0,0 +1,79 @@ +/*-------------------------------------------------------------------------- + +ParseBox + +The MIT License (MIT) + +Copyright (c) 2024-2025 Haydn Paterson + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +---------------------------------------------------------------------------*/ + +// deno-fmt-ignore-file + +import { IsEqual, IsString } from './internal/guard.ts' + +// ------------------------------------------------------------------ +// IsEnd +// ------------------------------------------------------------------ +type TIsEnd = ( + End extends [infer Left extends string, ...infer Right extends string[]] + ? Input extends `${Left}${string}` + ? true + : TIsEnd + : false +) +function IsEnd + (end: [...End], input: Input): + TIsEnd { + const [left, ...right] = end + return ( + IsString(left) + ? input.startsWith(left) + ? true + : IsEnd(right, input) + : false + ) as never +} +// ------------------------------------------------------------------ +// Until +// ------------------------------------------------------------------ +/** Match Input until but not including End. No match if End not found. */ +export type TUntil = ( + Input extends `` + ? [] // fail: Input is empty + : TIsEnd extends true + ? [Result, Input] + : Input extends `${infer Left extends string}${infer Right extends string}` + ? TUntil + : [] +) +/** Match Input until but not including End. No match if End not found. */ +export function Until + (end: [...End], input: Input, result: string = ''): TUntil { + return ( + IsEqual(input, '') + ? [] // fail: Input is empty + : IsEnd(end, input) ? [result, input] : (() => { + const [left, right] = [input.slice(0, 1), input.slice(1)] + return Until(end, right, `${result}${left}`) + })() + ) as never +} diff --git a/src/token/until_1.ts b/src/token/until_1.ts new file mode 100644 index 0000000..e95514c --- /dev/null +++ b/src/token/until_1.ts @@ -0,0 +1,58 @@ +/*-------------------------------------------------------------------------- + +ParseBox + +The MIT License (MIT) + +Copyright (c) 2024-2025 Haydn Paterson + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +---------------------------------------------------------------------------*/ + +// deno-fmt-ignore-file + +import { IsEqual } from './internal/guard.ts' +import { IsResult } from './internal/result.ts' +import { type TUntil, Until } from './until.ts' + +// ------------------------------------------------------------------ +// Until_1 +// ------------------------------------------------------------------ +/** Match Input until but not including End. No match if End not found or match is zero-length. */ +export type TUntil_1 = ( + TUntil extends [infer Until extends string, infer UntilRest extends string] + ? Until extends '' + ? [] // fail: match has no characters + : [Until, UntilRest] + : [] // fail: did not match Until +) +/** Match Input until but not including End. No match if End not found or match is zero-length. */ +export function Until_1 + (end: [...End], input: Input): + TUntil_1 { + const until = Until(end, input) + return ( + IsResult(until) + ? IsEqual(until[0], '') + ? [] // fail: match has no characters + : until + : [] // fail: did not match Until + ) as never +} diff --git a/tasks.ts b/tasks.ts index b07bd2c..82e742c 100644 --- a/tasks.ts +++ b/tasks.ts @@ -1,4 +1,4 @@ -import { Task } from 'https://raw.githubusercontent.com/sinclairzx81/tasksmith/0.8.2/src/index.ts' +import { Task } from 'tasksmith' // ------------------------------------------------------------------ // Clean @@ -10,7 +10,7 @@ Task.run('clean', async () => { // Format // ------------------------------------------------------------------ Task.run('format', async () => { - await Task.shell('deno fmt src') + await Task.shell('deno fmt src test') }) // ------------------------------------------------------------------ // Start @@ -21,20 +21,34 @@ Task.run('start', async () => { // ------------------------------------------------------------------ // Test // ------------------------------------------------------------------ -Task.run('test', async () => { - await Task.shell('deno test -A test') +Task.run('test', async (filter: string = '') => { + await Task.test.run(['test/parsebox'], { filter }) +}) +// ------------------------------------------------------------------ +// Fast +// ------------------------------------------------------------------ +Task.run('fast', async (filter: string = '') => { + await Task.test.run(['test/parsebox'], { + watch: true, noCheck: true, filter, + }) +}) +// ------------------------------------------------------------------ +// Report +// ------------------------------------------------------------------ +Task.run('report', async () => { + await Task.test.report(['test/parsebox']) }) // ------------------------------------------------------------------ // Build // ------------------------------------------------------------------ -Task.run('build', () => Task.build('src', { +Task.run('build', () => Task.build.dual('src', { compiler: 'latest', outdir: 'target/build', additional: ['license', 'readme.md'], packageJson: { name: '@sinclair/parsebox', description: 'Parser Combinators in the TypeScript Type System', - version: '0.10.0', + version: '0.11.0', keywords: ['typescript', 'parser', 'combinator'], license: 'MIT', author: 'sinclairzx81', diff --git a/test/__tests__/runtime/assert.ts b/test/__tests__/runtime/assert.ts deleted file mode 100644 index ee9bef6..0000000 --- a/test/__tests__/runtime/assert.ts +++ /dev/null @@ -1,5 +0,0 @@ -import { assertEquals } from 'jsr:@std/assert' - -export function Assert(left: unknown, right: unknown) { - assertEquals(left, right) -} \ No newline at end of file diff --git a/test/__tests__/runtime/guard.ts b/test/__tests__/runtime/guard.ts deleted file mode 100644 index 3c86bbd..0000000 --- a/test/__tests__/runtime/guard.ts +++ /dev/null @@ -1,54 +0,0 @@ -// deno-lint-ignore-file - -import { Runtime } from '@sinclair/parsebox' -import { Assert } from './assert.ts' - -Deno.test('IsArray', () => { - // @ts-ignore - Assert(Runtime.IsArray(Runtime.Array(1)), false) - Assert(Runtime.IsArray(Runtime.Array(Runtime.Const('A'))), true) -}) - -Deno.test('IsConst', () => { - Assert(Runtime.IsConst(Runtime.Const('A')), true) - // @ts-ignore - Assert(Runtime.IsConst(Runtime.Const(undefined)), false) -}) - -Deno.test('IsIdent', () => { - Assert(Runtime.IsIdent(Runtime.Const('A')), false) - Assert(Runtime.IsIdent(Runtime.Ident()), true) -}) - -Deno.test('IsNumber', () => { - Assert(Runtime.IsNumber(Runtime.Const('A')), false) - Assert(Runtime.IsNumber(Runtime.Number()), true) -}) - -Deno.test('IsOptional', () => { - // @ts-ignore - Assert(Runtime.IsOptional(Runtime.Optional(1)), false) - Assert(Runtime.IsOptional(Runtime.Optional(Runtime.Const('A'))), true) -}) - -Deno.test('IsRef', () => { - // @ts-ignore - Assert(Runtime.IsRef(Runtime.Ref(1)), false) - Assert(Runtime.IsRef(Runtime.Ref('A')), true) -}) - -Deno.test('IsString', () => { - Assert(Runtime.IsString(Runtime.Const('A')), false) - Assert(Runtime.IsString(Runtime.String(['"'])), true) -}) - -Deno.test('IsTuple', () => { - Assert(Runtime.IsTuple(Runtime.Const('A')), false) - Assert(Runtime.IsTuple(Runtime.Tuple([Runtime.Const('A')])), true) -}) - -Deno.test('IsUnion', () => { - Assert(Runtime.IsUnion(Runtime.Const('A')), false) - Assert(Runtime.IsUnion(Runtime.Union([Runtime.Const('A')])), true) -}) - diff --git a/test/__tests__/runtime/parse.ts b/test/__tests__/runtime/parse.ts deleted file mode 100644 index 54919a9..0000000 --- a/test/__tests__/runtime/parse.ts +++ /dev/null @@ -1,196 +0,0 @@ -import { Runtime } from '@sinclair/parsebox' -import { Assert } from './assert.ts' - -// ---------------------------------------------------------------- -// Array -// ---------------------------------------------------------------- -Deno.test('Array', () => { - Assert(Runtime.Parse(Runtime.Array(Runtime.Const('A')), ''), [[], '']) - Assert(Runtime.Parse(Runtime.Array(Runtime.Const('A')), 'AB'), [['A'], 'B']) - Assert(Runtime.Parse(Runtime.Array(Runtime.Const('A')), 'AAB'), [['A', 'A'], 'B']) - Assert(Runtime.Parse(Runtime.Array(Runtime.Const('AA')), 'AAB'), [['AA'], 'B']) - Assert(Runtime.Parse(Runtime.Array(Runtime.Const('AA')), 'AAAB'), [['AA'], 'AB']) - Assert(Runtime.Parse(Runtime.Array(Runtime.Const('AA')), 'B'), [[], 'B']) -}) - -// ---------------------------------------------------------------- -// Const -// ---------------------------------------------------------------- -Deno.test('Const', () => { - Assert(Runtime.Parse(Runtime.Const('A'), ''), []) - Assert(Runtime.Parse(Runtime.Const('A'), 'A'), ['A', '']) - Assert(Runtime.Parse(Runtime.Const('A'), ' A'), ['A', '']) - Assert(Runtime.Parse(Runtime.Const('A'), ' A '), ['A', ' ']) -}) - -// ---------------------------------------------------------------- -// Until -// ---------------------------------------------------------------- -Deno.test('Until', () => { - Assert(Runtime.Parse(Runtime.Until(['A']), ''), []) - Assert(Runtime.Parse(Runtime.Until(['A']), 'A'), ['', 'A']) - Assert(Runtime.Parse(Runtime.Until(['A']), ' A'), [' ', 'A']) - Assert(Runtime.Parse(Runtime.Until(['A']), ' A '), [' ', 'A ']) - - Assert(Runtime.Parse(Runtime.Until(['A', 'B']), ''), []) - Assert(Runtime.Parse(Runtime.Until(['A', 'B']), 'BA'), ['', 'BA']) - Assert(Runtime.Parse(Runtime.Until(['A', 'B']), ' BA'), [' ', 'BA']) - Assert(Runtime.Parse(Runtime.Until(['A', 'B']), ' BA '), [' ', 'BA ']) -}) - -// ---------------------------------------------------------------- -// UntilNonEmpty -// ---------------------------------------------------------------- -Deno.test('UntilNonEmpty', () => { - Assert(Runtime.Parse(Runtime.UntilNonEmpty(['A']), ''), []) - Assert(Runtime.Parse(Runtime.UntilNonEmpty(['A']), 'A'), []) - Assert(Runtime.Parse(Runtime.UntilNonEmpty(['A']), ' A'), [' ', 'A']) - Assert(Runtime.Parse(Runtime.UntilNonEmpty(['A']), ' A '), [' ', 'A ']) - - Assert(Runtime.Parse(Runtime.UntilNonEmpty(['A', 'B']), ''), []) - Assert(Runtime.Parse(Runtime.UntilNonEmpty(['A', 'B']), 'BA'), []) - Assert(Runtime.Parse(Runtime.UntilNonEmpty(['A', 'B']), ' BA'), [' ', 'BA']) - Assert(Runtime.Parse(Runtime.UntilNonEmpty(['A', 'B']), ' BA '), [' ', 'BA ']) -}) - -// ---------------------------------------------------------------- -// Ident -// ---------------------------------------------------------------- -Deno.test('Ident', () => { - Assert(Runtime.Parse(Runtime.Ident(), ''), []) - Assert(Runtime.Parse(Runtime.Ident(), '0'), []) - Assert(Runtime.Parse(Runtime.Ident(), '#'), []) - Assert(Runtime.Parse(Runtime.Ident(), '_'), ['_', '']) - Assert(Runtime.Parse(Runtime.Ident(), ' _'), ['_', '']) - Assert(Runtime.Parse(Runtime.Ident(), '_ '), ['_', ' ']) - Assert(Runtime.Parse(Runtime.Ident(), ' _ '), ['_', ' ']) - Assert(Runtime.Parse(Runtime.Ident(), '$'), ['$', '']) - Assert(Runtime.Parse(Runtime.Ident(), ' $'), ['$', '']) - Assert(Runtime.Parse(Runtime.Ident(), '$ '), ['$', ' ']) - Assert(Runtime.Parse(Runtime.Ident(), ' $ '), ['$', ' ']) - Assert(Runtime.Parse(Runtime.Ident(), 'A'), ['A', '']) - Assert(Runtime.Parse(Runtime.Ident(), ' A'), ['A', '']) - Assert(Runtime.Parse(Runtime.Ident(), 'A '), ['A', ' ']) - Assert(Runtime.Parse(Runtime.Ident(), ' A '), ['A', ' ']) - Assert(Runtime.Parse(Runtime.Ident(), 'A1'), ['A1', '']) - Assert(Runtime.Parse(Runtime.Ident(), ' A1'), ['A1', '']) - Assert(Runtime.Parse(Runtime.Ident(), 'A1 '), ['A1', ' ']) - Assert(Runtime.Parse(Runtime.Ident(), ' A1 '), ['A1', ' ']) -}) -// ---------------------------------------------------------------- -// Number -// ---------------------------------------------------------------- -Deno.test('Number', () => { - Assert(Runtime.Parse(Runtime.Number(), ''), []) - Assert(Runtime.Parse(Runtime.Number(), '01'), []) - Assert(Runtime.Parse(Runtime.Number(), ' 01'), []) - Assert(Runtime.Parse(Runtime.Number(), '01 '), []) - Assert(Runtime.Parse(Runtime.Number(), ' 01 '), []) - Assert(Runtime.Parse(Runtime.Number(), '0'), ['0', '']) - Assert(Runtime.Parse(Runtime.Number(), '0 '), ['0', ' ']) - Assert(Runtime.Parse(Runtime.Number(), ' 0'), ['0', '']) - Assert(Runtime.Parse(Runtime.Number(), ' 0 '), ['0', ' ']) - Assert(Runtime.Parse(Runtime.Number(), '-0'), ['-0', '']) - Assert(Runtime.Parse(Runtime.Number(), '-0 '), ['-0', ' ']) - Assert(Runtime.Parse(Runtime.Number(), ' -0'), ['-0', '']) - Assert(Runtime.Parse(Runtime.Number(), ' -0 '), ['-0', ' ']) - Assert(Runtime.Parse(Runtime.Number(), '100'), ['100', '']) - Assert(Runtime.Parse(Runtime.Number(), '100 '), ['100', ' ']) - Assert(Runtime.Parse(Runtime.Number(), ' 100'), ['100', '']) - Assert(Runtime.Parse(Runtime.Number(), ' 100 '), ['100', ' ']) - Assert(Runtime.Parse(Runtime.Number(), '-100'), ['-100', '']) - Assert(Runtime.Parse(Runtime.Number(), '-100 '), ['-100', ' ']) - Assert(Runtime.Parse(Runtime.Number(), ' -100'), ['-100', '']) - Assert(Runtime.Parse(Runtime.Number(), ' -100 '), ['-100', ' ']) - Assert(Runtime.Parse(Runtime.Number(), '0.1'), ['0.1', '']) - Assert(Runtime.Parse(Runtime.Number(), '0.1 '), ['0.1', ' ']) - Assert(Runtime.Parse(Runtime.Number(), ' 0.1'), ['0.1', '']) - Assert(Runtime.Parse(Runtime.Number(), ' 0.1 '), ['0.1', ' ']) - Assert(Runtime.Parse(Runtime.Number(), '100.1'), ['100.1', '']) - Assert(Runtime.Parse(Runtime.Number(), '100.1 '), ['100.1', ' ']) - Assert(Runtime.Parse(Runtime.Number(), ' 100.1'), ['100.1', '']) - Assert(Runtime.Parse(Runtime.Number(), ' 100.1 '), ['100.1', ' ']) - Assert(Runtime.Parse(Runtime.Number(), '-100.1'), ['-100.1', '']) - Assert(Runtime.Parse(Runtime.Number(), '-100.1 '), ['-100.1', ' ']) - Assert(Runtime.Parse(Runtime.Number(), ' -100.1'), ['-100.1', '']) - Assert(Runtime.Parse(Runtime.Number(), ' -100.1 '), ['-100.1', ' ']) - Assert(Runtime.Parse(Runtime.Number(), '100.1.1'), ['100.1', '.1']) - Assert(Runtime.Parse(Runtime.Number(), '100.1.1 '), ['100.1', '.1 ']) - Assert(Runtime.Parse(Runtime.Number(), ' 100.1.1'), ['100.1', '.1']) - Assert(Runtime.Parse(Runtime.Number(), ' 100.1.1 '), ['100.1', '.1 ']) - Assert(Runtime.Parse(Runtime.Number(), '-.1'), ['-.1', '']) - Assert(Runtime.Parse(Runtime.Number(), '-.1 '), ['-.1', ' ']) - Assert(Runtime.Parse(Runtime.Number(), ' -.1'), ['-.1', '']) - Assert(Runtime.Parse(Runtime.Number(), ' -.1 '), ['-.1', ' ']) - Assert(Runtime.Parse(Runtime.Number(), '-0.1'), ['-0.1', '']) - Assert(Runtime.Parse(Runtime.Number(), '-0.1 '), ['-0.1', ' ']) - Assert(Runtime.Parse(Runtime.Number(), ' -0.1'), ['-0.1', '']) - Assert(Runtime.Parse(Runtime.Number(), ' -0.1 '), ['-0.1', ' ']) -}) -// ---------------------------------------------------------------- -// Optional -// ---------------------------------------------------------------- -Deno.test('Optional', () => { - Assert(Runtime.Parse(Runtime.Optional(Runtime.Const('A')), ''), [[], '']) - Assert(Runtime.Parse(Runtime.Optional(Runtime.Const('A')), 'A'), [['A'], '']) - Assert(Runtime.Parse(Runtime.Optional(Runtime.Const('A')), 'AA'), [['A'], 'A']) - Assert(Runtime.Parse(Runtime.Optional(Runtime.Const('A')), 'B'), [[], 'B']) -}) -// ---------------------------------------------------------------- -// String -// ---------------------------------------------------------------- -Deno.test('String', () => { - Assert(Runtime.Parse(Runtime.String(['"']), ''), []) - Assert(Runtime.Parse(Runtime.String(['"']), '"A"'), ['A', '']) - Assert(Runtime.Parse(Runtime.String(['"']), ' "A"'), ['A', '']) - Assert(Runtime.Parse(Runtime.String(['"']), '"A" '), ['A', ' ']) - Assert(Runtime.Parse(Runtime.String(['"']), ' "A" '), ['A', ' ']) - Assert(Runtime.Parse(Runtime.String(['*', '"']), ''), []) - Assert(Runtime.Parse(Runtime.String(['*', '"']), '*A*'), ['A', '']) - Assert(Runtime.Parse(Runtime.String(['*', '"']), ' *A*'), ['A', '']) - Assert(Runtime.Parse(Runtime.String(['*', '"']), '*A* '), ['A', ' ']) - Assert(Runtime.Parse(Runtime.String(['*', '"']), ' *A* '), ['A', ' ']) - Assert(Runtime.Parse(Runtime.String(['*', '"']), '"A"'), ['A', '']) - Assert(Runtime.Parse(Runtime.String(['*', '"']), ' "A"'), ['A', '']) - Assert(Runtime.Parse(Runtime.String(['*', '"']), '"A" '), ['A', ' ']) - Assert(Runtime.Parse(Runtime.String(['*', '"']), ' "A" '), ['A', ' ']) -}) -// ---------------------------------------------------------------- -// Tuple -// ---------------------------------------------------------------- -Deno.test('Tuple', () => { - const Tuple = Runtime.Tuple([Runtime.Const('A'), Runtime.Const('B'), Runtime.Const('C')]) - Assert(Runtime.Parse(Tuple, ''), []) - Assert(Runtime.Parse(Tuple, 'A'), []) - Assert(Runtime.Parse(Tuple, 'A B C'), [['A', 'B', 'C'], '']) - Assert(Runtime.Parse(Tuple, 'A B C '), [['A', 'B', 'C'], ' ']) - Assert(Runtime.Parse(Tuple, 'ABC'), [['A', 'B', 'C'], '']) - Assert(Runtime.Parse(Tuple, ' ABC'), [['A', 'B', 'C'], '']) - Assert(Runtime.Parse(Tuple, ' ABC '), [['A', 'B', 'C'], ' ']) -}) -// ---------------------------------------------------------------- -// Union -// ---------------------------------------------------------------- -Deno.test('Union', () => { - const Union = Runtime.Union([Runtime.Const('A'), Runtime.Const('B'), Runtime.Const('C')]) - Assert(Runtime.Parse(Union, ''), []) - Assert(Runtime.Parse(Union, 'A B C'), ['A', ' B C']) - Assert(Runtime.Parse(Union, 'A B C '), ['A', ' B C ']) - Assert(Runtime.Parse(Union, 'ABC'), ['A', 'BC']) - Assert(Runtime.Parse(Union, ' ABC'), ['A', 'BC']) - Assert(Runtime.Parse(Union, ' ABC '), ['A', 'BC ']) - Assert(Runtime.Parse(Union, 'B B C'), ['B', ' B C']) - Assert(Runtime.Parse(Union, 'B B C '), ['B', ' B C ']) - Assert(Runtime.Parse(Union, 'BBC'), ['B', 'BC']) - Assert(Runtime.Parse(Union, ' BBC'), ['B', 'BC']) - Assert(Runtime.Parse(Union, ' BBC '), ['B', 'BC ']) -}) -// ---------------------------------------------------------------- -// Mapping -// ---------------------------------------------------------------- -Deno.test('Mapping', () => { - const Mapping = (_0: 'A', _1: 'B', _2: 'C') => [_2, _1, _0] as const - const Mapped = Runtime.Tuple([Runtime.Const('A'), Runtime.Const('B'), Runtime.Const('C')], values => Mapping(...values)) - Assert(Runtime.Parse(Mapped, ' A B C '), [['C', 'B', 'A'], ' ']) -}) - diff --git a/test/__tests__/runtime/token.ts b/test/__tests__/runtime/token.ts deleted file mode 100644 index 8707779..0000000 --- a/test/__tests__/runtime/token.ts +++ /dev/null @@ -1,306 +0,0 @@ -import { Runtime } from '@sinclair/parsebox' -import { Assert } from './assert.ts' - -// ------------------------------------------------------------------ -// Const -// ------------------------------------------------------------------ -Deno.test('Const: Empty', () => { - Assert(Runtime.Token.Const('', ''), ['', '']) - Assert(Runtime.Token.Const('', 'A'), ['', 'A']) - Assert(Runtime.Token.Const('', ' A'), ['', ' A']) -}) -Deno.test('Const: Single-Char', () => { - Assert(Runtime.Token.Const('A', 'A'), ['A', '']) - Assert(Runtime.Token.Const('A', 'A '), ['A', ' ']) - Assert(Runtime.Token.Const('A', 'AA'), ['A', 'A']) - Assert(Runtime.Token.Const('A', 'AA '), ['A', 'A ']) -}) -Deno.test('Const: Multi-Char', () => { - Assert(Runtime.Token.Const('AB', 'AB'), ['AB', '']) - Assert(Runtime.Token.Const('AB', 'AB '), ['AB', ' ']) - Assert(Runtime.Token.Const('AB', 'ABA'), ['AB', 'A']) - Assert(Runtime.Token.Const('AB', 'ABA '), ['AB', 'A ']) -}) -Deno.test('Const: Single-Char -> Ignore-Whitespace', () => { - Assert(Runtime.Token.Const('A', ' A'), ['A', '']) - Assert(Runtime.Token.Const('A', ' A '), ['A', ' ']) - Assert(Runtime.Token.Const('A', ' AA'), ['A', 'A']) - Assert(Runtime.Token.Const('A', ' AA '), ['A', 'A ']) - Assert(Runtime.Token.Const('A', '\nAA '), ['A', 'A ']) - Assert(Runtime.Token.Const('A', ' \nAA '), ['A', 'A ']) - Assert(Runtime.Token.Const('A', '\n AA '), ['A', 'A ']) - Assert(Runtime.Token.Const('A', ' \n AA '), ['A', 'A ']) -}) -Deno.test('Const: Multi-Char -> Ignore-Whitespace', () => { - Assert(Runtime.Token.Const('AB', ' AB'), ['AB', '']) - Assert(Runtime.Token.Const('AB', ' AB '), ['AB', ' ']) - Assert(Runtime.Token.Const('AB', ' ABA'), ['AB', 'A']) - Assert(Runtime.Token.Const('AB', ' ABA '), ['AB', 'A ']) - Assert(Runtime.Token.Const('AB', '\nABA '), ['AB', 'A ']) - Assert(Runtime.Token.Const('AB', ' \nABA '), ['AB', 'A ']) - Assert(Runtime.Token.Const('AB', '\n ABA '), ['AB', 'A ']) - Assert(Runtime.Token.Const('AB', ' \n ABA '), ['AB', 'A ']) -}) -Deno.test('Const: Single-Whitespace', () => { - Assert(Runtime.Token.Const(' ', ''), []) - Assert(Runtime.Token.Const(' ', ' '), [' ', '']) - Assert(Runtime.Token.Const(' ', ' A'), [' ', 'A']) - Assert(Runtime.Token.Const(' ', ' A '), [' ', 'A ']) - Assert(Runtime.Token.Const(' ', ' AA'), [' ', 'AA']) - Assert(Runtime.Token.Const(' ', ' AA '), [' ', 'AA ']) -}) -Deno.test('Const: Multi-Whitespace', () => { - Assert(Runtime.Token.Const(' ', ''), []) - Assert(Runtime.Token.Const(' ', ' '), []) - Assert(Runtime.Token.Const(' ', ' A'), [' ', 'A']) - Assert(Runtime.Token.Const(' ', ' A '), [' ', 'A ']) - Assert(Runtime.Token.Const(' ', ' AA'), [' ', 'AA']) - Assert(Runtime.Token.Const(' ', ' AA '), [' ', 'AA ']) -}) -Deno.test('Const: Newline', () => { - Assert(Runtime.Token.Const('\n', ''), []) - Assert(Runtime.Token.Const('\n', ' '), []) - Assert(Runtime.Token.Const('\n', '\nA'), ['\n', 'A']) - Assert(Runtime.Token.Const('\n', ' \nA '), ['\n', 'A ']) - Assert(Runtime.Token.Const('\n', ' \nAA'), ['\n', 'AA']) - Assert(Runtime.Token.Const('\n', ' \nAA '), ['\n', 'AA ']) -}) -Deno.test('Const: Newline-Single-Whitespace', () => { - Assert(Runtime.Token.Const('\n ', ''), []) - Assert(Runtime.Token.Const('\n ', ' '), []) - Assert(Runtime.Token.Const('\n ', '\nA'), []) - Assert(Runtime.Token.Const('\n ', ' \nA '), []) - Assert(Runtime.Token.Const('\n ', ' \nAA'), []) - Assert(Runtime.Token.Const('\n ', ' \nAA '), []) - Assert(Runtime.Token.Const('\n ', '\n A'), ['\n ', 'A']) - Assert(Runtime.Token.Const('\n ', ' \n A '), ['\n ', 'A ']) - Assert(Runtime.Token.Const('\n ', ' \n AA'), ['\n ', 'AA']) - Assert(Runtime.Token.Const('\n ', ' \n AA '), ['\n ', 'AA ']) -}) -Deno.test('Const: Newline-Multi-Whitespace', () => { - Assert(Runtime.Token.Const('\n ', ''), []) - Assert(Runtime.Token.Const('\n ', ' '), []) - Assert(Runtime.Token.Const('\n ', '\nA'), []) - Assert(Runtime.Token.Const('\n ', ' \nA '), []) - Assert(Runtime.Token.Const('\n ', ' \nAA'), []) - Assert(Runtime.Token.Const('\n ', ' \nAA '), []) - Assert(Runtime.Token.Const('\n ', '\n A'), ['\n ', 'A']) - Assert(Runtime.Token.Const('\n ', ' \n A '), ['\n ', 'A ']) - Assert(Runtime.Token.Const('\n ', ' \n AA'), ['\n ', 'AA']) - Assert(Runtime.Token.Const('\n ', ' \n AA '), ['\n ', 'AA ']) -}) -// ------------------------------------------------------------------ -// Until -// ------------------------------------------------------------------ -Deno.test('Until: Empty', () => { - Assert(Runtime.Token.Until([''], ''), []) - Assert(Runtime.Token.Until([''], 'A'), ['', 'A']) - Assert(Runtime.Token.Until([''], ' A'), ['', ' A']) -}) -Deno.test('Until: Single-Char', () => { - Assert(Runtime.Token.Until(['A'], 'A'), ['', 'A']) - Assert(Runtime.Token.Until(['A'], 'A '), ['', 'A ']) - Assert(Runtime.Token.Until(['A'], 'AA'), ['', 'AA']) - Assert(Runtime.Token.Until(['A'], 'AA '), ['', 'AA ']) -}) -Deno.test('Until: Multi-Char', () => { - Assert(Runtime.Token.Until(['AB'], 'AB'), ['', 'AB']) - Assert(Runtime.Token.Until(['AB'], 'AB '), ['', 'AB ']) - Assert(Runtime.Token.Until(['AB'], 'ABA'), ['', 'ABA']) - Assert(Runtime.Token.Until(['AB'], 'ABA '), ['', 'ABA ']) -}) -Deno.test('Until: Single-Char -> Ignore-Whitespace', () => { - Assert(Runtime.Token.Until(['A'], ' A'), [' ', 'A']) - Assert(Runtime.Token.Until(['A'], ' A '), [' ', 'A ']) - Assert(Runtime.Token.Until(['A'], ' AA'), [' ', 'AA']) - Assert(Runtime.Token.Until(['A'], ' AA '), [' ', 'AA ']) - Assert(Runtime.Token.Until(['A'], '\nAA '), ['\n', 'AA ']) - Assert(Runtime.Token.Until(['A'], ' \nAA '), [' \n', 'AA ']) - Assert(Runtime.Token.Until(['A'], '\n AA '), ['\n ', 'AA ']) - Assert(Runtime.Token.Until(['A'], ' \n AA '), [' \n ', 'AA ']) -}) -Deno.test('Until: Multi-Char -> Ignore-Whitespace', () => { - Assert(Runtime.Token.Until(['AB'], ' AB'), [' ', 'AB']) - Assert(Runtime.Token.Until(['AB'], ' AB '), [' ', 'AB ']) - Assert(Runtime.Token.Until(['AB'], ' ABA'), [' ', 'ABA']) - Assert(Runtime.Token.Until(['AB'], ' ABA '), [' ', 'ABA ']) - Assert(Runtime.Token.Until(['AB'], '\nABA '), ['\n', 'ABA ']) - Assert(Runtime.Token.Until(['AB'], ' \nABA '), [' \n', 'ABA ']) - Assert(Runtime.Token.Until(['AB'], '\n ABA '), ['\n ', 'ABA ']) - Assert(Runtime.Token.Until(['AB'], ' \n ABA '), [' \n ', 'ABA ']) -}) -Deno.test('Until: Single-Whitespace', () => { - Assert(Runtime.Token.Until([' '], ''), []) - Assert(Runtime.Token.Until([' '], ' '), ['', ' ']) - Assert(Runtime.Token.Until([' '], ' A'), ['', ' A']) - Assert(Runtime.Token.Until([' '], ' A '), ['', ' A ']) - Assert(Runtime.Token.Until([' '], ' AA'), ['', ' AA']) - Assert(Runtime.Token.Until([' '], ' AA '), ['', ' AA ']) -}) -Deno.test('Until: Multi-Whitespace', () => { - Assert(Runtime.Token.Until([' '], ''), []) - Assert(Runtime.Token.Until([' '], ' '), []) - Assert(Runtime.Token.Until([' '], ' A'), ['', ' A']) - Assert(Runtime.Token.Until([' '], ' A '), ['', ' A ']) - Assert(Runtime.Token.Until([' '], ' AA'), ['', ' AA']) - Assert(Runtime.Token.Until([' '], ' AA '), ['', ' AA ']) -}) -Deno.test('Until: Newline', () => { - Assert(Runtime.Token.Until(['\n'], ''), []) - Assert(Runtime.Token.Until(['\n'], ' '), []) - Assert(Runtime.Token.Until(['\n'], '\nA'), ['', '\nA']) - Assert(Runtime.Token.Until(['\n'], ' \nA '), [' ', '\nA ']) - Assert(Runtime.Token.Until(['\n'], ' \nAA'), [' ', '\nAA']) - Assert(Runtime.Token.Until(['\n'], ' \nAA '), [' ', '\nAA ']) -}) -Deno.test('Until: Newline-Single-Whitespace', () => { - Assert(Runtime.Token.Until(['\n '], ''), []) - Assert(Runtime.Token.Until(['\n '], ' '), []) - Assert(Runtime.Token.Until(['\n '], '\nA'), []) - Assert(Runtime.Token.Until(['\n '], ' \nA '), []) - Assert(Runtime.Token.Until(['\n '], ' \nAA'), []) - Assert(Runtime.Token.Until(['\n '], ' \nAA '), []) - Assert(Runtime.Token.Until(['\n '], '\n A'), ['', '\n A']) - Assert(Runtime.Token.Until(['\n '], ' \n A '), [' ', '\n A ']) - Assert(Runtime.Token.Until(['\n '], ' \n AA'), [' ', '\n AA']) - Assert(Runtime.Token.Until(['\n '], ' \n AA '), [' ', '\n AA ']) -}) -Deno.test('Until: Newline-Multi-Whitespace', () => { - Assert(Runtime.Token.Until(['\n '], ''), []) - Assert(Runtime.Token.Until(['\n '], ' '), []) - Assert(Runtime.Token.Until(['\n '], '\nA'), []) - Assert(Runtime.Token.Until(['\n '], ' \nA '), []) - Assert(Runtime.Token.Until(['\n '], ' \nAA'), []) - Assert(Runtime.Token.Until(['\n '], ' \nAA '), []) - Assert(Runtime.Token.Until(['\n '], '\n A'), ['', '\n A']) - Assert(Runtime.Token.Until(['\n '], ' \n A '), [' ', '\n A ']) - Assert(Runtime.Token.Until(['\n '], ' \n AA'), [' ', '\n AA']) - Assert(Runtime.Token.Until(['\n '], ' \n AA '), [' ', '\n AA ']) -}) - -Deno.test('Until: Multi Sentinal Test', () => { - Assert(Runtime.Token.Until(['A', 'B'], ''), []) - Assert(Runtime.Token.Until(['A', 'B'], 'A'), ['', 'A']) - Assert(Runtime.Token.Until(['A', 'B'], 'B'), ['', 'B']) - Assert(Runtime.Token.Until(['A', 'B'], 'AB'), ['', 'AB']) - Assert(Runtime.Token.Until(['A', 'B'], 'BA'), ['', 'BA']) - Assert(Runtime.Token.Until(['A', 'B'], ' AB'), [' ', 'AB']) - Assert(Runtime.Token.Until(['A', 'B'], ' BA'), [' ', 'BA']) - Assert(Runtime.Token.Until(['A', ' B'], ' BA'), [' ', ' BA']) - Assert(Runtime.Token.Until([' A', 'B'], ' BA'), [' ', 'BA']) - Assert(Runtime.Token.Until(['B', 'A'], ' AB'), [' ', 'AB']) - Assert(Runtime.Token.Until(['B', 'A'], ' BA'), [' ', 'BA']) - Assert(Runtime.Token.Until(['B', ' A'], ' BA'), [' ', 'BA']) - Assert(Runtime.Token.Until([' B', 'A'], ' BA'), [' ', ' BA']) -}) - -Deno.test('UntilNonEmpty: Empty', () => { - Assert(Runtime.Token.UntilNonEmpty([''], ''), []) - Assert(Runtime.Token.UntilNonEmpty([''], 'A'), []) - Assert(Runtime.Token.UntilNonEmpty([''], ' A'), []) -}) - -Deno.test('UntilNonEmpty: Single-Char', () => { - Assert(Runtime.Token.UntilNonEmpty(['A'], 'A'), []) - Assert(Runtime.Token.UntilNonEmpty(['A'], 'A '), []) - Assert(Runtime.Token.UntilNonEmpty(['A'], 'AA'), []) - Assert(Runtime.Token.UntilNonEmpty(['A'], 'AA '), []) -}) - -Deno.test('UntilNonEmpty: Multi-Char', () => { - Assert(Runtime.Token.UntilNonEmpty(['AB'], 'AB'), []) - Assert(Runtime.Token.UntilNonEmpty(['AB'], 'AB '), []) - Assert(Runtime.Token.UntilNonEmpty(['AB'], 'ABA'), []) - Assert(Runtime.Token.UntilNonEmpty(['AB'], 'ABA '), []) -}) - -Deno.test('UntilNonEmpty: Single-Char -> Ignore-Whitespace', () => { - Assert(Runtime.Token.UntilNonEmpty(['A'], ' A'), [' ', 'A']) - Assert(Runtime.Token.UntilNonEmpty(['A'], ' A '), [' ', 'A ']) - Assert(Runtime.Token.UntilNonEmpty(['A'], ' AA'), [' ', 'AA']) - Assert(Runtime.Token.UntilNonEmpty(['A'], ' AA '), [' ', 'AA ']) - Assert(Runtime.Token.UntilNonEmpty(['A'], '\nAA '), ['\n', 'AA ']) - Assert(Runtime.Token.UntilNonEmpty(['A'], ' \nAA '), [' \n', 'AA ']) - Assert(Runtime.Token.UntilNonEmpty(['A'], '\n AA '), ['\n ', 'AA ']) - Assert(Runtime.Token.UntilNonEmpty(['A'], ' \n AA '), [' \n ', 'AA ']) -}) - -Deno.test('UntilNonEmpty: Multi-Char -> Ignore-Whitespace', () => { - Assert(Runtime.Token.UntilNonEmpty(['AB'], ' AB'), [' ', 'AB']) - Assert(Runtime.Token.UntilNonEmpty(['AB'], ' AB '), [' ', 'AB ']) - Assert(Runtime.Token.UntilNonEmpty(['AB'], ' ABA'), [' ', 'ABA']) - Assert(Runtime.Token.UntilNonEmpty(['AB'], ' ABA '), [' ', 'ABA ']) - Assert(Runtime.Token.UntilNonEmpty(['AB'], '\nABA '), ['\n', 'ABA ']) - Assert(Runtime.Token.UntilNonEmpty(['AB'], ' \nABA '), [' \n', 'ABA ']) - Assert(Runtime.Token.UntilNonEmpty(['AB'], '\n ABA '), ['\n ', 'ABA ']) - Assert(Runtime.Token.UntilNonEmpty(['AB'], ' \n ABA '), [' \n ', 'ABA ']) -}) - -Deno.test('UntilNonEmpty: Single-Whitespace', () => { - Assert(Runtime.Token.UntilNonEmpty([' '], ''), []) - Assert(Runtime.Token.UntilNonEmpty([' '], ' '), []) - Assert(Runtime.Token.UntilNonEmpty([' '], ' A'), []) - Assert(Runtime.Token.UntilNonEmpty([' '], ' A '), []) - Assert(Runtime.Token.UntilNonEmpty([' '], ' AA'), []) - Assert(Runtime.Token.UntilNonEmpty([' '], ' AA '), []) -}) - -Deno.test('UntilNonEmpty: Multi-Whitespace', () => { - Assert(Runtime.Token.UntilNonEmpty([' '], ''), []) - Assert(Runtime.Token.UntilNonEmpty([' '], ' '), []) - Assert(Runtime.Token.UntilNonEmpty([' '], ' A'), []) - Assert(Runtime.Token.UntilNonEmpty([' '], ' A '), []) - Assert(Runtime.Token.UntilNonEmpty([' '], ' AA'), []) - Assert(Runtime.Token.UntilNonEmpty([' '], ' AA '), []) -}) - -Deno.test('UntilNonEmpty: Newline', () => { - Assert(Runtime.Token.UntilNonEmpty(['\n'], ''), []) - Assert(Runtime.Token.UntilNonEmpty(['\n'], ' '), []) - Assert(Runtime.Token.UntilNonEmpty(['\n'], '\nA'), []) - Assert(Runtime.Token.UntilNonEmpty(['\n'], ' \nA '), [' ', '\nA ']) - Assert(Runtime.Token.UntilNonEmpty(['\n'], ' \nAA'), [' ', '\nAA']) - Assert(Runtime.Token.UntilNonEmpty(['\n'], ' \nAA '), [' ', '\nAA ']) -}) - -Deno.test('UntilNonEmpty: Newline-Single-Whitespace', () => { - Assert(Runtime.Token.UntilNonEmpty(['\n '], ''), []) - Assert(Runtime.Token.UntilNonEmpty(['\n '], ' '), []) - Assert(Runtime.Token.UntilNonEmpty(['\n '], '\nA'), []) - Assert(Runtime.Token.UntilNonEmpty(['\n '], ' \nA '), []) - Assert(Runtime.Token.UntilNonEmpty(['\n '], ' \nAA'), []) - Assert(Runtime.Token.UntilNonEmpty(['\n '], ' \nAA '), []) - Assert(Runtime.Token.UntilNonEmpty(['\n '], '\n A'), []) - Assert(Runtime.Token.UntilNonEmpty(['\n '], ' \n A '), [' ', '\n A ']) - Assert(Runtime.Token.UntilNonEmpty(['\n '], ' \n AA'), [' ', '\n AA']) - Assert(Runtime.Token.UntilNonEmpty(['\n '], ' \n AA '), [' ', '\n AA ']) -}) - -Deno.test('UntilNonEmpty: Newline-Multi-Whitespace', () => { - Assert(Runtime.Token.UntilNonEmpty(['\n '], ''), []) - Assert(Runtime.Token.UntilNonEmpty(['\n '], ' '), []) - Assert(Runtime.Token.UntilNonEmpty(['\n '], '\nA'), []) - Assert(Runtime.Token.UntilNonEmpty(['\n '], ' \nA '), []) - Assert(Runtime.Token.UntilNonEmpty(['\n '], ' \nAA'), []) - Assert(Runtime.Token.UntilNonEmpty(['\n '], ' \nAA '), []) - Assert(Runtime.Token.UntilNonEmpty(['\n '], '\n A'), []) - Assert(Runtime.Token.UntilNonEmpty(['\n '], ' \n A '), [' ', '\n A ']) - Assert(Runtime.Token.UntilNonEmpty(['\n '], ' \n AA'), [' ', '\n AA']) - Assert(Runtime.Token.UntilNonEmpty(['\n '], ' \n AA '), [' ', '\n AA ']) -}) - -Deno.test('UntilNonEmpty: Multi Sentinal Test', () => { - Assert(Runtime.Token.UntilNonEmpty(['A', 'B'], ''), []) - Assert(Runtime.Token.UntilNonEmpty(['A', 'B'], 'A'), []) - Assert(Runtime.Token.UntilNonEmpty(['A', 'B'], 'B'), []) - Assert(Runtime.Token.UntilNonEmpty(['A', 'B'], 'AB'), []) - Assert(Runtime.Token.UntilNonEmpty(['A', 'B'], 'BA'), []) - Assert(Runtime.Token.UntilNonEmpty(['A', 'B'], ' AB'), [' ', 'AB']) - Assert(Runtime.Token.UntilNonEmpty(['A', 'B'], ' BA'), [' ', 'BA']) - Assert(Runtime.Token.UntilNonEmpty(['A', ' B'], ' BA'), [' ', ' BA']) - Assert(Runtime.Token.UntilNonEmpty([' A', 'B'], ' BA'), [' ', 'BA']) - Assert(Runtime.Token.UntilNonEmpty(['B', 'A'], ' AB'), [' ', 'AB']) - Assert(Runtime.Token.UntilNonEmpty(['B', 'A'], ' BA'), [' ', 'BA']) - Assert(Runtime.Token.UntilNonEmpty(['B', ' A'], ' BA'), [' ', 'BA']) - Assert(Runtime.Token.UntilNonEmpty([' B', 'A'], ' BA'), [' ', ' BA']) -}) \ No newline at end of file diff --git a/test/__tests__/static/parse.ts b/test/__tests__/static/parse.ts deleted file mode 100644 index 6f63770..0000000 --- a/test/__tests__/static/parse.ts +++ /dev/null @@ -1,190 +0,0 @@ -// deno-fmt-ignore-file - -import { Static } from '@sinclair/parsebox' - -function Assert(): void {} - -// ------------------------------------------------------------------ -// Array -// ------------------------------------------------------------------ -Assert>, ''>, [[], '']>() -Assert>, 'AB'>, [['A'], 'B']>() -Assert>, 'AAB'>, [['A', 'A'], 'B']>() -Assert>, 'AAB'>, [['AA'], 'B']>() -Assert>, 'AAAB'>, [['AA'], 'AB']>() -Assert>, 'B'>, [[], 'B']>() - -// ------------------------------------------------------------------ -// Const -// ------------------------------------------------------------------ -Assert, ''>, []>() -Assert, 'A'>, ['A', '']>() -Assert, ' A'>, ['A', '']>() -Assert, ' A '>, ['A', ' ']>() -// ------------------------------------------------------------------ -// Until -// ------------------------------------------------------------------ -Assert, ''>, []>() -Assert, 'A'>, ['', 'A']>() -Assert, ' A'>, [' ', 'A']>() -Assert, ' A '>, [' ', 'A ']>() - -Assert, ''>, []> -Assert, 'BA'>, ['', 'BA']> -Assert, ' BA'>, [' ', 'BA']> -Assert, ' BA '>, [' ', 'BA ']> - - -// ---------------------------------------------------------------- -// UntilNonEmpty -// ---------------------------------------------------------------- -Assert, ''>, []> -Assert, 'A'>, []> -Assert, ' A'>, [' ', 'A']> -Assert, ' A '>, [' ', 'A ']> - -Assert, ''>, []> -Assert, 'BA'>, []> -Assert, ' BA'>, [' ', 'BA']> -Assert, ' BA '>, [' ', 'BA ']> - - -// ------------------------------------------------------------------ -// Ident -// ------------------------------------------------------------------ -Assert, []>() -Assert, []>() -Assert, []>() -Assert, ['_', '']>() -Assert, ['_', '']>() -Assert, ['_', ' ']>() -Assert, ['_', ' ']>() -Assert, ['$', '']>() -Assert, ['$', '']>() -Assert, ['$', ' ']>() -Assert, ['$', ' ']>() -Assert, ['A', '']>() -Assert, ['A', '']>() -Assert, ['A', ' ']>() -Assert, ['A', ' ']>() -Assert, ['A1', '']>() -Assert, ['A1', '']>() -Assert, ['A1', ' ']>() -Assert, ['A1', ' ']>() - -// ------------------------------------------------------------------ -// Number -// ------------------------------------------------------------------ -Assert, []>() -Assert, []>() -Assert, []>() -Assert, []>() -Assert, []>() -Assert, ['0', '']>() -Assert, ['0', ' ']>() -Assert, ['0', '']>() -Assert, ['0', ' ']>() -Assert, ['-0', '']>() -Assert, ['-0', ' ']>() -Assert, ['-0', '']>() -Assert, ['-0', ' ']>() -Assert, ['100', '']>() -Assert, ['100', ' ']>() -Assert, ['100', '']>() -Assert, ['100', ' ']>() -Assert, ['-100', '']>() -Assert, ['-100', ' ']>() -Assert, ['-100', '']>() -Assert, ['-100', ' ']>() -Assert, ['0.1', '']>() -Assert, ['0.1', ' ']>() -Assert, ['0.1', '']>() -Assert, ['0.1', ' ']>() -Assert, ['100.1', '']>() -Assert, ['100.1', ' ']>() -Assert, ['100.1', '']>() -Assert, ['100.1', ' ']>() -Assert, ['-100.1', '']>() -Assert, ['-100.1', ' ']>() -Assert, ['-100.1', '']>() -Assert, ['-100.1', ' ']>() -Assert, ['100.1', '.1']>() -Assert, ['100.1', '.1 ']>() -Assert, ['100.1', '.1']>() -Assert, ['100.1', '.1 ']>() -Assert, ['-.1', '']>() -Assert, ['-.1', ' ']>() -Assert, ['-.1', '']>() -Assert, ['-.1', ' ']>() -Assert, ['-0.1', '']>() -Assert, ['-0.1', ' ']>() -Assert, ['-0.1', '']>() -Assert, ['-0.1', ' ']>() - -// ------------------------------------------------------------------ -// Optional -// ------------------------------------------------------------------ -Assert>, ''>, [[], '']>() -Assert>, 'A'>, [['A'], '']>() -Assert>, 'AA'>, [['A'], 'A']>() -Assert>, 'B'>, [[], 'B']>() - -// ------------------------------------------------------------------ -// String -// ------------------------------------------------------------------ -Assert, ''>, []>() -Assert, '"A"'>, ['A', '']>() -Assert, ' "A"'>, ['A', '']>() -Assert, '"A" '>, ['A', ' ']>() -Assert, ' "A" '>, ['A', ' ']>() -Assert, ''>, []>() -Assert, '*A*'>, ['A', '']>() -Assert, ' *A*'>, ['A', '']>() -Assert, '*A* '>, ['A', ' ']>() -Assert, ' *A* '>, ['A', ' ']>() -Assert, '"A"'>, ['A', '']>() -Assert, ' "A"'>, ['A', '']>() -Assert, '"A" '>, ['A', ' ']>() -Assert, ' "A" '>, ['A', ' ']>() - -// ------------------------------------------------------------------ -// Tuple -// ------------------------------------------------------------------ -type Tuple = Static.Tuple<[Static.Const<'A'>, Static.Const<'B'>, Static.Const<'C'>]> - -Assert, []>() -Assert, []>() -Assert, [['A', 'B', 'C'], '']>() -Assert, [['A', 'B', 'C'], ' ']>() -Assert, [['A', 'B', 'C'], '']>() -Assert, [['A', 'B', 'C'], '']>() -Assert, [['A', 'B', 'C'], ' ']>() - -// ------------------------------------------------------------------ -// Union -// ------------------------------------------------------------------ -type Union = Static.Union<[Static.Const<'A'>, Static.Const<'B'>, Static.Const<'C'>]> - -Assert, []>() -Assert, ['A', ' B C']>() -Assert, ['A', ' B C ']>() -Assert, ['A', 'BC']>() -Assert, ['A', 'BC']>() -Assert, ['A', 'BC ']>() -Assert, ['B', ' B C']>() -Assert, ['B', ' B C ']>() -Assert, ['B', 'BC']>() -Assert, ['B', 'BC']>() -Assert, ['B', 'BC ']>() - -// ------------------------------------------------------------------ -// Mapping -// ------------------------------------------------------------------ -interface Mapping extends Static.IMapping { - output: this['input'] extends [infer A, infer B, infer C] ? [C, B, A] : never -} - -type Mapped = Static.Tuple<[Static.Const<'A'>, Static.Const<'B'>, Static.Const<'C'>], Mapping> - -Assert, [['C', 'B', 'A'], ' ']>() - diff --git a/test/__tests__/static/token.ts b/test/__tests__/static/token.ts deleted file mode 100644 index b4aff90..0000000 --- a/test/__tests__/static/token.ts +++ /dev/null @@ -1,354 +0,0 @@ -import { Static } from '@sinclair/parsebox' - -function Assert(): void {} - -// ------------------------------------------------------------------ -// Const: Empty -// ------------------------------------------------------------------ -Assert, ['', '']>() -Assert, ['', 'A']>() -Assert, ['', ' A']>() - -// ------------------------------------------------------------------ -// Const: Single-Char -// ------------------------------------------------------------------ -Assert, ['A', '']>() -Assert, ['A', ' ']>() -Assert, ['A', 'A']>() -Assert, ['A', 'A ']>() - -// ------------------------------------------------------------------ -// Const: Multi-Char -// ------------------------------------------------------------------ -Assert, ['AB', '']>() -Assert, ['AB', ' ']>() -Assert, ['AB', 'A']>() -Assert, ['AB', 'A ']>() - -// ------------------------------------------------------------------ -// Const: Single-Char -> Ignore-Whitespace -// ------------------------------------------------------------------ -Assert, ['A', '']>() -Assert, ['A', ' ']>() -Assert, ['A', 'A']>() -Assert, ['A', 'A ']>() -Assert, ['A', 'A ']>() -Assert, ['A', 'A ']>() -Assert, ['A', 'A ']>() -Assert, ['A', 'A ']>() - -// ------------------------------------------------------------------ -// Const: Multi-Char -> Ignore-Whitespace -// ------------------------------------------------------------------ -Assert, ['AB', '']>() -Assert, ['AB', ' ']>() -Assert, ['AB', 'A']>() -Assert, ['AB', 'A ']>() -Assert, ['AB', 'A ']>() -Assert, ['AB', 'A ']>() -Assert, ['AB', 'A ']>() -Assert, ['AB', 'A ']>() - -// ------------------------------------------------------------------ -// Const: Single-Whitespace -// ------------------------------------------------------------------ -Assert, []>() -Assert, [' ', '']>() -Assert, [' ', 'A']>() -Assert, [' ', 'A ']>() -Assert, [' ', 'AA']>() -Assert, [' ', 'AA ']>() - -// ------------------------------------------------------------------ -// Const: Multi-Whitespace -// ------------------------------------------------------------------ -Assert, []>() -Assert, []>() -Assert, [' ', 'A']>() -Assert, [' ', 'A ']>() -Assert, [' ', 'AA']>() -Assert, [' ', 'AA ']>() - -// ------------------------------------------------------------------ -// Const: Newline -// ------------------------------------------------------------------ -Assert, []>() -Assert, []>() -Assert, ['\n', 'A']>() -Assert, ['\n', 'A ']>() -Assert, ['\n', 'AA']>() -Assert, ['\n', 'AA ']>() - -// ------------------------------------------------------------------ -// Const: Newline-Single-Whitespace -// ------------------------------------------------------------------ -Assert, []>() -Assert, []>() -Assert, []>() -Assert, []>() -Assert, []>() -Assert, []>() -Assert, ['\n ', 'A']>() -Assert, ['\n ', 'A ']>() -Assert, ['\n ', 'AA']>() -Assert, ['\n ', 'AA ']>() - -// ------------------------------------------------------------------ -// Const: Newline-Multi-Whitespace -// ------------------------------------------------------------------ -Assert, []>() -Assert, []>() -Assert, []>() -Assert, []>() -Assert, []>() -Assert, []>() -Assert, ['\n ', 'A']>() -Assert, ['\n ', 'A ']>() -Assert, ['\n ', 'AA']>() -Assert, ['\n ', 'AA ']>() - -// ------------------------------------------------------------------ -// Until: Empty -// ------------------------------------------------------------------ -Assert, []> -Assert, ['', 'A']> -Assert, ['', ' A']> - -// ------------------------------------------------------------------ -// Until: Single-Char -// ------------------------------------------------------------------ -Assert, ['', 'A']> -Assert, ['', 'A ']> -Assert, ['', 'AA']> -Assert, ['', 'AA ']> - -// ------------------------------------------------------------------ -// Until: Multi-Char -// ------------------------------------------------------------------ -Assert, ['', 'AB']> -Assert, ['', 'AB ']> -Assert, ['', 'ABA']> -Assert, ['', 'ABA ']> - -// ------------------------------------------------------------------ -// Until: Single-Char -> Ignore-Whitespace -// ------------------------------------------------------------------ -Assert, [' ', 'A']> -Assert, [' ', 'A ']> -Assert, [' ', 'AA']> -Assert, [' ', 'AA ']> -Assert, ['\n', 'AA ']> -Assert, [' \n', 'AA ']> -Assert, ['\n ', 'AA ']> -Assert, [' \n ', 'AA ']> - -// ------------------------------------------------------------------ -// Until: Multi-Char -> Ignore-Whitespace -// ------------------------------------------------------------------ -Assert, [' ', 'AB']> -Assert, [' ', 'AB ']> -Assert, [' ', 'ABA']> -Assert, [' ', 'ABA ']> -Assert, ['\n', 'ABA ']> -Assert, [' \n', 'ABA ']> -Assert, ['\n ', 'ABA ']> -Assert, [' \n ', 'ABA ']> - -// ------------------------------------------------------------------ -// Until: Single-Whitespace -// ------------------------------------------------------------------ -Assert, []> -Assert, ['', ' ']> -Assert, ['', ' A']> -Assert, ['', ' A ']> -Assert, ['', ' AA']> -Assert, ['', ' AA ']> - -// ------------------------------------------------------------------ -// Until: Multi-Whitespace -// ------------------------------------------------------------------ -Assert, []> -Assert, []> -Assert, ['', ' A']> -Assert, ['', ' A ']> -Assert, ['', ' AA']> -Assert, ['', ' AA ']> - -// ------------------------------------------------------------------ -// Until: Newline -// ------------------------------------------------------------------ -Assert, []> -Assert, []> -Assert, ['', '\nA']> -Assert, [' ', '\nA ']> -Assert, [' ', '\nAA']> -Assert, [' ', '\nAA ']> - -// ------------------------------------------------------------------ -// Until: Newline-Single-Whitespace -// ------------------------------------------------------------------ -Assert, []> -Assert, []> -Assert, []> -Assert, []> -Assert, []> -Assert, []> -Assert, ['', '\n A']> -Assert, [' ', '\n A ']> -Assert, [' ', '\n AA']> -Assert, [' ', '\n AA ']> - -// ------------------------------------------------------------------ -// Until: Newline-Multi-Whitespace -// ------------------------------------------------------------------ -Assert, []> -Assert, []> -Assert, []> -Assert, []> -Assert, []> -Assert, []> -Assert, ['', '\n A']> -Assert, [' ', '\n A ']> -Assert, [' ', '\n AA']> -Assert, [' ', '\n AA ']> - -// ------------------------------------------------------------------ -// Until: Multi Sentinal Test -// ------------------------------------------------------------------ -Assert, []> -Assert, ['', 'A']> -Assert, ['', 'B']> -Assert, ['', 'AB']> -Assert, ['', 'BA']> -Assert, [' ', 'AB']> -Assert, [' ', 'BA']> -Assert, [' ', ' BA']> -Assert, [' ', 'BA']> -Assert, [' ', 'AB']> -Assert, [' ', 'BA']> -Assert, [' ', 'BA']> -Assert, [' ', ' BA']> - - -// ------------------------------------------------------------------ -// UntilNonEmpty: Empty -// ------------------------------------------------------------------ -Assert, []> -Assert, []> -Assert, []> - -// ------------------------------------------------------------------ -// UntilNonEmpty: Single-Char -// ------------------------------------------------------------------ -Assert, []> -Assert, []> -Assert, []> -Assert, []> - -// ------------------------------------------------------------------ -// UntilNonEmpty: Multi-Char -// ------------------------------------------------------------------ -Assert, []> -Assert, []> -Assert, []> -Assert, []> - -// ------------------------------------------------------------------ -// UntilNonEmpty: Single-Char -> Ignore-Whitespace -// ------------------------------------------------------------------ -Assert, [' ', 'A']> -Assert, [' ', 'A ']> -Assert, [' ', 'AA']> -Assert, [' ', 'AA ']> -Assert, ['\n', 'AA ']> -Assert, [' \n', 'AA ']> -Assert, ['\n ', 'AA ']> -Assert, [' \n ', 'AA ']> - -// ------------------------------------------------------------------ -// UntilNonEmpty: Multi-Char -> Ignore-Whitespace -// ------------------------------------------------------------------ -Assert, [' ', 'AB']> -Assert, [' ', 'AB ']> -Assert, [' ', 'ABA']> -Assert, [' ', 'ABA ']> -Assert, ['\n', 'ABA ']> -Assert, [' \n', 'ABA ']> -Assert, ['\n ', 'ABA ']> -Assert, [' \n ', 'ABA ']> - -// ------------------------------------------------------------------ -// UntilNonEmpty: Single-Whitespace -// ------------------------------------------------------------------ -Assert, []> -Assert, []> -Assert, []> -Assert, []> -Assert, []> -Assert, []> - -// ------------------------------------------------------------------ -// UntilNonEmpty: Multi-Whitespace -// ------------------------------------------------------------------ -Assert, []> -Assert, []> -Assert, []> -Assert, []> -Assert, []> -Assert, []> - -// ------------------------------------------------------------------ -// UntilNonEmpty: Newline -// ------------------------------------------------------------------ -Assert, []> -Assert, []> -Assert, []> -Assert, [' ', '\nA ']> -Assert, [' ', '\nAA']> -Assert, [' ', '\nAA ']> - -// ------------------------------------------------------------------ -// UntilNonEmpty: Newline-Single-Whitespace -// ------------------------------------------------------------------ -Assert, []> -Assert, []> -Assert, []> -Assert, []> -Assert, []> -Assert, []> -Assert, []> -Assert, [' ', '\n A ']> -Assert, [' ', '\n AA']> -Assert, [' ', '\n AA ']> - -// ------------------------------------------------------------------ -// UntilNonEmpty: Newline-Multi-Whitespace -// ------------------------------------------------------------------ -Assert, []> -Assert, []> -Assert, []> -Assert, []> -Assert, []> -Assert, []> -Assert, []> -Assert, [' ', '\n A ']> -Assert, [' ', '\n AA']> -Assert, [' ', '\n AA ']> - -// ------------------------------------------------------------------ -// UntilNonEmpty: Multi Sentinal Test -// ------------------------------------------------------------------ -Assert, []> -Assert, []> -Assert, []> -Assert, []> -Assert, []> -Assert, [' ', 'AB']> -Assert, [' ', 'BA']> -Assert, [' ', ' BA']> -Assert, [' ', 'BA']> -Assert, [' ', 'AB']> -Assert, [' ', 'BA']> -Assert, [' ', 'BA']> -Assert, [' ', ' BA']> - diff --git a/test/common/assert.ts b/test/common/assert.ts new file mode 100644 index 0000000..b5049c1 --- /dev/null +++ b/test/common/assert.ts @@ -0,0 +1,47 @@ +import * as assert from 'node:assert' + +// ------------------------------------------------------------------ +// Runtime +// ------------------------------------------------------------------ +export type Test = (name: string, callback: (context: Deno.TestContext) => void) => any + +export function Context(context: string): Test { + return (name: string, callback: (context: Deno.TestContext) => void) => { + Deno.test(`${context}: ${name}`, callback) + } +} +export function HasPropertyKey(value: unknown, key: K): asserts value is Record { + if (typeof value === 'object' && value !== null && key in value) return + throw new Error(`Expected value to have property '${key as string}'`) +} +export function NotHasPropertyKey(value: unknown, key: K): asserts value is Record { + if (typeof value === 'object' && value !== null && !(key in value)) return + throw new Error(`Expected value not to have property '${key as string}'`) +} +export function IsTrue(value: boolean): asserts value is true { + return assert.strictEqual(value, true) +} +export function IsFalse(value: boolean): asserts value is false { + return assert.strictEqual(value, false) +} +export function IsEqual(actual: unknown, expect: unknown) { + if (actual instanceof Uint8Array && expect instanceof Uint8Array) { + assert.equal(actual.length, expect.length) + for (let i = 0; i < actual.length; i++) assert.equal(actual[i], expect[i]) + } + return assert.deepStrictEqual(actual, expect) +} +export function Throws(callback: Function) { + try { + callback() + } catch { + return + } + throw Error('Expected throw') +} +// ------------------------------------------------------------------ +// IsExact +// ------------------------------------------------------------------ +export function IsExact(left: Left, right: Right): void { + IsEqual(left, right) +} diff --git a/test/common/index.ts b/test/common/index.ts new file mode 100644 index 0000000..997848d --- /dev/null +++ b/test/common/index.ts @@ -0,0 +1 @@ +export * as Assert from './assert.ts' diff --git a/test/parsebox/build/json.ts b/test/parsebox/build/json.ts new file mode 100644 index 0000000..746f1bf --- /dev/null +++ b/test/parsebox/build/json.ts @@ -0,0 +1,131 @@ +/*-------------------------------------------------------------------------- + +ParseBox + +The MIT License (MIT) + +Copyright (c) 2024-2025 Haydn Paterson + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +---------------------------------------------------------------------------*/ + +import { Runtime } from '@sinclair/parsebox' + +// ----------------------------------------------------------------------- +// Json +// ----------------------------------------------------------------------- +const Json = Runtime.Union([ + Runtime.Ref('Number'), + Runtime.Ref('Boolean'), + Runtime.Ref('String'), + Runtime.Ref('Null'), + Runtime.Ref('Object'), + Runtime.Ref('Array'), +]) +// ----------------------------------------------------------------------- +// Number +// ----------------------------------------------------------------------- +const Number = Runtime.Number() +// ----------------------------------------------------------------------- +// String +// ----------------------------------------------------------------------- +const String = Runtime.String(['"']) +// ----------------------------------------------------------------------- +// Boolean +// ----------------------------------------------------------------------- +const Boolean = Runtime.Union([ + Runtime.Const('true'), + Runtime.Const('false'), +]) + +// ----------------------------------------------------------------------- +// Null +// ----------------------------------------------------------------------- +const Null = Runtime.Const('null') +// ----------------------------------------------------------------------- +// Key +// ----------------------------------------------------------------------- +const Key = Runtime.Union([Runtime.String(['"'])]) +// ----------------------------------------------------------------------- +// Property +// ----------------------------------------------------------------------- +const Property = Runtime.Tuple([Runtime.Ref('Key'), Runtime.Const(':'), Runtime.Ref('Json')]) +// ----------------------------------------------------------------------- +// Properties +// ----------------------------------------------------------------------- +const Properties = Runtime.Union([ + Runtime.Tuple([Runtime.Ref('Property'), Runtime.Const(','), Runtime.Ref('Properties')]), + Runtime.Tuple([Runtime.Ref('Property')]), + Runtime.Tuple([]), +]) +// ----------------------------------------------------------------------- +// Object +// ----------------------------------------------------------------------- +const _Object = Runtime.Tuple([ + Runtime.Const('{'), + Runtime.Ref('Properties'), + Runtime.Const('}'), +]) +// ----------------------------------------------------------------------- +// Elemments +// ----------------------------------------------------------------------- +const Elements = Runtime.Union([ + Runtime.Tuple([Runtime.Ref('Json'), Runtime.Const(','), Runtime.Ref('Elements')]), + Runtime.Tuple([Runtime.Ref('Json')]), + Runtime.Tuple([]), +]) +// ----------------------------------------------------------------------- +// Array +// ----------------------------------------------------------------------- +const Array = Runtime.Tuple([Runtime.Const('['), Runtime.Ref('Elements'), Runtime.Const(']')]) + +// ----------------------------------------------------------------------- +// Coverage +// +// These are only here to test there are no errors running these +// combinators through the build process. +// +// ----------------------------------------------------------------------- +const Coverage = Runtime.Union([ + Runtime.BigInt(), + Runtime.Array(Runtime.String(['"'])), + Runtime.Ident(), + Runtime.Integer(), + Runtime.Until(['x']), + Runtime.Until_1(['x']), + Runtime.Union([]), + Runtime.Optional(Runtime.Ident()), +]) +export const JsonModule = new Runtime.Module({ + // Coverage + Coverage, + // Json Core + Number, + Boolean, + String, + Null, + Key, + Property, + Properties, + Object: _Object, + Elements, + Array, + Json, +}) diff --git a/test/parsebox/build/project.ts b/test/parsebox/build/project.ts new file mode 100644 index 0000000..25851c7 --- /dev/null +++ b/test/parsebox/build/project.ts @@ -0,0 +1,12 @@ +import { Build } from '@sinclair/parsebox' +import { Assert } from 'test' + +import { JsonModule } from './json.ts' + +const Test = Assert.Context('Build.Project') + +Test('Should Build 1', () => { + const R = Build.Project(JsonModule) + Assert.IsTrue(typeof R.mapping === 'string') + Assert.IsTrue(typeof R.parser === 'string') +}) diff --git a/test/parsebox/guard/array.ts b/test/parsebox/guard/array.ts new file mode 100644 index 0000000..2fa5fdf --- /dev/null +++ b/test/parsebox/guard/array.ts @@ -0,0 +1,9 @@ +// deno-lint-ignore-file + +import { Runtime } from '@sinclair/parsebox' +import { Assert } from 'test' + +const Test = Assert.Context('Guard.IsArray') +// @ts-ignore +Test('Should Guard 1', () => Assert.IsFalse(Runtime.IsArray(Runtime.Array(1)))) +Test('Should Guard 2', () => Assert.IsTrue(Runtime.IsArray(Runtime.Array(Runtime.Const('A'))))) diff --git a/test/parsebox/guard/bigint.ts b/test/parsebox/guard/bigint.ts new file mode 100644 index 0000000..b92d56e --- /dev/null +++ b/test/parsebox/guard/bigint.ts @@ -0,0 +1,10 @@ +// deno-lint-ignore-file + +import { Runtime } from '@sinclair/parsebox' +import { Assert } from 'test' + +const Test = Assert.Context('Guard.IsBigInt') + +// @ts-ignore +Test('Should Guard 1', () => Assert.IsFalse(Runtime.IsBigInt(Runtime.Const('A')))) +Test('Should Guard 2', () => Assert.IsTrue(Runtime.IsBigInt(Runtime.BigInt()))) diff --git a/test/parsebox/guard/const.ts b/test/parsebox/guard/const.ts new file mode 100644 index 0000000..44e7e4a --- /dev/null +++ b/test/parsebox/guard/const.ts @@ -0,0 +1,11 @@ +// deno-lint-ignore-file + +import { Runtime } from '@sinclair/parsebox' +import { Assert } from 'test' + +const Test = Assert.Context('Guard.IsConst') + +// @ts-ignore +Test('Should Guard 1', () => Assert.IsFalse(Runtime.IsConst(Runtime.Const(undefined)))) + +Test('Should Guard 2', () => Assert.IsTrue(Runtime.IsConst(Runtime.Const('A')))) diff --git a/test/parsebox/guard/ident.ts b/test/parsebox/guard/ident.ts new file mode 100644 index 0000000..723ac6b --- /dev/null +++ b/test/parsebox/guard/ident.ts @@ -0,0 +1,11 @@ +// deno-lint-ignore-file + +import { Runtime } from '@sinclair/parsebox' +import { Assert } from 'test' + +const Test = Assert.Context('Guard.IsIdent') + +// @ts-ignore +Test('Should Guard 1', () => Assert.IsFalse(Runtime.IsIdent(Runtime.Const('A')))) + +Test('Should Guard 2', () => Assert.IsTrue(Runtime.IsIdent(Runtime.Ident()))) diff --git a/test/parsebox/guard/integer.ts b/test/parsebox/guard/integer.ts new file mode 100644 index 0000000..9622bcc --- /dev/null +++ b/test/parsebox/guard/integer.ts @@ -0,0 +1,10 @@ +// deno-lint-ignore-file + +import { Runtime } from '@sinclair/parsebox' +import { Assert } from 'test' + +const Test = Assert.Context('Guard.IsInteger') + +// @ts-ignore +Test('Should Guard 1', () => Assert.IsFalse(Runtime.IsInteger(Runtime.Const('A')))) +Test('Should Guard 2', () => Assert.IsTrue(Runtime.IsInteger(Runtime.Integer()))) diff --git a/test/parsebox/guard/number.ts b/test/parsebox/guard/number.ts new file mode 100644 index 0000000..a190a62 --- /dev/null +++ b/test/parsebox/guard/number.ts @@ -0,0 +1,10 @@ +// deno-lint-ignore-file + +import { Runtime } from '@sinclair/parsebox' +import { Assert } from 'test' + +const Test = Assert.Context('Guard.IsNumber') + +// @ts-ignore +Test('Should Guard 1', () => Assert.IsFalse(Runtime.IsNumber(Runtime.Const('A')))) +Test('Should Guard 2', () => Assert.IsTrue(Runtime.IsNumber(Runtime.Number()))) diff --git a/test/parsebox/guard/optional.ts b/test/parsebox/guard/optional.ts new file mode 100644 index 0000000..51ff51b --- /dev/null +++ b/test/parsebox/guard/optional.ts @@ -0,0 +1,10 @@ +// deno-lint-ignore-file + +import { Runtime } from '@sinclair/parsebox' +import { Assert } from 'test' + +const Test = Assert.Context('Guard.IsOptional') + +// @ts-ignore +Test('Should Guard 1', () => Assert.IsFalse(Runtime.IsOptional(Runtime.Optional(1)))) +Test('Should Guard 2', () => Assert.IsTrue(Runtime.IsOptional(Runtime.Optional(Runtime.Const('A'))))) diff --git a/test/parsebox/guard/ref.ts b/test/parsebox/guard/ref.ts new file mode 100644 index 0000000..e1997e0 --- /dev/null +++ b/test/parsebox/guard/ref.ts @@ -0,0 +1,10 @@ +// deno-lint-ignore-file + +import { Runtime } from '@sinclair/parsebox' +import { Assert } from 'test' + +const Test = Assert.Context('Guard.IsRef') + +// @ts-ignore +Test('Should Guard 1', () => Assert.IsFalse(Runtime.IsRef(Runtime.Ref(1)))) +Test('Should Guard 2', () => Assert.IsTrue(Runtime.IsRef(Runtime.Ref('A')))) diff --git a/test/parsebox/guard/string.ts b/test/parsebox/guard/string.ts new file mode 100644 index 0000000..a50a8af --- /dev/null +++ b/test/parsebox/guard/string.ts @@ -0,0 +1,11 @@ +// deno-lint-ignore-file + +import { Runtime } from '@sinclair/parsebox' +import { Assert } from 'test' + +const Test = Assert.Context('Guard.IsString') + +Test('Should Guard 1', () => Assert.IsFalse(Runtime.IsString(Runtime.Const('A')))) +// @ts-ignore +Test('Should Guard 2', () => Assert.IsFalse(Runtime.IsString(Runtime.String([1])))) +Test('Should Guard 3', () => Assert.IsTrue(Runtime.IsString(Runtime.String(['"'])))) diff --git a/test/parsebox/guard/tuple.ts b/test/parsebox/guard/tuple.ts new file mode 100644 index 0000000..27bf23e --- /dev/null +++ b/test/parsebox/guard/tuple.ts @@ -0,0 +1,10 @@ +// deno-lint-ignore-file + +import { Runtime } from '@sinclair/parsebox' +import { Assert } from 'test' + +const Test = Assert.Context('Guard.IsTuple') + +// @ts-ignore +Test('Should Guard 1', () => Assert.IsFalse(Runtime.IsTuple(Runtime.Const('A')))) +Test('Should Guard 2', () => Assert.IsTrue(Runtime.IsTuple(Runtime.Tuple([Runtime.Const('A')])))) diff --git a/test/parsebox/guard/union.ts b/test/parsebox/guard/union.ts new file mode 100644 index 0000000..89d169f --- /dev/null +++ b/test/parsebox/guard/union.ts @@ -0,0 +1,10 @@ +// deno-lint-ignore-file + +import { Runtime } from '@sinclair/parsebox' +import { Assert } from 'test' + +const Test = Assert.Context('Guard.IsUnion') + +// @ts-ignore +Test('Should Guard 1', () => Assert.IsFalse(Runtime.IsUnion(Runtime.Const('A')))) +Test('Should Guard 2', () => Assert.IsTrue(Runtime.IsUnion(Runtime.Union([Runtime.Const('A')])))) diff --git a/test/parsebox/guard/until.ts b/test/parsebox/guard/until.ts new file mode 100644 index 0000000..d87f148 --- /dev/null +++ b/test/parsebox/guard/until.ts @@ -0,0 +1,10 @@ +// deno-lint-ignore-file + +import { Runtime } from '@sinclair/parsebox' +import { Assert } from 'test' + +const Test = Assert.Context('Guard.IsUntil') + +// @ts-ignore +Test('Should Guard 1', () => Assert.IsFalse(Runtime.IsUntil(Runtime.Until_1(['A'])))) +Test('Should Guard 2', () => Assert.IsTrue(Runtime.IsUntil(Runtime.Until(['A'])))) diff --git a/test/parsebox/guard/until_1.ts b/test/parsebox/guard/until_1.ts new file mode 100644 index 0000000..82ac902 --- /dev/null +++ b/test/parsebox/guard/until_1.ts @@ -0,0 +1,10 @@ +// deno-lint-ignore-file + +import { Runtime } from '@sinclair/parsebox' +import { Assert } from 'test' + +const Test = Assert.Context('Guard.IsUntil_1') + +// @ts-ignore +Test('Should Guard 1', () => Assert.IsFalse(Runtime.IsUntil_1(Runtime.Until(['A'])))) +Test('Should Guard 2', () => Assert.IsTrue(Runtime.IsUntil_1(Runtime.Until_1(['A'])))) diff --git a/test/parsebox/runtime/array.ts b/test/parsebox/runtime/array.ts new file mode 100644 index 0000000..74ee12e --- /dev/null +++ b/test/parsebox/runtime/array.ts @@ -0,0 +1,11 @@ +import { Runtime } from '@sinclair/parsebox' +import { Assert } from 'test' + +const Test = Assert.Context('Runtime.Parse.Array') + +Test('Should Array 1', () => Assert.IsEqual(Runtime.Parse(Runtime.Array(Runtime.Const('A')), ''), [[], ''])) +Test('Should Array 2', () => Assert.IsEqual(Runtime.Parse(Runtime.Array(Runtime.Const('A')), 'AB'), [['A'], 'B'])) +Test('Should Array 3', () => Assert.IsEqual(Runtime.Parse(Runtime.Array(Runtime.Const('A')), 'AAB'), [['A', 'A'], 'B'])) +Test('Should Array 4', () => Assert.IsEqual(Runtime.Parse(Runtime.Array(Runtime.Const('AA')), 'AAB'), [['AA'], 'B'])) +Test('Should Array 5', () => Assert.IsEqual(Runtime.Parse(Runtime.Array(Runtime.Const('AA')), 'AAAB'), [['AA'], 'AB'])) +Test('Should Array 6', () => Assert.IsEqual(Runtime.Parse(Runtime.Array(Runtime.Const('AA')), 'B'), [[], 'B'])) diff --git a/test/parsebox/runtime/bigint.ts b/test/parsebox/runtime/bigint.ts new file mode 100644 index 0000000..0aaf4e2 --- /dev/null +++ b/test/parsebox/runtime/bigint.ts @@ -0,0 +1,10 @@ +import { Runtime } from '@sinclair/parsebox' +import { Assert } from 'test' + +const Test = Assert.Context('Runtime.Parse.BigInt') + +Test('Should BigInt 1', () => Assert.IsEqual(Runtime.Parse(Runtime.BigInt(), '0n'), ['0', ''])) +Test('Should BigInt 2', () => Assert.IsEqual(Runtime.Parse(Runtime.BigInt(), '00n'), [])) +Test('Should BigInt 3', () => Assert.IsEqual(Runtime.Parse(Runtime.BigInt(), '10n'), ['10', ''])) +Test('Should BigInt 4', () => Assert.IsEqual(Runtime.Parse(Runtime.BigInt(), ' 0n'), ['0', ''])) +Test('Should BigInt 5', () => Assert.IsEqual(Runtime.Parse(Runtime.BigInt(), '0n '), ['0', ' '])) diff --git a/test/parsebox/runtime/const.ts b/test/parsebox/runtime/const.ts new file mode 100644 index 0000000..31a3ae6 --- /dev/null +++ b/test/parsebox/runtime/const.ts @@ -0,0 +1,9 @@ +import { Runtime } from '@sinclair/parsebox' +import { Assert } from 'test' + +const Test = Assert.Context('Runtime.Parse.Const') + +Test('Should Const 1', () => Assert.IsEqual(Runtime.Parse(Runtime.Const('A'), ''), [])) +Test('Should Const 2', () => Assert.IsEqual(Runtime.Parse(Runtime.Const('A'), 'A'), ['A', ''])) +Test('Should Const 3', () => Assert.IsEqual(Runtime.Parse(Runtime.Const('A'), ' A'), ['A', ''])) +Test('Should Const 4', () => Assert.IsEqual(Runtime.Parse(Runtime.Const('A'), ' A '), ['A', ' '])) diff --git a/test/parsebox/runtime/ident.ts b/test/parsebox/runtime/ident.ts new file mode 100644 index 0000000..5f1e5cb --- /dev/null +++ b/test/parsebox/runtime/ident.ts @@ -0,0 +1,24 @@ +import { Runtime } from '@sinclair/parsebox' +import { Assert } from 'test' + +const Test = Assert.Context('Runtime.Parse.Ident') +Test('Should Ident 1', () => Assert.IsEqual(Runtime.Parse(Runtime.Ident(), ''), [])) +Test('Should Ident 2', () => Assert.IsEqual(Runtime.Parse(Runtime.Ident(), '0'), [])) +Test('Should Ident 3', () => Assert.IsEqual(Runtime.Parse(Runtime.Ident(), '#'), [])) +Test('Should Ident 4', () => Assert.IsEqual(Runtime.Parse(Runtime.Ident(), '_'), ['_', ''])) +Test('Should Ident 5', () => Assert.IsEqual(Runtime.Parse(Runtime.Ident(), ' _'), ['_', ''])) +Test('Should Ident 6', () => Assert.IsEqual(Runtime.Parse(Runtime.Ident(), '_ '), ['_', ' '])) +Test('Should Ident 7', () => Assert.IsEqual(Runtime.Parse(Runtime.Ident(), ' _ '), ['_', ' '])) +Test('Should Ident 8', () => Assert.IsEqual(Runtime.Parse(Runtime.Ident(), '$'), ['$', ''])) +Test('Should Ident 9', () => Assert.IsEqual(Runtime.Parse(Runtime.Ident(), ' $'), ['$', ''])) +Test('Should Ident 10', () => Assert.IsEqual(Runtime.Parse(Runtime.Ident(), '$ '), ['$', ' '])) +Test('Should Ident 11', () => Assert.IsEqual(Runtime.Parse(Runtime.Ident(), ' $ '), ['$', ' '])) +Test('Should Ident 12', () => Assert.IsEqual(Runtime.Parse(Runtime.Ident(), 'A'), ['A', ''])) +Test('Should Ident 13', () => Assert.IsEqual(Runtime.Parse(Runtime.Ident(), ' A'), ['A', ''])) +Test('Should Ident 14', () => Assert.IsEqual(Runtime.Parse(Runtime.Ident(), 'A '), ['A', ' '])) +Test('Should Ident 15', () => Assert.IsEqual(Runtime.Parse(Runtime.Ident(), ' A '), ['A', ' '])) +Test('Should Ident 16', () => Assert.IsEqual(Runtime.Parse(Runtime.Ident(), 'A1'), ['A1', ''])) +Test('Should Ident 17', () => Assert.IsEqual(Runtime.Parse(Runtime.Ident(), ' A1'), ['A1', ''])) +Test('Should Ident 18', () => Assert.IsEqual(Runtime.Parse(Runtime.Ident(), ' A1'), ['A1', ''])) +Test('Should Ident 19', () => Assert.IsEqual(Runtime.Parse(Runtime.Ident(), 'A1 '), ['A1', ' '])) +Test('Should Ident 20', () => Assert.IsEqual(Runtime.Parse(Runtime.Ident(), ' A1 '), ['A1', ' '])) diff --git a/test/parsebox/runtime/integer.ts b/test/parsebox/runtime/integer.ts new file mode 100644 index 0000000..761bb57 --- /dev/null +++ b/test/parsebox/runtime/integer.ts @@ -0,0 +1,9 @@ +import { Runtime } from '@sinclair/parsebox' +import { Assert } from 'test' + +const Test = Assert.Context('Runtime.Parse.Integer') + +Test('Should Integer 1', () => Assert.IsEqual(Runtime.Parse(Runtime.Integer(), '0'), ['0', ''])) +Test('Should Integer 2', () => Assert.IsEqual(Runtime.Parse(Runtime.Integer(), '00'), ['0', '0'])) +Test('Should Integer 3', () => Assert.IsEqual(Runtime.Parse(Runtime.Integer(), '10'), ['10', ''])) +Test('Should Integer 4', () => Assert.IsEqual(Runtime.Parse(Runtime.Integer(), ' 0'), ['0', ''])) diff --git a/test/parsebox/runtime/number.ts b/test/parsebox/runtime/number.ts new file mode 100644 index 0000000..c7d2d9f --- /dev/null +++ b/test/parsebox/runtime/number.ts @@ -0,0 +1,50 @@ +import { Runtime } from '@sinclair/parsebox' +import { Assert } from 'test' + +const Test = Assert.Context('Runtime.Parse.Integer') + +Test('Should Number 1', () => Assert.IsEqual(Runtime.Parse(Runtime.Number(), ''), [])) +Test('Should Number 2', () => Assert.IsEqual(Runtime.Parse(Runtime.Number(), '01'), ['0', '1'])) +Test('Should Number 3', () => Assert.IsEqual(Runtime.Parse(Runtime.Number(), ' 01'), ['0', '1'])) +Test('Should Number 4', () => Assert.IsEqual(Runtime.Parse(Runtime.Number(), '01 '), ['0', '1 '])) +Test('Should Number 5', () => Assert.IsEqual(Runtime.Parse(Runtime.Number(), ' 01 '), ['0', '1 '])) +Test('Should Number 6', () => Assert.IsEqual(Runtime.Parse(Runtime.Number(), '0'), ['0', ''])) +Test('Should Number 7', () => Assert.IsEqual(Runtime.Parse(Runtime.Number(), '0 '), ['0', ' '])) +Test('Should Number 8', () => Assert.IsEqual(Runtime.Parse(Runtime.Number(), ' 0'), ['0', ''])) +Test('Should Number 9', () => Assert.IsEqual(Runtime.Parse(Runtime.Number(), ' 0 '), ['0', ' '])) +Test('Should Number 10', () => Assert.IsEqual(Runtime.Parse(Runtime.Number(), '-0'), ['-0', ''])) +Test('Should Number 11', () => Assert.IsEqual(Runtime.Parse(Runtime.Number(), '-0 '), ['-0', ' '])) +Test('Should Number 12', () => Assert.IsEqual(Runtime.Parse(Runtime.Number(), ' -0'), ['-0', ''])) +Test('Should Number 13', () => Assert.IsEqual(Runtime.Parse(Runtime.Number(), ' -0 '), ['-0', ' '])) +Test('Should Number 14', () => Assert.IsEqual(Runtime.Parse(Runtime.Number(), '100'), ['100', ''])) +Test('Should Number 15', () => Assert.IsEqual(Runtime.Parse(Runtime.Number(), '100 '), ['100', ' '])) +Test('Should Number 16', () => Assert.IsEqual(Runtime.Parse(Runtime.Number(), ' 100'), ['100', ''])) +Test('Should Number 17', () => Assert.IsEqual(Runtime.Parse(Runtime.Number(), ' 100 '), ['100', ' '])) +Test('Should Number 18', () => Assert.IsEqual(Runtime.Parse(Runtime.Number(), '-100'), ['-100', ''])) +Test('Should Number 19', () => Assert.IsEqual(Runtime.Parse(Runtime.Number(), '-100 '), ['-100', ' '])) +Test('Should Number 20', () => Assert.IsEqual(Runtime.Parse(Runtime.Number(), ' -100'), ['-100', ''])) +Test('Should Number 21', () => Assert.IsEqual(Runtime.Parse(Runtime.Number(), ' -100 '), ['-100', ' '])) +Test('Should Number 22', () => Assert.IsEqual(Runtime.Parse(Runtime.Number(), '0.1'), ['0.1', ''])) +Test('Should Number 23', () => Assert.IsEqual(Runtime.Parse(Runtime.Number(), '0.1 '), ['0.1', ' '])) +Test('Should Number 24', () => Assert.IsEqual(Runtime.Parse(Runtime.Number(), ' 0.1'), ['0.1', ''])) +Test('Should Number 25', () => Assert.IsEqual(Runtime.Parse(Runtime.Number(), ' 0.1 '), ['0.1', ' '])) +Test('Should Number 26', () => Assert.IsEqual(Runtime.Parse(Runtime.Number(), '100.1'), ['100.1', ''])) +Test('Should Number 27', () => Assert.IsEqual(Runtime.Parse(Runtime.Number(), '100.1 '), ['100.1', ' '])) +Test('Should Number 28', () => Assert.IsEqual(Runtime.Parse(Runtime.Number(), ' 100.1'), ['100.1', ''])) +Test('Should Number 29', () => Assert.IsEqual(Runtime.Parse(Runtime.Number(), ' 100.1 '), ['100.1', ' '])) +Test('Should Number 30', () => Assert.IsEqual(Runtime.Parse(Runtime.Number(), '-100.1'), ['-100.1', ''])) +Test('Should Number 31', () => Assert.IsEqual(Runtime.Parse(Runtime.Number(), '-100.1 '), ['-100.1', ' '])) +Test('Should Number 32', () => Assert.IsEqual(Runtime.Parse(Runtime.Number(), ' -100.1'), ['-100.1', ''])) +Test('Should Number 33', () => Assert.IsEqual(Runtime.Parse(Runtime.Number(), ' -100.1 '), ['-100.1', ' '])) +Test('Should Number 34', () => Assert.IsEqual(Runtime.Parse(Runtime.Number(), '100.1.1'), ['100.1', '.1'])) +Test('Should Number 35', () => Assert.IsEqual(Runtime.Parse(Runtime.Number(), '100.1.1 '), ['100.1', '.1 '])) +Test('Should Number 36', () => Assert.IsEqual(Runtime.Parse(Runtime.Number(), ' 100.1.1'), ['100.1', '.1'])) +Test('Should Number 37', () => Assert.IsEqual(Runtime.Parse(Runtime.Number(), ' 100.1.1 '), ['100.1', '.1 '])) +Test('Should Number 38', () => Assert.IsEqual(Runtime.Parse(Runtime.Number(), '-.1'), ['-0.1', ''])) +Test('Should Number 39', () => Assert.IsEqual(Runtime.Parse(Runtime.Number(), '-.1 '), ['-0.1', ' '])) +Test('Should Number 40', () => Assert.IsEqual(Runtime.Parse(Runtime.Number(), ' -.1'), ['-0.1', ''])) +Test('Should Number 41', () => Assert.IsEqual(Runtime.Parse(Runtime.Number(), ' -.1 '), ['-0.1', ' '])) +Test('Should Number 42', () => Assert.IsEqual(Runtime.Parse(Runtime.Number(), '-0.1'), ['-0.1', ''])) +Test('Should Number 43', () => Assert.IsEqual(Runtime.Parse(Runtime.Number(), '-0.1 '), ['-0.1', ' '])) +Test('Should Number 44', () => Assert.IsEqual(Runtime.Parse(Runtime.Number(), ' -0.1'), ['-0.1', ''])) +Test('Should Number 45', () => Assert.IsEqual(Runtime.Parse(Runtime.Number(), ' -0.1 '), ['-0.1', ' '])) diff --git a/test/parsebox/runtime/optional.ts b/test/parsebox/runtime/optional.ts new file mode 100644 index 0000000..b161462 --- /dev/null +++ b/test/parsebox/runtime/optional.ts @@ -0,0 +1,9 @@ +import { Runtime } from '@sinclair/parsebox' +import { Assert } from 'test' + +const Test = Assert.Context('Runtime.Parse.Optional') + +Test('Should Optional 1', () => Assert.IsEqual(Runtime.Parse(Runtime.Optional(Runtime.Const('A')), ''), [[], ''])) +Test('Should Optional 2', () => Assert.IsEqual(Runtime.Parse(Runtime.Optional(Runtime.Const('A')), 'A'), [['A'], ''])) +Test('Should Optional 3', () => Assert.IsEqual(Runtime.Parse(Runtime.Optional(Runtime.Const('A')), 'AA'), [['A'], 'A'])) +Test('Should Optional 4', () => Assert.IsEqual(Runtime.Parse(Runtime.Optional(Runtime.Const('A')), 'B'), [[], 'B'])) diff --git a/test/index.ts b/test/parsebox/runtime/ref.ts similarity index 100% rename from test/index.ts rename to test/parsebox/runtime/ref.ts diff --git a/test/parsebox/runtime/string.ts b/test/parsebox/runtime/string.ts new file mode 100644 index 0000000..42ac650 --- /dev/null +++ b/test/parsebox/runtime/string.ts @@ -0,0 +1,10 @@ +import { Runtime } from '@sinclair/parsebox' +import { Assert } from 'test' + +const Test = Assert.Context('Runtime.Parse.String') + +Test('Should String 1', () => Assert.IsEqual(Runtime.Parse(Runtime.String([`'`, `"`]), ''), [])) +Test('Should String 2', () => Assert.IsEqual(Runtime.Parse(Runtime.String([`'`, `"`]), '"A"'), ['A', ''])) +Test('Should String 3', () => Assert.IsEqual(Runtime.Parse(Runtime.String([`'`, `"`]), ' "A"'), ['A', ''])) +Test('Should String 4', () => Assert.IsEqual(Runtime.Parse(Runtime.String([`'`, `"`]), '"A" '), ['A', ' '])) +Test('Should String 5', () => Assert.IsEqual(Runtime.Parse(Runtime.String([`'`, `"`]), ' "A" '), ['A', ' '])) diff --git a/test/parsebox/runtime/tuple.ts b/test/parsebox/runtime/tuple.ts new file mode 100644 index 0000000..502df28 --- /dev/null +++ b/test/parsebox/runtime/tuple.ts @@ -0,0 +1,13 @@ +import { Runtime } from '@sinclair/parsebox' +import { Assert } from 'test' + +const Test = Assert.Context('Runtime.Parse.Tuple') + +const Tuple = Runtime.Tuple([Runtime.Const('A'), Runtime.Const('B'), Runtime.Const('C')]) +Test('Should Tuple 1', () => Assert.IsEqual(Runtime.Parse(Tuple, ''), [])) +Test('Should Tuple 2', () => Assert.IsEqual(Runtime.Parse(Tuple, 'A'), [])) +Test('Should Tuple 3', () => Assert.IsEqual(Runtime.Parse(Tuple, 'A B C'), [['A', 'B', 'C'], ''])) +Test('Should Tuple 4', () => Assert.IsEqual(Runtime.Parse(Tuple, 'A B C '), [['A', 'B', 'C'], ' '])) +Test('Should Tuple 5', () => Assert.IsEqual(Runtime.Parse(Tuple, 'ABC'), [['A', 'B', 'C'], ''])) +Test('Should Tuple 6', () => Assert.IsEqual(Runtime.Parse(Tuple, ' ABC'), [['A', 'B', 'C'], ''])) +Test('Should Tuple 7', () => Assert.IsEqual(Runtime.Parse(Tuple, ' ABC '), [['A', 'B', 'C'], ' '])) diff --git a/test/parsebox/runtime/union.ts b/test/parsebox/runtime/union.ts new file mode 100644 index 0000000..2601fc3 --- /dev/null +++ b/test/parsebox/runtime/union.ts @@ -0,0 +1,17 @@ +import { Runtime } from '@sinclair/parsebox' +import { Assert } from 'test' + +const Test = Assert.Context('Runtime.Parse.Union') + +const Union = Runtime.Union([Runtime.Const('A'), Runtime.Const('B'), Runtime.Const('C')]) +Test('Should Union 1', () => Assert.IsEqual(Runtime.Parse(Union, ''), [])) +Test('Should Union 2', () => Assert.IsEqual(Runtime.Parse(Union, 'A B C'), ['A', ' B C'])) +Test('Should Union 3', () => Assert.IsEqual(Runtime.Parse(Union, 'A B C '), ['A', ' B C '])) +Test('Should Union 4', () => Assert.IsEqual(Runtime.Parse(Union, 'ABC'), ['A', 'BC'])) +Test('Should Union 5', () => Assert.IsEqual(Runtime.Parse(Union, ' ABC'), ['A', 'BC'])) +Test('Should Union 6', () => Assert.IsEqual(Runtime.Parse(Union, ' ABC '), ['A', 'BC '])) +Test('Should Union 7', () => Assert.IsEqual(Runtime.Parse(Union, 'B B C'), ['B', ' B C'])) +Test('Should Union 8', () => Assert.IsEqual(Runtime.Parse(Union, 'B B C '), ['B', ' B C '])) +Test('Should Union 9', () => Assert.IsEqual(Runtime.Parse(Union, 'BBC'), ['B', 'BC'])) +Test('Should Union 10', () => Assert.IsEqual(Runtime.Parse(Union, ' BBC'), ['B', 'BC'])) +Test('Should Union 11', () => Assert.IsEqual(Runtime.Parse(Union, ' BBC '), ['B', 'BC '])) diff --git a/test/parsebox/runtime/until.ts b/test/parsebox/runtime/until.ts new file mode 100644 index 0000000..3f3ad84 --- /dev/null +++ b/test/parsebox/runtime/until.ts @@ -0,0 +1,13 @@ +import { Runtime } from '@sinclair/parsebox' +import { Assert } from 'test' + +const Test = Assert.Context('Runtime.Parse.Until') + +Test('Should Until 1', () => Assert.IsEqual(Runtime.Parse(Runtime.Until(['A']), ''), [])) +Test('Should Until 2', () => Assert.IsEqual(Runtime.Parse(Runtime.Until(['A']), 'A'), ['', 'A'])) +Test('Should Until 3', () => Assert.IsEqual(Runtime.Parse(Runtime.Until(['A']), ' A'), [' ', 'A'])) +Test('Should Until 4', () => Assert.IsEqual(Runtime.Parse(Runtime.Until(['A']), ' A '), [' ', 'A '])) +Test('Should Until 5', () => Assert.IsEqual(Runtime.Parse(Runtime.Until(['A', 'B']), ''), [])) +Test('Should Until 6', () => Assert.IsEqual(Runtime.Parse(Runtime.Until(['A', 'B']), 'BA'), ['', 'BA'])) +Test('Should Until 7', () => Assert.IsEqual(Runtime.Parse(Runtime.Until(['A', 'B']), ' BA'), [' ', 'BA'])) +Test('Should Until 8', () => Assert.IsEqual(Runtime.Parse(Runtime.Until(['A', 'B']), ' BA '), [' ', 'BA '])) diff --git a/test/parsebox/runtime/until_1.ts b/test/parsebox/runtime/until_1.ts new file mode 100644 index 0000000..fa7d1b3 --- /dev/null +++ b/test/parsebox/runtime/until_1.ts @@ -0,0 +1,13 @@ +import { Runtime } from '@sinclair/parsebox' +import { Assert } from 'test' + +const Test = Assert.Context('Runtime.Parse.Until_1') + +Test('Should Until_1 1', () => Assert.IsEqual(Runtime.Parse(Runtime.Until_1(['A']), ''), [])) +Test('Should Until_1 2', () => Assert.IsEqual(Runtime.Parse(Runtime.Until_1(['A']), 'A'), [])) +Test('Should Until_1 3', () => Assert.IsEqual(Runtime.Parse(Runtime.Until_1(['A']), ' A'), [' ', 'A'])) +Test('Should Until_1 4', () => Assert.IsEqual(Runtime.Parse(Runtime.Until_1(['A']), ' A '), [' ', 'A '])) +Test('Should Until_1 5', () => Assert.IsEqual(Runtime.Parse(Runtime.Until_1(['A', 'B']), ''), [])) +Test('Should Until_1 6', () => Assert.IsEqual(Runtime.Parse(Runtime.Until_1(['A', 'B']), 'BA'), [])) +Test('Should Until_1 7', () => Assert.IsEqual(Runtime.Parse(Runtime.Until_1(['A', 'B']), ' BA'), [' ', 'BA'])) +Test('Should Until_1 8', () => Assert.IsEqual(Runtime.Parse(Runtime.Until_1(['A', 'B']), ' BA '), [' ', 'BA '])) diff --git a/test/parsebox/runtime/~mapping.ts b/test/parsebox/runtime/~mapping.ts new file mode 100644 index 0000000..bac8217 --- /dev/null +++ b/test/parsebox/runtime/~mapping.ts @@ -0,0 +1,9 @@ +import { Runtime } from '@sinclair/parsebox' +import { Assert } from 'test' + +const Test = Assert.Context('Runtime.Parse.Mapping') + +const Mapping = (_0: 'A', _1: 'B', _2: 'C') => [_2, _1, _0] as const +const Mapped = Runtime.Tuple([Runtime.Const('A'), Runtime.Const('B'), Runtime.Const('C')], (values) => Mapping(...values)) + +Test('Should Mapping 1', () => Assert.IsEqual(Runtime.Parse(Mapped, ' A B C '), [['C', 'B', 'A'], ' '])) diff --git a/test/parsebox/static/array.ts b/test/parsebox/static/array.ts new file mode 100644 index 0000000..73ddfa4 --- /dev/null +++ b/test/parsebox/static/array.ts @@ -0,0 +1,14 @@ +// deno-fmt-ignore-file + +import { Static } from '@sinclair/parsebox' +function Assert(): void {} + +// ------------------------------------------------------------------ +// Array +// ------------------------------------------------------------------ +Assert>, ''>, [[], '']>() +Assert>, 'AB'>, [['A'], 'B']>() +Assert>, 'AAB'>, [['A', 'A'], 'B']>() +Assert>, 'AAB'>, [['AA'], 'B']>() +Assert>, 'AAAB'>, [['AA'], 'AB']>() +Assert>, 'B'>, [[], 'B']>() \ No newline at end of file diff --git a/test/parsebox/static/bigint.ts b/test/parsebox/static/bigint.ts new file mode 100644 index 0000000..5fb369c --- /dev/null +++ b/test/parsebox/static/bigint.ts @@ -0,0 +1,11 @@ +// deno-fmt-ignore-file + +import { Static } from '@sinclair/parsebox' +function Assert(): void {} + +Assert, ['0', '']>() +Assert, []>() +Assert, ['10', '']>() +Assert, ['0', '']>() +Assert, ['0', ' ']>() + diff --git a/test/parsebox/static/const.ts b/test/parsebox/static/const.ts new file mode 100644 index 0000000..0929e78 --- /dev/null +++ b/test/parsebox/static/const.ts @@ -0,0 +1,9 @@ +// deno-fmt-ignore-file + +import { Static } from '@sinclair/parsebox' +function Assert(): void {} + +Assert, ''>, []>() +Assert, 'A'>, ['A', '']>() +Assert, ' A'>, ['A', '']>() +Assert, ' A '>, ['A', ' ']>() \ No newline at end of file diff --git a/test/parsebox/static/ident.ts b/test/parsebox/static/ident.ts new file mode 100644 index 0000000..6ec4ce0 --- /dev/null +++ b/test/parsebox/static/ident.ts @@ -0,0 +1,24 @@ +// deno-fmt-ignore-file + +import { Static } from '@sinclair/parsebox' +function Assert(): void {} + +Assert, []>() +Assert, []>() +Assert, []>() +Assert, ['_', '']>() +Assert, ['_', '']>() +Assert, ['_', ' ']>() +Assert, ['_', ' ']>() +Assert, ['$', '']>() +Assert, ['$', '']>() +Assert, ['$', ' ']>() +Assert, ['$', ' ']>() +Assert, ['A', '']>() +Assert, ['A', '']>() +Assert, ['A', ' ']>() +Assert, ['A', ' ']>() +Assert, ['A1', '']>() +Assert, ['A1', '']>() +Assert, ['A1', ' ']>() +Assert, ['A1', ' ']>() \ No newline at end of file diff --git a/test/parsebox/static/integer.ts b/test/parsebox/static/integer.ts new file mode 100644 index 0000000..ce0fb13 --- /dev/null +++ b/test/parsebox/static/integer.ts @@ -0,0 +1,9 @@ +// deno-fmt-ignore-file + +import { Static } from '@sinclair/parsebox' +function Assert(): void {} + +Assert, ['0', '']>() +Assert, ['0', '0']>() +Assert, ['10', '']>() +Assert, ['0', '']>() diff --git a/test/parsebox/static/number.ts b/test/parsebox/static/number.ts new file mode 100644 index 0000000..ddf021e --- /dev/null +++ b/test/parsebox/static/number.ts @@ -0,0 +1,50 @@ +// deno-fmt-ignore-file + +import { Static } from '@sinclair/parsebox' +function Assert(): void {} + +Assert, []>() +Assert, ['0', '1']>() +Assert, ['0', '1']>() +Assert, ['0', '1 ']>() +Assert, ['0', '1 ']>() +Assert, ['0', '']>() +Assert, ['0', ' ']>() +Assert, ['0', '']>() +Assert, ['0', ' ']>() +Assert, ['-0', '']>() +Assert, ['-0', ' ']>() +Assert, ['-0', '']>() +Assert, ['-0', ' ']>() +Assert, ['100', '']>() +Assert, ['100', ' ']>() +Assert, ['100', '']>() +Assert, ['100', ' ']>() +Assert, ['-100', '']>() +Assert, ['-100', ' ']>() +Assert, ['-100', '']>() +Assert, ['-100', ' ']>() +Assert, ['0.1', '']>() +Assert, ['0.1', ' ']>() +Assert, ['0.1', '']>() +Assert, ['0.1', ' ']>() +Assert, ['100.1', '']>() +Assert, ['100.1', ' ']>() +Assert, ['100.1', '']>() +Assert, ['100.1', ' ']>() +Assert, ['-100.1', '']>() +Assert, ['-100.1', ' ']>() +Assert, ['-100.1', '']>() +Assert, ['-100.1', ' ']>() +Assert, ['100.1', '.1']>() +Assert, ['100.1', '.1 ']>() +Assert, ['100.1', '.1']>() +Assert, ['100.1', '.1 ']>() +Assert, ['-0.1', '']>() +Assert, ['-0.1', ' ']>() +Assert, ['-0.1', '']>() +Assert, ['-0.1', ' ']>() +Assert, ['-0.1', '']>() +Assert, ['-0.1', ' ']>() +Assert, ['-0.1', '']>() +Assert, ['-0.1', ' ']>() \ No newline at end of file diff --git a/test/parsebox/static/optional.ts b/test/parsebox/static/optional.ts new file mode 100644 index 0000000..74750ab --- /dev/null +++ b/test/parsebox/static/optional.ts @@ -0,0 +1,9 @@ +// deno-fmt-ignore-file + +import { Static } from '@sinclair/parsebox' +function Assert(): void {} + +Assert>, ''>, [[], '']>() +Assert>, 'A'>, [['A'], '']>() +Assert>, 'AA'>, [['A'], 'A']>() +Assert>, 'B'>, [[], 'B']>() \ No newline at end of file diff --git a/test/parsebox/static/ref.ts b/test/parsebox/static/ref.ts new file mode 100644 index 0000000..79471bc --- /dev/null +++ b/test/parsebox/static/ref.ts @@ -0,0 +1,4 @@ +// deno-fmt-ignore-file + +import { Static } from '@sinclair/parsebox' +function Assert(): void {} \ No newline at end of file diff --git a/test/parsebox/static/string.ts b/test/parsebox/static/string.ts new file mode 100644 index 0000000..4c90918 --- /dev/null +++ b/test/parsebox/static/string.ts @@ -0,0 +1,10 @@ +// deno-fmt-ignore-file + +import { Static } from '@sinclair/parsebox' +function Assert(): void {} + +Assert, ''>, []>() +Assert, '"A"'>, ['A', '']>() +Assert, ' "A"'>, ['A', '']>() +Assert, '"A" '>, ['A', ' ']>() +Assert, ' "A" '>, ['A', ' ']>() \ No newline at end of file diff --git a/test/parsebox/static/tuple.ts b/test/parsebox/static/tuple.ts new file mode 100644 index 0000000..25c6789 --- /dev/null +++ b/test/parsebox/static/tuple.ts @@ -0,0 +1,13 @@ +// deno-fmt-ignore-file + +import { Static } from '@sinclair/parsebox' +function Assert(): void {} + +type Tuple = Static.Tuple<[Static.Const<'A'>, Static.Const<'B'>, Static.Const<'C'>]> +Assert, []>() +Assert, []>() +Assert, [['A', 'B', 'C'], '']>() +Assert, [['A', 'B', 'C'], ' ']>() +Assert, [['A', 'B', 'C'], '']>() +Assert, [['A', 'B', 'C'], '']>() +Assert, [['A', 'B', 'C'], ' ']>() \ No newline at end of file diff --git a/test/parsebox/static/union.ts b/test/parsebox/static/union.ts new file mode 100644 index 0000000..9f20759 --- /dev/null +++ b/test/parsebox/static/union.ts @@ -0,0 +1,18 @@ +// deno-fmt-ignore-file + +import { Static } from '@sinclair/parsebox' +function Assert(): void {} + +type Union = Static.Union<[Static.Const<'A'>, Static.Const<'B'>, Static.Const<'C'>]> + +Assert, []>() +Assert, ['A', ' B C']>() +Assert, ['A', ' B C ']>() +Assert, ['A', 'BC']>() +Assert, ['A', 'BC']>() +Assert, ['A', 'BC ']>() +Assert, ['B', ' B C']>() +Assert, ['B', ' B C ']>() +Assert, ['B', 'BC']>() +Assert, ['B', 'BC']>() +Assert, ['B', 'BC ']>() \ No newline at end of file diff --git a/test/parsebox/static/until.ts b/test/parsebox/static/until.ts new file mode 100644 index 0000000..08e892d --- /dev/null +++ b/test/parsebox/static/until.ts @@ -0,0 +1,14 @@ +// deno-fmt-ignore-file + +import { Static } from '@sinclair/parsebox' +function Assert(): void {} + +Assert, ''>, []>() +Assert, 'A'>, ['', 'A']>() +Assert, ' A'>, [' ', 'A']>() +Assert, ' A '>, [' ', 'A ']>() + +Assert, ''>, []> +Assert, 'BA'>, ['', 'BA']> +Assert, ' BA'>, [' ', 'BA']> +Assert, ' BA '>, [' ', 'BA ']> \ No newline at end of file diff --git a/test/parsebox/static/until_1.ts b/test/parsebox/static/until_1.ts new file mode 100644 index 0000000..099eec0 --- /dev/null +++ b/test/parsebox/static/until_1.ts @@ -0,0 +1,14 @@ +// deno-fmt-ignore-file + +import { Static } from '@sinclair/parsebox' +function Assert(): void {} + +Assert, ''>, []> +Assert, 'A'>, []> +Assert, ' A'>, [' ', 'A']> +Assert, ' A '>, [' ', 'A ']> + +Assert, ''>, []> +Assert, 'BA'>, []> +Assert, ' BA'>, [' ', 'BA']> +Assert, ' BA '>, [' ', 'BA ']> \ No newline at end of file diff --git a/test/parsebox/static/~mapping.ts b/test/parsebox/static/~mapping.ts new file mode 100644 index 0000000..95c6597 --- /dev/null +++ b/test/parsebox/static/~mapping.ts @@ -0,0 +1,12 @@ +// deno-fmt-ignore-file + +import { Static } from '@sinclair/parsebox' +function Assert(): void {} + +interface Mapping extends Static.IMapping { + output: this['input'] extends [infer A, infer B, infer C] ? [C, B, A] : never +} + +type Mapped = Static.Tuple<[Static.Const<'A'>, Static.Const<'B'>, Static.Const<'C'>], Mapping> + +Assert, [['C', 'B', 'A'], ' ']>() \ No newline at end of file diff --git a/test/parsebox/system/arguments.ts b/test/parsebox/system/arguments.ts new file mode 100644 index 0000000..d3ab225 --- /dev/null +++ b/test/parsebox/system/arguments.ts @@ -0,0 +1,12 @@ +import { System } from '@sinclair/parsebox' +import { Assert } from 'test' + +const Test = Assert.Context('System.Arguments') + +Test('Should Arguments Match 1', () => { + const Result = System.Arguments.Match([1], { 1: () => 'ok' }) + Assert.IsEqual(Result, 'ok') +}) +Test('Should Arguments Match 2', () => { + Assert.Throws(() => System.Arguments.Match([1, 2], { 1: () => 'ok' })) +}) diff --git a/test/parsebox/token/bigint.ts b/test/parsebox/token/bigint.ts new file mode 100644 index 0000000..0c9249f --- /dev/null +++ b/test/parsebox/token/bigint.ts @@ -0,0 +1,104 @@ +import { Token } from '@sinclair/parsebox' +import { Assert } from 'test' + +const Test = Assert.Context('Token.BigInt') + +// ------------------------------------------------------------------ +// Unsigned +// ------------------------------------------------------------------ +Test('Should BigInt 1', () => Assert.IsExact(Token.BigInt('0n'), ['0', ''])) +Test('Should BigInt 2', () => Assert.IsExact(Token.BigInt('00n'), [])) +Test('Should BigInt 3', () => Assert.IsExact(Token.BigInt('10n'), ['10', ''])) +Test('Should BigInt 4', () => Assert.IsExact(Token.BigInt(' 0n'), ['0', ''])) +Test('Should BigInt 5', () => Assert.IsExact(Token.BigInt('0n '), ['0', ' '])) +Test('Should BigInt 6', () => Assert.IsExact(Token.BigInt(' 0n '), ['0', ' '])) +Test('Should BigInt 7', () => Assert.IsExact(Token.BigInt(' 00n'), [])) +Test('Should BigInt 8', () => Assert.IsExact(Token.BigInt('00n '), [])) +Test('Should BigInt 9', () => Assert.IsExact(Token.BigInt(' 00n '), [])) +Test('Should BigInt 10', () => Assert.IsExact(Token.BigInt(' 10n'), ['10', ''])) +Test('Should BigInt 11', () => Assert.IsExact(Token.BigInt('10n '), ['10', ' '])) +Test('Should BigInt 12', () => Assert.IsExact(Token.BigInt(' 10n '), ['10', ' '])) + +// ------------------------------------------------------------------ +// Signed +// ------------------------------------------------------------------ +Test('Should BigInt 13', () => Assert.IsExact(Token.BigInt('-0n'), ['-0', ''])) +Test('Should BigInt 14', () => Assert.IsExact(Token.BigInt('-00n'), [])) +Test('Should BigInt 15', () => Assert.IsExact(Token.BigInt('-10n'), ['-10', ''])) +Test('Should BigInt 16', () => Assert.IsExact(Token.BigInt(' -0n'), ['-0', ''])) +Test('Should BigInt 17', () => Assert.IsExact(Token.BigInt('-0n '), ['-0', ' '])) +Test('Should BigInt 18', () => Assert.IsExact(Token.BigInt(' -0n '), ['-0', ' '])) +Test('Should BigInt 19', () => Assert.IsExact(Token.BigInt(' -00n'), [])) +Test('Should BigInt 20', () => Assert.IsExact(Token.BigInt('-00n '), [])) +Test('Should BigInt 21', () => Assert.IsExact(Token.BigInt(' -00n '), [])) +Test('Should BigInt 22', () => Assert.IsExact(Token.BigInt(' -10n'), ['-10', ''])) +Test('Should BigInt 23', () => Assert.IsExact(Token.BigInt('-10n '), ['-10', ' '])) +Test('Should BigInt 24', () => Assert.IsExact(Token.BigInt(' -10n '), ['-10', ' '])) + +// ------------------------------------------------------------------ +// Digits +// ------------------------------------------------------------------ +Test('Should BigInt 25', () => Assert.IsExact(Token.BigInt('0n'), ['0', ''])) +Test('Should BigInt 26', () => Assert.IsExact(Token.BigInt('1n'), ['1', ''])) +Test('Should BigInt 27', () => Assert.IsExact(Token.BigInt('2n'), ['2', ''])) +Test('Should BigInt 28', () => Assert.IsExact(Token.BigInt('3n'), ['3', ''])) +Test('Should BigInt 29', () => Assert.IsExact(Token.BigInt('4n'), ['4', ''])) +Test('Should BigInt 30', () => Assert.IsExact(Token.BigInt('5n'), ['5', ''])) +Test('Should BigInt 31', () => Assert.IsExact(Token.BigInt('6n'), ['6', ''])) +Test('Should BigInt 32', () => Assert.IsExact(Token.BigInt('7n'), ['7', ''])) +Test('Should BigInt 33', () => Assert.IsExact(Token.BigInt('8n'), ['8', ''])) +Test('Should BigInt 34', () => Assert.IsExact(Token.BigInt('9n'), ['9', ''])) +Test('Should BigInt 35', () => Assert.IsExact(Token.BigInt('-0n'), ['-0', ''])) +Test('Should BigInt 36', () => Assert.IsExact(Token.BigInt('-1n'), ['-1', ''])) +Test('Should BigInt 37', () => Assert.IsExact(Token.BigInt('-2n'), ['-2', ''])) +Test('Should BigInt 38', () => Assert.IsExact(Token.BigInt('-3n'), ['-3', ''])) +Test('Should BigInt 39', () => Assert.IsExact(Token.BigInt('-4n'), ['-4', ''])) +Test('Should BigInt 40', () => Assert.IsExact(Token.BigInt('-5n'), ['-5', ''])) +Test('Should BigInt 41', () => Assert.IsExact(Token.BigInt('-6n'), ['-6', ''])) +Test('Should BigInt 42', () => Assert.IsExact(Token.BigInt('-7n'), ['-7', ''])) +Test('Should BigInt 43', () => Assert.IsExact(Token.BigInt('-8n'), ['-8', ''])) +Test('Should BigInt 44', () => Assert.IsExact(Token.BigInt('-9n'), ['-9', ''])) +Test('Should BigInt 45', () => Assert.IsExact(Token.BigInt('10n'), ['10', ''])) +Test('Should BigInt 46', () => Assert.IsExact(Token.BigInt('11n'), ['11', ''])) +Test('Should BigInt 47', () => Assert.IsExact(Token.BigInt('12n'), ['12', ''])) +Test('Should BigInt 48', () => Assert.IsExact(Token.BigInt('13n'), ['13', ''])) +Test('Should BigInt 49', () => Assert.IsExact(Token.BigInt('14n'), ['14', ''])) +Test('Should BigInt 50', () => Assert.IsExact(Token.BigInt('15n'), ['15', ''])) +Test('Should BigInt 51', () => Assert.IsExact(Token.BigInt('16n'), ['16', ''])) +Test('Should BigInt 52', () => Assert.IsExact(Token.BigInt('17n'), ['17', ''])) +Test('Should BigInt 53', () => Assert.IsExact(Token.BigInt('18n'), ['18', ''])) +Test('Should BigInt 54', () => Assert.IsExact(Token.BigInt('19n'), ['19', ''])) +Test('Should BigInt 55', () => Assert.IsExact(Token.BigInt('-10n'), ['-10', ''])) +Test('Should BigInt 56', () => Assert.IsExact(Token.BigInt('-11n'), ['-11', ''])) +Test('Should BigInt 57', () => Assert.IsExact(Token.BigInt('-12n'), ['-12', ''])) +Test('Should BigInt 58', () => Assert.IsExact(Token.BigInt('-13n'), ['-13', ''])) +Test('Should BigInt 59', () => Assert.IsExact(Token.BigInt('-14n'), ['-14', ''])) +Test('Should BigInt 60', () => Assert.IsExact(Token.BigInt('-15n'), ['-15', ''])) +Test('Should BigInt 61', () => Assert.IsExact(Token.BigInt('-16n'), ['-16', ''])) +Test('Should BigInt 62', () => Assert.IsExact(Token.BigInt('-17n'), ['-17', ''])) +Test('Should BigInt 63', () => Assert.IsExact(Token.BigInt('-18n'), ['-18', ''])) +Test('Should BigInt 64', () => Assert.IsExact(Token.BigInt('-19n'), ['-19', ''])) + +// ------------------------------------------------------------------ +// Invariant +// ------------------------------------------------------------------ +Test('Should BigInt 65', () => Assert.IsExact(Token.BigInt('x'), [])) +Test('Should BigInt 66', () => Assert.IsExact(Token.BigInt(''), [])) + +// ------------------------------------------------------------------ +// Additional +// ------------------------------------------------------------------ +Test('Should BigInt 67', () => Assert.IsExact(Token.BigInt('000n'), [])) +Test('Should BigInt 68', () => Assert.IsExact(Token.BigInt('0000n'), [])) +Test('Should BigInt 69', () => Assert.IsExact(Token.BigInt('1000n'), ['1000', ''])) +Test('Should BigInt 70', () => Assert.IsExact(Token.BigInt('1000nx'), ['1000', 'x'])) + +// ------------------------------------------------------------------ +// Underscore: We support multiple underscore +// ------------------------------------------------------------------ +Test('Should BigInt 71', () => Assert.IsExact(Token.BigInt('10_000_000n'), ['10000000', ''])) +Test('Should BigInt 72', () => Assert.IsExact(Token.BigInt('10_000n _000'), ['10000', ' _000'])) +Test('Should BigInt 73', () => Assert.IsExact(Token.BigInt('10_000_n 000'), ['10000', ' 000'])) +Test('Should BigInt 74', () => Assert.IsExact(Token.BigInt('10__000n 000'), ['10000', ' 000'])) +Test('Should BigInt 75', () => Assert.IsExact(Token.BigInt('10__000__n 000'), ['10000', ' 000'])) +Test('Should BigInt 76', () => Assert.IsExact(Token.BigInt('10__000n __000'), ['10000', ' __000'])) diff --git a/test/parsebox/token/const.ts b/test/parsebox/token/const.ts new file mode 100644 index 0000000..5582ab5 --- /dev/null +++ b/test/parsebox/token/const.ts @@ -0,0 +1,109 @@ +import { Token } from '@sinclair/parsebox' +import { Assert } from 'test' + +const Test = Assert.Context('Token.Const') + +// ------------------------------------------------------------------ +// Const: Empty +// ------------------------------------------------------------------ +Test('Should Const 1', () => Assert.IsExact(Token.Const('', ''), ['', ''])) +Test('Should Const 2', () => Assert.IsExact(Token.Const('', 'A'), ['', 'A'])) +Test('Should Const 3', () => Assert.IsExact(Token.Const('', ' A'), ['', ' A'])) + +// ------------------------------------------------------------------ +// Const: Single-Char +// ------------------------------------------------------------------ +Test('Should Const 4', () => Assert.IsExact(Token.Const('A', 'A'), ['A', ''])) +Test('Should Const 5', () => Assert.IsExact(Token.Const('A', 'A '), ['A', ' '])) +Test('Should Const 6', () => Assert.IsExact(Token.Const('A', 'AA'), ['A', 'A'])) +Test('Should Const 7', () => Assert.IsExact(Token.Const('A', 'AA '), ['A', 'A '])) + +// ------------------------------------------------------------------ +// Const: Multi-Char +// ------------------------------------------------------------------ +Test('Should Const 8', () => Assert.IsExact(Token.Const('AB', 'AB'), ['AB', ''])) +Test('Should Const 9', () => Assert.IsExact(Token.Const('AB', 'AB '), ['AB', ' '])) +Test('Should Const 10', () => Assert.IsExact(Token.Const('AB', 'ABA'), ['AB', 'A'])) +Test('Should Const 11', () => Assert.IsExact(Token.Const('AB', 'ABA '), ['AB', 'A '])) + +// ------------------------------------------------------------------ +// Const: Single-Char -> Ignore-Whitespace +// ------------------------------------------------------------------ +Test('Should Const 12', () => Assert.IsExact(Token.Const('A', ' A'), ['A', ''])) +Test('Should Const 13', () => Assert.IsExact(Token.Const('A', ' A '), ['A', ' '])) +Test('Should Const 14', () => Assert.IsExact(Token.Const('A', ' AA'), ['A', 'A'])) +Test('Should Const 15', () => Assert.IsExact(Token.Const('A', ' AA '), ['A', 'A '])) +Test('Should Const 16', () => Assert.IsExact(Token.Const('A', '\nAA '), ['A', 'A '])) +Test('Should Const 17', () => Assert.IsExact(Token.Const('A', ' \nAA '), ['A', 'A '])) +Test('Should Const 18', () => Assert.IsExact(Token.Const('A', '\n AA '), ['A', 'A '])) +Test('Should Const 19', () => Assert.IsExact(Token.Const('A', ' \n AA '), ['A', 'A '])) + +// ------------------------------------------------------------------ +// Const: Multi-Char -> Ignore-Whitespace +// ------------------------------------------------------------------ +Test('Should Const 20', () => Assert.IsExact(Token.Const('AB', ' AB'), ['AB', ''])) +Test('Should Const 21', () => Assert.IsExact(Token.Const('AB', ' AB '), ['AB', ' '])) +Test('Should Const 22', () => Assert.IsExact(Token.Const('AB', ' ABA'), ['AB', 'A'])) +Test('Should Const 23', () => Assert.IsExact(Token.Const('AB', ' ABA '), ['AB', 'A '])) +Test('Should Const 24', () => Assert.IsExact(Token.Const('AB', '\nABA '), ['AB', 'A '])) +Test('Should Const 25', () => Assert.IsExact(Token.Const('AB', ' \nABA '), ['AB', 'A '])) +Test('Should Const 26', () => Assert.IsExact(Token.Const('AB', '\n ABA '), ['AB', 'A '])) +Test('Should Const 27', () => Assert.IsExact(Token.Const('AB', ' \n ABA '), ['AB', 'A '])) + +// ------------------------------------------------------------------ +// Const: Single-Whitespace +// ------------------------------------------------------------------ +Test('Should Const 28', () => Assert.IsExact(Token.Const(' ', ''), [])) +Test('Should Const 29', () => Assert.IsExact(Token.Const(' ', ' '), [' ', ''])) +Test('Should Const 30', () => Assert.IsExact(Token.Const(' ', ' A'), [' ', 'A'])) +Test('Should Const 31', () => Assert.IsExact(Token.Const(' ', ' A '), [' ', 'A '])) +Test('Should Const 32', () => Assert.IsExact(Token.Const(' ', ' AA'), [' ', 'AA'])) +Test('Should Const 33', () => Assert.IsExact(Token.Const(' ', ' AA '), [' ', 'AA '])) + +// ------------------------------------------------------------------ +// Const: Multi-Whitespace +// ------------------------------------------------------------------ +Test('Should Const 34', () => Assert.IsExact(Token.Const(' ', ''), [])) +Test('Should Const 35', () => Assert.IsExact(Token.Const(' ', ' '), [])) +Test('Should Const 36', () => Assert.IsExact(Token.Const(' ', ' A'), [' ', 'A'])) +Test('Should Const 37', () => Assert.IsExact(Token.Const(' ', ' A '), [' ', 'A '])) +Test('Should Const 38', () => Assert.IsExact(Token.Const(' ', ' AA'), [' ', 'AA'])) +Test('Should Const 39', () => Assert.IsExact(Token.Const(' ', ' AA '), [' ', 'AA '])) + +// ------------------------------------------------------------------ +// Const: Newline +// ------------------------------------------------------------------ +Test('Should Const 40', () => Assert.IsExact(Token.Const('\n', ''), [])) +Test('Should Const 41', () => Assert.IsExact(Token.Const('\n', ' '), [])) +Test('Should Const 42', () => Assert.IsExact(Token.Const('\n', '\nA'), ['\n', 'A'])) +Test('Should Const 43', () => Assert.IsExact(Token.Const('\n', ' \nA '), ['\n', 'A '])) +Test('Should Const 44', () => Assert.IsExact(Token.Const('\n', ' \nAA'), ['\n', 'AA'])) +Test('Should Const 45', () => Assert.IsExact(Token.Const('\n', ' \nAA '), ['\n', 'AA '])) + +// ------------------------------------------------------------------ +// Const: Newline-Single-Whitespace +// ------------------------------------------------------------------ +Test('Should Const 46', () => Assert.IsExact(Token.Const('\n ', ''), [])) +Test('Should Const 47', () => Assert.IsExact(Token.Const('\n ', ' '), [])) +Test('Should Const 48', () => Assert.IsExact(Token.Const('\n ', '\nA'), [])) +Test('Should Const 49', () => Assert.IsExact(Token.Const('\n ', ' \nA '), [])) +Test('Should Const 50', () => Assert.IsExact(Token.Const('\n ', ' \nAA'), [])) +Test('Should Const 51', () => Assert.IsExact(Token.Const('\n ', ' \nAA '), [])) +Test('Should Const 52', () => Assert.IsExact(Token.Const('\n ', '\n A'), ['\n ', 'A'])) +Test('Should Const 53', () => Assert.IsExact(Token.Const('\n ', ' \n A '), ['\n ', 'A '])) +Test('Should Const 54', () => Assert.IsExact(Token.Const('\n ', ' \n AA'), ['\n ', 'AA'])) +Test('Should Const 55', () => Assert.IsExact(Token.Const('\n ', ' \n AA '), ['\n ', 'AA '])) + +// ------------------------------------------------------------------ +// Const: Newline-Multi-Whitespace +// ------------------------------------------------------------------ +Test('Should Const 56', () => Assert.IsExact(Token.Const('\n ', ''), [])) +Test('Should Const 57', () => Assert.IsExact(Token.Const('\n ', ' '), [])) +Test('Should Const 58', () => Assert.IsExact(Token.Const('\n ', '\n A'), [])) +Test('Should Const 59', () => Assert.IsExact(Token.Const('\n ', ' \n A '), [])) +Test('Should Const 60', () => Assert.IsExact(Token.Const('\n ', ' \n AA'), [])) +Test('Should Const 61', () => Assert.IsExact(Token.Const('\n ', ' \n AA '), [])) +Test('Should Const 62', () => Assert.IsExact(Token.Const('\n ', '\n A'), ['\n ', 'A'])) +Test('Should Const 63', () => Assert.IsExact(Token.Const('\n ', ' \n A '), ['\n ', 'A '])) +Test('Should Const 64', () => Assert.IsExact(Token.Const('\n ', ' \n AA'), ['\n ', 'AA'])) +Test('Should Const 65', () => Assert.IsExact(Token.Const('\n ', ' \n AA '), ['\n ', 'AA '])) diff --git a/test/parsebox/token/ident.ts b/test/parsebox/token/ident.ts new file mode 100644 index 0000000..d8108ce --- /dev/null +++ b/test/parsebox/token/ident.ts @@ -0,0 +1,24 @@ +import { Token } from '@sinclair/parsebox' +import { Assert } from 'test' + +const Test = Assert.Context('Token.Ident') + +Test('Should Ident 1', () => Assert.IsExact(Token.Ident(''), [])) +Test('Should Ident 2', () => Assert.IsExact(Token.Ident('0'), [])) +Test('Should Ident 3', () => Assert.IsExact(Token.Ident('#'), [])) +Test('Should Ident 4', () => Assert.IsExact(Token.Ident('_'), ['_', ''])) +Test('Should Ident 5', () => Assert.IsExact(Token.Ident(' _'), ['_', ''])) +Test('Should Ident 6', () => Assert.IsExact(Token.Ident('_ '), ['_', ' '])) +Test('Should Ident 7', () => Assert.IsExact(Token.Ident(' _ '), ['_', ' '])) +Test('Should Ident 8', () => Assert.IsExact(Token.Ident('$'), ['$', ''])) +Test('Should Ident 9', () => Assert.IsExact(Token.Ident(' $'), ['$', ''])) +Test('Should Ident 10', () => Assert.IsExact(Token.Ident('$ '), ['$', ' '])) +Test('Should Ident 11', () => Assert.IsExact(Token.Ident(' $ '), ['$', ' '])) +Test('Should Ident 12', () => Assert.IsExact(Token.Ident('A'), ['A', ''])) +Test('Should Ident 13', () => Assert.IsExact(Token.Ident(' A'), ['A', ''])) +Test('Should Ident 14', () => Assert.IsExact(Token.Ident('A '), ['A', ' '])) +Test('Should Ident 15', () => Assert.IsExact(Token.Ident(' A '), ['A', ' '])) +Test('Should Ident 16', () => Assert.IsExact(Token.Ident('A1'), ['A1', ''])) +Test('Should Ident 17', () => Assert.IsExact(Token.Ident(' A1'), ['A1', ''])) +Test('Should Ident 18', () => Assert.IsExact(Token.Ident('A1 '), ['A1', ' '])) +Test('Should Ident 19', () => Assert.IsExact(Token.Ident(' A1 '), ['A1', ' '])) diff --git a/test/parsebox/token/integer.ts b/test/parsebox/token/integer.ts new file mode 100644 index 0000000..f847e99 --- /dev/null +++ b/test/parsebox/token/integer.ts @@ -0,0 +1,104 @@ +import { Token } from '@sinclair/parsebox' +import { Assert } from 'test' + +const Test = Assert.Context('Token.Integer') + +// ------------------------------------------------------------------ +// Unsigned +// ------------------------------------------------------------------ +Test('Should Integer 1', () => Assert.IsExact(Token.Integer('0'), ['0', ''])) +Test('Should Integer 2', () => Assert.IsExact(Token.Integer('00'), ['0', '0'])) +Test('Should Integer 3', () => Assert.IsExact(Token.Integer('10'), ['10', ''])) +Test('Should Integer 4', () => Assert.IsExact(Token.Integer(' 0'), ['0', ''])) +Test('Should Integer 5', () => Assert.IsExact(Token.Integer('0 '), ['0', ' '])) +Test('Should Integer 6', () => Assert.IsExact(Token.Integer(' 0 '), ['0', ' '])) +Test('Should Integer 7', () => Assert.IsExact(Token.Integer(' 00'), ['0', '0'])) +Test('Should Integer 8', () => Assert.IsExact(Token.Integer('00 '), ['0', '0 '])) +Test('Should Integer 9', () => Assert.IsExact(Token.Integer(' 00 '), ['0', '0 '])) +Test('Should Integer 10', () => Assert.IsExact(Token.Integer(' 10'), ['10', ''])) +Test('Should Integer 11', () => Assert.IsExact(Token.Integer('10 '), ['10', ' '])) +Test('Should Integer 12', () => Assert.IsExact(Token.Integer(' 10 '), ['10', ' '])) + +// ------------------------------------------------------------------ +// Signed +// ------------------------------------------------------------------ +Test('Should Integer 13', () => Assert.IsExact(Token.Integer('-0'), ['-0', ''])) +Test('Should Integer 14', () => Assert.IsExact(Token.Integer('-00'), ['-0', '0'])) +Test('Should Integer 15', () => Assert.IsExact(Token.Integer('-10'), ['-10', ''])) +Test('Should Integer 16', () => Assert.IsExact(Token.Integer(' -0'), ['-0', ''])) +Test('Should Integer 17', () => Assert.IsExact(Token.Integer('-0 '), ['-0', ' '])) +Test('Should Integer 18', () => Assert.IsExact(Token.Integer(' -0 '), ['-0', ' '])) +Test('Should Integer 19', () => Assert.IsExact(Token.Integer(' -00'), ['-0', '0'])) +Test('Should Integer 20', () => Assert.IsExact(Token.Integer('-00 '), ['-0', '0 '])) +Test('Should Integer 21', () => Assert.IsExact(Token.Integer(' -00 '), ['-0', '0 '])) +Test('Should Integer 22', () => Assert.IsExact(Token.Integer(' -10'), ['-10', ''])) +Test('Should Integer 23', () => Assert.IsExact(Token.Integer('-10 '), ['-10', ' '])) +Test('Should Integer 24', () => Assert.IsExact(Token.Integer(' -10 '), ['-10', ' '])) + +// ------------------------------------------------------------------ +// Digits +// ------------------------------------------------------------------ +Test('Should Integer 25', () => Assert.IsExact(Token.Integer('0'), ['0', ''])) +Test('Should Integer 26', () => Assert.IsExact(Token.Integer('1'), ['1', ''])) +Test('Should Integer 27', () => Assert.IsExact(Token.Integer('2'), ['2', ''])) +Test('Should Integer 28', () => Assert.IsExact(Token.Integer('3'), ['3', ''])) +Test('Should Integer 29', () => Assert.IsExact(Token.Integer('4'), ['4', ''])) +Test('Should Integer 30', () => Assert.IsExact(Token.Integer('5'), ['5', ''])) +Test('Should Integer 31', () => Assert.IsExact(Token.Integer('6'), ['6', ''])) +Test('Should Integer 32', () => Assert.IsExact(Token.Integer('7'), ['7', ''])) +Test('Should Integer 33', () => Assert.IsExact(Token.Integer('8'), ['8', ''])) +Test('Should Integer 34', () => Assert.IsExact(Token.Integer('9'), ['9', ''])) +Test('Should Integer 35', () => Assert.IsExact(Token.Integer('-0'), ['-0', ''])) +Test('Should Integer 36', () => Assert.IsExact(Token.Integer('-1'), ['-1', ''])) +Test('Should Integer 37', () => Assert.IsExact(Token.Integer('-2'), ['-2', ''])) +Test('Should Integer 38', () => Assert.IsExact(Token.Integer('-3'), ['-3', ''])) +Test('Should Integer 39', () => Assert.IsExact(Token.Integer('-4'), ['-4', ''])) +Test('Should Integer 40', () => Assert.IsExact(Token.Integer('-5'), ['-5', ''])) +Test('Should Integer 41', () => Assert.IsExact(Token.Integer('-6'), ['-6', ''])) +Test('Should Integer 42', () => Assert.IsExact(Token.Integer('-7'), ['-7', ''])) +Test('Should Integer 43', () => Assert.IsExact(Token.Integer('-8'), ['-8', ''])) +Test('Should Integer 44', () => Assert.IsExact(Token.Integer('-9'), ['-9', ''])) +Test('Should Integer 45', () => Assert.IsExact(Token.Integer('10'), ['10', ''])) +Test('Should Integer 46', () => Assert.IsExact(Token.Integer('11'), ['11', ''])) +Test('Should Integer 47', () => Assert.IsExact(Token.Integer('12'), ['12', ''])) +Test('Should Integer 48', () => Assert.IsExact(Token.Integer('13'), ['13', ''])) +Test('Should Integer 49', () => Assert.IsExact(Token.Integer('14'), ['14', ''])) +Test('Should Integer 50', () => Assert.IsExact(Token.Integer('15'), ['15', ''])) +Test('Should Integer 51', () => Assert.IsExact(Token.Integer('16'), ['16', ''])) +Test('Should Integer 52', () => Assert.IsExact(Token.Integer('17'), ['17', ''])) +Test('Should Integer 53', () => Assert.IsExact(Token.Integer('18'), ['18', ''])) +Test('Should Integer 54', () => Assert.IsExact(Token.Integer('19'), ['19', ''])) +Test('Should Integer 55', () => Assert.IsExact(Token.Integer('-10'), ['-10', ''])) +Test('Should Integer 56', () => Assert.IsExact(Token.Integer('-11'), ['-11', ''])) +Test('Should Integer 57', () => Assert.IsExact(Token.Integer('-12'), ['-12', ''])) +Test('Should Integer 58', () => Assert.IsExact(Token.Integer('-13'), ['-13', ''])) +Test('Should Integer 59', () => Assert.IsExact(Token.Integer('-14'), ['-14', ''])) +Test('Should Integer 60', () => Assert.IsExact(Token.Integer('-15'), ['-15', ''])) +Test('Should Integer 61', () => Assert.IsExact(Token.Integer('-16'), ['-16', ''])) +Test('Should Integer 62', () => Assert.IsExact(Token.Integer('-17'), ['-17', ''])) +Test('Should Integer 63', () => Assert.IsExact(Token.Integer('-18'), ['-18', ''])) +Test('Should Integer 64', () => Assert.IsExact(Token.Integer('-19'), ['-19', ''])) + +// ------------------------------------------------------------------ +// Invariant +// ------------------------------------------------------------------ +Test('Should Integer 65', () => Assert.IsExact(Token.Integer('x'), [])) +Test('Should Integer 66', () => Assert.IsExact(Token.Integer(''), [])) + +// ------------------------------------------------------------------ +// Additional +// ------------------------------------------------------------------ +Test('Should Integer 67', () => Assert.IsExact(Token.Integer('000'), ['0', '00'])) +Test('Should Integer 68', () => Assert.IsExact(Token.Integer('0000'), ['0', '000'])) +Test('Should Integer 69', () => Assert.IsExact(Token.Integer('1000'), ['1000', ''])) +Test('Should Integer 70', () => Assert.IsExact(Token.Integer('1000x'), ['1000', 'x'])) + +// ------------------------------------------------------------------ +// Underscore: We support multiple underscore (should we?) +// ------------------------------------------------------------------ +Test('Should Integer 71', () => Assert.IsExact(Token.Integer('10_000_000'), ['10000000', ''])) +Test('Should Integer 72', () => Assert.IsExact(Token.Integer('10_000 _000'), ['10000', ' _000'])) +Test('Should Integer 73', () => Assert.IsExact(Token.Integer('10_000_ 000'), ['10000', ' 000'])) +Test('Should Integer 74', () => Assert.IsExact(Token.Integer('10__000 000'), ['10000', ' 000'])) +Test('Should Integer 75', () => Assert.IsExact(Token.Integer('10__000__ 000'), ['10000', ' 000'])) +Test('Should Integer 76', () => Assert.IsExact(Token.Integer('10__000 __000'), ['10000', ' __000'])) diff --git a/test/parsebox/token/number.ts b/test/parsebox/token/number.ts new file mode 100644 index 0000000..1c228c0 --- /dev/null +++ b/test/parsebox/token/number.ts @@ -0,0 +1,89 @@ +import { Token } from '@sinclair/parsebox' +import { Assert } from 'test' + +const Test = Assert.Context('Token.Number') + +Test('Should Number 1', () => Assert.IsExact(Token.Number(''), [])) +Test('Should Number 2', () => Assert.IsExact(Token.Number('01'), ['0', '1'])) +Test('Should Number 3', () => Assert.IsExact(Token.Number(' 01'), ['0', '1'])) +Test('Should Number 4', () => Assert.IsExact(Token.Number('01 '), ['0', '1 '])) +Test('Should Number 5', () => Assert.IsExact(Token.Number(' 01 '), ['0', '1 '])) +Test('Should Number 6', () => Assert.IsExact(Token.Number('0'), ['0', ''])) +Test('Should Number 7', () => Assert.IsExact(Token.Number('0 '), ['0', ' '])) +Test('Should Number 8', () => Assert.IsExact(Token.Number(' 0'), ['0', ''])) +Test('Should Number 9', () => Assert.IsExact(Token.Number(' 0 '), ['0', ' '])) +Test('Should Number 10', () => Assert.IsExact(Token.Number('-0'), ['-0', ''])) +Test('Should Number 11', () => Assert.IsExact(Token.Number('-0 '), ['-0', ' '])) +Test('Should Number 12', () => Assert.IsExact(Token.Number(' -0'), ['-0', ''])) +Test('Should Number 13', () => Assert.IsExact(Token.Number(' -0 '), ['-0', ' '])) +Test('Should Number 14', () => Assert.IsExact(Token.Number('100'), ['100', ''])) +Test('Should Number 15', () => Assert.IsExact(Token.Number('100 '), ['100', ' '])) +Test('Should Number 16', () => Assert.IsExact(Token.Number(' 100'), ['100', ''])) +Test('Should Number 17', () => Assert.IsExact(Token.Number(' 100 '), ['100', ' '])) +Test('Should Number 18', () => Assert.IsExact(Token.Number('-100'), ['-100', ''])) +Test('Should Number 19', () => Assert.IsExact(Token.Number('-100 '), ['-100', ' '])) +Test('Should Number 20', () => Assert.IsExact(Token.Number(' -100'), ['-100', ''])) +Test('Should Number 21', () => Assert.IsExact(Token.Number(' -100 '), ['-100', ' '])) +Test('Should Number 22', () => Assert.IsExact(Token.Number('0.1'), ['0.1', ''])) +Test('Should Number 23', () => Assert.IsExact(Token.Number('0.1 '), ['0.1', ' '])) +Test('Should Number 24', () => Assert.IsExact(Token.Number(' 0.1'), ['0.1', ''])) +Test('Should Number 25', () => Assert.IsExact(Token.Number(' 0.1 '), ['0.1', ' '])) +Test('Should Number 26', () => Assert.IsExact(Token.Number('100.1'), ['100.1', ''])) +Test('Should Number 27', () => Assert.IsExact(Token.Number('100.1 '), ['100.1', ' '])) +Test('Should Number 28', () => Assert.IsExact(Token.Number(' 100.1'), ['100.1', ''])) +Test('Should Number 29', () => Assert.IsExact(Token.Number(' 100.1 '), ['100.1', ' '])) +Test('Should Number 30', () => Assert.IsExact(Token.Number('-100.1'), ['-100.1', ''])) +Test('Should Number 31', () => Assert.IsExact(Token.Number('-100.1 '), ['-100.1', ' '])) +Test('Should Number 32', () => Assert.IsExact(Token.Number(' -100.1'), ['-100.1', ''])) +Test('Should Number 33', () => Assert.IsExact(Token.Number(' -100.1 '), ['-100.1', ' '])) +Test('Should Number 34', () => Assert.IsExact(Token.Number('100.1.1'), ['100.1', '.1'])) +Test('Should Number 35', () => Assert.IsExact(Token.Number('100.1.1 '), ['100.1', '.1 '])) +Test('Should Number 36', () => Assert.IsExact(Token.Number(' 100.1.1'), ['100.1', '.1'])) +Test('Should Number 37', () => Assert.IsExact(Token.Number(' 100.1.1 '), ['100.1', '.1 '])) +Test('Should Number 38', () => Assert.IsExact(Token.Number('-.1'), ['-0.1', ''])) +Test('Should Number 39', () => Assert.IsExact(Token.Number('-.1 '), ['-0.1', ' '])) +Test('Should Number 40', () => Assert.IsExact(Token.Number(' -.1'), ['-0.1', ''])) +Test('Should Number 41', () => Assert.IsExact(Token.Number(' -.1 '), ['-0.1', ' '])) +Test('Should Number 42', () => Assert.IsExact(Token.Number('-0.1'), ['-0.1', ''])) +Test('Should Number 43', () => Assert.IsExact(Token.Number('-0.1 '), ['-0.1', ' '])) +Test('Should Number 44', () => Assert.IsExact(Token.Number(' -0.1'), ['-0.1', ''])) +Test('Should Number 45', () => Assert.IsExact(Token.Number(' -0.1 '), ['-0.1', ' '])) +Test('Should Number 46', () => Assert.IsExact(Token.Number(' -00.1'), ['-0', '0.1'])) +Test('Should Number 47', () => Assert.IsExact(Token.Number(' -00.1 '), ['-0', '0.1 '])) + +// ------------------------------------------------------------------ +// Large numbers +// ------------------------------------------------------------------ +Test('Should Number 48', () => Assert.IsExact(Token.Number('1234567890'), ['1234567890', ''])) +Test('Should Number 49', () => Assert.IsExact(Token.Number('-9876543210 '), ['-9876543210', ' '])) + +// ------------------------------------------------------------------ +// Decimal without leading zero +// ------------------------------------------------------------------ +Test('Should Number 50', () => Assert.IsExact(Token.Number('.5'), ['0.5', ''])) +Test('Should Number 51', () => Assert.IsExact(Token.Number(' -.5 '), ['-0.5', ' '])) +Test('Should Number 52', () => Assert.IsExact(Token.Number('+.5'), [])) + +// ------------------------------------------------------------------ +// Multiple leading zeros +// ------------------------------------------------------------------ +Test('Should Number 53', () => Assert.IsExact(Token.Number('000123'), ['0', '00123'])) +Test('Should Number 54', () => Assert.IsExact(Token.Number('-000.5'), ['-0', '00.5'])) + +// ------------------------------------------------------------------ +// Numbers next to text +// ------------------------------------------------------------------ +Test('Should Number 55', () => Assert.IsExact(Token.Number('100abc'), ['100', 'abc'])) +Test('Should Number 56', () => Assert.IsExact(Token.Number('-0.1xyz'), ['-0.1', 'xyz'])) + +// ------------------------------------------------------------------ +// Numbers with spaces inside (should stop at first space) +// ------------------------------------------------------------------ +Test('Should Number 57', () => Assert.IsExact(Token.Number('123 456'), ['123', ' 456'])) +Test('Should Number 58', () => Assert.IsExact(Token.Number('-78.9 0'), ['-78.9', ' 0'])) + +// ------------------------------------------------------------------ +// Just a dot (invalid number) +// ------------------------------------------------------------------ +Test('Should Number 59', () => Assert.IsExact(Token.Number('.'), [])) +Test('Should Number 60', () => Assert.IsExact(Token.Number(' . '), [])) diff --git a/test/parsebox/token/span.ts b/test/parsebox/token/span.ts new file mode 100644 index 0000000..0061b14 --- /dev/null +++ b/test/parsebox/token/span.ts @@ -0,0 +1,57 @@ +import { Token } from '@sinclair/parsebox' +import { Assert } from 'test' + +const Test = Assert.Context('Token.Span') + +// ------------------------------------------------------------------ +// SingleLine and MultiLine should be identical with the exception +// that SingleLine will fail if it encounters a NewLine +// ------------------------------------------------------------------ + +// ------------------------------------------------------------------ +// SingleLine +// ------------------------------------------------------------------ +Test('Should SingleLine Span 1', () => Assert.IsExact(Token.Span('(', ')', false, ' (hel\nlo) 1'), [])) +Test('Should SingleLine Span 2', () => Assert.IsExact(Token.Span('(', ')', false, ' (\n) 1'), [])) +Test('Should SingleLine Span 3', () => Assert.IsExact(Token.Span('(', ')', false, '()1'), ['', '1'])) +Test('Should SingleLine Span 4', () => Assert.IsExact(Token.Span('(', ')', false, '() 1'), ['', ' 1'])) +Test('Should SingleLine Span 5', () => Assert.IsExact(Token.Span('(', ')', false, ' () 1'), ['', ' 1'])) +Test('Should SingleLine Span 6', () => Assert.IsExact(Token.Span('(', ')', false, '(hello)'), ['hello', ''])) +Test('Should SingleLine Span 7', () => Assert.IsExact(Token.Span('(', ')', false, ' (hello)'), ['hello', ''])) +Test('Should SingleLine Span 8', () => Assert.IsExact(Token.Span('(', ')', false, ' (hello)'), ['hello', ''])) +Test('Should SingleLine Span 9', () => Assert.IsExact(Token.Span('(', ')', false, ' 1(hello)'), [])) +Test('Should SingleLine Span 10', () => Assert.IsExact(Token.Span('(', ')', false, ' (hello)1'), ['hello', '1'])) +Test('Should SingleLine Span 11', () => Assert.IsExact(Token.Span('(', ')', false, ' (hello) 1'), ['hello', ' 1'])) +Test('Should SingleLine Span 12', () => Assert.IsExact(Token.Span('((', '))', false, '((hello))'), ['hello', ''])) +Test('Should SingleLine Span 13', () => Assert.IsExact(Token.Span('((', '))', false, '((hello))1'), ['hello', '1'])) +Test('Should SingleLine Span 14', () => Assert.IsExact(Token.Span('((', '))', false, '((hello)) 1'), ['hello', ' 1'])) +Test('Should SingleLine Span 15', () => Assert.IsExact(Token.Span('(', '))', false, '((hello))'), ['(hello', ''])) +Test('Should SingleLine Span 16', () => Assert.IsExact(Token.Span('(', '))', false, '((hello))1'), ['(hello', '1'])) +Test('Should SingleLine Span 17', () => Assert.IsExact(Token.Span('(', '))', false, '((hello)) 1'), ['(hello', ' 1'])) +Test('Should SingleLine Span 18', () => Assert.IsExact(Token.Span('((', ')', false, '((hello))'), ['hello', ')'])) +Test('Should SingleLine Span 19', () => Assert.IsExact(Token.Span('((', ')', false, '((hello))1'), ['hello', ')1'])) +Test('Should SingleLine Span 20', () => Assert.IsExact(Token.Span('((', ')', false, '((hello)) 1'), ['hello', ') 1'])) + +// ------------------------------------------------------------------ +// MultiLine +// ------------------------------------------------------------------ +Test('Should MultiLine Span 1', () => Assert.IsExact(Token.Span('(', ')', true, ' (hel\nlo) 1'), ['hel\nlo', ' 1'])) +Test('Should MultiLine Span 2', () => Assert.IsExact(Token.Span('(', ')', true, ' (\n) 1'), ['\n', ' 1'])) +Test('Should MultiLine Span 3', () => Assert.IsExact(Token.Span('(', ')', true, '()1'), ['', '1'])) +Test('Should MultiLine Span 4', () => Assert.IsExact(Token.Span('(', ')', true, '() 1'), ['', ' 1'])) +Test('Should MultiLine Span 5', () => Assert.IsExact(Token.Span('(', ')', true, ' () 1'), ['', ' 1'])) +Test('Should MultiLine Span 6', () => Assert.IsExact(Token.Span('(', ')', true, '(hello)'), ['hello', ''])) +Test('Should MultiLine Span 7', () => Assert.IsExact(Token.Span('(', ')', true, ' (hello)'), ['hello', ''])) +Test('Should MultiLine Span 8', () => Assert.IsExact(Token.Span('(', ')', true, ' (hello)'), ['hello', ''])) +Test('Should MultiLine Span 9', () => Assert.IsExact(Token.Span('(', ')', true, ' 1(hello)'), [])) +Test('Should MultiLine Span 10', () => Assert.IsExact(Token.Span('(', ')', true, ' (hello)1'), ['hello', '1'])) +Test('Should MultiLine Span 11', () => Assert.IsExact(Token.Span('(', ')', true, ' (hello) 1'), ['hello', ' 1'])) +Test('Should MultiLine Span 12', () => Assert.IsExact(Token.Span('((', '))', true, '((hello))'), ['hello', ''])) +Test('Should MultiLine Span 13', () => Assert.IsExact(Token.Span('((', '))', true, '((hello))1'), ['hello', '1'])) +Test('Should MultiLine Span 14', () => Assert.IsExact(Token.Span('((', '))', true, '((hello)) 1'), ['hello', ' 1'])) +Test('Should MultiLine Span 15', () => Assert.IsExact(Token.Span('(', '))', true, '((hello))'), ['(hello', ''])) +Test('Should MultiLine Span 16', () => Assert.IsExact(Token.Span('(', '))', true, '((hello))1'), ['(hello', '1'])) +Test('Should MultiLine Span 17', () => Assert.IsExact(Token.Span('(', '))', true, '((hello)) 1'), ['(hello', ' 1'])) +Test('Should MultiLine Span 18', () => Assert.IsExact(Token.Span('((', ')', true, '((hello))'), ['hello', ')'])) +Test('Should MultiLine Span 19', () => Assert.IsExact(Token.Span('((', ')', true, '((hello))1'), ['hello', ')1'])) +Test('Should MultiLine Span 20', () => Assert.IsExact(Token.Span('((', ')', true, '((hello)) 1'), ['hello', ') 1'])) diff --git a/test/parsebox/token/string.ts b/test/parsebox/token/string.ts new file mode 100644 index 0000000..3afb48a --- /dev/null +++ b/test/parsebox/token/string.ts @@ -0,0 +1,96 @@ +import { Token } from '@sinclair/parsebox' +import { Assert } from 'test' + +const Test = Assert.Context('Token.String') + +// ------------------------------------------------------------------ +// Const: Empty +// ------------------------------------------------------------------ +Test('Should String 1', () => Assert.IsExact(Token.String([`'`, `"`], ''), [])) + +// ------------------------------------------------------------------ +// DoubleQuote +// ------------------------------------------------------------------ +Test('Should String 2', () => Assert.IsExact(Token.String([`'`, `"`], `"A"`), ['A', ''])) +Test('Should String 3', () => Assert.IsExact(Token.String([`'`, `"`], ` "A"`), ['A', ''])) +Test('Should String 4', () => Assert.IsExact(Token.String([`'`, `"`], `"A" `), ['A', ' '])) +Test('Should String 5', () => Assert.IsExact(Token.String([`'`, `"`], ` "A" `), ['A', ' '])) + +// ------------------------------------------------------------------ +// SingleQuote +// ------------------------------------------------------------------ +Test('Should String 6', () => Assert.IsExact(Token.String([`'`, `"`], `'A'`), ['A', ''])) +Test('Should String 7', () => Assert.IsExact(Token.String([`'`, `"`], ` 'A'`), ['A', ''])) +Test('Should String 8', () => Assert.IsExact(Token.String([`'`, `"`], `'A' `), ['A', ' '])) +Test('Should String 9', () => Assert.IsExact(Token.String([`'`, `"`], ` 'A' `), ['A', ' '])) + +// ------------------------------------------------------------------ +// Embedded +// ------------------------------------------------------------------ +Test('Should String 10', () => Assert.IsExact(Token.String([`'`, `"`], ` "A'" `), [`A'`, ' '])) +Test('Should String 11', () => Assert.IsExact(Token.String([`'`, `"`], ` 'A"' `), [`A"`, ' '])) + +// ------------------------------------------------------------------ +// Multi-Characters +// ------------------------------------------------------------------ +Test('Should String 12', () => Assert.IsExact(Token.String([`'`, `"`], `"Hello"`), ['Hello', ''])) +Test('Should String 13', () => Assert.IsExact(Token.String([`'`, `"`], `'World'`), ['World', ''])) +Test('Should String 14', () => Assert.IsExact(Token.String([`'`, `"`], ` "Hello"`), ['Hello', ''])) +Test('Should String 15', () => Assert.IsExact(Token.String([`'`, `"`], `'World' `), ['World', ' '])) + +// ------------------------------------------------------------------ +// Spaces +// ------------------------------------------------------------------ +Test('Should String 16', () => Assert.IsExact(Token.String([`'`, `"`], `"Hello World"`), ['Hello World', ''])) +Test('Should String 17', () => Assert.IsExact(Token.String([`'`, `"`], `'Hello World' `), ['Hello World', ' '])) +Test('Should String 18', () => Assert.IsExact(Token.String([`'`, `"`], ` "Hello World" `), ['Hello World', ' '])) + +// ------------------------------------------------------------------ +// Empty +// ------------------------------------------------------------------ +Test('Should String 19', () => Assert.IsExact(Token.String([`'`, `"`], `""`), ['', ''])) +Test('Should String 20', () => Assert.IsExact(Token.String([`'`, `"`], `''`), ['', ''])) +Test('Should String 21', () => Assert.IsExact(Token.String([`'`, `"`], ` " "`), [' ', ''])) + +// ------------------------------------------------------------------ +// Spaces Only +// ------------------------------------------------------------------ +Test('Should String 22', () => Assert.IsExact(Token.String([`'`, `"`], `" "`), [' ', ''])) +Test('Should String 23', () => Assert.IsExact(Token.String([`'`, `"`], `' '`), [' ', ''])) + +// ------------------------------------------------------------------ +// Unclosed +// ------------------------------------------------------------------ +Test('Should String 24', () => Assert.IsExact(Token.String([`'`, `"`], `"Unclosed`), [])) +Test('Should String 25', () => Assert.IsExact(Token.String([`'`, `"`], `'Unclosed`), [])) + +// ------------------------------------------------------------------ +// Adjacent quotes +// ------------------------------------------------------------------ +Test('Should String 26', () => Assert.IsExact(Token.String([`'`, `"`], `""""`), ['', '""'])) +Test('Should String 27', () => Assert.IsExact(Token.String([`'`, `"`], `''''`), ['', "''"])) + +// ------------------------------------------------------------------ +// Quotes with numbers inside +// ------------------------------------------------------------------ +Test('Should String 28', () => Assert.IsExact(Token.String([`'`, `"`], `"123"`), ['123', ''])) +Test('Should String 29', () => Assert.IsExact(Token.String([`'`, `"`], `'456' `), ['456', ' '])) + +// ------------------------------------------------------------------ +// Quotes next to other characters (should only consume first valid string) +// ------------------------------------------------------------------ +Test('Should String 30', () => Assert.IsExact(Token.String([`'`, `"`], `"Hello"'World'`), ['Hello', `'World'`])) +Test('Should String 31', () => Assert.IsExact(Token.String([`'`, `"`], `'Hello'"World"`), ['Hello', `"World"`])) + +// ------------------------------------------------------------------ +// Only whitespace before/after quotes +// ------------------------------------------------------------------ +Test('Should String 32', () => Assert.IsExact(Token.String([`'`, `"`], ` "Hi"`), ['Hi', ''])) +Test('Should String 33', () => Assert.IsExact(Token.String([`'`, `"`], `'Hi' `), ['Hi', ' '])) +Test('Should String 34', () => Assert.IsExact(Token.String([`'`, `"`], ` 'Hi' `), ['Hi', ' '])) + +// ------------------------------------------------------------------ +// Quotes with punctuation inside +// ------------------------------------------------------------------ +Test('Should String 35', () => Assert.IsExact(Token.String([`'`, `"`], `"Hello!"`), ['Hello!', ''])) +Test('Should String 36', () => Assert.IsExact(Token.String([`'`, `"`], `'Wow?!'`), ['Wow?!', ''])) diff --git a/test/parsebox/token/until.ts b/test/parsebox/token/until.ts new file mode 100644 index 0000000..46b4679 --- /dev/null +++ b/test/parsebox/token/until.ts @@ -0,0 +1,168 @@ +import { Token } from '@sinclair/parsebox' +import { Assert } from 'test' + +const Test = Assert.Context('Token.Until') + +// ------------------------------------------------------------------ +// Until: Empty +// ------------------------------------------------------------------ +Test('Should Until 1', () => Assert.IsExact(Token.Until([''], ''), [])) +Test('Should Until 2', () => Assert.IsExact(Token.Until([''], 'A'), ['', 'A'])) +Test('Should Until 3', () => Assert.IsExact(Token.Until([''], ' A'), ['', ' A'])) + +// ------------------------------------------------------------------ +// Until: Single-Char +// ------------------------------------------------------------------ +Test('Should Until 4', () => Assert.IsExact(Token.Until(['A'], 'A'), ['', 'A'])) +Test('Should Until 5', () => Assert.IsExact(Token.Until(['A'], 'A '), ['', 'A '])) +Test('Should Until 6', () => Assert.IsExact(Token.Until(['A'], 'AA'), ['', 'AA'])) +Test('Should Until 7', () => Assert.IsExact(Token.Until(['A'], 'AA '), ['', 'AA '])) + +// ------------------------------------------------------------------ +// Until: Multi-Char +// ------------------------------------------------------------------ +Test('Should Until 8', () => Assert.IsExact(Token.Until(['AB'], 'AB'), ['', 'AB'])) +Test('Should Until 9', () => Assert.IsExact(Token.Until(['AB'], 'AB '), ['', 'AB '])) +Test('Should Until 10', () => Assert.IsExact(Token.Until(['AB'], 'ABA'), ['', 'ABA'])) +Test('Should Until 11', () => Assert.IsExact(Token.Until(['AB'], 'ABA '), ['', 'ABA '])) + +// ------------------------------------------------------------------ +// Until: Single-Char -> Ignore-Whitespace +// ------------------------------------------------------------------ +Test('Should Until 12', () => Assert.IsExact(Token.Until(['A'], ' A'), [' ', 'A'])) +Test('Should Until 13', () => Assert.IsExact(Token.Until(['A'], ' A '), [' ', 'A '])) +Test('Should Until 14', () => Assert.IsExact(Token.Until(['A'], ' AA'), [' ', 'AA'])) +Test('Should Until 15', () => Assert.IsExact(Token.Until(['A'], ' AA '), [' ', 'AA '])) +Test('Should Until 16', () => Assert.IsExact(Token.Until(['A'], '\nAA '), ['\n', 'AA '])) +Test('Should Until 17', () => Assert.IsExact(Token.Until(['A'], ' \nAA '), [' \n', 'AA '])) +Test('Should Until 18', () => Assert.IsExact(Token.Until(['A'], '\n AA '), ['\n ', 'AA '])) +Test('Should Until 19', () => Assert.IsExact(Token.Until(['A'], ' \n AA '), [' \n ', 'AA '])) + +// ------------------------------------------------------------------ +// Until: Multi-Char -> Ignore-Whitespace +// ------------------------------------------------------------------ +Test('Should Until 20', () => Assert.IsExact(Token.Until(['AB'], ' AB'), [' ', 'AB'])) +Test('Should Until 21', () => Assert.IsExact(Token.Until(['AB'], ' AB '), [' ', 'AB '])) +Test('Should Until 22', () => Assert.IsExact(Token.Until(['AB'], ' ABA'), [' ', 'ABA'])) +Test('Should Until 23', () => Assert.IsExact(Token.Until(['AB'], ' ABA '), [' ', 'ABA '])) +Test('Should Until 24', () => Assert.IsExact(Token.Until(['AB'], '\nABA '), ['\n', 'ABA '])) +Test('Should Until 25', () => Assert.IsExact(Token.Until(['AB'], ' \nABA '), [' \n', 'ABA '])) +Test('Should Until 26', () => Assert.IsExact(Token.Until(['AB'], '\n ABA '), ['\n ', 'ABA '])) +Test('Should Until 27', () => Assert.IsExact(Token.Until(['AB'], ' \n ABA '), [' \n ', 'ABA '])) + +// ------------------------------------------------------------------ +// Until: Single-Whitespace +// ------------------------------------------------------------------ +Test('Should Until 28', () => Assert.IsExact(Token.Until([' '], ''), [])) +Test('Should Until 29', () => Assert.IsExact(Token.Until([' '], ' '), ['', ' '])) +Test('Should Until 30', () => Assert.IsExact(Token.Until([' '], ' A'), ['', ' A'])) +Test('Should Until 31', () => Assert.IsExact(Token.Until([' '], ' A '), ['', ' A '])) +Test('Should Until 32', () => Assert.IsExact(Token.Until([' '], ' AA'), ['', ' AA'])) +Test('Should Until 33', () => Assert.IsExact(Token.Until([' '], ' AA '), ['', ' AA '])) + +// ------------------------------------------------------------------ +// Until: Multi-Whitespace +// ------------------------------------------------------------------ +Test('Should Until 34', () => Assert.IsExact(Token.Until([' '], ''), [])) +Test('Should Until 35', () => Assert.IsExact(Token.Until([' '], ' '), [])) +Test('Should Until 36', () => Assert.IsExact(Token.Until([' '], ' A'), ['', ' A'])) +Test('Should Until 37', () => Assert.IsExact(Token.Until([' '], ' A '), ['', ' A '])) +Test('Should Until 38', () => Assert.IsExact(Token.Until([' '], ' AA'), ['', ' AA'])) +Test('Should Until 39', () => Assert.IsExact(Token.Until([' '], ' AA '), ['', ' AA '])) + +// ------------------------------------------------------------------ +// Until: Newline +// ------------------------------------------------------------------ +Test('Should Until 40', () => Assert.IsExact(Token.Until(['\n'], ''), [])) +Test('Should Until 41', () => Assert.IsExact(Token.Until(['\n'], ' '), [])) +Test('Should Until 42', () => Assert.IsExact(Token.Until(['\n'], '\nA'), ['', '\nA'])) +Test('Should Until 43', () => Assert.IsExact(Token.Until(['\n'], ' \nA '), [' ', '\nA '])) +Test('Should Until 44', () => Assert.IsExact(Token.Until(['\n'], ' \nAA'), [' ', '\nAA'])) +Test('Should Until 45', () => Assert.IsExact(Token.Until(['\n'], ' \nAA '), [' ', '\nAA '])) + +// ------------------------------------------------------------------ +// Until: Newline-Single-Whitespace +// ------------------------------------------------------------------ +Test('Should Until 46', () => Assert.IsExact(Token.Until(['\n '], ''), [])) +Test('Should Until 47', () => Assert.IsExact(Token.Until(['\n '], ' '), [])) +Test('Should Until 48', () => Assert.IsExact(Token.Until(['\n '], '\nA'), [])) +Test('Should Until 49', () => Assert.IsExact(Token.Until(['\n '], ' \nA '), [])) +Test('Should Until 50', () => Assert.IsExact(Token.Until(['\n '], ' \nAA'), [])) +Test('Should Until 51', () => Assert.IsExact(Token.Until(['\n '], ' \nAA '), [])) +Test('Should Until 52', () => Assert.IsExact(Token.Until(['\n '], '\n A'), ['', '\n A'])) +Test('Should Until 53', () => Assert.IsExact(Token.Until(['\n '], ' \n A '), [' ', '\n A '])) +Test('Should Until 54', () => Assert.IsExact(Token.Until(['\n '], ' \n AA'), [' ', '\n AA'])) +Test('Should Until 55', () => Assert.IsExact(Token.Until(['\n '], ' \n AA '), [' ', '\n AA '])) + +// ------------------------------------------------------------------ +// Until: Newline-Multi-Whitespace +// ------------------------------------------------------------------ +Test('Should Until 56', () => Assert.IsExact(Token.Until(['\n '], ''), [])) +Test('Should Until 57', () => Assert.IsExact(Token.Until(['\n '], ' '), [])) +Test('Should Until 58', () => Assert.IsExact(Token.Until(['\n '], '\nA'), [])) +Test('Should Until 59', () => Assert.IsExact(Token.Until(['\n '], ' \nA '), [])) +Test('Should Until 60', () => Assert.IsExact(Token.Until(['\n '], ' \nAA'), [])) +Test('Should Until 61', () => Assert.IsExact(Token.Until(['\n '], ' \nAA '), [])) +Test('Should Until 62', () => Assert.IsExact(Token.Until(['\n '], '\n A'), ['', '\n A'])) +Test('Should Until 63', () => Assert.IsExact(Token.Until(['\n '], ' \n A '), [' ', '\n A '])) +Test('Should Until 64', () => Assert.IsExact(Token.Until(['\n '], ' \n AA'), [' ', '\n AA'])) +Test('Should Until 65', () => Assert.IsExact(Token.Until(['\n '], ' \n AA '), [' ', '\n AA '])) + +// ------------------------------------------------------------------ +// Until: Multi Sentinal Test +// ------------------------------------------------------------------ +Test('Should Until 66', () => Assert.IsExact(Token.Until(['A', 'B'], ''), [])) +Test('Should Until 67', () => Assert.IsExact(Token.Until(['A', 'B'], 'A'), ['', 'A'])) +Test('Should Until 68', () => Assert.IsExact(Token.Until(['A', 'B'], 'B'), ['', 'B'])) +Test('Should Until 69', () => Assert.IsExact(Token.Until(['A', 'B'], 'AB'), ['', 'AB'])) +Test('Should Until 70', () => Assert.IsExact(Token.Until(['A', 'B'], 'BA'), ['', 'BA'])) +Test('Should Until 71', () => Assert.IsExact(Token.Until(['A', 'B'], ' AB'), [' ', 'AB'])) +Test('Should Until 72', () => Assert.IsExact(Token.Until(['A', 'B'], ' BA'), [' ', 'BA'])) +Test('Should Until 73', () => Assert.IsExact(Token.Until(['A', ' B'], ' BA'), [' ', ' BA'])) +Test('Should Until 74', () => Assert.IsExact(Token.Until([' A', 'B'], ' BA'), [' ', 'BA'])) +Test('Should Until 75', () => Assert.IsExact(Token.Until(['B', 'A'], ' AB'), [' ', 'AB'])) +Test('Should Until 76', () => Assert.IsExact(Token.Until(['B', 'A'], ' BA'), [' ', 'BA'])) +Test('Should Until 77', () => Assert.IsExact(Token.Until(['B', ' A'], ' BA'), [' ', 'BA'])) +Test('Should Until 78', () => Assert.IsExact(Token.Until([' B', 'A'], ' BA'), [' ', ' BA'])) + +// ------------------------------------------------------------------ +// Until: Empty-String Variants +// ------------------------------------------------------------------ +Test('Should Until 79', () => Assert.IsExact(Token.Until([''], ' '), ['', ' '])) +Test('Should Until 80', () => Assert.IsExact(Token.Until([''], '\n'), ['', '\n'])) +Test('Should Until 81', () => Assert.IsExact(Token.Until([''], '\n\n'), ['', '\n\n'])) + +// ------------------------------------------------------------------ +// Until: Mixed Characters & Whitespace +// ------------------------------------------------------------------ +Test('Should Until 82', () => Assert.IsExact(Token.Until(['A'], ' \n A'), [' \n ', 'A'])) +Test('Should Until 83', () => Assert.IsExact(Token.Until(['A'], '\tA'), ['\t', 'A'])) +Test('Should Until 84', () => Assert.IsExact(Token.Until(['AB'], '\tAB '), ['\t', 'AB '])) +Test('Should Until 85', () => Assert.IsExact(Token.Until(['AB'], ' \tAB '), [' \t', 'AB '])) +Test('Should Until 86', () => Assert.IsExact(Token.Until(['AB'], ' \t AB'), [' \t ', 'AB'])) + +// ------------------------------------------------------------------ +// Until: Multiple Sentinels with Overlaps +// ------------------------------------------------------------------ +Test('Should Until 87', () => Assert.IsExact(Token.Until(['A', 'AB'], 'AB'), ['', 'AB'])) +Test('Should Until 88', () => Assert.IsExact(Token.Until(['AB', 'A'], 'AB'), ['', 'AB'])) +Test('Should Until 89', () => Assert.IsExact(Token.Until(['A', 'AB'], 'AAB'), ['', 'AAB'])) +Test('Should Until 90', () => Assert.IsExact(Token.Until(['AB', 'A'], 'AAB'), ['', 'AAB'])) +Test('Should Until 91', () => Assert.IsExact(Token.Until(['AB', 'B'], 'ABB'), ['', 'ABB'])) + +// ------------------------------------------------------------------ +// Until: Only Whitespace with Multi-Sentinels +// ------------------------------------------------------------------ +Test('Should Until 92', () => Assert.IsExact(Token.Until([' ', '\n'], ' \nA'), ['', ' \nA'])) +Test('Should Until 93', () => Assert.IsExact(Token.Until([' ', '\n'], ' \nA'), ['', ' \nA'])) +Test('Should Until 94', () => Assert.IsExact(Token.Until(['\n', ' '], ' \nA'), ['', ' \nA'])) +Test('Should Until 95', () => Assert.IsExact(Token.Until(['\n', ' '], '\n A'), ['', '\n A'])) + +// ------------------------------------------------------------------ +// Until: Leading/Trailing Whitespace with Multiple Sentinels +// ------------------------------------------------------------------ +Test('Should Until 96', () => Assert.IsExact(Token.Until(['A', 'B'], ' A B'), [' ', 'A B'])) +Test('Should Until 97', () => Assert.IsExact(Token.Until(['A', 'B'], ' B A'), [' ', 'B A'])) +Test('Should Until 98', () => Assert.IsExact(Token.Until(['AB', 'BA'], ' AB BA '), [' ', 'AB BA '])) +Test('Should Until 99', () => Assert.IsExact(Token.Until(['AB', 'BA'], ' BA AB '), [' ', 'BA AB '])) +Test('Should Until 100', () => Assert.IsExact(Token.Until(['AB', 'BA'], '\nAB BA'), ['\n', 'AB BA'])) diff --git a/test/parsebox/token/until_1.ts b/test/parsebox/token/until_1.ts new file mode 100644 index 0000000..ba60886 --- /dev/null +++ b/test/parsebox/token/until_1.ts @@ -0,0 +1,168 @@ +import { Token } from '@sinclair/parsebox' +import { Assert } from 'test' + +const Test = Assert.Context('Token.Until_1') + +// ------------------------------------------------------------------ +// Until_1: Empty +// ------------------------------------------------------------------ +Test('Should Until_1 1', () => Assert.IsExact(Token.Until_1([''], ''), [])) +Test('Should Until_1 2', () => Assert.IsExact(Token.Until_1([''], 'A'), [])) +Test('Should Until_1 3', () => Assert.IsExact(Token.Until_1([''], ' A'), [])) + +// ------------------------------------------------------------------ +// Until_1: Single-Char +// ------------------------------------------------------------------ +Test('Should Until_1 4', () => Assert.IsExact(Token.Until_1(['A'], 'A'), [])) +Test('Should Until_1 5', () => Assert.IsExact(Token.Until_1(['A'], 'A '), [])) +Test('Should Until_1 6', () => Assert.IsExact(Token.Until_1(['A'], 'AA'), [])) +Test('Should Until_1 7', () => Assert.IsExact(Token.Until_1(['A'], 'AA '), [])) + +// ------------------------------------------------------------------ +// Until_1: Multi-Char +// ------------------------------------------------------------------ +Test('Should Until_1 8', () => Assert.IsExact(Token.Until_1(['AB'], 'AB'), [])) +Test('Should Until_1 9', () => Assert.IsExact(Token.Until_1(['AB'], 'AB '), [])) +Test('Should Until_1 10', () => Assert.IsExact(Token.Until_1(['AB'], 'ABA'), [])) +Test('Should Until_1 11', () => Assert.IsExact(Token.Until_1(['AB'], 'ABA '), [])) + +// ------------------------------------------------------------------ +// Until_1: Single-Char -> Ignore-Whitespace +// ------------------------------------------------------------------ +Test('Should Until_1 12', () => Assert.IsExact(Token.Until_1(['A'], ' A'), [' ', 'A'])) +Test('Should Until_1 13', () => Assert.IsExact(Token.Until_1(['A'], ' A '), [' ', 'A '])) +Test('Should Until_1 14', () => Assert.IsExact(Token.Until_1(['A'], ' AA'), [' ', 'AA'])) +Test('Should Until_1 15', () => Assert.IsExact(Token.Until_1(['A'], ' AA '), [' ', 'AA '])) +Test('Should Until_1 16', () => Assert.IsExact(Token.Until_1(['A'], '\nAA '), ['\n', 'AA '])) +Test('Should Until_1 17', () => Assert.IsExact(Token.Until_1(['A'], ' \nAA '), [' \n', 'AA '])) +Test('Should Until_1 18', () => Assert.IsExact(Token.Until_1(['A'], '\n AA '), ['\n ', 'AA '])) +Test('Should Until_1 19', () => Assert.IsExact(Token.Until_1(['A'], ' \n AA '), [' \n ', 'AA '])) + +// ------------------------------------------------------------------ +// Until_1: Multi-Char -> Ignore-Whitespace +// ------------------------------------------------------------------ +Test('Should Until_1 20', () => Assert.IsExact(Token.Until_1(['AB'], ' AB'), [' ', 'AB'])) +Test('Should Until_1 21', () => Assert.IsExact(Token.Until_1(['AB'], ' AB '), [' ', 'AB '])) +Test('Should Until_1 22', () => Assert.IsExact(Token.Until_1(['AB'], ' ABA'), [' ', 'ABA'])) +Test('Should Until_1 23', () => Assert.IsExact(Token.Until_1(['AB'], ' ABA '), [' ', 'ABA '])) +Test('Should Until_1 24', () => Assert.IsExact(Token.Until_1(['AB'], '\nABA '), ['\n', 'ABA '])) +Test('Should Until_1 25', () => Assert.IsExact(Token.Until_1(['AB'], ' \nABA '), [' \n', 'ABA '])) +Test('Should Until_1 26', () => Assert.IsExact(Token.Until_1(['AB'], '\n ABA '), ['\n ', 'ABA '])) +Test('Should Until_1 27', () => Assert.IsExact(Token.Until_1(['AB'], ' \n ABA '), [' \n ', 'ABA '])) + +// ------------------------------------------------------------------ +// Until_1: Single-Whitespace +// ------------------------------------------------------------------ +Test('Should Until_1 28', () => Assert.IsExact(Token.Until_1([' '], ''), [])) +Test('Should Until_1 29', () => Assert.IsExact(Token.Until_1([' '], ' '), [])) +Test('Should Until_1 30', () => Assert.IsExact(Token.Until_1([' '], ' A'), [])) +Test('Should Until_1 31', () => Assert.IsExact(Token.Until_1([' '], ' A '), [])) +Test('Should Until_1 32', () => Assert.IsExact(Token.Until_1([' '], ' AA'), [])) +Test('Should Until_1 33', () => Assert.IsExact(Token.Until_1([' '], ' AA '), [])) + +// ------------------------------------------------------------------ +// Until_1: Multi-Whitespace +// ------------------------------------------------------------------ +Test('Should Until_1 34', () => Assert.IsExact(Token.Until_1([' '], ''), [])) +Test('Should Until_1 35', () => Assert.IsExact(Token.Until_1([' '], ' '), [])) +Test('Should Until_1 36', () => Assert.IsExact(Token.Until_1([' '], ' A'), [])) +Test('Should Until_1 37', () => Assert.IsExact(Token.Until_1([' '], ' A '), [])) +Test('Should Until_1 38', () => Assert.IsExact(Token.Until_1([' '], ' AA'), [])) +Test('Should Until_1 39', () => Assert.IsExact(Token.Until_1([' '], ' AA '), [])) + +// ------------------------------------------------------------------ +// Until_1: Newline +// ------------------------------------------------------------------ +Test('Should Until_1 40', () => Assert.IsExact(Token.Until_1(['\n'], ''), [])) +Test('Should Until_1 41', () => Assert.IsExact(Token.Until_1(['\n'], ' '), [])) +Test('Should Until_1 42', () => Assert.IsExact(Token.Until_1(['\n'], '\nA'), [])) +Test('Should Until_1 43', () => Assert.IsExact(Token.Until_1(['\n'], ' \nA '), [' ', '\nA '])) +Test('Should Until_1 44', () => Assert.IsExact(Token.Until_1(['\n'], ' \nAA'), [' ', '\nAA'])) +Test('Should Until_1 45', () => Assert.IsExact(Token.Until_1(['\n'], ' \nAA '), [' ', '\nAA '])) + +// ------------------------------------------------------------------ +// Until_1: Newline-Single-Whitespace +// ------------------------------------------------------------------ +Test('Should Until_1 46', () => Assert.IsExact(Token.Until_1(['\n '], ''), [])) +Test('Should Until_1 47', () => Assert.IsExact(Token.Until_1(['\n '], ' '), [])) +Test('Should Until_1 48', () => Assert.IsExact(Token.Until_1(['\n '], '\nA'), [])) +Test('Should Until_1 49', () => Assert.IsExact(Token.Until_1(['\n '], ' \nA '), [])) +Test('Should Until_1 50', () => Assert.IsExact(Token.Until_1(['\n '], ' \nAA'), [])) +Test('Should Until_1 51', () => Assert.IsExact(Token.Until_1(['\n '], ' \nAA '), [])) +Test('Should Until_1 52', () => Assert.IsExact(Token.Until_1(['\n '], '\n A'), [])) +Test('Should Until_1 53', () => Assert.IsExact(Token.Until_1(['\n '], ' \n A '), [' ', '\n A '])) +Test('Should Until_1 54', () => Assert.IsExact(Token.Until_1(['\n '], ' \n AA'), [' ', '\n AA'])) +Test('Should Until_1 55', () => Assert.IsExact(Token.Until_1(['\n '], ' \n AA '), [' ', '\n AA '])) + +// ------------------------------------------------------------------ +// Until_1: Newline-Multi-Whitespace +// ------------------------------------------------------------------ +Test('Should Until_1 56', () => Assert.IsExact(Token.Until_1(['\n '], ''), [])) +Test('Should Until_1 57', () => Assert.IsExact(Token.Until_1(['\n '], ' '), [])) +Test('Should Until_1 58', () => Assert.IsExact(Token.Until_1(['\n '], '\nA'), [])) +Test('Should Until_1 59', () => Assert.IsExact(Token.Until_1(['\n '], ' \nA '), [])) +Test('Should Until_1 60', () => Assert.IsExact(Token.Until_1(['\n '], ' \nAA'), [])) +Test('Should Until_1 61', () => Assert.IsExact(Token.Until_1(['\n '], ' \nAA '), [])) +Test('Should Until_1 62', () => Assert.IsExact(Token.Until_1(['\n '], '\n A'), [])) +Test('Should Until_1 63', () => Assert.IsExact(Token.Until_1(['\n '], ' \n A '), [' ', '\n A '])) +Test('Should Until_1 64', () => Assert.IsExact(Token.Until_1(['\n '], ' \n AA'), [' ', '\n AA'])) +Test('Should Until_1 65', () => Assert.IsExact(Token.Until_1(['\n '], ' \n AA '), [' ', '\n AA '])) + +// ------------------------------------------------------------------ +// Until_1: Multi Sentinal Test +// ------------------------------------------------------------------ +Test('Should Until_1 66', () => Assert.IsExact(Token.Until_1(['A', 'B'], ''), [])) +Test('Should Until_1 67', () => Assert.IsExact(Token.Until_1(['A', 'B'], 'A'), [])) +Test('Should Until_1 68', () => Assert.IsExact(Token.Until_1(['A', 'B'], 'B'), [])) +Test('Should Until_1 69', () => Assert.IsExact(Token.Until_1(['A', 'B'], 'AB'), [])) +Test('Should Until_1 70', () => Assert.IsExact(Token.Until_1(['A', 'B'], 'BA'), [])) +Test('Should Until_1 71', () => Assert.IsExact(Token.Until_1(['A', 'B'], ' AB'), [' ', 'AB'])) +Test('Should Until_1 72', () => Assert.IsExact(Token.Until_1(['A', 'B'], ' BA'), [' ', 'BA'])) +Test('Should Until_1 73', () => Assert.IsExact(Token.Until_1(['A', ' B'], ' BA'), [' ', ' BA'])) +Test('Should Until_1 74', () => Assert.IsExact(Token.Until_1([' A', 'B'], ' BA'), [' ', 'BA'])) +Test('Should Until_1 75', () => Assert.IsExact(Token.Until_1(['B', 'A'], ' AB'), [' ', 'AB'])) +Test('Should Until_1 76', () => Assert.IsExact(Token.Until_1(['B', 'A'], ' BA'), [' ', 'BA'])) +Test('Should Until_1 77', () => Assert.IsExact(Token.Until_1(['B', ' A'], ' BA'), [' ', 'BA'])) +Test('Should Until_1 78', () => Assert.IsExact(Token.Until_1([' B', 'A'], ' BA'), [' ', ' BA'])) + +// ------------------------------------------------------------------ +// Until_1: Empty-String Variants +// ------------------------------------------------------------------ +Test('Should Until_1 79', () => Assert.IsExact(Token.Until_1([''], ' '), [])) +Test('Should Until_1 80', () => Assert.IsExact(Token.Until_1([''], '\n'), [])) +Test('Should Until_1 81', () => Assert.IsExact(Token.Until_1([''], '\n\n'), [])) + +// ------------------------------------------------------------------ +// Until_1: Mixed Characters & Whitespace +// ------------------------------------------------------------------ +Test('Should Until_1 82', () => Assert.IsExact(Token.Until_1(['A'], ' \n A'), [' \n ', 'A'])) +Test('Should Until_1 83', () => Assert.IsExact(Token.Until_1(['A'], '\tA'), ['\t', 'A'])) +Test('Should Until_1 84', () => Assert.IsExact(Token.Until_1(['AB'], '\tAB '), ['\t', 'AB '])) +Test('Should Until_1 85', () => Assert.IsExact(Token.Until_1(['AB'], ' \tAB '), [' \t', 'AB '])) +Test('Should Until_1 86', () => Assert.IsExact(Token.Until_1(['AB'], ' \t AB'), [' \t ', 'AB'])) + +// ------------------------------------------------------------------ +// Until_1: Multiple Sentinels with Overlaps +// ------------------------------------------------------------------ +Test('Should Until_1 87', () => Assert.IsExact(Token.Until_1(['A', 'AB'], 'AB'), [])) +Test('Should Until_1 88', () => Assert.IsExact(Token.Until_1(['AB', 'A'], 'AB'), [])) +Test('Should Until_1 89', () => Assert.IsExact(Token.Until_1(['A', 'AB'], 'AAB'), [])) +Test('Should Until_1 90', () => Assert.IsExact(Token.Until_1(['AB', 'A'], 'AAB'), [])) +Test('Should Until_1 91', () => Assert.IsExact(Token.Until_1(['AB', 'B'], 'ABB'), [])) + +// ------------------------------------------------------------------ +// Until_1: Only Whitespace with Multi-Sentinels +// ------------------------------------------------------------------ +Test('Should Until_1 92', () => Assert.IsExact(Token.Until_1([' ', '\n'], ' \nA'), [])) +Test('Should Until_1 93', () => Assert.IsExact(Token.Until_1([' ', '\n'], ' \nA'), [])) +Test('Should Until_1 94', () => Assert.IsExact(Token.Until_1(['\n', ' '], ' \nA'), [])) +Test('Should Until_1 95', () => Assert.IsExact(Token.Until_1(['\n', ' '], '\n A'), [])) + +// ------------------------------------------------------------------ +// Until_1: Leading/Trailing Whitespace with Multiple Sentinels +// ------------------------------------------------------------------ +Test('Should Until_1 96', () => Assert.IsExact(Token.Until_1(['A', 'B'], ' A B'), [' ', 'A B'])) +Test('Should Until_1 97', () => Assert.IsExact(Token.Until_1(['A', 'B'], ' B A'), [' ', 'B A'])) +Test('Should Until_1 98', () => Assert.IsExact(Token.Until_1(['AB', 'BA'], ' AB BA '), [' ', 'AB BA '])) +Test('Should Until_1 99', () => Assert.IsExact(Token.Until_1(['AB', 'BA'], ' BA AB '), [' ', 'BA AB '])) +Test('Should Until_1 100', () => Assert.IsExact(Token.Until_1(['AB', 'BA'], '\nAB BA'), ['\n', 'AB BA'])) diff --git a/test/tsconfig.json b/test/tsconfig.json deleted file mode 100644 index 9f4a7e2..0000000 --- a/test/tsconfig.json +++ /dev/null @@ -1,4 +0,0 @@ -{ - "extends": "../tsconfig.json", - "files": ["index.ts"] -}