@sap/cds-dk 6.2.2 → 6.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (72) hide show
  1. package/CHANGELOG.md +38 -0
  2. package/bin/bind.js +4 -4
  3. package/bin/deploy/to-h2.js +4 -0
  4. package/bin/deploy/to-sqlite.js +6 -4
  5. package/bin/help.js +1 -1
  6. package/bin/login.js +1 -0
  7. package/bin/mock.js +2 -2
  8. package/bin/push.js +29 -7
  9. package/lib/bind/userCdsrcJsonStorageProvider.js +4 -4
  10. package/lib/cds.js +6 -3
  11. package/lib/client/activate.js +1 -1
  12. package/lib/client/base_command.js +10 -10
  13. package/lib/client/helper/dependency_helper.js +10 -1
  14. package/lib/client/helper/logging.js +6 -2
  15. package/lib/client/pull.js +6 -6
  16. package/lib/client/push.js +33 -14
  17. package/lib/client/settings_manager.js +52 -21
  18. package/lib/compile/openapi/csdl2openapi.js +1 -1
  19. package/lib/compile/to-xsuaa.js +1 -1
  20. package/lib/import/odata/v2parser.js +37 -1
  21. package/lib/import/odata/v4parser.js +101 -23
  22. package/lib/init/constants.js +1 -1
  23. package/lib/init/index.js +23 -45
  24. package/lib/init/template/approuter/index.js +44 -48
  25. package/lib/init/template/auditlog/index.js +14 -10
  26. package/lib/init/template/cf-manifest/index.js +9 -11
  27. package/lib/init/template/connectivity/index.js +10 -10
  28. package/lib/init/template/data/index.js +20 -19
  29. package/lib/init/template/destinations/index.js +14 -9
  30. package/lib/init/template/enterprise-messaging/index.js +14 -9
  31. package/lib/init/template/extensibility/index.js +14 -9
  32. package/lib/init/template/hana/index.js +51 -57
  33. package/lib/init/template/helm/index.js +27 -59
  34. package/lib/init/template/helm/subchart/templates/_helpers.tpl +38 -0
  35. package/lib/init/template/helm/subchart/templates/deployment.yaml +12 -12
  36. package/lib/init/template/helm/subchart/values.md +565 -194
  37. package/lib/init/template/helm/subchart/values.schema.json +163 -8
  38. package/lib/init/template/helm/subchart/values.yaml +17 -1
  39. package/lib/init/template/html5-repo/index.js +15 -11
  40. package/lib/init/template/java/index.js +15 -11
  41. package/lib/init/template/kibana-logging/index.js +30 -31
  42. package/lib/init/template/lint/index.js +17 -18
  43. package/lib/init/template/mta/index.js +18 -40
  44. package/lib/init/template/mtx/index.js +2 -3
  45. package/lib/init/template/multitenancy/index.js +27 -20
  46. package/lib/init/template/nodejs/index.js +18 -20
  47. package/lib/init/template/notebook/index.js +5 -434
  48. package/lib/init/template/pipeline/index.js +10 -10
  49. package/lib/init/template/samples/index.js +7 -16
  50. package/lib/init/template/templateBase.js +17 -18
  51. package/lib/init/template/toggles/files/cdsrc.json +5 -0
  52. package/lib/init/template/toggles/files/cdsrc.json.hbs +7 -0
  53. package/lib/init/template/toggles/index.js +12 -6
  54. package/lib/init/template/xsuaa/index.js +44 -41
  55. package/lib/init/types.d.ts +0 -59
  56. package/lib/init/util/commandUtil.js +6 -7
  57. package/lib/init/util/fsUtil.js +23 -109
  58. package/lib/init/util/merge.js +319 -0
  59. package/lib/init/util/mvnArchetypeUtil.js +6 -5
  60. package/lib/init/util/projectReader.js +125 -300
  61. package/lib/init/util/spinner.js +10 -8
  62. package/lib/init/util/templateUtil.js +25 -368
  63. package/lib/lint/Linter.js +2 -3
  64. package/lib/lint/checks.js +0 -1
  65. package/lib/lint/io.js +18 -34
  66. package/npm-shrinkwrap.json +115 -261
  67. package/package.json +3 -3
  68. package/lib/init/template/notebook/cap_magic.py +0 -118
  69. package/lib/init/template/notebook/files/{{{name}}}.ipynb.hbs +0 -90
  70. package/lib/init/template/notebook/files/{{{name}}}.json +0 -102
  71. package/lib/init/template/notebook/notebook.js +0 -394
  72. package/lib/init/util/logger.js +0 -42
@@ -1,375 +1,32 @@
1
- const path = require('path');
2
- const YAML = require('@sap/cds-foss').yaml;
3
- const Mustache = require('mustache');
4
- const { fs } = require('../../cds').utils;
5
-
6
- const TEMPLATE_EXTENSION = '.hbs';
7
- const TEMPLATE_EXTENSION_REGEX = new RegExp(`${TEMPLATE_EXTENSION}$`);
8
-
9
- module.exports = class TemplateUtil {
10
-
11
- constructor(templateRoot, fsUtil) {
12
- this.templateRoot = templateRoot;
13
- this.fsUtil = fsUtil;
14
- }
15
-
16
- async copyFiles(template, destinationPath, templateValues, overwrite = false) {
17
- const templatePath = this._getTemplatePath(template);
18
-
19
- const files = await this.fsUtil.readdir(templatePath);
20
- for (const file of files) {
21
- const fileNew = Mustache.render(file, templateValues);
22
- const src = path.join(templatePath, file);
23
- const dest = path.join(destinationPath, fileNew);
24
-
25
- const stat = await this.fsUtil.stat(src);
26
- if (stat.isDirectory()) {
27
- await this.copyFiles(path.join(template, file), dest, templateValues, overwrite);
28
- } else if (this._isTemplateFile(file)) {
29
- await this._writeTemplateFile(src, dest, templateValues, overwrite);
30
- } else {
31
- await this.fsUtil.copy(src, dest);
32
- }
33
- }
34
- }
35
-
36
- async sortDependencies(packageJSONPath) {
37
- const json = await this.fsUtil.readJSON(packageJSONPath);
38
- json.dependencies = Object.fromEntries(
39
- Object.entries(json.dependencies).sort(([a],[b]) => a>b ? 1 : -1)
40
- )
41
- await this.fsUtil.writeJSON(packageJSONPath, json);
42
- }
43
-
44
- async _writeTemplateFile(src, destination, templateValues, overwrite = false) {
45
- const destinationPath = destination.replace(TEMPLATE_EXTENSION_REGEX, '');
46
- if (overwrite || !(await this.fsUtil.pathExists(destinationPath))) {
47
- const content = await this._processTemplateFile(src, templateValues);
48
- await this.fsUtil.writeFile(destinationPath, content);
49
- }
50
- }
51
-
52
- async _processTemplateFile(src, templateValues) {
53
- const content = await this.fsUtil.readFile(src);
54
- return Mustache.render(content, templateValues);
55
- }
56
-
57
- _getTemplatePath(templatePath) {
58
- return path.join(this.templateRoot, templatePath);
59
- }
60
-
61
- _isTemplateFile(filename) {
62
- return path.extname(filename) === TEMPLATE_EXTENSION;
63
- }
64
-
65
- /*
66
- Will do a syntactic merge when `semantics` is undefined.
67
- Syntactic merges are sufficient in some cases,
68
- e.g merging dependencies in a package.json, as they are
69
- just maps where you can do a key-value replacement.
70
- */
71
- _deepMerge(target, source) {
72
- const unique = array => [...new Set(array.map(JSON.stringify))].map(JSON.parse)
73
- if (this._isObject(target) && this._isObject(source)) {
74
- for (const key in source) {
75
- if (this._isObject(source[key])) {
76
- if (!target[key]) Object.assign(target, { [key]: source[key] })
77
- else this._deepMerge(target[key], source[key])
78
- } else if (Array.isArray(source[key]) && Array.isArray(target[key])) {
79
- target[key] = unique([...source[key], ...target[key]])
80
- } else {
81
- Object.assign(target, { [key]: target[key] || source[key] })
82
- }
1
+ const Mustache = require('mustache')
2
+ const { copy, read, write, exists, readdir, path, isdir } = require('../../cds').utils
3
+
4
+ async function copyFiles(templatePath, destinationPath, templateValues, overwrite = false) {
5
+ for (const dirent of await readdir(templatePath)) {
6
+ const fileNew = Mustache.render(dirent, templateValues)
7
+ const src = path.join(templatePath, dirent);
8
+ const dest = path.join(destinationPath, fileNew);
9
+
10
+ if (isdir(src)) {
11
+ await copyFiles(path.join(templatePath, dirent), dest, templateValues, overwrite);
12
+ } else if (path.extname(dirent) === '.hbs') {
13
+ const destinationPath = dest.replace('.hbs', '');
14
+ if (overwrite || !exists(destinationPath)) {
15
+ const content = await render(src, templateValues);
16
+ await write(destinationPath, content, { spaces: 2 });
83
17
  }
84
- } else if (Array.isArray(target) && Array.isArray(source)) {
85
- target = unique([...source, ...target])
86
- }
87
- return target || source
88
- }
89
-
90
- async mergeJSON(targetPath, from, projectDescriptor, semantics) {
91
- const source = typeof from === 'string' ? await this.fsUtil.readJSON(from, projectDescriptor) : from
92
-
93
- if (! await this.fsUtil.pathExists(targetPath)) {
94
- await this.fsUtil.writeJSON(targetPath, source)
95
- } else if (semantics) {
96
- const target = await this.fsUtil.readJSON(targetPath)
97
-
98
- if (!target) return // Has no JSON file
99
-
100
- const targetYAML = await YAML.parseDocument(YAML.stringify(target))
101
- const sourceYAML = await YAML.parseDocument(YAML.stringify(source))
102
- const resultYAML = await this.mergeYAML(targetYAML, sourceYAML, projectDescriptor, semantics)
103
- const result = YAML.parse(YAML.stringify(resultYAML))
104
- await this.fsUtil.writeJSON(targetPath, result)
105
18
  } else {
106
- const target = await this.fsUtil.readJSON(targetPath)
107
- const sourceFile = await this._processTemplateFile(from, projectDescriptor)
108
- const source = JSON.parse(sourceFile)
109
- const result = target && source ? this._deepMerge(target, source) : target || source
110
- await this.fsUtil.writeJSON(targetPath, result)
19
+ await copy(src, dest);
111
20
  }
112
21
  }
22
+ }
113
23
 
114
- async mergeYAML(into, from, projectDescriptor, semantics) {
115
- const target =
116
- typeof into === 'string' ? await this.fsUtil.readYAML(into) :
117
- into instanceof YAML.Document ? into :
118
- new YAML.Document(into)
119
- const source =
120
- typeof from === 'string' ? await this.fsUtil.readYAML(from, projectDescriptor)
121
- : from instanceof YAML.Document ? from :
122
- new YAML.Document(from)
123
-
124
- if (!target || !target.contents) {
125
- if (typeof into === 'string' && typeof from === 'string') {
126
- return projectDescriptor ? this.fsUtil.writeYAML(into, source) : fs.copy(from, into)
127
- }
128
- return /* has no YAML */
129
- }
130
-
131
- const existenceMap = new Map()
132
- const templateExistenceMap = new Map()
133
-
134
- const { additions, overwrites, deletions, relationships } = semantics
135
- additions?.forEach(existence => {
136
- existenceMap.set(existence.ref, undefined)
137
- templateExistenceMap.set(existence.ref, undefined)
138
- })
139
- deletions?.forEach(deletion => {
140
- existenceMap.set(deletion.item.ref, undefined)
141
- })
142
- relationships?.forEach(relationship => {
143
- const [existence] = relationship.into
144
- const [insertExistence] = relationship.insert
145
- const ref = insertExistence.ref + ' -> ' + existence.ref
146
- existenceMap.set(ref, undefined)
147
- })
148
-
149
- let collectionStack = [target.contents]
150
-
151
- const _getProperty = (object, keyPath) => keyPath.split('.').reduce((p, k) => p && p[k], object)
152
- const _getYAMLProperty = (object, keyPath) => keyPath.split('.').reduce((p, k) => p && p.get(k), object)
153
-
154
- const _validateWhere = (node, dict, index) => {
155
- const _addToMap = existences => existences?.filter(existence => {
156
- let where = existence.in
157
- if (typeof where === 'string') return true // just a key path on the document root
158
- else where = where[0] // a more complex list of constraints, a sequence/array is involved
159
- const neededParent = dict.get(where.ref)?.node
160
- return collectionStack.includes(neededParent) // lookbehind in parent collection stack
161
- // REVISIT: Only look behind until sequence is reached?
162
- }).forEach(({ where, ref }) => {
163
- const json = JSON.parse(String(node))
164
- const whereFulfilled = where.every(constraint =>
165
- constraint.isEqualTo === _getProperty(json, constraint.property)
166
- )
167
- if (whereFulfilled) {
168
- const [collection] = collectionStack
169
- dict.set(ref, { json, node, index, collection })
170
- }
171
- })
172
- if (additions) _addToMap(additions)
173
- if (deletions) _addToMap(deletions.map(deletion => deletion.item))
174
- if (relationships) _addToMap(relationships?.map(({into: [existence]}) => existence).filter(e => e))
175
- }
176
-
177
- function _traverseYAMLNode(node, index, actions, templateNode) {
178
- let shifted = false
179
- if (YAML.isMap(node)) {
180
- actions?.visitMap && actions.visitMap(node, index)
181
- const [collection] = collectionStack
182
- if (YAML.isSeq(collection)) {
183
- collectionStack.unshift(node)
184
- shifted = true
185
- }
186
- } else if (YAML.isPair(node) && node.value?.items) {
187
- collectionStack.unshift(node.value)
188
- } else if (YAML.isScalar(node) && semantics.forceOverwrite && templateNode) {
189
- node.value = templateNode.value ?? templateNode.items?.[0]?.value?.value
190
- }
191
-
192
- if (node.items) {
193
- if (YAML.isSeq(node) && templateNode?.items) {
194
- actions?.mergeCollection && actions.mergeCollection(node, templateNode)
195
- _traverseYAMLCollection(node, actions, templateNode)
196
- } else {
197
- _traverseYAMLCollection(node, actions, templateNode)
198
- }
199
- } else if (node.value?.items || node.value && semantics.forceOverwrite) {
200
- _traverseYAMLNode(node.value, index, actions, templateNode && templateNode.value)
201
- }
202
-
203
- if (node.value?.items || shifted) {
204
- collectionStack.shift()
205
- }
206
- }
207
- _traverseYAMLNode.bind(this)
208
-
209
- function _traverseYAMLCollection (collection, actions, templateCollection) {
210
- if (!collection) return
211
-
212
- const keyToIndex = new Map, templateIndexToIndex = new Map
213
-
214
- // Map collection items to their semantic counterpart(s)
215
- collection.items.forEach((node, i) => {
216
- if (node.key) keyToIndex.set(node.key.value, i)
217
- const existence = [...existenceMap.entries()].find(([,value]) => value?.node === node)
218
- if (existence) {
219
- const [existenceKey] = existence
220
- const templateExistence = existenceKey && templateExistenceMap.get(existenceKey)
221
- const templateIndex = templateExistence?.index
222
- if (templateIndex !== undefined) templateIndexToIndex.set(templateIndex, i)
223
- }
224
- if (!templateCollection) _traverseYAMLNode(node, i, actions)
225
- })
226
-
227
- if (!templateCollection) return
228
-
229
- templateCollection.items.forEach((templateNode, templateIndex) => {
230
- if (YAML.isScalar(templateNode)) {
231
- if (!collection.items.map(item => item.value).includes(templateNode.value)) {
232
- collection.add(templateNode)
233
- }
234
- } else if (YAML.isPair(templateNode)) {
235
- const i = keyToIndex.get(templateNode.key.value)
236
- const [collection] = collectionStack
237
- const targetNode = collection.items && collection.items[i]
238
- if (targetNode) {
239
- _traverseYAMLNode(targetNode, templateIndex, actions, templateNode)
240
- } else if (actions.mergePair) {
241
- actions.mergePair(collection, templateNode)
242
- }
243
- } else if (YAML.isMap(templateNode)) {
244
- const targetNode = collection.items[templateIndexToIndex.get(templateIndex)]
245
- if (actions.mergeCollection) actions.mergeCollection(targetNode, templateNode)
246
- if (targetNode) {
247
- _traverseYAMLNode(targetNode, templateIndex, actions, templateNode)
248
- }
249
- }
250
- })
251
- }
252
- _traverseYAMLCollection.bind(this)
253
-
254
- // 1. Validate the existences in the template
255
- _traverseYAMLNode(source.contents, null, {
256
- visitMap: (node, index) => {
257
- _validateWhere(node, templateExistenceMap, index)
258
- }
259
- })
260
-
261
- // 2. Validate the existences in the project
262
- _traverseYAMLNode(target.contents, null, {
263
- visitMap: (node, index) => {
264
- _validateWhere(node, existenceMap, index)
265
- }
266
- })
267
-
268
- // 3. Apply overwrites to already found existences
269
- overwrites?.forEach(({ item, withValue }) => {
270
- const keyPath = Array.isArray(item) && typeof item[0] === 'string' ? item[0] : typeof item === 'string' ? item : item[1]
271
- const inExistence = Array.isArray(item) && typeof item[0] === 'object' ? item[0] : typeof item === 'object' ? item : item[1]
272
- const node = inExistence && existenceMap.get(inExistence.ref) ? existenceMap.get(inExistence.ref).node : collectionStack[collectionStack.length - 1]
273
- const keys = keyPath.split('.')
274
- if (!node.getIn(keys)) return
275
- _getYAMLProperty(node, keys.slice(0, keys.length - 1).join('.'))
276
- .set(keys[keys.length - 1], withValue)
277
- })
278
-
279
- // 4. Delete existences from the project (e.g. separate deployer module when adding mtx)
280
- deletions?.forEach(({ item: { ref }, relationships }) => {
281
- const existence = existenceMap.get(ref)
282
- if (!existence) return
283
- existence.collection.delete(existence.index)
284
-
285
- relationships?.forEach(relationship => {
286
- const [allWithinKeyPath, inKeyPath, into] = relationship.allWithin
287
- const parent = _getYAMLProperty(target, allWithinKeyPath)
288
- for (const child of parent.items) {
289
- const grandchild = _getYAMLProperty(child, inKeyPath)
290
- const i = grandchild?.items?.findIndex(node =>
291
- node.get(into) === _getProperty(existence.json, relationship.removeProperty)
292
- ) ?? - 1
293
- if (i > -1) grandchild.delete(i)
294
- }
295
- })
296
- })
297
-
298
- // 5. Create missing existences and pairs
299
- _traverseYAMLNode(target.contents, null, {
300
- mergePair: (collection, templateNode) => {
301
- if (YAML.isMap(collection)) {
302
- collection.add(templateNode)
303
- }
304
- },
305
- mergeCollection: (targetNode, templateNode) => {
306
- if (YAML.isSeq(templateNode)) {
307
- let [,parent] = collectionStack
308
- additions?.filter(addition => {
309
- if (typeof addition.in === 'string' || Array.isArray(addition.in) && typeof addition.in[0] === 'string') return true
310
- const inExistence = Array.isArray(addition.in) ? existenceMap.get(addition.in[0].ref) : existenceMap.get(addition.in.ref)
311
- return inExistence?.node === parent
312
- })
313
- .filter(addition => {
314
- const keyPath = typeof addition.in === 'string' ? addition.in : Array.isArray(addition.in) && typeof addition.in[0] === 'string' ? addition.in[0] : addition.in[1]
315
- const keys = keyPath.split('.')
316
- if (keys.length > collectionStack.length + 1) return
317
- if (keys.length > 1) parent = collectionStack[keys.length]
318
- return _getYAMLProperty(parent, keyPath) === targetNode
319
- })
320
- .filter(({ ref }) => {
321
- return !existenceMap.get(ref)
322
- })
323
- .forEach(({ ref, at }) => {
324
- const templateNode = templateExistenceMap.get(ref).node
325
- at !== undefined ? targetNode.items.splice(at, 0, templateNode) : targetNode.add(templateNode)
326
- })
327
- }
328
- },
329
- }, source.contents)
330
-
331
- // 6. Re-validate the existences in the project
332
- _traverseYAMLNode(target.contents, null, {
333
- visitMap: (node, index) => {
334
- _validateWhere(node, existenceMap, index)
335
- }
336
- })
337
-
338
- // 7. Create missing relationships
339
- _traverseYAMLNode(target.contents, null, {
340
- mergeCollection: (targetNode, templateNode) => {
341
- if (YAML.isSeq(templateNode)) {
342
- const targetJSON = YAML.parse(String(targetNode))
343
- const relationship = semantics.relationships?.filter(r => r)
344
- .find(relationship => {
345
- const [existence, keyPath] = relationship.into
346
- if (!existenceMap.get(existence.ref)) return false
347
- const existingNode = _getYAMLProperty(existenceMap.get(existence.ref).node, keyPath)
348
- return targetNode === existingNode
349
- })
350
- if (!relationship) return
351
-
352
- const intoKey = relationship.into[relationship.into.length - 1]
353
- const [existence, existenceKeyPath] = relationship.insert
354
- const missingPairs = [existence]
355
- .filter(({ref}) =>
356
- !targetJSON.some(item =>
357
- _getProperty(existenceMap.get(ref).json, existenceKeyPath) === item[intoKey]
358
- )
359
- )
360
- .map(({ref}) => existenceMap.get(ref).node.get(intoKey))
361
- missingPairs.forEach(pair => {
362
- targetNode.add({ [intoKey]: pair })
363
- })
364
- }
365
- }
366
- }, source.contents)
367
-
368
- typeof into === 'string' && await this.fsUtil.writeYAML(into, target)
369
- return target
370
- }
24
+ async function render(src, templateValues) {
25
+ const content = await read(src, 'utf-8');
26
+ return Mustache.render(content, templateValues);
27
+ }
371
28
 
372
- _isObject(item) {
373
- return item && typeof item === 'object' && !Array.isArray(item)
374
- }
29
+ module.exports = {
30
+ render,
31
+ copyFiles
375
32
  }
@@ -124,10 +124,9 @@ class Linter {
124
124
  for (let i = 0; i < configFiles.length; i++) {
125
125
  const configPath = path.join(configDir, configFiles[i]);
126
126
  if (configFiles[i] !== "package.json" || (
127
- configFiles[i] !== "package.json" && require(configPath).eslintConfig
127
+ configFiles[i] === "package.json" && require(configPath).eslintConfig
128
128
  )) {
129
- if (await exists(configPath) && await isfile(configPath)) {
130
-
129
+ if (exists(configPath) && await isfile(configPath)) {
131
130
  return configPath;
132
131
  }
133
132
  }
@@ -106,7 +106,6 @@ module.exports = {
106
106
  cwd: inputPath,
107
107
  shell: IS_WIN,
108
108
  },
109
- undefined,
110
109
  true
111
110
  );
112
111
  } catch (err) {
package/lib/lint/io.js CHANGED
@@ -1,10 +1,9 @@
1
- const fsp = require("fs").promises;
2
1
  const path = require("path");
3
2
  const yaml = require("@sap/cds-foss")("yaml");
4
3
  const term = require("../util/term");
5
- const FsUtil = require("../init/util/fsUtil");
6
- const fsUtil = new FsUtil();
7
- const JSONC = require("../util/jsonc")
4
+ const { read, write, exists } = require('../cds').utils;
5
+ const { readJSONC } = require("../init/util/fsUtil");
6
+ const JSONC = require('../util/jsonc');
8
7
 
9
8
  module.exports = {
10
9
  /**
@@ -14,8 +13,8 @@ module.exports = {
14
13
  */
15
14
  async readEslintConfig(configPath) {
16
15
  let config;
17
- let configFile = path.basename(configPath);
18
- let configString = await fsp.readFile(configPath, "utf8");
16
+ const configFile = path.basename(configPath);
17
+ const configString = await read(configPath, "utf8");
19
18
  switch (configFile) {
20
19
  case ".eslintrc.js":
21
20
  case ".eslintrc.cjs":
@@ -27,14 +26,14 @@ module.exports = {
27
26
  break;
28
27
  case ".eslintrc.yaml":
29
28
  case ".eslintrc.yml":
30
- config = yaml.parse(await fsp.readFile(configPath, "utf8"));
29
+ config = yaml.parse(await read(configPath, "utf8"));
31
30
  break;
32
31
  case ".eslintrc.json":
33
32
  case ".eslintrc":
34
- config = await fsUtil.readJSONC(configPath);
33
+ config = await readJSONC(configPath);
35
34
  break;
36
35
  case "package.json":
37
- config = JSON.parse(await fsp.readFile(configPath, "utf8"));
36
+ config = JSON.parse(await read(configPath, "utf8"));
38
37
  if ("eslintConfig" in config) {
39
38
  config = config["eslintConfig"];
40
39
  } else {
@@ -60,7 +59,7 @@ module.exports = {
60
59
  let configContents = {};
61
60
  const isFilePath = typeof configIn === "string";
62
61
  if (isFilePath) {
63
- if (await fsUtil.pathExists(configIn)) {
62
+ if (exists(configIn)) {
64
63
  configContents = (await this.readEslintConfig(configIn)) || {};
65
64
  }
66
65
  } else {
@@ -103,7 +102,7 @@ module.exports = {
103
102
  * Writes ESLint config contents to file
104
103
  * @param {*} configContents config file contents
105
104
  * @param {*} configPath config file path to write to
106
- * @returns {void}
105
+ * @returns {Promise<void>}
107
106
  */
108
107
  async writeEslintConfig(configPath, configContents, logger=console) {
109
108
  const configType = "recommended";
@@ -139,15 +138,15 @@ module.exports = {
139
138
  break;
140
139
  case ".eslintrc.yaml":
141
140
  case ".eslintrc.yml":
142
- await fsUtil.writeFile(configPath, yaml.stringify(configContents));
141
+ await write(configPath, yaml.stringify(configContents));
143
142
  break;
144
143
  case ".eslintrc.json":
145
144
  case ".eslintrc":
146
- await fsUtil.writeFile(configPath, `${JSON.stringify(configContents, null, 2)}`);
145
+ await write(configPath, configContents, { spaces: 2 });
147
146
  break;
148
147
  case "package.json":
149
- if (await fsUtil.pathExists(configPath)) {
150
- contents = JSON.parse(await fsp.readFile(configPath, "utf8"));
148
+ if (exists(configPath)) {
149
+ contents = JSON.parse(await read(configPath, "utf8"));
151
150
  } else {
152
151
  contents = {};
153
152
  }
@@ -156,12 +155,11 @@ module.exports = {
156
155
  } else {
157
156
  contents["eslintConfig"] = [...configContents, ...contents["eslintConfig"]];
158
157
  }
159
- await fsUtil.writeFile(configPath, `${JSON.stringify(contents, null, 2)}`);
158
+ await write(configPath, contents, { spaces: 2 });
160
159
  break;
161
160
  default:
162
161
  break;
163
162
  }
164
- return;
165
163
  },
166
164
 
167
165
  /**
@@ -171,9 +169,9 @@ module.exports = {
171
169
  */
172
170
  async readVscodeSettings(settingsPath) {
173
171
  let settings;
174
- if (fsUtil.pathExists(settingsPath)) {
172
+ if (exists(settingsPath)) {
175
173
  try {
176
- settings = await fsUtil.readJSONC(settingsPath);
174
+ settings = await readJSONC(settingsPath);
177
175
  } catch (err) {
178
176
  settings = {};
179
177
  }
@@ -230,21 +228,7 @@ module.exports = {
230
228
  }
231
229
  }
232
230
 
233
- await this.writeVscodeSettings(settingsPath, settings);
234
- },
235
-
236
- /**
237
- * Writes VS Code settings from file
238
- * @param {*} settings settings file contents
239
- * @param {*} settingsPath settings file path to write to
240
- * @returns {void}
241
- */
242
- async writeVscodeSettings(settingsPath, settings) {
243
- if (!settings) {
244
- await fsUtil.mkdirp(path.dirname(settingsPath));
245
- }
246
- await fsUtil.writeJSON(settingsPath, settings);
247
- return;
231
+ await write(settingsPath, settings, { spaces: 2 });
248
232
  },
249
233
 
250
234
  /**