Ecosyste.ms: Awesome

An open API service indexing awesome lists of open source software.

Awesome Lists | Featured Topics | Projects

https://github.com/jayphelps/brainstorming

Brainstorming
https://github.com/jayphelps/brainstorming

Last synced: 21 days ago
JSON representation

Brainstorming

Awesome Lists containing this project

README

        

# 1 Motivating examples:

## 1.1 Conditional implementation

Conditional code generation:

```TypeScript
class Debug {
@conditional("debug")
static assert(condition: boolean, message?: string): void;
}

Debug.assert(false); // if window.debug is not defined Debug.assert is replaced by an empty function
```

## 1.2 Observable and computed properties

Consider the Ember.js alias-like definition:

```TypeScript
class Person {
    constructor(public firstName: string, public lastName: string) { }

   @computed('firstName', 'lastName', (f, l) => l + ', ' + f)
    fullName: string;
}

var david = new Person('David', 'Tang');
david.fullName; /// Tang, David
```

## 1.3 Dynamic Instantiation/Dependency Injection (composition)

Consider Angular 2.0 DI implementation example:

```TypeScript
class Engine {
}

class Car {
    constructor(@Inject(Engine) engine: Engine) {}
}

var inj = new Injector([Car, Engine]);

// AtScript compilation step adds a property “annotations” on Car of value [ new Inject(Engine) ].
// At runtime, a call to inj.get would cause Angular to look for annotations, and try to satisfy dependencies.
// in this case first by creating a new instance of Engine if it does not exist, and use it as a parameter to Car’s constructor
var car = inj.get(Car);
```

## 1.4 Attaching Meta data to functions/objects

Metadata that can be queried at runtime, for example:

```TypeScript
class Fixture {
@isTestable(true)
getValue(a: number): string {
    return a.toString();
}
}

// Desired JS
class Fixture {
getValue(a) {
    return a.toString();
}
}
Fixture.prototype.getValue.meta.isTestable = true;

// later on query the meta data
function isTestableFunction(func) {
    return !!(func && func.meta && func.meta.isTestable);
}
```

## 1.5 Design-time extensibility

An extensible way to declare properties on or associate special behavior to declarations; design time tools can leverage these associations to produce errors or produce documentation. For example:

Deprecated, to support warning on use of specific API’s:

```TypeScript
interface JQuery {
    /**
     * A selector representing selector passed to jQuery(), if any, when creating the original set.
    * version deprecated: 1.7, removed: 1.9
     */
    @deprecated("Property is only maintained to the extent needed for supporting .live() in the jQuery Migrate plugin. It may be removed without notice in a future version.", false)
    selector: string;
}
```

Suppress linter warning:

```TypeScript
@suppressWarning("disallow-leading-underscore")
function __init() {
}
```

# 2 Proposal

A decorator is defined as a function accepting the decorator’s target as an argument:

```TypeScript
// A simple decorator
@annotation
class MyClass { }

function annotation(target) {
// Add a property on target
target.annotated = true;
}
```

Alternatively a decorator factory can be specified accepting additional arguments:

```TypeScript
@isTestable(true)
class MyClass { }

function isTestable(value) {
return function decorator(target) {
target.isTestable = value;
}
}
```

A decorator can also alter the target:

```TypeScript
@log
var func = function() {
...
};

function log(target) {
return function() {
target.apply(this, arguments);
console.log("Function called!");
};
}
```

A decorator decorating a class or object literal members and accessor operate on the descriptor:

```TypeScript
class C {
    @enumerable(false)
    method() { }
}

function enumerable(value) {
return function (target, key, propertyDescriptor) {
propertyDescriptor.enumerable = value;
return propertyDescriptor;
}
}
```

# 3 Transformation details:

## 3.1 Introduction

This section shows the desugaring/compilation of the annotation forms to their corresponding ES5 and ES6.

## 3.2 Class Declaration

### 3.2.1 Syntax

```TypeScript
@F("color")
@G
class Foo {
}
```

### 3.2.2 Desugaring (ES6)

```TypeScript
var Foo = (function () {
class Foo {
}

Foo = F("color")(Foo = G(Foo) || Foo) || Foo;
return Foo;
})();
```

### 3.2.3 Desugaring (ES5)

```TypeScript
var Foo = (function () {
function Foo() {
}

Foo = F("color")(Foo = G(Foo) || Foo) || Foo;
return Foo;
})();
```

## 3.3 Function Expression

### 3.3.1 Syntax

```TypeScript
var funcExpr = @F("color") @G function() { }
```

### 3.3.2 Desugaring

```TypeScript
var funcExpr = (function () {
var _t = function() {}
_t = F("color")(_t = G(_t) || _t) || _t;
return _t;
})();
```

## 3.4 Class Parameter Declaration

### 3.4.1 Syntax

```TypeScript
class Foo {
constructor(@F("color") @G param0) {
}
}
```

### 3.4.2 Desugaring (ES6)

```TypeScript
var Foo = (function () {
class Foo {
constructor(param0) {
}
}

F("color")((G(Foo, 0), Foo), 0);
return Foo;
})();
```

### 3.4.3 Desugaring (ES5)

```TypeScript
var Foo = (function () {
function Foo(param0) {
}

F("color")((G(Foo, 0), Foo), 0);
return Foo;
})();
```

## 3.5 Class Method Declaration

### 3.5.1 Syntax

```TypeScript
class Foo {
@F("color")
@G
bar() { }
}
```

### 3.5.2 Desugaring (ES6)

```TypeScript
var Foo = (function () {
class Foo {
bar() { }
}

var _temp;
_temp = F("color")(Foo.prototype, "bar",
_temp = G(Foo.prototype, "bar",
_temp = Object.getOwnPropertyDescriptor(Foo.prototype, "bar")) || _temp) || _temp;
if (_temp) Object.defineProperty(Foo.prototype, "bar", _temp);
return Foo;
})();
```

### 3.5.3 Desugaring (ES5)

```TypeScript
var Foo = (function () {
function Foo() {
}
Foo.prototype.bar = function () { }

var _temp;
_temp = F("color")(Foo.prototype, "bar",
_temp = G(Foo.prototype, "bar",
_temp = Object.getOwnPropertyDescriptor(Foo.prototype, "bar")) || _temp) || _temp;
if (_temp) Object.defineProperty(Foo.prototype, "bar", _temp);
return Foo;
})();
```

### 3.5.4 By-hand for annotations not requiring descriptors (ES5)

```TypeScript
var Foo = (function () {
function Foo() {
}
Foo.prototype.bar = function () { }

G(Foo.prototype, "bar");
F("color")(Foo.prototype, "bar");

return Foo;
})();
```

## 3.6 Class Accessor Declaration

### 3.6.1 Syntax

```TypeScript
class Foo {
@F("color")
@G
get bar() { }
set bar(value) { }
}
```

### 3.6.2 Desugaring (ES6)

```TypeScript
var Foo = (function () {
class Foo {
get bar() { }
set bar(value) { }
}

var _temp;
_temp = F("color")(Foo.prototype, "bar",
_temp = G(Foo.prototype, "bar",
_temp = Object.getOwnPropertyDescriptor(Foo.prototype, "bar")) || _temp) || _temp;
if (_temp) Object.defineProperty(Foo.prototype, "bar", _temp);
return Foo;
})();
```

### 3.6.3 Desugaring (ES5)

```TypeScript
var Foo = (function () {
function Foo() {
}
Object.defineProperty(Foo.prototype, "bar", {
get: function () { },
set: function (value) { }
enumerable: true, configurable: true
});

var _temp;
_temp = F("color")(Foo.prototype, "bar",
_temp = G(Foo.prototype, "bar",
_temp = Object.getOwnPropertyDescriptor(Foo.prototype, "bar")) || _temp) || _temp;
if (_temp) Object.defineProperty(Foo.prototype, "bar", _temp);
return Foo;
})();
```

## 3.7 Object Literal Method Declaration

### 3.7.1 Syntax

```TypeScript
var o = {
@F("color")
@G
bar() { }
}
```

### 3.7.2 Desugaring (ES6)

```TypeScript
var o = (function () {
var _obj = {
bar() { }
}

var _temp;
_temp = F("color")(_obj, "bar",
_temp = G(_obj, "bar",
_temp = void 0) || _temp) || _temp;
if (_temp) Object.defineProperty(_obj, "bar", _temp);
return Foo;
})();
```

### 3.7.3 Desugaring (ES5)

```TypeScript
var o = (function () {
var _obj = {
bar: function () { }
}

var _temp;
_temp = F("color")(_obj, "bar",
_temp = G(_obj, "bar",
_temp = void 0) || _temp) || _temp;
if (_temp) Object.defineProperty(_obj, "bar", _temp);
return Foo;
})();
```

## 3.8 Object Literal Accessor Declaration

### 3.8.1 Syntax

```TypeScript
var o = {
@F("color")
@G
get bar() { }
set bar(value) { }
}
```

### 3.8.2 Desugaring (ES6)

```TypeScript
var o = (function () {
var _obj = {
get bar() { }
set bar(value) { }
}

var _temp;
_temp = F("color")(_obj, "bar",
_temp = G(_obj, "bar",
_temp = void 0) || _temp) || _temp;
if (_temp) Object.defineProperty(_obj, "bar", _temp);
return Foo;
})();
```

### 3.8.3 Desugaring (ES5)

```TypeScript
var o = (function () {
var _obj = {
}
Object.defineProperty(_obj, "bar", {
get: function () { },
set: function (value) { }
enumerable: true, configurable: true
});

var _temp;
_temp = F("color")(_obj, "bar",
_temp = G(_obj, "bar",
_temp = void 0) || _temp) || _temp;
if (_temp) Object.defineProperty(_obj, "bar", _temp);
return Foo;
})();
```

# 4 Examples

### 4.1 Inject

```TypeScript
// TypeScript Souce
function Inject(@type type: Function) {
return function (constructor) {
constructor.annotate = constructor.annotate || [];
constructor.annotate.push(new inject(type));
}
}

class Engine {
}

class Car {
constructor(@Inject() engine: Engine) {
}
}

// ES3/ES5
var Car = (function () {
function Car(engine) {
}

Inject(/* @type */ Engine)(Car, /* paramterIndex */ 0);

return Car;
})();

// ES7 decorator proposal
class Car {
constructor(@Inject(Engine) engine) {
}
}
```

### 4.2 Component

```TypeScript
// TypeScript Souce
function Component(options, @parameterTypes types?: Function[]) {
return function (constructor) {
constructor.annotate = constructor.annotate || [];
constructor.annotate.push(new component(options));
constructor.parameters = types;
}
}

@Component({
selector: 'b'
})
class MyComponent {
constructor(server: Server, service: Service) { }
}

// ES3/ES5
var MyComponent = (function () {
function MyComponent(server, service) {
}

MyComponent = Component({ selector: 'b' }, /* @parameterTypes */[Server, Service])(MyComponent) || MyComponent;

return MyComponent;
})();

// ES7 decorator proposal
@Component({
selector: 'b'
}, [Server, Service])
class MyComponent {
constructor(server, service) { }
}
```

# A Grammar

## A.1 Expressions

  *DecoratorList* [Yield] :
   *DecoratorList* [?Yield]opt  *Decorator* [?Yield]

  *Decorator* [Yield] :
   `@` *AssignmentExpression* [?Yield]

  *PropertyDefinition* [Yield] :
   *IdentifierReference* [?Yield]
   *CoverInitializedName* [?Yield]
   *PropertyName* [?Yield]  `:` *AssignmentExpression* [In, ?Yield]
   *DecoratorList* [?Yield]opt *MethodDefinition* [?Yield]

  *CoverMemberExpressionSquareBracketsAndComputedPropertyName* [Yield] :
   `[` *Expression* [In, ?Yield] `]`

NOTE The production *CoverMemberExpressionSquareBracketsAndComputedPropertyName* is used to cover parsing a *MemberExpression* that is part of a *Decorator* inside of an *ObjectLiteral* or *ClassBody*, to avoid lookahead when parsing a decorator against a *ComputedPropertyName*.

  *PropertyName* [Yield, GeneratorParameter] :
   *LiteralPropertyName*
   [+GeneratorParameter] *CoverMemberExpressionSquareBracketsAndComputedPropertyName*
   [~GeneratorParameter] *CoverMemberExpressionSquareBracketsAndComputedPropertyName* [?Yield]

  *MemberExpression* [Yield]  :
   [Lexical goal *InputElementRegExp*] *PrimaryExpression* [?Yield]
   *MemberExpression* [?Yield] *CoverMemberExpressionSquareBracketsAndComputedPropertyName* [?Yield]
   *MemberExpression* [?Yield] `.` *IdentifierName*
   *MemberExpression* [?Yield] *TemplateLiteral* [?Yield]
   *SuperProperty* [?Yield]
   *NewSuper* *Arguments* [?Yield]
   `new` *MemberExpression* [?Yield] *Arguments* [?Yield]

  *SuperProperty* [Yield] :
   `super` *CoverMemberExpressionSquareBracketsAndComputedPropertyName* [?Yield]
   `super` `.` *IdentifierName*

  *CallExpression* [Yield] :
   *MemberExpression* [?Yield] *Arguments* [?Yield]
   *SuperCall* [?Yield]
   *CallExpression* [?Yield] *Arguments* [?Yield]
   *CallExpression* [?Yield] *CoverMemberExpressionSquareBracketsAndComputedPropertyName* [In, ?Yield]
   *CallExpression* [?Yield] `.` *IdentifierName*
   *CallExpression* [?Yield] *TemplateLiteral* [?Yield]

## A.4 Functions and Classes

  *FormalRestParameter* [Yield] :
   *DecoratorList* [?Yield]opt *BindingRestElement* [?Yield]

  *FormalParameter* [Yield, GeneratorParameter] :
   *DecoratorList* [?Yield]opt *BindingElement* [?Yield, ?GeneratorParameter]

  *FunctionExpression* :
   *DecoratorList* [?Yield]opt `function` *BindingIdentifier* opt `(` *FormalParameters* `)` `{` *FunctionBody* `}`

  *GeneratorExpression* :
   *DecoratorList* [?Yield]opt `function` *BindingIdentifier* [Yield]opt `(` *FormalParameters* [Yield, GeneratorParameter] `)` `{` *GeneratorBody* [Yield] `}`

  *ClassDeclaration* [Yield, Default] :
   *DecoratorList* [?Yield]opt `class` *BindingIdentifier* [?Yield] *ClassTail* [?Yield]
   [+Default] *DecoratorList* [?Yield]opt `class` *ClassTail* [?Yield]

  *ClassExpression* [Yield, GeneratorParameter] :
   *DecoratorList* [?Yield]opt `class` *BindingIdentifier* [?Yield]opt *ClassTail* [?Yield, ?GeneratorParameter]

  *ClassElement* [Yield] :
   *DecoratorList* [?Yield]opt *MethodDefinition* [?Yield]
   *DecoratorList* [?Yield]opt `static` *MethodDefinition* [?Yield]

## A.5 Scripts and Modules

  *ExportDeclaration* :
   `export` `*` *FromClause* `;`
   `export` *ExportClause* *FromClause* `;`
   `export` *ExportClause* `;`
   `export` *VariableStatement*
   `export` *LexicalDeclaration*
   *DecoratorList* opt `export` [lookahead ≠ `@`] *HoistableDeclaration*
   *DecoratorList* opt `export` [lookahead ≠ `@`] *ClassDeclaration*
   *DecoratorList* opt `export` `default` [lookahead ≠ `@`] *HoistableDeclaration* [Default]
   *DecoratorList* opt `export` `default` [lookahead ≠ `@`] *ClassDeclaration* [Default]
   `export` `default` [lookahead  { `function`, `class`, `@` }] *AssignmentExpression* [In] `;`

# B Decorator definitions

```TypeScript
interface TypedPropertyDescriptor {
    enumerable?: boolean;
    configurable?: boolean;
    writable?: boolean;
    value?: T;
    get?: () => T;
    set?: (value: T) => void;
}

interface DecoratorFunction {
    (target: TFunction): TFunction | void;
}

interface ArgumentDecoratorFunction {
    (target: Function, parameterIndex: number): void;
}

interface MemberDecoratorFunction {
    (target: Function | Object, propertyKey: PropertyKey, descriptor: TypedPropertyDescriptor): TypedPropertyDescriptor | void;
}

interface PropertyDecoratorFunction {
    (target: Function | Object, propertyKey: PropertyKey): void;
}

interface DecoratorFactory {
    (...args: any[]): DecoratorFunction;
}

interface ArgumentDecoratorFactory {
    (...args: any[]): ArgumentDecoratorFunction;
}

interface MemberDecoratorFactory {
    (...args: any[]): MemberDecoratorFunction;
}

interface PropertyDecoratorFactory {
    (...args: any[]): PropertyDecoratorFunction;
}
```

# C TypeScript decorators

## C.1 Exposing types

TypeScript compiler will honor special decorator names and will flow additional information into the decorator factory parameters annotated by these decorators. The types provided are in a serialized form. Serialization logic is descriped in C.2

```TypeScript
@F("color")
class Foo {
constructor(a: Object, b: number, c: { a: number }, d: C2) {
}
}

function F(tag: string, @paramterTypes types?: Function[]) {
return function (target) {
target.paramterTypes = types; // [Object, Number, Object, C2]
}
}
```

## C.2 List of supported decorators

@type – The serialized form of the type of the decorator target

@returnType – The serialized form of the return type of the decorator target if it is a function type, undefined otherwise

@paramterTypes – A list of serialized types of the decorator target’s arguments if it is a function type, undefined otherwise

@name – The name of the decorator target

## C.3 Type Serialization:

### C.3.1 Example

```TypeScript
class C { }
interface I { }
enum E { }
module M { }
```

Formal parameter list in a call signature like so:

```TypeScript
(a: number, b: boolean, c: C, i: I, e: E, m: typeof M, f: () => void, o: { a: number; b: string; })
```

Serializes as:

```TypeScript
[Number, Boolean, C, Object, Number, Object, Function, Object]
```

### C.3.2 Details

* number serialized as Number
* string serialized as String
* boolean serialized as Boolean
* any serialized as Object
* void serializes as undefined
* Array serialized as Array
* If a Tuple, serialize as Array
* If a class serialize it as the class constructor
* If an Enum serialize it as Number
* If has at least one call signature, serialize as Function
* Otherwise serialize as Object

### C.3.3 Open issues

* Do we want to enable more elaborate serialization? E.g. `type O = { a: string; b: number }` as `{ a: String, b: Number }` instead of just `Object`.

## C.4 Defining a decorator

* Valid decorators must be annotated by the @decorator -- details below
* A decorator function must return a value that is assignable to what it is decorating to be considered valid.
* @decorator parameters define the usage of the decorator and are enforced by the compiler
* @decorator is defined in lib.d.ts and loaded by the checker when it is initialized, some constraints will be checked like that it is defined as a class with one constructor signature and one argument
* Decorators are only allowed on functions, parameters, or members. Thus, modules, enums, and variable declarations are not valid decorator targets.
* Constructors are not valid decorator targets. Containing classes should be used instead.
* Decorators are emitted in declaration files attached to their declarations, normal visibility rules applies to decorators and their arguments.

```TypeScript

/**
  * Built-in decorator annotation. Used to define a decorator and its properties.
  */
declare function decorator(options?: {
    /**
      * Valid targets for this decorator.
      *
      * default: DecoratorTargets.All
      */
    allowOn?: DecoratorTargets;
   
    /**
      * Indicates whether multiple applications are allowed on the same declaration or not.
      *
      * default: true
      */
    allowMultiple?: boolean;

    /**
      * True indicates that the decorator is for design-time only, and should not be
      * added to the emitted code.
      *
      * default: false
    */
    ambient?: boolean;
});

/**
  * Valid decorator targets
  */
declare const enum DecoratorTargets {
    Class,
    Interface,
    Function,
    Method,
    Property,
    Accessor,
    Parameter,
    All = Class | Interface | Function | Method | Property | Accessor | Parameter
}
```

## C.5 Run-time Decorators

* Runtime decorators are designated by setting { ambient: false } in the options of the @decorator decorator
* Runtime decorators follow their target, decorators targeting ambient declarations are not emitted
* Runtime decorators are not allowed on interfaces

## C.6 Ambient decorators

* Design-time (Ambient) decorators are designated by setting { ambient: true } in the options of the @decorator decorator
* These are decorators that are not emitted. This category include built-in decorator (decorator, conditional, deprecated, etc..)
* For design-time decorator, arguments are restricted to constant values. Variables would not be observable by the compiler at compile time. Here is the set of possible values:
* string literal,
* number literal,
* regexp literal,
* true keyword,
* false keyword,
* null keyword,
* undefined symbol,
* const enum members,
* array literals of one of the previous kinds,
* object literal with only properties with values of one of the previous kinds
* Examples: @conditional, @deprecated, @profile

# D Function declaration support

## D.1 Function Declaration

Since decorator evaluation involved expressions, decorated function declarations cannot be hoisted to the containing scope. Rather they should be treated similar to ES6 classes where only the function’s symbol is hoisted to the top but remains undefined until the definition is encountered.

Note that decorators applied to a function declaration would necessitate a TDZ for the declaration. The desugared emit below illustrates this as the function declaration is evaluated inside an IIFE

### D.1.1 Syntax

```TypeScript
@F("color")
@G
class Func() {
}
```

### D.1.2 Desugaring

```TypeScript
var Func = (function () {
function Func() {
}
Func = F("color")(Func = G(Func) || Func) || Func;
return Func;
})();
```

## D.2 Function Parameter Declaration

### D.2.1 Syntax

```TypeScript
function Func(@F("color") @G param0) {
}
```

### D.2.2 Desugaring

```TypeScript
var Func = (function () {
function Func(param0) {
}

F("color")((G(Func, 0), Func), 0);
return Func;
})();
```
### D.3 Grammar

  *FunctionDeclaration* [Yield, Default] :
   *DecoratorList* [?Yield]opt `function` *BindingIdentifier* [?Yield] `(` *FormalParameters* `)` `{` *FunctionBody* `}`
   [+Default] *DecoratorList* [?Yield]opt `function` `(` *FormalParameters* `)` `{` *FunctionBody* `}`

  *GeneratorDeclaration* [Yield, Default] :
   *DecoratorList* [?Yield]opt `function` `*` *BindingIdentifier* [?Yield] `(` *FormalParameters* [Yield, GeneratorParameter] `)` `{` *GeneratorBody* [Yield] `}`
   [+Default] *DecoratorList* [?Yield]opt `function` `*` `(` *FormalParameters* [Yield, GeneratorParameter] `)` `{` *GeneratorBody* [Yield] `}`