├── src └── com │ └── intellij │ └── lang │ ├── ES7LibraryProvider.java │ ├── ecmascript6 │ ├── parsing │ │ ├── ES7ExpressionParser.java │ │ ├── ES7Parser.java │ │ ├── ES7FunctionParser.java │ │ └── ES7StatementParser.java │ └── validation │ │ └── ES7AnnotatingVisitor.java │ ├── javascript │ ├── dialects │ │ └── ES7ParserDefinition.java │ ├── highlighting │ │ └── ES7SyntaxHighlighterFactory.java │ ├── folding │ │ └── ES7FoldingBuilder.java │ └── formatter │ │ └── ES7FormattingModelBuilder.java │ └── ES7ResolveScopeProvider.java ├── LICENSE ├── README.md └── META-INF └── plugin.xml /src/com/intellij/lang/ES7LibraryProvider.java: -------------------------------------------------------------------------------- 1 | package com.intellij.lang; 2 | 3 | import com.intellij.lang.javascript.library.JSCorePredefinedLibrariesProvider; 4 | import com.intellij.openapi.project.Project; 5 | import com.intellij.openapi.vfs.VirtualFile; 6 | import com.intellij.webcore.libraries.ui.ScriptingLibraryTableModel; 7 | 8 | import java.util.Set; 9 | 10 | /** 11 | * Created by Sergey on 4/4/15. 12 | */ 13 | public class ES7LibraryProvider extends JSCorePredefinedLibrariesProvider { 14 | } 15 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright 2014-2015 Sergey Mamyan 2 | 3 | Licensed under the Apache License, Version 2.0 (the "License"); 4 | you may not use this file except in compliance with the License. 5 | You may obtain a copy of the License at 6 | 7 | http://www.apache.org/licenses/LICENSE-2.0 8 | 9 | Unless required by applicable law or agreed to in writing, software 10 | distributed under the License is distributed on an "AS IS" BASIS, 11 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | See the License for the specific language governing permissions and 13 | limitations under the License. 14 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | intellij-es67 2 | ============= 3 | JavaScript ES6/7 syntax improvements and additions plugin for Inteliij IDEA 14. 4 | Features 5 | ------------- 6 | * ES7 AtScript annotations support 7 | * ES7 async/await support 8 | * `traits`, `export`, `import` block folding support 9 | 10 | Changes 11 | ------------- 12 | 13 | *Version 1.0.1* 14 | * Highlighting bug fix 15 | 16 | *Version 1.0* 17 | * [IDEA-134787](https://youtrack.jetbrains.com/issue/IDEA-134784) : Added support for ES7 AtScript Annotations 18 | * [IDEA-134786](https://youtrack.jetbrains.com/issue/IDEA-134786) : Added support for ES7 async/await 19 | * [IDEA-134785](https://youtrack.jetbrains.com/issue/IDEA-134785) : Fixed import/export parsing errors 20 | * [IDEA-134784](https://youtrack.jetbrains.com/issue/IDEA-134784) : Fixed broken indentations for trait, export, import blocks 21 | * [IDEA-134784](https://youtrack.jetbrains.com/issue/IDEA-134784) : Added folding for `traits`, `export`, `import` blocks 22 | -------------------------------------------------------------------------------- /src/com/intellij/lang/ecmascript6/parsing/ES7ExpressionParser.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2014-2015 Sergey Mamyan 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.intellij.lang.ecmascript6.parsing; 18 | 19 | import com.intellij.lang.PsiBuilder; 20 | import com.intellij.lang.ecmascript6.ES6ElementTypes; 21 | import com.intellij.lang.javascript.JSTokenTypes; 22 | 23 | /** 24 | * ES7 Expression Parser 25 | */ 26 | public class ES7ExpressionParser extends ES6ExpressionParser{ 27 | protected ES7ExpressionParser(ES6Parser parser) { 28 | super(parser); 29 | } 30 | protected boolean parseQualifiedTypeNameTail(PsiBuilder.Marker expr) { 31 | expr.drop(); 32 | return this.builder.getTokenType() != JSTokenTypes.LT || this.tryParseTypeArgumentList(false, ES6ElementTypes.TYPE_ARGUMENT_LIST); 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /src/com/intellij/lang/ecmascript6/parsing/ES7Parser.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2014-2015 Sergey Mamyan 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.intellij.lang.ecmascript6.parsing; 18 | 19 | 20 | import com.intellij.lang.PsiBuilder; 21 | import com.intellij.lang.atscript.AtScriptParser; 22 | 23 | /** 24 | * ES7 Parser 25 | */ 26 | public class ES7Parser extends AtScriptParser { 27 | public ES7Parser(PsiBuilder builder) { 28 | super(builder); 29 | /*builder.setTokenTypeRemapper(new ITokenTypeRemapper() { 30 | @Override 31 | public IElementType filter(IElementType source, int start, int end, CharSequence text) { 32 | if(source == JSTokenTypes.BAD_CHARACTER && '@'==text.charAt(start)) { 33 | return JSTokenTypes.AT; 34 | } 35 | return source; 36 | } 37 | });*/ 38 | this.myStatementParser = new ES7StatementParser(this); 39 | this.myFunctionParser = new ES7FunctionParser(this); 40 | this.myExpressionParser = new ES7ExpressionParser(this); 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /src/com/intellij/lang/javascript/dialects/ES7ParserDefinition.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2014-2015 Sergey Mamyan 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.intellij.lang.javascript.dialects; 18 | 19 | import com.intellij.lang.ASTNode; 20 | import com.intellij.lang.PsiBuilder; 21 | import com.intellij.lang.PsiParser; 22 | import com.intellij.lang.atscript.AtScriptParser; 23 | import com.intellij.lang.ecmascript6.parsing.ES7Parser; 24 | import com.intellij.lang.javascript.JSFlexAdapter; 25 | import com.intellij.lexer.Lexer; 26 | import com.intellij.openapi.project.Project; 27 | import com.intellij.psi.tree.IElementType; 28 | import org.jetbrains.annotations.NotNull; 29 | 30 | /** 31 | * ES7 Parser Definition 32 | */ 33 | public class ES7ParserDefinition extends AtScriptParserDefinition { 34 | @NotNull 35 | public PsiParser createParser(Project project) { 36 | return new PsiParser() { 37 | @NotNull 38 | public ASTNode parse(IElementType root, PsiBuilder builder) { 39 | (new ES7Parser(builder)).parseJS(root); 40 | return builder.getTreeBuilt(); 41 | } 42 | }; 43 | } 44 | 45 | } -------------------------------------------------------------------------------- /src/com/intellij/lang/ecmascript6/validation/ES7AnnotatingVisitor.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2014-2015 Sergey Mamyan 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.intellij.lang.ecmascript6.validation; 18 | 19 | import com.intellij.lang.annotation.AnnotationHolder; 20 | import com.intellij.lang.atscript.psi.impl.AtScriptAttributeImpl; 21 | import com.intellij.lang.ecmascript6.psi.ES6FromClause; 22 | import com.intellij.openapi.editor.DefaultLanguageHighlighterColors; 23 | import com.intellij.openapi.editor.colors.TextAttributesKey; 24 | import com.intellij.openapi.editor.markup.TextAttributes; 25 | import com.intellij.psi.PsiElement; 26 | import org.jetbrains.annotations.NotNull; 27 | 28 | /** 29 | * ES7 Annotating Visitor 30 | */ 31 | public class ES7AnnotatingVisitor extends ES6AnnotatingVisitor { 32 | public ES7AnnotatingVisitor() { 33 | } 34 | 35 | public void visitES6FromClause(ES6FromClause fromClause) { 36 | this.checkReferences(fromClause); 37 | } 38 | 39 | @Override 40 | public void visitElement(PsiElement element) { 41 | if(element instanceof AtScriptAttributeImpl){ 42 | lineMarker(element.getFirstChild(), DefaultLanguageHighlighterColors.METADATA, "attribute", this.myHolder); 43 | lineMarker(element.getFirstChild().getNextSibling(), DefaultLanguageHighlighterColors.METADATA, "attribute", this.myHolder); 44 | } 45 | super.visitElement(element); 46 | } 47 | private static void lineMarker(@NotNull PsiElement element, TextAttributesKey attrKey, String debugName, AnnotationHolder holder) { 48 | justLineMarker(element, attrKey, debugName, holder); 49 | } 50 | private static void justLineMarker(PsiElement markedNode, TextAttributesKey attrKey, String debugName, AnnotationHolder holder) { 51 | holder.createInfoAnnotation(markedNode, debugName).setEnforcedTextAttributes(TextAttributes.ERASE_MARKER); 52 | holder.createInfoAnnotation(markedNode, debugName).setTextAttributes(attrKey); 53 | 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /src/com/intellij/lang/javascript/highlighting/ES7SyntaxHighlighterFactory.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2014-2015 Sergey Mamyan 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.intellij.lang.javascript.highlighting; 18 | 19 | import com.intellij.lang.javascript.JSTokenTypes; 20 | import com.intellij.lang.javascript.dialects.ECMA6LanguageDialect; 21 | import com.intellij.lang.javascript.dialects.ECMA6SyntaxHighlighterFactory; 22 | import com.intellij.openapi.editor.DefaultLanguageHighlighterColors; 23 | import com.intellij.openapi.editor.colors.TextAttributesKey; 24 | import com.intellij.openapi.fileTypes.SyntaxHighlighter; 25 | import com.intellij.psi.tree.IElementType; 26 | import gnu.trove.THashMap; 27 | import org.jetbrains.annotations.NotNull; 28 | 29 | import java.util.Map; 30 | 31 | /** 32 | * ES7 Syntax Highlighter Factory 33 | */ 34 | public class ES7SyntaxHighlighterFactory extends ECMA6SyntaxHighlighterFactory { 35 | public ES7SyntaxHighlighterFactory() { 36 | super(); 37 | } 38 | 39 | @NotNull 40 | protected SyntaxHighlighter createHighlighter() { 41 | return new ES7SyntaxHighlighterFactory.ES7SyntaxHighlighter(); 42 | } 43 | 44 | private static class ES7SyntaxHighlighter extends JSHighlighter { 45 | private final Map myKeysMap = new THashMap(); 46 | 47 | public ES7SyntaxHighlighter() { 48 | super(ECMA6LanguageDialect.DIALECT_OPTION_HOLDER); 49 | this.myKeysMap.put(JSTokenTypes.STRING_TEMPLATE_PART, DefaultLanguageHighlighterColors.STRING); 50 | this.myKeysMap.put(JSTokenTypes.AT, DefaultLanguageHighlighterColors.METADATA); 51 | this.myKeysMap.put(JSTokenTypes.FROM_KEYWORD, DefaultLanguageHighlighterColors.KEYWORD); 52 | this.myKeysMap.put(JSTokenTypes.ASYNC_KEYWORD, DefaultLanguageHighlighterColors.KEYWORD); 53 | this.myKeysMap.put(JSTokenTypes.AWAIT_KEYWORD, DefaultLanguageHighlighterColors.KEYWORD); 54 | } 55 | 56 | @NotNull 57 | public TextAttributesKey[] getTokenHighlights(IElementType tokenType) { 58 | return this.myKeysMap.containsKey(tokenType)?pack((TextAttributesKey)this.myKeysMap.get(tokenType)):super.getTokenHighlights(tokenType); 59 | } 60 | 61 | @Override 62 | public TextAttributesKey getMappedKey(TextAttributesKey original) { 63 | return super.getMappedKey(original); 64 | } 65 | } 66 | 67 | } -------------------------------------------------------------------------------- /src/com/intellij/lang/ES7ResolveScopeProvider.java: -------------------------------------------------------------------------------- 1 | package com.intellij.lang; 2 | 3 | import com.intellij.lang.javascript.AtScriptFileType; 4 | import com.intellij.lang.javascript.TypeScriptFileType; 5 | import com.intellij.lang.javascript.ecmascript6.TypeScriptResolveScopeProvider; 6 | import com.intellij.lang.javascript.library.JSCorePredefinedLibrariesProvider; 7 | import com.intellij.lang.javascript.library.JSLibraryMappings; 8 | import com.intellij.lang.javascript.psi.resolve.JSResolveUtil; 9 | import com.intellij.openapi.components.ServiceManager; 10 | import com.intellij.openapi.fileTypes.FileType; 11 | import com.intellij.openapi.module.Module; 12 | import com.intellij.openapi.project.Project; 13 | import com.intellij.openapi.roots.ProjectRootManager; 14 | import com.intellij.openapi.vfs.VirtualFile; 15 | import com.intellij.psi.PsiElement; 16 | import com.intellij.psi.PsiFile; 17 | import com.intellij.psi.impl.ResolveScopeManager; 18 | import com.intellij.psi.search.GlobalSearchScope; 19 | import com.intellij.psi.util.CachedValue; 20 | import org.jetbrains.annotations.NotNull; 21 | import org.jetbrains.annotations.Nullable; 22 | import java.util.Set; 23 | 24 | /** 25 | * Created by Sergey on 4/4/15. 26 | */ 27 | public class ES7ResolveScopeProvider extends TypeScriptResolveScopeProvider { 28 | @NotNull 29 | public GlobalSearchScope getElementResolveScope(@NotNull PsiElement element) { 30 | GlobalSearchScope scope=null; 31 | Project project = element.getProject(); 32 | PsiFile psiFile = element.getContainingFile(); 33 | if(psiFile != null) { 34 | VirtualFile virtualFile = psiFile.getOriginalFile().getVirtualFile(); 35 | if(virtualFile != null) { 36 | scope = this.getResolveScope(virtualFile, project); 37 | } 38 | } 39 | if(scope==null){ 40 | scope = JSResolveUtil.getJavaScriptSymbolsResolveScope(project); 41 | } 42 | return GlobalSearchScope.getScopeRestrictedByFileTypes(scope, AtScriptFileType.INSTANCE); 43 | } 44 | @Nullable 45 | public GlobalSearchScope getResolveScope(@NotNull VirtualFile file, Project project) { 46 | if(file.getFileType() != AtScriptFileType.INSTANCE) { 47 | return null; 48 | } else if(JSCorePredefinedLibrariesProvider.getJavaScriptCorePredefinedLibraryFiles().contains(file)) { 49 | return new GlobalSearchScope.FilesScope(project, JSCorePredefinedLibrariesProvider.getJavaScriptCorePredefinedLibraryFiles()); 50 | } else { 51 | Module module = ProjectRootManager.getInstance(project).getFileIndex().getModuleForFile(file); 52 | if(module == null) { 53 | return JSResolveUtil.getJavaScriptSymbolsResolveScope(project); 54 | } else { 55 | GlobalSearchScope scopeExcludingJsLibs = (GlobalSearchScope)((CachedValue)JSResolveUtil.ourScopeCache.get(module, null)).getValue(); 56 | GlobalSearchScope.getScopeRestrictedByFileTypes(scopeExcludingJsLibs, AtScriptFileType.INSTANCE); 57 | return scopeExcludingJsLibs; 58 | } 59 | } 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /src/com/intellij/lang/ecmascript6/parsing/ES7FunctionParser.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2014-2015 Sergey Mamyan 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | /* 17 | * Copyright 2014-2015 Sergey Mamyan 18 | * 19 | * Licensed under the Apache License, Version 2.0 (the "License"); 20 | * you may not use this file except in compliance with the License. 21 | * You may obtain a copy of the License at 22 | * 23 | * http://www.apache.org/licenses/LICENSE-2.0 24 | * 25 | * Unless required by applicable law or agreed to in writing, software 26 | * distributed under the License is distributed on an "AS IS" BASIS, 27 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 28 | * See the License for the specific language governing permissions and 29 | * limitations under the License. 30 | */ 31 | package com.intellij.lang.ecmascript6.parsing; 32 | 33 | import com.intellij.lang.PsiBuilder; 34 | import com.intellij.lang.atscript.AtScriptElementTypes; 35 | import com.intellij.lang.atscript.AtScriptFunctionParser; 36 | import com.intellij.lang.javascript.JSStubElementTypes; 37 | import com.intellij.lang.javascript.JSTokenTypes; 38 | import com.intellij.lang.javascript.parsing.FunctionParser; 39 | import com.intellij.openapi.util.Key; 40 | import org.jetbrains.annotations.NotNull; 41 | 42 | /** 43 | * ES7 Function Parser 44 | */ 45 | public class ES7FunctionParser extends AtScriptFunctionParser { 46 | 47 | protected ES7FunctionParser(ES6Parser parser) { 48 | super(parser); 49 | } 50 | public void tryParseAttributesWithoutBrackets() { 51 | while(this.builder.getTokenType() == JSTokenTypes.AT) { 52 | this.parseAttributeWithoutBrackets(); 53 | } 54 | } 55 | 56 | public void parseAttributeWithoutBrackets() { 57 | PsiBuilder.Marker attribute = this.builder.mark(); 58 | this.builder.advanceLexer(); 59 | if(!this.myJavaScriptParser.getExpressionParser().parseQualifiedTypeName()) { 60 | attribute.drop(); 61 | } else { 62 | if(this.builder.getTokenType() == JSTokenTypes.LPAR) { 63 | this.myJavaScriptParser.getExpressionParser().parseArgumentList(); 64 | } 65 | attribute.done(AtScriptElementTypes.ATTRIBUTE); 66 | } 67 | } 68 | public boolean parseFunctionNoMarker(FunctionParser.Context context, @NotNull PsiBuilder.Marker functionMarker) { 69 | String oldKey = this.builder.getUserData(methodsEmptinessKey); 70 | this.builder.putUserData(methodsEmptinessKey,METHODS_EMPTINESS_POSSIBLY); 71 | Boolean result = super.parseFunctionNoMarker(context, functionMarker); 72 | this.builder.putUserData(methodsEmptinessKey,oldKey); 73 | return result; 74 | } 75 | } 76 | -------------------------------------------------------------------------------- /src/com/intellij/lang/javascript/folding/ES7FoldingBuilder.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2014-2015 Sergey Mamyan 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.intellij.lang.javascript.folding; 18 | 19 | import com.intellij.lang.ASTNode; 20 | import com.intellij.lang.ecmascript6.ES6ElementTypes; 21 | import com.intellij.lang.folding.FoldingDescriptor; 22 | import com.intellij.lang.javascript.JSTokenTypes; 23 | import com.intellij.openapi.editor.Document; 24 | import com.intellij.openapi.util.TextRange; 25 | import com.intellij.psi.tree.TokenSet; 26 | import org.jetbrains.annotations.NotNull; 27 | 28 | import java.util.List; 29 | 30 | /** 31 | * ES7 Folding Builder 32 | */ 33 | public class ES7FoldingBuilder extends JavaScriptFoldingBuilder { 34 | static final TokenSet EXPORT_IMPORT = TokenSet.create( 35 | ES6ElementTypes.IMPORT_DECLARATION, 36 | ES6ElementTypes.EXPORT_DECLARATION 37 | ); 38 | protected ASTNode appendDescriptors(ASTNode node, Document document, List descriptors) { 39 | if(EXPORT_IMPORT.contains(node.getElementType())){ 40 | ASTNode rc = node.findChildByType(JSTokenTypes.RBRACE); 41 | ASTNode lc =node.findChildByType(JSTokenTypes.LBRACE); 42 | if(rc!=null && lc!=null){ 43 | descriptors.add(new FoldingDescriptor(node, 44 | new TextRange(lc.getStartOffset(),rc.getStartOffset()+1) 45 | )); 46 | } 47 | }else 48 | if(ES6ElementTypes.ATTRIBUTE_LIST.equals(node.getElementType())){ 49 | if(node.getTextRange().getLength()>0){ 50 | descriptors.add(new FoldingDescriptor(node,node.getTextRange())); 51 | } 52 | }else 53 | if(ES6ElementTypes.PARAMETER_LIST.equals(node.getElementType())){ 54 | ASTNode parent = node.getTreeParent(); 55 | if( 56 | ES6ElementTypes.FUNCTION_DECLARATION.equals(parent.getElementType()) && 57 | ES6ElementTypes.CLASS.equals(parent.getTreeParent().getElementType()) 58 | ){ 59 | descriptors.add(new FoldingDescriptor(node,node.getTextRange())); 60 | } 61 | } 62 | return super.appendDescriptors(node, document, descriptors); 63 | } 64 | protected String getLanguagePlaceholderText(@NotNull ASTNode node, @NotNull TextRange range) { 65 | if(ES6ElementTypes.ATTRIBUTE_LIST.equals(node.getElementType())){ 66 | return "@(..)"; 67 | }else 68 | if(ES6ElementTypes.PARAMETER_LIST.equals(node.getElementType())){ 69 | return "(...)"; 70 | }else 71 | if(EXPORT_IMPORT.contains(node.getElementType())){ 72 | return "{...}"; 73 | }/*else 74 | if(TRAIT.contains(node.getElementType())){ 75 | return "{...}"; 76 | }*/ 77 | return super.getLanguagePlaceholderText(node, range); 78 | } 79 | } 80 | -------------------------------------------------------------------------------- /META-INF/plugin.xml: -------------------------------------------------------------------------------- 1 | 2 | com.intellij.lang.javascript.es67 3 | JavaScript.next Support Plugin 4 | 1.1.0 5 | Sergey Mamyan 6 | 7 | 11 | 12 | Version 1.1.0 14 |

Support only Intellij IDEA 14.1.x

15 |

Intellij IDEA 14.1.x now support ES6/AtScript natively, but still have syntax several issues, this plugin will fix following

16 |
    17 |
  • Migration to Intellij Idea 14.1.x (with AtScript support)
  • 18 |
  • Annotated imports
  • 19 |
  • Class members modifiers bug fix.
  • 20 |
  • Static members annotations bug fix.
  • 21 |
  • Indentation bug fixes.
  • 22 |
  • Syntax highlights for annotations and async,await,from
  • 23 |
24 |

Version 1.0.1

25 |
    26 |
  • Highlighting bug fix
  • 27 |
28 |

Version 1.0

29 |
    30 |
  • IDEA-134787 ES7 AtScript Annotations Support
  • 31 |
  • IDEA-134786 Javascript ES6 async/await support
  • 32 |
  • IDEA-134785 Javascript import/export parsing errors
  • 33 |
  • IDEA-134784 JavaScript Indentation Broken In for traits, export, import blocks
  • 34 |
  • IDEA-134784 traits, export, import block folding
  • 35 |
36 | ]]>
37 | 38 | 39 | 40 | 41 | 43 | JavaScript 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 |
-------------------------------------------------------------------------------- /src/com/intellij/lang/javascript/formatter/ES7FormattingModelBuilder.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2014-2015 Sergey Mamyan 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.intellij.lang.javascript.formatter; 18 | 19 | import com.intellij.formatting.Alignment; 20 | import com.intellij.formatting.Indent; 21 | import com.intellij.formatting.Wrap; 22 | import com.intellij.lang.ASTNode; 23 | import com.intellij.lang.Language; 24 | import com.intellij.lang.ecmascript6.ES6ElementTypes; 25 | import com.intellij.lang.javascript.JSTokenTypes; 26 | import com.intellij.lang.javascript.formatter.blocks.JSBlock; 27 | import com.intellij.lang.javascript.formatter.blocks.SubBlockVisitor; 28 | import com.intellij.lang.javascript.formatter.blocks.alignment.ASTNodeBasedAlignmentFactory; 29 | import com.intellij.psi.codeStyle.CodeStyleSettings; 30 | import com.intellij.psi.tree.TokenSet; 31 | import org.jetbrains.annotations.NotNull; 32 | import org.jetbrains.annotations.Nullable; 33 | 34 | /** 35 | * ES7Formatting Model Builder 36 | */ 37 | public class ES7FormattingModelBuilder extends JavascriptFormattingModelBuilder { 38 | static final TokenSet EXPORT_IMPORT = TokenSet.create( 39 | ES6ElementTypes.IMPORT_DECLARATION, 40 | ES6ElementTypes.EXPORT_DECLARATION 41 | ); 42 | @Override 43 | public JSBlock createSubBlock(@NotNull ASTNode child, Alignment childAlignment, Indent childIndent, Wrap wrap, @NotNull CodeStyleSettings topSettings, @NotNull Language dialect, @Nullable ASTNodeBasedAlignmentFactory sharedAlignmentFactory) { 44 | return new ES7Block(child, childAlignment, childIndent, wrap, topSettings, dialect, sharedAlignmentFactory); 45 | } 46 | 47 | public static class ES7BlockVisitor extends SubBlockVisitor { 48 | public ES7BlockVisitor(@Nullable JSBlock block, @NotNull CodeStyleSettings settings, @NotNull Language dialect, ASTNodeBasedAlignmentFactory alignmentFactory) { 49 | super(block, settings,dialect,alignmentFactory); 50 | } 51 | 52 | @Nullable 53 | @Override 54 | protected Indent getIndent(ASTNode node, ASTNode child) { 55 | if(EXPORT_IMPORT.contains(child.getElementType())){ 56 | return Indent.getAbsoluteNoneIndent(); 57 | } 58 | if( 59 | JSTokenTypes.RBRACE.equals(child.getElementType()) || 60 | JSTokenTypes.LBRACE.equals(child.getElementType()) 61 | ){ 62 | if(child.getTreeParent()!=null && EXPORT_IMPORT.contains(child.getTreeParent().getElementType())){ 63 | return Indent.getNoneIndent(); 64 | } 65 | } 66 | if(ES6ElementTypes.ATTRIBUTE_LIST.equals(node.getElementType())){ 67 | return Indent.getNoneIndent(); 68 | } 69 | if(ES6ElementTypes.VARIABLE.equals(child.getElementType())){ 70 | return Indent.getNoneIndent(); 71 | } 72 | return super.getIndent(node, child); 73 | 74 | } 75 | } 76 | 77 | public static class ES7Block extends JSBlock { 78 | private final Language dialect; 79 | private final ASTNodeBasedAlignmentFactory sharedAlignmentFactory; 80 | 81 | public ES7Block(@NotNull ASTNode node, Alignment alignment, Indent indent, Wrap wrap, @NotNull CodeStyleSettings settings, Language dialect,@Nullable ASTNodeBasedAlignmentFactory sharedAlignmentFactory) { 82 | super(node, alignment, indent, wrap, settings, sharedAlignmentFactory, dialect); 83 | this.sharedAlignmentFactory = sharedAlignmentFactory; 84 | this.dialect = dialect; 85 | } 86 | 87 | @Override 88 | protected SubBlockVisitor createSubBlockVisitor() { 89 | return new ES7BlockVisitor(this, this.getSettings(),this.dialect,this.sharedAlignmentFactory); 90 | } 91 | } 92 | } 93 | -------------------------------------------------------------------------------- /src/com/intellij/lang/ecmascript6/parsing/ES7StatementParser.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2014-2015 Sergey Mamyan 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.intellij.lang.ecmascript6.parsing; 17 | import com.intellij.lang.PsiBuilder; 18 | import com.intellij.lang.WhitespacesBinders; 19 | import com.intellij.lang.ecmascript6.ES6ElementTypes; 20 | import com.intellij.lang.javascript.*; 21 | import com.intellij.lang.javascript.parsing.FunctionParser; 22 | import com.intellij.psi.tree.IElementType; 23 | 24 | /** 25 | * ES7 Statement Parser 26 | */ 27 | public class ES7StatementParser extends ES6StatementParser{ 28 | private static boolean isPropertyNameStart(IElementType elementType) { 29 | return JSKeywordSets.IDENTIFIER_NAMES.contains(elementType) || elementType == JSTokenTypes.LBRACKET; 30 | } 31 | protected ES7StatementParser(ES6Parser parser) { 32 | super(parser); 33 | } 34 | public void parseSourceElement() { 35 | this.parseSourceElementAttributesList(); 36 | IElementType firstToken = this.builder.getTokenType(); 37 | if(firstToken == JSTokenTypes.EXPORT_KEYWORD &&(this.builder.lookAhead(1)== JSTokenTypes.MULT || this.builder.lookAhead(1) == JSTokenTypes.LBRACE)) { 38 | this.parseExportDeclaration(this.builder.mark()); 39 | }else{ 40 | super.parseSourceElement(); 41 | } 42 | 43 | } 44 | public void parseSourceElementAttributesList() { 45 | PsiBuilder.Marker attrList = this.builder.mark(); 46 | Boolean attrs = false; 47 | while(this.builder.getTokenType() == JSTokenTypes.AT) { 48 | attrs = true; 49 | this.myJavaScriptParser.getFunctionParser().parseAttributeWithoutBrackets(); 50 | } 51 | if(attrs){ 52 | attrList.done(JSStubElementTypes.ATTRIBUTE_LIST); 53 | }else{ 54 | attrList.drop(); 55 | } 56 | } 57 | public void parseClassMember() { 58 | PsiBuilder.Marker classMember = this.builder.mark(); 59 | int classMemberOffset = this.builder.getCurrentOffset(); 60 | if(this.builder.getTokenType() == JSTokenTypes.SEMICOLON) { 61 | classMember.drop(); 62 | this.parseEmptyStatement(); 63 | } else { 64 | boolean lexerAdvanced = false; 65 | PsiBuilder.Marker attrList = this.builder.mark(); 66 | this.myJavaScriptParser.getFunctionParser().tryParseAttributesWithoutBrackets(); 67 | IElementType modifier = this.builder.getTokenType(); 68 | while(( 69 | modifier == JSTokenTypes.STATIC_KEYWORD || 70 | modifier == JSTokenTypes.PUBLIC_KEYWORD || 71 | modifier == JSTokenTypes.PRIVATE_KEYWORD || 72 | modifier == JSTokenTypes.ASYNC_KEYWORD || 73 | modifier == JSTokenTypes.CONST_KEYWORD || 74 | modifier == JSTokenTypes.VAR_KEYWORD || 75 | modifier == JSTokenTypes.PROTECTED_KEYWORD 76 | )) { 77 | this.builder.advanceLexer(); 78 | modifier = this.builder.getTokenType(); 79 | lexerAdvanced = true; 80 | } 81 | 82 | attrList.done(JSStubElementTypes.ATTRIBUTE_LIST); 83 | IElementType nextToken = this.builder.getTokenType(); 84 | if(nextToken == JSTokenTypes.CLASS_KEYWORD) { 85 | this.parseClassNoMarker(classMember); 86 | } else 87 | if(nextToken == JSTokenTypes.MIXIN_KEYWORD) { 88 | this.builder.advanceLexer(); 89 | if(this.builder.getTokenType() == JSTokenTypes.IDENTIFIER) { 90 | this.myJavaScriptParser.getExpressionParser().buildTokenElement(JSElementTypes.REFERENCE_EXPRESSION); 91 | } 92 | 93 | this.forceCheckForSemicolon(); 94 | classMember.done(JSElementTypes.MIXIN_STATEMENT); 95 | } else if(nextToken == JSTokenTypes.VAR_KEYWORD || nextToken == JSTokenTypes.CONST_KEYWORD || nextToken == JSTokenTypes.LET_KEYWORD) { 96 | this.parseVarStatementNoMarker(false, classMember); 97 | } else if(nextToken != JSTokenTypes.GET_KEYWORD && nextToken != JSTokenTypes.SET_KEYWORD && nextToken != JSTokenTypes.MULT && nextToken != JSTokenTypes.FUNCTION_KEYWORD) { 98 | if(isPropertyNameStart(nextToken)) { 99 | if(JSKeywordSets.IDENTIFIER_NAMES.contains(nextToken) && JSTokenTypes.LPAR == this.builder.lookAhead(1)) { 100 | this.myJavaScriptParser.getFunctionParser().parseFunctionNoMarker(FunctionParser.Context.SOURCE_ELEMENT, classMember); 101 | this.forceCheckForSemicolon(); 102 | } else if(nextToken == JSTokenTypes.LBRACKET) { 103 | this.myJavaScriptParser.getExpressionParser().parsePropertyName(); 104 | this.myJavaScriptParser.getFunctionParser().parseFunctionNoMarker(FunctionParser.Context.EXPRESSION, classMember); 105 | this.forceCheckForSemicolon(); 106 | } else { 107 | this.parseVarList(false); 108 | this.forceCheckForSemicolon(); 109 | classMember.done(JSStubElementTypes.VAR_STATEMENT); 110 | classMember.setCustomEdgeTokenBinders(INCLUDE_DOC_COMMENT_AT_LEFT, WhitespacesBinders.DEFAULT_RIGHT_BINDER); 111 | } 112 | } else { 113 | this.builder.error(JSBundle.message("javascript.parser.message.expected.statement")); 114 | if(!lexerAdvanced) { 115 | this.builder.advanceLexer(); 116 | } 117 | 118 | classMember.drop(); 119 | } 120 | } else { 121 | if(nextToken == JSTokenTypes.MULT) { 122 | this.builder.advanceLexer(); 123 | } 124 | 125 | this.myJavaScriptParser.getFunctionParser().parseFunctionNoMarker(FunctionParser.Context.SOURCE_ELEMENT, classMember); 126 | } 127 | 128 | assert this.builder.getCurrentOffset() > classMemberOffset; 129 | 130 | } 131 | } 132 | 133 | 134 | @Override 135 | protected boolean parseDialectSpecificSourceElements(PsiBuilder.Marker marker) { 136 | if(this.builder.getTokenType() == JSTokenTypes.IMPORT_KEYWORD){ 137 | this.parseES6ImportStatement(marker); 138 | return true; 139 | }else 140 | if(this.builder.getTokenType() == JSTokenTypes.EXPORT_KEYWORD){ 141 | this.parseExportDeclaration(marker); 142 | return true; 143 | }else{ 144 | return super.parseDialectSpecificSourceElements(marker); 145 | } 146 | } 147 | 148 | 149 | protected void parseExportDeclaration(PsiBuilder.Marker marker) { 150 | LOG.assertTrue(this.builder.getTokenType() == JSTokenTypes.EXPORT_KEYWORD); 151 | this.builder.advanceLexer(); 152 | if(this.builder.getTokenType() == JSTokenTypes.MULT) { 153 | this.builder.advanceLexer(); 154 | if(this.builder.getTokenType() == JSTokenTypes.FROM_KEYWORD){ 155 | this.parseES6FromDeclaration(); 156 | this.forceCheckForSemicolon(); 157 | } 158 | this.forceCheckForSemicolon(); 159 | marker.done(ES6ElementTypes.EXPORT_DECLARATION); 160 | } else if(this.builder.getTokenType() == JSTokenTypes.LBRACE) { 161 | this.builder.advanceLexer(); 162 | this.parseES6ImportOrExportClause(true); 163 | if(this.builder.getTokenType() == JSTokenTypes.FROM_KEYWORD) { 164 | this.parseES6FromDeclaration(); 165 | } 166 | 167 | this.forceCheckForSemicolon(); 168 | marker.done(ES6ElementTypes.EXPORT_DECLARATION); 169 | } else { 170 | LOG.error("* or { expected"); 171 | marker.drop(); 172 | } 173 | 174 | } 175 | protected void parseES6ImportStatement() { 176 | parseES6ImportStatement(this.builder.mark()); 177 | } 178 | protected void parseES6ImportStatement(PsiBuilder.Marker marker) { 179 | LOG.assertTrue(this.builder.getTokenType() == JSTokenTypes.IMPORT_KEYWORD); 180 | this.builder.advanceLexer(); 181 | boolean parsedAnything; 182 | if(JSTokenTypes.STRING_LITERALS.contains(this.builder.getTokenType())) { 183 | parsedAnything = true; 184 | this.builder.advanceLexer(); 185 | if(this.builder.getTokenType() == JSTokenTypes.MULT || this.builder.getTokenType() == JSTokenTypes.LBRACE ){ 186 | this.parseES6ImportClause(); 187 | } 188 | } else { 189 | parsedAnything = this.parseES6ImportClause(); 190 | this.parseES6FromDeclaration(); 191 | } 192 | 193 | if(!parsedAnything) { 194 | this.builder.error(JSBundle.message("javascript.parser.message.expected.identifier.string.literal.or.lbrace")); 195 | } 196 | 197 | this.forceCheckForSemicolon(); 198 | marker.done(ES6ElementTypes.IMPORT_DECLARATION); 199 | } 200 | protected void parseClassNoMarker(PsiBuilder.Marker block) { 201 | if(!(this instanceof ES6StatementParser) && !this.isIdentifierToken(this.builder.lookAhead(1))) { 202 | block.drop(); 203 | this.builder.error(JSBundle.message("javascript.parser.message.expected.statement")); 204 | this.builder.advanceLexer(); 205 | } else { 206 | LOG.assertTrue(JSTokenTypes.CLASS_KEYWORD == this.builder.getTokenType()); 207 | this.builder.advanceLexer(); 208 | if(!this.isIdentifierToken(this.builder.getTokenType())) { 209 | this.builder.error(JSBundle.message("javascript.parser.message.expected.name")); 210 | block.drop(); 211 | } else { 212 | //this.myJavaScriptParser.getExpressionParser().buildTokenElement(JSElementTypes.REFERENCE_EXPRESSION); 213 | //((ES7ExpressionParser)this.myJavaScriptParser.getExpressionParser()).parseQualifiedTypeNameTail(this.builder.mark()); 214 | 215 | this.myJavaScriptParser.getExpressionParser().parseQualifiedTypeName(); 216 | if(this.builder.getTokenType() == JSTokenTypes.EXTENDS_KEYWORD) { 217 | this.parseReferenceList(); 218 | } 219 | 220 | if(this.builder.getTokenType() == JSTokenTypes.IMPLEMENTS_KEYWORD) { 221 | this.parseReferenceList(); 222 | } 223 | 224 | if(this.builder.getTokenType() != JSTokenTypes.LBRACE) { 225 | this.builder.error(JSBundle.message("javascript.parser.message.expected.lbrace")); 226 | } else { 227 | this.builder.advanceLexer(); 228 | 229 | while(this.builder.getTokenType() != JSTokenTypes.RBRACE) { 230 | if(this.builder.eof()) { 231 | this.builder.error(JSBundle.message("javascript.parser.message.missing.rbrace")); 232 | break; 233 | } 234 | 235 | this.parseClassMember(); 236 | } 237 | 238 | this.builder.advanceLexer(); 239 | } 240 | 241 | block.done(this.getClassElementType()); 242 | block.setCustomEdgeTokenBinders(INCLUDE_DOC_COMMENT_AT_LEFT, WhitespacesBinders.DEFAULT_RIGHT_BINDER); 243 | } 244 | } 245 | } 246 | 247 | 248 | } 249 | --------------------------------------------------------------------------------