Skip to content

feat: add iconpark lookup for lark slides#1123

Open
ethan-zhx wants to merge 1 commit into
mainfrom
feat/slide_icon_park
Open

feat: add iconpark lookup for lark slides#1123
ethan-zhx wants to merge 1 commit into
mainfrom
feat/slide_icon_park

Conversation

@ethan-zhx
Copy link
Copy Markdown
Collaborator

@ethan-zhx ethan-zhx commented May 27, 2026

Summary

Add IconPark lookup support for the lark-slides skill, including reference docs, index data, and a helper script for searching and selecting icons.

Changes

  • Add IconPark reference docs and generated icon index for lark-slides.
  • Add iconpark_tool.py with lookup helpers and tests.
  • Update lark-slides skill/reference docs to mention IconPark usage.

Test Plan

  • Unit tests pass
  • Manual local verification confirms the lark-cli <domain> <command> flow works as expected

Related Issues

  • None

Summary by CodeRabbit

  • New Features

    • Added a command-line tool for searching and resolving semantic icons with keyword queries and validation support.
  • Documentation

    • Enhanced documentation on semantic icon usage in slides, including lookup workflows and fallback options.
    • Added icon usage reference guide covering conventions, sizing, and color contrast requirements.

Review Change Stack

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented May 27, 2026

📝 Walkthrough

Walkthrough

This PR adds a new IconPark icon search and resolution tool for Lark Slides, along with comprehensive developer documentation. The implementation includes a 362-line Python CLI tool with multi-language query tokenization, relevance scoring, and three core commands (search, resolve, list-categories), validated by a 99-line test suite, and documented across process guidelines and reference materials.

Changes

IconPark Icon Search and Integration

Layer / File(s) Summary
Query tokenization and index loading foundation
skills/lark-slides/scripts/iconpark_tool.py (lines 1–158)
Module constants define the index path, default search limit, and curated keyword-to-iconType boosts. Text normalization handles whitespace and token cleanup; tokenization splits on punctuation and Chinese delimiters, generates phrase substrings, and expands synonyms. Index loading validates the JSON structure and confirms an icons array is present.
Icon search and resolution logic
skills/lark-slides/scripts/iconpark_tool.py (lines 160–299)
Relevance scoring combines exact-match boosting for iconType and name, field-token matches (tags, category, iconType), curated keyword boosts, and substring-based relevance. Search orchestration ranks candidates by score, applies category filtering, and respects limit constraints. Icon resolution matches normalized name/iconType/category SVG paths with ambiguity detection. Category listing counts icons per category.
CLI interface and execution
skills/lark-slides/scripts/iconpark_tool.py (lines 301–362)
Argument parser maps command and --key value options to structured dispatch. Usage text documents supported commands. JSON serialization outputs pretty-printed results. Index is loaded once and passed to handlers. Unknown commands are reported. Exception handling converts IconParkToolError to stderr and non-zero exit.
Comprehensive test suite
skills/lark-slides/scripts/iconpark_tool_test.py (lines 1–99)
Index loading validated in setUpClass. Search tests verify Chinese/English query support, category filtering, template and icon-type resolution, default candidate limits, term-boundary word-expansion rules, boosting of common slide terms, and error handling for missing query and invalid limit type. Resolve tests confirm both shorthand names and full icon-type paths are accepted; unknown names raise errors. Category listing returns non-empty counts.
Process documentation and guidelines
skills/lark-slides/SKILL.md, skills/lark-slides/references/iconpark.md, skills/lark-slides/references/lark-slides-replace-slide.md, skills/lark-slides/references/xml-schema-quick-ref.md
SKILL.md adds Quick Reference action "use semantic icons" and CRITICAL constraints requiring search/resolve for iconType lookup; references are updated to include iconpark.md and the tool. New iconpark.md guide explains search/resolve/list-categories workflow, shows XML examples with fill colors, lists usage rules (search-first, size conventions, color contrast, fallback to XML-native shapes), and maps common semantics to iconType. Existing schema docs are updated to direct developers to the tool and iconpark.md.

Sequence Diagram(s)

sequenceDiagram
    participant Developer
    participant CLI as iconpark_tool.py
    participant Loader as load_index()
    participant Tokenizer as tokenize_query()
    participant Scorer as score_icon()
    participant Index as Index JSON
    
    Developer->>CLI: search --query "arrow"
    CLI->>Loader: load_index()
    Loader->>Index: read icons.json
    Index-->>Loader: icon entries
    Loader-->>CLI: index_data
    CLI->>Tokenizer: tokenize_query("arrow")
    Tokenizer-->>CLI: tokens: ["arrow"]
    CLI->>Scorer: rank candidates by score(token)
    loop For each icon in index
        Scorer->>Scorer: exact match, field match, substring, boost
    end
    Scorer-->>CLI: ranked results
    CLI-->>Developer: JSON results [{"iconType": "...", ...}]
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Suggested labels

size/L

Suggested reviewers

  • fangshuyu-768

Poem

🐰 Hops through icons with glee,
A search tool for Lark Slides so free,
Chinese queries, boosts aligned,
Semantic icons, perfectly designed,
No more guessing, just run the CLI!

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title accurately describes the main change: adding IconPark lookup functionality for lark slides, which is the core objective of this PR.
Description check ✅ Passed The description covers all required template sections with appropriate content: summary explains motivation, changes lists the main additions, and test plan includes the standard verification steps.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/slide_icon_park

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.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@github-actions github-actions Bot added the size/XL Architecture-level or global-impact change label May 27, 2026
@codecov
Copy link
Copy Markdown

codecov Bot commented May 27, 2026

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 68.22%. Comparing base (367cfc9) to head (9a507b2).
⚠️ Report is 1 commits behind head on main.

Additional details and impacted files
@@            Coverage Diff             @@
##             main    #1123      +/-   ##
==========================================
+ Coverage   68.10%   68.22%   +0.11%     
==========================================
  Files         613      617       +4     
  Lines       56396    57192     +796     
==========================================
+ Hits        38409    39017     +608     
- Misses      14809    14945     +136     
- Partials     3178     3230      +52     

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@github-actions
Copy link
Copy Markdown

🚀 PR Preview Install Guide

🧰 CLI update

npm i -g https://pkg.pr.new/larksuite/cli/@larksuite/cli@9a507b26cef83cdbf5fc65d52c3a7944ba111881

🧩 Skill update

npx skills add larksuite/cli#feat/slide_icon_park -y -g

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick comments (2)
skills/lark-slides/scripts/iconpark_tool.py (2)

50-51: ⚡ Quick win

Add NoReturn type annotation for proper type checking.

The fail() function always raises but lacks a return type annotation. Type checkers will infer -> None, causing spurious "missing return" warnings in callers like parse_limit() and load_index().

Proposed fix
+from typing import Any, NoReturn
-from typing import Any


-def fail(message: str) -> None:
+def fail(message: str) -> NoReturn:
     raise IconParkToolError(message)
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@skills/lark-slides/scripts/iconpark_tool.py` around lines 50 - 51, The fail()
helper currently lacks a NoReturn annotation which causes type-checkers to infer
-> None and produce "missing return" warnings in callers like parse_limit() and
load_index(); update the fail function signature to def fail(message: str) ->
NoReturn: and add the required import from typing (NoReturn), leaving the
implementation raise IconParkToolError(message) unchanged so callers are
correctly treated as unreachable after calling fail().

214-220: 💤 Low value

Consider precomputing tag tokens to avoid repeated work.

field_tokens(tag) is called inside nested loops, recomputing the same token set for each query token. For a query with 10 tokens and an icon with 5 tags, this results in 50 calls instead of 5.

Proposed optimization
     name_tokens = field_tokens(name)
     category_tokens = field_tokens(category)
     tag_tokens = field_tokens(*tags)
     icon_type_tokens = field_tokens(icon_type)
+    tag_token_sets = [field_tokens(tag) for tag in tags]
     search_text = icon_search_text(entry)
     ...
-        for tag in tags:
+        for i, tag in enumerate(tags):
             if token == tag:
                 score += 60
-            elif token in field_tokens(tag):
+            elif token in tag_token_sets[i]:
                 score += 45
             elif allows_substring_match(token) and token in tag:
                 score += 20
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@skills/lark-slides/scripts/iconpark_tool.py` around lines 214 - 220, The
nested scoring loop calls field_tokens(tag) repeatedly for each query token; to
fix, compute the token set for each tag once before iterating tokens: inside the
outer loop over tags (the block using variables tag and score and calling
field_tokens and allows_substring_match), call field_tokens(tag) a single time
(e.g., tag_token_set) and reuse it for equality/in-set checks, and use the
original tag string only for substring checks (allows_substring_match(token) and
token in tag); this eliminates repeated field_tokens calls and preserves the
existing scoring logic.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Nitpick comments:
In `@skills/lark-slides/scripts/iconpark_tool.py`:
- Around line 50-51: The fail() helper currently lacks a NoReturn annotation
which causes type-checkers to infer -> None and produce "missing return"
warnings in callers like parse_limit() and load_index(); update the fail
function signature to def fail(message: str) -> NoReturn: and add the required
import from typing (NoReturn), leaving the implementation raise
IconParkToolError(message) unchanged so callers are correctly treated as
unreachable after calling fail().
- Around line 214-220: The nested scoring loop calls field_tokens(tag)
repeatedly for each query token; to fix, compute the token set for each tag once
before iterating tokens: inside the outer loop over tags (the block using
variables tag and score and calling field_tokens and allows_substring_match),
call field_tokens(tag) a single time (e.g., tag_token_set) and reuse it for
equality/in-set checks, and use the original tag string only for substring
checks (allows_substring_match(token) and token in tag); this eliminates
repeated field_tokens calls and preserves the existing scoring logic.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: b7b48cca-bbfa-4d26-99de-3a5927d18a0f

📥 Commits

Reviewing files that changed from the base of the PR and between 9e2be14 and 9a507b2.

📒 Files selected for processing (7)
  • skills/lark-slides/SKILL.md
  • skills/lark-slides/references/iconpark-index.json
  • skills/lark-slides/references/iconpark.md
  • skills/lark-slides/references/lark-slides-replace-slide.md
  • skills/lark-slides/references/xml-schema-quick-ref.md
  • skills/lark-slides/scripts/iconpark_tool.py
  • skills/lark-slides/scripts/iconpark_tool_test.py

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size/XL Architecture-level or global-impact change

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant