chore: Update lint dependencies

This commit is contained in:
Joachim Van Herwegen 2024-07-18 11:03:30 +02:00
parent d1282f6b1a
commit ecd031e69f
37 changed files with 3049 additions and 2931 deletions

View File

@ -39,9 +39,16 @@
},
"enabledJWA": {
"dPoPSigningAlgValues": [
"RS256", "RS384", "RS512",
"PS256", "PS384", "PS512",
"ES256", "ES256K", "ES384", "ES512",
"RS256",
"RS384",
"RS512",
"PS256",
"PS384",
"PS512",
"ES256",
"ES256K",
"ES384",
"ES512",
"EdDSA"
]
},

View File

@ -16,7 +16,7 @@ antfu.GLOB_EXCLUDE.splice(index, 1);
module.exports = antfu.default(
{
// Don't want to lint test assets, or TS snippets in markdown files
ignores: [ 'test/assets/*', '**/*.md/**/*.ts' ],
ignores: [ 'test/assets/*', '**/*.md' ],
typescript: {
tsconfigPath: [ './tsconfig.json', './scripts/tsconfig.json', './test/tsconfig.json' ],
},
@ -26,12 +26,12 @@ module.exports = antfu.default(
.append(unicornConfig)
.append(fileNamesConfig)
// Using an override here so all the type settings are also applied correctly
.override('antfu:typescript:rules-type-aware', typedConfig)
.override('antfu/typescript/rules-type-aware', typedConfig)
.append({
...testConfig,
files: [ 'test/**/*.ts' ],
})
.override('antfu:jsonc:rules', {
.override('antfu/jsonc/rules', {
rules: {
// Consistent with how we do it in code
'jsonc/array-bracket-spacing': [ 'error', 'always', {
@ -48,7 +48,7 @@ module.exports = antfu.default(
'unicorn/filename-case': 'off',
},
})
.override('antfu:markdown:parser', {
.override('antfu/markdown/parser', {
rules: {
// We want to be able to use these in Markdown text
'no-irregular-whitespace': 'off',

View File

@ -1,6 +1,6 @@
module.exports = [
{
name: 'opinionated:file-names:all',
name: 'opinionated/file-names/all',
rules: {
'unicorn/filename-case': [ 'error', {
cases: {
@ -17,7 +17,7 @@ module.exports = [
},
},
{
name: 'opinionated:file-names:ts',
name: 'opinionated/file-names/ts',
files: [ '**/*.ts' ],
rules: {
'unicorn/filename-case': [ 'error', {

View File

@ -1,5 +1,5 @@
module.exports = {
name: 'opinionated:general',
name: 'opinionated/general',
rules: {
'antfu/consistent-list-newline': 'error',
@ -126,6 +126,8 @@ module.exports = {
'ts/prefer-for-of': 'error',
'ts/prefer-function-type': 'error',
// Only need 1 unused vars rule
'no-unused-vars': 'off',
'unused-imports/no-unused-vars': [
'error',
{ args: 'after-used', vars: 'all', ignoreRestSiblings: true },

View File

@ -2,7 +2,7 @@ const jest = require('eslint-plugin-jest');
// Specifically for tests
module.exports = {
name: 'opinionated:test',
name: 'opinionated/test',
// See https://github.com/jest-community/eslint-plugin-jest/issues/1408
plugins: {
jest,

View File

@ -1,4 +1,5 @@
module.exports = {
name: 'opinionated/typed',
rules: {
'ts/consistent-type-assertions': [ 'error', {
assertionStyle: 'as',
@ -45,6 +46,8 @@ module.exports = {
'ts/prefer-readonly': 'error',
'ts/prefer-reduce-type-parameter': 'error',
'ts/prefer-regexp-exec': 'error',
// Not sure if this would make code better
'ts/strict-boolean-expressions': 'off',
'ts/prefer-string-starts-ends-with': 'error',
'ts/require-array-sort-compare': 'error',

View File

@ -1,5 +1,5 @@
module.exports = {
name: 'opinionated:unicorn',
name: 'opinionated/unicorn',
rules: {
'unicorn/better-regex': 'error',
'unicorn/empty-brace-spaces': 'error',

5842
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -143,9 +143,9 @@
"yup": "^1.3.2"
},
"devDependencies": {
"@antfu/eslint-config": "2.11.4",
"@commitlint/cli": "^17.7.2",
"@commitlint/config-conventional": "^17.7.0",
"@antfu/eslint-config": "2.21.3",
"@commitlint/cli": "^19.3.0",
"@commitlint/config-conventional": "^19.2.2",
"@inrupt/solid-client-authn-core": "^2.0.0",
"@inrupt/solid-client-authn-node": "^2.0.0",
"@tsconfig/node18": "^18.2.2",
@ -167,8 +167,8 @@
"supertest": "^6.3.3",
"ts-jest": "^29.1.1",
"ts-node": "^10.9.1",
"typedoc": "^0.25.2",
"typescript": "^5.2.2"
"typedoc": "^0.26.4",
"typescript": "^5.5.3"
},
"husky": {
"hooks": {

View File

@ -20,7 +20,7 @@ import { readFile, writeFile } from 'fs-extra';
* @returns Promise with output string
*/
async function capitalizeListEntries(input: string): Promise<string> {
return input.replaceAll(/^(\W*\* [a-z])/gmu, (match): string => match.toUpperCase());
return input.replaceAll(/^\W*\* [a-z]/gmu, (match): string => match.toUpperCase());
}
/**

View File

@ -19,7 +19,7 @@ export class UnsecureWebIdExtractor extends CredentialsExtractor {
}
public async handle({ headers }: HttpRequest): Promise<Credentials> {
const webId = /^WebID\s+(.*)/ui.exec(headers.authorization!)![1];
const webId = /^WebID\s+(.*)/iu.exec(headers.authorization!)![1];
this.logger.info(`Agent unsecurely claims to be ${webId}`);
return { agent: { webId }};
}

View File

@ -24,7 +24,7 @@ import { AclMode } from './permissions/AclPermissionSet';
import { AccessMode } from './permissions/Permissions';
import type { PermissionMap, PermissionSet } from './permissions/Permissions';
const modesMap: Record<string, Readonly<(keyof AclPermissionSet)[]>> = {
const modesMap: Record<string, readonly (keyof AclPermissionSet)[]> = {
[ACL.Read]: [ AccessMode.read ],
[ACL.Write]: [ AccessMode.append, AccessMode.write ],
[ACL.Append]: [ AccessMode.append ],

View File

@ -22,7 +22,7 @@ import type { PermissionMap } from './permissions/Permissions';
import { AccessMode } from './permissions/Permissions';
// Maps WebACL-specific modes to generic access modes.
const modesMap: Record<string, Readonly<(keyof AclPermissionSet)[]>> = {
const modesMap: Record<string, readonly (keyof AclPermissionSet)[]> = {
[ACL.Read]: [ AccessMode.read ],
[ACL.Write]: [ AccessMode.append, AccessMode.write ],
[ACL.Append]: [ AccessMode.append ],
@ -69,7 +69,7 @@ export class WebAclReader extends PermissionReader {
this.logger.debug(`Retrieving permissions of ${credentials.agent?.webId ?? 'an unknown agent'}`);
const aclMap = await this.getAclMatches(requestedModes.distinctKeys());
const storeMap = await this.findAuthorizationStatements(aclMap);
return await this.findPermissions(storeMap, credentials);
return this.findPermissions(storeMap, credentials);
}
/**

View File

@ -21,7 +21,7 @@ export class AgentGroupAccessChecker extends AccessChecker {
const { webId } = credentials.agent;
const groups = acl.getObjects(rule, ACL.terms.agentGroup, null);
return await promiseSome(groups.map(async(group: Term): Promise<boolean> =>
return promiseSome(groups.map(async(group: Term): Promise<boolean> =>
this.isMemberOfGroup(webId, group)));
}
return false;
@ -51,6 +51,6 @@ export class AgentGroupAccessChecker extends AccessChecker {
const representation = await fetchDataset(url);
return readableToQuads(representation.data);
})();
return await prom;
return prom;
}
}

View File

@ -79,7 +79,7 @@ class WebSocketListener extends WebSocketListenerEmitter {
private onMessage(message: string): void {
// Parse the message
const match = /^(\w+)\s+(.+)$/u.exec(message);
const match = /^(\w+)\s+(\S.+)$/u.exec(message);
if (!match) {
this.sendMessage('warning', `Unrecognized message format: ${message}`);
return;

View File

@ -23,7 +23,7 @@ export class BaseCookieStore implements CookieStore {
}
public async get(cookie: string): Promise<string | undefined> {
return await this.storage.get(cookie);
return this.storage.get(cookie);
}
public async refresh(cookie: string): Promise<Date | undefined> {

View File

@ -103,7 +103,7 @@ export class BaseLoginAccountStorage<T extends IndexTypeCollection<T>> implement
}
public async findIds<TType extends StringKey<T>>(type: TType, query: IndexedQuery<T, TType>): Promise<string[]> {
return await this.storage.findIds(type, query);
return this.storage.findIds(type, query);
}
public async set<TType extends StringKey<T>>(type: TType, value: TypeObject<T[TType]>): Promise<void> {

View File

@ -149,7 +149,7 @@ export class V6MigrationInitializer extends Initializer {
].join(' '), resolve);
});
readline.close();
if (!/^y(?:es)?$/ui.test(answer)) {
if (!/^y(?:es)?$/iu.test(answer)) {
throw new Error('Stopping server as migration was cancelled.');
}
}

View File

@ -40,6 +40,6 @@ export class BaseComponentsJsFactory implements ComponentsJsFactory {
Promise<T> {
const manager = await this.buildManager();
await manager.configRegistry.register(configPath);
return await manager.instantiate(componentIri, { variables });
return manager.instantiate(componentIri, { variables });
}
}

View File

@ -108,6 +108,6 @@ export class RedirectingHttpHandler extends HttpHandler {
throw new NotImplementedHttpError('Target is already correct.');
}
return /^(?:[a-z]+:)?\/\//ui.test(redirect) ? redirect : joinUrl(this.baseUrl, redirect);
return /^(?:[a-z]+:)?\/\//iu.test(redirect) ? redirect : joinUrl(this.baseUrl, redirect);
}
}

View File

@ -258,7 +258,7 @@ export class DataAccessorBasedStore implements ResourceStore {
this.validateConditions(conditions, oldMetadata);
if (this.metadataStrategy.isAuxiliaryIdentifier(identifier)) {
return await this.writeMetadata(identifier, representation);
return this.writeMetadata(identifier, representation);
}
// Potentially have to create containers if it didn't exist yet

View File

@ -184,7 +184,7 @@ export class FileDataAccessor implements DataAccessor {
*/
private async getDirectoryMetadata(link: ResourceLink, stats: Stats):
Promise<RepresentationMetadata> {
return await this.getBaseMetadata(link, stats, true);
return this.getBaseMetadata(link, stats, true);
}
/**

View File

@ -73,7 +73,7 @@ export class SparqlDataAccessor implements DataAccessor {
*/
public async getData(identifier: ResourceIdentifier): Promise<Guarded<Readable>> {
const name = namedNode(identifier.path);
return await this.sendSparqlConstruct(this.sparqlConstruct(name));
return this.sendSparqlConstruct(this.sparqlConstruct(name));
}
/**

View File

@ -98,7 +98,7 @@ export class ContainerToTemplateConverter extends BaseTypedRepresentationConvert
* Derives a short name for the given resource.
*/
private getLocalName(iri: string): string {
const match = /:\/+([^/]+).*?\/([^/]*)\/?$/u.exec(iri);
const match = /:\/+([^/]+)(?:\/[^/]*)*?\/([^/]*)\/?$/u.exec(iri);
return match?.[2] ? decodeURIComponent(match[2]) : match?.[1] ?? iri;
}
}

View File

@ -38,7 +38,8 @@ export class JsonResourceStorage<T> implements KeyValueStorage<string, T> {
const identifier = this.keyToIdentifier(key);
// eslint-disable-next-line ts/naming-convention
const representation = await this.source.getRepresentation(identifier, { type: { 'application/json': 1 }});
return JSON.parse(await readableToString(representation.data)) as Promise<T>;
// eslint-disable-next-line ts/no-unsafe-return
return JSON.parse(await readableToString(representation.data));
} catch (error: unknown) {
if (!NotFoundHttpError.isInstance(error)) {
throw error;
@ -48,7 +49,7 @@ export class JsonResourceStorage<T> implements KeyValueStorage<string, T> {
public async has(key: string): Promise<boolean> {
const identifier = this.keyToIdentifier(key);
return await this.source.hasResource(identifier);
return this.source.hasResource(identifier);
}
public async set(key: string, value: unknown): Promise<this> {

View File

@ -48,7 +48,7 @@ export class ExtensionBasedMapper extends BaseFileIdentifierMapper {
// Existing file
if (!contentType) {
// Find a matching file
const [ , folder, documentName ] = /^(.*\/)(.*)$/u.exec(filePath)!;
const [ , folder, documentName ] = /^(.*\/)([^/]*)$/u.exec(filePath)!;
let fileName: string | undefined;
try {
const files = await fsPromises.readdir(folder);

View File

@ -118,7 +118,7 @@ export interface LinkEntry {
//
// REUSED REGEXES
export const TCHAR = /[a-zA-Z0-9!#$%&'*+-.^_`|~]/u;
export const TCHAR = /[-\w!#$%&'*+.^`|~]/u;
export const TOKEN = new RegExp(`^${TCHAR.source}+$`, 'u');
export const SIMPLE_MEDIA_RANGE = new RegExp(`^${TCHAR.source}+/${TCHAR.source}+$`, 'u');
export const QUOTED_STRING =

View File

@ -493,7 +493,7 @@ const authSchemeRegexCache: Map<string, RegExp> = new Map();
export function matchesAuthorizationScheme(scheme: string, authorization?: string): boolean {
const lowerCaseScheme = scheme.toLowerCase();
if (!authSchemeRegexCache.has(lowerCaseScheme)) {
authSchemeRegexCache.set(lowerCaseScheme, new RegExp(`^${escapeStringRegexp(lowerCaseScheme)} `, 'ui'));
authSchemeRegexCache.set(lowerCaseScheme, new RegExp(`^${escapeStringRegexp(lowerCaseScheme)} `, 'iu'));
}
// Support authorization being undefined (for the sake of usability).
return typeof authorization !== 'undefined' && authSchemeRegexCache.get(lowerCaseScheme)!.test(authorization);

View File

@ -126,7 +126,7 @@ export function getExtension(path: string): string {
* preserving but normalizing path delimiters and their escaped forms.
*/
function transformPathComponents(path: string, transform: (part: string) => string): string {
const [ , base, queryString ] = /^([^?]*)(.*)$/u.exec(path)!;
const [ , base, queryString ] = /^([^?]*)(\?.*)?$/u.exec(path)!;
const transformed = base
// We split on actual URI path component delimiters (slash and backslash),
// but also on things that could be wrongly interpreted as component delimiters,
@ -135,7 +135,7 @@ function transformPathComponents(path: string, transform: (part: string) => stri
// since they would become _actual_ delimiters if accidentally decoded.
// Additionally, we need to preserve any encoded percent signs (%25)
// that precede them, because these might change their interpretation as well.
.split(/(\/|\\|%(?:25)*(?:2f|5c))/ui)
.split(/(\/|\\|%(?:25)*(?:2f|5c))/iu)
// Even parts map to components that need to be transformed,
// odd parts to (possibly escaped) delimiters that need to be normalized.
.map((part, index): string =>
@ -172,7 +172,7 @@ const forbiddenSymbols = {
'*': '%2A',
} as const;
/* eslint-enable ts/naming-convention */
const forbiddenRegex = new RegExp(`[${Object.keys(forbiddenSymbols).join('')}]`, 'ug');
const forbiddenRegex = new RegExp(`[${Object.keys(forbiddenSymbols).join('')}]`, 'gu');
/**
* This function is used when converting a URI to a file path. Decodes all components of a URI path,
* with the exception of encoded slash characters, as this would lead to unexpected file locations

View File

@ -2,6 +2,7 @@
* Helper class for instantiating multiple objects with Components.js.
* See https://github.com/LinkedSoftwareDependencies/Components.js/issues/26
*/
// eslint-disable-next-line ts/no-extraneous-class
export class RecordObject implements Record<string, unknown> {
public constructor(record: Record<string, unknown> = {}) {
// eslint-disable-next-line no-constructor-return

View File

@ -6,9 +6,9 @@ import { types } from 'node:util';
export function isError(error: unknown): error is Error {
return types.isNativeError(error) ||
(Boolean(error) &&
typeof (error as Error).name === 'string' &&
typeof (error as Error).message === 'string' &&
(typeof (error as Error).stack === 'undefined' || typeof (error as Error).stack === 'string'));
typeof (error as Error).name === 'string' &&
typeof (error as Error).message === 'string' &&
(typeof (error as Error).stack === 'undefined' || typeof (error as Error).stack === 'string'));
}
/**

View File

@ -10,6 +10,8 @@ const BaseHttpError = generateHttpErrorClass(405, 'MethodNotAllowedHttpError');
* Can keep track of the methods that are not allowed.
*/
export class MethodNotAllowedHttpError extends BaseHttpError {
// Components.js can't parse `readonly`
// eslint-disable-next-line ts/array-type
public readonly methods: Readonly<string[]>;
public constructor(methods: string[] = [], message?: string, options?: HttpErrorOptions) {

View File

@ -31,7 +31,7 @@ export async function instantiateFromConfig(
for (const configPath of configPaths) {
await manager.configRegistry.register(configPath);
}
return await manager.instantiate(componentUrl, { variables });
return manager.instantiate(componentUrl, { variables });
}
export function getTestConfigPath(configFile: string): string {

View File

@ -257,9 +257,9 @@ describe('AppRunner', (): void => {
} catch (error: unknown) {
caughtError = error as Error;
}
expect(caughtError?.message).toMatch(/^Cannot run a singlethreaded-only component in a multithreaded setup!/mu);
expect(caughtError?.message).toMatch(/^Cannot run a singlethreaded-only component in a multithreaded setup!/u);
expect(caughtError?.message).toMatch(
/\[ViolatingClass\] is not threadsafe and should not be run in multithreaded setups!/mu,
/\[ViolatingClass\] is not threadsafe and should not be run in multithreaded setups!/u,
);
expect(write).toHaveBeenCalledTimes(0);
@ -295,7 +295,7 @@ describe('AppRunner', (): void => {
}
expect(caughtError?.message).toMatch(/^Cannot run a singlethreaded-only component in a multithreaded setup!/mu);
expect(caughtError?.message).toMatch(
/\[ViolatingClass1, ViolatingClass2\] are not threadsafe and should not be run in multithreaded setups!/mu,
/\[ViolatingClass1, ViolatingClass2\] are not threadsafe and should not be run in multithreaded setups!/u,
);
expect(write).toHaveBeenCalledTimes(0);
@ -481,7 +481,7 @@ describe('AppRunner', (): void => {
}
expect(caughtError.message).toMatch(/^Cannot run a singlethreaded-only component in a multithreaded setup!/mu);
expect(caughtError?.message).toMatch(
/\[ViolatingClass\] is not threadsafe and should not be run in multithreaded setups!/mu,
/\[ViolatingClass\] is not threadsafe and should not be run in multithreaded setups!/u,
);
expect(write).toHaveBeenCalledTimes(0);
@ -820,7 +820,7 @@ describe('AppRunner', (): void => {
await flushPromises();
expect(write).toHaveBeenCalledTimes(1);
expect(write).toHaveBeenLastCalledWith(expect.stringMatching(/Error: Fatal/mu));
expect(write).toHaveBeenLastCalledWith(expect.stringMatching(/Error: Fatal/u));
expect(exit).toHaveBeenCalledTimes(1);
expect(exit).toHaveBeenLastCalledWith(1);

View File

@ -302,7 +302,7 @@ describe('A DataAccessorBasedStore', (): void => {
const generatedID = [ ...result.keys() ].find((id): boolean => id.path !== resourceID.path)!;
expect(generatedID).toBeDefined();
expect(generatedID.path).toMatch(new RegExp(`^${root}[^/]+?/$`, 'u'));
expect(generatedID.path).toMatch(new RegExp(`^${root}[^/]*/$`, 'u'));
expect(accessor.data[generatedID.path]).toBeDefined();
expect(accessor.data[generatedID.path].metadata.contentType).toBeUndefined();
@ -630,8 +630,7 @@ describe('A DataAccessorBasedStore', (): void => {
data: guardedStreamFrom([ resourceData ]),
metadata: new RepresentationMetadata({
[CONTENT_TYPE]: 'text/plain',
[RDF.type]: namedNode(LDP.Resource),
[RDF.type]: namedNode('http://example.org/Type'),
[RDF.type]: [ namedNode(LDP.Resource), namedNode('http://example.org/Type') ],
}),
isEmpty: false,
};
@ -659,8 +658,7 @@ describe('A DataAccessorBasedStore', (): void => {
data: guardedStreamFrom([ '<a> <b> <c>' ]),
metadata: new RepresentationMetadata({
[CONTENT_TYPE]: 'text/turtle',
[RDF.type]: namedNode(LDP.Resource),
[RDF.type]: namedNode('http://example.org/Type'),
[RDF.type]: [ namedNode(LDP.Resource), namedNode('http://example.org/Type') ],
}),
isEmpty: false,
};

View File

@ -17,9 +17,9 @@ describe('A JsonFileStorage', (): void => {
cache = mockFileSystem(rootFilePath);
locker = {
withReadLock:
jest.fn(async(identifier: ResourceIdentifier, whileLocked: () => any): Promise<any> => await whileLocked()),
jest.fn(async(identifier: ResourceIdentifier, whileLocked: () => any): Promise<any> => whileLocked()),
withWriteLock:
jest.fn(async(identifier: ResourceIdentifier, whileLocked: () => any): Promise<any> => await whileLocked()),
jest.fn(async(identifier: ResourceIdentifier, whileLocked: () => any): Promise<any> => whileLocked()),
};
storage = new JsonFileStorage(`${rootFilePath}${jsonPath}`, locker);
});

View File

@ -78,7 +78,7 @@ export function getSocket(name: typeof socketNames[number]): string {
export function describeIf(envFlag: string): Describe {
const flag = `TEST_${envFlag.toUpperCase()}`;
const enabled = !/^(|0|false)$/iu.test(process.env[flag] ?? '');
const enabled = !/^(?:0|false)?$/iu.test(process.env[flag] ?? '');
return enabled ? describe : describe.skip;
}
@ -316,7 +316,7 @@ export function mockFileSystem(rootFilepath?: string, time?: Date): { data: any
return mockFs.createWriteStream(path);
},
async realpath(path: string): Promise<string> {
return await mockFs.promises.realpath(path);
return mockFs.promises.realpath(path);
},
async stat(path: string): Promise<Stats> {
return mockFs.promises.lstat(await mockFs.promises.realpath(path));
@ -334,7 +334,7 @@ export function mockFileSystem(rootFilepath?: string, time?: Date): { data: any
await mockFs.promises.rm(path);
},
async readdir(path: string): Promise<string[]> {
return await mockFs.promises.readdir(path);
return mockFs.promises.readdir(path);
},
async* opendir(path: string): AsyncIterableIterator<Dirent> {
for await (const entry of mockFs.promises.opendir(path)) {
@ -345,7 +345,7 @@ export function mockFileSystem(rootFilepath?: string, time?: Date): { data: any
await mockFs.promises.mkdir(path);
},
async readFile(path: string): Promise<string> {
return await mockFs.promises.readFile(path);
return mockFs.promises.readFile(path);
},
async writeFile(path: string, data: string): Promise<void> {
await mockFs.promises.writeFile(path, data);