Created
March 1, 2023 23:05
-
-
Save mkg20001/fcfc5e364bc077a18d5876526b14daae to your computer and use it in GitHub Desktop.
Babel Transformer that addds __dirname, __filename
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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