Skip to content

Commit 0c545a5

Browse files
committed
test: html lint integ tests and fix issues from tests
1 parent e2b075d commit 0c545a5

21 files changed

+383
-90
lines changed

src/extensions/default/HTMLCodeHints/html-lint.js

Lines changed: 45 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@
1919
*
2020
*/
2121

22-
/* global path*/
22+
/* global path, fs*/
2323

2424
/**
2525
* Provides JSLint results via the core linting extension point
@@ -40,6 +40,11 @@ define(function (require, exports, module) {
4040
FileSystem = brackets.getModule("filesystem/FileSystem"),
4141
IndexingWorker = brackets.getModule("worker/IndexingWorker");
4242

43+
if(Phoenix.isTestWindow) {
44+
IndexingWorker.on("html_lint_extension_Loaded", ()=>{
45+
window._htmlLintExtensionReadyToIntegTest = true;
46+
});
47+
}
4348
IndexingWorker.loadScriptInWorker(`${module.uri}/../worker/html-worker.js`);
4449

4550
const prefs = PreferencesManager.getExtensionPrefs("HTMLLint");
@@ -117,26 +122,26 @@ define(function (require, exports, module) {
117122
return new Promise((resolve, reject)=>{
118123
const configFilePath = path.join(dir, CONFIG_FILE_NAME);
119124
let displayPath = ProjectManager.getProjectRelativeOrDisplayPath(configFilePath);
120-
DocumentManager.getDocumentForPath(configFilePath).done(function (configDoc) {
121-
let config;
122-
const content = configDoc.getText();
123-
try {
124-
config = JSON.parse(content);
125-
console.log("html-lint: loaded config file for project " + configFilePath);
126-
} catch (e) {
127-
console.log("html-lint: error parsing " + configFilePath, content, e);
128-
// just log and return as this is an expected failure for us while the user edits code
129-
reject(StringUtils.format(Strings.HTML_LINT_CONFIG_JSON_ERROR, displayPath));
130-
return;
131-
}
132-
resolve(config);
133-
}).fail((err)=>{
134-
if(err === FileSystemError.NOT_FOUND){
125+
// directly reading from fs as we are still getting deleted file from document manager read.
126+
fs.readFile(configFilePath, 'utf8', function (err, content) {
127+
if (err && fs.ERR_CODES.ENOENT === err.code) {
135128
resolve(null); // no config file is a valid case. we just resolve with null
136-
return;
129+
} else if(err){
130+
console.error("Error reading JSHint Config File", configFilePath, err);
131+
reject("Error reading JSHint Config File", displayPath);
132+
} else {
133+
let config;
134+
try {
135+
config = JSON.parse(content);
136+
console.log("html-lint: loaded config file for project " + configFilePath);
137+
} catch (e) {
138+
console.log("html-lint: error parsing " + configFilePath, content, e);
139+
// just log and return as this is an expected failure for us while the user edits code
140+
reject(StringUtils.format(Strings.HTML_LINT_CONFIG_JSON_ERROR, displayPath));
141+
return;
142+
}
143+
resolve(config);
137144
}
138-
console.error("Error reading JSHint Config File", configFilePath, err);
139-
reject("Error reading JSHint Config File", displayPath);
140145
});
141146
});
142147
}
@@ -191,29 +196,34 @@ define(function (require, exports, module) {
191196
});
192197
}
193198

194-
function _isFileInArray(pathToMatch, filePathArray){
195-
if(!filePathArray){
196-
return false;
197-
}
198-
for(let filePath of filePathArray){
199-
if(filePath === pathToMatch){
200-
return true;
201-
}
199+
let projectConfigPaths;
200+
function _getConfigPaths() {
201+
if(!projectConfigPaths){
202+
projectConfigPaths=[
203+
path.join(ProjectManager.getProjectRoot().fullPath, CONFIG_FILE_NAME),
204+
...UNSUPPORTED_CONFIG_FILES.map(fileName=>
205+
path.join(ProjectManager.getProjectRoot().fullPath, fileName))
206+
];
202207
}
203-
return false;
208+
return projectConfigPaths;
204209
}
205210

206-
function _projectFileChanged(_evt, changedPath, added, removed) {
207-
let configFilePath = path.join(ProjectManager.getProjectRoot().fullPath, CONFIG_FILE_NAME);
208-
if(changedPath=== configFilePath
209-
|| _isFileInArray(configFilePath, added) || _isFileInArray(configFilePath, removed)){
210-
_reloadOptions();
211+
function _projectFileChanged(_evt, changedPath, addedSet, removedSet) {
212+
const configPaths = _getConfigPaths();
213+
for(let configPath of configPaths) {
214+
if(changedPath=== configPath || addedSet.has(configPath) || removedSet.has(configPath)){
215+
_reloadOptions();
216+
return;
217+
}
211218
}
212219
}
213220

214221
AppInit.appReady(function () {
215-
ProjectManager.on(ProjectManager.EVENT_PROJECT_PATH_CHANGED_OR_RENAMED, _projectFileChanged);
216-
ProjectManager.on(ProjectManager.EVENT_PROJECT_OPEN, _reloadOptions);
222+
ProjectManager.on(ProjectManager.EVENT_PROJECT_CHANGED_OR_RENAMED_PATH, _projectFileChanged);
223+
ProjectManager.on(ProjectManager.EVENT_PROJECT_OPEN, ()=>{
224+
projectConfigPaths = null;
225+
_reloadOptions();
226+
});
217227
_reloadOptions();
218228
});
219229

src/extensions/default/HTMLCodeHints/worker/html-worker.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
let htmlValidator = HTMLLanguageService.createHTMLValidator({
2525
extends: ["html-validate:standard"]
2626
});
27+
WorkerComm.triggerPeer("html_lint_extension_Loaded", {});
2728

2829
let isUsingCustomConfig = false, currentConfigID;
2930

src/extensions/default/QuickView/colorGradientProvider.js

Lines changed: 21 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -29,10 +29,13 @@ define(function (require, exports, module) {
2929
CSSUtils = brackets.getModule("language/CSSUtils"),
3030
TokenUtils = brackets.getModule("utils/TokenUtils"),
3131
AppInit = brackets.getModule("utils/AppInit"),
32+
EditorManager = brackets.getModule("editor/EditorManager"),
3233
QuickView = brackets.getModule("features/QuickViewManager"),
3334
Strings = brackets.getModule("strings"),
3435
Metrics = brackets.getModule("utils/Metrics"),
3536
CommandManager = brackets.getModule("command/CommandManager"),
37+
MainViewManager = brackets.getModule("view/MainViewManager"),
38+
FileViewController = brackets.getModule("project/FileViewController"),
3639
Commands = brackets.getModule("command/Commands");
3740

3841
let styleLanguages = ["css", "text/x-less", "sass", "text/x-scss", "stylus"];
@@ -301,8 +304,24 @@ define(function (require, exports, module) {
301304
if(gradientMatch.match) {
302305
return;
303306
}
304-
editor.setCursorPos(startPos);
305-
CommandManager.execute(Commands.TOGGLE_QUICK_EDIT);
307+
let fullEditor = EditorManager.getCurrentFullEditor();
308+
if(fullEditor && fullEditor.document.file.fullPath !== editor.document.file.fullPath) {
309+
const foundResult = MainViewManager.findInAllWorkingSets(editor.document.file.fullPath);
310+
let paneToOpen;
311+
if(fullEditor.length) {
312+
paneToOpen = foundResult[0].pane;
313+
}
314+
FileViewController.openAndSelectDocument(editor.document.file.fullPath,
315+
FileViewController.WORKING_SET_VIEW, paneToOpen)
316+
.done(function () {
317+
fullEditor = EditorManager.getCurrentFullEditor();
318+
fullEditor.setCursorPos(startPos.line, startPos.ch, true);
319+
CommandManager.execute(Commands.TOGGLE_QUICK_EDIT);
320+
});
321+
} else {
322+
editor.setCursorPos(startPos.line, startPos.ch);
323+
CommandManager.execute(Commands.TOGGLE_QUICK_EDIT);
324+
}
306325
Metrics.countEvent(Metrics.EVENT_TYPE.QUICK_VIEW, "color", "click");
307326
});
308327

src/filesystem/File.js

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -140,6 +140,17 @@ define(function (require, exports, module) {
140140
}.bind(this));
141141
};
142142

143+
function _insertIfNotPresent(addedList, file) {
144+
if(!addedList || !addedList.length) {
145+
return [file];
146+
}
147+
const foundEntry = addedList.find(entry => entry.fullPath === file.fullPath);
148+
if(!foundEntry){
149+
addedList.push(file);
150+
}
151+
return addedList;
152+
}
153+
143154
/**
144155
* Write a file.
145156
*
@@ -179,11 +190,11 @@ define(function (require, exports, module) {
179190
this._clearCachedData();
180191
try {
181192
callback(err);
182-
return;
183193
} finally {
184194
// Always unblock external change events
185195
this._fileSystem._endChange();
186196
}
197+
return;
187198
}
188199

189200
// Always store the hash
@@ -205,6 +216,7 @@ define(function (require, exports, module) {
205216
if (parent._isWatched()) {
206217
// If the write succeeded and the parent directory is watched,
207218
// fire a synthetic change event
219+
added = _insertIfNotPresent(added, this);
208220
this._fileSystem._fireChangeEvent(parent, added, removed);
209221

210222
}

src/htmlContent/problems-panel-table.html

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@
2727
</td>
2828
<td>
2929
{{#fix.id}}
30-
<button class="btn btn-mini table-fix-err-button ph-fix-problem" title="{{Strings.FIX_ERROR}}"
30+
<button class="btn btn-mini table-fix-err-button ph-fix-problem"
3131
data-fixid="{{fix.id}}">
3232
{{Strings.FIX}}
3333
</button>

src/language/CodeInspection.js

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -547,11 +547,14 @@ define(function (require, exports, module) {
547547
const fixID = `${mark.metadata}`;
548548
let errorMessageHTML = `<a style="cursor:pointer;color: unset;">${_.escape(mark.message)}</a>`;
549549
if(documentFixes.get(fixID)){
550-
$problemView = $(`<div>
550+
$problemView = $(`<div class="code-inspection-quick-view-item">
551551
<i title="${Strings.CLICK_VIEW_PROBLEM}" style="margin-right: 3px;cursor: pointer;"
552552
class="${_getIconClassForType(mark.type, mark.isFixable)}"></i>
553-
<button class="btn btn-mini fix-problem-btn" style="margin-right: 5px;">Fix</button>
553+
<button class="btn btn-mini fix-problem-btn" style="margin-right: 5px;">${Strings.FIX}</button>
554554
${errorMessageHTML}
555+
<button class="btn btn-mini copy-qv-error-text-btn" title="${Strings.COPY_ERROR}">
556+
<i class="fas fa-copy copy-qv-error-text-btn"></i>
557+
</button>
555558
<br/>
556559
</div>`);
557560
$problemView.find(".fix-problem-btn").click(()=>{
@@ -561,10 +564,13 @@ define(function (require, exports, module) {
561564
});
562565
$hoverMessage.append($problemView);
563566
} else {
564-
$problemView = $(`<div>
567+
$problemView = $(`<div class="code-inspection-quick-view-item">
565568
<i title="${Strings.CLICK_VIEW_PROBLEM}" style="margin-right: 5px; cursor: pointer;"
566569
class="${_getIconClassForType(mark.type, mark.isFixable)}"></i>
567570
${errorMessageHTML}
571+
<button class="btn btn-mini copy-qv-error-text-btn" title="${Strings.COPY_ERROR}">
572+
<i class="fas fa-copy copy-qv-error-text-btn"></i>
573+
</button>
568574
<br/></div>`);
569575
$hoverMessage.append($problemView);
570576
}
@@ -578,6 +584,11 @@ define(function (require, exports, module) {
578584
toggleCollapsed(false);
579585
scrollToProblem(pos.line);
580586
});
587+
$problemView.find(".copy-qv-error-text-btn").click(function (evt) {
588+
evt.preventDefault();
589+
evt.stopPropagation();
590+
Phoenix.app.copyToClipboard(mark.message);
591+
});
581592
const markPos = mark.find();
582593
if(markPos.from && markPos.from.line < startPos.line){
583594
startPos.line = markPos.from.line;

src/nls/root/strings.js

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -421,8 +421,7 @@ define({
421421
"LINT_DISABLED": "Linting is disabled",
422422
"NO_LINT_AVAILABLE": "No linter available for {0}",
423423
"NOTHING_TO_LINT": "Nothing to lint",
424-
"COPY_ERROR": "Copy Error Message",
425-
"FIX_ERROR": "Fix Problem",
424+
"COPY_ERROR": "Copy problem",
426425
"FIX": "Fix",
427426
"CANNOT_FIX_TITLE": "Failed to Apply Fix",
428427
"CANNOT_FIX_SOME_TITLE": "Failed to Apply Some Fixes",

src/project/ProjectManager.js

Lines changed: 20 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -97,7 +97,7 @@ define(function (require, exports, module) {
9797
EVENT_PROJECT_FILE_CHANGED = "projectFileChanged",
9898
EVENT_PROJECT_FILE_RENAMED = "projectFileRenamed",
9999
// the path changed event differs in the sense that all events returned by this will be a path.
100-
EVENT_PROJECT_PATH_CHANGED_OR_RENAMED = "projectPathChanged";
100+
EVENT_PROJECT_CHANGED_OR_RENAMED_PATH = "projectChangedPath";
101101

102102
EventDispatcher.setLeakThresholdForEvent(EVENT_PROJECT_OPEN, 25);
103103

@@ -2025,16 +2025,25 @@ define(function (require, exports, module) {
20252025
return !unsafeExit;
20262026
}
20272027

2028-
function _entryToPathArray(entryArray) {
2029-
if(!entryArray || !entryArray.length) {
2030-
return [];
2028+
function _entryToPathSet(entryArray) {
2029+
if (!entryArray || !entryArray.length) {
2030+
return new Set();
20312031
}
2032-
return entryArray.map(entry => path.normalize(entry.fullPath));
2032+
return new Set(entryArray.map(entry => path.normalize(entry.fullPath)));
20332033
}
20342034

20352035
exports.on(EVENT_PROJECT_FILE_CHANGED, (_evt, entry, addedInProject, removedInProject)=>{
2036-
exports.trigger(EVENT_PROJECT_PATH_CHANGED_OR_RENAMED, entry && path.normalize(entry.fullPath),
2037-
_entryToPathArray(addedInProject), _entryToPathArray(removedInProject));
2036+
if(!entry && !addedInProject && !removedInProject){
2037+
// when clearing the cached files forcefully, empty change events may get trigerred, in which case ignore.
2038+
return;
2039+
}
2040+
const addedSet = _entryToPathSet(addedInProject);
2041+
const removedSet = _entryToPathSet(removedInProject);
2042+
if(!entry && !addedSet.size && !removedSet.size){
2043+
return;
2044+
}
2045+
exports.trigger(EVENT_PROJECT_CHANGED_OR_RENAMED_PATH, entry && path.normalize(entry.fullPath),
2046+
addedSet, removedSet);
20382047
});
20392048
exports.on(EVENT_PROJECT_FILE_RENAMED, (_evt, oldPath, newPath)=>{
20402049
oldPath = path.normalize(oldPath);
@@ -2044,10 +2053,10 @@ define(function (require, exports, module) {
20442053
}
20452054
const oldParent = path.dirname(oldPath), newParent = path.dirname(newPath);
20462055
if(oldParent === newParent) {
2047-
exports.trigger(EVENT_PROJECT_PATH_CHANGED_OR_RENAMED, newParent, [newPath], [oldPath]);
2056+
exports.trigger(EVENT_PROJECT_CHANGED_OR_RENAMED_PATH, newParent, new Set([newPath]), new Set([oldPath]));
20482057
} else {
2049-
exports.trigger(EVENT_PROJECT_PATH_CHANGED_OR_RENAMED, oldParent, [], [oldPath]);
2050-
exports.trigger(EVENT_PROJECT_PATH_CHANGED_OR_RENAMED, newParent, [newPath], []);
2058+
exports.trigger(EVENT_PROJECT_CHANGED_OR_RENAMED_PATH, oldParent, new Set(), new Set([oldPath]));
2059+
exports.trigger(EVENT_PROJECT_CHANGED_OR_RENAMED_PATH, newParent, new Set([newPath]), new Set());
20512060
}
20522061
});
20532062

@@ -2315,6 +2324,6 @@ define(function (require, exports, module) {
23152324
exports.EVENT_CONTENT_CHANGED = EVENT_CONTENT_CHANGED;
23162325
exports.EVENT_PROJECT_FILE_CHANGED = EVENT_PROJECT_FILE_CHANGED;
23172326
exports.EVENT_PROJECT_FILE_RENAMED = EVENT_PROJECT_FILE_RENAMED;
2318-
exports.EVENT_PROJECT_PATH_CHANGED_OR_RENAMED = EVENT_PROJECT_PATH_CHANGED_OR_RENAMED;
2327+
exports.EVENT_PROJECT_CHANGED_OR_RENAMED_PATH = EVENT_PROJECT_CHANGED_OR_RENAMED_PATH;
23192328
exports.EVENT_PROJECT_OPEN_FAILED = EVENT_PROJECT_OPEN_FAILED;
23202329
});

src/styles/brackets.less

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2992,6 +2992,14 @@ textarea.exclusions-editor {
29922992
}
29932993
}
29942994

2995+
.code-inspection-quick-view-item .copy-qv-error-text-btn {
2996+
visibility: hidden;
2997+
}
2998+
2999+
.code-inspection-quick-view-item:hover .copy-qv-error-text-btn {
3000+
visibility: visible;
3001+
}
3002+
29953003
/* Line up label text and input text */
29963004
label input {
29973005
position: relative;

src/thirdparty/licences/language-services.markdown

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -10,11 +10,6 @@ Copyright (c) Microsoft
1010
MIT License
1111
Copyright (c) 2017 Chai.js Assertion Library
1212

13-
## html-validate
14-
MIT License
15-
Copyright (c) 2017 David Sveningsson <[email protected]>
16-
https://html-validate.org/
17-
1813
## test/thirparty/mocha
1914
(The MIT License)
2015
Copyright (c) 2011-2022 OpenJS Foundation and contributors, https://openjsf.org

0 commit comments

Comments
 (0)