From 1d977bbdd5b5a12a2d2d1289843057c9595f6297 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marius=20Lundga=CC=8Ard?= Date: Sun, 4 Jun 2023 09:01:08 +0200 Subject: [PATCH] feat: init command --- README.md | 23 +- package.json | 10 +- pnpm-lock.yaml | 247 +++++++-- scripts/init.ts | 17 + src/cli/index.ts | 8 + src/cli/initAction.ts | 13 + src/node/core/index.ts | 1 + src/node/core/pkg/types.ts | 13 + src/node/core/template/createFromTemplate.ts | 85 ++++ src/node/core/template/define.ts | 6 + src/node/core/template/index.ts | 3 + src/node/core/template/types.ts | 45 ++ src/node/index.ts | 1 + src/node/init.ts | 55 ++ src/node/isEmptyDirectory.ts | 5 + src/node/templates/default/index.ts | 1 + src/node/templates/default/template.ts | 508 +++++++++++++++++++ src/node/templates/index.ts | 1 + 18 files changed, 996 insertions(+), 46 deletions(-) create mode 100644 scripts/init.ts create mode 100644 src/cli/initAction.ts create mode 100644 src/node/core/template/createFromTemplate.ts create mode 100644 src/node/core/template/define.ts create mode 100644 src/node/core/template/index.ts create mode 100644 src/node/core/template/types.ts create mode 100644 src/node/init.ts create mode 100644 src/node/isEmptyDirectory.ts create mode 100644 src/node/templates/default/index.ts create mode 100644 src/node/templates/default/template.ts create mode 100644 src/node/templates/index.ts diff --git a/README.md b/README.md index 03058530..435d041e 100644 --- a/README.md +++ b/README.md @@ -11,17 +11,19 @@ npm install @sanity/pkg-utils -D ## Basic usage ```sh +# Initialize a new package +npx @sanity/pkg-utils@latest init + # In a Node.js package directory with `package.json` present # Check the package -# This will validate the package.json file -pkg-utils +pkg-utils check # Build the package -pkg-utils build --tsconfig tsconfig.dist.json +pkg-utils build # Watch the package -pkg-utils watch --tsconfig tsconfig.dist.json +pkg-utils watch ``` Run `pkg-utils -h` for more information on CLI usage. @@ -38,8 +40,15 @@ control. You may then add a configuration file named `package.config.ts` (or `.j import {defineConfig} from '@sanity/pkg-utils' export default defineConfig({ - // Minify bundled JavaScript - minify: true, + extract: { + rules: { + // do not require internal members to be prefixed with `_` + 'ae-internal-missing-underscore': 'off', + }, + }, + + // the path to the tsconfig file for distributed builds + tsconfig: 'tsconfig.dist.json', }) ``` @@ -89,7 +98,7 @@ Override or modify the value of the `exports` before it’s parsed internally. ``` - Default: `undefined` -Configure the level of reporting of \`@microsoft/api-extractor\` (which is used to bundle the +Configure the level of reporting of [API Extractor](https://api-extractor.com/) (which is used to bundle the type definitions, as well as lint the TSDoc of the package). #### `external` diff --git a/package.json b/package.json index 41e819c3..d5b88182 100644 --- a/package.json +++ b/package.json @@ -139,12 +139,18 @@ "esbuild": "^0.17.19", "esbuild-register": "^3.4.2", "find-config": "^1.0.0", + "get-latest-version": "^5.0.1", + "git-url-parse": "^13.1.0", "globby": "^11.1.0", "jsonc-parser": "^3.2.0", "mkdirp": "^3.0.1", + "outdent": "^0.8.0", + "parse-git-config": "^3.0.0", "pkg-up": "^3.1.0", "prettier": "^2.8.8", + "prettier-plugin-packagejson": "^2.4.3", "pretty-bytes": "^5.6.0", + "prompts": "^2.4.2", "recast": "^0.23.2", "rimraf": "^5.0.1", "rollup": "^3.23.0", @@ -162,8 +168,11 @@ "@types/babel__core": "^7.20.1", "@types/cpx": "^1.5.2", "@types/find-config": "^1.0.1", + "@types/git-url-parse": "^9.0.1", "@types/node": "^20.2.5", + "@types/parse-git-config": "^3.0.1", "@types/prettier": "^2.7.2", + "@types/prompts": "^2.4.4", "@types/treeify": "^1.0.0", "@types/uuid": "^9.0.1", "@typescript-eslint/eslint-plugin": "^5.59.7", @@ -180,7 +189,6 @@ "lint-staged": "^13.2.2", "npm-run-all": "^4.1.5", "outdent": "^0.8.0", - "prettier-plugin-packagejson": "^2.4.3", "rollup-plugin-visualizer": "^5.9.0", "semantic-release": "^21.0.2", "ts-node": "^10.9.1", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index e6349d7f..5872b4fa 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -68,6 +68,12 @@ importers: find-config: specifier: ^1.0.0 version: 1.0.0 + get-latest-version: + specifier: ^5.0.1 + version: 5.0.1 + git-url-parse: + specifier: ^13.1.0 + version: 13.1.0 globby: specifier: ^11.1.0 version: 11.1.0 @@ -77,15 +83,27 @@ importers: mkdirp: specifier: ^3.0.1 version: 3.0.1 + outdent: + specifier: ^0.8.0 + version: 0.8.0 + parse-git-config: + specifier: ^3.0.0 + version: 3.0.0 pkg-up: specifier: ^3.1.0 version: 3.1.0 prettier: specifier: ^2.8.8 version: 2.8.8 + prettier-plugin-packagejson: + specifier: ^2.4.3 + version: 2.4.3(prettier@2.8.8) pretty-bytes: specifier: ^5.6.0 version: 5.6.0 + prompts: + specifier: ^2.4.2 + version: 2.4.2 recast: specifier: ^0.23.2 version: 0.23.2 @@ -132,12 +150,21 @@ importers: '@types/find-config': specifier: ^1.0.1 version: 1.0.1 + '@types/git-url-parse': + specifier: ^9.0.1 + version: 9.0.1 '@types/node': specifier: ^20.2.5 version: 20.2.5 + '@types/parse-git-config': + specifier: ^3.0.1 + version: 3.0.1 '@types/prettier': specifier: ^2.7.2 version: 2.7.2 + '@types/prompts': + specifier: ^2.4.4 + version: 2.4.4 '@types/treeify': specifier: ^1.0.0 version: 1.0.0 @@ -183,12 +210,6 @@ importers: npm-run-all: specifier: ^4.1.5 version: 4.1.5 - outdent: - specifier: ^0.8.0 - version: 0.8.0 - prettier-plugin-packagejson: - specifier: ^2.4.3 - version: 2.4.3(prettier@2.8.8) rollup-plugin-visualizer: specifier: ^5.9.0 version: 5.9.0(rollup@3.23.0) @@ -2595,18 +2616,17 @@ packages: open: 9.1.0 picocolors: 1.0.0 tslib: 2.5.2 + dev: false /@pnpm/config.env-replace@1.1.0: resolution: {integrity: sha512-htyl8TWnKL7K/ESFa1oW2UB5lVDxuF5DpM7tBi6Hu2LNL3mWkIzNLG6N4zoCUP1lCKNxWy/3iu8mS8MvToGd6w==} engines: {node: '>=12.22.0'} - dev: true /@pnpm/network.ca-file@1.0.2: resolution: {integrity: sha512-YcPQ8a0jwYU9bTdJDpXjMi7Brhkr1mXsXrUJvjqM2mQDgkRiz8jFaQGOdaLxgjtUfQgZhKy/O3cG/YwmgKaxLA==} engines: {node: '>=12.22.0'} dependencies: graceful-fs: 4.2.10 - dev: true /@pnpm/npm-conf@2.2.0: resolution: {integrity: sha512-roLI1ul/GwzwcfcVpZYPdrgW2W/drLriObl1h+yLF5syc8/5ULWw2ALbCHUWF+4YltIqA3xFSbG4IwyJz37e9g==} @@ -2615,7 +2635,6 @@ packages: '@pnpm/config.env-replace': 1.1.0 '@pnpm/network.ca-file': 1.0.2 config-chain: 1.1.13 - dev: true /@rollup/plugin-alias@5.0.0(rollup@3.23.0): resolution: {integrity: sha512-l9hY5chSCjuFRPsnRm16twWBiSApl2uYFLsepQYwtBuAxNMQ/1dJqADld40P0Jkqm65GRTLy/AC6hnpVebtLsA==} @@ -3022,6 +3041,10 @@ packages: resolution: {integrity: sha512-H4DFIQMwxCKRgVWMSqALg6aowTOgZi5D4pSPBBuOQFJLRwfNZaByhC9+s870CZgTRJoyVg5J+iesdF5uvnJ0mA==} dev: true + /@types/git-url-parse@9.0.1: + resolution: {integrity: sha512-Zf9mY4Mz7N3Nyi341nUkOtgVUQn4j6NS4ndqEha/lOgEbTkHzpD7wZuRagYKzrXNtvawWfsrojoC1nhsQexvNA==} + dev: true + /@types/hast@2.3.4: resolution: {integrity: sha512-wLEm0QvaoawEDoTRwzTXp4b4jpwiJDvR5KMnFnVodm3scufTlBOWRD6N1OBf9TZMhjlNsSfcO5V+7AF4+Vy+9g==} dependencies: @@ -3067,6 +3090,10 @@ packages: resolution: {integrity: sha512-Gj7cI7z+98M282Tqmp2K5EIsoouUEzbBJhQQzDE3jSIRk6r9gsz0oUokqIUR4u1R3dMHo0pDHM7sNOHyhulypw==} dev: true + /@types/parse-git-config@3.0.1: + resolution: {integrity: sha512-cBVLXlpIpP23p+jQm8d2TrTfxyub3aiqfqgd0TWRnMqwCJMskYiveNJT11YwN+gbo3+0ZFFmtaepKzN7pxExlA==} + dev: true + /@types/parse5@6.0.3: resolution: {integrity: sha512-SuT16Q1K51EAVPz1K29DJ/sXjhSQ0zjvsypYJ6tlwVsRV9jwW5Adq2ch8Dq8kDBCkYnELS7N7VNCSB5nC56t/g==} dev: false @@ -3075,6 +3102,13 @@ packages: resolution: {integrity: sha512-KufADq8uQqo1pYKVIYzfKbJfBAc0sOeXqGbFaSpv8MRmC/zXgowNZmFcbngndGk922QDmOASEXUZCaY48gs4cg==} dev: true + /@types/prompts@2.4.4: + resolution: {integrity: sha512-p5N9uoTH76lLvSAaYSZtBCdEXzpOOufsRjnhjVSrZGXikVGHX9+cc9ERtHRV4hvBKHyZb1bg4K+56Bd2TqUn4A==} + dependencies: + '@types/node': 20.2.5 + kleur: 3.0.3 + dev: true + /@types/prop-types@15.7.5: resolution: {integrity: sha512-JCB8C6SnDoQf0cNycqd/35A7MjcnK+ZTqE7judS6o7utxUCg6imJg3QK2qzHKszlTjcj2cn+NwMB2i96ubpj7w==} dev: true @@ -3820,6 +3854,7 @@ packages: /big-integer@1.6.51: resolution: {integrity: sha512-GPEid2Y9QU1Exl1rpO9B2IPJGHPSupF5GnVIP0blYvNOMer2bTvSWs1jGOUg04hTmu67nmLsQ9TBo1puaotBHg==} engines: {node: '>=0.6'} + dev: false /big.js@5.2.2: resolution: {integrity: sha512-vyL2OymJxmarO8gxMr0mhChsO9QGwhynfuu4+MHTAW6czfq9humCB7rKpUjDd9YUiDPU4mzpyupFSvOClAwbmQ==} @@ -3893,6 +3928,7 @@ packages: engines: {node: '>= 5.10.0'} dependencies: big-integer: 1.6.51 + dev: false /brace-expansion@1.1.11: resolution: {integrity: sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==} @@ -4053,6 +4089,7 @@ packages: engines: {node: '>=12'} dependencies: run-applescript: 5.0.0 + dev: false /busboy@1.6.0: resolution: {integrity: sha512-8SFQbg/0hQ9xy3UNTB0YEnsNBbWfhf7RtnzpL7TkBiTBRfrQ9Fxcnz7VJsleJpyp6rVLvXiuORqjlHi5q+PYuA==} @@ -4499,7 +4536,6 @@ packages: dependencies: ini: 1.3.8 proto-list: 1.2.4 - dev: true /console-browserify@1.2.0: resolution: {integrity: sha512-ZMkYO/LkF17QvCPqM0gxw8yUzigAOZOSWSHg91FH6orS7vcEj5dVZTidN2fQ14yBSdg97RqhSNwLUXInd52OTA==} @@ -4594,7 +4630,6 @@ packages: /core-util-is@1.0.3: resolution: {integrity: sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==} - dev: true /cosmiconfig-typescript-loader@4.3.0(@types/node@20.2.5)(cosmiconfig@8.1.3)(ts-node@10.9.1)(typescript@5.0.4): resolution: {integrity: sha512-NTxV1MFfZDLPiBMjxbHRwSh5LaLcPMwNdCutmnHJCKoVnlvldPWlllonKwrsRJ5pYZBIBGRWWU2tfvzxgeSW5Q==} @@ -4824,6 +4859,13 @@ packages: engines: {node: '>=0.10'} dev: true + /decompress-response@7.0.0: + resolution: {integrity: sha512-6IvPrADQyyPGLpMnUh6kfKiqy7SrbXbjoUuZ90WMBJKErzv2pCiwlGEXjRX9/54OnTq+XFVnkOnOMzclLI5aEA==} + engines: {node: '>=10'} + dependencies: + mimic-response: 3.1.0 + dev: false + /dedent@0.7.0: resolution: {integrity: sha512-Q6fKUPqnAHAyhiUgFU7BUzLiv0kd8saH9al7tnu5Q/okj6dnupxyTgFIBjVzJATdfIAm9NAsvXNzjaKa+bxVyA==} dev: true @@ -4838,7 +4880,6 @@ packages: /deep-extend@0.6.0: resolution: {integrity: sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==} engines: {node: '>=4.0.0'} - dev: true /deep-is@0.1.4: resolution: {integrity: sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==} @@ -4860,6 +4901,7 @@ packages: dependencies: bplist-parser: 0.2.0 untildify: 4.0.0 + dev: false /default-browser@4.0.0: resolution: {integrity: sha512-wX5pXO1+BrhMkSbROFsyxUm0i/cJEScyNhA4PPxc41ICuv05ZZB/MX28s8aZx6xjmatvebIapF6hLEKEcpneUA==} @@ -4869,6 +4911,7 @@ packages: default-browser-id: 3.0.0 execa: 7.1.1 titleize: 3.0.0 + dev: false /defaults@1.0.4: resolution: {integrity: sha512-eFuaLoy/Rxalv2kr+lqMlUnrDWV+3j4pljOIJgLIhI058IQfWJ7vXhyEIHu+HtC738klGALYxOKDO0bQP3tg8A==} @@ -4883,6 +4926,7 @@ packages: /define-lazy-prop@3.0.0: resolution: {integrity: sha512-N+MeXYoqr3pOgn8xfyRPREN7gHakLYjhsHhWGT3fWAiL4IkAt0iDw14QiiEm2bE30c5XX5q0FtAA3CK5f9/BUg==} engines: {node: '>=12'} + dev: false /define-properties@1.2.0: resolution: {integrity: sha512-xvqAVKGfT1+UAvPwKTVw/njhdQ8ZhXK4lI0bCIuCMrp2up9nPnaDftrLtmpTazqd1o+UY4zgzU+avtMbDP+ldA==} @@ -4942,12 +4986,12 @@ packages: /detect-indent@7.0.1: resolution: {integrity: sha512-Mc7QhQ8s+cLrnUfU/Ji94vG/r8M26m8f++vyres4ZoojaRDpZ1eSIh/EpzLNwlWuvzSZ3UbDFspjFvTDXe6e/g==} engines: {node: '>=12.20'} - dev: true + dev: false /detect-newline@4.0.0: resolution: {integrity: sha512-1aXUEPdfGdzVPFpzGJJNgq9o81bGg1s09uxTWsqBlo9PI332uyJRQq13+LK/UN4JfxJbFdCXonUFQ9R/p7yCtw==} engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} - dev: true + dev: false /devalue@4.3.2: resolution: {integrity: sha512-KqFl6pOgOW+Y6wJgu80rHpo2/3H07vr8ntR9rkkFIRETewbf5GaYYcakYfiKz89K+sLsuPkQIZaXDMjUObZwWg==} @@ -5866,6 +5910,18 @@ packages: resolution: {integrity: sha512-5nqDSxl8nn5BSNxyR3n4I6eDmbolI6WT+QqR547RwxQapgjQBmtktdP+HTBb/a/zLsbzERTONyUB5pefh5TtjQ==} dev: true + /follow-redirects@1.15.2(debug@4.3.4): + resolution: {integrity: sha512-VQLG33o04KaQ8uYi2tVNbdrWp1QWxNNea+nmIB4EVM28v0hmP17z7aG1+wAkNzVq4KeXTq3221ye5qTJP91JwA==} + engines: {node: '>=4.0'} + peerDependencies: + debug: '*' + peerDependenciesMeta: + debug: + optional: true + dependencies: + debug: 4.3.4 + dev: false + /for-each@0.3.3: resolution: {integrity: sha512-jqYfLp7mo9vIyQf8ykW2v7A+2N4QjeCeI5+Dz9XraiO1ign81wjiH7Fb9vSOWvQfNtmSa4H2RoQTrrXivdUZmw==} dependencies: @@ -5903,7 +5959,6 @@ packages: dependencies: inherits: 2.0.4 readable-stream: 2.3.8 - dev: true /fs-extra@11.1.1: resolution: {integrity: sha512-MGIE4HOvQCeUCzmlHs0vXpih4ysz4wg9qiSAu6cd42lVwPbTM1TjV7RusoyQqMmk/95gdQZX72u+YW+c3eEpFQ==} @@ -5997,6 +6052,36 @@ packages: has-proto: 1.0.1 has-symbols: 1.0.3 + /get-it@8.1.3: + resolution: {integrity: sha512-cbyYSla0qAQrwirBNHM4CERo8H32eUWNxhsby4AcKiRW3jIwMPDhgLnR0Ok/UmZO68vsccjRCFbZFEeB3BXvLg==} + engines: {node: '>=14.0.0'} + dependencies: + debug: 4.3.4 + decompress-response: 7.0.0 + follow-redirects: 1.15.2(debug@4.3.4) + into-stream: 6.0.0 + is-plain-object: 5.0.0 + is-retry-allowed: 2.2.0 + is-stream: 2.0.1 + parse-headers: 2.0.5 + progress-stream: 2.0.0 + tunnel-agent: 0.6.0 + transitivePeerDependencies: + - supports-color + dev: false + + /get-latest-version@5.0.1: + resolution: {integrity: sha512-oonDx2gj9GzP+b1dxrd4KJwnTEFPjugNVALey5ze7cBkwjI/2BQ6X93hzE5cTVHV3DOPTB8U9HlbpEZVLjI1MQ==} + engines: {node: '>=14.18'} + dependencies: + get-it: 8.1.3 + registry-auth-token: 5.0.2 + registry-url: 5.1.0 + semver: 7.5.1 + transitivePeerDependencies: + - supports-color + dev: false + /get-stream@3.0.0: resolution: {integrity: sha512-GlhdIUuVakc8SJ6kK0zAFbiGzRFzNnY4jUuEbV9UROo4Y+0Ny4fjvcZFVTeDA4odpFyOQzaw6hXukJSq/f28sQ==} engines: {node: '>=4'} @@ -6019,9 +6104,14 @@ packages: engines: {node: '>=0.10.0'} dev: true + /git-config-path@2.0.0: + resolution: {integrity: sha512-qc8h1KIQbJpp+241id3GuAtkdyJ+IK+LIVtkiFTRKRrmddDzs3SI9CvP1QYmWBFvm1I/PWRwj//of8bgAc0ltA==} + engines: {node: '>=4'} + dev: false + /git-hooks-list@3.1.0: resolution: {integrity: sha512-LF8VeHeR7v+wAbXqfgRlTSX/1BJR9Q1vEMR8JAz1cEg6GX07+zyj3sAdDvYjj/xnlIfVuGgj4qBei1K3hKH+PA==} - dev: true + dev: false /git-log-parser@1.2.0: resolution: {integrity: sha512-rnCVNfkTL8tdNryFuaY0fYiBWEBcgF748O6ZI61rslBvr2o7U65c2/6npCRqH40vuAhtgtDiqLTJjBVdrejCzA==} @@ -6046,6 +6136,19 @@ packages: through2: 4.0.2 dev: true + /git-up@7.0.0: + resolution: {integrity: sha512-ONdIrbBCFusq1Oy0sC71F5azx8bVkvtZtMJAsv+a6lz5YAmbNnLD6HAB4gptHZVLPR8S2/kVN6Gab7lryq5+lQ==} + dependencies: + is-ssh: 1.4.0 + parse-url: 8.1.0 + dev: false + + /git-url-parse@13.1.0: + resolution: {integrity: sha512-5FvPJP/70WkIprlUZ33bm4UAaFdjcLkJLpWft1BeZKqwR0uhhNGoKwlUaPtVb4LxCSQ++erHapRak9kWGj+FCA==} + dependencies: + git-up: 7.0.0 + dev: false + /github-slugger@1.5.0: resolution: {integrity: sha512-wIh+gKBI9Nshz2o46B0B3f5k/W+WI9ZAv6y5Dn5WJ5SK1t0TnDimB4WE5rmTD05ZAIn8HALCZVmCsvj0w0v0lw==} dev: false @@ -6195,7 +6298,7 @@ packages: ignore: 5.2.4 merge2: 1.4.1 slash: 4.0.0 - dev: true + dev: false /gopd@1.0.1: resolution: {integrity: sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==} @@ -6204,7 +6307,6 @@ packages: /graceful-fs@4.2.10: resolution: {integrity: sha512-9ByhssR2fPVsNZj478qUUbKfmL0+t5BDVyjShtyZZLiK7ZDAArFFfopyOTj0M05wE2tJPisA4iTnnXl2YoPvOA==} - dev: true /graceful-fs@4.2.11: resolution: {integrity: sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==} @@ -6575,7 +6677,6 @@ packages: /ini@1.3.8: resolution: {integrity: sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==} - dev: true /inquirer@8.2.5: resolution: {integrity: sha512-QAgPDQMEgrDssk1XiwwHoOGYF9BAbUcc1+j+FhEvaOt8/cKRqyLn0U5qA6F74fGhTMGxf92pOvPBeh29jQJDTQ==} @@ -6612,6 +6713,14 @@ packages: engines: {node: '>= 0.10'} dev: true + /into-stream@6.0.0: + resolution: {integrity: sha512-XHbaOAvP+uFKUFsOgoNPRjLkwB+I22JFPFe5OjTkQ0nwgj6+pSjb4NmB6VMxaPshLiOf+zcpOCBQuLwC1KHhZA==} + engines: {node: '>=10'} + dependencies: + from2: 2.3.0 + p-is-promise: 3.0.0 + dev: false + /into-stream@7.0.0: resolution: {integrity: sha512-2dYz766i9HprMBasCMvHMuazJ7u4WzhJwo5kb3iPSiW/iRYV6uPari3zHoqZlnuaR7V1bEiNMxikhp37rdBXbw==} engines: {node: '>=12'} @@ -6759,6 +6868,7 @@ packages: resolution: {integrity: sha512-eljcgEDlEns/7AXFosB5K/2nCM4P7FQPkGc/DWLy5rmFEWvZayGrik1d9/QIY5nJ4f9YsVvBkA6kJpHn9rISdQ==} engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} hasBin: true + dev: false /is-dotfile@1.0.3: resolution: {integrity: sha512-9YclgOGtN/f8zx0Pr4FQYMdibBiTaH3sn52vjYip4ZSf6C4/6RfTEZ+MR4GvKhCxdPh21Bg42/WL55f6KSnKpg==} @@ -6847,6 +6957,7 @@ packages: hasBin: true dependencies: is-docker: 3.0.0 + dev: false /is-interactive@1.0.0: resolution: {integrity: sha512-2HvIEKRoqS62guEC+qBjpvRubdX910WCMuJTZ+I9yvqKU2/12eSL549HMwtabb4oupdj2sMP50k+XJfB/8JE6w==} @@ -6923,6 +7034,7 @@ packages: /is-plain-obj@4.1.0: resolution: {integrity: sha512-+Pgi+vMuUNkJyExiMBt5IlFoMyKnr5zhJ4Uspz58WOhBF5QoIZkFyNHIbBAtHwzVAgk5RtndVNsDRN61/mmDqg==} engines: {node: '>=12'} + dev: false /is-plain-object@2.0.4: resolution: {integrity: sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==} @@ -6934,7 +7046,6 @@ packages: /is-plain-object@5.0.0: resolution: {integrity: sha512-VRSzKkbMm5jMDoKLbltAkFQ5Qr7VDiTFGXxYFXXowVj387GeGNOCsOH6Msy00SGZ3Fp84b1Naa1psqgcCIEP5Q==} engines: {node: '>=0.10.0'} - dev: true /is-posix-bracket@0.1.1: resolution: {integrity: sha512-Yu68oeXJ7LeWNmZ3Zov/xg/oDBnBK2RNxwYY1ilNJX+tKKZqgPK+qOn/Gs9jEu66KDY9Netf5XLKNGzas/vPfQ==} @@ -6960,12 +7071,23 @@ packages: has-tostringtag: 1.0.0 dev: true + /is-retry-allowed@2.2.0: + resolution: {integrity: sha512-XVm7LOeLpTW4jV19QSH38vkswxoLud8sQ57YwJVTPWdiaI9I8keEhGFpBlslyVsgdQy4Opg8QOLb8YRgsyZiQg==} + engines: {node: '>=10'} + dev: false + /is-shared-array-buffer@1.0.2: resolution: {integrity: sha512-sqN2UDu1/0y6uvXyStCOzyhAjCSlHceFoMKJW8W9EU9cvic/QdsZ0kEU93HEy3IUEFZIiH/3w+AH/UQbPHNdhA==} dependencies: call-bind: 1.0.2 dev: true + /is-ssh@1.4.0: + resolution: {integrity: sha512-x7+VxdxOdlV3CYpjvRLBv5Lo9OJerlYanjwFrPR9fuGPjCiNiCzFgAWpiLAohSbsnH4ZAys3SBh+hq5rJosxUQ==} + dependencies: + protocols: 2.0.1 + dev: false + /is-stream@1.1.0: resolution: {integrity: sha512-uQPm8kcs47jx38atAcWTVxyltQYoPT68y9aWYdV6yWXSyW8mzSat0TL6CiWdZeCdF3KrAvpVtnHbTv4RN+rqdQ==} engines: {node: '>=0.10.0'} @@ -7042,7 +7164,6 @@ packages: /isarray@1.0.0: resolution: {integrity: sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==} - dev: true /isexe@2.0.0: resolution: {integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==} @@ -7226,7 +7347,6 @@ packages: /kleur@3.0.3: resolution: {integrity: sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w==} engines: {node: '>=6'} - dev: false /kleur@4.1.5: resolution: {integrity: sha512-o+NO+8WrRiQEE4/7nwRJhN1HWpVmJm511pBHUxPLtp0BUISzlBplORYSmTclCnJvQq2tKu/sgl3xVpkc7ZWuQQ==} @@ -8140,6 +8260,11 @@ packages: resolution: {integrity: sha512-vqiC06CuhBTUdZH+RYl8sFrL096vA45Ok5ISO6sE/Mr1jRbGH4Csnhi8f3wKVl7x8mO4Au7Ir9D3Oyv1VYMFJw==} engines: {node: '>=12'} + /mimic-response@3.1.0: + resolution: {integrity: sha512-z0yWI+4FDrrweS8Zmt4Ej5HdJmky15+L2e6Wgn3+iK5fWzb6T3fhNFq2+MeTRb064c6Wr4N/wv0DzQTjNzHNGQ==} + engines: {node: '>=10'} + dev: false + /min-indent@1.0.1: resolution: {integrity: sha512-I9jwMn07Sy/IwOj3zVkVik2JTvgpaykDZEigL6Rx6N9LbMywwUSMtxET+7lVoDLLd3O3IXwJwvuuns8UB/HeAg==} engines: {node: '>=4'} @@ -8188,7 +8313,6 @@ packages: /minimist@1.2.8: resolution: {integrity: sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==} - dev: true /minipass@6.0.2: resolution: {integrity: sha512-MzWSV5nYVT7mVyWCwn2o7JH13w2TBRmmSqSRCKzTw+lmft9X4z+3wjvs06Tzijo5z4W/kahUCDpRXTF+ZrmF/w==} @@ -8667,6 +8791,7 @@ packages: define-lazy-prop: 3.0.0 is-inside-container: 1.0.0 is-wsl: 2.2.0 + dev: false /optionator@0.9.1: resolution: {integrity: sha512-74RlY5FCnhq4jRxVUPKDaRwrVNXMqsGsiW6AJw4XK8hmtm10wC0ypZBLw5IIp85NZMr91+qd1RvvENwg7jjRFw==} @@ -8735,7 +8860,7 @@ packages: /outdent@0.8.0: resolution: {integrity: sha512-KiOAIsdpUTcAXuykya5fnVVT+/5uS0Q1mrkRHcF89tpieSmY33O/tmc54CqwA+bfhbtEfZUNLHaPUiB9X3jt1A==} - dev: true + dev: false /p-each-series@3.0.0: resolution: {integrity: sha512-lastgtAdoH9YaLyDa5i5z64q+kzOcQHsQ5SsZJD3q0VEyI8mq872S3geuNbRUQLVAE9siMfgKrpj7MloKFHruw==} @@ -8757,7 +8882,6 @@ packages: /p-is-promise@3.0.0: resolution: {integrity: sha512-Wo8VsW4IRQSKVXsJCn7TomUaVtyfjVDn3nUP7kE967BQk0CwFpdbZs0X0uk5sW9mkBa9eNM7hCMaG93WUAwxYQ==} engines: {node: '>=8'} - dev: true /p-limit@1.3.0: resolution: {integrity: sha512-vvcXsLAJ9Dr5rQOPk7toZQZJApBl2K4J6dANSsEuh6QI41JYcsS/qhTGa9ErIUUgK3WNQoJYvylxvjqmiqEA9Q==} @@ -8878,6 +9002,14 @@ packages: safe-buffer: 5.2.1 dev: true + /parse-git-config@3.0.0: + resolution: {integrity: sha512-wXoQGL1D+2COYWCD35/xbiKma1Z15xvZL8cI25wvxzled58V51SJM04Urt/uznS900iQor7QO04SgdfT/XlbuA==} + engines: {node: '>=8'} + dependencies: + git-config-path: 2.0.0 + ini: 1.3.8 + dev: false + /parse-glob@3.0.4: resolution: {integrity: sha512-FC5TeK0AwXzq3tUBFtH74naWkPQCEWs4K+xMxWZBlKDWu0bVHXGZa+KKqxKidd7xwhdZ19ZNuF2uO1M/r196HA==} engines: {node: '>=0.10.0'} @@ -8888,6 +9020,10 @@ packages: is-glob: 2.0.1 dev: true + /parse-headers@2.0.5: + resolution: {integrity: sha512-ft3iAoLOB/MlwbNXgzy43SWGP6sQki2jQvAyBg/zDFAgr9bfNWZIUj42Kw2eJIl8kEi4PbgE6U1Zau/HwI75HA==} + dev: false + /parse-json@2.2.0: resolution: {integrity: sha512-QR/GGaKCkhwk1ePQNYDRKYZ3mwU9ypsKhB0XyFnLQdomyEqk3e8wpW3V5Jp88zbxK4n5ST1nqo+g9juTpownhQ==} engines: {node: '>=0.10.0'} @@ -8937,6 +9073,18 @@ packages: engines: {node: '>=0.10.0'} dev: true + /parse-path@7.0.0: + resolution: {integrity: sha512-Euf9GG8WT9CdqwuWJGdf3RkUcTBArppHABkO7Lm8IzRQp0e2r/kkFnmhu4TSK30Wcu5rVAZLmfPKSBBi9tWFog==} + dependencies: + protocols: 2.0.1 + dev: false + + /parse-url@8.1.0: + resolution: {integrity: sha512-xDvOoLU5XRrcOZvnI6b8zA6n9O9ejNk/GExuz1yBuWUGn9KA97GI6HTs6u02wKara1CeVmZhH+0TZFdWScR89w==} + dependencies: + parse-path: 7.0.0 + dev: false + /parse5@6.0.1: resolution: {integrity: sha512-Ofn/CTFzRGTTxwpNEs9PP93gXShHcTq255nzRYSKe8AkVpZY7e1fpmTfOyoIvjP5HG7Z2ZM7VS9PPhQGW2pOpw==} dev: false @@ -9172,7 +9320,7 @@ packages: prettier: 2.8.8 sort-package-json: 2.4.1 synckit: 0.8.5 - dev: true + dev: false /prettier@2.8.8: resolution: {integrity: sha512-tdN8qQGvNjw4CHbY+XXk0JgCXn9QiF21a55rBe5LJAU+kDyC4WQn4+awm2Xfk2lQMk5fKup9XgzTZtGkjBdP9Q==} @@ -9200,13 +9348,19 @@ packages: /process-nextick-args@2.0.1: resolution: {integrity: sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==} - dev: true /process@0.11.10: resolution: {integrity: sha512-cdGef/drWFoydD1JsMzuFf8100nZl+GT+yacc2bEced5f9Rjk4z+WtFUTBu9PhOi9j/jfmBPu0mMEY4wIdAF8A==} engines: {node: '>= 0.6.0'} dev: true + /progress-stream@2.0.0: + resolution: {integrity: sha512-xJwOWR46jcXUq6EH9yYyqp+I52skPySOeHfkxOZ2IY1AiBi/sFJhbhAKHoV3OTw/omQ45KTio9215dRJ2Yxd3Q==} + dependencies: + speedometer: 1.0.0 + through2: 2.0.5 + dev: false + /prompts@2.4.2: resolution: {integrity: sha512-NxNv/kLguCA7p3jE8oL2aEBsrJWgAakBpgmgK6lpPWV+WuOmY6r2/zbAVnP+T8bQlA0nzHXSJSJW0Hq7ylaD2Q==} engines: {node: '>= 6'} @@ -9221,7 +9375,10 @@ packages: /proto-list@1.2.4: resolution: {integrity: sha512-vtK/94akxsTMhe0/cbfpR+syPuszcuwhqVjJq26CuNDgFGj682oRBXOP5MJpv2r7JtE8MsiepGIqvvOTBwn2vA==} - dev: true + + /protocols@2.0.1: + resolution: {integrity: sha512-/XJ368cyBJ7fzLMwLKv1e4vLxOju2MNAIokcr7meSaNcVbWz/CPcW22cP04mwxOErdA5mwjA8Q6w/cdAQxVn7Q==} + dev: false /prr@1.0.1: resolution: {integrity: sha512-yPw4Sng1gWghHQWj0B3ZggWUm4qVbPwPFcRG8KyxiU7J2OHFSoEHKS+EZ3fv5l1t9CyCiop6l/ZYeWbrgoQejw==} @@ -9307,7 +9464,6 @@ packages: ini: 1.3.8 minimist: 1.2.8 strip-json-comments: 2.0.1 - dev: true /react-dom@18.2.0(react@18.2.0): resolution: {integrity: sha512-6IMTriUmvsjHUjNtEDudZfuDQUoWXVxKHhlEGSk81n4YFS+r/Kl99wXiwlVXtPBtJenozv2P+hxDsw9eA7Xo6g==} @@ -9414,7 +9570,6 @@ packages: safe-buffer: 5.1.2 string_decoder: 1.1.1 util-deprecate: 1.0.2 - dev: true /readable-stream@3.6.2: resolution: {integrity: sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==} @@ -9532,7 +9687,13 @@ packages: engines: {node: '>=14'} dependencies: '@pnpm/npm-conf': 2.2.0 - dev: true + + /registry-url@5.1.0: + resolution: {integrity: sha512-8acYXXTI0AkQv6RAOjE3vOaIXZkT9wo4LOFbBKYQEEnnMNBpKqdUrI6S4NT0KPIo/WVvJ5tE/X5LF/TQUf0ekw==} + engines: {node: '>=8'} + dependencies: + rc: 1.2.8 + dev: false /regjsparser@0.9.1: resolution: {integrity: sha512-dQUtn90WanSNl+7mQKcXAgZxvUe7Z0SqXlgzv0za4LwiUhyzBC58yQO3liFoUgu8GiJVInAhJjkj1N0EtQ5nkQ==} @@ -9832,6 +9993,7 @@ packages: engines: {node: '>=12'} dependencies: execa: 5.1.1 + dev: false /run-async@2.4.1: resolution: {integrity: sha512-tvVnVv01b8c1RrA6Ep7JkStj85Guv/YrMcwqYQnwjsAS2cTmmPGBBjAjpCW7RrSodNSoE2/qg9O4bceNvUuDgQ==} @@ -9861,7 +10023,6 @@ packages: /safe-buffer@5.1.2: resolution: {integrity: sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==} - dev: true /safe-buffer@5.2.1: resolution: {integrity: sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==} @@ -10101,6 +10262,7 @@ packages: /slash@4.0.0: resolution: {integrity: sha512-3dOsAHXXUkQTpOYcoAxLIorMTp4gIQr5IW3iVb7A7lFIp0VHhnynm9izx6TssdrIcVIESAlVjtnO2K8bg+Coew==} engines: {node: '>=12'} + dev: false /slice-ansi@3.0.0: resolution: {integrity: sha512-pSyv7bSTC7ig9Dcgbw9AuRNUb5k5V6oDudjZoMBSr13qpLBG7tB+zgCkARjq7xIUgdz5P1Qe8u+rSGdouOOIyQ==} @@ -10166,7 +10328,7 @@ packages: /sort-object-keys@1.1.3: resolution: {integrity: sha512-855pvK+VkU7PaKYPc+Jjnmt4EzejQHyhhF33q31qG8x7maDzkeFhAAThdCYay11CISO+qAMwjOBP+fPZe0IPyg==} - dev: true + dev: false /sort-package-json@2.4.1: resolution: {integrity: sha512-Nd3rgLBJcZ4iw7tpuOhwBupG6SvUDU0Fy1cZGAMorA2JmDUb+29Dg5phJK9gapa2Ak9d15w/RuMl/viwX+nKwQ==} @@ -10178,7 +10340,7 @@ packages: globby: 13.1.4 is-plain-obj: 4.1.0 sort-object-keys: 1.1.3 - dev: true + dev: false /source-list-map@2.0.1: resolution: {integrity: sha512-qnQ7gVMxGNxsiL4lEuJwe/To8UnK7fAnmbGEEH8RpLouuKbeEm0lhbQVFIrNSuB+G7tVrAlVsZgETT5nljf+Iw==} @@ -10255,6 +10417,10 @@ packages: resolution: {integrity: sha512-XkD+zwiqXHikFZm4AX/7JSCXA98U5Db4AFd5XUg/+9UNtnH75+Z9KxtpYiJZx36mUDVOwH83pl7yvCer6ewM3w==} dev: true + /speedometer@1.0.0: + resolution: {integrity: sha512-lgxErLl/7A5+vgIIXsh9MbeukOaCb2axgQ+bKCdIE+ibNT4XNYGNCR1qFEGq6F+YDASXK3Fh/c5FgtZchFolxw==} + dev: false + /split-string@3.1.0: resolution: {integrity: sha512-NzNVhJDYpwceVVii8/Hu6DKfD2G+NrQHlS/V/qgv763EYudVwEcMQNxd2lh+0VrUByXN/oJkl5grOhYWvQUYiw==} engines: {node: '>=0.10.0'} @@ -10411,7 +10577,6 @@ packages: resolution: {integrity: sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==} dependencies: safe-buffer: 5.1.2 - dev: true /string_decoder@1.3.0: resolution: {integrity: sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==} @@ -10487,7 +10652,6 @@ packages: /strip-json-comments@2.0.1: resolution: {integrity: sha512-4gB8na07fecVVkOI6Rs4e7T6NOTki5EmL7TUduTs6bu3EdnSycntVJ4re8kgZA+wx9IueI2Y11bfbgwtzuE0KQ==} engines: {node: '>=0.10.0'} - dev: true /strip-json-comments@3.1.1: resolution: {integrity: sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==} @@ -10572,6 +10736,7 @@ packages: dependencies: '@pkgr/utils': 2.4.0 tslib: 2.5.2 + dev: false /tapable@0.2.9: resolution: {integrity: sha512-2wsvQ+4GwBvLPLWsNfLCDYGsW6xb7aeC6utq2Qh0PFwgEy7K7dsma9Jsmb2zSQj7GvYAyUGSntLtsv++GmgL1A==} @@ -10618,7 +10783,6 @@ packages: dependencies: readable-stream: 2.3.8 xtend: 4.0.2 - dev: true /through2@4.0.2: resolution: {integrity: sha512-iOqSav00cVxEEICeD7TjLB1sueEL+81Wpzp2bY17uZjZN0pWZPuo4suZ/61VujxmqSGFfgOcNuTZ85QJwNZQpw==} @@ -10659,6 +10823,7 @@ packages: /titleize@3.0.0: resolution: {integrity: sha512-KxVu8EYHDPBdUYdKZdKtU2aj2XfEx9AfjXxE/Aj0vT06w2icA09Vus1rh6eSu1y01akYg6BjIK/hxyLJINoMLQ==} engines: {node: '>=12'} + dev: false /tmp@0.0.33: resolution: {integrity: sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw==} @@ -10804,6 +10969,12 @@ packages: resolution: {integrity: sha512-JVa5ijo+j/sOoHGjw0sxw734b1LhBkQ3bvUGNdxnVXDCX81Yx7TFgnZygxrIIWn23hbfTaMYLwRmAxFyDuFmIw==} dev: true + /tunnel-agent@0.6.0: + resolution: {integrity: sha512-McnNiV1l8RYeY8tBgEpuodCC1mLUdbSN+CYBL7kJsJNInOP8UjDDEwdk6Mw60vdLLrr5NHKZhMAOSrR2NZuQ+w==} + dependencies: + safe-buffer: 5.2.1 + dev: false + /type-check@0.4.0: resolution: {integrity: sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==} engines: {node: '>= 0.8.0'} @@ -11070,6 +11241,7 @@ packages: /untildify@4.0.0: resolution: {integrity: sha512-KK8xQ1mkzZeg9inewmFVDNkg3l5LUhoq9kN6iWYB/CC9YMG8HA+c1Q8HwDe6dEX7kErrEVNVBO3fWsVq5iDgtw==} engines: {node: '>=8'} + dev: false /upath@1.2.0: resolution: {integrity: sha512-aZwGpamFO61g3OlfT7OQCHqhGnW43ieH9WZeP7QxN/G/jS4jfqUkZxoryvJgVPEcrl5NL/ggHsSmLMHuH64Lhg==} @@ -11612,7 +11784,6 @@ packages: /xtend@4.0.2: resolution: {integrity: sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==} engines: {node: '>=0.4'} - dev: true /y18n@3.2.2: resolution: {integrity: sha512-uGZHXkHnhF0XeeAPgnKfPv1bgKAYyVvmNL1xlKsPYZPaIHxGti2hHqvOCQv71XMsLxu1QjergkqogUnms5D3YQ==} diff --git a/scripts/init.ts b/scripts/init.ts new file mode 100644 index 00000000..7670ab72 --- /dev/null +++ b/scripts/init.ts @@ -0,0 +1,17 @@ +import path from 'path' +import {argv} from 'process' + +import {init} from '../src/node' + +global.__DEV__ = true + +const args = argv.slice(2) + +init({ + cwd: path.resolve(__dirname, '..'), + path: args[0], +}).catch((err) => { + // eslint-disable-next-line no-console + console.error(err.stack) + process.exit(1) +}) diff --git a/src/cli/index.ts b/src/cli/index.ts index 1d1b270e..7f2bb421 100644 --- a/src/cli/index.ts +++ b/src/cli/index.ts @@ -26,6 +26,14 @@ cli return buildAction(options) }) +cli.command('init [path]', 'Initialize package').action(async (p) => { + const {initAction} = await import('./initAction') + + return initAction({ + path: p, + }) +}) + cli .command('watch', 'Watch package') .option('--strict', 'Strict mode') diff --git a/src/cli/initAction.ts b/src/cli/initAction.ts new file mode 100644 index 00000000..ff873409 --- /dev/null +++ b/src/cli/initAction.ts @@ -0,0 +1,13 @@ +import {init} from '../node/init' +import {handleError} from './handleError' + +export async function initAction(options: {path: string}): Promise { + try { + await init({ + cwd: process.cwd(), + path: options.path, + }) + } catch (err) { + handleError(err) + } +} diff --git a/src/node/core/index.ts b/src/node/core/index.ts index ff4604ce..14048291 100644 --- a/src/node/core/index.ts +++ b/src/node/core/index.ts @@ -3,4 +3,5 @@ export * from './contexts' export * from './defaults' export * from './isRecord' export * from './pkg' +export * from './template' export * from './ts' diff --git a/src/node/core/pkg/types.ts b/src/node/core/pkg/types.ts index a485c998..72f21cc9 100644 --- a/src/node/core/pkg/types.ts +++ b/src/node/core/pkg/types.ts @@ -3,7 +3,10 @@ export interface PackageJSON { type?: 'commonjs' | 'module' version: string private?: boolean + author?: string | {name: string; email?: string; url?: string} name: string + description?: string + keywords?: string[] bin?: Record dependencies?: Record devDependencies?: Record @@ -34,5 +37,15 @@ export interface PackageJSON { source?: string module?: string types?: string + files?: string[] + scripts?: Record browserslist?: string[] + engines?: { + node?: string + npm?: string + } + repository?: string | {type: 'git'; url: string} + bugs?: string | {url: string; email?: string} + homepage?: string + license?: string } diff --git a/src/node/core/template/createFromTemplate.ts b/src/node/core/template/createFromTemplate.ts new file mode 100644 index 00000000..2ee451f1 --- /dev/null +++ b/src/node/core/template/createFromTemplate.ts @@ -0,0 +1,85 @@ +import {writeFile} from 'fs/promises' +import {mkdirp} from 'mkdirp' +import {dirname, relative, resolve} from 'path' +import prompts from 'prompts' + +import {Logger} from '../../logger' +import {PkgTemplate} from './types' + +const promptsTypes = { + string: 'text' as const, +} + +/** @internal */ +export async function createFromTemplate(options: { + cwd: string + logger: Logger + packagePath: string + template: PkgTemplate +}): Promise { + const {cwd, logger, packagePath, template: templateOrResolver} = options + + const template = + typeof templateOrResolver === 'function' + ? await templateOrResolver({cwd, logger, packagePath}) + : templateOrResolver + + logger.log('create new package at', relative(cwd, packagePath)) + + const templateOptions: Record = {} + + for (const templateOption of template.options) { + const templateValidate = templateOption.validate + + const res = await prompts( + { + type: promptsTypes[templateOption.type], + name: templateOption.name, + message: templateOption.description, + validate: templateValidate ? (prev) => templateValidate(prev) : undefined, + initial: + typeof templateOption.initial === 'function' + ? templateOption.initial(templateOptions) + : templateOption.initial, + }, + {onCancel: () => process.exit(0)} + ) + + templateOptions[templateOption.name] = templateOption.parse + ? templateOption.parse(res[templateOption.name]) + : res[templateOption.name] + } + + const features: Record = {} + + for (const templateFeature of template.features) { + const res = templateFeature.optional + ? await prompts( + { + type: 'confirm', + name: 'confirm', + message: `use ${templateFeature.name}?`, + initial: templateFeature.initial, + }, + {onCancel: () => process.exit(0)} + ) + : undefined + + features[templateFeature.name] = res?.confirm || !templateFeature.optional + } + + const files = await template.getFiles(templateOptions, features) + + files.sort((a, b) => { + return a.name.localeCompare(b.name) + }) + + for (const file of files) { + const filePath = resolve(packagePath, file.name) + + await mkdirp(dirname(filePath)) + await writeFile(filePath, file.contents.trim() + '\n') + + logger.success(`wrote ${relative(cwd, filePath)}`) + } +} diff --git a/src/node/core/template/define.ts b/src/node/core/template/define.ts new file mode 100644 index 00000000..7d9aad57 --- /dev/null +++ b/src/node/core/template/define.ts @@ -0,0 +1,6 @@ +import {PkgTemplateOption} from './types' + +/** @public */ +export function defineTemplateOption(option: PkgTemplateOption): PkgTemplateOption { + return option +} diff --git a/src/node/core/template/index.ts b/src/node/core/template/index.ts new file mode 100644 index 00000000..79d73bbe --- /dev/null +++ b/src/node/core/template/index.ts @@ -0,0 +1,3 @@ +export * from './createFromTemplate' +export * from './define' +export * from './types' diff --git a/src/node/core/template/types.ts b/src/node/core/template/types.ts new file mode 100644 index 00000000..b1b85949 --- /dev/null +++ b/src/node/core/template/types.ts @@ -0,0 +1,45 @@ +import {Logger} from '../../logger' + +/** @public */ +export interface PkgTemplateFile { + name: string + contents: string +} + +/** @public */ +export interface PkgTemplateStringOption { + name: string + type: 'string' + description: string + initial?: T | ((options: Record) => T) + parse?: (v: string) => T | null + validate?: (v: string) => string | true +} + +/** @public */ +export type PkgTemplateOption = PkgTemplateStringOption + +/** @public */ +export interface PkgTemplateDefinition { + options: PkgTemplateStringOption[] + features: { + name: string + optional: boolean + initial: boolean + }[] + getFiles: ( + options: Record, + features: Record + ) => Promise +} + +/** @public */ +export type PkgTemplateResolver = (options: { + cwd: string + /** @internal */ + logger: Logger + packagePath: string +}) => PkgTemplateDefinition | Promise + +/** @public */ +export type PkgTemplate = PkgTemplateDefinition | PkgTemplateResolver diff --git a/src/node/index.ts b/src/node/index.ts index 70dcb454..e9ebffee 100644 --- a/src/node/index.ts +++ b/src/node/index.ts @@ -1,6 +1,7 @@ export * from './build' export * from './check' export * from './core' +export * from './init' export * from './logger' export * from './resolveBuildTasks' export * from './tasks' diff --git a/src/node/init.ts b/src/node/init.ts new file mode 100644 index 00000000..f7bed1fb --- /dev/null +++ b/src/node/init.ts @@ -0,0 +1,55 @@ +import {lstat} from 'fs/promises' +import {mkdirp} from 'mkdirp' +import {resolve} from 'path' + +import {createFromTemplate} from './core/template' +import {fileExists} from './fileExists' +import {isEmptyDirectory} from './isEmptyDirectory' +import {createLogger} from './logger' +import {defaultTemplate} from './templates' + +/** @public */ +export async function init(options: {cwd: string; path: string}): Promise { + if (!options.cwd) { + throw new Error('Missing required option: cwd') + } + + if (!options.path) { + throw new Error('Missing required option: path') + } + + const logger = createLogger() + + const packagePath = resolve(options.cwd, options.path) + + await ensurePackagePath(packagePath) + + await createFromTemplate({ + cwd: options.cwd, + logger, + template: defaultTemplate, + packagePath, + }) +} + +async function ensurePackagePath(packagePath: string): Promise { + const exists = fileExists(packagePath) + + if (!exists) { + await mkdirp(packagePath) + + return + } + + const dir = (await lstat(packagePath)).isDirectory() + + if (!dir) { + throw new Error('the package path is a file, not a directory') + } + + const empty = await isEmptyDirectory(packagePath) + + if (!empty) { + throw new Error('the package directory is not empty') + } +} diff --git a/src/node/isEmptyDirectory.ts b/src/node/isEmptyDirectory.ts new file mode 100644 index 00000000..48875aae --- /dev/null +++ b/src/node/isEmptyDirectory.ts @@ -0,0 +1,5 @@ +import {readdir} from 'fs/promises' + +export async function isEmptyDirectory(dirPath: string): Promise { + return (await readdir(dirPath)).length === 0 +} diff --git a/src/node/templates/default/index.ts b/src/node/templates/default/index.ts new file mode 100644 index 00000000..98227407 --- /dev/null +++ b/src/node/templates/default/index.ts @@ -0,0 +1 @@ +export * from './template' diff --git a/src/node/templates/default/template.ts b/src/node/templates/default/template.ts new file mode 100644 index 00000000..73f0a77b --- /dev/null +++ b/src/node/templates/default/template.ts @@ -0,0 +1,508 @@ +import getLatestVersion from 'get-latest-version' +import gitUrlParse from 'git-url-parse' +import {outdent} from 'outdent' +import parseGitConfig from 'parse-git-config' +import {resolve} from 'path' +import prettier, {Config as PrettierConfig} from 'prettier' + +import {defineTemplateOption, isRecord, PackageJSON, PkgTemplate, PkgTemplateFile} from '../../core' + +const RE_NAME = /^(?:@(?:[a-z0-9-*~][a-z0-9-*._~]*)\/)?[a-z0-9-~][a-z0-9-._~]*$/i + +export const defaultTemplate: PkgTemplate = async ({cwd, logger, packagePath}) => { + const gitConfig = await parseGitConfig({cwd, type: 'global'}) + + return { + options: [ + defineTemplateOption<{owner: string; name: string}>({ + name: 'repo', + type: 'string', + description: 'git url', + validate: (v) => { + if (!v) return true + + try { + gitUrlParse(v) + return true + } catch (err) { + return 'invalid git url' + } + }, + parse: (v) => { + if (!v) return null + + const result = gitUrlParse(v) + + return {source: result.source, owner: result.owner, name: result.name} + }, + }), + defineTemplateOption({ + name: 'pkgName', + type: 'string', + description: 'package name', + initial: (options) => options.repo?.name || undefined, + validate: (v) => { + if (!v) return 'package name is required' + + const match = RE_NAME.exec(v) + + if (!match) { + return 'invalid package name' + } + + return true + }, + parse: (v) => { + if (!v) { + throw new Error('package name is required') + } + + const match = RE_NAME.exec(v) + + if (!match) { + throw new Error('invalid package name') + } + + const [scope, name] = v.split('/') + + return {scope, name, fullName: v} + }, + }), + defineTemplateOption({ + name: 'description', + type: 'string', + description: 'package description', + }), + defineTemplateOption({ + name: 'authorName', + type: 'string', + description: 'package author name', + initial: gitConfig?.user?.name, + }), + defineTemplateOption({ + name: 'authorEmail', + type: 'string', + description: 'package author email', + initial: gitConfig?.user?.email, + }), + defineTemplateOption({ + name: 'license', + type: 'string', + description: 'package license', + initial: 'MIT', + validate: (v) => { + if (!v) return 'license is required' + + return true + }, + }), + ], + + features: [ + { + name: 'eslint', + optional: true, + initial: true, + }, + { + name: 'typescript', + optional: true, + initial: true, + }, + ], + + async getFiles(options, features) { + const {pkgName, repo} = options + const {fullName: name} = pkgName + + const author = + [options.authorName, options.authorEmail && `<${options.authorEmail}>`] + .filter(Boolean) + .join(' ') ?? undefined + + const prettierConfig: PrettierConfig = { + bracketSpacing: false, + printWidth: 100, + semi: false, + singleQuote: true, + tabWidth: 2, + plugins: ['prettier-plugin-packagejson'], + overrides: [ + { + files: ['*.yml'], + options: { + singleQuote: false, + }, + }, + ], + } + + const pkgJson: PackageJSON & { + prettier?: PrettierConfig + ['lint-staged']?: Record + } = { + name, + version: '0.0.0', + description: options.description ?? undefined, + keywords: [], + license: options.license, + author, + type: 'module', + exports: { + '.': { + types: undefined, + source: features.typescript ? './src/index.ts' : './src/index.js', + require: './dist/index.cjs', + import: './dist/index.js', + default: './dist/index.js', + }, + './package.json': './package.json', + }, + main: './dist/index.cjs', + module: './dist/index.js', + source: features.typescript ? './src/index.ts' : './src/index.js', + files: ['dist', 'src'], + scripts: { + build: 'run-s clean pkg:build pkg:check', + clean: 'rimraf dist', + format: 'prettier --write --cache --ignore-unknown .', + 'pkg:build': 'pkg build --strict', + 'pkg:check': 'pkg check --strict', + }, + prettier: prettierConfig, + 'lint-staged': { + '*': ['prettier --write --cache --ignore-unknown'], + }, + dependencies: {}, + devDependencies: { + '@sanity/pkg-utils': '*', + 'lint-staged': '*', + 'npm-run-all': '*', + prettier: '*', + 'prettier-plugin-packagejson': '*', + rimraf: '*', + }, + engines: { + node: '>=18.0.0', + }, + } + + const files: PkgTemplateFile[] = [] + + // .editorconfig + files.push({ + name: '.editorconfig', + contents: outdent` + root = true + + [*] + charset = utf-8 + indent_style = space + indent_size = 2 + end_of_line = lf + insert_final_newline = true + trim_trailing_whitespace = true + `, + }) + + // .gitignore + files.push({ + name: '.gitignore', + contents: outdent` + *.local + *.log + + .DS_Store + etc + dist + node_modules + `, + }) + + files.push({ + name: '.prettierignore', + contents: outdent` + /dist + /pnpm-lock.yaml + `, + }) + + if (repo) { + pkgJson.repository = { + type: 'git', + url: `git+ssh://git@${repo.source}/${repo.owner}/${repo.name}.git`, + } + pkgJson.bugs = { + url: `https://${repo.source}/${repo.owner}/${repo.name}/issues`, + } + pkgJson.homepage = `https://${repo.source}/${repo.owner}/${repo.name}#readme` + } + + if (features.typescript) { + pkgJson.types = './dist/index.d.ts' + + const mainExport = pkgJson.exports?.['.'] + + if (isRecord(mainExport)) { + mainExport.types = './dist/index.d.ts' + } + + pkgJson.scripts = { + ...pkgJson.scripts, + ['type:check']: 'tsc --build', + } + + const devDependencies = pkgJson.devDependencies + + if (isRecord(devDependencies)) { + devDependencies['typescript'] = '*' + } + } + + if (features.eslint) { + const eslintConfig: any = { + root: true, + env: { + browser: true, + es6: true, + node: true, + }, + extends: ['eslint:recommended', 'plugin:prettier/recommended'], + parserOptions: { + ecmaVersion: 2020, + sourceType: 'module', + }, + plugins: ['import', 'prettier'], + rules: { + 'no-console': 'error', + 'no-shadow': 'error', + 'no-warning-comments': ['warn', {location: 'start', terms: ['todo', 'fixme']}], + }, + } + + files.push({ + name: '.eslintignore', + contents: outdent` + /dist + `, + }) + + pkgJson.scripts = { + ...pkgJson.scripts, + lint: features.typescript + ? 'eslint . --ext .cjs,.js,.ts,.tsx' + : 'eslint . --ext .cjs,.js', + } + + pkgJson.devDependencies = { + ...pkgJson.devDependencies, + eslint: '*', + 'eslint-config-prettier': '*', + 'eslint-plugin-import': '*', + 'eslint-plugin-prettier': '*', + } + + if (features.typescript) { + pkgJson.devDependencies = { + ...pkgJson.devDependencies, + '@typescript-eslint/eslint-plugin': '*', + '@typescript-eslint/parser': '*', + } + + const eslintConfigOverride: any = { + files: ['**/*.ts', '**/*.tsx'], + parser: '@typescript-eslint/parser', + parserOptions: { + project: ['./tsconfig.json'], + }, + extends: [ + 'eslint:recommended', + 'plugin:prettier/recommended', + 'plugin:@typescript-eslint/eslint-recommended', + 'plugin:@typescript-eslint/recommended', + ].filter(Boolean), + plugins: ['import', '@typescript-eslint', 'prettier'].filter(Boolean), + rules: { + '@typescript-eslint/explicit-module-boundary-types': 'error', + '@typescript-eslint/interface-name-prefix': 'off', + '@typescript-eslint/member-delimiter-style': 'off', + '@typescript-eslint/no-empty-interface': 'off', + }, + } + + eslintConfig.overrides = [eslintConfigOverride] + } + + files.push({ + name: '.eslintrc.cjs', + contents: format( + resolve(packagePath, '.eslintrc.cjs'), + outdent` + 'use strict' + + /** @type import('eslint').Linter.Config */ + module.exports = ${JSON.stringify(eslintConfig, null, 2)} + `, + prettierConfig + ), + }) + } + + if (features.typescript) { + files.push({ + name: 'tsconfig.settings.json', + contents: format( + resolve(packagePath, 'tsconfig.settings.json'), + outdent` + { + "compilerOptions": { + "module": "ES2020", + "target": "ES2020", + "declaration": true, + "declarationMap": true, + "sourceMap": true, + + // Strict type-checking + "strict": true, + "noImplicitAny": true, + "strictNullChecks": true, + "strictFunctionTypes": true, + "strictPropertyInitialization": true, + "noImplicitThis": true, + "alwaysStrict": true, + + // Additional checks + "noUnusedLocals": true, + "noUnusedParameters": true, + "noImplicitReturns": true, + "noFallthroughCasesInSwitch": true, + "skipLibCheck": true, + + // Module resolution + "moduleResolution": "node", + "allowSyntheticDefaultImports": true, + "esModuleInterop": true + } + } + `, + prettierConfig + ), + }) + + files.push({ + name: 'tsconfig.dist.json', + contents: format( + resolve(packagePath, 'tsconfig.dist.json'), + outdent` + { + "extends": "./tsconfig.settings", + "include": ["./src"], + "compilerOptions": { + "rootDir": ".", + "outDir": "./dist", + "emitDeclarationOnly": true, + "resolveJsonModule": true + } + } + `, + prettierConfig + ), + }) + + files.push({ + name: 'tsconfig.json', + contents: format( + resolve(packagePath, 'tsconfig.json'), + outdent` + { + "extends": "./tsconfig.settings", + "include": ["./*.cjs", "./*.ts", "./src"], + "compilerOptions": { + "rootDir": ".", + "outDir": "./dist", + "noEmit": true, + "allowJs": true, + "resolveJsonModule": true, + } + } + `, + prettierConfig + ), + }) + } + + // source file + if (features.typescript) { + files.push({ + name: 'src/index.ts', + contents: format( + resolve(packagePath, 'src/index.ts'), + outdent` + /** @public */ + export function main(): void { + // + } + `, + prettierConfig + ), + }) + } else { + files.push({ + name: 'src/index.js', + contents: format( + resolve(packagePath, 'src/index.js'), + outdent` + /** @public */ + export function main() { + // + } + `, + prettierConfig + ), + }) + } + + // Resolve latest dependencies + try { + pkgJson.dependencies = await resolveLatestDeps(pkgJson.dependencies ?? {}) + } catch (error) { + logger.warn(error instanceof Error ? error.message : error) + } + + // Resolve latest devDependencies + try { + pkgJson.devDependencies = await resolveLatestDeps(pkgJson.devDependencies ?? {}) + } catch (error) { + logger.warn(error instanceof Error ? error.message : error) + } + + files.push({ + name: 'package.json', + contents: format( + resolve(packagePath, 'package.json'), + JSON.stringify(pkgJson, null, 2), + prettierConfig + ), + }) + + return files + }, + } +} + +function format(filepath: string, input: string, prettierOptions: PrettierConfig) { + return prettier.format(input, {...prettierOptions, filepath}) +} + +async function resolveLatestDeps(deps: Record) { + const depsEntries = Object.entries(deps) + const latestDeps: Record = {} + + for (const entry of depsEntries) { + const [name, version] = entry + const latestVersion = await getLatestVersion(name, version) + latestDeps[name] = latestVersion ? `^${latestVersion}` : version + } + + return latestDeps +} diff --git a/src/node/templates/index.ts b/src/node/templates/index.ts new file mode 100644 index 00000000..a17c69c2 --- /dev/null +++ b/src/node/templates/index.ts @@ -0,0 +1 @@ +export * from './default'