本文目录导读:

是的,Schematics(尤其是在 Angular 和现代 Web 开发上下文中)支持嵌套对象。
核心机制是:使用 JsonPointer(JSON 指针)语法来指定嵌套属性的路径。
在 Schematics 中,当你操作一个 JsonObject(package.json 或 angular.json)时,你可以通过路径字符串来访问或修改深层嵌套的属性,这个路径字符串遵循 JSON Pointer 标准,使用斜杠 分隔每一层级。
具体支持的方式:
- 路径表达式:使用
'key/subkey/subsubkey'的格式。 - 属性操作:
get、set、remove、append等操作都支持路径字符串。
示例(修改 package.json 中的嵌套对象)
假设 tree 是 Tree 对象,host 是 Host 对象。
场景 1:读取嵌套值
// 假设 package.json 中有:
// {
// "builders": {
// "my-builder": {
// "implementation": "./dist/my-builder.js"
// }
// }
// }
const packageJson = host.readJson('package.json') as any;
// 直接通过属性链访问嵌套对象
const builderImpl = packageJson.builders?.['my-builder']?.implementation;
console.log(builderImpl); // 输出: ./dist/my-builder.js
场景 2:使用路径修改嵌套值(推荐方式)
import { JsonArray, JsonObject, workspaces } from '@angular-devkit/core';
function updateNestedConfig(host: workspaces.WorkspaceHost) {
const config = host.readJson('angular.json') as JsonObject;
// 路径 'projects.my-app.architect.build.options.outputPath'
// 指向 angular.json 中:
// projects -> my-app -> architect -> build -> options -> outputPath 的值
const currentPath = config['projects']['my-app']['architect']['build']['options']['outputPath'];
// 或者使用更安全的方式(需要自己实现递归查找)
const newConfig = {
...config,
projects: {
...config['projects'],
'my-app': {
...(config['projects'] as any)['my-app'],
architect: {
...(config['projects'] as any)['my-app']?.['architect'],
build: {
...(config['projects'] as any)['my-app']?.['architect']?.['build'],
options: {
...(config['projects'] as any)['my-app']?.['architect']?.['build']?.options,
outputPath: 'dist/my-new-output'
}
}
}
}
}
};
host.overwrite('angular.json', JSON.stringify(newConfig, null, 2));
}
场景 3:使用 JsonPointer 库(更简洁)
Schematics 内部依赖 jsonc-parser,但它也支持 @angular-devkit/core 中的 JsonPointer 类(虽然不常用作 API)。
实际更常见的做法是:手动递归或使用 Lodash 的 set/get 函数。
// 如果项目中安装了 lodash(或使用 set/get 函数)
import * as _ from 'lodash';
function setNestedValue(obj: any, path: string, value: any) {
// path = "projects.my-app.architect.build.options.outputPath" (点号分隔)
// 或者 path = "projects/my-app/architect/build/options/outputPath" (斜杠分隔,需转换)
const pathArray = path.replace(/\//g, '.').split('.');
_.set(obj, pathArray, value);
}
// 使用
const config = host.readJson('angular.json') as any;
setNestedValue(config, 'projects.my-app.architect.build.options.outputPath', 'dist/new-path');
host.overwrite('angular.json', JSON.stringify(config, null, 2));
| 特性 | 说明 |
|---|---|
| 支持类型 | 任何可以被序列化为 JSON 的对象(Object、Array、基本类型) |
| 路径语法 | 使用点号 或斜杠 作为分隔符(在 JSON Pointer 中是 ,但在 JS 中常用 ) |
| 数组支持 | 支持通过索引访问数组元素,'arrayProp.0.name' 或 'arrayProp/0/name' |
| 安全注意事项 | 路径中的每一级都必须存在,如果中间级不存在,需要自行创建对象或使用 _.set 等库 |
实际示例:修改 angular.json 中的 project 配置
这是一个 Schematics 中非常常见的操作:
// schematic 规则
export function mySchematic(options: any): Rule {
return (tree: Tree, context: SchematicContext) => {
// 读取 angular.json
const angularJsonBuffer = tree.read('angular.json');
if (!angularJsonBuffer) {
context.logger.error('Could not read angular.json file.');
return tree;
}
const angularJson = JSON.parse(angularJsonBuffer.toString());
// 嵌套操作:修改某个项目的 builder 的 options
const projectName = options.project || 'defaultProject';
if (angularJson.projects && angularJson.projects[projectName]) {
// 确保嵌套路径存在
if (!angularJson.projects[projectName].architect) {
angularJson.projects[projectName].architect = {};
}
if (!angularJson.projects[projectName].architect.build) {
angularJson.projects[projectName].architect.build = {};
}
if (!angularJson.projects[projectName].architect.build.options) {
angularJson.projects[projectName].architect.build.options = {};
}
// 修改嵌套属性
angularJson.projects[projectName].architect.build.options.outputPath = options.outputPath || 'dist/my-app';
}
// 写回文件
tree.overwrite('angular.json', JSON.stringify(angularJson, null, 2));
return tree;
};
}
社区和库支持
@angular-devkit/core:提供JsonObject和JsonArray类型,但不提供内置的简洁嵌套路径 API。jsonc-parser:Schematics 内部使用,可以处理带注释的 JSON,但访问嵌套属性仍需手动。- 推荐:在自定义 Schematics 中,直接使用 JavaScript 的原生对象操作(如
obj.a.b.c)或lodash.set/lodash.get是最清晰、最简洁的方式。
Schematics 完全支持嵌套对象,但需要你通过标准的 JavaScript 对象操作或辅助库来实现嵌套路径的访问与修改,框架本身没有提供一种特殊的“嵌套对象路径 DSL”(领域特定语言),但操作普通的嵌入式对象在 JavaScript 中非常直接。