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

cjs-esm

Package Overview
Dependencies
Maintainers
1
Versions
12
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

cjs-esm - npm Package Compare versions

Comparing version 0.2.0 to 0.3.0

dist/generate-export.d.ts

31

dist/analyze.d.ts

@@ -1,6 +0,27 @@

import { Context } from './context';
export interface Analyze {
import { AcornNode } from './types';
export declare enum TopLevelType {
ExpressionStatement = "ExpressionStatement",
VariableDeclaration = "VariableDeclaration"
}
export declare function createAnalyze(context: Context): {
analyze: () => void;
};
export interface RequireStatement {
node: AcornNode;
ancestors: AcornNode[];
topLevelNode?: AcornNode & {
type: TopLevelType;
};
functionScope?: AcornNode;
}
export interface ExportsStatement {
node: AcornNode;
token: {
left: string;
right: string;
};
}
export interface Analyzed {
code: string;
ast: AcornNode;
require: RequireStatement[];
exports: ExportsStatement[];
}
export declare function analyzer(code: string): Analyzed;

191

dist/analyze.js
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.createAnalyze = void 0;
const acorn_walk_1 = require("acorn-walk");
function createAnalyze(context) {
return { analyze };
function analyze() {
acorn_walk_1.ancestor(context.ast, {
CallExpression(node, ancestors) {
if (node.callee.name === 'require') {
analyzeNode(node, ancestors /* 需要浅 copy */.slice(0));
}
},
});
}
function analyzeNode(_node, ancestors) {
let parentIndex;
for (let len = ancestors.length, i = len - 1; i >= 0; i--) {
// Reverse lookup of the first parent element
if (!['CallExpression', 'MemberExpression'].includes(ancestors[i].type)) {
parentIndex = i;
break;
}
exports.analyzer = exports.TopLevelType = void 0;
const acorn_1 = require("acorn");
// Top-level scope statement types
var TopLevelType;
(function (TopLevelType) {
// require('foo')
TopLevelType["ExpressionStatement"] = "ExpressionStatement";
// const foo = rquire('foo')
TopLevelType["VariableDeclaration"] = "VariableDeclaration";
// TODO: others top-level ...
})(TopLevelType = exports.TopLevelType || (exports.TopLevelType = {}));
function analyzer(code) {
const ast = (0, acorn_1.parse)(code, { ecmaVersion: 'latest' });
const analyzed = {
code,
ast,
require: [],
exports: [],
};
simpleWalk(ast, {
CallExpression(node, ancestors) {
if (node.callee.name !== 'require')
return;
analyzed.require.push({
node,
ancestors,
topLevelNode: findTopLevelScope(ancestors),
functionScope: findFunctionScope(ancestors),
});
},
AssignmentExpression(node, ancestors) {
if (node.left.type !== 'MemberExpression')
return;
if (!(node.left.object.type === 'Identifier' && ['module', 'exports'].includes(node.left.object.name)))
return;
analyzed.exports.push({
node,
token: {
left: node.left.object.name,
right: node.left.property.name,
},
});
},
});
return analyzed;
}
exports.analyzer = analyzer;
// ----------------------------------------------------------------------
function simpleWalk(ast, visitors, ancestors = []) {
var _a;
if (!ast)
return;
if (Array.isArray(ast)) {
for (const element of ast) {
simpleWalk(element, visitors, ancestors);
}
const parentNode = ancestors[parentIndex];
const requireNode = ancestors[parentIndex + 1];
const requireRecord = {
Statement: {
VariableDeclarator: null,
CallExpression: null,
},
ObjectExpression: null,
ArrayExpression: null,
};
const CallExpression = analyzeRequireCallExpression(requireNode, ancestors);
switch (parentNode.type) {
// An VariableDeclaration statement
case 'VariableDeclarator':
requireRecord.Statement = {
VariableDeclarator: analyzeVariableDeclarator(parentNode),
CallExpression,
};
break;
// An ObjectExpression Property
case 'Property':
requireRecord.ObjectExpression = {
Property: parentNode.key.name,
CallExpression,
};
break;
// An ArrayExpression element
case 'ArrayExpression':
requireRecord.ArrayExpression = {
Index: parentNode.elements.findIndex(elem => elem.start === requireNode.start),
CallExpression,
};
break;
// Just require statement
default:
requireRecord.Statement = {
VariableDeclarator: null,
CallExpression,
};
break;
}
context.requires.push(requireRecord);
}
function analyzeVariableDeclarator(node) {
const _node = node.id;
if (_node.type === 'Identifier') {
/* const acorn */
return {
type: _node.type,
node: _node,
name: _node.name,
};
else {
ancestors = ancestors.concat(ast);
for (const key of Object.keys(ast)) {
(typeof ast[key] === 'object' &&
simpleWalk(ast[key], visitors, ancestors));
}
if (_node.type === 'ObjectPattern') {
/* const { ancestor, simple } */
return {
type: _node.type,
node: _node,
names: _node.properties.map(property => property.key.name),
};
}
}
/**
* @todo 只考虑常量 require 参数,不考虑拼接、模板字符串 21-08-07
*/
function analyzeRequireCallExpression(requireNode, ancestors) {
if (requireNode.type === 'CallExpression') {
return {
type: requireNode.type,
node: requireNode,
ancestors,
// Require statement has only one argument
require: requireNode.arguments[0].value,
};
}
if (requireNode.type === 'MemberExpression') {
return {
type: requireNode.type,
node: requireNode,
ancestors,
property: requireNode.property.name,
// Require statement has only one argument
require: requireNode.object.arguments[0].value,
};
}
(_a = visitors[ast.type]) === null || _a === void 0 ? void 0 : _a.call(visitors, ast, ancestors);
}
simpleWalk.async = function simpleWalkAsync() { };
// The function node that wraps it will be returned
function findFunctionScope(ancestors) {
return ancestors.find(an => [
'FunctionDeclaration',
'ArrowFunctionExpression',
].includes(an.type));
}
// Will be return nearset ancestor node
function findTopLevelScope(ancestors) {
const ances = ancestors.map(an => an.type).join();
const arr = [...ancestors].reverse();
// TODO
// CallExpression,CallExpression | require('foo')()
// CallExpression,MemberExpression,CallExpression | require('foo').bar()
if (/Program,ExpressionStatement,(CallExpression,|MemberExpression,){0,}CallExpression$/.test(ances)) {
// require('foo')
// require('foo').bar
return arr.find(e => e.type === TopLevelType.ExpressionStatement);
}
if (/Program,VariableDeclaration,VariableDeclarator,(CallExpression,|MemberExpression,){0,}CallExpression$/.test(ances)) {
// const foo = require('foo')
// const bar = require('foo').bar
// const { foo, bar: baz } = require('foo')
return arr.find(e => e.type === TopLevelType.VariableDeclaration);
}
}
exports.createAnalyze = createAnalyze;

@@ -1,20 +0,6 @@

import { Context } from './context';
import { TransformExporttOptions, TransformImportOptions } from './transform';
export interface TransformeOptions {
/**
* @default false
*/
sourcemap?: boolean;
transformImport?: TransformImportOptions;
transformExport?: TransformExporttOptions;
import { SourceMap } from 'magic-string';
export interface Result {
code: string;
map?: SourceMap;
}
export interface Transformed {
code: string | null;
sourcemap: string | null;
context: Context;
}
export declare function transform(code: string, options?: TransformeOptions): Transformed;
declare const _default: {
transform: typeof transform;
};
export default _default;
export default function cjs2esm(code: string): Result;
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.transform = void 0;
const context_1 = require("./context");
const tslib_1 = require("tslib");
const magic_string_1 = tslib_1.__importDefault(require("magic-string"));
const utils_1 = require("./utils");
const analyze_1 = require("./analyze");
const transform_1 = require("./transform");
function transform(code, options = {}) {
try {
const context = context_1.createContext({ code });
analyze_1.createAnalyze(context).analyze();
transform_1.createTransform(context, {
transformImport: options.transformImport,
transformExport: options.transformExport,
}).transform();
return {
code: context.transformedCode,
sourcemap: context.sourcemap,
context,
};
const generate_import_1 = require("./generate-import");
const generate_export_1 = require("./generate-export");
function cjs2esm(code) {
var _a;
if (!(0, utils_1.isCommonjs)(code)) {
return { code };
}
catch (error) {
throw error;
const analyzed = (0, analyze_1.analyzer)(code);
const imports = (0, generate_import_1.generateImport)(analyzed);
const exportRuntime = (0, generate_export_1.generateExport)(analyzed);
const promotionImports = [];
const ms = new magic_string_1.default(code);
// Replace require statement
for (const impt of imports) {
const { node, topLevelNode, importee: imptee, declaration, importName, } = impt;
const importee = imptee + ';';
let importStatement;
if (topLevelNode) {
if (topLevelNode.type === analyze_1.TopLevelType.ExpressionStatement) {
importStatement = importee;
}
else if (topLevelNode.type === analyze_1.TopLevelType.VariableDeclaration) {
importStatement = declaration ? `${importee} ${declaration};` : importee;
}
}
else {
// TODO: Merge duplicated require id
// 🚧-①
promotionImports.push(importee);
importStatement = importName;
}
if (importStatement) {
const start = topLevelNode ? topLevelNode.start : node.start;
const end = topLevelNode ? topLevelNode.end : node.end;
ms.overwrite(start, end, importStatement);
}
}
if (promotionImports.length) {
ms.prepend(['/* import-promotion-S */', ...promotionImports, '/* import-promotion-E */'].join(' '));
}
// Replace exports statement
if (exportRuntime) {
if (exportRuntime.exportDefault) {
const { start } = exportRuntime.exportDefault.node;
ms.appendRight(start, `const ${exportRuntime.exportDefault.name} = `);
}
const polyfill = ['/* export-runtime-S */', exportRuntime.polyfill, '/* export-runtime-E */'].join(' ');
const _exports = [
'// --------- export-statement ---------',
(_a = exportRuntime.exportDefault) === null || _a === void 0 ? void 0 : _a.statement,
exportRuntime.exportMembers,
].filter(Boolean).join('\n');
ms.prepend(polyfill).append(_exports);
}
return {
code: ms.toString(),
map: ms.generateMap({ hires: true }),
};
}
exports.transform = transform;
exports.default = { transform }; // Compatible tsc transpileModule
exports.default = cjs2esm;

@@ -1,125 +0,2 @@

import acorn from 'acorn';
export declare type KV<V = unknown> = Record<string, V>;
export declare type AcornNode = acorn.Node & KV<any>;
export interface BaseNode {
type: string;
node: AcornNode;
}
export interface VariableDeclaratorNode extends BaseNode {
/** const acorn = require('acorn') */
name?: string;
/** const { ancestor, simple } = require('acorn-walk') */
names?: string[];
}
export interface CallExpressionNode extends BaseNode {
ancestors: AcornNode[];
require: string;
/** MemberExpression will have */
property?: string;
}
/**
* VariableDeclarator === null 代表只是 require 引入 (import 'xxxx')
*/
export interface RequireStatement {
VariableDeclarator: VariableDeclaratorNode | null;
CallExpression: CallExpressionNode | null;
}
/**
* 目前只考虑四种 require 情况 21-08-07
* 1. 作为赋值表达式 | Statement | const aconr = require('acorn')
* 2. 只有引入 | Statement | require('acorn')
* 3. 作为对象属性值 | ObjectExpression | const obj = { acorn: require('acorn') }
* 4. 作为数组成员 | ArrayExpression | const arr = [require('acorn')]
*/
export interface RequireRecord {
Statement: RequireStatement;
ObjectExpression: ObjectExpressionNode | null;
ArrayExpression: ArrayExpressionNode | null;
}
export interface ObjectExpressionNode {
Property: string;
CallExpression: CallExpressionNode;
}
export interface ArrayExpressionNode {
Index: number;
CallExpression: CallExpressionNode;
}
export interface ExportsRecord {
}
export declare type ImportName = string | Record</* (name as alias) */ string, string> | Record</* (* as name) */ '*', string>;
export interface ImportRecord {
/**
* const acornDefault = require('acorn').default
* const alias = require('acorn').parse
* const acorn = require('acorn')
*/
importName?: {
name: ImportName;
code: string;
Statement: RequireStatement;
};
/**
* const parse = require('acorn').parse
* const { ancestor, simple } = require('acorn-walk')
*/
importNames?: {
names: string[];
code: string;
Statement: RequireStatement;
};
/** require('acorn') */
importOnly?: {
code: string;
Statement: RequireStatement;
};
/** const { ancestor, simple } = require('acorn-walk').other */
importDeconstruct?: {
name: string;
deconstruct: string[];
codes: [
string,
string
];
Statement: RequireStatement;
};
/** const { ancestor, simple } = require('acorn-walk').default */
importDefaultDeconstruct?: {
/** 自定义模块名 */
name: string;
deconstruct: string[];
codes: [
string,
string
];
Statement: RequireStatement;
};
/** For ArrayExpression, ObjectExpression statement. */
importExpression?: {
/** 自定义模块名 */
name: Record<'*', string>;
code: string;
ArrayExpression: ArrayExpressionNode | null;
ObjectExpression: ObjectExpressionNode | null;
};
importDefaultExpression?: {
/** 自定义模块名 */
name: string;
code: string;
ArrayExpression: ArrayExpressionNode | null;
ObjectExpression: ObjectExpressionNode | null;
};
}
export interface CjsEsmRecord {
node: AcornNode;
require: string;
cjs: {
code: string;
};
importName?: ImportRecord['importName'];
importNames?: ImportRecord['importNames'];
importOnly?: ImportRecord['importOnly'];
importDeconstruct?: ImportRecord['importDeconstruct'];
importDefaultDeconstruct?: ImportRecord['importDefaultDeconstruct'];
importExpression?: ImportRecord['importExpression'];
importDefaultExpression?: ImportRecord['importDefaultExpression'];
}
import type { Node } from 'acorn';
export declare type AcornNode<T = any> = Node & Record<string, T>;
{
"name": "cjs-esm",
"version": "0.2.0",
"version": "0.3.0",
"description": "Another CommonJs transform ESModule lib.",
"main": "dist/index.js",
"repository": "https://github.com/caoxiemeihao/cjs-esm",
"repository": {
"type": "git",
"url": "https://github.com/caoxiemeihao/cjs-esm.git"
},
"author": "草鞋没号 <308487730@qq.com>",

@@ -11,11 +14,12 @@ "license": "MIT",

"build": "rm -rf dist && tsc",
"prepublish": "npm run build"
"prepublishOnly": "npm run build",
"test": "node test/index.js"
},
"dependencies": {
"acorn": "^8.4.1",
"acorn-walk": "^8.1.1"
"acorn": "^8.7.1",
"magic-string": "^0.26.1"
},
"devDependencies": {
"tslib": "^2.x",
"typescript": "^4.x"
"tslib": "^2.4.0",
"typescript": "^4.6.4"
},

@@ -25,5 +29,5 @@ "files": [

"package.json",
"tsconfig.json",
"package-lock.json",
"README.md"
]
}
# cjs-esm
Another CommonJs transform ESModule lib.
#### 21-08-07
- Release@0.1.0
* [x] transform `require` to `import`
* [ ] transform `exports` to `export`
[![NPM version](https://img.shields.io/npm/v/cjs-esm.svg?style=flat)](https://npmjs.org/package/cjs-esm)
[![NPM Downloads](https://img.shields.io/npm/dm/cjs-esm.svg?style=flat)](https://npmjs.org/package/cjs-esm)
English | [简体中文](https://github.com/caoxiemeihao/cjs-esm/blob/main/README.zh-CN.md)
## Usage
```js
import cjs2esm from 'cjs-esm'
// or
// const cjs2esm = require('cjs-esm').default
const { code, map } = cjs2esm(`const fs = require('fs')`)
```
## TODO
❌ Nested scope(function-scope)
❌ Dynamic require id
✅ require statement
```js
// Top-level scope
const foo = require('foo').default
import foo from 'foo';
const foo = require('foo')
import * as foo from 'foo';
const foo = require('foo').bar
import * as __CJS_import__0__ from 'foo'; const { bar: foo } = __CJS_import__0__;
// Non top-level scope
const foo = [{ bar: require('foo').bar }]
import * as __CJS_import__0__ from 'foo'; const foo = [{ bar: __CJS_import__0__.bar }]
```
✅ exports statement
```js
module.exports = fn() { };
const __CJS__export_default__ = module.exports = fn() { };
export { __CJS__export_default__ as default }
exports.foo = 'foo';
const __CJS__export_foo__ = (module.exports == null ? {} : module.exports).foo;
export { __CJS__export_foo__ as foo }
```
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