Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(58)

Side by Side Diff: third_party/WebKit/Source/devtools/scripts/extract_module/extract_module.js

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

Powered by Google App Engine
This is Rietveld 408576698