diff --git a/napi/parser/index.js b/napi/parser/index.js index c2bcf920136c0d..ea32cc6f886a43 100644 --- a/napi/parser/index.js +++ b/napi/parser/index.js @@ -12,7 +12,26 @@ function wrap(result) { let program, module, comments, errors, magicString; return { get program() { - if (!program) program = JSON.parse(result.program); + if (!program) { + program = JSON.parse(result.program, function(key, value) { + // Set `value` field of `Literal`s for `BigInt`s and `RegExp`s. + // This is not possible to do on Rust side, as neither can be represented correctly in JSON. + if (value === null && key === 'value' && Object.hasOwn(this, 'type') && this.type === 'Literal') { + if (Object.hasOwn(this, 'bigint')) { + return BigInt(this.bigint); + } + if (Object.hasOwn(this, 'regex')) { + const { regex } = this; + try { + return RegExp(regex.pattern, regex.flags); + } catch (_err) { + // Invalid regexp, or valid regexp using syntax not supported by this version of NodeJS + } + } + } + return value; + }); + } return program; }, get module() { diff --git a/napi/parser/test/parse.test.ts b/napi/parser/test/parse.test.ts index 2684b5adeddf54..f4cbe58204cabb 100644 --- a/napi/parser/test/parse.test.ts +++ b/napi/parser/test/parse.test.ts @@ -26,6 +26,71 @@ describe('parse', () => { }); expect(code.substring(comment.start, comment.end)).toBe('/*' + comment.value + '*/'); }); + + it('`BigIntLiteral` has `value` as `BigInt`', () => { + const ret = parseSync('test.js', '123_456n'); + expect(ret.errors.length).toBe(0); + expect(ret.program.body.length).toBe(1); + expect(ret.program.body[0]).toEqual({ + type: 'ExpressionStatement', + start: 0, + end: 8, + expression: { + type: 'Literal', + start: 0, + end: 8, + value: 123456n, + raw: '123_456n', + bigint: '123456', + }, + }); + }); + + describe('`RegExpLiteral`', () => { + it('has `value` as `RegExp` when valid regexp', () => { + const ret = parseSync('test.js', '/abc/gu'); + expect(ret.errors.length).toBe(0); + expect(ret.program.body.length).toBe(1); + expect(ret.program.body[0]).toEqual({ + type: 'ExpressionStatement', + start: 0, + end: 7, + expression: { + type: 'Literal', + start: 0, + end: 7, + value: /abc/gu, + raw: '/abc/gu', + regex: { + pattern: 'abc', + flags: 'gu', + }, + }, + }); + }); + + it('has `value` as `null` when invalid regexp', () => { + const ret = parseSync('test.js', '/+/'); + expect(ret.errors.length).toBe(0); + expect(ret.program.body.length).toBe(1); + expect(ret.program.body[0]).toEqual({ + type: 'ExpressionStatement', + start: 0, + end: 3, + expression: { + type: 'Literal', + start: 0, + end: 3, + value: null, + raw: '/+/', + regex: { + pattern: '+', + flags: '', + }, + }, + }); + }); + }); }); it('utf16 span', async () => {