Skip to content

feat: implemented new linting of entities to support new scorecards#2495

Open
AlbinaBlazhko17 wants to merge 16 commits intomainfrom
feat/new-scorecard-pitch
Open

feat: implemented new linting of entities to support new scorecards#2495
AlbinaBlazhko17 wants to merge 16 commits intomainfrom
feat/new-scorecard-pitch

Conversation

@AlbinaBlazhko17
Copy link
Contributor

@AlbinaBlazhko17 AlbinaBlazhko17 commented Jan 12, 2026

What/Why/How?

  • Implemented lintEntityWithScorecardLevel, which will be used in portal to lint new entities with new scorecard functionality.
  • Implemented lintSchema for linting specific schema. If entity has data-schema type we need to lint only provided schema.
  • Added support for Assertions (custom rules) in lintEntityFile.
  • The main goal of helper functions are to transform assertion subject to type, which is provided in @redocly/config.
  • Changed json-schema-adapter.ts to handle nodeTypeName if provided. Added returning of discriminatorFunc from adapter to get proper rootType. Added functionality to discriminatorFunc for handling mapping the default naming and provided nodeTypeName.
  • Fixed tests to match new structure.

Opened questions:

  • How to handle entities with the type of api-operations.
  • Adding support of custom rules for arrays. Currently, we don't have any Assertions (e.g. lt, lte, gte, etc.) for arrays.

Reference

Testing

Ran tests in CLI and Realm.

Screenshots (optional)

Check yourself

  • Code changed? - Tested with Redoc/Realm/Reunite (internal)
  • All new/updated code is covered by tests
  • New package installed? - Tested in different environments (browser/node)
  • Documentation update considered

Security

  • The security impact of the change has been considered
  • Code follows company security practices and guidelines

@changeset-bot
Copy link

changeset-bot bot commented Jan 12, 2026

🦋 Changeset detected

Latest commit: 475e9f8

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 3 packages
Name Type
@redocly/openapi-core Minor
@redocly/cli Minor
@redocly/respect-core Minor

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@github-actions
Copy link
Contributor

github-actions bot commented Jan 13, 2026

CLI Version Mean Time ± Std Dev (s) Relative Performance (Lower is Faster)
cli-latest 3.587s ± 0.042s ▓ 1.00x (Fastest)
cli-next 3.590s ± 0.042s ▓ 1.00x

@github-actions
Copy link
Contributor

github-actions bot commented Jan 13, 2026

Coverage Report

Status Category Percentage Covered / Total
🔵 Lines 79.33% (🎯 78%) 6249 / 7877
🔵 Statements 78.74% (🎯 78%) 6455 / 8197
🔵 Functions 82.96% (🎯 81%) 1271 / 1532
🔵 Branches 71.05% (🎯 70%) 4301 / 6053
File Coverage
File Stmts Branches Functions Lines Uncovered Lines
Changed Files
packages/core/src/lint.ts 94.5% 81.53% 100% 94.38% 128-139, 162, 359, 363-365
packages/core/src/types/entity-yaml.ts 100% 100% 100% 100%
packages/core/src/types/json-schema-adapter.ts 84.84% 82.17% 100% 84.04% 22, 40, 44, 48, 52-54, 76, 80, 98, 106-108, 112-114, 136, 158, 162, 166, 170-172
packages/core/src/types/redocly-yaml.ts 92.3% 82.85% 100% 91.93% 357, 359, 411, 414, 417
packages/core/src/utils/scorecards.ts 88.88% 84.84% 90.9% 90.9% 39, 78, 86, 97, 120-126
Generated in workflow #8440 for commit 475e9f8 by the Vitest Coverage Report Action

@AlbinaBlazhko17 AlbinaBlazhko17 self-assigned this Jan 26, 2026
@AlbinaBlazhko17 AlbinaBlazhko17 marked this pull request as ready for review January 26, 2026 17:56
@AlbinaBlazhko17 AlbinaBlazhko17 requested review from a team as code owners January 26, 2026 17:56
@AlbinaBlazhko17 AlbinaBlazhko17 force-pushed the feat/new-scorecard-pitch branch from bb3606d to 475e9f8 Compare January 30, 2026 08:46

expect(resolvedType).toBeTruthy();
expect(resolvedType.name).toBe('EntityFileDefault');
expect(resolvedType.name).toBe('UserEntity'); // Falls back to first type when discriminator fails
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe it's better to put Entity first, so it becomes the default fallback?

const { lintEntityFile } = await import('../lint.js');
const { makeDocumentFromString, BaseResolver } = await import('../resolve.js');

const entities = `- type: user
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could you use outdent?

expect(entityTypes).toHaveProperty('DomainEntity');
expect(entityTypes).toHaveProperty('TeamEntity');
expect(entityTypes).toHaveProperty('Entity');
expect(entityTypes).toHaveProperty('EntityFileArray');
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

WHy don't we expect EntityFile/Default anymore?

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I see we use them in createEntityTypes.

const discriminatedTypeName = value[discriminatedPropertyName];
if (typeof discriminatedTypeName === 'string' && ctx[discriminatedTypeName]) {
return discriminatedTypeName;
const discriminatorValue = value[discriminatedPropertyName];
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why changed discriminatedTypeName -> discriminatorValue? It's still a property name, not a value. Or am I missing something?


// Store mapping from discriminator value to actual type name
if (typeof actualTypeName === 'string') {
discriminatorMapping[discriminatorValue] = actualTypeName;
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not sure why do we need to mutate it here. Don't we receive the discriminator mapping in the needed form already?

Comment on lines +143 to +144
typeof parsed === 'object' &&
parsed !== null &&
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
typeof parsed === 'object' &&
parsed !== null &&
isPlainObject(parsed)

entityDefaultSchema: JSONSchema;
severity?: ProblemSeverity;
externalRefResolver?: BaseResolver;
assertionConfig?: Record<string, Assertion>;
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Assertions should be converted a separate array, at least it's so for regular lint. Let's discuss this offline.

}

const externalRefResolver = new BaseResolver();
const entityDocument = makeDocumentFromString(JSON.stringify(entity, null, 2), 'entity.yaml');
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why do we need to create a fake entity file on the fly? We should be able to resolve the real files.

});

return [...entityProblems, ...apiProblems];
} else if (Object.keys(apiRules).length !== 0) {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please use a utility function if possible (isEmptyObject or something like that).

return subjectType;
}

export function transformScorecardRulesToAssertions(
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why not use the existing assertion/rules conversion mechanism?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants