Skip to content

Commit

Permalink
Merge branch 'main' into fix/inline-constant-tag-transformation
Browse files Browse the repository at this point in the history
  • Loading branch information
pionxzh authored May 1, 2024
2 parents 2ac0130 + 8546f81 commit 9776239
Show file tree
Hide file tree
Showing 15 changed files with 251 additions and 56 deletions.
24 changes: 12 additions & 12 deletions packages/ast-utils/src/matchers/isIIFE.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,7 @@ import type { ASTNode, ASTPath, CallExpression, Collection, ExpressionStatement,
* ```js
* (() => { ... })(...)
* (function() { ... })(...)
* ```
*
* @example
* ```js
* !(() => { ... })(...)
* !function() { ... }(...)
* ```
*/
Expand All @@ -25,23 +22,20 @@ export function isStatementIIFE(j: JSCodeshift, node: Statement): node is Expres
* ```js
* (() => { ... })(...)
* (function() { ... })(...)
* ```
*
* @example
* ```js
* !(() => { ... })(...)
* !function() { ... }(...)
* ```
*/
export function isIIFE(j: JSCodeshift, node: ASTNode): node is ExpressionStatement {
if (j.UnaryExpression.check(node) && node.operator === '!') {
node = node.argument
}

if (j.CallExpression.check(node)) {
return j.FunctionExpression.check(node.callee)
|| j.ArrowFunctionExpression.check(node.callee)
}

if (j.UnaryExpression.check(node) && node.operator === '!') {
return j.FunctionExpression.check(node.argument)
}

return false
}

Expand Down Expand Up @@ -73,6 +67,12 @@ export function findIIFEs(
operator: '!',
argument: {
type: 'CallExpression',
callee: {
type: (type: string) => {
return type === 'FunctionExpression'
|| type === 'ArrowFunctionExpression'
},
},
},
},
})
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { defineInlineTest } from '@wakaru/test-utils'
import transform from '../un-import-rename'
import unOptionalChaining from '../un-optional-chaining'

const inlineTest = defineInlineTest(transform)

Expand Down Expand Up @@ -47,3 +48,20 @@ const foo_1 = 'local';
console.log(foo_2, bar_1, foo, bar, foo_1);
`,
)

defineInlineTest([transform, unOptionalChaining])('avoid crash when combined with scopes',
`
import { foo as a, bar as b, code } from '_';
console.log(a, b, code);
var _a;
(_a = a) === null || _a === void 0 ? void 0 : _a.b;
`, `
import { foo, bar, code } from '_';
console.log(foo, bar, code);
foo?.b;
`,
)
3 changes: 2 additions & 1 deletion packages/unminify/src/transformations/un-import-rename.ts
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,8 @@ export default createJSCodeshiftTransformationRule({

if (imported.name !== local.name) return

path.replace(j.importSpecifier(j.identifier(imported.name)))
const newIdent = j.identifier(imported.name)
path.replace(j.importSpecifier(newIdent, newIdent))
})
},
})
58 changes: 48 additions & 10 deletions packages/unpacker/__tests__/__snapshots__/webpack5.spec.ts.snap
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,15 @@ export default /* binding */ m1;
}
}
class A_A {
constructor() {
this.label = "a_a";
}
}
/***/
export { /* binding */ A };
export { /* binding */ A_A };
",
"id": "./src/a.js",
"isEntry": false,
Expand Down Expand Up @@ -62,29 +69,60 @@ export { /* binding */ getC };
"id": "./src/c.js",
"isEntry": false,
},
{
"code": "/* harmony import */ var _a_js__WEBPACK_IMPORTED_MODULE_0__ = require(/*! ./a.js */ "./src/a.js");
// re-export
/***/
export const A = /* reexport safe */ _a_js__WEBPACK_IMPORTED_MODULE_0__.A;
export const A_A = /* reexport safe */ _a_js__WEBPACK_IMPORTED_MODULE_0__.A_A;
",
"id": "./src/d.js",
"isEntry": false,
},
{
"code": "/* harmony import */ var _a_js__WEBPACK_IMPORTED_MODULE_0__ = require(/*! ./a.js */ "./src/a.js");
// partial re-export
/***/
export const A = /* reexport safe */ _a_js__WEBPACK_IMPORTED_MODULE_0__.A;
",
"id": "./src/e.js",
"isEntry": false,
},
{
"code": "/*!**********************!*\\
!*** ./src/index.js ***!
\\**********************/
__webpack_require__.r(__webpack_exports__);
/* harmony import */ var _a_js__WEBPACK_IMPORTED_MODULE_0__ =
/* harmony import */ var _1_js__WEBPACK_IMPORTED_MODULE_0__ =
__webpack_require__(/*! ./1.js */ "./src/1.js");
/* harmony import */ var _a_js__WEBPACK_IMPORTED_MODULE_1__ =
__webpack_require__(/*! ./a.js */ "./src/a.js");
/* harmony import */ var _b_js__WEBPACK_IMPORTED_MODULE_1__ =
/* harmony import */ var _b_js__WEBPACK_IMPORTED_MODULE_2__ =
__webpack_require__(/*! ./b.js */ "./src/b.js");
/* harmony import */ var _c_js__WEBPACK_IMPORTED_MODULE_2__ =
/* harmony import */ var _c_js__WEBPACK_IMPORTED_MODULE_3__ =
__webpack_require__(/*! ./c.js */ "./src/c.js");
/* harmony import */ var _1_js__WEBPACK_IMPORTED_MODULE_3__ =
__webpack_require__(/*! ./1.js */ "./src/1.js");
/* harmony import */ var _d_js__WEBPACK_IMPORTED_MODULE_4__ =
__webpack_require__(/*! ./d.js */ "./src/d.js");
/* harmony import */ var _e_js__WEBPACK_IMPORTED_MODULE_5__ =
__webpack_require__(/*! ./e.js */ "./src/e.js");
const d = new _d_js__WEBPACK_IMPORTED_MODULE_4__.A();
const e = new _e_js__WEBPACK_IMPORTED_MODULE_5__.A();
console.log(
_b_js__WEBPACK_IMPORTED_MODULE_1__.version,
_a_js__WEBPACK_IMPORTED_MODULE_0__.A
_b_js__WEBPACK_IMPORTED_MODULE_2__.version,
_a_js__WEBPACK_IMPORTED_MODULE_1__.A,
d,
e
);
(0, _b_js__WEBPACK_IMPORTED_MODULE_1__["default"])();
(0, _c_js__WEBPACK_IMPORTED_MODULE_2__.getC)().then(console.log);
(0, _b_js__WEBPACK_IMPORTED_MODULE_2__["default"])();
(0, _c_js__WEBPACK_IMPORTED_MODULE_3__.getC)().then(console.log);
// const M1 = await import('./1.js')
(0, _1_js__WEBPACK_IMPORTED_MODULE_3__["default"])();
(0, _1_js__WEBPACK_IMPORTED_MODULE_0__["default"])();
",
"id": "entry.js",
"isEntry": true,
Expand Down
2 changes: 1 addition & 1 deletion packages/unpacker/__tests__/webpack5.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ describe('Webpack 5', () => {

expect(result.moduleIdMapping).toMatchSnapshot()

expect(result.modules.length).toBe(5)
expect(result.modules.length).toBe(7)

const modules = result.modules.map(({ id, isEntry, code }) => ({ id, isEntry, code: format(code) }))
expect(modules).toMatchSnapshot()
Expand Down
15 changes: 9 additions & 6 deletions packages/unpacker/src/extractors/webpack/jsonp.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { renameFunctionParameters } from '@wakaru/ast-utils'
import { Module } from '../../Module'
import { convertRequireHelpersForWebpack4, convertRequireHelpersForWebpack5 } from './requireHelpers'
import type { ModuleMapping } from '@wakaru/ast-utils/types'
import type { ArrayExpression, Collection, FunctionExpression, JSCodeshift, MemberExpression, NumericLiteral, ObjectExpression, ObjectProperty, StringLiteral } from 'jscodeshift'
import type { ArrayExpression, ArrowFunctionExpression, BlockStatement, Collection, FunctionExpression, JSCodeshift, MemberExpression, NumericLiteral, ObjectExpression, ObjectProperty, StringLiteral } from 'jscodeshift'

/**
* Find the modules array in webpack jsonp chunk.
Expand Down Expand Up @@ -83,7 +83,9 @@ export function getModulesForWebpackJsonP(j: JSCodeshift, root: Collection):
return properties.every((property) => {
return j.ObjectProperty.check(property)
&& (j.StringLiteral.check(property.key) || j.NumericLiteral.check(property.key))
&& j.FunctionExpression.check(property.value)
&& (j.FunctionExpression.check(property.value)
|| (j.ArrowFunctionExpression.check(property.value) && j.BlockStatement.check(property.value.body))
)
})
},
},
Expand All @@ -99,12 +101,13 @@ export function getModulesForWebpackJsonP(j: JSCodeshift, root: Collection):
moreModules.properties.forEach((property) => {
const prop = property as ObjectProperty
const moduleId = (prop.key as StringLiteral | NumericLiteral).value
const functionExpression = prop.value as FunctionExpression
const functionExpression = prop.value as FunctionExpression | ArrowFunctionExpression
renameFunctionParameters(j, functionExpression, ['module', 'exports', 'require'])
const functionBody = functionExpression.body as BlockStatement

const program = j.program(functionExpression.body.body)
if (functionExpression.body.directives) {
program.directives = [...(program.directives || []), ...functionExpression.body.directives]
const program = j.program(functionBody.body)
if (functionBody.directives) {
program.directives = [...(program.directives || []), ...functionBody.directives]
}
const moduleContent = j(program)
convertRequireHelpersForWebpack4(j, moduleContent)
Expand Down
2 changes: 1 addition & 1 deletion packages/unpacker/src/extractors/webpack/requireHelpers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -178,7 +178,7 @@ export function convertExportsGetterForWebpack5(j: JSCodeshift, collection: Coll
exportValue = fn.body.body[0].argument
}

if (j.Identifier.check(fn.body)) {
if (j.Identifier.check(fn.body) || j.MemberExpression.check(fn.body)) {
exportValue = fn.body
}

Expand Down
12 changes: 8 additions & 4 deletions packages/unpacker/src/extractors/webpack/webpack5.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import { getTopLevelStatements } from '@wakaru/ast-utils/program'
import { Module } from '../../Module'
import { convertRequireHelpersForWebpack5 } from './requireHelpers'
import type { ModuleMapping } from '@wakaru/ast-utils/types'
import type { ArrowFunctionExpression, Collection, FunctionExpression, JSCodeshift, ObjectProperty, Statement, StringLiteral, VariableDeclaration } from 'jscodeshift'
import type { ArrowFunctionExpression, CallExpression, Collection, ExpressionStatement, FunctionExpression, JSCodeshift, ObjectProperty, Statement, StringLiteral, UnaryExpression, VariableDeclaration } from 'jscodeshift'

/**
* Find the modules map in webpack 5 bootstrap.
Expand Down Expand Up @@ -46,11 +46,15 @@ export function getModulesForWebpack5(j: JSCodeshift, root: Collection):
const moduleIdMapping: ModuleMapping = {}

const statements = getTopLevelStatements(root)
const webpackBootstrap = statements.find(node => isStatementIIFE(j, node))
const webpackBootstrap = statements.find(node => isStatementIIFE(j, node)) as ExpressionStatement | undefined
if (!webpackBootstrap) return null

// @ts-expect-error - skip type check
const statementsInBootstrap: Statement[] = webpackBootstrap.expression.callee.body.body
const expression = webpackBootstrap.expression as CallExpression | UnaryExpression
const callExpression = (j.CallExpression.check(expression) ? expression : expression.argument) as CallExpression
const callee = callExpression.callee as FunctionExpression | ArrowFunctionExpression
if (!j.BlockStatement.check(callee.body)) return null

const statementsInBootstrap: Statement[] = callee.body.body
const webpackModules = statementsInBootstrap.find((node) => {
if (node.type !== 'VariableDeclaration') return false

Expand Down
69 changes: 60 additions & 9 deletions testcases/webpack5/dist/index.js

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading

0 comments on commit 9776239

Please sign in to comment.