From 1160ea475df5a5bc812cc66d3bf0bc7526aaa312 Mon Sep 17 00:00:00 2001 From: Matthew Zikherman Date: Fri, 24 Jan 2020 16:53:31 -0500 Subject: [PATCH] [TSLint] Rule to warn about using QueryRenderer --- src/Artsy/Relay/SystemQueryRenderer.tsx | 1 + .../Publishing/ToolTip/TooltipsDataLoader.tsx | 4 +- src/DevTools/MockRelayRenderer.tsx | 1 + tslint.json | 1 + tslint/README.md | 2 +- tslint/noQueryRendererImportRule.js | 50 +++++++++++++++++++ 6 files changed, 56 insertions(+), 3 deletions(-) create mode 100644 tslint/noQueryRendererImportRule.js diff --git a/src/Artsy/Relay/SystemQueryRenderer.tsx b/src/Artsy/Relay/SystemQueryRenderer.tsx index 8d16b06629..5c3731a067 100644 --- a/src/Artsy/Relay/SystemQueryRenderer.tsx +++ b/src/Artsy/Relay/SystemQueryRenderer.tsx @@ -1,4 +1,5 @@ import React from "react" +/* tslint:disable-next-line:no-query-renderer-import */ import { QueryRenderer, QueryRendererProps } from "react-relay" import { OperationType } from "relay-runtime" diff --git a/src/Components/Publishing/ToolTip/TooltipsDataLoader.tsx b/src/Components/Publishing/ToolTip/TooltipsDataLoader.tsx index 351d6d939f..daff99aa30 100644 --- a/src/Components/Publishing/ToolTip/TooltipsDataLoader.tsx +++ b/src/Components/Publishing/ToolTip/TooltipsDataLoader.tsx @@ -1,12 +1,12 @@ import { TooltipsDataLoaderQueryResponse } from "__generated__/TooltipsDataLoaderQuery.graphql" import { TooltipsDataLoaderQuery } from "__generated__/TooltipsDataLoaderQuery.graphql" import * as Artsy from "Artsy" +import { SystemQueryRenderer } from "Artsy/Relay/SystemQueryRenderer" import { getArtsySlugsFromArticle } from "Components/Publishing/Constants" import { ArticleData } from "Components/Publishing/Typings" import { keyBy } from "lodash" import PropTypes from "prop-types" import React, { Component } from "react" -import { QueryRenderer } from "react-relay" import { graphql } from "react-relay" import { ArticleProps } from "../Article" @@ -39,7 +39,7 @@ export class TooltipsDataLoader extends Component { } return ( - + environment={relayEnvironment} query={graphql` query TooltipsDataLoaderQuery( diff --git a/src/DevTools/MockRelayRenderer.tsx b/src/DevTools/MockRelayRenderer.tsx index ab68ae48ed..09db53ffdd 100644 --- a/src/DevTools/MockRelayRenderer.tsx +++ b/src/DevTools/MockRelayRenderer.tsx @@ -4,6 +4,7 @@ import { renderWithLoadProgress } from "Artsy/Relay/renderWithLoadProgress" import { SystemQueryRenderer } from "Artsy/Relay/SystemQueryRenderer" import { IMocks } from "graphql-tools/dist/Interfaces" import React from "react" +/* tslint:disable-next-line:no-query-renderer-import */ import { QueryRenderer } from "react-relay" import { Environment, diff --git a/tslint.json b/tslint.json index 66b78b8c06..0886c5e423 100644 --- a/tslint.json +++ b/tslint.json @@ -17,6 +17,7 @@ "no-console": false, "no-import-un-mocked": true, "no-namespace": [true, "allow-declarations"], + "no-query-renderer-import": true, "no-switch-case-fall-through": true, "no-unused-expression": false, "no-var-requires": false, diff --git a/tslint/README.md b/tslint/README.md index 98da3c6e6f..37b64e45e7 100644 --- a/tslint/README.md +++ b/tslint/README.md @@ -1,6 +1,6 @@ ## Steps to adding a custom TSLint rule -1. Make a new file, the name is important, it must be camel-case and not a `.ts` file (the `@ts-check` declaration at the top of each file uses JSDoc to check types while developing rules – [read here](https://github.com/Microsoft/TypeScript/wiki/Type-Checking-JavaScript-Files) for more info). +1. Make a new file, the name is important, it must be camel-case and not a `.ts` file (the `@ts-check` declaration at the top of each file uses JSDoc to check types while developing rules – [read here](https://github.com/Microsoft/TypeScript/wiki/Type-Checking-JavaScript-Files) for more info). The suffix must be `...Rule.js`. 1. You will need to convert your camelCase name to kebab-case and add it to the [`tslint.json`](../tslint.json) E.g. `noDoingAnythingRule.js` -> `no-doing-anything` and: diff --git a/tslint/noQueryRendererImportRule.js b/tslint/noQueryRendererImportRule.js new file mode 100644 index 0000000000..0ae5accccf --- /dev/null +++ b/tslint/noQueryRendererImportRule.js @@ -0,0 +1,50 @@ +// @ts-check + +const Lint = require("tslint") +const ts = require("typescript") + +const message = "Did you mean to use `SystemQueryRenderer` instead?" + +class Rule extends Lint.Rules.AbstractRule { + /** + * @param {ts.SourceFile} sourceFile + */ + apply(sourceFile) { + // Skip storybook and test files. + if ( + sourceFile.fileName.includes(".story") || + sourceFile.fileName.includes(".test") + ) { + return [] + } + + return this.applyWithWalker( + new NoQueryRendererImportWalker(sourceFile, this.getOptions()) + ) + } +} + +class NoQueryRendererImportWalker extends Lint.RuleWalker { + visitImportDeclaration(node) { + const importSource = node.moduleSpecifier.text + + if (importSource === "react-relay") { + const namedBindings = node.importClause.namedBindings + const namedImports = + namedBindings && + namedBindings.elements && + namedBindings.elements.map(e => e.getText()) + + if (namedImports.includes("QueryRenderer")) { + this.addFailure( + this.createFailure(node.getStart(), node.getWidth(), message) + ) + } + } + + // call the base version of this visitor to actually parse this node + super.visitImportDeclaration(node) + } +} + +module.exports = { Rule: Rule }