Skip to content

Commit

Permalink
initial work in progress
Browse files Browse the repository at this point in the history
  • Loading branch information
connor4312 committed Feb 6, 2021
1 parent a8f3596 commit f5f8168
Show file tree
Hide file tree
Showing 53 changed files with 665 additions and 590 deletions.
2 changes: 1 addition & 1 deletion bin/prettier.js
Expand Up @@ -2,4 +2,4 @@

"use strict";

require("../src/cli").run(process.argv.slice(2));
module.exports = require("../src/cli").run(process.argv.slice(2));
11 changes: 11 additions & 0 deletions scripts/build/config.js
Expand Up @@ -143,6 +143,17 @@ const coreBundles = [
type: "core",
output: "bin-prettier.js",
target: "node",
externals: [
path.resolve("src/index.js"),
path.resolve("src/bin/format-worker.js"),
path.resolve("src/common/third-party.js"),
],
},
{
input: "src/bin/format-worker.js",
type: "core",
output: "format-worker.js",
target: "node",
externals: [
path.resolve("src/index.js"),
path.resolve("src/common/third-party.js"),
Expand Down
16 changes: 8 additions & 8 deletions src/cli/expand-patterns.js
Expand Up @@ -10,12 +10,12 @@ const flat = require("lodash/flatten");
/**
* @param {Context} context
*/
function* expandPatterns(context) {
async function* expandPatterns(context) {
const cwd = process.cwd();
const seen = new Set();
let noResults = true;

for (const pathOrError of expandPatternsInternal(context)) {
for await (const pathOrError of expandPatternsInternal(context)) {
noResults = false;
if (typeof pathOrError !== "string") {
yield pathOrError;
Expand Down Expand Up @@ -44,7 +44,7 @@ function* expandPatterns(context) {
/**
* @param {Context} context
*/
function* expandPatternsInternal(context) {
async function* expandPatternsInternal(context) {
// Ignores files in version control systems directories and `node_modules`
const silentlyIgnoredDirs = {
".git": true,
Expand Down Expand Up @@ -73,7 +73,7 @@ function* expandPatternsInternal(context) {
continue;
}

const stat = statSafeSync(absolutePath);
const stat = await statSafe(absolutePath);
if (stat) {
if (stat.isFile()) {
entries.push({
Expand Down Expand Up @@ -107,7 +107,7 @@ function* expandPatternsInternal(context) {
let result;

try {
result = fastGlob.sync(glob, globOptions);
result = await fastGlob(glob, globOptions);
} catch ({ message }) {
/* istanbul ignore next */
yield { error: `${errorMessages.globError[type]}: ${input}\n${message}` };
Expand Down Expand Up @@ -176,11 +176,11 @@ function sortPaths(paths) {
/**
* Get stats of a given path.
* @param {string} filePath The path to target file.
* @returns {fs.Stats | undefined} The stats.
* @returns {Promise<fs.Stats | undefined>} The stats.
*/
function statSafeSync(filePath) {
async function statSafe(filePath) {
try {
return fs.statSync(filePath);
return fs.promises.stat(filePath);
} catch (error) {
/* istanbul ignore next */
if (error.code !== "ENOENT") {
Expand Down
138 changes: 138 additions & 0 deletions src/cli/format-worker.js
@@ -0,0 +1,138 @@
"use strict";

const { parentPort, workerData } = require('worker_threads');
const { promises: fs } = require("fs");

const chalk = require("chalk");

const { getOptionsForFile } = require("./option");
const isTTY = require("./is-tty");
const { format, handleError, writeOutput } = require('./format');


/** @typedef {import('./context').Context} Context */

class ProxiedContext {
constructor(properties) {
Object.assign(this, properties);

/** @type any */
this.logger = new Proxy({}, {
get(_target, method) {
return (...args) => parentPort.postMessage(['log', method, args]);
}
});
}
}

/** @type Context */
// @ts-ignore
const context = new ProxiedContext(workerData);

/**
* @param {string} filename
* @param {boolean} fileIgnored
*/
async function processFile(filename, fileIgnored) {
const options = {
...getOptionsForFile(context, filename),
filepath: filename,
};

if (isTTY()) {
context.logger.log(filename, { newline: false });
}

let input;
try {
input = await fs.readFile(filename, "utf8");
} catch (error) {
// Add newline to split errors from filename line.
/* istanbul ignore next */
context.logger.log("");

/* istanbul ignore next */
context.logger.error(
`Unable to read file: ${filename}\n${error.message}`
);

// Don't exit the process if one file failed
/* istanbul ignore next */
parentPort.postMessage(['setExitCode', 2]);

/* istanbul ignore next */
return;
}

if (fileIgnored) {
writeOutput(context, { formatted: input }, options);
return;
}

const start = Date.now();

let result;
let output;

try {
result = format(context, input, options);
output = result.formatted;
} catch (error) {
handleError(context, filename, error);
return;
}

const isDifferent = output !== input;

if (isTTY()) {
// Remove previously printed filename to log it with duration.
parentPort.postMessage(['resetTTYLine'])
}

if (context.argv.write) {
// Don't write the file if it won't change in order not to invalidate
// mtime based caches.
if (isDifferent) {
if (!context.argv.check && !context.argv["list-different"]) {
context.logger.log(`${filename} ${Date.now() - start}ms`);
}

try {
await fs.writeFile(filename, output, "utf8");
} catch (error) {
/* istanbul ignore next */
context.logger.error(
`Unable to write file: ${filename}\n${error.message}`
);

// Don't exit the process if one file failed
/* istanbul ignore next */
parentPort.postMessage(['setExitCode', 2]);
}
} else if (!context.argv.check && !context.argv["list-different"]) {
context.logger.log(`${chalk.grey(filename)} ${Date.now() - start}ms`);
}
} else if (context.argv["debug-check"]) {
/* istanbul ignore else */
if (result.filepath) {
context.logger.log(result.filepath);
} else {
parentPort.postMessage(['setExitCode', 2]);
}
} else if (!context.argv.check && !context.argv["list-different"]) {
writeOutput(context, result, options);
}

if (isDifferent) {
if (context.argv.check) {
context.logger.warn(filename);
} else if (context.argv["list-different"]) {
context.logger.log(filename);
}
parentPort.postMessage(['foundUnformatted']);
}
}

parentPort.on('message', ([filename, ignored]) => {
processFile(filename, ignored).then(() => parentPort.postMessage(['doneWork']));
});
134 changes: 30 additions & 104 deletions src/cli/format.js
@@ -1,10 +1,8 @@
"use strict";

const fs = require("fs");
const readline = require("readline");
const path = require("path");

const chalk = require("chalk");
const { Worker } = require("worker_threads");

// eslint-disable-next-line no-restricted-modules
const prettier = require("../index");
Expand Down Expand Up @@ -266,7 +264,9 @@ function formatStdin(context) {
});
}

function formatFiles(context) {
const formatChunkSize = 25;

async function formatFiles(context) {
// The ignorer will be used to filter file paths after the glob is checked,
// before any files are actually written
const ignorer = createIgnorerFromContextOrDie(context);
Expand All @@ -277,7 +277,30 @@ function formatFiles(context) {
context.logger.log("Checking formatting...");
}

for (const pathOrError of expandPatterns(context)) {
const worker = new Worker(path.join(__dirname, "format-worker.js"));

worker.on('message', data => {
switch (data[0]) {
case 'foundUnformatted':
numberOfUnformattedFilesFound++;
break;
case 'log':
context.logger[data[1]](...data[2]);
break;
case 'resetTTYLine':
readline.clearLine(process.stdout, 0);
readline.cursorTo(process.stdout, 0, null);
break;
case 'setExitCode':
process.exitCode = data[1];
break;
case 'doneWork':
// todo
break;
}
});

for await (const pathOrError of expandPatterns(context)) {
if (typeof pathOrError === "object") {
context.logger.error(pathOrError.error);
// Don't exit, but set the exit code to 2
Expand All @@ -303,104 +326,7 @@ function formatFiles(context) {
continue;
}

const options = {
...getOptionsForFile(context, filename),
filepath: filename,
};

if (isTTY()) {
context.logger.log(filename, { newline: false });
}

let input;
try {
input = fs.readFileSync(filename, "utf8");
} catch (error) {
// Add newline to split errors from filename line.
/* istanbul ignore next */
context.logger.log("");

/* istanbul ignore next */
context.logger.error(
`Unable to read file: ${filename}\n${error.message}`
);

// Don't exit the process if one file failed
/* istanbul ignore next */
process.exitCode = 2;

/* istanbul ignore next */
continue;
}

if (fileIgnored) {
writeOutput(context, { formatted: input }, options);
continue;
}

const start = Date.now();

let result;
let output;

try {
result = format(context, input, options);
output = result.formatted;
} catch (error) {
handleError(context, filename, error);
continue;
}

const isDifferent = output !== input;

if (isTTY()) {
// Remove previously printed filename to log it with duration.
readline.clearLine(process.stdout, 0);
readline.cursorTo(process.stdout, 0, null);
}

if (context.argv.write) {
// Don't write the file if it won't change in order not to invalidate
// mtime based caches.
if (isDifferent) {
if (!context.argv.check && !context.argv["list-different"]) {
context.logger.log(`${filename} ${Date.now() - start}ms`);
}

try {
fs.writeFileSync(filename, output, "utf8");
} catch (error) {
/* istanbul ignore next */
context.logger.error(
`Unable to write file: ${filename}\n${error.message}`
);

// Don't exit the process if one file failed
/* istanbul ignore next */
process.exitCode = 2;
}
} else if (!context.argv.check && !context.argv["list-different"]) {
context.logger.log(`${chalk.grey(filename)} ${Date.now() - start}ms`);
}
} else if (context.argv["debug-check"]) {
/* istanbul ignore else */
if (result.filepath) {
context.logger.log(result.filepath);
} else {
process.exitCode = 2;
}
} else if (!context.argv.check && !context.argv["list-different"]) {
writeOutput(context, result, options);
}

if (isDifferent) {
if (context.argv.check) {
context.logger.warn(filename);
} else if (context.argv["list-different"]) {
context.logger.log(filename);
}
numberOfUnformattedFilesFound += 1;
}
worker.postMessage(pathOrError, fileIgnored);
}

// Print check summary based on expected exit code
Expand All @@ -427,4 +353,4 @@ function formatFiles(context) {
}
}

module.exports = { format, formatStdin, formatFiles };
module.exports = { format, formatStdin, formatFiles, writeOutput, handleError };

0 comments on commit f5f8168

Please sign in to comment.