Skip to content

Commit

Permalink
Updates entry_point to remove support for returning a string from a…
Browse files Browse the repository at this point in the history
…n 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<string>` type, meaning there is no need to support it. This removes that case from `entry_point` and removes an assertion error from `renderer`.
  • Loading branch information
dgp1130 committed Feb 20, 2021
1 parent 72c704d commit e41e196
Show file tree
Hide file tree
Showing 5 changed files with 14 additions and 88 deletions.
1 change: 0 additions & 1 deletion packages/renderer/BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,6 @@ ts_library(
":entry_point",
"//common:binary",
"//common:formatters",
"//common/models:prerender_resource",
"@npm//@types/node",
"@npm//@types/yargs",
],
Expand Down
19 changes: 10 additions & 9 deletions packages/renderer/entry_point.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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<string>`. 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<PrerenderResource> | Promise<Iterable<PrerenderResource>>
* | AsyncIterable<PrerenderResource>
* ```
*
* 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<PrerenderResource>
| AsyncIterable<PrerenderResource>
> {
Expand All @@ -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<PrerenderResource>;
}
Expand All @@ -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<string>',
'Promise<PrerenderResource>',
'Iterable<PrerenderResource>',
'Promise<Iterable<PrerenderResource>>',
'AsyncIterable<PrerenderResource>',
Expand Down
27 changes: 0 additions & 27 deletions packages/renderer/entry_point_test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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<string>` 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<PrerenderResource>` value', async () => {
const defaultExport =
jasmine.createSpy('defaultExport').and.returnValue([
Expand Down
27 changes: 4 additions & 23 deletions packages/renderer/renderer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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 () => {
Expand Down Expand Up @@ -34,27 +33,14 @@ main(async () => {
.argv;

// Invoke the provided entry point.
let resources: string | Iterable<PrerenderResource>
| AsyncIterable<PrerenderResource>;
let resources: PromiseValue<ReturnType<typeof invoke>>;
try {
resources = await invoke(entryPoint);
} catch (err) {
console.error(err.message);
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<PrerenderResource>',
'Promise<Iterable<PrerenderResource>>',
'AsyncIterable<PrerenderResource>',
].join('\n')}\n\nInstead, got:\n${stringify(resources)}`,
);
return 1;
}

// Write each resource to its file.
const writes = [] as Promise<void>[];
for await (const resource of resources) {
Expand All @@ -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<string, unknown>;
if (obj.toString) return obj.toString();
}
return JSON.stringify(value);
}
// Extracts the generic value type from an input `Promise`.
type PromiseValue<T extends Promise<unknown>> =
T extends Promise<infer V> ? V : never;
28 changes: 0 additions & 28 deletions packages/renderer/renderer_test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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([]);
});
});

0 comments on commit e41e196

Please sign in to comment.