From c8118091ba88f175d114a5d6b246e17727945f02 Mon Sep 17 00:00:00 2001 From: Bernhard Sirlinger Date: Wed, 10 Apr 2013 20:54:42 +0200 Subject: [PATCH 01/56] Removed all references to CodeHintManager from Editor --- src/editor/CodeHintManager.js | 30 +++++++++++++++++++++++++++++- src/editor/Editor.js | 9 ++------- 2 files changed, 31 insertions(+), 8 deletions(-) diff --git a/src/editor/CodeHintManager.js b/src/editor/CodeHintManager.js index 0ad0fb33c88..e0db62050e6 100644 --- a/src/editor/CodeHintManager.js +++ b/src/editor/CodeHintManager.js @@ -220,7 +220,10 @@ define(function (require, exports, module) { "use strict"; // Load dependent modules - var KeyEvent = require("utils/KeyEvent"), + var AppInit = require("utils/AppInit"), + Editor = require("editor/Editor"), + EditorManager = require("editor/EditorManager"), + KeyEvent = require("utils/KeyEvent"), CodeHintList = require("editor/CodeHintList").CodeHintList; var hintProviders = { "all" : [] }, @@ -508,6 +511,31 @@ define(function (require, exports, module) { function _getCodeHintList() { return hintList; } + + AppInit.htmlReady(function () { + var editor = EditorManager.getFocusedEditor(); + + var changeHandler = function (event, editor) { + handleChange(editor); + }, + keyEventHandler = function (jqEvent, editor, event) { + handleKeyEvent(editor, event); + }; + + $(EditorManager).on("activeEditorChange", function (event, current, previous) { + $(current).on("change", changeHandler); + $(current).on("keyEvent", keyEventHandler); + + //Removing all old Handlers + $(previous).on("change", changeHandler); + $(previous).on("keyEvent", keyEventHandler); + }); + + $(editor).on("change", "*", changeHandler); + + $(editor).on("keyEvent", "*", keyEventHandler); + }); + exports._getCodeHintList = _getCodeHintList; // Define public API diff --git a/src/editor/Editor.js b/src/editor/Editor.js index 6fa7b59575f..8b7d3e6ebdb 100644 --- a/src/editor/Editor.js +++ b/src/editor/Editor.js @@ -61,8 +61,7 @@ define(function (require, exports, module) { "use strict"; - var CodeHintManager = require("editor/CodeHintManager"), - Commands = require("command/Commands"), + var Commands = require("command/Commands"), CommandManager = require("command/CommandManager"), Menus = require("command/Menus"), PerfUtils = require("utils/PerfUtils"), @@ -249,9 +248,6 @@ define(function (require, exports, module) { function _handleKeyEvents(jqEvent, editor, event) { _checkElectricChars(jqEvent, editor, event); - - // Pass the key event to the code hint manager. It may call preventDefault() on the event. - CodeHintManager.handleKeyEvent(editor, event); } /** @@ -567,8 +563,7 @@ define(function (require, exports, module) { // we're the ground truth; nothing else to do, since Document listens directly to us // note: this change might have been a real edit made by the user, OR this might have // been a change synced from another editor - - CodeHintManager.handleChange(this); + $(this).triggerHandler("editorChange", [this]); }; /** From dc6ea6fe4c0638b560ce4b5b773ab31597c46985 Mon Sep 17 00:00:00 2001 From: Bernhard Sirlinger Date: Sat, 13 Apr 2013 07:35:06 +0200 Subject: [PATCH 02/56] Fixes after review --- src/editor/CodeHintManager.js | 34 ++++++++++++++-------------------- src/editor/Editor.js | 8 +++++++- test/spec/CodeHint-test.js | 6 +++--- 3 files changed, 24 insertions(+), 24 deletions(-) diff --git a/src/editor/CodeHintManager.js b/src/editor/CodeHintManager.js index e0db62050e6..a7f5679e385 100644 --- a/src/editor/CodeHintManager.js +++ b/src/editor/CodeHintManager.js @@ -220,9 +220,7 @@ define(function (require, exports, module) { "use strict"; // Load dependent modules - var AppInit = require("utils/AppInit"), - Editor = require("editor/Editor"), - EditorManager = require("editor/EditorManager"), + var EditorManager = require("editor/EditorManager"), KeyEvent = require("utils/KeyEvent"), CodeHintList = require("editor/CodeHintList").CodeHintList; @@ -512,9 +510,7 @@ define(function (require, exports, module) { return hintList; } - AppInit.htmlReady(function () { - var editor = EditorManager.getFocusedEditor(); - + function activeEditorChangeHandler(event, current, previous) { var changeHandler = function (event, editor) { handleChange(editor); }, @@ -522,24 +518,22 @@ define(function (require, exports, module) { handleKeyEvent(editor, event); }; - $(EditorManager).on("activeEditorChange", function (event, current, previous) { - $(current).on("change", changeHandler); - $(current).on("keyEvent", keyEventHandler); + $(current).on("change", changeHandler); + $(current).on("keyEvent", keyEventHandler); - //Removing all old Handlers - $(previous).on("change", changeHandler); - $(previous).on("keyEvent", keyEventHandler); - }); - - $(editor).on("change", "*", changeHandler); - - $(editor).on("keyEvent", "*", keyEventHandler); - }); + //Removing all old Handlers + $(previous).off("change", changeHandler); + $(previous).off("keyEvent", keyEventHandler); + } + + activeEditorChangeHandler(null, EditorManager.getActiveEditor(), null); + + $(EditorManager).on("activeEditorChange", activeEditorChangeHandler); exports._getCodeHintList = _getCodeHintList; + exports._handleKeyEvent = handleKeyEvent; + exports._handleChange = handleChange; // Define public API - exports.handleKeyEvent = handleKeyEvent; - exports.handleChange = handleChange; exports.registerHintProvider = registerHintProvider; }); diff --git a/src/editor/Editor.js b/src/editor/Editor.js index 8b7d3e6ebdb..fb2532198be 100644 --- a/src/editor/Editor.js +++ b/src/editor/Editor.js @@ -562,7 +562,13 @@ define(function (require, exports, module) { // Else, Master editor: // we're the ground truth; nothing else to do, since Document listens directly to us // note: this change might have been a real edit made by the user, OR this might have - // been a change synced from another editor + // been a change synced from another editor. + + // The "editorChange" event is mostly for the use of the CodeHintManager. + // It differs from the normal "change" event, that it's actually publicly usable, + // whereas the "change" event should be listend to on the document. Also the + // Editor dispatches a change event before this event is dispatched, because + // CodeHintManager needs to hook in here when other things are already done. $(this).triggerHandler("editorChange", [this]); }; diff --git a/test/spec/CodeHint-test.js b/test/spec/CodeHint-test.js index f67b1f2fbc1..f0a0cb9aa72 100644 --- a/test/spec/CodeHint-test.js +++ b/test/spec/CodeHint-test.js @@ -116,7 +116,7 @@ define(function (require, exports, module) { // Ultimately want to use SpecRunnerUtils.simulateKeyEvent() // here, but it does not yet support modifer keys - CodeHintManager.handleKeyEvent(editor, e); + CodeHintManager._handleKeyEvent(editor, e); var codeHintList = CodeHintManager._getCodeHintList(); expect(codeHintList).toBeTruthy(); @@ -131,7 +131,7 @@ define(function (require, exports, module) { editor = EditorManager.getCurrentFullEditor(); expect(editor).toBeTruthy(); - CodeHintManager.handleKeyEvent(editor, e); + CodeHintManager._handleKeyEvent(editor, e); // doesn't matter what was inserted, but line should be different var newPos = editor.getCursorPos(); @@ -159,7 +159,7 @@ define(function (require, exports, module) { // Ultimately want to use SpecRunnerUtils.simulateKeyEvent() // here, but it does not yet support modifer keys - CodeHintManager.handleKeyEvent(editor, e); + CodeHintManager._handleKeyEvent(editor, e); // verify list is open var codeHintList = CodeHintManager._getCodeHintList(); From 36815e01ffe5f7d58b75571a90c65d334510af0e Mon Sep 17 00:00:00 2001 From: Bernhard Sirlinger Date: Tue, 7 May 2013 21:49:09 +0200 Subject: [PATCH 03/56] Fix for a module not loaded issue --- test/spec/CodeHint-test.js | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/test/spec/CodeHint-test.js b/test/spec/CodeHint-test.js index f0a0cb9aa72..f36781f8286 100644 --- a/test/spec/CodeHint-test.js +++ b/test/spec/CodeHint-test.js @@ -33,7 +33,7 @@ define(function (require, exports, module) { Editor = require("editor/Editor").Editor, KeyEvent = require("utils/KeyEvent"), EditorManager, // loaded from brackets.test - CodeHintManager; + CodeHintManager = require("editor/CodeHintManager"); var testPath = SpecRunnerUtils.getTestPath("/spec/CodeHint-test-files"), testWindow, @@ -81,7 +81,6 @@ define(function (require, exports, module) { //testWindow.brackets.app.showDeveloperTools(); // Load module instances from brackets.test - CodeHintManager = testWindow.brackets.test.CodeHintManager; EditorManager = testWindow.brackets.test.EditorManager; }); }); @@ -116,7 +115,7 @@ define(function (require, exports, module) { // Ultimately want to use SpecRunnerUtils.simulateKeyEvent() // here, but it does not yet support modifer keys - CodeHintManager._handleKeyEvent(editor, e); + CodeHintManager.handleKeyEvent(editor, e); var codeHintList = CodeHintManager._getCodeHintList(); expect(codeHintList).toBeTruthy(); @@ -131,7 +130,7 @@ define(function (require, exports, module) { editor = EditorManager.getCurrentFullEditor(); expect(editor).toBeTruthy(); - CodeHintManager._handleKeyEvent(editor, e); + CodeHintManager.handleKeyEvent(editor, e); // doesn't matter what was inserted, but line should be different var newPos = editor.getCursorPos(); @@ -159,7 +158,7 @@ define(function (require, exports, module) { // Ultimately want to use SpecRunnerUtils.simulateKeyEvent() // here, but it does not yet support modifer keys - CodeHintManager._handleKeyEvent(editor, e); + CodeHintManager.handleKeyEvent(editor, e); // verify list is open var codeHintList = CodeHintManager._getCodeHintList(); From af6f22ef505e0a24210c64560b9efc2cac1bb74c Mon Sep 17 00:00:00 2001 From: Anatoliy Ostrovskiy Date: Tue, 20 Aug 2013 23:42:57 +0400 Subject: [PATCH 04/56] Clean up _getFileExtension() method and fix all its callers --- src/file/FileUtils.js | 20 ++++---------------- 1 file changed, 4 insertions(+), 16 deletions(-) diff --git a/src/file/FileUtils.js b/src/file/FileUtils.js index 4cfc8290946..5229d8b840d 100644 --- a/src/file/FileUtils.js +++ b/src/file/FileUtils.js @@ -314,18 +314,6 @@ define(function (require, exports, module) { return false; } - /** - * Returns the file extension for a file name - * @param {string} fileName file name with extension or just a file extension - * @return {string} File extension if found, otherwise return the original file name - */ - function _getFileExtension(fileName) { - var i = fileName.lastIndexOf("."), - ext = (i === -1 || i >= fileName.length - 1) ? fileName : fileName.substr(i + 1); - - return ext; - } - /** @const - hard-coded for now, but may want to make these preferences */ var _staticHtmlFileExts = ["htm", "html"], _serverHtmlFileExts = ["php", "php3", "php4", "php5", "phtm", "phtml", "cfm", "cfml", "asp", "aspx", "jsp", "jspx", "shtm", "shtml"]; @@ -340,7 +328,7 @@ define(function (require, exports, module) { return false; } - return (_staticHtmlFileExts.indexOf(_getFileExtension(fileExt).toLowerCase()) !== -1); + return (_staticHtmlFileExts.indexOf(getFilenameExtension(fileExt).toLowerCase()) !== -1); } /** @@ -353,7 +341,7 @@ define(function (require, exports, module) { return false; } - return (_serverHtmlFileExts.indexOf(_getFileExtension(fileExt).toLowerCase()) !== -1); + return (_serverHtmlFileExts.indexOf(getFilenameExtension(fileExt).toLowerCase()) !== -1); } /** @@ -391,7 +379,7 @@ define(function (require, exports, module) { return ""; } - return baseName.substr(idx); + return baseName.substr(idx + 1); } /** @@ -402,7 +390,7 @@ define(function (require, exports, module) { */ function _getFilenameWithoutExtension(filename) { var extension = getFilenameExtension(filename); - return extension ? filename.replace(new RegExp(extension + "$"), "") : filename; + return extension ? filename.replace(new RegExp("\." + extension + "$"), "") : filename; } /** From e76777d206d0bde5631abcd234015fc1cc8fcacb Mon Sep 17 00:00:00 2001 From: Anatoliy Ostrovskiy Date: Wed, 21 Aug 2013 00:01:00 +0400 Subject: [PATCH 05/56] fixed unnecessary escaping --- src/file/FileUtils.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/file/FileUtils.js b/src/file/FileUtils.js index 5229d8b840d..65635ed0e6a 100644 --- a/src/file/FileUtils.js +++ b/src/file/FileUtils.js @@ -390,7 +390,7 @@ define(function (require, exports, module) { */ function _getFilenameWithoutExtension(filename) { var extension = getFilenameExtension(filename); - return extension ? filename.replace(new RegExp("\." + extension + "$"), "") : filename; + return extension ? filename.replace(new RegExp("." + extension + "$"), "") : filename; } /** From 68a5189c11e762100a7f2cd16e8902dae8f96e44 Mon Sep 17 00:00:00 2001 From: Anatoliy Ostrovskiy Date: Sun, 25 Aug 2013 17:35:17 +0400 Subject: [PATCH 06/56] +fixes --- src/file/FileUtils.js | 38 +++++++++++++++++++------------------- 1 file changed, 19 insertions(+), 19 deletions(-) diff --git a/src/file/FileUtils.js b/src/file/FileUtils.js index 65635ed0e6a..de3fd5f8496 100644 --- a/src/file/FileUtils.js +++ b/src/file/FileUtils.js @@ -314,6 +314,24 @@ define(function (require, exports, module) { return false; } + /** + * Get the filename extension. + * + * @param {string} fullPath full path to a file or directory + * @return {string} Returns the extension of a filename or empty string if + * the argument is a directory or a filename with no extension + */ + function getFilenameExtension(fullPath) { + var baseName = getBaseName(fullPath), + idx = baseName.lastIndexOf("."); + + if (idx === -1) { + return ""; + } + + return baseName.substr(idx); + } + /** @const - hard-coded for now, but may want to make these preferences */ var _staticHtmlFileExts = ["htm", "html"], _serverHtmlFileExts = ["php", "php3", "php4", "php5", "phtm", "phtml", "cfm", "cfml", "asp", "aspx", "jsp", "jspx", "shtm", "shtml"]; @@ -364,24 +382,6 @@ define(function (require, exports, module) { return fullPath.substr(fullPath.lastIndexOf("/") + 1); } - /** - * Get the filename extension. - * - * @param {string} fullPath full path to a file or directory - * @return {string} Returns the extension of a filename or empty string if - * the argument is a directory or a filename with no extension - */ - function getFilenameExtension(fullPath) { - var baseName = getBaseName(fullPath), - idx = baseName.lastIndexOf("."); - - if (idx === -1) { - return ""; - } - - return baseName.substr(idx + 1); - } - /** * @private * Get the file name without the extension. @@ -390,7 +390,7 @@ define(function (require, exports, module) { */ function _getFilenameWithoutExtension(filename) { var extension = getFilenameExtension(filename); - return extension ? filename.replace(new RegExp("." + extension + "$"), "") : filename; + return filename.slice(0, filename.getLastIndexOf('.')); } /** From 9d8dd71d3dc50d9f461cd689e89068b119bcafa1 Mon Sep 17 00:00:00 2001 From: Anatoliy Ostrovskiy Date: Mon, 26 Aug 2013 19:30:21 +0400 Subject: [PATCH 07/56] getLastIndexOf > lastIndexOf --- src/file/FileUtils.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/file/FileUtils.js b/src/file/FileUtils.js index de3fd5f8496..b819512a404 100644 --- a/src/file/FileUtils.js +++ b/src/file/FileUtils.js @@ -390,7 +390,7 @@ define(function (require, exports, module) { */ function _getFilenameWithoutExtension(filename) { var extension = getFilenameExtension(filename); - return filename.slice(0, filename.getLastIndexOf('.')); + return filename.slice(0, filename.lastIndexOf('.')); } /** From eed81c28c203e4fe0a2c3168af16df408bea7e80 Mon Sep 17 00:00:00 2001 From: Anatoliy Ostrovskiy Date: Mon, 26 Aug 2013 19:33:42 +0400 Subject: [PATCH 08/56] - unnecessary var decl --- src/file/FileUtils.js | 1 - 1 file changed, 1 deletion(-) diff --git a/src/file/FileUtils.js b/src/file/FileUtils.js index b819512a404..a50fe28dfc1 100644 --- a/src/file/FileUtils.js +++ b/src/file/FileUtils.js @@ -389,7 +389,6 @@ define(function (require, exports, module) { * @return {string} Returns the file name without the extension */ function _getFilenameWithoutExtension(filename) { - var extension = getFilenameExtension(filename); return filename.slice(0, filename.lastIndexOf('.')); } From 143b7a2d5c475632515132f41eccca08846d988a Mon Sep 17 00:00:00 2001 From: kvarel Date: Sun, 8 Sep 2013 09:37:28 +0200 Subject: [PATCH 09/56] czech language - sprint 30 updated --- src/nls/cs/strings.js | 26 ++++++++++++++++++-------- 1 file changed, 18 insertions(+), 8 deletions(-) diff --git a/src/nls/cs/strings.js b/src/nls/cs/strings.js index 2fc7f693b80..b4c404da637 100644 --- a/src/nls/cs/strings.js +++ b/src/nls/cs/strings.js @@ -86,7 +86,7 @@ define({ "LIVE_DEV_SERVER_NOT_READY_MESSAGE" : "Chyba při spouštění HTTP serveru pro soubory živého náhledu. Prosím, zkuste to znovu.", "LIVE_DEVELOPMENT_INFO_TITLE" : "Vítejte v živém náhledu!", "LIVE_DEVELOPMENT_INFO_MESSAGE" : "Živý náhled připojí {APP_NAME} k vašemu prohlížeči. Spustí náhled HTML souboru, který se aktualizuje pokaždé, kdy editujete svůj kód.

V této verzi {APP_NAME}, živý náhled funguje pouze v Google Chrome a aktualizuje změny v CSS souborech. Změny v HTML nebo JavaScript souborech jsou automaticky načteny, když soubor uložíte.

(Tato zpráva se zobrazí pouze jednou.)", - "LIVE_DEVELOPMENT_TROUBLESHOOTING" : "Pro více informací navštivte Troubleshooting Live Development connection errors.", + "LIVE_DEVELOPMENT_TROUBLESHOOTING" : "Pro více informací navštivte Troubleshooting Live Development connection errors.", "LIVE_DEV_STATUS_TIP_NOT_CONNECTED" : "Živý náhled", "LIVE_DEV_STATUS_TIP_PROGRESS1" : "Živý náhled: Připojování\u2026", @@ -112,10 +112,14 @@ define({ // Najít, Nahradit, Nahradit v souborech "SEARCH_REGEXP_INFO" : "Použijte /re/ syntax pro regexp hledání", "FIND_RESULT_COUNT" : "{0} výsledků", + "FIND_RESULT_COUNT_SINGLE" : "1 výsledek", + "FIND_NO_RESULTS" : "Žádné výsledky", "WITH" : "S", "BUTTON_YES" : "Ano", "BUTTON_NO" : "Ne", + "BUTTON_REPLACE_ALL" : "Vše\u2026", "BUTTON_STOP" : "Stop", + "BUTTON_REPLACE" : "Nahradit", "OPEN_FILE" : "Otevřít soubor", "SAVE_FILE_AS" : "Uložit soubor", @@ -125,17 +129,21 @@ define({ "NO_UPDATE_TITLE" : "Vše je aktuální!", "NO_UPDATE_MESSAGE" : "Verze {APP_NAME} je aktuální.", - "FIND_IN_FILES_TITLE" : "pro \"{4}\" {5} - {0} {1} v {2} {3}", + "FIND_REPLACE_TITLE_PART1" : "Nahradit \"", + "FIND_REPLACE_TITLE_PART2" : "\" s \"", + "FIND_REPLACE_TITLE_PART3" : "\" — {2} {0} {1}", + + "FIND_IN_FILES_TITLE_PART1" : "\"", + "FIND_IN_FILES_TITLE_PART2" : "\" nalezen", + "FIND_IN_FILES_TITLE_PART3" : "— {0} {1} v {2} {3}", "FIND_IN_FILES_SCOPED" : "v {0}", "FIND_IN_FILES_NO_SCOPE" : "v projektu", - "FIND_IN_FILES_FILE" : "soubor", + "FIND_IN_FILES_FILE" : "souboru", "FIND_IN_FILES_FILES" : "souborech", "FIND_IN_FILES_MATCH" : "výsledek", "FIND_IN_FILES_MATCHES" : "výsledků", "FIND_IN_FILES_MORE_THAN" : "více než ", "FIND_IN_FILES_PAGING" : "{0}—{1}", - "FIND_IN_FILES_LESS" : " Méně", - "FIND_IN_FILES_MORE" : " Více", "FIND_IN_FILES_FILE_PATH" : "Soubor: {0}", "FIND_IN_FILES_LINE" : "řádek: {0}", @@ -293,11 +301,11 @@ define({ "ABOUT" : "O aplikaci", "CLOSE" : "Zavřít", "ABOUT_TEXT_LINE1" : "sprint {VERSION_MINOR} {BUILD_TYPE} {VERSION}", - "ABOUT_TEXT_LINE3" : "Oznámení, podmínky týkající se software třetích stran jsou umístěny na {ADOBE_THIRD_PARTY} a začleněny prostřednictvím odkazu zde.", - "ABOUT_TEXT_LINE4" : "Dokumentace a zdrojový kód na https://github.com/adobe/brackets/.", + "ABOUT_TEXT_LINE3" : "Oznámení, podmínky týkající se software třetích stran jsou umístěny na http://www.adobe.com/go/thirdparty/ a začleněny prostřednictvím odkazu zde.", + "ABOUT_TEXT_LINE4" : "Dokumentace a zdrojový kód na https://github.com/adobe/brackets/.", "ABOUT_TEXT_LINE5" : "Vytvořeno s \u2764 a pomocí JavaScript těmito lidmi:", "ABOUT_TEXT_LINE6" : "Mnoho lidí (ale momentálně máme problém s načítáním dat).", - "ABOUT_TEXT_WEB_PLATFORM_DOCS" : "Web Platform Docs a Web Platform logo využívají licenci Creative Commons Attribution, CC-BY 3.0 Unported.", + "ABOUT_TEXT_WEB_PLATFORM_DOCS" : "Web Platform Docs a Web Platform logo využívají licenci Creative Commons Attribution, CC-BY 3.0 Unported.", "UPDATE_NOTIFICATION_TOOLTIP" : "Je dostupná nová verze {APP_NAME} ! Klikněte zde pro více informací.", "UPDATE_AVAILABLE_TITLE" : "Dostupná aktualizace", "UPDATE_MESSAGE" : "Nová verze {APP_NAME} je dostupná. Seznam některých vylepšení:", @@ -444,6 +452,8 @@ define({ // extensions/default/JavaScriptCodeHints "CMD_JUMPTO_DEFINITION" : "Přejít na definici", + "CMD_SHOW_PARAMETER_HINT" : "Zobrazit nápovědu parametru", + "NO_ARGUMENTS" : "<žádné parametry>", // extensions/default/JSLint "CMD_JSLINT" : "Povolit JSLint", From ac3d4056033106778063b716465ea2fe5d3d8a30 Mon Sep 17 00:00:00 2001 From: Martin Starman Date: Tue, 10 Sep 2013 08:33:09 +0200 Subject: [PATCH 10/56] Typo in czech lang --- src/nls/cs/strings.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/nls/cs/strings.js b/src/nls/cs/strings.js index f5f629c8482..bf2e011861c 100644 --- a/src/nls/cs/strings.js +++ b/src/nls/cs/strings.js @@ -168,8 +168,8 @@ define({ "STATUSBAR_INDENT_TOOLTIP_TABS" : "Přepnout odsazení na tabulátory", "STATUSBAR_INDENT_SIZE_TOOLTIP_SPACES" : "Změnit počet mezer použitých pro odsazení", "STATUSBAR_INDENT_SIZE_TOOLTIP_TABS" : "Změnit šířku tabulátoru", - "STATUSBAR_SPACES" : "mezery", - "STATUSBAR_TAB_SIZE" : "Velikost tabulátoru", + "STATUSBAR_SPACES" : "Mezery:", + "STATUSBAR_TAB_SIZE" : "Velikost tabulátoru:", "STATUSBAR_LINE_COUNT_SINGULAR" : "Řádek: {0}", "STATUSBAR_LINE_COUNT_PLURAL" : "Řádky: {0}", From 6df5ca6c7a068127f980c0a1290d3e1552c647a0 Mon Sep 17 00:00:00 2001 From: Jeff Booher Date: Sun, 15 Sep 2013 23:33:27 -0700 Subject: [PATCH 11/56] Final changes to code review needed to get this into sprint 31 --- src/file/FileUtils.js | 27 ++++++++++++++------------- 1 file changed, 14 insertions(+), 13 deletions(-) diff --git a/src/file/FileUtils.js b/src/file/FileUtils.js index a50fe28dfc1..50eff71d0d9 100644 --- a/src/file/FileUtils.js +++ b/src/file/FileUtils.js @@ -237,7 +237,18 @@ define(function (require, exports, module) { return path; } } - + + /** + * Get the base name of a file or a directory. + * @param {string} fullPath full path to a file or directory + * @return {string} Returns the base name of a file or the name of a + * directory + */ + function getBaseName(fullPath) { + fullPath = canonicalizeFolderPath(fullPath); + return fullPath.substr(fullPath.lastIndexOf("/") + 1); + } + /** * Returns a native absolute path to the 'brackets' source directory. * Note that this only works when run in brackets/src/index.html, so it does @@ -371,17 +382,6 @@ define(function (require, exports, module) { return fullPath.substr(0, fullPath.lastIndexOf("/") + 1); } - /** - * Get the base name of a file or a directory. - * @param {string} fullPath full path to a file or directory - * @return {string} Returns the base name of a file or the name of a - * directory - */ - function getBaseName(fullPath) { - fullPath = canonicalizeFolderPath(fullPath); - return fullPath.substr(fullPath.lastIndexOf("/") + 1); - } - /** * @private * Get the file name without the extension. @@ -389,7 +389,8 @@ define(function (require, exports, module) { * @return {string} Returns the file name without the extension */ function _getFilenameWithoutExtension(filename) { - return filename.slice(0, filename.lastIndexOf('.')); + var index = filename.lastIndexOf("."); + return index === -1 ? filename : filename.slice(0, index); } /** From 55215dee89052f491cb438264bff8f0587c86e03 Mon Sep 17 00:00:00 2001 From: Martin Starman Date: Mon, 16 Sep 2013 20:31:59 +0200 Subject: [PATCH 12/56] Czech lang update --- src/nls/cs/strings.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/nls/cs/strings.js b/src/nls/cs/strings.js index f5f629c8482..a82c951a777 100644 --- a/src/nls/cs/strings.js +++ b/src/nls/cs/strings.js @@ -92,7 +92,8 @@ define({ "LIVE_DEV_STATUS_TIP_PROGRESS1" : "Živý náhled: Připojování\u2026", "LIVE_DEV_STATUS_TIP_PROGRESS2" : "Živý náhled: Spouštění\u2026", "LIVE_DEV_STATUS_TIP_CONNECTED" : "Zrušit živý náhled", - "LIVE_DEV_STATUS_TIP_OUT_OF_SYNC" : "Živý náhled: Klikněte pro odpojení (uložte soubor)", + "LIVE_DEV_STATUS_TIP_OUT_OF_SYNC" : "Živý náhled (uložte soubor)", + "LIVE_DEV_STATUS_TIP_SYNC_ERROR" : "Živý náhled (neaktualizováno kvůli chybě v syntaxi)", "LIVE_DEV_DETACHED_REPLACED_WITH_DEVTOOLS" : "Živý náhled byl zrušen, protože byly otevřeny vývojářské nástroje prohlížeče", "LIVE_DEV_DETACHED_TARGET_CLOSED" : "Živý náhled byl zrušen, protože dokument byl zavřen v prohlížeči", @@ -137,8 +138,6 @@ define({ "FIND_IN_FILES_LESS" : " Méně", "FIND_IN_FILES_MORE" : " Více", "FIND_IN_FILES_FILE_PATH" : "Soubor: {0}", - "FIND_IN_FILES_LINE" : "řádek: {0}", - "ERROR_FETCHING_UPDATE_INFO_TITLE" : "Chyba při získávání informací o aktualizaci", "ERROR_FETCHING_UPDATE_INFO_MSG" : "Nelze získat aktualizace. Ujistěte se, že máte připojení na internet a zkuste to znovu.", @@ -427,6 +426,7 @@ define({ "LOCALE_PT_BR" : "Portugalsky, Brazílie", "LOCALE_PT_PT" : "Portugalsky", "LOCALE_RU" : "Rusky", + "LOCALE_SK" : "Slovensky", "LOCALE_SV" : "Švédsky", "LOCALE_TR" : "Turecky", "LOCALE_FI" : "Finsky", From 903b9716bc4d85d50000a65a00dcfc7aa60f57ef Mon Sep 17 00:00:00 2001 From: Randy Edmunds Date: Mon, 16 Sep 2013 12:41:15 -0700 Subject: [PATCH 13/56] detect pending text insertion that's not reflected in hint list --- src/editor/CodeHintList.js | 73 +++++++++++++++++++ src/editor/CodeHintManager.js | 18 ++++- src/editor/Editor.js | 2 +- src/extensions/default/CSSCodeHints/main.js | 27 ++++--- src/extensions/default/HTMLCodeHints/main.js | 26 +++++-- .../default/HtmlEntityCodeHints/main.js | 25 +++++-- .../default/JavaScriptCodeHints/main.js | 11 ++- src/extensions/default/UrlCodeHints/main.js | 26 +++++-- 8 files changed, 169 insertions(+), 39 deletions(-) diff --git a/src/editor/CodeHintList.js b/src/editor/CodeHintList.js index 3608799482f..4f8643ed586 100644 --- a/src/editor/CodeHintList.js +++ b/src/editor/CodeHintList.js @@ -87,6 +87,20 @@ define(function (require, exports, module) { */ this.insertHintOnTab = insertHintOnTab; + /** + * Current query filtering hints + * + * @type {string} + */ + this.query = ""; + + /** + * Pending text insertion + * + * @type {string} + */ + this.pendingText = ""; + /** * The hint selection callback function * @@ -145,6 +159,24 @@ define(function (require, exports, module) { } }; + /** + * Rebuilds the list items for the hint list. + * + */ + CodeHintList.prototype.addPendingText = function (text) { + this.pendingText += text; + }; + + /** + * Rebuilds the list items for the hint list. + * + */ + CodeHintList.prototype.removePendingText = function (text) { + if (this.pendingText.indexOf(text) === 0) { + this.pendingText = this.pendingText.slice(text.length); + } + }; + /** * Rebuilds the list items for the hint list. * @@ -159,6 +191,7 @@ define(function (require, exports, module) { this.hints = hintObj.hints; this.hints.handleWideResults = hintObj.handleWideResults; + this.query = hintObj.query || ""; // if there is no match, assume name is already a formatted jQuery // object; otherwise, use match to format name for display. @@ -346,6 +379,28 @@ define(function (require, exports, module) { return itemsPerPage; } + + /** + * Determine whether item is in list. + * + * Performance: list is sorted alphabetically, so we could do binary search. + * + * @private + * @param {Array.} hintList - list to search + * @param {string} itemText - text of item to search for + * @return {boolean} + */ + function _listContainsItem(hintList, itemText) { + var found = false; + hintList.some(function (listItem, index) { + if (listItem[0].innerText.indexOf(itemText) === 0) { + found = true; + return true; + } + }); + + return found; + } // If we're no longer visible, skip handling the key and end the session. if (!this.isOpen()) { @@ -377,6 +432,24 @@ define(function (require, exports, module) { } else if (this.selectedIndex !== -1 && (keyCode === KeyEvent.DOM_VK_RETURN || (keyCode === KeyEvent.DOM_VK_TAB && this.insertHintOnTab))) { + + if (this.pendingText) { + // There is pending text to be inserted in page, and... + if (_listContainsItem(this.hints, this.query + this.pendingText)) { + // ...resulting text matches something in list. We can't accept it + // because the Editor will subsequently be inserting pending text + // in page, (which leads to double-insertion) so we have to eat the + // Enter (or Tab) char. + event.stopImmediatePropagation(); + event.preventDefault(); + return true; + } else { + // ...resulting text doesn't match anything in list, so + // let the event bubble. + return false; + } + } + // Trigger a click handler to commmit the selected item $(this.$hintMenu.find("li")[this.selectedIndex]).trigger("click"); } else { diff --git a/src/editor/CodeHintManager.js b/src/editor/CodeHintManager.js index 49ac880d58f..8e91bb22281 100644 --- a/src/editor/CodeHintManager.js +++ b/src/editor/CodeHintManager.js @@ -123,7 +123,7 @@ * list window; or true, which indicates that the manager should end the * current hinting session but immediately attempt to begin a new hinting * session by querying registered providers. Otherwise, the provider should - * return a response object that contains three properties: + * return a response object that contains the following properties: * * 1. hints, a sorted array hints that the provider could later insert * into the editor; @@ -131,6 +131,9 @@ * hints in the hint list; and * 3. selectInitial, a boolean that indicates whether or not the the * first hint in the list should be selected by default. + * 4. handleWideResults, a boolean (or undefined) that indicates whether + * to allow result string to stretch width of display. + * 5. query, the string that list is filtered on * * If the array of * hints is empty, then the manager will render an empty list, but the @@ -173,7 +176,9 @@ * return {jQuery.Deferred|{ * hints: Array., * match: string, - * selectInitial: boolean}} + * selectInitial: boolean, + * handleWideReuslts: boolean, + * query: string}} * * Null if the provider wishes to end the hinting session. Otherwise, a * response object, possibly deferred, that provides 1. a sorted array @@ -537,6 +542,9 @@ define(function (require, exports, module) { } else if (event.type === "keypress") { // Last inserted character, used later by handleChange lastChar = String.fromCharCode(event.charCode); + if (hintList) { + hintList.addPendingText(lastChar); + } } else if (event.type === "keyup" && _inSession(editor)) { if (event.keyCode === KeyEvent.DOM_VK_HOME || event.keyCode === KeyEvent.DOM_VK_END) { _endSession(); @@ -556,7 +564,7 @@ define(function (require, exports, module) { * Called by the editor after handleKeyEvent, which is responsible for setting * the lastChar. */ - function handleChange(editor) { + function handleChange(editor, changeList) { if (lastChar && editor === keyDownEditor) { keyDownEditor = null; if (_inSession(editor)) { @@ -574,6 +582,10 @@ define(function (require, exports, module) { } else { _beginSession(editor); } + + if (hintList && changeList.text.length && changeList.text[0].length) { + hintList.removePendingText(changeList.text[0]); + } } } diff --git a/src/editor/Editor.js b/src/editor/Editor.js index b4369836ecc..8d6d23e7869 100644 --- a/src/editor/Editor.js +++ b/src/editor/Editor.js @@ -593,7 +593,7 @@ define(function (require, exports, module) { // note: this change might have been a real edit made by the user, OR this might have // been a change synced from another editor - CodeHintManager.handleChange(this); + CodeHintManager.handleChange(this, changeList); }; /** diff --git a/src/extensions/default/CSSCodeHints/main.js b/src/extensions/default/CSSCodeHints/main.js index 5f1b07fff00..5d17e82008e 100644 --- a/src/extensions/default/CSSCodeHints/main.js +++ b/src/extensions/default/CSSCodeHints/main.js @@ -173,7 +173,7 @@ define(function (require, exports, module) { }; /** - * Returns a list of availble CSS protertyname or -value hints if possible for the current + * Returns a list of availble CSS propertyname or -value hints if possible for the current * editor context. * * @param {Editor} implicitChar @@ -181,15 +181,22 @@ define(function (require, exports, module) { * that represents the last insertion and that indicates an implicit * hinting request. * - * @return {{hints: Array., match: string, - * selectInitial: boolean}} + * @return {jQuery.Deferred|{ + * hints: Array., + * match: string, + * selectInitial: boolean, + * handleWideReuslts: boolean, + * query: string}} * Null if the provider wishes to end the hinting session. Otherwise, a - * response object that provides + * response object that provides: * 1. a sorted array hints that consists of strings - * 2. a string match that is used by the manager to emphasize matching - * substrings when rendering the hint list - * 3. a boolean that indicates whether the first result, if one exists, should be - * selected by default in the hint list window. + * 2. a string match that is used by the manager to emphasize matching + * substrings when rendering the hint list + * 3. a boolean that indicates whether the first result, if one exists, + * should be selected by default in the hint list window. + * 4. a boolean (or undefined) that indicates whether to allow result + * string to stretch width of display. + * 5. a query string that list is filtered on */ CssPropHints.prototype.getHints = function (implicitChar) { this.cursor = this.editor.getCursorPos(); @@ -266,7 +273,9 @@ define(function (require, exports, module) { return { hints: result, match: needle, - selectInitial: selectInitial + selectInitial: selectInitial, + handleWideResults: false, + query: valueNeedle }; } return null; diff --git a/src/extensions/default/HTMLCodeHints/main.js b/src/extensions/default/HTMLCodeHints/main.js index cd781b8519a..dad115ab23c 100644 --- a/src/extensions/default/HTMLCodeHints/main.js +++ b/src/extensions/default/HTMLCodeHints/main.js @@ -105,14 +105,22 @@ define(function (require, exports, module) { * Returns a list of availble HTML tag hints if possible for the current * editor context. * - * @return {{hints: Array., match: string, - * selectInitial: boolean}} + * @return {jQuery.Deferred|{ + * hints: Array., + * match: string, + * selectInitial: boolean, + * handleWideReuslts: boolean, + * query: string}} * Null if the provider wishes to end the hinting session. Otherwise, a - * response object that provides 1. a sorted array hints that consists - * of strings; 2. a string match that is used by the manager to emphasize - * matching substrings when rendering the hint list; and 3. a boolean that - * indicates whether the first result, if one exists, should be selected - * by default in the hint list window. + * response object that provides: + * 1. a sorted array hints that consists of strings + * 2. a string match that is used by the manager to emphasize matching + * substrings when rendering the hint list + * 3. a boolean that indicates whether the first result, if one exists, + * should be selected by default in the hint list window. + * 4. a boolean (or undefined) that indicates whether to allow result + * string to stretch width of display. + * 5. a query string that list is filtered on */ TagHints.prototype.getHints = function (implicitChar) { var query, @@ -132,7 +140,9 @@ define(function (require, exports, module) { return { hints: result, match: query, - selectInitial: true + selectInitial: true, + handleWideResults: false, + query: query }; } } diff --git a/src/extensions/default/HtmlEntityCodeHints/main.js b/src/extensions/default/HtmlEntityCodeHints/main.js index 6ad953fea02..1e31093cefe 100644 --- a/src/extensions/default/HtmlEntityCodeHints/main.js +++ b/src/extensions/default/HtmlEntityCodeHints/main.js @@ -102,13 +102,22 @@ define(function (require, exports, module) { * that represents the last insertion and that indicates an implicit * hinting request. * - * @return {{hints: Array.<(string|jQuery.Obj)>, match: string, selectInitial: boolean}} + * @return {jQuery.Deferred|{ + * hints: Array., + * match: string, + * selectInitial: boolean, + * handleWideReuslts: boolean, + * query: string}} * Null if the provider wishes to end the hinting session. Otherwise, a - * response object that provides 1. a sorted array hints that consists - * of strings; 2. a string match that is used by the manager to emphasize - * matching substrings when rendering the hint list; and 3. a boolean that - * indicates whether the first result, if one exists, should be selected - * by default in the hint list window. + * response object that provides: + * 1. a sorted array hints that consists of strings + * 2. a string match that is used by the manager to emphasize matching + * substrings when rendering the hint list + * 3. a boolean that indicates whether the first result, if one exists, + * should be selected by default in the hint list window. + * 4. a boolean (or undefined) that indicates whether to allow result + * string to stretch width of display. + * 5. a query string that list is filtered on */ SpecialCharHints.prototype.getHints = function (implicitChar) { var query, @@ -130,7 +139,9 @@ define(function (require, exports, module) { return { hints: result, match: query, - selectInitial: true + selectInitial: true, + handleWideResults: false, + query: query }; } diff --git a/src/extensions/default/JavaScriptCodeHints/main.js b/src/extensions/default/JavaScriptCodeHints/main.js index d9a3fb61e57..000f3f07533 100644 --- a/src/extensions/default/JavaScriptCodeHints/main.js +++ b/src/extensions/default/JavaScriptCodeHints/main.js @@ -85,8 +85,12 @@ define(function (require, exports, module) { * @param {Array.} hints - the list of hints to format * @param {string} query - querystring used for highlighting matched * poritions of each hint - * @return {Array.} - array of hints formatted as jQuery - * objects + * @return {jQuery.Deferred|{ + * hints: Array., + * match: string, + * selectInitial: boolean, + * handleWideReuslts: boolean, + * query: string}} */ function formatHints(hints, query) { return hints.map(function (token) { @@ -166,7 +170,8 @@ define(function (require, exports, module) { hints: formattedHints, match: null, // the CodeHintManager should not format the results selectInitial: true, - handleWideResults: hints.handleWideResults + handleWideResults: hints.handleWideResults, + query: query }; } diff --git a/src/extensions/default/UrlCodeHints/main.js b/src/extensions/default/UrlCodeHints/main.js index 78ee6e70aa0..d173e9e543f 100644 --- a/src/extensions/default/UrlCodeHints/main.js +++ b/src/extensions/default/UrlCodeHints/main.js @@ -365,14 +365,22 @@ define(function (require, exports, module) { * Returns a list of availble font hints, if possible, for the current * editor context. * - * @return {{hints: Array., match: string, selectInitial: boolean}} - * + * @return {jQuery.Deferred|{ + * hints: Array., + * match: string, + * selectInitial: boolean, + * handleWideReuslts: boolean, + * query: string}} * Null if the provider wishes to end the hinting session. Otherwise, a - * response object that provides: - * 1. a sorted array formatted hints; - * 2. a null string match to indicate that the hints are already formatted; - * 3. a boolean that indicates whether the first result, if one exists, - * should be selected by default in the hint list window. + * response object that provides + * 1. a sorted array hints that consists of strings + * 2. a string match that is used by the manager to emphasize matching + * substrings when rendering the hint list + * 3. a boolean that indicates whether the first result, if one exists, should be + * selected by default in the hint list window. + * 4. handleWideResults, a boolean (or undefined) that indicates whether + * to allow result string to stretch width of display. + * 5. query, the string that list is filtered on */ UrlCodeHints.prototype.getHints = function (key) { var mode = this.editor.getModeForSelection(), @@ -475,7 +483,9 @@ define(function (require, exports, module) { deferred.resolveWith(this, [{ hints: asyncHints, match: query.queryStr, - selectInitial: true + selectInitial: true, + handleWideResults: false, + query: query }]); }); From 3230fd4fa751f61257ad3aacb692da8522798acf Mon Sep 17 00:00:00 2001 From: Randy Edmunds Date: Tue, 17 Sep 2013 15:18:57 -0700 Subject: [PATCH 14/56] changes for code review --- src/editor/CodeHintList.js | 6 ++-- src/editor/CodeHintManager.js | 2 +- src/extensions/default/CSSCodeHints/main.js | 8 +++-- src/extensions/default/HTMLCodeHints/main.js | 36 +++++++++++++------ .../default/HtmlEntityCodeHints/main.js | 2 +- .../default/JavaScriptCodeHints/main.js | 2 +- src/extensions/default/UrlCodeHints/main.js | 4 +-- 7 files changed, 40 insertions(+), 20 deletions(-) diff --git a/src/editor/CodeHintList.js b/src/editor/CodeHintList.js index 4f8643ed586..65ba0b80ab7 100644 --- a/src/editor/CodeHintList.js +++ b/src/editor/CodeHintList.js @@ -160,16 +160,18 @@ define(function (require, exports, module) { }; /** - * Rebuilds the list items for the hint list. + * Appends text to end of pending text. * + * @param {string} text */ CodeHintList.prototype.addPendingText = function (text) { this.pendingText += text; }; /** - * Rebuilds the list items for the hint list. + * Removes text from beginning of pending text. * + * @param {string} text */ CodeHintList.prototype.removePendingText = function (text) { if (this.pendingText.indexOf(text) === 0) { diff --git a/src/editor/CodeHintManager.js b/src/editor/CodeHintManager.js index 8e91bb22281..911122abcce 100644 --- a/src/editor/CodeHintManager.js +++ b/src/editor/CodeHintManager.js @@ -177,7 +177,7 @@ * hints: Array., * match: string, * selectInitial: boolean, - * handleWideReuslts: boolean, + * handleWideResults: boolean, * query: string}} * * Null if the provider wishes to end the hinting session. Otherwise, a diff --git a/src/extensions/default/CSSCodeHints/main.js b/src/extensions/default/CSSCodeHints/main.js index 5d17e82008e..0add017971d 100644 --- a/src/extensions/default/CSSCodeHints/main.js +++ b/src/extensions/default/CSSCodeHints/main.js @@ -185,7 +185,7 @@ define(function (require, exports, module) { * hints: Array., * match: string, * selectInitial: boolean, - * handleWideReuslts: boolean, + * handleWideResults: boolean, * query: string}} * Null if the provider wishes to end the hinting session. Otherwise, a * response object that provides: @@ -259,7 +259,9 @@ define(function (require, exports, module) { return { hints: result, match: valueNeedle, - selectInitial: selectInitial + selectInitial: selectInitial, + handleWideResults: false, + query: valueNeedle }; } else if (context === CSSUtils.PROP_NAME) { lastContext = CSSUtils.PROP_NAME; @@ -275,7 +277,7 @@ define(function (require, exports, module) { match: needle, selectInitial: selectInitial, handleWideResults: false, - query: valueNeedle + query: needle }; } return null; diff --git a/src/extensions/default/HTMLCodeHints/main.js b/src/extensions/default/HTMLCodeHints/main.js index dad115ab23c..d78b9e1b232 100644 --- a/src/extensions/default/HTMLCodeHints/main.js +++ b/src/extensions/default/HTMLCodeHints/main.js @@ -109,7 +109,7 @@ define(function (require, exports, module) { * hints: Array., * match: string, * selectInitial: boolean, - * handleWideReuslts: boolean, + * handleWideResults: boolean, * query: string}} * Null if the provider wishes to end the hinting session. Otherwise, a * response object that provides: @@ -368,14 +368,22 @@ define(function (require, exports, module) { * Returns a list of availble HTML attribute hints if possible for the * current editor context. * - * @return {{hints: Array., match: string, - * selectInitial: boolean}} + * @return {jQuery.Deferred|{ + * hints: Array., + * match: string, + * selectInitial: boolean, + * handleWideResults: boolean, + * query: string}} * Null if the provider wishes to end the hinting session. Otherwise, a - * response object that provides 1. a sorted array hints that consists - * of strings; 2. a string match that is used by the manager to emphasize - * matching substrings when rendering the hint list; and 3. a boolean that - * indicates whether the first result, if one exists, should be selected - * by default in the hint list window. + * response object that provides: + * 1. a sorted array hints that consists of strings + * 2. a string match that is used by the manager to emphasize matching + * substrings when rendering the hint list + * 3. a boolean that indicates whether the first result, if one exists, + * should be selected by default in the hint list window. + * 4. a boolean (or undefined) that indicates whether to allow result + * string to stretch width of display. + * 5. a query string that list is filtered on */ AttrHints.prototype.getHints = function (implicitChar) { var cursor = this.editor.getCursorPos(), @@ -440,12 +448,20 @@ define(function (require, exports, module) { return { hints: result, match: query.queryStr, - selectInitial: true + selectInitial: true, + handleWideResults: false, + query: query.queryStr }; } else if (hints instanceof Object && hints.hasOwnProperty("done")) { // Deferred hints var deferred = $.Deferred(); hints.done(function (asyncHints) { - deferred.resolveWith(this, [{ hints : asyncHints, match: query.queryStr, selectInitial: true }]); + deferred.resolveWith(this, [{ + hints: asyncHints, + match: query.queryStr, + selectInitial: true, + handleWideResults: false, + query: query.queryStr + }]); }); return deferred; } else { diff --git a/src/extensions/default/HtmlEntityCodeHints/main.js b/src/extensions/default/HtmlEntityCodeHints/main.js index 1e31093cefe..a40768e9bae 100644 --- a/src/extensions/default/HtmlEntityCodeHints/main.js +++ b/src/extensions/default/HtmlEntityCodeHints/main.js @@ -106,7 +106,7 @@ define(function (require, exports, module) { * hints: Array., * match: string, * selectInitial: boolean, - * handleWideReuslts: boolean, + * handleWideResults: boolean, * query: string}} * Null if the provider wishes to end the hinting session. Otherwise, a * response object that provides: diff --git a/src/extensions/default/JavaScriptCodeHints/main.js b/src/extensions/default/JavaScriptCodeHints/main.js index 000f3f07533..dd153d4b8b3 100644 --- a/src/extensions/default/JavaScriptCodeHints/main.js +++ b/src/extensions/default/JavaScriptCodeHints/main.js @@ -89,7 +89,7 @@ define(function (require, exports, module) { * hints: Array., * match: string, * selectInitial: boolean, - * handleWideReuslts: boolean, + * handleWideResults: boolean, * query: string}} */ function formatHints(hints, query) { diff --git a/src/extensions/default/UrlCodeHints/main.js b/src/extensions/default/UrlCodeHints/main.js index d173e9e543f..cf6066d4786 100644 --- a/src/extensions/default/UrlCodeHints/main.js +++ b/src/extensions/default/UrlCodeHints/main.js @@ -369,7 +369,7 @@ define(function (require, exports, module) { * hints: Array., * match: string, * selectInitial: boolean, - * handleWideReuslts: boolean, + * handleWideResults: boolean, * query: string}} * Null if the provider wishes to end the hinting session. Otherwise, a * response object that provides @@ -485,7 +485,7 @@ define(function (require, exports, module) { match: query.queryStr, selectInitial: true, handleWideResults: false, - query: query + query: query.queryStr }]); }); From 1032262a40c75d725c2f601b0e647f0ae4cd1409 Mon Sep 17 00:00:00 2001 From: Jason San Jose Date: Tue, 17 Sep 2013 15:21:48 -0700 Subject: [PATCH 15/56] fix test-integration task on linux --- Gruntfile.js | 3 ++- tasks/lib/common.js | 3 ++- tasks/test.js | 6 +++--- tasks/write-config.js | 2 +- test/spec/NativeMenu-test.js | 6 ++++-- 5 files changed, 12 insertions(+), 8 deletions(-) diff --git a/Gruntfile.js b/Gruntfile.js index bd039aeb0ca..f1165bc424f 100644 --- a/Gruntfile.js +++ b/Gruntfile.js @@ -142,7 +142,8 @@ module.exports = function (grunt) { shell: { repo: grunt.option("shell-repo") || "../brackets-shell", mac: "<%= shell.repo %>/installer/mac/staging/<%= pkg.name %>.app", - win: "<%= shell.repo %>/installer/win/staging/<%= pkg.name %>.exe" + win: "<%= shell.repo %>/installer/win/staging/<%= pkg.name %>.exe", + linux: "<%= shell.repo %>/installer/linux/debian/package-root/opt/brackets/brackets" } }); diff --git a/tasks/lib/common.js b/tasks/lib/common.js index 6fb3f61ec28..76dbd466f83 100644 --- a/tasks/lib/common.js +++ b/tasks/lib/common.js @@ -20,7 +20,8 @@ * DEALINGS IN THE SOFTWARE. * */ - /*global module, require, process*/ +/*jslint nomen:true */ +/*global module, require, process */ module.exports = function (grunt) { "use strict"; diff --git a/tasks/test.js b/tasks/test.js index e3e03170213..73470fc992a 100644 --- a/tasks/test.js +++ b/tasks/test.js @@ -43,10 +43,10 @@ module.exports = function (grunt) { specRunnerPath = common.resolve("test/SpecRunner.html"), args = " --startup-path=\"" + specRunnerPath + "?suite=" + encodeURIComponent(suite) + "&spec=" + encodeURIComponent(spec) + "&resultsPath=" + encodeURIComponent(resultsPath) + "\""; - if (platform === "win") { - cmd += args; - } else if (platform === "mac") { + if (platform === "mac") { cmd = "open \"" + cmd + "\" -W --args " + args; + } else { + cmd += args; } grunt.log.writeln(cmd); diff --git a/tasks/write-config.js b/tasks/write-config.js index 05c165d38d3..bd847a132aa 100644 --- a/tasks/write-config.js +++ b/tasks/write-config.js @@ -20,7 +20,7 @@ * DEALINGS IN THE SOFTWARE. * */ - /*global module, require*/ +/*global module, require*/ module.exports = function (grunt) { "use strict"; diff --git a/test/spec/NativeMenu-test.js b/test/spec/NativeMenu-test.js index ec9277aff7a..19801522dcd 100644 --- a/test/spec/NativeMenu-test.js +++ b/test/spec/NativeMenu-test.js @@ -28,8 +28,10 @@ define(function (require, exports, module) { 'use strict'; - // Don't run tests when running in browser - if (brackets.inBrowser) { + require("utils/Global"); + + // Don't run tests when running in browser or linux + if (brackets.inBrowser || brackets.platform === "linux") { return; } From bc4cd131707a23a87e2a13bdbe5578bbd403cbcf Mon Sep 17 00:00:00 2001 From: Marcel Gerber Date: Sat, 21 Sep 2013 20:14:38 +0200 Subject: [PATCH 16/56] Update strings.js --- src/nls/de/strings.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/nls/de/strings.js b/src/nls/de/strings.js index 791f2854024..21220275d67 100644 --- a/src/nls/de/strings.js +++ b/src/nls/de/strings.js @@ -60,7 +60,7 @@ define({ "ERROR_DELETING_FILE" : "Beim Löschen der Datei {0} ist ein Fehler aufgetreten. {1}", "INVALID_FILENAME_TITLE" : "Ungültiger {0}name", "INVALID_FILENAME_MESSAGE" : "Dateinamen dürfen folgende Zeichen nicht enthalten: /?*:;{}<>\\| Auch dürfen keine vom System reservierten Wörter vorkommen.", - "FILE_ALREADY_EXISTS" : "{0} {0} existiert bereits.", // TODO: depends on {0} gender + "FILE_ALREADY_EXISTS" : "{0} {1} existiert bereits.", // TODO: depends on {0} gender "ERROR_CREATING_FILE_TITLE" : "Fehler beim Erstellen von {0}", // TODO: depends on {0} gender "ERROR_CREATING_FILE" : "Beim Erstellen von {0} {1} ist ein Fehler aufgetreten: {2}", // TODO: depends on {0} gender From 3f3712c729266d536b0f32129248c88187799c7d Mon Sep 17 00:00:00 2001 From: Lance Campbell Date: Sun, 22 Sep 2013 09:18:34 -0700 Subject: [PATCH 17/56] Split menu specs into HTML and Native. Add HTML and Native versions of createTestWindowAndRun. --- test/spec/Menu-test.js | 40 ++++++++++++++++++++++++++++-------- test/spec/SpecRunnerUtils.js | 22 +++++++++++++++++--- 2 files changed, 51 insertions(+), 11 deletions(-) diff --git a/test/spec/Menu-test.js b/test/spec/Menu-test.js index 178fb4b94ff..780ed23dcef 100644 --- a/test/spec/Menu-test.js +++ b/test/spec/Menu-test.js @@ -36,17 +36,15 @@ define(function (require, exports, module) { KeyEvent = require("utils/KeyEvent"); - describe("Menus", function () { + describe("Menus (Native Shell)", function () { this.category = "integration"; var testWindow; beforeFirst(function () { - // Create a new window that will be shared by ALL tests in this spec. (We need the tests to - // run in a real Brackets window since HTMLCodeHints requires various core modules (it can't - // run 100% in isolation), but popping a new window per testcase is unneeded overhead). - SpecRunnerUtils.createTestWindowAndRun(this, function (w) { + // Create a new native menu window that will be shared by ALL tests in this spec. + SpecRunnerUtils.createNativeTestWindowAndRun(this, function (w) { testWindow = w; // Load module instances from brackets.test @@ -210,11 +208,37 @@ define(function (require, exports, module) { expect($menus.length).toBe(0); }); }); + }); - if (!brackets.inBrowser) { - return; - } + + describe("Menus (HTML)", function () { + + this.category = "integration"; + var testWindow; + + beforeFirst(function () { + // Create a new HTML menu window that will be shared by ALL tests in this spec. + SpecRunnerUtils.createHTMLTestWindowAndRun(this, function (w) { + testWindow = w; + + // Load module instances from brackets.test + CommandManager = testWindow.brackets.test.CommandManager; + Commands = testWindow.brackets.test.Commands; + KeyBindingManager = testWindow.brackets.test.KeyBindingManager; + Menus = testWindow.brackets.test.Menus; + }); + }); + + afterLast(function () { + testWindow = null; + CommandManager = null; + Commands = null; + KeyBindingManager = null; + Menus = null; + SpecRunnerUtils.closeTestWindow(); + }); + describe("Add Menus", function () { function getTopMenus() { diff --git a/test/spec/SpecRunnerUtils.js b/test/spec/SpecRunnerUtils.js index 8a234648627..3b2362dcba5 100644 --- a/test/spec/SpecRunnerUtils.js +++ b/test/spec/SpecRunnerUtils.js @@ -476,8 +476,7 @@ define(function (require, exports, module) { waitsForDone(promise, "dismiss dialog"); } - - function createTestWindowAndRun(spec, callback) { + function _createTestWindowAndRun(spec, hasNativeMenus, callback) { runs(function () { // Position popup windows in the lower right so they're out of the way var testWindowWid = 1000, @@ -503,6 +502,9 @@ define(function (require, exports, module) { // disable initial dialog for live development params.put("skipLiveDevelopmentInfo", true); + // determines if test window should have native or html menus + params.put("hasNativeMenus", hasNativeMenus); + _testWindow = window.open(getBracketsSourceRoot() + "/index.html?" + params.toString(), "_blank", optionsStr); _testWindow.isBracketsTestWindow = true; @@ -524,7 +526,7 @@ define(function (require, exports, module) { }); }; }); - + // FIXME (issue #249): Need an event or something a little more reliable... waitsFor( function isBracketsDoneLoading() { @@ -540,6 +542,18 @@ define(function (require, exports, module) { }); } + function createTestWindowAndRun(spec, callback) { + _createTestWindowAndRun(spec, brackets.nativeMenus, callback); + } + + function createHTMLTestWindowAndRun(spec, callback) { + _createTestWindowAndRun(spec, false, callback); + } + + function createNativeTestWindowAndRun(spec, callback) { + _createTestWindowAndRun(spec, true, callback); + } + function closeTestWindow() { // debug-only to see testWindow state before closing // waits(500); @@ -1268,6 +1282,8 @@ define(function (require, exports, module) { exports.createMockEditorForDocument = createMockEditorForDocument; exports.createMockEditor = createMockEditor; exports.createTestWindowAndRun = createTestWindowAndRun; + exports.createHTMLTestWindowAndRun = createHTMLTestWindowAndRun; + exports.createNativeTestWindowAndRun = createNativeTestWindowAndRun; exports.closeTestWindow = closeTestWindow; exports.clickDialogButton = clickDialogButton; exports.destroyMockEditor = destroyMockEditor; From 1db93ab989a6b7babf377752e016b86d42c432fd Mon Sep 17 00:00:00 2001 From: Lance Campbell Date: Sun, 22 Sep 2013 17:42:18 -0700 Subject: [PATCH 18/56] Set brackets.nativeMenus based on hasNativeMenus URL parameter. --- src/utils/Global.js | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/src/utils/Global.js b/src/utils/Global.js index 56ab38524fb..9116301d4eb 100644 --- a/src/utils/Global.js +++ b/src/utils/Global.js @@ -34,7 +34,13 @@ define(function (require, exports, module) { "use strict"; - var configJSON = require("text!config.json"); + var configJSON = require("text!config.json"), + UrlParams = require("utils/UrlParams").UrlParams; + + var params = new UrlParams(); + + // read URL params + params.parse(); // Define core brackets namespace if it isn't already defined // @@ -77,7 +83,11 @@ define(function (require, exports, module) { global.brackets.inBrowser = !global.brackets.hasOwnProperty("fs"); - global.brackets.nativeMenus = (!global.brackets.inBrowser && (global.brackets.platform !== "linux")); + if (params.get("hasNativeMenus") !== undefined) { + global.brackets.nativeMenus = (params.get("hasNativeMenus") === "true"); + } else { + global.brackets.nativeMenus = (!global.brackets.inBrowser && (global.brackets.platform !== "linux")); + } global.brackets.isLocaleDefault = function () { return !global.localStorage.getItem("locale"); From 789649f07e5f75782ec7e32a869a75f377e29788 Mon Sep 17 00:00:00 2001 From: Peter Flynn Date: Mon, 23 Sep 2013 13:11:02 -0700 Subject: [PATCH 19/56] Performance improvements for Find, focused on the initial keystroke or two when the number of results is usually very high: - Batch tickmark creation (saves 120ms in med-size files like FindReplace) - Cut off tickmark & inline highlighting when tons of search results found (saves ~1 sec in huge files like codemirror.js) --- src/search/FindReplace.js | 43 ++++++++++++++++++-------------- src/search/ScrollTrackMarkers.js | 43 ++++++++++++++++++++++---------- 2 files changed, 54 insertions(+), 32 deletions(-) diff --git a/src/search/FindReplace.js b/src/search/FindReplace.js index 89f88d3a799..1fc59e825c1 100644 --- a/src/search/FindReplace.js +++ b/src/search/FindReplace.js @@ -152,6 +152,7 @@ define(function (require, exports, module) { }); }); state.marked.length = 0; + ScrollTrackMarkers.clear(); } @@ -206,13 +207,6 @@ define(function (require, exports, module) { ScrollTrackMarkers.setVisible(editor, enabled); } - - function addHighlight(editor, state, cursor) { - var cm = editor._codeMirror; - state.marked.push(cm.markText(cursor.from(), cursor.to(), { className: "CodeMirror-searching" })); - - ScrollTrackMarkers.addTickmark(editor, cursor.from()); - } /** * If no search pending, opens the search dialog. If search is already open, moves to @@ -264,19 +258,16 @@ define(function (require, exports, module) { //Flag that controls the navigation controls. var enableNavigator = false; - // Highlight all matches + // Find all matches // (Except on huge documents, where this is too expensive) + var resultSet = []; if (cm.getValue().length < 500000) { - toggleHighlighting(editor, true); - // FUTURE: if last query was prefix of this one, could optimize by filtering existing result set - var resultCount = 0; var cursor = getSearchCursor(cm, state.query); while (cursor.findNext()) { - addHighlight(editor, state, cursor); - resultCount++; - - //Remove this section when https://github.com/marijnh/CodeMirror/issues/1155 will be fixed + resultSet.push(cursor.pos); // pos is unique obj per search result + + // TODO: remove this section when https://github.com/marijnh/CodeMirror/issues/1155 is fixed if (cursor.pos.match && cursor.pos.match[0] === "") { if (cursor.to().line + 1 === cm.lineCount()) { break; @@ -284,13 +275,27 @@ define(function (require, exports, module) { cursor = getSearchCursor(cm, state.query, {line: cursor.to().line + 1, ch: 0}); } } - - if (resultCount === 0) { + + // Highlight all matches if there aren't too many + if (resultSet.length <= 2000) { + toggleHighlighting(editor, true); + + resultSet.forEach(function (result) { + state.marked.push(cm.markText(result.from, result.to, { className: "CodeMirror-searching" })); + }); + var scrollTrackPositions = resultSet.map(function (result) { + return result.from; + }); + + ScrollTrackMarkers.addTickmarks(editor, scrollTrackPositions); + } + + if (resultSet.length === 0) { $("#find-counter").text(Strings.FIND_NO_RESULTS); - } else if (resultCount === 1) { + } else if (resultSet.length === 1) { $("#find-counter").text(Strings.FIND_RESULT_COUNT_SINGLE); } else { - $("#find-counter").text(StringUtils.format(Strings.FIND_RESULT_COUNT, resultCount)); + $("#find-counter").text(StringUtils.format(Strings.FIND_RESULT_COUNT, resultSet.length)); enableNavigator = true; } diff --git a/src/search/ScrollTrackMarkers.js b/src/search/ScrollTrackMarkers.js index 6e742236b39..7d4cd71ab4a 100644 --- a/src/search/ScrollTrackMarkers.js +++ b/src/search/ScrollTrackMarkers.js @@ -78,14 +78,16 @@ define(function (require, exports, module) { trackHt -= trackOffset * 2; } - /** Add one tickmark to the DOM */ - function _renderMark(pos) { - var top = Math.round(pos.line / editor.lineCount() * trackHt) + trackOffset; - top--; // subtract ~1/2 the ht of a tickmark to center it on ideal pos - - var $mark = $("
"); - - $(".tickmark-track", editor.getRootElement()).append($mark); + /** Add all the given tickmarks to the DOM in a batch */ + function _renderMarks(posArray) { + var html = ""; + posArray.forEach(function (pos) { + var top = Math.round(pos.line / editor.lineCount() * trackHt) + trackOffset; + top--; // subtract ~1/2 the ht of a tickmark to center it on ideal pos + + html += "
"; + }); + $(".tickmark-track", editor.getRootElement()).append($(html)); } @@ -128,9 +130,7 @@ define(function (require, exports, module) { if (marks.length) { _calcScaling(); $(".tickmark-track", editor.getRootElement()).empty(); - marks.forEach(function (pos) { - _renderMark(pos); - }); + _renderMarks(marks); } })); @@ -143,16 +143,33 @@ define(function (require, exports, module) { } } - /** Add a tickmark to the editor's tickmark track, if it's visible */ + /** + * Add a tickmark to the editor's tickmark track, if it's visible + * @param curEditor {!Editor} + * @param pos {!{line:Number, ch:Number}} + */ function addTickmark(curEditor, pos) { console.assert(editor === curEditor); marks.push(pos); - _renderMark(pos); + _renderMarks([pos]); + } + + /** + * Add tickmarks to the editor's tickmark track, if it's visible + * @param curEditor {!Editor} + * @param posArray {!Array.<{line:Number, ch:Number}>} + */ + function addTickmarks(curEditor, posArray) { + console.assert(editor === curEditor); + + marks = marks.concat(posArray); + _renderMarks(posArray); } exports.clear = clear; exports.setVisible = setVisible; exports.addTickmark = addTickmark; + exports.addTickmarks = addTickmarks; }); From 2dc9d8251e5759a9bad68c8eb19d468a1added1e Mon Sep 17 00:00:00 2001 From: Narciso Jaramillo Date: Mon, 23 Sep 2013 15:52:01 -0700 Subject: [PATCH 20/56] Fix hrefs in Czech translation --- src/nls/cs/strings.js | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/nls/cs/strings.js b/src/nls/cs/strings.js index b4c404da637..b7469b8cd4a 100644 --- a/src/nls/cs/strings.js +++ b/src/nls/cs/strings.js @@ -86,7 +86,7 @@ define({ "LIVE_DEV_SERVER_NOT_READY_MESSAGE" : "Chyba při spouštění HTTP serveru pro soubory živého náhledu. Prosím, zkuste to znovu.", "LIVE_DEVELOPMENT_INFO_TITLE" : "Vítejte v živém náhledu!", "LIVE_DEVELOPMENT_INFO_MESSAGE" : "Živý náhled připojí {APP_NAME} k vašemu prohlížeči. Spustí náhled HTML souboru, který se aktualizuje pokaždé, kdy editujete svůj kód.

V této verzi {APP_NAME}, živý náhled funguje pouze v Google Chrome a aktualizuje změny v CSS souborech. Změny v HTML nebo JavaScript souborech jsou automaticky načteny, když soubor uložíte.

(Tato zpráva se zobrazí pouze jednou.)", - "LIVE_DEVELOPMENT_TROUBLESHOOTING" : "Pro více informací navštivte Troubleshooting Live Development connection errors.", + "LIVE_DEVELOPMENT_TROUBLESHOOTING" : "Pro více informací navštivte Troubleshooting Live Development connection errors.", "LIVE_DEV_STATUS_TIP_NOT_CONNECTED" : "Živý náhled", "LIVE_DEV_STATUS_TIP_PROGRESS1" : "Živý náhled: Připojování\u2026", @@ -301,11 +301,11 @@ define({ "ABOUT" : "O aplikaci", "CLOSE" : "Zavřít", "ABOUT_TEXT_LINE1" : "sprint {VERSION_MINOR} {BUILD_TYPE} {VERSION}", - "ABOUT_TEXT_LINE3" : "Oznámení, podmínky týkající se software třetích stran jsou umístěny na http://www.adobe.com/go/thirdparty/ a začleněny prostřednictvím odkazu zde.", - "ABOUT_TEXT_LINE4" : "Dokumentace a zdrojový kód na https://github.com/adobe/brackets/.", + "ABOUT_TEXT_LINE3" : "Oznámení, podmínky týkající se software třetích stran jsou umístěny na {ADOBE_THIRD_PARTY} a začleněny prostřednictvím odkazu zde.", + "ABOUT_TEXT_LINE4" : "Dokumentace a zdrojový kód na https://github.com/adobe/brackets/.", "ABOUT_TEXT_LINE5" : "Vytvořeno s \u2764 a pomocí JavaScript těmito lidmi:", "ABOUT_TEXT_LINE6" : "Mnoho lidí (ale momentálně máme problém s načítáním dat).", - "ABOUT_TEXT_WEB_PLATFORM_DOCS" : "Web Platform Docs a Web Platform logo využívají licenci Creative Commons Attribution, CC-BY 3.0 Unported.", + "ABOUT_TEXT_WEB_PLATFORM_DOCS" : "Web Platform Docs a Web Platform logo využívají licenci Creative Commons Attribution, CC-BY 3.0 Unported.", "UPDATE_NOTIFICATION_TOOLTIP" : "Je dostupná nová verze {APP_NAME} ! Klikněte zde pro více informací.", "UPDATE_AVAILABLE_TITLE" : "Dostupná aktualizace", "UPDATE_MESSAGE" : "Nová verze {APP_NAME} je dostupná. Seznam některých vylepšení:", From 88c77e191df492bcf86e032fbab467d94e01c71c Mon Sep 17 00:00:00 2001 From: Clay Miller Date: Mon, 23 Sep 2013 22:56:27 -0500 Subject: [PATCH 21/56] Apply HTML sytax highlighting to ASP.NET MVC View Master Page (.master) files. --- src/language/languages.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/language/languages.json b/src/language/languages.json index 9ab2d31e596..a78bee17185 100644 --- a/src/language/languages.json +++ b/src/language/languages.json @@ -36,7 +36,7 @@ "html": { "name": "HTML", "mode": ["htmlmixed", "text/x-brackets-html"], - "fileExtensions": ["html", "htm", "shtm", "shtml", "xhtml", "cfm", "cfml", "cfc", "dhtml", "xht", "tpl", "twig", "hbs", "handlebars", "kit", "jsp", "aspx", "asp"], + "fileExtensions": ["html", "htm", "shtm", "shtml", "xhtml", "cfm", "cfml", "cfc", "dhtml", "xht", "tpl", "twig", "hbs", "handlebars", "kit", "jsp", "aspx", "asp", "master"], "blockComment": [""] }, From b55096486707ffabf772dc9fe938f498651ea493 Mon Sep 17 00:00:00 2001 From: Kevin Dangoor Date: Tue, 24 Sep 2013 17:50:26 -0400 Subject: [PATCH 22/56] Fix in decompress-zip to support proper directory creation on Windows. --- .../node/node_modules/decompress-zip/lib/extractors.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/extensibility/node/node_modules/decompress-zip/lib/extractors.js b/src/extensibility/node/node_modules/decompress-zip/lib/extractors.js index dfe6887d49e..f3061b58af3 100644 --- a/src/extensibility/node/node_modules/decompress-zip/lib/extractors.js +++ b/src/extensibility/node/node_modules/decompress-zip/lib/extractors.js @@ -13,13 +13,14 @@ var cache = {}; // Use a cache of promises for building the directory tree. This allows us to // correctly queue up file extractions for after their path has been created, // avoid trying to create the path twice and still be async. +var windowsRoot = /^[A-Z]:\\$/; var mkdir = function (dir) { dir = path.normalize(path.resolve(process.cwd(), dir) + path.sep); if (!cache[dir]) { var parent; - if (dir === '/') { + if (dir === '/' || (process.platform === "win32" && dir.match(windowsRoot))) { parent = new Q(); } else { parent = mkdir(path.dirname(dir)); From 55133a850be41846cae1bb57e0e3f890a00e70e3 Mon Sep 17 00:00:00 2001 From: Randy Edmunds Date: Tue, 24 Sep 2013 15:28:45 -0700 Subject: [PATCH 23/56] clear highlights and Find selection color when modal bar closes --- src/search/FindReplace.js | 2 +- src/widgets/ModalBar.js | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/src/search/FindReplace.js b/src/search/FindReplace.js index 89f88d3a799..d6fa88ea725 100644 --- a/src/search/FindReplace.js +++ b/src/search/FindReplace.js @@ -329,7 +329,7 @@ define(function (require, exports, module) { findFirst(query); } }); - $(modalBar).on("closeOk closeCancel closeBlur", function (e, query) { + $(modalBar).on("closeOk closeCancel closeBlur close", function (e, query) { // Clear highlights but leave search state in place so Find Next/Previous work after closing clearHighlights(cm, state); diff --git a/src/widgets/ModalBar.js b/src/widgets/ModalBar.js index 63b8c08d707..c27fa5aacbc 100644 --- a/src/widgets/ModalBar.js +++ b/src/widgets/ModalBar.js @@ -159,6 +159,8 @@ define(function (require, exports, module) { if (this._autoClose) { window.document.body.removeEventListener("focusin", this._handleFocusChange, true); } + + $(this).triggerHandler("close"); if (animate) { AnimationUtils.animateUsingClass(this._$root.get(0), "modal-bar-hide") From 44f00ea9a65e63491292d1e06388ccbf83256944 Mon Sep 17 00:00:00 2001 From: Kevin Dangoor Date: Tue, 24 Sep 2013 18:31:29 -0700 Subject: [PATCH 24/56] Add console logging for unknown error. --- src/extensibility/Package.js | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/extensibility/Package.js b/src/extensibility/Package.js index 796b2192555..ea2726e71ab 100644 --- a/src/extensibility/Package.js +++ b/src/extensibility/Package.js @@ -364,7 +364,11 @@ define(function (require, exports, module) { */ function formatError(error) { function localize(key) { - return Strings[key] || Strings.UNKNOWN_ERROR; + if (Strings[key]) { + return Strings[key]; + } + console.log("Unknown installation error", key); + return Strings.UNKNOWN_ERROR; } if (Array.isArray(error)) { From 58aebd21e99b8343f1e2cdfad3f98ea65fc1f36b Mon Sep 17 00:00:00 2001 From: Kevin Dangoor Date: Tue, 24 Sep 2013 22:13:48 -0400 Subject: [PATCH 25/56] Change from "tmp" to "temp" for temporary stream creation --- .../node/node_modules/temp/.npmignore | 7 + .../node_modules/{tmp => temp}/.travis.yml | 5 +- .../node/node_modules/temp/LICENSE | 20 + .../node/node_modules/temp/README.md | 277 +++++++++++ .../node_modules/temp/examples/grepcount.js | 18 + .../node_modules/temp/examples/pdfcreator.js | 22 + .../node/node_modules/temp/lib/temp.js | 182 ++++++++ .../temp/node_modules/osenv/LICENSE | 25 + .../temp/node_modules/osenv/README.md | 63 +++ .../temp/node_modules/osenv/osenv.js | 80 ++++ .../temp/node_modules/osenv/package.json | 42 ++ .../temp/node_modules/osenv/test/unix.js | 76 +++ .../temp/node_modules/osenv/test/windows.js | 82 ++++ .../temp/node_modules/rimraf/AUTHORS | 6 + .../temp/node_modules/rimraf/LICENSE | 23 + .../temp/node_modules/rimraf/README.md | 21 + .../node_modules/graceful-fs}/.npmignore | 0 .../rimraf/node_modules/graceful-fs/LICENSE | 27 ++ .../rimraf/node_modules/graceful-fs/README.md | 33 ++ .../node_modules/graceful-fs/graceful-fs.js | 442 ++++++++++++++++++ .../node_modules/graceful-fs/package.json | 48 ++ .../node_modules/graceful-fs/test/open.js | 46 ++ .../node_modules/graceful-fs/test/ulimit.js | 158 +++++++ .../temp/node_modules/rimraf/package.json | 58 +++ .../temp/node_modules/rimraf/rimraf.js | 132 ++++++ .../temp/node_modules/rimraf/test/run.sh | 10 + .../temp/node_modules/rimraf/test/setup.sh | 47 ++ .../node_modules/rimraf/test/test-async.js | 5 + .../node_modules/rimraf/test/test-sync.js | 3 + .../node/node_modules/temp/package.json | 48 ++ .../node/node_modules/temp/test/temp-test.js | 77 +++ .../node/node_modules/tmp/README.md | 162 ------- .../node/node_modules/tmp/lib/tmp.js | 273 ----------- .../node/node_modules/tmp/package.json | 52 --- .../node/node_modules/tmp/test-all.sh | 6 - .../node/node_modules/tmp/test.js | 6 - .../node/node_modules/tmp/test/base.js | 74 --- .../node/node_modules/tmp/test/dir-test.js | 183 -------- .../node/node_modules/tmp/test/file-test.js | 165 ------- .../node/node_modules/tmp/test/graceful.js | 15 - .../node/node_modules/tmp/test/keep.js | 11 - .../node/node_modules/tmp/test/name-test.js | 82 ---- .../node/node_modules/tmp/test/spawn.js | 32 -- .../node_modules/tmp/test/symlinkme/file.js | 0 .../node/node_modules/tmp/test/unsafe.js | 30 -- src/extensibility/node/package.json | 28 +- 46 files changed, 2095 insertions(+), 1107 deletions(-) create mode 100644 src/extensibility/node/node_modules/temp/.npmignore rename src/extensibility/node/node_modules/{tmp => temp}/.travis.yml (70%) create mode 100644 src/extensibility/node/node_modules/temp/LICENSE create mode 100644 src/extensibility/node/node_modules/temp/README.md create mode 100644 src/extensibility/node/node_modules/temp/examples/grepcount.js create mode 100644 src/extensibility/node/node_modules/temp/examples/pdfcreator.js create mode 100644 src/extensibility/node/node_modules/temp/lib/temp.js create mode 100644 src/extensibility/node/node_modules/temp/node_modules/osenv/LICENSE create mode 100644 src/extensibility/node/node_modules/temp/node_modules/osenv/README.md create mode 100644 src/extensibility/node/node_modules/temp/node_modules/osenv/osenv.js create mode 100644 src/extensibility/node/node_modules/temp/node_modules/osenv/package.json create mode 100644 src/extensibility/node/node_modules/temp/node_modules/osenv/test/unix.js create mode 100644 src/extensibility/node/node_modules/temp/node_modules/osenv/test/windows.js create mode 100644 src/extensibility/node/node_modules/temp/node_modules/rimraf/AUTHORS create mode 100644 src/extensibility/node/node_modules/temp/node_modules/rimraf/LICENSE create mode 100644 src/extensibility/node/node_modules/temp/node_modules/rimraf/README.md rename src/extensibility/node/node_modules/{tmp => temp/node_modules/rimraf/node_modules/graceful-fs}/.npmignore (100%) create mode 100644 src/extensibility/node/node_modules/temp/node_modules/rimraf/node_modules/graceful-fs/LICENSE create mode 100644 src/extensibility/node/node_modules/temp/node_modules/rimraf/node_modules/graceful-fs/README.md create mode 100644 src/extensibility/node/node_modules/temp/node_modules/rimraf/node_modules/graceful-fs/graceful-fs.js create mode 100644 src/extensibility/node/node_modules/temp/node_modules/rimraf/node_modules/graceful-fs/package.json create mode 100644 src/extensibility/node/node_modules/temp/node_modules/rimraf/node_modules/graceful-fs/test/open.js create mode 100644 src/extensibility/node/node_modules/temp/node_modules/rimraf/node_modules/graceful-fs/test/ulimit.js create mode 100644 src/extensibility/node/node_modules/temp/node_modules/rimraf/package.json create mode 100644 src/extensibility/node/node_modules/temp/node_modules/rimraf/rimraf.js create mode 100644 src/extensibility/node/node_modules/temp/node_modules/rimraf/test/run.sh create mode 100644 src/extensibility/node/node_modules/temp/node_modules/rimraf/test/setup.sh create mode 100644 src/extensibility/node/node_modules/temp/node_modules/rimraf/test/test-async.js create mode 100644 src/extensibility/node/node_modules/temp/node_modules/rimraf/test/test-sync.js create mode 100644 src/extensibility/node/node_modules/temp/package.json create mode 100644 src/extensibility/node/node_modules/temp/test/temp-test.js delete mode 100644 src/extensibility/node/node_modules/tmp/README.md delete mode 100644 src/extensibility/node/node_modules/tmp/lib/tmp.js delete mode 100644 src/extensibility/node/node_modules/tmp/package.json delete mode 100755 src/extensibility/node/node_modules/tmp/test-all.sh delete mode 100644 src/extensibility/node/node_modules/tmp/test.js delete mode 100644 src/extensibility/node/node_modules/tmp/test/base.js delete mode 100644 src/extensibility/node/node_modules/tmp/test/dir-test.js delete mode 100644 src/extensibility/node/node_modules/tmp/test/file-test.js delete mode 100644 src/extensibility/node/node_modules/tmp/test/graceful.js delete mode 100644 src/extensibility/node/node_modules/tmp/test/keep.js delete mode 100644 src/extensibility/node/node_modules/tmp/test/name-test.js delete mode 100644 src/extensibility/node/node_modules/tmp/test/spawn.js delete mode 100644 src/extensibility/node/node_modules/tmp/test/symlinkme/file.js delete mode 100644 src/extensibility/node/node_modules/tmp/test/unsafe.js diff --git a/src/extensibility/node/node_modules/temp/.npmignore b/src/extensibility/node/node_modules/temp/.npmignore new file mode 100644 index 00000000000..05936003261 --- /dev/null +++ b/src/extensibility/node/node_modules/temp/.npmignore @@ -0,0 +1,7 @@ +.DS_Store +.\#* +/node_modules +\#* +npm-debug.log +node_modules +*.tgz diff --git a/src/extensibility/node/node_modules/tmp/.travis.yml b/src/extensibility/node/node_modules/temp/.travis.yml similarity index 70% rename from src/extensibility/node/node_modules/tmp/.travis.yml rename to src/extensibility/node/node_modules/temp/.travis.yml index 0175d82209d..ec4312514d8 100644 --- a/src/extensibility/node/node_modules/tmp/.travis.yml +++ b/src/extensibility/node/node_modules/temp/.travis.yml @@ -1,5 +1,6 @@ language: node_js node_js: - - "0.6" - - "0.8" + - "0.11" - "0.10" + - "0.8" + - "0.6" \ No newline at end of file diff --git a/src/extensibility/node/node_modules/temp/LICENSE b/src/extensibility/node/node_modules/temp/LICENSE new file mode 100644 index 00000000000..0146c4a3beb --- /dev/null +++ b/src/extensibility/node/node_modules/temp/LICENSE @@ -0,0 +1,20 @@ +Copyright (c) 2009 Bruce Williams + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/src/extensibility/node/node_modules/temp/README.md b/src/extensibility/node/node_modules/temp/README.md new file mode 100644 index 00000000000..d7fb9c3f98e --- /dev/null +++ b/src/extensibility/node/node_modules/temp/README.md @@ -0,0 +1,277 @@ +node-temp +========= + +Temporary files, directories, and streams for Node.js. + +Handles generating a unique file/directory name under the appropriate +system temporary directory, changing the file to an appropriate mode, +and supports automatic removal (if asked) + +`temp` has a similar API to the `fs` module. + +Node.js Compatibility +--------------------- + +Supports v0.6.0+. + +[![Build Status](https://travis-ci.org/bruce/node-temp.png)](https://travis-ci.org/bruce/node-temp) + +Please let me know if you have problems running it on a later version of Node.js or +have platform-specific problems. + +Installation +------------ + +Install it using [npm](http://github.com/isaacs/npm): + + $ npm install temp + +Or get it directly from: +http://github.com/bruce/node-temp + +Synopsis +-------- + +You can create temporary files with `open` and `openSync`, temporary +directories with `mkdir` and `mkdirSync`, or you can get a unique name +in the system temporary directory with `path`. + +Working copies of the following examples can be found under the +`examples` directory. + +### Temporary Files + +To create a temporary file use `open` or `openSync`, passing +them an optional prefix, suffix, or both (see below for details on +affixes). The object passed to the callback (or returned) has +`path` and `fd` keys: + +```javascript +{ path: "/path/to/file", +, fd: theFileDescriptor +} +``` + +In this example we write to a temporary file and call out to `grep` and +`wc -l` to determine the number of time `foo` occurs in the text. The +temporary file is chmod'd `0600` and cleaned up automatically when the +process at exit (because `temp.track()` is called): + +```javascript +var temp = require('temp'), + fs = require('fs'), + util = require('util'), + exec = require('child_process').exec; + +// Automatically track and cleanup files at exit +temp.track(); + +// Fake data +var myData = "foo\nbar\nfoo\nbaz"; + +// Process the data (note: error handling omitted) +temp.open('myprefix', function(err, info) { + fs.write(info.fd, myData); + fs.close(info.fd, function(err) { + exec("grep foo '" + info.path + "' | wc -l", function(err, stdout) { + util.puts(stdout.trim()); + }); + }); +}); +``` + +### Want Cleanup? Make sure you ask for it. + +As noted in the example above, if you want temp to track the files and directories +it creates and handle removing those files and directories on exit, you must call `track()`. +It's recommended that you do this immediately after requiring the module. + +```javascript +var temp = require("temp"); +temp.track(); +``` + +Why is this necessary? In pre-0.6 versions of temp, tracking was automatic. While this works +great for scripts and [Grunt tasks](http://gruntjs.com/), it's not so great for long-running +server processes. Since that's arguably what Node.js is _for_, you have to opt-in to tracking. + +But it's easy. + +#### Cleanup anytime + +When tracking, you can `cleanup()` anytime. An object will be returned with cleanup statistics +and the file/directory lists will be reset. + +```javascript +> temp.cleanup(); +{ files: { removed: 1, missing: 0 }, + dirs: { removed: 0, missing: 0 } } +``` + +Note: If you're not tracking, `false` will be returned. + +### Temporary Directories + +To create a temporary directory, use `mkdir` or `mkdirSync`, passing +it an optional prefix, suffix, or both (see below for details on affixes). + +In this example we create a temporary directory, write to a file +within it, call out to an external program to create a PDF, and read +the result. While the external process creates a lot of additional +files, the temporary directory is removed automatically at exit (because +`temp.track()` is called): + +```javascript +var temp = require('../lib/temp'), + fs = require('fs'), + util = require('util'), + path = require('path'), + exec = require('child_process').exec; + +// Automatically track and cleanup files at exit +temp.track(); + +// For use with ConTeXt, http://wiki.contextgarden.net +var myData = "\\starttext\nHello World\n\\stoptext"; + +temp.mkdir('pdfcreator', function(err, dirPath) { + var inputPath = path.join(dirPath, 'input.tex') + fs.writeFile(inputPath, myData, function(err) { + if (err) throw err; + process.chdir(dirPath); + exec("texexec '" + inputPath + "'", function(err) { + if (err) throw err; + fs.readFile(path.join(dirPath, 'input.pdf'), function(err, data) { + if (err) throw err; + sys.print(data); + }); + }); + }); +}); +``` + +### Temporary Streams + +To create a temporary WriteStream, use 'createWriteStream', which sits +on top of `fs.createWriteStream`. The return value is a +`fs.WriteStream` whose `path` is registered for removal when +`temp.cleanup` is called (because `temp.track()` is called). + +```javascript +var temp = require('temp'); + +// Automatically track and cleanup files at exit +temp.track(); + +var stream = temp.createWriteStream(); +stream.write("Some data"); +// Maybe do some other things +stream.end(); +``` + +### Affixes + +You can provide custom prefixes and suffixes when creating temporary +files and directories. If you provide a string, it is used as the prefix +for the temporary name. If you provide an object with `prefix`, +`suffix` and `dir` keys, they are used for the temporary name. + +Here are some examples: + +* `"aprefix"`: A simple prefix, prepended to the filename; this is + shorthand for: +* `{prefix: "aprefix"}`: A simple prefix, prepended to the filename +* `{suffix: ".asuffix"}`: A suffix, appended to the filename + (especially useful when the file needs to be named with specific + extension for use with an external program). +* `{prefix: "myprefix", suffix: "mysuffix"}`: Customize both affixes +* `{dir: path.join(os.tmpDir()), "myapp"}`: default prefix and suffix + within a new temporary directory. +* `null`: Use the defaults for files and directories (prefixes `"f-"` + and `"d-"`, respectively, no suffixes). + +In this simple example we read a `pdf`, write it to a temporary file with +a `.pdf` extension, and close it. + +```javascript +var fs = require('fs'), + temp = require('temp'); + +fs.readFile('/path/to/source.pdf', function(err, data) { + temp.open({suffix: '.pdf'}, function(err, info) { + if (err) throw err; + fs.write(info.fd, contents); + fs.close(info.fd, function(err) { + if (err) throw err; + // Do something with the file + }); + }); +}); +``` + +### Just a path, please + +If you just want a unique name in your temporary directory, use +`path`: + +```javascript +var fs = require('fs'); +var tempName = temp.path({suffix: '.pdf'}); +// Do something with tempName +``` + +Note: The file isn't created for you, and the mode is not changed -- and it +will not be removed automatically at exit. If you use `path`, it's +all up to you. + +Using it with Grunt +------------------- + +If you want to use the module with [Grunt](http://gruntjs.com/), make sure you +use `async()` in your Gruntfile: + +```javascript +module.exports = function (grunt) { + var temp = require("temp"); + temp.track(); // Cleanup files, please + grunt.registerTast("temptest", "Testing temp", function() { + + var done = this.async(); // Don't forget this! + + grunt.log.writeln("About to write a file..."); + temp.open('tempfile', function(err, info) { + // File writing shenanigans here + grunt.log.writeln("Wrote a file!") + + done(); // REALLY don't forget this! + + }); + }); +}; +``` + +For more information, see the [Grunt FAQ](http://gruntjs.com/frequently-asked-questions#why-doesn-t-my-asynchronous-task-complete). + +Testing +------- + +For now, run `test/temp-test.js`: + + $ node test/temp-test.js + +Contributing +------------ + +You can find the repository at: +http://github.com/bruce/node-temp + +Issues/Feature Requests can be submitted at: +http://github.com/bruce/node-temp/issues + +I'd really like to hear your feedback, and I'd love to receive your +pull-requests! + +Copyright +--------- + +Copyright (c) 2010-2012 Bruce Williams. See LICENSE for details. diff --git a/src/extensibility/node/node_modules/temp/examples/grepcount.js b/src/extensibility/node/node_modules/temp/examples/grepcount.js new file mode 100644 index 00000000000..420d864531a --- /dev/null +++ b/src/extensibility/node/node_modules/temp/examples/grepcount.js @@ -0,0 +1,18 @@ +var temp = require('../lib/temp'), + fs = require('fs'), + util = require('util'), + exec = require('child_process').exec; + +var myData = "foo\nbar\nfoo\nbaz"; + +temp.open('myprefix', function(err, info) { + if (err) throw err; + fs.write(info.fd, myData); + fs.close(info.fd, function(err) { + if (err) throw err; + exec("grep foo '" + info.path + "' | wc -l", function(err, stdout) { + if (err) throw err; + util.puts(stdout.trim()); + }); + }); +}); diff --git a/src/extensibility/node/node_modules/temp/examples/pdfcreator.js b/src/extensibility/node/node_modules/temp/examples/pdfcreator.js new file mode 100644 index 00000000000..63fd277fdc1 --- /dev/null +++ b/src/extensibility/node/node_modules/temp/examples/pdfcreator.js @@ -0,0 +1,22 @@ +var temp = require('../lib/temp'), + fs = require('fs'), + util = require('util'), + path = require('path'), + exec = require('child_process').exec; + +var myData = "\\starttext\nHello World\n\\stoptext"; + +temp.mkdir('pdfcreator', function(err, dirPath) { + var inputPath = path.join(dirPath, 'input.tex') + fs.writeFile(inputPath, myData, function(err) { + if (err) throw err; + process.chdir(dirPath); + exec("texexec '" + inputPath + "'", function(err) { + if (err) throw err; + fs.readFile(path.join(dirPath, 'input.pdf'), function(err, data) { + if (err) throw err; + util.print(data); + }); + }); + }); +}); diff --git a/src/extensibility/node/node_modules/temp/lib/temp.js b/src/extensibility/node/node_modules/temp/lib/temp.js new file mode 100644 index 00000000000..41edf98ce85 --- /dev/null +++ b/src/extensibility/node/node_modules/temp/lib/temp.js @@ -0,0 +1,182 @@ +var fs = require('fs'), + os = require('osenv'), + path = require('path'), + cnst = require('constants'); + +/* HELPERS */ + +var RDWR_EXCL = cnst.O_CREAT | cnst.O_TRUNC | cnst.O_RDWR | cnst.O_EXCL; + +var environmentVariables = ['TMPDIR', 'TMP', 'TEMP']; + +var generateName = function(rawAffixes, defaultPrefix) { + var affixes = parseAffixes(rawAffixes, defaultPrefix); + var now = new Date(); + var name = [affixes.prefix, + now.getYear(), now.getMonth(), now.getDate(), + '-', + process.pid, + '-', + (Math.random() * 0x100000000 + 1).toString(36), + affixes.suffix].join(''); + return path.join(affixes.dir || exports.dir, name); +} + +var parseAffixes = function(rawAffixes, defaultPrefix) { + var affixes = {prefix: null, suffix: null}; + if(rawAffixes) { + switch (typeof(rawAffixes)) { + case 'string': + affixes.prefix = rawAffixes; + break; + case 'object': + affixes = rawAffixes; + break + default: + throw("Unknown affix declaration: " + affixes); + } + } else { + affixes.prefix = defaultPrefix; + } + return affixes; +} + +/* ------------------------------------------------------------------------- + * Don't forget to call track() if you want file tracking and exit handlers! + * ------------------------------------------------------------------------- + * When any temp file or directory is created, it is added to filesToDelete + * or dirsToDelete. The first time any temp file is created, a listener is + * added to remove all temp files and directories at exit. + */ +var tracking = false; +var track = function(value) { + tracking = (value != false) +}; +var exitListenerAttached = false; +var filesToDelete = []; +var dirsToDelete = []; + +var deleteFileOnExit = function(filePath) { + if (!tracking) return false; + attachExitListener(); + filesToDelete.push(filePath); +}; + +var deleteDirOnExit = function(dirPath) { + if (!tracking) return false; + attachExitListener(); + dirsToDelete.push(dirPath); +}; + +var attachExitListener = function() { + if (!tracking) return false; + if (!exitListenerAttached) { + process.addListener('exit', cleanup); + exitListenerAttached = true; + } +}; + +var cleanupFiles = function() { + if (!tracking) return false; + var counts = {removed: 0, missing: 0} + var toDelete; + while (toDelete = filesToDelete.shift()) { + try { + fs.unlinkSync(toDelete); + counts.removed++; + } catch (rmErr) { + /* removed normally */ + counts.missing++; + } + } + return counts; +}; + +var cleanupDirs = function() { + if (!tracking) return false; + var rimrafSync = require('rimraf').sync; + var counts = {removed: 0, missing: 0} + var toDelete; + while (toDelete = dirsToDelete.shift()) { + try { + rimrafSync(toDelete, function (er) { + if (er) { + throw er; + } else { + counts.removed++; + } + }); + } catch (rmErr) { + /* removed normally */ + counts.missing++; + } + } + return counts; +}; + +var cleanup = function() { + if (!tracking) return false; + fileCount = cleanupFiles(); + dirCount = cleanupDirs(); + return {files: fileCount, dirs: dirCount}; +} + +/* DIRECTORIES */ + +var mkdir = function(affixes, callback) { + var dirPath = generateName(affixes, 'd-'); + fs.mkdir(dirPath, 0700, function(err) { + if (!err) { + deleteDirOnExit(dirPath); + } + if (callback) + callback(err, dirPath); + }); +} +var mkdirSync = function(affixes) { + var dirPath = generateName(affixes, 'd-'); + fs.mkdirSync(dirPath, 0700); + deleteDirOnExit(dirPath); + return dirPath; +} + +/* FILES */ + +var open = function(affixes, callback) { + var filePath = generateName(affixes, 'f-') + fs.open(filePath, RDWR_EXCL, 0600, function(err, fd) { + if (!err) + deleteFileOnExit(filePath); + if (callback) + callback(err, {path: filePath, fd: fd}); + }); +} + +var openSync = function(affixes) { + var filePath = generateName(affixes, 'f-') + var fd = fs.openSync(filePath, RDWR_EXCL, 0600); + deleteFileOnExit(filePath); + return {path: filePath, fd: fd}; +} + +var createWriteStream = function(affixes) { + var filePath = generateName(affixes, 's-') + var stream = fs.createWriteStream(filePath, {flags: RDWR_EXCL, mode: 0600}); + deleteFileOnExit(filePath); + return stream; +} + +/* EXPORTS */ +// Settings +exports.dir = path.resolve(os.tmpdir()); +exports.track = track; +// Functions +exports.mkdir = mkdir; +exports.mkdirSync = mkdirSync; +exports.open = open; +exports.openSync = openSync; +exports.path = generateName; +exports.cleanup = cleanup; +exports.createWriteStream = createWriteStream; + + diff --git a/src/extensibility/node/node_modules/temp/node_modules/osenv/LICENSE b/src/extensibility/node/node_modules/temp/node_modules/osenv/LICENSE new file mode 100644 index 00000000000..74489e2e265 --- /dev/null +++ b/src/extensibility/node/node_modules/temp/node_modules/osenv/LICENSE @@ -0,0 +1,25 @@ +Copyright (c) Isaac Z. Schlueter +All rights reserved. + +The BSD License + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. +2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS +``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED +TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS +BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. diff --git a/src/extensibility/node/node_modules/temp/node_modules/osenv/README.md b/src/extensibility/node/node_modules/temp/node_modules/osenv/README.md new file mode 100644 index 00000000000..08fd90023dc --- /dev/null +++ b/src/extensibility/node/node_modules/temp/node_modules/osenv/README.md @@ -0,0 +1,63 @@ +# osenv + +Look up environment settings specific to different operating systems. + +## Usage + +```javascript +var osenv = require('osenv') +var path = osenv.path() +var user = osenv.user() +// etc. + +// Some things are not reliably in the env, and have a fallback command: +var h = osenv.hostname(function (er, hostname) { + h = hostname +}) +// This will still cause it to be memoized, so calling osenv.hostname() +// is now an immediate operation. + +// You can always send a cb, which will get called in the nextTick +// if it's been memoized, or wait for the fallback data if it wasn't +// found in the environment. +osenv.hostname(function (er, hostname) { + if (er) console.error('error looking up hostname') + else console.log('this machine calls itself %s', hostname) +}) +``` + +## osenv.hostname() + +The machine name. Calls `hostname` if not found. + +## osenv.user() + +The currently logged-in user. Calls `whoami` if not found. + +## osenv.prompt() + +Either PS1 on unix, or PROMPT on Windows. + +## osenv.tmpdir() + +The place where temporary files should be created. + +## osenv.home() + +No place like it. + +## osenv.path() + +An array of the places that the operating system will search for +executables. + +## osenv.editor() + +Return the executable name of the editor program. This uses the EDITOR +and VISUAL environment variables, and falls back to `vi` on Unix, or +`notepad.exe` on Windows. + +## osenv.shell() + +The SHELL on Unix, which Windows calls the ComSpec. Defaults to 'bash' +or 'cmd'. diff --git a/src/extensibility/node/node_modules/temp/node_modules/osenv/osenv.js b/src/extensibility/node/node_modules/temp/node_modules/osenv/osenv.js new file mode 100644 index 00000000000..e3367a77439 --- /dev/null +++ b/src/extensibility/node/node_modules/temp/node_modules/osenv/osenv.js @@ -0,0 +1,80 @@ +var isWindows = process.platform === 'win32' +var windir = isWindows ? process.env.windir || 'C:\\Windows' : null +var path = require('path') +var exec = require('child_process').exec + +// looking up envs is a bit costly. +// Also, sometimes we want to have a fallback +// Pass in a callback to wait for the fallback on failures +// After the first lookup, always returns the same thing. +function memo (key, lookup, fallback) { + var fell = false + var falling = false + exports[key] = function (cb) { + var val = lookup() + if (!val && !fell && !falling && fallback) { + fell = true + falling = true + exec(fallback, function (er, output, stderr) { + falling = false + if (er) return // oh well, we tried + val = output.trim() + }) + } + exports[key] = function (cb) { + if (cb) process.nextTick(cb.bind(null, null, val)) + return val + } + if (cb && !falling) process.nextTick(cb.bind(null, null, val)) + return val + } +} + +memo('user', function () { + return ( isWindows + ? process.env.USERDOMAIN + '\\' + process.env.USERNAME + : process.env.USER + ) +}, 'whoami') + +memo('prompt', function () { + return isWindows ? process.env.PROMPT : process.env.PS1 +}) + +memo('hostname', function () { + return isWindows ? process.env.COMPUTERNAME : process.env.HOSTNAME +}, 'hostname') + +memo('tmpdir', function () { + var t = isWindows ? 'temp' : 'tmp' + return process.env.TMPDIR || + process.env.TMP || + process.env.TEMP || + ( exports.home() ? path.resolve(exports.home(), t) + : isWindows ? path.resolve(windir, t) + : '/tmp' + ) +}) + +memo('home', function () { + return ( isWindows ? process.env.USERPROFILE + : process.env.HOME + ) +}) + +memo('path', function () { + return (process.env.PATH || + process.env.Path || + process.env.path).split(isWindows ? ';' : ':') +}) + +memo('editor', function () { + return process.env.EDITOR || + process.env.VISUAL || + (isWindows ? 'notepad.exe' : 'vi') +}) + +memo('shell', function () { + return isWindows ? process.env.ComSpec || 'cmd' + : process.env.SHELL || 'bash' +}) diff --git a/src/extensibility/node/node_modules/temp/node_modules/osenv/package.json b/src/extensibility/node/node_modules/temp/node_modules/osenv/package.json new file mode 100644 index 00000000000..721c45ff1eb --- /dev/null +++ b/src/extensibility/node/node_modules/temp/node_modules/osenv/package.json @@ -0,0 +1,42 @@ +{ + "name": "osenv", + "version": "0.0.3", + "main": "osenv.js", + "directories": { + "test": "test" + }, + "dependencies": {}, + "devDependencies": { + "tap": "~0.2.5" + }, + "scripts": { + "test": "tap test/*.js" + }, + "repository": { + "type": "git", + "url": "git://github.com/isaacs/osenv" + }, + "keywords": [ + "environment", + "variable", + "home", + "tmpdir", + "path", + "prompt", + "ps1" + ], + "author": { + "name": "Isaac Z. Schlueter", + "email": "i@izs.me", + "url": "http://blog.izs.me/" + }, + "license": "BSD", + "description": "Look up environment settings specific to different operating systems", + "readme": "# osenv\n\nLook up environment settings specific to different operating systems.\n\n## Usage\n\n```javascript\nvar osenv = require('osenv')\nvar path = osenv.path()\nvar user = osenv.user()\n// etc.\n\n// Some things are not reliably in the env, and have a fallback command:\nvar h = osenv.hostname(function (er, hostname) {\n h = hostname\n})\n// This will still cause it to be memoized, so calling osenv.hostname()\n// is now an immediate operation.\n\n// You can always send a cb, which will get called in the nextTick\n// if it's been memoized, or wait for the fallback data if it wasn't\n// found in the environment.\nosenv.hostname(function (er, hostname) {\n if (er) console.error('error looking up hostname')\n else console.log('this machine calls itself %s', hostname)\n})\n```\n\n## osenv.hostname()\n\nThe machine name. Calls `hostname` if not found.\n\n## osenv.user()\n\nThe currently logged-in user. Calls `whoami` if not found.\n\n## osenv.prompt()\n\nEither PS1 on unix, or PROMPT on Windows.\n\n## osenv.tmpdir()\n\nThe place where temporary files should be created.\n\n## osenv.home()\n\nNo place like it.\n\n## osenv.path()\n\nAn array of the places that the operating system will search for\nexecutables.\n\n## osenv.editor() \n\nReturn the executable name of the editor program. This uses the EDITOR\nand VISUAL environment variables, and falls back to `vi` on Unix, or\n`notepad.exe` on Windows.\n\n## osenv.shell()\n\nThe SHELL on Unix, which Windows calls the ComSpec. Defaults to 'bash'\nor 'cmd'.\n", + "readmeFilename": "README.md", + "bugs": { + "url": "https://github.com/isaacs/osenv/issues" + }, + "_id": "osenv@0.0.3", + "_from": "osenv@0.0.3" +} diff --git a/src/extensibility/node/node_modules/temp/node_modules/osenv/test/unix.js b/src/extensibility/node/node_modules/temp/node_modules/osenv/test/unix.js new file mode 100644 index 00000000000..b72eb0b3f50 --- /dev/null +++ b/src/extensibility/node/node_modules/temp/node_modules/osenv/test/unix.js @@ -0,0 +1,76 @@ +// only run this test on windows +// pretending to be another platform is too hacky, since it breaks +// how the underlying system looks up module paths and runs +// child processes, and all that stuff is cached. +if (process.platform === 'win32') { + console.log('TAP Version 13\n' + + '1..0\n' + + '# Skip unix tests, this is not unix\n') + return +} +var tap = require('tap') + +// like unix, but funny +process.env.USER = 'sirUser' +process.env.HOME = '/home/sirUser' +process.env.HOSTNAME = 'my-machine' +process.env.TMPDIR = '/tmpdir' +process.env.TMP = '/tmp' +process.env.TEMP = '/temp' +process.env.PATH = '/opt/local/bin:/usr/local/bin:/usr/bin/:bin' +process.env.PS1 = '(o_o) $ ' +process.env.EDITOR = 'edit' +process.env.VISUAL = 'visualedit' +process.env.SHELL = 'zsh' + + +tap.test('basic unix sanity test', function (t) { + var osenv = require('../osenv.js') + + t.equal(osenv.user(), process.env.USER) + t.equal(osenv.home(), process.env.HOME) + t.equal(osenv.hostname(), process.env.HOSTNAME) + t.same(osenv.path(), process.env.PATH.split(':')) + t.equal(osenv.prompt(), process.env.PS1) + t.equal(osenv.tmpdir(), process.env.TMPDIR) + + // mildly evil, but it's for a test. + process.env.TMPDIR = '' + delete require.cache[require.resolve('../osenv.js')] + var osenv = require('../osenv.js') + t.equal(osenv.tmpdir(), process.env.TMP) + + process.env.TMP = '' + delete require.cache[require.resolve('../osenv.js')] + var osenv = require('../osenv.js') + t.equal(osenv.tmpdir(), process.env.TEMP) + + process.env.TEMP = '' + delete require.cache[require.resolve('../osenv.js')] + var osenv = require('../osenv.js') + t.equal(osenv.tmpdir(), '/home/sirUser/tmp') + + delete require.cache[require.resolve('../osenv.js')] + var osenv = require('../osenv.js') + osenv.home = function () { return null } + t.equal(osenv.tmpdir(), '/tmp') + + t.equal(osenv.editor(), 'edit') + process.env.EDITOR = '' + delete require.cache[require.resolve('../osenv.js')] + var osenv = require('../osenv.js') + t.equal(osenv.editor(), 'visualedit') + + process.env.VISUAL = '' + delete require.cache[require.resolve('../osenv.js')] + var osenv = require('../osenv.js') + t.equal(osenv.editor(), 'vi') + + t.equal(osenv.shell(), 'zsh') + process.env.SHELL = '' + delete require.cache[require.resolve('../osenv.js')] + var osenv = require('../osenv.js') + t.equal(osenv.shell(), 'bash') + + t.end() +}) diff --git a/src/extensibility/node/node_modules/temp/node_modules/osenv/test/windows.js b/src/extensibility/node/node_modules/temp/node_modules/osenv/test/windows.js new file mode 100644 index 00000000000..dd3fe807002 --- /dev/null +++ b/src/extensibility/node/node_modules/temp/node_modules/osenv/test/windows.js @@ -0,0 +1,82 @@ +// only run this test on windows +// pretending to be another platform is too hacky, since it breaks +// how the underlying system looks up module paths and runs +// child processes, and all that stuff is cached. +if (process.platform !== 'win32') { + console.log('TAP Version 13\n' + + '1..0\n' + + '# Skip windows tests, this is not windows\n') + return +} + +// load this before clubbing the platform name. +var tap = require('tap') + +process.env.windir = 'C:\\windows' +process.env.USERDOMAIN = 'some-domain' +process.env.USERNAME = 'sirUser' +process.env.USERPROFILE = 'C:\\Users\\sirUser' +process.env.COMPUTERNAME = 'my-machine' +process.env.TMPDIR = 'C:\\tmpdir' +process.env.TMP = 'C:\\tmp' +process.env.TEMP = 'C:\\temp' +process.env.Path = 'C:\\Program Files\\;C:\\Binary Stuff\\bin' +process.env.PROMPT = '(o_o) $ ' +process.env.EDITOR = 'edit' +process.env.VISUAL = 'visualedit' +process.env.ComSpec = 'some-com' + +tap.test('basic windows sanity test', function (t) { + var osenv = require('../osenv.js') + + var osenv = require('../osenv.js') + + t.equal(osenv.user(), + process.env.USERDOMAIN + '\\' + process.env.USERNAME) + t.equal(osenv.home(), process.env.USERPROFILE) + t.equal(osenv.hostname(), process.env.COMPUTERNAME) + t.same(osenv.path(), process.env.Path.split(';')) + t.equal(osenv.prompt(), process.env.PROMPT) + t.equal(osenv.tmpdir(), process.env.TMPDIR) + + // mildly evil, but it's for a test. + process.env.TMPDIR = '' + delete require.cache[require.resolve('../osenv.js')] + var osenv = require('../osenv.js') + t.equal(osenv.tmpdir(), process.env.TMP) + + process.env.TMP = '' + delete require.cache[require.resolve('../osenv.js')] + var osenv = require('../osenv.js') + t.equal(osenv.tmpdir(), process.env.TEMP) + + process.env.TEMP = '' + delete require.cache[require.resolve('../osenv.js')] + var osenv = require('../osenv.js') + t.equal(osenv.tmpdir(), 'C:\\Users\\sirUser\\temp') + + process.env.TEMP = '' + delete require.cache[require.resolve('../osenv.js')] + var osenv = require('../osenv.js') + osenv.home = function () { return null } + t.equal(osenv.tmpdir(), 'C:\\windows\\temp') + + t.equal(osenv.editor(), 'edit') + process.env.EDITOR = '' + delete require.cache[require.resolve('../osenv.js')] + var osenv = require('../osenv.js') + t.equal(osenv.editor(), 'visualedit') + + process.env.VISUAL = '' + delete require.cache[require.resolve('../osenv.js')] + var osenv = require('../osenv.js') + t.equal(osenv.editor(), 'notepad.exe') + + t.equal(osenv.shell(), 'some-com') + process.env.ComSpec = '' + delete require.cache[require.resolve('../osenv.js')] + var osenv = require('../osenv.js') + t.equal(osenv.shell(), 'cmd') + + t.end() +}) diff --git a/src/extensibility/node/node_modules/temp/node_modules/rimraf/AUTHORS b/src/extensibility/node/node_modules/temp/node_modules/rimraf/AUTHORS new file mode 100644 index 00000000000..247b7543737 --- /dev/null +++ b/src/extensibility/node/node_modules/temp/node_modules/rimraf/AUTHORS @@ -0,0 +1,6 @@ +# Authors sorted by whether or not they're me. +Isaac Z. Schlueter (http://blog.izs.me) +Wayne Larsen (http://github.com/wvl) +ritch +Marcel Laverdet +Yosef Dinerstein diff --git a/src/extensibility/node/node_modules/temp/node_modules/rimraf/LICENSE b/src/extensibility/node/node_modules/temp/node_modules/rimraf/LICENSE new file mode 100644 index 00000000000..05a4010949c --- /dev/null +++ b/src/extensibility/node/node_modules/temp/node_modules/rimraf/LICENSE @@ -0,0 +1,23 @@ +Copyright 2009, 2010, 2011 Isaac Z. Schlueter. +All rights reserved. + +Permission is hereby granted, free of charge, to any person +obtaining a copy of this software and associated documentation +files (the "Software"), to deal in the Software without +restriction, including without limitation the rights to use, +copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the +Software is furnished to do so, subject to the following +conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES +OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT +HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +OTHER DEALINGS IN THE SOFTWARE. diff --git a/src/extensibility/node/node_modules/temp/node_modules/rimraf/README.md b/src/extensibility/node/node_modules/temp/node_modules/rimraf/README.md new file mode 100644 index 00000000000..96ce9b2a0bd --- /dev/null +++ b/src/extensibility/node/node_modules/temp/node_modules/rimraf/README.md @@ -0,0 +1,21 @@ +A `rm -rf` for node. + +Install with `npm install rimraf`, or just drop rimraf.js somewhere. + +## API + +`rimraf(f, callback)` + +The callback will be called with an error if there is one. Certain +errors are handled for you: + +* `EBUSY` - rimraf will back off a maximum of opts.maxBusyTries times + before giving up. +* `EMFILE` - If too many file descriptors get opened, rimraf will + patiently wait until more become available. + + +## rimraf.sync + +It can remove stuff synchronously, too. But that's not so good. Use +the async API. It's better. diff --git a/src/extensibility/node/node_modules/tmp/.npmignore b/src/extensibility/node/node_modules/temp/node_modules/rimraf/node_modules/graceful-fs/.npmignore similarity index 100% rename from src/extensibility/node/node_modules/tmp/.npmignore rename to src/extensibility/node/node_modules/temp/node_modules/rimraf/node_modules/graceful-fs/.npmignore diff --git a/src/extensibility/node/node_modules/temp/node_modules/rimraf/node_modules/graceful-fs/LICENSE b/src/extensibility/node/node_modules/temp/node_modules/rimraf/node_modules/graceful-fs/LICENSE new file mode 100644 index 00000000000..0c44ae716db --- /dev/null +++ b/src/extensibility/node/node_modules/temp/node_modules/rimraf/node_modules/graceful-fs/LICENSE @@ -0,0 +1,27 @@ +Copyright (c) Isaac Z. Schlueter ("Author") +All rights reserved. + +The BSD License + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: + +1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + +2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS +BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR +BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, +WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE +OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN +IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/src/extensibility/node/node_modules/temp/node_modules/rimraf/node_modules/graceful-fs/README.md b/src/extensibility/node/node_modules/temp/node_modules/rimraf/node_modules/graceful-fs/README.md new file mode 100644 index 00000000000..01af3d6b63b --- /dev/null +++ b/src/extensibility/node/node_modules/temp/node_modules/rimraf/node_modules/graceful-fs/README.md @@ -0,0 +1,33 @@ +# graceful-fs + +graceful-fs functions as a drop-in replacement for the fs module, +making various improvements. + +The improvements are meant to normalize behavior across different +platforms and environments, and to make filesystem access more +resilient to errors. + +## Improvements over fs module + +graceful-fs: + +* keeps track of how many file descriptors are open, and by default + limits this to 1024. Any further requests to open a file are put in a + queue until new slots become available. If 1024 turns out to be too + much, it decreases the limit further. +* fixes `lchmod` for Node versions prior to 0.6.2. +* implements `fs.lutimes` if possible. Otherwise it becomes a noop. +* ignores `EINVAL` and `EPERM` errors in `chown`, `fchown` or + `lchown` if the user isn't root. +* makes `lchmod` and `lchown` become noops, if not available. +* retries reading a file if `read` results in EAGAIN error. + +On Windows, it retries renaming a file for up to one second if `EACCESS` +or `EPERM` error occurs, likely because antivirus software has locked +the directory. + +## Configuration + +The maximum number of open file descriptors that graceful-fs manages may +be adjusted by setting `fs.MAX_OPEN` to a different number. The default +is 1024. diff --git a/src/extensibility/node/node_modules/temp/node_modules/rimraf/node_modules/graceful-fs/graceful-fs.js b/src/extensibility/node/node_modules/temp/node_modules/rimraf/node_modules/graceful-fs/graceful-fs.js new file mode 100644 index 00000000000..ca9115243be --- /dev/null +++ b/src/extensibility/node/node_modules/temp/node_modules/rimraf/node_modules/graceful-fs/graceful-fs.js @@ -0,0 +1,442 @@ +// this keeps a queue of opened file descriptors, and will make +// fs operations wait until some have closed before trying to open more. + +var fs = exports = module.exports = {} +fs._originalFs = require("fs") + +Object.getOwnPropertyNames(fs._originalFs).forEach(function(prop) { + var desc = Object.getOwnPropertyDescriptor(fs._originalFs, prop) + Object.defineProperty(fs, prop, desc) +}) + +var queue = [] + , constants = require("constants") + +fs._curOpen = 0 + +fs.MIN_MAX_OPEN = 64 +fs.MAX_OPEN = 1024 + +// prevent EMFILE errors +function OpenReq (path, flags, mode, cb) { + this.path = path + this.flags = flags + this.mode = mode + this.cb = cb +} + +function noop () {} + +fs.open = gracefulOpen + +function gracefulOpen (path, flags, mode, cb) { + if (typeof mode === "function") cb = mode, mode = null + if (typeof cb !== "function") cb = noop + + if (fs._curOpen >= fs.MAX_OPEN) { + queue.push(new OpenReq(path, flags, mode, cb)) + setTimeout(flush) + return + } + open(path, flags, mode, function (er, fd) { + if (er && er.code === "EMFILE" && fs._curOpen > fs.MIN_MAX_OPEN) { + // that was too many. reduce max, get back in queue. + // this should only happen once in a great while, and only + // if the ulimit -n is set lower than 1024. + fs.MAX_OPEN = fs._curOpen - 1 + return fs.open(path, flags, mode, cb) + } + cb(er, fd) + }) +} + +function open (path, flags, mode, cb) { + cb = cb || noop + fs._curOpen ++ + fs._originalFs.open.call(fs, path, flags, mode, function (er, fd) { + if (er) onclose() + cb(er, fd) + }) +} + +fs.openSync = function (path, flags, mode) { + var ret + ret = fs._originalFs.openSync.call(fs, path, flags, mode) + fs._curOpen ++ + return ret +} + +function onclose () { + fs._curOpen -- + flush() +} + +function flush () { + while (fs._curOpen < fs.MAX_OPEN) { + var req = queue.shift() + if (!req) return + switch (req.constructor.name) { + case 'OpenReq': + open(req.path, req.flags || "r", req.mode || 0777, req.cb) + break + case 'ReaddirReq': + readdir(req.path, req.cb) + break + case 'ReadFileReq': + readFile(req.path, req.options, req.cb) + break + case 'WriteFileReq': + writeFile(req.path, req.data, req.options, req.cb) + break + default: + throw new Error('Unknown req type: ' + req.constructor.name) + } + } +} + +fs.close = function (fd, cb) { + cb = cb || noop + fs._originalFs.close.call(fs, fd, function (er) { + onclose() + cb(er) + }) +} + +fs.closeSync = function (fd) { + try { + return fs._originalFs.closeSync.call(fs, fd) + } finally { + onclose() + } +} + + +// readdir takes a fd as well. +// however, the sync version closes it right away, so +// there's no need to wrap. +// It would be nice to catch when it throws an EMFILE, +// but that's relatively rare anyway. + +fs.readdir = gracefulReaddir + +function gracefulReaddir (path, cb) { + if (fs._curOpen >= fs.MAX_OPEN) { + queue.push(new ReaddirReq(path, cb)) + setTimeout(flush) + return + } + + readdir(path, function (er, files) { + if (er && er.code === "EMFILE" && fs._curOpen > fs.MIN_MAX_OPEN) { + fs.MAX_OPEN = fs._curOpen - 1 + return fs.readdir(path, cb) + } + cb(er, files) + }) +} + +function readdir (path, cb) { + cb = cb || noop + fs._curOpen ++ + fs._originalFs.readdir.call(fs, path, function (er, files) { + onclose() + cb(er, files) + }) +} + +function ReaddirReq (path, cb) { + this.path = path + this.cb = cb +} + + +fs.readFile = gracefulReadFile + +function gracefulReadFile(path, options, cb) { + if (typeof options === "function") cb = options, options = null + if (typeof cb !== "function") cb = noop + + if (fs._curOpen >= fs.MAX_OPEN) { + queue.push(new ReadFileReq(path, options, cb)) + setTimeout(flush) + return + } + + readFile(path, options, function (er, data) { + if (er && er.code === "EMFILE" && fs._curOpen > fs.MIN_MAX_OPEN) { + fs.MAX_OPEN = fs._curOpen - 1 + return fs.readFile(path, options, cb) + } + cb(er, data) + }) +} + +function readFile (path, options, cb) { + cb = cb || noop + fs._curOpen ++ + fs._originalFs.readFile.call(fs, path, options, function (er, data) { + onclose() + cb(er, data) + }) +} + +function ReadFileReq (path, options, cb) { + this.path = path + this.options = options + this.cb = cb +} + + + + +fs.writeFile = gracefulWriteFile + +function gracefulWriteFile(path, data, options, cb) { + if (typeof options === "function") cb = options, options = null + if (typeof cb !== "function") cb = noop + + if (fs._curOpen >= fs.MAX_OPEN) { + queue.push(new WriteFileReq(path, data, options, cb)) + setTimeout(flush) + return + } + + writeFile(path, data, options, function (er) { + if (er && er.code === "EMFILE" && fs._curOpen > fs.MIN_MAX_OPEN) { + fs.MAX_OPEN = fs._curOpen - 1 + return fs.writeFile(path, data, options, cb) + } + cb(er) + }) +} + +function writeFile (path, data, options, cb) { + cb = cb || noop + fs._curOpen ++ + fs._originalFs.writeFile.call(fs, path, data, options, function (er) { + onclose() + cb(er) + }) +} + +function WriteFileReq (path, data, options, cb) { + this.path = path + this.data = data + this.options = options + this.cb = cb +} + + +// (re-)implement some things that are known busted or missing. + +var constants = require("constants") + +// lchmod, broken prior to 0.6.2 +// back-port the fix here. +if (constants.hasOwnProperty('O_SYMLINK') && + process.version.match(/^v0\.6\.[0-2]|^v0\.5\./)) { + fs.lchmod = function (path, mode, callback) { + callback = callback || noop + fs.open( path + , constants.O_WRONLY | constants.O_SYMLINK + , mode + , function (err, fd) { + if (err) { + callback(err) + return + } + // prefer to return the chmod error, if one occurs, + // but still try to close, and report closing errors if they occur. + fs.fchmod(fd, mode, function (err) { + fs.close(fd, function(err2) { + callback(err || err2) + }) + }) + }) + } + + fs.lchmodSync = function (path, mode) { + var fd = fs.openSync(path, constants.O_WRONLY | constants.O_SYMLINK, mode) + + // prefer to return the chmod error, if one occurs, + // but still try to close, and report closing errors if they occur. + var err, err2 + try { + var ret = fs.fchmodSync(fd, mode) + } catch (er) { + err = er + } + try { + fs.closeSync(fd) + } catch (er) { + err2 = er + } + if (err || err2) throw (err || err2) + return ret + } +} + + +// lutimes implementation, or no-op +if (!fs.lutimes) { + if (constants.hasOwnProperty("O_SYMLINK")) { + fs.lutimes = function (path, at, mt, cb) { + fs.open(path, constants.O_SYMLINK, function (er, fd) { + cb = cb || noop + if (er) return cb(er) + fs.futimes(fd, at, mt, function (er) { + fs.close(fd, function (er2) { + return cb(er || er2) + }) + }) + }) + } + + fs.lutimesSync = function (path, at, mt) { + var fd = fs.openSync(path, constants.O_SYMLINK) + , err + , err2 + , ret + + try { + var ret = fs.futimesSync(fd, at, mt) + } catch (er) { + err = er + } + try { + fs.closeSync(fd) + } catch (er) { + err2 = er + } + if (err || err2) throw (err || err2) + return ret + } + + } else if (fs.utimensat && constants.hasOwnProperty("AT_SYMLINK_NOFOLLOW")) { + // maybe utimensat will be bound soonish? + fs.lutimes = function (path, at, mt, cb) { + fs.utimensat(path, at, mt, constants.AT_SYMLINK_NOFOLLOW, cb) + } + + fs.lutimesSync = function (path, at, mt) { + return fs.utimensatSync(path, at, mt, constants.AT_SYMLINK_NOFOLLOW) + } + + } else { + fs.lutimes = function (_a, _b, _c, cb) { process.nextTick(cb) } + fs.lutimesSync = function () {} + } +} + + +// https://github.com/isaacs/node-graceful-fs/issues/4 +// Chown should not fail on einval or eperm if non-root. + +fs.chown = chownFix(fs.chown) +fs.fchown = chownFix(fs.fchown) +fs.lchown = chownFix(fs.lchown) + +fs.chownSync = chownFixSync(fs.chownSync) +fs.fchownSync = chownFixSync(fs.fchownSync) +fs.lchownSync = chownFixSync(fs.lchownSync) + +function chownFix (orig) { + if (!orig) return orig + return function (target, uid, gid, cb) { + return orig.call(fs, target, uid, gid, function (er, res) { + if (chownErOk(er)) er = null + cb(er, res) + }) + } +} + +function chownFixSync (orig) { + if (!orig) return orig + return function (target, uid, gid) { + try { + return orig.call(fs, target, uid, gid) + } catch (er) { + if (!chownErOk(er)) throw er + } + } +} + +function chownErOk (er) { + // if there's no getuid, or if getuid() is something other than 0, + // and the error is EINVAL or EPERM, then just ignore it. + // This specific case is a silent failure in cp, install, tar, + // and most other unix tools that manage permissions. + // When running as root, or if other types of errors are encountered, + // then it's strict. + if (!er || (!process.getuid || process.getuid() !== 0) + && (er.code === "EINVAL" || er.code === "EPERM")) return true +} + + +// if lchmod/lchown do not exist, then make them no-ops +if (!fs.lchmod) { + fs.lchmod = function (path, mode, cb) { + process.nextTick(cb) + } + fs.lchmodSync = function () {} +} +if (!fs.lchown) { + fs.lchown = function (path, uid, gid, cb) { + process.nextTick(cb) + } + fs.lchownSync = function () {} +} + + + +// on Windows, A/V software can lock the directory, causing this +// to fail with an EACCES or EPERM if the directory contains newly +// created files. Try again on failure, for up to 1 second. +if (process.platform === "win32") { + var rename_ = fs.rename + fs.rename = function rename (from, to, cb) { + var start = Date.now() + rename_(from, to, function CB (er) { + if (er + && (er.code === "EACCES" || er.code === "EPERM") + && Date.now() - start < 1000) { + return rename_(from, to, CB) + } + cb(er) + }) + } +} + + +// if read() returns EAGAIN, then just try it again. +var read = fs.read +fs.read = function (fd, buffer, offset, length, position, callback_) { + var callback + if (callback_ && typeof callback_ === 'function') { + var eagCounter = 0 + callback = function (er, _, __) { + if (er && er.code === 'EAGAIN' && eagCounter < 10) { + eagCounter ++ + return read.call(fs, fd, buffer, offset, length, position, callback) + } + callback_.apply(this, arguments) + } + } + return read.call(fs, fd, buffer, offset, length, position, callback) +} + +var readSync = fs.readSync +fs.readSync = function (fd, buffer, offset, length, position) { + var eagCounter = 0 + while (true) { + try { + return readSync.call(fs, fd, buffer, offset, length, position) + } catch (er) { + if (er.code === 'EAGAIN' && eagCounter < 10) { + eagCounter ++ + continue + } + throw er + } + } +} diff --git a/src/extensibility/node/node_modules/temp/node_modules/rimraf/node_modules/graceful-fs/package.json b/src/extensibility/node/node_modules/temp/node_modules/rimraf/node_modules/graceful-fs/package.json new file mode 100644 index 00000000000..bfc503c3fb6 --- /dev/null +++ b/src/extensibility/node/node_modules/temp/node_modules/rimraf/node_modules/graceful-fs/package.json @@ -0,0 +1,48 @@ +{ + "author": { + "name": "Isaac Z. Schlueter", + "email": "i@izs.me", + "url": "http://blog.izs.me" + }, + "name": "graceful-fs", + "description": "A drop-in replacement for fs, making various improvements.", + "version": "1.2.3", + "repository": { + "type": "git", + "url": "git://github.com/isaacs/node-graceful-fs.git" + }, + "main": "graceful-fs.js", + "engines": { + "node": ">=0.4.0" + }, + "directories": { + "test": "test" + }, + "scripts": { + "test": "tap test/*.js" + }, + "keywords": [ + "fs", + "module", + "reading", + "retry", + "retries", + "queue", + "error", + "errors", + "handling", + "EMFILE", + "EAGAIN", + "EINVAL", + "EPERM", + "EACCESS" + ], + "license": "BSD", + "readme": "# graceful-fs\n\ngraceful-fs functions as a drop-in replacement for the fs module,\nmaking various improvements.\n\nThe improvements are meant to normalize behavior across different\nplatforms and environments, and to make filesystem access more\nresilient to errors.\n\n## Improvements over fs module\n\ngraceful-fs:\n\n* keeps track of how many file descriptors are open, and by default\n limits this to 1024. Any further requests to open a file are put in a\n queue until new slots become available. If 1024 turns out to be too\n much, it decreases the limit further.\n* fixes `lchmod` for Node versions prior to 0.6.2.\n* implements `fs.lutimes` if possible. Otherwise it becomes a noop.\n* ignores `EINVAL` and `EPERM` errors in `chown`, `fchown` or\n `lchown` if the user isn't root.\n* makes `lchmod` and `lchown` become noops, if not available.\n* retries reading a file if `read` results in EAGAIN error.\n\nOn Windows, it retries renaming a file for up to one second if `EACCESS`\nor `EPERM` error occurs, likely because antivirus software has locked\nthe directory.\n\n## Configuration\n\nThe maximum number of open file descriptors that graceful-fs manages may\nbe adjusted by setting `fs.MAX_OPEN` to a different number. The default\nis 1024.\n", + "readmeFilename": "README.md", + "bugs": { + "url": "https://github.com/isaacs/node-graceful-fs/issues" + }, + "_id": "graceful-fs@1.2.3", + "_from": "graceful-fs@~1" +} diff --git a/src/extensibility/node/node_modules/temp/node_modules/rimraf/node_modules/graceful-fs/test/open.js b/src/extensibility/node/node_modules/temp/node_modules/rimraf/node_modules/graceful-fs/test/open.js new file mode 100644 index 00000000000..930d53257c2 --- /dev/null +++ b/src/extensibility/node/node_modules/temp/node_modules/rimraf/node_modules/graceful-fs/test/open.js @@ -0,0 +1,46 @@ +var test = require('tap').test +var fs = require('../graceful-fs.js') + +test('graceful fs is not fs', function (t) { + t.notEqual(fs, require('fs')) + t.end() +}) + +test('open an existing file works', function (t) { + var start = fs._curOpen + var fd = fs.openSync(__filename, 'r') + t.equal(fs._curOpen, start + 1) + fs.closeSync(fd) + t.equal(fs._curOpen, start) + fs.open(__filename, 'r', function (er, fd) { + if (er) throw er + t.equal(fs._curOpen, start + 1) + fs.close(fd, function (er) { + if (er) throw er + t.equal(fs._curOpen, start) + t.end() + }) + }) +}) + +test('open a non-existing file throws', function (t) { + var start = fs._curOpen + var er + try { + var fd = fs.openSync('this file does not exist', 'r') + } catch (x) { + er = x + } + t.ok(er, 'should throw') + t.notOk(fd, 'should not get an fd') + t.equal(er.code, 'ENOENT') + t.equal(fs._curOpen, start) + + fs.open('neither does this file', 'r', function (er, fd) { + t.ok(er, 'should throw') + t.notOk(fd, 'should not get an fd') + t.equal(er.code, 'ENOENT') + t.equal(fs._curOpen, start) + t.end() + }) +}) diff --git a/src/extensibility/node/node_modules/temp/node_modules/rimraf/node_modules/graceful-fs/test/ulimit.js b/src/extensibility/node/node_modules/temp/node_modules/rimraf/node_modules/graceful-fs/test/ulimit.js new file mode 100644 index 00000000000..8d0882d0c1e --- /dev/null +++ b/src/extensibility/node/node_modules/temp/node_modules/rimraf/node_modules/graceful-fs/test/ulimit.js @@ -0,0 +1,158 @@ +var test = require('tap').test + +// simulated ulimit +// this is like graceful-fs, but in reverse +var fs_ = require('fs') +var fs = require('../graceful-fs.js') +var files = fs.readdirSync(__dirname) + +// Ok, no more actual file reading! + +var fds = 0 +var nextFd = 60 +var limit = 8 +fs_.open = function (path, flags, mode, cb) { + process.nextTick(function() { + ++fds + if (fds >= limit) { + --fds + var er = new Error('EMFILE Curses!') + er.code = 'EMFILE' + er.path = path + return cb(er) + } else { + cb(null, nextFd++) + } + }) +} + +fs_.openSync = function (path, flags, mode) { + if (fds >= limit) { + var er = new Error('EMFILE Curses!') + er.code = 'EMFILE' + er.path = path + throw er + } else { + ++fds + return nextFd++ + } +} + +fs_.close = function (fd, cb) { + process.nextTick(function () { + --fds + cb() + }) +} + +fs_.closeSync = function (fd) { + --fds +} + +fs_.readdir = function (path, cb) { + process.nextTick(function() { + if (fds >= limit) { + var er = new Error('EMFILE Curses!') + er.code = 'EMFILE' + er.path = path + return cb(er) + } else { + ++fds + process.nextTick(function () { + --fds + cb(null, [__filename, "some-other-file.js"]) + }) + } + }) +} + +fs_.readdirSync = function (path) { + if (fds >= limit) { + var er = new Error('EMFILE Curses!') + er.code = 'EMFILE' + er.path = path + throw er + } else { + return [__filename, "some-other-file.js"] + } +} + + +test('open emfile autoreduce', function (t) { + fs.MIN_MAX_OPEN = 4 + t.equal(fs.MAX_OPEN, 1024) + + var max = 12 + for (var i = 0; i < max; i++) { + fs.open(__filename, 'r', next(i)) + } + + var phase = 0 + + var expect = + [ [ 0, 60, null, 1024, 4, 12, 1 ], + [ 1, 61, null, 1024, 4, 12, 2 ], + [ 2, 62, null, 1024, 4, 12, 3 ], + [ 3, 63, null, 1024, 4, 12, 4 ], + [ 4, 64, null, 1024, 4, 12, 5 ], + [ 5, 65, null, 1024, 4, 12, 6 ], + [ 6, 66, null, 1024, 4, 12, 7 ], + [ 7, 67, null, 6, 4, 5, 1 ], + [ 8, 68, null, 6, 4, 5, 2 ], + [ 9, 69, null, 6, 4, 5, 3 ], + [ 10, 70, null, 6, 4, 5, 4 ], + [ 11, 71, null, 6, 4, 5, 5 ] ] + + var actual = [] + + function next (i) { return function (er, fd) { + if (er) + throw er + actual.push([i, fd, er, fs.MAX_OPEN, fs.MIN_MAX_OPEN, fs._curOpen, fds]) + + if (i === max - 1) { + t.same(actual, expect) + t.ok(fs.MAX_OPEN < limit) + t.end() + } + + fs.close(fd) + } } +}) + +test('readdir emfile autoreduce', function (t) { + fs.MAX_OPEN = 1024 + var max = 12 + for (var i = 0; i < max; i ++) { + fs.readdir(__dirname, next(i)) + } + + var expect = + [ [0,[__filename,"some-other-file.js"],null,7,4,7,7], + [1,[__filename,"some-other-file.js"],null,7,4,7,6], + [2,[__filename,"some-other-file.js"],null,7,4,7,5], + [3,[__filename,"some-other-file.js"],null,7,4,7,4], + [4,[__filename,"some-other-file.js"],null,7,4,7,3], + [5,[__filename,"some-other-file.js"],null,7,4,6,2], + [6,[__filename,"some-other-file.js"],null,7,4,5,1], + [7,[__filename,"some-other-file.js"],null,7,4,4,0], + [8,[__filename,"some-other-file.js"],null,7,4,3,3], + [9,[__filename,"some-other-file.js"],null,7,4,2,2], + [10,[__filename,"some-other-file.js"],null,7,4,1,1], + [11,[__filename,"some-other-file.js"],null,7,4,0,0] ] + + var actual = [] + + function next (i) { return function (er, files) { + if (er) + throw er + var line = [i, files, er, fs.MAX_OPEN, fs.MIN_MAX_OPEN, fs._curOpen, fds ] + actual.push(line) + + if (i === max - 1) { + t.ok(fs.MAX_OPEN < limit) + t.same(actual, expect) + t.end() + } + } } +}) diff --git a/src/extensibility/node/node_modules/temp/node_modules/rimraf/package.json b/src/extensibility/node/node_modules/temp/node_modules/rimraf/package.json new file mode 100644 index 00000000000..f5072d7cb0a --- /dev/null +++ b/src/extensibility/node/node_modules/temp/node_modules/rimraf/package.json @@ -0,0 +1,58 @@ +{ + "name": "rimraf", + "version": "2.1.4", + "main": "rimraf.js", + "description": "A deep deletion module for node (like `rm -rf`)", + "author": { + "name": "Isaac Z. Schlueter", + "email": "i@izs.me", + "url": "http://blog.izs.me/" + }, + "license": { + "type": "MIT", + "url": "https://github.com/isaacs/rimraf/raw/master/LICENSE" + }, + "optionalDependencies": { + "graceful-fs": "~1" + }, + "repository": { + "type": "git", + "url": "git://github.com/isaacs/rimraf.git" + }, + "scripts": { + "test": "cd test && bash run.sh" + }, + "contributors": [ + { + "name": "Isaac Z. Schlueter", + "email": "i@izs.me", + "url": "http://blog.izs.me" + }, + { + "name": "Wayne Larsen", + "email": "wayne@larsen.st", + "url": "http://github.com/wvl" + }, + { + "name": "ritch", + "email": "skawful@gmail.com" + }, + { + "name": "Marcel Laverdet" + }, + { + "name": "Yosef Dinerstein", + "email": "yosefd@microsoft.com" + } + ], + "readme": "A `rm -rf` for node.\n\nInstall with `npm install rimraf`, or just drop rimraf.js somewhere.\n\n## API\n\n`rimraf(f, callback)`\n\nThe callback will be called with an error if there is one. Certain\nerrors are handled for you:\n\n* `EBUSY` - rimraf will back off a maximum of opts.maxBusyTries times\n before giving up.\n* `EMFILE` - If too many file descriptors get opened, rimraf will\n patiently wait until more become available.\n\n\n## rimraf.sync\n\nIt can remove stuff synchronously, too. But that's not so good. Use\nthe async API. It's better.\n", + "readmeFilename": "README.md", + "bugs": { + "url": "https://github.com/isaacs/rimraf/issues" + }, + "dependencies": { + "graceful-fs": "~1" + }, + "_id": "rimraf@2.1.4", + "_from": "rimraf@~2.1.4" +} diff --git a/src/extensibility/node/node_modules/temp/node_modules/rimraf/rimraf.js b/src/extensibility/node/node_modules/temp/node_modules/rimraf/rimraf.js new file mode 100644 index 00000000000..ed915f982e8 --- /dev/null +++ b/src/extensibility/node/node_modules/temp/node_modules/rimraf/rimraf.js @@ -0,0 +1,132 @@ +module.exports = rimraf +rimraf.sync = rimrafSync + +var path = require("path") + , fs + +try { + // optional dependency + fs = require("graceful-fs") +} catch (er) { + fs = require("fs") +} + +// for EMFILE handling +var timeout = 0 +exports.EMFILE_MAX = 1000 +exports.BUSYTRIES_MAX = 3 + +function rimraf (p, cb) { + if (!cb) throw new Error("No callback passed to rimraf()") + + var busyTries = 0 + rimraf_(p, function CB (er) { + if (er) { + if (er.code === "EBUSY" && busyTries < exports.BUSYTRIES_MAX) { + busyTries ++ + var time = busyTries * 100 + // try again, with the same exact callback as this one. + return setTimeout(function () { + rimraf_(p, CB) + }, time) + } + + // this one won't happen if graceful-fs is used. + if (er.code === "EMFILE" && timeout < exports.EMFILE_MAX) { + return setTimeout(function () { + rimraf_(p, CB) + }, timeout ++) + } + + // already gone + if (er.code === "ENOENT") er = null + } + + timeout = 0 + cb(er) + }) +} + +// Two possible strategies. +// 1. Assume it's a file. unlink it, then do the dir stuff on EPERM or EISDIR +// 2. Assume it's a directory. readdir, then do the file stuff on ENOTDIR +// +// Both result in an extra syscall when you guess wrong. However, there +// are likely far more normal files in the world than directories. This +// is based on the assumption that a the average number of files per +// directory is >= 1. +// +// If anyone ever complains about this, then I guess the strategy could +// be made configurable somehow. But until then, YAGNI. +function rimraf_ (p, cb) { + fs.unlink(p, function (er) { + if (er && er.code === "ENOENT") + return cb() + if (er && (er.code === "EPERM" || er.code === "EISDIR")) + return rmdir(p, er, cb) + return cb(er) + }) +} + +function rmdir (p, originalEr, cb) { + // try to rmdir first, and only readdir on ENOTEMPTY or EEXIST (SunOS) + // if we guessed wrong, and it's not a directory, then + // raise the original error. + fs.rmdir(p, function (er) { + if (er && (er.code === "ENOTEMPTY" || er.code === "EEXIST")) + rmkids(p, cb) + else if (er && er.code === "ENOTDIR") + cb(originalEr) + else + cb(er) + }) +} + +function rmkids(p, cb) { + fs.readdir(p, function (er, files) { + if (er) + return cb(er) + var n = files.length + if (n === 0) + return fs.rmdir(p, cb) + var errState + files.forEach(function (f) { + rimraf(path.join(p, f), function (er) { + if (errState) + return + if (er) + return cb(errState = er) + if (--n === 0) + fs.rmdir(p, cb) + }) + }) + }) +} + +// this looks simpler, and is strictly *faster*, but will +// tie up the JavaScript thread and fail on excessively +// deep directory trees. +function rimrafSync (p) { + try { + fs.unlinkSync(p) + } catch (er) { + if (er.code === "ENOENT") + return + if (er.code !== "EPERM" && er.code !== "EISDIR") + throw er + try { + fs.rmdirSync(p) + } catch (er2) { + if (er2.code === "ENOENT") + return + if (er2.code === "ENOTDIR") + throw er + if (er2.code === "ENOTEMPTY") { + fs.readdirSync(p).forEach(function (f) { + rimrafSync(path.join(p, f)) + }) + fs.rmdirSync(p) + } + } + } +} diff --git a/src/extensibility/node/node_modules/temp/node_modules/rimraf/test/run.sh b/src/extensibility/node/node_modules/temp/node_modules/rimraf/test/run.sh new file mode 100644 index 00000000000..598f0163b23 --- /dev/null +++ b/src/extensibility/node/node_modules/temp/node_modules/rimraf/test/run.sh @@ -0,0 +1,10 @@ +#!/bin/bash +set -e +for i in test-*.js; do + echo -n $i ... + bash setup.sh + node $i + ! [ -d target ] + echo "pass" +done +rm -rf target diff --git a/src/extensibility/node/node_modules/temp/node_modules/rimraf/test/setup.sh b/src/extensibility/node/node_modules/temp/node_modules/rimraf/test/setup.sh new file mode 100644 index 00000000000..2602e631602 --- /dev/null +++ b/src/extensibility/node/node_modules/temp/node_modules/rimraf/test/setup.sh @@ -0,0 +1,47 @@ +#!/bin/bash + +set -e + +files=10 +folders=2 +depth=4 +target="$PWD/target" + +rm -rf target + +fill () { + local depth=$1 + local files=$2 + local folders=$3 + local target=$4 + + if ! [ -d $target ]; then + mkdir -p $target + fi + + local f + + f=$files + while [ $f -gt 0 ]; do + touch "$target/f-$depth-$f" + let f-- + done + + let depth-- + + if [ $depth -le 0 ]; then + return 0 + fi + + f=$folders + while [ $f -gt 0 ]; do + mkdir "$target/folder-$depth-$f" + fill $depth $files $folders "$target/d-$depth-$f" + let f-- + done +} + +fill $depth $files $folders $target + +# sanity assert +[ -d $target ] diff --git a/src/extensibility/node/node_modules/temp/node_modules/rimraf/test/test-async.js b/src/extensibility/node/node_modules/temp/node_modules/rimraf/test/test-async.js new file mode 100644 index 00000000000..9c2e0b7be0e --- /dev/null +++ b/src/extensibility/node/node_modules/temp/node_modules/rimraf/test/test-async.js @@ -0,0 +1,5 @@ +var rimraf = require("../rimraf") + , path = require("path") +rimraf(path.join(__dirname, "target"), function (er) { + if (er) throw er +}) diff --git a/src/extensibility/node/node_modules/temp/node_modules/rimraf/test/test-sync.js b/src/extensibility/node/node_modules/temp/node_modules/rimraf/test/test-sync.js new file mode 100644 index 00000000000..eb71f10476e --- /dev/null +++ b/src/extensibility/node/node_modules/temp/node_modules/rimraf/test/test-sync.js @@ -0,0 +1,3 @@ +var rimraf = require("../rimraf") + , path = require("path") +rimraf.sync(path.join(__dirname, "target")) diff --git a/src/extensibility/node/node_modules/temp/package.json b/src/extensibility/node/node_modules/temp/package.json new file mode 100644 index 00000000000..bcff18a768d --- /dev/null +++ b/src/extensibility/node/node_modules/temp/package.json @@ -0,0 +1,48 @@ +{ + "name": "temp", + "description": "Temporary files and directories", + "tags": [ + "temporary", + "temp", + "tempfile", + "tempdir", + "tmpfile", + "tmpdir", + "security" + ], + "version": "0.6.0", + "author": { + "name": "Bruce Williams", + "email": "bruce@codefluency.com" + }, + "directories": { + "lib": "lib" + }, + "engines": [ + "node >=0.6.0" + ], + "main": "./lib/temp", + "dependencies": { + "rimraf": "~2.1.4", + "osenv": "0.0.3" + }, + "devDependencies": {}, + "repository": { + "type": "git", + "url": "git://github.com/bruce/node-temp.git" + }, + "scripts": { + "test": "node test/temp-test.js" + }, + "readme": "node-temp\n=========\n\nTemporary files, directories, and streams for Node.js.\n\nHandles generating a unique file/directory name under the appropriate\nsystem temporary directory, changing the file to an appropriate mode,\nand supports automatic removal (if asked)\n\n`temp` has a similar API to the `fs` module.\n\nNode.js Compatibility\n---------------------\n\nSupports v0.6.0+.\n\n[![Build Status](https://travis-ci.org/bruce/node-temp.png)](https://travis-ci.org/bruce/node-temp)\n\nPlease let me know if you have problems running it on a later version of Node.js or\nhave platform-specific problems.\n\nInstallation\n------------\n\nInstall it using [npm](http://github.com/isaacs/npm):\n\n $ npm install temp\n\nOr get it directly from:\nhttp://github.com/bruce/node-temp\n\nSynopsis\n--------\n\nYou can create temporary files with `open` and `openSync`, temporary\ndirectories with `mkdir` and `mkdirSync`, or you can get a unique name\nin the system temporary directory with `path`.\n\nWorking copies of the following examples can be found under the\n`examples` directory.\n\n### Temporary Files\n\nTo create a temporary file use `open` or `openSync`, passing\nthem an optional prefix, suffix, or both (see below for details on\naffixes). The object passed to the callback (or returned) has\n`path` and `fd` keys:\n\n```javascript\n{ path: \"/path/to/file\",\n, fd: theFileDescriptor\n}\n```\n\nIn this example we write to a temporary file and call out to `grep` and\n`wc -l` to determine the number of time `foo` occurs in the text. The\ntemporary file is chmod'd `0600` and cleaned up automatically when the\nprocess at exit (because `temp.track()` is called):\n\n```javascript\nvar temp = require('temp'),\n fs = require('fs'),\n util = require('util'),\n exec = require('child_process').exec;\n\n// Automatically track and cleanup files at exit\ntemp.track();\n\n// Fake data\nvar myData = \"foo\\nbar\\nfoo\\nbaz\";\n\n// Process the data (note: error handling omitted)\ntemp.open('myprefix', function(err, info) {\n fs.write(info.fd, myData);\n fs.close(info.fd, function(err) {\n exec(\"grep foo '\" + info.path + \"' | wc -l\", function(err, stdout) {\n util.puts(stdout.trim());\n });\n });\n});\n```\n\n### Want Cleanup? Make sure you ask for it.\n\nAs noted in the example above, if you want temp to track the files and directories\nit creates and handle removing those files and directories on exit, you must call `track()`.\nIt's recommended that you do this immediately after requiring the module.\n\n```javascript\nvar temp = require(\"temp\");\ntemp.track();\n```\n\nWhy is this necessary? In pre-0.6 versions of temp, tracking was automatic. While this works\ngreat for scripts and [Grunt tasks](http://gruntjs.com/), it's not so great for long-running\nserver processes. Since that's arguably what Node.js is _for_, you have to opt-in to tracking.\n\nBut it's easy.\n\n#### Cleanup anytime\n\nWhen tracking, you can `cleanup()` anytime. An object will be returned with cleanup statistics\nand the file/directory lists will be reset.\n\n```javascript\n> temp.cleanup();\n{ files: { removed: 1, missing: 0 },\n dirs: { removed: 0, missing: 0 } }\n```\n\nNote: If you're not tracking, `false` will be returned.\n\n### Temporary Directories\n\nTo create a temporary directory, use `mkdir` or `mkdirSync`, passing\nit an optional prefix, suffix, or both (see below for details on affixes).\n\nIn this example we create a temporary directory, write to a file\nwithin it, call out to an external program to create a PDF, and read\nthe result. While the external process creates a lot of additional\nfiles, the temporary directory is removed automatically at exit (because\n`temp.track()` is called):\n\n```javascript\nvar temp = require('../lib/temp'),\n fs = require('fs'),\n util = require('util'),\n path = require('path'),\n exec = require('child_process').exec;\n\n// Automatically track and cleanup files at exit\ntemp.track();\n\n// For use with ConTeXt, http://wiki.contextgarden.net\nvar myData = \"\\\\starttext\\nHello World\\n\\\\stoptext\";\n\ntemp.mkdir('pdfcreator', function(err, dirPath) {\n var inputPath = path.join(dirPath, 'input.tex')\n fs.writeFile(inputPath, myData, function(err) {\n if (err) throw err;\n process.chdir(dirPath);\n exec(\"texexec '\" + inputPath + \"'\", function(err) {\n if (err) throw err;\n fs.readFile(path.join(dirPath, 'input.pdf'), function(err, data) {\n if (err) throw err;\n sys.print(data);\n });\n });\n });\n});\n```\n\n### Temporary Streams\n\nTo create a temporary WriteStream, use 'createWriteStream', which sits\non top of `fs.createWriteStream`. The return value is a\n`fs.WriteStream` whose `path` is registered for removal when\n`temp.cleanup` is called (because `temp.track()` is called).\n\n```javascript\nvar temp = require('temp');\n\n// Automatically track and cleanup files at exit\ntemp.track();\n\nvar stream = temp.createWriteStream();\nstream.write(\"Some data\");\n// Maybe do some other things\nstream.end();\n```\n\n### Affixes\n\nYou can provide custom prefixes and suffixes when creating temporary\nfiles and directories. If you provide a string, it is used as the prefix\nfor the temporary name. If you provide an object with `prefix`,\n`suffix` and `dir` keys, they are used for the temporary name.\n\nHere are some examples:\n\n* `\"aprefix\"`: A simple prefix, prepended to the filename; this is\n shorthand for:\n* `{prefix: \"aprefix\"}`: A simple prefix, prepended to the filename\n* `{suffix: \".asuffix\"}`: A suffix, appended to the filename\n (especially useful when the file needs to be named with specific\n extension for use with an external program).\n* `{prefix: \"myprefix\", suffix: \"mysuffix\"}`: Customize both affixes\n* `{dir: path.join(os.tmpDir()), \"myapp\"}`: default prefix and suffix\n within a new temporary directory.\n* `null`: Use the defaults for files and directories (prefixes `\"f-\"`\n and `\"d-\"`, respectively, no suffixes).\n\nIn this simple example we read a `pdf`, write it to a temporary file with\na `.pdf` extension, and close it.\n\n```javascript\nvar fs = require('fs'),\n temp = require('temp');\n\nfs.readFile('/path/to/source.pdf', function(err, data) {\n temp.open({suffix: '.pdf'}, function(err, info) {\n if (err) throw err;\n fs.write(info.fd, contents);\n fs.close(info.fd, function(err) {\n if (err) throw err;\n // Do something with the file\n });\n });\n});\n```\n\n### Just a path, please\n\nIf you just want a unique name in your temporary directory, use\n`path`:\n\n```javascript\nvar fs = require('fs');\nvar tempName = temp.path({suffix: '.pdf'});\n// Do something with tempName\n```\n\nNote: The file isn't created for you, and the mode is not changed -- and it\nwill not be removed automatically at exit. If you use `path`, it's\nall up to you.\n\nUsing it with Grunt\n-------------------\n\nIf you want to use the module with [Grunt](http://gruntjs.com/), make sure you\nuse `async()` in your Gruntfile:\n\n```javascript\nmodule.exports = function (grunt) {\n var temp = require(\"temp\");\n temp.track(); // Cleanup files, please\n grunt.registerTast(\"temptest\", \"Testing temp\", function() {\n\n var done = this.async(); // Don't forget this!\n\n grunt.log.writeln(\"About to write a file...\");\n temp.open('tempfile', function(err, info) {\n // File writing shenanigans here\n grunt.log.writeln(\"Wrote a file!\")\n\n done(); // REALLY don't forget this!\n\n });\n });\n};\n```\n\nFor more information, see the [Grunt FAQ](http://gruntjs.com/frequently-asked-questions#why-doesn-t-my-asynchronous-task-complete).\n\nTesting\n-------\n\nFor now, run `test/temp-test.js`:\n\n $ node test/temp-test.js\n\nContributing\n------------\n\nYou can find the repository at:\nhttp://github.com/bruce/node-temp\n\nIssues/Feature Requests can be submitted at:\nhttp://github.com/bruce/node-temp/issues\n\nI'd really like to hear your feedback, and I'd love to receive your\npull-requests!\n\nCopyright\n---------\n\nCopyright (c) 2010-2012 Bruce Williams. See LICENSE for details.\n", + "readmeFilename": "README.md", + "bugs": { + "url": "https://github.com/bruce/node-temp/issues" + }, + "_id": "temp@0.6.0", + "dist": { + "shasum": "29d2d63697c79fb5108af11e1cba8edf097877bd" + }, + "_from": "temp@", + "_resolved": "https://registry.npmjs.org/temp/-/temp-0.6.0.tgz" +} diff --git a/src/extensibility/node/node_modules/temp/test/temp-test.js b/src/extensibility/node/node_modules/temp/test/temp-test.js new file mode 100644 index 00000000000..34071faf59c --- /dev/null +++ b/src/extensibility/node/node_modules/temp/test/temp-test.js @@ -0,0 +1,77 @@ +var assert = require('assert'); +var path = require('path'); +var fs = require('fs'); +var util = require('util'); + +var temp = require('../lib/temp'); +temp.track(); + +var existsSync = function(path){ + try { + fs.statSync(path); + return true; + } catch (e){ + return false; + } +}; + +// Use path.exists for 0.6 if necessary +var safeExists = fs.exists || path.exists; + +var mkdirFired = false; +var mkdirPath = null; +temp.mkdir('foo', function(err, tpath) { + mkdirFired = true; + assert.ok(!err, "temp.mkdir did not execute without errors"); + assert.ok(path.basename(tpath).slice(0, 3) == 'foo', 'temp.mkdir did not use the prefix'); + assert.ok(existsSync(tpath), 'temp.mkdir did not create the directory'); + + fs.writeFileSync(path.join(tpath, 'a file'), 'a content'); + temp.cleanup(); + assert.ok(!existsSync(tpath), 'temp.cleanup did not remove the directory'); + + mkdirPath = tpath; +}); + +var openFired = false; +var openPath = null; +temp.open('bar', function(err, info) { + openFired = true; + assert.equal('object', typeof(info), "temp.open did not invoke the callback with the err and info object"); + assert.equal('number', typeof(info.fd), 'temp.open did not invoke the callback with an fd'); + fs.writeSync(info.fd, 'foo'); + fs.closeSync(info.fd); + assert.equal('string', typeof(info.path), 'temp.open did not invoke the callback with a path'); + assert.ok(existsSync(info.path), 'temp.open did not create a file'); + + temp.cleanup(); + assert.ok(!existsSync(info.path), 'temp.cleanup did not remove the file'); + + openPath = info.path; +}); + + +var stream = temp.createWriteStream('baz'); +assert.ok(stream instanceof fs.WriteStream, "temp.createWriteStream did not invoke the callback with the err and stream object"); +stream.write('foo'); +stream.end("More text here\nand more..."); +assert.ok(existsSync(stream.path), 'temp.createWriteStream did not create a file'); + +console.log(temp.cleanup()); +assert.ok(!existsSync(stream.path), 'temp.cleanup did not remove the createWriteStream file'); + +var tempPath = temp.path(); +assert.ok(path.dirname(tempPath) === temp.dir, "temp.path does not work in default os temporary directory"); + +tempPath = temp.path({dir: process.cwd()}); +assert.ok(path.dirname(tempPath) === process.cwd(), "temp.path does not work in user-provided temporary directory"); + +for (var i=0; i <= 10; i++) { + temp.openSync(); +}; +assert.equal(process.listeners('exit').length, 1, 'temp created more than one listener for exit'); + +process.addListener('exit', function() { + assert.ok(mkdirFired, "temp.mkdir callback did not fire"); + assert.ok(openFired, "temp.open callback did not fire"); +}); diff --git a/src/extensibility/node/node_modules/tmp/README.md b/src/extensibility/node/node_modules/tmp/README.md deleted file mode 100644 index 3a1a509e9b2..00000000000 --- a/src/extensibility/node/node_modules/tmp/README.md +++ /dev/null @@ -1,162 +0,0 @@ -# Tmp - -A simple temporary file and directory creator for [node.js.][1] - -[![Build Status](https://secure.travis-ci.org/raszi/node-tmp.png?branch=master)](http://travis-ci.org/raszi/node-tmp) - -## About - -The main difference between bruce's [node-temp][2] is that mine more -aggressively checks for the existence of the newly created temporary file and -creates the new file with `O_EXCL` instead of simple `O_CREAT | O_RDRW`, so it -is safer. - -The API is slightly different as well, Tmp does not yet provide synchronous -calls and all the parameters are optional. - -You can set whether you want to remove the temporary file on process exit or -not, and the destination directory can also be set. - -## How to install - -```bash -npm install tmp -``` - -## Usage - -### File creation - -Simple temporary file creation, the file will be unlinked on process exit. - -```javascript -var tmp = require('tmp'); - -tmp.file(function _tempFileCreated(err, path, fd) { - if (err) throw err; - - console.log("File: ", path); - console.log("Filedescriptor: ", fd); -}); -``` - -### Directory creation - -Simple temporary directory creation, it will be removed on process exit. - -If the directory still contains items on process exit, then it won't be removed. - -```javascript -var tmp = require('tmp'); - -tmp.dir(function _tempDirCreated(err, path) { - if (err) throw err; - - console.log("Dir: ", path); -}); -``` - -If you want to cleanup the directory even when there are entries in it, then -you can pass the `unsafeCleanup` option when creating it. - -### Filename generation - -It is possible with this library to generate a unique filename in the specified -directory. - -```javascript -var tmp = require('tmp'); - -tmp.tmpName(function _tempNameGenerated(err, path) { - if (err) throw err; - - console.log("Created temporary filename: ", path); -}); -``` - -## Advanced usage - -### File creation - -Creates a file with mode `0644`, prefix will be `prefix-` and postfix will be `.txt`. - -```javascript -var tmp = require('tmp'); - -tmp.file({ mode: 0644, prefix: 'prefix-', postfix: '.txt' }, function _tempFileCreated(err, path, fd) { - if (err) throw err; - - console.log("File: ", path); - console.log("Filedescriptor: ", fd); -}); -``` - -### Directory creation - -Creates a directory with mode `0755`, prefix will be `myTmpDir_`. - -```javascript -var tmp = require('tmp'); - -tmp.dir({ mode: 0750, prefix: 'myTmpDir_' }, function _tempDirCreated(err, path) { - if (err) throw err; - - console.log("Dir: ", path); -}); -``` - -### mkstemps like - -Creates a new temporary directory with mode `0700` and filename like `/tmp/tmp-nk2J1u`. - -```javascript -var tmp = require('tmp'); - -tmp.dir({ template: '/tmp/tmp-XXXXXX' }, function _tempDirCreated(err, path) { - if (err) throw err; - - console.log("Dir: ", path); -}); -``` - -### Filename generation - -The `tmpName()` function accepts the `prefix`, `postfix`, `dir`, etc. parameters also: - -```javascript -var tmp = require('tmp'); - -tmp.tmpName({ template: '/tmp/tmp-XXXXXX' }, function _tempNameGenerated(err, path) { - if (err) throw err; - - console.log("Created temporary filename: ", path); -}); -``` - -## Graceful cleanup - -One may want to cleanup the temporary files even when an uncaught exception -occurs. To enforce this, you can call the `setGracefulCleanup()` method: - -```javascript -var tmp = require('tmp'); - -tmp.setGracefulCleanup(); -``` - -## Options - -All options are optional :) - - * `mode`: the file mode to create with, it fallbacks to `0600` on file creation and `0700` on directory creation - * `prefix`: the optional prefix, fallbacks to `tmp-` if not provided - * `postfix`: the optional postfix, fallbacks to `.tmp` on file creation - * `template`: [`mkstemps`][3] like filename template, no default - * `dir`: the optional temporary directory, fallbacks to system default (guesses from environment) - * `tries`: how many times should the function try to get a unique filename before giving up, default `3` - * `keep`: signals that the temporary file or directory should not be deleted on exit, default is `false`, means delete - * `unsafeCleanup`: recursively removes the created temporary directory, even when it's not empty. default is `false` - -[1]: http://nodejs.org/ -[2]: https://github.com/bruce/node-temp -[3]: http://www.kernel.org/doc/man-pages/online/pages/man3/mkstemp.3.html diff --git a/src/extensibility/node/node_modules/tmp/lib/tmp.js b/src/extensibility/node/node_modules/tmp/lib/tmp.js deleted file mode 100644 index 73cb03c1400..00000000000 --- a/src/extensibility/node/node_modules/tmp/lib/tmp.js +++ /dev/null @@ -1,273 +0,0 @@ -/*! - * Tmp - * - * Copyright (c) 2011-2013 KARASZI Istvan - * - * MIT Licensed - */ - -/** - * Module dependencies. - */ -var - fs = require('fs'), - path = require('path'), - os = require('os'), - exists = fs.exists || path.exists, - tmpDir = os.tmpDir || _getTMPDir, - _c = require('constants'); - -/** - * The working inner variables. - */ -var - // store the actual TMP directory - _TMP = tmpDir(), - - // the random characters to choose from - randomChars = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXTZabcdefghiklmnopqrstuvwxyz", - randomCharsLength = randomChars.length, - - // this will hold the objects need to be removed on exit - _removeObjects = [], - - _gracefulCleanup = false, - _uncaughtException = false; - -/** - * Gets the temp directory. - * - * @return {String} - * @api private - */ -function _getTMPDir() { - var tmpNames = [ 'TMPDIR', 'TMP', 'TEMP' ]; - - for (var i = 0, length = tmpNames.length; i < length; i++) { - if (_isUndefined(process.env[tmpNames[i]])) continue; - - return process.env[tmpNames[i]]; - } - - // fallback to the default - return '/tmp'; -} - -/** - * Checks whether the `obj` parameter is defined or not. - * - * @param {Object} obj - * @return {Boolean} - * @api private - */ -function _isUndefined(obj) { - return typeof obj === 'undefined'; -} - -/** - * Parses the function arguments. - * - * This function helps to have optional arguments. - * - * @param {Object} options - * @param {Function} callback - * @api private - */ -function _parseArguments(options, callback) { - if (!callback || typeof callback != "function") { - callback = options; - options = {}; - } - - return [ options, callback ]; -} - -/** - * Gets a temporary file name. - * - * @param {Object} opts - * @param {Function} cb - * @api private - */ -function _getTmpName(options, callback) { - var - args = _parseArguments(options, callback), - opts = args[0], - cb = args[1], - template = opts.template, - templateDefined = !_isUndefined(template), - tries = opts.tries || 3; - - if (isNaN(tries) || tries < 0) - return cb(new Error('Invalid tries')); - - if (templateDefined && !template.match(/XXXXXX/)) - return cb(new Error('Invalid template provided')); - - function _getName() { - - // prefix and postfix - if (!templateDefined) { - var name = [ - (_isUndefined(opts.prefix)) ? 'tmp-' : opts.prefix, - process.pid, - (Math.random() * 0x1000000000).toString(36), - opts.postfix - ].join(''); - - return path.join(opts.dir || _TMP, name); - } - - // mkstemps like template - var chars = []; - - for (var i = 0; i < 6; i++) { - chars.push(randomChars.substr(Math.floor(Math.random() * randomCharsLength), 1)); - } - - return template.replace(/XXXXXX/, chars.join('')); - } - - (function _getUniqueName() { - var name = _getName(); - - // check whether the path exists then retry if needed - exists(name, function _pathExists(pathExists) { - if (pathExists) { - if (tries-- > 0) return _getUniqueName(); - - return cb(new Error('Could not get a unique tmp filename, max tries reached')); - } - - cb(null, name); - }); - }()); -} - -/** - * Creates and opens a temporary file. - * - * @param {Object} options - * @param {Function} callback - * @api public - */ -function _createTmpFile(options, callback) { - var - args = _parseArguments(options, callback), - opts = args[0], - cb = args[1]; - - opts.postfix = (_isUndefined(opts.postfix)) ? '.tmp' : opts.postfix; - - // gets a temporary filename - _getTmpName(opts, function _tmpNameCreated(err, name) { - if (err) return cb(err); - - // create and open the file - fs.open(name, _c.O_CREAT | _c.O_EXCL | _c.O_RDWR, opts.mode || 0600, function _fileCreated(err, fd) { - if (err) return cb(err); - - if (!opts.keep) _removeObjects.unshift([ fs.unlinkSync, name ]); - - cb(null, name, fd); - }); - }); -} - -/** - * Removes files and folders in a directory recursively. - * - * @param {String} path - */ -function _rmdirRecursiveSync(dir) { - var files = fs.readdirSync(dir); - - for (var i = 0, length = files.length; i < length; i++) { - var file = path.join(dir, files[i]); - // lstat so we don't recurse into symlinked directories. - var stat = fs.lstatSync(file); - - if (stat.isDirectory()) { - _rmdirRecursiveSync(file); - } else { - fs.unlinkSync(file); - } - } - - fs.rmdirSync(dir); -} - -/** - * Creates a temporary directory. - * - * @param {Object} options - * @param {Function} callback - * @api public - */ -function _createTmpDir(options, callback) { - var - args = _parseArguments(options, callback), - opts = args[0], - cb = args[1]; - - // gets a temporary filename - _getTmpName(opts, function _tmpNameCreated(err, name) { - if (err) return cb(err); - - // create the directory - fs.mkdir(name, opts.mode || 0700, function _dirCreated(err) { - if (err) return cb(err); - - if (!opts.keep) { - if (opts.unsafeCleanup) { - _removeObjects.unshift([ _rmdirRecursiveSync, name ]); - } else { - _removeObjects.unshift([ fs.rmdirSync, name ]); - } - } - - cb(null, name); - }); - }); -} - -/** - * The garbage collector. - * - * @api private - */ -function _garbageCollector() { - if (_uncaughtException && !_gracefulCleanup) { - return; - } - - for (var i = 0, length = _removeObjects.length; i < length; i++) { - try { - _removeObjects[i][0].call(null, _removeObjects[i][1]); - } catch (e) { - // already removed? - } - } -} - -function _setGracefulCleanup() { - _gracefulCleanup = true; -} - -process.addListener('uncaughtException', function _uncaughtExceptionThrown( err ) { - _uncaughtException = true; - _garbageCollector(); - - throw err; -}); - -process.addListener('exit', function _exit() { - _garbageCollector(); -}); - -// exporting all the needed methods -module.exports.tmpdir = _TMP; -module.exports.dir = _createTmpDir; -module.exports.file = _createTmpFile; -module.exports.tmpName = _getTmpName; -module.exports.setGracefulCleanup = _setGracefulCleanup; diff --git a/src/extensibility/node/node_modules/tmp/package.json b/src/extensibility/node/node_modules/tmp/package.json deleted file mode 100644 index 96b18b61235..00000000000 --- a/src/extensibility/node/node_modules/tmp/package.json +++ /dev/null @@ -1,52 +0,0 @@ -{ - "name": "tmp", - "version": "0.0.21", - "description": "Temporary file and directory creator", - "author": { - "name": "KARASZI István", - "email": "github@spam.raszi.hu", - "url": "http://raszi.hu/" - }, - "homepage": "http://github.com/raszi/node-tmp", - "keywords": [ - "temporary", - "tmp", - "temp", - "tempdir", - "tempfile", - "tmpdir", - "tmpfile" - ], - "licenses": [ - { - "type": "MIT", - "url": "http://opensource.org/licenses/MIT" - } - ], - "repository": { - "type": "git", - "url": "git://github.com/raszi/node-tmp.git" - }, - "bugs": { - "url": "http://github.com/raszi/node-tmp/issues" - }, - "main": "lib/tmp.js", - "scripts": { - "test": "vows test/*-test.js" - }, - "engines": { - "node": ">=0.4.0" - }, - "dependencies": {}, - "devDependencies": { - "vows": "~0.7.0" - }, - "readme": "# Tmp\n\nA simple temporary file and directory creator for [node.js.][1]\n\n[![Build Status](https://secure.travis-ci.org/raszi/node-tmp.png?branch=master)](http://travis-ci.org/raszi/node-tmp)\n\n## About\n\nThe main difference between bruce's [node-temp][2] is that mine more\naggressively checks for the existence of the newly created temporary file and\ncreates the new file with `O_EXCL` instead of simple `O_CREAT | O_RDRW`, so it\nis safer.\n\nThe API is slightly different as well, Tmp does not yet provide synchronous\ncalls and all the parameters are optional.\n\nYou can set whether you want to remove the temporary file on process exit or\nnot, and the destination directory can also be set.\n\n## How to install\n\n```bash\nnpm install tmp\n```\n\n## Usage\n\n### File creation\n\nSimple temporary file creation, the file will be unlinked on process exit.\n\n```javascript\nvar tmp = require('tmp');\n\ntmp.file(function _tempFileCreated(err, path, fd) {\n if (err) throw err;\n\n console.log(\"File: \", path);\n console.log(\"Filedescriptor: \", fd);\n});\n```\n\n### Directory creation\n\nSimple temporary directory creation, it will be removed on process exit.\n\nIf the directory still contains items on process exit, then it won't be removed.\n\n```javascript\nvar tmp = require('tmp');\n\ntmp.dir(function _tempDirCreated(err, path) {\n if (err) throw err;\n\n console.log(\"Dir: \", path);\n});\n```\n\nIf you want to cleanup the directory even when there are entries in it, then\nyou can pass the `unsafeCleanup` option when creating it.\n\n### Filename generation\n\nIt is possible with this library to generate a unique filename in the specified\ndirectory.\n\n```javascript\nvar tmp = require('tmp');\n\ntmp.tmpName(function _tempNameGenerated(err, path) {\n if (err) throw err;\n\n console.log(\"Created temporary filename: \", path);\n});\n```\n\n## Advanced usage\n\n### File creation\n\nCreates a file with mode `0644`, prefix will be `prefix-` and postfix will be `.txt`.\n\n```javascript\nvar tmp = require('tmp');\n\ntmp.file({ mode: 0644, prefix: 'prefix-', postfix: '.txt' }, function _tempFileCreated(err, path, fd) {\n if (err) throw err;\n\n console.log(\"File: \", path);\n console.log(\"Filedescriptor: \", fd);\n});\n```\n\n### Directory creation\n\nCreates a directory with mode `0755`, prefix will be `myTmpDir_`.\n\n```javascript\nvar tmp = require('tmp');\n\ntmp.dir({ mode: 0750, prefix: 'myTmpDir_' }, function _tempDirCreated(err, path) {\n if (err) throw err;\n\n console.log(\"Dir: \", path);\n});\n```\n\n### mkstemps like\n\nCreates a new temporary directory with mode `0700` and filename like `/tmp/tmp-nk2J1u`.\n\n```javascript\nvar tmp = require('tmp');\n\ntmp.dir({ template: '/tmp/tmp-XXXXXX' }, function _tempDirCreated(err, path) {\n if (err) throw err;\n\n console.log(\"Dir: \", path);\n});\n```\n\n### Filename generation\n\nThe `tmpName()` function accepts the `prefix`, `postfix`, `dir`, etc. parameters also:\n\n```javascript\nvar tmp = require('tmp');\n\ntmp.tmpName({ template: '/tmp/tmp-XXXXXX' }, function _tempNameGenerated(err, path) {\n if (err) throw err;\n\n console.log(\"Created temporary filename: \", path);\n});\n```\n\n## Graceful cleanup\n\nOne may want to cleanup the temporary files even when an uncaught exception\noccurs. To enforce this, you can call the `setGracefulCleanup()` method:\n\n```javascript\nvar tmp = require('tmp');\n\ntmp.setGracefulCleanup();\n```\n\n## Options\n\nAll options are optional :)\n\n * `mode`: the file mode to create with, it fallbacks to `0600` on file creation and `0700` on directory creation\n * `prefix`: the optional prefix, fallbacks to `tmp-` if not provided\n * `postfix`: the optional postfix, fallbacks to `.tmp` on file creation\n * `template`: [`mkstemps`][3] like filename template, no default\n * `dir`: the optional temporary directory, fallbacks to system default (guesses from environment)\n * `tries`: how many times should the function try to get a unique filename before giving up, default `3`\n * `keep`: signals that the temporary file or directory should not be deleted on exit, default is `false`, means delete\n * `unsafeCleanup`: recursively removes the created temporary directory, even when it's not empty. default is `false`\n\n[1]: http://nodejs.org/\n[2]: https://github.com/bruce/node-temp\n[3]: http://www.kernel.org/doc/man-pages/online/pages/man3/mkstemp.3.html\n", - "readmeFilename": "README.md", - "_id": "tmp@0.0.21", - "dist": { - "shasum": "a21030368b57f1f439baae7f8c4c9344fa776053" - }, - "_from": "tmp@0.0.21", - "_resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.21.tgz" -} diff --git a/src/extensibility/node/node_modules/tmp/test-all.sh b/src/extensibility/node/node_modules/tmp/test-all.sh deleted file mode 100755 index 0fc42820034..00000000000 --- a/src/extensibility/node/node_modules/tmp/test-all.sh +++ /dev/null @@ -1,6 +0,0 @@ -#!/bin/bash - -for node in node06 node08 node; do - echo "Testing with $(${node} --version)..." - ${node} node_modules/vows/bin/vows test/*test.js -done diff --git a/src/extensibility/node/node_modules/tmp/test.js b/src/extensibility/node/node_modules/tmp/test.js deleted file mode 100644 index 8058221c4ab..00000000000 --- a/src/extensibility/node/node_modules/tmp/test.js +++ /dev/null @@ -1,6 +0,0 @@ -process.on('uncaughtException', function ( err ) { - console.log('blah'); - throw err; -}); - -throw "on purpose" diff --git a/src/extensibility/node/node_modules/tmp/test/base.js b/src/extensibility/node/node_modules/tmp/test/base.js deleted file mode 100644 index 498d8fb3b7f..00000000000 --- a/src/extensibility/node/node_modules/tmp/test/base.js +++ /dev/null @@ -1,74 +0,0 @@ -var - assert = require('assert'), - path = require('path'), - exec = require('child_process').exec; - -function _spawnTestWithError(testFile, params, cb) { - _spawnTest(true, testFile, params, cb); -} - -function _spawnTestWithoutError(testFile, params, cb) { - _spawnTest(false, testFile, params, cb); -} - -function _spawnTest(passError, testFile, params, cb) { - var - filename, - node_path = process.argv[0], - command = [ node_path, path.join(__dirname, testFile) ].concat(params).join(' '); - - exec(command, function _execDone(err, stdout, stderr) { - if (passError) { - if (err) { - return cb(err); - } else if (stderr.length > 0) { - return cb(stderr.toString()); - } - } - - return cb(null, stdout.toString()); - }); -} - -function _testStat(stat, mode) { - assert.equal(stat.uid, process.getuid(), 'should have the same UID'); - assert.equal(stat.gid, process.getgid(), 'should have the same GUID'); - assert.equal(stat.mode, mode); -} - -function _testPrefix(prefix) { - return function _testPrefixGenerated(err, name, fd) { - assert.equal(path.basename(name).slice(0, prefix.length), prefix, 'should have the provided prefix'); - }; -} - -function _testPostfix(postfix) { - return function _testPostfixGenerated(err, name, fd) { - assert.equal(name.slice(name.length - postfix.length, name.length), postfix, 'should have the provided postfix'); - }; -} - -function _testKeep(type, keep, cb) { - _spawnTestWithError('keep.js', [ type, keep ], cb); -} - -function _testGraceful(type, graceful, cb) { - _spawnTestWithoutError('graceful.js', [ type, graceful ], cb); -} - -function _assertName(err, name) { - assert.isString(name); - assert.isNotZero(name.length); -} - -function _testUnsafeCleanup(unsafe, cb) { - _spawnTestWithoutError('unsafe.js', [ 'dir', unsafe ], cb); -} - -module.exports.testStat = _testStat; -module.exports.testPrefix = _testPrefix; -module.exports.testPostfix = _testPostfix; -module.exports.testKeep = _testKeep; -module.exports.testGraceful = _testGraceful; -module.exports.assertName = _assertName; -module.exports.testUnsafeCleanup = _testUnsafeCleanup; diff --git a/src/extensibility/node/node_modules/tmp/test/dir-test.js b/src/extensibility/node/node_modules/tmp/test/dir-test.js deleted file mode 100644 index 9b890091223..00000000000 --- a/src/extensibility/node/node_modules/tmp/test/dir-test.js +++ /dev/null @@ -1,183 +0,0 @@ -var - vows = require('vows'), - assert = require('assert'), - - path = require('path'), - fs = require('fs'), - existsSync = fs.existsSync || path.existsSync, - - tmp = require('../lib/tmp.js'), - Test = require('./base.js'); - - -function _testDir(mode) { - return function _testDirGenerated(err, name) { - assert.ok(existsSync(name), 'should exist'); - - var stat = fs.statSync(name); - assert.ok(stat.isDirectory(), 'should be a directory'); - - Test.testStat(stat, mode); - }; -} - -vows.describe('Directory creation').addBatch({ - 'when using without parameters': { - topic: function () { - tmp.dir(this.callback); - }, - - 'should be a directory': _testDir(040700), - 'should have the default prefix': Test.testPrefix('tmp-') - }, - - 'when using with prefix': { - topic: function () { - tmp.dir({ prefix: 'something' }, this.callback); - }, - - 'should not return with an error': assert.isNull, - 'should return with a name': Test.assertName, - 'should be a directory': _testDir(040700), - 'should have the provided prefix': Test.testPrefix('something') - }, - - 'when using with postfix': { - topic: function () { - tmp.dir({ postfix: '.txt' }, this.callback); - }, - - 'should not return with an error': assert.isNull, - 'should return with a name': Test.assertName, - 'should be a directory': _testDir(040700), - 'should have the provided postfix': Test.testPostfix('.txt') - }, - - 'when using template': { - topic: function () { - tmp.dir({ template: path.join(tmp.tmpdir, 'clike-XXXXXX-postfix') }, this.callback); - }, - - 'should not return with error': assert.isNull, - 'should return with a name': Test.assertName, - 'should be a file': _testDir(040700), - 'should have the provided prefix': Test.testPrefix('clike-'), - 'should have the provided postfix': Test.testPostfix('-postfix') - }, - - 'when using multiple options': { - topic: function () { - tmp.dir({ prefix: 'foo', postfix: 'bar', mode: 0750 }, this.callback); - }, - - 'should not return with an error': assert.isNull, - 'should return with a name': Test.assertName, - 'should be a directory': _testDir(040750), - 'should have the provided prefix': Test.testPrefix('foo'), - 'should have the provided postfix': Test.testPostfix('bar') - }, - - 'when using multiple options and mode': { - topic: function () { - tmp.dir({ prefix: 'complicated', postfix: 'options', mode: 0755 }, this.callback); - }, - - 'should not return with an error': assert.isNull, - 'should return with a name': Test.assertName, - 'should be a directory': _testDir(040755), - 'should have the provided prefix': Test.testPrefix('complicated'), - 'should have the provided postfix': Test.testPostfix('options') - }, - - 'no tries': { - topic: function () { - tmp.dir({ tries: -1 }, this.callback); - }, - - 'should return with an error': assert.isObject - }, - - 'keep testing': { - topic: function () { - Test.testKeep('dir', '1', this.callback); - }, - - 'should not return with an error': assert.isNull, - 'should return with a name': Test.assertName, - 'should be a dir': function (err, name) { - _testDir(040700)(err, name); - fs.rmdirSync(name); - } - }, - - 'unlink testing': { - topic: function () { - Test.testKeep('dir', '0', this.callback); - }, - - 'should not return with error': assert.isNull, - 'should return with a name': Test.assertName, - 'should not exist': function (err, name) { - assert.ok(!existsSync(name), "Directory should be removed"); - } - }, - - 'non graceful testing': { - topic: function () { - Test.testGraceful('dir', '0', this.callback); - }, - - 'should not return with error': assert.isNull, - 'should return with a name': Test.assertName, - 'should be a dir': function (err, name) { - _testDir(040700)(err, name); - fs.rmdirSync(name); - } - }, - - 'graceful testing': { - topic: function () { - Test.testGraceful('dir', '1', this.callback); - }, - - 'should not return with an error': assert.isNull, - 'should return with a name': Test.assertName, - 'should not exist': function (err, name) { - assert.ok(!existsSync(name), "Directory should be removed"); - } - }, - - 'unsafeCleanup === true': { - topic: function () { - Test.testUnsafeCleanup('1', this.callback); - }, - - 'should not return with an error': assert.isNull, - 'should return with a name': Test.assertName, - 'should not exist': function (err, name) { - assert.ok(!existsSync(name), "Directory should be removed"); - }, - 'should remove symlinked dir': function(err, name) { - assert.ok( - !existsSync(name + '/symlinkme-target'), - 'should remove target' - ); - }, - 'should not remove contents of symlink dir': function(err, name) { - assert.ok( - existsSync(__dirname + '/symlinkme/file.js'), - 'should not remove symlinked directory\'s content' - ); - } - }, - - 'unsafeCleanup === false': { - topic: function () { - Test.testUnsafeCleanup('0', this.callback); - }, - - 'should not return with an error': assert.isNull, - 'should return with a name': Test.assertName, - 'should be a directory': _testDir(040700) - } -}).exportTo(module); diff --git a/src/extensibility/node/node_modules/tmp/test/file-test.js b/src/extensibility/node/node_modules/tmp/test/file-test.js deleted file mode 100644 index 150ca11f8c0..00000000000 --- a/src/extensibility/node/node_modules/tmp/test/file-test.js +++ /dev/null @@ -1,165 +0,0 @@ -var - vows = require('vows'), - assert = require('assert'), - - path = require('path'), - fs = require('fs'), - existsSync = fs.existsSync || path.existsSync, - - tmp = require('../lib/tmp.js'), - Test = require('./base.js'); - - -function _testFile(mode, fdTest) { - return function _testFileGenerated(err, name, fd) { - assert.ok(existsSync(name), 'should exist'); - - var stat = fs.statSync(name); - assert.equal(stat.size, 0, 'should have zero size'); - assert.ok(stat.isFile(), 'should be a file'); - - Test.testStat(stat, mode); - - // check with fstat as well (fd checking) - if (fdTest) { - var fstat = fs.fstatSync(fd); - assert.deepEqual(fstat, stat, 'fstat results should be the same'); - - var data = new Buffer('something'); - assert.equal(fs.writeSync(fd, data, 0, data.length, 0), data.length, 'should be writable'); - assert.ok(!fs.closeSync(fd), 'should not return with error'); - } - }; -} - -vows.describe('File creation').addBatch({ - 'when using without parameters': { - topic: function () { - tmp.file(this.callback); - }, - - 'should not return with an error': assert.isNull, - 'should return with a name': Test.assertName, - 'should be a file': _testFile(0100600, true), - 'should have the default prefix': Test.testPrefix('tmp-'), - 'should have the default postfix': Test.testPostfix('.tmp') - }, - - 'when using with prefix': { - topic: function () { - tmp.file({ prefix: 'something' }, this.callback); - }, - - 'should not return with an error': assert.isNull, - 'should return with a name': Test.assertName, - 'should be a file': _testFile(0100600, true), - 'should have the provided prefix': Test.testPrefix('something') - }, - - 'when using with postfix': { - topic: function () { - tmp.file({ postfix: '.txt' }, this.callback); - }, - - 'should not return with an error': assert.isNull, - 'should return with a name': Test.assertName, - 'should be a file': _testFile(0100600, true), - 'should have the provided postfix': Test.testPostfix('.txt') - - }, - - 'when using template': { - topic: function () { - tmp.file({ template: path.join(tmp.tmpdir, 'clike-XXXXXX-postfix') }, this.callback); - }, - - 'should not return with an error': assert.isNull, - 'should return with a name': Test.assertName, - 'should be a file': _testFile(0100600, true), - 'should have the provided prefix': Test.testPrefix('clike-'), - 'should have the provided postfix': Test.testPostfix('-postfix') - }, - - 'when using multiple options': { - topic: function () { - tmp.file({ prefix: 'foo', postfix: 'bar', mode: 0640 }, this.callback); - }, - - 'should not return with an error': assert.isNull, - 'should return with a name': Test.assertName, - 'should be a file': _testFile(0100640, true), - 'should have the provided prefix': Test.testPrefix('foo'), - 'should have the provided postfix': Test.testPostfix('bar') - }, - - 'when using multiple options and mode': { - topic: function () { - tmp.file({ prefix: 'complicated', postfix: 'options', mode: 0644 }, this.callback); - }, - - 'should not return with an error': assert.isNull, - 'should return with a name': Test.assertName, - 'should be a file': _testFile(0100644, true), - 'should have the provided prefix': Test.testPrefix('complicated'), - 'should have the provided postfix': Test.testPostfix('options') - }, - - 'no tries': { - topic: function () { - tmp.file({ tries: -1 }, this.callback); - }, - - 'should not be created': assert.isObject - }, - - 'keep testing': { - topic: function () { - Test.testKeep('file', '1', this.callback); - }, - - 'should not return with an error': assert.isNull, - 'should return with a name': Test.assertName, - 'should be a file': function (err, name) { - _testFile(0100600, false)(err, name, null); - fs.unlinkSync(name); - } - }, - - 'unlink testing': { - topic: function () { - Test.testKeep('file', '0', this.callback); - }, - - 'should not return with an error': assert.isNull, - 'should return with a name': Test.assertName, - 'should not exist': function (err, name) { - assert.ok(!existsSync(name), "File should be removed"); - } - }, - - 'non graceful testing': { - topic: function () { - Test.testGraceful('file', '0', this.callback); - }, - - 'should not return with error': assert.isNull, - 'should return with a name': Test.assertName, - 'should be a file': function (err, name) { - _testFile(0100600, false)(err, name, null); - fs.unlinkSync(name); - } - }, - - 'graceful testing': { - topic: function () { - Test.testGraceful('file', '1', this.callback); - }, - - 'should not return with an error': assert.isNull, - 'should return with a name': Test.assertName, - 'should not exist': function (err, name) { - assert.ok(!existsSync(name), "File should be removed"); - } - } - -}).exportTo(module); diff --git a/src/extensibility/node/node_modules/tmp/test/graceful.js b/src/extensibility/node/node_modules/tmp/test/graceful.js deleted file mode 100644 index c898656f326..00000000000 --- a/src/extensibility/node/node_modules/tmp/test/graceful.js +++ /dev/null @@ -1,15 +0,0 @@ -var - tmp = require('../lib/tmp'), - spawn = require('./spawn'); - -var graceful = spawn.arg; - -if (graceful) { - tmp.setGracefulCleanup(); -} - -spawn.tmpFunction(function (err, name) { - spawn.out(name, function () { - throw new Error("Thrown on purpose"); - }); -}); diff --git a/src/extensibility/node/node_modules/tmp/test/keep.js b/src/extensibility/node/node_modules/tmp/test/keep.js deleted file mode 100644 index 9538605dd83..00000000000 --- a/src/extensibility/node/node_modules/tmp/test/keep.js +++ /dev/null @@ -1,11 +0,0 @@ -var spawn = require('./spawn'); - -var keep = spawn.arg; - -spawn.tmpFunction({ keep: keep }, function (err, name) { - if (err) { - spawn.err(err, spawn.exit); - } else { - spawn.out(name, spawn.exit); - } -}); diff --git a/src/extensibility/node/node_modules/tmp/test/name-test.js b/src/extensibility/node/node_modules/tmp/test/name-test.js deleted file mode 100644 index a242c21b21a..00000000000 --- a/src/extensibility/node/node_modules/tmp/test/name-test.js +++ /dev/null @@ -1,82 +0,0 @@ -var - vows = require('vows'), - assert = require('assert'), - - path = require('path'), - - tmp = require('../lib/tmp.js'), - Test = require('./base.js'); - -vows.describe('Name creation').addBatch({ - 'when using without parameters': { - topic: function () { - tmp.tmpName(this.callback); - }, - - 'should not return with error': assert.isNull, - 'should have the default prefix': Test.testPrefix('tmp-') - }, - - 'when using with prefix': { - topic: function () { - tmp.tmpName({ prefix: 'something' }, this.callback); - }, - - 'should not return with error': assert.isNull, - 'should have the provided prefix': Test.testPrefix('something') - }, - - 'when using with postfix': { - topic: function () { - tmp.tmpName({ postfix: '.txt' }, this.callback); - }, - - 'should not return with error': assert.isNull, - 'should have the provided postfix': Test.testPostfix('.txt') - - }, - - 'when using template': { - topic: function () { - tmp.tmpName({ template: path.join(tmp.tmpdir, 'clike-XXXXXX-postfix') }, this.callback); - }, - - 'should not return with error': assert.isNull, - 'should have the provided prefix': Test.testPrefix('clike-'), - 'should have the provided postfix': Test.testPostfix('-postfix'), - 'should have template filled': function (err, name) { - assert.isTrue(/[a-zA-Z0-9]{6}/.test(name)); - } - }, - - 'when using multiple options': { - topic: function () { - tmp.tmpName({ prefix: 'foo', postfix: 'bar', tries: 5 }, this.callback); - }, - - 'should not return with error': assert.isNull, - 'should have the provided prefix': Test.testPrefix('foo'), - 'should have the provided postfix': Test.testPostfix('bar') - }, - - 'no tries': { - topic: function () { - tmp.tmpName({ tries: -1 }, this.callback); - }, - - 'should fail': function (err, name) { - assert.isObject(err); - } - }, - - 'tries not numeric': { - topic: function () { - tmp.tmpName({ tries: 'hello'}, this.callback); - }, - - 'should fail': function (err, name) { - assert.isObject(err); - } - } - -}).exportTo(module); diff --git a/src/extensibility/node/node_modules/tmp/test/spawn.js b/src/extensibility/node/node_modules/tmp/test/spawn.js deleted file mode 100644 index 6468eb39e6f..00000000000 --- a/src/extensibility/node/node_modules/tmp/test/spawn.js +++ /dev/null @@ -1,32 +0,0 @@ -var - fs = require('fs'), - tmp = require('../lib/tmp'); - -function _writeSync(stream, str, cb) { - var flushed = stream.write(str); - if (flushed) { - return cb(null); - } - - stream.once('drain', function _flushed() { - cb(null); - }); -} - -module.exports.out = function (str, cb) { - _writeSync(process.stdout, str, cb); -}; - -module.exports.err = function (str, cb) { - _writeSync(process.stderr, str, cb); -}; - -module.exports.exit = function () { - process.exit(0); -}; - -var type = process.argv[2]; -module.exports.tmpFunction = (type == 'file') ? tmp.file : tmp.dir; - -var arg = (process.argv[3] && parseInt(process.argv[3], 10) === 1) ? true : false; -module.exports.arg = arg; diff --git a/src/extensibility/node/node_modules/tmp/test/symlinkme/file.js b/src/extensibility/node/node_modules/tmp/test/symlinkme/file.js deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/src/extensibility/node/node_modules/tmp/test/unsafe.js b/src/extensibility/node/node_modules/tmp/test/unsafe.js deleted file mode 100644 index 73e4fb34e59..00000000000 --- a/src/extensibility/node/node_modules/tmp/test/unsafe.js +++ /dev/null @@ -1,30 +0,0 @@ -var - fs = require('fs'), - join = require('path').join, - spawn = require('./spawn'); - -var unsafe = spawn.arg; -spawn.tmpFunction({ unsafeCleanup: unsafe }, function (err, name) { - if (err) { - spawn.err(err, spawn.exit); - return; - } - - try { - // file that should be removed - var fd = fs.openSync(join(name, 'should-be-removed.file'), 'w'); - fs.closeSync(fd); - - // in tree source - var symlinkSource = join(__dirname, 'symlinkme'); - // testing target - var symlinkTarget = join(name, 'symlinkme-target'); - - // symlink that should be removed but the contents should be preserved. - fs.symlinkSync(symlinkSource, symlinkTarget, 'dir'); - - spawn.out(name, spawn.exit); - } catch (e) { - spawn.err(e.toString(), spawn.exit); - } -}); diff --git a/src/extensibility/node/package.json b/src/extensibility/node/package.json index 8d1b2780921..9ed0d85db29 100644 --- a/src/extensibility/node/package.json +++ b/src/extensibility/node/package.json @@ -1,16 +1,16 @@ { - "name": "brackets-extensibility", - "description": "Used in the management of Brackets extensions", - "version": "0.32.0", - "dependencies": { - "decompress-zip": "0.0.1", - "tmp": "0.0.21", - "semver": "2.x", - "fs-extra": "0.6.x", - "async": "0.2.x", - "request": "2.27.x" - }, - "devDependencies": { - "rewire": "1.1.x" - } + "name": "brackets-extensibility", + "description": "Used in the management of Brackets extensions", + "version": "0.32.0", + "dependencies": { + "decompress-zip": "0.0.1", + "semver": "2.x", + "fs-extra": "0.6.x", + "async": "0.2.x", + "request": "2.27.x", + "temp": "~0.6.0" + }, + "devDependencies": { + "rewire": "1.1.x" + } } From 0f714618f4c69559b4b8b076a71bfa65a4806df5 Mon Sep 17 00:00:00 2001 From: Kevin Dangoor Date: Tue, 24 Sep 2013 22:45:52 -0400 Subject: [PATCH 26/56] Change code to use temp package for temp file generation --- .../node/ExtensionManagerDomain.js | 36 ++++++------------- src/extensibility/node/package-validator.js | 9 +++-- .../node/spec/Validation.spec.js | 10 ++++-- 3 files changed, 22 insertions(+), 33 deletions(-) diff --git a/src/extensibility/node/ExtensionManagerDomain.js b/src/extensibility/node/ExtensionManagerDomain.js index e29e776e2a3..42427beafcd 100644 --- a/src/extensibility/node/ExtensionManagerDomain.js +++ b/src/extensibility/node/ExtensionManagerDomain.js @@ -33,8 +33,11 @@ var semver = require("semver"), request = require("request"), os = require("os"), fs = require("fs-extra"), + temp = require("temp"), validate = require("./package-validator").validate; +// Automatically clean up temp files on exit +temp.track(); var Errors = { API_NOT_COMPATIBLE: "API_NOT_COMPATIBLE", @@ -100,9 +103,10 @@ function _performInstall(packagePath, installDirectory, validationResult, callba var sourceDir = path.join(validationResult.extractDir, validationResult.commonPrefix); fs.copy(sourceDir, installDirectory, function (err) { + // We're done with the temporary directory used for extraction + fs.remove(validationResult.extractDir); if (err) { _removeFailedInstallation(installDirectory); - fs.remove(validationResult.extractDir); callback(err, null); } else { // The status may have already been set previously (as in the @@ -329,26 +333,6 @@ function _cmdUpdate(packagePath, destinationDirectory, options, callback) { _cmdInstall(packagePath, destinationDirectory, options, callback, true); } -/** - * Creates a uniquely-named file in the OS temp directory and opens it for writing. - * @return {{localPath: string, outStream: WriteStream}} - */ -function _createTempFile() { - var root = os.tmpDir(); - var pathPrefix = root + "/brackets.download"; - var suffix = 1; - while (fs.existsSync(pathPrefix + suffix) && suffix < 100) { - suffix++; - } - if (suffix === 100) { - return null; - } - - var localPath = pathPrefix + suffix; - var outStream = fs.createWriteStream(localPath); - return { outStream: outStream, localPath: localPath }; -} - /** * Wrap up after the given download has terminated (successfully or not). Closes connections, calls back the * client's callback, and IF there was an error, delete any partially-downloaded file. @@ -409,15 +393,15 @@ function _cmdDownloadFile(downloadId, url, callback) { return; } - var tempFileInfo = _createTempFile(); - if (!tempFileInfo) { + var stream = temp.createWriteStream("brackets"); + if (!stream) { _endDownload(downloadId, Errors.CANNOT_WRITE_TEMP); return; } - pendingDownloads[downloadId].localPath = tempFileInfo.localPath; - pendingDownloads[downloadId].outStream = tempFileInfo.outStream; + pendingDownloads[downloadId].localPath = stream.path; + pendingDownloads[downloadId].outStream = stream; - tempFileInfo.outStream.write(body); + stream.write(body); _endDownload(downloadId); }); diff --git a/src/extensibility/node/package-validator.js b/src/extensibility/node/package-validator.js index 38dcc7cdaac..b50db228a83 100644 --- a/src/extensibility/node/package-validator.js +++ b/src/extensibility/node/package-validator.js @@ -33,9 +33,11 @@ var DecompressZip = require("decompress-zip"), http = require("http"), request = require("request"), os = require("os"), - tmp = require("tmp"), + temp = require("temp"), fs = require("fs-extra"); +// Track and cleanup files at exit +temp.track(); var Errors = { NOT_FOUND_ERR: "NOT_FOUND_ERR", // {0} is path where ZIP file was expected @@ -335,10 +337,7 @@ function validate(path, options, callback) { }); return; } - tmp.dir({ - prefix: "bracketsPackage_", - unsafeCleanup: true - }, function _tempDirCreated(err, extractDir) { + temp.mkdir("bracketsPackage_", function _tempDirCreated(err, extractDir) { if (err) { callback(err, null); return; diff --git a/src/extensibility/node/spec/Validation.spec.js b/src/extensibility/node/spec/Validation.spec.js index caf5555016b..ccaf1371803 100644 --- a/src/extensibility/node/spec/Validation.spec.js +++ b/src/extensibility/node/spec/Validation.spec.js @@ -24,13 +24,14 @@ /*jslint vars: true, plusplus: true, devel: true, node: true, nomen: true, indent: 4, maxerr: 50 */ -/*global expect, describe, it */ +/*global expect, describe, it, afterEach */ "use strict"; var rewire = require("rewire"), packageValidator = rewire("../package-validator"), - path = require("path"); + path = require("path"), + temp = require("temp"); var testFilesDirectory = path.join(path.dirname(module.filename), "..", // node @@ -56,6 +57,11 @@ var basicValidExtension = path.join(testFilesDirectory, "basic-valid-extensio invalidBracketsVersion = path.join(testFilesDirectory, "invalid-brackets-version.zip"); describe("Package Validation", function () { + + afterEach(function () { + temp.cleanup(); + }); + it("should handle a good package", function (done) { packageValidator.validate(basicValidExtension, {}, function (err, result) { expect(err).toBeNull(); From a9a8e47ed30419499df90185cbe6dda124ce1789 Mon Sep 17 00:00:00 2001 From: Lance Campbell Date: Tue, 24 Sep 2013 21:56:34 -0700 Subject: [PATCH 27/56] API changes --- test/spec/Menu-test.js | 12 ++++++++---- test/spec/SpecRunnerUtils.js | 22 +++++----------------- 2 files changed, 13 insertions(+), 21 deletions(-) diff --git a/test/spec/Menu-test.js b/test/spec/Menu-test.js index 780ed23dcef..bbfe63932d8 100644 --- a/test/spec/Menu-test.js +++ b/test/spec/Menu-test.js @@ -43,8 +43,10 @@ define(function (require, exports, module) { var testWindow; beforeFirst(function () { + var testWindowOptions = {"hasNativeMenus" : true}; + // Create a new native menu window that will be shared by ALL tests in this spec. - SpecRunnerUtils.createNativeTestWindowAndRun(this, function (w) { + SpecRunnerUtils.createTestWindowAndRun(this, function (w) { testWindow = w; // Load module instances from brackets.test @@ -52,7 +54,7 @@ define(function (require, exports, module) { Commands = testWindow.brackets.test.Commands; KeyBindingManager = testWindow.brackets.test.KeyBindingManager; Menus = testWindow.brackets.test.Menus; - }); + }, testWindowOptions); }); afterLast(function () { @@ -218,8 +220,10 @@ define(function (require, exports, module) { var testWindow; beforeFirst(function () { + var testWindowOptions = {"hasNativeMenus" : false}; + // Create a new HTML menu window that will be shared by ALL tests in this spec. - SpecRunnerUtils.createHTMLTestWindowAndRun(this, function (w) { + SpecRunnerUtils.createTestWindowAndRun(this, function (w) { testWindow = w; // Load module instances from brackets.test @@ -227,7 +231,7 @@ define(function (require, exports, module) { Commands = testWindow.brackets.test.Commands; KeyBindingManager = testWindow.brackets.test.KeyBindingManager; Menus = testWindow.brackets.test.Menus; - }); + }, testWindowOptions); }); afterLast(function () { diff --git a/test/spec/SpecRunnerUtils.js b/test/spec/SpecRunnerUtils.js index 3b2362dcba5..1eb326703a6 100644 --- a/test/spec/SpecRunnerUtils.js +++ b/test/spec/SpecRunnerUtils.js @@ -476,7 +476,7 @@ define(function (require, exports, module) { waitsForDone(promise, "dismiss dialog"); } - function _createTestWindowAndRun(spec, hasNativeMenus, callback) { + function createTestWindowAndRun(spec, callback, options) { runs(function () { // Position popup windows in the lower right so they're out of the way var testWindowWid = 1000, @@ -502,8 +502,10 @@ define(function (require, exports, module) { // disable initial dialog for live development params.put("skipLiveDevelopmentInfo", true); - // determines if test window should have native or html menus - params.put("hasNativeMenus", hasNativeMenus); + // option to launch test window with either native or HTML menus + if (options && options.hasOwnProperty("hasNativeMenus")) { + params.put("hasNativeMenus", options.hasNativeMenus); + } _testWindow = window.open(getBracketsSourceRoot() + "/index.html?" + params.toString(), "_blank", optionsStr); @@ -542,18 +544,6 @@ define(function (require, exports, module) { }); } - function createTestWindowAndRun(spec, callback) { - _createTestWindowAndRun(spec, brackets.nativeMenus, callback); - } - - function createHTMLTestWindowAndRun(spec, callback) { - _createTestWindowAndRun(spec, false, callback); - } - - function createNativeTestWindowAndRun(spec, callback) { - _createTestWindowAndRun(spec, true, callback); - } - function closeTestWindow() { // debug-only to see testWindow state before closing // waits(500); @@ -1282,8 +1272,6 @@ define(function (require, exports, module) { exports.createMockEditorForDocument = createMockEditorForDocument; exports.createMockEditor = createMockEditor; exports.createTestWindowAndRun = createTestWindowAndRun; - exports.createHTMLTestWindowAndRun = createHTMLTestWindowAndRun; - exports.createNativeTestWindowAndRun = createNativeTestWindowAndRun; exports.closeTestWindow = closeTestWindow; exports.clickDialogButton = clickDialogButton; exports.destroyMockEditor = destroyMockEditor; From 8a48a0b455ac5fd0967bfc81f590b59ef7e8db5b Mon Sep 17 00:00:00 2001 From: Neil Stansbury Date: Wed, 25 Sep 2013 14:55:53 +0100 Subject: [PATCH 28/56] Added .jsm extension for Mozilla JavaScript Module support --- src/language/languages.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/language/languages.json b/src/language/languages.json index 9ab2d31e596..596aefee46b 100644 --- a/src/language/languages.json +++ b/src/language/languages.json @@ -57,7 +57,7 @@ "javascript": { "name": "JavaScript", "mode": "javascript", - "fileExtensions": ["js", "jsx", "js.erb"], + "fileExtensions": ["js", "jsx", "js.erb", "jsm"], "blockComment": ["/*", "*/"], "lineComment": ["//"] }, From 87fd4ba8959e4716c562e895ed7130f270fc6aff Mon Sep 17 00:00:00 2001 From: Kevin Dangoor Date: Wed, 25 Sep 2013 09:59:02 -0400 Subject: [PATCH 29/56] Add code to consistently delete the temporary extraction directory during install. --- .../node/ExtensionManagerDomain.js | 29 ++++++++++++------- 1 file changed, 19 insertions(+), 10 deletions(-) diff --git a/src/extensibility/node/ExtensionManagerDomain.js b/src/extensibility/node/ExtensionManagerDomain.js index 42427beafcd..4e35e99ba02 100644 --- a/src/extensibility/node/ExtensionManagerDomain.js +++ b/src/extensibility/node/ExtensionManagerDomain.js @@ -103,8 +103,6 @@ function _performInstall(packagePath, installDirectory, validationResult, callba var sourceDir = path.join(validationResult.extractDir, validationResult.commonPrefix); fs.copy(sourceDir, installDirectory, function (err) { - // We're done with the temporary directory used for extraction - fs.remove(validationResult.extractDir); if (err) { _removeFailedInstallation(installDirectory); callback(err, null); @@ -221,10 +219,21 @@ function _cmdInstall(packagePath, destinationDirectory, options, callback, _doUp var validateCallback = function (err, validationResult) { validationResult.localPath = packagePath; + + // This is a wrapper for the callback that will delete the temporary + // directory to which the package was unzipped. + function deleteTempAndCallback(err) { + if (validationResult.extractDir) { + fs.remove(validationResult.extractDir); + delete validationResult.extractDir; + } + callback(err, validationResult); + } + // If there was trouble at the validation stage, we stop right away. if (err || validationResult.errors.length > 0) { validationResult.installationStatus = Statuses.FAILED; - callback(err, validationResult); + deleteTempAndCallback(err, validationResult); return; } @@ -255,7 +264,7 @@ function _cmdInstall(packagePath, destinationDirectory, options, callback, _doUp installDirectory = path.join(options.disabledDirectory, extensionName); validationResult.installationStatus = Statuses.DISABLED; validationResult.disabledReason = Errors.API_NOT_COMPATIBLE; - _removeAndInstall(packagePath, installDirectory, validationResult, callback); + _removeAndInstall(packagePath, installDirectory, validationResult, deleteTempAndCallback); return; } } @@ -275,25 +284,25 @@ function _cmdInstall(packagePath, destinationDirectory, options, callback, _doUp // both legacy and new extensions installed. fs.remove(legacyDirectory, function (err) { if (err) { - callback(err); + deleteTempAndCallback(err, validationResult); return; } - _removeAndInstall(packagePath, installDirectory, validationResult, callback); + _removeAndInstall(packagePath, installDirectory, validationResult, deleteTempAndCallback); }); } else { - _removeAndInstall(packagePath, installDirectory, validationResult, callback); + _removeAndInstall(packagePath, installDirectory, validationResult, deleteTempAndCallback); } } else if (hasLegacyPackage) { validationResult.installationStatus = Statuses.NEEDS_UPDATE; validationResult.name = guessedName; - callback(null, validationResult); + deleteTempAndCallback(null, validationResult); } else { - _checkExistingInstallation(validationResult, installDirectory, systemInstallDirectory, callback); + _checkExistingInstallation(validationResult, installDirectory, systemInstallDirectory, deleteTempAndCallback); } } else { // Regular installation with no conflicts. validationResult.disabledReason = null; - _performInstall(packagePath, installDirectory, validationResult, callback); + _performInstall(packagePath, installDirectory, validationResult, deleteTempAndCallback); } }; From f7ee396a9759ed7293b569bd2e8765ca7536efcd Mon Sep 17 00:00:00 2001 From: Randy Edmunds Date: Wed, 25 Sep 2013 09:49:15 -0700 Subject: [PATCH 30/56] only need to handle closeOk and close events --- src/search/FindReplace.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/search/FindReplace.js b/src/search/FindReplace.js index d6fa88ea725..ff73062012b 100644 --- a/src/search/FindReplace.js +++ b/src/search/FindReplace.js @@ -329,7 +329,7 @@ define(function (require, exports, module) { findFirst(query); } }); - $(modalBar).on("closeOk closeCancel closeBlur close", function (e, query) { + $(modalBar).on("closeOk close", function (e, query) { // Clear highlights but leave search state in place so Find Next/Previous work after closing clearHighlights(cm, state); From 0fb6c87605331708dab80222f3e4540380399a43 Mon Sep 17 00:00:00 2001 From: Bernhard Sirlinger Date: Wed, 25 Sep 2013 22:19:20 +0200 Subject: [PATCH 31/56] Fix unit test failures --- test/SpecRunner.js | 33 +++++++++++++++++---------------- test/UnitTestSuite.js | 24 ++++++++++++------------ test/spec/CodeHint-test.js | 28 ++++++++++++++-------------- 3 files changed, 43 insertions(+), 42 deletions(-) diff --git a/test/SpecRunner.js b/test/SpecRunner.js index 212edeafee0..e0586aa081e 100644 --- a/test/SpecRunner.js +++ b/test/SpecRunner.js @@ -1,24 +1,24 @@ /* * Copyright (c) 2012 Adobe Systems Incorporated. All rights reserved. - * + * * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: - * + * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. - * + * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER * DEALINGS IN THE SOFTWARE. - * + * */ /*jslint vars: true, plusplus: true, devel: true, browser: true, nomen: true, indent: 4, maxerr: 50 */ @@ -53,8 +53,9 @@ define(function (require, exports, module) { NodeConnection = require("utils/NodeConnection"), BootstrapReporterView = require("test/BootstrapReporterView").BootstrapReporterView, ColorUtils = require("utils/ColorUtils"), - NativeApp = require("utils/NativeApp"); - + NativeApp = require("utils/NativeApp"), + CodeHintManager = require("editor/CodeHintManager"); + // Load modules that self-register and just need to get included in the main project require("document/ChangedDocumentTracker"); @@ -167,7 +168,7 @@ define(function (require, exports, module) { /** * Listener for UnitTestReporter "runnerEnd" event. Attached only if * "resultsPath" URL parameter exists. Does not overwrite existing file. - * + * * @param {!$.Event} event * @param {!UnitTestReporter} reporter */ @@ -263,7 +264,7 @@ define(function (require, exports, module) { function init() { // Start up the node connection, which is held in the - // _nodeConnectionDeferred module variable. (Use + // _nodeConnectionDeferred module variable. (Use // _nodeConnectionDeferred.done() to access it. // This is in SpecRunner rather than SpecRunnerUtils because the hope diff --git a/test/UnitTestSuite.js b/test/UnitTestSuite.js index b1b43bbf9a9..3a409b593a3 100644 --- a/test/UnitTestSuite.js +++ b/test/UnitTestSuite.js @@ -1,24 +1,24 @@ /* * Copyright (c) 2012 Adobe Systems Incorporated. All rights reserved. - * + * * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: - * + * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. - * + * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER * DEALINGS IN THE SOFTWARE. - * + * */ /*jslint vars: true, plusplus: true, devel: true, browser: true, nomen: true, indent: 4, maxerr: 50 */ diff --git a/test/spec/CodeHint-test.js b/test/spec/CodeHint-test.js index ea161cc55da..6cedb11cfde 100644 --- a/test/spec/CodeHint-test.js +++ b/test/spec/CodeHint-test.js @@ -1,24 +1,24 @@ /* * Copyright (c) 2012 Adobe Systems Incorporated. All rights reserved. - * + * * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: - * + * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. - * + * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER * DEALINGS IN THE SOFTWARE. - * + * */ /*jslint vars: true, plusplus: true, devel: true, browser: true, nomen: true, indent: 4, maxerr: 50 */ @@ -46,7 +46,7 @@ define(function (require, exports, module) { /** * Performs setup for a code hint test. Opens a file and set pos. - * + * * @param {!string} openFile Project relative file path to open in a main editor. * @param {!number} openPos The pos within openFile to place the IP. */ @@ -318,7 +318,7 @@ define(function (require, exports, module) { preventDefault: function () { } }); - // Verify that after the keydown, the session is closed + // Verify that after the keydown, the session is closed // (not just the hint popup). Because of #1381, we don't // actually have a way to close the session as soon as the // popup is dismissed by Bootstrap, so we do so on the next From 62e4f4d7eed0d2d86a51ab15e85b259d574e9207 Mon Sep 17 00:00:00 2001 From: Ingo Richter Date: Wed, 25 Sep 2013 16:05:54 -0700 Subject: [PATCH 32/56] Return the result of calling the original jquery focus() function This commit https://github.com/adobe/brackets/commit/8e5ad957333593fb5b6bc4f73d4c3121da811682 fixed a focus issue with HTML menus. On Linux (where we still use HTML menues), the new implementation of focus didn't return the result when calling the original jquery focus implementation. The result was an error opening modal dialogs like Extension Manager, About Box, etc. The dialogs didn't work properly anymore due to this error: "Uncaught TypeError: Cannot call method 'trigger' of undefined" in bootstrap- modal.js This fix returns the result from calling the original focus function. --- src/brackets.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/brackets.js b/src/brackets.js index ed125580826..3ec5ab61e52 100644 --- a/src/brackets.js +++ b/src/brackets.js @@ -289,7 +289,7 @@ define(function (require, exports, module) { var defaultFocus = $.fn.focus; $.fn.focus = function () { if (!this.hasClass("dropdown-toggle")) { - defaultFocus.apply(this, arguments); + return defaultFocus.apply(this, arguments); } }; }()); From 5964282a5055ed126bed30ce31691f49fb7762c5 Mon Sep 17 00:00:00 2001 From: Arzhan Kinzhalin Date: Wed, 25 Sep 2013 22:00:36 -0300 Subject: [PATCH 33/56] Amend PR #5311 with an comment and issue ref. As per discussion in PR #5311, related to issue #5310. --- src/brackets.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/brackets.js b/src/brackets.js index ed125580826..c8f28d3cfa3 100644 --- a/src/brackets.js +++ b/src/brackets.js @@ -284,7 +284,8 @@ define(function (require, exports, module) { if (brackets.nativeMenus) { $("body").addClass("has-appshell-menus"); } else { - // Prevent the menu item to grab the focus -- override focus implementation + // (issue #5310) workaround for bootstrap dropdown: prevent the menu item to grab + // the focus -- override jquery focus implementation for top-level menu items (function () { var defaultFocus = $.fn.focus; $.fn.focus = function () { From 9087fb680e6d40ff8f2f2dff62ded0c503deb97d Mon Sep 17 00:00:00 2001 From: Narciso Jaramillo Date: Wed, 25 Sep 2013 18:11:56 -0700 Subject: [PATCH 34/56] When switching documents from QuickOpen, pop the modal bar out before switching and animate after --- src/search/QuickOpen.js | 19 +++++++-- src/styles/brackets.less | 84 +++++++++++++++++++++------------------- src/widgets/ModalBar.js | 78 +++++++++++++++++++++++++------------ 3 files changed, 112 insertions(+), 69 deletions(-) diff --git a/src/search/QuickOpen.js b/src/search/QuickOpen.js index 93e2c51e1e9..2131dc99c77 100644 --- a/src/search/QuickOpen.js +++ b/src/search/QuickOpen.js @@ -309,7 +309,9 @@ define(function (require, exports, module) { selectedDOMItem = $(".smart_autocomplete_container > li:first-child").get(0); } - var selectedItem = domItemToSearchResult(selectedDOMItem); + var selectedItem = domItemToSearchResult(selectedDOMItem), + doClose = true, + self = this; // Delegate to current plugin if (currentPlugin) { @@ -323,21 +325,30 @@ define(function (require, exports, module) { // Navigate to file and line number var fullPath = selectedItem && selectedItem.fullPath; if (fullPath) { + // This case is tricky. We want to switch editors, so we need to deal with + // resizing/rescrolling the current editor first. But we don't actually want + // to start the animation of the ModalBar until afterward (otherwise it glitches + // because it gets starved of cycles during the creation of the new editor). + // So we call `prepareClose()` first, and finish the close later. + doClose = false; + this.modalBar.prepareClose(); CommandManager.execute(Commands.FILE_ADD_TO_WORKING_SET, {fullPath: fullPath}) .done(function () { if (!isNaN(gotoLine)) { var editor = EditorManager.getCurrentFullEditor(); editor.setCursorPos(gotoLine, 0, true); } + self.close(); }); } else if (!isNaN(gotoLine)) { EditorManager.getCurrentFullEditor().setCursorPos(gotoLine, 0, true); } } - - this.close(); - EditorManager.focusEditor(); + if (doClose) { + this.close(); + EditorManager.focusEditor(); + } }; /** diff --git a/src/styles/brackets.less b/src/styles/brackets.less index 99b256a4236..4cf338cfda3 100644 --- a/src/styles/brackets.less +++ b/src/styles/brackets.less @@ -840,21 +840,6 @@ a, img { /* Modal bar for Find/Quick Open */ -.modal-bar.modal-bar-hide { - position: absolute; - left: 0; - right: 0; - top: 0; - -webkit-transform: translate(0, -44px); - transform: translate(0, -44px); - transition: -webkit-transform 266ms cubic-bezier(0, 0.56, 0, 1); - transition: transform 266ms cubic-bezier(0, 0.56, 0, 1); - - body:not(.has-appshell-menus) & { - top: 37px; - } -} - .modal-bar { display: block; text-align: left; @@ -875,37 +860,56 @@ a, img { // Separator line between us and the HTML menu/titlebar above border-top: 1px solid darken(@background-color-3, @bc-color-step-size); } -} + + &.popout { + position: absolute; + left: 0; + right: 0; + top: 0; + } + + &.offscreen { + -webkit-transform: translate(0, -44px); + transform: translate(0, -44px); + transition: -webkit-transform 266ms cubic-bezier(0, 0.56, 0, 1); + transition: transform 266ms cubic-bezier(0, 0.56, 0, 1); + + body:not(.has-appshell-menus) & { + top: 37px; + } + } -.modal-bar input { - font-family: @sansFontFamily; - outline: none; - width: 20em; - margin: 5px 5px 0; - position: relative; - top: -3px; - &.no-results { - border: 1px solid #bc0023; - box-shadow: inset 0 1px 0 rgba(0, 0, 0, 0.12), 0 0 0 2px rgba(255, 0, 120, 0.5); + input { + font-family: @sansFontFamily; + outline: none; + width: 20em; + margin: 5px 5px 0; + position: relative; + top: -3px; + &.no-results { + border: 1px solid #bc0023; + box-shadow: inset 0 1px 0 rgba(0, 0, 0, 0.12), 0 0 0 2px rgba(255, 0, 120, 0.5); + } } -} -.modal-bar .message { - display: inline-block; -} -.modal-bar .error { - display: none; + .message { + display: inline-block; + } - .alert { - padding-top: 4px; - padding-bottom: 4px; + .error { + display: none; + + .alert { + padding-top: 4px; + padding-bottom: 4px; + } } -} -.modal-bar .navigator { - display: none; - button { - margin: 2px 1px 3px; + .navigator { + display: none; + button { + margin: 2px 1px 3px; + } } } diff --git a/src/widgets/ModalBar.js b/src/widgets/ModalBar.js index 63b8c08d707..7697b311d30 100644 --- a/src/widgets/ModalBar.js +++ b/src/widgets/ModalBar.js @@ -61,11 +61,11 @@ define(function (require, exports, module) { .insertBefore("#editor-holder"); if (animate) { - this._$root.addClass("modal-bar-hide"); - // Forcing the renderer to do a layout, which will cause it to apply the transform for the "modal-bar-hide" + this._$root.addClass("popout offscreen"); + // Forcing the renderer to do a layout, which will cause it to apply the transform for the "offscreen" // class, so it will animate when you remove the class. window.getComputedStyle(this._$root.get(0)).getPropertyValue("top"); - this._$root.removeClass("modal-bar-hide"); + this._$root.removeClass("popout offscreen"); } // If something *other* than an editor (like another modal bar) has focus, set the focus @@ -127,18 +127,56 @@ define(function (require, exports, module) { return this._$root.outerHeight(); }; + /** + * Prepares the ModalBar for closing by popping it out of the main flow and resizing/ + * rescrolling the Editor to maintain its current apparent code position. Useful if + * you want to do that as a separate operation from actually animating the ModalBar + * closed and removing it (for example, if you need to switch full editors in between). + * If you don't call this explicitly, it will get called at the beginning of `close()`. + * + * @param {boolean=} restoreScrollPos If true (the default), adjust the scroll position + * of the editor to account for the ModalBar disappearing. If not set, the caller + * should do it immediately on return of this function (before the animation completes), + * because the editor will already have been resized. + */ + ModalBar.prototype.prepareClose = function (restoreScrollPos) { + if (restoreScrollPos === undefined) { + restoreScrollPos = true; + } + + this._$root.addClass("popout"); + + // Preserve scroll position of the current full editor across the editor refresh, adjusting for the + // height of the modal bar so the code doesn't appear to shift if possible. + var fullEditor = EditorManager.getCurrentFullEditor(), + barHeight = this.height(), + scrollPos; + if (restoreScrollPos && fullEditor) { + scrollPos = fullEditor.getScrollPos(); + } + EditorManager.resizeEditor(); + if (restoreScrollPos && fullEditor) { + fullEditor._codeMirror.scrollTo(scrollPos.x, scrollPos.y - barHeight); + } + }; + /** * Closes the modal bar and returns focus to the active editor. Returns a promise that is * resolved when the bar is fully closed and the container is removed from the DOM. * @param {boolean=} restoreScrollPos If true (the default), adjust the scroll position * of the editor to account for the ModalBar disappearing. If not set, the caller * should do it immediately on return of this function (before the animation completes), - * because the editor will already have been resized. + * because the editor will already have been resized. Note that this is ignored if + * `prepareClose()` was already called (you need to pass the parameter to that + * function if you call it first). * @param {boolean=} animate If true (the default), animate the closing of the ModalBar, * otherwise close it immediately. * @return {$.Promise} promise resolved when close is finished */ ModalBar.prototype.close = function (restoreScrollPos, animate) { + var result = new $.Deferred(), + self = this; + if (restoreScrollPos === undefined) { restoreScrollPos = true; } @@ -146,40 +184,30 @@ define(function (require, exports, module) { animate = true; } - // Store our height before closing, while we can still measure it - var result = new $.Deferred(), - barHeight = this.height(), - self = this; - - function doRemove() { - self._$root.remove(); - result.resolve(); + // If someone hasn't already called `prepareClose()` to pop the ModalBar out of the flow + // and resize the editor, then do that here. + if (!this._$root.hasClass("popout")) { + this.prepareClose(restoreScrollPos); } if (this._autoClose) { window.document.body.removeEventListener("focusin", this._handleFocusChange, true); } + function doRemove() { + self._$root.remove(); + result.resolve(); + } + if (animate) { - AnimationUtils.animateUsingClass(this._$root.get(0), "modal-bar-hide") + AnimationUtils.animateUsingClass(this._$root.get(0), "offscreen") .done(doRemove); } else { doRemove(); } - // Preserve scroll position of the current full editor across the editor refresh, adjusting for the - // height of the modal bar so the code doesn't appear to shift if possible. - var fullEditor = EditorManager.getCurrentFullEditor(), - scrollPos; - if (restoreScrollPos && fullEditor) { - scrollPos = fullEditor.getScrollPos(); - } - EditorManager.resizeEditor(); - if (restoreScrollPos && fullEditor) { - fullEditor._codeMirror.scrollTo(scrollPos.x, scrollPos.y - barHeight); - } EditorManager.focusEditor(); - + return result.promise(); }; From 7dd8b5689fe9c7f0a1d78a703ebf39f2bab408c8 Mon Sep 17 00:00:00 2001 From: larz0 Date: Wed, 25 Sep 2013 19:42:12 -0700 Subject: [PATCH 35/56] First pass. --- src/styles/brackets_codemirror_override.less | 2 +- src/styles/brackets_theme_default.less | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/styles/brackets_codemirror_override.less b/src/styles/brackets_codemirror_override.less index af2dd9be056..1599ef45329 100644 --- a/src/styles/brackets_codemirror_override.less +++ b/src/styles/brackets_codemirror_override.less @@ -208,7 +208,7 @@ background: darken(@activeline-bgcolor, @bc-color-step-size / 2); } - .CodeMirror-matchingtag { background: @matching-bracket; color: @accent-bracket !important; } + .CodeMirror-matchingtag { background: @matching-bracket; } } /* diff --git a/src/styles/brackets_theme_default.less b/src/styles/brackets_theme_default.less index f99e36e9811..e1475b170f1 100644 --- a/src/styles/brackets_theme_default.less +++ b/src/styles/brackets_theme_default.less @@ -92,7 +92,7 @@ @cm-current-match-highlight: rgb(255, 108, 0); /* code highlight */ -@matching-bracket: #b0e3b6; +@matching-bracket: #cff4d9; /* inline editor colors */ @inline-background-color-1: #eaeaea; From cb49080abeb25d327058d38da9a0bb399832751d Mon Sep 17 00:00:00 2001 From: larz0 Date: Wed, 25 Sep 2013 19:51:07 -0700 Subject: [PATCH 36/56] Less bright. --- src/styles/brackets_theme_default.less | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/styles/brackets_theme_default.less b/src/styles/brackets_theme_default.less index e1475b170f1..d69ef05e4bf 100644 --- a/src/styles/brackets_theme_default.less +++ b/src/styles/brackets_theme_default.less @@ -92,7 +92,7 @@ @cm-current-match-highlight: rgb(255, 108, 0); /* code highlight */ -@matching-bracket: #cff4d9; +@matching-bracket: #cfead6; /* inline editor colors */ @inline-background-color-1: #eaeaea; From c738a2c0ec4e5798d6aff241f9dc3db90b38fdb5 Mon Sep 17 00:00:00 2001 From: Randy Edmunds Date: Wed, 25 Sep 2013 20:09:32 -0700 Subject: [PATCH 37/56] code cleanup --- src/search/FindReplace.js | 10 +++++----- src/widgets/ModalBar.js | 12 ++++++------ 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/src/search/FindReplace.js b/src/search/FindReplace.js index ff73062012b..a22a9984b17 100644 --- a/src/search/FindReplace.js +++ b/src/search/FindReplace.js @@ -178,7 +178,7 @@ define(function (require, exports, module) { modalBar.close(true, animate); } modalBar = new ModalBar(template, autoClose, animate); - $(modalBar).on("closeOk closeBlur closeCancel", function () { + $(modalBar).on("commit close", function () { modalBar = null; }); } @@ -319,7 +319,7 @@ define(function (require, exports, module) { } createModalBar(queryDialog, true); - $(modalBar).on("closeOk", function (e, query) { + $(modalBar).on("commit", function (e, query) { if (!state.findNextCalled) { // If findNextCalled is false, this means the user has *not* // entered any search text *or* pressed Cmd-G/F3 to find the @@ -329,7 +329,7 @@ define(function (require, exports, module) { findFirst(query); } }); - $(modalBar).on("closeOk close", function (e, query) { + $(modalBar).on("commit close", function (e, query) { // Clear highlights but leave search state in place so Find Next/Previous work after closing clearHighlights(cm, state); @@ -500,7 +500,7 @@ define(function (require, exports, module) { function replace(editor, all) { var cm = editor._codeMirror; createModalBar(replaceQueryDialog, true); - $(modalBar).on("closeOk", function (e, query) { + $(modalBar).on("commit", function (e, query) { if (!query) { return; } @@ -511,7 +511,7 @@ define(function (require, exports, module) { // Eventually we should rip out all this code (which comes from the old CodeMirror dialog // logic) and just change the content itself. createModalBar(replacementQueryDialog, true, false); - $(modalBar).on("closeOk", function (e, text) { + $(modalBar).on("commit", function (e, text) { text = text || ""; var match, fnMatch = function (w, i) { return match[i]; }; diff --git a/src/widgets/ModalBar.js b/src/widgets/ModalBar.js index c27fa5aacbc..67c73c4fedb 100644 --- a/src/widgets/ModalBar.js +++ b/src/widgets/ModalBar.js @@ -41,10 +41,9 @@ define(function (require, exports, module) { * * Creates a modal bar whose contents are the given template. * @param {string} template The HTML contents of the modal bar. - * @param {boolean} autoClose If true, then close the dialog if the user hits RETURN or ESC - * in the first input field, or if the modal bar loses focus to an outside item. Dispatches - * jQuery events for these cases: "closeOk" on RETURN, "closeCancel" on ESC, and "closeBlur" - * on focus loss. + * @param {boolean} autoClose If true, then close the dialog if the user hits RETURN + * in the first input field. Dispatches jQuery events for these cases: + * "commit" on RETURN and "close" always. * @param {boolean} animate If true (the default), animate the dialog closed, otherwise * close it immediately. */ @@ -195,7 +194,9 @@ define(function (require, exports, module) { var value = this._getFirstInput().val(); this.close(); - $(this).triggerHandler(e.keyCode === KeyEvent.DOM_VK_RETURN ? "closeOk" : "closeCancel", [value]); + if (e.keyCode === KeyEvent.DOM_VK_RETURN) { + $(this).triggerHandler("commit", [value]); + } } }; @@ -207,7 +208,6 @@ define(function (require, exports, module) { if (!$.contains(this._$root.get(0), e.target)) { var value = this._getFirstInput().val(); this.close(); - $(this).triggerHandler("closeBlur", [value]); } }; From 54e3ad0e2a60a1181af92202901c4b901cd265ac Mon Sep 17 00:00:00 2001 From: Lance Campbell Date: Wed, 25 Sep 2013 20:21:56 -0700 Subject: [PATCH 38/56] hasNativeMenus param code cleanup --- src/utils/Global.js | 9 ++++++--- test/spec/SpecRunnerUtils.js | 2 +- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/src/utils/Global.js b/src/utils/Global.js index 9116301d4eb..3f5bef20bde 100644 --- a/src/utils/Global.js +++ b/src/utils/Global.js @@ -37,7 +37,8 @@ define(function (require, exports, module) { var configJSON = require("text!config.json"), UrlParams = require("utils/UrlParams").UrlParams; - var params = new UrlParams(); + var params = new UrlParams(), + hasNativeMenus = ""; // read URL params params.parse(); @@ -83,8 +84,10 @@ define(function (require, exports, module) { global.brackets.inBrowser = !global.brackets.hasOwnProperty("fs"); - if (params.get("hasNativeMenus") !== undefined) { - global.brackets.nativeMenus = (params.get("hasNativeMenus") === "true"); + hasNativeMenus = params.get("hasNativeMenus"); + + if (hasNativeMenus) { + global.brackets.nativeMenus = (hasNativeMenus === "true"); } else { global.brackets.nativeMenus = (!global.brackets.inBrowser && (global.brackets.platform !== "linux")); } diff --git a/test/spec/SpecRunnerUtils.js b/test/spec/SpecRunnerUtils.js index 1eb326703a6..88bf1d455d6 100644 --- a/test/spec/SpecRunnerUtils.js +++ b/test/spec/SpecRunnerUtils.js @@ -504,7 +504,7 @@ define(function (require, exports, module) { // option to launch test window with either native or HTML menus if (options && options.hasOwnProperty("hasNativeMenus")) { - params.put("hasNativeMenus", options.hasNativeMenus); + params.put("hasNativeMenus", (options.hasNativeMenus ? "true" : "false")); } _testWindow = window.open(getBracketsSourceRoot() + "/index.html?" + params.toString(), "_blank", optionsStr); From 1b20e50633c963e31c65d8bdb756af9e93e27b3c Mon Sep 17 00:00:00 2001 From: Peter Flynn Date: Thu, 26 Sep 2013 01:01:11 -0700 Subject: [PATCH 39/56] Code review: use more consts in Find; remove unneeded single-tickmark API --- src/search/FindReplace.js | 18 ++++++++++++------ src/search/ScrollTrackMarkers.js | 13 ------------- 2 files changed, 12 insertions(+), 19 deletions(-) diff --git a/src/search/FindReplace.js b/src/search/FindReplace.js index 1fc59e825c1..baffa3d2f6e 100644 --- a/src/search/FindReplace.js +++ b/src/search/FindReplace.js @@ -52,8 +52,14 @@ define(function (require, exports, module) { var searchReplacePanelTemplate = require("text!htmlContent/search-replace-panel.html"), searchReplaceResultsTemplate = require("text!htmlContent/search-replace-results.html"); - /** @cost Constant used to define the maximum results to show */ - var FIND_REPLACE_MAX = 300; + /** @const Maximum file size to search within (in chars) */ + var FIND_MAX_FILE_SIZE = 500000; + + /** @const If the number of matches exceeds this limit, inline text highlighting and scroll-track tickmarks are disabled */ + var FIND_HIGHLIGHT_MAX = 2000; + + /** @const Maximum number of matches to collect for Replace All; any additional matches are not listed in the panel & are not replaced */ + var REPLACE_ALL_MAX = 300; /** @type {!Panel} Panel that shows results of replaceAll action */ var replaceAllPanel = null; @@ -261,7 +267,7 @@ define(function (require, exports, module) { // Find all matches // (Except on huge documents, where this is too expensive) var resultSet = []; - if (cm.getValue().length < 500000) { + if (cm.getValue().length <= FIND_MAX_FILE_SIZE) { // FUTURE: if last query was prefix of this one, could optimize by filtering existing result set var cursor = getSearchCursor(cm, state.query); while (cursor.findNext()) { @@ -277,7 +283,7 @@ define(function (require, exports, module) { } // Highlight all matches if there aren't too many - if (resultSet.length <= 2000) { + if (resultSet.length <= FIND_HIGHLIGHT_MAX) { toggleHighlighting(editor, true); resultSet.forEach(function (result) { @@ -432,7 +438,7 @@ define(function (require, exports, module) { post: multiLine ? "\u2026" : line.slice(to.ch) }); - if (results.length >= FIND_REPLACE_MAX) { + if (results.length >= REPLACE_ALL_MAX) { break; } } @@ -443,7 +449,7 @@ define(function (require, exports, module) { Strings.FIND_REPLACE_TITLE_PART3, resultsLength, resultsLength > 1 ? Strings.FIND_IN_FILES_MATCHES : Strings.FIND_IN_FILES_MATCH, - resultsLength >= FIND_REPLACE_MAX ? Strings.FIND_IN_FILES_MORE_THAN : "" + resultsLength >= REPLACE_ALL_MAX ? Strings.FIND_IN_FILES_MORE_THAN : "" ); // Insert the search summary diff --git a/src/search/ScrollTrackMarkers.js b/src/search/ScrollTrackMarkers.js index 7d4cd71ab4a..aa60cdb0e91 100644 --- a/src/search/ScrollTrackMarkers.js +++ b/src/search/ScrollTrackMarkers.js @@ -143,18 +143,6 @@ define(function (require, exports, module) { } } - /** - * Add a tickmark to the editor's tickmark track, if it's visible - * @param curEditor {!Editor} - * @param pos {!{line:Number, ch:Number}} - */ - function addTickmark(curEditor, pos) { - console.assert(editor === curEditor); - - marks.push(pos); - _renderMarks([pos]); - } - /** * Add tickmarks to the editor's tickmark track, if it's visible * @param curEditor {!Editor} @@ -170,6 +158,5 @@ define(function (require, exports, module) { exports.clear = clear; exports.setVisible = setVisible; - exports.addTickmark = addTickmark; exports.addTickmarks = addTickmarks; }); From c2fca0d1794de4667b9f1cd098e3b6015f0d7a93 Mon Sep 17 00:00:00 2001 From: Kevin Dangoor Date: Thu, 26 Sep 2013 10:11:13 -0400 Subject: [PATCH 40/56] Update to decompress-zip that includes fix for our issue. --- .../decompress-zip/bin/decompress-zip.js | 4 + .../decompress-zip/coverage/coverage.json | 1 - .../coverage/lcov-report/index.html | 333 ------ .../lcov-report/lib/decompress-zip.js.html | 1025 ----------------- .../lcov-report/lib/extractors.js.html | 623 ---------- .../coverage/lcov-report/lib/index.html | 372 ------ .../lcov-report/lib/signatures.js.html | 335 ------ .../lcov-report/lib/structures.js.html | 995 ---------------- .../coverage/lcov-report/prettify.css | 1 - .../coverage/lcov-report/prettify.js | 1 - .../decompress-zip/coverage/lcov.info | 446 ------- .../decompress-zip/download-test-assets.js | 2 +- .../decompress-zip/lib/decompress-zip.js | 103 +- .../decompress-zip/lib/extractors.js | 48 +- .../decompress-zip/lib/file-details.js | 37 + .../decompress-zip/lib/structures.js | 336 +++--- .../node_modules/mkpath/package.json | 6 +- .../node_modules/core-util-is/package.json | 6 +- .../node_modules/debuglog/package.json | 6 +- .../node_modules/readable-stream/package.json | 6 +- .../node_modules/touch/package.json | 6 +- .../node_modules/decompress-zip/package.json | 6 +- .../node_modules/decompress-zip/test/test.js | 2 +- src/extensibility/node/package.json | 2 +- 24 files changed, 307 insertions(+), 4395 deletions(-) delete mode 100644 src/extensibility/node/node_modules/decompress-zip/coverage/coverage.json delete mode 100644 src/extensibility/node/node_modules/decompress-zip/coverage/lcov-report/index.html delete mode 100644 src/extensibility/node/node_modules/decompress-zip/coverage/lcov-report/lib/decompress-zip.js.html delete mode 100644 src/extensibility/node/node_modules/decompress-zip/coverage/lcov-report/lib/extractors.js.html delete mode 100644 src/extensibility/node/node_modules/decompress-zip/coverage/lcov-report/lib/index.html delete mode 100644 src/extensibility/node/node_modules/decompress-zip/coverage/lcov-report/lib/signatures.js.html delete mode 100644 src/extensibility/node/node_modules/decompress-zip/coverage/lcov-report/lib/structures.js.html delete mode 100644 src/extensibility/node/node_modules/decompress-zip/coverage/lcov-report/prettify.css delete mode 100644 src/extensibility/node/node_modules/decompress-zip/coverage/lcov-report/prettify.js delete mode 100644 src/extensibility/node/node_modules/decompress-zip/coverage/lcov.info create mode 100644 src/extensibility/node/node_modules/decompress-zip/lib/file-details.js diff --git a/src/extensibility/node/node_modules/decompress-zip/bin/decompress-zip.js b/src/extensibility/node/node_modules/decompress-zip/bin/decompress-zip.js index 0f8556d9e6b..ee800c5aa5f 100755 --- a/src/extensibility/node/node_modules/decompress-zip/bin/decompress-zip.js +++ b/src/extensibility/node/node_modules/decompress-zip/bin/decompress-zip.js @@ -8,4 +8,8 @@ zip.on('file', function (file) { console.log(file.name); }); +zip.on('error', function (error) { + console.error(error.message, error.stack); +}); + zip.extract(); diff --git a/src/extensibility/node/node_modules/decompress-zip/coverage/coverage.json b/src/extensibility/node/node_modules/decompress-zip/coverage/coverage.json deleted file mode 100644 index 8121ebfdcbc..00000000000 --- a/src/extensibility/node/node_modules/decompress-zip/coverage/coverage.json +++ /dev/null @@ -1 +0,0 @@ -{"/usr/local/google/home/mscales/Projects/decompress/lib/decompress-zip.js":{"path":"/usr/local/google/home/mscales/Projects/decompress/lib/decompress-zip.js","s":{"1":1,"2":1,"3":1,"4":1,"5":1,"6":1,"7":1,"8":1,"9":1,"10":1,"11":1,"12":1,"13":1,"14":1,"15":1,"16":1,"17":1,"18":13,"19":13,"20":13,"21":13,"22":13,"23":1,"24":1,"25":1,"26":13,"27":1,"28":12,"29":12,"30":1,"31":0,"32":0,"33":0,"34":0,"35":0,"36":0,"37":0,"38":0,"39":1,"40":13,"41":13,"42":13,"43":13,"44":12,"45":12,"46":12,"47":2106,"48":2106,"49":2106,"50":12,"51":12,"52":1,"53":13,"54":1,"55":12,"56":12,"57":12,"58":1,"59":12,"60":12,"61":12,"62":268,"63":268,"64":12,"65":0,"66":12,"67":1,"68":12,"69":12,"70":12,"71":12,"72":1,"73":13,"74":13,"75":13,"76":1,"77":12,"78":12,"79":12,"80":12,"81":2106,"82":2106,"83":2106,"84":2106,"85":2106,"86":2106,"87":12,"88":12,"89":1,"90":2106,"91":2106,"92":163,"93":1943,"94":19,"95":1924,"96":0,"97":1},"b":{"1":[1,0],"2":[13,0],"3":[13,0],"4":[280,280],"5":[0,12],"6":[13,0],"7":[163,1943],"8":[19,1924,0]},"f":{"1":13,"2":13,"3":12,"4":0,"5":0,"6":0,"7":0,"8":13,"9":12,"10":2106,"11":2106,"12":12,"13":1,"14":12,"15":12,"16":12,"17":12,"18":13,"19":12,"20":2106,"21":2106,"22":12,"23":2106},"fnMap":{"1":{"name":"DecompressZip","line":30,"loc":{"start":{"line":30,"column":0},"end":{"line":30,"column":33}}},"2":{"name":"(anonymous_2)","line":47,"loc":{"start":{"line":47,"column":35},"end":{"line":47,"column":47}}},"3":{"name":"(anonymous_3)","line":51,"loc":{"start":{"line":51,"column":35},"end":{"line":51,"column":49}}},"4":{"name":"(anonymous_4)","line":56,"loc":{"start":{"line":56,"column":31},"end":{"line":56,"column":43}}},"5":{"name":"(anonymous_5)","line":60,"loc":{"start":{"line":60,"column":10},"end":{"line":60,"column":27}}},"6":{"name":"(anonymous_6)","line":63,"loc":{"start":{"line":63,"column":22},"end":{"line":63,"column":38}}},"7":{"name":"(anonymous_7)","line":69,"loc":{"start":{"line":69,"column":10},"end":{"line":69,"column":27}}},"8":{"name":"(anonymous_8)","line":76,"loc":{"start":{"line":76,"column":34},"end":{"line":76,"column":53}}},"9":{"name":"(anonymous_9)","line":83,"loc":{"start":{"line":83,"column":10},"end":{"line":83,"column":27}}},"10":{"name":"(anonymous_10)","line":87,"loc":{"start":{"line":87,"column":22},"end":{"line":87,"column":38}}},"11":{"name":"(anonymous_11)","line":89,"loc":{"start":{"line":89,"column":18},"end":{"line":89,"column":36}}},"12":{"name":"(anonymous_12)","line":97,"loc":{"start":{"line":97,"column":14},"end":{"line":97,"column":26}}},"13":{"name":"(anonymous_13)","line":101,"loc":{"start":{"line":101,"column":10},"end":{"line":101,"column":27}}},"14":{"name":"(anonymous_14)","line":109,"loc":{"start":{"line":109,"column":42},"end":{"line":109,"column":59}}},"15":{"name":"(anonymous_15)","line":112,"loc":{"start":{"line":112,"column":10},"end":{"line":112,"column":28}}},"16":{"name":"(anonymous_16)","line":117,"loc":{"start":{"line":117,"column":45},"end":{"line":117,"column":63}}},"17":{"name":"(anonymous_17)","line":139,"loc":{"start":{"line":139,"column":40},"end":{"line":139,"column":64}}},"18":{"name":"(anonymous_18)","line":151,"loc":{"start":{"line":151,"column":35},"end":{"line":151,"column":47}}},"19":{"name":"(anonymous_19)","line":164,"loc":{"start":{"line":164,"column":42},"end":{"line":164,"column":63}}},"20":{"name":"(anonymous_20)","line":169,"loc":{"start":{"line":169,"column":22},"end":{"line":169,"column":55}}},"21":{"name":"(anonymous_21)","line":175,"loc":{"start":{"line":175,"column":14},"end":{"line":175,"column":35}}},"22":{"name":"(anonymous_22)","line":190,"loc":{"start":{"line":190,"column":10},"end":{"line":190,"column":22}}},"23":{"name":"(anonymous_23)","line":195,"loc":{"start":{"line":195,"column":35},"end":{"line":195,"column":64}}}},"statementMap":{"1":{"start":{"line":1,"column":0},"end":{"line":1,"column":13}},"2":{"start":{"line":8,"column":0},"end":{"line":8,"column":23}},"3":{"start":{"line":9,"column":0},"end":{"line":9,"column":31}},"4":{"start":{"line":10,"column":0},"end":{"line":12,"column":1}},"5":{"start":{"line":11,"column":4},"end":{"line":11,"column":44}},"6":{"start":{"line":13,"column":0},"end":{"line":13,"column":21}},"7":{"start":{"line":14,"column":0},"end":{"line":14,"column":27}},"8":{"start":{"line":15,"column":0},"end":{"line":15,"column":27}},"9":{"start":{"line":16,"column":0},"end":{"line":16,"column":31}},"10":{"start":{"line":17,"column":0},"end":{"line":17,"column":41}},"11":{"start":{"line":18,"column":0},"end":{"line":18,"column":41}},"12":{"start":{"line":19,"column":0},"end":{"line":19,"column":41}},"13":{"start":{"line":20,"column":0},"end":{"line":20,"column":20}},"14":{"start":{"line":24,"column":0},"end":{"line":24,"column":34}},"15":{"start":{"line":25,"column":0},"end":{"line":25,"column":32}},"16":{"start":{"line":26,"column":0},"end":{"line":26,"column":33}},"17":{"start":{"line":30,"column":0},"end":{"line":41,"column":1}},"18":{"start":{"line":31,"column":4},"end":{"line":31,"column":35}},"19":{"start":{"line":33,"column":4},"end":{"line":33,"column":29}},"20":{"start":{"line":34,"column":4},"end":{"line":34,"column":27}},"21":{"start":{"line":35,"column":4},"end":{"line":35,"column":19}},"22":{"start":{"line":40,"column":4},"end":{"line":40,"column":17}},"23":{"start":{"line":43,"column":0},"end":{"line":43,"column":50}},"24":{"start":{"line":45,"column":0},"end":{"line":45,"column":59}},"25":{"start":{"line":47,"column":0},"end":{"line":49,"column":2}},"26":{"start":{"line":48,"column":4},"end":{"line":48,"column":37}},"27":{"start":{"line":51,"column":0},"end":{"line":54,"column":2}},"28":{"start":{"line":52,"column":4},"end":{"line":52,"column":17}},"29":{"start":{"line":53,"column":4},"end":{"line":53,"column":21}},"30":{"start":{"line":56,"column":0},"end":{"line":74,"column":2}},"31":{"start":{"line":57,"column":4},"end":{"line":57,"column":20}},"32":{"start":{"line":59,"column":4},"end":{"line":71,"column":7}},"33":{"start":{"line":61,"column":8},"end":{"line":61,"column":24}},"34":{"start":{"line":63,"column":8},"end":{"line":65,"column":11}},"35":{"start":{"line":64,"column":12},"end":{"line":64,"column":35}},"36":{"start":{"line":67,"column":8},"end":{"line":67,"column":34}},"37":{"start":{"line":70,"column":8},"end":{"line":70,"column":34}},"38":{"start":{"line":73,"column":4},"end":{"line":73,"column":16}},"39":{"start":{"line":76,"column":0},"end":{"line":106,"column":2}},"40":{"start":{"line":77,"column":4},"end":{"line":77,"column":20}},"41":{"start":{"line":79,"column":4},"end":{"line":79,"column":28}},"42":{"start":{"line":80,"column":4},"end":{"line":80,"column":39}},"43":{"start":{"line":82,"column":4},"end":{"line":103,"column":7}},"44":{"start":{"line":84,"column":8},"end":{"line":84,"column":26}},"45":{"start":{"line":85,"column":8},"end":{"line":85,"column":25}},"46":{"start":{"line":87,"column":8},"end":{"line":94,"column":11}},"47":{"start":{"line":88,"column":12},"end":{"line":91,"column":15}},"48":{"start":{"line":90,"column":16},"end":{"line":90,"column":37}},"49":{"start":{"line":93,"column":12},"end":{"line":93,"column":35}},"50":{"start":{"line":96,"column":8},"end":{"line":99,"column":11}},"51":{"start":{"line":98,"column":12},"end":{"line":98,"column":42}},"52":{"start":{"line":102,"column":8},"end":{"line":102,"column":34}},"53":{"start":{"line":105,"column":4},"end":{"line":105,"column":16}},"54":{"start":{"line":109,"column":0},"end":{"line":115,"column":2}},"55":{"start":{"line":110,"column":4},"end":{"line":110,"column":46}},"56":{"start":{"line":111,"column":4},"end":{"line":114,"column":7}},"57":{"start":{"line":113,"column":8},"end":{"line":113,"column":25}},"58":{"start":{"line":117,"column":0},"end":{"line":136,"column":2}},"59":{"start":{"line":118,"column":4},"end":{"line":118,"column":34}},"60":{"start":{"line":119,"column":4},"end":{"line":119,"column":19}},"61":{"start":{"line":126,"column":4},"end":{"line":129,"column":5}},"62":{"start":{"line":127,"column":8},"end":{"line":127,"column":16}},"63":{"start":{"line":128,"column":8},"end":{"line":128,"column":43}},"64":{"start":{"line":131,"column":4},"end":{"line":133,"column":5}},"65":{"start":{"line":132,"column":8},"end":{"line":132,"column":78}},"66":{"start":{"line":135,"column":4},"end":{"line":135,"column":31}},"67":{"start":{"line":139,"column":0},"end":{"line":149,"column":2}},"68":{"start":{"line":140,"column":4},"end":{"line":140,"column":56}},"69":{"start":{"line":142,"column":4},"end":{"line":142,"column":48}},"70":{"start":{"line":143,"column":4},"end":{"line":146,"column":8}},"71":{"start":{"line":148,"column":4},"end":{"line":148,"column":81}},"72":{"start":{"line":151,"column":0},"end":{"line":162,"column":2}},"73":{"start":{"line":152,"column":4},"end":{"line":159,"column":5}},"74":{"start":{"line":153,"column":8},"end":{"line":158,"column":47}},"75":{"start":{"line":161,"column":4},"end":{"line":161,"column":28}},"76":{"start":{"line":164,"column":0},"end":{"line":193,"column":2}},"77":{"start":{"line":165,"column":4},"end":{"line":165,"column":22}},"78":{"start":{"line":166,"column":4},"end":{"line":166,"column":19}},"79":{"start":{"line":167,"column":4},"end":{"line":167,"column":20}},"80":{"start":{"line":169,"column":4},"end":{"line":187,"column":7}},"81":{"start":{"line":170,"column":8},"end":{"line":170,"column":43}},"82":{"start":{"line":171,"column":8},"end":{"line":173,"column":12}},"83":{"start":{"line":174,"column":8},"end":{"line":184,"column":11}},"84":{"start":{"line":176,"column":12},"end":{"line":181,"column":14}},"85":{"start":{"line":183,"column":12},"end":{"line":183,"column":44}},"86":{"start":{"line":186,"column":8},"end":{"line":186,"column":31}},"87":{"start":{"line":189,"column":4},"end":{"line":192,"column":7}},"88":{"start":{"line":191,"column":8},"end":{"line":191,"column":21}},"89":{"start":{"line":195,"column":0},"end":{"line":237,"column":2}},"90":{"start":{"line":196,"column":4},"end":{"line":196,"column":52}},"91":{"start":{"line":199,"column":4},"end":{"line":201,"column":5}},"92":{"start":{"line":200,"column":8},"end":{"line":200,"column":52}},"93":{"start":{"line":227,"column":4},"end":{"line":236,"column":5}},"94":{"start":{"line":229,"column":8},"end":{"line":229,"column":66}},"95":{"start":{"line":232,"column":8},"end":{"line":232,"column":68}},"96":{"start":{"line":235,"column":8},"end":{"line":235,"column":56}},"97":{"start":{"line":240,"column":0},"end":{"line":240,"column":31}}},"branchMap":{"1":{"line":10,"type":"if","locations":[{"start":{"line":10,"column":0},"end":{"line":10,"column":0}},{"start":{"line":10,"column":0},"end":{"line":10,"column":0}}]},"2":{"line":79,"type":"binary-expr","locations":[{"start":{"line":79,"column":14},"end":{"line":79,"column":21}},{"start":{"line":79,"column":25},"end":{"line":79,"column":27}}]},"3":{"line":80,"type":"binary-expr","locations":[{"start":{"line":80,"column":19},"end":{"line":80,"column":31}},{"start":{"line":80,"column":35},"end":{"line":80,"column":38}}]},"4":{"line":126,"type":"binary-expr","locations":[{"start":{"line":126,"column":11},"end":{"line":126,"column":56}},{"start":{"line":126,"column":60},"end":{"line":126,"column":105}}]},"5":{"line":131,"type":"if","locations":[{"start":{"line":131,"column":4},"end":{"line":131,"column":4}},{"start":{"line":131,"column":4},"end":{"line":131,"column":4}}]},"6":{"line":152,"type":"if","locations":[{"start":{"line":152,"column":4},"end":{"line":152,"column":4}},{"start":{"line":152,"column":4},"end":{"line":152,"column":4}}]},"7":{"line":199,"type":"if","locations":[{"start":{"line":199,"column":4},"end":{"line":199,"column":4}},{"start":{"line":199,"column":4},"end":{"line":199,"column":4}}]},"8":{"line":227,"type":"switch","locations":[{"start":{"line":228,"column":4},"end":{"line":229,"column":66}},{"start":{"line":231,"column":4},"end":{"line":232,"column":68}},{"start":{"line":234,"column":4},"end":{"line":235,"column":56}}]}}},"/usr/local/google/home/mscales/Projects/decompress/lib/structures.js":{"path":"/usr/local/google/home/mscales/Projects/decompress/lib/structures.js","s":{"1":1,"2":1,"3":1,"4":1,"5":2106,"6":2106,"7":2106,"8":2106,"9":2106,"10":2106,"11":2106,"12":2106,"13":1,"14":12,"15":12,"16":12,"17":1,"18":12,"19":12,"20":12,"21":12,"22":12,"23":27,"24":27,"25":2109,"26":2109,"27":2109,"28":3,"29":2106,"30":2106,"31":2106,"32":33696,"33":2106,"34":2106,"35":2106,"36":2106,"37":2106,"38":2106,"39":2106,"40":2106,"41":0,"42":2106,"43":2106,"44":2106,"45":2106,"46":945,"47":945,"48":0,"49":945,"50":2106,"51":2106,"52":2106,"53":0,"54":0,"55":0,"56":0,"57":2106,"58":2106,"59":12,"60":12,"61":2106,"62":12,"63":12,"64":12,"65":0,"66":12,"67":1,"68":2106,"69":2106,"70":2106,"71":2106,"72":4212,"73":4212,"74":2106,"75":2106,"76":0,"77":2106,"78":2106,"79":2106,"80":2106,"81":4212,"82":2106,"83":2106,"84":2106,"85":0,"86":2106,"87":2106,"88":4212,"89":4212,"90":1902,"91":1902,"92":951,"93":951,"94":3261,"95":3261,"96":2106,"97":2106,"98":2106,"99":2106,"100":2106,"101":0,"102":2106,"103":1},"b":{"1":[2109,0],"2":[3,2106],"3":[2106,0],"4":[2106,0],"5":[0,2106],"6":[2106,0],"7":[945,1161],"8":[0,945],"9":[2106,0],"10":[0,2106],"11":[0,0],"12":[12,2094],"13":[2106,2106],"14":[0,2106],"15":[2106,2106],"16":[2106,0],"17":[0,2106],"18":[4212,0],"19":[1902,2310],"20":[951,951]},"f":{"1":2106,"2":12,"3":12,"4":27,"5":12,"6":0,"7":2106,"8":4212,"9":2106,"10":2106,"11":0},"fnMap":{"1":{"name":"(anonymous_1)","line":6,"loc":{"start":{"line":6,"column":22},"end":{"line":6,"column":50}}},"2":{"name":"(anonymous_2)","line":20,"loc":{"start":{"line":20,"column":20},"end":{"line":20,"column":38}}},"3":{"name":"(anonymous_3)","line":38,"loc":{"start":{"line":38,"column":20},"end":{"line":38,"column":45}}},"4":{"name":"(anonymous_4)","line":44,"loc":{"start":{"line":44,"column":26},"end":{"line":44,"column":38}}},"5":{"name":"(anonymous_5)","line":136,"loc":{"start":{"line":136,"column":21},"end":{"line":136,"column":33}}},"6":{"name":"(anonymous_6)","line":140,"loc":{"start":{"line":140,"column":23},"end":{"line":140,"column":38}}},"7":{"name":"(anonymous_7)","line":147,"loc":{"start":{"line":147,"column":20},"end":{"line":147,"column":38}}},"8":{"name":"(anonymous_8)","line":152,"loc":{"start":{"line":152,"column":26},"end":{"line":152,"column":38}}},"9":{"name":"(anonymous_9)","line":211,"loc":{"start":{"line":211,"column":21},"end":{"line":211,"column":33}}},"10":{"name":"(anonymous_10)","line":215,"loc":{"start":{"line":215,"column":23},"end":{"line":215,"column":35}}},"11":{"name":"(anonymous_11)","line":219,"loc":{"start":{"line":219,"column":23},"end":{"line":219,"column":38}}}},"statementMap":{"1":{"start":{"line":1,"column":0},"end":{"line":1,"column":13}},"2":{"start":{"line":3,"column":0},"end":{"line":3,"column":31}},"3":{"start":{"line":4,"column":0},"end":{"line":4,"column":21}},"4":{"start":{"line":6,"column":0},"end":{"line":18,"column":2}},"5":{"start":{"line":7,"column":4},"end":{"line":7,"column":46}},"6":{"start":{"line":8,"column":4},"end":{"line":8,"column":38}},"7":{"start":{"line":9,"column":4},"end":{"line":9,"column":29}},"8":{"start":{"line":11,"column":4},"end":{"line":11,"column":31}},"9":{"start":{"line":12,"column":4},"end":{"line":12,"column":39}},"10":{"start":{"line":13,"column":4},"end":{"line":13,"column":38}},"11":{"start":{"line":15,"column":4},"end":{"line":15,"column":73}},"12":{"start":{"line":17,"column":4},"end":{"line":17,"column":18}},"13":{"start":{"line":20,"column":0},"end":{"line":36,"column":2}},"14":{"start":{"line":21,"column":4},"end":{"line":31,"column":10}},"15":{"start":{"line":33,"column":4},"end":{"line":33,"column":43}},"16":{"start":{"line":35,"column":4},"end":{"line":35,"column":16}},"17":{"start":{"line":38,"column":0},"end":{"line":145,"column":2}},"18":{"start":{"line":39,"column":4},"end":{"line":39,"column":29}},"19":{"start":{"line":40,"column":4},"end":{"line":40,"column":23}},"20":{"start":{"line":41,"column":4},"end":{"line":41,"column":23}},"21":{"start":{"line":42,"column":4},"end":{"line":42,"column":16}},"22":{"start":{"line":44,"column":4},"end":{"line":134,"column":7}},"23":{"start":{"line":45,"column":8},"end":{"line":45,"column":18}},"24":{"start":{"line":47,"column":8},"end":{"line":133,"column":9}},"25":{"start":{"line":48,"column":12},"end":{"line":87,"column":13}},"26":{"start":{"line":49,"column":16},"end":{"line":49,"column":40}},"27":{"start":{"line":50,"column":16},"end":{"line":52,"column":17}},"28":{"start":{"line":51,"column":20},"end":{"line":51,"column":27}},"29":{"start":{"line":54,"column":16},"end":{"line":74,"column":22}},"30":{"start":{"line":76,"column":16},"end":{"line":76,"column":49}},"31":{"start":{"line":78,"column":16},"end":{"line":80,"column":17}},"32":{"start":{"line":79,"column":20},"end":{"line":79,"column":94}},"33":{"start":{"line":82,"column":16},"end":{"line":82,"column":105}},"34":{"start":{"line":83,"column":16},"end":{"line":83,"column":81}},"35":{"start":{"line":84,"column":16},"end":{"line":84,"column":122}},"36":{"start":{"line":86,"column":16},"end":{"line":86,"column":35}},"37":{"start":{"line":89,"column":12},"end":{"line":100,"column":13}},"38":{"start":{"line":90,"column":16},"end":{"line":97,"column":17}},"39":{"start":{"line":91,"column":20},"end":{"line":91,"column":64}},"40":{"start":{"line":92,"column":20},"end":{"line":94,"column":21}},"41":{"start":{"line":93,"column":24},"end":{"line":93,"column":31}},"42":{"start":{"line":96,"column":20},"end":{"line":96,"column":56}},"43":{"start":{"line":99,"column":16},"end":{"line":99,"column":37}},"44":{"start":{"line":102,"column":12},"end":{"line":113,"column":13}},"45":{"start":{"line":103,"column":16},"end":{"line":110,"column":17}},"46":{"start":{"line":104,"column":20},"end":{"line":104,"column":66}},"47":{"start":{"line":105,"column":20},"end":{"line":107,"column":21}},"48":{"start":{"line":106,"column":24},"end":{"line":106,"column":31}},"49":{"start":{"line":109,"column":20},"end":{"line":109,"column":58}},"50":{"start":{"line":112,"column":16},"end":{"line":112,"column":38}},"51":{"start":{"line":115,"column":12},"end":{"line":132,"column":13}},"52":{"start":{"line":116,"column":16},"end":{"line":122,"column":17}},"53":{"start":{"line":117,"column":20},"end":{"line":117,"column":67}},"54":{"start":{"line":118,"column":20},"end":{"line":120,"column":21}},"55":{"start":{"line":119,"column":24},"end":{"line":119,"column":31}},"56":{"start":{"line":121,"column":20},"end":{"line":121,"column":59}},"57":{"start":{"line":124,"column":16},"end":{"line":124,"column":40}},"58":{"start":{"line":126,"column":16},"end":{"line":129,"column":17}},"59":{"start":{"line":127,"column":20},"end":{"line":127,"column":48}},"60":{"start":{"line":128,"column":20},"end":{"line":128,"column":36}},"61":{"start":{"line":131,"column":16},"end":{"line":131,"column":31}},"62":{"start":{"line":136,"column":4},"end":{"line":138,"column":7}},"63":{"start":{"line":137,"column":8},"end":{"line":137,"column":36}},"64":{"start":{"line":140,"column":4},"end":{"line":142,"column":7}},"65":{"start":{"line":141,"column":8},"end":{"line":141,"column":29}},"66":{"start":{"line":144,"column":4},"end":{"line":144,"column":28}},"67":{"start":{"line":147,"column":0},"end":{"line":224,"column":2}},"68":{"start":{"line":148,"column":4},"end":{"line":148,"column":29}},"69":{"start":{"line":149,"column":4},"end":{"line":149,"column":23}},"70":{"start":{"line":150,"column":4},"end":{"line":150,"column":13}},"71":{"start":{"line":152,"column":4},"end":{"line":209,"column":7}},"72":{"start":{"line":153,"column":8},"end":{"line":153,"column":18}},"73":{"start":{"line":155,"column":8},"end":{"line":180,"column":9}},"74":{"start":{"line":156,"column":12},"end":{"line":156,"column":36}},"75":{"start":{"line":157,"column":12},"end":{"line":159,"column":13}},"76":{"start":{"line":158,"column":16},"end":{"line":158,"column":23}},"77":{"start":{"line":161,"column":12},"end":{"line":173,"column":18}},"78":{"start":{"line":175,"column":12},"end":{"line":175,"column":49}},"79":{"start":{"line":177,"column":12},"end":{"line":177,"column":80}},"80":{"start":{"line":179,"column":12},"end":{"line":179,"column":31}},"81":{"start":{"line":182,"column":8},"end":{"line":193,"column":9}},"82":{"start":{"line":183,"column":12},"end":{"line":190,"column":13}},"83":{"start":{"line":184,"column":16},"end":{"line":184,"column":57}},"84":{"start":{"line":185,"column":16},"end":{"line":187,"column":17}},"85":{"start":{"line":186,"column":20},"end":{"line":186,"column":27}},"86":{"start":{"line":189,"column":16},"end":{"line":189,"column":49}},"87":{"start":{"line":192,"column":12},"end":{"line":192,"column":33}},"88":{"start":{"line":195,"column":8},"end":{"line":208,"column":9}},"89":{"start":{"line":196,"column":12},"end":{"line":203,"column":13}},"90":{"start":{"line":197,"column":16},"end":{"line":197,"column":59}},"91":{"start":{"line":198,"column":16},"end":{"line":200,"column":17}},"92":{"start":{"line":199,"column":20},"end":{"line":199,"column":27}},"93":{"start":{"line":202,"column":16},"end":{"line":202,"column":51}},"94":{"start":{"line":205,"column":12},"end":{"line":205,"column":35}},"95":{"start":{"line":207,"column":12},"end":{"line":207,"column":28}},"96":{"start":{"line":211,"column":4},"end":{"line":213,"column":7}},"97":{"start":{"line":212,"column":8},"end":{"line":212,"column":31}},"98":{"start":{"line":215,"column":4},"end":{"line":217,"column":7}},"99":{"start":{"line":216,"column":8},"end":{"line":216,"column":31}},"100":{"start":{"line":219,"column":4},"end":{"line":221,"column":7}},"101":{"start":{"line":220,"column":8},"end":{"line":220,"column":29}},"102":{"start":{"line":223,"column":4},"end":{"line":223,"column":28}},"103":{"start":{"line":226,"column":0},"end":{"line":230,"column":2}}},"branchMap":{"1":{"line":48,"type":"if","locations":[{"start":{"line":48,"column":12},"end":{"line":48,"column":12}},{"start":{"line":48,"column":12},"end":{"line":48,"column":12}}]},"2":{"line":50,"type":"if","locations":[{"start":{"line":50,"column":16},"end":{"line":50,"column":16}},{"start":{"line":50,"column":16},"end":{"line":50,"column":16}}]},"3":{"line":89,"type":"if","locations":[{"start":{"line":89,"column":12},"end":{"line":89,"column":12}},{"start":{"line":89,"column":12},"end":{"line":89,"column":12}}]},"4":{"line":90,"type":"if","locations":[{"start":{"line":90,"column":16},"end":{"line":90,"column":16}},{"start":{"line":90,"column":16},"end":{"line":90,"column":16}}]},"5":{"line":92,"type":"if","locations":[{"start":{"line":92,"column":20},"end":{"line":92,"column":20}},{"start":{"line":92,"column":20},"end":{"line":92,"column":20}}]},"6":{"line":102,"type":"if","locations":[{"start":{"line":102,"column":12},"end":{"line":102,"column":12}},{"start":{"line":102,"column":12},"end":{"line":102,"column":12}}]},"7":{"line":103,"type":"if","locations":[{"start":{"line":103,"column":16},"end":{"line":103,"column":16}},{"start":{"line":103,"column":16},"end":{"line":103,"column":16}}]},"8":{"line":105,"type":"if","locations":[{"start":{"line":105,"column":20},"end":{"line":105,"column":20}},{"start":{"line":105,"column":20},"end":{"line":105,"column":20}}]},"9":{"line":115,"type":"if","locations":[{"start":{"line":115,"column":12},"end":{"line":115,"column":12}},{"start":{"line":115,"column":12},"end":{"line":115,"column":12}}]},"10":{"line":116,"type":"if","locations":[{"start":{"line":116,"column":16},"end":{"line":116,"column":16}},{"start":{"line":116,"column":16},"end":{"line":116,"column":16}}]},"11":{"line":118,"type":"if","locations":[{"start":{"line":118,"column":20},"end":{"line":118,"column":20}},{"start":{"line":118,"column":20},"end":{"line":118,"column":20}}]},"12":{"line":126,"type":"if","locations":[{"start":{"line":126,"column":16},"end":{"line":126,"column":16}},{"start":{"line":126,"column":16},"end":{"line":126,"column":16}}]},"13":{"line":155,"type":"if","locations":[{"start":{"line":155,"column":8},"end":{"line":155,"column":8}},{"start":{"line":155,"column":8},"end":{"line":155,"column":8}}]},"14":{"line":157,"type":"if","locations":[{"start":{"line":157,"column":12},"end":{"line":157,"column":12}},{"start":{"line":157,"column":12},"end":{"line":157,"column":12}}]},"15":{"line":182,"type":"if","locations":[{"start":{"line":182,"column":8},"end":{"line":182,"column":8}},{"start":{"line":182,"column":8},"end":{"line":182,"column":8}}]},"16":{"line":183,"type":"if","locations":[{"start":{"line":183,"column":12},"end":{"line":183,"column":12}},{"start":{"line":183,"column":12},"end":{"line":183,"column":12}}]},"17":{"line":185,"type":"if","locations":[{"start":{"line":185,"column":16},"end":{"line":185,"column":16}},{"start":{"line":185,"column":16},"end":{"line":185,"column":16}}]},"18":{"line":195,"type":"if","locations":[{"start":{"line":195,"column":8},"end":{"line":195,"column":8}},{"start":{"line":195,"column":8},"end":{"line":195,"column":8}}]},"19":{"line":196,"type":"if","locations":[{"start":{"line":196,"column":12},"end":{"line":196,"column":12}},{"start":{"line":196,"column":12},"end":{"line":196,"column":12}}]},"20":{"line":198,"type":"if","locations":[{"start":{"line":198,"column":16},"end":{"line":198,"column":16}},{"start":{"line":198,"column":16},"end":{"line":198,"column":16}}]}}},"/usr/local/google/home/mscales/Projects/decompress/lib/signatures.js":{"path":"/usr/local/google/home/mscales/Projects/decompress/lib/signatures.js","s":{"1":1},"b":{},"f":{},"fnMap":{},"statementMap":{"1":{"start":{"line":1,"column":0},"end":{"line":10,"column":2}}},"branchMap":{}},"/usr/local/google/home/mscales/Projects/decompress/lib/extractors.js":{"path":"/usr/local/google/home/mscales/Projects/decompress/lib/extractors.js","s":{"1":1,"2":1,"3":0,"4":1,"5":1,"6":1,"7":1,"8":1,"9":1,"10":1,"11":1,"12":2364,"13":2364,"14":259,"15":259,"16":1,"17":258,"18":259,"19":259,"20":2364,"21":1,"22":163,"23":163,"24":19,"25":19,"26":1,"27":18,"28":18,"29":18,"30":19,"31":19,"32":1924,"33":1924,"34":1924,"35":1924,"36":1924,"37":1924,"38":1,"39":1942,"40":1942,"41":1942,"42":0,"43":1942,"44":1942,"45":1942,"46":1942,"47":1942,"48":1942,"49":1942,"50":1},"b":{"1":[0,1],"2":[259,2105],"3":[1,258],"4":[1,18]},"f":{"1":2364,"2":259,"3":163,"4":163,"5":19,"6":19,"7":1924,"8":1924,"9":1924,"10":1942,"11":0,"12":1942,"13":1942},"fnMap":{"1":{"name":"(anonymous_1)","line":16,"loc":{"start":{"line":16,"column":12},"end":{"line":16,"column":27}}},"2":{"name":"(anonymous_2)","line":28,"loc":{"start":{"line":28,"column":33},"end":{"line":28,"column":45}}},"3":{"name":"(anonymous_3)","line":38,"loc":{"start":{"line":38,"column":12},"end":{"line":38,"column":43}}},"4":{"name":"(anonymous_4)","line":40,"loc":{"start":{"line":40,"column":14},"end":{"line":40,"column":26}}},"5":{"name":"(anonymous_5)","line":44,"loc":{"start":{"line":44,"column":11},"end":{"line":44,"column":52}}},"6":{"name":"(anonymous_6)","line":57,"loc":{"start":{"line":57,"column":14},"end":{"line":57,"column":26}}},"7":{"name":"(anonymous_7)","line":61,"loc":{"start":{"line":61,"column":13},"end":{"line":61,"column":54}}},"8":{"name":"(anonymous_8)","line":67,"loc":{"start":{"line":67,"column":14},"end":{"line":67,"column":26}}},"9":{"name":"(anonymous_9)","line":77,"loc":{"start":{"line":77,"column":14},"end":{"line":77,"column":26}}},"10":{"name":"(anonymous_10)","line":83,"loc":{"start":{"line":83,"column":18},"end":{"line":83,"column":48}}},"11":{"name":"(anonymous_11)","line":86,"loc":{"start":{"line":86,"column":23},"end":{"line":86,"column":40}}},"12":{"name":"(anonymous_12)","line":94,"loc":{"start":{"line":94,"column":20},"end":{"line":94,"column":32}}},"13":{"name":"(anonymous_13)","line":95,"loc":{"start":{"line":95,"column":19},"end":{"line":95,"column":31}}}},"statementMap":{"1":{"start":{"line":1,"column":0},"end":{"line":1,"column":31}},"2":{"start":{"line":2,"column":0},"end":{"line":4,"column":1}},"3":{"start":{"line":3,"column":4},"end":{"line":3,"column":44}},"4":{"start":{"line":5,"column":0},"end":{"line":5,"column":23}},"5":{"start":{"line":6,"column":0},"end":{"line":6,"column":21}},"6":{"start":{"line":7,"column":0},"end":{"line":7,"column":27}},"7":{"start":{"line":8,"column":0},"end":{"line":8,"column":27}},"8":{"start":{"line":9,"column":0},"end":{"line":9,"column":42}},"9":{"start":{"line":10,"column":0},"end":{"line":10,"column":44}},"10":{"start":{"line":11,"column":0},"end":{"line":11,"column":15}},"11":{"start":{"line":16,"column":0},"end":{"line":34,"column":2}},"12":{"start":{"line":17,"column":4},"end":{"line":17,"column":70}},"13":{"start":{"line":19,"column":4},"end":{"line":31,"column":5}},"14":{"start":{"line":20,"column":8},"end":{"line":20,"column":19}},"15":{"start":{"line":22,"column":8},"end":{"line":26,"column":9}},"16":{"start":{"line":23,"column":12},"end":{"line":23,"column":29}},"17":{"start":{"line":25,"column":12},"end":{"line":25,"column":46}},"18":{"start":{"line":28,"column":8},"end":{"line":30,"column":11}},"19":{"start":{"line":29,"column":12},"end":{"line":29,"column":31}},"20":{"start":{"line":33,"column":4},"end":{"line":33,"column":22}},"21":{"start":{"line":37,"column":0},"end":{"line":81,"column":2}},"22":{"start":{"line":39,"column":8},"end":{"line":42,"column":11}},"23":{"start":{"line":41,"column":12},"end":{"line":41,"column":41}},"24":{"start":{"line":45,"column":8},"end":{"line":45,"column":19}},"25":{"start":{"line":47,"column":8},"end":{"line":53,"column":9}},"26":{"start":{"line":48,"column":12},"end":{"line":48,"column":51}},"27":{"start":{"line":50,"column":12},"end":{"line":50,"column":46}},"28":{"start":{"line":51,"column":12},"end":{"line":51,"column":147}},"29":{"start":{"line":52,"column":12},"end":{"line":52,"column":64}},"30":{"start":{"line":55,"column":8},"end":{"line":59,"column":11}},"31":{"start":{"line":58,"column":12},"end":{"line":58,"column":39}},"32":{"start":{"line":66,"column":8},"end":{"line":79,"column":11}},"33":{"start":{"line":71,"column":12},"end":{"line":71,"column":46}},"34":{"start":{"line":72,"column":12},"end":{"line":72,"column":82}},"35":{"start":{"line":73,"column":12},"end":{"line":73,"column":89}},"36":{"start":{"line":75,"column":12},"end":{"line":75,"column":54}},"37":{"start":{"line":78,"column":12},"end":{"line":78,"column":41}},"38":{"start":{"line":83,"column":0},"end":{"line":103,"column":2}},"39":{"start":{"line":84,"column":4},"end":{"line":84,"column":29}},"40":{"start":{"line":85,"column":4},"end":{"line":85,"column":51}},"41":{"start":{"line":86,"column":4},"end":{"line":88,"column":6}},"42":{"start":{"line":87,"column":8},"end":{"line":87,"column":31}},"43":{"start":{"line":90,"column":4},"end":{"line":90,"column":36}},"44":{"start":{"line":91,"column":4},"end":{"line":91,"column":37}},"45":{"start":{"line":94,"column":4},"end":{"line":98,"column":7}},"46":{"start":{"line":95,"column":8},"end":{"line":97,"column":11}},"47":{"start":{"line":96,"column":12},"end":{"line":96,"column":31}},"48":{"start":{"line":100,"column":4},"end":{"line":100,"column":37}},"49":{"start":{"line":102,"column":4},"end":{"line":102,"column":28}},"50":{"start":{"line":106,"column":0},"end":{"line":106,"column":28}}},"branchMap":{"1":{"line":2,"type":"if","locations":[{"start":{"line":2,"column":0},"end":{"line":2,"column":0}},{"start":{"line":2,"column":0},"end":{"line":2,"column":0}}]},"2":{"line":19,"type":"if","locations":[{"start":{"line":19,"column":4},"end":{"line":19,"column":4}},{"start":{"line":19,"column":4},"end":{"line":19,"column":4}}]},"3":{"line":22,"type":"if","locations":[{"start":{"line":22,"column":8},"end":{"line":22,"column":8}},{"start":{"line":22,"column":8},"end":{"line":22,"column":8}}]},"4":{"line":47,"type":"if","locations":[{"start":{"line":47,"column":8},"end":{"line":47,"column":8}},{"start":{"line":47,"column":8},"end":{"line":47,"column":8}}]}}}} \ No newline at end of file diff --git a/src/extensibility/node/node_modules/decompress-zip/coverage/lcov-report/index.html b/src/extensibility/node/node_modules/decompress-zip/coverage/lcov-report/index.html deleted file mode 100644 index 3c750950be0..00000000000 --- a/src/extensibility/node/node_modules/decompress-zip/coverage/lcov-report/index.html +++ /dev/null @@ -1,333 +0,0 @@ - - - - Code coverage report for All files - - - - - - - -
-

Code coverage report for All files

-

- - Statements: 91.24% (229 / 251)      - - - Branches: 67.69% (44 / 65)      - - - Functions: 85.11% (40 / 47)      - - - Lines: 91.24% (229 / 251)      - -

-
-
-
-
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
FileStatementsBranchesFunctionsLines
lib/91.24%(229 / 251)67.69%(44 / 65)85.11%(40 / 47)91.24%(229 / 251)
-
-
- - - - - - - - diff --git a/src/extensibility/node/node_modules/decompress-zip/coverage/lcov-report/lib/decompress-zip.js.html b/src/extensibility/node/node_modules/decompress-zip/coverage/lcov-report/lib/decompress-zip.js.html deleted file mode 100644 index 6ada3768750..00000000000 --- a/src/extensibility/node/node_modules/decompress-zip/coverage/lcov-report/lib/decompress-zip.js.html +++ /dev/null @@ -1,1025 +0,0 @@ - - - - Code coverage report for lib/decompress-zip.js - - - - - - - -
-

Code coverage report for lib/decompress-zip.js

-

- - Statements: 89.69% (87 / 97)      - - - Branches: 64.71% (11 / 17)      - - - Functions: 82.61% (19 / 23)      - - - Lines: 89.69% (87 / 97)      - -

-
All files » lib/ » decompress-zip.js
-
-
-

-
-
1 -2 -3 -4 -5 -6 -7 -8 -9 -10 -11 -12 -13 -14 -15 -16 -17 -18 -19 -20 -21 -22 -23 -24 -25 -26 -27 -28 -29 -30 -31 -32 -33 -34 -35 -36 -37 -38 -39 -40 -41 -42 -43 -44 -45 -46 -47 -48 -49 -50 -51 -52 -53 -54 -55 -56 -57 -58 -59 -60 -61 -62 -63 -64 -65 -66 -67 -68 -69 -70 -71 -72 -73 -74 -75 -76 -77 -78 -79 -80 -81 -82 -83 -84 -85 -86 -87 -88 -89 -90 -91 -92 -93 -94 -95 -96 -97 -98 -99 -100 -101 -102 -103 -104 -105 -106 -107 -108 -109 -110 -111 -112 -113 -114 -115 -116 -117 -118 -119 -120 -121 -122 -123 -124 -125 -126 -127 -128 -129 -130 -131 -132 -133 -134 -135 -136 -137 -138 -139 -140 -141 -142 -143 -144 -145 -146 -147 -148 -149 -150 -151 -152 -153 -154 -155 -156 -157 -158 -159 -160 -161 -162 -163 -164 -165 -166 -167 -168 -169 -170 -171 -172 -173 -174 -175 -176 -177 -178 -179 -180 -181 -182 -183 -184 -185 -186 -187 -188 -189 -190 -191 -192 -193 -194 -195 -196 -197 -198 -199 -200 -201 -202 -203 -204 -205 -206 -207 -208 -209 -210 -211 -212 -213 -214 -215 -216 -217 -218 -219 -220 -221 -222 -223 -224 -225 -226 -227 -228 -229 -230 -231 -232 -233 -234 -235 -236 -237 -238 -239 -240 -2411 -  -  -  -  -  -  -1 -1 -1 -1 -  -1 -1 -1 -1 -1 -1 -1 -1 -  -  -  -1 -1 -1 -  -  -  -1 -13 -  -13 -13 -13 -  -  -  -  -13 -  -  -1 -  -1 -  -1 -13 -  -  -1 -12 -12 -  -  -1 -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -1 -13 -  -13 -13 -  -13 -  -12 -12 -  -12 -2106 -  -2106 -  -  -2106 -  -  -12 -  -12 -  -  -  -1 -  -  -13 -  -  -  -1 -12 -12 -  -12 -  -  -  -1 -12 -12 -  -  -  -  -  -  -12 -268 -268 -  -  -12 -  -  -  -12 -  -  -  -1 -12 -  -12 -12 -  -  -  -  -12 -  -  -1 -13 -13 -  -  -  -  -  -  -  -13 -  -  -1 -12 -12 -12 -  -12 -2106 -2106 -  -  -2106 -  -2106 -  -  -  -  -  -  -2106 -  -  -2106 -  -  -12 -  -12 -  -  -  -1 -2106 -  -  -2106 -163 -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -1943 -  -19 -  -  -1924 -  -  -  -  -  -  -  -1 - 
'use strict';
- 
-// The zip file spec is at http://www.pkware.com/documents/casestudies/APPNOTE.TXT
-// TODO: There is fair chunk of the spec that I have ignored. Need to add
-// assertions everywhere to make sure that we are not dealing with a ZIP type
-// that I haven't designed for. Things like spanning archives, non-DEFLATE
-// compression, encryption, etc.
-var fs = require('fs');
-var stream = require('stream');
-Eif (!stream.Readable) {
-    var stream = require('readable-stream');
-}
-var Q = require('q');
-var path = require('path');
-var util = require('util');
-var events = require('events');
-var structures = require('./structures');
-var signatures = require('./signatures');
-var extractors = require('./extractors');
-var huntSize = 1024; // We will search the last 1kb for END_OF_CENTRAL_DIRECTORY
- 
-// Denodify some node lib methods
- 
-var fstat = Q.denodeify(fs.fstat);
-var read = Q.denodeify(fs.read);
-var fopen = Q.denodeify(fs.open);
- 
-// Class definition
- 
-function DecompressZip(filename) {
-    events.EventEmitter.call(this);
- 
-    this.filename = filename;
-    this.fileBuffer = null;
-    this.fd = null;
- 
-    // When we need a resource, we should check if there is a promise for it
-    // already and use that. If the promise is already fulfilled we don't do the
-    // async work again and we get to queue up dependant tasks.
-    this._p = {}; // _p instead of _promises because it is a lot easier to read
-}
- 
-util.inherits(DecompressZip, events.EventEmitter);
- 
-DecompressZip.version = require('../package.json').version;
- 
-DecompressZip.prototype.openFile = function () {
-    return fopen(this.filename, 'r');
-};
- 
-DecompressZip.prototype.statFile = function (fd) {
-    this.fd = fd;
-    return fstat(fd);
-};
- 
-DecompressZip.prototype.list = function () {
-    var self = this;
- 
-    this.getFiles()
-    .then(function (files) {
-        var result = [];
- 
-        files.forEach(function (file) {
-            result.push(file.name);
-        });
- 
-        self.emit('list', result);
-    })
-    .fail(function (error) {
-        self.emit('error', error);
-    });
- 
-    return this;
-};
- 
-DecompressZip.prototype.extract = function (options) {
-    var self = this;
- 
-    options = options || {};
-    options.path = options.path || '.';
- 
-    this.getFiles()
-    .then(function (files) {
-        var promises = [];
-        var results = [];
- 
-        files.forEach(function (file) {
-            var promise = self._extract(file, options.path)
-            .then(function (result) {
-                results.push(result);
-            });
- 
-            promises.push(promise);
-        });
- 
-        return Q.all(promises)
-        .then(function () {
-            self.emit('extract', results);
-        });
-    })
-    .fail(function (error) {
-        self.emit('error', error);
-    });
- 
-    return this;
-};
- 
-// Utility methods
-DecompressZip.prototype.getSearchBuffer = function (stats) {
-    var size = Math.min(stats.size, huntSize);
-    return read(this.fd, new Buffer(size), 0, size, stats.size - size)
-    .then(function (result) {
-        return result[1];
-    });
-};
- 
-DecompressZip.prototype.findEndOfDirectory = function (buffer) {
-    var index = buffer.length - 3;
-    var chunk = '';
- 
-    // Apparently the ZIP spec is not very good and it is impossible to
-    // guarantee that you have read a zip file correctly, or to determine
-    // the location of the CD without hunting.
-    // Search backwards through the buffer, as it is very likely to be near the
-    // end of the file.
-    while (index > Math.max(buffer.length - huntSize, 0) && chunk !== signatures.END_OF_CENTRAL_DIRECTORY) {
-        index--;
-        chunk = buffer.readUInt32LE(index);
-    }
- 
-    Iif (chunk !== signatures.END_OF_CENTRAL_DIRECTORY) {
-        throw new Error('Could not find the End of Central Directory Record');
-    }
- 
-    return buffer.slice(index);
-};
- 
-// Directory here means the ZIP Central Directory, not a folder
-DecompressZip.prototype.readDirectory = function (recordBuffer) {
-    var record = structures.readEndRecord(recordBuffer);
- 
-    var directoryStream = new stream.Readable();
-    directoryStream.wrap(fs.createReadStream(this.filename, {
-        start: record.directoryOffset,
-        end: record.directoryOffset + record.directorySize
-    }));
- 
-    return structures.readDirectory(directoryStream, record.directoryEntryCount);
-};
- 
-DecompressZip.prototype.getFiles = function () {
-    Eif (!this._p.getFiles) {
-        this._p.getFiles = this.openFile()
-        .then(this.statFile.bind(this))
-        .then(this.getSearchBuffer.bind(this))
-        .then(this.findEndOfDirectory.bind(this))
-        .then(this.readDirectory.bind(this))
-        .then(this.readFileEntries.bind(this));
-    }
- 
-    return this._p.getFiles;
-};
- 
-DecompressZip.prototype.readFileEntries = function (directory) {
-    var promises = [];
-    var files = [];
-    var self = this;
- 
-    directory.forEach(function (directoryEntry, index) {
-        var fileStream = stream.Readable();
-        fileStream.wrap(fs.createReadStream(self.filename, {
-            start: directoryEntry.relativeOffsetOfLocalHeader
-        }));
-        var promise = structures.readFileEntry(fileStream, directoryEntry.relativeOffsetOfLocalHeader)
-        .then(function (fileEntry) {
-            files[index] = {
-                name: directoryEntry.fileName,
-                directoryEntry: directoryEntry,
-                fileEntry: fileEntry,
-                dataOffset: directoryEntry.relativeOffsetOfLocalHeader + fileEntry.entryLength
-            };
- 
-            self.emit('file', files[index]);
-        });
- 
-        promises.push(promise);
-    });
- 
-    return Q.all(promises)
-    .then(function () {
-        return files;
-    });
-};
- 
-DecompressZip.prototype._extract = function (file, destination) {
-    destination = path.join(destination, file.name);
- 
-    // TODO: This actually needs to come from the externalAttributes
-    if (file.name.substr(-1) === '/') {
-        return extractors.folder(file, destination);
-    }
- 
-    // Possible compression methods:
-    //    0 - The file is stored (no compression)
-    //    1 - The file is Shrunk
-    //    2 - The file is Reduced with compression factor 1
-    //    3 - The file is Reduced with compression factor 2
-    //    4 - The file is Reduced with compression factor 3
-    //    5 - The file is Reduced with compression factor 4
-    //    6 - The file is Imploded
-    //    7 - Reserved for Tokenizing compression algorithm
-    //    8 - The file is Deflated
-    //    9 - Enhanced Deflating using Deflate64(tm)
-    //   10 - PKWARE Data Compression Library Imploding (old IBM TERSE)
-    //   11 - Reserved by PKWARE
-    //   12 - File is compressed using BZIP2 algorithm
-    //   13 - Reserved by PKWARE
-    //   14 - LZMA (EFS)
-    //   15 - Reserved by PKWARE
-    //   16 - Reserved by PKWARE
-    //   17 - Reserved by PKWARE
-    //   18 - File is compressed using IBM TERSE (new)
-    //   19 - IBM LZ77 z Architecture (PFS)
-    //   97 - WavPack compressed data
-    //   98 - PPMd version I, Rev 1
- 
-    switch (file.directoryEntry.compressionMethod) {
-    case 0:
-        return extractors.store(file, destination, this.filename);
- 
-    case 8:
-        return extractors.deflate(file, destination, this.filename);
- 
-    default:
-        throw new Error('Unsupported compression type');
-    }
-};
- 
- 
-module.exports = DecompressZip;
- 
- -
- - - - - - - - diff --git a/src/extensibility/node/node_modules/decompress-zip/coverage/lcov-report/lib/extractors.js.html b/src/extensibility/node/node_modules/decompress-zip/coverage/lcov-report/lib/extractors.js.html deleted file mode 100644 index 2dcd31065ee..00000000000 --- a/src/extensibility/node/node_modules/decompress-zip/coverage/lcov-report/lib/extractors.js.html +++ /dev/null @@ -1,623 +0,0 @@ - - - - Code coverage report for lib/extractors.js - - - - - - - -
-

Code coverage report for lib/extractors.js

-

- - Statements: 96% (48 / 50)      - - - Branches: 87.5% (7 / 8)      - - - Functions: 92.31% (12 / 13)      - - - Lines: 96% (48 / 50)      - -

-
All files » lib/ » extractors.js
-
-
-

-
-
1 -2 -3 -4 -5 -6 -7 -8 -9 -10 -11 -12 -13 -14 -15 -16 -17 -18 -19 -20 -21 -22 -23 -24 -25 -26 -27 -28 -29 -30 -31 -32 -33 -34 -35 -36 -37 -38 -39 -40 -41 -42 -43 -44 -45 -46 -47 -48 -49 -50 -51 -52 -53 -54 -55 -56 -57 -58 -59 -60 -61 -62 -63 -64 -65 -66 -67 -68 -69 -70 -71 -72 -73 -74 -75 -76 -77 -78 -79 -80 -81 -82 -83 -84 -85 -86 -87 -88 -89 -90 -91 -92 -93 -94 -95 -96 -97 -98 -99 -100 -101 -102 -103 -104 -105 -106 -1071 -1 -  -  -1 -1 -1 -1 -1 -1 -1 -  -  -  -  -1 -2364 -  -2364 -259 -  -259 -1 -  -258 -  -  -259 -259 -  -  -  -2364 -  -  -  -1 -  -163 -  -163 -  -  -  -19 -  -19 -1 -  -18 -18 -18 -  -  -19 -  -  -19 -  -  -  -  -  -  -  -1924 -  -  -  -  -1924 -1924 -1924 -  -1924 -  -  -1924 -  -  -  -  -1 -1942 -1942 -1942 -  -  -  -1942 -1942 -  -  -1942 -1942 -1942 -  -  -  -1942 -  -1942 -  -  -  -1 - 
var stream = require('stream');
-Iif (!stream.Readable) {
-    var stream = require('readable-stream');
-}
-var fs = require('fs');
-var Q = require('q');
-var path = require('path');
-var zlib = require('zlib');
-var touch = Q.denodeify(require('touch'));
-var mkpath = Q.denodeify(require('mkpath'));
-var cache = {};
- 
-// Use a cache of promises for building the directory tree. This allows us to
-// correctly queue up file extractions for after their path has been created,
-// avoid trying to create the path twice and still be async.
-var mkdir = function (dir) {
-    dir = path.normalize(path.resolve(process.cwd(), dir) + path.sep);
- 
-    if (!cache[dir]) {
-        var parent;
- 
-        if (dir === '/') {
-            parent = new Q();
-        } else {
-            parent = mkdir(path.dirname(dir));
-        }
- 
-        cache[dir] = parent.then(function () {
-            return mkpath(dir);
-        });
-    }
- 
-    return cache[dir];
-};
- 
-// Utility methods for writing output files
-var extractors = {
-    folder: function (folder, destination) {
-        return mkdir(destination)
-        .then(function () {
-            return {folder: folder.name};
-        });
-    },
-    store: function (file, destination, sourceFile) {
-        var writer;
- 
-        if (file.directoryEntry.uncompressedSize === 0) {
-            writer = touch.bind(null, destination);
-        } else {
-            var input = new stream.Readable();
-            input.wrap(fs.createReadStream(sourceFile, {start: file.dataOffset, end: file.dataOffset + file.directoryEntry.uncompressedSize - 1}));
-            writer = pipePromise.bind(null, input, destination);
-        }
- 
-        return mkdir(path.dirname(destination))
-        .then(writer)
-        .then(function () {
-            return {stored: file.name};
-        });
-    },
-    deflate: function (file, destination, sourceFile) {
-        // For Deflate you don't actually need to specify the end offset - and
-        // in fact many ZIP files don't include compressed file sizes for
-        // Deflated files so we don't even know what the end offset is.
- 
-        return mkdir(path.dirname(destination))
-        .then(function () {
-            // For node 0.8 we need to create the Zlib stream and attach
-            // handlers in the same tick of the event loop, which is why we do
-            // the creation in here
-            var input = new stream.Readable();
-            input.wrap(fs.createReadStream(sourceFile, {start: file.dataOffset}));
-            var inflater = input.pipe(zlib.createInflateRaw({highWaterMark: 32 * 1024}));
- 
-            return pipePromise(inflater, destination);
-        })
-        .then(function () {
-            return {deflated: file.name};
-        });
-    }
-};
- 
-var pipePromise = function (input, destination) {
-    var deferred = Q.defer();
-    var output = fs.createWriteStream(destination);
-    var errorHandler = function (error) {
-        deferred.reject(error);
-    };
- 
-    input.on('error', errorHandler);
-    output.on('error', errorHandler);
- 
-    // For node 0.8 we can't just use the 'finish' event of the pipe
-    input.on('end', function () {
-        output.end(function () {
-            deferred.resolve();
-        });
-    });
- 
-    input.pipe(output, {end: false});
- 
-    return deferred.promise;
-};
- 
- 
-module.exports = extractors;
- 
- -
- - - - - - - - diff --git a/src/extensibility/node/node_modules/decompress-zip/coverage/lcov-report/lib/index.html b/src/extensibility/node/node_modules/decompress-zip/coverage/lcov-report/lib/index.html deleted file mode 100644 index 783b56a3447..00000000000 --- a/src/extensibility/node/node_modules/decompress-zip/coverage/lcov-report/lib/index.html +++ /dev/null @@ -1,372 +0,0 @@ - - - - Code coverage report for lib/ - - - - - - - -
-

Code coverage report for lib/

-

- - Statements: 91.24% (229 / 251)      - - - Branches: 67.69% (44 / 65)      - - - Functions: 85.11% (40 / 47)      - - - Lines: 91.24% (229 / 251)      - -

-
All files » lib/
-
-
-
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
FileStatementsBranchesFunctionsLines
decompress-zip.js89.69%(87 / 97)64.71%(11 / 17)82.61%(19 / 23)89.69%(87 / 97)
extractors.js96%(48 / 50)87.5%(7 / 8)92.31%(12 / 13)96%(48 / 50)
signatures.js100%(1 / 1)100%(0 / 0)100%(0 / 0)100%(1 / 1)
structures.js90.29%(93 / 103)65%(26 / 40)81.82%(9 / 11)90.29%(93 / 103)
-
-
- - - - - - - - diff --git a/src/extensibility/node/node_modules/decompress-zip/coverage/lcov-report/lib/signatures.js.html b/src/extensibility/node/node_modules/decompress-zip/coverage/lcov-report/lib/signatures.js.html deleted file mode 100644 index 422b7138e6a..00000000000 --- a/src/extensibility/node/node_modules/decompress-zip/coverage/lcov-report/lib/signatures.js.html +++ /dev/null @@ -1,335 +0,0 @@ - - - - Code coverage report for lib/signatures.js - - - - - - - -
-

Code coverage report for lib/signatures.js

-

- - Statements: 100% (1 / 1)      - - - Branches: 100% (0 / 0)      - - - Functions: 100% (0 / 0)      - - - Lines: 100% (1 / 1)      - -

-
All files » lib/ » signatures.js
-
-
-

-
-
1 -2 -3 -4 -5 -6 -7 -8 -9 -10 -111 -  -  -  -  -  -  -  -  -  - 
module.exports = {
-    LOCAL_FILE_HEADER: 0x04034b50,
-    DATA_DESCRIPTOR_RECORD: 0x08074b50,
-    ARCHIVE_EXTRA_DATA: 0x08064b50,
-    CENTRAL_FILE_HEADER: 0x02014b50,
-    HEADER: 0x05054b50,
-    ZIP64_END_OF_CENTRAL_DIRECTORY: 0x06064b50,
-    ZIP64_END_OF_CENTRAL_DIRECTORY_LOCATOR: 0x07064b50,
-    END_OF_CENTRAL_DIRECTORY: 0x06054b50
-};
- 
- -
- - - - - - - - diff --git a/src/extensibility/node/node_modules/decompress-zip/coverage/lcov-report/lib/structures.js.html b/src/extensibility/node/node_modules/decompress-zip/coverage/lcov-report/lib/structures.js.html deleted file mode 100644 index 2ddd9fa9fcf..00000000000 --- a/src/extensibility/node/node_modules/decompress-zip/coverage/lcov-report/lib/structures.js.html +++ /dev/null @@ -1,995 +0,0 @@ - - - - Code coverage report for lib/structures.js - - - - - - - -
-

Code coverage report for lib/structures.js

-

- - Statements: 90.29% (93 / 103)      - - - Branches: 65% (26 / 40)      - - - Functions: 81.82% (9 / 11)      - - - Lines: 90.29% (93 / 103)      - -

-
All files » lib/ » structures.js
-
-
-

-
-
1 -2 -3 -4 -5 -6 -7 -8 -9 -10 -11 -12 -13 -14 -15 -16 -17 -18 -19 -20 -21 -22 -23 -24 -25 -26 -27 -28 -29 -30 -31 -32 -33 -34 -35 -36 -37 -38 -39 -40 -41 -42 -43 -44 -45 -46 -47 -48 -49 -50 -51 -52 -53 -54 -55 -56 -57 -58 -59 -60 -61 -62 -63 -64 -65 -66 -67 -68 -69 -70 -71 -72 -73 -74 -75 -76 -77 -78 -79 -80 -81 -82 -83 -84 -85 -86 -87 -88 -89 -90 -91 -92 -93 -94 -95 -96 -97 -98 -99 -100 -101 -102 -103 -104 -105 -106 -107 -108 -109 -110 -111 -112 -113 -114 -115 -116 -117 -118 -119 -120 -121 -122 -123 -124 -125 -126 -127 -128 -129 -130 -131 -132 -133 -134 -135 -136 -137 -138 -139 -140 -141 -142 -143 -144 -145 -146 -147 -148 -149 -150 -151 -152 -153 -154 -155 -156 -157 -158 -159 -160 -161 -162 -163 -164 -165 -166 -167 -168 -169 -170 -171 -172 -173 -174 -175 -176 -177 -178 -179 -180 -181 -182 -183 -184 -185 -186 -187 -188 -189 -190 -191 -192 -193 -194 -195 -196 -197 -198 -199 -200 -201 -202 -203 -204 -205 -206 -207 -208 -209 -210 -211 -212 -213 -214 -215 -216 -217 -218 -219 -220 -221 -222 -223 -224 -225 -226 -227 -228 -229 -230 -2311 -  -1 -1 -  -1 -2106 -2106 -2106 -  -2106 -2106 -2106 -  -2106 -  -2106 -  -  -1 -12 -  -  -  -  -  -  -  -  -  -  -  -12 -  -12 -  -  -1 -12 -12 -12 -12 -  -12 -27 -  -27 -2109 -2109 -2109 -3 -  -  -2106 -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -2106 -  -2106 -33696 -  -  -2106 -2106 -2106 -  -2106 -  -  -2106 -2106 -2106 -2106 -  -  -  -2106 -  -  -2106 -  -  -2106 -2106 -945 -945 -  -  -  -945 -  -  -2106 -  -  -2106 -2106 -  -  -  -  -  -  -  -2106 -  -2106 -12 -12 -  -  -2106 -  -  -  -  -12 -12 -  -  -12 -  -  -  -12 -  -  -1 -2106 -2106 -2106 -  -2106 -4212 -  -4212 -2106 -2106 -  -  -  -2106 -  -  -  -  -  -  -  -  -  -  -  -  -  -2106 -  -2106 -  -2106 -  -  -4212 -2106 -2106 -2106 -  -  -  -2106 -  -  -2106 -  -  -4212 -4212 -1902 -1902 -951 -  -  -951 -  -  -3261 -  -3261 -  -  -  -2106 -2106 -  -  -2106 -2106 -  -  -2106 -  -  -  -2106 -  -  -1 -  -  -  -  - 
'use strict';
- 
-var binary = require('binary');
-var Q = require('q');
- 
-var convertDateTime = function (dosDate, dosTime) {
-    var year = ((dosDate >> 9) & 0x7F) + 1980;
-    var month = (dosDate >> 5) & 0x0F;
-    var day = dosDate & 0x1F;
- 
-    var hour = (dosTime >> 11);
-    var minute = (dosTime >> 5) & 0x3F;
-    var second = (dosTime & 0x1F) * 2;
- 
-    var result = new Date(year, month - 1, day, hour, minute, second, 0);
- 
-    return result;
-};
- 
-var readEndRecord = function (buffer) {
-    var data = binary.parse(buffer)
-    .word32lu('signature')
-    .word16lu('diskNumber')
-    .word16lu('directoryStartDisk')
-    .word16lu('directoryEntryCountDisk')
-    .word16lu('directoryEntryCount')
-    .word32lu('directorySize')
-    .word32lu('directoryOffset')
-    .word16lu('commentLength')
-    .buffer('comment', 'commentLength')
-    .vars;
- 
-    data.comment = data.comment.toString();
- 
-    return data;
-};
- 
-var readDirectory = function (stream, count) {
-    var deferred = Q.defer();
-    var stage = 'main';
-    var directory = [];
-    var current;
- 
-    stream.on('readable', function () {
-        var chunk;
- 
-        while (directory.length < count) {
-            Eif (stage === 'main') {
-                chunk = stream.read(46);
-                if (chunk === null) {
-                    return;
-                }
- 
-                current = binary.parse(chunk)
-                .word32lu('signature')
-                .word8lu('creatorSpecVersion')
-                .word8lu('creatorPlatform')
-                .word8lu('requiredSpecVersion')
-                .word8lu('requiredPlatform')
-                .word16lu('generalPurposeBitFlag')
-                .word16lu('compressionMethod')
-                .word16lu('lastModFileTime')
-                .word16lu('lastModFileDate')
-                .word32lu('crc32')
-                .word32lu('compressedSize')
-                .word32lu('uncompressedSize')
-                .word16lu('fileNameLength')
-                .word16lu('extraFieldLength')
-                .word16lu('fileCommentLength')
-                .word16lu('diskNumberStart')
-                .word16lu('internalFileAttributes')
-                .word32lu('externalFileAttributes')
-                .word32lu('relativeOffsetOfLocalHeader')
-                .vars;
- 
-                current.generalPurposeFlags = [];
- 
-                for (var i = 0; i < 16; i++) {
-                    current.generalPurposeFlags[i] = (current.generalPurposeBitFlag >> i) & 1;
-                }
- 
-                current.modifiedTime = convertDateTime(current.lastModFileDate, current.lastModFileTime);
-                current.fileName = current.extraField = current.fileComment = '';
-                current.headerLength = 46 + current.fileNameLength + current.extraFieldLength + current.fileCommentLength;
- 
-                stage = 'fileName';
-            }
- 
-            Eif (stage === 'fileName') {
-                Eif (current.fileNameLength > 0) {
-                    chunk = stream.read(current.fileNameLength);
-                    Iif (chunk === null) {
-                        return;
-                    }
- 
-                    current.fileName = chunk.toString();
-                }
- 
-                stage = 'extraField';
-            }
- 
-            Eif (stage === 'extraField') {
-                if (current.extraFieldLength > 0) {
-                    chunk = stream.read(current.extraFieldLength);
-                    Iif (chunk === null) {
-                        return;
-                    }
- 
-                    current.extraField = chunk.toString();
-                }
- 
-                stage = 'fileComment';
-            }
- 
-            Eif (stage === 'fileComment') {
-                Iif (current.fileCommentLength > 0) {
-                    chunk = stream.read(current.fileCommentLength);
-                    if (chunk === null) {
-                        return;
-                    }
-                    current.fileComment = chunk.toString();
-                }
- 
-                directory.push(current);
- 
-                if (directory.length === count) {
-                    deferred.resolve(directory);
-                    stream.resume();
-                }
- 
-                stage = 'main';
-            }
-        }
-    });
- 
-    stream.on('end', function () {
-        deferred.resolve(directory);
-    });
- 
-    stream.on('error', function (err) {
-        deferred.reject(err);
-    });
- 
-    return deferred.promise;
-};
- 
-var readFileEntry = function (stream) {
-    var deferred = Q.defer();
-    var stage = 'main';
-    var data;
- 
-    stream.on('readable', function () {
-        var chunk;
- 
-        if (stage === 'main') {
-            chunk = stream.read(30);
-            Iif (chunk === null) {
-                return;
-            }
- 
-            data = binary.parse(chunk)
-            .word32lu('signature')
-            .word16lu('versionNeededToExtract')
-            .word16lu('generalPurposeBitFlag')
-            .word16lu('compressionMethod')
-            .word16lu('lastModFileTime')
-            .word16lu('lastModFileDate')
-            .word32lu('crc32')
-            .word32lu('compressedSize')
-            .word32lu('uncompressedSize')
-            .word16lu('fileNameLength')
-            .word16lu('extraFieldLength')
-            .vars;
- 
-            data.fileName = data.extraField = '';
- 
-            data.entryLength = 30 + data.fileNameLength + data.extraFieldLength;
- 
-            stage = 'fileName';
-        }
- 
-        if (stage === 'fileName') {
-            Eif (data.fileNameLength > 0) {
-                chunk = stream.read(data.fileNameLength);
-                Iif (chunk === null) {
-                    return;
-                }
- 
-                data.fileName = chunk.toString();
-            }
- 
-            stage = 'extraField';
-        }
- 
-        Eif (stage === 'extraField') {
-            if (data.extraFieldLength > 0) {
-                chunk = stream.read(data.extraFieldLength);
-                if (chunk === null) {
-                    return;
-                }
- 
-                data.extraField = chunk.toString();
-            }
- 
-            deferred.resolve(data);
-            // Run the stream to the end so that it can be closed
-            stream.resume();
-        }
-    });
- 
-    stream.on('end', function () {
-        deferred.resolve(data);
-    });
- 
-    stream.on('close', function () {
-        deferred.resolve(data);
-    });
- 
-    stream.on('error', function (err) {
-        deferred.reject(err);
-    });
- 
-    return deferred.promise;
-};
- 
-module.exports = {
-    readEndRecord: readEndRecord,
-    readDirectory: readDirectory,
-    readFileEntry: readFileEntry
-};
- 
- -
- - - - - - - - diff --git a/src/extensibility/node/node_modules/decompress-zip/coverage/lcov-report/prettify.css b/src/extensibility/node/node_modules/decompress-zip/coverage/lcov-report/prettify.css deleted file mode 100644 index b317a7cda31..00000000000 --- a/src/extensibility/node/node_modules/decompress-zip/coverage/lcov-report/prettify.css +++ /dev/null @@ -1 +0,0 @@ -.pln{color:#000}@media screen{.str{color:#080}.kwd{color:#008}.com{color:#800}.typ{color:#606}.lit{color:#066}.pun,.opn,.clo{color:#660}.tag{color:#008}.atn{color:#606}.atv{color:#080}.dec,.var{color:#606}.fun{color:red}}@media print,projection{.str{color:#060}.kwd{color:#006;font-weight:bold}.com{color:#600;font-style:italic}.typ{color:#404;font-weight:bold}.lit{color:#044}.pun,.opn,.clo{color:#440}.tag{color:#006;font-weight:bold}.atn{color:#404}.atv{color:#060}}pre.prettyprint{padding:2px;border:1px solid #888}ol.linenums{margin-top:0;margin-bottom:0}li.L0,li.L1,li.L2,li.L3,li.L5,li.L6,li.L7,li.L8{list-style-type:none}li.L1,li.L3,li.L5,li.L7,li.L9{background:#eee} diff --git a/src/extensibility/node/node_modules/decompress-zip/coverage/lcov-report/prettify.js b/src/extensibility/node/node_modules/decompress-zip/coverage/lcov-report/prettify.js deleted file mode 100644 index ef51e038668..00000000000 --- a/src/extensibility/node/node_modules/decompress-zip/coverage/lcov-report/prettify.js +++ /dev/null @@ -1 +0,0 @@ -window.PR_SHOULD_USE_CONTINUATION=true;(function(){var h=["break,continue,do,else,for,if,return,while"];var u=[h,"auto,case,char,const,default,double,enum,extern,float,goto,int,long,register,short,signed,sizeof,static,struct,switch,typedef,union,unsigned,void,volatile"];var p=[u,"catch,class,delete,false,import,new,operator,private,protected,public,this,throw,true,try,typeof"];var l=[p,"alignof,align_union,asm,axiom,bool,concept,concept_map,const_cast,constexpr,decltype,dynamic_cast,explicit,export,friend,inline,late_check,mutable,namespace,nullptr,reinterpret_cast,static_assert,static_cast,template,typeid,typename,using,virtual,where"];var x=[p,"abstract,boolean,byte,extends,final,finally,implements,import,instanceof,null,native,package,strictfp,super,synchronized,throws,transient"];var R=[x,"as,base,by,checked,decimal,delegate,descending,dynamic,event,fixed,foreach,from,group,implicit,in,interface,internal,into,is,lock,object,out,override,orderby,params,partial,readonly,ref,sbyte,sealed,stackalloc,string,select,uint,ulong,unchecked,unsafe,ushort,var"];var r="all,and,by,catch,class,else,extends,false,finally,for,if,in,is,isnt,loop,new,no,not,null,of,off,on,or,return,super,then,true,try,unless,until,when,while,yes";var w=[p,"debugger,eval,export,function,get,null,set,undefined,var,with,Infinity,NaN"];var s="caller,delete,die,do,dump,elsif,eval,exit,foreach,for,goto,if,import,last,local,my,next,no,our,print,package,redo,require,sub,undef,unless,until,use,wantarray,while,BEGIN,END";var I=[h,"and,as,assert,class,def,del,elif,except,exec,finally,from,global,import,in,is,lambda,nonlocal,not,or,pass,print,raise,try,with,yield,False,True,None"];var f=[h,"alias,and,begin,case,class,def,defined,elsif,end,ensure,false,in,module,next,nil,not,or,redo,rescue,retry,self,super,then,true,undef,unless,until,when,yield,BEGIN,END"];var H=[h,"case,done,elif,esac,eval,fi,function,in,local,set,then,until"];var A=[l,R,w,s+I,f,H];var e=/^(DIR|FILE|vector|(de|priority_)?queue|list|stack|(const_)?iterator|(multi)?(set|map)|bitset|u?(int|float)\d*)/;var C="str";var z="kwd";var j="com";var O="typ";var G="lit";var L="pun";var F="pln";var m="tag";var E="dec";var J="src";var P="atn";var n="atv";var N="nocode";var M="(?:^^\\.?|[+-]|\\!|\\!=|\\!==|\\#|\\%|\\%=|&|&&|&&=|&=|\\(|\\*|\\*=|\\+=|\\,|\\-=|\\->|\\/|\\/=|:|::|\\;|<|<<|<<=|<=|=|==|===|>|>=|>>|>>=|>>>|>>>=|\\?|\\@|\\[|\\^|\\^=|\\^\\^|\\^\\^=|\\{|\\||\\|=|\\|\\||\\|\\|=|\\~|break|case|continue|delete|do|else|finally|instanceof|return|throw|try|typeof)\\s*";function k(Z){var ad=0;var S=false;var ac=false;for(var V=0,U=Z.length;V122)){if(!(al<65||ag>90)){af.push([Math.max(65,ag)|32,Math.min(al,90)|32])}if(!(al<97||ag>122)){af.push([Math.max(97,ag)&~32,Math.min(al,122)&~32])}}}}af.sort(function(av,au){return(av[0]-au[0])||(au[1]-av[1])});var ai=[];var ap=[NaN,NaN];for(var ar=0;arat[0]){if(at[1]+1>at[0]){an.push("-")}an.push(T(at[1]))}}an.push("]");return an.join("")}function W(al){var aj=al.source.match(new RegExp("(?:\\[(?:[^\\x5C\\x5D]|\\\\[\\s\\S])*\\]|\\\\u[A-Fa-f0-9]{4}|\\\\x[A-Fa-f0-9]{2}|\\\\[0-9]+|\\\\[^ux0-9]|\\(\\?[:!=]|[\\(\\)\\^]|[^\\x5B\\x5C\\(\\)\\^]+)","g"));var ah=aj.length;var an=[];for(var ak=0,am=0;ak=2&&ai==="["){aj[ak]=X(ag)}else{if(ai!=="\\"){aj[ak]=ag.replace(/[a-zA-Z]/g,function(ao){var ap=ao.charCodeAt(0);return"["+String.fromCharCode(ap&~32,ap|32)+"]"})}}}}return aj.join("")}var aa=[];for(var V=0,U=Z.length;V=0;){S[ac.charAt(ae)]=Y}}var af=Y[1];var aa=""+af;if(!ag.hasOwnProperty(aa)){ah.push(af);ag[aa]=null}}ah.push(/[\0-\uffff]/);V=k(ah)})();var X=T.length;var W=function(ah){var Z=ah.sourceCode,Y=ah.basePos;var ad=[Y,F];var af=0;var an=Z.match(V)||[];var aj={};for(var ae=0,aq=an.length;ae=5&&"lang-"===ap.substring(0,5);if(am&&!(ai&&typeof ai[1]==="string")){am=false;ap=J}if(!am){aj[ag]=ap}}var ab=af;af+=ag.length;if(!am){ad.push(Y+ab,ap)}else{var al=ai[1];var ak=ag.indexOf(al);var ac=ak+al.length;if(ai[2]){ac=ag.length-ai[2].length;ak=ac-al.length}var ar=ap.substring(5);B(Y+ab,ag.substring(0,ak),W,ad);B(Y+ab+ak,al,q(ar,al),ad);B(Y+ab+ac,ag.substring(ac),W,ad)}}ah.decorations=ad};return W}function i(T){var W=[],S=[];if(T.tripleQuotedStrings){W.push([C,/^(?:\'\'\'(?:[^\'\\]|\\[\s\S]|\'{1,2}(?=[^\']))*(?:\'\'\'|$)|\"\"\"(?:[^\"\\]|\\[\s\S]|\"{1,2}(?=[^\"]))*(?:\"\"\"|$)|\'(?:[^\\\']|\\[\s\S])*(?:\'|$)|\"(?:[^\\\"]|\\[\s\S])*(?:\"|$))/,null,"'\""])}else{if(T.multiLineStrings){W.push([C,/^(?:\'(?:[^\\\']|\\[\s\S])*(?:\'|$)|\"(?:[^\\\"]|\\[\s\S])*(?:\"|$)|\`(?:[^\\\`]|\\[\s\S])*(?:\`|$))/,null,"'\"`"])}else{W.push([C,/^(?:\'(?:[^\\\'\r\n]|\\.)*(?:\'|$)|\"(?:[^\\\"\r\n]|\\.)*(?:\"|$))/,null,"\"'"])}}if(T.verbatimStrings){S.push([C,/^@\"(?:[^\"]|\"\")*(?:\"|$)/,null])}var Y=T.hashComments;if(Y){if(T.cStyleComments){if(Y>1){W.push([j,/^#(?:##(?:[^#]|#(?!##))*(?:###|$)|.*)/,null,"#"])}else{W.push([j,/^#(?:(?:define|elif|else|endif|error|ifdef|include|ifndef|line|pragma|undef|warning)\b|[^\r\n]*)/,null,"#"])}S.push([C,/^<(?:(?:(?:\.\.\/)*|\/?)(?:[\w-]+(?:\/[\w-]+)+)?[\w-]+\.h|[a-z]\w*)>/,null])}else{W.push([j,/^#[^\r\n]*/,null,"#"])}}if(T.cStyleComments){S.push([j,/^\/\/[^\r\n]*/,null]);S.push([j,/^\/\*[\s\S]*?(?:\*\/|$)/,null])}if(T.regexLiterals){var X=("/(?=[^/*])(?:[^/\\x5B\\x5C]|\\x5C[\\s\\S]|\\x5B(?:[^\\x5C\\x5D]|\\x5C[\\s\\S])*(?:\\x5D|$))+/");S.push(["lang-regex",new RegExp("^"+M+"("+X+")")])}var V=T.types;if(V){S.push([O,V])}var U=(""+T.keywords).replace(/^ | $/g,"");if(U.length){S.push([z,new RegExp("^(?:"+U.replace(/[\s,]+/g,"|")+")\\b"),null])}W.push([F,/^\s+/,null," \r\n\t\xA0"]);S.push([G,/^@[a-z_$][a-z_$@0-9]*/i,null],[O,/^(?:[@_]?[A-Z]+[a-z][A-Za-z_$@0-9]*|\w+_t\b)/,null],[F,/^[a-z_$][a-z_$@0-9]*/i,null],[G,new RegExp("^(?:0x[a-f0-9]+|(?:\\d(?:_\\d+)*\\d*(?:\\.\\d*)?|\\.\\d\\+)(?:e[+\\-]?\\d+)?)[a-z]*","i"),null,"0123456789"],[F,/^\\[\s\S]?/,null],[L,/^.[^\s\w\.$@\'\"\`\/\#\\]*/,null]);return g(W,S)}var K=i({keywords:A,hashComments:true,cStyleComments:true,multiLineStrings:true,regexLiterals:true});function Q(V,ag){var U=/(?:^|\s)nocode(?:\s|$)/;var ab=/\r\n?|\n/;var ac=V.ownerDocument;var S;if(V.currentStyle){S=V.currentStyle.whiteSpace}else{if(window.getComputedStyle){S=ac.defaultView.getComputedStyle(V,null).getPropertyValue("white-space")}}var Z=S&&"pre"===S.substring(0,3);var af=ac.createElement("LI");while(V.firstChild){af.appendChild(V.firstChild)}var W=[af];function ae(al){switch(al.nodeType){case 1:if(U.test(al.className)){break}if("BR"===al.nodeName){ad(al);if(al.parentNode){al.parentNode.removeChild(al)}}else{for(var an=al.firstChild;an;an=an.nextSibling){ae(an)}}break;case 3:case 4:if(Z){var am=al.nodeValue;var aj=am.match(ab);if(aj){var ai=am.substring(0,aj.index);al.nodeValue=ai;var ah=am.substring(aj.index+aj[0].length);if(ah){var ak=al.parentNode;ak.insertBefore(ac.createTextNode(ah),al.nextSibling)}ad(al);if(!ai){al.parentNode.removeChild(al)}}}break}}function ad(ak){while(!ak.nextSibling){ak=ak.parentNode;if(!ak){return}}function ai(al,ar){var aq=ar?al.cloneNode(false):al;var ao=al.parentNode;if(ao){var ap=ai(ao,1);var an=al.nextSibling;ap.appendChild(aq);for(var am=an;am;am=an){an=am.nextSibling;ap.appendChild(am)}}return aq}var ah=ai(ak.nextSibling,0);for(var aj;(aj=ah.parentNode)&&aj.nodeType===1;){ah=aj}W.push(ah)}for(var Y=0;Y=S){ah+=2}if(V>=ap){Z+=2}}}var t={};function c(U,V){for(var S=V.length;--S>=0;){var T=V[S];if(!t.hasOwnProperty(T)){t[T]=U}else{if(window.console){console.warn("cannot override language handler %s",T)}}}}function q(T,S){if(!(T&&t.hasOwnProperty(T))){T=/^\s*]*(?:>|$)/],[j,/^<\!--[\s\S]*?(?:-\->|$)/],["lang-",/^<\?([\s\S]+?)(?:\?>|$)/],["lang-",/^<%([\s\S]+?)(?:%>|$)/],[L,/^(?:<[%?]|[%?]>)/],["lang-",/^]*>([\s\S]+?)<\/xmp\b[^>]*>/i],["lang-js",/^]*>([\s\S]*?)(<\/script\b[^>]*>)/i],["lang-css",/^]*>([\s\S]*?)(<\/style\b[^>]*>)/i],["lang-in.tag",/^(<\/?[a-z][^<>]*>)/i]]),["default-markup","htm","html","mxml","xhtml","xml","xsl"]);c(g([[F,/^[\s]+/,null," \t\r\n"],[n,/^(?:\"[^\"]*\"?|\'[^\']*\'?)/,null,"\"'"]],[[m,/^^<\/?[a-z](?:[\w.:-]*\w)?|\/?>$/i],[P,/^(?!style[\s=]|on)[a-z](?:[\w:-]*\w)?/i],["lang-uq.val",/^=\s*([^>\'\"\s]*(?:[^>\'\"\s\/]|\/(?=\s)))/],[L,/^[=<>\/]+/],["lang-js",/^on\w+\s*=\s*\"([^\"]+)\"/i],["lang-js",/^on\w+\s*=\s*\'([^\']+)\'/i],["lang-js",/^on\w+\s*=\s*([^\"\'>\s]+)/i],["lang-css",/^style\s*=\s*\"([^\"]+)\"/i],["lang-css",/^style\s*=\s*\'([^\']+)\'/i],["lang-css",/^style\s*=\s*([^\"\'>\s]+)/i]]),["in.tag"]);c(g([],[[n,/^[\s\S]+/]]),["uq.val"]);c(i({keywords:l,hashComments:true,cStyleComments:true,types:e}),["c","cc","cpp","cxx","cyc","m"]);c(i({keywords:"null,true,false"}),["json"]);c(i({keywords:R,hashComments:true,cStyleComments:true,verbatimStrings:true,types:e}),["cs"]);c(i({keywords:x,cStyleComments:true}),["java"]);c(i({keywords:H,hashComments:true,multiLineStrings:true}),["bsh","csh","sh"]);c(i({keywords:I,hashComments:true,multiLineStrings:true,tripleQuotedStrings:true}),["cv","py"]);c(i({keywords:s,hashComments:true,multiLineStrings:true,regexLiterals:true}),["perl","pl","pm"]);c(i({keywords:f,hashComments:true,multiLineStrings:true,regexLiterals:true}),["rb"]);c(i({keywords:w,cStyleComments:true,regexLiterals:true}),["js"]);c(i({keywords:r,hashComments:3,cStyleComments:true,multilineStrings:true,tripleQuotedStrings:true,regexLiterals:true}),["coffee"]);c(g([],[[C,/^[\s\S]+/]]),["regex"]);function d(V){var U=V.langExtension;try{var S=a(V.sourceNode);var T=S.sourceCode;V.sourceCode=T;V.spans=S.spans;V.basePos=0;q(U,T)(V);D(V)}catch(W){if("console" in window){console.log(W&&W.stack?W.stack:W)}}}function y(W,V,U){var S=document.createElement("PRE");S.innerHTML=W;if(U){Q(S,U)}var T={langExtension:V,numberLines:U,sourceNode:S};d(T);return S.innerHTML}function b(ad){function Y(af){return document.getElementsByTagName(af)}var ac=[Y("pre"),Y("code"),Y("xmp")];var T=[];for(var aa=0;aa=0){var ah=ai.match(ab);var am;if(!ah&&(am=o(aj))&&"CODE"===am.tagName){ah=am.className.match(ab)}if(ah){ah=ah[1]}var al=false;for(var ak=aj.parentNode;ak;ak=ak.parentNode){if((ak.tagName==="pre"||ak.tagName==="code"||ak.tagName==="xmp")&&ak.className&&ak.className.indexOf("prettyprint")>=0){al=true;break}}if(!al){var af=aj.className.match(/\blinenums\b(?::(\d+))?/);af=af?af[1]&&af[1].length?+af[1]:true:false;if(af){Q(aj,af)}S={langExtension:ah,sourceNode:aj,numberLines:af};d(S)}}}if(X]*(?:>|$)/],[PR.PR_COMMENT,/^<\!--[\s\S]*?(?:-\->|$)/],[PR.PR_PUNCTUATION,/^(?:<[%?]|[%?]>)/],["lang-",/^<\?([\s\S]+?)(?:\?>|$)/],["lang-",/^<%([\s\S]+?)(?:%>|$)/],["lang-",/^]*>([\s\S]+?)<\/xmp\b[^>]*>/i],["lang-handlebars",/^]*type\s*=\s*['"]?text\/x-handlebars-template['"]?\b[^>]*>([\s\S]*?)(<\/script\b[^>]*>)/i],["lang-js",/^]*>([\s\S]*?)(<\/script\b[^>]*>)/i],["lang-css",/^]*>([\s\S]*?)(<\/style\b[^>]*>)/i],["lang-in.tag",/^(<\/?[a-z][^<>]*>)/i],[PR.PR_DECLARATION,/^{{[#^>/]?\s*[\w.][^}]*}}/],[PR.PR_DECLARATION,/^{{&?\s*[\w.][^}]*}}/],[PR.PR_DECLARATION,/^{{{>?\s*[\w.][^}]*}}}/],[PR.PR_COMMENT,/^{{![^}]*}}/]]),["handlebars","hbs"]);PR.registerLangHandler(PR.createSimpleLexer([[PR.PR_PLAIN,/^[ \t\r\n\f]+/,null," \t\r\n\f"]],[[PR.PR_STRING,/^\"(?:[^\n\r\f\\\"]|\\(?:\r\n?|\n|\f)|\\[\s\S])*\"/,null],[PR.PR_STRING,/^\'(?:[^\n\r\f\\\']|\\(?:\r\n?|\n|\f)|\\[\s\S])*\'/,null],["lang-css-str",/^url\(([^\)\"\']*)\)/i],[PR.PR_KEYWORD,/^(?:url|rgb|\!important|@import|@page|@media|@charset|inherit)(?=[^\-\w]|$)/i,null],["lang-css-kw",/^(-?(?:[_a-z]|(?:\\[0-9a-f]+ ?))(?:[_a-z0-9\-]|\\(?:\\[0-9a-f]+ ?))*)\s*:/i],[PR.PR_COMMENT,/^\/\*[^*]*\*+(?:[^\/*][^*]*\*+)*\//],[PR.PR_COMMENT,/^(?:)/],[PR.PR_LITERAL,/^(?:\d+|\d*\.\d+)(?:%|[a-z]+)?/i],[PR.PR_LITERAL,/^#(?:[0-9a-f]{3}){1,2}/i],[PR.PR_PLAIN,/^-?(?:[_a-z]|(?:\\[\da-f]+ ?))(?:[_a-z\d\-]|\\(?:\\[\da-f]+ ?))*/i],[PR.PR_PUNCTUATION,/^[^\s\w\'\"]+/]]),["css"]);PR.registerLangHandler(PR.createSimpleLexer([],[[PR.PR_KEYWORD,/^-?(?:[_a-z]|(?:\\[\da-f]+ ?))(?:[_a-z\d\-]|\\(?:\\[\da-f]+ ?))*/i]]),["css-kw"]);PR.registerLangHandler(PR.createSimpleLexer([],[[PR.PR_STRING,/^[^\)\"\']+/]]),["css-str"]); diff --git a/src/extensibility/node/node_modules/decompress-zip/coverage/lcov.info b/src/extensibility/node/node_modules/decompress-zip/coverage/lcov.info deleted file mode 100644 index a86666f2481..00000000000 --- a/src/extensibility/node/node_modules/decompress-zip/coverage/lcov.info +++ /dev/null @@ -1,446 +0,0 @@ -TN: -SF:/usr/local/google/home/mscales/Projects/decompress/lib/decompress-zip.js -FN:30,DecompressZip -FN:47,(anonymous_2) -FN:51,(anonymous_3) -FN:56,(anonymous_4) -FN:60,(anonymous_5) -FN:63,(anonymous_6) -FN:69,(anonymous_7) -FN:76,(anonymous_8) -FN:83,(anonymous_9) -FN:87,(anonymous_10) -FN:89,(anonymous_11) -FN:97,(anonymous_12) -FN:101,(anonymous_13) -FN:109,(anonymous_14) -FN:112,(anonymous_15) -FN:117,(anonymous_16) -FN:139,(anonymous_17) -FN:151,(anonymous_18) -FN:164,(anonymous_19) -FN:169,(anonymous_20) -FN:175,(anonymous_21) -FN:190,(anonymous_22) -FN:195,(anonymous_23) -FNF:23 -FNH:19 -FNDA:13,DecompressZip -FNDA:13,(anonymous_2) -FNDA:12,(anonymous_3) -FNDA:0,(anonymous_4) -FNDA:0,(anonymous_5) -FNDA:0,(anonymous_6) -FNDA:0,(anonymous_7) -FNDA:13,(anonymous_8) -FNDA:12,(anonymous_9) -FNDA:2106,(anonymous_10) -FNDA:2106,(anonymous_11) -FNDA:12,(anonymous_12) -FNDA:1,(anonymous_13) -FNDA:12,(anonymous_14) -FNDA:12,(anonymous_15) -FNDA:12,(anonymous_16) -FNDA:12,(anonymous_17) -FNDA:13,(anonymous_18) -FNDA:12,(anonymous_19) -FNDA:2106,(anonymous_20) -FNDA:2106,(anonymous_21) -FNDA:12,(anonymous_22) -FNDA:2106,(anonymous_23) -DA:1,1 -DA:8,1 -DA:9,1 -DA:10,1 -DA:11,1 -DA:13,1 -DA:14,1 -DA:15,1 -DA:16,1 -DA:17,1 -DA:18,1 -DA:19,1 -DA:20,1 -DA:24,1 -DA:25,1 -DA:26,1 -DA:30,1 -DA:31,13 -DA:33,13 -DA:34,13 -DA:35,13 -DA:40,13 -DA:43,1 -DA:45,1 -DA:47,1 -DA:48,13 -DA:51,1 -DA:52,12 -DA:53,12 -DA:56,1 -DA:57,0 -DA:59,0 -DA:61,0 -DA:63,0 -DA:64,0 -DA:67,0 -DA:70,0 -DA:73,0 -DA:76,1 -DA:77,13 -DA:79,13 -DA:80,13 -DA:82,13 -DA:84,12 -DA:85,12 -DA:87,12 -DA:88,2106 -DA:90,2106 -DA:93,2106 -DA:96,12 -DA:98,12 -DA:102,1 -DA:105,13 -DA:109,1 -DA:110,12 -DA:111,12 -DA:113,12 -DA:117,1 -DA:118,12 -DA:119,12 -DA:126,12 -DA:127,268 -DA:128,268 -DA:131,12 -DA:132,0 -DA:135,12 -DA:139,1 -DA:140,12 -DA:142,12 -DA:143,12 -DA:148,12 -DA:151,1 -DA:152,13 -DA:153,13 -DA:161,13 -DA:164,1 -DA:165,12 -DA:166,12 -DA:167,12 -DA:169,12 -DA:170,2106 -DA:171,2106 -DA:174,2106 -DA:176,2106 -DA:183,2106 -DA:186,2106 -DA:189,12 -DA:191,12 -DA:195,1 -DA:196,2106 -DA:199,2106 -DA:200,163 -DA:227,1943 -DA:229,19 -DA:232,1924 -DA:235,0 -DA:240,1 -LF:97 -LH:87 -BRDA:10,1,0,1 -BRDA:10,1,1,0 -BRDA:79,2,0,13 -BRDA:79,2,1,0 -BRDA:80,3,0,13 -BRDA:80,3,1,0 -BRDA:126,4,0,280 -BRDA:126,4,1,280 -BRDA:131,5,0,0 -BRDA:131,5,1,12 -BRDA:152,6,0,13 -BRDA:152,6,1,0 -BRDA:199,7,0,163 -BRDA:199,7,1,1943 -BRDA:227,8,0,19 -BRDA:227,8,1,1924 -BRDA:227,8,2,0 -BRF:17 -BRH:11 -end_of_record -TN: -SF:/usr/local/google/home/mscales/Projects/decompress/lib/structures.js -FN:6,(anonymous_1) -FN:20,(anonymous_2) -FN:38,(anonymous_3) -FN:44,(anonymous_4) -FN:136,(anonymous_5) -FN:140,(anonymous_6) -FN:147,(anonymous_7) -FN:152,(anonymous_8) -FN:211,(anonymous_9) -FN:215,(anonymous_10) -FN:219,(anonymous_11) -FNF:11 -FNH:9 -FNDA:2106,(anonymous_1) -FNDA:12,(anonymous_2) -FNDA:12,(anonymous_3) -FNDA:27,(anonymous_4) -FNDA:12,(anonymous_5) -FNDA:0,(anonymous_6) -FNDA:2106,(anonymous_7) -FNDA:4212,(anonymous_8) -FNDA:2106,(anonymous_9) -FNDA:2106,(anonymous_10) -FNDA:0,(anonymous_11) -DA:1,1 -DA:3,1 -DA:4,1 -DA:6,1 -DA:7,2106 -DA:8,2106 -DA:9,2106 -DA:11,2106 -DA:12,2106 -DA:13,2106 -DA:15,2106 -DA:17,2106 -DA:20,1 -DA:21,12 -DA:33,12 -DA:35,12 -DA:38,1 -DA:39,12 -DA:40,12 -DA:41,12 -DA:42,12 -DA:44,12 -DA:45,27 -DA:47,27 -DA:48,2109 -DA:49,2109 -DA:50,2109 -DA:51,3 -DA:54,2106 -DA:76,2106 -DA:78,2106 -DA:79,33696 -DA:82,2106 -DA:83,2106 -DA:84,2106 -DA:86,2106 -DA:89,2106 -DA:90,2106 -DA:91,2106 -DA:92,2106 -DA:93,0 -DA:96,2106 -DA:99,2106 -DA:102,2106 -DA:103,2106 -DA:104,945 -DA:105,945 -DA:106,0 -DA:109,945 -DA:112,2106 -DA:115,2106 -DA:116,2106 -DA:117,0 -DA:118,0 -DA:119,0 -DA:121,0 -DA:124,2106 -DA:126,2106 -DA:127,12 -DA:128,12 -DA:131,2106 -DA:136,12 -DA:137,12 -DA:140,12 -DA:141,0 -DA:144,12 -DA:147,1 -DA:148,2106 -DA:149,2106 -DA:150,2106 -DA:152,2106 -DA:153,4212 -DA:155,4212 -DA:156,2106 -DA:157,2106 -DA:158,0 -DA:161,2106 -DA:175,2106 -DA:177,2106 -DA:179,2106 -DA:182,4212 -DA:183,2106 -DA:184,2106 -DA:185,2106 -DA:186,0 -DA:189,2106 -DA:192,2106 -DA:195,4212 -DA:196,4212 -DA:197,1902 -DA:198,1902 -DA:199,951 -DA:202,951 -DA:205,3261 -DA:207,3261 -DA:211,2106 -DA:212,2106 -DA:215,2106 -DA:216,2106 -DA:219,2106 -DA:220,0 -DA:223,2106 -DA:226,1 -LF:103 -LH:93 -BRDA:48,1,0,2109 -BRDA:48,1,1,0 -BRDA:50,2,0,3 -BRDA:50,2,1,2106 -BRDA:89,3,0,2106 -BRDA:89,3,1,0 -BRDA:90,4,0,2106 -BRDA:90,4,1,0 -BRDA:92,5,0,0 -BRDA:92,5,1,2106 -BRDA:102,6,0,2106 -BRDA:102,6,1,0 -BRDA:103,7,0,945 -BRDA:103,7,1,1161 -BRDA:105,8,0,0 -BRDA:105,8,1,945 -BRDA:115,9,0,2106 -BRDA:115,9,1,0 -BRDA:116,10,0,0 -BRDA:116,10,1,2106 -BRDA:118,11,0,0 -BRDA:118,11,1,0 -BRDA:126,12,0,12 -BRDA:126,12,1,2094 -BRDA:155,13,0,2106 -BRDA:155,13,1,2106 -BRDA:157,14,0,0 -BRDA:157,14,1,2106 -BRDA:182,15,0,2106 -BRDA:182,15,1,2106 -BRDA:183,16,0,2106 -BRDA:183,16,1,0 -BRDA:185,17,0,0 -BRDA:185,17,1,2106 -BRDA:195,18,0,4212 -BRDA:195,18,1,0 -BRDA:196,19,0,1902 -BRDA:196,19,1,2310 -BRDA:198,20,0,951 -BRDA:198,20,1,951 -BRF:40 -BRH:26 -end_of_record -TN: -SF:/usr/local/google/home/mscales/Projects/decompress/lib/signatures.js -FNF:0 -FNH:0 -DA:1,1 -LF:1 -LH:1 -BRF:0 -BRH:0 -end_of_record -TN: -SF:/usr/local/google/home/mscales/Projects/decompress/lib/extractors.js -FN:16,(anonymous_1) -FN:28,(anonymous_2) -FN:38,(anonymous_3) -FN:40,(anonymous_4) -FN:44,(anonymous_5) -FN:57,(anonymous_6) -FN:61,(anonymous_7) -FN:67,(anonymous_8) -FN:77,(anonymous_9) -FN:83,(anonymous_10) -FN:86,(anonymous_11) -FN:94,(anonymous_12) -FN:95,(anonymous_13) -FNF:13 -FNH:12 -FNDA:2364,(anonymous_1) -FNDA:259,(anonymous_2) -FNDA:163,(anonymous_3) -FNDA:163,(anonymous_4) -FNDA:19,(anonymous_5) -FNDA:19,(anonymous_6) -FNDA:1924,(anonymous_7) -FNDA:1924,(anonymous_8) -FNDA:1924,(anonymous_9) -FNDA:1942,(anonymous_10) -FNDA:0,(anonymous_11) -FNDA:1942,(anonymous_12) -FNDA:1942,(anonymous_13) -DA:1,1 -DA:2,1 -DA:3,0 -DA:5,1 -DA:6,1 -DA:7,1 -DA:8,1 -DA:9,1 -DA:10,1 -DA:11,1 -DA:16,1 -DA:17,2364 -DA:19,2364 -DA:20,259 -DA:22,259 -DA:23,1 -DA:25,258 -DA:28,259 -DA:29,259 -DA:33,2364 -DA:37,1 -DA:39,163 -DA:41,163 -DA:45,19 -DA:47,19 -DA:48,1 -DA:50,18 -DA:51,18 -DA:52,18 -DA:55,19 -DA:58,19 -DA:66,1924 -DA:71,1924 -DA:72,1924 -DA:73,1924 -DA:75,1924 -DA:78,1924 -DA:83,1 -DA:84,1942 -DA:85,1942 -DA:86,1942 -DA:87,0 -DA:90,1942 -DA:91,1942 -DA:94,1942 -DA:95,1942 -DA:96,1942 -DA:100,1942 -DA:102,1942 -DA:106,1 -LF:50 -LH:48 -BRDA:2,1,0,0 -BRDA:2,1,1,1 -BRDA:19,2,0,259 -BRDA:19,2,1,2105 -BRDA:22,3,0,1 -BRDA:22,3,1,258 -BRDA:47,4,0,1 -BRDA:47,4,1,18 -BRF:8 -BRH:7 -end_of_record diff --git a/src/extensibility/node/node_modules/decompress-zip/download-test-assets.js b/src/extensibility/node/node_modules/decompress-zip/download-test-assets.js index 4b6917c209b..5c27e47d97c 100644 --- a/src/extensibility/node/node_modules/decompress-zip/download-test-assets.js +++ b/src/extensibility/node/node_modules/decompress-zip/download-test-assets.js @@ -11,7 +11,7 @@ var errorHandler = function (error) { }; var extract = function (filename) { - exec('tar -xvzf ' + filename, {cwd: path.join(__dirname, 'test')}, function (err, stdout, stderr) { + exec('tar -xvzf ' + filename, {cwd: path.join(__dirname, 'test'), maxBuffer: 1024*1024}, function (err, stdout, stderr) { if (err) { throw err; } diff --git a/src/extensibility/node/node_modules/decompress-zip/lib/decompress-zip.js b/src/extensibility/node/node_modules/decompress-zip/lib/decompress-zip.js index 7136da6a51d..08c21ecdc8f 100644 --- a/src/extensibility/node/node_modules/decompress-zip/lib/decompress-zip.js +++ b/src/extensibility/node/node_modules/decompress-zip/lib/decompress-zip.js @@ -6,10 +6,6 @@ // that I haven't designed for. Things like spanning archives, non-DEFLATE // compression, encryption, etc. var fs = require('fs'); -var stream = require('stream'); -if (!stream.Readable) { - var stream = require('readable-stream'); -} var Q = require('q'); var path = require('path'); var util = require('util'); @@ -17,7 +13,7 @@ var events = require('events'); var structures = require('./structures'); var signatures = require('./signatures'); var extractors = require('./extractors'); -var huntSize = 1024; // We will search the last 1kb for END_OF_CENTRAL_DIRECTORY +var FileDetails = require('./file-details'); // Denodify some node lib methods @@ -31,8 +27,9 @@ function DecompressZip(filename) { events.EventEmitter.call(this); this.filename = filename; - this.fileBuffer = null; + this.stats = null; this.fd = null; + this.chunkSize = 1024 * 1024; // Buffer up to 1Mb at a time // When we need a resource, we should check if there is a promise for it // already and use that. If the promise is already fulfilled we don't do the @@ -61,7 +58,7 @@ DecompressZip.prototype.list = function () { var result = []; files.forEach(function (file) { - result.push(file.name); + result.push(file.path); }); self.emit('list', result); @@ -84,6 +81,10 @@ DecompressZip.prototype.extract = function (options) { var promises = []; var results = []; + if (options.filter) { + files = files.filter(options.filter); + } + files.forEach(function (file) { var promise = self._extract(file, options.path) .then(function (result) { @@ -107,8 +108,14 @@ DecompressZip.prototype.extract = function (options) { // Utility methods DecompressZip.prototype.getSearchBuffer = function (stats) { - var size = Math.min(stats.size, huntSize); - return read(this.fd, new Buffer(size), 0, size, stats.size - size) + var size = Math.min(stats.size, this.chunkSize); + this.stats = stats; + return this.getBuffer(stats.size - size, stats.size); +}; + +DecompressZip.prototype.getBuffer = function (start, end) { + var size = end - start; + return read(this.fd, new Buffer(size), 0, size, start) .then(function (result) { return result[1]; }); @@ -123,7 +130,7 @@ DecompressZip.prototype.findEndOfDirectory = function (buffer) { // the location of the CD without hunting. // Search backwards through the buffer, as it is very likely to be near the // end of the file. - while (index > Math.max(buffer.length - huntSize, 0) && chunk !== signatures.END_OF_CENTRAL_DIRECTORY) { + while (index > Math.max(buffer.length - this.chunkSize, 0) && chunk !== signatures.END_OF_CENTRAL_DIRECTORY) { index--; chunk = buffer.readUInt32LE(index); } @@ -139,13 +146,8 @@ DecompressZip.prototype.findEndOfDirectory = function (buffer) { DecompressZip.prototype.readDirectory = function (recordBuffer) { var record = structures.readEndRecord(recordBuffer); - var directoryStream = new stream.Readable(); - directoryStream.wrap(fs.createReadStream(this.filename, { - start: record.directoryOffset, - end: record.directoryOffset + record.directorySize - })); - - return structures.readDirectory(directoryStream, record.directoryEntryCount); + return this.getBuffer(record.directoryOffset, record.directoryOffset + record.directorySize) + .then(structures.readDirectory.bind(null)); }; DecompressZip.prototype.getFiles = function () { @@ -167,20 +169,32 @@ DecompressZip.prototype.readFileEntries = function (directory) { var self = this; directory.forEach(function (directoryEntry, index) { - var fileStream = stream.Readable(); - fileStream.wrap(fs.createReadStream(self.filename, { - start: directoryEntry.relativeOffsetOfLocalHeader - })); - var promise = structures.readFileEntry(fileStream, directoryEntry.relativeOffsetOfLocalHeader) + var start = directoryEntry.relativeOffsetOfLocalHeader; + var end = Math.min(self.stats.size, start + structures.maxFileEntrySize); + var fileDetails = new FileDetails(directoryEntry); + + var promise = self.getBuffer(start, end) + .then(structures.readFileEntry.bind(null)) .then(function (fileEntry) { - files[index] = { - name: directoryEntry.fileName, - directoryEntry: directoryEntry, - fileEntry: fileEntry, - dataOffset: directoryEntry.relativeOffsetOfLocalHeader + fileEntry.entryLength - }; - - self.emit('file', files[index]); + var maxSize; + + if (fileDetails.compressedSize > 0) { + maxSize = fileDetails.compressedSize; + } else { + maxSize = self.stats.size; + + if (index < directory.length - 1) { + maxSize = directory[index + 1].relativeOffsetOfLocalHeader; + } + + maxSize -= start + fileEntry.entryLength; + } + + fileDetails._offset = start + fileEntry.entryLength; + fileDetails._maxSize = maxSize; + + self.emit('file', fileDetails); + files[index] = fileDetails; }); promises.push(promise); @@ -193,12 +207,7 @@ DecompressZip.prototype.readFileEntries = function (directory) { }; DecompressZip.prototype._extract = function (file, destination) { - destination = path.join(destination, file.name); - - // TODO: This actually needs to come from the externalAttributes - if (file.name.substr(-1) === '/') { - return extractors.folder(file, destination); - } + destination = path.join(destination, file.path); // Possible compression methods: // 0 - The file is stored (no compression) @@ -224,16 +233,24 @@ DecompressZip.prototype._extract = function (file, destination) { // 97 - WavPack compressed data // 98 - PPMd version I, Rev 1 - switch (file.directoryEntry.compressionMethod) { - case 0: - return extractors.store(file, destination, this.filename); + if (file.type === 'Directory') { + return extractors.folder(file, destination); + } - case 8: - return extractors.deflate(file, destination, this.filename); + if (file.type === 'File') { + switch (file.compressionMethod) { + case 0: + return extractors.store(file, destination, this); - default: - throw new Error('Unsupported compression type'); + case 8: + return extractors.deflate(file, destination, this); + + default: + throw new Error('Unsupported compression type'); + } } + + throw new Error('Unsupported file type "' + file.type + '"'); }; diff --git a/src/extensibility/node/node_modules/decompress-zip/lib/extractors.js b/src/extensibility/node/node_modules/decompress-zip/lib/extractors.js index f3061b58af3..c43a6228453 100644 --- a/src/extensibility/node/node_modules/decompress-zip/lib/extractors.js +++ b/src/extensibility/node/node_modules/decompress-zip/lib/extractors.js @@ -8,19 +8,20 @@ var path = require('path'); var zlib = require('zlib'); var touch = Q.denodeify(require('touch')); var mkpath = Q.denodeify(require('mkpath')); +var writeFile = Q.denodeify(fs.writeFile); +var inflateRaw = Q.denodeify(zlib.inflateRaw); var cache = {}; // Use a cache of promises for building the directory tree. This allows us to // correctly queue up file extractions for after their path has been created, // avoid trying to create the path twice and still be async. -var windowsRoot = /^[A-Z]:\\$/; var mkdir = function (dir) { dir = path.normalize(path.resolve(process.cwd(), dir) + path.sep); if (!cache[dir]) { var parent; - if (dir === '/' || (process.platform === "win32" && dir.match(windowsRoot))) { + if (fs.existsSync(dir)) { parent = new Q(); } else { parent = mkdir(path.dirname(dir)); @@ -39,44 +40,57 @@ var extractors = { folder: function (folder, destination) { return mkdir(destination) .then(function () { - return {folder: folder.name}; + return {folder: folder.path}; }); }, - store: function (file, destination, sourceFile) { + store: function (file, destination, zip) { var writer; - if (file.directoryEntry.uncompressedSize === 0) { + if (file.uncompressedSize === 0) { writer = touch.bind(null, destination); + } else if (file.uncompressedSize <= zip.chunkSize) { + writer = function () { + return zip.getBuffer(file._offset, file._offset + file.uncompressedSize) + .then(writeFile.bind(null, destination)); + }; } else { var input = new stream.Readable(); - input.wrap(fs.createReadStream(sourceFile, {start: file.dataOffset, end: file.dataOffset + file.directoryEntry.uncompressedSize - 1})); + input.wrap(fs.createReadStream(zip.filename, {start: file._offset, end: file._offset + file.uncompressedSize - 1})); writer = pipePromise.bind(null, input, destination); } return mkdir(path.dirname(destination)) .then(writer) .then(function () { - return {stored: file.name}; + return {stored: file.path}; }); }, - deflate: function (file, destination, sourceFile) { + deflate: function (file, destination, zip) { // For Deflate you don't actually need to specify the end offset - and // in fact many ZIP files don't include compressed file sizes for // Deflated files so we don't even know what the end offset is. return mkdir(path.dirname(destination)) .then(function () { - // For node 0.8 we need to create the Zlib stream and attach - // handlers in the same tick of the event loop, which is why we do - // the creation in here - var input = new stream.Readable(); - input.wrap(fs.createReadStream(sourceFile, {start: file.dataOffset})); - var inflater = input.pipe(zlib.createInflateRaw({highWaterMark: 32 * 1024})); - - return pipePromise(inflater, destination); + if (file._maxSize <= zip.chunkSize) { + return zip.getBuffer(file._offset, file._offset + file._maxSize) + .then(inflateRaw) + .then(function (buffer) { + return writeFile(destination, buffer); + }); + } else { + // For node 0.8 we need to create the Zlib stream and attach + // handlers in the same tick of the event loop, which is why we do + // the creation in here + var input = new stream.Readable(); + input.wrap(fs.createReadStream(zip.filename, {start: file._offset})); + var inflater = input.pipe(zlib.createInflateRaw({highWaterMark: 32 * 1024})); + + return pipePromise(inflater, destination); + } }) .then(function () { - return {deflated: file.name}; + return {deflated: file.path}; }); } }; diff --git a/src/extensibility/node/node_modules/decompress-zip/lib/file-details.js b/src/extensibility/node/node_modules/decompress-zip/lib/file-details.js new file mode 100644 index 00000000000..1f3ca689817 --- /dev/null +++ b/src/extensibility/node/node_modules/decompress-zip/lib/file-details.js @@ -0,0 +1,37 @@ +// Objects with this prototype are used as the public representation of a file +var path = require('path'); + +var FileDetails = function (directoryEntry) { + // TODO: Add 'extra field' support + + this._offset = 0; + this._maxSize = 0; + + this.parent = path.dirname(directoryEntry.fileName); + this.filename = path.basename(directoryEntry.fileName); + this.path = path.normalize(directoryEntry.fileName); + + this.type = directoryEntry.fileAttributes.type; + this.mode = directoryEntry.fileAttributes.mode; + this.compressionMethod = directoryEntry.compressionMethod; + this.modified = directoryEntry.modifiedTime; + this.crc32 = directoryEntry.crc32; + this.compressedSize = directoryEntry.compressedSize; + this.uncompressedSize = directoryEntry.uncompressedSize; + this.comment = directoryEntry.fileComment; + + this.flags = { + encrypted: directoryEntry.generalPurposeFlags.encrypted, + compressionFlag1: directoryEntry.generalPurposeFlags.compressionFlag1, + compressionFlag2: directoryEntry.generalPurposeFlags.compressionFlag2, + useDataDescriptor: directoryEntry.generalPurposeFlags.useDataDescriptor, + enhancedDeflating: directoryEntry.generalPurposeFlags.enhancedDeflating, + compressedPatched: directoryEntry.generalPurposeFlags.compressedPatched, + strongEncryption: directoryEntry.generalPurposeFlags.strongEncryption, + utf8: directoryEntry.generalPurposeFlags.utf8, + encryptedCD: directoryEntry.generalPurposeFlags.encryptedCD + }; + +}; + +module.exports = FileDetails; diff --git a/src/extensibility/node/node_modules/decompress-zip/lib/structures.js b/src/extensibility/node/node_modules/decompress-zip/lib/structures.js index dfe03308380..66096ec4ae7 100644 --- a/src/extensibility/node/node_modules/decompress-zip/lib/structures.js +++ b/src/extensibility/node/node_modules/decompress-zip/lib/structures.js @@ -1,7 +1,6 @@ 'use strict'; var binary = require('binary'); -var Q = require('q'); var convertDateTime = function (dosDate, dosTime) { var year = ((dosDate >> 9) & 0x7F) + 1980; @@ -17,6 +16,81 @@ var convertDateTime = function (dosDate, dosTime) { return result; }; +var convertGeneralPurposeFlags = function (value) { + var bits = []; + + for (var i = 0; i < 16; i++) { + bits[i] = (value >> i) & 1; + } + + return { + encrypted: !!bits[0], + compressionFlag1: !!bits[1], + compressionFlag2: !!bits[2], + useDataDescriptor: !!bits[3], + enhancedDeflating: !!bits[4], + compressedPatched: !!bits[5], + strongEncryption: !!bits[6], + utf8: !!bits[11], + encryptedCD: !!bits[13] + }; +}; + +var parseExternalFileAttributes = function (externalAttributes, platform) { + var types = { + // In theory, any of these could be set. Realistically, though, it will + // be regular, directory or symlink + 1: 'NamedPipe', + 2: 'Character', + 4: 'Directory', + 6: 'Block', + 8: 'File', + 10: 'SymbolicLink', + 12: 'Socket' + }; + + switch (platform) { + case 0: // MSDOS + var attribs = { + A: (externalAttributes >> 5) & 0x01, + D: (externalAttributes >> 4) & 0x01, + V: (externalAttributes >> 3) & 0x01, + S: (externalAttributes >> 2) & 0x01, + H: (externalAttributes >> 1) & 0x01, + R: externalAttributes & 0x01 + }; + + // With no better guidance we'll make the default permissions ugo+r + var mode = parseInt('0444', 8); + + if (attribs.D) { + mode |= parseInt('0111', 8); // Set the execute bit + } + + if (!attribs.R) { + mode |= parseInt('0222', 8); // Set the write bit + } + + mode &= ~process.umask(); + + return { + platform: 'DOS', + type: attribs.D ? 'Directory' : 'File', + mode: mode + }; + + case 3: // Unix + return { + platform: 'Unix', + type: types[(externalAttributes >> 60) & 0x0F], + mode: (externalAttributes >> 48) & 0xFFF + }; + + default: + throw new Error('Unsupported platform type (' + platform + ')'); + } +}; + var readEndRecord = function (buffer) { var data = binary.parse(buffer) .word32lu('signature') @@ -35,196 +109,114 @@ var readEndRecord = function (buffer) { return data; }; -var readDirectory = function (stream, count) { - var deferred = Q.defer(); - var stage = 'main'; +var directorySort = function (a, b) { + return a.relativeOffsetOfLocalHeader - b.relativeOffsetOfLocalHeader; +}; + +var readDirectory = function (buffer) { var directory = []; var current; - - stream.on('readable', function () { - var chunk; - - while (directory.length < count) { - if (stage === 'main') { - chunk = stream.read(46); - if (chunk === null) { - return; - } - - current = binary.parse(chunk) - .word32lu('signature') - .word8lu('creatorSpecVersion') - .word8lu('creatorPlatform') - .word8lu('requiredSpecVersion') - .word8lu('requiredPlatform') - .word16lu('generalPurposeBitFlag') - .word16lu('compressionMethod') - .word16lu('lastModFileTime') - .word16lu('lastModFileDate') - .word32lu('crc32') - .word32lu('compressedSize') - .word32lu('uncompressedSize') - .word16lu('fileNameLength') - .word16lu('extraFieldLength') - .word16lu('fileCommentLength') - .word16lu('diskNumberStart') - .word16lu('internalFileAttributes') - .word32lu('externalFileAttributes') - .word32lu('relativeOffsetOfLocalHeader') - .vars; - - current.generalPurposeFlags = []; - - for (var i = 0; i < 16; i++) { - current.generalPurposeFlags[i] = (current.generalPurposeBitFlag >> i) & 1; - } - - current.modifiedTime = convertDateTime(current.lastModFileDate, current.lastModFileTime); - current.fileName = current.extraField = current.fileComment = ''; - current.headerLength = 46 + current.fileNameLength + current.extraFieldLength + current.fileCommentLength; - - stage = 'fileName'; - } - - if (stage === 'fileName') { - if (current.fileNameLength > 0) { - chunk = stream.read(current.fileNameLength); - if (chunk === null) { - return; - } - - current.fileName = chunk.toString(); - } - - stage = 'extraField'; - } - - if (stage === 'extraField') { - if (current.extraFieldLength > 0) { - chunk = stream.read(current.extraFieldLength); - if (chunk === null) { - return; - } - - current.extraField = chunk.toString(); - } - - stage = 'fileComment'; - } - - if (stage === 'fileComment') { - if (current.fileCommentLength > 0) { - chunk = stream.read(current.fileCommentLength); - if (chunk === null) { - return; - } - current.fileComment = chunk.toString(); - } - - directory.push(current); - - if (directory.length === count) { - deferred.resolve(directory); - stream.resume(); - } - - stage = 'main'; - } + var index = 0; + + while (index < buffer.length) { + current = binary.parse(buffer.slice(index, index + 46)) + .word32lu('signature') + .word8lu('creatorSpecVersion') + .word8lu('creatorPlatform') + .word8lu('requiredSpecVersion') + .word8lu('requiredPlatform') + .word16lu('generalPurposeBitFlag') + .word16lu('compressionMethod') + .word16lu('lastModFileTime') + .word16lu('lastModFileDate') + .word32lu('crc32') + .word32lu('compressedSize') + .word32lu('uncompressedSize') + .word16lu('fileNameLength') + .word16lu('extraFieldLength') + .word16lu('fileCommentLength') + .word16lu('diskNumberStart') + .word16lu('internalFileAttributes') + .word32lu('externalFileAttributes') + .word32lu('relativeOffsetOfLocalHeader') + .vars; + + index += 46; + + current.generalPurposeFlags = convertGeneralPurposeFlags(current.generalPurposeBitFlag); + current.fileAttributes = parseExternalFileAttributes(current.externalFileAttributes, current.creatorPlatform); + + current.modifiedTime = convertDateTime(current.lastModFileDate, current.lastModFileTime); + current.fileName = current.extraField = current.fileComment = ''; + current.headerLength = 46 + current.fileNameLength + current.extraFieldLength + current.fileCommentLength; + + if (current.fileNameLength > 0) { + current.fileName = buffer.slice(index, index + current.fileNameLength).toString(); + index += current.fileNameLength; } - }); - stream.on('end', function () { - deferred.resolve(directory); - }); + if (current.extraFieldLength > 0) { + current.extraField = buffer.slice(index, index + current.extraFieldLength).toString(); + index += current.extraFieldLength; + } - stream.on('error', function (err) { - deferred.reject(err); - }); + if (current.fileCommentLength > 0) { + current.fileComment = buffer.slice(index, index + current.fileCommentLength).toString(); + index += current.fileCommentLength; + } - return deferred.promise; -}; + directory.push(current); + } -var readFileEntry = function (stream) { - var deferred = Q.defer(); - var stage = 'main'; - var data; - - stream.on('readable', function () { - var chunk; - - if (stage === 'main') { - chunk = stream.read(30); - if (chunk === null) { - return; - } - - data = binary.parse(chunk) - .word32lu('signature') - .word16lu('versionNeededToExtract') - .word16lu('generalPurposeBitFlag') - .word16lu('compressionMethod') - .word16lu('lastModFileTime') - .word16lu('lastModFileDate') - .word32lu('crc32') - .word32lu('compressedSize') - .word32lu('uncompressedSize') - .word16lu('fileNameLength') - .word16lu('extraFieldLength') - .vars; - - data.fileName = data.extraField = ''; - - data.entryLength = 30 + data.fileNameLength + data.extraFieldLength; - - stage = 'fileName'; - } + directory.sort(directorySort); - if (stage === 'fileName') { - if (data.fileNameLength > 0) { - chunk = stream.read(data.fileNameLength); - if (chunk === null) { - return; - } + return directory; +}; - data.fileName = chunk.toString(); - } +var readFileEntry = function (buffer) { + var index = 0; - stage = 'extraField'; - } + var fileEntry = binary.parse(buffer.slice(index, 30)) + .word32lu('signature') + .word16lu('versionNeededToExtract') + .word16lu('generalPurposeBitFlag') + .word16lu('compressionMethod') + .word16lu('lastModFileTime') + .word16lu('lastModFileDate') + .word32lu('crc32') + .word32lu('compressedSize') + .word32lu('uncompressedSize') + .word16lu('fileNameLength') + .word16lu('extraFieldLength') + .vars; - if (stage === 'extraField') { - if (data.extraFieldLength > 0) { - chunk = stream.read(data.extraFieldLength); - if (chunk === null) { - return; - } + index += 30; - data.extraField = chunk.toString(); - } + fileEntry.fileName = fileEntry.extraField = ''; - deferred.resolve(data); - // Run the stream to the end so that it can be closed - stream.resume(); - } - }); + fileEntry.entryLength = 30 + fileEntry.fileNameLength + fileEntry.extraFieldLength; - stream.on('end', function () { - deferred.resolve(data); - }); + if (fileEntry.entryLength > structures.maxFileEntrySize) { + throw new Error('File entry unexpectedly large: ' + fileEntry.entryLength + ' (max: ' + structures.maxFileEntrySize + ')'); + } - stream.on('close', function () { - deferred.resolve(data); - }); + if (fileEntry.fileNameLength > 0) { + fileEntry.fileName = buffer.slice(index, index + fileEntry.fileNameLength).toString(); + index += fileEntry.fileNameLength; + } - stream.on('error', function (err) { - deferred.reject(err); - }); + if (fileEntry.extraFieldLength > 0) { + fileEntry.extraField = buffer.slice(index, index + fileEntry.extraFieldLength).toString(); + index += fileEntry.extraFieldLength; + } - return deferred.promise; + return fileEntry; }; -module.exports = { + +var structures = module.exports = { readEndRecord: readEndRecord, readDirectory: readDirectory, - readFileEntry: readFileEntry + readFileEntry: readFileEntry, + maxFileEntrySize: 4096 }; diff --git a/src/extensibility/node/node_modules/decompress-zip/node_modules/mkpath/package.json b/src/extensibility/node/node_modules/decompress-zip/node_modules/mkpath/package.json index 97b98eb712c..e5dbbfcef72 100644 --- a/src/extensibility/node/node_modules/decompress-zip/node_modules/mkpath/package.json +++ b/src/extensibility/node/node_modules/decompress-zip/node_modules/mkpath/package.json @@ -31,9 +31,5 @@ "url": "https://github.com/jrajav/mkpath/issues" }, "_id": "mkpath@0.1.0", - "dist": { - "shasum": "7554a6f8d871834cc97b5462b122c4c124d6de91" - }, - "_from": "mkpath@~0.1.0", - "_resolved": "https://registry.npmjs.org/mkpath/-/mkpath-0.1.0.tgz" + "_from": "mkpath@~0.1.0" } diff --git a/src/extensibility/node/node_modules/decompress-zip/node_modules/readable-stream/node_modules/core-util-is/package.json b/src/extensibility/node/node_modules/decompress-zip/node_modules/readable-stream/node_modules/core-util-is/package.json index 58703492ee9..f201198fd79 100644 --- a/src/extensibility/node/node_modules/decompress-zip/node_modules/readable-stream/node_modules/core-util-is/package.json +++ b/src/extensibility/node/node_modules/decompress-zip/node_modules/readable-stream/node_modules/core-util-is/package.json @@ -30,9 +30,5 @@ "readme": "# core-util-is\n\nThe `util.is*` functions introduced in Node v0.12.\n", "readmeFilename": "README.md", "_id": "core-util-is@1.0.0", - "dist": { - "shasum": "152a6bee4ee9d74c2b90ded347ae32dc2d48eb56" - }, - "_from": "core-util-is@~1.0.0", - "_resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.0.tgz" + "_from": "core-util-is@~1.0.0" } diff --git a/src/extensibility/node/node_modules/decompress-zip/node_modules/readable-stream/node_modules/debuglog/package.json b/src/extensibility/node/node_modules/decompress-zip/node_modules/readable-stream/node_modules/debuglog/package.json index b0bf338620a..670c981c4e4 100644 --- a/src/extensibility/node/node_modules/decompress-zip/node_modules/readable-stream/node_modules/debuglog/package.json +++ b/src/extensibility/node/node_modules/decompress-zip/node_modules/readable-stream/node_modules/debuglog/package.json @@ -21,9 +21,5 @@ "url": "https://github.com/sam-github/debuglog/issues" }, "_id": "debuglog@0.0.2", - "dist": { - "shasum": "d3c0b85f2f80fbc785af38262a87b7d6f863ed2f" - }, - "_from": "debuglog@0.0.2", - "_resolved": "https://registry.npmjs.org/debuglog/-/debuglog-0.0.2.tgz" + "_from": "debuglog@0.0.2" } diff --git a/src/extensibility/node/node_modules/decompress-zip/node_modules/readable-stream/package.json b/src/extensibility/node/node_modules/decompress-zip/node_modules/readable-stream/package.json index 92454554212..f924f3c7bca 100644 --- a/src/extensibility/node/node_modules/decompress-zip/node_modules/readable-stream/package.json +++ b/src/extensibility/node/node_modules/decompress-zip/node_modules/readable-stream/package.json @@ -37,9 +37,5 @@ "url": "https://github.com/isaacs/readable-stream/issues" }, "_id": "readable-stream@1.1.9", - "dist": { - "shasum": "498a54a8d00748fa5e4456da4dc58f8515c3cd67" - }, - "_from": "readable-stream@~1.1.8", - "_resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.1.9.tgz" + "_from": "readable-stream@~1.1.8" } diff --git a/src/extensibility/node/node_modules/decompress-zip/node_modules/touch/package.json b/src/extensibility/node/node_modules/decompress-zip/node_modules/touch/package.json index 30fcde44704..3fc55beef72 100644 --- a/src/extensibility/node/node_modules/decompress-zip/node_modules/touch/package.json +++ b/src/extensibility/node/node_modules/decompress-zip/node_modules/touch/package.json @@ -24,9 +24,5 @@ "url": "https://github.com/isaacs/node-touch/issues" }, "_id": "touch@0.0.2", - "dist": { - "shasum": "fb15541cd258c79a1e373af9ee0beadec87319b1" - }, - "_from": "touch@0.0.2", - "_resolved": "https://registry.npmjs.org/touch/-/touch-0.0.2.tgz" + "_from": "touch@0.0.2" } diff --git a/src/extensibility/node/node_modules/decompress-zip/package.json b/src/extensibility/node/node_modules/decompress-zip/package.json index 82ed28c56d0..229afbc5075 100644 --- a/src/extensibility/node/node_modules/decompress-zip/package.json +++ b/src/extensibility/node/node_modules/decompress-zip/package.json @@ -57,8 +57,8 @@ "readmeFilename": "README.md", "_id": "decompress-zip@0.0.1", "dist": { - "shasum": "7fddd26e8944714ba79d9c473a9debb339d29030" + "shasum": "8dd672e9b56e4a7a2bc52451aac34841422498c0" }, - "_from": "decompress-zip@0.0.1", - "_resolved": "https://registry.npmjs.org/decompress-zip/-/decompress-zip-0.0.1.tgz" + "_from": "https://github.com/bower/decompress-zip/archive/705ca19e9843b409b2d01fd3e31285b305753e59.tar.gz", + "_resolved": "https://github.com/bower/decompress-zip/archive/705ca19e9843b409b2d01fd3e31285b305753e59.tar.gz" } diff --git a/src/extensibility/node/node_modules/decompress-zip/test/test.js b/src/extensibility/node/node_modules/decompress-zip/test/test.js index a827deba517..b2c39fed3d7 100644 --- a/src/extensibility/node/node_modules/decompress-zip/test/test.js +++ b/src/extensibility/node/node_modules/decompress-zip/test/test.js @@ -75,7 +75,7 @@ describe('Extract', function () { }); it('should extract without any errors', function (done) { - this.timeout(10000); + this.timeout(60000); var zip = new DecompressZip(path.join(assetsPath, sample)); zip.on('extract', function () { diff --git a/src/extensibility/node/package.json b/src/extensibility/node/package.json index 9ed0d85db29..3cd020b3c40 100644 --- a/src/extensibility/node/package.json +++ b/src/extensibility/node/package.json @@ -3,7 +3,7 @@ "description": "Used in the management of Brackets extensions", "version": "0.32.0", "dependencies": { - "decompress-zip": "0.0.1", + "decompress-zip": "https://github.com/bower/decompress-zip/archive/705ca19e9843b409b2d01fd3e31285b305753e59.tar.gz", "semver": "2.x", "fs-extra": "0.6.x", "async": "0.2.x", From 3ca4f26b58ccf1577addd62b528a248fcb8a18be Mon Sep 17 00:00:00 2001 From: Martin Zagora Date: Thu, 12 Sep 2013 14:02:39 +1000 Subject: [PATCH 41/56] Expose code inspection providers for the extensions. First go at inspectFile method. Removed Async.withTimeout from inspectFile() Separated getProvider and inspectFile logic, added usage of DocumentManager.getOpenDocumentForPath to inspectFile Modified run() to use new methods. Moved $problemsPanelTable event handlers from run() to htmlReady() for optimization. Fix the case when getCurrentDocument returns null. Check if current document hasn't changed while inspectFile was running remove async handling of provider.scanFile Refactored according to comments. Made provider response nullable again, removed the warning. Refactored getProvider to getProviderForPath and updated docs. Remove getProvider from exports. --- src/language/CodeInspection.js | 165 +++++++++++++++++++++++---------- 1 file changed, 116 insertions(+), 49 deletions(-) diff --git a/src/language/CodeInspection.js b/src/language/CodeInspection.js index cf884c494f9..9fa2181a264 100644 --- a/src/language/CodeInspection.js +++ b/src/language/CodeInspection.js @@ -45,6 +45,7 @@ define(function (require, exports, module) { CommandManager = require("command/CommandManager"), DocumentManager = require("document/DocumentManager"), EditorManager = require("editor/EditorManager"), + FileUtils = require("file/FileUtils"), LanguageManager = require("language/LanguageManager"), PreferencesManager = require("preferences/PreferencesManager"), PerfUtils = require("utils/PerfUtils"), @@ -72,7 +73,6 @@ define(function (require, exports, module) { META: "problem_type_meta" }; - /** * @private * @type {PreferenceStorage} @@ -100,6 +100,12 @@ define(function (require, exports, module) { */ var $problemsPanel; + /** + * @private + * @type {$.Element} + */ + var $problemsPanelTable; + /** * @private * @type {boolean} @@ -145,7 +151,69 @@ define(function (require, exports, module) { } _providers[languageId] = provider; } - + + /** + * Returns a provider for given file path, if one is available. + * Decision is made depending on the file extension. + * + * @param {!string} filePath + * @return ?{{name:string, scanFile:function(string, string):?{!errors:Array, aborted:boolean}} provider + */ + function getProviderForPath(filePath) { + return _providers[LanguageManager.getLanguageForPath(filePath).getId()]; + } + + /** + * Runs a file inspection over passed file, specifying a provider is optional. + * This method doesn't update the Brackets UI, just provides inspection results. + * These results will reflect any unsaved changes present in the file that is currently opened. + * + * @param {!FileEntry} fileEntry File that will be inspected for errors. + * @param ?{{name:string, scanFile:function(string, string):?{!errors:Array, aborted:boolean}} provider + * @return {$.Promise} a jQuery promise that will be resolved with ?{!errors:Array, aborted:boolean} + */ + function inspectFile(fileEntry, provider) { + var response = new $.Deferred(); + provider = provider || getProviderForPath(fileEntry.fullPath); + + if (!provider) { + response.resolve(null); + return response.promise(); + } + + var doc = DocumentManager.getOpenDocumentForPath(fileEntry.fullPath), + fileTextPromise; + + if (doc) { + fileTextPromise = new $.Deferred().resolve(doc.getText()); + } else { + fileTextPromise = FileUtils.readAsText(fileEntry); + } + + fileTextPromise + .done(function (fileText) { + var result, + perfTimerInspector = PerfUtils.markStart("CodeInspection '" + provider.name + "':\t" + fileEntry.fullPath); + + try { + result = provider.scanFile(fileText, fileEntry.fullPath); + } catch (err) { + console.error("[CodeInspection] Provider " + provider.name + " threw an error: " + err); + response.reject(err); + return; + } + + PerfUtils.addMeasurement(perfTimerInspector); + response.resolve(result); + }) + .fail(function (err) { + console.error("[CodeInspection] Could not read file for inspection: " + fileEntry.fullPath); + response.reject(err); + }); + + return response.promise(); + } + /** * Run inspector applicable to current document. Updates status bar indicator and refreshes error list in * bottom panel. @@ -159,30 +227,31 @@ define(function (require, exports, module) { return; } - var currentDoc = DocumentManager.getCurrentDocument(); - - var perfTimerDOM, - perfTimerInspector; - - var language = currentDoc ? LanguageManager.getLanguageForPath(currentDoc.file.fullPath) : ""; - var languageId = language && language.getId(); - var provider = language && _providers[languageId]; + var currentDoc = DocumentManager.getCurrentDocument(), + provider = currentDoc && getProviderForPath(currentDoc.file.fullPath); if (provider) { - perfTimerInspector = PerfUtils.markStart("CodeInspection '" + languageId + "':\t" + currentDoc.file.fullPath); - - var result = provider.scanFile(currentDoc.getText(), currentDoc.file.fullPath); - _lastResult = result; - - PerfUtils.addMeasurement(perfTimerInspector); - perfTimerDOM = PerfUtils.markStart("ProblemsPanel render:\t" + currentDoc.file.fullPath); - - if (result && result.errors.length) { + inspectFile(currentDoc.file, provider).then(function (result) { + // check if current document wasn't changed while inspectFile was running + if (currentDoc !== DocumentManager.getCurrentDocument()) { + return; + } + + _lastResult = result; + + if (!result || !result.errors.length) { + Resizer.hide($problemsPanel); + StatusBar.updateIndicator(INDICATOR_ID, true, "inspection-valid", StringUtils.format(Strings.NO_ERRORS, provider.name)); + setGotoEnabled(false); + return; + } + + var perfTimerDOM = PerfUtils.markStart("ProblemsPanel render:\t" + currentDoc.file.fullPath); + // Augment error objects with additional fields needed by Mustache template var numProblems = 0; result.errors.forEach(function (error) { error.friendlyLine = error.pos.line + 1; - error.codeSnippet = currentDoc.getLine(error.pos.line); error.codeSnippet = error.codeSnippet.substr(0, Math.min(175, error.codeSnippet.length)); // limit snippet width @@ -193,27 +262,11 @@ define(function (require, exports, module) { // Update results table var html = Mustache.render(ResultsTemplate, {reportList: result.errors}); - var $selectedRow; - $problemsPanel.find(".table-container") + $problemsPanelTable .empty() .append(html) - .scrollTop(0) // otherwise scroll pos from previous contents is remembered - .on("click", "tr", function (e) { - if ($selectedRow) { - $selectedRow.removeClass("selected"); - } - - $selectedRow = $(e.currentTarget); - $selectedRow.addClass("selected"); - var lineTd = $selectedRow.find(".line-number"); - var line = parseInt(lineTd.text(), 10) - 1; // convert friendlyLine back to pos.line - var character = lineTd.data("character"); - - var editor = EditorManager.getCurrentFullEditor(); - editor.setCursorPos(line, character, true); - EditorManager.focusEditor(); - }); + .scrollTop(0); // otherwise scroll pos from previous contents is remembered $problemsPanel.find(".title").text(StringUtils.format(Strings.ERRORS_PANEL_TITLE, provider.name)); if (!_collapsed) { @@ -231,19 +284,14 @@ define(function (require, exports, module) { StringUtils.format(Strings.MULTIPLE_ERRORS, provider.name, numProblems)); } setGotoEnabled(true); - - } else { - Resizer.hide($problemsPanel); - StatusBar.updateIndicator(INDICATOR_ID, true, "inspection-valid", StringUtils.format(Strings.NO_ERRORS, provider.name)); - setGotoEnabled(false); - } - - PerfUtils.addMeasurement(perfTimerDOM); + PerfUtils.addMeasurement(perfTimerDOM); + }); } else { // No provider for current file _lastResult = null; Resizer.hide($problemsPanel); + var language = currentDoc && LanguageManager.getLanguageForPath(currentDoc.file.fullPath); if (language) { StatusBar.updateIndicator(INDICATOR_ID, true, "inspection-disabled", StringUtils.format(Strings.NO_LINT_AVAILABLE, language.getName())); } else { @@ -339,6 +387,24 @@ define(function (require, exports, module) { var resultsPanel = PanelManager.createBottomPanel("errors", $(panelHtml), 100); $problemsPanel = $("#problems-panel"); + var $selectedRow; + $problemsPanelTable = $problemsPanel.find(".table-container") + .on("click", "tr", function (e) { + if ($selectedRow) { + $selectedRow.removeClass("selected"); + } + + $selectedRow = $(e.currentTarget); + $selectedRow.addClass("selected"); + var lineTd = $selectedRow.find(".line-number"); + var line = parseInt(lineTd.text(), 10) - 1; // convert friendlyLine back to pos.line + var character = lineTd.data("character"); + + var editor = EditorManager.getCurrentFullEditor(); + editor.setCursorPos(line, character, true); + EditorManager.focusEditor(); + }); + $("#problems-panel .close").click(function () { toggleCollapsed(true); }); @@ -363,7 +429,8 @@ define(function (require, exports, module) { // Public API - exports.register = register; - exports.Type = Type; - exports.toggleEnabled = toggleEnabled; + exports.register = register; + exports.Type = Type; + exports.toggleEnabled = toggleEnabled; + exports.inspectFile = inspectFile; }); From 34f8a42157063108cce3d5c7e632d5e4895131ed Mon Sep 17 00:00:00 2001 From: Narciso Jaramillo Date: Thu, 26 Sep 2013 15:57:52 -0700 Subject: [PATCH 42/56] Code review cleanups --- src/search/QuickOpen.js | 2 ++ src/widgets/ModalBar.js | 3 ++- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/src/search/QuickOpen.js b/src/search/QuickOpen.js index 2131dc99c77..af9135a6e64 100644 --- a/src/search/QuickOpen.js +++ b/src/search/QuickOpen.js @@ -338,6 +338,8 @@ define(function (require, exports, module) { var editor = EditorManager.getCurrentFullEditor(); editor.setCursorPos(gotoLine, 0, true); } + }) + .always(function () { self.close(); }); } else if (!isNaN(gotoLine)) { diff --git a/src/widgets/ModalBar.js b/src/widgets/ModalBar.js index 7697b311d30..a208ec8a569 100644 --- a/src/widgets/ModalBar.js +++ b/src/widgets/ModalBar.js @@ -149,9 +149,10 @@ define(function (require, exports, module) { // Preserve scroll position of the current full editor across the editor refresh, adjusting for the // height of the modal bar so the code doesn't appear to shift if possible. var fullEditor = EditorManager.getCurrentFullEditor(), - barHeight = this.height(), + barHeight, scrollPos; if (restoreScrollPos && fullEditor) { + barHeight = this.height(); scrollPos = fullEditor.getScrollPos(); } EditorManager.resizeEditor(); From 11d73cef178f6281257291e02b93a9ab3af6e486 Mon Sep 17 00:00:00 2001 From: Randy Edmunds Date: Thu, 26 Sep 2013 16:44:58 -0700 Subject: [PATCH 43/56] simplify fix by assuming intent is to type (not insert hint) --- src/editor/CodeHintList.js | 61 ++++++------------- src/editor/CodeHintManager.js | 12 ++-- src/extensions/default/CSSCodeHints/main.js | 15 +---- src/extensions/default/HTMLCodeHints/main.js | 30 ++------- .../default/HtmlEntityCodeHints/main.js | 11 +--- .../default/JavaScriptCodeHints/main.js | 8 +-- src/extensions/default/UrlCodeHints/main.js | 11 +--- 7 files changed, 36 insertions(+), 112 deletions(-) diff --git a/src/editor/CodeHintList.js b/src/editor/CodeHintList.js index 65ba0b80ab7..2a98f5fdb36 100644 --- a/src/editor/CodeHintList.js +++ b/src/editor/CodeHintList.js @@ -87,13 +87,6 @@ define(function (require, exports, module) { */ this.insertHintOnTab = insertHintOnTab; - /** - * Current query filtering hints - * - * @type {string} - */ - this.query = ""; - /** * Pending text insertion * @@ -193,7 +186,6 @@ define(function (require, exports, module) { this.hints = hintObj.hints; this.hints.handleWideResults = hintObj.handleWideResults; - this.query = hintObj.query || ""; // if there is no match, assume name is already a formatted jQuery // object; otherwise, use match to format name for display. @@ -382,28 +374,6 @@ define(function (require, exports, module) { return itemsPerPage; } - /** - * Determine whether item is in list. - * - * Performance: list is sorted alphabetically, so we could do binary search. - * - * @private - * @param {Array.} hintList - list to search - * @param {string} itemText - text of item to search for - * @return {boolean} - */ - function _listContainsItem(hintList, itemText) { - var found = false; - hintList.some(function (listItem, index) { - if (listItem[0].innerText.indexOf(itemText) === 0) { - found = true; - return true; - } - }); - - return found; - } - // If we're no longer visible, skip handling the key and end the session. if (!this.isOpen()) { this.handleClose(); @@ -436,20 +406,23 @@ define(function (require, exports, module) { (keyCode === KeyEvent.DOM_VK_TAB && this.insertHintOnTab))) { if (this.pendingText) { - // There is pending text to be inserted in page, and... - if (_listContainsItem(this.hints, this.query + this.pendingText)) { - // ...resulting text matches something in list. We can't accept it - // because the Editor will subsequently be inserting pending text - // in page, (which leads to double-insertion) so we have to eat the - // Enter (or Tab) char. - event.stopImmediatePropagation(); - event.preventDefault(); - return true; - } else { - // ...resulting text doesn't match anything in list, so - // let the event bubble. - return false; - } + // Issues #5003: We received a "selection" key while there is "pending + // text". This is rare but can happen because CM uses polling, so we + // can receive key events while CM is waiting for timeout to expire. + // Pending text may dismiss the list, or it may cause a valid selection + // which keeps open hint list. We can compare pending text against + // list to determine whether list is dismissed or not, but to handle + // inserting selection in the page we'd need to either: + // 1. Synchronously force CodeMirror to poll (but there is not + // yet a public API for that). + // 2. Pass pending text back to where text gets inserted, which + // means it would need to be implemented for every HintProvider! + // You have to be typing so fast to hit this case, that's it's + // highly unlikely that inserting something from list was the intent, + // which makes this pretty rare, so case #2 is not worth implementing. + // If case #1 gets implemented, then we may want to use it here. + // So, assume that pending text dismisses hints and let event bubble. + return false; } // Trigger a click handler to commmit the selected item diff --git a/src/editor/CodeHintManager.js b/src/editor/CodeHintManager.js index 911122abcce..504f02a155f 100644 --- a/src/editor/CodeHintManager.js +++ b/src/editor/CodeHintManager.js @@ -123,7 +123,7 @@ * list window; or true, which indicates that the manager should end the * current hinting session but immediately attempt to begin a new hinting * session by querying registered providers. Otherwise, the provider should - * return a response object that contains the following properties: + * return a response object that contains three properties: * * 1. hints, a sorted array hints that the provider could later insert * into the editor; @@ -131,9 +131,6 @@ * hints in the hint list; and * 3. selectInitial, a boolean that indicates whether or not the the * first hint in the list should be selected by default. - * 4. handleWideResults, a boolean (or undefined) that indicates whether - * to allow result string to stretch width of display. - * 5. query, the string that list is filtered on * * If the array of * hints is empty, then the manager will render an empty list, but the @@ -176,9 +173,7 @@ * return {jQuery.Deferred|{ * hints: Array., * match: string, - * selectInitial: boolean, - * handleWideResults: boolean, - * query: string}} + * selectInitial: boolean}} * * Null if the provider wishes to end the hinting session. Otherwise, a * response object, possibly deferred, that provides 1. a sorted array @@ -542,6 +537,8 @@ define(function (require, exports, module) { } else if (event.type === "keypress") { // Last inserted character, used later by handleChange lastChar = String.fromCharCode(event.charCode); + + // Pending Text is used in hintList._keydownHook() if (hintList) { hintList.addPendingText(lastChar); } @@ -583,6 +580,7 @@ define(function (require, exports, module) { _beginSession(editor); } + // Pending Text is used in hintList._keydownHook() if (hintList && changeList.text.length && changeList.text[0].length) { hintList.removePendingText(changeList.text[0]); } diff --git a/src/extensions/default/CSSCodeHints/main.js b/src/extensions/default/CSSCodeHints/main.js index 0add017971d..6f6e8f68a40 100644 --- a/src/extensions/default/CSSCodeHints/main.js +++ b/src/extensions/default/CSSCodeHints/main.js @@ -184,9 +184,7 @@ define(function (require, exports, module) { * @return {jQuery.Deferred|{ * hints: Array., * match: string, - * selectInitial: boolean, - * handleWideResults: boolean, - * query: string}} + * selectInitial: boolean}} * Null if the provider wishes to end the hinting session. Otherwise, a * response object that provides: * 1. a sorted array hints that consists of strings @@ -194,9 +192,6 @@ define(function (require, exports, module) { * substrings when rendering the hint list * 3. a boolean that indicates whether the first result, if one exists, * should be selected by default in the hint list window. - * 4. a boolean (or undefined) that indicates whether to allow result - * string to stretch width of display. - * 5. a query string that list is filtered on */ CssPropHints.prototype.getHints = function (implicitChar) { this.cursor = this.editor.getCursorPos(); @@ -259,9 +254,7 @@ define(function (require, exports, module) { return { hints: result, match: valueNeedle, - selectInitial: selectInitial, - handleWideResults: false, - query: valueNeedle + selectInitial: selectInitial }; } else if (context === CSSUtils.PROP_NAME) { lastContext = CSSUtils.PROP_NAME; @@ -275,9 +268,7 @@ define(function (require, exports, module) { return { hints: result, match: needle, - selectInitial: selectInitial, - handleWideResults: false, - query: needle + selectInitial: selectInitial }; } return null; diff --git a/src/extensions/default/HTMLCodeHints/main.js b/src/extensions/default/HTMLCodeHints/main.js index d78b9e1b232..7424c98c94e 100644 --- a/src/extensions/default/HTMLCodeHints/main.js +++ b/src/extensions/default/HTMLCodeHints/main.js @@ -108,9 +108,7 @@ define(function (require, exports, module) { * @return {jQuery.Deferred|{ * hints: Array., * match: string, - * selectInitial: boolean, - * handleWideResults: boolean, - * query: string}} + * selectInitial: boolean}} * Null if the provider wishes to end the hinting session. Otherwise, a * response object that provides: * 1. a sorted array hints that consists of strings @@ -118,9 +116,6 @@ define(function (require, exports, module) { * substrings when rendering the hint list * 3. a boolean that indicates whether the first result, if one exists, * should be selected by default in the hint list window. - * 4. a boolean (or undefined) that indicates whether to allow result - * string to stretch width of display. - * 5. a query string that list is filtered on */ TagHints.prototype.getHints = function (implicitChar) { var query, @@ -140,9 +135,7 @@ define(function (require, exports, module) { return { hints: result, match: query, - selectInitial: true, - handleWideResults: false, - query: query + selectInitial: true }; } } @@ -371,9 +364,7 @@ define(function (require, exports, module) { * @return {jQuery.Deferred|{ * hints: Array., * match: string, - * selectInitial: boolean, - * handleWideResults: boolean, - * query: string}} + * selectInitial: boolean}} * Null if the provider wishes to end the hinting session. Otherwise, a * response object that provides: * 1. a sorted array hints that consists of strings @@ -381,9 +372,6 @@ define(function (require, exports, module) { * substrings when rendering the hint list * 3. a boolean that indicates whether the first result, if one exists, * should be selected by default in the hint list window. - * 4. a boolean (or undefined) that indicates whether to allow result - * string to stretch width of display. - * 5. a query string that list is filtered on */ AttrHints.prototype.getHints = function (implicitChar) { var cursor = this.editor.getCursorPos(), @@ -448,20 +436,12 @@ define(function (require, exports, module) { return { hints: result, match: query.queryStr, - selectInitial: true, - handleWideResults: false, - query: query.queryStr + selectInitial: true }; } else if (hints instanceof Object && hints.hasOwnProperty("done")) { // Deferred hints var deferred = $.Deferred(); hints.done(function (asyncHints) { - deferred.resolveWith(this, [{ - hints: asyncHints, - match: query.queryStr, - selectInitial: true, - handleWideResults: false, - query: query.queryStr - }]); + deferred.resolveWith(this, [{ hints: asyncHints, match: query.queryStr, selectInitial: true }]); }); return deferred; } else { diff --git a/src/extensions/default/HtmlEntityCodeHints/main.js b/src/extensions/default/HtmlEntityCodeHints/main.js index a40768e9bae..e575758f152 100644 --- a/src/extensions/default/HtmlEntityCodeHints/main.js +++ b/src/extensions/default/HtmlEntityCodeHints/main.js @@ -105,9 +105,7 @@ define(function (require, exports, module) { * @return {jQuery.Deferred|{ * hints: Array., * match: string, - * selectInitial: boolean, - * handleWideResults: boolean, - * query: string}} + * selectInitial: boolean}} * Null if the provider wishes to end the hinting session. Otherwise, a * response object that provides: * 1. a sorted array hints that consists of strings @@ -115,9 +113,6 @@ define(function (require, exports, module) { * substrings when rendering the hint list * 3. a boolean that indicates whether the first result, if one exists, * should be selected by default in the hint list window. - * 4. a boolean (or undefined) that indicates whether to allow result - * string to stretch width of display. - * 5. a query string that list is filtered on */ SpecialCharHints.prototype.getHints = function (implicitChar) { var query, @@ -139,9 +134,7 @@ define(function (require, exports, module) { return { hints: result, match: query, - selectInitial: true, - handleWideResults: false, - query: query + selectInitial: true }; } diff --git a/src/extensions/default/JavaScriptCodeHints/main.js b/src/extensions/default/JavaScriptCodeHints/main.js index dd153d4b8b3..1370553696a 100644 --- a/src/extensions/default/JavaScriptCodeHints/main.js +++ b/src/extensions/default/JavaScriptCodeHints/main.js @@ -88,9 +88,7 @@ define(function (require, exports, module) { * @return {jQuery.Deferred|{ * hints: Array., * match: string, - * selectInitial: boolean, - * handleWideResults: boolean, - * query: string}} + * selectInitial: boolean}} */ function formatHints(hints, query) { return hints.map(function (token) { @@ -169,9 +167,7 @@ define(function (require, exports, module) { return { hints: formattedHints, match: null, // the CodeHintManager should not format the results - selectInitial: true, - handleWideResults: hints.handleWideResults, - query: query + selectInitial: true }; } diff --git a/src/extensions/default/UrlCodeHints/main.js b/src/extensions/default/UrlCodeHints/main.js index cf6066d4786..bbb19969a0a 100644 --- a/src/extensions/default/UrlCodeHints/main.js +++ b/src/extensions/default/UrlCodeHints/main.js @@ -368,9 +368,7 @@ define(function (require, exports, module) { * @return {jQuery.Deferred|{ * hints: Array., * match: string, - * selectInitial: boolean, - * handleWideResults: boolean, - * query: string}} + * selectInitial: boolean}} * Null if the provider wishes to end the hinting session. Otherwise, a * response object that provides * 1. a sorted array hints that consists of strings @@ -378,9 +376,6 @@ define(function (require, exports, module) { * substrings when rendering the hint list * 3. a boolean that indicates whether the first result, if one exists, should be * selected by default in the hint list window. - * 4. handleWideResults, a boolean (or undefined) that indicates whether - * to allow result string to stretch width of display. - * 5. query, the string that list is filtered on */ UrlCodeHints.prototype.getHints = function (key) { var mode = this.editor.getModeForSelection(), @@ -483,9 +478,7 @@ define(function (require, exports, module) { deferred.resolveWith(this, [{ hints: asyncHints, match: query.queryStr, - selectInitial: true, - handleWideResults: false, - query: query.queryStr + selectInitial: true }]); }); From cfd025273fe7e6f4d2a67427bc6ff1e3dfba7716 Mon Sep 17 00:00:00 2001 From: Arzhan Kinzhalin Date: Fri, 27 Sep 2013 13:13:41 -0300 Subject: [PATCH 44/56] Fix #5362 (HTML menu z-index vs. bottom-panel). Raise toolbar +1 to be on top of the rest of the sibling panels. --- src/styles/brackets_variables.less | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/styles/brackets_variables.less b/src/styles/brackets_variables.less index d31c146c7e9..80ea7d1cc7c 100644 --- a/src/styles/brackets_variables.less +++ b/src/styles/brackets_variables.less @@ -47,7 +47,7 @@ @z-index-brackets-selection-triangle: (@z-index-brackets-ui + 1); @z-index-brackets-scroller-shadow: (@z-index-brackets-selection-triangle + 1); @z-index-brackets-inline-editor-shadow: @z-index-brackets-ui; -@z-index-brackets-toolbar: @z-index-brackets-ui; +@z-index-brackets-toolbar: (@z-index-brackets-ui + 1); @z-index-brackets-max: @z-index-brackets-toolbar; @z-index-brackets-modalbar: @z-index-brackets-toolbar - 1; From dd19801b92b0fb70bdf9c1e95cd137d58ca0d60b Mon Sep 17 00:00:00 2001 From: Arzhan Kinzhalin Date: Fri, 27 Sep 2013 13:16:31 -0300 Subject: [PATCH 45/56] Clean up Add braces to the expression as in the rest of the definitions. --- src/styles/brackets_variables.less | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/styles/brackets_variables.less b/src/styles/brackets_variables.less index 80ea7d1cc7c..a00aca90e02 100644 --- a/src/styles/brackets_variables.less +++ b/src/styles/brackets_variables.less @@ -49,7 +49,7 @@ @z-index-brackets-inline-editor-shadow: @z-index-brackets-ui; @z-index-brackets-toolbar: (@z-index-brackets-ui + 1); @z-index-brackets-max: @z-index-brackets-toolbar; -@z-index-brackets-modalbar: @z-index-brackets-toolbar - 1; +@z-index-brackets-modalbar: (@z-index-brackets-toolbar - 1); @z-index-brackets-sidebar-resizer: (@z-index-brackets-ui + 2); @z-index-brackets-resizer-div: (@z-index-brackets-sidebar-resizer + 1); From d10c13d3a2286e9d512c57e3cbbc6f5ddd64b418 Mon Sep 17 00:00:00 2001 From: Peter Flynn Date: Fri, 27 Sep 2013 14:09:06 -0700 Subject: [PATCH 46/56] Deprecate FileUtils.getFilenameExtension() (which includes leading "."), introduce new FileUtils.getFileExtension() (which excludes it). Fixes bug #5365. --- src/file/FileUtils.js | 36 ++++++++++++++++++++++++--------- src/language/JSUtils.js | 2 +- src/project/FileIndexManager.js | 2 +- 3 files changed, 29 insertions(+), 11 deletions(-) diff --git a/src/file/FileUtils.js b/src/file/FileUtils.js index 50eff71d0d9..4269f0fb6a7 100644 --- a/src/file/FileUtils.js +++ b/src/file/FileUtils.js @@ -239,7 +239,7 @@ define(function (require, exports, module) { } /** - * Get the base name of a file or a directory. + * Get the name of a file or a directory, removing any preceding path. * @param {string} fullPath full path to a file or directory * @return {string} Returns the base name of a file or the name of a * directory @@ -326,13 +326,15 @@ define(function (require, exports, module) { } /** - * Get the filename extension. + * Get the file extension (excluding ".") given a path OR a bare filename. + * Returns "" for names with no extension. If the name starts with ".", the + * full remaining text is considered the extension. * * @param {string} fullPath full path to a file or directory * @return {string} Returns the extension of a filename or empty string if * the argument is a directory or a filename with no extension */ - function getFilenameExtension(fullPath) { + function getFileExtension(fullPath) { var baseName = getBaseName(fullPath), idx = baseName.lastIndexOf("."); @@ -340,7 +342,21 @@ define(function (require, exports, module) { return ""; } - return baseName.substr(idx); + return baseName.substr(idx + 1); + } + + /** + * Similar to getFileExtension(), but includes the leading "." in the returned value. + * @deprecated Use getFileExtension() instead. This API will be removed soon. + */ + function getFilenameExtension(fullPath) { + console.error("Warning: FileUtils.getFilenameExtension() is deprecated. Use FileUtils.getFileExtension() (which omits the '.') instead."); + + var ext = getFileExtension(fullPath); + if (ext !== "") { + ext = "." + ext; + } + return ext; } /** @const - hard-coded for now, but may want to make these preferences */ @@ -357,7 +373,7 @@ define(function (require, exports, module) { return false; } - return (_staticHtmlFileExts.indexOf(getFilenameExtension(fileExt).toLowerCase()) !== -1); + return (_staticHtmlFileExts.indexOf(getFileExtension(fileExt).toLowerCase()) !== -1); } /** @@ -370,13 +386,14 @@ define(function (require, exports, module) { return false; } - return (_serverHtmlFileExts.indexOf(getFilenameExtension(fileExt).toLowerCase()) !== -1); + return (_serverHtmlFileExts.indexOf(getFileExtension(fileExt).toLowerCase()) !== -1); } /** * Get the parent directory of a file. If a directory is passed in the directory is returned. * @param {string} fullPath full path to a file or directory - * @return {string} Returns the path to the parent directory of a file or the path of a directory + * @return {string} Returns the path to the parent directory of a file or the path of a directory, + * including trailing "/" */ function getDirectoryPath(fullPath) { return fullPath.substr(0, fullPath.lastIndexOf("/") + 1); @@ -402,8 +419,8 @@ define(function (require, exports, module) { * @return {number} The result of the local compare function */ function compareFilenames(filename1, filename2, extFirst) { - var ext1 = getFilenameExtension(filename1), - ext2 = getFilenameExtension(filename2), + var ext1 = getFileExtension(filename1), + ext2 = getFileExtension(filename2), cmpExt = ext1.toLocaleLowerCase().localeCompare(ext2.toLocaleLowerCase(), undefined, {numeric: true}), cmpNames; @@ -438,6 +455,7 @@ define(function (require, exports, module) { exports.isServerHtmlFileExt = isServerHtmlFileExt; exports.getDirectoryPath = getDirectoryPath; exports.getBaseName = getBaseName; + exports.getFileExtension = getFileExtension; exports.getFilenameExtension = getFilenameExtension; exports.compareFilenames = compareFilenames; }); diff --git a/src/language/JSUtils.js b/src/language/JSUtils.js index 44875777959..1ccb0c9ba75 100644 --- a/src/language/JSUtils.js +++ b/src/language/JSUtils.js @@ -379,7 +379,7 @@ define(function (require, exports, module) { if (!keepAllFiles) { // Filter fileInfos for .js files jsFiles = fileInfos.filter(function (fileInfo) { - return (/^\.js/i).test(FileUtils.getFilenameExtension(fileInfo.fullPath)); + return FileUtils.getFileExtension(fileInfo.fullPath).toLowerCase() === "js"; }); } else { jsFiles = fileInfos; diff --git a/src/project/FileIndexManager.js b/src/project/FileIndexManager.js index 1c9fc08231e..d3457e2d370 100644 --- a/src/project/FileIndexManager.js +++ b/src/project/FileIndexManager.js @@ -439,7 +439,7 @@ define(function (require, exports, module) { _addIndex( "css", function (entry) { - return FileUtils.getFilenameExtension(entry.name) === ".css"; + return FileUtils.getFileExtension(entry.name) === "css"; } ); From 90a2b3f8a74c2c39a007132169c416dac41b8b62 Mon Sep 17 00:00:00 2001 From: Randy Edmunds Date: Fri, 27 Sep 2013 17:50:11 -0700 Subject: [PATCH 47/56] restore handleWideResults property --- src/editor/CodeHintManager.js | 7 ++++-- src/extensions/default/CSSCodeHints/main.js | 8 +++++-- src/extensions/default/HTMLCodeHints/main.js | 23 +++++++++++++++---- .../default/HtmlEntityCodeHints/main.js | 8 +++++-- .../default/JavaScriptCodeHints/main.js | 6 +++-- src/extensions/default/UrlCodeHints/main.js | 11 ++++++--- 6 files changed, 47 insertions(+), 16 deletions(-) diff --git a/src/editor/CodeHintManager.js b/src/editor/CodeHintManager.js index 504f02a155f..6619d9d8fcf 100644 --- a/src/editor/CodeHintManager.js +++ b/src/editor/CodeHintManager.js @@ -123,7 +123,7 @@ * list window; or true, which indicates that the manager should end the * current hinting session but immediately attempt to begin a new hinting * session by querying registered providers. Otherwise, the provider should - * return a response object that contains three properties: + * return a response object that contains the following properties: * * 1. hints, a sorted array hints that the provider could later insert * into the editor; @@ -131,6 +131,8 @@ * hints in the hint list; and * 3. selectInitial, a boolean that indicates whether or not the the * first hint in the list should be selected by default. + * 4. handleWideResults, a boolean (or undefined) that indicates whether + * to allow result string to stretch width of display. * * If the array of * hints is empty, then the manager will render an empty list, but the @@ -173,7 +175,8 @@ * return {jQuery.Deferred|{ * hints: Array., * match: string, - * selectInitial: boolean}} + * selectInitial: boolean, + * handleWideResults: boolean}} * * Null if the provider wishes to end the hinting session. Otherwise, a * response object, possibly deferred, that provides 1. a sorted array diff --git a/src/extensions/default/CSSCodeHints/main.js b/src/extensions/default/CSSCodeHints/main.js index 6f6e8f68a40..9aca2bbe1f4 100644 --- a/src/extensions/default/CSSCodeHints/main.js +++ b/src/extensions/default/CSSCodeHints/main.js @@ -184,7 +184,8 @@ define(function (require, exports, module) { * @return {jQuery.Deferred|{ * hints: Array., * match: string, - * selectInitial: boolean}} + * selectInitial: boolean, + * handleWideResults: boolean}} * Null if the provider wishes to end the hinting session. Otherwise, a * response object that provides: * 1. a sorted array hints that consists of strings @@ -192,6 +193,8 @@ define(function (require, exports, module) { * substrings when rendering the hint list * 3. a boolean that indicates whether the first result, if one exists, * should be selected by default in the hint list window. + * 4. handleWideResults, a boolean (or undefined) that indicates whether + * to allow result string to stretch width of display. */ CssPropHints.prototype.getHints = function (implicitChar) { this.cursor = this.editor.getCursorPos(); @@ -268,7 +271,8 @@ define(function (require, exports, module) { return { hints: result, match: needle, - selectInitial: selectInitial + selectInitial: selectInitial, + handleWideResults: false }; } return null; diff --git a/src/extensions/default/HTMLCodeHints/main.js b/src/extensions/default/HTMLCodeHints/main.js index 7424c98c94e..efdc4ea01ea 100644 --- a/src/extensions/default/HTMLCodeHints/main.js +++ b/src/extensions/default/HTMLCodeHints/main.js @@ -108,7 +108,8 @@ define(function (require, exports, module) { * @return {jQuery.Deferred|{ * hints: Array., * match: string, - * selectInitial: boolean}} + * selectInitial: boolean, + * handleWideResults: boolean}} * Null if the provider wishes to end the hinting session. Otherwise, a * response object that provides: * 1. a sorted array hints that consists of strings @@ -116,6 +117,8 @@ define(function (require, exports, module) { * substrings when rendering the hint list * 3. a boolean that indicates whether the first result, if one exists, * should be selected by default in the hint list window. + * 4. handleWideResults, a boolean (or undefined) that indicates whether + * to allow result string to stretch width of display. */ TagHints.prototype.getHints = function (implicitChar) { var query, @@ -135,7 +138,8 @@ define(function (require, exports, module) { return { hints: result, match: query, - selectInitial: true + selectInitial: true, + handleWideResults: false }; } } @@ -364,7 +368,8 @@ define(function (require, exports, module) { * @return {jQuery.Deferred|{ * hints: Array., * match: string, - * selectInitial: boolean}} + * selectInitial: boolean, + * handleWideResults: boolean}} * Null if the provider wishes to end the hinting session. Otherwise, a * response object that provides: * 1. a sorted array hints that consists of strings @@ -372,6 +377,8 @@ define(function (require, exports, module) { * substrings when rendering the hint list * 3. a boolean that indicates whether the first result, if one exists, * should be selected by default in the hint list window. + * 4. handleWideResults, a boolean (or undefined) that indicates whether + * to allow result string to stretch width of display. */ AttrHints.prototype.getHints = function (implicitChar) { var cursor = this.editor.getCursorPos(), @@ -436,12 +443,18 @@ define(function (require, exports, module) { return { hints: result, match: query.queryStr, - selectInitial: true + selectInitial: true, + handleWideResults: false }; } else if (hints instanceof Object && hints.hasOwnProperty("done")) { // Deferred hints var deferred = $.Deferred(); hints.done(function (asyncHints) { - deferred.resolveWith(this, [{ hints: asyncHints, match: query.queryStr, selectInitial: true }]); + deferred.resolveWith(this, [{ + hints: asyncHints, + match: query.queryStr, + selectInitial: true, + handleWideResults: false + }]); }); return deferred; } else { diff --git a/src/extensions/default/HtmlEntityCodeHints/main.js b/src/extensions/default/HtmlEntityCodeHints/main.js index e575758f152..c83ef1ab68e 100644 --- a/src/extensions/default/HtmlEntityCodeHints/main.js +++ b/src/extensions/default/HtmlEntityCodeHints/main.js @@ -105,7 +105,8 @@ define(function (require, exports, module) { * @return {jQuery.Deferred|{ * hints: Array., * match: string, - * selectInitial: boolean}} + * selectInitial: boolean, + * handleWideResults: boolean}} * Null if the provider wishes to end the hinting session. Otherwise, a * response object that provides: * 1. a sorted array hints that consists of strings @@ -113,6 +114,8 @@ define(function (require, exports, module) { * substrings when rendering the hint list * 3. a boolean that indicates whether the first result, if one exists, * should be selected by default in the hint list window. + * 4. handleWideResults, a boolean (or undefined) that indicates whether + * to allow result string to stretch width of display. */ SpecialCharHints.prototype.getHints = function (implicitChar) { var query, @@ -134,7 +137,8 @@ define(function (require, exports, module) { return { hints: result, match: query, - selectInitial: true + selectInitial: true, + handleWideResults: false }; } diff --git a/src/extensions/default/JavaScriptCodeHints/main.js b/src/extensions/default/JavaScriptCodeHints/main.js index c8fcfc1399d..e684f5447b1 100644 --- a/src/extensions/default/JavaScriptCodeHints/main.js +++ b/src/extensions/default/JavaScriptCodeHints/main.js @@ -88,7 +88,8 @@ define(function (require, exports, module) { * @return {jQuery.Deferred|{ * hints: Array., * match: string, - * selectInitial: boolean}} + * selectInitial: boolean, + * handleWideResults: boolean}} */ function formatHints(hints, query) { return hints.map(function (token) { @@ -167,7 +168,8 @@ define(function (require, exports, module) { return { hints: formattedHints, match: null, // the CodeHintManager should not format the results - selectInitial: true + selectInitial: true, + handleWideResults: hints.handleWideResults }; } diff --git a/src/extensions/default/UrlCodeHints/main.js b/src/extensions/default/UrlCodeHints/main.js index bbb19969a0a..9f00c7bab60 100644 --- a/src/extensions/default/UrlCodeHints/main.js +++ b/src/extensions/default/UrlCodeHints/main.js @@ -368,7 +368,8 @@ define(function (require, exports, module) { * @return {jQuery.Deferred|{ * hints: Array., * match: string, - * selectInitial: boolean}} + * selectInitial: boolean, + * handleWideResults: boolean}} * Null if the provider wishes to end the hinting session. Otherwise, a * response object that provides * 1. a sorted array hints that consists of strings @@ -376,6 +377,8 @@ define(function (require, exports, module) { * substrings when rendering the hint list * 3. a boolean that indicates whether the first result, if one exists, should be * selected by default in the hint list window. + * 4. handleWideResults, a boolean (or undefined) that indicates whether + * to allow result string to stretch width of display. */ UrlCodeHints.prototype.getHints = function (key) { var mode = this.editor.getModeForSelection(), @@ -468,7 +471,8 @@ define(function (require, exports, module) { return { hints: result, match: query.queryStr, - selectInitial: true + selectInitial: true, + handleWideResults: false }; } else if (hints instanceof Object && hints.hasOwnProperty("done")) { @@ -478,7 +482,8 @@ define(function (require, exports, module) { deferred.resolveWith(this, [{ hints: asyncHints, match: query.queryStr, - selectInitial: true + selectInitial: true, + handleWideResults: false }]); }); From 649b8b3d36a5c0d7984b43c03d1728714cd9e43c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tom=C3=A1s=20Malbr=C3=A1n?= Date: Sat, 28 Sep 2013 00:01:31 -0300 Subject: [PATCH 48/56] Find in Files title update --- src/nls/cs/strings.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/nls/cs/strings.js b/src/nls/cs/strings.js index b7469b8cd4a..d69e1254b50 100644 --- a/src/nls/cs/strings.js +++ b/src/nls/cs/strings.js @@ -135,7 +135,7 @@ define({ "FIND_IN_FILES_TITLE_PART1" : "\"", "FIND_IN_FILES_TITLE_PART2" : "\" nalezen", - "FIND_IN_FILES_TITLE_PART3" : "— {0} {1} v {2} {3}", + "FIND_IN_FILES_TITLE_PART3" : "— {0} {1} {2} v {3} {4}", "FIND_IN_FILES_SCOPED" : "v {0}", "FIND_IN_FILES_NO_SCOPE" : "v projektu", "FIND_IN_FILES_FILE" : "souboru", From e4a3f0102351d53f44d6f74581277da9fd6a35c6 Mon Sep 17 00:00:00 2001 From: Wouter92 Date: Sat, 28 Sep 2013 21:16:39 +0200 Subject: [PATCH 49/56] Added quick-edit.png for Finnish translation --- samples/fi/Aloitus/screenshots/quick-edit.png | Bin 0 -> 130646 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 samples/fi/Aloitus/screenshots/quick-edit.png diff --git a/samples/fi/Aloitus/screenshots/quick-edit.png b/samples/fi/Aloitus/screenshots/quick-edit.png new file mode 100644 index 0000000000000000000000000000000000000000..ca5011679bbb119cc332335bb9f70a6b8a6a6391 GIT binary patch literal 130646 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

&$?T%z&(XOyVyC3*^zXrC) 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 literal 0 HcmV?d00001 From c13da1b295e95edbb69902941a1809bca1658456 Mon Sep 17 00:00:00 2001 From: Bernhard Sirlinger Date: Sun, 29 Sep 2013 18:50:52 +0200 Subject: [PATCH 50/56] Fix minor nit --- test/SpecRunner.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/SpecRunner.js b/test/SpecRunner.js index e0586aa081e..39820234c6d 100644 --- a/test/SpecRunner.js +++ b/test/SpecRunner.js @@ -54,7 +54,7 @@ define(function (require, exports, module) { BootstrapReporterView = require("test/BootstrapReporterView").BootstrapReporterView, ColorUtils = require("utils/ColorUtils"), NativeApp = require("utils/NativeApp"), - CodeHintManager = require("editor/CodeHintManager"); + CodeHintManager = require("editor/CodeHintManager"); // Load modules that self-register and just need to get included in the main project require("document/ChangedDocumentTracker"); From f5905d68335f736d5833e515b59f838245df6972 Mon Sep 17 00:00:00 2001 From: Bernhard Sirlinger Date: Sun, 29 Sep 2013 19:23:04 +0200 Subject: [PATCH 51/56] Remove methods from eports --- src/editor/CodeHintManager.js | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/editor/CodeHintManager.js b/src/editor/CodeHintManager.js index 560c6dc1782..d11257ef2ec 100644 --- a/src/editor/CodeHintManager.js +++ b/src/editor/CodeHintManager.js @@ -651,8 +651,6 @@ define(function (require, exports, module) { // Define public API exports.isOpen = isOpen; - exports.handleKeyEvent = handleKeyEvent; - exports.handleChange = handleChange; exports.registerHintProvider = registerHintProvider; exports.hasValidExclusion = hasValidExclusion; exports.setInsertHintOnTab = setInsertHintOnTab; From d5d0b62842966714d3cb6f0fe06552a22a0f9ee4 Mon Sep 17 00:00:00 2001 From: Kevin Dangoor Date: Mon, 30 Sep 2013 11:22:16 -0400 Subject: [PATCH 52/56] Change decompress-zip to the release --- .../node/node_modules/.bin/decompress-zip | 1 + .../decompress-zip/bin/decompress-zip | 82 +++ .../decompress-zip/bin/decompress-zip.js | 15 - .../decompress-zip/node_modules/.bin/nopt | 1 + .../node_modules/nopt/.npmignore | 1 + .../decompress-zip/node_modules/nopt/LICENSE | 23 + .../node_modules/nopt/README.md | 210 ++++++ .../node_modules/nopt/bin/nopt.js | 51 ++ .../node_modules/nopt/examples/my-program.js | 30 + .../node_modules/nopt/lib/nopt.js | 612 ++++++++++++++++++ .../nopt/node_modules/abbrev/LICENSE | 23 + .../nopt/node_modules/abbrev/README.md | 23 + .../nopt/node_modules/abbrev/lib/abbrev.js | 111 ++++ .../nopt/node_modules/abbrev/package.json | 28 + .../node_modules/nopt/package.json | 35 + .../node_modules/decompress-zip/package.json | 19 +- .../node_modules/decompress-zip/test/test.js | 2 +- src/extensibility/node/package.json | 2 +- 18 files changed, 1244 insertions(+), 25 deletions(-) create mode 120000 src/extensibility/node/node_modules/.bin/decompress-zip create mode 100755 src/extensibility/node/node_modules/decompress-zip/bin/decompress-zip delete mode 100755 src/extensibility/node/node_modules/decompress-zip/bin/decompress-zip.js create mode 120000 src/extensibility/node/node_modules/decompress-zip/node_modules/.bin/nopt create mode 100644 src/extensibility/node/node_modules/decompress-zip/node_modules/nopt/.npmignore create mode 100644 src/extensibility/node/node_modules/decompress-zip/node_modules/nopt/LICENSE create mode 100644 src/extensibility/node/node_modules/decompress-zip/node_modules/nopt/README.md create mode 100755 src/extensibility/node/node_modules/decompress-zip/node_modules/nopt/bin/nopt.js create mode 100755 src/extensibility/node/node_modules/decompress-zip/node_modules/nopt/examples/my-program.js create mode 100644 src/extensibility/node/node_modules/decompress-zip/node_modules/nopt/lib/nopt.js create mode 100644 src/extensibility/node/node_modules/decompress-zip/node_modules/nopt/node_modules/abbrev/LICENSE create mode 100644 src/extensibility/node/node_modules/decompress-zip/node_modules/nopt/node_modules/abbrev/README.md create mode 100644 src/extensibility/node/node_modules/decompress-zip/node_modules/nopt/node_modules/abbrev/lib/abbrev.js create mode 100644 src/extensibility/node/node_modules/decompress-zip/node_modules/nopt/node_modules/abbrev/package.json create mode 100644 src/extensibility/node/node_modules/decompress-zip/node_modules/nopt/package.json diff --git a/src/extensibility/node/node_modules/.bin/decompress-zip b/src/extensibility/node/node_modules/.bin/decompress-zip new file mode 120000 index 00000000000..83255291682 --- /dev/null +++ b/src/extensibility/node/node_modules/.bin/decompress-zip @@ -0,0 +1 @@ +../decompress-zip/bin/decompress-zip \ No newline at end of file diff --git a/src/extensibility/node/node_modules/decompress-zip/bin/decompress-zip b/src/extensibility/node/node_modules/decompress-zip/bin/decompress-zip new file mode 100755 index 00000000000..b5e1df34cb6 --- /dev/null +++ b/src/extensibility/node/node_modules/decompress-zip/bin/decompress-zip @@ -0,0 +1,82 @@ +#!/usr/bin/env node +'use strict'; + +var nopt = require('nopt'); +var path = require('path'); +var version = require('../package.json').version; + +var knownOptions = { + 'list': Boolean, + 'extract': Boolean, + 'path': path +}; + +var shortcuts = { + 'x': ['--extract'], + 'l': ['--list'], + 'p': ['--path'], + 'v': ['--version'] +}; + +var parsedOptions = nopt(knownOptions, shortcuts); + +var pad = function (string, length) { + string = String(string); + + if (length <= string.length) { + return string; + } + + return string + (new Array(length - string.length).join(' ')); +}; + +var octal = function (number, digits) { + var result = ''; + for (var i = 0; i < digits; i++) { + result = (number & 0x07) + result; + number >>= 3; + } + return result; +}; + +var DecompressZip = require('../lib/decompress-zip'); +var zip = new DecompressZip(parsedOptions.argv.remain[0]); + +zip.on('file', function (file) { + console.log([octal(file.mode, 4), pad(file.type, 12), pad(file.compressedSize, 10), pad(file.uncompressedSize, 10), file.path].join(' ')); +}); + +zip.on('list', function (fileList) { + // console.log(fileList); +}); + +zip.on('extract', function (result) { + console.log(result); +}); + +zip.on('error', function (error) { + console.error(error.message, error.stack); +}); + +if (parsedOptions.version) { + console.log('version ' + version); +} else if (parsedOptions.list) { + console.log('Mode Type Zip size Full size Path'); + console.log('---- ---- -------- --------- ----'); + zip.list(); +} else if (parsedOptions.extract) { + var options = {}; + + if (parsedOptions.path) { + options.path = parsedOptions.path; + } + + zip.extract(options); +} else { + console.log('Usage: decompress-zip '); + console.log(' -x, --extract extract the given file'); + console.log(' -l, --list list the contents of the given file'); + console.log(' -v, --version extract the given file'); + console.log(' -p, --path extract the file into '); + console.log(' -h, --help show this message'); +} diff --git a/src/extensibility/node/node_modules/decompress-zip/bin/decompress-zip.js b/src/extensibility/node/node_modules/decompress-zip/bin/decompress-zip.js deleted file mode 100755 index ee800c5aa5f..00000000000 --- a/src/extensibility/node/node_modules/decompress-zip/bin/decompress-zip.js +++ /dev/null @@ -1,15 +0,0 @@ -#!/usr/bin/env node -'use strict'; - -var DecompressZip = require('../lib/decompress-zip'); -var zip = new DecompressZip(process.argv[2]); - -zip.on('file', function (file) { - console.log(file.name); -}); - -zip.on('error', function (error) { - console.error(error.message, error.stack); -}); - -zip.extract(); diff --git a/src/extensibility/node/node_modules/decompress-zip/node_modules/.bin/nopt b/src/extensibility/node/node_modules/decompress-zip/node_modules/.bin/nopt new file mode 120000 index 00000000000..6b6566ea7fe --- /dev/null +++ b/src/extensibility/node/node_modules/decompress-zip/node_modules/.bin/nopt @@ -0,0 +1 @@ +../nopt/bin/nopt.js \ No newline at end of file diff --git a/src/extensibility/node/node_modules/decompress-zip/node_modules/nopt/.npmignore b/src/extensibility/node/node_modules/decompress-zip/node_modules/nopt/.npmignore new file mode 100644 index 00000000000..3c3629e647f --- /dev/null +++ b/src/extensibility/node/node_modules/decompress-zip/node_modules/nopt/.npmignore @@ -0,0 +1 @@ +node_modules diff --git a/src/extensibility/node/node_modules/decompress-zip/node_modules/nopt/LICENSE b/src/extensibility/node/node_modules/decompress-zip/node_modules/nopt/LICENSE new file mode 100644 index 00000000000..05a4010949c --- /dev/null +++ b/src/extensibility/node/node_modules/decompress-zip/node_modules/nopt/LICENSE @@ -0,0 +1,23 @@ +Copyright 2009, 2010, 2011 Isaac Z. Schlueter. +All rights reserved. + +Permission is hereby granted, free of charge, to any person +obtaining a copy of this software and associated documentation +files (the "Software"), to deal in the Software without +restriction, including without limitation the rights to use, +copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the +Software is furnished to do so, subject to the following +conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES +OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT +HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +OTHER DEALINGS IN THE SOFTWARE. diff --git a/src/extensibility/node/node_modules/decompress-zip/node_modules/nopt/README.md b/src/extensibility/node/node_modules/decompress-zip/node_modules/nopt/README.md new file mode 100644 index 00000000000..f290da8f4f7 --- /dev/null +++ b/src/extensibility/node/node_modules/decompress-zip/node_modules/nopt/README.md @@ -0,0 +1,210 @@ +If you want to write an option parser, and have it be good, there are +two ways to do it. The Right Way, and the Wrong Way. + +The Wrong Way is to sit down and write an option parser. We've all done +that. + +The Right Way is to write some complex configurable program with so many +options that you go half-insane just trying to manage them all, and put +it off with duct-tape solutions until you see exactly to the core of the +problem, and finally snap and write an awesome option parser. + +If you want to write an option parser, don't write an option parser. +Write a package manager, or a source control system, or a service +restarter, or an operating system. You probably won't end up with a +good one of those, but if you don't give up, and you are relentless and +diligent enough in your procrastination, you may just end up with a very +nice option parser. + +## USAGE + + // my-program.js + var nopt = require("nopt") + , Stream = require("stream").Stream + , path = require("path") + , knownOpts = { "foo" : [String, null] + , "bar" : [Stream, Number] + , "baz" : path + , "bloo" : [ "big", "medium", "small" ] + , "flag" : Boolean + , "pick" : Boolean + , "many" : [String, Array] + } + , shortHands = { "foofoo" : ["--foo", "Mr. Foo"] + , "b7" : ["--bar", "7"] + , "m" : ["--bloo", "medium"] + , "p" : ["--pick"] + , "f" : ["--flag"] + } + // everything is optional. + // knownOpts and shorthands default to {} + // arg list defaults to process.argv + // slice defaults to 2 + , parsed = nopt(knownOpts, shortHands, process.argv, 2) + console.log(parsed) + +This would give you support for any of the following: + +```bash +$ node my-program.js --foo "blerp" --no-flag +{ "foo" : "blerp", "flag" : false } + +$ node my-program.js ---bar 7 --foo "Mr. Hand" --flag +{ bar: 7, foo: "Mr. Hand", flag: true } + +$ node my-program.js --foo "blerp" -f -----p +{ foo: "blerp", flag: true, pick: true } + +$ node my-program.js -fp --foofoo +{ foo: "Mr. Foo", flag: true, pick: true } + +$ node my-program.js --foofoo -- -fp # -- stops the flag parsing. +{ foo: "Mr. Foo", argv: { remain: ["-fp"] } } + +$ node my-program.js --blatzk 1000 -fp # unknown opts are ok. +{ blatzk: 1000, flag: true, pick: true } + +$ node my-program.js --blatzk true -fp # but they need a value +{ blatzk: true, flag: true, pick: true } + +$ node my-program.js --no-blatzk -fp # unless they start with "no-" +{ blatzk: false, flag: true, pick: true } + +$ node my-program.js --baz b/a/z # known paths are resolved. +{ baz: "/Users/isaacs/b/a/z" } + +# if Array is one of the types, then it can take many +# values, and will always be an array. The other types provided +# specify what types are allowed in the list. + +$ node my-program.js --many 1 --many null --many foo +{ many: ["1", "null", "foo"] } + +$ node my-program.js --many foo +{ many: ["foo"] } +``` + +Read the tests at the bottom of `lib/nopt.js` for more examples of +what this puppy can do. + +## Types + +The following types are supported, and defined on `nopt.typeDefs` + +* String: A normal string. No parsing is done. +* path: A file system path. Gets resolved against cwd if not absolute. +* url: A url. If it doesn't parse, it isn't accepted. +* Number: Must be numeric. +* Date: Must parse as a date. If it does, and `Date` is one of the options, + then it will return a Date object, not a string. +* Boolean: Must be either `true` or `false`. If an option is a boolean, + then it does not need a value, and its presence will imply `true` as + the value. To negate boolean flags, do `--no-whatever` or `--whatever + false` +* NaN: Means that the option is strictly not allowed. Any value will + fail. +* Stream: An object matching the "Stream" class in node. Valuable + for use when validating programmatically. (npm uses this to let you + supply any WriteStream on the `outfd` and `logfd` config options.) +* Array: If `Array` is specified as one of the types, then the value + will be parsed as a list of options. This means that multiple values + can be specified, and that the value will always be an array. + +If a type is an array of values not on this list, then those are +considered valid values. For instance, in the example above, the +`--bloo` option can only be one of `"big"`, `"medium"`, or `"small"`, +and any other value will be rejected. + +When parsing unknown fields, `"true"`, `"false"`, and `"null"` will be +interpreted as their JavaScript equivalents, and numeric values will be +interpreted as a number. + +You can also mix types and values, or multiple types, in a list. For +instance `{ blah: [Number, null] }` would allow a value to be set to +either a Number or null. When types are ordered, this implies a +preference, and the first type that can be used to properly interpret +the value will be used. + +To define a new type, add it to `nopt.typeDefs`. Each item in that +hash is an object with a `type` member and a `validate` method. The +`type` member is an object that matches what goes in the type list. The +`validate` method is a function that gets called with `validate(data, +key, val)`. Validate methods should assign `data[key]` to the valid +value of `val` if it can be handled properly, or return boolean +`false` if it cannot. + +You can also call `nopt.clean(data, types, typeDefs)` to clean up a +config object and remove its invalid properties. + +## Error Handling + +By default, nopt outputs a warning to standard error when invalid +options are found. You can change this behavior by assigning a method +to `nopt.invalidHandler`. This method will be called with +the offending `nopt.invalidHandler(key, val, types)`. + +If no `nopt.invalidHandler` is assigned, then it will console.error +its whining. If it is assigned to boolean `false` then the warning is +suppressed. + +## Abbreviations + +Yes, they are supported. If you define options like this: + +```javascript +{ "foolhardyelephants" : Boolean +, "pileofmonkeys" : Boolean } +``` + +Then this will work: + +```bash +node program.js --foolhar --pil +node program.js --no-f --pileofmon +# etc. +``` + +## Shorthands + +Shorthands are a hash of shorter option names to a snippet of args that +they expand to. + +If multiple one-character shorthands are all combined, and the +combination does not unambiguously match any other option or shorthand, +then they will be broken up into their constituent parts. For example: + +```json +{ "s" : ["--loglevel", "silent"] +, "g" : "--global" +, "f" : "--force" +, "p" : "--parseable" +, "l" : "--long" +} +``` + +```bash +npm ls -sgflp +# just like doing this: +npm ls --loglevel silent --global --force --long --parseable +``` + +## The Rest of the args + +The config object returned by nopt is given a special member called +`argv`, which is an object with the following fields: + +* `remain`: The remaining args after all the parsing has occurred. +* `original`: The args as they originally appeared. +* `cooked`: The args after flags and shorthands are expanded. + +## Slicing + +Node programs are called with more or less the exact argv as it appears +in C land, after the v8 and node-specific options have been plucked off. +As such, `argv[0]` is always `node` and `argv[1]` is always the +JavaScript program being run. + +That's usually not very useful to you. So they're sliced off by +default. If you want them, then you can pass in `0` as the last +argument, or any other number that you'd like to slice off the start of +the list. diff --git a/src/extensibility/node/node_modules/decompress-zip/node_modules/nopt/bin/nopt.js b/src/extensibility/node/node_modules/decompress-zip/node_modules/nopt/bin/nopt.js new file mode 100755 index 00000000000..30e9fdbab5d --- /dev/null +++ b/src/extensibility/node/node_modules/decompress-zip/node_modules/nopt/bin/nopt.js @@ -0,0 +1,51 @@ +#!/usr/bin/env node +var nopt = require("../lib/nopt") + , types = { num: Number + , bool: Boolean + , help: Boolean + , list: Array + , "num-list": [Number, Array] + , "str-list": [String, Array] + , "bool-list": [Boolean, Array] + , str: String + , clear: Boolean + , config: Boolean + , length: Number + } + , shorthands = { s: [ "--str", "astring" ] + , b: [ "--bool" ] + , nb: [ "--no-bool" ] + , tft: [ "--bool-list", "--no-bool-list", "--bool-list", "true" ] + , "?": ["--help"] + , h: ["--help"] + , H: ["--help"] + , n: [ "--num", "125" ] + , c: ["--config"] + , l: ["--length"] + } + , parsed = nopt( types + , shorthands + , process.argv + , 2 ) + +console.log("parsed", parsed) + +if (parsed.help) { + console.log("") + console.log("nopt cli tester") + console.log("") + console.log("types") + console.log(Object.keys(types).map(function M (t) { + var type = types[t] + if (Array.isArray(type)) { + return [t, type.map(function (type) { return type.name })] + } + return [t, type && type.name] + }).reduce(function (s, i) { + s[i[0]] = i[1] + return s + }, {})) + console.log("") + console.log("shorthands") + console.log(shorthands) +} diff --git a/src/extensibility/node/node_modules/decompress-zip/node_modules/nopt/examples/my-program.js b/src/extensibility/node/node_modules/decompress-zip/node_modules/nopt/examples/my-program.js new file mode 100755 index 00000000000..142447e18e7 --- /dev/null +++ b/src/extensibility/node/node_modules/decompress-zip/node_modules/nopt/examples/my-program.js @@ -0,0 +1,30 @@ +#!/usr/bin/env node + +//process.env.DEBUG_NOPT = 1 + +// my-program.js +var nopt = require("../lib/nopt") + , Stream = require("stream").Stream + , path = require("path") + , knownOpts = { "foo" : [String, null] + , "bar" : [Stream, Number] + , "baz" : path + , "bloo" : [ "big", "medium", "small" ] + , "flag" : Boolean + , "pick" : Boolean + } + , shortHands = { "foofoo" : ["--foo", "Mr. Foo"] + , "b7" : ["--bar", "7"] + , "m" : ["--bloo", "medium"] + , "p" : ["--pick"] + , "f" : ["--flag", "true"] + , "g" : ["--flag"] + , "s" : "--flag" + } + // everything is optional. + // knownOpts and shorthands default to {} + // arg list defaults to process.argv + // slice defaults to 2 + , parsed = nopt(knownOpts, shortHands, process.argv, 2) + +console.log("parsed =\n"+ require("util").inspect(parsed)) diff --git a/src/extensibility/node/node_modules/decompress-zip/node_modules/nopt/lib/nopt.js b/src/extensibility/node/node_modules/decompress-zip/node_modules/nopt/lib/nopt.js new file mode 100644 index 00000000000..20f3b5b1ddd --- /dev/null +++ b/src/extensibility/node/node_modules/decompress-zip/node_modules/nopt/lib/nopt.js @@ -0,0 +1,612 @@ +// info about each config option. + +var debug = process.env.DEBUG_NOPT || process.env.NOPT_DEBUG + ? function () { console.error.apply(console, arguments) } + : function () {} + +var url = require("url") + , path = require("path") + , Stream = require("stream").Stream + , abbrev = require("abbrev") + +module.exports = exports = nopt +exports.clean = clean + +exports.typeDefs = + { String : { type: String, validate: validateString } + , Boolean : { type: Boolean, validate: validateBoolean } + , url : { type: url, validate: validateUrl } + , Number : { type: Number, validate: validateNumber } + , path : { type: path, validate: validatePath } + , Stream : { type: Stream, validate: validateStream } + , Date : { type: Date, validate: validateDate } + } + +function nopt (types, shorthands, args, slice) { + args = args || process.argv + types = types || {} + shorthands = shorthands || {} + if (typeof slice !== "number") slice = 2 + + debug(types, shorthands, args, slice) + + args = args.slice(slice) + var data = {} + , key + , remain = [] + , cooked = args + , original = args.slice(0) + + parse(args, data, remain, types, shorthands) + // now data is full + clean(data, types, exports.typeDefs) + data.argv = {remain:remain,cooked:cooked,original:original} + Object.defineProperty(data.argv, 'toString', { value: function () { + return this.original.map(JSON.stringify).join(" ") + }, enumerable: false }) + return data +} + +function clean (data, types, typeDefs) { + typeDefs = typeDefs || exports.typeDefs + var remove = {} + , typeDefault = [false, true, null, String, Number, Array] + + Object.keys(data).forEach(function (k) { + if (k === "argv") return + var val = data[k] + , isArray = Array.isArray(val) + , type = types[k] + if (!isArray) val = [val] + if (!type) type = typeDefault + if (type === Array) type = typeDefault.concat(Array) + if (!Array.isArray(type)) type = [type] + + debug("val=%j", val) + debug("types=", type) + val = val.map(function (val) { + // if it's an unknown value, then parse false/true/null/numbers/dates + if (typeof val === "string") { + debug("string %j", val) + val = val.trim() + if ((val === "null" && ~type.indexOf(null)) + || (val === "true" && + (~type.indexOf(true) || ~type.indexOf(Boolean))) + || (val === "false" && + (~type.indexOf(false) || ~type.indexOf(Boolean)))) { + val = JSON.parse(val) + debug("jsonable %j", val) + } else if (~type.indexOf(Number) && !isNaN(val)) { + debug("convert to number", val) + val = +val + } else if (~type.indexOf(Date) && !isNaN(Date.parse(val))) { + debug("convert to date", val) + val = new Date(val) + } + } + + if (!types.hasOwnProperty(k)) { + return val + } + + // allow `--no-blah` to set 'blah' to null if null is allowed + if (val === false && ~type.indexOf(null) && + !(~type.indexOf(false) || ~type.indexOf(Boolean))) { + val = null + } + + var d = {} + d[k] = val + debug("prevalidated val", d, val, types[k]) + if (!validate(d, k, val, types[k], typeDefs)) { + if (exports.invalidHandler) { + exports.invalidHandler(k, val, types[k], data) + } else if (exports.invalidHandler !== false) { + debug("invalid: "+k+"="+val, types[k]) + } + return remove + } + debug("validated val", d, val, types[k]) + return d[k] + }).filter(function (val) { return val !== remove }) + + if (!val.length) delete data[k] + else if (isArray) { + debug(isArray, data[k], val) + data[k] = val + } else data[k] = val[0] + + debug("k=%s val=%j", k, val, data[k]) + }) +} + +function validateString (data, k, val) { + data[k] = String(val) +} + +function validatePath (data, k, val) { + data[k] = path.resolve(String(val)) + return true +} + +function validateNumber (data, k, val) { + debug("validate Number %j %j %j", k, val, isNaN(val)) + if (isNaN(val)) return false + data[k] = +val +} + +function validateDate (data, k, val) { + debug("validate Date %j %j %j", k, val, Date.parse(val)) + var s = Date.parse(val) + if (isNaN(s)) return false + data[k] = new Date(val) +} + +function validateBoolean (data, k, val) { + if (val instanceof Boolean) val = val.valueOf() + else if (typeof val === "string") { + if (!isNaN(val)) val = !!(+val) + else if (val === "null" || val === "false") val = false + else val = true + } else val = !!val + data[k] = val +} + +function validateUrl (data, k, val) { + val = url.parse(String(val)) + if (!val.host) return false + data[k] = val.href +} + +function validateStream (data, k, val) { + if (!(val instanceof Stream)) return false + data[k] = val +} + +function validate (data, k, val, type, typeDefs) { + // arrays are lists of types. + if (Array.isArray(type)) { + for (var i = 0, l = type.length; i < l; i ++) { + if (type[i] === Array) continue + if (validate(data, k, val, type[i], typeDefs)) return true + } + delete data[k] + return false + } + + // an array of anything? + if (type === Array) return true + + // NaN is poisonous. Means that something is not allowed. + if (type !== type) { + debug("Poison NaN", k, val, type) + delete data[k] + return false + } + + // explicit list of values + if (val === type) { + debug("Explicitly allowed %j", val) + // if (isArray) (data[k] = data[k] || []).push(val) + // else data[k] = val + data[k] = val + return true + } + + // now go through the list of typeDefs, validate against each one. + var ok = false + , types = Object.keys(typeDefs) + for (var i = 0, l = types.length; i < l; i ++) { + debug("test type %j %j %j", k, val, types[i]) + var t = typeDefs[types[i]] + if (t && type === t.type) { + var d = {} + ok = false !== t.validate(d, k, val) + val = d[k] + if (ok) { + // if (isArray) (data[k] = data[k] || []).push(val) + // else data[k] = val + data[k] = val + break + } + } + } + debug("OK? %j (%j %j %j)", ok, k, val, types[i]) + + if (!ok) delete data[k] + return ok +} + +function parse (args, data, remain, types, shorthands) { + debug("parse", args, data, remain) + + var key = null + , abbrevs = abbrev(Object.keys(types)) + , shortAbbr = abbrev(Object.keys(shorthands)) + + for (var i = 0; i < args.length; i ++) { + var arg = args[i] + debug("arg", arg) + + if (arg.match(/^-{2,}$/)) { + // done with keys. + // the rest are args. + remain.push.apply(remain, args.slice(i + 1)) + args[i] = "--" + break + } + var hadEq = false + if (arg.charAt(0) === "-" && arg.length > 1) { + if (arg.indexOf("=") !== -1) { + hadEq = true + var v = arg.split("=") + arg = v.shift() + v = v.join("=") + args.splice.apply(args, [i, 1].concat([arg, v])) + } + + // see if it's a shorthand + // if so, splice and back up to re-parse it. + var shRes = resolveShort(arg, shorthands, shortAbbr, abbrevs) + debug("arg=%j shRes=%j", arg, shRes) + if (shRes) { + debug(arg, shRes) + args.splice.apply(args, [i, 1].concat(shRes)) + if (arg !== shRes[0]) { + i -- + continue + } + } + arg = arg.replace(/^-+/, "") + var no = null + while (arg.toLowerCase().indexOf("no-") === 0) { + no = !no + arg = arg.substr(3) + } + + if (abbrevs[arg]) arg = abbrevs[arg] + + var isArray = types[arg] === Array || + Array.isArray(types[arg]) && types[arg].indexOf(Array) !== -1 + + // allow unknown things to be arrays if specified multiple times. + if (!types.hasOwnProperty(arg) && data.hasOwnProperty(arg)) { + if (!Array.isArray(data[arg])) + data[arg] = [data[arg]] + isArray = true + } + + var val + , la = args[i + 1] + + var isBool = typeof no === 'boolean' || + types[arg] === Boolean || + Array.isArray(types[arg]) && types[arg].indexOf(Boolean) !== -1 || + (typeof types[arg] === 'undefined' && !hadEq) || + (la === "false" && + (types[arg] === null || + Array.isArray(types[arg]) && ~types[arg].indexOf(null))) + + if (isBool) { + // just set and move along + val = !no + // however, also support --bool true or --bool false + if (la === "true" || la === "false") { + val = JSON.parse(la) + la = null + if (no) val = !val + i ++ + } + + // also support "foo":[Boolean, "bar"] and "--foo bar" + if (Array.isArray(types[arg]) && la) { + if (~types[arg].indexOf(la)) { + // an explicit type + val = la + i ++ + } else if ( la === "null" && ~types[arg].indexOf(null) ) { + // null allowed + val = null + i ++ + } else if ( !la.match(/^-{2,}[^-]/) && + !isNaN(la) && + ~types[arg].indexOf(Number) ) { + // number + val = +la + i ++ + } else if ( !la.match(/^-[^-]/) && ~types[arg].indexOf(String) ) { + // string + val = la + i ++ + } + } + + if (isArray) (data[arg] = data[arg] || []).push(val) + else data[arg] = val + + continue + } + + if (la && la.match(/^-{2,}$/)) { + la = undefined + i -- + } + + val = la === undefined ? true : la + if (isArray) (data[arg] = data[arg] || []).push(val) + else data[arg] = val + + i ++ + continue + } + remain.push(arg) + } +} + +function resolveShort (arg, shorthands, shortAbbr, abbrevs) { + // handle single-char shorthands glommed together, like + // npm ls -glp, but only if there is one dash, and only if + // all of the chars are single-char shorthands, and it's + // not a match to some other abbrev. + arg = arg.replace(/^-+/, '') + + // if it's an exact known option, then don't go any further + if (abbrevs[arg] === arg) + return null + + // if it's an exact known shortopt, same deal + if (shorthands[arg]) { + // make it an array, if it's a list of words + if (shorthands[arg] && !Array.isArray(shorthands[arg])) + shorthands[arg] = shorthands[arg].split(/\s+/) + + return shorthands[arg] + } + + // first check to see if this arg is a set of single-char shorthands + var singles = shorthands.___singles + if (!singles) { + singles = Object.keys(shorthands).filter(function (s) { + return s.length === 1 + }).reduce(function (l,r) { + l[r] = true + return l + }, {}) + shorthands.___singles = singles + debug('shorthand singles', singles) + } + + var chrs = arg.split("").filter(function (c) { + return singles[c] + }) + + if (chrs.join("") === arg) return chrs.map(function (c) { + return shorthands[c] + }).reduce(function (l, r) { + return l.concat(r) + }, []) + + + // if it's an arg abbrev, and not a literal shorthand, then prefer the arg + if (abbrevs[arg] && !shorthands[arg]) + return null + + // if it's an abbr for a shorthand, then use that + if (shortAbbr[arg]) + arg = shortAbbr[arg] + + // make it an array, if it's a list of words + if (shorthands[arg] && !Array.isArray(shorthands[arg])) + shorthands[arg] = shorthands[arg].split(/\s+/) + + return shorthands[arg] +} + +if (module === require.main) { +var assert = require("assert") + , util = require("util") + + , shorthands = + { s : ["--loglevel", "silent"] + , d : ["--loglevel", "info"] + , dd : ["--loglevel", "verbose"] + , ddd : ["--loglevel", "silly"] + , noreg : ["--no-registry"] + , reg : ["--registry"] + , "no-reg" : ["--no-registry"] + , silent : ["--loglevel", "silent"] + , verbose : ["--loglevel", "verbose"] + , h : ["--usage"] + , H : ["--usage"] + , "?" : ["--usage"] + , help : ["--usage"] + , v : ["--version"] + , f : ["--force"] + , desc : ["--description"] + , "no-desc" : ["--no-description"] + , "local" : ["--no-global"] + , l : ["--long"] + , p : ["--parseable"] + , porcelain : ["--parseable"] + , g : ["--global"] + } + + , types = + { aoa: Array + , nullstream: [null, Stream] + , date: Date + , str: String + , browser : String + , cache : path + , color : ["always", Boolean] + , depth : Number + , description : Boolean + , dev : Boolean + , editor : path + , force : Boolean + , global : Boolean + , globalconfig : path + , group : [String, Number] + , gzipbin : String + , logfd : [Number, Stream] + , loglevel : ["silent","win","error","warn","info","verbose","silly"] + , long : Boolean + , "node-version" : [false, String] + , npaturl : url + , npat : Boolean + , "onload-script" : [false, String] + , outfd : [Number, Stream] + , parseable : Boolean + , pre: Boolean + , prefix: path + , proxy : url + , "rebuild-bundle" : Boolean + , registry : url + , searchopts : String + , searchexclude: [null, String] + , shell : path + , t: [Array, String] + , tag : String + , tar : String + , tmp : path + , "unsafe-perm" : Boolean + , usage : Boolean + , user : String + , username : String + , userconfig : path + , version : Boolean + , viewer: path + , _exit : Boolean + } + +; [["-v", {version:true}, []] + ,["---v", {version:true}, []] + ,["ls -s --no-reg connect -d", + {loglevel:"info",registry:null},["ls","connect"]] + ,["ls ---s foo",{loglevel:"silent"},["ls","foo"]] + ,["ls --registry blargle", {}, ["ls"]] + ,["--no-registry", {registry:null}, []] + ,["--no-color true", {color:false}, []] + ,["--no-color false", {color:true}, []] + ,["--no-color", {color:false}, []] + ,["--color false", {color:false}, []] + ,["--color --logfd 7", {logfd:7,color:true}, []] + ,["--color=true", {color:true}, []] + ,["--logfd=10", {logfd:10}, []] + ,["--tmp=/tmp -tar=gtar",{tmp:"/tmp",tar:"gtar"},[]] + ,["--tmp=tmp -tar=gtar", + {tmp:path.resolve(process.cwd(), "tmp"),tar:"gtar"},[]] + ,["--logfd x", {}, []] + ,["a -true -- -no-false", {true:true},["a","-no-false"]] + ,["a -no-false", {false:false},["a"]] + ,["a -no-no-true", {true:true}, ["a"]] + ,["a -no-no-no-false", {false:false}, ["a"]] + ,["---NO-no-No-no-no-no-nO-no-no"+ + "-No-no-no-no-no-no-no-no-no"+ + "-no-no-no-no-NO-NO-no-no-no-no-no-no"+ + "-no-body-can-do-the-boogaloo-like-I-do" + ,{"body-can-do-the-boogaloo-like-I-do":false}, []] + ,["we are -no-strangers-to-love "+ + "--you-know=the-rules --and=so-do-i "+ + "---im-thinking-of=a-full-commitment "+ + "--no-you-would-get-this-from-any-other-guy "+ + "--no-gonna-give-you-up "+ + "-no-gonna-let-you-down=true "+ + "--no-no-gonna-run-around false "+ + "--desert-you=false "+ + "--make-you-cry false "+ + "--no-tell-a-lie "+ + "--no-no-and-hurt-you false" + ,{"strangers-to-love":false + ,"you-know":"the-rules" + ,"and":"so-do-i" + ,"you-would-get-this-from-any-other-guy":false + ,"gonna-give-you-up":false + ,"gonna-let-you-down":false + ,"gonna-run-around":false + ,"desert-you":false + ,"make-you-cry":false + ,"tell-a-lie":false + ,"and-hurt-you":false + },["we", "are"]] + ,["-t one -t two -t three" + ,{t: ["one", "two", "three"]} + ,[]] + ,["-t one -t null -t three four five null" + ,{t: ["one", "null", "three"]} + ,["four", "five", "null"]] + ,["-t foo" + ,{t:["foo"]} + ,[]] + ,["--no-t" + ,{t:["false"]} + ,[]] + ,["-no-no-t" + ,{t:["true"]} + ,[]] + ,["-aoa one -aoa null -aoa 100" + ,{aoa:["one", null, 100]} + ,[]] + ,["-str 100" + ,{str:"100"} + ,[]] + ,["--color always" + ,{color:"always"} + ,[]] + ,["--no-nullstream" + ,{nullstream:null} + ,[]] + ,["--nullstream false" + ,{nullstream:null} + ,[]] + ,["--notadate=2011-01-25" + ,{notadate: "2011-01-25"} + ,[]] + ,["--date 2011-01-25" + ,{date: new Date("2011-01-25")} + ,[]] + ,["-cl 1" + ,{config: true, length: 1} + ,[] + ,{config: Boolean, length: Number, clear: Boolean} + ,{c: "--config", l: "--length"}] + ,["--acount bla" + ,{"acount":true} + ,["bla"] + ,{account: Boolean, credentials: Boolean, options: String} + ,{a:"--account", c:"--credentials",o:"--options"}] + ,["--clear" + ,{clear:true} + ,[] + ,{clear:Boolean,con:Boolean,len:Boolean,exp:Boolean,add:Boolean,rep:Boolean} + ,{c:"--con",l:"--len",e:"--exp",a:"--add",r:"--rep"}] + ,["--file -" + ,{"file":"-"} + ,[] + ,{file:String} + ,{}] + ,["--file -" + ,{"file":true} + ,["-"] + ,{file:Boolean} + ,{}] + ].forEach(function (test) { + var argv = test[0].split(/\s+/) + , opts = test[1] + , rem = test[2] + , actual = nopt(test[3] || types, test[4] || shorthands, argv, 0) + , parsed = actual.argv + delete actual.argv + console.log(util.inspect(actual, false, 2, true), parsed.remain) + for (var i in opts) { + var e = JSON.stringify(opts[i]) + , a = JSON.stringify(actual[i] === undefined ? null : actual[i]) + if (e && typeof e === "object") { + assert.deepEqual(e, a) + } else { + assert.equal(e, a) + } + } + assert.deepEqual(rem, parsed.remain) + }) +} diff --git a/src/extensibility/node/node_modules/decompress-zip/node_modules/nopt/node_modules/abbrev/LICENSE b/src/extensibility/node/node_modules/decompress-zip/node_modules/nopt/node_modules/abbrev/LICENSE new file mode 100644 index 00000000000..05a4010949c --- /dev/null +++ b/src/extensibility/node/node_modules/decompress-zip/node_modules/nopt/node_modules/abbrev/LICENSE @@ -0,0 +1,23 @@ +Copyright 2009, 2010, 2011 Isaac Z. Schlueter. +All rights reserved. + +Permission is hereby granted, free of charge, to any person +obtaining a copy of this software and associated documentation +files (the "Software"), to deal in the Software without +restriction, including without limitation the rights to use, +copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the +Software is furnished to do so, subject to the following +conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES +OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT +HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +OTHER DEALINGS IN THE SOFTWARE. diff --git a/src/extensibility/node/node_modules/decompress-zip/node_modules/nopt/node_modules/abbrev/README.md b/src/extensibility/node/node_modules/decompress-zip/node_modules/nopt/node_modules/abbrev/README.md new file mode 100644 index 00000000000..99746fe67c4 --- /dev/null +++ b/src/extensibility/node/node_modules/decompress-zip/node_modules/nopt/node_modules/abbrev/README.md @@ -0,0 +1,23 @@ +# abbrev-js + +Just like [ruby's Abbrev](http://apidock.com/ruby/Abbrev). + +Usage: + + var abbrev = require("abbrev"); + abbrev("foo", "fool", "folding", "flop"); + + // returns: + { fl: 'flop' + , flo: 'flop' + , flop: 'flop' + , fol: 'folding' + , fold: 'folding' + , foldi: 'folding' + , foldin: 'folding' + , folding: 'folding' + , foo: 'foo' + , fool: 'fool' + } + +This is handy for command-line scripts, or other cases where you want to be able to accept shorthands. diff --git a/src/extensibility/node/node_modules/decompress-zip/node_modules/nopt/node_modules/abbrev/lib/abbrev.js b/src/extensibility/node/node_modules/decompress-zip/node_modules/nopt/node_modules/abbrev/lib/abbrev.js new file mode 100644 index 00000000000..bee4132c92b --- /dev/null +++ b/src/extensibility/node/node_modules/decompress-zip/node_modules/nopt/node_modules/abbrev/lib/abbrev.js @@ -0,0 +1,111 @@ + +module.exports = exports = abbrev.abbrev = abbrev + +abbrev.monkeyPatch = monkeyPatch + +function monkeyPatch () { + Object.defineProperty(Array.prototype, 'abbrev', { + value: function () { return abbrev(this) }, + enumerable: false, configurable: true, writable: true + }) + + Object.defineProperty(Object.prototype, 'abbrev', { + value: function () { return abbrev(Object.keys(this)) }, + enumerable: false, configurable: true, writable: true + }) +} + +function abbrev (list) { + if (arguments.length !== 1 || !Array.isArray(list)) { + list = Array.prototype.slice.call(arguments, 0) + } + for (var i = 0, l = list.length, args = [] ; i < l ; i ++) { + args[i] = typeof list[i] === "string" ? list[i] : String(list[i]) + } + + // sort them lexicographically, so that they're next to their nearest kin + args = args.sort(lexSort) + + // walk through each, seeing how much it has in common with the next and previous + var abbrevs = {} + , prev = "" + for (var i = 0, l = args.length ; i < l ; i ++) { + var current = args[i] + , next = args[i + 1] || "" + , nextMatches = true + , prevMatches = true + if (current === next) continue + for (var j = 0, cl = current.length ; j < cl ; j ++) { + var curChar = current.charAt(j) + nextMatches = nextMatches && curChar === next.charAt(j) + prevMatches = prevMatches && curChar === prev.charAt(j) + if (!nextMatches && !prevMatches) { + j ++ + break + } + } + prev = current + if (j === cl) { + abbrevs[current] = current + continue + } + for (var a = current.substr(0, j) ; j <= cl ; j ++) { + abbrevs[a] = current + a += current.charAt(j) + } + } + return abbrevs +} + +function lexSort (a, b) { + return a === b ? 0 : a > b ? 1 : -1 +} + + +// tests +if (module === require.main) { + +var assert = require("assert") +var util = require("util") + +console.log("running tests") +function test (list, expect) { + var actual = abbrev(list) + assert.deepEqual(actual, expect, + "abbrev("+util.inspect(list)+") === " + util.inspect(expect) + "\n"+ + "actual: "+util.inspect(actual)) + actual = abbrev.apply(exports, list) + assert.deepEqual(abbrev.apply(exports, list), expect, + "abbrev("+list.map(JSON.stringify).join(",")+") === " + util.inspect(expect) + "\n"+ + "actual: "+util.inspect(actual)) +} + +test([ "ruby", "ruby", "rules", "rules", "rules" ], +{ rub: 'ruby' +, ruby: 'ruby' +, rul: 'rules' +, rule: 'rules' +, rules: 'rules' +}) +test(["fool", "foom", "pool", "pope"], +{ fool: 'fool' +, foom: 'foom' +, poo: 'pool' +, pool: 'pool' +, pop: 'pope' +, pope: 'pope' +}) +test(["a", "ab", "abc", "abcd", "abcde", "acde"], +{ a: 'a' +, ab: 'ab' +, abc: 'abc' +, abcd: 'abcd' +, abcde: 'abcde' +, ac: 'acde' +, acd: 'acde' +, acde: 'acde' +}) + +console.log("pass") + +} diff --git a/src/extensibility/node/node_modules/decompress-zip/node_modules/nopt/node_modules/abbrev/package.json b/src/extensibility/node/node_modules/decompress-zip/node_modules/nopt/node_modules/abbrev/package.json new file mode 100644 index 00000000000..55ed011bf1f --- /dev/null +++ b/src/extensibility/node/node_modules/decompress-zip/node_modules/nopt/node_modules/abbrev/package.json @@ -0,0 +1,28 @@ +{ + "name": "abbrev", + "version": "1.0.4", + "description": "Like ruby's abbrev module, but in js", + "author": { + "name": "Isaac Z. Schlueter", + "email": "i@izs.me" + }, + "main": "./lib/abbrev.js", + "scripts": { + "test": "node lib/abbrev.js" + }, + "repository": { + "type": "git", + "url": "http://github.com/isaacs/abbrev-js" + }, + "license": { + "type": "MIT", + "url": "https://github.com/isaacs/abbrev-js/raw/master/LICENSE" + }, + "readme": "# abbrev-js\n\nJust like [ruby's Abbrev](http://apidock.com/ruby/Abbrev).\n\nUsage:\n\n var abbrev = require(\"abbrev\");\n abbrev(\"foo\", \"fool\", \"folding\", \"flop\");\n \n // returns:\n { fl: 'flop'\n , flo: 'flop'\n , flop: 'flop'\n , fol: 'folding'\n , fold: 'folding'\n , foldi: 'folding'\n , foldin: 'folding'\n , folding: 'folding'\n , foo: 'foo'\n , fool: 'fool'\n }\n\nThis is handy for command-line scripts, or other cases where you want to be able to accept shorthands.\n", + "readmeFilename": "README.md", + "bugs": { + "url": "https://github.com/isaacs/abbrev-js/issues" + }, + "_id": "abbrev@1.0.4", + "_from": "abbrev@1" +} diff --git a/src/extensibility/node/node_modules/decompress-zip/node_modules/nopt/package.json b/src/extensibility/node/node_modules/decompress-zip/node_modules/nopt/package.json new file mode 100644 index 00000000000..cdf2b96fb60 --- /dev/null +++ b/src/extensibility/node/node_modules/decompress-zip/node_modules/nopt/package.json @@ -0,0 +1,35 @@ +{ + "name": "nopt", + "version": "2.1.2", + "description": "Option parsing for Node, supporting types, shorthands, etc. Used by npm.", + "author": { + "name": "Isaac Z. Schlueter", + "email": "i@izs.me", + "url": "http://blog.izs.me/" + }, + "main": "lib/nopt.js", + "scripts": { + "test": "node lib/nopt.js" + }, + "repository": { + "type": "git", + "url": "http://github.com/isaacs/nopt" + }, + "bin": { + "nopt": "./bin/nopt.js" + }, + "license": { + "type": "MIT", + "url": "https://github.com/isaacs/nopt/raw/master/LICENSE" + }, + "dependencies": { + "abbrev": "1" + }, + "readme": "If you want to write an option parser, and have it be good, there are\ntwo ways to do it. The Right Way, and the Wrong Way.\n\nThe Wrong Way is to sit down and write an option parser. We've all done\nthat.\n\nThe Right Way is to write some complex configurable program with so many\noptions that you go half-insane just trying to manage them all, and put\nit off with duct-tape solutions until you see exactly to the core of the\nproblem, and finally snap and write an awesome option parser.\n\nIf you want to write an option parser, don't write an option parser.\nWrite a package manager, or a source control system, or a service\nrestarter, or an operating system. You probably won't end up with a\ngood one of those, but if you don't give up, and you are relentless and\ndiligent enough in your procrastination, you may just end up with a very\nnice option parser.\n\n## USAGE\n\n // my-program.js\n var nopt = require(\"nopt\")\n , Stream = require(\"stream\").Stream\n , path = require(\"path\")\n , knownOpts = { \"foo\" : [String, null]\n , \"bar\" : [Stream, Number]\n , \"baz\" : path\n , \"bloo\" : [ \"big\", \"medium\", \"small\" ]\n , \"flag\" : Boolean\n , \"pick\" : Boolean\n , \"many\" : [String, Array]\n }\n , shortHands = { \"foofoo\" : [\"--foo\", \"Mr. Foo\"]\n , \"b7\" : [\"--bar\", \"7\"]\n , \"m\" : [\"--bloo\", \"medium\"]\n , \"p\" : [\"--pick\"]\n , \"f\" : [\"--flag\"]\n }\n // everything is optional.\n // knownOpts and shorthands default to {}\n // arg list defaults to process.argv\n // slice defaults to 2\n , parsed = nopt(knownOpts, shortHands, process.argv, 2)\n console.log(parsed)\n\nThis would give you support for any of the following:\n\n```bash\n$ node my-program.js --foo \"blerp\" --no-flag\n{ \"foo\" : \"blerp\", \"flag\" : false }\n\n$ node my-program.js ---bar 7 --foo \"Mr. Hand\" --flag\n{ bar: 7, foo: \"Mr. Hand\", flag: true }\n\n$ node my-program.js --foo \"blerp\" -f -----p\n{ foo: \"blerp\", flag: true, pick: true }\n\n$ node my-program.js -fp --foofoo\n{ foo: \"Mr. Foo\", flag: true, pick: true }\n\n$ node my-program.js --foofoo -- -fp # -- stops the flag parsing.\n{ foo: \"Mr. Foo\", argv: { remain: [\"-fp\"] } }\n\n$ node my-program.js --blatzk 1000 -fp # unknown opts are ok.\n{ blatzk: 1000, flag: true, pick: true }\n\n$ node my-program.js --blatzk true -fp # but they need a value\n{ blatzk: true, flag: true, pick: true }\n\n$ node my-program.js --no-blatzk -fp # unless they start with \"no-\"\n{ blatzk: false, flag: true, pick: true }\n\n$ node my-program.js --baz b/a/z # known paths are resolved.\n{ baz: \"/Users/isaacs/b/a/z\" }\n\n# if Array is one of the types, then it can take many\n# values, and will always be an array. The other types provided\n# specify what types are allowed in the list.\n\n$ node my-program.js --many 1 --many null --many foo\n{ many: [\"1\", \"null\", \"foo\"] }\n\n$ node my-program.js --many foo\n{ many: [\"foo\"] }\n```\n\nRead the tests at the bottom of `lib/nopt.js` for more examples of\nwhat this puppy can do.\n\n## Types\n\nThe following types are supported, and defined on `nopt.typeDefs`\n\n* String: A normal string. No parsing is done.\n* path: A file system path. Gets resolved against cwd if not absolute.\n* url: A url. If it doesn't parse, it isn't accepted.\n* Number: Must be numeric.\n* Date: Must parse as a date. If it does, and `Date` is one of the options,\n then it will return a Date object, not a string.\n* Boolean: Must be either `true` or `false`. If an option is a boolean,\n then it does not need a value, and its presence will imply `true` as\n the value. To negate boolean flags, do `--no-whatever` or `--whatever\n false`\n* NaN: Means that the option is strictly not allowed. Any value will\n fail.\n* Stream: An object matching the \"Stream\" class in node. Valuable\n for use when validating programmatically. (npm uses this to let you\n supply any WriteStream on the `outfd` and `logfd` config options.)\n* Array: If `Array` is specified as one of the types, then the value\n will be parsed as a list of options. This means that multiple values\n can be specified, and that the value will always be an array.\n\nIf a type is an array of values not on this list, then those are\nconsidered valid values. For instance, in the example above, the\n`--bloo` option can only be one of `\"big\"`, `\"medium\"`, or `\"small\"`,\nand any other value will be rejected.\n\nWhen parsing unknown fields, `\"true\"`, `\"false\"`, and `\"null\"` will be\ninterpreted as their JavaScript equivalents, and numeric values will be\ninterpreted as a number.\n\nYou can also mix types and values, or multiple types, in a list. For\ninstance `{ blah: [Number, null] }` would allow a value to be set to\neither a Number or null. When types are ordered, this implies a\npreference, and the first type that can be used to properly interpret\nthe value will be used.\n\nTo define a new type, add it to `nopt.typeDefs`. Each item in that\nhash is an object with a `type` member and a `validate` method. The\n`type` member is an object that matches what goes in the type list. The\n`validate` method is a function that gets called with `validate(data,\nkey, val)`. Validate methods should assign `data[key]` to the valid\nvalue of `val` if it can be handled properly, or return boolean\n`false` if it cannot.\n\nYou can also call `nopt.clean(data, types, typeDefs)` to clean up a\nconfig object and remove its invalid properties.\n\n## Error Handling\n\nBy default, nopt outputs a warning to standard error when invalid\noptions are found. You can change this behavior by assigning a method\nto `nopt.invalidHandler`. This method will be called with\nthe offending `nopt.invalidHandler(key, val, types)`.\n\nIf no `nopt.invalidHandler` is assigned, then it will console.error\nits whining. If it is assigned to boolean `false` then the warning is\nsuppressed.\n\n## Abbreviations\n\nYes, they are supported. If you define options like this:\n\n```javascript\n{ \"foolhardyelephants\" : Boolean\n, \"pileofmonkeys\" : Boolean }\n```\n\nThen this will work:\n\n```bash\nnode program.js --foolhar --pil\nnode program.js --no-f --pileofmon\n# etc.\n```\n\n## Shorthands\n\nShorthands are a hash of shorter option names to a snippet of args that\nthey expand to.\n\nIf multiple one-character shorthands are all combined, and the\ncombination does not unambiguously match any other option or shorthand,\nthen they will be broken up into their constituent parts. For example:\n\n```json\n{ \"s\" : [\"--loglevel\", \"silent\"]\n, \"g\" : \"--global\"\n, \"f\" : \"--force\"\n, \"p\" : \"--parseable\"\n, \"l\" : \"--long\"\n}\n```\n\n```bash\nnpm ls -sgflp\n# just like doing this:\nnpm ls --loglevel silent --global --force --long --parseable\n```\n\n## The Rest of the args\n\nThe config object returned by nopt is given a special member called\n`argv`, which is an object with the following fields:\n\n* `remain`: The remaining args after all the parsing has occurred.\n* `original`: The args as they originally appeared.\n* `cooked`: The args after flags and shorthands are expanded.\n\n## Slicing\n\nNode programs are called with more or less the exact argv as it appears\nin C land, after the v8 and node-specific options have been plucked off.\nAs such, `argv[0]` is always `node` and `argv[1]` is always the\nJavaScript program being run.\n\nThat's usually not very useful to you. So they're sliced off by\ndefault. If you want them, then you can pass in `0` as the last\nargument, or any other number that you'd like to slice off the start of\nthe list.\n", + "readmeFilename": "README.md", + "bugs": { + "url": "https://github.com/isaacs/nopt/issues" + }, + "_id": "nopt@2.1.2", + "_from": "nopt@~2.1.2" +} diff --git a/src/extensibility/node/node_modules/decompress-zip/package.json b/src/extensibility/node/node_modules/decompress-zip/package.json index 229afbc5075..49a5a7ab55f 100644 --- a/src/extensibility/node/node_modules/decompress-zip/package.json +++ b/src/extensibility/node/node_modules/decompress-zip/package.json @@ -1,15 +1,21 @@ { "name": "decompress-zip", - "version": "0.0.1", + "version": "0.0.2", "description": "A library for reading data from zip files", "main": "lib/decompress-zip.js", "scripts": { "test": "grunt test" }, + "bin": { + "decompress-zip": "bin/decompress-zip" + }, "repository": { "type": "git", "url": "https://github.com/bower/decompress-zip.git" }, + "engines": { + "node": ">=0.8.0" + }, "keywords": [ "zip", "unzip", @@ -51,14 +57,11 @@ "mkpath": "~0.1.0", "binary": "~0.3.0", "touch": "0.0.2", - "readable-stream": "~1.1.8" + "readable-stream": "~1.1.8", + "nopt": "~2.1.2" }, "readme": "# decompress-zip [![Build Status](https://secure.travis-ci.org/bower/decompress-zip.png?branch=master)](http://travis-ci.org/bower/decompress-zip)\n\nExtract files from a ZIP archive\n\n## Usage\n\n### .extract(options)\n\nExtracts the contents of the ZIP archive `file`.\n\nReturns an EventEmitter with two possible events - `error` on an error, and `extract` when the extraction has completed. The value passed to the `extract` event is a basic log of each file and how it was compressed.\n\nThe default value for `options` is `{ path: '.' }`. Currently `path` is the\nonly option, and is the output path for the extraction.\n\n```js\nvar DecompressZip = require('decompress-zip');\nvar unzipper = new DecompressZip(filename)\n\nunzipper.on('error', function (err) {\n console.log('Caught an error');\n});\n\nunzipper.on('extract', function (log) {\n console.log('Finished extracting');\n});\n\nunzipper.extract({\n\tpath: 'some/path'\n});\n```\n\nIf `path` does not exist, decompress-zip will attempt to create it first.\n\n### .list()\n\nMuch like extract, except:\n- the success event is `list`\n- the data for the event is an array of paths\n- no files are actually extracted\n- there are no options\n\n```js\nvar DecompressZip = require('decompress-zip');\nvar unzipper = new DecompressZip(filename)\n\nunzipper.on('error', function (err) {\n console.log('Caught an error');\n});\n\nunzipper.on('list', function (files) {\n console.log('The archive contains:');\n console.log(files);\n});\n\nunzipper.list();\n```\n\n## License\n\nReleased under the [MIT License](http://www.opensource.org/licenses/mit-license.php).\n", "readmeFilename": "README.md", - "_id": "decompress-zip@0.0.1", - "dist": { - "shasum": "8dd672e9b56e4a7a2bc52451aac34841422498c0" - }, - "_from": "https://github.com/bower/decompress-zip/archive/705ca19e9843b409b2d01fd3e31285b305753e59.tar.gz", - "_resolved": "https://github.com/bower/decompress-zip/archive/705ca19e9843b409b2d01fd3e31285b305753e59.tar.gz" + "_id": "decompress-zip@0.0.2", + "_from": "decompress-zip@0.0.2" } diff --git a/src/extensibility/node/node_modules/decompress-zip/test/test.js b/src/extensibility/node/node_modules/decompress-zip/test/test.js index b2c39fed3d7..b15ce41be4b 100644 --- a/src/extensibility/node/node_modules/decompress-zip/test/test.js +++ b/src/extensibility/node/node_modules/decompress-zip/test/test.js @@ -75,7 +75,7 @@ describe('Extract', function () { }); it('should extract without any errors', function (done) { - this.timeout(60000); + this.timeout(20000); var zip = new DecompressZip(path.join(assetsPath, sample)); zip.on('extract', function () { diff --git a/src/extensibility/node/package.json b/src/extensibility/node/package.json index 3cd020b3c40..e83a1edc617 100644 --- a/src/extensibility/node/package.json +++ b/src/extensibility/node/package.json @@ -3,7 +3,7 @@ "description": "Used in the management of Brackets extensions", "version": "0.32.0", "dependencies": { - "decompress-zip": "https://github.com/bower/decompress-zip/archive/705ca19e9843b409b2d01fd3e31285b305753e59.tar.gz", + "decompress-zip": "0.0.2", "semver": "2.x", "fs-extra": "0.6.x", "async": "0.2.x", From 7b40e345f7dcfff18cc434b40ccf55ff908af39b Mon Sep 17 00:00:00 2001 From: Kevin Dangoor Date: Mon, 30 Sep 2013 11:42:46 -0400 Subject: [PATCH 53/56] Update Tern and Acorn to the latest --- src/extensions/default/JavaScriptCodeHints/thirdparty/acorn | 2 +- src/extensions/default/JavaScriptCodeHints/thirdparty/tern | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/extensions/default/JavaScriptCodeHints/thirdparty/acorn b/src/extensions/default/JavaScriptCodeHints/thirdparty/acorn index c152be4a2e8..83bfd6c5363 160000 --- a/src/extensions/default/JavaScriptCodeHints/thirdparty/acorn +++ b/src/extensions/default/JavaScriptCodeHints/thirdparty/acorn @@ -1 +1 @@ -Subproject commit c152be4a2e8383a21c573ba0b2495afc9ae84643 +Subproject commit 83bfd6c536335686894364b5f999837610323360 diff --git a/src/extensions/default/JavaScriptCodeHints/thirdparty/tern b/src/extensions/default/JavaScriptCodeHints/thirdparty/tern index 21c9f963b94..5fa9000f6d7 160000 --- a/src/extensions/default/JavaScriptCodeHints/thirdparty/tern +++ b/src/extensions/default/JavaScriptCodeHints/thirdparty/tern @@ -1 +1 @@ -Subproject commit 21c9f963b94f6ad077f95d182e9b4568c0d3874d +Subproject commit 5fa9000f6d7f7f1736824f7bc76c4e2da30c58ff From d02621c057c73158715130995ae0640b8519b5da Mon Sep 17 00:00:00 2001 From: wALF Utility Date: Mon, 30 Sep 2013 20:23:45 -0700 Subject: [PATCH 54/56] Updated by ALF automation. --- src/nls/ja/strings.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/nls/ja/strings.js b/src/nls/ja/strings.js index 2934eea7c03..6e20f55f8dc 100644 --- a/src/nls/ja/strings.js +++ b/src/nls/ja/strings.js @@ -141,7 +141,7 @@ define({ "FIND_IN_FILES_TITLE_PART1": "「", "FIND_IN_FILES_TITLE_PART2": "」の検索結果", - "FIND_IN_FILES_TITLE_PART3": "— {3} {4}で {1}件 {0}{2}", + "FIND_IN_FILES_TITLE_PART3": "— {3}個の{4}内で {1}件{0}{2}", "FIND_IN_FILES_SCOPED": "{0} 内", "FIND_IN_FILES_NO_SCOPE": "プロジェクト内", "FIND_IN_FILES_FILE": "ファイル", From e1132ecc65af53773c457b0252a83c9c71425c52 Mon Sep 17 00:00:00 2001 From: Ashok Gelal Date: Mon, 30 Sep 2013 22:04:57 -0600 Subject: [PATCH 55/56] Fix incorrect JSDoc parameter name. --- src/utils/AppInit.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/utils/AppInit.js b/src/utils/AppInit.js index 17e36b83cc3..ebbf5f417ff 100644 --- a/src/utils/AppInit.js +++ b/src/utils/AppInit.js @@ -90,7 +90,7 @@ define(function (require, exports, module) { * Adds a callback for the ready hook. Handlers are called after * htmlReady is done, the initial project is loaded, and all extensions are * loaded. - * @param {function} handler + * @param {function} callback */ function appReady(callback) { _addListener(APP_READY, callback); @@ -99,7 +99,7 @@ define(function (require, exports, module) { /** * Adds a callback for the htmlReady hook. Handlers are called after the * main application html template is rendered. - * @param {function} handler + * @param {function} callback */ function htmlReady(callback) { _addListener(HTML_READY, callback); From b08d0d17fc24a84a7e969aeb35bb4d5dc59e401c Mon Sep 17 00:00:00 2001 From: Peter Flynn Date: Wed, 2 Oct 2013 17:15:23 -0700 Subject: [PATCH 56/56] Change FileSystemManager.createFileSystem() to be async -- allowing filesystem impls time to seed any required initial data, or go through authentication workflows. --- src/filesystem/FileSystem.js | 9 +- src/filesystem/FileSystemManager.js | 15 +- src/filesystem/impls/FileSystemImpl.js | 2 +- .../impls/appshell/AppshellFileSystem.js | 6 +- .../impls/dropbox/DropboxFileSystem.js | 5 +- src/project/ProjectManager.js | 160 ++++++++++-------- 6 files changed, 115 insertions(+), 82 deletions(-) diff --git a/src/filesystem/FileSystem.js b/src/filesystem/FileSystem.js index 70921a1213a..fa7b4400ac1 100644 --- a/src/filesystem/FileSystem.js +++ b/src/filesystem/FileSystem.js @@ -37,11 +37,11 @@ define(function (require, exports, module) { /** * Constructor. FileSystem objects should not be constructed directly. * Use FileSystemManager.createFileSystem() instead. + * The FileSystem is not usable until init() signals its callback. * @param {!FileSystemImpl} impl Low-level file system implementation to use. */ function FileSystem(impl, system) { this._impl = impl; - this._impl.init(); this._system = system; // Create a file index @@ -64,6 +64,13 @@ define(function (require, exports, module) { * The FileIndex used by this object. This is initialized in the constructor. */ FileSystem.prototype._index = null; + + /** + * @param {function(?err)} callback + */ + FileSystem.prototype.init = function (callback) { + this._impl.init(callback); + }; /** * The name of the low-level file system implementation used by this object. diff --git a/src/filesystem/FileSystemManager.js b/src/filesystem/FileSystemManager.js index 3750df2cc27..08a13e1cafa 100644 --- a/src/filesystem/FileSystemManager.js +++ b/src/filesystem/FileSystemManager.js @@ -63,14 +63,18 @@ define(function (require, exports, module) { * * @param {string=} system The name of the low-level file system implementation. If omitted, * the default system is used. - * @return {FileSystem} A FileSystem object. + * @param {callback(?err, ?FileSystem)} Passed either an error or a fully-initialized FileSystem + * once it's ready */ - function createFileSystem(system) { + function createFileSystem(system, callback) { var impl = _impls[system || _defaultFileSystem]; console.assert(impl, "File System implementation not found: " + (system || _defaultFileSystem)); - return new FileSystem(impl, system); + var fs = new FileSystem(impl, system); + fs.init(function (err) { + callback(err, err ? null : fs); + }); } // TODO: Registration and assigning default should be done in brackets.js or globals.js @@ -87,7 +91,10 @@ define(function (require, exports, module) { // This file system is created with the "default" file system implementation, // which is different when running in the shell and in browsers. if (!appshell.appFileSystem) { - appshell.appFileSystem = createFileSystem(); + createFileSystem(null, function (err, fs) { + appshell.appFileSystem = fs; + }); + console.assert(appshell.appFileSystem, "Root 'appFileSystem' must be created synchronously!"); } // Export public API diff --git a/src/filesystem/impls/FileSystemImpl.js b/src/filesystem/impls/FileSystemImpl.js index 481c6142e05..92e233c70b4 100644 --- a/src/filesystem/impls/FileSystemImpl.js +++ b/src/filesystem/impls/FileSystemImpl.js @@ -9,7 +9,7 @@ // } // // -// init() +// init(callback) // showOpenDialog(allowMultipleSelection, chooseDirectories, title, initialPath, fileTypes, function (err, data)) // showSaveDialog((title, initialPath, proposedNewFilename, callback)) // [isNetworkDrive(path, callback)] diff --git a/src/filesystem/impls/appshell/AppshellFileSystem.js b/src/filesystem/impls/appshell/AppshellFileSystem.js index 2af83ecf570..82edf2b7d1d 100644 --- a/src/filesystem/impls/appshell/AppshellFileSystem.js +++ b/src/filesystem/impls/appshell/AppshellFileSystem.js @@ -51,7 +51,7 @@ define(function (require, exports, module) { var _changeTimeout, // Timeout used to batch up file watcher changes _pendingChanges = {}; // Pending file watcher changes - function init() { + function init(callback) { if (!_nodeConnectionDeferred) { _nodeConnectionDeferred = new $.Deferred(); @@ -85,6 +85,10 @@ define(function (require, exports, module) { ); }); } + + // Don't want to block on _nodeConnectionDeferred because we're needed as the 'root' fs + // at startup -- and the Node-side stuff isn't needed for most functionality anyway. + callback(); } function showOpenDialog(allowMultipleSelection, chooseDirectories, title, initialPath, fileTypes, callback) { diff --git a/src/filesystem/impls/dropbox/DropboxFileSystem.js b/src/filesystem/impls/dropbox/DropboxFileSystem.js index a8b7ceac4c6..5154752df85 100644 --- a/src/filesystem/impls/dropbox/DropboxFileSystem.js +++ b/src/filesystem/impls/dropbox/DropboxFileSystem.js @@ -32,7 +32,7 @@ define(function (require, exports, module) { var client; - function init() { + function init(callback) { if (!client) { client = new Dropbox.Client({ key: "sWR9wXcpXIA=|c5GZu+WL9XhxhReZMsg7QvspGpVZ80iF+Cin/xbKrQ==", @@ -40,7 +40,8 @@ define(function (require, exports, module) { }); client.authDriver(new Dropbox.Drivers.Redirect({rememberUser: true})); client.authenticate(function (err, client) { - // TODO: Handle errors + // TODO: Handle errors? + callback(err); }); } } diff --git a/src/project/ProjectManager.js b/src/project/ProjectManager.js index 11f2c29a650..aca0821e3cf 100644 --- a/src/project/ProjectManager.js +++ b/src/project/ProjectManager.js @@ -889,10 +889,22 @@ define(function (require, exports, module) { $(_fileSystem).off("change", _fileSystemChange); _fileSystem = null; } - - _fileSystem = FileSystemManager.createFileSystem(filesystem); - _fileSystem.setProjectRoot(rootPath); - $(_fileSystem).on("change", _fileSystemChange); + } + + function ensureFileSystem() { + var fsResult = new $.Deferred(); + if (_fileSystem) { + fsResult.resolve(); + } else { + FileSystemManager.createFileSystem(filesystem, function (err, fs) { + // TODO: check err? + _fileSystem = fs; + _fileSystem.setProjectRoot(rootPath); + $(_fileSystem).on("change", _fileSystemChange); + fsResult.resolve(); + }); + } + return fsResult.promise(); } // Clear project path map @@ -910,78 +922,80 @@ define(function (require, exports, module) { // Populate file tree as long as we aren't running in the browser if (!brackets.inBrowser) { - // Point at a real folder structure on local disk - var rootEntry = _fileSystem.getDirectoryForPath(rootPath); - rootEntry.exists() - .done(function (exists) { - if (exists) { - var projectRootChanged = (!_projectRoot || !rootEntry) || - _projectRoot.fullPath !== rootEntry.fullPath; - var i; - - // Success! - var perfTimerName = PerfUtils.markStart("Load Project: " + rootPath), - canonPath = FileUtils.canonicalizeFolderPath(rootPath); - - _projectRoot = rootEntry; - _projectBaseUrl = _prefs.getValue(_getBaseUrlKey()) || ""; - - // If this is the current welcome project, record it. In future launches, we always - // want to substitute the welcome project for the current build instead of using an - // outdated one (when loading recent projects or the last opened project). - if (canonPath === _getWelcomeProjectPath()) { - var welcomeProjects = _prefs.getValue("welcomeProjects") || []; - if (welcomeProjects.indexOf(canonPath) === -1) { - welcomeProjects.push(canonPath); - _prefs.setValue("welcomeProjects", welcomeProjects); - } - } - - // The tree will invoke our "data provider" function to populate the top-level items, then - // go idle until a node is expanded - at which time it'll call us again to fetch the node's - // immediate children, and so on. - resultRenderTree = _renderTree(_treeDataProvider); - - resultRenderTree.always(function () { - if (projectRootChanged) { - // Allow asynchronous event handlers to finish before resolving result by collecting promises from them - var promises = []; - $(exports).triggerHandler({ type: "projectOpen", promises: promises }, [_projectRoot]); - $.when.apply($, promises).then(result.resolve, result.reject); - } else { - result.resolve(); + ensureFileSystem().done(function () { + // Point at a real folder structure on local disk + var rootEntry = _fileSystem.getDirectoryForPath(rootPath); + rootEntry.exists() + .done(function (exists) { + if (exists) { + var projectRootChanged = (!_projectRoot || !rootEntry) || + _projectRoot.fullPath !== rootEntry.fullPath; + var i; + + // Success! + var perfTimerName = PerfUtils.markStart("Load Project: " + rootPath), + canonPath = FileUtils.canonicalizeFolderPath(rootPath); + + _projectRoot = rootEntry; + _projectBaseUrl = _prefs.getValue(_getBaseUrlKey()) || ""; + + // If this is the current welcome project, record it. In future launches, we always + // want to substitute the welcome project for the current build instead of using an + // outdated one (when loading recent projects or the last opened project). + if (canonPath === _getWelcomeProjectPath()) { + var welcomeProjects = _prefs.getValue("welcomeProjects") || []; + if (welcomeProjects.indexOf(canonPath) === -1) { + welcomeProjects.push(canonPath); + _prefs.setValue("welcomeProjects", welcomeProjects); + } } - }); - resultRenderTree.fail(function () { - // PerfUtils.terminateMeasurement(perfTimerName); - result.reject(); - }); - resultRenderTree.always(function () { - PerfUtils.addMeasurement(perfTimerName); - }); - } else { - Dialogs.showModalDialog( - DefaultDialogs.DIALOG_ID_ERROR, - Strings.ERROR_LOADING_PROJECT, - StringUtils.format( - Strings.REQUEST_NATIVE_FILE_SYSTEM_ERROR, - StringUtils.breakableUrl(rootPath), - "" // TODO: FileSystem error -- error.name - ) - ).done(function () { - // The project folder stored in preference doesn't exist, so load the default - // project directory. - // TODO (issue #267): When Brackets supports having no project directory - // defined this code will need to change - _loadProject(_getWelcomeProjectPath()).always(function () { - // Make sure not to reject the original deferred until the fallback - // project is loaded, so we don't violate expectations that there is always - // a current project before continuing after _loadProject(). + + // The tree will invoke our "data provider" function to populate the top-level items, then + // go idle until a node is expanded - at which time it'll call us again to fetch the node's + // immediate children, and so on. + resultRenderTree = _renderTree(_treeDataProvider); + + resultRenderTree.always(function () { + if (projectRootChanged) { + // Allow asynchronous event handlers to finish before resolving result by collecting promises from them + var promises = []; + $(exports).triggerHandler({ type: "projectOpen", promises: promises }, [_projectRoot]); + $.when.apply($, promises).then(result.resolve, result.reject); + } else { + result.resolve(); + } + }); + resultRenderTree.fail(function () { +// PerfUtils.terminateMeasurement(perfTimerName); result.reject(); }); - }); - } - }); + resultRenderTree.always(function () { + PerfUtils.addMeasurement(perfTimerName); + }); + } else { + Dialogs.showModalDialog( + DefaultDialogs.DIALOG_ID_ERROR, + Strings.ERROR_LOADING_PROJECT, + StringUtils.format( + Strings.REQUEST_NATIVE_FILE_SYSTEM_ERROR, + StringUtils.breakableUrl(rootPath), + "" // TODO: FileSystem error -- error.name + ) + ).done(function () { + // The project folder stored in preference doesn't exist, so load the default + // project directory. + // TODO (issue #267): When Brackets supports having no project directory + // defined this code will need to change + _loadProject(_getWelcomeProjectPath()).always(function () { + // Make sure not to reject the original deferred until the fallback + // project is loaded, so we don't violate expectations that there is always + // a current project before continuing after _loadProject(). + result.reject(); + }); + }); + } + }); + }); } return result.promise();