[Linter] Update linter rule to check if sdk-type exists in package.json (#18597)

This fixes #13214. This PR is an update from a past PR, https://github.com/Azure/azure-sdk-for-js/pull/18565.

What's new?
- I updated ```ts-package-json-sdktype.ts``` to enforce the existence of```sdk-type``` and that it is either ```client``` or ```mgmt```. If it does not, then the linter will throw an error.
- I added/updated appropriate tests and verified the entire repository using ```rush lint```
- I also put the rules in the correct files (```src/configs/index.ts, src/rules/index.ts```, and ```tests/plugin.ts```)
- I have written a docs file to put in ```docs/rules``` which are now included in the commit! 
- I do need to still update the actual ```README.md``` file, but I'm not sure what the actual version is (hopefully this isn't too much trouble)
This commit is contained in:
Ben Zhang 2021-11-09 16:46:33 -08:00 коммит произвёл GitHub
Родитель b1ae6ca29b
Коммит 41018c38bb
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: 4AEE18F83AFDEB23
8 изменённых файлов: 566 добавлений и 35 удалений

Просмотреть файл

@ -125,6 +125,7 @@ Some rules (see table below) are fixable using the `--fix` ESLint option (added
| [**ts-package-json-name**](https://github.com/Azure/azure-sdk-for-js/blob/main/common/tools/eslint-plugin-azure-sdk/docs/rules/ts-package-json-name.md) | :triangular_flag_on_post: | :x: | `1.0.0` |
| [**ts-package-json-repo**](https://github.com/Azure/azure-sdk-for-js/blob/main/common/tools/eslint-plugin-azure-sdk/docs/rules/ts-package-json-repo.md) | :triangular_flag_on_post: | :heavy_check_mark: | `1.0.0` |
| [**ts-package-json-required-scripts**](https://github.com/Azure/azure-sdk-for-js/blob/main/common/tools/eslint-plugin-azure-sdk/docs/rules/ts-package-json-required-scripts.md) | :triangular_flag_on_post: | :x: | `1.0.0` |
| [**ts-package-json-sdktype**](https://github.com/Azure/azure-sdk-for-js/blob/main/common/tools/eslint-plugin-azure-sdk/docs/rules/ts-package-json-sdktype.md) | :triangular_flag_on_post: | :x: | `3.1.0` |
| [**ts-package-json-sideeffects**](https://github.com/Azure/azure-sdk-for-js/blob/main/common/tools/eslint-plugin-azure-sdk/docs/rules/ts-package-json-sideeffects.md) | :triangular_flag_on_post: | :heavy_check_mark: | `1.0.0` |
| [**ts-package-json-types**](https://github.com/Azure/azure-sdk-for-js/blob/main/common/tools/eslint-plugin-azure-sdk/docs/rules/ts-package-json-types.md) | :triangular_flag_on_post: | :x: | `1.1.0` |
| [**ts-pagination-list**](https://github.com/Azure/azure-sdk-for-js/blob/main/common/tools/eslint-plugin-azure-sdk/docs/rules/ts-pagination-list.md) | :triangular_flag_on_post: | :x: | `1.2.0` |

Просмотреть файл

@ -0,0 +1,67 @@
# ts-package-json-sdktype
Requires the existence of the `sdk-type` field and be either 'client', 'mgmt', or 'utility'.
## Examples
### Good
```json
{
"sdk-type": "client"
}
```
```json
{
"sdk-type": "mgmt"
}
```
```json
{
"sdk-type": "utility"
}
```
### Bad
```json
{
"sdk-type": "invalid"
}
```
```json
{
"sdk-type": 1
}
```
```json
{
"sdk-type": true
}
```
```json
{
"not-sdk-type": "client"
}
```
```json
{
"outer": {
"sdk-type": "client"
}
}
```
```json
{}
```
## When to turn off
Only if the rule breaks.

Просмотреть файл

@ -48,7 +48,6 @@ export = {
"@azure/azure-sdk/ts-no-const-enums": "warn",
"@azure/azure-sdk/ts-no-namespaces": "error",
"@azure/azure-sdk/ts-no-window": "error",
"@azure/azure-sdk/ts-package-json-sdktype": "error",
"@azure/azure-sdk/ts-package-json-author": "error",
"@azure/azure-sdk/ts-package-json-bugs": "error",
"@azure/azure-sdk/ts-package-json-engine-is-present": "error",
@ -61,6 +60,7 @@ export = {
"@azure/azure-sdk/ts-package-json-name": "error",
"@azure/azure-sdk/ts-package-json-repo": "error",
"@azure/azure-sdk/ts-package-json-required-scripts": "error",
"@azure/azure-sdk/ts-package-json-sdktype": "error",
"@azure/azure-sdk/ts-package-json-sideeffects": "error",
"@azure/azure-sdk/ts-package-json-types": "error",
"@azure/azure-sdk/ts-pagination-list": "error",

Просмотреть файл

@ -33,7 +33,6 @@ import tsNoConstEnums from "./ts-no-const-enums";
import tsNoNamespaces from "./ts-no-namespaces";
import tsNoWindow from "./ts-no-window";
import tsPackageJsonAuthor from "./ts-package-json-author";
import tsPackageJsonSdkType from "./ts-package-json-sdktype";
import tsPackageJsonBugs from "./ts-package-json-bugs";
import tsPackageJsonEngineIsPresent from "./ts-package-json-engine-is-present";
import tsPackageJsonFilesRequired from "./ts-package-json-files-required";
@ -45,6 +44,7 @@ import tsPackageJsonModule from "./ts-package-json-module";
import tsPackageJsonName from "./ts-package-json-name";
import tsPackageJsonRepo from "./ts-package-json-repo";
import tsPackageJsonRequiredScripts from "./ts-package-json-required-scripts";
import tsPackageJsonSdkType from "./ts-package-json-sdktype";
import tsPackageJsonSideEffects from "./ts-package-json-sideeffects";
import tsPackageJsonTypes from "./ts-package-json-types";
import tsPaginationList from "./ts-pagination-list";

Просмотреть файл

@ -2,13 +2,14 @@
// Licensed under the MIT license.
/**
* @file Rule to force package.json's 'sdk-type' value to be valid
* @file Rule to force package.json's 'sdk-type' value to be valid (and exist)
* @author Arpan Laha
* @author Ben Zhang
*/
import { Rule } from "eslint";
import { Property } from "estree";
import { getRuleMetaData, stripPath } from "../utils";
import { getRuleMetaData, getVerifiers, stripPath } from "../utils";
//------------------------------------------------------------------------------
// Rule Definition
@ -17,41 +18,46 @@ import { getRuleMetaData, stripPath } from "../utils";
export = {
meta: getRuleMetaData(
"ts-package-json-sdktype",
"force package.json's sdk-type value to contain be 'client' or 'mgmt'"
"force package.json's sdk-type to exist and for its value to be 'client' or 'mgmt'",
"code"
),
create: (context: Rule.RuleContext): Rule.RuleListener =>
stripPath(context.getFilename()) === "package.json"
create: (context: Rule.RuleContext): Rule.RuleListener => {
const verifiers = getVerifiers(context, {
outer: "sdk-type"
});
return stripPath(context.getFilename()) === "package.json"
? ({
// callback functions
// callback functions
// check the node corresponding to sdk-type to see if its value contains "client" or "mgmt"
"ExpressionStatement > ObjectExpression > Property[key.value='sdk-type']": (
node: Property
) => {
if (!node) {
// Track1 packages don't have this property. Stop checking
return;
}
// check to see if package.json includes 'sdk-type'
"ExpressionStatement > ObjectExpression": verifiers.existsInFile,
const { value } = node;
if (value.type !== "Literal" || typeof value.value !== "string") {
context.report({
node: node.value,
message: "sdk-type is not set to a string"
});
return;
}
// check the node corresponding to sdk-type to see if its value contains "client" or "mgmt"
"ExpressionStatement > ObjectExpression > Property[key.value='sdk-type']": (
node: Property
): void => {
const { value } = node;
const strValue = stripPath(value.value);
if (!["client", "mgmt"].includes(strValue)) {
context.report({
node: node.value,
message: "sdk-type is not set to `client` or `mgmt`"
});
return;
}
// check for valid type
if (value.type !== "Literal" || typeof value.value !== "string") {
context.report({
node: node.value,
message: "sdk-type is not set to a string"
});
return;
}
} as Rule.RuleListener)
: {}
const strValue = stripPath(value.value);
if (!["client", "mgmt", "utility"].includes(strValue)) {
context.report({
node: node.value,
message: `unrecognized sdk-type value: ${strValue}. Expected either "client", "mgmt", or "utility."`
});
return;
}
}
} as Rule.RuleListener)
: {};
}
};

Просмотреть файл

@ -53,6 +53,7 @@ const ruleList = [
"ts-package-json-name",
"ts-package-json-repo",
"ts-package-json-required-scripts",
"ts-package-json-sdktype",
"ts-package-json-sideeffects",
"ts-package-json-types",
"ts-pagination-list",

Просмотреть файл

@ -0,0 +1,455 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.
/**
* @file Testing the ts-package-json-sdktype rule.
* @author Ben Zhang
*/
import { RuleTester } from "eslint";
import rule from "../../src/rules/ts-package-json-sdktype";
//------------------------------------------------------------------------------
// Example files
//------------------------------------------------------------------------------
const examplePackageGood = `{
"name": "@azure/event-hubs",
"sdk-type": "client",
"version": "5.7.0-beta.1",
"description": "Azure Event Hubs SDK for JS.",
"author": "Microsoft Corporation",
"license": "MIT",
"homepage": "https://github.com/Azure/azure-sdk-for-js/tree/main/sdk/eventhub/event-hubs/",
"repository": "github:Azure/azure-sdk-for-js",
"sideEffects": false,
"keywords": [
"azure",
"cloud",
"event hubs",
"events",
"Azure"
],
"bugs": {
"url": "https://github.com/Azure/azure-sdk-for-js/issues"
},
"engines": {
"node": ">=12.0.0"
},
"main": "./dist/index.js",
"module": "dist-esm/src/index.js",
"types": "./types/latest/event-hubs.d.ts",
"typesVersions": {
"<3.6": {
"types/latest/*": [
"types/3.1/*"
]
}
},
"browser": {
"./dist-esm/src/util/runtimeInfo.js": "./dist-esm/src/util/runtimeInfo.browser.js",
"./dist-esm/test/public/utils/mockService.js": "./dist-esm/test/public/utils/mockService.browser.js"
},
"files": [
"dist/",
"dist-esm/src/",
"types/latest/",
"types/3.1/",
"README.md",
"LICENSE"
],
"//metadata": {
"constantPaths": [
{
"path": "src/util/constants.ts",
"prefix": "version"
}
]
},
"//sampleConfiguration": {
"extraFiles": {
"./samples-browser": [
"browser"
],
"./samples-express": [
"express"
]
},
"skip": [
"iothubConnectionString.js",
"iothubConnectionStringWebsockets.js",
"useWithIotHub.js",
"usingAadAuth.js"
],
"productName": "Azure Event Hubs",
"productSlugs": [
"azure",
"azure-event-hubs"
],
"requiredResources": {
"Azure Event Hub": "https://docs.microsoft.com/azure/event-hubs/event-hubs-create"
}
},
"dependencies": {
"@azure/abort-controller": "^1.0.0",
"@azure/core-amqp": "^3.0.0",
"@azure/core-asynciterator-polyfill": "^1.0.0",
"@azure/core-auth": "^1.3.0",
"@azure/core-tracing": "1.0.0-preview.13",
"@azure/logger": "^1.0.0",
"buffer": "^6.0.0",
"is-buffer": "^2.0.3",
"jssha": "^3.1.0",
"process": "^0.11.10",
"rhea-promise": "^2.1.0",
"tslib": "^2.2.0",
"uuid": "^8.3.0"
},
"devDependencies": {
"@azure/dev-tool": "^1.0.0",
"@azure/eslint-plugin-azure-sdk": "^3.0.0",
"@azure/identity": "^2.0.1",
"@azure/mock-hub": "^1.0.0",
"@azure/test-utils": "^1.0.0",
"@azure/test-utils-perf": "^1.0.0",
"@microsoft/api-extractor": "^7.18.11",
"@rollup/plugin-commonjs": "11.0.2",
"@rollup/plugin-inject": "^4.0.0",
"@rollup/plugin-json": "^4.0.0",
"@rollup/plugin-multi-entry": "^3.0.0",
"@rollup/plugin-node-resolve": "^8.0.0",
"@rollup/plugin-replace": "^2.2.0",
"@types/async-lock": "^1.1.0",
"@types/chai": "^4.1.6",
"@types/chai-as-promised": "^7.1.0",
"@types/chai-string": "^1.4.1",
"@types/debug": "^4.1.4",
"@types/long": "^4.0.0",
"@types/mocha": "^7.0.2",
"@types/node": "^12.0.0",
"@types/sinon": "^9.0.4",
"@types/uuid": "^8.0.0",
"@types/ws": "^7.2.4",
"assert": "^1.4.1",
"chai": "^4.2.0",
"chai-as-promised": "^7.1.1",
"chai-exclude": "^2.0.2",
"chai-string": "^1.5.0",
"cross-env": "^7.0.2",
"debug": "^4.1.1",
"dotenv": "^8.2.0",
"downlevel-dts": "~0.4.0",
"eslint": "^7.15.0",
"esm": "^3.2.18",
"https-proxy-agent": "^5.0.0",
"karma": "^6.2.0",
"karma-chrome-launcher": "^3.0.0",
"karma-coverage": "^2.0.0",
"karma-edge-launcher": "^0.4.2",
"karma-env-preprocessor": "^0.1.1",
"karma-firefox-launcher": "^1.1.0",
"karma-ie-launcher": "^1.0.0",
"karma-junit-reporter": "^2.0.1",
"karma-mocha": "^2.0.1",
"karma-mocha-reporter": "^2.2.5",
"karma-sourcemap-loader": "^0.3.8",
"mocha": "^7.1.1",
"mocha-junit-reporter": "^1.18.0",
"moment": "^2.24.0",
"nyc": "^14.0.0",
"prettier": "^1.16.4",
"puppeteer": "^10.2.0",
"rimraf": "^3.0.0",
"rollup": "^1.16.3",
"rollup-plugin-shim": "^1.0.0",
"rollup-plugin-sourcemaps": "^0.4.2",
"rollup-plugin-terser": "^5.1.1",
"sinon": "^9.0.2",
"ts-node": "^10.0.0",
"typescript": "~4.2.0",
"ws": "^7.1.1",
"typedoc": "0.15.2"
}
}`;
const examplePackageBad = `{
"name": "@azure/event-hubs",
"version": "5.7.0-beta.1",
"description": "Azure Event Hubs SDK for JS.",
"author": "Microsoft Corporation",
"license": "MIT",
"homepage": "https://github.com/Azure/azure-sdk-for-js/tree/main/sdk/eventhub/event-hubs/",
"repository": "github:Azure/azure-sdk-for-js",
"sideEffects": false,
"keywords": [
"azure",
"cloud",
"event hubs",
"events",
"Azure"
],
"bugs": {
"url": "https://github.com/Azure/azure-sdk-for-js/issues"
},
"engines": {
"node": ">=12.0.0"
},
"main": "./dist/index.js",
"module": "dist-esm/src/index.js",
"types": "./types/latest/event-hubs.d.ts",
"typesVersions": {
"<3.6": {
"types/latest/*": [
"types/3.1/*"
]
}
},
"browser": {
"./dist-esm/src/util/runtimeInfo.js": "./dist-esm/src/util/runtimeInfo.browser.js",
"./dist-esm/test/public/utils/mockService.js": "./dist-esm/test/public/utils/mockService.browser.js"
},
"files": [
"dist/",
"dist-esm/src/",
"types/latest/",
"types/3.1/",
"README.md",
"LICENSE"
],
"//metadata": {
"constantPaths": [
{
"path": "src/util/constants.ts",
"prefix": "version"
}
]
},
"//sampleConfiguration": {
"extraFiles": {
"./samples-browser": [
"browser"
],
"./samples-express": [
"express"
]
},
"skip": [
"iothubConnectionString.js",
"iothubConnectionStringWebsockets.js",
"useWithIotHub.js",
"usingAadAuth.js"
],
"productName": "Azure Event Hubs",
"productSlugs": [
"azure",
"azure-event-hubs"
],
"requiredResources": {
"Azure Event Hub": "https://docs.microsoft.com/azure/event-hubs/event-hubs-create"
}
},
"dependencies": {
"@azure/abort-controller": "^1.0.0",
"@azure/core-amqp": "^3.0.0",
"@azure/core-asynciterator-polyfill": "^1.0.0",
"@azure/core-auth": "^1.3.0",
"@azure/core-tracing": "1.0.0-preview.13",
"@azure/logger": "^1.0.0",
"buffer": "^6.0.0",
"is-buffer": "^2.0.3",
"jssha": "^3.1.0",
"process": "^0.11.10",
"rhea-promise": "^2.1.0",
"tslib": "^2.2.0",
"uuid": "^8.3.0"
},
"devDependencies": {
"@azure/dev-tool": "^1.0.0",
"@azure/eslint-plugin-azure-sdk": "^3.0.0",
"@azure/identity": "^2.0.1",
"@azure/mock-hub": "^1.0.0",
"@azure/test-utils": "^1.0.0",
"@azure/test-utils-perf": "^1.0.0",
"@microsoft/api-extractor": "^7.18.11",
"@rollup/plugin-commonjs": "11.0.2",
"@rollup/plugin-inject": "^4.0.0",
"@rollup/plugin-json": "^4.0.0",
"@rollup/plugin-multi-entry": "^3.0.0",
"@rollup/plugin-node-resolve": "^8.0.0",
"@rollup/plugin-replace": "^2.2.0",
"@types/async-lock": "^1.1.0",
"@types/chai": "^4.1.6",
"@types/chai-as-promised": "^7.1.0",
"@types/chai-string": "^1.4.1",
"@types/debug": "^4.1.4",
"@types/long": "^4.0.0",
"@types/mocha": "^7.0.2",
"@types/node": "^12.0.0",
"@types/sinon": "^9.0.4",
"@types/uuid": "^8.0.0",
"@types/ws": "^7.2.4",
"assert": "^1.4.1",
"chai": "^4.2.0",
"chai-as-promised": "^7.1.1",
"chai-exclude": "^2.0.2",
"chai-string": "^1.5.0",
"cross-env": "^7.0.2",
"debug": "^4.1.1",
"dotenv": "^8.2.0",
"downlevel-dts": "~0.4.0",
"eslint": "^7.15.0",
"esm": "^3.2.18",
"https-proxy-agent": "^5.0.0",
"karma": "^6.2.0",
"karma-chrome-launcher": "^3.0.0",
"karma-coverage": "^2.0.0",
"karma-edge-launcher": "^0.4.2",
"karma-env-preprocessor": "^0.1.1",
"karma-firefox-launcher": "^1.1.0",
"karma-ie-launcher": "^1.0.0",
"karma-junit-reporter": "^2.0.1",
"karma-mocha": "^2.0.1",
"karma-mocha-reporter": "^2.2.5",
"karma-sourcemap-loader": "^0.3.8",
"mocha": "^7.1.1",
"mocha-junit-reporter": "^1.18.0",
"moment": "^2.24.0",
"nyc": "^14.0.0",
"prettier": "^1.16.4",
"puppeteer": "^10.2.0",
"rimraf": "^3.0.0",
"rollup": "^1.16.3",
"rollup-plugin-shim": "^1.0.0",
"rollup-plugin-sourcemaps": "^0.4.2",
"rollup-plugin-terser": "^5.1.1",
"sinon": "^9.0.2",
"ts-node": "^10.0.0",
"typescript": "~4.2.0",
"ws": "^7.1.1",
"typedoc": "0.15.2"
}
}`;
//------------------------------------------------------------------------------
// Tests
//------------------------------------------------------------------------------
const ruleTester = new RuleTester({
parser: require.resolve("@typescript-eslint/parser"),
parserOptions: {
createDefaultProgram: true,
project: "./tsconfig.json"
}
});
ruleTester.run("ts-package-json-sdktype", rule, {
valid: [
{
// only the fields we care about
code: '{"sdk-type": "client"}',
filename: "package.json"
},
{
// only the fields we care about
code: '{"sdk-type": "mgmt"}',
filename: "package.json"
},
{
// only the fields we care about
code: '{"sdk-type": "utility"}',
filename: "package.json"
},
{
// a full example package.json (taken from https://github.com/Azure/azure-sdk-for-js/blob/main/sdk/eventhub/event-hubs/package.json with "scripts" removed for testing purposes)
code: examplePackageGood,
filename: "package.json"
},
{
// incorrect format but in a file we don't care about
code: '{"types": "typings/index.d.ts"}',
filename: "not_package.json"
}
],
invalid: [
{
// sdk-type has incorrect value
code: '{"sdk-type": "clien"}',
filename: "package.json",
errors: [
{
message: 'unrecognized sdk-type value: clien. Expected either "client", "mgmt", or "utility."'
}
]
},
{
// sdk-type has incorrect value
code: '{"sdk-type": "mgm"}',
filename: "package.json",
errors: [
{
message: 'unrecognized sdk-type value: mgm. Expected either "client", "mgmt", or "utility."'
}
]
},
{
// sdk-type has incorrect value
code: '{"sdk-type": "util"}',
filename: "package.json",
errors: [
{
message: 'unrecognized sdk-type value: util. Expected either "client", "mgmt", or "utility."'
}
]
},
{
// sdk-type has incorrect value
code: '{"sdk-type": 1}',
filename: "package.json",
errors: [
{
message: "sdk-type is not set to a string"
}
]
},
{
// sdk-type has incorrect value
code: '{"sdk-type": true}',
filename: "package.json",
errors: [
{
message: "sdk-type is not set to a string"
}
]
},
{
// sdk-type does not exist
code: '{"not-sdk-type": "client"}',
filename: "package.json",
errors: [
{
message: "sdk-type does not exist at the outermost level"
}
]
},
{
// sdk-type is in a nested object
code: '{"outer": {"sdk-type": "client"}}',
filename: "package.json",
errors: [
{
message: "sdk-type does not exist at the outermost level"
}
]
},
{
// sdk-type does not exist
code: examplePackageBad,
filename: "package.json",
errors: [
{
message: "sdk-type does not exist at the outermost level"
}
]
}
]
});

Просмотреть файл

@ -1,6 +1,7 @@
{
"name": "@azure/keyvault-common",
"sideEffects": false,
"sdk-type": "client",
"private": true,
"author": "Microsoft Corporation",
"version": "1.0.0",