Skip to content
This repository was archived by the owner on Apr 16, 2020. It is now read-only.

Commit b265436

Browse files
guybedfordMylesBorins
authored andcommitted
specify import file specifier resolution proposal
1 parent 7bf886a commit b265436

File tree

1 file changed

+111
-20
lines changed

1 file changed

+111
-20
lines changed

doc/api/esm.md

Lines changed: 111 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -55,10 +55,6 @@ property:
5555

5656
## Notable differences between `import` and `require`
5757

58-
### Only Support for .mjs
59-
60-
ESM must have the `.mjs` extension.
61-
6258
### Mandatory file extensions
6359

6460
You must provide a file extension when using the `import` keyword.
@@ -157,37 +153,132 @@ The resolver has the following properties:
157153
158154
### Resolver Algorithm
159155
160-
The algorithm to resolve an ES module specifier is provided through
161-
_ESM_RESOLVE_:
156+
The algorithm to load an ES module specifier is given through the
157+
**ESM_RESOLVE** method below. It returns the resolved URL for a
158+
module specifier relative to a parentURL, in addition to the unique module
159+
format for that resolved URL given by the **ESM_FORMAT** routine.
160+
161+
In the following algorithms, all subroutine errors are propogated as errors
162+
of these top-level routines.
162163
163-
**ESM_RESOLVE**(_specifier_, _parentURL_)
164-
> 1. Let _resolvedURL_ be _undefined_.
165-
> 1. If _specifier_ is a valid URL then,
164+
#### ESM_RESOLVE(_specifier_, _parentURL_)
165+
> 1. Let _resolvedURL_ be *undefined*.
166+
> 1. If _specifier_ is a valid URL, then
166167
> 1. Set _resolvedURL_ to the result of parsing and reserializing
167168
> _specifier_ as a URL.
168-
> 1. Otherwise, if _specifier_ starts with _"/"_, _"./"_ or _"../"_ then,
169+
> 1. Otherwise, if _specifier_ starts with _"/"_, then
170+
> 1. Throw an _Invalid Specifier_ error.
171+
> 1. Otherwise, if _specifier_ starts with _"./"_ or _"../"_, then
169172
> 1. Set _resolvedURL_ to the URL resolution of _specifier_ relative to
170173
> _parentURL_.
171174
> 1. Otherwise,
172175
> 1. Note: _specifier_ is now a bare specifier.
173176
> 1. Set _resolvedURL_ the result of
174177
> **PACKAGE_RESOLVE**(_specifier_, _parentURL_).
175-
> 1. If the file at _resolvedURL_ does not exist then,
178+
> 1. If the file at _resolvedURL_ does not exist, then
176179
> 1. Throw a _Module Not Found_ error.
177-
> 1. Return _resolvedURL_.
178-
179-
**PACKAGE_RESOLVE**(_packageSpecifier_, _parentURL_)
180-
> 1. Assert: _packageSpecifier_ is a bare specifier.
181-
> 1. If _packageSpecifier_ is a Node.js builtin module then,
180+
> 1. Let _format_ be the result of **ESM_FORMAT**(_url_).
181+
> 1. Return _{ resolvedURL, format }_.
182+
183+
PACKAGE_RESOLVE(_packageSpecifier_, _parentURL_)
184+
> 1. Let _packageName_ be *undefined*.
185+
> 1. Let _packagePath_ be *undefined*.
186+
> 1. If _packageSpecifier_ does not start with _"@"_, then
187+
> 1. If _packageSpecifier_ is an empty string, then
188+
> 1. Throw an _Invalid Package Name_ error.
189+
> 1. Set _packageName_ to the substring of _packageSpecifier_ until the
190+
> first _"/"_ separator or the end of the string.
191+
> 1. If _packageSpecifier_ starts with _"@"_, then
192+
> 1. If _packageSpecifier_ does not contain a _"/"_ separator, then
193+
> 1. Throw an _Invalid Package Name_ error.
194+
> 1. Set _packageName_ to the substring of _packageSpecifier_
195+
> until the second _"/"_ separator or the end of the string.
196+
> 1. Let _packagePath_ be the substring of _packageSpecifier_ from the
197+
> position at the length of _packageName_ plus one, if any.
198+
> 1. Assert: _packageName_ is a valid package name or scoped package name.
199+
> 1. Assert: _packagePath_ is either empty, or a path without a leading
200+
> separator.
201+
> 1. Note: Further package name validations can be added here.
202+
> 1. If _packagePath_ is empty and _packageName_ is a Node.js builtin
203+
> module, then
182204
> 1. Return the string _"node:"_ concatenated with _packageSpecifier_.
183-
> 1. While _parentURL_ contains a non-empty _pathname_,
205+
> 1. While _parentURL_ is not the file system root,
184206
> 1. Set _parentURL_ to the parent folder URL of _parentURL_.
185207
> 1. Let _packageURL_ be the URL resolution of the string concatenation of
186-
> _parentURL_, _"/node_modules/"_ and _"packageSpecifier"_.
187-
> 1. If the file at _packageURL_ exists then,
188-
> 1. Return _packageURL_.
208+
> _parentURL_, _"/node_modules/"_ and _packageSpecifier_.
209+
> 1. If the folder at _packageURL_ does not exist, then
210+
> 1. Note: This check can be optimized out where possible in
211+
> implementation.
212+
> 1. Set _parentURL_ to the parent URL path of _parentURL_.
213+
> 1. Continue the next loop iteration.
214+
> 1. If _packagePath_ is empty, then
215+
> 1. Let _url_ be the result of **PACKAGE_MAIN_RESOLVE**(_packageURL_).
216+
> 1. If _url_ is *null*, then
217+
> 1. Throw a _Module Not Found_ error.
218+
> 1. Return _url_.
219+
> 1. Otherwise,
220+
> 1. Return the URL resolution of _packagePath_ in _packageURL_.
189221
> 1. Throw a _Module Not Found_ error.
190222
223+
PACKAGE_MAIN_RESOLVE(_packageURL_)
224+
> 1. Let _pjsonURL_ be the URL of the file _"package.json"_ within the parent
225+
path _packageURL_.
226+
> 1. If the file at _pjsonURL_ exists, then
227+
> 1. Let _pjson_ be the result of **READ_JSON_FILE**(_pjsonURL_).
228+
> 1. If **HAS_ESM_PROPERTIES**(_pjson_) is *true*, then
229+
> 1. Let _mainURL_ be the result applying the legacy
230+
> **LOAD_AS_DIRECTORY** CommonJS resolver to _packageURL_, returning
231+
> *undefined* for no resolution.
232+
> 1. If _mainURL_ is not *undefined* and **ESM_FORMAT**(_mainURL_) is not
233+
> equal to _"cjs"_, then
234+
> 1. Throw a _"Invalid Module Format"_ error.
235+
> 1. Return _mainURL_.
236+
> 1. _Note: ESM main yet to be implemented here._
237+
> 1. Return *null*.
238+
239+
#### ESM_FORMAT(_url_)
240+
> 1. Assert: _url_ corresponds to an existing file.
241+
> 1. Let _pjsonURL_ be the result of **READ_PACKAGE_BOUNDARY**(_url_).
242+
> 1. Let _pjson_ be *undefined*.
243+
> 1. If _pjsonURL_ is not *null*, then
244+
> 1. Set _pjson_ to the result of **READ_JSON_FILE**(_pjsonURL_).
245+
> 1. If _pjsonURL_ is *null* or **HAS_ESM_PROPERTIES**(_pjson_) is *true*, then
246+
> 1. If _url_ does not end in _".js"_ or _".mjs"_ then,
247+
> 1. Throw an _Unkonwn Module Format_ error.
248+
> 1. Return _"esm"_.
249+
> 1. Otherwise,
250+
> 1. If _url_ does not end in _".js"_ then,
251+
> 1. Throw an _Unknown Module Format_ error.
252+
> 1. Return _"cjs"_.
253+
254+
> 1. If **HAS_ESM_PROPERTIES**(_pjson_) is *true*, then
255+
> 1. Return _"esm"_.
256+
> 1. Return _"cjs"_.
257+
258+
READ_PACKAGE_BOUNDARY(_url_)
259+
> 1. Let _boundaryURL_ be the URL resolution of _"package.json"_ relative to
260+
> _url_.
261+
> 1. While _boundaryURL_ is not the file system root,
262+
> 1. If the file at _boundaryURL_ exists, then
263+
> 1. Return _boundaryURL_.
264+
> 1. Set _boundaryURL_ to the URL resolution of _"../package.json"_ relative
265+
> to _boundaryURL_.
266+
> 1. Return *null*.
267+
268+
READ_JSON_FILE(_url_)
269+
> 1. If the file at _url_ does not parse as valid JSON, then
270+
> 1. Throw an _Invalid Package Configuration_ error.
271+
> 1. Let _pjson_ be the parsed JSON source of the file at _url_.
272+
> 1. Return _pjson_.
273+
274+
HAS_ESM_PROPERTIES(_pjson_)
275+
> 1. Note: To be specified.
276+
277+
_ESM properties_ in a package.json file are yet to be specified.
278+
The current possible specifications for this are the
279+
[_"exports"_](https://github.com/jkrems/proposal-pkg-exports)
280+
or [_"mode"_](https://github.com/nodejs/node/pull/18392) flag.
281+
191282
[Node.js EP for ES Modules]: https://github.com/nodejs/node-eps/blob/master/002-es-modules.md
192283
[`module.createRequireFromPath()`]: modules.html#modules_module_createrequirefrompath_filename
193284
[ESM Minimal Kernel]: https://github.com/nodejs/modules/blob/master/doc/plan-for-new-modules-implementation.md

0 commit comments

Comments
 (0)