Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
29 changes: 0 additions & 29 deletions .github/PULL_REQUEST_TEMPLATE/time-detection-fixes.md

This file was deleted.

25 changes: 25 additions & 0 deletions PR_37_FIXES.md
Original file line number Diff line number Diff line change
@@ -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
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down Expand Up @@ -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` |
Expand Down
4 changes: 2 additions & 2 deletions index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,9 @@
/**
* Supported data types that can be predicted
*/
declare type DataType =
declare type DataType =
| 'string'
| 'number'
| 'number'
| 'boolean'
| 'email'
| 'phone'
Expand Down
7 changes: 5 additions & 2 deletions index.js
Original file line number Diff line number Diff line change
Expand Up @@ -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])?$/
};
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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';
Expand Down
28 changes: 23 additions & 5 deletions test/index.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -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');
});
});
Expand Down Expand Up @@ -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%';
Expand Down