Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Allow using workspace version of TS. Fix #682 #1158

Merged
merged 14 commits into from
Mar 20, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 6 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,11 @@ npm-debug.log
node_modules
.vscode-test

test/**/data-dir/**
!test/**/data-dir/User
test/**/data-dir/User/**
!test/**/data-dir/User/settings.json

dist
server/dist
docs/.vuepress/dist
Expand All @@ -12,4 +17,4 @@ docs/.vuepress/dist
*.vsix

.nyc_output
coverage.lcov
coverage.lcov
6 changes: 2 additions & 4 deletions .vscode/settings.json
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
{
"tslint.enable": true,
"files.exclude": {
"server/dist": true,
"docs/_book": true,
"dist": true
"docs/_book": true
}
}
}
12 changes: 12 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,20 @@

### 0.17.0

- Allow using workspace TS version. See below for details. #682.
- Switched PostCSS grammar to base on [hudochenkov/Syntax-highlighting-for-PostCSS](https://github.com/hudochenkov/Syntax-highlighting-for-PostCSS). #1115.

#### Using Workspace TypeScript version

Vetur depends on TypeScript's Language Server for its JavaScript/TypeScript capabilities. Previously Vetur bundles TS 2.8.4,
but now Vetur can run on any TypeScript > 2.8 from workspace `node_modules/typescript`. Use `vetur.useWorkspaceDependencies`
to enable this behavior.

Note that `vetur.useWorkspaceDependencies` can only be configured in user settings (no workspace setting) and defaults to `false`
because Vetur should not run 3rd party code without user's explicit approval.

Currently this setting does not affect `prettier` and other formatters, where workspace dependencies is preferred, but this will change in the future.

### 0.16.2 | 2019-02-20 | [VSIX](https://marketplace.visualstudio.com/_apis/public/gallery/publishers/octref/vsextensions/vetur/0.16.2/vspackage)

- Prettier as an option for `vetur.format.defaultFormatter.html`. #950.
Expand Down
11 changes: 8 additions & 3 deletions client/vueMain.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,9 +23,14 @@ export function activate(context: vscode.ExtensionContext) {
const client = initializeLanguageClient(serverModule);
context.subscriptions.push(client.start());

client.onReady().then(() => {
registerCustomClientNotificationHandlers(client);
});
client
.onReady()
.then(() => {
registerCustomClientNotificationHandlers(client);
})
.catch(e => {
console.log('Client initialization failed');
});
}

function registerCustomClientNotificationHandlers(client: LanguageClient) {
Expand Down
6 changes: 6 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -158,6 +158,12 @@
"configuration": {
"title": "Vetur",
"properties": {
"vetur.useWorkspaceDependencies": {
"type": "boolean",
"default": false,
"description": "Use dependencies from workspace. Currently only for TypeScript.",
"scope": "application"
},
"vetur.completion.autoImport": {
"type": "boolean",
"default": true,
Expand Down
1 change: 1 addition & 0 deletions server/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@
"@types/mocha": "^5.2.5",
"@types/node": "^10.12.10",
"@types/prettier": "^1.16.1",
"@types/read-pkg-up": "^3.0.1",
"@types/resolve": "0.0.8",
"codecov": "^3.0.4",
"glob": "^7.1.2",
Expand Down
186 changes: 99 additions & 87 deletions server/src/modes/languageModes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,11 +28,16 @@ import { getVueHTMLMode } from './template';
import { getStylusMode } from './style/stylus';
import { DocumentContext } from '../types';
import { VueInfoService } from '../services/vueInfoService';
import { DependencyService } from '../services/dependencyService';

export interface VLSServices {
infoService?: VueInfoService;
dependencyService?: DependencyService;
}

export interface LanguageMode {
getId(): string;
configure?(options: any): void;
configureService?(infoService: VueInfoService): void;
updateFileInfo?(doc: TextDocument): void;

doValidation?(document: TextDocument): Diagnostic[];
Expand All @@ -54,98 +59,105 @@ export interface LanguageMode {
dispose(): void;
}

export interface LanguageModes {
getModeAtPosition(document: TextDocument, position: Position): LanguageMode | null;
getModesInRange(document: TextDocument, range: Range): LanguageModeRange[];
getAllModes(): LanguageMode[];
getAllModesInDocument(document: TextDocument): LanguageMode[];
getMode(languageId: string): LanguageMode;
onDocumentRemoved(document: TextDocument): void;
dispose(): void;
}

export interface LanguageModeRange extends Range {
mode: LanguageMode;
attributeValue?: boolean;
}

export function getLanguageModes(workspacePath: string | null | undefined): LanguageModes {
const documentRegions = getLanguageModelCache<VueDocumentRegions>(10, 60, document => getDocumentRegions(document));

let modelCaches: LanguageModelCache<any>[] = [];
modelCaches.push(documentRegions);

const jsMode = getJavascriptMode(documentRegions, workspacePath);
let modes: { [k: string]: LanguageMode } = {
vue: getVueMode(),
'vue-html': getVueHTMLMode(documentRegions, workspacePath),
css: getCSSMode(documentRegions),
postcss: getPostCSSMode(documentRegions),
scss: getSCSSMode(documentRegions),
less: getLESSMode(documentRegions),
stylus: getStylusMode(documentRegions),
javascript: jsMode,
tsx: jsMode,
typescript: jsMode
};

return {
getModeAtPosition(document: TextDocument, position: Position): LanguageMode | null {
const languageId = documentRegions.get(document).getLanguageAtPosition(position);
if (languageId) {
return modes[languageId];
}
return null;
},
getModesInRange(document: TextDocument, range: Range): LanguageModeRange[] {
return documentRegions
.get(document)
.getLanguageRanges(range)
.map(r => {
return {
start: r.start,
end: r.end,
mode: modes[r.languageId],
attributeValue: r.attributeValue
};
});
},
getAllModesInDocument(document: TextDocument): LanguageMode[] {
const result = [];
for (const languageId of documentRegions.get(document).getLanguagesInDocument()) {
const mode = modes[languageId];
if (mode) {
result.push(mode);
}
}
return result;
},
getAllModes(): LanguageMode[] {
const result = [];
for (const languageId in modes) {
const mode = modes[languageId];
if (mode) {
result.push(mode);
}
}
return result;
},
getMode(languageId: string): LanguageMode {
return modes[languageId];
},
onDocumentRemoved(document: TextDocument) {
modelCaches.forEach(mc => mc.onDocumentRemoved(document));
for (const mode in modes) {
modes[mode].onDocumentRemoved(document);
export class LanguageModes {
private modes: { [k: string]: LanguageMode } = {};
private documentRegions: LanguageModelCache<VueDocumentRegions>;
private modelCaches: LanguageModelCache<any>[];

constructor() {
this.documentRegions = getLanguageModelCache<VueDocumentRegions>(10, 60, document => getDocumentRegions(document));

this.modelCaches = [];
this.modelCaches.push(this.documentRegions);
}

async init(workspacePath: string, services: VLSServices) {
const vueHtmlMode = getVueHTMLMode(this.documentRegions, workspacePath, services.infoService);
const jsMode = await getJavascriptMode(
this.documentRegions,
workspacePath,
services.infoService,
services.dependencyService
);

this.modes['vue'] = getVueMode();
this.modes['vue-html'] = vueHtmlMode;
this.modes['css'] = getCSSMode(this.documentRegions);
this.modes['postcss'] = getPostCSSMode(this.documentRegions);
this.modes['scss'] = getSCSSMode(this.documentRegions);
this.modes['less'] = getLESSMode(this.documentRegions);
this.modes['stylus'] = getStylusMode(this.documentRegions);
this.modes['javascript'] = jsMode;
this.modes['tsx'] = jsMode;
this.modes['typescript'] = jsMode;
}

getModeAtPosition(document: TextDocument, position: Position): LanguageMode | null {
const languageId = this.documentRegions.get(document).getLanguageAtPosition(position);
if (languageId) {
return this.modes[languageId];
}
return null;
}

getModesInRange(document: TextDocument, range: Range): LanguageModeRange[] {
return this.documentRegions
.get(document)
.getLanguageRanges(range)
.map(r => {
return {
start: r.start,
end: r.end,
mode: this.modes[r.languageId],
attributeValue: r.attributeValue
};
});
}

getAllModesInDocument(document: TextDocument): LanguageMode[] {
const result = [];
for (const languageId of this.documentRegions.get(document).getLanguagesInDocument()) {
const mode = this.modes[languageId];
if (mode) {
result.push(mode);
}
},
dispose(): void {
modelCaches.forEach(mc => mc.dispose());
modelCaches = [];
for (const mode in modes) {
modes[mode].dispose();
}
return result;
}

getAllModes(): LanguageMode[] {
const result = [];
for (const languageId in this.modes) {
const mode = this.modes[languageId];
if (mode) {
result.push(mode);
}
modes = {}; // drop all references
}
};
return result;
}

getMode(languageId: string): LanguageMode {
return this.modes[languageId];
}

onDocumentRemoved(document: TextDocument) {
this.modelCaches.forEach(mc => mc.onDocumentRemoved(document));
for (const mode in this.modes) {
this.modes[mode].onDocumentRemoved(document);
}
}

dispose(): void {
this.modelCaches.forEach(mc => mc.dispose());
this.modelCaches = [];
for (const mode in this.modes) {
this.modes[mode].dispose();
}
this.modes = {}; // drop all references
}
}
16 changes: 9 additions & 7 deletions server/src/modes/script/childComponents.ts
Original file line number Diff line number Diff line change
@@ -1,18 +1,20 @@
import * as ts from 'typescript';
import { getLastChild, buildDocumentation, getObjectLiteralExprFromExportExpr } from './componentInfo';
import { T_TypeScript } from '../../services/dependencyService';

interface InternalChildComponent {
name: string;
documentation?: string;
definition?: {
path: string;
start: number;
end: number
end: number;
};
defaultExportExpr?: ts.Node;
}

export function getChildComponents(
tsModule: T_TypeScript,
defaultExportType: ts.Type,
checker: ts.TypeChecker,
tagCasing = 'kebab'
Expand All @@ -27,7 +29,7 @@ export function getChildComponents(
return undefined;
}

if (componentsDeclaration.kind === ts.SyntaxKind.ObjectLiteralExpression) {
if (componentsDeclaration.kind === tsModule.SyntaxKind.ObjectLiteralExpression) {
const componentsType = checker.getTypeOfSymbolAtLocation(componentsSymbol, componentsDeclaration);

const result: InternalChildComponent[] = [];
Expand All @@ -42,18 +44,18 @@ export function getChildComponents(
}

let objectLiteralSymbol: ts.Symbol | undefined;
if (s.valueDeclaration.kind === ts.SyntaxKind.PropertyAssignment) {
if (s.valueDeclaration.kind === tsModule.SyntaxKind.PropertyAssignment) {
objectLiteralSymbol =
checker.getSymbolAtLocation((s.valueDeclaration as ts.PropertyAssignment).initializer) || s;
} else if (s.valueDeclaration.kind === ts.SyntaxKind.ShorthandPropertyAssignment) {
} else if (s.valueDeclaration.kind === tsModule.SyntaxKind.ShorthandPropertyAssignment) {
objectLiteralSymbol = checker.getShorthandAssignmentValueSymbol(s.valueDeclaration) || s;
}

if (!objectLiteralSymbol) {
return;
}

if (objectLiteralSymbol.flags & ts.SymbolFlags.Alias) {
if (objectLiteralSymbol.flags & tsModule.SymbolFlags.Alias) {
const definitionObjectLiteralSymbol = checker.getAliasedSymbol(objectLiteralSymbol);
if (definitionObjectLiteralSymbol.valueDeclaration) {
const defaultExportExpr = getLastChild(definitionObjectLiteralSymbol.valueDeclaration);
Expand All @@ -63,13 +65,13 @@ export function getChildComponents(

result.push({
name: componentName,
documentation: buildDocumentation(definitionObjectLiteralSymbol, checker),
documentation: buildDocumentation(tsModule, definitionObjectLiteralSymbol, checker),
definition: {
path: definitionObjectLiteralSymbol.valueDeclaration.getSourceFile().fileName,
start: defaultExportExpr.getStart(undefined, true),
end: defaultExportExpr.getEnd()
},
defaultExportExpr: getObjectLiteralExprFromExportExpr(defaultExportExpr)
defaultExportExpr: getObjectLiteralExprFromExportExpr(tsModule, defaultExportExpr)
});
}
}
Expand Down
Loading