OLD | NEW |
(Empty) | |
| 1 // Copyright 2016 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. |
| 4 'use strict'; |
| 5 const fs = require('fs'); |
| 6 const path = require('path'); |
| 7 |
| 8 const utils = require('./utils'); |
| 9 |
| 10 const FRONTEND_PATH = path.resolve(__dirname, '..', 'front_end'); |
| 11 const BUILD_GN_PATH = path.resolve(__dirname, '..', 'BUILD.gn'); |
| 12 |
| 13 const APPLICATION_DESCRIPTORS = [ |
| 14 'inspector.json', |
| 15 'unit_test_runner.json', |
| 16 ]; |
| 17 |
| 18 // Replace based on specified transformation |
| 19 |
| 20 const MODULES_TO_REMOVE = ['components_lazy', 'ui_lazy']; |
| 21 |
| 22 const JS_FILES_MAPPING = [ |
| 23 {file: 'components_lazy/CookiesTable.js', new: 'cookie_table'}, |
| 24 {file: 'ui/BezierEditor.js', new: 'inline_editor'}, |
| 25 {file: 'ui/BezierUI.js', new: 'inline_editor'}, |
| 26 {file: 'ui/ColorSwatch.js', new: 'inline_editor'}, |
| 27 {file: 'ui/CSSShadowEditor.js', new: 'inline_editor'}, |
| 28 {file: 'ui/SwatchPopoverHelper.js', new: 'inline_editor'}, |
| 29 {file: 'components/Spectrum.js', new: 'spectrum'}, |
| 30 {file: 'components/DataSaverInfobar.js', existing: 'main'}, |
| 31 |
| 32 // Cannot extract dom_ui because of cyclic dependency with components |
| 33 // {file: 'components/DOMPresentationUtils.js', new: 'dom_ui'}, |
| 34 {file: 'components/EventListenersUtils.js', new: 'js_ui'}, |
| 35 {file: 'components/EventListenersView.js', new: 'js_ui'}, |
| 36 {file: 'components/ExecutionContextSelector.js', existing: 'main'}, |
| 37 {file: 'components_lazy/FilmStripModel.js', existing: 'sdk'}, |
| 38 |
| 39 // NOTE: switched from network -> components b/c timeline depends on a class |
| 40 {file: 'components_lazy/FilmStripView.js', existing: 'components'}, |
| 41 {file: 'components_lazy/GCActionDelegate.js', existing: 'main'}, |
| 42 {file: 'components_lazy/LineLevelProfile.js', new: 'perf_ui'}, |
| 43 {file: 'components/RequestAppBannerActionDelegate.js', existing: 'main'}, |
| 44 {file: 'components/ShortcutsScreen.js', existing: 'ui'}, |
| 45 {file: 'components/Reload.js', existing: 'main'}, |
| 46 {file: 'ui_lazy/FilteredListWidget.js', new: 'quick_open'}, |
| 47 {file: 'ui_lazy/CommandMenu.js', new: 'quick_open'}, |
| 48 {file: 'ui_lazy/DataGrid.js', new: 'data_grid'}, |
| 49 {file: 'ui_lazy/ViewportDataGrid.js', new: 'data_grid'}, |
| 50 {file: 'ui_lazy/SortableDataGrid.js', new: 'data_grid'}, |
| 51 {file: 'ui_lazy/ShowMoreDataGridNode.js', new: 'data_grid'}, |
| 52 {file: 'ui_lazy/ChartViewport.js', new: 'perf_ui'}, |
| 53 {file: 'ui_lazy/FlameChart.js', new: 'perf_ui'}, |
| 54 {file: 'ui_lazy/OverviewGrid.js', new: 'perf_ui'}, |
| 55 {file: 'ui_lazy/PieChart.js', new: 'perf_ui'}, |
| 56 {file: 'ui_lazy/TimelineGrid.js', new: 'perf_ui'}, |
| 57 {file: 'ui_lazy/TimelineOverviewPane.js', new: 'perf_ui'} |
| 58 ]; |
| 59 |
| 60 const MODULE_MAPPING = { |
| 61 cookie_table: { |
| 62 dependencies: ['ui', 'sdk', 'data_grid'], |
| 63 dependents: ['resources', 'network'], |
| 64 applications: ['inspector.json'], |
| 65 autostart: false, |
| 66 }, |
| 67 inline_editor: { |
| 68 dependencies: ['ui'], |
| 69 dependents: ['sources', 'elements', 'resources'], |
| 70 applications: ['inspector.json', 'unit_test_runner.json'], |
| 71 autostart: false, |
| 72 }, |
| 73 spectrum: { |
| 74 dependencies: ['ui', 'sdk'], |
| 75 dependents: ['sources', 'elements'], |
| 76 applications: ['inspector.json'], |
| 77 autostart: false, |
| 78 }, |
| 79 // Cannot extract dom_ui because of cyclic dependency with components |
| 80 // dom_ui: { |
| 81 // dependencies: ['ui', 'sdk', 'components'], |
| 82 // dependents: ['animation', 'console', 'elements', 'network', 'timeline', '
layer_viewer', 'components'], |
| 83 // applications: ['inspector.json'], |
| 84 // autostart: true, |
| 85 // }, |
| 86 js_ui: { |
| 87 dependencies: ['ui', 'sdk', 'components'], |
| 88 dependents: ['elements', 'sources'], |
| 89 applications: ['inspector.json'], |
| 90 autostart: true, |
| 91 }, |
| 92 perf_ui: { |
| 93 dependencies: ['ui', 'sdk', 'bindings', 'sources', 'text_editor'], |
| 94 dependents: ['network', 'timeline', 'profiler', 'layer_viewer'], |
| 95 applications: ['inspector.json'], |
| 96 autostart: false, |
| 97 }, |
| 98 quick_open: { |
| 99 dependencies: ['ui', 'diff'], |
| 100 dependents: ['sources'], |
| 101 applications: ['inspector.json', 'unit_test_runner.json'], |
| 102 autostart: false, |
| 103 }, |
| 104 data_grid: { |
| 105 dependencies: ['ui'], |
| 106 dependents: ['network', 'profiler', 'resources', 'console', 'timeline'], |
| 107 applications: ['inspector.json', 'unit_test_runner.json'], |
| 108 autostart: false, |
| 109 }, |
| 110 }; |
| 111 |
| 112 const NEW_DEPENDENCIES_BY_EXISTING_MODULES = { |
| 113 sources: ['main'], |
| 114 resources: ['components'], |
| 115 }; |
| 116 |
| 117 const DEPENDENCIES_BY_MODULE = Object.keys(MODULE_MAPPING).reduce((acc, module)
=> { |
| 118 acc[module] = MODULE_MAPPING[module].dependencies; |
| 119 return acc; |
| 120 }, {}); |
| 121 |
| 122 const APPLICATIONS_BY_MODULE = Object.keys(MODULE_MAPPING).reduce((acc, module)
=> { |
| 123 acc[module] = MODULE_MAPPING[module].applications; |
| 124 return acc; |
| 125 }, {}); |
| 126 |
| 127 const DEPENDENTS_BY_MODULE = Object.keys(MODULE_MAPPING).reduce((acc, module) =>
{ |
| 128 acc[module] = MODULE_MAPPING[module].dependents; |
| 129 return acc; |
| 130 }, {}); |
| 131 |
| 132 function extractModule() { |
| 133 const modules = new Set(); |
| 134 for (let fileObj of JS_FILES_MAPPING) { |
| 135 let moduleName = fileObj.file.split('/')[0]; |
| 136 modules.add(moduleName); |
| 137 } |
| 138 const newModuleSet = JS_FILES_MAPPING.reduce((acc, file) => file.new ? acc.add
(file.new) : acc, new Set()); |
| 139 const targetToOriginalFilesMap = JS_FILES_MAPPING.reduce((acc, f) => { |
| 140 let components = f.file.split('/'); |
| 141 components[0] = f.new || f.existing; |
| 142 acc.set(components.join('/'), f.file); |
| 143 return acc; |
| 144 }, new Map()); |
| 145 |
| 146 const cssFilesMapping = findCSSFiles(); |
| 147 const identifiersByFile = calculateIdentifiers(); |
| 148 const identifierMap = mapIdentifiers(identifiersByFile, cssFilesMapping); |
| 149 const extensionMap = removeFromExistingModuleDescriptors(modules, identifierMa
p, cssFilesMapping); |
| 150 moveFiles(cssFilesMapping); |
| 151 createNewModuleDescriptors(extensionMap, cssFilesMapping, identifiersByFile, t
argetToOriginalFilesMap); |
| 152 updateExistingModuleDescriptors(extensionMap, cssFilesMapping, identifiersByFi
le, targetToOriginalFilesMap); |
| 153 addDependenciesToDescriptors(); |
| 154 renameIdentifiers(identifierMap); |
| 155 updateBuildGNFile(cssFilesMapping, newModuleSet); |
| 156 for (let descriptor of APPLICATION_DESCRIPTORS) |
| 157 updateApplicationDescriptor(descriptor, newModuleSet); |
| 158 |
| 159 // one-off |
| 160 utils.removeRecursive(path.resolve(FRONTEND_PATH, 'components_lazy')); |
| 161 utils.removeRecursive(path.resolve(FRONTEND_PATH, 'ui_lazy')); |
| 162 } |
| 163 |
| 164 String.prototype.replaceAll = function(search, replacement) { |
| 165 let target = this; |
| 166 return target.replace(new RegExp('\\b' + search + '\\b', 'g'), replacement); |
| 167 }; |
| 168 |
| 169 Set.prototype.union = function(setB) { |
| 170 let union = new Set(this); |
| 171 for (let elem of setB) |
| 172 union.add(elem); |
| 173 |
| 174 return union; |
| 175 }; |
| 176 |
| 177 function mapModuleToNamespace(module) { |
| 178 const specialCases = require(path.resolve(__dirname, 'module_to_namespaces.jso
n')); |
| 179 return specialCases[module] || toCamelCase(module); |
| 180 |
| 181 function toCamelCase(module) { |
| 182 return module.split('_').map(a => a.substring(0, 1).toUpperCase() + a.substr
ing(1)).join(''); |
| 183 } |
| 184 } |
| 185 |
| 186 function findCSSFiles() { |
| 187 let cssFilesMapping = new Map(); |
| 188 for (let fileObj of JS_FILES_MAPPING) |
| 189 cssFilesMapping.set(fileObj.file, scrapeCSSFile(fileObj.file)); |
| 190 |
| 191 |
| 192 function scrapeCSSFile(filePath) { |
| 193 let cssFiles = new Set(); |
| 194 const fullPath = path.resolve(FRONTEND_PATH, filePath); |
| 195 let content = fs.readFileSync(fullPath).toString(); |
| 196 let lines = content.split('\n'); |
| 197 for (let line of lines) { |
| 198 let match = line.match(/'(.+\.css)'/); |
| 199 if (!match) |
| 200 continue; |
| 201 let matchPath = match[1]; |
| 202 cssFiles.add(path.basename(path.resolve(FRONTEND_PATH, matchPath))); |
| 203 } |
| 204 if (filePath.includes('EventListenersView.js')) |
| 205 cssFiles.delete('objectValue.css'); |
| 206 return cssFiles; |
| 207 } |
| 208 |
| 209 return cssFilesMapping; |
| 210 } |
| 211 |
| 212 function calculateIdentifiers() { |
| 213 const identifiersByFile = new Map(); |
| 214 for (let fileObj of JS_FILES_MAPPING) { |
| 215 const fullPath = path.resolve(FRONTEND_PATH, fileObj.file); |
| 216 let content = fs.readFileSync(fullPath).toString(); |
| 217 identifiersByFile.set(fileObj.file, scrapeIdentifiers(content)); |
| 218 } |
| 219 return identifiersByFile; |
| 220 |
| 221 function scrapeIdentifiers(content) { |
| 222 let identifiers = []; |
| 223 let lines = content.split('\n'); |
| 224 for (let line of lines) { |
| 225 let match = line.match(new RegExp(`^([a-z_A-Z0-9\.]+)\\s=`)) || line.match
(new RegExp(`^([a-z_A-Z0-9\.]+);`)); |
| 226 if (!match) |
| 227 continue; |
| 228 let name = match[1]; |
| 229 identifiers.push(name); |
| 230 } |
| 231 return identifiers; |
| 232 } |
| 233 } |
| 234 |
| 235 function moveFiles(cssFilesMapping) { |
| 236 for (let fileObj of JS_FILES_MAPPING) { |
| 237 let sourceFilePath = path.resolve(FRONTEND_PATH, fileObj.file); |
| 238 let targetFilePath = getMappedFilePath(fileObj); |
| 239 let moduleDir = path.resolve(targetFilePath, '..'); |
| 240 if (!fs.existsSync(moduleDir)) |
| 241 fs.mkdirSync(moduleDir); |
| 242 |
| 243 move(sourceFilePath, targetFilePath); |
| 244 if (cssFilesMapping.has(fileObj.file)) { |
| 245 cssFilesMapping.get(fileObj.file).forEach((file) => { |
| 246 let module = fileObj.new || fileObj.existing; |
| 247 move(path.resolve(FRONTEND_PATH, fileObj.file.split('/')[0], file), path
.resolve(FRONTEND_PATH, module, file)); |
| 248 }); |
| 249 } |
| 250 } |
| 251 |
| 252 function move(sourceFilePath, targetFilePath) { |
| 253 try { |
| 254 fs.writeFileSync(targetFilePath, fs.readFileSync(sourceFilePath)); |
| 255 fs.unlinkSync(sourceFilePath); |
| 256 } catch (err) { |
| 257 console.log(`error moving ${sourceFilePath} -> ${targetFilePath}`); |
| 258 } |
| 259 } |
| 260 |
| 261 function getMappedFilePath(fileObj) { |
| 262 let components = fileObj.file.split('/'); |
| 263 components[0] = fileObj.existing || fileObj.new; |
| 264 return path.resolve(FRONTEND_PATH, components.join('/')); |
| 265 } |
| 266 } |
| 267 |
| 268 function updateBuildGNFile(cssFilesMapping, newModuleSet) { |
| 269 let content = fs.readFileSync(BUILD_GN_PATH).toString(); |
| 270 let newSourcesToAdd = []; |
| 271 let partialPathMapping = calculatePartialPathMapping(); |
| 272 for (let module of MODULES_TO_REMOVE) { |
| 273 partialPathMapping.set(`"front_end/${module}/module.json",\n`, ''); |
| 274 partialPathMapping.set(`"$resources_out_dir/${module}/${module}_module.js",\
n`, ''); |
| 275 } |
| 276 const newNonAutostartModules = [...newModuleSet] |
| 277 .filter(module => !MODULE_MAPPING[module].a
utostart) |
| 278 .map(module => `"$resources_out_dir/${modul
e}/${module}_module.js",`); |
| 279 |
| 280 let newContent = addContentToLinesInSortedOrder({ |
| 281 content, |
| 282 startLine: '# this contains non-autostart non-remote modules only.', |
| 283 endLine: ']', |
| 284 linesToInsert: newNonAutostartModules, |
| 285 }); |
| 286 |
| 287 for (let pair of partialPathMapping.entries()) |
| 288 newContent = newContent.replace(pair[0], pair[1]); |
| 289 |
| 290 newContent = addContentToLinesInSortedOrder({ |
| 291 content: newContent, |
| 292 startLine: 'all_devtools_files = [', |
| 293 endLine: ']', |
| 294 linesToInsert: newSourcesToAdd, |
| 295 }); |
| 296 |
| 297 fs.writeFileSync(BUILD_GN_PATH, newContent); |
| 298 |
| 299 function calculatePartialPathMapping() { |
| 300 let partialPathMapping = new Map(); |
| 301 for (let fileObj of JS_FILES_MAPPING) { |
| 302 let components = fileObj.file.split('/'); |
| 303 let sourceModule = components[0]; |
| 304 let targetModule = fileObj.existing || fileObj.new; |
| 305 components[0] = targetModule; |
| 306 partialPathMapping.set(`"front_end/${fileObj.file}",\n`, ''); |
| 307 newSourcesToAdd.push(`"front_end/${components.join('/')}",`); |
| 308 if (cssFilesMapping.has(fileObj.file)) { |
| 309 for (let cssFile of cssFilesMapping.get(fileObj.file)) { |
| 310 partialPathMapping.set(`"front_end/${sourceModule}/${cssFile}",\n`, ''
); |
| 311 newSourcesToAdd.push(`"front_end/${targetModule}/${cssFile}",`); |
| 312 } |
| 313 } |
| 314 } |
| 315 return partialPathMapping; |
| 316 } |
| 317 |
| 318 function top(array) { |
| 319 return array[array.length - 1]; |
| 320 } |
| 321 |
| 322 function addContentToLinesInSortedOrder({content, startLine, endLine, linesToI
nsert}) { |
| 323 let lines = content.split('\n'); |
| 324 let seenStartLine = false; |
| 325 let contentStack = linesToInsert.sort((a, b) => a.toLowerCase().localeCompar
e(b.toLowerCase())).reverse(); |
| 326 for (var i = 0; i < lines.length; i++) { |
| 327 let line = lines[i].trim(); |
| 328 let nextLine = lines[i + 1].trim(); |
| 329 if (line === startLine) |
| 330 seenStartLine = true; |
| 331 |
| 332 if (line === endLine && seenStartLine) |
| 333 break; |
| 334 |
| 335 if (!seenStartLine) |
| 336 continue; |
| 337 |
| 338 const nextContent = top(contentStack) ? top(contentStack).toLowerCase() :
''; |
| 339 if ((line === startLine || nextContent > line.toLowerCase()) && |
| 340 (nextLine === endLine || nextContent < nextLine.toLowerCase())) |
| 341 lines.splice(i + 1, 0, contentStack.pop()); |
| 342 } |
| 343 if (contentStack.length) |
| 344 lines.splice(i, 0, ...contentStack); |
| 345 return lines.join('\n'); |
| 346 } |
| 347 } |
| 348 |
| 349 function mapIdentifiers(identifiersByFile, cssFilesMapping) { |
| 350 const filesToTargetModule = new Map(); |
| 351 for (let fileObj of JS_FILES_MAPPING) |
| 352 filesToTargetModule.set(fileObj.file, fileObj.existing || fileObj.new); |
| 353 |
| 354 |
| 355 const map = new Map(); |
| 356 for (let [file, identifiers] of identifiersByFile) { |
| 357 let targetModule = filesToTargetModule.get(file); |
| 358 for (let identifier of identifiers) { |
| 359 let components = identifier.split('.'); |
| 360 components[0] = mapModuleToNamespace(targetModule); |
| 361 let newIdentifier = components.join('.'); |
| 362 map.set(identifier, newIdentifier); |
| 363 } |
| 364 } |
| 365 // one-off fix |
| 366 map.set('SDK.EventListener.frameworkEventListeners', 'JS_UI.frameworkEventList
eners'); |
| 367 for (let [jsFile, cssFiles] of cssFilesMapping) { |
| 368 let fileObj = JS_FILES_MAPPING.filter(f => f.file === jsFile)[0]; |
| 369 let sourceModule = fileObj.file.split('/')[0]; |
| 370 let targetModule = fileObj.existing || fileObj.new; |
| 371 for (let cssFile of cssFiles) { |
| 372 let key = `${sourceModule}/${cssFile}`; |
| 373 let value = `${targetModule}/${cssFile}`; |
| 374 map.set(key, value); |
| 375 } |
| 376 } |
| 377 return map; |
| 378 } |
| 379 |
| 380 function renameIdentifiers(identifierMap) { |
| 381 walkSync('front_end', write, true); |
| 382 |
| 383 walkSync('../../LayoutTests/http/tests/inspector', write, false); |
| 384 walkSync('../../LayoutTests/http/tests/inspector-enabled', write, false); |
| 385 walkSync('../../LayoutTests/http/tests/inspector-protocol', write, false); |
| 386 walkSync('../../LayoutTests/http/tests/inspector-unit', write, false); |
| 387 walkSync('../../LayoutTests/inspector', write, false); |
| 388 walkSync('../../LayoutTests/inspector-enabled', write, false); |
| 389 walkSync('../../LayoutTests/inspector-protocol', write, false); |
| 390 |
| 391 function walkSync(currentDirPath, process, json) { |
| 392 fs.readdirSync(currentDirPath).forEach(function(name) { |
| 393 let filePath = path.join(currentDirPath, name); |
| 394 let stat = fs.statSync(filePath); |
| 395 if (stat.isFile() && (filePath.endsWith('.js') || filePath.endsWith('.html
') || filePath.endsWith('.xhtml') || |
| 396 filePath.endsWith('-expected.txt') || (json && fileP
ath.endsWith('.json')))) { |
| 397 if (filePath.includes('ExtensionAPI.js')) |
| 398 return; |
| 399 if (filePath.includes('externs.js')) |
| 400 return; |
| 401 if (filePath.includes('eslint') || filePath.includes('lighthouse-backgro
und.js') || filePath.includes('/cm/') || |
| 402 filePath.includes('/xterm.js/') || filePath.includes('/acorn/') || f
ilePath.includes('/gonzales-scss')) |
| 403 return; |
| 404 if (filePath.includes('/cm_modes/') && !filePath.includes('DefaultCodeMi
rror') && |
| 405 !filePath.includes('module.json')) |
| 406 return; |
| 407 process(filePath); |
| 408 } else if (stat.isDirectory()) { |
| 409 walkSync(filePath, process, json); |
| 410 } |
| 411 }); |
| 412 } |
| 413 |
| 414 function write(filePath) { |
| 415 let content = fs.readFileSync(filePath).toString(); |
| 416 let newContent = content; |
| 417 for (let key of identifierMap.keys()) { |
| 418 let originalIdentifier = key; |
| 419 let newIdentifier = identifierMap.get(key); |
| 420 newContent = newContent.replaceAll(originalIdentifier, newIdentifier); |
| 421 } |
| 422 if (filePath.includes('LayoutTests/http/tests/inspector-unit/filtered-item-s
election-dialog-filtering.js')) |
| 423 newContent = newContent.replaceAll('ui_lazy', 'quick_open'); |
| 424 if (filePath.includes('LayoutTests/inspector/components/cookies-table.html')
) |
| 425 newContent = newContent.replaceAll('components_lazy', 'cookie_table'); |
| 426 if (filePath.includes('LayoutTests/inspector/components/datagrid-autosize.ht
ml')) |
| 427 newContent = newContent.replaceAll('ui_lazy', 'data_grid'); |
| 428 if (filePath.includes('LayoutTests/inspector/components/datagrid-test.js')) |
| 429 newContent = newContent.replaceAll('ui_lazy', 'data_grid'); |
| 430 |
| 431 if (content !== newContent) |
| 432 fs.writeFileSync(filePath, newContent); |
| 433 } |
| 434 } |
| 435 |
| 436 function removeFromExistingModuleDescriptors(modules, identifierMap, cssFilesMap
ping) { |
| 437 let extensionMap = new Map(); |
| 438 let moduleFileMap = new Map(); |
| 439 |
| 440 for (let fileObj of JS_FILES_MAPPING) { |
| 441 let components = fileObj.file.split('/'); |
| 442 let module = components[0]; |
| 443 let fileName = components[1]; |
| 444 |
| 445 if (!moduleFileMap.get(module)) |
| 446 moduleFileMap.set(module, []); |
| 447 |
| 448 moduleFileMap.set(module, moduleFileMap.get(module).concat(fileName)); |
| 449 } |
| 450 |
| 451 for (let module of modules) { |
| 452 let moduleJSONPath = path.resolve(FRONTEND_PATH, module, 'module.json'); |
| 453 let content = fs.readFileSync(moduleJSONPath).toString(); |
| 454 let moduleObj = JSON.parse(content); |
| 455 let removedScripts = removeScripts(moduleObj, module); |
| 456 removeResources(moduleObj, removedScripts); |
| 457 removeExtensions(moduleObj); |
| 458 fs.writeFileSync(moduleJSONPath, JSON.stringify(moduleObj, null, 4)); |
| 459 } |
| 460 |
| 461 return extensionMap; |
| 462 |
| 463 function removeScripts(moduleObj, module) { |
| 464 let remainingScripts = []; |
| 465 let removedScripts = []; |
| 466 let moduleFiles = moduleFileMap.get(module); |
| 467 for (let script of moduleObj.scripts) { |
| 468 if (!moduleFiles.includes(script)) |
| 469 remainingScripts.push(script); |
| 470 else |
| 471 removedScripts.push(module + '/' + script); |
| 472 } |
| 473 moduleObj.scripts = remainingScripts; |
| 474 return removedScripts; |
| 475 } |
| 476 |
| 477 function removeResources(moduleObj, removedScripts) { |
| 478 if (!moduleObj.resources) |
| 479 return; |
| 480 let remainingResources = []; |
| 481 let removedResources = new Set(); |
| 482 for (let script of removedScripts) |
| 483 removedResources = removedResources.union(cssFilesMapping.get(script)); |
| 484 |
| 485 |
| 486 for (let resource of moduleObj.resources) { |
| 487 if (!removedResources.has(resource)) |
| 488 remainingResources.push(resource); |
| 489 } |
| 490 moduleObj.resources = remainingResources; |
| 491 } |
| 492 |
| 493 function removeExtensions(moduleObj) { |
| 494 if (!moduleObj.extensions) |
| 495 return; |
| 496 let remainingExtensions = []; |
| 497 for (let extension of moduleObj.extensions) { |
| 498 if (!objectIncludesIdentifier(extension)) |
| 499 remainingExtensions.push(extension); |
| 500 else |
| 501 extensionMap.set(objectIncludesIdentifier(extension), extension); |
| 502 } |
| 503 moduleObj.extensions = remainingExtensions; |
| 504 } |
| 505 |
| 506 function objectIncludesIdentifier(object) { |
| 507 for (let key in object) { |
| 508 let value = object[key]; |
| 509 if (identifierMap.has(value)) |
| 510 return value; |
| 511 } |
| 512 return false; |
| 513 } |
| 514 } |
| 515 |
| 516 function createNewModuleDescriptors(extensionMap, cssFilesMapping, identifiersBy
File, targetToOriginalFilesMap) { |
| 517 let filesByNewModule = getFilesByNewModule(); |
| 518 |
| 519 for (let module of filesByNewModule.keys()) { |
| 520 let moduleObj = {}; |
| 521 |
| 522 let scripts = getModuleScripts(module); |
| 523 let extensions = getModuleExtensions(scripts, module); |
| 524 if (extensions.length) |
| 525 moduleObj.extensions = extensions; |
| 526 |
| 527 moduleObj.dependencies = DEPENDENCIES_BY_MODULE[module]; |
| 528 |
| 529 moduleObj.scripts = scripts; |
| 530 |
| 531 let resources = getModuleResources(moduleObj.scripts, module); |
| 532 if (resources.length) |
| 533 moduleObj.resources = resources; |
| 534 |
| 535 let moduleJSONPath = path.resolve(FRONTEND_PATH, module, 'module.json'); |
| 536 fs.writeFileSync(moduleJSONPath, JSON.stringify(moduleObj, null, 2)); |
| 537 } |
| 538 |
| 539 function getFilesByNewModule() { |
| 540 let filesByNewModule = new Map(); |
| 541 for (let fileObj of JS_FILES_MAPPING) { |
| 542 if (!fileObj.new) |
| 543 continue; |
| 544 if (!filesByNewModule.has(fileObj.new)) |
| 545 filesByNewModule.set(fileObj.new, []); |
| 546 |
| 547 filesByNewModule.set(fileObj.new, filesByNewModule.get(fileObj.new).concat
([fileObj.file])); |
| 548 } |
| 549 return filesByNewModule; |
| 550 } |
| 551 |
| 552 function getModuleScripts(module) { |
| 553 return filesByNewModule.get(module).map((file) => file.split('/')[1]); |
| 554 } |
| 555 |
| 556 function getModuleResources(scripts, module) { |
| 557 let resources = []; |
| 558 scripts.map(script => module + '/' + script).forEach((script) => { |
| 559 script = targetToOriginalFilesMap.get(script); |
| 560 if (!cssFilesMapping.has(script)) |
| 561 return; |
| 562 |
| 563 resources = resources.concat([...cssFilesMapping.get(script)]); |
| 564 }); |
| 565 return resources; |
| 566 } |
| 567 |
| 568 function getModuleExtensions(scripts, module) { |
| 569 let extensions = []; |
| 570 let identifiers = |
| 571 scripts.map(script => module + '/' + script) |
| 572 .reduce((acc, file) => acc.concat(identifiersByFile.get(targetToOrig
inalFilesMap.get(file))), []); |
| 573 for (let identifier of identifiers) { |
| 574 if (extensionMap.has(identifier)) |
| 575 extensions.push(extensionMap.get(identifier)); |
| 576 } |
| 577 return extensions; |
| 578 } |
| 579 } |
| 580 |
| 581 function calculateFilesByModuleType(type) { |
| 582 let filesByNewModule = new Map(); |
| 583 for (let fileObj of JS_FILES_MAPPING) { |
| 584 if (!fileObj[type]) |
| 585 continue; |
| 586 if (!filesByNewModule.has(fileObj[type])) |
| 587 filesByNewModule.set(fileObj[type], []); |
| 588 |
| 589 filesByNewModule.set(fileObj[type], filesByNewModule.get(fileObj[type]).conc
at([fileObj.file])); |
| 590 } |
| 591 return filesByNewModule; |
| 592 } |
| 593 |
| 594 function updateExistingModuleDescriptors(extensionMap, cssFilesMapping, identifi
ersByFile, targetToOriginalFilesMap) { |
| 595 let filesByExistingModule = calculateFilesByModuleType('existing'); |
| 596 for (let module of filesByExistingModule.keys()) { |
| 597 let moduleJSONPath = path.resolve(FRONTEND_PATH, module, 'module.json'); |
| 598 let content = fs.readFileSync(moduleJSONPath).toString(); |
| 599 let moduleObj = JSON.parse(content); |
| 600 |
| 601 let scripts = getModuleScripts(module); |
| 602 let existingExtensions = moduleObj.extensions || []; |
| 603 let extensions = existingExtensions.concat(getModuleExtensions(scripts, modu
le)); |
| 604 if (extensions.length) |
| 605 moduleObj.extensions = extensions; |
| 606 |
| 607 moduleObj.scripts = moduleObj.scripts.concat(scripts); |
| 608 |
| 609 let existingResources = moduleObj.resources || []; |
| 610 let resources = existingResources.concat(getModuleResources(scripts, module)
); |
| 611 if (resources.length) |
| 612 moduleObj.resources = resources; |
| 613 |
| 614 fs.writeFileSync(moduleJSONPath, JSON.stringify(moduleObj, null, 2)); |
| 615 } |
| 616 |
| 617 |
| 618 function getModuleScripts(module) { |
| 619 return filesByExistingModule.get(module).map((file) => file.split('/')[1]); |
| 620 } |
| 621 |
| 622 function getModuleResources(scripts, module) { |
| 623 let resources = []; |
| 624 scripts.map(script => module + '/' + script).forEach((script) => { |
| 625 script = targetToOriginalFilesMap.get(script); |
| 626 if (!cssFilesMapping.has(script)) |
| 627 return; |
| 628 |
| 629 resources = resources.concat([...cssFilesMapping.get(script)]); |
| 630 }); |
| 631 return resources; |
| 632 } |
| 633 |
| 634 function getModuleExtensions(scripts, module) { |
| 635 let extensions = []; |
| 636 let identifiers = |
| 637 scripts.map(script => module + '/' + script) |
| 638 .reduce((acc, file) => acc.concat(identifiersByFile.get(targetToOrig
inalFilesMap.get(file))), []); |
| 639 for (let identifier of identifiers) { |
| 640 if (extensionMap.has(identifier)) |
| 641 extensions.push(extensionMap.get(identifier)); |
| 642 } |
| 643 return extensions; |
| 644 } |
| 645 } |
| 646 |
| 647 function addDependenciesToDescriptors() { |
| 648 for (let module of getModules()) { |
| 649 let moduleJSONPath = path.resolve(FRONTEND_PATH, module, 'module.json'); |
| 650 let content = fs.readFileSync(moduleJSONPath).toString(); |
| 651 let moduleObj = JSON.parse(content); |
| 652 |
| 653 let existingDependencies = moduleObj.dependencies || []; |
| 654 let dependencies = existingDependencies.concat(getModuleDependencies(module)
) |
| 655 .filter((module) => !MODULES_TO_REMOVE.includes(modul
e)); |
| 656 let newDependenciesForExistingModule = NEW_DEPENDENCIES_BY_EXISTING_MODULES[
module]; |
| 657 if (newDependenciesForExistingModule) |
| 658 dependencies = dependencies.concat(newDependenciesForExistingModule); |
| 659 if (dependencies.length) |
| 660 moduleObj.dependencies = dependencies; |
| 661 let originalStringified = JSON.stringify(JSON.parse(content), null, 2); |
| 662 let newStringified = JSON.stringify(moduleObj, null, 2); |
| 663 if (originalStringified !== newStringified) |
| 664 fs.writeFileSync(moduleJSONPath, newStringified); |
| 665 } |
| 666 |
| 667 function getModuleDependencies(existingModule) { |
| 668 let newDeps = []; |
| 669 for (let newModule in DEPENDENTS_BY_MODULE) { |
| 670 let dependents = DEPENDENTS_BY_MODULE[newModule]; |
| 671 if (dependents.includes(existingModule)) |
| 672 newDeps.push(newModule); |
| 673 } |
| 674 return newDeps; |
| 675 } |
| 676 } |
| 677 |
| 678 function updateApplicationDescriptor(descriptorFileName, newModuleSet) { |
| 679 let descriptorPath = path.join(FRONTEND_PATH, descriptorFileName); |
| 680 let newModules = [...newModuleSet].filter(m => APPLICATIONS_BY_MODULE[m].inclu
des(descriptorFileName)); |
| 681 let includeNewModules = (acc, line) => { |
| 682 if (line.includes('{') && line.endsWith('}')) { |
| 683 line += ','; |
| 684 acc.push(line); |
| 685 return acc.concat(newModules.map((m, i) => { |
| 686 // Need spacing to preserve indentation |
| 687 let string; |
| 688 if (MODULE_MAPPING[m].autostart) |
| 689 string = ` { "name": "${m}", "type": "autostart"}`; |
| 690 else |
| 691 string = ` { "name": "${m}" }`; |
| 692 if (i !== newModules.length - 1) |
| 693 string += ','; |
| 694 return string; |
| 695 })); |
| 696 } |
| 697 return acc.concat([line]); |
| 698 }; |
| 699 let removeModules = (acc, line) => MODULES_TO_REMOVE.every(m => !line.includes
(m)) ? acc.concat([line]) : acc; |
| 700 let lines = |
| 701 fs.readFileSync(descriptorPath).toString().split('\n').reduce(includeNewMo
dules, []).reduce(removeModules, []); |
| 702 fs.writeFileSync(descriptorPath, lines.join('\n')); |
| 703 } |
| 704 |
| 705 function getModules() { |
| 706 return fs.readdirSync(FRONTEND_PATH).filter(function(file) { |
| 707 return fs.statSync(path.join(FRONTEND_PATH, file)).isDirectory() && |
| 708 utils.isFile(path.join(FRONTEND_PATH, file, 'module.json')); |
| 709 }); |
| 710 } |
| 711 |
| 712 if (require.main === module) |
| 713 extractModule(); |
OLD | NEW |