| OLD | NEW |
| 1 Sky Module System | 1 Sky Module System |
| 2 ================= | 2 ================= |
| 3 | 3 |
| 4 This document describes the Sky module system. | 4 This document describes the Sky module system. |
| 5 | 5 |
| 6 Overview | 6 Overview |
| 7 -------- | 7 -------- |
| 8 | 8 |
| 9 The Sky module system is based on the ``import`` element. In its | 9 The Sky module system is based on the ``import`` element. In its |
| 10 most basic form, you import a module as follows: | 10 most basic form, you import a module as follows: |
| (...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 48 all the modules referenced by ``<import>`` element up to that | 48 all the modules referenced by ``<import>`` element up to that |
| 49 ``<script>`` element and all the libraries defined by ``<script>`` | 49 ``<script>`` element and all the libraries defined by ``<script>`` |
| 50 elements up to that point, interleaved so as to maintain the same | 50 elements up to that point, interleaved so as to maintain the same |
| 51 relative order as those elements were first seen by the parser. | 51 relative order as those elements were first seen by the parser. |
| 52 | 52 |
| 53 When a library imports a module, it actually imports all the libraries | 53 When a library imports a module, it actually imports all the libraries |
| 54 that were declared by that module except the aforementioned element | 54 that were declared by that module except the aforementioned element |
| 55 tree library. | 55 tree library. |
| 56 | 56 |
| 57 At the end of the ``<script>`` block's source, if it parsed correctly | 57 At the end of the ``<script>`` block's source, if it parsed correctly |
| 58 and completely, the following code is appended: | 58 and completely, the conceptual equivalent of the following code is |
| 59 appended (but without affecting the library's list of declarations and |
| 60 without any possibility of it clashing with identifiers described in |
| 61 the library itself): |
| 59 | 62 |
| 60 ```dart | 63 ```dart |
| 61 class _ { } | 64 class _ { } |
| 62 module.registerElements(reflectClass(_).owner); | 65 void main() { |
| 66 LibraryMirror library = reflectClass(_).owner as LibraryMirror; |
| 67 if (library.declarations.containsKey(#init) && library.declarations[#init] is
MethodMirror) |
| 68 init(); |
| 69 module.init(library); |
| 70 } |
| 63 ``` | 71 ``` |
| 64 | 72 |
| 73 Then, that ``main()`` function is called. |
| 74 |
| 65 TODO(ianh): decide what URL and name we should give the libraries, as | 75 TODO(ianh): decide what URL and name we should give the libraries, as |
| 66 exposed in MirrorSystem.getName(libraryMirror.qualifiedName) etc | 76 exposed in MirrorSystem.getName(libraryMirror.qualifiedName) etc |
| 67 | 77 |
| 68 The ``Module`` class is defined in ``sky:core`` as follows: | 78 The ``Module`` class is defined in ``sky:core`` as follows: |
| 69 | 79 |
| 80 ```dart |
| 70 | 81 |
| 71 TODO(ianh): dartification of the rest of this file | 82 abstract class AbstractModule extends EventTarget { |
| 83 AbstractModule({this.document, this.url}); |
| 72 | 84 |
| 73 ### Exporting element definitions ### | 85 final Document document; // O(1) |
| 86 // the Document of the module or application |
| 74 | 87 |
| 75 When importing a module into another, Sky runs the following steps: | 88 final String url; |
| 76 - let export be the imported module's ``exports`` value | |
| 77 - try to import export | |
| 78 - if that fails: | |
| 79 - try to import each property of export | |
| 80 | 89 |
| 81 "Try to import" a value means to run the following steps: | 90 @nonnull external Future<@nonnull Module> import(String url); // O(Yikes) |
| 82 - if the value is an element constructor (generated by | 91 // load and return the URL at the given Module |
| 83 ``registerElement()``), call this importer module's | 92 // if it's already loaded, the future will resolve immediately |
| 84 ``registerElement()`` with the value | 93 // if loading fails, the future will have an error |
| 85 | 94 |
| 86 ### IDL ### | 95 @nonnull List</*@nonnull*/ Module> getImports(); // O(N) |
| 96 // returns the Module objects of all the imported modules |
| 87 | 97 |
| 88 ```javascript | 98 external registerElement(@nonnull String tagname, @nonnull Type elementClass);
// O(1) |
| 89 dictionary InternalElementOptions { | 99 // registers a tag name with the parser |
| 90 String tagName; | 100 // only useful during parse time |
| 91 Boolean shadow = false; | 101 // verify that tagname isn't null or empty |
| 92 Object prototype = Element; | 102 // verify that elementClass is the Type of a class that extends Element (direc
tly or indirectly, but not via "implements" or "with") |
| 93 } | 103 // (see the @tagname code for an example of how to verify that from dart) |
| 94 interface InternalElementConstructorWithoutShadow { | 104 // verify that there's not already a class registered for this tag name |
| 95 constructor (Module hostModule); | 105 // if there is, then mark this tagname is broken, so that it acts as if it's n
ot registered in the parser, |
| 96 attribute String tagName; | 106 // and, if this is the first time it was marked broken, log a console message
regarding the issue |
| 97 } | 107 // (mention the tag name but not the classes, so that it's not observable that
this currently happens out of order) |
| 98 interface InternalElementConstructorWithShadow { | |
| 99 constructor (Module hostModule); | |
| 100 attribute String tagName; | |
| 101 attribute Boolean shadow; | |
| 102 } | |
| 103 typedef ElementRegistrationOptions (InternalElementOptions or | |
| 104 InternalElementConstructorWithoutShadow or | |
| 105 InternalElementConstructorWithShadow); | |
| 106 | 108 |
| 107 abstract class AbstractModule : EventTarget { | 109 void init(LibraryMirror library) { |
| 108 readonly attribute Document document; // O(1) // the Document of the module or
application | 110 library.declarations.forEach((Symbol s, DeclarationMirror d) { |
| 109 Promise<any> import(String url); // O(Yikes) // returns the module's exports | 111 d.metadata.forEach((InstanceMirror i) { |
| 110 private Array<Module> getImports(); O(N) // returns the Module objects of all
the imported modules | 112 if (i.reflectee is AutomaticMetadata) |
| 111 | 113 i.reflectee.init(d, this); |
| 112 readonly attribute String url; | 114 }); |
| 113 | 115 }); |
| 114 ElementConstructor registerElement(Object options); // O(1) | 116 } |
| 115 // if you call registerElement() with an object that was created by | |
| 116 // registerElement(), it just returns the object after registering it, | |
| 117 // rather than creating a new constructor | |
| 118 // otherwise, it proceeds as follows: | |
| 119 // - if options is a Function (i.e. it is either an | |
| 120 // InternalElementConstructorWithoutShadow object or an | |
| 121 // InternalElementConstructorWithShadow object), then let | |
| 122 // constructor be that function, and let prototype be that | |
| 123 // functions's prototype; otherwise, let constructor be a no-op | |
| 124 // function and let prototype be the prototype property of the | |
| 125 // object passed in (the InternalElementOptions; prototype | |
| 126 // defaults to Element). | |
| 127 // - let shadow be option's shadow property's value coerced to a | |
| 128 // boolean, if the property is present, or else the value false. | |
| 129 // - let tagName be option's tagName property's value. | |
| 130 // - create a new Function that acts as if it had the signature of | |
| 131 // the constructors in the ElementConstructor interface, and that | |
| 132 // runs the follows steps when called: | |
| 133 // - throw if not called as a constructor | |
| 134 // - create an actual element object (the C++-backed object) | |
| 135 // called tagName, along with the specified attributes | |
| 136 // - initialise the shadow tree if shadow is true | |
| 137 // - call constructor, if it's not null, with the module | |
| 138 // within which the new element is being constructed as the | |
| 139 // argument | |
| 140 // - append all the specified children | |
| 141 // - mark that new Function as created by registerElement() so that | |
| 142 // it can be recognised if used as an argument to | |
| 143 // registerElement() | |
| 144 // - let that new Function's prototype be the aforementioned prototype | |
| 145 // - let that new Function have tagName and shadow properties set to | |
| 146 // the aforementioned tagName and shadow | |
| 147 // - register the new tagName with this constructor | |
| 148 // - return the new Function (which is, not coincidentally, an | |
| 149 // InternalElementConstructorWithShadow) | |
| 150 } | 117 } |
| 151 | 118 |
| 152 class Module : AbstractModule { | 119 class Module : AbstractModule { |
| 153 constructor (Application application, Document document, String url); // O(1) | 120 constructor (Application application, Document document, String url); // O(1) |
| 154 readonly attribute Application application; // O(1) | 121 readonly attribute Application application; // O(1) |
| 155 } | 122 } |
| 156 | 123 |
| 157 class Application : AbstractModule { | 124 class Application : AbstractModule { |
| 158 constructor (Document document, GestureManager gestureManager, String url); //
O(1) | 125 constructor (Document document, GestureManager gestureManager, String url); //
O(1) |
| 159 attribute String title; // O(1) | 126 attribute String title; // O(1) |
| (...skipping 23 matching lines...) Expand all Loading... |
| 183 Where ``name_1`` through ``name_n`` are the names bound to the | 150 Where ``name_1`` through ``name_n`` are the names bound to the |
| 184 various named imports in the script element's document, | 151 various named imports in the script element's document, |
| 185 ``source_code`` is the text content of the script element, | 152 ``source_code`` is the text content of the script element, |
| 186 ``source_module`` is the ``Module`` object of the script element's | 153 ``source_module`` is the ``Module`` object of the script element's |
| 187 module, and ``value_1`` through ``value_n`` are the values | 154 module, and ``value_1`` through ``value_n`` are the values |
| 188 exported by the various named imports in the script element's | 155 exported by the various named imports in the script element's |
| 189 document. | 156 document. |
| 190 | 157 |
| 191 When an import fails to load, the ``as`` name for the import gets | 158 When an import fails to load, the ``as`` name for the import gets |
| 192 bound to ``undefined``. | 159 bound to ``undefined``. |
| OLD | NEW |