From e41e196e50dc2a074df92c460ac0c5583df2492c Mon Sep 17 00:00:00 2001 From: Doug Parker Date: Sat, 20 Feb 2021 14:51:11 -0800 Subject: [PATCH] Updates `entry_point` to remove support for returning a string from an entry point. Refs #25. Since the original renderer tool was removed, it is no longer ever valid for users to return a `string` or `Promise` type, meaning there is no need to support it. This removes that case from `entry_point` and removes an assertion error from `renderer`. --- packages/renderer/BUILD.bazel | 1 - packages/renderer/entry_point.ts | 19 +++++++++--------- packages/renderer/entry_point_test.ts | 27 -------------------------- packages/renderer/renderer.ts | 27 ++++---------------------- packages/renderer/renderer_test.ts | 28 --------------------------- 5 files changed, 14 insertions(+), 88 deletions(-) diff --git a/packages/renderer/BUILD.bazel b/packages/renderer/BUILD.bazel index 788997df..c12019a5 100644 --- a/packages/renderer/BUILD.bazel +++ b/packages/renderer/BUILD.bazel @@ -19,7 +19,6 @@ ts_library( ":entry_point", "//common:binary", "//common:formatters", - "//common/models:prerender_resource", "@npm//@types/node", "@npm//@types/yargs", ], diff --git a/packages/renderer/entry_point.ts b/packages/renderer/entry_point.ts index e79f9678..d12c5975 100644 --- a/packages/renderer/entry_point.ts +++ b/packages/renderer/entry_point.ts @@ -6,13 +6,18 @@ import { PrerenderResource } from 'rules_prerender/common/models/prerender_resou * the default function export, and validates the result before returning it. * * @param entryPoint A path to a JavaScript CommonJS module. This module should - * have a default export of a function. This function accepts no arguments - * and returns a `string` or a `Promise`. The module is imported - * into the NodeJS runtime and invoked, propagating the return value to the - * caller. + * have a default export of a function with the type: + * + * ``` + * () => Iterable | Promise> + * | AsyncIterable + * ``` + * + * The module is imported into the NodeJS runtime and invoked, propagating + * the return value to the caller. + * @returns The returned value of the invoked entry point. */ export async function invoke(entryPoint: string): Promise< - string | Iterable | AsyncIterable > { @@ -33,7 +38,6 @@ export async function invoke(entryPoint: string): Promise< } const rendered = await defaultExport() as unknown; - if (typeof rendered === 'string') return rendered; if (isIterable(rendered)) { return rendered as Iterable; } @@ -43,9 +47,6 @@ export async function invoke(entryPoint: string): Promise< throw new Error(`Entry point (${entryPoint}) provided a default export` + ` which returned a value that is not one of:\n${[ - 'string', - 'Promise', - 'Promise', 'Iterable', 'Promise>', 'AsyncIterable', diff --git a/packages/renderer/entry_point_test.ts b/packages/renderer/entry_point_test.ts index 0c53f11f..f9d25b00 100644 --- a/packages/renderer/entry_point_test.ts +++ b/packages/renderer/entry_point_test.ts @@ -6,33 +6,6 @@ import * as importLib from 'rules_prerender/packages/renderer/dynamic_import'; describe('entry_point', () => { describe('invoke()', () => { - it('invokes the given entry point and returns its string value', async () => { - const defaultExport = jasmine.createSpy('defaultExport') - .and.returnValue('Hello, World!'); - spyOn(importLib, 'dynamicImport').and.resolveTo({ - default: defaultExport, - }); - - const rendered = await invoke('foo.js'); - - expect(importLib.dynamicImport).toHaveBeenCalledOnceWith('foo.js'); - expect(defaultExport).toHaveBeenCalledOnceWith(); - - expect(rendered).toBe('Hello, World!'); - }); - - it('invokes the given entry point and awaits its `Promise` value', async () => { - const defaultExport = jasmine.createSpy('defaultExport') - .and.resolveTo('Hello, World!'); - spyOn(importLib, 'dynamicImport').and.resolveTo({ - default: defaultExport, - }); - - const rendered = await invoke('foo.js'); - - expect(rendered).toBe('Hello, World!'); - }); - it('invokes the given entry point and returns its `Iterable` value', async () => { const defaultExport = jasmine.createSpy('defaultExport').and.returnValue([ diff --git a/packages/renderer/renderer.ts b/packages/renderer/renderer.ts index 15721aa7..8291fdae 100644 --- a/packages/renderer/renderer.ts +++ b/packages/renderer/renderer.ts @@ -3,7 +3,6 @@ import * as path from 'path'; import * as yargs from 'yargs'; import { main } from 'rules_prerender/common/binary'; import { mdSpacing } from 'rules_prerender/common/formatters'; -import { PrerenderResource } from 'rules_prerender/common/models/prerender_resource'; import { invoke } from 'rules_prerender/packages/renderer/entry_point'; main(async () => { @@ -34,8 +33,7 @@ main(async () => { .argv; // Invoke the provided entry point. - let resources: string | Iterable - | AsyncIterable; + let resources: PromiseValue>; try { resources = await invoke(entryPoint); } catch (err) { @@ -43,18 +41,6 @@ main(async () => { return 1; } - // Validate the result of the entry point. - if (typeof resources === 'string') { - console.error( - `Expected entry point (${entryPoint}) to return one of:\n${[ - 'Iterable', - 'Promise>', - 'AsyncIterable', - ].join('\n')}\n\nInstead, got:\n${stringify(resources)}`, - ); - return 1; - } - // Write each resource to its file. const writes = [] as Promise[]; for await (const resource of resources) { @@ -75,11 +61,6 @@ main(async () => { return 0; }); -function stringify(value: unknown): string { - if (typeof value === 'string') return value; - if (typeof value === 'object') { - const obj = value as Record; - if (obj.toString) return obj.toString(); - } - return JSON.stringify(value); -} +// Extracts the generic value type from an input `Promise`. +type PromiseValue> = + T extends Promise ? V : never; diff --git a/packages/renderer/renderer_test.ts b/packages/renderer/renderer_test.ts index 52295ff4..3fd2b33a 100644 --- a/packages/renderer/renderer_test.ts +++ b/packages/renderer/renderer_test.ts @@ -162,32 +162,4 @@ module.exports = 'Hello, World!'; // Not a function... }); expect(outputFiles).toEqual([]); }); - - it('fails from user code returning a bad type', async () => { - await fs.mkdir(`${tmpDir.get()}/output`); - await fs.writeFile(`${tmpDir.get()}/foo.js`, ` -module.exports = () => { - return 'Hello, World!'; // Not an iterable. -}; - `.trim()); - - const { code, stdout, stderr } = await run({ - entryPoint: `${tmpDir.get()}/foo.js`, - outputDir: `${tmpDir.get()}/output`, - }); - - expect(code).toBe(1); - expect(stdout).toBe(''); - expect(stderr).toContain(`${tmpDir.get()}/foo.js`); - expect(stderr).toContain('return one of:'); - expect(stderr).not.toContain('\\n'); // String should not be escaped. - // Stack trace should not be displayed for user-fault errors. - expect(stderr).not.toContain(' at '); - - // No output files should be written. - const outputFiles = await fs.readdir(`${tmpDir.get()}/output`, { - withFileTypes: true, - }); - expect(outputFiles).toEqual([]); - }); });