Merge pull request #15 from AurorNZ/eslint_upgrade

Eslint upgrade
This commit is contained in:
Alex Miller 2024-09-11 13:35:40 +12:00 committed by GitHub
commit e5970628e0
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
14 changed files with 672 additions and 402 deletions

View File

@ -1,3 +0,0 @@
dist/
lib/
node_modules/

View File

@ -1,52 +0,0 @@
{
"plugins": ["@typescript-eslint"],
"extends": ["plugin:github/internal"],
"parser": "@typescript-eslint/parser",
"parserOptions": {
"ecmaVersion": 9,
"sourceType": "module",
"project": "./tsconfig.json"
},
"rules": {
"eslint-comments/no-use": "off",
"import/no-namespace": "off",
"no-unused-vars": "off",
"@typescript-eslint/no-unused-vars": "error",
"@typescript-eslint/explicit-member-accessibility": ["error", {"accessibility": "no-public"}],
"@typescript-eslint/no-require-imports": "error",
"@typescript-eslint/array-type": "error",
"@typescript-eslint/await-thenable": "error",
"camelcase": "off",
"@typescript-eslint/camelcase": "off",
"@typescript-eslint/explicit-function-return-type": ["error", {"allowExpressions": true}],
"@typescript-eslint/func-call-spacing": ["error", "never"],
"@typescript-eslint/no-array-constructor": "error",
"@typescript-eslint/no-empty-interface": "error",
"@typescript-eslint/no-explicit-any": "off",
"@typescript-eslint/no-extraneous-class": "error",
"@typescript-eslint/no-for-in-array": "error",
"@typescript-eslint/no-inferrable-types": "error",
"@typescript-eslint/no-misused-new": "error",
"@typescript-eslint/no-namespace": "error",
"@typescript-eslint/no-non-null-assertion": "warn",
"@typescript-eslint/no-unnecessary-qualifier": "error",
"@typescript-eslint/no-unnecessary-type-assertion": "error",
"@typescript-eslint/no-useless-constructor": "error",
"@typescript-eslint/no-var-requires": "error",
"@typescript-eslint/prefer-for-of": "warn",
"@typescript-eslint/prefer-function-type": "warn",
"@typescript-eslint/prefer-includes": "error",
"@typescript-eslint/prefer-string-starts-ends-with": "error",
"@typescript-eslint/promise-function-async": ["error", { "allowAny": true }],
"@typescript-eslint/require-array-sort-compare": "error",
"@typescript-eslint/restrict-plus-operands": "error",
"semi": "off",
"@typescript-eslint/semi": ["error", "never"],
"@typescript-eslint/type-annotation-spacing": "error",
"@typescript-eslint/unbound-method": "error"
},
"env": {
"node": true,
"es6": true
}
}

View File

@ -1,11 +1,10 @@
{
"printWidth": 120,
"tabWidth": 2,
"useTabs": false,
"semi": false,
"singleQuote": true,
"trailingComma": "none",
"bracketSpacing": false,
"arrowParens": "avoid",
"parser": "typescript"
}
"printWidth": 120,
"tabWidth": 2,
"useTabs": false,
"semi": false,
"singleQuote": true,
"trailingComma": "none",
"bracketSpacing": false,
"arrowParens": "avoid"
}

View File

@ -1,7 +1,7 @@
import {describe, expect, test} from 'vitest'
import {Filter} from '../src/filter'
import {File, ChangeStatus} from '../src/file'
import {Filter} from '../src/filter'
describe('yaml filter parsing tests', () => {
test('throws if yaml is not a dictionary', () => {
@ -26,7 +26,7 @@ describe('matching tests', () => {
const yaml = `
src: "src/**/*.js"
`
let filter = new Filter(yaml)
const filter = new Filter(yaml)
const files = modified(['src/app/module/file.js'])
const match = filter.match(files)
expect(match.src).toEqual(files)

View File

@ -1,10 +1,10 @@
import {describe, expect, test} from 'vitest'
import * as git from '../src/git'
import {ChangeStatus} from '../src/file'
import * as git from '../src/git'
describe('parsing output of the git diff command', () => {
test('parseGitDiffOutput returns files with correct change status', async () => {
test('parseGitDiffOutput returns files with correct change status', () => {
const files = git.parseGitDiffOutput(
'A\u0000LICENSE\u0000' + 'M\u0000src/index.ts\u0000' + 'D\u0000src/main.ts\u0000'
)

98
eslint.config.mjs Normal file
View File

@ -0,0 +1,98 @@
// @ts-check
import {fixupPluginRules} from '@eslint/compat'
import {FlatCompat} from '@eslint/eslintrc'
import jsEslint from '@eslint/js'
import eslintConfigPrettier from 'eslint-config-prettier'
import tsEslint from 'typescript-eslint'
const compat = new FlatCompat({
baseDirectory: import.meta.dirname,
recommendedConfig: jsEslint.configs.recommended,
allConfig: jsEslint.configs.all
})
/* eslint-disable @typescript-eslint/explicit-function-return-type */
/**
* @param {string} name the pugin name
* @param {string} alias the plugin alias
* @returns {import("eslint").ESLint.Plugin}
*/
function legacyPlugin(name, alias = name) {
const plugin = compat.plugins(name)[0]?.plugins?.[alias]
if (!plugin) {
throw new Error(`Unable to resolve plugin ${name} and/or alias ${alias}`)
}
return fixupPluginRules(plugin)
}
/* eslint-enable @typescript-eslint/explicit-function-return-type */
export default tsEslint.config(
jsEslint.configs.recommended,
...tsEslint.configs.strictTypeChecked,
...tsEslint.configs.stylisticTypeChecked,
{
languageOptions: {
parserOptions: {
projectService: {
allowDefaultProject: ['*.js', '*.mjs']
},
tsconfigRootDir: import.meta.dirname
}
}
},
{
ignores: ['coverage', 'dist', 'lib']
},
{
plugins: {
github: legacyPlugin('eslint-plugin-github', 'github'), // pending https://github.com/github/eslint-plugin-github/issues/513
import: legacyPlugin('eslint-plugin-import', 'import') // Needed for above
},
rules: {
'@typescript-eslint/await-thenable': 'warn',
'@typescript-eslint/explicit-function-return-type': 'warn',
'@typescript-eslint/no-explicit-any': 'off',
'@typescript-eslint/no-floating-promises': ['warn', {ignoreIIFE: true, ignoreVoid: false}],
'@typescript-eslint/no-shadow': 'error',
'@typescript-eslint/no-unused-vars': ['warn', {argsIgnorePattern: '^_'}],
'@typescript-eslint/restrict-template-expressions': [
'error',
{
allowNever: true,
allowNumber: true
}
],
'github/array-foreach': 'error',
'github/no-implicit-buggy-globals': 'error',
'github/no-then': 'error',
'github/no-dynamic-script-tag': 'error',
'import/no-extraneous-dependencies': [
'error',
{
devDependencies: true,
optionalDependencies: true,
peerDependencies: true
}
],
'import/order': ['warn', {'newlines-between': 'always', alphabetize: {order: 'asc'}}],
'no-console': ['warn']
}
},
{
files: ['**/*.test.ts'],
rules: {
'@typescript-eslint/explicit-function-return-type': 'off',
'@typescript-eslint/no-non-null-assertion': 'off',
'@typescript-eslint/no-unsafe-assignment': 'off',
'@typescript-eslint/no-unsafe-member-access': 'off'
}
},
{
files: ['**/*.js', '**/*.mjs'],
...tsEslint.configs.disableTypeChecked
},
eslintConfigPrettier
)

View File

@ -5,14 +5,14 @@
"description": "Execute your workflow steps only if relevant files are modified.",
"main": "lib/main.js",
"scripts": {
"build": "tsc",
"tscheck": "tsc --noEmit",
"build": "tsc -b tsconfig.build.json",
"tscheck": "tsc",
"format": "prettier --write **/*.ts",
"format-check": "prettier --check **/*.ts",
"lint": "eslint src/**/*.ts",
"lint": "eslint",
"pack": "ncc build -m",
"test": "vitest",
"all": "pnpm run build && pnpm run format && pnpm run lint && pnpm run pack && pnpm test"
"all": "pnpm run build && pnpm run tscheck && pnpm run lint && pnpm run format && pnpm run pack && pnpm test run"
},
"repository": {
"type": "git",
@ -33,18 +33,25 @@
"micromatch": "^4.0.5"
},
"devDependencies": {
"@octokit/webhooks-types": "^7.3.1",
"@eslint/compat": "^1.1.1",
"@eslint/eslintrc": "^3.1.0",
"@eslint/js": "^9.10.0",
"@octokit/webhooks-types": "^7.5.1",
"@tsconfig/node20": "^20.1.2",
"@types/eslint__js": "^8.42.3",
"@types/js-yaml": "^4.0.9",
"@types/micromatch": "^4.0.2",
"@types/node": "^20.0.0",
"@typescript-eslint/eslint-plugin": "^6.20.0",
"@typescript-eslint/parser": "^6.20.0",
"@typescript-eslint/eslint-plugin": "^8.5.0",
"@typescript-eslint/parser": "^8.5.0",
"@vercel/ncc": "^0.38.1",
"eslint": "^8.56.0",
"eslint-plugin-github": "^4.10.1",
"prettier": "^3.2.4",
"eslint": "^9.10.0",
"eslint-config-prettier": "^9.1.0",
"eslint-import-resolver-typescript": "^3.6.3",
"eslint-plugin-github": "^5.0.1",
"prettier": "^3.3.3",
"typescript": "^5.3.3",
"typescript-eslint": "^8.5.0",
"vitest": "^2.0.5"
},
"volta": {

File diff suppressed because it is too large Load Diff

View File

@ -3,12 +3,12 @@ import {exec as execImpl, ExecOptions} from '@actions/exec'
// Wraps original exec() function
// Returns exit code and whole stdout/stderr
export default async function exec(commandLine: string, args?: string[], options?: ExecOptions): Promise<ExecResult> {
options = options || {}
options = options ?? {}
let stdout = ''
let stderr = ''
options.listeners = {
stdout: (data: Buffer) => (stdout += data.toString()),
stderr: (data: Buffer) => (stderr += data.toString())
stdout: (data: Buffer): string => (stdout += data.toString()),
stderr: (data: Buffer): string => (stderr += data.toString())
}
const code = await execImpl(commandLine, args, options)
return {code, stdout, stderr}

View File

@ -1,11 +1,10 @@
import * as jsyaml from 'js-yaml'
import micromatch from 'micromatch'
import {File} from './file'
// Type definition of object we expect to load from YAML
interface FilterYaml {
[name: string]: FilterItemYaml
}
type FilterYaml = Record<string, FilterItemYaml>
type FilterItemYaml =
| string // Filename pattern, e.g. "path/to/*.js"
| FilterItemYaml[] // Supports referencing another rule via YAML anchor
@ -15,12 +14,10 @@ const MatchOptions: micromatch.Options = {
dot: true
}
export interface FilterResults {
[key: string]: File[]
}
export type FilterResults = Partial<Record<string, File[]>>
export class Filter {
rules: {[key: string]: string[]} = {}
rules: Record<string, string[]> = {}
// Creates instance of Filter and load rules from YAML if it's provided
constructor(yaml?: string) {
@ -47,9 +44,9 @@ export class Filter {
match(files: File[]): FilterResults {
const result: FilterResults = {}
const filesMap = files.reduce((result, x) => {
result.set(x.filename, x)
return result
const filesMap = files.reduce((fileResult, x) => {
fileResult.set(x.filename, x)
return fileResult
}, new Map<string, File>())
for (const [key, patterns] of Object.entries(this.rules)) {

View File

@ -1,5 +1,6 @@
import exec from './exec'
import * as core from '@actions/core'
import exec from './exec'
import {File, ChangeStatus} from './file'
export const NULL_SHA = '0000000000000000000000000000000000000000'
@ -215,7 +216,7 @@ async function getLocalRef(shortName: string): Promise<string | undefined> {
const output = (await exec('git', ['show-ref', shortName], {ignoreReturnCode: true})).stdout
const refs = output
.split(/\r?\n/g)
.map(l => l.match(/refs\/(?:(?:heads)|(?:tags)|(?:remotes\/origin))\/(.*)$/))
.map(l => /refs\/(?:(?:heads)|(?:tags)|(?:remotes\/origin))\/(.*)$/.exec(l))
.filter(match => match !== null && match[1] === shortName)
.map(match => match?.[0] ?? '') // match can't be null here but compiler doesn't understand that
@ -260,7 +261,7 @@ function fixStdOutNullTermination(): void {
core.info('')
}
const statusMap: {[char: string]: ChangeStatus} = {
const statusMap: Record<string, ChangeStatus> = {
A: ChangeStatus.Added,
C: ChangeStatus.Copied,
D: ChangeStatus.Deleted,

View File

@ -1,13 +1,14 @@
import * as fs from 'fs'
import * as fs from 'node:fs'
import * as core from '@actions/core'
import * as github from '@actions/github'
import {PullRequest, PushEvent} from '@octokit/webhooks-types'
import {Filter, FilterResults} from './filter'
import {File, ChangeStatus} from './file'
import {Filter, FilterResults} from './filter'
import * as git from './git'
import {backslashEscape, shellEscape} from './list-format/shell-escape'
import {csvEscape} from './list-format/csv-escape'
import {backslashEscape, shellEscape} from './list-format/shell-escape'
type ExportFormat = 'none' | 'csv' | 'json' | 'shell' | 'escape'
@ -95,7 +96,10 @@ async function getChangedFiles(token: string, base: string, ref: string, initial
}
async function getChangedFilesFromGit(base: string, head: string, initialFetchDepth: number): Promise<File[]> {
const defaultBranch = github.context.payload.repository?.default_branch
const defaultBranch =
typeof github.context.payload.repository?.default_branch === 'string'
? github.context.payload.repository.default_branch
: ''
const beforeSha = github.context.eventName === 'push' ? (github.context.payload as PushEvent).before : null
@ -174,6 +178,7 @@ async function getChangedFilesFromApi(token: string, prNumber: PullRequest): Pro
page
})
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
if (response.status !== 200) {
throw new Error(`Fetching list of changed files from GitHub API failed with error code ${response.status}`)
}
@ -195,8 +200,9 @@ async function getChangedFilesFromApi(token: string, prNumber: PullRequest): Pro
status: ChangeStatus.Added
})
files.push({
// 'previous_filename' for some unknown reason isn't in the type definition or documentation
filename: (<any>row).previous_filename as string,
// Existing behaviour, possibly a bug
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
filename: row.previous_filename!,
status: ChangeStatus.Deleted
})
} else {
@ -220,6 +226,8 @@ function exportResults(results: FilterResults, format: ExportFormat): void {
core.info('Results:')
const changes = []
for (const [key, files] of Object.entries(results)) {
if (!files) continue
const value = files.length > 0
core.startGroup(`Filter ${key} = ${value}`)
if (files.length > 0) {
@ -241,7 +249,7 @@ function exportResults(results: FilterResults, format: ExportFormat): void {
core.endGroup()
}
if (results['changes'] === undefined) {
if (results.changes === undefined) {
const changesJson = JSON.stringify(changes)
core.info(`Changes output set to ${changesJson}`)
core.setOutput('changes', changesJson)
@ -270,4 +278,4 @@ function isExportFormat(value: string): value is ExportFormat {
return ['none', 'csv', 'shell', 'json', 'escape'].includes(value)
}
run()
;((): Promise<void> => run())()

10
tsconfig.build.json Normal file
View File

@ -0,0 +1,10 @@
{
"extends": "./tsconfig.json",
"compilerOptions": {
"noEmit": false,
"outDir": "./lib" /* Redirect output structure to the directory. */,
"rootDir": "./src" /* Specify the root directory of input files. Use to control the output directory structure with --outDir. */
},
"exclude": ["node_modules", "**/*.test.ts"]
}

View File

@ -1,8 +1,6 @@
{
"extends": "@tsconfig/node20/tsconfig.json",
"compilerOptions": {
"outDir": "./lib", /* Redirect output structure to the directory. */
"rootDir": "./src" /* Specify the root directory of input files. Use to control the output directory structure with --outDir. */
},
"exclude": ["node_modules", "**/*.test.ts"]
"noEmit": true
}
}