From 97dbdbfee0d97249200b8d656a66f0bce2e30df0 Mon Sep 17 00:00:00 2001 From: Mario Nebl Date: Fri, 5 Oct 2018 16:14:42 +0200 Subject: [PATCH] refactor: add partial user code checks --- packages/api/package.json | 2 +- packages/api/src/is-content.ts | 9 +++++++ packages/api/src/is-message.ts | 2 +- packages/api/src/is-renderer.ts | 9 +++++++ packages/api/src/routes/cover/cover.ts | 34 ++++++++++++------------- packages/api/src/routes/cover/html.ts | 12 ++------- packages/api/src/routes/demo/demo.ts | 22 ++++++++-------- packages/api/src/routes/demo/html.ts | 13 +++------- packages/api/src/types.ts | 18 +++++++++++++ packages/api/tsconfig.json | 3 ++- yarn.lock | 35 ++++++++++++++++++++------ 11 files changed, 101 insertions(+), 58 deletions(-) create mode 100644 packages/api/src/is-content.ts create mode 100644 packages/api/src/is-renderer.ts diff --git a/packages/api/package.json b/packages/api/package.json index 5624baba..750d6df8 100644 --- a/packages/api/package.json +++ b/packages/api/package.json @@ -80,7 +80,7 @@ "require-from-string": "^2.0.1", "resolve-pkg": "^1.0.0", "string-hash": "^1.1.3", - "ts-transform-json-schema": "^1.1.1", + "ts-transform-json-schema": "^1.1.2", "unindent": "^2.0.0", "ws": "^4.0.0", "yargs-parser": "^9.0.2", diff --git a/packages/api/src/is-content.ts b/packages/api/src/is-content.ts new file mode 100644 index 00000000..a908e000 --- /dev/null +++ b/packages/api/src/is-content.ts @@ -0,0 +1,9 @@ +import { fromType } from "ts-transform-json-schema" +import * as T from './types'; + +const validateOptions = require("schema-utils"); +const schema = fromType() as object; + +export function isContent(data: unknown): data is T.HtmlContent { + return validateOptions(schema, data, 'html-content'); +} diff --git a/packages/api/src/is-message.ts b/packages/api/src/is-message.ts index a3a4790d..0c3461aa 100644 --- a/packages/api/src/is-message.ts +++ b/packages/api/src/is-message.ts @@ -10,7 +10,7 @@ export function isMessage(data: unknown): data is T.QueueMessage { } catch (err) { const type = typeof data === "object" && data !== null ? (data as any).type || "unknown" : "unknown"; console.error(`Message of type ${type} is invalid: ${err.message}`); - console.log(`Invalid Message: ${JSON.stringify(data)}`); + // console.log(`Invalid Message: ${JSON.stringify(data)}`); return false; } } diff --git a/packages/api/src/is-renderer.ts b/packages/api/src/is-renderer.ts new file mode 100644 index 00000000..8ff5c029 --- /dev/null +++ b/packages/api/src/is-renderer.ts @@ -0,0 +1,9 @@ +import { fromType } from "ts-transform-json-schema"; +import * as T from "./types"; + +const validateOptions = require("schema-utils"); +const schema = fromType() as object; + +export function isRenderer(data: unknown): data is T.Renderer { + return validateOptions(schema, data, "renderer"); +} diff --git a/packages/api/src/routes/cover/cover.ts b/packages/api/src/routes/cover/cover.ts index f7c3cc9c..42c7ee45 100644 --- a/packages/api/src/routes/cover/cover.ts +++ b/packages/api/src/routes/cover/cover.ts @@ -1,10 +1,13 @@ import * as Path from "path"; import * as express from "express"; +import * as resolveFrom from "resolve-from"; + import { fromFs } from "../../from-fs"; -import { html, HtmlContent } from "./html"; +import { html } from "./html"; import { wait } from "../../wait"; import * as T from "../../types"; -import * as resolveFrom from "resolve-from"; +import { isContent } from "../../is-content"; +// import { isRenderer } from "../../is-renderer"; const AggregateError = require("aggregate-error"); @@ -26,31 +29,26 @@ export const cover = async ( const getModule = fromFs(fs); const coverFile = resolveFrom(cwd, options.config.render); - const rawCover = getModule(COVER_PATH, coverFile); - - if (typeof rawCover !== "object") { - throw new Error( - `Expected ${config.cover} to export an object, received ${typeof rawCover}` - ); - } + const cover = getModule(COVER_PATH, coverFile) as T.Renderer; - const cover = rawCover as { [key: string]: unknown }; + // TODO: Enable when ts-transform-json-schema supports functions + // if (!isRenderer(cover)) { + // return; + // } const renderFile = resolveFrom(cwd, options.config.render); - - const render = - typeof cover.render === "function" - ? cover.render - : // TODO: Schema checks for renderer - getModule(RENDER_PATH, renderFile) as () => HtmlContent; + const render = cover.render || (getModule(RENDER_PATH, renderFile) as T.Renderer["render"]); const content = await Promise.resolve( - render(cover, { + render!(cover, { dirname: Path.dirname(config.cover) }) ); - // TODO: Schema checks for produced content + if (!isContent(content)) { + return; + } + res.send( html(content, { base: req.params.base || "/", diff --git a/packages/api/src/routes/cover/html.ts b/packages/api/src/routes/cover/html.ts index 479953a1..1f73f435 100644 --- a/packages/api/src/routes/cover/html.ts +++ b/packages/api/src/routes/cover/html.ts @@ -1,22 +1,14 @@ import * as Url from "url"; +import * as T from "../../types"; const unindent = require("unindent"); -export interface HtmlContent { - head?: string; - css?: string; - before?: string; - html?: string; - after?: string; - js?: string; -} - export interface HtmlOptions { base: string; scripts?: boolean; } -export function html(content: HtmlContent, options: HtmlOptions): string { +export function html(content: T.HtmlContent, options: HtmlOptions): string { const prefix = Url.resolve(options.base, "api"); return unindent(` diff --git a/packages/api/src/routes/demo/demo.ts b/packages/api/src/routes/demo/demo.ts index 996371e0..36131f52 100644 --- a/packages/api/src/routes/demo/demo.ts +++ b/packages/api/src/routes/demo/demo.ts @@ -5,7 +5,8 @@ import * as resolveFrom from "resolve-from"; import * as T from "../../types"; import { wait } from "../../wait"; import { fromFs } from "../../from-fs"; -import { html, HtmlContent } from "./html"; +import { html } from "./html"; +import { isContent } from "../../is-content"; const AggregateError = require("aggregate-error"); @@ -37,26 +38,27 @@ export const demo = async function demo(options: T.RouteOptions): Promise HtmlContent; + : getModule(RENDER_PATH, renderFile) as () => T.HtmlContent; const content = await Promise.resolve( render(component, { dirname: Path.dirname(found.path) }) ); + if (!isContent(content)) { + return; + } + res.send(html(content, found)); } catch (err) { const error = Array.isArray(err) ? new AggregateError(err) : err; diff --git a/packages/api/src/routes/demo/html.ts b/packages/api/src/routes/demo/html.ts index 5985300f..e9b5b391 100644 --- a/packages/api/src/routes/demo/html.ts +++ b/packages/api/src/routes/demo/html.ts @@ -1,20 +1,13 @@ -const unindent = require("unindent"); +import * as T from "../../types"; -export interface HtmlContent { - head?: string; - css?: string; - before?: string; - html?: string; - after?: string; - js?: string; -} +const unindent = require("unindent"); export interface HtmlOptions { base: string; scripts?: boolean; } -export function html(content: HtmlContent, payload: unknown): string { +export function html(content: T.HtmlContent, payload: unknown): string { const data = encodeURIComponent(JSON.stringify(payload)); return unindent(` diff --git a/packages/api/src/types.ts b/packages/api/src/types.ts index 694735dc..e636a0b3 100644 --- a/packages/api/src/types.ts +++ b/packages/api/src/types.ts @@ -92,3 +92,21 @@ export interface RouteOptions { config: Types.PatternplateConfig; queue: MsgQueue; } + +export interface Renderer { + head: () => string; + default: () => void; + css?: () => string; + html?: () => string; + js?: () => string; + render?(input: Renderer, ctx: { dirname: string }): HtmlContent; +} + +export interface HtmlContent { + head?: string; + css?: string; + before?: string; + html?: string; + after?: string; + js?: string; +} diff --git a/packages/api/tsconfig.json b/packages/api/tsconfig.json index 16fae719..59079526 100644 --- a/packages/api/tsconfig.json +++ b/packages/api/tsconfig.json @@ -19,7 +19,8 @@ "required": true } } - ] + ], + }, "include": [ "src/**/*.ts" diff --git a/yarn.lock b/yarn.lock index 95aca31b..c7dd3319 100644 --- a/yarn.lock +++ b/yarn.lock @@ -657,13 +657,6 @@ call-me-maybe "^1.0.1" glob-to-regexp "^0.3.0" -"@patternplate/deploy-site@file:./packages/deploy": - version "2.5.18" - dependencies: - "@marionebl/sander" "^0.6.1" - execa "^0.9.0" - meow "^4.0.0" - "@patternplate/validate-manifest@3.0.3": version "3.0.3" resolved "https://registry.npmjs.org/@patternplate/validate-manifest/-/validate-manifest-3.0.3.tgz#131c509e52991d9ec67c0dc3dbcf4a61b503fc6d" @@ -8663,6 +8656,10 @@ neo-async@^2.5.0: version "2.5.1" resolved "https://registry.npmjs.org/neo-async/-/neo-async-2.5.1.tgz#acb909e327b1e87ec9ef15f41b8a269512ad41ee" +nested-error-stacks@^2.1.0: + version "2.1.0" + resolved "https://registry.npmjs.org/nested-error-stacks/-/nested-error-stacks-2.1.0.tgz#0fbdcf3e13fe4994781280524f8b96b0cdff9c61" + nice-try@^1.0.4: version "1.0.4" resolved "https://registry.npmjs.org/nice-try/-/nice-try-1.0.4.tgz#d93962f6c52f2c1558c0fbda6d512819f1efe1c4" @@ -12019,6 +12016,26 @@ ts-transform-json-schema@^1.1.1: resolve "^1.8.1" typescript-json-schema "^0.32.0" +ts-transform-json-schema@^1.1.2: + version "1.1.2" + resolved "https://registry.npmjs.org/ts-transform-json-schema/-/ts-transform-json-schema-1.1.2.tgz#5457c6e36d87270b96ee33b3ee0bfbd4f27c3e96" + dependencies: + "@types/read-pkg-up" "^3.0.1" + "@types/resolve" "0.0.8" + read-pkg-up "^4.0.0" + resolve "^1.8.1" + typescript-json-schema "^0.32.0" + +tslib@^1.8.1: + version "1.9.3" + resolved "https://registry.npmjs.org/tslib/-/tslib-1.9.3.tgz#d7e4dd79245d85428c4d7e4822a79917954ca286" + +tsutils@^3.0.0: + version "3.0.0" + resolved "https://registry.npmjs.org/tsutils/-/tsutils-3.0.0.tgz#0c5070a17a0503e056da038c48b5a1870a50a9ad" + dependencies: + tslib "^1.8.1" + tty-browserify@0.0.0: version "0.0.0" resolved "https://registry.npmjs.org/tty-browserify/-/tty-browserify-0.0.0.tgz#a157ba402da24e9bf957f9aa69d524eed42901a6" @@ -12057,6 +12074,10 @@ typedarray@^0.0.6: version "0.0.6" resolved "https://registry.yarnpkg.com/typedarray/-/typedarray-0.0.6.tgz#867ac74e3864187b1d3d47d996a78ec5c8830777" +typescript-is@^0.7.8: + version "0.7.8" + resolved "https://registry.npmjs.org/typescript-is/-/typescript-is-0.7.8.tgz#bc4962515fa91debf6187e81137020f95d000484" + typescript-json-schema@^0.32.0: version "0.32.0" resolved "https://registry.npmjs.org/typescript-json-schema/-/typescript-json-schema-0.32.0.tgz#d95af55eaf01be6d44b280fdc3f9b3a264435642"