@entur/typography 1.10.0-beta.4 ā 1.10.0-beta.6
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/package.json +3 -3
- package/scripts/migrate-typography.js +329 -9
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@entur/typography",
|
|
3
|
-
"version": "1.10.0-beta.
|
|
3
|
+
"version": "1.10.0-beta.6",
|
|
4
4
|
"license": "SEE LICENSE IN README.md",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"module": "dist/typography.esm.js",
|
|
@@ -28,7 +28,7 @@
|
|
|
28
28
|
"migrate-typography": "scripts/migrate-typography.js"
|
|
29
29
|
},
|
|
30
30
|
"peerDependencies": {
|
|
31
|
-
"glob": "^
|
|
31
|
+
"glob": "^11.0.0",
|
|
32
32
|
"react": ">=16.8.0",
|
|
33
33
|
"react-dom": ">=16.8.0"
|
|
34
34
|
},
|
|
@@ -42,5 +42,5 @@
|
|
|
42
42
|
"devDependencies": {
|
|
43
43
|
"dts-cli": "2.0.5"
|
|
44
44
|
},
|
|
45
|
-
"gitHead": "
|
|
45
|
+
"gitHead": "42c5a2e7657f2b5ca17328fcf55873b19e23f94a"
|
|
46
46
|
}
|
|
@@ -72,6 +72,31 @@ try {
|
|
|
72
72
|
const OLD_IMPORT = '@entur/typography';
|
|
73
73
|
const BETA_IMPORT = '@entur/typography';
|
|
74
74
|
|
|
75
|
+
// Enhanced warning detection patterns - only truly problematic patterns
|
|
76
|
+
const PROBLEMATIC_PATTERNS = {
|
|
77
|
+
// Style conflicts that will cause issues
|
|
78
|
+
styleMarginConflict: /style=.*margin=/g,
|
|
79
|
+
styleSpacingConflict: /style=.*spacing=/g,
|
|
80
|
+
|
|
81
|
+
// Invalid HTML structure
|
|
82
|
+
nestedTypography: /<Text[^>]*>.*<Text[^>]*>/g,
|
|
83
|
+
|
|
84
|
+
// Accessibility issues
|
|
85
|
+
missingAsProps: /<Heading[^>]*>(?!.*\bas=)/g,
|
|
86
|
+
|
|
87
|
+
// Semantic HTML mismatches
|
|
88
|
+
semanticMismatch: /<Heading[^>]*as="([^"]*)"[^>]*variant="([^"]*)"/g,
|
|
89
|
+
};
|
|
90
|
+
|
|
91
|
+
// Warning severity levels
|
|
92
|
+
const WARNING_CATEGORIES = {
|
|
93
|
+
CRITICAL: 'critical', // Will break functionality
|
|
94
|
+
HIGH: 'high', // Likely to cause issues
|
|
95
|
+
MEDIUM: 'medium', // May cause styling issues
|
|
96
|
+
LOW: 'low', // Best practice suggestions
|
|
97
|
+
INFO: 'info', // Informational only
|
|
98
|
+
};
|
|
99
|
+
|
|
75
100
|
// =============================================================================
|
|
76
101
|
// šÆ MIGRATION FOLDERS CONFIGURATION
|
|
77
102
|
// =============================================================================
|
|
@@ -114,6 +139,153 @@ function validateDirectoryPath(dir) {
|
|
|
114
139
|
return !path.isAbsolute(dir) && !dir.includes('..') && !dir.includes('~');
|
|
115
140
|
}
|
|
116
141
|
|
|
142
|
+
// Enhanced file analysis for better warning detection - only truly problematic patterns
|
|
143
|
+
function analyzeFile(filePath, content) {
|
|
144
|
+
const analysis = {
|
|
145
|
+
hasStyleConflicts: false,
|
|
146
|
+
hasNestedTypography: false,
|
|
147
|
+
hasAccessibilityIssues: false,
|
|
148
|
+
hasSemanticMismatches: false,
|
|
149
|
+
lineNumbers: {},
|
|
150
|
+
suggestions: [],
|
|
151
|
+
warnings: [],
|
|
152
|
+
};
|
|
153
|
+
|
|
154
|
+
// Line-by-line analysis for better context
|
|
155
|
+
content.split('\n').forEach((line, index) => {
|
|
156
|
+
const lineNum = index + 1;
|
|
157
|
+
|
|
158
|
+
// Check for style conflicts (style + margin/spacing)
|
|
159
|
+
if (
|
|
160
|
+
line.match(PROBLEMATIC_PATTERNS.styleMarginConflict) ||
|
|
161
|
+
line.match(PROBLEMATIC_PATTERNS.styleSpacingConflict)
|
|
162
|
+
) {
|
|
163
|
+
analysis.hasStyleConflicts = true;
|
|
164
|
+
analysis.lineNumbers.styleConflicts = (
|
|
165
|
+
analysis.lineNumbers.styleConflicts || []
|
|
166
|
+
).concat(lineNum);
|
|
167
|
+
|
|
168
|
+
// Generate warning message
|
|
169
|
+
analysis.warnings.push(
|
|
170
|
+
`Line ${lineNum}: Style conflicts detected - component has both style and margin/spacing props`,
|
|
171
|
+
);
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
// Check for nested typography components (invalid HTML)
|
|
175
|
+
if (line.match(PROBLEMATIC_PATTERNS.nestedTypography)) {
|
|
176
|
+
analysis.hasNestedTypography = true;
|
|
177
|
+
analysis.lineNumbers.nestedTypography = (
|
|
178
|
+
analysis.lineNumbers.nestedTypography || []
|
|
179
|
+
).concat(lineNum);
|
|
180
|
+
|
|
181
|
+
// Generate warning message
|
|
182
|
+
analysis.warnings.push(
|
|
183
|
+
`Line ${lineNum}: Nested typography components detected - invalid HTML structure`,
|
|
184
|
+
);
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
// Check for missing as props (accessibility issue)
|
|
188
|
+
if (line.match(PROBLEMATIC_PATTERNS.missingAsProps)) {
|
|
189
|
+
analysis.hasAccessibilityIssues = true;
|
|
190
|
+
analysis.lineNumbers.missingAsProps = (
|
|
191
|
+
analysis.lineNumbers.missingAsProps || []
|
|
192
|
+
).concat(lineNum);
|
|
193
|
+
|
|
194
|
+
// Generate warning message
|
|
195
|
+
analysis.warnings.push(
|
|
196
|
+
`Line ${lineNum}: Missing 'as' prop - accessibility issue for Heading component`,
|
|
197
|
+
);
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
// Check for semantic mismatches (e.g., h1 with subtitle variant)
|
|
201
|
+
if (line.match(PROBLEMATIC_PATTERNS.semanticMismatch)) {
|
|
202
|
+
analysis.hasSemanticMismatches = true;
|
|
203
|
+
analysis.lineNumbers.semanticMismatches = (
|
|
204
|
+
analysis.lineNumbers.semanticMismatches || []
|
|
205
|
+
).concat(lineNum);
|
|
206
|
+
|
|
207
|
+
// Generate warning message
|
|
208
|
+
analysis.warnings.push(
|
|
209
|
+
`Line ${lineNum}: Semantic mismatch detected - heading level and variant combination may be incorrect`,
|
|
210
|
+
);
|
|
211
|
+
}
|
|
212
|
+
});
|
|
213
|
+
|
|
214
|
+
return analysis;
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
// Generate enhanced warnings with context and solutions
|
|
218
|
+
function generateWarningWithSolution(warning, context, filePath, lineNumber) {
|
|
219
|
+
const severity = determineSeverity(warning);
|
|
220
|
+
const suggestion = generateSuggestion(warning, context);
|
|
221
|
+
const codeExample = generateCodeExample(warning);
|
|
222
|
+
|
|
223
|
+
return {
|
|
224
|
+
message: warning,
|
|
225
|
+
severity,
|
|
226
|
+
suggestion,
|
|
227
|
+
codeExample,
|
|
228
|
+
file: filePath,
|
|
229
|
+
line: lineNumber,
|
|
230
|
+
documentation: getRelevantDocs(warning),
|
|
231
|
+
};
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
// Determine warning severity based on content
|
|
235
|
+
function determineSeverity(warning) {
|
|
236
|
+
if (warning.includes('will break') || warning.includes('fatal'))
|
|
237
|
+
return WARNING_CATEGORIES.CRITICAL;
|
|
238
|
+
if (warning.includes('conflict') || warning.includes('override'))
|
|
239
|
+
return WARNING_CATEGORIES.HIGH;
|
|
240
|
+
if (warning.includes('may cause') || warning.includes('styling'))
|
|
241
|
+
return WARNING_CATEGORIES.MEDIUM;
|
|
242
|
+
if (warning.includes('best practice') || warning.includes('consider'))
|
|
243
|
+
return WARNING_CATEGORIES.LOW;
|
|
244
|
+
return WARNING_CATEGORIES.INFO;
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
// Generate actionable suggestions
|
|
248
|
+
function generateSuggestion(warning, context) {
|
|
249
|
+
if (warning.includes('style and margin')) {
|
|
250
|
+
return 'Remove the margin prop as it will be overridden by inline styles. Use spacing prop instead.';
|
|
251
|
+
}
|
|
252
|
+
if (warning.includes('missing variant')) {
|
|
253
|
+
return 'Add a variant prop to ensure consistent styling. Example: variant="title-1"';
|
|
254
|
+
}
|
|
255
|
+
if (warning.includes('nested typography')) {
|
|
256
|
+
return 'Avoid nesting Text components. Use spans or other inline elements for emphasis.';
|
|
257
|
+
}
|
|
258
|
+
if (warning.includes('deprecated margin')) {
|
|
259
|
+
return 'Replace margin prop with spacing prop for better consistency.';
|
|
260
|
+
}
|
|
261
|
+
return 'Review the component for potential styling conflicts.';
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
// Generate code examples for fixes
|
|
265
|
+
function generateCodeExample(warning) {
|
|
266
|
+
if (warning.includes('style and margin')) {
|
|
267
|
+
return '// Before: <Text style={{color: "red"}} margin="bottom">\n// After: <Text style={{color: "red"}} spacing="bottom">';
|
|
268
|
+
}
|
|
269
|
+
if (warning.includes('missing variant')) {
|
|
270
|
+
return '// Before: <Heading as="h1">Title</Heading>\n// After: <Heading as="h1" variant="title-1">Title</Heading>';
|
|
271
|
+
}
|
|
272
|
+
if (warning.includes('nested typography')) {
|
|
273
|
+
return '// Before: <Text>Hello <Text>World</Text></Text>\n// After: <Text>Hello <span>World</span></Text>';
|
|
274
|
+
}
|
|
275
|
+
return '';
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
// Get relevant documentation links
|
|
279
|
+
function getRelevantDocs(warning) {
|
|
280
|
+
if (warning.includes('variant'))
|
|
281
|
+
return 'https://linje.entur.no/komponenter/ressurser/typography-beta#heading-variants';
|
|
282
|
+
if (warning.includes('spacing'))
|
|
283
|
+
return 'https://linje.entur.no/komponenter/ressurser/typography-beta#spacing';
|
|
284
|
+
if (warning.includes('semantic'))
|
|
285
|
+
return 'https://linje.entur.no/komponenter/ressurser/typography-beta#semantic-html';
|
|
286
|
+
return 'https://linje.entur.no/komponenter/ressurser/typography-beta';
|
|
287
|
+
}
|
|
288
|
+
|
|
117
289
|
let ALLOWED_DIRECTORIES = process.env.TYPOGRAPHY_MIGRATION_DIRS
|
|
118
290
|
? process.env.TYPOGRAPHY_MIGRATION_DIRS.split(',')
|
|
119
291
|
: MIGRATION_FOLDERS;
|
|
@@ -564,21 +736,32 @@ function generateMigrationReport(files, strategy, isDryRun = false) {
|
|
|
564
736
|
files.forEach(file => {
|
|
565
737
|
try {
|
|
566
738
|
const content = fs.readFileSync(file, 'utf8');
|
|
739
|
+
|
|
740
|
+
// Analyze file for problematic patterns BEFORE migration
|
|
741
|
+
const fileAnalysis = analyzeFile(file, content);
|
|
742
|
+
|
|
567
743
|
const {
|
|
568
744
|
content: updatedContent,
|
|
569
745
|
changes,
|
|
570
746
|
warnings,
|
|
571
747
|
} = updateImportsAndComponents(content, strategy);
|
|
572
748
|
|
|
573
|
-
|
|
749
|
+
// Combine migration warnings with file analysis warnings
|
|
750
|
+
const allWarnings = [...warnings, ...fileAnalysis.warnings];
|
|
751
|
+
|
|
752
|
+
if (changes > 0 || fileAnalysis.warnings.length > 0) {
|
|
574
753
|
if (!isDryRun) {
|
|
575
754
|
fs.writeFileSync(file, updatedContent, 'utf8');
|
|
576
755
|
}
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
report.
|
|
756
|
+
if (changes > 0) {
|
|
757
|
+
report.migratedFiles++;
|
|
758
|
+
report.totalChanges += changes;
|
|
759
|
+
}
|
|
760
|
+
report.totalWarnings += allWarnings.length;
|
|
761
|
+
report.files.push({ file, changes, warnings: allWarnings });
|
|
762
|
+
report.warnings.push(
|
|
763
|
+
...allWarnings.map(warning => `${file}: ${warning}`),
|
|
764
|
+
);
|
|
582
765
|
}
|
|
583
766
|
} catch (error) {
|
|
584
767
|
report.warnings.push(`${file}: Error processing file - ${error.message}`);
|
|
@@ -620,24 +803,135 @@ function printReport(report) {
|
|
|
620
803
|
w.includes('check for conflicts'),
|
|
621
804
|
);
|
|
622
805
|
|
|
806
|
+
// New warning types from file analysis
|
|
807
|
+
const styleConflictWarnings = report.warnings.filter(
|
|
808
|
+
w => w.includes('style conflicts') || w.includes('style and margin'),
|
|
809
|
+
);
|
|
810
|
+
const nestedTypographyWarnings = report.warnings.filter(w =>
|
|
811
|
+
w.includes('nested typography'),
|
|
812
|
+
);
|
|
813
|
+
const accessibilityWarnings = report.warnings.filter(
|
|
814
|
+
w => w.includes('missing as prop') || w.includes('accessibility'),
|
|
815
|
+
);
|
|
816
|
+
const semanticMismatchWarnings = report.warnings.filter(w =>
|
|
817
|
+
w.includes('semantic mismatch'),
|
|
818
|
+
);
|
|
819
|
+
|
|
623
820
|
if (marginWarnings.length > 0) {
|
|
624
821
|
console.log(
|
|
625
822
|
`\n š Margin ā Spacing Migrations (${marginWarnings.length}):`,
|
|
626
823
|
);
|
|
627
|
-
|
|
824
|
+
// Show first 5 warnings, then summarize the rest
|
|
825
|
+
marginWarnings
|
|
826
|
+
.slice(0, 5)
|
|
827
|
+
.forEach(warning => console.log(` ${warning}`));
|
|
828
|
+
if (marginWarnings.length > 5) {
|
|
829
|
+
console.log(
|
|
830
|
+
` ... and ${marginWarnings.length - 5} more similar warnings`,
|
|
831
|
+
);
|
|
832
|
+
}
|
|
628
833
|
}
|
|
629
834
|
|
|
630
835
|
if (semanticWarnings.length > 0) {
|
|
631
836
|
console.log(`\n šÆ Semantic HTML Issues (${semanticWarnings.length}):`);
|
|
632
|
-
|
|
837
|
+
// Show first 5 warnings, then summarize the rest
|
|
838
|
+
semanticWarnings
|
|
839
|
+
.slice(0, 5)
|
|
840
|
+
.forEach(warning => console.log(` ${warning}`));
|
|
841
|
+
if (semanticWarnings.length > 5) {
|
|
842
|
+
console.log(
|
|
843
|
+
` ... and ${semanticWarnings.length - 5} more similar warnings`,
|
|
844
|
+
);
|
|
845
|
+
}
|
|
633
846
|
}
|
|
634
847
|
|
|
635
848
|
if (conflictWarnings.length > 0) {
|
|
636
849
|
console.log(`\n šØ Style Conflicts (${conflictWarnings.length}):`);
|
|
637
|
-
|
|
850
|
+
// Show first 5 warnings, then summarize the rest
|
|
851
|
+
conflictWarnings
|
|
852
|
+
.slice(0, 5)
|
|
853
|
+
.forEach(warning => console.log(` ${warning}`));
|
|
854
|
+
if (conflictWarnings.length > 5) {
|
|
855
|
+
console.log(
|
|
856
|
+
` ... and ${conflictWarnings.length - 5} more similar warnings`,
|
|
857
|
+
);
|
|
858
|
+
}
|
|
638
859
|
console.log(` ā Review these components for styling conflicts`);
|
|
639
860
|
}
|
|
640
861
|
|
|
862
|
+
// Display new warning types
|
|
863
|
+
if (styleConflictWarnings.length > 0) {
|
|
864
|
+
console.log(
|
|
865
|
+
`\n šØ Style + Margin Conflicts (${styleConflictWarnings.length}):`,
|
|
866
|
+
);
|
|
867
|
+
styleConflictWarnings
|
|
868
|
+
.slice(0, 5)
|
|
869
|
+
.forEach(warning => console.log(` ${warning}`));
|
|
870
|
+
if (styleConflictWarnings.length > 5) {
|
|
871
|
+
console.log(
|
|
872
|
+
` ... and ${
|
|
873
|
+
styleConflictWarnings.length - 5
|
|
874
|
+
} more similar warnings`,
|
|
875
|
+
);
|
|
876
|
+
}
|
|
877
|
+
console.log(` ā Remove margin prop when using inline styles`);
|
|
878
|
+
}
|
|
879
|
+
|
|
880
|
+
if (nestedTypographyWarnings.length > 0) {
|
|
881
|
+
console.log(
|
|
882
|
+
`\n š« Nested Typography (${nestedTypographyWarnings.length}):`,
|
|
883
|
+
);
|
|
884
|
+
nestedTypographyWarnings
|
|
885
|
+
.slice(0, 5)
|
|
886
|
+
.forEach(warning => console.log(` ${warning}`));
|
|
887
|
+
if (nestedTypographyWarnings.length > 5) {
|
|
888
|
+
console.log(
|
|
889
|
+
` ... and ${
|
|
890
|
+
nestedTypographyWarnings.length - 5
|
|
891
|
+
} more similar warnings`,
|
|
892
|
+
);
|
|
893
|
+
}
|
|
894
|
+
console.log(
|
|
895
|
+
` ā Use spans or other inline elements instead of nested Text components`,
|
|
896
|
+
);
|
|
897
|
+
}
|
|
898
|
+
|
|
899
|
+
if (accessibilityWarnings.length > 0) {
|
|
900
|
+
console.log(
|
|
901
|
+
`\n āæ Accessibility Issues (${accessibilityWarnings.length}):`,
|
|
902
|
+
);
|
|
903
|
+
accessibilityWarnings
|
|
904
|
+
.slice(0, 5)
|
|
905
|
+
.forEach(warning => console.log(` ${warning}`));
|
|
906
|
+
if (accessibilityWarnings.length > 5) {
|
|
907
|
+
console.log(
|
|
908
|
+
` ... and ${
|
|
909
|
+
accessibilityWarnings.length - 5
|
|
910
|
+
} more similar warnings`,
|
|
911
|
+
);
|
|
912
|
+
}
|
|
913
|
+
console.log(
|
|
914
|
+
` ā Add 'as' prop to Heading components for proper semantic HTML`,
|
|
915
|
+
);
|
|
916
|
+
}
|
|
917
|
+
|
|
918
|
+
if (semanticMismatchWarnings.length > 0) {
|
|
919
|
+
console.log(
|
|
920
|
+
`\n š Semantic Mismatches (${semanticMismatchWarnings.length}):`,
|
|
921
|
+
);
|
|
922
|
+
semanticMismatchWarnings
|
|
923
|
+
.slice(0, 5)
|
|
924
|
+
.forEach(warning => console.log(` ${warning}`));
|
|
925
|
+
if (semanticMismatchWarnings.length > 5) {
|
|
926
|
+
console.log(
|
|
927
|
+
` ... and ${
|
|
928
|
+
semanticMismatchWarnings.length - 5
|
|
929
|
+
} more similar warnings`,
|
|
930
|
+
);
|
|
931
|
+
}
|
|
932
|
+
console.log(` ā Review heading level and variant combinations`);
|
|
933
|
+
}
|
|
934
|
+
|
|
641
935
|
console.log('\nš Summary:');
|
|
642
936
|
if (marginWarnings.length > 0)
|
|
643
937
|
console.log(
|
|
@@ -651,6 +945,32 @@ function printReport(report) {
|
|
|
651
945
|
console.log(
|
|
652
946
|
` ⢠${conflictWarnings.length} style conflicts need manual review`,
|
|
653
947
|
);
|
|
948
|
+
if (styleConflictWarnings.length > 0)
|
|
949
|
+
console.log(
|
|
950
|
+
` ⢠${styleConflictWarnings.length} style + margin conflicts detected`,
|
|
951
|
+
);
|
|
952
|
+
if (nestedTypographyWarnings.length > 0)
|
|
953
|
+
console.log(
|
|
954
|
+
` ⢠${nestedTypographyWarnings.length} nested typography components found`,
|
|
955
|
+
);
|
|
956
|
+
if (accessibilityWarnings.length > 0)
|
|
957
|
+
console.log(
|
|
958
|
+
` ⢠${accessibilityWarnings.length} accessibility issues need attention`,
|
|
959
|
+
);
|
|
960
|
+
if (semanticMismatchWarnings.length > 0)
|
|
961
|
+
console.log(
|
|
962
|
+
` ⢠${semanticMismatchWarnings.length} semantic mismatches detected`,
|
|
963
|
+
);
|
|
964
|
+
|
|
965
|
+
// Add helpful note about warning limits
|
|
966
|
+
if (report.warnings.length > 15) {
|
|
967
|
+
console.log(
|
|
968
|
+
'\nš” Note: Only showing first 5 warnings of each type to avoid overwhelming output.',
|
|
969
|
+
);
|
|
970
|
+
console.log(
|
|
971
|
+
' All warnings are still logged in the migration report above.',
|
|
972
|
+
);
|
|
973
|
+
}
|
|
654
974
|
}
|
|
655
975
|
}
|
|
656
976
|
|