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

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

Powered by Google App Engine
This is Rietveld 408576698