redlint 6.6.0 → 6.8.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/CONTRIBUTING.md CHANGED
@@ -6,14 +6,15 @@
6
6
  - **No `t.pass('everything ok')` in tests** — every assertion must test something meaningful.
7
7
  - **100% coverage required** — checked via [`.nycrc.json`](.nycrc.json). Run `redrun coverage` to verify.
8
8
  - **Tests use [supertape](https://github.com/coderaiser/supertape)** with `stub()` for mocking.
9
- - **TDD is encouraged** — write a failing test first, then implement, then `redrun fix:lint test`.
10
- - **Run `redrun fix:lint test` before every commit** — linter must be clean, all tests green.
9
+ - **TDD is encouraged** — write a failing test first, then implement, then `redrun fix:lint coverage`.
10
+ - **Run `redrun fix:lint coverage` before every commit** — linter must be clean, all tests green, coverage 100%.
11
11
 
12
12
  ## Table of Contents
13
13
 
14
14
  - [Do / Don't](#do--dont)
15
15
  - [Workflow](#workflow)
16
16
  - [Architecture](#architecture)
17
+ - [How to add a new converter](#how-to-add-a-new-converter)
17
18
  - [Import Map](#import-map)
18
19
  - [File Tree](#file-tree)
19
20
  - [Overrides Pattern](#overrides-pattern)
@@ -74,6 +75,98 @@ The debug mode is an escape hatch when workers misbehave.
74
75
  - Mocking: `stub()` from supertape (no external mocking library)
75
76
  - Fixtures: plain `.js` files in `fixture/` directories
76
77
 
78
+ ## How to add a new converter (e.g. `convert-json-to-yaml`)?
79
+
80
+ All converters live in `lib/convert/converters/` and follow the same pattern. Adding a new one requires changes in **6 files** (1 new, 5 modified):
81
+
82
+ ### 1. Create the converter — `lib/convert/converters/convert-X-to-Y.js`
83
+
84
+ ```js
85
+ import * as pluginFilesystem from '@putout/plugin-filesystem';
86
+
87
+ const [, pluginConvertXToY] = pluginFilesystem.rules['convert-X-to-Y'];
88
+
89
+ export const convertXToY = (filename) => ({
90
+ rules: {
91
+ 'filesystem/convert-X-to-Y': ['on', {
92
+ filename,
93
+ }],
94
+ },
95
+ plugins: [
96
+ ['filesystem/convert-X-to-Y', pluginConvertXToY],
97
+ ],
98
+ });
99
+ ```
100
+
101
+ The `[@putout/plugin-filesystem](https://github.com/coderaiser/putout/tree/master/packages/plugin-filesystem)`
102
+ package must already export the rule (use `[@putout/plugin-filesystem](https://github.com/coderaiser/putout/tree/master/packages/plugin-filesystem)` >= 13.2.0 for `convert-json-to-yaml`).
103
+
104
+ ### 2. Register menu constants — `lib/menu.js`
105
+
106
+ Add a pair of exports (normal + debug):
107
+
108
+ ```js
109
+ export const CONVERT_X_TO_Y = '🦏 convert x to y';
110
+ export const CONVERT_X_TO_Y_DEBUG = '🦏 convert x to y: debug';
111
+ ```
112
+
113
+ Then add `CONVERT_X_TO_Y` to the array in `isConvertChosen()` and `CONVERT_X_TO_Y_DEBUG` to the array in `isConvertChosenDebug()`.
114
+
115
+ ### 3. Add to converters map — `lib/convert/create-options.js`
116
+
117
+ ```js
118
+ import {convertXToY} from './converters/convert-X-to-Y.js';
119
+
120
+ const CONVERTERS = {
121
+ // ...existing...
122
+ [CONVERT_X_TO_Y]: convertXToY,
123
+ [CONVERT_X_TO_Y_DEBUG]: convertXToY,
124
+ };
125
+ ```
126
+
127
+ ### 4. Add to convert menu — `lib/convert/index.js`
128
+
129
+ Import `CONVERT_X_TO_Y` and add it to the `chooseConvert()` dialog array.
130
+
131
+ ### 5. Add to debug menu — `lib/debug.js`
132
+
133
+ Import `CONVERT_X_TO_Y_DEBUG` and add it to the `debug()` dialog array.
134
+
135
+ ### 6. Add a test — `lib/convert/convert.spec.js`
136
+
137
+ ```js
138
+ import {CONVERT_X_TO_Y} from '../menu.js';
139
+
140
+ test('redlint: convert: x to y', (t) => {
141
+ const filesystem = stringify([
142
+ '/hello/world/',
143
+ '/hello/world/file.x',
144
+ ]);
145
+
146
+ const converted = convert('file.x', CONVERT_X_TO_Y, filesystem, {
147
+ merge,
148
+ branch,
149
+ });
150
+
151
+ const result = parse(converted);
152
+
153
+ const expected = ['/hello/world/', [
154
+ '/hello/world/file.y',
155
+ 'e30K',
156
+ ]];
157
+
158
+ t.deepEqual(result, expected);
159
+ t.end();
160
+ });
161
+ ```
162
+
163
+ ### 🧪 Verify
164
+
165
+ ```sh
166
+ redrun fix:lint # putout . --fix — must pass
167
+ redrun coverage # 100% required
168
+ ```
169
+
77
170
  ## Import Map
78
171
 
79
172
  The project uses Node.js [`imports`](package.json) for internal aliases:
@@ -177,5 +270,5 @@ This pattern keeps functions pure, easy to unit test, and doesn't require any mo
177
270
  | [madrun](https://github.com/coderaiser/madrun) | Define tasks in `.madrun.js` | `redrun` |
178
271
  | [putout](https://github.com/coderaiser/putout) | JavaScript code transformer & linter | `redrun fix:lint` |
179
272
  | [supertape](https://github.com/coderaiser/supertape) | Test framework with built-in `stub()` | `redrun test` |
180
- | [superc8](https://github.com/coderaiser/superc8) | Enhanced c8 wrapper | `redrun coverage` |
273
+ | [superc8](https://github.com/coderaiser/superc8) | coverage tool, drop-in modern `c8` replacement | `redrun coverage` |
181
274
  | [nodemon](https://github.com/remy/nodemon) | Watch mode for tests | `redrun watch:test` |
package/ChangeLog CHANGED
@@ -1,3 +1,16 @@
1
+ 2026.06.07, v6.8.0
2
+
3
+ feature:
4
+ - 4bd96fe redlint: convert: convert-toml-to-yaml: add
5
+ - c58d5a5 convert-json-to-toml: add
6
+ - 2978ff4 redlint: convert toml to json
7
+
8
+ 2026.06.07, v6.7.0
9
+
10
+ feature:
11
+ - 32a0dfc redlint: isKnownCommand: add
12
+ - 68d1431 redlint: convert-json-to-yaml
13
+
1
14
  2026.06.06, v6.6.0
2
15
 
3
16
  feature:
package/bin/redlint.js CHANGED
@@ -57,6 +57,7 @@ import {
57
57
  isBundleDebug,
58
58
  isEdit,
59
59
  isView,
60
+ isKnownCommand,
60
61
  VIEW,
61
62
  TEST,
62
63
  isTest,
@@ -120,6 +121,11 @@ async function uiLoop(arg) {
120
121
  if (!arg)
121
122
  return;
122
123
 
124
+ if (!isKnownCommand(arg)) {
125
+ console.error(`'${arg}' is not a redlint command. See 'redlint --help'.`);
126
+ process.exit(1);
127
+ }
128
+
123
129
  log('Running:');
124
130
  const spinner = ora('index filesystem').start();
125
131
  const CWD = process.cwd();
@@ -0,0 +1,14 @@
1
+ import * as pluginFilesystem from '@putout/plugin-filesystem';
2
+
3
+ const [, pluginConvertJsonToToml] = pluginFilesystem.rules['convert-json-to-toml'];
4
+
5
+ export const convertJsonToToml = (filename) => ({
6
+ rules: {
7
+ 'filesystem/convert-json-to-toml': ['on', {
8
+ filename,
9
+ }],
10
+ },
11
+ plugins: [
12
+ ['filesystem/convert-json-to-toml', pluginConvertJsonToToml],
13
+ ],
14
+ });
@@ -0,0 +1,14 @@
1
+ import * as pluginFilesystem from '@putout/plugin-filesystem';
2
+
3
+ const [, pluginConvertJsonToYaml] = pluginFilesystem.rules['convert-json-to-yaml'];
4
+
5
+ export const convertJsonToYaml = (filename) => ({
6
+ rules: {
7
+ 'filesystem/convert-json-to-yaml': ['on', {
8
+ filename,
9
+ }],
10
+ },
11
+ plugins: [
12
+ ['filesystem/convert-json-to-yaml', pluginConvertJsonToYaml],
13
+ ],
14
+ });
@@ -0,0 +1,14 @@
1
+ import * as pluginFilesystem from '@putout/plugin-filesystem';
2
+
3
+ const [, pluginConvertTomlToJson] = pluginFilesystem.rules['convert-toml-to-json'];
4
+
5
+ export const convertTomlToJson = (filename) => ({
6
+ rules: {
7
+ 'filesystem/convert-toml-to-json': ['on', {
8
+ filename,
9
+ }],
10
+ },
11
+ plugins: [
12
+ ['filesystem/convert-toml-to-json', pluginConvertTomlToJson],
13
+ ],
14
+ });
@@ -0,0 +1,14 @@
1
+ import * as pluginFilesystem from '@putout/plugin-filesystem';
2
+
3
+ const [, pluginConvertTomlToYaml] = pluginFilesystem.rules['convert-toml-to-yaml'];
4
+
5
+ export const convertTomlToYaml = (filename) => ({
6
+ rules: {
7
+ 'filesystem/convert-toml-to-yaml': ['on', {
8
+ filename,
9
+ }],
10
+ },
11
+ plugins: [
12
+ ['filesystem/convert-toml-to-yaml', pluginConvertTomlToYaml],
13
+ ],
14
+ });
@@ -5,11 +5,23 @@ import {
5
5
  CONVERT_JS_TO_JSON_DEBUG,
6
6
  CONVERT_YAML_TO_JSON,
7
7
  CONVERT_YAML_TO_JSON_DEBUG,
8
+ CONVERT_JSON_TO_YAML,
9
+ CONVERT_JSON_TO_YAML_DEBUG,
10
+ CONVERT_TOML_TO_JSON,
11
+ CONVERT_TOML_TO_JSON_DEBUG,
12
+ CONVERT_JSON_TO_TOML,
13
+ CONVERT_JSON_TO_TOML_DEBUG,
14
+ CONVERT_TOML_TO_YAML,
15
+ CONVERT_TOML_TO_YAML_DEBUG,
8
16
  CONVERT_RC_TO_FLAT,
9
17
  } from '../menu.js';
10
18
  import {convertYamlToJson} from './converters/convert-yaml-to-json.js';
19
+ import {convertJsonToYaml} from './converters/convert-json-to-yaml.js';
11
20
  import {convertJsonToJs} from './converters/convert-json-to-js.js';
12
21
  import {convertJSToJson} from './converters/convert-js-to-json.js';
22
+ import {convertTomlToJson} from './converters/convert-toml-to-json.js';
23
+ import {convertJsonToToml} from './converters/convert-json-to-toml.js';
24
+ import {convertTomlToYaml} from './converters/convert-toml-to-yaml.js';
13
25
  import {convertRCToFlat} from './converters/convert-rc-to-flat.js';
14
26
 
15
27
  const CONVERTERS = {
@@ -19,6 +31,14 @@ const CONVERTERS = {
19
31
  [CONVERT_JS_TO_JSON_DEBUG]: convertJSToJson,
20
32
  [CONVERT_YAML_TO_JSON]: convertYamlToJson,
21
33
  [CONVERT_YAML_TO_JSON_DEBUG]: convertYamlToJson,
34
+ [CONVERT_JSON_TO_YAML]: convertJsonToYaml,
35
+ [CONVERT_JSON_TO_YAML_DEBUG]: convertJsonToYaml,
36
+ [CONVERT_TOML_TO_JSON]: convertTomlToJson,
37
+ [CONVERT_TOML_TO_JSON_DEBUG]: convertTomlToJson,
38
+ [CONVERT_JSON_TO_TOML]: convertJsonToToml,
39
+ [CONVERT_JSON_TO_TOML_DEBUG]: convertJsonToToml,
40
+ [CONVERT_TOML_TO_YAML]: convertTomlToYaml,
41
+ [CONVERT_TOML_TO_YAML_DEBUG]: convertTomlToYaml,
22
42
  [CONVERT_RC_TO_FLAT]: convertRCToFlat,
23
43
  };
24
44
 
@@ -6,6 +6,10 @@ import {
6
6
  EXIT,
7
7
  CONVERT_RC_TO_FLAT,
8
8
  CONVERT_YAML_TO_JSON,
9
+ CONVERT_JSON_TO_YAML,
10
+ CONVERT_TOML_TO_JSON,
11
+ CONVERT_JSON_TO_TOML,
12
+ CONVERT_TOML_TO_YAML,
9
13
  } from '../menu.js';
10
14
 
11
15
  export * from './convert.js';
@@ -14,6 +18,10 @@ export const chooseConvert = async () => {
14
18
  CONVERT_JS_TO_JSON,
15
19
  CONVERT_JSON_TO_JS,
16
20
  CONVERT_YAML_TO_JSON,
21
+ CONVERT_JSON_TO_YAML,
22
+ CONVERT_TOML_TO_JSON,
23
+ CONVERT_JSON_TO_TOML,
24
+ CONVERT_TOML_TO_YAML,
17
25
  CONVERT_RC_TO_FLAT,
18
26
  BACK,
19
27
  EXIT,
package/lib/debug.js CHANGED
@@ -7,6 +7,7 @@ import {
7
7
  CONVERT_JS_TO_JSON_DEBUG,
8
8
  CONVERT_JSON_TO_JS_DEBUG,
9
9
  CONVERT_YAML_TO_JSON_DEBUG,
10
+ CONVERT_JSON_TO_YAML_DEBUG,
10
11
  RENAME_JS_TO_JSX_DEBUG,
11
12
  BACK,
12
13
  EXIT,
@@ -23,6 +24,7 @@ export const debug = async () => {
23
24
  CONVERT_JS_TO_JSON_DEBUG,
24
25
  CONVERT_JSON_TO_JS_DEBUG,
25
26
  CONVERT_YAML_TO_JSON_DEBUG,
27
+ CONVERT_JSON_TO_YAML_DEBUG,
26
28
  RENAME_JS_TO_JSX_DEBUG,
27
29
  RENAME_JS_TO_JSX_DEBUG,
28
30
  BUNDLE_DEBUG,
package/lib/menu.js CHANGED
@@ -29,6 +29,18 @@ export const CONVERT_JSON_TO_JS_DEBUG = '🦏 convert json to js: debug';
29
29
  export const CONVERT_YAML_TO_JSON = '🦏 convert yaml to json';
30
30
  export const CONVERT_YAML_TO_JSON_DEBUG = '🦏 convert yaml to json: debug';
31
31
 
32
+ export const CONVERT_JSON_TO_YAML = '🦏 convert json to yaml';
33
+ export const CONVERT_JSON_TO_YAML_DEBUG = '🦏 convert json to yaml: debug';
34
+
35
+ export const CONVERT_TOML_TO_JSON = '🦏 convert toml to json';
36
+ export const CONVERT_TOML_TO_JSON_DEBUG = '🦏 convert toml to json: debug';
37
+
38
+ export const CONVERT_JSON_TO_TOML = '🦏 convert json to toml';
39
+ export const CONVERT_JSON_TO_TOML_DEBUG = '🦏 convert json to toml: debug';
40
+
41
+ export const CONVERT_TOML_TO_YAML = '🦏 convert toml to yaml';
42
+ export const CONVERT_TOML_TO_YAML_DEBUG = '🦏 convert toml to yaml: debug';
43
+
32
44
  export const RENAME_JS_TO_JSX = '🦏 rename js to jsx';
33
45
  export const RENAME_JS_TO_JSX_DEBUG = '🦏 rename js to jsx: debug';
34
46
 
@@ -60,6 +72,10 @@ export const isConvertChosen = (a) => {
60
72
  CONVERT_JSON_TO_JS,
61
73
  CONVERT_JS_TO_JSON,
62
74
  CONVERT_YAML_TO_JSON,
75
+ CONVERT_JSON_TO_YAML,
76
+ CONVERT_TOML_TO_JSON,
77
+ CONVERT_JSON_TO_TOML,
78
+ CONVERT_TOML_TO_YAML,
63
79
  CONVERT_RC_TO_FLAT,
64
80
  ].includes(a);
65
81
  };
@@ -69,9 +85,43 @@ export const isConvertChosenDebug = (a) => [
69
85
  CONVERT_JS_TO_JSON_DEBUG,
70
86
  CONVERT_JSON_TO_JS_DEBUG,
71
87
  CONVERT_YAML_TO_JSON_DEBUG,
88
+ CONVERT_JSON_TO_YAML_DEBUG,
89
+ CONVERT_TOML_TO_JSON_DEBUG,
90
+ CONVERT_JSON_TO_TOML_DEBUG,
91
+ CONVERT_TOML_TO_YAML_DEBUG,
72
92
  ].includes(a);
73
93
 
74
94
  export const isConvertRCToFlat = (a) => a === CONVERT_RC_TO_FLAT;
75
95
 
76
96
  export const isRenameToJs = (a) => a === RENAME_JS_TO_JSX || a === RENAME_JS_TO_JSX_DEBUG;
77
97
  export const isRenameToJsx = (a) => a === RENAME_JSX_TO_JS || a === RENAME_JSX_TO_JS_DEBUG;
98
+
99
+ const callWith = (a) => (fn) => fn(a);
100
+
101
+ export const isKnownCommand = (a) => [
102
+ isScan,
103
+ isScanDebug,
104
+ isFix,
105
+ isFixDebug,
106
+ isPack,
107
+ isPackDebug,
108
+ isExtract,
109
+ isExtractDebug,
110
+ isGenerate,
111
+ isGenerateSimple,
112
+ isHelp,
113
+ isVersion,
114
+ isDebug,
115
+ isConvert,
116
+ isRename,
117
+ isBack,
118
+ isExit,
119
+ isEdit,
120
+ isView,
121
+ isTest,
122
+ isBundleDebug,
123
+ isConvertChosen,
124
+ isConvertChosenDebug,
125
+ isRenameToJsChosen,
126
+ isRenameToJsxChosen,
127
+ ].some(callWith(a));
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "redlint",
3
- "version": "6.6.0",
3
+ "version": "6.8.0",
4
4
  "type": "module",
5
5
  "author": "coderaiser <mnemonic.enemy@gmail.com> (https://github.com/coderaiser)",
6
6
  "description": "Lint Filesystem with 🐊Putout",
@@ -27,6 +27,8 @@
27
27
  "test:dts": "madrun test:dts",
28
28
  "watch:test": "madrun watch:test",
29
29
  "lint": "madrun lint",
30
+ "scan": "madrun scan",
31
+ "scan:fix": "madrun scan:fix",
30
32
  "fresh:lint": "madrun fresh:lint",
31
33
  "lint:fresh": "madrun lint:fresh",
32
34
  "fix:lint": "madrun fix:lint",