prototypey.org - atproto lexicon typescript toolkit - mirror https://github.com/tylersayshi/prototypey
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

move cli into prototypey

Tyler 1f6f5419 2bfd1c3a

+38 -202
-3
.github/workflows/ci.yml
··· 6 6 - uses: actions/checkout@v4 7 7 - uses: ./.github/actions/prepare 8 8 - run: pnpm build 9 - - run: node packages/prototypey/lib/index.js 10 9 lint: 11 10 name: Lint 12 11 runs-on: ubuntu-latest ··· 27 26 steps: 28 27 - uses: actions/checkout@v4 29 28 - uses: ./.github/actions/prepare 30 - - run: pnpm build 31 29 - run: pnpm tsc 32 30 test: 33 31 name: Test ··· 35 33 steps: 36 34 - uses: actions/checkout@v4 37 35 - uses: ./.github/actions/prepare 38 - - run: pnpm build 39 36 - run: pnpm test 40 37 benchmark_types: 41 38 name: Benchmark Types
-1
eslint.config.js
··· 9 9 "node_modules", 10 10 "pnpm-lock.yaml", 11 11 "**/setup-vitest.ts", 12 - "**/cli.js", 13 12 "**/tests/**", 14 13 ], 15 14 },
-68
packages/cli/README.md
··· 1 - # @prototypey/cli 2 - 3 - CLI tool for generating types from ATProto lexicon schemas. 4 - 5 - ## Installation 6 - 7 - ```bash 8 - npm install -g @prototypey/cli 9 - ``` 10 - 11 - Or use directly with npx: 12 - 13 - ```bash 14 - npx @prototypey/cli 15 - ``` 16 - 17 - ## Commands 18 - 19 - ### `gen-emit` 20 - 21 - Emit JSON lexicon schemas from authored TypeScript files. 22 - 23 - **Usage:** 24 - 25 - ```bash 26 - prototypey gen-emit <outdir> <sources...> 27 - ``` 28 - 29 - **Arguments:** 30 - 31 - - `outdir` - Output directory for emitted JSON schema files 32 - - `sources...` - One or more glob patterns matching TypeScript source files 33 - 34 - **Example:** 35 - 36 - ```bash 37 - prototypey gen-emit ./lexicons ./src/lexicons/**/*.ts 38 - ``` 39 - 40 - **What it does:** 41 - 42 - - Scans TypeScript files for exported lexicon definitions 43 - - Extracts the `.json` property from each lexicon 44 - - Emits properly formatted JSON lexicon schema files 45 - - Names output files by lexicon ID (e.g., `app.bsky.feed.post.json`) 46 - 47 - ## Workflow 48 - 49 - The typical workflow combines both commands for bidirectional type safety: 50 - 51 - 1. **Author lexicons in TypeScript** using the `prototypey` library 52 - 2. **Emit to JSON** with `gen-emit` for runtime validation and API contracts 53 - 54 - ```bash 55 - # Write your lexicons in TypeScript 56 - # src/lexicons/app.bsky.actor.profile.ts 57 - 58 - # Emit JSON schemas 59 - prototypey gen-emit ./schemas ./src/lexicons/**/*.ts 60 - ``` 61 - 62 - ## Requirements 63 - 64 - - Node.js >= 20.19.0 65 - 66 - ## License 67 - 68 - MIT
-43
packages/cli/package.json
··· 1 - { 2 - "name": "@prototypey/cli", 3 - "version": "0.2.1", 4 - "description": "CLI tool for generating types from ATProto lexicon schemas", 5 - "repository": { 6 - "type": "git", 7 - "url": "git+https://github.com/tylersayshi/prototypey.git", 8 - "directory": "packages/cli" 9 - }, 10 - "license": "MIT", 11 - "author": { 12 - "name": "tylersayshi", 13 - "email": "hi@tylur.dev" 14 - }, 15 - "type": "module", 16 - "bin": { 17 - "prototypey": "./lib/index.js" 18 - }, 19 - "files": [ 20 - "lib/", 21 - "README.md" 22 - ], 23 - "scripts": { 24 - "build": "tsdown --entry src/index.ts --format esm --dts false", 25 - "lint": "eslint .", 26 - "test": "vitest run", 27 - "tsc": "tsc" 28 - }, 29 - "dependencies": { 30 - "prototypey": "workspace:*", 31 - "sade": "^1.8.1", 32 - "tinyglobby": "^0.2.15" 33 - }, 34 - "devDependencies": { 35 - "@types/node": "24.0.4", 36 - "tsdown": "0.12.7", 37 - "typescript": "5.8.3", 38 - "vitest": "^3.2.4" 39 - }, 40 - "engines": { 41 - "node": ">=20.19.0" 42 - } 43 - }
packages/cli/src/commands/gen-emit.ts packages/prototypey/cli/gen-emit.ts
+3 -1
packages/cli/src/index.ts packages/prototypey/cli/main.ts
··· 1 + #!/usr/bin/env node 2 + 1 3 import { readFile } from "node:fs/promises"; 2 4 import sade from "sade"; 3 - import { genEmit } from "./commands/gen-emit.ts"; 5 + import { genEmit } from "./gen-emit.ts"; 4 6 5 7 const pkg = JSON.parse( 6 8 await readFile(new URL("../package.json", import.meta.url), "utf-8"),
+2 -1
packages/cli/tests/commands/gen-emit.test.ts packages/prototypey/cli/tests/gen-emit.test.ts
··· 1 1 import { expect, test, describe, beforeEach, afterEach } from "vitest"; 2 2 import { mkdir, writeFile, rm, readFile } from "node:fs/promises"; 3 3 import { join } from "node:path"; 4 - import { genEmit } from "../../src/commands/gen-emit.ts"; 4 + 5 5 import { tmpdir } from "node:os"; 6 + import { genEmit } from "../gen-emit.ts"; 6 7 7 8 describe("genEmit", () => { 8 9 let testDir: string;
packages/cli/tests/fixtures/simple-lexicon.ts packages/prototypey/cli/tests/simple-lexicon.ts
+2 -7
packages/cli/tests/integration/cli.test.ts packages/prototypey/cli/tests/cli.test.ts
··· 1 1 import { expect, test, describe } from "vitest"; 2 - import { readFileSync } from "node:fs"; 3 - import { resolve } from "node:path"; 4 - import { runCLI } from "../test-utils.js"; 5 - 6 - const pkg = JSON.parse( 7 - readFileSync(resolve(__dirname, "../../package.json"), "utf-8"), 8 - ) as { version: string }; 2 + import { runCLI } from "./test-utils.ts"; 3 + import pkg from "../../package.json" with { type: "json" }; 9 4 10 5 describe("CLI Integration", () => { 11 6 test("shows error when called without arguments", async () => {
+1 -1
packages/cli/tests/integration/error-handling.test.ts packages/prototypey/cli/tests/error-handling.test.ts
··· 2 2 import { mkdir, writeFile, rm } from "node:fs/promises"; 3 3 import { join } from "node:path"; 4 4 import { tmpdir } from "node:os"; 5 - import { runCLI } from "../test-utils.js"; 5 + import { runCLI } from "./test-utils.ts"; 6 6 7 7 describe("CLI Error Handling", () => { 8 8 let testDir: string;
+2 -3
packages/cli/tests/integration/workflow.test.ts packages/prototypey/cli/tests/workflow.test.ts
··· 1 - import { expect, test, describe, beforeEach, afterEach } from "vitest"; 2 - import { mkdir, writeFile, rm, readFile } from "node:fs/promises"; 1 + import { test, describe, beforeEach, afterEach } from "vitest"; 2 + import { mkdir, writeFile, rm } from "node:fs/promises"; 3 3 import { join } from "node:path"; 4 4 import { tmpdir } from "node:os"; 5 - import { runCLI } from "../test-utils.js"; 6 5 7 6 describe("CLI End-to-End Workflow", () => { 8 7 let testDir: string;
+3 -6
packages/cli/tests/test-utils.ts packages/prototypey/cli/tests/test-utils.ts
··· 1 1 import { spawn } from "node:child_process"; 2 - import { dirname, join } from "node:path"; 3 2 import { fileURLToPath } from "node:url"; 3 + 4 + const cliPath = fileURLToPath(new URL("../main.ts", import.meta.url)); 4 5 5 6 export function runCLI( 6 7 args: string[] = [], 7 8 options?: { cwd?: string; env?: NodeJS.ProcessEnv }, 8 9 ): Promise<{ stdout: string; stderr: string; code: number }> { 9 10 return new Promise((resolve) => { 10 - const cliPath = join( 11 - dirname(fileURLToPath(import.meta.url)), 12 - "../lib/index.js", 13 - ); 14 - const child = spawn("node", [cliPath, ...args], { 11 + const child = spawn("node", ["--experimental-strip-types", cliPath, ...args], { 15 12 cwd: options?.cwd ?? process.cwd(), 16 13 env: options?.env ?? process.env, 17 14 });
-4
packages/cli/tsconfig.json
··· 1 - { 2 - "extends": "../../tsconfig.json", 3 - "include": ["src", "tests"] 4 - }
-8
packages/cli/tsdown.config.ts
··· 1 - import { defineConfig } from "tsdown"; 2 - 3 - export default defineConfig({ 4 - dts: true, 5 - entry: ["src/index.ts"], 6 - outDir: "lib", 7 - unbundle: true, 8 - });
-7
packages/cli/vitest.config.ts
··· 1 - import { defineConfig } from "vitest/config"; 2 - 3 - export default defineConfig({ 4 - test: { 5 - include: ["tests/**/*.test.ts"], 6 - }, 7 - });
-3
packages/prototypey/cli.js
··· 1 - #!/usr/bin/env node 2 - 3 - import "@prototypey/cli/lib/index.js";
+5 -5
packages/prototypey/package.json
··· 14 14 "email": "hi@tylur.dev" 15 15 }, 16 16 "type": "module", 17 - "main": "lib/index.js", 18 17 "bin": { 19 - "prototypey": "./cli.js" 18 + "prototypey": "./lib/cli/main.js" 20 19 }, 21 20 "exports": { 22 - ".": "./lib/index.js", 23 - "./lib/*.d.ts": "./lib/*.d.ts" 21 + ".": "./lib/core/main.js", 22 + "./lib/core/*.d.ts": "./lib/core/*.d.ts" 24 23 }, 25 24 "files": [ 26 25 "lib/", ··· 37 36 }, 38 37 "dependencies": { 39 38 "@atproto/lexicon": "^0.5.1", 40 - "@prototypey/cli": "workspace:*" 39 + "sade": "^1.8.1", 40 + "tinyglobby": "^0.2.15" 41 41 }, 42 42 "devDependencies": { 43 43 "@ark/attest": "^0.49.0",
packages/prototypey/src/index.ts packages/prototypey/core/main.ts
packages/prototypey/src/infer.ts packages/prototypey/core/infer.ts
packages/prototypey/src/lib.ts packages/prototypey/core/lib.ts
packages/prototypey/src/type-utils.ts packages/prototypey/core/type-utils.ts
+1 -1
packages/prototypey/tests/base-case.test.ts packages/prototypey/core/tests/base-case.test.ts
··· 1 1 import { expect, test } from "vitest"; 2 - import { lx } from "../src/lib.ts"; 2 + import { lx } from "../lib.ts"; 3 3 4 4 test("app.bsky.actor.profile", () => { 5 5 const profileNamespace = lx.lexicon("app.bsky.actor.profile", {
+1 -1
packages/prototypey/tests/bsky-actor.test.ts packages/prototypey/core/tests/bsky-actor.test.ts
··· 1 1 import { expect, test } from "vitest"; 2 - import { lx } from "../src/lib.ts"; 2 + import { lx } from "../lib.ts"; 3 3 4 4 test("app.bsky.actor.defs - profileViewBasic", () => { 5 5 const profileViewBasic = lx.object({
+1 -1
packages/prototypey/tests/bsky-feed.test.ts packages/prototypey/core/tests/bsky-feed.test.ts
··· 1 1 import { expect, test } from "vitest"; 2 - import { lx } from "../src/lib.ts"; 2 + import { lx } from "../lib.ts"; 3 3 4 4 test("app.bsky.feed.defs - postView", () => { 5 5 const postView = lx.object({
+1 -1
packages/prototypey/tests/infer.bench.ts packages/prototypey/core/tests/infer.bench.ts
··· 1 1 import { bench } from "@ark/attest"; 2 - import { lx } from "../src/lib.ts"; 2 + import { lx } from "../lib.ts"; 3 3 4 4 bench("infer with simple object", () => { 5 5 const schema = lx.lexicon("test.simple", {
+1 -1
packages/prototypey/tests/infer.test.ts packages/prototypey/core/tests/infer.test.ts
··· 1 1 import { test } from "vitest"; 2 2 import { attest } from "@ark/attest"; 3 - import { lx } from "../src/lib.ts"; 3 + import { lx } from "../lib.ts"; 4 4 5 5 test("InferNS produces expected type shape", () => { 6 6 const exampleLexicon = lx.lexicon("com.example.post", {
+1 -1
packages/prototypey/tests/primitives.test.ts packages/prototypey/core/tests/primitives.test.ts
··· 1 1 import { expect, test } from "vitest"; 2 - import { lx } from "../src/lib.ts"; 2 + import { lx } from "../lib.ts"; 3 3 4 4 test("lx.null()", () => { 5 5 const result = lx.null();
+1 -1
packages/prototypey/tests/validation-baseline.bench.ts packages/prototypey/core/tests/validation-baseline.bench.ts
··· 1 1 import { bench, describe } from "vitest"; 2 2 import { Lexicons } from "@atproto/lexicon"; 3 - import { lx } from "../src/lib.ts"; 3 + import { lx } from "../lib.ts"; 4 4 5 5 // Phase 1 Benchmarks: Baseline measurements before implementation 6 6
+1 -1
packages/prototypey/tests/validation-eager.bench.ts packages/prototypey/core/tests/validation-eager.bench.ts
··· 1 1 import { bench, describe } from "vitest"; 2 - import { lx } from "../src/lib.ts"; 2 + import { lx } from "../lib.ts"; 3 3 4 4 // Phase 2 Benchmarks: Eager loading strategy 5 5
+1 -1
packages/prototypey/tests/validation.test.ts packages/prototypey/core/tests/validation.test.ts
··· 1 1 import { describe, it, expect } from "vitest"; 2 - import { lx } from "../src/lib.ts"; 2 + import { lx } from "../lib.ts"; 3 3 4 4 describe("basic validation", () => { 5 5 const schema = lx.lexicon("test.simple", {
+1 -1
packages/prototypey/tsconfig.json
··· 1 1 { 2 2 "extends": "../../tsconfig.json", 3 - "include": ["src", "tests"] 3 + "include": ["core", "cli"] 4 4 }
+2 -1
packages/prototypey/tsdown.config.ts
··· 2 2 3 3 export default defineConfig({ 4 4 dts: true, 5 - entry: ["src/index.ts"], 5 + entry: ["core/main.ts", "cli/main.ts"], 6 + clean: true, 6 7 outDir: "lib", 7 8 unbundle: true, 8 9 });
+1 -1
packages/prototypey/vitest.config.ts
··· 2 2 3 3 export default defineConfig({ 4 4 test: { 5 - include: ["tests/*.test.ts"], 5 + include: ["**/*.test.ts"], 6 6 globalSetup: ["setup-vitest.ts"], 7 7 }, 8 8 });
+3 -3
packages/site/src/components/Editor.tsx
··· 47 47 }); 48 48 49 49 void Promise.all([ 50 - import("prototypey/lib/type-utils.d.ts?raw"), 51 - import("prototypey/lib/infer.d.ts?raw"), 52 - import("prototypey/lib/lib.d.ts?raw"), 50 + import("prototypey/lib/core/type-utils.d.ts?raw"), 51 + import("prototypey/lib/core/infer.d.ts?raw"), 52 + import("prototypey/lib/core/lib.d.ts?raw"), 53 53 ]).then(([typeUtilsModule, inferModule, libModule]) => { 54 54 const stripImportsExports = (content: string) => 55 55 content
+4 -26
pnpm-lock.yaml
··· 24 24 specifier: 8.35.0 25 25 version: 8.35.0(eslint@9.29.0(jiti@2.6.1))(typescript@5.8.3) 26 26 27 - packages/cli: 27 + packages/prototypey: 28 28 dependencies: 29 - prototypey: 30 - specifier: workspace:* 31 - version: link:../prototypey 29 + '@atproto/lexicon': 30 + specifier: ^0.5.1 31 + version: 0.5.1 32 32 sade: 33 33 specifier: ^1.8.1 34 34 version: 1.8.1 35 35 tinyglobby: 36 36 specifier: ^0.2.15 37 37 version: 0.2.15 38 - devDependencies: 39 - '@types/node': 40 - specifier: 24.0.4 41 - version: 24.0.4 42 - tsdown: 43 - specifier: 0.12.7 44 - version: 0.12.7(typescript@5.8.3) 45 - typescript: 46 - specifier: 5.8.3 47 - version: 5.8.3 48 - vitest: 49 - specifier: ^3.2.4 50 - version: 3.2.4(@types/node@24.0.4)(esbuild@0.25.10)(jiti@2.6.1)(jsdom@25.0.1) 51 - 52 - packages/prototypey: 53 - dependencies: 54 - '@atproto/lexicon': 55 - specifier: ^0.5.1 56 - version: 0.5.1 57 - '@prototypey/cli': 58 - specifier: workspace:* 59 - version: link:../cli 60 38 devDependencies: 61 39 '@ark/attest': 62 40 specifier: ^0.49.0