diff --git a/bundles/org.eclipse.orion.client.javascript/web/javascript/nls/root/messages.js b/bundles/org.eclipse.orion.client.javascript/web/javascript/nls/root/messages.js index 0ea0d69..cdb79e1 100644 --- a/bundles/org.eclipse.orion.client.javascript/web/javascript/nls/root/messages.js +++ b/bundles/org.eclipse.orion.client.javascript/web/javascript/nls/root/messages.js @@ -29,6 +29,7 @@ define({ 'eslintValidator' : 'JavaScript Validator', 'missingCurly' : 'Statements not enclosed in braces:', 'curlyFixName': 'Enclose statement in braces', + 'ignoreInFileFixName': 'Ignore in file', 'noCaller' : 'Discouraged \'arguments.caller\' or \'arguments.callee\' use:', 'noCommaDangle' : 'Trailing commas in object expressions:', 'noCondAssign' : 'Assignments in conditional expressions:', diff --git a/bundles/org.eclipse.orion.client.javascript/web/javascript/plugins/javascriptPlugin.js b/bundles/org.eclipse.orion.client.javascript/web/javascript/plugins/javascriptPlugin.js index 86d92d8..a4aa8fd 100644 --- a/bundles/org.eclipse.orion.client.javascript/web/javascript/plugins/javascriptPlugin.js +++ b/bundles/org.eclipse.orion.client.javascript/web/javascript/plugins/javascriptPlugin.js @@ -717,6 +717,31 @@ define([ var quickFixComputer = new QuickFixes.JavaScriptQuickfixes(astManager, renameCommand, generateDocCommand, jsProject, ternWorker); provider.registerServiceProvider("orion.edit.command", //$NON-NLS-1$ + { + /** @callback */ + execute: function(editorContext, context) { + context.annotation.fixid = 'ignore-in-file'; //$NON-NLS-1$ + return quickFixComputer.execute(editorContext, context); + } + }, + { + name: javascriptMessages["ignoreInFileFixName"], + scopeId: "orion.edit.quickfix", //$NON-NLS-1$ + id: "ignore.in.file.fix", //$NON-NLS-1$ + contentType: ['application/javascript', 'text/html'], //$NON-NLS-1$ //$NON-NLS-2$ + validationProperties: [{ + source: "annotation:id", //$NON-NLS-1$ + match: "^(?:.*\\S.*)$" //$NON-NLS-1$ + }, + { + source: "readonly", //$NON-NLS-1$ + match: false + } + ] + } + ); + + provider.registerServiceProvider("orion.edit.command", //$NON-NLS-1$ quickFixComputer, { name: javascriptMessages["curlyFixName"], scopeId: "orion.edit.quickfix", //$NON-NLS-1$ diff --git a/bundles/org.eclipse.orion.client.javascript/web/javascript/validator.js b/bundles/org.eclipse.orion.client.javascript/web/javascript/validator.js index 8435d33..390b478 100644 --- a/bundles/org.eclipse.orion.client.javascript/web/javascript/validator.js +++ b/bundles/org.eclipse.orion.client.javascript/web/javascript/validator.js @@ -203,15 +203,22 @@ define([ prob.line = e.lineNumber; prob.start = e.column; } else if (typeof e.line === 'number' && typeof e.column === 'number') { - prob.line = e.line; + prob.line = e.line prob.start = e.column; } else { prob.start = 0; prob.end = 0; } + // Pass along any additional data to the problem annotation (Bug 464538) if (e.args && e.args.data){ - // Pass along any additional data to the problem annotation (Bug 464538) - prob.data = e.args.data; + if (typeof e.args.data === 'object'){ + prob.data = e.args.data; + prob.data.ruleId = e.ruleId; + } else { + prob.data = {data: e.args.data, ruleId: e.ruleId}; + } + } else { + prob.data = {ruleId: e.ruleId}; } return prob; } diff --git a/bundles/org.eclipse.orion.client.javascript/web/javascript/quickFixes.js b/bundles/org.eclipse.orion.client.javascript/web/javascript/quickFixes.js index 5e9c463..6873421 100644 --- a/bundles/org.eclipse.orion.client.javascript/web/javascript/quickFixes.js +++ b/bundles/org.eclipse.orion.client.javascript/web/javascript/quickFixes.js @@ -398,6 +398,9 @@ define([ "check-tern-plugin" : function(editorContext, context, astManager) { return astManager.getAST(editorContext).then(function(ast) { var newPlugin = context.annotation.data; + if (typeof newPlugin === 'object'){ + newPlugin = newPlugin.data; + } var json = {plugins: Object.create(null)}; json.plugins[translatePluginName(newPlugin)] = Object.create(null); return this.jsProject.updateFile(this.jsProject.TERN_PROJECT, true, json).then(function(/*file*/) { @@ -408,6 +411,9 @@ define([ "check-tern-lib" : function(editorContext, context, astManager) { return astManager.getAST(editorContext).then(function(ast) { var newLib = context.annotation.data; + if (typeof newLib === 'object'){ + newLib = newLib.data; + } var json = {libs: []}; json.libs.push(newLib); return this.jsProject.updateFile(this.jsProject.TERN_PROJECT, true, json).then(function(/*file*/) { @@ -419,14 +425,22 @@ define([ "unknown-require-plugin": function(editorContext, context, astManager) { return astManager.getAST(editorContext).then(function(ast) { var json = {plugins: Object.create(null)}; - var newPlugin = translatePluginName(context.annotation.data); + var name = context.annotation.data + if (typeof name === 'object'){ + name = name.data; + } + var newPlugin = translatePluginName(name); json.plugins[newPlugin] = Object.create(null); if (newPlugin === "commonjs") { // also add "node" see https://bugs.eclipse.org/bugs/show_bug.cgi?id=477377 json.plugins["node"] = Object.create(null); } return this.jsProject.updateFile(this.jsProject.TERN_PROJECT, true, json).then(function(/*file*/) { - var newDirective = updateDirective(ast, translateDirectiveName(context.annotation.data)); + var name = context.annotation.data + if (typeof name === 'object'){ + name = name.data; + } + var newDirective = updateDirective(ast, translateDirectiveName(name)); if(newDirective) { return editorContext.setText(newDirective.text, newDirective.start, newDirective.end).then(function() { return editorContext.syntaxCheck(ast.sourceFile.name); diff --git a/bundles/org.eclipse.orion.client.javascript/web/javascript/ternPlugins/quickfixes.js b/bundles/org.eclipse.orion.client.javascript/web/javascript/ternPlugins/quickfixes.js index 116d760..b414f33 100644 --- a/bundles/org.eclipse.orion.client.javascript/web/javascript/ternPlugins/quickfixes.js +++ b/bundles/org.eclipse.orion.client.javascript/web/javascript/ternPlugins/quickfixes.js @@ -1,6 +1,6 @@ /******************************************************************************* * @license - * Copyright (c) 2016 IBM Corporation and others. + * Copyright (c) 2016, 2017 IBM Corporation and others. * All rights reserved. This program and the accompanying materials are made * available under the terms of the Eclipse Public License v1.0 * (http://www.eclipse.org/legal/epl-v10.html), and the Eclipse Distribution @@ -502,6 +502,9 @@ define([ return false; } var name = annotation.data; + if (typeof name === 'object'){ + name = name.data; + } if(name !== null && typeof name !== 'undefined') { var comment = null; var start = 0; @@ -529,6 +532,9 @@ define([ */ "no-undef-defined-inenv": function(annotation, annotations, file) { var name = annotation.data; + if (typeof name === 'object'){ + name = name.data; + } if(name) { var comment = null; var start = 0; @@ -589,6 +595,9 @@ define([ */ "unknown-require-missing-env": function(annotation, annotations, file) { var name = annotation.data; + if (typeof name === 'object'){ + name = name.data; + } if(typeof name === 'string') { var start, comment = Finder.findDirective(file.ast, 'eslint-env'); //$NON-NLS-1$ @@ -1397,7 +1406,51 @@ define([ end: annot.end }; }); - } + }, + /** + * @callback + */ + "ignore-in-file": function(annotation, annotations, file) { + var id = annotation.data ? annotation.data.ruleId : null; + if(id) { + var result = []; + var start = 0; + var disable = Finder.findDirective(file.ast, 'eslint-disable'); //$NON-NLS-1$ + var enable = Finder.findDirective(file.ast, 'eslint-enable'); //$NON-NLS-1$ + var env = Finder.findDirective(file.ast, 'eslint-env'); //$NON-NLS-1$ + // TODO Program start only works if first entry is a function + var programStart = getDirectiveInsertionPoint(file.ast); + var insertion = programStart; + // Always insert the directive before eslint-env as it can have lint warnings + if (env){ + insertion = Math.min(env.range[0], programStart); + } + // If there is disable directive already there, add the rule to it + if (disable && disable.range[0] <= annotation.start){ + start = getDocOffset(file.ast.sourceFile.text, disable.range[0]) + disable.range[0]; + result.push({text: updateDirective(disable.value, 'eslint-disable', id, true), start: start, end: start+disable.value.length}); //$NON-NLS-1$ + } else { + var linestart = getLineStart(file.ast.sourceFile.text, insertion); + var indent = computeIndent(file.ast.sourceFile.text, linestart, false); + var fix = '/*eslint-disable '+id+' */\n' + indent; //$NON-NLS-1$ //$NON-NLS-2$ + result.push({text: fix, start: insertion, end: insertion}); + } + // If there is a file wide enable directive, remove the rule from it if there + if (enable && enable.range[0] <= annotation.start){ + var removal = removeDirective(enable.value, id); + if (removal){ + if (removal.all){ + result.push({text: '', start: enable.range[0], end: enable.range[1]}); + } else { + var enableStart = enable.range[0] + getDocOffset(file.ast.sourceFile.text, enable.range[0]) + removal.start; + var enableEnd = enable.range[0] + getDocOffset(file.ast.sourceFile.text, enable.range[0]) + removal.end; + result.push({text: '', start: enableStart, end: enableEnd}); + } + } + } + return result; + } + }, }; /** @@ -1532,9 +1585,9 @@ define([ /** * @description Updates the eslint directive - * @param {String}] text The text of the source file - * @param {String} directive The directive text - * @param {String} name The name to add + * @param {String}] text The text of the comment + * @param {String} directive The directive name + * @param {String} name The name to add to the directive * @param {Boolean} usecommas If we should separate the directive entries with commas or not * @returns {String} The new directive text */ @@ -1547,6 +1600,29 @@ define([ } return text.trim() + ' '+name; //$NON-NLS-1$ } + + /** + * @description Returns the offsets to delete to remove an entry from an eslint directive + * @param {String} text The text of the comment + * @param {String} directive The directive name + * @param {String} name The entry name to remove + * @returns {Object} Object with start and end properties for the offset to remove, will also have all: true if the directive can be removed + */ + function removeDirective(text, directive, name) { + // TODO Have tests for this + var offset = text.indexOf(name, directive.length); + if (offset >= 0){ + var end = offset+name.length; + if (text[end] === ','){ + end++; + } + if (text.slice(0,offset).trim() === "" && text.slice(end).trim() === ""){ + return {all:true, start: offset, end: end}; + } + return {start: offset, end: end}; + } + return null; + } /** * @description Finds the index of the given item in the given list