@public-ui/kolibri-cli 3.0.4-rc.1 → 3.0.4-rc.2
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.
- package/README.md +47 -0
- package/dist/migrate/runner/tasks/common/ScssAddSelectorTask.js +203 -0
- package/dist/migrate/runner/tasks/common/ScssRemoveSelectorTask.js +275 -0
- package/dist/migrate/runner/tasks/common/ScssRenameBlockTask.js +43 -0
- package/dist/migrate/runner/tasks/common/ScssRenameElementTask.js +48 -0
- package/dist/migrate/runner/tasks/common/ScssRenameModifierTask.js +48 -0
- package/dist/migrate/runner/tasks/common/ScssUpdateTokenTask.js +51 -0
- package/dist/migrate/runner/tasks/v3/index.js +2 -0
- package/dist/migrate/runner/tasks/v3/toaster.js +34 -0
- package/dist/types.js +3 -2
- package/package.json +11 -11
package/README.md
CHANGED
|
@@ -91,6 +91,53 @@ Actually the following migration tasks from version 1 to version 2 are available
|
|
|
91
91
|
- Detection of `_iconOnly` in TSX is not stable ([#5404](https://github.com/public-ui/kolibri/issues/5404)) ⏰
|
|
92
92
|
- Handle the remove `@public-ui/core` package ([#???](https://github.com/public-ui/kolibri/issues/????)) ⏰
|
|
93
93
|
|
|
94
|
+
#### Theme Migration
|
|
95
|
+
|
|
96
|
+
The CLI also supports migrating KoliBri themes alongside component updates to ensure theme packages remain synchronized with breaking changes in the component library.
|
|
97
|
+
|
|
98
|
+
##### Goal
|
|
99
|
+
|
|
100
|
+
Synchronies breaking changes in components with the styling of each theme package so that upgrades require minimal manual work.
|
|
101
|
+
|
|
102
|
+
##### Requirements
|
|
103
|
+
|
|
104
|
+
- Components and themes follow the BEM naming convention via `typed-bem`.
|
|
105
|
+
- Each theme lives under `packages/themes` and keeps its SCSS sources in `src/`.
|
|
106
|
+
- The CLI migration tool can read and modify `.scss` files.
|
|
107
|
+
|
|
108
|
+
##### Concept
|
|
109
|
+
|
|
110
|
+
1. **Central BEM schemas**
|
|
111
|
+
- Every component exports its BEM schema. These schemas are used by the CLI to generate SCSS files and by themes to reference selectors.
|
|
112
|
+
- When a selector changes, the same schema information allows the migration to update all theme packages consistently.
|
|
113
|
+
|
|
114
|
+
2. **SCSS migration tasks**
|
|
115
|
+
The CLI runner is extended with task types operating on SCSS. They behave like the existing property tasks and are idempotent.
|
|
116
|
+
- `RenameBlockTask` – rename a block selector everywhere in a theme.
|
|
117
|
+
- `RenameElementTask` – rename an element within a block.
|
|
118
|
+
- `RenameModifierTask` – rename or replace a modifier.
|
|
119
|
+
- `AddSelectorTask` and `RemoveSelectorTask` – insert or remove entire rule sets.
|
|
120
|
+
- `UpdateTokenTask` – adjust variable names or values when tokens change.
|
|
121
|
+
- `MoveRulesTask` – move declarations from one selector to another if the DOM structure changes.
|
|
122
|
+
|
|
123
|
+
Tasks scan the SCSS with regular expressions or an AST parser. If a pattern is missing the task logs a warning instead of failing.
|
|
124
|
+
|
|
125
|
+
3. **Safe execution**
|
|
126
|
+
- Migrations abort when uncommitted changes are detected unless `--ignore-uncommitted-changes` is specified.
|
|
127
|
+
- Each task logs the files it touched. After completion Prettier can format them automatically.
|
|
128
|
+
- Because tasks are idempotent, rerunning the migration produces no new changes. To undo a run, reset the Git state.
|
|
129
|
+
|
|
130
|
+
##### Theme Migration Workflow Example
|
|
131
|
+
|
|
132
|
+
```bash
|
|
133
|
+
pnpm i -g @public-ui/kolibri-cli@2 # install the CLI matching the next version
|
|
134
|
+
kolibri migrate path/to/project # run all tasks for the upgrade
|
|
135
|
+
pnpm format # format changed files
|
|
136
|
+
git diff # review results and commit
|
|
137
|
+
```
|
|
138
|
+
|
|
139
|
+
Using these tasks, theme packages remain aligned with component updates. Future breaking changes can be scripted and applied via the CLI so that projects can upgrade in a controlled and reproducible way.
|
|
140
|
+
|
|
94
141
|
#### How does it work?
|
|
95
142
|
|
|
96
143
|
1. The migration command will check your project for clear `git history` and the `installed version` of `KoliBri`. Now it loads all available migration tasks.
|
|
@@ -0,0 +1,203 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.ScssAddSelectorTask = void 0;
|
|
7
|
+
const fs_1 = __importDefault(require("fs"));
|
|
8
|
+
const types_1 = require("../../../../types");
|
|
9
|
+
const reuse_1 = require("../../../shares/reuse");
|
|
10
|
+
const abstract_task_1 = require("../../abstract-task");
|
|
11
|
+
/**
|
|
12
|
+
* Simple, fast hash function for string identifier generation.
|
|
13
|
+
* Based on djb2 algorithm - much faster than cryptographic hashes for non-security purposes.
|
|
14
|
+
* @param {string} str String to hash
|
|
15
|
+
* @returns {string} Hexadecimal hash string
|
|
16
|
+
*/
|
|
17
|
+
function simpleHash(str) {
|
|
18
|
+
let hash = 5381;
|
|
19
|
+
for (let i = 0; i < str.length; i++) {
|
|
20
|
+
hash = (hash << 5) + hash + str.charCodeAt(i);
|
|
21
|
+
}
|
|
22
|
+
return (hash >>> 0).toString(16).substring(0, 8);
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* Escapes special characters for use in a regular expression.
|
|
26
|
+
* @param {string} str String to escape
|
|
27
|
+
* @returns {string} Escaped string
|
|
28
|
+
*/
|
|
29
|
+
function escapeRegExp(str) {
|
|
30
|
+
return str.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* Analyzes the content to determine formatting preferences
|
|
34
|
+
* @param {string} content The CSS content to analyze
|
|
35
|
+
* @returns {object} Formatting preferences object
|
|
36
|
+
*/
|
|
37
|
+
function analyzeFormatting(content) {
|
|
38
|
+
const lines = content.split('\n');
|
|
39
|
+
// Detect indentation
|
|
40
|
+
let tabCount = 0;
|
|
41
|
+
let spaceCount = 0;
|
|
42
|
+
const indentSizes = [];
|
|
43
|
+
for (const line of lines) {
|
|
44
|
+
if (line.trim() === '')
|
|
45
|
+
continue;
|
|
46
|
+
const leadingWhitespace = line.match(/^(\s*)/)?.[1] || '';
|
|
47
|
+
if (leadingWhitespace.includes('\t')) {
|
|
48
|
+
tabCount++;
|
|
49
|
+
}
|
|
50
|
+
else if (leadingWhitespace.length > 0) {
|
|
51
|
+
spaceCount++;
|
|
52
|
+
indentSizes.push(leadingWhitespace.length);
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
const usesTabs = tabCount > spaceCount;
|
|
56
|
+
const averageSpaceIndent = indentSizes.length > 0 ? Math.round(indentSizes.reduce((sum, size) => sum + size, 0) / indentSizes.length) : 2;
|
|
57
|
+
// Detect brace formatting patterns
|
|
58
|
+
let newlineBeforeOpenBrace = false;
|
|
59
|
+
let newlineAfterOpenBrace = true; // Default to true for readability
|
|
60
|
+
let newlineBeforeCloseBrace = true; // Default to true for readability
|
|
61
|
+
let newlineAfterCloseBrace = true; // Default to true for separation
|
|
62
|
+
// Look for existing CSS rules to determine formatting style
|
|
63
|
+
const cssRulePattern = /[^{]*\{[^}]*\}/g;
|
|
64
|
+
const matches = content.match(cssRulePattern);
|
|
65
|
+
if (matches && matches.length > 0) {
|
|
66
|
+
let beforeOpenCount = 0;
|
|
67
|
+
let afterOpenCount = 0;
|
|
68
|
+
let beforeCloseCount = 0;
|
|
69
|
+
let afterCloseCount = 0;
|
|
70
|
+
for (const match of matches) {
|
|
71
|
+
// Check for newline before opening brace
|
|
72
|
+
if (/\n\s*\{/.test(match))
|
|
73
|
+
beforeOpenCount++;
|
|
74
|
+
// Check for newline after opening brace
|
|
75
|
+
if (/\{\s*\n/.test(match))
|
|
76
|
+
afterOpenCount++;
|
|
77
|
+
// Check for newline before closing brace
|
|
78
|
+
if (/\n\s*\}/.test(match))
|
|
79
|
+
beforeCloseCount++;
|
|
80
|
+
// Check for newline after closing brace (look at the context)
|
|
81
|
+
if (/\}\s*\n/.test(match))
|
|
82
|
+
afterCloseCount++;
|
|
83
|
+
}
|
|
84
|
+
// Use majority rule for formatting decisions
|
|
85
|
+
const totalMatches = matches.length;
|
|
86
|
+
newlineBeforeOpenBrace = beforeOpenCount > totalMatches / 2;
|
|
87
|
+
newlineAfterOpenBrace = afterOpenCount > totalMatches / 2;
|
|
88
|
+
newlineBeforeCloseBrace = beforeCloseCount > totalMatches / 2;
|
|
89
|
+
newlineAfterCloseBrace = afterCloseCount > totalMatches / 2;
|
|
90
|
+
}
|
|
91
|
+
return {
|
|
92
|
+
indentChar: usesTabs ? '\t' : ' ',
|
|
93
|
+
indentSize: usesTabs ? 1 : averageSpaceIndent,
|
|
94
|
+
newlineBeforeOpenBrace,
|
|
95
|
+
newlineAfterOpenBrace,
|
|
96
|
+
newlineBeforeCloseBrace,
|
|
97
|
+
newlineAfterCloseBrace,
|
|
98
|
+
};
|
|
99
|
+
}
|
|
100
|
+
/**
|
|
101
|
+
* Formats a CSS rule according to the detected formatting style
|
|
102
|
+
* @param {string} selector The CSS selector
|
|
103
|
+
* @param {string} rules The CSS rules
|
|
104
|
+
* @param {object} formatting The formatting preferences
|
|
105
|
+
* @param {string} formatting.indentChar The character used for indentation (tab or space)
|
|
106
|
+
* @param {number} formatting.indentSize The number of indent characters per level
|
|
107
|
+
* @param {boolean} formatting.newlineBeforeOpenBrace Whether to add newline before opening brace
|
|
108
|
+
* @param {boolean} formatting.newlineAfterOpenBrace Whether to add newline after opening brace
|
|
109
|
+
* @param {boolean} formatting.newlineBeforeCloseBrace Whether to add newline before closing brace
|
|
110
|
+
* @param {boolean} formatting.newlineAfterCloseBrace Whether to add newline after closing brace
|
|
111
|
+
* @returns {string} The formatted CSS rule
|
|
112
|
+
*/
|
|
113
|
+
function formatCssRule(selector, rules, formatting) {
|
|
114
|
+
const indent = formatting.indentChar.repeat(formatting.indentSize);
|
|
115
|
+
// Ensure rules are properly indented and trimmed
|
|
116
|
+
const formattedRules = rules
|
|
117
|
+
.split('\n')
|
|
118
|
+
.map((line) => line.trim())
|
|
119
|
+
.filter((line) => line.length > 0)
|
|
120
|
+
.map((line) => indent + line)
|
|
121
|
+
.join('\n');
|
|
122
|
+
let result = '';
|
|
123
|
+
// Add selector
|
|
124
|
+
result += selector;
|
|
125
|
+
// Add space or newline before opening brace
|
|
126
|
+
if (formatting.newlineBeforeOpenBrace) {
|
|
127
|
+
result += '\n';
|
|
128
|
+
}
|
|
129
|
+
else {
|
|
130
|
+
result += ' ';
|
|
131
|
+
}
|
|
132
|
+
// Add opening brace
|
|
133
|
+
result += '{';
|
|
134
|
+
// Add newline after opening brace if needed
|
|
135
|
+
if (formatting.newlineAfterOpenBrace) {
|
|
136
|
+
result += '\n';
|
|
137
|
+
}
|
|
138
|
+
// Add rules
|
|
139
|
+
if (formattedRules.trim()) {
|
|
140
|
+
if (!formatting.newlineAfterOpenBrace) {
|
|
141
|
+
result += ' ';
|
|
142
|
+
}
|
|
143
|
+
result += formattedRules;
|
|
144
|
+
if (!formatting.newlineBeforeCloseBrace) {
|
|
145
|
+
result += ' ';
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
// Add newline before closing brace if needed
|
|
149
|
+
if (formatting.newlineBeforeCloseBrace && formattedRules.trim()) {
|
|
150
|
+
result += '\n';
|
|
151
|
+
}
|
|
152
|
+
// Add closing brace
|
|
153
|
+
result += '}';
|
|
154
|
+
// Add newline after closing brace if needed
|
|
155
|
+
if (formatting.newlineAfterCloseBrace) {
|
|
156
|
+
result += '\n';
|
|
157
|
+
}
|
|
158
|
+
return result;
|
|
159
|
+
}
|
|
160
|
+
class ScssAddSelectorTask extends abstract_task_1.AbstractTask {
|
|
161
|
+
selector;
|
|
162
|
+
rules;
|
|
163
|
+
regExp;
|
|
164
|
+
constructor(identifier, selector, rules, versionRange, dependentTasks = [], options = {}) {
|
|
165
|
+
super(identifier, `Add selector "${selector}"`, types_1.SCSS_FILE_EXTENSIONS, versionRange, dependentTasks, options);
|
|
166
|
+
this.selector = selector;
|
|
167
|
+
this.rules = rules;
|
|
168
|
+
if (!selector.startsWith('.')) {
|
|
169
|
+
throw (0, reuse_1.logAndCreateError)(`Selector "${selector}" must start with a dot.`);
|
|
170
|
+
}
|
|
171
|
+
this.regExp = new RegExp(escapeRegExp(selector) + '\\s*{');
|
|
172
|
+
}
|
|
173
|
+
static getInstance(selector, rules, versionRange, dependentTasks = [], options = {}) {
|
|
174
|
+
// Include rules in identifier to ensure unique instances for different rule sets
|
|
175
|
+
// Use simple hash to create shorter, more predictable identifiers
|
|
176
|
+
const rulesHash = simpleHash(rules);
|
|
177
|
+
const identifier = `add-selector-${selector}-${rulesHash}`;
|
|
178
|
+
if (!this.instances.has(identifier)) {
|
|
179
|
+
this.instances.set(identifier, new ScssAddSelectorTask(identifier, selector, rules, versionRange, dependentTasks, options));
|
|
180
|
+
}
|
|
181
|
+
return this.instances.get(identifier);
|
|
182
|
+
}
|
|
183
|
+
run(baseDir) {
|
|
184
|
+
(0, reuse_1.filterFilesByExt)(baseDir, types_1.SCSS_FILE_EXTENSIONS).forEach((file) => {
|
|
185
|
+
let content = fs_1.default.readFileSync(file, 'utf8');
|
|
186
|
+
if (!this.regExp.test(content)) {
|
|
187
|
+
const formatting = analyzeFormatting(content);
|
|
188
|
+
const newRule = formatCssRule(this.selector, this.rules, formatting);
|
|
189
|
+
// Add appropriate spacing before the new rule
|
|
190
|
+
if (content.trim() && !content.endsWith('\n')) {
|
|
191
|
+
content += '\n';
|
|
192
|
+
}
|
|
193
|
+
if (content.trim()) {
|
|
194
|
+
content += '\n';
|
|
195
|
+
}
|
|
196
|
+
content += newRule;
|
|
197
|
+
reuse_1.MODIFIED_FILES.add(file);
|
|
198
|
+
fs_1.default.writeFileSync(file, content);
|
|
199
|
+
}
|
|
200
|
+
});
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
exports.ScssAddSelectorTask = ScssAddSelectorTask;
|
|
@@ -0,0 +1,275 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.ScssRemoveSelectorTask = void 0;
|
|
7
|
+
const fs_1 = __importDefault(require("fs"));
|
|
8
|
+
const types_1 = require("../../../../types");
|
|
9
|
+
const reuse_1 = require("../../../shares/reuse");
|
|
10
|
+
const abstract_task_1 = require("../../abstract-task");
|
|
11
|
+
/**
|
|
12
|
+
* Finds and removes a CSS selector and its complete rule block, handling nested braces correctly.
|
|
13
|
+
* Also handles comma-separated selector lists.
|
|
14
|
+
* @param {string} content The CSS content to process
|
|
15
|
+
* @param {string} selector The selector to remove (must start with a dot)
|
|
16
|
+
* @returns {string} The content with the selector removed
|
|
17
|
+
*/
|
|
18
|
+
function removeSelectorWithNestedBraces(content, selector) {
|
|
19
|
+
let result = content;
|
|
20
|
+
let offset = 0;
|
|
21
|
+
let currentIndex = 0;
|
|
22
|
+
while (currentIndex < content.length) {
|
|
23
|
+
// Find the next opening brace while properly handling strings and comments
|
|
24
|
+
const ruleStart = findNextRuleBlock(content, currentIndex);
|
|
25
|
+
if (ruleStart === -1)
|
|
26
|
+
break;
|
|
27
|
+
const openBraceIndex = ruleStart.openBraceIndex;
|
|
28
|
+
const selectorGroup = content.substring(ruleStart.selectorStart, openBraceIndex).trim();
|
|
29
|
+
// Check if this selector group contains our target selector
|
|
30
|
+
const selectors = selectorGroup.split(',').map((s) => s.trim());
|
|
31
|
+
let targetSelectorIndex = -1;
|
|
32
|
+
// First try exact match (for comma-separated lists)
|
|
33
|
+
targetSelectorIndex = selectors.findIndex((s) => s === selector);
|
|
34
|
+
// If no exact match, check if any selector contains our target as a class
|
|
35
|
+
if (targetSelectorIndex === -1) {
|
|
36
|
+
targetSelectorIndex = selectors.findIndex((s) => {
|
|
37
|
+
// Split by spaces to get individual parts of compound selectors
|
|
38
|
+
const parts = s.split(/\s+/);
|
|
39
|
+
return parts.includes(selector);
|
|
40
|
+
});
|
|
41
|
+
}
|
|
42
|
+
if (targetSelectorIndex === -1) {
|
|
43
|
+
// Target selector not found in this group, advance past this rule
|
|
44
|
+
currentIndex = findMatchingCloseBrace(content, openBraceIndex);
|
|
45
|
+
if (currentIndex === -1)
|
|
46
|
+
break;
|
|
47
|
+
currentIndex++;
|
|
48
|
+
continue;
|
|
49
|
+
}
|
|
50
|
+
// Find the matching closing brace using the existing brace counting logic
|
|
51
|
+
const closeBraceIndex = findMatchingCloseBrace(content, openBraceIndex);
|
|
52
|
+
if (closeBraceIndex === -1) {
|
|
53
|
+
// Malformed CSS, skip this rule
|
|
54
|
+
break;
|
|
55
|
+
}
|
|
56
|
+
let replacement;
|
|
57
|
+
if (selectors.length === 1) {
|
|
58
|
+
// Only one selector in the list, remove the entire rule block
|
|
59
|
+
replacement = `/* removed ${selector} */`;
|
|
60
|
+
}
|
|
61
|
+
else {
|
|
62
|
+
// Multiple selectors, remove only the target selector
|
|
63
|
+
const remainingSelectors = selectors.filter((_, index) => index !== targetSelectorIndex);
|
|
64
|
+
const ruleContent = content.substring(openBraceIndex, closeBraceIndex + 1);
|
|
65
|
+
replacement = `${remainingSelectors.join(', ')} ${ruleContent}`;
|
|
66
|
+
}
|
|
67
|
+
// Adjust for previous replacements
|
|
68
|
+
const adjustedStart = ruleStart.selectorStart - offset;
|
|
69
|
+
const adjustedEnd = closeBraceIndex + 1 - offset;
|
|
70
|
+
result = result.substring(0, adjustedStart) + replacement + result.substring(adjustedEnd);
|
|
71
|
+
const originalLength = closeBraceIndex + 1 - ruleStart.selectorStart;
|
|
72
|
+
offset += originalLength - replacement.length;
|
|
73
|
+
// Continue searching after this rule
|
|
74
|
+
currentIndex = closeBraceIndex + 1;
|
|
75
|
+
}
|
|
76
|
+
return result;
|
|
77
|
+
}
|
|
78
|
+
/**
|
|
79
|
+
* Finds the next CSS rule block while properly handling strings and comments.
|
|
80
|
+
* @param {string} content The CSS content to search
|
|
81
|
+
* @param {number} startIndex The index to start searching from
|
|
82
|
+
* @returns {object|number} Object with selectorStart and openBraceIndex, or -1 if no rule found
|
|
83
|
+
*/
|
|
84
|
+
function findNextRuleBlock(content, startIndex) {
|
|
85
|
+
let currentIndex = startIndex;
|
|
86
|
+
let inString = false;
|
|
87
|
+
let stringChar = '';
|
|
88
|
+
let inComment = false;
|
|
89
|
+
let inSingleLineComment = false;
|
|
90
|
+
let potentialSelectorStart = -1;
|
|
91
|
+
while (currentIndex < content.length) {
|
|
92
|
+
const char = content[currentIndex];
|
|
93
|
+
const nextChar = content[currentIndex + 1];
|
|
94
|
+
// Handle single-line comments
|
|
95
|
+
if (!inString && !inComment && char === '/' && nextChar === '/') {
|
|
96
|
+
inSingleLineComment = true;
|
|
97
|
+
currentIndex += 2;
|
|
98
|
+
continue;
|
|
99
|
+
}
|
|
100
|
+
if (inSingleLineComment) {
|
|
101
|
+
if (char === '\n' || char === '\r') {
|
|
102
|
+
inSingleLineComment = false;
|
|
103
|
+
}
|
|
104
|
+
currentIndex++;
|
|
105
|
+
continue;
|
|
106
|
+
}
|
|
107
|
+
// Handle multi-line comments
|
|
108
|
+
if (!inString && !inSingleLineComment && char === '/' && nextChar === '*') {
|
|
109
|
+
inComment = true;
|
|
110
|
+
currentIndex += 2;
|
|
111
|
+
continue;
|
|
112
|
+
}
|
|
113
|
+
if (inComment) {
|
|
114
|
+
if (char === '*' && nextChar === '/') {
|
|
115
|
+
inComment = false;
|
|
116
|
+
currentIndex += 2;
|
|
117
|
+
continue;
|
|
118
|
+
}
|
|
119
|
+
currentIndex++;
|
|
120
|
+
continue;
|
|
121
|
+
}
|
|
122
|
+
// Handle strings
|
|
123
|
+
if (!inComment && !inSingleLineComment && (char === '"' || char === "'")) {
|
|
124
|
+
if (!inString) {
|
|
125
|
+
inString = true;
|
|
126
|
+
stringChar = char;
|
|
127
|
+
}
|
|
128
|
+
else if (char === stringChar && content[currentIndex - 1] !== '\\') {
|
|
129
|
+
inString = false;
|
|
130
|
+
stringChar = '';
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
// Look for rule blocks only when not in strings or comments
|
|
134
|
+
if (!inString && !inComment && !inSingleLineComment) {
|
|
135
|
+
if (char === '{') {
|
|
136
|
+
// Found opening brace, find the start of this selector
|
|
137
|
+
if (potentialSelectorStart === -1) {
|
|
138
|
+
// Find the start of the selector by looking backwards for the previous rule end or start of content
|
|
139
|
+
potentialSelectorStart = findSelectorStart(content, currentIndex);
|
|
140
|
+
}
|
|
141
|
+
return {
|
|
142
|
+
selectorStart: potentialSelectorStart,
|
|
143
|
+
openBraceIndex: currentIndex,
|
|
144
|
+
};
|
|
145
|
+
}
|
|
146
|
+
else if (char === '}') {
|
|
147
|
+
// End of a rule, reset potential selector start
|
|
148
|
+
potentialSelectorStart = -1;
|
|
149
|
+
}
|
|
150
|
+
else if (potentialSelectorStart === -1 && /\S/.test(char)) {
|
|
151
|
+
// First non-whitespace character, potential start of a selector
|
|
152
|
+
potentialSelectorStart = currentIndex;
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
currentIndex++;
|
|
156
|
+
}
|
|
157
|
+
return -1;
|
|
158
|
+
}
|
|
159
|
+
/**
|
|
160
|
+
* Finds the start of a selector by looking backwards from an opening brace.
|
|
161
|
+
* @param {string} content The CSS content
|
|
162
|
+
* @param {number} openBraceIndex The index of the opening brace
|
|
163
|
+
* @returns {number} The index where the selector starts
|
|
164
|
+
*/
|
|
165
|
+
function findSelectorStart(content, openBraceIndex) {
|
|
166
|
+
let index = openBraceIndex - 1;
|
|
167
|
+
// Skip whitespace before the opening brace
|
|
168
|
+
while (index >= 0 && /\s/.test(content[index])) {
|
|
169
|
+
index--;
|
|
170
|
+
}
|
|
171
|
+
// Find the start of the selector (after previous '}' or at beginning)
|
|
172
|
+
while (index >= 0) {
|
|
173
|
+
if (content[index] === '}') {
|
|
174
|
+
return index + 1;
|
|
175
|
+
}
|
|
176
|
+
index--;
|
|
177
|
+
}
|
|
178
|
+
return 0; // Start of content
|
|
179
|
+
}
|
|
180
|
+
/**
|
|
181
|
+
* Finds the matching closing brace for an opening brace, handling nested braces correctly.
|
|
182
|
+
* @param {string} content The CSS content
|
|
183
|
+
* @param {number} openBraceIndex The index of the opening brace
|
|
184
|
+
* @returns {number} The index of the matching closing brace, or -1 if not found
|
|
185
|
+
*/
|
|
186
|
+
function findMatchingCloseBrace(content, openBraceIndex) {
|
|
187
|
+
let braceCount = 1;
|
|
188
|
+
let currentIndex = openBraceIndex + 1;
|
|
189
|
+
let inString = false;
|
|
190
|
+
let stringChar = '';
|
|
191
|
+
let inComment = false;
|
|
192
|
+
let inSingleLineComment = false;
|
|
193
|
+
while (currentIndex < content.length && braceCount > 0) {
|
|
194
|
+
const char = content[currentIndex];
|
|
195
|
+
const nextChar = content[currentIndex + 1];
|
|
196
|
+
// Handle single-line comments
|
|
197
|
+
if (!inString && !inComment && char === '/' && nextChar === '/') {
|
|
198
|
+
inSingleLineComment = true;
|
|
199
|
+
currentIndex += 2;
|
|
200
|
+
continue;
|
|
201
|
+
}
|
|
202
|
+
if (inSingleLineComment) {
|
|
203
|
+
if (char === '\n' || char === '\r') {
|
|
204
|
+
inSingleLineComment = false;
|
|
205
|
+
}
|
|
206
|
+
currentIndex++;
|
|
207
|
+
continue;
|
|
208
|
+
}
|
|
209
|
+
// Handle multi-line comments
|
|
210
|
+
if (!inString && !inSingleLineComment && char === '/' && nextChar === '*') {
|
|
211
|
+
inComment = true;
|
|
212
|
+
currentIndex += 2;
|
|
213
|
+
continue;
|
|
214
|
+
}
|
|
215
|
+
if (inComment) {
|
|
216
|
+
if (char === '*' && nextChar === '/') {
|
|
217
|
+
inComment = false;
|
|
218
|
+
currentIndex += 2;
|
|
219
|
+
continue;
|
|
220
|
+
}
|
|
221
|
+
currentIndex++;
|
|
222
|
+
continue;
|
|
223
|
+
}
|
|
224
|
+
// Handle strings
|
|
225
|
+
if (!inComment && !inSingleLineComment && (char === '"' || char === "'")) {
|
|
226
|
+
if (!inString) {
|
|
227
|
+
inString = true;
|
|
228
|
+
stringChar = char;
|
|
229
|
+
}
|
|
230
|
+
else if (char === stringChar && content[currentIndex - 1] !== '\\') {
|
|
231
|
+
inString = false;
|
|
232
|
+
stringChar = '';
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
// Count braces only when not in strings or comments
|
|
236
|
+
if (!inString && !inComment && !inSingleLineComment) {
|
|
237
|
+
if (char === '{') {
|
|
238
|
+
braceCount++;
|
|
239
|
+
}
|
|
240
|
+
else if (char === '}') {
|
|
241
|
+
braceCount--;
|
|
242
|
+
}
|
|
243
|
+
}
|
|
244
|
+
currentIndex++;
|
|
245
|
+
}
|
|
246
|
+
return braceCount === 0 ? currentIndex - 1 : -1;
|
|
247
|
+
}
|
|
248
|
+
class ScssRemoveSelectorTask extends abstract_task_1.AbstractTask {
|
|
249
|
+
selector;
|
|
250
|
+
constructor(identifier, selector, versionRange, dependentTasks = [], options = {}) {
|
|
251
|
+
super(identifier, `Remove selector "${selector}"`, types_1.SCSS_FILE_EXTENSIONS, versionRange, dependentTasks, options);
|
|
252
|
+
this.selector = selector;
|
|
253
|
+
if (!selector.startsWith('.')) {
|
|
254
|
+
throw (0, reuse_1.logAndCreateError)(`Selector "${selector}" must start with a dot.`);
|
|
255
|
+
}
|
|
256
|
+
}
|
|
257
|
+
static getInstance(selector, versionRange, dependentTasks = [], options = {}) {
|
|
258
|
+
const identifier = `remove-selector-${selector}`;
|
|
259
|
+
if (!this.instances.has(identifier)) {
|
|
260
|
+
this.instances.set(identifier, new ScssRemoveSelectorTask(identifier, selector, versionRange, dependentTasks, options));
|
|
261
|
+
}
|
|
262
|
+
return this.instances.get(identifier);
|
|
263
|
+
}
|
|
264
|
+
run(baseDir) {
|
|
265
|
+
(0, reuse_1.filterFilesByExt)(baseDir, types_1.SCSS_FILE_EXTENSIONS).forEach((file) => {
|
|
266
|
+
const content = fs_1.default.readFileSync(file, 'utf8');
|
|
267
|
+
const newContent = removeSelectorWithNestedBraces(content, this.selector);
|
|
268
|
+
if (content !== newContent) {
|
|
269
|
+
reuse_1.MODIFIED_FILES.add(file);
|
|
270
|
+
fs_1.default.writeFileSync(file, newContent);
|
|
271
|
+
}
|
|
272
|
+
});
|
|
273
|
+
}
|
|
274
|
+
}
|
|
275
|
+
exports.ScssRemoveSelectorTask = ScssRemoveSelectorTask;
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.ScssRenameBlockTask = void 0;
|
|
7
|
+
const fs_1 = __importDefault(require("fs"));
|
|
8
|
+
const types_1 = require("../../../../types");
|
|
9
|
+
const reuse_1 = require("../../../shares/reuse");
|
|
10
|
+
const abstract_task_1 = require("../../abstract-task");
|
|
11
|
+
class ScssRenameBlockTask extends abstract_task_1.AbstractTask {
|
|
12
|
+
newBlock;
|
|
13
|
+
regExp;
|
|
14
|
+
constructor(identifier, block, newBlock, versionRange, dependentTasks = [], options = {}) {
|
|
15
|
+
super(identifier, `Rename block selector "${block}" to "${newBlock}"`, types_1.SCSS_FILE_EXTENSIONS, versionRange, dependentTasks, options);
|
|
16
|
+
this.newBlock = newBlock;
|
|
17
|
+
if (!reuse_1.isKebabCaseRegExp.test(block)) {
|
|
18
|
+
throw (0, reuse_1.logAndCreateError)(`Block "${block}" is not in kebab case.`);
|
|
19
|
+
}
|
|
20
|
+
if (!reuse_1.isKebabCaseRegExp.test(newBlock)) {
|
|
21
|
+
throw (0, reuse_1.logAndCreateError)(`Block "${newBlock}" is not in kebab case.`);
|
|
22
|
+
}
|
|
23
|
+
this.regExp = new RegExp(`\\.${block}(?=(?:__|--|\\b))`, 'g');
|
|
24
|
+
}
|
|
25
|
+
static getInstance(block, newBlock, versionRange, dependentTasks = [], options = {}) {
|
|
26
|
+
const identifier = `${block}-rename-block-${newBlock}`;
|
|
27
|
+
if (!this.instances.has(identifier)) {
|
|
28
|
+
this.instances.set(identifier, new ScssRenameBlockTask(identifier, block, newBlock, versionRange, dependentTasks, options));
|
|
29
|
+
}
|
|
30
|
+
return this.instances.get(identifier);
|
|
31
|
+
}
|
|
32
|
+
run(baseDir) {
|
|
33
|
+
(0, reuse_1.filterFilesByExt)(baseDir, types_1.SCSS_FILE_EXTENSIONS).forEach((file) => {
|
|
34
|
+
const content = fs_1.default.readFileSync(file, 'utf8');
|
|
35
|
+
const newContent = content.replace(this.regExp, `.${this.newBlock}`);
|
|
36
|
+
if (content !== newContent) {
|
|
37
|
+
reuse_1.MODIFIED_FILES.add(file);
|
|
38
|
+
fs_1.default.writeFileSync(file, newContent);
|
|
39
|
+
}
|
|
40
|
+
});
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
exports.ScssRenameBlockTask = ScssRenameBlockTask;
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.ScssRenameElementTask = void 0;
|
|
7
|
+
const fs_1 = __importDefault(require("fs"));
|
|
8
|
+
const types_1 = require("../../../../types");
|
|
9
|
+
const reuse_1 = require("../../../shares/reuse");
|
|
10
|
+
const abstract_task_1 = require("../../abstract-task");
|
|
11
|
+
class ScssRenameElementTask extends abstract_task_1.AbstractTask {
|
|
12
|
+
block;
|
|
13
|
+
newElement;
|
|
14
|
+
regExp;
|
|
15
|
+
constructor(identifier, block, element, newElement, versionRange, dependentTasks = [], options = {}) {
|
|
16
|
+
super(identifier, `Rename element selector "${block}__${element}" to "${block}__${newElement}"`, types_1.SCSS_FILE_EXTENSIONS, versionRange, dependentTasks, options);
|
|
17
|
+
this.block = block;
|
|
18
|
+
this.newElement = newElement;
|
|
19
|
+
if (!reuse_1.isKebabCaseRegExp.test(block)) {
|
|
20
|
+
throw (0, reuse_1.logAndCreateError)(`Block "${block}" is not in kebab case.`);
|
|
21
|
+
}
|
|
22
|
+
if (!reuse_1.isKebabCaseRegExp.test(element)) {
|
|
23
|
+
throw (0, reuse_1.logAndCreateError)(`Element "${element}" is not in kebab case.`);
|
|
24
|
+
}
|
|
25
|
+
if (!reuse_1.isKebabCaseRegExp.test(newElement)) {
|
|
26
|
+
throw (0, reuse_1.logAndCreateError)(`Element "${newElement}" is not in kebab case.`);
|
|
27
|
+
}
|
|
28
|
+
this.regExp = new RegExp(`\\.${block}__${element}(?=(?:--|\\b))`, 'g');
|
|
29
|
+
}
|
|
30
|
+
static getInstance(block, element, newElement, versionRange, dependentTasks = [], options = {}) {
|
|
31
|
+
const identifier = `${block}-rename-element-${element}-to-${newElement}`;
|
|
32
|
+
if (!this.instances.has(identifier)) {
|
|
33
|
+
this.instances.set(identifier, new ScssRenameElementTask(identifier, block, element, newElement, versionRange, dependentTasks, options));
|
|
34
|
+
}
|
|
35
|
+
return this.instances.get(identifier);
|
|
36
|
+
}
|
|
37
|
+
run(baseDir) {
|
|
38
|
+
(0, reuse_1.filterFilesByExt)(baseDir, types_1.SCSS_FILE_EXTENSIONS).forEach((file) => {
|
|
39
|
+
const content = fs_1.default.readFileSync(file, 'utf8');
|
|
40
|
+
const newContent = content.replace(this.regExp, `.${this.block}__${this.newElement}`);
|
|
41
|
+
if (content !== newContent) {
|
|
42
|
+
reuse_1.MODIFIED_FILES.add(file);
|
|
43
|
+
fs_1.default.writeFileSync(file, newContent);
|
|
44
|
+
}
|
|
45
|
+
});
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
exports.ScssRenameElementTask = ScssRenameElementTask;
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.ScssRenameModifierTask = void 0;
|
|
7
|
+
const fs_1 = __importDefault(require("fs"));
|
|
8
|
+
const types_1 = require("../../../../types");
|
|
9
|
+
const reuse_1 = require("../../../shares/reuse");
|
|
10
|
+
const abstract_task_1 = require("../../abstract-task");
|
|
11
|
+
class ScssRenameModifierTask extends abstract_task_1.AbstractTask {
|
|
12
|
+
base;
|
|
13
|
+
newModifier;
|
|
14
|
+
regExp;
|
|
15
|
+
constructor(identifier, base, modifier, newModifier, versionRange, dependentTasks = [], options = {}) {
|
|
16
|
+
super(identifier, `Rename modifier "${modifier}" of "${base}" selector`, types_1.SCSS_FILE_EXTENSIONS, versionRange, dependentTasks, options);
|
|
17
|
+
this.base = base;
|
|
18
|
+
this.newModifier = newModifier;
|
|
19
|
+
if (!reuse_1.isKebabCaseRegExp.test(base)) {
|
|
20
|
+
throw (0, reuse_1.logAndCreateError)(`Base selector "${base}" is not in kebab case.`);
|
|
21
|
+
}
|
|
22
|
+
if (!reuse_1.isKebabCaseRegExp.test(modifier)) {
|
|
23
|
+
throw (0, reuse_1.logAndCreateError)(`Modifier "${modifier}" is not in kebab case.`);
|
|
24
|
+
}
|
|
25
|
+
if (!reuse_1.isKebabCaseRegExp.test(newModifier)) {
|
|
26
|
+
throw (0, reuse_1.logAndCreateError)(`Modifier "${newModifier}" is not in kebab case.`);
|
|
27
|
+
}
|
|
28
|
+
this.regExp = new RegExp(`\\.${base}--${modifier}(?=\\b)`, 'g');
|
|
29
|
+
}
|
|
30
|
+
static getInstance(base, modifier, newModifier, versionRange, dependentTasks = [], options = {}) {
|
|
31
|
+
const identifier = `${base}-rename-modifier-${modifier}-to-${newModifier}`;
|
|
32
|
+
if (!this.instances.has(identifier)) {
|
|
33
|
+
this.instances.set(identifier, new ScssRenameModifierTask(identifier, base, modifier, newModifier, versionRange, dependentTasks, options));
|
|
34
|
+
}
|
|
35
|
+
return this.instances.get(identifier);
|
|
36
|
+
}
|
|
37
|
+
run(baseDir) {
|
|
38
|
+
(0, reuse_1.filterFilesByExt)(baseDir, types_1.SCSS_FILE_EXTENSIONS).forEach((file) => {
|
|
39
|
+
const content = fs_1.default.readFileSync(file, 'utf8');
|
|
40
|
+
const newContent = content.replace(this.regExp, `.${this.base}--${this.newModifier}`);
|
|
41
|
+
if (content !== newContent) {
|
|
42
|
+
reuse_1.MODIFIED_FILES.add(file);
|
|
43
|
+
fs_1.default.writeFileSync(file, newContent);
|
|
44
|
+
}
|
|
45
|
+
});
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
exports.ScssRenameModifierTask = ScssRenameModifierTask;
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.ScssUpdateTokenTask = void 0;
|
|
7
|
+
const fs_1 = __importDefault(require("fs"));
|
|
8
|
+
const types_1 = require("../../../../types");
|
|
9
|
+
const reuse_1 = require("../../../shares/reuse");
|
|
10
|
+
const abstract_task_1 = require("../../abstract-task");
|
|
11
|
+
/**
|
|
12
|
+
* Escapes special characters for use in a regular expression.
|
|
13
|
+
* @param {string} str String to escape
|
|
14
|
+
* @returns {string} Escaped string
|
|
15
|
+
*/
|
|
16
|
+
function escapeRegExp(str) {
|
|
17
|
+
return str.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
|
|
18
|
+
}
|
|
19
|
+
class ScssUpdateTokenTask extends abstract_task_1.AbstractTask {
|
|
20
|
+
newToken;
|
|
21
|
+
regExp;
|
|
22
|
+
constructor(identifier, token, newToken, versionRange, dependentTasks = [], options = {}) {
|
|
23
|
+
super(identifier, `Update token "${token}" to "${newToken}"`, types_1.SCSS_FILE_EXTENSIONS, versionRange, dependentTasks, options);
|
|
24
|
+
this.newToken = newToken;
|
|
25
|
+
if (!token.startsWith('$')) {
|
|
26
|
+
throw (0, reuse_1.logAndCreateError)(`Token "${token}" must start with "$".`);
|
|
27
|
+
}
|
|
28
|
+
if (!newToken.startsWith('$')) {
|
|
29
|
+
throw (0, reuse_1.logAndCreateError)(`Token "${newToken}" must start with "$".`);
|
|
30
|
+
}
|
|
31
|
+
this.regExp = new RegExp(escapeRegExp(token) + '(?=\\s|:|;|,|\\)|\\}|$)', 'g');
|
|
32
|
+
}
|
|
33
|
+
static getInstance(token, newToken, versionRange, dependentTasks = [], options = {}) {
|
|
34
|
+
const identifier = `update-token-${token}-to-${newToken}`;
|
|
35
|
+
if (!this.instances.has(identifier)) {
|
|
36
|
+
this.instances.set(identifier, new ScssUpdateTokenTask(identifier, token, newToken, versionRange, dependentTasks, options));
|
|
37
|
+
}
|
|
38
|
+
return this.instances.get(identifier);
|
|
39
|
+
}
|
|
40
|
+
run(baseDir) {
|
|
41
|
+
(0, reuse_1.filterFilesByExt)(baseDir, types_1.SCSS_FILE_EXTENSIONS).forEach((file) => {
|
|
42
|
+
const content = fs_1.default.readFileSync(file, 'utf8');
|
|
43
|
+
const newContent = content.replace(this.regExp, this.newToken);
|
|
44
|
+
if (content !== newContent) {
|
|
45
|
+
reuse_1.MODIFIED_FILES.add(file);
|
|
46
|
+
fs_1.default.writeFileSync(file, newContent);
|
|
47
|
+
}
|
|
48
|
+
});
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
exports.ScssUpdateTokenTask = ScssUpdateTokenTask;
|
|
@@ -6,6 +6,7 @@ const abbr_1 = require("./abbr");
|
|
|
6
6
|
const modal_1 = require("./modal");
|
|
7
7
|
const input_file_1 = require("./input-file");
|
|
8
8
|
const all_input_1 = require("./all-input");
|
|
9
|
+
const toaster_1 = require("./toaster");
|
|
9
10
|
exports.v3Tasks = [];
|
|
10
11
|
exports.v3Tasks.push(textarea_1.TextareaUpdatePropertyValue_Resize_Both);
|
|
11
12
|
exports.v3Tasks.push(textarea_1.TextareaUpdatePropertyValue_Resize_Horizontal);
|
|
@@ -13,3 +14,4 @@ exports.v3Tasks.push(abbr_1.AbbrRemovePropertyTooltipAlign);
|
|
|
13
14
|
exports.v3Tasks.push(modal_1.ModalRemovePropertyActiveElement);
|
|
14
15
|
exports.v3Tasks.push(input_file_1.InputFileRemovePropertyValue);
|
|
15
16
|
exports.v3Tasks.push(...all_input_1.AllInputTasks);
|
|
17
|
+
exports.v3Tasks.push(toaster_1.ToasterRenameProperties);
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.ToasterRenameProperties = void 0;
|
|
7
|
+
const fs_1 = __importDefault(require("fs"));
|
|
8
|
+
const types_1 = require("../../../../types");
|
|
9
|
+
const fileExtensions = [...types_1.FILE_EXTENSIONS];
|
|
10
|
+
const reuse_1 = require("../../../shares/reuse");
|
|
11
|
+
const abstract_task_1 = require("../../abstract-task");
|
|
12
|
+
class ToasterRenamePropertiesTask extends abstract_task_1.AbstractTask {
|
|
13
|
+
constructor() {
|
|
14
|
+
super('toaster-rename-properties', 'Rename Toaster properties `alertVariant` to `variant` and `defaultAlertType` to `defaultVariant`', fileExtensions, '>=2 <4');
|
|
15
|
+
}
|
|
16
|
+
static getInstance() {
|
|
17
|
+
const identifier = 'toaster-rename-properties';
|
|
18
|
+
if (!this.instances.has(identifier)) {
|
|
19
|
+
this.instances.set(identifier, new ToasterRenamePropertiesTask());
|
|
20
|
+
}
|
|
21
|
+
return this.instances.get(identifier);
|
|
22
|
+
}
|
|
23
|
+
run(baseDir) {
|
|
24
|
+
(0, reuse_1.filterFilesByExt)(baseDir, fileExtensions).forEach((file) => {
|
|
25
|
+
const content = fs_1.default.readFileSync(file, 'utf8');
|
|
26
|
+
const newContent = content.replace(/alertVariant(?=\s*:)/g, 'variant').replace(/defaultAlertType(?=\s*:)/g, 'defaultVariant');
|
|
27
|
+
if (content !== newContent) {
|
|
28
|
+
reuse_1.MODIFIED_FILES.add(file);
|
|
29
|
+
fs_1.default.writeFileSync(file, newContent);
|
|
30
|
+
}
|
|
31
|
+
});
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
exports.ToasterRenameProperties = ToasterRenamePropertiesTask.getInstance();
|
package/dist/types.js
CHANGED
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.REACT_TAG_REGEX = exports.WEB_TAG_REGEX = exports.MARKUP_EXTENSIONS = exports.CUSTOM_ELEMENT_FILE_EXTENSIONS = exports.COMPONENT_FILE_EXTENSIONS = exports.FILE_EXTENSIONS = void 0;
|
|
4
|
-
exports.FILE_EXTENSIONS = ['html', 'xhtml', 'js', 'json', 'jsx', 'ts', 'tsx', 'vue'];
|
|
3
|
+
exports.REACT_TAG_REGEX = exports.WEB_TAG_REGEX = exports.SCSS_FILE_EXTENSIONS = exports.MARKUP_EXTENSIONS = exports.CUSTOM_ELEMENT_FILE_EXTENSIONS = exports.COMPONENT_FILE_EXTENSIONS = exports.FILE_EXTENSIONS = void 0;
|
|
4
|
+
exports.FILE_EXTENSIONS = ['html', 'xhtml', 'js', 'json', 'jsx', 'ts', 'tsx', 'vue', 'css', 'sass', 'scss'];
|
|
5
5
|
exports.COMPONENT_FILE_EXTENSIONS = ['jsx', 'tsx', 'vue'];
|
|
6
6
|
exports.CUSTOM_ELEMENT_FILE_EXTENSIONS = ['html', 'xhtml', 'jsx', 'tsx', 'vue'];
|
|
7
7
|
exports.MARKUP_EXTENSIONS = exports.COMPONENT_FILE_EXTENSIONS.concat(exports.CUSTOM_ELEMENT_FILE_EXTENSIONS);
|
|
8
|
+
exports.SCSS_FILE_EXTENSIONS = ['css', 'sass', 'scss'];
|
|
8
9
|
exports.WEB_TAG_REGEX = /\b<kol-[a-z-]+/i;
|
|
9
10
|
exports.REACT_TAG_REGEX = /\b<Kol[A-Z][A-Za-z]*/;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@public-ui/kolibri-cli",
|
|
3
|
-
"version": "3.0.4-rc.
|
|
3
|
+
"version": "3.0.4-rc.2",
|
|
4
4
|
"license": "EUPL-1.2",
|
|
5
5
|
"homepage": "https://public-ui.github.io",
|
|
6
6
|
"repository": {
|
|
@@ -21,35 +21,35 @@
|
|
|
21
21
|
"description": "CLI for executing some helpful commands for KoliBri projects.",
|
|
22
22
|
"type": "commonjs",
|
|
23
23
|
"dependencies": {
|
|
24
|
-
"chalk": "5.
|
|
24
|
+
"chalk": "5.6.0",
|
|
25
25
|
"commander": "14.0.0",
|
|
26
26
|
"deepmerge": "4.3.1",
|
|
27
27
|
"gradient-string": "3.0.0",
|
|
28
28
|
"loglevel": "1.9.2",
|
|
29
|
-
"prettier": "3.
|
|
29
|
+
"prettier": "3.6.2",
|
|
30
30
|
"semver": "7.7.2",
|
|
31
31
|
"typed-bem": "1.0.0-rc.7",
|
|
32
|
-
"@public-ui/components": "3.0.4-rc.
|
|
32
|
+
"@public-ui/components": "3.0.4-rc.2"
|
|
33
33
|
},
|
|
34
34
|
"devDependencies": {
|
|
35
|
-
"@types/node": "24.0
|
|
35
|
+
"@types/node": "24.3.0",
|
|
36
36
|
"@typescript-eslint/eslint-plugin": "7.18.0",
|
|
37
37
|
"@typescript-eslint/parser": "7.18.0",
|
|
38
|
-
"cpy-cli": "
|
|
39
|
-
"cross-env": "
|
|
38
|
+
"cpy-cli": "6.0.0",
|
|
39
|
+
"cross-env": "10.0.0",
|
|
40
40
|
"eslint": "8.57.1",
|
|
41
|
-
"eslint-config-prettier": "9.1.
|
|
41
|
+
"eslint-config-prettier": "9.1.2",
|
|
42
42
|
"eslint-plugin-html": "8.1.3",
|
|
43
43
|
"eslint-plugin-jsdoc": "50.8.0",
|
|
44
44
|
"eslint-plugin-json": "3.1.0",
|
|
45
45
|
"eslint-plugin-jsx-a11y": "6.10.2",
|
|
46
46
|
"eslint-plugin-react": "7.37.5",
|
|
47
|
-
"knip": "5.
|
|
48
|
-
"mocha": "11.
|
|
47
|
+
"knip": "5.63.0",
|
|
48
|
+
"mocha": "11.7.1",
|
|
49
49
|
"nodemon": "3.1.10",
|
|
50
50
|
"rimraf": "6.0.1",
|
|
51
51
|
"ts-node": "10.9.2",
|
|
52
|
-
"typescript": "5.
|
|
52
|
+
"typescript": "5.9.2"
|
|
53
53
|
},
|
|
54
54
|
"files": [
|
|
55
55
|
"dist"
|