From c5fe70449b50c96f6ae64a8b114b487525549272 Mon Sep 17 00:00:00 2001 From: Evan Sosenko Date: Mon, 17 Jun 2024 16:27:04 -0500 Subject: [PATCH 1/6] Add Usage --- README.md | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 4da4563..74be9ce 100644 --- a/README.md +++ b/README.md @@ -9,16 +9,30 @@ Build tools for the Seam API using this blueprint. TODO +## Motivation + +TODO + ## Installation Add this as a dependency to your project using [npm] with ``` -$ npm install @seamapi/blueprint +$ npm install --save-dev @seamapi/blueprint ``` [npm]: https://www.npmjs.com/ +## Usage + +```ts +import { createBlueprint } from '@seamapi/blueprint' +import * as types from '@seamapi/types' + +const blueprint = createBlueprint(types) +console.log(JSON.stringify(blueprint) +``` + ## Development and Testing ### Quickstart From 6c3f06fa8371f8fab26eaf61475833d7f68e175e Mon Sep 17 00:00:00 2001 From: Evan Sosenko Date: Mon, 17 Jun 2024 16:43:36 -0500 Subject: [PATCH 2/6] Add test fixture --- package-lock.json | 12 ++++- package.json | 3 +- test/fixtures/types/index.ts | 8 +++ test/fixtures/types/model-types.ts | 5 ++ test/fixtures/types/openapi.ts | 79 ++++++++++++++++++++++++++++ test/fixtures/types/route-schemas.ts | 0 test/fixtures/types/route-specs.ts | 13 +++++ test/fixtures/types/route-types.ts | 25 +++++++++ test/fixtures/types/schemas.ts | 6 +++ 9 files changed, 149 insertions(+), 2 deletions(-) create mode 100644 test/fixtures/types/index.ts create mode 100644 test/fixtures/types/model-types.ts create mode 100644 test/fixtures/types/openapi.ts create mode 100644 test/fixtures/types/route-schemas.ts create mode 100644 test/fixtures/types/route-specs.ts create mode 100644 test/fixtures/types/route-types.ts create mode 100644 test/fixtures/types/schemas.ts diff --git a/package-lock.json b/package-lock.json index 1aaf6e1..b70fc28 100644 --- a/package-lock.json +++ b/package-lock.json @@ -24,7 +24,8 @@ "tsc-alias": "^1.8.2", "tsup": "^8.0.1", "tsx": "^4.6.2", - "typescript": "~5.3.3" + "typescript": "~5.3.3", + "zod": "^3.23.8" }, "engines": { "node": ">=18.12.0", @@ -8178,6 +8179,15 @@ "funding": { "url": "https://github.com/sponsors/sindresorhus" } + }, + "node_modules/zod": { + "version": "3.23.8", + "resolved": "https://registry.npmjs.org/zod/-/zod-3.23.8.tgz", + "integrity": "sha512-XBx9AXhXktjUqnepgTiE5flcKIYWi/rme0Eaj+5Y0lftuGBq+jyRu/md4WnuxqgP1ubdpNCsYEYPxrzVHD8d6g==", + "dev": true, + "funding": { + "url": "https://github.com/sponsors/colinhacks" + } } } } diff --git a/package.json b/package.json index 4a4a7c8..695a642 100644 --- a/package.json +++ b/package.json @@ -83,6 +83,7 @@ "tsc-alias": "^1.8.2", "tsup": "^8.0.1", "tsx": "^4.6.2", - "typescript": "~5.3.3" + "typescript": "~5.3.3", + "zod": "^3.23.8" } } diff --git a/test/fixtures/types/index.ts b/test/fixtures/types/index.ts new file mode 100644 index 0000000..3a9695f --- /dev/null +++ b/test/fixtures/types/index.ts @@ -0,0 +1,8 @@ +import * as schemas from './schemas.js' + +export { schemas } + +export * from './model-types.js' +export { default as openapi } from './openapi.js' +export * from './route-schemas.js' +export * from './route-types.js' diff --git a/test/fixtures/types/model-types.ts b/test/fixtures/types/model-types.ts new file mode 100644 index 0000000..40b064e --- /dev/null +++ b/test/fixtures/types/model-types.ts @@ -0,0 +1,5 @@ +import type { z } from 'zod' + +import type { foo } from './schemas.js' + +export type Foo = z.infer diff --git a/test/fixtures/types/openapi.ts b/test/fixtures/types/openapi.ts new file mode 100644 index 0000000..00d1d76 --- /dev/null +++ b/test/fixtures/types/openapi.ts @@ -0,0 +1,79 @@ +export default { + openapi: '3.0.0', + info: { title: 'Foo', version: '1.0.0' }, + servers: [{ url: 'https://example.com' }], + tags: [{ description: 'foos', name: '/foos' }], + components: { + schemas: { + foo: { + type: 'object', + properties: { + foo_id: { + description: 'Foo id', + format: 'uuid', + type: 'string', + }, + name: { + description: 'Foo name', + type: 'string', + }, + }, + required: ['foo_id', 'name'], + }, + }, + }, + paths: { + '/foos/get': { + get: { + operationId: 'foosGetGet', + responses: { + 200: { + content: { + 'application/json': { + schema: { + properties: { + ok: { type: 'boolean' }, + foo: { $ref: '#/components/schemas/foo' }, + }, + required: ['foo', 'ok'], + type: 'object', + }, + }, + }, + description: 'OK', + }, + 400: { description: 'Bad Request' }, + 401: { description: 'Unauthorized' }, + }, + security: [], + summary: '/foos/get', + tags: ['/foos'], + }, + post: { + operationId: 'foosGetPost', + responses: { + 200: { + content: { + 'application/json': { + schema: { + properties: { + ok: { type: 'boolean' }, + foo: { $ref: '#/components/schemas/foo' }, + }, + required: ['foo', 'ok'], + type: 'object', + }, + }, + }, + description: 'OK', + }, + 400: { description: 'Bad Request' }, + 401: { description: 'Unauthorized' }, + }, + security: [], + summary: '/foos/get', + tags: ['/foos'], + }, + }, + }, +} diff --git a/test/fixtures/types/route-schemas.ts b/test/fixtures/types/route-schemas.ts new file mode 100644 index 0000000..e69de29 diff --git a/test/fixtures/types/route-specs.ts b/test/fixtures/types/route-specs.ts new file mode 100644 index 0000000..0f5e31e --- /dev/null +++ b/test/fixtures/types/route-specs.ts @@ -0,0 +1,13 @@ +import { z } from 'zod' + +import * as schemas from './schemas.js' + +export const routes = { + '/foos/get': { + auth: 'none', + methods: ['GET', 'POST'], + jsonResponse: z.object({ + foo: schemas.foo, + }), + }, +} as const diff --git a/test/fixtures/types/route-types.ts b/test/fixtures/types/route-types.ts new file mode 100644 index 0000000..54d2ec9 --- /dev/null +++ b/test/fixtures/types/route-types.ts @@ -0,0 +1,25 @@ +export interface Routes { + '/foos/get': { + route: '/foos/get' + method: 'GET' | 'POST' + queryParams: Record + jsonBody: Record + commonParams: Record + formData: Record + jsonResponse: { + foo: { + foo_id: string + name: string + } + } + } +} + +export type RouteResponse = + Routes[Path]['jsonResponse'] + +export type RouteRequestBody = + Routes[Path]['jsonBody'] & Routes[Path]['commonParams'] + +export type RouteRequestParams = + Routes[Path]['queryParams'] & Routes[Path]['commonParams'] diff --git a/test/fixtures/types/schemas.ts b/test/fixtures/types/schemas.ts new file mode 100644 index 0000000..4125ae8 --- /dev/null +++ b/test/fixtures/types/schemas.ts @@ -0,0 +1,6 @@ +import { z } from 'zod' + +export const foo = z.object({ + foo_id: z.string().uuid(), + name: z.string(), +}) From a7589be5ad9fc94fa113f4653370f6ca04e4fbfd Mon Sep 17 00:00:00 2001 From: Evan Sosenko Date: Mon, 17 Jun 2024 16:44:08 -0500 Subject: [PATCH 3/6] Add @seamapi/types --- package-lock.json | 14 ++++++++++++++ package.json | 1 + 2 files changed, 15 insertions(+) diff --git a/package-lock.json b/package-lock.json index b70fc28..cbf9ea1 100644 --- a/package-lock.json +++ b/package-lock.json @@ -9,6 +9,7 @@ "version": "0.0.1", "license": "MIT", "devDependencies": { + "@seamapi/types": "1.184.0", "@types/node": "^20.8.10", "ava": "^6.0.1", "c8": "^10.1.2", @@ -1046,6 +1047,19 @@ "win32" ] }, + "node_modules/@seamapi/types": { + "version": "1.184.0", + "resolved": "https://registry.npmjs.org/@seamapi/types/-/types-1.184.0.tgz", + "integrity": "sha512-1XR7Hr0uuYuheiide8l5fHx68caX7nMzQ3eyqe2YEyST6gzMDHrmg/hmKtfxSSqEsvtmvlZ7Lr8X4ooo02xI5Q==", + "dev": true, + "engines": { + "node": ">=18.12.0", + "npm": ">= 9.0.0" + }, + "peerDependencies": { + "zod": "^3.21.4" + } + }, "node_modules/@sindresorhus/merge-streams": { "version": "2.3.0", "resolved": "https://registry.npmjs.org/@sindresorhus/merge-streams/-/merge-streams-2.3.0.tgz", diff --git a/package.json b/package.json index 695a642..155131d 100644 --- a/package.json +++ b/package.json @@ -68,6 +68,7 @@ "npm": ">= 9.0.0" }, "devDependencies": { + "@seamapi/types": "1.184.0", "@types/node": "^20.8.10", "ava": "^6.0.1", "c8": "^10.1.2", From e12ff07297d51212f0d48a97ae6206f90d874a9e Mon Sep 17 00:00:00 2001 From: Evan Sosenko Date: Mon, 17 Jun 2024 16:59:45 -0500 Subject: [PATCH 4/6] Export blueprint API --- examples/blueprint.ts | 24 ++++++++++++++++++ examples/index.ts | 3 ++- src/lib/blueprint.ts | 15 +++++++++++ src/lib/index.ts | 5 ++++ src/lib/openapi.ts | 5 ++++ test/blueprint.test.ts | 10 ++++++++ test/fixtures/types/route-schemas.ts | 13 ++++++++++ test/seamapi-blueprint.test.ts | 9 +++++++ test/snapshots/blueprint.test.ts.md | 13 ++++++++++ test/snapshots/blueprint.test.ts.snap | Bin 0 -> 192 bytes test/snapshots/seamapi-blueprint.test.ts.md | 13 ++++++++++ test/snapshots/seamapi-blueprint.test.ts.snap | Bin 0 -> 202 bytes 12 files changed, 109 insertions(+), 1 deletion(-) create mode 100644 examples/blueprint.ts create mode 100644 src/lib/blueprint.ts create mode 100644 src/lib/openapi.ts create mode 100644 test/blueprint.test.ts create mode 100644 test/seamapi-blueprint.test.ts create mode 100644 test/snapshots/blueprint.test.ts.md create mode 100644 test/snapshots/blueprint.test.ts.snap create mode 100644 test/snapshots/seamapi-blueprint.test.ts.md create mode 100644 test/snapshots/seamapi-blueprint.test.ts.snap diff --git a/examples/blueprint.ts b/examples/blueprint.ts new file mode 100644 index 0000000..5dbc686 --- /dev/null +++ b/examples/blueprint.ts @@ -0,0 +1,24 @@ +import type { Builder, Command, Describe, Handler } from 'landlubber' + +import { createBlueprint, type TypesModule } from '@seamapi/blueprint' + +interface Options { + moduleName: string +} + +export const command: Command = 'blueprint [moduleName]' + +export const describe: Describe = 'Create a blueprint from a type module' + +export const builder: Builder = { + moduleName: { + type: 'string', + default: '@seamapi/types/connect', + describe: 'Module name or path to import', + }, +} + +export const handler: Handler = async ({ moduleName, logger }) => { + const types = (await import(moduleName)) as TypesModule + logger.info({ data: createBlueprint(types) }, 'blueprint') +} diff --git a/examples/index.ts b/examples/index.ts index 7a1cc11..5cf5bde 100755 --- a/examples/index.ts +++ b/examples/index.ts @@ -2,8 +2,9 @@ import landlubber from 'landlubber' +import * as blueprint from './blueprint.js' import * as todo from './todo.js' -const commands = [todo] +const commands = [blueprint, todo] await landlubber(commands).parse() diff --git a/src/lib/blueprint.ts b/src/lib/blueprint.ts new file mode 100644 index 0000000..9c9b691 --- /dev/null +++ b/src/lib/blueprint.ts @@ -0,0 +1,15 @@ +import type { Openapi } from './openapi.js' + +export interface Blueprint { + name: string +} + +export interface TypesModule { + openapi: Openapi +} + +export const createBlueprint = ({ openapi }: TypesModule): Blueprint => { + return { + name: openapi.info.title, + } +} diff --git a/src/lib/index.ts b/src/lib/index.ts index 0cbac41..0f279ba 100644 --- a/src/lib/index.ts +++ b/src/lib/index.ts @@ -1 +1,6 @@ +export { + type Blueprint, + createBlueprint, + type TypesModule, +} from './blueprint.js' export { todo } from './todo.js' diff --git a/src/lib/openapi.ts b/src/lib/openapi.ts new file mode 100644 index 0000000..140a788 --- /dev/null +++ b/src/lib/openapi.ts @@ -0,0 +1,5 @@ +export interface Openapi { + info: { + title: string + } +} diff --git a/test/blueprint.test.ts b/test/blueprint.test.ts new file mode 100644 index 0000000..95d9cb7 --- /dev/null +++ b/test/blueprint.test.ts @@ -0,0 +1,10 @@ +import test from 'ava' + +import { createBlueprint } from '@seamapi/blueprint' + +import * as types from './fixtures/types/index.js' + +test('createBlueprint', (t) => { + const blueprint = createBlueprint(types) + t.snapshot(blueprint, 'blueprint') +}) diff --git a/test/fixtures/types/route-schemas.ts b/test/fixtures/types/route-schemas.ts index e69de29..0f5e31e 100644 --- a/test/fixtures/types/route-schemas.ts +++ b/test/fixtures/types/route-schemas.ts @@ -0,0 +1,13 @@ +import { z } from 'zod' + +import * as schemas from './schemas.js' + +export const routes = { + '/foos/get': { + auth: 'none', + methods: ['GET', 'POST'], + jsonResponse: z.object({ + foo: schemas.foo, + }), + }, +} as const diff --git a/test/seamapi-blueprint.test.ts b/test/seamapi-blueprint.test.ts new file mode 100644 index 0000000..891ca3d --- /dev/null +++ b/test/seamapi-blueprint.test.ts @@ -0,0 +1,9 @@ +import { openapi } from '@seamapi/types/connect' +import test from 'ava' + +import { createBlueprint } from '@seamapi/blueprint' + +test('createBlueprint', (t) => { + const blueprint = createBlueprint({ openapi }) + t.snapshot(blueprint, 'blueprint') +}) diff --git a/test/snapshots/blueprint.test.ts.md b/test/snapshots/blueprint.test.ts.md new file mode 100644 index 0000000..2c9afcf --- /dev/null +++ b/test/snapshots/blueprint.test.ts.md @@ -0,0 +1,13 @@ +# Snapshot report for `test/blueprint.test.ts` + +The actual snapshot is saved in `blueprint.test.ts.snap`. + +Generated by [AVA](https://avajs.dev). + +## createBlueprint + +> blueprint + + { + name: 'Foo', + } diff --git a/test/snapshots/blueprint.test.ts.snap b/test/snapshots/blueprint.test.ts.snap new file mode 100644 index 0000000000000000000000000000000000000000..e1fc83c23dfd908dbd7a7c59e757ba815bf3e006 GIT binary patch literal 192 zcmV;x06+ghRzVPKfX zJzuYiAs>qf000000009$jWH5}Fcbyf14SE07(9oSC$O-!v9L|TcZ|k_A>RXV6gjD5 zfm`iX`?=YW+%u1psMjFL4PsP|;Vu2(qxu|8pYKWYICY&-bG?*U;Rn|&_5cn5T2>9K uvwetD@~?GWgBy_G7A=b%OK{n65zR~HC{HO#Fjj)M^Y#lXcmJrD0001^K~g&a literal 0 HcmV?d00001 diff --git a/test/snapshots/seamapi-blueprint.test.ts.md b/test/snapshots/seamapi-blueprint.test.ts.md new file mode 100644 index 0000000..6e45115 --- /dev/null +++ b/test/snapshots/seamapi-blueprint.test.ts.md @@ -0,0 +1,13 @@ +# Snapshot report for `test/seamapi-blueprint.test.ts` + +The actual snapshot is saved in `seamapi-blueprint.test.ts.snap`. + +Generated by [AVA](https://avajs.dev). + +## createBlueprint + +> blueprint + + { + name: 'Seam Connect', + } diff --git a/test/snapshots/seamapi-blueprint.test.ts.snap b/test/snapshots/seamapi-blueprint.test.ts.snap new file mode 100644 index 0000000000000000000000000000000000000000..f129021b383dd5d54894de004e9e50d52ee1c68a GIT binary patch literal 202 zcmV;*05$(XRzVa z3erfbEFX&q000000009$jj<7eKoCXugQ9_sFj#;U7+HZ9U|?cmuy?HE>2b$!YXOuZ zl{yCaqW7Zrxf>ttD-ENlQ!ml>!YW7qmaca}T?*W#N7OWoO~cC9TTTo5fhDp%5gmxA zMp2{#uqLVNC#GLp8E3a>BgAEO0ARtS-Xs?i521tK!*+cV_y30b6cONT2`! E0N|@sQUCw| literal 0 HcmV?d00001 From 647110c54d5d8351c6c027894a0a617340a7825d Mon Sep 17 00:00:00 2001 From: Evan Sosenko Date: Mon, 17 Jun 2024 17:00:34 -0500 Subject: [PATCH 5/6] Remove todo module --- examples/index.ts | 3 +-- examples/todo.ts | 23 ----------------------- src/lib/index.ts | 1 - src/lib/todo.test.ts | 7 ------- src/lib/todo.ts | 1 - test/todo.test.ts | 7 ------- 6 files changed, 1 insertion(+), 41 deletions(-) delete mode 100644 examples/todo.ts delete mode 100644 src/lib/todo.test.ts delete mode 100644 src/lib/todo.ts delete mode 100644 test/todo.test.ts diff --git a/examples/index.ts b/examples/index.ts index 5cf5bde..141d555 100755 --- a/examples/index.ts +++ b/examples/index.ts @@ -3,8 +3,7 @@ import landlubber from 'landlubber' import * as blueprint from './blueprint.js' -import * as todo from './todo.js' -const commands = [blueprint, todo] +const commands = [blueprint] await landlubber(commands).parse() diff --git a/examples/todo.ts b/examples/todo.ts deleted file mode 100644 index b688584..0000000 --- a/examples/todo.ts +++ /dev/null @@ -1,23 +0,0 @@ -import type { Builder, Command, Describe, Handler } from 'landlubber' - -import { todo } from '@seamapi/blueprint' - -interface Options { - x: string -} - -export const command: Command = 'todo x' - -export const describe: Describe = 'TODO' - -export const builder: Builder = { - x: { - type: 'string', - default: 'TODO', - describe: 'TODO', - }, -} - -export const handler: Handler = async ({ x, logger }) => { - logger.info({ data: todo(x) }, 'TODO') -} diff --git a/src/lib/index.ts b/src/lib/index.ts index 0f279ba..8745d01 100644 --- a/src/lib/index.ts +++ b/src/lib/index.ts @@ -3,4 +3,3 @@ export { createBlueprint, type TypesModule, } from './blueprint.js' -export { todo } from './todo.js' diff --git a/src/lib/todo.test.ts b/src/lib/todo.test.ts deleted file mode 100644 index 4f4b033..0000000 --- a/src/lib/todo.test.ts +++ /dev/null @@ -1,7 +0,0 @@ -import test from 'ava' - -import { todo } from './todo.js' - -test('todo: returns argument', (t) => { - t.is(todo('todo'), 'todo', 'returns input') -}) diff --git a/src/lib/todo.ts b/src/lib/todo.ts deleted file mode 100644 index 5633fe7..0000000 --- a/src/lib/todo.ts +++ /dev/null @@ -1 +0,0 @@ -export const todo = (x: string): string => x diff --git a/test/todo.test.ts b/test/todo.test.ts deleted file mode 100644 index 6e7e0f2..0000000 --- a/test/todo.test.ts +++ /dev/null @@ -1,7 +0,0 @@ -import test from 'ava' - -import { todo } from '@seamapi/blueprint' - -test('todo: returns argument', (t) => { - t.is(todo('todo'), 'todo', 'returns input') -}) From 1c2c3fa38f21aa265d334a58c18dfbe9285d7526 Mon Sep 17 00:00:00 2001 From: Evan Sosenko Date: Mon, 17 Jun 2024 17:05:32 -0500 Subject: [PATCH 6/6] Update describe --- examples/blueprint.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/blueprint.ts b/examples/blueprint.ts index 5dbc686..d8fd7d7 100644 --- a/examples/blueprint.ts +++ b/examples/blueprint.ts @@ -8,7 +8,7 @@ interface Options { export const command: Command = 'blueprint [moduleName]' -export const describe: Describe = 'Create a blueprint from a type module' +export const describe: Describe = 'Create a blueprint from a module' export const builder: Builder = { moduleName: {