Skip to content

Instantly share code, notes, and snippets.

@DerekNonGeneric
Last active July 21, 2020 22:37
/**
* @file Userland JS implementation of Node.js's specifier restriction.
* @flag --experimental-loader
* @license 0BSD
* @author Derek Lewis <DerekNonGeneric@inf.is>
* @module {Es6Module} reservedResolve_userland
* @see https://github.com/nodejs/modules/issues/505
*/
import { inspect } from 'util';
const baseURL = new URL('file://');
baseURL.pathname = process.cwd() + '/';
// -----------------------------------------------------------------------------
// Helpers
// -----------------------------------------------------------------------------
/**
* If specifier starts with the character U+002F SOLIDUS (`/`) or the
* two-character sequence U+002F SOLIDUS U+002F SOLIDUS (`//`), return true.
* @param {string} specifier
* @returns {boolean}
* @see https://github.com/nodejs/node/blame/master/doc/api/esm.md#L825-L826
*/
export function isReservedSpecifier(specifier) {
if (specifier.charCodeAt(0) === 0x2f /* U+002F SOLIDUS (`/`) */) {
return true;
} else {
return false;
}
}
// -----------------------------------------------------------------------------
// Errors
// -----------------------------------------------------------------------------
/**
**ERR_INVALID_MODULE_SPECIFIER
* @description An invalid module specifier.
*/
export class InvalidModuleSpecifierError extends TypeError {
/**
* @param {string} specifier The invalid module specifier.
* @param {string} baseFilePath The parent module's file path basename.
*/
constructor(specifier, baseFilePath) {
super(
`Failed to resolve module specifier ${inspect(specifier)} imported ` +
`from ${inspect(baseFilePath)}. Specifiers may not begin with '/' ` +
"or '//'. These are reserved for potential future use."
);
this.code = 'ERR_INVALID_MODULE_SPECIFIER';
}
}
// -----------------------------------------------------------------------------
// Hooks
// -----------------------------------------------------------------------------
/**
* Resolve hook that allows customizing the default module resolution.
* @param {string} specifier
* @param {{
* conditions: Array<string>,
* parentURL: !(string | undefined),
* }} context
* @param {!Function} defaultResolve
* @returns {Promise<{ url: string }>}
*/
export function resolve(specifier, context, defaultResolve) {
const { parentURL = baseURL.href } = context;
if (isReservedSpecifier(specifier)) {
throw new InvalidModuleSpecifierError(specifier, parentURL);
} else {
return defaultResolve(specifier, { parentURL }, defaultResolve);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment