Skip to content

Commit 4f4f442

Browse files
committed
Add Chrome extension to use Prettier for formatting on LeetCode
1 parent 92d04ee commit 4f4f442

File tree

11 files changed

+269
-35
lines changed

11 files changed

+269
-35
lines changed
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
dist/
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
# @code-chronicles/leetcode-prettier-extension
2+
3+
Chrome extension to replace LeetCode's code formatter with Prettier.
4+
5+
To use:
6+
7+
1. **Build the extension:**
8+
9+
```sh
10+
# It's easiest to do this from the package's directory:
11+
cd workspaces/leetcode-prettier-extension
12+
13+
# Install dependencies, if you haven't already:
14+
yarn
15+
16+
# Build the extension:
17+
yarn build
18+
```
19+
20+
2. **Load the extension into Chrome.** The built extension will be in a directory named `dist`. You will have to load it as an "unpacked extension", using Developer mode. See [the official tutorial](https://developer.chrome.com/docs/extensions/get-started/tutorial/hello-world#load-unpacked).
21+
22+
## Development
23+
24+
Like the rest of the [Code Chronicles Leetcode ecosystem](../../), this package is structured as a Node module, using [Yarn](https://yarnpkg.com/) as the package manager.
25+
26+
You can install dependencies by running `yarn`, either in this package's directory, or in the repository root. The usual `yarn format`, `yarn lint`, and `yarn typecheck` scripts are available to aid in development and occasionally to annoy. Read more in the repository's general [development guide](../../DEVELOPMENT.md).
27+
28+
This package supports an additional `package.json` script:
29+
30+
### `yarn build`
31+
32+
Builds (an unpacked version of) the extension, in a `dist` directory within the package's workspace.
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
import config from "@code-chronicles/eslint-config";
2+
3+
export default [...config, { ignores: ["dist/"] }];
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
{
2+
"name": "@code-chronicles/leetcode-prettier-extension",
3+
"description": "TODO: add a nice description",
4+
"version": "0.0.1",
5+
"license": "MIT",
6+
"private": false,
7+
"repository": {
8+
"type": "git",
9+
"url": "https://github.com/code-chronicles-code/leetcode-curriculum.git",
10+
"directory": "workspaces/leetcode-prettier-extension"
11+
},
12+
"author": {
13+
"name": "Miorel-Lucian Palii",
14+
"url": "https://github.com/miorel"
15+
},
16+
"type": "module",
17+
"exports": "./src/extension/main.ts",
18+
"scripts": {
19+
"build": "tsx src/scripts/writeManifest.ts && cross-env NODE_OPTIONS=\"--import tsx\" webpack",
20+
"format": "prettier --color --write .",
21+
"lint": "eslint --color --max-warnings=0 .",
22+
"typecheck": "tsc --pretty --project ."
23+
},
24+
"dependencies": {
25+
"prettier": "3.3.3"
26+
},
27+
"devDependencies": {
28+
"@code-chronicles/eslint-config": "workspace:*",
29+
"@code-chronicles/util": "workspace:*",
30+
"@types/node": "22.7.5",
31+
"cross-env": "7.0.3",
32+
"eslint": "9.12.0",
33+
"fork-ts-checker-webpack-plugin": "9.0.2",
34+
"ts-loader": "9.5.1",
35+
"tsx": "4.19.1",
36+
"type-fest": "4.26.1",
37+
"typescript": "5.6.3",
38+
"webpack": "5.95.0",
39+
"webpack-cli": "5.1.4"
40+
}
41+
}
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
import { format } from "prettier/standalone";
2+
import estreePlugin from "prettier/plugins/estree";
3+
import tsPlugin from "prettier/plugins/typescript";
4+
5+
function main(): void {
6+
// TODO: improve types
7+
let monaco: any = undefined;
8+
9+
Object.defineProperty(globalThis, "monaco", {
10+
get() {
11+
return monaco;
12+
},
13+
14+
set(newMonaco) {
15+
monaco = newMonaco;
16+
monaco.editor.onDidCreateEditor((ed: any) => {
17+
const { getAction } = ed;
18+
ed.getAction = function (this: unknown) {
19+
const action = getAction.apply(this, arguments);
20+
action.run = function () {
21+
format(ed.getModel().getValue(), {
22+
parser: "typescript",
23+
plugins: [estreePlugin, tsPlugin],
24+
}).then((text) => ed.getModel().setValue(text));
25+
};
26+
return action;
27+
};
28+
});
29+
},
30+
});
31+
}
32+
33+
main();
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
export const DIST_DIRECTORY = "dist";
2+
3+
export const SCRIPT_FILENAME = "main.js";
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
import type { JsonObject } from "type-fest";
2+
3+
import { SCRIPT_FILENAME } from "./constants.ts";
4+
import packageJson from "../../package.json" with { type: "json" };
5+
6+
export function getManifest(): JsonObject {
7+
return {
8+
name: "LeetCode Prettier",
9+
description: packageJson.description,
10+
version: packageJson.version,
11+
12+
// eslint-disable-next-line camelcase
13+
manifest_version: 3,
14+
// eslint-disable-next-line camelcase
15+
content_scripts: [
16+
{
17+
matches: ["https://*.leetcode.com/*"],
18+
js: [SCRIPT_FILENAME],
19+
// eslint-disable-next-line camelcase
20+
run_at: "document_start",
21+
world: "MAIN",
22+
},
23+
],
24+
};
25+
}
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
import { mkdir, writeFile } from "node:fs/promises";
2+
import path from "node:path";
3+
4+
import { jsonStringifyPrettyInDev } from "@code-chronicles/util/jsonStringifyPrettyInDev";
5+
6+
import { DIST_DIRECTORY } from "./constants.ts";
7+
import { getManifest } from "./getManifest.ts";
8+
9+
async function main(): Promise<void> {
10+
await mkdir(DIST_DIRECTORY, { recursive: true });
11+
12+
const manifest = getManifest();
13+
14+
await writeFile(
15+
path.join(DIST_DIRECTORY, "manifest.json"),
16+
jsonStringifyPrettyInDev(manifest),
17+
{ encoding: "utf8" },
18+
);
19+
}
20+
21+
main().catch((err) => {
22+
console.error(err);
23+
process.exitCode = 1;
24+
});
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
{
2+
"extends": "../../tsconfig-base.json"
3+
}
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
import path from "node:path";
2+
3+
import type { Configuration } from "webpack";
4+
import ForkTsCheckerWebpackPlugin from "fork-ts-checker-webpack-plugin";
5+
6+
import packageJson from "./package.json" with { type: "json" };
7+
8+
const config: Configuration = {
9+
target: "web",
10+
entry: path.resolve(__dirname, packageJson.exports),
11+
output: {
12+
filename: "main.js",
13+
path: path.resolve(__dirname, "dist"),
14+
},
15+
16+
module: {
17+
rules: [
18+
{
19+
test: /\.tsx?$/,
20+
use: [
21+
{
22+
loader: "ts-loader",
23+
options: {
24+
transpileOnly: true,
25+
},
26+
},
27+
],
28+
exclude: /\bnode_modules\b/,
29+
},
30+
],
31+
},
32+
33+
resolve: {
34+
conditionNames: ["import"],
35+
},
36+
37+
plugins: [new ForkTsCheckerWebpackPlugin()],
38+
};
39+
40+
export default config;

0 commit comments

Comments
 (0)