pipeline.js: implement basic pipeline
MODIFY
src/index.js
src/index.js
export { makeRootedResolver } from './resolve';
+
+export { makeImportPipeline as default } from './pipeline';

ADD
src/pipeline.js
+export const makeImportPipeline = (
+ importHooks,
+ moduleCache = new Map(),
+ rewriters = new Map(),
+) => {
+ const {
+ // Functions for the pipeline.
+ resolve,
+ locate,
+ retrieve,
+ rootContainer,
+ } = importHooks;
+
+ let makeImporter;
+ function recursiveLink(moduleId, container) {
+ const subContainer =
+ (container.containerFor && container.containerFor(moduleId)) || container;
+
+ let moduleInstance = subContainer.instanceCache.get(moduleId);
+ if (moduleInstance) {
+ return moduleInstance;
+ }
+
+ // Translate the linkage record into a module instance, and cache it.
+ const linkageRecord = moduleCache.get(moduleId);
+ moduleInstance = subContainer.link(linkageRecord, makeImporter);
+ subContainer.instanceCache.set(moduleId, moduleInstance);
+
+ return moduleInstance;
+ }
+
+ makeImporter = referrer => {
+ return async specifier => {
+ const moduleId = resolve(specifier, referrer);
+ if (!moduleCache.has(moduleId)) {
+ // This is sequential because we are beginning an import cycle.
+
+ // Get a location, and retrieve it with rewriting.
+ const location = await locate(moduleId);
+ const linkageRecord = await retrieve(location, rewriters);
+ moduleCache.set(moduleId, linkageRecord);
+ }
+
+ // Begin initialization of the linked modules.
+ const moduleInstance = recursiveLink(moduleId, rootContainer);
+ return moduleInstance.initialize();
+ };
+ };
+
+ return makeImporter;
+};

ADD
test/test-pipeline.js
+import { test } from 'tape-promise/tape';
+
+import makeImportPipeline from '../src';
+
+test.only('import pipeline', async t => {
+ try {
+ const SPECIFIER_MAGIC = {
+ toString() {
+ return 'SPECIFIER_MAGIC';
+ },
+ };
+ const moduleCache = new Map([[SPECIFIER_MAGIC, 'hello123']]);
+ const makeImporter = makeImportPipeline(
+ {
+ resolve(specifier, _referrer) {
+ if (specifier === SPECIFIER_MAGIC) {
+ return specifier;
+ }
+ throw TypeError(`Not a magical referrer`);
+ },
+ rootContainer: {
+ link(mlr, _mimp) {
+ return {
+ initialize() {
+ return mlr;
+ },
+ };
+ },
+ instanceCache: new Map(),
+ },
+ },
+ moduleCache,
+ );
+
+ const importer = makeImporter('file:///some/where/over');
+ t.deepEquals(
+ await importer(SPECIFIER_MAGIC),
+ 'hello123',
+ `pipeline works with magic specifier`,
+ );
+ } catch (e) {
+ t.isNot(e, e, 'unexpected exception');
+ } finally {
+ t.end();
+ }
+});

MODIFY
test/test-resolve.js
test/test-resolve.js
@@ -22,8 +22,7 @@ test('rooted resolve', async t => {
`cannot skip root`,
);
} catch (e) {
- console.log('unexpected exception', e);
- t.assert(false, e);
+ t.isNot(e, e, 'unexpected exception');
} finally {
t.end();
}

pipeline.js: implement basic pipeline