Skip to content

Commit

Permalink
fix: compatibility with other plugins
Browse files Browse the repository at this point in the history
issue: #99
  • Loading branch information
hosseinmd committed Apr 2, 2021
1 parent ce00b26 commit bfc9c39
Show file tree
Hide file tree
Showing 8 changed files with 312 additions and 8 deletions.
1 change: 1 addition & 0 deletions .eslintignore
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
node_modules/
prettier-plugin-fake/
lib/
tests/files
5 changes: 4 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,9 @@
"name": "prettier-plugin-jsdoc",
"version": "0.3.17",
"description": "",
"workspaces": {
"prettier-plugin-fake": "./prettier-plugin-fake"
},
"main": "lib/index.js",
"scripts": {
"prepare": "tsc",
Expand Down Expand Up @@ -79,4 +82,4 @@
"engines": {
"node": ">=12.0.0"
}
}
}
29 changes: 29 additions & 0 deletions prettier-plugin-fake/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
const { parsers: typescriptParsers } = require("prettier/parser-typescript");

/**
*
* @param {*} text
* @param {import("prettier/index").Options} options
* @returns
*/
const preprocess = (text, options) => {
if (
options.plugins.find((plugin) => plugin.name === "prettier-plugin-fake")
) {
return `//prettier-plugin-fake\n${text}`;
}
return text;
};

exports.parsers = {
typescript: {
...typescriptParsers.typescript,
preprocess: typescriptParsers.typescript.preprocess
? (text, options) =>
preprocess(
typescriptParsers.typescript.preprocess(text, options),
options,
)
: preprocess,
},
};
8 changes: 8 additions & 0 deletions prettier-plugin-fake/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
{
"name": "prettier-plugin-fake",
"version": "1.1.1",
"main": "index.js",
"files": [
"index.js"
]
}
71 changes: 64 additions & 7 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -95,32 +95,89 @@ const parsers = {
// JS - Babel
get babel() {
const parser = parserBabel.parsers.babel;
return { ...parser, parse: getParser(parser.parse) };
return mergeParsers(parser, "babel-babel");
},
get "babel-flow"() {
const parser = parserBabel.parsers["babel-flow"];
return { ...parser, parse: getParser(parser.parse) };
return mergeParsers(parser, "babel-flow");
},
get "babel-ts"() {
const parser = parserBabel.parsers["babel-ts"];
return { ...parser, parse: getParser(parser.parse) };
return mergeParsers(parser, "babel-ts");
},
// JS - Flow
get flow() {
const parser = parserFlow.parsers.flow;
return { ...parser, parse: getParser(parser.parse) };
return mergeParsers(parser, "flow");
},
// JS - TypeScript
get typescript() {
get typescript(): prettier.Parser {
const parser = parserTypescript.parsers.typescript;
return { ...parser, parse: getParser(parser.parse) };

return mergeParsers(parser, "typescript");
// require("./parser-typescript").parsers.typescript;
},
get "jsdoc-parser"() {
// Backward compatible, don't use this in new version since 1.0.0
const parser = parserBabel.parsers["babel-ts"];
return { ...parser, parse: getParser(parser.parse) };

return mergeParsers(parser, "babel-ts");
},
};

function mergeParsers(originalParser: prettier.Parser, parserName: string) {
let pluginParse = originalParser.parse;

const jsDocParse = getParser(pluginParse) as any;
const jsDocPreprocess = (text: string, options: prettier.ParserOptions) => {
const tsPlugin = options.plugins.find((plugin) => {
return (
typeof plugin === "object" &&
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
//@ts-ignore
plugin.name &&
plugin.parsers &&
// eslint-disable-next-line no-prototype-builtins
plugin.parsers.hasOwnProperty(parserName)
);
}) as prettier.Plugin | undefined;

if (
!tsPlugin || // eslint-disable-next-line @typescript-eslint/ban-ts-comment
//@ts-ignore
tsPlugin.name === "prettier-plugin-jsdoc" ||
tsPlugin.parsers?.hasOwnProperty("jsdoc-parser")
) {
return originalParser.preprocess
? // eslint-disable-next-line @typescript-eslint/ban-ts-comment
//@ts-ignore
originalParser.preprocess(text, options)
: text;
}

const tsPluginParser = tsPlugin.parsers?.typescript || originalParser;

pluginParse = tsPluginParser.parse || pluginParse;

const preprocess = tsPluginParser.preprocess || originalParser.preprocess;

Object.assign(parser, {
...parser,
...tsPluginParser,
preprocess: jsDocPreprocess,
parse: jsDocParse,
});

return preprocess ? preprocess(text, options) : text;
};

const parser = {
...originalParser,
preprocess: jsDocPreprocess,
parse: jsDocParse,
};

return parser;
}

export { languages, options, parsers, defaultOptions };
2 changes: 2 additions & 0 deletions src/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,8 @@ function formatType(type: string, options?: Options): string {
pretty = format(`${TYPE_START}${pretty}`, {
...options,
parser: "typescript",
plugins: [],
filepath: "file.ts",
});
pretty = pretty.slice(TYPE_START.length);
pretty = pretty.replace(/[;\n]*$/g, "");
Expand Down
126 changes: 126 additions & 0 deletions tests/__snapshots__/compatibleWithPlugins.test.ts.snap
Original file line number Diff line number Diff line change
@@ -0,0 +1,126 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP

exports[`Should convert to single line if necessary 1`] = `
"//prettier-plugin-fake
/** Single line description */
"
`;

exports[`Should convert to single line if necessary 2`] = `
"//prettier-plugin-fake
/** Single line description */
"
`;

exports[`Should convert to single line if necessary 3`] = `
"//prettier-plugin-fake
/**
* Single line description
*
* @returns {Boolean} Always true
*/
"
`;

exports[`Should format jsDoc default values 1`] = `
"//prettier-plugin-fake
/**
* @param {String} [arg1=\\"defaultTest\\"] Foo. Default is \`\\"defaultTest\\"\`
* @param {number} [arg2=123] The width of the rectangle. Default is \`123\`
* @param {number} [arg3=123] Default is \`123\`
* @param {number} [arg4=Foo.bar.baz] Default is \`Foo.bar.baz\`
* @param {number | string} [arg5=123] Something. Default is \`123\`
*/
"
`;

exports[`Should format jsDoc default values 2`] = `
"//prettier-plugin-fake
//prettier-plugin-fake
/**
* @param {String} [arg1=\\"defaultTest\\"] Foo. Default is \`\\"defaultTest\\"\`
* @param {number} [arg2=123] The width of the rectangle. Default is \`123\`
* @param {number} [arg3=123] Default is \`123\`
* @param {number} [arg4=Foo.bar.baz] Default is \`Foo.bar.baz\`
* @param {number | string} [arg5=123] Something. Default is \`123\`
*/
"
`;

exports[`Should format regular jsDoc 1`] = `
"//prettier-plugin-fake
import b from \\"b\\";
import { k } from \\"k\\";
import a from \\"a\\";
/**
* Function example description that was wrapped by hand so it have more then
* one line and don't end with a dot REPEATED TWO TIMES BECAUSE IT WAS EASIER to
* copy function example description that was wrapped by hand so it have more
* then one line.
*
* @async
* @private
* @memberof test
* @example
* //prettier-plugin-fake
* var one = 5;
* var two = 10;
*
* if (one > 2) {
* two += one;
* }
*
* @param {String | Number} text - Some text description that is very long and
* needs to be wrapped
* @param {String} [defaultValue=\\"defaultTest\\"] TODO. Default is \`\\"defaultTest\\"\`
* @param {Number | Null} [optionalNumber]
* @returns {Boolean} Description for @returns with s
* @undefiendTag
* @undefiendTag {number} name des
*/
const testFunction = (text, defaultValue, optionalNumber) => true;
"
`;

exports[`Should format regular jsDoc 2`] = `
"//prettier-plugin-fake
//prettier-plugin-fake
import b from \\"b\\";
import { k } from \\"k\\";
import a from \\"a\\";
/**
* Function example description that was wrapped by hand so it have more then
* one line and don't end with a dot REPEATED TWO TIMES BECAUSE IT WAS EASIER to
* copy function example description that was wrapped by hand so it have more
* then one line.
*
* @async
* @private
* @memberof test
* @example
* //prettier-plugin-fake
* //prettier-plugin-fake
* var one = 5;
* var two = 10;
*
* if (one > 2) {
* two += one;
* }
*
* @param {String | Number} text - Some text description that is very long and
* needs to be wrapped
* @param {String} [defaultValue=\\"defaultTest\\"] TODO. Default is \`\\"defaultTest\\"\`
* @param {Number | Null} [optionalNumber]
* @returns {Boolean} Description for @returns with s
* @undefiendTag
* @undefiendTag {number} name des
*/
const testFunction = (text, defaultValue, optionalNumber) => true;
"
`;
78 changes: 78 additions & 0 deletions tests/compatibleWithPlugins.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
import prettier from "prettier";
import { AllOptions } from "../src/types";

function subject(code: string, options: Partial<AllOptions> = {}) {
return prettier.format(code, {
parser: "typescript",
plugins: ["prettier-plugin-fake", "prettier-plugin-jsdoc"],
jsdocSpaces: 1,
...options,
} as AllOptions);
}

test("Should format regular jsDoc", () => {
const result = subject(`
import b from "b"
import {k} from "k"
import a from "a"
/**
* function example description that was wrapped by hand
* so it have more then one line and don't end with a dot
* REPEATED TWO TIMES BECAUSE IT WAS EASIER to copy
* function example description that was wrapped by hand
* so it have more then one line.
* @return {Boolean} Description for @returns with s
* @param {String|Number} text - some text description that is very long and needs to be wrapped
* @param {String} [defaultValue="defaultTest"] TODO
* @arg {Number|Null} [optionalNumber]
* @private
*@memberof test
@async
* @examples
* var one = 5
* var two = 10
*
* if(one > 2) { two += one }
* @undefiendTag${" "}
* @undefiendTag {number} name des
*/
const testFunction = (text, defaultValue, optionalNumber) => true
`);

expect(result).toMatchSnapshot();
expect(subject(result)).toMatchSnapshot();
});

test("Should format jsDoc default values", () => {
const result = subject(`
/**
* @param {String} [arg1="defaultTest"] foo
* @param {number} [arg2=123] the width of the rectangle
* @param {number} [arg3= 123 ]
* @param {number} [arg4= Foo.bar.baz ]
* @param {number|string} [arg5=123] Something. Default is \`"wrong"\`
*/
`);

expect(result).toMatchSnapshot();
expect(subject(result)).toMatchSnapshot();
});

test("Should convert to single line if necessary", () => {
const Result1 = subject(`/** single line description*/`);
const Result2 = subject(`/**
* single line description
* @example
*/`);

const Result3 = subject(`/**
* single line description
* @return {Boolean} Always true
* @example
*/`);

expect(Result1).toMatchSnapshot();
expect(Result2).toMatchSnapshot();
expect(Result3).toMatchSnapshot();
});

0 comments on commit bfc9c39

Please sign in to comment.