Skip to content

Commit

Permalink
Merge pull request #135 from jscheid/prettier-3-plugins
Browse files Browse the repository at this point in the history
Prettier 3 Plugins
  • Loading branch information
jscheid authored Jun 1, 2024
2 parents d11bd50 + dac98f4 commit 5965223
Show file tree
Hide file tree
Showing 7 changed files with 92 additions and 48 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ and this project adheres to

- `prettier-diff-timeout-seconds` customization option
- `prettier-diff-edit-cost` customization option
- Support for Prettier 3

## Changed

Expand Down
61 changes: 34 additions & 27 deletions bootstrap.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,37 +17,44 @@
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.

const nodeVersion = process["version"];
if (Number(nodeVersion["split"](/[v.]/)[1]) < 6) {
process.exit(3);
}

const externalRequire = require;

const gunzipSync = externalRequire("zlib")["gunzipSync"];
const vm = externalRequire("vm");
const fs = externalRequire("fs");
function loadScript() {
const nodeVersion = process["version"];
if (Number(nodeVersion["split"](/[v.]/)[1]) < 6) {
process.exit(3);
}

function readFully(fd, size) {
const buf = Buffer["alloc"](size);
let offset = 0;
while (offset < size) {
const numRead = fs["readSync"](fd, buf, offset, size - offset, null);
if (numRead <= 0) {
throw new Error("EOF");
const externalRequire = require;

const gunzipSync = externalRequire("zlib")["gunzipSync"];
const vm = externalRequire("vm");
const fs = externalRequire("fs");

function readFully(fd, size) {
const buf = Buffer["alloc"](size);
let offset = 0;
while (offset < size) {
const numRead = fs["readSync"](fd, buf, offset, size - offset, null);
if (numRead <= 0) {
throw new Error("EOF");
}
offset += numRead;
}
offset += numRead;
return buf;
}
return buf;
}

const script = new vm["Script"](
gunzipSync(
Buffer.from(
readFully(0, Number(process["argv"][1])).toString("ascii"),
"base64"
)
).toString("utf-8")
);
const script = new vm["Script"](
gunzipSync(
Buffer.from(
readFully(0, Number(process["argv"][1])).toString("ascii"),
"base64"
)
).toString("utf-8")
);

return script;
}

const script = loadScript();
global.env = process.env;
script["runInThisContext"]()(script);
4 changes: 3 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,15 @@
"version": "0.0.0",
"private": true,
"license": "GPLv3+",
"packageManager": "yarn@1",
"devDependencies": {
"closurecompiler-externs": "1.0.4",
"diff-match-patch": "1.0.5"
},
"dependencies": {
"google-closure-compiler": "20220405.0.0",
"node-zopfli-es": "1.0.7"
},
"prettier": {
"trailingComma": "es5"
}
}
69 changes: 51 additions & 18 deletions prettier-el.js
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@
function noop() {}
global["console"]["warn"] = noop;

process.env = global.env;

// Hack to circumvent Closure Compiler CommonJS resolution
const externalRequire = require;

Expand Down Expand Up @@ -48,7 +50,15 @@ const ignoreParser = "ignored";

const syncBeacon = Buffer.from("#prettier.el-sync#\n");

/** @type{PrettierAPI} */
/**
* @typedef {{
* api: !(PrettierAPI|V3CompatAPI),
* require: !function(string)
* }}
*/
var PrettierAPIAndRequire;

/** @type{PrettierAPIAndRequire} */
let globalPrettier;

/**
Expand Down Expand Up @@ -123,7 +133,7 @@ function makeU32(val) {
* Find a globally installed Prettier or error if not found. Memoize results for
* future lookups.
*
* @return {!PrettierAPI | !Error}
* @return {PrettierAPIAndRequire | !Error}
*/
function getGlobalPrettier() {
if (globalPrettier) {
Expand Down Expand Up @@ -164,7 +174,7 @@ function getGlobalPrettier() {
for (let i = 0; i < pathOptions.length; ++i) {
if (pathOptions[i]) {
try {
return globalRequire(pathOptions[i]);
return { api: globalRequire(pathOptions[i]), require: globalRequire };
} catch (e) {
if (
!(e instanceof Error) ||
Expand Down Expand Up @@ -225,7 +235,7 @@ function findFileInAncestry(directory, fileNames) {
/**
* Try requiring the Prettier package using the given require function.
*
* @param {!Function} targetRequire The require function to use.
* @param {!function(string)} targetRequire The require function to use.
* @return {PrettierAPI} The Prettier package if found, or null if not found.
*/
function tryRequirePrettier(targetRequire) {
Expand All @@ -252,15 +262,15 @@ function tryRequirePrettier(targetRequire) {
* Find locally installed Prettier, or null if not found.
*
* @param {!string} directory The directory for which to find a local Prettier installation.
* @return {PrettierAPI} The Prettier package if found, or null if not found.
* @return {PrettierAPIAndRequire|null} The Prettier package if found, or null if not found.
*/
function getLocalPrettier(directory) {
const targetRequire = createRequire(path["join"](directory, "package.json"));

// Try loading prettier for non-PnP packages and return it if found.
const prettier = tryRequirePrettier(targetRequire);
if (prettier) {
return prettier;
return { api: prettier, require: targetRequire };
}

// Try finding .pnp.[c]js and bail out if we can't find it.
Expand All @@ -271,7 +281,12 @@ function getLocalPrettier(directory) {

// Setup PnP API and retry loading prettier.
targetRequire(pnpJs)["setup"]();
return tryRequirePrettier(targetRequire);
const prettierFromPnp = tryRequirePrettier(targetRequire);
if (!prettierFromPnp) {
return null;
}

return { api: prettierFromPnp, require: targetRequire };
}

/**
Expand All @@ -282,7 +297,7 @@ function getLocalPrettier(directory) {
* @param {!string} directory The directory for which to find the Prettier
* package.
*
* @return {!PrettierAPI | !Error}
* @return {PrettierAPIAndRequire | !Error}
*/
function getPrettierForDirectory(directory) {
if (prettierCache.has(directory)) {
Expand Down Expand Up @@ -318,7 +333,7 @@ function getPrettierForDirectory(directory) {
*
* @param {!string} filepath
*
* @return {!PrettierAPI | !V3CompatAPI} The Prettier package found.
* @return {PrettierAPIAndRequire} The Prettier package found.
*/
function getPrettierForPath(filepath) {
const result = path["isAbsolute"](filepath)
Expand All @@ -328,8 +343,9 @@ function getPrettierForPath(filepath) {
throw result;
}

if (isV3Later(result)) return result;
return new V3CompatAPI(result);
const { api } = result;
if (isV3Later(api)) return result;
return { api: new V3CompatAPI(api), require: result.require };
}

function parseParsers(parsersString) {
Expand Down Expand Up @@ -366,6 +382,7 @@ async function bestParser(prettier, parsers, options, filepath, inferParser) {
["ignorePath"]: findFileInAncestry(path["dirname"](filepath), [
".prettierignore",
]),
["plugins"]: options["plugins"],
});
}

Expand Down Expand Up @@ -433,7 +450,7 @@ global["m"] = function m(baseScript, cacheFilename, inp) {

const editorconfig = packet[1] === "E".charCodeAt(0);
const filepath = packet.toString("utf-8", 2, newlineIndex1);
const prettier = getPrettierForPath(filepath);
const { api: prettier } = getPrettierForPath(filepath);
if (filepath.length > 0) {
await prettier.resolveConfig(filepath, {
editorconfig,
Expand Down Expand Up @@ -482,6 +499,20 @@ global["m"] = function m(baseScript, cacheFilename, inp) {
return result;
}

/**
* Make plugin module paths absolute by resolving with the given
* require function,
*
* @param options the Prettier options, will be modified in place.
* @param {function(string)} req the require function to use for resolving modules.
*/
function postProcessOptions(options, req) {
const plugins = options["plugins"];
if (plugins) {
options["plugins"] = plugins.map((plugin) => req["resolve"](plugin));
}
}

/**
* Handle a request for formatting a file.
*
Expand All @@ -495,7 +526,7 @@ global["m"] = function m(baseScript, cacheFilename, inp) {
const inferParser = config["infer-parser"];

try {
const prettier = getPrettierForPath(filepath);
const { api: prettier, require: req } = getPrettierForPath(filepath);

const timeBeforeFormat = Date.now();

Expand All @@ -507,6 +538,7 @@ global["m"] = function m(baseScript, cacheFilename, inp) {
})
.then((x) => x || {});
}
postProcessOptions(options, req);

const parser = await bestParser(
prettier,
Expand Down Expand Up @@ -632,11 +664,12 @@ global["m"] = function m(baseScript, cacheFilename, inp) {
);
const parsers = parseParsers(parsersString);

const prettier = getPrettierForPath(filepath);
const { api: prettier, require: req } = getPrettierForPath(filepath);

const options = await prettier
.resolveConfig(filepath, { editorconfig })
.then((x) => x || {});
postProcessOptions(options, req);

let optionsFromParser;
if (isV3Later(prettier)) {
Expand Down Expand Up @@ -763,7 +796,7 @@ global["m"] = function m(baseScript, cacheFilename, inp) {
*
* @param {!string} filename Filename to be used to construct the require function.
*
* @return {!Function} the require function.
* @return {!function(string)} the require function.
*/
function createRequire(filename) {
// Added in Node v12.2.0
Expand All @@ -785,7 +818,7 @@ function createRequire(filename) {
*
* @param {!string} filename Filename to be used to construct the require function.
*
* @return {!Function} the require function.
* @return {!function(string)} the require function.
*/
function _createRequire(filename) {
const mod = new nativeModule["Module"](filename, null);
Expand All @@ -800,7 +833,7 @@ function _createRequire(filename) {
// The following is for Prettier version 2 and below.

class V3CompatAPI {
/** @param {!PrettierAPI} prettier */
/** @param {!(PrettierAPI|V3CompatAPI)} prettier */
constructor(prettier) {
this.prettier = prettier;
}
Expand All @@ -825,7 +858,7 @@ class V3CompatAPI {
}

/**
* @param {!PrettierAPI | V3CompatAPI} prettier
* @param {!(PrettierAPI|V3CompatAPI)} prettier
* @return {!boolean}
*/
function isV3Later(prettier) {
Expand Down
1 change: 0 additions & 1 deletion test-stable/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@
"workspaces": [
"*"
],
"packageManager": "yarn@1",
"devDependencies": {
"prettier": "3.0.0"
}
Expand Down
1 change: 0 additions & 1 deletion test-v2/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@
"workspaces": [
"*"
],
"packageManager": "yarn@1",
"devDependencies": {
"prettier": "2.6.2"
}
Expand Down
3 changes: 3 additions & 0 deletions test-v2/ruby-mode/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,5 +4,8 @@
"private": true,
"devDependencies": {
"@prettier/plugin-ruby": "2.1.0"
},
"prettier": {
"trailingComma": "none"
}
}

0 comments on commit 5965223

Please sign in to comment.