redlint 1.0.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.
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) coderaiser
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,326 @@
1
+ # Printer [![License][LicenseIMGURL]][LicenseURL] [![NPM version][NPMIMGURL]][NPMURL] [![Build Status][BuildStatusIMGURL]][BuildStatusURL] [![Coverage Status][CoverageIMGURL]][CoverageURL]
2
+
3
+ [NPMURL]: https://npmjs.org/package/@putout/printer "npm"
4
+ [NPMIMGURL]: https://img.shields.io/npm/v/@putout/printer.svg?style=flat&longCache=true
5
+ [BuildStatusURL]: https://github.com/putoutjs/printer/actions/workflows/nodejs.yml "Build Status"
6
+ [BuildStatusIMGURL]: https://github.com/putoutjs/printer/actions/workflows/nodejs.yml/badge.svg
7
+ [LicenseURL]: https://tldrlegal.com/license/mit-license "MIT License"
8
+ [LicenseIMGURL]: https://img.shields.io/badge/license-MIT-317BF9.svg?style=flat
9
+ [CoverageURL]: https://coveralls.io/github/putoutjs/printer?branch=master
10
+ [CoverageIMGURL]: https://coveralls.io/repos/putoutjs/printer/badge.svg?branch=master&service=github
11
+
12
+ Prints [**Babel AST**](https://github.com/coderaiser/estree-to-babel) to readable **JavaScript**. For **ESTree** use [`estree-to-babel`](https://github.com/coderaiser/estree-to-babel).
13
+
14
+ - ☝️ Similar to **Recast**, but [twice faster](#speed-comparison), also simpler and easier in maintenance, since it supports only **Babel**.
15
+ - ☝️ As opinionated as **Prettier**, but has more user-friendly output and works directly with **AST**.
16
+ - ☝️ Like **ESLint** but works directly with **Babel AST**.
17
+ - ☝️ Easily extendable with help of [Overrides](#overrides).
18
+
19
+ Supports:
20
+
21
+ - ✅ **ES2023**;
22
+ - ✅ **JSX**;
23
+ - ✅ **TypeScript**;
24
+ - ✅ [**JSON**](https://github.com/coderaiser/putout/tree/master/packages/processor-json#readme);
25
+
26
+ ## Install
27
+
28
+ ```
29
+ npm i @putout/printer
30
+ ```
31
+
32
+ ## 🐊 Support of Printer
33
+
34
+ **Printer** has first class support from 🐊**Putout** with help of [`@putout/plugin-printer`](https://github.com/coderaiser/putout/tree/master/packages/plugin-printer#putoutplugin-printer-). So install:
35
+
36
+ ```sh
37
+ npm i @putout/plugin-printer -aD
38
+ ```
39
+
40
+ And update `.putout.json`:
41
+
42
+ ```json
43
+ {
44
+ "printer": "putout",
45
+ "plugins": ["printer"]
46
+ }
47
+ ```
48
+
49
+ To benefit from it.
50
+
51
+ ## Example
52
+
53
+ ```js
54
+ const {print} = require('@putout/printer');
55
+ const {parse} = require('@babel/parser');
56
+ const ast = parse('const a = (b, c) => {const d = 5; return a;}');
57
+
58
+ print(ast);
59
+ // returns
60
+ `
61
+ const a = (b, c) => {
62
+ const d = 5;
63
+ return a;
64
+ };
65
+ `;
66
+ ```
67
+
68
+ ## Overrides
69
+
70
+ When you need to extend syntax of `@putout/printer` just pass a function which receives:
71
+
72
+ - `path`, Babel Path
73
+ - `write`, a function to output result of printing into token array;
74
+
75
+ When `path` contains to dashes `__` and name, it is the same as: `write(path.get('right'))`, and this is
76
+ actually `traverse(path.get('right'))` shortened to simplify read and process.
77
+
78
+ Here is how you can override `AssignmentPattern`:
79
+
80
+ ```js
81
+ const ast = parse('const {a = 5} = b');
82
+
83
+ print(ast, {
84
+ format: {
85
+ indent: ' ',
86
+ newline: '\n',
87
+ space: ' ',
88
+ splitter: '\n',
89
+ roundBraceOpen: '(',
90
+ roundBraceClose: ')',
91
+ quote: `'`,
92
+ endOfFile: '\n',
93
+ },
94
+ semantics: {
95
+ comments: true,
96
+ maxSpecifiersInOneLine: 2,
97
+ maxElementsInOneLine: 3,
98
+ maxVariablesInOneLine: 4,
99
+ maxPropertiesInOneLine: 2,
100
+ trailingComma: true,
101
+ },
102
+ visitors: {
103
+ AssignmentPattern(path, {print}) {
104
+ print('/* [hello world] */= ');
105
+ print('__right');
106
+ },
107
+ },
108
+ });
109
+
110
+ // returns
111
+ 'const {a/* [hello world] */= 5} = b;\n';
112
+ ```
113
+
114
+ ### `format`
115
+
116
+ Options related to visuals and not related to logic of output can be changed with help of `format`,
117
+ you can override next options:
118
+
119
+ ```js
120
+ const overrides = {
121
+ format: {
122
+ indent: ' ',
123
+ newline: '\n',
124
+ space: ' ',
125
+ splitter: '\n',
126
+ roundBraceOpen: '(',
127
+ roundBraceClose: ')',
128
+ endOfFile: '\n',
129
+ },
130
+ };
131
+ ```
132
+
133
+ - `indent` - use two spaces, tabs, or anything you want;
134
+ - `newline` - symbol for used for line separation;
135
+ - `space` - default symbol used for space character;
136
+ - `splitter` - mandatory symbol that used inside of statements like this:
137
+ - `roundBraceOpen` and `roundBraceClose` symbols to output braces in a single argument arrow function expressions: `(a) => {}`.
138
+
139
+ Default options produce:
140
+
141
+ ```js
142
+ if (a > 3)
143
+ console.log('ok');
144
+ else
145
+ console.log('not ok');
146
+ ```
147
+
148
+ But you can override them with:
149
+
150
+ ```js
151
+ const overrides = {
152
+ format: {
153
+ indent: '',
154
+ newline: '',
155
+ space: '',
156
+ splitter: ' ',
157
+ },
158
+ };
159
+ ```
160
+
161
+ And have minified code:
162
+
163
+ ```
164
+ if(a>3)console.log('ok');else console.log('not ok');
165
+ ```
166
+
167
+ ### Semantics
168
+
169
+ Options used to configure logic of output, similar to ESLint rules:
170
+
171
+ - ✅ `maxElementsInOneLine` - count of `ArrayExpression` and `ArrayPattern` elements placed in one line.
172
+ - ✅ `maxVariablesInOneLine` - count of `VariableDeclarators` in one line.
173
+ - ✅ `maxPropertiesInOneLine` - count of `ObjectProperties` in one line.
174
+
175
+ ## Visitors API
176
+
177
+ When you want to improve support of existing visitor or extend **Printer** with a new ones, you need next base operations:
178
+
179
+ ### override
180
+
181
+ When you need to override behavior of existing visitor use:
182
+
183
+ ```js
184
+ import {
185
+ print,
186
+ visitors as v,
187
+ } from '@putout/printer';
188
+
189
+ print(ast, {
190
+ visitors: {
191
+ CallExpression(path, printer, semantics) {
192
+ const {print} = printer;
193
+
194
+ if (!path.node.goldstein)
195
+ return v.CallExpression(path, printer, semantics);
196
+
197
+ print('__goldstein');
198
+ },
199
+ },
200
+ });
201
+ ```
202
+
203
+ ### `print`
204
+
205
+ Used in previous example `print` can be used for a couple purposes:
206
+
207
+ - to write `string`;
208
+ - to write `node` when `object` passed;
209
+ - to write `node` when `string` started with `__`;
210
+
211
+ ```js
212
+ print(ast, {
213
+ visitors: {
214
+ AssignmentPattern(path, {print, maybe}) {
215
+ maybe.write.newline(path.parentPath.isCallExpression());
216
+ print('/* [hello world] */= ');
217
+ print('__right');
218
+ },
219
+ },
220
+ });
221
+ ```
222
+
223
+ ### `maybe`
224
+
225
+ When you need some condition use `maybe`. For example, to add newline only when parent node is `CallExpression` you
226
+ can use `maybe.write.newline(condition)`:
227
+
228
+ ```js
229
+ print(ast, {
230
+ visitors: {
231
+ AssignmentPattern(path, {write, maybe}) {
232
+ maybe.write.newline(path.parentPath.isCallExpression());
233
+ write(' /* [hello world] */= ');
234
+ write('__right');
235
+ },
236
+ },
237
+ });
238
+ ```
239
+
240
+ ### `write`
241
+
242
+ When you going to output string you can use low-level function `write`:
243
+
244
+ ```js
245
+ print(ast, {
246
+ visitors: {
247
+ BlockStatement(path, {write}) {
248
+ write('hello');
249
+ },
250
+ },
251
+ });
252
+ ```
253
+
254
+ ### `indent`
255
+
256
+ When you need to add indentation use `indent`, for example when you output body,
257
+ you need to increment indentation, and then decrement it back:
258
+
259
+ ```js
260
+ print(ast, {
261
+ visitors: {
262
+ BlockStatement(path, {write, indent}) {
263
+ write('{');
264
+ indent.inc();
265
+ indent();
266
+ write('some;');
267
+ indent.dec();
268
+ write('{');
269
+ },
270
+ },
271
+ });
272
+ ```
273
+
274
+ ### `traverse`
275
+
276
+ When you need to traverse node path, you can use `traverse`:
277
+
278
+ ```js
279
+ print(ast, {
280
+ visitors: {
281
+ AssignmentExpression(path, {traverse}) {
282
+ traverse(path.get('left'));
283
+ },
284
+ },
285
+ });
286
+ ```
287
+
288
+ This is the same as `print('__left')` but more low-level, and supports only objects.
289
+
290
+ ## Speed Comparison
291
+
292
+ About speed, for file `speed.js`:
293
+
294
+ ```js
295
+ const {readFileSync} = require('fs');
296
+
297
+ const putout = require('putout');
298
+ const parser = require('@babel/parser');
299
+
300
+ const code = readFileSync('./lib/tokenize/tokenize.js', 'utf8');
301
+ const ast = parser.parse(code);
302
+
303
+ speed('recast');
304
+ speed('putout');
305
+
306
+ function speed(printer) {
307
+ console.time(printer);
308
+
309
+ for (let i = 0; i < 1000; i++) {
310
+ putout(code, {
311
+ printer,
312
+ plugins: ['remove-unused-variables'],
313
+ });
314
+ }
315
+
316
+ console.timeEnd(printer);
317
+ }
318
+ ```
319
+
320
+ With contents of [`tokenize.js`](https://github.com/putoutjs/printer/blob/v1.69.1/lib/tokenize/tokenize.js), we have:
321
+
322
+ ![image](https://user-images.githubusercontent.com/1573141/234004942-8f890da3-a145-425f-9040-25924dcfba7b.png)
323
+
324
+ ## License
325
+
326
+ MIT
package/bin/redlint.js ADDED
@@ -0,0 +1,8 @@
1
+ import process from 'node:process';
2
+ import {writeFile} from 'node:fs/promises';
3
+ import {buildTree} from '../lib/redlint.js';
4
+
5
+ const result = await buildTree(process.cwd());
6
+ const filesystem = JSON.stringify(result, null, 4) + '\n';
7
+
8
+ await writeFile('.filesystem.json', filesystem);
package/lib/redlint.js ADDED
@@ -0,0 +1,58 @@
1
+ import { opendir } from 'node:fs/promises';
2
+ import {relative} from 'node:path';
3
+ import fastGlob from 'fast-glob';
4
+
5
+ const ignore = [
6
+ 'node_modules',
7
+ 'coverage',
8
+ '.git',
9
+ '.idea',
10
+ 'fixture',
11
+ ];
12
+
13
+ export const buildTree = async (filename) => {
14
+ return {
15
+ type: 'directory',
16
+ filename,
17
+ files: await walk(filename)
18
+ };
19
+ };
20
+
21
+ async function walk(cwd, files = []) {
22
+ const dir = await opendir(cwd);
23
+
24
+ for await (const dirent of dir) {
25
+ const {path, name} = dirent;
26
+
27
+ if (isIgnored(name))
28
+ continue;
29
+
30
+ const filename = `${path}/${name}`;
31
+
32
+ if (dirent.isDirectory()) {
33
+ debugger;
34
+ files.push({
35
+ type: 'directory',
36
+ filename,
37
+ files: await walk(filename),
38
+ });
39
+ continue;
40
+ }
41
+
42
+ files.push({
43
+ type: 'file',
44
+ filename,
45
+ });
46
+ }
47
+
48
+ return files;
49
+ }
50
+
51
+ function isIgnored(name) {
52
+ for (const current of ignore) {
53
+ if (RegExp(current).test(name))
54
+ return true;
55
+ }
56
+
57
+ return false;
58
+ }
package/package.json ADDED
@@ -0,0 +1,79 @@
1
+ {
2
+ "name": "redlint",
3
+ "version": "1.0.0",
4
+ "type": "module",
5
+ "author": "coderaiser <mnemonic.enemy@gmail.com> (https://github.com/coderaiser)",
6
+ "description": "Lint Filesystem with 🐊Putout",
7
+ "homepage": "https://github.com/putoutjs/redlint#readme",
8
+ "main": "./lib/redlint.js",
9
+ "exports": {
10
+ ".": "./lib/redlint.js"
11
+ },
12
+ "repository": {
13
+ "type": "git",
14
+ "url": "git://github.com/putoutjs/redlint.git"
15
+ },
16
+ "scripts": {
17
+ "wisdom": "madrun wisdom",
18
+ "test": "madrun test",
19
+ "test:dts": "madrun test:dts",
20
+ "watch:test": "madrun watch:test",
21
+ "lint": "madrun lint",
22
+ "fresh:lint": "madrun fresh:lint",
23
+ "lint:fresh": "madrun lint:fresh",
24
+ "fix:lint": "madrun fix:lint",
25
+ "coverage": "madrun coverage",
26
+ "coverage:html": "madrun coverage:html",
27
+ "report": "madrun report"
28
+ },
29
+ "dependencies": {
30
+ "@putout/babel": "^1.1.1",
31
+ "@putout/compare": "^13.0.0",
32
+ "@putout/operate": "^11.0.0",
33
+ "@putout/processor-json": "^7.0.0",
34
+ "fullstore": "^3.0.0",
35
+ "just-snake-case": "^3.2.0",
36
+ "parse-import-specifiers": "^1.0.1",
37
+ "rendy": "^4.0.0"
38
+ },
39
+ "keywords": [
40
+ "putout",
41
+ "redlint",
42
+ "AST",
43
+ "babel",
44
+ "api",
45
+ "traverse",
46
+ "generate"
47
+ ],
48
+ "devDependencies": {
49
+ "@babel/plugin-codemod-object-assign-to-object-spread": "^7.10.4",
50
+ "@putout/plugin-minify": "^5.0.0",
51
+ "@putout/plugin-redlint": "^3.0.0",
52
+ "@putout/plugin-promises": "^13.0.0",
53
+ "@putout/plugin-react-hook-form": "^4.0.0",
54
+ "@putout/plugin-react-hooks": "^5.0.0",
55
+ "acorn": "^8.8.2",
56
+ "c8": "^8.0.0",
57
+ "check-dts": "^0.7.2",
58
+ "escover": "^3.0.0",
59
+ "eslint": "^8.0.1",
60
+ "eslint-plugin-n": "^16.0.0",
61
+ "eslint-plugin-putout": "^21.0.1",
62
+ "estree-to-babel": "^8.0.0",
63
+ "just-kebab-case": "^4.2.0",
64
+ "madrun": "^9.0.0",
65
+ "mock-require": "^3.0.3",
66
+ "montag": "^1.0.0",
67
+ "nodemon": "^3.0.1",
68
+ "putout": "^32.0.4",
69
+ "supertape": "^8.0.0",
70
+ "try-catch": "^3.0.0"
71
+ },
72
+ "license": "MIT",
73
+ "engines": {
74
+ "node": ">=16"
75
+ },
76
+ "publishConfig": {
77
+ "access": "public"
78
+ }
79
+ }