_ = require 'underscore' ItemSpecificities = new WeakMap merge = (menu, item, itemSpecificity=Infinity) -> item = cloneMenuItem(item) ItemSpecificities.set(item, itemSpecificity) if itemSpecificity matchingItemIndex = findMatchingItemIndex(menu, item) matchingItem = menu[matchingItemIndex] unless matchingItemIndex is - 1 if matchingItem? if item.submenu? merge(matchingItem.submenu, submenuItem, itemSpecificity) for submenuItem in item.submenu else if itemSpecificity unless itemSpecificity < ItemSpecificities.get(matchingItem) menu[matchingItemIndex] = item else unless item.type is 'separator' and _.last(menu)?.type is 'separator' menu.push(item) unmerge = (menu, item) -> matchingItemIndex = findMatchingItemIndex(menu, item) matchingItem = menu[matchingItemIndex] unless matchingItemIndex is - 1 if matchingItem? if item.submenu? unmerge(matchingItem.submenu, submenuItem) for submenuItem in item.submenu unless matchingItem.submenu?.length > 0 menu.splice(matchingItemIndex, 1) findMatchingItemIndex = (menu, {type, label, submenu}) -> return -1 if type is 'separator' for item, index in menu if normalizeLabel(item.label) is normalizeLabel(label) and item.submenu? is submenu? return index -1 normalizeLabel = (label) -> return undefined unless label? if process.platform is 'darwin' label else label.replace(/\&/g, '') cloneMenuItem = (item) -> item = _.pick(item, 'type', 'label', 'enabled', 'visible', 'command', 'submenu', 'commandDetail') if item.submenu? item.submenu = item.submenu.map (submenuItem) -> cloneMenuItem(submenuItem) item module.exports = {merge, unmerge, normalizeLabel, cloneMenuItem}