diff --git a/.github/workflows/build.yaml b/.github/workflows/build.yaml index bcfd896c..04b23ad0 100644 --- a/.github/workflows/build.yaml +++ b/.github/workflows/build.yaml @@ -50,7 +50,7 @@ jobs: - uses: denoland/setup-deno@v1 with: deno-version: v1.x - - run: deno task check + - run: deno task hooks:pre-commit - run: deno task check working-directory: ${{ github.workspace }}/examples/blog/ @@ -71,6 +71,8 @@ jobs: - run: deno task dnt - run: npm publish --dry-run working-directory: ${{ github.workspace }}/npm/ + - run: deno task publish-dry-run + working-directory: ${{ github.workspace }}/cli/ publish: needs: [test, lint, release-test] @@ -129,6 +131,11 @@ jobs: github.event_name == 'push' && github.ref_type == 'tag' || github.ref == 'refs/heads/main' run: deno task publish --allow-dirty + - if: | + github.event_name == 'push' && + github.ref_type == 'tag' || github.ref == 'refs/heads/main' + run: deno task publish --allow-dirty + working-directory: ${{ github.workspace }}/cli/ - if: | github.event_name == 'push' && github.ref_type == 'tag' || github.ref == 'refs/heads/main' diff --git a/.vscode/settings.json b/.vscode/settings.json index bdebd850..2c56bd28 100755 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -2,6 +2,11 @@ "deno.enable": true, "deno.unstable": true, "files.eol": "\n", + "files.exclude": { + "cli": true, + "examples/blog": true, + "examples/hono-sample": true + }, "files.insertFinalNewline": true, "files.trimFinalNewlines": true, "yaml.completion": true, diff --git a/CHANGES.md b/CHANGES.md index 7a88e4b2..b59736fc 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -8,6 +8,9 @@ Version 0.8.0 To be released. + - The CLI toolchain is now available on JSR: [@fedify/cli]. You can install + it with `deno install -A -n fedify jsr:@fedify/cli`. + - Implemented [followers collection synchronization mechanism][FEP-8fcf]. - Added `RequestContext.sendActivity()` overload that takes `"followers"` @@ -21,7 +24,7 @@ To be released. - Added the second type parameter to `CollectionCursor` type. - Added the third parameter to `CollectionCursor` type. - - Relaxed the required type for activity recipients. + - Relaxed the required type for activity recipients. - Added `Recipient` interface. - The type of the second parameter of `Context.sendActivity()` method @@ -46,6 +49,7 @@ To be released. - `["fedify", "federation", "collection"]` - `["fedify", "runtime", "docloader"]` +[@fedify/cli]: https://jsr.io/@fedify/cli [FEP-8fcf]: https://codeberg.org/fediverse/fep/src/branch/main/fep/8fcf/fep-8fcf.md diff --git a/cli/.vscode/extensions.json b/cli/.vscode/extensions.json new file mode 100755 index 00000000..064d0a5c --- /dev/null +++ b/cli/.vscode/extensions.json @@ -0,0 +1,6 @@ +{ + "recommendations": [ + "denoland.vscode-deno", + "streetsidesoftware.code-spell-checker" + ] +} diff --git a/cli/.vscode/settings.json b/cli/.vscode/settings.json new file mode 100755 index 00000000..c50dd19e --- /dev/null +++ b/cli/.vscode/settings.json @@ -0,0 +1,40 @@ +{ + "deno.enable": true, + "deno.unstable": true, + "files.eol": "\n", + "files.exclude": { + "cli": true, + "examples/blog": true, + "examples/hono-sample": true + }, + "files.insertFinalNewline": true, + "files.trimFinalNewlines": true, + "[json]": { + "editor.defaultFormatter": "vscode.json-language-features", + "editor.formatOnSave": true + }, + "[jsonc]": { + "editor.defaultFormatter": "vscode.json-language-features", + "editor.formatOnSave": true + }, + "[typescript]": { + "editor.defaultFormatter": "denoland.vscode-deno", + "editor.formatOnSave": true, + "editor.codeActionsOnSave": { + "source.sortImports": "always" + } + }, + "cSpell.words": [ + "codegen", + "denokv", + "docloader", + "fedify", + "hongminhee", + "hono", + "httpsig", + "logtape", + "nodeinfo", + "tempserver", + "webfinger" + ] +} diff --git a/cli/deno.json b/cli/deno.json new file mode 100644 index 00000000..787ee496 --- /dev/null +++ b/cli/deno.json @@ -0,0 +1,19 @@ +{ + "name": "@fedify/cli", + "version": "0.8.0", + "exports": "./mod.ts", + "importMap": "import_map.g.json", + "exclude": [ + ".vscode", + "scripts" + ], + "tasks": { + "fedify-codegen": "cat ../vocab/vocab.ts > /dev/null || (deno run --allow-read --allow-write --check ../codegen/main.ts ../vocab/ ../runtime/ > ../vocab/vocab.ts && deno fmt ../vocab/vocab.ts && deno cache ../vocab/vocab.ts && deno check ../vocab/vocab.ts)", + "generate-import-map": "deno run --allow-read --allow-write scripts/generate_import_map.ts", + "sync-version": "deno run --allow-read=deno.json --allow-write=deno.json scripts/sync_version.ts", + "codegen": "deno task fedify-codegen && deno task generate-import-map && deno task sync-version", + "run": "deno task codegen && deno run --allow-read --allow-write --allow-net --allow-env --allow-run mod.ts", + "publish": "deno task codegen && deno task generate-import-map --release && deno publish", + "publish-dry-run": "deno task codegen && deno publish --dry-run --allow-dirty" + } +} diff --git a/cli/import_map.g.json b/cli/import_map.g.json new file mode 100644 index 00000000..a07d2079 --- /dev/null +++ b/cli/import_map.g.json @@ -0,0 +1,48 @@ +{ + "imports": { + "@cfworker/json-schema": "npm:@cfworker/json-schema@^1.12.8", + "@david/which-runtime": "jsr:@david/which-runtime@^0.2.0", + "@deno/dnt": "jsr:@deno/dnt@^0.41.1", + "@fedify/fedify": ".././mod.ts", + "@fedify/fedify/federation": ".././federation/mod.ts", + "@fedify/fedify/httpsig": ".././httpsig/mod.ts", + "@fedify/fedify/nodeinfo": ".././nodeinfo/mod.ts", + "@fedify/fedify/runtime": ".././runtime/mod.ts", + "@fedify/fedify/vocab": ".././vocab/mod.ts", + "@fedify/fedify/webfinger": ".././webfinger/mod.ts", + "@fedify/fedify/x/denokv": ".././x/denokv.ts", + "@fedify/fedify/x/fresh": ".././x/fresh.ts", + "@fedify/fedify/x/hono": ".././x/hono.ts", + "@hongminhee/aitertools": "jsr:@hongminhee/aitertools@^0.6.0", + "@logtape/logtape": "jsr:@logtape/logtape@^0.2.2", + "@phensley/language-tag": "npm:@phensley/language-tag@^1.8.0", + "@std/assert": "jsr:@std/assert@^0.220.1", + "@std/async/delay": "jsr:@std/async@^0.220.1/delay", + "@std/bytes": "jsr:@std/bytes@^0.220.1", + "@std/collections": "jsr:@std/collections@^0.220.1", + "@std/encoding": "jsr:@std/encoding@^0.220.1", + "@std/encoding/base64": "jsr:@std/encoding@^0.220.1/base64", + "@std/encoding/hex": "jsr:@std/encoding@^0.220.1/hex", + "@std/fs": "jsr:@std/fs@^0.220.1", + "@std/http/negotiation": "jsr:@std/http@^0.220.1/negotiation", + "@std/json/common": "jsr:@std/json@^0.220.1/common", + "@std/path": "jsr:@std/path@^0.220.1", + "@std/semver": "jsr:@std/semver@^0.220.1", + "@std/testing": "jsr:@std/testing@^0.220.1", + "@std/text": "jsr:@std/text@^0.220.1", + "@std/url": "jsr:@std/url@^0.220.1", + "@std/yaml": "jsr:@std/yaml@^0.220.1", + "fast-check": "npm:fast-check@^3.17.0", + "jsonld": "npm:jsonld@^8.3.2", + "mock_fetch": "https://deno.land/x/mock_fetch@0.3.0/mod.ts", + "uri-template-router": "npm:uri-template-router@^0.0.16", + "url-template": "npm:url-template@^3.1.1", + "@cliffy/command": "jsr:@cliffy/command@1.0.0-rc.4", + "@cliffy/prompt": "jsr:@cliffy/prompt@1.0.0-rc.4", + "@cross/dir": "jsr:@cross/dir@^1.1.0", + "@hongminhee/localtunnel": "jsr:@hongminhee/localtunnel@^0.1.0", + "cli-highlight": "npm:cli-highlight@^2.1.11", + "json-preserve-indent": "npm:json-preserve-indent@^1.1.3", + "ora": "npm:ora@^8.0.1" + } +} diff --git a/cli/import_map.json b/cli/import_map.json new file mode 100644 index 00000000..db0c3f99 --- /dev/null +++ b/cli/import_map.json @@ -0,0 +1,14 @@ +{ + "imports": { + "@cliffy/command": "jsr:@cliffy/command@1.0.0-rc.4", + "@cliffy/prompt": "jsr:@cliffy/prompt@1.0.0-rc.4", + "@cross/dir": "jsr:@cross/dir@^1.1.0", + "@hongminhee/localtunnel": "jsr:@hongminhee/localtunnel@^0.1.0", + "@logtape/logtape": "jsr:@logtape/logtape@^0.2.2", + "@std/fs": "jsr:@std/fs@^0.220.1", + "@std/path": "jsr:@std/path@^0.220.1", + "cli-highlight": "npm:cli-highlight@^2.1.11", + "json-preserve-indent": "npm:json-preserve-indent@^1.1.3", + "ora": "npm:ora@^8.0.1" + } +} diff --git a/cli/mod.ts b/cli/mod.ts index 42ea5019..b3cd7b3a 100644 --- a/cli/mod.ts +++ b/cli/mod.ts @@ -1,7 +1,7 @@ import { Command, HelpCommand } from "@cliffy/command"; import { configure, getConsoleSink } from "@logtape/logtape"; -import metadata from "../deno.json" with { type: "json" }; import { DEFAULT_CACHE_DIR, setCacheDir } from "./cache.ts"; +import metadata from "./deno.json" with { type: "json" }; import { command as lookup } from "./lookup.ts"; const command = new Command() diff --git a/cli/scripts/check_version.ts b/cli/scripts/check_version.ts new file mode 100644 index 00000000..baa1da28 --- /dev/null +++ b/cli/scripts/check_version.ts @@ -0,0 +1,10 @@ +import parentMetadata from "../../deno.json" with { type: "json" }; +import metadata from "../deno.json" with { type: "json" }; + +if (metadata.version !== parentMetadata.version) { + console.error( + `Version mismatch: parent version ${parentMetadata.version} ` + + `does not match child version ${metadata.version}`, + ); + Deno.exit(1); +} diff --git a/cli/scripts/generate_import_map.ts b/cli/scripts/generate_import_map.ts new file mode 100644 index 00000000..bc305551 --- /dev/null +++ b/cli/scripts/generate_import_map.ts @@ -0,0 +1,25 @@ +import fedifyMetadata from "../../deno.json" with { type: "json" }; +import cliImportMap from "../import_map.json" with { type: "json" }; + +const release = Deno.args[0] == "--release"; + +const fedifyImports = Object.fromEntries( + Object.entries(fedifyMetadata.exports) + .map(([k, v]) => [ + k.replace(/^\./, "@fedify/fedify"), + release + ? `jsr:${k.replace(/^\./, "@fedify/fedify")}@^${fedifyMetadata.version}` + : "../" + v, + ]), +); + +const importMap = { + ...fedifyMetadata.imports, + ...fedifyImports, + ...cliImportMap.imports, +}; + +await Deno.writeTextFile( + `${import.meta.dirname}/../import_map.g.json`, + JSON.stringify({ imports: importMap }, null, 2) + "\n", +); diff --git a/cli/scripts/sync_version.ts b/cli/scripts/sync_version.ts new file mode 100644 index 00000000..611443e9 --- /dev/null +++ b/cli/scripts/sync_version.ts @@ -0,0 +1,8 @@ +import jsonPreserveIndent from "json-preserve-indent"; +import metadata from "../../deno.json" with { type: "json" }; + +const denoJsonPath = `${import.meta.dirname}/../deno.json`; +const denoJson = await Deno.readTextFile(denoJsonPath); +const data = jsonPreserveIndent(denoJson); +data.set("version", metadata.version); +await Deno.writeTextFile(denoJsonPath, data.format()); diff --git a/deno.json b/deno.json index df7616b1..94843142 100644 --- a/deno.json +++ b/deno.json @@ -15,9 +15,6 @@ }, "imports": { "@cfworker/json-schema": "npm:@cfworker/json-schema@^1.12.8", - "@cliffy/command": "https://deno.land/x/cliffy@v1.0.0-rc.4/command/mod.ts", - "@cliffy/prompt": "https://deno.land/x/cliffy@v1.0.0-rc.4/prompt/mod.ts", - "@cross/dir": "jsr:@cross/dir@^1.1.0", "@david/which-runtime": "jsr:@david/which-runtime@^0.2.0", "@deno/dnt": "jsr:@deno/dnt@^0.41.1", "@fedify/fedify": "./mod.ts", @@ -31,7 +28,6 @@ "@fedify/fedify/x/fresh": "./x/fresh.ts", "@fedify/fedify/x/hono": "./x/hono.ts", "@hongminhee/aitertools": "jsr:@hongminhee/aitertools@^0.6.0", - "@hongminhee/localtunnel": "jsr:@hongminhee/localtunnel@^0.1.0", "@logtape/logtape": "jsr:@logtape/logtape@^0.2.2", "@phensley/language-tag": "npm:@phensley/language-tag@^1.8.0", "@std/assert": "jsr:@std/assert@^0.220.1", @@ -50,11 +46,9 @@ "@std/text": "jsr:@std/text@^0.220.1", "@std/url": "jsr:@std/url@^0.220.1", "@std/yaml": "jsr:@std/yaml@^0.220.1", - "cli-highlight": "npm:cli-highlight@^2.1.11", "fast-check": "npm:fast-check@^3.17.0", "jsonld": "npm:jsonld@^8.3.2", "mock_fetch": "https://deno.land/x/mock_fetch@0.3.0/mod.ts", - "ora": "npm:ora@^8.0.1", "uri-template-router": "npm:uri-template-router@^0.0.16", "url-template": "npm:url-template@^3.1.1" }, @@ -64,6 +58,7 @@ "exclude": [ ".git/", "apidoc/", + "cli/", "docs/", "examples/", "npm/" @@ -72,15 +67,15 @@ "cache": "deno task codegen && deno cache mod.ts", "check": "deno task codegen && deno fmt --check && deno lint && deno check */*.ts", "codegen": "deno run --allow-read --allow-write --check codegen/main.ts vocab/ ../runtime/ > vocab/vocab.ts && deno fmt vocab/vocab.ts && deno cache vocab/vocab.ts && deno check vocab/vocab.ts", - "cli": "deno task codegen && deno run --allow-read --allow-write --allow-net --allow-env --allow-run cli/mod.ts", "test-without-codegen": "deno test --check --doc --allow-read --allow-write --unstable-kv --trace-leaks", "test": "deno task codegen && deno task test-without-codegen", "coverage": "rm -rf coverage/ && deno task test --coverage && deno coverage --html coverage", "apidoc": "deno task codegen && deno doc --html --name=Fedify --output=apidoc/ mod.ts", + "check-version": "deno run cli/scripts/check_version.ts", "publish": "deno task codegen && deno publish", "dnt": "deno task codegen && deno run -A dnt.ts", "hooks:install": "deno run --allow-read=deno.json,.git/hooks/ --allow-write=.git/hooks/ jsr:@hongminhee/deno-task-hooks", - "hooks:pre-commit": "deno task check" + "hooks:pre-commit": "deno task check && deno task check-version" }, "unstable": [ "kv", diff --git a/fedify.code-workspace b/fedify.code-workspace new file mode 100644 index 00000000..d402164a --- /dev/null +++ b/fedify.code-workspace @@ -0,0 +1,16 @@ +{ + "folders": [ + { + "path": "." + }, + { + "path": "cli" + }, + { + "path": "examples/blog" + }, + { + "path": "examples/hono-example" + } + ] +}