@aforemendude/prettier-plugin-wrap-comments 1.1.1 → 1.2.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/README.md CHANGED
@@ -31,6 +31,20 @@ Then run Prettier normally:
31
31
  npx prettier --write .
32
32
  ```
33
33
 
34
+ ### Use With `prettier-plugin-jsdoc`
35
+
36
+ When using both plugins, `@aforemendude/prettier-plugin-wrap-comments` must be loaded after `prettier-plugin-jsdoc`:
37
+
38
+ ```json
39
+ {
40
+ "plugins": ["prettier-plugin-jsdoc", "@aforemendude/prettier-plugin-wrap-comments"]
41
+ }
42
+ ```
43
+
44
+ This order is required regardless of `prettier-plugin-jsdoc`'s documentation saying that it should be the last plugin.
45
+ With wrap-comments last, ordinary comments are handled here and parsing is delegated to the preceding JSDoc plugin, so
46
+ JSDoc comments are formatted as well.
47
+
34
48
  ### Cache Repeated CLI Runs
35
49
 
36
50
  Prettier's CLI cache skips files that have not changed since a successful formatting pass. Enable it in package scripts
@@ -59,9 +73,10 @@ for cache keys, strategies, and custom cache locations.
59
73
  ## Behavior
60
74
 
61
75
  The plugin wraps comments for Prettier's `babel`, `babel-ts`, and `typescript` parsers. It runs during parser
62
- preprocessing: the underlying Prettier parser preprocesses and parses the source first, the plugin rewrites eligible
63
- comments from that parsed comment list, and Prettier then formats the rewritten source with its built-in JavaScript and
64
- TypeScript printers. If the parser cannot parse the preprocessed source, the plugin leaves the source unchanged.
76
+ preprocessing: the nearest preceding plugin for the selected parser, or Prettier's built-in parser when there is none,
77
+ preprocesses and parses the source first. This plugin rewrites eligible comments from that parsed comment list, and
78
+ Prettier then formats the rewritten source with its built-in JavaScript and TypeScript printers. If the parser cannot
79
+ parse the preprocessed source, the plugin leaves the source unchanged.
65
80
 
66
81
  Offset-sensitive formatting is conservative. Full-file `formatWithCursor` calls skip comment rewriting so Prettier can
67
82
  map the cursor from the original source. During range formatting, preprocessing does not rewrite text outside Prettier's
package/dist/index.d.ts CHANGED
@@ -1,10 +1,14 @@
1
1
  import type { Plugin } from 'prettier';
2
+ declare const name = "@aforemendude/prettier-plugin-wrap-comments";
2
3
  declare const parsers: {
3
4
  [parserName: string]: import("prettier").Parser<any>;
4
5
  };
5
6
  declare const printers: {
6
7
  [astFormat: string]: import("prettier").Printer<any>;
7
8
  };
8
- declare const plugin: Plugin;
9
- export { parsers, printers };
9
+ declare const plugin: NamedPlugin;
10
+ export { name, parsers, printers };
10
11
  export default plugin;
12
+ interface NamedPlugin extends Plugin {
13
+ name: string;
14
+ }
package/dist/index.js CHANGED
@@ -1,10 +1,13 @@
1
1
  import { createParsers } from './plugin/create-parsers.js';
2
2
  import { createPrinters } from './plugin/create-printers.js';
3
+ import { PLUGIN_NAME } from './plugin/plugin-name.js';
4
+ const name = PLUGIN_NAME;
3
5
  const parsers = createParsers();
4
6
  const printers = createPrinters();
5
7
  const plugin = {
8
+ name,
6
9
  parsers,
7
10
  printers,
8
11
  };
9
- export { parsers, printers };
12
+ export { name, parsers, printers };
10
13
  export default plugin;
@@ -6,6 +6,7 @@ import { wrapCommentsWithMetadata } from '../comments/wrap-comments.js';
6
6
  import { getPrinterLayoutSource } from './get-printer-layout-source.js';
7
7
  import { markRewrittenJsxBlockComments, setJsxBlockCommentRewrites } from './jsx-comment-rewrite-metadata.js';
8
8
  import { SUPPORTED_PARSER_NAMES } from './parser-names.js';
9
+ import { PLUGIN_NAME } from './plugin-name.js';
9
10
  export function createParsers() {
10
11
  const parsers = {};
11
12
  for (const parserName of SUPPORTED_PARSER_NAMES) {
@@ -18,17 +19,19 @@ export function createParsers() {
18
19
  return parsers;
19
20
  }
20
21
  function createWrappedParser(parserName, parser) {
21
- return {
22
+ const wrappedParser = {
22
23
  ...parser,
23
24
  async parse(text, options) {
24
- const ast = await parser.parse(text, options);
25
+ const delegate = await resolveParserDelegate(parserName, parser, wrappedParser, options);
26
+ const ast = await parseWithDelegate(text, delegate, options);
25
27
  const neutralizedAst = neutralizePrettierIgnoreForIgnoredComments(text, ast);
26
28
  markRewrittenJsxBlockComments(text, neutralizedAst, options);
27
29
  return neutralizedAst;
28
30
  },
29
31
  async preprocess(text, options) {
30
32
  setJsxBlockCommentRewrites(options, []);
31
- const preprocessed = parser.preprocess === undefined ? text : await parser.preprocess(text, options);
33
+ const delegate = await resolveParserDelegate(parserName, parser, wrappedParser, options);
34
+ const preprocessed = await preprocessWithDelegate(text, delegate, options);
32
35
  if (hasOffsetSensitiveFormatting(text, options)) {
33
36
  return preprocessed;
34
37
  }
@@ -37,7 +40,7 @@ function createWrappedParser(parserName, parser) {
37
40
  }
38
41
  let ast;
39
42
  try {
40
- ast = await parser.parse(preprocessed, { ...options, parser: parserName });
43
+ ast = await parseWithDelegate(preprocessed, delegate, { ...options, parser: parserName });
41
44
  }
42
45
  catch {
43
46
  return preprocessed;
@@ -45,12 +48,93 @@ function createWrappedParser(parserName, parser) {
45
48
  if (collectAstComments(ast).length === 0) {
46
49
  return preprocessed;
47
50
  }
48
- const printerLayoutSource = await getPrinterLayoutSource(preprocessed, ast, parserName, parser, options);
51
+ const printerLayoutSource = await getPrinterLayoutSource(preprocessed, ast, parserName, delegate.parser, createDelegateOptions(options, delegate.plugins));
49
52
  const result = await wrapCommentsWithMetadata(preprocessed, ast, options, printerLayoutSource);
50
53
  setJsxBlockCommentRewrites(options, result.jsxBlockCommentRewrites);
51
54
  return result.text;
52
55
  },
53
56
  };
57
+ return wrappedParser;
58
+ }
59
+ async function resolveParserDelegate(parserName, nativeParser, wrappedParser, options) {
60
+ const plugins = options.plugins ?? [];
61
+ const wrappedPluginIndex = findWrappedPluginIndex(plugins, parserName, wrappedParser);
62
+ if (wrappedPluginIndex === -1) {
63
+ return { parser: nativeParser };
64
+ }
65
+ for (let index = wrappedPluginIndex - 1; index >= 0; index -= 1) {
66
+ const plugin = getPlugin(plugins[index]);
67
+ const parserEntry = getParserEntry(plugin, parserName);
68
+ if (parserEntry === undefined) {
69
+ continue;
70
+ }
71
+ const precedingParser = typeof parserEntry === 'function' ? await parserEntry() : parserEntry;
72
+ if (isParser(precedingParser)) {
73
+ return {
74
+ parser: precedingParser,
75
+ plugins: plugins.slice(0, wrappedPluginIndex),
76
+ };
77
+ }
78
+ }
79
+ return { parser: nativeParser };
80
+ }
81
+ async function parseWithDelegate(text, delegate, options) {
82
+ return withDelegatePlugins(options, delegate.plugins, async () => delegate.parser.parse(text, options));
83
+ }
84
+ async function preprocessWithDelegate(text, delegate, options) {
85
+ const preprocess = delegate.parser.preprocess;
86
+ if (preprocess === undefined) {
87
+ return text;
88
+ }
89
+ return withDelegatePlugins(options, delegate.plugins, async () => preprocess(text, options));
90
+ }
91
+ async function withDelegatePlugins(options, plugins, callback) {
92
+ if (plugins === undefined) {
93
+ return callback();
94
+ }
95
+ const originalPlugins = options.plugins;
96
+ options.plugins = plugins;
97
+ try {
98
+ return await callback();
99
+ }
100
+ finally {
101
+ options.plugins = originalPlugins;
102
+ }
103
+ }
104
+ function createDelegateOptions(options, plugins) {
105
+ return plugins === undefined ? options : { ...options, plugins };
106
+ }
107
+ function findWrappedPluginIndex(plugins, parserName, wrappedParser) {
108
+ for (let index = plugins.length - 1; index >= 0; index -= 1) {
109
+ const plugin = getPlugin(plugins[index]);
110
+ const parserEntry = getParserEntry(plugin, parserName);
111
+ if (parserEntry === wrappedParser) {
112
+ return index;
113
+ }
114
+ }
115
+ for (let index = plugins.length - 1; index >= 0; index -= 1) {
116
+ const plugin = getPlugin(plugins[index]);
117
+ const parserEntry = getParserEntry(plugin, parserName);
118
+ if (plugin?.name === PLUGIN_NAME && parserEntry !== undefined) {
119
+ return index;
120
+ }
121
+ }
122
+ return -1;
123
+ }
124
+ function getPlugin(plugin) {
125
+ if (typeof plugin !== 'object' || plugin === null || plugin instanceof URL) {
126
+ return undefined;
127
+ }
128
+ return plugin;
129
+ }
130
+ function getParserEntry(plugin, parserName) {
131
+ if (plugin?.parsers === undefined || !Object.hasOwn(plugin.parsers, parserName)) {
132
+ return undefined;
133
+ }
134
+ return plugin.parsers[parserName];
135
+ }
136
+ function isParser(value) {
137
+ return typeof value === 'object' && value !== null && 'parse' in value && typeof value.parse === 'function';
54
138
  }
55
139
  function hasOffsetSensitiveFormatting(text, options) {
56
140
  const cursorOffset = options['cursorOffset'];
@@ -0,0 +1 @@
1
+ export declare const PLUGIN_NAME = "@aforemendude/prettier-plugin-wrap-comments";
@@ -0,0 +1 @@
1
+ export const PLUGIN_NAME = '@aforemendude/prettier-plugin-wrap-comments';
package/package.json CHANGED
@@ -7,7 +7,8 @@
7
7
  "devDependencies": {
8
8
  "@types/node": "20.19.43",
9
9
  "prettier": "3.9.6",
10
- "prettier-plugin-wrap-comments-stable": "npm:@aforemendude/prettier-plugin-wrap-comments@1.0.6",
10
+ "prettier-plugin-jsdoc": "1.8.1",
11
+ "prettier-plugin-wrap-comments-stable": "npm:@aforemendude/prettier-plugin-wrap-comments@1.1.1",
11
12
  "typescript": "7.0.2",
12
13
  "vite": "8.2.0",
13
14
  "vitest": "4.1.10"
@@ -67,5 +68,5 @@
67
68
  },
68
69
  "type": "module",
69
70
  "types": "./dist/index.d.ts",
70
- "version": "1.1.1"
71
+ "version": "1.2.0"
71
72
  }