mirror of
https://github.com/lucide-icons/lucide.git
synced 2026-11-14 13:58:21 +00:00
feat(scripts): follow metadata instructions for described use-cases
Load the Use Cases section of .github/instructions/metadata.instructions.md into the --describe prompt so generated use-cases match the repository style, and make useCase an array of phrases per usage group. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Q2D9GYbnSV56MAVVhHPRhH
This commit is contained in:
@@ -24,7 +24,7 @@ pnpm icon-usage --icons-file exports.txt --describe --max-contexts 30
|
||||
|
||||
`--context` extracts how each icon is used in every validated file: what kind of usage it is (a JSX/template element, a prop such as `icon={Trash2}`, a config object such as `{ title: 'Settings', icon: Settings }`, or a `data-lucide` attribute), the parent elements (for example `DropdownMenuItem` or `Button`), the enclosing component, label text (`aria-label`, `title`, visible text, i18n keys like `t('actions.delete')`), event handlers, links, and a short code snippet. Each usage gets a heuristic description such as `Trash2 in <DropdownMenuItem> labelled "Delete Project" within NavProjects`. Each icon gets a summary of the most common labels, parents and handlers, plus example links to the exact lines on GitHub.
|
||||
|
||||
`--describe` does the same, then sends the collected contexts to an OpenAI model (`OPENAI_API_KEY` required; `--model` or `OPENAI_MODEL` selects the model, `gpt-5-mini` by default). The model groups them into several use cases per icon, each with a short lowercase `useCase` phrase in the style of the `use-cases` field in `icons/*.json`, a description of where the icon appears in the UI, its approximate share of the sample, and example links. The icon's existing `use-cases` are included in the prompt. Responses are cached in the cache directory.
|
||||
`--describe` does the same, then sends the collected contexts to an OpenAI model (`OPENAI_API_KEY` required; `--model` or `OPENAI_MODEL` selects the model, `gpt-5-mini` by default). The model groups them into 1 to 4 use cases per icon. Each has a `useCase` array of 1 to 3 phrases for the `use-cases` field in `icons/*.json`, written following the "Use Cases" section of `.github/instructions/metadata.instructions.md` (loaded into the prompt at runtime), a description of where the icon appears in the UI, its approximate share of the sample, and example links. The icon's existing `use-cases` are included in the prompt. Responses are cached in the cache directory.
|
||||
|
||||
Use `--output <file>` (or `-o`) to write the results per icon to a JSON file shaped as `{ [icon]: [...usage] }`. With `--describe`, each entry is a use case (`useCase`, `description`, `sampleShare`, `examples`). Without it, each entry is an individual usage (`description`, `repository`, `url`, `kind`, `parents`, `component`, `labels`, `handlers`, `links`). `--output` implies `--context`, and the normal terminal, `--json` or `--csv` output is still printed.
|
||||
|
||||
|
||||
@@ -1445,7 +1445,7 @@ const printUsage = (usage: Record<string, IconUsage>) => {
|
||||
console.log(' use cases:');
|
||||
for (const description of descriptions) {
|
||||
console.log(
|
||||
` - ${description.useCase} (~${formatPercent(description.sampleShare * 100)})`,
|
||||
` - ${description.useCase.join(' / ')} (~${formatPercent(description.sampleShare * 100)})`,
|
||||
);
|
||||
console.log(` ${description.description}`);
|
||||
for (const example of description.examples) console.log(` ${example}`);
|
||||
|
||||
@@ -514,7 +514,7 @@ export const summarizeContexts = (matches: ContextMatch[]): IconContextSummary =
|
||||
};
|
||||
|
||||
export type UsageDescription = {
|
||||
useCase: string;
|
||||
useCase: string[];
|
||||
description: string;
|
||||
sampleShare: number;
|
||||
examples: string[];
|
||||
@@ -531,6 +531,33 @@ type DescribeOptions = {
|
||||
writeCache: (key: string, value: UsageDescription[]) => Promise<void>;
|
||||
};
|
||||
|
||||
const METADATA_INSTRUCTIONS = new URL(
|
||||
'../.github/instructions/metadata.instructions.md',
|
||||
import.meta.url,
|
||||
);
|
||||
|
||||
const FALLBACK_USE_CASE_GUIDELINES = `Write each use-case as a short phrase of roughly 4-12 words starting with a present participle verb (e.g. "Indicating a low battery charge level"), from the interface's perspective, naming the concrete context where useful. No trailing period, no first person, no marketing language, and never just the icon's name.`;
|
||||
|
||||
/**
|
||||
* Returns the "Use Cases" section of the repository's metadata instructions
|
||||
* (including its examples), so generated use-cases follow the same style.
|
||||
*/
|
||||
const loadUseCaseGuidelines = async () => {
|
||||
try {
|
||||
const fs = await import('node:fs/promises');
|
||||
const instructions = await fs.readFile(METADATA_INSTRUCTIONS, 'utf8');
|
||||
const start = instructions.indexOf('## Use Cases');
|
||||
if (start === -1) return FALLBACK_USE_CASE_GUIDELINES;
|
||||
const sections = instructions.slice(start).split(/\n(?=## )/);
|
||||
return sections
|
||||
.filter((section, index) => index === 0 || section.startsWith('## Examples'))
|
||||
.join('\n')
|
||||
.trim();
|
||||
} catch {
|
||||
return FALLBACK_USE_CASE_GUIDELINES;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Asks an OpenAI model to cluster the collected usage contexts into distinct,
|
||||
* real-world use cases for the icon. Responses are cached by prompt hash.
|
||||
@@ -560,15 +587,24 @@ export const describeIconUsage = async ({
|
||||
|
||||
const input = `You are maintaining the metadata for the Lucide icon library. Below are real usages of the \`${icon}\` icon found in public GitHub repositories, extracted from source code.
|
||||
|
||||
Group these usages into distinct use cases and describe each one.
|
||||
Group these usages by what the icon means in them, and describe each group.
|
||||
|
||||
Guidelines:
|
||||
- useCase: short lowercase phrase describing the concrete situation the icon represents (e.g. "deleting an item from a list"). No trailing punctuation. Match the style of the existing use-cases if any.
|
||||
Fields for each group:
|
||||
- useCase: an array of 1-3 use-case phrases for this group, written exactly as the use-case guidelines below describe. Add more than one phrase only when the group covers genuinely distinct uses; never rephrase the same idea. Don't repeat a phrase across groups.
|
||||
- description: one or two sentences describing how and where the icon appears in the UI (e.g. inside a ghost button in a table row, next to a "Delete" label).
|
||||
- sampleShare: the approximate fraction (0-1) of the samples that belong to this use case.
|
||||
- examples: ids of up to 3 samples that best illustrate the use case.
|
||||
- Return between 1 and 8 use cases, most common first. Ignore samples without enough context to judge.
|
||||
- Base everything on the samples; do not invent use cases that are not supported by them.
|
||||
- sampleShare: the approximate fraction (0-1) of the samples that belong to this group.
|
||||
- examples: ids of up to 3 samples that best illustrate the group.
|
||||
|
||||
Rules:
|
||||
- Return between 1 and 4 groups, most common first. Ignore samples without enough context to judge.
|
||||
- The samples are your source material: extract the function the icon serves in the interface and discard implementation details such as component names, class names or file paths.
|
||||
- Base everything on the samples; never invent use cases that are not supported by them.
|
||||
- Match the style of the existing use-cases, and avoid duplicating them.
|
||||
|
||||
Use-case guidelines (from .github/instructions/metadata.instructions.md):
|
||||
<guidelines>
|
||||
${await loadUseCaseGuidelines()}
|
||||
</guidelines>
|
||||
|
||||
Existing use-cases for "${icon}": ${JSON.stringify(existingUseCases)}
|
||||
|
||||
@@ -591,7 +627,7 @@ ${JSON.stringify(samples, null, 1)}`;
|
||||
const schema = z.object({
|
||||
useCases: z.array(
|
||||
z.object({
|
||||
useCase: z.string(),
|
||||
useCase: z.array(z.string()),
|
||||
description: z.string(),
|
||||
sampleShare: z.number(),
|
||||
examples: z.array(z.number()),
|
||||
|
||||
Reference in New Issue
Block a user