Skip to content
This repository has been archived by the owner on May 19, 2018. It is now read-only.

exact object type annotations for Flow plugin #104

Merged
merged 4 commits into from Sep 13, 2016
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
26 changes: 20 additions & 6 deletions src/plugins/flow.js
Expand Up @@ -335,7 +335,7 @@ pp.flowParseObjectTypeCallProperty = function (node, isStatic) {
return this.finishNode(node, "ObjectTypeCallProperty");
};

pp.flowParseObjectType = function (allowStatic) {
pp.flowParseObjectType = function (allowStatic, allowExact) {
let nodeStart = this.startNode();
let node;
let propertyKey;
Expand All @@ -345,9 +345,21 @@ pp.flowParseObjectType = function (allowStatic) {
nodeStart.properties = [];
nodeStart.indexers = [];

this.expect(tt.braceL);
let endDelim;
let exact;
if (allowExact && this.match(tt.braceBarL)) {
this.expect(tt.braceBarL);
endDelim = tt.braceBarR;
exact = true;
} else {
this.expect(tt.braceL);
endDelim = tt.braceR;
exact = false;
}

while (!this.match(tt.braceR)) {
nodeStart.exact = exact;

while (!this.match(endDelim)) {
let optional = false;
let startPos = this.state.start, startLoc = this.state.startLoc;
node = this.startNode();
Expand Down Expand Up @@ -383,13 +395,14 @@ pp.flowParseObjectType = function (allowStatic) {
}
}

this.expect(tt.braceR);
this.expect(endDelim);

return this.finishNode(nodeStart, "ObjectTypeAnnotation");
};

pp.flowObjectTypeSemicolon = function () {
if (!this.eat(tt.semi) && !this.eat(tt.comma) && !this.match(tt.braceR)) {
if (!this.eat(tt.semi) && !this.eat(tt.comma) &&
!this.match(tt.braceR) && !this.match(tt.braceBarR)) {
this.unexpected();
}
};
Expand Down Expand Up @@ -510,7 +523,8 @@ pp.flowParsePrimaryType = function () {
return this.flowIdentToTypeAnnotation(startPos, startLoc, node, this.parseIdentifier());

case tt.braceL:
return this.flowParseObjectType();
case tt.braceBarL:
return this.flowParseObjectType(false, true);
Copy link
Member

@danez danez Sep 2, 2016

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If the token === tt.braceLshouldn't the call be this.flowParseObjectType(false, false);. It probably doesn't really change anything but it would be more clear maybe (and saves us one comparison in the flowParseObjectType, although it probably doesn't have an impact.)


case tt.bracketL:
return this.flowParseTupleType();
Expand Down
14 changes: 12 additions & 2 deletions src/tokenizer/index.js
Expand Up @@ -322,6 +322,7 @@ export default class Tokenizer {
let next = this.input.charCodeAt(this.state.pos + 1);
if (next === code) return this.finishOp(code === 124 ? tt.logicalOR : tt.logicalAND, 2);
if (next === 61) return this.finishOp(tt.assign, 2);
if (code === 124 && next === 125 && this.hasPlugin("flow")) return this.finishOp(tt.braceBarR, 2);
return this.finishOp(code === 124 ? tt.bitwiseOR : tt.bitwiseAND, 1);
}

Expand Down Expand Up @@ -404,8 +405,17 @@ export default class Tokenizer {
case 44: ++this.state.pos; return this.finishToken(tt.comma);
case 91: ++this.state.pos; return this.finishToken(tt.bracketL);
case 93: ++this.state.pos; return this.finishToken(tt.bracketR);
case 123: ++this.state.pos; return this.finishToken(tt.braceL);
case 125: ++this.state.pos; return this.finishToken(tt.braceR);

case 123:
if (this.hasPlugin("flow") && this.input.charCodeAt(this.state.pos + 1) == 124) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

=== 124

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

(y)

return this.finishOp(tt.braceBarL, 2);
} else {
++this.state.pos;
return this.finishToken(tt.braceL);
}

case 125:
++this.state.pos; return this.finishToken(tt.braceR);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Needs 2 space indentation.


case 58:
if (this.hasPlugin("functionBind") && this.input.charCodeAt(this.state.pos + 1) === 58) {
Expand Down
2 changes: 2 additions & 0 deletions src/tokenizer/types.js
Expand Up @@ -48,7 +48,9 @@ export const types = {
bracketL: new TokenType("[", {beforeExpr: true, startsExpr: true}),
bracketR: new TokenType("]"),
braceL: new TokenType("{", {beforeExpr: true, startsExpr: true}),
braceBarL: new TokenType("{|", {beforeExpr: true, startsExpr: true}),
braceR: new TokenType("}"),
braceBarR: new TokenType("|}"),
parenL: new TokenType("(", {beforeExpr: true, startsExpr: true}),
parenR: new TokenType(")"),
comma: new TokenType(",", beforeExpr),
Expand Down
2 changes: 1 addition & 1 deletion test/fixtures/flow/type-annotations/107/expected.json
Expand Up @@ -256,4 +256,4 @@
],
"directives": []
}
}
}
5 changes: 5 additions & 0 deletions test/fixtures/flow/type-annotations/108/actual.js
@@ -0,0 +1,5 @@
var a : {| x: number, y: string |} = { x: 0, y: 'foo' };
var b : {| x: number, y: string, |} = { x: 0, y: 'foo' };
var c : {| |} = {};
var d : { a: {| x: number, y: string |}, b: boolean } = { a: { x: 0, y: 'foo' }, b: false };
var e : {| a: { x: number, y: string }, b: boolean |} = { a: { x: 0, y: 'foo' }, b: false };