| FazBrowse GitHub Viewer | Trending | | Home |
| Tools: [Download Repo ZIP] [Original HTTPS Page] |
1 parent 8958af4 commit 20accb0
8 files changed
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -1,3 +1,7 @@ | |||
| 1 | + 0.5.0 | ||
| 2 | + - Breaking Change: No longer emit Object.defineProperty exports (https://github.com/guybedford/cjs-module-lexer/pull/24) | ||
| 3 | + - Doc: Update link to WASI SDK (https://github.com/guybedford/cjs-module-lexer/pull/19) | ||
| 4 | + | ||
| 1 | 5 | 0.4.3 | |
| 2 | 6 | - Support for Babel 7.12 reexports (https://github.com/guybedford/cjs-module-lexer/pull/16) | |
| 3 | 7 | - Support module.exports = { ...require('x') } reexports (https://github.com/guybedford/cjs-module-lexer/pull/18) | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -82,11 +82,13 @@ EXPORTS_LITERAL_COMPUTED_ASSIGN: EXPORTS_IDENTIFIER COMMENT_SPACE `[` COMMENT_SP | |||
| 82 | 82 | ||
| 83 | 83 | EXPORTS_LITERAL_PROP: (IDENTIFIER (COMMENT_SPACE `:` COMMENT_SPACE IDENTIFIER)?) | (IDENTIFIER_STRING COMMENT_SPACE `:` COMMENT_SPACE IDENTIFIER) | |
| 84 | 84 | ||
| 85 | + EXPORTS_SPREAD: `...` COMMENT_SPACE (IDENTIFIER | REQUIRE) | ||
| 86 | + | ||
| 85 | 87 | EXPORTS_MEMBER: EXPORTS_DOT_ASSIGN | EXPORTS_LITERAL_COMPUTED_ASSIGN | |
| 86 | 88 | ||
| 87 | - EXPORTS_DEFINE: `Object` COMMENT_SPACE `.` COMMENT_SPACE `defineProperty COMMENT_SPACE `(` EXPORTS_IDENTIFIER COMMENT_SPACE `,` COMMENT_SPACE IDENTIFIER_STRING | ||
| 89 | + ES_MODULE_DEFINE: `Object` COMMENT_SPACE `.` COMMENT_SPACE `defineProperty COMMENT_SPACE `(` COMMENT_SPACE `__esModule` COMMENT_SPACE `,` COMMENT_SPACE IDENTIFIER_STRING | ||
| 88 | 90 | ||
| 89 | - EXPORTS_LITERAL: MODULE_EXPORTS COMMENT_SPACE `=` COMMENT_SPACE `{` COMMENT_SPACE (EXPORTS_LITERAL_PROP COMMENT_SPACE `,` COMMENT_SPACE)+ `}` | ||
| 91 | + EXPORTS_LITERAL: MODULE_EXPORTS COMMENT_SPACE `=` COMMENT_SPACE `{` COMMENT_SPACE (EXPORTS_LITERAL_PROP | EXPORTS_SPREAD) COMMENT_SPACE `,` COMMENT_SPACE)+ `}` | ||
| 90 | 92 | ||
| 91 | 93 | REQUIRE: `require` COMMENT_SPACE `(` COMMENT_SPACE STRING_LITERAL COMMENT_SPACE `)` | |
| 92 | 94 | ||
@@ -101,15 +103,22 @@ EXPORT_STAR_LIB: `Object.keys(` IDENTIFIER$1 `).forEach(function (` IDENTIFIER$2 | |||
| 101 | 103 | `if (` IDENTIFIER$2 `===` ( `'default'` | `"default"` ) `||` IDENTIFIER$2 `===` ( '__esModule' | `"__esModule"` ) `) return` `;`? | | |
| 102 | 104 | `if (` IDENTIFIER$2 `!==` ( `'default'` | `"default"` ) `)` | |
| 103 | 105 | ) | |
| 106 | + ( | ||
| 107 | + `if (` IDENTIFIER$2 `in` EXPORTS_IDENTIFIER `&&` EXPORTS_IDENTIFIER `[` IDENTIFIER$2 `] ===` IDENTIFIER$1 `[` IDENTIFIER$2 `]) return` `;`? | ||
| 108 | + )? | ||
| 104 | 109 | ( | |
| 105 | 110 | EXPORTS_IDENTIFIER `[` IDENTIFIER$2 `] =` IDENTIFIER$1 `[` IDENTIFIER$2 `]` `;`? | | |
| 106 | 111 | `Object.defineProperty(` EXPORTS_IDENTIFIER `, ` IDENTIFIER$2 `, { enumerable: true, get: function () { return ` IDENTIFIER$1 `[` IDENTIFIER$2 `]` `;`? } })` `;`? | |
| 107 | 112 | ) | |
| 108 | 113 | `})` | |
| 109 | 114 | ``` | |
| 110 | 115 | ||
| 111 | - * 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`. | ||
| 116 | + * The returned export names are taken to be the combination of: | ||
| 117 | + 1. `IDENTIFIER` and `IDENTIFIER_STRING` slots for all `EXPORTS_MEMBER` and `EXPORTS_LITERAL` matches. | ||
| 118 | + 2. `__esModule` if there is an `ES_MODULE_DEFINE` match. | ||
| 119 | + * The reexport specifiers are taken to be the the combination of: | ||
| 120 | + 1. The `REQUIRE` matches of the last matched of either `MODULE_EXPORTS_ASSIGN` or `EXPORTS_LITERAL`. | ||
| 121 | + 2. All _top-level_ `EXPORT_STAR` `REQUIRE` matches and `EXPORTS_ASSIGN` matches whose `IDENTIFIER` also matches the first `IDENTIFIER` in `EXPORT_STAR_LIB`. | ||
| 113 | 122 | ||
| 114 | 123 | ### Parsing Examples | |
| 115 | 124 | ||
@@ -118,11 +127,10 @@ EXPORT_STAR_LIB: `Object.keys(` IDENTIFIER$1 `).forEach(function (` IDENTIFIER$2 | |||
| 118 | 127 | The basic matching rules for named exports are `exports.name`, `exports['name']` or `Object.defineProperty(exports, 'name', ...)`. This matching is done without scope analysis and regardless of the expression position: | |
| 119 | 128 | ||
| 120 | 129 | ```js | |
| 121 | - // DETECTS EXPORTS: a, b, c | ||
| 130 | + // DETECTS EXPORTS: a, b | ||
| 122 | 131 | (function (exports) { | |
| 123 | 132 | exports.a = 'a'; | |
| 124 | 133 | exports['b'] = 'b'; | |
| 125 | - Object.defineProperty(exports, 'c', { value: 'c' }); | ||
| 126 | 134 | })(exports); | |
| 127 | 135 | ``` | |
| 128 | 136 | ||
@@ -134,21 +142,32 @@ Because there is no scope analysis, the above detection may overclassify: | |||
| 134 | 142 | exports.a = 'a'; | |
| 135 | 143 | exports['b'] = 'b'; | |
| 136 | 144 | if (false) | |
| 137 | - Object.defineProperty(exports, 'c', { value: 'c' }); | ||
| 145 | + exports.c = 'c'; | ||
| 138 | 146 | })(NOT_EXPORTS, NOT_OBJECT); | |
| 139 | 147 | ``` | |
| 140 | 148 | ||
| 141 | 149 | It will in turn underclassify in cases where the identifiers are renamed: | |
| 142 | 150 | ||
| 143 | 151 | ```js | |
| 144 | 152 | // DETECTS: NO EXPORTS | |
| 145 | - (function (e, defineProperty) { | ||
| 153 | + (function (e) { | ||
| 146 | 154 | e.a = 'a'; | |
| 147 | 155 | e['b'] = 'b'; | |
| 148 | - defineProperty(e, 'c', { value: 'c' }); | ||
| 149 | - })(exports, defineProperty); | ||
| 156 | + })(exports); | ||
| 157 | + ``` | ||
| 158 | + | ||
| 159 | + #### __esModule Detection | ||
| 160 | + | ||
| 161 | + In addition, `__esModule` is detected as an export when set by `Object.defineProperty`: | ||
| 162 | + | ||
| 163 | + ```js | ||
| 164 | + // DETECTS: __esModule | ||
| 165 | + Object.defineProperty(exports, 'a', { value: 'a' }); | ||
| 166 | + Object.defineProperty(exports, '__esModule', { value: true }); | ||
| 150 | 167 | ``` | |
| 151 | 168 | ||
| 169 | + No other named exports are detected for `defineProperty` calls in order not to trigger getters or non-enumerable properties unnecessarily. | ||
| 170 | + | ||
| 152 | 171 | #### Exports Object Assignment | |
| 153 | 172 | ||
| 154 | 173 | A best-effort is made to detect `module.exports` object assignments, but because this is not a full parser, arbitrary expressions are not handled in the | |
@@ -160,17 +179,19 @@ Simple object definitions are supported: | |||
| 160 | 179 | // DETECTS EXPORTS: a, b, c | |
| 161 | 180 | module.exports = { | |
| 162 | 181 | a, | |
| 163 | - b: 'c', | ||
| 164 | - c: c | ||
| 182 | + 'b': b, | ||
| 183 | + c: c, | ||
| 184 | + ...d | ||
| 165 | 185 | }; | |
| 166 | 186 | ``` | |
| 167 | 187 | ||
| 168 | - Object properties that are not identifiers or string expressions will bail out of the object detection: | ||
| 188 | + Object properties that are not identifiers or string expressions will bail out of the object detection, while spreads are ignored: | ||
| 169 | 189 | ||
| 170 | 190 | ```js | |
| 171 | 191 | // DETECTS EXPORTS: a, b | |
| 172 | 192 | module.exports = { | |
| 173 | 193 | a, | |
| 194 | + ...d, | ||
| 174 | 195 | b: require('c'), | |
| 175 | 196 | c: "not detected since require('c') above bails the object detection" | |
| 176 | 197 | } | |
@@ -180,16 +201,27 @@ module.exports = { | |||
| 180 | 201 | ||
| 181 | 202 | #### module.exports reexport assignment | |
| 182 | 203 | ||
| 183 | - Any `module.exports = require('mod')` assignment is detected as a reexport: | ||
| 204 | + Any `module.exports = require('mod')` assignment is detected as a reexport, but only the last one is returned: | ||
| 184 | 205 | ||
| 185 | 206 | ```js | |
| 186 | - // DETECTS REEXPORTS: a, b, c | ||
| 207 | + // DETECTS REEXPORTS: c | ||
| 187 | 208 | module.exports = require('a'); | |
| 188 | 209 | (module => module.exports = require('b'))(NOT_MODULE); | |
| 189 | 210 | if (false) module.exports = require('c'); | |
| 190 | 211 | ``` | |
| 191 | 212 | ||
| 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. | ||
| 213 | + This is to avoid over-classification in Webpack bundles with externals which include `module.exports = require('external')` in their source for every external dependency. | ||
| 214 | + | ||
| 215 | + In exports object assignment, any spread of `require()` are detected as multiple separate reexports: | ||
| 216 | + | ||
| 217 | + ```js | ||
| 218 | + // DETECTS REEXPORTS: a, b | ||
| 219 | + module.exports = require('ignored'); | ||
| 220 | + module.exports = { | ||
| 221 | + ...require('a'), | ||
| 222 | + ...require('b') | ||
| 223 | + }; | ||
| 224 | + ``` | ||
| 193 | 225 | ||
| 194 | 226 | #### Transpiler Re-exports | |
| 195 | 227 | ||
@@ -249,71 +281,72 @@ Current results: | |||
| 249 | 281 | JS Build: | |
| 250 | 282 | ||
| 251 | 283 | ``` | |
| 284 | + --- JS Build --- | ||
| 252 | 285 | Module load time | |
| 253 | 286 | > 2ms | |
| 254 | 287 | Cold Run, All Samples | |
| 255 | 288 | test/samples/*.js (3635 KiB) | |
| 256 | - > 333ms | ||
| 289 | + > 311ms | ||
| 257 | 290 | ||
| 258 | 291 | Warm Runs (average of 25 runs) | |
| 259 | 292 | test/samples/angular.js (1410 KiB) | |
| 260 | - > 16.48ms | ||
| 293 | + > 14.76ms | ||
| 261 | 294 | test/samples/angular.min.js (303 KiB) | |
| 262 | - > 5.36ms | ||
| 295 | + > 5.04ms | ||
| 263 | 296 | test/samples/d3.js (553 KiB) | |
| 264 | - > 8.32ms | ||
| 297 | + > 7.12ms | ||
| 265 | 298 | test/samples/d3.min.js (250 KiB) | |
| 266 | - > 4.28ms | ||
| 299 | + > 4ms | ||
| 267 | 300 | test/samples/magic-string.js (34 KiB) | |
| 268 | - > 1ms | ||
| 301 | + > 0.84ms | ||
| 269 | 302 | test/samples/magic-string.min.js (20 KiB) | |
| 270 | - > 0.36ms | ||
| 303 | + > 0.08ms | ||
| 271 | 304 | test/samples/rollup.js (698 KiB) | |
| 272 | - > 10.48ms | ||
| 305 | + > 9.08ms | ||
| 273 | 306 | test/samples/rollup.min.js (367 KiB) | |
| 274 | - > 6.64ms | ||
| 307 | + > 6ms | ||
| 275 | 308 | ||
| 276 | 309 | Warm Runs, All Samples (average of 25 runs) | |
| 277 | 310 | test/samples/*.js (3635 KiB) | |
| 278 | - > 49.28ms | ||
| 311 | + > 41.32ms | ||
| 279 | 312 | ``` | |
| 280 | 313 | ||
| 281 | 314 | Wasm Build: | |
| 282 | 315 | ``` | |
| 283 | 316 | Module load time | |
| 284 | - > 11ms | ||
| 317 | + > 10ms | ||
| 285 | 318 | Cold Run, All Samples | |
| 286 | 319 | test/samples/*.js (3635 KiB) | |
| 287 | - > 48ms | ||
| 320 | + > 47ms | ||
| 288 | 321 | ||
| 289 | 322 | Warm Runs (average of 25 runs) | |
| 290 | 323 | test/samples/angular.js (1410 KiB) | |
| 291 | - > 12.32ms | ||
| 324 | + > 12.96ms | ||
| 292 | 325 | test/samples/angular.min.js (303 KiB) | |
| 293 | - > 3.76ms | ||
| 326 | + > 4ms | ||
| 294 | 327 | test/samples/d3.js (553 KiB) | |
| 295 | - > 6.08ms | ||
| 328 | + > 6.12ms | ||
| 296 | 329 | test/samples/d3.min.js (250 KiB) | |
| 297 | - > 3ms | ||
| 330 | + > 3.08ms | ||
| 298 | 331 | test/samples/magic-string.js (34 KiB) | |
| 299 | - > 0.24ms | ||
| 332 | + > 0.32ms | ||
| 300 | 333 | test/samples/magic-string.min.js (20 KiB) | |
| 301 | 334 | > 0ms | |
| 302 | 335 | test/samples/rollup.js (698 KiB) | |
| 303 | - > 7.2ms | ||
| 336 | + > 7.8ms | ||
| 304 | 337 | test/samples/rollup.min.js (367 KiB) | |
| 305 | - > 4.2ms | ||
| 338 | + > 4.64ms | ||
| 306 | 339 | ||
| 307 | 340 | Warm Runs, All Samples (average of 25 runs) | |
| 308 | 341 | test/samples/*.js (3635 KiB) | |
| 309 | - > 33.6ms | ||
| 342 | + > 35.64ms | ||
| 310 | 343 | ``` | |
| 311 | 344 | ||
| 312 | 345 | ### Wasm Build Steps | |
| 313 | 346 | ||
| 314 | - To build download the WASI SDK from https://github.com/CraneStation/wasi-sdk/releases. | ||
| 347 | + To build download the WASI SDK from https://github.com/WebAssembly/wasi-sdk/releases. | ||
| 315 | 348 | ||
| 316 | - The Makefile assumes the existence of "wasi-sdk-10.0", "binaryen" and "wabt" (both optional) as sibling folders to this project. | ||
| 349 | + The Makefile assumes the existence of "wasi-sdk-11.0" and "wabt" (optional) as sibling folders to this project. | ||
| 317 | 350 | ||
| 318 | 351 | The build through the Makefile is then run via `make lib/lexer.wasm`, which can also be triggered via `npm run build-wasm` to create `dist/lexer.js`. | |
| 319 | 352 | ||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -278,7 +278,9 @@ function tryParseObjectDefineOrKeys (keys) { | |||
| 278 | 278 | const exportPos = ++pos; | |
| 279 | 279 | if (identifier() && source.charCodeAt(pos) === ch) { | |
| 280 | 280 | // revert for "(" | |
| 281 | - addExport(source.slice(exportPos, pos)); | ||
| 281 | + const expt = source.slice(exportPos, pos); | ||
| 282 | + if (expt === '__esModule') | ||
| 283 | + addExport(expt); | ||
| 282 | 284 | } | |
| 283 | 285 | } | |
| 284 | 286 | } | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -1,6 +1,6 @@ | |||
| 1 | 1 | { | |
| 2 | 2 | "name": "cjs-module-lexer", | |
| 3 | - "version": "0.4.3", | ||
| 3 | + "version": "0.5.0", | ||
| 4 | 4 | "description": "Lexes CommonJS modules, returning their named exports metadata", | |
| 5 | 5 | "main": "lexer.js", | |
| 6 | 6 | "exports": { | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -1287,7 +1287,7 @@ success! | |||
| 1287 | 1287 | [`transformSource` hook]: #esm_transformsource_source_context_defaulttransformsource | |
| 1288 | 1288 | [`string`]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String | |
| 1289 | 1289 | [`util.TextDecoder`]: util.md#util_class_util_textdecoder | |
| 1290 | - [cjs-module-lexer]: https://github.com/guybedford/cjs-module-lexer/tree/0.4.3 | ||
| 1290 | + [cjs-module-lexer]: https://github.com/guybedford/cjs-module-lexer/tree/0.5.0 | ||
| 1291 | 1291 | [special scheme]: https://url.spec.whatwg.org/#special-scheme | |
| 1292 | 1292 | [the official standard format]: https://tc39.github.io/ecma262/#sec-modules | |
| 1293 | 1293 | [transpiler loader example]: #esm_transpiler_loader | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -1,11 +1,10 @@ | |||
| 1 | 1 | import { strictEqual, deepEqual } from 'assert'; | |
| 2 | 2 | ||
| 3 | - import m, { π, z } from './exports-cases.js'; | ||
| 3 | + import m, { π } from './exports-cases.js'; | ||
| 4 | 4 | import * as ns from './exports-cases.js'; | |
| 5 | 5 | ||
| 6 | - deepEqual(Object.keys(ns), ['default', 'isObject', 'z', 'π']); | ||
| 6 | + deepEqual(Object.keys(ns), ['default', 'isObject', 'π']); | ||
| 7 | 7 | strictEqual(π, 'yes'); | |
| 8 | - strictEqual(z, 'yes'); | ||
| 9 | 8 | strictEqual(typeof m.isObject, 'undefined'); | |
| 10 | 9 | strictEqual(m.π, 'yes'); | |
| 11 | 10 | strictEqual(m.z, 'yes'); | |
@@ -19,7 +18,7 @@ strictEqual(typeof m2, 'object'); | |||
| 19 | 18 | strictEqual(m2.default, 'the default'); | |
| 20 | 19 | strictEqual(ns2.__esModule, true); | |
| 21 | 20 | strictEqual(ns2.name, 'name'); | |
| 22 | - deepEqual(Object.keys(ns2), ['__esModule', 'case2', 'default', 'name', 'pi']); | ||
| 21 | + deepEqual(Object.keys(ns2), ['__esModule', 'case2', 'default', 'name']); | ||
| 23 | 22 | ||
| 24 | 23 | import m3, { __esModule as __esModule3, name as name3 } from './exports-cases3.js'; | |
| 25 | 24 | import * as ns3 from './exports-cases3.js'; | |
| Back | FazBrowse Home | New Git URL |
0 commit comments