@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 CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@entur/typography",
3
- "version": "1.10.0-beta.4",
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": "^8.0.0",
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": "8d064eda2fb3e82dc87f08625f7833f92737f32e"
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
- if (changes > 0) {
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
- report.migratedFiles++;
578
- report.totalChanges += changes;
579
- report.totalWarnings += warnings.length;
580
- report.files.push({ file, changes, warnings });
581
- report.warnings.push(...warnings.map(warning => `${file}: ${warning}`));
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
- marginWarnings.forEach(warning => console.log(` ${warning}`));
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
- semanticWarnings.forEach(warning => console.log(` ${warning}`));
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
- conflictWarnings.forEach(warning => console.log(` ${warning}`));
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