From 6ad299aad5008868384639d8e75c5f829db0ca48 Mon Sep 17 00:00:00 2001 From: Lee Byron Date: Tue, 29 Mar 2016 00:11:59 -0700 Subject: [PATCH] Initial commit --- ESTree.md | 43 ++++ README.md | 120 +++++++++++ spec/index.html | 533 ++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 696 insertions(+) create mode 100644 ESTree.md create mode 100644 README.md create mode 100644 spec/index.html diff --git a/ESTree.md b/ESTree.md new file mode 100644 index 0000000..dc2b681 --- /dev/null +++ b/ESTree.md @@ -0,0 +1,43 @@ +This document specifies the extensions to the [ESTree ES6 AST][] types to +support the "export-ns-from" proposal. + + +# Modules + +## ExportNamedDeclaration + +```js +extend interface ExportNamedDeclaration { + specifiers: [ ExportSpecifier | ExportNamespaceSpecifier ]; +} +``` + +Extends the [ExportNamedDeclaration][], e.g., `export {foo} from "mod";` to +allow a new type of specifier: *ExportNamespaceSpecifier*. + +_Note: When `source` is `null`, having `specifiers` include +*ExportNamespaceSpecifier* results in an invalid state._ + +_Note: Having `specifiers` include more than one *ExportNamespaceSpecifier* +results in an invalid state._ + +_Note: Having `specifiers` include both *ExportSpecifier* and +*ExportNamespaceSpecifier* results in an invalid state._ + + +## ExportNamespaceSpecifier + +```js +interface ExportNamespaceSpecifier <: Node { + type: "ExportNamespaceSpecifier"; + exported: Identifier; +} +``` + +An exported binding `* as ns` in `export * as ns from "mod";`. The `exported` +field refers to the name exported in this module. That name is bound to the +ModuleNameSpace exotic object from the `source` of the parent *ExportNamedDeclaration*. + + +[ESTree ES6 AST]: https://github.com/estree/estree/blob/master/es6.md +[ExportNamedDeclaration]: https://github.com/estree/estree/blob/master/es6.md#exportnameddeclaration diff --git a/README.md b/README.md new file mode 100644 index 0000000..fe4d13f --- /dev/null +++ b/README.md @@ -0,0 +1,120 @@ +# export-ns-from + +## Future ECMAScript Proposal + +**Stage:** 1 + +**Author:** Lee Byron + +**Specification:** [Spec.md](./Spec.md) + +**AST:** [ESTree.md](./ESTree.md) + +**Transpiler:** See Babel's `es7.exportExtensions` option. + +## Problem statement and rationale + +The `export ___ from "module"` statements are a very useful mechanism for +building up "package" modules in a declarative way. In the ECMAScript 2015 spec, +we can: + +* export through a single export with `export {x} from "mod"` +* ...optionally renaming it with `export {x as v} from "mod"` +* We can also spread all exports with `export * from "mod"`. + +These three export-from statements are easy to understand if you understand the +semantics of the similar looking import statements. + +However there is an import statement which does not have corresponding +export-from statement, exporting the ModuleNameSpace object as a named export. + +Example: + +```js +export * as someIdentifier from "someModule"; +``` + + +### Current ECMAScript 2015 Modules: + +Import Statement Form | [[ModuleRequest]] | [[ImportName]] | [[LocalName]] +--------------------- | ----------------- | -------------- | ------------- +`import v from "mod";` | `"mod"` | `"default"` | `"v"` +`import * as ns from "mod";` | `"mod"` | `"*"` | `"ns"` +`import {x} from "mod";` | `"mod"` | `"x"` | `"x"` +`import {x as v} from "mod";` | `"mod"` | `"x"` | `"v"` +`import "mod";` | | | + + +Export Statement Form | [[ModuleRequest]] | [[ImportName]] | [[LocalName]] | [[ExportName]] +--------------------- | ----------------- | -------------- | ------------- | -------------- +`export var v;` | **null** | **null** | `"v"` | `"v"` +`export default function f(){};`| **null** | **null** | `"f"` | `"default"` +`export default function(){};` | **null** | **null** | `"*default*"` | `"default"` +`export default 42;` | **null** | **null** | `"*default*"` | `"default"` +`export {x}`; | **null** | **null** | `"x"` | `"x"` +`export {x as v}`; | **null** | **null** | `"x"` | `"v"` +`export {x} from "mod"`; | `"mod"` | `"x"` | **null** | `"x"` +`export {x as v} from "mod"`; | `"mod"` | `"x"` | **null** | `"v"` +`export * from "mod"`; | `"mod"` | `"*"` | **null** | **null** + + +### Proposed addition: + +Export Statement Form | [[ModuleRequest]] | [[ImportName]] | [[LocalName]] | [[ExportName]] +--------------------- | ----------------- | -------------- | ------------- | -------------- +`export * as ns from "mod";` | `"mod"` | `"*"` | **null** | `"ns"` + + +### Symmetry between import and export + +There's a syntactic symmetry between the export-from statements and the import +statements they resemble. There is also a semantic symmetry; where import +creates a locally named binding, export-from creates an export entry. + +As an example: + +```js +export {v} from "mod"; +``` + +Is symmetric to: + +```js +import {v} from "mod"; +``` + +However, where importing `v` introduces a name in the local scope, export-from +`v` does not alter the local scope, instead creating an export entry. + +The proposed addition follows this same symmetric pattern: + +**Exporting a namespace exotic object without altering local scope:** + +```js +// proposed: +export * as ns from "mod"; +// symmetric to: +import * as ns from "mod"; +``` + +Using the terminology of [Table 40][] and [Table 42][] in ECMAScript 2015, the +export-from form can be created from the symmetric import form by setting +export-from's **[[ExportName]]** to import's **[[LocalName]]** and export-from's +**[[LocalName]]** to **null**. + +[Table 40]: http://www.ecma-international.org/ecma-262/6.0/#table-40 +[Table 42]: http://www.ecma-international.org/ecma-262/6.0/#table-42 + +#### Table showing symmetry + +Statement Form | [[ModuleRequest]] | [[ImportName]] | [[LocalName]] | [[ExportName]] +-------------- | ----------------- | -------------- | -------------- | -------------- +`import v from "mod";` | `"mod"` | `"default"` | `"v"` | +`import {x} from "mod";` | `"mod"` | `"x"` | `"x"` | +`export {x} from "mod";` | `"mod"` | `"x"` | **null** | `"x"` +`import {x as v} from "mod";` | `"mod"` | `"x"` | `"v"` | +`export {x as v} from "mod";` | `"mod"` | `"x"` | **null** | `"v"` +`import * as ns from "mod";` | `"mod"` | `"*"` | `"ns"` | +`export * as ns from "mod";` | `"mod"` | `"*"` | **null** | `"ns"` +`export * from "mod";` | `"mod"` | `"*"` | **null** | **null** (many) diff --git a/spec/index.html b/spec/index.html new file mode 100644 index 0000000..3f47e93 --- /dev/null +++ b/spec/index.html @@ -0,0 +1,533 @@ + + +
+title: ECMAScript export ns from
+stage: 1
+location: https://github.com/leebyron/ecmascript-export-ns-from
+copyright: false
+contributors: Lee Byron
+
+ + + + + + +

Introduction

+ +

This proposal adds a new form of "export from" which exports another module's namespace + exotic object as an exported name of another, filling a use case similar to the use cases + for existing "export from" forms.

+ +

See the proposal repository for more information.

+ + +

This spec proposal is written as a diff against the existing ECMAScript specification.

+
+
+ + + +

ECMAScript Language: Scripts and Modules

+ + + +

Modules

+ + + +

Module Semantics

+ + + +

Source Text Module Records

+ + +

Table 42 gives examples of the ExportEntry record fields used to represent the syntactic export forms:

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ Export Statement Form + + [[ExportName]] + + [[ModuleRequest]] + + [[ImportName]] + + [[LocalName]] +
+ `export var v;` + + `"v"` + + *null* + + *null* + + `"v"` +
+ `export default function f(){}` + + `"default"` + + *null* + + *null* + + `"f"` +
+ `export default function(){}` + + `"default"` + + *null* + + *null* + + `"*default*"` +
+ `export default 42;` + + `"default"` + + *null* + + *null* + + `"*default*"` +
+ `export {x};` + + `"x"` + + *null* + + *null* + + `"x"` +
+ `export {v as x};` + + `"x"` + + *null* + + *null* + + `"v"` +
+ `export {x} from "mod";` + + `"x"` + + `"mod"` + + `"x"` + + *null* +
+ `export {v as x} from "mod";` + + `"x"` + + `"mod"` + + `"v"` + + *null* +
+ `export * from "mod";` + + *null* + + `"mod"` + + `"*"` + + *null* +
+ `export * as ns from "mod";` + + *null* + + `"mod"` + + `"*"` + + `"ns"` +
+
+
+
+ +
+ + + +

Exports

+

Syntax

+ + + ExportDeclaration : + `export` VariableStatement + `export` Declaration + `export` `default` HoistableDeclaration[Default] + `export` `default` ClassDeclaration[Default] + `export` `default` [lookahead <! {`function`, `class`}] AssignmentExpression[In] `;` + + + + ExportDeclaration : + `export` `*` FromClause `;` + `export` ExportClause FromClause `;` + `export` ExportClause `;` + + + + + ExportDeclaration : + `export` ExportFromClause FromClause `;` + `export` NamedExports `;` + + ExportFromClause : + `*` + NamedExports + NameSpaceExport + + NameSpaceExport : + `*` `as` IdentifierName + + + + + + ExportClause : + `{` `}` + `{` ExportsList `}` + `{` ExportsList `,` `}` + + + + + NamedExports : + `{` `}` + `{` ExportsList `}` + `{` ExportsList `,` `}` + + + Renaming |ExportClause| to |NamedExports| reflects the similarly + named |NamedImports|, and should be reflected throughout the spec. + + + ExportsList : + ExportSpecifier + ExportsList `,` ExportSpecifier + + ExportSpecifier : + IdentifierName + IdentifierName `as` IdentifierName + + + + +

Static Semantics: BoundNames

+ + + ExportDeclaration : + `export` `*` FromClause `;` + `export` ExportClause FromClause `;` + `export` ExportClause `;` + + + + + ExportDeclaration : + `export` ExportFromClause FromClause `;` + `export` NamedExports `;` + + + + 1. Return a new empty List. + +
+ + + +

Static Semantics: ExportedBindings

+ + + ExportDeclaration : + `export` ExportClause FromClause `;` + `export` `*` FromClause `;` + + + + + ExportDeclaration : + `export` ExportFromClause FromClause `;` + + + + 1. Return a new empty List. + +
+ + + +

Static Semantics: ExportedNames

+ + ExportDeclaration : `export` `*` FromClause `;` + + 1. Return a new empty List. + + + ExportDeclaration : + `export` ExportClause FromClause `;` + `export` ExportClause `;` + + + 1. Return the ExportedNames of |ExportClause|. + + + + + ExportDeclaration : `export` ExportFromClause FromClause `;` + + 1. Return the ExportedNames of ExportFromClause. + + ExportFromClause : `*` + + 1. Return a new empty List. + + ExportFromClause : NamedExports + + 1. Return the ExportedNames of |NamedExports|. + + ExportFromClause : NameSpaceExport + + 1. Return the ExportedNames of |NameSpaceExport|. + + +
+ + + +

Static Semantics: ExportEntries

+ + ExportDeclaration : `export` `*` FromClause `;` + + 1. Let _module_ be the sole element of ModuleRequests of |FromClause|. + 1. Let _entry_ be the Record {[[ModuleRequest]]: _module_, [[ImportName]]: `"*"`, [[LocalName]]: *null*, [[ExportName]]: *null* }. + 1. Return a new List containing _entry_. + + ExportDeclaration : `export` ExportClause FromClause `;` + + 1. Let _module_ be the sole element of ModuleRequests of |FromClause|. + 1. Return ExportEntriesForModule of |ExportClause| with argument _module_. + + + + ExportDeclaration : `export` ExportFromClause FromClause `;` + + 1. Let _module_ be the sole element of ModuleRequests of |FromClause|. + 1. Return ExportEntriesForModule of |ExportFromClause| with argument _module_. + + +
+ + + +

Static Semantics: ExportEntriesForModule

+

With parameter _module_.

+ + ExportFromClause : `*` + + 1. Return a new List containing the Record {[[ModuleRequest]]: _module_, [[ImportName]]: "*", [[LocalName]]: null, [[ExportName]]: null }. + + NameSpaceExport : `*` as IdentifierName + + 1. Let _exportName_ be the StringValue of |IdentifierName|. + 1. Return a new List containing the Record {[[ModuleRequest]]: _module_, [[ImportName]]: "*", [[LocalName]]: null, [[ExportName]]: _exportName_ }. + + +
+ + + +

Static Semantics: IsConstantDeclaration

+ + + ExportDeclaration : + `export` `*` FromClause `;` + `export` ExportClause FromClause `;` + `export` ExportClause `;` + `export` `default` AssignmentExpression `;` + + + + + ExportDeclaration : + `export` ExportFromClause FromClause `;` + `export` NamedExports `;` + `export` `default` AssignmentExpression `;` + + + + 1. Return *false*. + +
+ + + +

Static Semantics: LexicallyScopedDeclarations

+ + + ExportDeclaration : + `export` `*` FromClause `;` + `export` ExportClause FromClause `;` + `export` ExportClause `;` + `export` VariableStatement + + + + + ExportDeclaration : + `export` ExportFromClause FromClause `;` + `export` NamedExports `;` + `export` VariableStatement + + + + 1. Return a new empty List. + +
+ + + +

Static Semantics: ModuleRequests

+ + + ExportDeclaration : `export` `*` FromClause `;` + + ExportDeclaration : `export` ExportClause FromClause `;` + + + + + ExportDeclaration : `export` ExportFromClause FromClause `;` + + + + 1. Return the ModuleRequests of |FromClause|. + +
+ + + +

Runtime Semantics: Evaluation

+ + + ExportDeclaration : + `export` `*` FromClause `;` + `export` ExportClause FromClause `;` + `export` ExportClause `;` + + + + + ExportDeclaration : + `export` ExportFromClause FromClause `;` + `export` NamedExports `;` + + + + 1. Return NormalCompletion(~empty~). + +
+
+
+