From 7a9fc0f57e43c2eab44e9442e5896f951a8c751a Mon Sep 17 00:00:00 2001 From: Peter Burns Date: Thu, 29 Sep 2022 10:06:31 -0700 Subject: [PATCH] [labs/cli] Lazily install and locally version localize (#2936) * [cli] Lazily install and locally version localize Also merge the two localize commands into one They have just about the same deps and share some setup and teardown code, there's no win in putting them in separate modules. * Use better assertions of no errors. This should print out the stderr output in the case there was some. * Fix error output The .finally fork of the Promise.race result promise was causing an early exit from node before the ordinary uvu error handling could kick in. * Fix failing test It was passing locally because the cwd was set to the CLI directory, but we want to run in a fake workspace directory. * Add an installation message when running npm install. * Changeset * Use try/finally instead of promise methods * Move localize command into its own package. --- .changeset/clean-parents-doubt.md | 6 + .eslintignore | 3 + .prettierignore | 3 + package-lock.json | 45 ++ packages/labs/cli-localize/.gitignore | 2 + packages/labs/cli-localize/CHANGELOG.md | 3 + packages/labs/cli-localize/README.md | 7 + packages/labs/cli-localize/package-lock.json | 660 ++++++++++++++++++ packages/labs/cli-localize/package.json | 81 +++ .../build.ts => cli-localize/src/commands.ts} | 30 +- packages/labs/cli-localize/src/index.ts | 59 ++ packages/labs/cli-localize/tsconfig.json | 23 + packages/labs/cli/bin/lit.js | 4 +- packages/labs/cli/package.json | 2 +- .../labs/cli/src/lib/commands/localize.ts | 51 +- packages/labs/cli/src/lib/lit-cli.ts | 10 +- packages/labs/cli/src/lib/localize/extract.ts | 54 -- packages/labs/cli/src/test/cli-test-utils.ts | 4 + packages/labs/cli/src/test/gen/react_test.ts | 2 +- packages/labs/cli/src/test/help_test.ts | 30 +- packages/labs/cli/src/test/uvu-wrapper.ts | 30 +- 21 files changed, 975 insertions(+), 134 deletions(-) create mode 100644 .changeset/clean-parents-doubt.md create mode 100644 packages/labs/cli-localize/.gitignore create mode 100644 packages/labs/cli-localize/CHANGELOG.md create mode 100644 packages/labs/cli-localize/README.md create mode 100644 packages/labs/cli-localize/package-lock.json create mode 100644 packages/labs/cli-localize/package.json rename packages/labs/{cli/src/lib/localize/build.ts => cli-localize/src/commands.ts} (60%) create mode 100644 packages/labs/cli-localize/src/index.ts create mode 100644 packages/labs/cli-localize/tsconfig.json delete mode 100644 packages/labs/cli/src/lib/localize/extract.ts diff --git a/.changeset/clean-parents-doubt.md b/.changeset/clean-parents-doubt.md new file mode 100644 index 0000000000..29b811b703 --- /dev/null +++ b/.changeset/clean-parents-doubt.md @@ -0,0 +1,6 @@ +--- +'@lit-labs/cli': minor +'@lit/localize-tools': minor +--- + +Locally version and lazily install the localize command. diff --git a/.eslintignore b/.eslintignore index 60ea085f70..7c51e12262 100644 --- a/.eslintignore +++ b/.eslintignore @@ -159,6 +159,9 @@ packages/labs/cli/index.d.ts packages/labs/cli/index.d.ts.map packages/labs/cli/test-gen/ +packages/labs/cli-localize/lib/ +packages/labs/cli-localize/node_modules/ + packages/labs/context/development/ packages/labs/context/test/ packages/labs/context/node_modules/ diff --git a/.prettierignore b/.prettierignore index 1a9631ebbb..1371f4b5d5 100644 --- a/.prettierignore +++ b/.prettierignore @@ -145,6 +145,9 @@ packages/labs/cli/index.d.ts packages/labs/cli/index.d.ts.map packages/labs/cli/test-gen/ +packages/labs/cli-localize/lib/ +packages/labs/cli-localize/node_modules/ + packages/labs/context/development/ packages/labs/context/test/ packages/labs/context/node_modules/ diff --git a/package-lock.json b/package-lock.json index 6809531d52..c13ff6baa2 100644 --- a/package-lock.json +++ b/package-lock.json @@ -2563,6 +2563,10 @@ "resolved": "packages/labs/cli", "link": true }, + "node_modules/@lit-labs/cli-localize": { + "resolved": "packages/labs/cli-localize", + "link": true + }, "node_modules/@lit-labs/context": { "resolved": "packages/labs/context", "link": true @@ -23877,6 +23881,32 @@ "node": ">=14.8.0" } }, + "packages/labs/cli-localize": { + "version": "0.0.1", + "license": "BSD-3-Clause", + "dependencies": { + "@lit/localize-tools": "^0.6.3" + }, + "devDependencies": { + "typescript": "~4.6.2" + }, + "engines": { + "node": ">=14.8.0" + } + }, + "packages/labs/cli-localize/node_modules/typescript": { + "version": "4.6.4", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.6.4.tgz", + "integrity": "sha512-9ia/jWHIEbo49HfjrLGfKbZSuWo9iTMwXO+Ca3pRsSpbsMbc7/IU8NKdCZVRRBafVPGnoJeFL76ZOAA84I9fEg==", + "dev": true, + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=4.2.0" + } + }, "packages/labs/cli/node_modules/chalk": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/chalk/-/chalk-5.0.1.tgz", @@ -26420,6 +26450,21 @@ } } }, + "@lit-labs/cli-localize": { + "version": "file:packages/labs/cli-localize", + "requires": { + "@lit/localize-tools": "^0.6.3", + "typescript": "~4.6.2" + }, + "dependencies": { + "typescript": { + "version": "4.6.4", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.6.4.tgz", + "integrity": "sha512-9ia/jWHIEbo49HfjrLGfKbZSuWo9iTMwXO+Ca3pRsSpbsMbc7/IU8NKdCZVRRBafVPGnoJeFL76ZOAA84I9fEg==", + "dev": true + } + } + }, "@lit-labs/context": { "version": "file:packages/labs/context", "requires": { diff --git a/packages/labs/cli-localize/.gitignore b/packages/labs/cli-localize/.gitignore new file mode 100644 index 0000000000..ca54677a04 --- /dev/null +++ b/packages/labs/cli-localize/.gitignore @@ -0,0 +1,2 @@ +/lib/ +/node_modules/ diff --git a/packages/labs/cli-localize/CHANGELOG.md b/packages/labs/cli-localize/CHANGELOG.md new file mode 100644 index 0000000000..4419748b49 --- /dev/null +++ b/packages/labs/cli-localize/CHANGELOG.md @@ -0,0 +1,3 @@ +# @lit-labs/cli + +## 0.0.1 diff --git a/packages/labs/cli-localize/README.md b/packages/labs/cli-localize/README.md new file mode 100644 index 0000000000..3b9adf7fe4 --- /dev/null +++ b/packages/labs/cli-localize/README.md @@ -0,0 +1,7 @@ +# @lit-labs/cli-localize + +Powers the `lit localize` command. + +Don't use this directly, but install `@lit-labs/cli` and run `lit localize` from it. + +That command will load this package from the nearest node_modules directory, or offer to install it if it's not found. diff --git a/packages/labs/cli-localize/package-lock.json b/packages/labs/cli-localize/package-lock.json new file mode 100644 index 0000000000..7715f04c85 --- /dev/null +++ b/packages/labs/cli-localize/package-lock.json @@ -0,0 +1,660 @@ +{ + "name": "@lit-labs/cli-localize", + "version": "0.0.1", + "lockfileVersion": 2, + "requires": true, + "packages": { + "": { + "name": "@lit-labs/cli-localize", + "version": "0.0.1", + "license": "BSD-3-Clause", + "dependencies": { + "@lit/localize-tools": "^0.6.3" + }, + "devDependencies": { + "typescript": "~4.6.2" + }, + "engines": { + "node": ">=14.8.0" + } + }, + "node_modules/@lit/localize": { + "version": "0.11.3", + "resolved": "https://registry.npmjs.org/@lit/localize/-/localize-0.11.3.tgz", + "integrity": "sha512-zWq74Sa/HvSRAtXv9UaBbZd7B1wP82rV/71krYJ+INdexye+nILjPUiGHYHb0G54+v7YpyZi61Fm5yI+kfcJnw==", + "dependencies": { + "@lit/reactive-element": "^1.0.0", + "lit": "^2.0.0" + } + }, + "node_modules/@lit/localize-tools": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/@lit/localize-tools/-/localize-tools-0.6.3.tgz", + "integrity": "sha512-cJ5RazZw2GxUoSRqeZt5oIZfIvf217r/VFWXx7DkcNCELDdr29MCF9Bvl4gLK5X6GG0i4WjNccEIn3TO4i/BMg==", + "dependencies": { + "@lit/localize": "^0.11.0", + "@xmldom/xmldom": "^0.7.0", + "fast-glob": "^3.2.7", + "fs-extra": "^10.0.0", + "jsonschema": "^1.4.0", + "lit": "^2.2.0", + "minimist": "^1.2.5", + "parse5": "^6.0.1", + "source-map-support": "^0.5.19", + "typescript": "^4.3.5" + }, + "bin": { + "lit-localize": "bin/lit-localize.js" + } + }, + "node_modules/@lit/reactive-element": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/@lit/reactive-element/-/reactive-element-1.3.2.tgz", + "integrity": "sha512-A2e18XzPMrIh35nhIdE4uoqRzoIpEU5vZYuQN4S3Ee1zkGdYC27DP12pewbw/RLgPHzaE4kx/YqxMzebOpm0dA==" + }, + "node_modules/@nodelib/fs.scandir": { + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", + "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", + "dependencies": { + "@nodelib/fs.stat": "2.0.5", + "run-parallel": "^1.1.9" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.stat": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", + "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.walk": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", + "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", + "dependencies": { + "@nodelib/fs.scandir": "2.1.5", + "fastq": "^1.6.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@types/trusted-types": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/@types/trusted-types/-/trusted-types-2.0.2.tgz", + "integrity": "sha512-F5DIZ36YVLE+PN+Zwws4kJogq47hNgX3Nx6WyDJ3kcplxyke3XIzB8uK5n/Lpm1HBsbGzd6nmGehL8cPekP+Tg==" + }, + "node_modules/@xmldom/xmldom": { + "version": "0.7.5", + "resolved": "https://registry.npmjs.org/@xmldom/xmldom/-/xmldom-0.7.5.tgz", + "integrity": "sha512-V3BIhmY36fXZ1OtVcI9W+FxQqxVLsPKcNjWigIaa81dLC9IolJl5Mt4Cvhmr0flUnjSpTdrbMTSbXqYqV5dT6A==", + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/braces": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", + "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", + "dependencies": { + "fill-range": "^7.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/buffer-from": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", + "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==" + }, + "node_modules/fast-glob": { + "version": "3.2.11", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.11.tgz", + "integrity": "sha512-xrO3+1bxSo3ZVHAnqzyuewYT6aMFHRAd4Kcs92MAonjwQZLsK9d0SF1IyQ3k5PoirxTW0Oe/RqFgMQ6TcNE5Ew==", + "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" + }, + "engines": { + "node": ">=8.6.0" + } + }, + "node_modules/fastq": { + "version": "1.13.0", + "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.13.0.tgz", + "integrity": "sha512-YpkpUnK8od0o1hmeSc7UUs/eB/vIPWJYjKck2QKIzAf71Vm1AAQ3EbuZB3g2JIy+pg+ERD0vqI79KyZiB2e2Nw==", + "dependencies": { + "reusify": "^1.0.4" + } + }, + "node_modules/fill-range": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", + "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", + "dependencies": { + "to-regex-range": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/fs-extra": { + "version": "10.1.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-10.1.0.tgz", + "integrity": "sha512-oRXApq54ETRj4eMiFzGnHWGy+zo5raudjuxN0b8H7s/RU2oW0Wvsx9O0ACRN/kRq9E8Vu/ReskGB5o3ji+FzHQ==", + "dependencies": { + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/graceful-fs": { + "version": "4.2.10", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.10.tgz", + "integrity": "sha512-9ByhssR2fPVsNZj478qUUbKfmL0+t5BDVyjShtyZZLiK7ZDAArFFfopyOTj0M05wE2tJPisA4iTnnXl2YoPvOA==" + }, + "node_modules/is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-glob": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", + "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", + "dependencies": { + "is-extglob": "^2.1.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "engines": { + "node": ">=0.12.0" + } + }, + "node_modules/jsonfile": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.1.0.tgz", + "integrity": "sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==", + "dependencies": { + "universalify": "^2.0.0" + }, + "optionalDependencies": { + "graceful-fs": "^4.1.6" + } + }, + "node_modules/jsonschema": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/jsonschema/-/jsonschema-1.4.1.tgz", + "integrity": "sha512-S6cATIPVv1z0IlxdN+zUk5EPjkGCdnhN4wVSBlvoUO1tOLJootbo9CquNJmbIh4yikWHiUedhRYrNPn1arpEmQ==", + "engines": { + "node": "*" + } + }, + "node_modules/lit": { + "version": "2.2.6", + "resolved": "https://registry.npmjs.org/lit/-/lit-2.2.6.tgz", + "integrity": "sha512-K2vkeGABfSJSfkhqHy86ujchJs3NR9nW1bEEiV+bXDkbiQ60Tv5GUausYN2mXigZn8lC1qXuc46ArQRKYmumZw==", + "dependencies": { + "@lit/reactive-element": "^1.3.0", + "lit-element": "^3.2.0", + "lit-html": "^2.2.0" + } + }, + "node_modules/lit-element": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/lit-element/-/lit-element-3.2.0.tgz", + "integrity": "sha512-HbE7yt2SnUtg5DCrWt028oaU4D5F4k/1cntAFHTkzY8ZIa8N0Wmu92PxSxucsQSOXlODFrICkQ5x/tEshKi13g==", + "dependencies": { + "@lit/reactive-element": "^1.3.0", + "lit-html": "^2.2.0" + } + }, + "node_modules/lit-html": { + "version": "2.2.6", + "resolved": "https://registry.npmjs.org/lit-html/-/lit-html-2.2.6.tgz", + "integrity": "sha512-xOKsPmq/RAKJ6dUeOxhmOYFjcjf0Q7aSdfBJgdJkOfCUnkmmJPxNrlZpRBeVe1Gg50oYWMlgm6ccAE/SpJgSdw==", + "dependencies": { + "@types/trusted-types": "^2.0.2" + } + }, + "node_modules/merge2": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", + "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", + "engines": { + "node": ">= 8" + } + }, + "node_modules/micromatch": { + "version": "4.0.5", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.5.tgz", + "integrity": "sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==", + "dependencies": { + "braces": "^3.0.2", + "picomatch": "^2.3.1" + }, + "engines": { + "node": ">=8.6" + } + }, + "node_modules/minimist": { + "version": "1.2.6", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.6.tgz", + "integrity": "sha512-Jsjnk4bw3YJqYzbdyBiNsPWHPfO++UGG749Cxs6peCu5Xg4nrena6OVxOYxrQTqww0Jmwt+Ref8rggumkTLz9Q==" + }, + "node_modules/parse5": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/parse5/-/parse5-6.0.1.tgz", + "integrity": "sha512-Ofn/CTFzRGTTxwpNEs9PP93gXShHcTq255nzRYSKe8AkVpZY7e1fpmTfOyoIvjP5HG7Z2ZM7VS9PPhQGW2pOpw==" + }, + "node_modules/picomatch": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/queue-microtask": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", + "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/reusify": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", + "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==", + "engines": { + "iojs": ">=1.0.0", + "node": ">=0.10.0" + } + }, + "node_modules/run-parallel": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", + "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "dependencies": { + "queue-microtask": "^1.2.2" + } + }, + "node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/source-map-support": { + "version": "0.5.21", + "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz", + "integrity": "sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==", + "dependencies": { + "buffer-from": "^1.0.0", + "source-map": "^0.6.0" + } + }, + "node_modules/to-regex-range": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "dependencies": { + "is-number": "^7.0.0" + }, + "engines": { + "node": ">=8.0" + } + }, + "node_modules/typescript": { + "version": "4.6.4", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.6.4.tgz", + "integrity": "sha512-9ia/jWHIEbo49HfjrLGfKbZSuWo9iTMwXO+Ca3pRsSpbsMbc7/IU8NKdCZVRRBafVPGnoJeFL76ZOAA84I9fEg==", + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=4.2.0" + } + }, + "node_modules/universalify": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.0.tgz", + "integrity": "sha512-hAZsKq7Yy11Zu1DE0OzWjw7nnLZmJZYTDZZyEFHZdUhV8FkH5MCfoU1XMaxXovpyW5nq5scPqq0ZDP9Zyl04oQ==", + "engines": { + "node": ">= 10.0.0" + } + } + }, + "dependencies": { + "@lit/localize": { + "version": "0.11.3", + "resolved": "https://registry.npmjs.org/@lit/localize/-/localize-0.11.3.tgz", + "integrity": "sha512-zWq74Sa/HvSRAtXv9UaBbZd7B1wP82rV/71krYJ+INdexye+nILjPUiGHYHb0G54+v7YpyZi61Fm5yI+kfcJnw==", + "requires": { + "@lit/reactive-element": "^1.0.0", + "lit": "^2.0.0" + } + }, + "@lit/localize-tools": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/@lit/localize-tools/-/localize-tools-0.6.3.tgz", + "integrity": "sha512-cJ5RazZw2GxUoSRqeZt5oIZfIvf217r/VFWXx7DkcNCELDdr29MCF9Bvl4gLK5X6GG0i4WjNccEIn3TO4i/BMg==", + "requires": { + "@lit/localize": "^0.11.0", + "@xmldom/xmldom": "^0.7.0", + "fast-glob": "^3.2.7", + "fs-extra": "^10.0.0", + "jsonschema": "^1.4.0", + "lit": "^2.2.0", + "minimist": "^1.2.5", + "parse5": "^6.0.1", + "source-map-support": "^0.5.19", + "typescript": "^4.3.5" + } + }, + "@lit/reactive-element": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/@lit/reactive-element/-/reactive-element-1.3.2.tgz", + "integrity": "sha512-A2e18XzPMrIh35nhIdE4uoqRzoIpEU5vZYuQN4S3Ee1zkGdYC27DP12pewbw/RLgPHzaE4kx/YqxMzebOpm0dA==" + }, + "@nodelib/fs.scandir": { + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", + "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", + "requires": { + "@nodelib/fs.stat": "2.0.5", + "run-parallel": "^1.1.9" + } + }, + "@nodelib/fs.stat": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", + "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==" + }, + "@nodelib/fs.walk": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", + "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", + "requires": { + "@nodelib/fs.scandir": "2.1.5", + "fastq": "^1.6.0" + } + }, + "@types/trusted-types": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/@types/trusted-types/-/trusted-types-2.0.2.tgz", + "integrity": "sha512-F5DIZ36YVLE+PN+Zwws4kJogq47hNgX3Nx6WyDJ3kcplxyke3XIzB8uK5n/Lpm1HBsbGzd6nmGehL8cPekP+Tg==" + }, + "@xmldom/xmldom": { + "version": "0.7.5", + "resolved": "https://registry.npmjs.org/@xmldom/xmldom/-/xmldom-0.7.5.tgz", + "integrity": "sha512-V3BIhmY36fXZ1OtVcI9W+FxQqxVLsPKcNjWigIaa81dLC9IolJl5Mt4Cvhmr0flUnjSpTdrbMTSbXqYqV5dT6A==" + }, + "braces": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", + "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", + "requires": { + "fill-range": "^7.0.1" + } + }, + "buffer-from": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", + "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==" + }, + "fast-glob": { + "version": "3.2.11", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.11.tgz", + "integrity": "sha512-xrO3+1bxSo3ZVHAnqzyuewYT6aMFHRAd4Kcs92MAonjwQZLsK9d0SF1IyQ3k5PoirxTW0Oe/RqFgMQ6TcNE5Ew==", + "requires": { + "@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" + } + }, + "fastq": { + "version": "1.13.0", + "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.13.0.tgz", + "integrity": "sha512-YpkpUnK8od0o1hmeSc7UUs/eB/vIPWJYjKck2QKIzAf71Vm1AAQ3EbuZB3g2JIy+pg+ERD0vqI79KyZiB2e2Nw==", + "requires": { + "reusify": "^1.0.4" + } + }, + "fill-range": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", + "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", + "requires": { + "to-regex-range": "^5.0.1" + } + }, + "fs-extra": { + "version": "10.1.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-10.1.0.tgz", + "integrity": "sha512-oRXApq54ETRj4eMiFzGnHWGy+zo5raudjuxN0b8H7s/RU2oW0Wvsx9O0ACRN/kRq9E8Vu/ReskGB5o3ji+FzHQ==", + "requires": { + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" + } + }, + "glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "requires": { + "is-glob": "^4.0.1" + } + }, + "graceful-fs": { + "version": "4.2.10", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.10.tgz", + "integrity": "sha512-9ByhssR2fPVsNZj478qUUbKfmL0+t5BDVyjShtyZZLiK7ZDAArFFfopyOTj0M05wE2tJPisA4iTnnXl2YoPvOA==" + }, + "is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==" + }, + "is-glob": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", + "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", + "requires": { + "is-extglob": "^2.1.1" + } + }, + "is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==" + }, + "jsonfile": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.1.0.tgz", + "integrity": "sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==", + "requires": { + "graceful-fs": "^4.1.6", + "universalify": "^2.0.0" + } + }, + "jsonschema": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/jsonschema/-/jsonschema-1.4.1.tgz", + "integrity": "sha512-S6cATIPVv1z0IlxdN+zUk5EPjkGCdnhN4wVSBlvoUO1tOLJootbo9CquNJmbIh4yikWHiUedhRYrNPn1arpEmQ==" + }, + "lit": { + "version": "2.2.6", + "resolved": "https://registry.npmjs.org/lit/-/lit-2.2.6.tgz", + "integrity": "sha512-K2vkeGABfSJSfkhqHy86ujchJs3NR9nW1bEEiV+bXDkbiQ60Tv5GUausYN2mXigZn8lC1qXuc46ArQRKYmumZw==", + "requires": { + "@lit/reactive-element": "^1.3.0", + "lit-element": "^3.2.0", + "lit-html": "^2.2.0" + } + }, + "lit-element": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/lit-element/-/lit-element-3.2.0.tgz", + "integrity": "sha512-HbE7yt2SnUtg5DCrWt028oaU4D5F4k/1cntAFHTkzY8ZIa8N0Wmu92PxSxucsQSOXlODFrICkQ5x/tEshKi13g==", + "requires": { + "@lit/reactive-element": "^1.3.0", + "lit-html": "^2.2.0" + } + }, + "lit-html": { + "version": "2.2.6", + "resolved": "https://registry.npmjs.org/lit-html/-/lit-html-2.2.6.tgz", + "integrity": "sha512-xOKsPmq/RAKJ6dUeOxhmOYFjcjf0Q7aSdfBJgdJkOfCUnkmmJPxNrlZpRBeVe1Gg50oYWMlgm6ccAE/SpJgSdw==", + "requires": { + "@types/trusted-types": "^2.0.2" + } + }, + "merge2": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", + "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==" + }, + "micromatch": { + "version": "4.0.5", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.5.tgz", + "integrity": "sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==", + "requires": { + "braces": "^3.0.2", + "picomatch": "^2.3.1" + } + }, + "minimist": { + "version": "1.2.6", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.6.tgz", + "integrity": "sha512-Jsjnk4bw3YJqYzbdyBiNsPWHPfO++UGG749Cxs6peCu5Xg4nrena6OVxOYxrQTqww0Jmwt+Ref8rggumkTLz9Q==" + }, + "parse5": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/parse5/-/parse5-6.0.1.tgz", + "integrity": "sha512-Ofn/CTFzRGTTxwpNEs9PP93gXShHcTq255nzRYSKe8AkVpZY7e1fpmTfOyoIvjP5HG7Z2ZM7VS9PPhQGW2pOpw==" + }, + "picomatch": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==" + }, + "queue-microtask": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", + "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==" + }, + "reusify": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", + "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==" + }, + "run-parallel": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", + "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", + "requires": { + "queue-microtask": "^1.2.2" + } + }, + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==" + }, + "source-map-support": { + "version": "0.5.21", + "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz", + "integrity": "sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==", + "requires": { + "buffer-from": "^1.0.0", + "source-map": "^0.6.0" + } + }, + "to-regex-range": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "requires": { + "is-number": "^7.0.0" + } + }, + "typescript": { + "version": "4.6.4", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.6.4.tgz", + "integrity": "sha512-9ia/jWHIEbo49HfjrLGfKbZSuWo9iTMwXO+Ca3pRsSpbsMbc7/IU8NKdCZVRRBafVPGnoJeFL76ZOAA84I9fEg==" + }, + "universalify": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.0.tgz", + "integrity": "sha512-hAZsKq7Yy11Zu1DE0OzWjw7nnLZmJZYTDZZyEFHZdUhV8FkH5MCfoU1XMaxXovpyW5nq5scPqq0ZDP9Zyl04oQ==" + } + } +} diff --git a/packages/labs/cli-localize/package.json b/packages/labs/cli-localize/package.json new file mode 100644 index 0000000000..428c7aa2a7 --- /dev/null +++ b/packages/labs/cli-localize/package.json @@ -0,0 +1,81 @@ +{ + "private": true, + "name": "@lit-labs/cli-localize", + "description": "Implements the `lit localize` command. Use from @lit-labs/cli", + "version": "0.0.1", + "author": "Google LLC", + "license": "BSD-3-Clause", + "bugs": "https://github.com/lit/lit/issues", + "type": "module", + "main": "lib/index.js", + "repository": "lit/lit", + "scripts": { + "build": "wireit", + "test": "wireit", + "test:compile": "wireit", + "build:deps": "wireit", + "build:compile": "wireit" + }, + "wireit": { + "build": { + "dependencies": [ + "build:deps", + "build:compile" + ] + }, + "build:compile": { + "command": "tsc --skipLibCheck || echo ''", + "#comment": "This never fails and always emits output so that we can run tests of code that doesn't type check", + "clean": "if-file-deleted", + "files": [ + "tsconfig.json", + "src/**/*" + ], + "output": [ + "lib", + "test", + "index.{js,js.map,d.ts}" + ] + }, + "build:deps": { + "dependencies": [ + "../../localize-tools:build:ts" + ] + }, + "test": { + "dependencies": [ + "test:compile" + ] + }, + "test:compile": { + "dependencies": [ + "build:deps" + ], + "command": "tsc --pretty --noEmit", + "files": [ + "tsconfig.json", + "src/**/*" + ], + "output": [] + } + }, + "dependencies": { + "@lit/localize-tools": "^0.6.3" + }, + "devDependencies": { + "typescript": "~4.6.2" + }, + "engines": { + "node": ">=14.8.0" + }, + "files": [ + "lib" + ], + "homepage": "https://github.com/lit/lit", + "keywords": [ + "lit", + "localization", + "localize", + "lit-cli" + ] +} diff --git a/packages/labs/cli/src/lib/localize/build.ts b/packages/labs/cli-localize/src/commands.ts similarity index 60% rename from packages/labs/cli/src/lib/localize/build.ts rename to packages/labs/cli-localize/src/commands.ts index 12fdb9ed95..1bed84ff82 100644 --- a/packages/labs/cli/src/lib/localize/build.ts +++ b/packages/labs/cli-localize/src/commands.ts @@ -4,6 +4,17 @@ * SPDX-License-Identifier: BSD-3-Clause */ +/** + * The implementations of our commands exposed in the Lit CLI. + * + * These are in their own module so that we can separate out lightweight + * metadata about the commands (which are used for the --help command, + * and argument parsing), from their actual implementations here, because + * loading all of our deps of the implementation takes time, and loading all + * of the deps of all of the implementations of _every_ command would seriously + * slow down the CLI. + */ + import { readConfigFileAndWriteSchema, Config, @@ -14,8 +25,9 @@ import {TransformLitLocalizer} from '@lit/localize-tools/lib/modes/transform.js' import {RuntimeLitLocalizer} from '@lit/localize-tools/lib/modes/runtime.js'; import {KnownError, unreachable} from '@lit/localize-tools/lib/error.js'; import {LitLocalizer} from '@lit/localize-tools/lib/index.js'; +import {printDiagnostics} from '@lit/localize-tools/lib/typescript.js'; -export const run = async (configPath: string, console: Console) => { +export const build = async (configPath: string, console: Console) => { const config = readConfigFileAndWriteSchema(configPath); const localizer = makeLocalizer(config); console.log('Building'); @@ -35,6 +47,22 @@ export const run = async (configPath: string, console: Console) => { await localizer.build(); }; +export const extract = async (configPath: string, console: Console) => { + const config = readConfigFileAndWriteSchema(configPath); + const localizer = makeLocalizer(config); + // TODO(aomarks) Don't even require the user to have configured their output + // mode if they're just doing extraction. + console.log('Extracting messages'); + const {messages, errors} = localizer.extractSourceMessages(); + if (errors.length > 0) { + printDiagnostics(errors); + throw new KnownError('Error analyzing program'); + } + console.log(`Extracted ${messages.length} messages`); + console.log(`Writing interchange files`); + await localizer.writeInterchangeFiles(); +}; + const makeLocalizer = (config: Config): LitLocalizer => { switch (config.output.mode) { case 'transform': diff --git a/packages/labs/cli-localize/src/index.ts b/packages/labs/cli-localize/src/index.ts new file mode 100644 index 0000000000..fa24d7b1e6 --- /dev/null +++ b/packages/labs/cli-localize/src/index.ts @@ -0,0 +1,59 @@ +/** + * @license + * Copyright 2022 Google LLC + * SPDX-License-Identifier: BSD-3-Clause + */ + +/** + * Defines our interface within the Lit CLI. + */ +export const getCommand = () => { + return { + kind: 'resolved', + name: 'localize', + description: 'Lit localize', + subcommands: [ + { + kind: 'resolved', + name: 'extract', + description: 'Extracts lit-localize messages', + options: [ + { + name: 'config', + description: 'The path to the localize config file', + defaultValue: './lit-localize.json', + }, + ], + async run({config}: {config: string}, console: Console) { + const commands = await import('./commands.js'); + await commands.extract(config, console); + }, + }, + { + kind: 'resolved', + name: 'build', + description: 'Build lit-localize projects', + options: [ + { + name: 'config', + description: 'The path to the localize config file', + defaultValue: './lit-localize.json', + }, + ], + async run({config}: {config: string}, console: Console) { + const commands = await import('./commands.js'); + await commands.build(config, console); + }, + }, + ], + async run(_options: unknown, console: Console) { + console.error( + 'Use one of the localize subcommands, like `lit localize build` or ' + + '`lit localize extract`. Run `lit help localize` for more help.' + ); + return { + exitCode: 1, + }; + }, + }; +}; diff --git a/packages/labs/cli-localize/tsconfig.json b/packages/labs/cli-localize/tsconfig.json new file mode 100644 index 0000000000..91a03f01d9 --- /dev/null +++ b/packages/labs/cli-localize/tsconfig.json @@ -0,0 +1,23 @@ +{ + "compilerOptions": { + "target": "es2020", + "module": "es2022", + "moduleResolution": "node", + "allowSyntheticDefaultImports": true, + "lib": ["es2020"], + "strict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "preserveConstEnums": true, + "forceConsistentCasingInFileNames": true, + "rootDir": "src/", + "outDir": "lib/", + "declaration": true, + "sourceMap": true, + "incremental": true, + "tsBuildInfoFile": "./lib/.tsbuildinfo", + "skipLibCheck": true + }, + "include": ["src/**/*"], + "exclude": [] +} diff --git a/packages/labs/cli/bin/lit.js b/packages/labs/cli/bin/lit.js index dfc30b0cb4..c322726d92 100755 --- a/packages/labs/cli/bin/lit.js +++ b/packages/labs/cli/bin/lit.js @@ -20,7 +20,9 @@ process.on('unhandledRejection', (error) => { // eslint-disable-next-line no-undef const args = process.argv.slice(2); -const cli = new LitCli(args); +// eslint-disable-next-line no-undef +const cwd = process.cwd(); +const cli = new LitCli(args, {cwd}); const result = await cli.run(); // eslint-disable-next-line no-undef process.exit(result?.exitCode ?? 0); diff --git a/packages/labs/cli/package.json b/packages/labs/cli/package.json index 405601dab9..cdf7b36262 100644 --- a/packages/labs/cli/package.json +++ b/packages/labs/cli/package.json @@ -41,7 +41,7 @@ }, "build:deps": { "dependencies": [ - "../../localize-tools:build:ts", + "../cli-localize:build", "../../tests:build", "../analyzer:build", "../gen-wrapper-react:build", diff --git a/packages/labs/cli/src/lib/commands/localize.ts b/packages/labs/cli/src/lib/commands/localize.ts index f060870119..af8fe19bc3 100644 --- a/packages/labs/cli/src/lib/commands/localize.ts +++ b/packages/labs/cli/src/lib/commands/localize.ts @@ -4,53 +4,12 @@ * SPDX-License-Identifier: BSD-3-Clause */ -import {ResolvedCommand, CommandOptions} from '../command.js'; +import {ReferenceToCommand} from '../command.js'; -export const localize: ResolvedCommand = { - kind: 'resolved', +export const localize: ReferenceToCommand = { + kind: 'reference', name: 'localize', description: 'Lit localize', - subcommands: [ - { - kind: 'resolved', - name: 'extract', - description: 'Extracts lit-localize messages', - options: [ - { - name: 'config', - description: 'The path to the localize config file', - defaultValue: './lit-localize.json', - }, - ], - async run({config}: {config: string}, console: Console) { - const extract = await import('../localize/extract.js'); - await extract.run(config, console); - }, - }, - { - kind: 'resolved', - name: 'build', - description: 'Build lit-localize projects', - options: [ - { - name: 'config', - description: 'The path to the localize config file', - defaultValue: './lit-localize.json', - }, - ], - async run({config}: {config: string}, console: Console) { - const build = await import('../localize/build.js'); - await build.run(config, console); - }, - }, - ], - async run(_options: CommandOptions, console: Console) { - console.error( - 'Use one of the localize subcommands, like `lit localize build` or ' + - '`lit localize extract`. Run `lit help localize` for more help.' - ); - return { - exitCode: 1, - }; - }, + importSpecifier: '@lit-labs/cli-localize', + installFrom: '@lit-labs/cli-localize', }; diff --git a/packages/labs/cli/src/lib/lit-cli.ts b/packages/labs/cli/src/lib/lit-cli.ts index 18b00d0587..559b149848 100644 --- a/packages/labs/cli/src/lib/lit-cli.ts +++ b/packages/labs/cli/src/lib/lit-cli.ts @@ -23,8 +23,9 @@ import {createRequire} from 'module'; import * as childProcess from 'child_process'; export interface Options { + // Mandatory, so that all tests must specify it. + cwd: string; console?: LitConsole; - cwd?: string; stdin?: NodeJS.ReadableStream; } @@ -36,9 +37,9 @@ export class LitCli { private readonly cwd: string; private readonly stdin: NodeJS.ReadableStream; - constructor(args: string[], options?: Options) { - this.stdin = options?.stdin ?? process.stdin; - this.cwd = options?.cwd ?? process.cwd(); + constructor(args: string[], options: Options) { + this.cwd = options.cwd; + this.stdin = options.stdin ?? process.stdin; this.console = options?.console ?? new LitConsole(process.stdout, process.stderr); this.console.logLevel = 'info'; @@ -281,6 +282,7 @@ export class LitCli { return false; } const installFrom = reference.installFrom ?? reference.importSpecifier; + this.console.log(`Installing ${installFrom}...`); const child = childProcess.spawn( // https://stackoverflow.com/questions/43230346/error-spawn-npm-enoent /^win/.test(process.platform) ? 'npm.cmd' : 'npm', diff --git a/packages/labs/cli/src/lib/localize/extract.ts b/packages/labs/cli/src/lib/localize/extract.ts deleted file mode 100644 index 111ed2fb6f..0000000000 --- a/packages/labs/cli/src/lib/localize/extract.ts +++ /dev/null @@ -1,54 +0,0 @@ -/** - * @license - * Copyright 2020 Google LLC - * SPDX-License-Identifier: BSD-3-Clause - */ - -import { - readConfigFileAndWriteSchema, - Config, - TransformOutputConfig, - RuntimeOutputConfig, -} from '@lit/localize-tools/lib/config.js'; -import {TransformLitLocalizer} from '@lit/localize-tools/lib/modes/transform.js'; -import {RuntimeLitLocalizer} from '@lit/localize-tools/lib/modes/runtime.js'; -import {printDiagnostics} from '@lit/localize-tools/lib/typescript.js'; -import {KnownError, unreachable} from '@lit/localize-tools/lib/error.js'; -import {LitLocalizer} from '@lit/localize-tools/lib/index.js'; - -export const run = async (configPath: string, console: Console) => { - const config = readConfigFileAndWriteSchema(configPath); - const localizer = makeLocalizer(config); - // TODO(aomarks) Don't even require the user to have configured their output - // mode if they're just doing extraction. - console.log('Extracting messages'); - const {messages, errors} = localizer.extractSourceMessages(); - if (errors.length > 0) { - printDiagnostics(errors); - throw new KnownError('Error analyzing program'); - } - console.log(`Extracted ${messages.length} messages`); - console.log(`Writing interchange files`); - await localizer.writeInterchangeFiles(); -}; - -const makeLocalizer = (config: Config): LitLocalizer => { - switch (config.output.mode) { - case 'transform': - return new TransformLitLocalizer( - // TODO(aomarks) Unfortunate that TypeScript doesn't automatically do - // this type narrowing. Because the union is on a nested property? - config as Config & {output: TransformOutputConfig} - ); - case 'runtime': - return new RuntimeLitLocalizer( - config as Config & {output: RuntimeOutputConfig} - ); - default: - throw new KnownError( - `Internal error: unknown mode ${ - (unreachable(config.output as never) as Config['output']).mode - }` - ); - } -}; diff --git a/packages/labs/cli/src/test/cli-test-utils.ts b/packages/labs/cli/src/test/cli-test-utils.ts index 95c556da98..0187c74e43 100644 --- a/packages/labs/cli/src/test/cli-test-utils.ts +++ b/packages/labs/cli/src/test/cli-test-utils.ts @@ -89,6 +89,10 @@ export const symlinkAllCommands = async (rig: FilesystemTestRig) => { relPath: ['..', '..', '..', 'gen-wrapper-vue'], packageName: ['@lit-labs', 'gen-wrapper-vue'], }, + { + relPath: ['..', '..', '..', 'cli-localize'], + packageName: ['@lit-labs', 'cli-localize'], + }, ]; await Promise.all( symLinks.map(async ({packageName, relPath}) => { diff --git a/packages/labs/cli/src/test/gen/react_test.ts b/packages/labs/cli/src/test/gen/react_test.ts index 8f27ead544..e9d39fa48e 100644 --- a/packages/labs/cli/src/test/gen/react_test.ts +++ b/packages/labs/cli/src/test/gen/react_test.ts @@ -55,7 +55,7 @@ test('basic wrapper generation', async ({rig, testConsole}) => { testConsole.alsoLogToGlobalConsole = true; await cli.run(); - assert.equal(testConsole.errorStream.buffer.join(''), ''); + assert.snapshot(testConsole.errorStream.text, ''); // Note, this is only a very basic test that wrapper generation succeeds when // executed via the CLI. For detailed tests, see tests in diff --git a/packages/labs/cli/src/test/help_test.ts b/packages/labs/cli/src/test/help_test.ts index ab186af1c1..8002032332 100644 --- a/packages/labs/cli/src/test/help_test.ts +++ b/packages/labs/cli/src/test/help_test.ts @@ -9,7 +9,7 @@ import 'source-map-support/register.js'; import * as assert from 'uvu/assert'; import {LitCli} from '../lib/lit-cli.js'; import {LitConsole} from '../lib/console.js'; -import {BufferedWritable} from './cli-test-utils.js'; +import {BufferedWritable, symlinkAllCommands} from './cli-test-utils.js'; import {ReferenceToCommand} from '../lib/command.js'; import {ConsoleConstructorOptions} from 'console'; import * as stream from 'stream'; @@ -50,41 +50,47 @@ test.after.each(async (ctx) => { await ctx.fs.cleanup(); }); -test('help with no command', async ({console, stdin}) => { - const cli = new LitCli(['help'], {console, stdin: stdin}); +test('help with no command', async ({fs, console, stdin}) => { + const cli = new LitCli(['help'], {console, stdin: stdin, cwd: fs.rootDir}); await cli.run(); const output = console.outputStream.text; - assert.equal(console.errorStream.buffer.length, 0); + assert.snapshot(console.errorStream.text, ''); assert.match(output, 'Lit CLI'); assert.match(output, 'Available Commands'); assert.match(output, 'localize'); }); -test('help with localize command', async ({console, stdin}) => { - const cli = new LitCli(['help', 'localize'], {console, stdin}); +test('help with localize command', async ({fs, console, stdin}) => { + await symlinkAllCommands(fs); + const cli = new LitCli(['help', 'localize'], { + console, + stdin, + cwd: fs.rootDir, + }); await cli.run(); const output = console.outputStream.text; - assert.equal(console.errorStream.buffer.length, 0); assert.match(output, 'lit localize'); assert.match(output, 'Sub-Commands'); assert.match(output, 'extract'); assert.match(output, 'build'); }); -test('help with localize extract command', async ({console, stdin}) => { +test('help with localize extract command', async ({fs, console, stdin}) => { + await symlinkAllCommands(fs); const cli = new LitCli(['help', 'localize', 'extract'], { console, stdin, + cwd: fs.rootDir, }); await cli.run(); const output = console.outputStream.text; - assert.equal(console.errorStream.buffer.length, 0); + assert.snapshot(console.errorStream.text, ''); assert.match(output, 'lit localize extract'); assert.match(output, '--config'); }); @@ -109,7 +115,7 @@ test('help includes unresolved external command descriptions', async ({ cli.addCommand(fooCommandReference); await cli.run(); const output = console.outputStream.text; - assert.equal(console.errorStream.buffer.length, 0); + assert.snapshot(console.errorStream.text, ''); assert.match( output, /\s+foo\s+This is the description in the `foo` reference./ @@ -183,7 +189,7 @@ test(`help for a resolved external command`, async ({console, fs, stdin}) => { cli.addCommand(fooCommandReference); await cli.run(); output = console.outputStream.text; - assert.equal(console.errorStream.buffer.length, 0); + assert.snapshot(console.errorStream.text, ''); assert.match( output, /\s+foo\s+this is the resolved foo command from the node_modules directory/ @@ -224,7 +230,7 @@ test('we install a referenced command with permission', async ({ }); cli.addCommand({...fooCommandReference, installFrom: '../foo-package'}); await cli.run(); - assert.equal(console.errorStream.text, ''); + assert.snapshot(console.errorStream.text, ''); // The npm install happend. assert.match(console.outputStream.text, 'added 1 package'); // After installation, we were able to resolve the command. diff --git a/packages/labs/cli/src/test/uvu-wrapper.ts b/packages/labs/cli/src/test/uvu-wrapper.ts index 14df06c00d..8343029781 100644 --- a/packages/labs/cli/src/test/uvu-wrapper.ts +++ b/packages/labs/cli/src/test/uvu-wrapper.ts @@ -37,19 +37,21 @@ function timeout( test: uvu.Callback ): uvu.Callback { return async (ctx) => { - let timeoutId: ReturnType; - const result = Promise.race([ - test(ctx), - new Promise((_, reject) => { - timeoutId = setTimeout( - () => reject(new Error(`Test timed out: ${JSON.stringify(name)}`)), - ms - ); - }), - ]); - result.finally(() => { - clearTimeout(timeoutId); - }); - return result; + let timeoutId: ReturnType | undefined; + try { + return await Promise.race([ + test(ctx), + new Promise((_, reject) => { + timeoutId = setTimeout( + () => reject(new Error(`Test timed out: ${JSON.stringify(name)}`)), + ms + ); + }), + ]); + } finally { + if (timeoutId !== undefined) { + clearTimeout(timeoutId); + } + } }; }