diff --git a/packages/babel-generator/src/generators/classes.js b/packages/babel-generator/src/generators/classes.js index 4d00272c4ce8..db0288e08310 100644 --- a/packages/babel-generator/src/generators/classes.js +++ b/packages/babel-generator/src/generators/classes.js @@ -134,3 +134,18 @@ export function _classMethodHead(node) { this.tsPrintClassMemberModifiers(node, /* isField */ false); this._methodHead(node); } + +export function StaticBlock(node) { + this.word("static"); + this.space(); + this.token("{"); + if (node.body.length === 0) { + this.token("}"); + } else { + this.newline(); + this.printSequence(node.body, node, { + indent: true, + }); + this.rightBrace(); + } +} diff --git a/packages/babel-generator/test/fixtures/minified/static-block/input.js b/packages/babel-generator/test/fixtures/minified/static-block/input.js new file mode 100644 index 000000000000..f23760defc73 --- /dev/null +++ b/packages/babel-generator/test/fixtures/minified/static-block/input.js @@ -0,0 +1,16 @@ +class Foo { + static {} +} + +class A1 { + static{ + foo; + } +} + +class A2 { + static { + foo; + bar; + } +} diff --git a/packages/babel-generator/test/fixtures/minified/static-block/options.json b/packages/babel-generator/test/fixtures/minified/static-block/options.json new file mode 100644 index 000000000000..e6005300df4e --- /dev/null +++ b/packages/babel-generator/test/fixtures/minified/static-block/options.json @@ -0,0 +1,4 @@ +{ + "minified": true, + "plugins": ["classStaticBlock"] +} diff --git a/packages/babel-generator/test/fixtures/minified/static-block/output.js b/packages/babel-generator/test/fixtures/minified/static-block/output.js new file mode 100644 index 000000000000..922f95fe6df0 --- /dev/null +++ b/packages/babel-generator/test/fixtures/minified/static-block/output.js @@ -0,0 +1 @@ +class Foo{static{}}class A1{static{foo}}class A2{static{foo;bar}} \ No newline at end of file diff --git a/packages/babel-generator/test/fixtures/types/ClassBody-StaticBlock/input.js b/packages/babel-generator/test/fixtures/types/ClassBody-StaticBlock/input.js new file mode 100644 index 000000000000..ea56b39d27ef --- /dev/null +++ b/packages/babel-generator/test/fixtures/types/ClassBody-StaticBlock/input.js @@ -0,0 +1,15 @@ +class Foo { + static {} +} + +class A1 { + static{ + foo; + } +} + +class A2 { + static { + foo;bar; + } +} diff --git a/packages/babel-generator/test/fixtures/types/ClassBody-StaticBlock/options.json b/packages/babel-generator/test/fixtures/types/ClassBody-StaticBlock/options.json new file mode 100644 index 000000000000..6f3a5e716c93 --- /dev/null +++ b/packages/babel-generator/test/fixtures/types/ClassBody-StaticBlock/options.json @@ -0,0 +1 @@ +{ "plugins": ["classStaticBlock"] } diff --git a/packages/babel-generator/test/fixtures/types/ClassBody-StaticBlock/output.js b/packages/babel-generator/test/fixtures/types/ClassBody-StaticBlock/output.js new file mode 100644 index 000000000000..8ce10b0ba345 --- /dev/null +++ b/packages/babel-generator/test/fixtures/types/ClassBody-StaticBlock/output.js @@ -0,0 +1,16 @@ +class Foo { + static {} +} + +class A1 { + static { + foo; + } +} + +class A2 { + static { + foo; + bar; + } +} \ No newline at end of file diff --git a/packages/babel-parser/ast/spec.md b/packages/babel-parser/ast/spec.md index 0484bc9f1faa..a3774d40cd8f 100644 --- a/packages/babel-parser/ast/spec.md +++ b/packages/babel-parser/ast/spec.md @@ -1183,7 +1183,7 @@ interface Class <: Node { ```js interface ClassBody <: Node { type: "ClassBody"; - body: [ ClassMethod | ClassPrivateMethod | ClassProperty | ClassPrivateProperty ]; + body: [ ClassMethod | ClassPrivateMethod | ClassProperty | ClassPrivateProperty | StaticBlock ]; } ``` @@ -1235,6 +1235,17 @@ interface ClassPrivateProperty <: Node { } ``` +## StaticBlock + +```js +interface StaticBlock <: Node { + type: "StaticBlock"; + body: [ Statement ]; +} +``` + +A static block proposed in https://github.com/tc39/proposal-class-static-block. + ## ClassDeclaration ```js diff --git a/packages/babel-parser/src/parser/error-message.js b/packages/babel-parser/src/parser/error-message.js index 05518147755a..d9cd63ab4a72 100644 --- a/packages/babel-parser/src/parser/error-message.js +++ b/packages/babel-parser/src/parser/error-message.js @@ -4,8 +4,8 @@ // The Errors key follows https://cs.chromium.org/chromium/src/v8/src/common/message-template.h unless it does not exist export const ErrorMessages = Object.freeze({ AccessorIsGenerator: "A %0ter cannot be a generator", - ArgumentsDisallowedInInitializer: - "'arguments' is not allowed in class field initializer", + ArgumentsInClass: + "'arguments' is only allowed in functions and class methods", AsyncFunctionInSingleStatementContext: "Async functions can only be declared at the top level or inside a block", AwaitBindingIdentifier: @@ -32,6 +32,7 @@ export const ErrorMessages = Object.freeze({ DecoratorExportClass: "Using the export keyword between a decorator and a class is not allowed. Please use `export @dec class` instead.", DecoratorSemicolon: "Decorators must not be followed by a semicolon", + DecoratorStaticBlock: "Decorators can't be used with a static block", DeletePrivateField: "Deleting a private field is not allowed", DestructureNamedImport: "ES2015 named imports do not destructure. Use another statement for destructuring after the import.", @@ -41,6 +42,7 @@ export const ErrorMessages = Object.freeze({ "`%0` has already been exported. Exported identifiers must be unique.", DuplicateProto: "Redefinition of __proto__ property", DuplicateRegExpFlags: "Duplicate regular expression flag", + DuplicateStaticBlock: "Duplicate static block in the same class", ElementAfterRest: "Rest element must be last element", EscapedCharNotAnIdentifier: "Invalid Unicode escape", ExportDefaultFromAsIdentifier: diff --git a/packages/babel-parser/src/parser/expression.js b/packages/babel-parser/src/parser/expression.js index 4321bbf5f437..a212dae53770 100644 --- a/packages/babel-parser/src/parser/expression.js +++ b/packages/babel-parser/src/parser/expression.js @@ -2382,7 +2382,7 @@ export default class ExpressionParser extends LValParser { !this.scope.inNonArrowFunction && word === "arguments" ) { - this.raise(startLoc, Errors.ArgumentsDisallowedInInitializer); + this.raise(startLoc, Errors.ArgumentsInClass); return; } if (checkKeywords && isKeyword(word)) { diff --git a/packages/babel-parser/src/parser/statement.js b/packages/babel-parser/src/parser/statement.js index 4e2f7a513010..5d2bf5e2cf02 100644 --- a/packages/babel-parser/src/parser/statement.js +++ b/packages/babel-parser/src/parser/statement.js @@ -795,7 +795,7 @@ export default class StatementParser extends ExpressionParser { } // Parse a semicolon-enclosed block of statements, handling `"use - // strict"` declarations when `allowStrict` is true (used for + // strict"` declarations when `allowDirectives` is true (used for // function bodies). parseBlock( @@ -1205,7 +1205,11 @@ export default class StatementParser extends ExpressionParser { ): N.ClassBody { this.classScope.enter(); - const state = { hadConstructor: false }; + const state: N.ParseClassMemberState = { + constructorAllowsSuper, + hadConstructor: false, + hadStaticBlock: false, + }; let decorators: N.Decorator[] = []; const classBody: N.ClassBody = this.startNode(); classBody.body = []; @@ -1237,7 +1241,7 @@ export default class StatementParser extends ExpressionParser { decorators = []; } - this.parseClassMember(classBody, member, state, constructorAllowsSuper); + this.parseClassMember(classBody, member, state); if ( member.kind === "constructor" && @@ -1303,31 +1307,33 @@ export default class StatementParser extends ExpressionParser { parseClassMember( classBody: N.ClassBody, member: N.ClassMember, - state: { hadConstructor: boolean }, - constructorAllowsSuper: boolean, + state: N.ParseClassMemberState, ): void { const isStatic = this.isContextual("static"); - if (isStatic && this.parseClassMemberFromModifier(classBody, member)) { - // a class element named 'static' - return; + if (isStatic) { + if (this.parseClassMemberFromModifier(classBody, member)) { + // a class element named 'static' + return; + } + if (this.eat(tt.braceL)) { + this.parseClassStaticBlock( + classBody, + ((member: any): N.StaticBlock), + state, + ); + return; + } } - this.parseClassMemberWithIsStatic( - classBody, - member, - state, - isStatic, - constructorAllowsSuper, - ); + this.parseClassMemberWithIsStatic(classBody, member, state, isStatic); } parseClassMemberWithIsStatic( classBody: N.ClassBody, member: N.ClassMember, - state: { hadConstructor: boolean }, + state: N.ParseClassMemberState, isStatic: boolean, - constructorAllowsSuper: boolean, ) { const publicMethod: $FlowSubtype = member; const privateMethod: $FlowSubtype = member; @@ -1394,7 +1400,7 @@ export default class StatementParser extends ExpressionParser { this.raise(key.start, Errors.DuplicateConstructor); } state.hadConstructor = true; - allowsDirectSuper = constructorAllowsSuper; + allowsDirectSuper = state.constructorAllowsSuper; } this.pushClassMethod( @@ -1513,6 +1519,35 @@ export default class StatementParser extends ExpressionParser { return key; } + parseClassStaticBlock( + classBody: N.ClassBody, + member: N.StaticBlock & { decorators?: Array }, + state: N.ParseClassMemberState, + ) { + this.expectPlugin("classStaticBlock", member.start); + // Start a new lexical scope + this.scope.enter(SCOPE_CLASS | SCOPE_SUPER); + // Start a new scope with regard to loop labels + const oldLabels = this.state.labels; + this.state.labels = []; + // ClassStaticBlockStatementList: + // StatementList[~Yield, ~Await, ~Return] opt + this.prodParam.enter(PARAM); + const body = (member.body = []); + this.parseBlockOrModuleBlockBody(body, undefined, false, tt.braceR); + this.prodParam.exit(); + this.scope.exit(); + this.state.labels = oldLabels; + classBody.body.push(this.finishNode(member, "StaticBlock")); + if (state.hadStaticBlock) { + this.raise(member.start, Errors.DuplicateStaticBlock); + } + if (member.decorators?.length) { + this.raise(member.start, Errors.DecoratorStaticBlock); + } + state.hadStaticBlock = true; + } + pushClassProperty(classBody: N.ClassBody, prop: N.ClassProperty) { if ( !prop.computed && diff --git a/packages/babel-parser/src/plugins/flow.js b/packages/babel-parser/src/plugins/flow.js index 96e7b5654d05..26ddfeaae787 100644 --- a/packages/babel-parser/src/plugins/flow.js +++ b/packages/babel-parser/src/plugins/flow.js @@ -2096,8 +2096,7 @@ export default (superClass: Class): Class => parseClassMember( classBody: N.ClassBody, member: any, - state: { hadConstructor: boolean }, - constructorAllowsSuper: boolean, + state: N.ParseClassMemberState, ): void { const pos = this.state.start; if (this.isContextual("declare")) { @@ -2109,7 +2108,7 @@ export default (superClass: Class): Class => member.declare = true; } - super.parseClassMember(classBody, member, state, constructorAllowsSuper); + super.parseClassMember(classBody, member, state); if (member.declare) { if ( diff --git a/packages/babel-parser/src/plugins/typescript/index.js b/packages/babel-parser/src/plugins/typescript/index.js index 1b9b7f1f3e83..bfc82d5f7a6b 100644 --- a/packages/babel-parser/src/plugins/typescript/index.js +++ b/packages/babel-parser/src/plugins/typescript/index.js @@ -2068,8 +2068,7 @@ export default (superClass: Class): Class => parseClassMember( classBody: N.ClassBody, member: any, - state: { hadConstructor: boolean }, - constructorAllowsSuper: boolean, + state: N.ParseClassMemberState, ): void { this.tsParseModifiers(member, ["declare"]); const accessibility = this.parseAccessModifier(); @@ -2077,12 +2076,7 @@ export default (superClass: Class): Class => this.tsParseModifiers(member, ["declare"]); const callParseClassMember = () => { - super.parseClassMember( - classBody, - member, - state, - constructorAllowsSuper, - ); + super.parseClassMember(classBody, member, state); }; if (member.declare) { this.tsInDeclareContext(callParseClassMember); @@ -2094,9 +2088,8 @@ export default (superClass: Class): Class => parseClassMemberWithIsStatic( classBody: N.ClassBody, member: N.ClassMember | N.TsIndexSignature, - state: { hadConstructor: boolean }, + state: N.ParseClassMemberState, isStatic: boolean, - constructorAllowsSuper: boolean, ): void { this.tsParseModifiers(member, ["abstract", "readonly", "declare"]); @@ -2126,13 +2119,7 @@ export default (superClass: Class): Class => /*:: invariant(member.type !== "TSIndexSignature") */ - super.parseClassMemberWithIsStatic( - classBody, - member, - state, - isStatic, - constructorAllowsSuper, - ); + super.parseClassMemberWithIsStatic(classBody, member, state, isStatic); } parsePostMemberNameModifiers( diff --git a/packages/babel-parser/src/types.js b/packages/babel-parser/src/types.js index 6d77c5c0d00d..98681c50013e 100644 --- a/packages/babel-parser/src/types.js +++ b/packages/babel-parser/src/types.js @@ -705,7 +705,7 @@ export type ClassBase = HasDecorators & { export type ClassBody = NodeBase & { type: "ClassBody", - body: Array, // TODO: $ReadOnlyArray + body: Array, // TODO: $ReadOnlyArray }; // | Placeholder<"ClassBody">; @@ -719,6 +719,11 @@ export type ClassMemberBase = NodeBase & optional?: ?true, }; +export type StaticBlock = NodeBase & { + type: "StaticBlock", + body: Array, +}; + export type ClassMember = | ClassMethod | ClassPrivateMethod @@ -1487,3 +1492,9 @@ export type ParseSubscriptState = { maybeAsyncArrow: boolean, stop: boolean, }; + +export type ParseClassMemberState = {| + hadConstructor: boolean, + hadStaticBlock: boolean, + constructorAllowsSuper: boolean, +|}; diff --git a/packages/babel-parser/test/fixtures/experimental/_no-plugin/class-static-block/input.js b/packages/babel-parser/test/fixtures/experimental/_no-plugin/class-static-block/input.js new file mode 100644 index 000000000000..56ee01f2a2ae --- /dev/null +++ b/packages/babel-parser/test/fixtures/experimental/_no-plugin/class-static-block/input.js @@ -0,0 +1,6 @@ +class C { + static foo() {} + static { + this.bar = this.foo; + } +} diff --git a/packages/babel-parser/test/fixtures/experimental/_no-plugin/class-static-block/options.json b/packages/babel-parser/test/fixtures/experimental/_no-plugin/class-static-block/options.json new file mode 100644 index 000000000000..5d350a1a938c --- /dev/null +++ b/packages/babel-parser/test/fixtures/experimental/_no-plugin/class-static-block/options.json @@ -0,0 +1,3 @@ +{ + "throws": "This experimental syntax requires enabling the parser plugin: 'classStaticBlock' (3:2)" +} \ No newline at end of file diff --git a/packages/babel-parser/test/fixtures/experimental/class-properties/arguments-in-arrow-function/output.json b/packages/babel-parser/test/fixtures/experimental/class-properties/arguments-in-arrow-function/output.json index 17dd38b5c5b0..e4fcbae89abd 100644 --- a/packages/babel-parser/test/fixtures/experimental/class-properties/arguments-in-arrow-function/output.json +++ b/packages/babel-parser/test/fixtures/experimental/class-properties/arguments-in-arrow-function/output.json @@ -2,7 +2,7 @@ "type": "File", "start":0,"end":60,"loc":{"start":{"line":1,"column":0},"end":{"line":5,"column":1}}, "errors": [ - "SyntaxError: 'arguments' is not allowed in class field initializer (3:16)" + "SyntaxError: 'arguments' is only allowed in functions and class methods (3:16)" ], "program": { "type": "Program", diff --git a/packages/babel-parser/test/fixtures/experimental/class-properties/arguments-in-nested-class-decorator-call-expression/output.json b/packages/babel-parser/test/fixtures/experimental/class-properties/arguments-in-nested-class-decorator-call-expression/output.json index 226c11bd0fe2..a6645c3bef45 100644 --- a/packages/babel-parser/test/fixtures/experimental/class-properties/arguments-in-nested-class-decorator-call-expression/output.json +++ b/packages/babel-parser/test/fixtures/experimental/class-properties/arguments-in-nested-class-decorator-call-expression/output.json @@ -2,7 +2,7 @@ "type": "File", "start":0,"end":76,"loc":{"start":{"line":1,"column":0},"end":{"line":5,"column":1}}, "errors": [ - "SyntaxError: 'arguments' is not allowed in class field initializer (3:25)" + "SyntaxError: 'arguments' is only allowed in functions and class methods (3:25)" ], "program": { "type": "Program", diff --git a/packages/babel-parser/test/fixtures/experimental/class-properties/arguments/output.json b/packages/babel-parser/test/fixtures/experimental/class-properties/arguments/output.json index ffd15aa2c2b3..48d889e597ff 100644 --- a/packages/babel-parser/test/fixtures/experimental/class-properties/arguments/output.json +++ b/packages/babel-parser/test/fixtures/experimental/class-properties/arguments/output.json @@ -2,7 +2,7 @@ "type": "File", "start":0,"end":54,"loc":{"start":{"line":1,"column":0},"end":{"line":5,"column":1}}, "errors": [ - "SyntaxError: 'arguments' is not allowed in class field initializer (3:10)" + "SyntaxError: 'arguments' is only allowed in functions and class methods (3:10)" ], "program": { "type": "Program", diff --git a/packages/babel-parser/test/fixtures/experimental/class-static-block/basic/input.js b/packages/babel-parser/test/fixtures/experimental/class-static-block/basic/input.js new file mode 100644 index 000000000000..56ee01f2a2ae --- /dev/null +++ b/packages/babel-parser/test/fixtures/experimental/class-static-block/basic/input.js @@ -0,0 +1,6 @@ +class C { + static foo() {} + static { + this.bar = this.foo; + } +} diff --git a/packages/babel-parser/test/fixtures/experimental/class-static-block/basic/output.json b/packages/babel-parser/test/fixtures/experimental/class-static-block/basic/output.json new file mode 100644 index 000000000000..1a03f17cde54 --- /dev/null +++ b/packages/babel-parser/test/fixtures/experimental/class-static-block/basic/output.json @@ -0,0 +1,94 @@ +{ + "type": "File", + "start":0,"end":69,"loc":{"start":{"line":1,"column":0},"end":{"line":6,"column":1}}, + "program": { + "type": "Program", + "start":0,"end":69,"loc":{"start":{"line":1,"column":0},"end":{"line":6,"column":1}}, + "sourceType": "script", + "interpreter": null, + "body": [ + { + "type": "ClassDeclaration", + "start":0,"end":69,"loc":{"start":{"line":1,"column":0},"end":{"line":6,"column":1}}, + "id": { + "type": "Identifier", + "start":6,"end":7,"loc":{"start":{"line":1,"column":6},"end":{"line":1,"column":7},"identifierName":"C"}, + "name": "C" + }, + "superClass": null, + "body": { + "type": "ClassBody", + "start":8,"end":69,"loc":{"start":{"line":1,"column":8},"end":{"line":6,"column":1}}, + "body": [ + { + "type": "ClassMethod", + "start":12,"end":27,"loc":{"start":{"line":2,"column":2},"end":{"line":2,"column":17}}, + "static": true, + "key": { + "type": "Identifier", + "start":19,"end":22,"loc":{"start":{"line":2,"column":9},"end":{"line":2,"column":12},"identifierName":"foo"}, + "name": "foo" + }, + "computed": false, + "kind": "method", + "id": null, + "generator": false, + "async": false, + "params": [], + "body": { + "type": "BlockStatement", + "start":25,"end":27,"loc":{"start":{"line":2,"column":15},"end":{"line":2,"column":17}}, + "body": [], + "directives": [] + } + }, + { + "type": "StaticBlock", + "start":30,"end":67,"loc":{"start":{"line":3,"column":2},"end":{"line":5,"column":3}}, + "body": [ + { + "type": "ExpressionStatement", + "start":43,"end":63,"loc":{"start":{"line":4,"column":4},"end":{"line":4,"column":24}}, + "expression": { + "type": "AssignmentExpression", + "start":43,"end":62,"loc":{"start":{"line":4,"column":4},"end":{"line":4,"column":23}}, + "operator": "=", + "left": { + "type": "MemberExpression", + "start":43,"end":51,"loc":{"start":{"line":4,"column":4},"end":{"line":4,"column":12}}, + "object": { + "type": "ThisExpression", + "start":43,"end":47,"loc":{"start":{"line":4,"column":4},"end":{"line":4,"column":8}} + }, + "computed": false, + "property": { + "type": "Identifier", + "start":48,"end":51,"loc":{"start":{"line":4,"column":9},"end":{"line":4,"column":12},"identifierName":"bar"}, + "name": "bar" + } + }, + "right": { + "type": "MemberExpression", + "start":54,"end":62,"loc":{"start":{"line":4,"column":15},"end":{"line":4,"column":23}}, + "object": { + "type": "ThisExpression", + "start":54,"end":58,"loc":{"start":{"line":4,"column":15},"end":{"line":4,"column":19}} + }, + "computed": false, + "property": { + "type": "Identifier", + "start":59,"end":62,"loc":{"start":{"line":4,"column":20},"end":{"line":4,"column":23},"identifierName":"foo"}, + "name": "foo" + } + } + } + } + ] + } + ] + } + } + ], + "directives": [] + } +} \ No newline at end of file diff --git a/packages/babel-parser/test/fixtures/experimental/class-static-block/directive-like-literal/input.js b/packages/babel-parser/test/fixtures/experimental/class-static-block/directive-like-literal/input.js new file mode 100644 index 000000000000..652bf6751ce9 --- /dev/null +++ b/packages/babel-parser/test/fixtures/experimental/class-static-block/directive-like-literal/input.js @@ -0,0 +1,7 @@ +class C { + static foo() {} + static { + "use strict"; // will not be parsed as directives + this.bar = this.foo; + } +} diff --git a/packages/babel-parser/test/fixtures/experimental/class-static-block/directive-like-literal/output.json b/packages/babel-parser/test/fixtures/experimental/class-static-block/directive-like-literal/output.json new file mode 100644 index 000000000000..09da3453e230 --- /dev/null +++ b/packages/babel-parser/test/fixtures/experimental/class-static-block/directive-like-literal/output.json @@ -0,0 +1,128 @@ +{ + "type": "File", + "start":0,"end":123,"loc":{"start":{"line":1,"column":0},"end":{"line":7,"column":1}}, + "program": { + "type": "Program", + "start":0,"end":123,"loc":{"start":{"line":1,"column":0},"end":{"line":7,"column":1}}, + "sourceType": "script", + "interpreter": null, + "body": [ + { + "type": "ClassDeclaration", + "start":0,"end":123,"loc":{"start":{"line":1,"column":0},"end":{"line":7,"column":1}}, + "id": { + "type": "Identifier", + "start":6,"end":7,"loc":{"start":{"line":1,"column":6},"end":{"line":1,"column":7},"identifierName":"C"}, + "name": "C" + }, + "superClass": null, + "body": { + "type": "ClassBody", + "start":8,"end":123,"loc":{"start":{"line":1,"column":8},"end":{"line":7,"column":1}}, + "body": [ + { + "type": "ClassMethod", + "start":12,"end":27,"loc":{"start":{"line":2,"column":2},"end":{"line":2,"column":17}}, + "static": true, + "key": { + "type": "Identifier", + "start":19,"end":22,"loc":{"start":{"line":2,"column":9},"end":{"line":2,"column":12},"identifierName":"foo"}, + "name": "foo" + }, + "computed": false, + "kind": "method", + "id": null, + "generator": false, + "async": false, + "params": [], + "body": { + "type": "BlockStatement", + "start":25,"end":27,"loc":{"start":{"line":2,"column":15},"end":{"line":2,"column":17}}, + "body": [], + "directives": [] + } + }, + { + "type": "StaticBlock", + "start":30,"end":121,"loc":{"start":{"line":3,"column":2},"end":{"line":6,"column":3}}, + "body": [ + { + "type": "ExpressionStatement", + "start":43,"end":56,"loc":{"start":{"line":4,"column":4},"end":{"line":4,"column":17}}, + "trailingComments": [ + { + "type": "CommentLine", + "value": " will not be parsed as directives", + "start":57,"end":92,"loc":{"start":{"line":4,"column":18},"end":{"line":4,"column":53}} + } + ], + "expression": { + "type": "StringLiteral", + "start":43,"end":55,"loc":{"start":{"line":4,"column":4},"end":{"line":4,"column":16}}, + "extra": { + "rawValue": "use strict", + "raw": "\"use strict\"" + }, + "value": "use strict" + } + }, + { + "type": "ExpressionStatement", + "start":97,"end":117,"loc":{"start":{"line":5,"column":4},"end":{"line":5,"column":24}}, + "leadingComments": [ + { + "type": "CommentLine", + "value": " will not be parsed as directives", + "start":57,"end":92,"loc":{"start":{"line":4,"column":18},"end":{"line":4,"column":53}} + } + ], + "expression": { + "type": "AssignmentExpression", + "start":97,"end":116,"loc":{"start":{"line":5,"column":4},"end":{"line":5,"column":23}}, + "operator": "=", + "left": { + "type": "MemberExpression", + "start":97,"end":105,"loc":{"start":{"line":5,"column":4},"end":{"line":5,"column":12}}, + "object": { + "type": "ThisExpression", + "start":97,"end":101,"loc":{"start":{"line":5,"column":4},"end":{"line":5,"column":8}} + }, + "computed": false, + "property": { + "type": "Identifier", + "start":102,"end":105,"loc":{"start":{"line":5,"column":9},"end":{"line":5,"column":12},"identifierName":"bar"}, + "name": "bar" + } + }, + "right": { + "type": "MemberExpression", + "start":108,"end":116,"loc":{"start":{"line":5,"column":15},"end":{"line":5,"column":23}}, + "object": { + "type": "ThisExpression", + "start":108,"end":112,"loc":{"start":{"line":5,"column":15},"end":{"line":5,"column":19}} + }, + "computed": false, + "property": { + "type": "Identifier", + "start":113,"end":116,"loc":{"start":{"line":5,"column":20},"end":{"line":5,"column":23},"identifierName":"foo"}, + "name": "foo" + } + } + } + } + ] + } + ] + } + } + ], + "directives": [] + }, + "comments": [ + { + "type": "CommentLine", + "value": " will not be parsed as directives", + "start":57,"end":92,"loc":{"start":{"line":4,"column":18},"end":{"line":4,"column":53}} + } + ] +} \ No newline at end of file diff --git a/packages/babel-parser/test/fixtures/experimental/class-static-block/empty-statement/input.js b/packages/babel-parser/test/fixtures/experimental/class-static-block/empty-statement/input.js new file mode 100644 index 000000000000..af2acabc582c --- /dev/null +++ b/packages/babel-parser/test/fixtures/experimental/class-static-block/empty-statement/input.js @@ -0,0 +1,4 @@ +class C { + static foo() {} + static {} +} diff --git a/packages/babel-parser/test/fixtures/experimental/class-static-block/empty-statement/output.json b/packages/babel-parser/test/fixtures/experimental/class-static-block/empty-statement/output.json new file mode 100644 index 000000000000..7c453254c252 --- /dev/null +++ b/packages/babel-parser/test/fixtures/experimental/class-static-block/empty-statement/output.json @@ -0,0 +1,56 @@ +{ + "type": "File", + "start":0,"end":41,"loc":{"start":{"line":1,"column":0},"end":{"line":4,"column":1}}, + "program": { + "type": "Program", + "start":0,"end":41,"loc":{"start":{"line":1,"column":0},"end":{"line":4,"column":1}}, + "sourceType": "script", + "interpreter": null, + "body": [ + { + "type": "ClassDeclaration", + "start":0,"end":41,"loc":{"start":{"line":1,"column":0},"end":{"line":4,"column":1}}, + "id": { + "type": "Identifier", + "start":6,"end":7,"loc":{"start":{"line":1,"column":6},"end":{"line":1,"column":7},"identifierName":"C"}, + "name": "C" + }, + "superClass": null, + "body": { + "type": "ClassBody", + "start":8,"end":41,"loc":{"start":{"line":1,"column":8},"end":{"line":4,"column":1}}, + "body": [ + { + "type": "ClassMethod", + "start":12,"end":27,"loc":{"start":{"line":2,"column":2},"end":{"line":2,"column":17}}, + "static": true, + "key": { + "type": "Identifier", + "start":19,"end":22,"loc":{"start":{"line":2,"column":9},"end":{"line":2,"column":12},"identifierName":"foo"}, + "name": "foo" + }, + "computed": false, + "kind": "method", + "id": null, + "generator": false, + "async": false, + "params": [], + "body": { + "type": "BlockStatement", + "start":25,"end":27,"loc":{"start":{"line":2,"column":15},"end":{"line":2,"column":17}}, + "body": [], + "directives": [] + } + }, + { + "type": "StaticBlock", + "start":30,"end":39,"loc":{"start":{"line":3,"column":2},"end":{"line":3,"column":11}}, + "body": [] + } + ] + } + } + ], + "directives": [] + } +} \ No newline at end of file diff --git a/packages/babel-parser/test/fixtures/experimental/class-static-block/invalid-arguments/input.js b/packages/babel-parser/test/fixtures/experimental/class-static-block/invalid-arguments/input.js new file mode 100644 index 000000000000..6852e2b7da9a --- /dev/null +++ b/packages/babel-parser/test/fixtures/experimental/class-static-block/invalid-arguments/input.js @@ -0,0 +1,5 @@ +class C { + static { + this.foo = arguments; + } +} diff --git a/packages/babel-parser/test/fixtures/experimental/class-static-block/invalid-arguments/output.json b/packages/babel-parser/test/fixtures/experimental/class-static-block/invalid-arguments/output.json new file mode 100644 index 000000000000..3dd4e8af7079 --- /dev/null +++ b/packages/babel-parser/test/fixtures/experimental/class-static-block/invalid-arguments/output.json @@ -0,0 +1,66 @@ +{ + "type": "File", + "start":0,"end":52,"loc":{"start":{"line":1,"column":0},"end":{"line":5,"column":1}}, + "errors": [ + "SyntaxError: 'arguments' is only allowed in functions and class methods (3:15)" + ], + "program": { + "type": "Program", + "start":0,"end":52,"loc":{"start":{"line":1,"column":0},"end":{"line":5,"column":1}}, + "sourceType": "script", + "interpreter": null, + "body": [ + { + "type": "ClassDeclaration", + "start":0,"end":52,"loc":{"start":{"line":1,"column":0},"end":{"line":5,"column":1}}, + "id": { + "type": "Identifier", + "start":6,"end":7,"loc":{"start":{"line":1,"column":6},"end":{"line":1,"column":7},"identifierName":"C"}, + "name": "C" + }, + "superClass": null, + "body": { + "type": "ClassBody", + "start":8,"end":52,"loc":{"start":{"line":1,"column":8},"end":{"line":5,"column":1}}, + "body": [ + { + "type": "StaticBlock", + "start":12,"end":50,"loc":{"start":{"line":2,"column":2},"end":{"line":4,"column":3}}, + "body": [ + { + "type": "ExpressionStatement", + "start":25,"end":46,"loc":{"start":{"line":3,"column":4},"end":{"line":3,"column":25}}, + "expression": { + "type": "AssignmentExpression", + "start":25,"end":45,"loc":{"start":{"line":3,"column":4},"end":{"line":3,"column":24}}, + "operator": "=", + "left": { + "type": "MemberExpression", + "start":25,"end":33,"loc":{"start":{"line":3,"column":4},"end":{"line":3,"column":12}}, + "object": { + "type": "ThisExpression", + "start":25,"end":29,"loc":{"start":{"line":3,"column":4},"end":{"line":3,"column":8}} + }, + "computed": false, + "property": { + "type": "Identifier", + "start":30,"end":33,"loc":{"start":{"line":3,"column":9},"end":{"line":3,"column":12},"identifierName":"foo"}, + "name": "foo" + } + }, + "right": { + "type": "Identifier", + "start":36,"end":45,"loc":{"start":{"line":3,"column":15},"end":{"line":3,"column":24},"identifierName":"arguments"}, + "name": "arguments" + } + } + } + ] + } + ] + } + } + ], + "directives": [] + } +} \ No newline at end of file diff --git a/packages/babel-parser/test/fixtures/experimental/class-static-block/invalid-await/input.js b/packages/babel-parser/test/fixtures/experimental/class-static-block/invalid-await/input.js new file mode 100644 index 000000000000..1f96a4fe89e2 --- /dev/null +++ b/packages/babel-parser/test/fixtures/experimental/class-static-block/invalid-await/input.js @@ -0,0 +1,8 @@ +async function foo() { + class C { + static foo() {} + static { + await 42; + } + } +} diff --git a/packages/babel-parser/test/fixtures/experimental/class-static-block/invalid-await/options.json b/packages/babel-parser/test/fixtures/experimental/class-static-block/invalid-await/options.json new file mode 100644 index 000000000000..ed5be518c9cc --- /dev/null +++ b/packages/babel-parser/test/fixtures/experimental/class-static-block/invalid-await/options.json @@ -0,0 +1,6 @@ +{ + "plugins": [ + "classStaticBlock" + ], + "throws": "Unexpected token, expected \";\" (5:12)" +} \ No newline at end of file diff --git a/packages/babel-parser/test/fixtures/experimental/class-static-block/invalid-break/input.js b/packages/babel-parser/test/fixtures/experimental/class-static-block/invalid-break/input.js new file mode 100644 index 000000000000..21c9faa76713 --- /dev/null +++ b/packages/babel-parser/test/fixtures/experimental/class-static-block/invalid-break/input.js @@ -0,0 +1,10 @@ +switch (0) { + default: { + class C { + static foo() {} + static { + break; + } + } + } +} diff --git a/packages/babel-parser/test/fixtures/experimental/class-static-block/invalid-break/output.json b/packages/babel-parser/test/fixtures/experimental/class-static-block/invalid-break/output.json new file mode 100644 index 000000000000..945a53080c99 --- /dev/null +++ b/packages/babel-parser/test/fixtures/experimental/class-static-block/invalid-break/output.json @@ -0,0 +1,94 @@ +{ + "type": "File", + "start":0,"end":111,"loc":{"start":{"line":1,"column":0},"end":{"line":10,"column":1}}, + "errors": [ + "SyntaxError: Unsyntactic break (6:8)" + ], + "program": { + "type": "Program", + "start":0,"end":111,"loc":{"start":{"line":1,"column":0},"end":{"line":10,"column":1}}, + "sourceType": "script", + "interpreter": null, + "body": [ + { + "type": "SwitchStatement", + "start":0,"end":111,"loc":{"start":{"line":1,"column":0},"end":{"line":10,"column":1}}, + "discriminant": { + "type": "NumericLiteral", + "start":8,"end":9,"loc":{"start":{"line":1,"column":8},"end":{"line":1,"column":9}}, + "extra": { + "rawValue": 0, + "raw": "0" + }, + "value": 0 + }, + "cases": [ + { + "type": "SwitchCase", + "start":15,"end":109,"loc":{"start":{"line":2,"column":2},"end":{"line":9,"column":3}}, + "consequent": [ + { + "type": "BlockStatement", + "start":24,"end":109,"loc":{"start":{"line":2,"column":11},"end":{"line":9,"column":3}}, + "body": [ + { + "type": "ClassDeclaration", + "start":30,"end":105,"loc":{"start":{"line":3,"column":4},"end":{"line":8,"column":5}}, + "id": { + "type": "Identifier", + "start":36,"end":37,"loc":{"start":{"line":3,"column":10},"end":{"line":3,"column":11},"identifierName":"C"}, + "name": "C" + }, + "superClass": null, + "body": { + "type": "ClassBody", + "start":38,"end":105,"loc":{"start":{"line":3,"column":12},"end":{"line":8,"column":5}}, + "body": [ + { + "type": "ClassMethod", + "start":46,"end":61,"loc":{"start":{"line":4,"column":6},"end":{"line":4,"column":21}}, + "static": true, + "key": { + "type": "Identifier", + "start":53,"end":56,"loc":{"start":{"line":4,"column":13},"end":{"line":4,"column":16},"identifierName":"foo"}, + "name": "foo" + }, + "computed": false, + "kind": "method", + "id": null, + "generator": false, + "async": false, + "params": [], + "body": { + "type": "BlockStatement", + "start":59,"end":61,"loc":{"start":{"line":4,"column":19},"end":{"line":4,"column":21}}, + "body": [], + "directives": [] + } + }, + { + "type": "StaticBlock", + "start":68,"end":99,"loc":{"start":{"line":5,"column":6},"end":{"line":7,"column":7}}, + "body": [ + { + "type": "BreakStatement", + "start":85,"end":91,"loc":{"start":{"line":6,"column":8},"end":{"line":6,"column":14}}, + "label": null + } + ] + } + ] + } + } + ], + "directives": [] + } + ], + "test": null + } + ] + } + ], + "directives": [] + } +} \ No newline at end of file diff --git a/packages/babel-parser/test/fixtures/experimental/class-static-block/invalid-continue/input.js b/packages/babel-parser/test/fixtures/experimental/class-static-block/invalid-continue/input.js new file mode 100644 index 000000000000..7d2445e76679 --- /dev/null +++ b/packages/babel-parser/test/fixtures/experimental/class-static-block/invalid-continue/input.js @@ -0,0 +1,8 @@ +while (0) { + class C { + static foo() {} + static { + continue; + } + } +} diff --git a/packages/babel-parser/test/fixtures/experimental/class-static-block/invalid-continue/output.json b/packages/babel-parser/test/fixtures/experimental/class-static-block/invalid-continue/output.json new file mode 100644 index 000000000000..e427962f49ba --- /dev/null +++ b/packages/babel-parser/test/fixtures/experimental/class-static-block/invalid-continue/output.json @@ -0,0 +1,85 @@ +{ + "type": "File", + "start":0,"end":84,"loc":{"start":{"line":1,"column":0},"end":{"line":8,"column":1}}, + "errors": [ + "SyntaxError: Unsyntactic continue (5:6)" + ], + "program": { + "type": "Program", + "start":0,"end":84,"loc":{"start":{"line":1,"column":0},"end":{"line":8,"column":1}}, + "sourceType": "script", + "interpreter": null, + "body": [ + { + "type": "WhileStatement", + "start":0,"end":84,"loc":{"start":{"line":1,"column":0},"end":{"line":8,"column":1}}, + "test": { + "type": "NumericLiteral", + "start":7,"end":8,"loc":{"start":{"line":1,"column":7},"end":{"line":1,"column":8}}, + "extra": { + "rawValue": 0, + "raw": "0" + }, + "value": 0 + }, + "body": { + "type": "BlockStatement", + "start":10,"end":84,"loc":{"start":{"line":1,"column":10},"end":{"line":8,"column":1}}, + "body": [ + { + "type": "ClassDeclaration", + "start":14,"end":82,"loc":{"start":{"line":2,"column":2},"end":{"line":7,"column":3}}, + "id": { + "type": "Identifier", + "start":20,"end":21,"loc":{"start":{"line":2,"column":8},"end":{"line":2,"column":9},"identifierName":"C"}, + "name": "C" + }, + "superClass": null, + "body": { + "type": "ClassBody", + "start":22,"end":82,"loc":{"start":{"line":2,"column":10},"end":{"line":7,"column":3}}, + "body": [ + { + "type": "ClassMethod", + "start":28,"end":43,"loc":{"start":{"line":3,"column":4},"end":{"line":3,"column":19}}, + "static": true, + "key": { + "type": "Identifier", + "start":35,"end":38,"loc":{"start":{"line":3,"column":11},"end":{"line":3,"column":14},"identifierName":"foo"}, + "name": "foo" + }, + "computed": false, + "kind": "method", + "id": null, + "generator": false, + "async": false, + "params": [], + "body": { + "type": "BlockStatement", + "start":41,"end":43,"loc":{"start":{"line":3,"column":17},"end":{"line":3,"column":19}}, + "body": [], + "directives": [] + } + }, + { + "type": "StaticBlock", + "start":48,"end":78,"loc":{"start":{"line":4,"column":4},"end":{"line":6,"column":5}}, + "body": [ + { + "type": "ContinueStatement", + "start":63,"end":72,"loc":{"start":{"line":5,"column":6},"end":{"line":5,"column":15}}, + "label": null + } + ] + } + ] + } + } + ], + "directives": [] + } + } + ], + "directives": [] + } +} diff --git a/packages/babel-parser/test/fixtures/experimental/class-static-block/invalid-decorators/input.js b/packages/babel-parser/test/fixtures/experimental/class-static-block/invalid-decorators/input.js new file mode 100644 index 000000000000..90049ea86482 --- /dev/null +++ b/packages/babel-parser/test/fixtures/experimental/class-static-block/invalid-decorators/input.js @@ -0,0 +1,7 @@ +class C { + static foo() {} + @dec + static { + this.bar = this.foo; + } +} diff --git a/packages/babel-parser/test/fixtures/experimental/class-static-block/invalid-decorators/options.json b/packages/babel-parser/test/fixtures/experimental/class-static-block/invalid-decorators/options.json new file mode 100644 index 000000000000..0dba4407dcf1 --- /dev/null +++ b/packages/babel-parser/test/fixtures/experimental/class-static-block/invalid-decorators/options.json @@ -0,0 +1,6 @@ +{ + "plugins": [ + "classStaticBlock", + ["decorators", { "decoratorsBeforeExport": true }] + ] +} diff --git a/packages/babel-parser/test/fixtures/experimental/class-static-block/invalid-decorators/output.json b/packages/babel-parser/test/fixtures/experimental/class-static-block/invalid-decorators/output.json new file mode 100644 index 000000000000..bd16de29ca2e --- /dev/null +++ b/packages/babel-parser/test/fixtures/experimental/class-static-block/invalid-decorators/output.json @@ -0,0 +1,108 @@ +{ + "type": "File", + "start":0,"end":76,"loc":{"start":{"line":1,"column":0},"end":{"line":7,"column":1}}, + "errors": [ + "SyntaxError: Decorators can't be used with a static block (3:2)" + ], + "program": { + "type": "Program", + "start":0,"end":76,"loc":{"start":{"line":1,"column":0},"end":{"line":7,"column":1}}, + "sourceType": "script", + "interpreter": null, + "body": [ + { + "type": "ClassDeclaration", + "start":0,"end":76,"loc":{"start":{"line":1,"column":0},"end":{"line":7,"column":1}}, + "id": { + "type": "Identifier", + "start":6,"end":7,"loc":{"start":{"line":1,"column":6},"end":{"line":1,"column":7},"identifierName":"C"}, + "name": "C" + }, + "superClass": null, + "body": { + "type": "ClassBody", + "start":8,"end":76,"loc":{"start":{"line":1,"column":8},"end":{"line":7,"column":1}}, + "body": [ + { + "type": "ClassMethod", + "start":12,"end":27,"loc":{"start":{"line":2,"column":2},"end":{"line":2,"column":17}}, + "static": true, + "key": { + "type": "Identifier", + "start":19,"end":22,"loc":{"start":{"line":2,"column":9},"end":{"line":2,"column":12},"identifierName":"foo"}, + "name": "foo" + }, + "computed": false, + "kind": "method", + "id": null, + "generator": false, + "async": false, + "params": [], + "body": { + "type": "BlockStatement", + "start":25,"end":27,"loc":{"start":{"line":2,"column":15},"end":{"line":2,"column":17}}, + "body": [], + "directives": [] + } + }, + { + "type": "StaticBlock", + "start":30,"end":74,"loc":{"start":{"line":3,"column":2},"end":{"line":6,"column":3}}, + "decorators": [ + { + "type": "Decorator", + "start":30,"end":34,"loc":{"start":{"line":3,"column":2},"end":{"line":3,"column":6}}, + "expression": { + "type": "Identifier", + "start":31,"end":34,"loc":{"start":{"line":3,"column":3},"end":{"line":3,"column":6},"identifierName":"dec"}, + "name": "dec" + } + } + ], + "body": [ + { + "type": "ExpressionStatement", + "start":50,"end":70,"loc":{"start":{"line":5,"column":4},"end":{"line":5,"column":24}}, + "expression": { + "type": "AssignmentExpression", + "start":50,"end":69,"loc":{"start":{"line":5,"column":4},"end":{"line":5,"column":23}}, + "operator": "=", + "left": { + "type": "MemberExpression", + "start":50,"end":58,"loc":{"start":{"line":5,"column":4},"end":{"line":5,"column":12}}, + "object": { + "type": "ThisExpression", + "start":50,"end":54,"loc":{"start":{"line":5,"column":4},"end":{"line":5,"column":8}} + }, + "computed": false, + "property": { + "type": "Identifier", + "start":55,"end":58,"loc":{"start":{"line":5,"column":9},"end":{"line":5,"column":12},"identifierName":"bar"}, + "name": "bar" + } + }, + "right": { + "type": "MemberExpression", + "start":61,"end":69,"loc":{"start":{"line":5,"column":15},"end":{"line":5,"column":23}}, + "object": { + "type": "ThisExpression", + "start":61,"end":65,"loc":{"start":{"line":5,"column":15},"end":{"line":5,"column":19}} + }, + "computed": false, + "property": { + "type": "Identifier", + "start":66,"end":69,"loc":{"start":{"line":5,"column":20},"end":{"line":5,"column":23},"identifierName":"foo"}, + "name": "foo" + } + } + } + } + ] + } + ] + } + } + ], + "directives": [] + } +} \ No newline at end of file diff --git a/packages/babel-parser/test/fixtures/experimental/class-static-block/invalid-duplicated-static-block/input.js b/packages/babel-parser/test/fixtures/experimental/class-static-block/invalid-duplicated-static-block/input.js new file mode 100644 index 000000000000..b464ab07fbd3 --- /dev/null +++ b/packages/babel-parser/test/fixtures/experimental/class-static-block/invalid-duplicated-static-block/input.js @@ -0,0 +1,5 @@ +class C { + static foo() {} + static {} + static {} +} diff --git a/packages/babel-parser/test/fixtures/experimental/class-static-block/invalid-duplicated-static-block/output.json b/packages/babel-parser/test/fixtures/experimental/class-static-block/invalid-duplicated-static-block/output.json new file mode 100644 index 000000000000..ee9eecdf60fa --- /dev/null +++ b/packages/babel-parser/test/fixtures/experimental/class-static-block/invalid-duplicated-static-block/output.json @@ -0,0 +1,64 @@ +{ + "type": "File", + "start":0,"end":53,"loc":{"start":{"line":1,"column":0},"end":{"line":5,"column":1}}, + "errors": [ + "SyntaxError: Duplicate static block in the same class (4:2)" + ], + "program": { + "type": "Program", + "start":0,"end":53,"loc":{"start":{"line":1,"column":0},"end":{"line":5,"column":1}}, + "sourceType": "script", + "interpreter": null, + "body": [ + { + "type": "ClassDeclaration", + "start":0,"end":53,"loc":{"start":{"line":1,"column":0},"end":{"line":5,"column":1}}, + "id": { + "type": "Identifier", + "start":6,"end":7,"loc":{"start":{"line":1,"column":6},"end":{"line":1,"column":7},"identifierName":"C"}, + "name": "C" + }, + "superClass": null, + "body": { + "type": "ClassBody", + "start":8,"end":53,"loc":{"start":{"line":1,"column":8},"end":{"line":5,"column":1}}, + "body": [ + { + "type": "ClassMethod", + "start":12,"end":27,"loc":{"start":{"line":2,"column":2},"end":{"line":2,"column":17}}, + "static": true, + "key": { + "type": "Identifier", + "start":19,"end":22,"loc":{"start":{"line":2,"column":9},"end":{"line":2,"column":12},"identifierName":"foo"}, + "name": "foo" + }, + "computed": false, + "kind": "method", + "id": null, + "generator": false, + "async": false, + "params": [], + "body": { + "type": "BlockStatement", + "start":25,"end":27,"loc":{"start":{"line":2,"column":15},"end":{"line":2,"column":17}}, + "body": [], + "directives": [] + } + }, + { + "type": "StaticBlock", + "start":30,"end":39,"loc":{"start":{"line":3,"column":2},"end":{"line":3,"column":11}}, + "body": [] + }, + { + "type": "StaticBlock", + "start":42,"end":51,"loc":{"start":{"line":4,"column":2},"end":{"line":4,"column":11}}, + "body": [] + } + ] + } + } + ], + "directives": [] + } +} \ No newline at end of file diff --git a/packages/babel-parser/test/fixtures/experimental/class-static-block/invalid-legacy-decorators/input.js b/packages/babel-parser/test/fixtures/experimental/class-static-block/invalid-legacy-decorators/input.js new file mode 100644 index 000000000000..90049ea86482 --- /dev/null +++ b/packages/babel-parser/test/fixtures/experimental/class-static-block/invalid-legacy-decorators/input.js @@ -0,0 +1,7 @@ +class C { + static foo() {} + @dec + static { + this.bar = this.foo; + } +} diff --git a/packages/babel-parser/test/fixtures/experimental/class-static-block/invalid-legacy-decorators/options.json b/packages/babel-parser/test/fixtures/experimental/class-static-block/invalid-legacy-decorators/options.json new file mode 100644 index 000000000000..fb2927c28fc8 --- /dev/null +++ b/packages/babel-parser/test/fixtures/experimental/class-static-block/invalid-legacy-decorators/options.json @@ -0,0 +1,3 @@ +{ + "plugins": ["classStaticBlock", "decorators-legacy"] +} diff --git a/packages/babel-parser/test/fixtures/experimental/class-static-block/invalid-legacy-decorators/output.json b/packages/babel-parser/test/fixtures/experimental/class-static-block/invalid-legacy-decorators/output.json new file mode 100644 index 000000000000..bd16de29ca2e --- /dev/null +++ b/packages/babel-parser/test/fixtures/experimental/class-static-block/invalid-legacy-decorators/output.json @@ -0,0 +1,108 @@ +{ + "type": "File", + "start":0,"end":76,"loc":{"start":{"line":1,"column":0},"end":{"line":7,"column":1}}, + "errors": [ + "SyntaxError: Decorators can't be used with a static block (3:2)" + ], + "program": { + "type": "Program", + "start":0,"end":76,"loc":{"start":{"line":1,"column":0},"end":{"line":7,"column":1}}, + "sourceType": "script", + "interpreter": null, + "body": [ + { + "type": "ClassDeclaration", + "start":0,"end":76,"loc":{"start":{"line":1,"column":0},"end":{"line":7,"column":1}}, + "id": { + "type": "Identifier", + "start":6,"end":7,"loc":{"start":{"line":1,"column":6},"end":{"line":1,"column":7},"identifierName":"C"}, + "name": "C" + }, + "superClass": null, + "body": { + "type": "ClassBody", + "start":8,"end":76,"loc":{"start":{"line":1,"column":8},"end":{"line":7,"column":1}}, + "body": [ + { + "type": "ClassMethod", + "start":12,"end":27,"loc":{"start":{"line":2,"column":2},"end":{"line":2,"column":17}}, + "static": true, + "key": { + "type": "Identifier", + "start":19,"end":22,"loc":{"start":{"line":2,"column":9},"end":{"line":2,"column":12},"identifierName":"foo"}, + "name": "foo" + }, + "computed": false, + "kind": "method", + "id": null, + "generator": false, + "async": false, + "params": [], + "body": { + "type": "BlockStatement", + "start":25,"end":27,"loc":{"start":{"line":2,"column":15},"end":{"line":2,"column":17}}, + "body": [], + "directives": [] + } + }, + { + "type": "StaticBlock", + "start":30,"end":74,"loc":{"start":{"line":3,"column":2},"end":{"line":6,"column":3}}, + "decorators": [ + { + "type": "Decorator", + "start":30,"end":34,"loc":{"start":{"line":3,"column":2},"end":{"line":3,"column":6}}, + "expression": { + "type": "Identifier", + "start":31,"end":34,"loc":{"start":{"line":3,"column":3},"end":{"line":3,"column":6},"identifierName":"dec"}, + "name": "dec" + } + } + ], + "body": [ + { + "type": "ExpressionStatement", + "start":50,"end":70,"loc":{"start":{"line":5,"column":4},"end":{"line":5,"column":24}}, + "expression": { + "type": "AssignmentExpression", + "start":50,"end":69,"loc":{"start":{"line":5,"column":4},"end":{"line":5,"column":23}}, + "operator": "=", + "left": { + "type": "MemberExpression", + "start":50,"end":58,"loc":{"start":{"line":5,"column":4},"end":{"line":5,"column":12}}, + "object": { + "type": "ThisExpression", + "start":50,"end":54,"loc":{"start":{"line":5,"column":4},"end":{"line":5,"column":8}} + }, + "computed": false, + "property": { + "type": "Identifier", + "start":55,"end":58,"loc":{"start":{"line":5,"column":9},"end":{"line":5,"column":12},"identifierName":"bar"}, + "name": "bar" + } + }, + "right": { + "type": "MemberExpression", + "start":61,"end":69,"loc":{"start":{"line":5,"column":15},"end":{"line":5,"column":23}}, + "object": { + "type": "ThisExpression", + "start":61,"end":65,"loc":{"start":{"line":5,"column":15},"end":{"line":5,"column":19}} + }, + "computed": false, + "property": { + "type": "Identifier", + "start":66,"end":69,"loc":{"start":{"line":5,"column":20},"end":{"line":5,"column":23},"identifierName":"foo"}, + "name": "foo" + } + } + } + } + ] + } + ] + } + } + ], + "directives": [] + } +} \ No newline at end of file diff --git a/packages/babel-parser/test/fixtures/experimental/class-static-block/invalid-legacy-octal/input.js b/packages/babel-parser/test/fixtures/experimental/class-static-block/invalid-legacy-octal/input.js new file mode 100644 index 000000000000..c2efed4d038f --- /dev/null +++ b/packages/babel-parser/test/fixtures/experimental/class-static-block/invalid-legacy-octal/input.js @@ -0,0 +1,6 @@ +class C { + static foo() {} + static { + 042; + } +} diff --git a/packages/babel-parser/test/fixtures/experimental/class-static-block/invalid-legacy-octal/output.json b/packages/babel-parser/test/fixtures/experimental/class-static-block/invalid-legacy-octal/output.json new file mode 100644 index 000000000000..e22e29928345 --- /dev/null +++ b/packages/babel-parser/test/fixtures/experimental/class-static-block/invalid-legacy-octal/output.json @@ -0,0 +1,73 @@ +{ + "type": "File", + "start":0,"end":53,"loc":{"start":{"line":1,"column":0},"end":{"line":6,"column":1}}, + "errors": [ + "SyntaxError: Legacy octal literals are not allowed in strict mode (4:4)" + ], + "program": { + "type": "Program", + "start":0,"end":53,"loc":{"start":{"line":1,"column":0},"end":{"line":6,"column":1}}, + "sourceType": "script", + "interpreter": null, + "body": [ + { + "type": "ClassDeclaration", + "start":0,"end":53,"loc":{"start":{"line":1,"column":0},"end":{"line":6,"column":1}}, + "id": { + "type": "Identifier", + "start":6,"end":7,"loc":{"start":{"line":1,"column":6},"end":{"line":1,"column":7},"identifierName":"C"}, + "name": "C" + }, + "superClass": null, + "body": { + "type": "ClassBody", + "start":8,"end":53,"loc":{"start":{"line":1,"column":8},"end":{"line":6,"column":1}}, + "body": [ + { + "type": "ClassMethod", + "start":12,"end":27,"loc":{"start":{"line":2,"column":2},"end":{"line":2,"column":17}}, + "static": true, + "key": { + "type": "Identifier", + "start":19,"end":22,"loc":{"start":{"line":2,"column":9},"end":{"line":2,"column":12},"identifierName":"foo"}, + "name": "foo" + }, + "computed": false, + "kind": "method", + "id": null, + "generator": false, + "async": false, + "params": [], + "body": { + "type": "BlockStatement", + "start":25,"end":27,"loc":{"start":{"line":2,"column":15},"end":{"line":2,"column":17}}, + "body": [], + "directives": [] + } + }, + { + "type": "StaticBlock", + "start":30,"end":51,"loc":{"start":{"line":3,"column":2},"end":{"line":5,"column":3}}, + "body": [ + { + "type": "ExpressionStatement", + "start":43,"end":47,"loc":{"start":{"line":4,"column":4},"end":{"line":4,"column":8}}, + "expression": { + "type": "NumericLiteral", + "start":43,"end":46,"loc":{"start":{"line":4,"column":4},"end":{"line":4,"column":7}}, + "extra": { + "rawValue": 34, + "raw": "042" + }, + "value": 34 + } + } + ] + } + ] + } + } + ], + "directives": [] + } +} \ No newline at end of file diff --git a/packages/babel-parser/test/fixtures/experimental/class-static-block/invalid-return/input.js b/packages/babel-parser/test/fixtures/experimental/class-static-block/invalid-return/input.js new file mode 100644 index 000000000000..bbb719cbfd1a --- /dev/null +++ b/packages/babel-parser/test/fixtures/experimental/class-static-block/invalid-return/input.js @@ -0,0 +1,6 @@ +class C { + static foo() {} + static { + return this; + } +} diff --git a/packages/babel-parser/test/fixtures/experimental/class-static-block/invalid-return/output.json b/packages/babel-parser/test/fixtures/experimental/class-static-block/invalid-return/output.json new file mode 100644 index 000000000000..2f0fef206125 --- /dev/null +++ b/packages/babel-parser/test/fixtures/experimental/class-static-block/invalid-return/output.json @@ -0,0 +1,68 @@ +{ + "type": "File", + "start":0,"end":61,"loc":{"start":{"line":1,"column":0},"end":{"line":6,"column":1}}, + "errors": [ + "SyntaxError: 'return' outside of function (4:4)" + ], + "program": { + "type": "Program", + "start":0,"end":61,"loc":{"start":{"line":1,"column":0},"end":{"line":6,"column":1}}, + "sourceType": "script", + "interpreter": null, + "body": [ + { + "type": "ClassDeclaration", + "start":0,"end":61,"loc":{"start":{"line":1,"column":0},"end":{"line":6,"column":1}}, + "id": { + "type": "Identifier", + "start":6,"end":7,"loc":{"start":{"line":1,"column":6},"end":{"line":1,"column":7},"identifierName":"C"}, + "name": "C" + }, + "superClass": null, + "body": { + "type": "ClassBody", + "start":8,"end":61,"loc":{"start":{"line":1,"column":8},"end":{"line":6,"column":1}}, + "body": [ + { + "type": "ClassMethod", + "start":12,"end":27,"loc":{"start":{"line":2,"column":2},"end":{"line":2,"column":17}}, + "static": true, + "key": { + "type": "Identifier", + "start":19,"end":22,"loc":{"start":{"line":2,"column":9},"end":{"line":2,"column":12},"identifierName":"foo"}, + "name": "foo" + }, + "computed": false, + "kind": "method", + "id": null, + "generator": false, + "async": false, + "params": [], + "body": { + "type": "BlockStatement", + "start":25,"end":27,"loc":{"start":{"line":2,"column":15},"end":{"line":2,"column":17}}, + "body": [], + "directives": [] + } + }, + { + "type": "StaticBlock", + "start":30,"end":59,"loc":{"start":{"line":3,"column":2},"end":{"line":5,"column":3}}, + "body": [ + { + "type": "ReturnStatement", + "start":43,"end":55,"loc":{"start":{"line":4,"column":4},"end":{"line":4,"column":16}}, + "argument": { + "type": "ThisExpression", + "start":50,"end":54,"loc":{"start":{"line":4,"column":11},"end":{"line":4,"column":15}} + } + } + ] + } + ] + } + } + ], + "directives": [] + } +} \ No newline at end of file diff --git a/packages/babel-parser/test/fixtures/experimental/class-static-block/invalid-super-call/input.js b/packages/babel-parser/test/fixtures/experimental/class-static-block/invalid-super-call/input.js new file mode 100644 index 000000000000..3ceed33e67cf --- /dev/null +++ b/packages/babel-parser/test/fixtures/experimental/class-static-block/invalid-super-call/input.js @@ -0,0 +1,7 @@ +class B {} +class C extends B { + static foo() {} + static { + super(); + } +} diff --git a/packages/babel-parser/test/fixtures/experimental/class-static-block/invalid-super-call/output.json b/packages/babel-parser/test/fixtures/experimental/class-static-block/invalid-super-call/output.json new file mode 100644 index 000000000000..e07c019a7eb3 --- /dev/null +++ b/packages/babel-parser/test/fixtures/experimental/class-static-block/invalid-super-call/output.json @@ -0,0 +1,92 @@ +{ + "type": "File", + "start":0,"end":78,"loc":{"start":{"line":1,"column":0},"end":{"line":7,"column":1}}, + "errors": [ + "SyntaxError: super() is only valid inside a class constructor of a subclass. Maybe a typo in the method name ('constructor') or not extending another class? (5:4)" + ], + "program": { + "type": "Program", + "start":0,"end":78,"loc":{"start":{"line":1,"column":0},"end":{"line":7,"column":1}}, + "sourceType": "script", + "interpreter": null, + "body": [ + { + "type": "ClassDeclaration", + "start":0,"end":10,"loc":{"start":{"line":1,"column":0},"end":{"line":1,"column":10}}, + "id": { + "type": "Identifier", + "start":6,"end":7,"loc":{"start":{"line":1,"column":6},"end":{"line":1,"column":7},"identifierName":"B"}, + "name": "B" + }, + "superClass": null, + "body": { + "type": "ClassBody", + "start":8,"end":10,"loc":{"start":{"line":1,"column":8},"end":{"line":1,"column":10}}, + "body": [] + } + }, + { + "type": "ClassDeclaration", + "start":11,"end":78,"loc":{"start":{"line":2,"column":0},"end":{"line":7,"column":1}}, + "id": { + "type": "Identifier", + "start":17,"end":18,"loc":{"start":{"line":2,"column":6},"end":{"line":2,"column":7},"identifierName":"C"}, + "name": "C" + }, + "superClass": { + "type": "Identifier", + "start":27,"end":28,"loc":{"start":{"line":2,"column":16},"end":{"line":2,"column":17},"identifierName":"B"}, + "name": "B" + }, + "body": { + "type": "ClassBody", + "start":29,"end":78,"loc":{"start":{"line":2,"column":18},"end":{"line":7,"column":1}}, + "body": [ + { + "type": "ClassMethod", + "start":33,"end":48,"loc":{"start":{"line":3,"column":2},"end":{"line":3,"column":17}}, + "static": true, + "key": { + "type": "Identifier", + "start":40,"end":43,"loc":{"start":{"line":3,"column":9},"end":{"line":3,"column":12},"identifierName":"foo"}, + "name": "foo" + }, + "computed": false, + "kind": "method", + "id": null, + "generator": false, + "async": false, + "params": [], + "body": { + "type": "BlockStatement", + "start":46,"end":48,"loc":{"start":{"line":3,"column":15},"end":{"line":3,"column":17}}, + "body": [], + "directives": [] + } + }, + { + "type": "StaticBlock", + "start":51,"end":76,"loc":{"start":{"line":4,"column":2},"end":{"line":6,"column":3}}, + "body": [ + { + "type": "ExpressionStatement", + "start":64,"end":72,"loc":{"start":{"line":5,"column":4},"end":{"line":5,"column":12}}, + "expression": { + "type": "CallExpression", + "start":64,"end":71,"loc":{"start":{"line":5,"column":4},"end":{"line":5,"column":11}}, + "callee": { + "type": "Super", + "start":64,"end":69,"loc":{"start":{"line":5,"column":4},"end":{"line":5,"column":9}} + }, + "arguments": [] + } + } + ] + } + ] + } + } + ], + "directives": [] + } +} \ No newline at end of file diff --git a/packages/babel-parser/test/fixtures/experimental/class-static-block/invalid-yield/input.js b/packages/babel-parser/test/fixtures/experimental/class-static-block/invalid-yield/input.js new file mode 100644 index 000000000000..436aaa94f2da --- /dev/null +++ b/packages/babel-parser/test/fixtures/experimental/class-static-block/invalid-yield/input.js @@ -0,0 +1,8 @@ +function* foo() { + class C { + static foo() {} + static { + yield 42; + } + } +} diff --git a/packages/babel-parser/test/fixtures/experimental/class-static-block/invalid-yield/options.json b/packages/babel-parser/test/fixtures/experimental/class-static-block/invalid-yield/options.json new file mode 100644 index 000000000000..ed5be518c9cc --- /dev/null +++ b/packages/babel-parser/test/fixtures/experimental/class-static-block/invalid-yield/options.json @@ -0,0 +1,6 @@ +{ + "plugins": [ + "classStaticBlock" + ], + "throws": "Unexpected token, expected \";\" (5:12)" +} \ No newline at end of file diff --git a/packages/babel-parser/test/fixtures/experimental/class-static-block/lexical-scope/input.js b/packages/babel-parser/test/fixtures/experimental/class-static-block/lexical-scope/input.js new file mode 100644 index 000000000000..2cd8f709b6be --- /dev/null +++ b/packages/babel-parser/test/fixtures/experimental/class-static-block/lexical-scope/input.js @@ -0,0 +1,6 @@ +class C { + static foo() {} + static { + const C = {}; + } +} diff --git a/packages/babel-parser/test/fixtures/experimental/class-static-block/lexical-scope/output.json b/packages/babel-parser/test/fixtures/experimental/class-static-block/lexical-scope/output.json new file mode 100644 index 000000000000..f699611490f0 --- /dev/null +++ b/packages/babel-parser/test/fixtures/experimental/class-static-block/lexical-scope/output.json @@ -0,0 +1,78 @@ +{ + "type": "File", + "start":0,"end":62,"loc":{"start":{"line":1,"column":0},"end":{"line":6,"column":1}}, + "program": { + "type": "Program", + "start":0,"end":62,"loc":{"start":{"line":1,"column":0},"end":{"line":6,"column":1}}, + "sourceType": "script", + "interpreter": null, + "body": [ + { + "type": "ClassDeclaration", + "start":0,"end":62,"loc":{"start":{"line":1,"column":0},"end":{"line":6,"column":1}}, + "id": { + "type": "Identifier", + "start":6,"end":7,"loc":{"start":{"line":1,"column":6},"end":{"line":1,"column":7},"identifierName":"C"}, + "name": "C" + }, + "superClass": null, + "body": { + "type": "ClassBody", + "start":8,"end":62,"loc":{"start":{"line":1,"column":8},"end":{"line":6,"column":1}}, + "body": [ + { + "type": "ClassMethod", + "start":12,"end":27,"loc":{"start":{"line":2,"column":2},"end":{"line":2,"column":17}}, + "static": true, + "key": { + "type": "Identifier", + "start":19,"end":22,"loc":{"start":{"line":2,"column":9},"end":{"line":2,"column":12},"identifierName":"foo"}, + "name": "foo" + }, + "computed": false, + "kind": "method", + "id": null, + "generator": false, + "async": false, + "params": [], + "body": { + "type": "BlockStatement", + "start":25,"end":27,"loc":{"start":{"line":2,"column":15},"end":{"line":2,"column":17}}, + "body": [], + "directives": [] + } + }, + { + "type": "StaticBlock", + "start":30,"end":60,"loc":{"start":{"line":3,"column":2},"end":{"line":5,"column":3}}, + "body": [ + { + "type": "VariableDeclaration", + "start":43,"end":56,"loc":{"start":{"line":4,"column":4},"end":{"line":4,"column":17}}, + "declarations": [ + { + "type": "VariableDeclarator", + "start":49,"end":55,"loc":{"start":{"line":4,"column":10},"end":{"line":4,"column":16}}, + "id": { + "type": "Identifier", + "start":49,"end":50,"loc":{"start":{"line":4,"column":10},"end":{"line":4,"column":11},"identifierName":"C"}, + "name": "C" + }, + "init": { + "type": "ObjectExpression", + "start":53,"end":55,"loc":{"start":{"line":4,"column":14},"end":{"line":4,"column":16}}, + "properties": [] + } + } + ], + "kind": "const" + } + ] + } + ] + } + } + ], + "directives": [] + } +} \ No newline at end of file diff --git a/packages/babel-parser/test/fixtures/experimental/class-static-block/nested-control-flow/input.js b/packages/babel-parser/test/fixtures/experimental/class-static-block/nested-control-flow/input.js new file mode 100644 index 000000000000..ab5609153f0b --- /dev/null +++ b/packages/babel-parser/test/fixtures/experimental/class-static-block/nested-control-flow/input.js @@ -0,0 +1,17 @@ +class C { + static foo() {} + static { + while (this.foo) { + if (this.foo) { + break; + } else { + continue; + } + } + class C2 { + bar() { + return; + } + } + } +} diff --git a/packages/babel-parser/test/fixtures/experimental/class-static-block/nested-control-flow/output.json b/packages/babel-parser/test/fixtures/experimental/class-static-block/nested-control-flow/output.json new file mode 100644 index 000000000000..02113c87951f --- /dev/null +++ b/packages/babel-parser/test/fixtures/experimental/class-static-block/nested-control-flow/output.json @@ -0,0 +1,168 @@ +{ + "type": "File", + "start":0,"end":210,"loc":{"start":{"line":1,"column":0},"end":{"line":17,"column":1}}, + "program": { + "type": "Program", + "start":0,"end":210,"loc":{"start":{"line":1,"column":0},"end":{"line":17,"column":1}}, + "sourceType": "script", + "interpreter": null, + "body": [ + { + "type": "ClassDeclaration", + "start":0,"end":210,"loc":{"start":{"line":1,"column":0},"end":{"line":17,"column":1}}, + "id": { + "type": "Identifier", + "start":6,"end":7,"loc":{"start":{"line":1,"column":6},"end":{"line":1,"column":7},"identifierName":"C"}, + "name": "C" + }, + "superClass": null, + "body": { + "type": "ClassBody", + "start":8,"end":210,"loc":{"start":{"line":1,"column":8},"end":{"line":17,"column":1}}, + "body": [ + { + "type": "ClassMethod", + "start":12,"end":27,"loc":{"start":{"line":2,"column":2},"end":{"line":2,"column":17}}, + "static": true, + "key": { + "type": "Identifier", + "start":19,"end":22,"loc":{"start":{"line":2,"column":9},"end":{"line":2,"column":12},"identifierName":"foo"}, + "name": "foo" + }, + "computed": false, + "kind": "method", + "id": null, + "generator": false, + "async": false, + "params": [], + "body": { + "type": "BlockStatement", + "start":25,"end":27,"loc":{"start":{"line":2,"column":15},"end":{"line":2,"column":17}}, + "body": [], + "directives": [] + } + }, + { + "type": "StaticBlock", + "start":30,"end":208,"loc":{"start":{"line":3,"column":2},"end":{"line":16,"column":3}}, + "body": [ + { + "type": "WhileStatement", + "start":43,"end":145,"loc":{"start":{"line":4,"column":4},"end":{"line":10,"column":5}}, + "test": { + "type": "MemberExpression", + "start":50,"end":58,"loc":{"start":{"line":4,"column":11},"end":{"line":4,"column":19}}, + "object": { + "type": "ThisExpression", + "start":50,"end":54,"loc":{"start":{"line":4,"column":11},"end":{"line":4,"column":15}} + }, + "computed": false, + "property": { + "type": "Identifier", + "start":55,"end":58,"loc":{"start":{"line":4,"column":16},"end":{"line":4,"column":19},"identifierName":"foo"}, + "name": "foo" + } + }, + "body": { + "type": "BlockStatement", + "start":60,"end":145,"loc":{"start":{"line":4,"column":21},"end":{"line":10,"column":5}}, + "body": [ + { + "type": "IfStatement", + "start":68,"end":139,"loc":{"start":{"line":5,"column":6},"end":{"line":9,"column":7}}, + "test": { + "type": "MemberExpression", + "start":72,"end":80,"loc":{"start":{"line":5,"column":10},"end":{"line":5,"column":18}}, + "object": { + "type": "ThisExpression", + "start":72,"end":76,"loc":{"start":{"line":5,"column":10},"end":{"line":5,"column":14}} + }, + "computed": false, + "property": { + "type": "Identifier", + "start":77,"end":80,"loc":{"start":{"line":5,"column":15},"end":{"line":5,"column":18},"identifierName":"foo"}, + "name": "foo" + } + }, + "consequent": { + "type": "BlockStatement", + "start":82,"end":106,"loc":{"start":{"line":5,"column":20},"end":{"line":7,"column":7}}, + "body": [ + { + "type": "BreakStatement", + "start":92,"end":98,"loc":{"start":{"line":6,"column":8},"end":{"line":6,"column":14}}, + "label": null + } + ], + "directives": [] + }, + "alternate": { + "type": "BlockStatement", + "start":112,"end":139,"loc":{"start":{"line":7,"column":13},"end":{"line":9,"column":7}}, + "body": [ + { + "type": "ContinueStatement", + "start":122,"end":131,"loc":{"start":{"line":8,"column":8},"end":{"line":8,"column":17}}, + "label": null + } + ], + "directives": [] + } + } + ], + "directives": [] + } + }, + { + "type": "ClassDeclaration", + "start":150,"end":204,"loc":{"start":{"line":11,"column":4},"end":{"line":15,"column":5}}, + "id": { + "type": "Identifier", + "start":156,"end":158,"loc":{"start":{"line":11,"column":10},"end":{"line":11,"column":12},"identifierName":"C2"}, + "name": "C2" + }, + "superClass": null, + "body": { + "type": "ClassBody", + "start":159,"end":204,"loc":{"start":{"line":11,"column":13},"end":{"line":15,"column":5}}, + "body": [ + { + "type": "ClassMethod", + "start":167,"end":198,"loc":{"start":{"line":12,"column":6},"end":{"line":14,"column":7}}, + "static": false, + "key": { + "type": "Identifier", + "start":167,"end":170,"loc":{"start":{"line":12,"column":6},"end":{"line":12,"column":9},"identifierName":"bar"}, + "name": "bar" + }, + "computed": false, + "kind": "method", + "id": null, + "generator": false, + "async": false, + "params": [], + "body": { + "type": "BlockStatement", + "start":173,"end":198,"loc":{"start":{"line":12,"column":12},"end":{"line":14,"column":7}}, + "body": [ + { + "type": "ReturnStatement", + "start":183,"end":190,"loc":{"start":{"line":13,"column":8},"end":{"line":13,"column":15}}, + "argument": null + } + ], + "directives": [] + } + } + ] + } + } + ] + } + ] + } + } + ], + "directives": [] + } +} \ No newline at end of file diff --git a/packages/babel-parser/test/fixtures/experimental/class-static-block/options.json b/packages/babel-parser/test/fixtures/experimental/class-static-block/options.json new file mode 100644 index 000000000000..70adcb5e62d3 --- /dev/null +++ b/packages/babel-parser/test/fixtures/experimental/class-static-block/options.json @@ -0,0 +1,3 @@ +{ + "plugins": ["classStaticBlock"] +} diff --git a/packages/babel-parser/test/fixtures/experimental/class-static-block/super-property/input.js b/packages/babel-parser/test/fixtures/experimental/class-static-block/super-property/input.js new file mode 100644 index 000000000000..ff11fa3c1c58 --- /dev/null +++ b/packages/babel-parser/test/fixtures/experimental/class-static-block/super-property/input.js @@ -0,0 +1,8 @@ +class B { + static foo() {} +} +class C extends B { + static { + this.bar = super.foo; + } +} diff --git a/packages/babel-parser/test/fixtures/experimental/class-static-block/super-property/output.json b/packages/babel-parser/test/fixtures/experimental/class-static-block/super-property/output.json new file mode 100644 index 000000000000..47fdf151f2b3 --- /dev/null +++ b/packages/babel-parser/test/fixtures/experimental/class-static-block/super-property/output.json @@ -0,0 +1,114 @@ +{ + "type": "File", + "start":0,"end":92,"loc":{"start":{"line":1,"column":0},"end":{"line":8,"column":1}}, + "program": { + "type": "Program", + "start":0,"end":92,"loc":{"start":{"line":1,"column":0},"end":{"line":8,"column":1}}, + "sourceType": "script", + "interpreter": null, + "body": [ + { + "type": "ClassDeclaration", + "start":0,"end":29,"loc":{"start":{"line":1,"column":0},"end":{"line":3,"column":1}}, + "id": { + "type": "Identifier", + "start":6,"end":7,"loc":{"start":{"line":1,"column":6},"end":{"line":1,"column":7},"identifierName":"B"}, + "name": "B" + }, + "superClass": null, + "body": { + "type": "ClassBody", + "start":8,"end":29,"loc":{"start":{"line":1,"column":8},"end":{"line":3,"column":1}}, + "body": [ + { + "type": "ClassMethod", + "start":12,"end":27,"loc":{"start":{"line":2,"column":2},"end":{"line":2,"column":17}}, + "static": true, + "key": { + "type": "Identifier", + "start":19,"end":22,"loc":{"start":{"line":2,"column":9},"end":{"line":2,"column":12},"identifierName":"foo"}, + "name": "foo" + }, + "computed": false, + "kind": "method", + "id": null, + "generator": false, + "async": false, + "params": [], + "body": { + "type": "BlockStatement", + "start":25,"end":27,"loc":{"start":{"line":2,"column":15},"end":{"line":2,"column":17}}, + "body": [], + "directives": [] + } + } + ] + } + }, + { + "type": "ClassDeclaration", + "start":30,"end":92,"loc":{"start":{"line":4,"column":0},"end":{"line":8,"column":1}}, + "id": { + "type": "Identifier", + "start":36,"end":37,"loc":{"start":{"line":4,"column":6},"end":{"line":4,"column":7},"identifierName":"C"}, + "name": "C" + }, + "superClass": { + "type": "Identifier", + "start":46,"end":47,"loc":{"start":{"line":4,"column":16},"end":{"line":4,"column":17},"identifierName":"B"}, + "name": "B" + }, + "body": { + "type": "ClassBody", + "start":48,"end":92,"loc":{"start":{"line":4,"column":18},"end":{"line":8,"column":1}}, + "body": [ + { + "type": "StaticBlock", + "start":52,"end":90,"loc":{"start":{"line":5,"column":2},"end":{"line":7,"column":3}}, + "body": [ + { + "type": "ExpressionStatement", + "start":65,"end":86,"loc":{"start":{"line":6,"column":4},"end":{"line":6,"column":25}}, + "expression": { + "type": "AssignmentExpression", + "start":65,"end":85,"loc":{"start":{"line":6,"column":4},"end":{"line":6,"column":24}}, + "operator": "=", + "left": { + "type": "MemberExpression", + "start":65,"end":73,"loc":{"start":{"line":6,"column":4},"end":{"line":6,"column":12}}, + "object": { + "type": "ThisExpression", + "start":65,"end":69,"loc":{"start":{"line":6,"column":4},"end":{"line":6,"column":8}} + }, + "computed": false, + "property": { + "type": "Identifier", + "start":70,"end":73,"loc":{"start":{"line":6,"column":9},"end":{"line":6,"column":12},"identifierName":"bar"}, + "name": "bar" + } + }, + "right": { + "type": "MemberExpression", + "start":76,"end":85,"loc":{"start":{"line":6,"column":15},"end":{"line":6,"column":24}}, + "object": { + "type": "Super", + "start":76,"end":81,"loc":{"start":{"line":6,"column":15},"end":{"line":6,"column":20}} + }, + "computed": false, + "property": { + "type": "Identifier", + "start":82,"end":85,"loc":{"start":{"line":6,"column":21},"end":{"line":6,"column":24},"identifierName":"foo"}, + "name": "foo" + } + } + } + } + ] + } + ] + } + } + ], + "directives": [] + } +} \ No newline at end of file diff --git a/packages/babel-parser/typings/babel-parser.d.ts b/packages/babel-parser/typings/babel-parser.d.ts index 60fabcc52510..51b1ef9fce5e 100644 --- a/packages/babel-parser/typings/babel-parser.d.ts +++ b/packages/babel-parser/typings/babel-parser.d.ts @@ -100,6 +100,7 @@ export type ParserPlugin = 'classPrivateMethods' | 'classPrivateProperties' | 'classProperties' | + 'classStaticBlock' | 'decimal' | 'decorators' | 'decorators-legacy' | diff --git a/packages/babel-plugin-syntax-class-static-block/.npmignore b/packages/babel-plugin-syntax-class-static-block/.npmignore new file mode 100644 index 000000000000..f9806945836e --- /dev/null +++ b/packages/babel-plugin-syntax-class-static-block/.npmignore @@ -0,0 +1,3 @@ +src +test +*.log diff --git a/packages/babel-plugin-syntax-class-static-block/README.md b/packages/babel-plugin-syntax-class-static-block/README.md new file mode 100644 index 000000000000..77cdf1e229c0 --- /dev/null +++ b/packages/babel-plugin-syntax-class-static-block/README.md @@ -0,0 +1,19 @@ +# @babel/plugin-syntax-class-static-block + +> Allow parsing of class static blocks + +See our website [@babel/plugin-syntax-class-static-block](https://babeljs.io/docs/en/next/babel-plugin-syntax-class-static-block.html) for more information. + +## Install + +Using npm: + +```sh +npm install --save-dev @babel/plugin-syntax-class-static-block +``` + +or using yarn: + +```sh +yarn add @babel/plugin-syntax-class-static-block --dev +``` diff --git a/packages/babel-plugin-syntax-class-static-block/package.json b/packages/babel-plugin-syntax-class-static-block/package.json new file mode 100644 index 000000000000..18fcf9e5c376 --- /dev/null +++ b/packages/babel-plugin-syntax-class-static-block/package.json @@ -0,0 +1,27 @@ +{ + "name": "@babel/plugin-syntax-class-static-block", + "version": "7.11.0", + "description": "Allow parsing of class static blocks", + "repository": { + "type": "git", + "url": "https://github.com/babel/babel.git", + "directory": "packages/babel-plugin-syntax-class-static-block" + }, + "license": "MIT", + "publishConfig": { + "access": "public" + }, + "main": "./lib/index.js", + "exports": { + ".": "./lib/index.js" + }, + "keywords": [ + "babel-plugin" + ], + "dependencies": { + "@babel/helper-plugin-utils": "workspace:^7.10.1" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } +} diff --git a/packages/babel-plugin-syntax-class-static-block/src/index.js b/packages/babel-plugin-syntax-class-static-block/src/index.js new file mode 100644 index 000000000000..716fb853b288 --- /dev/null +++ b/packages/babel-plugin-syntax-class-static-block/src/index.js @@ -0,0 +1,13 @@ +import { declare } from "@babel/helper-plugin-utils"; + +export default declare(api => { + api.assertVersion(7); + + return { + name: "syntax-class-static-block", + + manipulateOptions(opts, parserOpts) { + parserOpts.plugins.push("classStaticBlock"); + }, + }; +}); diff --git a/packages/babel-types/src/asserts/generated/index.js b/packages/babel-types/src/asserts/generated/index.js index 23a3e3cbb9e2..c695066b4fdd 100644 --- a/packages/babel-types/src/asserts/generated/index.js +++ b/packages/babel-types/src/asserts/generated/index.js @@ -803,6 +803,9 @@ export function assertTupleExpression(node: Object, opts?: Object = {}): void { export function assertDecimalLiteral(node: Object, opts?: Object = {}): void { assert("DecimalLiteral", node, opts); } +export function assertStaticBlock(node: Object, opts?: Object = {}): void { + assert("StaticBlock", node, opts); +} export function assertTSParameterProperty( node: Object, opts?: Object = {}, diff --git a/packages/babel-types/src/builders/generated/index.js b/packages/babel-types/src/builders/generated/index.js index 44b76e7aea31..8c969f838690 100644 --- a/packages/babel-types/src/builders/generated/index.js +++ b/packages/babel-types/src/builders/generated/index.js @@ -734,6 +734,10 @@ export function decimalLiteral(...args: Array): Object { return builder("DecimalLiteral", ...args); } export { decimalLiteral as DecimalLiteral }; +export function staticBlock(...args: Array): Object { + return builder("StaticBlock", ...args); +} +export { staticBlock as StaticBlock }; export function tsParameterProperty(...args: Array): Object { return builder("TSParameterProperty", ...args); } diff --git a/packages/babel-types/src/definitions/experimental.js b/packages/babel-types/src/definitions/experimental.js index 984e1897da3d..d9e0b9879a8b 100644 --- a/packages/babel-types/src/definitions/experimental.js +++ b/packages/babel-types/src/definitions/experimental.js @@ -245,3 +245,17 @@ defineType("DecimalLiteral", { }, aliases: ["Expression", "Pureish", "Literal", "Immutable"], }); + +// https://github.com/tc39/proposal-class-static-block +defineType("StaticBlock", { + visitor: ["body"], + fields: { + body: { + validate: chain( + assertValueType("array"), + assertEach(assertNodeType("Statement")), + ), + }, + }, + aliases: ["Scopable", "BlockParent"], +}); diff --git a/packages/babel-types/src/validators/generated/index.js b/packages/babel-types/src/validators/generated/index.js index a5c5b68bdf7b..ac0aa73a3fb9 100644 --- a/packages/babel-types/src/validators/generated/index.js +++ b/packages/babel-types/src/validators/generated/index.js @@ -2587,6 +2587,20 @@ export function isDecimalLiteral(node: ?Object, opts?: Object): boolean { return false; } +export function isStaticBlock(node: ?Object, opts?: Object): boolean { + if (!node) return false; + + const nodeType = node.type; + if (nodeType === "StaticBlock") { + if (typeof opts === "undefined") { + return true; + } else { + return shallowEqual(node, opts); + } + } + + return false; +} export function isTSParameterProperty(node: ?Object, opts?: Object): boolean { if (!node) return false; @@ -3591,6 +3605,7 @@ export function isScopable(node: ?Object, opts?: Object): boolean { "ForOfStatement" === nodeType || "ClassMethod" === nodeType || "ClassPrivateMethod" === nodeType || + "StaticBlock" === nodeType || "TSModuleBlock" === nodeType || (nodeType === "Placeholder" && "BlockStatement" === node.expectedNode) ) { @@ -3624,6 +3639,7 @@ export function isBlockParent(node: ?Object, opts?: Object): boolean { "ForOfStatement" === nodeType || "ClassMethod" === nodeType || "ClassPrivateMethod" === nodeType || + "StaticBlock" === nodeType || "TSModuleBlock" === nodeType || (nodeType === "Placeholder" && "BlockStatement" === node.expectedNode) ) { diff --git a/yarn.lock b/yarn.lock index a2a7fe4ea314..b3bec718c577 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1449,6 +1449,16 @@ __metadata: languageName: unknown linkType: soft +"@babel/plugin-syntax-class-static-block@workspace:packages/babel-plugin-syntax-class-static-block": + version: 0.0.0-use.local + resolution: "@babel/plugin-syntax-class-static-block@workspace:packages/babel-plugin-syntax-class-static-block" + dependencies: + "@babel/helper-plugin-utils": "workspace:^7.10.1" + peerDependencies: + "@babel/core": ^7.0.0-0 + languageName: unknown + linkType: soft + "@babel/plugin-syntax-decimal@workspace:^7.11.0, @babel/plugin-syntax-decimal@workspace:packages/babel-plugin-syntax-decimal": version: 0.0.0-use.local resolution: "@babel/plugin-syntax-decimal@workspace:packages/babel-plugin-syntax-decimal"