Repository: stoplightio/spectral
Pull request #300 (2019-07-06 11:45:56)

refactor: unify config and ruleset naming
BREAKING CHANGE: config is gone - use ruleset instead.

Related to #310 

**Checklist**

- [x] Tests added / updated
- [x] Docs added / updated
- [x] Check this off Breaking change?

**Does this PR introduce a breaking change?**

- [x] Yes
- [ ] No




Patch:
diff --git a/README.md b/README.md
index ad37354c..f3eb2944 100644
--- a/README.md
+++ b/README.md
@@ -28,7 +28,7 @@ npm install @stoplight/spectral
 npm install -g @stoplight/spectral
 ```
 
-Supports Node v8.3+.
+Supports Node v8.3+ and modern browsers.
 
 ### Executable binaries
 
@@ -70,7 +70,6 @@ spectral lint petstore.yaml
 Other options include:
 
 ``` text
-  -c, --config=config          path to a config file
   -e, --encoding=encoding      text encoding to use
   -f, --format=json|stylish    formatter to use for outputting results
   -h, --help                   show CLI help
@@ -97,10 +96,6 @@ There are three key concepts in Spectral: **Rulesets**, **Rules** and **Function
 
 Think of a set of **rules** and **functions** as a flexible and customizable style guide for your JSON objects.
 
-## Config
-
-Spectral CLI supports [config files](docs/config.md), to avoid typing out CLI options and arguments every single time.
-
 ## Programmatic usage
 
 Spectral is written in TypeScript (JavaScript) and can be used directly for when you need to use Spectral programmatically. Take a look at our ["JavaScript API documentation"](docs/js-api.md).
diff --git a/docs/config.md b/docs/config.md
deleted file mode 100644
index 672282b7..00000000
--- a/docs/config.md
+++ /dev/null
@@ -1,62 +0,0 @@
----
-title: Spectral Config
-tags: 
-- Documentation
-- Config
----
-
-Spectral CLI supports config files, to avoid typing out CLI options and arguments every single time. 
-
-By default Spectral CLI will look for `spectral.yml` in the current working directory, but it could be any JSON or YAML file if you specify it with the `--config` option. 
-
-## Usage
-
-```bash
-spectral lint openapi.yaml --config=spectral.yaml
-```
-
-## Example Config
-
-```yaml
-lint:
-  format: json
-  ruleset: 
-  - http://apis.example.com/governance/core.yml
-  - http://apis.example.com/governance/rest.yml
-  skipRule: 
-  - that-one-rule
-  - broken-rule
-  output: tmp/lint-results.json
-  verbose: true
-```
-
-Right now Spectral only has the one command: `lint`, but other commands in the
-future will have their own config namespace too.
-
-Here are all the available options, with their default values:
-
-```yaml
-lint:
-  encoding: utf8   # text encoding to use
-  format: stylish  # stylish, json
-  output:          # filename for output instead of stdout
-  maxResults:      # only show the first X erros
-  verbose: false   # see more output for debugging
-  ruleset:         # array of local files or URLs
-  quiet: false     # see only results
-  skipRule: []     # array of rule names as strings
-```
-
-The TypeScript interface here looks like this:
-
-```typescript
-export interface ILintConfig {
-  encoding: string;
-  format: ConfigFormat;
-  maxResults?: number;
-  output?: string;
-  ruleset?: string[];
-  skipRule?: string[];
-  verbose: boolean;
-}
-```
diff --git a/src/cli/commands/lint.ts b/src/cli/commands/lint.ts
index 252a5d22..68305d22 100644
--- a/src/cli/commands/lint.ts
+++ b/src/cli/commands/lint.ts
@@ -7,16 +7,16 @@ import { isNil, omitBy } from 'lodash';
 import { promisify } from 'util';
 
 import { IRuleResult } from '../..';
-import { createEmptyConfig, getDefaultRulesetFile } from '../../config/configLoader';
 import { json, stylish } from '../../formatters';
 import { readParsable } from '../../fs/reader';
 import { httpAndFileResolver } from '../../resolvers/http-and-file';
+import { getDefaultRulesetFile } from '../../rulesets/loader';
 import { oas2Functions, rules as oas2Rules } from '../../rulesets/oas2';
 import { oas3Functions, rules as oas3Rules } from '../../rulesets/oas3';
 import { readRulesFromRulesets } from '../../rulesets/reader';
 import { Spectral } from '../../spectral';
 import { IParsedResult, RuleCollection } from '../../types';
-import { ILintConfig } from '../../types/config';
+import { ILintConfig, OutputFormat } from '../../types/config';
 
 const writeFileAsync = promisify(writeFile);
 export default class Lint extends Command {
@@ -28,12 +28,14 @@ linting ./openapi.yaml
 `,
   ];
 
+  private static defaultLintConfig: ILintConfig = {
+    encoding: 'utf8',
+    format: OutputFormat.STYLISH,
+    verbose: false,
+  };
+
   public static flags = {
     help: flagHelpers.help({ char: 'h' }),
-    config: flagHelpers.string({
-      char: 'c',
-      description: 'path to a config file',
-    }),
     encoding: flagHelpers.string({
       char: 'e',
       description: 'text encoding to use',
@@ -81,11 +83,11 @@ linting ./openapi.yaml
 
     const cwd = process.cwd();
 
-    const config: ILintConfig = mergeConfig(createEmptyConfig(), flags as Partial<ILintConfig>);
+    const lintConfig: ILintConfig = mergeConfig({ ...Lint.defaultLintConfig }, flags as Partial<ILintConfig>);
 
     this.quiet = flags.quiet;
 
-    const rulesetFile = ruleset || (await getDefaultRulesetFile(cwd)) || null;
+    const rulesetFile = ruleset || (await getDefaultRulesetFile(cwd));
 
     if (rulesetFile) {
       try {
@@ -102,7 +104,7 @@ linting ./openapi.yaml
 
     if (args.source) {
       try {
-        await lint(args.source, config, this, rules);
+        await lint(args.source, lintConfig, this, rules);
       } catch (ex) {
         this.error(ex.message);
       }
diff --git a/src/config/configLoader.ts b/src/rulesets/loader.ts
similarity index 73%
rename from src/config/configLoader.ts
rename to src/rulesets/loader.ts
index b9c304b3..d5520bb1 100644
--- a/src/config/configLoader.ts
+++ b/src/rulesets/loader.ts
@@ -1,15 +1,8 @@
 import { join } from '@stoplight/path';
 import * as fs from 'fs';
-import { ILintConfig, OutputFormat } from '../types/config';
 
 const DEFAULT_RULESET_FILE = /^\.?spectral\.(?:ya?ml|json)$/;
 
-export const createEmptyConfig = (): ILintConfig => ({
-  encoding: 'utf8',
-  format: OutputFormat.STYLISH,
-  verbose: false,
-});
-
 export const getDefaultRulesetFile = (directory: string): Promise<string | null> => {
   return new Promise(resolve => {
     fs.readdir(directory, (err, files) => {


Test patch:
diff --git a/src/cli/commands/__tests__/lint.test.ts b/src/cli/commands/__tests__/lint.test.ts
index 9f93704a..8fa2e2b9 100644
--- a/src/cli/commands/__tests__/lint.test.ts
+++ b/src/cli/commands/__tests__/lint.test.ts
@@ -308,7 +308,7 @@ describe('lint', () => {
       });
   });
 
-  describe('when not using config nor default config file', () => {
+  describe('when not using ruleset nor default ruleset file', () => {
     test
       .stdout()
       .command(['lint', invalidOas3SpecPath])
@@ -317,7 +317,7 @@ describe('lint', () => {
       });
   });
 
-  describe('when using default config file', () => {
+  describe('when using default ruleset file', () => {
     let spy: SpyInstance;
     beforeAll(() => {
       spy = jest.spyOn(process, 'cwd').mockReturnValue(resolve(__dirname, '__fixtures__'));
diff --git a/src/config/__tests__/__fixtures__/empty.json b/src/rulesets/__tests__/__fixtures__/empty.json
similarity index 100%
rename from src/config/__tests__/__fixtures__/empty.json
rename to src/rulesets/__tests__/__fixtures__/empty.json
diff --git a/src/config/__tests__/__fixtures__/spectral.json b/src/rulesets/__tests__/__fixtures__/spectral.json
similarity index 100%
rename from src/config/__tests__/__fixtures__/spectral.json
rename to src/rulesets/__tests__/__fixtures__/spectral.json
diff --git a/src/config/__tests__/__fixtures__/yaml/.spectral.yaml b/src/rulesets/__tests__/__fixtures__/yaml/.spectral.yaml
similarity index 100%
rename from src/config/__tests__/__fixtures__/yaml/.spectral.yaml
rename to src/rulesets/__tests__/__fixtures__/yaml/.spectral.yaml
diff --git a/src/config/__tests__/config.test.ts b/src/rulesets/__tests__/loader.test.ts
similarity index 65%
rename from src/config/__tests__/config.test.ts
rename to src/rulesets/__tests__/loader.test.ts
index bac29e2b..e378ee85 100644
--- a/src/config/__tests__/config.test.ts
+++ b/src/rulesets/__tests__/loader.test.ts
@@ -1,15 +1,15 @@
 import * as path from '@stoplight/path';
-import { getDefaultRulesetFile } from '../configLoader';
+import { getDefaultRulesetFile } from '../loader';
 
 const ROOT = path.join(__dirname, './__fixtures__');
 
-describe('config loading', () => {
+describe('ruleset loading', () => {
   describe('getDefaultRulesetFile', () => {
-    test('should resolve with null if a default config does not exist', () => {
+    test('should resolve with null if a default ruleset does not exist', () => {
       return expect(getDefaultRulesetFile(path.join(ROOT, './empty'))).resolves.toBeNull();
     });
 
-    test('should resolve with a path to found config if there is any matching', async () => {
+    test('should resolve with a path to found ruleset if there is any matching', async () => {
       await expect(getDefaultRulesetFile(ROOT)).resolves.toEqual(path.join(ROOT, './spectral.json'));
       await expect(getDefaultRulesetFile(path.join(ROOT, './yaml'))).resolves.toEqual(
         path.join(ROOT, './yaml/.spectral.yaml'),