Skip to content

Commit

Permalink
feat: added project references, with more docs
Browse files Browse the repository at this point in the history
  • Loading branch information
JoshuaKGoldberg committed Jul 17, 2024
1 parent 27ac09f commit 81986db
Show file tree
Hide file tree
Showing 15 changed files with 138 additions and 213 deletions.
2 changes: 1 addition & 1 deletion .prettierignore
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
./cases/
.all-contributorsrc
.husky/
cases/
30 changes: 30 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,12 +15,42 @@

## Usage

You'll need [hyperfine](https://github.com/sharkdp/hyperfine) installed locally, such as with `brew install hyperfine` or `winget install hyperfine`.
See [sharkdp/hyperfine#installation](https://github.com/sharkdp/hyperfine#installation).

```shell
npm install
npm generate
npm measure
```

### Measured Attributes

The `caseEntries` values in `src/data.ts` can be modified to test:

- `files`: roughly how many generated files should be linted
- `layout`: what rough shape of imports those files exhibit:
- `"even"`: a single root-level `index.ts` importing from roughly an even triangle shape of files
- `"references"`: a single root-level `tsconfig.json` with project references to a few projects
- `"wide"`: one root-level `index.ts` importing from all files in the project
- `singleRun`: whether to enable [single-run inference](https://v8--typescript-eslint.netlify.app/packages/parser#disallowautomaticsingleruninference) as a performance boost
- `types`: whether to use `parserOptions.project` or `parserOptions.projectService` for typed linting

## Results

Right now, `parserOptions.project` outperforms `parserOptions.projectService`.
This is a performance issue and we are investigating it as a critical bug for v8.

```plaintext
┌───────┬──────────────────────┬──────────────────────┬──────────────────────┬──────────────────────┐
│ files │ project (even) │ project (references) │ service (even) │ service (references) │
┼───────┼──────────────────────┼──────────────────────┼──────────────────────┼──────────────────────┤
│ 128 │ '1.149 s ± 0.030 s' │ '1.135 s ± 0.008 s' │ '1.178 s ± 0.010 s' │ '1.736 s ± 0.012 s' │
│ 512 │ '1.636 s ± 0.009 s' │ '1.656 s ± 0.004 s' │ '1.895 s ± 0.007 s' │ '2.613 s ± 0.020 s' │
│ 1024 │ '2.353 s ± 0.013 s' │ '2.399 s ± 0.016 s' │ '3.130 s ± 0.017 s' │ '4.034 s ± 0.061 s' │
┴───────┴──────────────────────┴──────────────────────┴──────────────────────┴──────────────────────┘
```

## Contributors

<!-- spellchecker: disable -->
Expand Down
2 changes: 1 addition & 1 deletion cspell.json
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
{
"dictionaries": ["typescript"],
"ignorePaths": [".github", "cases", "node_modules"],
"words": ["execa", "knip", "packagejson", "tseslint"]
"words": ["execa", "knip", "packagejson", "sharkdp", "tseslint", "winget"]
}
67 changes: 0 additions & 67 deletions src/creators/createEvenCaseFiles.ts

This file was deleted.

6 changes: 0 additions & 6 deletions src/creators/createProjectsCaseFiles.ts

This file was deleted.

43 changes: 0 additions & 43 deletions src/creators/createWideCaseFiles.ts

This file was deleted.

38 changes: 0 additions & 38 deletions src/creators/files.ts

This file was deleted.

33 changes: 33 additions & 0 deletions src/creators/files/createESLintConfigFile.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
export interface ESLintConfigFileOptions {
singleRun: boolean;
types: "tsconfig.eslint.json" | "projectService" | true;

Check failure on line 3 in src/creators/files/createESLintConfigFile.ts

View workflow job for this annotation

GitHub Actions / lint

Expected ""projectService"" to come before ""tsconfig.eslint.json""
}

export function createESLintConfigFile({
singleRun,
types,
}: ESLintConfigFileOptions) {
const [projectKey, projectValue] =
types === "projectService" ? ["projectService", true] : ["project", types];

return `
import tseslint from "typescript-eslint";
export default tseslint.config(
tseslint.configs.base,
{
files: ["**/*.ts"],
languageOptions: {
parserOptions: {
${singleRun ? "disallowAutomaticSingleRunInference: true," : ""}
${projectKey}: ${typeof projectValue === "string" ? `"${projectValue}"` : projectValue},
tsconfigRootDir: import.meta.dirname,
},
},
rules: {
"@typescript-eslint/no-floating-promises": "error"
}
},
);
`;
}
18 changes: 18 additions & 0 deletions src/creators/files/createPackageFile.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import { NamedCaseData } from "../../data.js";

export function createPackageFile(data: NamedCaseData) {
return {
devDependencies: {
"@eslint/js": "*",
eslint: "*",
typescript: "*",
"typescript-eslint": "rc-v8",
},
name: data.name,
private: true,
scripts: {
lint: "eslint src",
},
type: "module",
};
}
12 changes: 12 additions & 0 deletions src/creators/files/createStandardTSConfigFile.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
export function createStandardTSConfigFile() {
return {
compilerOptions: {
module: "NodeNext",
noEmit: true,
skipLibCheck: true,
strict: true,
target: "ESNext",
},
include: ["src"],
};
}
15 changes: 15 additions & 0 deletions src/creators/writeCaseFiles.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import { CaseData } from "../data.js";
import { writeStructure } from "../writing/writeStructure.js";
import { writeEvenCaseFiles } from "./cases/createEvenCaseFiles.js";

Check failure on line 3 in src/creators/writeCaseFiles.ts

View workflow job for this annotation

GitHub Actions / lint

Can't resolve './cases/createEvenCaseFiles.js' in '/home/runner/work/performance/performance/src/creators'
import { createReferencesCaseFiles } from "./cases/createReferencesCaseFiles.js";

Check failure on line 4 in src/creators/writeCaseFiles.ts

View workflow job for this annotation

GitHub Actions / lint

Can't resolve './cases/createReferencesCaseFiles.js' in '/home/runner/work/performance/performance/src/creators'
import { writeWideCaseFiles } from "./cases/createWideCaseFiles.js";

Check failure on line 5 in src/creators/writeCaseFiles.ts

View workflow job for this annotation

GitHub Actions / lint

Can't resolve './cases/createWideCaseFiles.js' in '/home/runner/work/performance/performance/src/creators'

const caseFileCreators = {
even: writeEvenCaseFiles,

Check failure on line 8 in src/creators/writeCaseFiles.ts

View workflow job for this annotation

GitHub Actions / lint

Unsafe assignment of an error typed value
references: createReferencesCaseFiles,

Check failure on line 9 in src/creators/writeCaseFiles.ts

View workflow job for this annotation

GitHub Actions / lint

Unsafe assignment of an error typed value
wide: writeWideCaseFiles,

Check failure on line 10 in src/creators/writeCaseFiles.ts

View workflow job for this annotation

GitHub Actions / lint

Unsafe assignment of an error typed value
};

export async function writeCaseFiles(data: CaseData, directory: string) {
return await writeStructure(directory, caseFileCreators[data.layout](data));

Check failure on line 14 in src/creators/writeCaseFiles.ts

View workflow job for this annotation

GitHub Actions / lint

Unsafe argument of type `any` assigned to a parameter of type `Structure`

Check failure on line 14 in src/creators/writeCaseFiles.ts

View workflow job for this annotation

GitHub Actions / lint

Unsafe call of an `error` type typed value
}
8 changes: 4 additions & 4 deletions src/data.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,16 +3,16 @@ export const casesPath = "cases";
export const caseEntries = [
{
label: "files",
// values: [1, 32, 64, 128, 256, 512, 1024],
values: [512, 1024],
values: [128, 512, 1024],
},
{
label: "layout",
values: ["even" /* , "projects" , "wide" */],
// values: ["even" /* , "references" , "wide" */],
values: ["even", "references" /* , "wide" */],
},
{
label: "singleRun",
values: [false, true],
values: [/* false, */ true],
},
{
label: "types",
Expand Down
59 changes: 15 additions & 44 deletions src/generate.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,56 +2,27 @@ import { execa } from "execa";
import fs from "node:fs/promises";
import path from "node:path";

import { createESLintConfigFile, writeCaseFiles } from "./creators/files.js";
import { writeCaseFiles } from "./creators/writeCaseFiles.js";
import { createPackageFile } from "./creators/files/createPackageFile.js";

Check failure on line 6 in src/generate.ts

View workflow job for this annotation

GitHub Actions / lint

Expected "./creators/files/createPackageFile.js" to come before "./creators/writeCaseFiles.js"
import { createESLintConfigFile } from "./creators/files/createESLintConfigFile.js";
import { CaseData, NamedCaseData, caseEntries, casesPath } from "./data.js";
import { createProjectName } from "./utils.js";
import { writeFile } from "./writing/writeFile.js";

async function createCase(data: CaseData): Promise<NamedCaseData> {
const name = createProjectName(data);
async function createCase(data: NamedCaseData): Promise<NamedCaseData> {
const name = createProjectName({
files: data.files,
layout: data.layout,
singleRun: data.singleRun,
types: data.types,
});
const directory = path.join(casesPath, name);

console.log(`Populating ${name}...`);

await fs.mkdir(path.join(directory, "src"), { recursive: true });

await writeFile(directory, "eslint.config.js", createESLintConfigFile(data));

await writeFile(
directory,
"package.json",
{
devDependencies: {
"@eslint/js": "*",
eslint: "*",
typescript: "*",
"typescript-eslint": "rc-v8",
},
name,
private: true,
scripts: {
lint: "eslint src",
},
type: "module",
},
"json",
);

await writeFile(
directory,
"tsconfig.json",
{
compilerOptions: {
module: "NodeNext",
noEmit: true,
skipLibCheck: true,
strict: true,
target: "ESNext",
},
include: ["src"],
},
"json",
);
await writeFile(directory, "package.json", createPackageFile(data), "json");

console.log("Created", await writeCaseFiles(data, directory), "files");

Expand All @@ -71,10 +42,10 @@ const cases: NamedCaseData[] = [];

for (const files of caseEntries[0].values) {
for (const layout of caseEntries[1].values) {
for (const singleRun of caseEntries[2].values) {
for (const types of caseEntries[3].values) {
cases.push(await createCase({ files, layout, singleRun, types }));
}
for (const types of caseEntries[3].values) {
const data: CaseData = { files, layout, singleRun: true, types };
const name = createProjectName(data);
cases.push(await createCase({ ...data, name }));
}
}
}
Expand Down
Loading

0 comments on commit 81986db

Please sign in to comment.