-
Notifications
You must be signed in to change notification settings - Fork 83
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #34 from deco-cx/feat/wake
feat: Wake Integration
- Loading branch information
Showing
334 changed files
with
137,811 additions
and
23 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
import { ImageObject } from "../types.ts"; | ||
|
||
export const DEFAULT_IMAGE: ImageObject = { | ||
"@type": "ImageObject", | ||
alternateName: "Default Image Placeholder", | ||
url: | ||
"https://ozksgdmyrqcxcwhnbepg.supabase.co/storage/v1/object/public/assets/1818/ff6bb37e-0eab-40e1-a454-86856efc278e", | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,199 @@ | ||
import "npm:@graphql-codegen/typescript"; | ||
import "npm:@graphql-codegen/typescript-operations"; | ||
|
||
import { CodegenConfig, generate } from "npm:@graphql-codegen/cli"; | ||
import { | ||
compile, | ||
Options as CompileOptions, | ||
} from "npm:json-schema-to-typescript"; | ||
import { OpenAPIV3 } from "npm:openapi-types"; | ||
import { walk } from "std/fs/mod.ts"; | ||
import { dirname, join } from "std/path/mod.ts"; | ||
|
||
const allOpenAPIPaths: string[] = []; | ||
const allGraphqlPaths: string[] = []; | ||
|
||
for await (const entry of walk(".")) { | ||
if (entry.isFile) { | ||
if (entry.path.endsWith(".openapi.json")) { | ||
allOpenAPIPaths.push(entry.path); | ||
} | ||
if (entry.path.endsWith(".graphql.json")) { | ||
allGraphqlPaths.push(entry.path); | ||
} | ||
} | ||
} | ||
|
||
const openAPISpecsByModule = allOpenAPIPaths.reduce( | ||
(acc, specPath) => { | ||
const dir = dirname(specPath); | ||
|
||
acc[dir] ||= []; | ||
acc[dir].push(specPath); | ||
|
||
return acc; | ||
}, | ||
{} as Record<string, string[]>, | ||
); | ||
|
||
// transforms: /a/{b}/c => /a/:b/c | ||
const toPathTemplate = (path: string) => | ||
path.replace(/{/g, ":").replace(/}/g, ""); | ||
|
||
const generateOpenAPI = async () => { | ||
const isOpenAPIv3 = (x: any): x is OpenAPIV3.Document => | ||
x?.openapi?.startsWith("3."); | ||
|
||
const isReferenceObject = (x: any): x is OpenAPIV3.ReferenceObject => x?.$ref; | ||
|
||
const BANNER_COMMENT = ` | ||
// DO NOT EDIT. This file is generated by deco. | ||
// This file SHOULD be checked into source version control. | ||
// To generate this file: deno run -A scripts/openAPI.ts | ||
`; | ||
|
||
const HTTP_VERBS = ["get", "post", "put", "delete", "patch", "head"] as const; | ||
|
||
const COMPILE_OPTIONS: Partial<CompileOptions> = { | ||
bannerComment: "", | ||
unknownAny: true, | ||
additionalProperties: false, | ||
format: true, | ||
}; | ||
|
||
const MEDIA_TYPE_JSON = "application/json"; | ||
|
||
const AUTOGEN_TYPE_NAME = "Autogen"; | ||
|
||
for (const [base, paths] of Object.entries(openAPISpecsByModule)) { | ||
const outfile = join(base, "openapi.gen.ts"); | ||
const types = []; | ||
|
||
console.info(`Generating OpenAPI types for specs at ${base}`); | ||
for (const path of paths) { | ||
const document = JSON.parse(await Deno.readTextFile(path)); | ||
|
||
if (!isOpenAPIv3(document)) { | ||
throw new Error("Only OpenAPI@3x is supported"); | ||
} | ||
|
||
for (const [path, pathItem] of Object.entries(document.paths)) { | ||
const pathTemplate = toPathTemplate(path); | ||
|
||
for (const verb of HTTP_VERBS) { | ||
const item = pathItem?.[verb]; | ||
|
||
if (!item) { | ||
continue; | ||
} | ||
|
||
const { | ||
parameters = [], | ||
requestBody, | ||
responses, | ||
summary, | ||
description, | ||
} = item; | ||
|
||
const paramsSchema = parameters | ||
.filter((x): x is OpenAPIV3.ParameterObject => | ||
!isReferenceObject(x) | ||
) | ||
.filter((x) => x.in === "query") | ||
.reduce((schema, item) => { | ||
if (item.schema && !isReferenceObject(item.schema)) { | ||
schema.properties[item.name] = { | ||
required: item.required as any, | ||
description: item.description, | ||
...item.schema, | ||
}; | ||
} | ||
|
||
return schema; | ||
}, { | ||
type: "object" as const, | ||
properties: {} as Record<string, OpenAPIV3.SchemaObject>, | ||
}); | ||
|
||
const bodySchema = !isReferenceObject(requestBody) && | ||
requestBody?.content?.[MEDIA_TYPE_JSON]?.schema; | ||
|
||
const ok = responses?.["200"] || responses?.["201"] || | ||
responses?.["206"]; | ||
const responseSchema = !isReferenceObject(ok) && | ||
ok?.content?.[MEDIA_TYPE_JSON].schema; | ||
|
||
const [searchParams, body, response] = await Promise.all([ | ||
Object.keys(paramsSchema.properties).length > 0 && paramsSchema, | ||
bodySchema, | ||
responseSchema, | ||
].map((schema) => | ||
schema ? compile(schema, AUTOGEN_TYPE_NAME, COMPILE_OPTIONS) : null | ||
)); | ||
|
||
const docs = (description || summary) && | ||
`/** @description ${description || summary} */`; | ||
|
||
const typed = `${docs}\n "${verb.toUpperCase()} ${pathTemplate}": { | ||
${ | ||
Object.entries({ searchParams, body, response }) | ||
.filter((e) => Boolean(e[1])) | ||
.map(([key, value]) => | ||
`${key}: ${ | ||
value!.replace(`export interface ${AUTOGEN_TYPE_NAME}`, "") | ||
.replace(`export type ${AUTOGEN_TYPE_NAME} = `, "") | ||
}` | ||
) | ||
} | ||
}`; | ||
|
||
types.push(typed); | ||
} | ||
} | ||
} | ||
|
||
await Deno.writeTextFile( | ||
outfile, | ||
`${BANNER_COMMENT}export interface API {\n${types.join("\n")}\n}`, | ||
); | ||
|
||
// Format using deno | ||
const fmt = new Deno.Command(Deno.execPath(), { args: ["fmt", outfile] }); | ||
await fmt.output(); | ||
} | ||
}; | ||
|
||
const generateGraphQL = async () => { | ||
for (const path of allGraphqlPaths) { | ||
const base = dirname(path); | ||
const [appEntrypoint, ...tail] = base.split("/"); | ||
|
||
console.info(`Generating GraphQL types for specs at ${base}`); | ||
const config: CodegenConfig = { | ||
silent: true, | ||
schema: join(Deno.cwd(), path), | ||
documents: [`./**/*.ts`], | ||
generates: { | ||
[join(...tail, "graphql.gen.ts")]: { | ||
plugins: [ | ||
"typescript", | ||
"typescript-operations", | ||
], | ||
config: { | ||
skipTypename: true, | ||
enumsAsTypes: true, | ||
}, | ||
}, | ||
}, | ||
}; | ||
|
||
await generate({ ...config, cwd: appEntrypoint }, true); | ||
} | ||
}; | ||
|
||
const generateDeco = () => import("deco/scripts/apps/bundle.ts"); | ||
|
||
await generateOpenAPI(); | ||
await generateGraphQL(); | ||
await generateDeco(); |
Oops, something went wrong.