Skip to content

Commit

Permalink
Merge pull request #34 from deco-cx/feat/wake
Browse files Browse the repository at this point in the history
feat: Wake Integration
  • Loading branch information
tlgimenes authored Sep 11, 2023
2 parents bc65198 + ebbcdca commit cb0acb3
Show file tree
Hide file tree
Showing 334 changed files with 137,811 additions and 23 deletions.
6 changes: 5 additions & 1 deletion commerce/mod.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,17 +2,19 @@ import { App } from "deco/mod.ts";
import shopify, { Props as ShopifyProps } from "../shopify/mod.ts";
import vnda, { Props as VNDAProps } from "../vnda/mod.ts";
import vtex, { Props as VTEXProps } from "../vtex/mod.ts";
import wake, { Props as WakeProps } from "../wake/mod.ts";
import website, { Props as WebsiteProps } from "../website/mod.ts";
import manifest, { Manifest } from "./manifest.gen.ts";

export type Props = WebsiteProps & {
commerce: VNDAProps | VTEXProps | ShopifyProps;
commerce: VNDAProps | VTEXProps | ShopifyProps | WakeProps;
};

type WebsiteApp = ReturnType<typeof website>;
type CommerceApp =
| ReturnType<typeof vnda>
| ReturnType<typeof vtex>
| ReturnType<typeof wake>
| ReturnType<typeof shopify>;

export default function Site(
Expand All @@ -25,6 +27,8 @@ export default function Site(
? vnda(commerce)
: commerce.platform === "vtex"
? vtex(commerce)
: commerce.platform === "wake"
? wake(commerce)
: shopify(commerce);

return {
Expand Down
8 changes: 8 additions & 0 deletions commerce/utils/constants.ts
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",
};
1 change: 1 addition & 0 deletions deco.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ const config = {
app("handlebars"),
app("vtex"),
app("vnda"),
app("wake"),
app("shopify"),
app("website"),
app("commerce"),
Expand Down
2 changes: 1 addition & 1 deletion deno.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
"tasks": {
"check": "deno fmt && deno lint",
"release": "deno eval 'import \"deco/scripts/release.ts\"'",
"start": "deno eval 'import \"deco/scripts/apps/bundle.ts\"'",
"start": "deno run -A ./scripts/start.ts",
"link": "deno eval 'import \"deco/scripts/apps/link.ts\"'",
"unlink": "deno eval 'import \"deco/scripts/apps/unlink.ts\"'",
"serve": "deno eval 'import \"deco/scripts/apps/serve.ts\"'",
Expand Down
199 changes: 199 additions & 0 deletions scripts/start.ts
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();
Loading

0 comments on commit cb0acb3

Please sign in to comment.