Skip to content

fix(db custom color importer) optimizing and fixing#498

Open
leape wants to merge 7 commits intomainfrom
fix(db-custom-color-importer)--optimizing-naming
Open

fix(db custom color importer) optimizing and fixing#498
leape wants to merge 7 commits intomainfrom
fix(db-custom-color-importer)--optimizing-naming

Conversation

@leape
Copy link
Contributor

@leape leape commented Jan 29, 2026

Proposed changes

Initial setup DB Icon Studio

Types of changes

  • Bugfix (non-breaking change that fixes an issue)
  • New feature (non-breaking change which adds functionality)
  • Refactoring (improvements to existing components or architectural decisions)
  • Breaking change (fix or feature that would cause existing functionality to not work as expected)
  • Documentation Update (if none of the other choices apply)

Further comments

leape added 2 commits January 29, 2026 17:22
…lection reuse

- Add checkExistingPrefix function to detect existing variable collections with different prefixes
- Implement prefix conflict warning system that alerts users when importing with mismatched prefixes
- Update getOrCreateCollections to reuse existing collections instead of creating duplicates
- Modify setupDisplayModes to properly configure Light/Dark modes for Display collection
- Change Theme collection to use single "Value" mode instead of Light/Dark modes
- Add logic to remove extra modes from Theme collection to maintain single-mode structure
- Prevent duplicate prefix naming in color family mode names
- Update ImportMessage type to include optional customPrefix field
- Enhance variable path generation to avoid prefix duplication in family names
- Improve collection detection to find existing collections by suffix matching rather than exact name matching
…riable reuse logic

- Update collection deletion to support prefixed collection names using endsWith matching
- Add error handling with console warnings for collection and variable removal operations
- Improve cleanup logic to handle Theme, Mode, and Colors collections with proper error catching
- Refactor adaptive color variable creation to reuse existing variables across prefixes
- Add pattern-based search for existing adaptive variables to prevent duplication
- Implement conditional value setting for db-adaptive mode to avoid overwriting existing values
- Add scopes configuration for display mode variables based on variable name patterns
- Enhance code formatting and add clarifying comments for collection handling logic
@leape leape self-assigned this Jan 29, 2026
@leape leape added the javascript Pull requests that update Javascript code label Jan 29, 2026
- Add `isNewVariable` flag to track when adaptive color variables are newly created
- Update db-adaptive mode assignment to apply to both new variables and existing variables without values
- Extract `hasDbAdaptiveValue` check into a separate variable for improved readability
- Refactor conditional logic to use `isNewVariable || !hasDbAdaptiveValue` for more comprehensive value assignment
- Ensure adaptive variables receive proper mode values regardless of creation state
@leape leape changed the title Fix(db custom color importer) optimizing naming, fixing some import bugs fix(db custom color importer) optimizing naming, fixing some import bugs Feb 3, 2026
leape added 2 commits February 3, 2026 16:07
…ation

- Add comprehensive documentation for the new prefix confirmation step in README
- Document automatic prefix detection and manual adjustment capabilities
- Include examples of prefix naming conventions (dibe, custom)
- Explain importance of prefix consistency with Theme Builder exports
- Remove unused `detectedPrefix` state variable from App component
- Add `overflow-visible` class to main container for proper dialog rendering
- Add horizontal padding and negative margin to prefix dialog stack for better spacing
- Renumber subsequent sections in README (3→4, 4→5, 5→6) to accommodate new section
- Improve UI layout and accessibility for prefix confirmation workflow
@leape leape changed the title fix(db custom color importer) optimizing naming, fixing some import bugs fix(db custom color importer) optimizing and fixing Feb 4, 2026
…unit tests after Amazon Q review

- Add VariableScope type definition for type-safe Figma variable scopes
- Create SCOPES constants (BACKGROUND, FOREGROUND, NONE) to eliminate magic strings
- Add getScopesForMapping() helper function to centralize scope logic and remove duplication
- Create MODE_NAMES constants for Light Mode, Dark Mode, and db-adaptive mode names
- Add MESSAGES constants for success and error notifications
- Implement ensurePrefixedFamily() helper to standardize prefix handling across codebase
- Create standardized logging system (utils/logger.ts) with debug, info, warn, error, and success levels
- Add context tags and visual sections to logging for improved debugging
- Implement unit tests with Vitest for color utilities, logger, and configuration
- Add vitest.config.ts and test documentation (tests/README.md)
- Create IMPROVEMENTS.md documenting all type safety and logging enhancements
- Update README.md and package.json with testing instructions and dependencies
- Refactor existing code to use new constants and logging system throughout codebase
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

This PR enhances the DB Custom Color Importer plugin by adding prefix detection and confirmation UI, refactoring code for better type safety and maintainability, adding comprehensive unit tests, and implementing performance optimizations through parallel operations.

Changes:

  • Added prefix detection and confirmation dialog in UI with automatic extraction from JSON color families and filenames
  • Refactored code with centralized configuration constants (SCOPES, MODE_NAMES, MESSAGES), improved type safety, and standardized logging system
  • Added 53 unit tests covering color utilities, configuration, and logger functionality, plus comprehensive testing documentation

Reviewed changes

Copilot reviewed 18 out of 19 changed files in this pull request and generated 9 comments.

Show a summary per file
File Description
packages/db-custom-color-importer/ui/src/App.tsx Adds prefix detection/confirmation workflow with dialog UI and state management
packages/db-custom-color-importer/plugin/utils/variables.ts Refactors variable creation with prefix support, parallel processing, and logging integration
packages/db-custom-color-importer/plugin/utils/logger.ts New standardized logging system with levels, timestamps, and context tags
packages/db-custom-color-importer/plugin/utils/logger.test.ts Comprehensive unit tests for logger functionality (24 tests)
packages/db-custom-color-importer/plugin/utils/color.test.ts Unit tests for color conversion utilities (16 tests)
packages/db-custom-color-importer/plugin/utils/collections.ts Enhances collection management with prefix support and improved mode setup
packages/db-custom-color-importer/plugin/utils/cleanup.ts Optimizes deletion with parallel operations for variables and collections
packages/db-custom-color-importer/plugin/config.ts Adds centralized constants and helper functions for scopes, modes, and messages
packages/db-custom-color-importer/plugin/config.test.ts Unit tests for configuration helpers (13 tests)
packages/db-custom-color-importer/plugin/code.ts Adds prefix checking message handler for existing collections
packages/db-custom-color-importer/plugin/types.ts Adds VariableScope type and customPrefix to ImportMessage
packages/db-custom-color-importer/plugin/vitest.config.ts Configures Vitest test framework
packages/db-custom-color-importer/plugin/package.json Adds test scripts and vitest dependency
packages/db-custom-color-importer/package.json Adds test scripts at package root level
packages/db-custom-color-importer/README.md Updates documentation with prefix confirmation workflow details
packages/db-custom-color-importer/TESTING.md New comprehensive testing guide with examples and best practices
packages/db-custom-color-importer/IMPROVEMENTS.md New detailed documentation of refactoring and optimization changes
packages/db-custom-color-importer/plugin/tests/README.md Test structure documentation for the plugin directory

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines 101 to 106
const lightModeId = displayCol.modes.find(
(m) => m.name === "Light Mode",
(m) => m.name === MODE_NAMES.LIGHT,
)!.modeId;
const darkModeId = displayCol.modes.find(
(m) => m.name === "Dark Mode",
(m) => m.name === MODE_NAMES.DARK,
)!.modeId;
Copy link

Copilot AI Feb 4, 2026

Choose a reason for hiding this comment

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

Missing null checks: The non-null assertion operators (!) are used on lines 103 and 106, but if MODE_NAMES.LIGHT or MODE_NAMES.DARK are not found in displayCol.modes, these will throw runtime errors. While the modes are created just above, it's safer to add proper null checks or error handling.

Copilot uses AI. Check for mistakes.
Comment on lines +113 to +118
prefixOriginal = matchWithMiddle[2].trim();
} else if (matchDirect && matchDirect[1]) {
// Direct match with known prefix - ignore it
prefixOriginal = "";
}

Copy link

Copilot AI Feb 4, 2026

Choose a reason for hiding this comment

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

Regex logic issue: The function returns an empty string when matchDirect succeeds, but this doesn't align with the comment on line 115. If the direct match succeeds (e.g., "DB Theme-figma"), the intent seems to be to ignore the known prefix and return empty. However, this means files like "DB Theme-figma.json" will not extract any prefix, which might not be the desired behavior. Consider clarifying the logic or documenting why direct matches should result in an empty prefix.

Suggested change
prefixOriginal = matchWithMiddle[2].trim();
} else if (matchDirect && matchDirect[1]) {
// Direct match with known prefix - ignore it
prefixOriginal = "";
}
// Example: "DB SomePrefix Theme-figma.json" -> "SomePrefix"
prefixOriginal = matchWithMiddle[2].trim();
} else if (matchDirect && matchDirect[1]) {
// Example: "DB Theme-figma.json"
// Direct match with known prefix only - intentionally do not extract a custom prefix
return "";
}
if (!prefixOriginal) {
// No prefix segment found to normalize
return "";
}

Copilot uses AI. Check for mistakes.
const nameWithoutExt = filename.replace(/\.json$/i, "");

// Known prefixes at the start that should be ignored
const knownPrefixes = ["DB", "Whitelabel", "S-Bahn", "sab", "SAB"];
Copy link

Copilot AI Feb 4, 2026

Choose a reason for hiding this comment

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

Inconsistent knownPrefixes array: The knownPrefixes array in the UI (line 95) includes "SAB" in addition to "sab", while the plugin's knownPrefixes array (variables.ts:254) only has "sab". This inconsistency could lead to different prefix extraction behavior between the UI preview and the actual plugin import. Consider synchronizing these arrays or extracting them to a shared constant.

Suggested change
const knownPrefixes = ["DB", "Whitelabel", "S-Bahn", "sab", "SAB"];
const knownPrefixes = ["DB", "Whitelabel", "S-Bahn", "sab"];

Copilot uses AI. Check for mistakes.
Comment on lines +61 to +122
const extractPrefixFromJson = (data: any): string | null => {
// Extract prefix from color family names
// Example: "dibe-br-color-01" -> "dibe"
const colors = data?.colors || {};
const colorFamilies = Object.keys(colors);

if (colorFamilies.length === 0) return null;

// Extract prefixes from all color family names
// Expected format: "prefix-something-color-number" or "prefix-color-number"
const prefixes = colorFamilies
.map((familyName) => {
// Extract the first part before the first dash
const match = familyName.match(/^([a-zA-Z0-9]+)(?:-|$)/);
return match ? match[1].toLowerCase() : null;
})
.filter((p) => p !== null);

if (prefixes.length === 0) return null;

// Check if all prefixes are the same
const firstPrefix = prefixes[0];
const allSame = prefixes.every((p) => p === firstPrefix);

return allSame ? firstPrefix : null;
};

const extractPrefixFromFilename = (filename: string): string => {
if (!filename) return "";

// Remove .json extension
const nameWithoutExt = filename.replace(/\.json$/i, "");

// Known prefixes at the start that should be ignored
const knownPrefixes = ["DB", "Whitelabel", "S-Bahn", "sab", "SAB"];

// Try to match pattern: [KnownPrefix][-\s][Something]Theme-figma
// or: [KnownPrefix][-\s]Theme-figma
const regexWithMiddle = new RegExp(
`^(${knownPrefixes.join("|")})[-\\s]+(.+?)Theme-figma`,
"i",
);
const regexDirect = new RegExp(
`^(${knownPrefixes.join("|")})[-\\s]+Theme-figma`,
"i",
);

const matchWithMiddle = nameWithoutExt.match(regexWithMiddle);
const matchDirect = nameWithoutExt.match(regexDirect);

let prefixOriginal = "";
if (matchWithMiddle && matchWithMiddle[2]) {
prefixOriginal = matchWithMiddle[2].trim();
} else if (matchDirect && matchDirect[1]) {
// Direct match with known prefix - ignore it
prefixOriginal = "";
}

// Remove special characters and convert to lowercase
const prefix = prefixOriginal.replace(/[^a-zA-Z0-9]/g, "").toLowerCase();
return prefix;
};
Copy link

Copilot AI Feb 4, 2026

Choose a reason for hiding this comment

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

Missing test coverage: The extractPrefixFromJson and extractPrefixFromFilename functions contain complex logic with multiple edge cases (e.g., different filename patterns, prefix consistency checks), but there are no test files for the UI components. Given that the plugin directory has comprehensive test coverage, consider adding tests for these critical prefix extraction functions to ensure they work correctly across different scenarios.

Copilot uses AI. Check for mistakes.
Comment on lines +361 to +365
**Performance Improvements:**

- **Variable deletion:** ~10x faster for collections with many variables
- **Adaptive variable creation:** ~3-5x faster (depends on number of mappings)
- **Overall import time:** Reduced by 40-60% for large color sets
Copy link

Copilot AI Feb 4, 2026

Choose a reason for hiding this comment

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

Unverified performance claims: The IMPROVEMENTS.md document claims specific performance improvements (10x faster variable deletion, 3-5x faster adaptive variable creation, 40-60% faster overall), but these metrics are not backed by benchmarks or measurements in the codebase. Consider adding performance benchmarks to verify these claims or qualifying them as estimated improvements.

Copilot uses AI. Check for mistakes.
Comment on lines +279 to +281
file. Your new colors with prefix "{prefixInput}" will be added to
the existing collections. This means both color families will be
available in the same collections.
Copy link

Copilot AI Feb 4, 2026

Choose a reason for hiding this comment

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

Misleading warning message: The warning message states that "both color families will be available in the same collections," but this may not accurately describe what happens. Based on the code logic in getOrCreateCollections (collections.ts), if collections already exist, they are reused regardless of prefix. The warning should clarify whether existing variables will be updated/merged or if this could lead to naming conflicts.

Suggested change
file. Your new colors with prefix "{prefixInput}" will be added to
the existing collections. This means both color families will be
available in the same collections.
file and will be reused. Your new colors with prefix "{prefixInput}"
will be added to these existing collections. This means color
variables from both prefixes will coexist in the same collections
and may update existing variables or lead to naming conflicts.

Copilot uses AI. Check for mistakes.
Comment on lines +145 to 169
let createdCount = 0;
let linkedCount = 0;

// Process all mappings in parallel
const processingPromises = MAPPINGS.map(async (m) => {
// First, try to find existing adaptive variable (with any prefix)
const adaptivePattern = `-adaptive/${m.name}`;
let v: Variable | undefined;
let isNewVariable = false;

// Search for existing variable ending with "-adaptive/..."
for (const [varName, variable] of varMap.entries()) {
if (varName.endsWith(adaptivePattern)) {
v = variable;
break;
}
}

// If not found, create new one with current prefix
if (!v) {
const colorVarPath = `${prefix}-adaptive/${m.name}`;
v = figma.variables.createVariable(colorVarPath, colorCol, "COLOR");
isNewVariable = true;
createdCount++;
}
Copy link

Copilot AI Feb 4, 2026

Choose a reason for hiding this comment

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

Race condition: The createdCount variable is being modified by multiple async operations running in parallel. Since JavaScript doesn't have atomic increments, this can lead to incorrect counts when multiple promises update createdCount simultaneously. The same issue exists for linkedCount on line 187. Consider using a different approach such as filtering the results after Promise.all or using a thread-safe counter pattern.

Copilot uses AI. Check for mistakes.
if (existingCollections.length > 0) {
// Extract prefix from first existing collection
const firstCollection = existingCollections[0];
const existingPrefix = firstCollection.name.split("-")[0].toLowerCase();
Copy link

Copilot AI Feb 4, 2026

Choose a reason for hiding this comment

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

Potential bug with prefix extraction: This regex will fail to extract a prefix from collection names that contain multiple dashes before the suffix. For example, a collection named "my-custom-Theme" would incorrectly extract "my" as the prefix when it should be "my-custom". Consider splitting from the end using the suffix instead of splitting from the beginning, or using a more robust pattern like c.name.slice(0, c.name.lastIndexOf('-')).

Suggested change
const existingPrefix = firstCollection.name.split("-")[0].toLowerCase();
const name = firstCollection.name;
const lastDashIndex = name.lastIndexOf("-");
const existingPrefix = (lastDashIndex !== -1 ? name.slice(0, lastDashIndex) : name).toLowerCase();

Copilot uses AI. Check for mistakes.
Comment on lines 137 to 139
const dbAdaptiveModeId = colorCol.modes.find(
(m) => m.name === "db-adaptive",
(m) => m.name === MODE_NAMES.DB_ADAPTIVE,
)!.modeId;
Copy link

Copilot AI Feb 4, 2026

Choose a reason for hiding this comment

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

Missing null check: The non-null assertion operator (!) is used here, but if MODE_NAMES.DB_ADAPTIVE is not found in colorCol.modes, this will throw a runtime error. While this scenario may be unlikely due to the mode being renamed just above, it's safer to add error handling or a proper check before accessing modeId.

Copilot uses AI. Check for mistakes.
@leape leape marked this pull request as draft February 10, 2026 13:28
…selection, and smart variable grouping

- Add color precision handling with full RGB precision and alpha rounding to prevent hex value distortion (e.g., #001110 → #00120F)
- Implement flexible prefix selection dialog showing all detected prefixes from variable names and filenames
- Add automatic variable grouping with nested slash-separated paths (e.g., db-poi-db-services → db-poi/db-services)
- Implement smart variable reuse by detecting existing variables and updating modes instead of creating duplicates
- Separate collection prefix from variable prefix for cleaner organization
- Add processing screen with loading animation to prevent accidental multiple imports
- Add comprehensive CHANGELOG.md documenting all changes and technical details
- Update README.md with improved prefix handling and grouping documentation
- Add color-precision.test.ts with test cases using real RITheme JSON values
- Enhance color.test.ts with additional precision test cases
- Add RITheme-figma-custom-colors.json sample file for testing and reference
- Update types.ts, collections.ts, color.ts, variables.ts, and App.tsx to support new features
- Improve user guidance with clearer explanation of variable grouping functionality
@leape leape marked this pull request as ready for review February 11, 2026 13:17
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

javascript Pull requests that update Javascript code

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants