UNPKG

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