diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index c2a8f0dc..a9de0efd 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -16,8 +16,12 @@ jobs: name: Test uses: hasundue/actions/.github/workflows/test-deno.yml@main secrets: inherit + with: + task: test:unit integration: name: Integration uses: hasundue/actions/.github/workflows/integration-deno.yml@main secrets: inherit + with: + task: test:integration diff --git a/README.md b/README.md index 00000ecb..7f75132b 100644 --- a/README.md +++ b/README.md @@ -4,11 +4,11 @@ [![codecov](https://codecov.io/github/hasundue/molt/graph/badge.svg?token=NhpMdDRNxy)](https://codecov.io/github/hasundue/molt) > [!WARNING]\ -> Molt is still being developed actively. The API is not stable yet and may +> Molt is still under active development. The API is not stable yet and may > change frequently. Molt is a [Deno] module to bump version strings in import specifiers, like -[udd], but with some unique concepts: +[udd], but with different design principles: **The Deno way** - Molt finds dependencies and checks their latest versions in a consistent way as the Deno runtime, with [deno_graph] and [import_map] crates, @@ -25,7 +25,7 @@ subsequent git commits. Molt can check updates to dependencies written in different formats and bump their versions. URL imports, `npm:` and `jsr:` specifiers are all supported: -> [!NOTE]\ +> [!IMPORTANT]\ > Molt does NOT bump version ragnges like `1`, `1.x`, `~1.2.3` and `^1.2.3` in > `npm:` and `jrs:` specifiers, but only updates a lockfile. @@ -78,7 +78,7 @@ their versions. URL imports, `npm:` and `jsr:` specifiers are all supported: ## Usage -### Deno Module +### [@molt/core] #### [API Reference](https://deno.land/x/molt/mod.ts) @@ -87,31 +87,31 @@ their versions. URL imports, `npm:` and `jsr:` specifiers are all supported: ##### Update all dependencies in a module and write the changes to local files ```ts -import { collect, write } from "https://deno.land/x/molt@{VERSION}/mod.ts"; +import { collect, write } from "jsr:@molt/core"; -const result = await collect("./mod.ts"); -await write(result); +const updates = await collect("./mod.ts"); +await write(updates); ``` ##### Update all dependencies in a module and commit the changes to git ```ts -import { collect, commit } from "https://deno.land/x/molt@{VERSION}/mod.ts"; +import { collect, commit } from "jsr:@molt/core"; -const result = await collect("./mod.ts"); +const updates = await collect("./mod.ts"); -await commit(result, { +await commit(updates, { groupBy: (dependency) => dependency.name, composeCommitMessage: ({ group, version }) => `build(deps): bump ${group} to ${version!.to}`, }); ``` -### CLI +### [@molt/cli] Although it is encouraged to write your own scripts, a pre-built CLI tool is -also provided as `cli.ts` for convenience or a reference implementation, which -is supposed to cover most of the use cases. +also provided for convenience or as a reference implementation, which is +supposed to cover most of the use cases. #### Installation (optional) @@ -119,7 +119,7 @@ The molt CLI can be installed globally with the following command, for example: ```sh deno install --allow-env --allow-read --allow-write --allow-net --allow-run=git,deno\ ---name molt https://deno.land/x/molt@{VERSION}/cli.ts +--name molt jsr:@molt/cli ``` Alternatively, you may prefer to run the remote script directly through @@ -128,8 +128,8 @@ Alternatively, you may prefer to run the remote script directly through ```json { "tasks": { - "update": "deno run --allow-env --allow-read --allow-write=. --allow-run=git,deno --allow-net=deno.land https://deno.land/x/molt@{VERSION}/cli.ts ./**/*.ts", - "update:commit": "deno task -q update --commit --pre-commit=fmt" + "update": "deno run --allow-env --allow-read --allow-write=. --allow-run=git,deno --allow-net=jsr.io,registry.npmjs.org jsr:@molt/cli ./*.ts", + "update:commit": "deno task -q update --commit --pre-commit=fmt,lint" } } ``` @@ -154,11 +154,8 @@ Options: -w, --write - Write changes to local files (Conflicts: --commit) -c, --commit - Commit changes to local git repository (Conflicts: --write) --pre-commit - Run tasks before each commit (Depends: --commit) - --post-commit - Run tasks after each commit (Depends: --commit) --prefix - Prefix for commit messages (Depends: --commit) --prefix-lock - Prefix for commit messages of updating a lock file (Depends: --commit, --unstable-lock) - --summary - Write a summary of changes to file - --report - Write a report of changes to file --unstable-lock [file] - Enable unstable updating of a lock file ``` @@ -179,6 +176,13 @@ Options: 📦 node-emoji 2.0.0 => 2.1.3 ``` +You may specify the modules to check, alternatively: + +```sh +> molt main.ts main_test.ts + ... +``` + ##### Write changes to files ```sh @@ -260,5 +264,7 @@ and of full respect to the authors. [deno_graph]: https://github.com/denoland/deno_graph [import_map]: https://github.com/denoland/import_map [udd]: https://github.com/hayd/deno-udd +[@molt/core]: https://jsr.io/@molt/core +[@molt/cli]: https://jsr.io/@molt/cli [issues]: https://github.com/hasundue/molt/issues [dependabot]: https://docs.github.com/en/code-security/dependabot/dependabot-version-updates/configuration-options-for-the-dependabot.yml-file#versioning-strategy diff --git a/cli.ts b/cli.ts index 05bf43ee..a0978aad 100644 --- a/cli.ts +++ b/cli.ts @@ -1,330 +1 @@ -import { distinct, filterKeys, mapEntries } from "./lib/std/collections.ts"; -import { parse as parseJsonc } from "./lib/std/jsonc.ts"; -import { relative } from "./lib/std/path.ts"; -import { colors, Command } from "./lib/x/cliffy.ts"; -import { $ } from "./lib/x/dax.ts"; -import { ensure, is } from "./lib/x/unknownutil.ts"; -import { findFileUp } from "./lib/path.ts"; -import { - collect, - CollectResult, - CommitSequence, - createCommitSequence, - DependencyUpdate, - execute, - parse, - write, -} from "./mod.ts"; - -const { gray, yellow, bold, cyan } = colors; - -const main = new Command() - .name("molt") - .description( - "Check updates to dependencies in Deno modules and configuration files", - ) - .versionOption("-v, --version", "Print version info.", versionCommand) - .option("--import-map ", "Specify import map file") - .option("--ignore=", "Ignore dependencies") - .option("--only=", "Check specified dependencies") - .option("-w, --write", "Write changes to local files", { - conflicts: ["commit"], - }) - .option("-c, --commit", "Commit changes to local git repository", { - conflicts: ["write"], - }) - .option("--pre-commit=", "Run tasks before each commit", { - depends: ["commit"], - }) - .option("--post-commit=", "Run tasks after each commit", { - depends: ["commit"], - }) - .option("--prefix ", "Prefix for commit messages", { - depends: ["commit"], - }) - .option( - "--prefix-lock ", - "Prefix for commit messages of updating a lock file", - { depends: ["commit", "unstable-lock"] }, - ) - .option("--summary ", "Write a summary of changes to file") - .option("--report ", "Write a report of changes to file") - .option( - "--unstable-lock [file:string]", - "Enable unstable updating of a lock file", - ) - .arguments("") - .action(async function (options, ...files) { - if (options.importMap) { - if (await $.path(options.importMap).exists() === false) { - console.error(`Import map ${options.importMap} does not exist.`); - Deno.exit(1); - } - } - ensureFiles(files); - const result = await collectUpdates(files, options); - printResult(files, result); - if (options.write) { - return writeResult(result, options); - } - if (options.commit) { - const tasks = await getTasks(); - return commitResult(result, { - ...options, - preCommit: filterKeys( - tasks, - (key) => options.preCommit?.includes(key) ?? false, - ), - postCommit: filterKeys( - tasks, - (key) => options.postCommit?.includes(key) ?? false, - ), - }); - } - }); - -function versionCommand() { - const version = parse(import.meta.url).version ?? "dev"; - console.log(version); -} - -async function collectUpdates( - entrypoints: string[], - options: { - ignore?: string[]; - importMap?: string; - only?: string[]; - unstableLock?: true | string; - }, -): Promise { - const result = await $.progress("Checking for updates").with(() => - collect(entrypoints, { - lock: !!options.unstableLock, - lockFile: typeof options.unstableLock === "string" - ? options.unstableLock - : undefined, - importMap: options.importMap, - ignore: options.ignore - ? (dep) => options.ignore!.some((it) => dep.name.includes(it)) - : undefined, - only: options.only - ? (dep) => options.only!.some((it) => dep.name.includes(it)) - : undefined, - }) - ); - if (!result.updates.length) { - console.log("🍵 No updates found"); - Deno.exit(0); - } - return result; -} - -type TaskRecord = Record; - -async function getTasks() { - const tasks: TaskRecord = { - fmt: ["fmt"], - lint: ["lint"], - test: ["test"], - }; - const config = await findFileUp(Deno.cwd(), "deno.json", "deno.jsonc"); - if (!config) { - return tasks; - } - try { - const json = ensure( - parseJsonc(await Deno.readTextFile(config)), - is.ObjectOf({ tasks: is.Record }), - ); - return { - ...tasks, - ...mapEntries(json.tasks, ([name]) => [name, ["task", "-q", name]]), - }; - } catch { - return tasks; - } -} - -const toRelativePath = (path: string) => relative(Deno.cwd(), path); - -function printResult( - files: string[], - result: CollectResult, -) { - const dependencies = new Map(); - for (const u of result.updates) { - const list = dependencies.get(u.to.name) ?? []; - list.push(u); - dependencies.set(u.to.name, list); - } - let count = 0; - const nWrites = distinct(result.updates.map((u) => u.referrer)).length; - for (const [name, list] of dependencies.entries()) { - const froms = distinct(list.map((u) => u.from?.version)).join(", "); - console.log( - `📦 ${bold(name)} ${yellow(froms)} => ${yellow(list[0].to.version)}`, - ); - if (files.length > 1 || nWrites > 1) { - distinct( - list.map((u) => { - const source = toRelativePath(u.map?.source ?? u.referrer); - return ` ${source} ` + gray(u.from?.version ?? ""); - }), - ).forEach((line) => console.log(line)); - if (++count < dependencies.size) { - console.log(); - } - } - } -} - -async function writeResult( - result: CollectResult, - options?: { - summary?: string; - report?: string; - }, -) { - console.log(); - await write(result, { - onWrite: (file) => console.log(`💾 ${toRelativePath(file.path)}`), - }); - if (options?.summary || options?.report) { - console.log(); - } - if (options?.summary) { - await Deno.writeTextFile(options.summary, "Update dependencies"); - console.log(`📄 ${options.summary}`); - } - if (options?.report) { - const content = distinct( - result.updates.map((u) => - `- ${u.to.name} ${u.from?.version} => ${u.to.version}` - ), - ).join("\n"); - await Deno.writeTextFile(options.report, content); - console.log(`📄 ${options.report}`); - } -} - -async function commitResult( - result: CollectResult, - options: { - preCommit?: TaskRecord; - postCommit?: TaskRecord; - prefix?: string; - prefixLock?: string; - summary?: string; - report?: string; - }, -) { - console.log(); - - const preCommitTasks = Object.entries(options?.preCommit ?? {}); - const postCommitTasks = Object.entries(options?.postCommit ?? {}); - const hasTask = preCommitTasks.length > 0 || postCommitTasks.length > 0; - - let count = 0; - const commits = createCommitSequence(result, { - groupBy: (dependency) => dependency.to.name, - composeCommitMessage: ({ group, types, version }) => - formatPrefix( - types.length === 1 && types.includes("lockfile") - ? options.prefixLock - : options.prefix, - ) + `bump ${group}` + - (version?.from ? ` from ${version?.from}` : "") + - (version?.to ? ` to ${version?.to}` : ""), - preCommit: preCommitTasks.length > 0 - ? async (commit) => { - console.log(`💾 ${commit.message}`); - for (const t of preCommitTasks) { - await runTask(t); - } - } - : undefined, - postCommit: async (commit) => { - console.log(`📝 ${commit.message}`); - for (const task of postCommitTasks) { - await runTask(task); - } - if (hasTask && ++count < commits.commits.length) { - console.log(); - } - }, - }); - await execute(commits); - - if (options?.summary || options?.report) { - console.log(); - } - if (options?.summary) { - await Deno.writeTextFile(options.summary, createSummary(commits, options)); - console.log(`📄 ${options.summary}`); - } - if (options?.report) { - await Deno.writeTextFile(options.report, createReport(commits)); - console.log(`📄 ${options.report}`); - } -} - -async function runTask([name, args]: [string, string[]]) { - console.log(`🔨 Running task ${cyan(name)}...`); - const { code } = await new Deno.Command("deno", { - args, - stdout: "inherit", - stderr: "inherit", - }).output(); - if (code != 0) { - Deno.exit(code); - } -} - -function ensureFiles(paths: string[]) { - for (const path of paths) { - try { - if (!Deno.statSync(path).isFile) { - throw new Error(`Not a valid file: "${path}"`); - } - } catch { - throw new Error(`Path does not exist: "${path}"`); - } - } -} - -function createSummary( - sequence: CommitSequence, - options: { prefix?: string }, -): string { - if (sequence.commits.length === 0) { - return "No updates"; - } - if (sequence.commits.length === 1) { - return sequence.commits[0].message; - } - const groups = sequence.commits.map((commit) => commit.group).join(", "); - const full = formatPrefix(options.prefix) + `update ${groups}`; - return (full.length <= 50) - ? full - : formatPrefix(options.prefix) + "update dependencies"; -} - -const createReport = (sequence: CommitSequence): string => - sequence.commits.map((commit) => `- ${commit.message}`).join("\n"); - -const formatPrefix = (prefix: string | undefined) => - prefix ? prefix.trimEnd() + " " : ""; - -try { - const env = await Deno.permissions.query({ name: "env" }); - if (env.state === "granted" && Deno.env.get("MOLT_TEST")) { - const { enableTestMode } = await import("./lib/testing.ts"); - enableTestMode(); - } - await main.parse(Deno.args); -} catch (error) { - if (error.message) { - console.error("Error: " + error.message); - } - Deno.exit(1); -} +import "./cli/main.ts"; diff --git a/cli/cli_test.ts b/cli/cli_test.ts new file mode 100644 index 00000000..5ffecad1 --- /dev/null +++ b/cli/cli_test.ts @@ -0,0 +1,107 @@ +import { assertEquals } from "@std/assert/assert-equals"; +import { stripAnsiCode } from "@std/fmt/colors"; +import { fromFileUrl, join } from "@std/path"; +import { createAssertSnapshot } from "@std/testing/snapshot"; + +// basic commands +molt("", { code: 2 }); +molt("--help"); +molt("--version"); + +// single file +molt("not_exist.ts", { code: 1 }); +molt("import.ts"); + +// special registries +molt("jsr.ts"); + +// with import maps +molt("mod.ts", { dir: "import_map" }); +molt("mod.ts --import-map deno.json", { dir: "import_map" }); + +// --ignore and --only +molt("multiple_imports.ts --ignore node-emoji"); +molt("multiple_imports.ts --ignore=deno_graph,node-emoji"); +molt("multiple_imports.ts --only deno.land/std"); +molt("multiple_imports.ts --only=deno.land/std,deno_graph"); +molt("multiple_imports.ts --only deno.land --ignore deno_graph"); + +// --write +molt("mod.ts --write", { dir: "multiple_modules" }); + +// --commit +molt("mod.ts --commit", { dir: "multiple_modules" }); +molt("mod.ts --commit --prefix :package:", { dir: "multiple_modules" }); +molt("mod.ts --commit --pre-commit=fmt", { dir: "multiple_modules" }); + +// deno.json +molt("deno.json", { dir: "import_map" }); +molt("deno.json --write", { dir: "import_map" }); +molt("deno.json --commit", { dir: "import_map" }); + +// deno.jsonc +molt("deno.jsonc", { dir: "jsonc" }); +molt("deno.jsonc --write", { dir: "jsonc" }); +molt("deno.jsonc --commit", { dir: "jsonc" }); + +// lockfile +molt("deno.json --unstable-lock not_exist.lock", { dir: "lockfile", code: 1 }); +molt("deno.json --unstable-lock", { dir: "lockfile" }); +molt("deno.json --unstable-lock --write", { dir: "lockfile" }); +molt( + "deno.json --commit --unstable-lock --prefix :package: --prefix-lock :lock:", + { dir: "lockfile" }, +); + +//----------------------- +// Test implementation +//----------------------- + +const BIN = new URL("./main.ts", import.meta.url).pathname; +const CASES = new URL("../test/cases", import.meta.url).pathname; +const CONFIG = new URL("../deno.json", import.meta.url).pathname; + +function molt(line: string, opts?: { + dir?: string; + code?: number; +}) { + const args = line.length > 0 ? line.split(" ") : []; + + const name = "cli - " + (opts?.dir ? opts.dir + " - " : "") + + '"' + ["molt"].concat(args).join(" ") + '"'; + + Deno.test(name, async (t) => { + const output = await new Deno.Command("deno", { + args: ["run", "-A", "--unstable-kv", "--config", CONFIG, BIN, ...args], + env: { MOLT_TEST: "1" }, + cwd: join(CASES, opts?.dir ? `/${opts?.dir}` : ""), + }).output(); + + const stdout = stringify(output.stdout); + const stderr = stringify(output.stderr); + try { + assertEquals(output.code, opts?.code ?? 0); + } catch (err) { + console.error(stdout); + console.error(stderr); + throw err; + } + await assertSnapshot(t, stdout); + await assertSnapshot(t, stderr); + }); +} + +function stringify(data: Uint8Array) { + const decoder = new TextDecoder(); + let text = decoder.decode(data); + if (Deno.build.os === "windows") { + text = text + .replace(/\r\n/g, "\n") + .replace(/\\/g, "/"); + } + return stripAnsiCode(text); +} + +const assertSnapshot = createAssertSnapshot({ + dir: fromFileUrl(new URL("../test/snapshots/", import.meta.url)), +}); diff --git a/cli/deno.json b/cli/deno.json new file mode 100644 index 00000000..1546ab8c --- /dev/null +++ b/cli/deno.json @@ -0,0 +1,27 @@ +{ + "name": "@molt/cli", + "version": "0.18.0", + "exports": { + ".": "./main.ts" + }, + "publish": { + "exclude": [ + "./integration" + ] + }, + "imports": { + "@cliffy/ansi": "jsr:@cliffy/ansi@1.0.0-rc.4", + "@cliffy/command": "jsr:@cliffy/command@1.0.0-rc.4", + "@conventional-commits/parser": "npm:@conventional-commits/parser@^0.4.1", + "@core/unknownutil": "jsr:@core/unknownutil@3.18.0", + "@david/dax": "jsr:@david/dax@0.40.0", + "@molt/core": "jsr:@molt/core@0.14.3", + "@std/assert": "jsr:@std/assert@0.222.1", + "@std/collections": "jsr:@std/collections@0.222.1", + "@std/fmt": "jsr:@std/fmt@0.222.1", + "@std/jsonc": "jsr:@std/jsonc@0.222.1", + "@std/semver": "jsr:@std/semver@0.222.1", + "@std/path": "jsr:@std/path@0.222.1", + "@std/testing": "jsr:@std/testing@0.222.1" + } +} diff --git a/cli/deno.lock b/cli/deno.lock new file mode 100644 index 00000000..158f0fdb --- /dev/null +++ b/cli/deno.lock @@ -0,0 +1,431 @@ +{ + "version": "3", + "packages": { + "specifiers": { + "jsr:@cliffy/ansi@1.0.0-rc.4": "jsr:@cliffy/ansi@1.0.0-rc.4", + "jsr:@cliffy/command@1.0.0-rc.4": "jsr:@cliffy/command@1.0.0-rc.4", + "jsr:@cliffy/flags@1.0.0-rc.4": "jsr:@cliffy/flags@1.0.0-rc.4", + "jsr:@cliffy/table@1.0.0-rc.4": "jsr:@cliffy/table@1.0.0-rc.4", + "jsr:@core/unknownutil@3.18.0": "jsr:@core/unknownutil@3.18.0", + "jsr:@david/dax@0.40.0": "jsr:@david/dax@0.40.0", + "jsr:@david/which@0.3": "jsr:@david/which@0.3.0", + "jsr:@std/assert@0.222.1": "jsr:@std/assert@0.222.1", + "jsr:@std/assert@^0.221.0": "jsr:@std/assert@0.221.0", + "jsr:@std/assert@^0.222.1": "jsr:@std/assert@0.222.1", + "jsr:@std/bytes@^0.221.0": "jsr:@std/bytes@0.221.0", + "jsr:@std/collections@0.222.1": "jsr:@std/collections@0.222.1", + "jsr:@std/console@0.221": "jsr:@std/console@0.221.0", + "jsr:@std/encoding@0.221": "jsr:@std/encoding@0.221.0", + "jsr:@std/fmt@0.221": "jsr:@std/fmt@0.221.0", + "jsr:@std/fmt@0.222.1": "jsr:@std/fmt@0.222.1", + "jsr:@std/fmt@^0.221.0": "jsr:@std/fmt@0.221.0", + "jsr:@std/fmt@^0.222.1": "jsr:@std/fmt@0.222.1", + "jsr:@std/fs@0.221.0": "jsr:@std/fs@0.221.0", + "jsr:@std/fs@^0.222.1": "jsr:@std/fs@0.222.1", + "jsr:@std/io@0.221": "jsr:@std/io@0.221.0", + "jsr:@std/io@0.221.0": "jsr:@std/io@0.221.0", + "jsr:@std/io@^0.221.0": "jsr:@std/io@0.221.0", + "jsr:@std/json@^0.222.1": "jsr:@std/json@0.222.1", + "jsr:@std/jsonc@0.222.1": "jsr:@std/jsonc@0.222.1", + "jsr:@std/path@0.221.0": "jsr:@std/path@0.221.0", + "jsr:@std/path@0.222.1": "jsr:@std/path@0.222.1", + "jsr:@std/path@^0.221.0": "jsr:@std/path@0.221.0", + "jsr:@std/path@^0.222.1": "jsr:@std/path@0.222.1", + "jsr:@std/semver@0.222.1": "jsr:@std/semver@0.222.1", + "jsr:@std/streams@0.221.0": "jsr:@std/streams@0.221.0", + "jsr:@std/testing@0.222.1": "jsr:@std/testing@0.222.1", + "jsr:@std/text@0.221": "jsr:@std/text@0.221.0", + "npm:@octokit/rest@20.1.0": "npm:@octokit/rest@20.1.0_@octokit+core@5.2.0" + }, + "jsr": { + "@cliffy/ansi@1.0.0-rc.4": { + "integrity": "df561b6a69bb5177c31618c027274504ed24b996b854fa072eb7d0a380e41ac1", + "dependencies": [ + "jsr:@std/encoding@0.221", + "jsr:@std/fmt@0.221", + "jsr:@std/io@0.221" + ] + }, + "@cliffy/command@1.0.0-rc.4": { + "integrity": "709884ffe0f53ce3edafa92b58223634397878fbf6dcabe0c74ea0108273b9f7", + "dependencies": [ + "jsr:@cliffy/flags@1.0.0-rc.4", + "jsr:@cliffy/table@1.0.0-rc.4", + "jsr:@std/fmt@0.221", + "jsr:@std/text@0.221" + ] + }, + "@cliffy/flags@1.0.0-rc.4": { + "integrity": "29f370ade4ddf6e150a4d25fc44661234c19870ffcf7fb07cd100f1843fcd6e1" + }, + "@cliffy/table@1.0.0-rc.4": { + "integrity": "990e4e0b3910e6c9cf7a5b4318b8f5e121cf681494c94fd113febb9b4d4c0741", + "dependencies": [ + "jsr:@std/console@0.221" + ] + }, + "@core/unknownutil@3.18.0": { + "integrity": "bff7ab4a2f554bbade301127519523b0d3baa4273ecbed51287133ac00a48738" + }, + "@david/dax@0.40.0": { + "integrity": "1e0534a437e1d6c915979f19a3d048e5e2ce2a91176555a0ea1e89d929187279", + "dependencies": [ + "jsr:@david/which@0.3", + "jsr:@std/fmt@^0.221.0", + "jsr:@std/fs@0.221.0", + "jsr:@std/io@0.221.0", + "jsr:@std/path@0.221.0", + "jsr:@std/streams@0.221.0" + ] + }, + "@david/which@0.3.0": { + "integrity": "6bdb62c40ac90edcf328e854fa8103a8db21e7c326089cbe3c3a1cf7887d3204" + }, + "@std/assert@0.221.0": { + "integrity": "a5f1aa6e7909dbea271754fd4ab3f4e687aeff4873b4cef9a320af813adb489a" + }, + "@std/assert@0.222.1": { + "integrity": "691637161ee584a9919d1f9950ddd1272feb8e0a19e83aa5b7563cedaf73d74c", + "dependencies": [ + "jsr:@std/fmt@^0.222.1" + ] + }, + "@std/bytes@0.221.0": { + "integrity": "64a047011cf833890a4a2ab7293ac55a1b4f5a050624ebc6a0159c357de91966" + }, + "@std/collections@0.222.1": { + "integrity": "234099e08eead6a87e59f4f1abdcba35df5503cfb0e852e77a19f79359ed5760" + }, + "@std/console@0.221.0": { + "integrity": "8f2afc1f3f14f5d6039c0c767f057e4aa1897d2210e167c4667cb155cafb9d11" + }, + "@std/encoding@0.221.0": { + "integrity": "d1dd76ef0dc5d14088411e6dc1dede53bf8308c95d1537df1214c97137208e45" + }, + "@std/fmt@0.221.0": { + "integrity": "379fed69bdd9731110f26b9085aeb740606b20428ce6af31ef6bd45ef8efa62a" + }, + "@std/fmt@0.222.1": { + "integrity": "ec3382f9b0261c1ab1a5c804aa355d816515fa984cdd827ed32edfb187c0a722" + }, + "@std/fs@0.221.0": { + "integrity": "028044450299de8ed5a716ade4e6d524399f035513b85913794f4e81f07da286", + "dependencies": [ + "jsr:@std/assert@^0.221.0", + "jsr:@std/path@^0.221.0" + ] + }, + "@std/fs@0.222.1": { + "integrity": "337613f33e6e5970dddb263c3a3e5b8e39c97810ad6fe326cb9f65146af2503b", + "dependencies": [ + "jsr:@std/path@^0.222.1" + ] + }, + "@std/io@0.221.0": { + "integrity": "faf7f8700d46ab527fa05cc6167f4b97701a06c413024431c6b4d207caa010da", + "dependencies": [ + "jsr:@std/assert@^0.221.0", + "jsr:@std/bytes@^0.221.0" + ] + }, + "@std/json@0.222.1": { + "integrity": "ce4fb420dfd818fc2569289217842a3e70f249279f038a5e266f7b6572a2829a" + }, + "@std/jsonc@0.222.1": { + "integrity": "5d82d64eeb244e88fbb0927587dea7e1feccc6d5d9f49995b9ff5756d01be493", + "dependencies": [ + "jsr:@std/assert@^0.222.1", + "jsr:@std/json@^0.222.1" + ] + }, + "@std/path@0.221.0": { + "integrity": "0a36f6b17314ef653a3a1649740cc8db51b25a133ecfe838f20b79a56ebe0095", + "dependencies": [ + "jsr:@std/assert@^0.221.0" + ] + }, + "@std/path@0.222.1": { + "integrity": "aad3e9463ca53b0adb25b4d5beb330025674aaa3278da24c1c261d9289a9e48b", + "dependencies": [ + "jsr:@std/assert@^0.222.1" + ] + }, + "@std/semver@0.222.1": { + "integrity": "43c5b526423f48f6f75375c77226646803776fdc678b331f243b0bd667d54c18" + }, + "@std/streams@0.221.0": { + "integrity": "47f2f74634b47449277c0ee79fe878da4424b66bd8975c032e3afdca88986e61", + "dependencies": [ + "jsr:@std/io@^0.221.0" + ] + }, + "@std/testing@0.222.1": { + "integrity": "7be5c3ef185d31883116824a2dd604eb6f12a56fd5ed80489c7c696b2a76c5bc", + "dependencies": [ + "jsr:@std/assert@^0.222.1", + "jsr:@std/fmt@^0.222.1", + "jsr:@std/fs@^0.222.1", + "jsr:@std/path@^0.222.1" + ] + }, + "@std/text@0.221.0": { + "integrity": "a2f89ceb0d8851cd33e6774064621a1da9fbc36578cf4f02c5b5bcd7e8c84b67", + "dependencies": [ + "jsr:@std/assert@^0.221.0" + ] + } + }, + "npm": { + "@octokit/auth-token@4.0.0": { + "integrity": "sha512-tY/msAuJo6ARbK6SPIxZrPBms3xPbfwBrulZe0Wtr/DIY9lje2HeV1uoebShn6mx7SjCHif6EjMvoREj+gZ+SA==", + "dependencies": {} + }, + "@octokit/core@5.2.0": { + "integrity": "sha512-1LFfa/qnMQvEOAdzlQymH0ulepxbxnCYAKJZfMci/5XJyIHWgEYnDmgnKakbTh7CH2tFQ5O60oYDvns4i9RAIg==", + "dependencies": { + "@octokit/auth-token": "@octokit/auth-token@4.0.0", + "@octokit/graphql": "@octokit/graphql@7.1.0", + "@octokit/request": "@octokit/request@8.4.0", + "@octokit/request-error": "@octokit/request-error@5.1.0", + "@octokit/types": "@octokit/types@13.4.1", + "before-after-hook": "before-after-hook@2.2.3", + "universal-user-agent": "universal-user-agent@6.0.1" + } + }, + "@octokit/endpoint@9.0.5": { + "integrity": "sha512-ekqR4/+PCLkEBF6qgj8WqJfvDq65RH85OAgrtnVp1mSxaXF03u2xW/hUdweGS5654IlC0wkNYC18Z50tSYTAFw==", + "dependencies": { + "@octokit/types": "@octokit/types@13.4.1", + "universal-user-agent": "universal-user-agent@6.0.1" + } + }, + "@octokit/graphql@7.1.0": { + "integrity": "sha512-r+oZUH7aMFui1ypZnAvZmn0KSqAUgE1/tUXIWaqUCa1758ts/Jio84GZuzsvUkme98kv0WFY8//n0J1Z+vsIsQ==", + "dependencies": { + "@octokit/request": "@octokit/request@8.4.0", + "@octokit/types": "@octokit/types@13.4.1", + "universal-user-agent": "universal-user-agent@6.0.1" + } + }, + "@octokit/openapi-types@20.0.0": { + "integrity": "sha512-EtqRBEjp1dL/15V7WiX5LJMIxxkdiGJnabzYx5Apx4FkQIFgAfKumXeYAqqJCj1s+BMX4cPFIFC4OLCR6stlnA==", + "dependencies": {} + }, + "@octokit/openapi-types@22.1.0": { + "integrity": "sha512-pGUdSP+eEPfZiQHNkZI0U01HLipxncisdJQB4G//OAmfeO8sqTQ9KRa0KF03TUPCziNsoXUrTg4B2Q1EX++T0Q==", + "dependencies": {} + }, + "@octokit/plugin-paginate-rest@9.2.1_@octokit+core@5.2.0": { + "integrity": "sha512-wfGhE/TAkXZRLjksFXuDZdmGnJQHvtU/joFQdweXUgzo1XwvBCD4o4+75NtFfjfLK5IwLf9vHTfSiU3sLRYpRw==", + "dependencies": { + "@octokit/core": "@octokit/core@5.2.0", + "@octokit/types": "@octokit/types@12.6.0" + } + }, + "@octokit/plugin-request-log@4.0.1_@octokit+core@5.2.0": { + "integrity": "sha512-GihNqNpGHorUrO7Qa9JbAl0dbLnqJVrV8OXe2Zm5/Y4wFkZQDfTreBzVmiRfJVfE4mClXdihHnbpyyO9FSX4HA==", + "dependencies": { + "@octokit/core": "@octokit/core@5.2.0" + } + }, + "@octokit/plugin-rest-endpoint-methods@10.4.1_@octokit+core@5.2.0": { + "integrity": "sha512-xV1b+ceKV9KytQe3zCVqjg+8GTGfDYwaT1ATU5isiUyVtlVAO3HNdzpS4sr4GBx4hxQ46s7ITtZrAsxG22+rVg==", + "dependencies": { + "@octokit/core": "@octokit/core@5.2.0", + "@octokit/types": "@octokit/types@12.6.0" + } + }, + "@octokit/request-error@5.1.0": { + "integrity": "sha512-GETXfE05J0+7H2STzekpKObFe765O5dlAKUTLNGeH+x47z7JjXHfsHKo5z21D/o/IOZTUEI6nyWyR+bZVP/n5Q==", + "dependencies": { + "@octokit/types": "@octokit/types@13.4.1", + "deprecation": "deprecation@2.3.1", + "once": "once@1.4.0" + } + }, + "@octokit/request@8.4.0": { + "integrity": "sha512-9Bb014e+m2TgBeEJGEbdplMVWwPmL1FPtggHQRkV+WVsMggPtEkLKPlcVYm/o8xKLkpJ7B+6N8WfQMtDLX2Dpw==", + "dependencies": { + "@octokit/endpoint": "@octokit/endpoint@9.0.5", + "@octokit/request-error": "@octokit/request-error@5.1.0", + "@octokit/types": "@octokit/types@13.4.1", + "universal-user-agent": "universal-user-agent@6.0.1" + } + }, + "@octokit/rest@20.1.0_@octokit+core@5.2.0": { + "integrity": "sha512-STVO3itHQLrp80lvcYB2UIKoeil5Ctsgd2s1AM+du3HqZIR35ZH7WE9HLwUOLXH0myA0y3AGNPo8gZtcgIbw0g==", + "dependencies": { + "@octokit/core": "@octokit/core@5.2.0", + "@octokit/plugin-paginate-rest": "@octokit/plugin-paginate-rest@9.2.1_@octokit+core@5.2.0", + "@octokit/plugin-request-log": "@octokit/plugin-request-log@4.0.1_@octokit+core@5.2.0", + "@octokit/plugin-rest-endpoint-methods": "@octokit/plugin-rest-endpoint-methods@10.4.1_@octokit+core@5.2.0" + } + }, + "@octokit/types@12.6.0": { + "integrity": "sha512-1rhSOfRa6H9w4YwK0yrf5faDaDTb+yLyBUKOCV4xtCDB5VmIPqd/v9yr9o6SAzOAlRxMiRiCic6JVM1/kunVkw==", + "dependencies": { + "@octokit/openapi-types": "@octokit/openapi-types@20.0.0" + } + }, + "@octokit/types@13.4.1": { + "integrity": "sha512-Y73oOAzRBAUzR/iRAbGULzpNkX8vaxKCqEtg6K74Ff3w9f5apFnWtE/2nade7dMWWW3bS5Kkd6DJS4HF04xreg==", + "dependencies": { + "@octokit/openapi-types": "@octokit/openapi-types@22.1.0" + } + }, + "before-after-hook@2.2.3": { + "integrity": "sha512-NzUnlZexiaH/46WDhANlyR2bXRopNg4F/zuSA3OpZnllCUgRaOF2znDioDWrmbNVsuZk6l9pMquQB38cfBZwkQ==", + "dependencies": {} + }, + "deprecation@2.3.1": { + "integrity": "sha512-xmHIy4F3scKVwMsQ4WnVaS8bHOx0DmVwRywosKhaILI0ywMDWPtBSku2HNxRvF7jtwDRsoEwYQSfbxj8b7RlJQ==", + "dependencies": {} + }, + "once@1.4.0": { + "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", + "dependencies": { + "wrappy": "wrappy@1.0.2" + } + }, + "universal-user-agent@6.0.1": { + "integrity": "sha512-yCzhz6FN2wU1NiiQRogkTQszlQSlpWaw8SvVegAc+bDxbzHgh1vX8uIe8OYyMH6DwH+sdTJsgMl36+mSMdRJIQ==", + "dependencies": {} + }, + "wrappy@1.0.2": { + "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", + "dependencies": {} + } + } + }, + "remote": { + "https://deno.land/std@0.222.1/assert/_constants.ts": "a271e8ef5a573f1df8e822a6eb9d09df064ad66a4390f21b3e31f820a38e0975", + "https://deno.land/std@0.222.1/assert/_diff.ts": "4bf42969aa8b1a33aaf23eb8e478b011bfaa31b82d85d2ff4b5c4662d8780d2b", + "https://deno.land/std@0.222.1/assert/_format.ts": "0ba808961bf678437fb486b56405b6fefad2cf87b5809667c781ddee8c32aff4", + "https://deno.land/std@0.222.1/assert/assert.ts": "09d30564c09de846855b7b071e62b5974b001bb72a4b797958fe0660e7849834", + "https://deno.land/std@0.222.1/assert/assert_array_includes.ts": "167b2c29997defd49a1835de52b54ae3cbb2bcba52df7c7ee45fe64b473264f1", + "https://deno.land/std@0.222.1/assert/assert_equals.ts": "cc1f4b0ff4ad511e69f965535b56a6cdbbbc0f086bf376e0243214df6039c883", + "https://deno.land/std@0.222.1/assert/assert_exists.ts": "43420cf7f956748ae6ed1230646567b3593cb7a36c5a5327269279c870c5ddfd", + "https://deno.land/std@0.222.1/assert/assert_instance_of.ts": "e22343c1fdcacfaea8f37784ad782683ec1cf599ae9b1b618954e9c22f376f2c", + "https://deno.land/std@0.222.1/assert/assert_is_error.ts": "f856b3bc978a7aa6a601f3fec6603491ab6255118afa6baa84b04426dd3cc491", + "https://deno.land/std@0.222.1/assert/assert_not_equals.ts": "78d45dd46133d76ce624b2c6c09392f6110f0df9b73f911d20208a68dee2ef29", + "https://deno.land/std@0.222.1/assert/assert_object_match.ts": "411450fd194fdaabc0089ae68f916b545a49d7b7e6d0026e84a54c9e7eed2693", + "https://deno.land/std@0.222.1/assert/assert_rejects.ts": "4bee1d6d565a5b623146a14668da8f9eb1f026a4f338bbf92b37e43e0aa53c31", + "https://deno.land/std@0.222.1/assert/assert_throws.ts": "c6508b2879d465898dab2798009299867e67c570d7d34c90a2d235e4553906eb", + "https://deno.land/std@0.222.1/assert/assertion_error.ts": "ba8752bd27ebc51f723702fac2f54d3e94447598f54264a6653d6413738a8917", + "https://deno.land/std@0.222.1/assert/equal.ts": "bddf07bb5fc718e10bb72d5dc2c36c1ce5a8bdd3b647069b6319e07af181ac47", + "https://deno.land/std@0.222.1/collections/_utils.ts": "b2ec8ada31b5a72ebb1d99774b849b4c09fe4b3a38d07794bd010bd218a16e0b", + "https://deno.land/std@0.222.1/collections/deep_merge.ts": "04f8d2a6cfa15c7580e788689bcb5e162512b9ccb18bab1241824b432a78551e", + "https://deno.land/std@0.222.1/collections/distinct.ts": "42d81633e4ccd5ea89118cb08f875bbfc683ac6620df2fa60f3d07270b177f4d", + "https://deno.land/std@0.222.1/collections/distinct_by.ts": "e895705decb0ce88b31c6679fd4e2bd08ac6d47cde7d00bf2016e3c2bac565a7", + "https://deno.land/std@0.222.1/collections/filter_entries.ts": "12202e99001695fcf541ec0191e9762fe7290ba4597df762d3a0c6e611a1aafe", + "https://deno.land/std@0.222.1/collections/filter_keys.ts": "bf8eaae2769e6ddd34f23ba1912f7feda2b6f374253c07a6630e9a2e384ba611", + "https://deno.land/std@0.222.1/collections/map_entries.ts": "45b8bf3f197ee24abe2e078213a4cf2f4e187ad130649fff34e13b1a03ede478", + "https://deno.land/std@0.222.1/collections/map_not_nullish.ts": "f519f74db550afcf6c6e2486382cb4dc6b0465e4234b6acca26910d118e7dd55", + "https://deno.land/std@0.222.1/collections/map_values.ts": "91d6ece4b4dc4b94abc378f51e0e309e7f7f18b2ce4c335dab673a31ebd17c75", + "https://deno.land/std@0.222.1/collections/max_by.ts": "a601c296d54349097d5b424bc86c84010ab22733b622b480e2ad65927063d7bb", + "https://deno.land/std@0.222.1/collections/omit.ts": "7a875ecbb02e3c418195325fd8c520bcf492362344d4d6b295d2e0f101ccccae", + "https://deno.land/std@0.222.1/collections/partition.ts": "22689dc4834bbcaa06f9ac204ac5502ab0f7087d7fca26bad50319c12434d099", + "https://deno.land/std@0.222.1/fmt/colors.ts": "d239d84620b921ea520125d778947881f62c50e78deef2657073840b8af9559a", + "https://deno.land/std@0.222.1/fs/_get_file_info_type.ts": "da7bec18a7661dba360a1db475b826b18977582ce6fc9b25f3d4ee0403fe8cbd", + "https://deno.land/std@0.222.1/fs/_to_path_string.ts": "29bfc9c6c112254961d75cbf6ba814d6de5349767818eb93090cecfa9665591e", + "https://deno.land/std@0.222.1/fs/ensure_dir.ts": "313e8a62b8bb20d900138ff794bde6a6ac0a6bebc91220fba6dfc3303bde56c6", + "https://deno.land/std@0.222.1/fs/ensure_file.ts": "67608cf550529f3d4aa1f8b6b36bf817bdc40b14487bf8f60e61cbf68f507cf3", + "https://deno.land/std@0.222.1/fs/eol.ts": "18c4ac009d0318504c285879eb7f47942643f13619e0ff070a0edc59353306bd", + "https://deno.land/std@0.222.1/fs/exists.ts": "3d38cb7dcbca3cf313be343a7b8af18a87bddb4b5ca1bd2314be12d06533b50f", + "https://deno.land/std@0.222.1/json/common.ts": "33f1a4f39a45e2f9f357823fd0b5cf88b63fb4784b8c9a28f8120f70a20b23e9", + "https://deno.land/std@0.222.1/jsonc/parse.ts": "06fbe10f0bb0cba684f7902bf7de5126b16eb0e5a82220c98a4b86675c7f9cff", + "https://deno.land/std@0.222.1/path/_common/assert_path.ts": "dbdd757a465b690b2cc72fc5fb7698c51507dec6bfafce4ca500c46b76ff7bd8", + "https://deno.land/std@0.222.1/path/_common/basename.ts": "569744855bc8445f3a56087fd2aed56bdad39da971a8d92b138c9913aecc5fa2", + "https://deno.land/std@0.222.1/path/_common/constants.ts": "dc5f8057159f4b48cd304eb3027e42f1148cf4df1fb4240774d3492b5d12ac0c", + "https://deno.land/std@0.222.1/path/_common/dirname.ts": "684df4aa71a04bbcc346c692c8485594fc8a90b9408dfbc26ff32cf3e0c98cc8", + "https://deno.land/std@0.222.1/path/_common/from_file_url.ts": "d672bdeebc11bf80e99bf266f886c70963107bdd31134c4e249eef51133ceccf", + "https://deno.land/std@0.222.1/path/_common/normalize.ts": "684df4aa71a04bbcc346c692c8485594fc8a90b9408dfbc26ff32cf3e0c98cc8", + "https://deno.land/std@0.222.1/path/_common/normalize_string.ts": "33edef773c2a8e242761f731adeb2bd6d683e9c69e4e3d0092985bede74f4ac3", + "https://deno.land/std@0.222.1/path/_common/relative.ts": "faa2753d9b32320ed4ada0733261e3357c186e5705678d9dd08b97527deae607", + "https://deno.land/std@0.222.1/path/_common/strip_trailing_separators.ts": "7024a93447efcdcfeaa9339a98fa63ef9d53de363f1fbe9858970f1bba02655a", + "https://deno.land/std@0.222.1/path/_common/to_file_url.ts": "7f76adbc83ece1bba173e6e98a27c647712cab773d3f8cbe0398b74afc817883", + "https://deno.land/std@0.222.1/path/_interface.ts": "8dfeb930ca4a772c458a8c7bbe1e33216fe91c253411338ad80c5b6fa93ddba0", + "https://deno.land/std@0.222.1/path/_os.ts": "8fb9b90fb6b753bd8c77cfd8a33c2ff6c5f5bc185f50de8ca4ac6a05710b2c15", + "https://deno.land/std@0.222.1/path/basename.ts": "7ee495c2d1ee516ffff48fb9a93267ba928b5a3486b550be73071bc14f8cc63e", + "https://deno.land/std@0.222.1/path/dirname.ts": "85bd955bf31d62c9aafdd7ff561c4b5fb587d11a9a5a45e2b01aedffa4238a7c", + "https://deno.land/std@0.222.1/path/extname.ts": "593303db8ae8c865cbd9ceec6e55d4b9ac5410c1e276bfd3131916591b954441", + "https://deno.land/std@0.222.1/path/from_file_url.ts": "911833ae4fd10a1c84f6271f36151ab785955849117dc48c6e43b929504ee069", + "https://deno.land/std@0.222.1/path/is_absolute.ts": "4791afc8bfd0c87f0526eaa616b0d16e7b3ab6a65b62942e50eac68de4ef67d7", + "https://deno.land/std@0.222.1/path/join.ts": "ae2ec5ca44c7e84a235fd532e4a0116bfb1f2368b394db1c4fb75e3c0f26a33a", + "https://deno.land/std@0.222.1/path/parse.ts": "3e172974e3c71025f5fbd2bd9db4307acb9cc2de14cf6f4464bf40957663cabe", + "https://deno.land/std@0.222.1/path/posix/_util.ts": "1e3937da30f080bfc99fe45d7ed23c47dd8585c5e473b2d771380d3a6937cf9d", + "https://deno.land/std@0.222.1/path/posix/basename.ts": "d2fa5fbbb1c5a3ab8b9326458a8d4ceac77580961b3739cd5bfd1d3541a3e5f0", + "https://deno.land/std@0.222.1/path/posix/dirname.ts": "76cd348ffe92345711409f88d4d8561d8645353ac215c8e9c80140069bf42f00", + "https://deno.land/std@0.222.1/path/posix/extname.ts": "e398c1d9d1908d3756a7ed94199fcd169e79466dd88feffd2f47ce0abf9d61d2", + "https://deno.land/std@0.222.1/path/posix/from_file_url.ts": "951aee3a2c46fd0ed488899d024c6352b59154c70552e90885ed0c2ab699bc40", + "https://deno.land/std@0.222.1/path/posix/is_absolute.ts": "cebe561ad0ae294f0ce0365a1879dcfca8abd872821519b4fcc8d8967f888ede", + "https://deno.land/std@0.222.1/path/posix/join.ts": "7fc2cb3716aa1b863e990baf30b101d768db479e70b7313b4866a088db016f63", + "https://deno.land/std@0.222.1/path/posix/normalize.ts": "baeb49816a8299f90a0237d214cef46f00ba3e95c0d2ceb74205a6a584b58a91", + "https://deno.land/std@0.222.1/path/posix/parse.ts": "0b1fc4cb890dbb699ec1d2c232d274843b4a7142e1ad976b69fe51c954eb6080", + "https://deno.land/std@0.222.1/path/posix/relative.ts": "3907d6eda41f0ff723d336125a1ad4349112cd4d48f693859980314d5b9da31c", + "https://deno.land/std@0.222.1/path/posix/resolve.ts": "08b699cfeee10cb6857ccab38fa4b2ec703b0ea33e8e69964f29d02a2d5257cf", + "https://deno.land/std@0.222.1/path/posix/to_file_url.ts": "7aa752ba66a35049e0e4a4be5a0a31ac6b645257d2e031142abb1854de250aaf", + "https://deno.land/std@0.222.1/path/relative.ts": "ab739d727180ed8727e34ed71d976912461d98e2b76de3d3de834c1066667add", + "https://deno.land/std@0.222.1/path/resolve.ts": "a6f977bdb4272e79d8d0ed4333e3d71367cc3926acf15ac271f1d059c8494d8d", + "https://deno.land/std@0.222.1/path/to_file_url.ts": "88f049b769bce411e2d2db5bd9e6fd9a185a5fbd6b9f5ad8f52bef517c4ece1b", + "https://deno.land/std@0.222.1/path/windows/_util.ts": "d5f47363e5293fced22c984550d5e70e98e266cc3f31769e1710511803d04808", + "https://deno.land/std@0.222.1/path/windows/basename.ts": "6bbc57bac9df2cec43288c8c5334919418d784243a00bc10de67d392ab36d660", + "https://deno.land/std@0.222.1/path/windows/dirname.ts": "33e421be5a5558a1346a48e74c330b8e560be7424ed7684ea03c12c21b627bc9", + "https://deno.land/std@0.222.1/path/windows/extname.ts": "165a61b00d781257fda1e9606a48c78b06815385e7d703232548dbfc95346bef", + "https://deno.land/std@0.222.1/path/windows/from_file_url.ts": "ced2d587b6dff18f963f269d745c4a599cf82b0c4007356bd957cb4cb52efc01", + "https://deno.land/std@0.222.1/path/windows/is_absolute.ts": "4a8f6853f8598cf91a835f41abed42112cebab09478b072e4beb00ec81f8ca8a", + "https://deno.land/std@0.222.1/path/windows/join.ts": "8d03530ab89195185103b7da9dfc6327af13eabdcd44c7c63e42e27808f50ecf", + "https://deno.land/std@0.222.1/path/windows/normalize.ts": "78126170ab917f0ca355a9af9e65ad6bfa5be14d574c5fb09bb1920f52577780", + "https://deno.land/std@0.222.1/path/windows/parse.ts": "dbdfe2bc6db482d755b5f63f7207cd019240fcac02ad2efa582adf67ff10553a", + "https://deno.land/std@0.222.1/path/windows/relative.ts": "3e1abc7977ee6cc0db2730d1f9cb38be87b0ce4806759d271a70e4997fc638d7", + "https://deno.land/std@0.222.1/path/windows/resolve.ts": "8dae1dadfed9d46ff46cc337c9525c0c7d959fb400a6308f34595c45bdca1972", + "https://deno.land/std@0.222.1/path/windows/to_file_url.ts": "40e560ee4854fe5a3d4d12976cef2f4e8914125c81b11f1108e127934ced502e", + "https://deno.land/std@0.222.1/semver/_constants.ts": "5ef89c5f33e6095546ae3e57920592feefcb8372d4cc05542f6bf15a1977e3c9", + "https://deno.land/std@0.222.1/semver/_shared.ts": "5c53a675225cba9ad74ae2e17c124e333728fc2b551a13e8a32b99433b90c1c2", + "https://deno.land/std@0.222.1/semver/compare.ts": "7b5610c25ded57dc4aa41034ee02857d1a6fff609ab183afea17849284f86236", + "https://deno.land/std@0.222.1/semver/constants.ts": "bd442eb6d51d5032686e02abdf575b32dd08f2c95e653e66bbeb927e8ff54bb5", + "https://deno.land/std@0.222.1/semver/format.ts": "a4492b55a10210a10b9307491c0ec7f0c2475cc82af33de1c2565a15083b83df", + "https://deno.land/std@0.222.1/semver/parse.ts": "94c09f3486643853e7438e64f2c6741462fbeb84cf141ad5bfe88b73ec4cb0f3", + "https://deno.land/std@0.222.1/semver/parse_range.ts": "f48ca42b59988d9274225b1f93c39d84005e810bb858faf564f48c0ad8431fa7", + "https://deno.land/std@0.222.1/semver/try_parse.ts": "043204f1235243c3d02b66ffca2c37dc2941e417dbccaf6c3a15b476a33f0e24", + "https://deno.land/std@0.222.1/semver/try_parse_range.ts": "cf1e2d489bbe9ed6185de551acdf708e23e0e1bc4be0958052dfef178f763eee", + "https://deno.land/std@0.222.1/semver/types.ts": "9286e72b160e25856608f4bc5f08f8f5ccba54e6cdfc9aba8adee68a355c4b36", + "https://deno.land/std@0.222.1/testing/_test_suite.ts": "f10a8a6338b60c403f07a76f3f46bdc9f1e1a820c0a1decddeb2949f7a8a0546", + "https://deno.land/std@0.222.1/testing/bdd.ts": "3e4de4ff6d8f348b5574661cef9501b442046a59079e201b849d0e74120d476b", + "https://deno.land/std@0.222.1/testing/mock.ts": "a963181c2860b6ba3eb60e08b62c164d33cf5da7cd445893499b2efda20074db", + "https://deno.land/std@0.222.1/testing/snapshot.ts": "35ca1c8e8bfb98d7b7e794f1b7be8d992483fcff572540e41396f22a5bddb944", + "https://deno.land/x/async@v2.1.0/mutex.ts": "782792457021425da571b8f30d6c62f7dc1cdf83d7299257343d57cac7357e27", + "https://deno.land/x/deno_graph@0.69.6/deno_graph_wasm.generated.js": "db34a2f6e33c4dda6b60bdd1a698babd9593a6d042757949d773b72662a45520", + "https://deno.land/x/deno_graph@0.69.6/loader.ts": "512a406cb4c449b45110f2b878cd09929a883a4af193060232d2d9fc76a9d4dd", + "https://deno.land/x/deno_graph@0.69.6/media_type.ts": "7c1c5c6654e3cf84b8daa53c0d1ffc1b7864849406f559b961eccff859b0a417", + "https://deno.land/x/deno_graph@0.69.6/mod.ts": "be92f206bb38138ffc1c81a0b607dc22bb3a1dd9159b05331b2b37200ba25039", + "https://deno.land/x/deno_graph@0.69.6/types.ts": "bde84cb2919068c07e6cf4d8bf3054e8da908f2f221623d5302380df29b96320", + "https://deno.land/x/dir@1.5.1/data_local_dir/mod.ts": "91eb1c4bfadfbeda30171007bac6d85aadacd43224a5ed721bbe56bc64e9eb66", + "https://deno.land/x/import_map@v0.19.1/import_map.generated.js": "c46023bef881ccecc740740962331f98decbfe72d88644396bf674145c20dd1e", + "https://deno.land/x/import_map@v0.19.1/mod.ts": "dd4c4e20639dcfd720a6d41f47bea250db86137901a08988102094678c6b7859", + "https://deno.land/x/unknownutil@v3.18.0/_typeutil.ts": "774d207c47fb5350f468cdcf68e80f1bc6e278f6bc77c04d17a601618c49d2c1", + "https://deno.land/x/unknownutil@v3.18.0/inspect.ts": "33e61bdfed94cd586d66600813b528fa93046a2802d8144277b92f0fa5e5f10e", + "https://deno.land/x/unknownutil@v3.18.0/is.ts": "0c552cf85f8eeca86b41d892da627168185eaabfd79931e39cfdf00a70de6269", + "https://deno.land/x/unknownutil@v3.18.0/metadata.ts": "04fcfbca1338e44b4067be4bde51b863dc4c91b279541c78620e617d3e77e01a", + "https://deno.land/x/unknownutil@v3.18.0/mod.ts": "c38cc1fe09a108ecca944adde2dd2f37c1c00a83c964f0a3b8a7debd62d33fc8", + "https://deno.land/x/unknownutil@v3.18.0/util.ts": "051fb654a110aa8bc9e034ce03aea2d39349fdf723da6ce6b783e5299327444d", + "https://deno.land/x/wasmbuild@0.15.1/cache.ts": "9d01b5cb24e7f2a942bbd8d14b093751fa690a6cde8e21709ddc97667e6669ed", + "https://deno.land/x/wasmbuild@0.15.1/loader.ts": "8c2fc10e21678e42f84c5135d8ab6ab7dc92424c3f05d2354896a29ccfd02a63" + }, + "workspace": { + "dependencies": [ + "jsr:@cliffy/ansi@1.0.0-rc.4", + "jsr:@cliffy/command@1.0.0-rc.4", + "jsr:@core/unknownutil@3.18.0", + "jsr:@david/dax@0.40.0", + "jsr:@molt/core@0.14.3", + "jsr:@std/assert@0.222.1", + "jsr:@std/collections@0.222.1", + "jsr:@std/fmt@0.222.1", + "jsr:@std/jsonc@0.222.1", + "jsr:@std/path@0.222.1", + "jsr:@std/semver@0.222.1", + "jsr:@std/testing@0.222.1" + ] + } +} diff --git a/cli/main.ts b/cli/main.ts new file mode 100644 index 00000000..d5eb3138 --- /dev/null +++ b/cli/main.ts @@ -0,0 +1,109 @@ +import { Command } from "@cliffy/command"; +import $ from "@david/dax"; + +const main = new Command() + .name("molt") + .description( + "Check updates to dependencies in Deno modules and configuration files", + ) + .versionOption("-v, --version", "Print version info", versionCommand) + .option("-w, --write", "Write changes to local files", { + conflicts: ["commit"], + }) + .option("-c, --commit", "Commit changes to local git repository", { + conflicts: ["write"], + }) + .option( + "--changelog=[commit_types:string[]]", + "Show a curated changelog for each update", + ) + .option("--debug", "Print debug information") + .option("--import-map ", "Specify import map file") + .option("--ignore=", "Ignore dependencies") + .option("--only=", "Check specified dependencies") + .option("--pre-commit=", "Run tasks before each commit", { + depends: ["commit"], + }) + .option("--prefix ", "Prefix for commit messages", { + depends: ["commit"], + }) + .option( + "--prefix-lock ", + "Prefix for commit messages of updating a lock file", + { depends: ["commit", "unstable-lock"] }, + ) + .option( + "--unstable-lock [file:string]", + "Enable unstable updating of a lock file", + ) + .arguments("") + .action(async function (options, ...files) { + if ( + options.importMap && await $.path(options.importMap).exists() === false + ) { + throw new Error(`Import map ${options.importMap} does not exist.`); + } + ensureFiles(files); + const updates = await import("./modules/collect.ts").then((mod) => + mod.default(files, options) + ); + await import("./modules/print.ts").then((mod) => + mod.default(files, updates, options) + ); + if (options.write) { + await import("./modules/write.ts").then((mod) => mod.default(updates)); + } + if (options.commit) { + const tasks = await import("./modules/tasks.ts").then((mod) => + mod.getTasks() + ); + const { filterKeys } = await import("@std/collections/filter-keys"); + await import("./modules/commit.ts").then((mod) => + mod.default(updates, { + ...options, + preCommit: filterKeys( + tasks, + (key) => options.preCommit?.includes(key) ?? false, + ), + }) + ); + } + }); + +async function versionCommand() { + const { default: configs } = await import("./deno.json", { + with: { type: "json" }, + }); + console.log(configs.version); +} + +function ensureFiles(paths: string[]) { + for (const path of paths) { + try { + if (!Deno.statSync(path).isFile) { + throw new Error(`Not a valid file: "${path}"`); + } + } catch { + throw new Error(`Path does not exist: "${path}"`); + } + } +} + +if (import.meta.main) { + const debug = Deno.args.includes("--debug"); + try { + const env = await Deno.permissions.query({ name: "env" }); + if (env.state === "granted" && Deno.env.get("MOLT_TEST")) { + (await import("./modules/testing.ts")).default(); + } + await main.parse(Deno.args); + } catch (error) { + if (debug) { + throw error; + } + if (error.message) { + console.error("Error: " + error.message); + } + Deno.exit(1); + } +} diff --git a/cli/modules/changelog.ts b/cli/modules/changelog.ts new file mode 100644 index 00000000..0605a803 --- /dev/null +++ b/cli/modules/changelog.ts @@ -0,0 +1,65 @@ +import { minWith } from "@std/collections"; +import { curateChangeLog } from "@molt/lib/changelog"; +import { + compareCommits, + fromDependency, + resolveCreatedDate, + resolvePackageRoot, + resolveRepository, +} from "@molt/integration"; +import type { Dependency, UpdatedDependency } from "@molt/core"; + +export default async function ( + updated: UpdatedDependency, + froms: Dependency[], + options: { + changelog?: true | string[]; + }, +) { + const pkg = fromDependency(updated); + if (!pkg) { + // Can't provide a changelog for a non-package dependency + return; + } + const repo = await resolveRepository(pkg); + if (!repo) { + return; + } + /** A map of dependency names to the created date of the oldest update */ + const dates = new Map(); + await Promise.all( + froms.map(async (it) => { + dates.set(name, await resolveCreatedDate(pkg, it.version!)); + }), + ); + /** The oldest update from which to fetch commit logs */ + const oldest = minWith( + froms, + (a, b) => Math.sign(dates.get(a.name)! - dates.get(b.name)!), + ); + if (!oldest) { + // The dependency was newly added in this update + return; + } + const messages = await compareCommits( + repo, + oldest.version!, + updated.version, + ); + const root = await resolvePackageRoot(repo, pkg, updated.version); + if (!root) { + // The package seems to be generated dynamically on publish + return; + } + const changelog = curateChangeLog(messages, { + types: Array.isArray(options.changelog) + ? options.changelog + : ["feat", "fix", "deprecation"], + scope: root !== "." ? pkg.name : undefined, + }); + for (const [type, records] of Object.entries(changelog)) { + for (const record of records) { + console.log(` ${type}: ${record.text}`); + } + } +} diff --git a/cli/modules/collect.ts b/cli/modules/collect.ts new file mode 100644 index 00000000..9521da82 --- /dev/null +++ b/cli/modules/collect.ts @@ -0,0 +1,33 @@ +import { $ } from "@david/dax"; +import { collect, type CollectResult } from "@molt/core"; + +export default async function ( + entrypoints: string[], + options: { + ignore?: string[]; + importMap?: string; + only?: string[]; + unstableLock?: true | string; + }, +): Promise { + const result = await $.progress("Checking for updates").with(() => + collect(entrypoints, { + lock: !!options.unstableLock, + lockFile: typeof options.unstableLock === "string" + ? options.unstableLock + : undefined, + importMap: options.importMap, + ignore: options.ignore + ? (dep) => options.ignore!.some((it) => dep.name.includes(it)) + : undefined, + only: options.only + ? (dep) => options.only!.some((it) => dep.name.includes(it)) + : undefined, + }) + ); + if (!result.updates.length) { + console.log("🍵 No updates found"); + Deno.exit(0); + } + return result; +} diff --git a/cli/modules/commit.ts b/cli/modules/commit.ts new file mode 100644 index 00000000..37e5f050 --- /dev/null +++ b/cli/modules/commit.ts @@ -0,0 +1,52 @@ +import { type CollectResult, createCommitSequence, execute } from "@molt/core"; +import { runTask, type TaskRecord } from "./tasks.ts"; + +const formatPrefix = (prefix: string | undefined) => + prefix ? prefix.trimEnd() + " " : ""; + +export default async function ( + result: CollectResult, + options: { + preCommit?: TaskRecord; + postCommit?: TaskRecord; + prefix?: string; + prefixLock?: string; + }, +) { + console.log(); + + const preCommitTasks = Object.entries(options?.preCommit ?? {}); + const postCommitTasks = Object.entries(options?.postCommit ?? {}); + const hasTask = preCommitTasks.length > 0 || postCommitTasks.length > 0; + + let count = 0; + const commits = createCommitSequence(result, { + groupBy: (dependency) => dependency.to.name, + composeCommitMessage: ({ group, types, version }) => + formatPrefix( + types.length === 1 && types.includes("lockfile") + ? options.prefixLock + : options.prefix, + ) + `bump ${group}` + + (version?.from ? ` from ${version?.from}` : "") + + (version?.to ? ` to ${version?.to}` : ""), + preCommit: preCommitTasks.length > 0 + ? async (commit) => { + console.log(`💾 ${commit.message}`); + for (const t of preCommitTasks) { + await runTask(t); + } + } + : undefined, + postCommit: async (commit) => { + console.log(`📝 ${commit.message}`); + for (const task of postCommitTasks) { + await runTask(task); + } + if (hasTask && ++count < commits.commits.length) { + console.log(); + } + }, + }); + await execute(commits); +} diff --git a/cli/modules/print.ts b/cli/modules/print.ts new file mode 100644 index 00000000..3d2ff62e --- /dev/null +++ b/cli/modules/print.ts @@ -0,0 +1,62 @@ +import { distinct, mapNotNullish } from "@std/collections"; +import { relative } from "@std/path"; +import { colors } from "@cliffy/ansi"; +import type { CollectResult, DependencyUpdate } from "@molt/core"; + +const { gray, yellow, bold } = colors; + +export default async function ( + entrypoints: string[], + result: CollectResult, + options: { changelog?: true | string[] }, +): Promise { + /** A map of names of dependencies to a list of updates */ + const dependencies = new Map(); + for (const u of result.updates) { + const list = dependencies.get(u.to.name) ?? []; + list.push(u); + dependencies.set(u.to.name, list); + } + /** A list of files that being updated */ + const files = distinct(result.updates.map((u) => u.referrer)); + // + // Print information on each dependency + // + for (const [name, updates] of dependencies) { + const froms = mapNotNullish(updates, (it) => it.from); + const updated = updates[0].to; + // + // Print the name of the dependency and the version change + // ex. deno.land/std 0.220, 0.222.1 => 0.223.0 + // + const versions = distinct(froms.map((d) => d.version)); + const joined = versions.join(", "); + console.log( + `📦 ${bold(name)} ${yellow(joined)} => ${yellow(updated.version)}`, + ); + // + // Print a curated changelog for the dependency + // + if (options.changelog) { + const { default: printChangeLog } = await import("./changelog.ts"); + try { + await printChangeLog(updated, froms, options); + } catch { + // The dependency is a package but not tagged in the repository + } + } + // + // Print modules that import the dependency. + // ex. /path/to/mod.ts 0.222.1 + // + if (entrypoints.length > 1 || files.length > 1) { + distinct( + updates.map((u) => { + const source = relative(Deno.cwd(), u.map?.source ?? u.referrer); + const version = versions.length > 1 ? u.from?.version : undefined; + return " " + gray(source + (version ? ` (${version})` : "")); + }), + ).forEach((it) => console.log(it)); + } + } +} diff --git a/cli/modules/tasks.ts b/cli/modules/tasks.ts new file mode 100644 index 00000000..c24fa23b --- /dev/null +++ b/cli/modules/tasks.ts @@ -0,0 +1,45 @@ +import { mapEntries } from "@std/collections/map-entries"; +import { parse as parseJsonc } from "@std/jsonc"; +import { colors } from "@cliffy/ansi"; +import { ensure, is } from "@core/unknownutil"; +import { findFileUp } from "@molt/lib/path"; + +const { cyan } = colors; + +export type TaskRecord = Record; + +export async function getTasks() { + const tasks: TaskRecord = { + fmt: ["fmt", "--no-config"], + lint: ["lint", "--no-config"], + test: ["test", "--no-config"], + }; + const config = await findFileUp(Deno.cwd(), "deno.json", "deno.jsonc"); + if (!config) { + return tasks; + } + try { + const json = ensure( + parseJsonc(await Deno.readTextFile(config)), + is.ObjectOf({ tasks: is.Record }), + ); + return { + ...tasks, + ...mapEntries(json.tasks, ([name]) => [name, ["task", "-q", name]]), + }; + } catch { + return tasks; + } +} + +export async function runTask([name, args]: [string, string[]]) { + console.log(`🔨 Running task ${cyan(name)}...`); + const { code } = await new Deno.Command("deno", { + args, + stdout: "inherit", + stderr: "inherit", + }).output(); + if (code != 0) { + Deno.exit(code); + } +} diff --git a/cli/modules/testing.ts b/cli/modules/testing.ts new file mode 100644 index 00000000..26d5904f --- /dev/null +++ b/cli/modules/testing.ts @@ -0,0 +1,24 @@ +import { + CommandStub, + FileSystemFake, + LatestVersionStub, + ReadTextFileStub, + WriteTextFileStub, +} from "@molt/lib/testing"; + +/** + * Enables all test stubs. + */ +export default function () { + LatestVersionStub.create({ + "deno.land/std": "0.218.2", + "deno_graph": "0.69.7", + "node-emoji": "2.1.3", + "@luca/flag": "1.0.1", + "@std/": "0.218.2", + }); + const fs = new FileSystemFake(); + ReadTextFileStub.create(fs, { readThrough: true }); + WriteTextFileStub.create(fs); + Deno.Command = CommandStub.create("git"); +} diff --git a/cli/modules/write.ts b/cli/modules/write.ts new file mode 100644 index 00000000..808ed191 --- /dev/null +++ b/cli/modules/write.ts @@ -0,0 +1,12 @@ +import { relative } from "@std/path"; + +import { CollectResult, write } from "@molt/core"; + +export default async function ( + result: CollectResult, +): Promise { + console.log(); + await write(result, { + onWrite: (file) => console.log(`💾 ${relative(Deno.cwd(), file.path)}`), + }); +} diff --git a/core/deno.json b/core/deno.json new file mode 100644 index 00000000..ed3f6f58 --- /dev/null +++ b/core/deno.json @@ -0,0 +1,32 @@ +{ + "name": "@molt/core", + "version": "0.18.0", + "exports": { + ".": "./mod.ts" + }, + "publish": { + "exclude": [ + "*_test.ts" + ] + }, + "imports": { + "@core/unknownutil": "jsr:@core/unknownutil@^3.18.0", + "@lambdalisue/async": "jsr:@lambdalisue/async@^2.1.1", + "@molt/lib": "jsr:@molt/lib@^0.18.0", + "@std/assert": "jsr:@std/assert@^0.222.1", + "@std/collections": "jsr:@std/collections@^0.222.1", + "@std/fmt": "jsr:@std/fmt@^0.222.1", + "@std/fs": "jsr:@std/fs@^0.222.1", + "@std/jsonc": "jsr:@std/jsonc@^0.222.1", + "@std/path": "jsr:@std/path@^0.222.1", + "@std/semver": "jsr:@std/semver@^0.222.1", + "@std/testing": "jsr:@std/testing@^0.222.1", + "x/deno_graph": "./vendor/deno.land/x/deno_graph@0.69.6/mod.ts", + "x/import_map": "./vendor/deno.land/x/import_map@v0.19.1/mod.ts" + }, + "scopes": { + "./vendor/": { + "https://deno.land/": "./vendor/deno.land/" + } + } +} diff --git a/lib/dependency.ts b/core/dependency.ts similarity index 96% rename from lib/dependency.ts rename to core/dependency.ts index ded6c8bf..5527406a 100644 --- a/lib/dependency.ts +++ b/core/dependency.ts @@ -1,8 +1,8 @@ -import { filterEntries } from "./std/collections.ts"; -import { assertExists } from "./std/assert.ts"; -import * as SemVer from "./std/semver.ts"; -import { Mutex } from "./x/async.ts"; -import { ensure, is } from "./x/unknownutil.ts"; +import { filterEntries } from "@std/collections"; +import { assertExists } from "@std/assert"; +import * as SemVer from "@std/semver"; +import { Mutex } from "@lambdalisue/async"; +import { ensure, is } from "@core/unknownutil"; /** * Properties of a dependency parsed from an import specifier. @@ -250,6 +250,9 @@ async function _resolveLatestVersion( ([version, { yanked }]) => !yanked && !isPreRelease(version), ); const semvers = Object.keys(candidates).map(SemVer.parse); + if (!semvers.length) { + break; + } const latest = SemVer.format(semvers.sort(SemVer.compare).reverse()[0]); if (isPreRelease(latest)) { break; diff --git a/lib/dependency_test.ts b/core/dependency_test.ts similarity index 96% rename from lib/dependency_test.ts rename to core/dependency_test.ts index a05fce34..ad7751d2 100644 --- a/lib/dependency_test.ts +++ b/core/dependency_test.ts @@ -1,7 +1,7 @@ -import { afterAll, beforeAll, describe, it } from "./std/testing.ts"; -import { assertEquals, assertExists, assertObjectMatch } from "./std/assert.ts"; +import { afterAll, beforeAll, describe, it } from "@std/testing/bdd"; +import { assertEquals, assertExists, assertObjectMatch } from "@std/assert"; +import { LatestVersionStub } from "@molt/lib/testing"; import { isPreRelease, parse, resolveLatestVersion } from "./dependency.ts"; -import { LatestVersionStub } from "./testing.ts"; describe("parse", () => { it("deno.land/std", () => diff --git a/lib/file.ts b/core/file.ts similarity index 95% rename from lib/file.ts rename to core/file.ts index 1d050f78..5293d647 100644 --- a/lib/file.ts +++ b/core/file.ts @@ -1,12 +1,16 @@ -import { assertEquals } from "./std/assert.ts"; -import { deepMerge, omit, partition } from "./std/collections.ts"; -import { detectEOL, EOL } from "./std/fs.ts"; +import { assertEquals } from "@std/assert"; +import { deepMerge, omit, partition } from "@std/collections"; +import { detect as detectEOL, EOL } from "@std/fs/eol"; import { stringify } from "./dependency.ts"; -import { createLockPart, LockPart, parseLockFileJson } from "./lockfile.ts"; import { - CollectResult, - DependencyUpdate, - SourceType, + createLockPart, + type LockPart, + parseLockFileJson, +} from "./lockfile.ts"; +import { + type CollectResult, + type DependencyUpdate, + type SourceType, sourceTypeOf, } from "./update.ts"; @@ -44,7 +48,7 @@ export interface WriteOptions { export function write( result: CollectResult, options: WriteOptions = {}, -) { +): Promise { return writeFileUpdate(associateByFile(result), options); } diff --git a/lib/file_test.ts b/core/file_test.ts similarity index 80% rename from lib/file_test.ts rename to core/file_test.ts index 9f38264a..700d611e 100644 --- a/lib/file_test.ts +++ b/core/file_test.ts @@ -1,16 +1,16 @@ -import { basename, dirname } from "./std/path.ts"; -import { formatEOL, LF } from "./std/fs.ts"; -import { assert, assertInstanceOf } from "./std/assert.ts"; -import { fromFileUrl } from "./std/path.ts"; -import { createAssertSnapshot } from "./std/testing.ts"; -import { collect, CollectResult } from "./update.ts"; -import { associateByFile, type FileUpdate, writeFileUpdate } from "./file.ts"; +import { basename, dirname } from "@std/path"; +import { format, LF } from "@std/fs/eol"; +import { assert, assertInstanceOf } from "@std/assert"; +import { fromFileUrl } from "@std/path"; +import { createAssertSnapshot } from "@std/testing/snapshot"; import { FileSystemFake, LatestVersionStub, ReadTextFileStub, WriteTextFileStub, -} from "./testing.ts"; +} from "@molt/lib/testing"; +import { associateByFile, type FileUpdate, writeFileUpdate } from "./file.ts"; +import { collect, type CollectResult } from "./update.ts"; function toName(path: string) { const base = basename(path); @@ -52,7 +52,7 @@ async function assertFileSystemSnapshot( ) { await assertSnapshot( t, - Array.from(fs.entries()).map(([, content]) => formatEOL(content, LF)), + Array.from(fs.entries()).map(([, content]) => format(content, LF)), ); } @@ -99,24 +99,24 @@ function test(path: string, name = toName(path)) { }); } -// Test the all cases in test/data +// Test the all cases in test/cases for await ( - const testCase of Deno.readDir(new URL("../test/data", import.meta.url)) + const testCase of Deno.readDir(new URL("../test/cases", import.meta.url)) ) { if (testCase.isFile && testCase.name.endsWith(".ts")) { - test(`../test/data/${testCase.name}`); + test(`../test/cases/${testCase.name}`); } if (testCase.isDirectory) { for await ( const entry of Deno.readDir( - new URL("../test/data/" + testCase.name, import.meta.url), + new URL("../test/cases/" + testCase.name, import.meta.url), ) ) { if ( entry.isFile && entry.name === "mod.ts" || entry.name.endsWith(".json") || entry.name.endsWith(".jsonc") ) { - test(`../test/data/${testCase.name}/${entry.name}`); + test(`../test/cases/${testCase.name}/${entry.name}`); } } } diff --git a/lib/git.ts b/core/git.ts similarity index 94% rename from lib/git.ts rename to core/git.ts index 600000bf..197408fd 100644 --- a/lib/git.ts +++ b/core/git.ts @@ -1,16 +1,16 @@ -import { distinct, mapN } from "./std/collections.ts"; -import { relative } from "./std/path.ts"; +import { distinct, mapNotNullish as mapN } from "@std/collections"; +import { relative } from "@std/path"; import { associateByFile, type FileUpdate, writeFileUpdate, - WriteOptions, + type WriteOptions, } from "./file.ts"; -import { LockPart } from "./lockfile.ts"; +import type { LockPart } from "./lockfile.ts"; import { - CollectResult, - DependencyUpdate, - SourceType, + type CollectResult, + type DependencyUpdate, + type SourceType, sourceTypeOf, } from "./update.ts"; @@ -66,7 +66,7 @@ const defaultCommitOptions = { export function commit( result: CollectResult, options?: CommitOptions, -) { +): Promise { return execute(createCommitSequence(result, { ...defaultCommitOptions, ...options, diff --git a/lib/git_test.ts b/core/git_test.ts similarity index 95% rename from lib/git_test.ts rename to core/git_test.ts index 3c3e7ba4..a3f63a23 100644 --- a/lib/git_test.ts +++ b/core/git_test.ts @@ -1,19 +1,16 @@ -import { - assertArrayIncludes, - assertEquals, - assertThrows, -} from "./std/assert.ts"; -import { assertSpyCall, describe, it } from "./std/testing.ts"; -import { basename, relative } from "./std/path.ts"; +import { assertArrayIncludes, assertEquals, assertThrows } from "@std/assert"; +import { describe, it } from "@std/testing/bdd"; +import { assertSpyCall } from "@std/testing/mock"; +import { basename, relative } from "@std/path"; +import { commit, getVersionChange } from "./git.ts"; +import { collect } from "./update.ts"; import { CommandStub, FileSystemFake, LatestVersionStub, ReadTextFileStub, WriteTextFileStub, -} from "./testing.ts"; -import { collect } from "./update.ts"; -import { commit, getVersionChange } from "./git.ts"; +} from "@molt/lib/testing"; //-------------------------------------------------------------------- // @@ -169,7 +166,7 @@ describe("getVersionChange", () => { //-------------------------------------------------------------------- Deno.test("commit", async (t) => { - const DIR = "test/data/multiple_modules"; + const DIR = "test/cases/multiple_modules"; const LATEST = "123.456.789"; LatestVersionStub.create(LATEST); diff --git a/lib/graph.ts b/core/graph.ts similarity index 95% rename from lib/graph.ts rename to core/graph.ts index e76a9014..4960c530 100644 --- a/lib/graph.ts +++ b/core/graph.ts @@ -1,9 +1,9 @@ import { createGraph, - CreateGraphOptions, + type CreateGraphOptions, init as initDenoGraph, load as defaultLoad, -} from "./x/deno_graph.ts"; +} from "x/deno_graph"; class DenoGraph { static #initialized = false; diff --git a/lib/import_map.ts b/core/import_map.ts similarity index 92% rename from lib/import_map.ts rename to core/import_map.ts index 1a4ca823..7fc2c930 100644 --- a/lib/import_map.ts +++ b/core/import_map.ts @@ -1,9 +1,9 @@ -import { assertEquals } from "./std/assert.ts"; -import { maxBy } from "./std/collections.ts"; -import { parse as parseJsonc } from "./std/jsonc.ts"; -import { type ImportMapJson, parseFromJson } from "./x/import_map.ts"; -import { ensure, is } from "./x/unknownutil.ts"; -import { toPath } from "./path.ts"; +import { assertEquals } from "@std/assert"; +import { maxBy } from "@std/collections"; +import { parse as parseJsonc } from "@std/jsonc"; +import { ensure, is } from "@core/unknownutil"; +import { toPath } from "@molt/lib/path"; +import { type ImportMapJson, parseFromJson } from "x/import_map"; export type { ImportMapJson }; diff --git a/lib/import_map_test.ts b/core/import_map_test.ts similarity index 71% rename from lib/import_map_test.ts rename to core/import_map_test.ts index 9ccafe85..c12e2104 100644 --- a/lib/import_map_test.ts +++ b/core/import_map_test.ts @@ -1,6 +1,6 @@ -import { assertEquals, assertExists, assertRejects } from "./std/assert.ts"; -import { fromFileUrl, toFileUrl } from "./std/path.ts"; -import { describe, it } from "./std/testing.ts"; +import { assertEquals, assertExists, assertRejects } from "@std/assert"; +import { fromFileUrl, toFileUrl } from "@std/path"; +import { describe, it } from "@std/testing/bdd"; import { readFromJson } from "./import_map.ts"; describe("readFromJson", () => { @@ -15,16 +15,16 @@ describe("readFromJson", () => { await Deno.remove(f); }); - it("test/data/import_map/deno.json", async () => { - const url = new URL("../test/data/import_map/deno.json", import.meta.url); + it("test/cases/import_map/deno.json", async () => { + const url = new URL("../test/cases/import_map/deno.json", import.meta.url); const importMap = await readFromJson(url); assertExists(importMap); assertEquals(importMap.path, fromFileUrl(url)); }); - it("test/data/import_map_referred/import_map.json", async () => { + it("test/cases/import_map_referred/import_map.json", async () => { const url = new URL( - "../test/data/import_map_referred/import_map.json", + "../test/cases/import_map_referred/import_map.json", import.meta.url, ); const importMap = await readFromJson(url); @@ -36,10 +36,13 @@ describe("readFromJson", () => { describe("resolve()", () => { it("resolve specifiers in import maps", async () => { const importMap = await readFromJson( - new URL("../test/data/import_map/deno.json", import.meta.url), + new URL("../test/cases/import_map/deno.json", import.meta.url), ); assertExists(importMap); - const referrer = new URL("../test/data/import_map/mod.ts", import.meta.url); + const referrer = new URL( + "../test/cases/import_map/mod.ts", + import.meta.url, + ); assertEquals( importMap.resolve("std/version.ts", referrer), { @@ -68,7 +71,7 @@ describe("resolve()", () => { importMap.resolve("/lib.ts", referrer), { resolved: - new URL("../test/data/import_map/lib.ts", import.meta.url).href, + new URL("../test/cases/import_map/lib.ts", import.meta.url).href, key: undefined, value: undefined, }, @@ -77,13 +80,13 @@ describe("resolve()", () => { it("do not resolve an url", async () => { const importMap = await readFromJson( new URL( - "../test/data/import_map_no_resolve/deno.json", + "../test/cases/import_map_no_resolve/deno.json", import.meta.url, ), ); assertExists(importMap); const referrer = new URL( - "../test/data/import_map_no_resolve/deps.ts", + "../test/cases/import_map_no_resolve/deps.ts", import.meta.url, ); assertEquals( @@ -97,13 +100,13 @@ describe("resolve()", () => { it("resolve specifiers in a referred import map", async () => { const importMap = await readFromJson( new URL( - "../test/data/import_map_referred/deno.json", + "../test/cases/import_map_referred/deno.json", import.meta.url, ), ); assertExists(importMap); const referrer = new URL( - "../test/data/import_map_referred/mod.ts", + "../test/cases/import_map_referred/mod.ts", import.meta.url, ); assertEquals( @@ -119,13 +122,13 @@ describe("resolve()", () => { Deno.test("resolveInner", async () => { const { resolveInner } = await readFromJson( - new URL("../test/data/import_map/deno.json", import.meta.url), + new URL("../test/cases/import_map/deno.json", import.meta.url), ); assertEquals( resolveInner( "/lib.ts", - new URL("../test/data/import_map/mod.ts", import.meta.url), + new URL("../test/cases/import_map/mod.ts", import.meta.url), ), - new URL("../test/data/import_map/lib.ts", import.meta.url).href, + new URL("../test/cases/import_map/lib.ts", import.meta.url).href, ); }); diff --git a/lib/lockfile.ts b/core/lockfile.ts similarity index 85% rename from lib/lockfile.ts rename to core/lockfile.ts index 9e66200c..6b62e784 100644 --- a/lib/lockfile.ts +++ b/core/lockfile.ts @@ -1,8 +1,33 @@ -import { parse, UpdatedDependency } from "./dependency.ts"; -import { toPath } from "./path.ts"; -import { distinctBy, mapN } from "./std/collections.ts"; -import { DependencyUpdate } from "./update.ts"; -import { ensure, is, PredicateType } from "./x/unknownutil.ts"; +import { parse, type UpdatedDependency } from "./dependency.ts"; +import { toPath } from "@molt/lib/path"; +import { distinctBy, mapNotNullish as mapN } from "@std/collections"; +import type { DependencyUpdate } from "./update.ts"; +import { ensure, is } from "@core/unknownutil"; + +// We can't use unknowntuil's `PredicateType` because it results in a +// 'slow type' for `deno publish`, unfortunately. +export interface LockFileJson { + version: string; + packages?: { + specifiers: Record; + jsr?: Record; + npm?: Record; + }; + remote?: Record; + workspace?: { + dependencies?: string[]; + }; +} + +interface JsrEntry { + integrity: string; + dependencies?: string[]; +} + +interface NpmEntry { + integrity: string; + dependencies: Record; +} const isLockFileJson = is.ObjectOf({ version: is.String, @@ -44,7 +69,6 @@ const isLockFileJson = is.ObjectOf({ * }, * } */ -export type LockFileJson = PredicateType; /** An object representing a lockfile. */ export interface LockFile { @@ -139,7 +163,14 @@ export async function createLockPart( // Create a lockfile for the dummy module. await using lock = await createTempFile(); const { code, stderr } = await new Deno.Command("deno", { - args: ["cache", "--lock-write", "--lock", lock.path, mod.path], + args: [ + "cache", + "--no-config", + "--lock-write", + "--lock", + lock.path, + mod.path, + ], }).output(); if (code !== 0) { throw new CommandError(new TextDecoder().decode(stderr)); diff --git a/lib/lockfile_test.ts b/core/lockfile_test.ts similarity index 91% rename from lib/lockfile_test.ts rename to core/lockfile_test.ts index 477b96e1..ec638c00 100644 --- a/lib/lockfile_test.ts +++ b/core/lockfile_test.ts @@ -5,13 +5,13 @@ import { parseLockFileJson, readLockFile, } from "./lockfile.ts"; -import { assertEquals, assertObjectMatch } from "./std/assert.ts"; +import { assertEquals, assertObjectMatch } from "@std/assert"; Deno.test("parseLockFileJson", async () => assertObjectMatch( parseLockFileJson( await Deno.readTextFile( - new URL("../test/data/lockfile/deno.updated.lock", import.meta.url), + new URL("../test/cases/lockfile/deno.updated.lock", import.meta.url), ), ), { @@ -58,7 +58,7 @@ Deno.test("createLockPart - npm:hono", async () => { Deno.test("createLockPartForEach", async () => { const updated = await createLockPartForEach( await readLockFile( - new URL("../test/data/lockfile/deno.lock", import.meta.url), + new URL("../test/cases/lockfile/deno.lock", import.meta.url), ), ); assertEquals(updated.length, 3); @@ -98,7 +98,7 @@ Deno.test("createLockPartForEach", async () => { Deno.test("createLockPartForEach - no updates", async () => { const updated = await createLockPartForEach( await readLockFile( - new URL("../test/data/lockfile/deno.lock", import.meta.url), + new URL("../test/cases/lockfile/deno.lock", import.meta.url), ), false, ); @@ -146,7 +146,7 @@ Deno.test("createLockPartForEach - no updates", async () => { Deno.test("collectUpdateFromLockFile", async () => { const updates = await collectUpdateFromLockFile( await readLockFile( - new URL("../test/data/lockfile/deno.lock", import.meta.url), + new URL("../test/cases/lockfile/deno.lock", import.meta.url), ), ); assertEquals(updates.length, 2); @@ -193,7 +193,7 @@ Deno.test("collectUpdateFromLockFile", async () => { Deno.test("collectUpdateFromLockFile - with a patch", async () => { const updates = await collectUpdateFromLockFile( await readLockFile( - new URL("../test/data/lockfile/deno.lock", import.meta.url), + new URL("../test/cases/lockfile/deno.lock", import.meta.url), ), await createLockPart("npm:hono@^3"), ); diff --git a/core/mod.ts b/core/mod.ts new file mode 100644 index 00000000..5c768501 --- /dev/null +++ b/core/mod.ts @@ -0,0 +1,63 @@ +// Copyright 2023 Shun Ueda. All rights reserved. MIT license. + +/** + * A module to bump version strings in import specifiers. + * + * ### Examples + * + * To update all dependencies in a module and write the changes to files: + * + * ```ts + * import { collect, write } from "jsr:@molt/core@{VERSION}"; + * + * const result = await collect("./mod.ts"); + * await write(result); + * ``` + * + * To update all dependencies in a module and commit the changes to local git repository: + * + * ```ts + * import { collect, commit } from "jsr:@molt/core@{VERSION}"; + * + * const result = await collect("./mod.ts"); + * + * await commit(result, { + * groupBy: (dependency) => dependency.name, + * composeCommitMessage: ({ group, version }) => + * `build(deps): bump ${group} to ${version!.to}`, + * }); + * ``` + * + * @module + */ + +export { + type Dependency, + parse, + resolveLatestVersion, + stringify, + type UpdatedDependency, +} from "./dependency.ts"; + +export { + associateByFile, + type FileUpdate, + write, + type WriteOptions, +} from "./file.ts"; + +export { + commit, + type CommitSequence, + createCommitSequence, + execute, + type GitCommit, +} from "./git.ts"; + +export { + collect, + type CollectOptions, + type CollectResult, + type DependencyUpdate, + type SourceType, +} from "./update.ts"; diff --git a/lib/update.ts b/core/update.ts similarity index 96% rename from lib/update.ts rename to core/update.ts index 80fbaa78..beb1bf33 100644 --- a/lib/update.ts +++ b/core/update.ts @@ -1,29 +1,29 @@ -import { assertExists } from "./std/assert.ts"; -import { partition } from "./std/collections.ts"; -import { exists } from "./std/fs.ts"; -import { ModuleJson } from "./x/deno_graph.ts"; +import { findFileUp, toPath, toUrl } from "@molt/lib/path"; +import { assertExists } from "@std/assert"; +import { partition } from "@std/collections"; +import { exists } from "@std/fs"; +import type { ModuleJson } from "x/deno_graph"; import { createGraphLocally } from "./graph.ts"; -import { findFileUp, toPath, toUrl } from "./path.ts"; import { - ImportMap, - ImportMapResolveResult, + type ImportMap, + type ImportMapResolveResult, readImportMapJson, tryReadFromJson, } from "./import_map.ts"; import { - Dependency, + type Dependency, hasVersionRange, parse, resolveLatestVersion, stringify, - UpdatedDependency, + type UpdatedDependency, } from "./dependency.ts"; import { collectUpdateFromLockFile, CommandError, createLockPart, - LockFile, - LockPart, + type LockFile, + type LockPart, readLockFile, } from "./lockfile.ts"; diff --git a/lib/update_test.ts b/core/update_test.ts similarity index 76% rename from lib/update_test.ts rename to core/update_test.ts index 9b881d7e..fd2225a1 100644 --- a/lib/update_test.ts +++ b/core/update_test.ts @@ -1,10 +1,10 @@ -import { dirname } from "./std/path.ts"; -import { assertEquals, assertInstanceOf } from "./std/assert.ts"; -import { filterKeys } from "./std/collections.ts"; -import { basename, fromFileUrl } from "./std/path.ts"; -import { createAssertSnapshot } from "./std/testing.ts"; -import { LatestVersionStub } from "./testing.ts"; -import { collect, DependencyUpdate } from "./update.ts"; +import { dirname } from "@std/path"; +import { assertEquals, assertInstanceOf } from "@std/assert"; +import { filterKeys } from "@std/collections/filter-keys"; +import { basename, fromFileUrl } from "@std/path"; +import { createAssertSnapshot } from "@std/testing/snapshot"; +import { LatestVersionStub } from "@molt/lib/testing"; +import { collect, type DependencyUpdate } from "./update.ts"; const assertSnapshot = createAssertSnapshot({ dir: fromFileUrl(new URL("../test/snapshots/", import.meta.url)), @@ -66,17 +66,17 @@ async function assertUpdateSnapshot( LatestVersionStub.create({ "deno.land/std": "0.218.0", _: "123.456.789" }); -// Test collect() for all cases in test/data +// Test collect() for all cases in test/cases for await ( - const testCase of Deno.readDir(new URL("../test/data", import.meta.url)) + const testCase of Deno.readDir(new URL("../test/cases", import.meta.url)) ) { if (testCase.isFile && testCase.name.endsWith(".ts")) { - test(`../test/data/${testCase.name}`); + test(`../test/cases/${testCase.name}`); } if (testCase.isDirectory) { for await ( const entry of Deno.readDir( - new URL("../test/data/" + testCase.name, import.meta.url), + new URL("../test/cases/" + testCase.name, import.meta.url), ) ) { if ( @@ -84,7 +84,7 @@ for await ( entry.name.endsWith(".json") || entry.name.endsWith(".jsonc") ) { test( - `../test/data/${testCase.name}/${entry.name}`, + `../test/cases/${testCase.name}/${entry.name}`, testCase.name, entry.name, ); diff --git a/deno.json b/deno.json index d2dd91e0..ce8f2175 100644 --- a/deno.json +++ b/deno.json @@ -1,14 +1,51 @@ { "tasks": { - "cache": "deno cache ./lib/*/*.ts --lock", - "lock": "deno task -q cache --lock-write && git add deno.lock", - "check": "deno check ./*.ts ./lib/*.ts ./test/integration/*.ts", - "test": "NO_COLOR=1 deno test -A --no-check", + "cache": "deno cache ./lib/*.ts ./core/*.ts ./cli/**/*.ts --lock", + "lock": "deno task -q cache --lock-write", + "check": "deno check ./*.ts ./lib/*.ts ./core/*.ts ./integration/*.ts ./cli/**/*.ts", + "test": "NO_COLOR=1 deno test -A --unstable-kv --no-check", + "test:unit": "deno task -q test ./lib ./core", + "test:integration": "deno task -q test --no-lock ./integration ./cli", "pre-commit": "deno fmt && deno lint && deno task -q check && deno task lock && deno task -q test", - "integration": "deno task -q test --no-lock ./test/integration/*.ts", - "run": "deno run --allow-env --allow-read --allow-net --allow-write=. --allow-run=git,deno cli.ts", - "update": "deno run --allow-env --allow-read --allow-write --allow-net=deno.land,registry.npmjs.org --allow-run=git,deno ./cli.ts ./lib/*/*.ts --unstable-lock", - "update:commit": "deno task -q update --commit --prefix 'build(deps):' --prefix-lock 'build(lock)'" + "run": "deno run -A --unstable-kv --config ./deno.json ./cli/main.ts", + "install": "deno install -Afg --config ./deno.json --name molt ./cli/main.ts", + "update": "deno run --unstable-kv --config ./deno.json --allow-env --allow-read --allow-write --allow-net=deno.land,jsr.io,registry.npmjs.org --allow-run=git,deno ./cli/main.ts ./deno.json --changelog --unstable-lock", + "update:commit": "deno task -q update --commit --prefix 'build(deps):' --prefix-lock 'build(lock)'", + "vendor": "deno vendor --no-config https://deno.land/x/deno_graph/mod.ts https://deno.land/x/import_map/mod.ts" + }, + "imports": { + "@cliffy/ansi": "jsr:@cliffy/ansi@1.0.0-rc.4", + "@cliffy/command": "jsr:@cliffy/command@1.0.0-rc.4", + "@conventional-commits/parser": "npm:@conventional-commits/parser@^0.4.1", + "@core/unknownutil": "jsr:@core/unknownutil@^3.18.0", + "@core/match": "jsr:@core/match@^0.2.5", + "@david/dax": "jsr:@david/dax@^0.40.0", + "@lambdalisue/async": "jsr:@lambdalisue/async@^2.1.1", + "@octokit/rest": "npm:@octokit/rest@^20.1.0", + "@std/assert": "jsr:@std/assert@^0.222.1", + "@std/collections": "jsr:@std/collections@^0.222.1", + "@std/dotenv": "jsr:@std/dotenv@^0.222.1", + "@std/fmt": "jsr:@std/fmt@^0.222.1", + "@std/fs": "jsr:@std/fs@^0.222.1", + "@std/jsonc": "jsr:@std/jsonc@^0.222.1", + "@std/path": "jsr:@std/path@^0.222.1", + "@std/semver": "jsr:@std/semver@^0.222.1", + "@std/testing": "jsr:@std/testing@^0.222.1", + "x/deno_graph": "https://deno.land/x/deno_graph@0.69.6/mod.ts", + "x/import_map": "https://deno.land/x/import_map@v0.19.1/mod.ts" + }, + "scopes": { + ".": { + "@molt/core": "./core/mod.ts", + "@molt/lib/path": "./lib/path.ts", + "@molt/lib/testing": "./lib/testing.ts", + "@molt/lib/changelog": "./lib/changelog.ts", + "@molt/integration": "./integration/mod.ts", + "@molt/integration/commits": "./integration/commits.ts", + "@molt/integration/github": "./integration/github.ts", + "@molt/integration/packages": "./integration/packages.ts", + "@molt/integration/repository": "./integration/repository.ts" + } }, "fmt": { "exclude": [ @@ -17,7 +54,7 @@ }, "lint": { "exclude": [ - "test/data", + "test/cases", "test/snapshots" ], "rules": { diff --git a/deno.lock b/deno.lock index cced2d3d..fec8606b 100644 --- a/deno.lock +++ b/deno.lock @@ -1,297 +1,348 @@ { "version": "3", + "packages": { + "specifiers": { + "jsr:@cliffy/ansi@1.0.0-rc.4": "jsr:@cliffy/ansi@1.0.0-rc.4", + "jsr:@cliffy/command@1.0.0-rc.4": "jsr:@cliffy/command@1.0.0-rc.4", + "jsr:@cliffy/flags@1.0.0-rc.4": "jsr:@cliffy/flags@1.0.0-rc.4", + "jsr:@cliffy/table@1.0.0-rc.4": "jsr:@cliffy/table@1.0.0-rc.4", + "jsr:@core/match@^0.2.5": "jsr:@core/match@0.2.5", + "jsr:@core/unknownutil@^3.18.0": "jsr:@core/unknownutil@3.18.0", + "jsr:@david/dax@^0.40.0": "jsr:@david/dax@0.40.0", + "jsr:@david/which@0.3": "jsr:@david/which@0.3.0", + "jsr:@lambdalisue/async@^2.1.1": "jsr:@lambdalisue/async@2.1.1", + "jsr:@std/assert@^0.221.0": "jsr:@std/assert@0.221.0", + "jsr:@std/assert@^0.222.1": "jsr:@std/assert@0.222.1", + "jsr:@std/bytes@^0.221.0": "jsr:@std/bytes@0.221.0", + "jsr:@std/collections@^0.222.1": "jsr:@std/collections@0.222.1", + "jsr:@std/console@0.221": "jsr:@std/console@0.221.0", + "jsr:@std/dotenv@^0.222.1": "jsr:@std/dotenv@0.222.1", + "jsr:@std/encoding@0.221": "jsr:@std/encoding@0.221.0", + "jsr:@std/fmt@0.221": "jsr:@std/fmt@0.221.0", + "jsr:@std/fmt@^0.221.0": "jsr:@std/fmt@0.221.0", + "jsr:@std/fmt@^0.222.1": "jsr:@std/fmt@0.222.1", + "jsr:@std/fs@0.221.0": "jsr:@std/fs@0.221.0", + "jsr:@std/fs@^0.222.1": "jsr:@std/fs@0.222.1", + "jsr:@std/io@0.221": "jsr:@std/io@0.221.0", + "jsr:@std/io@0.221.0": "jsr:@std/io@0.221.0", + "jsr:@std/io@^0.221.0": "jsr:@std/io@0.221.0", + "jsr:@std/json@^0.222.1": "jsr:@std/json@0.222.1", + "jsr:@std/jsonc@^0.222.1": "jsr:@std/jsonc@0.222.1", + "jsr:@std/path@0.221.0": "jsr:@std/path@0.221.0", + "jsr:@std/path@^0.221.0": "jsr:@std/path@0.221.0", + "jsr:@std/path@^0.222.1": "jsr:@std/path@0.222.1", + "jsr:@std/semver@^0.222.1": "jsr:@std/semver@0.222.1", + "jsr:@std/streams@0.221.0": "jsr:@std/streams@0.221.0", + "jsr:@std/testing@^0.222.1": "jsr:@std/testing@0.222.1", + "jsr:@std/text@0.221": "jsr:@std/text@0.221.0", + "npm:@conventional-commits/parser@^0.4.1": "npm:@conventional-commits/parser@0.4.1", + "npm:@octokit/rest@^20.1.0": "npm:@octokit/rest@20.1.0_@octokit+core@5.2.0", + "npm:ts-toolbelt@9.6.0": "npm:ts-toolbelt@9.6.0" + }, + "jsr": { + "@cliffy/ansi@1.0.0-rc.4": { + "integrity": "df561b6a69bb5177c31618c027274504ed24b996b854fa072eb7d0a380e41ac1", + "dependencies": [ + "jsr:@std/encoding@0.221", + "jsr:@std/fmt@0.221", + "jsr:@std/io@0.221" + ] + }, + "@cliffy/command@1.0.0-rc.4": { + "integrity": "709884ffe0f53ce3edafa92b58223634397878fbf6dcabe0c74ea0108273b9f7", + "dependencies": [ + "jsr:@cliffy/flags@1.0.0-rc.4", + "jsr:@cliffy/table@1.0.0-rc.4", + "jsr:@std/fmt@0.221", + "jsr:@std/text@0.221" + ] + }, + "@cliffy/flags@1.0.0-rc.4": { + "integrity": "29f370ade4ddf6e150a4d25fc44661234c19870ffcf7fb07cd100f1843fcd6e1" + }, + "@cliffy/table@1.0.0-rc.4": { + "integrity": "990e4e0b3910e6c9cf7a5b4318b8f5e121cf681494c94fd113febb9b4d4c0741", + "dependencies": [ + "jsr:@std/console@0.221" + ] + }, + "@core/match@0.2.5": { + "integrity": "55f38d482ce845958883571e543afa9da2eb89f6fe1825f38764bbd0e7585594", + "dependencies": [ + "npm:ts-toolbelt@9.6.0" + ] + }, + "@core/unknownutil@3.18.0": { + "integrity": "bff7ab4a2f554bbade301127519523b0d3baa4273ecbed51287133ac00a48738" + }, + "@david/dax@0.40.0": { + "integrity": "1e0534a437e1d6c915979f19a3d048e5e2ce2a91176555a0ea1e89d929187279", + "dependencies": [ + "jsr:@david/which@0.3", + "jsr:@std/fmt@^0.221.0", + "jsr:@std/fs@0.221.0", + "jsr:@std/io@0.221.0", + "jsr:@std/path@0.221.0", + "jsr:@std/streams@0.221.0" + ] + }, + "@david/which@0.3.0": { + "integrity": "6bdb62c40ac90edcf328e854fa8103a8db21e7c326089cbe3c3a1cf7887d3204" + }, + "@lambdalisue/async@2.1.1": { + "integrity": "1fc9bc6f4ed50215cd2f7217842b18cea80f81c25744f88f8c5eb4be5a1c9ab4" + }, + "@std/assert@0.221.0": { + "integrity": "a5f1aa6e7909dbea271754fd4ab3f4e687aeff4873b4cef9a320af813adb489a" + }, + "@std/assert@0.222.1": { + "integrity": "691637161ee584a9919d1f9950ddd1272feb8e0a19e83aa5b7563cedaf73d74c" + }, + "@std/bytes@0.221.0": { + "integrity": "64a047011cf833890a4a2ab7293ac55a1b4f5a050624ebc6a0159c357de91966" + }, + "@std/collections@0.222.1": { + "integrity": "234099e08eead6a87e59f4f1abdcba35df5503cfb0e852e77a19f79359ed5760" + }, + "@std/console@0.221.0": { + "integrity": "8f2afc1f3f14f5d6039c0c767f057e4aa1897d2210e167c4667cb155cafb9d11" + }, + "@std/dotenv@0.222.1": { + "integrity": "61c75269cfd569033d580d9341597eb1cd4b2796323c5823033bb6d60c66d619" + }, + "@std/encoding@0.221.0": { + "integrity": "d1dd76ef0dc5d14088411e6dc1dede53bf8308c95d1537df1214c97137208e45" + }, + "@std/fmt@0.221.0": { + "integrity": "379fed69bdd9731110f26b9085aeb740606b20428ce6af31ef6bd45ef8efa62a" + }, + "@std/fmt@0.222.1": { + "integrity": "ec3382f9b0261c1ab1a5c804aa355d816515fa984cdd827ed32edfb187c0a722" + }, + "@std/fs@0.221.0": { + "integrity": "028044450299de8ed5a716ade4e6d524399f035513b85913794f4e81f07da286", + "dependencies": [ + "jsr:@std/assert@^0.221.0", + "jsr:@std/path@^0.221.0" + ] + }, + "@std/fs@0.222.1": { + "integrity": "337613f33e6e5970dddb263c3a3e5b8e39c97810ad6fe326cb9f65146af2503b", + "dependencies": [ + "jsr:@std/assert@^0.222.1", + "jsr:@std/path@^0.222.1" + ] + }, + "@std/io@0.221.0": { + "integrity": "faf7f8700d46ab527fa05cc6167f4b97701a06c413024431c6b4d207caa010da", + "dependencies": [ + "jsr:@std/assert@^0.221.0", + "jsr:@std/bytes@^0.221.0" + ] + }, + "@std/json@0.222.1": { + "integrity": "ce4fb420dfd818fc2569289217842a3e70f249279f038a5e266f7b6572a2829a" + }, + "@std/jsonc@0.222.1": { + "integrity": "5d82d64eeb244e88fbb0927587dea7e1feccc6d5d9f49995b9ff5756d01be493", + "dependencies": [ + "jsr:@std/assert@^0.222.1", + "jsr:@std/json@^0.222.1" + ] + }, + "@std/path@0.221.0": { + "integrity": "0a36f6b17314ef653a3a1649740cc8db51b25a133ecfe838f20b79a56ebe0095", + "dependencies": [ + "jsr:@std/assert@^0.221.0" + ] + }, + "@std/path@0.222.1": { + "integrity": "aad3e9463ca53b0adb25b4d5beb330025674aaa3278da24c1c261d9289a9e48b", + "dependencies": [ + "jsr:@std/assert@^0.222.1" + ] + }, + "@std/semver@0.222.1": { + "integrity": "43c5b526423f48f6f75375c77226646803776fdc678b331f243b0bd667d54c18" + }, + "@std/streams@0.221.0": { + "integrity": "47f2f74634b47449277c0ee79fe878da4424b66bd8975c032e3afdca88986e61", + "dependencies": [ + "jsr:@std/io@^0.221.0" + ] + }, + "@std/testing@0.222.1": { + "integrity": "7be5c3ef185d31883116824a2dd604eb6f12a56fd5ed80489c7c696b2a76c5bc", + "dependencies": [ + "jsr:@std/assert@^0.222.1", + "jsr:@std/fs@^0.222.1", + "jsr:@std/path@^0.222.1" + ] + }, + "@std/text@0.221.0": { + "integrity": "a2f89ceb0d8851cd33e6774064621a1da9fbc36578cf4f02c5b5bcd7e8c84b67", + "dependencies": [ + "jsr:@std/assert@^0.221.0" + ] + } + }, + "npm": { + "@conventional-commits/parser@0.4.1": { + "integrity": "sha512-H2ZmUVt6q+KBccXfMBhbBF14NlANeqHTXL4qCL6QGbMzrc4HDXyzWuxPxPNbz71f/5UkR5DrycP5VO9u7crahg==", + "dependencies": { + "unist-util-visit": "unist-util-visit@2.0.3", + "unist-util-visit-parents": "unist-util-visit-parents@3.1.1" + } + }, + "@octokit/auth-token@4.0.0": { + "integrity": "sha512-tY/msAuJo6ARbK6SPIxZrPBms3xPbfwBrulZe0Wtr/DIY9lje2HeV1uoebShn6mx7SjCHif6EjMvoREj+gZ+SA==", + "dependencies": {} + }, + "@octokit/core@5.2.0": { + "integrity": "sha512-1LFfa/qnMQvEOAdzlQymH0ulepxbxnCYAKJZfMci/5XJyIHWgEYnDmgnKakbTh7CH2tFQ5O60oYDvns4i9RAIg==", + "dependencies": { + "@octokit/auth-token": "@octokit/auth-token@4.0.0", + "@octokit/graphql": "@octokit/graphql@7.1.0", + "@octokit/request": "@octokit/request@8.4.0", + "@octokit/request-error": "@octokit/request-error@5.1.0", + "@octokit/types": "@octokit/types@13.4.1", + "before-after-hook": "before-after-hook@2.2.3", + "universal-user-agent": "universal-user-agent@6.0.1" + } + }, + "@octokit/endpoint@9.0.5": { + "integrity": "sha512-ekqR4/+PCLkEBF6qgj8WqJfvDq65RH85OAgrtnVp1mSxaXF03u2xW/hUdweGS5654IlC0wkNYC18Z50tSYTAFw==", + "dependencies": { + "@octokit/types": "@octokit/types@13.4.1", + "universal-user-agent": "universal-user-agent@6.0.1" + } + }, + "@octokit/graphql@7.1.0": { + "integrity": "sha512-r+oZUH7aMFui1ypZnAvZmn0KSqAUgE1/tUXIWaqUCa1758ts/Jio84GZuzsvUkme98kv0WFY8//n0J1Z+vsIsQ==", + "dependencies": { + "@octokit/request": "@octokit/request@8.4.0", + "@octokit/types": "@octokit/types@13.4.1", + "universal-user-agent": "universal-user-agent@6.0.1" + } + }, + "@octokit/openapi-types@20.0.0": { + "integrity": "sha512-EtqRBEjp1dL/15V7WiX5LJMIxxkdiGJnabzYx5Apx4FkQIFgAfKumXeYAqqJCj1s+BMX4cPFIFC4OLCR6stlnA==", + "dependencies": {} + }, + "@octokit/openapi-types@22.1.0": { + "integrity": "sha512-pGUdSP+eEPfZiQHNkZI0U01HLipxncisdJQB4G//OAmfeO8sqTQ9KRa0KF03TUPCziNsoXUrTg4B2Q1EX++T0Q==", + "dependencies": {} + }, + "@octokit/plugin-paginate-rest@9.2.1_@octokit+core@5.2.0": { + "integrity": "sha512-wfGhE/TAkXZRLjksFXuDZdmGnJQHvtU/joFQdweXUgzo1XwvBCD4o4+75NtFfjfLK5IwLf9vHTfSiU3sLRYpRw==", + "dependencies": { + "@octokit/core": "@octokit/core@5.2.0", + "@octokit/types": "@octokit/types@12.6.0" + } + }, + "@octokit/plugin-request-log@4.0.1_@octokit+core@5.2.0": { + "integrity": "sha512-GihNqNpGHorUrO7Qa9JbAl0dbLnqJVrV8OXe2Zm5/Y4wFkZQDfTreBzVmiRfJVfE4mClXdihHnbpyyO9FSX4HA==", + "dependencies": { + "@octokit/core": "@octokit/core@5.2.0" + } + }, + "@octokit/plugin-rest-endpoint-methods@10.4.1_@octokit+core@5.2.0": { + "integrity": "sha512-xV1b+ceKV9KytQe3zCVqjg+8GTGfDYwaT1ATU5isiUyVtlVAO3HNdzpS4sr4GBx4hxQ46s7ITtZrAsxG22+rVg==", + "dependencies": { + "@octokit/core": "@octokit/core@5.2.0", + "@octokit/types": "@octokit/types@12.6.0" + } + }, + "@octokit/request-error@5.1.0": { + "integrity": "sha512-GETXfE05J0+7H2STzekpKObFe765O5dlAKUTLNGeH+x47z7JjXHfsHKo5z21D/o/IOZTUEI6nyWyR+bZVP/n5Q==", + "dependencies": { + "@octokit/types": "@octokit/types@13.4.1", + "deprecation": "deprecation@2.3.1", + "once": "once@1.4.0" + } + }, + "@octokit/request@8.4.0": { + "integrity": "sha512-9Bb014e+m2TgBeEJGEbdplMVWwPmL1FPtggHQRkV+WVsMggPtEkLKPlcVYm/o8xKLkpJ7B+6N8WfQMtDLX2Dpw==", + "dependencies": { + "@octokit/endpoint": "@octokit/endpoint@9.0.5", + "@octokit/request-error": "@octokit/request-error@5.1.0", + "@octokit/types": "@octokit/types@13.4.1", + "universal-user-agent": "universal-user-agent@6.0.1" + } + }, + "@octokit/rest@20.1.0_@octokit+core@5.2.0": { + "integrity": "sha512-STVO3itHQLrp80lvcYB2UIKoeil5Ctsgd2s1AM+du3HqZIR35ZH7WE9HLwUOLXH0myA0y3AGNPo8gZtcgIbw0g==", + "dependencies": { + "@octokit/core": "@octokit/core@5.2.0", + "@octokit/plugin-paginate-rest": "@octokit/plugin-paginate-rest@9.2.1_@octokit+core@5.2.0", + "@octokit/plugin-request-log": "@octokit/plugin-request-log@4.0.1_@octokit+core@5.2.0", + "@octokit/plugin-rest-endpoint-methods": "@octokit/plugin-rest-endpoint-methods@10.4.1_@octokit+core@5.2.0" + } + }, + "@octokit/types@12.6.0": { + "integrity": "sha512-1rhSOfRa6H9w4YwK0yrf5faDaDTb+yLyBUKOCV4xtCDB5VmIPqd/v9yr9o6SAzOAlRxMiRiCic6JVM1/kunVkw==", + "dependencies": { + "@octokit/openapi-types": "@octokit/openapi-types@20.0.0" + } + }, + "@octokit/types@13.4.1": { + "integrity": "sha512-Y73oOAzRBAUzR/iRAbGULzpNkX8vaxKCqEtg6K74Ff3w9f5apFnWtE/2nade7dMWWW3bS5Kkd6DJS4HF04xreg==", + "dependencies": { + "@octokit/openapi-types": "@octokit/openapi-types@22.1.0" + } + }, + "@types/unist@2.0.10": { + "integrity": "sha512-IfYcSBWE3hLpBg8+X2SEa8LVkJdJEkT2Ese2aaLs3ptGdVtABxndrMaxuFlQ1qdFf9Q5rDvDpxI3WwgvKFAsQA==", + "dependencies": {} + }, + "before-after-hook@2.2.3": { + "integrity": "sha512-NzUnlZexiaH/46WDhANlyR2bXRopNg4F/zuSA3OpZnllCUgRaOF2znDioDWrmbNVsuZk6l9pMquQB38cfBZwkQ==", + "dependencies": {} + }, + "deprecation@2.3.1": { + "integrity": "sha512-xmHIy4F3scKVwMsQ4WnVaS8bHOx0DmVwRywosKhaILI0ywMDWPtBSku2HNxRvF7jtwDRsoEwYQSfbxj8b7RlJQ==", + "dependencies": {} + }, + "once@1.4.0": { + "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", + "dependencies": { + "wrappy": "wrappy@1.0.2" + } + }, + "ts-toolbelt@9.6.0": { + "integrity": "sha512-nsZd8ZeNUzukXPlJmTBwUAuABDe/9qtVDelJeT/qW0ow3ZS3BsQJtNkan1802aM9Uf68/Y8ljw86Hu0h5IUW3w==", + "dependencies": {} + }, + "unist-util-is@4.1.0": { + "integrity": "sha512-ZOQSsnce92GrxSqlnEEseX0gi7GH9zTJZ0p9dtu87WRb/37mMPO2Ilx1s/t9vBHrFhbgweUwb+t7cIn5dxPhZg==", + "dependencies": {} + }, + "unist-util-visit-parents@3.1.1": { + "integrity": "sha512-1KROIZWo6bcMrZEwiH2UrXDyalAa0uqzWCxCJj6lPOvTve2WkfgCytoDTPaMnodXh1WrXOq0haVYHj99ynJlsg==", + "dependencies": { + "@types/unist": "@types/unist@2.0.10", + "unist-util-is": "unist-util-is@4.1.0" + } + }, + "unist-util-visit@2.0.3": { + "integrity": "sha512-iJ4/RczbJMkD0712mGktuGpm/U4By4FfDonL7N/9tATGIF4imikjOuagyMY53tnZq3NP6BcmlrHhEKAfGWjh7Q==", + "dependencies": { + "@types/unist": "@types/unist@2.0.10", + "unist-util-is": "unist-util-is@4.1.0", + "unist-util-visit-parents": "unist-util-visit-parents@3.1.1" + } + }, + "universal-user-agent@6.0.1": { + "integrity": "sha512-yCzhz6FN2wU1NiiQRogkTQszlQSlpWaw8SvVegAc+bDxbzHgh1vX8uIe8OYyMH6DwH+sdTJsgMl36+mSMdRJIQ==", + "dependencies": {} + }, + "wrappy@1.0.2": { + "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", + "dependencies": {} + } + } + }, "remote": { - "https://deno.land/std@0.196.0/assert/assert.ts": "9a97dad6d98c238938e7540736b826440ad8c1c1e54430ca4c4e623e585607ee", - "https://deno.land/std@0.196.0/assert/assertion_error.ts": "4d0bde9b374dfbcbe8ac23f54f567b77024fb67dbb1906a852d67fe050d42f56", - "https://deno.land/std@0.196.0/console/_data.json": "cf2cc9d039a192b3adbfe64627167c7e6212704c888c25c769fc8f1709e1e1b8", - "https://deno.land/std@0.196.0/console/_rle.ts": "56668d5c44f964f1b4ff93f21c9896df42d6ee4394e814db52d6d13f5bb247c7", - "https://deno.land/std@0.196.0/console/unicode_width.ts": "10661c0f2eeab802d16b8b85ed8825bbc573991bbfb6affed32dc1ff994f54f9", - "https://deno.land/std@0.196.0/fmt/colors.ts": "a7eecffdf3d1d54db890723b303847b6e0a1ab4b528ba6958b8f2e754cf1b3bc", - "https://deno.land/std@0.213.0/assert/assert.ts": "bec068b2fccdd434c138a555b19a2c2393b71dfaada02b7d568a01541e67cdc5", - "https://deno.land/std@0.213.0/assert/assertion_error.ts": "9f689a101ee586c4ce92f52fa7ddd362e86434ffdf1f848e45987dc7689976b8", - "https://deno.land/std@0.213.0/bytes/concat.ts": "9cac3b4376afbef98ff03588eb3cf948e0d1eb6c27cfe81a7651ab6dd3adc54a", - "https://deno.land/std@0.213.0/bytes/copy.ts": "f29c03168853720dfe82eaa57793d0b9e3543ebfe5306684182f0f1e3bfd422a", - "https://deno.land/std@0.213.0/fmt/colors.ts": "aeaee795471b56fc62a3cb2e174ed33e91551b535f44677f6320336aabb54fbb", - "https://deno.land/std@0.213.0/fs/_create_walk_entry.ts": "5d9d2aaec05bcf09a06748b1684224d33eba7a4de24cf4cf5599991ca6b5b412", - "https://deno.land/std@0.213.0/fs/_get_file_info_type.ts": "da7bec18a7661dba360a1db475b826b18977582ce6fc9b25f3d4ee0403fe8cbd", - "https://deno.land/std@0.213.0/fs/_is_same_path.ts": "709c95868345fea051c58b9e96af95cff94e6ae98dfcff2b66dee0c212c4221f", - "https://deno.land/std@0.213.0/fs/_is_subdir.ts": "c68b309d46cc8568ed83c000f608a61bbdba0943b7524e7a30f9e450cf67eecd", - "https://deno.land/std@0.213.0/fs/_to_path_string.ts": "29bfc9c6c112254961d75cbf6ba814d6de5349767818eb93090cecfa9665591e", - "https://deno.land/std@0.213.0/fs/copy.ts": "dc0f68c4b6c3b090bfdb909387e309f6169b746bd713927c9507c9ef545d71f6", - "https://deno.land/std@0.213.0/fs/empty_dir.ts": "4f01e6d56e2aa8d90ad60f20bc25601f516b00f6c3044cdf6863a058791d91aa", - "https://deno.land/std@0.213.0/fs/ensure_dir.ts": "dffff68de0d10799b5aa9e39dec4e327e12bbd29e762292193684542648c4aeb", - "https://deno.land/std@0.213.0/fs/ensure_file.ts": "ac5cfde94786b0284d2c8e9f7f9425269bea1b2140612b4aea1f20b508870f59", - "https://deno.land/std@0.213.0/fs/ensure_link.ts": "d42af2edefeaa9817873ec6e46dc5d209ac4d744f8c69c5ecc2dffade78465b6", - "https://deno.land/std@0.213.0/fs/ensure_symlink.ts": "aee3f1655700f60090b4a3037f5b6c07ab37c36807cccad746ce89987719e6d2", - "https://deno.land/std@0.213.0/fs/eol.ts": "c9807291f78361d49fd986a9be04654610c615c5e2ec63d748976197d30ff206", - "https://deno.land/std@0.213.0/fs/exists.ts": "d2757ef764eaf5c6c5af7228e8447db2de42ab084a2dae540097f905723d83f5", - "https://deno.land/std@0.213.0/fs/expand_glob.ts": "a64e4ab51f62780f764789c9cdeacc862d221e35207fb81170a980ccc22868e3", - "https://deno.land/std@0.213.0/fs/mod.ts": "107f5afa4424c2d3ce2f7e9266173198da30302c69af662c720115fe504dc5ee", - "https://deno.land/std@0.213.0/fs/move.ts": "39e0d7ccb88a566d20b949712020e766b15ef1ec19159573d11f949bd677909c", - "https://deno.land/std@0.213.0/fs/walk.ts": "f04cc83ad3b27b5a5d078c831a01c7406069474bf280d5db015d937149a60128", - "https://deno.land/std@0.213.0/io/_constants.ts": "3c7ad4695832e6e4a32e35f218c70376b62bc78621ef069a4a0a3d55739f8856", - "https://deno.land/std@0.213.0/io/buf_reader.ts": "ccbd43ace0a9eebbd5e1b4765724b79da79d1e28b90c2b08537b99192da4a1f7", - "https://deno.land/std@0.213.0/io/buffer.ts": "79182995c8340ece2fa8763a8da86d282c507e854921d0a4c2ba7425c63609ef", - "https://deno.land/std@0.213.0/io/read_all.ts": "876c1cb20adea15349c72afc86cecd3573335845ae778967aefb5e55fe5a8a4a", - "https://deno.land/std@0.213.0/io/types.ts": "748bbb3ac96abda03594ef5a0db15ce5450dcc6c0d841c8906f8b10ac8d32c96", - "https://deno.land/std@0.213.0/io/write_all.ts": "24aac2312bb21096ae3ae0b102b22c26164d3249dff96dbac130958aa736f038", - "https://deno.land/std@0.213.0/path/_common/assert_path.ts": "2ca275f36ac1788b2acb60fb2b79cb06027198bc2ba6fb7e163efaedde98c297", - "https://deno.land/std@0.213.0/path/_common/basename.ts": "569744855bc8445f3a56087fd2aed56bdad39da971a8d92b138c9913aecc5fa2", - "https://deno.land/std@0.213.0/path/_common/common.ts": "6157c7ec1f4db2b4a9a187efd6ce76dcaf1e61cfd49f87e40d4ea102818df031", - "https://deno.land/std@0.213.0/path/_common/constants.ts": "dc5f8057159f4b48cd304eb3027e42f1148cf4df1fb4240774d3492b5d12ac0c", - "https://deno.land/std@0.213.0/path/_common/dirname.ts": "684df4aa71a04bbcc346c692c8485594fc8a90b9408dfbc26ff32cf3e0c98cc8", - "https://deno.land/std@0.213.0/path/_common/format.ts": "92500e91ea5de21c97f5fe91e178bae62af524b72d5fcd246d6d60ae4bcada8b", - "https://deno.land/std@0.213.0/path/_common/from_file_url.ts": "d672bdeebc11bf80e99bf266f886c70963107bdd31134c4e249eef51133ceccf", - "https://deno.land/std@0.213.0/path/_common/glob_to_reg_exp.ts": "2007aa87bed6eb2c8ae8381adcc3125027543d9ec347713c1ad2c68427330770", - "https://deno.land/std@0.213.0/path/_common/normalize.ts": "684df4aa71a04bbcc346c692c8485594fc8a90b9408dfbc26ff32cf3e0c98cc8", - "https://deno.land/std@0.213.0/path/_common/normalize_string.ts": "dfdf657a1b1a7db7999f7c575ee7e6b0551d9c20f19486c6c3f5ff428384c965", - "https://deno.land/std@0.213.0/path/_common/relative.ts": "faa2753d9b32320ed4ada0733261e3357c186e5705678d9dd08b97527deae607", - "https://deno.land/std@0.213.0/path/_common/strip_trailing_separators.ts": "7024a93447efcdcfeaa9339a98fa63ef9d53de363f1fbe9858970f1bba02655a", - "https://deno.land/std@0.213.0/path/_common/to_file_url.ts": "7f76adbc83ece1bba173e6e98a27c647712cab773d3f8cbe0398b74afc817883", - "https://deno.land/std@0.213.0/path/_interface.ts": "a1419fcf45c0ceb8acdccc94394e3e94f99e18cfd32d509aab514c8841799600", - "https://deno.land/std@0.213.0/path/_os.ts": "8fb9b90fb6b753bd8c77cfd8a33c2ff6c5f5bc185f50de8ca4ac6a05710b2c15", - "https://deno.land/std@0.213.0/path/basename.ts": "5d341aadb7ada266e2280561692c165771d071c98746fcb66da928870cd47668", - "https://deno.land/std@0.213.0/path/common.ts": "03e52e22882402c986fe97ca3b5bb4263c2aa811c515ce84584b23bac4cc2643", - "https://deno.land/std@0.213.0/path/constants.ts": "0c206169ca104938ede9da48ac952de288f23343304a1c3cb6ec7625e7325f36", - "https://deno.land/std@0.213.0/path/dirname.ts": "85bd955bf31d62c9aafdd7ff561c4b5fb587d11a9a5a45e2b01aedffa4238a7c", - "https://deno.land/std@0.213.0/path/extname.ts": "593303db8ae8c865cbd9ceec6e55d4b9ac5410c1e276bfd3131916591b954441", - "https://deno.land/std@0.213.0/path/format.ts": "98fad25f1af7b96a48efb5b67378fcc8ed77be895df8b9c733b86411632162af", - "https://deno.land/std@0.213.0/path/from_file_url.ts": "911833ae4fd10a1c84f6271f36151ab785955849117dc48c6e43b929504ee069", - "https://deno.land/std@0.213.0/path/glob.ts": "04510962905d4b1513b44da9cb195914e0fa46c24359f6feaca20848d797dcb0", - "https://deno.land/std@0.213.0/path/glob_to_regexp.ts": "83c5fd36a8c86f5e72df9d0f45317f9546afa2ce39acaafe079d43a865aced08", - "https://deno.land/std@0.213.0/path/is_absolute.ts": "4791afc8bfd0c87f0526eaa616b0d16e7b3ab6a65b62942e50eac68de4ef67d7", - "https://deno.land/std@0.213.0/path/is_glob.ts": "a65f6195d3058c3050ab905705891b412ff942a292bcbaa1a807a74439a14141", - "https://deno.land/std@0.213.0/path/join.ts": "ae2ec5ca44c7e84a235fd532e4a0116bfb1f2368b394db1c4fb75e3c0f26a33a", - "https://deno.land/std@0.213.0/path/join_globs.ts": "e9589869a33dc3982101898ee50903db918ca00ad2614dbe3934d597d7b1fbea", - "https://deno.land/std@0.213.0/path/mod.ts": "ffeaccb713dbe6c72e015b7c767f753f8ec5fbc3b621ff5eeee486ffc2c0ddda", - "https://deno.land/std@0.213.0/path/normalize.ts": "4155743ccceeed319b350c1e62e931600272fad8ad00c417b91df093867a8352", - "https://deno.land/std@0.213.0/path/normalize_glob.ts": "98ee8268fad271193603271c203ae973280b5abfbdd2cbca1053fd2af71869ca", - "https://deno.land/std@0.213.0/path/parse.ts": "65e8e285f1a63b714e19ef24b68f56e76934c3df0b6e65fd440d3991f4f8aefb", - "https://deno.land/std@0.213.0/path/posix/_util.ts": "1e3937da30f080bfc99fe45d7ed23c47dd8585c5e473b2d771380d3a6937cf9d", - "https://deno.land/std@0.213.0/path/posix/basename.ts": "39ee27a29f1f35935d3603ccf01d53f3d6e0c5d4d0f84421e65bd1afeff42843", - "https://deno.land/std@0.213.0/path/posix/common.ts": "26f60ccc8b2cac3e1613000c23ac5a7d392715d479e5be413473a37903a2b5d4", - "https://deno.land/std@0.213.0/path/posix/constants.ts": "93481efb98cdffa4c719c22a0182b994e5a6aed3047e1962f6c2c75b7592bef1", - "https://deno.land/std@0.213.0/path/posix/dirname.ts": "6535d2bdd566118963537b9dda8867ba9e2a361015540dc91f5afbb65c0cce8b", - "https://deno.land/std@0.213.0/path/posix/extname.ts": "8d36ae0082063c5e1191639699e6f77d3acf501600a3d87b74943f0ae5327427", - "https://deno.land/std@0.213.0/path/posix/format.ts": "185e9ee2091a42dd39e2a3b8e4925370ee8407572cee1ae52838aed96310c5c1", - "https://deno.land/std@0.213.0/path/posix/from_file_url.ts": "951aee3a2c46fd0ed488899d024c6352b59154c70552e90885ed0c2ab699bc40", - "https://deno.land/std@0.213.0/path/posix/glob_to_regexp.ts": "54d3ff40f309e3732ab6e5b19d7111d2d415248bcd35b67a99defcbc1972e697", - "https://deno.land/std@0.213.0/path/posix/is_absolute.ts": "cebe561ad0ae294f0ce0365a1879dcfca8abd872821519b4fcc8d8967f888ede", - "https://deno.land/std@0.213.0/path/posix/is_glob.ts": "8a8b08c08bf731acf2c1232218f1f45a11131bc01de81e5f803450a5914434b9", - "https://deno.land/std@0.213.0/path/posix/join.ts": "aef88d5fa3650f7516730865dbb951594d1a955b785e2450dbee93b8e32694f3", - "https://deno.land/std@0.213.0/path/posix/join_globs.ts": "ee2f4676c5b8a0dfa519da58b8ade4d1c4aa8dd3fe35619edec883ae9df1f8c9", - "https://deno.land/std@0.213.0/path/posix/mod.ts": "563a18c2b3ddc62f3e4a324ff0f583e819b8602a72ad880cb98c9e2e34f8db5b", - "https://deno.land/std@0.213.0/path/posix/normalize.ts": "baeb49816a8299f90a0237d214cef46f00ba3e95c0d2ceb74205a6a584b58a91", - "https://deno.land/std@0.213.0/path/posix/normalize_glob.ts": "65f0138fa518ef9ece354f32889783fc38cdf985fb02dcf1c3b14fa47d665640", - "https://deno.land/std@0.213.0/path/posix/parse.ts": "d5bac4eb21262ab168eead7e2196cb862940c84cee572eafedd12a0d34adc8fb", - "https://deno.land/std@0.213.0/path/posix/relative.ts": "3907d6eda41f0ff723d336125a1ad4349112cd4d48f693859980314d5b9da31c", - "https://deno.land/std@0.213.0/path/posix/resolve.ts": "bac20d9921beebbbb2b73706683b518b1d0c1b1da514140cee409e90d6b2913a", - "https://deno.land/std@0.213.0/path/posix/separator.ts": "c9ecae5c843170118156ac5d12dc53e9caf6a1a4c96fc8b1a0ab02dff5c847b0", - "https://deno.land/std@0.213.0/path/posix/to_file_url.ts": "7aa752ba66a35049e0e4a4be5a0a31ac6b645257d2e031142abb1854de250aaf", - "https://deno.land/std@0.213.0/path/posix/to_namespaced_path.ts": "28b216b3c76f892a4dca9734ff1cc0045d135532bfd9c435ae4858bfa5a2ebf0", - "https://deno.land/std@0.213.0/path/relative.ts": "ab739d727180ed8727e34ed71d976912461d98e2b76de3d3de834c1066667add", - "https://deno.land/std@0.213.0/path/resolve.ts": "a6f977bdb4272e79d8d0ed4333e3d71367cc3926acf15ac271f1d059c8494d8d", - "https://deno.land/std@0.213.0/path/separator.ts": "c6c890507f944a1f5cb7d53b8d638d6ce3cf0f34609c8d84a10c1eaa400b77a9", - "https://deno.land/std@0.213.0/path/to_file_url.ts": "88f049b769bce411e2d2db5bd9e6fd9a185a5fbd6b9f5ad8f52bef517c4ece1b", - "https://deno.land/std@0.213.0/path/to_namespaced_path.ts": "b706a4103b104cfadc09600a5f838c2ba94dbcdb642344557122dda444526e40", - "https://deno.land/std@0.213.0/path/windows/_util.ts": "d5f47363e5293fced22c984550d5e70e98e266cc3f31769e1710511803d04808", - "https://deno.land/std@0.213.0/path/windows/basename.ts": "e2dbf31d1d6385bfab1ce38c333aa290b6d7ae9e0ecb8234a654e583cf22f8fe", - "https://deno.land/std@0.213.0/path/windows/common.ts": "26f60ccc8b2cac3e1613000c23ac5a7d392715d479e5be413473a37903a2b5d4", - "https://deno.land/std@0.213.0/path/windows/constants.ts": "5afaac0a1f67b68b0a380a4ef391bf59feb55856aa8c60dfc01bd3b6abb813f5", - "https://deno.land/std@0.213.0/path/windows/dirname.ts": "33e421be5a5558a1346a48e74c330b8e560be7424ed7684ea03c12c21b627bc9", - "https://deno.land/std@0.213.0/path/windows/extname.ts": "165a61b00d781257fda1e9606a48c78b06815385e7d703232548dbfc95346bef", - "https://deno.land/std@0.213.0/path/windows/format.ts": "bbb5ecf379305b472b1082cd2fdc010e44a0020030414974d6029be9ad52aeb6", - "https://deno.land/std@0.213.0/path/windows/from_file_url.ts": "ced2d587b6dff18f963f269d745c4a599cf82b0c4007356bd957cb4cb52efc01", - "https://deno.land/std@0.213.0/path/windows/glob_to_regexp.ts": "6dcd1242bd8907aa9660cbdd7c93446e6927b201112b0cba37ca5d80f81be51b", - "https://deno.land/std@0.213.0/path/windows/is_absolute.ts": "4a8f6853f8598cf91a835f41abed42112cebab09478b072e4beb00ec81f8ca8a", - "https://deno.land/std@0.213.0/path/windows/is_glob.ts": "8a8b08c08bf731acf2c1232218f1f45a11131bc01de81e5f803450a5914434b9", - "https://deno.land/std@0.213.0/path/windows/join.ts": "e0b3356615c1a75c56ebb6a7311157911659e11fd533d80d724800126b761ac3", - "https://deno.land/std@0.213.0/path/windows/join_globs.ts": "ee2f4676c5b8a0dfa519da58b8ade4d1c4aa8dd3fe35619edec883ae9df1f8c9", - "https://deno.land/std@0.213.0/path/windows/mod.ts": "7d6062927bda47c47847ffb55d8f1a37b0383840aee5c7dfc93984005819689c", - "https://deno.land/std@0.213.0/path/windows/normalize.ts": "78126170ab917f0ca355a9af9e65ad6bfa5be14d574c5fb09bb1920f52577780", - "https://deno.land/std@0.213.0/path/windows/normalize_glob.ts": "179c86ba89f4d3fe283d2addbe0607341f79ee9b1ae663abcfb3439db2e97810", - "https://deno.land/std@0.213.0/path/windows/parse.ts": "b9239edd892a06a06625c1b58425e199f018ce5649ace024d144495c984da734", - "https://deno.land/std@0.213.0/path/windows/relative.ts": "3e1abc7977ee6cc0db2730d1f9cb38be87b0ce4806759d271a70e4997fc638d7", - "https://deno.land/std@0.213.0/path/windows/resolve.ts": "75b2e3e1238d840782cee3d8864d82bfaa593c7af8b22f19c6422cf82f330ab3", - "https://deno.land/std@0.213.0/path/windows/separator.ts": "e51c5522140eff4f8402617c5c68a201fdfa3a1a8b28dc23587cff931b665e43", - "https://deno.land/std@0.213.0/path/windows/to_file_url.ts": "1cd63fd35ec8d1370feaa4752eccc4cc05ea5362a878be8dc7db733650995484", - "https://deno.land/std@0.213.0/path/windows/to_namespaced_path.ts": "4ffa4fb6fae321448d5fe810b3ca741d84df4d7897e61ee29be961a6aac89a4c", - "https://deno.land/std@0.213.0/streams/reader_from_stream_reader.ts": "f981cf94a42133e5c6ace8c3b500565750806c4fc9802262ee63746abc528b0d", - "https://deno.land/std@0.213.0/streams/writer_from_stream_writer.ts": "b0e39ef607dfdc5abdfb627edf61a9672809463e2bb022afcbaf0cd006c40feb", - "https://deno.land/std@0.222.1/assert/_constants.ts": "a271e8ef5a573f1df8e822a6eb9d09df064ad66a4390f21b3e31f820a38e0975", - "https://deno.land/std@0.222.1/assert/_diff.ts": "4bf42969aa8b1a33aaf23eb8e478b011bfaa31b82d85d2ff4b5c4662d8780d2b", - "https://deno.land/std@0.222.1/assert/_format.ts": "0ba808961bf678437fb486b56405b6fefad2cf87b5809667c781ddee8c32aff4", - "https://deno.land/std@0.222.1/assert/assert.ts": "09d30564c09de846855b7b071e62b5974b001bb72a4b797958fe0660e7849834", - "https://deno.land/std@0.222.1/assert/assert_array_includes.ts": "167b2c29997defd49a1835de52b54ae3cbb2bcba52df7c7ee45fe64b473264f1", - "https://deno.land/std@0.222.1/assert/assert_equals.ts": "cc1f4b0ff4ad511e69f965535b56a6cdbbbc0f086bf376e0243214df6039c883", - "https://deno.land/std@0.222.1/assert/assert_exists.ts": "43420cf7f956748ae6ed1230646567b3593cb7a36c5a5327269279c870c5ddfd", - "https://deno.land/std@0.222.1/assert/assert_instance_of.ts": "e22343c1fdcacfaea8f37784ad782683ec1cf599ae9b1b618954e9c22f376f2c", - "https://deno.land/std@0.222.1/assert/assert_is_error.ts": "f856b3bc978a7aa6a601f3fec6603491ab6255118afa6baa84b04426dd3cc491", - "https://deno.land/std@0.222.1/assert/assert_not_equals.ts": "78d45dd46133d76ce624b2c6c09392f6110f0df9b73f911d20208a68dee2ef29", - "https://deno.land/std@0.222.1/assert/assert_object_match.ts": "411450fd194fdaabc0089ae68f916b545a49d7b7e6d0026e84a54c9e7eed2693", - "https://deno.land/std@0.222.1/assert/assert_rejects.ts": "4bee1d6d565a5b623146a14668da8f9eb1f026a4f338bbf92b37e43e0aa53c31", - "https://deno.land/std@0.222.1/assert/assert_throws.ts": "c6508b2879d465898dab2798009299867e67c570d7d34c90a2d235e4553906eb", - "https://deno.land/std@0.222.1/assert/assertion_error.ts": "ba8752bd27ebc51f723702fac2f54d3e94447598f54264a6653d6413738a8917", - "https://deno.land/std@0.222.1/assert/equal.ts": "bddf07bb5fc718e10bb72d5dc2c36c1ce5a8bdd3b647069b6319e07af181ac47", - "https://deno.land/std@0.222.1/collections/_utils.ts": "b2ec8ada31b5a72ebb1d99774b849b4c09fe4b3a38d07794bd010bd218a16e0b", - "https://deno.land/std@0.222.1/collections/deep_merge.ts": "04f8d2a6cfa15c7580e788689bcb5e162512b9ccb18bab1241824b432a78551e", - "https://deno.land/std@0.222.1/collections/distinct.ts": "42d81633e4ccd5ea89118cb08f875bbfc683ac6620df2fa60f3d07270b177f4d", - "https://deno.land/std@0.222.1/collections/distinct_by.ts": "e895705decb0ce88b31c6679fd4e2bd08ac6d47cde7d00bf2016e3c2bac565a7", - "https://deno.land/std@0.222.1/collections/filter_entries.ts": "12202e99001695fcf541ec0191e9762fe7290ba4597df762d3a0c6e611a1aafe", - "https://deno.land/std@0.222.1/collections/filter_keys.ts": "bf8eaae2769e6ddd34f23ba1912f7feda2b6f374253c07a6630e9a2e384ba611", - "https://deno.land/std@0.222.1/collections/map_entries.ts": "45b8bf3f197ee24abe2e078213a4cf2f4e187ad130649fff34e13b1a03ede478", - "https://deno.land/std@0.222.1/collections/map_not_nullish.ts": "f519f74db550afcf6c6e2486382cb4dc6b0465e4234b6acca26910d118e7dd55", - "https://deno.land/std@0.222.1/collections/map_values.ts": "91d6ece4b4dc4b94abc378f51e0e309e7f7f18b2ce4c335dab673a31ebd17c75", - "https://deno.land/std@0.222.1/collections/max_by.ts": "a601c296d54349097d5b424bc86c84010ab22733b622b480e2ad65927063d7bb", - "https://deno.land/std@0.222.1/collections/omit.ts": "7a875ecbb02e3c418195325fd8c520bcf492362344d4d6b295d2e0f101ccccae", - "https://deno.land/std@0.222.1/collections/partition.ts": "22689dc4834bbcaa06f9ac204ac5502ab0f7087d7fca26bad50319c12434d099", - "https://deno.land/std@0.222.1/fmt/colors.ts": "d239d84620b921ea520125d778947881f62c50e78deef2657073840b8af9559a", - "https://deno.land/std@0.222.1/fs/_get_file_info_type.ts": "da7bec18a7661dba360a1db475b826b18977582ce6fc9b25f3d4ee0403fe8cbd", - "https://deno.land/std@0.222.1/fs/_to_path_string.ts": "29bfc9c6c112254961d75cbf6ba814d6de5349767818eb93090cecfa9665591e", - "https://deno.land/std@0.222.1/fs/ensure_dir.ts": "313e8a62b8bb20d900138ff794bde6a6ac0a6bebc91220fba6dfc3303bde56c6", - "https://deno.land/std@0.222.1/fs/ensure_file.ts": "67608cf550529f3d4aa1f8b6b36bf817bdc40b14487bf8f60e61cbf68f507cf3", - "https://deno.land/std@0.222.1/fs/eol.ts": "18c4ac009d0318504c285879eb7f47942643f13619e0ff070a0edc59353306bd", - "https://deno.land/std@0.222.1/fs/exists.ts": "3d38cb7dcbca3cf313be343a7b8af18a87bddb4b5ca1bd2314be12d06533b50f", - "https://deno.land/std@0.222.1/json/common.ts": "33f1a4f39a45e2f9f357823fd0b5cf88b63fb4784b8c9a28f8120f70a20b23e9", - "https://deno.land/std@0.222.1/jsonc/parse.ts": "06fbe10f0bb0cba684f7902bf7de5126b16eb0e5a82220c98a4b86675c7f9cff", - "https://deno.land/std@0.222.1/path/_common/assert_path.ts": "dbdd757a465b690b2cc72fc5fb7698c51507dec6bfafce4ca500c46b76ff7bd8", - "https://deno.land/std@0.222.1/path/_common/basename.ts": "569744855bc8445f3a56087fd2aed56bdad39da971a8d92b138c9913aecc5fa2", - "https://deno.land/std@0.222.1/path/_common/constants.ts": "dc5f8057159f4b48cd304eb3027e42f1148cf4df1fb4240774d3492b5d12ac0c", - "https://deno.land/std@0.222.1/path/_common/dirname.ts": "684df4aa71a04bbcc346c692c8485594fc8a90b9408dfbc26ff32cf3e0c98cc8", - "https://deno.land/std@0.222.1/path/_common/from_file_url.ts": "d672bdeebc11bf80e99bf266f886c70963107bdd31134c4e249eef51133ceccf", - "https://deno.land/std@0.222.1/path/_common/normalize.ts": "684df4aa71a04bbcc346c692c8485594fc8a90b9408dfbc26ff32cf3e0c98cc8", - "https://deno.land/std@0.222.1/path/_common/normalize_string.ts": "33edef773c2a8e242761f731adeb2bd6d683e9c69e4e3d0092985bede74f4ac3", - "https://deno.land/std@0.222.1/path/_common/relative.ts": "faa2753d9b32320ed4ada0733261e3357c186e5705678d9dd08b97527deae607", - "https://deno.land/std@0.222.1/path/_common/strip_trailing_separators.ts": "7024a93447efcdcfeaa9339a98fa63ef9d53de363f1fbe9858970f1bba02655a", - "https://deno.land/std@0.222.1/path/_common/to_file_url.ts": "7f76adbc83ece1bba173e6e98a27c647712cab773d3f8cbe0398b74afc817883", - "https://deno.land/std@0.222.1/path/_interface.ts": "8dfeb930ca4a772c458a8c7bbe1e33216fe91c253411338ad80c5b6fa93ddba0", - "https://deno.land/std@0.222.1/path/_os.ts": "8fb9b90fb6b753bd8c77cfd8a33c2ff6c5f5bc185f50de8ca4ac6a05710b2c15", - "https://deno.land/std@0.222.1/path/basename.ts": "7ee495c2d1ee516ffff48fb9a93267ba928b5a3486b550be73071bc14f8cc63e", - "https://deno.land/std@0.222.1/path/dirname.ts": "85bd955bf31d62c9aafdd7ff561c4b5fb587d11a9a5a45e2b01aedffa4238a7c", - "https://deno.land/std@0.222.1/path/extname.ts": "593303db8ae8c865cbd9ceec6e55d4b9ac5410c1e276bfd3131916591b954441", - "https://deno.land/std@0.222.1/path/from_file_url.ts": "911833ae4fd10a1c84f6271f36151ab785955849117dc48c6e43b929504ee069", - "https://deno.land/std@0.222.1/path/is_absolute.ts": "4791afc8bfd0c87f0526eaa616b0d16e7b3ab6a65b62942e50eac68de4ef67d7", - "https://deno.land/std@0.222.1/path/join.ts": "ae2ec5ca44c7e84a235fd532e4a0116bfb1f2368b394db1c4fb75e3c0f26a33a", - "https://deno.land/std@0.222.1/path/parse.ts": "3e172974e3c71025f5fbd2bd9db4307acb9cc2de14cf6f4464bf40957663cabe", - "https://deno.land/std@0.222.1/path/posix/_util.ts": "1e3937da30f080bfc99fe45d7ed23c47dd8585c5e473b2d771380d3a6937cf9d", - "https://deno.land/std@0.222.1/path/posix/basename.ts": "d2fa5fbbb1c5a3ab8b9326458a8d4ceac77580961b3739cd5bfd1d3541a3e5f0", - "https://deno.land/std@0.222.1/path/posix/dirname.ts": "76cd348ffe92345711409f88d4d8561d8645353ac215c8e9c80140069bf42f00", - "https://deno.land/std@0.222.1/path/posix/extname.ts": "e398c1d9d1908d3756a7ed94199fcd169e79466dd88feffd2f47ce0abf9d61d2", - "https://deno.land/std@0.222.1/path/posix/from_file_url.ts": "951aee3a2c46fd0ed488899d024c6352b59154c70552e90885ed0c2ab699bc40", - "https://deno.land/std@0.222.1/path/posix/is_absolute.ts": "cebe561ad0ae294f0ce0365a1879dcfca8abd872821519b4fcc8d8967f888ede", - "https://deno.land/std@0.222.1/path/posix/join.ts": "7fc2cb3716aa1b863e990baf30b101d768db479e70b7313b4866a088db016f63", - "https://deno.land/std@0.222.1/path/posix/normalize.ts": "baeb49816a8299f90a0237d214cef46f00ba3e95c0d2ceb74205a6a584b58a91", - "https://deno.land/std@0.222.1/path/posix/parse.ts": "0b1fc4cb890dbb699ec1d2c232d274843b4a7142e1ad976b69fe51c954eb6080", - "https://deno.land/std@0.222.1/path/posix/relative.ts": "3907d6eda41f0ff723d336125a1ad4349112cd4d48f693859980314d5b9da31c", - "https://deno.land/std@0.222.1/path/posix/resolve.ts": "08b699cfeee10cb6857ccab38fa4b2ec703b0ea33e8e69964f29d02a2d5257cf", - "https://deno.land/std@0.222.1/path/posix/to_file_url.ts": "7aa752ba66a35049e0e4a4be5a0a31ac6b645257d2e031142abb1854de250aaf", - "https://deno.land/std@0.222.1/path/relative.ts": "ab739d727180ed8727e34ed71d976912461d98e2b76de3d3de834c1066667add", - "https://deno.land/std@0.222.1/path/resolve.ts": "a6f977bdb4272e79d8d0ed4333e3d71367cc3926acf15ac271f1d059c8494d8d", - "https://deno.land/std@0.222.1/path/to_file_url.ts": "88f049b769bce411e2d2db5bd9e6fd9a185a5fbd6b9f5ad8f52bef517c4ece1b", - "https://deno.land/std@0.222.1/path/windows/_util.ts": "d5f47363e5293fced22c984550d5e70e98e266cc3f31769e1710511803d04808", - "https://deno.land/std@0.222.1/path/windows/basename.ts": "6bbc57bac9df2cec43288c8c5334919418d784243a00bc10de67d392ab36d660", - "https://deno.land/std@0.222.1/path/windows/dirname.ts": "33e421be5a5558a1346a48e74c330b8e560be7424ed7684ea03c12c21b627bc9", - "https://deno.land/std@0.222.1/path/windows/extname.ts": "165a61b00d781257fda1e9606a48c78b06815385e7d703232548dbfc95346bef", - "https://deno.land/std@0.222.1/path/windows/from_file_url.ts": "ced2d587b6dff18f963f269d745c4a599cf82b0c4007356bd957cb4cb52efc01", - "https://deno.land/std@0.222.1/path/windows/is_absolute.ts": "4a8f6853f8598cf91a835f41abed42112cebab09478b072e4beb00ec81f8ca8a", - "https://deno.land/std@0.222.1/path/windows/join.ts": "8d03530ab89195185103b7da9dfc6327af13eabdcd44c7c63e42e27808f50ecf", - "https://deno.land/std@0.222.1/path/windows/normalize.ts": "78126170ab917f0ca355a9af9e65ad6bfa5be14d574c5fb09bb1920f52577780", - "https://deno.land/std@0.222.1/path/windows/parse.ts": "dbdfe2bc6db482d755b5f63f7207cd019240fcac02ad2efa582adf67ff10553a", - "https://deno.land/std@0.222.1/path/windows/relative.ts": "3e1abc7977ee6cc0db2730d1f9cb38be87b0ce4806759d271a70e4997fc638d7", - "https://deno.land/std@0.222.1/path/windows/resolve.ts": "8dae1dadfed9d46ff46cc337c9525c0c7d959fb400a6308f34595c45bdca1972", - "https://deno.land/std@0.222.1/path/windows/to_file_url.ts": "40e560ee4854fe5a3d4d12976cef2f4e8914125c81b11f1108e127934ced502e", - "https://deno.land/std@0.222.1/semver/_constants.ts": "5ef89c5f33e6095546ae3e57920592feefcb8372d4cc05542f6bf15a1977e3c9", - "https://deno.land/std@0.222.1/semver/_shared.ts": "5c53a675225cba9ad74ae2e17c124e333728fc2b551a13e8a32b99433b90c1c2", - "https://deno.land/std@0.222.1/semver/compare.ts": "7b5610c25ded57dc4aa41034ee02857d1a6fff609ab183afea17849284f86236", - "https://deno.land/std@0.222.1/semver/constants.ts": "bd442eb6d51d5032686e02abdf575b32dd08f2c95e653e66bbeb927e8ff54bb5", - "https://deno.land/std@0.222.1/semver/format.ts": "a4492b55a10210a10b9307491c0ec7f0c2475cc82af33de1c2565a15083b83df", - "https://deno.land/std@0.222.1/semver/parse.ts": "94c09f3486643853e7438e64f2c6741462fbeb84cf141ad5bfe88b73ec4cb0f3", - "https://deno.land/std@0.222.1/semver/parse_range.ts": "f48ca42b59988d9274225b1f93c39d84005e810bb858faf564f48c0ad8431fa7", - "https://deno.land/std@0.222.1/semver/try_parse.ts": "043204f1235243c3d02b66ffca2c37dc2941e417dbccaf6c3a15b476a33f0e24", - "https://deno.land/std@0.222.1/semver/try_parse_range.ts": "cf1e2d489bbe9ed6185de551acdf708e23e0e1bc4be0958052dfef178f763eee", - "https://deno.land/std@0.222.1/semver/types.ts": "9286e72b160e25856608f4bc5f08f8f5ccba54e6cdfc9aba8adee68a355c4b36", - "https://deno.land/std@0.222.1/testing/_test_suite.ts": "f10a8a6338b60c403f07a76f3f46bdc9f1e1a820c0a1decddeb2949f7a8a0546", - "https://deno.land/std@0.222.1/testing/bdd.ts": "3e4de4ff6d8f348b5574661cef9501b442046a59079e201b849d0e74120d476b", - "https://deno.land/std@0.222.1/testing/mock.ts": "a963181c2860b6ba3eb60e08b62c164d33cf5da7cd445893499b2efda20074db", - "https://deno.land/std@0.222.1/testing/snapshot.ts": "35ca1c8e8bfb98d7b7e794f1b7be8d992483fcff572540e41396f22a5bddb944", - "https://deno.land/x/async@v2.1.0/mutex.ts": "782792457021425da571b8f30d6c62f7dc1cdf83d7299257343d57cac7357e27", - "https://deno.land/x/cliffy@v1.0.0-rc.3/_utils/distance.ts": "02af166952c7c358ac83beae397aa2fbca4ad630aecfcd38d92edb1ea429f004", - "https://deno.land/x/cliffy@v1.0.0-rc.3/ansi/colors.ts": "328916ea1627c202b39f2ed0f1ca65a573cfb75fa8986aa3dbcc0b7463911005", - "https://deno.land/x/cliffy@v1.0.0-rc.3/command/_argument_types.ts": "ab269dacea2030f865a07c2a1e953ec437a64419a05bad1f1ddaab3f99752ead", - "https://deno.land/x/cliffy@v1.0.0-rc.3/command/_errors.ts": "12d513ff401020287a344e0830e1297ce1c80c077ecb91e0ac5db44d04a6019c", - "https://deno.land/x/cliffy@v1.0.0-rc.3/command/_spread.ts": "0cc6eb70a6df97b5d7d26008822d39f3e8a1232ee0a27f395aa19e68de738245", - "https://deno.land/x/cliffy@v1.0.0-rc.3/command/_type_utils.ts": "820004a59bc858e355b11f80e5b3ff1be2c87e66f31f53f253610170795602f0", - "https://deno.land/x/cliffy@v1.0.0-rc.3/command/_utils.ts": "3c88ff4f36eba298beb07de08068fdce5e5cb7b9d82c8a319f09596d8279be64", - "https://deno.land/x/cliffy@v1.0.0-rc.3/command/command.ts": "ae690745759524082776b7f271f66d5b93933170b1b132f888bd4ac12e9fdd7d", - "https://deno.land/x/cliffy@v1.0.0-rc.3/command/deps.ts": "7473ebd5625bf901becd7ff80afdde3b8a50ae5d1bbfa2f43805cfacf4559d5a", - "https://deno.land/x/cliffy@v1.0.0-rc.3/command/help/_help_generator.ts": "532dd4a928baab8b45ce46bb6d20e2ebacfdf3da141ce9d12da796652b1de478", - "https://deno.land/x/cliffy@v1.0.0-rc.3/command/type.ts": "f588f5d9635b79100044e62aced4b00e510e75b83801f9b089c40c2d98674de2", - "https://deno.land/x/cliffy@v1.0.0-rc.3/command/types.ts": "bc9ff7459b9cc1079eeb95ff101690a51b4b4afa4af5623340076ee361d08dbb", - "https://deno.land/x/cliffy@v1.0.0-rc.3/command/types/boolean.ts": "3879ec16092b4b5b1a0acb8675f8c9250c0b8a972e1e4c7adfba8335bd2263ed", - "https://deno.land/x/cliffy@v1.0.0-rc.3/command/types/file.ts": "8618f16ac9015c8589cbd946b3de1988cc4899b90ea251f3325c93c46745140e", - "https://deno.land/x/cliffy@v1.0.0-rc.3/command/types/integer.ts": "29864725fd48738579d18123d7ee78fed37515e6dc62146c7544c98a82f1778d", - "https://deno.land/x/cliffy@v1.0.0-rc.3/command/types/number.ts": "aeba96e6f470309317a16b308c82e0e4138a830ec79c9877e4622c682012bc1f", - "https://deno.land/x/cliffy@v1.0.0-rc.3/command/types/string.ts": "e4dadb08a11795474871c7967beab954593813bb53d9f69ea5f9b734e43dc0e0", - "https://deno.land/x/cliffy@v1.0.0-rc.3/command/upgrade/_check_version.ts": "6cfa7dc26bc0dc46381500e8d4b130fb224f4c5456152dada15bd3793edca89b", - "https://deno.land/x/cliffy@v1.0.0-rc.3/flags/_errors.ts": "f1fbb6bfa009e7950508c9d491cfb4a5551027d9f453389606adb3f2327d048f", - "https://deno.land/x/cliffy@v1.0.0-rc.3/flags/_utils.ts": "340d3ecab43cde9489187e1f176504d2c58485df6652d1cdd907c0e9c3ce4cc2", - "https://deno.land/x/cliffy@v1.0.0-rc.3/flags/_validate_flags.ts": "e60b9038c0136ab7e6bd1baf0e993a07bf23f18afbfb6e12c59adf665a622957", - "https://deno.land/x/cliffy@v1.0.0-rc.3/flags/deprecated.ts": "a72a35de3cc7314e5ebea605ca23d08385b218ef171c32a3f135fb4318b08126", - "https://deno.land/x/cliffy@v1.0.0-rc.3/flags/flags.ts": "3e62c4a9756b5705aada29e7e94847001356b3a83cd18ad56f4207387a71cf51", - "https://deno.land/x/cliffy@v1.0.0-rc.3/flags/types.ts": "9e2f75edff2217d972fc711a21676a59dfd88378da2f1ace440ea84c07db1dcc", - "https://deno.land/x/cliffy@v1.0.0-rc.3/flags/types/boolean.ts": "4c026dd66ec9c5436860dc6d0241427bdb8d8e07337ad71b33c08193428a2236", - "https://deno.land/x/cliffy@v1.0.0-rc.3/flags/types/integer.ts": "b60d4d590f309ddddf066782d43e4dc3799f0e7d08e5ede7dc62a5ee94b9a6d9", - "https://deno.land/x/cliffy@v1.0.0-rc.3/flags/types/number.ts": "610936e2d29de7c8c304b65489a75ebae17b005c6122c24e791fbed12444d51e", - "https://deno.land/x/cliffy@v1.0.0-rc.3/flags/types/string.ts": "e89b6a5ce322f65a894edecdc48b44956ec246a1d881f03e97bbda90dd8638c5", - "https://deno.land/x/cliffy@v1.0.0-rc.3/table/_layout.ts": "e4a518da28333de95ad791208b9930025987c8b93d5f8b7f30b377b3e26b24e1", - "https://deno.land/x/cliffy@v1.0.0-rc.3/table/_utils.ts": "fd48d1a524a42e72aa3ad2eec858a92f5a00728d306c7e8436fba6c34314fee6", - "https://deno.land/x/cliffy@v1.0.0-rc.3/table/border.ts": "5c6e9ef5078c6930169aacb668b274bdbb498461c724a7693ac9270fe9d3f5d5", - "https://deno.land/x/cliffy@v1.0.0-rc.3/table/cell.ts": "1ffabd43b6b7fddfac9625cb0d015532e144702a9bfed03b358b79375115d06b", - "https://deno.land/x/cliffy@v1.0.0-rc.3/table/column.ts": "cf14009f2cb14bad156f879946186c1893acdc6a2fee6845db152edddb6a2714", - "https://deno.land/x/cliffy@v1.0.0-rc.3/table/consume_words.ts": "456e75755fdf6966abdefb8b783df2855e2a8bad6ddbdf21bd748547c5fc1d4b", - "https://deno.land/x/cliffy@v1.0.0-rc.3/table/deps.ts": "1226c4d39d53edc81d7c3e661fb8a79f2e704937c276c60355cd4947a0fe9153", - "https://deno.land/x/cliffy@v1.0.0-rc.3/table/row.ts": "79eb1468aafdd951e5963898cdafe0752d4ab4c519d5f847f3d8ecb8fe857d4f", - "https://deno.land/x/cliffy@v1.0.0-rc.3/table/table.ts": "298671e72e61f1ab18b42ae36643181993f79e29b39dc411fdc6ffd53aa04684", - "https://deno.land/x/dax@0.39.2/mod.ts": "309f96ce11fa8a1bb244fdfdcb60fa66f092200a72295402094aab88bdf02bdd", - "https://deno.land/x/dax@0.39.2/src/command.ts": "01980353fec193bbc7f1c3690bb87472607d0b1b7d9844d17904920b907cd0de", - "https://deno.land/x/dax@0.39.2/src/command_handler.ts": "a9e40f0f1ec57318e62904b5785fede82dcdf1101922ebb3ebfad8f1c4d9c8df", - "https://deno.land/x/dax@0.39.2/src/commands/args.ts": "a138aef24294e3cbf13cef08f4836d018e8dd99fd06ad82e7e7f08ef680bbc1d", - "https://deno.land/x/dax@0.39.2/src/commands/cat.ts": "ac42675faaf87609fd5d4bff9a7741cef7fd4465d6de709b8ccabe70f7fd4c98", - "https://deno.land/x/dax@0.39.2/src/commands/cd.ts": "32533465933fada680c1fc887e24b65c8d4de3f5f98d0f55950dcead64da445c", - "https://deno.land/x/dax@0.39.2/src/commands/cp_mv.ts": "29a11a0f6c81e9a19b897c9b3178594f06a55a00ca28cb63c17773e154b34299", - "https://deno.land/x/dax@0.39.2/src/commands/echo.ts": "4672ad44a39fdcb3f9d9296a7c5773895bfae0f50a617fd999d1f0ca62a6aa36", - "https://deno.land/x/dax@0.39.2/src/commands/exit.ts": "508a388671240381a2a9a8910d4bf068421ace27ae1cc10c056df48cf9d23334", - "https://deno.land/x/dax@0.39.2/src/commands/export.ts": "c10d1dc6a45fd00e40afa6b19d7ecd29d09333f422b5b0fc75863baf13350969", - "https://deno.land/x/dax@0.39.2/src/commands/mkdir.ts": "28220eae8d7e872dca26b8217ad1b7e15eacf24e92d80277201caacbbecb8232", - "https://deno.land/x/dax@0.39.2/src/commands/printenv.ts": "8e1210b01ef5fcb8de71623f1195aab6ee034dbe684cd08e068ab855f9133ff9", - "https://deno.land/x/dax@0.39.2/src/commands/pwd.ts": "113af521c5dc257310c26815295c691b8f894051249d1eb8ba49a46965e28c68", - "https://deno.land/x/dax@0.39.2/src/commands/rm.ts": "a3441ddf9cb8f07fdf1657cb475caefcae71b71378681f4948e8ada93ef4478d", - "https://deno.land/x/dax@0.39.2/src/commands/sleep.ts": "2ba65ab19ae0f78709070f43d588c8fd3ff76d0299d2485e587aaaed7b86dd51", - "https://deno.land/x/dax@0.39.2/src/commands/test.ts": "336008d64d9737474ee225be9f8bd6fbad3f1c2128ba427e1b42d2c98366554f", - "https://deno.land/x/dax@0.39.2/src/commands/touch.ts": "b8229c2c38b56ebff054dd8dc70109cb85bcef5aaf160193fd80ac93924aa7ad", - "https://deno.land/x/dax@0.39.2/src/commands/unset.ts": "a85e9aca0606fd582114c5fc1f97fd6838a766110bad72dce7bd386172c1fbbb", - "https://deno.land/x/dax@0.39.2/src/common.ts": "7a96f3e4d576f92be12364d520107cff54b3d1a98124b5a88538494c5109c6e6", - "https://deno.land/x/dax@0.39.2/src/console/confirm.ts": "d9128d10b77fcc0a8df2784f71c79df68f5c8e00a34b04547b9ba9ddf1c97f96", - "https://deno.land/x/dax@0.39.2/src/console/logger.ts": "e0ab5025915cef70df03681c756e211f25bb2e4331f82ed4256b17ddd9e794ea", - "https://deno.land/x/dax@0.39.2/src/console/mod.ts": "de8af7d646f6cb222eee6560171993690247941b13ed9d757789d16f019d73ee", - "https://deno.land/x/dax@0.39.2/src/console/multiSelect.ts": "31003744e58f45f720271bd034d8cfba1055c954ba02d77a2f2eb21e4c1ed55a", - "https://deno.land/x/dax@0.39.2/src/console/progress/format.ts": "15ddbb8051580f88ed499281e12ca6f881f875ab73268d7451d7113ee130bd7d", - "https://deno.land/x/dax@0.39.2/src/console/progress/interval.ts": "54ffc8c7501f8ab0b6370e120c00e9e2d3e9b0640fc2dc2989bbf22855172ed0", - "https://deno.land/x/dax@0.39.2/src/console/progress/mod.ts": "dd9330c3edd1790d70808d043f417f0eaf80a4442a945545c38e47ce11e907b6", - "https://deno.land/x/dax@0.39.2/src/console/prompt.ts": "1ad65c8a5a27fb58ce6138f8ebefe2fca4cd12015fea550fbdc62f875d4b31f7", - "https://deno.land/x/dax@0.39.2/src/console/select.ts": "c9d7124d975bf34d52ea1ac88fd610ed39db8ee6505b9bb53f371cef2f56c6ab", - "https://deno.land/x/dax@0.39.2/src/console/utils.ts": "6f2c4d7c98c13d40b0a16af622d654495eace06778343eb1507ecd0f3875d3ab", - "https://deno.land/x/dax@0.39.2/src/deps.ts": "c6f4195419244d38879d4dd14de5190a507818ac62a5a992493c7567a1235f7d", - "https://deno.land/x/dax@0.39.2/src/lib/mod.ts": "7d9d0cf99ecd3ff5c3e5329ea9e456b737581afb4a5c94c3f90244c990b5630d", - "https://deno.land/x/dax@0.39.2/src/lib/rs_lib.generated.js": "0a1a482c4387379106ef0da69534ebc5b0c2a1ec9f6dab76833fe84a7e6bbdf6", - "https://deno.land/x/dax@0.39.2/src/path.ts": "a1ca507225a516336f083432b992d83ad4cddeea9a91eef69abbbebb729721ae", - "https://deno.land/x/dax@0.39.2/src/pipes.ts": "5ed17dc0aea34d219568d59c826c04e319a91497cac2be7c51a99603a3771c70", - "https://deno.land/x/dax@0.39.2/src/request.ts": "21de624bc21155cf6143ea5eddf4de706944e26af10219957da4b8b20c7104ce", - "https://deno.land/x/dax@0.39.2/src/result.ts": "719a9b4bc6bafeec785106744381cd5f37927c973334fcba6a33b6418fb9e7be", - "https://deno.land/x/dax@0.39.2/src/runtimes/process.common.ts": "692afd5fa15f40ce452904fa5ce380462cee56fbee7abe271e509e78da997200", - "https://deno.land/x/dax@0.39.2/src/runtimes/process.deno.ts": "50f85a086a9208b26c10dc2c1406fd9274226401f670d6862fdee05433c9ea4e", - "https://deno.land/x/dax@0.39.2/src/shell.ts": "b95677094cc553c987f0f113a95a45d72f2896ef82754f9831029efbbafea5d5", - "https://deno.land/x/dax@0.39.2/src/vendor/outdent.ts": "4d0283726579688c50b20c4b779e068acd3fa159a8784a4549e5e21bbef0ae64", "https://deno.land/x/deno_graph@0.69.6/deno_graph_wasm.generated.js": "db34a2f6e33c4dda6b60bdd1a698babd9593a6d042757949d773b72662a45520", "https://deno.land/x/deno_graph@0.69.6/loader.ts": "512a406cb4c449b45110f2b878cd09929a883a4af193060232d2d9fc76a9d4dd", "https://deno.land/x/deno_graph@0.69.6/media_type.ts": "7c1c5c6654e3cf84b8daa53c0d1ffc1b7864849406f559b961eccff859b0a417", @@ -300,14 +351,28 @@ "https://deno.land/x/dir@1.5.1/data_local_dir/mod.ts": "91eb1c4bfadfbeda30171007bac6d85aadacd43224a5ed721bbe56bc64e9eb66", "https://deno.land/x/import_map@v0.19.1/import_map.generated.js": "c46023bef881ccecc740740962331f98decbfe72d88644396bf674145c20dd1e", "https://deno.land/x/import_map@v0.19.1/mod.ts": "dd4c4e20639dcfd720a6d41f47bea250db86137901a08988102094678c6b7859", - "https://deno.land/x/unknownutil@v3.18.0/_typeutil.ts": "774d207c47fb5350f468cdcf68e80f1bc6e278f6bc77c04d17a601618c49d2c1", - "https://deno.land/x/unknownutil@v3.18.0/inspect.ts": "33e61bdfed94cd586d66600813b528fa93046a2802d8144277b92f0fa5e5f10e", - "https://deno.land/x/unknownutil@v3.18.0/is.ts": "0c552cf85f8eeca86b41d892da627168185eaabfd79931e39cfdf00a70de6269", - "https://deno.land/x/unknownutil@v3.18.0/metadata.ts": "04fcfbca1338e44b4067be4bde51b863dc4c91b279541c78620e617d3e77e01a", - "https://deno.land/x/unknownutil@v3.18.0/mod.ts": "c38cc1fe09a108ecca944adde2dd2f37c1c00a83c964f0a3b8a7debd62d33fc8", - "https://deno.land/x/unknownutil@v3.18.0/util.ts": "051fb654a110aa8bc9e034ce03aea2d39349fdf723da6ce6b783e5299327444d", "https://deno.land/x/wasmbuild@0.15.1/cache.ts": "9d01b5cb24e7f2a942bbd8d14b093751fa690a6cde8e21709ddc97667e6669ed", - "https://deno.land/x/wasmbuild@0.15.1/loader.ts": "8c2fc10e21678e42f84c5135d8ab6ab7dc92424c3f05d2354896a29ccfd02a63", - "https://deno.land/x/which@0.3.0/mod.ts": "3e10d07953c14e4ddc809742a3447cef14202cdfe9be6678a1dfc8769c4487e6" + "https://deno.land/x/wasmbuild@0.15.1/loader.ts": "8c2fc10e21678e42f84c5135d8ab6ab7dc92424c3f05d2354896a29ccfd02a63" + }, + "workspace": { + "dependencies": [ + "jsr:@cliffy/ansi@1.0.0-rc.4", + "jsr:@cliffy/command@1.0.0-rc.4", + "jsr:@core/match@^0.2.5", + "jsr:@core/unknownutil@^3.18.0", + "jsr:@david/dax@^0.40.0", + "jsr:@lambdalisue/async@^2.1.1", + "jsr:@std/assert@^0.222.1", + "jsr:@std/collections@^0.222.1", + "jsr:@std/dotenv@^0.222.1", + "jsr:@std/fmt@^0.222.1", + "jsr:@std/fs@^0.222.1", + "jsr:@std/jsonc@^0.222.1", + "jsr:@std/path@^0.222.1", + "jsr:@std/semver@^0.222.1", + "jsr:@std/testing@^0.222.1", + "npm:@conventional-commits/parser@^0.4.1", + "npm:@octokit/rest@^20.1.0" + ] } } diff --git a/integration/commits.ts b/integration/commits.ts new file mode 100644 index 00000000..265f3b32 --- /dev/null +++ b/integration/commits.ts @@ -0,0 +1,54 @@ +import type { Repository } from "./repository.ts"; +import * as github from "./github.ts"; + +/** + * Get the commits between two Git references in the repository. + */ +export async function compareCommits( + repo: Repository, + base: string, + head: string, +): Promise { + // + // Return the stored commits if available + // + using kv = await Deno.openKv(); + const stored = await kv.get([ + "commits", + repo.owner, + repo.name, + base, + head, + ]); + if (stored.value) { + return stored.value; + } + // + // Otherwise, fetch the commits from the Git hosting platform + // + const commits = await _compareCommits(repo, base, head); + await kv.set( + [ + "commits", + repo.owner, + repo.name, + base, + head, + ], + commits, + ); + return commits; +} + +async function _compareCommits( + repo: Repository, + base: string, + head: string, +): Promise { + switch (repo.host) { + case "github": + return await github.compareCommits(repo, base, head); + default: + throw new Error(`Unsupported Git hosting platform: ${repo.host}`); + } +} diff --git a/integration/commits_test.ts b/integration/commits_test.ts new file mode 100644 index 00000000..e69de29b diff --git a/integration/deno.json b/integration/deno.json new file mode 100644 index 00000000..026af728 --- /dev/null +++ b/integration/deno.json @@ -0,0 +1,20 @@ +{ + "name": "@molt/integration", + "version": "0.18.0", + "exports": { + ".": "./mod.ts", + "./github": "./github.ts", + "./package": "./package.ts", + "./repository": "./repository.ts" + }, + "publish": { + "exclude": [ + "*_test.ts" + ] + }, + "imports": { + "@molt/core": "jsr:@molt/core@0.18.0", + "@std/path": "jsr:@std/path@^0.222.1", + "@std/testing": "jsr:@std/testing@^0.222.1" + } +} diff --git a/integration/github.ts b/integration/github.ts new file mode 100644 index 00000000..1a6dae8b --- /dev/null +++ b/integration/github.ts @@ -0,0 +1,137 @@ +import { dirname } from "@std/path"; +import { parse as parseJsonc } from "@std/jsonc"; +import { match, placeholder as _ } from "@core/match"; +import { isString } from "@core/unknownutil"; +import { Octokit } from "@octokit/rest"; +import { is, type Package } from "./packages.ts"; +import type { Repository } from "./repository.ts"; + +const octokit = new Octokit({ + auth: Deno.env.get("GITHUB_TOKEN"), +}); + +/** + * Fetch commit log from the GitHub repository via the GitHub REST API. + */ +export async function compareCommits( + repo: Repository<"github">, + base: string, + head: string, +): Promise { + const { data } = await octokit.repos.compareCommits({ + owner: repo.owner, + repo: repo.name, + base, + head, + }); + return data.commits.map((it) => it.commit.message); +} + +type GitHubContent = { + path?: string; + type?: "blob" | "tree"; + sha?: string; +}; + +export function resolvePackageRoot( + repo: Repository<"github">, + pkg: Package, + ref?: string, +): Promise { + switch (pkg.registry) { + case "jsr": + return resolveJsrPackageRoot(repo, pkg, ref); + default: + throw new Error(`Unsupported registry: ${pkg.registry}`); + } +} + +async function resolveJsrPackageRoot( + repo: Repository<"github">, + pkg: Package<"jsr">, + ref?: string, +): Promise { + const contents = await getContents(repo, ref); + + const candidates: GitHubContent[] = []; + + const rootConfig = contents.find((it) => + it.path === "deno.json" || it.path === "deno.jsonc" + ); + if (rootConfig) candidates.push(rootConfig); + + // A heuristic to find the directory for the package + const moduleConfig = contents.find((it) => + it.path === `${pkg.name}/deno.json` || it.path === `${pkg.name}/deno.jsonc` + ); + if (moduleConfig) candidates.push(moduleConfig); + + for (const config of candidates) { + if (!config.path || !config.sha) { + continue; + } + const { data } = await octokit.git.getBlob({ + owner: repo.owner, + repo: repo.name, + file_sha: config.sha, + }); + const json = match( + { name: _("name", isString) }, + parseJsonc(atob(data.content)), + ); + if (json && is(`jsr:${json.name}`, pkg)) { + return dirname(config.path); + } + } +} + +async function getContents( + repo: Repository<"github">, + ref?: string, +): Promise { + ref = ref ?? await getDefaultRef(repo); + + // Check if the contents are cached in Deno KV + using kv = await Deno.openKv(); + const entries = await Array.fromAsync( + kv.list({ prefix: ["github", repo.owner, repo.name, ref] }), + ); + if (entries.length) { + return entries.map((it) => it.value); + } + + // Fetch the contents from the GitHub API + const { data } = await octokit.git.getTree({ + owner: repo.owner, + repo: repo.name, + tree_sha: ref, + recursive: "true", + }); + + // Cache the contents of the repository to Deno KV + const contents = data.tree as GitHubContent[]; + await Promise.all( + contents.map((it) => + it.path + ? kv.set(["github", repo.owner, repo.name, ref, it.path], it) + : undefined + ), + ); + + return contents; +} + +async function getDefaultRef( + repo: Repository<"github">, +): Promise { + const { data: meta } = await octokit.repos.get({ + owner: repo.owner, + repo: repo.name, + }); + const { data: branch } = await octokit.repos.getBranch({ + owner: repo.owner, + repo: repo.name, + branch: meta.default_branch, + }); + return branch.commit.sha; +} diff --git a/integration/github_test.ts b/integration/github_test.ts new file mode 100644 index 00000000..4dfb14f2 --- /dev/null +++ b/integration/github_test.ts @@ -0,0 +1,70 @@ +import { assertEquals } from "@std/assert/assert-equals"; +import "@std/dotenv/load"; +import { compareCommits, resolvePackageRoot } from "./github.ts"; +import { parse } from "./packages.ts"; +import type { Repository } from "./repository.ts"; + +Deno.test("compareCommits", async () => { + const repo = { + host: "github", + owner: "hasundue", + name: "molt", + } satisfies Repository; + assertEquals( + await compareCommits(repo, "0.17.0", "0.17.2"), + [ + "fix: accept a lock file without `dependencies`", + "test(cli): update snapshot", + "chore(task/update): enable `--unstable-lock`", + "chore(cli): `--version` returns `dev` if undefined", + "test(lib/file): check EOL at the end of file", + "fix: add EOL at the end of updated lock file", + "test(cli): stub latest version of `jsr:@std/`", + "test(cli): update snapshot", + "build(deps): bump deno.land/std from 0.219.1 to 0.220.1", + ], + ); +}); + +Deno.test("resolvePackageRoot", async () => { + // + // An example of a single package repository + // + const match: Repository = { + host: "github", + owner: "jsr-core", + name: "match", + }; + assertEquals( + await resolvePackageRoot( + match, + parse("jsr:@core/match"), + "735360d", + ), + ".", + ); + // + // An example of a monorepo with multiple packages + // + const cliffy: Repository = { + host: "github", + owner: "JOTSR", + name: "deno-cliffy", + }; + assertEquals( + await resolvePackageRoot( + cliffy, + parse("jsr:@cliffy/command"), + "297574f", + ), + "command", + ); + assertEquals( + await resolvePackageRoot( + cliffy, + parse("jsr:@molt/core"), + "297574f", + ), + undefined, + ); +}); diff --git a/integration/mod.ts b/integration/mod.ts new file mode 100644 index 00000000..6d72ec9e --- /dev/null +++ b/integration/mod.ts @@ -0,0 +1,4 @@ +export * from "./commits.ts"; +export * as github from "./github.ts"; +export * from "./packages.ts"; +export * from "./repository.ts"; diff --git a/integration/packages.ts b/integration/packages.ts new file mode 100644 index 00000000..e403f2ad --- /dev/null +++ b/integration/packages.ts @@ -0,0 +1,148 @@ +import { match, placeholder as _ } from "@core/match"; +import type { Dependency } from "@molt/core"; +import type { Repository } from "./repository.ts"; +import * as github from "./github.ts"; + +/** + * A known package registry. + */ +export type KnownPackageRegistry = typeof KNOWN_PACKAGE_REGISTRIES[number]; + +const KNOWN_PACKAGE_REGISTRIES = [ + "jsr", +] as const; + +/** + * Check if a string is a known package registry. + */ +export function isKnownRegistry(str: unknown): str is KnownPackageRegistry { + return typeof str === "string" && + KNOWN_PACKAGE_REGISTRIES.includes(str as KnownPackageRegistry); +} + +/** + * A package in a package registry. + */ +export interface Package< + R extends KnownPackageRegistry = KnownPackageRegistry, +> { + registry: R; + scope: string; + name: string; +} + +/** + * A string representation of a package in a package registry. + * + * @example + * ```ts + * const pkg = { registry: "jsr", scope: "molt", name: "core" }; + * stringify(pkg); // "jsr:@molt/core" + * ``` + */ +export type PackageString< + R extends KnownPackageRegistry = KnownPackageRegistry, +> = `${R}:@${string}/${string}`; + +/** + * Convert a package to a string representation. + * + * @example + * ```ts + * const pkg = { registry: "jsr", scope: "molt", name: "core" }; + * stringify(pkg); // "jsr:@molt/core" + * ``` + */ +export function stringify( + pkg: Package, +): PackageString { + return `${pkg.registry}:@${pkg.scope}/${pkg.name}`; +} + +/** + * Parse a package from a string representation. + * If the string is not a valid package, an error is thrown. + * + * @example + * ```ts + * parse("jsr:@molt/core"); // { registry: "jsr", scope: "molt", name: "core" } + * ``` + */ +export function parse( + str: T, +): T extends PackageString ? Package : Package { + const result = match( + _`${_("registry", isKnownRegistry)}:@${_("scope")}/${_("name")}`, + str, + ); + if (!result) { + throw new Error(`Invalid package specifier: ${str}`); + } + // deno-lint-ignore no-explicit-any + return result as any; +} + +/** + * Try to parse a package from a string representation. + * If the string is not a valid package, `undefined` is returned. + * + * @example + * ```ts + * tryParse("jsr:@molt/core"); // { registry: "jsr", scope: "molt", name: "core" } + * + * tryParse("invalid"); // undefined + * ``` + */ +export function tryParse( + str: T, +): T extends PackageString ? Package : Package | undefined { + try { + // deno-lint-ignore no-explicit-any + return parse(str) as any; + } catch { + // deno-lint-ignore no-explicit-any + return undefined as any; + } +} + +/** + * Check if a string represents the given package. + * + * @example + * ```ts + * const pkg = { registry: "jsr", scope: "molt", name: "core" }; + * is("jsr:@molt/core", pkg); // true + * is("jsr:@molt/other", pkg); // false + * ``` + */ +export function is(str: string, pkg: Package): boolean { + return str === stringify(pkg); +} + +/** + * Convert a dependency to a package representation if possible. + * If the dependency is not a package, `undefined` is returned. + * + * @example + * ```ts + * const dependency = { protocol: "jsr", name: "core", version: "0.18.0" }; + * fromDependency(dependency); // { registry: "jsr", scope: "molt", name: "core" } + * ``` + */ +export function fromDependency(dependency: Dependency): Package | undefined { + const { protocol, name } = dependency; + return tryParse(protocol + name); +} + +export function resolvePackageRoot( + repo: Repository, + pkg: Package, + ref?: string, +): Promise { + switch (repo.host) { + case "github": + return github.resolvePackageRoot(repo, pkg, ref); + default: + throw new Error(`Unsupported hosting platform: ${repo.host}`); + } +} diff --git a/integration/packages_test.ts b/integration/packages_test.ts new file mode 100644 index 00000000..483068b3 --- /dev/null +++ b/integration/packages_test.ts @@ -0,0 +1,99 @@ +import { + assertEquals, + assertExists, + assertObjectMatch, + assertThrows, +} from "@std/assert"; +import { + fromDependency, + is, + type Package, + parse, + stringify, + tryParse, +} from "./packages.ts"; + +Deno.test("parse", () => { + assertObjectMatch( + parse("jsr:@std/collections"), + { + registry: "jsr", + scope: "std", + name: "collections", + } satisfies Package, + ); + assertThrows(() => parse("std/collections")); +}); + +Deno.test("tryParse", () => { + assertObjectMatch( + tryParse("jsr:@std/collections"), + { + registry: "jsr", + scope: "std", + name: "collections", + } satisfies Package, + ); + assertEquals( + tryParse("std/collections"), + undefined, + ); +}); + +Deno.test("stringify", () => { + assertEquals( + stringify({ + registry: "jsr", + scope: "std", + name: "collections", + }), + "jsr:@std/collections", + ); +}); + +Deno.test("is", () => { + assertEquals( + is("jsr:@std/collections", { + registry: "jsr", + scope: "std", + name: "collections", + }), + true, + ); + assertEquals( + is("std/collections", { + registry: "jsr", + scope: "std", + name: "collections", + }), + false, + ); +}); + +Deno.test("fromDependency - JSR", () => { + const result = fromDependency({ + protocol: "jsr:", + name: "@std/collections", + version: "0.200.0", + path: "/fs", + }); + assertExists(result); + assertObjectMatch( + result, + { + registry: "jsr", + scope: "std", + name: "collections", + } satisfies Package, + ); +}); + +Deno.test("fromDependency - deno.land", () => { + const result = fromDependency({ + protocol: "https:", + name: "https://deno.land/std", + version: "0.200.0", + path: "/fs/mod.ts", + }); + assertEquals(result, undefined); +}); diff --git a/test/integration/registries.ts b/integration/registries_test.ts similarity index 87% rename from test/integration/registries.ts rename to integration/registries_test.ts index b80a91e9..b5a504d3 100644 --- a/test/integration/registries.ts +++ b/integration/registries_test.ts @@ -1,6 +1,6 @@ -import { fromFileUrl } from "../../lib/std/path.ts"; -import { createAssertSnapshot } from "../../lib/std/testing.ts"; -import { parse, resolveLatestVersion } from "../../lib/dependency.ts"; +import { fromFileUrl } from "@std/path"; +import { createAssertSnapshot } from "@std/testing/snapshot"; +import { parse, resolveLatestVersion } from "@molt/core"; type RegistryTestSpec = [ name: string, @@ -83,5 +83,5 @@ for (const spec of SPECS) { } const assertSnapshot = createAssertSnapshot({ - dir: fromFileUrl(new URL("../snapshots/", import.meta.url)), + dir: fromFileUrl(new URL("../test/snapshots/", import.meta.url)), }); diff --git a/integration/repository.ts b/integration/repository.ts new file mode 100644 index 00000000..06d7cf1d --- /dev/null +++ b/integration/repository.ts @@ -0,0 +1,116 @@ +import { ensure, is } from "@core/unknownutil"; +import { type Package, stringify } from "./packages.ts"; + +/** + * A git repository on a hosting platform. + */ +export interface Repository< + Host extends KnownGitHostingPlatform = KnownGitHostingPlatform, +> { + host: Host; + owner: string; + name: string; +} + +export type KnownGitHostingPlatform = "github"; + +/** + * Resolve the repository of the given package + */ +export async function resolveRepository( + pkg: Package, +): Promise { + const { registry, scope, name } = pkg; + switch (registry) { + case "jsr": { + const response = await fetch( + `https://api.jsr.io/scopes/${scope}/packages/${name}`, + { + headers: { + "User-Agent": "molt/0.18.0; https://github.com/hasundue/molt", + }, + }, + ); + if (!response.ok) { + console.warn( + `Failed to fetch details of ${ + stringify(pkg) + }: ${response.statusText}`, + ); + return; + } + const { githubRepository: repo } = ensure( + await response.json(), + isJsrPackageDetails, + { message: `Unexpected response from JSR registry: ${response.url}` }, + ); + if (repo) { + return { host: "github", name: repo.name, owner: repo.owner }; + } + } + } +} + +/** + * Resolve the created date of the given dependency as a number. + * If the created date cannot be resolved, the current time is returned gracefully. + * + * @example + * ```ts + * const createdDate = await resolveCreatedDate({ + * registry: "jsr", + * scope: "molt", + * name: "core", + * version: "0.18.0", + * }); + * // => 1620000000000 + * ``` + */ +export async function resolveCreatedDate( + pkg: Package, + version: string, +): Promise { + const { registry, scope, name } = pkg; + switch (registry) { + case "jsr": { + if (!version) { + return Date.now(); + } + const response = await fetch( + `https://api.jsr.io/scopes/${scope}/packages/${name}/versions/${version}`, + { + headers: { + "User-Agent": "molt/0.18.0; https://github.com/hasundue/molt", + }, + }, + ); + if (!response.ok) { + console.warn( + `Failed to fetch version details of ${ + stringify(pkg) + }: ${response.statusText}`, + ); + return Date.now(); + } + const { createdAt } = ensure( + await response.json(), + isJsrPackageVersionDetails, + { message: `Unexpected response from JSR registry: ${response.url}` }, + ); + return Date.parse(createdAt); + } + default: + return Date.now(); + } +} + +const isJsrPackageDetails = is.ObjectOf({ + githubRepository: is.OptionalOf(is.ObjectOf({ + owner: is.String, + name: is.String, + })), +}); + +const isJsrPackageVersionDetails = is.ObjectOf({ + createdAt: is.String, +}); diff --git a/integration/repository_test.ts b/integration/repository_test.ts new file mode 100644 index 00000000..e69de29b diff --git a/lib/changelog.ts b/lib/changelog.ts new file mode 100644 index 00000000..73225b6f --- /dev/null +++ b/lib/changelog.ts @@ -0,0 +1,85 @@ +import { + type ConventionalChangelogCommit as Commit, + parser, + toConventionalChangelogFormat, +} from "@conventional-commits/parser"; +import { associateWith, mapNotNullish } from "@std/collections"; + +export type { Commit }; + +export type ChangeLog< + T extends string = string, +> = { + [K in T | "BREAKING CHANGE"]: ChangeLogRecord[]; +}; + +export interface ChangeLogRecord { + scope: string | null; + text: string; +} + +export interface ChangeLogOptions< + T extends string = string, +> { + types: T[]; + scope?: string; +} + +export function curateChangeLog< + T extends string = string, +>( + messages: string[], + options: ChangeLogOptions, +): ChangeLog { + const { scope, types } = options; + let commits = mapNotNullish(messages, tryParseCommit); + if (scope) { + commits = commits + .filter((it) => it.scope?.startsWith(scope)) + .map((it): Commit => ({ ...it, scope: flatten(it.scope, scope) })); + } + return { + ...associateWith( + types, + (type) => + commits + .filter((it) => it.type === type) + .map((it): ChangeLogRecord => ({ + scope: it.scope, + text: it.subject, + })), + ), + "BREAKING CHANGE": commits + .flatMap(curateBreakingChange) + .map((it): ChangeLogRecord => ({ scope: null, text: it })), + } as ChangeLog; +} + +function flatten(scope: string | null, root?: string): string | null { + if (!scope) { + return null; + } + if (!root) { + return scope; + } + const sliced = scope.slice(root.length); + return sliced.length ? sliced : null; +} + +export function tryParseCommit(message: string): Commit | undefined { + try { + return toConventionalChangelogFormat(parser(message)); + } catch { + return undefined; + } +} + +export function parseCommit(message: string): Commit { + return toConventionalChangelogFormat(parser(message)); +} + +export function curateBreakingChange(commit: Commit): string[] { + return commit.notes + .filter((note) => note.title === "BREAKING CHANGE") + .map((note) => note.text); +} diff --git a/lib/changelog_test.ts b/lib/changelog_test.ts new file mode 100644 index 00000000..12ee4fdf --- /dev/null +++ b/lib/changelog_test.ts @@ -0,0 +1,122 @@ +import { + assertArrayIncludes, + assertEquals, + assertObjectMatch, +} from "@std/assert"; +import { + curateBreakingChange, + curateChangeLog, + parseCommit, +} from "./changelog.ts"; + +Deno.test("parseCommit", () => { + assertObjectMatch( + parseCommit("fix: accept a lock file without `dependencies`"), + { + type: "fix", + scope: null, + subject: "accept a lock file without `dependencies`", + body: "", + }, + ); + assertObjectMatch( + parseCommit("test(cli): update snapshot"), + { + type: "test", + scope: "cli", + subject: "update snapshot", + body: "", + }, + ); + assertObjectMatch( + parseCommit(`refactor(core)!: use deno_lockfile crate internally + +BREAKING CHANGE: rename \`--unstable-lock\` as \`--lock\` +`), + { + type: "refactor", + scope: "core", + subject: "use deno_lockfile crate internally", + notes: [ + { + title: "BREAKING CHANGE", + text: "rename `--unstable-lock` as `--lock`", + }, + ], + }, + ); +}); + +Deno.test("curateBreakingChange", () => { + assertArrayIncludes( + curateBreakingChange( + parseCommit(`refactor(core)!: use deno_lockfile crate internally + +BREAKING CHANGE: rename \`--unstable-lock\` as \`--lock\` +`), + ), + ["rename `--unstable-lock` as `--lock`"], + ); + assertEquals( + curateBreakingChange( + parseCommit("fix: accept a lock file without `dependencies`"), + ).length, + 0, + ); +}); + +Deno.test("createChangeLog", () => { + const messages = [ + "feat: add `--lock` option", + "fix(cli): accept a lock file without `dependencies`", + `refactor(core)!: use deno_lockfile crate internally + +BREAKING CHANGE: rename \`--unstable-lock\` as \`--lock\` +`, + ]; + + const changelog = curateChangeLog(messages, { + types: ["feat", "fix"], + }); + + assertEquals(changelog["feat"].length, 1); + assertObjectMatch( + changelog["feat"][0], + { + scope: null, + text: "add `--lock` option", + }, + ); + assertEquals(changelog["fix"].length, 1); + assertObjectMatch( + changelog["fix"][0], + { + scope: "cli", + text: "accept a lock file without `dependencies`", + }, + ); + assertEquals(changelog["BREAKING CHANGE"].length, 1); + assertObjectMatch( + changelog["BREAKING CHANGE"][0], + { + scope: null, + text: "rename `--unstable-lock` as `--lock`", + }, + ); + + const scoped = curateChangeLog(messages, { + types: ["feat", "fix"], + scope: "cli", + }); + + assertEquals(scoped["feat"].length, 0); + assertEquals(scoped["fix"].length, 1); + assertObjectMatch( + scoped["fix"][0], + { + scope: null, + text: "accept a lock file without `dependencies`", + }, + ); + assertEquals(scoped["BREAKING CHANGE"].length, 0); +}); diff --git a/lib/deno.json b/lib/deno.json new file mode 100644 index 00000000..bcc99e71 --- /dev/null +++ b/lib/deno.json @@ -0,0 +1,23 @@ +{ + "name": "@molt/lib", + "version": "0.18.0", + "exports": { + "./changelog": "./changelog.ts", + "./path": "./path.ts", + "./testing": "./testing.ts" + }, + "publish": { + "exclude": [ + "*_test.ts" + ] + }, + "imports": { + "@conventional-commits/parser": "npm:@conventional-commits/parser@^0.4.1", + "@core/match": "jsr:@core/match@^0.2.5", + "@std/assert": "jsr:@std/assert@^0.222.1", + "@std/collections": "jsr:@std/collections@^0.222.1", + "@std/fs": "jsr:@std/fs@^0.222.1", + "@std/path": "jsr:@std/path@^0.222.1", + "@std/testing": "jsr:@std/testing@^0.222.1" + } +} diff --git a/lib/path.ts b/lib/path.ts index baaf75f5..a7d6f4da 100644 --- a/lib/path.ts +++ b/lib/path.ts @@ -1,4 +1,4 @@ -import { dirname, fromFileUrl, join, resolve, toFileUrl } from "./std/path.ts"; +import { dirname, fromFileUrl, join, resolve, toFileUrl } from "@std/path"; /** * Convert a path to a string URL diff --git a/lib/path_test.ts b/lib/path_test.ts index 82c39fc8..aa8a5a77 100644 --- a/lib/path_test.ts +++ b/lib/path_test.ts @@ -1,5 +1,5 @@ -import { assertEquals, assertRejects } from "./std/assert.ts"; -import { dirname, fromFileUrl, resolve } from "./std/path.ts"; +import { assertEquals, assertRejects } from "@std/assert"; +import { dirname, fromFileUrl, resolve } from "@std/path"; import { findFileUp, toPath, toUrl } from "./path.ts"; const isWindows = Deno.build.os === "windows"; @@ -85,8 +85,8 @@ Deno.test("toPath (Windows)", { ignore: !isWindows }, () => { Deno.test("findFileUp", async () => { const dir = dirname(toPath(import.meta.url)); assertEquals( - await findFileUp(dir, "deno.json"), - fromFileUrl(new URL("../deno.json", import.meta.url)), + await findFileUp(dir, "LICENSE"), + fromFileUrl(new URL("../LICENSE", import.meta.url)), ); // Throws for a non-directory path assertRejects( diff --git a/lib/std/assert.ts b/lib/std/assert.ts deleted file mode 100644 index 482d99c9..00000000 --- a/lib/std/assert.ts +++ /dev/null @@ -1,10 +0,0 @@ -export { assert } from "https://deno.land/std@0.222.1/assert/assert.ts"; -export { assertArrayIncludes } from "https://deno.land/std@0.222.1/assert/assert_array_includes.ts"; -export { assertEquals } from "https://deno.land/std@0.222.1/assert/assert_equals.ts"; -export { assertExists } from "https://deno.land/std@0.222.1/assert/assert_exists.ts"; -export { assertNotEquals } from "https://deno.land/std@0.222.1/assert/assert_not_equals.ts"; -export { assertObjectMatch } from "https://deno.land/std@0.222.1/assert/assert_object_match.ts"; -export { assertThrows } from "https://deno.land/std@0.222.1/assert/assert_throws.ts"; -export { AssertionError } from "https://deno.land/std@0.222.1/assert/assertion_error.ts"; -export { assertRejects } from "https://deno.land/std@0.222.1/assert/assert_rejects.ts"; -export { assertInstanceOf } from "https://deno.land/std@0.222.1/assert/assert_instance_of.ts"; diff --git a/lib/std/collections.ts b/lib/std/collections.ts deleted file mode 100644 index 0c4e9c49..00000000 --- a/lib/std/collections.ts +++ /dev/null @@ -1,11 +0,0 @@ -export { deepMerge } from "https://deno.land/std@0.222.1/collections/deep_merge.ts"; -export { distinct } from "https://deno.land/std@0.222.1/collections/distinct.ts"; -export { distinctBy } from "https://deno.land/std@0.222.1/collections/distinct_by.ts"; -export { filterEntries } from "https://deno.land/std@0.222.1/collections/filter_entries.ts"; -export { filterKeys } from "https://deno.land/std@0.222.1/collections/filter_keys.ts"; -export { mapValues } from "https://deno.land/std@0.222.1/collections/map_values.ts"; -export { mapEntries } from "https://deno.land/std@0.222.1/collections/map_entries.ts"; -export { mapNotNullish as mapN } from "https://deno.land/std@0.222.1/collections/map_not_nullish.ts"; -export { maxBy } from "https://deno.land/std@0.222.1/collections/max_by.ts"; -export { omit } from "https://deno.land/std@0.222.1/collections/omit.ts"; -export { partition } from "https://deno.land/std@0.222.1/collections/partition.ts"; diff --git a/lib/std/fmt.ts b/lib/std/fmt.ts deleted file mode 100644 index b887df31..00000000 --- a/lib/std/fmt.ts +++ /dev/null @@ -1 +0,0 @@ -export { stripAnsiCode } from "https://deno.land/std@0.222.1/fmt/colors.ts"; diff --git a/lib/std/fs.ts b/lib/std/fs.ts deleted file mode 100644 index 82ccf2bc..00000000 --- a/lib/std/fs.ts +++ /dev/null @@ -1,7 +0,0 @@ -export { exists, existsSync } from "https://deno.land/std@0.222.1/fs/exists.ts"; -export { - detect as detectEOL, - EOL, - format as formatEOL, - LF, -} from "https://deno.land/std@0.222.1/fs/eol.ts"; diff --git a/lib/std/jsonc.ts b/lib/std/jsonc.ts deleted file mode 100644 index 95687719..00000000 --- a/lib/std/jsonc.ts +++ /dev/null @@ -1 +0,0 @@ -export { parse } from "https://deno.land/std@0.222.1/jsonc/parse.ts"; diff --git a/lib/std/path.ts b/lib/std/path.ts deleted file mode 100644 index 5c130d54..00000000 --- a/lib/std/path.ts +++ /dev/null @@ -1,9 +0,0 @@ -export { isAbsolute } from "https://deno.land/std@0.222.1/path/is_absolute.ts"; -export { relative } from "https://deno.land/std@0.222.1/path/relative.ts"; -export { resolve } from "https://deno.land/std@0.222.1/path/resolve.ts"; -export { toFileUrl } from "https://deno.land/std@0.222.1/path/to_file_url.ts"; -export { fromFileUrl } from "https://deno.land/std@0.222.1/path/from_file_url.ts"; -export { extname } from "https://deno.land/std@0.222.1/path/extname.ts"; -export { join } from "https://deno.land/std@0.222.1/path/join.ts"; -export { dirname } from "https://deno.land/std@0.222.1/path/dirname.ts"; -export { basename } from "https://deno.land/std@0.222.1/path/basename.ts"; diff --git a/lib/std/semver.ts b/lib/std/semver.ts deleted file mode 100644 index e4ab5bde..00000000 --- a/lib/std/semver.ts +++ /dev/null @@ -1,5 +0,0 @@ -export { compare } from "https://deno.land/std@0.222.1/semver/compare.ts"; -export { format } from "https://deno.land/std@0.222.1/semver/format.ts"; -export { parse } from "https://deno.land/std@0.222.1/semver/parse.ts"; -export { tryParse } from "https://deno.land/std@0.222.1/semver/try_parse.ts"; -export { tryParseRange } from "https://deno.land/std@0.222.1/semver/try_parse_range.ts"; diff --git a/lib/std/testing.ts b/lib/std/testing.ts deleted file mode 100644 index a93432dc..00000000 --- a/lib/std/testing.ts +++ /dev/null @@ -1,23 +0,0 @@ -export { - afterAll, - afterEach, - beforeAll, - beforeEach, - describe, - it, -} from "https://deno.land/std@0.222.1/testing/bdd.ts"; -export { - assertSpyCall, - assertSpyCallArg, - assertSpyCalls, - type ConstructorSpy, - type ExpectedSpyCall, - type Spy, - spy, - type SpyCall, - type Stub, - stub, -} from "https://deno.land/std@0.222.1/testing/mock.ts"; -export { - createAssertSnapshot, -} from "https://deno.land/std@0.222.1/testing/snapshot.ts"; diff --git a/lib/testing.ts b/lib/testing.ts index 22247f76..23655ddf 100644 --- a/lib/testing.ts +++ b/lib/testing.ts @@ -1,6 +1,6 @@ -import { spy, Stub, stub } from "./std/testing.ts"; -import { formatEOL, LF } from "./std/fs.ts"; -import { dirname } from "./std/path.ts"; +import { spy, type Stub, stub } from "@std/testing/mock"; +import { format, LF } from "@std/fs/eol"; +import { dirname } from "@std/path"; export const CommandStub = { create(pattern = "") { @@ -80,7 +80,7 @@ export const WriteTextFileStub = { if (path.toString().startsWith(tmp)) { return original(path, data); } else { - fs.set(path.toString(), formatEOL(data.toString(), LF)); + fs.set(path.toString(), format(data.toString(), LF)); return Promise.resolve(); } }, @@ -188,23 +188,6 @@ function parseDenoLandUrl(url: URL) { }; } -/** - * Enables all test stubs. - */ -export function enableTestMode() { - LatestVersionStub.create({ - "deno.land/std": "0.218.2", - "deno_graph": "0.69.7", - "node-emoji": "2.1.3", - "@luca/flag": "1.0.1", - "@std/": "0.218.2", - }); - const fs = new FileSystemFake(); - ReadTextFileStub.create(fs, { readThrough: true }); - WriteTextFileStub.create(fs); - Deno.Command = CommandStub.create("git"); -} - /** Utility function to throw an error. */ function _throw(error: Error): never { throw error; diff --git a/lib/testing_test.ts b/lib/testing_test.ts index a53eea17..1d83b2ab 100644 --- a/lib/testing_test.ts +++ b/lib/testing_test.ts @@ -1,5 +1,5 @@ -import { assertObjectMatch } from "./std/assert.ts"; -import { assertSpyCall, assertSpyCalls } from "./std/testing.ts"; +import { assertObjectMatch } from "@std/assert"; +import { assertSpyCall, assertSpyCalls } from "@std/testing/mock"; import { CommandStub } from "./testing.ts"; Deno.test("CommandStub", async () => { diff --git a/lib/x/async.ts b/lib/x/async.ts deleted file mode 100644 index 1a9f4a14..00000000 --- a/lib/x/async.ts +++ /dev/null @@ -1 +0,0 @@ -export { Mutex } from "https://deno.land/x/async@v2.1.0/mutex.ts"; diff --git a/lib/x/cliffy.ts b/lib/x/cliffy.ts deleted file mode 100644 index abb2d7f7..00000000 --- a/lib/x/cliffy.ts +++ /dev/null @@ -1,2 +0,0 @@ -export { Command } from "https://deno.land/x/cliffy@v1.0.0-rc.3/command/command.ts"; -export { colors } from "https://deno.land/x/cliffy@v1.0.0-rc.3/ansi/colors.ts"; diff --git a/lib/x/dax.ts b/lib/x/dax.ts deleted file mode 100644 index 6ba868f7..00000000 --- a/lib/x/dax.ts +++ /dev/null @@ -1 +0,0 @@ -export { $ } from "https://deno.land/x/dax@0.39.2/mod.ts"; diff --git a/lib/x/deno_graph.ts b/lib/x/deno_graph.ts deleted file mode 100644 index 121e4fc9..00000000 --- a/lib/x/deno_graph.ts +++ /dev/null @@ -1,7 +0,0 @@ -export { - createGraph, - type CreateGraphOptions, - init, - load, - type ModuleJson, -} from "https://deno.land/x/deno_graph@0.69.6/mod.ts"; diff --git a/lib/x/import_map.ts b/lib/x/import_map.ts deleted file mode 100644 index 366858ec..00000000 --- a/lib/x/import_map.ts +++ /dev/null @@ -1,5 +0,0 @@ -export { - ImportMap, - type ImportMapJson, - parseFromJson, -} from "https://deno.land/x/import_map@v0.19.1/mod.ts"; diff --git a/lib/x/unknownutil.ts b/lib/x/unknownutil.ts deleted file mode 100644 index 8ad593f6..00000000 --- a/lib/x/unknownutil.ts +++ /dev/null @@ -1,6 +0,0 @@ -export { - assert, - ensure, - is, - type PredicateType, -} from "https://deno.land/x/unknownutil@v3.18.0/mod.ts"; diff --git a/mod.ts b/mod.ts index 8b9aae43..0da6c532 100644 --- a/mod.ts +++ b/mod.ts @@ -31,28 +31,4 @@ * @module */ -export { - type Dependency, - parse, - resolveLatestVersion, - stringify, - type UpdatedDependency, -} from "./lib/dependency.ts"; - -export { type FileUpdate, write, type WriteOptions } from "./lib/file.ts"; - -export { - commit, - type CommitSequence, - createCommitSequence, - execute, - type GitCommit, -} from "./lib/git.ts"; - -export { - collect, - type CollectOptions, - type CollectResult, - type DependencyUpdate, - type SourceType, -} from "./lib/update.ts"; +export * from "./core/mod.ts"; diff --git a/test/data/export.ts b/test/cases/export.ts similarity index 100% rename from test/data/export.ts rename to test/cases/export.ts diff --git a/test/data/import.ts b/test/cases/import.ts similarity index 100% rename from test/data/import.ts rename to test/cases/import.ts diff --git a/test/data/import_and_export.ts b/test/cases/import_and_export.ts similarity index 100% rename from test/data/import_and_export.ts rename to test/cases/import_and_export.ts diff --git a/test/data/import_map/deno.json b/test/cases/import_map/deno.json similarity index 100% rename from test/data/import_map/deno.json rename to test/cases/import_map/deno.json diff --git a/test/data/import_map/mod.ts b/test/cases/import_map/mod.ts similarity index 100% rename from test/data/import_map/mod.ts rename to test/cases/import_map/mod.ts diff --git a/test/data/import_map/noop.ts b/test/cases/import_map/noop.ts similarity index 100% rename from test/data/import_map/noop.ts rename to test/cases/import_map/noop.ts diff --git a/test/data/import_map_no_resolve/deno.json b/test/cases/import_map_no_resolve/deno.json similarity index 100% rename from test/data/import_map_no_resolve/deno.json rename to test/cases/import_map_no_resolve/deno.json diff --git a/test/data/import_map_no_resolve/mod.ts b/test/cases/import_map_no_resolve/mod.ts similarity index 100% rename from test/data/import_map_no_resolve/mod.ts rename to test/cases/import_map_no_resolve/mod.ts diff --git a/test/data/import_map_referred/deno.json b/test/cases/import_map_referred/deno.json similarity index 100% rename from test/data/import_map_referred/deno.json rename to test/cases/import_map_referred/deno.json diff --git a/test/data/import_map_referred/import_map.json b/test/cases/import_map_referred/import_map.json similarity index 100% rename from test/data/import_map_referred/import_map.json rename to test/cases/import_map_referred/import_map.json diff --git a/test/data/import_map_referred/mod.ts b/test/cases/import_map_referred/mod.ts similarity index 100% rename from test/data/import_map_referred/mod.ts rename to test/cases/import_map_referred/mod.ts diff --git a/test/data/jsonc/deno.jsonc b/test/cases/jsonc/deno.jsonc similarity index 100% rename from test/data/jsonc/deno.jsonc rename to test/cases/jsonc/deno.jsonc diff --git a/test/data/jsr.ts b/test/cases/jsr.ts similarity index 100% rename from test/data/jsr.ts rename to test/cases/jsr.ts diff --git a/test/data/lockfile/deno.json b/test/cases/lockfile/deno.json similarity index 100% rename from test/data/lockfile/deno.json rename to test/cases/lockfile/deno.json diff --git a/test/data/lockfile/deno.lock b/test/cases/lockfile/deno.lock similarity index 100% rename from test/data/lockfile/deno.lock rename to test/cases/lockfile/deno.lock diff --git a/test/data/lockfile/deno.updated.lock b/test/cases/lockfile/deno.updated.lock similarity index 100% rename from test/data/lockfile/deno.updated.lock rename to test/cases/lockfile/deno.updated.lock diff --git a/test/data/lockfile/mod.ts b/test/cases/lockfile/mod.ts similarity index 100% rename from test/data/lockfile/mod.ts rename to test/cases/lockfile/mod.ts diff --git a/test/data/lockfile_not_importable/deno.json b/test/cases/lockfile_not_importable/deno.json similarity index 100% rename from test/data/lockfile_not_importable/deno.json rename to test/cases/lockfile_not_importable/deno.json diff --git a/test/data/lockfile_not_importable/deno.lock b/test/cases/lockfile_not_importable/deno.lock similarity index 100% rename from test/data/lockfile_not_importable/deno.lock rename to test/cases/lockfile_not_importable/deno.lock diff --git a/test/data/lockfile_not_importable/mod.ts b/test/cases/lockfile_not_importable/mod.ts similarity index 100% rename from test/data/lockfile_not_importable/mod.ts rename to test/cases/lockfile_not_importable/mod.ts diff --git a/test/data/multiple_imports.ts b/test/cases/multiple_imports.ts similarity index 100% rename from test/data/multiple_imports.ts rename to test/cases/multiple_imports.ts diff --git a/test/data/multiple_modules/lib.ts b/test/cases/multiple_modules/lib.ts similarity index 100% rename from test/data/multiple_modules/lib.ts rename to test/cases/multiple_modules/lib.ts diff --git a/test/data/multiple_modules/mod.ts b/test/cases/multiple_modules/mod.ts similarity index 100% rename from test/data/multiple_modules/mod.ts rename to test/cases/multiple_modules/mod.ts diff --git a/test/data/npm.ts b/test/cases/npm.ts similarity index 100% rename from test/data/npm.ts rename to test/cases/npm.ts diff --git a/test/data/relative_import/assert.ts b/test/cases/relative_import/assert.ts similarity index 100% rename from test/data/relative_import/assert.ts rename to test/cases/relative_import/assert.ts diff --git a/test/data/relative_import/mod.ts b/test/cases/relative_import/mod.ts similarity index 100% rename from test/data/relative_import/mod.ts rename to test/cases/relative_import/mod.ts diff --git a/test/data/unversioned.ts b/test/cases/unversioned.ts similarity index 100% rename from test/data/unversioned.ts rename to test/cases/unversioned.ts diff --git a/test/data/updated_and_outdated.ts b/test/cases/updated_and_outdated.ts similarity index 100% rename from test/data/updated_and_outdated.ts rename to test/cases/updated_and_outdated.ts diff --git a/test/data/updated_import_and_outdated_export.ts b/test/cases/updated_import_and_outdated_export.ts similarity index 100% rename from test/data/updated_import_and_outdated_export.ts rename to test/cases/updated_import_and_outdated_export.ts diff --git a/test/integration/cli.ts b/test/integration/cli.ts deleted file mode 100644 index 2cd5b6db..00000000 --- a/test/integration/cli.ts +++ /dev/null @@ -1,121 +0,0 @@ -import { assertEquals } from "../../lib/std/assert.ts"; -import { stripAnsiCode } from "../../lib/std/fmt.ts"; -import { fromFileUrl, join } from "../../lib/std/path.ts"; -import { createAssertSnapshot } from "../../lib/std/testing.ts"; - -// basic commands -molt("", { code: 2 }); -molt("--help"); -molt("--version"); - -// single file -molt("not_exist.ts", { code: 1 }); -molt("import.ts"); - -// special registries -molt("jsr.ts"); - -// with import maps -molt("mod.ts", { cwd: "import_map" }); -molt("mod.ts --import-map deno.json", { cwd: "import_map" }); - -// --ignore and --only -molt("multiple_imports.ts --ignore node-emoji"); -molt("multiple_imports.ts --ignore=deno_graph,node-emoji"); -molt("multiple_imports.ts --only deno.land/std"); -molt("multiple_imports.ts --only=deno.land/std,deno_graph"); -molt("multiple_imports.ts --only deno.land --ignore deno_graph"); - -// --write -molt("mod.ts --write", { cwd: "multiple_modules" }); -molt( - "mod.ts --write --summary title.txt --report body.md", - { cwd: "multiple_modules" }, -); - -// --commit -molt("mod.ts --commit", { cwd: "multiple_modules" }); -molt("mod.ts --commit --prefix :package:", { cwd: "multiple_modules" }); -molt( - "mod.ts --commit --pre-commit=fmt --post-commit=lint", - { cwd: "multiple_modules" }, -); -molt( - "mod.ts --commit --summary title.txt --report body.md", - { cwd: "multiple_modules" }, -); -molt( - "mod.ts --commit --summary title.txt --pre-commit=fmt", - { cwd: "multiple_modules" }, -); - -// deno.json -molt("deno.json", { cwd: "import_map" }); -molt("deno.json --write", { cwd: "import_map" }); -molt("deno.json --commit", { cwd: "import_map" }); - -// deno.jsonc -molt("deno.jsonc", { cwd: "jsonc" }); -molt("deno.jsonc --write", { cwd: "jsonc" }); -molt("deno.jsonc --commit", { cwd: "jsonc" }); - -// lockfile -molt("deno.json --unstable-lock not_exist.lock", { cwd: "lockfile", code: 1 }); -molt("deno.json --unstable-lock", { cwd: "lockfile" }); -molt("deno.json --unstable-lock --write", { cwd: "lockfile" }); -molt( - "deno.json --commit --unstable-lock --prefix :package: --prefix-lock :lock:", - { cwd: "lockfile" }, -); - -//----------------------- -// Test implementation -//----------------------- - -const BIN = new URL("../../cli.ts", import.meta.url).pathname; -const DATA = new URL("../data", import.meta.url).pathname; - -function molt(line: string, opts?: { - cwd?: string; - code?: number; -}) { - const args = line.length > 0 ? line.split(" ") : []; - - const name = "cli - " + (opts?.cwd ? opts.cwd + " - " : "") + - '"' + ["molt"].concat(args).join(" ") + '"'; - - Deno.test(name, async (t) => { - const output = await new Deno.Command("deno", { - args: ["run", "-A", BIN, ...args], - env: { MOLT_TEST: "1" }, - cwd: join(DATA, opts?.cwd ? `/${opts?.cwd}` : ""), - }).output(); - - const stdout = stringify(output.stdout); - const stderr = stringify(output.stderr); - try { - assertEquals(output.code, opts?.code ?? 0); - } catch (err) { - console.error(stdout); - console.error(stderr); - throw err; - } - await assertSnapshot(t, stdout); - await assertSnapshot(t, stderr); - }); -} - -function stringify(data: Uint8Array) { - const decoder = new TextDecoder(); - let text = decoder.decode(data); - if (Deno.build.os === "windows") { - text = text - .replace(/\r\n/g, "\n") - .replace(/\\/g, "/"); - } - return stripAnsiCode(text); -} - -const assertSnapshot = createAssertSnapshot({ - dir: fromFileUrl(new URL("../snapshots/", import.meta.url)), -}); diff --git a/test/snapshots/cli.ts.snap b/test/snapshots/cli_test.ts.snap similarity index 58% rename from test/snapshots/cli.ts.snap rename to test/snapshots/cli_test.ts.snap index 25aae004..8b08bdfd 100644 --- a/test/snapshots/cli.ts.snap +++ b/test/snapshots/cli_test.ts.snap @@ -10,20 +10,19 @@ Description: Options: - -h, --help - Show this help. - -v, --version - Print version info. - --import-map - Specify import map file - --ignore - Ignore dependencies - --only - Check specified dependencies - -w, --write - Write changes to local files (Conflicts: --commit) - -c, --commit - Commit changes to local git repository (Conflicts: --write) - --pre-commit - Run tasks before each commit (Depends: --commit) - --post-commit - Run tasks after each commit (Depends: --commit) - --prefix - Prefix for commit messages (Depends: --commit) - --prefix-lock - Prefix for commit messages of updating a lock file (Depends: --commit, --unstable-lock) - --summary - Write a summary of changes to file - --report - Write a report of changes to file - --unstable-lock [file] - Enable unstable updating of a lock file + -h, --help - Show this help. + -v, --version - Print version info + -w, --write - Write changes to local files (Conflicts: --commit) + -c, --commit - Commit changes to local git repository (Conflicts: --write) + --changelog [commit_types] - Show a curated changelog for each update + --debug - Print debug information + --import-map - Specify import map file + --ignore - Ignore dependencies + --only - Check specified dependencies + --pre-commit - Run tasks before each commit (Depends: --commit) + --prefix - Prefix for commit messages (Depends: --commit) + --prefix-lock - Prefix for commit messages of updating a lock file (Depends: --commit, --unstable-lock) + --unstable-lock [file] - Enable unstable updating of a lock file " `; @@ -44,20 +43,19 @@ Description: Options: - -h, --help - Show this help. - -v, --version - Print version info. - --import-map - Specify import map file - --ignore - Ignore dependencies - --only - Check specified dependencies - -w, --write - Write changes to local files (Conflicts: --commit) - -c, --commit - Commit changes to local git repository (Conflicts: --write) - --pre-commit - Run tasks before each commit (Depends: --commit) - --post-commit - Run tasks after each commit (Depends: --commit) - --prefix - Prefix for commit messages (Depends: --commit) - --prefix-lock - Prefix for commit messages of updating a lock file (Depends: --commit, --unstable-lock) - --summary - Write a summary of changes to file - --report - Write a report of changes to file - --unstable-lock [file] - Enable unstable updating of a lock file + -h, --help - Show this help. + -v, --version - Print version info + -w, --write - Write changes to local files (Conflicts: --commit) + -c, --commit - Commit changes to local git repository (Conflicts: --write) + --changelog [commit_types] - Show a curated changelog for each update + --debug - Print debug information + --import-map - Specify import map file + --ignore - Ignore dependencies + --only - Check specified dependencies + --pre-commit - Run tasks before each commit (Depends: --commit) + --prefix - Prefix for commit messages (Depends: --commit) + --prefix-lock - Prefix for commit messages of updating a lock file (Depends: --commit, --unstable-lock) + --unstable-lock [file] - Enable unstable updating of a lock file " `; @@ -65,7 +63,7 @@ Options: snapshot[`cli - "molt --help" 2`] = `""`; snapshot[`cli - "molt --version" 1`] = ` -"dev +"0.18.0 " `; @@ -180,14 +178,12 @@ snapshot[`cli - "molt multiple_imports.ts --only deno.land --ignore deno_graph" snapshot[`cli - multiple_modules - "molt mod.ts --write" 1`] = ` "📦 deno.land/std 0.200.0 => 0.218.2 - lib.ts 0.200.0 - mod.ts 0.200.0 - + lib.ts + mod.ts 📦 deno.land/x/deno_graph 0.50.0 => 0.69.7 - mod.ts 0.50.0 - + mod.ts 📦 node-emoji 2.0.0 => 2.1.3 - mod.ts 2.0.0 + mod.ts 💾 lib.ts 💾 mod.ts @@ -199,40 +195,14 @@ snapshot[`cli - multiple_modules - "molt mod.ts --write" 2`] = ` " `; -snapshot[`cli - multiple_modules - "molt mod.ts --write --summary title.txt --report body.md" 1`] = ` -"📦 deno.land/std 0.200.0 => 0.218.2 - lib.ts 0.200.0 - mod.ts 0.200.0 - -📦 deno.land/x/deno_graph 0.50.0 => 0.69.7 - mod.ts 0.50.0 - -📦 node-emoji 2.0.0 => 2.1.3 - mod.ts 2.0.0 - -💾 lib.ts -💾 mod.ts - -📄 title.txt -📄 body.md -" -`; - -snapshot[`cli - multiple_modules - "molt mod.ts --write --summary title.txt --report body.md" 2`] = ` -"Checking for updates -" -`; - snapshot[`cli - multiple_modules - "molt mod.ts --commit" 1`] = ` "📦 deno.land/std 0.200.0 => 0.218.2 - lib.ts 0.200.0 - mod.ts 0.200.0 - + lib.ts + mod.ts 📦 deno.land/x/deno_graph 0.50.0 => 0.69.7 - mod.ts 0.50.0 - + mod.ts 📦 node-emoji 2.0.0 => 2.1.3 - mod.ts 2.0.0 + mod.ts 📝 bump deno.land/std from 0.200.0 to 0.218.2 📝 bump deno.land/x/deno_graph from 0.50.0 to 0.69.7 @@ -247,14 +217,12 @@ snapshot[`cli - multiple_modules - "molt mod.ts --commit" 2`] = ` snapshot[`cli - multiple_modules - "molt mod.ts --commit --prefix :package:" 1`] = ` "📦 deno.land/std 0.200.0 => 0.218.2 - lib.ts 0.200.0 - mod.ts 0.200.0 - + lib.ts + mod.ts 📦 deno.land/x/deno_graph 0.50.0 => 0.69.7 - mod.ts 0.50.0 - + mod.ts 📦 node-emoji 2.0.0 => 2.1.3 - mod.ts 2.0.0 + mod.ts 📝 :package: bump deno.land/std from 0.200.0 to 0.218.2 📝 :package: bump deno.land/x/deno_graph from 0.50.0 to 0.69.7 @@ -267,80 +235,14 @@ snapshot[`cli - multiple_modules - "molt mod.ts --commit --prefix :package:" 2`] " `; -snapshot[`cli - multiple_modules - "molt mod.ts --commit --pre-commit=fmt --post-commit=lint" 1`] = ` -"📦 deno.land/std 0.200.0 => 0.218.2 - lib.ts 0.200.0 - mod.ts 0.200.0 - -📦 deno.land/x/deno_graph 0.50.0 => 0.69.7 - mod.ts 0.50.0 - -📦 node-emoji 2.0.0 => 2.1.3 - mod.ts 2.0.0 - -💾 bump deno.land/std from 0.200.0 to 0.218.2 -🔨 Running task fmt... -📝 bump deno.land/std from 0.200.0 to 0.218.2 -🔨 Running task lint... - -💾 bump deno.land/x/deno_graph from 0.50.0 to 0.69.7 -🔨 Running task fmt... -📝 bump deno.land/x/deno_graph from 0.50.0 to 0.69.7 -🔨 Running task lint... - -💾 bump node-emoji from 2.0.0 to 2.1.3 -🔨 Running task fmt... -📝 bump node-emoji from 2.0.0 to 2.1.3 -🔨 Running task lint... -" -`; - -snapshot[`cli - multiple_modules - "molt mod.ts --commit --pre-commit=fmt --post-commit=lint" 2`] = ` -"Checking for updates -Checked 64 files -Checked 35 files -Checked 64 files -Checked 35 files -Checked 64 files -Checked 35 files -" -`; - -snapshot[`cli - multiple_modules - "molt mod.ts --commit --summary title.txt --report body.md" 1`] = ` -"📦 deno.land/std 0.200.0 => 0.218.2 - lib.ts 0.200.0 - mod.ts 0.200.0 - -📦 deno.land/x/deno_graph 0.50.0 => 0.69.7 - mod.ts 0.50.0 - -📦 node-emoji 2.0.0 => 2.1.3 - mod.ts 2.0.0 - -📝 bump deno.land/std from 0.200.0 to 0.218.2 -📝 bump deno.land/x/deno_graph from 0.50.0 to 0.69.7 -📝 bump node-emoji from 2.0.0 to 2.1.3 - -📄 title.txt -📄 body.md -" -`; - -snapshot[`cli - multiple_modules - "molt mod.ts --commit --summary title.txt --report body.md" 2`] = ` -"Checking for updates -" -`; - -snapshot[`cli - multiple_modules - "molt mod.ts --commit --summary title.txt --pre-commit=fmt" 1`] = ` +snapshot[`cli - multiple_modules - "molt mod.ts --commit --pre-commit=fmt" 1`] = ` "📦 deno.land/std 0.200.0 => 0.218.2 - lib.ts 0.200.0 - mod.ts 0.200.0 - + lib.ts + mod.ts 📦 deno.land/x/deno_graph 0.50.0 => 0.69.7 - mod.ts 0.50.0 - + mod.ts 📦 node-emoji 2.0.0 => 2.1.3 - mod.ts 2.0.0 + mod.ts 💾 bump deno.land/std from 0.200.0 to 0.218.2 🔨 Running task fmt... @@ -353,16 +255,14 @@ snapshot[`cli - multiple_modules - "molt mod.ts --commit --summary title.txt --p 💾 bump node-emoji from 2.0.0 to 2.1.3 🔨 Running task fmt... 📝 bump node-emoji from 2.0.0 to 2.1.3 - -📄 title.txt " `; -snapshot[`cli - multiple_modules - "molt mod.ts --commit --summary title.txt --pre-commit=fmt" 2`] = ` +snapshot[`cli - multiple_modules - "molt mod.ts --commit --pre-commit=fmt" 2`] = ` "Checking for updates -Checked 64 files -Checked 64 files -Checked 64 files +Checked 2 files +Checked 2 files +Checked 2 files " `; @@ -468,14 +368,12 @@ Error: No such file or directory (os error 2): readfile 'not_exist.lock' snapshot[`cli - lockfile - "molt deno.json --unstable-lock" 1`] = ` "📦 @core/match 0.1.0 => 0.1.9 - deno.lock 0.1.0 - + deno.lock 📦 deno.land/std 0.200.0 => 0.218.2 - deno.json 0.200.0 - deno.lock 0.200.0 - + deno.json + deno.lock 📦 hono 3.0.0 => 3.12.12 - deno.lock 3.0.0 + deno.lock " `; @@ -486,14 +384,12 @@ snapshot[`cli - lockfile - "molt deno.json --unstable-lock" 2`] = ` snapshot[`cli - lockfile - "molt deno.json --unstable-lock --write" 1`] = ` "📦 @core/match 0.1.0 => 0.1.9 - deno.lock 0.1.0 - + deno.lock 📦 deno.land/std 0.200.0 => 0.218.2 - deno.json 0.200.0 - deno.lock 0.200.0 - + deno.json + deno.lock 📦 hono 3.0.0 => 3.12.12 - deno.lock 3.0.0 + deno.lock 💾 deno.json 💾 deno.lock @@ -507,14 +403,12 @@ snapshot[`cli - lockfile - "molt deno.json --unstable-lock --write" 2`] = ` snapshot[`cli - lockfile - "molt deno.json --commit --unstable-lock --prefix :package: --prefix-lock :lock:" 1`] = ` "📦 @core/match 0.1.0 => 0.1.9 - deno.lock 0.1.0 - + deno.lock 📦 deno.land/std 0.200.0 => 0.218.2 - deno.json 0.200.0 - deno.lock 0.200.0 - + deno.json + deno.lock 📦 hono 3.0.0 => 3.12.12 - deno.lock 3.0.0 + deno.lock 📝 :lock: bump @core/match from 0.1.0 to 0.1.9 📝 :package: bump deno.land/std from 0.200.0 to 0.218.2 diff --git a/test/snapshots/registries.ts.snap b/test/snapshots/registries_test.ts.snap similarity index 100% rename from test/snapshots/registries.ts.snap rename to test/snapshots/registries_test.ts.snap