Skip to content

Commit b88000f

Browse files
Merge pull request #15 from kumavis/static-fix
2 parents d61ed46 + a1dfef9 commit b88000f

File tree

4 files changed

+61
-98
lines changed

4 files changed

+61
-98
lines changed

build.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,13 +24,13 @@ function privateClassElements (str) {
2424

2525
compile('acorn-bigint', './lib/bigint/index.js')
2626
compile('acorn-numeric-separator', './lib/numeric-separator/index.js')
27-
compile('acorn-dynamic-import', './lib/dynamic-import/index.js')
2827
compile('acorn-import-meta', './lib/import-meta/index.js')
2928
compile('acorn-export-ns-from', './lib/export-ns-from/index.js')
3029
compile('acorn-class-fields', './lib/class-fields/index.js', privateClassElements)
3130
compile('acorn-static-class-features', './lib/static-class-features/index.js', privateClassElements)
3231
compile('acorn-private-class-elements', './lib/private-class-elements/index.js', function (str) {
3332
return str.replace('class extends Parser', 'class Parser_ extends Parser')
33+
.replace('new Parser', 'new Parser_')
3434
// it also works with v7
3535
.replace('if (acorn.version.indexOf("6.") != 0 || acorn.version.indexOf("6.0.") == 0) {', 'if (false) {')
3636
})

lib/private-class-elements/index.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ module.exports = function(Parser) {
3535
Parser_.prototype.constructor = Parser_;
3636

3737
Parser_.prototype._branch = function _branch () {
38-
this.__branch = this.__branch || new Parser({ecmaVersion: this.options.ecmaVersion}, this.input)
38+
this.__branch = this.__branch || new Parser_({ecmaVersion: this.options.ecmaVersion}, this.input)
3939
this.__branch.end = this.end
4040
this.__branch.pos = this.pos
4141
this.__branch.type = this.type

lib/static-class-features/index.js

Lines changed: 52 additions & 96 deletions
Original file line numberDiff line numberDiff line change
@@ -2,25 +2,14 @@
22

33
"use strict"
44

5-
var skipWhiteSpace = /(?:\s|\/\/.*|\/\*[^]*?\*\/)*/g
6-
7-
var acorn = require("acorn")
8-
var tt = acorn.tokTypes
9-
10-
function maybeParseFieldValue(field) {
11-
if (this.eat(tt.eq)) {
12-
var oldInFieldValue = this._inStaticFieldValue
13-
this._inStaticFieldValue = true
14-
field.value = this.parseExpression()
15-
this._inStaticFieldValue = oldInFieldValue
16-
} else { field.value = null }
17-
}
18-
195
var privateClassElements = require("../private-class-elements")
206

217
module.exports = function(Parser) {
228
var ExtendedParser = privateClassElements(Parser)
239

10+
var acorn = Parser.acorn || require("acorn")
11+
var tt = acorn.tokTypes
12+
2413
return /*@__PURE__*/(function (ExtendedParser) {
2514
function anonymous () {
2615
ExtendedParser.apply(this, arguments);
@@ -30,107 +19,74 @@ module.exports = function(Parser) {
3019
anonymous.prototype = Object.create( ExtendedParser && ExtendedParser.prototype );
3120
anonymous.prototype.constructor = anonymous;
3221

33-
anonymous.prototype.parseClassElement = function parseClassElement (_constructorAllowsSuper) {
34-
var this$1 = this;
35-
36-
if (this.eat(tt.semi)) { return null }
37-
38-
var node = this.startNode()
22+
anonymous.prototype._maybeParseFieldValue = function _maybeParseFieldValue (field) {
23+
if (this.eat(tt.eq)) {
24+
var oldInFieldValue = this._inStaticFieldScope
25+
this._inStaticFieldScope = this.currentThisScope()
26+
field.value = this.parseExpression()
27+
this._inStaticFieldScope = oldInFieldValue
28+
} else { field.value = null }
29+
};
3930

40-
var tryContextual = function (k, noLineBreak) {
41-
if (typeof noLineBreak == "undefined") { noLineBreak = false }
42-
var start = this$1.start, startLoc = this$1.startLoc
43-
if (!this$1.eatContextual(k)) { return false }
44-
if (this$1.type !== tt.parenL && (!noLineBreak || !this$1.canInsertSemicolon())) { return true }
45-
if (node.key) { this$1.unexpected() }
46-
node.computed = false
47-
node.key = this$1.startNodeAt(start, startLoc)
48-
node.key.name = k
49-
this$1.finishNode(node.key, "Identifier")
50-
return false
31+
// Parse fields
32+
anonymous.prototype.parseClassElement = function parseClassElement (_constructorAllowsSuper) {
33+
if (this.options.ecmaVersion < 8 || !this.isContextual("static")) {
34+
return ExtendedParser.prototype.parseClassElement.apply(this, arguments)
5135
}
5236

53-
node.static = tryContextual("static")
54-
if (!node.static) { return ExtendedParser.prototype.parseClassElement.apply(this, arguments) }
55-
56-
var isGenerator = this.eat(tt.star)
57-
var isAsync = false
58-
if (!isGenerator) {
59-
// Special-case for `async`, since `parseClassMember` currently looks
60-
// for `(` to determine whether `async` is a method name
61-
if (this.options.ecmaVersion >= 8 && this.isContextual("async")) {
62-
skipWhiteSpace.lastIndex = this.pos
63-
var skip = skipWhiteSpace.exec(this.input)
64-
var next = this.input.charAt(this.pos + skip[0].length)
65-
if (next === ";" || next === "=") {
66-
node.key = this.parseIdent(true)
67-
node.computed = false
68-
maybeParseFieldValue.call(this, node)
69-
this.finishNode(node, "FieldDefinition")
70-
this.semicolon()
71-
return node
72-
} else if (this.options.ecmaVersion >= 8 && tryContextual("async", true)) {
73-
isAsync = true
74-
isGenerator = this.options.ecmaVersion >= 9 && this.eat(tt.star)
75-
}
76-
} else if (tryContextual("get")) {
77-
node.kind = "get"
78-
} else if (tryContextual("set")) {
79-
node.kind = "set"
80-
}
37+
var branch = this._branch()
38+
branch.next()
39+
if ([tt.name, tt.bracketL, tt.string, tt.num, this.privateNameToken].indexOf(branch.type) == -1) {
40+
return ExtendedParser.prototype.parseClassElement.apply(this, arguments)
41+
}
42+
if (branch.type == tt.bracketL) {
43+
var count = 0
44+
do {
45+
if (branch.eat(tt.bracketL)) { ++count }
46+
else if (branch.eat(tt.bracketR)) { --count }
47+
else { branch.next() }
48+
} while (count > 0)
49+
} else { branch.next() }
50+
if (branch.type != tt.eq && !branch.canInsertSemicolon() && branch.type != tt.semi) {
51+
return ExtendedParser.prototype.parseClassElement.apply(this, arguments)
8152
}
82-
if (this.type === this.privateNameToken) {
53+
54+
var node = this.startNode()
55+
node.static = this.eatContextual("static")
56+
if (this.type == this.privateNameToken) {
8357
this.parsePrivateClassElementName(node)
84-
if (this.type !== tt.parenL) {
85-
if (node.key.name === "prototype") {
86-
this.raise(node.key.start, "Classes may not have a private static property named prototype")
87-
}
88-
maybeParseFieldValue.call(this, node)
89-
this.finishNode(node, "FieldDefinition")
90-
this.semicolon()
91-
return node
92-
}
93-
} else if (!node.key) {
58+
} else {
9459
this.parsePropertyName(node)
95-
if ((node.key.name || node.key.value) === "prototype" && !node.computed) {
96-
this.raise(node.key.start, "Classes may not have a static property named prototype")
97-
}
98-
}
99-
if (!node.kind) { node.kind = "method" }
100-
this.parseClassMethod(node, isGenerator, isAsync)
101-
if (!node.kind && (node.key.name || node.key.value) === "constructor" && !node.computed) {
102-
this.raise(node.key.start, "Classes may not have a static field named constructor")
10360
}
104-
if (node.kind === "get" && node.value.params.length !== 0) {
105-
this.raiseRecoverable(node.value.start, "getter should have no params")
61+
if ((node.key.type === "Identifier" && node.key.name === "constructor") ||
62+
(node.key.type === "Literal" && !node.computed && node.key.value === "constructor")) {
63+
this.raise(node.key.start, "Classes may not have a field called constructor")
10664
}
107-
if (node.kind === "set" && node.value.params.length !== 1) {
108-
this.raiseRecoverable(node.value.start, "setter should have exactly one param")
109-
}
110-
if (node.kind === "set" && node.value.params[0].type === "RestElement") {
111-
this.raiseRecoverable(node.value.params[0].start, "Setter cannot use rest params")
65+
if ((node.key.name || node.key.value) === "prototype" && !node.computed) {
66+
this.raise(node.key.start, "Classes may not have a static property named prototype")
11267
}
11368

69+
this._maybeParseFieldValue(node)
70+
this.finishNode(node, "FieldDefinition")
71+
this.semicolon()
11472
return node
115-
11673
};
11774

118-
// Parse public static fields
119-
anonymous.prototype.parseClassMethod = function parseClassMethod (method, isGenerator, isAsync, _allowsDirectSuper) {
120-
if (isGenerator || isAsync || method.kind != "method" || !method.static || this.options.ecmaVersion < 8 || this.type == tt.parenL) {
121-
return ExtendedParser.prototype.parseClassMethod.apply(this, arguments)
75+
// Parse private static methods
76+
anonymous.prototype.parsePropertyName = function parsePropertyName (prop) {
77+
if (prop.static && this.type == this.privateNameToken) {
78+
this.parsePrivateClassElementName(prop)
79+
} else {
80+
ExtendedParser.prototype.parsePropertyName.call(this, prop)
12281
}
123-
maybeParseFieldValue.call(this, method)
124-
delete method.kind
125-
method = this.finishNode(method, "FieldDefinition")
126-
this.semicolon()
127-
return method
12882
};
12983

13084
// Prohibit arguments in class field initializers
13185
anonymous.prototype.parseIdent = function parseIdent (liberal, isBinding) {
13286
var ident = ExtendedParser.prototype.parseIdent.call(this, liberal, isBinding)
133-
if (this._inStaticFieldValue && ident.name == "arguments") { this.raise(ident.start, "A static class field initializer may not contain arguments") }
87+
if (this._inStaticFieldScope && this.currentThisScope() === this._inStaticFieldScope && ident.name == "arguments") {
88+
this.raise(ident.start, "A static class field initializer may not contain arguments")
89+
}
13490
return ident
13591
};
13692

test/index.js

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -125,6 +125,13 @@ test('supports class static properties', function (t) {
125125
t.end()
126126
})
127127

128+
test('supports class function named static', function (t) {
129+
t.doesNotThrow(function () {
130+
acorn.parse('class X { static () {} }', { sourceType: 'script' })
131+
})
132+
t.end()
133+
})
134+
128135
test('supports private class static properties', function (t) {
129136
t.doesNotThrow(function () {
130137
acorn.parse('class X { static #x = y }', { sourceType: 'script' })

0 commit comments

Comments
 (0)