Repository: stoplightio/spectral
Pull request #898 (2020-01-08 18:38:59)

chore: reorganize rule types declaration
Tries to tackle @philsturgeon 's comment @ https://github.com/stoplightio/spectral/pull/884/files/5375e91f368c107f59c09c47c65cd834ab011b35#r363666263

**Checklist**

- [ ] Tests added / updated
- [ ] Docs added / updated

**Does this PR introduce a breaking change?**

- [ ] Yes
- [x] No

This PR moves some type declarations back into the files that should expose them.


nulltoken: @P0lip Thanks for the in-depth explanation.

Conflicts solved, squashed and rebased.

Patch:
diff --git a/src/functions/alphabetical.ts b/src/functions/alphabetical.ts
index 566a45a3..43cf5ae5 100644
--- a/src/functions/alphabetical.ts
+++ b/src/functions/alphabetical.ts
@@ -1,5 +1,12 @@
 import { isObject } from 'lodash';
-import { IAlphaRuleOptions, IFunction, IFunctionResult } from '../types';
+import { IFunction, IFunctionResult, IRule, RuleFunction } from '../types';
+
+export interface IAlphaRuleOptions {
+  /** if sorting array of objects, which key to use for comparison */
+  keyedBy?: string;
+}
+
+export type AlphaRule = IRule<RuleFunction.ALPHABETICAL, IAlphaRuleOptions>;
 
 const compare = (a: unknown, b: unknown): number => {
   if ((typeof a === 'number' || Number.isNaN(Number(a))) && (typeof b === 'number' || !Number.isNaN(Number(b)))) {
diff --git a/src/functions/casing.ts b/src/functions/casing.ts
index 223391b1..95cfee0e 100644
--- a/src/functions/casing.ts
+++ b/src/functions/casing.ts
@@ -1,5 +1,12 @@
 import { Dictionary } from '@stoplight/types';
-import { ICasingOptions, IFunction } from '../types';
+import { IFunction, IRule, RuleFunction } from '../types';
+
+export interface ICasingOptions {
+  type: 'flat' | 'camel' | 'pascal' | 'kebab' | 'cobol' | 'snake' | 'macro';
+  disallowDigits?: boolean;
+}
+
+export type CasingRule = IRule<RuleFunction.CASING, ICasingOptions>;
 
 const CASES: Dictionary<RegExp, ICasingOptions['type']> = {
   flat: /^[a-z]+$/,
diff --git a/src/functions/enumeration.ts b/src/functions/enumeration.ts
index 210b8513..c8bcadd9 100644
--- a/src/functions/enumeration.ts
+++ b/src/functions/enumeration.ts
@@ -1,4 +1,10 @@
-import { IEnumRuleOptions, IFunction, IFunctionResult } from '../types';
+import { IFunction, IFunctionResult, IRule, RuleFunction } from '../types';
+
+export interface IEnumRuleOptions {
+  values: Array<string | number>;
+}
+
+export type EnumRule = IRule<RuleFunction.ENUM, IEnumRuleOptions>;
 
 export const enumeration: IFunction<IEnumRuleOptions> = (targetVal, opts) => {
   const results: IFunctionResult[] = [];
diff --git a/src/functions/length.ts b/src/functions/length.ts
index 6cc8e6ac..b1e71a8a 100644
--- a/src/functions/length.ts
+++ b/src/functions/length.ts
@@ -1,4 +1,11 @@
-import { IFunction, IFunctionResult, ILengthRuleOptions } from '../types';
+import { IFunction, IFunctionResult, IRule, RuleFunction } from '../types';
+
+export interface ILengthRuleOptions {
+  min?: number;
+  max?: number;
+}
+
+export type LengthRule = IRule<RuleFunction.LENGTH, ILengthRuleOptions>;
 
 export const length: IFunction<ILengthRuleOptions> = (targetVal, opts) => {
   const results: IFunctionResult[] = [];
diff --git a/src/functions/pattern.ts b/src/functions/pattern.ts
index 03a1f089..dca4fa90 100644
--- a/src/functions/pattern.ts
+++ b/src/functions/pattern.ts
@@ -1,4 +1,14 @@
-import { IFunction, IFunctionResult, IRulePatternOptions } from '../types';
+import { IFunction, IFunctionResult, IRule, RuleFunction } from '../types';
+
+export interface IRulePatternOptions {
+  /** regex that target must match */
+  match?: string;
+
+  /** regex that target must not match */
+  notMatch?: string;
+}
+
+export type PatternRule = IRule<RuleFunction.PATTERN, IRulePatternOptions>;
 
 function test(value: string, regex: RegExp | string) {
   let re;
diff --git a/src/functions/schema-path.ts b/src/functions/schema-path.ts
index e8843166..ee8f85ee 100644
--- a/src/functions/schema-path.ts
+++ b/src/functions/schema-path.ts
@@ -7,11 +7,19 @@
  * The primary use case for this was validating OpenAPI examples
  * against their schema, but this could be used for other things.
  */
-import { IFunction, ISchemaPathOptions } from '../types';
+import { IFunction, IRule, RuleFunction } from '../types';
 import { schema } from './schema';
 
 const { JSONPath } = require('jsonpath-plus');
 
+export interface ISchemaPathOptions {
+  schemaPath: string;
+  // the `path.to.prop` to field, or special `@key` value to target keys for matched `given` object
+  field?: string;
+}
+
+export type SchemaPathRule = IRule<RuleFunction.SCHEMAPATH, ISchemaPathOptions>;
+
 export const schemaPath: IFunction<ISchemaPathOptions> = (targetVal, opts, paths, otherValues) => {
   if (!targetVal || typeof targetVal !== 'object') return [];
 
diff --git a/src/functions/schema.ts b/src/functions/schema.ts
index 058702b2..7eab63a7 100644
--- a/src/functions/schema.ts
+++ b/src/functions/schema.ts
@@ -7,10 +7,16 @@ import * as jsonSpecv6 from 'ajv/lib/refs/json-schema-draft-06.json';
 import * as jsonSpecv7 from 'ajv/lib/refs/json-schema-draft-07.json';
 import { IOutputError } from 'better-ajv-errors';
 import { escapeRegExp } from 'lodash';
-import { IFunction, IFunctionResult, ISchemaOptions, JSONSchema } from '../types';
+import { IFunction, IFunctionResult, IRule, JSONSchema, RuleFunction } from '../types';
 const oasFormatValidator = require('ajv-oai/lib/format-validator');
 const betterAjvErrors = require('better-ajv-errors/lib/modern');
 
+export interface ISchemaOptions {
+  schema: object;
+}
+
+export type SchemaRule = IRule<RuleFunction.SCHEMA, ISchemaOptions>;
+
 interface IAJVOutputError extends IOutputError {
   path?: string;
 }
diff --git a/src/functions/truthy.ts b/src/functions/truthy.ts
index e3a2a024..bc86661a 100644
--- a/src/functions/truthy.ts
+++ b/src/functions/truthy.ts
@@ -1,4 +1,6 @@
-import { IFunction, IFunctionResult } from '../types';
+import { IFunction, IFunctionResult, IRule, RuleFunction } from '../types';
+
+export type TruthyRule = IRule<RuleFunction.TRUTHY>;
 
 export const truthy: IFunction = (targetVal): void | IFunctionResult[] => {
   if (!targetVal) {
diff --git a/src/functions/xor.ts b/src/functions/xor.ts
index a3205a03..32b4a334 100644
--- a/src/functions/xor.ts
+++ b/src/functions/xor.ts
@@ -1,4 +1,11 @@
-import { IFunction, IFunctionResult, IXorRuleOptions } from '../types';
+import { IFunction, IFunctionResult, IRule, RuleFunction } from '../types';
+
+export interface IXorRuleOptions {
+  /** test to verify if one (but not all) of the provided keys are present in object */
+  properties: string[];
+}
+
+export type XorRule = IRule<RuleFunction.XOR, IXorRuleOptions>;
 
 export const xor: IFunction<IXorRuleOptions> = (targetVal, opts) => {
   const results: IFunctionResult[] = [];
diff --git a/src/types/rule.ts b/src/types/rule.ts
index 5e672488..2d2ea760 100644
--- a/src/types/rule.ts
+++ b/src/types/rule.ts
@@ -1,7 +1,24 @@
 import { DiagnosticSeverity } from '@stoplight/types';
-import { RuleFunction, RuleType } from './enums';
-
-export type Rule = IRule | TruthyRule | XorRule | LengthRule | AlphaRule | PatternRule | CasingRule | SchemaRule;
+import { AlphaRule } from '../functions/alphabetical';
+import { CasingRule } from '../functions/casing';
+import { LengthRule } from '../functions/length';
+import { PatternRule } from '../functions/pattern';
+import { SchemaRule } from '../functions/schema';
+import { SchemaPathRule } from '../functions/schema-path';
+import { TruthyRule } from '../functions/truthy';
+import { XorRule } from '../functions/xor';
+import { RuleType } from './enums';
+
+export type Rule =
+  | IRule
+  | TruthyRule
+  | XorRule
+  | LengthRule
+  | AlphaRule
+  | PatternRule
+  | CasingRule
+  | SchemaRule
+  | SchemaPathRule;
 
 export interface IRule<T = string, O = any> {
   type?: RuleType;
@@ -46,56 +63,4 @@ export interface IThen<T = string, O = any> {
   functionOptions?: O;
 }
 
-export type TruthyRule = IRule<RuleFunction.TRUTHY>;
-
-export interface IXorRuleOptions {
-  /** test to verify if one (but not all) of the provided keys are present in object */
-  properties: string[];
-}
-export type XorRule = IRule<RuleFunction.XOR, IXorRuleOptions>;
-
-export interface ILengthRuleOptions {
-  min?: number;
-  max?: number;
-}
-export type LengthRule = IRule<RuleFunction.LENGTH, ILengthRuleOptions>;
-
-export interface IEnumRuleOptions {
-  values: Array<string | number>;
-}
-export type EnumRule = IRule<RuleFunction.ENUM, IEnumRuleOptions>;
-
-export interface IAlphaRuleOptions {
-  /** if sorting array of objects, which key to use for comparison */
-  keyedBy?: string;
-}
-export type AlphaRule = IRule<RuleFunction.ALPHABETICAL, IAlphaRuleOptions>;
-
-export interface IRulePatternOptions {
-  /** regex that target must match */
-  match?: string;
-
-  /** regex that target must not match */
-  notMatch?: string;
-}
-export type PatternRule = IRule<RuleFunction.PATTERN, IRulePatternOptions>;
-
-export interface ICasingOptions {
-  type: 'flat' | 'camel' | 'pascal' | 'kebab' | 'cobol' | 'snake' | 'macro';
-  disallowDigits?: boolean;
-}
-export type CasingRule = IRule<RuleFunction.CASING, ICasingOptions>;
-
-export interface ISchemaOptions {
-  schema: object;
-}
-export type SchemaRule = IRule<RuleFunction.SCHEMA, ISchemaOptions>;
-
-export interface ISchemaPathOptions {
-  schemaPath: string;
-  // the `path.to.prop` to field, or special `@key` value to target keys for matched `given` object
-  field?: string;
-}
-export type SchemaPathRule = IRule<RuleFunction.SCHEMAPATH, ISchemaPathOptions>;
-
 export type HumanReadableDiagnosticSeverity = 'error' | 'warn' | 'info' | 'hint' | 'off';


Test patch:
diff --git a/src/functions/__tests__/casing.test.ts b/src/functions/__tests__/casing.test.ts
index 4ee5f111..6e367d65 100644
--- a/src/functions/__tests__/casing.test.ts
+++ b/src/functions/__tests__/casing.test.ts
@@ -1,5 +1,4 @@
-import { ICasingOptions } from '../../types';
-import { casing } from '../casing';
+import { casing, ICasingOptions } from '../casing';
 
 function runCasing(target: unknown, type: ICasingOptions['type'], disallowDigits?: boolean) {
   return casing(