Skip to content

Tracking: Language services provide intellisense for Angular 2 templates #7482

Closed

Description

@mhevery

We plan to use the extension API tracked by TypeScript issue #6508 to provide language services inside template strings of a @Component decorator as well as reuse these services in loose HTML files.

Features

The features we plan to support are,

  • Syntax and semantic code highlighting
  • Syntactic and semantic error reporting
  • Completion lists for HTML built-in elements and referenced directives
  • Completion list for data-binding expression
  • Parameter lists for data-binding function calls
  • Go-to definition on attributes, elements and binding expressions

A prototype of these features was already implemented by Microsoft as part of the work to validate the their extensibility and the referenced issue has an animated GIF that shows the prototype in action.

This work is to use the Angular 2's template parser, instead of a custom parser, as well as using the Angular 2 offline-compiler metadata to describe the components allowing libraries (such as Material) to be self-describing.

Additional features (probably post-final):

  • Source formatting and indentation support
  • Rename of directive and attributes
  • Quick fix to add missing directives Component decorator

Editor support

Editors that support configuring TypeScript extensions will be able to use the Angular 2 extensions for template strings with no additional changes.

Editors will need to be modified to integrate the Angular 2 language service for loose HTML files similar to how TypeScript is integrated for use in .ts, .d.ts and .tsx.

This work will extend the TypeScript node server and VS Code to support both the Angular 2 extension and loose HTML files.

Milestones

Initial release

Extending TypeScript

Tasks:

Problem: Angular 2 templates can be specified using a string literal or string template inside a TypeScript file. Providing language services for these strings requires TypeScript's language service to delegate calls to LanguageService to the Angular 2 language service.

Soltuion: Use the proposed extensibility interface provided by TypeScript. Help evangelize the extension API to editors that support TypeScript.

Syntax Highlighting

Tasks:

  • Augment the result of getEncodedSemanticClassifications with Angular 2 classifications using HtmlLexer. Using .tmLanguage instead.

Problem: Produce ClassifiedSpan[] for ranges that intersect with a Angular 2 template. This requires determining if the span is in a template string which itself requires a semantic analysis of the TypeScript module to determine if the string is in a @Component decorator.

Solution: Only return Angular 2 syntactic classification in getEncodedSemanticClassifications because the semantic analysis of the TypeScript module is already available. To produce the spans, scan the ClassifiedSpans returned by TypeScript and determine if any strings contained in the result are candidates. Use HtmlLexer to produce lexical tokens from the string and generate ClassifiedSpans from the tokens.

Semantic Highlighting

Tasks:

  • Augment the result from Syntax Highlighting with semantic information from the TemplateParser AST. Using tmLanguage file instead.

Problem: Allow highlighting directives with a different color from built in HTML elements and attributes.

Solution: Use Angular 2's TemplateParser to produce a template AST and augment the classifications produce during Syntax Highlighting using information from this AST.

Diagnostic Messages

Tasks:

  • Invoke the TemplateParser on template strings and augment the result of getSemanticDiagnostics().
  • Generate the template code for the template AST and augment with the diagnostics from the generated modules.

Problem: Produce error and warning messages for Angular 2 templates in .ts.

Solution: Invoke the Angular 2 TemplateParser on template strings in TypeScript modules and augment the result of getSemanticDiagnostics() with the result. Even syntax errors are delayed until getSemanticDiagnostics() because determining if a string is a Angular 2 template requires TypeScript semantic analysis.

Problem: Produce errors produced by code generated from a template.

Solution: Invoke the offline compiler to produce the corresponding TypeScript for a template. Produce a secondary LanguageService for a project that now includes the generated code and augment the result diagnostics from the generated module.

Alternative: The proposed solution might take significant time and resources because it requires instantiating an additional TypeScript language service which potentially could double the memory and time to respond to language service calls. Alternately the expression AST could be typed directly against the TypeScript symbols and error messages produced without invoking a secondary language service. The current proposal is simpler but the alternative should be considered if performance and memory are an issue for the proposed solution.

Template Completions

Tasks:

  • Produce completion lists for element names.
  • Produce completion lists for attribute names.
  • Produce completion lists for attribute values from attribute type.
  • Produce completion lists for binding expressions.
  • Produce completion lists for interpolation expressions.
  • Produce parameter help for data-binding function calls.

Notes: All solutions begin by producing a TemplateParser AST and determine where in the AST the position requested corresponds to. All built-in HTML elements and attributes are treated as a built-in list of directives to avoid special casing HTML.

Problem: Produce completions lists for element names.

Solution: If the position is where an element is expected produce a list of available element selectors from the referenced directives.

Problem: Produce a list of attributes names.

Solution: If the position is where an attribute name is expected produce the list of available attribute selectors that could match the current element.

Problem: Produce list for attribute values from attribute type.

Solution: If the position is where an attribute value is expected determine the type of the attribute by requesting the type from TypeScript, produce the completion list from the types member symbols.

Problem: Produce completion lists for binding expressions.

Solution: If the position is where a binding expression is expected generate the corresponding template code and request a completion list from the corresponding location in the generated code from an internal TypeScript language service. See Alternatives in Diagnostic Messages for an alternative to the code generation approach and conditions for pursuing the alternative.

Problem: Produce completion lists for interpolation expressions.

Solution: If the position is where an interpolation expression is expected treat it like a binding expression above.

Problem: Produce parameter help for data-binding function calls.

Solution: If the position is where a binding expression or interpolation expression is expected use the technique in binding expressions above but requires a parameter list instead of a completion list from the language service.

Go to definition

  • Go to definition of an element name.
  • Go to definition of an attribute name.
  • Go to definition of an attribute value.
  • Go to definition of an binding expression.
  • Go to definition of an interpolation expression.

Problem: Determine location that defines a template element.

Solution: Use the same technique as is used in Template Completions for the corresponding request but request references from TypeScript instead generating a completion list.

Sharable metadata

Tasks:

Problem: Parsing an Angular 2 template relies on information provided using decorators. These decorators, however, are discarded when TypeScript produces a .d.ts file. The language services need a way to retrieve this information for modules for which it only has .d.ts files.

Solution: Write the decorator information discarded by TypeScript into a .metadata.json file that can be read by the language services. This is will be produced for Angular by the Angular build and for other libraries, such as Angular Material, by the Angular CLI when packaging the module for deployment.

Alternative: The metadata could be derived by loading the referenced modules. However this requires executing the modules thus requiring the language service to execute arbitrary third-party code directly. In many contexts, this would be an unacceptable risk. Also, some modules might have dependencies that could not be loaded in all contexts the language service must run such as modules with a browser dependency running in the tsserver. The proposed solution does not rely on executing third-party code so does not expose the language service to running potentially unready, incompatible, and/or unreliable code with unintended side-effects just to extract metadata information. Also, .metadata.json files can be written by a system that does load the modules and extracts the metadata information allowing the module to be loaded in a controlled environment outside the language service.

Activity

  1. added this to the milestone on Mar 8, 2016
  2. modified the milestones: , Angular 2 Release Candidate on Mar 8, 2016
  3. mhevery commented on Mar 9, 2016

    @mhevery
    ContributorAuthor

    @chuckjaz this is great (I moved your comment to the description). Could we add some checklist to it of smaller milestones? See: https://github.com/blog/1375-task-lists-in-gfm-issues-pulls-comments

  4. chuckjaz commented on Mar 10, 2016

    @chuckjaz
    Contributor

    @mhevery I added milestone information.

  5. mhevery commented on Mar 11, 2016

    @mhevery
    ContributorAuthor

    Very nice! Thanks @chuckjaz!

  6. billti commented on Mar 13, 2016

    @billti

    Sweet! Just a note on the Syntax Highlighting section above - currently VSCode (as well as Sublime Text) use TextMate grammars for syntax highlighting, so having an AST available doesn't help there. I'm not sure if/when those editors plan to provide more programatic control over syntax highlighting.

    FWIW: I did a simple TextMate grammar update while prototyping to provide some rudimentary syntax highlighting if the expression is a JavaScript template string for an object property named template, or was preceded by a marker comment (e.g. /** @html */).

    Note that I found the JsDoc type marker helpful (for syntax highlighting at least) as in several samples I saw, devs would use a pattern like the below, which is a challenge to tool for the template string. Hopefully with better tooling this will become less of a thing.

    // comp.ts
    import {tmpl} from './mytemplate'
    
    @Component({
      template: tmpl
      // etc..
    })
    export class SomeComp { }
    
    // mytemplate.ts
    export const tmpl = /** @html */ `<div>Some component here</div>`
  7. chuckjaz commented on Mar 28, 2016

    @chuckjaz
    Contributor

    @billti How do you get VSCode to read the updated grammar?

  8. billti commented on Mar 28, 2016

    @billti

    For development/testing, I just copy it over (e.g. on a Mac cp "/Users/bill/src/TypeScript-TmLanguage/TypeScript.tmLanguage" "/Applications/Visual Studio Code.app/Contents/Resources/app/extensions/typescript/syntaxes/TypeScript.tmLanguage".

    I don't believe VS Code has a supported way to extend built-in grammars yet, so we'd need to update the official one, or get some type of support added.

  9. 47 remaining items

  10. angelozerr commented on Jan 11, 2017

    @angelozerr

    which won't happen until after TypeScript 2.2.

    To fix this problem today, I'm updating tsserver by following the same idea than https://github.com/Quramy/ng-tsserver It's little ugly but it works. I'm developping a tslint language service like your angular language service at https://github.com/angelozerr/tslint-language-service

  11. chuckjaz commented on Jan 11, 2017

    @chuckjaz
    Contributor

    @angelozerr That is terrific! That works in a large set scenarios.

    However, you have to make compromises in how the information is presented as all the completions and diagnostics have to look like they came from TypeScript. I am collaborating with TypeScript to fix this by extending the completion kinds, allowing specifying a source for the diagnostic, etc. Also, we need to define the behavior of what happens when a file unknown to the interface is passed in as well as how to augment the server in such a way as to include template files when calculating the project, etc. None of these compromises we feel are are acceptable for a VS integration.

  12. angelozerr commented on Feb 8, 2017

    @angelozerr

    @chuckjaz thanks for this information.

    I have created https://github.com/angelozerr/tsserver-plugins which concat at runtime the JS which override createLangugaeService to load plugins declared in the tsconfig.json and a the tsserver.js which is hosted in the node_modules. Instead starting tsserver with typescript/bin/tsserver, you start with tsserver-plugins/bin/tsserver-plugins

  13. andrewrheingans commented on Jul 14, 2017

    @andrewrheingans

    @chuckjaz any update on when this will land in Visual Studio? Thanks!

  14. VovanSuper commented on May 7, 2018

    @VovanSuper

    So, as of release of Angualar 6, is it at all valid project / is it undegoes any active development ?

  15. olivermuc commented on Aug 16, 2018

    @olivermuc

    There is also this autocompletion bug still present:
    angular/vscode-ng-language-service#258

    Sincerely hope this get's addressed at some point. Or if someone could point out how to fix this locally, I'm even happy to do it myself.

    Posting it also here, since I'm not sure who's responsible.

  16. olivermuc commented on Aug 20, 2018

    @olivermuc

    Even if it's decided to not allow underscores in html template property autocompletes, could someone point out how to fix this in the code, I can only image this to be a couple of lines...
    Thanks so much.
    @chuckjaz

  17. jpike88 commented on Feb 26, 2019

    @jpike88

    @olivermuc @chuckjaz last activity on that repo was 3 months ago, and the plugin is plain broken. Is this going to ever be sorted? Just curious

  18. jpike88 commented on Feb 26, 2019

    @jpike88
  19. olivermuc commented on Feb 26, 2019

    @olivermuc

    I found a small hack/workaround to make it work. Will post a link shortly.

  20. olivermuc commented on Feb 26, 2019

    @olivermuc
  21. angular-automatic-lock-bot commented on Sep 14, 2019

    @angular-automatic-lock-bot

    This issue has been automatically locked due to inactivity.
    Please file a new issue if you are encountering a similar or related problem.

    Read more about our automatic conversation locking policy.

    This action has been performed automatically by a bot.

  22. locked and limited conversation to collaborators on Sep 14, 2019
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions