UNPKG

6.73 kBJavaScriptView Raw
1"use strict";
2Object.defineProperty(exports, "__esModule", { value: true });
3exports.findPropertyInAstObject = exports.appendValueInAstArray = exports.removePropertyInAstObject = exports.insertPropertyInAstObjectInOrder = exports.appendPropertyInAstObject = void 0;
4function appendPropertyInAstObject(recorder, node, propertyName, value, indent) {
5 const indentStr = _buildIndent(indent);
6 let index = node.start.offset + 1;
7 if (node.properties.length > 0) {
8 // Insert comma.
9 const last = node.properties[node.properties.length - 1];
10 const { text, end } = last;
11 const commaIndex = text.endsWith('\n') ? end.offset - 1 : end.offset;
12 recorder.insertRight(commaIndex, ',');
13 index = end.offset;
14 }
15 const content = _stringifyContent(value, indentStr);
16 recorder.insertRight(index, (node.properties.length === 0 && indent ? '\n' : '')
17 + ' '.repeat(indent)
18 + `"${propertyName}":${indent ? ' ' : ''}${content}`
19 + indentStr.slice(0, -indent));
20}
21exports.appendPropertyInAstObject = appendPropertyInAstObject;
22function insertPropertyInAstObjectInOrder(recorder, node, propertyName, value, indent) {
23 if (node.properties.length === 0) {
24 appendPropertyInAstObject(recorder, node, propertyName, value, indent);
25 return;
26 }
27 // Find insertion info.
28 let insertAfterProp = null;
29 let prev = null;
30 let isLastProp = false;
31 const last = node.properties[node.properties.length - 1];
32 for (const prop of node.properties) {
33 if (prop.key.value > propertyName) {
34 if (prev) {
35 insertAfterProp = prev;
36 }
37 break;
38 }
39 if (prop === last) {
40 isLastProp = true;
41 insertAfterProp = last;
42 }
43 prev = prop;
44 }
45 if (isLastProp) {
46 appendPropertyInAstObject(recorder, node, propertyName, value, indent);
47 return;
48 }
49 const indentStr = _buildIndent(indent);
50 const insertIndex = insertAfterProp === null
51 ? node.start.offset + 1
52 : insertAfterProp.end.offset + 1;
53 const content = _stringifyContent(value, indentStr);
54 recorder.insertRight(insertIndex, indentStr
55 + `"${propertyName}":${indent ? ' ' : ''}${content}`
56 + ',');
57}
58exports.insertPropertyInAstObjectInOrder = insertPropertyInAstObjectInOrder;
59function removePropertyInAstObject(recorder, node, propertyName) {
60 // Find the property inside the object.
61 const propIdx = node.properties.findIndex(prop => prop.key.value === propertyName);
62 if (propIdx === -1) {
63 // There's nothing to remove.
64 return;
65 }
66 if (node.properties.length === 1) {
67 // This is a special case. Everything should be removed, including indentation.
68 recorder.remove(node.start.offset, node.end.offset - node.start.offset);
69 recorder.insertRight(node.start.offset, '{}');
70 return;
71 }
72 // The AST considers commas and indentation to be part of the preceding property.
73 // To get around messy comma and identation management, we can work over the range between
74 // two properties instead.
75 const previousProp = node.properties[propIdx - 1];
76 const targetProp = node.properties[propIdx];
77 const nextProp = node.properties[propIdx + 1];
78 let start, end;
79 if (previousProp) {
80 // Given the object below, and intending to remove the `m` property:
81 // "{\n \"a\": \"a\",\n \"m\": \"m\",\n \"z\": \"z\"\n}"
82 // ^---------------^
83 // Removing the range above results in:
84 // "{\n \"a\": \"a\",\n \"z\": \"z\"\n}"
85 start = previousProp.end;
86 end = targetProp.end;
87 }
88 else {
89 // If there's no previousProp there is a nextProp, since we've specialcased the 1 length case.
90 // Given the object below, and intending to remove the `a` property:
91 // "{\n \"a\": \"a\",\n \"m\": \"m\",\n \"z\": \"z\"\n}"
92 // ^---------------^
93 // Removing the range above results in:
94 // "{\n \"m\": \"m\",\n \"z\": \"z\"\n}"
95 start = targetProp.start;
96 end = nextProp.start;
97 }
98 recorder.remove(start.offset, end.offset - start.offset);
99 if (!nextProp) {
100 recorder.insertRight(start.offset, '\n');
101 }
102}
103exports.removePropertyInAstObject = removePropertyInAstObject;
104function appendValueInAstArray(recorder, node, value, indent = 4) {
105 let indentStr = _buildIndent(indent);
106 let index = node.start.offset + 1;
107 // tslint:disable-next-line: no-any
108 let newNodes;
109 if (node.elements.length > 0) {
110 // Insert comma.
111 const { end } = node.elements[node.elements.length - 1];
112 const isClosingOnSameLine = node.end.offset - end.offset === 1;
113 if (isClosingOnSameLine && indent) {
114 // Reformat the entire array
115 recorder.remove(node.start.offset, node.end.offset - node.start.offset);
116 newNodes = [
117 ...node.elements.map(({ value }) => value),
118 value,
119 ];
120 index = node.start.offset;
121 // In case we are generating the entire node we need to reduce the spacing as
122 // otherwise we'd end up having incorrect double spacing
123 indent = indent - 2;
124 indentStr = _buildIndent(indent);
125 }
126 else {
127 recorder.insertRight(end.offset, ',');
128 index = end.offset;
129 }
130 }
131 recorder.insertRight(index, (newNodes ? '' : indentStr)
132 + _stringifyContent(newNodes || value, indentStr)
133 + (node.elements.length === 0 && indent ? indentStr.substr(0, -indent) + '\n' : ''));
134}
135exports.appendValueInAstArray = appendValueInAstArray;
136function findPropertyInAstObject(node, propertyName) {
137 let maybeNode = null;
138 for (const property of node.properties) {
139 if (property.key.value == propertyName) {
140 maybeNode = property.value;
141 }
142 }
143 return maybeNode;
144}
145exports.findPropertyInAstObject = findPropertyInAstObject;
146function _buildIndent(count) {
147 return count ? '\n' + ' '.repeat(count) : '';
148}
149function _stringifyContent(value, indentStr) {
150 // TODO: Add snapshot tests
151 // The 'space' value is 2, because we want to add 2 additional
152 // indents from the 'key' node.
153 // If we use the indent provided we will have double indents:
154 // "budgets": [
155 // {
156 // "type": "initial",
157 // "maximumWarning": "2mb",
158 // "maximumError": "5mb"
159 // },
160 // {
161 // "type": "anyComponentStyle",
162 // 'maximumWarning": "5kb"
163 // }
164 // ]
165 return JSON.stringify(value, null, 2).replace(/\n/g, indentStr);
166}