From 9d9272653a45c36066a76b50a03d62d21a159803 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kasper=20Isager=20Dalsgar=C3=B0?= Date: Fri, 15 Nov 2024 13:57:47 +0100 Subject: [PATCH] Support `require(.addon).resolve()` --- README.md | 5 +++-- binding.c | 1 + index.js | 10 ++++++++-- lex.h | 46 +++++++++++++++++++++++++++++++++++++--------- test.js | 37 ++++++++++++++++++++++++++++++++++++- 5 files changed, 85 insertions(+), 14 deletions(-) diff --git a/README.md b/README.md index d6b6105..08c0077 100644 --- a/README.md +++ b/README.md @@ -63,8 +63,9 @@ Constant | Description `REQUIRE` | CommonJS `require()`. `IMPORT` | ES module `import`. `DYNAMIC` | ES module `import()` if `IMPORT` is set. -`ADDON` | CommonJS `require.addon()` if `REQUIRE` is set or ES module `import.meta.addon()` if `IMPORT` is set. -`ASSET` | CommonJS `require.asset()` if `REQUIRE` is set or ES module `import.meta.asset()` if `IMPORT` is set. +`ADDON` | CommonJS `require.addon()` if `REQUIRE` is set, or ES module `import.meta.addon()` if `IMPORT` is set. +`ASSET` | CommonJS `require.asset()` if `REQUIRE` is set, or ES module `import.meta.asset()` if `IMPORT` is set. +`RESOLVE` | CommonJS `require.resolve()` or `require.addon.resolve()` if `REQUIRE` and optionally `ADDON` are set, or ES module `import.meta.resolve()` or `import.meta.addon.resolve()` if `IMPORT` and optionally `ADDON` are set. `REEXPORT` | Re-export of a CommonJS `require()` if `REQUIRE` is set. ## License diff --git a/binding.c b/binding.c index 022b864..a0c352d 100644 --- a/binding.c +++ b/binding.c @@ -76,6 +76,7 @@ bare_module_lexer_exports (js_env_t *env, js_value_t *exports) { V("DYNAMIC", bare_module_lexer_dynamic) V("ADDON", bare_module_lexer_addon) V("ASSET", bare_module_lexer_asset) + V("RESOLVE", bare_module_lexer_resolve) V("REEXPORT", bare_module_lexer_reexport) #undef V diff --git a/index.js b/index.js index 15fb44e..75db2a0 100644 --- a/index.js +++ b/index.js @@ -30,15 +30,21 @@ exports.constants = { DYNAMIC: binding.DYNAMIC, /** - * CommonJS `require.addon()` if `REQUIRE` is set or ES module `import.meta.addon()` if `IMPORT` is set. + * CommonJS `require.addon()` if `REQUIRE` is set, or ES module `import.meta.addon()` if `IMPORT` is set. */ ADDON: binding.ADDON, /** - * CommonJS `require.asset()` if `REQUIRE` is set or ES module `import.meta.asset()` if `IMPORT` is set. + * CommonJS `require.asset()` if `REQUIRE` is set, or ES module `import.meta.asset()` if `IMPORT` is set. */ ASSET: binding.ASSET, + /** + * CommonJS `require.resolve()` or `require.addon.resolve()` if `REQUIRE` and optionally `ADDON` are set, or ES module + * `import.meta.resolve()` or `import.meta.addon.resolve()` if `IMPORT` and optionally `ADDON` are set. + */ + RESOLVE: binding.RESOLVE, + /** * Re-export of a CommonJS `require()` if `REQUIRE` is set. */ diff --git a/lex.h b/lex.h index 2889df5..6d68ae1 100644 --- a/lex.h +++ b/lex.h @@ -14,7 +14,8 @@ enum { bare_module_lexer_dynamic = 0x4, bare_module_lexer_addon = 0x8, bare_module_lexer_asset = 0x10, - bare_module_lexer_reexport = 0x20, + bare_module_lexer_resolve = 0x20, + bare_module_lexer_reexport = 0x40, }; static inline bool @@ -428,9 +429,7 @@ bare_module_lexer__lex (js_env_t *env, js_value_t *imports, js_value_t *exports, while (i < n && ws(u(0))) i++; } - else { - i++; - } + else i++; continue; @@ -456,6 +455,24 @@ bare_module_lexer__lex (js_env_t *env, js_value_t *imports, js_value_t *exports, while (i < n && ws(u(0))) i++; type |= bare_module_lexer_addon; + + // require\.addon\. + if (c(0) == '.') { + i++; + + while (i < n && ws(u(0))) i++; + + // require\.addon\.resolve + if (i + 7 < n && bu("resolve", 7)) { + i += 7; + + while (i < n && ws(u(0))) i++; + + type |= bare_module_lexer_resolve; + } + + else continue; + } } // require\.asset @@ -467,15 +484,26 @@ bare_module_lexer__lex (js_env_t *env, js_value_t *imports, js_value_t *exports, type |= bare_module_lexer_asset; } } + + // require\.resolve + else if (i + 7 < n && bu("resolve", 7)) { + i += 7; + + while (i < n && ws(u(0))) i++; + + type |= bare_module_lexer_resolve; + } + + else continue; } - // require(\.(addon|asset))?\( + // require(\.(resolve|addon(\.resolve)?|asset))?\( if (c(0) == '(') { i++; while (i < n && ws(u(0))) i++; - // require(\.(addon|asset))?\(['"] + // require(\.(resolve|addon(\.resolve)?|asset))?\(['"] if (c(0) == '\'' || c(0) == '"') { utf8_t e = u(0); @@ -483,7 +511,7 @@ bare_module_lexer__lex (js_env_t *env, js_value_t *imports, js_value_t *exports, while (i < n && u(0) != e) i++; - // require(\.(addon|asset))?\(['"].*['"] + // require(\.(resolve|addon(\.resolve)?|asset))?\(['"].*['"] if (c(0) == e) { se = i; @@ -493,7 +521,7 @@ bare_module_lexer__lex (js_env_t *env, js_value_t *imports, js_value_t *exports, while (i < n && u(0) != ')') i++; - // require(\.(addon|asset))?\(['"].*['"][^)]*\) + // require(\.(resolve|addon(\.resolve)?|asset))?\(['"].*['"][^)]*\) if (c(0) == ')') { i++; @@ -503,7 +531,7 @@ bare_module_lexer__lex (js_env_t *env, js_value_t *imports, js_value_t *exports, } } - // require\.addon\(\) + // require\.addon(\.resolve)?\(\) else if (c(0) == ')' && (type & bare_module_lexer_addon)) { ss = se = i++; diff --git a/test.js b/test.js index a341ba8..d208abb 100644 --- a/test.js +++ b/test.js @@ -1,7 +1,7 @@ const test = require('brittle') const lex = require('.') -const { REQUIRE, IMPORT, DYNAMIC, ADDON, ASSET, REEXPORT } = lex.constants +const { REQUIRE, IMPORT, DYNAMIC, ADDON, ASSET, REEXPORT, RESOLVE } = lex.constants test('require(\'id\')', (t) => { t.alike(lex('require(\'./foo.js\')'), { @@ -17,6 +17,20 @@ test('require("id")', (t) => { }) }) +test('require.resolve(\'id\')', (t) => { + t.alike(lex('require.resolve(\'./foo.js\')'), { + imports: [{ specifier: './foo.js', type: REQUIRE | RESOLVE, names: [], position: [0, 17, 25] }], + exports: [] + }) +}) + +test('require.resolve("id")', (t) => { + t.alike(lex('require.resolve("./foo.js")'), { + imports: [{ specifier: './foo.js', type: REQUIRE | RESOLVE, names: [], position: [0, 17, 25] }], + exports: [] + }) +}) + test('require.addon()', (t) => { t.alike(lex('require.addon()'), { imports: [{ specifier: '', type: REQUIRE | ADDON, names: [], position: [0, 14, 14] }], @@ -38,6 +52,27 @@ test('require.addon("id")', (t) => { }) }) +test('require.addon.resolve()', (t) => { + t.alike(lex('require.addon.resolve()'), { + imports: [{ specifier: '', type: REQUIRE | ADDON | RESOLVE, names: [], position: [0, 22, 22] }], + exports: [] + }) +}) + +test('require.addon.resolve(\'id\')', (t) => { + t.alike(lex('require.addon.resolve(\'./foo.bare\')'), { + imports: [{ specifier: './foo.bare', type: REQUIRE | ADDON | RESOLVE, names: [], position: [0, 23, 33] }], + exports: [] + }) +}) + +test('require.addon.resolve("id")', (t) => { + t.alike(lex('require.addon.resolve("./foo.bare")'), { + imports: [{ specifier: './foo.bare', type: REQUIRE | ADDON | RESOLVE, names: [], position: [0, 23, 33] }], + exports: [] + }) +}) + test('require.asset(\'id\')', (t) => { t.alike(lex('require.asset(\'./foo.txt\')'), { imports: [{ specifier: './foo.txt', type: REQUIRE | ASSET, names: [], position: [0, 15, 24] }],