test: delete integration test for language service plugin (#41740)
This commit deletes the integration test for `@angular/language-service` as a plugin to the standard tsserver. In version 12, Ivy LS will replace legacy View Engine LS as the default, and Ivy LS plugin cannot be loaded via `tsconfig.json` due to the need to run ngcc. This makes the test irrelevant. PR Close #41740
This commit is contained in:
parent
98fc4f4b2f
commit
a0a373be8d
|
@ -29,7 +29,6 @@ integration/hello_world__systemjs_umd/node_modules
|
|||
integration/i18n/node_modules
|
||||
integration/injectable-def/node_modules
|
||||
integration/ivy-i18n/node_modules
|
||||
integration/language_service_plugin/node_modules
|
||||
integration/ng_elements/node_modules
|
||||
integration/ng_elements_schematics/node_modules
|
||||
integration/ng_update/node_modules
|
||||
|
@ -56,7 +55,6 @@ integration/hello_world__systemjs_umd/.yarn_local_cache
|
|||
integration/i18n/.yarn_local_cache
|
||||
integration/injectable-def/.yarn_local_cache
|
||||
integration/ivy-i18n/.yarn_local_cache
|
||||
integration/language_service_plugin/.yarn_local_cache
|
||||
integration/ng_elements/.yarn_local_cache
|
||||
integration/ng_elements_schematics/.yarn_local_cache
|
||||
integration/ng_update/.yarn_local_cache
|
||||
|
@ -83,7 +81,6 @@ integration/hello_world__systemjs_umd/NPM_PACKAGE_MANIFEST.json
|
|||
integration/i18n/NPM_PACKAGE_MANIFEST.json
|
||||
integration/injectable-def/NPM_PACKAGE_MANIFEST.json
|
||||
integration/ivy-i18n/NPM_PACKAGE_MANIFEST.json
|
||||
integration/language_service_plugin/NPM_PACKAGE_MANIFEST.json
|
||||
integration/ng_elements/NPM_PACKAGE_MANIFEST.json
|
||||
integration/ng_elements_schematics/NPM_PACKAGE_MANIFEST.json
|
||||
integration/ng_update/NPM_PACKAGE_MANIFEST.json
|
||||
|
|
|
@ -79,7 +79,6 @@ INTEGRATION_TESTS = {
|
|||
"injectable-def": {"tags": ["no-ivy-aot"]},
|
||||
"ivy-i18n": {"tags": ["ivy-only"]},
|
||||
"trusted-types": {"tags": ["ivy-only"]},
|
||||
"language_service_plugin": {},
|
||||
"ng_elements": {"tags": ["no-ivy-aot"]},
|
||||
"ng_elements_schematics": {"tags": ["ivy-only"]},
|
||||
"ng_update": {},
|
||||
|
|
|
@ -1,3 +0,0 @@
|
|||
*.js
|
||||
tsserver.log
|
||||
ti-*.log
|
|
@ -1,32 +0,0 @@
|
|||
# Angular Language Service Test
|
||||
|
||||
This directory is an integration test for `@angular/language-service` to ensure
|
||||
that the language service works correctly as a `tsserver` plugin.
|
||||
|
||||
To use the tests:
|
||||
|
||||
- Use `yarn install` to install all dependencies in this directory and in the Angular repo root
|
||||
directory.
|
||||
- Build an Angular distribution with `yarn build-dist`. This needs to be done after changes to
|
||||
Angular, but not after changes to integration tests. This is an expensive build.
|
||||
- In this directory, run the integration tests with `yarn test`.
|
||||
|
||||
## Update golden files
|
||||
|
||||
If the expected output needs to be updated, run `yarn golden my-golden.json`, replacing
|
||||
`my-golden.json` with the golden file to be updated. Do not qualify the file with a directory path.
|
||||
See [generate.ts](./generate.ts) for more information.
|
||||
|
||||
## Adding a new fixture
|
||||
|
||||
Currently there is no automated way to produce a new fixture. The way the
|
||||
current fixtures were created was to hack a version of tsserver.js to write the
|
||||
commands from `VSCode` to a file while performing the operation to be tested.
|
||||
I also hand modified the input to remove superfluous request.
|
||||
|
||||
Once a new fixture is created:
|
||||
|
||||
1) Add the fixture name to `goldens/`
|
||||
2) Run `yarn golden my-golden.json`, replacing `my-golden.json` with the new fixture name, to
|
||||
produce the expected output files.
|
||||
3) Hand validate that the expected output is reasonable.
|
|
@ -1,22 +0,0 @@
|
|||
/**
|
||||
* @fileOverview
|
||||
* This file serves as the entry point for generating goldens file for the
|
||||
* language service integration test. It expects each golden file that needs
|
||||
* to be generated to be passed in as command line arguments.
|
||||
* For example, to generate golden file for the 'configure' request, run
|
||||
* `yarn golden configure.json`.
|
||||
* To generate multiple golden files, run
|
||||
* `yarn golden configure.json completionInfo.json`.
|
||||
*
|
||||
* This is different from just running `yarn jasmine test.js` because this
|
||||
* allows passing in arbitrary arguments.
|
||||
*/
|
||||
|
||||
import Jasmine = require('jasmine');
|
||||
|
||||
function main() {
|
||||
const jasmine = new Jasmine({});
|
||||
jasmine.execute(['test.js']);
|
||||
}
|
||||
|
||||
main()
|
|
@ -1,8 +0,0 @@
|
|||
{
|
||||
"seq": 0,
|
||||
"type": "response",
|
||||
"command": "compilerOptionsForInferredProjects",
|
||||
"request_seq": 1,
|
||||
"success": true,
|
||||
"body": true
|
||||
}
|
|
@ -1,293 +0,0 @@
|
|||
{
|
||||
"seq": 0,
|
||||
"type": "response",
|
||||
"command": "completionInfo",
|
||||
"request_seq": 5,
|
||||
"success": true,
|
||||
"performanceData": {
|
||||
"updateGraphDurationMs": 34.82808400003705
|
||||
},
|
||||
"body": {
|
||||
"isGlobalCompletion": false,
|
||||
"isMemberCompletion": false,
|
||||
"isNewIdentifierLocation": false,
|
||||
"entries": [
|
||||
{
|
||||
"name": "anchor",
|
||||
"kind": "method",
|
||||
"sortText": "anchor",
|
||||
"insertText": "anchor()"
|
||||
},
|
||||
{
|
||||
"name": "big",
|
||||
"kind": "method",
|
||||
"sortText": "big",
|
||||
"insertText": "big()"
|
||||
},
|
||||
{
|
||||
"name": "blink",
|
||||
"kind": "method",
|
||||
"sortText": "blink",
|
||||
"insertText": "blink()"
|
||||
},
|
||||
{
|
||||
"name": "bold",
|
||||
"kind": "method",
|
||||
"sortText": "bold",
|
||||
"insertText": "bold()"
|
||||
},
|
||||
{
|
||||
"name": "charAt",
|
||||
"kind": "method",
|
||||
"sortText": "charAt",
|
||||
"insertText": "charAt()"
|
||||
},
|
||||
{
|
||||
"name": "charCodeAt",
|
||||
"kind": "method",
|
||||
"sortText": "charCodeAt",
|
||||
"insertText": "charCodeAt()"
|
||||
},
|
||||
{
|
||||
"name": "codePointAt",
|
||||
"kind": "method",
|
||||
"sortText": "codePointAt",
|
||||
"insertText": "codePointAt()"
|
||||
},
|
||||
{
|
||||
"name": "concat",
|
||||
"kind": "method",
|
||||
"sortText": "concat",
|
||||
"insertText": "concat()"
|
||||
},
|
||||
{
|
||||
"name": "endsWith",
|
||||
"kind": "method",
|
||||
"sortText": "endsWith",
|
||||
"insertText": "endsWith()"
|
||||
},
|
||||
{
|
||||
"name": "fixed",
|
||||
"kind": "method",
|
||||
"sortText": "fixed",
|
||||
"insertText": "fixed()"
|
||||
},
|
||||
{
|
||||
"name": "fontcolor",
|
||||
"kind": "method",
|
||||
"sortText": "fontcolor",
|
||||
"insertText": "fontcolor()"
|
||||
},
|
||||
{
|
||||
"name": "fontsize",
|
||||
"kind": "method",
|
||||
"sortText": "fontsize",
|
||||
"insertText": "fontsize()"
|
||||
},
|
||||
{
|
||||
"name": "includes",
|
||||
"kind": "method",
|
||||
"sortText": "includes",
|
||||
"insertText": "includes()"
|
||||
},
|
||||
{
|
||||
"name": "indexOf",
|
||||
"kind": "method",
|
||||
"sortText": "indexOf",
|
||||
"insertText": "indexOf()"
|
||||
},
|
||||
{
|
||||
"name": "italics",
|
||||
"kind": "method",
|
||||
"sortText": "italics",
|
||||
"insertText": "italics()"
|
||||
},
|
||||
{
|
||||
"name": "lastIndexOf",
|
||||
"kind": "method",
|
||||
"sortText": "lastIndexOf",
|
||||
"insertText": "lastIndexOf()"
|
||||
},
|
||||
{
|
||||
"name": "length",
|
||||
"kind": "property",
|
||||
"sortText": "length",
|
||||
"insertText": "length"
|
||||
},
|
||||
{
|
||||
"name": "link",
|
||||
"kind": "method",
|
||||
"sortText": "link",
|
||||
"insertText": "link()"
|
||||
},
|
||||
{
|
||||
"name": "localeCompare",
|
||||
"kind": "method",
|
||||
"sortText": "localeCompare",
|
||||
"insertText": "localeCompare()"
|
||||
},
|
||||
{
|
||||
"name": "match",
|
||||
"kind": "method",
|
||||
"sortText": "match",
|
||||
"insertText": "match()"
|
||||
},
|
||||
{
|
||||
"name": "normalize",
|
||||
"kind": "method",
|
||||
"sortText": "normalize",
|
||||
"insertText": "normalize()"
|
||||
},
|
||||
{
|
||||
"name": "padEnd",
|
||||
"kind": "method",
|
||||
"sortText": "padEnd",
|
||||
"insertText": "padEnd()"
|
||||
},
|
||||
{
|
||||
"name": "padStart",
|
||||
"kind": "method",
|
||||
"sortText": "padStart",
|
||||
"insertText": "padStart()"
|
||||
},
|
||||
{
|
||||
"name": "repeat",
|
||||
"kind": "method",
|
||||
"sortText": "repeat",
|
||||
"insertText": "repeat()"
|
||||
},
|
||||
{
|
||||
"name": "replace",
|
||||
"kind": "method",
|
||||
"sortText": "replace",
|
||||
"insertText": "replace()"
|
||||
},
|
||||
{
|
||||
"name": "search",
|
||||
"kind": "method",
|
||||
"sortText": "search",
|
||||
"insertText": "search()"
|
||||
},
|
||||
{
|
||||
"name": "slice",
|
||||
"kind": "method",
|
||||
"sortText": "slice",
|
||||
"insertText": "slice()"
|
||||
},
|
||||
{
|
||||
"name": "small",
|
||||
"kind": "method",
|
||||
"sortText": "small",
|
||||
"insertText": "small()"
|
||||
},
|
||||
{
|
||||
"name": "split",
|
||||
"kind": "method",
|
||||
"sortText": "split",
|
||||
"insertText": "split()"
|
||||
},
|
||||
{
|
||||
"name": "startsWith",
|
||||
"kind": "method",
|
||||
"sortText": "startsWith",
|
||||
"insertText": "startsWith()"
|
||||
},
|
||||
{
|
||||
"name": "strike",
|
||||
"kind": "method",
|
||||
"sortText": "strike",
|
||||
"insertText": "strike()"
|
||||
},
|
||||
{
|
||||
"name": "sub",
|
||||
"kind": "method",
|
||||
"sortText": "sub",
|
||||
"insertText": "sub()"
|
||||
},
|
||||
{
|
||||
"name": "substr",
|
||||
"kind": "method",
|
||||
"sortText": "substr",
|
||||
"insertText": "substr()"
|
||||
},
|
||||
{
|
||||
"name": "substring",
|
||||
"kind": "method",
|
||||
"sortText": "substring",
|
||||
"insertText": "substring()"
|
||||
},
|
||||
{
|
||||
"name": "sup",
|
||||
"kind": "method",
|
||||
"sortText": "sup",
|
||||
"insertText": "sup()"
|
||||
},
|
||||
{
|
||||
"name": "toLocaleLowerCase",
|
||||
"kind": "method",
|
||||
"sortText": "toLocaleLowerCase",
|
||||
"insertText": "toLocaleLowerCase()"
|
||||
},
|
||||
{
|
||||
"name": "toLocaleUpperCase",
|
||||
"kind": "method",
|
||||
"sortText": "toLocaleUpperCase",
|
||||
"insertText": "toLocaleUpperCase()"
|
||||
},
|
||||
{
|
||||
"name": "toLowerCase",
|
||||
"kind": "method",
|
||||
"sortText": "toLowerCase",
|
||||
"insertText": "toLowerCase()"
|
||||
},
|
||||
{
|
||||
"name": "toString",
|
||||
"kind": "method",
|
||||
"sortText": "toString",
|
||||
"insertText": "toString()"
|
||||
},
|
||||
{
|
||||
"name": "toUpperCase",
|
||||
"kind": "method",
|
||||
"sortText": "toUpperCase",
|
||||
"insertText": "toUpperCase()"
|
||||
},
|
||||
{
|
||||
"name": "trim",
|
||||
"kind": "method",
|
||||
"sortText": "trim",
|
||||
"insertText": "trim()"
|
||||
},
|
||||
{
|
||||
"name": "trimEnd",
|
||||
"kind": "method",
|
||||
"sortText": "trimEnd",
|
||||
"insertText": "trimEnd()"
|
||||
},
|
||||
{
|
||||
"name": "trimLeft",
|
||||
"kind": "method",
|
||||
"sortText": "trimLeft",
|
||||
"insertText": "trimLeft()"
|
||||
},
|
||||
{
|
||||
"name": "trimRight",
|
||||
"kind": "method",
|
||||
"sortText": "trimRight",
|
||||
"insertText": "trimRight()"
|
||||
},
|
||||
{
|
||||
"name": "trimStart",
|
||||
"kind": "method",
|
||||
"sortText": "trimStart",
|
||||
"insertText": "trimStart()"
|
||||
},
|
||||
{
|
||||
"name": "valueOf",
|
||||
"kind": "method",
|
||||
"sortText": "valueOf",
|
||||
"insertText": "valueOf()"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
|
@ -1,7 +0,0 @@
|
|||
{
|
||||
"seq": 0,
|
||||
"type": "response",
|
||||
"command": "configure",
|
||||
"request_seq": 0,
|
||||
"success": true
|
||||
}
|
|
@ -1,20 +0,0 @@
|
|||
{
|
||||
"seq": 0,
|
||||
"type": "response",
|
||||
"command": "definition",
|
||||
"request_seq": 2,
|
||||
"success": true,
|
||||
"body": [
|
||||
{
|
||||
"file": "${PWD}/project/app/app.component.ts",
|
||||
"start": {
|
||||
"line": 7,
|
||||
"offset": 30
|
||||
},
|
||||
"end": {
|
||||
"line": 7,
|
||||
"offset": 47
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
|
@ -1,32 +0,0 @@
|
|||
{
|
||||
"seq": 0,
|
||||
"type": "response",
|
||||
"command": "definitionAndBoundSpan",
|
||||
"request_seq": 2,
|
||||
"success": true,
|
||||
"body": {
|
||||
"definitions": [
|
||||
{
|
||||
"file": "${PWD}/project/app/app.component.ts",
|
||||
"start": {
|
||||
"line": 7,
|
||||
"offset": 30
|
||||
},
|
||||
"end": {
|
||||
"line": 7,
|
||||
"offset": 47
|
||||
}
|
||||
}
|
||||
],
|
||||
"textSpan": {
|
||||
"start": {
|
||||
"line": 5,
|
||||
"offset": 26
|
||||
},
|
||||
"end": {
|
||||
"line": 5,
|
||||
"offset": 30
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,22 +0,0 @@
|
|||
{
|
||||
"seq": 0,
|
||||
"type": "response",
|
||||
"command": "quickinfo",
|
||||
"request_seq": 2,
|
||||
"success": true,
|
||||
"body": {
|
||||
"kind": "property",
|
||||
"kindModifiers": "",
|
||||
"start": {
|
||||
"line": 5,
|
||||
"offset": 26
|
||||
},
|
||||
"end": {
|
||||
"line": 5,
|
||||
"offset": 30
|
||||
},
|
||||
"displayString": "(property) AppComponent.name: string",
|
||||
"documentation": "",
|
||||
"tags": []
|
||||
}
|
||||
}
|
|
@ -1,32 +0,0 @@
|
|||
{
|
||||
"seq": 0,
|
||||
"type": "response",
|
||||
"command": "definitionAndBoundSpan",
|
||||
"request_seq": 3,
|
||||
"success": true,
|
||||
"body": {
|
||||
"definitions": [
|
||||
{
|
||||
"file": "${PWD}/project/app/style.css",
|
||||
"start": {
|
||||
"line": 1,
|
||||
"offset": 1
|
||||
},
|
||||
"end": {
|
||||
"line": 1,
|
||||
"offset": 1
|
||||
}
|
||||
}
|
||||
],
|
||||
"textSpan": {
|
||||
"start": {
|
||||
"line": 6,
|
||||
"offset": 16
|
||||
},
|
||||
"end": {
|
||||
"line": 6,
|
||||
"offset": 27
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,32 +0,0 @@
|
|||
{
|
||||
"seq": 0,
|
||||
"type": "response",
|
||||
"command": "definitionAndBoundSpan",
|
||||
"request_seq": 2,
|
||||
"success": true,
|
||||
"body": {
|
||||
"definitions": [
|
||||
{
|
||||
"file": "${PWD}/project/app/widget.component.html",
|
||||
"start": {
|
||||
"line": 1,
|
||||
"offset": 1
|
||||
},
|
||||
"end": {
|
||||
"line": 1,
|
||||
"offset": 1
|
||||
}
|
||||
}
|
||||
],
|
||||
"textSpan": {
|
||||
"start": {
|
||||
"line": 5,
|
||||
"offset": 17
|
||||
},
|
||||
"end": {
|
||||
"line": 5,
|
||||
"offset": 40
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,35 +0,0 @@
|
|||
import { writeFileSync, readFileSync } from 'fs';
|
||||
|
||||
const goldens: string[] = process.argv.slice(2);
|
||||
|
||||
export const goldenMatcher: jasmine.CustomMatcherFactories = {
|
||||
toMatchGolden(util: jasmine.MatchersUtil): jasmine.CustomMatcher {
|
||||
return {
|
||||
compare(actual: {body?: {}}, golden: string): jasmine.CustomMatcherResult {
|
||||
if (goldens.includes(golden)) {
|
||||
console.error(`Writing golden file ${golden}`);
|
||||
writeFileSync(`./goldens/${golden}`, JSON.stringify(actual, null, 2));
|
||||
return { pass : true };
|
||||
}
|
||||
const content = readFileSync(`./goldens/${golden}`, 'utf-8');
|
||||
const expected = JSON.parse(content.replace("${PWD}", process.env.PWD!));
|
||||
const hasBody = Object.hasOwnProperty.call(expected, 'body');
|
||||
const pass = hasBody ? util.equals(actual.body, expected.body) : util.equals(actual, expected);
|
||||
return {
|
||||
pass,
|
||||
message: `Expected ${JSON.stringify(actual, null, 2)} to match golden ` +
|
||||
`${JSON.stringify(expected, null, 2)}.\n` +
|
||||
`To generate new golden file, run "yarn golden ${golden}".`,
|
||||
};
|
||||
}
|
||||
};
|
||||
},
|
||||
};
|
||||
|
||||
declare global {
|
||||
namespace jasmine {
|
||||
interface Matchers<T> {
|
||||
toMatchGolden(golden: string): void
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,21 +0,0 @@
|
|||
{
|
||||
"name": "language_service_plugin",
|
||||
"version": "0.0.0",
|
||||
"license": "MIT",
|
||||
"description": "Angular Language Service plugin integration test",
|
||||
"dependencies": {
|
||||
"@angular/core": "file:../../dist/packages-dist/core",
|
||||
"@angular/language-service": "file:../../dist/packages-dist/language-service",
|
||||
"@types/jasmine": "file:../../node_modules/@types/jasmine",
|
||||
"@types/node": "file:../../node_modules/@types/node",
|
||||
"jasmine": "file:../../node_modules/jasmine",
|
||||
"typescript": "file:../../node_modules/typescript"
|
||||
},
|
||||
"scripts": {
|
||||
"build": "tsc -p tsconfig.json",
|
||||
"build-dist": "node ../../scripts/build/build-packages-dist.js && yarn install --check-files",
|
||||
"cleanup": "rm -rf ti-*.log tsserver.log",
|
||||
"golden": "yarn build && node generate.js",
|
||||
"test": "yarn cleanup && yarn build && jasmine test.js"
|
||||
}
|
||||
}
|
|
@ -1,7 +0,0 @@
|
|||
import { Component } from '@angular/core';
|
||||
|
||||
@Component({
|
||||
selector: 'my-app',
|
||||
template: `<h1>Hello {{name}}</h1><my-widget></my-widget>`,
|
||||
})
|
||||
export class AppComponent { name = 'Angular'; }
|
|
@ -1,12 +0,0 @@
|
|||
import { NgModule } from '@angular/core';
|
||||
import { BrowserModule } from '@angular/platform-browser';
|
||||
|
||||
import { AppComponent } from './app.component';
|
||||
import { WidgetComponent } from './widget.component';
|
||||
|
||||
@NgModule({
|
||||
imports: [ BrowserModule ],
|
||||
declarations: [ AppComponent, WidgetComponent ],
|
||||
bootstrap: [ AppComponent ]
|
||||
})
|
||||
export class AppModule { }
|
|
@ -1,5 +0,0 @@
|
|||
import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';
|
||||
|
||||
import { AppModule } from './app.module';
|
||||
|
||||
platformBrowserDynamic().bootstrapModule(AppModule);
|
|
@ -1,4 +0,0 @@
|
|||
body,
|
||||
html {
|
||||
width: 100%;
|
||||
}
|
|
@ -1 +0,0 @@
|
|||
<h1>This is a {{name}} widget!</h1>
|
|
@ -1,8 +0,0 @@
|
|||
import { Component } from '@angular/core';
|
||||
|
||||
@Component({
|
||||
selector: 'my-widget',
|
||||
templateUrl: './widget.component.html',
|
||||
styleUrls: ['./style.css'],
|
||||
})
|
||||
export class WidgetComponent { name = 'Angular'; }
|
|
@ -1,16 +0,0 @@
|
|||
{
|
||||
"compilerOptions": {
|
||||
"target": "es5",
|
||||
"module": "commonjs",
|
||||
"moduleResolution": "node",
|
||||
"sourceMap": true,
|
||||
"emitDecoratorMetadata": true,
|
||||
"experimentalDecorators": true,
|
||||
"lib": [ "es2015", "dom" ],
|
||||
"noImplicitAny": true,
|
||||
"suppressImplicitAnyIndexErrors": true,
|
||||
"plugins": [
|
||||
{"name": "@angular/language-service"}
|
||||
]
|
||||
}
|
||||
}
|
|
@ -1,203 +0,0 @@
|
|||
import {ChildProcess, fork} from 'child_process';
|
||||
import {join} from 'path';
|
||||
import {goldenMatcher} from './matcher';
|
||||
import {Client} from './tsclient';
|
||||
|
||||
describe('Angular Language Service', () => {
|
||||
jasmine.DEFAULT_TIMEOUT_INTERVAL = 10000; /* 10 seconds */
|
||||
const PWD = process.env.PWD!;
|
||||
const SERVER_PATH = './node_modules/typescript/lib/tsserver.js';
|
||||
let server: ChildProcess;
|
||||
let client: Client;
|
||||
|
||||
beforeEach(() => {
|
||||
jasmine.addMatchers(goldenMatcher);
|
||||
server = fork(
|
||||
SERVER_PATH,
|
||||
[
|
||||
'--logVerbosity',
|
||||
'verbose',
|
||||
'--logFile',
|
||||
join(PWD, 'tsserver.log'),
|
||||
],
|
||||
{
|
||||
stdio: ['pipe', 'pipe', 'inherit', 'ipc'],
|
||||
});
|
||||
client = new Client(server);
|
||||
client.listen();
|
||||
});
|
||||
|
||||
afterEach(async () => {
|
||||
client.sendRequest('exit', {});
|
||||
|
||||
// Give server process some time to flush all messages
|
||||
await new Promise((resolve) => setTimeout(resolve, 1000));
|
||||
});
|
||||
|
||||
it('should be launched as tsserver plugin', async () => {
|
||||
let response = await client.sendRequest('configure', {
|
||||
hostInfo: 'vscode',
|
||||
});
|
||||
expect(response).toMatchGolden('configure.json');
|
||||
response = await client.sendRequest('compilerOptionsForInferredProjects', {
|
||||
'options': {
|
||||
module: 'CommonJS',
|
||||
target: 'ES6',
|
||||
allowSyntheticDefaultImports: true,
|
||||
allowNonTsExtensions: true,
|
||||
allowJs: true,
|
||||
jsx: 'Preserve'
|
||||
}
|
||||
});
|
||||
expect(response).toMatchGolden('compilerOptionsForInferredProjects.json');
|
||||
// Server does not send response to open request
|
||||
// https://github.com/Microsoft/TypeScript/blob/master/lib/protocol.d.ts#L1055
|
||||
client.sendRequest('open', {
|
||||
file: `${PWD}/project/app/app.module.ts`,
|
||||
});
|
||||
// Server does not send response to geterr request
|
||||
// https://github.com/Microsoft/TypeScript/blob/master/lib/protocol.d.ts#L1770
|
||||
client.sendRequest('geterr', {delay: 0, files: [`${PWD}/project/app/app.module.ts`]});
|
||||
});
|
||||
|
||||
it('should perform completions', async () => {
|
||||
await client.sendRequest('configure', {
|
||||
hostInfo: 'vscode',
|
||||
});
|
||||
await client.sendRequest('compilerOptionsForInferredProjects', {
|
||||
'options': {
|
||||
module: 'CommonJS',
|
||||
target: 'ES6',
|
||||
allowSyntheticDefaultImports: true,
|
||||
allowNonTsExtensions: true,
|
||||
allowJs: true,
|
||||
jsx: 'Preserve'
|
||||
}
|
||||
});
|
||||
|
||||
client.sendRequest('open', {
|
||||
file: `${PWD}/project/app/app.component.ts`,
|
||||
});
|
||||
|
||||
client.sendRequest('geterr', {delay: 0, files: [`${PWD}/project/app/app.component.ts`]});
|
||||
|
||||
client.sendRequest('change', {
|
||||
file: `${PWD}/project/app/app.component.ts`,
|
||||
line: 5,
|
||||
offset: 30,
|
||||
endLine: 5,
|
||||
endOffset: 30,
|
||||
insertString: '.',
|
||||
});
|
||||
|
||||
const response = await client.sendRequest('completionInfo', {
|
||||
file: `${PWD}/project/app/app.component.ts`,
|
||||
line: 5,
|
||||
offset: 31,
|
||||
});
|
||||
expect(response).toMatchGolden('completionInfo.json');
|
||||
});
|
||||
|
||||
it('should perform quickinfo', async () => {
|
||||
client.sendRequest('open', {
|
||||
file: `${PWD}/project/app/app.component.ts`,
|
||||
});
|
||||
|
||||
const resp1 = await client.sendRequest('reload', {
|
||||
file: `${PWD}/project/app/app.component.ts`,
|
||||
tmpFile: `${PWD}/project/app/app.component.ts`,
|
||||
}) as any;
|
||||
expect(resp1.command).toBe('reload');
|
||||
expect(resp1.success).toBe(true);
|
||||
|
||||
const resp2 = await client.sendRequest('quickinfo', {
|
||||
file: `${PWD}/project/app/app.component.ts`,
|
||||
line: 5,
|
||||
offset: 28,
|
||||
});
|
||||
expect(resp2).toMatchGolden('quickinfo.json');
|
||||
});
|
||||
|
||||
it('should perform definition', async () => {
|
||||
client.sendRequest('open', {
|
||||
file: `${PWD}/project/app/app.component.ts`,
|
||||
});
|
||||
|
||||
const resp1 = await client.sendRequest('reload', {
|
||||
file: `${PWD}/project/app/app.component.ts`,
|
||||
tmpFile: `${PWD}/project/app/app.component.ts`,
|
||||
}) as any;
|
||||
expect(resp1.command).toBe('reload');
|
||||
expect(resp1.success).toBe(true);
|
||||
|
||||
const resp2 = await client.sendRequest('definition', {
|
||||
file: `${PWD}/project/app/app.component.ts`,
|
||||
line: 5,
|
||||
offset: 28,
|
||||
});
|
||||
expect(resp2).toMatchGolden('definition.json');
|
||||
});
|
||||
|
||||
it('should perform definitionAndBoundSpan', async () => {
|
||||
client.sendRequest('open', {
|
||||
file: `${PWD}/project/app/app.component.ts`,
|
||||
});
|
||||
|
||||
const resp1 = await client.sendRequest('reload', {
|
||||
file: `${PWD}/project/app/app.component.ts`,
|
||||
tmpFile: `${PWD}/project/app/app.component.ts`,
|
||||
}) as any;
|
||||
expect(resp1.command).toBe('reload');
|
||||
expect(resp1.success).toBe(true);
|
||||
|
||||
const resp2 = await client.sendRequest('definitionAndBoundSpan', {
|
||||
file: `${PWD}/project/app/app.component.ts`,
|
||||
line: 5,
|
||||
offset: 28,
|
||||
});
|
||||
expect(resp2).toMatchGolden('definitionAndBoundSpan.json');
|
||||
});
|
||||
|
||||
it('should perform definitionAndBoundSpan for template URLs', async () => {
|
||||
client.sendRequest('open', {
|
||||
file: `${PWD}/project/app/widget.component.ts`,
|
||||
});
|
||||
|
||||
const resp1 = await client.sendRequest('reload', {
|
||||
file: `${PWD}/project/app/widget.component.ts`,
|
||||
tmpFile: `${PWD}/project/app/widget.component.ts`,
|
||||
}) as any;
|
||||
expect(resp1.command).toBe('reload');
|
||||
expect(resp1.success).toBe(true);
|
||||
|
||||
const resp2 = await client.sendRequest('definitionAndBoundSpan', {
|
||||
file: `${PWD}/project/app/widget.component.ts`,
|
||||
line: 5,
|
||||
offset: 19,
|
||||
});
|
||||
expect(resp2).toMatchGolden('templateUrlDefinition.json');
|
||||
});
|
||||
|
||||
it('should perform definitionAndBoundSpan for style URLs', async () => {
|
||||
client.sendRequest('open', {
|
||||
file: `${PWD}/project/app/widget.component.ts`,
|
||||
});
|
||||
client.sendRequest('open', {
|
||||
file: `${PWD}/project/app/style.css`,
|
||||
});
|
||||
|
||||
const resp1 = await client.sendRequest('reload', {
|
||||
file: `${PWD}/project/app/widget.component.ts`,
|
||||
tmpFile: `${PWD}/project/app/widget.component.ts`,
|
||||
}) as any;
|
||||
expect(resp1.command).toBe('reload');
|
||||
expect(resp1.success).toBe(true);
|
||||
|
||||
const resp2 = await client.sendRequest('definitionAndBoundSpan', {
|
||||
file: `${PWD}/project/app/widget.component.ts`,
|
||||
line: 6,
|
||||
offset: 18,
|
||||
});
|
||||
expect(resp2).toMatchGolden('styleUrlsDefinition.json');
|
||||
});
|
||||
});
|
|
@ -1,75 +0,0 @@
|
|||
import { ChildProcess } from "child_process";
|
||||
import { EventEmitter } from "events";
|
||||
|
||||
/**
|
||||
* Provides a client for tsserver. Tsserver does not use standard JSON-RPC
|
||||
* protocol thus the need for this custom client.
|
||||
*/
|
||||
export class Client {
|
||||
private data: Buffer|undefined;
|
||||
private id = 0;
|
||||
private responseEmitter = new EventEmitter();
|
||||
|
||||
constructor(private readonly server: ChildProcess) {}
|
||||
|
||||
listen() {
|
||||
this.server.stdout!.on('data', (data: Buffer) => {
|
||||
this.data = this.data ? Buffer.concat([this.data, data]) : data;
|
||||
// tsserver could batch multiple responses together so we have to go
|
||||
// through the entire buffer to keep looking for messages.
|
||||
const CONTENT_LENGTH = 'Content-Length: '
|
||||
do {
|
||||
const index = this.data.indexOf(CONTENT_LENGTH);
|
||||
if (index < 0) {
|
||||
return;
|
||||
}
|
||||
let start = index + CONTENT_LENGTH.length;
|
||||
let end = this.data.indexOf('\r\n', start);
|
||||
if (end < start) {
|
||||
return;
|
||||
}
|
||||
const contentLengthStr = this.data.slice(start, end).toString();
|
||||
const contentLength = Number(contentLengthStr);
|
||||
if (isNaN(contentLength) || contentLength < 0) {
|
||||
return;
|
||||
}
|
||||
start = end + 4;
|
||||
end = start + contentLength;
|
||||
if (end > this.data.length) {
|
||||
return;
|
||||
}
|
||||
const content = this.data.slice(start, end).toString();
|
||||
this.data = this.data.slice(end);
|
||||
try {
|
||||
const payload = JSON.parse(content);
|
||||
if (payload.type === "response") {
|
||||
const seq = `${payload.request_seq}`;
|
||||
this.responseEmitter.emit(seq, payload);
|
||||
}
|
||||
}
|
||||
catch (error) {
|
||||
this.responseEmitter.emit('error', error);
|
||||
}
|
||||
} while (this.data.length > 0)
|
||||
});
|
||||
}
|
||||
|
||||
async send(type: string, command: string, params: {}) {
|
||||
const seq = this.id++;
|
||||
const request = {
|
||||
seq,
|
||||
type,
|
||||
command,
|
||||
arguments: params
|
||||
};
|
||||
this.server.stdin!.write(JSON.stringify(request) + '\r\n');
|
||||
return new Promise((resolve, reject) => {
|
||||
this.responseEmitter.once(`${seq}`, resolve);
|
||||
this.responseEmitter.once('error', reject);
|
||||
});
|
||||
}
|
||||
|
||||
async sendRequest(command: string, params: {}) {
|
||||
return this.send('request', command, params);
|
||||
}
|
||||
}
|
|
@ -1,60 +0,0 @@
|
|||
{
|
||||
"compilerOptions": {
|
||||
/* Basic Options */
|
||||
"target": "es2016", /* Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017','ES2018' or 'ESNEXT'. */
|
||||
"module": "commonjs", /* Specify module code generation: 'none', 'commonjs', 'amd', 'system', 'umd', 'es2015', or 'ESNext'. */
|
||||
// "lib": [], /* Specify library files to be included in the compilation. */
|
||||
// "allowJs": true, /* Allow javascript files to be compiled. */
|
||||
// "checkJs": true, /* Report errors in .js files. */
|
||||
// "jsx": "preserve", /* Specify JSX code generation: 'preserve', 'react-native', or 'react'. */
|
||||
// "declaration": true, /* Generates corresponding '.d.ts' file. */
|
||||
// "declarationMap": true, /* Generates a sourcemap for each corresponding '.d.ts' file. */
|
||||
// "sourceMap": true, /* Generates corresponding '.map' file. */
|
||||
// "outFile": "./", /* Concatenate and emit output to single file. */
|
||||
// "outDir": "./", /* Redirect output structure to the directory. */
|
||||
// "rootDir": "./", /* Specify the root directory of input files. Use to control the output directory structure with --outDir. */
|
||||
// "composite": true, /* Enable project compilation */
|
||||
// "removeComments": true, /* Do not emit comments to output. */
|
||||
// "noEmit": true, /* Do not emit outputs. */
|
||||
// "importHelpers": true, /* Import emit helpers from 'tslib'. */
|
||||
// "downlevelIteration": true, /* Provide full support for iterables in 'for-of', spread, and destructuring when targeting 'ES5' or 'ES3'. */
|
||||
// "isolatedModules": true, /* Transpile each file as a separate module (similar to 'ts.transpileModule'). */
|
||||
|
||||
/* Strict Type-Checking Options */
|
||||
"strict": true, /* Enable all strict type-checking options. */
|
||||
// "noImplicitAny": true, /* Raise error on expressions and declarations with an implied 'any' type. */
|
||||
// "strictNullChecks": true, /* Enable strict null checks. */
|
||||
// "strictFunctionTypes": true, /* Enable strict checking of function types. */
|
||||
// "strictPropertyInitialization": true, /* Enable strict checking of property initialization in classes. */
|
||||
// "noImplicitThis": true, /* Raise error on 'this' expressions with an implied 'any' type. */
|
||||
// "alwaysStrict": true, /* Parse in strict mode and emit "use strict" for each source file. */
|
||||
|
||||
/* Additional Checks */
|
||||
// "noUnusedLocals": true, /* Report errors on unused locals. */
|
||||
// "noUnusedParameters": true, /* Report errors on unused parameters. */
|
||||
// "noImplicitReturns": true, /* Report error when not all code paths in function return a value. */
|
||||
// "noFallthroughCasesInSwitch": true, /* Report errors for fallthrough cases in switch statement. */
|
||||
|
||||
/* Module Resolution Options */
|
||||
// "moduleResolution": "node", /* Specify module resolution strategy: 'node' (Node.js) or 'classic' (TypeScript pre-1.6). */
|
||||
// "baseUrl": "./", /* Base directory to resolve non-absolute module names. */
|
||||
// "paths": {}, /* A series of entries which re-map imports to lookup locations relative to the 'baseUrl'. */
|
||||
// "rootDirs": [], /* List of root folders whose combined content represents the structure of the project at runtime. */
|
||||
"typeRoots": ["node_modules/@types"], /* List of folders to include type definitions from. */
|
||||
// "types": [], /* Type declaration files to be included in compilation. */
|
||||
// "allowSyntheticDefaultImports": true, /* Allow default imports from modules with no default export. This does not affect code emit, just typechecking. */
|
||||
"esModuleInterop": true /* Enables emit interoperability between CommonJS and ES Modules via creation of namespace objects for all imports. Implies 'allowSyntheticDefaultImports'. */
|
||||
// "preserveSymlinks": true, /* Do not resolve the real path of symlinks. */
|
||||
|
||||
/* Source Map Options */
|
||||
// "sourceRoot": "", /* Specify the location where debugger should locate TypeScript files instead of source locations. */
|
||||
// "mapRoot": "", /* Specify the location where debugger should locate map files instead of generated locations. */
|
||||
// "inlineSourceMap": true, /* Emit a single file with source maps instead of having a separate file. */
|
||||
// "inlineSources": true, /* Emit the source alongside the sourcemaps within a single file; requires '--inlineSourceMap' or '--sourceMap' to be set. */
|
||||
|
||||
/* Experimental Options */
|
||||
// "experimentalDecorators": true, /* Enables experimental support for ES7 decorators. */
|
||||
// "emitDecoratorMetadata": true, /* Enables experimental support for emitting type metadata for decorators. */
|
||||
},
|
||||
"include": ["*.ts"]
|
||||
}
|
|
@ -1,98 +0,0 @@
|
|||
# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY.
|
||||
# yarn lockfile v1
|
||||
|
||||
|
||||
"@angular/core@file:../../dist/packages-dist/core":
|
||||
version "9.0.0-rc.1"
|
||||
|
||||
"@angular/language-service@file:../../dist/packages-dist/language-service":
|
||||
version "9.0.0-rc.1"
|
||||
|
||||
"@types/node@file:../../node_modules/@types/node":
|
||||
version "12.11.1"
|
||||
|
||||
balanced-match@^1.0.0:
|
||||
version "1.0.0"
|
||||
resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.0.tgz#89b4d199ab2bee49de164ea02b89ce462d71b767"
|
||||
integrity sha1-ibTRmasr7kneFk6gK4nORi1xt2c=
|
||||
|
||||
brace-expansion@^1.1.7:
|
||||
version "1.1.11"
|
||||
resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.11.tgz#3c7fcbf529d87226f3d2f52b966ff5271eb441dd"
|
||||
integrity sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==
|
||||
dependencies:
|
||||
balanced-match "^1.0.0"
|
||||
concat-map "0.0.1"
|
||||
|
||||
concat-map@0.0.1:
|
||||
version "0.0.1"
|
||||
resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b"
|
||||
integrity sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=
|
||||
|
||||
fs.realpath@^1.0.0:
|
||||
version "1.0.0"
|
||||
resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f"
|
||||
integrity sha1-FQStJSMVjKpA20onh8sBQRmU6k8=
|
||||
|
||||
glob@^7.0.6:
|
||||
version "7.1.3"
|
||||
resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.3.tgz#3960832d3f1574108342dafd3a67b332c0969df1"
|
||||
integrity sha512-vcfuiIxogLV4DlGBHIUOwI0IbrJ8HWPc4MU7HzviGeNho/UJDfi6B5p3sHeWIQ0KGIU0Jpxi5ZHxemQfLkkAwQ==
|
||||
dependencies:
|
||||
fs.realpath "^1.0.0"
|
||||
inflight "^1.0.4"
|
||||
inherits "2"
|
||||
minimatch "^3.0.4"
|
||||
once "^1.3.0"
|
||||
path-is-absolute "^1.0.0"
|
||||
|
||||
inflight@^1.0.4:
|
||||
version "1.0.6"
|
||||
resolved "https://registry.yarnpkg.com/inflight/-/inflight-1.0.6.tgz#49bd6331d7d02d0c09bc910a1075ba8165b56df9"
|
||||
integrity sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=
|
||||
dependencies:
|
||||
once "^1.3.0"
|
||||
wrappy "1"
|
||||
|
||||
inherits@2:
|
||||
version "2.0.3"
|
||||
resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.3.tgz#633c2c83e3da42a502f52466022480f4208261de"
|
||||
integrity sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=
|
||||
|
||||
jasmine-core@~3.3.0:
|
||||
version "3.3.0"
|
||||
resolved "https://registry.yarnpkg.com/jasmine-core/-/jasmine-core-3.3.0.tgz#dea1cdc634bc93c7e0d4ad27185df30fa971b10e"
|
||||
integrity sha512-3/xSmG/d35hf80BEN66Y6g9Ca5l/Isdeg/j6zvbTYlTzeKinzmaTM4p9am5kYqOmE05D7s1t8FGjzdSnbUbceA==
|
||||
|
||||
"jasmine@file:../../node_modules/jasmine":
|
||||
version "3.3.1"
|
||||
dependencies:
|
||||
glob "^7.0.6"
|
||||
jasmine-core "~3.3.0"
|
||||
|
||||
minimatch@^3.0.4:
|
||||
version "3.0.4"
|
||||
resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.0.4.tgz#5166e286457f03306064be5497e8dbb0c3d32083"
|
||||
integrity sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==
|
||||
dependencies:
|
||||
brace-expansion "^1.1.7"
|
||||
|
||||
once@^1.3.0:
|
||||
version "1.4.0"
|
||||
resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1"
|
||||
integrity sha1-WDsap3WWHUsROsF9nFC6753Xa9E=
|
||||
dependencies:
|
||||
wrappy "1"
|
||||
|
||||
path-is-absolute@^1.0.0:
|
||||
version "1.0.1"
|
||||
resolved "https://registry.yarnpkg.com/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f"
|
||||
integrity sha1-F0uSaHNVNP+8es5r9TpanhtcX18=
|
||||
|
||||
"typescript@file:../../node_modules/typescript":
|
||||
version "3.6.4"
|
||||
|
||||
wrappy@1:
|
||||
version "1.0.2"
|
||||
resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f"
|
||||
integrity sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=
|
Loading…
Reference in New Issue