@putout/printer 17.8.0 → 17.9.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/ChangeLog CHANGED
@@ -1,3 +1,16 @@
1
+ 2026.02.22, v17.9.0
2
+
3
+ feature:
4
+ - cc0746d @putout/printer: private import: #types
5
+ - 0e9fa7f @putout/printer: move out indent
6
+ - c7f8249 @putout/printer: printer: simplify
7
+ - d2f8005 @putout/printer: tokenize: printer: add
8
+
9
+ 2026.02.22, v17.8.1
10
+
11
+ feature:
12
+ - 89ae686 tokenize: rm useless round
13
+
1
14
  2026.02.22, v17.8.0
2
15
 
3
16
  feature:
@@ -1,7 +1,7 @@
1
1
  import process from 'node:process';
2
2
  import toSnakeCase from 'just-snake-case';
3
3
  import {codeFrameColumns} from '@putout/babel';
4
- import {TYPES} from '../types.js';
4
+ import {TYPES} from '#types';
5
5
 
6
6
  const {stringify} = JSON;
7
7
  const {
@@ -0,0 +1,38 @@
1
+ import {TYPES} from '#types';
2
+
3
+ const {assign} = Object;
4
+
5
+ export const createIndent = ({format, addToken}) => {
6
+ let i = 0;
7
+
8
+ const incIndent = () => ++i;
9
+ const decIndent = () => --i;
10
+
11
+ const indent = () => {
12
+ addToken({
13
+ type: TYPES.INDENT,
14
+ value: printIndent(i, format.indent),
15
+ });
16
+ };
17
+
18
+ assign(indent, {
19
+ inc: incIndent,
20
+ dec: decIndent,
21
+ getLevel() {
22
+ return i;
23
+ },
24
+ });
25
+
26
+ return indent;
27
+ };
28
+
29
+ function printIndent(i, indent) {
30
+ let result = '';
31
+ ++i;
32
+
33
+ while (--i > 0) {
34
+ result += indent;
35
+ }
36
+
37
+ return result;
38
+ }
@@ -0,0 +1,314 @@
1
+ import {fullstore} from 'fullstore';
2
+ import {TYPES} from '#types';
3
+ import {createDebug, createLog} from './debug.js';
4
+ import {maybeMarkAfter} from '../mark.js';
5
+ import * as baseVisitors from '../visitors.js';
6
+ import {maybeVisitor, maybeThrow} from '../maybe/index.js';
7
+ import {
8
+ parseLeadingComments,
9
+ parseTrailingComments,
10
+ } from '../comment/comment.js';
11
+ import {parseOverrides} from '../overrides/overrides.js';
12
+ import {createIndent} from './indent.js';
13
+
14
+ const isObject = (a) => a && typeof a === 'object';
15
+ const isString = (a) => typeof a === 'string';
16
+
17
+ const GET = '__';
18
+ const get = (path, command) => path.get(command.replace(GET, ''));
19
+
20
+ const {freeze, assign} = Object;
21
+
22
+ export const createPrinter = (overrides) => {
23
+ const tokens = [];
24
+ const {
25
+ format,
26
+ semantics,
27
+ visitors,
28
+ } = parseOverrides(overrides);
29
+
30
+ const addToken = createAddToken(tokens);
31
+ const debug = createDebug(tokens);
32
+ const write = createWrite(addToken);
33
+
34
+ const indent = createIndent({
35
+ format,
36
+ addToken,
37
+ });
38
+
39
+ const newline = createNewline({
40
+ format,
41
+ addToken,
42
+ });
43
+
44
+ const breakline = createBreakline({
45
+ newline,
46
+ indent,
47
+ });
48
+
49
+ const linebreak = createLinebreak({
50
+ indent,
51
+ newline,
52
+ });
53
+
54
+ const space = createSpace({
55
+ format,
56
+ addToken,
57
+ });
58
+
59
+ const splitter = createSplitter({
60
+ format,
61
+ addToken,
62
+ });
63
+
64
+ const endOfFile = createEndOfFile({
65
+ format,
66
+ addToken,
67
+ });
68
+
69
+ const quote = createQuote({
70
+ addToken,
71
+ format,
72
+ });
73
+
74
+ assign(write, {
75
+ indent,
76
+ newline,
77
+ linebreak,
78
+ breakline,
79
+ space,
80
+ splitter,
81
+ quote,
82
+ endOfFile,
83
+ });
84
+
85
+ const maybeBreakline = createMaybe(breakline);
86
+ const maybeNewline = createMaybe(newline);
87
+ const maybeLinebreak = createMaybe(linebreak);
88
+ const maybeSpace = createMaybe(space);
89
+
90
+ const maybeWrite = createMaybeWrite({
91
+ write,
92
+ });
93
+
94
+ assign(maybeWrite, {
95
+ newline: maybeNewline,
96
+ breakline: maybeBreakline,
97
+ linebreak: maybeLinebreak,
98
+ space: maybeSpace,
99
+ });
100
+
101
+ const maybeIndent = createMaybe(indent);
102
+
103
+ const maybe = {
104
+ indent: maybeIndent,
105
+ markAfter: maybeMarkAfter,
106
+ write: maybeWrite,
107
+ space: maybeSpace,
108
+ };
109
+
110
+ const maybeIndentInc = createMaybe(indent.inc);
111
+ const maybeIndentDec = createMaybe(indent.dec);
112
+
113
+ assign(maybe.indent, {
114
+ inc: maybeIndentInc,
115
+ dec: maybeIndentDec,
116
+ });
117
+
118
+ const getMainPrinter = () => mainPrinter;
119
+
120
+ const traverse = createTraverse({
121
+ maybeNewline,
122
+ maybeLinebreak,
123
+ maybeSpace,
124
+ maybeBreakline,
125
+ indent,
126
+ write,
127
+ debug,
128
+ semantics,
129
+ visitors,
130
+ getMainPrinter,
131
+ });
132
+
133
+ // should never change to avoid unexpected errors related to printing path, since it hard to debug
134
+ const mainPrinter = freeze({
135
+ indent,
136
+ write,
137
+ debug,
138
+ maybe,
139
+ quote,
140
+ store: fullstore(),
141
+ traverse,
142
+ });
143
+
144
+ const getTokens = () => tokens;
145
+
146
+ return {
147
+ getTokens,
148
+ traverse,
149
+ };
150
+ };
151
+
152
+ const createTraverse = (overrides) => function traverse(path) {
153
+ const {
154
+ write,
155
+ debug,
156
+ maybeLinebreak,
157
+ maybeSpace,
158
+ maybeBreakline,
159
+ maybeNewline,
160
+ indent,
161
+ semantics,
162
+ visitors,
163
+ getMainPrinter,
164
+ } = overrides;
165
+
166
+ const mainPrinter = getMainPrinter();
167
+
168
+ const currentTraversers = {
169
+ ...baseVisitors,
170
+ ...visitors,
171
+ };
172
+
173
+ const {type} = path;
174
+ const currentTraverse = currentTraversers[type];
175
+
176
+ if (!path.node)
177
+ return;
178
+
179
+ const print = createPrint(path, {
180
+ write,
181
+ traverse,
182
+ });
183
+
184
+ const printer = {
185
+ ...mainPrinter,
186
+ traverse,
187
+ print,
188
+ };
189
+
190
+ const maybePrint = (a, b) => a && print(b);
191
+
192
+ assign(maybePrint, {
193
+ newline: maybeNewline,
194
+ breakline: maybeBreakline,
195
+ linebreak: maybeLinebreak,
196
+ space: maybeSpace,
197
+ });
198
+
199
+ assign(printer.maybe, {
200
+ print: maybePrint,
201
+ });
202
+
203
+ maybeThrow(!currentTraverse, path, `☝️ Node type '{{ type }}' is not supported yet by @putout/printer: '{{ path }}'`);
204
+
205
+ const currentIndent = indent.getLevel();
206
+
207
+ parseLeadingComments(path, printer, semantics, {
208
+ currentTraverse,
209
+ });
210
+
211
+ // this is main thing
212
+ maybeVisitor(currentTraverse, path, printer, semantics);
213
+ parseTrailingComments(path, printer, semantics, {
214
+ currentTraverse,
215
+ });
216
+
217
+ maybeThrow(indent.getLevel() !== currentIndent, path, `☝️Looks like indent level changed after token visitor: '{{ type }}', for code: '{{ path }}'`);
218
+
219
+ debug(path.type);
220
+ };
221
+
222
+ const createPrint = (path, {traverse, write}) => {
223
+ const print = (maybeLine) => {
224
+ if (maybeLine === path)
225
+ return null;
226
+
227
+ const computed = computePath(path, maybeLine);
228
+
229
+ if (isObject(computed))
230
+ return traverse(computed);
231
+
232
+ return write(computed);
233
+ };
234
+
235
+ assign(print, write);
236
+
237
+ return print;
238
+ };
239
+
240
+ const computePath = (path, maybeLine) => {
241
+ if (isString(maybeLine) && maybeLine.startsWith(GET))
242
+ return get(path, maybeLine);
243
+
244
+ if (isObject(maybeLine))
245
+ return maybeLine;
246
+
247
+ return maybeLine;
248
+ };
249
+
250
+ const createWrite = (addToken) => (value) => {
251
+ addToken({
252
+ type: TYPES.TOKEN,
253
+ value,
254
+ });
255
+ };
256
+
257
+ const createNewline = ({format, addToken}) => () => {
258
+ addToken({
259
+ type: TYPES.NEWLINE,
260
+ value: format.newline,
261
+ });
262
+ };
263
+
264
+ const createMaybe = (fn) => (a) => a && fn();
265
+
266
+ const createBreakline = ({newline, indent}) => () => {
267
+ newline();
268
+ indent();
269
+ };
270
+
271
+ const createLinebreak = ({indent, newline}) => () => {
272
+ indent();
273
+ newline();
274
+ };
275
+
276
+ const createMaybeWrite = ({write}) => (a, b) => a && write(b);
277
+
278
+ const createSpace = ({format, addToken}) => () => {
279
+ addToken({
280
+ type: TYPES.SPACE,
281
+ value: format.space,
282
+ });
283
+ };
284
+
285
+ const createSplitter = ({format, addToken}) => () => {
286
+ addToken({
287
+ type: TYPES.SPLITTER,
288
+ value: format.splitter,
289
+ });
290
+ };
291
+
292
+ const createQuote = ({addToken, format}) => () => {
293
+ addToken({
294
+ type: TYPES.QUOTE,
295
+ value: format.quote,
296
+ });
297
+ };
298
+
299
+ const createEndOfFile = ({format, addToken}) => () => {
300
+ addToken({
301
+ type: TYPES.END_OF_FILE,
302
+ value: format.endOfFile,
303
+ });
304
+ };
305
+
306
+ const createAddToken = (tokens) => {
307
+ const log = createLog();
308
+
309
+ return (token) => {
310
+ log(token);
311
+ tokens.push(token);
312
+ };
313
+ };
314
+
@@ -1,175 +1,9 @@
1
- import {fullstore} from 'fullstore';
2
1
  import {traverse as babelTraverse} from '@putout/babel';
3
- import {TYPES} from '../types.js';
4
- import * as baseVisitors from './visitors.js';
5
- import {
6
- maybeFile,
7
- maybeVisitor,
8
- maybeThrow,
9
- } from './maybe/index.js';
10
- import {createDebug, createLog} from './debug.js';
11
- import {maybeMarkAfter} from './mark.js';
12
- import {
13
- parseLeadingComments,
14
- parseTrailingComments,
15
- } from './comment/comment.js';
16
- import {parseOverrides} from './overrides/overrides.js';
17
-
18
- const isObject = (a) => a && typeof a === 'object';
19
- const {round} = Math;
20
- const isString = (a) => typeof a === 'string';
21
- const {assign, freeze} = Object;
22
-
23
- const GET = '__';
24
- const get = (path, command) => path.get(command.replace(GET, ''));
25
-
26
- const createAddToken = (tokens) => {
27
- const log = createLog();
28
-
29
- return (token) => {
30
- log(token);
31
- tokens.push(token);
32
- };
33
- };
2
+ import {maybeFile} from './maybe/index.js';
3
+ import {createPrinter} from './printer/printer.js';
34
4
 
35
5
  export const tokenize = (ast, overrides) => {
36
- const {
37
- visitors,
38
- format,
39
- semantics,
40
- } = parseOverrides(overrides);
41
-
42
- const tokens = [];
43
- const addToken = createAddToken(tokens);
44
- const debug = createDebug(tokens);
45
-
46
- const write = (value) => {
47
- addToken({
48
- type: TYPES.TOKEN,
49
- value,
50
- });
51
- };
52
-
53
- const indent = () => {
54
- addToken({
55
- type: TYPES.INDENT,
56
- value: printIndent(i, format.indent),
57
- });
58
- };
59
-
60
- const maybeIndent = (a) => a && indent();
61
-
62
- const maybeIndentInc = (a) => a && indent.inc();
63
-
64
- const maybeIndentDec = (a) => a && indent.dec();
65
-
66
- const newline = () => {
67
- addToken({
68
- type: TYPES.NEWLINE,
69
- value: format.newline,
70
- });
71
- };
72
-
73
- const maybeNewline = (a) => a && newline();
74
-
75
- const breakline = () => {
76
- newline();
77
- indent();
78
- };
79
-
80
- const maybeBreakline = (a) => a && breakline();
81
-
82
- const linebreak = () => {
83
- indent();
84
- newline();
85
- };
86
-
87
- const maybeLinebreak = (a) => a && linebreak();
88
- const maybeWrite = (a, b) => a && write(b);
89
-
90
- const space = () => {
91
- addToken({
92
- type: TYPES.SPACE,
93
- value: format.space,
94
- });
95
- };
96
-
97
- const maybeSpace = (a) => a && space();
98
- let i = 0;
99
- const incIndent = () => ++i;
100
- const decIndent = () => --i;
101
-
102
- assign(indent, {
103
- inc: incIndent,
104
- dec: decIndent,
105
- });
106
-
107
- const splitter = () => {
108
- addToken({
109
- type: TYPES.SPLITTER,
110
- value: format.splitter,
111
- });
112
- };
113
-
114
- const quote = () => {
115
- addToken({
116
- type: TYPES.QUOTE,
117
- value: format.quote,
118
- });
119
- };
120
-
121
- const endOfFile = () => {
122
- addToken({
123
- type: TYPES.END_OF_FILE,
124
- value: format.endOfFile,
125
- });
126
- };
127
-
128
- assign(write, {
129
- indent,
130
- newline,
131
- linebreak,
132
- breakline,
133
- space,
134
- splitter,
135
- quote,
136
- endOfFile,
137
- });
138
-
139
- assign(maybeWrite, {
140
- newline: maybeNewline,
141
- breakline: maybeBreakline,
142
- linebreak: maybeLinebreak,
143
- space: maybeSpace,
144
- });
145
-
146
- const maybe = {
147
- indent: maybeIndent,
148
- markAfter: maybeMarkAfter,
149
- write: maybeWrite,
150
- space: maybeSpace,
151
- };
152
-
153
- assign(maybe.indent, {
154
- inc: maybeIndentInc,
155
- dec: maybeIndentDec,
156
- });
157
-
158
- // should never change to avoid unexpected errors related to printing path, since it hard to debug
159
- const mainPrinter = freeze({
160
- indent,
161
- write,
162
- debug,
163
- traverse,
164
- maybe,
165
- quote,
166
- store: fullstore(),
167
- });
168
-
169
- const currentTraversers = {
170
- ...baseVisitors,
171
- ...visitors,
172
- };
6
+ const {getTokens, traverse} = createPrinter(overrides);
173
7
 
174
8
  if (ast.parentPath)
175
9
  pathTraverse(ast, traverse);
@@ -181,92 +15,7 @@ export const tokenize = (ast, overrides) => {
181
15
  },
182
16
  });
183
17
 
184
- function traverse(path) {
185
- const {type} = path;
186
- const currentTraverse = currentTraversers[type];
187
-
188
- if (!path.node)
189
- return;
190
-
191
- const print = createPrint(path, {
192
- write,
193
- traverse,
194
- });
195
-
196
- assign(print, write, {
197
- space,
198
- round,
199
- });
200
-
201
- const printer = {
202
- ...mainPrinter,
203
- print,
204
- };
205
-
206
- const maybePrint = (a, b) => a && print(b);
207
-
208
- assign(maybePrint, {
209
- newline: maybeNewline,
210
- breakline: maybeBreakline,
211
- linebreak: maybeLinebreak,
212
- space: maybeSpace,
213
- });
214
-
215
- assign(printer.maybe, {
216
- print: maybePrint,
217
- });
218
-
219
- maybeThrow(!currentTraverse, path, `☝️ Node type '{{ type }}' is not supported yet by @putout/printer: '{{ path }}'`);
220
-
221
- const currentIndent = i;
222
- parseLeadingComments(path, printer, semantics, {
223
- currentTraverse,
224
- });
225
-
226
- // this is main thing
227
- maybeVisitor(currentTraverse, path, printer, semantics);
228
- parseTrailingComments(path, printer, semantics, {
229
- currentTraverse,
230
- });
231
- maybeThrow(i !== currentIndent, path, `☝️Looks like indent level changed after token visitor: '{{ type }}', for code: '{{ path }}'`);
232
-
233
- debug(path.type);
234
- }
235
-
236
- return tokens;
237
- };
238
-
239
- function printIndent(i, indent) {
240
- let result = '';
241
- ++i;
242
-
243
- while (--i > 0) {
244
- result += indent;
245
- }
246
-
247
- return result;
248
- }
249
-
250
- const createPrint = (path, {traverse, write}) => (maybeLine) => {
251
- if (maybeLine === path)
252
- return null;
253
-
254
- const computed = computePath(path, maybeLine);
255
-
256
- if (isObject(computed))
257
- return traverse(computed);
258
-
259
- return write(computed);
260
- };
261
-
262
- const computePath = (path, maybeLine) => {
263
- if (isString(maybeLine) && maybeLine.startsWith(GET))
264
- return get(path, maybeLine);
265
-
266
- if (isObject(maybeLine))
267
- return maybeLine;
268
-
269
- return maybeLine;
18
+ return getTokens();
270
19
  };
271
20
 
272
21
  function pathTraverse(ast, traverse) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@putout/printer",
3
- "version": "17.8.0",
3
+ "version": "17.9.0",
4
4
  "type": "module",
5
5
  "author": "coderaiser <mnemonic.enemy@gmail.com> (https://github.com/coderaiser)",
6
6
  "description": "Simplest possible opinionated Babel AST printer for 🐊Putout",
@@ -59,7 +59,8 @@
59
59
  "#is": "./lib/tokenize/is.js",
60
60
  "#maybe-parens": "./lib/tokenize/maybe/maybe-parens.js",
61
61
  "#print-params": "./lib/tokenize/expressions/function/params.js",
62
- "#import-attributes": "./lib/tokenize/statements/import-declaration/import-attribute.js"
62
+ "#import-attributes": "./lib/tokenize/statements/import-declaration/import-attribute.js",
63
+ "#types": "./lib/types.js"
63
64
  },
64
65
  "devDependencies": {
65
66
  "@babel/parser": "^7.28.5",