ADFA-3736 | Ignore canvas metadata and fix attribute parsing#1241
ADFA-3736 | Ignore canvas metadata and fix attribute parsing#1241
Conversation
📝 WalkthroughRelease Notes - ADFA-3736: Canvas Metadata Filtering & Attribute ParsingFeatures
Risks & Best Practice Violations
Testing Recommendations
WalkthroughSix domain-layer files updated: margin annotation now unconditionally records explicit-tag blocks; tag extraction regex broadened; UI-candidate selection filters canvas metadata; entries validator always normalizes bracketed lists; ImageView grammar accepts two new attributes; TextCleaner gains canvas-metadata detection. Changes
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~20 minutes Possibly related PRs
Suggested reviewers
Poem
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Actionable comments posted: 1
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (2)
cv-image-to-xml/src/main/java/org/appdevforall/codeonthego/computervision/domain/WidgetAnnotationMatcher.kt (1)
74-85:⚠️ Potential issue | 🔴 CriticalThe metadata filtering does not protect against tag misclassification at line 44.
Line 44 extracts
widgetTagsfrom the original unfiltereddetectionslist usingisTag(), while metadata filtering viaTextCleaner.isCanvasMetadata()is only applied touiCandidates(line 25). This means canvas metadata strings that happen to start with a tag letter + digit (e.g.,"B 1 layout_width","C 3 wrap_content") can pass theisTag()check—becausenormalizeTagText("B 1 layout_width")returns"B-1"—and incorrectly be classified as widget tags. The metadata filter should also be applied when extractingwidgetTagsfrom the original detections, orwidgetTagsshould be filtered to exclude metadata after extraction.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@cv-image-to-xml/src/main/java/org/appdevforall/codeonthego/computervision/domain/WidgetAnnotationMatcher.kt` around lines 74 - 85, The widget tag extraction currently uses isTag() on the raw detections, allowing canvas metadata (e.g., "B 1 layout_width") to be misclassified; update the extraction to apply the same metadata filter used for uiCandidates—use TextCleaner.isCanvasMetadata(...) to skip metadata strings when building widgetTags from detections or, after computing widgetTags, filter out any entries where TextCleaner.isCanvasMetadata(originalDetection) is true; ensure the change touches the code that builds widgetTags and preserves use of normalizeTagText/isTag for validation.cv-image-to-xml/src/main/java/org/appdevforall/codeonthego/computervision/domain/grammar/AttributeValidator.kt (1)
56-80:⚠️ Potential issue | 🟠 MajorBehavior change causes silent data loss:
[...]array format generated by validator is discarded by parseStringArray downstream.The validator now returns
"[$finalString]"for all non-@resource inputs, butparseStringArray()in basicParseUtils.kt does not parse this format. The function only handles@referencestrings or empty inputs; for any other string (including"[red]"or"[]"), it returns the defaultemptyArray(). This means OCR'd literals likeredbecome[red], then silently convert to empty arrays downstream instead of being validated as text entries. For genuinely empty inputs,[]will also become empty arrays—but if the goal is to represent empty entry arrays with a canonical format, the current approach loses that distinction. Either: (1) modifyparseStringArray()to actually parse the[...]format, or (2) returnnullfrom the validator when the result would be empty so the attribute is omitted entirely.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@cv-image-to-xml/src/main/java/org/appdevforall/codeonthego/computervision/domain/grammar/AttributeValidator.kt` around lines 56 - 80, The validator now emits bracketed arrays (AttributeValidator.validate) but parseStringArray in basicParseUtils.kt doesn't handle that format, causing silent data loss; update parseStringArray to detect strings that start with "[" and end with "]", strip the brackets, split on commas (respecting trimming and empty cases), return an array of the trimmed items (empty array for "[]"), and still continue to support the existing `@reference` and empty-input behavior so bracketed values like "[red]" are parsed correctly instead of being dropped.
🧹 Nitpick comments (4)
cv-image-to-xml/src/main/java/org/appdevforall/codeonthego/computervision/domain/WidgetAnnotationMatcher.kt (1)
8-8: Nit: make the trailing-suffix group non-capturing.
normalizeTagTextonly readsgroupValues[1]andgroupValues[2]; the new third group(.+)is captured but never used. Switching it to a non-capturing group communicates intent (we only want to tolerate/discard OCR noise after the ordinal) and avoids allocating the extra match group.♻️ Proposed tweak
- private val TAG_EXTRACT_REGEX = Regex("^(?i)(SW|S\\s*8|8\\s*W|[BPDTCRS8]\\s*W?)[^a-zA-Z0-9]*([\\dlIoO!]+)(?:\\s+(.+))?$") + private val TAG_EXTRACT_REGEX = Regex("^(?i)(SW|S\\s*8|8\\s*W|[BPDTCRS8]\\s*W?)[^a-zA-Z0-9]*([\\dlIoO!]+)(?:\\s+.+)?$")🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@cv-image-to-xml/src/main/java/org/appdevforall/codeonthego/computervision/domain/WidgetAnnotationMatcher.kt` at line 8, The TAG_EXTRACT_REGEX currently captures a trailing suffix with a third group "(.+)" even though normalizeTagText only uses groupValues[1] and groupValues[2]; change that trailing group to non-capturing (?:.+) so the regex still tolerates/discards OCR noise but doesn't allocate an unused capture. Update the Regex literal assigned to TAG_EXTRACT_REGEX in WidgetAnnotationMatcher (and ensure normalizeTagText remains unchanged).cv-image-to-xml/src/main/java/org/appdevforall/codeonthego/computervision/utils/TextCleaner.kt (2)
37-40: Optional: useignoreCaseflag to avoid the lowercase allocation.
String.containsaccepts anignoreCaseparameter, which avoids allocating a lowercased copy oftextfor each call. On hot paths (YOLO detections can be numerous), this is a small but free win.🔧 Suggested change
fun isCanvasMetadata(text: String): Boolean { - val lowerText = text.lowercase() - return METADATA_KEYWORDS.any { keyword -> lowerText.contains(keyword) } + return METADATA_KEYWORDS.any { keyword -> text.contains(keyword, ignoreCase = true) } }🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@cv-image-to-xml/src/main/java/org/appdevforall/codeonthego/computervision/utils/TextCleaner.kt` around lines 37 - 40, The isCanvasMetadata function currently allocates a lowercase copy of text before checking keywords; change the check to call lowerText.contains(keyword) replacement by using text.contains(keyword, ignoreCase = true) inside the METADATA_KEYWORDS.any lambda so you avoid the lowercase allocation. Locate isCanvasMetadata and METADATA_KEYWORDS in TextCleaner.kt and update the predicate to use String.contains with ignoreCase rather than creating lowerText.
6-11: Minor: naming convention inconsistency.The existing private
val nonAlphanumericRegexuses camelCase, while the newMETADATA_KEYWORDSuses UPPER_SNAKE_CASE. Both areprivate valproperties on the sameobject, so consider picking one style for consistency (Kotlin conventions allowUPPER_SNAKE_CASEforconst val/ compile-time constants; for runtimevals,camelCaseis typical).🔧 Suggested change
- private val METADATA_KEYWORDS = listOf( + private val metadataKeywords = listOf( "layout_width", "layout_height", "match_parent", "wrap_content" )(and update the reference in
isCanvasMetadataaccordingly)🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@cv-image-to-xml/src/main/java/org/appdevforall/codeonthego/computervision/utils/TextCleaner.kt` around lines 6 - 11, Rename METADATA_KEYWORDS to follow the same camelCase style as nonAlphanumericRegex (e.g., metadataKeywords) since it's a private runtime val, and update any usages such as in isCanvasMetadata to reference the new name; ensure you only change the identifier (not the list contents) so behavior remains the same.cv-image-to-xml/src/main/java/org/appdevforall/codeonthego/computervision/domain/grammar/WidgetGrammar.kt (1)
29-30: Consider centralizing common View attributes.
android:backgroundandapp:backgroundTintare inherited by everyViewsubclass, so as more widget grammars need them you'll end up duplicating these entries in each grammar object. Consider extracting a sharedcommonViewAttributes: Map<String, AttributeValidator>and merging it into each widget'sattributesmap to avoid drift.private val commonViewAttributes = mapOf( "android:background" to PassThroughValidator, "app:backgroundTint" to PassThroughValidator, // ...layout_width/height, id, etc. )Not blocking for this PR; just flagging for the next iteration.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@cv-image-to-xml/src/main/java/org/appdevforall/codeonthego/computervision/domain/grammar/WidgetGrammar.kt` around lines 29 - 30, The android:background and app:backgroundTint entries are duplicated across widget grammars; extract those shared keys into a single reusable Map (e.g., private val commonViewAttributes) and merge it into each widget's attributes map when building grammar objects (merge commonViewAttributes with each widget's specific attributes in the widget grammar initializers), ensuring keys like "android:background" and "app:backgroundTint" are removed from individual maps and referenced only via commonViewAttributes.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In
`@cv-image-to-xml/src/main/java/org/appdevforall/codeonthego/computervision/domain/grammar/AttributeValidator.kt`:
- Around line 60-63: The trailing-character class in the content normalization
(in AttributeValidator -> the content = trimmed... chain using
Regex("[)}\\]>7]$")) incorrectly removes the digit '7'; remove '7' from that
character class and instead perform a targeted OCR-fix step: add a separate
normalization before trimming that only replaces a trailing '7' when it clearly
looks like an OCR artifact (e.g., when the char before it is a non-digit or when
a matching opening delimiter was present), so update the Regex call used to
strip closing delimiters to Regex("[)}\\]>]$") and implement a conditional
replacement for stray trailing '7' tied to that artifact detection within the
same method so EntriesValidator and other callers retain legitimate numeric
digits.
---
Outside diff comments:
In
`@cv-image-to-xml/src/main/java/org/appdevforall/codeonthego/computervision/domain/grammar/AttributeValidator.kt`:
- Around line 56-80: The validator now emits bracketed arrays
(AttributeValidator.validate) but parseStringArray in basicParseUtils.kt doesn't
handle that format, causing silent data loss; update parseStringArray to detect
strings that start with "[" and end with "]", strip the brackets, split on
commas (respecting trimming and empty cases), return an array of the trimmed
items (empty array for "[]"), and still continue to support the existing
`@reference` and empty-input behavior so bracketed values like "[red]" are parsed
correctly instead of being dropped.
In
`@cv-image-to-xml/src/main/java/org/appdevforall/codeonthego/computervision/domain/WidgetAnnotationMatcher.kt`:
- Around line 74-85: The widget tag extraction currently uses isTag() on the raw
detections, allowing canvas metadata (e.g., "B 1 layout_width") to be
misclassified; update the extraction to apply the same metadata filter used for
uiCandidates—use TextCleaner.isCanvasMetadata(...) to skip metadata strings when
building widgetTags from detections or, after computing widgetTags, filter out
any entries where TextCleaner.isCanvasMetadata(originalDetection) is true;
ensure the change touches the code that builds widgetTags and preserves use of
normalizeTagText/isTag for validation.
---
Nitpick comments:
In
`@cv-image-to-xml/src/main/java/org/appdevforall/codeonthego/computervision/domain/grammar/WidgetGrammar.kt`:
- Around line 29-30: The android:background and app:backgroundTint entries are
duplicated across widget grammars; extract those shared keys into a single
reusable Map (e.g., private val commonViewAttributes) and merge it into each
widget's attributes map when building grammar objects (merge
commonViewAttributes with each widget's specific attributes in the widget
grammar initializers), ensuring keys like "android:background" and
"app:backgroundTint" are removed from individual maps and referenced only via
commonViewAttributes.
In
`@cv-image-to-xml/src/main/java/org/appdevforall/codeonthego/computervision/domain/WidgetAnnotationMatcher.kt`:
- Line 8: The TAG_EXTRACT_REGEX currently captures a trailing suffix with a
third group "(.+)" even though normalizeTagText only uses groupValues[1] and
groupValues[2]; change that trailing group to non-capturing (?:.+) so the regex
still tolerates/discards OCR noise but doesn't allocate an unused capture.
Update the Regex literal assigned to TAG_EXTRACT_REGEX in
WidgetAnnotationMatcher (and ensure normalizeTagText remains unchanged).
In
`@cv-image-to-xml/src/main/java/org/appdevforall/codeonthego/computervision/utils/TextCleaner.kt`:
- Around line 37-40: The isCanvasMetadata function currently allocates a
lowercase copy of text before checking keywords; change the check to call
lowerText.contains(keyword) replacement by using text.contains(keyword,
ignoreCase = true) inside the METADATA_KEYWORDS.any lambda so you avoid the
lowercase allocation. Locate isCanvasMetadata and METADATA_KEYWORDS in
TextCleaner.kt and update the predicate to use String.contains with ignoreCase
rather than creating lowerText.
- Around line 6-11: Rename METADATA_KEYWORDS to follow the same camelCase style
as nonAlphanumericRegex (e.g., metadataKeywords) since it's a private runtime
val, and update any usages such as in isCanvasMetadata to reference the new
name; ensure you only change the identifier (not the list contents) so behavior
remains the same.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
Run ID: 1393e72a-75ce-4692-9c2e-6bd6c7e221a7
📒 Files selected for processing (6)
cv-image-to-xml/src/main/java/org/appdevforall/codeonthego/computervision/domain/MarginAnnotationParser.ktcv-image-to-xml/src/main/java/org/appdevforall/codeonthego/computervision/domain/WidgetAnnotationMatcher.ktcv-image-to-xml/src/main/java/org/appdevforall/codeonthego/computervision/domain/YoloToXmlConverter.ktcv-image-to-xml/src/main/java/org/appdevforall/codeonthego/computervision/domain/grammar/AttributeValidator.ktcv-image-to-xml/src/main/java/org/appdevforall/codeonthego/computervision/domain/grammar/WidgetGrammar.ktcv-image-to-xml/src/main/java/org/appdevforall/codeonthego/computervision/utils/TextCleaner.kt
Daniel-ADFA
left a comment
There was a problem hiding this comment.
LGTM, but please check code rabbits comment.
d86d1db to
fee9d2f
Compare
There was a problem hiding this comment.
🧹 Nitpick comments (1)
cv-image-to-xml/src/main/java/org/appdevforall/codeonthego/computervision/domain/WidgetAnnotationMatcher.kt (1)
8-8: Optional: make the trailing segment non-capturing.The broader regex is fine and aligns with
MarginAnnotationParser.extractTag's pattern. However, group 3 ((.+)) is never consumed bynormalizeTagText— onlygroupValues[1]andgroupValues[2]are used at lines 78–82. You can drop the capture to make intent explicit and avoid giving future readers the impression that trailing text is retained:♻️ Proposed tweak
- private val TAG_EXTRACT_REGEX = Regex("^(?i)(SW|S\\s*8|8\\s*W|[BPDTCRS8]\\s*W?)[^a-zA-Z0-9]*([\\dlIoO!]+)(?:\\s+(.+))?$") + private val TAG_EXTRACT_REGEX = Regex("^(?i)(SW|S\\s*8|8\\s*W|[BPDTCRS8]\\s*W?)[^a-zA-Z0-9]*([\\dlIoO!]+)(?:\\s+.+)?$")🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@cv-image-to-xml/src/main/java/org/appdevforall/codeonthego/computervision/domain/WidgetAnnotationMatcher.kt` at line 8, Change TAG_EXTRACT_REGEX to make the trailing segment non-capturing since normalizeTagText only uses the first two capture groups; update the regex in the WidgetAnnotationMatcher.kt declaration (TAG_EXTRACT_REGEX) to replace the third capture group "(.+)" with a non-capturing group "(?:.+)" so the pattern still matches trailing text but does not create an unused capture, keeping behavior consistent with MarginAnnotationParser.extractTag and the uses of groupValues[1] and groupValues[2] in normalizeTagText.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Nitpick comments:
In
`@cv-image-to-xml/src/main/java/org/appdevforall/codeonthego/computervision/domain/WidgetAnnotationMatcher.kt`:
- Line 8: Change TAG_EXTRACT_REGEX to make the trailing segment non-capturing
since normalizeTagText only uses the first two capture groups; update the regex
in the WidgetAnnotationMatcher.kt declaration (TAG_EXTRACT_REGEX) to replace the
third capture group "(.+)" with a non-capturing group "(?:.+)" so the pattern
still matches trailing text but does not create an unused capture, keeping
behavior consistent with MarginAnnotationParser.extractTag and the uses of
groupValues[1] and groupValues[2] in normalizeTagText.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
Run ID: 6081ff6c-a68c-4cb7-b30f-915c64417e6a
📒 Files selected for processing (6)
cv-image-to-xml/src/main/java/org/appdevforall/codeonthego/computervision/domain/MarginAnnotationParser.ktcv-image-to-xml/src/main/java/org/appdevforall/codeonthego/computervision/domain/WidgetAnnotationMatcher.ktcv-image-to-xml/src/main/java/org/appdevforall/codeonthego/computervision/domain/YoloToXmlConverter.ktcv-image-to-xml/src/main/java/org/appdevforall/codeonthego/computervision/domain/grammar/AttributeValidator.ktcv-image-to-xml/src/main/java/org/appdevforall/codeonthego/computervision/domain/grammar/WidgetGrammar.ktcv-image-to-xml/src/main/java/org/appdevforall/codeonthego/computervision/utils/TextCleaner.kt
✅ Files skipped from review due to trivial changes (2)
- cv-image-to-xml/src/main/java/org/appdevforall/codeonthego/computervision/utils/TextCleaner.kt
- cv-image-to-xml/src/main/java/org/appdevforall/codeonthego/computervision/domain/grammar/WidgetGrammar.kt
🚧 Files skipped from review as they are similar to previous changes (2)
- cv-image-to-xml/src/main/java/org/appdevforall/codeonthego/computervision/domain/YoloToXmlConverter.kt
- cv-image-to-xml/src/main/java/org/appdevforall/codeonthego/computervision/domain/grammar/AttributeValidator.kt
Description
This PR fixes an issue where margin and layout metadata present in the canvas areas were being incorrectly detected as text and included in the generated XML code, causing attribute mix-ups. It introduces a
METADATA_KEYWORDSlist to actively filter out these layout properties and updates the regex and validation logic to correctly parse widget tags and array attributes.Details
Logic updates only. YOLO text detections matching canvas metadata (e.g.,
layout_width,match_parent,wrap_content) are now successfully filtered out inYoloToXmlConverter.document_5141153794083523807.mp4
Ticket
ADFA-3736
Observation
In addition to the metadata filtering,
AttributeValidatorwas updated to more aggressively strip various enclosing bracket types (e.g.,(,{,<) before standardizing the final string array output to use square brackets[ ].android:backgroundandapp:backgroundTintwere also added as pass-through validators inWidgetGrammar.