Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 16 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ This project is used in Node.js core for detecting the named exports available w

PRs will be accepted and upstreamed for parser bugs, performance improvements or new syntax support only.

_Detection patterns for this project are **frozen**_. This is because adding any new export detection patterns would result in fragmented backwards-compatibility. Specifically, it would be very difficult to figure out why an ES module named export for CommonJS might work in newer Node.js versions but not older versions. This problem would only be discovered downstream of module authors, with the fix for module authors being to then have to understand which patterns in this project provide full backwards-compatibily. Rather, by fully freezing the detected patterns, if it works in any Node.js version it will work in any other. Build tools can also reliably treat the supported syntax for this project as a part of their output target for ensuring syntax support.
_Default detection patterns for this project are **frozen**_. This is because adding any new export detection patterns would result in fragmented backwards-compatibility. Specifically, it would be very difficult to figure out why an ES module named export for CommonJS might work in newer Node.js versions but not older versions. This problem would only be discovered downstream of module authors, with the fix for module authors being to then have to understand which patterns in this project provide full backwards-compatibily. Rather, by fully freezing the detected patterns, if it works in any Node.js version it will work in any other. Build tools can also reliably treat the supported syntax for this project as a part of their output target for ensuring syntax support.

### Usage

Expand Down Expand Up @@ -71,9 +71,23 @@ Browser main threads can restrict synchronous Wasm compilation, so await

The Wasm build is around 1.5x faster and without a cold start.

The optional third argument to `parse(source, name, options)` controls detection extensions.
`allowMinifiedEnumerable` defaults to `false`. Set it to `true` to recognize `enumerable: !0`
in supported `Object.defineProperty` exports and star reexports. Whitespace and comments can separate `!` and `0`.
This option does not change Node.js's built-in CommonJS named-export detection.

```js
const { exports } = parse(
"Object.defineProperty(exports, 'b', { enumerable: !0, value: 'b' });",
undefined,
{ allowMinifiedEnumerable: true }
);
// exports === ['b']
```

### Grammar

CommonJS exports matches are run against the source token stream.
CommonJS exports matches are run against the source token stream. The grammar below describes default detection.

The token grammar is:

Expand Down
1 change: 1 addition & 0 deletions build/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ WASM_TARGET := -target wasm32-unknown-wasi
WASM_EXTRA_CFLAGS := -I include-wasm/ -Wno-logical-op-parentheses -Wno-parentheses -Oz
WASM_EXTRA_LDFLAGS := -Wl,-z,stack-size=13312,--no-entry,--compress-relocations,--strip-all
WASM_EXTRA_LDFLAGS += -Wl,--export=__heap_base,--export=parseCJS,--export=sa
WASM_EXTRA_LDFLAGS += -Wl,--export=parseCJSWithOptions
WASM_EXTRA_LDFLAGS += -Wl,--export=e,--export=re,--export=es,--export=ee
WASM_EXTRA_LDFLAGS += -Wl,--export=rre,--export=ree,--export=res,--export=ru,--export=us,--export=ue

Expand Down
1 change: 1 addition & 0 deletions include-wasm/cjs-module-lexer.h
Original file line number Diff line number Diff line change
Expand Up @@ -162,6 +162,7 @@ void (*addReexport)(const uint16_t*, const uint16_t*) = &_addReexport;
void (*addUnsafeGetter)(const uint16_t*, const uint16_t*) = &_addUnsafeGetter;
void (*clearReexports)() = &_clearReexports;
uint32_t 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), void (*addUnsafeGetter)(const uint16_t*, const uint16_t*), void (*clearReexports)());
uint32_t parseCJSWithOptions (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), void (*addUnsafeGetter)(const uint16_t*, const uint16_t*), void (*clearReexports)(), uint32_t options);

enum RequireType {
Import,
Expand Down
6 changes: 5 additions & 1 deletion lexer.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,10 @@ export interface Exports {
reexports: string[];
}

export declare function parse(source: string, name?: string): Exports;
export interface ParseOptions {
allowMinifiedEnumerable?: boolean;
}

export declare function parse(source: string, name?: string, options?: ParseOptions): Exports;
export declare function init(): Promise<void>;
export declare function initSync(): void;
43 changes: 34 additions & 9 deletions lexer.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ let openTokenDepth,
lastSlashWasDivision,
templateStackDepth,
nextBraceIsClass,
allowMinifiedEnumerable,
starExportMap,
lastStarExportSpecifier,
_exports,
Expand All @@ -22,6 +23,7 @@ function resetState () {
lastSlashWasDivision = false;
templateStackDepth = 0;
nextBraceIsClass = false;
allowMinifiedEnumerable = false;
starExportMap = Object.create(null);
lastStarExportSpecifier = null;

Expand Down Expand Up @@ -49,15 +51,22 @@ function pushTemplate () {
templateDepth = ++openTokenDepth;
}

function parseCJS (source, name = '@') {
/**
* @param {string} source
* @param {string} [name]
* @param {import('./lexer').ParseOptions} [options]
*/
function parseCJS (source, name = '@', options) {
const minifiedEnumerable = options ? options.allowMinifiedEnumerable === true : false;
resetState();
allowMinifiedEnumerable = minifiedEnumerable;
try {
parseSource(source);
}
catch (e) {
e.message += `\n at ${name}:${source.slice(0, pos).split('\n').length}:${pos - source.lastIndexOf('\n', pos - 1)}`;
e.loc = pos;
throw e;
catch (error) {
error.message += `\n at ${name}:${source.slice(0, pos).split('\n').length}:${pos - source.lastIndexOf('\n', pos - 1)}`;
error.loc = pos;
throw error;
}
const result = { exports: [..._exports].filter(expt => expt !== undefined && !unsafeGetters.has(expt)), reexports: [...reexports].filter(reexpt => reexpt !== undefined) };
resetState();
Expand Down Expand Up @@ -353,6 +362,16 @@ function tryParseObjectHasOwnProperty (it_id) {
return true;
}

/** @param {number} ch */
function tryParseMinifiedEnumerable (ch) {
if (!allowMinifiedEnumerable || ch !== 33/*!*/) return false;
pos++;
if (commentWhitespace() !== 48/*0*/) return false;
pos++;
return true;
}

/** @param {boolean} keys */
function tryParseObjectDefineOrKeys (keys) {
pos += 6;
let revertPos = pos - 1;
Expand Down Expand Up @@ -392,8 +411,11 @@ function tryParseObjectDefineOrKeys (keys) {
if (ch !== 58/*:*/) break;
pos++;
ch = commentWhitespace();
if (ch !== 116/*t*/ || !source.startsWith('rue', pos + 1)) break;
pos += 4;
if (ch === 116/*t*/ && source.startsWith('rue', pos + 1)) {
pos += 4;
} else if (!tryParseMinifiedEnumerable(ch)) {
break;
}
ch = commentWhitespace();
if (ch !== 44) break;
pos++;
Expand Down Expand Up @@ -771,8 +793,11 @@ function tryParseObjectDefineOrKeys (keys) {
if (ch !== 58/*:*/) break;
pos++;
ch = commentWhitespace();
if (ch !== 116/*t*/ && !source.startsWith('rue', pos + 1)) break;
pos += 4;
if (ch === 116/*t*/ && source.startsWith('rue', pos + 1)) {
pos += 4;
} else if (!tryParseMinifiedEnumerable(ch)) {
break;
}
ch = commentWhitespace();
if (ch !== 44/*,*/) break;
pos++;
Expand Down
Binary file modified lib/lexer.wasm
Binary file not shown.
Loading
Loading