diff --git a/.eslintrc.cjs b/.eslintrc.cjs index 02f9f1ea5..2a5c4f028 100644 --- a/.eslintrc.cjs +++ b/.eslintrc.cjs @@ -6,6 +6,7 @@ module.exports = { reportUnusedDisableDirectives: true, ignorePatterns: [ 'scripts', + 'rules', 'out', 'public', 'packages/web/app/src/graphql/index.ts', @@ -17,7 +18,7 @@ module.exports = { sourceType: 'module', }, parser: '@typescript-eslint/parser', - plugins: ['@typescript-eslint', 'import'], + plugins: ['@typescript-eslint', 'import', 'hive'], extends: ['eslint:recommended', 'plugin:@typescript-eslint/recommended'], rules: { '@typescript-eslint/no-unused-vars': ['error', { argsIgnorePattern: '^_', ignoreRestSiblings: true }], @@ -36,11 +37,17 @@ module.exports = { 'import/no-extraneous-dependencies': [ 'error', { - devDependencies: ['packages/services/storage/tools/*.js'], + devDependencies: ['packages/services/storage/tools/*.js', 'packages/services/**'], optionalDependencies: false, }, ], - 'no-restricted-imports': ['error', { patterns: ['packages/*'] }], + 'hive/enforce-deps-in-dev': [ + 'error', + { + scopes: ['@hive', '@graphql-hive'], + ignored: ['packages/libraries/**', 'packages/web/**'], + }, + ], // 🚨 The following rules needs to be fixed and was temporarily disabled to avoid printing warning '@typescript-eslint/no-explicit-any': 'off', diff --git a/package.json b/package.json index d373f2c16..10f4c2442 100644 --- a/package.json +++ b/package.json @@ -35,6 +35,7 @@ "turbo": "env-cmd --silent turbo run" }, "devDependencies": { + "eslint-plugin-hive": "file:./rules", "@changesets/cli": "2.22.0", "@graphql-codegen/add": "3.1.1", "@graphql-codegen/cli": "2.6.2", diff --git a/packages/services/api/package.json b/packages/services/api/package.json index 421e1fec2..ff272b014 100644 --- a/packages/services/api/package.json +++ b/packages/services/api/package.json @@ -2,7 +2,7 @@ "name": "@hive/api", "type": "module", "private": true, - "version": "0.0.2", + "version": "0.0.0", "license": "MIT", "peerDependencies": { "graphql": "^16.0.0", @@ -45,6 +45,9 @@ "zod": "3.15.1" }, "devDependencies": { + "@hive/schema": "0.0.0", + "@hive/tokens": "0.0.0", + "@graphql-hive/core": "0.2.2", "@types/auth0": "2.34.2", "@types/ioredis": "4.28.7", "@types/lodash": "4.14.182", diff --git a/packages/services/cdn-worker/package.json b/packages/services/cdn-worker/package.json index aa5fc17f0..1d37a559e 100644 --- a/packages/services/cdn-worker/package.json +++ b/packages/services/cdn-worker/package.json @@ -16,6 +16,7 @@ "graphql": "16.5.0" }, "devDependencies": { + "@hive/service-common": "0.0.0", "fastify": "3.29.0", "esbuild": "0.14.39", "cross-undici-fetch": "0.1.27", diff --git a/packages/services/cdn-worker/src/dev-polyfill.ts b/packages/services/cdn-worker/src/dev-polyfill.ts index b9a3a2ec0..69687df33 100644 --- a/packages/services/cdn-worker/src/dev-polyfill.ts +++ b/packages/services/cdn-worker/src/dev-polyfill.ts @@ -1,4 +1,3 @@ -/* eslint-disable import/no-extraneous-dependencies */ import { Response, Request, Headers, ReadableStream } from 'cross-undici-fetch'; globalThis.Response = Response; diff --git a/packages/services/rate-limit/package.json b/packages/services/rate-limit/package.json index 7ce404079..d6169c1e4 100644 --- a/packages/services/rate-limit/package.json +++ b/packages/services/rate-limit/package.json @@ -3,7 +3,7 @@ "type": "module", "name": "@hive/rate-limit", "description": "A microservice for Hive SaaS, that exposes information about rate limits per given org/target.", - "version": "0.0.1", + "version": "0.0.0", "license": "MIT", "scripts": { "dev": "tsup-node src/dev.ts --watch --format esm --target node16 --onSuccess 'node dist/dev.js' | pino-pretty --translateTime HH:MM:ss TT --ignore pid,hostname", @@ -23,6 +23,8 @@ "got": "12.0.4" }, "devDependencies": { + "@hive/service-common": "0.0.0", + "@hive/storage": "0.0.0", "pino-pretty": "6.0.0" }, "buildOptions": { diff --git a/packages/services/schema/package.json b/packages/services/schema/package.json index 08e4b02eb..920bcc70f 100644 --- a/packages/services/schema/package.json +++ b/packages/services/schema/package.json @@ -2,7 +2,7 @@ "name": "@hive/schema", "private": true, "type": "module", - "version": "0.2.1", + "version": "0.0.0", "license": "MIT", "scripts": { "dev": "tsup-node src/dev.ts --format esm --target node16 --watch --onSuccess 'node dist/dev.js' | pino-pretty --translateTime HH:MM:ss TT --ignore pid,hostname", @@ -22,6 +22,7 @@ "ioredis": "4.28.3" }, "devDependencies": { + "@hive/service-common": "0.0.0", "@types/ioredis": "4.28.7", "pino-pretty": "6.0.0" }, diff --git a/packages/services/server/package.json b/packages/services/server/package.json index eafac5955..2ec4bae53 100644 --- a/packages/services/server/package.json +++ b/packages/services/server/package.json @@ -3,7 +3,7 @@ "type": "module", "private": true, "bin": "index.js", - "version": "0.27.8", + "version": "0.0.0", "license": "MIT", "scripts": { "dev": "tsup-node src/dev.ts --format esm --target node16 --watch --onSuccess 'node dist/dev.js' | pino-pretty --translateTime HH:MM:ss TT --ignore pid,hostname", @@ -25,6 +25,10 @@ "reflect-metadata": "0.1.13" }, "devDependencies": { + "@graphql-hive/client": "0.15.4", + "@hive/api": "0.0.0", + "@hive/service-common": "0.0.0", + "@hive/storage": "0.0.0", "pino-pretty": "6.0.0", "@swc/core": "1.2.185" }, diff --git a/packages/services/service-common/package.json b/packages/services/service-common/package.json index e51a1310a..e882fe03c 100644 --- a/packages/services/service-common/package.json +++ b/packages/services/service-common/package.json @@ -2,7 +2,7 @@ "private": true, "type": "module", "name": "@hive/service-common", - "version": "0.1.3", + "version": "0.0.0", "license": "MIT", "dependencies": { "fastify": "3.29.0", diff --git a/packages/services/storage/docker-compose.yml b/packages/services/storage/docker-compose.yml index 9c9b36b70..1fca35b3c 100644 --- a/packages/services/storage/docker-compose.yml +++ b/packages/services/storage/docker-compose.yml @@ -56,28 +56,31 @@ services: - 'stack' zookeeper: - image: confluentinc/cp-zookeeper:6.2.2 + image: confluentinc/cp-zookeeper:6.2.2-3-ubi8 hostname: zookeeper networks: - 'stack' ports: - '2181:2181' - environment: - BUMP: 1 - ZOOKEEPER_CLIENT_PORT: 2181 - ZOOKEEPER_TICK_TIME: 2000 + ulimits: + nofile: + soft: 20000 + hard: 40000 healthcheck: test: ['CMD', 'cub', 'zk-ready', '127.0.0.1:2181', '10'] - interval: 30s + interval: 5s timeout: 10s - retries: 10 - start_period: 30s + retries: 6 + start_period: 15s + environment: + ZOOKEEPER_CLIENT_PORT: 2181 + ZOOKEEPER_TICK_TIME: 2000 volumes: - ./volumes/zookeeper/db:/var/lib/zookeeper/data - ./volumes/zookeeper/log:/var/lib/zookeeper/log broker: - image: confluentinc/cp-kafka:6.2.2 + image: confluentinc/cp-kafka:6.2.2-3-ubi8 hostname: borker depends_on: zookeeper: @@ -87,19 +90,20 @@ services: ports: - '29092:29092' - '9092:9092' - healthcheck: - test: ['CMD', 'cub', 'kafka-ready', '1', '5', '-b', '127.0.0.1:9092', '-c', '/etc/kafka/kafka.properties'] - interval: 30s - timeout: 10s - retries: 10 - start_period: 30s ulimits: nofile: - soft: 16384 - hard: 16384 + soft: 20000 + hard: 40000 + healthcheck: + test: ['CMD', 'cub', 'kafka-ready', '1', '5', '-b', '127.0.0.1:9092', '-c', '/etc/kafka/kafka.properties'] + interval: 15s + timeout: 10s + retries: 6 + start_period: 15s environment: KAFKA_BROKER_ID: 1 - KAFKA_ZOOKEEPER_CONNECT: 'zookeeper:2181' + KAFKA_ZOOKEEPER_CONNECT: zookeeper:2181 + KAFKA_AUTO_CREATE_TOPICS_ENABLE: 'true' KAFKA_LISTENER_SECURITY_PROTOCOL_MAP: PLAINTEXT:PLAINTEXT,PLAINTEXT_HOST:PLAINTEXT KAFKA_ADVERTISED_LISTENERS: PLAINTEXT://broker:29092,PLAINTEXT_HOST://localhost:9092 KAFKA_OFFSETS_TOPIC_REPLICATION_FACTOR: 1 diff --git a/packages/services/storage/package.json b/packages/services/storage/package.json index f80c43f84..23fa267ca 100644 --- a/packages/services/storage/package.json +++ b/packages/services/storage/package.json @@ -2,7 +2,7 @@ "name": "@hive/storage", "type": "module", "private": true, - "version": "0.14.1", + "version": "0.0.0", "license": "MIT", "scripts": { "setup": "yarn db:start && yarn db", diff --git a/packages/services/storage/src/index.ts b/packages/services/storage/src/index.ts index af9a9ba7a..4cd696f1e 100644 --- a/packages/services/storage/src/index.ts +++ b/packages/services/storage/src/index.ts @@ -13,8 +13,10 @@ import type { Alert, AuthProvider, OrganizationBilling, + Storage, + ProjectType, + OrganizationType, } from '@hive/api'; -import { Storage, ProjectType, OrganizationType } from '@hive/api'; import { sql, TaggedTemplateLiteralInvocationType } from 'slonik'; import { commits, @@ -97,7 +99,7 @@ export async function createStorage(connection: string): Promise { schemaPush: parseInt(organization.limit_schema_push_monthly), }, billingPlan: organization.plan_name, - type: organization.type === 'PERSONAL' ? OrganizationType.PERSONAL : OrganizationType.REGULAR, + type: (organization.type === 'PERSONAL' ? 'PERSONAL' : 'REGULAR') as OrganizationType, }; } @@ -570,7 +572,7 @@ export async function createStorage(connection: string): Promise { }, async getMyOrganization({ user }) { const org = await pool.maybeOne>( - sql`SELECT * FROM public.organizations WHERE user_id = ${user} AND type = ${OrganizationType.PERSONAL} LIMIT 1` + sql`SELECT * FROM public.organizations WHERE user_id = ${user} AND type = ${'PERSONAL'} LIMIT 1` ); return org ? transformOrganization(org) : null; diff --git a/packages/services/stripe-billing/package.json b/packages/services/stripe-billing/package.json index 30f7f0bbf..cb02368d7 100644 --- a/packages/services/stripe-billing/package.json +++ b/packages/services/stripe-billing/package.json @@ -3,7 +3,7 @@ "type": "module", "name": "@hive/stripe-billing", "description": "A microservice for Hive SaaS, that syncs usage information to Stripe (metered billing)", - "version": "0.0.1", + "version": "0.0.0", "license": "MIT", "scripts": { "dev": "tsup-node src/dev.ts --format esm --target node16 --watch --onSuccess 'node dist/dev.js' | pino-pretty --translateTime HH:MM:ss TT --ignore pid,hostname", @@ -24,6 +24,8 @@ "got": "12.0.4" }, "devDependencies": { + "@hive/service-common": "0.0.0", + "@hive/storage": "0.0.0", "pino-pretty": "6.0.0" }, "buildOptions": { diff --git a/packages/services/tokens/package.json b/packages/services/tokens/package.json index bc8c18852..a8ad788ca 100644 --- a/packages/services/tokens/package.json +++ b/packages/services/tokens/package.json @@ -2,7 +2,7 @@ "name": "@hive/tokens", "type": "module", "private": true, - "version": "0.6.8", + "version": "0.0.0", "license": "MIT", "scripts": { "dev": "tsup-node src/dev.ts --format esm --target node16 --watch --onSuccess 'node dist/dev.js' | pino-pretty --translateTime HH:MM:ss TT --ignore pid,hostname", @@ -21,6 +21,8 @@ "reflect-metadata": "0.1.13" }, "devDependencies": { + "@hive/service-common": "0.0.0", + "@hive/storage": "0.0.0", "@types/ms": "0.7.31", "pino-pretty": "6.0.0" }, diff --git a/packages/services/usage-common/package.json b/packages/services/usage-common/package.json index 6d9234680..d8ad4d769 100644 --- a/packages/services/usage-common/package.json +++ b/packages/services/usage-common/package.json @@ -1,7 +1,7 @@ { "name": "@hive/usage-common", "private": true, - "version": "0.0.1", + "version": "0.0.0", "license": "MIT", "dependencies": { "graphql": "16.5.0" diff --git a/packages/services/usage-estimator/package.json b/packages/services/usage-estimator/package.json index ad2f6973c..6cd8569b1 100644 --- a/packages/services/usage-estimator/package.json +++ b/packages/services/usage-estimator/package.json @@ -3,7 +3,7 @@ "type": "module", "name": "@hive/usage-estimator", "description": "A microservice for Hive SaaS, that calculates and exposes usage information.", - "version": "0.0.1", + "version": "0.0.0", "license": "MIT", "scripts": { "dev": "tsup-node src/dev.ts --format esm --target node16 --watch --onSuccess 'node dist/dev.js' | pino-pretty --translateTime HH:MM:ss TT --ignore pid,hostname", @@ -21,6 +21,9 @@ "got": "12.0.4" }, "devDependencies": { + "@hive/api": "0.0.0", + "@hive/service-common": "0.0.0", + "@hive/storage": "0.0.0", "pino-pretty": "6.0.0" }, "buildOptions": { diff --git a/packages/services/usage-ingestor/package.json b/packages/services/usage-ingestor/package.json index 4ec326ef1..8fc884fb7 100644 --- a/packages/services/usage-ingestor/package.json +++ b/packages/services/usage-ingestor/package.json @@ -2,7 +2,7 @@ "private": true, "type": "module", "name": "@hive/usage-ingestor", - "version": "0.0.2", + "version": "0.0.0", "license": "MIT", "scripts": { "dev": "tsup-node src/dev.ts --watch --format esm --target node16 --onSuccess 'node dist/dev.js' | pino-pretty --translateTime HH:MM:ss TT --ignore pid,hostname", @@ -22,6 +22,9 @@ "tiny-lru": "8.0.2" }, "devDependencies": { + "@graphql-hive/core": "0.2.2", + "@hive/service-common": "0.0.0", + "@hive/usage-common": "0.0.0", "pino-pretty": "6.0.0" }, "buildOptions": { diff --git a/packages/services/usage/package.json b/packages/services/usage/package.json index e351928e0..4d5b697f9 100644 --- a/packages/services/usage/package.json +++ b/packages/services/usage/package.json @@ -2,7 +2,7 @@ "name": "@hive/usage", "type": "module", "private": true, - "version": "0.18.0", + "version": "0.0.0", "license": "MIT", "scripts": { "dev": "tsup-node src/dev.ts --format esm --target node16 --watch --onSuccess 'node dist/dev.js' | pino-pretty --translateTime HH:MM:ss TT --ignore pid,hostname", @@ -21,6 +21,9 @@ "tiny-lru": "8.0.2" }, "devDependencies": { + "@hive/usage-common": "0.0.0", + "@hive/service-common": "0.0.0", + "@hive/tokens": "0.0.0", "pino-pretty": "6.0.0" }, "buildOptions": { diff --git a/packages/services/webhooks/package.json b/packages/services/webhooks/package.json index bfd2c6681..c9b62e3d0 100644 --- a/packages/services/webhooks/package.json +++ b/packages/services/webhooks/package.json @@ -2,7 +2,7 @@ "name": "@hive/webhooks", "type": "module", "private": true, - "version": "0.1.4", + "version": "0.0.0", "license": "MIT", "scripts": { "dev": "tsup-node src/dev.ts --format esm --target node16 --watch --onSuccess 'node dist/dev.js' | pino-pretty --translateTime HH:MM:ss TT --ignore pid,hostname", @@ -20,6 +20,7 @@ "p-timeout": "5.0.2" }, "devDependencies": { + "@hive/service-common": "0.0.0", "ioredis": "4.28.3", "copyfiles": "2.4.1", "pino-pretty": "6.0.0" diff --git a/packages/web/app/package.json b/packages/web/app/package.json index 60698925b..1e5354a2e 100644 --- a/packages/web/app/package.json +++ b/packages/web/app/package.json @@ -1,7 +1,7 @@ { "name": "@hive/app", "private": true, - "version": "0.16.2", + "version": "0.0.0", "scripts": { "dev": "next dev", "start": "next start", diff --git a/packages/web/app/src/components/v2/header.tsx b/packages/web/app/src/components/v2/header.tsx index b9a352421..a5f78efee 100644 --- a/packages/web/app/src/components/v2/header.tsx +++ b/packages/web/app/src/components/v2/header.tsx @@ -6,6 +6,7 @@ import { useQuery } from 'urql'; import { useUser } from '@/components/auth/AuthProvider'; import { Avatar, Button, DropdownMenu, HiveLink } from '@/components/v2'; import { + AlertTriangleIcon, ArrowDownIcon, CalendarIcon, FileTextIcon, @@ -15,7 +16,6 @@ import { PlusIcon, SettingsIcon, TrendingUpIcon, - AlertTriangleIcon, } from '@/components/v2/icon'; import { CreateOrganizationModal } from '@/components/v2/modals'; import { MeDocument, OrganizationsDocument, OrganizationsQuery, OrganizationType } from '@/graphql'; diff --git a/packages/web/app/src/components/v2/toggle-group.tsx b/packages/web/app/src/components/v2/toggle-group.tsx index c01fbf277..451ea20a0 100644 --- a/packages/web/app/src/components/v2/toggle-group.tsx +++ b/packages/web/app/src/components/v2/toggle-group.tsx @@ -1,5 +1,5 @@ import { ForwardRefExoticComponent } from 'react'; -import { Root, Item } from '@radix-ui/react-toggle-group'; +import { Item, Root } from '@radix-ui/react-toggle-group'; import clsx from 'clsx'; type PropsOf = T extends ForwardRefExoticComponent ? P : unknown; diff --git a/packages/web/docs/package.json b/packages/web/docs/package.json index 19df216b3..2a5441862 100644 --- a/packages/web/docs/package.json +++ b/packages/web/docs/package.json @@ -1,7 +1,7 @@ { "name": "@hive/docs", "private": true, - "version": "0.0.1", + "version": "0.0.0", "scripts": { "dev": "next dev", "start": "next start", diff --git a/packages/web/landing-page/package.json b/packages/web/landing-page/package.json index aea7e76b3..9dfc8c118 100644 --- a/packages/web/landing-page/package.json +++ b/packages/web/landing-page/package.json @@ -1,7 +1,7 @@ { "name": "@hive/landing-page", "private": true, - "version": "0.1.20", + "version": "0.0.0", "scripts": { "dev": "next dev", "build": "bob runify --single" diff --git a/rules/enforce-deps-in-dev.cjs b/rules/enforce-deps-in-dev.cjs new file mode 100644 index 000000000..cc52a4e19 --- /dev/null +++ b/rules/enforce-deps-in-dev.cjs @@ -0,0 +1,227 @@ +/** + * Why? Few reasons: + * - tsup treats dependencies as external code and does not bundle them + * - without dependencies turborepo will always serve stale code when some of dependencies changed + * + * Moving internal dependencies to devDependencies makes tsup treat them as non-external and turborepo still keep tracks of relations + */ + +/// @ts-check +const path = require('path'); +const fs = require('fs'); +const minimatch = require('minimatch'); +const readPkgUp = require('eslint-module-utils/readPkgUp').default; +const moduleVisitor = require('eslint-module-utils/moduleVisitor').default; + +function isHivePackage(packageName, scopes) { + return typeof packageName === 'string' && scopes.some(scope => packageName.startsWith(`${scope}/`)); +} + +const depFieldCache = new Map(); + +function hasKeys(obj = {}) { + return Object.keys(obj).length > 0; +} + +function extractDepFields(pkg) { + return { + name: pkg.name, + dependencies: pkg.dependencies || {}, + devDependencies: pkg.devDependencies || {}, + optionalDependencies: pkg.optionalDependencies || {}, + peerDependencies: pkg.peerDependencies || {}, + }; +} + +function getDependencies(context, packageDir) { + let paths = []; + try { + const packageContent = { + name: '', + dependencies: {}, + devDependencies: {}, + optionalDependencies: {}, + peerDependencies: {}, + }; + + if (packageDir && packageDir.length > 0) { + if (!Array.isArray(packageDir)) { + paths = [path.resolve(packageDir)]; + } else { + paths = packageDir.map(dir => path.resolve(dir)); + } + } + + if (paths.length > 0) { + // use rule config to find package.json + paths.forEach(dir => { + const packageJsonPath = path.join(dir, 'package.json'); + if (!depFieldCache.has(packageJsonPath)) { + const depFields = extractDepFields(JSON.parse(fs.readFileSync(packageJsonPath, 'utf8'))); + depFieldCache.set(packageJsonPath, depFields); + } + const _packageContent = depFieldCache.get(packageJsonPath); + Object.keys(packageContent).forEach(depsKey => + Object.assign(packageContent[depsKey], _packageContent[depsKey]) + ); + }); + } else { + // use closest package.json + Object.assign( + packageContent, + extractDepFields( + readPkgUp({ + cwd: context.getPhysicalFilename ? context.getPhysicalFilename() : context.getFilename(), + normalize: false, + }).pkg + ) + ); + } + + if ( + ![ + packageContent.dependencies, + packageContent.devDependencies, + packageContent.optionalDependencies, + packageContent.peerDependencies, + ].some(hasKeys) + ) { + return null; + } + + return packageContent; + } catch (e) { + if (paths.length > 0 && e.code === 'ENOENT') { + context.report({ + message: 'The package.json file could not be found.', + loc: { line: 0, column: 0 }, + }); + } + if (e.name === 'JSONError' || e instanceof SyntaxError) { + context.report({ + message: 'The package.json file could not be parsed: ' + e.message, + loc: { line: 0, column: 0 }, + }); + } + + return null; + } +} + +function missingErrorMessage(packageName) { + return `'${packageName}' should be listed in the project's devDependencies. `; +} + +function directDepErrorMessage(packageName) { + return `'${packageName}' should be listed in the project's devDependencies, not dependencies.`; +} + +function optDepErrorMessage(packageName) { + return `'${packageName}' should be listed in the project's devDependencies, not optionalDependencies`; +} + +function peerDepErrorMessage(packageName) { + return `'${packageName}' should be listed in the project's devDependencies, not peerDependencies`; +} + +function getModuleOriginalName(name) { + const [first, second] = name.split('/'); + return first.startsWith('@') ? `${first}/${second}` : first; +} + +function checkDependencyDeclaration(deps, packageName, declarationStatus) { + const newDeclarationStatus = declarationStatus || { + isInDeps: false, + isInDevDeps: false, + isInOptDeps: false, + isInPeerDeps: false, + }; + + // in case of sub package.json inside a module + // check the dependencies on all hierarchy + const packageHierarchy = []; + const packageNameParts = packageName ? packageName.split('/') : []; + packageNameParts.forEach((namePart, index) => { + if (!namePart.startsWith('@')) { + const ancestor = packageNameParts.slice(0, index + 1).join('/'); + packageHierarchy.push(ancestor); + } + }); + + return packageHierarchy.reduce((result, ancestorName) => { + return { + isInDeps: result.isInDeps || deps.dependencies[ancestorName] !== undefined, + isInDevDeps: result.isInDevDeps || deps.devDependencies[ancestorName] !== undefined, + isInOptDeps: result.isInOptDeps || deps.optionalDependencies[ancestorName] !== undefined, + isInPeerDeps: result.isInPeerDeps || deps.peerDependencies[ancestorName] !== undefined, + }; + }, newDeclarationStatus); +} + +function reportIfMissing(context, deps, node, name, scopes) { + if (node.importKind === 'type' || node.importKind === 'typeof') { + return; + } + + if (!isHivePackage(name, scopes)) { + return; + } + + const importPackageName = getModuleOriginalName(name); + let declarationStatus = checkDependencyDeclaration(deps, importPackageName); + + if (declarationStatus.isInDevDeps) { + return; + } + + if (declarationStatus.isInDeps) { + context.report(node, directDepErrorMessage(importPackageName)); + return; + } + + if (declarationStatus.isInOptDeps) { + context.report(node, optDepErrorMessage(importPackageName)); + return; + } + + if (declarationStatus.isInPeerDeps) { + context.report(node, peerDepErrorMessage(importPackageName)); + return; + } + + context.report(node, missingErrorMessage(importPackageName)); +} + +module.exports = { + meta: { + type: 'problem', + }, + + create(context) { + const options = context.options[0] || {}; + const deps = getDependencies(context, options.packageDir) || extractDepFields({}); + + if (Array.isArray(options.ignored)) { + const filepath = context.getPhysicalFilename ? context.getPhysicalFilename() : context.getFilename(); + + if ( + options.ignored.some( + ignored => minimatch(filepath, ignored) || minimatch(filepath, path.join(process.cwd(), ignored)) + ) + ) { + return {}; + } + } + + if (!Array.isArray(options.scopes)) { + throw new Error('[hive/enforce-deps-in-dev] The scopes option must be an array.'); + } + + return moduleVisitor( + (source, node) => { + reportIfMissing(context, deps, node, source.value, options.scopes); + }, + { commonjs: true } + ); + }, +}; diff --git a/rules/index.cjs b/rules/index.cjs new file mode 100644 index 000000000..2f7b267e2 --- /dev/null +++ b/rules/index.cjs @@ -0,0 +1,5 @@ +module.exports = { + rules: { + 'enforce-deps-in-dev': require('./enforce-deps-in-dev.cjs'), + }, +}; diff --git a/rules/package.json b/rules/package.json new file mode 100644 index 000000000..744e89af3 --- /dev/null +++ b/rules/package.json @@ -0,0 +1,7 @@ +{ + "private": true, + "name": "eslint-plugin-hive", + "main": "index.cjs", + "type": "commonjs", + "version": "0.0.0" +} diff --git a/yarn.lock b/yarn.lock index a3ae36ce0..72a47905e 100644 --- a/yarn.lock +++ b/yarn.lock @@ -8236,6 +8236,9 @@ eslint-module-utils@^2.7.3: debug "^3.2.7" find-up "^2.1.0" +"eslint-plugin-hive@file:./rules": + version "0.0.0" + eslint-plugin-import@2.26.0: version "2.26.0" resolved "https://registry.yarnpkg.com/eslint-plugin-import/-/eslint-plugin-import-2.26.0.tgz#f812dc47be4f2b72b478a021605a59fc6fe8b88b"