Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: do not fail on gitignore failures + fix: optimize TypeScript project disable search #91

Merged
merged 3 commits into from
Aug 15, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 1 addition & 5 deletions .vscode/settings.json
Original file line number Diff line number Diff line change
@@ -1,9 +1,5 @@
{
"cSpell.words": [
"astrojs",
"Globified",
"globify"
],
"cSpell.words": ["astrojs", "Globified", "globify"],
"explorer.fileNesting.patterns": {
"index.js": "*.js"
}
Expand Down
2 changes: 1 addition & 1 deletion src/astro.cts
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ export const astroConfig: Linter.ConfigOverride<Linter.RulesRecord> = {
plugins: ["astro", "only-warn"],
extends: ["plugin:astro/recommended"],
rules: {
...pluginImportAstroRulesExtra
...pluginImportAstroRulesExtra,
},
globals: {
astroHTML: "readonly",
Expand Down
39 changes: 22 additions & 17 deletions src/typescript.cts
Original file line number Diff line number Diff line change
Expand Up @@ -2,17 +2,30 @@ import { eslintRulesExtra } from "./official-eslint-rules.cjs"
import { pluginImportRulesExtra, pluginImportTypeScriptRulesExtra } from "./plugin-import-rules.cjs"
import { pluginNodeRules } from "./plugin-node-rules.cjs"
import makeSynchronous from "make-synchronous"
import { findOneFile } from "./utils.cjs"
import { findFilesForGroups } from "./utils.cjs"
import type { GlobifiedEntry } from "globify-gitignore"
import { Linter } from "eslint"

const tsFiles = ["**/*.tsx", "**/*.ts", "**/*.mts", "**/*.cts"]
const project = ["**/tsconfig.json", "!**/node_modules/**/tsconfig.json"]
const tscConfigFiles = ["**/tsconfig.json", "!**/node_modules/**/tsconfig.json"]

function globifyGitIgnoreFileWithDeps(cwd: string, include: boolean) {
// eslint-disable-next-line @typescript-eslint/no-var-requires
const { globifyGitIgnoreFile } = require("globify-gitignore") as typeof import("globify-gitignore") // prettier-ignore
return globifyGitIgnoreFile(cwd, include)
async function globifyGitIgnoreFileWithDeps(cwd: string, include: boolean) {
try {
// import in the function to allow makeSynchronous to work
/* eslint-disable @typescript-eslint/no-var-requires */
const { globifyGitIgnoreFile } = require("globify-gitignore") as typeof import("globify-gitignore") // prettier-ignore
const { existsSync } = require("fs") as typeof import("fs")
const { join } = require("path") as typeof import("path")
/* eslint-enable @typescript-eslint/no-var-requires */

if (!existsSync(join(cwd, ".gitignore"))) {
return []
}
return await globifyGitIgnoreFile(cwd, include)
} catch (error) {
console.error(error)
return []
}
}
const globifyGitIgnoreFileSync = makeSynchronous(globifyGitIgnoreFileWithDeps) as (
cwd: string,
Expand Down Expand Up @@ -41,18 +54,10 @@ function disableProjectBasedRules() {
)

// check if there are any ts files
const hasTsFile = findOneFile(cwd, tsFiles, ignore)

// return if there are no ts files
if (!hasTsFile) {
return true
}

// check if there is a tsconfig.json file
const hasTsConfig = findOneFile(cwd, project, ignore)
const [hasTscConfig, hasTsFile] = findFilesForGroups(cwd, tscConfigFiles, tsFiles, ignore)

// if there is no tsconfig.json file, but there are ts files, disable the project-based rules
const disable = !hasTsConfig && hasTsFile
const disable = !hasTscConfig && hasTsFile

if (disable) {
console.warn(
Expand Down Expand Up @@ -119,7 +124,7 @@ export const tsConfig: Linter.ConfigOverride<Linter.RulesRecord> = {
files: tsFiles,
parser: "@typescript-eslint/parser",
parserOptions: {
project,
project: tscConfigFiles,
createDefaultProgram: true, // otherwise Eslint will error if a ts file is not covered by one of the tsconfig.json files
},
plugins: ["@typescript-eslint", "node", "import", "only-warn"],
Expand Down
46 changes: 35 additions & 11 deletions src/utils.cts
Original file line number Diff line number Diff line change
Expand Up @@ -2,23 +2,47 @@ import { readdirSync } from "fs"
import { join } from "path"
import { default as anymatch } from "anymatch"

export function findOneFile(cwd: string, search: string[], ignored: string[]) {
export function findFilesForGroups(
cwd: string,
earlyExitSearchGroup: string[],
exhaustiveSearchGroup: string[],
ignored: string[],
) {
const status = [false, false]
searchDirectory(cwd, status, earlyExitSearchGroup, exhaustiveSearchGroup, ignored)

return status
}

function searchDirectory(
directory: string,
status: boolean[],
earlyExitSearchGroup: string[],
exhaustiveSearchGroup: string[],
ignored: string[],
): boolean {
// recursively search the current folder for a file with the given fileEnding, ignoring the given folders, and return true as soon as one is found
const files = readdirSync(cwd, { withFileTypes: true, recursive: false })
const files = readdirSync(directory, { withFileTypes: true, recursive: false })
for (const file of files) {
const path = join(cwd, file.name)
const path = join(directory, file.name)
if (file.isDirectory()) {
// if the folder is not ignored, search it recursively
if (!anymatch(ignored, path)) {
// if the folder is not ignored, search it recursively
const found = findOneFile(path, search, ignored)
if (found) {
return true
if (searchDirectory(path, status, earlyExitSearchGroup, exhaustiveSearchGroup, ignored)) {
return true // exit
}
}
} else if (anymatch(search, path)) {
// if the file ends with the given fileEnding, return true
return true
} else {
// check the early exit search group first
status[0] = status[0] || anymatch(exhaustiveSearchGroup, path)
if (status[0]) {
return true // exit
}

// check the exhaustive search group
status[1] = status[1] || anymatch(exhaustiveSearchGroup, path)
}
}
return false

return false // continue
}