Re: [heycam/webidl] Define Web IDL Modules (#675)

domenic approved this pull request.

Overall LGTM. I think we should add an "under construction" signage, file issues for the other follow-ups @littledan mentioned, and merge. Really nice work.

We can then iterate on those issues and also attempt to use modules in the KV storage spec. I don't think we'll want to merge into KV storage quite yet because of the remaining issues in https://github.com/WICG/kv-storage/issues/46, but just writing the spec patch would give us a good idea of how these things would be used. For example it'd let us see "set a module attribute" in action.

> @@ -801,11 +807,32 @@ expected that an object that implements a particular IDL interface
 provides ways to inspect and modify the object's state and to
 invoke the behavior described by the interface.
 
+[=Interfaces=] and [=partial interfaces=] have an <dfn for="interface,partial interface">enclosing
+module</dfn>, which is a [=module=] or null.
+Unless otherwise specified, it is null.
+
+<div algorithm>
+  [=Interfaces=] and [=partial interfaces=] have a
+  <dfn for="interface,partial interface">scoped identifier</dfn>,
+  which uniquely identifies an [=interface=].

Why is this a separate concept from qualfiied name? The difference seems to be that for modules we allow two same-named interfaces in different modules, but we don't allow two same-named interfaces in [LegacyNamespace]. Is that mismatch desirable?

> +<h3 id="idl-modules">Modules</h3>
+
+A <dfn id="dfn-module" export>module</dfn> is a structure that exposes a collection of
+[=interfaces=], [=read only=] [=regular attributes=], and [=regular operations=] as a logical unit.
+A [=module=] has a <dfn for=module>specifier</dfn> that uniquely identifies it.
+
+<div algorithm>
+A module has a [=list=] of
+<dfn id="dfn-module-member" export lt="module member" for=module>module members</dfn> which are
+[=interfaces=], [=read only=] [=regular attributes=], and [=regular operations=].
+
+The [=module/module members=] of a [=module=] |module| are given by the following steps:
+
+    1.  Let |result| be « ».
+    1.  Let |specifier| be |module|'s [=module/specifier=].
+    1.  For each [=module declaration=] |declaration| whose [=module declaration/specifier=] is

How could there be more than one?

> +    1.  Return |result|.
+
+Note: The order that members appear in this list has significance for property enumeration in the
+<a href="#es-modules">ECMAScript binding</a>.
+
+Issue: Exclude [=partial interfaces=]?
+</div>
+
+For all [=modules=] |module|, all [=interfaces=] and [=partial interfaces=] that are in |module|'s
+[=module/module members=] have their [=interface/enclosing module=] set to |module|.
+
+<div algorithm>
+  The <dfn for=module>url</dfn> of a [=module=] |module| is given by the following steps:
+
+    1.  Let |specifier| be |module|'s [=module/specifier=].
+    1.  Return the [=concatenation=] of « "<code>import:std:</code>", |specifier| ».

Currently I am leaning toward it just being `std:` for built-in modules, but I am not certain until I write proper spec text for the import maps resolver. I would keep it as `std:` for now though.

> +</div>
+
+Note that like [=namespaces=], modules do not create types.
+
+Rather than defining behavior when accessed, the [=attributes=] of a [=module=] act as a simple
+storage location. The relevant language binding defines the steps to "set a module attribute" to
+an IDL value of the type of the [=attribute=].
+
+Note: See the ECMAScript binding's definition of [=set a module attribute=].
+
+Each module may have <dfn for=module>evaluation steps</dfn> which are executed when the module is
+first imported.
+These steps have access to a <dfn>this module</dfn> value, which is the [=module=] being
+evaluated, and a [=Realm=].
+They may throw an [=exception=], which prevents the module from being accessed.
+The [=module/evaluation steps=] for a module |m| must invoke the "set a module attribute"

I'm not a big fan of this "quotes surrounding a term" in place of cross-links, but I understand that the alternative is defining a language-agnostic term and a ES-specific term which is also annoying. I'm not sure what to do here.

> +                <b>this module</b> to |initial|.
+    </blockquote>
+
+    An ECMAScript implementation would then expose a <code class="idl">"std:temporal"</code>
+    module which includes an [=interface object=] for the interface and a function for the operation:
+
+    <pre highlight="js">
+        import * from "std:temporal" as temporal;
+        Object.keys(temporal);                      // Evaluates to ["Timezone", "getCurrentTimezone", "currentTimezone"]
+        typeof temporal.Timezone;                   // Evaluates to "function"
+        typeof temporal.getCurrentTimezone;         // Evaluates to "function"
+        typeof temporal.initialTimezone;            // Evaluates to "object"
+    </pre>
+</div>
+
+### Syntax ### {#idl-modules-syntax}

I note that nothing else has syntax subsections, although I do agree it's a nice thematic break here. Not sure what to do. (Although it doesn't matter much.)

> +        1.  Append the [=identifier=] of |member| to |exports|.
+    1.  Let |moduleRecord| be [=!=] [=CreateSyntheticModule=](|exports|, the following steps,
+        |realm|, undefined), with the following steps:
+        1.  [=list/For each=] |member| of |module|'s [=module/module members|members=]:
+            1.  Let |id| be |member|'s [=identifier=].
+            1.  If |member| is an [=interface=]:
+                1.  Let |interfaceObject| be the result of [=create an interface object|creating
+                    an interface object=] for |member| with |id| in |realm|.
+                1.  Perform [=!=] [=SetSyntheticModuleExport=](|moduleRecord|, |id|,
+                    |interfaceObject|).
+            1.  Otherwise, if |member| is an [=operation=]:
+                1.  Let |method| be the result of [=creating an operation function=] given
+                    |member|, |module|, and |realm|.
+                1.  Perform [=!=] [=SetSyntheticModuleExport=](|moduleRecord|, |id|, |method|).
+            1.  Otherwise:
+                1.  Assert: |member| is an [=attribute=] or a [=partial interface=].

Seeing this here makes me think that yes, we should exclude partial interfaces. (Which is an inline issue above.)

-- 
You are receiving this because you are subscribed to this thread.
Reply to this email directly or view it on GitHub:
https://github.com/heycam/webidl/pull/675#pullrequestreview-222847403

Received on Thursday, 4 April 2019 15:59:52 UTC