@fedify/lint 2.2.0-dev.869 → 2.2.0-pr.695.23
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/deno.json +1 -1
- package/dist/index.cjs +44 -300
- package/dist/index.js +44 -300
- package/package.json +2 -2
package/deno.json
CHANGED
package/dist/index.cjs
CHANGED
|
@@ -29,7 +29,7 @@ let _typescript_eslint_parser = require("@typescript-eslint/parser");
|
|
|
29
29
|
_typescript_eslint_parser = __toESM(_typescript_eslint_parser);
|
|
30
30
|
//#region deno.json
|
|
31
31
|
var name = "@fedify/lint";
|
|
32
|
-
var version = "2.2.0-
|
|
32
|
+
var version = "2.2.0-pr.695.23+d0b31ca2";
|
|
33
33
|
//#endregion
|
|
34
34
|
//#region src/lib/const.ts
|
|
35
35
|
/**
|
|
@@ -146,8 +146,7 @@ const RULE_IDS = {
|
|
|
146
146
|
actorFeaturedTagsPropertyMismatch: "actor-featured-tags-property-mismatch",
|
|
147
147
|
actorInboxPropertyMismatch: "actor-inbox-property-mismatch",
|
|
148
148
|
actorSharedInboxPropertyMismatch: "actor-shared-inbox-property-mismatch",
|
|
149
|
-
collectionFilteringNotImplemented: "collection-filtering-not-implemented"
|
|
150
|
-
outboxListenerDeliveryRequired: "outbox-listener-delivery-required"
|
|
149
|
+
collectionFilteringNotImplemented: "collection-filtering-not-implemented"
|
|
151
150
|
};
|
|
152
151
|
//#endregion
|
|
153
152
|
//#region src/lib/messages.ts
|
|
@@ -192,7 +191,6 @@ function allOf(...predicates) {
|
|
|
192
191
|
return (value) => predicates.every((predicate) => predicate(value));
|
|
193
192
|
}
|
|
194
193
|
const anyOf = (...predicates) => (value) => predicates.some((predicate) => predicate(value));
|
|
195
|
-
const isNode = (obj) => (0, _fxts_core.isObject)(obj) && "type" in obj;
|
|
196
194
|
/**
|
|
197
195
|
* Checks if a node is of a specific type.
|
|
198
196
|
*/
|
|
@@ -445,7 +443,7 @@ function createRequiredRuleEslint(config) {
|
|
|
445
443
|
};
|
|
446
444
|
}
|
|
447
445
|
createRequiredRuleDeno(properties.assertionMethod);
|
|
448
|
-
const eslint$
|
|
446
|
+
const eslint$20 = createRequiredRuleEslint(properties.assertionMethod);
|
|
449
447
|
//#endregion
|
|
450
448
|
//#region src/lib/mismatch.ts
|
|
451
449
|
const isIdentifierWithName = (name) => (node) => allOf(isNodeType("Identifier"), isNodeName(name))(node);
|
|
@@ -515,43 +513,43 @@ const createMismatchRuleEslint = (config) => ({
|
|
|
515
513
|
}))
|
|
516
514
|
});
|
|
517
515
|
createMismatchRuleDeno(properties.featured);
|
|
518
|
-
const eslint$
|
|
516
|
+
const eslint$19 = createMismatchRuleEslint(properties.featured);
|
|
519
517
|
createRequiredRuleDeno(properties.featured);
|
|
520
|
-
const eslint$
|
|
518
|
+
const eslint$18 = createRequiredRuleEslint(properties.featured);
|
|
521
519
|
createMismatchRuleDeno(properties.featuredTags);
|
|
522
|
-
const eslint$
|
|
520
|
+
const eslint$17 = createMismatchRuleEslint(properties.featuredTags);
|
|
523
521
|
createRequiredRuleDeno(properties.featuredTags);
|
|
524
|
-
const eslint$
|
|
522
|
+
const eslint$16 = createRequiredRuleEslint(properties.featuredTags);
|
|
525
523
|
createMismatchRuleDeno(properties.followers);
|
|
526
|
-
const eslint$
|
|
524
|
+
const eslint$15 = createMismatchRuleEslint(properties.followers);
|
|
527
525
|
createRequiredRuleDeno(properties.followers);
|
|
528
|
-
const eslint$
|
|
526
|
+
const eslint$14 = createRequiredRuleEslint(properties.followers);
|
|
529
527
|
createMismatchRuleDeno(properties.following);
|
|
530
|
-
const eslint$
|
|
528
|
+
const eslint$13 = createMismatchRuleEslint(properties.following);
|
|
531
529
|
createRequiredRuleDeno(properties.following);
|
|
532
|
-
const eslint$
|
|
530
|
+
const eslint$12 = createRequiredRuleEslint(properties.following);
|
|
533
531
|
createMismatchRuleDeno(properties.id);
|
|
534
|
-
const eslint$
|
|
532
|
+
const eslint$11 = createMismatchRuleEslint(properties.id);
|
|
535
533
|
createRequiredRuleDeno(properties.id);
|
|
536
|
-
const eslint$
|
|
534
|
+
const eslint$10 = createRequiredRuleEslint(properties.id);
|
|
537
535
|
createMismatchRuleDeno(properties.inbox);
|
|
538
|
-
const eslint$
|
|
536
|
+
const eslint$9 = createMismatchRuleEslint(properties.inbox);
|
|
539
537
|
createRequiredRuleDeno(properties.inbox);
|
|
540
|
-
const eslint$
|
|
538
|
+
const eslint$8 = createRequiredRuleEslint(properties.inbox);
|
|
541
539
|
createMismatchRuleDeno(properties.liked);
|
|
542
|
-
const eslint$
|
|
540
|
+
const eslint$7 = createMismatchRuleEslint(properties.liked);
|
|
543
541
|
createRequiredRuleDeno(properties.liked);
|
|
544
|
-
const eslint$
|
|
542
|
+
const eslint$6 = createRequiredRuleEslint(properties.liked);
|
|
545
543
|
createMismatchRuleDeno(properties.outbox);
|
|
546
|
-
const eslint$
|
|
544
|
+
const eslint$5 = createMismatchRuleEslint(properties.outbox);
|
|
547
545
|
createRequiredRuleDeno(properties.outbox);
|
|
548
|
-
const eslint$
|
|
546
|
+
const eslint$4 = createRequiredRuleEslint(properties.outbox);
|
|
549
547
|
createRequiredRuleDeno(properties.publicKey);
|
|
550
|
-
const eslint$
|
|
548
|
+
const eslint$3 = createRequiredRuleEslint(properties.publicKey);
|
|
551
549
|
createMismatchRuleDeno(properties.sharedInbox);
|
|
552
|
-
const eslint$
|
|
550
|
+
const eslint$2 = createMismatchRuleEslint(properties.sharedInbox);
|
|
553
551
|
createRequiredRuleDeno(properties.sharedInbox);
|
|
554
|
-
const eslint$
|
|
552
|
+
const eslint$1 = createRequiredRuleEslint(properties.sharedInbox);
|
|
555
553
|
//#endregion
|
|
556
554
|
//#region src/rules/collection-filtering-not-implemented.ts
|
|
557
555
|
/**
|
|
@@ -570,7 +568,7 @@ const isFollowersDispatcherCall = (node) => "callee" in node && node.callee && n
|
|
|
570
568
|
* CollectionDispatcher signature: (context, identifier, cursor, filter?) => ...
|
|
571
569
|
*/
|
|
572
570
|
const hasFilterParameter = hasMinParams(4);
|
|
573
|
-
const eslint
|
|
571
|
+
const eslint = {
|
|
574
572
|
meta: {
|
|
575
573
|
type: "suggestion",
|
|
576
574
|
docs: { description: "Ensure followers dispatcher implements filtering" },
|
|
@@ -595,287 +593,33 @@ const eslint$1 = {
|
|
|
595
593
|
}
|
|
596
594
|
};
|
|
597
595
|
//#endregion
|
|
598
|
-
//#region src/rules/outbox-listener-delivery-required.ts
|
|
599
|
-
const MESSAGE = "Outbox listeners should deliver posted activities explicitly with ctx.sendActivity() or ctx.forwardActivity().";
|
|
600
|
-
const isChainedFromOutboxListeners = (expr, federationTracker) => {
|
|
601
|
-
if (expr.type !== "CallExpression") return false;
|
|
602
|
-
if (!hasMemberExpressionCallee(expr) || !hasIdentifierProperty(expr)) return false;
|
|
603
|
-
const methodName = expr.callee.property.name;
|
|
604
|
-
if (methodName === "setOutboxListeners") return federationTracker.isFederationObject(expr.callee.object);
|
|
605
|
-
if (methodName === "authorize" || methodName === "onError" || methodName === "on") return isChainedFromOutboxListeners(expr.callee.object, federationTracker);
|
|
606
|
-
return false;
|
|
607
|
-
};
|
|
608
|
-
const DELIVERY_METHOD_NAMES = new Set(["sendActivity", "forwardActivity"]);
|
|
609
|
-
const getMemberPropertyName = (expr) => {
|
|
610
|
-
if (expr.type !== "MemberExpression") return null;
|
|
611
|
-
const property = expr.property;
|
|
612
|
-
if (property.type === "Identifier") return property.name;
|
|
613
|
-
if (property.type === "Literal" && typeof property.value === "string") return property.value;
|
|
614
|
-
return null;
|
|
615
|
-
};
|
|
616
|
-
function unwrapContextParam(node) {
|
|
617
|
-
let current = node ?? null;
|
|
618
|
-
while (current?.type === "AssignmentPattern") current = current.left;
|
|
619
|
-
return current;
|
|
620
|
-
}
|
|
621
|
-
function escapeRegExp(value) {
|
|
622
|
-
return value.replaceAll(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
623
|
-
}
|
|
624
|
-
function stripCommentsAndStrings(code) {
|
|
625
|
-
let result = "";
|
|
626
|
-
let index = 0;
|
|
627
|
-
const skipQuotedString = (quote) => {
|
|
628
|
-
const start = index;
|
|
629
|
-
index += 1;
|
|
630
|
-
while (index < code.length) {
|
|
631
|
-
const char = code[index];
|
|
632
|
-
if (char === "\\") {
|
|
633
|
-
index += 2;
|
|
634
|
-
continue;
|
|
635
|
-
}
|
|
636
|
-
index += 1;
|
|
637
|
-
if (char === quote) break;
|
|
638
|
-
}
|
|
639
|
-
const literal = code.slice(start, index);
|
|
640
|
-
const value = literal.slice(1, -1);
|
|
641
|
-
result += DELIVERY_METHOD_NAMES.has(value) ? literal : `${quote}${quote}`;
|
|
642
|
-
};
|
|
643
|
-
const stripTemplateLiteral = () => {
|
|
644
|
-
const start = index;
|
|
645
|
-
index += 1;
|
|
646
|
-
let raw = "";
|
|
647
|
-
let hasExpression = false;
|
|
648
|
-
while (index < code.length) {
|
|
649
|
-
const char = code[index];
|
|
650
|
-
if (char === "\\") {
|
|
651
|
-
raw += char;
|
|
652
|
-
raw += code[index + 1] ?? "";
|
|
653
|
-
index += 2;
|
|
654
|
-
continue;
|
|
655
|
-
}
|
|
656
|
-
if (char === "`") {
|
|
657
|
-
index += 1;
|
|
658
|
-
if (!hasExpression && DELIVERY_METHOD_NAMES.has(raw)) result += code.slice(start, index);
|
|
659
|
-
else result += "``";
|
|
660
|
-
return;
|
|
661
|
-
}
|
|
662
|
-
if (char === "$" && code[index + 1] === "{") {
|
|
663
|
-
hasExpression = true;
|
|
664
|
-
result += "`${";
|
|
665
|
-
index += 2;
|
|
666
|
-
let depth = 1;
|
|
667
|
-
while (index < code.length && depth > 0) {
|
|
668
|
-
const exprChar = code[index];
|
|
669
|
-
const next = code[index + 1];
|
|
670
|
-
if (exprChar === "'" || exprChar === "\"") {
|
|
671
|
-
skipQuotedString(exprChar);
|
|
672
|
-
continue;
|
|
673
|
-
}
|
|
674
|
-
if (exprChar === "`") {
|
|
675
|
-
stripTemplateLiteral();
|
|
676
|
-
continue;
|
|
677
|
-
}
|
|
678
|
-
if (exprChar === "/" && next === "*") {
|
|
679
|
-
index += 2;
|
|
680
|
-
while (index < code.length) {
|
|
681
|
-
if (code[index] === "*" && code[index + 1] === "/") {
|
|
682
|
-
index += 2;
|
|
683
|
-
break;
|
|
684
|
-
}
|
|
685
|
-
index += 1;
|
|
686
|
-
}
|
|
687
|
-
continue;
|
|
688
|
-
}
|
|
689
|
-
if (exprChar === "/" && next === "/") {
|
|
690
|
-
index += 2;
|
|
691
|
-
while (index < code.length && code[index] !== "\n") index += 1;
|
|
692
|
-
continue;
|
|
693
|
-
}
|
|
694
|
-
result += exprChar;
|
|
695
|
-
index += 1;
|
|
696
|
-
if (exprChar === "{") depth += 1;
|
|
697
|
-
else if (exprChar === "}") depth -= 1;
|
|
698
|
-
}
|
|
699
|
-
continue;
|
|
700
|
-
}
|
|
701
|
-
raw += char;
|
|
702
|
-
index += 1;
|
|
703
|
-
}
|
|
704
|
-
result += "``";
|
|
705
|
-
};
|
|
706
|
-
while (index < code.length) {
|
|
707
|
-
const char = code[index];
|
|
708
|
-
const next = code[index + 1];
|
|
709
|
-
if (char === "/" && next === "*") {
|
|
710
|
-
index += 2;
|
|
711
|
-
while (index < code.length) {
|
|
712
|
-
if (code[index] === "*" && code[index + 1] === "/") {
|
|
713
|
-
index += 2;
|
|
714
|
-
break;
|
|
715
|
-
}
|
|
716
|
-
index += 1;
|
|
717
|
-
}
|
|
718
|
-
continue;
|
|
719
|
-
}
|
|
720
|
-
if (char === "/" && next === "/") {
|
|
721
|
-
index += 2;
|
|
722
|
-
while (index < code.length && code[index] !== "\n") index += 1;
|
|
723
|
-
continue;
|
|
724
|
-
}
|
|
725
|
-
if (char === "'" || char === "\"") {
|
|
726
|
-
skipQuotedString(char);
|
|
727
|
-
continue;
|
|
728
|
-
}
|
|
729
|
-
if (char === "`") {
|
|
730
|
-
stripTemplateLiteral();
|
|
731
|
-
continue;
|
|
732
|
-
}
|
|
733
|
-
result += char;
|
|
734
|
-
index += 1;
|
|
735
|
-
}
|
|
736
|
-
return result;
|
|
737
|
-
}
|
|
738
|
-
function getDeliveryAliasName(node) {
|
|
739
|
-
if (node.type === "Identifier") return node.name;
|
|
740
|
-
if (node.type === "AssignmentPattern" && node.left.type === "Identifier") return node.left.name;
|
|
741
|
-
return null;
|
|
742
|
-
}
|
|
743
|
-
function buildContextExpressionPattern(contextName) {
|
|
744
|
-
const name = escapeRegExp(contextName);
|
|
745
|
-
const boundedName = String.raw`(?<![\w$])${name}(?![\w$])`;
|
|
746
|
-
return String.raw`(?:${boundedName}|\(\s*${boundedName}(?:\s+as\s+[^)]+)?\s*\))`;
|
|
747
|
-
}
|
|
748
|
-
const resolveListenerReference = (expr, bindings, seen = /* @__PURE__ */ new Set()) => {
|
|
749
|
-
if (isFunction(expr)) return expr;
|
|
750
|
-
if (expr.type === "Identifier") {
|
|
751
|
-
if (seen.has(expr.name)) return null;
|
|
752
|
-
seen.add(expr.name);
|
|
753
|
-
const binding = bindings.get(expr.name);
|
|
754
|
-
if (binding == null || !isNode(binding)) return null;
|
|
755
|
-
if (isFunction(binding) || binding.type === "FunctionDeclaration") return binding;
|
|
756
|
-
if (binding.type === "Identifier") return resolveListenerReference(binding, bindings, seen);
|
|
757
|
-
return null;
|
|
758
|
-
}
|
|
759
|
-
if (expr.type === "MemberExpression" && expr.object.type === "Identifier" && !expr.computed) {
|
|
760
|
-
const binding = bindings.get(expr.object.name);
|
|
761
|
-
if (binding == null || !isNode(binding) || binding.type !== "ObjectExpression") return null;
|
|
762
|
-
const propertyName = getMemberPropertyName(expr);
|
|
763
|
-
if (propertyName == null) return null;
|
|
764
|
-
for (const prop of binding.properties) {
|
|
765
|
-
if (!isNode(prop) || prop.type !== "Property") continue;
|
|
766
|
-
if ((prop.key.type === "Identifier" ? prop.key.name : prop.key.type === "Literal" && typeof prop.key.value === "string" ? prop.key.value : null) !== propertyName || !isNode(prop.value)) continue;
|
|
767
|
-
const value = prop.value;
|
|
768
|
-
if (isFunction(value) || value.type === "FunctionDeclaration") return value;
|
|
769
|
-
}
|
|
770
|
-
}
|
|
771
|
-
return null;
|
|
772
|
-
};
|
|
773
|
-
const listenerCallsDeliveryMethod = (sourceCode, listener) => {
|
|
774
|
-
const code = stripCommentsAndStrings(sourceCode.getText(listener));
|
|
775
|
-
const aliases = /* @__PURE__ */ new Set();
|
|
776
|
-
const contextParam = unwrapContextParam(listener.params[0]);
|
|
777
|
-
const contextName = contextParam?.type === "Identifier" ? contextParam.name : null;
|
|
778
|
-
if (contextParam?.type === "ObjectPattern") for (const prop of contextParam.properties) {
|
|
779
|
-
if (!isNode(prop) || prop.type !== "Property") continue;
|
|
780
|
-
const keyName = prop.key.type === "Identifier" ? prop.key.name : prop.key.type === "Literal" && typeof prop.key.value === "string" ? prop.key.value : null;
|
|
781
|
-
if (keyName == null || !DELIVERY_METHOD_NAMES.has(keyName)) continue;
|
|
782
|
-
const alias = getDeliveryAliasName(prop.value);
|
|
783
|
-
if (alias != null) aliases.add(alias);
|
|
784
|
-
}
|
|
785
|
-
if (contextName != null) {
|
|
786
|
-
const contextExpr = buildContextExpressionPattern(contextName);
|
|
787
|
-
if (new RegExp(String.raw`${contextExpr}\s*(?:\?\s*\.\s*(?:sendActivity|forwardActivity)|\.\s*(?:sendActivity|forwardActivity)|\?\s*\.\s*\[\s*["'\`](?:sendActivity|forwardActivity)["'\`]\s*\]|\[\s*["'\`](?:sendActivity|forwardActivity)["'\`]\s*\])\s*\(`).test(code)) return true;
|
|
788
|
-
const destructuringPattern = new RegExp(String.raw`(?:const|let|var)\s*{([^}]*)}\s*=\s*${contextExpr}`, "g");
|
|
789
|
-
for (const match of code.matchAll(destructuringPattern)) {
|
|
790
|
-
const fields = match[1].split(",").map((field) => field.trim()).filter(Boolean);
|
|
791
|
-
for (const field of fields) {
|
|
792
|
-
const [sourceName, aliasName] = field.split(":").map((part) => part.trim());
|
|
793
|
-
if (!DELIVERY_METHOD_NAMES.has(sourceName)) continue;
|
|
794
|
-
aliases.add(aliasName ?? sourceName);
|
|
795
|
-
}
|
|
796
|
-
}
|
|
797
|
-
const aliasPattern = new RegExp(String.raw`(?:const|let|var)\s+([A-Za-z_$][\w$]*)\s*=\s*${contextExpr}\s*(?:\?\s*\.\s*(sendActivity|forwardActivity)|\.\s*(sendActivity|forwardActivity)|\?\s*\.\s*\[\s*["'\`](sendActivity|forwardActivity)["'\`]\s*\]|\[\s*["'\`](sendActivity|forwardActivity)["'\`]\s*\])`, "g");
|
|
798
|
-
for (const match of code.matchAll(aliasPattern)) aliases.add(match[1]);
|
|
799
|
-
}
|
|
800
|
-
return globalThis.Array.from(aliases).some((alias) => new RegExp(String.raw`\b${escapeRegExp(alias)}\s*\(`).test(code));
|
|
801
|
-
};
|
|
802
|
-
function createRule(buildReport) {
|
|
803
|
-
return (context) => {
|
|
804
|
-
const federationTracker = trackFederationVariables();
|
|
805
|
-
const bindings = /* @__PURE__ */ new Map();
|
|
806
|
-
const pendingCalls = [];
|
|
807
|
-
const sourceCode = context.sourceCode;
|
|
808
|
-
const inspectCall = (node) => {
|
|
809
|
-
if (!hasMemberExpressionCallee(node) || !hasIdentifierProperty(node) || !hasMethodName("on")(node) || node.arguments.length < 2) return;
|
|
810
|
-
if (!isChainedFromOutboxListeners(node.callee.object, federationTracker)) return;
|
|
811
|
-
const listener = node.arguments[1];
|
|
812
|
-
const resolvedListener = isNode(listener) && isFunction(listener) ? listener : isNode(listener) ? resolveListenerReference(listener, bindings) : null;
|
|
813
|
-
if (resolvedListener == null) return;
|
|
814
|
-
if (listenerCallsDeliveryMethod(sourceCode, resolvedListener)) return;
|
|
815
|
-
context.report({
|
|
816
|
-
node: resolvedListener,
|
|
817
|
-
...buildReport
|
|
818
|
-
});
|
|
819
|
-
};
|
|
820
|
-
return {
|
|
821
|
-
VariableDeclarator(node) {
|
|
822
|
-
federationTracker.VariableDeclarator(node);
|
|
823
|
-
if (node.id.type === "Identifier" && node.init != null) bindings.set(node.id.name, node.init);
|
|
824
|
-
},
|
|
825
|
-
FunctionDeclaration(node) {
|
|
826
|
-
if (node.id != null) bindings.set(node.id.name, node);
|
|
827
|
-
},
|
|
828
|
-
CallExpression(node) {
|
|
829
|
-
pendingCalls.push(node);
|
|
830
|
-
},
|
|
831
|
-
"Program:exit"() {
|
|
832
|
-
for (const node of pendingCalls) inspectCall(node);
|
|
833
|
-
}
|
|
834
|
-
};
|
|
835
|
-
};
|
|
836
|
-
}
|
|
837
|
-
createRule({ message: MESSAGE });
|
|
838
|
-
const eslint = {
|
|
839
|
-
meta: {
|
|
840
|
-
type: "suggestion",
|
|
841
|
-
docs: { description: "Warn when an outbox listener omits explicit delivery methods" },
|
|
842
|
-
schema: [],
|
|
843
|
-
messages: { required: "{{ message }}" }
|
|
844
|
-
},
|
|
845
|
-
create: createRule({
|
|
846
|
-
messageId: "required",
|
|
847
|
-
data: { message: MESSAGE }
|
|
848
|
-
})
|
|
849
|
-
};
|
|
850
|
-
//#endregion
|
|
851
596
|
//#region src/index.ts
|
|
852
597
|
/**
|
|
853
598
|
* ESLint plugin for Fedify.
|
|
854
599
|
* Provides lint rules for validating Fedify federation code.
|
|
855
600
|
*/
|
|
856
601
|
const rules = {
|
|
857
|
-
[RULE_IDS.actorIdMismatch]: eslint$
|
|
858
|
-
[RULE_IDS.actorIdRequired]: eslint$
|
|
859
|
-
[RULE_IDS.actorFollowingPropertyRequired]: eslint$
|
|
860
|
-
[RULE_IDS.actorFollowingPropertyMismatch]: eslint$
|
|
861
|
-
[RULE_IDS.actorFollowersPropertyRequired]: eslint$
|
|
862
|
-
[RULE_IDS.actorFollowersPropertyMismatch]: eslint$
|
|
863
|
-
[RULE_IDS.actorOutboxPropertyRequired]: eslint$
|
|
864
|
-
[RULE_IDS.actorOutboxPropertyMismatch]: eslint$
|
|
865
|
-
[RULE_IDS.actorLikedPropertyRequired]: eslint$
|
|
866
|
-
[RULE_IDS.actorLikedPropertyMismatch]: eslint$
|
|
867
|
-
[RULE_IDS.actorFeaturedPropertyRequired]: eslint$
|
|
868
|
-
[RULE_IDS.actorFeaturedPropertyMismatch]: eslint$
|
|
869
|
-
[RULE_IDS.actorFeaturedTagsPropertyRequired]: eslint$
|
|
870
|
-
[RULE_IDS.actorFeaturedTagsPropertyMismatch]: eslint$
|
|
871
|
-
[RULE_IDS.actorInboxPropertyRequired]: eslint$
|
|
872
|
-
[RULE_IDS.actorInboxPropertyMismatch]: eslint$
|
|
873
|
-
[RULE_IDS.actorSharedInboxPropertyRequired]: eslint$
|
|
874
|
-
[RULE_IDS.actorSharedInboxPropertyMismatch]: eslint$
|
|
875
|
-
[RULE_IDS.actorPublicKeyRequired]: eslint$
|
|
876
|
-
[RULE_IDS.actorAssertionMethodRequired]: eslint$
|
|
877
|
-
[RULE_IDS.collectionFilteringNotImplemented]: eslint
|
|
878
|
-
[RULE_IDS.outboxListenerDeliveryRequired]: eslint
|
|
602
|
+
[RULE_IDS.actorIdMismatch]: eslint$11,
|
|
603
|
+
[RULE_IDS.actorIdRequired]: eslint$10,
|
|
604
|
+
[RULE_IDS.actorFollowingPropertyRequired]: eslint$12,
|
|
605
|
+
[RULE_IDS.actorFollowingPropertyMismatch]: eslint$13,
|
|
606
|
+
[RULE_IDS.actorFollowersPropertyRequired]: eslint$14,
|
|
607
|
+
[RULE_IDS.actorFollowersPropertyMismatch]: eslint$15,
|
|
608
|
+
[RULE_IDS.actorOutboxPropertyRequired]: eslint$4,
|
|
609
|
+
[RULE_IDS.actorOutboxPropertyMismatch]: eslint$5,
|
|
610
|
+
[RULE_IDS.actorLikedPropertyRequired]: eslint$6,
|
|
611
|
+
[RULE_IDS.actorLikedPropertyMismatch]: eslint$7,
|
|
612
|
+
[RULE_IDS.actorFeaturedPropertyRequired]: eslint$18,
|
|
613
|
+
[RULE_IDS.actorFeaturedPropertyMismatch]: eslint$19,
|
|
614
|
+
[RULE_IDS.actorFeaturedTagsPropertyRequired]: eslint$16,
|
|
615
|
+
[RULE_IDS.actorFeaturedTagsPropertyMismatch]: eslint$17,
|
|
616
|
+
[RULE_IDS.actorInboxPropertyRequired]: eslint$8,
|
|
617
|
+
[RULE_IDS.actorInboxPropertyMismatch]: eslint$9,
|
|
618
|
+
[RULE_IDS.actorSharedInboxPropertyRequired]: eslint$1,
|
|
619
|
+
[RULE_IDS.actorSharedInboxPropertyMismatch]: eslint$2,
|
|
620
|
+
[RULE_IDS.actorPublicKeyRequired]: eslint$3,
|
|
621
|
+
[RULE_IDS.actorAssertionMethodRequired]: eslint$20,
|
|
622
|
+
[RULE_IDS.collectionFilteringNotImplemented]: eslint
|
|
879
623
|
};
|
|
880
624
|
const recommendedRuleIds = [RULE_IDS.actorIdMismatch, RULE_IDS.actorIdRequired];
|
|
881
625
|
/**
|
package/dist/index.js
CHANGED
|
@@ -2,7 +2,7 @@ import { always, every, fromEntries, head, isEmpty, isObject, keys, map, negate,
|
|
|
2
2
|
import parser from "@typescript-eslint/parser";
|
|
3
3
|
//#region deno.json
|
|
4
4
|
var name = "@fedify/lint";
|
|
5
|
-
var version = "2.2.0-
|
|
5
|
+
var version = "2.2.0-pr.695.23+d0b31ca2";
|
|
6
6
|
//#endregion
|
|
7
7
|
//#region src/lib/const.ts
|
|
8
8
|
/**
|
|
@@ -119,8 +119,7 @@ const RULE_IDS = {
|
|
|
119
119
|
actorFeaturedTagsPropertyMismatch: "actor-featured-tags-property-mismatch",
|
|
120
120
|
actorInboxPropertyMismatch: "actor-inbox-property-mismatch",
|
|
121
121
|
actorSharedInboxPropertyMismatch: "actor-shared-inbox-property-mismatch",
|
|
122
|
-
collectionFilteringNotImplemented: "collection-filtering-not-implemented"
|
|
123
|
-
outboxListenerDeliveryRequired: "outbox-listener-delivery-required"
|
|
122
|
+
collectionFilteringNotImplemented: "collection-filtering-not-implemented"
|
|
124
123
|
};
|
|
125
124
|
//#endregion
|
|
126
125
|
//#region src/lib/messages.ts
|
|
@@ -165,7 +164,6 @@ function allOf(...predicates) {
|
|
|
165
164
|
return (value) => predicates.every((predicate) => predicate(value));
|
|
166
165
|
}
|
|
167
166
|
const anyOf = (...predicates) => (value) => predicates.some((predicate) => predicate(value));
|
|
168
|
-
const isNode = (obj) => isObject(obj) && "type" in obj;
|
|
169
167
|
/**
|
|
170
168
|
* Checks if a node is of a specific type.
|
|
171
169
|
*/
|
|
@@ -418,7 +416,7 @@ function createRequiredRuleEslint(config) {
|
|
|
418
416
|
};
|
|
419
417
|
}
|
|
420
418
|
createRequiredRuleDeno(properties.assertionMethod);
|
|
421
|
-
const eslint$
|
|
419
|
+
const eslint$20 = createRequiredRuleEslint(properties.assertionMethod);
|
|
422
420
|
//#endregion
|
|
423
421
|
//#region src/lib/mismatch.ts
|
|
424
422
|
const isIdentifierWithName = (name) => (node) => allOf(isNodeType("Identifier"), isNodeName(name))(node);
|
|
@@ -488,43 +486,43 @@ const createMismatchRuleEslint = (config) => ({
|
|
|
488
486
|
}))
|
|
489
487
|
});
|
|
490
488
|
createMismatchRuleDeno(properties.featured);
|
|
491
|
-
const eslint$
|
|
489
|
+
const eslint$19 = createMismatchRuleEslint(properties.featured);
|
|
492
490
|
createRequiredRuleDeno(properties.featured);
|
|
493
|
-
const eslint$
|
|
491
|
+
const eslint$18 = createRequiredRuleEslint(properties.featured);
|
|
494
492
|
createMismatchRuleDeno(properties.featuredTags);
|
|
495
|
-
const eslint$
|
|
493
|
+
const eslint$17 = createMismatchRuleEslint(properties.featuredTags);
|
|
496
494
|
createRequiredRuleDeno(properties.featuredTags);
|
|
497
|
-
const eslint$
|
|
495
|
+
const eslint$16 = createRequiredRuleEslint(properties.featuredTags);
|
|
498
496
|
createMismatchRuleDeno(properties.followers);
|
|
499
|
-
const eslint$
|
|
497
|
+
const eslint$15 = createMismatchRuleEslint(properties.followers);
|
|
500
498
|
createRequiredRuleDeno(properties.followers);
|
|
501
|
-
const eslint$
|
|
499
|
+
const eslint$14 = createRequiredRuleEslint(properties.followers);
|
|
502
500
|
createMismatchRuleDeno(properties.following);
|
|
503
|
-
const eslint$
|
|
501
|
+
const eslint$13 = createMismatchRuleEslint(properties.following);
|
|
504
502
|
createRequiredRuleDeno(properties.following);
|
|
505
|
-
const eslint$
|
|
503
|
+
const eslint$12 = createRequiredRuleEslint(properties.following);
|
|
506
504
|
createMismatchRuleDeno(properties.id);
|
|
507
|
-
const eslint$
|
|
505
|
+
const eslint$11 = createMismatchRuleEslint(properties.id);
|
|
508
506
|
createRequiredRuleDeno(properties.id);
|
|
509
|
-
const eslint$
|
|
507
|
+
const eslint$10 = createRequiredRuleEslint(properties.id);
|
|
510
508
|
createMismatchRuleDeno(properties.inbox);
|
|
511
|
-
const eslint$
|
|
509
|
+
const eslint$9 = createMismatchRuleEslint(properties.inbox);
|
|
512
510
|
createRequiredRuleDeno(properties.inbox);
|
|
513
|
-
const eslint$
|
|
511
|
+
const eslint$8 = createRequiredRuleEslint(properties.inbox);
|
|
514
512
|
createMismatchRuleDeno(properties.liked);
|
|
515
|
-
const eslint$
|
|
513
|
+
const eslint$7 = createMismatchRuleEslint(properties.liked);
|
|
516
514
|
createRequiredRuleDeno(properties.liked);
|
|
517
|
-
const eslint$
|
|
515
|
+
const eslint$6 = createRequiredRuleEslint(properties.liked);
|
|
518
516
|
createMismatchRuleDeno(properties.outbox);
|
|
519
|
-
const eslint$
|
|
517
|
+
const eslint$5 = createMismatchRuleEslint(properties.outbox);
|
|
520
518
|
createRequiredRuleDeno(properties.outbox);
|
|
521
|
-
const eslint$
|
|
519
|
+
const eslint$4 = createRequiredRuleEslint(properties.outbox);
|
|
522
520
|
createRequiredRuleDeno(properties.publicKey);
|
|
523
|
-
const eslint$
|
|
521
|
+
const eslint$3 = createRequiredRuleEslint(properties.publicKey);
|
|
524
522
|
createMismatchRuleDeno(properties.sharedInbox);
|
|
525
|
-
const eslint$
|
|
523
|
+
const eslint$2 = createMismatchRuleEslint(properties.sharedInbox);
|
|
526
524
|
createRequiredRuleDeno(properties.sharedInbox);
|
|
527
|
-
const eslint$
|
|
525
|
+
const eslint$1 = createRequiredRuleEslint(properties.sharedInbox);
|
|
528
526
|
//#endregion
|
|
529
527
|
//#region src/rules/collection-filtering-not-implemented.ts
|
|
530
528
|
/**
|
|
@@ -543,7 +541,7 @@ const isFollowersDispatcherCall = (node) => "callee" in node && node.callee && n
|
|
|
543
541
|
* CollectionDispatcher signature: (context, identifier, cursor, filter?) => ...
|
|
544
542
|
*/
|
|
545
543
|
const hasFilterParameter = hasMinParams(4);
|
|
546
|
-
const eslint
|
|
544
|
+
const eslint = {
|
|
547
545
|
meta: {
|
|
548
546
|
type: "suggestion",
|
|
549
547
|
docs: { description: "Ensure followers dispatcher implements filtering" },
|
|
@@ -568,287 +566,33 @@ const eslint$1 = {
|
|
|
568
566
|
}
|
|
569
567
|
};
|
|
570
568
|
//#endregion
|
|
571
|
-
//#region src/rules/outbox-listener-delivery-required.ts
|
|
572
|
-
const MESSAGE = "Outbox listeners should deliver posted activities explicitly with ctx.sendActivity() or ctx.forwardActivity().";
|
|
573
|
-
const isChainedFromOutboxListeners = (expr, federationTracker) => {
|
|
574
|
-
if (expr.type !== "CallExpression") return false;
|
|
575
|
-
if (!hasMemberExpressionCallee(expr) || !hasIdentifierProperty(expr)) return false;
|
|
576
|
-
const methodName = expr.callee.property.name;
|
|
577
|
-
if (methodName === "setOutboxListeners") return federationTracker.isFederationObject(expr.callee.object);
|
|
578
|
-
if (methodName === "authorize" || methodName === "onError" || methodName === "on") return isChainedFromOutboxListeners(expr.callee.object, federationTracker);
|
|
579
|
-
return false;
|
|
580
|
-
};
|
|
581
|
-
const DELIVERY_METHOD_NAMES = new Set(["sendActivity", "forwardActivity"]);
|
|
582
|
-
const getMemberPropertyName = (expr) => {
|
|
583
|
-
if (expr.type !== "MemberExpression") return null;
|
|
584
|
-
const property = expr.property;
|
|
585
|
-
if (property.type === "Identifier") return property.name;
|
|
586
|
-
if (property.type === "Literal" && typeof property.value === "string") return property.value;
|
|
587
|
-
return null;
|
|
588
|
-
};
|
|
589
|
-
function unwrapContextParam(node) {
|
|
590
|
-
let current = node ?? null;
|
|
591
|
-
while (current?.type === "AssignmentPattern") current = current.left;
|
|
592
|
-
return current;
|
|
593
|
-
}
|
|
594
|
-
function escapeRegExp(value) {
|
|
595
|
-
return value.replaceAll(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
596
|
-
}
|
|
597
|
-
function stripCommentsAndStrings(code) {
|
|
598
|
-
let result = "";
|
|
599
|
-
let index = 0;
|
|
600
|
-
const skipQuotedString = (quote) => {
|
|
601
|
-
const start = index;
|
|
602
|
-
index += 1;
|
|
603
|
-
while (index < code.length) {
|
|
604
|
-
const char = code[index];
|
|
605
|
-
if (char === "\\") {
|
|
606
|
-
index += 2;
|
|
607
|
-
continue;
|
|
608
|
-
}
|
|
609
|
-
index += 1;
|
|
610
|
-
if (char === quote) break;
|
|
611
|
-
}
|
|
612
|
-
const literal = code.slice(start, index);
|
|
613
|
-
const value = literal.slice(1, -1);
|
|
614
|
-
result += DELIVERY_METHOD_NAMES.has(value) ? literal : `${quote}${quote}`;
|
|
615
|
-
};
|
|
616
|
-
const stripTemplateLiteral = () => {
|
|
617
|
-
const start = index;
|
|
618
|
-
index += 1;
|
|
619
|
-
let raw = "";
|
|
620
|
-
let hasExpression = false;
|
|
621
|
-
while (index < code.length) {
|
|
622
|
-
const char = code[index];
|
|
623
|
-
if (char === "\\") {
|
|
624
|
-
raw += char;
|
|
625
|
-
raw += code[index + 1] ?? "";
|
|
626
|
-
index += 2;
|
|
627
|
-
continue;
|
|
628
|
-
}
|
|
629
|
-
if (char === "`") {
|
|
630
|
-
index += 1;
|
|
631
|
-
if (!hasExpression && DELIVERY_METHOD_NAMES.has(raw)) result += code.slice(start, index);
|
|
632
|
-
else result += "``";
|
|
633
|
-
return;
|
|
634
|
-
}
|
|
635
|
-
if (char === "$" && code[index + 1] === "{") {
|
|
636
|
-
hasExpression = true;
|
|
637
|
-
result += "`${";
|
|
638
|
-
index += 2;
|
|
639
|
-
let depth = 1;
|
|
640
|
-
while (index < code.length && depth > 0) {
|
|
641
|
-
const exprChar = code[index];
|
|
642
|
-
const next = code[index + 1];
|
|
643
|
-
if (exprChar === "'" || exprChar === "\"") {
|
|
644
|
-
skipQuotedString(exprChar);
|
|
645
|
-
continue;
|
|
646
|
-
}
|
|
647
|
-
if (exprChar === "`") {
|
|
648
|
-
stripTemplateLiteral();
|
|
649
|
-
continue;
|
|
650
|
-
}
|
|
651
|
-
if (exprChar === "/" && next === "*") {
|
|
652
|
-
index += 2;
|
|
653
|
-
while (index < code.length) {
|
|
654
|
-
if (code[index] === "*" && code[index + 1] === "/") {
|
|
655
|
-
index += 2;
|
|
656
|
-
break;
|
|
657
|
-
}
|
|
658
|
-
index += 1;
|
|
659
|
-
}
|
|
660
|
-
continue;
|
|
661
|
-
}
|
|
662
|
-
if (exprChar === "/" && next === "/") {
|
|
663
|
-
index += 2;
|
|
664
|
-
while (index < code.length && code[index] !== "\n") index += 1;
|
|
665
|
-
continue;
|
|
666
|
-
}
|
|
667
|
-
result += exprChar;
|
|
668
|
-
index += 1;
|
|
669
|
-
if (exprChar === "{") depth += 1;
|
|
670
|
-
else if (exprChar === "}") depth -= 1;
|
|
671
|
-
}
|
|
672
|
-
continue;
|
|
673
|
-
}
|
|
674
|
-
raw += char;
|
|
675
|
-
index += 1;
|
|
676
|
-
}
|
|
677
|
-
result += "``";
|
|
678
|
-
};
|
|
679
|
-
while (index < code.length) {
|
|
680
|
-
const char = code[index];
|
|
681
|
-
const next = code[index + 1];
|
|
682
|
-
if (char === "/" && next === "*") {
|
|
683
|
-
index += 2;
|
|
684
|
-
while (index < code.length) {
|
|
685
|
-
if (code[index] === "*" && code[index + 1] === "/") {
|
|
686
|
-
index += 2;
|
|
687
|
-
break;
|
|
688
|
-
}
|
|
689
|
-
index += 1;
|
|
690
|
-
}
|
|
691
|
-
continue;
|
|
692
|
-
}
|
|
693
|
-
if (char === "/" && next === "/") {
|
|
694
|
-
index += 2;
|
|
695
|
-
while (index < code.length && code[index] !== "\n") index += 1;
|
|
696
|
-
continue;
|
|
697
|
-
}
|
|
698
|
-
if (char === "'" || char === "\"") {
|
|
699
|
-
skipQuotedString(char);
|
|
700
|
-
continue;
|
|
701
|
-
}
|
|
702
|
-
if (char === "`") {
|
|
703
|
-
stripTemplateLiteral();
|
|
704
|
-
continue;
|
|
705
|
-
}
|
|
706
|
-
result += char;
|
|
707
|
-
index += 1;
|
|
708
|
-
}
|
|
709
|
-
return result;
|
|
710
|
-
}
|
|
711
|
-
function getDeliveryAliasName(node) {
|
|
712
|
-
if (node.type === "Identifier") return node.name;
|
|
713
|
-
if (node.type === "AssignmentPattern" && node.left.type === "Identifier") return node.left.name;
|
|
714
|
-
return null;
|
|
715
|
-
}
|
|
716
|
-
function buildContextExpressionPattern(contextName) {
|
|
717
|
-
const name = escapeRegExp(contextName);
|
|
718
|
-
const boundedName = String.raw`(?<![\w$])${name}(?![\w$])`;
|
|
719
|
-
return String.raw`(?:${boundedName}|\(\s*${boundedName}(?:\s+as\s+[^)]+)?\s*\))`;
|
|
720
|
-
}
|
|
721
|
-
const resolveListenerReference = (expr, bindings, seen = /* @__PURE__ */ new Set()) => {
|
|
722
|
-
if (isFunction(expr)) return expr;
|
|
723
|
-
if (expr.type === "Identifier") {
|
|
724
|
-
if (seen.has(expr.name)) return null;
|
|
725
|
-
seen.add(expr.name);
|
|
726
|
-
const binding = bindings.get(expr.name);
|
|
727
|
-
if (binding == null || !isNode(binding)) return null;
|
|
728
|
-
if (isFunction(binding) || binding.type === "FunctionDeclaration") return binding;
|
|
729
|
-
if (binding.type === "Identifier") return resolveListenerReference(binding, bindings, seen);
|
|
730
|
-
return null;
|
|
731
|
-
}
|
|
732
|
-
if (expr.type === "MemberExpression" && expr.object.type === "Identifier" && !expr.computed) {
|
|
733
|
-
const binding = bindings.get(expr.object.name);
|
|
734
|
-
if (binding == null || !isNode(binding) || binding.type !== "ObjectExpression") return null;
|
|
735
|
-
const propertyName = getMemberPropertyName(expr);
|
|
736
|
-
if (propertyName == null) return null;
|
|
737
|
-
for (const prop of binding.properties) {
|
|
738
|
-
if (!isNode(prop) || prop.type !== "Property") continue;
|
|
739
|
-
if ((prop.key.type === "Identifier" ? prop.key.name : prop.key.type === "Literal" && typeof prop.key.value === "string" ? prop.key.value : null) !== propertyName || !isNode(prop.value)) continue;
|
|
740
|
-
const value = prop.value;
|
|
741
|
-
if (isFunction(value) || value.type === "FunctionDeclaration") return value;
|
|
742
|
-
}
|
|
743
|
-
}
|
|
744
|
-
return null;
|
|
745
|
-
};
|
|
746
|
-
const listenerCallsDeliveryMethod = (sourceCode, listener) => {
|
|
747
|
-
const code = stripCommentsAndStrings(sourceCode.getText(listener));
|
|
748
|
-
const aliases = /* @__PURE__ */ new Set();
|
|
749
|
-
const contextParam = unwrapContextParam(listener.params[0]);
|
|
750
|
-
const contextName = contextParam?.type === "Identifier" ? contextParam.name : null;
|
|
751
|
-
if (contextParam?.type === "ObjectPattern") for (const prop of contextParam.properties) {
|
|
752
|
-
if (!isNode(prop) || prop.type !== "Property") continue;
|
|
753
|
-
const keyName = prop.key.type === "Identifier" ? prop.key.name : prop.key.type === "Literal" && typeof prop.key.value === "string" ? prop.key.value : null;
|
|
754
|
-
if (keyName == null || !DELIVERY_METHOD_NAMES.has(keyName)) continue;
|
|
755
|
-
const alias = getDeliveryAliasName(prop.value);
|
|
756
|
-
if (alias != null) aliases.add(alias);
|
|
757
|
-
}
|
|
758
|
-
if (contextName != null) {
|
|
759
|
-
const contextExpr = buildContextExpressionPattern(contextName);
|
|
760
|
-
if (new RegExp(String.raw`${contextExpr}\s*(?:\?\s*\.\s*(?:sendActivity|forwardActivity)|\.\s*(?:sendActivity|forwardActivity)|\?\s*\.\s*\[\s*["'\`](?:sendActivity|forwardActivity)["'\`]\s*\]|\[\s*["'\`](?:sendActivity|forwardActivity)["'\`]\s*\])\s*\(`).test(code)) return true;
|
|
761
|
-
const destructuringPattern = new RegExp(String.raw`(?:const|let|var)\s*{([^}]*)}\s*=\s*${contextExpr}`, "g");
|
|
762
|
-
for (const match of code.matchAll(destructuringPattern)) {
|
|
763
|
-
const fields = match[1].split(",").map((field) => field.trim()).filter(Boolean);
|
|
764
|
-
for (const field of fields) {
|
|
765
|
-
const [sourceName, aliasName] = field.split(":").map((part) => part.trim());
|
|
766
|
-
if (!DELIVERY_METHOD_NAMES.has(sourceName)) continue;
|
|
767
|
-
aliases.add(aliasName ?? sourceName);
|
|
768
|
-
}
|
|
769
|
-
}
|
|
770
|
-
const aliasPattern = new RegExp(String.raw`(?:const|let|var)\s+([A-Za-z_$][\w$]*)\s*=\s*${contextExpr}\s*(?:\?\s*\.\s*(sendActivity|forwardActivity)|\.\s*(sendActivity|forwardActivity)|\?\s*\.\s*\[\s*["'\`](sendActivity|forwardActivity)["'\`]\s*\]|\[\s*["'\`](sendActivity|forwardActivity)["'\`]\s*\])`, "g");
|
|
771
|
-
for (const match of code.matchAll(aliasPattern)) aliases.add(match[1]);
|
|
772
|
-
}
|
|
773
|
-
return globalThis.Array.from(aliases).some((alias) => new RegExp(String.raw`\b${escapeRegExp(alias)}\s*\(`).test(code));
|
|
774
|
-
};
|
|
775
|
-
function createRule(buildReport) {
|
|
776
|
-
return (context) => {
|
|
777
|
-
const federationTracker = trackFederationVariables();
|
|
778
|
-
const bindings = /* @__PURE__ */ new Map();
|
|
779
|
-
const pendingCalls = [];
|
|
780
|
-
const sourceCode = context.sourceCode;
|
|
781
|
-
const inspectCall = (node) => {
|
|
782
|
-
if (!hasMemberExpressionCallee(node) || !hasIdentifierProperty(node) || !hasMethodName("on")(node) || node.arguments.length < 2) return;
|
|
783
|
-
if (!isChainedFromOutboxListeners(node.callee.object, federationTracker)) return;
|
|
784
|
-
const listener = node.arguments[1];
|
|
785
|
-
const resolvedListener = isNode(listener) && isFunction(listener) ? listener : isNode(listener) ? resolveListenerReference(listener, bindings) : null;
|
|
786
|
-
if (resolvedListener == null) return;
|
|
787
|
-
if (listenerCallsDeliveryMethod(sourceCode, resolvedListener)) return;
|
|
788
|
-
context.report({
|
|
789
|
-
node: resolvedListener,
|
|
790
|
-
...buildReport
|
|
791
|
-
});
|
|
792
|
-
};
|
|
793
|
-
return {
|
|
794
|
-
VariableDeclarator(node) {
|
|
795
|
-
federationTracker.VariableDeclarator(node);
|
|
796
|
-
if (node.id.type === "Identifier" && node.init != null) bindings.set(node.id.name, node.init);
|
|
797
|
-
},
|
|
798
|
-
FunctionDeclaration(node) {
|
|
799
|
-
if (node.id != null) bindings.set(node.id.name, node);
|
|
800
|
-
},
|
|
801
|
-
CallExpression(node) {
|
|
802
|
-
pendingCalls.push(node);
|
|
803
|
-
},
|
|
804
|
-
"Program:exit"() {
|
|
805
|
-
for (const node of pendingCalls) inspectCall(node);
|
|
806
|
-
}
|
|
807
|
-
};
|
|
808
|
-
};
|
|
809
|
-
}
|
|
810
|
-
createRule({ message: MESSAGE });
|
|
811
|
-
const eslint = {
|
|
812
|
-
meta: {
|
|
813
|
-
type: "suggestion",
|
|
814
|
-
docs: { description: "Warn when an outbox listener omits explicit delivery methods" },
|
|
815
|
-
schema: [],
|
|
816
|
-
messages: { required: "{{ message }}" }
|
|
817
|
-
},
|
|
818
|
-
create: createRule({
|
|
819
|
-
messageId: "required",
|
|
820
|
-
data: { message: MESSAGE }
|
|
821
|
-
})
|
|
822
|
-
};
|
|
823
|
-
//#endregion
|
|
824
569
|
//#region src/index.ts
|
|
825
570
|
/**
|
|
826
571
|
* ESLint plugin for Fedify.
|
|
827
572
|
* Provides lint rules for validating Fedify federation code.
|
|
828
573
|
*/
|
|
829
574
|
const rules = {
|
|
830
|
-
[RULE_IDS.actorIdMismatch]: eslint$
|
|
831
|
-
[RULE_IDS.actorIdRequired]: eslint$
|
|
832
|
-
[RULE_IDS.actorFollowingPropertyRequired]: eslint$
|
|
833
|
-
[RULE_IDS.actorFollowingPropertyMismatch]: eslint$
|
|
834
|
-
[RULE_IDS.actorFollowersPropertyRequired]: eslint$
|
|
835
|
-
[RULE_IDS.actorFollowersPropertyMismatch]: eslint$
|
|
836
|
-
[RULE_IDS.actorOutboxPropertyRequired]: eslint$
|
|
837
|
-
[RULE_IDS.actorOutboxPropertyMismatch]: eslint$
|
|
838
|
-
[RULE_IDS.actorLikedPropertyRequired]: eslint$
|
|
839
|
-
[RULE_IDS.actorLikedPropertyMismatch]: eslint$
|
|
840
|
-
[RULE_IDS.actorFeaturedPropertyRequired]: eslint$
|
|
841
|
-
[RULE_IDS.actorFeaturedPropertyMismatch]: eslint$
|
|
842
|
-
[RULE_IDS.actorFeaturedTagsPropertyRequired]: eslint$
|
|
843
|
-
[RULE_IDS.actorFeaturedTagsPropertyMismatch]: eslint$
|
|
844
|
-
[RULE_IDS.actorInboxPropertyRequired]: eslint$
|
|
845
|
-
[RULE_IDS.actorInboxPropertyMismatch]: eslint$
|
|
846
|
-
[RULE_IDS.actorSharedInboxPropertyRequired]: eslint$
|
|
847
|
-
[RULE_IDS.actorSharedInboxPropertyMismatch]: eslint$
|
|
848
|
-
[RULE_IDS.actorPublicKeyRequired]: eslint$
|
|
849
|
-
[RULE_IDS.actorAssertionMethodRequired]: eslint$
|
|
850
|
-
[RULE_IDS.collectionFilteringNotImplemented]: eslint
|
|
851
|
-
[RULE_IDS.outboxListenerDeliveryRequired]: eslint
|
|
575
|
+
[RULE_IDS.actorIdMismatch]: eslint$11,
|
|
576
|
+
[RULE_IDS.actorIdRequired]: eslint$10,
|
|
577
|
+
[RULE_IDS.actorFollowingPropertyRequired]: eslint$12,
|
|
578
|
+
[RULE_IDS.actorFollowingPropertyMismatch]: eslint$13,
|
|
579
|
+
[RULE_IDS.actorFollowersPropertyRequired]: eslint$14,
|
|
580
|
+
[RULE_IDS.actorFollowersPropertyMismatch]: eslint$15,
|
|
581
|
+
[RULE_IDS.actorOutboxPropertyRequired]: eslint$4,
|
|
582
|
+
[RULE_IDS.actorOutboxPropertyMismatch]: eslint$5,
|
|
583
|
+
[RULE_IDS.actorLikedPropertyRequired]: eslint$6,
|
|
584
|
+
[RULE_IDS.actorLikedPropertyMismatch]: eslint$7,
|
|
585
|
+
[RULE_IDS.actorFeaturedPropertyRequired]: eslint$18,
|
|
586
|
+
[RULE_IDS.actorFeaturedPropertyMismatch]: eslint$19,
|
|
587
|
+
[RULE_IDS.actorFeaturedTagsPropertyRequired]: eslint$16,
|
|
588
|
+
[RULE_IDS.actorFeaturedTagsPropertyMismatch]: eslint$17,
|
|
589
|
+
[RULE_IDS.actorInboxPropertyRequired]: eslint$8,
|
|
590
|
+
[RULE_IDS.actorInboxPropertyMismatch]: eslint$9,
|
|
591
|
+
[RULE_IDS.actorSharedInboxPropertyRequired]: eslint$1,
|
|
592
|
+
[RULE_IDS.actorSharedInboxPropertyMismatch]: eslint$2,
|
|
593
|
+
[RULE_IDS.actorPublicKeyRequired]: eslint$3,
|
|
594
|
+
[RULE_IDS.actorAssertionMethodRequired]: eslint$20,
|
|
595
|
+
[RULE_IDS.collectionFilteringNotImplemented]: eslint
|
|
852
596
|
};
|
|
853
597
|
const recommendedRuleIds = [RULE_IDS.actorIdMismatch, RULE_IDS.actorIdRequired];
|
|
854
598
|
/**
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@fedify/lint",
|
|
3
|
-
"version": "2.2.0-
|
|
3
|
+
"version": "2.2.0-pr.695.23+d0b31ca2",
|
|
4
4
|
"description": "Fedify linting rules and plugins",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"Fedify",
|
|
@@ -47,7 +47,7 @@
|
|
|
47
47
|
],
|
|
48
48
|
"peerDependencies": {
|
|
49
49
|
"eslint": ">=9.0.0",
|
|
50
|
-
"@fedify/fedify": "^2.2.0-
|
|
50
|
+
"@fedify/fedify": "^2.2.0-pr.695.23+d0b31ca2"
|
|
51
51
|
},
|
|
52
52
|
"peerDependenciesMeta": {
|
|
53
53
|
"eslint": {
|