Some Eclipse Foundation services are deprecated, or will be soon. Please ensure you've read this important communication.
View | Details | Raw Unified | Return to bug 493276 | Differences between
and this patch

Collapse All | Expand All

(-)a/bundles/org.eclipse.orion.client.javascript/web/eslint/lib/load-rules-async.js (-4 / +10 lines)
Lines 265-272 define([ Link Here
265
    							if(!comments || comments.leading.length < 1) {
265
    							if(!comments || comments.leading.length < 1) {
266
    							    //TODO see https://github.com/jquery/esprima/issues/1071
266
    							    //TODO see https://github.com/jquery/esprima/issues/1071
267
							        comments = context.getComments(node.id);
267
							        comments = context.getComments(node.id);
268
    							} 
268
    							}
269
    							if(!validComment(comments)) {
269
    							if(!validComment(comments) && node.parent && node.parent.type !== "ExportNamedDeclaration") {
270
    								context.report(node.id, ProblemMessages['missing-doc'], {0:node.id.name}, { type: 'decl' });  //$NON-NLS-1$
270
    								context.report(node.id, ProblemMessages['missing-doc'], {0:node.id.name}, { type: 'decl' });  //$NON-NLS-1$
271
    							}
271
    							}
272
        						break;
272
        						break;
Lines 297-303 define([ Link Here
297
        		return {
302
        		return {
298
        			"Property": checkDoc,
303
        			"Property": checkDoc,
299
        			"FunctionDeclaration": checkDoc,
304
        			"FunctionDeclaration": checkDoc,
300
        			"ExpressionStatement": checkDoc
305
        			"ExpressionStatement": checkDoc,
306
        			"ExportNamedDeclaration": checkDoc
301
        		};
307
        		};
302
        },
308
        },
303
        /** @callback */
309
        /** @callback */
Lines 287-293 define([ Link Here
287
        							}
287
        							}
288
        						}
288
        						}
289
        						break;
289
        						break;
290
        				}
290
        					case 'ExportNamedDeclaration' :
291
    							comments = context.getComments(node);
292
    							if(!validComment(comments) && node.declaration && node.declaration.type === "FunctionDeclaration") {
293
    								context.report(node.declaration.id, ProblemMessages['missing-doc'], {0:node.declaration.id.name}, { type: 'decl' });  //$NON-NLS-1$
294
    							}
295
    					}
291
        			}
296
        			}
292
        			catch(ex) {
297
        			catch(ex) {
293
        				Logger.log(ex);
298
        				Logger.log(ex);
(-)a/bundles/org.eclipse.orion.client.javascript/web/eslint/lib/source-code.js (-9 / +14 lines)
Lines 141-149 SourceCode.prototype = { Link Here
141
        if (node) {
141
        if (node) {
142
            return (this.text !== null) ? this.text.slice(Math.max(node.range[0] - (beforeCount || 0), 0),
142
            return (this.text !== null) ? this.text.slice(Math.max(node.range[0] - (beforeCount || 0), 0),
143
                node.range[1] + (afterCount || 0)) : null;
143
                node.range[1] + (afterCount || 0)) : null;
144
        } else {
145
            return this.text;
146
        }
144
        }
145
        return this.text;
147
146
148
    },
147
    },
149
148
Lines 179-188 SourceCode.prototype = { Link Here
179
         * leadingComments/trailingComments. Comments are only left in the
178
         * leadingComments/trailingComments. Comments are only left in the
180
         * Program node comments array if there is no executable code.
179
         * Program node comments array if there is no executable code.
181
         */
180
         */
182
        if (node.type === "Program") {
181
        switch(node.type) {
183
            if (node.body.length === 0) {
182
        	case "Program" :
184
                leadingComments = node.comments;
183
	            if (node.body.length === 0) {
185
            }
184
	                leadingComments = node.comments;
185
	            }
186
	            break;
187
	        case "FunctionDeclaration" :
188
	            var parent = node.parent;
189
	            if (looksLikeExport(parent)) {
190
	               leadingComments = parent.leadingComments || [];
191
	               trailingComments = parent.trailingComments || [];
192
	            }
186
        }
193
        }
187
194
188
        return {
195
        return {
Lines 207-216 SourceCode.prototype = { Link Here
207
            case "FunctionDeclaration":
214
            case "FunctionDeclaration":
208
                if (looksLikeExport(parent)) {
215
                if (looksLikeExport(parent)) {
209
                    return findJSDocComment(parent.leadingComments, line);
216
                    return findJSDocComment(parent.leadingComments, line);
210
                } else {
211
                    return findJSDocComment(node.leadingComments, line);
212
                }
217
                }
213
                break;
218
                return findJSDocComment(node.leadingComments, line);
214
219
215
            case "ClassDeclaration":
220
            case "ClassDeclaration":
216
                return findJSDocComment(node.leadingComments, line);
221
                return findJSDocComment(node.leadingComments, line);
(-)a/bundles/org.eclipse.orion.client.javascript/web/javascript/commands/generateDocCommand.js (-2 / +20 lines)
Lines 28-34 define([ Link Here
28
		this.astManager = ASTManager;
28
		this.astManager = ASTManager;
29
		this.cuprovider = CUProvider;
29
		this.cuprovider = CUProvider;
30
	}
30
	}
31
	
31
32
	/**
33
	 * Check to see if its a ES6 export declaration
34
	 * @param {ASTNode} astNode - any node
35
	 * @returns {boolean} whether the given node represents a export declaration
36
	 * @private
37
	 */
38
	function looksLikeExport(astNode) {
39
	    return astNode.type === "ExportDefaultDeclaration" || astNode.type === "ExportNamedDeclaration" ||
40
	        astNode.type === "ExportAllDeclaration" || astNode.type === "ExportSpecifier";
41
	}
42
32
	Objects.mixin(GenerateDocCommand.prototype, {
43
	Objects.mixin(GenerateDocCommand.prototype, {
33
		/**
44
		/**
34
		 * @callback
45
		 * @callback
Lines 72-78 define([ Link Here
72
					var template;
83
					var template;
73
					var start = parent.range[0];
84
					var start = parent.range[0];
74
					if(parent.type === 'FunctionDeclaration') {
85
					if(parent.type === 'FunctionDeclaration') {
75
						template = this._genTemplate(parent.id.name, parent.params, false, parent.range[0], text);
86
						var len = parent.parents.length-1;
87
						var funcParent = parent.parents[len];
88
						if (funcParent && looksLikeExport(funcParent)) {
89
							template = this._genTemplate(parent.id.name, parent.params, false, funcParent.range[0], text);
90
							start = funcParent.range[0];
91
						} else {
92
							template = this._genTemplate(parent.id.name, parent.params, false, parent.range[0], text);
93
						}
76
					} else if(parent.type === 'Property') {
94
					} else if(parent.type === 'Property') {
77
						template = this._genTemplate(parent.key.name ? parent.key.name : parent.key.value, parent.value.params, true, parent.range[0], text);
95
						template = this._genTemplate(parent.key.name ? parent.key.name : parent.key.value, parent.value.params, true, parent.range[0], text);
78
					} else if(parent.type === 'VariableDeclarator') {
96
					} else if(parent.type === 'VariableDeclarator') {
(-)a/bundles/org.eclipse.orion.client.javascript/web/js-tests/javascript/JsMochaSuite.html (-4 / +8 lines)
Lines 23-29 Link Here
23
				"js-tests/javascript/testingWorker",
23
				"js-tests/javascript/testingWorker",
24
				'js-tests/javascript/crossFileTests',
24
				'js-tests/javascript/crossFileTests',
25
				'js-tests/javascript/ternAssistIndexTests',
25
				'js-tests/javascript/ternAssistIndexTests',
26
				'js-tests/javascript/ternAssistModuleTests',				
26
				'js-tests/javascript/ternAssistModuleTests',
27
				'js-tests/javascript/ternAssistTests',
27
				'js-tests/javascript/ternAssistTests',
28
				'js-tests/javascript/ternCommandsTests',
28
				'js-tests/javascript/ternCommandsTests',
29
				'js-tests/javascript/esprimaTolerantTests',
29
				'js-tests/javascript/esprimaTolerantTests',
Lines 34-47 Link Here
34
				'js-tests/javascript/validatorTests',
34
				'js-tests/javascript/validatorTests',
35
				'js-tests/javascript/lruTests',
35
				'js-tests/javascript/lruTests',
36
				'js-tests/javascript/quickfixTests',
36
				'js-tests/javascript/quickfixTests',
37
				'js-tests/javascript/es6QuickfixTests',
37
				'js-tests/javascript/eslintCoreTests',
38
				'js-tests/javascript/eslintCoreTests',
38
				'js-tests/javascript/scriptResolverTests',
39
				'js-tests/javascript/scriptResolverTests',
39
				'js-tests/javascript/sigparserTests',
40
				'js-tests/javascript/sigparserTests',
41
				'js-tests/javascript/es6ValidatorTests',
40
				'js-tests/javascript/ternProjectFileTests',
42
				'js-tests/javascript/ternProjectFileTests',
41
				'js-tests/javascript/ternProjectManagerTests',
43
				'js-tests/javascript/ternProjectManagerTests',
42
				'js-tests/javascript/ternProjectValidatorTests'
44
				'js-tests/javascript/ternProjectValidatorTests',
43
				], function(worker, crossFileTests, ternAssistIndexTests, ternAssistModuleTests, ternAssistTests, ternCommandTests, esprimaTolerantTests, dependencyTests, finderTests, occurrencesTests, outlinerTests, validatorTests, lruTests, quickfixTests, 
45
				], function(worker, crossFileTests, ternAssistIndexTests, ternAssistModuleTests, ternAssistTests, ternCommandTests, esprimaTolerantTests, dependencyTests, finderTests, occurrencesTests, outlinerTests, validatorTests, lruTests, quickfixTests, 
44
							eslintCoreTests, scriptResolverTests, sigparserTests, ternProjectTests, ternProjectValidatorTests) {
46
							es6QuickfixTests, eslintCoreTests, scriptResolverTests, sigparserTests, es6ValidatorTests, ternProjectTests, ternProjectValidatorTests) {
45
					var testworker;
47
					var testworker;
46
					before("reset timeout", function(done) {
48
					before("reset timeout", function(done) {
47
						this.timeout(30000);
49
						this.timeout(30000);
Lines 62-74 Link Here
62
					occurrencesTests(testworker);
64
					occurrencesTests(testworker);
63
					outlinerTests(testworker);
65
					outlinerTests(testworker);
64
					quickfixTests(testworker);
66
					quickfixTests(testworker);
67
					es6QuickfixTests(testworker);
65
					scriptResolverTests(testworker);
68
					scriptResolverTests(testworker);
66
					sigparserTests(testworker);
69
					sigparserTests(testworker);
67
					ternAssistIndexTests(testworker);
70
					ternAssistIndexTests(testworker);
68
					ternAssistModuleTests(testworker);					
71
					ternAssistModuleTests(testworker);
69
					ternAssistTests(testworker);
72
					ternAssistTests(testworker);
70
					ternCommandTests(testworker);
73
					ternCommandTests(testworker);
71
					validatorTests(testworker);
74
					validatorTests(testworker);
75
					es6ValidatorTests(testworker);
72
					ternProjectTests(testworker);
76
					ternProjectTests(testworker);
73
					ternProjectValidatorTests(testworker);
77
					ternProjectValidatorTests(testworker);
74
					testSuite.run();
78
					testSuite.run();
(-)a/bundles/org.eclipse.orion.client.javascript/web/js-tests/javascript/es6QuickfixTests.js (+292 lines)
Added Link Here
1
/*******************************************************************************
2
 * @license
3
 * Copyright (c) 2016 IBM Corporation and others.
4
 * All rights reserved. This program and the accompanying materials are made 
5
 * available under the terms of the Eclipse Public License v1.0 
6
 * (http://www.eclipse.org/legal/epl-v10.html), and the Eclipse Distribution 
7
 * License v1.0 (http://www.eclipse.org/org/documents/edl-v10.html).
8
 *
9
 * Contributors:
10
 *	 IBM Corporation - initial API and implementation
11
 ******************************************************************************/
12
/*eslint-env amd, mocha*/
13
/* eslint-disable  missing-nls */
14
define([
15
	'javascript/quickFixes',
16
	'javascript/validator',
17
	'chai/chai',
18
	'orion/Deferred',
19
	'javascript/astManager',
20
	'javascript/cuProvider',
21
	'javascript/commands/renameCommand',
22
	'javascript/commands/generateDocCommand',
23
	'orion/serviceregistry',
24
	'javascript/javascriptProject',
25
	'mocha/mocha', //must stay at the end, not a module
26
], function(QuickFixes, Validator, chai, Deferred, ASTManager, CUProvider, RenameCommand, GenerateDocCommand, mServiceRegistry, JSProject) {
27
	var assert = chai.assert;
28
	
29
	return function(worker) {
30
		describe('ES6 Quick Fix Tests',function() {
31
			this.timeout(10000);
32
			before('Reset Tern Server', function(done) {
33
				worker.start(done,  {options:{ecmaVersion:6, sourceType:"module"}});
34
			});
35
			
36
			/**
37
			 * @description Sets up the test
38
			 * 
39
			 * Supported options include:
40
			 * -    `buffer` - the source to process
41
			 * -    `contentType` - the content type to load, defaults to application/javascript if not specified
42
			 * -    `callback` - the 'done' param from the tests, its required for all worker-based tests
43
			 * -    `rule` - the rule object. {@link #createTestRule(...)}
44
			 * -    `expected` - the array of expected fixes
45
			 * -    `fixid` - the id of the rule to use if not the same as the one created by default - allows testing multifixes
46
			 * @param {Object} options {buffer, contentType}
47
			 * @returns {Object} The object with the initialized values
48
			 */
49
			function setup(options) {
50
				var buffer = options.buffer;
51
				var contentType = options.contentType ? options.contentType : 'application/javascript';
52
				var astManager = new ASTManager.ASTManager();
53
				var serviceRegistry = new mServiceRegistry.ServiceRegistry();
54
				var validator = new Validator(worker);
55
				var state = Object.create(null);
56
				var loc = contentType === 'text/html' ? 'es6quickfix_test_script.html' : 'es6quickfix_test_script.js';
57
				assert(options.callback, "You must provide a callback for a worker-based test");
58
				state.callback = options.callback;
59
				worker.setTestState(state);
60
				var rule = options.rule;
61
				validator._enableOnly(rule.id, rule.severity, rule.opts);
62
				var renameCommand = new RenameCommand.RenameCommand(worker, {setSearchLocation: function(){}});
63
				var generateDocCommand = new GenerateDocCommand.GenerateDocCommand(astManager, CUProvider);
64
				var fixComputer = new QuickFixes.JavaScriptQuickfixes(astManager, renameCommand, generateDocCommand, new JSProject(serviceRegistry), worker);
65
				var editorContext = {
66
					/*override*/
67
					getText: function(start, end) {
68
						if(typeof start === 'undefined' && typeof end === 'undefined') {
69
							return new Deferred().resolve(buffer);
70
						}
71
						return new Deferred().resolve(buffer.slice(start, end));
72
					},
73
					
74
					setText: function(text, start, end) {
75
						return new Deferred().resolve(assertFixes(text, start, end, options.expected));
76
					},
77
					
78
					getSelections: function(){
79
						return new Deferred().resolve([]);
80
					},
81
					
82
					getFileMetadata:function() {
83
						var o = Object.create(null);
84
						o.contentType = Object.create(null);
85
						o.contentType.id = contentType;
86
						o.location = loc;
87
						return new Deferred().resolve(o);
88
					},
89
					exitLinkedMode: function() {
90
						return new Deferred().resolve();
91
					},
92
					enterLinkedMode: function(linkModel) {
93
						return new Deferred().resolve(assertLinkedModel(linkModel, options.expected));
94
					},
95
					setCaretOffset: function(caretOffset) {
96
						return new Deferred().resolve(caretOffset);
97
					},
98
					openEditor: function(file, opts){
99
						return new Deferred().resolve(assertFixes({file: file, start: opts.start, end: opts.end}, null, null, options.expected));
100
					}
101
				};
102
				return {
103
					validator: validator,
104
					fixComputer: fixComputer,
105
					editorContext: editorContext,
106
					contentType: contentType,
107
					loc: loc
108
				};
109
			}
110
		
111
			/**
112
			 * @callback from Mocha after each test run
113
			 */
114
			afterEach(function() {
115
				CUProvider.onModelChanging({file: {location: 'es6quickfix_test_script.js'}});
116
				CUProvider.onModelChanging({file: {location: 'es6quickfix_test_script.html'}});
117
			});
118
		
119
			/**
120
			 * @description Checks the state of the linked models
121
			 * @param {Object} linkedModel The linked model from the platform
122
			 * @param {Object} expected The expected linked model from the test
123
			 * @since 11.0
124
			 */
125
			function assertLinkedModel(linkedModel, expected) {
126
				try {
127
					assert(expected, "There must be an expected linkedModel");
128
					assert(expected.groups, "There must be a groups node in the expected linked model");
129
					assert(Array.isArray(expected.groups), "Groups must be an array in the expected linked model");
130
					assert(linkedModel, "There must be a linkedModel");
131
					assert(linkedModel.groups, "There must be a groups node in the linked model");
132
					assert(Array.isArray(linkedModel.groups), "Groups must be an array in the linked model");
133
					assert.equal(linkedModel.groups.length, expected.groups.length, "The linked mode groups should be the same length");
134
					expected.groups.forEach(function(group, index) {
135
						//groups have data and positions: [{offset, length}]
136
						var g = linkedModel.groups[index];
137
						assert.equal(typeof g.data, typeof group.data, "The type of the data of the groups is not the same");
138
						assert(Array.isArray(g.positions), "There should be a positions array");
139
						assert(Array.isArray(group.positions), "There must be an expected positions array");
140
						assert.equal(g.positions.length, group.positions.length, "The position arrays should be the same size");
141
						group.positions.forEach(function(pos, index2) {
142
							var p = g.positions[index2];
143
							assert(p, "There should be a position");
144
							assert.equal(p.offset, pos.offset, "The position offsets do not match");
145
							assert.equal(p.length, pos.length, "The position lengths do not match");
146
						});
147
					});
148
				}
149
				catch(err) {
150
					worker.getTestState().callback(err);
151
				}
152
			}
153
		
154
			/**
155
			 * @description Runs the validator on the given options and computes fixes for those problems
156
			 * @param {Object} options {buffer, contentType, rule}
157
			 * @returns {orion.Promise} The validation promise
158
			 */
159
			function getFixes(options) {
160
				var obj = setup(options);
161
				return obj.validator.computeProblems(obj.editorContext, {contentType: obj.contentType, rule: options.rule}).then(
162
					function(problems) {
163
						try {
164
							var pbs = problems.problems;
165
							var annot = pbs[0];
166
							if(options.pid) {
167
								for(var i = 0; i < pbs.length; i++) {
168
									if(pbs[i].id === options.pid) {
169
										annot = pbs[i];
170
										break;
171
									}
172
								}
173
								assert(i !== pbs.length, "Did not find any problems for the expected id: "+ options.pid);
174
							} else {
175
								assert(pbs, "There should always be problems");
176
								// Some quick fixes may provide multiple expected text edits per problem
177
								if (!Array.isArray(options.expected)){
178
									assert.equal(pbs.length, 1, 'Expected only one problem per test');
179
								}
180
								assert(annot.id, "No problem id is reported");
181
								assert(annot.id.indexOf(options.rule.id) === 0, "The problem id should start with the enabled rule id");
182
							}
183
							annot.title = annot.description;
184
							if(options.fixid) {
185
								annot.fixid = options.fixid;
186
							}
187
							var annotations;
188
							if (Array.isArray(options.expected)){
189
								annotations = pbs;
190
								for (i=0; i<annotations.length; i++) {
191
									annotations[i].title = annotations[i].description;
192
								}
193
							}
194
							return obj.fixComputer.execute(obj.editorContext, {annotation: annot, annotations: annotations, input: obj.loc}).then(function() {
195
									worker.getTestState().callback();
196
								},
197
								function(err) {
198
									if(err instanceof Error) {
199
										worker.getTestState().callback(err);
200
									} else if(typeof err.Message === 'string') {
201
										worker.getTestState().callback(err.Message);
202
									} else {
203
										worker.getTestState().callback("Test rejected with unknown error");
204
									}
205
								});
206
						}
207
						catch(err) {
208
							worker.getTestState().callback(err);
209
						}
210
					},
211
					function (error) {
212
							worker.getTestState().callback(error);
213
					});
214
			}
215
		
216
			/**
217
			 * @description Compares the computed fixes set against the expected ones
218
			 * @param {Array.<orion.Fix>} computed The computed set of fixes
219
			 * @param {Array.<Object>} expected The expected set of fixes
220
			 */
221
			function assertFixes(computed, start, end, expected) {
222
				try {
223
					assert(computed !== null && typeof computed !== 'undefined', 'There should be fixes');
224
					if (Array.isArray(expected)){
225
						assert(Array.isArray(computed.text), "Expected multiple quick fix text edits");
226
						assert(Array.isArray(computed.selection), "Expected multiple quick fix selections");
227
						assert.equal(computed.text.length, expected.length, "Wrong number of quick fix text edits");
228
						assert.equal(computed.selection.length, expected.length, "Wrong number of quick fix selections");
229
						for (var i=0; i<expected.length; i++) {
230
							assert(computed.text[i] === expected[i].value, 'The fix: \"'+computed.text[i]+'\" does not match the expected fix of: \"'+expected[i].value + '\"');
231
							assert.equal(computed.selection[i].start, expected[i].start, 'The fix starts do not match');
232
							assert.equal(computed.selection[i].end, expected[i].end, 'The fix ends do not match');
233
						}
234
					} else if (typeof computed === 'object' && computed.file && expected.file){
235
						assert.equal(computed.file, expected.file, 'Navigation fix found but to wrong file.\nExpected: ' + expected.file +  ' (' + expected.start + ',' + expected.end + ')\nActual: ' + computed.file +  ' (' + computed.start + ',' + computed.end + ')');
236
						assert.equal(computed.start, expected.start, 'Navigation fix found but to wrong start.\nExpected: ' + expected.file +  ' (' + expected.start + ',' + expected.end + ')\nActual: ' + computed.file +  ' (' + computed.start + ',' + computed.end + ')');
237
						assert.equal(computed.end, expected.end, 'Navigation fix found but to wrong end.\nExpected: ' + expected.file +  ' (' + expected.start + ',' + expected.end + ')\nActual: ' + computed.file +  ' (' + computed.start + ',' + computed.end + ')');
238
					} else if (typeof computed === 'object' && Array.isArray(computed.text)){
239
						assert.equal(computed.text.length, 1, 'Was expecting one quick fix text edit');
240
						assert.equal(computed.selection.length, 1, 'Was expected one quick fix selection range');
241
						assert(computed.text[0].indexOf(expected.value) > -1, 'The fix: \"'+computed.text[0]+'\"" does not match the expected fix of: '+expected.value);
242
						assert.equal(computed.selection[0].start, expected.start, 'The fix starts do not match');
243
						assert.equal(computed.selection[0].end, expected.end, 'The fix ends do not match');
244
					} else {
245
						assert(computed.indexOf(expected.value) > -1, 'The fix: '+computed+' does not match the expected fix of: '+expected.value);
246
						assert.equal(start, expected.start, 'The fix starts do not match');
247
						assert.equal(end, expected.end, 'The fix ends do not match');
248
					}
249
				}
250
				catch(err) {
251
					worker.getTestState().callback(err);
252
				}
253
			}
254
255
			/**
256
			 * @description Creates a test rule object for the test set up
257
			 * @param {String} id The id of the rule used to update the preferences in javascript/validator#updated
258
			 * @param {Number} severity The severity of the problem or null (which defaults to '2')
259
			 * @param {String} opts The optional args for a rule. For example no-missing-doc has 'decl' and 'expr' as optional args
260
			 * @returns {Object} Returns a new rule object for testing with
261
			 */
262
			function createTestRule(id, severity, opts) {
263
				var rule = Object.create(null);
264
				rule.id = id;
265
				rule.severity = severity ? severity : 2;
266
				rule.opts = opts;
267
				return rule;
268
			}
269
			//MISSING-DOC
270
			describe("missing-doc", function() {
271
				it("export named declaration", function(done) {
272
					var rule = createTestRule("missing-doc");
273
					var expected = {
274
						value: "/**\n"+
275
								" * @name myFunc\n"+
276
								" * @description description\n"+
277
								" * @returns returns\n"+
278
								" */\n",
279
						start: 21,
280
						end: 21
281
					};
282
					return getFixes({
283
						buffer: "var MYCONSTANT = \"\";\nexport function myFunc() { return MYCONSTANT; }",
284
						rule: rule,
285
						expected: expected,
286
						callback: done
287
					});
288
				});
289
			});
290
		});
291
	};
292
});
(-)a/bundles/org.eclipse.orion.client.javascript/web/js-tests/javascript/es6ValidatorTests.js (+196 lines)
Added Link Here
1
/*******************************************************************************
2
 * @license
3
 * Copyright (c) 2016 IBM Corporation and others.
4
 * All rights reserved. This program and the accompanying materials are made 
5
 * available under the terms of the Eclipse Public License v1.0 
6
 * (http://www.eclipse.org/legal/epl-v10.html), and the Eclipse Distribution 
7
 * License v1.0 (http://www.eclipse.org/org/documents/edl-v10.html).
8
 *
9
 * Contributors:
10
 *	 IBM Corporation - initial API and implementation
11
 ******************************************************************************/
12
/*eslint-env amd, mocha, node*/
13
/* eslint-disable missing-nls */
14
define([
15
	'javascript/validator',
16
	'chai/chai',
17
	'orion/Deferred',
18
	'mocha/mocha', //must stay at the end, not a module
19
], function(Validator, chai, Deferred) {
20
	var assert = chai.assert;
21
	return function(worker) {
22
		describe('ES6 Validator Tests', function() {
23
			
24
			before('Reset Tern Server', function(done) {
25
				worker.start(done,  {options:{ecmaVersion:6, sourceType:"module"}});
26
			});
27
			
28
			/**
29
			 * @description Sets up the test
30
			 * @param {Object} options {buffer, contentType}i
31
			 * @returns {Object} The object with the initialized values
32
			 */
33
			function setup(options) {
34
				var buffer = options.buffer;
35
				var contentType = options.contentType ? options.contentType : 'application/javascript';
36
				var validator = new Validator(worker);
37
				var state = Object.create(null);
38
				assert(options.callback, "You must provide a callback for a worker-based test");
39
				state.callback = options.callback;
40
				worker.setTestState(state);
41
				
42
				if (options.createFiles){
43
					for (var i=0; i<options.createFiles.length; i++) {
44
						worker.createTestFile(options.createFiles[i].name, options.createFiles[i].text);
45
					}
46
				}
47
				
48
				var editorContext = {
49
					/*override*/
50
					getText: function() {
51
						return new Deferred().resolve(buffer);
52
					},
53
					/*override*/
54
					getFileMetadata: function() {
55
						var o = Object.create(null);
56
						o.contentType = Object.create(null);
57
						o.contentType.id = contentType;
58
						o.location = 'es6validator_test_script.js';
59
						if (contentType === 'text/html'){
60
							o.location = 'es6validator_test_script.html';
61
						}
62
						return new Deferred().resolve(o);
63
					}
64
				};
65
				return {
66
					validator: validator,
67
					editorContext: editorContext,
68
					contentType: contentType
69
				};
70
			}
71
			
72
			/**
73
			 * @name validate
74
			 * @description Runs the validator on the given options
75
			 * @param {Object} options {buffer, contentType}
76
			 * @returns {orion.Promise} The validation promise
77
			 */
78
			function validate(options) {
79
				var obj = setup(options);
80
				return obj.validator.computeProblems(obj.editorContext, {contentType: obj.contentType}, options.config);
81
			}
82
		
83
			/**
84
			 * @name assertProblems
85
			 * @description Compares the computed problem set against the expected ones
86
			 * @param {Array.<orion.Problem>} computed The computed est of problems
87
			 * @param {Array.<Object>} expected The expected set of problems
88
			 */
89
			function assertProblems(computed, expected) {
90
				try {
91
					var problems = computed.problems;
92
					assert.equal(problems.length, expected.length, "The wrong number of problems was computed");
93
					for(var i = 0; i < problems.length; i++) {
94
						var pb = problems[i];
95
						var expb = expected[i];
96
						if (expb.start) {
97
							assert.equal(pb.start, expb.start, "Wrong problem start");
98
						}
99
						if (expb.end) {
100
							assert.equal(pb.end, expb.end, "Wrong problem end");
101
						}
102
						if (expb.line) {
103
							assert.equal(pb.line, expb.line, "Wrong problem line number");
104
						}
105
						if (expb.description) {
106
							assert.equal(pb.description, expb.description, "Wrong problem message");
107
						}
108
						if (expb.severity) {
109
							assert.equal(pb.severity, expb.severity, "Wrong problem severity");
110
						}
111
						if(pb.descriptionArgs) {
112
							assert(expb.descriptionArgs, "Missing expected description arguments");
113
							assert.equal(pb.descriptionArgs.nls, expb.descriptionArgs.nls, "Missing NLS descriptipon argument key");
114
						}
115
						if (expb.nodeType) {
116
							assert.equal(pb.nodeType, expb.nodeType);
117
						}
118
						if (expb.nlsComment) {
119
							assert(pb.data, "Missing data");
120
							assert(pb.data.nlsComment, "Missing data nlsComment");
121
							assert.equal(pb.data.nlsComment, expb.nlsComment, "Wrong data nlsComment");
122
						}
123
					}
124
					worker.getTestState().callback();
125
				}
126
				catch(err) {
127
					worker.getTestState().callback(err);
128
				}
129
			}
130
131
			describe("missing-doc - function declaration - ecma6", function() {
132
				it("should flag missing doc for export named declaration", function(callback) {
133
					var config = { rules: {} };
134
					config.rules['missing-doc'] = [1, {decl: 1}];
135
					var features = Object.create(null);
136
					features.modules = true;
137
					config.ecmaFeatures = features;
138
					validate({buffer: "var i = 0; export function myFunc() { return i; };", callback: callback, config: config}).then(
139
					function (problems) {
140
						assertProblems(problems, [{
141
							id: 'missing-doc',
142
							severity: 'warning',
143
							description: "Missing documentation for function \'myFunc\'.",
144
							nodeType: "Identifier"
145
						}]);
146
					},
147
					function (error) {
148
						worker.getTestState().callback(error);
149
					});
150
				});
151
			});
152
			describe("missing-nls", function() {
153
				var RULE_ID = "missing-nls";
154
				it("Ignore es6 import 1", function(callback) {
155
					var topic = 'import { MYCONSTANT , arr } from "./exports";'; 
156
					var config = { rules: {} };
157
					var createFiles = [{name: './exports', text: ''}];
158
					config.rules[RULE_ID] = 1;
159
					validate({buffer: topic, callback: callback, config: config, createFiles: createFiles}).then(
160
						function (problems) {
161
							assertProblems(problems, []);
162
						},
163
						function (error) {
164
							worker.getTestState().callback(error);
165
						});
166
				});
167
				it("Ignore es6 import 2", function(callback) {
168
					var topic = 'import * as myImport from "./exports";'; 
169
					var config = { rules: {} };
170
					var createFiles = [{name: './exports', text: ''}];
171
					config.rules[RULE_ID] = 1;
172
					validate({buffer: topic, callback: callback, config: config, createFiles: createFiles}).then(
173
						function (problems) {
174
							assertProblems(problems, []);
175
						},
176
						function (error) {
177
							worker.getTestState().callback(error);
178
						});
179
				});
180
				it("Ignore es6 import 3", function(callback) {
181
					var topic = 'import "./exports";'; 
182
					var config = { rules: {} };
183
					var createFiles = [{name: './exports', text: ''}];
184
					config.rules[RULE_ID] = 1;
185
					validate({buffer: topic, callback: callback, config: config, createFiles: createFiles}).then(
186
						function (problems) {
187
							assertProblems(problems, []);
188
						},
189
						function (error) {
190
							worker.getTestState().callback(error);
191
						});
192
				});
193
			});
194
		});
195
	};
196
});
(-)a/bundles/org.eclipse.orion.client.javascript/web/js-tests/javascript/testingWorker.js (-5 / +13 lines)
Lines 83-95 define([ Link Here
83
	 * @param {Function} callback The callback to call when done starting worker and server
83
	 * @param {Function} callback The callback to call when done starting worker and server
84
	 * @since 11.0
84
	 * @since 11.0
85
	 */
85
	 */
86
	WrappedWorker.prototype.start = function(callback) {
86
	WrappedWorker.prototype.start = function(callback, json, fn) {
87
		_state.callback = callback;
87
		if(callback) {
88
		message({request: 'start_server', args: {}}, function() {
88
			//tests can pass in null here to avoid having the test "complete" once the server starts
89
			callback();
89
			_state.callback = callback;
90
		}
91
		var j = json ? json : {};
92
		message({request: 'start_server', args: j}, function() {
93
			if(typeof fn === "function") {
94
				fn();
95
			}
96
			if(callback) {
97
				callback();
98
			}
90
		});
99
		});
91
	};
100
	};
92
	
93
	/**
101
	/**
94
	 * @name WrappedWorker.prototype.setTestState
102
	 * @name WrappedWorker.prototype.setTestState
95
	 * @description Sets the test state, must be called per test to ensure the correct state is being tested
103
	 * @description Sets the test state, must be called per test to ensure the correct state is being tested
(-)a/bundles/org.eclipse.orion.client.javascript/web/js-tests/javascript/validatorTests.js (-60 lines)
Lines 5617-5682 define([ Link Here
5617
								worker.getTestState().callback(error);
5617
								worker.getTestState().callback(error);
5618
							});
5618
							});
5619
					});
5619
					});
5620
					it("Ignore es6 import 1", function(callback) {
5621
						var topic = 'import { MYCONSTANT , arr } from "./exports";'; 
5622
						var config = { rules: {} };
5623
						var createFiles = [{name: './exports', text: ''}];
5624
						config.rules[RULE_ID] = 1;
5625
						validate({buffer: topic, callback: callback, config: config, createFiles: createFiles}).then(
5626
							function (problems) {
5627
								// TODO Tern does not default to 'sourceType: module' so we have a parse error, accepting the parse error is faster than restarting the server
5628
								assertProblems(problems, [
5629
								{
5630
									id: "forbiddenExportImport",
5631
									severity: 'error',
5632
									description: "'import' and 'export' may appear only with 'sourceType: module'",
5633
								}
5634
								]);
5635
							},
5636
							function (error) {
5637
								worker.getTestState().callback(error);
5638
							});
5639
					});
5640
					it("Ignore es6 import 2", function(callback) {
5641
						var topic = 'import * from "./exports";'; 
5642
						var config = { rules: {} };
5643
						var createFiles = [{name: './exports', text: ''}];
5644
						config.rules[RULE_ID] = 1;
5645
						validate({buffer: topic, callback: callback, config: config, createFiles: createFiles}).then(
5646
							function (problems) {
5647
								// TODO Tern does not default to 'sourceType: module' so we have a parse error, accepting the parse error is faster than restarting the server
5648
								assertProblems(problems, [
5649
								{
5650
									id: "forbiddenExportImport",
5651
									severity: 'error',
5652
									description: "'import' and 'export' may appear only with 'sourceType: module'",
5653
								}
5654
								]);
5655
							},
5656
							function (error) {
5657
								worker.getTestState().callback(error);
5658
							});
5659
					});
5660
					it("Ignore es6 import 3", function(callback) {
5661
						var topic = 'import "./exports";'; 
5662
						var config = { rules: {} };
5663
						var createFiles = [{name: './exports', text: ''}];
5664
						config.rules[RULE_ID] = 1;
5665
						validate({buffer: topic, callback: callback, config: config, createFiles: createFiles}).then(
5666
							function (problems) {
5667
								// TODO Tern does not default to 'sourceType: module' so we have a parse error, accepting the parse error is faster than restarting the server
5668
								assertProblems(problems, [
5669
								{
5670
									id: "forbiddenExportImport",
5671
									severity: 'error',
5672
									description: "'import' and 'export' may appear only with 'sourceType: module'",
5673
								}
5674
								]);
5675
							},
5676
							function (error) {
5677
								worker.getTestState().callback(error);
5678
							});
5679
					});
5680
					it("HTML Mark missing", function(callback) {
5620
					it("HTML Mark missing", function(callback) {
5681
						var topic = "<script>var a = \"a\"; var b = \"bb\";</script>";
5621
						var topic = "<script>var a = \"a\"; var b = \"bb\";</script>";
5682
						var config = { rules: {} };
5622
						var config = { rules: {} };
(-)a/bundles/org.eclipse.orion.client.javascript/web/tern/plugin/doc_comment.js (+12 lines)
Lines 108-113 Link Here
108
            if (prop) interpretComments(node, node.commentsBefore, scope, prop);
108
            if (prop) interpretComments(node, node.commentsBefore, scope, prop);
109
          }
109
          }
110
        }
110
        }
111
      },
112
      // ORION
113
      ExportNamedDeclaration: function(node, scope) {
114
        if (node.leadingComments && node.declaration && node.declaration.type === 'FunctionDeclaration') {
115
          var commentsBefore = [];
116
          node.leadingComments.forEach(function(comment) {
117
            commentsBefore.push(comment.value);
118
          });
119
          interpretComments(node, commentsBefore, scope,
120
                            scope.getProp(node.declaration.id.name),
121
                            node.declaration.scope.fnType);
122
        }
111
      }
123
      }
112
    }, infer.searchVisitor, scope);
124
    }, infer.searchVisitor, scope);
113
  }
125
  }

Return to bug 493276