@babel/register
Version:
babel require hook
343 lines (333 loc) • 8.62 kB
JavaScript
import { ACTIONS } from '../types-shared.js';
import { loadPartialConfigAsync, loadOptionsAsync, transformAsync, version, getEnv, DEFAULT_EXTENSIONS } from '@babel/core';
import cloneDeep from 'clone-deep';
import path, { isAbsolute, resolve, dirname, join } from 'node:path';
import fs, { constants, accessSync, existsSync, mkdirSync } from 'node:fs';
import crypto from 'node:crypto';
import os from 'node:os';
import { env } from 'node:process';
import 'node:module';
import 'node:url';
import cacache from 'cacache';
import { unzipSync, gzipSync } from 'node:zlib';
import { parentPort } from 'node:worker_threads';
function ok(path, mode) {
try {
accessSync(path, mode);
return true;
} catch {
return false;
}
}
function writable(path) {
return ok(path, constants.W_OK);
}
function absolute(input, root) {
return isAbsolute(input) ? input : resolve(root || ".", input);
}
function up$2(base, options) {
let {
last,
cwd
} = options || {};
let tmp = absolute(base, cwd);
let root = absolute(last || "/", cwd);
let prev,
arr = [];
while (prev !== root) {
arr.push(tmp);
tmp = dirname(prev = tmp);
if (tmp === prev) break;
}
return arr;
}
function up$1(name, options) {
let dir, tmp;
let start = options && options.cwd || "";
for (dir of up$2(start, options)) {
tmp = join(dir, name);
if (existsSync(tmp)) return tmp;
}
}
function up(options) {
return up$1("package.json", options);
}
function cache$1(name, options) {
options = options || {};
let dir = env.CACHE_DIR;
if (!dir || /^(1|0|true|false)$/.test(dir)) {
let pkg = up(options);
if (dir = pkg && dirname(pkg)) {
let mods = join(dir, "node_modules");
let exists = existsSync(mods);
if (!writable(exists ? mods : dir)) return;
dir = join(mods, ".cache");
}
}
if (dir) {
dir = join(dir, name);
if (options.create && !existsSync(dir)) {
mkdirSync(dir, {
recursive: true
});
}
return dir;
}
}
let globalDisableCache = false;
class Cache {
enabled = false;
cacheDir = process.env.BABEL_CACHE_PATH || cache$1("@babel/register") || path.join(os.tmpdir() || os.homedir(), `.babel-register`);
batched = [];
batchedSize = 0;
cache = new Map();
index = new Map();
constructor() {
globalDisableCache = !!process.env.BABEL_DISABLE_CACHE;
if (fs.existsSync(this.cacheDir)) {
if (fs.statSync(this.cacheDir).isFile()) {
console.warn(`Cache directory ${this.cacheDir} is a file, not a directory.`);
globalDisableCache = true;
}
return;
}
try {
fs.mkdirSync(this.cacheDir, {
recursive: true
});
} catch (_) {
console.warn(`Failed to create cache directory ${this.cacheDir}`);
globalDisableCache = true;
return;
}
try {
fs.accessSync(this.cacheDir, fs.constants.W_OK | fs.constants.R_OK);
} catch (_) {
console.warn(`Cache directory ${this.cacheDir} is not writable or readable.`);
globalDisableCache = true;
}
}
async enable() {
if (globalDisableCache) return;
this.enabled = true;
const entries = await cacache.ls(this.cacheDir);
for (const [key, cache] of Object.entries(entries)) {
const now = Date.now();
if (now - cache.time > 1000 * 60 * 60 * 24) {
await cacache.rm.content(this.cacheDir, cache.integrity);
await cacache.rm.entry(this.cacheDir, key);
continue;
}
key.split("|").forEach(k => {
this.index.set(k, cache.integrity);
});
}
}
async get(key) {
if (!this.enabled) return;
if (this.cache.has(key)) {
return this.cache.get(key);
}
const integrity = this.index.get(key);
if (!integrity) return;
try {
let cache = await cacache.get.byDigest(this.cacheDir, integrity, {
memoize: false
});
cache = unzipSync(cache);
const items = JSON.parse(cache.toString("utf8"));
for (const item of items) {
this.cache.set(item.key, item.data);
}
return this.cache.get(key);
} catch (error) {
if (error.code !== "ENOENT") {
throw error;
}
}
}
async disable() {
await this.flush();
this.enabled = false;
}
async set(key, data) {
if (!this.enabled) return;
this.cache.set(key, data);
this.batched.push({
key,
data
});
this.batchedSize += JSON.stringify(data).length;
if (this.batchedSize >= 1024 * 1024) {
await this.flush();
}
}
async flush() {
if (!this.enabled) return;
const key = this.batched.map(item => item.key).join("|");
const buf = Buffer.from(JSON.stringify(this.batched));
await cacache.put(this.cacheDir, key, gzipSync(buf), {
algorithms: ["sha1"]
});
this.batched = [];
this.batchedSize = 0;
}
}
const cache = new Cache();
const nmRE = escapeRegExp(path.sep + "node_modules" + path.sep);
function escapeRegExp(string) {
return string.replace(/[|\\{}()[\]^$+*?.]/g, "\\$&");
}
const id = value => value;
async function cacheLookup(opts, filename) {
if (!cache.enabled) {
return {
cached: null,
store: id
};
}
let cacheKey = `${JSON.stringify(opts)}:${version}`;
const env = getEnv();
if (env) cacheKey += `:${env}`;
cacheKey = crypto.createHash("sha1").update(cacheKey).digest("hex");
const cached = await cache.get(cacheKey);
const fileMtime = +fs.statSync(filename).mtime;
if (cached?.mtime === fileMtime) {
return {
cached: cached.value,
store: id
};
}
return {
cached: null,
async store(value) {
await cache.set(cacheKey, {
value,
mtime: fileMtime
});
return value;
}
};
}
let transformOpts;
async function setOptions(opts) {
if (opts.cache === false && cache.enabled) {
await cache.disable();
} else if (opts.cache !== false && !cache.enabled) {
await cache.enable();
}
delete opts.cache;
delete opts.extensions;
transformOpts = {
...opts,
caller: {
name: "@babel/register",
supportsStaticESM: false,
supportsDynamicImport: false,
supportsExportNamespaceFrom: false,
...(opts.caller || {})
}
};
let {
cwd = "."
} = transformOpts;
cwd = transformOpts.cwd = path.resolve(cwd);
if (transformOpts.ignore === undefined && transformOpts.only === undefined) {
const cwdRE = escapeRegExp(cwd);
transformOpts.only = [new RegExp("^" + cwdRE, "i")];
transformOpts.ignore = [new RegExp(`^${cwdRE}(?:${path.sep}.*)?${nmRE}`, "i")];
}
}
async function transform(input, filename) {
const opts = await loadOptionsAsync({
sourceRoot: path.dirname(filename) + path.sep,
...cloneDeep(transformOpts),
filename
});
if (opts === null) {
return null;
}
const {
cached,
store
} = await cacheLookup(opts, filename);
if (cached) return cached;
const {
code,
map
} = await transformAsync(input, {
...opts,
sourceMaps: opts.sourceMaps === undefined ? "both" : opts.sourceMaps,
ast: false
});
return await store({
code,
map
});
}
async function isFileIgnored(filename) {
const opts = await loadPartialConfigAsync({
...cloneDeep(transformOpts),
filename,
showIgnoredFiles: true,
babelrc: false,
configFile: false,
browserslistConfigFile: false,
plugins: [],
presets: [],
targets: {
browsers: undefined
}
});
return opts === null;
}
function disableCache() {
return cache.disable();
}
function handleMessage(action, payload) {
switch (action) {
case ACTIONS.GET_DEFAULT_EXTENSIONS:
return DEFAULT_EXTENSIONS;
case ACTIONS.SET_OPTIONS:
return setOptions(payload);
case ACTIONS.TRANSFORM:
return transform(payload.code, payload.filename);
case ACTIONS.IS_FILE_IGNORED:
return isFileIgnored(payload);
case ACTIONS.CLOSE:
return disableCache();
}
throw new Error(`Unknown internal parser worker action: ${action}`);
}
parentPort.addListener("message", async ({
signal,
port,
action,
payload
}) => {
let response;
try {
response = {
result: await handleMessage(action, payload)
};
} catch (error) {
response = {
error,
errorData: {
...error
}
};
}
try {
port.postMessage(response);
} catch {
port.postMessage({
error: new Error("Cannot serialize worker response")
});
} finally {
port.close();
Atomics.store(signal, 0, 1);
Atomics.notify(signal, 0);
}
});
//# sourceMappingURL=index.js.map