| 01:10 | <littledan> | Could anyone summarize the conclusions of this conversation? |
| 03:47 | <Kris Kowal> | Kevin might be convinced that a path from module text to evaluated behavior is permissible if 1. no new loopholes to CSP are introduced (and we agree that this is not a concern) 2. the capability is not too easy to find or use, for example made possibly only through a Compartment importHook that returns { source } (but presumably not a Module importHook, and with no ModuleSource constructor. We agree that this does not limit expressible behavior.) and 2. motivation more compelling than just Agoric’s use case can be found. The use cases presented as yet are not sufficiently compelling. |
| 03:49 | <Kris Kowal> | To that end, I might reach out to the community at large to build a coalition. It seems we need some combination of quantity and quality of use cases that we have not yet presented. I believe these exist and we need testimonials. |
| 03:54 | <ljharb> | my primary use case is being able to test module-level syntax features, like TLA, without necessarily needing a filesystem to be present. That's already what I use Function for (and potentially AsyncFunction, GeneratorFunction, and AsyncGeneratorFunction as well). |
| 04:01 | <littledan> | ljharb, could you elaborate on what the testing is for? I take it that this is for a polyfill, rather than test262-related (where we could add extra host callbacks) |
| 04:02 | <littledan> | I take it that the use case has to be something that bakkot can be convinced is important enough (since he questioned that above); maybe context from ljharb could meet that requirement |
| 04:06 | <ljharb> | yes, polyfills or environment testing packages - like “has object spread” or “has top-level await” |
| 04:07 | <ljharb> | or “has Unicode named exports”, or any new syntax we add to the top level of Modules in the future |
| 04:07 | <ljharb> | until we ship a syntax detection mechanism (which we may never do), eval is the only viable alternative. |
| 04:12 | <littledan> | Could you say more about why ModuleSource helps you do something that you can't do with plain eval? |
| 04:17 | <Kris Kowal> | I’m also motivated by ljharb’s use case, but in the interest of demonstrating that I’ve listened to bakkot carefully, I imagine that module blocks + eval are sufficient to that end and would not require ModuleSource(text) |
| 04:18 | <ljharb> | nope, because i can’t test for the syntax in an engine that lacks module blocks |
| 04:18 | <ljharb> | i need a purely API-based solution |
| 04:18 | <bakkot> | module blocks would presumably need to contain valid-in-the-current-engine syntax anyway |
| 04:18 | <ljharb> | oh i see what you mean, inside Function, put a module block |
| 04:18 | <bakkot> | oh wait yeah |
| 04:19 | <bakkot> | yeah that seems adequate for this use case if I understand the use case correctly |
| 04:20 | <Kris Kowal> | That’s not to say I wouldn’t favor ModuleSource(x) over eval('module {' + x + '})') for that purpose, but we would only need one or the other strictly speaking. |
| 04:20 | <ljharb> | Function, to be clear, never eval :-) |
| 04:20 | <ljharb> | but yeah, same. |
| 04:20 | <Kris Kowal> | Yeah, fair. |
| 04:20 | <Kris Kowal> | Never direct-eval, anyway. |
| 04:22 | <ljharb> | i just avoid it like a bad word, direct or not |
| 04:22 | <bakkot> | ljharb: kind of a tangent, but why do you need to feature-test syntax anyway? is it just to decide which polyfill to load or is there some other case it comes up? |
| 04:23 | <bakkot> | ("deciding which polyfill to load" is an important use case, I'm just wondering if there's others I'm missing) |
| 04:23 | <ljharb> | i use it constantly in test suites |
| 04:23 | <ljharb> | (also even if Function + a module block works for me, i still have the consistency argument that every other way of passing around code-to-be-executed has a constructor) |
| 04:23 | <Kris Kowal> | We do eval-based syntax testing to discover intrinsics we need to freeze, tame, and trim. |
| 04:23 | <Kris Kowal> | (In ses shim.) |
| 04:24 | <Kris Kowal> | I’m sympathetic to the consistency argument, but it doesn’t pass the bakkot test. |
| 04:25 | <Kris Kowal> | I feel very strongly that the best proposals triangulate a void implied by two other features, the way Array.from and async imply the existence of Array.fromAsync. |
| 04:26 | <Kris Kowal> | Or the way Array and iterators imply iterator helpers. |
| 04:30 | <bakkot> | if the only goal was to fill the void left by eval only handling the Script parse goal, the way to fill it would be eval(source, { type: 'module' }) or something, which... I mean, I find that instinctively distasteful, but the reason I don't like it is because it's enhancing eval, which is also my objection to all of the other options |
| 04:30 | <bakkot> | it at least has the advantage that it would not be new thing that we would need to tell people not to use |
| 04:32 | <bakkot> | honestly I kind of appreciate the honesty of it - the fundamental question before the committee, do we want to make eval-for-modules? if we would not add eval(source, { type: 'module' }) then we probably should not add a constructible ModuleSource either |
| 05:33 | <Jack Works> | Looks like the solution is to add a new directive for e.g. |
| 05:39 | <Jack Works> | 🤔 Is ModuleSource unforgeable? via (module {}).constructor |
| 05:42 | <Justin Ridgewell> | What do you mean by unforgeable? |
| 05:44 | <Justin Ridgewell> |
unsafe-module-source is a more specific variant of unsafe-eval (unsafe-eval disables both like it does for wasm-unsafe-eval) |
| 05:46 | <Jack Works> | Great, this is clear. We can focus on building 1. the strongest reason and 2. the work-arounds other proposals (specifically module binding static analysis) can be recovered in the absence of ModuleSource(text). ModuleSource.fromString a thing and make it potional? |
| 05:53 | <Jack Works> | And the motivation for parsing bindings is bundle, web archive, or import map generation, in which case, a path to eval is not needed. further split
|
| 06:05 | <Jack Works> | https://github.com/guybedford/es-module-lexer Every time I want to use es-module-lexer for some fast analyzing it always fails because
|
| 06:09 | <Jack Works> | I assume this is sufficient to accept exactly and only grammatically valid sources. That requires block matching, but not AST generation. The other motivation for a full parse is that text = '}; run any code; {' |
| 14:24 | <littledan> | 🤔 Is Module |
| 14:25 | <littledan> | nope, because i can’t test for the syntax in an engine that lacks module blocks |
| 14:27 | <littledan> |
|
| 17:28 | <ljharb> | I guess this is mostly an issue if there exists any engine that ships constructable Module before module blocks. |
| 17:30 | <Jack Works> | What do you end up doing instead? |
| 18:08 | <Kris Kowal> | which definitely seems worse |
| 18:09 | <Kris Kowal> | I do think that 1.) performance of native will be unbeatable and 2.) code injection foot-gun do count in favor of ModuleSource, but my understanding is that this is not enough to sway @bakkot. |
| 18:11 | <Kris Kowal> | or make Module from constructible ModuleSource. |
| 18:16 | <Kris Kowal> | honestly I kind of appreciate the honesty of it - the fundamental question before the committee, do we want to make eval(source, { type: 'module' }) as the vessel for it under any circumstances. Modules are more analogous to the Function constructor form of eval since they are reusable and defer execution, but differ because they can import and export. An eval form would have to answer a lot of questions about top-level await. The form would clearly be unable to export, and a completion value would stand in the way of an exports namespace. I think that the question of whether to support eval-but-modules is a better framing, but ModuleSource is consistent with the prevailing eval aesthetic. |
| 18:17 | <Kris Kowal> | That said, I don’t know whether JSDOM for example would be able to emulate <script type="module"> faithfully using ModuleSource. I don’t recall whether scripts can export. |
| 18:20 | <Kris Kowal> | Inviting domenic (Domenic Denicola) because I had reason to wonder whether JSDOM would be a motivating use case for ModuleSource, such that <script type="module"> could maybe be emulated faithfully on a language feature. |
| 18:20 | <Kris Kowal> | And also because domenic (Domenic Denicola) should be here anyway. 😊 |
| 19:07 | <ljharb> | i think script type modules can export, but i'm not sure if anything can access them? |
| 19:07 | <Kris Kowal> | Yeah, ModuleSource would be sufficient assuming the exports just get black-holed. |
| 19:08 | <ljharb> | there's only one Module parse goal so i'm not sure how you'd have a Module without allowing exports |
| 19:08 | <Kris Kowal> | And I don’t think we should make an eval form that reveals the completion value of a module. I can’t imagine that being useful. |
| 19:11 | <ljharb> | i mean it could easily be the module namespace object for it, but i agree it's not super useful and best avoided |