diff --git a/modules/specification.md b/modules/specification.md index 1ef7ad6..a4b89b3 100644 --- a/modules/specification.md +++ b/modules/specification.md @@ -1,99 +1,139 @@ -This specification addresses how modules should be written in order to -be interoperable among a class of module systems that can be both client -and server side, secure or insecure, implemented today or supported by -future systems with syntax extensions. These modules are offered -privacy of their top scope, facility for importing singleton objects -from other modules, and exporting their own API. By implication, this -specification defines the minimum features that a module system must -provide in order to support interoperable modules. - - -Require -------- - -1. ``require`` is a Function - 1. The ``require`` function accepts a module identifier. - 1. ``require`` returns the exported API of the foreign module. - 1. If there is a dependency cycle, the foreign module may not have - finished executing at the time it is required by one of its - transitive dependencies; in this case, the object returned by - ``require`` must contain at least the exports that the foreign - module has prepared before the call to require that led to the - current module's execution. - 1. If the requested module cannot be returned, ``require`` must - throw an error. - 1. The ``require`` function may have a ``main`` property. - 1. This attribute, when feasible, should be read-only, don't - delete. - 1. The ``main`` property must either be undefined or be identical - to the ``module`` object in the context of one loaded module. - 1. The ``require`` function may have a ``paths`` attribute, that is - a prioritized Array of path Strings, from high to low, of paths - to top-level module directories. - 1. The ``paths`` property must not exist in "sandbox" (a - secured module system). - 1. The ``paths`` attribute must be referentially identical in all - modules. - 1. Replacing the ``paths`` object with an alternate object may - have no effect. - 1. If the ``paths`` attribute exists, in-place modification of - the contents of ``paths`` must be reflected by corresponding - module search behavior. - 1. If the ``paths`` attribute exists, it may not be an - exhaustive list of search paths, as the loader may - internally look in other locations before or after the - mentioned paths. - 1. If the ``paths`` attribute exists, it is the loader's - prorogative to resolve, normalize, or canonicalize the paths - provided. - -Module Context --------------- - -1. In a module, there is a free variable ``require``, which conforms to - the above definiton. -1. In a module, there is a free variable called ``exports``, that is an - object that the module may add its API to as it executes. - 1. modules must use the ``exports`` object as the only means of - exporting. - 1. In a module, there must be a free variable ``module``, that is - an Object. - 1. The ``module`` object must have a ``id`` property that is the - top-level ``id`` of the module. The ``id`` property must be - such that ``require(module.id)`` will return the exports object - from which the ``module.id`` originated. (That is to say - module.id can be passed to another module, and requiring that - must return the original module). When feasible this property - should be read-only, don't delete. - 1. The ``module`` object may have a ``uri`` String that is the - fully-qualified URI to the resource from which the module was - created. The ``uri`` property must not exist in a sandbox. +This specification establishes a convention for creating a style of +reusable JavaScript modules and systems that will load and link those +modules. + +* Modules are singletons. +* Modules have an implicitly isolated lexical scope. +* Loading may be eager in asynchronous loaders. +* Execution must be lazy. +* With some care, modules may have cyclic dependencies. +* Systems of modules may be isolated but still share the same context. +* Modules may be used both in browsers and servers. + + +Guarantees Made by Module Writers +================================= + +1. A module must only read and write variables in its lexical scope. +1. A module must only assume that its lexical scope contains the free + variables ``require``, ``module``, ``exports``, and ``define`` + beyond those defined by JavaScript. *What constitutes JavaScript is + beyond the scope of this specification and may vary with practical + limits on a module's portability.* +1. A module must only depend on specified behavior of the values + provided to its lexical scope. +1. All calls to ``require`` must be by name from lexical scope. +1. All calls to ``require`` must be given a single string literal as + the argument. +1. For interoperability with loaders that support the following cases, + modules must call ``define`` in their first and only module scope + statement. + * When modules must be **debugged when deployed** on a different + domain than the origin page (perhaps a CDN) in browsers that do + not support cross-origin HTTP request headers (CORS) or the + developer cannot configure the deployment server to provide CORS + headers. JavaScript that is deployed in a debuggable form will + suffer performance penalties since it would preclude + minification and bundling. + * modules must be debugged in browsers that do not support + ``//@sourceURL`` comments **and** (a module build step **or** + module server that add ``define`` calls are not acceptable). +1. Within a ``define`` ``callback``, the variables ``require``, + ``exports``, and ``module`` must use the corresponding values + provided as arguments to the callback instead of those received from + lexical scope. +1. The first argument, ``require``, to a ``define`` ``callback`` must + be named ``require``. + + +Guarantees Made by Module Interpreters +====================================== + +1. The top scope of a module must not be shared with any other module. +1. A ``require`` function must exist in a function's lexical scope. + 1. The ``require`` function must accept a module identifier as its + first and only argument. + 1. ``require`` must return the same value as ``module.exports`` in + the identified module, or must throw an exception while trying. + 1. ``require`` may have a ``main`` property. + 1. The ``require.main`` property may be read-only and + non-configurable. + 1. The ``require.main`` property must be the same value as + ``module`` in the lexical scope of the first module that + began executing in the current system of modules. + 1. The ``require.main`` property must be the same value in + every module. +1. an ``exports`` object must exist in a function's lexical scope. + 1. the ``exports`` object must initially be the same value as + ``module.exports``. +1. A ``module`` object must exist in a function's lexical scope. + 1. The ``module`` object must have an ``id`` property. + 1. The ``module.id`` property must be a module identifier such + that ``require(module.id)`` must return the + ``module.exports`` value when called in this or any module + in the same system of modules. + 1. The ``module.id`` property may be read-only and + non-configurable. + 1. The ``module`` object must have an ``exports`` property. + 1. The ``module.exports`` property must initially be an empty + object. + 1. The ``module.exports`` property must be writable and + configurable. + 1. The ``module`` object may have a ``path`` URL relative to + ``file:///`` + 1. The ``module`` object may have a ``directory`` URL relative to + ``file:///`` + 1. The directory must be the directory containing the ``path``. +1. a ``define`` function must exist in a function's lexical scope. + 1. ``define`` accepts a function ("callback") as its last argument. + 1. ``callback`` accepts ``require``, ``exports``, and ``module``. + 1. ``callback`` must be called with the corresponding values from + the module's lexical scope. + 1. If ``callback`` returns a value other than ``undefined``, the + return value must be assigned to ``module.exports``. Module Identifiers ------------------- +================== -1. A module identifier is a String of "terms" delimited by forward +1. A module identifier is a string of "terms" delimited by forward slashes. -1. A term must be a camelCase identifier, ``.``, or ``..``. -1. Module identifiers may not have file-name extensions like ``.js``. -1. Module identifiers may be "relative" or "top-level". A module +1. A term is either: + 1. any combination of lower-case letters, numbers, and hyphens, + 1. ``.``, or + 1. ``..`` +1. Module identifiers should not have file-name extensions like + ``.js``. +1. Module identifiers may be "relative" or "resolved". A module identifier is "relative" if the first term is ``.`` or ``..``. -1. Top-level identifiers are resolved off the conceptual module name - space root. -1. Relative identifiers are resolved relative to the identifier of the - module in which ``require`` is written and called. +1. Top-level identifiers are resolved relative to ``""``. +1. The ``require`` function in each module resolves relative + identifiers from the corresponding ``module.id``. +1. To resolve a module identifier, + 1. an array of terms must be initialized to an empty array. + 1. For each ordered term in some ordered module identifiers, from + left to right, + 1. no action is taken for ``"."`` terms, + 1. a term is popped off the end of the array for ``".."`` + terms, and + 1. the term is pushed on the end of the array for all other + terms. + 1. The array of terms must be joined with forward slashes, ``"/"`` + to construct the resulting "resolved" identifier. + Unspecified ------------ +=========== This specification leaves the following important points of interoperability unspecified: 1. Whether modules are stored with a database, file system, or factory functions, or are interchangeable with link libraries. -1. Whether a PATH is supported by the module loader for resolving +1. Whether a path is supported by the module loader for resolving module identifiers. +1. Whether other arguments may be provided to ``define`` and how they + are interpreted.