Skip to content

Commit

Permalink
feat(diagnostics): code action & diagnostic warning to convert 'one-w…
Browse files Browse the repository at this point in the history
…ay' to 'to-view' (#66)

* feat(diagnostics): introduce one-way warning and refactor server diagnostics
* refactor(code-action): refactor to server code actions
  • Loading branch information
Erik Lieben authored Dec 31, 2017
1 parent 06815bd commit 2eb4ee1
Show file tree
Hide file tree
Showing 19 changed files with 641 additions and 1,552 deletions.
499 changes: 252 additions & 247 deletions package.json

Large diffs are not rendered by default.

48 changes: 0 additions & 48 deletions src/client/htmlInvalidCasingCodeActionProvider.ts

This file was deleted.

104 changes: 59 additions & 45 deletions src/client/main.ts
Original file line number Diff line number Diff line change
@@ -1,45 +1,59 @@
import * as path from 'path';
import { ExtensionContext, OutputChannel, window, languages, SnippetString } from 'vscode';
import { LanguageClient, LanguageClientOptions, ServerOptions, TransportKind } from 'vscode-languageclient';
import AureliaCliCommands from './aureliaCLICommands';
import htmlInvalidCasingActionProvider from './htmlInvalidCasingCodeActionProvider';
import { RelatedFiles } from './relatedFiles';

let outputChannel: OutputChannel;

export function activate(context: ExtensionContext) {

// Create default output channel
outputChannel = window.createOutputChannel('aurelia');
context.subscriptions.push(outputChannel);

// Register CLI commands
context.subscriptions.push(AureliaCliCommands.registerCommands(outputChannel));
context.subscriptions.push(new RelatedFiles());

// Register code fix
const invalidCasingAction = new htmlInvalidCasingActionProvider();
invalidCasingAction.activate(context.subscriptions);
languages.registerCodeActionsProvider('html', invalidCasingAction);

// Register Aurelia language server
const serverModule = context.asAbsolutePath(path.join('dist', 'src', 'server', 'main.js'));
const debugOptions = { execArgv: ['--nolazy', '--debug=6100'] };
const serverOptions: ServerOptions = {
debug: { module: serverModule, options: debugOptions, transport: TransportKind.ipc },
run: { module: serverModule, transport: TransportKind.ipc },
};

const clientOptions: LanguageClientOptions = {
diagnosticCollectionName: 'Aurelia',
documentSelector: ['html'],
initializationOptions: {},
synchronize: {
configurationSection: ['aurelia'],
},
};

const client = new LanguageClient('html', 'Aurelia', serverOptions, clientOptions);
const disposable = client.start();
context.subscriptions.push(disposable);
}
import * as path from 'path';
import { ExtensionContext, OutputChannel, window, languages, SnippetString, commands, TextEdit } from 'vscode';
import { LanguageClient, LanguageClientOptions, ServerOptions, TransportKind } from 'vscode-languageclient';
import AureliaCliCommands from './aureliaCLICommands';
import { RelatedFiles } from './relatedFiles';

let outputChannel: OutputChannel;

export function activate(context: ExtensionContext) {

// Create default output channel
outputChannel = window.createOutputChannel('aurelia');
context.subscriptions.push(outputChannel);

// Register CLI commands
context.subscriptions.push(AureliaCliCommands.registerCommands(outputChannel));
context.subscriptions.push(new RelatedFiles());

// Register Code Actions
const edit = (uri: string, documentVersion: number, edits: TextEdit[]) =>
{
let textEditor = window.activeTextEditor;
if (textEditor && textEditor.document.uri.toString() === uri) {
textEditor.edit(mutator => {
for(let edit of edits) {
mutator.replace(client.protocol2CodeConverter.asRange(edit.range), edit.newText);
}
}).then((success) => {
window.activeTextEditor.document.save();
if (!success) {
window.showErrorMessage('Failed to apply Aurelia code fixes to the document. Please consider opening an issue with steps to reproduce.');
}
});
}
};
context.subscriptions.push(commands.registerCommand('aurelia-attribute-invalid-case', edit));
context.subscriptions.push(commands.registerCommand('aurelia-binding-one-way-deprecated', edit));

// Register Aurelia language server
const serverModule = context.asAbsolutePath(path.join('dist', 'src', 'server', 'main.js'));
const debugOptions = { execArgv: ['--nolazy', '--debug=6100'] };
const serverOptions: ServerOptions = {
debug: { module: serverModule, options: debugOptions, transport: TransportKind.ipc },
run: { module: serverModule, transport: TransportKind.ipc },
};

const clientOptions: LanguageClientOptions = {
diagnosticCollectionName: 'Aurelia',
documentSelector: ['html'],
initializationOptions: {},
synchronize: {
configurationSection: ['aurelia'],
},
};

const client = new LanguageClient('html', 'Aurelia', serverOptions, clientOptions);
const disposable = client.start();
context.subscriptions.push(disposable);
}
2 changes: 1 addition & 1 deletion src/server/AureliaSettings.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
export default class AureliaSettings {
public quote: string = '"';

public validation: boolean = true;
public bindings = {
data : []
}
Expand Down
30 changes: 30 additions & 0 deletions src/server/CodeActions/HtmlInvalidCaseCodeAction.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
import { Diagnostic, TextEdit, Command, TextDocument } from "vscode-languageserver-types";
import { DocumentParser } from "../DocumentParser";
import { attributeInvalidCaseFix } from "../Common/AttributeInvalidCaseFix";

export class HtmlInvalidCaseCodeAction {
public name = 'aurelia-attribute-invalid-case';

public async commands(diagnostic: Diagnostic, document: TextDocument): Promise<Command> {
const text = document.getText();
const start = document.offsetAt(diagnostic.range.start);
const end = document.offsetAt(diagnostic.range.end);
const parser = new DocumentParser();
const element = await parser.getElementAtPosition(text, start, end);

const original = text.substring(start, end);
let fixed = original;
if (element) {
fixed = attributeInvalidCaseFix(fixed, element.name);
}

return Command.create(
`Rename ${original} to ${fixed}`,
'aurelia-attribute-invalid-case',
document.uri,
document.version,
[
TextEdit.replace(diagnostic.range, fixed)
]);
}
}
17 changes: 17 additions & 0 deletions src/server/CodeActions/OneWayBindingDeprecatedCodeAction.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import { Diagnostic, TextEdit, Command, TextDocument } from "vscode-languageserver-types";

export class OneWayBindingDeprecatedCodeAction {
public name = 'aurelia-binding-one-way-deprecated';

public async commands(diagnostic: Diagnostic, document: TextDocument): Promise<Command> {

return Command.create(
`Change 'one-way' binding behaviour to 'to-view'`,
'aurelia-binding-one-way-deprecated',
document.uri,
document.version,
[
TextEdit.replace(diagnostic.range, 'to-view')
]);
}
}
31 changes: 31 additions & 0 deletions src/server/Common/AttributeInvalidCaseFix.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
import { AttributeMap } from 'aurelia-templating-binding';
import {AttributeDefinition, TagDefinition } from './../../server/DocumentParser';

export function attributeInvalidCaseFix(name: string, elementName: string) {

// TODO: find a way to detect if this element is a svg element
const attributeMap = new AttributeMap({
isStandardSvgAttribute: () => false
});

let fixed;
const auElement = attributeMap.elements[elementName];

// only replace dashes in non data-* and aria-* attributes
let lookupProperty = name.toLowerCase();
if (/^(?!(data|aria)-).*$/g.test(lookupProperty)) {
lookupProperty = lookupProperty.replace('-','');
}

if (auElement && lookupProperty in auElement) {
fixed = auElement[lookupProperty];
}
else if (lookupProperty in attributeMap.allElements) {
fixed = attributeMap.allElements[lookupProperty];
}
else {
fixed = name.split(/(?=[A-Z])/).map(s => s.toLowerCase()).join('-');
}

return fixed;
}
Loading

0 comments on commit 2eb4ee1

Please sign in to comment.