Родитель
f351c7f968
Коммит
c7d50c8e29
|
@ -0,0 +1,22 @@
|
|||
{
|
||||
// Use IntelliSense to learn about possible attributes.
|
||||
// Hover to view descriptions of existing attributes.
|
||||
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
|
||||
"version": "0.2.0",
|
||||
"configurations": [
|
||||
{
|
||||
"type": "pwa-node",
|
||||
"request": "launch",
|
||||
"name": "Launch Program",
|
||||
"skipFiles": [
|
||||
"<node_internals>/**"
|
||||
],
|
||||
"program": "${workspaceFolder}\\src\\index.ts",
|
||||
"args": ["src/**/*.ts"],
|
||||
"preLaunchTask": "tsc: build - tsconfig.json",
|
||||
"outFiles": [
|
||||
"${workspaceFolder}/dist/**/*.js"
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
|
@ -8,7 +8,9 @@ import * as cluster from 'cluster';
|
|||
import * as commander from 'commander';
|
||||
import { cpus } from 'os';
|
||||
import * as prettier from 'prettier';
|
||||
import { version } from '../package.json';
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-var-requires
|
||||
const { version } = require('../package.json');
|
||||
|
||||
function startMaster() {
|
||||
const program = commander
|
||||
|
|
|
@ -39,7 +39,7 @@ export function spawnWorkers(options: IOptions) {
|
|||
() => {
|
||||
progress.complete();
|
||||
|
||||
if (progress.reformatted && options.check) {
|
||||
if ((progress.reformatted && options.check) || progress.failed) {
|
||||
process.exit(1);
|
||||
} else {
|
||||
process.exit(0);
|
||||
|
|
|
@ -12,6 +12,7 @@ import { IFormatResults } from './protocol';
|
|||
export class ProgressReporter {
|
||||
public total = 0;
|
||||
public reformatted = 0;
|
||||
public failed = 0;
|
||||
private spinner?: ora.Ora;
|
||||
|
||||
constructor(quiet: boolean, private readonly check: boolean) {
|
||||
|
@ -26,6 +27,7 @@ export class ProgressReporter {
|
|||
public update(results: IFormatResults) {
|
||||
this.total += results.files;
|
||||
this.reformatted += results.formatted.length;
|
||||
this.failed += results.failed.length;
|
||||
|
||||
if (results.formatted.length) {
|
||||
if (this.spinner) {
|
||||
|
|
|
@ -46,6 +46,7 @@ export type MasterMessage = IInitializationMessage | IFilesMessage;
|
|||
*/
|
||||
export interface IFormatResults {
|
||||
files: number;
|
||||
failed: IDiscoveredFile[];
|
||||
formatted: IDiscoveredFile[];
|
||||
}
|
||||
|
||||
|
|
|
@ -3,8 +3,8 @@
|
|||
*--------------------------------------------------------*/
|
||||
|
||||
import * as cluster from 'cluster';
|
||||
import { fromEvent, Observable } from 'rxjs';
|
||||
import { filter, map, take, tap } from 'rxjs/operators';
|
||||
import { BehaviorSubject, fromEvent, Observable } from 'rxjs';
|
||||
import { filter, map, switchMap, take, tap } from 'rxjs/operators';
|
||||
import {
|
||||
IFormatResults,
|
||||
IInitializationMessage,
|
||||
|
@ -14,11 +14,17 @@ import {
|
|||
WorkerMode,
|
||||
} from './protocol';
|
||||
|
||||
export class WorkerExitedError extends Error {
|
||||
constructor(codeOrSignal: number | string) {
|
||||
super(`Worker exited with unexpected ${codeOrSignal} code`);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Pool of workers.
|
||||
*/
|
||||
export class WorkerPool {
|
||||
private readonly workers: Array<{ worker: cluster.Worker; active: number }> = [];
|
||||
private readonly workers: Array<{ worker: Observable<cluster.Worker>; active: number }> = [];
|
||||
private workIdCounter = 0;
|
||||
|
||||
/**
|
||||
|
@ -41,10 +47,13 @@ export class WorkerPool {
|
|||
const target = this.workers[0];
|
||||
const id = this.workIdCounter++;
|
||||
target.active++;
|
||||
target.worker.send({ type: MessageType.WorkerFiles, files, id });
|
||||
this.sortWorkers();
|
||||
|
||||
return fromEvent<[WorkerMessage]>(target.worker, 'message').pipe(
|
||||
return target.worker.pipe(
|
||||
switchMap((worker) => {
|
||||
worker.send({ type: MessageType.WorkerFiles, files, id });
|
||||
return fromEvent<[WorkerMessage]>(worker, 'message');
|
||||
}),
|
||||
map(([m]) => m),
|
||||
filter((m) => m.id === id),
|
||||
take(1),
|
||||
|
@ -60,9 +69,14 @@ export class WorkerPool {
|
|||
}
|
||||
|
||||
private spawnWorker() {
|
||||
const worker = { worker: cluster.fork(), active: 0 };
|
||||
this.workers.unshift(worker);
|
||||
worker.worker.send({
|
||||
const worker = cluster.fork();
|
||||
const subject = new BehaviorSubject(worker);
|
||||
this.workers.unshift({ worker: subject, active: 0 });
|
||||
|
||||
worker.on('exit', (code, signal) => subject.error(new WorkerExitedError(code ?? signal)));
|
||||
worker.on('error', (err) => subject.error(err));
|
||||
|
||||
worker.send({
|
||||
mode: this.options.check
|
||||
? WorkerMode.Assert
|
||||
: this.options.write
|
||||
|
|
|
@ -6,7 +6,7 @@ import { readFile, writeFile } from 'fs';
|
|||
import * as prettier from 'prettier';
|
||||
import { combineLatest, Observable, of, Subject } from 'rxjs';
|
||||
import { last, mergeMap } from 'rxjs/operators';
|
||||
import { promisify } from 'util';
|
||||
import { inspect, promisify } from 'util';
|
||||
import {
|
||||
IFilesMessage,
|
||||
IFormattedMessage,
|
||||
|
@ -32,6 +32,7 @@ function runFormatting(
|
|||
const output: IFormattedMessage = {
|
||||
files: files.files.length,
|
||||
formatted: [],
|
||||
failed: [],
|
||||
id: files.id,
|
||||
type: MessageType.Formatted,
|
||||
};
|
||||
|
@ -39,10 +40,17 @@ function runFormatting(
|
|||
return of(...files.files).pipe(
|
||||
mergeMap(async (file) => {
|
||||
const contents = await readFileAsync(file.path, 'utf-8');
|
||||
const formatted = prettier.format(contents, {
|
||||
...(await prettier.resolveConfig(file.path)),
|
||||
filepath: file.path,
|
||||
});
|
||||
let formatted: string;
|
||||
try {
|
||||
formatted = prettier.format(contents, {
|
||||
...(await prettier.resolveConfig(file.path)),
|
||||
filepath: file.path,
|
||||
});
|
||||
} catch (e) {
|
||||
process.stderr.write('\r\n' + inspect(e) + '\r\n');
|
||||
output.failed.push(file);
|
||||
return output;
|
||||
}
|
||||
|
||||
if (formatted === contents) {
|
||||
return output;
|
||||
|
@ -76,7 +84,7 @@ export function startWorker() {
|
|||
}
|
||||
});
|
||||
|
||||
combineLatest(settings, files)
|
||||
combineLatest([settings, files])
|
||||
.pipe(mergeMap(([s, f]) => runFormatting(s, f)))
|
||||
.subscribe(
|
||||
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
||||
|
|
|
@ -14,5 +14,8 @@
|
|||
"lib": ["es6", "es7"],
|
||||
"outDir": "dist",
|
||||
"types": ["node"]
|
||||
}
|
||||
},
|
||||
"include": [
|
||||
"src"
|
||||
]
|
||||
}
|
||||
|
|
Загрузка…
Ссылка в новой задаче