diff --git a/.eslintrc.js b/.eslintrc.js index 4ef0585b7674..f236d21a44f2 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -61,12 +61,6 @@ module.exports = { files: ['package.json'], parser: 'jsonc-eslint-parser', }, - { - files: ['package.json'], - rules: { - '@react-native/monorepo/react-native-manifest': 'error', - }, - }, { files: ['flow-typed/**/*.js', 'packages/react-native/flow/**/*'], rules: { diff --git a/.github/workflow-scripts/lint_files.sh b/.github/workflow-scripts/lint_files.sh deleted file mode 100755 index 9563d7dafb57..000000000000 --- a/.github/workflow-scripts/lint_files.sh +++ /dev/null @@ -1,12 +0,0 @@ -#!/bin/bash -# Copyright (c) Meta Platforms, Inc. and affiliates. -# -# This source code is licensed under the MIT license found in the -# LICENSE file in the root directory of this source tree. - -set -e - -if git ls-files | grep -E '\.npmignore$'; then - echo "Error: Found unexpected .npmignore file(s). Please use package.json#files instead." - exit 1 -fi diff --git a/.github/workflows/test-all.yml b/.github/workflows/test-all.yml index 1f49896cbf36..ef4e0a50029f 100644 --- a/.github/workflows/test-all.yml +++ b/.github/workflows/test-all.yml @@ -453,9 +453,6 @@ jobs: uses: ./.github/actions/setup-node - name: Install dependencies uses: ./.github/actions/yarn-install - - name: Lint file structure - shell: bash - run: ./.github/workflow-scripts/lint_files.sh - name: Run shellcheck shell: bash run: ./.github/workflow-scripts/analyze_scripts.sh diff --git a/private/eslint-plugin-monorepo/index.js b/private/eslint-plugin-monorepo/index.js index 6b34791bc03b..7ad4b026eb82 100644 --- a/private/eslint-plugin-monorepo/index.js +++ b/private/eslint-plugin-monorepo/index.js @@ -15,7 +15,6 @@ exports.rules = { 'no-react-named-type-imports': require('./rules/no-react-named-type-imports'), 'no-react-native-imports': require('./rules/no-react-native-imports'), 'no-react-node-imports': require('./rules/no-react-node-imports'), - 'react-native-manifest': require('./rules/react-native-manifest'), 'require-extends-error': require('./rules/require-extends-error'), 'sort-imports': require('./rules/sort-imports'), 'valid-flow-typed-signature': require('./rules/valid-flow-typed-signature'), diff --git a/private/eslint-plugin-monorepo/rules/__tests__/react-native-manifest-test.js b/private/eslint-plugin-monorepo/rules/__tests__/react-native-manifest-test.js deleted file mode 100644 index c0ec67da127b..000000000000 --- a/private/eslint-plugin-monorepo/rules/__tests__/react-native-manifest-test.js +++ /dev/null @@ -1,92 +0,0 @@ -/** - * Copyright (c) Meta Platforms, Inc. and affiliates. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - * - * @format - * @noflow - */ - -'use strict'; - -const rule = require('../react-native-manifest.js'); -const {RuleTester} = require('eslint'); - -const ruleTester = new RuleTester({ - parser: require.resolve('jsonc-eslint-parser'), -}); - -ruleTester.run('react-native-manifest', rule, { - valid: [ - { - code: JSON.stringify({ - name: '@react-native/package-name', - }), - }, - { - code: JSON.stringify({ - name: '@react-native/package-name', - dependencies: { - dependencyA: '1.0.0', - }, - devDependencies: { - dependencyB: '1.0.0', - }, - }), - }, - { - code: JSON.stringify({ - name: '@react-native/monorepo', - devDependencies: { - dependencyB: '1.0.0', - }, - }), - }, - { - code: JSON.stringify({ - name: 'react-native', - dependencies: { - dependencyA: '1.0.0', - }, - }), - }, - ], - invalid: [ - { - code: JSON.stringify({ - name: '@react-native/monorepo', - dependencies: { - dependencyA: '1.0.0', - }, - }), - errors: [ - { - messageId: 'propertyDisallowed', - data: { - property: 'dependencies', - describe: - "Declare 'dependencies' in `packages/react-native/package.json`.", - }, - }, - ], - }, - { - code: JSON.stringify({ - name: 'react-native', - devDependencies: { - dependencyA: '1.0.0', - }, - }), - errors: [ - { - messageId: 'propertyDisallowed', - data: { - property: 'devDependencies', - describe: "Declare 'devDependencies' in `/package.json`.", - }, - }, - ], - }, - ], -}); diff --git a/private/eslint-plugin-monorepo/rules/react-native-manifest.js b/private/eslint-plugin-monorepo/rules/react-native-manifest.js deleted file mode 100644 index ff073946ac17..000000000000 --- a/private/eslint-plugin-monorepo/rules/react-native-manifest.js +++ /dev/null @@ -1,85 +0,0 @@ -/** - * Copyright (c) Meta Platforms, Inc. and affiliates. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - * - * @format - * @noflow - */ - -'use strict'; - -/** - * React Native's monorepo requires that "devDependencies" be declared at the - * root package.json and "dependencies" in the `react-native` package.json to - * permit the ability to segment dependent workspaces into 1) a development - * workspace root (which depends on the monorepo) and 2) a production workspace - * (which depends on the `react-native` package). - */ -const PACKAGE_CONSTRAINTS = { - '@react-native/monorepo': { - disallowed: [ - { - property: 'dependencies', - describe: - "Declare 'dependencies' in `packages/react-native/package.json`.", - }, - ], - }, - 'react-native': { - disallowed: [ - { - property: 'devDependencies', - describe: "Declare 'devDependencies' in `/package.json`.", - }, - ], - }, -}; - -module.exports = { - meta: { - type: 'problem', - docs: { - description: 'Enforce react-native manifest constraints', - }, - messages: { - propertyDisallowed: - "'{{property}}' is disallowed in this file. {{describe}}", - }, - schema: [], - }, - - create(context) { - // @see https://www.npmjs.com/package/jsonc-eslint-parser - if (!context.parserServices.isJSON) { - return {}; - } - return { - 'JSONExpressionStatement > JSONObjectExpression'(node) { - const propertyNodes = {}; - for (const propertyNode of node.properties) { - propertyNodes[propertyNode.key.value] = propertyNode; - } - - const name = propertyNodes.name?.value?.value; - const constraints = PACKAGE_CONSTRAINTS[name]; - if (constraints == null) { - return; - } - - for (const {property, describe} of constraints.disallowed) { - const propertyNode = propertyNodes[property]; - if (propertyNode == null) { - continue; - } - context.report({ - node: propertyNode, - messageId: 'propertyDisallowed', - data: {property, describe}, - }); - } - }, - }; - }, -}; diff --git a/private/monorepo-tests/__tests__/no-dependencies-in-root-package-test.js b/private/monorepo-tests/__tests__/no-dependencies-in-root-package-test.js deleted file mode 100644 index 9bc646c0dbbe..000000000000 --- a/private/monorepo-tests/__tests__/no-dependencies-in-root-package-test.js +++ /dev/null @@ -1,31 +0,0 @@ -/** - * Copyright (c) Meta Platforms, Inc. and affiliates. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - * - * @flow strict-local - * @format - */ - -import fs from 'fs'; -import path from 'path'; - -const CURRENT_DIR = __dirname; -const PATH_TO_ROOT_PACKAGE_MANIFEST = path.join( - CURRENT_DIR, - '..', - '..', - '..', - 'package.json', -); - -const manifest = JSON.parse( - fs.readFileSync(PATH_TO_ROOT_PACKAGE_MANIFEST).toString(), -); - -describe('@react-native/monorepo root package', () => { - it('expected not to list any dependencies', () => { - expect(manifest).not.toHaveProperty('dependencies'); - }); -}); diff --git a/private/monorepo-tests/__tests__/no-dev-dependencies-in-react-native-package-test.js b/private/monorepo-tests/__tests__/no-dev-dependencies-in-react-native-package-test.js deleted file mode 100644 index 0ce252a19469..000000000000 --- a/private/monorepo-tests/__tests__/no-dev-dependencies-in-react-native-package-test.js +++ /dev/null @@ -1,33 +0,0 @@ -/** - * Copyright (c) Meta Platforms, Inc. and affiliates. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - * - * @flow strict-local - * @format - */ - -import fs from 'fs'; -import path from 'path'; - -const CURRENT_DIR = __dirname; -const PATH_TO_REACT_NATIVE_PACKAGE_MANIFEST = path.join( - CURRENT_DIR, - '..', - '..', - '..', - 'packages', - 'react-native', - 'package.json', -); - -const manifest = JSON.parse( - fs.readFileSync(PATH_TO_REACT_NATIVE_PACKAGE_MANIFEST).toString(), -); - -describe('react-native package', () => { - it('expected not to list any devDependencies', () => { - expect(manifest).not.toHaveProperty('devDependencies'); - }); -}); diff --git a/private/monorepo-tests/__tests__/no-dev-dependencies-in-tester-package.js b/private/monorepo-tests/__tests__/no-dev-dependencies-in-tester-package.js deleted file mode 100644 index 3a3e48430c13..000000000000 --- a/private/monorepo-tests/__tests__/no-dev-dependencies-in-tester-package.js +++ /dev/null @@ -1,33 +0,0 @@ -/** - * Copyright (c) Meta Platforms, Inc. and affiliates. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - * - * @flow strict-local - * @format - */ - -import fs from 'fs'; -import path from 'path'; - -const CURRENT_DIR = __dirname; -const PATH_TO_TESTER_PACKAGE_MANIFEST = path.join( - CURRENT_DIR, - '..', - '..', - '..', - 'packages', - 'rn-tester', - 'package.json', -); - -const manifest = JSON.parse( - fs.readFileSync(PATH_TO_TESTER_PACKAGE_MANIFEST).toString(), -); - -describe('@react-native/tester package', () => { - it('expected not to list any devDependencies', () => { - expect(manifest).not.toHaveProperty('devDependencies'); - }); -}); diff --git a/private/monorepo-tests/package.json b/private/monorepo-tests/package.json deleted file mode 100644 index 10725c529541..000000000000 --- a/private/monorepo-tests/package.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "name": "@react-native/monorepo-tests", - "private": true, - "version": "0.0.0" -} diff --git a/scripts/monorepo-tests/__tests__/check-packages-test.js b/scripts/monorepo-tests/__tests__/check-packages-test.js new file mode 100644 index 000000000000..3fc0611203a1 --- /dev/null +++ b/scripts/monorepo-tests/__tests__/check-packages-test.js @@ -0,0 +1,42 @@ +/** + * Copyright (c) Meta Platforms, Inc. and affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + * + * @flow strict-local + * @format + */ + +import {REPO_ROOT} from '../../shared/consts'; +import { + getReactNativePackage, + getWorkspaceRoot, +} from '../../shared/monorepoUtils'; +import {globSync} from 'tinyglobby'; + +describe('package manifests', () => { + test('the workspace root must not declare runtime dependencies', async () => { + const {packageJson} = await getWorkspaceRoot(); + expect(packageJson).not.toHaveProperty('dependencies'); + }); + + test('the react-native package must not declare devDependencies', async () => { + const {packageJson} = await getReactNativePackage(); + expect(packageJson).not.toHaveProperty('devDependencies'); + }); +}); + +describe('package file structure', () => { + test('packages must not contain .npmignore files', () => { + // Publishing must be controlled via the package.json "files" field, which is + // easier to audit and does not silently expand what gets shipped to npm. + const npmignoreFiles = globSync('{packages,private}/**/.npmignore', { + cwd: REPO_ROOT, + dot: true, + ignore: ['**/node_modules/**'], + }); + + expect(npmignoreFiles).toEqual([]); + }); +});