@cms-lab/core 1.2.5 → 1.2.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.d.ts CHANGED
@@ -160,10 +160,21 @@ type ScanSummary = {
160
160
  warnings: number;
161
161
  info: number;
162
162
  };
163
+ type DiagnosticGroupSummary = {
164
+ key: string;
165
+ severity: DiagnosticSeverity;
166
+ code: string;
167
+ count: number;
168
+ label: string;
169
+ type?: string;
170
+ routePattern?: string;
171
+ examples: string[];
172
+ };
163
173
  type ScanResult = {
164
174
  project: ProjectInfo;
165
175
  documents: CMSDocument[];
166
176
  diagnostics: Diagnostic[];
177
+ diagnosticGroups?: DiagnosticGroupSummary[];
167
178
  summary: ScanSummary;
168
179
  };
169
180
  type FetchLike = typeof fetch;
@@ -222,4 +233,4 @@ type ScanDocumentsOptions = {
222
233
  declare function scanDocuments(options: ScanDocumentsOptions): Promise<ScanResult>;
223
234
  declare function resolveSiteHealthUrl(site: CmsLabConfig["site"]): URL;
224
235
 
225
- export { type CMSDocument, type CMSDocumentStatus, type CheckGroup, CmsFetchError, type CmsFieldMappingConfig, type CmsLabConfig, CmsLabError, type CmsProviderConfig, ConfigLoadError, type ContentfulCmsProviderConfig, type ContentfulContentTypeConfig, type Diagnostic, type DiagnosticExplanation, type DiagnosticSeverity, type DirectusCmsProviderConfig, type DirectusCollectionConfig, type FetchLike, type LoadedCmsLabConfig, type PrismicCmsProviderConfig, type ProjectInfo, type RelationshipRule, type RequiredFieldRule, type RouteDefinition, type SanityCmsProviderConfig, type SanityContentTypeConfig, type ScanDocumentsOptions, type ScanFilters, type ScanResult, type ScanSummary, SiteUnreachableError, type StrapiCmsProviderConfig, type StrapiCollectionConfig, type StrapiLocaleConfig, type StrapiSingleTypeConfig, type WordPressCmsProviderConfig, type WordPressContentTypeConfig, createDiagnostic, defineConfig, explainDiagnostic, listDiagnosticExplanations, loadCmsLabConfig, readCmsDataPath, resolveSiteHealthUrl, scanDocuments, strapiRelationSlug, strapiRelationValue, summarizeDiagnostics, validateConfig };
236
+ export { type CMSDocument, type CMSDocumentStatus, type CheckGroup, CmsFetchError, type CmsFieldMappingConfig, type CmsLabConfig, CmsLabError, type CmsProviderConfig, ConfigLoadError, type ContentfulCmsProviderConfig, type ContentfulContentTypeConfig, type Diagnostic, type DiagnosticExplanation, type DiagnosticGroupSummary, type DiagnosticSeverity, type DirectusCmsProviderConfig, type DirectusCollectionConfig, type FetchLike, type LoadedCmsLabConfig, type PrismicCmsProviderConfig, type ProjectInfo, type RelationshipRule, type RequiredFieldRule, type RouteDefinition, type SanityCmsProviderConfig, type SanityContentTypeConfig, type ScanDocumentsOptions, type ScanFilters, type ScanResult, type ScanSummary, SiteUnreachableError, type StrapiCmsProviderConfig, type StrapiCollectionConfig, type StrapiLocaleConfig, type StrapiSingleTypeConfig, type WordPressCmsProviderConfig, type WordPressContentTypeConfig, createDiagnostic, defineConfig, explainDiagnostic, listDiagnosticExplanations, loadCmsLabConfig, readCmsDataPath, resolveSiteHealthUrl, scanDocuments, strapiRelationSlug, strapiRelationValue, summarizeDiagnostics, validateConfig };
package/dist/index.js CHANGED
@@ -443,6 +443,11 @@ async function scanDocuments(options) {
443
443
  project: options.project,
444
444
  documents,
445
445
  diagnostics,
446
+ diagnosticGroups: summarizeDiagnosticGroups(
447
+ diagnostics,
448
+ options.config,
449
+ routeCandidates
450
+ ),
446
451
  summary: summarizeDiagnostics(diagnostics)
447
452
  };
448
453
  }
@@ -773,6 +778,80 @@ function checkRelationships(config, documents) {
773
778
  function relationshipRules(config) {
774
779
  return config.checks?.relationships ?? [];
775
780
  }
781
+ function summarizeDiagnosticGroups(diagnostics, config, routeCandidates) {
782
+ const routePatternBySource = new Map(
783
+ routeCandidates.map((candidate) => [
784
+ sourceFor(config, candidate.document),
785
+ candidate.route.pattern
786
+ ])
787
+ );
788
+ const groups = /* @__PURE__ */ new Map();
789
+ for (const diagnostic of diagnostics) {
790
+ const type = typeFromSource(diagnostic.source);
791
+ const routePattern = routePatternForDiagnostic(
792
+ diagnostic,
793
+ type,
794
+ config,
795
+ routePatternBySource
796
+ );
797
+ const key = diagnosticGroupKey(diagnostic, type, routePattern);
798
+ const existing = groups.get(key);
799
+ const example = diagnosticExample(diagnostic);
800
+ if (existing) {
801
+ existing.count += 1;
802
+ if (example && !existing.examples.includes(example)) {
803
+ existing.examples.push(example);
804
+ }
805
+ existing.examples = existing.examples.slice(0, 3);
806
+ continue;
807
+ }
808
+ groups.set(key, {
809
+ key,
810
+ severity: diagnostic.severity,
811
+ code: diagnostic.code,
812
+ count: 1,
813
+ ...type ? { type } : {},
814
+ ...routePattern ? { routePattern } : {},
815
+ label: diagnosticGroupLabel(type, routePattern),
816
+ examples: example ? [example] : []
817
+ });
818
+ }
819
+ return [...groups.values()];
820
+ }
821
+ function routePatternForDiagnostic(diagnostic, type, config, routePatternBySource) {
822
+ if (!isRouteDiagnostic(diagnostic.code) && diagnostic.code !== "CMS-UID-MISSING") {
823
+ return void 0;
824
+ }
825
+ if (diagnostic.source) {
826
+ const routePattern = routePatternBySource.get(diagnostic.source);
827
+ if (routePattern) {
828
+ return routePattern;
829
+ }
830
+ }
831
+ return type ? config.routes.find((route) => route.type === type)?.pattern : void 0;
832
+ }
833
+ function isRouteDiagnostic(code) {
834
+ return code.startsWith("CMS-ROUTE");
835
+ }
836
+ function diagnosticGroupKey(diagnostic, type, routePattern) {
837
+ return [diagnostic.severity, diagnostic.code, type, routePattern].filter(Boolean).join(":");
838
+ }
839
+ function diagnosticGroupLabel(type, routePattern) {
840
+ if (type && routePattern) {
841
+ return `${type} ${routePattern}`;
842
+ }
843
+ return type ?? "project";
844
+ }
845
+ function diagnosticExample(diagnostic) {
846
+ return diagnostic.path ?? diagnostic.source ?? diagnostic.message;
847
+ }
848
+ function typeFromSource(source) {
849
+ if (!source) {
850
+ return void 0;
851
+ }
852
+ const match = /^[^:]+:([^#]+)#/.exec(source);
853
+ return match?.[1];
854
+ }
776
855
  function hasRelationshipMatch(fromValues, toValues) {
777
856
  if (fromValues.length === 0 || toValues.length === 0) {
778
857
  return false;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cms-lab/core",
3
- "version": "1.2.5",
3
+ "version": "1.2.6",
4
4
  "type": "module",
5
5
  "description": "Core config, scan, diagnostics, and checks for cms-lab.",
6
6
  "license": "MIT",