UNPKG

stylelint

Version:

A mighty CSS linter that helps you avoid errors and enforce conventions.

850 lines (779 loc) 25.3 kB
import type * as PostCSS from 'postcss'; import type { GlobbyOptions } from 'globby'; import type * as Cosmiconfig from 'cosmiconfig'; type ConfigExtends = string | string[]; type ConfigPlugins = string | stylelint.Plugin | (string | stylelint.Plugin)[]; type ConfigIgnoreFiles = string | string[]; type ConfigRules = { [ruleName: string]: stylelint.ConfigRuleSettings<any, Object>; }; type ConfigOverride = Omit<stylelint.Config, 'overrides'> & { files: string | string[]; }; type ConfigProcessors = string[]; type DisableSettings = stylelint.ConfigRuleSettings<boolean, stylelint.DisableOptions>; // A meta-type that returns a union over all properties of `T` whose values // have type `U`. type PropertyNamesOfType<T, U> = { [K in keyof T]-?: T[K] extends U ? K : never; }[keyof T]; type FileCache = { calcHashOfConfig: (config: stylelint.Config) => void; hasFileChanged: (absoluteFilepath: string) => boolean; reconcile: () => void; destroy: () => void; removeEntry: (absoluteFilepath: string) => void; }; type EmptyResult = { root: { nodes?: undefined; source: { lang?: undefined; input: { file?: string; }; }; }; messages: PostCSS.Message[]; opts: undefined; }; // Note: With strict function types enabled, function signatures are checked contravariantly. // This means that it would not be possible for rule authors to narrow the message function // parameters to e.g. just `string`. Declaring the type for rule message functions through // method declarations tricks TypeScript into bivariant signature checking. More details can // be found here: https://stackoverflow.com/questions/52667959/what-is-the-purpose-of-bivariancehack-in-typescript-types. // and in the original discussion: https://github.com/stylelint/stylelint/pull/6147#issuecomment-1155337016. type RuleMessageFunc = { bivariance(...args: (string | number | boolean | RegExp)[]): string; }['bivariance']; type RuleSeverityFunc = { bivariance(...args: (string | number | boolean | RegExp)[]): stylelint.Severity | null; }['bivariance']; type RuleOptionsPossibleFunc = (value: unknown) => boolean; type DisableReportEntry = { source?: string; ranges: stylelint.DisableReportRange[]; }; declare namespace stylelint { /** * Rule severity. */ export type Severity = 'warning' | 'error'; /** * A Stylelint plugin. */ export type Plugin = | { default?: { ruleName: string; rule: Rule } } | { ruleName: string; rule: Rule }; /** @internal */ export type ConfigRuleSettings<T, O extends Object> = | null | undefined | NonNullable<T> | [NonNullable<T>] | [NonNullable<T>, O]; /** @internal */ export type DisableOptions = { except?: (string | RegExp)[]; severity?: Severity; }; /** * Configuration. */ export type Config = { extends?: ConfigExtends; plugins?: ConfigPlugins; pluginFunctions?: { [pluginName: string]: Rule; }; ignoreFiles?: ConfigIgnoreFiles; ignorePatterns?: string; rules?: ConfigRules; quiet?: boolean; defaultSeverity?: Severity; ignoreDisables?: DisableSettings; reportNeedlessDisables?: DisableSettings; reportInvalidScopeDisables?: DisableSettings; reportDescriptionlessDisables?: DisableSettings; configurationComment?: string; overrides?: ConfigOverride[]; customSyntax?: CustomSyntax; processors?: ConfigProcessors; /** @internal */ _processorFunctions?: Map<string, ReturnType<Processor>['postprocess']>; allowEmptyInput?: boolean; cache?: boolean; fix?: boolean; }; /** @internal */ export type DisablePropertyName = PropertyNamesOfType<Config, DisableSettings>; /** @internal */ export type CosmiconfigResult = Cosmiconfig.CosmiconfigResult<Config>; /** @internal */ export type DisabledRange = { comment: PostCSS.Comment; start: number; strictStart: boolean; end?: number; strictEnd?: boolean; rules?: string[]; description?: string; }; /** @internal */ export type DisabledRangeObject = { [ruleName: string]: DisabledRange[]; }; /** @internal */ export type DisabledWarning = { line: number; rule: string }; /** @internal */ export type StylelintPostcssResult = { ruleSeverities: { [ruleName: string]: RuleSeverity }; customMessages: { [ruleName: string]: RuleMessage }; ruleMetadata: { [ruleName: string]: Partial<RuleMeta> }; quiet?: boolean; disabledRanges: DisabledRangeObject; disabledWarnings?: DisabledWarning[]; ignored?: boolean; stylelintError?: boolean; stylelintWarning?: boolean; disableWritingFix?: boolean; config?: Config; }; /** @internal */ export type WarningOptions = PostCSS.WarningOptions & { stylelintType?: string; severity?: Severity; rule?: string; }; /** @internal */ export type PostcssResult = (PostCSS.Result | EmptyResult) & { stylelint: StylelintPostcssResult; warn(message: string, options?: WarningOptions): void; }; /** @internal */ export type Formatter = (results: LintResult[], returnValue: LinterResult) => string; type Formatters = { readonly compact: Promise<Formatter>; readonly github: Promise<Formatter>; readonly json: Promise<Formatter>; readonly string: Promise<Formatter>; readonly tap: Promise<Formatter>; readonly unix: Promise<Formatter>; readonly verbose: Promise<Formatter>; }; /** @internal */ export type FormatterType = keyof Formatters; /** @internal */ export type CustomSyntax = string | PostCSS.Syntax; /** * WARNING: This is an experimental feature. The API may change in the future. */ export type Processor = () => { name: string; postprocess: (result: LintResult, root?: PostCSS.Root) => void; }; /** @internal */ export type RuleMessage = string | RuleMessageFunc; /** @internal */ export type RuleMessages = { [message: string]: RuleMessage }; /** @internal */ export type RuleOptionsPossible = boolean | number | string | RuleOptionsPossibleFunc; /** @internal */ export type RuleOptions = { actual: unknown; possible?: | RuleOptionsPossibleFunc | RuleOptionsPossible[] | Record<string, RuleOptionsPossible[]>; optional?: boolean; }; /** @internal */ type RuleSeverity = Severity | RuleSeverityFunc; /** * A rule context. */ export type RuleContext = { configurationComment?: string | undefined; fix?: boolean | undefined; newline?: string | undefined; }; /** @internal */ export type RuleBase<P = any, S = any> = ( primaryOption: P, secondaryOptions: Record<string, S>, context: RuleContext, ) => (root: PostCSS.Root, result: PostcssResult) => Promise<void> | void; /** @internal */ export type RuleMeta = { url: string; deprecated?: boolean; fixable?: boolean; }; /** * A rule. */ export type Rule<P = any, S = any> = RuleBase<P, S> & { ruleName: string; messages: RuleMessages; primaryOptionArray?: boolean; meta?: RuleMeta; }; type BuiltInRules = { readonly 'alpha-value-notation': Promise<Rule>; readonly 'annotation-no-unknown': Promise<Rule>; readonly 'at-rule-allowed-list': Promise<Rule>; readonly 'at-rule-disallowed-list': Promise<Rule>; readonly 'at-rule-empty-line-before': Promise<Rule>; readonly 'at-rule-no-unknown': Promise<Rule>; readonly 'at-rule-no-vendor-prefix': Promise<Rule>; readonly 'at-rule-property-required-list': Promise<Rule>; readonly 'block-no-empty': Promise<Rule>; readonly 'color-function-notation': Promise<Rule>; readonly 'color-hex-alpha': Promise<Rule>; readonly 'color-hex-length': Promise<Rule>; readonly 'color-named': Promise<Rule>; readonly 'color-no-hex': Promise<Rule>; readonly 'color-no-invalid-hex': Promise<Rule>; readonly 'comment-empty-line-before': Promise<Rule>; readonly 'comment-no-empty': Promise<Rule>; readonly 'comment-pattern': Promise<Rule>; readonly 'comment-whitespace-inside': Promise<Rule>; readonly 'comment-word-disallowed-list': Promise<Rule>; readonly 'custom-media-pattern': Promise<Rule>; readonly 'custom-property-empty-line-before': Promise<Rule>; readonly 'custom-property-no-missing-var-function': Promise<Rule>; readonly 'custom-property-pattern': Promise<Rule>; readonly 'declaration-block-no-duplicate-custom-properties': Promise<Rule>; readonly 'declaration-block-no-duplicate-properties': Promise<Rule>; readonly 'declaration-block-no-redundant-longhand-properties': Promise<Rule>; readonly 'declaration-block-no-shorthand-property-overrides': Promise<Rule>; readonly 'declaration-block-single-line-max-declarations': Promise<Rule>; readonly 'declaration-empty-line-before': Promise<Rule>; readonly 'declaration-no-important': Promise<Rule>; readonly 'declaration-property-max-values': Promise<Rule>; readonly 'declaration-property-unit-allowed-list': Promise<Rule>; readonly 'declaration-property-unit-disallowed-list': Promise<Rule>; readonly 'declaration-property-value-allowed-list': Promise<Rule>; readonly 'declaration-property-value-disallowed-list': Promise<Rule>; readonly 'declaration-property-value-no-unknown': Promise<Rule>; readonly 'font-family-name-quotes': Promise<Rule>; readonly 'font-family-no-duplicate-names': Promise<Rule>; readonly 'font-family-no-missing-generic-family-keyword': Promise<Rule>; readonly 'font-weight-notation': Promise<Rule>; readonly 'function-allowed-list': Promise<Rule>; readonly 'function-calc-no-unspaced-operator': Promise<Rule>; readonly 'function-disallowed-list': Promise<Rule>; readonly 'function-linear-gradient-no-nonstandard-direction': Promise<Rule>; readonly 'function-name-case': Promise<Rule>; readonly 'function-no-unknown': Promise<Rule>; readonly 'function-url-no-scheme-relative': Promise<Rule>; readonly 'function-url-quotes': Promise<Rule>; readonly 'function-url-scheme-allowed-list': Promise<Rule>; readonly 'function-url-scheme-disallowed-list': Promise<Rule>; readonly 'hue-degree-notation': Promise<Rule>; readonly 'import-notation': Promise<Rule>; readonly 'keyframe-block-no-duplicate-selectors': Promise<Rule>; readonly 'keyframe-declaration-no-important': Promise<Rule>; readonly 'keyframe-selector-notation': Promise<Rule>; readonly 'keyframes-name-pattern': Promise<Rule>; readonly 'length-zero-no-unit': Promise<Rule>; readonly 'lightness-notation': Promise<Rule>; readonly 'max-nesting-depth': Promise<Rule>; readonly 'media-feature-name-allowed-list': Promise<Rule>; readonly 'media-feature-name-disallowed-list': Promise<Rule>; readonly 'media-feature-name-no-unknown': Promise<Rule>; readonly 'media-feature-name-no-vendor-prefix': Promise<Rule>; readonly 'media-feature-name-unit-allowed-list': Promise<Rule>; readonly 'media-feature-name-value-allowed-list': Promise<Rule>; readonly 'media-feature-name-value-no-unknown': Promise<Rule>; readonly 'media-feature-range-notation': Promise<Rule>; readonly 'media-query-no-invalid': Promise<Rule>; readonly 'named-grid-areas-no-invalid': Promise<Rule>; readonly 'no-descending-specificity': Promise<Rule>; readonly 'no-duplicate-at-import-rules': Promise<Rule>; readonly 'no-duplicate-selectors': Promise<Rule>; readonly 'no-empty-source': Promise<Rule>; readonly 'no-invalid-double-slash-comments': Promise<Rule>; readonly 'no-invalid-position-at-import-rule': Promise<Rule>; readonly 'no-irregular-whitespace': Promise<Rule>; readonly 'no-unknown-animations': Promise<Rule>; readonly 'no-unknown-custom-media': Promise<Rule>; readonly 'no-unknown-custom-properties': Promise<Rule>; readonly 'number-max-precision': Promise<Rule>; readonly 'property-allowed-list': Promise<Rule>; readonly 'property-disallowed-list': Promise<Rule>; readonly 'property-no-unknown': Promise<Rule>; readonly 'property-no-vendor-prefix': Promise<Rule>; readonly 'rule-empty-line-before': Promise<Rule>; readonly 'rule-selector-property-disallowed-list': Promise<Rule>; readonly 'selector-anb-no-unmatchable': Promise<Rule>; readonly 'selector-attribute-name-disallowed-list': Promise<Rule>; readonly 'selector-attribute-operator-allowed-list': Promise<Rule>; readonly 'selector-attribute-operator-disallowed-list': Promise<Rule>; readonly 'selector-attribute-quotes': Promise<Rule>; readonly 'selector-class-pattern': Promise<Rule>; readonly 'selector-combinator-allowed-list': Promise<Rule>; readonly 'selector-combinator-disallowed-list': Promise<Rule>; readonly 'selector-disallowed-list': Promise<Rule>; readonly 'selector-id-pattern': Promise<Rule>; readonly 'selector-max-attribute': Promise<Rule>; readonly 'selector-max-class': Promise<Rule>; readonly 'selector-max-combinators': Promise<Rule>; readonly 'selector-max-compound-selectors': Promise<Rule>; readonly 'selector-max-id': Promise<Rule>; readonly 'selector-max-pseudo-class': Promise<Rule>; readonly 'selector-max-specificity': Promise<Rule>; readonly 'selector-max-type': Promise<Rule>; readonly 'selector-max-universal': Promise<Rule>; readonly 'selector-nested-pattern': Promise<Rule>; readonly 'selector-no-qualifying-type': Promise<Rule>; readonly 'selector-no-vendor-prefix': Promise<Rule>; readonly 'selector-not-notation': Promise<Rule>; readonly 'selector-pseudo-class-allowed-list': Promise<Rule>; readonly 'selector-pseudo-class-disallowed-list': Promise<Rule>; readonly 'selector-pseudo-class-no-unknown': Promise<Rule>; readonly 'selector-pseudo-element-allowed-list': Promise<Rule>; readonly 'selector-pseudo-element-colon-notation': Promise<Rule>; readonly 'selector-pseudo-element-disallowed-list': Promise<Rule>; readonly 'selector-pseudo-element-no-unknown': Promise<Rule>; readonly 'selector-type-case': Promise<Rule>; readonly 'selector-type-no-unknown': Promise<Rule>; readonly 'shorthand-property-no-redundant-values': Promise<Rule>; readonly 'string-no-newline': Promise<Rule>; readonly 'time-min-milliseconds': Promise<Rule>; readonly 'unit-allowed-list': Promise<Rule>; readonly 'unit-disallowed-list': Promise<Rule>; readonly 'unit-no-unknown': Promise<Rule>; readonly 'value-keyword-case': Promise<Rule>; readonly 'value-no-vendor-prefix': Promise<Rule>; }; /** @internal */ export type GetPostcssOptions = { code?: string; codeFilename?: string; filePath?: string; customSyntax?: CustomSyntax; }; /** @internal */ export type GetLintSourceOptions = GetPostcssOptions & { existingPostcssResult?: PostCSS.Result; cache?: boolean; }; /** * Linter options. */ export type LinterOptions = { files?: string | string[]; globbyOptions?: GlobbyOptions; cache?: boolean; cacheLocation?: string; cacheStrategy?: string; code?: string; codeFilename?: string; config?: Config; configFile?: string; configBasedir?: string; /** * The working directory to resolve files from. Defaults to the * current working directory. */ cwd?: string; ignoreDisables?: boolean; ignorePath?: string | string[]; ignorePattern?: string[]; reportDescriptionlessDisables?: boolean; reportNeedlessDisables?: boolean; reportInvalidScopeDisables?: boolean; maxWarnings?: number; customSyntax?: CustomSyntax; formatter?: FormatterType | Formatter; disableDefaultIgnores?: boolean; fix?: boolean; allowEmptyInput?: boolean; quiet?: boolean; quietDeprecationWarnings?: boolean; }; /** * A CSS syntax error. */ export type CssSyntaxError = { file?: string; input: { column: number; file?: string; line: number; source: string; }; /** * The line of the inclusive start position of the error. */ line: number; /** * The column of the inclusive start position of the error. */ column: number; /** * The line of the exclusive end position of the error. */ endLine?: number; /** * The column of the exclusive end position of the error. */ endColumn?: number; message: string; name: string; reason: string; source: string; }; /** * A lint warning. */ export type Warning = { /** * The line of the inclusive start position of the warning. */ line: number; /** * The column of the inclusive start position of the warning. */ column: number; /** * The line of the exclusive end position of the warning. */ endLine?: number; /** * The column of the exclusive end position of the warning. */ endColumn?: number; rule: string; severity: Severity; text: string; stylelintType?: string; }; /** * A lint result. */ export type LintResult = { source?: string; deprecations: { text: string; reference?: string; }[]; invalidOptionWarnings: { text: string; }[]; parseErrors: (PostCSS.Warning & { stylelintType: string })[]; errored?: boolean; warnings: Warning[]; ignored?: boolean; /** * Internal use only. Do not use or rely on this property. It may * change at any time. * @internal */ _postcssResult?: PostcssResult; }; /** @internal */ export type DisableReportRange = { rule: string; start: number; end?: number; }; /** * A linter result. */ export type LinterResult = { /** * The working directory from which the linter was run when the * results were generated. */ cwd: string; results: LintResult[]; errored: boolean; /** * @deprecated Use `report` for the formatted problems, or use `code` * for the autofixed code instead. This will be removed in the next major version. */ output: string; /** @internal To show the deprecation warning. */ _output?: string; /** @internal To show the deprecation warning. */ _outputWarned?: boolean; /** * A string that contains the formatted problems. */ report: string; /** * A string that contains the autofixed code, if the `fix` option is set to `true` * and the `code` option is provided. */ code?: string; maxWarningsExceeded?: { maxWarnings: number; foundWarnings: number; }; reportedDisables: DisableOptionsReport; descriptionlessDisables?: DisableOptionsReport; needlessDisables?: DisableOptionsReport; invalidScopeDisables?: DisableOptionsReport; /** * Each rule metadata by name. */ ruleMetadata: { [ruleName: string]: Partial<RuleMeta> }; }; /** * A lint problem. */ export type Problem = { ruleName: string; result: PostcssResult; message: RuleMessage; messageArgs?: Parameters<RuleMessageFunc> | undefined; node: PostCSS.Node; /** * The inclusive start index of the problem, relative to the node's * source text. */ index?: number; /** * The exclusive end index of the problem, relative to the node's * source text. */ endIndex?: number; /** * The inclusive start position of the problem, relative to the * node's source text. If provided, this will be used instead of * `index`. */ start?: { line: number; column: number; }; /** * The exclusive end position of the problem, relative to the * node's source text. If provided, this will be used instead of * `endIndex`. */ end?: { line: number; column: number; }; word?: string; line?: number; /** * Optional severity override for the problem. */ severity?: RuleSeverity; }; /** @internal */ export type ShorthandProperties = | 'animation' | 'background' | 'border' | 'border-block' | 'border-block-end' | 'border-block-start' | 'border-inline' | 'border-inline-end' | 'border-inline-start' | 'border-bottom' | 'border-color' | 'border-image' | 'border-inline-end' | 'border-inline-start' | 'border-left' | 'border-radius' | 'border-right' | 'border-style' | 'border-top' | 'border-width' | 'column-rule' | 'columns' | 'flex' | 'flex-flow' | 'font' | 'font-synthesis' | 'gap' | 'grid' | 'grid-area' | 'grid-column' | 'grid-gap' | 'grid-row' | 'grid-template' | 'inset' | 'inset-block' | 'inset-inline' | 'list-style' | 'margin' | 'margin-block' | 'margin-inline' | 'mask' | 'outline' | 'overflow' | 'overscroll-behavior' | 'padding' | 'padding-block' | 'padding-inline' | 'place-content' | 'place-items' | 'place-self' | 'scroll-margin' | 'scroll-margin-block' | 'scroll-margin-inline' | 'scroll-padding' | 'scroll-padding-block' | 'scroll-padding-inline' | 'text-decoration' | 'text-emphasis' | 'transition'; /** @internal */ export type LonghandSubPropertiesOfShorthandProperties = ReadonlyMap< ShorthandProperties, ReadonlySet<string> >; /** * Utility functions. */ export type Utils = { /** * Report a problem. * * This function accounts for `disabledRanges` attached to the result. * That is, if the reported problem is within a disabledRange, * it is ignored. Otherwise, it is attached to the result as a * postcss warning. * * It also accounts for the rule's severity. * * You *must* pass *either* a node or a line number. * * @param problem - A problem */ report: (problem: Problem) => void; /** * Given an object of problem messages, return another * that provides the same messages postfixed with the rule * that has been violated. * * @param ruleName - A rule name * @param messages - An object whose keys are message identifiers * and values are either message strings or functions that return message strings * @returns New message object, whose messages will be marked with the rule name */ ruleMessages: <T extends RuleMessages, R extends { [K in keyof T]: T[K] }>( ruleName: string, messages: T, ) => R; /** * Validate a rule's options. * * See existing rules for examples. * * @param result - PostCSS result * @param ruleName - A rule name * @param optionDescriptions - Each optionDescription can have the following properties: * - `actual` (required): the actual passed option value or object. * - `possible` (required): a schema representation of what values are * valid for those options. `possible` should be an object if the * options are an object, with corresponding keys; if the options are not an * object, `possible` isn't, either. All `possible` value representations * should be **arrays of either values or functions**. Values are === checked * against `actual`. Functions are fed `actual` as an argument and their * return value is interpreted: truthy = valid, falsy = invalid. * - `optional` (optional): If this is `true`, `actual` can be undefined. * @returns Whether or not the options are valid (`true` = valid) */ validateOptions: ( result: PostcssResult, ruleName: string, ...optionDescriptions: RuleOptions[] ) => boolean; /** * Useful for third-party code (e.g. plugins) to run a PostCSS Root * against a specific rule and do something with the warnings. */ checkAgainstRule: <T, O extends Object>( options: { ruleName: string; ruleSettings: ConfigRuleSettings<T, O>; root: PostCSS.Root; result?: PostcssResult; context?: RuleContext; }, callback: (warning: PostCSS.Warning) => void, ) => Promise<void>; }; /** * Internal use only. Do not use or rely on this type. It may change at * any time. * @internal */ export type InternalApi = { _options: LinterOptions & { cwd: string }; _extendExplorer: Cosmiconfig.PublicExplorer; _specifiedConfigCache: Map<Config, Promise<CosmiconfigResult>>; _postcssResultCache: Map<string, PostCSS.Result>; _fileCache: FileCache; }; /** @internal */ export type DisableOptionsReport = DisableReportEntry[]; /** @internal */ export type PostcssPluginOptions = Omit<LinterOptions, 'customSyntax'> | Config; /** * The Stylelint public API. */ export type PublicApi = PostCSS.PluginCreator<PostcssPluginOptions> & { /** * Runs Stylelint with the given options and returns a Promise that * resolves to the results. * * @param options - A lint options object * @returns A lint result */ lint: (options: LinterOptions) => Promise<LinterResult>; /** * Available rules. */ rules: BuiltInRules; /** * Result report formatters by name. */ formatters: Formatters; /** * Creates a Stylelint plugin. */ createPlugin: (ruleName: string, rule: Rule) => Plugin; /** * The Stylelint "internal API" is passed among functions * so that methods on a Stylelint instance can invoke * each other while sharing options and caches. * * @internal */ _createLinter: (options: LinterOptions) => InternalApi; /** * Resolves the effective configuration for a given file. Resolves to * `undefined` if no config is found. * * @param filePath - The path to the file to get the config for. * @param options - The options to use when creating the Stylelint instance. * @returns A resolved config or `undefined`. */ resolveConfig: ( filePath: string, options?: Pick<LinterOptions, 'cwd' | 'config' | 'configBasedir' | 'configFile'>, ) => Promise<Config | undefined>; /** * Utility functions. */ utils: Utils; /** * Reference objects. */ reference: { longhandSubPropertiesOfShorthandProperties: LonghandSubPropertiesOfShorthandProperties; }; }; } declare const stylelint: stylelint.PublicApi; export = stylelint;