Skip to content

Commit 9ed8b2b

Browse files
committed
Add oxlint to the repo
1 parent e755ced commit 9ed8b2b

9 files changed

Lines changed: 384 additions & 136 deletions

File tree

.github/workflows/ci.yml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,9 @@ jobs:
4444
- name: Run format:check
4545
run: yarn format:check
4646

47+
- name: Run lint and typecheck
48+
run: yarn lint
49+
4750
ci-ok:
4851
name: CI OK
4952
runs-on: ubuntu-latest

.oxlintrc.json

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
{
2+
"$schema": "./node_modules/oxlint/configuration_schema.json",
3+
"plugins": ["typescript", "unicorn", "oxc", "vitest", "import", "promise"],
4+
"categories": {
5+
"correctness": "error",
6+
"suspicious": "error",
7+
"perf": "error",
8+
"pedantic": "error"
9+
},
10+
"options": {
11+
"typeAware": true,
12+
"typeCheck": true
13+
},
14+
"rules": {
15+
"func-style": "off",
16+
"max-lines": "off",
17+
"max-lines-per-function": "off",
18+
"no-implicit-coercion": "off",
19+
"no-magic-numbers": "off",
20+
"no-ternary": "off",
21+
"no-warning-comments": "off",
22+
"typescript/array-type": ["error", { "default": "generic", "readonly": "generic" }],
23+
"typescript/consistent-type-imports": "error",
24+
"typescript/no-unsafe-type-assertion": "off",
25+
"typescript/return-await": "off",
26+
"typescript/strict-boolean-expressions": "off"
27+
},
28+
"env": {
29+
"builtin": true
30+
}
31+
}

get-changed-packages.ts

Lines changed: 72 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -3,14 +3,19 @@ import nodePath from "path";
33
import assembleReleasePlan from "@changesets/assemble-release-plan";
44
import { parse as parseConfig } from "@changesets/config";
55
import parseChangeset from "@changesets/parse";
6-
import { PreState, NewChangeset } from "@changesets/types";
7-
import { Packages, Tool } from "@manypkg/get-packages";
6+
import type {
7+
NewChangeset,
8+
PreState,
9+
WrittenConfig,
10+
PackageJSON as ChangesetPackageJSON,
11+
} from "@changesets/types";
12+
import type { Packages, Tool } from "@manypkg/get-packages";
813
import { safeLoad } from "js-yaml";
914
import micromatch from "micromatch";
1015
import fetch from "node-fetch";
11-
import { ProbotOctokit } from "probot";
16+
import type { ProbotOctokit } from "probot";
1217

13-
export let getChangedPackages = async ({
18+
export const getChangedPackages = async ({
1419
owner,
1520
repo,
1621
ref,
@@ -21,12 +26,12 @@ export let getChangedPackages = async ({
2126
owner: string;
2227
repo: string;
2328
ref: string;
24-
changedFiles: string[] | Promise<string[]>;
29+
changedFiles: Array<string> | Promise<Array<string>>;
2530
octokit: InstanceType<typeof ProbotOctokit>;
2631
installationToken: string;
2732
}) => {
2833
let hasErrored = false;
29-
let encodedCredentials = Buffer.from(`x-access-token:${installationToken}`).toString("base64");
34+
const encodedCredentials = Buffer.from(`x-access-token:${installationToken}`).toString("base64");
3035

3136
function fetchFile(path: string) {
3237
return fetch(`https://raw.githubusercontent.com/${owner}/${repo}/${ref}/${path}`, {
@@ -36,54 +41,63 @@ export let getChangedPackages = async ({
3641
});
3742
}
3843

39-
function fetchJsonFile(path: string) {
40-
return fetchFile(path)
41-
.then((x) => x.json())
42-
.catch((err) => {
43-
hasErrored = true;
44-
console.error(err);
45-
return {};
46-
});
44+
async function fetchJsonFile<T>(path: string): Promise<T> {
45+
try {
46+
const x = await fetchFile(path);
47+
return x.json() as Promise<T>;
48+
} catch (error) {
49+
hasErrored = true;
50+
console.error(error);
51+
return {} as Promise<T>;
52+
}
53+
}
54+
55+
async function fetchTextFile(path: string): Promise<string> {
56+
try {
57+
const x = await fetchFile(path);
58+
return x.text();
59+
} catch (err) {
60+
hasErrored = true;
61+
console.error(err);
62+
return "";
63+
}
4764
}
4865

49-
function fetchTextFile(path: string) {
50-
return fetchFile(path)
51-
.then((x) => x.text())
52-
.catch((err) => {
53-
hasErrored = true;
54-
console.error(err);
55-
return "";
56-
});
66+
interface PackageJSON extends ChangesetPackageJSON {
67+
workspaces?: Array<string> | { packages: Array<string> };
68+
bolt?: { workspaces: Array<string> };
5769
}
5870

59-
async function getPackage(pkgPath: string) {
60-
let jsonContent = await fetchJsonFile(pkgPath + "/package.json");
71+
async function getPackage(pkgPath: string): Promise<{ dir: string; packageJson: PackageJSON }> {
72+
const jsonContent = await fetchJsonFile(pkgPath + "/package.json");
6173
return {
62-
packageJson: jsonContent,
6374
dir: pkgPath,
75+
packageJson: jsonContent as PackageJSON,
6476
};
6577
}
6678

67-
let rootPackageJsonContentsPromise = fetchJsonFile("package.json");
68-
let configPromise: Promise<any> = fetchJsonFile(".changeset/config.json");
79+
const rootPackageJsonContentsPromise: Promise<PackageJSON> = fetchJsonFile("package.json");
80+
const rawConfigPromise: Promise<WrittenConfig> = fetchJsonFile(".changeset/config.json");
6981

70-
let tree = await octokit.git.getTree({
82+
const tree = await octokit.git.getTree({
7183
owner,
7284
repo,
7385
recursive: "1",
7486
tree_sha: ref,
7587
});
7688

7789
let preStatePromise: Promise<PreState> | undefined;
78-
let changesetPromises: Promise<NewChangeset>[] = [];
79-
let potentialWorkspaceDirectories: string[] = [];
90+
const changesetPromises: Array<Promise<NewChangeset>> = [];
91+
const potentialWorkspaceDirectories: Array<string> = [];
8092
let isPnpm = false;
81-
let changedFiles = await changedFilesPromise;
93+
const changedFiles = await changedFilesPromise;
8294

83-
for (let item of tree.data.tree) {
84-
if (!item.path) continue;
95+
for (const item of tree.data.tree) {
96+
if (!item.path) {
97+
continue;
98+
}
8599
if (item.path.endsWith("/package.json")) {
86-
let dirPath = nodePath.dirname(item.path);
100+
const dirPath = nodePath.dirname(item.path);
87101
potentialWorkspaceDirectories.push(dirPath);
88102
} else if (item.path === "pnpm-workspace.yaml") {
89103
isPnpm = true;
@@ -95,56 +109,62 @@ export let getChangedPackages = async ({
95109
item.path.endsWith(".md") &&
96110
changedFiles.includes(item.path)
97111
) {
98-
let res = /\.changeset\/([^\.]+)\.md/.exec(item.path);
112+
const res = /\.changeset\/([^.]+)\.md/.exec(item.path);
99113
if (!res) {
100114
throw new Error("could not get name from changeset filename");
101115
}
102-
let id = res[1];
116+
const id = res[1];
117+
103118
changesetPromises.push(
104-
fetchTextFile(item.path).then((text) => {
105-
return { ...parseChangeset(text), id };
106-
}),
119+
fetchTextFile(item.path).then((text) => ({ ...parseChangeset(text), id })),
107120
);
108121
}
109122
}
110123
let tool:
111124
| {
112125
tool: Tool;
113-
globs: string[];
126+
globs: Array<string>;
114127
}
115128
| undefined;
116129

117130
if (isPnpm) {
131+
interface PnpmWorkspace {
132+
packages: Array<string>;
133+
}
134+
135+
const pnpmWorkspaceContent = await fetchTextFile("pnpm-workspace.yaml");
136+
const pnpmWorkspace = safeLoad(pnpmWorkspaceContent) as PnpmWorkspace;
137+
118138
tool = {
139+
globs: pnpmWorkspace.packages,
119140
tool: "pnpm",
120-
globs: safeLoad(await fetchTextFile("pnpm-workspace.yaml")).packages,
121141
};
122142
} else {
123-
let rootPackageJsonContent = await rootPackageJsonContentsPromise;
143+
const rootPackageJsonContent = await rootPackageJsonContentsPromise;
124144

125145
if (rootPackageJsonContent.workspaces) {
126-
if (!Array.isArray(rootPackageJsonContent.workspaces)) {
146+
if (Array.isArray(rootPackageJsonContent.workspaces)) {
127147
tool = {
148+
globs: rootPackageJsonContent.workspaces,
128149
tool: "yarn",
129-
globs: rootPackageJsonContent.workspaces.packages,
130150
};
131151
} else {
132152
tool = {
153+
globs: rootPackageJsonContent.workspaces.packages,
133154
tool: "yarn",
134-
globs: rootPackageJsonContent.workspaces,
135155
};
136156
}
137157
} else if (rootPackageJsonContent.bolt && rootPackageJsonContent.bolt.workspaces) {
138158
tool = {
139-
tool: "bolt",
140159
globs: rootPackageJsonContent.bolt.workspaces,
160+
tool: "bolt",
141161
};
142162
}
143163
}
144164

145-
let rootPackageJsonContent = await rootPackageJsonContentsPromise;
165+
const rootPackageJsonContent = await rootPackageJsonContentsPromise;
146166

147-
let packages: Packages = {
167+
const packages: Packages = {
148168
root: {
149169
dir: "/",
150170
packageJson: rootPackageJsonContent,
@@ -157,7 +177,7 @@ export let getChangedPackages = async ({
157177
if (!Array.isArray(tool.globs) || !tool.globs.every((x) => typeof x === "string")) {
158178
throw new Error("globs are not valid: " + JSON.stringify(tool.globs));
159179
}
160-
let matches = micromatch(potentialWorkspaceDirectories, tool.globs);
180+
const matches = micromatch(potentialWorkspaceDirectories, tool.globs);
161181

162182
packages.packages = await Promise.all(matches.map((dir) => getPackage(dir)));
163183
} else {
@@ -167,10 +187,12 @@ export let getChangedPackages = async ({
167187
throw new Error("an error occurred when fetching files");
168188
}
169189

190+
const rawConfig = await rawConfigPromise;
191+
170192
const releasePlan = assembleReleasePlan(
171193
await Promise.all(changesetPromises),
172194
packages,
173-
await configPromise.then((rawConfig) => parseConfig(rawConfig, packages)),
195+
parseConfig(rawConfig, packages),
174196
await preStatePromise,
175197
);
176198

index.ts

Lines changed: 11 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,10 @@
11
import { ValidationError } from "@changesets/errors";
2-
import { ReleasePlan, ComprehensiveRelease, VersionType } from "@changesets/types";
3-
import { EmitterWebhookEvent } from "@octokit/webhooks";
2+
import type { ReleasePlan, ComprehensiveRelease, VersionType } from "@changesets/types";
3+
import type { EmitterWebhookEvent } from "@octokit/webhooks";
44
import { captureException } from "@sentry/node";
5-
// @ts-ignore
65
import humanId from "human-id";
76
import markdownTable from "markdown-table";
8-
import { Probot, Context } from "probot";
7+
import type { Probot, Context } from "probot";
98

109
import { getChangedPackages } from "./get-changed-packages";
1110

@@ -31,15 +30,15 @@ const getReleasePlanMessage = (releasePlan: ReleasePlan | null) => {
3130
]);
3231

3332
return `<details><summary>This PR includes ${
34-
releasePlan.changesets.length
33+
releasePlan.changesets.length > 0
3534
? `changesets to release ${
3635
publishableReleases.length === 1 ? "1 package" : `${publishableReleases.length} packages`
3736
}`
3837
: "no changesets"
3938
}</summary>
4039
4140
${
42-
publishableReleases.length
41+
publishableReleases.length > 0
4342
? table
4443
: "When changesets are added to this PR, you'll see the packages that this PR includes changesets for and the associated semver types"
4544
}
@@ -83,7 +82,7 @@ Not sure what this means? [Click here to learn what changesets are](https://git
8382
8483
`;
8584

86-
const getNewChangesetTemplate = (changedPackages: string[], title: string) =>
85+
const getNewChangesetTemplate = (changedPackages: Array<string>, title: string) =>
8786
encodeURIComponent(`---
8887
${changedPackages.map((x) => `"${x}": patch`).join("\n")}
8988
---
@@ -120,8 +119,8 @@ const hasChangesetBeenAdded = (
120119
),
121120
);
122121

123-
export default (app: Probot) => {
124-
app.auth();
122+
export default (app: Probot): void => {
123+
void app.auth();
125124
app.log("Yay, the app was loaded!");
126125

127126
app.on(["pull_request.opened", "pull_request.synchronize"], async (context) => {
@@ -152,13 +151,13 @@ export default (app: Probot) => {
152151
// deploying this doesn't cost money
153152
context.payload.action === "synchronize"
154153
? getCommentId(context, { ...repo, issue_number: number })
155-
: undefined,
154+
: Promise.resolve(null),
156155
hasChangesetBeenAdded(changedFilesPromise),
157156
getChangedPackages({
158157
repo: context.payload.pull_request.head.repo.name,
159158
owner: context.payload.pull_request.head.repo.owner.login,
160159
ref: context.payload.pull_request.head.ref,
161-
changedFiles: changedFilesPromise.then((x) => x.data.map((x) => x.filename)),
160+
changedFiles: changedFilesPromise.then((x) => x.data.map(({ filename }) => filename)),
162161
octokit: context.octokit,
163162
installationToken: (
164163
await (await app.auth()).apps.createInstallationAccessToken({
@@ -196,7 +195,7 @@ export default (app: Probot) => {
196195
errFromFetchingChangedFiles,
197196
};
198197

199-
if (commentId != null) {
198+
if (commentId !== null) {
200199
return context.octokit.issues.updateComment({
201200
...prComment,
202201
comment_id: commentId,

modules.d.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
declare module "human-id" {
2+
export default function humanId(options: { separator: string; capitalize: boolean }): string;
3+
}

package.json

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@
88
"scripts": {
99
"format": "oxfmt",
1010
"format:check": "oxfmt --check",
11+
"lint": "oxlint",
12+
"lint:fix": "oxlint --fix",
1113
"test": "vitest"
1214
},
1315
"dependencies": {
@@ -32,11 +34,13 @@
3234
"probot": "^12.2.4",
3335
"react": "^18.2.0",
3436
"react-dom": "^18.2.0",
35-
"typescript": "^4.7.4"
37+
"typescript": "^6.0.2"
3638
},
3739
"devDependencies": {
3840
"msw": "^2.12.14",
3941
"oxfmt": "^0.42.0",
42+
"oxlint": "^1.58.0",
43+
"oxlint-tsgolint": "^0.19.0",
4044
"vite": "^8.0.3",
4145
"vitest": "^4.1.2"
4246
},

pages/api/webhook.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ import { createNodeMiddleware, createProbot } from "probot";
22

33
import app from "../../index";
44

5-
// requires:
5+
// Requires:
66
// - APP_ID
77
// - PRIVATE_KEY
88
// - WEBHOOK_SECRET

0 commit comments

Comments
 (0)