Skip to content

Commit

Permalink
feat: add option to disable features using the configuration
Browse files Browse the repository at this point in the history
closes #3
  • Loading branch information
MartinJohns committed Apr 8, 2018
1 parent 11e2fd0 commit 04d848a
Show file tree
Hide file tree
Showing 4 changed files with 108 additions and 12 deletions.
33 changes: 33 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -47,5 +47,38 @@
"scripts": {
"postbump": "vsce package"
}
},
"contributes": {
"configuration": {
"type": "object",
"title": "inline-types extension configuration",
"properties": {
"inlineTypes.features.variableType": {
"type": "boolean",
"default": true,
"description": "Render the type of variables."
},
"inlineTypes.features.functionReturnType": {
"type": "boolean",
"default": true,
"description": "Render the return type of functions."
},
"inlineTypes.features.functionParameterType": {
"type": "boolean",
"default": true,
"description": "Render the type of function parameters."
},
"inlineTypes.features.propertyType": {
"type": "boolean",
"default": true,
"description": "Render the type of properties."
},
"inlineTypes.features.parameterName": {
"type": "boolean",
"default": true,
"description": "Render the names of parameters in function calls."
}
}
}
}
}
42 changes: 38 additions & 4 deletions src/extension.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import * as vscode from 'vscode';

import { error as logError, info as logInfo } from './log';
import { createService } from './service';
import { FileChangeTypes, Decoration, TextChange, Position, Service } from './types';
import { FileChangeTypes, Decoration, TextChange, Position, Service, Configuration, Disposable } from './types';

export function activate(extensionContext: vscode.ExtensionContext): void {
const rootPath = vscode.workspace.rootPath;
Expand All @@ -11,22 +11,56 @@ export function activate(extensionContext: vscode.ExtensionContext): void {
return;
}

const subscriptions: Disposable[] = [];
function dispose(): void {
let nextSubscription: Disposable | undefined;;
while ((nextSubscription = subscriptions.pop()) !== undefined) {
nextSubscription.dispose();
}
}
extensionContext.subscriptions.push({ dispose });

createServiceForExtension(rootPath, subscriptions);
extensionContext.subscriptions.push(vscode.workspace.onDidChangeConfiguration(e => {
if (e.affectsConfiguration('inlineTypes')) {
dispose();
createServiceForExtension(rootPath, subscriptions);
}
}));
}

function createServiceForExtension(
rootPath: string,
subscriptions: Disposable[]
): Service {
const decorationType: vscode.TextEditorDecorationType = vscode.window.createTextEditorDecorationType({});
extensionContext.subscriptions.push(decorationType);
subscriptions.push(decorationType);

const service = createService(rootPath, () => updateDecorations(decorationType, service));
const configuration: Configuration = mapConfiguration(vscode.workspace.getConfiguration('inlineTypes'));
const service = createService(
rootPath,
configuration,
() => updateDecorations(decorationType, service));
updateDecorations(decorationType, service);

const fileWatcher = vscode.workspace.createFileSystemWatcher('{!node_modules,**}/*.ts');
fileWatcher.onDidCreate(e => service.notifyFileChange(normalizeFileName(e.fsPath), FileChangeTypes.Created));
fileWatcher.onDidChange(e => service.notifyFileChange(normalizeFileName(e.fsPath), FileChangeTypes.Changed));
fileWatcher.onDidDelete(e => service.notifyFileChange(normalizeFileName(e.fsPath), FileChangeTypes.Deleted));
extensionContext.subscriptions.push(fileWatcher);
subscriptions.push(fileWatcher);

vscode.window.onDidChangeActiveTextEditor(() => updateDecorations(decorationType, service));
vscode.workspace.onDidChangeTextDocument(e => service.notifyDocumentChange(
normalizeFileName(e.document.fileName),
e.contentChanges.map(mapContentChange)));

return service;
}

function mapConfiguration(configuration: vscode.WorkspaceConfiguration): Configuration {
return {
features: configuration.features
};
}

function updateDecorations(
Expand Down
30 changes: 22 additions & 8 deletions src/service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { join as joinPath } from 'path';

import { throwError, isUndefined, assertNever, curry, isRestParameter } from './utils';
import { error as logError, info as logInfo } from './log';
import { TextChange, Service, FileChangeType, FileChangeTypes, Decoration, Position } from './types';
import { TextChange, Service, FileChangeType, FileChangeTypes, Decoration, Position, Configuration } from './types';

class SourceFilesCache extends Map<string, ts.SourceFile> {
public constructor() {
Expand All @@ -13,6 +13,7 @@ class SourceFilesCache extends Map<string, ts.SourceFile> {

interface ServiceContext {
readonly rootPath: string;
readonly configuration: Configuration;
readonly sourceFilesCache: SourceFilesCache;
readonly updateProgram: () => void;
readonly getProgram: () => ts.Program;
Expand All @@ -21,8 +22,12 @@ interface ServiceContext {
readonly getRootFileNames: () => ReadonlyArray<string>;
}

export function createService(rootPath: string, onUpdate: () => void): Service {
const context = createServiceContext(rootPath, onUpdate);
export function createService(
rootPath: string,
configuration: Configuration,
onUpdate: () => void
): Service {
const context = createServiceContext(rootPath, configuration, onUpdate);

return {
getDecorations: curry(getDecorations, context),
Expand All @@ -31,11 +36,16 @@ export function createService(rootPath: string, onUpdate: () => void): Service {
};
}

function createServiceContext(rootPath: string, onUpdate: () => void): ServiceContext {
function createServiceContext(
rootPath: string,
configuration: Configuration,
onUpdate: () => void
): ServiceContext {
const sourceFilesCache = new SourceFilesCache();
let program: ts.Program = createProgram(rootPath, sourceFilesCache);
const context: ServiceContext = {
rootPath,
configuration,
sourceFilesCache,
updateProgram: () => updateProgram(() => context, newProgram => program = newProgram, onUpdate),
getProgram: () => program,
Expand Down Expand Up @@ -80,15 +90,19 @@ function getDecorations(
return result;

function aux(node: ts.Node): void {
if ((ts.isVariableDeclaration(node) || ts.isPropertySignature(node) || ts.isParameter(node)) && !node.type) {
if (ts.isVariableDeclaration(node) && !node.type && context.configuration.features.variableType) {
result.push(getDecoration(sourceFile!, typeChecker, node.name))
} else if (ts.isPropertySignature(node) && !node.type && context.configuration.features.propertyType) {
result.push(getDecoration(sourceFile!, typeChecker, node.name))
} else if (ts.isParameter(node) && !node.type && context.configuration.features.functionParameterType) {
result.push(getDecoration(sourceFile!, typeChecker, node.name))
} else if (ts.isFunctionDeclaration(node) && !node.type) {
} else if (ts.isFunctionDeclaration(node) && !node.type && context.configuration.features.functionReturnType) {
const signature = typeChecker.getSignatureFromDeclaration(node);
result.push(getDecoration(sourceFile!, typeChecker, node, node.body, signature && signature.getReturnType()));
} else if (ts.isArrowFunction(node) && !node.type) {
} else if (ts.isArrowFunction(node) && !node.type && context.configuration.features.functionReturnType) {
const signature = typeChecker.getSignatureFromDeclaration(node);
result.push(getDecoration(sourceFile!, typeChecker, node, node.equalsGreaterThanToken, signature && signature.getReturnType(), true));
} else if (ts.isCallExpression(node) && node.arguments.length > 0) {
} else if (ts.isCallExpression(node) && node.arguments.length > 0 && context.configuration.features.parameterName) {
const resolvedSignature = typeChecker.getResolvedSignature(node);
for (let i = 0; i < node.arguments.length; ++i) {
const argument = node.arguments[i];
Expand Down
15 changes: 15 additions & 0 deletions src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,3 +28,18 @@ export interface Service {
notifyFileChange(fileName: string, fileChangeType: FileChangeType): void;
getDecorations(fileName: string): ReadonlyArray<Decoration>;
}

export type FeatureType =
| 'variableType'
| 'functionReturnType'
| 'functionParameterType'
| 'propertyType'
| 'parameterName'

export interface Configuration {
readonly features: { readonly [P in FeatureType]: boolean };
}

export interface Disposable {
dispose(): any;
}

0 comments on commit 04d848a

Please sign in to comment.