Skip to content

Commit a15d309

Browse files
authored
only include last reexport (#11)
1 parent 9a551db commit a15d309

File tree

6 files changed

+88
-42
lines changed

6 files changed

+88
-42
lines changed

README.md

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -109,7 +109,7 @@ EXPORT_STAR_LIB: `Object.keys(` IDENTIFIER$1 `).forEach(function (` IDENTIFIER$2
109109
```
110110

111111
* The returned export names are the matched `IDENTIFIER` and `IDENTIFIER_STRING` slots for all `EXPORTS_MEMBER`, `EXPORTS_DEFINE` and `EXPORTS_LITERAL` matches.
112-
* The reexport specifiers are taken to be the `STRING_LITERAL` slots of all `MODULE_EXPORTS_ASSIGN` as well as all _top-level_ `EXPORT_STAR` `REQUIRE` matches and `EXPORTS_ASSIGN` matches whose `IDENTIFIER` also matches the first `IDENTIFIER` in `EXPORT_STAR_LIB`.
112+
* The reexport specifiers are taken to be the `STRING_LITERAL` slot of the last `MODULE_EXPORTS_ASSIGN` as well as all _top-level_ `EXPORT_STAR` `REQUIRE` matches and `EXPORTS_ASSIGN` matches whose `IDENTIFIER` also matches the first `IDENTIFIER` in `EXPORT_STAR_LIB`.
113113

114114
### Parsing Examples
115115

@@ -180,16 +180,16 @@ module.exports = {
180180

181181
#### module.exports reexport assignment
182182

183-
Any `module.exports = require('mod')` assignment is detected as a reexport:
183+
Any `module.exports = require('mod')` assignment is detected as a reexport, but only the last one is returned:
184184

185185
```js
186-
// DETECTS REEXPORTS: a, b, c
186+
// DETECTS REEXPORTS: c
187187
module.exports = require('a');
188188
(module => module.exports = require('b'))(NOT_MODULE);
189189
if (false) module.exports = require('c');
190190
```
191191

192-
As a result, the total list of exports would be inferred as the union of all of these reexported modules, which can lead to possible over-classification.
192+
This is to avoid overclassification in Webpack bundles with externals which include `module.exports = require('external')` in their source for every external dependency.
193193

194194
#### Transpiler Re-exports
195195

include-wasm/cjs-module-lexer.h

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -123,8 +123,14 @@ void (*addExport)(const uint16_t*, const uint16_t*) = &_addExport;
123123
void (*addReexport)(const uint16_t*, const uint16_t*) = &_addReexport;
124124
bool parseCJS (uint16_t* source, uint32_t sourceLen, void (*addExport)(const uint16_t* start, const uint16_t* end), void (*addReexport)(const uint16_t* start, const uint16_t* end));
125125

126+
enum RequireType {
127+
Import,
128+
ExportAssign,
129+
ExportStar
130+
};
131+
126132
void tryBacktrackAddStarExportBinding (uint16_t* pos);
127-
bool tryParseRequire (bool directStarExport);
133+
bool tryParseRequire (enum RequireType requireType);
128134
void tryParseLiteralExports ();
129135
bool readExportsOrModuleDotExports (uint16_t ch);
130136
void tryParseModuleExportsDotAssign ();

include/cjs-module-lexer.h

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,8 +29,14 @@ void bail (uint32_t err);
2929

3030
bool parseCJS (uint16_t* source, uint32_t sourceLen, void (*addExport)(const uint16_t*, const uint16_t*), void (*addReexport)(const uint16_t*, const uint16_t*));
3131

32+
enum RequireType {
33+
Import,
34+
ExportAssign,
35+
ExportStar
36+
};
37+
3238
void tryBacktrackAddStarExportBinding (uint16_t* pos);
33-
bool tryParseRequire (bool directStarExport);
39+
bool tryParseRequire (enum RequireType requireType);
3440
void tryParseLiteralExports ();
3541
bool readExportsOrModuleDotExports (uint16_t ch);
3642
void tryParseModuleExportsDotAssign ();

lexer.js

Lines changed: 33 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ let openTokenDepth,
1010
nextBraceIsClass,
1111
starExportMap,
1212
lastStarExportSpecifier,
13+
lastExportsAssignSpecifier,
1314
_exports,
1415
reexports;
1516

@@ -25,11 +26,17 @@ function resetState () {
2526
nextBraceIsClass = false;
2627
starExportMap = Object.create(null);
2728
lastStarExportSpecifier = null;
29+
lastExportsAssignSpecifier = null;
2830

2931
_exports = new Set();
3032
reexports = new Set();
3133
}
3234

35+
// RequireType
36+
const Import = 0;
37+
const ExportAssign = 1;
38+
const ExportStar = 2;
39+
3340
const strictReserved = new Set(['implements', 'interface', 'let', 'package', 'private', 'protected', 'public', 'static', 'yield', 'enum']);
3441

3542
module.exports = function parseCJS (source, name = '@') {
@@ -42,6 +49,8 @@ module.exports = function parseCJS (source, name = '@') {
4249
e.loc = pos;
4350
throw e;
4451
}
52+
if (lastExportsAssignSpecifier)
53+
reexports.add(lastExportsAssignSpecifier);
4554
const result = { exports: [..._exports], reexports: [...reexports] };
4655
resetState();
4756
return result;
@@ -85,7 +94,7 @@ function parseSource (cjsSource) {
8594
continue;
8695
case 114/*r*/:
8796
const startPos = pos;
88-
if (tryParseRequire(false) && keywordStart(startPos))
97+
if (tryParseRequire(Import) && keywordStart(startPos))
8998
tryBacktrackAddStarExportBinding(startPos - 1);
9099
lastTokenPos = pos;
91100
continue;
@@ -97,7 +106,7 @@ function parseSource (cjsSource) {
97106
if (source.charCodeAt(pos) === 40/*(*/) {
98107
openTokenPosStack[openTokenDepth++] = lastTokenPos;
99108
if (source.charCodeAt(++pos) === 114/*r*/)
100-
tryParseRequire(true);
109+
tryParseRequire(ExportStar);
101110
}
102111
}
103112
lastTokenPos = pos;
@@ -623,14 +632,14 @@ function tryParseExportsDotAssign (assign) {
623632

624633
// require('...')
625634
if (ch === 114/*r*/)
626-
tryParseRequire(true);
635+
tryParseRequire(ExportAssign);
627636
}
628637
}
629638
}
630639
pos = revertPos;
631640
}
632641

633-
function tryParseRequire (directStarExport) {
642+
function tryParseRequire (requireType) {
634643
// require('...')
635644
if (source.startsWith('equire', pos + 1)) {
636645
pos += 7;
@@ -645,27 +654,35 @@ function tryParseRequire (directStarExport) {
645654
const reexportEnd = pos++;
646655
ch = commentWhitespace();
647656
if (ch === 41/*)*/) {
648-
if (directStarExport) {
649-
reexports.add(source.slice(reexportStart, reexportEnd));
650-
}
651-
else {
652-
lastStarExportSpecifier = source.slice(reexportStart, reexportEnd);
657+
switch (requireType) {
658+
case ExportAssign:
659+
lastExportsAssignSpecifier = source.slice(reexportStart, reexportEnd);
660+
return true;
661+
case ExportStar:
662+
reexports.add(source.slice(reexportStart, reexportEnd));
663+
return true;
664+
default:
665+
lastStarExportSpecifier = source.slice(reexportStart, reexportEnd);
666+
return true;
653667
}
654-
return true;
655668
}
656669
}
657670
else if (ch === 34/*"*/) {
658671
doubleQuoteString();
659672
const reexportEnd = pos++;
660673
ch = commentWhitespace();
661674
if (ch === 41/*)*/) {
662-
if (directStarExport) {
663-
reexports.add(source.slice(reexportStart, reexportEnd));
664-
}
665-
else {
666-
lastStarExportSpecifier = source.slice(reexportStart, reexportEnd);
675+
switch (requireType) {
676+
case ExportAssign:
677+
lastExportsAssignSpecifier = source.slice(reexportStart, reexportEnd);
678+
return true;
679+
case ExportStar:
680+
reexports.add(source.slice(reexportStart, reexportEnd));
681+
return true;
682+
default:
683+
lastStarExportSpecifier = source.slice(reexportStart, reexportEnd);
684+
return true;
667685
}
668-
return true;
669686
}
670687
}
671688
}

src/lexer.c

Lines changed: 35 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,8 @@ uint16_t* end;
2121
uint16_t* templateStack;
2222
uint16_t** openTokenPosStack;
2323
StarExportBinding* starExportStack;
24+
uint16_t* reexportAssignStart;
25+
uint16_t* reexportAssignEnd;
2426
bool nextBraceIsClass;
2527

2628
uint16_t* lastReexportStart;
@@ -62,6 +64,8 @@ bool parseCJS (uint16_t* _source, uint32_t _sourceLen, void (*_addExport)(const
6264
openTokenPosStack = &openTokenPosStack_[0];
6365
starExportStack = &starExportStack_[0];
6466
nextBraceIsClass = false;
67+
reexportAssignStart = NULL;
68+
reexportAssignEnd = NULL;
6569

6670
pos = (uint16_t*)(source - 1);
6771
uint16_t ch = '\0';
@@ -94,7 +98,7 @@ bool parseCJS (uint16_t* _source, uint32_t _sourceLen, void (*_addExport)(const
9498
continue;
9599
case 'r': {
96100
uint16_t* startPos = pos;
97-
if (tryParseRequire(false) && keywordStart(startPos))
101+
if (tryParseRequire(Import) && keywordStart(startPos))
98102
tryBacktrackAddStarExportBinding(startPos - 1);
99103
lastTokenPos = pos;
100104
continue;
@@ -107,7 +111,7 @@ bool parseCJS (uint16_t* _source, uint32_t _sourceLen, void (*_addExport)(const
107111
if (*pos == '(') {
108112
openTokenPosStack[openTokenDepth++] = lastTokenPos;
109113
if (*(++pos) == 'r')
110-
tryParseRequire(true);
114+
tryParseRequire(ExportStar);
111115
}
112116
}
113117
lastTokenPos = pos;
@@ -217,6 +221,9 @@ bool parseCJS (uint16_t* _source, uint32_t _sourceLen, void (*_addExport)(const
217221
if (templateDepth != UINT16_MAX || openTokenDepth || has_error)
218222
return false;
219223

224+
if (reexportAssignStart)
225+
addReexport(reexportAssignStart, reexportAssignEnd);
226+
220227
// success
221228
return true;
222229
}
@@ -647,14 +654,14 @@ void tryParseExportsDotAssign (bool assign) {
647654

648655
// require('...')
649656
if (ch == 'r')
650-
tryParseRequire(true);
657+
tryParseRequire(ExportAssign);
651658
}
652659
}
653660
}
654661
pos = revertPos;
655662
}
656663

657-
bool tryParseRequire (bool directStarExport) {
664+
bool tryParseRequire (enum RequireType requireType) {
658665
// require('...')
659666
if (str_eq6(pos + 1, 'e', 'q', 'u', 'i', 'r', 'e')) {
660667
pos += 7;
@@ -669,27 +676,38 @@ bool tryParseRequire (bool directStarExport) {
669676
uint16_t* reexportEnd = pos++;
670677
ch = commentWhitespace();
671678
if (ch == ')') {
672-
if (directStarExport) {
673-
addReexport(reexportStart, reexportEnd);
674-
}
675-
else {
676-
starExportStack->specifier_start = reexportStart;
677-
starExportStack->specifier_end = reexportEnd;
679+
switch (requireType) {
680+
case ExportStar:
681+
addReexport(reexportStart, reexportEnd);
682+
return true;
683+
case ExportAssign:
684+
reexportAssignStart = reexportStart;
685+
reexportAssignEnd = reexportEnd;
686+
return true;
687+
default:
688+
starExportStack->specifier_start = reexportStart;
689+
starExportStack->specifier_end = reexportEnd;
690+
return true;
678691
}
679-
return true;
680692
}
681693
}
682694
else if (ch == '"') {
683695
doubleQuoteString();
684696
uint16_t* reexportEnd = pos++;
685697
ch = commentWhitespace();
686698
if (ch == ')') {
687-
if (directStarExport) {
688-
addReexport(reexportStart, reexportEnd);
689-
}
690-
else {
691-
starExportStack->specifier_start = reexportStart;
692-
starExportStack->specifier_end = reexportEnd;
699+
switch (requireType) {
700+
case ExportStar:
701+
addReexport(reexportStart, reexportEnd);
702+
return true;
703+
case ExportAssign:
704+
reexportAssignStart = reexportStart;
705+
reexportAssignEnd = reexportEnd;
706+
return true;
707+
default:
708+
starExportStack->specifier_start = reexportStart;
709+
starExportStack->specifier_end = reexportEnd;
710+
return true;
693711
}
694712
return true;
695713
}

test/_unit.js

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -423,9 +423,8 @@ suite('Lexer', () => {
423423
`);
424424
assert.equal(exports.length, 1);
425425
assert.equal(exports[0], 'asdf');
426-
assert.equal(reexports.length, 2);
427-
assert.equal(reexports[0], './asdf');
428-
assert.equal(reexports[1], './another');
426+
assert.equal(reexports.length, 1);
427+
assert.equal(reexports[0], './another');
429428
});
430429

431430
test('Single parse cases', () => {

0 commit comments

Comments
 (0)