@round-core/prettier 0.1.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/package.json +16 -0
- package/src/index.js +28 -0
- package/src/parser.js +49 -0
- package/src/printer.js +120 -0
package/package.json
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@round-core/prettier",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Prettier plugin for RoundJS",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "src/index.js",
|
|
7
|
+
"files": [
|
|
8
|
+
"src"
|
|
9
|
+
],
|
|
10
|
+
"peerDependencies": {
|
|
11
|
+
"prettier": "^3.0.0"
|
|
12
|
+
},
|
|
13
|
+
"dependencies": {
|
|
14
|
+
"@round-core/shared": "latest"
|
|
15
|
+
}
|
|
16
|
+
}
|
package/src/index.js
ADDED
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { parsers as babelParsers } from "prettier/plugins/babel";
|
|
2
|
+
import { printers as estreePrinters } from "prettier/plugins/estree";
|
|
3
|
+
import { parse } from './parser.js';
|
|
4
|
+
import * as myImportedPrinter from './printer.js';
|
|
5
|
+
|
|
6
|
+
export const languages = [
|
|
7
|
+
{
|
|
8
|
+
name: 'RoundJS',
|
|
9
|
+
extensions: ['.round'],
|
|
10
|
+
parsers: ['round'],
|
|
11
|
+
}
|
|
12
|
+
];
|
|
13
|
+
|
|
14
|
+
export const parsers = {
|
|
15
|
+
round: {
|
|
16
|
+
parse,
|
|
17
|
+
astFormat: 'estree',
|
|
18
|
+
locStart: (node) => node.start,
|
|
19
|
+
locEnd: (node) => node.end
|
|
20
|
+
}
|
|
21
|
+
};
|
|
22
|
+
|
|
23
|
+
export const printers = {
|
|
24
|
+
estree: {
|
|
25
|
+
...estreePrinters.estree,
|
|
26
|
+
print: myImportedPrinter.print
|
|
27
|
+
}
|
|
28
|
+
};
|
package/src/parser.js
ADDED
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import { parsers as babelParsers } from "prettier/plugins/babel";
|
|
2
|
+
import { SourceMapper, runPreprocess } from "@round-core/shared";
|
|
3
|
+
|
|
4
|
+
function traverseAndRemap(node, mapper) {
|
|
5
|
+
if (!node) return;
|
|
6
|
+
|
|
7
|
+
if (node.type === 'File') {
|
|
8
|
+
// console.error('DEBUG ROOT KEYS:', Object.keys(node));
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
// Remap location
|
|
12
|
+
if (typeof node.start === 'number') {
|
|
13
|
+
const oldStart = node.start;
|
|
14
|
+
node.start = mapper.remap(node.start);
|
|
15
|
+
if (node.type === 'CommentLine') {
|
|
16
|
+
// console.error(`DEBUG COMMENT REMAP: ${oldStart} -> ${node.start}`);
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
if (typeof node.end === 'number') node.end = mapper.remap(node.end);
|
|
20
|
+
// if (node.loc) delete node.loc; // Force calc
|
|
21
|
+
|
|
22
|
+
for (const key in node) {
|
|
23
|
+
if (key === 'loc') continue;
|
|
24
|
+
const val = node[key];
|
|
25
|
+
if (Array.isArray(val)) {
|
|
26
|
+
val.forEach(child => traverseAndRemap(child, mapper));
|
|
27
|
+
} else if (val && typeof val === 'object' && typeof val.type === 'string') {
|
|
28
|
+
traverseAndRemap(val, mapper);
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
export function parse(text, parsers, options) {
|
|
34
|
+
const mapper = new SourceMapper();
|
|
35
|
+
runPreprocess(text, mapper, 0);
|
|
36
|
+
|
|
37
|
+
// Explicitly request tokens
|
|
38
|
+
const ast = babelParsers.babel.parse(mapper.code, parsers, { ...options, tokens: true });
|
|
39
|
+
traverseAndRemap(ast, mapper);
|
|
40
|
+
|
|
41
|
+
// Debug AST comments
|
|
42
|
+
// if (ast.comments && ast.comments.length > 0) {
|
|
43
|
+
// console.error('DEBUG AST COMMENTS:', JSON.stringify(ast.comments.map(c => ({
|
|
44
|
+
// val: c.value, start: c.start, end: c.end, loc: c.loc
|
|
45
|
+
// })), null, 2));
|
|
46
|
+
// }
|
|
47
|
+
|
|
48
|
+
return ast;
|
|
49
|
+
}
|
package/src/printer.js
ADDED
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
import { printers as estreePrinters } from "prettier/plugins/estree";
|
|
2
|
+
import { builders } from "prettier/doc";
|
|
3
|
+
|
|
4
|
+
const estreePrinter = estreePrinters.estree;
|
|
5
|
+
const { group, indent, softline, hardline, join, line } = builders;
|
|
6
|
+
|
|
7
|
+
function getKind(node) {
|
|
8
|
+
if (node.type !== 'JSXElement') return null;
|
|
9
|
+
if (node.openingElement.name.name !== 'RoundControlFlow') return null;
|
|
10
|
+
const attrs = node.openingElement.attributes;
|
|
11
|
+
for (const attr of attrs) {
|
|
12
|
+
if (attr.name.name === 'kind') return attr.value.value;
|
|
13
|
+
}
|
|
14
|
+
return null;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
function isContinuation(kind) {
|
|
18
|
+
return ['else', 'else if', 'catch', 'finally'].includes(kind);
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
function hasNextContinuation(path) {
|
|
22
|
+
const node = path.getValue();
|
|
23
|
+
const siblings = path.getParentNode().children;
|
|
24
|
+
if (!siblings) return false;
|
|
25
|
+
let idx = path.getName();
|
|
26
|
+
if (typeof idx !== 'number') return false;
|
|
27
|
+
|
|
28
|
+
// Look ahead
|
|
29
|
+
for (let i = idx + 1; i < siblings.length; i++) {
|
|
30
|
+
const sib = siblings[i];
|
|
31
|
+
if (sib.type === 'JSXText' && !sib.value.trim()) continue;
|
|
32
|
+
|
|
33
|
+
const kind = getKind(sib);
|
|
34
|
+
if (kind && isContinuation(kind)) return true;
|
|
35
|
+
|
|
36
|
+
return false;
|
|
37
|
+
}
|
|
38
|
+
return false;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
export const canAttachComment = estreePrinter.canAttachComment;
|
|
42
|
+
export const handleComments = estreePrinter.handleComments;
|
|
43
|
+
export const isBlockComment = estreePrinter.isBlockComment;
|
|
44
|
+
export const getVisitorKeys = estreePrinter.getVisitorKeys;
|
|
45
|
+
export const printComment = estreePrinter.printComment; // Usually exists
|
|
46
|
+
// export const embed = estreePrinter.embed; // Careful with embed recursion?
|
|
47
|
+
|
|
48
|
+
export function print(path, options, print) {
|
|
49
|
+
const node = path.getValue();
|
|
50
|
+
|
|
51
|
+
// Check if originalText is preprocessed
|
|
52
|
+
if (node.type === 'Program') {
|
|
53
|
+
// console.error('DEBUG ORIGINAL TEXT:', options.originalText.slice(0, 500));
|
|
54
|
+
// console.error('DEBUG ESTREE KEYS:', Object.keys(estreePrinter));
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
if (node.type === 'JSXElement' &&
|
|
58
|
+
node.openingElement.name.name === 'RoundControlFlow') {
|
|
59
|
+
|
|
60
|
+
const attrs = node.openingElement.attributes;
|
|
61
|
+
let kind = '';
|
|
62
|
+
let head = '';
|
|
63
|
+
let rawAttrs = '';
|
|
64
|
+
|
|
65
|
+
for (let i = 0; i < attrs.length; i++) {
|
|
66
|
+
const attr = attrs[i];
|
|
67
|
+
if (attr.name.name === 'kind') kind = attr.value.value;
|
|
68
|
+
if (attr.name.name === 'head') {
|
|
69
|
+
if (attr.value.type === 'JSXExpressionContainer') {
|
|
70
|
+
head = path.call(print, "openingElement", "attributes", i, "value", "expression");
|
|
71
|
+
} else {
|
|
72
|
+
head = attr.value.value;
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
if (attr.name.name === '_attrs') rawAttrs = attr.value.value;
|
|
76
|
+
}
|
|
77
|
+
if (typeof head === 'string') {
|
|
78
|
+
head = head ? head.replace(/"/g, '"') : '';
|
|
79
|
+
}
|
|
80
|
+
rawAttrs = rawAttrs ? rawAttrs.replace(/"/g, '"') : '';
|
|
81
|
+
|
|
82
|
+
const parts = [];
|
|
83
|
+
|
|
84
|
+
// Opening
|
|
85
|
+
if (isContinuation(kind)) {
|
|
86
|
+
parts.push(' ', kind);
|
|
87
|
+
} else {
|
|
88
|
+
parts.push('{', kind);
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
if (head) {
|
|
92
|
+
parts.push(' (', head, ')');
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
if (rawAttrs) {
|
|
96
|
+
parts.push(' ', rawAttrs);
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
parts.push(' {');
|
|
100
|
+
|
|
101
|
+
const childDocs = path.map(print, "children").filter(doc => doc && doc !== "");
|
|
102
|
+
parts.push(indent([hardline, join(hardline, childDocs)]));
|
|
103
|
+
parts.push(hardline, '}');
|
|
104
|
+
|
|
105
|
+
// Closing
|
|
106
|
+
if (!hasNextContinuation(path)) {
|
|
107
|
+
parts.push('}');
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
return group(parts);
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
if (node.type === 'JSXText') {
|
|
114
|
+
const trimmed = node.value.trim();
|
|
115
|
+
if (!trimmed) return '';
|
|
116
|
+
return trimmed;
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
return estreePrinter.print(path, options, print);
|
|
120
|
+
}
|