Skip to content

Commit

Permalink
part: set up overridable options
Browse files Browse the repository at this point in the history
  • Loading branch information
RebeccaStevens committed Apr 22, 2024
1 parent 0dc490d commit 2a8bbbc
Show file tree
Hide file tree
Showing 5 changed files with 126 additions and 1 deletion.
3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,8 @@
"deepmerge-ts": "^5.1.0",
"escape-string-regexp": "^4.0.0",
"is-immutable-type": "^3.1.0",
"ts-api-utils": "^1.3.0"
"ts-api-utils": "^1.3.0",
"ts-declaration-location": "^1.0.0"
},
"devDependencies": {
"@babel/eslint-parser": "7.24.1",
Expand Down
3 changes: 3 additions & 0 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions src/options/index.ts
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
export * from "./ignore";
export * from "./overrides";
68 changes: 68 additions & 0 deletions src/options/overrides.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
import { type TSESTree } from "@typescript-eslint/utils";
import { type RuleContext } from "@typescript-eslint/utils/ts-eslint";
import typeMatchesSpecifier, {
type TypeDeclarationSpecifier,
} from "ts-declaration-location";

import { getTypeOfNode } from "../utils/rule";

/**
* Options that can be overridden.
*/
export type OverridableOptions<CoreOptions> = CoreOptions & {
overrides?: Array<
{
specifiers: TypeDeclarationSpecifier | TypeDeclarationSpecifier[];
} & (
| {
options: CoreOptions;
disable?: false;
}
| {
disable: true;
}
)
>;
};

/**
* Get the core options to use, taking into account overrides.
*
* @throws when there is a configuration error.
*/
export function getCoreOptions<
CoreOptions extends object,
Options extends readonly [Readonly<OverridableOptions<CoreOptions>>],
>(
node: TSESTree.Node,
context: Readonly<RuleContext<string, Options>>,
options: Readonly<Options>,
): CoreOptions | null {
const [optionsObject] = options;

const program = context.sourceCode.parserServices?.program ?? undefined;
if (program === undefined) {
return optionsObject;
}

const type = getTypeOfNode(node, context);
const found = optionsObject.overrides?.find((override) =>
(Array.isArray(override.specifiers)
? override.specifiers
: [override.specifiers]
).some((specifier) => typeMatchesSpecifier(program, specifier, type)),
);

if (found !== undefined) {
if (found.disable === true) {
return null;
}
if (found.options === undefined) {
// eslint-disable-next-line functional/no-throw-statements
throw new Error("Configuration error: No options found for override.");
}
return found.options;
}

return optionsObject;
}
52 changes: 52 additions & 0 deletions src/utils/schemas.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
import { type JSONSchema4 } from "@typescript-eslint/utils/json-schema";

const typeSpecifierSchema: JSONSchema4 = {
oneOf: [
{
type: "object",
properties: {
from: {
type: "string",
enum: ["file"],
},
path: {
type: "string",
},
},
additionalProperties: false,
},
{
type: "object",
properties: {
from: {
type: "string",
enum: ["lib"],
},
},
additionalProperties: false,
},
{
type: "object",
properties: {
from: {
type: "string",
enum: ["package"],
},
package: {
type: "string",
},
},
additionalProperties: false,
},
],
};

export const typeSpecifiersSchema: JSONSchema4 = {
oneOf: [
{
type: "array",
items: typeSpecifierSchema,
},
typeSpecifierSchema,
],
};

0 comments on commit 2a8bbbc

Please sign in to comment.