Skip to content

Commit

Permalink
Add support for built-in configs (palantir#1261)
Browse files Browse the repository at this point in the history
Support built-in configs. This allows a user to have a `tslint.json` file like this:

```
{
  "extends": "tslint:recommended"
}
```

This does not allow `"tslint:recommended"` as an "entry point" configuration. That is, it can only be used by extending it, not doing something like `tslint --config tslint:recommended files/**/*.ts`.
  • Loading branch information
jkillian authored and adidahiya committed Jun 8, 2016
1 parent e36647c commit 6bae5c7
Show file tree
Hide file tree
Showing 8 changed files with 198 additions and 6 deletions.
1 change: 1 addition & 0 deletions Gruntfile.js
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ module.exports = function (grunt) {
tslint: {
src: [
"src/*.ts",
"src/configs/**/*.ts",
"src/formatters/**/*.ts",
"src/language/**/*.ts",
"src/rules/**/*.ts",
Expand Down
23 changes: 23 additions & 0 deletions src/configs/latest.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
/**
* @license
* Copyright 2016 Palantir Technologies, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

export const rules = {
};

// work around "extends" being a keyword
const xtends = "tslint:recommended";
export { xtends as extends };
127 changes: 127 additions & 0 deletions src/configs/recommended.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,127 @@
/**
* @license
* Copyright 2016 Palantir Technologies, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

export const rules = {
"align": [true,
"parameters",
"statements",
],
"class-name": true,
"comment-format": [true,
"check-space",
],
"curly": true,
"eofline": true,
"forin": true,
"indent": [true, "spaces"],
"interface-name": [true, "always-prefix"],
"jsdoc-format": true,
"label-position": true,
"label-undefined": true,
"max-line-length": [true, 120],
"member-access": true,
"member-ordering": [true,
{ "order": "statics-first" },
],
"new-parens": true,
"no-any": false,
"no-arg": true,
"no-bitwise": true,
"no-conditional-assignment": true,
"no-consecutive-blank-lines": true,
"no-console": [true,
"debug",
"info",
"log",
"time",
"timeEnd",
"trace",
],
"no-construct": true,
"no-constructor-vars": false,
"no-debugger": true,
"no-duplicate-key": true,
"no-duplicate-variable": true,
"no-empty": true,
"no-eval": true,
"no-internal-module": true,
"no-namespace": true,
"no-reference": true,
"no-shadowed-variable": true,
"no-string-literal": true,
"no-switch-case-fall-through": false,
"no-trailing-whitespace": true,
"no-unreachable": true,
"no-unused-expression": true,
"no-unused-variable": [true, "react"],
// disable this rule as it is very heavy performance-wise and not that useful
"no-use-before-declare": false,
"no-var-keyword": true,
"no-var-requires": true,
"object-literal-sort-keys": true,
"one-line": [true,
"check-catch",
"check-else",
"check-finally",
"check-open-brace",
"check-whitespace",
],
"one-variable-per-declaration": [true,
"ignore-for-loop",
],
"quotemark": [true, "double", "avoid-escape"],
"radix": true,
"semicolon": [true, "always"],
"switch-default": true,
"trailing-comma": [true,
{
"singleline": "never",
"multiline": "always",
},
],
"triple-equals": [true, "allow-null-check"],
"typedef": false,
"typedef-whitespace": [true,
{
"call-signature": "nospace",
"index-signature": "nospace",
"parameter": "nospace",
"property-declaration": "nospace",
"variable-declaration": "nospace",
}, {
"call-signature": "onespace",
"index-signature": "onespace",
"parameter": "onespace",
"property-declaration": "onespace",
"variable-declaration": "onespace",
},
],
"use-isnan": true,
"variable-name": [true,
"ban-keywords",
"check-format",
"allow-pascal-case",
],
"whitespace": [true,
"check-branch",
"check-decl",
"check-operator",
"check-separator",
"check-type",
"check-typecast",
],
};
25 changes: 19 additions & 6 deletions src/configuration.ts
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,8 @@ export const DEFAULT_CONFIG = {
const PACKAGE_DEPRECATION_MSG = "Configuration of TSLint via package.json has been deprecated, "
+ "please start using a tslint.json file instead (http://palantir.github.io/tslint/usage/tslint-json/).";

const BUILT_IN_CONFIG = /^tslint:(.*)$/;

/**
* Searches for a TSLint configuration and returns the data from the config.
* @param configFile A path to a config file, this can be null if the location of a config is not known
Expand Down Expand Up @@ -162,18 +164,29 @@ export function loadConfigurationFromPath(configFilePath: string): IConfiguratio
}

/**
* Resolve configuration file path
* @var relativeFilePath Relative path or package name (tslint-config-X) or package short name (X)
* Resolve configuration file path or node_module reference
* @param filePath Relative ("./path"), absolute ("/path"), node module ("path"), or built-in ("tslint:path")
*/
function resolveConfigurationPath(relativeFilePath: string, relativeTo?: string) {
function resolveConfigurationPath(filePath: string, relativeTo?: string) {
const matches = filePath.match(BUILT_IN_CONFIG);
const isBuiltInConfig = matches != null;
if (isBuiltInConfig) {
const configName = matches[1];
try {
return require.resolve(`./configs/${configName}`);
} catch (err) {
throw new Error(`${filePath} is not a built-in config, try "tslint:recommended" instead.`);
}
}

const basedir = relativeTo || process.cwd();
try {
return resolve.sync(relativeFilePath, { basedir });
return resolve.sync(filePath, { basedir });
} catch (err) {
try {
return require.resolve(relativeFilePath);
return require.resolve(filePath);
} catch (err) {
throw new Error(`Invalid "extends" configuration value - could not require "${relativeFilePath}". ` +
throw new Error(`Invalid "extends" configuration value - could not require "${filePath}". ` +
"Review the Node lookup algorithm (https://nodejs.org/api/modules.html#modules_all_together) " +
"for the approximate method TSLint uses to find the referenced configuration file.");
}
Expand Down
3 changes: 3 additions & 0 deletions src/tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
"../custom-typings/**/*.d.ts",
"../typings/**/*.d.ts",
"./*.ts",
"./configs/**/*.ts",
"./formatters/**/*.ts",
"./language/**/*.ts",
"./rules/**/*.ts",
Expand Down Expand Up @@ -42,6 +43,8 @@
"tslint-cli.ts",
"tslint.ts",
"utils.ts",
"configs/latest.ts",
"configs/recommended.ts",
"formatters/checkstyleFormatter.ts",
"formatters/index.ts",
"formatters/jsonFormatter.ts",
Expand Down
6 changes: 6 additions & 0 deletions test/config/tslint-extends-builtin.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
{
"extends": "tslint:latest",
"rules": {
"no-eval": false
}
}
17 changes: 17 additions & 0 deletions test/configurationTests.ts
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,12 @@ describe("Configuration", () => {
});
});

it("extends with builtin", () => {
const config = loadConfigurationFromPath("./test/config/tslint-extends-builtin.json");
assert.isTrue(config.rules["no-var-keyword"]);
assert.isFalse(config.rules["no-eval"]);
});

describe("with config not relative to tslint", () => {
let tmpfile: string;

Expand Down Expand Up @@ -153,5 +159,16 @@ describe("Configuration", () => {
"rule-four": "/*also not a comment*/",
});
});

it("can load a built-in configuration", () => {
const config = loadConfigurationFromPath("tslint:recommended");
assert.isTrue(config.rules["no-eval"]);
});

it("throws on an invalid built-in configuration path", () => {
assert.throws(() => {
loadConfigurationFromPath("tslint:doesnotexist");
});
});
});
});
2 changes: 2 additions & 0 deletions test/tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,8 @@
"../typings/underscore/underscore.d.ts",
"typings/chai/chai.d.ts",
"typings/mocha/mocha.d.ts",
"../src/configs/latest.ts",
"../src/configs/recommended.ts",
"../src/configuration.ts",
"../src/enableDisableRules.ts",
"../src/formatterLoader.ts",
Expand Down

0 comments on commit 6bae5c7

Please sign in to comment.