Merge pull request #16174 from backstage/rugvip/rules
add @backstage/eslint-plugin
This commit is contained in:
@@ -0,0 +1,5 @@
|
||||
---
|
||||
'@backstage/backend-test-utils': patch
|
||||
---
|
||||
|
||||
Removed unnecessary `@backstage/cli` dependency.
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
'@backstage/cli': patch
|
||||
---
|
||||
|
||||
Replaced several monorepo lint rules with new rules from `@backstage/eslint-plugin`. See the [README](https://github.com/import-js/eslint-plugin-import/blob/main/packages/eslint-plugin/README.md) for a full list of rules.
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
'@backstage/codemods': patch
|
||||
---
|
||||
|
||||
Moved `commander` to being a regular dependency.
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
'@backstage/repo-tools': patch
|
||||
---
|
||||
|
||||
Packages without a declared `backstage.role` are now ignored.
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
'@backstage/eslint-plugin': minor
|
||||
---
|
||||
|
||||
Added a new ESLint plugin with common rules for Backstage projects. See the [README](https://github.com/import-js/eslint-plugin-import/blob/main/packages/eslint-plugin/README.md) for more details.
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
'@backstage/create-app': patch
|
||||
---
|
||||
|
||||
Updated `packages/app/cypress/.eslintrc.json` to remove the unnecessary `import/no-extraneous-dependencies` rule.
|
||||
@@ -336,6 +336,7 @@ subfolders
|
||||
subheader
|
||||
subheaders
|
||||
subkey
|
||||
subpath
|
||||
subroutes
|
||||
subtree
|
||||
superfences
|
||||
@@ -418,4 +419,4 @@ Dominik
|
||||
Henneke
|
||||
Kuang
|
||||
Frontside
|
||||
Kaswell
|
||||
Kaswell
|
||||
|
||||
@@ -2,15 +2,6 @@ module.exports = {
|
||||
extends: [require.resolve('@backstage/cli/config/eslint.backend')],
|
||||
rules: {
|
||||
'no-console': 0,
|
||||
'import/no-extraneous-dependencies': [
|
||||
'error',
|
||||
{
|
||||
devDependencies: true,
|
||||
optionalDependencies: false,
|
||||
peerDependencies: false,
|
||||
bundledDependencies: false,
|
||||
},
|
||||
],
|
||||
'jest/valid-expect': 'off',
|
||||
'jest/expect-expect': 'off',
|
||||
'no-restricted-syntax': 'off',
|
||||
|
||||
@@ -7,15 +7,6 @@
|
||||
{
|
||||
"assertFunctionNames": ["expect", "cy.contains"]
|
||||
}
|
||||
],
|
||||
"import/no-extraneous-dependencies": [
|
||||
"error",
|
||||
{
|
||||
"devDependencies": true,
|
||||
"optionalDependencies": true,
|
||||
"peerDependencies": true,
|
||||
"bundledDependencies": true
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
@@ -40,7 +40,7 @@ import {
|
||||
} from '@backstage/backend-plugin-api';
|
||||
|
||||
// Internal import of the type to avoid needing to export this.
|
||||
// eslint-disable-next-line monorepo/no-internal-import
|
||||
// eslint-disable-next-line @backstage/no-forbidden-package-imports
|
||||
import type { InternalSharedBackendEnvironment } from '@backstage/backend-plugin-api/src/wiring/createSharedEnvironment';
|
||||
|
||||
export const defaultServiceFactories = [
|
||||
|
||||
@@ -37,7 +37,6 @@
|
||||
"@backstage/backend-app-api": "workspace:^",
|
||||
"@backstage/backend-common": "workspace:^",
|
||||
"@backstage/backend-plugin-api": "workspace:^",
|
||||
"@backstage/cli": "workspace:^",
|
||||
"@backstage/config": "workspace:^",
|
||||
"@backstage/plugin-auth-node": "workspace:^",
|
||||
"@backstage/types": "workspace:^",
|
||||
|
||||
+1
-1
@@ -14,7 +14,7 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
/* eslint-disable import/no-extraneous-dependencies */
|
||||
/* eslint-disable @backstage/no-undeclared-imports */
|
||||
|
||||
/// <reference types="node" />
|
||||
/// <reference types="react" />
|
||||
|
||||
@@ -60,7 +60,7 @@ function createConfig(dir, extraConfig = {}) {
|
||||
'@spotify/eslint-config-typescript',
|
||||
'prettier',
|
||||
'plugin:jest/recommended',
|
||||
'plugin:monorepo/recommended',
|
||||
'plugin:@backstage/recommended',
|
||||
...(extraExtends ?? []),
|
||||
],
|
||||
parser: '@typescript-eslint/parser',
|
||||
@@ -88,32 +88,6 @@ function createConfig(dir, extraConfig = {}) {
|
||||
'@typescript-eslint/no-redeclare': 'error',
|
||||
'no-undef': 'off',
|
||||
'import/newline-after-import': 'error',
|
||||
'import/no-extraneous-dependencies': [
|
||||
'error',
|
||||
{
|
||||
devDependencies: dir
|
||||
? [
|
||||
`!${joinPath(dir, 'src/**')}`,
|
||||
joinPath(dir, 'src/**/*.test.*'),
|
||||
joinPath(dir, 'src/**/*.stories.*'),
|
||||
joinPath(dir, 'src/**/__testUtils__/**'),
|
||||
joinPath(dir, 'src/**/__mocks__/**'),
|
||||
joinPath(dir, 'src/setupTests.*'),
|
||||
]
|
||||
: [
|
||||
// Legacy config for packages that don't provide a dir
|
||||
'**/*.test.*',
|
||||
'**/*.stories.*',
|
||||
'**/__testUtils__/**',
|
||||
'**/__mocks__/**',
|
||||
'**/src/setupTests.*',
|
||||
'**/dev/**',
|
||||
],
|
||||
optionalDependencies: true,
|
||||
peerDependencies: true,
|
||||
bundledDependencies: true,
|
||||
},
|
||||
],
|
||||
'no-unused-expressions': 'off',
|
||||
'@typescript-eslint/no-unused-expressions': 'error',
|
||||
'@typescript-eslint/consistent-type-assertions': 'error',
|
||||
@@ -135,9 +109,6 @@ function createConfig(dir, extraConfig = {}) {
|
||||
...(restrictedSrcImports ?? []),
|
||||
],
|
||||
patterns: [
|
||||
// Avoid cross-package imports
|
||||
'**/../../**/*/src/**',
|
||||
'**/../../**/*/src',
|
||||
// Prevent imports of stories or tests
|
||||
'*.stories*',
|
||||
'*.test*',
|
||||
@@ -187,8 +158,6 @@ function createConfig(dir, extraConfig = {}) {
|
||||
...(restrictedImports ?? []),
|
||||
...(restrictedTestImports ?? []),
|
||||
],
|
||||
// Avoid cross-package imports
|
||||
patterns: ['**/../../**/*/src/**', '**/../../**/*/src'],
|
||||
},
|
||||
],
|
||||
},
|
||||
|
||||
@@ -34,6 +34,7 @@
|
||||
"@backstage/config": "workspace:^",
|
||||
"@backstage/config-loader": "workspace:^",
|
||||
"@backstage/errors": "workspace:^",
|
||||
"@backstage/eslint-plugin": "workspace:^",
|
||||
"@backstage/release-manifests": "workspace:^",
|
||||
"@backstage/types": "workspace:^",
|
||||
"@esbuild-kit/cjs-loader": "^2.4.1",
|
||||
@@ -78,7 +79,6 @@
|
||||
"eslint-plugin-import": "^2.25.4",
|
||||
"eslint-plugin-jest": "^27.0.0",
|
||||
"eslint-plugin-jsx-a11y": "^6.5.1",
|
||||
"eslint-plugin-monorepo": "^0.3.2",
|
||||
"eslint-plugin-react": "^7.28.0",
|
||||
"eslint-plugin-react-hooks": "^4.3.0",
|
||||
"eslint-webpack-plugin": "^3.1.1",
|
||||
|
||||
@@ -50,7 +50,7 @@ export async function buildTypeDefinitionsWorker(
|
||||
*/
|
||||
const {
|
||||
PackageJsonLookup,
|
||||
// eslint-disable-next-line import/no-extraneous-dependencies
|
||||
// eslint-disable-next-line @backstage/no-undeclared-imports
|
||||
} = require('@rushstack/node-core-library/lib/PackageJsonLookup');
|
||||
|
||||
const old = PackageJsonLookup.prototype.tryGetPackageJsonFilePathFor;
|
||||
|
||||
@@ -17,7 +17,6 @@
|
||||
import mockFs from 'mock-fs';
|
||||
import { packageVersions, createPackageVersionProvider } from './version';
|
||||
import { Lockfile } from './versioning';
|
||||
// eslint-disable-next-line monorepo/no-internal-import
|
||||
import corePluginApiPkg from '@backstage/core-plugin-api/package.json';
|
||||
|
||||
describe('createPackageVersionProvider', () => {
|
||||
|
||||
@@ -19,7 +19,7 @@ import semver from 'semver';
|
||||
import { paths } from './paths';
|
||||
import { Lockfile } from './versioning';
|
||||
|
||||
/* eslint-disable monorepo/no-relative-import */
|
||||
/* eslint-disable @backstage/no-relative-monorepo-imports */
|
||||
|
||||
/*
|
||||
This is a list of all packages used by the templates. If dependencies are added or removed,
|
||||
|
||||
@@ -1,14 +1 @@
|
||||
module.exports = require('@backstage/cli/config/eslint-factory')(__dirname, {
|
||||
rules: {
|
||||
'no-console': 0,
|
||||
'import/no-extraneous-dependencies': [
|
||||
'error',
|
||||
{
|
||||
devDependencies: true,
|
||||
optionalDependencies: false,
|
||||
peerDependencies: false,
|
||||
bundledDependencies: false,
|
||||
},
|
||||
],
|
||||
},
|
||||
});
|
||||
module.exports = require('@backstage/cli/config/eslint-factory')(__dirname);
|
||||
|
||||
@@ -35,6 +35,7 @@
|
||||
"dependencies": {
|
||||
"@backstage/cli-common": "workspace:^",
|
||||
"chalk": "^4.0.0",
|
||||
"commander": "^9.1.0",
|
||||
"jscodeshift": "^0.14.0",
|
||||
"jscodeshift-add-imports": "^1.0.10"
|
||||
},
|
||||
@@ -42,7 +43,6 @@
|
||||
"@backstage/cli": "workspace:^",
|
||||
"@types/jscodeshift": "^0.11.0",
|
||||
"@types/node": "^16.11.26",
|
||||
"commander": "^9.1.0",
|
||||
"ts-node": "^10.0.0"
|
||||
},
|
||||
"nodemonConfig": {
|
||||
|
||||
@@ -18,7 +18,7 @@ import React, { ReactNode } from 'react';
|
||||
import userEvent from '@testing-library/user-event';
|
||||
import { renderInTestApp } from '@backstage/test-utils';
|
||||
import { RealLogViewer } from './RealLogViewer';
|
||||
// eslint-disable-next-line import/no-extraneous-dependencies
|
||||
// eslint-disable-next-line @backstage/no-undeclared-imports
|
||||
import copyToClipboard from 'copy-to-clipboard';
|
||||
|
||||
// Used by useCopyToClipboard
|
||||
|
||||
@@ -20,7 +20,7 @@ import { TestApiProvider, MockErrorApi } from '@backstage/test-utils';
|
||||
import { errorApiRef } from '@backstage/core-plugin-api';
|
||||
import { AnsiLine } from './AnsiProcessor';
|
||||
import { useLogViewerSelection } from './useLogViewerSelection';
|
||||
// eslint-disable-next-line import/no-extraneous-dependencies
|
||||
// eslint-disable-next-line @backstage/no-undeclared-imports
|
||||
import copyToClipboard from 'copy-to-clipboard';
|
||||
|
||||
// Used by useCopyToClipboard
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
// This is a bit of a hack that we use to avoid having to redeclare these types
|
||||
// within this package or have an explicit dependency on core-app-api.
|
||||
// These types end up being inlined and duplicated into this package at build time.
|
||||
// eslint-disable-next-line no-restricted-imports
|
||||
// eslint-disable-next-line @backstage/no-relative-monorepo-imports
|
||||
export type {
|
||||
BootErrorPageProps,
|
||||
SignInPageProps,
|
||||
|
||||
@@ -25,7 +25,7 @@ if (!isLocal || process.env.BACKSTAGE_E2E_CLI_TEST) {
|
||||
require('..');
|
||||
} else {
|
||||
// Only used for development, so should be a devDependency
|
||||
// eslint-disable-next-line import/no-extraneous-dependencies
|
||||
// eslint-disable-next-line @backstage/no-undeclared-imports
|
||||
require('ts-node').register({
|
||||
transpileOnly: true,
|
||||
project: path.resolve(__dirname, '../../../tsconfig.json'),
|
||||
|
||||
@@ -22,6 +22,7 @@
|
||||
|
||||
import { program } from 'commander';
|
||||
import { exitWithError } from './lib/errors';
|
||||
// eslint-disable-next-line @backstage/no-relative-monorepo-imports
|
||||
import { version } from '../../../package.json';
|
||||
import createApp from './createApp';
|
||||
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
/* eslint-disable monorepo/no-relative-import */
|
||||
/* eslint-disable @backstage/no-relative-monorepo-imports */
|
||||
|
||||
/*
|
||||
This is a list of all packages used by the template. If dependencies are added or removed,
|
||||
|
||||
@@ -7,15 +7,6 @@
|
||||
{
|
||||
"assertFunctionNames": ["expect", "cy.contains"]
|
||||
}
|
||||
],
|
||||
"import/no-extraneous-dependencies": [
|
||||
"error",
|
||||
{
|
||||
"devDependencies": true,
|
||||
"optionalDependencies": true,
|
||||
"peerDependencies": true,
|
||||
"bundledDependencies": true
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,14 +1 @@
|
||||
module.exports = require('@backstage/cli/config/eslint-factory')(__dirname, {
|
||||
rules: {
|
||||
'no-console': 0,
|
||||
'import/no-extraneous-dependencies': [
|
||||
'error',
|
||||
{
|
||||
devDependencies: true,
|
||||
optionalDependencies: false,
|
||||
peerDependencies: false,
|
||||
bundledDependencies: false,
|
||||
},
|
||||
],
|
||||
},
|
||||
});
|
||||
module.exports = require('@backstage/cli/config/eslint-factory')(__dirname);
|
||||
|
||||
@@ -26,22 +26,24 @@
|
||||
"clean": "backstage-cli package clean"
|
||||
},
|
||||
"bin": "bin/e2e-test",
|
||||
"devDependencies": {
|
||||
"@backstage/cli": "workspace:^",
|
||||
"dependencies": {
|
||||
"@backstage/cli-common": "workspace:^",
|
||||
"@backstage/errors": "workspace:^",
|
||||
"@types/fs-extra": "^9.0.1",
|
||||
"@types/node": "^16.11.26",
|
||||
"@types/puppeteer": "^5.4.4",
|
||||
"chalk": "^4.0.0",
|
||||
"commander": "^9.1.0",
|
||||
"cross-fetch": "^3.1.5",
|
||||
"fs-extra": "10.1.0",
|
||||
"handlebars": "^4.7.3",
|
||||
"nodemon": "^2.0.2",
|
||||
"pgtools": "^0.3.0",
|
||||
"puppeteer": "^17.0.0",
|
||||
"tree-kill": "^1.2.2",
|
||||
"tree-kill": "^1.2.2"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@backstage/cli": "workspace:^",
|
||||
"@types/fs-extra": "^9.0.1",
|
||||
"@types/node": "^16.11.26",
|
||||
"@types/puppeteer": "^5.4.4",
|
||||
"nodemon": "^2.0.2",
|
||||
"ts-node": "^10.0.0"
|
||||
},
|
||||
"nodemonConfig": {
|
||||
|
||||
@@ -159,7 +159,7 @@ async function buildDistWorkspace(workspaceName: string, rootDir: string) {
|
||||
appendDeps(pkg);
|
||||
}
|
||||
|
||||
// eslint-disable-next-line import/no-extraneous-dependencies
|
||||
// eslint-disable-next-line @backstage/no-forbidden-package-imports
|
||||
appendDeps(require('@backstage/create-app/package.json'));
|
||||
|
||||
print(`Preparing workspace`);
|
||||
|
||||
@@ -0,0 +1,34 @@
|
||||
/*
|
||||
* Copyright 2023 The Backstage Authors
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
// Custom lint config here since source is ES5
|
||||
module.exports = {
|
||||
plugins: ['@backstage'],
|
||||
env: {
|
||||
node: true,
|
||||
es2021: true,
|
||||
},
|
||||
parser: '@typescript-eslint/parser',
|
||||
parserOptions: {
|
||||
ecmaVersion: 2018,
|
||||
sourceType: 'module',
|
||||
lib: require('@backstage/cli/config/tsconfig.json').compilerOptions.lib,
|
||||
},
|
||||
rules: {
|
||||
'@backstage/no-undeclared-imports': ['error'],
|
||||
'no-unused-expressions': 'off',
|
||||
},
|
||||
};
|
||||
@@ -0,0 +1,42 @@
|
||||
# @backstage/eslint-plugin
|
||||
|
||||
A collection of ESLint rules useful to Backstage projects.
|
||||
|
||||
## Usage
|
||||
|
||||
This ESLint plugin is part of the default lint configuration provided by the [Backstage CLI](https://www.npmjs.com/package/@backstage/cli), so you generally do not need to install it manually.
|
||||
|
||||
If you do wish to install this plugin manually, start by adding it as a development dependency to your project:
|
||||
|
||||
```sh
|
||||
yarn add --dev @backstage/eslint-plugin
|
||||
```
|
||||
|
||||
Then add it to your ESLint configuration:
|
||||
|
||||
```js
|
||||
extends: [
|
||||
'plugin:@backstage/recommended',
|
||||
],
|
||||
```
|
||||
|
||||
Alternatively, if you want to install in individual rules manually:
|
||||
|
||||
```js
|
||||
plugins: [
|
||||
'@backstage',
|
||||
],
|
||||
rules: {
|
||||
'@backstage/no-forbidden-package-imports': 'error',
|
||||
}
|
||||
```
|
||||
|
||||
## Rules
|
||||
|
||||
The following rules are provided by this plugin:
|
||||
|
||||
| Rule | Description |
|
||||
| --------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------ |
|
||||
| [@backstage/no-forbidden-package-imports](./docs/rules/no-forbidden-package-imports.md) | Disallow internal monorepo imports from package subpaths that are not exported. |
|
||||
| [@backstage/no-relative-monorepo-imports](./docs/rules/no-relative-monorepo-imports.md) | Forbid relative imports that reach outside of the package in a monorepo. |
|
||||
| [@backstage/no-undeclared-imports](./docs/rules/no-undeclared-imports.md) | Forbid imports of external packages that have not been declared in the appropriate dependencies field in `package.json`. |
|
||||
@@ -0,0 +1,52 @@
|
||||
# @backstage/no-forbidden-package-imports
|
||||
|
||||
Disallow internal monorepo imports from package subpaths that are not exported.
|
||||
|
||||
## Usage
|
||||
|
||||
Add the rules as follows, it has no options:
|
||||
|
||||
```js
|
||||
"@backstage/no-forbidden-package-imports": ["error"]
|
||||
```
|
||||
|
||||
## Rule Details
|
||||
|
||||
Given the following two target packages:
|
||||
|
||||
```json
|
||||
{
|
||||
"name": "@backstage/plugin-foo",
|
||||
"files": ["dist", "type-utils"]
|
||||
}
|
||||
```
|
||||
|
||||
```json
|
||||
{
|
||||
"name": "@backstage/plugin-bar",
|
||||
"exports": {
|
||||
".": "./src/index.ts",
|
||||
"./testUtils": "./src/testUtils/index.ts",
|
||||
"./package.json": "./package.json"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Fail
|
||||
|
||||
```ts
|
||||
import { FooCard } from '@backstage/plugin-foo/src/components';
|
||||
import { BarCard } from '@backstage/plugin-bar/src/components';
|
||||
```
|
||||
|
||||
### Pass
|
||||
|
||||
```ts
|
||||
import { FooCard } from '@backstage/plugin-foo';
|
||||
import { FooType } from '@backstage/plugin-foo/type-utils';
|
||||
import fooPkg from '@backstage/plugin-foo/package.json';
|
||||
|
||||
import { BarCard } from '@backstage/plugin-bar';
|
||||
import { renderBarCardExtension } from '@backstage/plugin-bar/testUtils';
|
||||
import barPkg from '@backstage/plugin-bar/package.json';
|
||||
```
|
||||
@@ -0,0 +1,43 @@
|
||||
# @backstage/no-relative-monorepo-imports
|
||||
|
||||
Forbid relative imports that reach outside of the package in a monorepo.
|
||||
|
||||
## Usage
|
||||
|
||||
Add the rules as follows, it has no options:
|
||||
|
||||
```js
|
||||
"@backstage/no-relative-monorepo-imports": ["error"]
|
||||
```
|
||||
|
||||
The following patterns are considered files used during development, and only need dependencies to be declared in devDependencies:
|
||||
|
||||
```python
|
||||
!src/** # Any files outside of src are considered dev files
|
||||
src/**/*.test.*
|
||||
src/**/*.stories.*
|
||||
src/**/__testUtils__/**
|
||||
src/**/__mocks__/**
|
||||
src/setupTests.*
|
||||
```
|
||||
|
||||
## Rule Details
|
||||
|
||||
Assuming an import from for example `plugins/bar/src/index.ts`:
|
||||
|
||||
### Fail
|
||||
|
||||
```ts
|
||||
import { FooCard } from '../../foo';
|
||||
|
||||
import { FooCard } from '../../foo/src/components/FooCard';
|
||||
```
|
||||
|
||||
### Pass
|
||||
|
||||
```ts
|
||||
import { FooCard } from '@internal/plugin-foo';
|
||||
|
||||
// This is allowed by this rule, but not by no-forbidden-package-imports
|
||||
import { FooCard } from '@internal/plugin-foo/src/components/FooCard';
|
||||
```
|
||||
@@ -0,0 +1,84 @@
|
||||
# @backstage/no-undeclared-imports
|
||||
|
||||
Forbid imports of external packages that have not been declared in the appropriate dependencies field in `package.json`.
|
||||
|
||||
## Usage
|
||||
|
||||
Add the rules as follows, it has no options:
|
||||
|
||||
```js
|
||||
"@backstage/no-undeclared-imports": ["error"]
|
||||
```
|
||||
|
||||
The following patterns are considered files used during development, and only need dependencies to be declared in devDependencies:
|
||||
|
||||
```python
|
||||
!src/** # Any files outside of src are considered dev files
|
||||
src/**/*.test.*
|
||||
src/**/*.stories.*
|
||||
src/**/__testUtils__/**
|
||||
src/**/__mocks__/**
|
||||
src/setupTests.*
|
||||
```
|
||||
|
||||
## Rule Details
|
||||
|
||||
Given the following `package.json`:
|
||||
|
||||
```json
|
||||
{
|
||||
"name": "@backstage/plugin-foo",
|
||||
"backstage": {
|
||||
"role": "frontend-plugin"
|
||||
},
|
||||
"dependencies": {
|
||||
"react": "^17.0.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@backstage/core-plugin-api": "^1.0.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@backstage/config": "*"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Fail
|
||||
|
||||
Inside `src/my-plugin.ts`:
|
||||
|
||||
```ts
|
||||
// Should be declared as a dependency
|
||||
const _ = require('lodash');
|
||||
import _ from 'lodash';
|
||||
|
||||
// React should be a peer dependency in frontend plugins
|
||||
import react from 'react';
|
||||
|
||||
// Should be declared as a dependency, not a dev dependency
|
||||
import { useApi } from '@backstage/core-plugin-api';
|
||||
```
|
||||
|
||||
Inside `src/my-plugin.test.ts` (a test file):
|
||||
|
||||
```ts
|
||||
// Should be declared as a dev dependency
|
||||
const _ = require('lodash');
|
||||
import _ from 'lodash';
|
||||
```
|
||||
|
||||
### Pass
|
||||
|
||||
Inside `src/my-plugin.ts`:
|
||||
|
||||
```ts
|
||||
// Declared in peerDependencies, so it is allowed
|
||||
import { ConfigReader } from '@backstage/config';
|
||||
```
|
||||
|
||||
Inside `src/my-plugin.test.ts` (a test file):
|
||||
|
||||
```ts
|
||||
// Declared as a dev dependency inside a test file
|
||||
import { useApi } from '@backstage/core-plugin-api';
|
||||
```
|
||||
@@ -0,0 +1,33 @@
|
||||
/*
|
||||
* Copyright 2023 The Backstage Authors
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
module.exports = {
|
||||
configs: {
|
||||
recommended: {
|
||||
plugins: ['@backstage'],
|
||||
rules: {
|
||||
'@backstage/no-forbidden-package-imports': 'error',
|
||||
'@backstage/no-relative-monorepo-imports': 'error',
|
||||
'@backstage/no-undeclared-imports': 'error',
|
||||
},
|
||||
},
|
||||
},
|
||||
rules: {
|
||||
'no-forbidden-package-imports': require('./rules/no-forbidden-package-imports'),
|
||||
'no-relative-monorepo-imports': require('./rules/no-relative-monorepo-imports'),
|
||||
'no-undeclared-imports': require('./rules/no-undeclared-imports'),
|
||||
},
|
||||
};
|
||||
@@ -0,0 +1,71 @@
|
||||
/*
|
||||
* Copyright 2023 The Backstage Authors
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
// @ts-check
|
||||
|
||||
const path = require('path');
|
||||
const manypkg = require('@manypkg/get-packages');
|
||||
|
||||
/**
|
||||
* @typedef ExtendedPackage
|
||||
* @type {import('@manypkg/get-packages').Package & { packageJson: { exports?: Record<string, string>, files?: Array<string> }}} packageJson
|
||||
*/
|
||||
|
||||
/**
|
||||
* @typedef PackageMap
|
||||
* @type object
|
||||
*
|
||||
* @property {ExtendedPackage} root
|
||||
* @property {ExtendedPackage[]} list
|
||||
* @property {Map<string, ExtendedPackage>} map
|
||||
* @property {(path: string) => ExtendedPackage | undefined} byPath
|
||||
*/
|
||||
|
||||
// Loads all packages in the monorepo once, and caches the result
|
||||
module.exports = (function () {
|
||||
/** @type {PackageMap | undefined} */
|
||||
let result = undefined;
|
||||
/** @type {number} */
|
||||
let lastLoadAt = 0;
|
||||
|
||||
/** @returns {PackageMap | undefined} */
|
||||
return function getPackages(/** @type {string} */ dir) {
|
||||
if (result) {
|
||||
// Only cache for 5 seconds, to avoid the need to reload ESLint servers
|
||||
if (Date.now() - lastLoadAt > 5000) {
|
||||
result = undefined;
|
||||
} else {
|
||||
return result;
|
||||
}
|
||||
}
|
||||
const packages = manypkg.getPackagesSync(dir);
|
||||
if (!packages) {
|
||||
return undefined;
|
||||
}
|
||||
result = {
|
||||
map: new Map(packages.packages.map(pkg => [pkg.packageJson.name, pkg])),
|
||||
list: packages.packages,
|
||||
root: packages.root,
|
||||
byPath(filePath) {
|
||||
return packages.packages.find(
|
||||
pkg => !path.relative(pkg.dir, filePath).startsWith('..'),
|
||||
);
|
||||
},
|
||||
};
|
||||
lastLoadAt = Date.now();
|
||||
return result;
|
||||
};
|
||||
})();
|
||||
@@ -0,0 +1,173 @@
|
||||
/*
|
||||
* Copyright 2023 The Backstage Authors
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
// @ts-check
|
||||
|
||||
const { builtinModules } = require('module');
|
||||
const getPackages = require('./getPackages');
|
||||
|
||||
/**
|
||||
* @typedef LocalImport
|
||||
* @type {object}
|
||||
* @property {'local'} type
|
||||
* @property {'value' | 'type'} kind
|
||||
* @property {string} path
|
||||
*/
|
||||
|
||||
/**
|
||||
* @typedef InternalImport
|
||||
* @type {object}
|
||||
* @property {'internal'} type
|
||||
* @property {'value' | 'type'} kind
|
||||
* @property {string} path
|
||||
* @property {import('./getPackages').ExtendedPackage} package
|
||||
*/
|
||||
|
||||
/**
|
||||
* @typedef ExternalImport
|
||||
* @type {object}
|
||||
* @property {'external'} type
|
||||
* @property {'value' | 'type'} kind
|
||||
* @property {string} path
|
||||
* @property {string} packageName
|
||||
*/
|
||||
|
||||
/**
|
||||
* @typedef BuiltinImport
|
||||
* @type {object}
|
||||
* @property {'builtin'} type
|
||||
* @property {'value' | 'type'} kind
|
||||
* @property {string} path
|
||||
* @property {string} packageName
|
||||
*/
|
||||
|
||||
/**
|
||||
* @callback ImportVisitor
|
||||
* @param {ConsideredNode} node
|
||||
* @param {LocalImport | InternalImport | ExternalImport | BuiltinImport} import
|
||||
*/
|
||||
|
||||
/**
|
||||
* @typedef ConsideredNode
|
||||
* @type {import('estree').ImportDeclaration | import('estree').ExportAllDeclaration | import('estree').ExportNamedDeclaration | import('estree').ImportExpression | import('estree').SimpleCallExpression}
|
||||
*/
|
||||
|
||||
/**
|
||||
* @param {ConsideredNode} node
|
||||
* @returns {undefined | {path: string, kind: 'type' | 'value'}}
|
||||
*/
|
||||
function getImportInfo(node) {
|
||||
/** @type {import('estree').Expression | import('estree').SpreadElement | undefined | null} */
|
||||
let pathNode;
|
||||
|
||||
if (node.type === 'CallExpression') {
|
||||
if (
|
||||
node.callee.type === 'Identifier' &&
|
||||
node.callee.name == 'require' &&
|
||||
node.arguments.length === 1
|
||||
) {
|
||||
pathNode = node.arguments[0];
|
||||
}
|
||||
} else {
|
||||
pathNode = node.source;
|
||||
}
|
||||
|
||||
if (pathNode?.type !== 'Literal') {
|
||||
return undefined;
|
||||
}
|
||||
if (typeof pathNode.value !== 'string') {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
/** @type {any} */
|
||||
const anyNode = node;
|
||||
return { path: pathNode.value, kind: anyNode.importKind ?? 'value' };
|
||||
}
|
||||
|
||||
/**
|
||||
* @param visitor - Visitor callback
|
||||
* @param {import('eslint').Rule.RuleContext} context
|
||||
* @param {ImportVisitor} visitor
|
||||
*/
|
||||
module.exports = function visitImports(context, visitor) {
|
||||
const packages = getPackages(context.getCwd());
|
||||
if (!packages) {
|
||||
return;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {ConsideredNode} node
|
||||
*/
|
||||
function visit(node) {
|
||||
const info = getImportInfo(node);
|
||||
if (!info) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (info.path[0] === '.') {
|
||||
return visitor(node, { type: 'local', ...info });
|
||||
}
|
||||
|
||||
const pathParts = info.path.split('/');
|
||||
|
||||
// Check for match with plain name, then namespaced name
|
||||
let packageName;
|
||||
let subPath;
|
||||
if (info.path[0] === '@') {
|
||||
packageName = pathParts.slice(0, 2).join('/');
|
||||
subPath = pathParts.slice(2).join('/');
|
||||
} else {
|
||||
packageName = pathParts[0];
|
||||
subPath = pathParts.slice(1).join('/');
|
||||
}
|
||||
const pkg = packages?.map.get(packageName);
|
||||
if (!pkg) {
|
||||
if (
|
||||
packageName.startsWith('node:') ||
|
||||
builtinModules.includes(packageName)
|
||||
) {
|
||||
return visitor(node, {
|
||||
type: 'builtin',
|
||||
kind: info.kind,
|
||||
path: subPath,
|
||||
packageName,
|
||||
});
|
||||
}
|
||||
|
||||
return visitor(node, {
|
||||
type: 'external',
|
||||
kind: info.kind,
|
||||
path: subPath,
|
||||
packageName,
|
||||
});
|
||||
}
|
||||
|
||||
return visitor(node, {
|
||||
type: 'internal',
|
||||
kind: info.kind,
|
||||
path: subPath,
|
||||
package: pkg,
|
||||
});
|
||||
}
|
||||
|
||||
return {
|
||||
ImportDeclaration: visit,
|
||||
ExportAllDeclaration: visit,
|
||||
ExportNamedDeclaration: visit,
|
||||
ImportExpression: visit,
|
||||
CallExpression: visit,
|
||||
};
|
||||
};
|
||||
@@ -0,0 +1,28 @@
|
||||
{
|
||||
"name": "@backstage/eslint-plugin",
|
||||
"description": "Backstage ESLint plugin",
|
||||
"version": "0.0.0",
|
||||
"publishConfig": {
|
||||
"access": "public"
|
||||
},
|
||||
"homepage": "https://backstage.io",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/backstage/backstage",
|
||||
"directory": "packages/eslint-plugin"
|
||||
},
|
||||
"license": "Apache-2.0",
|
||||
"main": "./index.js",
|
||||
"scripts": {
|
||||
"lint": "backstage-cli package lint",
|
||||
"test": "backstage-cli package test"
|
||||
},
|
||||
"dependencies": {
|
||||
"@manypkg/get-packages": "^1.1.3",
|
||||
"minimatch": "^5.1.2"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@backstage/cli": "workspace:^",
|
||||
"eslint": "^8.33.0"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,74 @@
|
||||
/*
|
||||
* Copyright 2023 The Backstage Authors
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
// @ts-check
|
||||
|
||||
const visitImports = require('../lib/visitImports');
|
||||
|
||||
/** @type {import('eslint').Rule.RuleModule} */
|
||||
module.exports = {
|
||||
meta: {
|
||||
type: 'problem',
|
||||
messages: {
|
||||
forbidden: '{{packageName}} does not export {{subPath}}',
|
||||
},
|
||||
docs: {
|
||||
description:
|
||||
'Disallow internal monorepo imports from package subpaths that are not exported.',
|
||||
url: 'https://github.com/backstage/backstage/blob/master/packages/eslint-plugin/docs/rules/no-forbidden-package-imports.md',
|
||||
},
|
||||
},
|
||||
create(context) {
|
||||
return visitImports(context, (node, imp) => {
|
||||
if (imp.type !== 'internal') {
|
||||
return;
|
||||
}
|
||||
// Empty subpaths are always allowed
|
||||
if (!imp.path) {
|
||||
return;
|
||||
}
|
||||
|
||||
// If the import is listed in the package.json exports field, we allow it
|
||||
const exp = imp.package.packageJson.exports;
|
||||
if (exp && (exp[imp.path] || exp['./' + imp.path])) {
|
||||
return;
|
||||
}
|
||||
if (!exp) {
|
||||
// If there's no exports field, we allow anything listed in files, except dist
|
||||
const files = imp.package.packageJson.files;
|
||||
if (
|
||||
!files ||
|
||||
files.some(f => !f.startsWith('dist') && imp.path.startsWith(f))
|
||||
) {
|
||||
return;
|
||||
}
|
||||
// And also package.json
|
||||
if (imp.path === 'package.json') {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
context.report({
|
||||
node: node,
|
||||
messageId: 'forbidden',
|
||||
data: {
|
||||
packageName: imp.package.packageJson.name || imp.package.dir,
|
||||
subPath: imp.path,
|
||||
},
|
||||
});
|
||||
});
|
||||
},
|
||||
};
|
||||
@@ -0,0 +1,85 @@
|
||||
/*
|
||||
* Copyright 2023 The Backstage Authors
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
// @ts-check
|
||||
|
||||
const path = require('path');
|
||||
const visitImports = require('../lib/visitImports');
|
||||
const getPackageMap = require('../lib/getPackages');
|
||||
|
||||
/** @type {import('eslint').Rule.RuleModule} */
|
||||
module.exports = {
|
||||
meta: {
|
||||
type: 'problem',
|
||||
messages: {
|
||||
outside: 'Import of {{path}} is outside of any known monorepo package',
|
||||
forbidden:
|
||||
"Relative imports of monorepo packages are forbidden, use '{{newImport}}' instead",
|
||||
},
|
||||
docs: {
|
||||
description:
|
||||
'Forbid relative imports that reach outside of the package in a monorepo.',
|
||||
url: 'https://github.com/backstage/backstage/blob/master/packages/eslint-plugin/docs/rules/no-relative-monorepo-imports.md',
|
||||
},
|
||||
},
|
||||
create(context) {
|
||||
const packages = getPackageMap(context.getCwd());
|
||||
if (!packages) {
|
||||
return {};
|
||||
}
|
||||
const filePath = context.getPhysicalFilename
|
||||
? context.getPhysicalFilename()
|
||||
: context.getFilename();
|
||||
|
||||
const localPkg = packages.byPath(filePath);
|
||||
if (!localPkg) {
|
||||
return {};
|
||||
}
|
||||
|
||||
return visitImports(context, (node, imp) => {
|
||||
if (imp.type !== 'local') {
|
||||
return;
|
||||
}
|
||||
|
||||
const target = path.resolve(path.dirname(filePath), imp.path);
|
||||
if (!path.relative(localPkg.dir, target).startsWith('..')) {
|
||||
return;
|
||||
}
|
||||
|
||||
const targetPkg = packages.byPath(target);
|
||||
if (!targetPkg) {
|
||||
context.report({
|
||||
node: node,
|
||||
messageId: 'outside',
|
||||
data: {
|
||||
path: target,
|
||||
},
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
const targetPath = path.relative(targetPkg.dir, target);
|
||||
const targetName = targetPkg.packageJson.name ?? '<unknown>';
|
||||
context.report({
|
||||
node: node,
|
||||
messageId: 'forbidden',
|
||||
data: {
|
||||
newImport: targetPath ? `${targetName}/${targetPath}` : targetName,
|
||||
},
|
||||
});
|
||||
});
|
||||
},
|
||||
};
|
||||
@@ -0,0 +1,205 @@
|
||||
/*
|
||||
* Copyright 2023 The Backstage Authors
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
// @ts-check
|
||||
|
||||
const path = require('path');
|
||||
const getPackageMap = require('../lib/getPackages');
|
||||
const visitImports = require('../lib/visitImports');
|
||||
const minimatch = require('minimatch');
|
||||
|
||||
const depFields = {
|
||||
dep: 'dependencies',
|
||||
dev: 'devDependencies',
|
||||
peer: 'peerDependencies',
|
||||
};
|
||||
|
||||
const devModulePatterns = [
|
||||
new minimatch.Minimatch('!src/**'),
|
||||
new minimatch.Minimatch('src/**/*.test.*'),
|
||||
new minimatch.Minimatch('src/**/*.stories.*'),
|
||||
new minimatch.Minimatch('src/**/__testUtils__/**'),
|
||||
new minimatch.Minimatch('src/**/__mocks__/**'),
|
||||
new minimatch.Minimatch('src/setupTests.*'),
|
||||
];
|
||||
|
||||
function getExpectedDepType(
|
||||
/** @type {any} */ localPkg,
|
||||
/** @type {string} */ impPath,
|
||||
/** @type {string} */ modulePath,
|
||||
) {
|
||||
const role = localPkg?.backstage?.role;
|
||||
// Some package roles have known dependency types
|
||||
switch (role) {
|
||||
case 'common-library':
|
||||
case 'web-library':
|
||||
case 'frontend-plugin':
|
||||
case 'frontend-plugin-module':
|
||||
case 'node-library':
|
||||
case 'backend-plugin':
|
||||
case 'backend-plugin-module':
|
||||
switch (impPath) {
|
||||
case 'react':
|
||||
case 'react-dom':
|
||||
case 'react-router':
|
||||
case 'react-router-dom':
|
||||
return 'peer';
|
||||
}
|
||||
break;
|
||||
case 'cli':
|
||||
case 'frontend':
|
||||
case 'backend':
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
for (const pattern of devModulePatterns) {
|
||||
if (pattern.match(modulePath)) {
|
||||
return 'dev';
|
||||
}
|
||||
}
|
||||
return 'dep';
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param {import('@manypkg/get-packages').Package['packageJson']} pkg
|
||||
* @param {string} name
|
||||
* @param {ReturnType<typeof getExpectedDepType>} expectedType
|
||||
* @returns {{oldDepsField?: string, depsField: string} | undefined}
|
||||
*/
|
||||
function findConflict(pkg, name, expectedType) {
|
||||
const isDep = pkg.dependencies?.[name];
|
||||
const isDevDep = pkg.devDependencies?.[name];
|
||||
const isPeerDep = pkg.peerDependencies?.[name];
|
||||
const depsField = depFields[expectedType];
|
||||
|
||||
if (expectedType === 'dep' && !isDep && !isPeerDep) {
|
||||
const oldDepsField = isDevDep ? depFields.dev : undefined;
|
||||
return { oldDepsField, depsField };
|
||||
} else if (expectedType === 'dev' && !isDevDep && !isDep && !isPeerDep) {
|
||||
return { oldDepsField: undefined, depsField };
|
||||
} else if (expectedType === 'peer' && !isPeerDep) {
|
||||
const oldDepsField = isDep
|
||||
? depFields.dep
|
||||
: isDevDep
|
||||
? depFields.dev
|
||||
: undefined;
|
||||
|
||||
return { oldDepsField, depsField };
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string} depsField
|
||||
*/
|
||||
function getAddFlagForDepsField(depsField) {
|
||||
switch (depsField) {
|
||||
case depFields.dep:
|
||||
return '';
|
||||
case depFields.dev:
|
||||
return ' --dev';
|
||||
case depFields.peer:
|
||||
return ' --peer';
|
||||
default:
|
||||
return '';
|
||||
}
|
||||
}
|
||||
|
||||
/** @type {import('eslint').Rule.RuleModule} */
|
||||
module.exports = {
|
||||
meta: {
|
||||
type: 'problem',
|
||||
messages: {
|
||||
undeclared:
|
||||
"{{ packageName }} must be declared in {{ depsField }} of {{ packageJsonPath }}, run 'yarn --cwd {{ packagePath }} add{{ addFlag }} {{ packageName }}' from the project root.",
|
||||
switch:
|
||||
'{{ packageName }} is declared in {{ oldDepsField }}, but should be moved to {{ depsField }} in {{ packageJsonPath }}.',
|
||||
},
|
||||
docs: {
|
||||
description:
|
||||
'Forbid imports of external packages that have not been declared in the appropriate dependencies field in `package.json`.',
|
||||
url: 'https://github.com/backstage/backstage/blob/master/packages/eslint-plugin/docs/rules/no-undeclared-imports.md',
|
||||
},
|
||||
},
|
||||
create(context) {
|
||||
const packages = getPackageMap(context.getCwd());
|
||||
if (!packages) {
|
||||
return {};
|
||||
}
|
||||
const filePath = context.getPhysicalFilename
|
||||
? context.getPhysicalFilename()
|
||||
: context.getFilename();
|
||||
|
||||
const localPkg = packages.byPath(filePath);
|
||||
if (!localPkg) {
|
||||
return {};
|
||||
}
|
||||
|
||||
return visitImports(context, (node, imp) => {
|
||||
if (imp.type !== 'external') {
|
||||
return;
|
||||
}
|
||||
// We leave checking of type imports to the repo-tools check
|
||||
if (imp.kind === 'type') {
|
||||
return;
|
||||
}
|
||||
|
||||
const modulePath = path.relative(localPkg.dir, filePath);
|
||||
const expectedType = getExpectedDepType(
|
||||
localPkg.packageJson,
|
||||
imp.packageName,
|
||||
modulePath,
|
||||
);
|
||||
|
||||
const conflict = findConflict(
|
||||
localPkg.packageJson,
|
||||
imp.packageName,
|
||||
expectedType,
|
||||
);
|
||||
|
||||
if (conflict) {
|
||||
try {
|
||||
const fullImport = imp.path
|
||||
? `${imp.packageName}/${imp.path}`
|
||||
: imp.packageName;
|
||||
require.resolve(fullImport, {
|
||||
paths: [localPkg.dir],
|
||||
});
|
||||
} catch {
|
||||
// If the dependency doesn't resolve then it's likely a type import, ignore
|
||||
return;
|
||||
}
|
||||
|
||||
const packagePath = path.relative(packages.root.dir, localPkg.dir);
|
||||
const packageJsonPath = path.join(packagePath, 'package.json');
|
||||
|
||||
context.report({
|
||||
node,
|
||||
messageId: conflict.oldDepsField ? 'switch' : 'undeclared',
|
||||
data: {
|
||||
...conflict,
|
||||
packagePath,
|
||||
addFlag: getAddFlagForDepsField(conflict.depsField),
|
||||
packageName: imp.packageName,
|
||||
packageJsonPath: packageJsonPath,
|
||||
},
|
||||
});
|
||||
}
|
||||
});
|
||||
},
|
||||
};
|
||||
@@ -0,0 +1,6 @@
|
||||
{
|
||||
"name": "root",
|
||||
"workspaces": [
|
||||
"packages/*"
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
{
|
||||
"name": "@internal/bar",
|
||||
"exports": {
|
||||
".": "./src/index.ts",
|
||||
"./BarPage": "./src/components/Bar.tsx",
|
||||
"./package.json": "./package.json"
|
||||
},
|
||||
"backstage": {
|
||||
"role": "frontend-plugin"
|
||||
},
|
||||
"dependencies": {
|
||||
"react-router": "*"
|
||||
},
|
||||
"devDependencies": {
|
||||
"react-router-dom": "*"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
{
|
||||
"name": "@internal/foo",
|
||||
"dependencies": {
|
||||
"@internal/bar": "1.0.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"lodash": "*"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"react": "*"
|
||||
},
|
||||
"files": [
|
||||
"dist",
|
||||
"type-utils"
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,120 @@
|
||||
/*
|
||||
* Copyright 2023 The Backstage Authors
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
import { RuleTester } from 'eslint';
|
||||
import path from 'path';
|
||||
import rule from '../rules/no-forbidden-package-imports';
|
||||
|
||||
const RULE = 'no-forbidden-package-imports';
|
||||
const FIXTURE = path.resolve(__dirname, '__fixtures__/monorepo');
|
||||
|
||||
const ERR = (name: string, path: string) => ({
|
||||
message: `${name} does not export ${path}`,
|
||||
});
|
||||
|
||||
process.chdir(FIXTURE);
|
||||
|
||||
const ruleTester = new RuleTester({
|
||||
parserOptions: {
|
||||
sourceType: 'module',
|
||||
ecmaVersion: 2021,
|
||||
},
|
||||
});
|
||||
|
||||
ruleTester.run(RULE, rule, {
|
||||
valid: [
|
||||
{
|
||||
code: `import '@internal/foo'`,
|
||||
filename: path.join(FIXTURE, 'index.ts'),
|
||||
},
|
||||
{
|
||||
code: `import '@internal/foo/type-utils'`,
|
||||
filename: path.join(FIXTURE, 'index.ts'),
|
||||
},
|
||||
{
|
||||
code: `import '@internal/foo/type-utils/anything'`,
|
||||
filename: path.join(FIXTURE, 'index.ts'),
|
||||
},
|
||||
{
|
||||
code: `import '@internal/foo/package.json'`,
|
||||
filename: path.join(FIXTURE, 'index.ts'),
|
||||
},
|
||||
{
|
||||
code: `import '@internal/bar'`,
|
||||
filename: path.join(FIXTURE, 'index.ts'),
|
||||
},
|
||||
{
|
||||
code: `import '@internal/bar/package.json'`,
|
||||
filename: path.join(FIXTURE, 'index.ts'),
|
||||
},
|
||||
{
|
||||
code: `import '@internal/bar/BarPage'`,
|
||||
filename: path.join(FIXTURE, 'index.ts'),
|
||||
},
|
||||
],
|
||||
invalid: [
|
||||
{
|
||||
code: `import '@internal/foo/FooPage'`,
|
||||
filename: path.join(FIXTURE, 'index.ts'),
|
||||
errors: [ERR('@internal/foo', 'FooPage')],
|
||||
},
|
||||
{
|
||||
code: `import '@internal/foo/dist'`,
|
||||
filename: path.join(FIXTURE, 'index.ts'),
|
||||
errors: [ERR('@internal/foo', 'dist')],
|
||||
},
|
||||
{
|
||||
code: `import '@internal/foo/dist/FooPage'`,
|
||||
filename: path.join(FIXTURE, 'index.ts'),
|
||||
errors: [ERR('@internal/foo', 'dist/FooPage')],
|
||||
},
|
||||
{
|
||||
code: `import '@internal/foo/src/FooPage'`,
|
||||
filename: path.join(FIXTURE, 'index.ts'),
|
||||
errors: [ERR('@internal/foo', 'src/FooPage')],
|
||||
},
|
||||
{
|
||||
code: `import '@internal/foo/src'`,
|
||||
filename: path.join(FIXTURE, 'index.ts'),
|
||||
errors: [ERR('@internal/foo', 'src')],
|
||||
},
|
||||
{
|
||||
code: `import '@internal/bar/OtherBarPage'`,
|
||||
filename: path.join(FIXTURE, 'index.ts'),
|
||||
errors: [ERR('@internal/bar', 'OtherBarPage')],
|
||||
},
|
||||
{
|
||||
code: `import '@internal/bar/dist'`,
|
||||
filename: path.join(FIXTURE, 'index.ts'),
|
||||
errors: [ERR('@internal/bar', 'dist')],
|
||||
},
|
||||
{
|
||||
code: `import '@internal/bar/dist/BarPage'`,
|
||||
filename: path.join(FIXTURE, 'index.ts'),
|
||||
errors: [ERR('@internal/bar', 'dist/BarPage')],
|
||||
},
|
||||
{
|
||||
code: `import '@internal/bar/src/BarPage'`,
|
||||
filename: path.join(FIXTURE, 'index.ts'),
|
||||
errors: [ERR('@internal/bar', 'src/BarPage')],
|
||||
},
|
||||
{
|
||||
code: `import '@internal/bar/src'`,
|
||||
filename: path.join(FIXTURE, 'index.ts'),
|
||||
errors: [ERR('@internal/bar', 'src')],
|
||||
},
|
||||
],
|
||||
});
|
||||
@@ -0,0 +1,68 @@
|
||||
/*
|
||||
* Copyright 2023 The Backstage Authors
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
import { RuleTester } from 'eslint';
|
||||
import path from 'path';
|
||||
import rule from '../rules/no-relative-monorepo-imports';
|
||||
|
||||
const RULE = 'no-relative-monorepo-imports';
|
||||
const FIXTURE = path.resolve(__dirname, '__fixtures__/monorepo');
|
||||
|
||||
const ERR_OUTSIDE = (path: string) => ({
|
||||
message: `Import of ${path} is outside of any known monorepo package`,
|
||||
});
|
||||
const ERR_FORBIDDEN = (newImp: string) => ({
|
||||
message: `Relative imports of monorepo packages are forbidden, use '${newImp}' instead`,
|
||||
});
|
||||
|
||||
process.chdir(FIXTURE);
|
||||
|
||||
const ruleTester = new RuleTester({
|
||||
parserOptions: {
|
||||
sourceType: 'module',
|
||||
ecmaVersion: 2021,
|
||||
},
|
||||
});
|
||||
|
||||
ruleTester.run(RULE, rule, {
|
||||
valid: [
|
||||
{
|
||||
code: `import { version } from '@internal/foo'`,
|
||||
filename: path.join(FIXTURE, 'packages/bar/src/index.ts'),
|
||||
},
|
||||
{
|
||||
code: `import { version } from '@internal/foo/src'`,
|
||||
filename: path.join(FIXTURE, 'packages/bar/src/index.ts'),
|
||||
},
|
||||
],
|
||||
invalid: [
|
||||
{
|
||||
code: `import { version } from '../../foo'`,
|
||||
filename: path.join(FIXTURE, 'packages/bar/src/index.ts'),
|
||||
errors: [ERR_FORBIDDEN('@internal/foo')],
|
||||
},
|
||||
{
|
||||
code: `import { version } from '../../foo/src'`,
|
||||
filename: path.join(FIXTURE, 'packages/bar/src/index.ts'),
|
||||
errors: [ERR_FORBIDDEN('@internal/foo/src')],
|
||||
},
|
||||
{
|
||||
code: `import { version } from '../../../package.json'`,
|
||||
filename: path.join(FIXTURE, 'packages/bar/src/index.ts'),
|
||||
errors: [ERR_OUTSIDE(path.join(FIXTURE, 'package.json'))],
|
||||
},
|
||||
],
|
||||
});
|
||||
@@ -0,0 +1,194 @@
|
||||
/*
|
||||
* Copyright 2023 The Backstage Authors
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
import { RuleTester } from 'eslint';
|
||||
import path from 'path';
|
||||
import rule from '../rules/no-undeclared-imports';
|
||||
|
||||
const RULE = 'no-undeclared-imports';
|
||||
const FIXTURE = path.resolve(__dirname, '__fixtures__/monorepo');
|
||||
|
||||
const ERR_UNDECLARED = (
|
||||
name: string,
|
||||
field: string,
|
||||
path: string,
|
||||
flag?: string,
|
||||
) => ({
|
||||
message: `${name} must be declared in ${field} of ${path}/package.json, run 'yarn --cwd ${path} add${
|
||||
flag ? ` ${flag}` : ''
|
||||
} ${name}' from the project root.`,
|
||||
});
|
||||
const ERR_SWITCHED = (
|
||||
name: string,
|
||||
old: string,
|
||||
field: string,
|
||||
path: string,
|
||||
) => ({
|
||||
message: `${name} is declared in ${old}, but should be moved to ${field} in ${path}/package.json.`,
|
||||
});
|
||||
|
||||
process.chdir(FIXTURE);
|
||||
|
||||
const ruleTester = new RuleTester({
|
||||
parserOptions: {
|
||||
sourceType: 'module',
|
||||
ecmaVersion: 2021,
|
||||
},
|
||||
});
|
||||
|
||||
ruleTester.run(RULE, rule, {
|
||||
valid: [
|
||||
{
|
||||
code: `import '@internal/foo'`,
|
||||
filename: path.join(FIXTURE, 'packages/foo/src/index.ts'),
|
||||
},
|
||||
{
|
||||
code: `import '@internal/bar'`,
|
||||
filename: path.join(FIXTURE, 'packages/foo/src/index.ts'),
|
||||
},
|
||||
{
|
||||
code: `import 'react'`,
|
||||
filename: path.join(FIXTURE, 'packages/foo/src/index.ts'),
|
||||
},
|
||||
{
|
||||
code: `import '@internal/foo'`,
|
||||
filename: path.join(FIXTURE, 'packages/foo/src/index.test.ts'),
|
||||
},
|
||||
{
|
||||
code: `import '@internal/bar'`,
|
||||
filename: path.join(FIXTURE, 'packages/foo/src/index.test.ts'),
|
||||
},
|
||||
{
|
||||
code: `import 'lodash'`,
|
||||
filename: path.join(FIXTURE, 'packages/foo/src/index.test.ts'),
|
||||
},
|
||||
{
|
||||
code: `import 'react'`,
|
||||
filename: path.join(FIXTURE, 'packages/foo/src/index.test.ts'),
|
||||
},
|
||||
{
|
||||
// We're only able to validate literals
|
||||
code: `require('lod' + 'ash')`,
|
||||
filename: path.join(FIXTURE, 'packages/bar/src/index.ts'),
|
||||
},
|
||||
],
|
||||
invalid: [
|
||||
{
|
||||
code: `import 'lodash'`,
|
||||
filename: path.join(FIXTURE, 'packages/foo/src/index.ts'),
|
||||
errors: [
|
||||
ERR_SWITCHED(
|
||||
'lodash',
|
||||
'devDependencies',
|
||||
'dependencies',
|
||||
'packages/foo',
|
||||
),
|
||||
],
|
||||
},
|
||||
{
|
||||
code: `import 'react-router'`,
|
||||
filename: path.join(FIXTURE, 'packages/bar/src/index.ts'),
|
||||
errors: [
|
||||
ERR_SWITCHED(
|
||||
'react-router',
|
||||
'dependencies',
|
||||
'peerDependencies',
|
||||
'packages/bar',
|
||||
),
|
||||
],
|
||||
},
|
||||
{
|
||||
code: `import 'react-router-dom'`,
|
||||
filename: path.join(FIXTURE, 'packages/bar/src/index.ts'),
|
||||
errors: [
|
||||
ERR_SWITCHED(
|
||||
'react-router-dom',
|
||||
'devDependencies',
|
||||
'peerDependencies',
|
||||
'packages/bar',
|
||||
),
|
||||
],
|
||||
},
|
||||
{
|
||||
code: `import 'lodash'`,
|
||||
filename: path.join(FIXTURE, 'packages/bar/src/index.ts'),
|
||||
errors: [ERR_UNDECLARED('lodash', 'dependencies', 'packages/bar')],
|
||||
},
|
||||
{
|
||||
code: `import { debounce } from 'lodash'`,
|
||||
filename: path.join(FIXTURE, 'packages/bar/src/index.ts'),
|
||||
errors: [ERR_UNDECLARED('lodash', 'dependencies', 'packages/bar')],
|
||||
},
|
||||
{
|
||||
code: `import * as _ from 'lodash'`,
|
||||
filename: path.join(FIXTURE, 'packages/bar/src/index.ts'),
|
||||
errors: [ERR_UNDECLARED('lodash', 'dependencies', 'packages/bar')],
|
||||
},
|
||||
{
|
||||
code: `import _ from 'lodash'`,
|
||||
filename: path.join(FIXTURE, 'packages/bar/src/index.ts'),
|
||||
errors: [ERR_UNDECLARED('lodash', 'dependencies', 'packages/bar')],
|
||||
},
|
||||
{
|
||||
code: `import('lodash')`,
|
||||
filename: path.join(FIXTURE, 'packages/bar/src/index.ts'),
|
||||
errors: [ERR_UNDECLARED('lodash', 'dependencies', 'packages/bar')],
|
||||
},
|
||||
{
|
||||
code: `require('lodash')`,
|
||||
filename: path.join(FIXTURE, 'packages/bar/src/index.ts'),
|
||||
errors: [ERR_UNDECLARED('lodash', 'dependencies', 'packages/bar')],
|
||||
},
|
||||
{
|
||||
code: `import 'lodash'`,
|
||||
filename: path.join(FIXTURE, 'packages/bar/src/index.ts'),
|
||||
errors: [ERR_UNDECLARED('lodash', 'dependencies', 'packages/bar')],
|
||||
},
|
||||
{
|
||||
code: `import 'lodash'`,
|
||||
filename: path.join(FIXTURE, 'packages/bar/src/index.test.ts'),
|
||||
errors: [
|
||||
ERR_UNDECLARED('lodash', 'devDependencies', 'packages/bar', '--dev'),
|
||||
],
|
||||
},
|
||||
{
|
||||
code: `import 'react'`,
|
||||
filename: path.join(FIXTURE, 'packages/bar/src/index.ts'),
|
||||
errors: [
|
||||
ERR_UNDECLARED('react', 'peerDependencies', 'packages/bar', '--peer'),
|
||||
],
|
||||
},
|
||||
{
|
||||
code: `import 'react'`,
|
||||
filename: path.join(FIXTURE, 'packages/bar/src/index.test.ts'),
|
||||
errors: [
|
||||
ERR_UNDECLARED('react', 'peerDependencies', 'packages/bar', '--peer'),
|
||||
],
|
||||
},
|
||||
{
|
||||
code: `import 'react-dom'`,
|
||||
filename: path.join(FIXTURE, 'packages/foo/src/index.ts'),
|
||||
errors: [ERR_UNDECLARED('react-dom', 'dependencies', 'packages/foo')],
|
||||
},
|
||||
{
|
||||
code: `import 'react-dom'`,
|
||||
filename: path.join(FIXTURE, 'packages/foo/src/index.test.ts'),
|
||||
errors: [
|
||||
ERR_UNDECLARED('react-dom', 'devDependencies', 'packages/foo', '--dev'),
|
||||
],
|
||||
},
|
||||
],
|
||||
});
|
||||
@@ -1107,7 +1107,7 @@ export async function categorizePackageDirs(packageDirs: any[]) {
|
||||
});
|
||||
const role = pkgJson?.backstage?.role;
|
||||
if (!role) {
|
||||
throw new Error(`No backstage.role in ${dir}/package.json`);
|
||||
return; // Ignore packages without roles
|
||||
}
|
||||
if (role === 'cli') {
|
||||
cliPackageDirs.push(dir);
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
import fs from 'fs';
|
||||
import { resolve as resolvePath } from 'path';
|
||||
// Cba polluting root package.json, we'll have this
|
||||
// eslint-disable-next-line import/no-extraneous-dependencies
|
||||
// eslint-disable-next-line @backstage/no-undeclared-imports
|
||||
import chalk from 'chalk';
|
||||
import { getPackages, Package } from '@manypkg/get-packages';
|
||||
|
||||
|
||||
@@ -7,15 +7,6 @@
|
||||
{
|
||||
"assertFunctionNames": ["expect", "cy.contains"]
|
||||
}
|
||||
],
|
||||
"import/no-extraneous-dependencies": [
|
||||
"error",
|
||||
{
|
||||
"devDependencies": true,
|
||||
"optionalDependencies": true,
|
||||
"peerDependencies": true,
|
||||
"bundledDependencies": true
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,15 +7,6 @@
|
||||
{
|
||||
"assertFunctionNames": ["expect", "cy.contains", "cy.document"]
|
||||
}
|
||||
],
|
||||
"import/no-extraneous-dependencies": [
|
||||
"error",
|
||||
{
|
||||
"devDependencies": true,
|
||||
"optionalDependencies": true,
|
||||
"peerDependencies": true,
|
||||
"bundledDependencies": true
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
// eslint-disable-next-line import/no-extraneous-dependencies
|
||||
// eslint-disable-next-line @backstage/no-undeclared-imports
|
||||
import {
|
||||
databaseFactory,
|
||||
discoveryFactory,
|
||||
|
||||
@@ -15,7 +15,7 @@
|
||||
*/
|
||||
|
||||
import { Entity } from '@backstage/catalog-model';
|
||||
// eslint-disable-next-line import/no-extraneous-dependencies
|
||||
// eslint-disable-next-line @backstage/no-undeclared-imports
|
||||
import { createDevApp, EntityGridItem } from '@backstage/dev-utils';
|
||||
import { Grid } from '@material-ui/core';
|
||||
import React from 'react';
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
/* eslint-disable import/no-extraneous-dependencies */
|
||||
/* eslint-disable @backstage/no-undeclared-imports */
|
||||
|
||||
import '@testing-library/jest-dom';
|
||||
import 'cross-fetch/polyfill';
|
||||
|
||||
@@ -22,7 +22,7 @@
|
||||
|
||||
// IMPORTANT: Remove the lines below to enable type checking and linting
|
||||
// @ts-nocheck
|
||||
/* eslint-disable import/no-extraneous-dependencies */
|
||||
/* eslint-disable @backstage/no-undeclared-imports */
|
||||
|
||||
import {
|
||||
CostInsightsApi,
|
||||
|
||||
@@ -1,14 +1 @@
|
||||
module.exports = {
|
||||
extends: [require.resolve('@backstage/cli/config/eslint')],
|
||||
rules: {
|
||||
'import/no-extraneous-dependencies': [
|
||||
'error',
|
||||
{
|
||||
devDependencies: true,
|
||||
optionalDependencies: true,
|
||||
peerDependencies: true,
|
||||
bundledDependencies: true,
|
||||
},
|
||||
],
|
||||
},
|
||||
};
|
||||
module.exports = require('@backstage/cli/config/eslint-factory')(__dirname);
|
||||
|
||||
@@ -16,7 +16,7 @@
|
||||
*/
|
||||
|
||||
/* eslint-disable no-restricted-syntax */
|
||||
/* eslint-disable import/no-extraneous-dependencies */
|
||||
/* eslint-disable @backstage/no-undeclared-imports */
|
||||
|
||||
const path = require('path');
|
||||
|
||||
|
||||
@@ -13,7 +13,7 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
// eslint-disable-next-line import/no-extraneous-dependencies
|
||||
// eslint-disable-next-line @backstage/no-undeclared-imports
|
||||
import {
|
||||
act,
|
||||
fireEvent,
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
#!/usr/bin/env node
|
||||
/* eslint-disable import/no-extraneous-dependencies */
|
||||
/* eslint-disable @backstage/no-undeclared-imports */
|
||||
/*
|
||||
* Copyright 2022 The Backstage Authors
|
||||
*
|
||||
|
||||
@@ -56,7 +56,7 @@ async function listFiles(dir = '') {
|
||||
// caused by the script. In CI, we want to ensure vale linter is run.
|
||||
async function exitIfMissingVale() {
|
||||
try {
|
||||
// eslint-disable-next-line import/no-extraneous-dependencies
|
||||
// eslint-disable-next-line @backstage/no-undeclared-imports
|
||||
await require('command-exists')('vale');
|
||||
} catch (e) {
|
||||
if (process.env.CI) {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
#!/usr/bin/env node
|
||||
/* eslint-disable import/no-extraneous-dependencies */
|
||||
/* eslint-disable @backstage/no-undeclared-imports */
|
||||
/*
|
||||
* Copyright 2020 The Backstage Authors
|
||||
*
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
#!/usr/bin/env node
|
||||
/* eslint-disable import/no-extraneous-dependencies */
|
||||
/* eslint-disable @backstage/no-undeclared-imports */
|
||||
/*
|
||||
* Copyright 2020 The Backstage Authors
|
||||
*
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
#!/usr/bin/env node
|
||||
/* eslint-disable import/no-extraneous-dependencies */
|
||||
/* eslint-disable @backstage/no-undeclared-imports */
|
||||
/*
|
||||
* Copyright 2020 The Backstage Authors
|
||||
*
|
||||
|
||||
@@ -15,7 +15,7 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
/* eslint-disable import/no-extraneous-dependencies */
|
||||
/* eslint-disable @backstage/no-undeclared-imports */
|
||||
|
||||
const _ = require('lodash');
|
||||
const fs = require('fs-extra');
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
#!/usr/bin/env node
|
||||
/* eslint-disable import/no-extraneous-dependencies */
|
||||
/* eslint-disable @backstage/no-undeclared-imports */
|
||||
/*
|
||||
* Copyright 2022 The Backstage Authors
|
||||
*
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
/* eslint-disable import/no-extraneous-dependencies */
|
||||
/* eslint-disable @backstage/no-undeclared-imports */
|
||||
import { Octokit } from '@octokit/rest';
|
||||
import minimist from 'minimist';
|
||||
// Generated by GitHub workflow .github/workflows/snyk-github-issue-creator
|
||||
|
||||
@@ -15,7 +15,7 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
/* eslint-disable import/no-extraneous-dependencies */
|
||||
/* eslint-disable @backstage/no-undeclared-imports */
|
||||
|
||||
const { resolve: resolvePath } = require('path');
|
||||
const { promises: fs } = require('fs');
|
||||
|
||||
@@ -15,7 +15,7 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
/* eslint-disable import/no-extraneous-dependencies */
|
||||
/* eslint-disable @backstage/no-undeclared-imports */
|
||||
|
||||
const { resolve: resolvePath } = require('path');
|
||||
const fs = require('fs-extra');
|
||||
|
||||
@@ -15,7 +15,7 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
/* eslint-disable import/no-extraneous-dependencies */
|
||||
/* eslint-disable @backstage/no-undeclared-imports */
|
||||
|
||||
const { resolve: resolvePath, join: joinPath, dirname } = require('path');
|
||||
const fs = require('fs').promises;
|
||||
|
||||
@@ -15,7 +15,7 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
/* eslint-disable import/no-extraneous-dependencies */
|
||||
/* eslint-disable @backstage/no-undeclared-imports */
|
||||
|
||||
const { execFile: execFileCb } = require('child_process');
|
||||
const { resolve: resolvePath, dirname: dirnamePath } = require('path');
|
||||
|
||||
@@ -3669,6 +3669,7 @@ __metadata:
|
||||
"@backstage/core-plugin-api": "workspace:^"
|
||||
"@backstage/dev-utils": "workspace:^"
|
||||
"@backstage/errors": "workspace:^"
|
||||
"@backstage/eslint-plugin": "workspace:^"
|
||||
"@backstage/release-manifests": "workspace:^"
|
||||
"@backstage/test-utils": "workspace:^"
|
||||
"@backstage/theme": "workspace:^"
|
||||
@@ -3733,7 +3734,6 @@ __metadata:
|
||||
eslint-plugin-import: ^2.25.4
|
||||
eslint-plugin-jest: ^27.0.0
|
||||
eslint-plugin-jsx-a11y: ^6.5.1
|
||||
eslint-plugin-monorepo: ^0.3.2
|
||||
eslint-plugin-react: ^7.28.0
|
||||
eslint-plugin-react-hooks: ^4.3.0
|
||||
eslint-webpack-plugin: ^3.1.1
|
||||
@@ -4107,6 +4107,17 @@ __metadata:
|
||||
languageName: unknown
|
||||
linkType: soft
|
||||
|
||||
"@backstage/eslint-plugin@workspace:^, @backstage/eslint-plugin@workspace:packages/eslint-plugin":
|
||||
version: 0.0.0-use.local
|
||||
resolution: "@backstage/eslint-plugin@workspace:packages/eslint-plugin"
|
||||
dependencies:
|
||||
"@backstage/cli": "workspace:^"
|
||||
"@manypkg/get-packages": ^1.1.3
|
||||
eslint: ^8.33.0
|
||||
minimatch: ^5.1.2
|
||||
languageName: unknown
|
||||
linkType: soft
|
||||
|
||||
"@backstage/integration-aws-node@workspace:^, @backstage/integration-aws-node@workspace:packages/integration-aws-node":
|
||||
version: 0.0.0-use.local
|
||||
resolution: "@backstage/integration-aws-node@workspace:packages/integration-aws-node"
|
||||
@@ -16739,15 +16750,6 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"array-union@npm:^1.0.1":
|
||||
version: 1.0.2
|
||||
resolution: "array-union@npm:1.0.2"
|
||||
dependencies:
|
||||
array-uniq: ^1.0.1
|
||||
checksum: 82cec6421b6e6766556c484835a6d476a873f1b71cace5ab2b4f1b15b1e3162dc4da0d16f7a2b04d4aec18146c6638fe8f661340b31ba8e469fd811a1b45dc8d
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"array-union@npm:^2.1.0":
|
||||
version: 2.1.0
|
||||
resolution: "array-union@npm:2.1.0"
|
||||
@@ -16755,13 +16757,6 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"array-uniq@npm:^1.0.1":
|
||||
version: 1.0.3
|
||||
resolution: "array-uniq@npm:1.0.3"
|
||||
checksum: 1625f06b093d8bf279b81adfec6e72951c0857d65b5e3f65f053fffe9f9dd61c2fc52cff57e38a4700817e7e3f01a4faa433d505ea9e33cdae4514c334e0bf9e
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"array.prototype.flat@npm:^1.2.3, array.prototype.flat@npm:^1.3.1":
|
||||
version: 1.3.1
|
||||
resolution: "array.prototype.flat@npm:1.3.1"
|
||||
@@ -20603,15 +20598,6 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"dir-glob@npm:^2.0.0":
|
||||
version: 2.2.2
|
||||
resolution: "dir-glob@npm:2.2.2"
|
||||
dependencies:
|
||||
path-type: ^3.0.0
|
||||
checksum: 3aa48714a9f7845ffc30ab03a5c674fe760477cc55e67b0847333371549227d93953e6627ec160f75140c5bea5c5f88d13c01de79bd1997a588efbcf06980842
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"dir-glob@npm:^3.0.1":
|
||||
version: 3.0.1
|
||||
resolution: "dir-glob@npm:3.0.1"
|
||||
@@ -21675,7 +21661,7 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"eslint-module-utils@npm:^2.1.1, eslint-module-utils@npm:^2.7.4":
|
||||
"eslint-module-utils@npm:^2.7.4":
|
||||
version: 2.7.4
|
||||
resolution: "eslint-module-utils@npm:2.7.4"
|
||||
dependencies:
|
||||
@@ -21780,21 +21766,6 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"eslint-plugin-monorepo@npm:^0.3.2":
|
||||
version: 0.3.2
|
||||
resolution: "eslint-plugin-monorepo@npm:0.3.2"
|
||||
dependencies:
|
||||
eslint-module-utils: ^2.1.1
|
||||
get-monorepo-packages: ^1.1.0
|
||||
globby: ^7.1.1
|
||||
load-json-file: ^4.0.0
|
||||
minimatch: ^3.0.4
|
||||
parse-package-name: ^0.1.0
|
||||
path-is-inside: ^1.0.2
|
||||
checksum: b6f17efbc9e66aefbf7aacf9aa130bc8e729a6311c412d1b0026ce7d93361c10b0e6e4b10cf434f24ca9a8b2e891bc8e5b82e66dc9ccc5e782f9c18a989eca28
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"eslint-plugin-notice@npm:^0.9.10":
|
||||
version: 0.9.10
|
||||
resolution: "eslint-plugin-notice@npm:0.9.10"
|
||||
@@ -21914,7 +21885,7 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"eslint@npm:^8.6.0":
|
||||
"eslint@npm:^8.33.0, eslint@npm:^8.6.0":
|
||||
version: 8.33.0
|
||||
resolution: "eslint@npm:8.33.0"
|
||||
dependencies:
|
||||
@@ -23507,16 +23478,6 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"get-monorepo-packages@npm:^1.1.0":
|
||||
version: 1.2.0
|
||||
resolution: "get-monorepo-packages@npm:1.2.0"
|
||||
dependencies:
|
||||
globby: ^7.1.1
|
||||
load-json-file: ^4.0.0
|
||||
checksum: f9321c11b8e11f02138758db6589d8ab8b7e1b05e78cac92493b635faea10aa100c20fe40f2cf110c82ec100c118c6c131dff4c65d32a721c617dc2928f7b277
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"get-package-type@npm:^0.1.0":
|
||||
version: 0.1.0
|
||||
resolution: "get-package-type@npm:0.1.0"
|
||||
@@ -23674,7 +23635,7 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"glob@npm:^7.0.0, glob@npm:^7.1.1, glob@npm:^7.1.2, glob@npm:^7.1.3, glob@npm:^7.1.4, glob@npm:^7.1.6, glob@npm:^7.1.7, glob@npm:^7.2.0":
|
||||
"glob@npm:^7.0.0, glob@npm:^7.1.1, glob@npm:^7.1.3, glob@npm:^7.1.4, glob@npm:^7.1.6, glob@npm:^7.1.7, glob@npm:^7.2.0":
|
||||
version: 7.2.3
|
||||
resolution: "glob@npm:7.2.3"
|
||||
dependencies:
|
||||
@@ -23783,20 +23744,6 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"globby@npm:^7.1.1":
|
||||
version: 7.1.1
|
||||
resolution: "globby@npm:7.1.1"
|
||||
dependencies:
|
||||
array-union: ^1.0.1
|
||||
dir-glob: ^2.0.0
|
||||
glob: ^7.1.2
|
||||
ignore: ^3.3.5
|
||||
pify: ^3.0.0
|
||||
slash: ^1.0.0
|
||||
checksum: f0eba08a08ae7c98149a4411661c0bf08c4717d81e6f355cf624fb01880b249737eb8e951bf86124cb3af8ea1c793c0a9d363ed5cdec99bb2c6b68f8a323025f
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"good-listener@npm:^1.2.2":
|
||||
version: 1.2.2
|
||||
resolution: "good-listener@npm:1.2.2"
|
||||
@@ -24786,13 +24733,6 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"ignore@npm:^3.3.5":
|
||||
version: 3.3.10
|
||||
resolution: "ignore@npm:3.3.10"
|
||||
checksum: 23e8cc776e367b56615ab21b78decf973a35dfca5522b39d9b47643d8168473b0d1f18dd1321a1bab466a12ea11a2411903f3b21644f4d5461ee0711ec8678bd
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"ignore@npm:^5.1.4, ignore@npm:^5.2.0":
|
||||
version: 5.2.0
|
||||
resolution: "ignore@npm:5.2.0"
|
||||
@@ -26904,13 +26844,6 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"json-parse-better-errors@npm:^1.0.1":
|
||||
version: 1.0.2
|
||||
resolution: "json-parse-better-errors@npm:1.0.2"
|
||||
checksum: ff2b5ba2a70e88fd97a3cb28c1840144c5ce8fae9cbeeddba15afa333a5c407cf0e42300cd0a2885dbb055227fe68d405070faad941beeffbfde9cf3b2c78c5d
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"json-parse-even-better-errors@npm:^2.3.0, json-parse-even-better-errors@npm:^2.3.1":
|
||||
version: 2.3.1
|
||||
resolution: "json-parse-even-better-errors@npm:2.3.1"
|
||||
@@ -27801,18 +27734,6 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"load-json-file@npm:^4.0.0":
|
||||
version: 4.0.0
|
||||
resolution: "load-json-file@npm:4.0.0"
|
||||
dependencies:
|
||||
graceful-fs: ^4.1.2
|
||||
parse-json: ^4.0.0
|
||||
pify: ^3.0.0
|
||||
strip-bom: ^3.0.0
|
||||
checksum: 8f5d6d93ba64a9620445ee9bde4d98b1eac32cf6c8c2d20d44abfa41a6945e7969456ab5f1ca2fb06ee32e206c9769a20eec7002fe290de462e8c884b6b8b356
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"load-yaml-file@npm:^0.2.0":
|
||||
version: 0.2.0
|
||||
resolution: "load-yaml-file@npm:0.2.0"
|
||||
@@ -30925,16 +30846,6 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"parse-json@npm:^4.0.0":
|
||||
version: 4.0.0
|
||||
resolution: "parse-json@npm:4.0.0"
|
||||
dependencies:
|
||||
error-ex: ^1.3.1
|
||||
json-parse-better-errors: ^1.0.1
|
||||
checksum: 0fe227d410a61090c247e34fa210552b834613c006c2c64d9a05cfe9e89cf8b4246d1246b1a99524b53b313e9ac024438d0680f67e33eaed7e6f38db64cfe7b5
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"parse-json@npm:^5.0.0, parse-json@npm:^5.2.0":
|
||||
version: 5.2.0
|
||||
resolution: "parse-json@npm:5.2.0"
|
||||
@@ -30947,13 +30858,6 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"parse-package-name@npm:^0.1.0":
|
||||
version: 0.1.0
|
||||
resolution: "parse-package-name@npm:0.1.0"
|
||||
checksum: 7d69b1deeaf82d5a59536c5a8772c8db003b1415dd2465073343dfab5caf90917ecfffdd71d1c004f5cf963c3881ccb8899d0ff820eac705a272e817e246de14
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"parse-path@npm:^7.0.0":
|
||||
version: 7.0.0
|
||||
resolution: "parse-path@npm:7.0.0"
|
||||
@@ -31226,7 +31130,7 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"path-is-inside@npm:1.0.2, path-is-inside@npm:^1.0.2":
|
||||
"path-is-inside@npm:1.0.2":
|
||||
version: 1.0.2
|
||||
resolution: "path-is-inside@npm:1.0.2"
|
||||
checksum: 0b5b6c92d3018b82afb1f74fe6de6338c4c654de4a96123cb343f2b747d5606590ac0c890f956ed38220a4ab59baddfd7b713d78a62d240b20b14ab801fa02cb
|
||||
@@ -31325,15 +31229,6 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"path-type@npm:^3.0.0":
|
||||
version: 3.0.0
|
||||
resolution: "path-type@npm:3.0.0"
|
||||
dependencies:
|
||||
pify: ^3.0.0
|
||||
checksum: 735b35e256bad181f38fa021033b1c33cfbe62ead42bb2222b56c210e42938eecb272ae1949f3b6db4ac39597a61b44edd8384623ec4d79bfdc9a9c0f12537a6
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"path-type@npm:^4.0.0":
|
||||
version: 4.0.0
|
||||
resolution: "path-type@npm:4.0.0"
|
||||
@@ -31508,13 +31403,6 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"pify@npm:^3.0.0":
|
||||
version: 3.0.0
|
||||
resolution: "pify@npm:3.0.0"
|
||||
checksum: 6cdcbc3567d5c412450c53261a3f10991665d660961e06605decf4544a61a97a54fefe70a68d5c37080ff9d6f4cf51444c90198d1ba9f9309a6c0d6e9f5c4fde
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"pify@npm:^4.0.1":
|
||||
version: 4.0.1
|
||||
resolution: "pify@npm:4.0.1"
|
||||
@@ -35061,13 +34949,6 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"slash@npm:^1.0.0":
|
||||
version: 1.0.0
|
||||
resolution: "slash@npm:1.0.0"
|
||||
checksum: 4b6e21b1fba6184a7e2efb1dd173f692d8a845584c1bbf9dc818ff86f5a52fc91b413008223d17cc684604ee8bb9263a420b1182027ad9762e35388434918860
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"slash@npm:^2.0.0":
|
||||
version: 2.0.0
|
||||
resolution: "slash@npm:2.0.0"
|
||||
|
||||
Reference in New Issue
Block a user