From d994377608920e5ce4908d13604e0484df297098 Mon Sep 17 00:00:00 2001 From: David Matejka Date: Fri, 3 Feb 2023 14:23:29 +0100 Subject: [PATCH] add imports linter --- .github/workflows/ci.yaml | 2 + .../src/controllers/ApiController.ts | 6 +- .../src/controllers/BaseController.ts | 4 +- .../controllers/CollaborationController.ts | 2 +- .../src/controllers/DeployController.ts | 2 +- .../src/controllers/LegacyController.ts | 4 +- .../src/controllers/LoginController.ts | 2 +- .../src/controllers/MeController.ts | 2 +- .../src/controllers/PanelController.ts | 2 +- .../src/controllers/ProjectController.ts | 4 +- ee/admin-server/src/dic.ts | 2 +- ee/admin-server/src/services/Router.ts | 4 +- ee/admin-server/src/services/S3Manager.ts | 4 +- .../src/services/StaticFileHandler.ts | 6 +- .../src/utils/WebSocketProtocol.ts | 4 +- ee/admin-server/src/utils/cookies.ts | 2 +- ee/admin-server/src/utils/forwared.ts | 4 +- .../src/utils/readHostFromHeader.ts | 2 +- ee/admin-server/src/utils/readReadable.ts | 2 +- package.json | 1 + packages/admin-i18n/package.json | 2 +- packages/admin/package.json | 4 +- .../bindingFacade/environment/Variable.tsx | 2 +- packages/admin/src/tsconfig.json | 2 +- packages/ui/package.json | 4 +- .../ui/src/components/Forms/Select/Select.tsx | 7 +- packages/ui/src/tsconfig.json | 1 - pnpm-lock.yaml | 2 + scripts/lint/module-import-linter.ts | 142 ++++++++++++++++++ 29 files changed, 185 insertions(+), 42 deletions(-) create mode 100644 scripts/lint/module-import-linter.ts diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index 815d7aede5..2b255ed894 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -19,6 +19,8 @@ jobs: - uses: actions/checkout@v3 - run: npm install -g pnpm@6 - run: pnpm install + - name: "Lint imports" + run: yarn tsx ./scripts/lint/module-import-linter.js - run: pnpm run eslint:lint build: diff --git a/ee/admin-server/src/controllers/ApiController.ts b/ee/admin-server/src/controllers/ApiController.ts index 9e3ee658b6..bb8d30943f 100644 --- a/ee/admin-server/src/controllers/ApiController.ts +++ b/ee/admin-server/src/controllers/ApiController.ts @@ -1,6 +1,6 @@ -import { IncomingMessage, OutgoingHttpHeaders, request as httpRequest, ServerResponse } from 'http' -import { request as httpsRequest, RequestOptions } from 'https' -import { TLSSocket } from 'tls' +import { IncomingMessage, OutgoingHttpHeaders, request as httpRequest, ServerResponse } from 'node:http' +import { request as httpsRequest, RequestOptions } from 'node:https' +import { TLSSocket } from 'node:tls' import { ApiEndpointResolver } from '../services/ApiEndpointResolver' import { readAuthCookie, writeAuthCookie } from '../utils/cookies' import { isProxyRequest } from '../utils/forwared' diff --git a/ee/admin-server/src/controllers/BaseController.ts b/ee/admin-server/src/controllers/BaseController.ts index e88c2ce219..dd41df7216 100644 --- a/ee/admin-server/src/controllers/BaseController.ts +++ b/ee/admin-server/src/controllers/BaseController.ts @@ -1,6 +1,6 @@ -import type { IncomingMessage, ServerResponse } from 'http' +import type { IncomingMessage, ServerResponse } from 'node:http' import type { Json, Type } from '../utils/schema' -import { Buffer } from 'buffer' +import { Buffer } from 'node:buffer' export abstract class BaseController { abstract handle(req: IncomingMessage, res: ServerResponse, params: T): Promise diff --git a/ee/admin-server/src/controllers/CollaborationController.ts b/ee/admin-server/src/controllers/CollaborationController.ts index 6602f733a6..4606d0bc42 100644 --- a/ee/admin-server/src/controllers/CollaborationController.ts +++ b/ee/admin-server/src/controllers/CollaborationController.ts @@ -1,4 +1,4 @@ -import { randomInt } from 'crypto' +import { randomInt } from 'node:crypto' import { ClientIdentity, CollaborationStorage, Scope } from '../services/CollaborationStorage' import { ProjectGroupResolver } from '../services/ProjectGroupResolver' import { TenantClient } from '../services/TenantClient' diff --git a/ee/admin-server/src/controllers/DeployController.ts b/ee/admin-server/src/controllers/DeployController.ts index 2a4aaadb1e..b34ca51016 100644 --- a/ee/admin-server/src/controllers/DeployController.ts +++ b/ee/admin-server/src/controllers/DeployController.ts @@ -1,4 +1,4 @@ -import type { IncomingMessage, ServerResponse } from 'http' +import type { IncomingMessage, ServerResponse } from 'node:http' import { array, object, ParseError, string } from '../utils/schema' import { BaseController } from './BaseController' import type { TenantClient } from '../services/TenantClient' diff --git a/ee/admin-server/src/controllers/LegacyController.ts b/ee/admin-server/src/controllers/LegacyController.ts index 041d6bfb5f..69ed64c77c 100644 --- a/ee/admin-server/src/controllers/LegacyController.ts +++ b/ee/admin-server/src/controllers/LegacyController.ts @@ -1,6 +1,6 @@ import { BaseController } from './BaseController' -import type { IncomingMessage, ServerResponse } from 'http' -import { URL } from 'url' +import type { IncomingMessage, ServerResponse } from 'node:http' +import { URL } from 'node:url' const OLD_PROJECT_URL_PATTERN = /^\/p\/([^\/]+)(\/[^\/]+(\/null)?)?/ diff --git a/ee/admin-server/src/controllers/LoginController.ts b/ee/admin-server/src/controllers/LoginController.ts index d55beee892..32f47a506a 100644 --- a/ee/admin-server/src/controllers/LoginController.ts +++ b/ee/admin-server/src/controllers/LoginController.ts @@ -1,4 +1,4 @@ -import type { IncomingMessage, ServerResponse } from 'http' +import type { IncomingMessage, ServerResponse } from 'node:http' import { BaseController } from './BaseController' import { StaticFileHandler } from '../services/StaticFileHandler' import { ConfigResolver } from '../services/ConfigResolver' diff --git a/ee/admin-server/src/controllers/MeController.ts b/ee/admin-server/src/controllers/MeController.ts index cab8af4f68..d5d491fb68 100644 --- a/ee/admin-server/src/controllers/MeController.ts +++ b/ee/admin-server/src/controllers/MeController.ts @@ -1,5 +1,5 @@ import { BaseController } from './BaseController' -import type { IncomingMessage, ServerResponse } from 'http' +import type { IncomingMessage, ServerResponse } from 'node:http' import type { TenantClient } from '../services/TenantClient' import type { S3Manager } from '../services/S3Manager' import { readAuthCookie } from '../utils/cookies' diff --git a/ee/admin-server/src/controllers/PanelController.ts b/ee/admin-server/src/controllers/PanelController.ts index 0230f97f22..a5b6c7dad3 100644 --- a/ee/admin-server/src/controllers/PanelController.ts +++ b/ee/admin-server/src/controllers/PanelController.ts @@ -1,4 +1,4 @@ -import type { IncomingMessage, ServerResponse } from 'http' +import type { IncomingMessage, ServerResponse } from 'node:http' import { BaseController } from './BaseController' import { StaticFileHandler } from '../services/StaticFileHandler' import { PanelConfig } from '../config' diff --git a/ee/admin-server/src/controllers/ProjectController.ts b/ee/admin-server/src/controllers/ProjectController.ts index a6732686f2..4613d5bc0d 100644 --- a/ee/admin-server/src/controllers/ProjectController.ts +++ b/ee/admin-server/src/controllers/ProjectController.ts @@ -1,8 +1,8 @@ import { BaseController } from './BaseController' -import type { IncomingMessage, ServerResponse } from 'http' +import type { IncomingMessage, ServerResponse } from 'node:http' import type { TenantClient } from '../services/TenantClient' import type { S3Manager } from '../services/S3Manager' -import { Readable } from 'stream' +import { Readable } from 'node:stream' import type { GetObjectCommandOutput } from '@aws-sdk/client-s3' import { readAuthCookie } from '../utils/cookies' import { readReadable } from '../utils/readReadable' diff --git a/ee/admin-server/src/dic.ts b/ee/admin-server/src/dic.ts index a15338bc83..1dcd4c29de 100644 --- a/ee/admin-server/src/dic.ts +++ b/ee/admin-server/src/dic.ts @@ -7,7 +7,7 @@ import { DeployController } from './controllers/DeployController' import { ProjectController } from './controllers/ProjectController' import { TenantClient } from './services/TenantClient' import { ApiController } from './controllers/ApiController' -import * as http from 'http' +import * as http from 'node:http' import { S3Manager } from './services/S3Manager' import { MeController } from './controllers/MeController' import { LegacyController } from './controllers/LegacyController' diff --git a/ee/admin-server/src/services/Router.ts b/ee/admin-server/src/services/Router.ts index 924168bf10..b17862a5d7 100644 --- a/ee/admin-server/src/services/Router.ts +++ b/ee/admin-server/src/services/Router.ts @@ -1,5 +1,5 @@ -import { IncomingMessage, ServerResponse } from 'http' -import { URL } from 'url' +import { IncomingMessage, ServerResponse } from 'node:http' +import { URL } from 'node:url' import { readHostFromHeader } from '../utils/readHostFromHeader' import { BadRequestError } from '../BadRequestError' import { ProjectGroupResolver } from './ProjectGroupResolver' diff --git a/ee/admin-server/src/services/S3Manager.ts b/ee/admin-server/src/services/S3Manager.ts index 9048efa08d..b54a83424a 100644 --- a/ee/admin-server/src/services/S3Manager.ts +++ b/ee/admin-server/src/services/S3Manager.ts @@ -6,10 +6,10 @@ import { PutObjectCommandOutput, S3Client, } from '@aws-sdk/client-s3' -import type * as Buffer from 'buffer' +import type * as Buffer from 'node:buffer' import mime from 'mime' import { S3LocationResolver } from './S3LocationResolver' -import { Readable } from 'stream' +import { Readable } from 'node:stream' import { readReadable } from '../utils/readReadable' export class S3Manager { diff --git a/ee/admin-server/src/services/StaticFileHandler.ts b/ee/admin-server/src/services/StaticFileHandler.ts index 9f68b7c5ca..caab7b945d 100644 --- a/ee/admin-server/src/services/StaticFileHandler.ts +++ b/ee/admin-server/src/services/StaticFileHandler.ts @@ -1,7 +1,7 @@ -import { IncomingMessage, ServerResponse } from 'http' -import { URL } from 'url' +import { IncomingMessage, ServerResponse } from 'node:http' +import { URL } from 'node:url' import mime from 'mime' -import { readFile } from 'fs/promises' +import { readFile } from 'node:fs/promises' export type ProcessFile = (path: string, content: Buffer, req: IncomingMessage) => Promise diff --git a/ee/admin-server/src/utils/WebSocketProtocol.ts b/ee/admin-server/src/utils/WebSocketProtocol.ts index db66dde3c1..7dcb57ad15 100644 --- a/ee/admin-server/src/utils/WebSocketProtocol.ts +++ b/ee/admin-server/src/utils/WebSocketProtocol.ts @@ -1,6 +1,6 @@ import { WebSocket, WebSocketServer } from 'ws' -import { IncomingMessage } from 'http' -import { Socket } from 'net' +import { IncomingMessage } from 'node:http' +import { Socket } from 'node:net' import { intersection, JsonObject, literal, object, ParseError, string, Type, union } from './schema' interface ProtocolDefinition> { diff --git a/ee/admin-server/src/utils/cookies.ts b/ee/admin-server/src/utils/cookies.ts index cbc55fb9cd..47f7037af8 100644 --- a/ee/admin-server/src/utils/cookies.ts +++ b/ee/admin-server/src/utils/cookies.ts @@ -1,4 +1,4 @@ -import { IncomingMessage, OutgoingMessage } from 'http' +import { IncomingMessage, OutgoingMessage } from 'node:http' import * as cookie from 'cookie' import { isRequestSecure } from './forwared' diff --git a/ee/admin-server/src/utils/forwared.ts b/ee/admin-server/src/utils/forwared.ts index 558702b605..3327a84515 100644 --- a/ee/admin-server/src/utils/forwared.ts +++ b/ee/admin-server/src/utils/forwared.ts @@ -1,6 +1,6 @@ -import { IncomingMessage } from 'http' +import { IncomingMessage } from 'node:http' import ipaddr from 'ipaddr.js' -import { TLSSocket } from 'tls' +import { TLSSocket } from 'node:tls' export const isProxyRequest = (req: IncomingMessage): boolean => { const ip = ipaddr.parse(req.socket.remoteAddress ?? '0.0.0.0') diff --git a/ee/admin-server/src/utils/readHostFromHeader.ts b/ee/admin-server/src/utils/readHostFromHeader.ts index f562c40caa..d2f35c86d0 100644 --- a/ee/admin-server/src/utils/readHostFromHeader.ts +++ b/ee/admin-server/src/utils/readHostFromHeader.ts @@ -1,4 +1,4 @@ -import { IncomingMessage } from 'http' +import { IncomingMessage } from 'node:http' import { BadRequestError } from '../BadRequestError' export const readHostFromHeader = (req: IncomingMessage): string => { diff --git a/ee/admin-server/src/utils/readReadable.ts b/ee/admin-server/src/utils/readReadable.ts index 9c64b9be76..d89e994ea8 100644 --- a/ee/admin-server/src/utils/readReadable.ts +++ b/ee/admin-server/src/utils/readReadable.ts @@ -1,4 +1,4 @@ -import { Readable } from 'stream' +import { Readable } from 'node:stream' export const readReadable = (readable: Readable): Promise => { return new Promise((resolve, reject) => { diff --git a/package.json b/package.json index 6ad638ed70..886a48c221 100644 --- a/package.json +++ b/package.json @@ -45,6 +45,7 @@ "eslint-plugin-prettier": "3.4.0", "eslint-plugin-react": "7.24.0", "eslint-plugin-react-hooks": "4.2.0", + "fast-glob": "^3.2.12", "jsdom": "^17.0.0", "prettier": "2.3.2", "react": "^18.2.0", diff --git a/packages/admin-i18n/package.json b/packages/admin-i18n/package.json index 862a44100a..c533fcb60a 100644 --- a/packages/admin-i18n/package.json +++ b/packages/admin-i18n/package.json @@ -30,7 +30,7 @@ "ae:build": "api-extractor run --local", "ae:test": "api-extractor run" }, - "devDependencies": { + "dependencies": { "@contember/admin": "workspace:*" } } diff --git a/packages/admin/package.json b/packages/admin/package.json index c94b58954e..01f32ec5b2 100644 --- a/packages/admin/package.json +++ b/packages/admin/package.json @@ -42,7 +42,6 @@ "test": "vitest --environment jsdom tests/vitest" }, "dependencies": { - "@babel/core": "7.17.10", "@contember/client": "workspace:*", "@contember/react-binding": "workspace:*", "@contember/react-client": "workspace:*", @@ -50,7 +49,6 @@ "@contember/react-utils": "workspace:*", "@contember/ui": "workspace:*", "@formatjs/icu-messageformat-parser": "2.0.11", - "@mangoweb/sass-base": "0.0.8", "@sindresorhus/slugify": "0.11.0", "blueimp-md5": "2.18.0", "buffer": "6.0.3", @@ -77,10 +75,12 @@ "react-dom": "^17 || ^18" }, "devDependencies": { + "@babel/core": "7.17.10", "@contember/schema": "^1.0.0-rc.16", "@contember/schema-definition": "^1.0.0-rc.16", "@contember/schema-migrations": "^1.0.0-rc.16", "@contember/schema-utils": "^1.0.0-rc.16", + "@mangoweb/sass-base": "0.0.8", "@playwright/test": "1.20.0", "@types/blueimp-md5": "2.18.0", "@types/debounce": "1.2.0", diff --git a/packages/admin/src/components/bindingFacade/environment/Variable.tsx b/packages/admin/src/components/bindingFacade/environment/Variable.tsx index 13afba60e7..5fe82981bf 100644 --- a/packages/admin/src/components/bindingFacade/environment/Variable.tsx +++ b/packages/admin/src/components/bindingFacade/environment/Variable.tsx @@ -8,7 +8,7 @@ interface VariableProps { export const Variable = memo(({ name, format }: VariableProps): ReactElement => { const environment = useEnvironment() - const value = environment.getVariableOrElse(name, undefined) ?? environment.getParameter(name) + const value = environment.getVariableOrElse(name, undefined) ?? environment.getParameter(name) const formatted = useMemo(() => (format ? format(value) : value), [format, value]) diff --git a/packages/admin/src/tsconfig.json b/packages/admin/src/tsconfig.json index d60aec005d..be4897bd4c 100644 --- a/packages/admin/src/tsconfig.json +++ b/packages/admin/src/tsconfig.json @@ -1,7 +1,7 @@ { "extends": "../../../tsconfig.settings.json", "compilerOptions": { - "outDir": "../dist/types", + "outDir": "../dist/types" }, "references": [ { "path": "../../client/src" }, diff --git a/packages/ui/package.json b/packages/ui/package.json index e941e8848c..888e01b7a7 100644 --- a/packages/ui/package.json +++ b/packages/ui/package.json @@ -35,11 +35,8 @@ }, "dependencies": { "@blueprintjs/icons": "3.29.0", - "@contember/react-multipass-rendering": "workspace:*", "@contember/react-utils": "workspace:*", - "@mangoweb/sass-base": "0.0.8", "@popperjs/core": "2.10.2", - "chroma-js": "2.1.2", "classnames": "2.3.1", "react-aria": "^3.20.0", "react-popper": "^2.3.0", @@ -53,6 +50,7 @@ }, "devDependencies": { "@babel/core": "7.15.5", + "@mangoweb/sass-base": "0.0.8", "@storybook/addon-actions": "6.5.13", "@storybook/addon-essentials": "6.5.13", "@storybook/addon-links": "6.5.13", diff --git a/packages/ui/src/components/Forms/Select/Select.tsx b/packages/ui/src/components/Forms/Select/Select.tsx index 668ed4fc79..c54ff6f30e 100644 --- a/packages/ui/src/components/Forms/Select/Select.tsx +++ b/packages/ui/src/components/Forms/Select/Select.tsx @@ -1,7 +1,6 @@ import classNames from 'classnames' import { ComponentProps, CSSProperties, ForwardedRef, forwardRef, memo, ReactElement, RefAttributes, useCallback, useMemo, useRef } from 'react' -import ReactSelect, { StylesConfig, useStateManager } from 'react-select' -import SelectClass from 'react-select/dist/declarations/src/Select' +import ReactSelect, { StylesConfig, useStateManager, SelectInstance } from 'react-select' import { useComponentClassName } from '../../../auxiliary' import { noop } from '../../../utils' import { getPortalRoot } from '../../Portal' @@ -21,8 +20,8 @@ export type SelectOptionWithKey = & Omit, 'key'> & { key: string } -export type HTMLReactSelectElement = SelectClass, false, never> -export type HTMLReactSelectElementWithKey = SelectClass, false, never> +export type HTMLReactSelectElement = SelectInstance, false, never> +export type HTMLReactSelectElementWithKey = SelectInstance, false, never> export type SelectProps = Omit, 'type' | keyof ControlConstraintProps> & { options: SelectOption[] diff --git a/packages/ui/src/tsconfig.json b/packages/ui/src/tsconfig.json index e5097eee52..ebf2e189db 100644 --- a/packages/ui/src/tsconfig.json +++ b/packages/ui/src/tsconfig.json @@ -4,7 +4,6 @@ "outDir": "../dist/types" }, "references": [ - { "path": "../../react-multipass-rendering/src" }, { "path": "../../react-utils/src" } ] } diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 2a6ce8cede..8ab4b8a405 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -17,6 +17,7 @@ importers: eslint-plugin-prettier: 3.4.0 eslint-plugin-react: 7.24.0 eslint-plugin-react-hooks: 4.2.0 + fast-glob: ^3.2.12 jsdom: ^17.0.0 prettier: 2.3.2 react: ^18.2.0 @@ -41,6 +42,7 @@ importers: eslint-plugin-prettier: 3.4.0_5a48a349ffec60f5257b5f148f5199c3 eslint-plugin-react: 7.24.0_eslint@7.32.0 eslint-plugin-react-hooks: 4.2.0_eslint@7.32.0 + fast-glob: 3.2.12 jsdom: 17.0.0 prettier: 2.3.2 react: 18.2.0 diff --git a/scripts/lint/module-import-linter.ts b/scripts/lint/module-import-linter.ts new file mode 100644 index 0000000000..b01b58a5f1 --- /dev/null +++ b/scripts/lint/module-import-linter.ts @@ -0,0 +1,142 @@ +import ts from 'typescript' +import * as fs from 'fs/promises' +import { join, normalize } from 'path' +import glob from 'fast-glob' + +const globalModules = new Set(['vitest']) +const allowedUnused = new Set([ + 'stacktracey', + '@popperjs/core', + '@mangoweb/sass-base', + '@aws-sdk/signature-v4-crt', +]) + +const allowedDirectoryImports = new Set([ + 'fast-deep-equal/es6', +]) + +const processPackage = async (dir: string, projectList: ProjectList) => { + const files = await glob(`${dir}/src/**/*.{ts,tsx}`, { onlyFiles: true }) + const contents = await Promise.all(files.map(async (it): Promise<[file: string, content: string]> => [it, await fs.readFile(it, 'utf-8')])) + const imports = new Set() + const errors: {file: string; message: string}[] = [] + for (const [file, content] of contents) { + const sourceFile = ts.createSourceFile(file, content, ts.ScriptTarget.ESNext) + sourceFile.forEachChild(node => { + if (node.kind === ts.SyntaxKind.ImportDeclaration || node.kind === ts.SyntaxKind.ExportDeclaration) { + const moduleSpecifier = (node as ts.ImportDeclaration | ts.ExportDeclaration).moduleSpecifier + if (!moduleSpecifier) { + return + } + const module = (moduleSpecifier as ts.StringLiteral).text + if (module === '.') { + errors.push({ file, message: 'Dot import (".") is forbidden' }) + } + if (!module.startsWith('node:') && !module.startsWith('.') && !globalModules.has(module)) { + const moduleMatch = module.match(/^((?:@[\w_-]+\/)?[.\w_-]+)(\/.+)?$/) + if (!moduleMatch) { + throw new Error(`Invalid module ${module}`) + } + if (moduleMatch[2] && !allowedDirectoryImports.has(module)) { + errors.push({ file, message: `Forbidden file/directory import found: ${module}` }) + } + imports.add(moduleMatch[1]) + } + } + }) + } + const thisProject = projectList.getByDir(dir) + const allProjectNames = projectList.projects.map(it => it.name) + const referencedProjects = thisProject.tsconfig.references?.map(it => projectList.getByDir(normalize(join(dir, 'src', it.path)))) ?? [] + const referencedProjectNames = referencedProjects.map(it => it.name) + + for (const module of Array.from(imports.values())) { + if (!thisProject.packageJson.dependencies?.[module] && !thisProject.packageJson.peerDependencies?.[module]) { + errors.push({ file: dir, message: `Module ${module} is missing in package.json` }) + } + if (allProjectNames.includes(module) && !referencedProjectNames.includes(module)) { + errors.push({ file: dir, message: `Module ${module} is not referenced from tsconfig.json` }) + } + } + for (const referenced of referencedProjectNames) { + if (!imports.has(referenced)) { + errors.push({ file: dir, message: `Project ${referenced} referenced from tsconfig.json is not used` }) + } + } + for (const key in thisProject.packageJson.dependencies ?? {}) { + if (!imports.has(key) && !allowedUnused.has(key)) { + errors.push({ file: dir, message: `Module ${key} from package.json dependencies is unused` }) + } + } + + if (errors.length > 0) { + for (const { file, message } of errors) { + console.log(`${file}:\n${message}\n`) + } + return false + } + return true +} + +class ProjectList { + constructor( + public readonly projects: Project[], + ) { + } + + public getByName(name: string) { + const project = this.projects.find(it => it.name === name) + if (!project) { + throw new Error(`Undefined project ${name}`) + } + return project + } + + public getByDir(dir: string) { + const project = this.projects.find(it => it.dir === dir || join(it.dir, 'src') === dir) + if (!project) { + throw new Error(`Undefined project ${dir}`) + } + return project + } +} +interface Project { + name: string + dir: string + tsconfig: { + references?: { path: string }[] + } + packageJson: { + dependencies?: Record + peerDependencies?: Record + devDependencies?: Record + } +} +(async () => { + const dirs = (await glob(process.cwd() + '/{ee,packages}/*', { onlyDirectories: true })) + .filter(dir => !dir.endsWith('packages/admin-sandbox')) + + const projects = await Promise.all(dirs.map(async (dir): Promise => { + try { + const packageJson = JSON.parse(await fs.readFile(`${dir}/package.json`, 'utf8')) + const tsconfig = JSON.parse(await fs.readFile(`${dir}/src/tsconfig.json`, 'utf8')) + return { + dir, + name: packageJson.name, + packageJson, + tsconfig, + } + } catch (e) { + console.log(dir) + throw e + } + })) + const projectList = new ProjectList(projects) + const failed = (await Promise.all(dirs.map(it => processPackage(it, projectList)))).some(it => !it) + if (failed) { + process.exit(1) + } +})().catch(e => { + console.error(e) + process.exit(1) +})