From 692895c410c88d9f7056245a1c58e123cb2b7746 Mon Sep 17 00:00:00 2001 From: Amin Yahyaabadi Date: Sat, 4 Jul 2020 05:34:30 -0500 Subject: [PATCH 01/35] bump underscore dependencies --- package.json | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/package.json b/package.json index e205563..8b5d354 100644 --- a/package.json +++ b/package.json @@ -24,9 +24,10 @@ "underscore" ], "dependencies": { - "underscore": "^1.9.1" + "underscore": "^1.10.2" }, "devDependencies": { + "@types/underscore": "^1.10.3", "jasmine-focused": "1.x", "grunt-contrib-coffee": "~0.9.0", "grunt-cli": "~0.1.8", From c82cdff53e322573970c7f9b055307dbb3129d35 Mon Sep 17 00:00:00 2001 From: Amin Yahyaabadi Date: Sat, 4 Jul 2020 05:47:19 -0500 Subject: [PATCH 02/35] using babel --- babel.config.js | 20 ++++++++++++++++++++ package.json | 12 ++++++++++-- 2 files changed, 30 insertions(+), 2 deletions(-) create mode 100644 babel.config.js diff --git a/babel.config.js b/babel.config.js new file mode 100644 index 0000000..0d779b8 --- /dev/null +++ b/babel.config.js @@ -0,0 +1,20 @@ +let presets = []; + +let plugins = [ + ["@babel/plugin-proposal-optional-chaining", { loose: false }], + ["@babel/plugin-proposal-nullish-coalescing-operator", { loose: false }], +]; + +if (process.env.BABEL_ENV === "development") { + plugins.push(...[ + "@babel/plugin-transform-modules-commonjs", + "@babel/plugin-proposal-export-namespace-from", + ]); +} + +module.exports = { + presets: presets, + plugins: plugins, + exclude: "node_modules/**", + sourceMap: true, +}; diff --git a/package.json b/package.json index 8b5d354..fd8b191 100644 --- a/package.json +++ b/package.json @@ -11,7 +11,9 @@ "main": "./lib/underscore-plus.js", "scripts": { "prepublish": "grunt clean coffee lint", - "test": "grunt test" + "test": "grunt test", + "babel": "env env BABEL_ENV=development babel src --out-dir lib", + "prepare": "npm run babel" }, "repository": { "type": "git", @@ -34,6 +36,12 @@ "grunt": "~0.4.1", "grunt-shell": "~0.2.2", "grunt-coffeelint": "0.0.6", - "rimraf": "~2.5.2" + "rimraf": "~2.5.2", + "@babel/cli": "7.10.3", + "@babel/core": "7.10.3", + "@babel/plugin-proposal-export-namespace-from": "^7.10.4", + "@babel/plugin-proposal-nullish-coalescing-operator": "^7.10.4", + "@babel/plugin-proposal-optional-chaining": "^7.10.4", + "@babel/plugin-transform-modules-commonjs": "^7.10.4" } } From 30e616eefdd764e750f5654cb259697820f52d2d Mon Sep 17 00:00:00 2001 From: Amin Yahyaabadi Date: Sat, 4 Jul 2020 06:08:02 -0500 Subject: [PATCH 03/35] replace grunt with scripts Add coffeelint --- Gruntfile.coffee | 46 ---------------------------------------------- package.json | 29 ++++++++++++++++++----------- 2 files changed, 18 insertions(+), 57 deletions(-) delete mode 100644 Gruntfile.coffee diff --git a/Gruntfile.coffee b/Gruntfile.coffee deleted file mode 100644 index 4f36d71..0000000 --- a/Gruntfile.coffee +++ /dev/null @@ -1,46 +0,0 @@ -module.exports = (grunt) -> - grunt.initConfig - pkg: grunt.file.readJSON('package.json') - - coffee: - lib: - expand: true - cwd: 'src' - src: ['*.coffee'] - dest: 'lib' - ext: '.js' - - dist: - expand: true - cwd: 'src' - src: ['*.coffee'] - dest: 'dist' - ext: '.js' - - coffeelint: - options: - no_empty_param_list: - level: 'error' - max_line_length: - level: 'ignore' - - src: ['src/*.coffee'] - test: ['spec/*.coffee'] - - shell: - test: - command: 'node node_modules/jasmine-focused/bin/jasmine-focused --captureExceptions --coffee spec' - options: - stdout: true - stderr: true - failOnError: true - - grunt.loadNpmTasks('grunt-contrib-coffee') - grunt.loadNpmTasks('grunt-shell') - grunt.loadNpmTasks('grunt-coffeelint') - - grunt.registerTask 'clean', -> require('rimraf').sync('lib') - grunt.registerTask('lint', ['coffeelint:src', 'coffeelint:test']) - grunt.registerTask('bower', ['lint', 'coffee:dist']) - grunt.registerTask('default', ['coffee:lib', 'coffeelint']) - grunt.registerTask('test', ['default', 'coffeelint:test', 'shell:test']) diff --git a/package.json b/package.json index fd8b191..8c2b74e 100644 --- a/package.json +++ b/package.json @@ -10,10 +10,13 @@ ], "main": "./lib/underscore-plus.js", "scripts": { - "prepublish": "grunt clean coffee lint", - "test": "grunt test", - "babel": "env env BABEL_ENV=development babel src --out-dir lib", - "prepare": "npm run babel" + "clean": "shx rm -rf lib", + "test": "jasmine-focused --captureExceptions --coffee spec", + "lint": "coffeelint spec/*.coffee", + "babel": "npm run clean && shx cp -r src lib && env NODE_ENV=development env BABEL_ENV=development babel lib --out-dir lib && shx cp lib/* dist", + "build": "npm run babel", + "prepare": "npm run build", + "prepublish": "npm run clean && npm run build" }, "repository": { "type": "git", @@ -31,17 +34,21 @@ "devDependencies": { "@types/underscore": "^1.10.3", "jasmine-focused": "1.x", - "grunt-contrib-coffee": "~0.9.0", - "grunt-cli": "~0.1.8", - "grunt": "~0.4.1", - "grunt-shell": "~0.2.2", - "grunt-coffeelint": "0.0.6", - "rimraf": "~2.5.2", + "coffeelint": "^2.1.0", "@babel/cli": "7.10.3", "@babel/core": "7.10.3", "@babel/plugin-proposal-export-namespace-from": "^7.10.4", "@babel/plugin-proposal-nullish-coalescing-operator": "^7.10.4", "@babel/plugin-proposal-optional-chaining": "^7.10.4", - "@babel/plugin-transform-modules-commonjs": "^7.10.4" + "@babel/plugin-transform-modules-commonjs": "^7.10.4", + "shx": "^0.3.2" + }, + "coffeelintConfig": { + "no_empty_param_list": { + "level": "error" + }, + "max_line_length": { + "level": "ignore" + } } } From 8929903ad80ab33424c609caa2e380401b74a003 Mon Sep 17 00:00:00 2001 From: Amin Yahyaabadi Date: Sat, 4 Jul 2020 06:08:34 -0500 Subject: [PATCH 04/35] spec: require from lib --- spec/underscore-plus-spec.coffee | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spec/underscore-plus-spec.coffee b/spec/underscore-plus-spec.coffee index 615f772..ecc5e15 100644 --- a/spec/underscore-plus-spec.coffee +++ b/spec/underscore-plus-spec.coffee @@ -1,4 +1,4 @@ -_ = require '../src/underscore-plus' +_ = require '../lib/underscore-plus.js' describe "underscore extensions", -> describe "::adviseBefore(object, methodName, advice)", -> From fcf6367db34d1e464b310c1498a09363bf95f534 Mon Sep 17 00:00:00 2001 From: Amin Yahyaabadi Date: Sat, 4 Jul 2020 05:39:00 -0500 Subject: [PATCH 05/35] decaffeinate --- src/underscore-plus.coffee | 366 ---------------------------- src/underscore-plus.js | 479 +++++++++++++++++++++++++++++++++++++ 2 files changed, 479 insertions(+), 366 deletions(-) delete mode 100644 src/underscore-plus.coffee create mode 100644 src/underscore-plus.js diff --git a/src/underscore-plus.coffee b/src/underscore-plus.coffee deleted file mode 100644 index 18cb5e5..0000000 --- a/src/underscore-plus.coffee +++ /dev/null @@ -1,366 +0,0 @@ -_ = require 'underscore' - -macModifierKeyMap = - cmd: '\u2318' - ctrl: '\u2303' - alt: '\u2325' - option: '\u2325' - shift: '\u21e7' - enter: '\u23ce' - left: '\u2190' - right: '\u2192' - up: '\u2191' - down: '\u2193' - -nonMacModifierKeyMap = - cmd: 'Cmd' - ctrl: 'Ctrl' - alt: 'Alt' - option: 'Alt' - shift: 'Shift' - enter: 'Enter' - left: 'Left' - right: 'Right' - up: 'Up' - down: 'Down' - -# Human key combos should always explicitly state the shift key. This map is a disambiguator. -# 'shift-version': 'no-shift-version' -shiftKeyMap = - '~': '`' - '_': '-' - '+': '=' - '|': '\\' - '{': '[' - '}': ']' - ':': ';' - '"': '\'' - '<': ',' - '>': '.' - '?': '/' - -splitKeyPath = (keyPath) -> - startIndex = 0 - keyPathArray = [] - return keyPathArray unless keyPath? - for char, i in keyPath - if char is '.' and (i is 0 or keyPath[i-1] != '\\') - keyPathArray.push keyPath.substring(startIndex, i) - startIndex = i + 1 - keyPathArray.push keyPath.substr(startIndex, keyPath.length) - keyPathArray - -isPlainObject = (value) -> - _.isObject(value) and not _.isArray(value) - -plus = - adviseBefore: (object, methodName, advice) -> - original = object[methodName] - object[methodName] = (args...) -> - unless advice.apply(this, args) == false - original.apply(this, args) - - camelize: (string) -> - if string - string.replace /[_-]+(\w)/g, (m) -> m[1].toUpperCase() - else - '' - - capitalize: (word) -> - return '' unless word - - if word.toLowerCase() is 'github' - 'GitHub' - else - word[0].toUpperCase() + word[1..] - - compactObject: (object) -> - newObject = {} - for key, value of object - newObject[key] = value if value? - newObject - - dasherize: (string) -> - return '' unless string - - string = string[0].toLowerCase() + string[1..] - string.replace /([A-Z])|(_)/g, (m, letter) -> - if letter - "-" + letter.toLowerCase() - else - "-" - - # Deep clones the given JSON object. - # - # `object` - The JSON object to clone. - # - # Returns a deep clone of the JSON object. - deepClone: (object) -> - if _.isArray(object) - object.map (value) -> plus.deepClone(value) - else if _.isObject(object) and not _.isFunction(object) - plus.mapObject object, (key, value) => [key, plus.deepClone(value)] - else - object - - deepExtend: (target) -> - result = target - i = 0 - while ++i < arguments.length - object = arguments[i] - if isPlainObject(result) and isPlainObject(object) - for key in Object.keys(object) - result[key] = plus.deepExtend(result[key], object[key]) - else - result = plus.deepClone(object) - result - - deepContains: (array, target) -> - return false unless array? - for object in array - return true if _.isEqual(object, target) - false - - endsWith: (string, suffix='') -> - if string - string.indexOf(suffix, string.length - suffix.length) isnt -1 - else - false - - escapeAttribute: (string) -> - if string - string.replace(/"/g, '"').replace(/\n/g, '').replace(/\\/g, '-') - else - '' - - escapeRegExp: (string) -> - if string - string.replace(/[-\/\\^$*+?.()|[\]{}]/g, '\\$&') - else - '' - - humanizeEventName: (eventName, eventDoc) -> - [namespace, event] = eventName.split(':') - return plus.undasherize(namespace) unless event? - - namespaceDoc = plus.undasherize(namespace) - eventDoc ?= plus.undasherize(event) - - "#{namespaceDoc}: #{eventDoc}" - - humanizeKey: (key, platform=process.platform) -> - return key unless key - - modifierKeyMap = if platform is 'darwin' then macModifierKeyMap else nonMacModifierKeyMap - - if modifierKeyMap[key] - modifierKeyMap[key] - else if key.length == 1 and shiftKeyMap[key]? - [modifierKeyMap.shift, shiftKeyMap[key]] - else if key.length == 1 and key == key.toUpperCase() and key.toUpperCase() != key.toLowerCase() - [modifierKeyMap.shift, key.toUpperCase()] - else if key.length == 1 or /f[0-9]{1,2}/.test(key) - key.toUpperCase() - else - if platform is 'darwin' - key - else - plus.capitalize(key) - - # Humanize the keystroke according to platform conventions. This method - # attempts to mirror the text the given keystroke would have if displayed in - # a system menu. - # - # keystroke - A String keystroke to humanize such as `ctrl-O`. - # platform - An optional String platform to humanize for (default: - # `process.platform`). - # - # Returns a humanized representation of the keystroke. - humanizeKeystroke: (keystroke, platform=process.platform) -> - return keystroke unless keystroke - - keystrokes = keystroke.split(' ') - humanizedKeystrokes = [] - for keystroke in keystrokes - keys = [] - splitKeystroke = keystroke.split('-') - for key, index in splitKeystroke - # Check for consecutive dashes such as cmd-- - key = '-' if key is '' and splitKeystroke[index-1] is '' - keys.push(plus.humanizeKey(key, platform)) if key - - keys = _.uniq(_.flatten(keys)) - if platform is 'darwin' - keys = keys.join('') - else - keys = keys.join('+') - humanizedKeystrokes.push(keys) - - humanizedKeystrokes.join(' ') - - isSubset: (potentialSubset, potentialSuperset) -> - _.every potentialSubset, (element) -> _.include(potentialSuperset, element) - - losslessInvert: (hash) -> - inverted = {} - for key, value of hash - inverted[value] ?= [] - inverted[value].push(key) - inverted - - # Transform the given object into another object. - # - # `object` - The object to transform. - # `iterator` - - # A function that takes `(key, value)` arguments and returns a - # `[key, value]` tuple. - # - # Returns a new object based with the key/values returned by the iterator. - mapObject: (object, iterator) -> - newObject = {} - for key in Object.keys(object) - [key, value] = iterator(key, object[key]) - newObject[key] = value - - newObject - - multiplyString: (string, n) -> - finalString = "" - i = 0 - while i < n - finalString += string - i++ - finalString - - pluralize: (count=0, singular, plural=singular+'s') -> - if count is 1 - "#{count} #{singular}" - else - "#{count} #{plural}" - - remove: (array, element) -> - index = array.indexOf(element) - array.splice(index, 1) if index >= 0 - array - - setValueForKeyPath: (object, keyPath, value) -> - keys = splitKeyPath(keyPath) - while keys.length > 1 - key = keys.shift() - object[key] ?= {} - object = object[key] - if value? - object[keys.shift()] = value - else - delete object[keys.shift()] - - hasKeyPath: (object, keyPath) -> - keys = splitKeyPath(keyPath) - for key in keys - return false unless object.hasOwnProperty(key) - object = object[key] - true - - spliceWithArray: (originalArray, start, length, insertedArray, chunkSize=100000) -> - if insertedArray.length < chunkSize - originalArray.splice(start, length, insertedArray...) - else - originalArray.splice(start, length) - for chunkStart in [0..insertedArray.length] by chunkSize - originalArray.splice(start + chunkStart, 0, insertedArray.slice(chunkStart, chunkStart + chunkSize)...) - - sum: (array) -> - sum = 0 - sum += elt for elt in array - sum - - uncamelcase: (string) -> - return '' unless string - - result = string.replace /([A-Z])|_+/g, (match, letter='') -> " #{letter}" - plus.capitalize(result.trim()) - - undasherize: (string) -> - if string - string.split('-').map(plus.capitalize).join(' ') - else - '' - - underscore: (string) -> - return '' unless string - - string = string[0].toLowerCase() + string[1..] - string.replace /([A-Z])|-+/g, (match, letter='') -> "_#{letter.toLowerCase()}" - - valueForKeyPath: (object, keyPath) -> - keys = splitKeyPath(keyPath) - for key in keys - object = object[key] - return unless object? - object - - isEqual: (a, b, aStack, bStack) -> - if _.isArray(aStack) and _.isArray(bStack) - isEqual(a, b, aStack, bStack) - else - isEqual(a, b) - - isEqualForProperties: (a, b, properties...) -> - for property in properties - return false unless _.isEqual(a[property], b[property]) - true - -isEqual = (a, b, aStack=[], bStack=[]) -> - return _.isEqual(a, b) if a is b - return _.isEqual(a, b) if _.isFunction(a) or _.isFunction(b) - - stackIndex = aStack.length - while stackIndex-- - return bStack[stackIndex] is b if aStack[stackIndex] is a - aStack.push(a) - bStack.push(b) - - equal = false - if _.isFunction(a?.isEqual) - equal = a.isEqual(b, aStack, bStack) - else if _.isFunction(b?.isEqual) - equal = b.isEqual(a, bStack, aStack) - else if _.isArray(a) and _.isArray(b) and a.length is b.length - equal = true - for aElement, i in a - unless isEqual(aElement, b[i], aStack, bStack) - equal = false - break - else if _.isRegExp(a) and _.isRegExp(b) - equal = _.isEqual(a, b) - else if _.isElement(a) and _.isElement(b) - equal = a is b - else if _.isObject(a) and _.isObject(b) - aCtor = a.constructor - bCtor = b.constructor - aCtorValid = _.isFunction(aCtor) and aCtor instanceof aCtor - bCtorValid = _.isFunction(bCtor) and bCtor instanceof bCtor - if aCtor isnt bCtor and not (aCtorValid and bCtorValid) - equal = false - else - aKeyCount = 0 - equal = true - for key, aValue of a - continue unless _.has(a, key) - aKeyCount++ - unless _.has(b, key) and isEqual(aValue, b[key], aStack, bStack) - equal = false - break - if equal - bKeyCount = 0 - for key, bValue of b - bKeyCount++ if _.has(b, key) - equal = aKeyCount is bKeyCount - else - equal = _.isEqual(a, b) - - aStack.pop() - bStack.pop() - equal - -module.exports = _.extend({}, _, plus) diff --git a/src/underscore-plus.js b/src/underscore-plus.js new file mode 100644 index 0000000..c95ad68 --- /dev/null +++ b/src/underscore-plus.js @@ -0,0 +1,479 @@ +/* + * decaffeinate suggestions: + * DS101: Remove unnecessary use of Array.from + * DS102: Remove unnecessary code created because of implicit returns + * DS202: Simplify dynamic range loops + * DS205: Consider reworking code to avoid use of IIFEs + * DS207: Consider shorter variations of null checks + * Full docs: https://github.com/decaffeinate/decaffeinate/blob/master/docs/suggestions.md + */ +const _ = require('underscore'); + +const macModifierKeyMap = { + cmd: '\u2318', + ctrl: '\u2303', + alt: '\u2325', + option: '\u2325', + shift: '\u21e7', + enter: '\u23ce', + left: '\u2190', + right: '\u2192', + up: '\u2191', + down: '\u2193' +}; + +const nonMacModifierKeyMap = { + cmd: 'Cmd', + ctrl: 'Ctrl', + alt: 'Alt', + option: 'Alt', + shift: 'Shift', + enter: 'Enter', + left: 'Left', + right: 'Right', + up: 'Up', + down: 'Down' +}; + +// Human key combos should always explicitly state the shift key. This map is a disambiguator. +// 'shift-version': 'no-shift-version' +const shiftKeyMap = { + '~': '`', + '_': '-', + '+': '=', + '|': '\\', + '{': '[', + '}': ']', + ':': ';', + '"': '\'', + '<': ',', + '>': '.', + '?': '/' +}; + +const splitKeyPath = function(keyPath) { + let startIndex = 0; + const keyPathArray = []; + if (keyPath == null) { return keyPathArray; } + for (let i = 0; i < keyPath.length; i++) { + const char = keyPath[i]; + if ((char === '.') && ((i === 0) || (keyPath[i-1] !== '\\'))) { + keyPathArray.push(keyPath.substring(startIndex, i)); + startIndex = i + 1; + } + } + keyPathArray.push(keyPath.substr(startIndex, keyPath.length)); + return keyPathArray; +}; + +const isPlainObject = value => _.isObject(value) && !_.isArray(value); + +var plus = { + adviseBefore(object, methodName, advice) { + const original = object[methodName]; + return object[methodName] = function(...args) { + if (advice.apply(this, args) !== false) { + return original.apply(this, args); + } + }; + }, + + camelize(string) { + if (string) { + return string.replace(/[_-]+(\w)/g, m => m[1].toUpperCase()); + } else { + return ''; + } + }, + + capitalize(word) { + if (!word) { return ''; } + + if (word.toLowerCase() === 'github') { + return 'GitHub'; + } else { + return word[0].toUpperCase() + word.slice(1); + } + }, + + compactObject(object) { + const newObject = {}; + for (let key in object) { + const value = object[key]; + if (value != null) { newObject[key] = value; } + } + return newObject; + }, + + dasherize(string) { + if (!string) { return ''; } + + string = string[0].toLowerCase() + string.slice(1); + return string.replace(/([A-Z])|(_)/g, function(m, letter) { + if (letter) { + return "-" + letter.toLowerCase(); + } else { + return "-"; + } + }); + }, + + // Deep clones the given JSON object. + // + // `object` - The JSON object to clone. + // + // Returns a deep clone of the JSON object. + deepClone(object) { + if (_.isArray(object)) { + return object.map(value => plus.deepClone(value)); + } else if (_.isObject(object) && !_.isFunction(object)) { + return plus.mapObject(object, (key, value) => [key, plus.deepClone(value)]); + } else { + return object; + } + }, + + deepExtend(target) { + let result = target; + let i = 0; + while (++i < arguments.length) { + const object = arguments[i]; + if (isPlainObject(result) && isPlainObject(object)) { + for (let key of Array.from(Object.keys(object))) { + result[key] = plus.deepExtend(result[key], object[key]); + } + } else { + result = plus.deepClone(object); + } + } + return result; + }, + + deepContains(array, target) { + if (array == null) { return false; } + for (let object of Array.from(array)) { + if (_.isEqual(object, target)) { return true; } + } + return false; + }, + + endsWith(string, suffix) { + if (suffix == null) { suffix = ''; } + if (string) { + return string.indexOf(suffix, string.length - suffix.length) !== -1; + } else { + return false; + } + }, + + escapeAttribute(string) { + if (string) { + return string.replace(/"/g, '"').replace(/\n/g, '').replace(/\\/g, '-'); + } else { + return ''; + } + }, + + escapeRegExp(string) { + if (string) { + return string.replace(/[-\/\\^$*+?.()|[\]{}]/g, '\\$&'); + } else { + return ''; + } + }, + + humanizeEventName(eventName, eventDoc) { + const [namespace, event] = Array.from(eventName.split(':')); + if (event == null) { return plus.undasherize(namespace); } + + const namespaceDoc = plus.undasherize(namespace); + if (eventDoc == null) { eventDoc = plus.undasherize(event); } + + return `${namespaceDoc}: ${eventDoc}`; + }, + + humanizeKey(key, platform) { + if (platform == null) { ({ + platform + } = process); } + if (!key) { return key; } + + const modifierKeyMap = platform === 'darwin' ? macModifierKeyMap : nonMacModifierKeyMap; + + if (modifierKeyMap[key]) { + return modifierKeyMap[key]; + } else if ((key.length === 1) && (shiftKeyMap[key] != null)) { + return [modifierKeyMap.shift, shiftKeyMap[key]]; + } else if ((key.length === 1) && (key === key.toUpperCase()) && (key.toUpperCase() !== key.toLowerCase())) { + return [modifierKeyMap.shift, key.toUpperCase()]; + } else if ((key.length === 1) || /f[0-9]{1,2}/.test(key)) { + return key.toUpperCase(); + } else { + if (platform === 'darwin') { + return key; + } else { + return plus.capitalize(key); + } + } + }, + + // Humanize the keystroke according to platform conventions. This method + // attempts to mirror the text the given keystroke would have if displayed in + // a system menu. + // + // keystroke - A String keystroke to humanize such as `ctrl-O`. + // platform - An optional String platform to humanize for (default: + // `process.platform`). + // + // Returns a humanized representation of the keystroke. + humanizeKeystroke(keystroke, platform) { + if (platform == null) { ({ + platform + } = process); } + if (!keystroke) { return keystroke; } + + const keystrokes = keystroke.split(' '); + const humanizedKeystrokes = []; + for (keystroke of Array.from(keystrokes)) { + let keys = []; + const splitKeystroke = keystroke.split('-'); + for (let index = 0; index < splitKeystroke.length; index++) { + // Check for consecutive dashes such as cmd-- + let key = splitKeystroke[index]; + if ((key === '') && (splitKeystroke[index-1] === '')) { key = '-'; } + if (key) { keys.push(plus.humanizeKey(key, platform)); } + } + + keys = _.uniq(_.flatten(keys)); + if (platform === 'darwin') { + keys = keys.join(''); + } else { + keys = keys.join('+'); + } + humanizedKeystrokes.push(keys); + } + + return humanizedKeystrokes.join(' '); + }, + + isSubset(potentialSubset, potentialSuperset) { + return _.every(potentialSubset, element => _.include(potentialSuperset, element)); + }, + + losslessInvert(hash) { + const inverted = {}; + for (let key in hash) { + const value = hash[key]; + if (inverted[value] == null) { inverted[value] = []; } + inverted[value].push(key); + } + return inverted; + }, + + // Transform the given object into another object. + // + // `object` - The object to transform. + // `iterator` - + // A function that takes `(key, value)` arguments and returns a + // `[key, value]` tuple. + // + // Returns a new object based with the key/values returned by the iterator. + mapObject(object, iterator) { + const newObject = {}; + for (let key of Array.from(Object.keys(object))) { + let value; + [key, value] = Array.from(iterator(key, object[key])); + newObject[key] = value; + } + + return newObject; + }, + + multiplyString(string, n) { + let finalString = ""; + let i = 0; + while (i < n) { + finalString += string; + i++; + } + return finalString; + }, + + pluralize(count, singular, plural) { + if (count == null) { count = 0; } + if (plural == null) { plural = singular+'s'; } + if (count === 1) { + return `${count} ${singular}`; + } else { + return `${count} ${plural}`; + } + }, + + remove(array, element) { + const index = array.indexOf(element); + if (index >= 0) { array.splice(index, 1); } + return array; + }, + + setValueForKeyPath(object, keyPath, value) { + const keys = splitKeyPath(keyPath); + while (keys.length > 1) { + const key = keys.shift(); + if (object[key] == null) { object[key] = {}; } + object = object[key]; + } + if (value != null) { + return object[keys.shift()] = value; + } else { + return delete object[keys.shift()]; + } + }, + + hasKeyPath(object, keyPath) { + const keys = splitKeyPath(keyPath); + for (let key of Array.from(keys)) { + if (!object.hasOwnProperty(key)) { return false; } + object = object[key]; + } + return true; + }, + + spliceWithArray(originalArray, start, length, insertedArray, chunkSize) { + if (chunkSize == null) { chunkSize = 100000; } + if (insertedArray.length < chunkSize) { + return originalArray.splice(start, length, ...Array.from(insertedArray)); + } else { + originalArray.splice(start, length); + return (() => { + const result = []; + for (let chunkStart = 0, end = insertedArray.length, step = chunkSize, asc = step > 0; asc ? chunkStart <= end : chunkStart >= end; chunkStart += step) { + result.push(originalArray.splice(start + chunkStart, 0, ...Array.from(insertedArray.slice(chunkStart, chunkStart + chunkSize)))); + } + return result; + })(); + } + }, + + sum(array) { + let sum = 0; + for (let elt of Array.from(array)) { sum += elt; } + return sum; + }, + + uncamelcase(string) { + if (!string) { return ''; } + + const result = string.replace(/([A-Z])|_+/g, function(match, letter) { if (letter == null) { letter = ''; } return ` ${letter}`; }); + return plus.capitalize(result.trim()); + }, + + undasherize(string) { + if (string) { + return string.split('-').map(plus.capitalize).join(' '); + } else { + return ''; + } + }, + + underscore(string) { + if (!string) { return ''; } + + string = string[0].toLowerCase() + string.slice(1); + return string.replace(/([A-Z])|-+/g, function(match, letter) { if (letter == null) { letter = ''; } return `_${letter.toLowerCase()}`; }); + }, + + valueForKeyPath(object, keyPath) { + const keys = splitKeyPath(keyPath); + for (let key of Array.from(keys)) { + object = object[key]; + if (object == null) { return; } + } + return object; + }, + + isEqual(a, b, aStack, bStack) { + if (_.isArray(aStack) && _.isArray(bStack)) { + return isEqual(a, b, aStack, bStack); + } else { + return isEqual(a, b); + } + }, + + isEqualForProperties(a, b, ...properties) { + for (let property of Array.from(properties)) { + if (!_.isEqual(a[property], b[property])) { return false; } + } + return true; + } +}; + +var isEqual = function(a, b, aStack, bStack) { + if (aStack == null) { aStack = []; } + if (bStack == null) { bStack = []; } + if (a === b) { return _.isEqual(a, b); } + if (_.isFunction(a) || _.isFunction(b)) { return _.isEqual(a, b); } + + let stackIndex = aStack.length; + while (stackIndex--) { + if (aStack[stackIndex] === a) { return bStack[stackIndex] === b; } + } + aStack.push(a); + bStack.push(b); + + let equal = false; + if (_.isFunction(a?.isEqual)) { + equal = a.isEqual(b, aStack, bStack); + } else if (_.isFunction(b?.isEqual)) { + equal = b.isEqual(a, bStack, aStack); + } else if (_.isArray(a) && _.isArray(b) && (a.length === b.length)) { + equal = true; + for (let i = 0; i < a.length; i++) { + const aElement = a[i]; + if (!isEqual(aElement, b[i], aStack, bStack)) { + equal = false; + break; + } + } + } else if (_.isRegExp(a) && _.isRegExp(b)) { + equal = _.isEqual(a, b); + } else if (_.isElement(a) && _.isElement(b)) { + equal = a === b; + } else if (_.isObject(a) && _.isObject(b)) { + const aCtor = a.constructor; + const bCtor = b.constructor; + const aCtorValid = _.isFunction(aCtor) && aCtor instanceof aCtor; + const bCtorValid = _.isFunction(bCtor) && bCtor instanceof bCtor; + if ((aCtor !== bCtor) && !(aCtorValid && bCtorValid)) { + equal = false; + } else { + let key; + let aKeyCount = 0; + equal = true; + for (key in a) { + const aValue = a[key]; + if (!_.has(a, key)) { continue; } + aKeyCount++; + if (!_.has(b, key) || !isEqual(aValue, b[key], aStack, bStack)) { + equal = false; + break; + } + } + if (equal) { + let bKeyCount = 0; + for (key in b) { + const bValue = b[key]; + if (_.has(b, key)) { bKeyCount++; } + } + equal = aKeyCount === bKeyCount; + } + } + } else { + equal = _.isEqual(a, b); + } + + aStack.pop(); + bStack.pop(); + return equal; +}; + +module.exports = _.extend({}, _, plus); From 1ddf28c7af451078f17b29dcf69ece9d0d4d21f8 Mon Sep 17 00:00:00 2001 From: Amin Yahyaabadi Date: Sat, 4 Jul 2020 05:49:48 -0500 Subject: [PATCH 06/35] rename to mjs to support modules directly --- src/{underscore-plus.js => underscore-plus.mjs} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename src/{underscore-plus.js => underscore-plus.mjs} (100%) diff --git a/src/underscore-plus.js b/src/underscore-plus.mjs similarity index 100% rename from src/underscore-plus.js rename to src/underscore-plus.mjs From 8a461b8784626357f32c49a80e279d6994e0bc9c Mon Sep 17 00:00:00 2001 From: Amin Yahyaabadi Date: Sat, 4 Jul 2020 05:47:59 -0500 Subject: [PATCH 07/35] named import from underscore --- src/underscore-plus.mjs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/underscore-plus.mjs b/src/underscore-plus.mjs index c95ad68..8376113 100644 --- a/src/underscore-plus.mjs +++ b/src/underscore-plus.mjs @@ -7,7 +7,7 @@ * DS207: Consider shorter variations of null checks * Full docs: https://github.com/decaffeinate/decaffeinate/blob/master/docs/suggestions.md */ -const _ = require('underscore'); +import * as _ from 'underscore' const macModifierKeyMap = { cmd: '\u2318', From f16853e08b46bcb2d13bf136ed58fac91ba5b093 Mon Sep 17 00:00:00 2001 From: Amin Yahyaabadi Date: Sat, 4 Jul 2020 05:48:21 -0500 Subject: [PATCH 08/35] named export all the functions Replaces plus. with the actual name of the function --- src/underscore-plus.mjs | 613 ++++++++++++++++++++-------------------- 1 file changed, 305 insertions(+), 308 deletions(-) diff --git a/src/underscore-plus.mjs b/src/underscore-plus.mjs index 8376113..3744d7e 100644 --- a/src/underscore-plus.mjs +++ b/src/underscore-plus.mjs @@ -7,6 +7,7 @@ * DS207: Consider shorter variations of null checks * Full docs: https://github.com/decaffeinate/decaffeinate/blob/master/docs/suggestions.md */ +export * from 'underscore' import * as _ from 'underscore' const macModifierKeyMap = { @@ -68,346 +69,344 @@ const splitKeyPath = function(keyPath) { const isPlainObject = value => _.isObject(value) && !_.isArray(value); -var plus = { - adviseBefore(object, methodName, advice) { - const original = object[methodName]; - return object[methodName] = function(...args) { - if (advice.apply(this, args) !== false) { - return original.apply(this, args); - } - }; - }, - - camelize(string) { - if (string) { - return string.replace(/[_-]+(\w)/g, m => m[1].toUpperCase()); - } else { - return ''; +export function adviseBefore(object, methodName, advice) { + const original = object[methodName]; + return object[methodName] = function(...args) { + if (advice.apply(this, args) !== false) { + return original.apply(this, args); } - }, + }; +} - capitalize(word) { - if (!word) { return ''; } +export function camelize(string) { + if (string) { + return string.replace(/[_-]+(\w)/g, m => m[1].toUpperCase()); + } else { + return ''; + } +} - if (word.toLowerCase() === 'github') { - return 'GitHub'; - } else { - return word[0].toUpperCase() + word.slice(1); - } - }, +export function capitalize(word) { + if (!word) { return ''; } - compactObject(object) { - const newObject = {}; - for (let key in object) { - const value = object[key]; - if (value != null) { newObject[key] = value; } - } - return newObject; - }, - - dasherize(string) { - if (!string) { return ''; } - - string = string[0].toLowerCase() + string.slice(1); - return string.replace(/([A-Z])|(_)/g, function(m, letter) { - if (letter) { - return "-" + letter.toLowerCase(); - } else { - return "-"; - } - }); - }, - - // Deep clones the given JSON object. - // - // `object` - The JSON object to clone. - // - // Returns a deep clone of the JSON object. - deepClone(object) { - if (_.isArray(object)) { - return object.map(value => plus.deepClone(value)); - } else if (_.isObject(object) && !_.isFunction(object)) { - return plus.mapObject(object, (key, value) => [key, plus.deepClone(value)]); + if (word.toLowerCase() === 'github') { + return 'GitHub'; + } else { + return word[0].toUpperCase() + word.slice(1); + } +} + +export function compactObject(object) { + const newObject = {}; + for (let key in object) { + const value = object[key]; + if (value != null) { newObject[key] = value; } + } + return newObject; +} + +export function dasherize(string) { + if (!string) { return ''; } + + string = string[0].toLowerCase() + string.slice(1); + return string.replace(/([A-Z])|(_)/g, function(m, letter) { + if (letter) { + return "-" + letter.toLowerCase(); } else { - return object; + return "-"; } - }, - - deepExtend(target) { - let result = target; - let i = 0; - while (++i < arguments.length) { - const object = arguments[i]; - if (isPlainObject(result) && isPlainObject(object)) { - for (let key of Array.from(Object.keys(object))) { - result[key] = plus.deepExtend(result[key], object[key]); - } - } else { - result = plus.deepClone(object); + }); +} + +// Deep clones the given JSON object. +// +// `object` - The JSON object to clone. +// +// Returns a deep clone of the JSON object. +export function deepClone(object) { + if (_.isArray(object)) { + return object.map(value => deepClone(value)); + } else if (_.isObject(object) && !_.isFunction(object)) { + return mapObject(object, (key, value) => [key, deepClone(value)]); + } else { + return object; + } +} + +export function deepExtend(target) { + let result = target; + let i = 0; + while (++i < arguments.length) { + const object = arguments[i]; + if (isPlainObject(result) && isPlainObject(object)) { + for (let key of Array.from(Object.keys(object))) { + result[key] = deepExtend(result[key], object[key]); } + } else { + result = deepClone(object); } - return result; - }, + } + return result; +} - deepContains(array, target) { - if (array == null) { return false; } - for (let object of Array.from(array)) { - if (_.isEqual(object, target)) { return true; } - } - return false; - }, +export function deepContains(array, target) { + if (array == null) { return false; } + for (let object of Array.from(array)) { + if (_.isEqual(object, target)) { return true; } + } + return false; +} - endsWith(string, suffix) { - if (suffix == null) { suffix = ''; } - if (string) { - return string.indexOf(suffix, string.length - suffix.length) !== -1; - } else { - return false; - } - }, +export function endsWith(string, suffix) { + if (suffix == null) { suffix = ''; } + if (string) { + return string.indexOf(suffix, string.length - suffix.length) !== -1; + } else { + return false; + } +} - escapeAttribute(string) { - if (string) { - return string.replace(/"/g, '"').replace(/\n/g, '').replace(/\\/g, '-'); - } else { - return ''; - } - }, +export function escapeAttribute(string) { + if (string) { + return string.replace(/"/g, '"').replace(/\n/g, '').replace(/\\/g, '-'); + } else { + return ''; + } +} - escapeRegExp(string) { - if (string) { - return string.replace(/[-\/\\^$*+?.()|[\]{}]/g, '\\$&'); +export function escapeRegExp(string) { + if (string) { + return string.replace(/[-\/\\^$*+?.()|[\]{}]/g, '\\$&'); + } else { + return ''; + } +} + +export function humanizeEventName(eventName, eventDoc) { + const [namespace, event] = Array.from(eventName.split(':')); + if (event == null) { return undasherize(namespace); } + + const namespaceDoc = undasherize(namespace); + if (eventDoc == null) { eventDoc = undasherize(event); } + + return `${namespaceDoc}: ${eventDoc}`; +} + +export function humanizeKey(key, platform) { + if (platform == null) { ({ + platform + } = process); } + if (!key) { return key; } + + const modifierKeyMap = platform === 'darwin' ? macModifierKeyMap : nonMacModifierKeyMap; + + if (modifierKeyMap[key]) { + return modifierKeyMap[key]; + } else if ((key.length === 1) && (shiftKeyMap[key] != null)) { + return [modifierKeyMap.shift, shiftKeyMap[key]]; + } else if ((key.length === 1) && (key === key.toUpperCase()) && (key.toUpperCase() !== key.toLowerCase())) { + return [modifierKeyMap.shift, key.toUpperCase()]; + } else if ((key.length === 1) || /f[0-9]{1,2}/.test(key)) { + return key.toUpperCase(); + } else { + if (platform === 'darwin') { + return key; } else { - return ''; + return capitalize(key); } - }, - - humanizeEventName(eventName, eventDoc) { - const [namespace, event] = Array.from(eventName.split(':')); - if (event == null) { return plus.undasherize(namespace); } - - const namespaceDoc = plus.undasherize(namespace); - if (eventDoc == null) { eventDoc = plus.undasherize(event); } - - return `${namespaceDoc}: ${eventDoc}`; - }, - - humanizeKey(key, platform) { - if (platform == null) { ({ - platform - } = process); } - if (!key) { return key; } - - const modifierKeyMap = platform === 'darwin' ? macModifierKeyMap : nonMacModifierKeyMap; - - if (modifierKeyMap[key]) { - return modifierKeyMap[key]; - } else if ((key.length === 1) && (shiftKeyMap[key] != null)) { - return [modifierKeyMap.shift, shiftKeyMap[key]]; - } else if ((key.length === 1) && (key === key.toUpperCase()) && (key.toUpperCase() !== key.toLowerCase())) { - return [modifierKeyMap.shift, key.toUpperCase()]; - } else if ((key.length === 1) || /f[0-9]{1,2}/.test(key)) { - return key.toUpperCase(); - } else { - if (platform === 'darwin') { - return key; - } else { - return plus.capitalize(key); - } + } +} + +// Humanize the keystroke according to platform conventions. This method +// attempts to mirror the text the given keystroke would have if displayed in +// a system menu. +// +// keystroke - A String keystroke to humanize such as `ctrl-O`. +// platform - An optional String platform to humanize for (default: +// `process.platform`). +// +// Returns a humanized representation of the keystroke. +export function humanizeKeystroke(keystroke, platform) { + if (platform == null) { ({ + platform + } = process); } + if (!keystroke) { return keystroke; } + + const keystrokes = keystroke.split(' '); + const humanizedKeystrokes = []; + for (keystroke of Array.from(keystrokes)) { + let keys = []; + const splitKeystroke = keystroke.split('-'); + for (let index = 0; index < splitKeystroke.length; index++) { + // Check for consecutive dashes such as cmd-- + let key = splitKeystroke[index]; + if ((key === '') && (splitKeystroke[index-1] === '')) { key = '-'; } + if (key) { keys.push(humanizeKey(key, platform)); } } - }, - - // Humanize the keystroke according to platform conventions. This method - // attempts to mirror the text the given keystroke would have if displayed in - // a system menu. - // - // keystroke - A String keystroke to humanize such as `ctrl-O`. - // platform - An optional String platform to humanize for (default: - // `process.platform`). - // - // Returns a humanized representation of the keystroke. - humanizeKeystroke(keystroke, platform) { - if (platform == null) { ({ - platform - } = process); } - if (!keystroke) { return keystroke; } - - const keystrokes = keystroke.split(' '); - const humanizedKeystrokes = []; - for (keystroke of Array.from(keystrokes)) { - let keys = []; - const splitKeystroke = keystroke.split('-'); - for (let index = 0; index < splitKeystroke.length; index++) { - // Check for consecutive dashes such as cmd-- - let key = splitKeystroke[index]; - if ((key === '') && (splitKeystroke[index-1] === '')) { key = '-'; } - if (key) { keys.push(plus.humanizeKey(key, platform)); } - } - keys = _.uniq(_.flatten(keys)); - if (platform === 'darwin') { - keys = keys.join(''); - } else { - keys = keys.join('+'); - } - humanizedKeystrokes.push(keys); + keys = _.uniq(_.flatten(keys)); + if (platform === 'darwin') { + keys = keys.join(''); + } else { + keys = keys.join('+'); } + humanizedKeystrokes.push(keys); + } - return humanizedKeystrokes.join(' '); - }, + return humanizedKeystrokes.join(' '); +} - isSubset(potentialSubset, potentialSuperset) { - return _.every(potentialSubset, element => _.include(potentialSuperset, element)); - }, +export function isSubset(potentialSubset, potentialSuperset) { + return _.every(potentialSubset, element => _.include(potentialSuperset, element)); +} - losslessInvert(hash) { - const inverted = {}; - for (let key in hash) { - const value = hash[key]; - if (inverted[value] == null) { inverted[value] = []; } - inverted[value].push(key); - } - return inverted; - }, - - // Transform the given object into another object. - // - // `object` - The object to transform. - // `iterator` - - // A function that takes `(key, value)` arguments and returns a - // `[key, value]` tuple. - // - // Returns a new object based with the key/values returned by the iterator. - mapObject(object, iterator) { - const newObject = {}; - for (let key of Array.from(Object.keys(object))) { - let value; - [key, value] = Array.from(iterator(key, object[key])); - newObject[key] = value; - } +export function losslessInvert(hash) { + const inverted = {}; + for (let key in hash) { + const value = hash[key]; + if (inverted[value] == null) { inverted[value] = []; } + inverted[value].push(key); + } + return inverted; +} + +// Transform the given object into another object. +// +// `object` - The object to transform. +// `iterator` - +// A function that takes `(key, value)` arguments and returns a +// `[key, value]` tuple. +// +// Returns a new object based with the key/values returned by the iterator. +export function mapObject(object, iterator) { + const newObject = {}; + for (let key of Array.from(Object.keys(object))) { + let value; + [key, value] = Array.from(iterator(key, object[key])); + newObject[key] = value; + } - return newObject; - }, + return newObject; +} - multiplyString(string, n) { - let finalString = ""; - let i = 0; - while (i < n) { - finalString += string; - i++; - } - return finalString; - }, - - pluralize(count, singular, plural) { - if (count == null) { count = 0; } - if (plural == null) { plural = singular+'s'; } - if (count === 1) { - return `${count} ${singular}`; - } else { - return `${count} ${plural}`; - } - }, - - remove(array, element) { - const index = array.indexOf(element); - if (index >= 0) { array.splice(index, 1); } - return array; - }, - - setValueForKeyPath(object, keyPath, value) { - const keys = splitKeyPath(keyPath); - while (keys.length > 1) { - const key = keys.shift(); - if (object[key] == null) { object[key] = {}; } - object = object[key]; - } - if (value != null) { - return object[keys.shift()] = value; - } else { - return delete object[keys.shift()]; - } - }, +export function multiplyString(string, n) { + let finalString = ""; + let i = 0; + while (i < n) { + finalString += string; + i++; + } + return finalString; +} + +export function pluralize(count, singular, plural) { + if (count == null) { count = 0; } + if (plural == null) { plural = singular+'s'; } + if (count === 1) { + return `${count} ${singular}`; + } else { + return `${count} ${plural}`; + } +} + +export function remove(array, element) { + const index = array.indexOf(element); + if (index >= 0) { array.splice(index, 1); } + return array; +} + +export function setValueForKeyPath(object, keyPath, value) { + const keys = splitKeyPath(keyPath); + while (keys.length > 1) { + const key = keys.shift(); + if (object[key] == null) { object[key] = {}; } + object = object[key]; + } + if (value != null) { + return object[keys.shift()] = value; + } else { + return delete object[keys.shift()]; + } +} - hasKeyPath(object, keyPath) { - const keys = splitKeyPath(keyPath); - for (let key of Array.from(keys)) { - if (!object.hasOwnProperty(key)) { return false; } - object = object[key]; - } - return true; - }, +export function hasKeyPath(object, keyPath) { + const keys = splitKeyPath(keyPath); + for (let key of Array.from(keys)) { + if (!object.hasOwnProperty(key)) { return false; } + object = object[key]; + } + return true; +} - spliceWithArray(originalArray, start, length, insertedArray, chunkSize) { - if (chunkSize == null) { chunkSize = 100000; } - if (insertedArray.length < chunkSize) { - return originalArray.splice(start, length, ...Array.from(insertedArray)); - } else { - originalArray.splice(start, length); - return (() => { - const result = []; - for (let chunkStart = 0, end = insertedArray.length, step = chunkSize, asc = step > 0; asc ? chunkStart <= end : chunkStart >= end; chunkStart += step) { - result.push(originalArray.splice(start + chunkStart, 0, ...Array.from(insertedArray.slice(chunkStart, chunkStart + chunkSize)))); - } - return result; - })(); - } - }, +export function spliceWithArray(originalArray, start, length, insertedArray, chunkSize) { + if (chunkSize == null) { chunkSize = 100000; } + if (insertedArray.length < chunkSize) { + return originalArray.splice(start, length, ...Array.from(insertedArray)); + } else { + originalArray.splice(start, length); + return (() => { + const result = []; + for (let chunkStart = 0, end = insertedArray.length, step = chunkSize, asc = step > 0; asc ? chunkStart <= end : chunkStart >= end; chunkStart += step) { + result.push(originalArray.splice(start + chunkStart, 0, ...Array.from(insertedArray.slice(chunkStart, chunkStart + chunkSize)))); + } + return result; + })(); + } +} - sum(array) { - let sum = 0; - for (let elt of Array.from(array)) { sum += elt; } - return sum; - }, +export function sum(array) { + let sum = 0; + for (let elt of Array.from(array)) { sum += elt; } + return sum; +} - uncamelcase(string) { - if (!string) { return ''; } +export function uncamelcase(string) { + if (!string) { return ''; } - const result = string.replace(/([A-Z])|_+/g, function(match, letter) { if (letter == null) { letter = ''; } return ` ${letter}`; }); - return plus.capitalize(result.trim()); - }, + const result = string.replace(/([A-Z])|_+/g, function(match, letter) { if (letter == null) { letter = ''; } return ` ${letter}`; }); + return capitalize(result.trim()); +} - undasherize(string) { - if (string) { - return string.split('-').map(plus.capitalize).join(' '); - } else { - return ''; - } - }, +export function undasherize(string) { + if (string) { + return string.split('-').map(capitalize).join(' '); + } else { + return ''; + } +} - underscore(string) { - if (!string) { return ''; } +export function underscore(string) { + if (!string) { return ''; } - string = string[0].toLowerCase() + string.slice(1); - return string.replace(/([A-Z])|-+/g, function(match, letter) { if (letter == null) { letter = ''; } return `_${letter.toLowerCase()}`; }); - }, + string = string[0].toLowerCase() + string.slice(1); + return string.replace(/([A-Z])|-+/g, function(match, letter) { if (letter == null) { letter = ''; } return `_${letter.toLowerCase()}`; }); +} - valueForKeyPath(object, keyPath) { - const keys = splitKeyPath(keyPath); - for (let key of Array.from(keys)) { - object = object[key]; - if (object == null) { return; } - } - return object; - }, +export function valueForKeyPath(object, keyPath) { + const keys = splitKeyPath(keyPath); + for (let key of Array.from(keys)) { + object = object[key]; + if (object == null) { return; } + } + return object; +} - isEqual(a, b, aStack, bStack) { - if (_.isArray(aStack) && _.isArray(bStack)) { - return isEqual(a, b, aStack, bStack); - } else { - return isEqual(a, b); - } - }, +export function isEqual(a, b, aStack, bStack) { + if (_.isArray(aStack) && _.isArray(bStack)) { + return isEqual(a, b, aStack, bStack); + } else { + return isEqual(a, b); + } +} - isEqualForProperties(a, b, ...properties) { - for (let property of Array.from(properties)) { - if (!_.isEqual(a[property], b[property])) { return false; } - } - return true; +export function isEqualForProperties(a, b, ...properties) { + for (let property of Array.from(properties)) { + if (!_.isEqual(a[property], b[property])) { return false; } } -}; + return true; +} -var isEqual = function(a, b, aStack, bStack) { +isEqual = function(a, b, aStack, bStack) { if (aStack == null) { aStack = []; } if (bStack == null) { bStack = []; } if (a === b) { return _.isEqual(a, b); } @@ -474,6 +473,4 @@ var isEqual = function(a, b, aStack, bStack) { aStack.pop(); bStack.pop(); return equal; -}; - -module.exports = _.extend({}, _, plus); +}; \ No newline at end of file From bf2f536e2d8528c3f5cde9aa3ce449265b2ad02d Mon Sep 17 00:00:00 2001 From: Amin Yahyaabadi Date: Sat, 4 Jul 2020 06:25:12 -0500 Subject: [PATCH 09/35] named import needed functions from "underscore" --- src/underscore-plus.mjs | 50 +++++++++++++++++++++-------------------- 1 file changed, 26 insertions(+), 24 deletions(-) diff --git a/src/underscore-plus.mjs b/src/underscore-plus.mjs index 3744d7e..85a00eb 100644 --- a/src/underscore-plus.mjs +++ b/src/underscore-plus.mjs @@ -8,7 +8,9 @@ * Full docs: https://github.com/decaffeinate/decaffeinate/blob/master/docs/suggestions.md */ export * from 'underscore' -import * as _ from 'underscore' + +// import * as _ from 'underscore' // if we needed all +import {every, flatten, has, include, isArray, isElement, isFunction, isObject, isRegExp, uniq} from "underscore"; const macModifierKeyMap = { cmd: '\u2318', @@ -67,7 +69,7 @@ const splitKeyPath = function(keyPath) { return keyPathArray; }; -const isPlainObject = value => _.isObject(value) && !_.isArray(value); +const isPlainObject = value => isObject(value) && !isArray(value); export function adviseBefore(object, methodName, advice) { const original = object[methodName]; @@ -124,9 +126,9 @@ export function dasherize(string) { // // Returns a deep clone of the JSON object. export function deepClone(object) { - if (_.isArray(object)) { + if (isArray(object)) { return object.map(value => deepClone(value)); - } else if (_.isObject(object) && !_.isFunction(object)) { + } else if (isObject(object) && !isFunction(object)) { return mapObject(object, (key, value) => [key, deepClone(value)]); } else { return object; @@ -152,7 +154,7 @@ export function deepExtend(target) { export function deepContains(array, target) { if (array == null) { return false; } for (let object of Array.from(array)) { - if (_.isEqual(object, target)) { return true; } + if (isEqual(object, target)) { return true; } } return false; } @@ -244,7 +246,7 @@ export function humanizeKeystroke(keystroke, platform) { if (key) { keys.push(humanizeKey(key, platform)); } } - keys = _.uniq(_.flatten(keys)); + keys = uniq(flatten(keys)); if (platform === 'darwin') { keys = keys.join(''); } else { @@ -257,7 +259,7 @@ export function humanizeKeystroke(keystroke, platform) { } export function isSubset(potentialSubset, potentialSuperset) { - return _.every(potentialSubset, element => _.include(potentialSuperset, element)); + return every(potentialSubset, element => include(potentialSuperset, element)); } export function losslessInvert(hash) { @@ -392,7 +394,7 @@ export function valueForKeyPath(object, keyPath) { } export function isEqual(a, b, aStack, bStack) { - if (_.isArray(aStack) && _.isArray(bStack)) { + if (isArray(aStack) && isArray(bStack)) { return isEqual(a, b, aStack, bStack); } else { return isEqual(a, b); @@ -401,7 +403,7 @@ export function isEqual(a, b, aStack, bStack) { export function isEqualForProperties(a, b, ...properties) { for (let property of Array.from(properties)) { - if (!_.isEqual(a[property], b[property])) { return false; } + if (!isEqual(a[property], b[property])) { return false; } } return true; } @@ -409,8 +411,8 @@ export function isEqualForProperties(a, b, ...properties) { isEqual = function(a, b, aStack, bStack) { if (aStack == null) { aStack = []; } if (bStack == null) { bStack = []; } - if (a === b) { return _.isEqual(a, b); } - if (_.isFunction(a) || _.isFunction(b)) { return _.isEqual(a, b); } + if (a === b) { return isEqual(a, b); } + if (isFunction(a) || isFunction(b)) { return isEqual(a, b); } let stackIndex = aStack.length; while (stackIndex--) { @@ -420,11 +422,11 @@ isEqual = function(a, b, aStack, bStack) { bStack.push(b); let equal = false; - if (_.isFunction(a?.isEqual)) { + if (isFunction(a?.isEqual)) { equal = a.isEqual(b, aStack, bStack); - } else if (_.isFunction(b?.isEqual)) { + } else if (isFunction(b?.isEqual)) { equal = b.isEqual(a, bStack, aStack); - } else if (_.isArray(a) && _.isArray(b) && (a.length === b.length)) { + } else if (isArray(a) && isArray(b) && (a.length === b.length)) { equal = true; for (let i = 0; i < a.length; i++) { const aElement = a[i]; @@ -433,15 +435,15 @@ isEqual = function(a, b, aStack, bStack) { break; } } - } else if (_.isRegExp(a) && _.isRegExp(b)) { - equal = _.isEqual(a, b); - } else if (_.isElement(a) && _.isElement(b)) { + } else if (isRegExp(a) && isRegExp(b)) { + equal = isEqual(a, b); + } else if (isElement(a) && isElement(b)) { equal = a === b; - } else if (_.isObject(a) && _.isObject(b)) { + } else if (isObject(a) && isObject(b)) { const aCtor = a.constructor; const bCtor = b.constructor; - const aCtorValid = _.isFunction(aCtor) && aCtor instanceof aCtor; - const bCtorValid = _.isFunction(bCtor) && bCtor instanceof bCtor; + const aCtorValid = isFunction(aCtor) && aCtor instanceof aCtor; + const bCtorValid = isFunction(bCtor) && bCtor instanceof bCtor; if ((aCtor !== bCtor) && !(aCtorValid && bCtorValid)) { equal = false; } else { @@ -450,9 +452,9 @@ isEqual = function(a, b, aStack, bStack) { equal = true; for (key in a) { const aValue = a[key]; - if (!_.has(a, key)) { continue; } + if (!has(a, key)) { continue; } aKeyCount++; - if (!_.has(b, key) || !isEqual(aValue, b[key], aStack, bStack)) { + if (!has(b, key) || !isEqual(aValue, b[key], aStack, bStack)) { equal = false; break; } @@ -461,13 +463,13 @@ isEqual = function(a, b, aStack, bStack) { let bKeyCount = 0; for (key in b) { const bValue = b[key]; - if (_.has(b, key)) { bKeyCount++; } + if (has(b, key)) { bKeyCount++; } } equal = aKeyCount === bKeyCount; } } } else { - equal = _.isEqual(a, b); + equal = isEqual(a, b); } aStack.pop(); From dce9ab51060c06e32949bafac772f429bacb583a Mon Sep 17 00:00:00 2001 From: Amin Yahyaabadi Date: Sat, 4 Jul 2020 06:34:52 -0500 Subject: [PATCH 10/35] isEqual move default values to function head --- src/underscore-plus.mjs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/underscore-plus.mjs b/src/underscore-plus.mjs index 85a00eb..3216e64 100644 --- a/src/underscore-plus.mjs +++ b/src/underscore-plus.mjs @@ -408,9 +408,7 @@ export function isEqualForProperties(a, b, ...properties) { return true; } -isEqual = function(a, b, aStack, bStack) { - if (aStack == null) { aStack = []; } - if (bStack == null) { bStack = []; } +isEqual = function(a, b, aStack=[], bStack=[]) { if (a === b) { return isEqual(a, b); } if (isFunction(a) || isFunction(b)) { return isEqual(a, b); } From 1c031eaa293297e5fcc0ffacb0de03495391c675 Mon Sep 17 00:00:00 2001 From: Amin Yahyaabadi Date: Sat, 4 Jul 2020 06:54:56 -0500 Subject: [PATCH 11/35] use different names for isEqual functions to avoid confusion --- src/underscore-plus.mjs | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/src/underscore-plus.mjs b/src/underscore-plus.mjs index 3216e64..1b2ac12 100644 --- a/src/underscore-plus.mjs +++ b/src/underscore-plus.mjs @@ -10,7 +10,7 @@ export * from 'underscore' // import * as _ from 'underscore' // if we needed all -import {every, flatten, has, include, isArray, isElement, isFunction, isObject, isRegExp, uniq} from "underscore"; +import {every, flatten, has, include, isArray, isElement, isEqual as _isEqual, isFunction, isObject, isRegExp, uniq} from "underscore"; const macModifierKeyMap = { cmd: '\u2318', @@ -154,7 +154,7 @@ export function deepExtend(target) { export function deepContains(array, target) { if (array == null) { return false; } for (let object of Array.from(array)) { - if (isEqual(object, target)) { return true; } + if (_isEqual(object, target)) { return true; } } return false; } @@ -395,22 +395,22 @@ export function valueForKeyPath(object, keyPath) { export function isEqual(a, b, aStack, bStack) { if (isArray(aStack) && isArray(bStack)) { - return isEqual(a, b, aStack, bStack); + return isEqual_(a, b, aStack, bStack); } else { - return isEqual(a, b); + return isEqual_(a, b); } } export function isEqualForProperties(a, b, ...properties) { for (let property of Array.from(properties)) { - if (!isEqual(a[property], b[property])) { return false; } + if (!_isEqual(a[property], b[property])) { return false; } } return true; } -isEqual = function(a, b, aStack=[], bStack=[]) { - if (a === b) { return isEqual(a, b); } - if (isFunction(a) || isFunction(b)) { return isEqual(a, b); } +function isEqual_(a, b, aStack=[], bStack=[]) { + if (a === b) { return _isEqual(a, b); } + if (isFunction(a) || isFunction(b)) { return _isEqual(a, b); } let stackIndex = aStack.length; while (stackIndex--) { @@ -428,13 +428,13 @@ isEqual = function(a, b, aStack=[], bStack=[]) { equal = true; for (let i = 0; i < a.length; i++) { const aElement = a[i]; - if (!isEqual(aElement, b[i], aStack, bStack)) { + if (!isEqual_(aElement, b[i], aStack, bStack)) { equal = false; break; } } } else if (isRegExp(a) && isRegExp(b)) { - equal = isEqual(a, b); + equal = _isEqual(a, b); } else if (isElement(a) && isElement(b)) { equal = a === b; } else if (isObject(a) && isObject(b)) { @@ -452,7 +452,7 @@ isEqual = function(a, b, aStack=[], bStack=[]) { const aValue = a[key]; if (!has(a, key)) { continue; } aKeyCount++; - if (!has(b, key) || !isEqual(aValue, b[key], aStack, bStack)) { + if (!has(b, key) || !isEqual_(aValue, b[key], aStack, bStack)) { equal = false; break; } @@ -467,10 +467,10 @@ isEqual = function(a, b, aStack=[], bStack=[]) { } } } else { - equal = isEqual(a, b); + equal = _isEqual(a, b); } aStack.pop(); bStack.pop(); return equal; -}; \ No newline at end of file +} \ No newline at end of file From 2eb691efaa339c30c831cc16ccf07c72eab34ea8 Mon Sep 17 00:00:00 2001 From: Amin Yahyaabadi Date: Sat, 4 Jul 2020 06:38:29 -0500 Subject: [PATCH 12/35] make splitKeyPath directly a function --- src/underscore-plus.mjs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/underscore-plus.mjs b/src/underscore-plus.mjs index 1b2ac12..b9ec4a2 100644 --- a/src/underscore-plus.mjs +++ b/src/underscore-plus.mjs @@ -54,7 +54,7 @@ const shiftKeyMap = { '?': '/' }; -const splitKeyPath = function(keyPath) { +function splitKeyPath(keyPath) { let startIndex = 0; const keyPathArray = []; if (keyPath == null) { return keyPathArray; } From b849fdf3c668678504617e534d51834a43d5d413 Mon Sep 17 00:00:00 2001 From: Amin Yahyaabadi Date: Sat, 4 Jul 2020 07:22:45 -0500 Subject: [PATCH 13/35] deepExtend keys is array --- src/underscore-plus.mjs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/underscore-plus.mjs b/src/underscore-plus.mjs index b9ec4a2..24bed15 100644 --- a/src/underscore-plus.mjs +++ b/src/underscore-plus.mjs @@ -67,7 +67,7 @@ function splitKeyPath(keyPath) { } keyPathArray.push(keyPath.substr(startIndex, keyPath.length)); return keyPathArray; -}; +} const isPlainObject = value => isObject(value) && !isArray(value); @@ -141,7 +141,8 @@ export function deepExtend(target) { while (++i < arguments.length) { const object = arguments[i]; if (isPlainObject(result) && isPlainObject(object)) { - for (let key of Array.from(Object.keys(object))) { + const keys = Object.keys(object) + for (let key of keys) { result[key] = deepExtend(result[key], object[key]); } } else { From 0942b4f2dc5b3407c0766a2ef5d88b35a105dada Mon Sep 17 00:00:00 2001 From: Amin Yahyaabadi Date: Sat, 4 Jul 2020 07:23:38 -0500 Subject: [PATCH 14/35] deepContains unnecessary Array.from --- src/underscore-plus.mjs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/underscore-plus.mjs b/src/underscore-plus.mjs index 24bed15..10e9093 100644 --- a/src/underscore-plus.mjs +++ b/src/underscore-plus.mjs @@ -154,7 +154,7 @@ export function deepExtend(target) { export function deepContains(array, target) { if (array == null) { return false; } - for (let object of Array.from(array)) { + for (let object of array) { if (_isEqual(object, target)) { return true; } } return false; From 924a59001b23f8a69e9ab74903e4d4e5042081fa Mon Sep 17 00:00:00 2001 From: Amin Yahyaabadi Date: Sat, 4 Jul 2020 07:25:15 -0500 Subject: [PATCH 15/35] humanizeEventName unnecessary Array.from --- src/underscore-plus.mjs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/underscore-plus.mjs b/src/underscore-plus.mjs index 10e9093..85b2a17 100644 --- a/src/underscore-plus.mjs +++ b/src/underscore-plus.mjs @@ -186,7 +186,7 @@ export function escapeRegExp(string) { } export function humanizeEventName(eventName, eventDoc) { - const [namespace, event] = Array.from(eventName.split(':')); + const [namespace, event] = eventName.split(':'); if (event == null) { return undasherize(namespace); } const namespaceDoc = undasherize(namespace); From c8d700a5ae020154cafd511d5db586bb1e91d124 Mon Sep 17 00:00:00 2001 From: Amin Yahyaabadi Date: Sat, 4 Jul 2020 07:27:59 -0500 Subject: [PATCH 16/35] humanizeKeystroke unnecessary Array.from --- src/underscore-plus.mjs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/underscore-plus.mjs b/src/underscore-plus.mjs index 85b2a17..0ab5ef3 100644 --- a/src/underscore-plus.mjs +++ b/src/underscore-plus.mjs @@ -237,7 +237,7 @@ export function humanizeKeystroke(keystroke, platform) { const keystrokes = keystroke.split(' '); const humanizedKeystrokes = []; - for (keystroke of Array.from(keystrokes)) { + for (keystroke of keystrokes) { let keys = []; const splitKeystroke = keystroke.split('-'); for (let index = 0; index < splitKeystroke.length; index++) { From 1adcb13008266e6c83b9ebec6b1ac6f6f5cbeb6a Mon Sep 17 00:00:00 2001 From: Amin Yahyaabadi Date: Sat, 4 Jul 2020 07:30:17 -0500 Subject: [PATCH 17/35] mapObject keys is an array + unncessary Array.from --- src/underscore-plus.mjs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/underscore-plus.mjs b/src/underscore-plus.mjs index 0ab5ef3..6cd8180 100644 --- a/src/underscore-plus.mjs +++ b/src/underscore-plus.mjs @@ -283,9 +283,10 @@ export function losslessInvert(hash) { // Returns a new object based with the key/values returned by the iterator. export function mapObject(object, iterator) { const newObject = {}; - for (let key of Array.from(Object.keys(object))) { + const keys = Object.keys(object) + for (let key of keys) { let value; - [key, value] = Array.from(iterator(key, object[key])); + [key, value] = iterator(key, object[key]); newObject[key] = value; } From b254c56c78c3bd8f76d9a2cc593a7e567a6605e3 Mon Sep 17 00:00:00 2001 From: Amin Yahyaabadi Date: Sat, 4 Jul 2020 07:31:18 -0500 Subject: [PATCH 18/35] setValueForKeyPath excess return --- src/underscore-plus.mjs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/underscore-plus.mjs b/src/underscore-plus.mjs index 6cd8180..e52ed07 100644 --- a/src/underscore-plus.mjs +++ b/src/underscore-plus.mjs @@ -327,9 +327,9 @@ export function setValueForKeyPath(object, keyPath, value) { object = object[key]; } if (value != null) { - return object[keys.shift()] = value; + object[keys.shift()] = value; } else { - return delete object[keys.shift()]; + delete object[keys.shift()]; } } From 47df0ed5de5c47b1fbebaac348a3b56aa6763580 Mon Sep 17 00:00:00 2001 From: Amin Yahyaabadi Date: Sat, 4 Jul 2020 07:32:14 -0500 Subject: [PATCH 19/35] hasKeyPath unncessary Array.from --- src/underscore-plus.mjs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/underscore-plus.mjs b/src/underscore-plus.mjs index e52ed07..484e47d 100644 --- a/src/underscore-plus.mjs +++ b/src/underscore-plus.mjs @@ -335,7 +335,7 @@ export function setValueForKeyPath(object, keyPath, value) { export function hasKeyPath(object, keyPath) { const keys = splitKeyPath(keyPath); - for (let key of Array.from(keys)) { + for (let key of keys) { if (!object.hasOwnProperty(key)) { return false; } object = object[key]; } From 39ad1b30889673fed82f410544151877927db54a Mon Sep 17 00:00:00 2001 From: Amin Yahyaabadi Date: Sat, 4 Jul 2020 07:33:20 -0500 Subject: [PATCH 20/35] spliceWithArray unncessary Array.from --- src/underscore-plus.mjs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/underscore-plus.mjs b/src/underscore-plus.mjs index 484e47d..d0368f6 100644 --- a/src/underscore-plus.mjs +++ b/src/underscore-plus.mjs @@ -345,13 +345,13 @@ export function hasKeyPath(object, keyPath) { export function spliceWithArray(originalArray, start, length, insertedArray, chunkSize) { if (chunkSize == null) { chunkSize = 100000; } if (insertedArray.length < chunkSize) { - return originalArray.splice(start, length, ...Array.from(insertedArray)); + return originalArray.splice(start, length, ...insertedArray); } else { originalArray.splice(start, length); return (() => { const result = []; for (let chunkStart = 0, end = insertedArray.length, step = chunkSize, asc = step > 0; asc ? chunkStart <= end : chunkStart >= end; chunkStart += step) { - result.push(originalArray.splice(start + chunkStart, 0, ...Array.from(insertedArray.slice(chunkStart, chunkStart + chunkSize)))); + result.push(originalArray.splice(start + chunkStart, 0, ...insertedArray.slice(chunkStart, chunkStart + chunkSize))); } return result; })(); From bd7352feb64c24e90b739901f810a9a3597b1688 Mon Sep 17 00:00:00 2001 From: Amin Yahyaabadi Date: Sat, 4 Jul 2020 07:35:39 -0500 Subject: [PATCH 21/35] spliceWithArray excess return --- src/underscore-plus.mjs | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/src/underscore-plus.mjs b/src/underscore-plus.mjs index d0368f6..2e6219c 100644 --- a/src/underscore-plus.mjs +++ b/src/underscore-plus.mjs @@ -345,16 +345,12 @@ export function hasKeyPath(object, keyPath) { export function spliceWithArray(originalArray, start, length, insertedArray, chunkSize) { if (chunkSize == null) { chunkSize = 100000; } if (insertedArray.length < chunkSize) { - return originalArray.splice(start, length, ...insertedArray); + originalArray.splice(start, length, ...insertedArray); } else { - originalArray.splice(start, length); - return (() => { - const result = []; + originalArray.splice(start, length); for (let chunkStart = 0, end = insertedArray.length, step = chunkSize, asc = step > 0; asc ? chunkStart <= end : chunkStart >= end; chunkStart += step) { - result.push(originalArray.splice(start + chunkStart, 0, ...insertedArray.slice(chunkStart, chunkStart + chunkSize))); + originalArray.splice(start + chunkStart, 0, ...insertedArray.slice(chunkStart, chunkStart + chunkSize)); } - return result; - })(); } } From 43ff2ab4ab65749fc5d8a1288aec507fcdb52a24 Mon Sep 17 00:00:00 2001 From: Amin Yahyaabadi Date: Sat, 4 Jul 2020 08:37:09 -0500 Subject: [PATCH 22/35] spliceWithArray loop simplification --- src/underscore-plus.mjs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/underscore-plus.mjs b/src/underscore-plus.mjs index 2e6219c..aa8e821 100644 --- a/src/underscore-plus.mjs +++ b/src/underscore-plus.mjs @@ -348,7 +348,7 @@ export function spliceWithArray(originalArray, start, length, insertedArray, chu originalArray.splice(start, length, ...insertedArray); } else { originalArray.splice(start, length); - for (let chunkStart = 0, end = insertedArray.length, step = chunkSize, asc = step > 0; asc ? chunkStart <= end : chunkStart >= end; chunkStart += step) { + for (let chunkStart = 0, end = insertedArray.length; chunkStart <= end; chunkStart += chunkSize) { originalArray.splice(start + chunkStart, 0, ...insertedArray.slice(chunkStart, chunkStart + chunkSize)); } } From ee5116335071eef6cf11a7c4e595a40baa359fff Mon Sep 17 00:00:00 2001 From: Amin Yahyaabadi Date: Sat, 4 Jul 2020 07:39:08 -0500 Subject: [PATCH 23/35] sum unncessary Array.from --- src/underscore-plus.mjs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/underscore-plus.mjs b/src/underscore-plus.mjs index aa8e821..c9a35a5 100644 --- a/src/underscore-plus.mjs +++ b/src/underscore-plus.mjs @@ -356,7 +356,7 @@ export function spliceWithArray(originalArray, start, length, insertedArray, chu export function sum(array) { let sum = 0; - for (let elt of Array.from(array)) { sum += elt; } + for (let elt of array) { sum += elt; } return sum; } From d318b31ede55aadcffceea40dc8d7c67e5981d94 Mon Sep 17 00:00:00 2001 From: Amin Yahyaabadi Date: Sat, 4 Jul 2020 07:42:00 -0500 Subject: [PATCH 24/35] uncamelcase use => --- src/underscore-plus.mjs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/underscore-plus.mjs b/src/underscore-plus.mjs index c9a35a5..d3f1e0a 100644 --- a/src/underscore-plus.mjs +++ b/src/underscore-plus.mjs @@ -363,7 +363,7 @@ export function sum(array) { export function uncamelcase(string) { if (!string) { return ''; } - const result = string.replace(/([A-Z])|_+/g, function(match, letter) { if (letter == null) { letter = ''; } return ` ${letter}`; }); + const result = string.replace(/([A-Z])|_+/g, (match, letter='') => ` ${letter}`); return capitalize(result.trim()); } From 39c6fdb16a991f4cf00d3f8f32087dede6450c05 Mon Sep 17 00:00:00 2001 From: Amin Yahyaabadi Date: Sat, 4 Jul 2020 07:42:12 -0500 Subject: [PATCH 25/35] underscore use => --- src/underscore-plus.mjs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/underscore-plus.mjs b/src/underscore-plus.mjs index d3f1e0a..469f1f3 100644 --- a/src/underscore-plus.mjs +++ b/src/underscore-plus.mjs @@ -379,7 +379,7 @@ export function underscore(string) { if (!string) { return ''; } string = string[0].toLowerCase() + string.slice(1); - return string.replace(/([A-Z])|-+/g, function(match, letter) { if (letter == null) { letter = ''; } return `_${letter.toLowerCase()}`; }); + return string.replace(/([A-Z])|-+/g, (match, letter='') => `_${letter.toLowerCase()}`); } export function valueForKeyPath(object, keyPath) { From 3b0388f410465948de93ceb33b2bd95279119c1e Mon Sep 17 00:00:00 2001 From: Amin Yahyaabadi Date: Sat, 4 Jul 2020 07:42:33 -0500 Subject: [PATCH 26/35] valueForKeyPath unncessary Array.from --- src/underscore-plus.mjs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/underscore-plus.mjs b/src/underscore-plus.mjs index 469f1f3..67abbe1 100644 --- a/src/underscore-plus.mjs +++ b/src/underscore-plus.mjs @@ -384,7 +384,7 @@ export function underscore(string) { export function valueForKeyPath(object, keyPath) { const keys = splitKeyPath(keyPath); - for (let key of Array.from(keys)) { + for (let key of keys) { object = object[key]; if (object == null) { return; } } From 8b5cf09d0c5d4a2cb996ae74123bd7c0d0101fdd Mon Sep 17 00:00:00 2001 From: Amin Yahyaabadi Date: Sat, 4 Jul 2020 07:52:22 -0500 Subject: [PATCH 27/35] humanizeKey default values in function head --- src/underscore-plus.mjs | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/src/underscore-plus.mjs b/src/underscore-plus.mjs index 67abbe1..c727ff9 100644 --- a/src/underscore-plus.mjs +++ b/src/underscore-plus.mjs @@ -195,10 +195,7 @@ export function humanizeEventName(eventName, eventDoc) { return `${namespaceDoc}: ${eventDoc}`; } -export function humanizeKey(key, platform) { - if (platform == null) { ({ - platform - } = process); } +export function humanizeKey(key, platform=process.platform) { if (!key) { return key; } const modifierKeyMap = platform === 'darwin' ? macModifierKeyMap : nonMacModifierKeyMap; From 8577c7b8ee622aebabb7ec96f2f1ea3193bcc41d Mon Sep 17 00:00:00 2001 From: Amin Yahyaabadi Date: Sat, 4 Jul 2020 07:52:54 -0500 Subject: [PATCH 28/35] humanizeKeystroke default value in function head --- src/underscore-plus.mjs | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/src/underscore-plus.mjs b/src/underscore-plus.mjs index c727ff9..1128d8c 100644 --- a/src/underscore-plus.mjs +++ b/src/underscore-plus.mjs @@ -226,11 +226,8 @@ export function humanizeKey(key, platform=process.platform) { // `process.platform`). // // Returns a humanized representation of the keystroke. -export function humanizeKeystroke(keystroke, platform) { - if (platform == null) { ({ - platform - } = process); } - if (!keystroke) { return keystroke; } +export function humanizeKeystroke(keystroke, platform=process.platform) { + if (!keystroke) { return keystroke; } const keystrokes = keystroke.split(' '); const humanizedKeystrokes = []; From 0eb5a4b204af859043d1341febc84321f47e1bb0 Mon Sep 17 00:00:00 2001 From: Amin Yahyaabadi Date: Sat, 4 Jul 2020 07:53:47 -0500 Subject: [PATCH 29/35] pluralize default value in function head --- src/underscore-plus.mjs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/underscore-plus.mjs b/src/underscore-plus.mjs index 1128d8c..a9275a0 100644 --- a/src/underscore-plus.mjs +++ b/src/underscore-plus.mjs @@ -297,9 +297,7 @@ export function multiplyString(string, n) { return finalString; } -export function pluralize(count, singular, plural) { - if (count == null) { count = 0; } - if (plural == null) { plural = singular+'s'; } +export function pluralize(count=0, singular, plural=singular+'s') { if (count === 1) { return `${count} ${singular}`; } else { From e6b626796c129045b06228cf99c6dfc7dda9826f Mon Sep 17 00:00:00 2001 From: Amin Yahyaabadi Date: Sat, 4 Jul 2020 07:54:34 -0500 Subject: [PATCH 30/35] spliceWithArray default value in function head --- src/underscore-plus.mjs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/underscore-plus.mjs b/src/underscore-plus.mjs index a9275a0..46b90d9 100644 --- a/src/underscore-plus.mjs +++ b/src/underscore-plus.mjs @@ -334,8 +334,7 @@ export function hasKeyPath(object, keyPath) { return true; } -export function spliceWithArray(originalArray, start, length, insertedArray, chunkSize) { - if (chunkSize == null) { chunkSize = 100000; } +export function spliceWithArray(originalArray, start, length, insertedArray, chunkSize=100000) { if (insertedArray.length < chunkSize) { originalArray.splice(start, length, ...insertedArray); } else { From 2ec24fb8334c376595da3ed393a163078468edbe Mon Sep 17 00:00:00 2001 From: Amin Yahyaabadi Date: Sat, 4 Jul 2020 07:57:29 -0500 Subject: [PATCH 31/35] remove addressed suggestions --- src/underscore-plus.mjs | 15 +++++---------- 1 file changed, 5 insertions(+), 10 deletions(-) diff --git a/src/underscore-plus.mjs b/src/underscore-plus.mjs index 46b90d9..edc73c6 100644 --- a/src/underscore-plus.mjs +++ b/src/underscore-plus.mjs @@ -1,12 +1,3 @@ -/* - * decaffeinate suggestions: - * DS101: Remove unnecessary use of Array.from - * DS102: Remove unnecessary code created because of implicit returns - * DS202: Simplify dynamic range loops - * DS205: Consider reworking code to avoid use of IIFEs - * DS207: Consider shorter variations of null checks - * Full docs: https://github.com/decaffeinate/decaffeinate/blob/master/docs/suggestions.md - */ export * from 'underscore' // import * as _ from 'underscore' // if we needed all @@ -391,6 +382,7 @@ export function isEqual(a, b, aStack, bStack) { } export function isEqualForProperties(a, b, ...properties) { + // TODO is Array.from needed? for (let property of Array.from(properties)) { if (!_isEqual(a[property], b[property])) { return false; } } @@ -462,4 +454,7 @@ function isEqual_(a, b, aStack=[], bStack=[]) { aStack.pop(); bStack.pop(); return equal; -} \ No newline at end of file +} + +// TODO: Consider shorter variations of null checks: +// https://github.com/decaffeinate/decaffeinate/blob/master/docs/suggestions.md#ds207-consider-shorter-variations-of-null-checks From dff4b83017462042a5a1fbee7dacf99c3910996e Mon Sep 17 00:00:00 2001 From: Amin Yahyaabadi Date: Sat, 4 Jul 2020 09:05:23 -0500 Subject: [PATCH 32/35] more node versions in travis and appveyor --- .travis.yml | 4 +++- appveyor.yml | 7 +++++-- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/.travis.yml b/.travis.yml index 239240b..0922f09 100644 --- a/.travis.yml +++ b/.travis.yml @@ -6,4 +6,6 @@ notifications: on_failure: change node_js: - - 8 + - 14 + - 12 + - 10 diff --git a/appveyor.yml b/appveyor.yml index ebd3e68..ab37c36 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -1,7 +1,10 @@ -image: Visual Studio 2015 +image: Visual Studio 2017 environment: - nodejs_version: "6" + nodejs_version: + - 10 + - 12 + - 14 platform: - x86 From ba3ba505b291f5d008a42816afb1c25a13f87dc8 Mon Sep 17 00:00:00 2001 From: aminya Date: Sat, 11 Jul 2020 05:07:04 -0500 Subject: [PATCH 33/35] using cross-env --- package.json | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/package.json b/package.json index 8c2b74e..4754de1 100644 --- a/package.json +++ b/package.json @@ -13,10 +13,10 @@ "clean": "shx rm -rf lib", "test": "jasmine-focused --captureExceptions --coffee spec", "lint": "coffeelint spec/*.coffee", - "babel": "npm run clean && shx cp -r src lib && env NODE_ENV=development env BABEL_ENV=development babel lib --out-dir lib && shx cp lib/* dist", + "bower": "shx cp lib/* dist", + "babel": "npm run clean && shx cp -r src lib && cross-env NODE_ENV=development cross-env BABEL_ENV=development babel lib --out-dir lib", "build": "npm run babel", - "prepare": "npm run build", - "prepublish": "npm run clean && npm run build" + "prepare": "npm run clean && npm run build && npm run bower" }, "repository": { "type": "git", @@ -41,7 +41,8 @@ "@babel/plugin-proposal-nullish-coalescing-operator": "^7.10.4", "@babel/plugin-proposal-optional-chaining": "^7.10.4", "@babel/plugin-transform-modules-commonjs": "^7.10.4", - "shx": "^0.3.2" + "shx": "^0.3.2", + "cross-env": "^7.0.2" }, "coffeelintConfig": { "no_empty_param_list": { From 9e00efd7e221a7db68f7764f7fc34594d51ff9b5 Mon Sep 17 00:00:00 2001 From: aminya Date: Fri, 17 Jul 2020 00:57:28 -0500 Subject: [PATCH 34/35] update babel and bower command --- package.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/package.json b/package.json index 4754de1..24f55fe 100644 --- a/package.json +++ b/package.json @@ -13,8 +13,8 @@ "clean": "shx rm -rf lib", "test": "jasmine-focused --captureExceptions --coffee spec", "lint": "coffeelint spec/*.coffee", - "bower": "shx cp lib/* dist", - "babel": "npm run clean && shx cp -r src lib && cross-env NODE_ENV=development cross-env BABEL_ENV=development babel lib --out-dir lib", + "bower": "shx mkdir -p dist && shx cp -r lib/*.js ./dist", + "babel": "npm run clean && shx cp -r src lib && cross-env NODE_ENV=development cross-env BABEL_ENV=development babel lib --out-dir lib && shx rm -f lib/*.mjs", "build": "npm run babel", "prepare": "npm run clean && npm run build && npm run bower" }, From e6e3da13a66bcadb156e5ff667784356719be11f Mon Sep 17 00:00:00 2001 From: aminya Date: Fri, 17 Jul 2020 00:57:57 -0500 Subject: [PATCH 35/35] update bower --- dist/underscore-plus.js | 1107 ++++++++++++++++++++++----------------- 1 file changed, 615 insertions(+), 492 deletions(-) diff --git a/dist/underscore-plus.js b/dist/underscore-plus.js index 32eb482..9b34617 100644 --- a/dist/underscore-plus.js +++ b/dist/underscore-plus.js @@ -1,522 +1,645 @@ -(function() { - var isEqual, isPlainObject, macModifierKeyMap, nonMacModifierKeyMap, plus, shiftKeyMap, splitKeyPath, _, - __slice = [].slice; - - _ = require('underscore'); - - macModifierKeyMap = { - cmd: '\u2318', - ctrl: '\u2303', - alt: '\u2325', - option: '\u2325', - shift: '\u21e7', - enter: '\u23ce', - left: '\u2190', - right: '\u2192', - up: '\u2191', - down: '\u2193' - }; +"use strict"; - nonMacModifierKeyMap = { - cmd: 'Cmd', - ctrl: 'Ctrl', - alt: 'Alt', - option: 'Alt', - shift: 'Shift', - enter: 'Enter', - left: 'Left', - right: 'Right', - up: 'Up', - down: 'Down' - }; +Object.defineProperty(exports, "__esModule", { + value: true +}); +var _exportNames = { + adviseBefore: true, + camelize: true, + capitalize: true, + compactObject: true, + dasherize: true, + deepClone: true, + deepExtend: true, + deepContains: true, + endsWith: true, + escapeAttribute: true, + escapeRegExp: true, + humanizeEventName: true, + humanizeKey: true, + humanizeKeystroke: true, + isSubset: true, + losslessInvert: true, + mapObject: true, + multiplyString: true, + pluralize: true, + remove: true, + setValueForKeyPath: true, + hasKeyPath: true, + spliceWithArray: true, + sum: true, + uncamelcase: true, + undasherize: true, + underscore: true, + valueForKeyPath: true, + isEqual: true, + isEqualForProperties: true +}; +exports.adviseBefore = adviseBefore; +exports.camelize = camelize; +exports.capitalize = capitalize; +exports.compactObject = compactObject; +exports.dasherize = dasherize; +exports.deepClone = deepClone; +exports.deepExtend = deepExtend; +exports.deepContains = deepContains; +exports.endsWith = endsWith; +exports.escapeAttribute = escapeAttribute; +exports.escapeRegExp = escapeRegExp; +exports.humanizeEventName = humanizeEventName; +exports.humanizeKey = humanizeKey; +exports.humanizeKeystroke = humanizeKeystroke; +exports.isSubset = isSubset; +exports.losslessInvert = losslessInvert; +exports.mapObject = mapObject; +exports.multiplyString = multiplyString; +exports.pluralize = pluralize; +exports.remove = remove; +exports.setValueForKeyPath = setValueForKeyPath; +exports.hasKeyPath = hasKeyPath; +exports.spliceWithArray = spliceWithArray; +exports.sum = sum; +exports.uncamelcase = uncamelcase; +exports.undasherize = undasherize; +exports.underscore = underscore; +exports.valueForKeyPath = valueForKeyPath; +exports.isEqual = isEqual; +exports.isEqualForProperties = isEqualForProperties; - shiftKeyMap = { - '~': '`', - '_': '-', - '+': '=', - '|': '\\', - '{': '[', - '}': ']', - ':': ';', - '"': '\'', - '<': ',', - '>': '.', - '?': '/' - }; +var _underscore = require("underscore"); - splitKeyPath = function(keyPath) { - var char, i, keyPathArray, startIndex, _i, _len; - startIndex = 0; - keyPathArray = []; - if (keyPath == null) { - return keyPathArray; +Object.keys(_underscore).forEach(function (key) { + if (key === "default" || key === "__esModule") return; + if (Object.prototype.hasOwnProperty.call(_exportNames, key)) return; + Object.defineProperty(exports, key, { + enumerable: true, + get: function () { + return _underscore[key]; } - for (i = _i = 0, _len = keyPath.length; _i < _len; i = ++_i) { - char = keyPath[i]; - if (char === '.' && (i === 0 || keyPath[i - 1] !== '\\')) { - keyPathArray.push(keyPath.substring(startIndex, i)); - startIndex = i + 1; - } - } - keyPathArray.push(keyPath.substr(startIndex, keyPath.length)); + }); +}); +// import * as _ from 'underscore' // if we needed all +const macModifierKeyMap = { + cmd: '\u2318', + ctrl: '\u2303', + alt: '\u2325', + option: '\u2325', + shift: '\u21e7', + enter: '\u23ce', + left: '\u2190', + right: '\u2192', + up: '\u2191', + down: '\u2193' +}; +const nonMacModifierKeyMap = { + cmd: 'Cmd', + ctrl: 'Ctrl', + alt: 'Alt', + option: 'Alt', + shift: 'Shift', + enter: 'Enter', + left: 'Left', + right: 'Right', + up: 'Up', + down: 'Down' +}; // Human key combos should always explicitly state the shift key. This map is a disambiguator. +// 'shift-version': 'no-shift-version' + +const shiftKeyMap = { + '~': '`', + '_': '-', + '+': '=', + '|': '\\', + '{': '[', + '}': ']', + ':': ';', + '"': '\'', + '<': ',', + '>': '.', + '?': '/' +}; + +function splitKeyPath(keyPath) { + let startIndex = 0; + const keyPathArray = []; + + if (keyPath == null) { return keyPathArray; - }; + } + + for (let i = 0; i < keyPath.length; i++) { + const char = keyPath[i]; + + if (char === '.' && (i === 0 || keyPath[i - 1] !== '\\')) { + keyPathArray.push(keyPath.substring(startIndex, i)); + startIndex = i + 1; + } + } + + keyPathArray.push(keyPath.substr(startIndex, keyPath.length)); + return keyPathArray; +} - isPlainObject = function(value) { - return _.isObject(value) && !_.isArray(value); +const isPlainObject = value => (0, _underscore.isObject)(value) && !(0, _underscore.isArray)(value); + +function adviseBefore(object, methodName, advice) { + const original = object[methodName]; + return object[methodName] = function (...args) { + if (advice.apply(this, args) !== false) { + return original.apply(this, args); + } }; +} - plus = { - adviseBefore: function(object, methodName, advice) { - var original; - original = object[methodName]; - return object[methodName] = function() { - var args; - args = 1 <= arguments.length ? __slice.call(arguments, 0) : []; - if (advice.apply(this, args) !== false) { - return original.apply(this, args); - } - }; - }, - camelize: function(string) { - if (string) { - return string.replace(/[_-]+(\w)/g, function(m) { - return m[1].toUpperCase(); - }); - } else { - return ''; - } - }, - capitalize: function(word) { - if (!word) { - return ''; - } - if (word.toLowerCase() === 'github') { - return 'GitHub'; - } else { - return word[0].toUpperCase() + word.slice(1); - } - }, - compactObject: function(object) { - var key, newObject, value; - newObject = {}; - for (key in object) { - value = object[key]; - if (value != null) { - newObject[key] = value; - } - } - return newObject; - }, - dasherize: function(string) { - if (!string) { - return ''; - } - string = string[0].toLowerCase() + string.slice(1); - return string.replace(/([A-Z])|(_)/g, function(m, letter) { - if (letter) { - return "-" + letter.toLowerCase(); - } else { - return "-"; - } - }); - }, - deepClone: function(object) { - if (_.isArray(object)) { - return object.map(function(value) { - return plus.deepClone(value); - }); - } else if (_.isObject(object) && !_.isFunction(object)) { - return plus.mapObject(object, (function(_this) { - return function(key, value) { - return [key, plus.deepClone(value)]; - }; - })(this)); - } else { - return object; - } - }, - deepExtend: function(target) { - var i, key, object, result, _i, _len, _ref; - result = target; - i = 0; - while (++i < arguments.length) { - object = arguments[i]; - if (isPlainObject(result) && isPlainObject(object)) { - _ref = Object.keys(object); - for (_i = 0, _len = _ref.length; _i < _len; _i++) { - key = _ref[_i]; - result[key] = plus.deepExtend(result[key], object[key]); - } - } else { - result = plus.deepClone(object); - } - } - return result; - }, - deepContains: function(array, target) { - var object, _i, _len; - if (array == null) { - return false; - } - for (_i = 0, _len = array.length; _i < _len; _i++) { - object = array[_i]; - if (_.isEqual(object, target)) { - return true; - } - } - return false; - }, - endsWith: function(string, suffix) { - if (suffix == null) { - suffix = ''; - } - if (string) { - return string.indexOf(suffix, string.length - suffix.length) !== -1; - } else { - return false; - } - }, - escapeAttribute: function(string) { - if (string) { - return string.replace(/"/g, '"').replace(/\n/g, '').replace(/\\/g, '-'); - } else { - return ''; - } - }, - escapeRegExp: function(string) { - if (string) { - return string.replace(/[-\/\\^$*+?.()|[\]{}]/g, '\\$&'); - } else { - return ''; - } - }, - humanizeEventName: function(eventName, eventDoc) { - var event, namespace, namespaceDoc, _ref; - _ref = eventName.split(':'), namespace = _ref[0], event = _ref[1]; - if (event == null) { - return plus.undasherize(namespace); - } - namespaceDoc = plus.undasherize(namespace); - if (eventDoc == null) { - eventDoc = plus.undasherize(event); - } - return "" + namespaceDoc + ": " + eventDoc; - }, - humanizeKey: function(key, platform) { - var modifierKeyMap; - if (platform == null) { - platform = process.platform; - } - if (!key) { - return key; - } - modifierKeyMap = platform === 'darwin' ? macModifierKeyMap : nonMacModifierKeyMap; - if (modifierKeyMap[key]) { - return modifierKeyMap[key]; - } else if (key.length === 1 && (shiftKeyMap[key] != null)) { - return [modifierKeyMap.shift, shiftKeyMap[key]]; - } else if (key.length === 1 && key === key.toUpperCase() && key.toUpperCase() !== key.toLowerCase()) { - return [modifierKeyMap.shift, key.toUpperCase()]; - } else if (key.length === 1 || /f[0-9]{1,2}/.test(key)) { - return key.toUpperCase(); - } else { - if (platform === 'darwin') { - return key; - } else { - return plus.capitalize(key); - } - } - }, - humanizeKeystroke: function(keystroke, platform) { - var humanizedKeystrokes, index, key, keys, keystrokes, splitKeystroke, _i, _j, _len, _len1; - if (platform == null) { - platform = process.platform; - } - if (!keystroke) { - return keystroke; - } - keystrokes = keystroke.split(' '); - humanizedKeystrokes = []; - for (_i = 0, _len = keystrokes.length; _i < _len; _i++) { - keystroke = keystrokes[_i]; - keys = []; - splitKeystroke = keystroke.split('-'); - for (index = _j = 0, _len1 = splitKeystroke.length; _j < _len1; index = ++_j) { - key = splitKeystroke[index]; - if (key === '' && splitKeystroke[index - 1] === '') { - key = '-'; - } - if (key) { - keys.push(plus.humanizeKey(key, platform)); - } - } - keys = _.uniq(_.flatten(keys)); - if (platform === 'darwin') { - keys = keys.join(''); - } else { - keys = keys.join('+'); - } - humanizedKeystrokes.push(keys); - } - return humanizedKeystrokes.join(' '); - }, - isSubset: function(potentialSubset, potentialSuperset) { - return _.every(potentialSubset, function(element) { - return _.include(potentialSuperset, element); - }); - }, - losslessInvert: function(hash) { - var inverted, key, value; - inverted = {}; - for (key in hash) { - value = hash[key]; - if (inverted[value] == null) { - inverted[value] = []; - } - inverted[value].push(key); - } - return inverted; - }, - mapObject: function(object, iterator) { - var key, newObject, value, _i, _len, _ref, _ref1; - newObject = {}; - _ref = Object.keys(object); - for (_i = 0, _len = _ref.length; _i < _len; _i++) { - key = _ref[_i]; - _ref1 = iterator(key, object[key]), key = _ref1[0], value = _ref1[1]; - newObject[key] = value; - } - return newObject; - }, - multiplyString: function(string, n) { - var finalString, i; - finalString = ""; - i = 0; - while (i < n) { - finalString += string; - i++; - } - return finalString; - }, - pluralize: function(count, singular, plural) { - if (count == null) { - count = 0; - } - if (plural == null) { - plural = singular + 's'; - } - if (count === 1) { - return "" + count + " " + singular; - } else { - return "" + count + " " + plural; - } - }, - remove: function(array, element) { - var index; - index = array.indexOf(element); - if (index >= 0) { - array.splice(index, 1); - } - return array; - }, - setValueForKeyPath: function(object, keyPath, value) { - var key, keys; - keys = splitKeyPath(keyPath); - while (keys.length > 1) { - key = keys.shift(); - if (object[key] == null) { - object[key] = {}; - } - object = object[key]; - } - if (value != null) { - return object[keys.shift()] = value; - } else { - return delete object[keys.shift()]; - } - }, - hasKeyPath: function(object, keyPath) { - var key, keys, _i, _len; - keys = splitKeyPath(keyPath); - for (_i = 0, _len = keys.length; _i < _len; _i++) { - key = keys[_i]; - if (!object.hasOwnProperty(key)) { - return false; - } - object = object[key]; +function camelize(string) { + if (string) { + return string.replace(/[_-]+(\w)/g, m => m[1].toUpperCase()); + } else { + return ''; + } +} + +function capitalize(word) { + if (!word) { + return ''; + } + + if (word.toLowerCase() === 'github') { + return 'GitHub'; + } else { + return word[0].toUpperCase() + word.slice(1); + } +} + +function compactObject(object) { + const newObject = {}; + + for (let key in object) { + const value = object[key]; + + if (value != null) { + newObject[key] = value; + } + } + + return newObject; +} + +function dasherize(string) { + if (!string) { + return ''; + } + + string = string[0].toLowerCase() + string.slice(1); + return string.replace(/([A-Z])|(_)/g, function (m, letter) { + if (letter) { + return "-" + letter.toLowerCase(); + } else { + return "-"; + } + }); +} // Deep clones the given JSON object. +// +// `object` - The JSON object to clone. +// +// Returns a deep clone of the JSON object. + + +function deepClone(object) { + if ((0, _underscore.isArray)(object)) { + return object.map(value => deepClone(value)); + } else if ((0, _underscore.isObject)(object) && !(0, _underscore.isFunction)(object)) { + return mapObject(object, (key, value) => [key, deepClone(value)]); + } else { + return object; + } +} + +function deepExtend(target) { + let result = target; + let i = 0; + + while (++i < arguments.length) { + const object = arguments[i]; + + if (isPlainObject(result) && isPlainObject(object)) { + const keys = Object.keys(object); + + for (let key of keys) { + result[key] = deepExtend(result[key], object[key]); } + } else { + result = deepClone(object); + } + } + + return result; +} + +function deepContains(array, target) { + if (array == null) { + return false; + } + + for (let object of array) { + if ((0, _underscore.isEqual)(object, target)) { return true; - }, - spliceWithArray: function(originalArray, start, length, insertedArray, chunkSize) { - var chunkStart, _i, _ref, _results; - if (chunkSize == null) { - chunkSize = 100000; - } - if (insertedArray.length < chunkSize) { - return originalArray.splice.apply(originalArray, [start, length].concat(__slice.call(insertedArray))); - } else { - originalArray.splice(start, length); - _results = []; - for (chunkStart = _i = 0, _ref = insertedArray.length; chunkSize > 0 ? _i <= _ref : _i >= _ref; chunkStart = _i += chunkSize) { - _results.push(originalArray.splice.apply(originalArray, [start + chunkStart, 0].concat(__slice.call(insertedArray.slice(chunkStart, chunkStart + chunkSize))))); - } - return _results; - } - }, - sum: function(array) { - var elt, sum, _i, _len; - sum = 0; - for (_i = 0, _len = array.length; _i < _len; _i++) { - elt = array[_i]; - sum += elt; - } - return sum; - }, - uncamelcase: function(string) { - var result; - if (!string) { - return ''; - } - result = string.replace(/([A-Z])|_+/g, function(match, letter) { - if (letter == null) { - letter = ''; - } - return " " + letter; - }); - return plus.capitalize(result.trim()); - }, - undasherize: function(string) { - if (string) { - return string.split('-').map(plus.capitalize).join(' '); - } else { - return ''; - } - }, - underscore: function(string) { - if (!string) { - return ''; - } - string = string[0].toLowerCase() + string.slice(1); - return string.replace(/([A-Z])|-+/g, function(match, letter) { - if (letter == null) { - letter = ''; - } - return "_" + (letter.toLowerCase()); - }); - }, - valueForKeyPath: function(object, keyPath) { - var key, keys, _i, _len; - keys = splitKeyPath(keyPath); - for (_i = 0, _len = keys.length; _i < _len; _i++) { - key = keys[_i]; - object = object[key]; - if (object == null) { - return; - } - } - return object; - }, - isEqual: function(a, b, aStack, bStack) { - if (_.isArray(aStack) && _.isArray(bStack)) { - return isEqual(a, b, aStack, bStack); - } else { - return isEqual(a, b); + } + } + + return false; +} + +function endsWith(string, suffix) { + if (suffix == null) { + suffix = ''; + } + + if (string) { + return string.indexOf(suffix, string.length - suffix.length) !== -1; + } else { + return false; + } +} + +function escapeAttribute(string) { + if (string) { + return string.replace(/"/g, '"').replace(/\n/g, '').replace(/\\/g, '-'); + } else { + return ''; + } +} + +function escapeRegExp(string) { + if (string) { + return string.replace(/[-\/\\^$*+?.()|[\]{}]/g, '\\$&'); + } else { + return ''; + } +} + +function humanizeEventName(eventName, eventDoc) { + const [namespace, event] = eventName.split(':'); + + if (event == null) { + return undasherize(namespace); + } + + const namespaceDoc = undasherize(namespace); + + if (eventDoc == null) { + eventDoc = undasherize(event); + } + + return `${namespaceDoc}: ${eventDoc}`; +} + +function humanizeKey(key, platform = process.platform) { + if (!key) { + return key; + } + + const modifierKeyMap = platform === 'darwin' ? macModifierKeyMap : nonMacModifierKeyMap; + + if (modifierKeyMap[key]) { + return modifierKeyMap[key]; + } else if (key.length === 1 && shiftKeyMap[key] != null) { + return [modifierKeyMap.shift, shiftKeyMap[key]]; + } else if (key.length === 1 && key === key.toUpperCase() && key.toUpperCase() !== key.toLowerCase()) { + return [modifierKeyMap.shift, key.toUpperCase()]; + } else if (key.length === 1 || /f[0-9]{1,2}/.test(key)) { + return key.toUpperCase(); + } else { + if (platform === 'darwin') { + return key; + } else { + return capitalize(key); + } + } +} // Humanize the keystroke according to platform conventions. This method +// attempts to mirror the text the given keystroke would have if displayed in +// a system menu. +// +// keystroke - A String keystroke to humanize such as `ctrl-O`. +// platform - An optional String platform to humanize for (default: +// `process.platform`). +// +// Returns a humanized representation of the keystroke. + + +function humanizeKeystroke(keystroke, platform = process.platform) { + if (!keystroke) { + return keystroke; + } + + const keystrokes = keystroke.split(' '); + const humanizedKeystrokes = []; + + for (keystroke of keystrokes) { + let keys = []; + const splitKeystroke = keystroke.split('-'); + + for (let index = 0; index < splitKeystroke.length; index++) { + // Check for consecutive dashes such as cmd-- + let key = splitKeystroke[index]; + + if (key === '' && splitKeystroke[index - 1] === '') { + key = '-'; } - }, - isEqualForProperties: function() { - var a, b, properties, property, _i, _len; - a = arguments[0], b = arguments[1], properties = 3 <= arguments.length ? __slice.call(arguments, 2) : []; - for (_i = 0, _len = properties.length; _i < _len; _i++) { - property = properties[_i]; - if (!_.isEqual(a[property], b[property])) { - return false; - } + + if (key) { + keys.push(humanizeKey(key, platform)); } - return true; } - }; - isEqual = function(a, b, aStack, bStack) { - var aCtor, aCtorValid, aElement, aKeyCount, aValue, bCtor, bCtorValid, bKeyCount, bValue, equal, i, key, stackIndex, _i, _len; - if (aStack == null) { - aStack = []; + keys = (0, _underscore.uniq)((0, _underscore.flatten)(keys)); + + if (platform === 'darwin') { + keys = keys.join(''); + } else { + keys = keys.join('+'); } - if (bStack == null) { - bStack = []; + + humanizedKeystrokes.push(keys); + } + + return humanizedKeystrokes.join(' '); +} + +function isSubset(potentialSubset, potentialSuperset) { + return (0, _underscore.every)(potentialSubset, element => (0, _underscore.include)(potentialSuperset, element)); +} + +function losslessInvert(hash) { + const inverted = {}; + + for (let key in hash) { + const value = hash[key]; + + if (inverted[value] == null) { + inverted[value] = []; } - if (a === b) { - return _.isEqual(a, b); + + inverted[value].push(key); + } + + return inverted; +} // Transform the given object into another object. +// +// `object` - The object to transform. +// `iterator` - +// A function that takes `(key, value)` arguments and returns a +// `[key, value]` tuple. +// +// Returns a new object based with the key/values returned by the iterator. + + +function mapObject(object, iterator) { + const newObject = {}; + const keys = Object.keys(object); + + for (let key of keys) { + let value; + [key, value] = iterator(key, object[key]); + newObject[key] = value; + } + + return newObject; +} + +function multiplyString(string, n) { + let finalString = ""; + let i = 0; + + while (i < n) { + finalString += string; + i++; + } + + return finalString; +} + +function pluralize(count = 0, singular, plural = singular + 's') { + if (count === 1) { + return `${count} ${singular}`; + } else { + return `${count} ${plural}`; + } +} + +function remove(array, element) { + const index = array.indexOf(element); + + if (index >= 0) { + array.splice(index, 1); + } + + return array; +} + +function setValueForKeyPath(object, keyPath, value) { + const keys = splitKeyPath(keyPath); + + while (keys.length > 1) { + const key = keys.shift(); + + if (object[key] == null) { + object[key] = {}; } - if (_.isFunction(a) || _.isFunction(b)) { - return _.isEqual(a, b); + + object = object[key]; + } + + if (value != null) { + object[keys.shift()] = value; + } else { + delete object[keys.shift()]; + } +} + +function hasKeyPath(object, keyPath) { + const keys = splitKeyPath(keyPath); + + for (let key of keys) { + if (!object.hasOwnProperty(key)) { + return false; } - stackIndex = aStack.length; - while (stackIndex--) { - if (aStack[stackIndex] === a) { - return bStack[stackIndex] === b; + + object = object[key]; + } + + return true; +} + +function spliceWithArray(originalArray, start, length, insertedArray, chunkSize = 100000) { + if (insertedArray.length < chunkSize) { + originalArray.splice(start, length, ...insertedArray); + } else { + originalArray.splice(start, length); + + for (let chunkStart = 0, end = insertedArray.length; chunkStart <= end; chunkStart += chunkSize) { + originalArray.splice(start + chunkStart, 0, ...insertedArray.slice(chunkStart, chunkStart + chunkSize)); + } + } +} + +function sum(array) { + let sum = 0; + + for (let elt of array) { + sum += elt; + } + + return sum; +} + +function uncamelcase(string) { + if (!string) { + return ''; + } + + const result = string.replace(/([A-Z])|_+/g, (match, letter = '') => ` ${letter}`); + return capitalize(result.trim()); +} + +function undasherize(string) { + if (string) { + return string.split('-').map(capitalize).join(' '); + } else { + return ''; + } +} + +function underscore(string) { + if (!string) { + return ''; + } + + string = string[0].toLowerCase() + string.slice(1); + return string.replace(/([A-Z])|-+/g, (match, letter = '') => `_${letter.toLowerCase()}`); +} + +function valueForKeyPath(object, keyPath) { + const keys = splitKeyPath(keyPath); + + for (let key of keys) { + object = object[key]; + + if (object == null) { + return; + } + } + + return object; +} + +function isEqual(a, b, aStack, bStack) { + if ((0, _underscore.isArray)(aStack) && (0, _underscore.isArray)(bStack)) { + return isEqual_(a, b, aStack, bStack); + } else { + return isEqual_(a, b); + } +} + +function isEqualForProperties(a, b, ...properties) { + // TODO is Array.from needed? + for (let property of Array.from(properties)) { + if (!(0, _underscore.isEqual)(a[property], b[property])) { + return false; + } + } + + return true; +} + +function isEqual_(a, b, aStack = [], bStack = []) { + if (a === b) { + return (0, _underscore.isEqual)(a, b); + } + + if ((0, _underscore.isFunction)(a) || (0, _underscore.isFunction)(b)) { + return (0, _underscore.isEqual)(a, b); + } + + let stackIndex = aStack.length; + + while (stackIndex--) { + if (aStack[stackIndex] === a) { + return bStack[stackIndex] === b; + } + } + + aStack.push(a); + bStack.push(b); + let equal = false; + + if ((0, _underscore.isFunction)(a === null || a === void 0 ? void 0 : a.isEqual)) { + equal = a.isEqual(b, aStack, bStack); + } else if ((0, _underscore.isFunction)(b === null || b === void 0 ? void 0 : b.isEqual)) { + equal = b.isEqual(a, bStack, aStack); + } else if ((0, _underscore.isArray)(a) && (0, _underscore.isArray)(b) && a.length === b.length) { + equal = true; + + for (let i = 0; i < a.length; i++) { + const aElement = a[i]; + + if (!isEqual_(aElement, b[i], aStack, bStack)) { + equal = false; + break; } } - aStack.push(a); - bStack.push(b); - equal = false; - if (_.isFunction(a != null ? a.isEqual : void 0)) { - equal = a.isEqual(b, aStack, bStack); - } else if (_.isFunction(b != null ? b.isEqual : void 0)) { - equal = b.isEqual(a, bStack, aStack); - } else if (_.isArray(a) && _.isArray(b) && a.length === b.length) { + } else if ((0, _underscore.isRegExp)(a) && (0, _underscore.isRegExp)(b)) { + equal = (0, _underscore.isEqual)(a, b); + } else if ((0, _underscore.isElement)(a) && (0, _underscore.isElement)(b)) { + equal = a === b; + } else if ((0, _underscore.isObject)(a) && (0, _underscore.isObject)(b)) { + const aCtor = a.constructor; + const bCtor = b.constructor; + const aCtorValid = (0, _underscore.isFunction)(aCtor) && aCtor instanceof aCtor; + const bCtorValid = (0, _underscore.isFunction)(bCtor) && bCtor instanceof bCtor; + + if (aCtor !== bCtor && !(aCtorValid && bCtorValid)) { + equal = false; + } else { + let key; + let aKeyCount = 0; equal = true; - for (i = _i = 0, _len = a.length; _i < _len; i = ++_i) { - aElement = a[i]; - if (!isEqual(aElement, b[i], aStack, bStack)) { + + for (key in a) { + const aValue = a[key]; + + if (!(0, _underscore.has)(a, key)) { + continue; + } + + aKeyCount++; + + if (!(0, _underscore.has)(b, key) || !isEqual_(aValue, b[key], aStack, bStack)) { equal = false; break; } } - } else if (_.isRegExp(a) && _.isRegExp(b)) { - equal = _.isEqual(a, b); - } else if (_.isElement(a) && _.isElement(b)) { - equal = a === b; - } else if (_.isObject(a) && _.isObject(b)) { - aCtor = a.constructor; - bCtor = b.constructor; - aCtorValid = _.isFunction(aCtor) && aCtor instanceof aCtor; - bCtorValid = _.isFunction(bCtor) && bCtor instanceof bCtor; - if (aCtor !== bCtor && !(aCtorValid && bCtorValid)) { - equal = false; - } else { - aKeyCount = 0; - equal = true; - for (key in a) { - aValue = a[key]; - if (!_.has(a, key)) { - continue; - } - aKeyCount++; - if (!(_.has(b, key) && isEqual(aValue, b[key], aStack, bStack))) { - equal = false; - break; - } - } - if (equal) { - bKeyCount = 0; - for (key in b) { - bValue = b[key]; - if (_.has(b, key)) { - bKeyCount++; - } + + if (equal) { + let bKeyCount = 0; + + for (key in b) { + const bValue = b[key]; + + if ((0, _underscore.has)(b, key)) { + bKeyCount++; } - equal = aKeyCount === bKeyCount; } + + equal = aKeyCount === bKeyCount; } - } else { - equal = _.isEqual(a, b); } - aStack.pop(); - bStack.pop(); - return equal; - }; - - module.exports = _.extend({}, _, plus); + } else { + equal = (0, _underscore.isEqual)(a, b); + } -}).call(this); + aStack.pop(); + bStack.pop(); + return equal; +} // TODO: Consider shorter variations of null checks: +// https://github.com/decaffeinate/decaffeinate/blob/master/docs/suggestions.md#ds207-consider-shorter-variations-of-null-checks \ No newline at end of file