Skip to content

Commit 0895c5f

Browse files
Detect Babel reexports with conflict filter for other exports
1 parent 4543ca1 commit 0895c5f

File tree

7 files changed

+204
-8
lines changed

7 files changed

+204
-8
lines changed

README.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -111,6 +111,9 @@ EXPORT_STAR_LIB: `Object.keys(` IDENTIFIER$1 `).forEach(function (` IDENTIFIER$2
111111
`if (` IDENTIFIER$2 `===` ( `'default'` | `"default"` ) `||` IDENTIFIER$2 `===` ( '__esModule' | `"__esModule"` ) `) return` `;`? |
112112
`if (` IDENTIFIER$2 `!==` ( `'default'` | `"default"` ) `)`
113113
)
114+
(
115+
`if (Object.prototype.hasOwnProperty.call(` IDENTIFIER `, ` IDENTIFIER$2 `)) return` `;`?
116+
)?
114117
(
115118
`if (` IDENTIFIER$2 `in` EXPORTS_IDENTIFIER `&&` EXPORTS_IDENTIFIER `[` IDENTIFIER$2 `] ===` IDENTIFIER$1 `[` IDENTIFIER$2 `]) return` `;`?
116119
)?

demo.mjs

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
import { parse, init } from "./lexer.js";
2+
3+
await init();
4+
5+
const code = `
6+
"use strict";
7+
8+
exports.__esModule = true;
9+
var _exportNames = {
10+
named: true
11+
};
12+
exports.named = void 0;
13+
14+
var _reExport = require("./re-export");
15+
16+
Object.keys(_reExport).forEach(function (key) {
17+
if (key === "default" || key === "__esModule") return;
18+
if (Object.prototype.hasOwnProperty.call(_exportNames, key)) return;
19+
if (key in exports && exports[key] === _reExport[key]) return;
20+
exports[key] = _reExport[key];
21+
});
22+
var named;
23+
exports.named = named;
24+
`
25+
26+
console.log(parse(code));

include-wasm/cjs-module-lexer.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -213,6 +213,7 @@ bool str_eq4 (uint16_t* pos, uint16_t c1, uint16_t c2, uint16_t c3, uint16_t c4)
213213
bool str_eq5 (uint16_t* pos, uint16_t c1, uint16_t c2, uint16_t c3, uint16_t c4, uint16_t c5);
214214
bool str_eq6 (uint16_t* pos, uint16_t c1, uint16_t c2, uint16_t c3, uint16_t c4, uint16_t c5, uint16_t c6);
215215
bool str_eq7 (uint16_t* pos, uint16_t c1, uint16_t c2, uint16_t c3, uint16_t c4, uint16_t c5, uint16_t c6, uint16_t c7);
216+
bool str_eq8 (uint16_t* pos, uint16_t c1, uint16_t c2, uint16_t c3, uint16_t c4, uint16_t c5, uint16_t c6, uint16_t c7, uint16_t c8);
216217
bool str_eq9 (uint16_t* pos, uint16_t c1, uint16_t c2, uint16_t c3, uint16_t c4, uint16_t c5, uint16_t c6, uint16_t c7, uint16_t c8, uint16_t c9);
217218
bool str_eq10 (uint16_t* pos, uint16_t c1, uint16_t c2, uint16_t c3, uint16_t c4, uint16_t c5, uint16_t c6, uint16_t c7, uint16_t c8, uint16_t c9, uint16_t c10);
218219
bool str_eq13 (uint16_t* pos, uint16_t c1, uint16_t c2, uint16_t c3, uint16_t c4, uint16_t c5, uint16_t c6, uint16_t c7, uint16_t c8, uint16_t c9, uint16_t c10, uint16_t c11, uint16_t c12, uint16_t c13);

lexer.js

Lines changed: 67 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -489,6 +489,73 @@ function tryParseObjectDefineOrKeys (keys) {
489489
}
490490
else break;
491491

492+
// `if (Object.prototype.hasOwnProperty.call(` IDENTIFIER `, ` IDENTIFIER$2 `)) return` `;`?
493+
currentIfStatement: if (ch === 105/*i*/ && source.charCodeAt(pos + 1) === 102/*f*/) {
494+
let ifStartPos = pos;
495+
496+
pos += 2;
497+
ch = commentWhitespace();
498+
if (ch !== 40/*(*/) break;
499+
pos++;
500+
ch = commentWhitespace();
501+
if (ch !== 79/*O*/ || !source.startsWith('bject', pos + 1)) {
502+
// Revert parsing the current optional if statement, but don't bail
503+
// out since we can try parse the next possible if statement.
504+
pos = ifStartPos;
505+
ch = 105/*i*/;
506+
break currentIfStatement;
507+
}
508+
pos += 6;
509+
ch = commentWhitespace();
510+
if (ch !== 46/*.*/) {
511+
// Revert parsing the current optional if statement, but don't bail
512+
// out since we can try parse the next possible if statement.
513+
pos = ifStartPos;
514+
ch = 105/*i*/;
515+
break currentIfStatement;
516+
}
517+
pos++;
518+
ch = commentWhitespace();
519+
if (ch !== 112/*p*/ || !source.startsWith('rototype', pos + 1)) break;
520+
pos += 9;
521+
ch = commentWhitespace();
522+
if (ch !== 46/*.*/) break;
523+
pos++;
524+
ch = commentWhitespace();
525+
if (ch !== 104/*h*/ || !source.startsWith('asOwnProperty', pos + 1)) break;
526+
pos += 14;
527+
ch = commentWhitespace();
528+
if (ch !== 46/*.*/) break;
529+
pos++;
530+
ch = commentWhitespace();
531+
if (ch !== 99/*c*/ || !source.startsWith('all', pos + 1)) break;
532+
pos += 4;
533+
ch = commentWhitespace();
534+
if (ch !== 40/*(*/) break;
535+
pos++;
536+
ch = commentWhitespace();
537+
if (!identifier()) break;
538+
ch = commentWhitespace();
539+
if (ch !== 44/*,*/) break;
540+
pos++;
541+
ch = commentWhitespace();
542+
if (!source.startsWith(it_id, pos)) break;
543+
pos += it_id.length;
544+
ch = commentWhitespace();
545+
if (ch !== 41/*)*/) break;
546+
pos++;
547+
ch = commentWhitespace();
548+
if (ch !== 41/*)*/) break;
549+
pos++;
550+
ch = commentWhitespace();
551+
if (ch !== 114/*r*/ || !source.startsWith('eturn', pos + 1)) break;
552+
pos += 6;
553+
ch = commentWhitespace();
554+
if (ch === 59/*;*/)
555+
pos++;
556+
ch = commentWhitespace();
557+
}
558+
492559
// `if (` IDENTIFIER$2 `in` EXPORTS_IDENTIFIER `&&` EXPORTS_IDENTIFIER `[` IDENTIFIER$2 `] ===` IDENTIFIER$1 `[` IDENTIFIER$2 `]) return` `;`?
493560
if (ch === 105/*i*/ && source.charCodeAt(pos + 1) === 102/*f*/) {
494561
pos += 2;
@@ -1039,7 +1106,6 @@ function throwIfImportStatement () {
10391106
// import.meta
10401107
case 46/*.*/:
10411108
throw new Error('Unexpected import.meta in CJS module.');
1042-
return;
10431109

10441110
default:
10451111
// no space after "import" -> not an import keyword

lib/lexer.wasm

745 Bytes
Binary file not shown.

src/lexer.c

Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -508,6 +508,75 @@ void tryParseObjectDefineOrKeys (bool keys) {
508508
else break;
509509

510510

511+
// `if (Object.prototype.hasOwnProperty.call(` IDENTIFIER `, ` IDENTIFIER$2 `)) return` `;`?
512+
if (ch == 'i' && *(pos + 1) == 'f') {
513+
uint16_t *ifStartPos = pos;
514+
515+
pos += 2;
516+
ch = commentWhitespace();
517+
if (ch != '(') break;
518+
pos++;
519+
ch = commentWhitespace();
520+
if (ch != 'O' || !str_eq5(pos + 1, 'b', 'j', 'e', 'c', 't')) {
521+
// Revert parsing the current optional if statement, but don't bail
522+
// out since we can try parse the next possible if statement.
523+
pos = ifStartPos;
524+
ch = 'i';
525+
goto currentIfStatementEnd;
526+
}
527+
pos += 6;
528+
ch = commentWhitespace();
529+
if (ch != '.') {
530+
// Revert parsing the current optional if statement, but don't bail
531+
// out since we can try parse the next possible if statement.
532+
pos = ifStartPos;
533+
ch = 'i';
534+
goto currentIfStatementEnd;
535+
}
536+
pos++;
537+
ch = commentWhitespace();
538+
if (ch != 'p' || !str_eq8(pos + 1, 'r', 'o', 't', 'o', 't', 'y', 'p', 'e')) break;
539+
pos += 9;
540+
ch = commentWhitespace();
541+
if (ch != '.') break;
542+
pos++;
543+
ch = commentWhitespace();
544+
if (ch != 'h' || !str_eq13(pos + 1, 'a', 's', 'O', 'w', 'n', 'P', 'r', 'o', 'p', 'e', 'r', 't', 'y')) break;
545+
pos += 14;
546+
ch = commentWhitespace();
547+
if (ch != '.') break;
548+
pos++;
549+
ch = commentWhitespace();
550+
if (ch != 'c' || !str_eq3(pos + 1, 'a', 'l', 'l')) break;
551+
pos += 4;
552+
ch = commentWhitespace();
553+
if (ch != '(') break;
554+
pos++;
555+
ch = commentWhitespace();
556+
if (!identifier(ch)) break;
557+
ch = commentWhitespace();
558+
if (ch != ',') break;
559+
pos++;
560+
ch = commentWhitespace();
561+
if (memcmp(pos, it_id_start, it_id_len * sizeof(uint16_t)) != 0) break;
562+
pos += it_id_len;
563+
ch = commentWhitespace();
564+
if (ch != ')') break;
565+
pos++;
566+
ch = commentWhitespace();
567+
if (ch != ')') break;
568+
pos++;
569+
ch = commentWhitespace();
570+
if (ch != 'r' || !str_eq5(pos + 1, 'e', 't', 'u', 'r', 'n')) break;
571+
pos += 6;
572+
ch = commentWhitespace();
573+
if (ch == ';')
574+
pos++;
575+
ch = commentWhitespace();
576+
}
577+
currentIfStatementEnd:;
578+
579+
511580
// `if (` IDENTIFIER$2 `in` EXPORTS_IDENTIFIER `&&` EXPORTS_IDENTIFIER `[` IDENTIFIER$2 `] ===` IDENTIFIER$1 `[` IDENTIFIER$2 `]) return` `;`?
512581
if (ch == 'i' && *(pos + 1) == 'f') {
513582
pos += 2;
@@ -1257,6 +1326,10 @@ bool str_eq7 (uint16_t* pos, uint16_t c1, uint16_t c2, uint16_t c3, uint16_t c4,
12571326
return *pos == c1 && *(pos + 1) == c2 && *(pos + 2) == c3 && *(pos + 3) == c4 && *(pos + 4) == c5 && *(pos + 5) == c6 && *(pos + 6) == c7;
12581327
}
12591328

1329+
bool str_eq8 (uint16_t* pos, uint16_t c1, uint16_t c2, uint16_t c3, uint16_t c4, uint16_t c5, uint16_t c6, uint16_t c7, uint16_t c8) {
1330+
return *pos == c1 && *(pos + 1) == c2 && *(pos + 2) == c3 && *(pos + 3) == c4 && *(pos + 4) == c5 && *(pos + 5) == c6 && *(pos + 6) == c7 && *(pos + 7) == c8;
1331+
}
1332+
12601333
bool str_eq9 (uint16_t* pos, uint16_t c1, uint16_t c2, uint16_t c3, uint16_t c4, uint16_t c5, uint16_t c6, uint16_t c7, uint16_t c8, uint16_t c9) {
12611334
return *pos == c1 && *(pos + 1) == c2 && *(pos + 2) == c3 && *(pos + 3) == c4 && *(pos + 4) == c5 && *(pos + 5) == c6 && *(pos + 6) == c7 && *(pos + 7) == c8 && *(pos + 8) == c9;
12621335
}

test/_unit.js

Lines changed: 34 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -144,9 +144,19 @@ suite('Lexer', () => {
144144
exports[key] = _external001[key];
145145
});
146146
147+
var _external003 = require("external003");
148+
149+
// Babel >=7.12.0, loose mode, reexports conflicts filter
150+
Object.keys(_external003).forEach(function (key) {
151+
if (key === "default" || key === "__esModule") return;
152+
if (Object.prototype.hasOwnProperty.call(_exportNames, key)) return;
153+
if (key in exports && exports[key] === _external003[key]) return;
154+
exports[key] = _external003[key];
155+
});
156+
147157
var _external002 = require("external002");
148158
149-
// Babel >=7.12.0, loose mode
159+
// Babel >=7.12.0
150160
Object.keys(_external002).forEach(function (key) {
151161
if (key === "default" || key === "__esModule") return;
152162
if (key in exports && exports[key] === _external002[key]) return;
@@ -158,6 +168,21 @@ suite('Lexer', () => {
158168
});
159169
});
160170
171+
var _external004 = require("external004");
172+
173+
// Babel >=7.12.0, reexports conflict filter
174+
Object.keys(_external004).forEach(function (key) {
175+
if (key === "default" || key === "__esModule") return;
176+
if (Object.prototype.hasOwnProperty.call(_exportNames, key)) return;
177+
if (key in exports && exports[key] === _external004[key]) return;
178+
Object.defineProperty(exports, key, {
179+
enumerable: true,
180+
get: function () {
181+
return _external004[key];
182+
}
183+
});
184+
});
185+
161186
let external3 = require('external3');
162187
const external4 = require('external4');
163188
@@ -285,15 +310,17 @@ suite('Lexer', () => {
285310
`);
286311
assert.equal(exports.length, 1);
287312
assert.equal(exports[0], '__esModule');
288-
assert.equal(reexports.length, 8);
313+
assert.equal(reexports.length, 10);
289314
assert.equal(reexports[0], 'external');
290315
assert.equal(reexports[1], 'external2');
291316
assert.equal(reexports[2], 'external001');
292-
assert.equal(reexports[3], 'external002');
293-
assert.equal(reexports[4], 'external3');
294-
assert.equal(reexports[5], 'external4');
295-
assert.equal(reexports[6], 'external😃');
296-
assert.equal(reexports[7], 'external𤭢');
317+
assert.equal(reexports[3], 'external003');
318+
assert.equal(reexports[4], 'external002');
319+
assert.equal(reexports[5], 'external004');
320+
assert.equal(reexports[6], 'external3');
321+
assert.equal(reexports[7], 'external4');
322+
assert.equal(reexports[8], 'external😃');
323+
assert.equal(reexports[9], 'external𤭢');
297324
});
298325

299326
test('invalid exports cases', () => {

0 commit comments

Comments
 (0)