@memberjunction/react-test-harness 2.127.0 → 2.129.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.
- package/dist/lib/component-linter.d.ts.map +1 -1
- package/dist/lib/component-linter.js +103 -27
- package/dist/lib/component-linter.js.map +1 -1
- package/dist/lib/component-runner.d.ts +50 -1
- package/dist/lib/component-runner.d.ts.map +1 -1
- package/dist/lib/component-runner.js +96 -13
- package/dist/lib/component-runner.js.map +1 -1
- package/package.json +9 -8
- package/dist/lib/test-broken-7.d.ts +0 -2
- package/dist/lib/test-broken-7.d.ts.map +0 -1
- package/dist/lib/test-broken-7.js +0 -73
- package/dist/lib/test-broken-7.js.map +0 -1
- package/dist/lib/test-broken-9.d.ts +0 -3
- package/dist/lib/test-broken-9.d.ts.map +0 -1
- package/dist/lib/test-broken-9.js +0 -122
- package/dist/lib/test-broken-9.js.map +0 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"component-linter.d.ts","sourceRoot":"","sources":["../../src/lib/component-linter.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,aAAa,
|
|
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
|
-
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
|
|
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
|
-
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
|
|
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
|
|
4954
|
-
|
|
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) {
|