Skip to content

Commit

Permalink
Merge pull request #271 from podium-lib/refactor_hints_to_assets
Browse files Browse the repository at this point in the history
Refactor hints to assets
  • Loading branch information
digitalsadhu authored Nov 13, 2024
2 parents 5e3f18a + e16819c commit 49b3c8c
Show file tree
Hide file tree
Showing 5 changed files with 159 additions and 72 deletions.
57 changes: 57 additions & 0 deletions lib/assets.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
import { EventEmitter } from 'node:events';

export class Assets extends EventEmitter {
#expectedAssets = new Set();
#receivedAssets = new Map();
#js;
#css;

// pointless constructor with super to appease TS which cryptically errors otherwise.
constructor() {
super();
}

/**
* Adds a new expected asset to the set
* Expected assets are used to determine if all assets have been received
* @param {string} name - The name of the asset
*/
addExpectedAsset(name) {
this.#expectedAssets.add(name);
}

/**
* Adds a new received asset to the set
* After each asset has been received, we check if all assets have been received
* and emit the 'complete' event if so
* @param {string} name - The name of the asset
* @param {{js: Array<import('./asset-js.js').JavaScriptAsset | string>, css: Array<import('./asset-css.js').CssAsset | string>}} assets - The assets for a given resource
*/
addReceivedAsset(name, assets = { js: [], css: [] }) {
this.#receivedAssets.set(name, assets);
if (this.allAssetsReceived) {
const assets = Array.from(this.#receivedAssets.values());
this.#js = assets.flatMap(({ js = [] }) => js);
this.#css = assets.flatMap(({ css = [] }) => css);
this.emit('received', { js: this.#js, css: this.#css });
}
}

get js() {
return this.#js;
}

get css() {
return this.#css;
}

/**
* Value will be true if all expected assets have been received
*/
get allAssetsReceived() {
return (
this.#expectedAssets.size === this.#receivedAssets.size &&
[...this.#expectedAssets].every((x) => this.#receivedAssets.has(x))
);
}
}
47 changes: 0 additions & 47 deletions lib/hints.js

This file was deleted.

26 changes: 23 additions & 3 deletions lib/http-incoming.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { URL } from 'node:url';
import { Hints } from './hints.js';
import { Assets } from './assets.js';

const inspect = Symbol.for('nodejs.util.inspect.custom');

Expand Down Expand Up @@ -59,8 +59,8 @@ export default class HttpIncoming {
*/
#js;

/** @type {Hints} */
hints = new Hints();
/** @type {Assets} */
assets = new Assets();

/**
* @constructor
Expand Down Expand Up @@ -222,6 +222,26 @@ export default class HttpIncoming {
return this.#js;
}

/**
* Wait for assets to be received from podlets
*
* @returns {Promise<{js: Array<import('./asset-js.js').JavaScriptAsset | string>, css: Array<import('./asset-css.js').CssAsset | string>}>}
*/
waitForAssets() {
if (this.assets.allAssetsReceived) {
return Promise.resolve({
js: this.assets.js,
css: this.assets.css,
});
}

return new Promise((resolve) => {
this.assets.on('received', (assets) => {
resolve(assets);
});
});
}

/**
* @returns {PodiumHttpIncoming<T>}
*/
Expand Down
28 changes: 14 additions & 14 deletions tests/hints.test.js → tests/assets.test.js
Original file line number Diff line number Diff line change
@@ -1,26 +1,26 @@
import tap from 'tap';
import { Hints } from '../lib/hints.js';
import { Assets } from '../lib/assets.js';

tap.test('Hints() - allHintsReceived property - should be true', (t) => {
const hints = new Hints();
hints.addExpectedHint('foo');
hints.addExpectedHint('bar');
hints.addReceivedHint('foo', {
const assets = new Assets();
assets.addExpectedAsset('foo');
assets.addExpectedAsset('bar');
assets.addReceivedAsset('foo', {
js: [{ value: 'foo.js' }],
css: [{ value: 'foo.css' }],
});
hints.addReceivedHint('bar', {
assets.addReceivedAsset('bar', {
js: [{ value: 'foo.js' }],
css: [{ value: 'foo.css' }],
});
t.equal(hints.allHintsReceived, true);
t.equal(assets.allAssetsReceived, true);
t.end();
});

tap.test('Hints() - complete event - should fire', (t) => {
tap.test('Hints() - received event - should fire', (t) => {
t.plan(6);
const hints = new Hints();
hints.on('complete', ({ js, css }) => {
const assets = new Assets();
assets.on('received', ({ js, css }) => {
t.equal(js.length, 2);
t.equal(css.length, 2);
t.equal(js[0].value, 'foo.js');
Expand All @@ -29,13 +29,13 @@ tap.test('Hints() - complete event - should fire', (t) => {
t.equal(css[1].value, 'foo.css');
t.end();
});
hints.addExpectedHint('foo');
hints.addExpectedHint('bar');
hints.addReceivedHint('foo', {
assets.addExpectedAsset('foo');
assets.addExpectedAsset('bar');
assets.addReceivedAsset('foo', {
js: [{ value: 'foo.js' }],
css: [{ value: 'foo.css' }],
});
hints.addReceivedHint('bar', {
assets.addReceivedAsset('bar', {
js: [{ value: 'foo.js' }],
css: [{ value: 'foo.css' }],
});
Expand Down
73 changes: 65 additions & 8 deletions tests/http-incoming.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -359,22 +359,79 @@ tap.test('can read values from view with default types', (t) => {
t.end();
});

tap.test('can read values from view with default types', (t) => {
tap.test('can set asset expectations and receive assets', (t) => {
t.plan(1);
// really only here for tsc
/**
* @type {HttpIncoming}
*/
const incoming = new HttpIncoming(SIMPLE_REQ, SIMPLE_RES);
incoming.assets.addExpectedAsset('foo');
incoming.assets.addExpectedAsset('bar');

incoming.assets.on('received', () => {
t.ok(incoming.assets.allAssetsReceived);
t.end();
});

incoming.assets.addReceivedAsset('foo', {
js: [{ value: 'foo.js' }],
css: [{ value: 'foo.css' }],
});
incoming.assets.addReceivedAsset('bar', {
js: [{ value: 'foo.js' }],
css: [{ value: 'foo.css' }],
});
});

tap.test('can wait for expected assets', (t) => {
t.plan(1);
/**
* @type {HttpIncoming}
*/
const incoming = new HttpIncoming(SIMPLE_REQ, SIMPLE_RES);
incoming.hints.addExpectedHint('foo');
incoming.hints.addExpectedHint('bar');
incoming.assets.addExpectedAsset('foo');
incoming.assets.addExpectedAsset('bar');

incoming.hints.on('complete', () => {
t.ok(incoming.hints.allHintsReceived);
incoming.waitForAssets().then(() => {
t.ok(incoming.assets.allAssetsReceived);
t.end();
});

incoming.hints.addReceivedHint('foo');
incoming.hints.addReceivedHint('bar');
incoming.assets.addReceivedAsset('foo', {
js: [{ value: 'foo.js' }],
css: [{ value: 'foo.css' }],
});
incoming.assets.addReceivedAsset('bar', {
js: [{ value: 'foo.js' }],
css: [{ value: 'foo.css' }],
});
});

tap.test(
'waitForAssets will resolve even if all assets have already been received',
async (t) => {
t.plan(3);
/**
* @type {HttpIncoming}
*/
const incoming = new HttpIncoming(SIMPLE_REQ, SIMPLE_RES);
incoming.assets.addExpectedAsset('foo');
incoming.assets.addExpectedAsset('bar');

incoming.assets.addReceivedAsset('foo', {
js: [{ value: 'foo.js' }],
css: [{ value: 'foo.css' }],
});
incoming.assets.addReceivedAsset('bar', {
js: [{ value: 'foo.js' }],
css: [{ value: 'foo.css' }],
});

const { js, css } = await incoming.waitForAssets();

t.ok(incoming.assets.allAssetsReceived);
t.same(js, [{ value: 'foo.js' }, { value: 'foo.js' }]);
t.same(css, [{ value: 'foo.css' }, { value: 'foo.css' }]);
t.end();
},
);

0 comments on commit 49b3c8c

Please sign in to comment.