chore(repo): migrate to conformance v3 (#31475)

This commit is contained in:
James Henry 2025-06-20 01:37:16 +04:00 committed by GitHub
parent ec457f72df
commit 4c7586c82d
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
21 changed files with 214 additions and 207 deletions

View File

@ -69,6 +69,15 @@
"originalFilePath": "/libs/nx-packages/conformance/src/generators/create-rule/schema.json", "originalFilePath": "/libs/nx-packages/conformance/src/generators/create-rule/schema.json",
"path": "conformance/generators/create-rule", "path": "conformance/generators/create-rule",
"type": "generator" "type": "generator"
},
{
"description": "Nx workspace preset which includes a working conformance rule",
"file": "external-generated/packages/conformance/generators/preset.json",
"hidden": false,
"name": "preset",
"originalFilePath": "/libs/nx-packages/conformance/src/generators/preset/schema.json",
"path": "conformance/generators/preset",
"type": "generator"
} }
], ],
"migrations": [], "migrations": [],

View File

@ -3,6 +3,8 @@ title: Overview of the Nx Azure Cache Plugin
description: The @nx/azure-cache plugin enables you to use Azure Storage to host your remote cache for efficient build caching across your team. description: The @nx/azure-cache plugin enables you to use Azure Storage to host your remote cache for efficient build caching across your team.
--- ---
# @nx/azure-cache
The `@nx/azure-cache` plugin enables you to self-host your remote cache on [Azure Storage](https://azure.microsoft.com/en-us/products/storage/blobs). The `@nx/azure-cache` plugin enables you to self-host your remote cache on [Azure Storage](https://azure.microsoft.com/en-us/products/storage/blobs).
{% callout type="deepdive" title="Free managed remote cache with Nx Cloud" %} {% callout type="deepdive" title="Free managed remote cache with Nx Cloud" %}
@ -15,9 +17,9 @@ If you are an enterprise and **data privacy and security is a concern**, [reach
{% /callout %} {% /callout %}
{% callout type="info" title="Self-hosted caching is now free" %} {% callout type="warning" title="Bucket-based caches are vulnerable to poisoning and often prohibited in organizations" %}
Self-hosted caching is **now free for everyone** to use. CREEP (CVE-2025-36852) is a critical vulnerability in bucket-based self-hosted remote caches. It lets attackers with PR access poison production builds via a race condition during artifact creation—before security checks can catch it. [Learn more](/blog/cve-2025-36852-critical-cache-poisoning-vulnerability-creep)
{% /callout %} {% /callout %}

View File

@ -17,7 +17,6 @@ To write your own conformance rule, run the `@nx/conformance:create-rule` genera
✔ What is the name of the rule? · local-conformance-rule-example ✔ What is the name of the rule? · local-conformance-rule-example
✔ Which directory do you want to create the rule directory in? · packages/my-plugin/local-conformance-rule ✔ Which directory do you want to create the rule directory in? · packages/my-plugin/local-conformance-rule
✔ What category does this rule belong to? · security ✔ What category does this rule belong to? · security
✔ What reporter do you want to use for this rule? · project-reporter
✔ What is the description of the rule? · an example of a conformance rule ✔ What is the description of the rule? · an example of a conformance rule
CREATE packages/my-plugin/local-conformance-rule/local-conformance-rule-example/index.ts CREATE packages/my-plugin/local-conformance-rule/local-conformance-rule-example/index.ts
CREATE packages/my-plugin/local-conformance-rule/local-conformance-rule-example/schema.json CREATE packages/my-plugin/local-conformance-rule/local-conformance-rule-example/schema.json
@ -26,15 +25,14 @@ CREATE packages/my-plugin/local-conformance-rule/local-conformance-rule-example/
The generated rule definition file should look like this: The generated rule definition file should look like this:
```ts {% fileName="packages/my-plugin/local-conformance-rule/index.ts" %} ```ts {% fileName="packages/my-plugin/local-conformance-rule/index.ts" %}
import { createConformanceRule, ProjectViolation } from '@nx/conformance'; import { createConformanceRule, ConformanceViolation } from '@nx/conformance';
export default createConformanceRule({ export default createConformanceRule({
name: 'local-conformance-rule-example', name: 'local-conformance-rule-example',
category: 'security', category: 'security',
description: 'an example of a conformance rule', description: 'an example of a conformance rule',
reporter: 'project-reporter',
implementation: async (context) => { implementation: async (context) => {
const violations: ProjectViolation[] = []; const violations: ConformanceViolation[] = [];
return { return {
severity: 'low', severity: 'low',
@ -64,28 +62,27 @@ Note that the severity of the error is defined by the rule author and can be adj
## Conformance Rule Examples ## Conformance Rule Examples
There are three types of reporters that a rule can use. Rules should report on the most specific thing that is in violation of the rule. They can report on one or more of the following things within a workspace:
- `project-reporter` - The rule evaluates an entire project at a time. - file - The rule reports on a particular file being in violation of the rule.
- `project-files-reporter` - The rule evaluates a single project file at a time. - project - The rule reports on a particular project being in violation of the rule, because no one file within it would be applicable to flag up.
- `non-project-files-reporter` - The rule evaluates files that don't belong to any project. - the workspace itself - Sometimes there is no specific file or project that is most applicable to flag up, so the rule can report on the workspace itself.
{% tabs %} {% tabs %}
{% tab label="project-reporter" %} {% tab label="project violation" %}
The `@nx/conformance:ensure-owners` rule provides us an example of how to write a `project-reporter` rule. The `@nx/owners` plugin adds an `owners` metadata property to every project node that has an owner in the project graph. This rule checks each project node metadata to make sure that each project has some owner defined. The `@nx/conformance:ensure-owners` rule provides us an example of how to write a rule that reports on a project being in violation of the rule. The `@nx/owners` plugin adds an `owners` metadata property to every project node that has an owner in the project graph. This rule checks each project node metadata to make sure that each project has some owner defined.
```ts ```ts
import { ProjectGraphProjectNode } from '@nx/devkit'; import { ProjectGraphProjectNode } from '@nx/devkit';
import { createConformanceRule, ProjectViolation } from '@nx/conformance'; import { createConformanceRule, ConformanceViolation } from '@nx/conformance';
export default createConformanceRule({ export default createConformanceRule({
name: 'ensure-owners', name: 'ensure-owners',
category: 'consistency', category: 'consistency',
description: 'Ensure that all projects have owners defined via Nx Owners.', description: 'Ensure that all projects have owners defined via Nx Owners.',
reporter: 'project-reporter',
implementation: async (context) => { implementation: async (context) => {
const violations: ProjectViolation[] = []; const violations: ConformanceViolation[] = [];
for (const node of Object.values( for (const node of Object.values(
context.projectGraph.nodes context.projectGraph.nodes
@ -110,12 +107,12 @@ export default createConformanceRule({
``` ```
{% /tab %} {% /tab %}
{% tab label="project-files-reporter" %} {% tab label="file violation" %}
This rule uses TypeScript AST processing to ensure that `index.ts` files use a client-side style of export syntax and `server.ts` files use a server-side style of export syntax. This rule uses TypeScript AST processing to ensure that `index.ts` files use a client-side style of export syntax and `server.ts` files use a server-side style of export syntax.
```ts ```ts
import { createConformanceRule, ProjectFilesViolation } from '@nx/conformance'; import { createConformanceRule, ConformanceViolation } from '@nx/conformance';
import { existsSync, readFileSync } from 'node:fs'; import { existsSync, readFileSync } from 'node:fs';
import { join } from 'node:path'; import { join } from 'node:path';
import { import {
@ -131,9 +128,8 @@ export default createConformanceRule({
name: 'server-client-public-api', name: 'server-client-public-api',
category: 'consistency', category: 'consistency',
description: 'Ensure server-only and client-only public APIs are not mixed', description: 'Ensure server-only and client-only public APIs are not mixed',
reporter: 'project-files-reporter',
implementation: async ({ projectGraph }) => { implementation: async ({ projectGraph }) => {
const violations: ProjectFilesViolation[] = []; const violations: ConformanceViolation[] = [];
for (const nodeId in projectGraph.nodes) { for (const nodeId in projectGraph.nodes) {
const node = projectGraph.nodes[nodeId]; const node = projectGraph.nodes[nodeId];
@ -171,7 +167,7 @@ export function processEntryPoint(
project: string, project: string,
style: 'server' | 'client' style: 'server' | 'client'
) { ) {
const violations: ProjectFilesViolation[] = []; const violations: ConformanceViolation[] = [];
const sf = createSourceFile( const sf = createSourceFile(
entryPoint, entryPoint,
@ -246,42 +242,30 @@ function isModuleSpecifierViolated(
``` ```
{% /tab %} {% /tab %}
{% tab label="non-project-files-reporter" %} {% tab label="workspace violation" %}
This rule checks the root `package.json` file and ensures that if the `tmp` package is included as a dependency, it has a minimum version of 0.2.3. This rule checks to see if there is a root README.md file in the workspace, and if there is not, it reports on the workspace itself.
```ts ```ts
import { readJsonFile, workspaceRoot } from '@nx/devkit'; import { workspaceRoot } from '@nx/devkit';
import { import { createConformanceRule, ConformanceViolation } from '@nx/conformance';
createConformanceRule,
NonProjectFilesViolation,
} from '@nx/conformance';
import { join } from 'node:path'; import { join } from 'node:path';
import { satisfies } from 'semver'; import { existsSync } from 'node:fs';
export default createConformanceRule<object>({ export default createConformanceRule<object>({
name: 'package-tmp-0.2.3', name: 'readme-file',
category: 'maintainability', category: 'maintainability',
description: 'The tmp dependency should be a minimum version of 0.2.3', description: 'The workspace should have a root README.md file',
reporter: 'non-project-files-reporter',
implementation: async () => { implementation: async () => {
const violations: NonProjectFilesViolation[] = []; const violations: ConformanceViolation[] = [];
const applyViolationIfApplicable = (version: string | undefined) => {
if (version && !satisfies(version, '>=0.2.3')) { const readmePath = join(workspaceRoot, 'README.md');
if (!existsSync(readmePath)) {
violations.push({ violations.push({
message: 'The "tmp" package must be version "0.2.3" or higher', message: 'The workspace should have a root README.md file',
file: 'package.json', workspaceViolation: true,
}); });
} }
};
const workspaceRootPackageJson = await readJsonFile(
join(workspaceRoot, 'package.json')
);
applyViolationIfApplicable(workspaceRootPackageJson.dependencies?.['tmp']);
applyViolationIfApplicable(
workspaceRootPackageJson.devDependencies?.['tmp']
);
return { return {
severity: 'low', severity: 'low',

View File

@ -3,6 +3,8 @@ title: Overview of the Nx powerpack-conformance Plugin
description: The Nx Powerpack Conformance plugin provides the ability to write and apply rules for your workspace description: The Nx Powerpack Conformance plugin provides the ability to write and apply rules for your workspace
--- ---
# @nx/conformance
The `@nx/conformance` plugin allows [Nx Powerpack](/powerpack) users to write and apply rules for your entire workspace that help with **consistency**, **maintainability**, **reliability** and **security**. The `@nx/conformance` plugin allows [Nx Powerpack](/powerpack) users to write and apply rules for your entire workspace that help with **consistency**, **maintainability**, **reliability** and **security**.
The conformance plugin allows you to encode your own organization's standards so that they can be enforced automatically. Conformance rules can also complement linting tools by enforcing that those tools are configured in the recommended way. The rules are written in TypeScript but can be applied to any language in the codebase or focus entirely on configuration files. The conformance plugin allows you to encode your own organization's standards so that they can be enforced automatically. Conformance rules can also complement linting tools by enforcing that those tools are configured in the recommended way. The rules are written in TypeScript but can be applied to any language in the codebase or focus entirely on configuration files.

View File

@ -28,17 +28,6 @@
"x-prompt": "What category does this rule belong to?", "x-prompt": "What category does this rule belong to?",
"x-priority": "important" "x-priority": "important"
}, },
"reporter": {
"type": "string",
"enum": [
"project-reporter",
"project-files-reporter",
"non-project-files-reporter"
],
"description": "The reporter of the rule.",
"x-prompt": "What reporter do you want to use for this rule?",
"x-priority": "important"
},
"description": { "description": {
"type": "string", "type": "string",
"description": "The description of the rule.", "description": "The description of the rule.",
@ -47,7 +36,7 @@
} }
}, },
"additionalProperties": false, "additionalProperties": false,
"required": ["name", "directory", "category", "reporter"], "required": ["name", "directory", "category"],
"presets": [] "presets": []
}, },
"description": "Create a new conformance rule", "description": "Create a new conformance rule",

View File

@ -0,0 +1,19 @@
{
"name": "preset",
"factory": "./src/generators/preset/preset",
"schema": {
"$schema": "http://json-schema.org/schema",
"id": "NxPowerpackConformancePreset",
"title": "Nx workspace preset which includes a working conformance rule",
"type": "object",
"properties": {},
"required": [],
"presets": []
},
"description": "Nx workspace preset which includes a working conformance rule",
"implementation": "/libs/nx-packages/conformance/src/generators/preset/preset.ts",
"aliases": [],
"hidden": false,
"path": "/libs/nx-packages/conformance/src/generators/preset/schema.json",
"type": "generator"
}

View File

@ -3,6 +3,8 @@ title: Overview of the Nx GCS Cache Plugin
description: The @nx/gcs-cache plugin enables you to use Google Cloud Storage to host your remote cache for efficient build caching across your team. description: The @nx/gcs-cache plugin enables you to use Google Cloud Storage to host your remote cache for efficient build caching across your team.
--- ---
# @nx/gcs-cache
The `@nx/gcs-cache` plugin enables you to self-host your remote cache on [Google Cloud Storage](https://cloud.google.com/storage). The `@nx/gcs-cache` plugin enables you to self-host your remote cache on [Google Cloud Storage](https://cloud.google.com/storage).
{% callout type="deepdive" title="Free managed remote cache with Nx Cloud" %} {% callout type="deepdive" title="Free managed remote cache with Nx Cloud" %}
@ -15,9 +17,9 @@ If you are an enterprise and **data privacy and security is a concern**, [reach
{% /callout %} {% /callout %}
{% callout type="info" title="Self-hosted caching is now free" %} {% callout type="warning" title="Bucket-based caches are vulnerable to poisoning and often prohibited in organizations" %}
Self-hosted caching is **now free for everyone** to use. CREEP (CVE-2025-36852) is a critical vulnerability in bucket-based self-hosted remote caches. It lets attackers with PR access poison production builds via a race condition during artifact creation—before security checks can catch it. [Learn more](/blog/cve-2025-36852-critical-cache-poisoning-vulnerability-creep)
{% /callout %} {% /callout %}

View File

@ -3,6 +3,8 @@ title: Overview of the Nx powerpack-owners Plugin
description: The Nx Powerpack Owners plugin provides the ability to define code ownership based on projects in addition to files description: The Nx Powerpack Owners plugin provides the ability to define code ownership based on projects in addition to files
--- ---
# @nx/owners
The `@nx/owners` plugin extends the CODEOWNERS functionality to allow you to define code ownership based on projects in addition to the standard file-based definitions. It leverages the [`nx sync`](/concepts/sync-generators) command to compile `owners` configuration settings from `nx.json` and project configuration files into valid CODEOWNERS files for [GitHub](https://docs.github.com/en/repositories/managing-your-repositorys-settings-and-features/customizing-your-repository/about-code-owners), [Bitbucket](https://support.atlassian.com/bitbucket-cloud/docs/set-up-and-use-code-owners/) or [GitLab](https://docs.gitlab.com/ee/user/project/codeowners/). The `@nx/owners` plugin extends the CODEOWNERS functionality to allow you to define code ownership based on projects in addition to the standard file-based definitions. It leverages the [`nx sync`](/concepts/sync-generators) command to compile `owners` configuration settings from `nx.json` and project configuration files into valid CODEOWNERS files for [GitHub](https://docs.github.com/en/repositories/managing-your-repositorys-settings-and-features/customizing-your-repository/about-code-owners), [Bitbucket](https://support.atlassian.com/bitbucket-cloud/docs/set-up-and-use-code-owners/) or [GitLab](https://docs.gitlab.com/ee/user/project/codeowners/).
With this plugin, you can specify code ownership using the same project matcher syntax as [`nx run-many`](/reference/core-api/nx/documents/run-many#examples). This allows you to easily define rules for multiple projects that may not be located in the same directory. Also, the CODEOWNERS rules will not need to be revisited if a project location is changed or a new project is added. With this plugin, you can specify code ownership using the same project matcher syntax as [`nx run-many`](/reference/core-api/nx/documents/run-many#examples). This allows you to easily define rules for multiple projects that may not be located in the same directory. Also, the CODEOWNERS rules will not need to be revisited if a project location is changed or a new project is added.

View File

@ -3,6 +3,8 @@ title: Overview of the Nx S3 Cache Plugin
description: The @nx/s3-cache plugin enables you to use an Amazon S3 bucket to host your remote cache for efficient build caching across your team. description: The @nx/s3-cache plugin enables you to use an Amazon S3 bucket to host your remote cache for efficient build caching across your team.
--- ---
# @nx/s3-cache
The `@nx/s3-cache` plugin enables you to self-host your remote cache on an [Amazon S3](https://aws.amazon.com/s3) bucket. The `@nx/s3-cache` plugin enables you to self-host your remote cache on an [Amazon S3](https://aws.amazon.com/s3) bucket.
{% callout type="deepdive" title="Free managed remote cache with Nx Cloud" %} {% callout type="deepdive" title="Free managed remote cache with Nx Cloud" %}
@ -14,9 +16,9 @@ If you are an enterprise and **data privacy and security is a concern**, [reach
**Are you an OSS project?** Nx Cloud is free for OSS. [Reach out here](/pricing#oss). **Are you an OSS project?** Nx Cloud is free for OSS. [Reach out here](/pricing#oss).
{% /callout %} {% /callout %}
{% callout type="info" title="Self-hosted caching is now free" %} {% callout type="warning" title="Bucket-based caches are vulnerable to poisoning and often prohibited in organizations" %}
Self-hosted caching is **now free for everyone** to use. CREEP (CVE-2025-36852) is a critical vulnerability in bucket-based self-hosted remote caches. It lets attackers with PR access poison production builds via a race condition during artifact creation—before security checks can catch it. [Learn more](/blog/cve-2025-36852-critical-cache-poisoning-vulnerability-creep)
{% /callout %} {% /callout %}

View File

@ -3,11 +3,9 @@ title: Overview of the Nx Shared File System Cache Plugin
description: The @nx/shared-fs-cache plugin enables you to use a shared file system directory to host your remote cache for efficient build caching across your team. description: The @nx/shared-fs-cache plugin enables you to use a shared file system directory to host your remote cache for efficient build caching across your team.
--- ---
The `@nx/shared-fs-cache` plugin enables you to host your remote cache on a shared file system directory. While you're responsible for implementing the actual directory sharing mechanism, the plugin configures Nx to read from both your local cache and the shared directory. # @nx/shared-fs-cache
{% callout type="warning" title="Potential Cache Poisoning" %} The `@nx/shared-fs-cache` plugin enables you to host your remote cache on a shared file system directory. While you're responsible for implementing the actual directory sharing mechanism, the plugin configures Nx to read from both your local cache and the shared directory.
Using a shared file system folder for remote caching introduces the risk of [cache poisoning](/troubleshooting/unknown-local-cache). To mitigate this risk, consider using [Nx Replay](/ci/features/remote-cache) instead.
{% /callout %}
{% callout type="deepdive" title="Free managed remote cache with Nx Cloud" %} {% callout type="deepdive" title="Free managed remote cache with Nx Cloud" %}
@ -19,9 +17,9 @@ If you are an enterprise and **data privacy and security is a concern**, [reach
{% /callout %} {% /callout %}
{% callout type="info" title="Self-hosted caching is now free" %} {% callout type="warning" title="Bucket-based caches are vulnerable to poisoning and often prohibited in organizations" %}
Self-hosted caching is **now free for everyone** to use. CREEP (CVE-2025-36852) is a critical vulnerability in bucket-based self-hosted remote caches. It lets attackers with PR access poison production builds via a race condition during artifact creation—before security checks can catch it. [Learn more](/blog/cve-2025-36852-critical-cache-poisoning-vulnerability-creep)
{% /callout %} {% /callout %}

View File

@ -5944,6 +5944,14 @@
"children": [], "children": [],
"isExternal": false, "isExternal": false,
"disableCollapsible": false "disableCollapsible": false
},
{
"id": "preset",
"path": "/reference/core-api/conformance/generators/preset",
"name": "preset",
"children": [],
"isExternal": false,
"disableCollapsible": false
} }
], ],
"isExternal": false, "isExternal": false,

View File

@ -5577,6 +5577,15 @@
"originalFilePath": "/libs/nx-packages/conformance/src/generators/create-rule/schema.json", "originalFilePath": "/libs/nx-packages/conformance/src/generators/create-rule/schema.json",
"path": "/reference/core-api/conformance/generators/create-rule", "path": "/reference/core-api/conformance/generators/create-rule",
"type": "generator" "type": "generator"
},
"/reference/core-api/conformance/generators/preset": {
"description": "Nx workspace preset which includes a working conformance rule",
"file": "external-generated/packages/conformance/generators/preset.json",
"hidden": false,
"name": "preset",
"originalFilePath": "/libs/nx-packages/conformance/src/generators/preset/schema.json",
"path": "/reference/core-api/conformance/generators/preset",
"type": "generator"
} }
}, },
"migrations": {}, "migrations": {},

View File

@ -17,7 +17,6 @@ To write your own conformance rule, run the `@nx/conformance:create-rule` genera
✔ What is the name of the rule? · local-conformance-rule-example ✔ What is the name of the rule? · local-conformance-rule-example
✔ Which directory do you want to create the rule directory in? · packages/my-plugin/local-conformance-rule ✔ Which directory do you want to create the rule directory in? · packages/my-plugin/local-conformance-rule
✔ What category does this rule belong to? · security ✔ What category does this rule belong to? · security
✔ What reporter do you want to use for this rule? · project-reporter
✔ What is the description of the rule? · an example of a conformance rule ✔ What is the description of the rule? · an example of a conformance rule
CREATE packages/my-plugin/local-conformance-rule/local-conformance-rule-example/index.ts CREATE packages/my-plugin/local-conformance-rule/local-conformance-rule-example/index.ts
CREATE packages/my-plugin/local-conformance-rule/local-conformance-rule-example/schema.json CREATE packages/my-plugin/local-conformance-rule/local-conformance-rule-example/schema.json
@ -26,15 +25,14 @@ CREATE packages/my-plugin/local-conformance-rule/local-conformance-rule-example/
The generated rule definition file should look like this: The generated rule definition file should look like this:
```ts {% fileName="packages/my-plugin/local-conformance-rule/index.ts" %} ```ts {% fileName="packages/my-plugin/local-conformance-rule/index.ts" %}
import { createConformanceRule, ProjectViolation } from '@nx/conformance'; import { createConformanceRule, ConformanceViolation } from '@nx/conformance';
export default createConformanceRule({ export default createConformanceRule({
name: 'local-conformance-rule-example', name: 'local-conformance-rule-example',
category: 'security', category: 'security',
description: 'an example of a conformance rule', description: 'an example of a conformance rule',
reporter: 'project-reporter',
implementation: async (context) => { implementation: async (context) => {
const violations: ProjectViolation[] = []; const violations: ConformanceViolation[] = [];
return { return {
severity: 'low', severity: 'low',
@ -64,28 +62,27 @@ Note that the severity of the error is defined by the rule author and can be adj
## Conformance Rule Examples ## Conformance Rule Examples
There are three types of reporters that a rule can use. Rules should report on the most specific thing that is in violation of the rule. They can report on one or more of the following things within a workspace:
- `project-reporter` - The rule evaluates an entire project at a time. - file - The rule reports on a particular file being in violation of the rule.
- `project-files-reporter` - The rule evaluates a single project file at a time. - project - The rule reports on a particular project being in violation of the rule, because no one file within it would be applicable to flag up.
- `non-project-files-reporter` - The rule evaluates files that don't belong to any project. - the workspace itself - Sometimes there is no specific file or project that is most applicable to flag up, so the rule can report on the workspace itself.
{% tabs %} {% tabs %}
{% tab label="project-reporter" %} {% tab label="project violation" %}
The `@nx/conformance:ensure-owners` rule provides us an example of how to write a `project-reporter` rule. The `@nx/owners` plugin adds an `owners` metadata property to every project node that has an owner in the project graph. This rule checks each project node metadata to make sure that each project has some owner defined. The `@nx/conformance:ensure-owners` rule provides us an example of how to write a rule that reports on a project being in violation of the rule. The `@nx/owners` plugin adds an `owners` metadata property to every project node that has an owner in the project graph. This rule checks each project node metadata to make sure that each project has some owner defined.
```ts ```ts
import { ProjectGraphProjectNode } from '@nx/devkit'; import { ProjectGraphProjectNode } from '@nx/devkit';
import { createConformanceRule, ProjectViolation } from '@nx/conformance'; import { createConformanceRule, ConformanceViolation } from '@nx/conformance';
export default createConformanceRule({ export default createConformanceRule({
name: 'ensure-owners', name: 'ensure-owners',
category: 'consistency', category: 'consistency',
description: 'Ensure that all projects have owners defined via Nx Owners.', description: 'Ensure that all projects have owners defined via Nx Owners.',
reporter: 'project-reporter',
implementation: async (context) => { implementation: async (context) => {
const violations: ProjectViolation[] = []; const violations: ConformanceViolation[] = [];
for (const node of Object.values( for (const node of Object.values(
context.projectGraph.nodes context.projectGraph.nodes
@ -110,12 +107,12 @@ export default createConformanceRule({
``` ```
{% /tab %} {% /tab %}
{% tab label="project-files-reporter" %} {% tab label="file violation" %}
This rule uses TypeScript AST processing to ensure that `index.ts` files use a client-side style of export syntax and `server.ts` files use a server-side style of export syntax. This rule uses TypeScript AST processing to ensure that `index.ts` files use a client-side style of export syntax and `server.ts` files use a server-side style of export syntax.
```ts ```ts
import { createConformanceRule, ProjectFilesViolation } from '@nx/conformance'; import { createConformanceRule, ConformanceViolation } from '@nx/conformance';
import { existsSync, readFileSync } from 'node:fs'; import { existsSync, readFileSync } from 'node:fs';
import { join } from 'node:path'; import { join } from 'node:path';
import { import {
@ -131,9 +128,8 @@ export default createConformanceRule({
name: 'server-client-public-api', name: 'server-client-public-api',
category: 'consistency', category: 'consistency',
description: 'Ensure server-only and client-only public APIs are not mixed', description: 'Ensure server-only and client-only public APIs are not mixed',
reporter: 'project-files-reporter',
implementation: async ({ projectGraph }) => { implementation: async ({ projectGraph }) => {
const violations: ProjectFilesViolation[] = []; const violations: ConformanceViolation[] = [];
for (const nodeId in projectGraph.nodes) { for (const nodeId in projectGraph.nodes) {
const node = projectGraph.nodes[nodeId]; const node = projectGraph.nodes[nodeId];
@ -171,7 +167,7 @@ export function processEntryPoint(
project: string, project: string,
style: 'server' | 'client' style: 'server' | 'client'
) { ) {
const violations: ProjectFilesViolation[] = []; const violations: ConformanceViolation[] = [];
const sf = createSourceFile( const sf = createSourceFile(
entryPoint, entryPoint,
@ -246,42 +242,30 @@ function isModuleSpecifierViolated(
``` ```
{% /tab %} {% /tab %}
{% tab label="non-project-files-reporter" %} {% tab label="workspace violation" %}
This rule checks the root `package.json` file and ensures that if the `tmp` package is included as a dependency, it has a minimum version of 0.2.3. This rule checks to see if there is a root README.md file in the workspace, and if there is not, it reports on the workspace itself.
```ts ```ts
import { readJsonFile, workspaceRoot } from '@nx/devkit'; import { workspaceRoot } from '@nx/devkit';
import { import { createConformanceRule, ConformanceViolation } from '@nx/conformance';
createConformanceRule,
NonProjectFilesViolation,
} from '@nx/conformance';
import { join } from 'node:path'; import { join } from 'node:path';
import { satisfies } from 'semver'; import { existsSync } from 'node:fs';
export default createConformanceRule<object>({ export default createConformanceRule<object>({
name: 'package-tmp-0.2.3', name: 'readme-file',
category: 'maintainability', category: 'maintainability',
description: 'The tmp dependency should be a minimum version of 0.2.3', description: 'The workspace should have a root README.md file',
reporter: 'non-project-files-reporter',
implementation: async () => { implementation: async () => {
const violations: NonProjectFilesViolation[] = []; const violations: ConformanceViolation[] = [];
const applyViolationIfApplicable = (version: string | undefined) => {
if (version && !satisfies(version, '>=0.2.3')) { const readmePath = join(workspaceRoot, 'README.md');
if (!existsSync(readmePath)) {
violations.push({ violations.push({
message: 'The "tmp" package must be version "0.2.3" or higher', message: 'The workspace should have a root README.md file',
file: 'package.json', workspaceViolation: true,
}); });
} }
};
const workspaceRootPackageJson = await readJsonFile(
join(workspaceRoot, 'package.json')
);
applyViolationIfApplicable(workspaceRootPackageJson.dependencies?.['tmp']);
applyViolationIfApplicable(
workspaceRootPackageJson.devDependencies?.['tmp']
);
return { return {
severity: 'low', severity: 'low',

View File

@ -158,7 +158,7 @@ Below is an example on how to connect to MinIO:
"forcePathStyle": true, "forcePathStyle": true,
"accessKeyId": "abc1234", "accessKeyId": "abc1234",
"secretAccessKey": "4321cba", "secretAccessKey": "4321cba",
"disableChecksum: true "disableChecksum": true
} }
} }
``` ```

View File

@ -719,6 +719,7 @@
- [bundle-rules](/reference/core-api/conformance/executors/bundle-rules) - [bundle-rules](/reference/core-api/conformance/executors/bundle-rules)
- [generators](/reference/core-api/conformance/generators) - [generators](/reference/core-api/conformance/generators)
- [create-rule](/reference/core-api/conformance/generators/create-rule) - [create-rule](/reference/core-api/conformance/generators/create-rule)
- [preset](/reference/core-api/conformance/generators/preset)
- [azure-cache](/reference/core-api/azure-cache) - [azure-cache](/reference/core-api/azure-cache)
- [Overview](/reference/core-api/azure-cache/overview) - [Overview](/reference/core-api/azure-cache/overview)
- [gcs-cache](/reference/core-api/gcs-cache) - [gcs-cache](/reference/core-api/gcs-cache)

View File

@ -80,20 +80,20 @@
"@nuxt/kit": "^3.10.0", "@nuxt/kit": "^3.10.0",
"@nuxt/schema": "^3.10.0", "@nuxt/schema": "^3.10.0",
"@nx/angular": "21.2.0-beta.4", "@nx/angular": "21.2.0-beta.4",
"@nx/conformance": "2.0.1", "@nx/conformance": "3.0.0",
"@nx/cypress": "21.2.0-beta.4", "@nx/cypress": "21.2.0-beta.4",
"@nx/devkit": "21.2.0-beta.4", "@nx/devkit": "21.2.0-beta.4",
"@nx/enterprise-cloud": "2.0.1", "@nx/enterprise-cloud": "3.0.0",
"@nx/esbuild": "21.2.0-beta.4", "@nx/esbuild": "21.2.0-beta.4",
"@nx/eslint": "21.2.0-beta.4", "@nx/eslint": "21.2.0-beta.4",
"@nx/eslint-plugin": "21.2.0-beta.4", "@nx/eslint-plugin": "21.2.0-beta.4",
"@nx/gradle": "21.2.0-beta.4", "@nx/gradle": "21.2.0-beta.4",
"@nx/jest": "21.2.0-beta.4", "@nx/jest": "21.2.0-beta.4",
"@nx/js": "21.2.0-beta.4", "@nx/js": "21.2.0-beta.4",
"@nx/key": "2.0.1", "@nx/key": "3.0.0",
"@nx/next": "21.2.0-beta.4", "@nx/next": "21.2.0-beta.4",
"@nx/playwright": "21.2.0-beta.4", "@nx/playwright": "21.2.0-beta.4",
"@nx/powerpack-license": "2.0.1", "@nx/powerpack-license": "3.0.0",
"@nx/react": "21.2.0-beta.4", "@nx/react": "21.2.0-beta.4",
"@nx/rsbuild": "21.2.0-beta.4", "@nx/rsbuild": "21.2.0-beta.4",
"@nx/rspack": "21.2.0-beta.4", "@nx/rspack": "21.2.0-beta.4",

118
pnpm-lock.yaml generated
View File

@ -328,8 +328,8 @@ importers:
specifier: 21.2.0-beta.4 specifier: 21.2.0-beta.4
version: 21.2.0-beta.4(42a8a72230adc94556bc5d96e7eba89b) version: 21.2.0-beta.4(42a8a72230adc94556bc5d96e7eba89b)
'@nx/conformance': '@nx/conformance':
specifier: 2.0.1 specifier: 3.0.0
version: 2.0.1(@nx/js@21.2.0-beta.4(@babel/traverse@7.27.1)(@swc-node/register@1.9.1(@swc/core@1.5.7(@swc/helpers@0.5.11))(@swc/types@0.1.21)(typescript@5.8.3))(@swc/core@1.5.7(@swc/helpers@0.5.11))(nx@21.2.0-beta.4(@swc-node/register@1.9.1(@swc/core@1.5.7(@swc/helpers@0.5.11))(@swc/types@0.1.21)(typescript@5.8.3))(@swc/core@1.5.7(@swc/helpers@0.5.11)))(verdaccio@6.0.5(encoding@0.1.13)(typanion@3.14.0)))(nx@21.2.0-beta.4(@swc-node/register@1.9.1(@swc/core@1.5.7(@swc/helpers@0.5.11))(@swc/types@0.1.21)(typescript@5.8.3))(@swc/core@1.5.7(@swc/helpers@0.5.11))) version: 3.0.0(@nx/js@21.2.0-beta.4(@babel/traverse@7.27.1)(@swc-node/register@1.9.1(@swc/core@1.5.7(@swc/helpers@0.5.11))(@swc/types@0.1.21)(typescript@5.8.3))(@swc/core@1.5.7(@swc/helpers@0.5.11))(nx@21.2.0-beta.4(@swc-node/register@1.9.1(@swc/core@1.5.7(@swc/helpers@0.5.11))(@swc/types@0.1.21)(typescript@5.8.3))(@swc/core@1.5.7(@swc/helpers@0.5.11)))(verdaccio@6.0.5(encoding@0.1.13)(typanion@3.14.0)))(nx@21.2.0-beta.4(@swc-node/register@1.9.1(@swc/core@1.5.7(@swc/helpers@0.5.11))(@swc/types@0.1.21)(typescript@5.8.3))(@swc/core@1.5.7(@swc/helpers@0.5.11)))
'@nx/cypress': '@nx/cypress':
specifier: 21.2.0-beta.4 specifier: 21.2.0-beta.4
version: 21.2.0-beta.4(@babel/traverse@7.27.1)(@swc-node/register@1.9.1(@swc/core@1.5.7(@swc/helpers@0.5.11))(@swc/types@0.1.21)(typescript@5.8.3))(@swc/core@1.5.7(@swc/helpers@0.5.11))(@zkochan/js-yaml@0.0.7)(cypress@14.3.0)(eslint@8.57.0)(nx@21.2.0-beta.4(@swc-node/register@1.9.1(@swc/core@1.5.7(@swc/helpers@0.5.11))(@swc/types@0.1.21)(typescript@5.8.3))(@swc/core@1.5.7(@swc/helpers@0.5.11)))(typescript@5.8.3)(verdaccio@6.0.5(encoding@0.1.13)(typanion@3.14.0)) version: 21.2.0-beta.4(@babel/traverse@7.27.1)(@swc-node/register@1.9.1(@swc/core@1.5.7(@swc/helpers@0.5.11))(@swc/types@0.1.21)(typescript@5.8.3))(@swc/core@1.5.7(@swc/helpers@0.5.11))(@zkochan/js-yaml@0.0.7)(cypress@14.3.0)(eslint@8.57.0)(nx@21.2.0-beta.4(@swc-node/register@1.9.1(@swc/core@1.5.7(@swc/helpers@0.5.11))(@swc/types@0.1.21)(typescript@5.8.3))(@swc/core@1.5.7(@swc/helpers@0.5.11)))(typescript@5.8.3)(verdaccio@6.0.5(encoding@0.1.13)(typanion@3.14.0))
@ -337,8 +337,8 @@ importers:
specifier: 21.2.0-beta.4 specifier: 21.2.0-beta.4
version: 21.2.0-beta.4(nx@21.2.0-beta.4(@swc-node/register@1.9.1(@swc/core@1.5.7(@swc/helpers@0.5.11))(@swc/types@0.1.21)(typescript@5.8.3))(@swc/core@1.5.7(@swc/helpers@0.5.11))) version: 21.2.0-beta.4(nx@21.2.0-beta.4(@swc-node/register@1.9.1(@swc/core@1.5.7(@swc/helpers@0.5.11))(@swc/types@0.1.21)(typescript@5.8.3))(@swc/core@1.5.7(@swc/helpers@0.5.11)))
'@nx/enterprise-cloud': '@nx/enterprise-cloud':
specifier: 2.0.1 specifier: 3.0.0
version: 2.0.1(nx@21.2.0-beta.4(@swc-node/register@1.9.1(@swc/core@1.5.7(@swc/helpers@0.5.11))(@swc/types@0.1.21)(typescript@5.8.3))(@swc/core@1.5.7(@swc/helpers@0.5.11))) version: 3.0.0(nx@21.2.0-beta.4(@swc-node/register@1.9.1(@swc/core@1.5.7(@swc/helpers@0.5.11))(@swc/types@0.1.21)(typescript@5.8.3))(@swc/core@1.5.7(@swc/helpers@0.5.11)))
'@nx/esbuild': '@nx/esbuild':
specifier: 21.2.0-beta.4 specifier: 21.2.0-beta.4
version: 21.2.0-beta.4(@babel/traverse@7.27.1)(@swc-node/register@1.9.1(@swc/core@1.5.7(@swc/helpers@0.5.11))(@swc/types@0.1.21)(typescript@5.8.3))(@swc/core@1.5.7(@swc/helpers@0.5.11))(esbuild@0.25.0)(nx@21.2.0-beta.4(@swc-node/register@1.9.1(@swc/core@1.5.7(@swc/helpers@0.5.11))(@swc/types@0.1.21)(typescript@5.8.3))(@swc/core@1.5.7(@swc/helpers@0.5.11)))(verdaccio@6.0.5(encoding@0.1.13)(typanion@3.14.0)) version: 21.2.0-beta.4(@babel/traverse@7.27.1)(@swc-node/register@1.9.1(@swc/core@1.5.7(@swc/helpers@0.5.11))(@swc/types@0.1.21)(typescript@5.8.3))(@swc/core@1.5.7(@swc/helpers@0.5.11))(esbuild@0.25.0)(nx@21.2.0-beta.4(@swc-node/register@1.9.1(@swc/core@1.5.7(@swc/helpers@0.5.11))(@swc/types@0.1.21)(typescript@5.8.3))(@swc/core@1.5.7(@swc/helpers@0.5.11)))(verdaccio@6.0.5(encoding@0.1.13)(typanion@3.14.0))
@ -358,8 +358,8 @@ importers:
specifier: 21.2.0-beta.4 specifier: 21.2.0-beta.4
version: 21.2.0-beta.4(@babel/traverse@7.27.1)(@swc-node/register@1.9.1(@swc/core@1.5.7(@swc/helpers@0.5.11))(@swc/types@0.1.21)(typescript@5.8.3))(@swc/core@1.5.7(@swc/helpers@0.5.11))(nx@21.2.0-beta.4(@swc-node/register@1.9.1(@swc/core@1.5.7(@swc/helpers@0.5.11))(@swc/types@0.1.21)(typescript@5.8.3))(@swc/core@1.5.7(@swc/helpers@0.5.11)))(verdaccio@6.0.5(encoding@0.1.13)(typanion@3.14.0)) version: 21.2.0-beta.4(@babel/traverse@7.27.1)(@swc-node/register@1.9.1(@swc/core@1.5.7(@swc/helpers@0.5.11))(@swc/types@0.1.21)(typescript@5.8.3))(@swc/core@1.5.7(@swc/helpers@0.5.11))(nx@21.2.0-beta.4(@swc-node/register@1.9.1(@swc/core@1.5.7(@swc/helpers@0.5.11))(@swc/types@0.1.21)(typescript@5.8.3))(@swc/core@1.5.7(@swc/helpers@0.5.11)))(verdaccio@6.0.5(encoding@0.1.13)(typanion@3.14.0))
'@nx/key': '@nx/key':
specifier: 2.0.1 specifier: 3.0.0
version: 2.0.1 version: 3.0.0
'@nx/next': '@nx/next':
specifier: 21.2.0-beta.4 specifier: 21.2.0-beta.4
version: 21.2.0-beta.4(@babel/core@7.25.2)(@babel/traverse@7.27.1)(@rspack/core@1.3.9(@swc/helpers@0.5.11))(@swc-node/register@1.9.1(@swc/core@1.5.7(@swc/helpers@0.5.11))(@swc/types@0.1.21)(typescript@5.8.3))(@swc/core@1.5.7(@swc/helpers@0.5.11))(@swc/helpers@0.5.11)(@zkochan/js-yaml@0.0.7)(bufferutil@4.0.7)(esbuild@0.25.0)(eslint@8.57.0)(html-webpack-plugin@5.5.0(webpack@5.99.8))(next@14.2.28(@babel/core@7.25.2)(@opentelemetry/api@1.9.0)(@playwright/test@1.47.1)(babel-plugin-macros@3.1.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(sass@1.55.0))(nx@21.2.0-beta.4(@swc-node/register@1.9.1(@swc/core@1.5.7(@swc/helpers@0.5.11))(@swc/types@0.1.21)(typescript@5.8.3))(@swc/core@1.5.7(@swc/helpers@0.5.11)))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.8.3)(verdaccio@6.0.5(encoding@0.1.13)(typanion@3.14.0))(webpack-cli@5.1.4)(webpack@5.99.8) version: 21.2.0-beta.4(@babel/core@7.25.2)(@babel/traverse@7.27.1)(@rspack/core@1.3.9(@swc/helpers@0.5.11))(@swc-node/register@1.9.1(@swc/core@1.5.7(@swc/helpers@0.5.11))(@swc/types@0.1.21)(typescript@5.8.3))(@swc/core@1.5.7(@swc/helpers@0.5.11))(@swc/helpers@0.5.11)(@zkochan/js-yaml@0.0.7)(bufferutil@4.0.7)(esbuild@0.25.0)(eslint@8.57.0)(html-webpack-plugin@5.5.0(webpack@5.99.8))(next@14.2.28(@babel/core@7.25.2)(@opentelemetry/api@1.9.0)(@playwright/test@1.47.1)(babel-plugin-macros@3.1.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(sass@1.55.0))(nx@21.2.0-beta.4(@swc-node/register@1.9.1(@swc/core@1.5.7(@swc/helpers@0.5.11))(@swc/types@0.1.21)(typescript@5.8.3))(@swc/core@1.5.7(@swc/helpers@0.5.11)))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.8.3)(verdaccio@6.0.5(encoding@0.1.13)(typanion@3.14.0))(webpack-cli@5.1.4)(webpack@5.99.8)
@ -367,8 +367,8 @@ importers:
specifier: 21.2.0-beta.4 specifier: 21.2.0-beta.4
version: 21.2.0-beta.4(@babel/traverse@7.27.1)(@playwright/test@1.47.1)(@swc-node/register@1.9.1(@swc/core@1.5.7(@swc/helpers@0.5.11))(@swc/types@0.1.21)(typescript@5.8.3))(@swc/core@1.5.7(@swc/helpers@0.5.11))(@zkochan/js-yaml@0.0.7)(eslint@8.57.0)(nx@21.2.0-beta.4(@swc-node/register@1.9.1(@swc/core@1.5.7(@swc/helpers@0.5.11))(@swc/types@0.1.21)(typescript@5.8.3))(@swc/core@1.5.7(@swc/helpers@0.5.11)))(typescript@5.8.3)(verdaccio@6.0.5(encoding@0.1.13)(typanion@3.14.0)) version: 21.2.0-beta.4(@babel/traverse@7.27.1)(@playwright/test@1.47.1)(@swc-node/register@1.9.1(@swc/core@1.5.7(@swc/helpers@0.5.11))(@swc/types@0.1.21)(typescript@5.8.3))(@swc/core@1.5.7(@swc/helpers@0.5.11))(@zkochan/js-yaml@0.0.7)(eslint@8.57.0)(nx@21.2.0-beta.4(@swc-node/register@1.9.1(@swc/core@1.5.7(@swc/helpers@0.5.11))(@swc/types@0.1.21)(typescript@5.8.3))(@swc/core@1.5.7(@swc/helpers@0.5.11)))(typescript@5.8.3)(verdaccio@6.0.5(encoding@0.1.13)(typanion@3.14.0))
'@nx/powerpack-license': '@nx/powerpack-license':
specifier: 2.0.1 specifier: 3.0.0
version: 2.0.1 version: 3.0.0
'@nx/react': '@nx/react':
specifier: 21.2.0-beta.4 specifier: 21.2.0-beta.4
version: 21.2.0-beta.4(@babel/traverse@7.27.1)(@swc-node/register@1.9.1(@swc/core@1.5.7(@swc/helpers@0.5.11))(@swc/types@0.1.21)(typescript@5.8.3))(@swc/core@1.5.7(@swc/helpers@0.5.11))(@swc/helpers@0.5.11)(@zkochan/js-yaml@0.0.7)(bufferutil@4.0.7)(esbuild@0.25.0)(eslint@8.57.0)(next@14.2.28(@babel/core@7.25.2)(@opentelemetry/api@1.9.0)(@playwright/test@1.47.1)(babel-plugin-macros@3.1.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(sass@1.55.0))(nx@21.2.0-beta.4(@swc-node/register@1.9.1(@swc/core@1.5.7(@swc/helpers@0.5.11))(@swc/types@0.1.21)(typescript@5.8.3))(@swc/core@1.5.7(@swc/helpers@0.5.11)))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.8.3)(verdaccio@6.0.5(encoding@0.1.13)(typanion@3.14.0))(webpack-cli@5.1.4)(webpack@5.99.8) version: 21.2.0-beta.4(@babel/traverse@7.27.1)(@swc-node/register@1.9.1(@swc/core@1.5.7(@swc/helpers@0.5.11))(@swc/types@0.1.21)(typescript@5.8.3))(@swc/core@1.5.7(@swc/helpers@0.5.11))(@swc/helpers@0.5.11)(@zkochan/js-yaml@0.0.7)(bufferutil@4.0.7)(esbuild@0.25.0)(eslint@8.57.0)(next@14.2.28(@babel/core@7.25.2)(@opentelemetry/api@1.9.0)(@playwright/test@1.47.1)(babel-plugin-macros@3.1.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(sass@1.55.0))(nx@21.2.0-beta.4(@swc-node/register@1.9.1(@swc/core@1.5.7(@swc/helpers@0.5.11))(@swc/types@0.1.21)(typescript@5.8.3))(@swc/core@1.5.7(@swc/helpers@0.5.11)))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.8.3)(verdaccio@6.0.5(encoding@0.1.13)(typanion@3.14.0))(webpack-cli@5.1.4)(webpack@5.99.8)
@ -5725,8 +5725,8 @@ packages:
ng-packagr: ng-packagr:
optional: true optional: true
'@nx/conformance@2.0.1': '@nx/conformance@3.0.0':
resolution: {integrity: sha512-4yx/mz2+YEe6Clh8E3g3Y0+DJ6h1kpC9h0ZQPY3u3JRnAVlOvUWjr203aeYgJ4bL4c8xYC4LsTBC98Wj6spQhg==} resolution: {integrity: sha512-GojZtOwWjojqIM9oAmvsPRhbprtlOFgY0/fbjdjymuJJ3SBl5eY9LGFHavGoIvyCPOsQeG3mGo+qxw3rlaXZQg==}
hasBin: true hasBin: true
peerDependencies: peerDependencies:
'@nx/js': '>= 18 < 22' '@nx/js': '>= 18 < 22'
@ -5755,8 +5755,8 @@ packages:
peerDependencies: peerDependencies:
nx: 21.2.0-beta.4 nx: 21.2.0-beta.4
'@nx/enterprise-cloud@2.0.1': '@nx/enterprise-cloud@3.0.0':
resolution: {integrity: sha512-w5N/IoQ/AZquN7Q/hMt7b05z3wwQGys6QqO8BjyegW9wL8DTvtHwfMNSQRnX9UXjWk2PlRg/MfSjwflssAgS0g==} resolution: {integrity: sha512-e28NeMB6UPrYjdgTZqtaVkB9edt/OL7OAPnrs343ZOmJQCIVax39xR+bPFiymuTIDdWqm8mbYPbiCo6xlW+PCg==}
peerDependencies: peerDependencies:
nx: '>= 18 < 22' nx: '>= 18 < 22'
@ -5809,62 +5809,62 @@ packages:
verdaccio: verdaccio:
optional: true optional: true
'@nx/key-darwin-arm64@2.0.1': '@nx/key-darwin-arm64@3.0.0':
resolution: {integrity: sha512-yf+0nT+TggktJ5sfMXmWR5hFX+aC9sFO12Wbv/7dxCqQESWjpXIOdN0Z+F0c3RH77X7zivK4kfiwGXslOas6hA==} resolution: {integrity: sha512-oVb9RqCqtrUXmPxKrum8FwW5GHv/DgxE1MXOBQUt8eEsO9NOBN3t80SyIvrlUPrd5hNIxXPz4IRA9Fl5+9ZMAA==}
engines: {node: '>= 10'} engines: {node: '>= 10'}
cpu: [arm64] cpu: [arm64]
os: [darwin] os: [darwin]
'@nx/key-darwin-x64@2.0.1': '@nx/key-darwin-x64@3.0.0':
resolution: {integrity: sha512-LvhVx7CQkDOssvnE1Zq20gq5gXjuzL4SjRr24tv/AssAlOiNAyeGxos+2Maaxhm2DyXv+2p3+YUWEJDXEYeWmQ==} resolution: {integrity: sha512-eMV1Nkb4+/k7/qjPuLFjgQriSyupphWHrf+Wc5nD41G8j+Nf7SVYliiQ8Bl4/pgxr7TxCXw0vFa5FsYcIHdOzQ==}
engines: {node: '>= 10'} engines: {node: '>= 10'}
cpu: [x64] cpu: [x64]
os: [darwin] os: [darwin]
'@nx/key-linux-arm-gnueabihf@2.0.1': '@nx/key-linux-arm-gnueabihf@3.0.0':
resolution: {integrity: sha512-Xnl3RHz0Wf/oRwem2T4svnpvz74om7Dfv2hYHJv7Bddb00xCBKWZjNhUCKaTZk7cqgzOVGb30dsagb1LmLHZhA==} resolution: {integrity: sha512-Ra8dsogoCyxM8W/QrLuRR4O4gU/bcFPnnzhIeQ6mTfnEtGQlqZFBDVWSjjJKVoRzwtAnruJX1liDtnUaNUg5yQ==}
engines: {node: '>= 10'} engines: {node: '>= 10'}
cpu: [arm] cpu: [arm]
os: [linux] os: [linux]
'@nx/key-linux-arm64-gnu@2.0.1': '@nx/key-linux-arm64-gnu@3.0.0':
resolution: {integrity: sha512-PEYGlTupf1SU6s9XSNgJCtWClS6V8iG8KtNtgWU4mk/7mu4VYrAnBlwX0i4OyLY89cAiR0rIV0dvQd0UgLSwFw==} resolution: {integrity: sha512-Wrg4CYfLIQB8wmfX15lDVNeg1ivrh9B+m0eEHq1BjXAVwKuT74B5l8kquKa0GihMY0SdkGCrNCttC3Dgtm/vaQ==}
engines: {node: '>= 10'} engines: {node: '>= 10'}
cpu: [arm64] cpu: [arm64]
os: [linux] os: [linux]
'@nx/key-linux-arm64-musl@2.0.1': '@nx/key-linux-arm64-musl@3.0.0':
resolution: {integrity: sha512-OOLDzCgMaVLiJ7Cw937ClrvRUAMe1Ce3G1GQr7Wvqhd7Z0ylsDfYyjnvbBhmW5HLsDlQg7GHs8reyBZ2s2hrWw==} resolution: {integrity: sha512-vAlICrMMY5LjzoAN6elAKbkqhfKVki2uqjTF9IPULBX4BZGH8qY0VAhXjwprKkrA4044ND5TI2MIWs3OWQetMA==}
engines: {node: '>= 10'} engines: {node: '>= 10'}
cpu: [arm64] cpu: [arm64]
os: [linux] os: [linux]
'@nx/key-linux-x64-gnu@2.0.1': '@nx/key-linux-x64-gnu@3.0.0':
resolution: {integrity: sha512-HDUCWIJMSxAXpvzf0sJ6wWLe740nhETzq4HfHMxVOmMDL/8YttxLPYcF403RYWH8msXsg7wR9lFreOfMbjgE1w==} resolution: {integrity: sha512-51gwUYJP3SzTMwVioIXSERs63gaKg7Avlhr84dHPLcM7sABHzHaDfpiD7xl5dlKLn1+2cGETdiShUllBdC/Xvg==}
engines: {node: '>= 10'} engines: {node: '>= 10'}
cpu: [x64] cpu: [x64]
os: [linux] os: [linux]
'@nx/key-linux-x64-musl@2.0.1': '@nx/key-linux-x64-musl@3.0.0':
resolution: {integrity: sha512-bUJRmplEp/ukUaUXitcceGltGNafBzXb0tWMTw9DbJlynZK5u5oN6/ByTPLLK175Lu0K9KIyRcoqcPfpb4KCig==} resolution: {integrity: sha512-DG3ecD1gNzEQmE0kSRZcLE7SFY0hFVKgtuNBxuui/OJRgk0HG0yNTqxoNBEfEFKbHIZvKY0Ga2xq3+ELq7tAcQ==}
engines: {node: '>= 10'} engines: {node: '>= 10'}
cpu: [x64] cpu: [x64]
os: [linux] os: [linux]
'@nx/key-win32-arm64-msvc@2.0.1': '@nx/key-win32-arm64-msvc@3.0.0':
resolution: {integrity: sha512-vdwTmHGY3wTBLD2OJiz13rSgs4fgesribLqKahwBltHUZ/i6ZqHgLn3//6Qcu0V/ab++8O79qwj4Zxehr2wRCg==} resolution: {integrity: sha512-4KHAnabcyyewMpXEp+SfV/Lwn4pmHZu1idg6vipIpI+wiUHPNS2tEx8cLloVEM08/Bf6O+WW8bqveyz6uNhvNw==}
engines: {node: '>= 10'} engines: {node: '>= 10'}
cpu: [arm64] cpu: [arm64]
os: [win32] os: [win32]
'@nx/key-win32-x64-msvc@2.0.1': '@nx/key-win32-x64-msvc@3.0.0':
resolution: {integrity: sha512-QrCJi6fhvjy6cBwXrhBrzuYtYGTP59WitNATGDytNjgbfrKalCDX3B+tHJPbFbk+GLNgTmtJ4nT5XoMBNwzkfg==} resolution: {integrity: sha512-Ym5ZEphBiYyDnESgMfAG99jYWqXghPTeOxAp6+FhZ5IB00+sAkIbGqOEx6sMxa+BOyDst8XlUoFsn8+14csi5w==}
engines: {node: '>= 10'} engines: {node: '>= 10'}
cpu: [x64] cpu: [x64]
os: [win32] os: [win32]
'@nx/key@2.0.1': '@nx/key@3.0.0':
resolution: {integrity: sha512-Z4odswr+V3ZsW0sGpSzEn8mxPmX0baPcBmKo0QVlhDkaI/fDoHED1NSi80wc41WKk1/l2SILQvXi99eUASkxRA==} resolution: {integrity: sha512-Lz1oDkih4bXVnuXp2vzL4MM5Ep6m+5yyftvB5qD9IAS2cCpqVEDLDwnTkqdOpdz681jtXUCJ5UlZy9yRuGPaww==}
engines: {node: '>= 10'} engines: {node: '>= 10'}
'@nx/module-federation@21.2.0-beta.4': '@nx/module-federation@21.2.0-beta.4':
@ -5933,8 +5933,8 @@ packages:
'@playwright/test': '@playwright/test':
optional: true optional: true
'@nx/powerpack-license@2.0.1': '@nx/powerpack-license@3.0.0':
resolution: {integrity: sha512-RpZ6geFvmWTb8aHMaDJ/HN6Uf1vpm84iEA8DhF5vmp3S4SbCD4eBk/5vmd4DTqyj+ROPMalRrUwaJDd+/O95dQ==} resolution: {integrity: sha512-3/VnpG4RWe8Pw7EDIxPMuMUuiZXYcTjMa4YYtm21NQ8owWlHarJZ9psHjVCshVjkLSq7Z5LjPUDZJbpw+OqHXw==}
engines: {node: '>= 10'} engines: {node: '>= 10'}
'@nx/react@21.2.0-beta.4': '@nx/react@21.2.0-beta.4':
@ -25781,11 +25781,11 @@ snapshots:
- vue-tsc - vue-tsc
- webpack-cli - webpack-cli
'@nx/conformance@2.0.1(@nx/js@21.2.0-beta.4(@babel/traverse@7.27.1)(@swc-node/register@1.9.1(@swc/core@1.5.7(@swc/helpers@0.5.11))(@swc/types@0.1.21)(typescript@5.8.3))(@swc/core@1.5.7(@swc/helpers@0.5.11))(nx@21.2.0-beta.4(@swc-node/register@1.9.1(@swc/core@1.5.7(@swc/helpers@0.5.11))(@swc/types@0.1.21)(typescript@5.8.3))(@swc/core@1.5.7(@swc/helpers@0.5.11)))(verdaccio@6.0.5(encoding@0.1.13)(typanion@3.14.0)))(nx@21.2.0-beta.4(@swc-node/register@1.9.1(@swc/core@1.5.7(@swc/helpers@0.5.11))(@swc/types@0.1.21)(typescript@5.8.3))(@swc/core@1.5.7(@swc/helpers@0.5.11)))': '@nx/conformance@3.0.0(@nx/js@21.2.0-beta.4(@babel/traverse@7.27.1)(@swc-node/register@1.9.1(@swc/core@1.5.7(@swc/helpers@0.5.11))(@swc/types@0.1.21)(typescript@5.8.3))(@swc/core@1.5.7(@swc/helpers@0.5.11))(nx@21.2.0-beta.4(@swc-node/register@1.9.1(@swc/core@1.5.7(@swc/helpers@0.5.11))(@swc/types@0.1.21)(typescript@5.8.3))(@swc/core@1.5.7(@swc/helpers@0.5.11)))(verdaccio@6.0.5(encoding@0.1.13)(typanion@3.14.0)))(nx@21.2.0-beta.4(@swc-node/register@1.9.1(@swc/core@1.5.7(@swc/helpers@0.5.11))(@swc/types@0.1.21)(typescript@5.8.3))(@swc/core@1.5.7(@swc/helpers@0.5.11)))':
dependencies: dependencies:
'@nx/devkit': 21.0.0(nx@21.2.0-beta.4(@swc-node/register@1.9.1(@swc/core@1.5.7(@swc/helpers@0.5.11))(@swc/types@0.1.21)(typescript@5.8.3))(@swc/core@1.5.7(@swc/helpers@0.5.11))) '@nx/devkit': 21.0.0(nx@21.2.0-beta.4(@swc-node/register@1.9.1(@swc/core@1.5.7(@swc/helpers@0.5.11))(@swc/types@0.1.21)(typescript@5.8.3))(@swc/core@1.5.7(@swc/helpers@0.5.11)))
'@nx/js': 21.2.0-beta.4(@babel/traverse@7.27.1)(@swc-node/register@1.9.1(@swc/core@1.5.7(@swc/helpers@0.5.11))(@swc/types@0.1.21)(typescript@5.8.3))(@swc/core@1.5.7(@swc/helpers@0.5.11))(nx@21.2.0-beta.4(@swc-node/register@1.9.1(@swc/core@1.5.7(@swc/helpers@0.5.11))(@swc/types@0.1.21)(typescript@5.8.3))(@swc/core@1.5.7(@swc/helpers@0.5.11)))(verdaccio@6.0.5(encoding@0.1.13)(typanion@3.14.0)) '@nx/js': 21.2.0-beta.4(@babel/traverse@7.27.1)(@swc-node/register@1.9.1(@swc/core@1.5.7(@swc/helpers@0.5.11))(@swc/types@0.1.21)(typescript@5.8.3))(@swc/core@1.5.7(@swc/helpers@0.5.11))(nx@21.2.0-beta.4(@swc-node/register@1.9.1(@swc/core@1.5.7(@swc/helpers@0.5.11))(@swc/types@0.1.21)(typescript@5.8.3))(@swc/core@1.5.7(@swc/helpers@0.5.11)))(verdaccio@6.0.5(encoding@0.1.13)(typanion@3.14.0))
'@nx/key': 2.0.1 '@nx/key': 3.0.0
ajv: 8.17.1 ajv: 8.17.1
esbuild: 0.21.5 esbuild: 0.21.5
nx: 21.2.0-beta.4(@swc-node/register@1.9.1(@swc/core@1.5.7(@swc/helpers@0.5.11))(@swc/types@0.1.21)(typescript@5.8.3))(@swc/core@1.5.7(@swc/helpers@0.5.11)) nx: 21.2.0-beta.4(@swc-node/register@1.9.1(@swc/core@1.5.7(@swc/helpers@0.5.11))(@swc/types@0.1.21)(typescript@5.8.3))(@swc/core@1.5.7(@swc/helpers@0.5.11))
@ -25855,10 +25855,10 @@ snapshots:
tslib: 2.8.1 tslib: 2.8.1
yargs-parser: 21.1.1 yargs-parser: 21.1.1
'@nx/enterprise-cloud@2.0.1(nx@21.2.0-beta.4(@swc-node/register@1.9.1(@swc/core@1.5.7(@swc/helpers@0.5.11))(@swc/types@0.1.21)(typescript@5.8.3))(@swc/core@1.5.7(@swc/helpers@0.5.11)))': '@nx/enterprise-cloud@3.0.0(nx@21.2.0-beta.4(@swc-node/register@1.9.1(@swc/core@1.5.7(@swc/helpers@0.5.11))(@swc/types@0.1.21)(typescript@5.8.3))(@swc/core@1.5.7(@swc/helpers@0.5.11)))':
dependencies: dependencies:
'@nx/devkit': 21.0.0(nx@21.2.0-beta.4(@swc-node/register@1.9.1(@swc/core@1.5.7(@swc/helpers@0.5.11))(@swc/types@0.1.21)(typescript@5.8.3))(@swc/core@1.5.7(@swc/helpers@0.5.11))) '@nx/devkit': 21.0.0(nx@21.2.0-beta.4(@swc-node/register@1.9.1(@swc/core@1.5.7(@swc/helpers@0.5.11))(@swc/types@0.1.21)(typescript@5.8.3))(@swc/core@1.5.7(@swc/helpers@0.5.11)))
'@nx/key': 2.0.1 '@nx/key': 3.0.0
nx: 21.2.0-beta.4(@swc-node/register@1.9.1(@swc/core@1.5.7(@swc/helpers@0.5.11))(@swc/types@0.1.21)(typescript@5.8.3))(@swc/core@1.5.7(@swc/helpers@0.5.11)) nx: 21.2.0-beta.4(@swc-node/register@1.9.1(@swc/core@1.5.7(@swc/helpers@0.5.11))(@swc/types@0.1.21)(typescript@5.8.3))(@swc/core@1.5.7(@swc/helpers@0.5.11))
semver: 7.5.4 semver: 7.5.4
transitivePeerDependencies: transitivePeerDependencies:
@ -26014,34 +26014,34 @@ snapshots:
- nx - nx
- supports-color - supports-color
'@nx/key-darwin-arm64@2.0.1': '@nx/key-darwin-arm64@3.0.0':
optional: true optional: true
'@nx/key-darwin-x64@2.0.1': '@nx/key-darwin-x64@3.0.0':
optional: true optional: true
'@nx/key-linux-arm-gnueabihf@2.0.1': '@nx/key-linux-arm-gnueabihf@3.0.0':
optional: true optional: true
'@nx/key-linux-arm64-gnu@2.0.1': '@nx/key-linux-arm64-gnu@3.0.0':
optional: true optional: true
'@nx/key-linux-arm64-musl@2.0.1': '@nx/key-linux-arm64-musl@3.0.0':
optional: true optional: true
'@nx/key-linux-x64-gnu@2.0.1': '@nx/key-linux-x64-gnu@3.0.0':
optional: true optional: true
'@nx/key-linux-x64-musl@2.0.1': '@nx/key-linux-x64-musl@3.0.0':
optional: true optional: true
'@nx/key-win32-arm64-msvc@2.0.1': '@nx/key-win32-arm64-msvc@3.0.0':
optional: true optional: true
'@nx/key-win32-x64-msvc@2.0.1': '@nx/key-win32-x64-msvc@3.0.0':
optional: true optional: true
'@nx/key@2.0.1': '@nx/key@3.0.0':
dependencies: dependencies:
'@napi-rs/wasm-runtime': 0.2.4 '@napi-rs/wasm-runtime': 0.2.4
axios: 1.8.3 axios: 1.8.3
@ -26050,15 +26050,15 @@ snapshots:
enquirer: 2.4.1 enquirer: 2.4.1
ora: 5.4.1 ora: 5.4.1
optionalDependencies: optionalDependencies:
'@nx/key-darwin-arm64': 2.0.1 '@nx/key-darwin-arm64': 3.0.0
'@nx/key-darwin-x64': 2.0.1 '@nx/key-darwin-x64': 3.0.0
'@nx/key-linux-arm-gnueabihf': 2.0.1 '@nx/key-linux-arm-gnueabihf': 3.0.0
'@nx/key-linux-arm64-gnu': 2.0.1 '@nx/key-linux-arm64-gnu': 3.0.0
'@nx/key-linux-arm64-musl': 2.0.1 '@nx/key-linux-arm64-musl': 3.0.0
'@nx/key-linux-x64-gnu': 2.0.1 '@nx/key-linux-x64-gnu': 3.0.0
'@nx/key-linux-x64-musl': 2.0.1 '@nx/key-linux-x64-musl': 3.0.0
'@nx/key-win32-arm64-msvc': 2.0.1 '@nx/key-win32-arm64-msvc': 3.0.0
'@nx/key-win32-x64-msvc': 2.0.1 '@nx/key-win32-x64-msvc': 3.0.0
transitivePeerDependencies: transitivePeerDependencies:
- debug - debug
@ -26198,9 +26198,9 @@ snapshots:
- typescript - typescript
- verdaccio - verdaccio
'@nx/powerpack-license@2.0.1': '@nx/powerpack-license@3.0.0':
dependencies: dependencies:
'@nx/key': 2.0.1 '@nx/key': 3.0.0
transitivePeerDependencies: transitivePeerDependencies:
- debug - debug

View File

@ -1,22 +1,21 @@
import { readFileSync, existsSync } from 'node:fs';
import { join, dirname, basename, extname } from 'node:path';
import { load as yamlLoad } from 'js-yaml';
import { workspaceRoot } from '@nx/devkit';
import { sync as globSync } from 'glob';
import { import {
createConformanceRule, createConformanceRule,
type ProjectFilesViolation, type ConformanceViolation,
} from '@nx/conformance'; } from '@nx/conformance';
import { workspaceRoot } from '@nx/devkit';
import { sync as globSync } from 'glob';
import { load as yamlLoad } from 'js-yaml';
import { existsSync, readFileSync } from 'node:fs';
import { extname, join } from 'node:path';
export default createConformanceRule<{ mdGlobPattern: string }>({ export default createConformanceRule<{ mdGlobPattern: string }>({
name: 'blog-cover-image', name: 'blog-cover-image',
category: 'consistency', category: 'consistency',
description: description:
'Ensures that blog posts have a cover_image defined in avif or jpg format with appropriate fallbacks', 'Ensures that blog posts have a cover_image defined in avif or jpg format with appropriate fallbacks',
reporter: 'project-files-reporter',
implementation: async ({ projectGraph, ruleOptions }) => { implementation: async ({ projectGraph, ruleOptions }) => {
const violations: ProjectFilesViolation[] = []; const violations: ConformanceViolation[] = [];
const webinarWarnings: ProjectFilesViolation[] = []; const webinarWarnings: ConformanceViolation[] = [];
const { mdGlobPattern } = ruleOptions; const { mdGlobPattern } = ruleOptions;
// Look for the docs project // Look for the docs project

View File

@ -1,21 +1,20 @@
import { readFileSync, existsSync } from 'node:fs';
import { join } from 'node:path';
import { load as yamlLoad } from 'js-yaml';
import { workspaceRoot } from '@nx/devkit';
import { sync as globSync } from 'glob';
import { import {
createConformanceRule, createConformanceRule,
type ProjectFilesViolation, type ConformanceViolation,
} from '@nx/conformance'; } from '@nx/conformance';
import { workspaceRoot } from '@nx/devkit';
import { sync as globSync } from 'glob';
import { load as yamlLoad } from 'js-yaml';
import { readFileSync } from 'node:fs';
import { join } from 'node:path';
export default createConformanceRule<{ mdGlobPattern: string }>({ export default createConformanceRule<{ mdGlobPattern: string }>({
name: 'blog-description', name: 'blog-description',
category: 'consistency', category: 'consistency',
description: description:
'Ensures that markdown documentation files have a description in their frontmatter', 'Ensures that markdown documentation files have a description in their frontmatter',
reporter: 'project-files-reporter',
implementation: async ({ projectGraph, ruleOptions }) => { implementation: async ({ projectGraph, ruleOptions }) => {
const violations: ProjectFilesViolation[] = []; const violations: ConformanceViolation[] = [];
const { mdGlobPattern } = ruleOptions; const { mdGlobPattern } = ruleOptions;
// Look for the docs project // Look for the docs project

View File

@ -1,8 +1,8 @@
import { readJsonFile, workspaceRoot } from '@nx/devkit';
import { import {
createConformanceRule, createConformanceRule,
type ProjectFilesViolation, type ConformanceViolation,
} from '@nx/conformance'; } from '@nx/conformance';
import { readJsonFile, workspaceRoot } from '@nx/devkit';
import { existsSync } from 'node:fs'; import { existsSync } from 'node:fs';
import { join } from 'node:path'; import { join } from 'node:path';
import { satisfies } from 'semver'; import { satisfies } from 'semver';
@ -17,9 +17,8 @@ export default createConformanceRule<Options>({
category: 'consistency', category: 'consistency',
description: description:
'Ensures that packageJsonUpdates in migrations.json have all packages included from groups. e.g. @typescript-eslint/* packages must be in sync', 'Ensures that packageJsonUpdates in migrations.json have all packages included from groups. e.g. @typescript-eslint/* packages must be in sync',
reporter: 'project-files-reporter',
implementation: async ({ projectGraph, ruleOptions }) => { implementation: async ({ projectGraph, ruleOptions }) => {
const violations: ProjectFilesViolation[] = []; const violations: ConformanceViolation[] = [];
for (const project of Object.values(projectGraph.nodes)) { for (const project of Object.values(projectGraph.nodes)) {
if ( if (
@ -60,10 +59,10 @@ export function validateMigrations(
sourceProject: string, sourceProject: string,
migrationsPath: string, migrationsPath: string,
options: Options options: Options
): ProjectFilesViolation[] { ): ConformanceViolation[] {
if (!migrations.packageJsonUpdates) return []; if (!migrations.packageJsonUpdates) return [];
const violations: ProjectFilesViolation[] = []; const violations: ConformanceViolation[] = [];
// Check that if package updates include one package in the group, then: // Check that if package updates include one package in the group, then:
// 1. They all have the same version // 1. They all have the same version

View File

@ -1,8 +1,8 @@
import { readJsonFile, workspaceRoot } from '@nx/devkit';
import { import {
createConformanceRule, createConformanceRule,
type ProjectFilesViolation, type ConformanceViolation,
} from '@nx/conformance'; } from '@nx/conformance';
import { readJsonFile, workspaceRoot } from '@nx/devkit';
import { existsSync } from 'node:fs'; import { existsSync } from 'node:fs';
import { join } from 'node:path'; import { join } from 'node:path';
@ -11,9 +11,8 @@ export default createConformanceRule<object>({
category: 'consistency', category: 'consistency',
description: description:
'Ensures consistency across our project package.json files within the Nx repo', 'Ensures consistency across our project package.json files within the Nx repo',
reporter: 'project-files-reporter',
implementation: async ({ projectGraph }) => { implementation: async ({ projectGraph }) => {
const violations: ProjectFilesViolation[] = []; const violations: ConformanceViolation[] = [];
for (const project of Object.values(projectGraph.nodes)) { for (const project of Object.values(projectGraph.nodes)) {
const projectPackageJsonPath = join( const projectPackageJsonPath = join(
@ -48,8 +47,8 @@ export function validateProjectPackageJson(
sourceProject: string, sourceProject: string,
sourceProjectRoot: string, sourceProjectRoot: string,
projectPackageJsonPath: string projectPackageJsonPath: string
): ProjectFilesViolation[] { ): ConformanceViolation[] {
const violations: ProjectFilesViolation[] = []; const violations: ConformanceViolation[] = [];
// Private packages are exempt from this rule // Private packages are exempt from this rule
if (projectPackageJson.private === true) { if (projectPackageJson.private === true) {