stylelint-vitest-rule-tester
Version:
Styelint rule tester with Vitest.
342 lines (341 loc) • 9.92 kB
text/typescript
import { Awaitable, unindent } from "@ntnyq/utils";
import stylelint, { LinterOptions } from "stylelint";
import { Warning } from "postcss";
//#region src/types/stylelint.d.ts
type StylelintLinterResult = Omit<stylelint.LinterResult, 'cwd' | 'report'>;
/**
* @pg
*/
type LintResultDeprecation = {
text: string;
reference?: string;
};
type LintResultInvalidOptionWarning = {
text: string;
};
type LintResultParseError = Warning & {
stylelintType: 'parseError';
};
type LintResultWarning = stylelint.Warning;
/**
* @pg
*/
type LintResultMessage = LintResultDeprecation | LintResultInvalidOptionWarning | LintResultParseError | LintResultWarning;
/**
* Stylelint options
*/
interface StylelintOptions<RuleOptions = any> {
/**
* linter options for `stylelint.lint(options)`
*/
linterOptions?: stylelint.LinterOptions;
/**
* rule options
*/
ruleOptions?: RuleOptions;
/**
* stylelint config
*/
stylelintConfig?: stylelint.Config;
}
//#endregion
//#region src/types/test.d.ts
/**
* Test case options
*/
interface TestCasesOptions<RuleOptions = any> {
/**
* invalid cases
*/
invalid?: (string | InvalidTestCase<RuleOptions>)[];
/**
* valid cases
*/
valid?: (string | ValidTestCase<RuleOptions>)[];
/**
* callback to be called after each test case
*/
onResult?: (testCase: NormalizedTestCase<RuleOptions>, result: TestExecutionResult) => Promise<void> | void;
}
/**
* Test execution result
*/
type TestExecutionResult = StylelintLinterResult & {
/**
* whether the code was fixed
*/
fixed?: boolean;
/**
* if the rule fixes in multiple steps, the result of each step is present here
*/
steps?: StylelintLinterResult[];
};
//#endregion
//#region src/types/file.d.ts
/**
* default filename when not provided
*/
interface DefaultFilenames {
css: string;
less: string;
postcss: string;
sass: string;
scss: string;
styl: string;
stylus: string;
[key: string]: string;
}
//#endregion
//#region src/types/tester.d.ts
/**
* Rule tester behavior options
*/
type RuleTesterBehaviorOptions = {
/**
* the number of times to recursively apply the rule
*
* @default 10
*/
recursive?: false | number;
/**
* run verification after applying the fix
*
* @default true
*/
verifyAfterFix?: boolean;
/**
* verify that fix allways changes the code
*
* @default true
*/
verifyFixChanges?: boolean;
};
/**
* Rule tester init options
*/
type RuleTesterInitOptions<RuleOptions = any> = RuleTesterBehaviorOptions & StylelintOptions<RuleOptions> & {
/**
* rule name to test
*/
name: string;
/**
* default filenames to be used for tests
*/
defaultFileNames?: Partial<DefaultFilenames>;
};
/**
* Rule Tester
* @pg
*/
interface RuleTester<RuleOptions = any> {
/**
* run multiple test cases
*/
run: (options: TestCasesOptions<RuleOptions>) => Promise<void>;
/**
* run a single test case
*/
each: (arg: TestCase) => Promise<{
result: TestExecutionResult;
testcase: NormalizedTestCase<RuleOptions>;
}>;
/**
* run a single invalid test case
*/
invalid: (arg: InvalidTestCase) => Promise<{
result: TestExecutionResult;
testcase: NormalizedTestCase<RuleOptions>;
}>;
/**
* run a single valid test case
*/
valid: (arg: ValidTestCase) => Promise<{
result: TestExecutionResult;
testcase: NormalizedTestCase<RuleOptions>;
}>;
}
//#endregion
//#region src/types/case.d.ts
/**
* Invalid test case
*/
type InvalidTestCase<RuleOptions = any> = string | InvalidTestCaseBase<RuleOptions>;
type InvalidTestCaseBase<RuleOptions = any> = ValidTestCaseBase<RuleOptions> & {
/**
* expect for {@link LintResultDeprecation}
*/
deprecations?: number | (string | LintResultDeprecation)[] | ((deprecations: LintResultDeprecation[]) => Awaitable<void>);
/**
* expect for {@link LintResultInvalidOptionWarning}
*/
invalidOptionWarnings?: number | (string | LintResultInvalidOptionWarning)[] | ((invalidOptionWarnings: LintResultInvalidOptionWarning[]) => Awaitable<void>);
/**
* Assert if output is expected.
* Pass `null` to assert that the output is the same as the input.
*/
output?: string | ((output: string, input: string) => Awaitable<void>) | null;
/**
* expect for {@link LintResultParseError}
*/
parseErrors?: number | (string | LintResultParseError)[] | ((parseErrors: LintResultParseError[]) => Awaitable<void>);
/**
* expect for {@link LintResultWarning}
*/
warnings?: number | (string | LintResultWarning)[] | ((warnings: LintResultWarning[]) => Awaitable<void>);
};
/**
* Valid test case
*/
type ValidTestCase<RuleOptions = any> = string | ValidTestCaseBase<RuleOptions>;
type ValidTestCaseBase<RuleOptions = any> = RuleTesterBehaviorOptions & StylelintOptions<RuleOptions> & {
/**
* code to test
*/
code: string;
/**
* test case description
*/
description?: string;
/**
* test case filename
*/
filename?: string;
/**
* test case name
*/
name?: string;
/**
* only run this test case
*/
only?: boolean;
/**
* skip this test case
*/
skip?: boolean;
/**
* hook after run test case
*/
after?: (this: NormalizedTestCase<RuleOptions>, result: TestExecutionResult) => Awaitable<void>;
/**
* hook before run test case
*/
before?: (this: NormalizedTestCase<RuleOptions>, linterOptions: LinterOptions) => Awaitable<void>;
};
/**
* Test case
* @pg
*/
type TestCase<RuleOptions = any> = InvalidTestCase<RuleOptions> | ValidTestCase<RuleOptions>;
/**
* Normalized test case
* @pg
*/
type NormalizedTestCase<RuleOptions = any> = InvalidTestCaseBase<RuleOptions> & {
code: string;
filename: string;
type: 'invalid' | 'valid';
};
//#endregion
//#region src/run.d.ts
/**
* Shortcut to run test cases for a rule
*/
declare function run<RuleOptions = any>(options: TestCasesOptions<RuleOptions> & RuleTesterInitOptions<RuleOptions>): Promise<void>;
/**
* Shortcut to run test cases for a rule in classic style
*/
declare function runClassic<RuleOptions = any>(ruleName: string, cases: TestCasesOptions<RuleOptions>, options?: RuleTesterInitOptions<RuleOptions>): Promise<void>;
//#endregion
//#region src/utils/resolveRuleMeta.d.ts
/**
* Resolve rule meta by tester options
* @param options - tester options
* @returns a promise resolved rule meta or undefined
*/
declare function resolveRuleMeta(options: RuleTesterInitOptions): Promise<stylelint.RuleMeta | undefined>;
//#endregion
//#region src/utils/normalizeTestCase.d.ts
/**
* Normalize test case
*
* @param testCase - test case
* @param defaultFilenames - given default file name
* @param type - case type
* @returns normalized test case
*/
declare function normalizeTestCase<RuleOptions = any>(testCase: TestCase<RuleOptions>, defaultFilenames: Partial<DefaultFilenames>, type?: 'valid' | 'invalid'): NormalizedTestCase<RuleOptions>;
//#endregion
//#region src/utils/resolveRuleOptions.d.ts
/**
* Normalize rule options
*
* @param testCase - test case
* @param options - tester options
* @returns normalized rule option
*/
declare function resolveRuleOptions(testCase: NormalizedTestCase, options: RuleTesterInitOptions, ruleMeta?: stylelint.RuleMeta): any[];
//#endregion
//#region src/utils/validateLintResult.d.ts
declare function validateLintResult(testCase: NormalizedTestCase, lintResult: stylelint.LintResult): Promise<void>;
//#endregion
//#region src/utils/normalizeCaseMessage.d.ts
/**
* Normalize test case message
*
* @param message - message string or lint result
* @returns normalized message
*/
declare function normalizeCaseMessage(message: string | LintResultMessage): Partial<LintResultMessage>;
//#endregion
//#region src/utils/resolveLinterOptions.d.ts
/**
* Resolve linter options of stylelint
*
* @param options - tester init options
* @param testCase - normalized test case
* @returns resolved linter options
*/
declare function resolveLinterOptions(options: RuleTesterInitOptions, testCase: NormalizedTestCase, ruleOptions: any): stylelint.LinterOptions;
//#endregion
//#region src/utils/normalizeLinterResult.d.ts
/**
* Normalize linter result
*
* @param result - linter result {@link Stylelint.LinterResult}
*/
declare function normalizeLinterResult(result: stylelint.LinterResult): {
results: {
deprecations: {
text: string;
reference?: string;
}[];
invalidOptionWarnings: {
text: string;
}[];
parseErrors: (import("postcss").Warning & {
stylelintType: Extract<stylelint.StylelintWarningType, "parseError">;
})[];
errored?: boolean;
warnings: stylelint.Warning[];
ignored?: boolean;
autofixed?: boolean;
}[];
errored: boolean;
code?: string;
maxWarningsExceeded?: {
maxWarnings: number;
foundWarnings: number;
};
reportedDisables: stylelint.DisableOptionsReport;
descriptionlessDisables?: stylelint.DisableOptionsReport;
needlessDisables?: stylelint.DisableOptionsReport;
invalidScopeDisables?: stylelint.DisableOptionsReport;
ruleMetadata: {
[ruleName: string]: Partial<stylelint.RuleMeta>;
};
};
//#endregion
//#region src/tester.d.ts
declare function createRuleTester<RuleOptions = any>(options: RuleTesterInitOptions<RuleOptions>): RuleTester<RuleOptions>;
//#endregion
export { unindent as $, unindent, DefaultFilenames, InvalidTestCase, InvalidTestCaseBase, LintResultDeprecation, LintResultInvalidOptionWarning, LintResultMessage, LintResultParseError, LintResultWarning, NormalizedTestCase, RuleTester, RuleTesterBehaviorOptions, RuleTesterInitOptions, StylelintLinterResult, StylelintOptions, TestCase, TestCasesOptions, TestExecutionResult, ValidTestCase, ValidTestCaseBase, createRuleTester, normalizeCaseMessage, normalizeLinterResult, normalizeTestCase, resolveLinterOptions, resolveRuleMeta, resolveRuleOptions, run, runClassic, validateLintResult };