@ts-bridge/cli
Version:
Bridge the gap between ES modules and CommonJS modules with an easy-to-use alternative to `tsc`.
182 lines (181 loc) • 10.9 kB
JavaScript
import typescript from 'typescript';
const { factory, SyntaxKind, NodeFlags } = typescript;
/**
* Get the AST for the `fileURLToPath` function, i.e.:
*
* ```ts
* function fileURLToPath(fileUrl: string) {
* const url = new URL(fileUrl);
* return url.pathname.replace(/^\/([a-zA-Z]:)/u, '$1');
* }
* ```
*
* This function is a simplified version of the `fileURLToPath` function in
* Node.js and does not handle edge cases like file URLs that contain invalid
* characters. It is assumed that the input is always a valid file URL.
*
* This is used to avoid the need for polyfills in browser environment.
*
* @param functionName - The name of the function to create.
* @returns The AST for the `fileURLToPath` function.
*/
export function getFileUrlToPathHelperFunction(functionName) {
return factory.createFunctionDeclaration(undefined, undefined, factory.createIdentifier(functionName), undefined, [
factory.createParameterDeclaration(undefined, undefined, factory.createIdentifier('fileUrl'), undefined, factory.createKeywordTypeNode(SyntaxKind.StringKeyword), undefined),
], undefined, factory.createBlock([
factory.createVariableStatement(undefined, factory.createVariableDeclarationList([
factory.createVariableDeclaration(factory.createIdentifier('url'), undefined, undefined, factory.createNewExpression(factory.createIdentifier('URL'), undefined, [factory.createIdentifier('fileUrl')])),
], NodeFlags.Const)),
factory.createReturnStatement(factory.createCallExpression(factory.createPropertyAccessExpression(factory.createPropertyAccessExpression(factory.createIdentifier('url'), factory.createIdentifier('pathname')), factory.createIdentifier('replace')), undefined, [
factory.createRegularExpressionLiteral('/^\\/([a-zA-Z]:)/u'),
factory.createStringLiteral('$1'),
])),
], true));
}
/**
* Get the AST for the `dirname` function, i.e.:
*
* ```ts
* function dirname(path: string) {
* const sanitisedPath = path
* .toString()
* .replace(/\\/gu, '/')
* .replace(/\/$/u, '');
*
* const index = sanitisedPath.lastIndexOf('/');
* if (index === -1) {
* return path;
* }
*
* if (index === 0) {
* return '/';
* }
*
* return sanitisedPath.slice(0, index);
* }
* ```
*
* This function is a simplified version of the `dirname` function in Node.js.
* It does not handle edge cases like paths that end with multiple slashes or
* paths that contain invalid characters. It is assumed that the input is always
* a valid path.
*
* This is used to avoid the need for polyfills in browser environment.
*
* @param functionName - The name of the function to create.
* @returns The AST for the `dirname` function.
*/
export function getDirnameHelperFunction(functionName) {
return factory.createFunctionDeclaration(undefined, undefined, factory.createIdentifier(functionName), undefined, [
factory.createParameterDeclaration(undefined, undefined, factory.createIdentifier('path'), undefined, factory.createKeywordTypeNode(SyntaxKind.StringKeyword), undefined),
], undefined, factory.createBlock([
factory.createVariableStatement(undefined, factory.createVariableDeclarationList([
factory.createVariableDeclaration(factory.createIdentifier('sanitisedPath'), undefined, undefined, factory.createCallExpression(factory.createPropertyAccessExpression(factory.createCallExpression(factory.createPropertyAccessExpression(factory.createCallExpression(factory.createPropertyAccessExpression(factory.createIdentifier('path'), factory.createIdentifier('toString')), undefined, []), factory.createIdentifier('replace')), undefined, [
factory.createRegularExpressionLiteral('/\\\\/gu'),
factory.createStringLiteral('/'),
]), factory.createIdentifier('replace')), undefined, [
factory.createRegularExpressionLiteral('/\\/$/u'),
factory.createStringLiteral(''),
])),
], NodeFlags.Const)),
factory.createVariableStatement(undefined, factory.createVariableDeclarationList([
factory.createVariableDeclaration(factory.createIdentifier('index'), undefined, undefined, factory.createCallExpression(factory.createPropertyAccessExpression(factory.createIdentifier('sanitisedPath'), factory.createIdentifier('lastIndexOf')), undefined, [factory.createStringLiteral('/')])),
], NodeFlags.Const)),
factory.createIfStatement(factory.createBinaryExpression(factory.createIdentifier('index'), factory.createToken(SyntaxKind.EqualsEqualsEqualsToken), factory.createPrefixUnaryExpression(SyntaxKind.MinusToken, factory.createNumericLiteral('1'))), factory.createBlock([factory.createReturnStatement(factory.createIdentifier('path'))], true), undefined),
factory.createIfStatement(factory.createBinaryExpression(factory.createIdentifier('index'), factory.createToken(SyntaxKind.EqualsEqualsEqualsToken), factory.createNumericLiteral('0')), factory.createBlock([factory.createReturnStatement(factory.createStringLiteral('/'))], true), undefined),
factory.createReturnStatement(factory.createCallExpression(factory.createPropertyAccessExpression(factory.createIdentifier('sanitisedPath'), factory.createIdentifier('slice')), undefined, [
factory.createNumericLiteral('0'),
factory.createIdentifier('index'),
])),
], true));
}
/**
* Get the AST for the `__dirname` global function, i.e.:
*
* ```ts
* function __dirname(url: string): string {
* return dirname(fileUrlToPath(url));
* }
* ```
*
* This function returns the directory name of the current module, i.e.,
* `__dirname`, but for ESM.
*
* @param functionName - The name of the function to create.
* @param fileUrlToPathFunctionName - The name of the function that converts a
* file URL to a path.
* @param dirnameFunctionName - The name of the function that gets the directory
* name of a path.
* @returns The AST for the `__dirname` global function.
*/
export function getDirnameGlobalFunction(functionName, fileUrlToPathFunctionName, dirnameFunctionName) {
return factory.createFunctionDeclaration(undefined, undefined, factory.createIdentifier(functionName), undefined, [
factory.createParameterDeclaration(undefined, undefined, factory.createIdentifier('url'), undefined, factory.createKeywordTypeNode(SyntaxKind.StringKeyword), undefined),
], factory.createKeywordTypeNode(SyntaxKind.StringKeyword), factory.createBlock([
factory.createReturnStatement(factory.createCallExpression(factory.createIdentifier(dirnameFunctionName), undefined, [
factory.createCallExpression(factory.createIdentifier(fileUrlToPathFunctionName), undefined, [factory.createIdentifier('url')]),
])),
], true));
}
/**
* Get the AST for the `getImportMetaUrl` function, i.e.:
*
* ```ts
* function getImportMetaUrl(fileName: string): string {
* return typeof document === 'undefined'
* ? new URL(`file:${fileName}`).href
* : document.currentScript?.src ?? new URL('main.js', document.baseURI).href;
* }
* ```
*
* If the current environment is a browser, it will return the URL of the
* current script (if it's available). Otherwise, it will return the URL of the
* current file.
*
* @param functionName - The name of the function to create.
* @returns The AST for the `getImportMetaUrl` function.
*/
export function getImportMetaUrlFunction(functionName) {
return factory.createFunctionDeclaration(undefined, undefined, factory.createIdentifier(functionName), undefined, [
factory.createParameterDeclaration(undefined, undefined, factory.createIdentifier('fileName'), undefined, factory.createKeywordTypeNode(SyntaxKind.StringKeyword), undefined),
], factory.createKeywordTypeNode(SyntaxKind.StringKeyword), factory.createBlock([
factory.createReturnStatement(factory.createConditionalExpression(factory.createBinaryExpression(factory.createTypeOfExpression(factory.createIdentifier('document')), factory.createToken(SyntaxKind.EqualsEqualsEqualsToken), factory.createStringLiteral('undefined')), factory.createToken(SyntaxKind.QuestionToken), factory.createPropertyAccessExpression(factory.createNewExpression(factory.createIdentifier('URL'), undefined, [
factory.createTemplateExpression(factory.createTemplateHead('file:', 'file:'), [
factory.createTemplateSpan(factory.createIdentifier('fileName'), factory.createTemplateTail('', '')),
]),
]), factory.createIdentifier('href')), factory.createToken(SyntaxKind.ColonToken), factory.createBinaryExpression(factory.createPropertyAccessChain(factory.createPropertyAccessExpression(factory.createIdentifier('document'), factory.createIdentifier('currentScript')), factory.createToken(SyntaxKind.QuestionDotToken), factory.createIdentifier('src')), factory.createToken(SyntaxKind.QuestionQuestionToken), factory.createPropertyAccessExpression(factory.createNewExpression(factory.createIdentifier('URL'), undefined, [
factory.createStringLiteral('main.js'),
factory.createPropertyAccessExpression(factory.createIdentifier('document'), factory.createIdentifier('baseURI')),
]), factory.createIdentifier('href'))))),
], true));
}
/**
* Get the AST for the `require` function, i.e.:
*
* ```ts
* import { createRequire as $createRequire } from 'module';
*
* const $require = $createRequire(import.meta.url);
* ```
*
* This is a shim for Node.js's `require` function, and is intended to be used
* in ESM modules. Note that this function cannot be used to import ESM modules,
* only CJS modules.
*
* @param functionName - The name of the require function to create.
* @param createRequireFunctionName - The name of the `createRequire` function
* to import.
* @returns The AST for the `require` function.
*/
export function getRequireHelperFunction(functionName, createRequireFunctionName) {
return [
factory.createImportDeclaration(undefined, factory.createImportClause(false, undefined, factory.createNamedImports([
factory.createImportSpecifier(false, factory.createIdentifier('createRequire'), factory.createIdentifier(createRequireFunctionName)),
])), factory.createStringLiteral('module'), undefined),
factory.createVariableStatement(undefined, factory.createVariableDeclarationList([
factory.createVariableDeclaration(factory.createIdentifier(functionName), undefined, undefined, factory.createCallExpression(factory.createIdentifier(createRequireFunctionName), undefined, [
factory.createPropertyAccessExpression(factory.createMetaProperty(SyntaxKind.ImportKeyword, factory.createIdentifier('meta')), factory.createIdentifier('url')),
])),
], NodeFlags.Const)),
];
}