applyPostTransforms should not be applied for all builder schemas
- Ngôn ngữ chính
- TypeScript
- Star
- 27k
- Fork
- 11.8k
- Merge trung bình
- 14 giờ 23 phút
- Pull request đã merge (30 ngày)
- 162
Mô tả
# 🚀 Feature request
### Command (mark with an `x`)
```
- [ ] new
- [ ] build
- [ ] serve
- [ ] test
- [ ] e2e
- [ ] generate
- [ ] add
- [ ] update
- [ ] lint
- [ ] xi18n
- [x] run
- [ ] config
- [ ] help
- [ ] version
- [ ] doc
```
### Description
I am currently writing a builder and the appropriate JSON schema to validate its options.
The builder will be used in different targets, but all of these targets _usually_ share some base options which is why I added some target reference support, similar to the `browserTarget`
option of the `@angular-devkit/build-angular:dev-server` builder.
An example config could look like this:
"target1": {
"builder": "mybuilder:f":
"options": {
"a": "foo",
"b": {
"asd": "wer"
}
}
},
"target2": {
"builder": "mybuilder:f":
"options": {
"targetRef": "myproject:target1", // References the options of target1 above
"a": "bar"
}
},
So, at the end the options of `target2` should be evaluated to the following:
{
"a": "bar",
"b": {
"asd": "wer"
}
}
This should be as simple as using some Object.assign code:
const target2Options = { "a": "bar" };
const target1Options = { "a": "foo", "b": { "asd": "wer" } };
const result = Object.assign({}, target1Options, target2Options);
But the problem is, that Angular modifies the incoming options-object. It passes in an empty object for the `b` property of `target2`'s options: `{ "a": "bar", "b": {} }`. Thus, `result.b` will be `{}` instead of `{ "asd": "wer" }`.
This is done by the Angular's postTransform `addUndefinedDefaults` which is always added to the `CoreSchemaRegistry`. In theory postTransforms can be disabled as seen [here](https://github.com/angular/angular-cli/blob/48e6060e02792cd614a1f80ae8b87109df88c893/packages/angular_devkit/core/src/json/schema/registry.ts#L337L339) using `applyPostTransforms: false`. However, it is not possible to override this value when the builder's schema is compiled and the validator is used, see [here](https://github.com/angular/angular-cli/blob/master/packages/angular_devkit/architect/src/architect.ts#L63) (no second argument is passed to `validation`).
Of course, I could add some code to my builder that checks for that `{}` and ignores it. But actually, it should be possible to explicitly set `b: {}` to override the inherited value, e.g.:
"target3": {
"builder": "mybuilder:f":
"options": {
"targetRef": "myproject:target1",
"b": {}
}
},
So I really need to distinguish between the `{}` set by the user and the `{}` set by the postTransform.
NOTE: All of this affects options that are set to type `object` or `array` (in which case `[]` is used as default) in the schema.
### Describe the solution you'd like
It would be nice to be able to disable postTransforms for a specific builder, for example in the builder code itself.
Actually I do not know why the `addUndefinedDefaults` transform is used at all, but there is probably a reason for that. Is it? 😛
### Describe alternatives you've considered
I cannot imagine any workarounds. Angular modifies the options passed to a builder where it should not, IMHO. In the above case, the user does not specified a `b` property, but Angular passes in an empty object for `b`. And currently there is no way to change that behavior, as far as I can see.
EDIT:
I did find a workaround, but it is an ugly hack as it relies on the internals of `addUndefinedDefault` and thus could easily break when Angular is updated.
Instead of this schema:
"b": {
"type": "object",
"additionalProperties": {
"type": "string"
}
}
One can use this schema:
"b": {
"oneOf": [
{
"type": "null"
},
{
"type": "object",
"additionalProperties": {
"type": "string"
}
}
]
}
This works, because Angular detects that two types are possible for `b`: `object`and `null`. This causes Angular to not override the value.
Of course, `null` is now a valid value for `b`, too, but that may not be a problem in some cases.
Hướng dẫn đóng góp
Hướng nghiên cứu
Bắt đầu với packages/angular_devkit/core/src/json/schema/registry.ts, đặc biệt là tùy chọn applyPostTransforms, sau đó kiểm tra packages/angular_devkit/architect/src/architect.ts, nơi validation được gọi mà không có đối số thứ hai. Tái hiện hành vi của builder schema được mô tả trong issue và xác định cách một builder cụ thể có thể vô hiệu hóa addUndefinedDefaults mà không thay đổi các defaults hiện có cho những schema khác.
Do mô hình lập chỉ mục viết ra từ nội dung của issue.
Đánh giá
- Công nghệ
- typescript
- Lĩnh vực
- tooling
- Loại issue
- Tính năng
- Độ khó
- 4/5
- Thời gian dự kiến
- 3-5 ngày
- Mức độ hoạt động
- Đình trệ
- Độ rõ ràng
- Khá rõ ràng
- Mức phù hợp với người mới
- 35/100