@tsrx/prettier-plugin 0.3.85 → 0.3.87

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 CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tsrx/prettier-plugin",
3
- "version": "0.3.85",
3
+ "version": "0.3.87",
4
4
  "description": "Ripple plugin for Prettier",
5
5
  "type": "module",
6
6
  "module": "src/index.js",
@@ -24,10 +24,10 @@
24
24
  },
25
25
  "devDependencies": {
26
26
  "@types/node": "^24.3.0",
27
- "prettier": "^3.8.3"
27
+ "prettier": "^3.8.4"
28
28
  },
29
29
  "dependencies": {
30
- "@tsrx/core": "0.1.33"
30
+ "@tsrx/core": "0.1.34"
31
31
  },
32
32
  "files": [
33
33
  "src/"
package/src/index.js CHANGED
@@ -223,6 +223,32 @@ function hasComment(node) {
223
223
  return !!(node.leadingComments || node.trailingComments || node.innerComments);
224
224
  }
225
225
 
226
+ /**
227
+ * Check whether a comment is a `prettier-ignore` directive.
228
+ * @param {AST.Comment | undefined} comment - The comment to check
229
+ * @returns {boolean} - True if the comment reads exactly `prettier-ignore`
230
+ */
231
+ function isPrettierIgnoreComment(comment) {
232
+ if (!comment || (comment.type !== 'Line' && comment.type !== 'Block')) {
233
+ return false;
234
+ }
235
+ return comment.value.trim() === 'prettier-ignore';
236
+ }
237
+
238
+ /**
239
+ * Check whether a node is immediately preceded by a `prettier-ignore` directive.
240
+ * Only the last leading comment counts, matching Prettier core.
241
+ * @param {AST.Node & AST.NodeWithMaybeComments} node - The AST node to check
242
+ * @returns {boolean} - True if the node should be printed verbatim
243
+ */
244
+ function hasPrettierIgnore(node) {
245
+ const comments = node.leadingComments;
246
+ if (!comments || comments.length === 0) {
247
+ return false;
248
+ }
249
+ return isPrettierIgnoreComment(comments[comments.length - 1]);
250
+ }
251
+
226
252
  /**
227
253
  * @param {AST.FunctionDeclaration | AST.FunctionExpression | AST.ArrowFunctionExpression | AST.TSDeclareFunction} node - The function node
228
254
  * @returns {Array<AST.Pattern | AST.Parameter>} - Array of parameter patterns
@@ -722,6 +748,70 @@ function printKey(node, path, options, print) {
722
748
  return parts;
723
749
  }
724
750
 
751
+ /**
752
+ * Combine already-printed leading comment parts, a node's printed body, and its
753
+ * trailing comments into the final Doc returned by {@link printRippleNode}.
754
+ * @param {AST.Node} node - The AST node
755
+ * @param {Doc[]} parts - Leading-comment parts already collected for the node
756
+ * @param {Doc[] | Doc} nodeContent - The printed body of the node
757
+ * @returns {Doc[] | Doc}
758
+ */
759
+ function finishRippleNode(node, parts, nodeContent) {
760
+ // Handle trailing comments
761
+ if (node.trailingComments) {
762
+ const trailingParts = [];
763
+ let previousComment = null;
764
+
765
+ for (let i = 0; i < node.trailingComments.length; i++) {
766
+ const comment = node.trailingComments[i];
767
+ const isInlineComment = Boolean(
768
+ node.loc && comment.loc && node.loc.end.line === comment.loc.start.line,
769
+ );
770
+
771
+ const commentDoc =
772
+ comment.type === 'Line' ? '//' + comment.value : '/*' + comment.value + '*/';
773
+
774
+ if (isInlineComment) {
775
+ if (comment.type === 'Line') {
776
+ trailingParts.push(lineSuffix([' ', commentDoc]));
777
+ trailingParts.push(breakParent);
778
+ } else {
779
+ trailingParts.push(' ' + commentDoc);
780
+ }
781
+ } else {
782
+ const refs = [];
783
+ refs.push(hardline);
784
+
785
+ const blankLinesBetween = previousComment
786
+ ? getBlankLinesBetweenNodes(previousComment, comment)
787
+ : getBlankLinesBetweenNodes(node, comment);
788
+ if (blankLinesBetween > 0) {
789
+ refs.push(hardline);
790
+ }
791
+
792
+ refs.push(commentDoc);
793
+ trailingParts.push(lineSuffix(refs));
794
+ }
795
+
796
+ previousComment = comment;
797
+ }
798
+
799
+ if (trailingParts.length > 0) {
800
+ parts.push(nodeContent);
801
+ parts.push(...trailingParts);
802
+ return parts;
803
+ }
804
+ } // Return with or without leading comments
805
+ if (parts.length > 0) {
806
+ // Don't add blank line between leading comments and node
807
+ // because they're meant to be attached together
808
+ parts.push(nodeContent);
809
+ return parts;
810
+ }
811
+
812
+ return nodeContent;
813
+ }
814
+
725
815
  /**
726
816
  * Main print function for Ripple AST nodes
727
817
  * @param {AST.Node | AST.CSS.StyleSheet} node - The AST node to print
@@ -812,6 +902,23 @@ function printRippleNode(node, path, options, print, args) {
812
902
  }
813
903
  }
814
904
 
905
+ // A `prettier-ignore` directive keeps the node's original source verbatim.
906
+ const commentNode = /** @type {AST.Node & AST.NodeWithMaybeComments} */ (node);
907
+ const ignoreStart = /** @type {AST.NodeWithLocation} */ (node).start;
908
+ const ignoreEnd = /** @type {AST.NodeWithLocation} */ (node).end;
909
+ if (
910
+ hasPrettierIgnore(commentNode) &&
911
+ typeof options.originalText === 'string' &&
912
+ typeof ignoreStart === 'number' &&
913
+ typeof ignoreEnd === 'number'
914
+ ) {
915
+ return finishRippleNode(
916
+ commentNode,
917
+ parts,
918
+ replaceEndOfLine(options.originalText.slice(ignoreStart, ignoreEnd)),
919
+ );
920
+ }
921
+
815
922
  /** @type {Doc[] | Doc} */
816
923
  let nodeContent;
817
924
 
@@ -2338,64 +2445,7 @@ function printRippleNode(node, path, options, print, args) {
2338
2445
  break;
2339
2446
  }
2340
2447
 
2341
- // Handle trailing comments
2342
- if (node.trailingComments) {
2343
- const trailingParts = [];
2344
- let previousComment = null;
2345
-
2346
- for (let i = 0; i < node.trailingComments.length; i++) {
2347
- const comment = node.trailingComments[i];
2348
- const isInlineComment = Boolean(
2349
- node.loc && comment.loc && node.loc.end.line === comment.loc.start.line,
2350
- );
2351
-
2352
- const commentDoc =
2353
- comment.type === 'Line' ? '//' + comment.value : '/*' + comment.value + '*/';
2354
-
2355
- if (isInlineComment) {
2356
- if (comment.type === 'Line') {
2357
- trailingParts.push(lineSuffix([' ', commentDoc]));
2358
- trailingParts.push(breakParent);
2359
- } else {
2360
- trailingParts.push(' ' + commentDoc);
2361
- }
2362
- } else {
2363
- const refs = [];
2364
- refs.push(hardline);
2365
-
2366
- const blankLinesBetween = previousComment
2367
- ? getBlankLinesBetweenNodes(previousComment, comment)
2368
- : getBlankLinesBetweenNodes(node, comment);
2369
- if (blankLinesBetween > 0) {
2370
- refs.push(hardline);
2371
- }
2372
-
2373
- if (comment.type === 'Line') {
2374
- refs.push(commentDoc);
2375
- trailingParts.push(lineSuffix(refs));
2376
- } else {
2377
- refs.push(commentDoc);
2378
- trailingParts.push(lineSuffix(refs));
2379
- }
2380
- }
2381
-
2382
- previousComment = comment;
2383
- }
2384
-
2385
- if (trailingParts.length > 0) {
2386
- parts.push(nodeContent);
2387
- parts.push(...trailingParts);
2388
- return parts;
2389
- }
2390
- } // Return with or without leading comments
2391
- if (parts.length > 0) {
2392
- // Don't add blank line between leading comments and node
2393
- // because they're meant to be attached together
2394
- parts.push(nodeContent);
2395
- return parts;
2396
- }
2397
-
2398
- return nodeContent;
2448
+ return finishRippleNode(/** @type {AST.Node} */ (node), parts, nodeContent);
2399
2449
  }
2400
2450
 
2401
2451
  /**
package/src/index.test.js CHANGED
@@ -851,6 +851,89 @@ const items=[1,2,3];
851
851
  expect(result).toBeWithNewline(expected);
852
852
  });
853
853
 
854
+ describe('prettier-ignore', () => {
855
+ it('preserves a statement verbatim after a line directive', async () => {
856
+ const input = `export function App() {
857
+ // prettier-ignore
858
+ const matrix = [1,0,0,
859
+ 0,1,0,
860
+ 0,0,1];
861
+ return <div>{matrix.length}</div>;
862
+ }`;
863
+ const expected = `export function App() {
864
+ // prettier-ignore
865
+ const matrix = [1,0,0,
866
+ 0,1,0,
867
+ 0,0,1];
868
+ return <div>{matrix.length}</div>;
869
+ }`;
870
+ const result = await format(input);
871
+ expect(result).toBeWithNewline(expected);
872
+ });
873
+
874
+ it('preserves a statement verbatim after a block directive', async () => {
875
+ const input = `export function App() {
876
+ /* prettier-ignore */
877
+ const obj = {a:1, b:2};
878
+ return <div>{obj.a}</div>;
879
+ }`;
880
+ const expected = `export function App() {
881
+ /* prettier-ignore */
882
+ const obj = {a:1, b:2};
883
+ return <div>{obj.a}</div>;
884
+ }`;
885
+ const result = await format(input);
886
+ expect(result).toBeWithNewline(expected);
887
+ });
888
+
889
+ it('preserves a JSX element verbatim', async () => {
890
+ const input = `export function App() @{
891
+ // prettier-ignore
892
+ <div class="x" id="y">
893
+ hello
894
+ </div>
895
+ }`;
896
+ const expected = `export function App() @{
897
+ // prettier-ignore
898
+ <div class="x" id="y">
899
+ hello
900
+ </div>
901
+ }`;
902
+ const result = await format(input);
903
+ expect(result).toBeWithNewline(expected);
904
+ });
905
+
906
+ it('preserves a whitespace-only fragment verbatim', async () => {
907
+ const input = `function WhitespaceOnlyApp() @{
908
+ // prettier-ignore
909
+ <>
910
+ </>
911
+ }`;
912
+ const expected = `function WhitespaceOnlyApp() @{
913
+ // prettier-ignore
914
+ <>
915
+ </>
916
+ }`;
917
+ const result = await format(input);
918
+ expect(result).toBeWithNewline(expected);
919
+ });
920
+
921
+ it('still formats when the comment is not a prettier-ignore directive', async () => {
922
+ const input = `export function App() {
923
+ // this is a normal comment
924
+ const obj = {a:1, b:2};
925
+ return <div>{obj.a}</div>;
926
+ }`;
927
+ const expected = `export function App() {
928
+ // this is a normal comment
929
+ const obj = { a: 1, b: 2 };
930
+ return <div>{obj.a}</div>;
931
+ }`;
932
+ const result = await format(input);
933
+ expect(result).toBeWithNewline(expected);
934
+ });
935
+ });
936
+
854
937
  describe('recovered', () => {
855
938
  /**
856
939
  * @param {string} code