@putout/printer 1.4.0 → 1.4.2

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,19 @@
1
+ 2023.03.18, v1.4.2
2
+
3
+ feature:
4
+ - fe8c410 @putout/printer: add support of AwaitExpression
5
+
6
+ 2023.03.17, v1.4.1
7
+
8
+ feature:
9
+ - 1948ce5 @putout/printer: improve support of ObjectExpression
10
+ - 09e1a5c @putout/printer: improve support of ObjectExpression
11
+ - 2d13bc2 @putout/printer: ArrayExpression: newlines
12
+ - 9fc6a00 @putout/printer: improve support of ArrayExpression
13
+ - b91d908 @putout/printer: UnaryExpression: add support of delete
14
+ - 337492b @putout/printer: improve support of NumericLiteral
15
+ - 166085c @putout/printer: add support of hex numbers
16
+
1
17
  2023.03.17, v1.4.0
2
18
 
3
19
  feature:
package/README.md CHANGED
@@ -3,7 +3,7 @@
3
3
  [NPMIMGURL]: https://img.shields.io/npm/v/@putout/printer.svg?style=flat&longCache=true
4
4
  [NPMURL]: https://npmjs.org/package/@putout/printer "npm"
5
5
 
6
- **@putout/printer** prints [**Babel AST**](https://github.com/coderaiser/estree-to-babel) to readable **JavaScript**.
6
+ Prints [**Babel AST**](https://github.com/coderaiser/estree-to-babel) to readable **JavaScript**.
7
7
 
8
8
  - ☝️ Similar to **Recast**, but simpler and easier in maintenance, since it supports only **Babel**.
9
9
  - ☝️ As opinionated as **Prettier**, but has more user-friendly output and works directly with **AST**.
@@ -1,16 +1,17 @@
1
1
  'use strict';
2
2
 
3
+ const {isObjectProperty} = require('@babel/types');
3
4
  const {entries} = Object;
4
5
  const isForOf = ({parentPath}) => parentPath.isForOfStatement();
5
6
 
6
- module.exports.ArrayExpression = (path, {write, indent, maybe, traverse}) => {
7
- write('[');
8
-
7
+ module.exports.ArrayExpression = (path, {write, maybe, traverse}) => {
9
8
  const elements = path.get('elements');
9
+ const elementIsObject = isElementObject(path);
10
10
 
11
- indent.inc();
11
+ write('[');
12
+ maybe.indent.inc(!elementIsObject);
12
13
 
13
- const isNewLine = !isNumbers(elements) && !isForOf(path);
14
+ const isNewLine = !isNumbers(elements) && !isForOf(path) && isLastArg(path) && !isParentProperty(path);
14
15
  const n = elements.length - 1;
15
16
 
16
17
  maybe.write(isNewLine && elements.length, '\n');
@@ -24,8 +25,7 @@ module.exports.ArrayExpression = (path, {write, indent, maybe, traverse}) => {
24
25
  maybe.write(!isNewLine && index < n, ', ');
25
26
  }
26
27
 
27
- indent.dec();
28
-
28
+ maybe.indent.dec(!elementIsObject);
29
29
  maybe.indent(elements.length && isNewLine);
30
30
 
31
31
  write(']');
@@ -40,3 +40,27 @@ function isNumbers(elements) {
40
40
  return false;
41
41
  }
42
42
 
43
+ function isLastArg(path) {
44
+ const {parentPath} = path;
45
+
46
+ if (!parentPath.isCallExpression())
47
+ return true;
48
+
49
+ const args = parentPath.get('arguments');
50
+ const n = args.length - 1;
51
+
52
+ return path === args[n];
53
+ }
54
+
55
+ function isParentProperty(path) {
56
+ return path.find(isObjectProperty);
57
+ }
58
+
59
+ function isElementObject(path) {
60
+ const elements = path.get('elements');
61
+
62
+ if (!elements.length)
63
+ return false;
64
+
65
+ return elements[0].isObjectExpression();
66
+ }
@@ -9,6 +9,7 @@ module.exports.ArrayPattern = (path, {write, indent, maybe, traverse}) => {
9
9
  const elements = path.get('elements');
10
10
 
11
11
  indent.inc();
12
+
12
13
  const isNewLine = !isForOf(path) && elements.length > 2;
13
14
  const n = elements.length - 1;
14
15
 
@@ -1,8 +1,8 @@
1
1
  'use strict';
2
2
 
3
3
  const {
4
- hasPrevNewline,
5
4
  isMarkedParentBefore,
5
+ isMarkedPrevAfter,
6
6
  } = require('../mark');
7
7
 
8
8
  const {entries} = Object;
@@ -10,10 +10,8 @@ const {entries} = Object;
10
10
  module.exports.CallExpression = (path, {traverse, indent, write, incIndent, decIndent, maybeWrite}) => {
11
11
  const isParentCall = toLong(path) && path.parentPath.isCallExpression();
12
12
 
13
- if (shouldAddNewLine(path) && !hasPrevNewline(path.parentPath) && !isMarkedParentBefore(path)) {
14
- write.newline();
15
- write.indent();
16
- }
13
+ if (shouldAddNewLine(path) && !isMarkedParentBefore(path) && !isMarkedPrevAfter(path.parentPath))
14
+ write.linebreak();
17
15
 
18
16
  traverse(path.get('callee'));
19
17
  write('(');
@@ -3,7 +3,10 @@
3
3
  const {isMarkedPrevAfter} = require('../mark');
4
4
  const isFirst = (path) => path.node === path.parentPath.node.body[0];
5
5
 
6
- module.exports.ArrowFunctionExpression = (path, {write, traverse}) => {
6
+ module.exports.ArrowFunctionExpression = (path, {write, maybe, traverse}) => {
7
+ const {async} = path.node;
8
+ maybe.write(async, 'async ');
9
+
7
10
  write('(');
8
11
 
9
12
  const params = path.get('params');
@@ -38,10 +41,14 @@ module.exports.ObjectMethod = (path, {write, traverse}) => {
38
41
  traverse(path.get('body'));
39
42
  };
40
43
 
41
- module.exports.FunctionDeclaration = (path, {write, traverse}) => {
44
+ module.exports.FunctionDeclaration = (path, {write, maybe, traverse}) => {
45
+ const {async} = path.node;
46
+
42
47
  if (!isFirst(path) && !isMarkedPrevAfter(path))
43
48
  write('\n');
44
49
 
50
+ maybe.write(async, 'async ');
51
+
45
52
  write('function ');
46
53
  traverse(path.get('id'));
47
54
  write('(');
@@ -1,38 +1,33 @@
1
1
  'use strict';
2
2
 
3
+ const {isCoupleLines} = require('../is');
3
4
  const isBodyOfArrow = (path) => path.parentPath.node.body === path.node;
4
5
  const isForOf = (path) => {
5
6
  if (path.parentPath.isForOfStatement())
6
7
  return true;
7
8
 
8
- if (path.parentPath?.parentPath?.isForOfStatement())
9
- return true;
10
-
11
- return false;
9
+ return path.parentPath?.parentPath?.isForOfStatement();
12
10
  };
13
11
 
14
- const isFirstMethod = (path) => path.get('properties.0').isObjectMethod();
15
-
16
12
  module.exports.ObjectExpression = (path, {traverse, write, maybe, indent}) => {
17
13
  indent.inc();
18
14
 
19
15
  const properties = path.get('properties');
20
- const parens = isBodyOfArrow(path);
21
- const isCall = path.parentPath.isCallExpression();
22
16
  const {length} = properties;
23
- const isOneLine = !length || isCall && length < 2 && !isFirstMethod(path) || isForOf(path);
17
+ const parens = isBodyOfArrow(path);
18
+ const manyLines = !isOneLine(path);
24
19
 
25
20
  maybe.write(parens, '(');
26
21
  write('{');
27
22
 
28
- maybe.write(!isOneLine, '\n');
23
+ maybe.write(manyLines, '\n');
29
24
 
30
25
  for (const property of properties) {
31
26
  if (property.isSpreadElement()) {
32
- maybe.indent(properties.length > 1);
27
+ maybe.indent(length > 1);
33
28
  traverse(property);
34
29
 
35
- if (properties.length > 1) {
30
+ if (length > 1) {
36
31
  write(',');
37
32
  write.newline();
38
33
  }
@@ -42,7 +37,7 @@ module.exports.ObjectExpression = (path, {traverse, write, maybe, indent}) => {
42
37
 
43
38
  const {shorthand, computed} = property.node;
44
39
 
45
- maybe.indent(!isOneLine);
40
+ maybe.indent(manyLines);
46
41
 
47
42
  if (property.isObjectMethod()) {
48
43
  traverse(property);
@@ -58,11 +53,27 @@ module.exports.ObjectExpression = (path, {traverse, write, maybe, indent}) => {
58
53
  traverse(property.get('value'));
59
54
  }
60
55
 
61
- maybe.write(!isOneLine, ',\n');
56
+ maybe.write(manyLines, ',\n');
62
57
  }
63
58
 
64
59
  indent.dec();
65
- maybe.indent(!isOneLine);
60
+
61
+ maybe.indent(manyLines);
66
62
  write('}');
67
63
  maybe.write(parens, ')');
68
64
  };
65
+ function isOneLine(path) {
66
+ const isCall = path.parentPath.isCallExpression();
67
+ const {length} = path.get('properties');
68
+
69
+ if (isCoupleLines(path))
70
+ return false;
71
+
72
+ if (!length)
73
+ return true;
74
+
75
+ if (isCall && length < 2)
76
+ return true;
77
+
78
+ return isForOf(path);
79
+ }
@@ -2,16 +2,20 @@
2
2
 
3
3
  module.exports.UnaryExpression = unaryExpressions;
4
4
  module.exports.UpdateExpression = unaryExpressions;
5
+ module.exports.AwaitExpression = (path, {write, traverse}) => {
6
+ write('await ');
7
+ traverse(path.get('argument'));
8
+ };
9
+
10
+ const isWord = (a) => /delete|typeof/.test(a);
5
11
 
6
- function unaryExpressions(path, {traverse, write}) {
12
+ function unaryExpressions(path, {traverse, write, maybe}) {
7
13
  const {prefix, operator} = path.node;
8
14
 
9
15
  if (prefix)
10
16
  write(operator);
11
17
 
12
- if (operator === 'typeof')
13
- write(' ');
14
-
18
+ maybe.write(isWord(operator), ' ');
15
19
  traverse(path.get('argument'));
16
20
 
17
21
  if (!prefix)
@@ -1,4 +1,11 @@
1
1
  'use strict';
2
2
 
3
+ module.exports.isFirst = (path) => path.node === path.parentPath.node.body[0];
3
4
  module.exports.isPrevBody = (path) => path.getPrevSibling().isBlockStatement();
4
5
  module.exports.isNext = (path) => path.getNextSibling().node;
6
+ module.exports.isCoupleLines = (path) => {
7
+ const start = path.node?.loc?.start.line;
8
+ const end = path.node?.loc?.end.line;
9
+
10
+ return end > start;
11
+ };
@@ -5,7 +5,8 @@ const {TemplateLiteral} = require('./template-literal');
5
5
  module.exports = {
6
6
  TemplateLiteral,
7
7
  NumericLiteral(path, {write}) {
8
- write(path.node.value);
8
+ const {extra, raw} = path.node;
9
+ write(raw || extra.raw);
9
10
  },
10
11
  BooleanLiteral(path, {write}) {
11
12
  write(path.node.value);
@@ -1,17 +1,10 @@
1
1
  'use strict';
2
2
 
3
- const {isMarkedAfter} = require('../mark');
4
- const isPrevNewLine = (path) => {
5
- const prev = path.getPrevSibling();
6
-
7
- if (!prev.node)
8
- return true;
9
-
10
- return isMarkedAfter(prev);
11
- };
3
+ const {isMarkedPrevAfter} = require('../mark');
4
+ const {isFirst} = require('../is');
12
5
 
13
6
  module.exports.ForOfStatement = (path, {write, indent, traverse}) => {
14
- if (!isPrevNewLine(path)) {
7
+ if (!isFirst(path) && !isMarkedPrevAfter(path)) {
15
8
  write.indent();
16
9
  write.newline();
17
10
  }
@@ -1,6 +1,7 @@
1
1
  'use strict';
2
2
 
3
3
  const {hasPrevNewline} = require('../mark');
4
+ const {isFirst} = require('../is');
4
5
 
5
6
  module.exports.IfStatement = (path, {write, indent, traverse, incIndent, decIndent}) => {
6
7
  if (!isFirst(path) && !hasPrevNewline(path)) {
@@ -36,7 +37,3 @@ module.exports.IfStatement = (path, {write, indent, traverse, incIndent, decInde
36
37
  write('\n');
37
38
  };
38
39
 
39
- function isFirst(path) {
40
- return path.node === path.parentPath.node.body[0];
41
- }
42
-
@@ -1,6 +1,6 @@
1
1
  'use strict';
2
2
 
3
- const {isNext} = require('../is');
3
+ const {isNext, isCoupleLines} = require('../is');
4
4
  const isNextAssign = (path) => {
5
5
  const nextPath = path.getNextSibling();
6
6
 
@@ -27,21 +27,25 @@ module.exports.VariableDeclaration = (path, {write, maybe, maybeIndent, traverse
27
27
  traverse(initPath);
28
28
  maybe.write(isParentBlock, ';\n');
29
29
 
30
- const is = isNext(path) && isCoupleLinesExpression(path) && !isNextAssign(path);
30
+ const is = isNext(path) && isCoupleLines(path) && !isNextAssign(path);
31
31
 
32
32
  maybe.indent(is);
33
33
  maybe.write(is, '\n');
34
34
  maybe.markAfter(is, path);
35
35
  };
36
- function isCoupleLinesExpression(path) {
37
- const start = path.node?.loc?.start.line;
38
- const end = path.node?.loc?.end.line;
39
-
40
- return end > start;
41
- }
42
36
 
43
37
  function shouldAddNewLine(path) {
44
38
  const prevPath = path.getPrevSibling();
39
+
40
+ if (prevPath.isStatement() && !prevPath.isExpressionStatement() && !prevPath.isBlockStatement())
41
+ return false;
42
+
43
+ if (prevPath.isExpressionStatement() && prevPath.get('expression').isStringLiteral())
44
+ return false;
45
+
46
+ if (isCoupleLines(path))
47
+ return true;
48
+
45
49
  const nextPath = path.getNextSibling();
46
50
  const nextNextPath = nextPath.getNextSibling();
47
51
 
@@ -50,12 +54,6 @@ function shouldAddNewLine(path) {
50
54
  if (!twoNext)
51
55
  return false;
52
56
 
53
- if (prevPath.isVariableDeclaration() || prevPath.isExpressionStatement() && prevPath.get('expression').isStringLiteral())
54
- return false;
55
-
56
- if (prevPath.isIfStatement())
57
- return false;
58
-
59
57
  return true;
60
58
  }
61
59
 
@@ -32,11 +32,12 @@ module.exports.tokenize = (ast) => {
32
32
 
33
33
  const maybeWrite = (a, b) => a && write(b);
34
34
  const maybeIndent = (a) => a && indent();
35
+ const maybeIndentInc = (a) => a && indent.inc();
36
+ const maybeIndentDec = (a) => a && indent.dec();
35
37
 
36
38
  let i = 0;
37
39
  const incIndent = () => ++i;
38
40
  const decIndent = () => --i;
39
-
40
41
  const indent = () => {
41
42
  tokens.push({
42
43
  type: TYPES.INDENT,
@@ -76,6 +77,11 @@ module.exports.tokenize = (ast) => {
76
77
  markAfter: maybeMarkAfter,
77
78
  };
78
79
 
80
+ assign(maybe.indent, {
81
+ inc: maybeIndentInc,
82
+ dec: maybeIndentDec,
83
+ });
84
+
79
85
  const printer = {
80
86
  incIndent,
81
87
  decIndent,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@putout/printer",
3
- "version": "1.4.0",
3
+ "version": "1.4.2",
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",
@@ -28,6 +28,7 @@
28
28
  "dependencies": {
29
29
  "@babel/parser": "^7.19.0",
30
30
  "@babel/traverse": "^7.21.2",
31
+ "@babel/types": "^7.21.3",
31
32
  "just-snake-case": "^3.2.0"
32
33
  },
33
34
  "keywords": [
@@ -44,6 +45,7 @@
44
45
  "eslint": "^8.0.1",
45
46
  "eslint-plugin-n": "^15.2.4",
46
47
  "eslint-plugin-putout": "^17.0.0",
48
+ "estree-to-babel": "^5.0.1",
47
49
  "just-kebab-case": "^4.2.0",
48
50
  "lerna": "^6.0.1",
49
51
  "madrun": "^9.0.0",