Skip to content

Commit

Permalink
feat: Support default exported functions (#99)
Browse files Browse the repository at this point in the history
  • Loading branch information
bennycode authored Nov 19, 2024
1 parent d0aac83 commit 690580d
Show file tree
Hide file tree
Showing 10 changed files with 72 additions and 23 deletions.
12 changes: 12 additions & 0 deletions src/converter/convertFile.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -91,5 +91,17 @@ describe('convertFile', () => {

await expect(modifiedFile?.getFullText()).toMatchFileSnapshot(snapshot);
});

it('handles functions exported as default from plain JavaScript files', async () => {
const projectDir = path.join(fixtures, 'module-exports-function-js');
const projectConfig = path.join(projectDir, 'tsconfig.json');
const snapshot = path.join(projectDir, 'src', 'build-example-index.snap.js');
const project = ProjectUtil.getProject(projectConfig);

const sourceFile = project.getSourceFile('build-example-index.js')!;
const modifiedFile = convertFile(sourceFile);

await expect(modifiedFile?.getFullText()).toMatchFileSnapshot(snapshot);
});
});
});
34 changes: 16 additions & 18 deletions src/converter/replacer/replaceModuleExports.ts
Original file line number Diff line number Diff line change
@@ -1,30 +1,36 @@
import {SourceFile, SyntaxKind} from 'ts-morph';
import {NodeUtil} from '../../util/NodeUtil.js';

export function replaceModuleExports(sourceFile: SourceFile) {
let defaultExport: string | undefined = undefined;
const namedExports: string[] = [];

// Iterate through all statements in the source file
sourceFile.getStatements().forEach(statement => {
try {
if (statement.getKind() === SyntaxKind.ExpressionStatement) {
const expressionStatement = statement.asKind(SyntaxKind.ExpressionStatement);
if (!expressionStatement) {
return;
}

const expression = expressionStatement.getExpression();
if (expression.getKind() === SyntaxKind.BinaryExpression) {
const binaryExpression = expression.asKind(SyntaxKind.BinaryExpression);
if (!binaryExpression) {
return;
}

const left = binaryExpression.getLeft().getText();
const right = binaryExpression.getRight().getText();
const right = binaryExpression.getRight();

if (left === 'module.exports') {
defaultExport = right;
// Handle `module.exports = <expression>;`
if (left === 'module.exports' && right) {
const {comment} = NodeUtil.extractComment(binaryExpression.getLeft());
defaultExport = right.getText();
sourceFile.addStatements(`${comment}export default ${defaultExport};`);
statement.remove();
} else if (left.startsWith('module.exports.')) {
} else if (left.startsWith('module.exports.') && right) {
// Handle `module.exports.<name> = <value>;`
const exportName = left.split('.')[2];
if (exportName) {
namedExports.push(exportName);
Expand All @@ -35,27 +41,19 @@ export function replaceModuleExports(sourceFile: SourceFile) {
}
} catch (error: unknown) {
console.error(` There was an issue with "${sourceFile.getFilePath()}":`, error);
process.exit(1);
}
});

try {
if (defaultExport) {
sourceFile.addExportAssignment({
expression: defaultExport,
isExportEquals: false,
});
}

namedExports.forEach(name => {
if (namedExports.length > 0) {
sourceFile.addExportDeclaration({
namedExports: [name],
namedExports,
});
});
}
} catch (error: unknown) {
console.error(` There was an issue with "${sourceFile.getFilePath()}":`, error);
}

const madeChanges = namedExports.length || defaultExport;
return !!madeChanges;
const madeChanges = defaultExport !== undefined || namedExports.length > 0;
return madeChanges;
}
7 changes: 3 additions & 4 deletions src/converter/replacer/replaceRequire.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import {SourceFile, SyntaxKind, VariableStatement} from 'ts-morph';
import {NodeUtil} from '../../util/NodeUtil.js';

/**
* Replaces a CommonJS require statement with an ESM import declaration.
Expand Down Expand Up @@ -61,10 +62,8 @@ export function replaceRequires(sourceFile: SourceFile) {
if (hasShebang) {
// The full text contains both comments and the following statment,
// so we are separating the statement into comments and the instruction that follow on the next line.
const statementWithComment = firstStatement.getFullText();
const pureStatement = firstStatement.getText();
shebangText = statementWithComment.replace(pureStatement, '');
const lineAfterShebang = statementWithComment.replace(shebangText, '');
const {statement: lineAfterShebang, comment} = NodeUtil.extractComment(firstStatement);
shebangText = comment;
// We remove the node containing the shebang comment (and the following statement) to insert only the pure statement.
const index = firstStatement.getChildIndex();
firstStatement.remove();
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
import path from 'path';
import info from './example-info.json';

export default function buildExampleMarkdown(names, exampleBasePaths) {}
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
const path = require('path');
const info = require('./example-info.json');

module.exports = function buildExampleMarkdown(names, exampleBasePaths) {};
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
const path = require('path');

/** This comment should be kept. */
module.exports = function buildExampleIndex(names, exampleBasePaths) {};
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
import path from "path";

/** This comment should be kept. */
export default function buildExampleIndex(names, exampleBasePaths) {};
11 changes: 11 additions & 0 deletions src/test/fixtures/module-exports-function-js/tsconfig.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
{
"compilerOptions": {
"allowJs": true,
"esModuleInterop": true,
"forceConsistentCasingInFileNames": true,
"module": "Node16",
"skipLibCheck": true,
"strict": true,
"target": "ES2020"
}
}
1 change: 0 additions & 1 deletion src/test/fixtures/module-exports/src/main.snap.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
const Benny = 1;
const Code = 2;

export default Benny;

export { Code };
14 changes: 14 additions & 0 deletions src/util/NodeUtil.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import {Expression, Statement} from 'ts-morph';

export class NodeUtil {
static extractComment(input: Statement | Expression) {
const statementWithComment = input.getFullText();
const pureStatement = input.getText();
const comment = statementWithComment.replace(pureStatement, '');
const statement = statementWithComment.replace(comment, '');
return {
comment,
statement,
};
}
}

0 comments on commit 690580d

Please sign in to comment.