Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add caching #5

Merged
merged 2 commits into from
Feb 24, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
36 changes: 30 additions & 6 deletions index.d.ts
Original file line number Diff line number Diff line change
@@ -1,14 +1,25 @@
declare function _exports(code: string, options: FromMemOptions): Promise<unknown>;
export = _exports;
export = fromMem;
/**
* Import or require the given code from memory. Knows about the different
* Peggy output formats. Returns the exports of the module.
*
* @param {string} code Code to import
* @param {FromMemOptions} options Options. Most important is filename.
* @returns {Promise<unknown>} The evaluated code.
*/
declare function fromMem(code: string, options: FromMemOptions): Promise<unknown>;
declare namespace fromMem {
export { guessModuleType, FromMemOptions, ModuleType };
}
/**
* Options for how to process code.
*/
export type FromMemOptions = {
type FromMemOptions = {
/**
* What format does the code have? Throws an error if the format is not
* "commonjs", "es", "umd", or "bare".
* What format does the code have? "guess" means to read the closest
* package.json file looking for the "type" key.
*/
format?: "amd" | "bare" | "commonjs" | "es" | "globals" | "umd" | undefined;
format?: "amd" | "bare" | "commonjs" | "es" | "globals" | "guess" | "umd" | undefined;
/**
* What is the fully-qualified synthetic
* filename for the code? Most important is the directory, which is used to
Expand All @@ -31,3 +42,16 @@ export type FromMemOptions = {
*/
globalExport?: string | undefined;
};
/**
* Figure out the module type for the given file. If no package.json is
* found, default to "commonjs".
*
* @param {string} filename Fully-qualified filename to start from.
* @returns {Promise<ModuleType>}
* @throws On invalid package.json
*/
declare function guessModuleType(filename: string): Promise<ModuleType>;
declare namespace guessModuleType {
function clearCache(): void;
}
type ModuleType = "commonjs" | "es";
40 changes: 35 additions & 5 deletions index.js
Original file line number Diff line number Diff line change
Expand Up @@ -151,12 +151,21 @@ async function importString(code, dirname, options) {
return mod.namespace;
}

/**
* @typedef {"commonjs"|"es"} ModuleType
*/

/**
* @type Record<string, ModuleType>
*/
let cache = {};

/**
* Figure out the module type for the given file. If no package.json is
* found, default to "commonjs".
*
* @param {string} filename Fully-qualified filename to start from.
* @returns {Promise<"commonjs"|"es">}
* @returns {Promise<ModuleType>}
* @throws On invalid package.json
*/
async function guessModuleType(filename) {
Expand All @@ -167,13 +176,23 @@ async function guessModuleType(filename) {
default:
// Fall-through
}

/** @type {ModuleType} */
let res = "commonjs";
let dir = fp.dir;
let prev = undefined;
const pending = [];
while (dir !== prev) {
const cached = cache[dir];
if (cached) {
return cached;
}
pending.push(dir);
try {
const pkg = await fs.readFile(path.join(dir, "package.json"), "utf8");
const pkgj = JSON.parse(pkg);
return (pkgj.type === "module") ? "es" : "commonjs";
res = (pkgj.type === "module") ? "es" : "commonjs";
break;
} catch (err) {
// If the file just didn't exist, keep going.
if (/** @type {NodeJS.ErrnoException} */ (err).code !== "ENOENT") {
Expand All @@ -183,9 +202,16 @@ async function guessModuleType(filename) {
prev = dir;
dir = path.dirname(dir);
}
return "commonjs";
for (const p of pending) {
cache[p] = res;
}
return res;
}

guessModuleType.clearCache = function clearCache() {
cache = {};
};

/**
* Import or require the given code from memory. Knows about the different
* Peggy output formats. Returns the exports of the module.
Expand All @@ -194,7 +220,7 @@ async function guessModuleType(filename) {
* @param {FromMemOptions} options Options. Most important is filename.
* @returns {Promise<unknown>} The evaluated code.
*/
module.exports = async function fromMem(code, options) {
async function fromMem(code, options) {
options = {
format: "commonjs",
context: {},
Expand Down Expand Up @@ -239,4 +265,8 @@ module.exports = async function fromMem(code, options) {
default:
throw new Error(`Unsupported output format: "${options.format}"`);
}
};
}

fromMem.guessModuleType = guessModuleType;

module.exports = fromMem;
8 changes: 4 additions & 4 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -17,11 +17,11 @@
"author": "Joe Hildebrand <[email protected]>",
"license": "MIT",
"devDependencies": {
"@peggyjs/eslint-config": "3.2.2",
"@types/node": "20.11.19",
"@types/semver": "7.5.7",
"@peggyjs/eslint-config": "3.2.3",
"@types/node": "20.11.20",
"@types/semver": "7.5.8",
"c8": "9.1.0",
"eslint": "8.56.0",
"eslint": "8.57.0",
"typescript": "5.3.3"
},
"packageManager": "[email protected]",
Expand Down
92 changes: 46 additions & 46 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading