pax_global_header00006660000000000000000000000064140113434150014506gustar00rootroot0000000000000052 comment=ed68ba5cd8a71b45cb97cba7e83c8a7c7db3ef7e ascjs-5.0.1/000077500000000000000000000000001401134341500126145ustar00rootroot00000000000000ascjs-5.0.1/.gitignore000066400000000000000000000001011401134341500145740ustar00rootroot00000000000000.DS_Store .nyc_output/ coverage/ node_modules/ package-lock.json ascjs-5.0.1/.npmignore000066400000000000000000000001401401134341500146060ustar00rootroot00000000000000.nyc_output/* coverage/* node_modules/* test/* .gitignore .travis.yml test.js package-lock.json ascjs-5.0.1/.travis.yml000066400000000000000000000002251401134341500147240ustar00rootroot00000000000000language: node_js node_js: - stable git: depth: 1 branches: only: - master - /^greenkeeper/.*$/ after_success: - "npm run coveralls" ascjs-5.0.1/LICENSE.txt000066400000000000000000000013751401134341500144450ustar00rootroot00000000000000ISC License Copyright (c) 2017, Andrea Giammarchi, @WebReflection Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ascjs-5.0.1/README.md000066400000000000000000000073441401134341500141030ustar00rootroot00000000000000# ascjs [![License: ISC](https://img.shields.io/badge/License-ISC-yellow.svg)](https://opensource.org/licenses/ISC) [![Build Status](https://travis-ci.org/WebReflection/ascjs.svg?branch=master)](https://travis-ci.org/WebReflection/ascjs) [![Coverage Status](https://coveralls.io/repos/github/WebReflection/ascjs/badge.svg?branch=master)](https://coveralls.io/github/WebReflection/ascjs?branch=master) [![donate](https://img.shields.io/badge/$-donate-ff69b4.svg?maxAge=2592000&style=flat)](https://github.com/WebReflection/donate) [![Greenkeeper badge](https://badges.greenkeeper.io/WebReflection/ascjs.svg)](https://greenkeeper.io/) ES2015 to CommonJS import/export transformer - - - ### Looking for a CommonJS minimalistic bundler ? Fully based on _ascjs_, **[asbundle](https://github.com/WebReflection/asbundle)** is a no-brainer to create out of the box browser compatible bundles. Don't miss it out! - - - This module does one thing only: it loosely transpiles **ES2015** [import](https://developer.mozilla.org/en-US/docs/web/javascript/reference/statements/import)/[export](https://developer.mozilla.org/en-US/docs/web/javascript/reference/statements/export) statements **into** valid **CommonJS** in order to fix the only part of Node that's incompatible with modern JS. ## How to You can use _ascjs_ as binary utility or as module. ```sh npm install -g ascjs # to see what you can do ascjs --help ``` As executable, you can use _ascjs_ to output, or save, some code content. ```sh ascjs code ascjs --ignore=a.js,b.js sourceFile ascjs --no-default ascjs sourceFile ascjs sourceFile destFile # folders are recursively parsed # destFolder is mandatory ascjs sourceFolder destFolder ``` You can also use it via pipe operator. ```sh echo code | ascjs cat source.js | ascjs | uglifyjs -o dest.js ``` As module, you can require it and use it to convert ESM to CJS. ```js const ascjs = require('ascjs'); ascjs('import "test";'); // require("test"); ``` ### Features * extremely lightweight, based on [babylon](https://github.com/babel/babylon) for performance and reliability, it transforms only imports/exports ignoring everything else * produces modern JavaScript, you are in charge of extra transformations if needed * indentation, spaces, semi or no-semi are preserved: beautiful source code remains beautiful * uses same [Babel](http://babeljs.io) convention, resolving `export default ...` intent as `exports.default` * you can finally write `.js` code and transform it for Node only before publishing on _npm_ * you could write `.mjs` modules and transform them into CommonJS for [Browserify](http://browserify.org) or other bundlers as target ### Constrains * live bindings for exported values are not preserved. You need to delegate in scope eventual changes * dynamic `import(...)` is untouched. If you write that, let [Webpack](https://webpack.js.org) handle it for you later on * there is no magic whatsoever in module names resolution, what you write in ESM is what you get as CJS ### Flags * `--ignore=...` a comma separated paths to ignore parsing * `--no-default` remove the `__esModule` flag and export default via `module.exports = ` ### Example This module can transform the following ES2015+ code ```js import func, {a, b} from './module.js'; import * as tmp from 'other'; const val = 123; export default function test() { console.log('ascjs'); }; export {func, val}; ``` into the following one: ```js 'use strict'; const func = (m => m.__esModule ? m.default : m)(require('./module.js')); const {a, b} = require('./module.js'); const tmp = require('other'); const val = 123; function test() { console.log('ascjs'); } Object.defineProperty(exports, '__esModule', {value: true}).default = test; exports.func = func; exports.val = val; ```ascjs-5.0.1/bin.js000077500000000000000000000072721401134341500137350ustar00rootroot00000000000000#!/usr/bin/env node const path = require('path'); const $ascjs = require('./index.js'); const ascjs = input => { const output = $ascjs(input); return noDefault ? output.replace(`${$ascjs.EXPORT}.default`, 'module.exports') : output; }; const argv = process.argv.slice(2); const files = argv.filter(arg => /^[^-]/.test(arg)); const options = argv.filter(arg => /^-/.test(arg)); let noDefault = false; const ignore = []; options.forEach(arg => { if (/^--no-default$/.test(arg)) noDefault = true; else if (/^--ignore=/.test(arg)) ignore.push.apply( ignore, arg.slice(9).replace(/^('|")|('|")$/g, '').split(',') .map(file => path.resolve(__dirname, file)) ); }); const source = files[0]; if (files.length < 1 && options.length) { const info = require('./package.json'); console.log(` \x1B[1mascjs\x1B[0m v${info.version} ${'-'.repeat(info.description.length)} ${info.description} ${'-'.repeat(info.description.length)} # as executable ascjs code ascjs --ignore=a.js,b.js sourceFile ascjs --no-default ascjs sourceFile destFile ascjs sourceFolder destFolder # dest is required # as pipe echo code | ascjs cat sourceFile | ascjs ${'-'.repeat(info.description.length)} ${' '.repeat(info.description.length) .slice(0, -(3 + info.author.length))}by ${info.author} `); } else if (files.length) { const fs = require('fs'); const dest = files[1]; fs.stat(source, (err, stat) => { if (err) { process.stdout.write(ascjs(source)); } else if (stat.isFile()) { fs.readFile(source, (err, source) => { if (err) throw err; if (dest) fs.writeFileSync(dest, ascjs(source)); else process.stdout.write(ascjs(source)); }); } else if (stat.isDirectory() && dest && fs.statSync(dest).isDirectory()) { const cjsDest = path.resolve(process.cwd(), dest); process.on('exit', () => { const cjsPackage = path.join(cjsDest, 'package.json'); if (!fs.existsSync(cjsPackage)) fs.writeFileSync(cjsPackage, JSON.stringify({type: 'commonjs'})); }); const mkdir = dir => { try{ fs.mkdirSync(dir); } catch(e){ if(e.errno === 34){ mkdir(path.dirname(dir)); mkdir(dir); } } }; (function walkThrough(source, dest) { fs.readdir(source, (err, files) => { if (err) throw err; files.forEach(file => { if (ignore.includes(path.join(source, file))) return; fs.stat(path.join(source, file), (err, stat) => { if (err) throw err; switch (true) { case stat.isDirectory(): walkThrough(path.join(source, file), path.join(dest, file)); break; case stat.isFile(): if (/\.(?:m\.?)?js$/.test(file)) { fs.readFile(path.join(source, file), (err, content) => { if (err) throw err; mkdir(dest); fs.writeFile( path.join(dest, file), ascjs(content), (err) => { if (err) throw err; } ); }); } break; } }); }); }); }( path.resolve(process.cwd(), source), cjsDest )); } else { throw new Error('not sure what to do, try ascjs --help\n'); } }); } else { const chunks = []; process.stdin.on('data', data => { chunks.push(data); }); process.stdin.on('end', () => { process.stdout.write(ascjs(chunks.join(''))); }); } ascjs-5.0.1/index.js000066400000000000000000000135111401134341500142620ustar00rootroot00000000000000'use strict'; const parser = require('@babel/parser'); const defaultOptions = { allowAwaitOutsideFunction: true, sourceType: 'module', plugins: [ // 'estree', 'jsx', 'typescript', 'exportExtensions', 'exportDefaultFrom', 'exportNamespaceFrom', 'dynamicImport', 'importMeta', 'asyncGenerators', 'bigInt', 'classProperties', 'classPrivateProperties', 'classPrivateMethods', ['decorators', {decoratorsBeforeExport: true}], 'doExpressions', 'functionBind', 'functionSent', 'logicalAssignment', 'nullishCoalescingOperator', 'numericSeparator', 'objectRestSpread', 'optionalCatchBinding', 'optionalChaining', 'partialApplication', ['pipelineOperator', {proposal: 'minimal'}], 'throwExpressions', 'topLevelAwait' ] }; const EXPORT = `Object.defineProperty(exports, '__esModule', {value: true})`; const IMPORT = `(m => /* c8 ignore start */ m.__esModule ? m.default : m /* c8 ignore stop */)`; const asDefault = name => name === 'default' ? `${parse.info.EXPORT}.default` : `exports.${name}`; const fromDefault = defaultImport => `${parse.info.IMPORT}(${defaultImport})`; const slice = (code, info) => code.slice(info.start, info.end); const chunk = (info, esm, cjs) => ({ start: info.start, end: info.end, esm, cjs }); const replace = { ImportDeclaration(code, item) { const source = item.source; const name = withoutCDN(slice(code, source)); const esm = slice(code, item); const SEPS = /\{(\s+)/.test(esm) ? RegExp.$1 : ''; const SEPE = /(\s+)\}/.test(esm) ? RegExp.$1 : ''; const SEP = /(,\s+)[^{]/.test(esm) ? RegExp.$1 : ', '; const EOL = /;$/.test(esm) ? ';' : ''; const imported = []; const specifiers = []; let defaultImport = `require(${name})`; if (item.specifiers.length) { item.specifiers.forEach(specifier => { switch(specifier.type) { case 'ImportDefaultSpecifier': imported.push( `const ${specifier.local.name} = ${fromDefault(defaultImport)}${EOL}` ); break; case 'ImportNamespaceSpecifier': imported.push( `const ${specifier.local.name} = ${defaultImport}${EOL}` ); break; case 'ImportSpecifier': specifiers.push( specifier.local.name === specifier.imported.name ? specifier.local.name : `${specifier.imported.name}: ${specifier.local.name}` ); break; } }); if (specifiers.length) { imported.push( `const {${SEPS}${specifiers.join(SEP)}${SEPE}} = ${defaultImport}${EOL}` ); } } else { imported.push(`${defaultImport}${EOL}`); } return chunk(item, esm, imported.join('\n')); }, ExportAllDeclaration(code, item) { const source = item.source; const esm = slice(code, item); const cjs = `(m => Object.keys(m).map(k => k !== 'default' && (exports[k] = m[k])))\n(require(${ withoutCDN(slice(code, source)) }));`; return chunk(item, esm, cjs); }, ExportDefaultDeclaration(code, item) { const declaration = item.declaration; const esm = slice(code, item); let cjs; switch (declaration.type) { case 'AssignmentExpression': case 'FunctionDeclaration': if (declaration.id) { cjs = `${esm.replace(/^export\s+default\s+/, '')}\n${parse.info.EXPORT}.default = ${declaration.id.name}`; } else { cjs = esm.replace(/^export\s+default\s+/, `${parse.info.EXPORT}.default = `); } break; case 'Identifier': case 'ObjectExpression': default: cjs = esm.replace(/^export\s+default\s+/, `${parse.info.EXPORT}.default = `); break; } return chunk(item, esm, cjs); }, ExportNamedDeclaration(code, item) { const declaration = item.declaration; const source = item.source; const esm = slice(code, item); const EOL = /;$/.test(esm) ? ';\n' : '\n'; let cjs = source ? '(m => {\n' : ''; item.specifiers.forEach(specifier => { cjs += `${ source ? ' ' : '' }${asDefault(specifier.exported.name)} = ${ source ? 'm.' : '' }${specifier.local.name}${EOL}`; }); if (declaration) { cjs += esm.replace(/^export\s+/, '') + '\n'; (declaration.declarations || [declaration]).forEach(specifier => { cjs += `${asDefault(specifier.id.name)} = ${specifier.id.name}${EOL}`; }); } if (source) cjs += `})(require(${ withoutCDN(slice(code, source)) }));\n`; return chunk(item, esm, cjs.trim()); } }; const parse = (code, options) => { if (!options) options = {}; const parserOptions = Object.assign( {}, defaultOptions, options ); parse.info = { EXPORT: options.EXPORT || EXPORT, IMPORT: options.IMPORT || IMPORT }; delete options.EXPORT; delete options.IMPORT; code = code.toString(); const out = []; const chunks = []; const parsed = parser.parse(code, parserOptions); parsed.program.body.forEach(item => { if (replace.hasOwnProperty(item.type)) { chunks.push(replace[item.type](code, item)); } }); const length = chunks.length; let c = 0; for (let i = 0; i < length; i++) { out.push( code.slice(c, chunks[i].start), chunks[i].cjs ); c = chunks[i].end; } out.push(length ? code.slice(c) : code); let result = out.join('').replace( /\bimport\.meta\b/g, "({url: require('url').pathToFileURL(__filename).href})" ); return /^(?:#!|['"]use strict['"])/.test(result.trim()) ? result : ("'use strict';\n" + result); }; const withoutCDN = name => /^(['"`])https?:\/\/(?:unpkg\.com)\/([^@/]+)\S*?\1$/.test(name) ? `${RegExp.$1}${RegExp.$2}${RegExp.$1}` : name; parse.EXPORT = EXPORT; parse.IMPORT = IMPORT; module.exports = parse; ascjs-5.0.1/package.json000066400000000000000000000014271401134341500151060ustar00rootroot00000000000000{ "name": "ascjs", "version": "5.0.1", "description": "ES2015 to CommonJS import/export transformer", "bin": "bin.js", "main": "index.js", "scripts": { "coveralls": "nyc report --reporter=text-lcov | coveralls", "test": "nyc node test.js" }, "repository": { "type": "git", "url": "git+https://github.com/WebReflection/ascjs.git" }, "keywords": [ "cjs", "esm", "transpile", "convert", "safe", "module" ], "author": "Andrea Giammarchi", "license": "ISC", "bugs": { "url": "https://github.com/WebReflection/ascjs/issues" }, "homepage": "https://github.com/WebReflection/ascjs#readme", "dependencies": { "@babel/parser": "^7.12.5" }, "devDependencies": { "coveralls": "^3.1.0", "nyc": "^15.1.0" } } ascjs-5.0.1/test.js000066400000000000000000000130141401134341500141300ustar00rootroot00000000000000const ascjs = require('./index.js'); const bold = text => `\x1B[1m${text}\x1B[0m`; const tests = [ { esm: 'console.log(import.meta.url);', cjs: `console.log(({url: require('url').pathToFileURL(__filename).href}).url);` }, // nothing to do { esm: '', cjs: '' }, // exports { esm: `const name1 = 1, name2 = 2, nameN = 3; export { name1, name2, nameN }`, cjs: `const name1 = 1, name2 = 2, nameN = 3; exports.name1 = name1\nexports.name2 = name2\nexports.nameN = nameN` }, { esm: `export { name1, name2, nameN } from "module"`, cjs: `(m => {\n exports.name1 = m.name1\n exports.name2 = m.name2\n exports.nameN = m.nameN\n})(require("module"));` }, { esm: `const name0 = 0, name1 = 1; export { name0, name1 as default };`, cjs: `const name0 = 0, name1 = 1; exports.name0 = name0;\nObject.defineProperty(exports, '__esModule', {value: true}).default = name1;` }, { esm: `export { name0, name1 as default } from "shenanigans"`, cjs: `(m => {\n exports.name0 = m.name0\n Object.defineProperty(exports, '__esModule', {value: true}).default = m.name1\n})(require("shenanigans"));` }, { esm: `const variable1 = 1, variable2 = 2, nameN = 3; export { variable1 as name1, variable2 as name2, nameN };`, cjs: `const variable1 = 1, variable2 = 2, nameN = 3; exports.name1 = variable1;\nexports.name2 = variable2;\nexports.nameN = nameN;` }, { esm: `export let name1 = 1, name2 = function () {}, nameN = 'N';`, cjs: `let name1 = 1, name2 = function () {}, nameN = 'N';\nexports.name1 = name1;\nexports.name2 = name2;\nexports.nameN = nameN;` }, { esm: `export default function () {};`, cjs: `Object.defineProperty(exports, '__esModule', {value: true}).default = function () {};` }, { esm: `export default function named() {};`, cjs: `function named() {}\nObject.defineProperty(exports, '__esModule', {value: true}).default = named;` }, { esm: `export default sideEffect = true;`, cjs: `Object.defineProperty(exports, '__esModule', {value: true}).default = sideEffect = true;` }, { esm: `export const identifier = 123;`, cjs: `const identifier = 123;\nexports.identifier = identifier;` }, { esm: `const identifier = 123;\nexport {identifier};`, cjs: `const identifier = 123;\nexports.identifier = identifier;` }, { esm: `const identifier = 123;\nexport default identifier;`, cjs: `const identifier = 123;\nObject.defineProperty(exports, '__esModule', {value: true}).default = identifier;` }, { esm: `export * from "foo";`, cjs: `(m => Object.keys(m).map(k => k !== 'default' && (exports[k] = m[k])))\n(require("foo"));` }, // imports { esm: `import * as name from "module-name";`, cjs: `const name = require("module-name");` }, { esm: `import { name } from "module-name";`, cjs: `const { name } = require("module-name");` }, { esm: `import {name} from "module-name"`, cjs: `const {name} = require("module-name")` }, { esm: `import { name as alias } from "module-name";`, cjs: `const { name: alias } = require("module-name");` }, { esm: `import { export1 , export2 } from "module-name";`, cjs: `const { export1, export2 } = require("module-name");` }, { esm: `import { export1 , export2 as alias2 } from "module-name";`, cjs: `const { export1, export2: alias2 } = require("module-name");` }, { esm: `import defaultExport, { otherExport } from "module-name"`, cjs: `const defaultExport = (m => /* c8 ignore start */ m.__esModule ? m.default : m /* c8 ignore stop */)(require("module-name"))\nconst { otherExport } = require("module-name")` }, { esm: `import defaultExport, * as name from "module-name";`, cjs: `const defaultExport = (m => /* c8 ignore start */ m.__esModule ? m.default : m /* c8 ignore stop */)(require("module-name"));\nconst name = require("module-name");` }, { esm: `import "foo";`, cjs: `require("foo");` }, { esm: `import 'foo';`, cjs: `require('foo');` }, { esm: `import "foo"`, cjs: `require("foo")` }, { esm: `export function test() {}`, cjs: `function test() {}\nexports.test = test` }, { esm: `export default function () {}`, cjs: `Object.defineProperty(exports, '__esModule', {value: true}).default = function () {}` }, { esm: `export default function test() {};`, cjs: `function test() {}\nObject.defineProperty(exports, '__esModule', {value: true}).default = test;` }, { esm: `import "https://unpkg.com/hyperhtml@latest/min.js"`, cjs: `require("hyperhtml")` }, { esm: `export default {a: 1, b: 2};`, cjs: `Object.defineProperty(exports, '__esModule', {value: true}).default = {a: 1, b: 2};` }, { esm: `export default [1, 2, 3]`, cjs: `Object.defineProperty(exports, '__esModule', {value: true}).default = [1, 2, 3]` }, { esm: `'use strict';\nmodule.exports = 123;`, cjs: `module.exports = 123;` } ]; console.log(`${bold('ascjs')} v${require('./package.json').version} - ${tests.length} tests\n`); tests.forEach(code => { console.assert( ("'use strict';\n" + code.cjs) === ascjs(code.esm), `\n${bold('Source')}\n${code.esm}\n${bold('Expected')}\n${code.cjs}\n${bold('Received')}\n${ascjs(code.esm)}\n` ); }); console.log( ascjs( 'import I from "test";\nexport default function E() {}', {IMPORT: 'require.I', EXPORT: 'require.E(exports)'} ) === `'use strict';\nconst I = require.I(require("test"));\nfunction E() {}\nrequire.E(exports).default = E`, 'both import and export can be overwritten' );ascjs-5.0.1/test/000077500000000000000000000000001401134341500135735ustar00rootroot00000000000000ascjs-5.0.1/test/default.cjs000066400000000000000000000000431401134341500157150ustar00rootroot00000000000000'use strict'; module.exports = 123;ascjs-5.0.1/test/default.mjs000066400000000000000000000000231401134341500157250ustar00rootroot00000000000000export default 123;ascjs-5.0.1/test/dest/000077500000000000000000000000001401134341500145325ustar00rootroot00000000000000ascjs-5.0.1/test/dest/package.json000066400000000000000000000000231401134341500170130ustar00rootroot00000000000000{"type":"commonjs"}ascjs-5.0.1/test/dest/test.js000066400000000000000000000006331401134341500160510ustar00rootroot00000000000000'use strict'; const func = (m => m.__esModule ? m.default : m)(require('./module.js')); const {a, b} = require('./module.js'); const tmp = require('other'); console.log(({url: require('url').pathToFileURL(__filename).href}).url); const val = 123; function test() { console.log('ascjs'); } Object.defineProperty(exports, '__esModule', {value: true}).default = test; exports.func = func; exports.val = val; ascjs-5.0.1/test/source/000077500000000000000000000000001401134341500150735ustar00rootroot00000000000000ascjs-5.0.1/test/source/test.js000066400000000000000000000003111401134341500164030ustar00rootroot00000000000000import func, {a, b} from './module.js'; import * as tmp from 'other'; console.log(import.meta.url); const val = 123; export default function test() { console.log('ascjs'); }; export {func, val};