diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index 6be6054b4..360f4c660 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -34,6 +34,9 @@ jobs: - name: Check TypeScript Types run: npx turbo check-types + - name: Run Tests + run: npx turbo run test --filter=roam --ui stream + lint-changed-files: if: github.event_name == 'pull_request' runs-on: ubuntu-latest diff --git a/apps/roam/package.json b/apps/roam/package.json index 481d4f99e..9aa1b1b01 100644 --- a/apps/roam/package.json +++ b/apps/roam/package.json @@ -9,7 +9,9 @@ "lint": "eslint .", "lint:fix": "eslint . --fix", "publish": "tsx scripts/publish.ts", - "check-types": "tsc --noEmit --skipLibCheck" + "check-types": "tsc --noEmit --skipLibCheck", + "test": "vitest run --config vitest.config.mts", + "test:watch": "vitest --config vitest.config.mts" }, "license": "Apache-2.0", "devDependencies": { @@ -19,6 +21,7 @@ "@repo/typescript-config": "workspace:*", "@types/file-saver": "2.0.5", "@types/nanoid": "2.0.0", + "@types/node": "^20", "@types/react": "catalog:roam", "@types/react-dom": "catalog:roam", "@types/react-vertical-timeline-component": "^3.3.3", @@ -26,7 +29,8 @@ "dotenv": "^16.0.3", "esbuild": "0.17.14", "tailwindcss": "^3.4.17", - "tsx": "^4.19.2" + "tsx": "^4.19.2", + "vitest": "catalog:" }, "//": "axios dep temporary - need to fix the dep in underlying libraries", "tags": [ diff --git a/apps/roam/src/utils/__tests__/datalogUtils.test.ts b/apps/roam/src/utils/__tests__/datalogUtils.test.ts new file mode 100644 index 000000000..cf865e273 --- /dev/null +++ b/apps/roam/src/utils/__tests__/datalogUtils.test.ts @@ -0,0 +1,121 @@ +import { describe, expect, it } from "vitest"; +import compileDatalog, { toVar } from "~/utils/compileDatalog"; +import gatherDatalogVariablesFromClause from "~/utils/gatherDatalogVariablesFromClause"; +import replaceDatalogVariables from "~/utils/replaceDatalogVariables"; + +describe("compileDatalog", () => { + it("sanitizes variable names", () => { + expect(toVar('a b"(c)')).toBe("abc"); + }); + + it("compiles nested and-clauses", () => { + const query = compileDatalog({ + type: "and-clause", + clauses: [ + { + type: "data-pattern", + arguments: [ + { type: "variable", value: "node" }, + { type: "constant", value: ":node/title" }, + { type: "constant", value: '"Hello"' }, + ], + }, + { + type: "pred-expr", + pred: "=", + arguments: [ + { type: "variable", value: "node" }, + { type: "variable", value: "match" }, + ], + }, + ], + }); + + expect(query).toContain("(and"); + expect(query).toContain('[?node :node/title "Hello"]'); + expect(query).toContain("[(= ?node ?match)]"); + }); +}); + +describe("gatherDatalogVariablesFromClause", () => { + it("collects variables from nested clauses", () => { + const variables = gatherDatalogVariablesFromClause({ + type: "and-clause", + clauses: [ + { + type: "data-pattern", + arguments: [ + { type: "variable", value: "a" }, + { type: "constant", value: ":rel" }, + { type: "variable", value: "b" }, + ], + }, + { + type: "or-join-clause", + variables: [ + { type: "variable", value: "c" }, + { type: "variable", value: "d" }, + ], + clauses: [], + }, + ], + }); + + expect(Array.from(variables).sort()).toEqual(["a", "b", "c", "d"]); + }); +}); + +describe("replaceDatalogVariables", () => { + it("replaces explicit variable names and function bindings", () => { + const [clause] = replaceDatalogVariables( + [{ from: "node", to: "page" }], + [ + { + type: "fn-expr", + fn: "get", + arguments: [{ type: "variable", value: "node" }], + binding: { + type: "bind-scalar", + variable: { type: "variable", value: "node" }, + }, + }, + ], + ); + + expect(clause.type).toBe("fn-expr"); + if (clause.type !== "fn-expr") return; + expect(clause.arguments[0]).toMatchObject({ value: "page" }); + expect(clause.binding).toMatchObject({ + variable: { value: "page" }, + }); + }); + + it("supports transform replacement for all variables", () => { + const [clause] = replaceDatalogVariables( + [{ from: true, to: (v) => `${v}-v2` }], + [ + { + type: "not-join-clause", + variables: [{ type: "variable", value: "a" }], + clauses: [ + { + type: "data-pattern", + arguments: [ + { type: "variable", value: "a" }, + { type: "constant", value: ":x" }, + { type: "variable", value: "b" }, + ], + }, + ], + }, + ], + ); + + expect(clause.type).toBe("not-join-clause"); + if (clause.type !== "not-join-clause") return; + expect(clause.variables[0].value).toBe("a-v2"); + expect(clause.clauses[0]).toMatchObject({ + arguments: [{ value: "a-v2" }, { value: ":x" }, { value: "b-v2" }], + }); + }); +}); diff --git a/apps/roam/src/utils/__tests__/fireQuery.test.ts b/apps/roam/src/utils/__tests__/fireQuery.test.ts new file mode 100644 index 000000000..dcc1efb54 --- /dev/null +++ b/apps/roam/src/utils/__tests__/fireQuery.test.ts @@ -0,0 +1,128 @@ +import { beforeEach, describe, expect, it, vi } from "vitest"; + +type ConditionToDatalogArgs = { + source: string; + target: string; +}; + +vi.mock("~/utils/conditionToDatalog", () => ({ + default: vi.fn(({ source, target }: ConditionToDatalogArgs) => [ + { + type: "data-pattern", + arguments: [ + { type: "variable", value: source }, + { type: "constant", value: ":rel" }, + /^:in /.test(target) + ? { type: "variable", value: target.substring(4) } + : { type: "constant", value: '"value"' }, + ], + }, + ]), +})); +vi.mock("~/utils/predefinedSelections", () => ({ + default: [ + { + test: /^created$/, + pull: () => "(pull ?node [:create/time])", + mapper: (r: Record) => r[":create/time"] || "", + }, + ], +})); +vi.mock("roamjs-components/util/env", () => ({ getNodeEnv: () => "test" })); + +import fireQuery, { fireQuerySync, getDatalogQuery } from "~/utils/fireQuery"; + +describe("getDatalogQuery", () => { + it("includes :in variables and de-duplicates expected inputs", async () => { + const built = getDatalogQuery({ + conditions: [ + { + type: "clause", + relation: "r", + source: "node", + target: ":in title", + uid: "1", + not: false, + }, + { + type: "clause", + relation: "r", + source: "node", + target: ":in title", + uid: "2", + not: false, + }, + ], + selections: [{ uid: "s1", text: "created", label: "Created" }], + inputs: { title: "Graph" }, + }); + + expect(built.query).toContain(":in $ ?title"); + expect(built.inputs).toEqual(["Graph"]); + const formatted = await built.formatResult([ + { ":node/title": "A", ":block/uid": "u1" }, + { ":block/uid": "u1" }, + { ":create/time": "123" }, + ]); + expect(formatted).toMatchObject({ text: "A", uid: "u1", Created: "123" }); + }); +}); + +describe("fireQuery", () => { + beforeEach(() => { + (globalThis as { window: unknown }).window = { + roamAlphaAPI: { + data: { + async: { + fast: { + q: vi + .fn() + .mockResolvedValue([ + [ + { ":node/title": "Local", ":block/uid": "l1" }, + { ":block/uid": "l1" }, + ], + ]), + }, + }, + backend: { + q: vi + .fn() + .mockResolvedValue([ + [ + { ":node/title": "Remote", ":block/uid": "r1" }, + { ":block/uid": "r1" }, + ], + ]), + }, + fast: { + q: vi + .fn() + .mockReturnValue([ + [{ ":node/title": "Sync", ":block/uid": "s1" }], + ]), + }, + }, + }, + }; + }); + + it("uses backend queries by default and maps output", async () => { + const results = await fireQuery({ conditions: [], selections: [] }); + expect(results[0]).toMatchObject({ text: "Remote", uid: "r1" }); + }); + + it("uses async fast query when local=true", async () => { + const results = await fireQuery({ + conditions: [], + selections: [], + local: true, + }); + expect(results[0]).toMatchObject({ text: "Local", uid: "l1" }); + }); + + it("returns sync mapped results", () => { + const results = fireQuerySync({ conditions: [], selections: [] }); + expect(results).toEqual([{ text: "Sync", uid: "s1" }]); + }); +}); diff --git a/apps/roam/src/utils/__tests__/queryParsing.test.ts b/apps/roam/src/utils/__tests__/queryParsing.test.ts new file mode 100644 index 000000000..b885f8997 --- /dev/null +++ b/apps/roam/src/utils/__tests__/queryParsing.test.ts @@ -0,0 +1,127 @@ +import { beforeEach, describe, expect, it, vi } from "vitest"; + +type SettingsTreeNode = { + text: string; + children?: SettingsTreeNode[]; +}; + +type GetSettingValueArgs = { + tree?: SettingsTreeNode[]; + key: string; +}; + +vi.mock("roamjs-components/util/getSubTree", () => ({ + default: vi.fn(), +})); +vi.mock("roamjs-components/util/getSettingValueFromTree", () => ({ + default: vi.fn( + ({ tree = [], key }: GetSettingValueArgs): string => + tree.find((t: { text: string }) => t.text === key)?.children?.[0]?.text || + "", + ), +})); +vi.mock("roamjs-components/writes/createBlock", () => ({ + default: vi.fn(), +})); + +import getSubTree from "roamjs-components/util/getSubTree"; +import createBlock from "roamjs-components/writes/createBlock"; +import parseQuery from "~/utils/parseQuery"; +import { getTitleDatalog } from "~/utils/conditionToDatalog"; + +const mockedGetSubTree = vi.mocked(getSubTree); +const mockedCreateBlock = vi.mocked(createBlock); + +describe("parseQuery", () => { + beforeEach(() => { + vi.clearAllMocks(); + (globalThis as { window: unknown }).window = { + roamAlphaAPI: { + util: { generateUID: () => "new-uid" }, + }, + }; + }); + + it("parses query nodes and builds default return column", () => { + const queryTree = { + uid: "parent", + children: [ + { text: "conditions" }, + { text: "selections" }, + { text: "custom" }, + ], + }; + mockedGetSubTree.mockImplementation(({ key }) => { + if (key === "conditions") { + return { uid: "conditions-uid", text: "conditions", children: [] }; + } + if (key === "selections") { + return { + uid: "selections-uid", + text: "selections", + children: [ + { + uid: "sel-node", + text: "node", + children: [{ uid: "title-label", text: "Title", children: [] }], + }, + { + uid: "sel-created", + text: "created", + children: [ + { uid: "created-label", text: "Created", children: [] }, + ], + }, + ], + }; + } + return { + uid: "custom-uid", + text: "custom", + children: [ + { uid: "custom-query", text: "[:find ?x]", children: [] }, + { uid: "custom-enabled", text: "enabled", children: [] }, + ], + }; + }); + + const parsed = parseQuery(queryTree as never); + + expect(parsed.columns).toEqual([ + { key: "Title", uid: "returnuid", selection: "node" }, + { key: "Created", uid: "sel-created", selection: "created" }, + ]); + expect(parsed.isCustomEnabled).toBe(true); + expect(parsed.customNode).toBe("[:find ?x]"); + }); + + it("creates missing subtree blocks", () => { + const queryTree = { uid: "parent", children: [] }; + mockedGetSubTree.mockReturnValue({ uid: "", children: [] } as never); + + parseQuery(queryTree as never); + + expect(mockedCreateBlock).toHaveBeenCalledTimes(3); + }); +}); + +describe("getTitleDatalog", () => { + it("maps :in input target to variable binding", () => { + const clauses = getTitleDatalog({ source: "node", target: ":in title" }); + expect(clauses[0]).toMatchObject({ + type: "data-pattern", + arguments: [ + { type: "variable", value: "node" }, + { type: "constant", value: ":node/title" }, + { type: "variable", value: "title" }, + ], + }); + }); + + it("maps regex target to re-find expression", () => { + const clauses = getTitleDatalog({ source: "node", target: "/hello/i" }); + expect(clauses).toHaveLength(3); + expect(clauses[1]).toMatchObject({ type: "fn-expr", fn: "re-pattern" }); + expect(clauses[2]).toMatchObject({ type: "pred-expr", pred: "re-find" }); + }); +}); diff --git a/apps/roam/vitest.config.mts b/apps/roam/vitest.config.mts new file mode 100644 index 000000000..9b056e9d9 --- /dev/null +++ b/apps/roam/vitest.config.mts @@ -0,0 +1,17 @@ +import path from "node:path"; +import { fileURLToPath } from "node:url"; +import { defineConfig } from "vitest/config"; + +const dirname = path.dirname(fileURLToPath(import.meta.url)); + +export default defineConfig({ + test: { + environment: "node", + include: ["src/utils/__tests__/**/*.test.ts"], + }, + resolve: { + alias: { + "~": path.resolve(dirname, "src"), + }, + }, +}); diff --git a/apps/website/package.json b/apps/website/package.json index 38247ae30..63362e565 100644 --- a/apps/website/package.json +++ b/apps/website/package.json @@ -39,7 +39,7 @@ "devDependencies": { "@repo/eslint-config": "workspace:*", "dotenv": "^16.0.0", - "vitest": "^4.0.0", + "vitest": "catalog:", "@repo/tailwind-config": "workspace:*", "@repo/types": "workspace:*", "@repo/typescript-config": "workspace:*", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 787d30739..908dcfba1 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -42,6 +42,9 @@ catalogs: react-dom: specifier: ^19.1.0 version: 19.1.1 + vitest: + specifier: ^4.0.0 + version: 4.1.6 obsidian: '@types/react': specifier: ^19.0.12 @@ -343,7 +346,7 @@ importers: version: 3.5.2(react@18.2.0) roamjs-components: specifier: 0.88.3 - version: 0.88.3(bf7afe7a8e3269c4acb427d06becbe47) + version: 0.88.3(6fc269b31b2749e4d441ca378d1de710) tldraw: specifier: 2.4.6 version: 2.4.6(patch_hash=56e196052862c9a58a11b43e5e121384cd1d6548416afa0f16e9fbfbf0e4080d)(@types/react-dom@18.2.17)(@types/react@18.2.21)(react-dom@18.2.0(react@18.2.0))(react@18.2.0) @@ -375,6 +378,9 @@ importers: '@types/nanoid': specifier: 2.0.0 version: 2.0.0 + '@types/node': + specifier: ^20 + version: 20.19.13 '@types/react': specifier: 18.2.21 version: 18.2.21 @@ -395,10 +401,13 @@ importers: version: 0.17.14 tailwindcss: specifier: ^3.4.17 - version: 3.4.17(ts-node@10.9.2(@types/node@20.19.13)(typescript@5.9.3)) + version: 3.4.17(ts-node@10.9.2(@types/node@20.19.13)(typescript@5.5.4)) tsx: specifier: ^4.19.2 version: 4.20.5 + vitest: + specifier: 'catalog:' + version: 4.1.6(@edge-runtime/vm@3.2.0)(@opentelemetry/api@1.9.0)(@types/node@20.19.13)(jsdom@20.0.3)(msw@2.11.1(@types/node@20.19.13)(typescript@5.5.4))(vite@7.3.3(@types/node@20.19.13)(jiti@1.21.7)(tsx@4.20.5)(yaml@2.8.2)) apps/tldraw-sync-worker: dependencies: @@ -537,7 +546,7 @@ importers: specifier: ^5 version: 5.5.4 vitest: - specifier: ^4.0.0 + specifier: 'catalog:' version: 4.1.6(@edge-runtime/vm@3.2.0)(@opentelemetry/api@1.9.0)(@types/node@20.19.13)(jsdom@20.0.3)(msw@2.11.1(@types/node@20.19.13)(typescript@5.5.4))(vite@7.3.3(@types/node@20.19.13)(jiti@1.21.7)(tsx@4.21.0)(yaml@2.8.2)) packages/database: @@ -653,10 +662,10 @@ importers: version: link:../typescript-config tailwindcss: specifier: ^3.4.1 - version: 3.4.17(ts-node@10.9.2(@types/node@20.19.13)(typescript@5.9.3)) + version: 3.4.17(ts-node@10.9.2(@types/node@20.19.13)(typescript@5.5.4)) tailwindcss-animate: specifier: ^1.0.7 - version: 1.0.7(tailwindcss@3.4.17(ts-node@10.9.2(@types/node@20.19.13)(typescript@5.9.3))) + version: 1.0.7(tailwindcss@3.4.17(ts-node@10.9.2(@types/node@20.19.13)(typescript@5.5.4))) packages/types: {} @@ -9396,10 +9405,6 @@ packages: resolution: {integrity: sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==} engines: {node: '>=8.6'} - picomatch@4.0.3: - resolution: {integrity: sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==} - engines: {node: '>=12'} - picomatch@4.0.4: resolution: {integrity: sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A==} engines: {node: '>=12'} @@ -10826,10 +10831,6 @@ packages: resolution: {integrity: sha512-W/KYk+NFhkmsYpuHq5JykngiOCnxeVL8v8dFnqxSD8qEEdRfXk1SDM6JzNqcERbcGYj9tMrDQBYV9cjgnunFIg==} engines: {node: '>=18'} - tinyglobby@0.2.14: - resolution: {integrity: sha512-tX5e7OM1HnYr2+a2C/4V0htOcSQcoSTH9KgJnVvNm5zm/cyEWKJ7j7YutsH9CxMdtOkkLFy2AHrMci9IM8IPZQ==} - engines: {node: '>=12.0.0'} - tinyglobby@0.2.16: resolution: {integrity: sha512-pn99VhoACYR8nFHhxqix+uvsbXineAasWm5ojXoN8xEwK5Kd3/TrhNn1wByuD52UxWRLy8pu+kRMniEi6Eq9Zg==} engines: {node: '>=12.0.0'} @@ -15831,22 +15832,22 @@ snapshots: '@rushstack/eslint-patch@1.12.0': {} - '@samepage/scripts@0.74.5(@aws-sdk/client-lambda@3.882.0)(@aws-sdk/client-s3@3.882.0)(@samepage/testing@0.74.5(@playwright/test@1.29.0)(@testing-library/react@16.3.0(@testing-library/dom@10.4.1)(@types/react-dom@18.2.17)(@types/react@18.2.21)(react-dom@18.2.0(react@18.2.0))(react@18.2.0))(@testing-library/user-event@14.6.1(@testing-library/dom@10.4.1))(@types/jsdom@20.0.1)(c8@7.14.0)(debug@4.4.3)(dotenv@16.6.1)(jsdom@20.0.3)(ts-node@10.9.2(@types/node@20.19.13)(typescript@5.9.3)))(archiver@5.3.2)(axios@0.27.2(debug@4.4.3))(debug@4.4.3)(dotenv@16.6.1)(esbuild@0.17.14)(patch-package@6.5.1)(tailwindcss@3.4.17(ts-node@10.9.2(@types/node@20.19.13)(typescript@5.9.3)))(ts-node@10.9.2(@types/node@20.19.13)(typescript@5.9.3))(zod@3.25.76)': + '@samepage/scripts@0.74.5(@aws-sdk/client-lambda@3.882.0)(@aws-sdk/client-s3@3.882.0)(@samepage/testing@0.74.5(@playwright/test@1.29.0)(@testing-library/react@16.3.0(@testing-library/dom@10.4.1)(@types/react-dom@18.2.17)(@types/react@18.2.21)(react-dom@18.2.0(react@18.2.0))(react@18.2.0))(@testing-library/user-event@14.6.1(@testing-library/dom@10.4.1))(@types/jsdom@20.0.1)(c8@7.14.0)(debug@4.4.3)(dotenv@16.6.1)(jsdom@20.0.3)(ts-node@10.9.2(@types/node@20.19.13)(typescript@5.5.4)))(archiver@5.3.2)(axios@0.27.2(debug@4.4.3))(debug@4.4.3)(dotenv@16.6.1)(esbuild@0.17.14)(patch-package@6.5.1)(tailwindcss@3.4.17(ts-node@10.9.2(@types/node@20.19.13)(typescript@5.5.4)))(ts-node@10.9.2(@types/node@20.19.13)(typescript@5.5.4))(zod@3.25.76)': dependencies: '@aws-sdk/client-lambda': 3.882.0 '@aws-sdk/client-s3': 3.882.0 - '@samepage/testing': 0.74.5(@playwright/test@1.29.0)(@testing-library/react@16.3.0(@testing-library/dom@10.4.1)(@types/react-dom@18.2.17)(@types/react@18.2.21)(react-dom@18.2.0(react@18.2.0))(react@18.2.0))(@testing-library/user-event@14.6.1(@testing-library/dom@10.4.1))(@types/jsdom@20.0.1)(c8@7.14.0)(debug@4.4.3)(dotenv@16.6.1)(jsdom@20.0.3)(ts-node@10.9.2(@types/node@20.19.13)(typescript@5.9.3)) + '@samepage/testing': 0.74.5(@playwright/test@1.29.0)(@testing-library/react@16.3.0(@testing-library/dom@10.4.1)(@types/react-dom@18.2.17)(@types/react@18.2.21)(react-dom@18.2.0(react@18.2.0))(react@18.2.0))(@testing-library/user-event@14.6.1(@testing-library/dom@10.4.1))(@types/jsdom@20.0.1)(c8@7.14.0)(debug@4.4.3)(dotenv@16.6.1)(jsdom@20.0.3)(ts-node@10.9.2(@types/node@20.19.13)(typescript@5.5.4)) archiver: 5.3.2 axios: 0.27.2(debug@4.4.3) debug: 4.4.3 dotenv: 16.6.1 esbuild: 0.17.14 patch-package: 6.5.1 - tailwindcss: 3.4.17(ts-node@10.9.2(@types/node@20.19.13)(typescript@5.9.3)) - ts-node: 10.9.2(@types/node@20.19.13)(typescript@5.9.3) + tailwindcss: 3.4.17(ts-node@10.9.2(@types/node@20.19.13)(typescript@5.5.4)) + ts-node: 10.9.2(@types/node@20.19.13)(typescript@5.5.4) zod: 3.25.76 - '@samepage/testing@0.74.5(@playwright/test@1.29.0)(@testing-library/react@16.3.0(@testing-library/dom@10.4.1)(@types/react-dom@18.2.17)(@types/react@18.2.21)(react-dom@18.2.0(react@18.2.0))(react@18.2.0))(@testing-library/user-event@14.6.1(@testing-library/dom@10.4.1))(@types/jsdom@20.0.1)(c8@7.14.0)(debug@4.4.3)(dotenv@16.6.1)(jsdom@20.0.3)(ts-node@10.9.2(@types/node@20.19.13)(typescript@5.9.3))': + '@samepage/testing@0.74.5(@playwright/test@1.29.0)(@testing-library/react@16.3.0(@testing-library/dom@10.4.1)(@types/react-dom@18.2.17)(@types/react@18.2.21)(react-dom@18.2.0(react@18.2.0))(react@18.2.0))(@testing-library/user-event@14.6.1(@testing-library/dom@10.4.1))(@types/jsdom@20.0.1)(c8@7.14.0)(debug@4.4.3)(dotenv@16.6.1)(jsdom@20.0.3)(ts-node@10.9.2(@types/node@20.19.13)(typescript@5.5.4))': dependencies: '@playwright/test': 1.29.0 '@testing-library/react': 16.3.0(@testing-library/dom@10.4.1)(@types/react-dom@18.2.17)(@types/react@18.2.21)(react-dom@18.2.0(react@18.2.0))(react@18.2.0) @@ -15856,7 +15857,7 @@ snapshots: debug: 4.4.3 dotenv: 16.6.1 jsdom: 20.0.3 - ts-node: 10.9.2(@types/node@20.19.13)(typescript@5.9.3) + ts-node: 10.9.2(@types/node@20.19.13)(typescript@5.5.4) '@selderee/plugin-htmlparser2@0.11.0': dependencies: @@ -16705,7 +16706,7 @@ snapshots: dependencies: minimatch: 10.1.1 path-browserify: 1.0.1 - tinyglobby: 0.2.14 + tinyglobby: 0.2.16 '@tsconfig/node10@1.0.11': {} @@ -17474,7 +17475,7 @@ snapshots: glob: 13.0.0 graceful-fs: 4.2.11 node-gyp-build: 4.8.4 - picomatch: 4.0.3 + picomatch: 4.0.4 resolve-from: 5.0.0 transitivePeerDependencies: - encoding @@ -17638,6 +17639,15 @@ snapshots: chai: 6.2.2 tinyrainbow: 3.1.0 + '@vitest/mocker@4.1.6(msw@2.11.1(@types/node@20.19.13)(typescript@5.5.4))(vite@7.3.3(@types/node@20.19.13)(jiti@1.21.7)(tsx@4.20.5)(yaml@2.8.2))': + dependencies: + '@vitest/spy': 4.1.6 + estree-walker: 3.0.3 + magic-string: 0.30.21 + optionalDependencies: + msw: 2.11.1(@types/node@20.19.13)(typescript@5.5.4) + vite: 7.3.3(@types/node@20.19.13)(jiti@1.21.7)(tsx@4.20.5)(yaml@2.8.2) + '@vitest/mocker@4.1.6(msw@2.11.1(@types/node@20.19.13)(typescript@5.5.4))(vite@7.3.3(@types/node@20.19.13)(jiti@1.21.7)(tsx@4.21.0)(yaml@2.8.2))': dependencies: '@vitest/spy': 4.1.6 @@ -19329,7 +19339,7 @@ snapshots: get-tsconfig: 4.10.1 is-bun-module: 2.0.0 stable-hash: 0.0.5 - tinyglobby: 0.2.14 + tinyglobby: 0.2.16 unrs-resolver: 1.11.1 optionalDependencies: eslint-plugin-import: 2.32.0(@typescript-eslint/parser@7.18.0(eslint@8.57.1)(typescript@5.5.4))(eslint-import-resolver-typescript@3.10.1)(eslint@8.57.1) @@ -22489,8 +22499,6 @@ snapshots: picomatch@2.3.1: {} - picomatch@4.0.3: {} - picomatch@4.0.4: {} pify@2.3.0: {} @@ -22540,14 +22548,6 @@ snapshots: postcss: 8.5.6 ts-node: 10.9.2(@types/node@20.19.13)(typescript@5.5.4) - postcss-load-config@4.0.2(postcss@8.5.6)(ts-node@10.9.2(@types/node@20.19.13)(typescript@5.9.3)): - dependencies: - lilconfig: 3.1.3 - yaml: 2.8.1 - optionalDependencies: - postcss: 8.5.6 - ts-node: 10.9.2(@types/node@20.19.13)(typescript@5.9.3) - postcss-nested@6.2.0(postcss@8.5.6): dependencies: postcss: 8.5.6 @@ -23497,12 +23497,12 @@ snapshots: dependencies: glob: 7.2.3 - roamjs-components@0.88.3(bf7afe7a8e3269c4acb427d06becbe47): + roamjs-components@0.88.3(6fc269b31b2749e4d441ca378d1de710): dependencies: '@blueprintjs/core': 3.50.4(patch_hash=51c5847e0a73a1be0cc263036ff64d8fada46f3b65831ed938dbca5eecf3edc0)(react-dom@18.2.0(react@18.2.0))(react@18.2.0) '@blueprintjs/datetime': 3.23.14(react-dom@18.2.0(react@18.2.0))(react@18.2.0) '@blueprintjs/select': 3.19.1(patch_hash=5b2821b0bf7274e9b64d7824648c596b9e73c61f421d699a6d4c494f12f62355)(react-dom@18.2.0(react@18.2.0))(react@18.2.0) - '@samepage/scripts': 0.74.5(@aws-sdk/client-lambda@3.882.0)(@aws-sdk/client-s3@3.882.0)(@samepage/testing@0.74.5(@playwright/test@1.29.0)(@testing-library/react@16.3.0(@testing-library/dom@10.4.1)(@types/react-dom@18.2.17)(@types/react@18.2.21)(react-dom@18.2.0(react@18.2.0))(react@18.2.0))(@testing-library/user-event@14.6.1(@testing-library/dom@10.4.1))(@types/jsdom@20.0.1)(c8@7.14.0)(debug@4.4.3)(dotenv@16.6.1)(jsdom@20.0.3)(ts-node@10.9.2(@types/node@20.19.13)(typescript@5.9.3)))(archiver@5.3.2)(axios@0.27.2(debug@4.4.3))(debug@4.4.3)(dotenv@16.6.1)(esbuild@0.17.14)(patch-package@6.5.1)(tailwindcss@3.4.17(ts-node@10.9.2(@types/node@20.19.13)(typescript@5.9.3)))(ts-node@10.9.2(@types/node@20.19.13)(typescript@5.9.3))(zod@3.25.76) + '@samepage/scripts': 0.74.5(@aws-sdk/client-lambda@3.882.0)(@aws-sdk/client-s3@3.882.0)(@samepage/testing@0.74.5(@playwright/test@1.29.0)(@testing-library/react@16.3.0(@testing-library/dom@10.4.1)(@types/react-dom@18.2.17)(@types/react@18.2.21)(react-dom@18.2.0(react@18.2.0))(react@18.2.0))(@testing-library/user-event@14.6.1(@testing-library/dom@10.4.1))(@types/jsdom@20.0.1)(c8@7.14.0)(debug@4.4.3)(dotenv@16.6.1)(jsdom@20.0.3)(ts-node@10.9.2(@types/node@20.19.13)(typescript@5.5.4)))(archiver@5.3.2)(axios@0.27.2(debug@4.4.3))(debug@4.4.3)(dotenv@16.6.1)(esbuild@0.17.14)(patch-package@6.5.1)(tailwindcss@3.4.17(ts-node@10.9.2(@types/node@20.19.13)(typescript@5.5.4)))(ts-node@10.9.2(@types/node@20.19.13)(typescript@5.5.4))(zod@3.25.76) '@types/crypto-js': 4.1.1 '@types/cytoscape': 3.21.9 '@types/file-saver': 2.0.5 @@ -24298,10 +24298,6 @@ snapshots: dependencies: tailwindcss: 3.4.17(ts-node@10.9.2(@types/node@20.19.13)(typescript@5.5.4)) - tailwindcss-animate@1.0.7(tailwindcss@3.4.17(ts-node@10.9.2(@types/node@20.19.13)(typescript@5.9.3))): - dependencies: - tailwindcss: 3.4.17(ts-node@10.9.2(@types/node@20.19.13)(typescript@5.9.3)) - tailwindcss@3.4.17(ts-node@10.9.2(@types/node@20.19.13)(typescript@5.5.4)): dependencies: '@alloc/quick-lru': 5.2.0 @@ -24329,33 +24325,6 @@ snapshots: transitivePeerDependencies: - ts-node - tailwindcss@3.4.17(ts-node@10.9.2(@types/node@20.19.13)(typescript@5.9.3)): - dependencies: - '@alloc/quick-lru': 5.2.0 - arg: 5.0.2 - chokidar: 3.6.0 - didyoumean: 1.2.2 - dlv: 1.1.3 - fast-glob: 3.3.3 - glob-parent: 6.0.2 - is-glob: 4.0.3 - jiti: 1.21.7 - lilconfig: 3.1.3 - micromatch: 4.0.8 - normalize-path: 3.0.0 - object-hash: 3.0.0 - picocolors: 1.1.1 - postcss: 8.5.6 - postcss-import: 15.1.0(postcss@8.5.6) - postcss-js: 4.0.1(postcss@8.5.6) - postcss-load-config: 4.0.2(postcss@8.5.6)(ts-node@10.9.2(@types/node@20.19.13)(typescript@5.9.3)) - postcss-nested: 6.2.0(postcss@8.5.6) - postcss-selector-parser: 6.1.2 - resolve: 1.22.10 - sucrase: 3.35.0 - transitivePeerDependencies: - - ts-node - tar-stream@2.2.0: dependencies: bl: 4.1.0 @@ -24431,11 +24400,6 @@ snapshots: tinyexec@1.0.2: {} - tinyglobby@0.2.14: - dependencies: - fdir: 6.5.0(picomatch@4.0.4) - picomatch: 4.0.4 - tinyglobby@0.2.16: dependencies: fdir: 6.5.0(picomatch@4.0.4) @@ -24612,24 +24576,6 @@ snapshots: v8-compile-cache-lib: 3.0.1 yn: 3.1.1 - ts-node@10.9.2(@types/node@20.19.13)(typescript@5.9.3): - dependencies: - '@cspotcode/source-map-support': 0.8.1 - '@tsconfig/node10': 1.0.11 - '@tsconfig/node12': 1.0.11 - '@tsconfig/node14': 1.0.3 - '@tsconfig/node16': 1.0.4 - '@types/node': 20.19.13 - acorn: 8.15.0 - acorn-walk: 8.3.4 - arg: 4.1.3 - create-require: 1.1.1 - diff: 4.0.2 - make-error: 1.3.6 - typescript: 5.9.3 - v8-compile-cache-lib: 3.0.1 - yn: 3.1.1 - ts-toolbelt@6.15.5: {} ts-toolbelt@9.6.0: {} @@ -25112,6 +25058,21 @@ snapshots: '@types/unist': 3.0.3 vfile-message: 4.0.3 + vite@7.3.3(@types/node@20.19.13)(jiti@1.21.7)(tsx@4.20.5)(yaml@2.8.2): + dependencies: + esbuild: 0.27.0 + fdir: 6.5.0(picomatch@4.0.4) + picomatch: 4.0.4 + postcss: 8.5.6 + rollup: 4.60.3 + tinyglobby: 0.2.16 + optionalDependencies: + '@types/node': 20.19.13 + fsevents: 2.3.3 + jiti: 1.21.7 + tsx: 4.20.5 + yaml: 2.8.2 + vite@7.3.3(@types/node@20.19.13)(jiti@1.21.7)(tsx@4.21.0)(yaml@2.8.2): dependencies: esbuild: 0.27.0 @@ -25127,6 +25088,36 @@ snapshots: tsx: 4.21.0 yaml: 2.8.2 + vitest@4.1.6(@edge-runtime/vm@3.2.0)(@opentelemetry/api@1.9.0)(@types/node@20.19.13)(jsdom@20.0.3)(msw@2.11.1(@types/node@20.19.13)(typescript@5.5.4))(vite@7.3.3(@types/node@20.19.13)(jiti@1.21.7)(tsx@4.20.5)(yaml@2.8.2)): + dependencies: + '@vitest/expect': 4.1.6 + '@vitest/mocker': 4.1.6(msw@2.11.1(@types/node@20.19.13)(typescript@5.5.4))(vite@7.3.3(@types/node@20.19.13)(jiti@1.21.7)(tsx@4.20.5)(yaml@2.8.2)) + '@vitest/pretty-format': 4.1.6 + '@vitest/runner': 4.1.6 + '@vitest/snapshot': 4.1.6 + '@vitest/spy': 4.1.6 + '@vitest/utils': 4.1.6 + es-module-lexer: 2.1.0 + expect-type: 1.3.0 + magic-string: 0.30.21 + obug: 2.1.1 + pathe: 2.0.3 + picomatch: 4.0.4 + std-env: 4.1.0 + tinybench: 2.9.0 + tinyexec: 1.0.2 + tinyglobby: 0.2.16 + tinyrainbow: 3.1.0 + vite: 7.3.3(@types/node@20.19.13)(jiti@1.21.7)(tsx@4.20.5)(yaml@2.8.2) + why-is-node-running: 2.3.0 + optionalDependencies: + '@edge-runtime/vm': 3.2.0 + '@opentelemetry/api': 1.9.0 + '@types/node': 20.19.13 + jsdom: 20.0.3 + transitivePeerDependencies: + - msw + vitest@4.1.6(@edge-runtime/vm@3.2.0)(@opentelemetry/api@1.9.0)(@types/node@20.19.13)(jsdom@20.0.3)(msw@2.11.1(@types/node@20.19.13)(typescript@5.5.4))(vite@7.3.3(@types/node@20.19.13)(jiti@1.21.7)(tsx@4.21.0)(yaml@2.8.2)): dependencies: '@vitest/expect': 4.1.6 diff --git a/pnpm-workspace.yaml b/pnpm-workspace.yaml index 34ffc0afa..b2f199388 100644 --- a/pnpm-workspace.yaml +++ b/pnpm-workspace.yaml @@ -27,6 +27,7 @@ catalog: "@types/react": ^19.1.12 "@types/react-dom": ^19.1.9 eslint: 8.57.1 + vitest: ^4.0.0 react: ^19.1.0 react-dom: ^19.1.0 posthog-js: 1.372.10 diff --git a/turbo.json b/turbo.json index de6407e7d..74949a86b 100644 --- a/turbo.json +++ b/turbo.json @@ -66,6 +66,9 @@ "check-types": { "dependsOn": ["^check-types"] }, + "test": { + "outputs": [] + }, "dev": { "passThroughEnv": ["OBSIDIAN_PLUGIN_PATH"], "cache": false,