oxlint-plugin-react-doctor 0.5.6-dev.424d8f9 → 0.5.6-dev.431e515
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.js +10 -65
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -890,64 +890,24 @@ const advancedEventHandlerRefs = defineRule({
|
|
|
890
890
|
});
|
|
891
891
|
//#endregion
|
|
892
892
|
//#region src/plugin/rules/security-scan/utils/strip-comments-preserving-positions.ts
|
|
893
|
-
const
|
|
894
|
-
const quotedLiteralHasWhitespace = (content, openQuoteIndex, delimiter) => {
|
|
895
|
-
for (let cursor = openQuoteIndex + 1; cursor < content.length; cursor += 1) {
|
|
896
|
-
const character = content[cursor];
|
|
897
|
-
if (character === "\\") {
|
|
898
|
-
cursor += 1;
|
|
899
|
-
continue;
|
|
900
|
-
}
|
|
901
|
-
if (character === delimiter) return false;
|
|
902
|
-
if (WHITESPACE_PATTERN.test(character)) return true;
|
|
903
|
-
}
|
|
904
|
-
return false;
|
|
905
|
-
};
|
|
906
|
-
const blankNonCodePreservingPositions = (content, blankStringContents) => {
|
|
893
|
+
const stripCommentsPreservingPositions = (content) => {
|
|
907
894
|
const characters = content.split("");
|
|
908
895
|
let stringDelimiter = null;
|
|
909
|
-
let isBlankingString = false;
|
|
910
|
-
const templateExpressionDepths = [];
|
|
911
896
|
let index = 0;
|
|
912
|
-
const blankUnlessNewline = (offset) => {
|
|
913
|
-
if (offset < content.length && content[offset] !== "\n") characters[offset] = " ";
|
|
914
|
-
};
|
|
915
897
|
while (index < content.length) {
|
|
916
898
|
const character = content[index];
|
|
917
899
|
const nextCharacter = content[index + 1];
|
|
918
900
|
if (stringDelimiter !== null) {
|
|
919
901
|
if (character === "\\") {
|
|
920
|
-
if (isBlankingString) {
|
|
921
|
-
blankUnlessNewline(index);
|
|
922
|
-
blankUnlessNewline(index + 1);
|
|
923
|
-
}
|
|
924
|
-
index += 2;
|
|
925
|
-
continue;
|
|
926
|
-
}
|
|
927
|
-
if (character === stringDelimiter) {
|
|
928
|
-
stringDelimiter = null;
|
|
929
|
-
index += 1;
|
|
930
|
-
continue;
|
|
931
|
-
}
|
|
932
|
-
if (blankStringContents && stringDelimiter === "`" && character === "$" && nextCharacter === "{") {
|
|
933
|
-
templateExpressionDepths.push(0);
|
|
934
|
-
stringDelimiter = null;
|
|
935
902
|
index += 2;
|
|
936
903
|
continue;
|
|
937
904
|
}
|
|
938
|
-
if (
|
|
905
|
+
if (character === stringDelimiter) stringDelimiter = null;
|
|
939
906
|
index += 1;
|
|
940
907
|
continue;
|
|
941
908
|
}
|
|
942
|
-
if (character === "\"" || character === "'") {
|
|
909
|
+
if (character === "\"" || character === "'" || character === "`") {
|
|
943
910
|
stringDelimiter = character;
|
|
944
|
-
isBlankingString = blankStringContents && quotedLiteralHasWhitespace(content, index, character);
|
|
945
|
-
index += 1;
|
|
946
|
-
continue;
|
|
947
|
-
}
|
|
948
|
-
if (character === "`") {
|
|
949
|
-
stringDelimiter = "`";
|
|
950
|
-
isBlankingString = blankStringContents;
|
|
951
911
|
index += 1;
|
|
952
912
|
continue;
|
|
953
913
|
}
|
|
@@ -966,42 +926,29 @@ const blankNonCodePreservingPositions = (content, blankStringContents) => {
|
|
|
966
926
|
index += 2;
|
|
967
927
|
break;
|
|
968
928
|
}
|
|
969
|
-
|
|
929
|
+
if (content[index] !== "\n") characters[index] = " ";
|
|
970
930
|
index += 1;
|
|
971
931
|
}
|
|
972
932
|
continue;
|
|
973
933
|
}
|
|
974
|
-
if (templateExpressionDepths.length > 0) {
|
|
975
|
-
const innermost = templateExpressionDepths.length - 1;
|
|
976
|
-
if (character === "{") templateExpressionDepths[innermost] += 1;
|
|
977
|
-
else if (character === "}") if (templateExpressionDepths[innermost] === 0) {
|
|
978
|
-
templateExpressionDepths.pop();
|
|
979
|
-
stringDelimiter = "`";
|
|
980
|
-
isBlankingString = blankStringContents;
|
|
981
|
-
} else templateExpressionDepths[innermost] -= 1;
|
|
982
|
-
}
|
|
983
934
|
index += 1;
|
|
984
935
|
}
|
|
985
936
|
return characters.join("");
|
|
986
937
|
};
|
|
987
|
-
const stripCommentsPreservingPositions = (content) => blankNonCodePreservingPositions(content, false);
|
|
988
|
-
const stripCommentsAndStringLiteralsPreservingPositions = (content) => blankNonCodePreservingPositions(content, true);
|
|
989
938
|
//#endregion
|
|
990
939
|
//#region src/plugin/rules/security-scan/utils/scan-by-pattern.ts
|
|
991
940
|
const strippedContentCache = /* @__PURE__ */ new WeakMap();
|
|
992
|
-
const
|
|
993
|
-
const getScannableContent = (file, ignoreStringLiterals = false) => {
|
|
941
|
+
const getScannableContent = (file) => {
|
|
994
942
|
if (!SOURCE_FILE_PATTERN.test(file.relativePath)) return file.content;
|
|
995
|
-
const
|
|
996
|
-
const cachedContent = cache.get(file);
|
|
943
|
+
const cachedContent = strippedContentCache.get(file);
|
|
997
944
|
if (cachedContent !== void 0) return cachedContent;
|
|
998
|
-
const strippedContent =
|
|
999
|
-
|
|
945
|
+
const strippedContent = stripCommentsPreservingPositions(file.content);
|
|
946
|
+
strippedContentCache.set(file, strippedContent);
|
|
1000
947
|
return strippedContent;
|
|
1001
948
|
};
|
|
1002
|
-
const scanByPattern = ({ shouldScan, pattern, requireAll, suppressWhen,
|
|
949
|
+
const scanByPattern = ({ shouldScan, pattern, requireAll, suppressWhen, message }) => (file) => {
|
|
1003
950
|
if (!shouldScan(file)) return [];
|
|
1004
|
-
const content = getScannableContent(file
|
|
951
|
+
const content = getScannableContent(file);
|
|
1005
952
|
if (requireAll !== void 0 && !requireAll.every((gate) => gate.test(content))) return [];
|
|
1006
953
|
const matchedPattern = (pattern instanceof RegExp ? [pattern] : pattern).find((candidate) => candidate.test(content));
|
|
1007
954
|
if (matchedPattern === void 0) return [];
|
|
@@ -1026,7 +973,6 @@ const agentToolCapabilityRisk = defineRule({
|
|
|
1026
973
|
shouldScan: (file) => isProductionSourcePath(file.relativePath) && AGENT_TOOL_CONTEXT_PATH_PATTERN.test(file.relativePath),
|
|
1027
974
|
pattern: AGENT_TOOL_DEFINITION_PATTERN,
|
|
1028
975
|
requireAll: [AGENT_TOOL_DANGEROUS_CAPABILITY_PATTERN],
|
|
1029
|
-
ignoreStringLiterals: true,
|
|
1030
976
|
message: "An agent-callable tool appears to expose network, filesystem, shell, or code-execution capability."
|
|
1031
977
|
})
|
|
1032
978
|
});
|
|
@@ -13521,7 +13467,6 @@ const mcpToolCapabilityRisk = defineRule({
|
|
|
13521
13467
|
shouldScan: (file) => isProductionSourcePath(file.relativePath),
|
|
13522
13468
|
pattern: /\bserver\.\s*tool\s*\(|\bregisterTool\s*\(|\bsetRequestHandler\s*\(\s*CallToolRequestSchema/,
|
|
13523
13469
|
requireAll: [/\bfrom\s+["']@modelcontextprotocol\/sdk[^"']*["']|\bMcpServer\b|\bMcpAgent\b/, AGENT_TOOL_DANGEROUS_CAPABILITY_PATTERN],
|
|
13524
|
-
ignoreStringLiterals: true,
|
|
13525
13470
|
message: "An MCP tool/resource/prompt handler appears to expose file, shell, network, or code-execution capability."
|
|
13526
13471
|
})
|
|
13527
13472
|
});
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "oxlint-plugin-react-doctor",
|
|
3
|
-
"version": "0.5.6-dev.
|
|
3
|
+
"version": "0.5.6-dev.431e515",
|
|
4
4
|
"description": "oxlint plugin for React Doctor: diagnose React codebases for security, performance, correctness, accessibility, bundle-size, and architecture issues",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"accessibility",
|