@memberjunction/react-test-harness 2.128.0 → 2.130.0

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.
@@ -1 +1 @@
1
- {"version":3,"file":"component-linter.d.ts","sourceRoot":"","sources":["../../src/lib/component-linter.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,aAAa,EAAiC,MAAM,6CAA6C,CAAC;AAI3G,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,sBAAsB,CAAC;AAErD,OAAO,EAAE,yBAAyB,EAAE,MAAM,oBAAoB,CAAC;AAU/D,MAAM,WAAW,UAAU;IACzB,OAAO,EAAE,OAAO,CAAC;IACjB,UAAU,EAAE,SAAS,EAAE,CAAC;IACxB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,OAAO,CAAC;CACpB;AAED,MAAM,WAAW,WAAW;IAC1B,SAAS,CAAC,EAAE,OAAO,CAAC;CACrB;AAED,MAAM,WAAW,SAAS;IACxB,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,UAAU,GAAG,MAAM,GAAG,QAAQ,GAAG,KAAK,CAAC;IACjD,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,MAAM,CAAC,EAAE,gBAAgB,GAAG,iBAAiB,GAAG,iBAAiB,GAAG,cAAc,CAAC;IACnF,UAAU,CAAC,EAAE;QACX,IAAI,EAAE,MAAM,CAAC;QACb,OAAO,CAAC,EAAE,MAAM,CAAC;KAClB,CAAC;CACH;AA0OD,qBAAa,eAAe;IAC1B,OAAO,CAAC,MAAM,CAAC,cAAc,CAAqB;IAGlD,OAAO,CAAC,MAAM,CAAC,iBAAiB;IAQhC,OAAO,CAAC,MAAM,CAAC,cAAc;IA8B7B,OAAO,CAAC,MAAM,CAAC,4BAA4B;IAyC3C,OAAO,CAAC,MAAM,CAAC,uBAAuB,CAg2PpC;WAEkB,uBAAuB,CAAC,IAAI,EAAE,MAAM,EAAE,aAAa,EAAE,MAAM,GAAG,OAAO,CAAC;QAAE,KAAK,EAAE,OAAO,CAAC;QAAC,MAAM,EAAE,MAAM,EAAE,CAAA;KAAE,CAAC;WAmC3G,aAAa,CAC/B,IAAI,EAAE,MAAM,EACZ,aAAa,EAAE,MAAM,EACrB,aAAa,CAAC,EAAE,aAAa,EAC7B,eAAe,CAAC,EAAE,OAAO,EACzB,WAAW,CAAC,EAAE,QAAQ,EACtB,SAAS,CAAC,EAAE,OAAO,EACnB,OAAO,CAAC,EAAE,yBAAyB,GAClC,OAAO,CAAC,UAAU,CAAC;IA4KtB,OAAO,CAAC,MAAM,CAAC,wBAAwB;IAsWvC,OAAO,CAAC,MAAM,CAAC,eAAe;IA2B9B,OAAO,CAAC,MAAM,CAAC,qBAAqB;IAyBpC;;;;OAIG;IACH,OAAO,CAAC,MAAM,CAAC,0BAA0B;IA4hCzC,OAAO,CAAC,MAAM,CAAC,8BAA8B;IA0B7C;;OAEG;mBACkB,qBAAqB;IA0H1C;;OAEG;IACH,OAAO,CAAC,MAAM,CAAC,0BAA0B;IAqDzC;;;OAGG;IACH,OAAO,CAAC,MAAM,CAAC,6BAA6B;IAwB5C;;OAEG;IACH,OAAO,CAAC,MAAM,CAAC,mBAAmB;IA+BlC;;OAEG;IACH,OAAO,CAAC,MAAM,CAAC,qBAAqB;IA+KpC;;OAEG;IACH,OAAO,CAAC,MAAM,CAAC,mBAAmB;IA2DlC;;OAEG;IACH,OAAO,CAAC,MAAM,CAAC,yBAAyB;CAqGzC"}
1
+ {"version":3,"file":"component-linter.d.ts","sourceRoot":"","sources":["../../src/lib/component-linter.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,aAAa,EAAwD,MAAM,6CAA6C,CAAC;AAIlI,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,sBAAsB,CAAC;AAErD,OAAO,EAAE,yBAAyB,EAAE,MAAM,oBAAoB,CAAC;AAU/D,MAAM,WAAW,UAAU;IACzB,OAAO,EAAE,OAAO,CAAC;IACjB,UAAU,EAAE,SAAS,EAAE,CAAC;IACxB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,OAAO,CAAC;CACpB;AAED,MAAM,WAAW,WAAW;IAC1B,SAAS,CAAC,EAAE,OAAO,CAAC;CACrB;AAED,MAAM,WAAW,SAAS;IACxB,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,UAAU,GAAG,MAAM,GAAG,QAAQ,GAAG,KAAK,CAAC;IACjD,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,MAAM,CAAC,EAAE,gBAAgB,GAAG,iBAAiB,GAAG,iBAAiB,GAAG,cAAc,CAAC;IACnF,UAAU,CAAC,EAAE;QACX,IAAI,EAAE,MAAM,CAAC;QACb,OAAO,CAAC,EAAE,MAAM,CAAC;KAClB,CAAC;CACH;AA0OD,qBAAa,eAAe;IAC1B,OAAO,CAAC,MAAM,CAAC,cAAc,CAAqB;IAGlD,OAAO,CAAC,MAAM,CAAC,iBAAiB;IAQhC,OAAO,CAAC,MAAM,CAAC,cAAc;IA8B7B,OAAO,CAAC,MAAM,CAAC,4BAA4B;IAyC3C,OAAO,CAAC,MAAM,CAAC,uBAAuB,CAu2PpC;WAEkB,uBAAuB,CAAC,IAAI,EAAE,MAAM,EAAE,aAAa,EAAE,MAAM,GAAG,OAAO,CAAC;QAAE,KAAK,EAAE,OAAO,CAAC;QAAC,MAAM,EAAE,MAAM,EAAE,CAAA;KAAE,CAAC;WAmC3G,aAAa,CAC/B,IAAI,EAAE,MAAM,EACZ,aAAa,EAAE,MAAM,EACrB,aAAa,CAAC,EAAE,aAAa,EAC7B,eAAe,CAAC,EAAE,OAAO,EACzB,WAAW,CAAC,EAAE,QAAQ,EACtB,SAAS,CAAC,EAAE,OAAO,EACnB,OAAO,CAAC,EAAE,yBAAyB,GAClC,OAAO,CAAC,UAAU,CAAC;IA4KtB,OAAO,CAAC,MAAM,CAAC,wBAAwB;IA+avC,OAAO,CAAC,MAAM,CAAC,eAAe;IA2B9B,OAAO,CAAC,MAAM,CAAC,qBAAqB;IAyBpC;;;;OAIG;IACH,OAAO,CAAC,MAAM,CAAC,0BAA0B;IA4hCzC,OAAO,CAAC,MAAM,CAAC,8BAA8B;IA0B7C;;OAEG;mBACkB,qBAAqB;IA0H1C;;OAEG;IACH,OAAO,CAAC,MAAM,CAAC,0BAA0B;IAqDzC;;;OAGG;IACH,OAAO,CAAC,MAAM,CAAC,6BAA6B;IAwB5C;;OAEG;IACH,OAAO,CAAC,MAAM,CAAC,mBAAmB;IA+BlC;;OAEG;IACH,OAAO,CAAC,MAAM,CAAC,qBAAqB;IA+KpC;;OAEG;IACH,OAAO,CAAC,MAAM,CAAC,mBAAmB;IA2DlC;;OAEG;IACH,OAAO,CAAC,MAAM,CAAC,yBAAyB;CAqGzC"}
@@ -438,7 +438,7 @@ class ComponentLinter {
438
438
  // Add data requirements validation if componentSpec is provided
439
439
  if (componentSpec?.dataRequirements?.entities) {
440
440
  try {
441
- const dataViolations = this.validateDataRequirements(ast, componentSpec);
441
+ const dataViolations = this.validateDataRequirements(ast, componentSpec, options);
442
442
  violations.push(...dataViolations);
443
443
  }
444
444
  catch (error) {
@@ -524,15 +524,28 @@ class ComponentLinter {
524
524
  };
525
525
  }
526
526
  }
527
- static validateDataRequirements(ast, componentSpec) {
527
+ static validateDataRequirements(ast, componentSpec, options) {
528
528
  const violations = [];
529
529
  // Extract entity names from dataRequirements
530
530
  const requiredEntities = new Set();
531
531
  const requiredQueries = new Set();
532
532
  // Map to store full query definitions for parameter validation
533
533
  const queryDefinitionsMap = new Map();
534
- // Map to track allowed fields per entity
534
+ // Map to track allowed fields per entity (from dataRequirements display/filter/sort arrays)
535
535
  const entityFieldsMap = new Map();
536
+ // Map to track ALL fields that exist in the entity
537
+ // Used to distinguish "field not in requirements" (medium) from "field doesn't exist" (critical)
538
+ const entityAllFieldsMap = new Map();
539
+ // FIRST: Populate entityAllFieldsMap from options.entityMetadata if provided
540
+ // This gives us the complete list of fields that actually exist in each entity
541
+ if (options?.entityMetadata && Array.isArray(options.entityMetadata)) {
542
+ for (const entity of options.entityMetadata) {
543
+ if (entity.name && entity.fields) {
544
+ const fieldNames = new Set(entity.fields.map((f) => f.name));
545
+ entityAllFieldsMap.set(entity.name, fieldNames);
546
+ }
547
+ }
548
+ }
536
549
  if (componentSpec.dataRequirements?.entities) {
537
550
  for (const entity of componentSpec.dataRequirements.entities) {
538
551
  if (entity.name) {
@@ -542,6 +555,17 @@ class ComponentLinter {
542
555
  filterFields: new Set(entity.filterFields || []),
543
556
  sortFields: new Set(entity.sortFields || []),
544
557
  });
558
+ // Build set of ALL fields from fieldMetadata if available
559
+ // Only use fieldMetadata as fallback if entityMetadata wasn't provided for this entity
560
+ if (!entityAllFieldsMap.has(entity.name) && entity.fieldMetadata && Array.isArray(entity.fieldMetadata)) {
561
+ const allFields = new Set();
562
+ for (const field of entity.fieldMetadata) {
563
+ if (field.name) {
564
+ allFields.add(field.name);
565
+ }
566
+ }
567
+ entityAllFieldsMap.set(entity.name, allFields);
568
+ }
545
569
  }
546
570
  }
547
571
  }
@@ -574,6 +598,17 @@ class ComponentLinter {
574
598
  sortFields: new Set(entity.sortFields || []),
575
599
  });
576
600
  }
601
+ // Merge fieldMetadata into allFields map only if entityMetadata wasn't provided
602
+ // If entityMetadata was provided, it already has the complete field list
603
+ if (!entityAllFieldsMap.has(entity.name) && entity.fieldMetadata && Array.isArray(entity.fieldMetadata)) {
604
+ const existingAll = new Set();
605
+ for (const field of entity.fieldMetadata) {
606
+ if (field.name) {
607
+ existingAll.add(field.name);
608
+ }
609
+ }
610
+ entityAllFieldsMap.set(entity.name, existingAll);
611
+ }
577
612
  }
578
613
  }
579
614
  }
@@ -672,18 +707,35 @@ class ComponentLinter {
672
707
  // Check if field is in allowed fields
673
708
  const isAllowed = entityFields.displayFields.has(fieldName) || entityFields.filterFields.has(fieldName) || entityFields.sortFields.has(fieldName);
674
709
  if (!isAllowed) {
675
- violations.push({
676
- rule: 'field-not-in-requirements',
677
- severity: 'critical',
678
- line: fieldElement.loc?.start.line || 0,
679
- column: fieldElement.loc?.start.column || 0,
680
- message: `Field "${fieldName}" not found in dataRequirements for entity "${usedEntity}". Available fields: ${[
681
- ...entityFields.displayFields,
682
- ...entityFields.filterFields,
683
- ...entityFields.sortFields,
684
- ].join(', ')}`,
685
- code: fieldName,
686
- });
710
+ // Check if field exists in entity metadata (two-tier severity)
711
+ const allFields = entityAllFieldsMap.get(usedEntity);
712
+ const existsInEntity = allFields ? allFields.has(fieldName) : false;
713
+ if (existsInEntity) {
714
+ // Field exists but not in dataRequirements - medium severity (works but suboptimal)
715
+ violations.push({
716
+ rule: 'field-not-in-requirements',
717
+ severity: 'medium',
718
+ line: fieldElement.loc?.start.line || 0,
719
+ column: fieldElement.loc?.start.column || 0,
720
+ message: `Field "${fieldName}" exists in entity "${usedEntity}" but not declared in dataRequirements. Consider adding to displayFields, filterFields, or sortFields.`,
721
+ code: fieldName,
722
+ });
723
+ }
724
+ else {
725
+ // Field doesn't exist in entity - critical severity (will fail at runtime)
726
+ violations.push({
727
+ rule: 'field-not-in-requirements',
728
+ severity: 'critical',
729
+ line: fieldElement.loc?.start.line || 0,
730
+ column: fieldElement.loc?.start.column || 0,
731
+ message: `Field "${fieldName}" does not exist in entity "${usedEntity}". Available fields: ${[
732
+ ...entityFields.displayFields,
733
+ ...entityFields.filterFields,
734
+ ...entityFields.sortFields,
735
+ ].join(', ')}`,
736
+ code: fieldName,
737
+ });
738
+ }
687
739
  }
688
740
  }
689
741
  }
@@ -696,16 +748,33 @@ class ComponentLinter {
696
748
  // Extract field name from OrderBy (e.g., "AccountName ASC" -> "AccountName")
697
749
  const orderByField = orderByValue.split(/\s+/)[0];
698
750
  if (!entityFields.sortFields.has(orderByField)) {
699
- violations.push({
700
- rule: 'orderby-field-not-sortable',
701
- severity: 'critical',
702
- line: orderByProperty.value.loc?.start.line || 0,
703
- column: orderByProperty.value.loc?.start.column || 0,
704
- message: `OrderBy field "${orderByField}" not in sortFields for entity "${usedEntity}". Available sort fields: ${[
705
- ...entityFields.sortFields,
706
- ].join(', ')}`,
707
- code: orderByValue,
708
- });
751
+ // Check if field exists in entity metadata (two-tier severity)
752
+ const allFields = entityAllFieldsMap.get(usedEntity);
753
+ const existsInEntity = allFields ? allFields.has(orderByField) : false;
754
+ if (existsInEntity) {
755
+ // Field exists but not in sortFields - medium severity (works but suboptimal)
756
+ violations.push({
757
+ rule: 'orderby-field-not-sortable',
758
+ severity: 'medium',
759
+ line: orderByProperty.value.loc?.start.line || 0,
760
+ column: orderByProperty.value.loc?.start.column || 0,
761
+ message: `OrderBy field "${orderByField}" exists in entity "${usedEntity}" but not declared in sortFields. Consider adding for optimization.`,
762
+ code: orderByValue,
763
+ });
764
+ }
765
+ else {
766
+ // Field doesn't exist in entity - critical severity (will fail at runtime)
767
+ violations.push({
768
+ rule: 'orderby-field-not-sortable',
769
+ severity: 'critical',
770
+ line: orderByProperty.value.loc?.start.line || 0,
771
+ column: orderByProperty.value.loc?.start.column || 0,
772
+ message: `OrderBy field "${orderByField}" does not exist in entity "${usedEntity}". Available sort fields: ${[
773
+ ...entityFields.sortFields,
774
+ ].join(', ')}`,
775
+ code: orderByValue,
776
+ });
777
+ }
709
778
  }
710
779
  }
711
780
  }
@@ -4950,8 +5019,15 @@ Valid properties: QueryID, QueryName, CategoryID, CategoryPath, Parameters, MaxR
4950
5019
  });
4951
5020
  }
4952
5021
  }
4953
- // Case 3: Parameters is neither array nor object
4954
- else if (!t.isObjectExpression(paramValue)) {
5022
+ // Case 3: Parameters is a valid format we can't or don't need to validate further
5023
+ // - Variable reference (e.g., Parameters: statusParams) - can't validate without scope tracking
5024
+ // - Object expression without spec query params - nothing to validate against
5025
+ else if (t.isIdentifier(paramValue) || t.isObjectExpression(paramValue)) {
5026
+ // Valid format - skip further validation
5027
+ // Either a variable reference or an object when we have no spec to validate against
5028
+ }
5029
+ // Case 4: Parameters is neither array, object, nor variable reference
5030
+ else {
4955
5031
  let fixCode;
4956
5032
  let message;
4957
5033
  if (specQuery?.parameters && specQuery.parameters.length > 0) {