Skip to content

Commit

Permalink
Support global components
Browse files Browse the repository at this point in the history
  • Loading branch information
yoyo930021 committed Dec 8, 2020
1 parent e30b23d commit 85eecb3
Show file tree
Hide file tree
Showing 12 changed files with 162 additions and 72 deletions.
80 changes: 43 additions & 37 deletions server/src/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import path from 'path';
import { getPathDepth, normalizeFileNameToFsPath, normalizeResolve } from './utils/paths';
import fg from 'fast-glob';
import { findConfigFile } from './utils/workspace';
import { flatten } from 'lodash';

export interface VLSFormatConfig {
defaultFormatter: {
Expand Down Expand Up @@ -147,14 +148,14 @@ export function getDefaultVLSConfig(): VLSFullConfig {
};
}

export interface Component {
export interface BasicComponentInfo {
name: string;
path: string;
}

export type Glob = string;

export interface VeturProject<C = Component | Glob> {
export interface VeturProject<C = BasicComponentInfo | Glob> {
root: string;
package?: string;
tsconfig?: string;
Expand All @@ -163,55 +164,60 @@ export interface VeturProject<C = Component | Glob> {

export interface VeturFullConfig {
settings: Record<string, boolean | string | number>;
projects: VeturProject<Component>[];
projects: VeturProject<BasicComponentInfo>[];
}

export type VeturConfig = Partial<Pick<VeturFullConfig, 'settings'>> & {
projects?: Array<string | (Pick<VeturProject, 'root'> & Partial<VeturProject>)>
projects?: Array<string | (Pick<VeturProject, 'root'> & Partial<VeturProject>)>;
};

export async function getVeturFullConfig (
export async function getVeturFullConfig(
rootPathForConfig: string,
workspacePath: string,
veturConfig: VeturConfig
): Promise<VeturFullConfig> {
const oldProjects = veturConfig.projects ?? [workspacePath];
const projects = oldProjects.map((project) => {
const getFallbackPackagePath = (projectRoot: string) => {
const fallbackPackage = findConfigFile(projectRoot, 'package.json');
return (fallbackPackage ? normalizeFileNameToFsPath(fallbackPackage) : undefined);
};
const projects = oldProjects
.map(project => {
const getFallbackPackagePath = (projectRoot: string) => {
const fallbackPackage = findConfigFile(projectRoot, 'package.json');
return fallbackPackage ? normalizeFileNameToFsPath(fallbackPackage) : undefined;
};

if (typeof project === 'string') {
const projectRoot = normalizeResolve(rootPathForConfig, project);
const tsconfigPath = findConfigFile(projectRoot, 'tsconfig.json') ?? findConfigFile(projectRoot, 'jsconfig.json');
if (typeof project === 'string') {
const projectRoot = normalizeResolve(rootPathForConfig, project);
const tsconfigPath =
findConfigFile(projectRoot, 'tsconfig.json') ?? findConfigFile(projectRoot, 'jsconfig.json');

return {
root: projectRoot,
package: getFallbackPackagePath(projectRoot),
tsconfig: tsconfigPath ? normalizeFileNameToFsPath(tsconfigPath) : undefined,
globalComponents: []
} as VeturProject;
}

const projectRoot = normalizeResolve(rootPathForConfig, project.root);
return {
root: projectRoot,
package: getFallbackPackagePath(projectRoot),
tsconfig: tsconfigPath ? normalizeFileNameToFsPath(tsconfigPath) : undefined,
globalComponents: []
} as VeturProject;
}

const projectRoot = normalizeResolve(rootPathForConfig, project.root);
return {
root: projectRoot,
package: project.package ?? getFallbackPackagePath(projectRoot),
tsconfig: project.tsconfig ?? undefined,
globalComponents: project.globalComponents
?.map(comp => {
if (typeof comp === 'string') {
return fg.sync(comp, { cwd: normalizeResolve(rootPathForConfig, projectRoot) })
.map(fileName => ({
name: path.basename(fileName, path.extname(fileName)),
path: normalizeFileNameToFsPath(fileName)
}));
}
return comp;
}) ?? []
} as VeturProject<Component>;
}).sort((a, b) => getPathDepth(b.root, '/') - getPathDepth(a.root, '/'));
package: project.package ?? getFallbackPackagePath(projectRoot),
tsconfig: project.tsconfig ?? undefined,
globalComponents: flatten(
project.globalComponents?.map(comp => {
if (typeof comp === 'string') {
return fg
.sync(comp, { cwd: normalizeResolve(rootPathForConfig, projectRoot), absolute: true })
.map(fileName => ({
name: path.basename(fileName, path.extname(fileName)),
path: normalizeFileNameToFsPath(fileName)
}));
}
return comp;
}) ?? []
)
} as VeturProject<BasicComponentInfo>;
})
.sort((a, b) => getPathDepth(b.root, '/') - getPathDepth(a.root, '/'));

return {
settings: veturConfig.settings ?? {},
Expand Down
4 changes: 3 additions & 1 deletion server/src/embeddedSupport/languageModes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ import { VueInfoService } from '../services/vueInfoService';
import { DependencyService } from '../services/dependencyService';
import { nullMode } from '../modes/nullMode';
import { getServiceHost, IServiceHost } from '../services/typescriptService/serviceHost';
import { VLSFullConfig } from '../config';
import { BasicComponentInfo, VLSFullConfig } from '../config';
import { SassLanguageMode } from '../modes/style/sass/sassLanguageMode';
import { getPugMode } from '../modes/pug';
import { VCancellationToken } from '../utils/cancellationToken';
Expand Down Expand Up @@ -116,6 +116,7 @@ export class LanguageModes {
projectPath: string,
tsconfigPath: string | undefined,
packagePath: string | undefined,
globalComponentInfos: BasicComponentInfo[],
services: VLSServices,
globalSnippetDir?: string
) {
Expand Down Expand Up @@ -150,6 +151,7 @@ export class LanguageModes {
this.serviceHost,
this.documentRegions,
services.dependencyService,
globalComponentInfos,
services.infoService
);
autoImportVueService.setGetJSResolve(jsMode.doResolve!);
Expand Down
2 changes: 1 addition & 1 deletion server/src/modes/script/childComponents.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import {
import { kebabCase } from 'lodash';
import { RuntimeLibrary } from '../../services/dependencyService';

interface InternalChildComponent {
export interface InternalChildComponent {
name: string;
documentation?: string;
definition?: {
Expand Down
18 changes: 18 additions & 0 deletions server/src/modes/script/componentInfo.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import type ts from 'typescript';
import { BasicComponentInfo } from '../../config';
import { RuntimeLibrary } from '../../services/dependencyService';
import {
VueFileInfo,
Expand All @@ -9,11 +10,13 @@ import {
ChildComponent
} from '../../services/vueInfoService';
import { analyzeComponentsDefine } from './childComponents';
import { getGlobalComponents } from './globalComponents';

export function getComponentInfo(
tsModule: RuntimeLibrary['typescript'],
service: ts.LanguageService,
fileFsPath: string,
globalComponentInfos: BasicComponentInfo[],
config: any
): VueFileInfo | undefined {
const program = service.getProgram();
Expand Down Expand Up @@ -51,13 +54,28 @@ export function getComponentInfo(
name: c.name,
documentation: c.documentation,
definition: c.definition,
global: false,
info: c.defaultExportNode ? analyzeDefaultExportExpr(tsModule, c.defaultExportNode, checker) : undefined
});
});
vueFileInfo.componentInfo.childComponents = childComponents;
vueFileInfo.componentInfo.componentsDefine = defineInfo;
}

const globalComponents = getGlobalComponents(tsModule, service, globalComponentInfos);
if (globalComponents.length > 0) {
vueFileInfo.componentInfo.childComponents = [
...(vueFileInfo.componentInfo.childComponents ?? []),
...globalComponents.map(c => ({
name: c.name,
documentation: c.documentation,
definition: c.definition,
global: true,
info: c.defaultExportNode ? analyzeDefaultExportExpr(tsModule, c.defaultExportNode, checker) : undefined
}))
];
}

return vueFileInfo;
}

Expand Down
53 changes: 53 additions & 0 deletions server/src/modes/script/globalComponents.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
import { kebabCase } from 'lodash';
import type ts from 'typescript';
import { BasicComponentInfo } from '../../config';
import { RuntimeLibrary } from '../../services/dependencyService';
import { InternalChildComponent } from './childComponents';
import { buildDocumentation, getDefaultExportNode } from './componentInfo';

export function getGlobalComponents(
tsModule: RuntimeLibrary['typescript'],
service: ts.LanguageService,
componentInfos: BasicComponentInfo[],
tagCasing = 'kebab'
): InternalChildComponent[] {
const program = service.getProgram();
if (!program) {
return [];
}

const checker = program.getTypeChecker();

const result: InternalChildComponent[] = [];
componentInfos.forEach(info => {
const sourceFile = program.getSourceFile(info.path);
if (!sourceFile) {
return;
}

const defaultExportNode = getDefaultExportNode(tsModule, sourceFile);
if (!defaultExportNode) {
return;
}

const defaultExportSymbol = checker.getTypeAtLocation(defaultExportNode);
if (!defaultExportSymbol) {
return;
}

const name = tagCasing === 'kebab' ? kebabCase(info.name) : info.name;

result.push({
name,
documentation: buildDocumentation(tsModule, defaultExportSymbol.symbol, checker),
definition: {
path: sourceFile.fileName,
start: defaultExportNode.getStart(sourceFile, true),
end: defaultExportNode.getEnd()
},
defaultExportNode
});
});

return result;
}
5 changes: 3 additions & 2 deletions server/src/modes/script/javascript.ts
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ import type ts from 'typescript';
import _ from 'lodash';

import { nullMode, NULL_SIGNATURE } from '../nullMode';
import { VLSFormatConfig } from '../../config';
import { BasicComponentInfo, VLSFormatConfig } from '../../config';
import { VueInfoService } from '../../services/vueInfoService';
import { getComponentInfo } from './componentInfo';
import { DependencyService, RuntimeLibrary } from '../../services/dependencyService';
Expand All @@ -58,6 +58,7 @@ export async function getJavascriptMode(
serviceHost: IServiceHost,
documentRegions: LanguageModelCache<VueDocumentRegions>,
dependencyService: DependencyService,
globalComponentInfos: BasicComponentInfo[],
vueInfoService?: VueInfoService
): Promise<LanguageMode> {
const jsDocuments = getLanguageModelCache(10, 60, document => {
Expand Down Expand Up @@ -128,7 +129,7 @@ export async function getJavascriptMode(

const { service } = updateCurrentVueTextDocument(doc);
const fileFsPath = getFileFsPath(doc.uri);
const info = getComponentInfo(tsModule, service, fileFsPath, config);
const info = getComponentInfo(tsModule, service, fileFsPath, globalComponentInfos, config);
if (info) {
vueInfoService.updateInfo(doc, info);
}
Expand Down
6 changes: 3 additions & 3 deletions server/src/services/autoImportVueService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ export interface AutoImportVueService {
setGetConfigure(fn: () => VLSFullConfig): void;
setGetFilesFn(fn: () => string[]): void;
setGetJSResolve(fn: (doc: TextDocument, item: CompletionItem) => CompletionItem): void;
setGetTSScriptTarget (fn: () => ts.ScriptTarget | undefined): void;
setGetTSScriptTarget(fn: () => ts.ScriptTarget | undefined): void;
doComplete(document: TextDocument): CompletionItem[];
isMyResolve(item: CompletionItem): boolean;
doResolve(document: TextDocument, item: CompletionItem): CompletionItem;
Expand Down Expand Up @@ -98,7 +98,7 @@ export function createAutoImportVueService(
setGetJSResolve(fn) {
getJSResolve = fn;
},
setGetTSScriptTarget (fn) {
setGetTSScriptTarget(fn) {
getTSScriptTarget = fn;
},
doComplete(document): CompletionItem[] {
Expand Down Expand Up @@ -149,7 +149,7 @@ import ${upperFirst(camelCase(tagName))} from '${fileName}'
}

const componentDefine = componentInfo?.componentsDefine;
const childComponents = componentInfo?.childComponents;
const childComponents = componentInfo?.childComponents?.filter(c => !c.global);
const nameForTriggerResolveInTs = modulePathToValidIdentifier(
tsModule,
item.data.path,
Expand Down
8 changes: 6 additions & 2 deletions server/src/services/projectService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,19 +29,20 @@ import {
} from 'vscode-languageserver';
import { TextDocument } from 'vscode-languageserver-textdocument';
import { URI } from 'vscode-uri';
import { VLSConfig, VLSFullConfig } from '../config';
import { BasicComponentInfo, VLSConfig, VLSFullConfig } from '../config';
import { LanguageId } from '../embeddedSupport/embeddedSupport';
import { LanguageMode, LanguageModes } from '../embeddedSupport/languageModes';
import { logger } from '../log';
import { NULL_COMPLETION, NULL_HOVER, NULL_SIGNATURE } from '../modes/nullMode';
import { DocumentContext, RefactorAction } from '../types';
import { VCancellationToken, VCancellationTokenSource } from '../utils/cancellationToken';
import { getFileFsPath } from '../utils/paths';
import { getFileFsPath, getFsPathToUri } from '../utils/paths';
import { DependencyService } from './dependencyService';
import { DocumentService } from './documentService';
import { VueInfoService } from './vueInfoService';

export interface ProjectService {
languageModes: LanguageModes;
configure(config: VLSFullConfig): void;
onDocumentFormatting(params: DocumentFormattingParams): Promise<TextEdit[]>;
onCompletion(params: CompletionParams): Promise<CompletionList>;
Expand All @@ -68,6 +69,7 @@ export async function createProjectService(
projectPath: string,
tsconfigPath: string | undefined,
packagePath: string | undefined,
globalComponentInfos: BasicComponentInfo[],
documentService: DocumentService,
initialConfig: VLSConfig,
globalSnippetDir: string | undefined,
Expand Down Expand Up @@ -97,6 +99,7 @@ export async function createProjectService(
projectPath,
tsconfigPath,
packagePath,
globalComponentInfos,
{
infoService: vueInfoService,
dependencyService
Expand All @@ -116,6 +119,7 @@ export async function createProjectService(

return {
configure,
languageModes,
async onDocumentFormatting({ textDocument, options }) {
const doc = documentService.getDocument(textDocument.uri)!;

Expand Down
1 change: 1 addition & 0 deletions server/src/services/typescriptService/serviceHost.ts
Original file line number Diff line number Diff line change
Expand Up @@ -518,6 +518,7 @@ function getParsedConfig(
) {
const configFilename = tsconfigPath;
const configJson = (configFilename && tsModule.readConfigFile(configFilename, tsModule.sys.readFile).config) || {
include: ['**/*.vue'],
exclude: defaultIgnorePatterns(tsModule, projectPath)
};
// existingOptions should be empty since it always takes priority
Expand Down
Loading

0 comments on commit 85eecb3

Please sign in to comment.