prettify-bru 0.1.9 → 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 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
- `npm i prettify-bru`
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
- Boom, now you're ready you can run:
27
+ To actually **modify** the files, I recommend committing your changes before doing this, run the command with the `--write` flag:
8
28
 
9
- `npx prettify-bru -d .`
29
+ ```
30
+ npx prettify-bru --write
31
+ ```
10
32
 
11
- The above command will sweep through all directories looking to `.bru` files and it will find any `body:json` blocks and prettify the JSON inside.
33
+ ⚠️ This will modify the files in place, use with caution.
package/cli.js CHANGED
@@ -1,36 +1,43 @@
1
1
  #!/usr/bin/env node
2
2
 
3
3
  import yargs from 'yargs';
4
- import { hideBin } from 'yargs/helpers';
5
- import { go } from './index.js';
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(`
8
+ .usage(`
9
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
- 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();
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();
31
31
 
32
32
  if (argv.h) {
33
- yargs.showHelp();
33
+ yargs.showHelp();
34
34
  } else {
35
- go(argv.w, argv._[0]);
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
+ });
36
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.9",
3
+ "version": "0.1.10",
4
4
  "description": "Prettifies JSON and JavaScript blocks in Bruno .bru files",
5
5
  "keywords": [
6
6
  "bruno",
@@ -20,15 +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 (http://martinjoiner.co.uk)",
23
+ "author": "Martin Joiner (https://martinjoiner.co.uk)",
24
24
  "type": "module",
25
25
  "files": [
26
26
  "index.js",
27
27
  "cli.js",
28
- "src/"
28
+ "lib/"
29
29
  ],
30
30
  "bin": "./cli.js",
31
31
  "dependencies": {
32
+ "prettier": "^3.3.3",
32
33
  "yargs": "18.0.0"
33
34
  },
34
35
  "scripts": {
package/index.js DELETED
@@ -1,13 +0,0 @@
1
- export function go(path, write) {
2
- if (path === '.') {
3
- path = process.cwd()
4
- } else if (!/^\//.test(path)) {
5
- // Path is absolute, do not modify
6
- } else {
7
- // Turn relative path into absolute
8
- path = process.cwd() + '/' + path
9
- }
10
-
11
- console.log("go() method inside index.js");
12
- console.log(path, write);
13
- };
package/src/index.js DELETED
@@ -1,3 +0,0 @@
1
- export function check() {
2
- console.log("This is check");
3
- }