@invarn/cibuild 2.0.5 → 2.0.6
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.
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ui-fidelity-render.d.ts","sourceRoot":"","sources":["../../../../src/yaml/steps/ui-fidelity-render.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAiDG;AAEH,OAAO,EAAE,gBAAgB,EAAE,MAAM,WAAW,CAAC;AAC7C,OAAO,KAAK,EAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,gBAAgB,CAAC;AACxD,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,wBAAwB,CAAC;AAEpE;;GAEG;AACH,MAAM,WAAW,sBAAsB;IACrC;;;;;;OAMG;IACH,cAAc,CAAC,EAAE,MAAM,GAAG,QAAQ,CAAC;IACnC;;;OAGG;IACH,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB;;;;;OAKG;IACH,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,mFAAmF;IACnF,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,6DAA6D;IAC7D,KAAK,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;CACzB;AAED;;;;;GAKG;AACH,eAAO,MAAM,mBAAmB,YAAY,CAAC;AAE7C,mFAAmF;AACnF,eAAO,MAAM,aAAa,IAAI,CAAC;AAE/B,iDAAiD;AACjD,eAAO,MAAM,eAAe,6BAA8B,CAAC;AAC3D,MAAM,MAAM,aAAa,GAAG,CAAC,OAAO,eAAe,CAAC,CAAC,MAAM,CAAC,CAAC;AAE7D,sEAAsE;AACtE,eAAO,MAAM,sBAAsB,EAAE,aAAsB,CAAC;AAE5D,+EAA+E;AAC/E,eAAO,MAAM,wBAAwB,mBAAmB,CAAC;AAEzD;;;;;;;GAOG;AACH,eAAO,MAAM,2BAA2B,QAAmB,CAAC;AAE5D,MAAM,WAAW,UAAU;IACzB,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;CAChB;AAED;;;GAGG;AACH,wBAAgB,eAAe,CAAC,KAAK,EAAE,MAAM,GAAG,UAAU,CAWzD;AAED;;;GAGG;AACH,wBAAgB,UAAU,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,GAAG,MAAM,CAQzD;AAED;;;;;;;;;;;GAWG;AACH,MAAM,WAAW,kBAAkB;IACjC,2EAA2E;IAC3E,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,yEAAyE;IACzE,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;IACtB,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,MAAM,CAAC;IACd,aAAa,CAAC,EAAE,aAAa,CAAC;CAC/B;AAED,4DAA4D;AAC5D,MAAM,WAAW,uBAAuB;IACtC,WAAW,EAAE,MAAM,CAAC;IACpB,UAAU,EAAE,MAAM,CAAC;IACnB,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,MAAM,CAAC;CACf;AAED,gFAAgF;AAChF,MAAM,WAAW,qBAAqB;IACpC,kBAAkB,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAAC;IAC1C,2BAA2B,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE,OAAO,EAAE,uBAAuB,GAAG,MAAM,CAAC;IACzF,kBAAkB,CAAC,OAAO,EAAE,uBAAuB,GAAG,MAAM,CAAC;IAC7D,mBAAmB,CAAC,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,uBAAuB,GAAG,MAAM,CAAC;CAC/E;
|
|
1
|
+
{"version":3,"file":"ui-fidelity-render.d.ts","sourceRoot":"","sources":["../../../../src/yaml/steps/ui-fidelity-render.ts"],"names":[],"mappings":"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"}
|
|
@@ -1039,8 +1039,11 @@ var TRIM_HELPER_SWIFT = [
|
|
|
1039
1039
|
' return ctx.makeImage()',
|
|
1040
1040
|
'}',
|
|
1041
1041
|
'',
|
|
1042
|
-
'// Bounding box of pixels
|
|
1043
|
-
'
|
|
1042
|
+
'// Bounding box of content: pixels that are neither transparent nor part of a',
|
|
1043
|
+
'// uniform solid background. The background is detected from the four corners',
|
|
1044
|
+
'// (opaque and agreeing within a tight tolerance); when the corners disagree,',
|
|
1045
|
+
'// only transparency is trimmed. Top-left image coordinates.',
|
|
1046
|
+
'func contentBoundingBox(_ image: CGImage) -> CGRect? {',
|
|
1044
1047
|
' let w = image.width, h = image.height',
|
|
1045
1048
|
' if w == 0 || h == 0 { return nil }',
|
|
1046
1049
|
' let bytesPerRow = w * 4',
|
|
@@ -1048,11 +1051,36 @@ var TRIM_HELPER_SWIFT = [
|
|
|
1048
1051
|
' let space = CGColorSpaceCreateDeviceRGB()',
|
|
1049
1052
|
' guard let ctx = CGContext(data: &data, width: w, height: h, bitsPerComponent: 8, bytesPerRow: bytesPerRow, space: space, bitmapInfo: CGImageAlphaInfo.premultipliedLast.rawValue) else { return nil }',
|
|
1050
1053
|
' ctx.draw(image, in: CGRect(x: 0, y: 0, width: w, height: h))',
|
|
1054
|
+
' // Tight tolerance: exact solid fills match, near-colored content does not.',
|
|
1055
|
+
' let tolerance = 4',
|
|
1056
|
+
' func sample(_ x: Int, _ y: Int) -> (Int, Int, Int, Int) {',
|
|
1057
|
+
' let i = y * bytesPerRow + x * 4',
|
|
1058
|
+
' return (Int(data[i]), Int(data[i + 1]), Int(data[i + 2]), Int(data[i + 3]))',
|
|
1059
|
+
' }',
|
|
1060
|
+
' // Detect a uniform opaque background shared by all four corners.',
|
|
1061
|
+
' let corners = [sample(0, 0), sample(w - 1, 0), sample(0, h - 1), sample(w - 1, h - 1)]',
|
|
1062
|
+
' var background: (Int, Int, Int, Int)? = corners[0]',
|
|
1063
|
+
' for c in corners {',
|
|
1064
|
+
' if let bg = background {',
|
|
1065
|
+
' if c.3 == 0 || abs(c.0 - bg.0) > tolerance || abs(c.1 - bg.1) > tolerance || abs(c.2 - bg.2) > tolerance || abs(c.3 - bg.3) > tolerance {',
|
|
1066
|
+
' background = nil',
|
|
1067
|
+
' }',
|
|
1068
|
+
' }',
|
|
1069
|
+
' }',
|
|
1051
1070
|
' var minX = w, minY = h, maxX = -1, maxY = -1',
|
|
1052
1071
|
' for y in 0..<h {',
|
|
1053
1072
|
' let rowBase = y * bytesPerRow',
|
|
1054
1073
|
' for x in 0..<w {',
|
|
1055
|
-
'
|
|
1074
|
+
' let idx = rowBase + x * 4',
|
|
1075
|
+
' let a = Int(data[idx + 3])',
|
|
1076
|
+
' var isMargin = a == 0',
|
|
1077
|
+
' if !isMargin, let bg = background {',
|
|
1078
|
+
' let r = Int(data[idx]), g = Int(data[idx + 1]), b = Int(data[idx + 2])',
|
|
1079
|
+
' if abs(r - bg.0) <= tolerance && abs(g - bg.1) <= tolerance && abs(b - bg.2) <= tolerance && abs(a - bg.3) <= tolerance {',
|
|
1080
|
+
' isMargin = true',
|
|
1081
|
+
' }',
|
|
1082
|
+
' }',
|
|
1083
|
+
' if !isMargin {',
|
|
1056
1084
|
' if x < minX { minX = x }',
|
|
1057
1085
|
' if x > maxX { maxX = x }',
|
|
1058
1086
|
' if y < minY { minY = y }',
|
|
@@ -1075,8 +1103,8 @@ var TRIM_HELPER_SWIFT = [
|
|
|
1075
1103
|
' FileHandle.standardError.write(Data(("could not read image at " + inputPath).utf8))',
|
|
1076
1104
|
' exit(65)',
|
|
1077
1105
|
'}',
|
|
1078
|
-
'guard let box =
|
|
1079
|
-
' FileHandle.standardError.write(Data("
|
|
1106
|
+
'guard let box = contentBoundingBox(image) else {',
|
|
1107
|
+
' FileHandle.standardError.write(Data("no content to trim (image is uniform)".utf8))',
|
|
1080
1108
|
' exit(66)',
|
|
1081
1109
|
'}',
|
|
1082
1110
|
'guard let cropped = image.cropping(to: box) else {',
|
|
@@ -1106,8 +1134,9 @@ var TRIM_HELPER_SWIFT = [
|
|
|
1106
1134
|
' }',
|
|
1107
1135
|
'}',
|
|
1108
1136
|
'',
|
|
1109
|
-
'// Report: rendered (trimmed) px
|
|
1110
|
-
'
|
|
1137
|
+
'// Report: rendered (trimmed) px, reference px (0 0 when unavailable), then',
|
|
1138
|
+
'// the pre-trim source px so the caller can log how much margin was removed.',
|
|
1139
|
+
'print("TRIMDIMS " + String(croppedWidth) + " " + String(croppedHeight) + " " + String(referenceWidth) + " " + String(referenceHeight) + " " + String(image.width) + " " + String(image.height))'
|
|
1111
1140
|
].join('\n') + '\n';
|
|
1112
1141
|
|
|
1113
1142
|
// Write the helper into the harness dir once (idempotent across screens).
|
|
@@ -1124,15 +1153,23 @@ function roundTwo(value) {
|
|
|
1124
1153
|
return Math.round(value * 100) / 100;
|
|
1125
1154
|
}
|
|
1126
1155
|
|
|
1127
|
-
// Parse the helper's "TRIMDIMS <rW> <rH> <refW> <refH>" line
|
|
1156
|
+
// Parse the helper's "TRIMDIMS <rW> <rH> <refW> <refH> <srcW> <srcH>" line
|
|
1157
|
+
// (rendered/reference/source px; last one wins).
|
|
1128
1158
|
function parseTrimDims(stdout) {
|
|
1129
1159
|
var lines = String(stdout || '').split('\n');
|
|
1130
1160
|
for (var i = lines.length - 1; i >= 0; i--) {
|
|
1131
1161
|
var parts = lines[i].trim().split(/\s+/);
|
|
1132
|
-
if (parts[0] === 'TRIMDIMS' && parts.length >=
|
|
1133
|
-
var nums = [
|
|
1162
|
+
if (parts[0] === 'TRIMDIMS' && parts.length >= 7) {
|
|
1163
|
+
var nums = [
|
|
1164
|
+
Number(parts[1]), Number(parts[2]), Number(parts[3]),
|
|
1165
|
+
Number(parts[4]), Number(parts[5]), Number(parts[6]),
|
|
1166
|
+
];
|
|
1134
1167
|
if (nums.every(function (n) { return Number.isFinite(n); })) {
|
|
1135
|
-
return {
|
|
1168
|
+
return {
|
|
1169
|
+
rendered: [nums[0], nums[1]],
|
|
1170
|
+
reference: [nums[2], nums[3]],
|
|
1171
|
+
source: [nums[4], nums[5]],
|
|
1172
|
+
};
|
|
1136
1173
|
}
|
|
1137
1174
|
}
|
|
1138
1175
|
}
|
|
@@ -1171,6 +1208,12 @@ function trimRenderedImage(entry, renderedPath, harnessDir) {
|
|
|
1171
1208
|
logical_pt: [roundTwo(dims.rendered[0] / scale), roundTwo(dims.rendered[1] / scale)],
|
|
1172
1209
|
reference_px: dims.reference[0] > 0 && dims.reference[1] > 0 ? dims.reference : null,
|
|
1173
1210
|
};
|
|
1211
|
+
// Surface how much margin was removed -- a no-op (source == rendered) means
|
|
1212
|
+
// the view fills an opaque canvas with no transparent or uniform margin.
|
|
1213
|
+
log(
|
|
1214
|
+
'trimmed ' + entry.screen + ': ' + dims.source[0] + 'x' + dims.source[1] +
|
|
1215
|
+
' -> ' + dims.rendered[0] + 'x' + dims.rendered[1]
|
|
1216
|
+
);
|
|
1174
1217
|
}
|
|
1175
1218
|
if (fs.existsSync(alignedPath)) {
|
|
1176
1219
|
entry.aligned_image_path = alignedRelative;
|
|
@@ -116,7 +116,8 @@ const FAKE_SWIFT_LINES = [
|
|
|
116
116
|
// stands in for the CoreGraphics trim helper. Overwrites <out> with a PNG
|
|
117
117
|
// marked "trimmed:<in basename>" and writes an "aligned:<in basename>" PNG so
|
|
118
118
|
// tests can prove both outputs. Emits a fixed TRIMDIMS line (rendered
|
|
119
|
-
// 320x640, reference 160x320). FAKE_TRIM_FAIL exercises
|
|
119
|
+
// 320x640, reference 160x320, source 400x800). FAKE_TRIM_FAIL exercises
|
|
120
|
+
// warn-and-continue.
|
|
120
121
|
' if [ -n "$FAKE_TRIM_FAIL" ]; then echo "trim: simulated failure" >&2; exit 1; fi',
|
|
121
122
|
' in_png="$1"; out_png="$2"; aligned_png="$3"',
|
|
122
123
|
" printf '\\x89PNG\\r\\n\\x1a\\n' > \"$out_png\"",
|
|
@@ -125,7 +126,7 @@ const FAKE_SWIFT_LINES = [
|
|
|
125
126
|
" printf '\\x89PNG\\r\\n\\x1a\\n' > \"$aligned_png\"",
|
|
126
127
|
' printf \'aligned:%s\' "$(basename "$in_png")" >> "$aligned_png"',
|
|
127
128
|
' fi',
|
|
128
|
-
' echo "TRIMDIMS 320 640 160 320"',
|
|
129
|
+
' echo "TRIMDIMS 320 640 160 320 400 800"',
|
|
129
130
|
' exit 0 ;;',
|
|
130
131
|
' *)',
|
|
131
132
|
' exit 0 ;;',
|
|
@@ -1030,6 +1031,15 @@ describe('render output trimming (package_source variants)', () => {
|
|
|
1030
1031
|
reference_px: [160, 320],
|
|
1031
1032
|
});
|
|
1032
1033
|
});
|
|
1034
|
+
test('logs how much margin the trim removed (source -> rendered)', async () => {
|
|
1035
|
+
const project = makeProject({ screens: { HomeView: 'home.png' } });
|
|
1036
|
+
writeReference(project, 'home.png');
|
|
1037
|
+
const run = runScript(project, await buildScript(project, { package_source: 'repo' }));
|
|
1038
|
+
expect(run.status).toBe(0);
|
|
1039
|
+
// The pre-trim source size and the trimmed size are both surfaced, so a
|
|
1040
|
+
// no-op trim (an opaque-canvas wrapper) is visible in the build log.
|
|
1041
|
+
expect(run.stdout).toContain('trimmed HomeView: 400x800 -> 320x640');
|
|
1042
|
+
});
|
|
1033
1043
|
test('a failing trim warns but still renders (warn-and-continue)', async () => {
|
|
1034
1044
|
const project = makeProject({ screens: { HomeView: 'home.png' } });
|
|
1035
1045
|
writeReference(project, 'home.png');
|