Skip to content

Instantly share code, notes, and snippets.

@maksimr
Last active April 18, 2024 21:04
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save maksimr/dc80652c63abfa287e0f8d98f2a094ef to your computer and use it in GitHub Desktop.
Save maksimr/dc80652c63abfa287e0f8d98f2a094ef to your computer and use it in GitHub Desktop.
async function main() {
const fs = require('fs/promises');
const os = require('os');
const path = require('path');
const promisify = require('util').promisify;
const babelParentDir = path.resolve(__dirname, '..', 'packages');
const babelParserDir = path.join(babelParentDir, 'babel-parser')
const babelPackageName = '@packages/babel-parser';
const babelOutDir = 'lib';
const babelVersion = process.argv[2] || 'v7.24.4';
const babelCloneDir = path.join(os.tmpdir(), `babel-${babelVersion}`);
await cloneBabelParser(babelCloneDir, babelVersion);
await copyBabelParser(babelCloneDir);
await Promise.all([
await removeTsExtensionFromImportAndTsExpectError(),
await patchPackageJson(babelCloneDir),
await patchTsConfig()
]);
async function cloneBabelParser(babelCloneDir, version = 'main') {
await fs.mkdir(babelCloneDir, { recursive: true });
const isNotEmpty = (await fs.readdir(babelCloneDir)).length > 0;
if (isNotEmpty) {
console.log(`babel@${version} is already cloned to ${babelCloneDir}`);
return;
};
console.log(`cloning babel@${version}`);
const exec = promisify(require('child_process').exec);
await exec(`git clone --depth=1 --branch=${version} https://github.com/babel/babel ${babelCloneDir}`)
console.log(`cloned babel@${version} to ${babelCloneDir}`);
}
async function copyBabelParser(babelCloneDir) {
console.log('copying babel-parser to the project');
await fs.mkdir(babelParserDir, { recursive: true });
await fs.cp(path.join(babelCloneDir, 'packages', 'babel-parser'), babelParserDir, { recursive: true })
await fs.copyFile(
path.join(babelCloneDir, 'tsconfig.base.json'),
path.join(babelParserDir, 'tsconfig.json')
);
console.log('copied babel-parser')
}
async function getBabelPackagesVersion(babelCloneDir) {
const babelPackages = await fs.readdir(path.join(babelCloneDir, 'packages'));
const babelPackagesVersion = new Map();
for (const package of babelPackages) {
try {
const pkg = require(path.join(babelCloneDir, 'packages', package, 'package.json'));
babelPackagesVersion.set(pkg.name, pkg.version);
} catch (error) {
continue;
}
}
return babelPackagesVersion;
}
async function patchPackageJson(babelCloneDir) {
console.log('patching package.json');
const babelPackagesVersion = await getBabelPackagesVersion(babelCloneDir);
const pkg = require(path.join(babelParserDir, 'package.json'));
pkg.name = babelPackageName;
// patch workspace: dependencies
if (pkg.devDependencies) {
pkg.devDependencies = Object.fromEntries(
Object.entries(pkg.devDependencies).map(([name, version]) => {
if (/^workspace:/.test(version)) {
return [name, babelPackagesVersion.get(name)];
}
return [name, version];
})
);
// add typescript and @types/node to build babel-parser
pkg.devDependencies["typescript"] = "5.4.5";
pkg.devDependencies["@types/node"] = "20.12.7";
// add @types/charcodes for charcodes
if (pkg.devDependencies['charcodes']) {
pkg.devDependencies['@types/charcodes'] = pkg.devDependencies['charcodes'];
}
// convert devDependencies to dependencies
// because we will build the package without inline dependencies
// how it is done in the babel project
pkg.dependencies = pkg.devDependencies;
pkg.devDependencies = undefined;
}
pkg.types = undefined;
pkg.conditions = undefined;
// add preapre and build script
pkg.scripts = pkg.scripts || {};
pkg.scripts['prepare'] = 'npm run build';
pkg.scripts['build'] = 'tsc';
pkg.exports = pkg.exports || {};
pkg.exports["./src/*"] = `./${babelOutDir}/*.js`;
await fs.writeFile(path.join(babelParserDir, 'package.json'), JSON.stringify(pkg, null, 2));
console.log('patched package.json');
}
async function removeTsExtensionFromImportAndTsExpectError() {
console.log('processing .ts files');
const src = path.join(babelParserDir, 'src');
processTsFiles(src, async (filePath) => {
const content = await fs.readFile(filePath, 'utf-8');
let newContent = content.replace(/from (['"])(.+)\.ts['"];/g, 'from $1$2$1;');
newContent = newContent.replace(/@ts-expect-error/g, '@ts-ignore');
await fs.writeFile(filePath, newContent);
});
console.log('processed .ts files');
}
async function processTsFiles(dir, cb) {
const files = await fs.readdir(dir, { withFileTypes: true });
for (const file of files) {
const filePath = path.join(dir, file.name);
if (file.isFile() && file.name.endsWith('.ts')) {
cb(filePath);
continue;
}
if (file.isDirectory()) {
processTsFiles(filePath, cb);
}
}
}
async function patchTsConfig() {
console.log('patching tsconfig.json');
const tsConfigPath = path.resolve(babelParserDir, 'tsconfig.json');
const babelBaseTsConfig = require(tsConfigPath);
const babelTsConfig = {
...babelBaseTsConfig,
/**@type {import('typescript').CompilerOptions} */
compilerOptions: {
...babelBaseTsConfig.compilerOptions,
declarationDir: undefined,
emitDeclarationOnly: false,
skipLibCheck: false,
allowImportingTsExtensions: false,
outDir: babelOutDir,
noImplicitAny: false,
sourceMap: true,
module: 'commonjs',
moduleResolution: 'node',
incremental: true
},
include: ["src"]
};
await fs.writeFile(tsConfigPath, JSON.stringify(babelTsConfig, null, 2));
console.log('patched tsconfig.json');
}
}
main();
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment