From 1481fcd0b9afa8bdd603286cab935ee445a83071 Mon Sep 17 00:00:00 2001 From: Takashi Arai Date: Thu, 16 May 2024 11:46:07 -0700 Subject: [PATCH 1/6] Contributing.md --- CONTRIBUTING.md | 76 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 76 insertions(+) create mode 100644 CONTRIBUTING.md diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 0000000..c9ec82c --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,76 @@ +*This is a suggested `CONTRIBUTING.md` file template for use by open sourced Salesforce projects. The main goal of this file is to make clear the intents and expectations that end-users may have regarding this project and how/if to engage with it. Adjust as needed (especially look for `{project_slug}` which refers to the org and repo name of your project) and remove this paragraph before committing to your repo.* + +# Contributing Guide For @salesforce/eslint-plugin-lwc-mobile + +This page lists the operational governance model of this project, as well as the recommendations and requirements for how to best contribute to @salesforce/eslint-plugin-lwc-mobile. We strive to obey these as best as possible. As always, thanks for contributing – we hope these guidelines make it easier and shed some light on our approach and processes. + +# Governance Model + +## Salesforce Sponsored + +The intent and goal of open sourcing this project is to increase the contributor and user base. However, only Salesforce employees will be given `admin` rights and will be the final arbitrars of what contributions are accepted or not. + +# Issues, requests & ideas + +Use GitHub Issues page to submit issues, enhancement requests and discuss ideas. + +### Bug Reports and Fixes +- If you find a bug, please search for it in the [Issues](https://github.com/salesforce/eslint-plugin-lwc-mobile/issues), and if it isn't already tracked, + [create a new issue](https://github.com/salesforce/eslint-plugin-lwc-mobile/issues/new). Fill out the "Bug Report" section of the issue template. Even if an Issue is closed, feel free to comment and add details, it will still + be reviewed. +- Issues that have already been identified as a bug (note: able to reproduce) will be labelled `bug`. +- If you'd like to submit a fix for a bug, [send a Pull Request](#creating_a_pull_request) and mention the Issue number. + - Include tests that isolate the bug and verifies that it was fixed. + +### New Features +- If you'd like to add new functionality to this project, describe the problem you want to solve in a [new Issue](https://github.com/salesforce/eslint-plugin-lwc-mobile/issues/new). +- Issues that have been identified as a feature request will be labelled `enhancement`. +- If you'd like to implement the new feature, please wait for feedback from the project + maintainers before spending too much time writing the code. In some cases, `enhancement`s may + not align well with the project objectives at the time. + +### Tests, Documentation, Miscellaneous +- If you'd like to improve the tests, you want to make the documentation clearer, you have an + alternative implementation of something that may have advantages over the way its currently + done, or you have any other change, we would be happy to hear about it! + - If its a trivial change, go ahead and [send a Pull Request](#creating_a_pull_request) with the changes you have in mind. + - If not, [open an Issue](https://github.com/salesforce/eslint-plugin-lwc-mobile/issues/new) to discuss the idea first. + +If you're new to our project and looking for some way to make your first contribution, look for +Issues labelled `good first contribution`. + +# Contribution Checklist + +- [x] Clean, simple, well styled code +- [x] Commits should be atomic and messages must be descriptive. Related issues should be mentioned by Issue number. +- [x] Comments + - Module-level & function-level comments. + - Comments on complex blocks of code or algorithms (include references to sources). +- [x] Tests + - The test suite, if provided, must be complete and pass + - Increase code coverage, not versa. + - Use any of our testkits that contains a bunch of testing facilities you would need. For example: `import com.salesforce.op.test._` and borrow inspiration from existing tests. +- [x] Dependencies + - Minimize number of dependencies. + - Prefer Apache 2.0, BSD3, MIT, ISC and MPL licenses. +- [x] Reviews + - Changes must be approved via peer code review + +# Creating a Pull Request + +1. **Ensure the bug/feature was not already reported** by searching on GitHub under Issues. If none exists, create a new issue so that other contributors can keep track of what you are trying to add/fix and offer suggestions (or let you know if there is already an effort in progress). +3. **Clone** the forked repo to your machine. +4. **Create** a new branch to contain your work (e.g. `git br fix-issue-11`) +4. **Commit** changes to your own branch. +5. **Push** your work back up to your fork. (e.g. `git push fix-issue-11`) +6. **Submit** a Pull Request against the `main` branch and refer to the issue(s) you are fixing. Try not to pollute your pull request with unintended changes. Keep it simple and small. +7. **Sign** the Salesforce CLA (you will be prompted to do so when submitting the Pull Request) + +> **NOTE**: Be sure to [sync your fork](https://help.github.com/articles/syncing-a-fork/) before making a pull request. + + +# Code of Conduct +Please follow our [Code of Conduct](CODE_OF_CONDUCT.md). + +# License +By contributing your code, you agree to license your contribution under the terms of our project [LICENSE](LICENSE.txt) and to sign the [Salesforce CLA](https://cla.salesforce.com/sign-cla) \ No newline at end of file From f2febcd87ef5f337bf6c24178973850b245aabf9 Mon Sep 17 00:00:00 2001 From: Takashi Arai Date: Thu, 16 May 2024 12:57:29 -0700 Subject: [PATCH 2/6] Remove comment. --- CONTRIBUTING.md | 2 -- 1 file changed, 2 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index c9ec82c..6a76844 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -1,5 +1,3 @@ -*This is a suggested `CONTRIBUTING.md` file template for use by open sourced Salesforce projects. The main goal of this file is to make clear the intents and expectations that end-users may have regarding this project and how/if to engage with it. Adjust as needed (especially look for `{project_slug}` which refers to the org and repo name of your project) and remove this paragraph before committing to your repo.* - # Contributing Guide For @salesforce/eslint-plugin-lwc-mobile This page lists the operational governance model of this project, as well as the recommendations and requirements for how to best contribute to @salesforce/eslint-plugin-lwc-mobile. We strive to obey these as best as possible. As always, thanks for contributing – we hope these guidelines make it easier and shed some light on our approach and processes. From 182d73475d18a6e19f6d1458202853082260141a Mon Sep 17 00:00:00 2001 From: "haifeng.li" Date: Thu, 16 May 2024 17:01:19 -0700 Subject: [PATCH 3/6] functional mutation-not-supported-rule --- eslint.config.mjs | 17 +++--- jest.config.ts | 13 ++--- package-lock.json | 11 ++++ package.json | 1 + src/configs/base.ts | 19 ++++++- src/index.ts | 8 +-- src/rules/graphql/mutation-not-supported.ts | 52 +++++++++++++++++++ src/rules/graphql/{utils => }/types.ts | 0 src/rules/utils.ts | 16 ++++++ .../graphql/mutation-not-supported.spec.ts | 32 ++++++++++++ test/rules/utils.spec.ts | 20 +++++++ tsconfig.json | 4 +- 12 files changed, 171 insertions(+), 22 deletions(-) create mode 100644 src/rules/graphql/mutation-not-supported.ts rename src/rules/graphql/{utils => }/types.ts (100%) create mode 100644 src/rules/utils.ts create mode 100644 test/rules/graphql/mutation-not-supported.spec.ts create mode 100644 test/rules/utils.spec.ts diff --git a/eslint.config.mjs b/eslint.config.mjs index 826dc62..13603d7 100644 --- a/eslint.config.mjs +++ b/eslint.config.mjs @@ -8,13 +8,10 @@ import eslint from '@eslint/js'; import tsEslint from 'typescript-eslint'; -export default tsEslint.config( - eslint.configs.recommended, - ...tsEslint.configs.recommended, - { - rules: { - strict: ['error', 'global'], - '@typescript-eslint/no-extra-non-null-assertion': 'off' - } - }, -); +export default tsEslint.config(eslint.configs.recommended, ...tsEslint.configs.recommended, { + rules: { + strict: ['error', 'global'], + '@typescript-eslint/no-extra-non-null-assertion': 'off', + '@typescript-eslint/no-explicit-any': 'off' + } +}); diff --git a/jest.config.ts b/jest.config.ts index 8382862..9005f93 100644 --- a/jest.config.ts +++ b/jest.config.ts @@ -11,17 +11,18 @@ const config: Config = { displayName: 'Unit Tests', setupFilesAfterEnv: ['jest-extended', 'jest-chain'], preset: 'ts-jest', - testMatch: [ - '/test/plugin.ts', - '/test/rules/**/*.ts', - '!**/test/rules/shared.ts' - ], + testMatch: ['/test/rules/**/*.ts'], moduleFileExtensions: ['ts', 'js', 'json'], testResultsProcessor: 'jest-sonar-reporter', testPathIgnorePatterns: ['/node_modules/', '/lib/'], moduleDirectories: ['node_modules'], collectCoverage: true, - collectCoverageFrom: ['src/**/*.ts'], + collectCoverageFrom: [ + 'src/**/*.ts', + '!src/index.ts', + '!src/configs/*.ts', + '!src/graphql/types.ts' + ], coverageDirectory: 'reports/coverage', reporters: [ 'default', diff --git a/package-lock.json b/package-lock.json index 7927340..d79e066 100644 --- a/package-lock.json +++ b/package-lock.json @@ -16,6 +16,7 @@ "devDependencies": { "@eslint/js": "^9.2.0", "@jest/globals": "^29.7.0", + "@types/jest": "^29.5.12", "@typescript-eslint/eslint-plugin": "^7.8.0", "@typescript-eslint/parser": "^7.8.0", "@typescript-eslint/rule-tester": "^7.8.0", @@ -1719,6 +1720,16 @@ "@types/istanbul-lib-report": "*" } }, + "node_modules/@types/jest": { + "version": "29.5.12", + "resolved": "https://registry.npmjs.org/@types/jest/-/jest-29.5.12.tgz", + "integrity": "sha512-eDC8bTvT/QhYdxJAulQikueigY5AsdBRH2yDKW3yveW7svY3+DzN84/2NUgkw10RTiJbWqZrTtoGVdYlvFJdLw==", + "dev": true, + "dependencies": { + "expect": "^29.0.0", + "pretty-format": "^29.0.0" + } + }, "node_modules/@types/json-schema": { "version": "7.0.15", "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.15.tgz", diff --git a/package.json b/package.json index 80ca452..da600af 100644 --- a/package.json +++ b/package.json @@ -65,6 +65,7 @@ "devDependencies": { "@eslint/js": "^9.2.0", "@jest/globals": "^29.7.0", + "@types/jest": "^29.5.12", "@typescript-eslint/eslint-plugin": "^7.8.0", "@typescript-eslint/parser": "^7.8.0", "@typescript-eslint/rule-tester": "^7.8.0", diff --git a/src/configs/base.ts b/src/configs/base.ts index 3453c49..e37e5b3 100644 --- a/src/configs/base.ts +++ b/src/configs/base.ts @@ -7,5 +7,22 @@ import type { ClassicConfig } from '@typescript-eslint/utils/ts-eslint'; export = { - plugins: ['@salesforce/lwc-mobile'] + plugins: ['@salesforce/lwc-mobile', '@graphql-eslint'], + overrides: [ + { + files: ['*.js'], + processor: '@graphql-eslint/graphql' + }, + { + files: ['*.graphql'], + parser: '@graphql-eslint/eslint-plugin', + + parserOptions: { + skipGraphQLConfig: true + }, + rules: { + '@salesforce/lwc-mobile/mutation-not-supported': 'warn' + } + } + ] } satisfies ClassicConfig.Config; diff --git a/src/index.ts b/src/index.ts index 43fedc7..53665cc 100644 --- a/src/index.ts +++ b/src/index.ts @@ -5,11 +5,10 @@ * For full license text, see the LICENSE file in the repo root or https://opensource.org/licenses/MIT */ -import type { Linter } from '@typescript-eslint/utils/ts-eslint'; - import base from './configs/base.js'; import recommended from './configs/recommended.js'; import enforceFooBar from './rules/dummy/enforce-foo-bar.js'; +import { rule as mutionNotSupported } from './rules/graphql/mutation-not-supported.js'; import { name, version } from '../package.json'; export = { configs: { @@ -21,6 +20,7 @@ export = { version }, rules: { - 'enforce-foo-bar': enforceFooBar + 'enforce-foo-bar': enforceFooBar, + 'mutation-not-supported': mutionNotSupported } -} satisfies Linter.Plugin; +}; diff --git a/src/rules/graphql/mutation-not-supported.ts b/src/rules/graphql/mutation-not-supported.ts new file mode 100644 index 0000000..4d5e562 --- /dev/null +++ b/src/rules/graphql/mutation-not-supported.ts @@ -0,0 +1,52 @@ +import { GraphQLESLintRule, GraphQLESLintRuleContext } from '@graphql-eslint/eslint-plugin'; + +import { getLocation } from '../utils'; +export const MESSAGE_ID = 'mutation-not-supported'; + +export const rule: GraphQLESLintRule = { + meta: { + type: 'problem', + hasSuggestions: false, + docs: { + description: 'mutation is not supported offline', + category: 'Operations', + recommended: true, + examples: [ + { + title: 'Incorrect', + code: /* GraphQL */ ` + mutation AccountExample { + uiapi { + AccountCreate(input: { Account: { Name: "Trailblazer Express" } }) { + Record { + Id + Name { + value + } + } + } + } + } + ` + } + ] + }, + messages: { + [MESSAGE_ID]: 'Mutation is not supported offline' + }, + schema: [] + }, + + create(context: GraphQLESLintRuleContext) { + return { + OperationDefinition(node) { + if (node.operation === 'mutation') { + context.report({ + messageId: MESSAGE_ID, + loc: getLocation(node.loc.start, node.operation) + }); + } + } + }; + } +}; diff --git a/src/rules/graphql/utils/types.ts b/src/rules/graphql/types.ts similarity index 100% rename from src/rules/graphql/utils/types.ts rename to src/rules/graphql/types.ts diff --git a/src/rules/utils.ts b/src/rules/utils.ts new file mode 100644 index 0000000..11d6987 --- /dev/null +++ b/src/rules/utils.ts @@ -0,0 +1,16 @@ +import { Position } from 'estree'; +import { AST } from 'eslint'; + +export function getLocation(start: Position, fieldName = ''): AST.SourceLocation { + const { line, column } = start; + return { + start: { + line, + column + }, + end: { + line, + column: column + fieldName.length + } + }; +} diff --git a/test/rules/graphql/mutation-not-supported.spec.ts b/test/rules/graphql/mutation-not-supported.spec.ts new file mode 100644 index 0000000..014684c --- /dev/null +++ b/test/rules/graphql/mutation-not-supported.spec.ts @@ -0,0 +1,32 @@ +import { RuleTester } from '@typescript-eslint/rule-tester'; +import { rule, MESSAGE_ID } from '../../../src/rules/graphql/mutation-not-supported'; + +const ruleTester = new RuleTester({ + parser: '@graphql-eslint/eslint-plugin', + parserOptions: { + graphQLConfig: {} + } +}); + +ruleTester.run('@salesforce/lwc-mobile/mutation-not-supported', rule as any, { + valid: [], + invalid: [ + { + code: /* GraphQL */ ` + mutation AccountExample { + uiapi { + AccountCreate(input: { Account: { Name: "Trailblazer Express" } }) { + Record { + Id + Name { + value + } + } + } + } + } + `, + errors: [{ messageId: MESSAGE_ID }] + } + ] +}); diff --git a/test/rules/utils.spec.ts b/test/rules/utils.spec.ts new file mode 100644 index 0000000..2f5f62c --- /dev/null +++ b/test/rules/utils.spec.ts @@ -0,0 +1,20 @@ +import { describe } from 'node:test'; +import { getLocation } from '../../src/rules/utils'; +import { Position } from 'estree'; + +import { expect } from '@jest/globals'; + +describe('utils', () => { + it('getLocation() should return location with field name length added', () => { + const startLocation: Position = { + line: 1, + column: 1 + }; + + const result = getLocation(startLocation, 'Field1'); + expect(result.end).toMatchObject({ + line: 1, + column: 7 + }); + }); +}); diff --git a/tsconfig.json b/tsconfig.json index 41deeed..c7a80b9 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -4,7 +4,9 @@ "target": "es2016" /* Set the JavaScript language version for emitted JavaScript and include compatible library declarations. */, "module": "Node16" /* Specify what module code is generated. */, "moduleResolution": "Node16" /* Specify how TypeScript looks up a file from a given module specifier. */, - "types": [] /* Specify type package names to be included without being referenced in a source file. */, + "types": [ + "jest" + ] /* Specify type package names to be included without being referenced in a source file. */, "rootDir": "./src", "outDir": "dist" /* Specify an output folder for all emitted files. */, "esModuleInterop": true /* Emit additional JavaScript to ease support for importing CommonJS modules. This enables 'allowSyntheticDefaultImports' for type compatibility. */, From d700d66b8959c18bcee6e708305c6752aea9559b Mon Sep 17 00:00:00 2001 From: "haifeng.li" Date: Fri, 17 May 2024 09:52:44 -0700 Subject: [PATCH 4/6] Clean up code with standard convention --- src/index.ts | 7 +++++-- ...utation-not-supported.ts => no-mutation-supported.ts} | 6 +++--- ...t-supported.spec.ts => no-mutation-supported.spec.ts} | 9 ++++++--- 3 files changed, 14 insertions(+), 8 deletions(-) rename src/rules/graphql/{mutation-not-supported.ts => no-mutation-supported.ts} (87%) rename test/rules/graphql/{mutation-not-supported.spec.ts => no-mutation-supported.spec.ts} (74%) diff --git a/src/index.ts b/src/index.ts index 53665cc..b9c6e64 100644 --- a/src/index.ts +++ b/src/index.ts @@ -8,7 +8,10 @@ import base from './configs/base.js'; import recommended from './configs/recommended.js'; import enforceFooBar from './rules/dummy/enforce-foo-bar.js'; -import { rule as mutionNotSupported } from './rules/graphql/mutation-not-supported.js'; +import { + rule as mutionNotSupported, + NO_MUTATION_SUPPORTED_RULE_ID +} from './rules/graphql/no-mutation-supported.js'; import { name, version } from '../package.json'; export = { configs: { @@ -21,6 +24,6 @@ export = { }, rules: { 'enforce-foo-bar': enforceFooBar, - 'mutation-not-supported': mutionNotSupported + [NO_MUTATION_SUPPORTED_RULE_ID]: mutionNotSupported } }; diff --git a/src/rules/graphql/mutation-not-supported.ts b/src/rules/graphql/no-mutation-supported.ts similarity index 87% rename from src/rules/graphql/mutation-not-supported.ts rename to src/rules/graphql/no-mutation-supported.ts index 4d5e562..186d4e4 100644 --- a/src/rules/graphql/mutation-not-supported.ts +++ b/src/rules/graphql/no-mutation-supported.ts @@ -1,7 +1,7 @@ import { GraphQLESLintRule, GraphQLESLintRuleContext } from '@graphql-eslint/eslint-plugin'; import { getLocation } from '../utils'; -export const MESSAGE_ID = 'mutation-not-supported'; +export const NO_MUTATION_SUPPORTED_RULE_ID = 'no-mutation-supported'; export const rule: GraphQLESLintRule = { meta: { @@ -32,7 +32,7 @@ export const rule: GraphQLESLintRule = { ] }, messages: { - [MESSAGE_ID]: 'Mutation is not supported offline' + [NO_MUTATION_SUPPORTED_RULE_ID]: 'Mutation is not supported offline' }, schema: [] }, @@ -42,7 +42,7 @@ export const rule: GraphQLESLintRule = { OperationDefinition(node) { if (node.operation === 'mutation') { context.report({ - messageId: MESSAGE_ID, + messageId: NO_MUTATION_SUPPORTED_RULE_ID, loc: getLocation(node.loc.start, node.operation) }); } diff --git a/test/rules/graphql/mutation-not-supported.spec.ts b/test/rules/graphql/no-mutation-supported.spec.ts similarity index 74% rename from test/rules/graphql/mutation-not-supported.spec.ts rename to test/rules/graphql/no-mutation-supported.spec.ts index 014684c..d44c9b1 100644 --- a/test/rules/graphql/mutation-not-supported.spec.ts +++ b/test/rules/graphql/no-mutation-supported.spec.ts @@ -1,5 +1,8 @@ import { RuleTester } from '@typescript-eslint/rule-tester'; -import { rule, MESSAGE_ID } from '../../../src/rules/graphql/mutation-not-supported'; +import { + rule, + NO_MUTATION_SUPPORTED_RULE_ID +} from '../../../src/rules/graphql/no-mutation-supported'; const ruleTester = new RuleTester({ parser: '@graphql-eslint/eslint-plugin', @@ -8,7 +11,7 @@ const ruleTester = new RuleTester({ } }); -ruleTester.run('@salesforce/lwc-mobile/mutation-not-supported', rule as any, { +ruleTester.run('@salesforce/lwc-mobile/no-mutation-supported', rule as any, { valid: [], invalid: [ { @@ -26,7 +29,7 @@ ruleTester.run('@salesforce/lwc-mobile/mutation-not-supported', rule as any, { } } `, - errors: [{ messageId: MESSAGE_ID }] + errors: [{ messageId: NO_MUTATION_SUPPORTED_RULE_ID }] } ] }); From 52b93d7700a71f3a6c0091b8f0e2181d14b49d1e Mon Sep 17 00:00:00 2001 From: "haifeng.li" Date: Fri, 17 May 2024 10:26:31 -0700 Subject: [PATCH 5/6] remove types.ts --- jest.config.ts | 7 +- src/rules/graphql/types.ts | 138 ------------------------------------- 2 files changed, 1 insertion(+), 144 deletions(-) delete mode 100644 src/rules/graphql/types.ts diff --git a/jest.config.ts b/jest.config.ts index 9005f93..eef3027 100644 --- a/jest.config.ts +++ b/jest.config.ts @@ -17,12 +17,7 @@ const config: Config = { testPathIgnorePatterns: ['/node_modules/', '/lib/'], moduleDirectories: ['node_modules'], collectCoverage: true, - collectCoverageFrom: [ - 'src/**/*.ts', - '!src/index.ts', - '!src/configs/*.ts', - '!src/graphql/types.ts' - ], + collectCoverageFrom: ['src/**/*.ts', '!src/index.ts', '!src/configs/*.ts'], coverageDirectory: 'reports/coverage', reporters: [ 'default', diff --git a/src/rules/graphql/types.ts b/src/rules/graphql/types.ts deleted file mode 100644 index e4bf90b..0000000 --- a/src/rules/graphql/types.ts +++ /dev/null @@ -1,138 +0,0 @@ -import { AST } from 'eslint'; -import { Comment, SourceLocation } from 'estree'; -import { - ArgumentNode, - ASTNode, - DefinitionNode, - DirectiveDefinitionNode, - DirectiveNode, - DocumentNode, - EnumTypeDefinitionNode, - EnumTypeExtensionNode, - EnumValueDefinitionNode, - ExecutableDefinitionNode, - FieldDefinitionNode, - FieldNode, - FragmentSpreadNode, - InlineFragmentNode, - InputObjectTypeDefinitionNode, - InputObjectTypeExtensionNode, - InputValueDefinitionNode, - InterfaceTypeDefinitionNode, - InterfaceTypeExtensionNode, - ListTypeNode, - NamedTypeNode, - NameNode, - NonNullTypeNode, - ObjectTypeDefinitionNode, - ObjectTypeExtensionNode, - OperationTypeDefinitionNode, - SelectionNode, - SelectionSetNode, - TypeDefinitionNode, - TypeExtensionNode, - TypeInfo, - TypeNode, - VariableDefinitionNode, - VariableNode -} from 'graphql'; - -type SafeGraphQLType = T extends { type: TypeNode } - ? Omit & { gqlType: T['type'] } - : Omit; - -type Writeable = { -readonly [K in keyof T]: T[K] }; - -export type TypeInformation = { - argument: ReturnType; - defaultValue: ReturnType; - directive: ReturnType; - enumValue: ReturnType; - fieldDef: ReturnType; - inputType: ReturnType; - parentInputType: ReturnType; - parentType: ReturnType; - gqlType: ReturnType; -}; - -type NodeWithName = - | ArgumentNode - | DirectiveDefinitionNode - | EnumValueDefinitionNode - | ExecutableDefinitionNode - | FieldDefinitionNode - | FieldNode - | FragmentSpreadNode - | NamedTypeNode - | TypeDefinitionNode - | TypeExtensionNode - | VariableNode; - -type NodeWithType = - | FieldDefinitionNode - | InputValueDefinitionNode - | ListTypeNode - | NonNullTypeNode - | OperationTypeDefinitionNode - | VariableDefinitionNode; - -type ParentNode = T extends DocumentNode - ? AST.Program - : T extends DefinitionNode - ? DocumentNode - : T extends EnumValueDefinitionNode - ? EnumTypeDefinitionNode | EnumTypeExtensionNode - : T extends InputValueDefinitionNode - ? - | DirectiveDefinitionNode - | FieldDefinitionNode - | InputObjectTypeDefinitionNode - | InputObjectTypeExtensionNode - : T extends FieldDefinitionNode - ? - | InterfaceTypeDefinitionNode - | InterfaceTypeExtensionNode - | ObjectTypeDefinitionNode - | ObjectTypeExtensionNode - : T extends SelectionSetNode - ? ExecutableDefinitionNode | FieldNode | InlineFragmentNode - : T extends SelectionNode - ? SelectionSetNode - : T extends TypeNode - ? NodeWithType - : T extends NameNode - ? NodeWithName - : T extends DirectiveNode - ? InputObjectTypeDefinitionNode | ObjectTypeDefinitionNode - : T extends VariableNode - ? VariableDefinitionNode - : unknown; // Explicitly show error to add new ternary with parent nodes - -type Node = - // Remove readonly for friendly editor popup - Writeable> & { - type: T['kind']; - loc: SourceLocation; - range: AST.Range; - leadingComments: Comment[]; - typeInfo: () => WithTypeInfo extends true ? TypeInformation : Record; - rawNode: () => T; - parent: GraphQLESTreeNode>; - }; - -export type GraphQLESTreeNode = - // if value is ASTNode => convert to Node type - T extends ASTNode - ? { - // Loop recursively over object values - [K in keyof Node]: Node[K] extends - | ReadonlyArray - | undefined // If optional readonly array => loop over array items - ? GraphQLESTreeNode[] - : GraphQLESTreeNode[K], W>; - } - : // If Program node => add `parent: null` field - T extends AST.Program - ? T & { parent: null } - : // Return value as is - T; From 7bcc0b389975f46973c889804114763b69e42394 Mon Sep 17 00:00:00 2001 From: "haifeng.li" Date: Mon, 20 May 2024 18:27:10 -0700 Subject: [PATCH 6/6] changes based on feedback --- package.json | 6 ++-- salesforce-eslint-plugin-lwc-mobile-0.0.1.tgz | Bin 0 -> 4344 bytes src/configs/base.ts | 20 ++--------- src/configs/recommended.ts | 20 +++++++++-- src/rules/graphql/no-mutation-supported.ts | 34 ++++++++++++++++-- src/{rules => }/utils.ts | 0 .../graphql/no-mutation-supported.spec.ts | 23 +++++++++++- test/rules/utils.spec.ts | 2 +- 8 files changed, 77 insertions(+), 28 deletions(-) create mode 100644 salesforce-eslint-plugin-lwc-mobile-0.0.1.tgz rename src/{rules => }/utils.ts (100%) diff --git a/package.json b/package.json index da600af..e6f7334 100644 --- a/package.json +++ b/package.json @@ -58,14 +58,14 @@ "/dist" ], "dependencies": { - "@graphql-eslint/eslint-plugin": "^3.20.1", - "@types/eslint": "^8.56.10", - "@types/estree": "^1.0.5" + "@graphql-eslint/eslint-plugin": "^3.20.1" }, "devDependencies": { "@eslint/js": "^9.2.0", "@jest/globals": "^29.7.0", "@types/jest": "^29.5.12", + "@types/eslint": "^8.56.10", + "@types/estree": "^1.0.5", "@typescript-eslint/eslint-plugin": "^7.8.0", "@typescript-eslint/parser": "^7.8.0", "@typescript-eslint/rule-tester": "^7.8.0", diff --git a/salesforce-eslint-plugin-lwc-mobile-0.0.1.tgz b/salesforce-eslint-plugin-lwc-mobile-0.0.1.tgz new file mode 100644 index 0000000000000000000000000000000000000000..22dd9c735ad57e9be682014f5bac3c92ad72bf63 GIT binary patch literal 4344 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 literal 0 HcmV?d00001 diff --git a/src/configs/base.ts b/src/configs/base.ts index e37e5b3..2ec1333 100644 --- a/src/configs/base.ts +++ b/src/configs/base.ts @@ -8,21 +8,7 @@ import type { ClassicConfig } from '@typescript-eslint/utils/ts-eslint'; export = { plugins: ['@salesforce/lwc-mobile', '@graphql-eslint'], - overrides: [ - { - files: ['*.js'], - processor: '@graphql-eslint/graphql' - }, - { - files: ['*.graphql'], - parser: '@graphql-eslint/eslint-plugin', - - parserOptions: { - skipGraphQLConfig: true - }, - rules: { - '@salesforce/lwc-mobile/mutation-not-supported': 'warn' - } - } - ] + rules: { + '@salesforce/lwc-mobile/enforce-foo-bar': 'warn' + } } satisfies ClassicConfig.Config; diff --git a/src/configs/recommended.ts b/src/configs/recommended.ts index 3eba7d7..4b5b1f6 100644 --- a/src/configs/recommended.ts +++ b/src/configs/recommended.ts @@ -8,7 +8,21 @@ import type { ClassicConfig } from '@typescript-eslint/utils/ts-eslint'; export = { extends: ['./configs/base'], - rules: { - '@salesforce/lwc-mobile/enforce-foo-bar': 'warn' - } + overrides: [ + { + files: ['*.js'], + processor: '@graphql-eslint/graphql' + }, + { + files: ['*.graphql'], + parser: '@graphql-eslint/eslint-plugin', + + parserOptions: { + skipGraphQLConfig: true + }, + rules: { + '@salesforce/lwc-mobile/offline-graphql-no-mutation-supported': 'warn' + } + } + ] } satisfies ClassicConfig.Config; diff --git a/src/rules/graphql/no-mutation-supported.ts b/src/rules/graphql/no-mutation-supported.ts index 186d4e4..a8b3e70 100644 --- a/src/rules/graphql/no-mutation-supported.ts +++ b/src/rules/graphql/no-mutation-supported.ts @@ -1,7 +1,13 @@ +/* + * Copyright (c) 2024, salesforce.com, inc. + * All rights reserved. + * SPDX-License-Identifier: MIT + * For full license text, see the LICENSE file in the repo root or https://opensource.org/licenses/MIT + */ import { GraphQLESLintRule, GraphQLESLintRuleContext } from '@graphql-eslint/eslint-plugin'; -import { getLocation } from '../utils'; -export const NO_MUTATION_SUPPORTED_RULE_ID = 'no-mutation-supported'; +import { getLocation } from '../../utils'; +export const NO_MUTATION_SUPPORTED_RULE_ID = 'offline-graphql-no-mutation-supported'; export const rule: GraphQLESLintRule = { meta: { @@ -12,6 +18,27 @@ export const rule: GraphQLESLintRule = { category: 'Operations', recommended: true, examples: [ + { + title: 'Correct', + code: /* GraphQL */ ` + query accountQuery { + uiapi { + query { + Account { + edges { + node { + Id + Name { + value + } + } + } + } + } + } + } + ` + }, { title: 'Incorrect', code: /* GraphQL */ ` @@ -32,7 +59,8 @@ export const rule: GraphQLESLintRule = { ] }, messages: { - [NO_MUTATION_SUPPORTED_RULE_ID]: 'Mutation is not supported offline' + [NO_MUTATION_SUPPORTED_RULE_ID]: + 'Offline GraphQL: Mutation (data modification) is not supported offline.' }, schema: [] }, diff --git a/src/rules/utils.ts b/src/utils.ts similarity index 100% rename from src/rules/utils.ts rename to src/utils.ts diff --git a/test/rules/graphql/no-mutation-supported.spec.ts b/test/rules/graphql/no-mutation-supported.spec.ts index d44c9b1..04f681c 100644 --- a/test/rules/graphql/no-mutation-supported.spec.ts +++ b/test/rules/graphql/no-mutation-supported.spec.ts @@ -12,7 +12,28 @@ const ruleTester = new RuleTester({ }); ruleTester.run('@salesforce/lwc-mobile/no-mutation-supported', rule as any, { - valid: [], + valid: [ + { + code: /* GraphQL */ ` + query accountQuery { + uiapi { + query { + Account { + edges { + node { + Id + Name { + value + } + } + } + } + } + } + } + ` + } + ], invalid: [ { code: /* GraphQL */ ` diff --git a/test/rules/utils.spec.ts b/test/rules/utils.spec.ts index 2f5f62c..b74a05b 100644 --- a/test/rules/utils.spec.ts +++ b/test/rules/utils.spec.ts @@ -1,5 +1,5 @@ import { describe } from 'node:test'; -import { getLocation } from '../../src/rules/utils'; +import { getLocation } from '../../src/utils'; import { Position } from 'estree'; import { expect } from '@jest/globals';