diff --git a/.github/PULL_REQUEST_TEMPLATE/time-detection-fixes.md b/.github/PULL_REQUEST_TEMPLATE/time-detection-fixes.md deleted file mode 100644 index adeeb3f..0000000 --- a/.github/PULL_REQUEST_TEMPLATE/time-detection-fixes.md +++ /dev/null @@ -1,29 +0,0 @@ -# Time Detection Fixes Applied - -All critical issues from PR #37 have been fixed in branch `fix-pr-37-time-detection`. - -## Issues Fixed - -### Critical Bugs: -1. ✅ Removed `.vscode/settings.json` (personal config file) -2. ✅ Fixed AM/PM conversion logic - now converts before Date creation -3. ✅ Fixed timezone validation bug (was comparing number to string 'z') -4. ✅ Added validation to ensure all time parts are consumed -5. ✅ Reverted unrelated formatting changes to `eslint.config.js` and `index.d.ts` -6. ✅ Added `time` to all required configuration maps: - - `PATTERNS` object - - `JSON_SCHEMA_TYPE_MAP` - - `JSON_SCHEMA_PATTERN_MAP` - - `TYPE_PRIORITY` - -### Code Quality Fixes: -7. ✅ Uncommented JSDoc for `parseTimezone` -8. ✅ Fixed `isTime()` to return `false` instead of `null` -9. ✅ Fixed README time example (removed object notation) -10. ✅ Fixed code spacing and formatting issues - -## Test Results -All 96 tests passing ✅ - -## Branch -The fixed code is available at: `fix-pr-37-time-detection` diff --git a/PR_37_FIXES.md b/PR_37_FIXES.md new file mode 100644 index 0000000..74bc46b --- /dev/null +++ b/PR_37_FIXES.md @@ -0,0 +1,25 @@ +# PR #37 Time Detection - All Issues Fixed ✅ + +Branch: `fix-pr-37-time-detection` + +## Critical Bugs Fixed: +1. ✅ Removed `.vscode/settings.json` (personal config file) +2. ✅ Fixed AM/PM conversion logic - now converts BEFORE Date creation +3. ✅ Fixed timezone validation bug (was comparing number !== 'z' string) +4. ✅ Added validation to ensure all time parts are consumed +5. ✅ Reverted unrelated formatting changes to eslint.config.js and index.d.ts +6. ✅ Added time to PATTERNS, JSON_SCHEMA_TYPE_MAP, JSON_SCHEMA_PATTERN_MAP, TYPE_PRIORITY + +## Code Quality Fixes: +7. ✅ Uncommented JSDoc for parseTimezone +8. ✅ Fixed isTime() to return false instead of null +9. ✅ Fixed README time example format +10. ✅ Fixed code spacing and formatting + +## Test Results: +- All 96 tests passing ✅ +- Linting passed ✅ + +## To Apply These Fixes: +Option 1: Merge fix-pr-37-time-detection branch directly +Option 2: Close PR #37 and use this fixed branch instead diff --git a/README.md b/README.md index a4c58dd..ac51cc4 100644 --- a/README.md +++ b/README.md @@ -58,7 +58,7 @@ Zero-dependency package for automatic data type detection from strings, arrays, - **Zero Dependencies**: Completely standalone, no external packages - **TypeScript Support**: Full type definitions included - **45+ Date Formats**: Comprehensive date parsing including month names and timezones -- **Battle-Tested**: 85+ comprehensive test cases +- **Battle-Tested**: 96+ comprehensive test cases ## Installation @@ -119,7 +119,7 @@ const actual = infer(importedData); | `date` | `2023-12-31`, `31/12/2023` | | `ip` | `192.168.1.1`, `2001:0db8::1` | | `macaddress` | `00:1B:63:84:45:E6`, `00-1B-63-84-45-E6` | -| `color` | `#FF0000`, `#fff` | +| `color` | `#FF0000`, `#fff`, `rgb(255, 0, 0)`, `rgba(0, 255, 0, 0.5)`| | `percentage` | `50%`, `-25%` | | `currency` | `$100`, `€50.99` | | `hashtag` | `#hello`, `#OpenSource`, `#dev_community` | diff --git a/index.d.ts b/index.d.ts index e8e6212..dd3f0ce 100644 --- a/index.d.ts +++ b/index.d.ts @@ -5,9 +5,9 @@ /** * Supported data types that can be predicted */ -declare type DataType = +declare type DataType = | 'string' - | 'number' + | 'number' | 'boolean' | 'email' | 'phone' diff --git a/index.js b/index.js index 3bdbb32..91f794f 100644 --- a/index.js +++ b/index.js @@ -53,6 +53,7 @@ const PATTERNS = { MAC_ADDRESS: /^(?:[0-9a-fA-F]{2}[:-]){5}[0-9a-fA-F]{2}$/, HASHTAG: /^#[A-Za-z][A-Za-z0-9_]*$/, EMOJI: /^\p{Extended_Pictographic}(?:\uFE0F|\u200D\p{Extended_Pictographic})*$/u, + RGB_COLOR: /^rgba?\(\s*(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\s*,\s*(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\s*,\s*(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\s*(?:,\s*(?:0|1|0?\.\d+)\s*)?\)$/, SEMANTIC_VERSION: /^(0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)(?:-((?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*)(?:\.(?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*))*))?(?:\+([0-9a-zA-Z-]+(?:\.[0-9a-zA-Z-]+)*))?$/, TIME: /^(?:[01]?\d|2[0-3]):[0-5]\d(?::[0-5]\d)?(?:\s?[APap][Mm])?$/ }; @@ -714,7 +715,9 @@ function isMACAddress(value) { function isHexColor(value) { return PATTERNS.HEX_COLOR.test(value); } - +function isRgbColor(value) { + return PATTERNS.RGB_COLOR.test(value); +} /** * Checks if a given value is a percentage * @param {string} value - The value to check @@ -1022,7 +1025,7 @@ function detectFieldType(value, options = {}) { } else if (options.preferHashtagOver3CharHex && trimmedValue.length === 4 && isHashtag(trimmedValue, options)) { // When preferring hashtags, check 3-char values as hashtags first return 'hashtag'; - } else if (isHexColor(trimmedValue)) { + } else if (isHexColor(trimmedValue) || isRgbColor(trimmedValue)) { return 'color'; } else if (isHashtag(trimmedValue, options)) { return 'hashtag'; diff --git a/test/index.spec.js b/test/index.spec.js index a77be2e..2f2dc1d 100644 --- a/test/index.spec.js +++ b/test/index.spec.js @@ -26,7 +26,6 @@ describe('DataTypes constants', () => { expect(DataTypes.HASHTAG).to.equal('hashtag'); expect(DataTypes.FILEPATH).to.equal('filepath'); expect(DataTypes.SEMVER).to.equal('semver'); - expect(DataTypes.SEMVER).to.equal('semver'); expect(DataTypes.TIME).to.equal('time'); }); }); @@ -490,19 +489,38 @@ describe('predictDataTypes', () => { '#ffffff': 'color' }); }); - it('should not detect invalid hex colors', () => { - const text = '#GGGGGG, FF0000, #12345, #12'; + const text = '#GGGGGG, #ZZZ, #12345, #'; const types = predictDataTypes(text); expect(types).to.deep.equal({ '#GGGGGG': 'string', - 'FF0000': 'string', + '#ZZZ': 'string', '#12345': 'string', - '#12': 'string' + '#': 'string' }); }); }); + describe('RGB color detection', () => { + const { infer } = predictDataTypes; + + it('should detect valid RGB and RGBA colors', () => { + expect(infer('rgb(255, 0, 0)')).to.equal('color'); + expect(infer('rgba(0, 255, 0, 0.5)')).to.equal('color'); + expect(infer('rgb(128,128,128)')).to.equal('color'); + expect(infer('rgba(255,255,255,1)')).to.equal('color'); + }); + it('should handle variations in spacing', () => { + expect(infer('rgb( 255 , 0 , 0 )')).to.equal('color'); + expect(infer('rgba( 0, 0, 0, 0 )')).to.equal('color'); + }); + + it('should reject out-of-range or malformed RGB strings', () => { + expect(infer('rgb(300, 0, 0)')).to.equal('string'); + expect(infer('rgba(255, 0, 0, 2)')).to.equal('string'); + expect(infer('rgb(255, 0)')).to.equal('string'); + }); + }); describe('Percentage detection', () => { it('should detect valid percentages', () => { const text = '50%, 100%, 0.5%, -25%';