prettify-bru 1.9.0 β 1.9.2
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.
- package/README.md +12 -4
- package/cli.js +3 -10
- package/lib/config.mjs +8 -5
- package/lib/format.mjs +28 -16
- package/lib/main.mjs +18 -12
- package/lib/onlyParam.mjs +25 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -14,7 +14,6 @@ Imposes a standard format on all blocks of JSON and JavaScript code across multi
|
|
|
14
14
|
## Table of contents
|
|
15
15
|
|
|
16
16
|
<!-- TOC -->
|
|
17
|
-
|
|
18
17
|
- [Why use this?](#why-use-this)
|
|
19
18
|
- [Style choices](#style-choices)
|
|
20
19
|
- [Feedback](#feedback)
|
|
@@ -24,9 +23,12 @@ Imposes a standard format on all blocks of JSON and JavaScript code across multi
|
|
|
24
23
|
- [Fixing the files](#fixing-the-files)
|
|
25
24
|
- [Limit to one directory](#limit-to-one-directory)
|
|
26
25
|
- [Limit to one file](#limit-to-one-file)
|
|
27
|
-
- [Limit to
|
|
26
|
+
- [Limit to only a subset of blocks](#limit-to-only-a-subset-of-blocks)
|
|
28
27
|
- [Complex example](#complex-example)
|
|
29
28
|
- [Config file](#config-file)
|
|
29
|
+
- [Agnostic File Paths](#agnostic-file-paths)
|
|
30
|
+
- [Shorten Getters](#shorten-getters)
|
|
31
|
+
- [Prettier](#prettier)
|
|
30
32
|
- [Automatically checking PRs](#automatically-checking-prs)
|
|
31
33
|
<!-- TOC -->
|
|
32
34
|
|
|
@@ -104,14 +106,20 @@ Similar to above example, you can also provide a specific filename:
|
|
|
104
106
|
npx prettify-bru speed-tests/get-all.bru
|
|
105
107
|
```
|
|
106
108
|
|
|
107
|
-
### Limit to
|
|
109
|
+
### Limit to only a subset of blocks
|
|
108
110
|
|
|
109
|
-
Use the `--only` option to
|
|
111
|
+
Use the `--only` option to operate on a specific block or subset of blocks. For example to only assess the `body:json` blocks in your files, specify the exact name of the block:
|
|
110
112
|
|
|
111
113
|
```
|
|
112
114
|
npx prettify-bru --only body:json
|
|
113
115
|
```
|
|
114
116
|
|
|
117
|
+
Some values target groups of blocks:
|
|
118
|
+
|
|
119
|
+
- "graphql" will operate on `body:graphql` and `body:graphql:vars`
|
|
120
|
+
- "script" will do both `script:pre-request` and `script:post-response`
|
|
121
|
+
- "body" will target all 3 body blocks `body:json`, `body:graphql` and `body:graphql:vars`
|
|
122
|
+
|
|
115
123
|
### Complex example
|
|
116
124
|
|
|
117
125
|
Fix the formatting of just the `body:json` block in 1 specific file:
|
package/cli.js
CHANGED
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
import yargs from 'yargs'
|
|
4
4
|
import {hideBin} from 'yargs/helpers'
|
|
5
5
|
import {main} from './lib/main.mjs'
|
|
6
|
+
import {onlyParamOptions} from './lib/onlyParam.mjs'
|
|
6
7
|
|
|
7
8
|
const argv = yargs(hideBin(process.argv))
|
|
8
9
|
.command(
|
|
@@ -20,17 +21,9 @@ const argv = yargs(hideBin(process.argv))
|
|
|
20
21
|
)
|
|
21
22
|
.options({
|
|
22
23
|
only: {
|
|
23
|
-
describe: 'Limit to only
|
|
24
|
+
describe: 'Limit to only certain block types',
|
|
24
25
|
type: 'string',
|
|
25
|
-
choices:
|
|
26
|
-
'body:json',
|
|
27
|
-
'json',
|
|
28
|
-
'script:pre-request',
|
|
29
|
-
'pre-request',
|
|
30
|
-
'script:post-response',
|
|
31
|
-
'post-request',
|
|
32
|
-
'tests',
|
|
33
|
-
],
|
|
26
|
+
choices: Object.keys(onlyParamOptions),
|
|
34
27
|
},
|
|
35
28
|
w: {
|
|
36
29
|
describe: 'Write mode (Formats files in place, overwriting contents)',
|
package/lib/config.mjs
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import {readIfExists} from './files.mjs'
|
|
2
|
+
import {styleText} from 'node:util'
|
|
2
3
|
|
|
3
4
|
const configFilename = '.prettifybrurc'
|
|
4
5
|
|
|
@@ -44,17 +45,19 @@ export function parseFile(console, fileContents) {
|
|
|
44
45
|
fileConfig = JSON.parse(fileContents)
|
|
45
46
|
} catch (e) {
|
|
46
47
|
console.error(
|
|
47
|
-
|
|
48
|
+
styleText('red', `Error parsing JSON in ${configFilename} config file:\n${e.message}\n`)
|
|
48
49
|
)
|
|
49
50
|
return {}
|
|
50
51
|
}
|
|
51
52
|
|
|
52
53
|
if (fileConfig instanceof Array || typeof fileConfig !== 'object') {
|
|
53
|
-
console.error(
|
|
54
|
+
console.error(
|
|
55
|
+
styleText('red', `${configFilename} is not valid, the JSON is not an Object\n`)
|
|
56
|
+
)
|
|
54
57
|
return {}
|
|
55
58
|
}
|
|
56
59
|
|
|
57
|
-
console.log(`π§
|
|
60
|
+
console.log(`π§ ${styleText('dim', `Using config file ${configFilename}`)}`)
|
|
58
61
|
|
|
59
62
|
let config = {}
|
|
60
63
|
|
|
@@ -73,11 +76,11 @@ export function parseFile(console, fileContents) {
|
|
|
73
76
|
config[key] = fileConfig[key]
|
|
74
77
|
} else {
|
|
75
78
|
console.warn(
|
|
76
|
-
`β οΈ
|
|
79
|
+
`β οΈ ${styleText('yellow', `"${key}" is not correct type, it should be ${validType}`)}`
|
|
77
80
|
)
|
|
78
81
|
}
|
|
79
82
|
} else {
|
|
80
|
-
console.warn(`β οΈ
|
|
83
|
+
console.warn(`β οΈ ${styleText('yellow', `Ignoring unsupported property "${key}"`)}`)
|
|
81
84
|
}
|
|
82
85
|
})
|
|
83
86
|
|
package/lib/format.mjs
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import prettier from 'prettier'
|
|
2
2
|
import {defaultConfig} from './config.mjs'
|
|
3
|
+
import {onlyParamOptions, validateOnlyParam} from './onlyParam.mjs'
|
|
3
4
|
import {format as jsoncFormat, applyEdits} from 'jsonc-parser'
|
|
4
5
|
|
|
5
6
|
// This Prettier config should match what the Bruno GUI implements
|
|
@@ -24,6 +25,9 @@ const formattableBlocks = [
|
|
|
24
25
|
'tests',
|
|
25
26
|
]
|
|
26
27
|
|
|
28
|
+
const maskPattern = /("(?:\\.|[^"\\])*")|(\{\{.*?\}\})/g
|
|
29
|
+
const unmaskPattern = /"__ββSTART__(\{\{.*?\}\})__ENDββ__"/g
|
|
30
|
+
|
|
27
31
|
/**
|
|
28
32
|
* @typedef {Object} FileOutcome
|
|
29
33
|
* @property {string} newContents
|
|
@@ -42,6 +46,8 @@ const formattableBlocks = [
|
|
|
42
46
|
* @returns {Promise<FileOutcome>}
|
|
43
47
|
*/
|
|
44
48
|
export async function format(originalContents, only = null, configOverrides = {}) {
|
|
49
|
+
validateOnlyParam(only)
|
|
50
|
+
|
|
45
51
|
/** @type {import('./config.mjs').PrettifyBruConfig} */
|
|
46
52
|
const config = {
|
|
47
53
|
...defaultConfig,
|
|
@@ -61,15 +67,7 @@ export async function format(originalContents, only = null, configOverrides = {}
|
|
|
61
67
|
}
|
|
62
68
|
|
|
63
69
|
for (const blockName of formattableBlocks) {
|
|
64
|
-
if (only !== null)
|
|
65
|
-
// This is non-documented feature, but is covered with tests.
|
|
66
|
-
// Specifying only 'json' will match both 'body:json', 'pre-request' will match 'script:pre-request' etc.
|
|
67
|
-
// However that is causing issue with `body:graphql` and `body:graphql:vars`,
|
|
68
|
-
// as they both start with 'body:graphql'.
|
|
69
|
-
// So not to introduce breaking change on non-documented feature, someone may rely on, use this workaround.
|
|
70
|
-
if (blockName.startsWith('body:graphql') && blockName !== only) continue
|
|
71
|
-
if (!blockName.includes(only)) continue
|
|
72
|
-
}
|
|
70
|
+
if (only !== null && !blockName.match(onlyParamOptions[only])) continue
|
|
73
71
|
|
|
74
72
|
const blockOutcome = await formatBlock(fileOutcome.newContents, blockName, config)
|
|
75
73
|
fileOutcome.blocksSearchedFor++
|
|
@@ -145,8 +143,12 @@ async function formatBlock(fileContents, blockName, config) {
|
|
|
145
143
|
if (blockName === 'body:graphql') {
|
|
146
144
|
opts.parser = 'graphql'
|
|
147
145
|
opts.bracketSpacing = true
|
|
146
|
+
unindented = wrapNonStringPlaceholdersInDelimiters(unindented)
|
|
148
147
|
}
|
|
149
148
|
reformatted = await prettier.format(unindented, opts)
|
|
149
|
+
if (blockName === 'body:graphql') {
|
|
150
|
+
reformatted = unwrapDelimitedPlaceholders(reformatted)
|
|
151
|
+
}
|
|
150
152
|
} catch (e) {
|
|
151
153
|
outcome.errorMessage = `Prettier could not format ${blockName} because...\n${e.message}`
|
|
152
154
|
return outcome
|
|
@@ -194,23 +196,33 @@ function shortenGetters(blockContents) {
|
|
|
194
196
|
}
|
|
195
197
|
|
|
196
198
|
/**
|
|
197
|
-
* Turns Bruno variable placeholders into strings with special delimiters, effectively making it valid JSON
|
|
199
|
+
* Turns Bruno variable placeholders into strings with special delimiters, effectively making it valid JSON,
|
|
200
|
+
* and for standard cases also valid GraphQL.
|
|
198
201
|
*
|
|
199
|
-
* @param {string}
|
|
202
|
+
* @param {string} block
|
|
200
203
|
* @returns {string}
|
|
201
204
|
*/
|
|
202
|
-
function wrapNonStringPlaceholdersInDelimiters(
|
|
203
|
-
return
|
|
205
|
+
function wrapNonStringPlaceholdersInDelimiters(block) {
|
|
206
|
+
return block.replace(maskPattern, (match, group1, group2) => {
|
|
207
|
+
// If group1 exists, we found a standard JSON string. Return it untouched.
|
|
208
|
+
if (group1) {
|
|
209
|
+
return group1
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
// If group2 exists, we found a placeholder outside a string.
|
|
213
|
+
// Wrap it in a unique dummy string.
|
|
214
|
+
return `"__ββSTART__${group2}__ENDββ__"`
|
|
215
|
+
})
|
|
204
216
|
}
|
|
205
217
|
|
|
206
218
|
/**
|
|
207
219
|
* Reverts delimited Bruno variable placeholders back to their original form within a JSON block.
|
|
208
220
|
*
|
|
209
|
-
* @param {string}
|
|
221
|
+
* @param {string} block
|
|
210
222
|
* @returns {string}
|
|
211
223
|
*/
|
|
212
|
-
function unwrapDelimitedPlaceholders(
|
|
213
|
-
return
|
|
224
|
+
function unwrapDelimitedPlaceholders(block) {
|
|
225
|
+
return block.replace(unmaskPattern, '$1')
|
|
214
226
|
}
|
|
215
227
|
|
|
216
228
|
/**
|
package/lib/main.mjs
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import {findFiles, readFile, writeFile} from './files.mjs'
|
|
2
2
|
import {format} from './format.mjs'
|
|
3
|
+
import {validateOnlyParam} from './onlyParam.mjs'
|
|
3
4
|
import {loadConfigFile} from './config.mjs'
|
|
5
|
+
import {styleText} from 'node:util'
|
|
4
6
|
|
|
5
7
|
/**
|
|
6
8
|
* Finds all .bru files and formats contents
|
|
@@ -13,6 +15,8 @@ import {loadConfigFile} from './config.mjs'
|
|
|
13
15
|
* @returns {Promise<boolean>} True means some files contained errors or needed reformatting
|
|
14
16
|
*/
|
|
15
17
|
export async function main(console, cwd, path, write, only = null) {
|
|
18
|
+
validateOnlyParam(only)
|
|
19
|
+
|
|
16
20
|
if (path === '') {
|
|
17
21
|
path = cwd
|
|
18
22
|
} else {
|
|
@@ -46,14 +50,14 @@ export async function main(console, cwd, path, write, only = null) {
|
|
|
46
50
|
|
|
47
51
|
const changeableSuffix = write ? 'reformatted' : 'require reformatting'
|
|
48
52
|
let changeableReport = null
|
|
53
|
+
const changeableColor = write ? 'green' : 'yellow'
|
|
49
54
|
if (changeableFiles.length) {
|
|
50
|
-
const changeableCol = write ? '\x1b[32m' : '\x1b[33m'
|
|
51
55
|
const emoji = write ? 'βοΈ' : 'β οΈ'
|
|
52
56
|
const changeableFilesDesc = fileDesc(changeableFiles)
|
|
53
|
-
changeableReport = `${
|
|
54
|
-
console.log(
|
|
57
|
+
changeableReport = `${changeableFilesDesc} ${changeableSuffix}`
|
|
58
|
+
console.log(styleText([changeableColor, 'underline'], `${changeableReport}:\n`))
|
|
55
59
|
changeableFiles.forEach(r =>
|
|
56
|
-
console.log(`${emoji} ${
|
|
60
|
+
console.log(`${emoji} ${styleText(changeableColor, r.displayFilePath)}`)
|
|
57
61
|
)
|
|
58
62
|
console.log(' ')
|
|
59
63
|
}
|
|
@@ -61,12 +65,12 @@ export async function main(console, cwd, path, write, only = null) {
|
|
|
61
65
|
let erroredReport = null
|
|
62
66
|
if (erroredFiles.length) {
|
|
63
67
|
const erroredFilesDesc = fileDesc(erroredFiles)
|
|
64
|
-
erroredReport =
|
|
65
|
-
console.warn(
|
|
68
|
+
erroredReport = `${erroredFilesDesc} causing errors`
|
|
69
|
+
console.warn(styleText(['red', 'underline'], `${erroredReport}:\n`))
|
|
66
70
|
erroredFiles.forEach((r, i) => {
|
|
67
71
|
console.warn(`${i + 1}) ${r.displayFilePath}\n`)
|
|
68
72
|
r.outcome.errorMessages.forEach(err => {
|
|
69
|
-
console.warn(`β
|
|
73
|
+
console.warn(`β ${styleText('red', err)}\n`)
|
|
70
74
|
})
|
|
71
75
|
})
|
|
72
76
|
}
|
|
@@ -75,15 +79,17 @@ export async function main(console, cwd, path, write, only = null) {
|
|
|
75
79
|
const filesDesc = fileDesc(files)
|
|
76
80
|
console.log(`Inspected ${filesDesc}:`)
|
|
77
81
|
if (changeableReport) {
|
|
78
|
-
console.log(` ${changeableReport}
|
|
82
|
+
console.log(styleText(changeableColor, ` ${changeableReport}`))
|
|
79
83
|
}
|
|
80
84
|
if (erroredReport) {
|
|
81
|
-
console.log(` ${erroredReport}
|
|
85
|
+
console.log(styleText('red', ` ${erroredReport}`))
|
|
82
86
|
}
|
|
83
87
|
if (requireNothing > 0) {
|
|
84
|
-
|
|
85
|
-
requireNothingMessage
|
|
86
|
-
console.log(
|
|
88
|
+
const requireNothingColor = requireNothing === files.length ? 'green' : 'dim'
|
|
89
|
+
const requireNothingMessage = `${requireNothing} file` + (requireNothing > 1 ? 's' : '')
|
|
90
|
+
console.log(
|
|
91
|
+
` ${styleText(requireNothingColor, `${requireNothingMessage} did not require any changes`)}`
|
|
92
|
+
)
|
|
87
93
|
}
|
|
88
94
|
|
|
89
95
|
return erroredFiles.length > 0 || changeableFiles.length > 0
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
export const onlyParamOptions = {
|
|
2
|
+
body: /^body:/,
|
|
3
|
+
'body:json': /^body:json$/,
|
|
4
|
+
json: /json$/,
|
|
5
|
+
'body:graphql': /^body:graphql$/,
|
|
6
|
+
graphql: /.+graphql/,
|
|
7
|
+
'body:graphql:vars': /^body:graphql:vars$/,
|
|
8
|
+
script: /^script:/,
|
|
9
|
+
'script:pre-request': /^script:pre-request$/,
|
|
10
|
+
'pre-request': /.+:pre-request$/,
|
|
11
|
+
'script:post-response': /^script:post-response$/,
|
|
12
|
+
'post-response': /.+:post-response$/,
|
|
13
|
+
tests: /^tests$/,
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* @param {?string} only Value to be validated
|
|
18
|
+
* @throws Error
|
|
19
|
+
* @returns void
|
|
20
|
+
*/
|
|
21
|
+
export function validateOnlyParam(only) {
|
|
22
|
+
if (only !== null && !Object.hasOwn(onlyParamOptions, only)) {
|
|
23
|
+
throw new Error('Invalid value for only parameter')
|
|
24
|
+
}
|
|
25
|
+
}
|