@putout/printer 1.7.3 → 1.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/ChangeLog CHANGED
@@ -1,3 +1,13 @@
1
+ 2023.03.26, v1.8.0
2
+
3
+ feature:
4
+ - 14f4f82 @putout/printer: add support of SwitchStatement
5
+
6
+ 2023.03.26, v1.7.4
7
+
8
+ feature:
9
+ - 81adee2 @putout/printer: add newline before comment
10
+
1
11
  2023.03.24, v1.7.3
2
12
 
3
13
  feature:
@@ -26,4 +26,3 @@ module.exports.cook = (tokens) => {
26
26
 
27
27
  return cookedTokens;
28
28
  };
29
-
@@ -1,16 +1,24 @@
1
1
  'use strict';
2
2
 
3
- module.exports.parseComments = (path, {print}) => {
3
+ const {isFirst} = require('./is');
4
+ const {markBefore} = require('./mark');
5
+
6
+ module.exports.parseComments = (path, {print, indent, maybe}) => {
4
7
  const {leadingComments} = path.node;
5
8
 
6
9
  if (leadingComments)
7
- parseLeadingComments(path, {print});
10
+ parseLeadingComments(path, {print, indent, maybe});
8
11
  };
9
12
 
10
- function parseLeadingComments(path, {print}) {
13
+ function parseLeadingComments(path, {print, indent}) {
11
14
  const {leadingComments} = path.node;
12
15
 
16
+ if (shouldAddNewlineBefore(path))
17
+ print.linebreak();
18
+
13
19
  for (const {type, value} of leadingComments) {
20
+ indent();
21
+
14
22
  if (type === 'CommentLine') {
15
23
  print(`//${value}`);
16
24
  print.newline();
@@ -19,7 +27,18 @@ function parseLeadingComments(path, {print}) {
19
27
 
20
28
  if (type === 'CommentBlock') {
21
29
  print(`/*${value}*/`);
30
+
31
+ if (path.isStatement()) {
32
+ print.newline();
33
+ markBefore(path);
34
+ }
35
+
22
36
  continue;
23
37
  }
24
38
  }
25
39
  }
40
+
41
+ function shouldAddNewlineBefore(path) {
42
+ return path.isStatement() && !isFirst(path);
43
+ }
44
+
@@ -2,7 +2,8 @@
2
2
 
3
3
  const {TYPES} = require('../types');
4
4
  const toSnakeCase = require('just-snake-case');
5
- const {DEBUG} = process.env;
5
+ const {LOG, DEBUG} = process.env;
6
+ const {codeFrameColumns} = require('@babel/code-frame');
6
7
 
7
8
  module.exports.createDebug = (tokens) => (a) => {
8
9
  if (!DEBUG)
@@ -13,3 +14,34 @@ module.exports.createDebug = (tokens) => (a) => {
13
14
  value: `/*__${toSnakeCase(a)}*/`,
14
15
  });
15
16
  };
17
+
18
+ module.exports.createLog = ({newline = '\n', store = createStore()} = {}) => (chunk) => {
19
+ if (!LOG)
20
+ return;
21
+
22
+ if (chunk === newline) {
23
+ console.log(codeFrameColumns(store(), {}, {
24
+ highlightCode: true,
25
+ }));
26
+ return;
27
+ }
28
+
29
+ store(chunk);
30
+ };
31
+
32
+ function createStore() {
33
+ let chunks = [];
34
+
35
+ return (chunk) => {
36
+ if (chunk) {
37
+ chunks.push(chunk);
38
+ return;
39
+ }
40
+
41
+ const result = chunks.join('');
42
+ chunks = [];
43
+
44
+ return result;
45
+ };
46
+ }
47
+
@@ -20,8 +20,9 @@ module.exports.CallExpression = CallExpression;
20
20
  function CallExpression(path, {indent, print, maybe}) {
21
21
  const isParentCall = toLong(path) && path.parentPath.isCallExpression();
22
22
 
23
- if (isNewLineBefore(path) && !isMarkedParentBefore(path) && !hasPrevNewline(path.parentPath))
23
+ if (isNewLineBefore(path) && !isMarkedParentBefore(path) && !hasPrevNewline(path.parentPath)) {
24
24
  print.breakline();
25
+ }
25
26
 
26
27
  print('__callee');
27
28
  print('(');
@@ -26,9 +26,9 @@ module.exports.BlockStatement = (path, {indent, maybe, print}) => {
26
26
  print(',');
27
27
  }
28
28
 
29
- const shouldAddNewLine = isAddNewLineAfter(path);
29
+ const shouldAddNewline = isAddNewLineAfter(path);
30
30
 
31
- if (shouldAddNewLine) {
31
+ if (shouldAddNewline) {
32
32
  print.newline();
33
33
  }
34
34
  };
@@ -8,21 +8,19 @@ const {
8
8
 
9
9
  const {isNext} = require('../is');
10
10
 
11
- module.exports.ExpressionStatement = (path, {write, indent, traverse, print}) => {
12
- if (isCoupleLinesExpression(path) && !isFirst(path) && shouldAddNewLine(path) && !hasPrevNewline(path)) {
11
+ module.exports.ExpressionStatement = (path, {indent, print}) => {
12
+ if (isCoupleLinesExpression(path) && !isFirst(path) && shouldAddNewline(path) && !hasPrevNewline(path)) {
13
13
  print.breakline();
14
14
  markBefore(path);
15
15
  }
16
16
 
17
- const expressionPath = path.get('expression');
18
-
19
17
  indent();
20
- traverse(expressionPath);
21
- write(';');
22
- write.newline();
18
+ print('__expression');
19
+ print(';');
20
+ print.newline();
23
21
 
24
22
  if (isStrictMode(path) || isCoupleLinesExpression(path) && isNext(path)) {
25
- write.newline();
23
+ print.newline();
26
24
  markAfter(path);
27
25
  }
28
26
  };
@@ -49,7 +47,7 @@ function isFirst(path) {
49
47
  return path.node === path.parentPath.node.body[0];
50
48
  }
51
49
 
52
- function shouldAddNewLine(path) {
50
+ function shouldAddNewline(path) {
53
51
  const prev = path.getPrevSibling();
54
52
 
55
53
  if (prev.isVariableDeclaration())
@@ -1,6 +1,10 @@
1
1
  'use strict';
2
2
 
3
- const {hasPrevNewline, markAfter} = require('../mark');
3
+ const {
4
+ hasPrevNewline,
5
+ markAfter,
6
+ markBefore,
7
+ } = require('../mark');
4
8
 
5
9
  const {isFirst} = require('../is');
6
10
 
@@ -8,6 +12,7 @@ module.exports.ForOfStatement = (path, {indent, print}) => {
8
12
  if (!isFirst(path) && !hasPrevNewline(path)) {
9
13
  print.indent();
10
14
  print.newline();
15
+ markBefore(path);
11
16
  }
12
17
 
13
18
  indent();
@@ -22,7 +27,7 @@ module.exports.ForOfStatement = (path, {indent, print}) => {
22
27
  if (bodyPath.isExpressionStatement()) {
23
28
  indent.inc();
24
29
  print.newline();
25
- print(bodyPath);
30
+ print('__body');
26
31
  indent.dec();
27
32
  print.newline();
28
33
 
@@ -31,7 +36,7 @@ module.exports.ForOfStatement = (path, {indent, print}) => {
31
36
 
32
37
  if (bodyPath.isBlockStatement()) {
33
38
  print(' ');
34
- print(bodyPath);
39
+ print('__body');
35
40
  }
36
41
 
37
42
  if (path.getNextSibling().node) {
@@ -12,6 +12,7 @@ const {ForStatement} = require('./for-statement');
12
12
  const importDeclarations = require('./import-declarations');
13
13
  const exportDeclarations = require('./export-declarations');
14
14
  const {WhileStatement} = require('./while-statement');
15
+ const {SwitchStatement} = require('./switch-statement');
15
16
 
16
17
  module.exports = {
17
18
  ...importDeclarations,
@@ -27,6 +28,7 @@ module.exports = {
27
28
  Program(path, {traverse}) {
28
29
  path.get('body').forEach(traverse);
29
30
  },
31
+ SwitchStatement,
30
32
  ...TryStatements,
31
33
  BreakStatement(path, {print, indent}) {
32
34
  indent();
@@ -0,0 +1,47 @@
1
+ 'use strict';
2
+
3
+ const {entries} = Object;
4
+
5
+ module.exports.SwitchStatement = (path, {print, maybe}) => {
6
+ print('switch');
7
+ print.space();
8
+ print('(');
9
+ print('__discriminant');
10
+ print(') {');
11
+
12
+ print.newline();
13
+
14
+ const cases = path.get('cases');
15
+ const n = cases.length - 1;
16
+
17
+ for (const [index, switchCase] of entries(cases)) {
18
+ print('case');
19
+ print.space();
20
+ print(switchCase.get('test'));
21
+ print(':');
22
+
23
+ const isBlock = switchCase.get('consequent.0').isBlockStatement();
24
+
25
+ maybe.indent.inc(!isBlock);
26
+ maybe.print.newline(!isBlock);
27
+
28
+ for (const consequent of switchCase.get('consequent')) {
29
+ if (!consequent.isBlockStatement()) {
30
+ print(consequent);
31
+ continue;
32
+ }
33
+
34
+ print.space();
35
+ print(consequent);
36
+ }
37
+
38
+ if (index < n) {
39
+ print.indent();
40
+ maybe.indent.dec(!isBlock);
41
+ print.newline();
42
+ }
43
+ }
44
+
45
+ print('}');
46
+ };
47
+
@@ -9,19 +9,9 @@ const {
9
9
  markAfter,
10
10
  } = require('../mark');
11
11
 
12
- const isNextAssign = (path) => {
13
- const nextPath = path.getNextSibling();
14
-
15
- if (!nextPath.isExpressionStatement())
16
- return false;
17
-
18
- return nextPath.get('expression').isAssignmentExpression();
19
- };
20
-
21
12
  module.exports.VariableDeclaration = (path, {maybe, print}) => {
22
- if (!isFirst(path) && isNewLineBefore(path) && !hasPrevNewline(path)) {
13
+ if (shouldAddNewlineBefore(path))
23
14
  print.breakline();
24
- }
25
15
 
26
16
  const isParentBlock = /Program|BlockStatement/.test(path.parentPath.type);
27
17
 
@@ -36,7 +26,7 @@ module.exports.VariableDeclaration = (path, {maybe, print}) => {
36
26
  maybe.print(isParentBlock, ';');
37
27
  maybe.print.newline(isParentBlock);
38
28
 
39
- const is = shouldAddNewLineAfter(path);
29
+ const is = shouldAddNewlineAfter(path);
40
30
 
41
31
  if (is) {
42
32
  print.linebreak();
@@ -44,7 +34,7 @@ module.exports.VariableDeclaration = (path, {maybe, print}) => {
44
34
  }
45
35
  };
46
36
 
47
- function shouldAddNewLineAfter(path) {
37
+ function shouldAddNewlineAfter(path) {
48
38
  if (isLast(path))
49
39
  return true;
50
40
 
@@ -65,13 +55,19 @@ function shouldAddNewLineAfter(path) {
65
55
 
66
56
  const isLast = (path) => path.parentPath.isProgram() && !isNext(path);
67
57
 
68
- function isNewLineBefore(path) {
69
- const prevPath = path.getPrevSibling();
58
+ function shouldAddNewlineBefore(path) {
59
+ if (isFirst(path))
60
+ return false;
70
61
 
71
- if (prevPath.isStatement() && !prevPath.isExpressionStatement() && !prevPath.isBlockStatement())
62
+ if (hasPrevNewline(path))
72
63
  return false;
73
64
 
74
- if (prevPath.isExpressionStatement() && prevPath.get('expression').isStringLiteral())
65
+ if (hasPrevNewline(path.parentPath))
66
+ return false;
67
+
68
+ const prevPath = path.getPrevSibling();
69
+
70
+ if (prevPath.isStatement() && !prevPath.isExpressionStatement() && !prevPath.isBlockStatement())
75
71
  return false;
76
72
 
77
73
  if (isCoupleLines(path))
@@ -90,3 +86,12 @@ function isNewLineBefore(path) {
90
86
  function isFirst(path) {
91
87
  return path.node === path.parentPath.node.body[0];
92
88
  }
89
+ const isNextAssign = (path) => {
90
+ const nextPath = path.getNextSibling();
91
+
92
+ if (!nextPath.isExpressionStatement())
93
+ return false;
94
+
95
+ return nextPath.get('expression').isAssignmentExpression();
96
+ };
97
+
@@ -6,7 +6,7 @@ const expressions = require('./expressions');
6
6
  const statements = require('./statements');
7
7
  const literals = require('./literals');
8
8
  const {TYPES} = require('../types');
9
- const {createDebug} = require('./debug');
9
+ const {createDebug, createLog} = require('./debug');
10
10
 
11
11
  const {
12
12
  maybeMarkAfter,
@@ -33,13 +33,24 @@ function initFormat(format) {
33
33
  };
34
34
  }
35
35
 
36
+ const createAddToken = (tokens) => {
37
+ const log = createLog();
38
+ return (token) => {
39
+ const {value} = token;
40
+
41
+ log(value);
42
+ tokens.push(token);
43
+ };
44
+ };
45
+
36
46
  module.exports.tokenize = (ast, overrides = {}) => {
37
47
  const format = initFormat(overrides.format);
38
48
  const tokens = [];
49
+ const addToken = createAddToken(tokens);
39
50
  const debug = createDebug(tokens);
40
51
 
41
52
  const write = (value) => {
42
- tokens.push({
53
+ addToken({
43
54
  type: TYPES.TOKEN,
44
55
  value,
45
56
  });
@@ -55,7 +66,7 @@ module.exports.tokenize = (ast, overrides = {}) => {
55
66
  const decIndent = () => --i;
56
67
 
57
68
  const indent = () => {
58
- tokens.push({
69
+ addToken({
59
70
  type: TYPES.INDENT,
60
71
  value: printIndent(i, format.indent),
61
72
  });
@@ -67,21 +78,28 @@ module.exports.tokenize = (ast, overrides = {}) => {
67
78
  });
68
79
 
69
80
  const linebreak = () => {
70
- tokens.push({
81
+ addToken({
71
82
  type: TYPES.NEWLINE,
72
83
  value: `${printIndent(i, format.indent)}\n`,
73
84
  });
74
85
  };
75
86
 
87
+ const space = () => {
88
+ addToken({
89
+ type: TYPES.SPACE,
90
+ value: ' ',
91
+ });
92
+ };
93
+
76
94
  const breakline = () => {
77
- tokens.push({
95
+ addToken({
78
96
  type: TYPES.NEWLINE,
79
97
  value: `\n${printIndent(i, format.indent)}`,
80
98
  });
81
99
  };
82
100
 
83
101
  const newline = () => {
84
- tokens.push({
102
+ addToken({
85
103
  type: TYPES.NEWLINE,
86
104
  value: '\n',
87
105
  });
@@ -106,12 +124,9 @@ module.exports.tokenize = (ast, overrides = {}) => {
106
124
  });
107
125
 
108
126
  const printer = {
109
- incIndent,
110
- decIndent,
111
127
  indent,
112
128
  write,
113
129
  debug,
114
- maybeIndent,
115
130
  traverse,
116
131
  maybe,
117
132
  };
@@ -140,7 +155,9 @@ module.exports.tokenize = (ast, overrides = {}) => {
140
155
  traverse,
141
156
  });
142
157
 
143
- assign(print, write);
158
+ assign(print, write, {
159
+ space,
160
+ });
144
161
 
145
162
  assign(printer, {
146
163
  print,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@putout/printer",
3
- "version": "1.7.3",
3
+ "version": "1.8.0",
4
4
  "type": "commonjs",
5
5
  "author": "coderaiser <mnemonic.enemy@gmail.com> (https://github.com/coderaiser)",
6
6
  "description": "Easiest possible opinionated Babel AST printer made with ❤️ to use in 🐊Putout",
@@ -26,6 +26,7 @@
26
26
  "report": "madrun report"
27
27
  },
28
28
  "dependencies": {
29
+ "@babel/code-frame": "^7.18.6",
29
30
  "@babel/parser": "^7.19.0",
30
31
  "@babel/traverse": "^7.21.2",
31
32
  "@babel/types": "^7.21.3",