From e16a278a51f1a60bebf96c81df4acd2f8aadec4e Mon Sep 17 00:00:00 2001 From: Joram van den Boezem Date: Tue, 22 Mar 2022 10:54:42 +0000 Subject: [PATCH 01/10] test: initialize type tests --- examples/cat.ts | 2 +- package.json | 6 +- test-d/command.test-d.ts | 6 + test-d/program.test-d.ts | 6 + tests/program.spec.ts | 4 +- yarn.lock | 491 +++++++++++++++++++++++++++++++++++++-- 6 files changed, 496 insertions(+), 19 deletions(-) create mode 100644 test-d/command.test-d.ts create mode 100644 test-d/program.test-d.ts diff --git a/examples/cat.ts b/examples/cat.ts index 411fce97..1e2f8713 100644 --- a/examples/cat.ts +++ b/examples/cat.ts @@ -3,7 +3,7 @@ import { command, program } from '../src' const cat = command('cat') .description('Concatenate files') - .argument('files', { variadic: true }) + .argument('files', { variadic: true, default: [] }) .action(({ files }) => console.log( files.reduce((str, file) => str + readFileSync(file, 'utf8'), '') diff --git a/package.json b/package.json index de69d5d8..69e87376 100644 --- a/package.json +++ b/package.json @@ -22,12 +22,13 @@ "files": [ "lib" ], + "types": "lib/index.d.ts", "scripts": { "prepublishOnly": "yarn build", "build": "tsc", "watch": "tsc --watch", "lint": "prettier --write \"src/**/*\"", - "test": "jest", + "test": "tsd && jest", "start": "ts-node", "doc:toc": "doctoc README.md", "doc:todos": "leasot --exit-nicely --reporter markdown \"src/**/*.ts\" > TODO.md" @@ -57,6 +58,7 @@ "prettier": "2.6.0", "ts-jest": "27.1.3", "ts-node": "10.7.0", + "tsd": "^0.19.1", "typescript": "4.6.2" } -} +} \ No newline at end of file diff --git a/test-d/command.test-d.ts b/test-d/command.test-d.ts new file mode 100644 index 00000000..1caf995c --- /dev/null +++ b/test-d/command.test-d.ts @@ -0,0 +1,6 @@ +import { expectType } from 'tsd' +import { Command, command } from '../src/command' + +const cmd = command() + +expectType(cmd) diff --git a/test-d/program.test-d.ts b/test-d/program.test-d.ts new file mode 100644 index 00000000..333ddb47 --- /dev/null +++ b/test-d/program.test-d.ts @@ -0,0 +1,6 @@ +import { expectType } from 'tsd' +import { Program, program } from '../src/program' + +const app = program() + +expectType(app) diff --git a/tests/program.spec.ts b/tests/program.spec.ts index ecbb122e..80a9a0f2 100644 --- a/tests/program.spec.ts +++ b/tests/program.spec.ts @@ -1,6 +1,4 @@ -// @ts-ignore import mockArgv from 'mock-argv' -import { mocked } from 'ts-jest/utils' import { command, program, Program, Repl } from '../src' jest.mock('../src/repl', () => { @@ -22,7 +20,7 @@ class MockedRepl { } beforeEach(() => { - const MockedRepl = mocked(Repl, true) + const MockedRepl = jest.mocked(Repl, true) MockedRepl.mockClear() }) diff --git a/yarn.lock b/yarn.lock index f8aa9a9f..fb87e6d4 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1275,6 +1275,16 @@ __metadata: languageName: node linkType: hard +"@tsd/typescript@npm:~4.5.2": + version: 4.5.5 + resolution: "@tsd/typescript@npm:4.5.5" + bin: + tsc: typescript/bin/tsc + tsserver: typescript/bin/tsserver + checksum: 6b57a087b713530966f073b47837c47a52adf7f4b036495853283ff0a6d7b39ec6d6a59105ca4708bb715f7a8551f4dd004de20ca0b72c396103c360841b6aab + languageName: node + linkType: hard + "@types/babel__core@npm:^7.0.0": version: 7.1.9 resolution: "@types/babel__core@npm:7.1.9" @@ -1345,6 +1355,23 @@ __metadata: languageName: node linkType: hard +"@types/eslint@npm:^7.2.13": + version: 7.29.0 + resolution: "@types/eslint@npm:7.29.0" + dependencies: + "@types/estree": "*" + "@types/json-schema": "*" + checksum: df13991c554954353ce8f3bb03e19da6cc71916889443d68d178d4f858b561ba4cc4a4f291c6eb9eebb7f864b12b9b9313051b3a8dfea3e513dadf3188a77bdf + languageName: node + linkType: hard + +"@types/estree@npm:*": + version: 0.0.51 + resolution: "@types/estree@npm:0.0.51" + checksum: e56a3bcf759fd9185e992e7fdb3c6a5f81e8ff120e871641607581fb3728d16c811702a7d40fa5f869b7f7b4437ab6a87eb8d98ffafeee51e85bbe955932a189 + languageName: node + linkType: hard + "@types/graceful-fs@npm:^4.1.2": version: 4.1.3 resolution: "@types/graceful-fs@npm:4.1.3" @@ -1389,6 +1416,20 @@ __metadata: languageName: node linkType: hard +"@types/json-schema@npm:*": + version: 7.0.10 + resolution: "@types/json-schema@npm:7.0.10" + checksum: 369f12207298e3c8931100ab86c9c60d9217ab930a8ae0b851495f4f30695d3f0eb431eedc8e8d9c69357869899ea0fe6f9d65ddde5ea70415d67ef340dfdd1f + languageName: node + linkType: hard + +"@types/minimist@npm:^1.2.0": + version: 1.2.2 + resolution: "@types/minimist@npm:1.2.2" + checksum: b8da83c66eb4aac0440e64674b19564d9d86c80ae273144db9681e5eeff66f238ade9515f5006ffbfa955ceff8b89ad2bd8ec577d7caee74ba101431fb07045d + languageName: node + linkType: hard + "@types/node@npm:*": version: 14.0.26 resolution: "@types/node@npm:14.0.26" @@ -1403,6 +1444,13 @@ __metadata: languageName: node linkType: hard +"@types/normalize-package-data@npm:^2.4.0": + version: 2.4.1 + resolution: "@types/normalize-package-data@npm:2.4.1" + checksum: e87bccbf11f95035c89a132b52b79ce69a1e3652fe55962363063c9c0dae0fe2477ebc585e03a9652adc6f381d24ba5589cc5e51849df4ced3d3e004a7d40ed5 + languageName: node + linkType: hard + "@types/prettier@npm:^2.1.5": version: 2.2.3 resolution: "@types/prettier@npm:2.2.3" @@ -1682,6 +1730,13 @@ __metadata: languageName: node linkType: hard +"arrify@npm:^1.0.1": + version: 1.0.1 + resolution: "arrify@npm:1.0.1" + checksum: 745075dd4a4624ff0225c331dacb99be501a515d39bcb7c84d24660314a6ec28e68131b137e6f7e16318170842ce97538cd298fc4cd6b2cc798e0b957f2747e7 + languageName: node + linkType: hard + "async@npm:^3.2.0": version: 3.2.0 resolution: "async@npm:3.2.0" @@ -1813,6 +1868,7 @@ __metadata: string-argv: ^0.3.1 ts-jest: 27.1.3 ts-node: 10.7.0 + tsd: ^0.19.1 typed-emitter: ^1.3.1 typescript: 4.6.2 yargs: ^17.1.1 @@ -1939,6 +1995,17 @@ __metadata: languageName: node linkType: hard +"camelcase-keys@npm:^6.2.2": + version: 6.2.2 + resolution: "camelcase-keys@npm:6.2.2" + dependencies: + camelcase: ^5.3.1 + map-obj: ^4.0.0 + quick-lru: ^4.0.1 + checksum: 43c9af1adf840471e54c68ab3e5fe8a62719a6b7dbf4e2e86886b7b0ff96112c945736342b837bd2529ec9d1c7d1934e5653318478d98e0cf22c475c04658e2a + languageName: node + linkType: hard + "camelcase@npm:^5.3.1": version: 5.3.1 resolution: "camelcase@npm:5.3.1" @@ -2241,6 +2308,23 @@ __metadata: languageName: node linkType: hard +"decamelize-keys@npm:^1.1.0": + version: 1.1.0 + resolution: "decamelize-keys@npm:1.1.0" + dependencies: + decamelize: ^1.1.0 + map-obj: ^1.0.0 + checksum: 8bc5d32e035a072f5dffc1f1f3d26ca7ab1fb44a9cade34c97ab6cd1e62c81a87e718101e96de07d78cecda20a3fdb955df958e46671ccad01bb8dcf0de2e298 + languageName: node + linkType: hard + +"decamelize@npm:^1.1.0, decamelize@npm:^1.2.0": + version: 1.2.0 + resolution: "decamelize@npm:1.2.0" + checksum: ad8c51a7e7e0720c70ec2eeb1163b66da03e7616d7b98c9ef43cce2416395e84c1e9548dd94f5f6ffecfee9f8b94251fc57121a8b021f2ff2469b2bae247b8aa + languageName: node + linkType: hard + "decimal.js@npm:^10.2.1": version: 10.2.1 resolution: "decimal.js@npm:10.2.1" @@ -2529,6 +2613,29 @@ __metadata: languageName: node linkType: hard +"eslint-formatter-pretty@npm:^4.1.0": + version: 4.1.0 + resolution: "eslint-formatter-pretty@npm:4.1.0" + dependencies: + "@types/eslint": ^7.2.13 + ansi-escapes: ^4.2.1 + chalk: ^4.1.0 + eslint-rule-docs: ^1.1.5 + log-symbols: ^4.0.0 + plur: ^4.0.0 + string-width: ^4.2.0 + supports-hyperlinks: ^2.0.0 + checksum: e8e0cd3843513fff32a70b036dd349fdab81d73b5e522f23685181c907a1faf2b2ebcae1688dc71d0fc026184011792f7e39b833d349df18fe2baea00d017901 + languageName: node + linkType: hard + +"eslint-rule-docs@npm:^1.1.5": + version: 1.1.231 + resolution: "eslint-rule-docs@npm:1.1.231" + checksum: b776c75469bf392d58747e2ffa12e96041f7fef00d6b6c7d5e1a3f3621e42fdde4811795eb7cd4c429c33ef71b9d84f5822d58bca8964e2814485f2498be77b5 + languageName: node + linkType: hard + "esprima@npm:^4.0.0, esprima@npm:^4.0.1": version: 4.0.1 resolution: "esprima@npm:4.0.1" @@ -2610,6 +2717,19 @@ __metadata: languageName: node linkType: hard +"fast-glob@npm:^3.2.9": + version: 3.2.11 + resolution: "fast-glob@npm:3.2.11" + dependencies: + "@nodelib/fs.stat": ^2.0.2 + "@nodelib/fs.walk": ^1.2.3 + glob-parent: ^5.1.2 + merge2: ^1.3.0 + micromatch: ^4.0.4 + checksum: f473105324a7780a20c06de842e15ddbb41d3cb7e71d1e4fe6e8373204f22245d54f5ab9e2061e6a1c613047345954d29b022e0e76f5c28b1df9858179a0e6d7 + languageName: node + linkType: hard + "fast-json-stable-stringify@npm:2.x, fast-json-stable-stringify@npm:^2.0.0": version: 2.1.0 resolution: "fast-json-stable-stringify@npm:2.1.0" @@ -2808,6 +2928,15 @@ fsevents@^2.3.2: languageName: node linkType: hard +"glob-parent@npm:^5.1.2": + version: 5.1.2 + resolution: "glob-parent@npm:5.1.2" + dependencies: + is-glob: ^4.0.1 + checksum: f4f2bfe2425296e8a47e36864e4f42be38a996db40420fe434565e4480e3322f18eb37589617a98640c5dc8fdec1a387007ee18dbb1f3f5553409c34d17f425e + languageName: node + linkType: hard + "glob@npm:^7.1.1, glob@npm:^7.1.2, glob@npm:^7.1.3, glob@npm:^7.1.4": version: 7.1.6 resolution: "glob@npm:7.1.6" @@ -2829,6 +2958,20 @@ fsevents@^2.3.2: languageName: node linkType: hard +"globby@npm:^11.0.1": + version: 11.1.0 + resolution: "globby@npm:11.1.0" + dependencies: + array-union: ^2.1.0 + dir-glob: ^3.0.1 + fast-glob: ^3.2.9 + ignore: ^5.2.0 + merge2: ^1.4.1 + slash: ^3.0.0 + checksum: b4be8885e0cfa018fc783792942d53926c35c50b3aefd3fdcfb9d22c627639dc26bd2327a40a0b74b074100ce95bb7187bfeae2f236856aa3de183af7a02aea6 + languageName: node + linkType: hard + "globby@npm:^11.0.3": version: 11.0.3 resolution: "globby@npm:11.0.3" @@ -2864,6 +3007,13 @@ fsevents@^2.3.2: languageName: node linkType: hard +"hard-rejection@npm:^2.1.0": + version: 2.1.0 + resolution: "hard-rejection@npm:2.1.0" + checksum: 7baaf80a0c7fff4ca79687b4060113f1529589852152fa935e6787a2bc96211e784ad4588fb3048136ff8ffc9dfcf3ae385314a5b24db32de20bea0d1597f9dc + languageName: node + linkType: hard + "has-flag@npm:^3.0.0": version: 3.0.0 resolution: "has-flag@npm:3.0.0" @@ -2894,6 +3044,22 @@ fsevents@^2.3.2: languageName: node linkType: hard +"hosted-git-info@npm:^2.1.4": + version: 2.8.9 + resolution: "hosted-git-info@npm:2.8.9" + checksum: c955394bdab888a1e9bb10eb33029e0f7ce5a2ac7b3f158099dc8c486c99e73809dca609f5694b223920ca2174db33d32b12f9a2a47141dc59607c29da5a62dd + languageName: node + linkType: hard + +"hosted-git-info@npm:^4.0.1": + version: 4.1.0 + resolution: "hosted-git-info@npm:4.1.0" + dependencies: + lru-cache: ^6.0.0 + checksum: c3f87b3c2f7eb8c2748c8f49c0c2517c9a95f35d26f4bf54b2a8cba05d2e668f3753548b6ea366b18ec8dadb4e12066e19fa382a01496b0ffa0497eb23cbe461 + languageName: node + linkType: hard + "html-encoding-sniffer@npm:^2.0.1": version: 2.0.1 resolution: "html-encoding-sniffer@npm:2.0.1" @@ -3000,6 +3166,13 @@ fsevents@^2.3.2: languageName: node linkType: hard +"ignore@npm:^5.2.0": + version: 5.2.0 + resolution: "ignore@npm:5.2.0" + checksum: 6b1f926792d614f64c6c83da3a1f9c83f6196c2839aa41e1e32dd7b8d174cef2e329d75caabb62cb61ce9dc432f75e67d07d122a037312db7caa73166a1bdb77 + languageName: node + linkType: hard + "import-local@npm:^3.0.2": version: 3.0.2 resolution: "import-local@npm:3.0.2" @@ -3057,6 +3230,13 @@ fsevents@^2.3.2: languageName: node linkType: hard +"irregular-plurals@npm:^3.2.0": + version: 3.3.0 + resolution: "irregular-plurals@npm:3.3.0" + checksum: 1282d8adfb00a9718655ce21e5b096d4b31d2115c817a30e1e3254648ae4ac0f84d706cd0cad2a93c64f4bb5c5572ea8f63fcc9766f005a5362031c56d9e77b5 + languageName: node + linkType: hard + "is-alphabetical@npm:^1.0.0": version: 1.0.4 resolution: "is-alphabetical@npm:1.0.4" @@ -3108,6 +3288,15 @@ fsevents@^2.3.2: languageName: node linkType: hard +"is-core-module@npm:^2.5.0, is-core-module@npm:^2.8.1": + version: 2.8.1 + resolution: "is-core-module@npm:2.8.1" + dependencies: + has: ^1.0.3 + checksum: 418b7bc10768a73c41c7ef497e293719604007f88934a6ffc5f7c78702791b8528102fb4c9e56d006d69361549b3d9519440214a74aefc7e0b79e5e4411d377f + languageName: node + linkType: hard + "is-decimal@npm:^1.0.0": version: 1.0.4 resolution: "is-decimal@npm:1.0.4" @@ -3913,6 +4102,13 @@ fsevents@^2.3.2: languageName: node linkType: hard +"kind-of@npm:^6.0.3": + version: 6.0.3 + resolution: "kind-of@npm:6.0.3" + checksum: 3ab01e7b1d440b22fe4c31f23d8d38b4d9b91d9f291df683476576493d5dfd2e03848a8b05813dd0c3f0e835bc63f433007ddeceb71f05cb25c45ae1b19c6d3b + languageName: node + linkType: hard + "kleur@npm:^3.0.3": version: 3.0.3 resolution: "kleur@npm:3.0.3" @@ -3996,7 +4192,7 @@ fsevents@^2.3.2: languageName: node linkType: hard -"log-symbols@npm:^4.1.0": +"log-symbols@npm:^4.0.0, log-symbols@npm:^4.1.0": version: 4.1.0 resolution: "log-symbols@npm:4.1.0" dependencies: @@ -4063,6 +4259,20 @@ fsevents@^2.3.2: languageName: node linkType: hard +"map-obj@npm:^1.0.0": + version: 1.0.1 + resolution: "map-obj@npm:1.0.1" + checksum: 9949e7baec2a336e63b8d4dc71018c117c3ce6e39d2451ccbfd3b8350c547c4f6af331a4cbe1c83193d7c6b786082b6256bde843db90cb7da2a21e8fcc28afed + languageName: node + linkType: hard + +"map-obj@npm:^4.0.0": + version: 4.3.0 + resolution: "map-obj@npm:4.3.0" + checksum: fbc554934d1a27a1910e842bc87b177b1a556609dd803747c85ece420692380827c6ae94a95cce4407c054fa0964be3bf8226f7f2cb2e9eeee432c7c1985684e + languageName: node + linkType: hard + "markdown-escapes@npm:^1.0.0": version: 1.0.4 resolution: "markdown-escapes@npm:1.0.4" @@ -4070,6 +4280,26 @@ fsevents@^2.3.2: languageName: node linkType: hard +"meow@npm:^9.0.0": + version: 9.0.0 + resolution: "meow@npm:9.0.0" + dependencies: + "@types/minimist": ^1.2.0 + camelcase-keys: ^6.2.2 + decamelize: ^1.2.0 + decamelize-keys: ^1.1.0 + hard-rejection: ^2.1.0 + minimist-options: 4.1.0 + normalize-package-data: ^3.0.0 + read-pkg-up: ^7.0.1 + redent: ^3.0.0 + trim-newlines: ^3.0.0 + type-fest: ^0.18.0 + yargs-parser: ^20.2.3 + checksum: 99799c47247f4daeee178e3124f6ef6f84bde2ba3f37652865d5d8f8b8adcf9eedfc551dd043e2455cd8206545fd848e269c0c5ab6b594680a0ad4d3617c9639 + languageName: node + linkType: hard + "merge-stream@npm:^2.0.0": version: 2.0.0 resolution: "merge-stream@npm:2.0.0" @@ -4077,7 +4307,7 @@ fsevents@^2.3.2: languageName: node linkType: hard -"merge2@npm:^1.3.0": +"merge2@npm:^1.3.0, merge2@npm:^1.4.1": version: 1.4.1 resolution: "merge2@npm:1.4.1" checksum: 7268db63ed5169466540b6fb947aec313200bcf6d40c5ab722c22e242f651994619bcd85601602972d3c85bd2cc45a358a4c61937e9f11a061919a1da569b0c2 @@ -4127,6 +4357,13 @@ fsevents@^2.3.2: languageName: node linkType: hard +"min-indent@npm:^1.0.0": + version: 1.0.1 + resolution: "min-indent@npm:1.0.1" + checksum: bfc6dd03c5eaf623a4963ebd94d087f6f4bbbfd8c41329a7f09706b0cb66969c4ddd336abeb587bc44bc6f08e13bf90f0b374f9d71f9f01e04adc2cd6f083ef1 + languageName: node + linkType: hard + "minimatch@npm:^3.0.4": version: 3.0.4 resolution: "minimatch@npm:3.0.4" @@ -4136,6 +4373,17 @@ fsevents@^2.3.2: languageName: node linkType: hard +"minimist-options@npm:4.1.0": + version: 4.1.0 + resolution: "minimist-options@npm:4.1.0" + dependencies: + arrify: ^1.0.1 + is-plain-obj: ^1.1.0 + kind-of: ^6.0.3 + checksum: 8c040b3068811e79de1140ca2b708d3e203c8003eb9a414c1ab3cd467fc5f17c9ca02a5aef23bedc51a7f8bfbe77f87e9a7e31ec81fba304cda675b019496f4e + languageName: node + linkType: hard + "minimist@npm:^1.2.5, minimist@npm:~1.2.5": version: 1.2.5 resolution: "minimist@npm:1.2.5" @@ -4302,6 +4550,30 @@ fsevents@^2.3.2: languageName: node linkType: hard +"normalize-package-data@npm:^2.5.0": + version: 2.5.0 + resolution: "normalize-package-data@npm:2.5.0" + dependencies: + hosted-git-info: ^2.1.4 + resolve: ^1.10.0 + semver: 2 || 3 || 4 || 5 + validate-npm-package-license: ^3.0.1 + checksum: 7999112efc35a6259bc22db460540cae06564aa65d0271e3bdfa86876d08b0e578b7b5b0028ee61b23f1cae9fc0e7847e4edc0948d3068a39a2a82853efc8499 + languageName: node + linkType: hard + +"normalize-package-data@npm:^3.0.0": + version: 3.0.3 + resolution: "normalize-package-data@npm:3.0.3" + dependencies: + hosted-git-info: ^4.0.1 + is-core-module: ^2.5.0 + semver: ^7.3.4 + validate-npm-package-license: ^3.0.1 + checksum: bbcee00339e7c26fdbc760f9b66d429258e2ceca41a5df41f5df06cc7652de8d82e8679ff188ca095cad8eff2b6118d7d866af2b68400f74602fbcbce39c160a + languageName: node + linkType: hard + "normalize-path@npm:^3.0.0": version: 3.0.0 resolution: "normalize-path@npm:3.0.0" @@ -4438,7 +4710,7 @@ fsevents@^2.3.2: languageName: node linkType: hard -"parse-json@npm:^5.2.0": +"parse-json@npm:^5.0.0, parse-json@npm:^5.2.0": version: 5.2.0 resolution: "parse-json@npm:5.2.0" dependencies: @@ -4485,6 +4757,13 @@ fsevents@^2.3.2: languageName: node linkType: hard +"path-parse@npm:^1.0.7": + version: 1.0.7 + resolution: "path-parse@npm:1.0.7" + checksum: 49abf3d81115642938a8700ec580da6e830dde670be21893c62f4e10bd7dd4c3742ddc603fe24f898cba7eb0c6bc1777f8d9ac14185d34540c6d4d80cd9cae8a + languageName: node + linkType: hard + "path-type@npm:^4.0.0": version: 4.0.0 resolution: "path-type@npm:4.0.0" @@ -4529,6 +4808,15 @@ fsevents@^2.3.2: languageName: node linkType: hard +"plur@npm:^4.0.0": + version: 4.0.0 + resolution: "plur@npm:4.0.0" + dependencies: + irregular-plurals: ^3.2.0 + checksum: fea2e903efca67cc5c7a8952fca3db46ae8d9e9353373b406714977e601a5d3b628bcb043c3ad2126c6ff0e73d8020bf43af30a72dd087eff1ec240eb13b90e1 + languageName: node + linkType: hard + "prelude-ls@npm:~1.1.2": version: 1.1.2 resolution: "prelude-ls@npm:1.1.2" @@ -4616,6 +4904,13 @@ fsevents@^2.3.2: languageName: node linkType: hard +"quick-lru@npm:^4.0.1": + version: 4.0.1 + resolution: "quick-lru@npm:4.0.1" + checksum: bea46e1abfaa07023e047d3cf1716a06172c4947886c053ede5c50321893711577cb6119360f810cc3ffcd70c4d7db4069c3cee876b358ceff8596e062bd1154 + languageName: node + linkType: hard + "react-is@npm:^17.0.1": version: 17.0.1 resolution: "react-is@npm:17.0.1" @@ -4623,6 +4918,29 @@ fsevents@^2.3.2: languageName: node linkType: hard +"read-pkg-up@npm:^7.0.0, read-pkg-up@npm:^7.0.1": + version: 7.0.1 + resolution: "read-pkg-up@npm:7.0.1" + dependencies: + find-up: ^4.1.0 + read-pkg: ^5.2.0 + type-fest: ^0.8.1 + checksum: e4e93ce70e5905b490ca8f883eb9e48b5d3cebc6cd4527c25a0d8f3ae2903bd4121c5ab9c5a3e217ada0141098eeb661313c86fa008524b089b8ed0b7f165e44 + languageName: node + linkType: hard + +"read-pkg@npm:^5.2.0": + version: 5.2.0 + resolution: "read-pkg@npm:5.2.0" + dependencies: + "@types/normalize-package-data": ^2.4.0 + normalize-package-data: ^2.5.0 + parse-json: ^5.0.0 + type-fest: ^0.6.0 + checksum: eb696e60528b29aebe10e499ba93f44991908c57d70f2d26f369e46b8b9afc208ef11b4ba64f67630f31df8b6872129e0a8933c8c53b7b4daf0eace536901222 + languageName: node + linkType: hard + "readable-stream@npm:^2.0.6": version: 2.3.7 resolution: "readable-stream@npm:2.3.7" @@ -4638,6 +4956,16 @@ fsevents@^2.3.2: languageName: node linkType: hard +"redent@npm:^3.0.0": + version: 3.0.0 + resolution: "redent@npm:3.0.0" + dependencies: + indent-string: ^4.0.0 + strip-indent: ^3.0.0 + checksum: fa1ef20404a2d399235e83cc80bd55a956642e37dd197b4b612ba7327bf87fa32745aeb4a1634b2bab25467164ab4ed9c15be2c307923dd08b0fe7c52431ae6b + languageName: node + linkType: hard + "remark-frontmatter@npm:^1.2.0": version: 1.3.3 resolution: "remark-frontmatter@npm:1.3.3" @@ -4715,6 +5043,19 @@ fsevents@^2.3.2: languageName: node linkType: hard +resolve@^1.10.0: + version: 1.22.0 + resolution: "resolve@npm:1.22.0" + dependencies: + is-core-module: ^2.8.1 + path-parse: ^1.0.7 + supports-preserve-symlinks-flag: ^1.0.0 + bin: + resolve: bin/resolve + checksum: a2d14cc437b3a23996f8c7367eee5c7cf8149c586b07ca2ae00e96581ce59455555a1190be9aa92154785cf9f2042646c200d0e00e0bbd2b8a995a93a0ed3e4e + languageName: node + linkType: hard + resolve@^1.20.0: version: 1.20.0 resolution: "resolve@npm:1.20.0" @@ -4734,6 +5075,19 @@ resolve@^1.3.2: languageName: node linkType: hard +"resolve@patch:resolve@^1.10.0#~builtin": + version: 1.22.0 + resolution: "resolve@patch:resolve@npm%3A1.22.0#~builtin::version=1.22.0&hash=00b1ff" + dependencies: + is-core-module: ^2.8.1 + path-parse: ^1.0.7 + supports-preserve-symlinks-flag: ^1.0.0 + bin: + resolve: bin/resolve + checksum: b63b73ecbb7928e71c30e231f6adc380fca66bd5819a1b1324d3dcae573c726d9923df06eef3ac50be52b1dcea67272f3b6f12ba2e87ec8a9d3ebdf8454103bb + languageName: node + linkType: hard + "resolve@patch:resolve@^1.20.0#~builtin": version: 1.20.0 resolution: "resolve@patch:resolve@npm%3A1.20.0#~builtin::version=1.20.0&hash=00b1ff" @@ -4808,6 +5162,15 @@ resolve@^1.3.2: languageName: node linkType: hard +"semver@npm:2 || 3 || 4 || 5, semver@npm:^5.4.1": + version: 5.7.1 + resolution: "semver@npm:5.7.1" + bin: + semver: ./bin/semver + checksum: 57fd0acfd0bac382ee87cd52cd0aaa5af086a7dc8d60379dfe65fea491fb2489b6016400813930ecd61fd0952dae75c115287a1b16c234b1550887117744dfaf + languageName: node + linkType: hard + "semver@npm:7.x, semver@npm:^7.3.2": version: 7.3.4 resolution: "semver@npm:7.3.4" @@ -4819,15 +5182,6 @@ resolve@^1.3.2: languageName: node linkType: hard -"semver@npm:^5.4.1": - version: 5.7.1 - resolution: "semver@npm:5.7.1" - bin: - semver: ./bin/semver - checksum: 57fd0acfd0bac382ee87cd52cd0aaa5af086a7dc8d60379dfe65fea491fb2489b6016400813930ecd61fd0952dae75c115287a1b16c234b1550887117744dfaf - languageName: node - linkType: hard - "semver@npm:^6.0.0, semver@npm:^6.3.0": version: 6.3.0 resolution: "semver@npm:6.3.0" @@ -4837,7 +5191,7 @@ resolve@^1.3.2: languageName: node linkType: hard -"semver@npm:^7.3.5": +"semver@npm:^7.3.4, semver@npm:^7.3.5": version: 7.3.5 resolution: "semver@npm:7.3.5" dependencies: @@ -4951,6 +5305,40 @@ resolve@^1.3.2: languageName: node linkType: hard +"spdx-correct@npm:^3.0.0": + version: 3.1.1 + resolution: "spdx-correct@npm:3.1.1" + dependencies: + spdx-expression-parse: ^3.0.0 + spdx-license-ids: ^3.0.0 + checksum: 77ce438344a34f9930feffa61be0eddcda5b55fc592906ef75621d4b52c07400a97084d8701557b13f7d2aae0cb64f808431f469e566ef3fe0a3a131dcb775a6 + languageName: node + linkType: hard + +"spdx-exceptions@npm:^2.1.0": + version: 2.3.0 + resolution: "spdx-exceptions@npm:2.3.0" + checksum: cb69a26fa3b46305637123cd37c85f75610e8c477b6476fa7354eb67c08128d159f1d36715f19be6f9daf4b680337deb8c65acdcae7f2608ba51931540687ac0 + languageName: node + linkType: hard + +"spdx-expression-parse@npm:^3.0.0": + version: 3.0.1 + resolution: "spdx-expression-parse@npm:3.0.1" + dependencies: + spdx-exceptions: ^2.1.0 + spdx-license-ids: ^3.0.0 + checksum: a1c6e104a2cbada7a593eaa9f430bd5e148ef5290d4c0409899855ce8b1c39652bcc88a725259491a82601159d6dc790bedefc9016c7472f7de8de7361f8ccde + languageName: node + linkType: hard + +"spdx-license-ids@npm:^3.0.0": + version: 3.0.11 + resolution: "spdx-license-ids@npm:3.0.11" + checksum: 1da1acb090257773e60b022094050e810ae9fec874dc1461f65dc0400cd42dd830ab2df6e64fb49c2db3dce386dd0362110780e1b154db7c0bb413488836aaeb + languageName: node + linkType: hard + "sprintf-js@npm:~1.0.2": version: 1.0.3 resolution: "sprintf-js@npm:1.0.3" @@ -5082,6 +5470,15 @@ resolve@^1.3.2: languageName: node linkType: hard +"strip-indent@npm:^3.0.0": + version: 3.0.0 + resolution: "strip-indent@npm:3.0.0" + dependencies: + min-indent: ^1.0.0 + checksum: 18f045d57d9d0d90cd16f72b2313d6364fd2cb4bf85b9f593523ad431c8720011a4d5f08b6591c9d580f446e78855c5334a30fb91aa1560f5d9f95ed1b4a0530 + languageName: node + linkType: hard + "strip-json-comments@npm:^3.1.1": version: 3.1.1 resolution: "strip-json-comments@npm:3.1.1" @@ -5135,6 +5532,13 @@ resolve@^1.3.2: languageName: node linkType: hard +"supports-preserve-symlinks-flag@npm:^1.0.0": + version: 1.0.0 + resolution: "supports-preserve-symlinks-flag@npm:1.0.0" + checksum: 53b1e247e68e05db7b3808b99b892bd36fb096e6fba213a06da7fab22045e97597db425c724f2bbd6c99a3c295e1e73f3e4de78592289f38431049e1277ca0ae + languageName: node + linkType: hard + "symbol-tree@npm:^3.2.4": version: 3.2.4 resolution: "symbol-tree@npm:3.2.4" @@ -5241,6 +5645,13 @@ resolve@^1.3.2: languageName: node linkType: hard +"trim-newlines@npm:^3.0.0": + version: 3.0.1 + resolution: "trim-newlines@npm:3.0.1" + checksum: b530f3fadf78e570cf3c761fb74fef655beff6b0f84b29209bac6c9622db75ad1417f4a7b5d54c96605dcd72734ad44526fef9f396807b90839449eb543c6206 + languageName: node + linkType: hard + "trim-trailing-lines@npm:^1.0.0": version: 1.1.3 resolution: "trim-trailing-lines@npm:1.1.3" @@ -5334,6 +5745,22 @@ resolve@^1.3.2: languageName: node linkType: hard +"tsd@npm:^0.19.1": + version: 0.19.1 + resolution: "tsd@npm:0.19.1" + dependencies: + "@tsd/typescript": ~4.5.2 + eslint-formatter-pretty: ^4.1.0 + globby: ^11.0.1 + meow: ^9.0.0 + path-exists: ^4.0.0 + read-pkg-up: ^7.0.0 + bin: + tsd: dist/cli.js + checksum: be8531da502c5de9b99a013b15d1fed854141e5b893c9e4075a8b440a5210bacbba389a63638b583c144b259fbcc97160021b106cb32d32e6187a37649a8667e + languageName: node + linkType: hard + "type-check@npm:~0.3.2": version: 0.3.2 resolution: "type-check@npm:0.3.2" @@ -5357,6 +5784,27 @@ resolve@^1.3.2: languageName: node linkType: hard +"type-fest@npm:^0.18.0": + version: 0.18.1 + resolution: "type-fest@npm:0.18.1" + checksum: e96dcee18abe50ec82dab6cbc4751b3a82046da54c52e3b2d035b3c519732c0b3dd7a2fa9df24efd1a38d953d8d4813c50985f215f1957ee5e4f26b0fe0da395 + languageName: node + linkType: hard + +"type-fest@npm:^0.6.0": + version: 0.6.0 + resolution: "type-fest@npm:0.6.0" + checksum: b2188e6e4b21557f6e92960ec496d28a51d68658018cba8b597bd3ef757721d1db309f120ae987abeeda874511d14b776157ff809f23c6d1ce8f83b9b2b7d60f + languageName: node + linkType: hard + +"type-fest@npm:^0.8.1": + version: 0.8.1 + resolution: "type-fest@npm:0.8.1" + checksum: d61c4b2eba24009033ae4500d7d818a94fd6d1b481a8111612ee141400d5f1db46f199c014766b9fa9b31a6a7374d96fc748c6d688a78a3ce5a33123839becb7 + languageName: node + linkType: hard + "typed-emitter@npm:^1.3.1": version: 1.4.0 resolution: "typed-emitter@npm:1.4.0" @@ -5529,6 +5977,16 @@ typescript@4.6.2: languageName: node linkType: hard +"validate-npm-package-license@npm:^3.0.1": + version: 3.0.4 + resolution: "validate-npm-package-license@npm:3.0.4" + dependencies: + spdx-correct: ^3.0.0 + spdx-expression-parse: ^3.0.0 + checksum: 35703ac889d419cf2aceef63daeadbe4e77227c39ab6287eeb6c1b36a746b364f50ba22e88591f5d017bc54685d8137bc2d328d0a896e4d3fd22093c0f32a9ad + languageName: node + linkType: hard + "vfile-location@npm:^2.0.0": version: 2.0.6 resolution: "vfile-location@npm:2.0.6" @@ -5764,6 +6222,13 @@ typescript@4.6.2: languageName: node linkType: hard +"yargs-parser@npm:^20.2.3": + version: 20.2.9 + resolution: "yargs-parser@npm:20.2.9" + checksum: 8bb69015f2b0ff9e17b2c8e6bfe224ab463dd00ca211eece72a4cd8a906224d2703fb8a326d36fdd0e68701e201b2a60ed7cf81ce0fd9b3799f9fe7745977ae3 + languageName: node + linkType: hard + "yargs@npm:^16.2.0": version: 16.2.0 resolution: "yargs@npm:16.2.0" From 95074fcda636674b3a749349dbb3cf8f8a5a56f1 Mon Sep 17 00:00:00 2001 From: Joram van den Boezem Date: Tue, 22 Mar 2022 15:01:41 +0000 Subject: [PATCH 02/10] test: expand type tests --- .github/workflows/ci.yaml | 2 +- test-d/command.test-d.ts | 17 +++++++++++++++++ test-d/program.test-d.ts | 20 ++++++++++++++++++++ 3 files changed, 38 insertions(+), 1 deletion(-) diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index bf178f95..89b7af0a 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -21,8 +21,8 @@ jobs: with: node-version: ${{ matrix.node }} - run: yarn install - - run: yarn test - run: yarn build + - run: yarn test coverage: needs: test diff --git a/test-d/command.test-d.ts b/test-d/command.test-d.ts index 1caf995c..89df1ad3 100644 --- a/test-d/command.test-d.ts +++ b/test-d/command.test-d.ts @@ -4,3 +4,20 @@ import { Command, command } from '../src/command' const cmd = command() expectType(cmd) + +// Chainable methods +expectType(cmd.description('foo')) +expectType(cmd.hidden()) +expectType(cmd.add(cmd)) +expectType(cmd.default()) +expectType(cmd.action(undefined)) + +// Argument types +cmd.argument('foo').action((args) => { + expectType<{ foo: string }>(args) +}) + +// Option types +cmd.option('foo').action((args) => { + expectType<{ foo: unknown }>(args) +}) diff --git a/test-d/program.test-d.ts b/test-d/program.test-d.ts index 333ddb47..ca2532ae 100644 --- a/test-d/program.test-d.ts +++ b/test-d/program.test-d.ts @@ -1,6 +1,26 @@ import { expectType } from 'tsd' +import { command } from '../src/command' import { Program, program } from '../src/program' +import { Repl } from '../src/repl' const app = program() expectType(app) + +// Chainable methods +expectType(app.description('foo')) +expectType(app.prompt('foo')) +expectType(app.add(command())) +expectType(app.default(command())) +expectType(app.on('run', undefined)) + +// Run methods +expectType>(app.run('foo')) +expectType>(app.run(['foo', 'bar'])) +expectType>(app.run()) +expectType(app.repl()) +expectType>(app.runOrRepl()) + +// Getters +expectType(app.isRepl()) +expectType(app.isRepl()) From 38695cf98831203c1aeebb0d6829db9f087da891 Mon Sep 17 00:00:00 2001 From: Joram van den Boezem Date: Tue, 22 Mar 2022 15:37:06 +0000 Subject: [PATCH 03/10] test: add failing test --- .vscode/settings.json | 2 +- package.json | 2 +- src/baseArg.ts | 19 +++++++++++++++++-- test-d/command.test-d.ts | 16 ++++++++++++++++ tsconfig.json | 2 +- 5 files changed, 36 insertions(+), 5 deletions(-) diff --git a/.vscode/settings.json b/.vscode/settings.json index 910a2a5f..25fa6215 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -1,3 +1,3 @@ { - "typescript.tsdk": "node_modules\\typescript\\lib" + "typescript.tsdk": "node_modules/typescript/lib" } diff --git a/package.json b/package.json index 69e87376..f39e23ea 100644 --- a/package.json +++ b/package.json @@ -25,7 +25,7 @@ "types": "lib/index.d.ts", "scripts": { "prepublishOnly": "yarn build", - "build": "tsc", + "build": "tsc --rootDir src", "watch": "tsc --watch", "lint": "prettier --write \"src/**/*\"", "test": "tsd && jest", diff --git a/src/baseArg.ts b/src/baseArg.ts index 7f467bf4..aaa9341f 100644 --- a/src/baseArg.ts +++ b/src/baseArg.ts @@ -8,7 +8,7 @@ export interface BaseArgOptions { export type InferArgType = /** - * Add support for numeric variadic arguments + * Numeric variadic arguments */ O extends { variadic: true @@ -16,12 +16,27 @@ export type InferArgType = } ? Array : /** - * Add support for string variadic arguments + * String variadic arguments */ O extends { variadic: true } ? Array + : /** + * Numeric optional argument + */ + O extends { + optional: true + type: 'number' + } + ? number | undefined + : /** + * String optional argument + */ + O extends { + optional: true + } + ? string | undefined : /** * Choices with array type */ O extends { choices: ReadonlyArray; type: 'array' } diff --git a/test-d/command.test-d.ts b/test-d/command.test-d.ts index 89df1ad3..84213951 100644 --- a/test-d/command.test-d.ts +++ b/test-d/command.test-d.ts @@ -14,8 +14,24 @@ expectType(cmd.action(undefined)) // Argument types cmd.argument('foo').action((args) => { + // Argument without options expectType<{ foo: string }>(args) }) +cmd.argument('foo', { default: 'bar' }).action((args) => { + // Argument with default + expectType<{ foo: string }>(args) +}) +cmd.argument('foo', { optional: true }).action((args) => { + // Optional argument + expectType<{ foo: string }>(args) +}) +cmd + .argument('foo', { + type: 'number', + }) + .action((args) => { + expectType<{ foo: number }>(args) + }) // Option types cmd.option('foo').action((args) => { diff --git a/tsconfig.json b/tsconfig.json index cab0f582..5e31cf76 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -1,5 +1,5 @@ { - "include": ["./src"], + "include": ["src", "tests", "test-d"], "compilerOptions": { "target": "es2017", "module": "commonjs", From c63dcd31891b9d662deeff3e0db0b67bedeac783 Mon Sep 17 00:00:00 2001 From: Joram van den Boezem Date: Tue, 22 Mar 2022 15:37:40 +0000 Subject: [PATCH 04/10] test: add failing tests --- package.json | 2 +- test-d/command.test-d.ts | 76 +++++++++++++++++++++++++++++++++------- test-d/program.test-d.ts | 2 +- tsconfig.build.json | 9 +++++ tsconfig.json | 11 +++--- 5 files changed, 80 insertions(+), 20 deletions(-) create mode 100644 tsconfig.build.json diff --git a/package.json b/package.json index f39e23ea..927694f7 100644 --- a/package.json +++ b/package.json @@ -25,7 +25,7 @@ "types": "lib/index.d.ts", "scripts": { "prepublishOnly": "yarn build", - "build": "tsc --rootDir src", + "build": "tsc --project tsconfig.build.json", "watch": "tsc --watch", "lint": "prettier --write \"src/**/*\"", "test": "tsd && jest", diff --git a/test-d/command.test-d.ts b/test-d/command.test-d.ts index 84213951..13350483 100644 --- a/test-d/command.test-d.ts +++ b/test-d/command.test-d.ts @@ -10,30 +10,80 @@ expectType(cmd.description('foo')) expectType(cmd.hidden()) expectType(cmd.add(cmd)) expectType(cmd.default()) -expectType(cmd.action(undefined)) +expectType(cmd.action(() => {})) -// Argument types +// String argument types cmd.argument('foo').action((args) => { - // Argument without options + // No options expectType<{ foo: string }>(args) }) cmd.argument('foo', { default: 'bar' }).action((args) => { - // Argument with default + // With default expectType<{ foo: string }>(args) }) cmd.argument('foo', { optional: true }).action((args) => { - // Optional argument - expectType<{ foo: string }>(args) + // Optional + expectType<{ foo: string | undefined }>(args) +}) +cmd.argument('foo', { optional: true, default: 'bar' }).action((args) => { + // Optional with default + expectType<{ foo: string | undefined }>(args) +}) + +// Numeric argument types +cmd.argument('foo', { type: 'number' }).action((args) => { + // No options + expectType<{ foo: number }>(args) +}) +cmd.argument('foo', { type: 'number', default: 100 }).action((args) => { + // With default + expectType<{ foo: number }>(args) +}) +cmd.argument('foo', { default: 100 }).action((args) => { + // Inferred from default + expectType<{ foo: number }>(args) +}) +cmd.argument('foo', { type: 'number', optional: true }).action((args) => { + // Optional + expectType<{ foo: number | undefined }>(args) }) cmd - .argument('foo', { - type: 'number', - }) + .argument('foo', { type: 'number', optional: true, default: 100 }) .action((args) => { - expectType<{ foo: number }>(args) + // Optional with default + expectType<{ foo: string | undefined }>(args) }) +cmd.argument('foo', { optional: true, default: 100 }).action((args) => { + // Optional inferred from default + expectType<{ foo: number | undefined }>(args) +}) -// Option types -cmd.option('foo').action((args) => { - expectType<{ foo: unknown }>(args) +// Boolean argument types +cmd.argument('foo', { type: 'boolean' }).action((args) => { + // No options + expectType<{ foo: boolean }>(args) }) +cmd.argument('foo', { type: 'boolean', default: false }).action((args) => { + // With default + expectType<{ foo: boolean }>(args) +}) +cmd.argument('foo', { default: false }).action((args) => { + // Inferred from default + expectType<{ foo: boolean }>(args) +}) +cmd.argument('foo', { type: 'boolean', optional: true }).action((args) => { + // Optional + expectType<{ foo: boolean | undefined }>(args) +}) +cmd + .argument('foo', { type: 'boolean', optional: true, default: false }) + .action((args) => { + // Optional with default + expectType<{ foo: boolean | undefined }>(args) + }) +cmd.argument('foo', { optional: true, default: false }).action((args) => { + // Optional inferred from default + expectType<{ foo: boolean | undefined }>(args) +}) + +// @todo: option types diff --git a/test-d/program.test-d.ts b/test-d/program.test-d.ts index ca2532ae..7648161f 100644 --- a/test-d/program.test-d.ts +++ b/test-d/program.test-d.ts @@ -12,7 +12,7 @@ expectType(app.description('foo')) expectType(app.prompt('foo')) expectType(app.add(command())) expectType(app.default(command())) -expectType(app.on('run', undefined)) +expectType(app.on('run', () => {})) // Run methods expectType>(app.run('foo')) diff --git a/tsconfig.build.json b/tsconfig.build.json new file mode 100644 index 00000000..b9ebe6b1 --- /dev/null +++ b/tsconfig.build.json @@ -0,0 +1,9 @@ +{ + "extends": "tsconfig.json", + "include": ["src"], + "compilerOptions": { + "outDir": "lib", + "rootDir": "src", + "declaration": true + } +} diff --git a/tsconfig.json b/tsconfig.json index 5e31cf76..88dbf549 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -1,15 +1,16 @@ { "include": ["src", "tests", "test-d"], "compilerOptions": { + "rootDir": ".", + "noEmit": true, + "target": "es2017", "module": "commonjs", "lib": ["es2017"], - "declaration": true, - "outDir": "lib", - "rootDir": "src", - "strict": true, "allowSyntheticDefaultImports": true, + "moduleResolution": "node", "esModuleInterop": true, - "moduleResolution": "node" + + "strict": true } } From 4043259941cc5bb04d0907a00793a5bf35859dfd Mon Sep 17 00:00:00 2001 From: Joram van den Boezem Date: Tue, 22 Mar 2022 16:47:08 +0000 Subject: [PATCH 05/10] fix: types --- README.md | 4 +- TODO.md | 12 ++++-- examples/types.ts | 57 +++++++++++++++++++++++++-- package.json | 2 +- src/baseArg.ts | 85 ++++++++++++++++------------------------ src/command.ts | 6 ++- src/option.ts | 7 ++-- test-d/command.test-d.ts | 10 ++--- tsconfig.build.json | 4 +- tsconfig.json | 3 +- 10 files changed, 115 insertions(+), 75 deletions(-) diff --git a/README.md b/README.md index 2bcc2b0a..4d59601c 100644 --- a/README.md +++ b/README.md @@ -737,9 +737,7 @@ Optionally deploy to GitHub, S3, etc. using your preferred CD method if needed. ## Todo -- [ ] Better code coverage -- [ ] Consider resolving ambiguity in _prompt_ param/method -- [ ] Async autocomplete method for arg values +See [TODO.md](TODO.md) ## Contributing diff --git a/TODO.md b/TODO.md index 4523b4c3..672d757a 100644 --- a/TODO.md +++ b/TODO.md @@ -1,5 +1,9 @@ ### TODOs -| Filename | line # | TODO -|:------|:------:|:------ -| [src/prompter.ts](src/prompter.ts#L16) | 16 | Wait for upstream change to import types from enquirer -| [src/prompter.ts](src/prompter.ts#L77) | 77 | ignoring type error here, probably need another type +| Filename | line # | TODO | +|:------|:------:|:------| +| [src/baseArg.ts](src/baseArg.ts#L88) | 88 | See if we can add this to autocompleter | +| [src/command.ts](src/command.ts#L278) | 278 | coerce all types and remove coerce option from baseArg | +| [src/command.ts](src/command.ts#L293) | 293 | Upgrade to native async handlers in yarn 17 | +| [src/prompter.ts](src/prompter.ts#L16) | 16 | Wait for upstream change to import types from enquirer | +| [src/prompter.ts](src/prompter.ts#L77) | 77 | ignoring type error here, probably need another type | +| [test-d/command.test-d.ts](test-d/command.test-d.ts#L89) | 89 | option types | diff --git a/examples/types.ts b/examples/types.ts index a4ec8c5a..297cad45 100644 --- a/examples/types.ts +++ b/examples/types.ts @@ -1,4 +1,4 @@ -import { program, command } from '../src' +import { command, program } from '../src' /** * Keep in mind that argument/option types are not validated at runtime. @@ -7,8 +7,57 @@ import { program, command } from '../src' */ const string = command('string') - .argument('arg', { description: 'Required string argument' }) - .option('opt', { description: 'Optional string option', type: 'string' }) + .argument('arg1', { description: 'Required string argument' }) + .argument('arg2', { optional: true, description: 'Optional string argument' }) + .argument('arg3', { variadic: true, description: 'Variadic string argument' }) + .option('opt1', { type: 'string', description: 'String option' }) + .option('opt2', { + default: 'foo', + description: 'String option with default', + }) + .action((args) => { + console.log('Args are', args) + }) + +const number = command('number') + .argument('arg1', { type: 'number', description: 'Required number argument' }) + .argument('arg2', { + type: 'number', + optional: true, + description: 'Optional number argument', + }) + .argument('arg3', { + type: 'number', + variadic: true, + description: 'Variadic number argument', + }) + .option('opt1', { type: 'number', description: 'number option' }) + .option('opt2', { default: 100, description: 'Number option with default' }) + .action((args) => { + console.log('Args are', args) + }) + +const boolean = command('boolean') + .argument('arg1', { + type: 'boolean', + description: 'Required boolean argument', + }) + .argument('arg2', { + type: 'boolean', + optional: true, + description: 'Optional boolean argument', + }) + .argument('arg3', { + type: 'boolean', + variadic: true, + description: 'Variadic boolean argument', + }) + .option('opt1', { type: 'boolean', description: 'number option' }) + .option('opt2', { + type: 'boolean', + default: false, + description: 'Number option with default', + }) .action((args) => { console.log('Args are', args) }) @@ -41,6 +90,8 @@ const defaultValues = command('default') const app = program() .description('All argument and option types') .add(string) + .add(number) + .add(boolean) .add(choices) .add(defaultValues) diff --git a/package.json b/package.json index 927694f7..55f9e7f9 100644 --- a/package.json +++ b/package.json @@ -31,7 +31,7 @@ "test": "tsd && jest", "start": "ts-node", "doc:toc": "doctoc README.md", - "doc:todos": "leasot --exit-nicely --reporter markdown \"src/**/*.ts\" > TODO.md" + "doc:todos": "leasot --exit-nicely --reporter markdown \"{src,test-d,tests}/**/*.ts\" > TODO.md" }, "author": "", "license": "MIT", diff --git a/src/baseArg.ts b/src/baseArg.ts index aaa9341f..658f7cb1 100644 --- a/src/baseArg.ts +++ b/src/baseArg.ts @@ -6,58 +6,40 @@ export interface BaseArgOptions { prompt?: true | string } +// prettier-ignore export type InferArgType = - /** - * Numeric variadic arguments - */ - O extends { - variadic: true - type: 'number' - } - ? Array - : /** - * String variadic arguments - */ - O extends { - variadic: true - } - ? Array - : /** - * Numeric optional argument - */ - O extends { - optional: true - type: 'number' - } - ? number | undefined - : /** - * String optional argument - */ - O extends { - optional: true - } - ? string | undefined - : /** - * Choices with array type - */ O extends { choices: ReadonlyArray; type: 'array' } - ? C[] - : /** - * Choices with array default - */ O extends { - choices: ReadonlyArray - default: ReadonlyArray - } - ? C[] - : /** - * Prefer choices over default - */ O extends { choices: ReadonlyArray } - ? C - : /** - * Allow fallback type - */ - unknown extends InferredOptionType - ? F - : InferredOptionType + // Default number + O extends { default: number } ? number : + // Optional number + O extends { type: 'number', optional: true } ? number | undefined : + // Variadic number + O extends { type: 'number', variadic: true } ? Array : + // Number + O extends { type: 'number' } ? number : + // Default boolean + O extends { default: boolean } ? boolean : + // Optional boolean + O extends { type: 'boolean', optional: true } ? boolean | undefined : + // Variadic boolean + O extends { type: 'boolean', variadic: true } ? Array : + // Boolean + O extends { type: 'boolean' } ? boolean : + // Default string + O extends { default: string } ? string : + // Optional string + O extends { optional: true } ? string | undefined : + // Variadic string + O extends { variadic: true } ? Array : + // Choices with array type + O extends { choices: ReadonlyArray; type: 'array' } ? C[] : + // Choices with array default + O extends { choices: ReadonlyArray, default: ReadonlyArray } ? C[] : + // Prefer choices over default + O extends { choices: ReadonlyArray } ? C : + // Allow fallback type + unknown extends InferredOptionType ? F : + // yargs type + InferredOptionType export class BaseArg { protected name: string @@ -102,6 +84,7 @@ export class BaseArg { /** * Get possible values, is specified. + * @todo See if we can add this to autocompleter */ getChoices() { return this.options.choices diff --git a/src/command.ts b/src/command.ts index b266aabc..65fbd0c5 100644 --- a/src/command.ts +++ b/src/command.ts @@ -92,7 +92,7 @@ export class Command { ) { this.add(new Argument(name, options)) - return (this as unknown) as Command< + return this as unknown as Command< T & { [key in K]: InferArgType } > } @@ -107,7 +107,7 @@ export class Command { ) { this.add(new Option(name, options)) - return (this as unknown) as Command }> + return this as unknown as Command }> } /** @@ -275,6 +275,7 @@ export class Command { let promise = prompterInstance.prompt() promise = promise.then((args) => { + // @todo coerce all types and remove coerce option from baseArg if (this.handler) { return this.handler(args, commandRunner) } @@ -289,6 +290,7 @@ export class Command { // Save promise chain on argv instance, so we can access it in parse // callback. + // @todo Upgrade to native async handlers in yarn 17 argv.__promise = promise return promise diff --git a/src/option.ts b/src/option.ts index 016721da..06070e97 100644 --- a/src/option.ts +++ b/src/option.ts @@ -1,5 +1,5 @@ -import { Options as BaseOptions, Argv } from 'yargs' -import { BaseArgOptions, BaseArg } from './baseArg' +import { Argv, Options as BaseOptions } from 'yargs' +import { BaseArg, BaseArgOptions } from './baseArg' // We ignore some not-so-common use cases from the type to make using this // library easier. They could still be used at runtime but won't be documented @@ -14,6 +14,7 @@ type IgnoreOptions = | 'defaultDescription' | 'demand' | 'demandOption' + | 'deprecate' | 'desc' | 'describe' | 'global' @@ -28,7 +29,7 @@ type IgnoreOptions = | 'requiresArg' | 'skipValidation' | 'string' -// | 'implies' + | 'implies' export interface OptionOptions extends Omit, diff --git a/test-d/command.test-d.ts b/test-d/command.test-d.ts index 13350483..e5d23cf5 100644 --- a/test-d/command.test-d.ts +++ b/test-d/command.test-d.ts @@ -27,7 +27,7 @@ cmd.argument('foo', { optional: true }).action((args) => { }) cmd.argument('foo', { optional: true, default: 'bar' }).action((args) => { // Optional with default - expectType<{ foo: string | undefined }>(args) + expectType<{ foo: string }>(args) }) // Numeric argument types @@ -51,11 +51,11 @@ cmd .argument('foo', { type: 'number', optional: true, default: 100 }) .action((args) => { // Optional with default - expectType<{ foo: string | undefined }>(args) + expectType<{ foo: number }>(args) }) cmd.argument('foo', { optional: true, default: 100 }).action((args) => { // Optional inferred from default - expectType<{ foo: number | undefined }>(args) + expectType<{ foo: number }>(args) }) // Boolean argument types @@ -79,11 +79,11 @@ cmd .argument('foo', { type: 'boolean', optional: true, default: false }) .action((args) => { // Optional with default - expectType<{ foo: boolean | undefined }>(args) + expectType<{ foo: boolean }>(args) }) cmd.argument('foo', { optional: true, default: false }).action((args) => { // Optional inferred from default - expectType<{ foo: boolean | undefined }>(args) + expectType<{ foo: boolean }>(args) }) // @todo: option types diff --git a/tsconfig.build.json b/tsconfig.build.json index b9ebe6b1..1278bfb3 100644 --- a/tsconfig.build.json +++ b/tsconfig.build.json @@ -1,9 +1,9 @@ { - "extends": "tsconfig.json", + "extends": "./tsconfig.json", "include": ["src"], "compilerOptions": { "outDir": "lib", "rootDir": "src", - "declaration": true + "noEmit": false } } diff --git a/tsconfig.json b/tsconfig.json index 88dbf549..df4715a4 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -1,8 +1,9 @@ { - "include": ["src", "tests", "test-d"], + "include": ["src", "tests", "test-d", "examples"], "compilerOptions": { "rootDir": ".", "noEmit": true, + "declaration": true, "target": "es2017", "module": "commonjs", From 49d2c9e59d7f88a3f29bd0c087d641a04940249e Mon Sep 17 00:00:00 2001 From: Joram van den Boezem Date: Tue, 22 Mar 2022 16:53:32 +0000 Subject: [PATCH 06/10] build: fix cc --- .github/workflows/ci.yaml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index 89b7af0a..5537dadf 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -23,6 +23,9 @@ jobs: - run: yarn install - run: yarn build - run: yarn test + - uses: actions/upload-artifact@v3 + with: + path: lib coverage: needs: test @@ -30,6 +33,7 @@ jobs: steps: - uses: actions/checkout@v3 - run: yarn install + - uses: actions/download-artifact@v3 - uses: paambaati/codeclimate-action@v3.0.0 env: CC_TEST_REPORTER_ID: e1a2f8ecd90c13810c302d9cdfb4a26a5b79666e899c4f353e558416c168da0d From fc2c92447d610e968593a2a0fde69c52de8c0894 Mon Sep 17 00:00:00 2001 From: Joram van den Boezem Date: Tue, 22 Mar 2022 16:57:24 +0000 Subject: [PATCH 07/10] build: cache node_modules --- .github/workflows/ci.yaml | 8 ++++++++ .github/workflows/release.yaml | 2 +- 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index 5537dadf..8c961a36 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -20,6 +20,14 @@ jobs: - uses: actions/setup-node@v3 with: node-version: ${{ matrix.node }} + - id: yarn-cache-dir-path + run: echo "::set-output name=dir::$(yarn config get cacheFolder)" + - uses: actions/cache@v3 + with: + path: ${{ steps.yarn-cache-dir-path.outputs.dir }} + key: ${{ runner.os }}-yarn-${{ hashFiles('**/yarn.lock') }} + restore-keys: | + ${{ runner.os }}-yarn- - run: yarn install - run: yarn build - run: yarn test diff --git a/.github/workflows/release.yaml b/.github/workflows/release.yaml index 3d7a4de4..cebe6b49 100644 --- a/.github/workflows/release.yaml +++ b/.github/workflows/release.yaml @@ -13,7 +13,7 @@ jobs: - uses: actions/checkout@v3 - uses: actions/setup-node@v3 with: - node-version: 14 + node-version: 16 - run: yarn install - run: npx semantic-release env: From c1e723b864b9cb3bbc326b8ccb5c087ef6534a11 Mon Sep 17 00:00:00 2001 From: Joram van den Boezem Date: Tue, 22 Mar 2022 16:58:15 +0000 Subject: [PATCH 08/10] build: cache more --- .github/workflows/ci.yaml | 8 ++++++++ .github/workflows/release.yaml | 9 +++++++-- 2 files changed, 15 insertions(+), 2 deletions(-) diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index 8c961a36..749b1b98 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -40,6 +40,14 @@ jobs: runs-on: ubuntu-latest steps: - uses: actions/checkout@v3 + - id: yarn-cache-dir-path + run: echo "::set-output name=dir::$(yarn config get cacheFolder)" + - uses: actions/cache@v3 + with: + path: ${{ steps.yarn-cache-dir-path.outputs.dir }} + key: ${{ runner.os }}-yarn-${{ hashFiles('**/yarn.lock') }} + restore-keys: | + ${{ runner.os }}-yarn- - run: yarn install - uses: actions/download-artifact@v3 - uses: paambaati/codeclimate-action@v3.0.0 diff --git a/.github/workflows/release.yaml b/.github/workflows/release.yaml index cebe6b49..2dee7eef 100644 --- a/.github/workflows/release.yaml +++ b/.github/workflows/release.yaml @@ -11,9 +11,14 @@ jobs: runs-on: ubuntu-latest steps: - uses: actions/checkout@v3 - - uses: actions/setup-node@v3 + - id: yarn-cache-dir-path + run: echo "::set-output name=dir::$(yarn config get cacheFolder)" + - uses: actions/cache@v3 with: - node-version: 16 + path: ${{ steps.yarn-cache-dir-path.outputs.dir }} + key: ${{ runner.os }}-yarn-${{ hashFiles('**/yarn.lock') }} + restore-keys: | + ${{ runner.os }}-yarn- - run: yarn install - run: npx semantic-release env: From d0e6ba6a7054f8c271b24efd40ecf858358a1015 Mon Sep 17 00:00:00 2001 From: Joram van den Boezem Date: Tue, 22 Mar 2022 17:03:27 +0000 Subject: [PATCH 09/10] build: fix artifacts (?) --- .github/workflows/ci.yaml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index 749b1b98..87257344 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -33,6 +33,7 @@ jobs: - run: yarn test - uses: actions/upload-artifact@v3 with: + name: lib path: lib coverage: @@ -50,6 +51,8 @@ jobs: ${{ runner.os }}-yarn- - run: yarn install - uses: actions/download-artifact@v3 + with: + name: lib - uses: paambaati/codeclimate-action@v3.0.0 env: CC_TEST_REPORTER_ID: e1a2f8ecd90c13810c302d9cdfb4a26a5b79666e899c4f353e558416c168da0d From 43f0c53598cf4bbc6cc7fc57332f998d631bad16 Mon Sep 17 00:00:00 2001 From: Joram van den Boezem Date: Tue, 22 Mar 2022 17:05:40 +0000 Subject: [PATCH 10/10] build: fix artifact path (?) --- .github/workflows/ci.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index 87257344..a2b4ff2a 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -53,6 +53,7 @@ jobs: - uses: actions/download-artifact@v3 with: name: lib + path: lib - uses: paambaati/codeclimate-action@v3.0.0 env: CC_TEST_REPORTER_ID: e1a2f8ecd90c13810c302d9cdfb4a26a5b79666e899c4f353e558416c168da0d