├── .gitignore ├── .travis.yml ├── CHANGES.md ├── LICENSE ├── README.md ├── fixtures ├── bad.clj ├── good.clj └── untrimmed.clj ├── package.json ├── parlinter.js ├── sync.sh ├── test.sh └── yarn.lock /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | fixtures/actual.clj 3 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: node_js 2 | node_js: 3 | - "7.4" 4 | -------------------------------------------------------------------------------- /CHANGES.md: -------------------------------------------------------------------------------- 1 | # 1.3.0 2 | 3 | - fix `--list-different` option (see [#4](https://github.com/shaunlebron/parlinter/pull/4), thanks [@zhanjing1214](https://github.com/zhanjing1214)) 4 | - only prints filenames of those unformatted 5 | - returns correct exit code (1 for unformatted file is found, 0 otherwise) 6 | 7 | # 1.2.0 8 | 9 | - update to Parinfer 3.9.0 10 | - shift comment indentation when parent forms are shifted 11 | - [extend indentation contraints](https://github.com/shaunlebron/parinfer/blob/master/lib/test/cases/paren-mode.md#extending-indentation-constraints) for better stability 12 | 13 | # 1.1.0 14 | 15 | - update to Parinfer 2.2.1 16 | - fix: do not process if unmatched close-parens found anywhere 17 | 18 | # 1.0.1 19 | 20 | - fix `parlinter` binary publish 21 | 22 | # 1.0.0 23 | 24 | - Public release (readme changes) 25 | - `--trim` removes lines that become empty after linting 26 | 27 | # 0.1.0 28 | 29 | - Initial early release 30 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2017 Shaun Williams and contributors 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 4 | 5 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 6 | 7 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 8 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Parlinter 2 | 3 | A low-friction linter for Lisp that finally allows your team members to use [Parinfer]. 4 | 5 | Unlike full pretty-printers, it preserves as much of the original source as 6 | possible, only fixing _confusing indentation_ and _dangling close-parens_. But 7 | it's still flexible, allowing any-space indentation within thresholds. 8 | 9 | Adopt Parlinter to make your project Parinfer friendly! 10 | 11 | ![parinfer friendly](https://img.shields.io/badge/parinfer-friendly-ff69b4.svg) [![Build Status](https://travis-ci.org/shaunlebron/parlinter.svg?branch=master)](https://travis-ci.org/shaunlebron/parlinter) 12 | 13 | ## Want a Quick Look? 14 | 15 | - See concrete examples of [Common Lint Results in Clojure]. 16 | - See the only [Two Rules] it follows. 17 | - [Try it out on your project] then check `git diff -w` to verify the minor changes. 18 | 19 | [Common Lint Results in Clojure]:#common-lint-results-in-clojure 20 | [Two Rules]:#two-rules 21 | [Try it out on your project]:#install 22 | 23 | ## Two Rules 24 | 25 | Parlinter performs minimal source transformation in order to satisfy two rules: 26 | 27 | ### Rule #1 - no dangling close-parens 28 | 29 | Close-parens at the beginning of a line are moved to the end of its previous 30 | token: 31 | 32 | ```clj 33 | ;; bad 34 | (foo (bar 35 | ) baz 36 | ) ^ 37 | ^ 38 | 39 | ;; fixed 40 | (foo (bar) 41 | baz) ^ 42 | ^ 43 | ``` 44 | 45 | > __Conventional Formatters__ comply with Rule #1 for all cases except to allow 46 | > [close-parens after a comment]. Parlinter does NOT make this exception. 47 | 48 | [close-parens after a comment]:#2-close-parens-after-comments 49 | 50 | ### Rule #2 - ordered indentation 51 | 52 | Newlines must be indented to the right of their parent open-paren: 53 | 54 | ```clj 55 | (foo (bar) 56 | | 57 | | 58 | > 59 | bar) ;; must be indented to the right of the point above: ✔️ 60 | ^ 61 | ``` 62 | 63 | But they cannot extend too far right into another open-paren: 64 | 65 | ```clj 66 | (foo (bar) 67 | | 68 | | 69 | < 70 | bar) ;; must be indented to the left of the point above: ✔️ 71 | ^ 72 | ``` 73 | 74 | To fix, indentation is clamped to these points: 75 | 76 | ```clj 77 | ;; bad 78 | (foo (bar) 79 | baz) 80 | 81 | ;; fixed 82 | (foo (bar) 83 | baz) ;; <-- nudged to the right 84 | ``` 85 | 86 | ```clj 87 | ;; bad 88 | (foo (bar) 89 | baz) 90 | 91 | ;; fixed 92 | (foo (bar) 93 | baz) ;; <-- nudged to the left 94 | ``` 95 | 96 | > __Conventional formatters__ comply with Rule #2 for all cases, except 97 | > [clojure.pprint] and older versions of [clojure-mode], which cause extra indentation 98 | > of [multi-arity function bodies]. 99 | 100 | [Compatibility]:#compatibility 101 | [multi-arity function bodies]:#1-multi-arity-function-bodies 102 | 103 | ## Install 104 | 105 | ``` 106 | npm install -g parlinter 107 | or 108 | yarn global add parlinter 109 | ``` 110 | 111 | > Want to use as a plugin in your build environment instead? (e.g. lein, boot) Help wanted! Please [create an issue]. 112 | 113 | [create an issue]:https://github.com/shaunlebron/parlinter/issues/new 114 | 115 | ## Usage 116 | 117 | ``` 118 | $ parlinter 119 | 120 | Usage: parlinter [opts] [filename|glob ...] 121 | 122 | Available options: 123 | --write Edit the file in-place. (Beware!) 124 | --trim Remove lines that become empty after linting. 125 | --list-different or -l Print filenames of files that are different from Parlinter formatting. 126 | --stdin Read input from stdin. 127 | --version or -v Print Parlinter version. 128 | ``` 129 | 130 | [Glob patterns](https://github.com/isaacs/node-glob#glob-primer) must be quoted. 131 | 132 | ## Examples 133 | 134 | Format all clojure files: 135 | 136 | ``` 137 | parlinter --trim --write "**/*.{clj,cljs,cljc,edn}" 138 | ``` 139 | 140 | Verify non-whitespace changes below for peace-of-mind: (AST not changed) 141 | 142 | ``` 143 | git diff -w 144 | ``` 145 | 146 | Check if all clojure files are properly formatted (non-zero exit code if not): 147 | 148 | ``` 149 | $ parlinter -l "**/*.{clj,cljs,cljc,edn}" 150 | ``` 151 | 152 | ## Performance 153 | 154 | It takes ~0.5s to run against ~40k lines. (tested on the [Clojure] and [ClojureScript] project repos) 155 | 156 | It was heavily optimized to allow [Parinfer] to run at 60hz on a ~3k line file 157 | while typing. 158 | 159 | [Clojure]:https://github.com/clojure/clojure 160 | [ClojureScript]:https://github.com/clojure/clojurescript 161 | 162 | ## Compatibility 163 | 164 | _Syntactically_ compatible with Clojure, Racket, Scheme, and other Lisps that follow this syntax: 165 | 166 | - delimiters `(`, `{`, `[` 167 | - strings `"` 168 | - characters `\` 169 | - comments `;` 170 | 171 | _Culturally_ compatible with standard Lisp styles\*: 172 | 173 | - [Lisp Indentation] 174 | - [Clojure Style Guide] 175 | - [Google Common Lisp Style Guide] 176 | - [Racket Style Guide] 177 | 178 | > _\* some allow close-parens on their own line, but still allow them to be 179 | removed as Parlinter does_ 180 | 181 | [Lisp Indentation]:http://wiki.c2.com/?LispIndentation 182 | [Racket Style Guide]:http://docs.racket-lang.org/style/Textual_Matters.html 183 | [Google Common Lisp Style Guide]:https://google.github.io/styleguide/lispguide.xml 184 | 185 | ## Common Lint Results in Clojure 186 | 187 | A collection of common changes performed by Parlinter on Clojure code—the 188 | Lisp I am most familiar with. 189 | 190 | ### 1. Multi-arity function bodies 191 | 192 | Sometimes function bodies for multi-arity functions are indented past the 193 | function params. 194 | 195 | ```clj 196 | ;; bad 197 | (defn foo 198 | "I have two arities." 199 | ([x] 200 | (foo x 1)) 201 | ([x y] 202 | (+ x y))) 203 | 204 | ;; fixed 205 | (defn foo 206 | "I have two arities." 207 | ([x] 208 | (foo x 1)) 209 | ([x y] 210 | (+ x y))) 211 | ``` 212 | 213 | ### 2. Close-parens after comments 214 | 215 | Since close-parens cannot be at the beginning of a line, they cannot come after 216 | comments. 217 | 218 | ```clj 219 | ;; bad 220 | (-> 10 221 | (foo 20) 222 | (bar 30) 223 | ;; my comment 224 | ) 225 | 226 | ;; fixed 227 | (-> 10 228 | (foo 20) 229 | (bar 30)) 230 | ;; my comment 231 | ``` 232 | 233 | ### 3. Lines inside strings are not touched 234 | 235 | Indentation of lines inside multi-line strings is significant, so it is not 236 | modified: 237 | 238 | ```clj 239 | ;; bad 240 | (foo (bar 241 | "Hello 242 | world")) 243 | 244 | ;; fixed 245 | (foo (bar 246 | "Hello 247 | world")) ;; <-- not nudged 248 | ``` 249 | 250 | ### 4. Recessed function bodies 251 | 252 | Function bodies are sometimes indented to its grandparent form rather than its 253 | parent: 254 | 255 | ```clj 256 | ;; bad 257 | (foo bar (fn [a] 258 | (println a))) 259 | 260 | ;; fixed 261 | (foo bar (fn [a] 262 | (println a))) ;; <-- nudged to be inside "(fn" 263 | ``` 264 | 265 | ### 5. Recessed lines after JSON-style `{` 266 | 267 | It is sometimes common to use JSON-style indentation in a top-level EDN config: 268 | 269 | ```clj 270 | ;; bad 271 | :cljsbuild { 272 | :builds [...] 273 | } 274 | 275 | ;; fixed 276 | :cljsbuild { 277 | :builds [...]} ;; <-- nudged to be inside "{" 278 | 279 | ;; fine (but not automated) 280 | :cljsbuild {:builds [...]} 281 | 282 | ;; fine (but not automated) 283 | :cljsbuild 284 | {:builds [...]} 285 | ``` 286 | 287 | ### 6. Recessed lines after `#_` and `comment` 288 | 289 | Comment and ignore forms are commonly added retroactively without adjusting 290 | indentation: 291 | 292 | ```clj 293 | ;; bad 294 | #_(defn foo [] 295 | (bar baz)) 296 | 297 | ;; fixed 298 | #_(defn foo [] 299 | (bar baz)) 300 | ``` 301 | 302 | ```clj 303 | ;; bad 304 | (comment 305 | (defn foo [] 306 | (bar baz)) 307 | ) 308 | 309 | ;; fixed 310 | (comment 311 | (defn foo [] 312 | (bar baz))) 313 | ``` 314 | 315 | ### 7. Vertically-aligned comments 316 | 317 | Linting may throw off the alignment of comments, due to paren movement: 318 | 319 | ```clj 320 | ;; bad 321 | (let [foo 1 ; this is number one 322 | bar 2 ; this is number two 323 | ] 324 | (+ foo bar)) 325 | 326 | ;; fixed 327 | (let [foo 1 ; this is number one 328 | bar 2] ; this is number two 329 | (+ foo bar)) 330 | ``` 331 | 332 | ## Motivation 333 | 334 | Though [Parinfer] was designed to lower the barrier for newcomers, it faced a 335 | problem of practicality by not allowing them to collaborate smoothly with people 336 | who didn't use it. This friction was not part of the intended experience. 337 | 338 | Parlinter was designed as an answer to this problem, since there now seems to be 339 | a growing acceptance of linters and even full-formatters like [Prettier], 340 | [refmt], and [gofmt] from other language communities. 341 | 342 | Thus, I hope that Parlinter at least spurs some thoughts on what is an 343 | acceptable amount of process around linting in Lisp, whether or not Parinfer is 344 | worth linting for, and how else we can help newcomers get into Lisp easier. 345 | 346 | (It may also open the door for some exciting next-gen things I'm not yet ready 347 | to talk about.) 348 | 349 | Written for Lisp with <3 350 | 351 | [Prettier]:https://github.com/prettier/prettier 352 | [refmt]:https://facebook.github.io/reason/tools.html#tools-command-line-utilities-refmt 353 | [gofmt]:https://golang.org/cmd/gofmt/ 354 | 355 | [clojure.pprint]:https://clojure.github.io/clojure/clojure.pprint-api.html 356 | [clojure-mode]:https://github.com/clojure-emacs/clojure-mode 357 | [fipp]:https://github.com/brandonbloom/fipp 358 | [cljfmt]:https://github.com/weavejester/cljfmt 359 | [zprint]:https://github.com/kkinnear/zprint 360 | 361 | 362 | [Clojure Style Guide]:https://github.com/bbatsov/clojure-style-guide 363 | [Parinfer]:http://shaunlebron.github.io/parinfer/ 364 | -------------------------------------------------------------------------------- /fixtures/bad.clj: -------------------------------------------------------------------------------- 1 | 2 | (foo 3 | bar 4 | ) 5 | 6 | -------------------------------------------------------------------------------- /fixtures/good.clj: -------------------------------------------------------------------------------- 1 | 2 | (foo 3 | bar) 4 | 5 | -------------------------------------------------------------------------------- /fixtures/untrimmed.clj: -------------------------------------------------------------------------------- 1 | 2 | (foo 3 | bar) 4 | 5 | 6 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "parlinter", 3 | "version": "1.3.0", 4 | "description": "A minimal formatting linter for Lisp code (using Parinfer)", 5 | "main": "parlinter.js", 6 | "repository": "https://github.com/shaunlebron/parlinter", 7 | "author": "Shaun Lebron ", 8 | "license": "MIT", 9 | "bin": { 10 | "parlinter": "parlinter.js" 11 | }, 12 | "scripts": { 13 | "test": "./test.sh" 14 | }, 15 | "files": [ 16 | "README.md", 17 | "CHANGES.md", 18 | "parlinter.js" 19 | ], 20 | "dependencies": { 21 | "chalk": "^1.1.3", 22 | "get-stdin": "^5.0.1", 23 | "glob": "^7.1.2", 24 | "minimist": "^1.2.0", 25 | "parinfer": "^3.9.0", 26 | "readline": "^1.3.0" 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /parlinter.js: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | 3 | // Parlinter 1.3.0 4 | 5 | // Source copied from Prettier's CLI! (MIT License) 6 | // https://github.com/prettier/prettier/blob/master/bin/prettier.js 7 | 8 | "use strict"; 9 | 10 | const fs = require("fs"); 11 | const getStdin = require("get-stdin"); 12 | const glob = require("glob"); 13 | const chalk = require("chalk"); 14 | const minimist = require("minimist"); 15 | const readline = require("readline"); 16 | const parinfer = require("parinfer"); 17 | 18 | const version = "1.3.0"; 19 | 20 | const argv = minimist(process.argv.slice(2), { 21 | boolean: ["write", "trim", "stdin", "help", "version", "list-different"], 22 | alias: { help: "h", version: "v", "list-different": "l" }, 23 | unknown: param => { 24 | if (param.startsWith("-")) { 25 | console.warn("Ignored unknown option: " + param + "\n"); 26 | return false; 27 | } 28 | } 29 | }); 30 | 31 | if (argv["version"]) { 32 | console.log( 33 | "Parlinter " + version + " (using Parinfer " + parinfer.version + ")" 34 | ); 35 | process.exit(0); 36 | } 37 | 38 | const filepatterns = argv["_"]; 39 | const write = argv["write"]; 40 | const trim = argv["trim"]; 41 | const stdin = argv["stdin"] || (!filepatterns.length && !process.stdin.isTTY); 42 | const globOptions = { 43 | dot: true 44 | }; 45 | 46 | function getLineEnding(text) { 47 | // NOTE: We assume that if the CR char "\r" is used anywhere, 48 | // then we should use CRLF line-endings after every line. 49 | var i = text.search("\r"); 50 | if (i !== -1) { 51 | return "\r\n"; 52 | } 53 | return "\n"; 54 | } 55 | 56 | function trimOutput(input, output) { 57 | const inLines = input.split(/\r?\n/); 58 | const outLines = output.split(/\r?\n/); 59 | const trimLines = []; 60 | const empty = /^\s*$/; 61 | for (let i = 0; i < outLines.length; i++) { 62 | const emptyAfterLinting = !empty.test(inLines[i]) && empty.test(outLines[i]); 63 | if (!emptyAfterLinting) { 64 | trimLines.push(outLines[i]); 65 | } 66 | } 67 | return trimLines.join(getLineEnding(output)); 68 | } 69 | 70 | function format(input) { 71 | const result = parinfer.parenMode(input); 72 | if (result.error) { 73 | throw result.error; 74 | } 75 | const output = result.text; 76 | return trim ? trimOutput(input, output) : output; 77 | } 78 | 79 | function handleError(filename, e) { 80 | console.error( 81 | filename + ":" + (e.lineNo + 1) + ":" + e.x + " - " + e.message 82 | ); 83 | 84 | // Don't exit the process if one file failed 85 | process.exitCode = 2; 86 | } 87 | 88 | if (argv["help"] || (!filepatterns.length && !stdin)) { 89 | console.log( 90 | "\n" + 91 | "Usage: parlinter [opts] [filename ...]\n" + 92 | "\n" + 93 | "A minimal formatting linter for Lisp code (using Parinfer)\n" + 94 | "\n" + 95 | "Available options:\n" + 96 | " --write Edit the file in-place. (Beware!)\n" + 97 | " --trim Remove lines that become empty after linting.\n" + 98 | " --list-different or -l Print filenames of files that are different from Parlinter formatting.\n" + 99 | " --stdin Read input from stdin.\n" + 100 | " --version or -v Print Parlinter version.\n" + 101 | "\n" 102 | ); 103 | process.exit(argv["help"] ? 0 : 1); 104 | } 105 | 106 | if (stdin) { 107 | getStdin().then(input => { 108 | try { 109 | writeOutput(format(input)); 110 | } catch (e) { 111 | handleError("stdin", e); 112 | return; 113 | } 114 | }); 115 | } else { 116 | eachFilename(filepatterns, filename => { 117 | if (write) { 118 | // Don't use `console.log` here since we need to replace this line. 119 | process.stdout.write(filename); 120 | } 121 | 122 | let input; 123 | try { 124 | input = fs.readFileSync(filename, "utf8"); 125 | } catch (e) { 126 | // Add newline to split errors from filename line. 127 | process.stdout.write("\n"); 128 | 129 | console.error("Unable to read file: " + filename + "\n" + e); 130 | // Don't exit the process if one file failed 131 | process.exitCode = 2; 132 | return; 133 | } 134 | 135 | const start = Date.now(); 136 | 137 | let output; 138 | 139 | try { 140 | output = format(input); 141 | } catch (e) { 142 | // Add newline to split errors from filename line. 143 | process.stdout.write("\n"); 144 | 145 | handleError(filename, e); 146 | return; 147 | } 148 | 149 | if (argv["list-different"]) { 150 | if (output !== input) { 151 | if (!write) { 152 | console.log(filename); 153 | } 154 | process.exitCode = 1; 155 | } 156 | } 157 | 158 | if (write) { 159 | // Remove previously printed filename to log it with duration. 160 | readline.clearLine(process.stdout, 0); 161 | readline.cursorTo(process.stdout, 0, null); 162 | 163 | // Don't write the file if it won't change in order not to invalidate 164 | // mtime based caches. 165 | if (output === input) { 166 | if (!argv["list-different"]) { 167 | console.log(chalk.grey("%s %dms"), filename, Date.now() - start); 168 | } 169 | } else { 170 | if (argv["list-different"]) { 171 | console.log(filename); 172 | } else { 173 | console.log("%s %dms", filename, Date.now() - start); 174 | } 175 | 176 | try { 177 | fs.writeFileSync(filename, output, "utf8"); 178 | } catch (err) { 179 | console.error("Unable to write file: " + filename + "\n" + err); 180 | // Don't exit the process if one file failed 181 | process.exitCode = 2; 182 | } 183 | } 184 | } else if (!argv["list-different"]) { 185 | writeOutput(output); 186 | } 187 | }); 188 | } 189 | 190 | function writeOutput(text) { 191 | // Don't use `console.log` here since it adds an extra newline at the end. 192 | process.stdout.write(text); 193 | } 194 | 195 | function eachFilename(patterns, callback) { 196 | patterns.forEach(pattern => { 197 | if (!glob.hasMagic(pattern)) { 198 | callback(pattern); 199 | return; 200 | } 201 | 202 | glob(pattern, globOptions, (err, filenames) => { 203 | if (err) { 204 | console.error("Unable to expand glob pattern: " + pattern + "\n" + err); 205 | // Don't exit the process if one pattern failed 206 | process.exitCode = 2; 207 | return; 208 | } 209 | 210 | filenames.forEach(filename => { 211 | callback(filename); 212 | }); 213 | }); 214 | }); 215 | } 216 | -------------------------------------------------------------------------------- /sync.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | ## Sync dependent files with each other: 4 | ## - package.json version => parlinter.js 5 | 6 | jsfile=parlinter.js 7 | 8 | ##---------------------------------------------------------------------------- 9 | ## Version sync 10 | ##---------------------------------------------------------------------------- 11 | 12 | # Get package.json version. 13 | version=$(perl -n -e'/"version": "(.+)"/ && print "$1"' package.json) 14 | 15 | # Sync version 16 | sed -i.bak "s|^// Parlinter .*|// Parlinter $version|" $jsfile 17 | sed -i.bak "s|^const version = .*|const version = \"$version\";|" $jsfile 18 | rm ${jsfile}.bak 19 | 20 | echo "Updated $jsfile with package.json version $version" 21 | echo 22 | -------------------------------------------------------------------------------- /test.sh: -------------------------------------------------------------------------------- 1 | 2 | bad=fixtures/bad.clj 3 | good=fixtures/good.clj 4 | untrimmed=fixtures/untrimmed.clj 5 | temp=fixtures/temp.clj 6 | actual=fixtures/actual.clj 7 | 8 | # default 9 | node parlinter.js $bad > $temp 10 | restore() { 11 | rm $temp 12 | } 13 | if ! diff $temp $untrimmed > /dev/null; then 14 | echo "Test Failed for --write : expected $bad to be corrected to match $untrimmed." 15 | echo "Check $actual for actual output." 16 | cp $temp $actual 17 | restore 18 | exit 1 19 | fi 20 | restore 21 | 22 | 23 | # --write 24 | cp $bad $temp 25 | node parlinter.js --write $bad > /dev/null 26 | restore() { 27 | cp $temp $bad 28 | rm $temp 29 | } 30 | if ! diff $bad $untrimmed > /dev/null; then 31 | echo "Test Failed for --write : expected $bad to be corrected to match $good." 32 | echo "Check $actual for actual output." 33 | cp $bad $actual 34 | restore 35 | exit 1 36 | fi 37 | restore 38 | 39 | # --trim 40 | node parlinter.js --trim $bad > $temp 41 | restore() { 42 | rm $temp 43 | } 44 | if ! diff $temp $good > /dev/null; then 45 | echo "Test Failed for --trim : expected $bad to trim down to $good." 46 | echo "Check $actual for actual output." 47 | cp $temp $actual 48 | restore 49 | exit 1 50 | fi 51 | restore 52 | 53 | # --list different 54 | if node parlinter.js -l $bad > /dev/null; then 55 | echo "Test Failed for --list-different : expected $bad to be listed" 56 | exit 1 57 | fi 58 | if ! node parlinter.js -l $good > /dev/null; then 59 | echo "Test Failed for --list-different : expected $good to not be listed" 60 | exit 1 61 | fi 62 | if ! node parlinter.js -l $untrimmed > /dev/null; then 63 | echo "Test Failed for --list-different : expected $untrimmed to not be listed" 64 | exit 1 65 | fi 66 | 67 | echo "TESTS PASSED." 68 | -------------------------------------------------------------------------------- /yarn.lock: -------------------------------------------------------------------------------- 1 | # THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. 2 | # yarn lockfile v1 3 | 4 | 5 | ansi-regex@^2.0.0: 6 | version "2.1.1" 7 | resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-2.1.1.tgz#c3b33ab5ee360d86e0e628f0468ae7ef27d654df" 8 | 9 | ansi-styles@^2.2.1: 10 | version "2.2.1" 11 | resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-2.2.1.tgz#b432dd3358b634cf75e1e4664368240533c1ddbe" 12 | 13 | balanced-match@^0.4.1: 14 | version "0.4.2" 15 | resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-0.4.2.tgz#cb3f3e3c732dc0f01ee70b403f302e61d7709838" 16 | 17 | brace-expansion@^1.1.7: 18 | version "1.1.7" 19 | resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.7.tgz#3effc3c50e000531fb720eaff80f0ae8ef23cf59" 20 | dependencies: 21 | balanced-match "^0.4.1" 22 | concat-map "0.0.1" 23 | 24 | chalk@^1.1.3: 25 | version "1.1.3" 26 | resolved "https://registry.yarnpkg.com/chalk/-/chalk-1.1.3.tgz#a8115c55e4a702fe4d150abd3872822a7e09fc98" 27 | dependencies: 28 | ansi-styles "^2.2.1" 29 | escape-string-regexp "^1.0.2" 30 | has-ansi "^2.0.0" 31 | strip-ansi "^3.0.0" 32 | supports-color "^2.0.0" 33 | 34 | concat-map@0.0.1: 35 | version "0.0.1" 36 | resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b" 37 | 38 | escape-string-regexp@^1.0.2: 39 | version "1.0.5" 40 | resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4" 41 | 42 | fs.realpath@^1.0.0: 43 | version "1.0.0" 44 | resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f" 45 | 46 | get-stdin@^5.0.1: 47 | version "5.0.1" 48 | resolved "https://registry.yarnpkg.com/get-stdin/-/get-stdin-5.0.1.tgz#122e161591e21ff4c52530305693f20e6393a398" 49 | 50 | glob@^7.1.2: 51 | version "7.1.2" 52 | resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.2.tgz#c19c9df9a028702d678612384a6552404c636d15" 53 | dependencies: 54 | fs.realpath "^1.0.0" 55 | inflight "^1.0.4" 56 | inherits "2" 57 | minimatch "^3.0.4" 58 | once "^1.3.0" 59 | path-is-absolute "^1.0.0" 60 | 61 | has-ansi@^2.0.0: 62 | version "2.0.0" 63 | resolved "https://registry.yarnpkg.com/has-ansi/-/has-ansi-2.0.0.tgz#34f5049ce1ecdf2b0649af3ef24e45ed35416d91" 64 | dependencies: 65 | ansi-regex "^2.0.0" 66 | 67 | inflight@^1.0.4: 68 | version "1.0.6" 69 | resolved "https://registry.yarnpkg.com/inflight/-/inflight-1.0.6.tgz#49bd6331d7d02d0c09bc910a1075ba8165b56df9" 70 | dependencies: 71 | once "^1.3.0" 72 | wrappy "1" 73 | 74 | inherits@2: 75 | version "2.0.3" 76 | resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.3.tgz#633c2c83e3da42a502f52466022480f4208261de" 77 | 78 | minimatch@^3.0.4: 79 | version "3.0.4" 80 | resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.0.4.tgz#5166e286457f03306064be5497e8dbb0c3d32083" 81 | dependencies: 82 | brace-expansion "^1.1.7" 83 | 84 | minimist@^1.2.0: 85 | version "1.2.0" 86 | resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.0.tgz#a35008b20f41383eec1fb914f4cd5df79a264284" 87 | 88 | once@^1.3.0: 89 | version "1.4.0" 90 | resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1" 91 | dependencies: 92 | wrappy "1" 93 | 94 | parinfer@^3.9.0: 95 | version "3.9.0" 96 | resolved "https://registry.yarnpkg.com/parinfer/-/parinfer-3.9.0.tgz#22f7d1d1fbcac347d46f3864181f546e103b8830" 97 | 98 | path-is-absolute@^1.0.0: 99 | version "1.0.1" 100 | resolved "https://registry.yarnpkg.com/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f" 101 | 102 | readline@^1.3.0: 103 | version "1.3.0" 104 | resolved "https://registry.yarnpkg.com/readline/-/readline-1.3.0.tgz#c580d77ef2cfc8752b132498060dc9793a7ac01c" 105 | 106 | strip-ansi@^3.0.0: 107 | version "3.0.1" 108 | resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-3.0.1.tgz#6a385fb8853d952d5ff05d0e8aaf94278dc63dcf" 109 | dependencies: 110 | ansi-regex "^2.0.0" 111 | 112 | supports-color@^2.0.0: 113 | version "2.0.0" 114 | resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-2.0.0.tgz#535d045ce6b6363fa40117084629995e9df324c7" 115 | 116 | wrappy@1: 117 | version "1.0.2" 118 | resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f" 119 | --------------------------------------------------------------------------------