Skip to content

Instantly share code, notes, and snippets.

@mkg20001
Created March 1, 2023 23:05
Show Gist options
  • Save mkg20001/fcfc5e364bc077a18d5876526b14daae to your computer and use it in GitHub Desktop.
Save mkg20001/fcfc5e364bc077a18d5876526b14daae to your computer and use it in GitHub Desktop.
Babel Transformer that addds __dirname, __filename
import {template} from '@babel/core'
import path from 'path'
import fs from 'fs'
const header = `
import { dirname as _INJECT_d } from 'path';
import { fileURLToPath as _INJECT_f } from 'url';
const __filename = _INJECT_f(import.meta.url)
const __dirname = _INJECT_d(__filename)
`
function getPackageType(file, prev) {
// `url` is only a file path during the first iteration when passed the
// resolved url from the load() hook
// an actual file path from load() will contain a file extension as it's
// required by the spec
// this simple truthy check for whether `url` contains a file extension will
// work for most projects but does not cover some edge-cases (such as
// extensionless files or a url ending in a trailing space)
const ext = path.extname(file);
if (ext === "cjs") return "commonjs";
if (ext === "mjs") return "module";
// If it is a file path, get the directory it's in
const dir = ext ? path.dirname(file) : file;
// Compose a file path to a package.json in the same directory,
// which may or may not exist
const packagePath = path.resolve(dir, "package.json");
// Try to read the possibly nonexistent package.json
let type
try {
type = JSON.parse(fs.readFileSync(packagePath, { encoding: "utf8" })).type
} catch(err) {
if (err?.code !== "ENOENT") console.error(err);
}
// Ff package.json existed and contained a `type` field with a value, voila
if (type) return type;
// Otherwise, (if not at the root) continue checking the next directory up
// If at the root, stop and return false
return dir.length > 1 && getPackageType(path.resolve(dir, ".."), dir);
}
export default (api) => {
api.assertVersion(7);
const { types: t } = api;
return {
name: 'inject',
visitor: {
Program(path, state) {
const filename = state.file.opts.parserOpts.sourceFilename || state.file.opts.filename || '/'
const type = getPackageType(filename)
// path.unshiftContainer('body', template(`console.log(${JSON.stringify({s:path.node.sourceType,b:path.scope.hasBinding('__dirname'), t:type,filename})});`, { sourceType: path.node.sourceType })())
if (!path.scope.hasBinding('__dirname')) {
if (path.node.sourceType === 'module' && type === 'module') {
path.unshiftContainer('body', template(header, { sourceType: path.node.sourceType })())
}
}
},
},
};
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment