Skip to content

Add TSLint rewire #14

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 3 commits into from
Jun 18, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 6 additions & 2 deletions packages/example/config-overrides.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
const {
rewireWebpack: rewireTypescript,
rewireJest: rewireTypescriptJest
rewireJest: rewireTypescriptJest,
rewireTSLint
} = require("react-app-rewire-typescript-babel-preset");
// const {
// rewireWebpack: rewireTypescript,
Expand All @@ -9,7 +10,10 @@ const {

module.exports = {
webpack: function(config, env) {
return rewireTypescript(config);
config = rewireTypescript(config);
config = rewireTSLint(config);

return config;
},
jest: function(config) {
return rewireTypescriptJest(config);
Expand Down
4 changes: 3 additions & 1 deletion packages/example/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,8 @@
"@types/react": "^16.3.17",
"@types/react-dom": "^16.0.6",
"react-app-rewire-typescript-babel-preset": "^2.0.0",
"react-app-rewired": "^2.0.0"
"react-app-rewired": "^2.0.0",
"tslint": "^5.10.0",
"tslint-react": "^3.6.0"
}
}
13 changes: 13 additions & 0 deletions packages/example/src/AnotherComponent.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import * as React from "react";

export interface TypeScriptComponentProps {
message: string;
}

export default class TypeScriptComponent extends React.Component<
TypeScriptComponentProps
> {
render() {
return <p>{this.props.message}</p>;
}
}
14 changes: 3 additions & 11 deletions packages/example/src/App.tsx
Original file line number Diff line number Diff line change
@@ -1,17 +1,9 @@
import * as React from "react";
import logo from "./logo.svg";
import { ReactComponent as TypeScriptLogo } from "./typescriptLogo.svg";
import "./App.css";

interface TypeScriptComponentProps {
message: string;
}
import AnotherComponent from "./AnotherComponent";

class TypeScriptComponent extends React.Component<TypeScriptComponentProps> {
render() {
return <p>{this.props.message}</p>;
}
}
import "./App.css";

class App extends React.Component {
render() {
Expand All @@ -26,7 +18,7 @@ class App extends React.Component {
<p>
Edit <code>src/App.tsx</code> and save to reload.
</p>
<TypeScriptComponent message="Hello from TypeScript component." />
<AnotherComponent message="Hello from another TypeScript component." />
<a
className="App-link"
href="https://reactjs.org"
Expand Down
29 changes: 29 additions & 0 deletions packages/example/tslint.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
{
"extends": ["tslint:recommended", "tslint-react"],
"rules": {
"arrow-parens": false,
"eofline": false,
"interface-name": false,
"jsx-boolean-value": false,
"jsx-no-lambda": false,
"jsx-no-multiline-js": false,
"member-access": false,
"no-return-await": false,
"no-submodule-imports": false,
"no-trailing-whitespace": false,
"no-var-requires": false,
"object-literal-sort-keys": false,
"only-arrow-functions": false,
"ordered-imports": false,
"prefer-conditional-expression": false,
"semicolon": [true, "always", "ignore-bound-class-methods"],
"trailing-comma": false,
"variable-name": [
true,
"ban-keywords",
"check-format",
"allow-leading-underscore",
"allow-pascal-case"
]
}
}
1 change: 1 addition & 0 deletions packages/rewire/index.ts
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
export { default as rewireWebpack } from "./rewireWebpack";
export { default as rewireJest } from "./rewireJest";
export { default as rewireTSLint } from "./rewireTSLint";
3 changes: 3 additions & 0 deletions packages/rewire/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -22,5 +22,8 @@
},
"peerDependencies": {
"react-app-rewired": "^2.0.0"
},
"dependencies": {
"tslint-loader": "^3.6.0"
}
}
40 changes: 40 additions & 0 deletions packages/rewire/rewireTSLint.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
import * as webpack from "webpack";
import { getLoader, Matcher } from "react-app-rewired";
import { getValidatedConfig } from "./webpackUtils";

export default function(
c: webpack.Configuration,
options?: object
): webpack.Configuration {
// Validate and narrow type
const config = getValidatedConfig(c);

// Grab the current ESLint config so we can copy some of its settings
const esLintLoader = getLoader(config.module.rules, esLintLoaderMatcher);

// Create a new rule
const tsLintLoader: webpack.RuleSetRule = {
test: /\.(ts|tsx)$/,
enforce: "pre",
use: [
{
options,
loader: require.resolve("tslint-loader")
}
],
include: esLintLoader.include,
exclude: esLintLoader.exclude
};

config.module.rules.unshift(tsLintLoader);

return config;
}

const esLintLoaderMatcher: Matcher = rule =>
Boolean(
rule.test &&
rule.test.toString() === /\.(js|jsx|mjs)$/.toString() &&
Array.isArray(rule.use) &&
rule.use.find((r: any) => r.loader && /eslint-loader/.test(r.loader))
);
28 changes: 1 addition & 27 deletions packages/rewire/rewireWebpack.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import path from "path";
import * as webpack from "webpack";
import reactScriptsPaths from "react-scripts/config/paths";
import { getBabelLoader, getLoader, Matcher } from "react-app-rewired";
import { getValidatedConfig } from "./webpackUtils";

// Switch out the entry point index.js for index.tsx.
// We need to do this on module import to intercept react-script's preflight
Expand Down Expand Up @@ -77,30 +78,3 @@ const svgLoaderMatcher: Matcher = rule =>
rule.use &&
rule.use.find((r: any) => r.loader && /babel-loader/.test(r.loader))
);

interface ReactScriptsConfig extends webpack.Configuration {
resolve: {
extensions: string[];
};
module: {
rules: webpack.Rule[];
};
}

function getValidatedConfig(config: webpack.Configuration): ReactScriptsConfig {
let error: string | undefined;

const matchesShape = (c: webpack.Configuration): c is ReactScriptsConfig => {
error = (() => {
if (!c.resolve) return "resolve is undefined";
if (!c.resolve.extensions) return "resolve.extensions is undefined";
if (!c.module) return "module is undefined";
return undefined;
})();

return error === undefined;
};

if (matchesShape(config)) return config;
throw new Error(`Unexpected Webpack config shape: ${error}.`);
}
30 changes: 30 additions & 0 deletions packages/rewire/webpackUtils.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
import * as webpack from "webpack";

interface ReactScriptsConfig extends webpack.Configuration {
resolve: {
extensions: string[];
};
module: {
rules: webpack.Rule[];
};
}

export function getValidatedConfig(
config: webpack.Configuration
): ReactScriptsConfig {
let error: string | undefined;

const matchesShape = (c: webpack.Configuration): c is ReactScriptsConfig => {
error = (() => {
if (!c.resolve) return "resolve is undefined";
if (!c.resolve.extensions) return "resolve.extensions is undefined";
if (!c.module) return "module is undefined";
return undefined;
})();

return error === undefined;
};

if (matchesShape(config)) return config;
throw new Error(`Unexpected Webpack config shape: ${error}.`);
}
20 changes: 18 additions & 2 deletions yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -9253,7 +9253,7 @@ right-align@^0.1.1:
dependencies:
align-text "^0.1.1"

rimraf@^2.2.8, rimraf@^2.5.4, rimraf@^2.6.1, rimraf@^2.6.2:
rimraf@^2.2.8, rimraf@^2.4.4, rimraf@^2.5.4, rimraf@^2.6.1, rimraf@^2.6.2:
version "2.6.2"
resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-2.6.2.tgz#2ed8150d24a16ea8651e6d6ef0f47c4158ce7a36"
dependencies:
Expand Down Expand Up @@ -10233,6 +10233,16 @@ tslint-language-service@^0.9.9:
dependencies:
mock-require "^2.0.2"

tslint-loader@^3.6.0:
version "3.6.0"
resolved "https://registry.yarnpkg.com/tslint-loader/-/tslint-loader-3.6.0.tgz#12ed4d5ef57d68be25cd12692fb2108b66469d76"
dependencies:
loader-utils "^1.0.2"
mkdirp "^0.5.1"
object-assign "^4.1.1"
rimraf "^2.4.4"
semver "^5.3.0"

tslint-microsoft-contrib@~5.0.1:
version "5.0.3"
resolved "https://registry.yarnpkg.com/tslint-microsoft-contrib/-/tslint-microsoft-contrib-5.0.3.tgz#6fc3e238179cd72045c2b422e4d655f4183a8d5c"
Expand All @@ -10246,6 +10256,12 @@ tslint-plugin-prettier@^1.3.0:
eslint-plugin-prettier "^2.2.0"
tslib "^1.7.1"

tslint-react@^3.6.0:
version "3.6.0"
resolved "https://registry.yarnpkg.com/tslint-react/-/tslint-react-3.6.0.tgz#7f462c95c4a0afaae82507f06517ff02942196a1"
dependencies:
tsutils "^2.13.1"

tslint@^5.10.0:
version "5.10.0"
resolved "https://registry.yarnpkg.com/tslint/-/tslint-5.10.0.tgz#11e26bccb88afa02dd0d9956cae3d4540b5f54c3"
Expand All @@ -10269,7 +10285,7 @@ [email protected]:
dependencies:
tslib "^1.7.1"

tsutils@^2.12.1, tsutils@^2.24.0, tsutils@^2.27.0:
tsutils@^2.12.1, tsutils@^2.13.1, tsutils@^2.24.0, tsutils@^2.27.0:
version "2.27.1"
resolved "https://registry.yarnpkg.com/tsutils/-/tsutils-2.27.1.tgz#ab0276ac23664f36ce8fd4414daec4aebf4373ee"
dependencies:
Expand Down