mta-mcp 3.15.2 → 3.15.3
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
CHANGED
|
@@ -6403,13 +6403,17 @@ var OUTPUT_GUIDE = {
|
|
|
6403
6403
|
"- **token**: AppShadows.xxx token \u540D\uFF0C\u4F18\u5148\u4F7F\u7528\u4EE3\u66FF\u786C\u7F16\u7801 BoxShadow",
|
|
6404
6404
|
"- **r**: borderRadius \u6570\u503C",
|
|
6405
6405
|
"- **rp**: [left,top,right,bottom] \u76F8\u5BF9\u7236\u5BB9\u5668\u8FB9\u8DDD",
|
|
6406
|
+
"- **vf**: [x,y,w,h] \u89C6\u89C9\u8FB9\u754C\uFF1B\u5F53\u80CC\u666F\u5C42/\u9634\u5F71\u8D85\u51FA\u7236 Group frame \u65F6\uFF0C\u5BB9\u5668\u5C3A\u5BF8\u548C\u89C6\u89C9\u5E95\u8FB9\u8DDD\u4F18\u5148\u770B vf",
|
|
6406
6407
|
"- **icon/svg/cs/xs**: \u56FE\u6807\u6807\u8BC6/\u771F\u5B9E SvgPicture.string(...) \u4EE3\u7801/containerSize/contentSize",
|
|
6408
|
+
"- **image/img/bitmapPath/bitmapScales**: \u4F4D\u56FE\u56FE\u5C42\u6807\u8BC6/Image.asset \u4EE3\u7801/\u5EFA\u8BAE\u843D\u76D8\u8DEF\u5F84/1x-3x \u5BFC\u51FA\u8981\u6C42",
|
|
6407
6409
|
"- **svgMode/svgReason/svgFile**: preserve|tint / \u989C\u8272\u7B56\u7565\u539F\u56E0 / \u5EFA\u8BAE\u843D\u76D8\u6587\u4EF6\u540D",
|
|
6408
6410
|
"- **text/style/family/textHeight**: \u6587\u672C\u5185\u5BB9/\u5B8C\u6574 TextStyle/\u5B57\u4F53\u65CF/\u884C\u9AD8\u6BD4",
|
|
6409
6411
|
"- **lh/strut**: strutHeight / \u5B8C\u6574 StrutStyle(...)",
|
|
6410
6412
|
"- **tag**: {bg,ph,pv,r,text} Tag\u5BB9\u5668\u4FE1\u606F",
|
|
6411
6413
|
"- **layout**: {dir,gap,main,cross,pad} \u5E03\u5C40\u610F\u56FE",
|
|
6412
6414
|
"- **ch**: \u5B50\u5143\u7D20\u6570\u7EC4\uFF08\u9012\u5F52\uFF09",
|
|
6415
|
+
"- **designSurface**: {width,height,maxWidth,wideScreenRule} \u8BBE\u8BA1\u753B\u677F\u7EA6\u675F\uFF1B\u79FB\u52A8\u7AEF\u7A84\u753B\u677F\u5728\u5BBD\u5C4F\u5FC5\u987B\u505A\u5C45\u4E2D\u5939\u6301",
|
|
6416
|
+
"- **selectionContext**: compact \u82E5\u53D1\u73B0\u9009\u4E2D\u7684\u662F\u5B50\u56FE\u5C42\uFF0C\u4F1A\u81EA\u52A8\u63D0\u5347\u5230\u6240\u5C5E\u753B\u677F/\u9876\u5C42\u5BB9\u5668\u5E76\u8BB0\u5F55 warning",
|
|
6413
6417
|
"",
|
|
6414
6418
|
"### \u4F7F\u7528\u65B9\u5F0F",
|
|
6415
6419
|
"\u5148\u8BFB\u53D6 restorationContract.blockOrder/bodyCopyLedger/hardRules \u9501\u5B9A\u7ED3\u6784\uFF0C\u518D\u7528 tree \u4E2D\u7684 flutter* \u5B57\u6BB5\u586B\u5145\u6837\u5F0F\u548C\u5E03\u5C40\u7EC6\u8282\u3002",
|
|
@@ -6418,7 +6422,10 @@ var OUTPUT_GUIDE = {
|
|
|
6418
6422
|
"- \u56FE\u6807\u662F\u5426\u8BEF\u7528\u65E7\u9875\u9762\u8D44\u4EA7\uFF1A\u540C\u540D\u7BAD\u5934/\u56FE\u6807\u9ED8\u8BA4\u4E0D\u53EF\u4FE1\uFF0C\u5148\u6838\u5BF9\u6765\u6E90\u56FE\u5C42",
|
|
6419
6423
|
"- SVG \u662F\u5426\u8BEF\u52A0 ColorFilter\uFF1A\u4FDD\u7559\u539F\u8272\u7684 SVG \u4E0D\u5F97\u4E8C\u6B21\u67D3\u8272",
|
|
6420
6424
|
"- \u56FE\u6807\u662F\u5426\u7528\u9519\u5C3A\u5BF8\uFF1A16x16 \u69FD\u4F4D\u4E0D\u7B49\u4E8E 16x16 \u56FE\u5F62\uFF0C\u6309 xs/cs \u5206\u79BB\u5360\u4F4D\u4E0E\u6E32\u67D3",
|
|
6421
|
-
"- Bitmap \u662F\u5426\u8BEF\u5F53 SVG\uFF1ASketch Image \u56FE\u5C42\u5FC5\u987B\u5BFC\u51FA PNG + Image.asset",
|
|
6425
|
+
"- Bitmap \u662F\u5426\u8BEF\u5F53 SVG\uFF1ASketch Image \u56FE\u5C42\u5FC5\u987B\u5BFC\u51FA PNG + Image.asset\uFF0C\u4E14\u8865\u9F50 2.0x/3.0x \u53D8\u4F53",
|
|
6426
|
+
"- \u79FB\u52A8\u7AEF\u7A84\u753B\u677F\uFF08\u5982 390 \u5BBD\uFF09\u5728\u5BBD\u5C4F\u5FC5\u987B\u7528 Center + ConstrainedBox(maxWidth: designSurface.maxWidth) \u5939\u6301\uFF0C\u7981\u6B62\u8BA9 Positioned(left/right) \u76F4\u63A5\u62C9\u4F38\u5230\u5168\u5C4F",
|
|
6427
|
+
"- \u82E5\u8282\u70B9\u540C\u65F6\u7ED9\u51FA f \u4E0E vf\uFF0C\u8BF4\u660E\u80CC\u666F\u5C42/\u9634\u5F71\u8D85\u51FA\u903B\u8F91 frame\uFF1B\u5BB9\u5668\u5C3A\u5BF8\u548C\u5E95\u90E8\u89C6\u89C9\u95F4\u8DDD\u4F18\u5148\u4F7F\u7528 vf",
|
|
6428
|
+
"- \u82E5 selectionContext.autoPromoted=true\uFF0C\u8BF4\u660E\u4E4B\u524D\u9009\u4E2D\u4E86\u5185\u5C42 glyph\uFF1B\u540E\u7EED\u5C40\u90E8\u5BFC\u51FA\u56FE\u6807\u65F6\u5E94\u6539\u7528 cmd=svg \u9009\u4E2D\u5177\u4F53\u56FE\u5C42",
|
|
6422
6429
|
"- \u9875\u9762\u9AA8\u67B6\u662F\u5426\u88AB\u4E1A\u52A1\u7EC4\u4EF6\u6539\u5199\uFF1A\u6807\u9898\u3001\u9876\u90E8\u5165\u53E3\u3001\u641C\u7D22\u5757\u548C\u5E95\u5BFC\u987A\u5E8F\u5FC5\u987B\u56DE\u770B restorationContract"
|
|
6423
6430
|
].join("\n")
|
|
6424
6431
|
};
|
|
@@ -6509,13 +6516,16 @@ async function sketchMeasure(args) {
|
|
|
6509
6516
|
scriptPath: tempScriptPath,
|
|
6510
6517
|
scriptLength: fullScript.length,
|
|
6511
6518
|
pluginInstall: installStatus,
|
|
6512
|
-
instruction: "\u5C06 loaderScript \u4F20\u5165 mcp_sketch_run_code({ code: loaderScript }) \u6267\u884C\u3002\u8BBE\u8BA1\u7A3F\u8FD8\u539F\u9996\u8F6E\u4F18\u5148\u4F7F\u7528 cmd=compact\uFF1B\u53EA\u6709\u5F53 compact contract \u4E0D\u8DB3\u4EE5\u89E3\u91CA\u5C40\u90E8\u5E03\u5C40\u6216\u6837\u5F0F\u65F6\uFF0C\u518D\u8865\u7528 measure/style\u3002\u82E5\u504F\u5DEE\u96C6\u4E2D\u5728\u5355\u4E2A icon/svg/bitmap\uFF0C\u8BF7\u91CD\u65B0\u9009\u4E2D\u8BE5\u56FE\u5C42\u6267\u884C svg \u6216\u5C40\u90E8\u5BFC\u51FA\uFF0C\u5E76\u590D\u67E5 colorStrategy\u3001viewBox\u3001containerSize/contentSize\uFF0C\u907F\u514D\u590D\u7528\u65E7\u9875\u9762\u8D44\u4EA7\u3002\u8BF7\u5148\u5728 Sketch \u4E2D\u9009\u4E2D\u76EE\u6807\u753B\u677F/\u56FE\u5C42\u3002",
|
|
6519
|
+
instruction: "\u5C06 loaderScript \u4F20\u5165 mcp_sketch_run_code({ code: loaderScript }) \u6267\u884C\u3002\u8BBE\u8BA1\u7A3F\u8FD8\u539F\u9996\u8F6E\u4F18\u5148\u4F7F\u7528 cmd=compact\uFF1B\u53EA\u6709\u5F53 compact contract \u4E0D\u8DB3\u4EE5\u89E3\u91CA\u5C40\u90E8\u5E03\u5C40\u6216\u6837\u5F0F\u65F6\uFF0C\u518D\u8865\u7528 measure/style\u3002\u82E5\u504F\u5DEE\u96C6\u4E2D\u5728\u5355\u4E2A icon/svg/bitmap\uFF0C\u8BF7\u91CD\u65B0\u9009\u4E2D\u8BE5\u56FE\u5C42\u6267\u884C svg \u6216\u5C40\u90E8\u5BFC\u51FA\uFF0C\u5E76\u590D\u67E5 colorStrategy\u3001viewBox\u3001containerSize/contentSize\u3001vf \u4E0E bitmapScales\uFF0C\u907F\u514D\u590D\u7528\u65E7\u9875\u9762\u8D44\u4EA7\u3002\u79FB\u52A8\u7AEF\u7A84\u753B\u677F\u8981\u6309 designSurface.maxWidth \u505A\u5BBD\u5C4F\u5939\u6301\u3002compact \u82E5\u68C0\u6D4B\u5230\u4F60\u9009\u4E2D\u7684\u662F\u5185\u5C42 glyph\uFF0C\u4F1A\u81EA\u52A8\u63D0\u5347\u5230\u6240\u5C5E\u753B\u677F\u5E76\u901A\u8FC7 selectionContext \u56DE\u62A5\u3002\u8BF7\u5148\u5728 Sketch \u4E2D\u9009\u4E2D\u76EE\u6807\u753B\u677F/\u56FE\u5C42\u3002",
|
|
6513
6520
|
restoreChecklist: [
|
|
6514
6521
|
"\u5148\u6309 restorationContract \u9501\u5B9A\u9875\u9762\u9AA8\u67B6\uFF0C\u518D\u5904\u7406\u5C40\u90E8\u6837\u5F0F",
|
|
6515
6522
|
"\u5355\u4E2A\u56FE\u6807\u504F\u5DEE\u4F18\u5148\u5C40\u90E8\u91CD\u5BFC\u51FA\uFF0C\u4E0D\u590D\u7528\u5176\u5B83\u9875\u9762\u65E7\u8D44\u4EA7",
|
|
6516
6523
|
"preserve \u6A21\u5F0F SVG \u7981\u6B62\u8FFD\u52A0 ColorFilter",
|
|
6517
6524
|
"16x16 \u69FD\u4F4D\u4E0E 6x8/12x12 \u56FE\u5F62\u8981\u5206\u5F00\u5904\u7406",
|
|
6518
|
-
"Sketch Image \u56FE\u5C42\u5BFC\u51FA PNG\uFF0C\u4E0D\u8981\u4F2A\u88C5\u6210 SVG \u4F7F\u7528",
|
|
6525
|
+
"Sketch Image \u56FE\u5C42\u5BFC\u51FA PNG\uFF0C\u4E0D\u8981\u4F2A\u88C5\u6210 SVG \u4F7F\u7528\uFF0C\u5E76\u8865\u9F50 2.0x/3.0x \u53D8\u4F53",
|
|
6526
|
+
"\u79FB\u52A8\u7AEF\u7A84\u753B\u677F\u5728\u5BBD\u5C4F\u5FC5\u987B\u7528 Center + ConstrainedBox(maxWidth: designSurface.maxWidth) \u5939\u6301\uFF0C\u7981\u6B62\u5168\u5C4F\u62C9\u4F38",
|
|
6527
|
+
"\u82E5\u8282\u70B9\u540C\u65F6\u51FA\u73B0 f \u4E0E vf\uFF0C\u5BB9\u5668\u5C3A\u5BF8\u548C\u5E95\u90E8\u89C6\u89C9\u95F4\u8DDD\u4F18\u5148\u4F7F\u7528 vf\uFF0C\u4E0D\u8981\u53EA\u6284\u903B\u8F91 frame",
|
|
6528
|
+
"\u82E5 compact \u8FD4\u56DE selectionContext.autoPromoted=true\uFF0C\u8BF4\u660E\u4E4B\u524D\u8BEF\u9009\u4E2D\u4E86\u5B50\u56FE\u5C42\uFF0C\u4E0D\u8981\u628A\u5185\u5C42 glyph \u5F53\u6574\u9875\u5408\u540C",
|
|
6519
6529
|
"\u4EE3\u7801\u751F\u6210\u540E\u5FC5\u987B\u8C03\u7528 validate_restoration \u6821\u9A8C\u9875\u9762\u9AA8\u67B6\u3001\u8D44\u4EA7\u6765\u6E90\u548C\u771F\u5B9E\u8DEF\u7531"
|
|
6520
6530
|
],
|
|
6521
6531
|
postRestoreValidator: {
|
|
@@ -6600,7 +6610,9 @@ function collectAssetContracts(node, bucket = []) {
|
|
|
6600
6610
|
if (node.t === "Image") {
|
|
6601
6611
|
bucket.push({
|
|
6602
6612
|
sketchName: node.n || "Image",
|
|
6603
|
-
|
|
6613
|
+
fileName: typeof node.bitmapFile === "string" ? path20.posix.basename(node.bitmapFile) : typeof node.bitmapPath === "string" ? path20.posix.basename(node.bitmapPath) : void 0,
|
|
6614
|
+
sourceType: "bitmap",
|
|
6615
|
+
scaleVariants: node.bitmapScales
|
|
6604
6616
|
});
|
|
6605
6617
|
}
|
|
6606
6618
|
for (const child of node.ch || []) {
|
|
@@ -6612,12 +6624,64 @@ function extractCodeAssets(codeContent) {
|
|
|
6612
6624
|
const matches = codeContent.match(/assets\/[A-Za-z0-9_./-]+\.(svg|png|jpg|jpeg|webp)/g);
|
|
6613
6625
|
return matches ? [...new Set(matches)] : [];
|
|
6614
6626
|
}
|
|
6627
|
+
function hasCodePropertyLiteral(codeContent, property, value) {
|
|
6628
|
+
const escapedValue = String(value).replace(".", "\\.");
|
|
6629
|
+
return new RegExp(`${property}\\s*:\\s*${escapedValue}(?:\\.0+)?\\b`).test(codeContent);
|
|
6630
|
+
}
|
|
6631
|
+
function hasResponsiveSurfaceConstraint(codeContent, designWidth) {
|
|
6632
|
+
const escapedWidth = String(designWidth).replace(".", "\\.");
|
|
6633
|
+
const directPatterns = [
|
|
6634
|
+
new RegExp(`maxWidth\\s*:\\s*${escapedWidth}(?:\\.0+)?\\b`),
|
|
6635
|
+
new RegExp(`width\\s*:\\s*${escapedWidth}(?:\\.0+)?\\b`),
|
|
6636
|
+
/ConstrainedBox\s*\(/,
|
|
6637
|
+
/BoxConstraints\s*\([^)]*maxWidth\s*:/,
|
|
6638
|
+
/LayoutBuilder\s*\(/,
|
|
6639
|
+
/MediaQuery\.(sizeOf|of)\(/,
|
|
6640
|
+
/math\.(min|max)\(/,
|
|
6641
|
+
/clamp\(/
|
|
6642
|
+
];
|
|
6643
|
+
return directPatterns.some((pattern) => pattern.test(codeContent));
|
|
6644
|
+
}
|
|
6645
|
+
function hasWideStretchRisk(codeContent) {
|
|
6646
|
+
const edgePinnedPositioned = /Positioned\([\s\S]{0,220}left\s*:\s*[-\d.]+[\s\S]{0,220}right\s*:\s*[-\d.]+/.test(codeContent) || /Positioned\([\s\S]{0,220}right\s*:\s*[-\d.]+[\s\S]{0,220}left\s*:\s*[-\d.]+/.test(codeContent);
|
|
6647
|
+
return edgePinnedPositioned || /SizedBox\.expand\s*\(/.test(codeContent) || /double\.infinity/.test(codeContent);
|
|
6648
|
+
}
|
|
6649
|
+
function collectVisualFrameContracts(node, bucket = []) {
|
|
6650
|
+
if (!node) {
|
|
6651
|
+
return bucket;
|
|
6652
|
+
}
|
|
6653
|
+
if (node.f && node.vf) {
|
|
6654
|
+
const hasVisualDelta = node.f.some((value, index) => value !== node.vf[index]);
|
|
6655
|
+
if (hasVisualDelta) {
|
|
6656
|
+
bucket.push({
|
|
6657
|
+
nodeName: node.n || node.t || "unknown",
|
|
6658
|
+
frame: node.f,
|
|
6659
|
+
visualFrame: node.vf
|
|
6660
|
+
});
|
|
6661
|
+
}
|
|
6662
|
+
}
|
|
6663
|
+
for (const child of node.ch || []) {
|
|
6664
|
+
collectVisualFrameContracts(child, bucket);
|
|
6665
|
+
}
|
|
6666
|
+
return bucket;
|
|
6667
|
+
}
|
|
6668
|
+
function resolveProjectAssetPath(projectPath, assetPath) {
|
|
6669
|
+
return path20.join(projectPath, assetPath);
|
|
6670
|
+
}
|
|
6671
|
+
function getBitmapScaleVariantPaths(projectPath, assetPath) {
|
|
6672
|
+
const relativeDir = path20.posix.dirname(assetPath);
|
|
6673
|
+
const fileName = path20.posix.basename(assetPath);
|
|
6674
|
+
return [
|
|
6675
|
+
path20.join(projectPath, relativeDir, "2.0x", fileName),
|
|
6676
|
+
path20.join(projectPath, relativeDir, "3.0x", fileName)
|
|
6677
|
+
];
|
|
6678
|
+
}
|
|
6615
6679
|
function extractPageClassName(codeContent) {
|
|
6616
6680
|
const match = codeContent.match(/class\s+([A-Za-z0-9_]+)\s+extends\s+(StatelessWidget|StatefulWidget)/);
|
|
6617
6681
|
return (match == null ? void 0 : match[1]) || null;
|
|
6618
6682
|
}
|
|
6619
6683
|
function buildContractValidator(payload, codeContent) {
|
|
6620
|
-
var _a, _b, _c;
|
|
6684
|
+
var _a, _b, _c, _d, _e;
|
|
6621
6685
|
const findings = [];
|
|
6622
6686
|
const blockOrder = ((_a = payload.restorationContract) == null ? void 0 : _a.blockOrder) || [];
|
|
6623
6687
|
const navCopyLedger = ((_b = payload.restorationContract) == null ? void 0 : _b.navCopyLedger) || [];
|
|
@@ -6694,6 +6758,34 @@ function buildContractValidator(payload, codeContent) {
|
|
|
6694
6758
|
});
|
|
6695
6759
|
}
|
|
6696
6760
|
}
|
|
6761
|
+
const designWidth = ((_d = payload.designSurface) == null ? void 0 : _d.maxWidth) || ((_e = payload.artboard) == null ? void 0 : _e.w);
|
|
6762
|
+
if (designWidth && designWidth <= 430) {
|
|
6763
|
+
const isClamped = hasResponsiveSurfaceConstraint(codeContent, designWidth);
|
|
6764
|
+
if (hasWideStretchRisk(codeContent) && !isClamped) {
|
|
6765
|
+
findings.push({
|
|
6766
|
+
id: "design_surface_constraint_missing",
|
|
6767
|
+
severity: "error",
|
|
6768
|
+
message: `\u5F53\u524D\u8BBE\u8BA1\u7A3F\u4E3A ${designWidth} \u5BBD\u79FB\u52A8\u7AEF\u753B\u677F\uFF0C\u4F46\u4EE3\u7801\u672A\u68C0\u6D4B\u5230\u5BBD\u5C4F\u5939\u6301\u7EA6\u675F\uFF0C\u5BBD\u7A97\u53E3\u4E0B\u4F1A\u88AB\u76F4\u63A5\u62C9\u4F38\u3002`,
|
|
6769
|
+
suggestion: "\u5916\u5C42\u5148\u7528 Center + ConstrainedBox(maxWidth: designSurface.maxWidth) \u6216\u7B49\u6548\u7EA6\u675F\uFF0C\u518D\u5728\u7EA6\u675F\u5185\u4F7F\u7528 Positioned/Stack\u3002"
|
|
6770
|
+
});
|
|
6771
|
+
}
|
|
6772
|
+
}
|
|
6773
|
+
const visualFrameContracts = collectVisualFrameContracts(payload.tree);
|
|
6774
|
+
for (const contract of visualFrameContracts) {
|
|
6775
|
+
const [, , frameWidth, frameHeight] = contract.frame;
|
|
6776
|
+
const [, , visualWidth, visualHeight] = contract.visualFrame;
|
|
6777
|
+
const widthMismatch = frameWidth !== visualWidth && hasCodePropertyLiteral(codeContent, "width", frameWidth) && !hasCodePropertyLiteral(codeContent, "width", visualWidth);
|
|
6778
|
+
const heightMismatch = frameHeight !== visualHeight && hasCodePropertyLiteral(codeContent, "height", frameHeight) && !hasCodePropertyLiteral(codeContent, "height", visualHeight);
|
|
6779
|
+
if (widthMismatch || heightMismatch) {
|
|
6780
|
+
findings.push({
|
|
6781
|
+
id: "visual_frame_literal_mismatch",
|
|
6782
|
+
severity: "warning",
|
|
6783
|
+
message: `${contract.nodeName} \u7684\u89C6\u89C9\u8FB9\u754C\u662F ${visualWidth}x${visualHeight}\uFF0C\u4F46\u4EE3\u7801\u770B\u8D77\u6765\u4ECD\u5728\u4F7F\u7528\u903B\u8F91 frame ${frameWidth}x${frameHeight}\uFF0C\u5BB9\u6613\u9020\u6210\u5E95\u8FB9\u8DDD\u6216\u9634\u5F71\u89C6\u89C9\u8BEF\u5DEE\u3002`,
|
|
6784
|
+
evidence: [`${contract.nodeName}: frame=${contract.frame.join(",")} visualFrame=${contract.visualFrame.join(",")}`],
|
|
6785
|
+
suggestion: "\u5F53 compact \u540C\u65F6\u7ED9\u51FA f \u4E0E vf \u65F6\uFF0C\u5916\u5C42\u5BB9\u5668\u5C3A\u5BF8\u548C\u7531\u6B64\u63A8\u5BFC\u7684\u5E95\u90E8\u89C6\u89C9\u95F4\u8DDD\u4F18\u5148\u4EE5 vf \u4E3A\u51C6\u3002"
|
|
6786
|
+
});
|
|
6787
|
+
}
|
|
6788
|
+
}
|
|
6697
6789
|
return {
|
|
6698
6790
|
passed: !findings.some((item) => item.severity === "error"),
|
|
6699
6791
|
requiredBlocks,
|
|
@@ -6701,7 +6793,7 @@ function buildContractValidator(payload, codeContent) {
|
|
|
6701
6793
|
findings
|
|
6702
6794
|
};
|
|
6703
6795
|
}
|
|
6704
|
-
function buildAssetValidator(payload, codeContent) {
|
|
6796
|
+
function buildAssetValidator(payload, codeContent, args) {
|
|
6705
6797
|
const findings = [];
|
|
6706
6798
|
const assetContracts = collectAssetContracts(payload.tree);
|
|
6707
6799
|
const expectedVectorFiles = new Set(
|
|
@@ -6738,6 +6830,54 @@ function buildAssetValidator(payload, codeContent) {
|
|
|
6738
6830
|
suggestion: "\u4F4D\u56FE\u8D44\u6E90\u4F18\u5148\u6309\u5F53\u524D\u753B\u677F\u76F4\u63A5\u5BFC\u51FA\u5230 assets/icons/\uFF0C\u907F\u514D\u7EE7\u7EED\u590D\u7528\u65E7\u9875\u9762 PNG\u3002"
|
|
6739
6831
|
});
|
|
6740
6832
|
}
|
|
6833
|
+
if (expectedBitmapCount > 0 && codeBitmapAssets.length > 0) {
|
|
6834
|
+
const pageClassName = extractPageClassName(codeContent) || "";
|
|
6835
|
+
const normalizedStem = pageClassName.replace(/Page$/, "").replace(/([a-z])([A-Z])/g, "$1_$2").toLowerCase();
|
|
6836
|
+
if (normalizedStem) {
|
|
6837
|
+
const hasPageLocalBitmap = codeBitmapAssets.some(
|
|
6838
|
+
(asset) => path20.posix.basename(asset).toLowerCase().includes(normalizedStem)
|
|
6839
|
+
);
|
|
6840
|
+
if (!hasPageLocalBitmap) {
|
|
6841
|
+
findings.push({
|
|
6842
|
+
id: "bitmap_assets_not_page_local",
|
|
6843
|
+
severity: "warning",
|
|
6844
|
+
message: "\u5F53\u524D\u9875\u9762\u4F4D\u56FE\u8D44\u6E90\u770B\u8D77\u6765\u4E0D\u662F page-local \u547D\u540D\uFF0C\u5B58\u5728\u7EE7\u7EED\u590D\u7528\u65E7\u9875\u9762 PNG \u7684\u98CE\u9669\u3002",
|
|
6845
|
+
evidence: codeBitmapAssets,
|
|
6846
|
+
suggestion: "\u4F4D\u56FE\u8D44\u6E90\u4F18\u5148\u6309\u5F53\u524D\u9875\u9762\u547D\u540D\u5BFC\u51FA\uFF0C\u4F8B\u5982\u5E26\u4E0A\u9875\u9762 stem\uFF0C\u907F\u514D\u6DF7\u5165\u65E7\u9875\u9762\u901A\u7528 PNG\u3002"
|
|
6847
|
+
});
|
|
6848
|
+
}
|
|
6849
|
+
}
|
|
6850
|
+
}
|
|
6851
|
+
const expectedBitmapScales = new Set(
|
|
6852
|
+
assetContracts.filter((item) => item.sourceType === "bitmap").flatMap((item) => item.scaleVariants || [])
|
|
6853
|
+
);
|
|
6854
|
+
if (expectedBitmapCount > 0 && codeBitmapAssets.length > 0 && args.projectPath) {
|
|
6855
|
+
const requiresRetinaVariants = expectedBitmapScales.size === 0 || expectedBitmapScales.has("2.0x") || expectedBitmapScales.has("3.0x");
|
|
6856
|
+
if (requiresRetinaVariants) {
|
|
6857
|
+
const missingRetinaEvidence = [];
|
|
6858
|
+
for (const asset of codeBitmapAssets) {
|
|
6859
|
+
const assetOnDisk = resolveProjectAssetPath(args.projectPath, asset);
|
|
6860
|
+
if (!fs20.existsSync(assetOnDisk)) {
|
|
6861
|
+
missingRetinaEvidence.push(`${asset} (base missing)`);
|
|
6862
|
+
continue;
|
|
6863
|
+
}
|
|
6864
|
+
const variantPaths = getBitmapScaleVariantPaths(args.projectPath, asset);
|
|
6865
|
+
const missingVariants = variantPaths.filter((variantPath) => !fs20.existsSync(variantPath)).map((variantPath) => path20.relative(args.projectPath, variantPath));
|
|
6866
|
+
if (missingVariants.length > 0) {
|
|
6867
|
+
missingRetinaEvidence.push(`${asset} -> missing ${missingVariants.join(", ")}`);
|
|
6868
|
+
}
|
|
6869
|
+
}
|
|
6870
|
+
if (missingRetinaEvidence.length > 0) {
|
|
6871
|
+
findings.push({
|
|
6872
|
+
id: "bitmap_retina_variants_missing",
|
|
6873
|
+
severity: "error",
|
|
6874
|
+
message: "\u4F4D\u56FE\u8D44\u6E90\u7F3A\u5C11 2.0x/3.0x \u53D8\u4F53\uFF0C\u9AD8\u5206\u5C4F\u4E0B\u5BB9\u6613\u53D1\u7CCA\u3002",
|
|
6875
|
+
evidence: missingRetinaEvidence,
|
|
6876
|
+
suggestion: "\u6309\u5F53\u524D\u753B\u677F\u91CD\u65B0\u5BFC\u51FA PNG\uFF0C\u5E76\u8865\u9F50 assets/.../2.0x \u4E0E 3.0x \u53D8\u4F53\u540E\u518D\u9A8C\u6536\u3002"
|
|
6877
|
+
});
|
|
6878
|
+
}
|
|
6879
|
+
}
|
|
6880
|
+
}
|
|
6741
6881
|
const preserveContracts = assetContracts.filter((item) => item.mode === "preserve");
|
|
6742
6882
|
if (preserveContracts.length > 0 && /colorFilter\s*:|ColorFilter\./.test(codeContent)) {
|
|
6743
6883
|
findings.push({
|
|
@@ -6849,7 +6989,7 @@ async function validateRestoration(args) {
|
|
|
6849
6989
|
const payload = loadMeasurePayload(args);
|
|
6850
6990
|
const codeContent = fs20.readFileSync(args.codeFilePath, "utf-8");
|
|
6851
6991
|
const contractValidator = buildContractValidator(payload, codeContent);
|
|
6852
|
-
const assetValidator = buildAssetValidator(payload, codeContent);
|
|
6992
|
+
const assetValidator = buildAssetValidator(payload, codeContent, args);
|
|
6853
6993
|
const routeReviewValidator = buildRouteReviewValidator(args, codeContent);
|
|
6854
6994
|
return {
|
|
6855
6995
|
artboardName: (_a = payload.artboard) == null ? void 0 : _a.name,
|