1"use strict" 2 3const skipWhiteSpace = /(?:\s|\/\/.*|\/\*[^]*?\*\/)*/g 4 5const acorn = require('internal/deps/acorn/acorn/dist/acorn') 6const tt = acorn.tokTypes 7 8function maybeParseFieldValue(field) { 9 if (this.eat(tt.eq)) { 10 const oldInFieldValue = this._inStaticFieldValue 11 this._inStaticFieldValue = true 12 field.value = this.parseExpression() 13 this._inStaticFieldValue = oldInFieldValue 14 } else field.value = null 15} 16 17const privateClassElements = require("internal/deps/acorn-plugins/acorn-private-class-elements/index") 18 19module.exports = function(Parser) { 20 const ExtendedParser = privateClassElements(Parser) 21 22 return class extends ExtendedParser { 23 // Parse private fields 24 parseClassElement(_constructorAllowsSuper) { 25 if (this.eat(tt.semi)) return null 26 27 const node = this.startNode() 28 29 const tryContextual = (k, noLineBreak) => { 30 if (typeof noLineBreak == "undefined") noLineBreak = false 31 const start = this.start, startLoc = this.startLoc 32 if (!this.eatContextual(k)) return false 33 if (this.type !== tt.parenL && (!noLineBreak || !this.canInsertSemicolon())) return true 34 if (node.key) this.unexpected() 35 node.computed = false 36 node.key = this.startNodeAt(start, startLoc) 37 node.key.name = k 38 this.finishNode(node.key, "Identifier") 39 return false 40 } 41 42 node.static = tryContextual("static") 43 if (!node.static) return super.parseClassElement.apply(this, arguments) 44 45 let isGenerator = this.eat(tt.star) 46 let isAsync = false 47 if (!isGenerator) { 48 // Special-case for `async`, since `parseClassMember` currently looks 49 // for `(` to determine whether `async` is a method name 50 if (this.options.ecmaVersion >= 8 && this.isContextual("async")) { 51 skipWhiteSpace.lastIndex = this.pos 52 let skip = skipWhiteSpace.exec(this.input) 53 let next = this.input.charAt(this.pos + skip[0].length) 54 if (next === ";" || next === "=") { 55 node.key = this.parseIdent(true) 56 node.computed = false 57 maybeParseFieldValue.call(this, node) 58 this.finishNode(node, "FieldDefinition") 59 this.semicolon() 60 return node 61 } else if (this.options.ecmaVersion >= 8 && tryContextual("async", true)) { 62 isAsync = true 63 isGenerator = this.options.ecmaVersion >= 9 && this.eat(tt.star) 64 } 65 } else if (tryContextual("get")) { 66 node.kind = "get" 67 } else if (tryContextual("set")) { 68 node.kind = "set" 69 } 70 } 71 if (this.type === this.privateNameToken) { 72 this.parsePrivateClassElementName(node) 73 if (this.type !== tt.parenL) { 74 if (node.key.name === "prototype") { 75 this.raise(node.key.start, "Classes may not have a private static property named prototype") 76 } 77 maybeParseFieldValue.call(this, node) 78 this.finishNode(node, "FieldDefinition") 79 this.semicolon() 80 return node 81 } 82 } else if (!node.key) { 83 this.parsePropertyName(node) 84 if ((node.key.name || node.key.value) === "prototype" && !node.computed) { 85 this.raise(node.key.start, "Classes may not have a static property named prototype") 86 } 87 } 88 if (!node.kind) node.kind = "method" 89 this.parseClassMethod(node, isGenerator, isAsync) 90 if (!node.kind && (node.key.name || node.key.value) === "constructor" && !node.computed) { 91 this.raise(node.key.start, "Classes may not have a static field named constructor") 92 } 93 if (node.kind === "get" && node.value.params.length !== 0) { 94 this.raiseRecoverable(node.value.start, "getter should have no params") 95 } 96 if (node.kind === "set" && node.value.params.length !== 1) { 97 this.raiseRecoverable(node.value.start, "setter should have exactly one param") 98 } 99 if (node.kind === "set" && node.value.params[0].type === "RestElement") { 100 this.raiseRecoverable(node.value.params[0].start, "Setter cannot use rest params") 101 } 102 103 return node 104 105 } 106 107 // Parse public static fields 108 parseClassMethod(method, isGenerator, isAsync, _allowsDirectSuper) { 109 if (isGenerator || isAsync || method.kind != "method" || !method.static || this.options.ecmaVersion < 8 || this.type == tt.parenL) { 110 return super.parseClassMethod.apply(this, arguments) 111 } 112 maybeParseFieldValue.call(this, method) 113 delete method.kind 114 method = this.finishNode(method, "FieldDefinition") 115 this.semicolon() 116 return method 117 } 118 119 // Prohibit arguments in class field initializers 120 parseIdent(liberal, isBinding) { 121 const ident = super.parseIdent(liberal, isBinding) 122 if (this._inStaticFieldValue && ident.name == "arguments") this.raise(ident.start, "A static class field initializer may not contain arguments") 123 return ident 124 } 125 } 126} 127