@angular-devkit/core
Version:
Angular DevKit - Core Utility Library
145 lines (144 loc) • 5.12 kB
JavaScript
/**
* @license
* Copyright Google LLC All Rights Reserved.
*
* Use of this source code is governed by an MIT-style license that can be
* found in the LICENSE file at https://angular.dev/license
*/
Object.defineProperty(exports, "__esModule", { value: true });
exports.writeJsonWorkspace = writeJsonWorkspace;
const jsonc_parser_1 = require("jsonc-parser");
const node_os_1 = require("node:os");
const metadata_1 = require("./metadata");
async function writeJsonWorkspace(workspace, host, path, options = {}) {
const metadata = workspace[metadata_1.JsonWorkspaceSymbol];
if (metadata) {
if (!metadata.hasChanges) {
return;
}
// update existing JSON workspace
const data = updateJsonWorkspace(metadata);
return host.writeFile(path ?? metadata.filePath, data);
}
else {
// serialize directly
if (!path) {
throw new Error('path option is required');
}
const obj = convertJsonWorkspace(workspace, options.schema);
const data = JSON.stringify(obj, null, 2);
return host.writeFile(path, data);
}
}
function convertJsonWorkspace(workspace, schema) {
const obj = {
$schema: schema || './node_modules/@angular/cli/lib/config/schema.json',
version: 1,
...workspace.extensions,
...(isEmpty(workspace.projects)
? {}
: { projects: convertJsonProjectCollection(workspace.projects) }),
};
return obj;
}
function convertJsonProjectCollection(collection) {
const projects = Object.create(null);
for (const [projectName, project] of collection) {
projects[projectName] = convertJsonProject(project);
}
return projects;
}
function convertJsonProject(project) {
let targets;
if (project.targets.size > 0) {
targets = Object.create(null);
for (const [targetName, target] of project.targets) {
targets[targetName] = convertJsonTarget(target);
}
}
const obj = {
...project.extensions,
root: project.root,
...(project.sourceRoot === undefined ? {} : { sourceRoot: project.sourceRoot }),
...(project.prefix === undefined ? {} : { prefix: project.prefix }),
...(targets === undefined ? {} : { architect: targets }),
};
return obj;
}
function isEmpty(obj) {
return obj === undefined || Object.keys(obj).length === 0;
}
function convertJsonTarget(target) {
return {
builder: target.builder,
...(isEmpty(target.options) ? {} : { options: target.options }),
...(isEmpty(target.configurations)
? {}
: { configurations: target.configurations }),
...(target.defaultConfiguration === undefined
? {}
: { defaultConfiguration: target.defaultConfiguration }),
};
}
function convertJsonTargetCollection(collection) {
const targets = Object.create(null);
for (const [projectName, target] of collection) {
targets[projectName] = convertJsonTarget(target);
}
return targets;
}
function normalizeValue(value, type) {
if (value === undefined) {
return undefined;
}
switch (type) {
case 'project':
return convertJsonProject(value);
case 'projectcollection': {
const projects = convertJsonProjectCollection(value);
return isEmpty(projects) ? undefined : projects;
}
case 'target':
return convertJsonTarget(value);
case 'targetcollection': {
const targets = convertJsonTargetCollection(value);
return isEmpty(targets) ? undefined : targets;
}
default:
return value;
}
}
function updateJsonWorkspace(metadata) {
let { raw: content } = metadata;
const { changes, hasLegacyTargetsName } = metadata;
for (const { jsonPath, value, type } of changes.values()) {
// Determine which key to use if (architect or targets)
if (hasLegacyTargetsName && jsonPath[2] === 'targets') {
jsonPath[2] = 'architect';
}
// TODO: `modify` re-parses the content every time.
// See: https://github.com/microsoft/node-jsonc-parser/blob/35d94cd71bd48f9784453b2439262c938e21d49b/src/impl/edit.ts#L18
// Ideally this should accept a string or an AST to avoid the potentially expensive repeat parsing operation.
const edits = (0, jsonc_parser_1.modify)(content, jsonPath, normalizeValue(value, type), {
formattingOptions: {
insertSpaces: true,
tabSize: 2,
eol: getEOL(content),
},
});
content = (0, jsonc_parser_1.applyEdits)(content, edits);
}
return content;
}
function getEOL(content) {
const CRLF = '\r\n';
const LF = '\n';
const newlines = content.match(/(?:\r?\n)/g);
if (newlines?.length) {
const crlf = newlines.filter((l) => l === CRLF).length;
const lf = newlines.length - crlf;
return crlf > lf ? CRLF : LF;
}
return node_os_1.EOL;
}
;