@memberjunction/react-test-harness 2.99.0 → 2.100.1
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 +192 -0
- package/dist/lib/component-linter.js.map +1 -1
- package/dist/lib/component-runner.d.ts.map +1 -1
- package/dist/lib/component-runner.js +122 -20
- package/dist/lib/component-runner.js.map +1 -1
- package/dist/lib/test-broken-9.d.ts +3 -0
- package/dist/lib/test-broken-9.d.ts.map +1 -0
- package/dist/lib/test-broken-9.js +122 -0
- package/dist/lib/test-broken-9.js.map +1 -0
- package/package.json +3 -3
|
@@ -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;AAG3G,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,sBAAsB,CAAC;AAErD,OAAO,EAAE,yBAAyB,EAAE,MAAM,oBAAoB,CAAC;AAG/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;AAiFD,qBAAa,eAAe;IAC1B,OAAO,CAAC,MAAM,CAAC,cAAc,CAAqB;IAGlD,OAAO,CAAC,MAAM,CAAC,iBAAiB;IAQhC,OAAO,CAAC,MAAM,CAAC,cAAc;IAoB7B,OAAO,CAAC,MAAM,CAAC,4BAA4B;IA2C3C,OAAO,CAAC,MAAM,CAAC,uBAAuB,
|
|
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;AAG3G,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,sBAAsB,CAAC;AAErD,OAAO,EAAE,yBAAyB,EAAE,MAAM,oBAAoB,CAAC;AAG/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;AAiFD,qBAAa,eAAe;IAC1B,OAAO,CAAC,MAAM,CAAC,cAAc,CAAqB;IAGlD,OAAO,CAAC,MAAM,CAAC,iBAAiB;IAQhC,OAAO,CAAC,MAAM,CAAC,cAAc;IAoB7B,OAAO,CAAC,MAAM,CAAC,4BAA4B;IA2C3C,OAAO,CAAC,MAAM,CAAC,uBAAuB,CA8hOpC;WAEkB,uBAAuB,CACzC,IAAI,EAAE,MAAM,EACZ,aAAa,EAAE,MAAM,GACpB,OAAO,CAAC;QAAE,KAAK,EAAE,OAAO,CAAC;QAAC,MAAM,EAAE,MAAM,EAAE,CAAA;KAAE,CAAC;WAmC5B,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;IAqJtB,OAAO,CAAC,MAAM,CAAC,wBAAwB;IAoXvC,OAAO,CAAC,MAAM,CAAC,eAAe;IA2B9B,OAAO,CAAC,MAAM,CAAC,qBAAqB;IAyBpC;;;;OAIG;IACH,OAAO,CAAC,MAAM,CAAC,0BAA0B;IA6hCzC,OAAO,CAAC,MAAM,CAAC,8BAA8B;IA2B7C;;OAEG;mBACkB,qBAAqB;IAuJ1C;;OAEG;IACH,OAAO,CAAC,MAAM,CAAC,0BAA0B;IAiEzC;;OAEG;IACH,OAAO,CAAC,MAAM,CAAC,mBAAmB;IA8ClC;;OAEG;IACH,OAAO,CAAC,MAAM,CAAC,qBAAqB;IA8GpC;;OAEG;IACH,OAAO,CAAC,MAAM,CAAC,mBAAmB;IAoElC;;OAEG;IACH,OAAO,CAAC,MAAM,CAAC,yBAAyB;CAkGzC"}
|
|
@@ -8460,6 +8460,198 @@ ${eventName}?.(data);`
|
|
|
8460
8460
|
});
|
|
8461
8461
|
return violations;
|
|
8462
8462
|
}
|
|
8463
|
+
},
|
|
8464
|
+
{
|
|
8465
|
+
name: 'callbacks-passthrough-only',
|
|
8466
|
+
appliesTo: 'all',
|
|
8467
|
+
test: (ast, _componentName, _componentSpec) => {
|
|
8468
|
+
const violations = [];
|
|
8469
|
+
(0, traverse_1.default)(ast, {
|
|
8470
|
+
JSXAttribute(path) {
|
|
8471
|
+
// Check if this is a callbacks prop being passed to a component
|
|
8472
|
+
if (t.isJSXIdentifier(path.node.name) && path.node.name.name === 'callbacks') {
|
|
8473
|
+
const value = path.node.value;
|
|
8474
|
+
// Check if value is a JSXExpressionContainer
|
|
8475
|
+
if (t.isJSXExpressionContainer(value)) {
|
|
8476
|
+
const expr = value.expression;
|
|
8477
|
+
// Valid patterns:
|
|
8478
|
+
// - callbacks={callbacks}
|
|
8479
|
+
// - callbacks={props.callbacks}
|
|
8480
|
+
// - callbacks={restProps.callbacks}
|
|
8481
|
+
const isValidPassthrough = (t.isIdentifier(expr) && expr.name === 'callbacks') ||
|
|
8482
|
+
(t.isMemberExpression(expr) &&
|
|
8483
|
+
t.isIdentifier(expr.property) &&
|
|
8484
|
+
expr.property.name === 'callbacks');
|
|
8485
|
+
if (!isValidPassthrough) {
|
|
8486
|
+
// Check for spreading pattern: {...callbacks, ...}
|
|
8487
|
+
if (t.isObjectExpression(expr)) {
|
|
8488
|
+
const hasSpread = expr.properties.some(prop => t.isSpreadElement(prop) &&
|
|
8489
|
+
t.isIdentifier(prop.argument) &&
|
|
8490
|
+
prop.argument.name === 'callbacks');
|
|
8491
|
+
if (hasSpread) {
|
|
8492
|
+
// Found spreading callbacks with additional properties
|
|
8493
|
+
const addedProps = expr.properties
|
|
8494
|
+
.filter(prop => !t.isSpreadElement(prop) && t.isObjectProperty(prop))
|
|
8495
|
+
.map(prop => {
|
|
8496
|
+
if (t.isObjectProperty(prop)) {
|
|
8497
|
+
if (t.isIdentifier(prop.key)) {
|
|
8498
|
+
return prop.key.name;
|
|
8499
|
+
}
|
|
8500
|
+
else if (t.isStringLiteral(prop.key)) {
|
|
8501
|
+
return prop.key.value;
|
|
8502
|
+
}
|
|
8503
|
+
}
|
|
8504
|
+
return 'unknown';
|
|
8505
|
+
});
|
|
8506
|
+
violations.push({
|
|
8507
|
+
rule: 'callbacks-passthrough-only',
|
|
8508
|
+
severity: 'critical',
|
|
8509
|
+
line: path.node.loc?.start.line || 0,
|
|
8510
|
+
column: path.node.loc?.start.column || 0,
|
|
8511
|
+
message: `Callbacks must be passed through unchanged. Found spreading with additional properties: ${addedProps.join(', ')}. Component events should be passed as direct props, not added to callbacks.`,
|
|
8512
|
+
suggestion: {
|
|
8513
|
+
text: `The callbacks prop should only contain OpenEntityRecord and RegisterMethod. Pass component events as separate props.`,
|
|
8514
|
+
example: `// ❌ WRONG - Modifying callbacks
|
|
8515
|
+
<ChildComponent
|
|
8516
|
+
callbacks={{ ...callbacks, onOpen: handleOpen }}
|
|
8517
|
+
/>
|
|
8518
|
+
|
|
8519
|
+
// ✅ CORRECT - Pass callbacks unchanged, events as props
|
|
8520
|
+
<ChildComponent
|
|
8521
|
+
callbacks={callbacks}
|
|
8522
|
+
onOpen={handleOpen}
|
|
8523
|
+
/>`
|
|
8524
|
+
}
|
|
8525
|
+
});
|
|
8526
|
+
}
|
|
8527
|
+
else if (expr.properties.length > 0) {
|
|
8528
|
+
// Creating new callbacks object
|
|
8529
|
+
violations.push({
|
|
8530
|
+
rule: 'callbacks-passthrough-only',
|
|
8531
|
+
severity: 'critical',
|
|
8532
|
+
line: path.node.loc?.start.line || 0,
|
|
8533
|
+
column: path.node.loc?.start.column || 0,
|
|
8534
|
+
message: `Callbacks must be passed through unchanged. Do not create new callback objects. Pass the callbacks prop directly.`,
|
|
8535
|
+
suggestion: {
|
|
8536
|
+
text: `Pass callbacks directly without modification.`,
|
|
8537
|
+
example: `// ❌ WRONG - Creating new callbacks object
|
|
8538
|
+
<ChildComponent
|
|
8539
|
+
callbacks={{ OpenEntityRecord: customHandler }}
|
|
8540
|
+
/>
|
|
8541
|
+
|
|
8542
|
+
// ✅ CORRECT - Pass callbacks unchanged
|
|
8543
|
+
<ChildComponent
|
|
8544
|
+
callbacks={callbacks}
|
|
8545
|
+
/>`
|
|
8546
|
+
}
|
|
8547
|
+
});
|
|
8548
|
+
}
|
|
8549
|
+
}
|
|
8550
|
+
// Check for conditional expressions
|
|
8551
|
+
else if (t.isConditionalExpression(expr) || t.isLogicalExpression(expr)) {
|
|
8552
|
+
violations.push({
|
|
8553
|
+
rule: 'callbacks-passthrough-only',
|
|
8554
|
+
severity: 'medium',
|
|
8555
|
+
line: path.node.loc?.start.line || 0,
|
|
8556
|
+
column: path.node.loc?.start.column || 0,
|
|
8557
|
+
message: `Callbacks should be passed through directly without conditional logic. Consider handling the condition at a higher level.`,
|
|
8558
|
+
suggestion: {
|
|
8559
|
+
text: `Pass callbacks directly or handle conditions in parent component.`,
|
|
8560
|
+
example: `// ⚠️ AVOID - Conditional callbacks
|
|
8561
|
+
<ChildComponent
|
|
8562
|
+
callbacks={someCondition ? callbacks : undefined}
|
|
8563
|
+
/>
|
|
8564
|
+
|
|
8565
|
+
// ✅ BETTER - Pass callbacks directly
|
|
8566
|
+
<ChildComponent
|
|
8567
|
+
callbacks={callbacks}
|
|
8568
|
+
/>`
|
|
8569
|
+
}
|
|
8570
|
+
});
|
|
8571
|
+
}
|
|
8572
|
+
// Check for function calls or other expressions
|
|
8573
|
+
else if (!t.isIdentifier(expr) && !t.isMemberExpression(expr)) {
|
|
8574
|
+
violations.push({
|
|
8575
|
+
rule: 'callbacks-passthrough-only',
|
|
8576
|
+
severity: 'critical',
|
|
8577
|
+
line: path.node.loc?.start.line || 0,
|
|
8578
|
+
column: path.node.loc?.start.column || 0,
|
|
8579
|
+
message: `Callbacks must be passed through unchanged. Found complex expression instead of direct passthrough.`,
|
|
8580
|
+
suggestion: {
|
|
8581
|
+
text: `Pass the callbacks prop directly without modification.`,
|
|
8582
|
+
example: `// ✅ CORRECT
|
|
8583
|
+
<ChildComponent callbacks={callbacks} />`
|
|
8584
|
+
}
|
|
8585
|
+
});
|
|
8586
|
+
}
|
|
8587
|
+
}
|
|
8588
|
+
}
|
|
8589
|
+
}
|
|
8590
|
+
},
|
|
8591
|
+
// Also check for Object.assign or spread operations on callbacks
|
|
8592
|
+
CallExpression(path) {
|
|
8593
|
+
// Check for Object.assign(callbacks, ...)
|
|
8594
|
+
if (t.isMemberExpression(path.node.callee) &&
|
|
8595
|
+
t.isIdentifier(path.node.callee.object) &&
|
|
8596
|
+
path.node.callee.object.name === 'Object' &&
|
|
8597
|
+
t.isIdentifier(path.node.callee.property) &&
|
|
8598
|
+
path.node.callee.property.name === 'assign') {
|
|
8599
|
+
const args = path.node.arguments;
|
|
8600
|
+
if (args.length > 0) {
|
|
8601
|
+
// Check if callbacks is being modified
|
|
8602
|
+
const hasCallbacks = args.some(arg => t.isIdentifier(arg) && arg.name === 'callbacks');
|
|
8603
|
+
if (hasCallbacks) {
|
|
8604
|
+
violations.push({
|
|
8605
|
+
rule: 'callbacks-passthrough-only',
|
|
8606
|
+
severity: 'critical',
|
|
8607
|
+
line: path.node.loc?.start.line || 0,
|
|
8608
|
+
column: path.node.loc?.start.column || 0,
|
|
8609
|
+
message: `Do not modify callbacks with Object.assign. Callbacks should be passed through unchanged.`,
|
|
8610
|
+
suggestion: {
|
|
8611
|
+
text: `Pass callbacks directly and use separate props for component events.`,
|
|
8612
|
+
example: `// ❌ WRONG
|
|
8613
|
+
const modifiedCallbacks = Object.assign({}, callbacks, { onOpen: handler });
|
|
8614
|
+
|
|
8615
|
+
// ✅ CORRECT - Keep callbacks separate from events
|
|
8616
|
+
<Component callbacks={callbacks} onOpen={handler} />`
|
|
8617
|
+
}
|
|
8618
|
+
});
|
|
8619
|
+
}
|
|
8620
|
+
}
|
|
8621
|
+
}
|
|
8622
|
+
},
|
|
8623
|
+
// Check for variable assignments that modify callbacks
|
|
8624
|
+
VariableDeclarator(path) {
|
|
8625
|
+
if (t.isObjectExpression(path.node.init)) {
|
|
8626
|
+
const hasCallbacksSpread = path.node.init.properties.some(prop => t.isSpreadElement(prop) &&
|
|
8627
|
+
t.isIdentifier(prop.argument) &&
|
|
8628
|
+
prop.argument.name === 'callbacks');
|
|
8629
|
+
if (hasCallbacksSpread) {
|
|
8630
|
+
const hasAdditionalProps = path.node.init.properties.some(prop => !t.isSpreadElement(prop));
|
|
8631
|
+
if (hasAdditionalProps) {
|
|
8632
|
+
violations.push({
|
|
8633
|
+
rule: 'callbacks-passthrough-only',
|
|
8634
|
+
severity: 'critical',
|
|
8635
|
+
line: path.node.loc?.start.line || 0,
|
|
8636
|
+
column: path.node.loc?.start.column || 0,
|
|
8637
|
+
message: `Do not create modified copies of callbacks. Pass callbacks unchanged and use separate props for events.`,
|
|
8638
|
+
suggestion: {
|
|
8639
|
+
text: `Keep callbacks immutable and pass component events as separate props.`,
|
|
8640
|
+
example: `// ❌ WRONG
|
|
8641
|
+
const extendedCallbacks = { ...callbacks, onCustomEvent: handler };
|
|
8642
|
+
|
|
8643
|
+
// ✅ CORRECT - Keep them separate
|
|
8644
|
+
// Pass to child component:
|
|
8645
|
+
<Component callbacks={callbacks} onCustomEvent={handler} />`
|
|
8646
|
+
}
|
|
8647
|
+
});
|
|
8648
|
+
}
|
|
8649
|
+
}
|
|
8650
|
+
}
|
|
8651
|
+
}
|
|
8652
|
+
});
|
|
8653
|
+
return violations;
|
|
8654
|
+
}
|
|
8463
8655
|
}
|
|
8464
8656
|
];
|
|
8465
8657
|
//# sourceMappingURL=component-linter.js.map
|