Skip to content

Commit

Permalink
Fix lint errors
Browse files Browse the repository at this point in the history
Signed-off-by: Sora Morimoto <[email protected]>
  • Loading branch information
smorimoto committed Apr 23, 2024
1 parent 50a9f25 commit fa4902a
Show file tree
Hide file tree
Showing 6 changed files with 112 additions and 112 deletions.
82 changes: 41 additions & 41 deletions src/index.ts
Original file line number Diff line number Diff line change
@@ -1,26 +1,26 @@
import * as path from 'path';
import { existsSync } from 'fs';
import * as fs from 'fs/promises';
import { Plugin } from 'vite';
import { execaCommand } from 'execa';
import { npmRunPathEnv } from 'npm-run-path';
import * as stream from 'stream';
import chalk from 'chalk';
import parseCompilerLog from './parseCompilerLog.js';

const logPrefix = chalk.cyan('[@jihchi/vite-plugin-rescript]');
import { existsSync } from "node:fs";
import * as fs from "node:fs/promises";
import * as path from "node:path";
import type { Readable } from "node:stream";
import chalk from "chalk";
import { execaCommand } from "execa";
import { npmRunPathEnv } from "npm-run-path";
import type { Plugin } from "vite";
import parseCompilerLog from "./parseCompilerLog.js";

const logPrefix = chalk.cyan("[@jihchi/vite-plugin-rescript]");

type ReScriptProcess = {
shutdown: () => void;
};

async function launchReScript(
watch: boolean,
silent: boolean
silent: boolean,
): Promise<ReScriptProcess> {
const cmd = watch
? 'rescript build -with-deps -w'
: 'rescript build -with-deps';
? "rescript build -with-deps -w"
: "rescript build -with-deps";

const result = execaCommand(cmd, {
env: npmRunPathEnv(),
Expand All @@ -32,20 +32,20 @@ async function launchReScript(

let compileOnce = (_value: unknown) => {};

function dataListener(chunk: stream.Readable) {
function dataListener(chunk: Readable) {
const output = chunk.toString().trimEnd();
if (!silent) {
// eslint-disable-next-line no-console
console.log(logPrefix, output);
}
if (watch && output.includes('>>>> Finish compiling')) {
if (watch && output.includes(">>>> Finish compiling")) {
compileOnce(true);
}
}

const { stdout, stderr } = result;
stdout && stdout.on('data', dataListener);
stderr && stderr.on('data', dataListener);
stdout?.on("data", dataListener);
stderr?.on("data", dataListener);

if (watch) {
await new Promise((resolve) => {
Expand Down Expand Up @@ -78,31 +78,31 @@ export default function createReScriptPlugin(config?: Config): Plugin {
let childProcessReScript: undefined | ReScriptProcess;

// Retrieve config
const output = config?.loader?.output ?? './lib/es6';
const suffix = config?.loader?.suffix ?? '.bs.js';
const suffixRegex = new RegExp(`${suffix.replace('.', '\\.')}$`);
const output = config?.loader?.output ?? "./lib/es6";
const suffix = config?.loader?.suffix ?? ".bs.js";
const suffixRegex = new RegExp(`${suffix.replace(".", "\\.")}$`);
const silent = config?.silent ?? false;

return {
name: '@jihchi/vite-plugin-rescript',
enforce: 'pre',
name: "@jihchi/vite-plugin-rescript",
enforce: "pre",
async configResolved(resolvedConfig) {
root = resolvedConfig.root;

const { build, command, inlineConfig } = resolvedConfig;

// exclude "vite preview [--mode <mode>]"
const isOnlyDevServerLaunching =
command === 'serve' && !inlineConfig.hasOwnProperty('preview');
command === "serve" && !Object.hasOwn(inlineConfig, "preview");

const isBuildForProduction = command === 'build';
const isBuildForProduction = command === "build";

const needReScript = isOnlyDevServerLaunching || isBuildForProduction;

// The watch command can only be run by one process at the same time.
const isLocked = existsSync(path.resolve('./.bsb.lock'));
const isLocked = existsSync(path.resolve("./.bsb.lock"));

const watch = !isLocked && (command === 'serve' || Boolean(build.watch));
const watch = !isLocked && (command === "serve" || Boolean(build.watch));

if (needReScript) {
childProcessReScript = await launchReScript(watch, silent);
Expand All @@ -113,32 +113,32 @@ export default function createReScriptPlugin(config?: Config): Plugin {
// If the build watcher is enabled (adding watch config would automatically enable it),
// exclude rescript files since recompilation should be based on the generated JS files.
watch: userConfig.build?.watch
? { exclude: ['**/*.res', '**/*.resi'] }
? { exclude: ["**/*.res", "**/*.resi"] }
: null,
},
server: {
watch: {
// Ignore rescript files when watching since they may occasionally trigger hot update
ignored: ['**/*.res', '**/*.resi'],
ignored: ["**/*.res", "**/*.resi"],
},
},
}),
configureServer(server) {
// Manually find and parse log file after server start since
// initial compilation does not trigger handleHotUpdate.
fs.readFile(path.resolve('./lib/bs/.compiler.log'), 'utf8').then(
fs.readFile(path.resolve("./lib/bs/.compiler.log"), "utf8").then(
(data) => {
const log = data.toString();
const err = parseCompilerLog(log);
if (err) server.hot.send({ type: 'error', err });
}
if (err) server.hot.send({ type: "error", err });
},
);
},
// Hook that resolves `.bs.js` imports to their `.res` counterpart
async resolveId(source, importer, options) {
if (source.endsWith('.res')) usingLoader = true;
if (source.endsWith(".res")) usingLoader = true;
if (options.isEntry || !importer) return null;
if (!importer.endsWith('.res')) return null;
if (!importer.endsWith(".res")) return null;
if (!source.endsWith(suffix)) return null;
if (path.isAbsolute(source)) return null;

Expand All @@ -154,7 +154,7 @@ export default function createReScriptPlugin(config?: Config): Plugin {
}

// Only replace the last occurrence
const resFile = source.replace(suffixRegex, '.res');
const resFile = source.replace(suffixRegex, ".res");
const id = path.join(dirname, resFile);

// Enable other plugins to resolve the file
Expand All @@ -174,7 +174,7 @@ export default function createReScriptPlugin(config?: Config): Plugin {
},
// Hook that loads the generated `.bs.js` file from `lib/es6` for ReScript files
async load(id) {
if (!id.endsWith('.res')) return null;
if (!id.endsWith(".res")) return null;

// Find the path to the generated js file
const relativePath = path.relative(root, id);
Expand All @@ -186,7 +186,7 @@ export default function createReScriptPlugin(config?: Config): Plugin {
this.addWatchFile(filePath);

// Read the file content and return the code
return { code: await fs.readFile(filePath, 'utf8') };
return { code: await fs.readFile(filePath, "utf8") };
},
async handleHotUpdate({ file, read, server }) {
// HMR is not automatically triggered when using the ReScript file loader.
Expand All @@ -195,15 +195,15 @@ export default function createReScriptPlugin(config?: Config): Plugin {
if (usingLoader && file.endsWith(suffix)) {
const lib = path.resolve(output);
const relativePath = path.relative(lib, file);
if (relativePath.startsWith('..')) return;
const resFile = relativePath.replace(suffixRegex, '.res');
if (relativePath.startsWith("..")) return;
const resFile = relativePath.replace(suffixRegex, ".res");
const id = path.join(root, resFile);
const moduleNode = server.moduleGraph.getModuleById(id);
if (moduleNode) return [moduleNode];
} else if (file.endsWith('.compiler.log')) {
} else if (file.endsWith(".compiler.log")) {
const log = await read();
const err = parseCompilerLog(log);
if (err) server.hot.send({ type: 'error', err });
if (err) server.hot.send({ type: "error", err });
}

return;
Expand Down
30 changes: 15 additions & 15 deletions src/parseCompilerLog.ts
Original file line number Diff line number Diff line change
@@ -1,21 +1,21 @@
import { ErrorPayload } from 'vite';
import { EOL } from 'os';
import { EOL } from "node:os";
import type { ErrorPayload } from "vite";

const ruler = '—'.repeat(80);
const ruler = "—".repeat(80);

// https://github.com/rescript-lang/rescript-vscode/blob/7ab2d231f91fee2f93cbf6cae1b38f94c06a58c1/server/src/utils.ts#L288
const fileAndRangeRegex = /(.+):(\d+):(\d+)(-(\d+)(:(\d+))?)?$/;

// https://github.com/rescript-lang/rescript-vscode/blob/7ab2d231f91fee2f93cbf6cae1b38f94c06a58c1/server/src/utils.ts#L433
const codeRegex = /^ +([0-9]+| +|\.) (│|┆)/;
const codeRegex = /^ {2,}([0-9]+| +|\.) (│|┆)/;

// Compiler can treat warnings as hard errors based on `warnings` object in bsconfig.json
const warningErrorRegex = /Warning number \d+ \(configured as error\)/;

// Returns true if the line indicates the start of an error block
function isErrorLine(line: string | undefined) {
if (line?.startsWith(" We've found a bug for you!")) return true;
if (line?.startsWith(' Syntax error!')) return true;
if (line?.startsWith(" Syntax error!")) return true;
if (line && warningErrorRegex.test(line)) return true;
return false;
}
Expand All @@ -26,13 +26,13 @@ function isErrorLine(line: string | undefined) {
* @returns Error object to send to the client or null.
*/
export default function parseCompilerLog(
log: string
): ErrorPayload['err'] | null {
log: string,
): ErrorPayload["err"] | null {
// Split by line endings and remove empty lines
const lines = log.split(EOL).filter(Boolean);

// Optimization; only parse log when compiler is done
if (lines[lines.length - 1]?.startsWith('#Done(')) {
if (lines[lines.length - 1]?.startsWith("#Done(")) {
let foundError = false;
let path: string | undefined;
let startLine = 0;
Expand Down Expand Up @@ -68,10 +68,10 @@ export default function parseCompilerLog(
i += 1;
} else if (!foundError) {
// Only run below checks once an error has been found
} else if (line?.startsWith(' Warning number ')) {
} else if (line?.startsWith(" Warning number ")) {
// Reached the end of the error
break;
} else if (line?.startsWith('#Done(')) {
} else if (line?.startsWith("#Done(")) {
// Reached the end of the log file
break;
} else {
Expand All @@ -81,7 +81,7 @@ export default function parseCompilerLog(
// Replace strange vertical bars with regular ones in order to match
// the code frame regex defined in the vite overlay file:
// https://github.com/vitejs/vite/blob/96591bf9989529de839ba89958755eafe4c445ae/packages/vite/src/client/overlay.ts#L116
let codeFrameLine = line?.replace('┆', '|').replace('│', '|');
let codeFrameLine = line?.replace("┆", "|").replace("│", "|");

// Since the red color indicator is lost when parsing the log file,
// this adds a pointer (`>`) to the line where the error starts.
Expand All @@ -92,7 +92,7 @@ export default function parseCompilerLog(
if (codeFrameLine) {
frame.push(codeFrameLine);
}
} else if (line?.startsWith(' ')) {
} else if (line?.startsWith(" ")) {
// It has to be a message by now
messages.push(line.trim());
}
Expand All @@ -101,9 +101,9 @@ export default function parseCompilerLog(

if (foundError) {
return {
message: messages.join('\n'),
frame: `${frame.join('\n')}`,
stack: '',
message: messages.join("\n"),
frame: `${frame.join("\n")}`,
stack: "",
id: path,
};
}
Expand Down
18 changes: 9 additions & 9 deletions test/index.test.ts
Original file line number Diff line number Diff line change
@@ -1,20 +1,20 @@
import { describe, expect, it } from 'vitest';
import Plugin from '../src/index.js';
import { describe, expect, it } from "vitest";
import Plugin from "../src/index.js";

describe('@jihchi/vite-plugin-rescript', () => {
it('works', () => {
describe("@jihchi/vite-plugin-rescript", () => {
it("works", () => {
const actual = Plugin();
expect(actual).toHaveProperty('name', '@jihchi/vite-plugin-rescript');
expect(actual).toHaveProperty('configResolved');
expect(actual).toHaveProperty("name", "@jihchi/vite-plugin-rescript");
expect(actual).toHaveProperty("configResolved");
expect(actual.configResolved).toBeInstanceOf(Function);
});

it('invokes closeBundle hook without crashing', async () => {
it("invokes closeBundle hook without crashing", async () => {
const actual = Plugin();
expect(actual).toHaveProperty('closeBundle');
expect(actual).toHaveProperty("closeBundle");
await expect(
// @ts-expect-error
actual.closeBundle()
actual.closeBundle(),
).resolves.toEqual(undefined);
});
});
Loading

0 comments on commit fa4902a

Please sign in to comment.