Skip to content

Commit cdff686

Browse files
committed
refactor(@schematics/angular): add jsonc-parser to parse and modify JSON files
Currently, interaction with JSON AST is complex and requires a lot of boiler-platting. With this change we add `jsonc-parser` and add a basic helper class to greatly simplify such interaction. This would come in handle when writing new migrations in 10.1+ **Note**: this is a private implementation and shouldn't be used by 3rd parties.
1 parent 56c06fd commit cdff686

File tree

5 files changed

+92
-1
lines changed

5 files changed

+92
-1
lines changed

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -157,6 +157,7 @@
157157
"jasmine-spec-reporter": "~5.0.0",
158158
"jest-worker": "26.0.0",
159159
"jquery": "^3.3.1",
160+
"jsonc-parser": "2.2.1",
160161
"karma": "~5.0.0",
161162
"karma-chrome-launcher": "~3.1.0",
162163
"karma-coverage-istanbul-reporter": "~3.0.0",

packages/schematics/angular/BUILD.bazel

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,7 @@ ts_library(
8282
"@npm//@types/browserslist",
8383
"@npm//@types/caniuse-lite",
8484
"@npm//@types/node",
85+
"@npm//jsonc-parser",
8586
"@npm//rxjs",
8687
"@npm//tslint",
8788
],
@@ -119,6 +120,7 @@ ts_library(
119120
"//packages/schematics/angular/third_party/github.com/Microsoft/TypeScript",
120121
"@npm//@types/browserslist",
121122
"@npm//@types/caniuse-lite",
123+
"@npm//jsonc-parser",
122124
"@npm//rxjs",
123125
"@npm//tslint",
124126
],

packages/schematics/angular/package.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
"schematics": "./collection.json",
1111
"dependencies": {
1212
"@angular-devkit/core": "0.0.0",
13-
"@angular-devkit/schematics": "0.0.0"
13+
"@angular-devkit/schematics": "0.0.0",
14+
"jsonc-parser": "2.2.1"
1415
}
1516
}
Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
/**
2+
* @license
3+
* Copyright Google Inc. All Rights Reserved.
4+
*
5+
* Use of this source code is governed by an MIT-style license that can be
6+
* found in the LICENSE file at https://angular.io/license
7+
*/
8+
9+
import { JsonValue } from '@angular-devkit/core';
10+
import { Tree } from '@angular-devkit/schematics';
11+
import { Node, applyEdits, findNodeAtLocation, getNodeValue, modify, parseTree } from 'jsonc-parser';
12+
13+
export type JSONPath = (string | number)[];
14+
15+
/** @internal */
16+
export class JSONFile {
17+
private content: string;
18+
error: undefined | Error;
19+
20+
constructor(
21+
private readonly host: Tree,
22+
private readonly path: string,
23+
) {
24+
const buffer = this.host.read(this.path);
25+
if (buffer) {
26+
this.content = buffer.toString();
27+
} else {
28+
this.error = new Error(`Could not read ${path}.`);
29+
}
30+
}
31+
32+
private _jsonAst: Node | undefined;
33+
private get JsonAst(): Node {
34+
if (this._jsonAst) {
35+
return this._jsonAst;
36+
}
37+
38+
this._jsonAst = parseTree(this.content);
39+
40+
return this._jsonAst;
41+
}
42+
43+
get(jsonPath: JSONPath): unknown {
44+
if (jsonPath.length === 0) {
45+
return getNodeValue(this.JsonAst);
46+
}
47+
48+
const node = findNodeAtLocation(this.JsonAst, jsonPath);
49+
50+
return node === undefined ? undefined : getNodeValue(node);
51+
}
52+
53+
modify(jsonPath: JSONPath, value: JsonValue | undefined, getInsertionIndex?: (properties: string[]) => number): void {
54+
if (!getInsertionIndex) {
55+
const property = jsonPath.slice(-1)[0];
56+
getInsertionIndex = properties => [...properties, property].sort().findIndex(p => p === property);
57+
}
58+
59+
const edits = modify(
60+
this.content,
61+
jsonPath,
62+
value,
63+
{
64+
getInsertionIndex,
65+
formattingOptions: {
66+
insertSpaces: true,
67+
tabSize: 2,
68+
},
69+
},
70+
);
71+
72+
this.content = applyEdits(this.content, edits);
73+
this.host.overwrite(this.path, this.content);
74+
this._jsonAst = undefined;
75+
}
76+
77+
remove(jsonPath: JSONPath): void {
78+
if (this.get(jsonPath) !== undefined) {
79+
this.modify(jsonPath, undefined);
80+
}
81+
}
82+
}

yarn.lock

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7832,6 +7832,11 @@ json5@^2.1.0, json5@^2.1.2:
78327832
dependencies:
78337833
minimist "^1.2.5"
78347834

7835+
7836+
version "2.2.1"
7837+
resolved "https://registry.yarnpkg.com/jsonc-parser/-/jsonc-parser-2.2.1.tgz#db73cd59d78cce28723199466b2a03d1be1df2bc"
7838+
integrity sha512-o6/yDBYccGvTz1+QFevz6l6OBZ2+fMVu2JZ9CIhzsYRX4mjaK5IyX9eldUdCmga16zlgQxyrj5pt9kzuj2C02w==
7839+
78357840
jsonfile@^4.0.0:
78367841
version "4.0.0"
78377842
resolved "https://registry.yarnpkg.com/jsonfile/-/jsonfile-4.0.0.tgz#8771aae0799b64076b76640fca058f9c10e33ecb"

0 commit comments

Comments
 (0)