mirror of
https://github.com/react/react-native-devtools-frontend.git
synced 2026-10-01 01:38:07 +08:00
Move and rename files. NOAUTOREVERT=true NOPRESUBMIT=true NOTREECHECKS=true Bug: 768828 TBR=darin@chromium.org NOTRY=true Change-Id: I66d3b155808bc5bdbf237b80208e1e552bcf7f28 Reviewed-on: https://chromium-review.googlesource.com/1001153 Reviewed-by: Blink Reformat <blink-reformat@chromium.org> Commit-Queue: Blink Reformat <blink-reformat@chromium.org> Cr-Original-Commit-Position: refs/heads/master@{#549061} Cr-Mirrored-From: https://chromium.googlesource.com/chromium/src Cr-Mirrored-Commit: 0aee4434a4dba42a42abaea9bfbc0cd196a63bc1
742 lines
25 KiB
JavaScript
742 lines
25 KiB
JavaScript
// Copyright 2016 The Chromium Authors. All rights reserved.
|
|
// Use of this source code is governed by a BSD-style license that can be
|
|
// found in the LICENSE file.
|
|
'use strict';
|
|
const fs = require('fs');
|
|
const path = require('path');
|
|
|
|
const utils = require('../utils');
|
|
|
|
const FRONTEND_PATH = path.resolve(__dirname, '..', '..', 'front_end');
|
|
const BUILD_GN_PATH = path.resolve(__dirname, '..', '..', 'BUILD.gn');
|
|
const SPECIAL_CASE_NAMESPACES_PATH = path.resolve(__dirname, '..', 'special_case_namespaces.json');
|
|
|
|
/*
|
|
* This is used to extract a new module from an existing module by:
|
|
* - Moving selected files into new modules (including relevant
|
|
* css files)
|
|
* - Renaming all identifiers to the new namespace
|
|
* - Updating the BUILD.gn and module.json files (including extensions)
|
|
* ==========================================
|
|
* START EDITING HERE - TRANSFORMATION INPUTS
|
|
* ==========================================
|
|
*/
|
|
|
|
const APPLICATION_DESCRIPTORS = [
|
|
'devtools_app.json',
|
|
'js_app.json',
|
|
'shell.json',
|
|
'worker_app.json',
|
|
'inspector.json',
|
|
'toolbox.json',
|
|
'integration_test_runner.json',
|
|
'formatter_worker.json',
|
|
'heap_snapshot_worker.json',
|
|
];
|
|
|
|
/*
|
|
* If the transformation removes all the files of a module:
|
|
* ['text_editor']
|
|
*/
|
|
const MODULES_TO_REMOVE = ['profiler_test_runner', 'heap_snapshot_test_runner'];
|
|
|
|
/**
|
|
* If moving to a new module:
|
|
* {file: 'common/Text.js', new: 'a_new_module'}
|
|
*
|
|
* If moving to an existing module:
|
|
* {file: 'ui/SomeFile.js', existing: 'common'}
|
|
*/
|
|
const JS_FILES_MAPPING = [
|
|
// {file: 'heap_snapshot_test_runner/HeapSnapshotTestRunner.js', new: 'heap_profiler_test_runner'},
|
|
// {file: 'profiler_test_runner/ProfilerTestRunner.js', new: 'cpu_profiler_test_runner'},
|
|
{file: 'network_log/HAREntry.js', existing: 'browser_sdk'},
|
|
];
|
|
|
|
/**
|
|
* List all new modules here:
|
|
* mobile_throttling: {
|
|
* dependencies: ['sdk'],
|
|
* dependents: ['console'],
|
|
* applications: ['inspector.json'],
|
|
* autostart: false,
|
|
* }
|
|
*/
|
|
const MODULE_MAPPING = {
|
|
// heap_profiler_test_runner: {
|
|
// dependencies: ['heap_snapshot_worker', 'test_runner'],
|
|
// dependents: [],
|
|
// applications: ['integration_test_runner.json'],
|
|
// autostart: false,
|
|
// },
|
|
// cpu_profiler_test_runner: {
|
|
// dependencies: ['profiler', 'test_runner'],
|
|
// dependents: [],
|
|
// applications: ['integration_test_runner.json'],
|
|
// autostart: false,
|
|
// },
|
|
};
|
|
|
|
/**
|
|
* If an existing module will have a new dependency on an existing module:
|
|
* console: ['new_dependency']
|
|
*/
|
|
const NEW_DEPENDENCIES_BY_EXISTING_MODULES = {
|
|
// resources: ['components'],
|
|
};
|
|
|
|
/**
|
|
* If an existing module will no longer have a dependency on a module:
|
|
* console: ['former_dependency']
|
|
*/
|
|
const REMOVE_DEPENDENCIES_BY_EXISTING_MODULES = {
|
|
// console_test_runner: ['main']
|
|
};
|
|
|
|
/*
|
|
* ==========================================
|
|
* STOP EDITING HERE
|
|
* ==========================================
|
|
*/
|
|
|
|
const DEPENDENCIES_BY_MODULE = Object.keys(MODULE_MAPPING).reduce((acc, module) => {
|
|
acc[module] = MODULE_MAPPING[module].dependencies;
|
|
return acc;
|
|
}, {});
|
|
|
|
const APPLICATIONS_BY_MODULE = Object.keys(MODULE_MAPPING).reduce((acc, module) => {
|
|
acc[module] = MODULE_MAPPING[module].applications;
|
|
return acc;
|
|
}, {});
|
|
|
|
const DEPENDENTS_BY_MODULE = Object.keys(MODULE_MAPPING).reduce((acc, module) => {
|
|
acc[module] = MODULE_MAPPING[module].dependents;
|
|
return acc;
|
|
}, {});
|
|
|
|
function extractModule() {
|
|
const modules = new Set();
|
|
for (let fileObj of JS_FILES_MAPPING) {
|
|
let moduleName = fileObj.file.split('/')[0];
|
|
modules.add(moduleName);
|
|
}
|
|
const newModuleSet = JS_FILES_MAPPING.reduce((acc, file) => file.new ? acc.add(file.new) : acc, new Set());
|
|
const targetToOriginalFilesMap = JS_FILES_MAPPING.reduce((acc, f) => {
|
|
let components = f.file.split('/');
|
|
components[0] = f.new || f.existing;
|
|
acc.set(components.join('/'), f.file);
|
|
return acc;
|
|
}, new Map());
|
|
|
|
const cssFilesMapping = findCSSFiles();
|
|
console.log('cssFilesMapping', cssFilesMapping);
|
|
const identifiersByFile = calculateIdentifiers();
|
|
const identifierMap = mapIdentifiers(identifiersByFile, cssFilesMapping);
|
|
console.log('identifierMap', identifierMap);
|
|
const extensionMap = removeFromExistingModuleDescriptors(modules, identifierMap, cssFilesMapping);
|
|
|
|
// Find out which files are moving extensions
|
|
for (let e of extensionMap.keys()) {
|
|
for (let [f, identifiers] of identifiersByFile) {
|
|
if (identifiers.includes(e))
|
|
console.log(`extension: ${e} in file: ${f}`);
|
|
}
|
|
}
|
|
|
|
moveFiles(cssFilesMapping);
|
|
createNewModuleDescriptors(extensionMap, cssFilesMapping, identifiersByFile, targetToOriginalFilesMap);
|
|
updateExistingModuleDescriptors(extensionMap, cssFilesMapping, identifiersByFile, targetToOriginalFilesMap);
|
|
addDependenciesToDescriptors();
|
|
renameIdentifiers(identifierMap);
|
|
updateBuildGNFile(cssFilesMapping, newModuleSet);
|
|
for (let descriptor of APPLICATION_DESCRIPTORS)
|
|
updateApplicationDescriptor(descriptor, newModuleSet);
|
|
|
|
for (let m of MODULES_TO_REMOVE)
|
|
utils.removeRecursive(path.resolve(FRONTEND_PATH, m));
|
|
}
|
|
|
|
String.prototype.replaceAll = function(search, replacement) {
|
|
let target = this;
|
|
return target.replace(new RegExp('\\b' + search + '\\b', 'g'), replacement);
|
|
};
|
|
|
|
Set.prototype.union = function(setB) {
|
|
let union = new Set(this);
|
|
for (let elem of setB)
|
|
union.add(elem);
|
|
|
|
return union;
|
|
};
|
|
|
|
function mapModuleToNamespace(module) {
|
|
const specialCases = require(SPECIAL_CASE_NAMESPACES_PATH);
|
|
return specialCases[module] || toCamelCase(module);
|
|
|
|
function toCamelCase(module) {
|
|
return module.split('_').map(a => a.substring(0, 1).toUpperCase() + a.substring(1)).join('');
|
|
}
|
|
}
|
|
|
|
function findCSSFiles() {
|
|
let cssFilesMapping = new Map();
|
|
for (let fileObj of JS_FILES_MAPPING)
|
|
cssFilesMapping.set(fileObj.file, scrapeCSSFile(fileObj.file));
|
|
|
|
|
|
function scrapeCSSFile(filePath) {
|
|
let cssFiles = new Set();
|
|
const fullPath = path.resolve(FRONTEND_PATH, filePath);
|
|
let content = fs.readFileSync(fullPath).toString();
|
|
let lines = content.split('\n');
|
|
for (let line of lines) {
|
|
let match = line.match(/'(.+\.css)'/);
|
|
if (!match)
|
|
continue;
|
|
let matchPath = match[1];
|
|
cssFiles.add(path.basename(path.resolve(FRONTEND_PATH, matchPath)));
|
|
}
|
|
return cssFiles;
|
|
}
|
|
|
|
return cssFilesMapping;
|
|
}
|
|
|
|
function calculateIdentifiers() {
|
|
const identifiersByFile = new Map();
|
|
for (let fileObj of JS_FILES_MAPPING) {
|
|
const fullPath = path.resolve(FRONTEND_PATH, fileObj.file);
|
|
let content = fs.readFileSync(fullPath).toString();
|
|
identifiersByFile.set(fileObj.file, scrapeIdentifiers(content, fileObj));
|
|
}
|
|
return identifiersByFile;
|
|
|
|
function scrapeIdentifiers(content, fileObj) {
|
|
let identifiers = [];
|
|
let lines = content.split('\n');
|
|
for (let line of lines) {
|
|
let match =
|
|
line.match(new RegExp(`^\\s*([a-z_A-Z0-9\.]+)\\s=`)) || line.match(new RegExp(`^\\s*([a-z_A-Z0-9\.]+);`));
|
|
if (!match)
|
|
continue;
|
|
let name = match[1];
|
|
|
|
var currentModule = fileObj.file.split('/')[0];
|
|
if (name.split('.')[0] !== mapModuleToNamespace(currentModule)) {
|
|
console.log(`POSSIBLE ISSUE: identifier: ${name} found in ${currentModule}`);
|
|
// one-off
|
|
if (name.includes('UI.')) {
|
|
console.log(`including ${name} anyways`);
|
|
identifiers.push(name);
|
|
}
|
|
} else {
|
|
identifiers.push(name);
|
|
}
|
|
}
|
|
return identifiers;
|
|
}
|
|
}
|
|
|
|
function moveFiles(cssFilesMapping) {
|
|
for (let fileObj of JS_FILES_MAPPING) {
|
|
let sourceFilePath = path.resolve(FRONTEND_PATH, fileObj.file);
|
|
let targetFilePath = getMappedFilePath(fileObj);
|
|
let moduleDir = path.resolve(targetFilePath, '..');
|
|
if (!fs.existsSync(moduleDir))
|
|
fs.mkdirSync(moduleDir);
|
|
|
|
move(sourceFilePath, targetFilePath);
|
|
if (cssFilesMapping.has(fileObj.file)) {
|
|
cssFilesMapping.get(fileObj.file).forEach((file) => {
|
|
let module = fileObj.new || fileObj.existing;
|
|
move(path.resolve(FRONTEND_PATH, fileObj.file.split('/')[0], file), path.resolve(FRONTEND_PATH, module, file));
|
|
});
|
|
}
|
|
}
|
|
|
|
function move(sourceFilePath, targetFilePath) {
|
|
try {
|
|
fs.writeFileSync(targetFilePath, fs.readFileSync(sourceFilePath));
|
|
fs.unlinkSync(sourceFilePath);
|
|
} catch (err) {
|
|
console.log(`error moving ${sourceFilePath} -> ${targetFilePath}`);
|
|
}
|
|
}
|
|
|
|
function getMappedFilePath(fileObj) {
|
|
let components = fileObj.file.split('/');
|
|
components[0] = fileObj.existing || fileObj.new;
|
|
return path.resolve(FRONTEND_PATH, components.join('/'));
|
|
}
|
|
}
|
|
|
|
function updateBuildGNFile(cssFilesMapping, newModuleSet) {
|
|
let content = fs.readFileSync(BUILD_GN_PATH).toString();
|
|
let newSourcesToAdd = [];
|
|
let partialPathMapping = calculatePartialPathMapping();
|
|
for (let module of MODULES_TO_REMOVE) {
|
|
partialPathMapping.set(`"front_end/${module}/module.json",\n`, '');
|
|
partialPathMapping.set(`"$resources_out_dir/${module}/${module}_module.js",\n`, '');
|
|
}
|
|
const newNonAutostartModules = [...newModuleSet]
|
|
.filter(module => !MODULE_MAPPING[module].autostart)
|
|
.map(module => `"$resources_out_dir/${module}/${module}_module.js",`);
|
|
|
|
let newContent = addContentToLinesInSortedOrder({
|
|
content,
|
|
startLine: 'generated_non_autostart_non_remote_modules = [',
|
|
endLine: ']',
|
|
linesToInsert: newNonAutostartModules,
|
|
});
|
|
|
|
for (let pair of partialPathMapping.entries())
|
|
newContent = newContent.replace(pair[0], pair[1]);
|
|
|
|
newContent = addContentToLinesInSortedOrder({
|
|
content: newContent,
|
|
startLine: 'all_devtools_files = [',
|
|
endLine: ']',
|
|
linesToInsert: newSourcesToAdd.concat([...newModuleSet].map(module => `"front_end/${module}/module.json",`)),
|
|
});
|
|
|
|
fs.writeFileSync(BUILD_GN_PATH, newContent);
|
|
|
|
function calculatePartialPathMapping() {
|
|
let partialPathMapping = new Map();
|
|
for (let fileObj of JS_FILES_MAPPING) {
|
|
let components = fileObj.file.split('/');
|
|
let sourceModule = components[0];
|
|
let targetModule = fileObj.existing || fileObj.new;
|
|
components[0] = targetModule;
|
|
partialPathMapping.set(`"front_end/${fileObj.file}",\n`, '');
|
|
newSourcesToAdd.push(`"front_end/${components.join('/')}",`);
|
|
if (cssFilesMapping.has(fileObj.file)) {
|
|
for (let cssFile of cssFilesMapping.get(fileObj.file)) {
|
|
partialPathMapping.set(`"front_end/${sourceModule}/${cssFile}",\n`, '');
|
|
newSourcesToAdd.push(`"front_end/${targetModule}/${cssFile}",`);
|
|
}
|
|
}
|
|
}
|
|
return partialPathMapping;
|
|
}
|
|
|
|
function top(array) {
|
|
return array[array.length - 1];
|
|
}
|
|
|
|
function addContentToLinesInSortedOrder({content, startLine, endLine, linesToInsert}) {
|
|
if (linesToInsert.length === 0)
|
|
return content;
|
|
let lines = content.split('\n');
|
|
let seenStartLine = false;
|
|
let contentStack = linesToInsert.sort((a, b) => a.toLowerCase().localeCompare(b.toLowerCase())).reverse();
|
|
for (var i = 0; i < lines.length; i++) {
|
|
let line = lines[i].trim();
|
|
let nextLine = lines[i + 1].trim();
|
|
if (line === startLine)
|
|
seenStartLine = true;
|
|
|
|
if (line === endLine && seenStartLine)
|
|
break;
|
|
|
|
if (!seenStartLine)
|
|
continue;
|
|
|
|
const nextContent = top(contentStack) ? top(contentStack).toLowerCase() : '';
|
|
if ((line === startLine || nextContent >= line.toLowerCase()) &&
|
|
(nextLine === endLine || nextContent <= nextLine.toLowerCase()))
|
|
lines.splice(i + 1, 0, contentStack.pop());
|
|
}
|
|
if (contentStack.length)
|
|
lines.splice(i, 0, ...contentStack);
|
|
return lines.join('\n');
|
|
}
|
|
}
|
|
|
|
function mapIdentifiers(identifiersByFile, cssFilesMapping) {
|
|
const filesToTargetModule = new Map();
|
|
for (let fileObj of JS_FILES_MAPPING)
|
|
filesToTargetModule.set(fileObj.file, fileObj.existing || fileObj.new);
|
|
|
|
|
|
const map = new Map();
|
|
for (let [file, identifiers] of identifiersByFile) {
|
|
let targetModule = filesToTargetModule.get(file);
|
|
for (let identifier of identifiers) {
|
|
let components = identifier.split('.');
|
|
components[0] = mapModuleToNamespace(targetModule);
|
|
let newIdentifier = components.join('.');
|
|
map.set(identifier, newIdentifier);
|
|
}
|
|
}
|
|
for (let [jsFile, cssFiles] of cssFilesMapping) {
|
|
let fileObj = JS_FILES_MAPPING.filter(f => f.file === jsFile)[0];
|
|
let sourceModule = fileObj.file.split('/')[0];
|
|
let targetModule = fileObj.existing || fileObj.new;
|
|
for (let cssFile of cssFiles) {
|
|
let key = `${sourceModule}/${cssFile}`;
|
|
let value = `${targetModule}/${cssFile}`;
|
|
map.set(key, value);
|
|
}
|
|
}
|
|
return map;
|
|
}
|
|
|
|
function renameIdentifiers(identifierMap) {
|
|
walkSync('front_end', write, true);
|
|
|
|
walkSync('../../LayoutTests/http/tests/devtools', write, false);
|
|
walkSync('../../LayoutTests/http/tests/inspector-protocol', write, false);
|
|
walkSync('../../LayoutTests/inspector-protocol', write, false);
|
|
|
|
function walkSync(currentDirPath, process, json) {
|
|
fs.readdirSync(currentDirPath).forEach(function(name) {
|
|
let filePath = path.join(currentDirPath, name);
|
|
let stat = fs.statSync(filePath);
|
|
if (stat.isFile() && (filePath.endsWith('.js') || filePath.endsWith('.html') || filePath.endsWith('.xhtml') ||
|
|
filePath.endsWith('-expected.txt') || (json && filePath.endsWith('.json')))) {
|
|
if (filePath.includes('ExtensionAPI.js'))
|
|
return;
|
|
if (filePath.includes('externs.js'))
|
|
return;
|
|
if (filePath.includes('eslint') || filePath.includes('lighthouse-background.js') || filePath.includes('/cm/') ||
|
|
filePath.includes('/xterm.js/') || filePath.includes('/acorn/'))
|
|
return;
|
|
if (filePath.includes('/cm_modes/') && !filePath.includes('DefaultCodeMirror') &&
|
|
!filePath.includes('module.json'))
|
|
return;
|
|
process(filePath);
|
|
} else if (stat.isDirectory()) {
|
|
walkSync(filePath, process, json);
|
|
}
|
|
});
|
|
}
|
|
|
|
function write(filePath) {
|
|
let content = fs.readFileSync(filePath).toString();
|
|
let newContent = content;
|
|
for (let key of identifierMap.keys()) {
|
|
let originalIdentifier = key;
|
|
let newIdentifier = identifierMap.get(key);
|
|
newContent = newContent.replaceAll(originalIdentifier, newIdentifier);
|
|
}
|
|
|
|
if (content !== newContent)
|
|
fs.writeFileSync(filePath, newContent);
|
|
}
|
|
}
|
|
|
|
function removeFromExistingModuleDescriptors(modules, identifierMap, cssFilesMapping) {
|
|
let extensionMap = new Map();
|
|
let moduleFileMap = new Map();
|
|
|
|
for (let fileObj of JS_FILES_MAPPING) {
|
|
let components = fileObj.file.split('/');
|
|
let module = components[0];
|
|
let fileName = components[1];
|
|
|
|
if (!moduleFileMap.get(module))
|
|
moduleFileMap.set(module, []);
|
|
|
|
moduleFileMap.set(module, moduleFileMap.get(module).concat(fileName));
|
|
}
|
|
|
|
for (let module of modules) {
|
|
let moduleJSONPath = path.resolve(FRONTEND_PATH, module, 'module.json');
|
|
let content = fs.readFileSync(moduleJSONPath).toString();
|
|
let moduleObj = parseJSON(content);
|
|
let removedScripts = removeScripts(moduleObj, module);
|
|
removeResources(moduleObj, removedScripts);
|
|
removeExtensions(moduleObj);
|
|
fs.writeFileSync(moduleJSONPath, stringifyJSON(moduleObj));
|
|
}
|
|
|
|
return extensionMap;
|
|
|
|
function removeScripts(moduleObj, module) {
|
|
let remainingScripts = [];
|
|
let removedScripts = [];
|
|
let moduleFiles = moduleFileMap.get(module);
|
|
for (let script of moduleObj.scripts) {
|
|
if (!moduleFiles.includes(script))
|
|
remainingScripts.push(script);
|
|
else
|
|
removedScripts.push(module + '/' + script);
|
|
}
|
|
moduleObj.scripts = remainingScripts;
|
|
return removedScripts;
|
|
}
|
|
|
|
function removeResources(moduleObj, removedScripts) {
|
|
if (!moduleObj.resources)
|
|
return;
|
|
let remainingResources = [];
|
|
let removedResources = new Set();
|
|
for (let script of removedScripts)
|
|
removedResources = removedResources.union(cssFilesMapping.get(script));
|
|
|
|
|
|
for (let resource of moduleObj.resources) {
|
|
if (!removedResources.has(resource))
|
|
remainingResources.push(resource);
|
|
}
|
|
moduleObj.resources = remainingResources;
|
|
}
|
|
|
|
function removeExtensions(moduleObj) {
|
|
if (!moduleObj.extensions)
|
|
return;
|
|
let remainingExtensions = [];
|
|
for (let extension of moduleObj.extensions) {
|
|
if (!objectIncludesIdentifier(extension)) {
|
|
remainingExtensions.push(extension);
|
|
} else {
|
|
if (extensionMap.has(objectIncludesIdentifier(extension))) {
|
|
let existingExtensions = extensionMap.get(objectIncludesIdentifier(extension));
|
|
extensionMap.set(objectIncludesIdentifier(extension), existingExtensions.concat(extension));
|
|
} else {
|
|
extensionMap.set(objectIncludesIdentifier(extension), [extension]);
|
|
}
|
|
}
|
|
}
|
|
moduleObj.extensions = remainingExtensions;
|
|
}
|
|
|
|
function objectIncludesIdentifier(object) {
|
|
for (let key in object) {
|
|
let value = object[key];
|
|
if (identifierMap.has(value))
|
|
return value;
|
|
}
|
|
return false;
|
|
}
|
|
}
|
|
|
|
function createNewModuleDescriptors(extensionMap, cssFilesMapping, identifiersByFile, targetToOriginalFilesMap) {
|
|
let filesByNewModule = getFilesByNewModule();
|
|
|
|
for (let module of filesByNewModule.keys()) {
|
|
let moduleObj = {};
|
|
|
|
let scripts = getModuleScripts(module);
|
|
let extensions = getModuleExtensions(scripts, module);
|
|
if (extensions.length)
|
|
moduleObj.extensions = extensions;
|
|
|
|
moduleObj.dependencies = DEPENDENCIES_BY_MODULE[module];
|
|
|
|
moduleObj.scripts = scripts;
|
|
|
|
let resources = getModuleResources(moduleObj.scripts, module);
|
|
if (resources.length)
|
|
moduleObj.resources = resources;
|
|
|
|
let moduleJSONPath = path.resolve(FRONTEND_PATH, module, 'module.json');
|
|
fs.writeFileSync(moduleJSONPath, stringifyJSON(moduleObj));
|
|
}
|
|
|
|
function getFilesByNewModule() {
|
|
let filesByNewModule = new Map();
|
|
for (let fileObj of JS_FILES_MAPPING) {
|
|
if (!fileObj.new)
|
|
continue;
|
|
if (!filesByNewModule.has(fileObj.new))
|
|
filesByNewModule.set(fileObj.new, []);
|
|
|
|
filesByNewModule.set(fileObj.new, filesByNewModule.get(fileObj.new).concat([fileObj.file]));
|
|
}
|
|
return filesByNewModule;
|
|
}
|
|
|
|
function getModuleScripts(module) {
|
|
return filesByNewModule.get(module).map((file) => file.split('/')[1]);
|
|
}
|
|
|
|
function getModuleResources(scripts, module) {
|
|
let resources = [];
|
|
scripts.map(script => module + '/' + script).forEach((script) => {
|
|
script = targetToOriginalFilesMap.get(script);
|
|
if (!cssFilesMapping.has(script))
|
|
return;
|
|
|
|
resources = resources.concat([...cssFilesMapping.get(script)]);
|
|
});
|
|
return resources;
|
|
}
|
|
|
|
function getModuleExtensions(scripts, module) {
|
|
let extensions = [];
|
|
let identifiers =
|
|
scripts.map(script => module + '/' + script)
|
|
.reduce((acc, file) => acc.concat(identifiersByFile.get(targetToOriginalFilesMap.get(file))), []);
|
|
for (let identifier of identifiers) {
|
|
if (extensionMap.has(identifier))
|
|
extensions = extensions.concat(extensionMap.get(identifier));
|
|
}
|
|
return extensions;
|
|
}
|
|
}
|
|
|
|
function calculateFilesByModuleType(type) {
|
|
let filesByNewModule = new Map();
|
|
for (let fileObj of JS_FILES_MAPPING) {
|
|
if (!fileObj[type])
|
|
continue;
|
|
if (!filesByNewModule.has(fileObj[type]))
|
|
filesByNewModule.set(fileObj[type], []);
|
|
|
|
filesByNewModule.set(fileObj[type], filesByNewModule.get(fileObj[type]).concat([fileObj.file]));
|
|
}
|
|
return filesByNewModule;
|
|
}
|
|
|
|
function updateExistingModuleDescriptors(extensionMap, cssFilesMapping, identifiersByFile, targetToOriginalFilesMap) {
|
|
let filesByExistingModule = calculateFilesByModuleType('existing');
|
|
for (let module of filesByExistingModule.keys()) {
|
|
let moduleJSONPath = path.resolve(FRONTEND_PATH, module, 'module.json');
|
|
let content = fs.readFileSync(moduleJSONPath).toString();
|
|
let moduleObj = parseJSON(content);
|
|
|
|
let scripts = getModuleScripts(module);
|
|
let existingExtensions = moduleObj.extensions || [];
|
|
let extensions = existingExtensions.concat(getModuleExtensions(scripts, module));
|
|
if (extensions.length)
|
|
moduleObj.extensions = extensions;
|
|
|
|
moduleObj.scripts = moduleObj.scripts.concat(scripts);
|
|
|
|
let existingResources = moduleObj.resources || [];
|
|
let resources = existingResources.concat(getModuleResources(scripts, module));
|
|
if (resources.length)
|
|
moduleObj.resources = resources;
|
|
|
|
fs.writeFileSync(moduleJSONPath, stringifyJSON(moduleObj));
|
|
}
|
|
|
|
|
|
function getModuleScripts(module) {
|
|
return filesByExistingModule.get(module).map((file) => file.split('/')[1]);
|
|
}
|
|
|
|
function getModuleResources(scripts, module) {
|
|
let resources = [];
|
|
scripts.map(script => module + '/' + script).forEach((script) => {
|
|
script = targetToOriginalFilesMap.get(script);
|
|
if (!cssFilesMapping.has(script))
|
|
return;
|
|
|
|
resources = resources.concat([...cssFilesMapping.get(script)]);
|
|
});
|
|
return resources;
|
|
}
|
|
|
|
function getModuleExtensions(scripts, module) {
|
|
let extensions = [];
|
|
let identifiers =
|
|
scripts.map(script => module + '/' + script)
|
|
.reduce((acc, file) => acc.concat(identifiersByFile.get(targetToOriginalFilesMap.get(file))), []);
|
|
for (let identifier of identifiers) {
|
|
if (extensionMap.has(identifier))
|
|
extensions = extensions.concat(extensionMap.get(identifier));
|
|
}
|
|
return extensions;
|
|
}
|
|
}
|
|
|
|
function addDependenciesToDescriptors() {
|
|
for (let module of getModules()) {
|
|
let moduleJSONPath = path.resolve(FRONTEND_PATH, module, 'module.json');
|
|
let content = fs.readFileSync(moduleJSONPath).toString();
|
|
let moduleObj = parseJSON(content);
|
|
|
|
let existingDependencies = moduleObj.dependencies || [];
|
|
let dependencies =
|
|
existingDependencies.concat(getModuleDependencies(module))
|
|
.filter((depModule) => !MODULES_TO_REMOVE.includes(depModule))
|
|
.filter((depModule) => !(REMOVE_DEPENDENCIES_BY_EXISTING_MODULES[module] || []).includes(depModule));
|
|
let newDependenciesForExistingModule = NEW_DEPENDENCIES_BY_EXISTING_MODULES[module];
|
|
if (newDependenciesForExistingModule)
|
|
dependencies = dependencies.concat(newDependenciesForExistingModule);
|
|
if (dependencies.length)
|
|
moduleObj.dependencies = dependencies;
|
|
let newStringified = stringifyJSON(moduleObj);
|
|
if (stringifyJSON(moduleObj) !== stringifyJSON(parseJSON(content)))
|
|
fs.writeFileSync(moduleJSONPath, newStringified);
|
|
}
|
|
|
|
function getModuleDependencies(existingModule) {
|
|
let newDeps = [];
|
|
for (let newModule in DEPENDENTS_BY_MODULE) {
|
|
let dependents = DEPENDENTS_BY_MODULE[newModule];
|
|
if (dependents.includes(existingModule))
|
|
newDeps.push(newModule);
|
|
}
|
|
return newDeps;
|
|
}
|
|
}
|
|
|
|
function updateApplicationDescriptor(descriptorFileName, newModuleSet) {
|
|
let descriptorPath = path.join(FRONTEND_PATH, descriptorFileName);
|
|
let newModules = [...newModuleSet].filter(m => APPLICATIONS_BY_MODULE[m].includes(descriptorFileName));
|
|
if (newModules.length === 0)
|
|
return;
|
|
let includeNewModules = (acc, line) => {
|
|
if (line.includes('{') && line.endsWith('}')) {
|
|
line += ',';
|
|
acc.push(line);
|
|
return acc.concat(newModules.map((m, i) => {
|
|
// Need spacing to preserve indentation
|
|
let string;
|
|
if (MODULE_MAPPING[m].autostart)
|
|
string = ` { "name": "${m}", "type": "autostart" }`;
|
|
else
|
|
string = ` { "name": "${m}" }`;
|
|
if (i !== newModules.length - 1)
|
|
string += ',';
|
|
return string;
|
|
}));
|
|
}
|
|
return acc.concat([line]);
|
|
};
|
|
let removeModules = (acc, line) => MODULES_TO_REMOVE.every(m => !line.includes(m)) ? acc.concat([line]) : acc;
|
|
let lines =
|
|
fs.readFileSync(descriptorPath).toString().split('\n').reduce(includeNewModules, []).reduce(removeModules, []);
|
|
fs.writeFileSync(descriptorPath, lines.join('\n'));
|
|
}
|
|
|
|
function getModules() {
|
|
return fs.readdirSync(FRONTEND_PATH).filter(function(file) {
|
|
return fs.statSync(path.join(FRONTEND_PATH, file)).isDirectory() &&
|
|
utils.isFile(path.join(FRONTEND_PATH, file, 'module.json'));
|
|
});
|
|
}
|
|
|
|
function parseJSON(string) {
|
|
return JSON.parse(string);
|
|
}
|
|
|
|
function stringifyJSON(obj) {
|
|
return unicodeEscape(JSON.stringify(obj, null, 4) + '\n');
|
|
}
|
|
|
|
// http://stackoverflow.com/questions/7499473/need-to-escape-non-ascii-characters-in-javascript
|
|
function unicodeEscape(string) {
|
|
function padWithLeadingZeros(string) {
|
|
return new Array(5 - string.length).join('0') + string;
|
|
}
|
|
|
|
function unicodeCharEscape(charCode) {
|
|
return '\\u' + padWithLeadingZeros(charCode.toString(16));
|
|
}
|
|
|
|
return string.split('')
|
|
.map(function(char) {
|
|
var charCode = char.charCodeAt(0);
|
|
return charCode > 127 ? unicodeCharEscape(charCode) : char;
|
|
})
|
|
.join('');
|
|
}
|
|
|
|
if (require.main === module)
|
|
extractModule();
|