@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 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(/&quot;/g, '"') : '';
79
+ }
80
+ rawAttrs = rawAttrs ? rawAttrs.replace(/&quot;/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
+ }