prettier-plugin-wolfram 0.7.9 → 0.7.11

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/README.md CHANGED
@@ -129,6 +129,7 @@ Typical `.prettierrc` example:
129
129
  "alignRuleValues": false,
130
130
  "documentationCommentColumn": 0,
131
131
  "documentationCommentPadding": 2,
132
+ "documentationCommentMarkers": false,
132
133
  "topLevelSpacingMode": "declarations",
133
134
  "preserveTildeInfixFunctions": "",
134
135
  "moduleVarsBreakThreshold": 40,
@@ -158,6 +159,7 @@ this plugin.
158
159
  | `wolfram.alignRuleValues` | boolean | `false` | Vertically aligns `Rule` and `RuleDelayed` values in multiline argument, list, and association layouts. |
159
160
  | `wolfram.documentationCommentColumn` | integer | `0` | Column for trailing documentation comments. `0` computes a column per contiguous block. |
160
161
  | `wolfram.documentationCommentPadding` | integer | `2` | Minimum spaces between code and an aligned trailing documentation comment when the column is computed automatically. |
162
+ | `wolfram.documentationCommentMarkers` | boolean | `false` | Treats trailing comments beginning with `<` as documentation comments aligned at `printWidth`. |
161
163
  | `wolfram.topLevelSpacingMode` | string | `"declarations"` | Top-level blank-line policy. Allowed values are `declarations`, `all`, and `none`. |
162
164
  | `wolfram.preserveTildeInfixFunctions` | string | `""` | Comma-separated function names that stay in `x ~ f ~ y` form instead of normalizing to `f[x, y]`. |
163
165
  | `wolfram.moduleVarsBreakThreshold` | integer | `40` | Character count at which block-structure variable lists break across lines. |
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "prettier-plugin-wolfram",
3
- "version": "0.7.9",
3
+ "version": "0.7.11",
4
4
  "description": "Prettier plugin for Wolfram Language using tree-sitter",
5
5
  "license": "MIT",
6
6
  "repository": {
package/src/options.js CHANGED
@@ -109,6 +109,13 @@ export const wolframOptions = {
109
109
  description:
110
110
  "Minimum spaces between code and an aligned trailing documentation comment in auto mode.",
111
111
  },
112
+ documentationCommentMarkers: {
113
+ type: "boolean",
114
+ default: false,
115
+ legacyName: "wolframDocumentationCommentMarkers",
116
+ description:
117
+ "Treat trailing comments beginning with < as documentation comments aligned at printWidth.",
118
+ },
112
119
  topLevelSpacingMode: {
113
120
  type: "string",
114
121
  default: "declarations",
@@ -1,6 +1,7 @@
1
1
  import { doc } from "prettier";
2
2
  import { normalizeWolframOptions } from "../options.js";
3
3
  import { sameLineCommentSeparator } from "./commentSpacing.js";
4
+ import { sourceLineGap } from "./sourceLines.js";
4
5
 
5
6
  export function joinDocsWithSpace(docs) {
6
7
  const nonEmptyDocs = docs.filter(
@@ -19,7 +20,15 @@ export function isDocumentationCommentMarkerText(text) {
19
20
  return /^\(\*\s*</u.test(String(text ?? ""));
20
21
  }
21
22
 
22
- export function hasDocumentationCommentMarker(comment) {
23
+ function documentationCommentMarkersEnabled(options) {
24
+ return (
25
+ normalizeWolframOptions(options).wolframDocumentationCommentMarkers ===
26
+ true
27
+ );
28
+ }
29
+
30
+ export function hasDocumentationCommentMarker(comment, options) {
31
+ if (!documentationCommentMarkersEnabled(options)) return false;
23
32
  const node = comment?.node ?? comment;
24
33
  return (
25
34
  node?.kind === "Token`Comment" &&
@@ -27,6 +36,25 @@ export function hasDocumentationCommentMarker(comment) {
27
36
  );
28
37
  }
29
38
 
39
+ function hasMarkedDocumentationCommentEntry(entry, options) {
40
+ return (entry?.trailingComments ?? []).some((comment) =>
41
+ hasDocumentationCommentMarker(comment, options),
42
+ );
43
+ }
44
+
45
+ function isCommaEntry(entry) {
46
+ return entry?.node?.type === "LeafNode" && entry.node.kind === "Token`Comma";
47
+ }
48
+
49
+ function canAttachMarkedTrailingComment(previousEntry, commentEntry, options) {
50
+ return (
51
+ previousEntry &&
52
+ !isCommaEntry(previousEntry) &&
53
+ hasDocumentationCommentMarker(commentEntry, options) &&
54
+ sourceLineGap(previousEntry.node, commentEntry.node, options) === 0
55
+ );
56
+ }
57
+
30
58
  function normalizeDocumentationCommentMarker(text) {
31
59
  return String(text).replace(/^\(\*\s*<\s*/u, "(* < ");
32
60
  }
@@ -34,6 +62,7 @@ function normalizeDocumentationCommentMarker(text) {
34
62
  function normalizedCommentDoc(comment, options) {
35
63
  const rendered = renderFlatDoc(comment.doc, options);
36
64
  if (
65
+ !documentationCommentMarkersEnabled(options) ||
37
66
  !isDocumentationCommentMarkerText(rendered) ||
38
67
  rendered.includes("\n")
39
68
  ) {
@@ -62,6 +91,30 @@ export function joinCommentDocs(comments, options) {
62
91
  return joined;
63
92
  }
64
93
 
94
+ export function withMarkedTrailingCommentDocs(entries, options) {
95
+ const result = [];
96
+
97
+ for (const entry of entries) {
98
+ const previousEntry = result[result.length - 1];
99
+ if (canAttachMarkedTrailingComment(previousEntry, entry, options)) {
100
+ previousEntry.trailingComments ??= [];
101
+ previousEntry.trailingComments.push({
102
+ node: entry.node,
103
+ doc: entry.doc,
104
+ });
105
+ previousEntry.trailingCommentDoc = joinCommentDocs(
106
+ previousEntry.trailingComments,
107
+ options,
108
+ );
109
+ continue;
110
+ }
111
+
112
+ result.push(entry);
113
+ }
114
+
115
+ return result;
116
+ }
117
+
65
118
  export function renderFlatDoc(docNode, options) {
66
119
  const rendered = doc.printer.printDocToString(docNode, {
67
120
  printWidth: 100000,
@@ -76,10 +129,18 @@ export function documentationCommentColumn(
76
129
  entries,
77
130
  options,
78
131
  suffixForEntry = () => "",
132
+ columnOffset = 0,
79
133
  ) {
80
134
  options = normalizeWolframOptions(options);
81
135
  const manual = options.wolframDocumentationCommentColumn ?? 0;
82
- if (manual > 0) return manual;
136
+ if (manual > 0) return Math.max(1, manual - columnOffset);
137
+ if (
138
+ entries.some((entry) =>
139
+ hasMarkedDocumentationCommentEntry(entry, options),
140
+ )
141
+ ) {
142
+ return Math.max(1, (options.printWidth ?? 80) - columnOffset);
143
+ }
83
144
  const padding = Math.max(
84
145
  1,
85
146
  options.wolframDocumentationCommentPadding ?? 2,
@@ -1,11 +1,16 @@
1
1
  // src/translator/nodes/call.js
2
2
  import { doc } from "prettier";
3
3
  const { builders } = doc;
4
- import { isComment, isTrivia } from "./leaf.js";
4
+ import { isComment, isTrivia, stringLineIndentDepth } from "./leaf.js";
5
5
  import { alignedRuleDoc, withAlignedRuleValues } from "../ruleAlignment.js";
6
6
  import { commentBoundarySeparator } from "../commentSpacing.js";
7
+ import {
8
+ documentationCommentColumn,
9
+ withAlignedTrailingComment,
10
+ withMarkedTrailingCommentDocs,
11
+ } from "../docComments.js";
7
12
  import { normalizeWolframOptions } from "../../options.js";
8
- const { group, indent, softline, line } = builders;
13
+ const { group, indent, softline, line, hardline } = builders;
9
14
 
10
15
  const BRACKET_KINDS = new Set(["Token`OpenSquare", "Token`CloseSquare"]);
11
16
 
@@ -14,7 +19,7 @@ function isBracketToken(node) {
14
19
  }
15
20
 
16
21
  function isCommaToken(node) {
17
- return node.type === "LeafNode" && node.kind === "Token`Comma";
22
+ return node?.type === "LeafNode" && node.kind === "Token`Comma";
18
23
  }
19
24
 
20
25
  function nextContentEntry(entries, startIndex) {
@@ -154,19 +159,48 @@ function printedEntries(path, print, entries) {
154
159
  }));
155
160
  }
156
161
 
157
- function sequenceDocs(entries, options, itemKind) {
162
+ function sequenceDocs(rawEntries, options, itemKind, columnOffset = 0) {
163
+ const entries = withMarkedTrailingCommentDocs(rawEntries, options);
158
164
  const docs = [];
159
165
  const commaGap = options.wolframSpaceAfterComma ? line : softline;
160
166
  const alignmentGroupId = entries.some((entry) => entry.alignedRuleDoc)
161
167
  ? Symbol("wolfram-align-rule-values")
162
168
  : null;
169
+ for (let i = 0; i < entries.length; i++) {
170
+ if (entries[i].trailingCommentDoc) {
171
+ entries[i].trailingCommentSuffix = trailingCommentSuffix(
172
+ entries,
173
+ i,
174
+ );
175
+ }
176
+ }
177
+ const trailingCommentEntries = entries.filter(
178
+ (entry) => entry.trailingCommentDoc,
179
+ );
180
+ const trailingCommentColumn =
181
+ trailingCommentEntries.length > 0
182
+ ? documentationCommentColumn(
183
+ trailingCommentEntries,
184
+ options,
185
+ (entry) => entry.trailingCommentSuffix ?? "",
186
+ columnOffset,
187
+ )
188
+ : null;
163
189
  let previousKind = null;
164
190
 
165
191
  for (let i = 0; i < entries.length; i++) {
166
192
  const entry = entries[i];
167
193
  if (isCommaToken(entry.node)) {
168
- if (previousKind === null || previousKind === "comma") continue;
169
194
  const previousEntry = previousContentEntry(entries, i);
195
+ if (
196
+ previousEntry?.trailingCommentDoc &&
197
+ previousEntry.trailingCommentSuffix === ","
198
+ ) {
199
+ previousKind = "comma";
200
+ continue;
201
+ }
202
+
203
+ if (previousKind === null || previousKind === "comma") continue;
170
204
  const followingEntry = nextContentEntry(entries, i);
171
205
  const separator =
172
206
  followingEntry &&
@@ -192,7 +226,27 @@ function sequenceDocs(entries, options, itemKind) {
192
226
  );
193
227
  }
194
228
 
195
- docs.push(alignedRuleDoc(entry, alignmentGroupId));
229
+ const entryDoc = alignedRuleDoc(entry, alignmentGroupId);
230
+ if (entry.trailingCommentDoc) {
231
+ docs.push(
232
+ withAlignedTrailingComment(
233
+ { ...entry, doc: entryDoc },
234
+ options,
235
+ trailingCommentColumn,
236
+ entry.trailingCommentSuffix ?? "",
237
+ ),
238
+ );
239
+ if (
240
+ entry.trailingCommentSuffix === "," &&
241
+ nextContentEntry(entries, i)
242
+ ) {
243
+ docs.push(hardline);
244
+ previousKind = "comma";
245
+ continue;
246
+ }
247
+ } else {
248
+ docs.push(entryDoc);
249
+ }
196
250
  previousKind = isComment(entry.node) ? "comment" : itemKind;
197
251
  }
198
252
 
@@ -205,6 +259,14 @@ function grouped(contents, alignmentGroupId) {
205
259
  : group(contents);
206
260
  }
207
261
 
262
+ function contentColumnOffset(path, options) {
263
+ return stringLineIndentDepth(path) * (options.tabWidth ?? 2);
264
+ }
265
+
266
+ function trailingCommentSuffix(entries, index) {
267
+ return isCommaToken(entries[index + 1]?.node) ? "," : "";
268
+ }
269
+
208
270
  function printPartCall(path, options, print, node, head) {
209
271
  const partEntry = partGroupEntry(node);
210
272
  if (!partEntry) return null;
@@ -223,7 +285,12 @@ function printPartCall(path, options, print, node, head) {
223
285
 
224
286
  if (args.length === 0) return [head, "[[]]"];
225
287
 
226
- const { docs, alignmentGroupId } = sequenceDocs(entries, options, "part");
288
+ const { docs, alignmentGroupId } = sequenceDocs(
289
+ entries,
290
+ options,
291
+ "part",
292
+ contentColumnOffset(path, options),
293
+ );
227
294
  return grouped(
228
295
  [head, "[[", indent([softline, ...docs]), softline, "]]"],
229
296
  alignmentGroupId,
@@ -246,7 +313,12 @@ export function printCall(path, options, print, node) {
246
313
 
247
314
  if (args.length === 0) return [head, "[]"];
248
315
 
249
- const { docs, alignmentGroupId } = sequenceDocs(entries, options, "arg");
316
+ const { docs, alignmentGroupId } = sequenceDocs(
317
+ entries,
318
+ options,
319
+ "arg",
320
+ contentColumnOffset(path, options),
321
+ );
250
322
  const contents = [head, "[", indent([softline, ...docs]), softline, "]"];
251
323
 
252
324
  return grouped(contents, alignmentGroupId);
@@ -1,11 +1,16 @@
1
1
  // src/translator/nodes/group.js
2
2
  import { doc } from "prettier";
3
3
  const { builders } = doc;
4
- import { isComment, isTrivia } from "./leaf.js";
4
+ import { isComment, isTrivia, stringLineIndentDepth } from "./leaf.js";
5
5
  import { alignedRuleDoc, withAlignedRuleValues } from "../ruleAlignment.js";
6
6
  import { commentBoundarySeparator } from "../commentSpacing.js";
7
+ import {
8
+ documentationCommentColumn,
9
+ withAlignedTrailingComment,
10
+ withMarkedTrailingCommentDocs,
11
+ } from "../docComments.js";
7
12
  import { normalizeWolframOptions } from "../../options.js";
8
- const { group, indent, softline, line } = builders;
13
+ const { group, indent, softline, line, hardline } = builders;
9
14
 
10
15
  const GROUP_DELIMITERS = {
11
16
  GroupSquare: ["[", "]"],
@@ -32,7 +37,7 @@ function isBracketToken(node) {
32
37
  }
33
38
 
34
39
  function isCommaToken(node) {
35
- return node.type === "LeafNode" && node.kind === "Token`Comma";
40
+ return node?.type === "LeafNode" && node.kind === "Token`Comma";
36
41
  }
37
42
 
38
43
  function nextContentEntry(entries, startIndex) {
@@ -96,14 +101,25 @@ function sequenceEntries(path, print, node) {
96
101
  }, []);
97
102
  }
98
103
 
104
+ function contentColumnOffset(path, options) {
105
+ return stringLineIndentDepth(path) * (options.tabWidth ?? 2);
106
+ }
107
+
108
+ function trailingCommentSuffix(entries, index) {
109
+ return isCommaToken(entries[index + 1]?.node) ? "," : "";
110
+ }
111
+
99
112
  export function printGroup(path, options, print, node) {
100
113
  options = normalizeWolframOptions(options);
101
114
  const [open, close] = GROUP_DELIMITERS[node.kind] ?? ["{", "}"];
102
- const entries = withAlignedRuleValues(
103
- sequenceEntries(path, print, node),
104
- path,
115
+ const entries = withMarkedTrailingCommentDocs(
116
+ withAlignedRuleValues(
117
+ sequenceEntries(path, print, node),
118
+ path,
119
+ options,
120
+ print,
121
+ ),
105
122
  options,
106
- print,
107
123
  );
108
124
 
109
125
  if (entries.length === 0) return `${open}${close}`;
@@ -113,13 +129,41 @@ export function printGroup(path, options, print, node) {
113
129
  const alignmentGroupId = entries.some((entry) => entry.alignedRuleDoc)
114
130
  ? Symbol("wolfram-align-rule-values")
115
131
  : null;
132
+ for (let i = 0; i < entries.length; i++) {
133
+ if (entries[i].trailingCommentDoc) {
134
+ entries[i].trailingCommentSuffix = trailingCommentSuffix(
135
+ entries,
136
+ i,
137
+ );
138
+ }
139
+ }
140
+ const trailingCommentEntries = entries.filter(
141
+ (entry) => entry.trailingCommentDoc,
142
+ );
143
+ const trailingCommentColumn =
144
+ trailingCommentEntries.length > 0
145
+ ? documentationCommentColumn(
146
+ trailingCommentEntries,
147
+ options,
148
+ (entry) => entry.trailingCommentSuffix ?? "",
149
+ contentColumnOffset(path, options),
150
+ )
151
+ : null;
116
152
  let previousKind = null;
117
153
 
118
154
  for (let i = 0; i < entries.length; i++) {
119
155
  const entry = entries[i];
120
156
  if (isCommaToken(entry.node)) {
121
- if (previousKind === null || previousKind === "comma") continue;
122
157
  const previousEntry = previousContentEntry(entries, i);
158
+ if (
159
+ previousEntry?.trailingCommentDoc &&
160
+ previousEntry.trailingCommentSuffix === ","
161
+ ) {
162
+ previousKind = "comma";
163
+ continue;
164
+ }
165
+
166
+ if (previousKind === null || previousKind === "comma") continue;
123
167
  const followingEntry = nextContentEntry(entries, i);
124
168
  const separator =
125
169
  followingEntry &&
@@ -145,7 +189,27 @@ export function printGroup(path, options, print, node) {
145
189
  );
146
190
  }
147
191
 
148
- docs.push(alignedRuleDoc(entry, alignmentGroupId));
192
+ const entryDoc = alignedRuleDoc(entry, alignmentGroupId);
193
+ if (entry.trailingCommentDoc) {
194
+ docs.push(
195
+ withAlignedTrailingComment(
196
+ { ...entry, doc: entryDoc },
197
+ options,
198
+ trailingCommentColumn,
199
+ entry.trailingCommentSuffix ?? "",
200
+ ),
201
+ );
202
+ if (
203
+ entry.trailingCommentSuffix === "," &&
204
+ nextContentEntry(entries, i)
205
+ ) {
206
+ docs.push(hardline);
207
+ previousKind = "comma";
208
+ continue;
209
+ }
210
+ } else {
211
+ docs.push(entryDoc);
212
+ }
149
213
  previousKind = isComment(entry.node) ? "comment" : "item";
150
214
  }
151
215
 
@@ -192,7 +192,9 @@ export function printInfix(node, options, print) {
192
192
  (entry) => entry.trailingCommentDoc,
193
193
  );
194
194
  const hasMarkedDocumentationComment = trailingEntries.some((entry) =>
195
- entry.trailingComments.some(hasDocumentationCommentMarker),
195
+ entry.trailingComments.some((comment) =>
196
+ hasDocumentationCommentMarker(comment, options),
197
+ ),
196
198
  );
197
199
  const alignTrailingComments =
198
200
  (options.wolframDocumentationCommentColumn ?? 0) > 0 ||