Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

@ts-liveserver/ts-transpiler

Package Overview
Dependencies
Maintainers
2
Versions
38
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@ts-liveserver/ts-transpiler - npm Package Compare versions

Comparing version 0.0.1 to 0.0.2

__tests__/transformers/CodeOptimizerTransformer.test.ts

3

__tests__/outputData/.eslintrc.js
module.exports = require("../../.eslintrc.js");
module.exports.rule["prefer-const"] = "off";
module.exports.rules["prefer-const"] = "off";
module.exports.rules["no-console"] = "off";

@@ -6,2 +6,2 @@ module.exports = {

singleQuote: false,
}
};
import ModuleB from "./ModuleB.ts";
const component = React.createElement("div", null, "Hello");
component;
console.log(component);
const ModuleA = ModuleB;
export default ModuleA;
//# sourceMappingURL=ModuleA.js.map

@@ -5,27 +5,92 @@ import CommonJsTransformer from '../../src/transformers/CommonJsTransformer'

describe('CommonJsTransformer', () => {
it('Should convert to default export to ES6', async () => {
const input = 'module.exports = {};'
const output = 'export default {};'
expect(await transform(input)).toBe(output)
describe('Import', () => {
it('Should convert simple import', async () => {
const input = 'require("./hello.ts")'
const output = 'import "./hello.ts";'
expect(await transformWithPlugin(input)).toBe(output)
})
it('Should convert default import to ES6', async () => {
const input = 'const Hello = require("./hello.ts")'
const output = 'import * as Hello from "./hello.ts";'
expect(await transformWithPlugin(input)).toBe(output)
})
it('Should convert named import', async () => {
const input = 'const { Hello } = require("./hello.ts")'
const output = 'import { Hello } from "./hello.ts";'
expect(await transformWithPlugin(input)).toBe(output)
})
it('Should convert require in sub-scope', async () => {
const input = '{ const hello = require("hello.js") }'
const output =
'import * as GENERATED_VAR_BY_TRANSFORMER_1 from "hello.js"; { const hello = GENERATED_VAR_BY_TRANSFORMER_1; }'
expect(await transformWithPlugin(input)).toBe(
await transformWithoutPlugin(output),
)
})
})
it('Should convert to default export to ES6', async () => {
const input = 'module.exports = {};'
const output = 'export default {};'
expect(await transform(input)).toBe(output)
describe('Forwards', () => {
it('Should convert redirects', async () => {
const input = 'module.exports = require("./hello.js")'
const output = 'export * from "./hello.js";'
expect(await transformWithPlugin(input)).toBe(output)
})
})
it('Should convert default import to ES6', async () => {
const input = 'const Hello = require("./hello.ts");'
const output = 'import Hello from "./hello.ts";'
expect(await transform(input)).toBe(output)
describe('Exports', () => {
it('Should convert to default export to ES6', async () => {
const input = 'module.exports = Hello'
const output = 'export default Hello'
expect(await transformWithPlugin(input)).toBe(
await transformWithoutPlugin(output),
)
})
it('Should convert exports.name', async () => {
const input = 'exports.hello = Hello'
const output = 'export { Hello as hello }'
expect(await transformWithPlugin(input)).toBe(
await transformWithoutPlugin(output),
)
})
it('Should convert exports.name with same name as the parameter', async () => {
const input = 'const hello = null; exports.hello = hello'
const output = 'const hello = null; export { hello }'
expect(await transformWithPlugin(input)).toBe(
await transformWithoutPlugin(output),
)
})
it('Should convert exports.default', async () => {
const input = 'exports.default = Hello'
const output = 'export default Hello'
expect(await transformWithPlugin(input)).toBe(
await transformWithoutPlugin(output),
)
})
it('Should convert define.property with getter', async () => {
const input =
'Object.defineProperty(exports, "hello", { enumerable: true, get: function () { return parts_js_1.PropertyPart; } });'
const output =
'var GENERATED_VAR_BY_TRANSFORMER_1 = parts_js_1.PropertyPart; export { GENERATED_VAR_BY_TRANSFORMER_1 as hello };'
expect(await transformWithPlugin(input)).toBe(
await transformWithoutPlugin(output),
)
})
it('Should convert define.property for identifier', async () => {
const input = 'Object.defineProperty(exports, "a", b });'
const output = 'export { b as a };'
expect(await transformWithPlugin(input)).toBe(
await transformWithoutPlugin(output),
)
})
it('Should convert define.property', async () => {
const input = 'module.exports = { a: b, c: d }'
const output = 'export { b as a, d as c };'
expect(await transformWithPlugin(input)).toBe(
await transformWithoutPlugin(output),
)
})
it('Should convert to default export', async () => {
const input = 'module.exports.hello = Hello;'
const output = 'export { Hello as hello };'
expect(await transformWithPlugin(input)).toBe(output)
})
})
it('Should convert simple import', async () => {
const input = 'require("./hello.ts");'
const output = 'import "./hello.ts";'
expect(await transform(input)).toBe(output)
})
it('Should convert named import', async () => {
const input = 'const { Hello } = require("./hello.ts");'
const output = 'import { Hello } from "./hello.ts";'
expect(await transform(input)).toBe(output)
})
})

@@ -37,3 +102,3 @@

checkJs: false,
noResolve: false,
noResolve: true,
esModuleInterop: true,

@@ -51,6 +116,6 @@ skipLibCheck: true,

const transformers: TypeScript.CustomTransformers = {
after: [(context) => new CommonJsTransformer(context)],
before: [(context) => new CommonJsTransformer(context)],
}
async function transform(code: string): Promise<string> {
async function transformWithPlugin(code: string): Promise<string> {
const results = await TypeScript.transpileModule(code, {

@@ -63,1 +128,9 @@ compilerOptions: compilerOptions,

}
async function transformWithoutPlugin(code: string): Promise<string> {
const results = await TypeScript.transpileModule(code, {
compilerOptions: compilerOptions,
fileName: 'hello.ts',
})
return results.outputText.trim()
}

@@ -9,5 +9,7 @@ import TsTranspiler from '../src/TsTranspiler'

const transpiler = new TsTranspiler()
const results = await transpiler.transformFile(
Path.resolve(__dirname, 'inputData', inputFileName),
)
const results = (
await transpiler.transformFile(
Path.resolve(__dirname, 'inputData', inputFileName),
)
).outputText
expect(results + '\n').toBe(

@@ -14,0 +16,0 @@ Fs.readFileSync(

@@ -1,1 +0,1 @@

module.exports = require("../../.prettierrc.js");
module.exports = require('../../.prettierrc.js')
import TypeScript from 'typescript';
export default class CommonJsTransformer implements TypeScript.CustomTransformer {
private context;
private counter;
constructor(context: TypeScript.TransformationContext);
private visit;
transformSourceFile(node: TypeScript.SourceFile): TypeScript.SourceFile;
transformBundle(node: TypeScript.Bundle): TypeScript.Bundle;
transformBundle(): TypeScript.Bundle;
transformSourceFile(sourceFile: TypeScript.SourceFile): TypeScript.SourceFile;
private generateUniqueName;
private convertDefinePropery;
private convertToEsmImport;
private convertToEsmExport;
private stripModule;
private requireTopScope;
}

@@ -7,2 +7,3 @@ "use strict";

const typescript_1 = __importDefault(require("typescript"));
const KEYNAME_EXPORTS = 'exports';
/*

@@ -13,15 +14,230 @@ Transpile CommonJS to ES6 module

constructor(context) {
this.counter = 0;
this.context = context;
}
visit(node) {
return typescript_1.default.visitEachChild(node, this.visit.bind(this), this.context);
transformBundle() {
throw new Error('Method not implemented.');
}
transformSourceFile(node) {
return typescript_1.default.visitNode(node, this.visit.bind(this));
transformSourceFile(sourceFile) {
const requireInTopScope = this.requireTopScope(sourceFile);
const withoutModule = this.stripModule(requireInTopScope);
const withoutDefineProperty = this.convertDefinePropery(withoutModule);
const esmExport = this.convertToEsmExport(withoutDefineProperty);
return this.convertToEsmImport(esmExport);
}
transformBundle(node) {
return node;
// Generate a file unique variable name
generateUniqueName() {
this.counter++;
return 'GENERATED_VAR_BY_TRANSFORMER_' + String(this.counter);
}
// Convert all Object.defineProperty(exports, "hello", Hello);"
convertDefinePropery(sourceFile) {
const visit = (node) => {
if (typescript_1.default.isCallExpression(node) &&
typescript_1.default.isPropertyAccessExpression(node.expression) &&
typescript_1.default.isIdentifier(node.expression.expression) &&
typescript_1.default.isIdentifier(node.expression.name) &&
node.expression.expression.text === 'Object' &&
node.expression.name.text === 'defineProperty' &&
typescript_1.default.isIdentifier(node.arguments[0])) {
const firstArgument = node.arguments[0];
const secondArgument = node.arguments[1];
const thirdArgument = node.arguments[2];
if (typescript_1.default.isIdentifier(firstArgument) &&
firstArgument.text === KEYNAME_EXPORTS &&
typescript_1.default.isStringLiteral(secondArgument)) {
if (typescript_1.default.isIdentifier(thirdArgument)) {
return typescript_1.default.factory.createBinaryExpression(typescript_1.default.factory.createPropertyAccessExpression(typescript_1.default.factory.createIdentifier(KEYNAME_EXPORTS), typescript_1.default.factory.createIdentifier(secondArgument.text)), typescript_1.default.SyntaxKind.EqualsToken, thirdArgument);
}
else if (typescript_1.default.isObjectLiteralExpression(thirdArgument)) {
const propertyGetter = thirdArgument.properties
.filter((property) => typescript_1.default.isPropertyAssignment(property))
.find((property) => typescript_1.default.isPropertyAssignment(property) &&
typescript_1.default.isIdentifier(property.name) &&
property.name.text === 'get');
if (propertyGetter &&
typescript_1.default.isPropertyAssignment(propertyGetter) &&
propertyGetter.initializer &&
typescript_1.default.isFunctionExpression(propertyGetter.initializer) &&
typescript_1.default.isBlock(propertyGetter.initializer.body)) {
const firstStatement = propertyGetter.initializer.body.statements[0];
if (typescript_1.default.isReturnStatement(firstStatement) &&
firstStatement.expression) {
return typescript_1.default.factory.createBinaryExpression(typescript_1.default.factory.createPropertyAccessExpression(typescript_1.default.factory.createIdentifier(KEYNAME_EXPORTS), typescript_1.default.factory.createIdentifier(secondArgument.text)), typescript_1.default.SyntaxKind.EqualsToken, firstStatement.expression);
}
}
}
}
}
return typescript_1.default.visitEachChild(node, visit, this.context);
};
return typescript_1.default.visitNode(sourceFile, visit);
}
// Top level CommonJS to ESM
convertToEsmImport(sourceFile) {
const visit = (node) => {
// Import without name
if (typescript_1.default.isExpressionStatement(node) &&
typescript_1.default.isCallExpression(node.expression) &&
typescript_1.default.isIdentifier(node.expression.expression) &&
node.expression.expression.text === 'require' &&
node.expression.arguments.length === 1) {
const argument = node.expression.arguments[0];
if (typescript_1.default.isStringLiteralLike(argument)) {
return typescript_1.default.factory.createImportDeclaration(undefined, undefined, undefined, typescript_1.default.factory.createStringLiteral(argument.text));
}
}
// Import with reference
if (typescript_1.default.isVariableStatement(node) &&
typescript_1.default.isVariableDeclarationList(node.declarationList)) {
const importDeclarations = [];
const variableDeclarations = [];
for (const variableDeclaration of node.declarationList.declarations) {
if (variableDeclaration.initializer &&
typescript_1.default.isCallExpression(variableDeclaration.initializer) &&
typescript_1.default.isIdentifier(variableDeclaration.initializer.expression) &&
variableDeclaration.initializer.expression.text === 'require' &&
variableDeclaration.initializer.arguments.length === 1) {
const argument = variableDeclaration.initializer.arguments[0];
if (typescript_1.default.isStringLiteral(argument) &&
typescript_1.default.isIdentifier(variableDeclaration.name)) {
importDeclarations.push(typescript_1.default.factory.createImportDeclaration(undefined, undefined, typescript_1.default.factory.createImportClause(false, undefined, typescript_1.default.factory.createNamespaceImport(variableDeclaration.name)), argument));
}
else if (typescript_1.default.isStringLiteral(argument) &&
typescript_1.default.isObjectBindingPattern(variableDeclaration.name)) {
importDeclarations.push(typescript_1.default.factory.createImportDeclaration(undefined, undefined, typescript_1.default.factory.createImportClause(false, undefined, typescript_1.default.factory.createNamedImports(variableDeclaration.name.elements.map((bindingElement) => typescript_1.default.factory.createImportSpecifier(bindingElement.propertyName, bindingElement.name)))), typescript_1.default.factory.createStringLiteral(argument.text)));
}
}
else {
variableDeclarations.push(variableDeclaration);
}
}
if (variableDeclarations.length === 0) {
return importDeclarations;
}
else {
return [
...importDeclarations,
typescript_1.default.factory.updateVariableStatement(node, undefined, typescript_1.default.factory.updateVariableDeclarationList(node.declarationList, variableDeclarations)),
];
}
}
return node;
};
return typescript_1.default.visitEachChild(sourceFile, visit, this.context);
}
// Top level CommonJS to ESM
convertToEsmExport(sourceFile) {
const visit = (node) => {
if (typescript_1.default.isExpressionStatement(node) &&
typescript_1.default.isBinaryExpression(node.expression) &&
node.expression.operatorToken.kind === typescript_1.default.SyntaxKind.EqualsToken) {
// exports.something = something;
if (typescript_1.default.isPropertyAccessExpression(node.expression.left) &&
typescript_1.default.isIdentifier(node.expression.left.name) &&
typescript_1.default.isIdentifier(node.expression.left.expression) &&
node.expression.left.expression.text === KEYNAME_EXPORTS) {
// exports.default = something;
if (node.expression.left.name.text === 'default') {
return typescript_1.default.factory.createExportAssignment(undefined, undefined, undefined, node.expression.right);
}
// exports.something = anIdentifier;
else if (typescript_1.default.isIdentifier(node.expression.right)) {
return typescript_1.default.factory.createExportDeclaration(undefined, undefined, false, typescript_1.default.factory.createNamedExports([
typescript_1.default.factory.createExportSpecifier(node.expression.right.text === node.expression.left.name.text
? undefined
: node.expression.right, node.expression.left.name),
]));
}
else {
const newIdentifierName = this.generateUniqueName();
const variableStatement = typescript_1.default.factory.createVariableStatement(undefined, [
typescript_1.default.factory.createVariableDeclaration(newIdentifierName, undefined, undefined, node.expression.right),
]);
return [
variableStatement,
typescript_1.default.factory.createExportDeclaration(undefined, undefined, false, typescript_1.default.factory.createNamedExports([
typescript_1.default.factory.createExportSpecifier(typescript_1.default.factory.createIdentifier(newIdentifierName), node.expression.left.name),
])),
];
}
}
// exports = something;
if (typescript_1.default.isIdentifier(node.expression.left) &&
node.expression.left.text === KEYNAME_EXPORTS) {
// exports = { a: false, b: true }
if (typescript_1.default.isObjectLiteralExpression(node.expression.right)) {
const exportSpecifiers = [];
for (const property of node.expression.right.properties) {
if (typescript_1.default.isPropertyAssignment(property) &&
typescript_1.default.isIdentifier(property.name) &&
typescript_1.default.isIdentifier(property.initializer)) {
exportSpecifiers.push(typescript_1.default.factory.createExportSpecifier(property.initializer.text === property.name.text
? undefined
: property.initializer, property.name));
}
}
return typescript_1.default.factory.createExportDeclaration(undefined, undefined, false, typescript_1.default.factory.createNamedExports(exportSpecifiers));
}
// exports = require('hello.js');
else if (typescript_1.default.isCallExpression(node.expression.right) &&
typescript_1.default.isIdentifier(node.expression.right.expression) &&
node.expression.right.expression.text === 'require' &&
typescript_1.default.isStringLiteral(node.expression.right.arguments[0])) {
return typescript_1.default.factory.createExportDeclaration(undefined, undefined, false, undefined, node.expression.right.arguments[0]);
}
// exports = 'hello' or exports = Hello
else {
return typescript_1.default.factory.createExportAssignment(undefined, undefined, undefined, node.expression.right);
}
}
}
return node;
};
return typescript_1.default.visitEachChild(sourceFile, visit, this.context);
}
// module.exports -> exports
stripModule(sourceFile) {
const visit = (node) => {
if (typescript_1.default.isPropertyAccessExpression(node) &&
typescript_1.default.isIdentifier(node.expression) &&
typescript_1.default.isIdentifier(node.name) &&
node.expression.text === 'module' &&
node.name.text === KEYNAME_EXPORTS) {
return node.name;
}
return typescript_1.default.visitEachChild(node, visit, this.context);
};
return typescript_1.default.visitNode(sourceFile, visit);
}
// Move all require-calls to top-scope
requireTopScope(sourceFile) {
const newStatements = [];
const visit = (node) => {
const inRootScope = node?.parent?.parent?.parent?.parent &&
typescript_1.default.isVariableDeclaration(node.parent) &&
typescript_1.default.isVariableDeclarationList(node.parent.parent) &&
typescript_1.default.isVariableStatement(node.parent.parent.parent) &&
typescript_1.default.isSourceFile(node.parent.parent.parent.parent);
if (typescript_1.default.isCallExpression(node) &&
typescript_1.default.isIdentifier(node.expression) &&
node.arguments.length === 1 &&
node.expression.text === 'require' &&
inRootScope === false) {
const newIdentifierName = this.generateUniqueName();
newStatements.push(typescript_1.default.factory.createVariableStatement(undefined, [
typescript_1.default.factory.createVariableDeclaration(newIdentifierName, undefined, undefined, node),
]));
return typescript_1.default.factory.createIdentifier(newIdentifierName);
}
return typescript_1.default.visitEachChild(node, visit, this.context);
};
const changedSourceFile = typescript_1.default.visitNode(sourceFile, visit);
return typescript_1.default.factory.updateSourceFile(changedSourceFile, [
...newStatements,
...changedSourceFile.statements,
]);
}
}
exports.default = CommonJsTransformer;
//# sourceMappingURL=CommonJsTransformer.js.map
import TypeScript from 'typescript';
export default class ResolveTransformer implements TypeScript.CustomTransformer {
private context;
private moduleResolutionHost;
constructor(context: TypeScript.TransformationContext);
private resolveDependencyName;
private resolveDependencyPath;
transformSourceFile(sourceFile: TypeScript.SourceFile): TypeScript.SourceFile;
transformBundle(node: TypeScript.Bundle): TypeScript.Bundle;
private resolveStaticImport;
private resolveDynamicImport;
private visit;
transformSourceFile(node: TypeScript.SourceFile): TypeScript.SourceFile;
transformBundle(node: TypeScript.Bundle): TypeScript.Bundle;
}

@@ -7,58 +7,58 @@ "use strict";

const typescript_1 = __importDefault(require("typescript"));
const path_1 = __importDefault(require("path"));
/*
class ModuleResolutionHost implements TypeScript.ModuleResolutionHost {
fileExists(fileName: string): boolean
readFile(fileName: string): string | undefined
trace?(s: string): void
directoryExists?(directoryName: string): boolean
realpath?(path: string): string
getCurrentDirectory?(): string
getDirectories?(path: string): string[]
}
*/
const DependencyResolver_1 = __importDefault(require("./utils/DependencyResolver"));
class ResolveTransformer {
constructor(context) {
this.context = context;
this.moduleResolutionHost = typescript_1.default.createCompilerHost(this.context.getCompilerOptions());
}
// Return e.g. ./hello/module.js
resolveDependencyName(parentPath, dendencyName) {
const absolutePath = this.resolveDependencyPath(parentPath, dendencyName);
const pathObj = path_1.default.parse(absolutePath);
const relativeDir = path_1.default.relative(path_1.default.dirname(parentPath), pathObj.dir) || '.';
return relativeDir + '/' + pathObj.name + pathObj.ext;
transformSourceFile(sourceFile) {
const dynamicImportsResolved = this.resolveDynamicImport(sourceFile);
return this.resolveStaticImport(dynamicImportsResolved);
}
// Return an aboslute path e.g. /tmp/a-apath/node_modules/hello/module.js
resolveDependencyPath(parentPath, dendencyName) {
const resolveResults = typescript_1.default.resolveModuleName(dendencyName, parentPath, this.context.getCompilerOptions(), this.moduleResolutionHost);
if (resolveResults?.resolvedModule?.isExternalLibraryImport) {
const nodeResolve = require.resolve(dendencyName, {
paths: [path_1.default.dirname(parentPath)],
});
if (nodeResolve) {
// disable-eslint no-console
console.error(nodeResolve);
return nodeResolve;
transformBundle(node) {
return node;
}
resolveStaticImport(sourceFile) {
const visit = (node) => {
if ((typescript_1.default.isImportDeclaration(node) ||
typescript_1.default.isExportDeclaration(node)) &&
node.moduleSpecifier) {
return typescript_1.default.visitEachChild(node, visit, this.context);
}
}
const resolvedFileName = resolveResults?.resolvedModule?.resolvedFileName;
if (!resolvedFileName) {
throw new Error('Could not resolve' + dendencyName + 'from module' + parentPath);
}
return resolvedFileName;
if (typescript_1.default.isStringLiteral(node) &&
node.parent &&
(typescript_1.default.isExportDeclaration(node.parent) ||
typescript_1.default.isImportDeclaration(node.parent)) &&
node.parent.moduleSpecifier) {
return typescript_1.default.factory.createStringLiteral(new DependencyResolver_1.default(node.getSourceFile().fileName, this.context).resolveRelativeDependency(node.text));
}
return node;
};
return typescript_1.default.visitEachChild(sourceFile, visit, this.context);
}
resolveDynamicImport(sourceFile) {
const visit = (node) => {
if (node.parent &&
typescript_1.default.isCallExpression(node.parent) &&
node.parent.expression.kind === typescript_1.default.SyntaxKind.ImportKeyword &&
typescript_1.default.isStringLiteral(node) &&
node === node.parent.arguments[0]) {
return typescript_1.default.factory.createStringLiteral(new DependencyResolver_1.default(node.getSourceFile().fileName, this.context).resolveRelativeDependency(node.text));
}
return typescript_1.default.visitEachChild(node, visit, this.context);
};
return typescript_1.default.visitEachChild(sourceFile, visit, this.context);
}
visit(node) {
if (node.parent &&
typescript_1.default.isStringLiteral(node) &&
if ((typescript_1.default.isImportDeclaration(node) ||
typescript_1.default.isExportDeclaration(node)) &&
node.moduleSpecifier) {
return typescript_1.default.visitEachChild(node, this.visit.bind(this), this.context);
}
if (typescript_1.default.isStringLiteral(node) &&
node.parent &&
(typescript_1.default.isExportDeclaration(node.parent) ||
typescript_1.default.isImportDeclaration(node.parent))) {
return typescript_1.default.factory.createStringLiteral(this.resolveDependencyName(node.getSourceFile().fileName, node.text));
typescript_1.default.isImportDeclaration(node.parent)) &&
node.parent.moduleSpecifier) {
return typescript_1.default.factory.createStringLiteral(new DependencyResolver_1.default(node.getSourceFile().fileName, this.context).resolveRelativeDependency(node.text));
}
return typescript_1.default.visitEachChild(node, this.visit.bind(this), this.context);
}
transformSourceFile(node) {
return typescript_1.default.visitNode(node, this.visit.bind(this));
}
transformBundle(node) {
return node;

@@ -65,0 +65,0 @@ }

@@ -1,5 +0,5 @@

/// <reference types="node" />
import TypeScript from 'typescript';
export default class TsTranspiler {
transformCode(code: string, fileName: string): Promise<Buffer | string>;
transformFile(fileName: string): Promise<Buffer | string>;
transformCode(code: string, fileName: string): Promise<TypeScript.TranspileOutput>;
transformFile(fileName: string): Promise<TypeScript.TranspileOutput>;
}

@@ -10,2 +10,4 @@ "use strict";

const CommonJsTransformer_1 = __importDefault(require("./transformers/CommonJsTransformer"));
const NodeEnvTransformer_1 = __importDefault(require("./transformers/NodeEnvTransformer"));
const CodeOptimizerTransformer_1 = __importDefault(require("./transformers/CodeOptimizerTransformer"));
const compilerOptions = {

@@ -21,5 +23,5 @@ allowJs: true,

checkJs: false,
noResolve: false,
noResolve: true,
esModuleInterop: true,
skipLibCheck: true,
skipLibCheck: false,
target: typescript_1.default.ScriptTarget.ES2020,

@@ -32,2 +34,6 @@ declaration: false,

const transformers = {
before: [
(context) => new NodeEnvTransformer_1.default(context),
(context) => new CodeOptimizerTransformer_1.default(context),
],
after: [

@@ -40,10 +46,12 @@ (context) => new CommonJsTransformer_1.default(context),

async transformCode(code, fileName) {
const results = await typescript_1.default.transpileModule(code, {
const results = typescript_1.default.transpileModule(code, {
compilerOptions: compilerOptions,
fileName: fileName,
// reportDiagnostics: true,
// renamedDependencies: {},
reportDiagnostics: true,
transformers: transformers,
});
return results.outputText;
if (results.diagnostics?.length) {
console.log(results.diagnostics);
}
return results;
}

@@ -50,0 +58,0 @@ async transformFile(fileName) {

{
"name": "@ts-liveserver/ts-transpiler",
"version": "0.0.1",
"version": "0.0.2",
"main": "dist/index.js",

@@ -5,0 +5,0 @@ "scripts": {

import TypeScript from 'typescript'
const KEYNAME_EXPORTS = 'exports'
/*

@@ -9,100 +10,393 @@ Transpile CommonJS to ES6 module

private context: TypeScript.TransformationContext
private counter = 0
constructor(context: TypeScript.TransformationContext) {
this.context = context
}
private visit(node: TypeScript.Node) {
// Import
if (
TypeScript.isExpressionStatement(node) &&
TypeScript.isCallExpression(node.expression) &&
TypeScript.isIdentifier(node.expression.expression) &&
node.expression.expression.getText() === 'require' &&
node.expression.arguments.length === 1
) {
const argument = node.expression.arguments[0]
if (TypeScript.isStringLiteralLike(argument)) {
return TypeScript.factory.createImportDeclaration(
undefined,
undefined,
undefined,
TypeScript.factory.createStringLiteral(argument.text),
)
transformBundle(): TypeScript.Bundle {
throw new Error('Method not implemented.')
}
public transformSourceFile(
sourceFile: TypeScript.SourceFile,
): TypeScript.SourceFile {
const requireInTopScope = this.requireTopScope(sourceFile)
const withoutModule = this.stripModule(requireInTopScope)
const withoutDefineProperty = this.convertDefinePropery(withoutModule)
const esmExport = this.convertToEsmExport(withoutDefineProperty)
return this.convertToEsmImport(esmExport)
}
// Generate a file unique variable name
private generateUniqueName() {
this.counter++
return 'GENERATED_VAR_BY_TRANSFORMER_' + String(this.counter)
}
// Convert all Object.defineProperty(exports, "hello", Hello);"
private convertDefinePropery(
sourceFile: TypeScript.SourceFile,
): TypeScript.SourceFile {
const visit = (node: TypeScript.Node): TypeScript.Node => {
if (
TypeScript.isCallExpression(node) &&
TypeScript.isPropertyAccessExpression(node.expression) &&
TypeScript.isIdentifier(node.expression.expression) &&
TypeScript.isIdentifier(node.expression.name) &&
node.expression.expression.text === 'Object' &&
node.expression.name.text === 'defineProperty' &&
TypeScript.isIdentifier(node.arguments[0])
) {
const firstArgument = node.arguments[0]
const secondArgument = node.arguments[1]
const thirdArgument = node.arguments[2]
if (
TypeScript.isIdentifier(firstArgument) &&
firstArgument.text === KEYNAME_EXPORTS &&
TypeScript.isStringLiteral(secondArgument)
) {
if (TypeScript.isIdentifier(thirdArgument)) {
return TypeScript.factory.createBinaryExpression(
TypeScript.factory.createPropertyAccessExpression(
TypeScript.factory.createIdentifier(KEYNAME_EXPORTS),
TypeScript.factory.createIdentifier(secondArgument.text),
),
TypeScript.SyntaxKind.EqualsToken,
thirdArgument,
)
} else if (TypeScript.isObjectLiteralExpression(thirdArgument)) {
const propertyGetter = thirdArgument.properties
.filter((property) => TypeScript.isPropertyAssignment(property))
.find(
(property) =>
TypeScript.isPropertyAssignment(property) &&
TypeScript.isIdentifier(property.name) &&
property.name.text === 'get',
)
if (
propertyGetter &&
TypeScript.isPropertyAssignment(propertyGetter) &&
propertyGetter.initializer &&
TypeScript.isFunctionExpression(propertyGetter.initializer) &&
TypeScript.isBlock(propertyGetter.initializer.body)
) {
const firstStatement =
propertyGetter.initializer.body.statements[0]
if (
TypeScript.isReturnStatement(firstStatement) &&
firstStatement.expression
) {
return TypeScript.factory.createBinaryExpression(
TypeScript.factory.createPropertyAccessExpression(
TypeScript.factory.createIdentifier(KEYNAME_EXPORTS),
TypeScript.factory.createIdentifier(secondArgument.text),
),
TypeScript.SyntaxKind.EqualsToken,
firstStatement.expression,
)
}
}
}
}
}
return TypeScript.visitEachChild(node, visit, this.context)
}
// Default import
if (
TypeScript.isVariableStatement(node) &&
TypeScript.isVariableDeclarationList(node.declarationList) &&
node.declarationList.declarations.length === 1 &&
TypeScript.isVariableDeclaration(node.declarationList.declarations[0])
) {
const declaration = node.declarationList.declarations[0]
return TypeScript.visitNode(sourceFile, visit)
}
// Top level CommonJS to ESM
private convertToEsmImport(
sourceFile: TypeScript.SourceFile,
): TypeScript.SourceFile {
const visit = (
node: TypeScript.Node,
): TypeScript.Node | TypeScript.Node[] => {
// Import without name
if (
TypeScript.isVariableDeclaration(declaration) &&
declaration.initializer &&
TypeScript.isCallExpression(declaration.initializer) &&
TypeScript.isIdentifier(declaration.initializer.expression) &&
declaration.initializer.expression.getText() === 'require' &&
declaration.initializer.arguments.length === 1
TypeScript.isExpressionStatement(node) &&
TypeScript.isCallExpression(node.expression) &&
TypeScript.isIdentifier(node.expression.expression) &&
node.expression.expression.text === 'require' &&
node.expression.arguments.length === 1
) {
const argument = declaration.initializer.arguments[0]
const argument = node.expression.arguments[0]
if (TypeScript.isStringLiteralLike(argument)) {
if (TypeScript.isIdentifier(declaration.name)) {
return TypeScript.factory.createImportDeclaration(
return TypeScript.factory.createImportDeclaration(
undefined,
undefined,
undefined,
TypeScript.factory.createStringLiteral(argument.text),
)
}
}
// Import with reference
if (
TypeScript.isVariableStatement(node) &&
TypeScript.isVariableDeclarationList(node.declarationList)
) {
const importDeclarations: TypeScript.ImportDeclaration[] = []
const variableDeclarations: TypeScript.VariableDeclaration[] = []
for (const variableDeclaration of node.declarationList.declarations) {
if (
variableDeclaration.initializer &&
TypeScript.isCallExpression(variableDeclaration.initializer) &&
TypeScript.isIdentifier(
variableDeclaration.initializer.expression,
) &&
variableDeclaration.initializer.expression.text === 'require' &&
variableDeclaration.initializer.arguments.length === 1
) {
const argument = variableDeclaration.initializer.arguments[0]
if (
TypeScript.isStringLiteral(argument) &&
TypeScript.isIdentifier(variableDeclaration.name)
) {
importDeclarations.push(
TypeScript.factory.createImportDeclaration(
undefined,
undefined,
TypeScript.factory.createImportClause(
false,
undefined,
TypeScript.factory.createNamespaceImport(
variableDeclaration.name,
),
),
argument,
),
)
} else if (
TypeScript.isStringLiteral(argument) &&
TypeScript.isObjectBindingPattern(variableDeclaration.name)
) {
importDeclarations.push(
TypeScript.factory.createImportDeclaration(
undefined,
undefined,
TypeScript.factory.createImportClause(
false,
undefined,
TypeScript.factory.createNamedImports(
variableDeclaration.name.elements.map((bindingElement) =>
TypeScript.factory.createImportSpecifier(
bindingElement.propertyName as TypeScript.Identifier,
bindingElement.name as TypeScript.Identifier,
),
),
),
),
TypeScript.factory.createStringLiteral(argument.text),
),
)
}
} else {
variableDeclarations.push(variableDeclaration)
}
}
if (variableDeclarations.length === 0) {
return importDeclarations
} else {
return [
...importDeclarations,
TypeScript.factory.updateVariableStatement(
node,
undefined,
TypeScript.factory.updateVariableDeclarationList(
node.declarationList,
variableDeclarations,
),
),
]
}
}
return node
}
return TypeScript.visitEachChild(sourceFile, visit, this.context)
}
// Top level CommonJS to ESM
private convertToEsmExport(
sourceFile: TypeScript.SourceFile,
): TypeScript.SourceFile {
const visit = (
node: TypeScript.Node,
): TypeScript.Node | TypeScript.Node[] => {
if (
TypeScript.isExpressionStatement(node) &&
TypeScript.isBinaryExpression(node.expression) &&
node.expression.operatorToken.kind === TypeScript.SyntaxKind.EqualsToken
) {
// exports.something = something;
if (
TypeScript.isPropertyAccessExpression(node.expression.left) &&
TypeScript.isIdentifier(node.expression.left.name) &&
TypeScript.isIdentifier(node.expression.left.expression) &&
node.expression.left.expression.text === KEYNAME_EXPORTS
) {
// exports.default = something;
if (node.expression.left.name.text === 'default') {
return TypeScript.factory.createExportAssignment(
undefined,
TypeScript.factory.createImportClause(
false,
declaration.name,
undefined,
),
TypeScript.factory.createStringLiteral(argument.text),
undefined,
undefined,
node.expression.right,
)
} else if (TypeScript.isObjectBindingPattern(declaration.name)) {
return TypeScript.factory.createImportDeclaration(
}
// exports.something = anIdentifier;
else if (TypeScript.isIdentifier(node.expression.right)) {
return TypeScript.factory.createExportDeclaration(
undefined,
undefined,
TypeScript.factory.createImportClause(
false,
TypeScript.factory.createNamedExports([
TypeScript.factory.createExportSpecifier(
node.expression.right.text === node.expression.left.name.text
? undefined
: node.expression.right,
node.expression.left.name,
),
]),
)
} else {
const newIdentifierName = this.generateUniqueName()
const variableStatement = TypeScript.factory.createVariableStatement(
undefined,
[
TypeScript.factory.createVariableDeclaration(
newIdentifierName,
undefined,
undefined,
node.expression.right,
),
],
)
return [
variableStatement,
TypeScript.factory.createExportDeclaration(
undefined,
undefined,
false,
undefined,
TypeScript.factory.createNamedImports(
declaration.name.elements.map((bindingElement) =>
TypeScript.factory.createImportSpecifier(
bindingElement.propertyName as TypeScript.Identifier,
bindingElement.name as TypeScript.Identifier,
),
TypeScript.factory.createNamedExports([
TypeScript.factory.createExportSpecifier(
TypeScript.factory.createIdentifier(newIdentifierName),
node.expression.left.name,
),
),
]),
),
TypeScript.factory.createStringLiteral(argument.text),
]
}
}
// exports = something;
if (
TypeScript.isIdentifier(node.expression.left) &&
node.expression.left.text === KEYNAME_EXPORTS
) {
// exports = { a: false, b: true }
if (TypeScript.isObjectLiteralExpression(node.expression.right)) {
const exportSpecifiers: TypeScript.ExportSpecifier[] = []
for (const property of node.expression.right.properties) {
if (
TypeScript.isPropertyAssignment(property) &&
TypeScript.isIdentifier(property.name) &&
TypeScript.isIdentifier(property.initializer)
) {
exportSpecifiers.push(
TypeScript.factory.createExportSpecifier(
property.initializer.text === property.name.text
? undefined
: property.initializer,
property.name,
),
)
}
}
return TypeScript.factory.createExportDeclaration(
undefined,
undefined,
false,
TypeScript.factory.createNamedExports(exportSpecifiers),
)
}
// exports = require('hello.js');
else if (
TypeScript.isCallExpression(node.expression.right) &&
TypeScript.isIdentifier(node.expression.right.expression) &&
node.expression.right.expression.text === 'require' &&
TypeScript.isStringLiteral(node.expression.right.arguments[0])
) {
return TypeScript.factory.createExportDeclaration(
undefined,
undefined,
false,
undefined,
node.expression.right.arguments[0],
)
}
// exports = 'hello' or exports = Hello
else {
return TypeScript.factory.createExportAssignment(
undefined,
undefined,
undefined,
node.expression.right,
)
}
}
}
return node
}
// Default export
if (
TypeScript.isExpressionStatement(node) &&
TypeScript.isBinaryExpression(node.expression) &&
TypeScript.isPropertyAccessExpression(node.expression.left) &&
TypeScript.isIdentifier(node.expression.left.expression) &&
TypeScript.isIdentifier(node.expression.left.name) &&
node.expression.left.name.getText() === 'exports' &&
node.expression.left.expression.getText() === 'module'
) {
return TypeScript.factory.createExportAssignment(
undefined,
undefined,
undefined,
node.expression.right,
)
return TypeScript.visitEachChild(sourceFile, visit, this.context)
}
// module.exports -> exports
private stripModule(
sourceFile: TypeScript.SourceFile,
): TypeScript.SourceFile {
const visit = (node: TypeScript.Node): TypeScript.Node => {
if (
TypeScript.isPropertyAccessExpression(node) &&
TypeScript.isIdentifier(node.expression) &&
TypeScript.isIdentifier(node.name) &&
node.expression.text === 'module' &&
node.name.text === KEYNAME_EXPORTS
) {
return node.name
}
return TypeScript.visitEachChild(node, visit, this.context)
}
return node
return TypeScript.visitNode(sourceFile, visit)
}
transformSourceFile(node: TypeScript.SourceFile): TypeScript.SourceFile {
return TypeScript.visitEachChild(node, this.visit.bind(this), this.context)
// Move all require-calls to top-scope
private requireTopScope(
sourceFile: TypeScript.SourceFile,
): TypeScript.SourceFile {
const newStatements: TypeScript.VariableStatement[] = []
const visit = (node: TypeScript.Node): TypeScript.Node => {
const inRootScope =
node?.parent?.parent?.parent?.parent &&
TypeScript.isVariableDeclaration(node.parent) &&
TypeScript.isVariableDeclarationList(node.parent.parent) &&
TypeScript.isVariableStatement(node.parent.parent.parent) &&
TypeScript.isSourceFile(node.parent.parent.parent.parent)
if (
TypeScript.isCallExpression(node) &&
TypeScript.isIdentifier(node.expression) &&
node.arguments.length === 1 &&
node.expression.text === 'require' &&
inRootScope === false
) {
const newIdentifierName = this.generateUniqueName()
newStatements.push(
TypeScript.factory.createVariableStatement(undefined, [
TypeScript.factory.createVariableDeclaration(
newIdentifierName,
undefined,
undefined,
node,
),
]),
)
return TypeScript.factory.createIdentifier(newIdentifierName)
}
return TypeScript.visitEachChild(node, visit, this.context)
}
const changedSourceFile = TypeScript.visitNode(sourceFile, visit)
return TypeScript.factory.updateSourceFile(changedSourceFile, [
...newStatements,
...changedSourceFile.statements,
])
}
transformBundle(node: TypeScript.Bundle): TypeScript.Bundle {
return node
}
}
import TypeScript from 'typescript'
import Path from 'path'
/*
class ModuleResolutionHost implements TypeScript.ModuleResolutionHost {
fileExists(fileName: string): boolean
readFile(fileName: string): string | undefined
trace?(s: string): void
directoryExists?(directoryName: string): boolean
realpath?(path: string): string
getCurrentDirectory?(): string
getDirectories?(path: string): string[]
}
*/
import DependencyResolver from './utils/DependencyResolver'

@@ -18,68 +7,95 @@ export default class ResolveTransformer

private context: TypeScript.TransformationContext
private moduleResolutionHost: TypeScript.ModuleResolutionHost
constructor(context: TypeScript.TransformationContext) {
this.context = context
this.moduleResolutionHost = TypeScript.createCompilerHost(
this.context.getCompilerOptions(),
)
}
// Return e.g. ./hello/module.js
private resolveDependencyName(
parentPath: string,
dendencyName: string,
): string {
const absolutePath = this.resolveDependencyPath(parentPath, dendencyName)
const pathObj = Path.parse(absolutePath)
const relativeDir =
Path.relative(Path.dirname(parentPath), pathObj.dir) || '.'
return relativeDir + '/' + pathObj.name + pathObj.ext
public transformSourceFile(
sourceFile: TypeScript.SourceFile,
): TypeScript.SourceFile {
const dynamicImportsResolved = this.resolveDynamicImport(sourceFile)
return this.resolveStaticImport(dynamicImportsResolved)
}
// Return an aboslute path e.g. /tmp/a-apath/node_modules/hello/module.js
private resolveDependencyPath(
parentPath: string,
dendencyName: string,
): string {
const resolveResults = TypeScript.resolveModuleName(
dendencyName,
parentPath,
this.context.getCompilerOptions(),
this.moduleResolutionHost,
)
if (resolveResults?.resolvedModule?.isExternalLibraryImport) {
const nodeResolve = require.resolve(dendencyName, {
paths: [Path.dirname(parentPath)],
})
if (nodeResolve) {
// disable-eslint no-console
console.error(nodeResolve)
return nodeResolve
public transformBundle(node: TypeScript.Bundle): TypeScript.Bundle {
return node
}
private resolveStaticImport(
sourceFile: TypeScript.SourceFile,
): TypeScript.SourceFile {
const visit = (node: TypeScript.Node): TypeScript.Node => {
if (
(TypeScript.isImportDeclaration(node) ||
TypeScript.isExportDeclaration(node)) &&
node.moduleSpecifier
) {
return TypeScript.visitEachChild(node, visit, this.context)
}
if (
TypeScript.isStringLiteral(node) &&
node.parent &&
(TypeScript.isExportDeclaration(node.parent) ||
TypeScript.isImportDeclaration(node.parent)) &&
node.parent.moduleSpecifier
) {
return TypeScript.factory.createStringLiteral(
new DependencyResolver(
node.getSourceFile().fileName,
this.context,
).resolveRelativeDependency(node.text),
// this.resolveDependencyName(node.getSourceFile().fileName, node.text),
)
}
return node
}
const resolvedFileName = resolveResults?.resolvedModule?.resolvedFileName
if (!resolvedFileName) {
throw new Error(
'Could not resolve' + dendencyName + 'from module' + parentPath,
)
return TypeScript.visitEachChild(sourceFile, visit, this.context)
}
private resolveDynamicImport(
sourceFile: TypeScript.SourceFile,
): TypeScript.SourceFile {
const visit = (node: TypeScript.Node): TypeScript.Node => {
if (
node.parent &&
TypeScript.isCallExpression(node.parent) &&
node.parent.expression.kind === TypeScript.SyntaxKind.ImportKeyword &&
TypeScript.isStringLiteral(node) &&
node === node.parent.arguments[0]
) {
return TypeScript.factory.createStringLiteral(
new DependencyResolver(
node.getSourceFile().fileName,
this.context,
).resolveRelativeDependency(node.text),
)
}
return TypeScript.visitEachChild(node, visit, this.context)
}
return resolvedFileName
return TypeScript.visitEachChild(sourceFile, visit, this.context)
}
private visit(node: TypeScript.Node) {
if (
(TypeScript.isImportDeclaration(node) ||
TypeScript.isExportDeclaration(node)) &&
node.moduleSpecifier
) {
return TypeScript.visitEachChild(
node,
this.visit.bind(this),
this.context,
)
}
if (
TypeScript.isStringLiteral(node) &&
node.parent &&
TypeScript.isStringLiteral(node) &&
(TypeScript.isExportDeclaration(node.parent) ||
TypeScript.isImportDeclaration(node.parent))
TypeScript.isImportDeclaration(node.parent)) &&
node.parent.moduleSpecifier
) {
return TypeScript.factory.createStringLiteral(
this.resolveDependencyName(node.getSourceFile().fileName, node.text),
new DependencyResolver(
node.getSourceFile().fileName,
this.context,
).resolveRelativeDependency(node.text),
// this.resolveDependencyName(node.getSourceFile().fileName, node.text),
)
}
return TypeScript.visitEachChild(node, this.visit.bind(this), this.context)
}
transformSourceFile(node: TypeScript.SourceFile): TypeScript.SourceFile {
return TypeScript.visitNode(node, this.visit.bind(this))
}
transformBundle(node: TypeScript.Bundle): TypeScript.Bundle {
return node
}
}

@@ -5,2 +5,4 @@ import Fs from 'fs'

import CommonJsTransformer from './transformers/CommonJsTransformer'
import NodeEnvTransformer from './transformers/NodeEnvTransformer'
import CodeOptimizerTransformer from './transformers/CodeOptimizerTransformer'

@@ -17,5 +19,5 @@ const compilerOptions: TypeScript.CompilerOptions = {

checkJs: false,
noResolve: false,
noResolve: true,
esModuleInterop: true,
skipLibCheck: true,
skipLibCheck: false,
target: TypeScript.ScriptTarget.ES2020,

@@ -29,2 +31,6 @@ declaration: false,

const transformers: TypeScript.CustomTransformers = {
before: [
(context) => new NodeEnvTransformer(context),
(context) => new CodeOptimizerTransformer(context),
],
after: [

@@ -40,13 +46,15 @@ (context) => new CommonJsTransformer(context),

fileName: string,
): Promise<Buffer | string> {
const results = await TypeScript.transpileModule(code, {
): Promise<TypeScript.TranspileOutput> {
const results = TypeScript.transpileModule(code, {
compilerOptions: compilerOptions,
fileName: fileName,
// reportDiagnostics: true,
// renamedDependencies: {},
reportDiagnostics: true,
transformers: transformers,
})
return results.outputText
if (results.diagnostics?.length) {
console.log(results.diagnostics)
}
return results
}
async transformFile(fileName: string): Promise<Buffer | string> {
async transformFile(fileName: string): Promise<TypeScript.TranspileOutput> {
const buffer = await Fs.promises.readFile(fileName)

@@ -53,0 +61,0 @@ return this.transformCode(buffer.toString(), fileName)

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc