prettify-bru 0.1.8 → 0.1.10
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 +27 -5
- package/cli.js +30 -24
- package/lib/format.js +91 -0
- package/lib/main.js +108 -0
- package/package.json +5 -6
- package/index.js +0 -4
- package/src/index.js +0 -3
package/README.md
CHANGED
|
@@ -1,11 +1,33 @@
|
|
|
1
|
-
# Prettify Bru Files
|
|
1
|
+
# Prettify Bruno Bru Files
|
|
2
|
+
|
|
3
|
+
A simple CLI tool to prettify the contents of `.bru` files.
|
|
4
|
+
|
|
5
|
+
## Installation
|
|
2
6
|
|
|
3
7
|
To install in your project, run:
|
|
4
8
|
|
|
5
|
-
|
|
9
|
+
```
|
|
10
|
+
npm i prettify-bru
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
Boom, now you can get a non-destructive report of all the incorrect formatting by running:
|
|
14
|
+
|
|
15
|
+
```
|
|
16
|
+
npx prettify-bru
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
The above command will walk subdirectories, finding all `.bru` files.
|
|
20
|
+
With each file it will assess the formatting of the JSON/JavsScript inside the following types of block:
|
|
21
|
+
|
|
22
|
+
- `body:json` will be parsed with the JSON parser
|
|
23
|
+
- `script:pre-request` blocks parsed with Babel
|
|
24
|
+
- `script:post-request` blocks parsed with Babel
|
|
25
|
+
- `tests` blocks parsed with Babel
|
|
6
26
|
|
|
7
|
-
|
|
27
|
+
To actually **modify** the files, I recommend committing your changes before doing this, run the command with the `--write` flag:
|
|
8
28
|
|
|
9
|
-
|
|
29
|
+
```
|
|
30
|
+
npx prettify-bru --write
|
|
31
|
+
```
|
|
10
32
|
|
|
11
|
-
|
|
33
|
+
⚠️ This will modify the files in place, use with caution.
|
package/cli.js
CHANGED
|
@@ -1,37 +1,43 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
|
|
3
3
|
import yargs from 'yargs';
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
4
|
+
import {hideBin} from 'yargs/helpers';
|
|
5
|
+
import {main} from './lib/main.js';
|
|
6
6
|
|
|
7
7
|
const argv = yargs(hideBin(process.argv))
|
|
8
|
-
.usage(`
|
|
9
|
-
Usage: $0 [
|
|
8
|
+
.usage(`
|
|
9
|
+
Usage: $0 [--write|-w] path
|
|
10
10
|
|
|
11
11
|
Running the command with no arguments will modify all files
|
|
12
12
|
|
|
13
13
|
`).options({
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
.parse();
|
|
14
|
+
w: {
|
|
15
|
+
type: 'boolean',
|
|
16
|
+
default: false
|
|
17
|
+
},
|
|
18
|
+
path: {
|
|
19
|
+
default: '.',
|
|
20
|
+
},
|
|
21
|
+
})
|
|
22
|
+
.describe({
|
|
23
|
+
w: 'Write mode (Formats files in place, overwriting contents)',
|
|
24
|
+
h: 'Display the help message',
|
|
25
|
+
})
|
|
26
|
+
.boolean(['w', 'h'])
|
|
27
|
+
.help()
|
|
28
|
+
.alias('h', 'help')
|
|
29
|
+
.alias('w', 'write')
|
|
30
|
+
.parse();
|
|
32
31
|
|
|
33
32
|
if (argv.h) {
|
|
34
|
-
|
|
33
|
+
yargs.showHelp();
|
|
35
34
|
} else {
|
|
36
|
-
|
|
35
|
+
go(argv._[0], argv.w);
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
function go(path, write) {
|
|
39
|
+
main(process.cwd(), path, write).catch((err) => {
|
|
40
|
+
console.error(err);
|
|
41
|
+
process.exitCode = 1;
|
|
42
|
+
});
|
|
37
43
|
}
|
package/lib/format.js
ADDED
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Uses Prettier to format blocks of JSON/JavaScript
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
import prettier from 'prettier'
|
|
6
|
+
|
|
7
|
+
// This Prettier config should match what the Bruno GUI implements
|
|
8
|
+
const prettierConfig = {
|
|
9
|
+
tabWidth: 4,
|
|
10
|
+
useTabs: false,
|
|
11
|
+
bracketSpacing: false,
|
|
12
|
+
trailingComma: "none",
|
|
13
|
+
endOfLine: "endOfLine",
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
const formattableBlocks = [
|
|
17
|
+
['body:json', 'json'],
|
|
18
|
+
['script:pre-request', 'babel'],
|
|
19
|
+
['script:post-request', 'babel'],
|
|
20
|
+
['tests', 'babel'],
|
|
21
|
+
]
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
export async function formatBlocks(originalContents) {
|
|
25
|
+
|
|
26
|
+
let fileOutcome = {
|
|
27
|
+
newContents: originalContents.replace(/\r\n/g, "\n"),
|
|
28
|
+
changed: false,
|
|
29
|
+
error_messages: []
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
let i
|
|
33
|
+
for (i in formattableBlocks) {
|
|
34
|
+
const blockOutcome = await formatBlock(fileOutcome.newContents, ...formattableBlocks[i])
|
|
35
|
+
if (blockOutcome.error_message !== null) {
|
|
36
|
+
fileOutcome.error_messages.push(blockOutcome.error_message)
|
|
37
|
+
} else if (blockOutcome.changed) {
|
|
38
|
+
fileOutcome.changed = true
|
|
39
|
+
fileOutcome.newContents = blockOutcome.fileContents;
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
return fileOutcome
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
async function formatBlock(fileContents, blockName, parser) {
|
|
47
|
+
|
|
48
|
+
let outcome = {fileContents, changed: false, error_message: null};
|
|
49
|
+
|
|
50
|
+
const blockBodyRegex = new RegExp('\n' + blockName + ' [{]\\n(.+?)\\n}\\n', 's')
|
|
51
|
+
const match = fileContents.match(blockBodyRegex)
|
|
52
|
+
if (match === null) {
|
|
53
|
+
return outcome
|
|
54
|
+
}
|
|
55
|
+
const rawBody = match[1]
|
|
56
|
+
|
|
57
|
+
// Remove 2-spaces of indentation, added due to being inside a Bru lang Multimap
|
|
58
|
+
const unindented = rawBody.replace(/^ /gm, "")
|
|
59
|
+
|
|
60
|
+
let prettierFormatted;
|
|
61
|
+
|
|
62
|
+
try {
|
|
63
|
+
prettierFormatted = await prettier.format(unindented, {
|
|
64
|
+
prettierConfig,
|
|
65
|
+
parser,
|
|
66
|
+
}).then((formatted) => formatted);
|
|
67
|
+
} catch (e) {
|
|
68
|
+
outcome.error_message = `Prettier could not format ${blockName} because...\n${e.message}`;
|
|
69
|
+
return outcome
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
const bodyLines = prettierFormatted.split("\n");
|
|
73
|
+
|
|
74
|
+
// Remove leading/trailing empty lines
|
|
75
|
+
while (bodyLines.length && bodyLines[0].trim() === "") bodyLines.shift();
|
|
76
|
+
while (bodyLines.length && bodyLines[bodyLines.length - 1].trim() === "") bodyLines.pop();
|
|
77
|
+
|
|
78
|
+
// Indent the whole body by 2 spaces so it sits inside the Bru lang Multimap
|
|
79
|
+
const indentedLines = bodyLines.map((l) => " " + l)
|
|
80
|
+
|
|
81
|
+
const formattedBody = indentedLines.join("\n");
|
|
82
|
+
|
|
83
|
+
if (formattedBody === rawBody) {
|
|
84
|
+
// Nothing has changed after formatting
|
|
85
|
+
return outcome
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
outcome.fileContents = fileContents.replace(rawBody, formattedBody)
|
|
89
|
+
outcome.changed = true
|
|
90
|
+
return outcome;
|
|
91
|
+
}
|
package/lib/main.js
ADDED
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Finds all .bru files and formats contents
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
import fs from 'fs'
|
|
6
|
+
import path from 'path'
|
|
7
|
+
import {formatBlocks} from './format.js'
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
*
|
|
11
|
+
* @param cwd {String} Current working directory
|
|
12
|
+
* @param path {String}
|
|
13
|
+
* @param write {Boolean}
|
|
14
|
+
* @returns {Promise<void>}
|
|
15
|
+
*/
|
|
16
|
+
export async function main(cwd, path, write) {
|
|
17
|
+
|
|
18
|
+
if (path === '.') {
|
|
19
|
+
path = cwd
|
|
20
|
+
} else if (!/^\//.test(path)) {
|
|
21
|
+
// Path is absolute, do not modify
|
|
22
|
+
} else {
|
|
23
|
+
// Append the relative path to the current working directory
|
|
24
|
+
path = cwd + '/' + path
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
const files = [];
|
|
28
|
+
|
|
29
|
+
walkDir(path, (p) => {
|
|
30
|
+
if (p.endsWith(".bru")) files.push(p);
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
if (files.length === 0) {
|
|
34
|
+
console.log("No .bru files found.");
|
|
35
|
+
return;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
console.log(`Found ${files.length} .bru file(s)\n`);
|
|
39
|
+
|
|
40
|
+
let changedFiles = [];
|
|
41
|
+
let erroredFiles = [];
|
|
42
|
+
|
|
43
|
+
for (const filePath of files) {
|
|
44
|
+
const outcome = await processFile(filePath);
|
|
45
|
+
|
|
46
|
+
let displayFilePath = filePath.replace(new RegExp('^' + cwd), "");
|
|
47
|
+
|
|
48
|
+
if (outcome.changed) {
|
|
49
|
+
changedFiles.push({displayFilePath, outcome});
|
|
50
|
+
} else if (outcome.error_messages.length) {
|
|
51
|
+
erroredFiles.push({displayFilePath, outcome});
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
if (changedFiles.length) {
|
|
56
|
+
console.log(`\x1b[4m\x1b[32mReformatted blocks in ${changedFiles.length} file(s):\x1b[0m\n`);
|
|
57
|
+
changedFiles.forEach((r) => console.log(`✏️ \x1b[32m${r.displayFilePath}\x1b[0m`));
|
|
58
|
+
console.log(" ")
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
if (erroredFiles.length) {
|
|
62
|
+
console.warn(`\x1b[4m\x1b[33mEncountered errors in ${erroredFiles.length} file(s):\x1b[0m\n`);
|
|
63
|
+
erroredFiles.forEach((r, i) => {
|
|
64
|
+
console.warn(`${i + 1}) ${r.displayFilePath}\n`)
|
|
65
|
+
r.outcome.error_messages.forEach((err) => {
|
|
66
|
+
console.warn(`⚠️ \x1b[33m${err}\x1b[0m\n`)
|
|
67
|
+
})
|
|
68
|
+
})
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
console.log(
|
|
72
|
+
`\x1b[35mProcessed ${files.length} .bru file(s).\x1b[0m Reformatted blocks in ${changedFiles.length}. Encountered errors in ${erroredFiles.length}.`
|
|
73
|
+
);
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
function walkDir(dir, onFile) {
|
|
77
|
+
// Skip node_modules by default
|
|
78
|
+
const skip = new Set(["node_modules", ".git"]);
|
|
79
|
+
let entries;
|
|
80
|
+
try {
|
|
81
|
+
entries = fs.readdirSync(dir, {withFileTypes: true});
|
|
82
|
+
} catch (e) {
|
|
83
|
+
return;
|
|
84
|
+
}
|
|
85
|
+
for (const entry of entries) {
|
|
86
|
+
const full = path.join(dir, entry.name);
|
|
87
|
+
if (entry.isDirectory()) {
|
|
88
|
+
if (skip.has(entry.name)) continue;
|
|
89
|
+
walkDir(full, onFile);
|
|
90
|
+
} else if (entry.isFile()) {
|
|
91
|
+
onFile(full);
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
async function processFile(filePath) {
|
|
97
|
+
const original = fs.readFileSync(filePath, "utf8");
|
|
98
|
+
|
|
99
|
+
const fileOutcome = await formatBlocks(original);
|
|
100
|
+
|
|
101
|
+
if (!fileOutcome.changed) {
|
|
102
|
+
return fileOutcome
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
fs.writeFileSync(filePath, fileOutcome.newContents, "utf8");
|
|
106
|
+
|
|
107
|
+
return fileOutcome;
|
|
108
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "prettify-bru",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.10",
|
|
4
4
|
"description": "Prettifies JSON and JavaScript blocks in Bruno .bru files",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"bruno",
|
|
@@ -20,17 +20,16 @@
|
|
|
20
20
|
"url": "git+https://github.com/martinjoiner/prettify-bru.git"
|
|
21
21
|
},
|
|
22
22
|
"license": "GPL-3.0-or-later",
|
|
23
|
-
"author": "Martin Joiner (
|
|
23
|
+
"author": "Martin Joiner (https://martinjoiner.co.uk)",
|
|
24
24
|
"type": "module",
|
|
25
25
|
"files": [
|
|
26
26
|
"index.js",
|
|
27
27
|
"cli.js",
|
|
28
|
-
"
|
|
28
|
+
"lib/"
|
|
29
29
|
],
|
|
30
|
-
"bin":
|
|
31
|
-
"prettify-bru": "./cli.js"
|
|
32
|
-
},
|
|
30
|
+
"bin": "./cli.js",
|
|
33
31
|
"dependencies": {
|
|
32
|
+
"prettier": "^3.3.3",
|
|
34
33
|
"yargs": "18.0.0"
|
|
35
34
|
},
|
|
36
35
|
"scripts": {
|
package/index.js
DELETED
package/src/index.js
DELETED