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); + } + } }; }