UNPKG

14.4 kBJavaScriptView Raw
1"use strict";
2/**
3 * @license
4 * Copyright Google Inc. All Rights Reserved.
5 *
6 * Use of this source code is governed by an MIT-style license that can be
7 * found in the LICENSE file at https://angular.io/license
8 */
9Object.defineProperty(exports, "__esModule", { value: true });
10exports.isWarningEnabled = exports.getSchematicDefaults = exports.migrateLegacyGlobalConfig = exports.getConfiguredPackageManager = exports.getProjectByCwd = exports.validateWorkspace = exports.getWorkspaceRaw = exports.createGlobalSettings = exports.getWorkspace = exports.AngularWorkspace = exports.workspaceSchemaPath = void 0;
11const core_1 = require("@angular-devkit/core");
12const node_1 = require("@angular-devkit/core/node");
13const fs_1 = require("fs");
14const os = require("os");
15const path = require("path");
16const find_up_1 = require("./find-up");
17function isJsonObject(value) {
18 return value !== undefined && core_1.json.isJsonObject(value);
19}
20function getSchemaLocation() {
21 return path.join(__dirname, '../lib/config/schema.json');
22}
23exports.workspaceSchemaPath = getSchemaLocation();
24const configNames = ['angular.json', '.angular.json'];
25const globalFileName = '.angular-config.json';
26function xdgConfigHome(home, configFile) {
27 // https://specifications.freedesktop.org/basedir-spec/basedir-spec-latest.html
28 const p = process.env['XDG_CONFIG_HOME'] || path.join(home, '.config', 'angular');
29 return configFile ? path.join(p, configFile) : p;
30}
31function projectFilePath(projectPath) {
32 // Find the configuration, either where specified, in the Angular CLI project
33 // (if it's in node_modules) or from the current process.
34 return ((projectPath && find_up_1.findUp(configNames, projectPath)) ||
35 find_up_1.findUp(configNames, process.cwd()) ||
36 find_up_1.findUp(configNames, __dirname));
37}
38function globalFilePath() {
39 const home = os.homedir();
40 if (!home) {
41 return null;
42 }
43 // follow XDG Base Directory spec
44 // note that createGlobalSettings() will continue creating
45 // global file in home directory, with this user will have
46 // choice to move change its location to meet XDG convention
47 const xdgConfig = xdgConfigHome(home, globalFileName);
48 if (fs_1.existsSync(xdgConfig)) {
49 return xdgConfig;
50 }
51 const p = path.join(home, globalFileName);
52 if (fs_1.existsSync(p)) {
53 return p;
54 }
55 return null;
56}
57class AngularWorkspace {
58 constructor(workspace, filePath) {
59 this.workspace = workspace;
60 this.filePath = filePath;
61 this.basePath = path.dirname(filePath);
62 }
63 get extensions() {
64 return this.workspace.extensions;
65 }
66 get projects() {
67 return this.workspace.projects;
68 }
69 // Temporary helper functions to support refactoring
70 // tslint:disable-next-line: no-any
71 getCli() {
72 return this.workspace.extensions['cli'] || {};
73 }
74 // tslint:disable-next-line: no-any
75 getProjectCli(projectName) {
76 const project = this.workspace.projects.get(projectName);
77 return (project === null || project === void 0 ? void 0 : project.extensions['cli']) || {};
78 }
79}
80exports.AngularWorkspace = AngularWorkspace;
81const cachedWorkspaces = new Map();
82async function getWorkspace(level = 'local') {
83 const cached = cachedWorkspaces.get(level);
84 if (cached !== undefined) {
85 return cached;
86 }
87 const configPath = level === 'local' ? projectFilePath() : globalFilePath();
88 if (!configPath) {
89 cachedWorkspaces.set(level, null);
90 return null;
91 }
92 try {
93 const result = await core_1.workspaces.readWorkspace(configPath, core_1.workspaces.createWorkspaceHost(new node_1.NodeJsSyncHost()), core_1.workspaces.WorkspaceFormat.JSON);
94 const workspace = new AngularWorkspace(result.workspace, configPath);
95 cachedWorkspaces.set(level, workspace);
96 return workspace;
97 }
98 catch (error) {
99 throw new Error(`Workspace config file cannot be loaded: ${configPath}` +
100 `\n${error instanceof Error ? error.message : error}`);
101 }
102}
103exports.getWorkspace = getWorkspace;
104function createGlobalSettings() {
105 const home = os.homedir();
106 if (!home) {
107 throw new Error('No home directory found.');
108 }
109 const globalPath = path.join(home, globalFileName);
110 fs_1.writeFileSync(globalPath, JSON.stringify({ version: 1 }));
111 return globalPath;
112}
113exports.createGlobalSettings = createGlobalSettings;
114function getWorkspaceRaw(level = 'local') {
115 let configPath = level === 'local' ? projectFilePath() : globalFilePath();
116 if (!configPath) {
117 if (level === 'global') {
118 configPath = createGlobalSettings();
119 }
120 else {
121 return [null, null];
122 }
123 }
124 const data = fs_1.readFileSync(configPath);
125 let start = 0;
126 if (data.length > 3 && data[0] === 0xef && data[1] === 0xbb && data[2] === 0xbf) {
127 // Remove BOM
128 start = 3;
129 }
130 const content = data.toString('utf-8', start);
131 const ast = core_1.parseJsonAst(content, core_1.JsonParseMode.Loose);
132 if (ast.kind != 'object') {
133 throw new Error(`Invalid JSON file: ${configPath}`);
134 }
135 return [ast, configPath];
136}
137exports.getWorkspaceRaw = getWorkspaceRaw;
138async function validateWorkspace(data) {
139 const schemaContent = fs_1.readFileSync(path.join(__dirname, '..', 'lib', 'config', 'schema.json'), 'utf-8');
140 const schema = core_1.parseJson(schemaContent, core_1.JsonParseMode.Loose);
141 const { formats } = await Promise.resolve().then(() => require('@angular-devkit/schematics'));
142 const registry = new core_1.json.schema.CoreSchemaRegistry(formats.standardFormats);
143 const validator = await registry.compile(schema).toPromise();
144 const { success, errors } = await validator(data).toPromise();
145 if (!success) {
146 throw new core_1.json.schema.SchemaValidationException(errors);
147 }
148}
149exports.validateWorkspace = validateWorkspace;
150function getProjectByPath(workspace, location) {
151 const isInside = (base, potential) => {
152 const absoluteBase = path.resolve(workspace.basePath, base);
153 const absolutePotential = path.resolve(workspace.basePath, potential);
154 const relativePotential = path.relative(absoluteBase, absolutePotential);
155 if (!relativePotential.startsWith('..') && !path.isAbsolute(relativePotential)) {
156 return true;
157 }
158 return false;
159 };
160 const projects = Array.from(workspace.projects)
161 .map(([name, project]) => [project.root, name])
162 .filter((tuple) => isInside(tuple[0], location))
163 // Sort tuples by depth, with the deeper ones first. Since the first member is a path and
164 // we filtered all invalid paths, the longest will be the deepest (and in case of equality
165 // the sort is stable and the first declared project will win).
166 .sort((a, b) => b[0].length - a[0].length);
167 if (projects.length === 0) {
168 return null;
169 }
170 else if (projects.length > 1) {
171 const found = new Set();
172 const sameRoots = projects.filter((v) => {
173 if (!found.has(v[0])) {
174 found.add(v[0]);
175 return false;
176 }
177 return true;
178 });
179 if (sameRoots.length > 0) {
180 // Ambiguous location - cannot determine a project
181 return null;
182 }
183 }
184 return projects[0][1];
185}
186function getProjectByCwd(workspace) {
187 if (workspace.projects.size === 1) {
188 // If there is only one project, return that one.
189 return Array.from(workspace.projects.keys())[0];
190 }
191 const project = getProjectByPath(workspace, process.cwd());
192 if (project) {
193 return project;
194 }
195 const defaultProject = workspace.extensions['defaultProject'];
196 if (defaultProject && typeof defaultProject === 'string') {
197 // If there is a default project name, return it.
198 return defaultProject;
199 }
200 return null;
201}
202exports.getProjectByCwd = getProjectByCwd;
203async function getConfiguredPackageManager() {
204 var _a;
205 const getPackageManager = (source) => {
206 if (isJsonObject(source)) {
207 const value = source['packageManager'];
208 if (value && typeof value === 'string') {
209 return value;
210 }
211 }
212 };
213 let result;
214 const workspace = await getWorkspace('local');
215 if (workspace) {
216 const project = getProjectByCwd(workspace);
217 if (project) {
218 result = getPackageManager((_a = workspace.projects.get(project)) === null || _a === void 0 ? void 0 : _a.extensions['cli']);
219 }
220 result = result !== null && result !== void 0 ? result : getPackageManager(workspace.extensions['cli']);
221 }
222 if (result === undefined) {
223 const globalOptions = await getWorkspace('global');
224 result = getPackageManager(globalOptions === null || globalOptions === void 0 ? void 0 : globalOptions.extensions['cli']);
225 if (!workspace && !globalOptions) {
226 // Only check legacy if updated workspace is not found
227 result = getLegacyPackageManager();
228 }
229 }
230 // Default to null
231 return result !== null && result !== void 0 ? result : null;
232}
233exports.getConfiguredPackageManager = getConfiguredPackageManager;
234function migrateLegacyGlobalConfig() {
235 const homeDir = os.homedir();
236 if (homeDir) {
237 const legacyGlobalConfigPath = path.join(homeDir, '.angular-cli.json');
238 if (fs_1.existsSync(legacyGlobalConfigPath)) {
239 const content = fs_1.readFileSync(legacyGlobalConfigPath, 'utf-8');
240 const legacy = core_1.parseJson(content, core_1.JsonParseMode.Loose);
241 if (!isJsonObject(legacy)) {
242 return false;
243 }
244 const cli = {};
245 if (legacy.packageManager &&
246 typeof legacy.packageManager == 'string' &&
247 legacy.packageManager !== 'default') {
248 cli['packageManager'] = legacy.packageManager;
249 }
250 if (isJsonObject(legacy.defaults) &&
251 isJsonObject(legacy.defaults.schematics) &&
252 typeof legacy.defaults.schematics.collection == 'string') {
253 cli['defaultCollection'] = legacy.defaults.schematics.collection;
254 }
255 if (isJsonObject(legacy.warnings)) {
256 const warnings = {};
257 if (typeof legacy.warnings.versionMismatch == 'boolean') {
258 warnings['versionMismatch'] = legacy.warnings.versionMismatch;
259 }
260 if (Object.getOwnPropertyNames(warnings).length > 0) {
261 cli['warnings'] = warnings;
262 }
263 }
264 if (Object.getOwnPropertyNames(cli).length > 0) {
265 const globalPath = path.join(homeDir, globalFileName);
266 fs_1.writeFileSync(globalPath, JSON.stringify({ version: 1, cli }, null, 2));
267 return true;
268 }
269 }
270 }
271 return false;
272}
273exports.migrateLegacyGlobalConfig = migrateLegacyGlobalConfig;
274// Fallback, check for packageManager in config file in v1.* global config.
275function getLegacyPackageManager() {
276 const homeDir = os.homedir();
277 if (homeDir) {
278 const legacyGlobalConfigPath = path.join(homeDir, '.angular-cli.json');
279 if (fs_1.existsSync(legacyGlobalConfigPath)) {
280 const content = fs_1.readFileSync(legacyGlobalConfigPath, 'utf-8');
281 const legacy = core_1.parseJson(content, core_1.JsonParseMode.Loose);
282 if (!isJsonObject(legacy)) {
283 return null;
284 }
285 if (legacy.packageManager &&
286 typeof legacy.packageManager === 'string' &&
287 legacy.packageManager !== 'default') {
288 return legacy.packageManager;
289 }
290 }
291 }
292 return null;
293}
294async function getSchematicDefaults(collection, schematic, project) {
295 var _a;
296 const result = {};
297 const mergeOptions = (source) => {
298 if (isJsonObject(source)) {
299 // Merge options from the qualified name
300 Object.assign(result, source[`${collection}:${schematic}`]);
301 // Merge options from nested collection schematics
302 const collectionOptions = source[collection];
303 if (isJsonObject(collectionOptions)) {
304 Object.assign(result, collectionOptions[schematic]);
305 }
306 }
307 };
308 // Global level schematic options
309 const globalOptions = await getWorkspace('global');
310 mergeOptions(globalOptions === null || globalOptions === void 0 ? void 0 : globalOptions.extensions['schematics']);
311 const workspace = await getWorkspace('local');
312 if (workspace) {
313 // Workspace level schematic options
314 mergeOptions(workspace.extensions['schematics']);
315 project = project || getProjectByCwd(workspace);
316 if (project) {
317 // Project level schematic options
318 mergeOptions((_a = workspace.projects.get(project)) === null || _a === void 0 ? void 0 : _a.extensions['schematics']);
319 }
320 }
321 return result;
322}
323exports.getSchematicDefaults = getSchematicDefaults;
324async function isWarningEnabled(warning) {
325 var _a;
326 const getWarning = (source) => {
327 if (isJsonObject(source)) {
328 const warnings = source['warnings'];
329 if (isJsonObject(warnings)) {
330 const value = warnings[warning];
331 if (typeof value == 'boolean') {
332 return value;
333 }
334 }
335 }
336 };
337 let result;
338 const workspace = await getWorkspace('local');
339 if (workspace) {
340 const project = getProjectByCwd(workspace);
341 if (project) {
342 result = getWarning((_a = workspace.projects.get(project)) === null || _a === void 0 ? void 0 : _a.extensions['cli']);
343 }
344 result = result !== null && result !== void 0 ? result : getWarning(workspace.extensions['cli']);
345 }
346 if (result === undefined) {
347 const globalOptions = await getWorkspace('global');
348 result = getWarning(globalOptions === null || globalOptions === void 0 ? void 0 : globalOptions.extensions['cli']);
349 }
350 // All warnings are enabled by default
351 return result !== null && result !== void 0 ? result : true;
352}
353exports.isWarningEnabled = isWarningEnabled;