diff --git a/.github/workflows/docs.yaml b/.github/workflows/docs.yaml new file mode 100644 index 00000000..8edc8592 --- /dev/null +++ b/.github/workflows/docs.yaml @@ -0,0 +1,28 @@ +name: Docs + +on: + push: + branches: + - main + +jobs: + publish-docs: + runs-on: ubuntu-latest + + steps: + - name: Set up Deno + uses: denoland/setup-deno@v1 + with: + deno-version: "2.x" + + - name: Check out the code + uses: actions/checkout@v2 + + - name: Generate documentation + run: deno task doc + + - name: Upload the docs to Val Town Electric + run: cd docs && deno run -A https://esm.town/v/wolf/VTDocs/cli/mod.ts upload + env: + ELECTRIC_ROOT_URL: https://vt-docs.val.run + ELECTRIC_MASTER_BEARER: ${{ secrets.ELECTRIC_MASTER_BEARER }} diff --git a/.gitignore b/.gitignore index c03e4ca0..8459a2d9 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,5 @@ tinker +docs # Created by https://www.toptal.com/developers/gitignore/api/deno # Edit at https://www.toptal.com/developers/gitignore?templates=deno @@ -16,4 +17,4 @@ tinker # End of https://www.toptal.com/developers/gitignore/api/deno -.DS_Store \ No newline at end of file +.DS_Store diff --git a/deno.json b/deno.json index d12b457b..49bb08bb 100644 --- a/deno.json +++ b/deno.json @@ -11,7 +11,9 @@ "test:cmd": "env DENO_NO_PROMPT=1 deno test -A --trace-leaks --fail-fast ./src/cmd", "test:lib": "env DENO_NO_PROMPT=1 deno test -A --trace-leaks --parallel ./src/vt/lib", "check": "env DENO_NO_PROMPT=1 deno check .", - "fmt:check": "env DENO_NO_PROMPT=1 deno fmt --check" + "fmt": "env DENO_NO_PROMPT=1 deno fmt --ignore=docs", + "fmt:check": "env DENO_NO_PROMPT=1 deno fmt --check", + "doc": "deno doc --html --name='vtlib' --output=docs mod.ts" }, "imports": { "@std/random": "jsr:@std/random@^0.1.0", diff --git a/deno.lock b/deno.lock index 20695752..61bbf2b4 100644 --- a/deno.lock +++ b/deno.lock @@ -11,41 +11,37 @@ "jsr:@cliffy/keycode@1.0.0-rc.7": "1.0.0-rc.7", "jsr:@cliffy/prompt@^1.0.0-rc.7": "1.0.0-rc.7", "jsr:@cliffy/table@1.0.0-rc.7": "1.0.0-rc.7", - "jsr:@deno-library/logger@^1.1.9": "1.1.9", "jsr:@jonasschiano/kia@0.0.120": "0.0.120", - "jsr:@std/assert@1": "1.0.12", - "jsr:@std/assert@~1.0.6": "1.0.12", + "jsr:@std/assert@1": "1.0.13", + "jsr:@std/assert@~1.0.6": "1.0.13", "jsr:@std/async@^1.0.11": "1.0.12", "jsr:@std/bytes@^1.0.5": "1.0.5", "jsr:@std/cache@0.2": "0.2.0", - "jsr:@std/collections@^1.0.10": "1.0.10", + "jsr:@std/collections@^1.0.10": "1.0.11", "jsr:@std/dotenv@~0.225.3": "0.225.3", - "jsr:@std/encoding@^1.0.7": "1.0.9", - "jsr:@std/encoding@~1.0.5": "1.0.9", - "jsr:@std/fmt@1.0.3": "1.0.3", + "jsr:@std/encoding@~1.0.5": "1.0.10", "jsr:@std/fmt@1.0.5": "1.0.5", - "jsr:@std/fmt@~1.0.2": "1.0.6", - "jsr:@std/fs@^1.0.13": "1.0.16", - "jsr:@std/fs@^1.0.6": "1.0.16", + "jsr:@std/fmt@~1.0.2": "1.0.7", + "jsr:@std/fs@^1.0.13": "1.0.17", "jsr:@std/internal@^1.0.6": "1.0.6", "jsr:@std/io@~0.224.9": "0.224.9", "jsr:@std/io@~0.225.2": "0.225.2", - "jsr:@std/path@^1.0.8": "1.0.8", - "jsr:@std/path@~1.0.6": "1.0.8", + "jsr:@std/path@^1.0.8": "1.0.9", + "jsr:@std/path@^1.0.9": "1.0.9", + "jsr:@std/path@~1.0.6": "1.0.9", "jsr:@std/random@0.1": "0.1.0", - "jsr:@std/text@^1.0.12": "1.0.12", - "jsr:@std/text@~1.0.7": "1.0.12", - "jsr:@std/yaml@^1.0.5": "1.0.5", - "jsr:@valtown/sdk@1": "1.0.0", - "npm:@types/node@*": "22.12.0", + "jsr:@std/text@^1.0.12": "1.0.13", + "jsr:@std/text@~1.0.7": "1.0.13", + "jsr:@std/yaml@^1.0.5": "1.0.6", + "jsr:@valtown/sdk@1": "1.1.0", "npm:emphasize@7": "7.0.0", "npm:highlight.js@^11.11.1": "11.11.1", - "npm:open@^10.1.0": "10.1.0", + "npm:open@^10.1.0": "10.1.2", "npm:strip-ansi@^7.1.0": "7.1.0", "npm:word-wrap@^1.2.5": "1.2.5", - "npm:zod-to-json-schema@^3.24.5": "3.24.5_zod@3.24.2", - "npm:zod-validation-error@^3.4.0": "3.4.0_zod@3.24.2", - "npm:zod@^3.24.2": "3.24.2" + "npm:zod-to-json-schema@^3.24.5": "3.24.5_zod@3.24.4", + "npm:zod-validation-error@^3.4.0": "3.4.1_zod@3.24.4", + "npm:zod@^3.24.2": "3.24.4" }, "jsr": { "@404wolf/xdg-portable@0.1.0": { @@ -61,7 +57,7 @@ "integrity": "f71c921cce224c13d322e5cedba4f38e8f7354c7d855c9cb22729362a53f25aa", "dependencies": [ "jsr:@cliffy/internal", - "jsr:@std/encoding@~1.0.5", + "jsr:@std/encoding", "jsr:@std/fmt@~1.0.2", "jsr:@std/io@~0.224.9" ] @@ -107,13 +103,6 @@ "jsr:@std/fmt@~1.0.2" ] }, - "@deno-library/logger@1.1.9": { - "integrity": "f7d7347b3bdf85dd3692b501bb27b11d685c53efd90a07bc6a4d6edd01f8511b", - "dependencies": [ - "jsr:@std/fmt@1.0.3", - "jsr:@std/fs@^1.0.6" - ] - }, "@jonasschiano/kia@0.0.120": { "integrity": "6b88a98a10788ada17bde6accae2d807cabc4a610eff86446f7c7c05c8429309", "dependencies": [ @@ -121,8 +110,8 @@ "jsr:@std/io@~0.225.2" ] }, - "@std/assert@1.0.12": { - "integrity": "08009f0926dda9cbd8bef3a35d3b6a4b964b0ab5c3e140a4e0351fbf34af5b9a", + "@std/assert@1.0.13": { + "integrity": "ae0d31e41919b12c656c742b22522c32fb26ed0cba32975cb0de2a273cb68b29", "dependencies": [ "jsr:@std/internal" ] @@ -136,28 +125,25 @@ "@std/cache@0.2.0": { "integrity": "63a2ccd5a9e7c03e430f7d34dfcfd0d0cfc90731a1eaf8208f4c66e418fc3035" }, - "@std/collections@1.0.10": { - "integrity": "903af106a3d92970d74e20f7ebff77d9658af9bef4403f1dc42a7801c0575899" + "@std/collections@1.0.11": { + "integrity": "2f62cf9587484b1fff364f6c3e1f83478eea53dbb6faed6ffeda92ddb6b172f0" }, "@std/dotenv@0.225.3": { "integrity": "a95e5b812c27b0854c52acbae215856d9cce9d4bbf774d938c51d212711e8d4a" }, - "@std/encoding@1.0.9": { - "integrity": "025b8f18eb1749bc30d1353bf48b77d1eb5e35610220fa226f5a046b9240c5d7" - }, - "@std/fmt@1.0.3": { - "integrity": "97765c16aa32245ff4e2204ecf7d8562496a3cb8592340a80e7e554e0bb9149f" + "@std/encoding@1.0.10": { + "integrity": "8783c6384a2d13abd5e9e87a7ae0520a30e9f56aeeaa3bdf910a3eaaf5c811a1" }, "@std/fmt@1.0.5": { "integrity": "0cfab43364bc36650d83c425cd6d99910fc20c4576631149f0f987eddede1a4d" }, - "@std/fmt@1.0.6": { - "integrity": "a2c56a69a2369876ddb3ad6a500bb6501b5bad47bb3ea16bfb0c18974d2661fc" + "@std/fmt@1.0.7": { + "integrity": "2a727c043d8df62cd0b819b3fb709b64dd622e42c3b1bb817ea7e6cc606360fb" }, - "@std/fs@1.0.16": { - "integrity": "81878f62b6eeda0bf546197fc3daa5327c132fee1273f6113f940784a468b036", + "@std/fs@1.0.17": { + "integrity": "1c00c632677c1158988ef7a004cb16137f870aafdb8163b9dce86ec652f3952b", "dependencies": [ - "jsr:@std/path@^1.0.8" + "jsr:@std/path@^1.0.9" ] }, "@std/internal@1.0.6": { @@ -172,23 +158,20 @@ "jsr:@std/bytes" ] }, - "@std/path@1.0.8": { - "integrity": "548fa456bb6a04d3c1a1e7477986b6cffbce95102d0bb447c67c4ee70e0364be" + "@std/path@1.0.9": { + "integrity": "260a49f11edd3db93dd38350bf9cd1b4d1366afa98e81b86167b4e3dd750129e" }, "@std/random@0.1.0": { "integrity": "70a006be0ffb77d036bab54aa8ae6bd0119ba77ace0f2f56f63273d4262a5667" }, - "@std/text@1.0.12": { - "integrity": "921132a41e03a2363f76ee5afe83c90a6271596aa95c137494edcb3404a564a5" + "@std/text@1.0.13": { + "integrity": "2191c90e6e667b0c3b7dea1cd082137580a93b3c136bad597c0212d5fe006eb1" }, - "@std/yaml@1.0.5": { - "integrity": "71ba3d334305ee2149391931508b2c293a8490f94a337eef3a09cade1a2a2742" + "@std/yaml@1.0.6": { + "integrity": "c9a5a914e1d51c46756cb10e356710035cfa905e713c90d3b711413fd3aead27" }, - "@valtown/sdk@0.38.3": { - "integrity": "9348b2ad6f9fd74ed913a46f446160114297daabcc683ccff06e8e57a8b567b8" - }, - "@valtown/sdk@1.0.0": { - "integrity": "dc4fd0865a5b19fcc344dd3f18dd1ce11c8e2f338addeb7317ee62cd3fbd0b0a" + "@valtown/sdk@1.1.0": { + "integrity": "b495098335baf406e862b4a7b6947a93b7420b59433e535001578ec7e2279d3d" } }, "npm": { @@ -198,12 +181,6 @@ "@types/unist" ] }, - "@types/node@22.12.0": { - "integrity": "sha512-Fll2FZ1riMjNmlmJOdAyY5pUbkftXslB5DgEzlIuNaiWhXd00FhWxVC/r4yV/4wBb9JfImTu+jiSvXTkJ7F/gA==", - "dependencies": [ - "undici-types" - ] - }, "@types/unist@3.0.3": { "integrity": "sha512-ko/gIFJRv177XgZsZcBwnqJN5x/Gien8qNOn0D5bQU/zAzVf9Zt3BlcUiLqhV9y4ARk0GbT3tnUiPNgnTXzc/Q==" }, @@ -279,8 +256,8 @@ "highlight.js@11.9.0" ] }, - "open@10.1.0": { - "integrity": "sha512-mnkeQ1qP5Ue2wd+aivTD3NHd/lZ96Lu0jgf0pwktLPtx6cTZiH7tyeGRRHs0zX0rbrahXPnXlUnbeXyaBBuIaw==", + "open@10.1.2": { + "integrity": "sha512-cxN6aIDPz6rm8hbebcP7vrQNhvRcveZoJU72Y7vskh4oIm+BZwBECnx5nTmrlres1Qapvx27Qo1Auukpf8PKXw==", "dependencies": [ "default-browser", "define-lazy-prop", @@ -297,26 +274,23 @@ "ansi-regex" ] }, - "undici-types@6.20.0": { - "integrity": "sha512-Ny6QZ2Nju20vw1SRHe3d9jVu6gJ+4e3+MMpqu7pqE5HT6WsTSlce++GQmK5UXS8mzV8DSYHrQH+Xrf2jVcuKNg==" - }, "word-wrap@1.2.5": { "integrity": "sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==" }, - "zod-to-json-schema@3.24.5_zod@3.24.2": { + "zod-to-json-schema@3.24.5_zod@3.24.4": { "integrity": "sha512-/AuWwMP+YqiPbsJx5D6TfgRTc4kTLjsh5SOcd4bLsfUg2RcEXrFMJl1DGgdHy2aCfsIA/cr/1JM0xcB2GZji8g==", "dependencies": [ "zod" ] }, - "zod-validation-error@3.4.0_zod@3.24.2": { - "integrity": "sha512-ZOPR9SVY6Pb2qqO5XHt+MkkTRxGXb4EVtnjc9JpXUOtUB1T9Ru7mZOT361AN3MsetVe7R0a1KZshJDZdgp9miQ==", + "zod-validation-error@3.4.1_zod@3.24.4": { + "integrity": "sha512-1KP64yqDPQ3rupxNv7oXhf7KdhHHgaqbKuspVoiN93TT0xrBjql+Svjkdjq/Qh/7GSMmgQs3AfvBT0heE35thw==", "dependencies": [ "zod" ] }, - "zod@3.24.2": { - "integrity": "sha512-lY7CDW43ECgW9u1TcT3IoXHflywfVqDYze4waEz812jR/bZ8FHDsl7pFQoSZTz5N+2NqRXs8GBwnAwo3ZNxqhQ==" + "zod@3.24.4": { + "integrity": "sha512-OdqJE9UDRPwWsrHjLN2F8bPxvwJBK22EHLWtanu0LSYr5YqzsaaW3RMgmjwr8Rypg5k+meEJdSPXJZXE/yqOMg==" } }, "workspace": { diff --git a/mod.ts b/mod.ts old mode 100644 new mode 100755 index 912a66d4..2767f53d --- a/mod.ts +++ b/mod.ts @@ -1 +1,81 @@ +#!/usr/bin/env -S deno run --allow-read --allow-write --allow-env --allow-net --allow-sys --allow-run +import { launch } from "./vt.ts"; + +/** + * # vtlib + * + * ### What is `vtlib`? + * `vtlib` is the internal library used by `vt`, the Val Town CLI. `vtlib` lets + * you do `push`ing, `pull`ing, `clone`ing, and more, from a Deno context, so + * that you can reuse much of the internal syncing functionality of `vt`. + * + * Primary library functions include + * + * - {@link checkout} Check out a branch from a Val Town project + * - {@link clone} Clone a Val Town project to a local directory + * - {@link create} Create a new Val Town project from local files + * - {@link pull} Pull changes from a Val Town project to a local directory + * - {@link push} Push local changes to a Val Town project + * - {@link remix} Create a new project based on an existing project + * - {@link status} Check the status of local files compared to a Val Town project + * + * @example Clone a project to a directory + * ```typescript + * import { clone } from "@valtown/vt"; + * + * const result = await clone({ + * projectId: "d23e2d8d-9cc8-40e3-bbf4-107c42efe6c1", + * branchId: "0e73994d-f9bd-4e59-a255-7f4593127623", + * targetDir: "./my-project" + * }); + * ``` + * + * @example Push changes to a project + * ```typescript + * import { push } from "@valtown/vt"; + * + * const result = await push({ + * projectId: "c085baed-ec07-4a2e-811a-216f567b5ef1", + * targetDir: "." + * }); + * ``` + * + * @example Create a new project from local files + * ```typescript + * import { create } from "@valtown/vt"; + * + * const result = await create({ + * projectId: "01b34cb3-f581-47c9-8024-ae126c0f0b1e", + * sourceDir: "./my-code" + * }); + * ``` + * + * @example Check status of local files compared to remote + * ```typescript + * import { status } from "@valtown/vt"; + * + * const result = await status({ + * projectId: "79af7bd7-3e5b-4492-8b14-dac502cdbce6", + * targetDir: "." + * }); + * ``` + * + * @example Remix an existing project + * ```typescript + * import { remix } from "@valtown/vt"; + * + * const result = await remix({ + * srcProjectId: "a35e5f60-5a47-4201-9d82-b6a60bd57d4d", + * projectName: "My Remix", + * targetDir: "./remixed-project" + * }); + * ``` + * + * @module + */ + +if (import.meta.main) { + await launch(); +} + export * from "~/vt/lib/mod.ts"; diff --git a/src/cmd/lib/branch.ts b/src/cmd/lib/branch.ts index 162c529d..09028c66 100644 --- a/src/cmd/lib/branch.ts +++ b/src/cmd/lib/branch.ts @@ -1,5 +1,5 @@ import { Command } from "@cliffy/command"; -import sdk, { branchNameToBranch } from "~/sdk.ts"; +import sdk, { branchNameToBranch } from "../../utils/sdk.ts"; import { colors } from "@cliffy/ansi/colors"; import { Table } from "@cliffy/table"; import { doWithSpinner } from "~/cmd/utils.ts"; diff --git a/src/cmd/lib/browse.ts b/src/cmd/lib/browse.ts index 5889a0cb..5146c465 100644 --- a/src/cmd/lib/browse.ts +++ b/src/cmd/lib/browse.ts @@ -1,6 +1,6 @@ import { Command } from "@cliffy/command"; import open from "open"; -import sdk from "~/sdk.ts"; +import sdk from "../../utils/sdk.ts"; import { doWithSpinner } from "~/cmd/utils.ts"; import VTClient from "~/vt/vt/VTClient.ts"; import { findVtRoot } from "~/vt/vt/utils.ts"; diff --git a/src/cmd/lib/checkout.ts b/src/cmd/lib/checkout.ts index 228d7ee3..8c1c7bda 100644 --- a/src/cmd/lib/checkout.ts +++ b/src/cmd/lib/checkout.ts @@ -6,7 +6,7 @@ import { findVtRoot } from "~/vt/vt/utils.ts"; import { colors } from "@cliffy/ansi/colors"; import { Confirm } from "@cliffy/prompt"; import { tty } from "@cliffy/ansi/tty"; -import sdk, { getCurrentUser } from "~/sdk.ts"; +import sdk, { getCurrentUser } from "../../utils/sdk.ts"; import { displayFileStateChanges } from "~/cmd/lib/utils/displayFileStatus.ts"; import { noChangesDryRunMsg } from "~/cmd/lib/utils/messages.ts"; diff --git a/src/cmd/lib/clone.ts b/src/cmd/lib/clone.ts index 3e122fd8..1e79a31c 100644 --- a/src/cmd/lib/clone.ts +++ b/src/cmd/lib/clone.ts @@ -1,7 +1,7 @@ import { Command } from "@cliffy/command"; import { Input } from "@cliffy/prompt/input"; import { colors } from "@cliffy/ansi/colors"; -import sdk, { getCurrentUser } from "~/sdk.ts"; +import sdk, { getCurrentUser } from "../../utils/sdk.ts"; import VTClient from "~/vt/vt/VTClient.ts"; import { relative } from "@std/path"; import { doWithSpinner, getClonePath } from "~/cmd/utils.ts"; @@ -10,7 +10,7 @@ import { Confirm } from "@cliffy/prompt"; import { ensureAddEditorFiles } from "~/cmd/lib/utils/messages.ts"; import { parseValUrl } from "~/cmd/parsing.ts"; import { DEFAULT_BRANCH_NAME, DEFAULT_EDITOR_TEMPLATE } from "~/consts.ts"; -import { arrayFromAsyncN } from "~/utils.ts"; +import { arrayFromAsyncN } from "~/utils/mod.ts"; export const cloneCmd = new Command() .name("clone") diff --git a/src/cmd/lib/config.ts b/src/cmd/lib/config.ts index 4f5543e9..332e2b5c 100644 --- a/src/cmd/lib/config.ts +++ b/src/cmd/lib/config.ts @@ -2,7 +2,7 @@ import { Command } from "@cliffy/command"; import VTConfig from "~/vt/VTConfig.ts"; import { findVtRoot } from "~/vt/vt/utils.ts"; import { doWithSpinner } from "~/cmd/utils.ts"; -import { getNestedProperty, setNestedProperty } from "~/utils.ts"; +import { getNestedProperty, setNestedProperty } from "../../utils/misc.ts"; import { stringify as stringifyYaml } from "@std/yaml"; import { VTConfigSchema } from "~/vt/vt/schemas.ts"; import { zodToJsonSchema } from "zod-to-json-schema"; diff --git a/src/cmd/lib/create.ts b/src/cmd/lib/create.ts index c5c60cc2..06dcb2aa 100644 --- a/src/cmd/lib/create.ts +++ b/src/cmd/lib/create.ts @@ -1,7 +1,7 @@ import { Command } from "@cliffy/command"; import { basename } from "@std/path"; import VTClient from "~/vt/vt/VTClient.ts"; -import { getCurrentUser } from "~/sdk.ts"; +import { getCurrentUser } from "../../utils/sdk.ts"; import { APIError } from "@valtown/sdk"; import { doWithSpinner, getClonePath } from "~/cmd/utils.ts"; import { ensureAddEditorFiles } from "~/cmd/lib/utils/messages.ts"; diff --git a/src/cmd/lib/delete.ts b/src/cmd/lib/delete.ts index c0ed4168..092e1b9a 100644 --- a/src/cmd/lib/delete.ts +++ b/src/cmd/lib/delete.ts @@ -2,7 +2,7 @@ import { Command } from "@cliffy/command"; import VTClient from "~/vt/vt/VTClient.ts"; import { doWithSpinner } from "~/cmd/utils.ts"; import { Confirm } from "@cliffy/prompt"; -import sdk from "~/sdk.ts"; +import sdk from "../../utils/sdk.ts"; import { findVtRoot } from "~/vt/vt/utils.ts"; import { colors } from "@cliffy/ansi/colors"; diff --git a/src/cmd/lib/list.ts b/src/cmd/lib/list.ts index f99e09b6..45ac2766 100644 --- a/src/cmd/lib/list.ts +++ b/src/cmd/lib/list.ts @@ -1,9 +1,9 @@ import { Command } from "@cliffy/command"; import { colors } from "@cliffy/ansi/colors"; import { Table } from "@cliffy/table"; -import sdk from "~/sdk.ts"; +import sdk from "../../utils/sdk.ts"; import { doWithSpinner } from "~/cmd/utils.ts"; -import { arrayFromAsyncN } from "~/utils.ts"; +import { arrayFromAsyncN } from "~/utils/mod.ts"; const VAL_LIST_BATCH_SIZE = 20; diff --git a/src/cmd/lib/push.ts b/src/cmd/lib/push.ts index 8846de97..8cdb0897 100644 --- a/src/cmd/lib/push.ts +++ b/src/cmd/lib/push.ts @@ -2,7 +2,7 @@ import { Command } from "@cliffy/command"; import { doWithSpinner } from "~/cmd/utils.ts"; import VTClient from "~/vt/vt/VTClient.ts"; import { findVtRoot } from "~/vt/vt/utils.ts"; -import sdk, { getCurrentUser } from "~/sdk.ts"; +import sdk, { getCurrentUser } from "../../utils/sdk.ts"; import { displayFileStateChanges } from "~/cmd/lib/utils/displayFileStatus.ts"; import { noChangesDryRunMsg } from "~/cmd/lib/utils/messages.ts"; diff --git a/src/cmd/lib/remix.ts b/src/cmd/lib/remix.ts index 66aeb210..388c6bd4 100644 --- a/src/cmd/lib/remix.ts +++ b/src/cmd/lib/remix.ts @@ -1,7 +1,6 @@ import { Command } from "@cliffy/command"; import { join } from "@std/path"; import VTClient from "~/vt/vt/VTClient.ts"; -import { getCurrentUser, valExists } from "~/sdk.ts"; import { APIError } from "@valtown/sdk"; import { doWithSpinner } from "~/cmd/utils.ts"; import { parseValUrl } from "~/cmd/parsing.ts"; @@ -9,6 +8,7 @@ import { randomIntegerBetween } from "@std/random"; import { ensureAddEditorFiles } from "~/cmd/lib/utils/messages.ts"; import { Confirm } from "@cliffy/prompt"; import { DEFAULT_EDITOR_TEMPLATE } from "~/consts.ts"; +import { getCurrentUser, valExists } from "~/utils/sdk.ts"; export const remixCmd = new Command() .name("remix") diff --git a/src/cmd/lib/status.ts b/src/cmd/lib/status.ts index 15ab4d2d..d830fe04 100644 --- a/src/cmd/lib/status.ts +++ b/src/cmd/lib/status.ts @@ -1,6 +1,6 @@ import { Command } from "@cliffy/command"; import { colors } from "@cliffy/ansi/colors"; -import sdk from "~/sdk.ts"; +import sdk from "../../utils/sdk.ts"; import { FIRST_VERSION_NUMBER } from "~/consts.ts"; import { doWithSpinner } from "~/cmd/utils.ts"; import VTClient from "~/vt/vt/VTClient.ts"; diff --git a/src/cmd/lib/watch.ts b/src/cmd/lib/watch.ts index c4f58d6a..70d002bd 100644 --- a/src/cmd/lib/watch.ts +++ b/src/cmd/lib/watch.ts @@ -1,7 +1,7 @@ import { Command } from "@cliffy/command"; import VTClient from "~/vt/vt/VTClient.ts"; import { colors } from "@cliffy/ansi/colors"; -import sdk from "~/sdk.ts"; +import sdk from "../../utils/sdk.ts"; import { FIRST_VERSION_NUMBER } from "~/consts.ts"; import { doWithSpinner } from "~/cmd/utils.ts"; import { findVtRoot } from "~/vt/vt/utils.ts"; diff --git a/src/cmd/tests/branch_test.ts b/src/cmd/tests/branch_test.ts index 87860b3d..2586045c 100644 --- a/src/cmd/tests/branch_test.ts +++ b/src/cmd/tests/branch_test.ts @@ -1,6 +1,6 @@ import { doWithNewVal } from "~/vt/lib/tests/utils.ts"; import { join } from "@std/path"; -import sdk from "~/sdk.ts"; +import sdk from "../../utils/sdk.ts"; import { runVtCommand } from "~/cmd/tests/utils.ts"; import { assert, assertEquals, assertStringIncludes } from "@std/assert"; import type ValTown from "@valtown/sdk"; diff --git a/src/cmd/tests/checkout_test.ts b/src/cmd/tests/checkout_test.ts index 88eeb751..548ece96 100644 --- a/src/cmd/tests/checkout_test.ts +++ b/src/cmd/tests/checkout_test.ts @@ -1,7 +1,7 @@ import { doWithNewVal } from "~/vt/lib/tests/utils.ts"; import { doWithTempDir } from "~/vt/lib/utils/misc.ts"; import { join } from "@std/path"; -import sdk from "~/sdk.ts"; +import sdk from "../../utils/sdk.ts"; import { runVtCommand } from "~/cmd/tests/utils.ts"; import { assert, assertStringIncludes } from "@std/assert"; import { exists } from "@std/fs"; diff --git a/src/cmd/tests/clone_test.ts b/src/cmd/tests/clone_test.ts index f9165509..1e2121bc 100644 --- a/src/cmd/tests/clone_test.ts +++ b/src/cmd/tests/clone_test.ts @@ -13,7 +13,7 @@ import { waitForStable, } from "~/cmd/tests/utils.ts"; import { doWithTempDir } from "~/vt/lib/utils/misc.ts"; -import sdk, { getCurrentUser, randomValName } from "~/sdk.ts"; +import sdk, { getCurrentUser, randomValName } from "~/utils/sdk.ts"; import type { ValFileType } from "~/types.ts"; Deno.test({ diff --git a/src/cmd/tests/create_test.ts b/src/cmd/tests/create_test.ts index 3aee622d..0c6c2f59 100644 --- a/src/cmd/tests/create_test.ts +++ b/src/cmd/tests/create_test.ts @@ -3,7 +3,7 @@ import { exists } from "@std/fs"; import { join } from "@std/path"; import type ValTown from "@valtown/sdk"; import { doWithTempDir } from "~/vt/lib/utils/misc.ts"; -import sdk, { getCurrentUser, randomValName } from "~/sdk.ts"; +import sdk, { getCurrentUser, randomValName } from "~/utils/sdk.ts"; import { runVtCommand } from "~/cmd/tests/utils.ts"; Deno.test({ diff --git a/src/cmd/tests/delete_test.ts b/src/cmd/tests/delete_test.ts index dc701715..6b6378b4 100644 --- a/src/cmd/tests/delete_test.ts +++ b/src/cmd/tests/delete_test.ts @@ -3,7 +3,7 @@ import { doWithTempDir } from "~/vt/lib/utils/misc.ts"; import { join } from "@std/path"; import { runVtCommand, runVtProc } from "~/cmd/tests/utils.ts"; import { assert, assertStringIncludes } from "@std/assert"; -import { valExists } from "~/sdk.ts"; +import { valExists } from "~/utils/sdk.ts"; import stripAnsi from "strip-ansi"; import { exists } from "@std/fs"; import { META_FOLDER_NAME } from "~/consts.ts"; diff --git a/src/cmd/tests/pull_test.ts b/src/cmd/tests/pull_test.ts index 74fe3f4b..e694e978 100644 --- a/src/cmd/tests/pull_test.ts +++ b/src/cmd/tests/pull_test.ts @@ -1,6 +1,6 @@ import { doWithNewVal } from "~/vt/lib/tests/utils.ts"; import { join } from "@std/path"; -import sdk from "~/sdk.ts"; +import sdk from "../../utils/sdk.ts"; import { removeAllEditorFiles, runVtCommand } from "~/cmd/tests/utils.ts"; import { assertStringIncludes } from "@std/assert"; import { doWithTempDir } from "~/vt/lib/utils/misc.ts"; diff --git a/src/cmd/tests/push_test.ts b/src/cmd/tests/push_test.ts index 3e3eabcc..f4f09ec2 100644 --- a/src/cmd/tests/push_test.ts +++ b/src/cmd/tests/push_test.ts @@ -1,6 +1,6 @@ import { doWithNewVal } from "~/vt/lib/tests/utils.ts"; import { join } from "@std/path"; -import sdk from "~/sdk.ts"; +import sdk from "../../utils/sdk.ts"; import { runVtCommand } from "~/cmd/tests/utils.ts"; import { assertStringIncludes } from "@std/assert"; import { doWithTempDir } from "~/vt/lib/utils/misc.ts"; diff --git a/src/cmd/tests/remix_test.ts b/src/cmd/tests/remix_test.ts index 53e51e00..75fc5efb 100644 --- a/src/cmd/tests/remix_test.ts +++ b/src/cmd/tests/remix_test.ts @@ -1,6 +1,6 @@ import { doWithNewVal } from "~/vt/lib/tests/utils.ts"; import { join } from "@std/path"; -import sdk, { getCurrentUser } from "~/sdk.ts"; +import sdk, { getCurrentUser } from "../../utils/sdk.ts"; import { runVtCommand } from "~/cmd/tests/utils.ts"; import { assert, assertStringIncludes } from "@std/assert"; import { exists } from "@std/fs"; diff --git a/src/cmd/tests/status_test.ts b/src/cmd/tests/status_test.ts index 646aa977..67ddc13e 100644 --- a/src/cmd/tests/status_test.ts +++ b/src/cmd/tests/status_test.ts @@ -1,6 +1,6 @@ import { doWithNewVal } from "~/vt/lib/tests/utils.ts"; import { join } from "@std/path"; -import sdk from "~/sdk.ts"; +import sdk from "../../utils/sdk.ts"; import { runVtCommand } from "~/cmd/tests/utils.ts"; import { assertStringIncludes } from "@std/assert"; import { doWithTempDir } from "~/vt/lib/utils/misc.ts"; diff --git a/src/cmd/tests/utils.ts b/src/cmd/tests/utils.ts index 1b5292f8..ca4db58d 100644 --- a/src/cmd/tests/utils.ts +++ b/src/cmd/tests/utils.ts @@ -7,7 +7,7 @@ import sdk, { getCurrentUser, getLatestVersion, listValItems, -} from "~/sdk.ts"; +} from "~/utils/sdk.ts"; import { ENTRYPOINT_NAME } from "~/consts.ts"; import { doWithTempDir } from "~/vt/lib/utils/misc.ts"; import { parseValUri } from "~/cmd/lib/utils/parsing.ts"; diff --git a/src/cmd/tests/watch_test.ts b/src/cmd/tests/watch_test.ts index af15c4a8..e2c96588 100644 --- a/src/cmd/tests/watch_test.ts +++ b/src/cmd/tests/watch_test.ts @@ -4,7 +4,7 @@ import { assert } from "@std/assert"; import { exists } from "@std/fs"; import { delay } from "@std/async"; import VTClient from "~/vt/vt/VTClient.ts"; -import { getLatestVersion, listValItems, valItemExists } from "~/sdk.ts"; +import { getLatestVersion, listValItems, valItemExists } from "~/utils/sdk.ts"; import { runVtCommand, streamVtCommand, diff --git a/src/utils.ts b/src/utils/misc.ts similarity index 100% rename from src/utils.ts rename to src/utils/misc.ts diff --git a/src/utils/mod.ts b/src/utils/mod.ts new file mode 100644 index 00000000..ec1585dc --- /dev/null +++ b/src/utils/mod.ts @@ -0,0 +1,2 @@ +export * from "./sdk.ts"; +export * from "./misc.ts"; diff --git a/src/sdk.ts b/src/utils/sdk.ts similarity index 82% rename from src/sdk.ts rename to src/utils/sdk.ts index 1f119826..664a0c94 100644 --- a/src/sdk.ts +++ b/src/utils/sdk.ts @@ -120,20 +120,27 @@ export async function valItemExists( * @param options.filePath - The file path to locate * @returns Promise resolving to the file data or undefined if not found */ -export const getValItem = memoize(async ( +export const getValItem: ( valId: string, branchId: string, version: number, filePath: string, -): Promise => { - const valItems = await listValItems(valId, branchId, version); - - for (const filepath of valItems) { - if (filepath.path === filePath) return filepath; - } +) => Promise = memoize( + async ( + valId: string, + branchId: string, + version: number, + filePath: string, + ) => { + const valItems = await listValItems(valId, branchId, version); + + for (const filepath of valItems) { + if (filepath.path === filePath) return filepath; + } - return undefined; -}); + return undefined; + }, +); /** * Lists all file paths in a Val with pagination support. @@ -146,16 +153,22 @@ export const getValItem = memoize(async ( * @param [params.options.recursive] Whether to recursively list files in subdirectories * @returns Promise resolving to a Set of file paths */ -export const listValItems = memoize(async ( +export const listValItems: ( + valId: string, + branchId: string, + version: number, +) => Promise = memoize(async ( valId: string, branchId: string, version: number, -): Promise => { - const files: ValTown.Vals.FileRetrieveResponse[] = []; +) => { + const files: ValTown.Vals.Files.FileRetrieveResponse[] = []; - branchId = branchId || - (await branchNameToBranch(valId, DEFAULT_BRANCH_NAME) + // If branchId is not provided, get the default branch id + if (!branchId) { + branchId = (await branchNameToBranch(valId, DEFAULT_BRANCH_NAME) .then((resp) => resp.id))!; + } for await ( const file of sdk.vals.files.retrieve(valId, { @@ -164,7 +177,9 @@ export const listValItems = memoize(async ( version, recursive: true, }) - ) files.push(file); + ) { + files.push(file); + } return files; }); @@ -172,22 +187,29 @@ export const listValItems = memoize(async ( /** * Get the latest version of a branch. */ -export async function getLatestVersion(valId: string, branchId: string) { +export async function getLatestVersion( + valId: string, + branchId: string, +): Promise { return (await sdk.vals.branches.retrieve(valId, branchId)).version; } /** * Generate a random (valid) Val name. Useful for tests. */ -export function randomValName(label = "") { +export function randomValName(label = ""): string { return `a${crypto.randomUUID().replaceAll("-", "").slice(0, 10)}_${label}`; } /** * Get the owner of the API key used to auth the current ValTown instance. */ -export const getCurrentUser = memoize(async () => { - return await sdk.me.profile.retrieve(); -}); +export const getCurrentUser: () => Promise< + ValTown.Me.Profile.ProfileRetrieveResponse +> = memoize( + async () => { + return await sdk.me.profile.retrieve(); + }, +); export default sdk; diff --git a/src/vt/lib/mod.ts b/src/vt/lib/mod.ts index 5edb870f..dc79c548 100644 --- a/src/vt/lib/mod.ts +++ b/src/vt/lib/mod.ts @@ -1,7 +1,12 @@ -export { checkout } from "./checkout.ts"; -export { clone } from "./clone.ts"; -export { create } from "./create.ts"; -export { pull } from "./pull.ts"; -export { push } from "./push.ts"; -export { remix } from "./remix.ts"; -export { status } from "./status.ts"; +/** + * Core functionalities of the Val Town CLI. It includes modules for checking + * out, cloning, creating, pulling, pushing, remixing, and checking the status + * of Val Town projects. + */ + +export type { ItemStatusManager } from "./utils/ItemStatusManager.ts"; +export { getValItemType } from "./utils/paths.ts"; +export type * from "~/types.ts"; + +export * from "./vals/mod.ts"; +export * as utils from "../../utils/mod.ts"; diff --git a/src/vt/lib/tests/checkout_test.ts b/src/vt/lib/tests/checkout_test.ts index 13cdf859..dd10b385 100644 --- a/src/vt/lib/tests/checkout_test.ts +++ b/src/vt/lib/tests/checkout_test.ts @@ -1,11 +1,11 @@ import { doWithNewVal } from "~/vt/lib/tests/utils.ts"; -import sdk, { branchExists, getLatestVersion } from "~/sdk.ts"; -import { checkout } from "~/vt/lib/checkout.ts"; +import sdk, { branchExists, getLatestVersion } from "~/utils/sdk.ts"; import { assert, assertEquals } from "@std/assert"; import { join } from "@std/path"; import { exists } from "@std/fs"; import type ValTown from "@valtown/sdk"; import { doWithTempDir } from "~/vt/lib/utils/misc.ts"; +import { checkout } from "~/vt/lib/mod.ts"; Deno.test({ name: "test cross branch checkout", @@ -40,7 +40,7 @@ Deno.test({ await doWithTempDir(async (tempDir) => { // Checkout main branch - await checkout({ + await checkout.checkout({ targetDir: tempDir, valId: val.id, toBranchId: mainBranch.id, @@ -64,7 +64,7 @@ Deno.test({ ); // Checkout feature branch - const result = await checkout({ + const result = await checkout.checkout({ targetDir: tempDir, valId: val.id, toBranchId: featureBranch.id, @@ -113,7 +113,7 @@ Deno.test({ await doWithTempDir(async (tempDir) => { // Checkout main branch - await checkout({ + await checkout.checkout({ targetDir: tempDir, valId: val.id, toBranchId: mainBranch.id, @@ -128,7 +128,7 @@ Deno.test({ ); // Create and checkout a new branch - const result = await checkout({ + const result = await checkout.checkout({ targetDir: tempDir, valId: val.id, forkedFromId: mainBranch.id, @@ -157,7 +157,7 @@ Deno.test({ ); // Switch back to main branch - await checkout({ + await checkout.checkout({ targetDir: tempDir, valId: val.id, toBranchId: mainBranch.id, @@ -210,7 +210,7 @@ Deno.test({ await doWithTempDir(async (tempDir) => { // Checkout main branch - await checkout({ + await checkout.checkout({ targetDir: tempDir, valId: val.id, toBranchId: mainBranch.id, @@ -241,7 +241,7 @@ Deno.test({ ); // Checkout feature branch - await checkout({ + await checkout.checkout({ targetDir: tempDir, valId: val.id, toBranchId: featureBranch.id, @@ -309,7 +309,7 @@ Deno.test({ // First temp directory for feature branch checkout await doWithTempDir(async (featureTempDir) => { await t.step("checkout feature branch", async () => { - await checkout({ + await checkout.checkout({ targetDir: featureTempDir, valId: val.id, toBranchId: featureBranch.id, @@ -333,7 +333,7 @@ Deno.test({ // Second temp directory for main branch checkout await doWithTempDir(async (mainTempDir) => { await t.step("checkout main branch", async () => { - await checkout({ + await checkout.checkout({ targetDir: mainTempDir, valId: val.id, toBranchId: mainBranch.id, @@ -377,7 +377,7 @@ Deno.test({ await t.step("test dry run for new branch creation", async () => { await doWithTempDir(async (tempDir) => { // Try to create new branch with dryRun - const result = await checkout({ + const result = await checkout.checkout({ targetDir: tempDir, valId: val.id, forkedFromId: mainBranch.id, @@ -401,7 +401,7 @@ Deno.test({ ); // Checkout a second time, and expect no changes - await checkout({ + await checkout.checkout({ targetDir: tempDir, valId: val.id, toBranchId: mainBranch.id, @@ -420,7 +420,7 @@ Deno.test({ await doWithTempDir(async (tempDir) => { // Checkout main branch to temp dir first (actual checkout, not dry // run) - await checkout({ + await checkout.checkout({ targetDir: tempDir, valId: val.id, toBranchId: mainBranch.id, @@ -434,7 +434,7 @@ Deno.test({ await Deno.writeTextFile(localFilePath, modifiedContent); // Run checkout with dryRun - const result = await checkout({ + const result = await checkout.checkout({ targetDir: tempDir, valId: val.id, toBranchId: mainBranch.id, @@ -476,7 +476,7 @@ Deno.test({ await doWithTempDir(async (tempDir) => { // Checkout main branch - await checkout({ + await checkout.checkout({ targetDir: tempDir, valId: val.id, toBranchId: mainBranch.id, @@ -499,7 +499,7 @@ Deno.test({ await Deno.writeTextFile(originalFilePath, "modified content"); // Create and checkout a new branch (equivalent to checkout -b) - const result = await checkout({ + const result = await checkout.checkout({ targetDir: tempDir, valId: val.id, forkedFromId: mainBranch.id, @@ -549,7 +549,7 @@ Deno.test({ }); // Checkout main branch again to verify changes aren't there - await checkout({ + await checkout.checkout({ targetDir: tempDir, valId: val.id, toBranchId: mainBranch.id, diff --git a/src/vt/lib/tests/clone_test.ts b/src/vt/lib/tests/clone_test.ts index 4e4e3c10..9d91157d 100644 --- a/src/vt/lib/tests/clone_test.ts +++ b/src/vt/lib/tests/clone_test.ts @@ -1,11 +1,11 @@ import { doWithNewVal } from "~/vt/lib/tests/utils.ts"; import { doWithTempDir } from "~/vt/lib/utils/misc.ts"; -import sdk from "~/sdk.ts"; -import { clone } from "~/vt/lib/clone.ts"; import { assertEquals } from "@std/assert"; import { join } from "@std/path"; import { exists } from "@std/fs"; import type { ValFileType } from "~/types.ts"; +import sdk from "~/utils/sdk.ts"; +import { clone } from "~/vt/lib/mod.ts"; Deno.test({ name: "test typical cloning", @@ -81,7 +81,7 @@ Deno.test({ await doWithTempDir(async (tempDir) => { await t.step("verify cloned files", async () => { // Clone the Val to the temp directory - await clone({ + await clone.clone({ targetDir: tempDir, valId: val.id, branchId: branch.id, @@ -144,7 +144,7 @@ Deno.test({ await doWithTempDir(async (tempDir) => { await t.step("clone the val", async () => { // Clone the Val to the temp directory - await clone({ + await clone.clone({ targetDir: tempDir, valId: val.id, branchId: branch.id, diff --git a/src/vt/lib/tests/pull_test.ts b/src/vt/lib/tests/pull_test.ts index 1597732b..d96b1fce 100644 --- a/src/vt/lib/tests/pull_test.ts +++ b/src/vt/lib/tests/pull_test.ts @@ -1,10 +1,10 @@ import { doWithNewVal } from "~/vt/lib/tests/utils.ts"; -import sdk, { getLatestVersion } from "~/sdk.ts"; -import { pull } from "~/vt/lib/pull.ts"; import { assert, assertEquals } from "@std/assert"; import { join } from "@std/path"; import { exists } from "@std/fs"; import { doWithTempDir } from "~/vt/lib/utils/misc.ts"; +import sdk, { getLatestVersion } from "~/utils/sdk.ts"; +import { pull } from "~/vt/lib/mod.ts"; Deno.test({ name: "test typical pulling", @@ -29,7 +29,7 @@ Deno.test({ }); await doWithTempDir(async (tempDir) => { - await pull({ + await pull.pull({ targetDir: tempDir, valId: val.id, branchId: branch.id, @@ -70,7 +70,7 @@ Deno.test({ ); // Pull updates - await pull({ + await pull.pull({ targetDir: tempDir, valId: val.id, branchId: branch.id, @@ -99,7 +99,7 @@ Deno.test({ ); // Pull updates - await pull({ + await pull.pull({ targetDir: tempDir, valId: val.id, branchId: branch.id, @@ -146,7 +146,7 @@ Deno.test({ await Deno.writeTextFile(localIgnoredPath, "Ignored local file"); // Pull with gitignore rules - await pull({ + await pull.pull({ targetDir: tempDir, valId: val.id, branchId: branch.id, @@ -206,7 +206,7 @@ Deno.test({ await t.step("perform dry run pull", async () => { // Run pull with dryRun option - const { itemStateChanges } = await pull({ + const { itemStateChanges } = await pull.pull({ targetDir: tempDir, valId: val.id, branchId: branch.id, @@ -237,7 +237,7 @@ Deno.test({ }); // Now actually pull the file so we can test modifications - await pull({ + await pull.pull({ targetDir: tempDir, valId: val.id, branchId: branch.id, @@ -257,7 +257,7 @@ Deno.test({ ); // Run pull with dryRun option - const { itemStateChanges } = await pull({ + const { itemStateChanges } = await pull.pull({ targetDir: tempDir, valId: val.id, branchId: branch.id, @@ -313,7 +313,7 @@ Deno.test({ await t.step("pull that creates directories", async () => { // Pull the project to the temp directory - const { itemStateChanges: firstPullChanges } = await pull({ + const { itemStateChanges: firstPullChanges } = await pull.pull({ targetDir: tempDir, valId: val.id, branchId: branch.id, @@ -339,7 +339,7 @@ Deno.test({ await t.step("pull that should not detect changes", async () => { // Pull again - should not detect changes - const { itemStateChanges: secondPullChanges } = await pull({ + const { itemStateChanges: secondPullChanges } = await pull.pull({ targetDir: tempDir, valId: val.id, branchId: branch.id, diff --git a/src/vt/lib/tests/push_test.ts b/src/vt/lib/tests/push_test.ts index 63aa6b19..c901acea 100644 --- a/src/vt/lib/tests/push_test.ts +++ b/src/vt/lib/tests/push_test.ts @@ -1,9 +1,13 @@ import { doWithNewVal } from "~/vt/lib/tests/utils.ts"; -import sdk, { getLatestVersion, listValItems, valItemExists } from "~/sdk.ts"; -import { push } from "~/vt/lib/push.ts"; import { assert, assertEquals } from "@std/assert"; import { join } from "@std/path"; import { doWithTempDir } from "~/vt/lib/utils/misc.ts"; +import { push } from "~/vt/lib/mod.ts"; +import sdk, { + getLatestVersion, + listValItems, + valItemExists, +} from "~/utils/sdk.ts"; Deno.test({ name: "test renaming file at root", @@ -15,7 +19,7 @@ Deno.test({ // Create and push the original file await Deno.writeTextFile(oldFilePath, "root file content"); - await push({ + await push.push({ targetDir: tempDir, valId: val.id, branchId: branch.id, @@ -26,7 +30,7 @@ Deno.test({ await Deno.rename(oldFilePath, newFilePath); // Push the renamed file - const { itemStateChanges: result } = await push({ + const { itemStateChanges: result } = await push.push({ targetDir: tempDir, valId: val.id, branchId: branch.id, @@ -80,7 +84,7 @@ Deno.test({ await Deno.writeTextFile(initialFilePath, "test content"); // Push the file in subdirectory - const { itemStateChanges: firstPush } = await push({ + const { itemStateChanges: firstPush } = await push.push({ targetDir: tempDir, valId: val.id, branchId: branch.id, @@ -104,7 +108,7 @@ Deno.test({ await Deno.writeTextFile(rootFilePath, "test content"); // Push the moved file - const { itemStateChanges: secondPush } = await push({ + const { itemStateChanges: secondPush } = await push.push({ targetDir: tempDir, valId: val.id, branchId: branch.id, @@ -116,7 +120,7 @@ Deno.test({ await t.step("ensure push is idempotent", async () => { // Push again with no changes - const { itemStateChanges: thirdPush } = await push({ + const { itemStateChanges: thirdPush } = await push.push({ targetDir: tempDir, valId: val.id, branchId: branch.id, @@ -150,7 +154,7 @@ Deno.test({ await Deno.utime(join(valDir, "file1.ts"), 0, 0); // Push initial files - await push({ + await push.push({ targetDir: tempDir, valId: val.id, branchId: branch.id, @@ -171,7 +175,7 @@ Deno.test({ await Deno.writeTextFile(join(valDir, "newfile2.ts"), sameContent); // Push changes - const { itemStateChanges: result } = await push({ + const { itemStateChanges: result } = await push.push({ targetDir: tempDir, valId: val.id, branchId: branch.id, @@ -232,7 +236,7 @@ Deno.test({ await t.step("create a file and push it", async () => { await Deno.writeTextFile(originalFilePath, fileContent); - await push({ + await push.push({ targetDir: tempDir, valId: val.id, branchId: branch.id, @@ -262,7 +266,7 @@ Deno.test({ await Deno.writeTextFile(newFilePath, fileContent); // Push the changes - await push({ + await push.push({ targetDir: tempDir, valId: val.id, branchId: branch.id, @@ -320,7 +324,7 @@ Deno.test({ await t.step("create a file and push it", async () => { await Deno.writeTextFile(localFilePath, "test"); - await push({ + await push.push({ targetDir: tempDir, valId: val.id, branchId: branch.id, @@ -341,7 +345,7 @@ Deno.test({ await t.step("modify the file and push changes", async () => { await Deno.writeTextFile(localFilePath, "test2"); - await push({ + await push.push({ targetDir: tempDir, valId: val.id, branchId: branch.id, @@ -359,7 +363,7 @@ Deno.test({ await t.step("delete the file and push deletion", async () => { await Deno.remove(localFilePath); - await push({ + await push.push({ targetDir: tempDir, valId: val.id, branchId: branch.id, @@ -394,7 +398,7 @@ Deno.test({ "unchanged content", ); - await push({ + await push.push({ targetDir: tempDir, valId: val.id, branchId: branch.id, @@ -416,7 +420,7 @@ Deno.test({ ); // Push renamed file - const { itemStateChanges: statusResult } = await push({ + const { itemStateChanges: statusResult } = await push.push({ targetDir: tempDir, valId: val.id, branchId: branch.id, @@ -464,7 +468,7 @@ Deno.test({ "content", ); - await push({ + await push.push({ targetDir: tempDir, valId: val.id, branchId: branch.id, @@ -486,7 +490,7 @@ Deno.test({ await Deno.writeTextFile(join(valDir, "new.tsx"), "contentt"); // Push renamed file - const { itemStateChanges: statusResult } = await push({ + const { itemStateChanges: statusResult } = await push.push({ targetDir: tempDir, valId: val.id, branchId: branch.id, @@ -547,7 +551,7 @@ Deno.test({ await Deno.mkdir(emptyDirPath, { recursive: true }); // Push the empty directory - const { itemStateChanges: pushResult } = await push({ + const { itemStateChanges: pushResult } = await push.push({ targetDir: tempDir, valId: val.id, branchId: branch.id, @@ -593,7 +597,7 @@ Deno.test({ await Deno.writeTextFile(localFilePath, "test content"); // Push with dryRun enabled - const { itemStateChanges: result } = await push({ + const { itemStateChanges: result } = await push.push({ targetDir: tempDir, valId: val.id, branchId: branch.id, @@ -631,7 +635,7 @@ Deno.test({ await Deno.writeTextFile(localFilePath, "test content"); // Do the push - const { itemStateChanges: firstResult } = await push({ + const { itemStateChanges: firstResult } = await push.push({ targetDir: tempDir, valId: val.id, branchId: branch.id, @@ -643,7 +647,7 @@ Deno.test({ assertEquals(firstResult.created.length, 1); assertEquals(firstResult.size(), 1); - const { itemStateChanges: secondResult } = await push({ + const { itemStateChanges: secondResult } = await push.push({ targetDir: tempDir, valId: val.id, branchId: branch.id, @@ -683,7 +687,7 @@ Deno.test({ await t.step("push and verify warnings", async () => { // Push all files - const { itemStateChanges } = await push({ + const { itemStateChanges } = await push.push({ targetDir: tempDir, valId: val.id, branchId: branch.id, @@ -773,7 +777,7 @@ Deno.test({ await Deno.writeTextFile(anotherFilePath, "another file content"); // First push to establish files on the server - const { itemStateChanges: initialPush } = await push({ + const { itemStateChanges: initialPush } = await push.push({ targetDir: tempDir, valId: val.id, branchId: branch.id, @@ -796,7 +800,7 @@ Deno.test({ await Deno.writeTextFile(anotherFilePath, "updated another content"); // Try to push all changes - const { itemStateChanges: secondPush } = await push({ + const { itemStateChanges: secondPush } = await push.push({ targetDir: tempDir, valId: val.id, branchId: branch.id, diff --git a/src/vt/lib/tests/remix_test.ts b/src/vt/lib/tests/remix_test.ts index 1b496c61..cb2d3c38 100644 --- a/src/vt/lib/tests/remix_test.ts +++ b/src/vt/lib/tests/remix_test.ts @@ -1,10 +1,10 @@ import { assert, assertEquals } from "@std/assert"; import { join } from "@std/path"; -import { exists } from "@std/fs"; -import { remix } from "~/vt/lib/remix.ts"; -import { doWithTempDir } from "~/vt/lib/utils/misc.ts"; import { doWithNewVal } from "~/vt/lib/tests/utils.ts"; -import sdk, { getCurrentUser } from "~/sdk.ts"; +import sdk, { getCurrentUser } from "~/utils/sdk.ts"; +import { remix } from "~/vt/lib/mod.ts"; +import { doWithTempDir } from "~/vt/lib/utils/misc.ts"; +import { exists } from "@std/fs"; Deno.test({ name: "remix preserves HTTP Val type", @@ -31,7 +31,7 @@ Deno.test({ // Remix the val await t.step("remix Val with HTTP val", async () => { - const result = await remix({ + const result = await remix.remix({ targetDir: destTmpDir, srcValId: val.id, srcBranchId: "main", @@ -95,7 +95,7 @@ Deno.test({ const remixedValName = `${val.name}_private`; // Remix as private val - const result = await remix({ + const result = await remix.remix({ targetDir: destTmpDir, srcValId: val.id, srcBranchId: "main", @@ -130,7 +130,7 @@ Deno.test({ "This is a custom description for the remixed val"; // Remix with custom description - const result = await remix({ + const result = await remix.remix({ targetDir: destTmpDir, srcValId: val.id, srcBranchId: "main", @@ -186,7 +186,7 @@ Deno.test({ await t.step("general remix test", async () => { // Perform the remix - const result = await remix({ + const result = await remix.remix({ targetDir: destTmpDir, srcValId: val.id, srcBranchId: "main", diff --git a/src/vt/lib/tests/status_test.ts b/src/vt/lib/tests/status_test.ts index 13e04fb0..524d02c4 100644 --- a/src/vt/lib/tests/status_test.ts +++ b/src/vt/lib/tests/status_test.ts @@ -1,9 +1,9 @@ -import { doWithNewVal } from "~/vt/lib/tests/utils.ts"; -import sdk, { getLatestVersion } from "~/sdk.ts"; +import { doWithTempDir } from "~/vt/lib/utils/misc.ts"; +import sdk, { getLatestVersion } from "../../../utils/sdk.ts"; import { assertEquals } from "@std/assert"; import { join } from "@std/path"; -import { status } from "~/vt/lib/status.ts"; -import { doWithTempDir } from "~/vt/lib/utils/misc.ts"; +import { status } from "~/vt/lib/vals/status.ts"; +import { doWithNewVal } from "~/vt/lib/tests/utils.ts"; Deno.test({ name: "test status detects binary files", @@ -123,7 +123,7 @@ Deno.test({ ); }); - await t.step("varify status layout", async () => { + await t.step("verify status layout", async () => { // Run status check const { itemStateChanges: statusResult } = await status({ targetDir: tempDir, diff --git a/src/vt/lib/tests/utils.ts b/src/vt/lib/tests/utils.ts index 87f11c76..ffe6dc0a 100644 --- a/src/vt/lib/tests/utils.ts +++ b/src/vt/lib/tests/utils.ts @@ -1,4 +1,5 @@ -import sdk, { branchNameToBranch, randomValName } from "~/sdk.ts"; +import { branchNameToBranch } from "~/utils/mod.ts"; +import sdk, { randomValName } from "~/utils/sdk.ts"; export interface ExpectedValInode { path: string; diff --git a/src/vt/lib/utils/ItemStatusManager.ts b/src/vt/lib/utils/ItemStatusManager.ts index b6938c63..a937f838 100644 --- a/src/vt/lib/utils/ItemStatusManager.ts +++ b/src/vt/lib/utils/ItemStatusManager.ts @@ -8,7 +8,7 @@ import { VAL_ITEM_NAME_REGEX, } from "~/consts.ts"; import { basename } from "@std/path"; -import { hasNullBytes } from "~/utils.ts"; +import { hasNullBytes } from "../../../utils/misc.ts"; /** * Possible warning states for a Val item. diff --git a/src/vt/lib/paths.ts b/src/vt/lib/utils/paths.ts similarity index 98% rename from src/vt/lib/paths.ts rename to src/vt/lib/utils/paths.ts index 2e00bf38..5fd54bdb 100644 --- a/src/vt/lib/paths.ts +++ b/src/vt/lib/utils/paths.ts @@ -3,9 +3,9 @@ import { FIRST_VERSION_NUMBER, RECENT_VERSION_COUNT, } from "~/consts.ts"; -import { getValItem } from "~/sdk.ts"; import { compile as compileGitignore } from "gitignore-parser"; import type { ValItemType } from "~/types.ts"; +import { getValItem } from "~/utils/mod.ts"; /** * Determine the type of a Val file. diff --git a/src/vt/lib/checkout.ts b/src/vt/lib/vals/checkout.ts similarity index 91% rename from src/vt/lib/checkout.ts rename to src/vt/lib/vals/checkout.ts index 4ce773a3..bb4e82a9 100644 --- a/src/vt/lib/checkout.ts +++ b/src/vt/lib/vals/checkout.ts @@ -1,17 +1,17 @@ -import sdk, { listValItems } from "~/sdk.ts"; import type ValTown from "@valtown/sdk"; -import { pull } from "~/vt/lib/pull.ts"; -import { getValItemType, shouldIgnore } from "~/vt/lib/paths.ts"; import { join, relative } from "@std/path"; import { ItemStatusManager } from "~/vt/lib/utils/ItemStatusManager.ts"; import { doAtomically, gracefulRecursiveCopy } from "~/vt/lib/utils/misc.ts"; import { walk } from "@std/fs"; +import sdk, { listValItems } from "~/utils/sdk.ts"; +import { getValItemType, shouldIgnore } from "~/vt/lib/utils/paths.ts"; +import { pull } from "~/vt/lib/vals/pull.ts"; /** * Result of a checkout operation containing branch information and file * changes. */ -export interface CheckoutResult { +interface CheckoutResult { /** The source branch */ fromBranch: ValTown.Vals.BranchCreateResponse; /** @@ -28,7 +28,7 @@ export interface CheckoutResult { /** * Base parameters for all checkout operations. */ -export type BaseCheckoutParams = { +type BaseCheckoutParams = { /** The directory where the branch will be checked out */ targetDir: string; /** The ID of the Val */ @@ -44,7 +44,7 @@ export type BaseCheckoutParams = { /** * Parameters for checking out an existing branch. */ -export type BranchCheckoutParams = BaseCheckoutParams & { +type BranchCheckoutParams = BaseCheckoutParams & { /** The ID of the branch to checkout */ toBranchId: string; /** The ID of the branch we're switching from */ @@ -54,7 +54,7 @@ export type BranchCheckoutParams = BaseCheckoutParams & { /** * Parameters for creating and checking out a new branch (fork). */ -export type ForkCheckoutParams = BaseCheckoutParams & { +type ForkCheckoutParams = BaseCheckoutParams & { /** The branch ID from which to create the fork */ forkedFromId: string; /** The name for the new forked branch */ @@ -66,7 +66,7 @@ export type ForkCheckoutParams = BaseCheckoutParams & { * @param params Options for the checkout operation. * @returns Promise that resolves with checkout information. */ -export function checkout(params: BranchCheckoutParams): Promise; +function checkout(params: BranchCheckoutParams): Promise; /** * Creates a new branch from a val's branch and checks it out. @@ -74,8 +74,8 @@ export function checkout(params: BranchCheckoutParams): Promise; * @returns Promise that resolves with checkout information (including the new branch details). */ -export function checkout(params: ForkCheckoutParams): Promise; -export function checkout( +function checkout(params: ForkCheckoutParams): Promise; +function checkout( params: BranchCheckoutParams | ForkCheckoutParams, ): Promise { // Determine if we're creating a new branch or checking out an existing one @@ -90,9 +90,7 @@ export function checkout( } } -/** - * Handles creating a new branch (fork) and marking all files as not_modified - */ +// Handles creating a new branch (fork) and marking all files as not_modified async function handleForkCheckout( params: ForkCheckoutParams, ): Promise { @@ -146,9 +144,7 @@ async function handleForkCheckout( }; } -/** - * Handles checking out an existing branch - */ +// Handles checking out an existing branch async function handleBranchCheckout( params: BranchCheckoutParams, ): Promise { @@ -262,3 +258,11 @@ async function handleBranchCheckout( { targetDir: params.targetDir }, ); } + +export { checkout }; +export type { + BaseCheckoutParams, + BranchCheckoutParams, + CheckoutResult, + ForkCheckoutParams, +}; diff --git a/src/vt/lib/clone.ts b/src/vt/lib/vals/clone.ts similarity index 93% rename from src/vt/lib/clone.ts rename to src/vt/lib/vals/clone.ts index c306948f..98319624 100644 --- a/src/vt/lib/clone.ts +++ b/src/vt/lib/vals/clone.ts @@ -1,5 +1,3 @@ -import sdk, { listValItems } from "~/sdk.ts"; -import { shouldIgnore } from "~/vt/lib/paths.ts"; import { ensureDir, exists } from "@std/fs"; import { dirname } from "@std/path/dirname"; import { join } from "@std/path"; @@ -9,11 +7,13 @@ import { type ItemStatus, ItemStatusManager, } from "~/vt/lib/utils/ItemStatusManager.ts"; +import sdk, { getLatestVersion, listValItems } from "~/utils/sdk.ts"; +import { shouldIgnore } from "~/vt/lib/utils/paths.ts"; /** * Result of a clone operation. */ -export interface CloneResult { +interface CloneResult { /** Changes made to items during the cloning process */ itemStateChanges: ItemStatusManager; } @@ -22,7 +22,7 @@ export interface CloneResult { * Parameters for cloning a Val by downloading its files and directories to the specified * target directory. */ -export interface CloneParams { +interface CloneParams { /** The directory where the Val will be cloned */ targetDir: string; /** The id of the Val to be cloned */ @@ -30,7 +30,7 @@ export interface CloneParams { /** The branch ID of the Val to clone */ branchId: string; /** The version to clone. Defaults to latest */ - version: number; + version?: number; /** A list of gitignore rules. */ gitignoreRules?: string[]; /** If true, don't actually write files, just report what would change */ @@ -46,8 +46,8 @@ export interface CloneParams { * @param params Options for the clone operation * @returns Promise that resolves with changes that were applied or would be applied (if dryRun=true) */ -export function clone(params: CloneParams): Promise { - const { +function clone(params: CloneParams): Promise { + let { targetDir, valId, branchId, @@ -58,6 +58,7 @@ export function clone(params: CloneParams): Promise { } = params; return doAtomically( async (tmpDir) => { + version = version ?? (await getLatestVersion(valId, branchId)); const itemStateChanges = new ItemStatusManager(); const valItems = await listValItems( valId, @@ -216,3 +217,6 @@ async function createFile( // Set the file's mtime to match the source await Deno.utime(join(targetRoot, path), updatedAt, updatedAt); } + +export { clone }; +export type { CloneParams, CloneResult }; diff --git a/src/vt/lib/create.ts b/src/vt/lib/vals/create.ts similarity index 88% rename from src/vt/lib/create.ts rename to src/vt/lib/vals/create.ts index 363db66a..26e54aeb 100644 --- a/src/vt/lib/create.ts +++ b/src/vt/lib/vals/create.ts @@ -1,9 +1,9 @@ -import { push } from "~/vt/lib/push.ts"; -import sdk, { branchNameToBranch } from "~/sdk.ts"; import type { ValPrivacy } from "~/types.ts"; import { DEFAULT_BRANCH_NAME } from "~/consts.ts"; import { ensureDir } from "@std/fs"; import type { ItemStatusManager } from "~/vt/lib/utils/ItemStatusManager.ts"; +import sdk, { branchNameToBranch } from "~/utils/sdk.ts"; +import { push } from "~/vt/lib/vals/mod.ts"; /** * Result of a checkout operation containing branch information and file @@ -21,7 +21,7 @@ interface CreateResponse { /** * Parameters for creating a new Val Town Val from a local directory. */ -export interface CreateParams { +interface CreateParams { /** The root directory containing the files to upload to the new val. */ sourceDir: string; /** The name for the new val. */ @@ -40,7 +40,7 @@ export interface CreateParams { * @param params Options for create operation. * @returns Promise that resolves with changes that were applied during the push operation and the new Val ID. */ -export async function create( +async function create( params: CreateParams, ): Promise { const { @@ -65,7 +65,7 @@ export async function create( ); // Push the local directory contents to the new val - const { itemStateChanges } = await push({ + const { itemStateChanges } = await push.push({ targetDir: sourceDir, valId: newVal.id, branchId: newBranch.id, @@ -78,3 +78,6 @@ export async function create( newBranchId: newBranch.id, }; } + +export { create }; +export type { CreateParams, CreateResponse }; diff --git a/src/vt/lib/vals/mod.ts b/src/vt/lib/vals/mod.ts new file mode 100644 index 00000000..8941ef47 --- /dev/null +++ b/src/vt/lib/vals/mod.ts @@ -0,0 +1,7 @@ +export * as checkout from "./checkout.ts"; +export * as clone from "./clone.ts"; +export * as create from "./create.ts"; +export * as pull from "./pull.ts"; +export * as push from "./push.ts"; +export * as remix from "./remix.ts"; +export * as status from "./status.ts"; diff --git a/src/vt/lib/pull.ts b/src/vt/lib/vals/pull.ts similarity index 89% rename from src/vt/lib/pull.ts rename to src/vt/lib/vals/pull.ts index 6008eab8..5975b42d 100644 --- a/src/vt/lib/pull.ts +++ b/src/vt/lib/vals/pull.ts @@ -1,23 +1,20 @@ import { join, relative } from "@std/path"; -import { getValItemType, shouldIgnore } from "~/vt/lib/paths.ts"; -import { listValItems } from "~/sdk.ts"; import { type ItemStatus, ItemStatusManager, } from "~/vt/lib/utils/ItemStatusManager.ts"; import { walk } from "@std/fs"; -import { clone } from "~/vt/lib/clone.ts"; import { doAtomically, gracefulRecursiveCopy } from "~/vt/lib/utils/misc.ts"; +import { clone } from "~/vt/lib/mod.ts"; +import { getLatestVersion, listValItems } from "~/utils/sdk.ts"; +import { getValItemType, shouldIgnore } from "~/vt/lib/utils/paths.ts"; /** Result of pull operation */ export interface PushResult { itemStateChanges: ItemStatusManager; } -/** - * Parameters for pulling latest changes from a Val Town Val into a vt folder. - */ -export interface PullParams { +interface PullParams { /** The vt Val root directory. */ targetDir: string; /** The id of the Val to download from. */ @@ -25,7 +22,7 @@ export interface PullParams { /** The branch ID to download file content from. */ branchId: string; /** The version to pull. Defaults to latest version. */ - version: number; + version?: number; /** A list of gitignore rules. */ gitignoreRules?: string[]; /** If true, don't actually modify files, just report what would change. */ @@ -46,15 +43,17 @@ export interface PullParams { * @param params Options for pull operation. * @returns Promise that resolves with changes that were applied or would be applied (if dryRun=true) */ -export function pull(params: PullParams): Promise { +async function pull(params: PullParams): Promise { const { targetDir, valId, branchId, - version, + version = params.version || + await getLatestVersion(params.valId, params.branchId), gitignoreRules = [], dryRun = false, } = params; + return doAtomically( async (tmpDir) => { const changes = new ItemStatusManager(); @@ -71,7 +70,7 @@ export function pull(params: PullParams): Promise { // Clone all the files from the Val into the temp dir. This // implicitly will overwrite files with the current version on the // server. - const { itemStateChanges: cloneChanges } = await clone({ + const { itemStateChanges: cloneChanges } = await clone.clone({ targetDir: tmpDir, valId, branchId, @@ -136,3 +135,6 @@ export function pull(params: PullParams): Promise { { targetDir, prefix: "vt_pull_" }, ); } + +export { pull }; +export type { PullParams }; diff --git a/src/vt/lib/push.ts b/src/vt/lib/vals/push.ts similarity index 93% rename from src/vt/lib/push.ts rename to src/vt/lib/vals/push.ts index 1fdbc43e..702f9f2e 100644 --- a/src/vt/lib/push.ts +++ b/src/vt/lib/vals/push.ts @@ -1,6 +1,4 @@ import type { ValFileType, ValItemType } from "~/types.ts"; -import sdk, { getLatestVersion, listValItems } from "~/sdk.ts"; -import { status } from "~/vt/lib/status.ts"; import { basename, dirname, join } from "@std/path"; import { assert } from "@std/assert"; import { exists } from "@std/fs/exists"; @@ -10,9 +8,16 @@ import { getItemWarnings, ItemStatusManager, } from "~/vt/lib/utils/ItemStatusManager.ts"; +import sdk, { + branchNameToBranch, + getLatestVersion, + listValItems, +} from "~/utils/sdk.ts"; +import { DEFAULT_BRANCH_NAME } from "~/consts.ts"; +import { status } from "~/vt/lib/mod.ts"; /** Result of push operation */ -export interface PushResult { +interface PushResult { /** Changes made to Val items during the push process */ itemStateChanges: ItemStatusManager; } @@ -20,13 +25,13 @@ export interface PushResult { /** * Parameters for pushing latest changes from a vt folder into a Val Town val. */ -export interface PushParams { +interface PushParams { /** The vt Val root directory. */ targetDir: string; /** The id of the Val to upload to. */ valId: string; /** The branch ID to upload to. */ - branchId: string; + branchId?: string; /** A list of gitignore rules. */ gitignoreRules?: string[]; /** If true, don't actually modify files on server, just report what would change. */ @@ -42,11 +47,13 @@ export interface PushParams { * @param params Options for push operation. * @returns Promise that resolves with changes that were applied or would be applied (if dryRun=true) */ -export async function push(params: PushParams): Promise { +async function push(params: PushParams): Promise { const { targetDir, valId, - branchId, + branchId = params.branchId || + (await branchNameToBranch(valId, DEFAULT_BRANCH_NAME) + .then((resp) => resp.id))!, gitignoreRules, dryRun = false, concurrencyPoolSize = 5, @@ -56,7 +63,7 @@ export async function push(params: PushParams): Promise { assert(await exists(targetDir), "target directory doesn't exist"); // Retrieve the status - const { itemStateChanges } = await status({ + const { itemStateChanges } = await status.status({ targetDir, valId, branchId, @@ -280,3 +287,6 @@ async function doReqMaybeApplyWarning( return undefined; } } + +export { push }; +export type { PushParams, PushResult }; diff --git a/src/vt/lib/remix.ts b/src/vt/lib/vals/remix.ts similarity index 90% rename from src/vt/lib/remix.ts rename to src/vt/lib/vals/remix.ts index 70970702..f6d51820 100644 --- a/src/vt/lib/remix.ts +++ b/src/vt/lib/vals/remix.ts @@ -1,14 +1,11 @@ -import { clone } from "~/vt/lib/clone.ts"; -import { create } from "~/vt/lib/create.ts"; -import sdk, { - branchNameToBranch, - getLatestVersion, - listValItems, -} from "~/sdk.ts"; +import { clone } from "~/vt/lib/vals/clone.ts"; +import { create } from "~/vt/lib/vals/create.ts"; import { doAtomically } from "~/vt/lib/utils/misc.ts"; import { DEFAULT_BRANCH_NAME, DEFAULT_VAL_PRIVACY } from "~/consts.ts"; import { ItemStatusManager } from "~/vt/lib/utils/ItemStatusManager.ts"; import type { ValPrivacy } from "~/types.ts"; +import { branchNameToBranch } from "~/utils/mod.ts"; +import sdk, { getLatestVersion, listValItems } from "~/utils/sdk.ts"; /** * Result of remixing a val. @@ -17,7 +14,7 @@ import type { ValPrivacy } from "~/types.ts"; * This object contains information about the newly created Val and the changes * that were made to the local file state during the remix operation. */ -export interface RemixResult { +interface RemixResult { /** The ID of the newly created Val */ toValId: string; /** The version number of the newly created Val */ @@ -32,7 +29,7 @@ export interface RemixResult { /** * Parameters for remixing some Val Town Val to a new Val Town val. */ -export interface RemixParams { +interface RemixParams { /** The root directory to contain the newly remixed val. */ targetDir: string; /** The id of the Val to remix from. */ @@ -56,7 +53,7 @@ export interface RemixParams { * @returns Promise that resolves with a CheckoutResult containing information about the * newly created Val and the changes made during the remix operation. */ -export async function remix( +async function remix( params: RemixParams, ): Promise { const itemStateChanges = new ItemStatusManager(); @@ -127,3 +124,6 @@ export async function remix( }, true]; }, { targetDir }); } + +export { remix }; +export type { RemixParams, RemixResult }; diff --git a/src/vt/lib/status.ts b/src/vt/lib/vals/status.ts similarity index 89% rename from src/vt/lib/status.ts rename to src/vt/lib/vals/status.ts index 9eecb552..47a3be7b 100644 --- a/src/vt/lib/status.ts +++ b/src/vt/lib/vals/status.ts @@ -1,18 +1,20 @@ -import sdk, { listValItems } from "~/sdk.ts"; -import { getValItemType, shouldIgnore } from "~/vt/lib/paths.ts"; -import * as fs from "@std/fs"; -import * as path from "@std/path"; +import type { + CreatedItemStatus, + DeletedItemStatus, + ItemInfo, + ModifiedItemStatus, + NotModifiedItemStatus, +} from "~/vt/lib/utils/ItemStatusManager.ts"; import { - type CreatedItemStatus, - type DeletedItemStatus, getItemWarnings, - type ItemInfo, ItemStatusManager, - type ModifiedItemStatus, - type NotModifiedItemStatus, } from "~/vt/lib/utils/ItemStatusManager.ts"; -import { join } from "@std/path"; +import { join, relative } from "@std/path"; import { isFileModified } from "~/vt/lib/utils/misc.ts"; +import { listValItems } from "~/utils/mod.ts"; +import { getValItemType, shouldIgnore } from "~/vt/lib/utils/paths.ts"; +import sdk from "~/utils/sdk.ts"; +import { walk } from "@std/fs"; /** Result of status operation */ export interface StatusResult { @@ -22,7 +24,7 @@ export interface StatusResult { /** * Parameters for scanning a directory and determining the status of files compared to the Val Town val. */ -export interface StatusParams { +interface StatusParams { /** The directory to scan for changes. */ targetDir: string; /** The Val Town Val ID. */ @@ -43,7 +45,7 @@ export interface StatusParams { * @param params Options for status operation. * @returns Promise that resolves to a FileState object containing categorized files. */ -export async function status(params: StatusParams): Promise { +async function status(params: StatusParams): Promise { const { targetDir, valId, @@ -87,7 +89,7 @@ export async function status(params: StatusParams): Promise { result.insert(createdFileState); } else { if (localFile.type !== "directory") { - const localStat = await Deno.stat(path.join(targetDir, localFile.path)); + const localStat = await Deno.stat(join(targetDir, localFile.path)); // File exists in both places, check if modified const isModified = isFileModified({ srcContent: localFile.content!, // We know it isn't a dir, so there should be content @@ -193,10 +195,10 @@ async function getLocalFiles({ }): Promise { const filePromises: Promise[] = []; - for await (const entry of fs.walk(targetDir)) { + for await (const entry of walk(targetDir)) { filePromises.push((async () => { // Check if this is on the ignore list - const relativePath = path.relative(targetDir, entry.path); + const relativePath = relative(targetDir, entry.path); if (shouldIgnore(relativePath, gitignoreRules)) return null; if (entry.path === targetDir) return null; @@ -227,3 +229,6 @@ async function getLocalFiles({ const results = await Promise.all(filePromises); return results.filter((item): item is ItemInfo => item !== null); } + +export { status }; +export type { StatusParams }; diff --git a/src/vt/vt/VTClient.ts b/src/vt/vt/VTClient.ts index b01a940c..1a2512d8 100644 --- a/src/vt/vt/VTClient.ts +++ b/src/vt/vt/VTClient.ts @@ -1,20 +1,14 @@ import { checkout, clone, create, remix, status } from "~/vt/lib/mod.ts"; import { debounce, delay } from "@std/async"; import VTMeta from "~/vt/vt/VTMeta.ts"; -import { pull } from "~/vt/lib/pull.ts"; -import { push } from "~/vt/lib/push.ts"; +import { pull } from "~/vt/lib/vals/pull.ts"; +import { push } from "~/vt/lib/vals/push.ts"; import { join, relative } from "@std/path"; -import type { - BaseCheckoutParams, - BranchCheckoutParams, - CheckoutResult, - ForkCheckoutParams, -} from "~/vt/lib/checkout.ts"; import sdk, { branchNameToBranch, getCurrentUser, getLatestVersion, -} from "~/sdk.ts"; +} from "../../utils/sdk.ts"; import { DEFAULT_BRANCH_NAME, DEFAULT_EDITOR_TEMPLATE, @@ -23,11 +17,17 @@ import { } from "~/consts.ts"; import { exists } from "@std/fs"; import ValTown from "@valtown/sdk"; -import { dirIsEmpty } from "~/utils.ts"; +import { dirIsEmpty } from "../../utils/misc.ts"; import VTConfig from "~/vt/VTConfig.ts"; import type { ValPrivacy } from "~/types.ts"; import type { ItemStatusManager } from "~/vt/lib/utils/ItemStatusManager.ts"; import { parseValUri } from "~/cmd/lib/utils/parsing.ts"; +import type { + BaseCheckoutParams, + BranchCheckoutParams, + CheckoutResult, + ForkCheckoutParams, +} from "~/vt/lib/vals/checkout.ts"; /** * The VTClient class is an abstraction on a VT directory that exposes @@ -86,7 +86,7 @@ export default class VTClient { DEFAULT_BRANCH_NAME, ); - await clone({ + await clone.clone({ targetDir: this.rootPath, valId: templateVal.id, branchId: templateBranch.id, @@ -269,7 +269,7 @@ export default class VTClient { await assertSafeDirectory(rootPath); // First create the val - const { newValId: newValId } = await create({ + const { newValId: newValId } = await create.create({ sourceDir: rootPath, valName, privacy, @@ -325,7 +325,7 @@ export default class VTClient { srcValName, ); - const { toValId, toVersion } = await remix({ + const { toValId, toVersion } = await remix.remix({ targetDir: rootPath, srcValId: srcVal.id, srcBranchId: srcBranchName, @@ -384,7 +384,7 @@ export default class VTClient { await vt.getMeta().doWithVtState(async (config) => { // Do the clone using the configuration - await clone({ + await clone.clone({ targetDir: rootPath, valId: config.val.id, branchId: config.branch.id, @@ -428,7 +428,7 @@ export default class VTClient { // Use provided branchId or fall back to the current branch from state const targetBranchId = branchId || vtState.branch.id; - const { itemStateChanges } = await status({ + const { itemStateChanges } = await status.status({ targetDir: this.rootPath, valId: vtState.val.id, branchId: targetBranchId, @@ -557,7 +557,7 @@ export default class VTClient { toBranchVersion: FIRST_VERSION_NUMBER, // Version should be 1 for a new forked branch }; - result = await checkout(forkParams); + result = await checkout.checkout(forkParams); if (!baseParams.dryRun) { if (result.toBranch) { @@ -584,7 +584,7 @@ export default class VTClient { toBranchVersion: options?.toBranchVersion || checkoutBranch.version, // Use specified version or the branch's version }; - result = await checkout(branchParams); + result = await checkout.checkout(branchParams); } // Don't touch the state if it's a dry run diff --git a/src/vt/vt/utils.ts b/src/vt/vt/utils.ts index cc39e629..ccd1c70c 100644 --- a/src/vt/vt/utils.ts +++ b/src/vt/vt/utils.ts @@ -1,6 +1,6 @@ import { join } from "@std/path"; import { MAX_WALK_UP_LEVELS } from "~/consts.ts"; -import { findRoot } from "~/utils.ts"; +import { findRoot } from "../../utils/misc.ts"; /** * Finds the nearest directory containing a .vt folder by climbing up the directory tree diff --git a/vt.ts b/vt.ts old mode 100755 new mode 100644 index 29b23902..7d609c44 --- a/vt.ts +++ b/vt.ts @@ -4,7 +4,7 @@ import { ensureGlobalVtConfig, globalConfig } from "~/vt/VTConfig.ts"; import { onboardFlow } from "~/cmd/flows/onboard.ts"; import { API_KEY_KEY } from "~/consts.ts"; import { colors } from "@cliffy/ansi/colors"; -import sdk from "~/sdk.ts"; +import sdk from "~/utils/sdk.ts"; await ensureGlobalVtConfig(); @@ -58,7 +58,7 @@ async function startVt() { await vt.parse(Deno.args); } -if (import.meta.main) { +export async function launch() { await ensureValidApiKey(); sdk.bearerToken = Deno.env.get(API_KEY_KEY) ?? sdk.bearerToken; await startVt();