@fhss-web-team/fuzzy-dates 1.0.0 → 1.1.1

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 CHANGED
@@ -1,8 +1,11 @@
1
- # CFHG Fuzzy Dates
1
+ # Fuzzy Dates
2
2
 
3
3
  Parse imprecise, human-entered date strings into a structured, consistent model that you can normalize, search, sort, and serialize.
4
4
 
5
+ Explore the docs
6
+
5
7
  ## Features
8
+
6
9
  - Handles modifiers like `before`, `after`, `about`, `between`, `from`, `early`, `mid`, `late`.
7
10
  - Normalizes many input shapes (`1st of February 1900`, `Feb 1 1900`, `winter 1890`, `1800s`).
8
11
  - Produces inclusive lower/upper bounds for range filtering and a collation key for stable chronological sorting.
@@ -10,21 +13,23 @@ Parse imprecise, human-entered date strings into a structured, consistent model
10
13
  - ESM + TypeScript ready (`.d.ts` shipped with the package).
11
14
 
12
15
  ## Installation
16
+
13
17
  ```bash
14
- npm install cfhg-fuzzy-dates
18
+ npm i @fhss-web-team/fuzzy-dates
15
19
  ```
16
20
 
17
21
  ## Quick start
22
+
18
23
  ```ts
19
- import { FuzzyDate } from 'cfhg-fuzzy-dates';
24
+ import { FuzzyDate } from "@fhss-web-team/fuzzy-dates";
20
25
 
21
- const parsed = FuzzyDate.parse('about Feb 1900');
26
+ const parsed = FuzzyDate.parse("about Feb 1900");
22
27
  if (!parsed.ok) throw parsed.error;
23
28
 
24
29
  const date = parsed.value;
25
- console.log(date.normalized); // "about 1 February 1900"
26
- console.log(date.lowerBound); // 1899-02-01T00:00:00.000Z (Date)
27
- console.log(date.upperBound); // 1901-01-31T23:59:59.999Z (Date)
30
+ console.log(date.normalized); // "about 1 February 1900"
31
+ console.log(date.lowerBound); // 1899-02-01T00:00:00.000Z (Date)
32
+ console.log(date.upperBound); // 1901-01-31T23:59:59.999Z (Date)
28
33
  console.log(date.collationKey); // deterministic string for sorting
29
34
 
30
35
  // Serialize for storage and hydrate later
@@ -33,10 +38,10 @@ const hydrated = FuzzyDate.fromJSON(json);
33
38
  ```
34
39
 
35
40
  ## API snapshot
41
+
36
42
  - `FuzzyDate.parse(input: string): Result<FuzzyDate, string>` — non-throwing parse; errors come back as `{ ok: false, error }`.
37
43
  - `FuzzyDate.fromJSON(model: FuzzyDateModel)` — rebuild from the canonical JSON model.
38
44
  - `FuzzyDate` instance properties:
39
- - `original` — original input string.
40
45
  - `normalized` — normalized human-readable string.
41
46
  - `lowerBound` / `upperBound` — inclusive Date bounds (or `null` for unbounded).
42
47
  - `collationKey` — sortable string aligned to chronological order.
@@ -44,9 +49,16 @@ const hydrated = FuzzyDate.fromJSON(json);
44
49
  - `toJSON()` — returns the canonical model.
45
50
 
46
51
  ## Development
52
+
47
53
  - Tests: `npm test` (Vitest)
48
54
  - Build: `npm run build` (TypeScript -> `dist/`)
49
55
  - Pack locally (publish dry-run): `npm pack` then install the generated `.tgz` in a temp project to verify exports and typings.
50
56
 
57
+ ## Support
58
+
59
+ This package was developed by the [BYU's Center for Family History and Genealogy](https://cfhg.byu.edu/). To support
60
+ our mission to provide quality online family history research and resources for the public at no cost, consider donating [HERE](https://donate.churchofjesuschrist.org/contribute/byu/family-home-social-sciences/center-family-history-genealogy)
61
+
51
62
  ## License
63
+
52
64
  MIT © FHSS Web Team
@@ -51,12 +51,6 @@ export declare class FuzzyDate {
51
51
  * Consumers must use {@link FuzzyDate.parse} or {@link FuzzyDate.fromJSON}.
52
52
  */
53
53
  private constructor();
54
- /**
55
- * The original human-readable input string used to construct this fuzzy date.
56
- *
57
- * This value is preserved verbatim and is not normalized or modified.
58
- */
59
- get original(): string;
60
54
  /**
61
55
  * GEDCOM X formal date representation of this fuzzy date.
62
56
  *
@@ -57,14 +57,6 @@ export class FuzzyDate {
57
57
  constructor(model) {
58
58
  this._model = model;
59
59
  }
60
- /**
61
- * The original human-readable input string used to construct this fuzzy date.
62
- *
63
- * This value is preserved verbatim and is not normalized or modified.
64
- */
65
- get original() {
66
- return this._model.original;
67
- }
68
60
  /**
69
61
  * GEDCOM X formal date representation of this fuzzy date.
70
62
  *
@@ -11,7 +11,6 @@ export declare function parse(input: string): {
11
11
  } | {
12
12
  ok: true;
13
13
  value: {
14
- readonly original: string;
15
14
  readonly modifier: "NONE";
16
15
  readonly start: {
17
16
  readonly format: "YYYYs" | "YYYY" | "SEASON_YYYY" | "MMMM_YYYY" | "D_MMMM_YYYY";
@@ -27,7 +26,6 @@ export declare function parse(input: string): {
27
26
  } | {
28
27
  ok: true;
29
28
  value: {
30
- readonly original: string;
31
29
  readonly modifier: "BEFORE";
32
30
  readonly start: {
33
31
  readonly format: "YYYYs" | "YYYY" | "SEASON_YYYY" | "MMMM_YYYY" | "D_MMMM_YYYY";
@@ -43,7 +41,6 @@ export declare function parse(input: string): {
43
41
  } | {
44
42
  ok: true;
45
43
  value: {
46
- readonly original: string;
47
44
  readonly modifier: "AFTER";
48
45
  readonly start: {
49
46
  readonly format: "YYYYs" | "YYYY" | "SEASON_YYYY" | "MMMM_YYYY" | "D_MMMM_YYYY";
@@ -59,7 +56,6 @@ export declare function parse(input: string): {
59
56
  } | {
60
57
  ok: true;
61
58
  value: {
62
- readonly original: string;
63
59
  readonly modifier: "ABOUT";
64
60
  readonly start: {
65
61
  readonly format: "YYYYs" | "YYYY" | "SEASON_YYYY" | "MMMM_YYYY" | "D_MMMM_YYYY";
@@ -78,7 +74,6 @@ export declare function parse(input: string): {
78
74
  } | {
79
75
  ok: true;
80
76
  value: {
81
- readonly original: string;
82
77
  readonly modifier: "BETWEEN";
83
78
  readonly start: {
84
79
  readonly format: "YYYYs" | "YYYY" | "SEASON_YYYY" | "MMMM_YYYY" | "D_MMMM_YYYY";
@@ -97,7 +92,6 @@ export declare function parse(input: string): {
97
92
  } | {
98
93
  ok: true;
99
94
  value: {
100
- readonly original: string;
101
95
  readonly modifier: "FROM";
102
96
  readonly start: {
103
97
  readonly format: "YYYYs" | "YYYY" | "SEASON_YYYY" | "MMMM_YYYY" | "D_MMMM_YYYY";
@@ -113,7 +107,6 @@ export declare function parse(input: string): {
113
107
  } | {
114
108
  ok: true;
115
109
  value: {
116
- readonly original: string;
117
110
  readonly modifier: "EARLY";
118
111
  readonly start: {
119
112
  readonly format: "YYYYs" | "YYYY" | "SEASON_YYYY" | "MMMM_YYYY" | "D_MMMM_YYYY";
@@ -129,7 +122,6 @@ export declare function parse(input: string): {
129
122
  } | {
130
123
  ok: true;
131
124
  value: {
132
- readonly original: string;
133
125
  readonly modifier: "MID";
134
126
  readonly start: {
135
127
  readonly format: "YYYYs" | "YYYY" | "SEASON_YYYY" | "MMMM_YYYY" | "D_MMMM_YYYY";
@@ -145,7 +137,6 @@ export declare function parse(input: string): {
145
137
  } | {
146
138
  ok: true;
147
139
  value: {
148
- readonly original: string;
149
140
  readonly modifier: "LATE";
150
141
  readonly start: {
151
142
  readonly format: "YYYYs" | "YYYY" | "SEASON_YYYY" | "MMMM_YYYY" | "D_MMMM_YYYY";
@@ -9,22 +9,22 @@ export function parse(input) {
9
9
  .replace(/\s+/g, ' ') // collapses multiple spaces to a single space
10
10
  .trim(); // Removes trailing and leading spaces
11
11
  if (cleanedInput.startsWith('before '))
12
- return before(cleanedInput, input);
12
+ return before(cleanedInput);
13
13
  if (cleanedInput.startsWith('after '))
14
- return after(cleanedInput, input);
14
+ return after(cleanedInput);
15
15
  if (cleanedInput.startsWith('about '))
16
- return about(cleanedInput, input);
16
+ return about(cleanedInput);
17
17
  if (cleanedInput.startsWith('between '))
18
- return between(cleanedInput, input);
18
+ return between(cleanedInput);
19
19
  if (cleanedInput.startsWith('from '))
20
- return from(cleanedInput, input);
20
+ return from(cleanedInput);
21
21
  if (cleanedInput.startsWith('early '))
22
- return early(cleanedInput, input);
22
+ return early(cleanedInput);
23
23
  if (cleanedInput.startsWith('mid '))
24
- return mid(cleanedInput, input);
24
+ return mid(cleanedInput);
25
25
  if (cleanedInput.startsWith('late '))
26
- return late(cleanedInput, input);
27
- return none(cleanedInput, input);
26
+ return late(cleanedInput);
27
+ return none(cleanedInput);
28
28
  }
29
29
  // Helpers
30
30
  export function getTimes(date) {
@@ -1,4 +1,4 @@
1
- export declare const none: (cleanedInput: string, rawInput: string) => {
1
+ export declare const none: (cleanedInput: string) => {
2
2
  ok: false;
3
3
  error: "Year is required.";
4
4
  } | {
@@ -10,7 +10,6 @@ export declare const none: (cleanedInput: string, rawInput: string) => {
10
10
  } | {
11
11
  ok: true;
12
12
  value: {
13
- readonly original: string;
14
13
  readonly modifier: "NONE";
15
14
  readonly start: {
16
15
  readonly format: "YYYYs" | "YYYY" | "SEASON_YYYY" | "MMMM_YYYY" | "D_MMMM_YYYY";
@@ -24,7 +23,7 @@ export declare const none: (cleanedInput: string, rawInput: string) => {
24
23
  };
25
24
  };
26
25
  };
27
- export declare const before: (cleanedInput: string, rawInput: string) => {
26
+ export declare const before: (cleanedInput: string) => {
28
27
  ok: false;
29
28
  error: "Year is required.";
30
29
  } | {
@@ -36,7 +35,6 @@ export declare const before: (cleanedInput: string, rawInput: string) => {
36
35
  } | {
37
36
  ok: true;
38
37
  value: {
39
- readonly original: string;
40
38
  readonly modifier: "BEFORE";
41
39
  readonly start: {
42
40
  readonly format: "YYYYs" | "YYYY" | "SEASON_YYYY" | "MMMM_YYYY" | "D_MMMM_YYYY";
@@ -50,7 +48,7 @@ export declare const before: (cleanedInput: string, rawInput: string) => {
50
48
  };
51
49
  };
52
50
  };
53
- export declare const after: (cleanedInput: string, rawInput: string) => {
51
+ export declare const after: (cleanedInput: string) => {
54
52
  ok: false;
55
53
  error: "Year is required.";
56
54
  } | {
@@ -62,7 +60,6 @@ export declare const after: (cleanedInput: string, rawInput: string) => {
62
60
  } | {
63
61
  ok: true;
64
62
  value: {
65
- readonly original: string;
66
63
  readonly modifier: "AFTER";
67
64
  readonly start: {
68
65
  readonly format: "YYYYs" | "YYYY" | "SEASON_YYYY" | "MMMM_YYYY" | "D_MMMM_YYYY";
@@ -76,7 +73,7 @@ export declare const after: (cleanedInput: string, rawInput: string) => {
76
73
  };
77
74
  };
78
75
  };
79
- export declare const about: (cleanedInput: string, rawInput: string) => {
76
+ export declare const about: (cleanedInput: string) => {
80
77
  ok: false;
81
78
  error: "Year is required.";
82
79
  } | {
@@ -88,7 +85,6 @@ export declare const about: (cleanedInput: string, rawInput: string) => {
88
85
  } | {
89
86
  ok: true;
90
87
  value: {
91
- readonly original: string;
92
88
  readonly modifier: "ABOUT";
93
89
  readonly start: {
94
90
  readonly format: "YYYYs" | "YYYY" | "SEASON_YYYY" | "MMMM_YYYY" | "D_MMMM_YYYY";
@@ -102,7 +98,7 @@ export declare const about: (cleanedInput: string, rawInput: string) => {
102
98
  };
103
99
  };
104
100
  };
105
- export declare const between: (cleanedInput: string, rawInput: string) => {
101
+ export declare const between: (cleanedInput: string) => {
106
102
  ok: false;
107
103
  error: "Year is required.";
108
104
  } | {
@@ -117,7 +113,6 @@ export declare const between: (cleanedInput: string, rawInput: string) => {
117
113
  } | {
118
114
  ok: true;
119
115
  value: {
120
- readonly original: string;
121
116
  readonly modifier: "BETWEEN";
122
117
  readonly start: {
123
118
  readonly format: "YYYYs" | "YYYY" | "SEASON_YYYY" | "MMMM_YYYY" | "D_MMMM_YYYY";
@@ -131,7 +126,7 @@ export declare const between: (cleanedInput: string, rawInput: string) => {
131
126
  };
132
127
  };
133
128
  };
134
- export declare const from: (cleanedInput: string, rawInput: string) => {
129
+ export declare const from: (cleanedInput: string) => {
135
130
  ok: false;
136
131
  error: "Year is required.";
137
132
  } | {
@@ -146,7 +141,6 @@ export declare const from: (cleanedInput: string, rawInput: string) => {
146
141
  } | {
147
142
  ok: true;
148
143
  value: {
149
- readonly original: string;
150
144
  readonly modifier: "FROM";
151
145
  readonly start: {
152
146
  readonly format: "YYYYs" | "YYYY" | "SEASON_YYYY" | "MMMM_YYYY" | "D_MMMM_YYYY";
@@ -160,7 +154,7 @@ export declare const from: (cleanedInput: string, rawInput: string) => {
160
154
  };
161
155
  };
162
156
  };
163
- export declare const early: (cleanedInput: string, rawInput: string) => {
157
+ export declare const early: (cleanedInput: string) => {
164
158
  ok: false;
165
159
  error: "Year is required.";
166
160
  } | {
@@ -172,7 +166,6 @@ export declare const early: (cleanedInput: string, rawInput: string) => {
172
166
  } | {
173
167
  ok: true;
174
168
  value: {
175
- readonly original: string;
176
169
  readonly modifier: "EARLY";
177
170
  readonly start: {
178
171
  readonly format: "YYYYs" | "YYYY" | "SEASON_YYYY" | "MMMM_YYYY" | "D_MMMM_YYYY";
@@ -186,7 +179,7 @@ export declare const early: (cleanedInput: string, rawInput: string) => {
186
179
  };
187
180
  };
188
181
  };
189
- export declare const mid: (cleanedInput: string, rawInput: string) => {
182
+ export declare const mid: (cleanedInput: string) => {
190
183
  ok: false;
191
184
  error: "Year is required.";
192
185
  } | {
@@ -198,7 +191,6 @@ export declare const mid: (cleanedInput: string, rawInput: string) => {
198
191
  } | {
199
192
  ok: true;
200
193
  value: {
201
- readonly original: string;
202
194
  readonly modifier: "MID";
203
195
  readonly start: {
204
196
  readonly format: "YYYYs" | "YYYY" | "SEASON_YYYY" | "MMMM_YYYY" | "D_MMMM_YYYY";
@@ -212,7 +204,7 @@ export declare const mid: (cleanedInput: string, rawInput: string) => {
212
204
  };
213
205
  };
214
206
  };
215
- export declare const late: (cleanedInput: string, rawInput: string) => {
207
+ export declare const late: (cleanedInput: string) => {
216
208
  ok: false;
217
209
  error: "Year is required.";
218
210
  } | {
@@ -224,7 +216,6 @@ export declare const late: (cleanedInput: string, rawInput: string) => {
224
216
  } | {
225
217
  ok: true;
226
218
  value: {
227
- readonly original: string;
228
219
  readonly modifier: "LATE";
229
220
  readonly start: {
230
221
  readonly format: "YYYYs" | "YYYY" | "SEASON_YYYY" | "MMMM_YYYY" | "D_MMMM_YYYY";
@@ -1,13 +1,12 @@
1
1
  import { getTimes } from '.';
2
2
  import { ok, err, DATE_NEG_INFINITY, DATE_POS_INFINITY } from '../types';
3
3
  import { stringToDate } from './stringToDate';
4
- export const none = (cleanedInput, rawInput) => {
4
+ export const none = (cleanedInput) => {
5
5
  const result = stringToDate(cleanedInput);
6
6
  if (!result.ok)
7
7
  return result;
8
8
  const date = result.value;
9
9
  return ok({
10
- original: rawInput,
11
10
  modifier: 'NONE',
12
11
  start: {
13
12
  format: date.format,
@@ -21,13 +20,12 @@ export const none = (cleanedInput, rawInput) => {
21
20
  },
22
21
  });
23
22
  };
24
- export const before = (cleanedInput, rawInput) => {
23
+ export const before = (cleanedInput) => {
25
24
  const result = stringToDate(cleanedInput.slice('before '.length));
26
25
  if (!result.ok)
27
26
  return result;
28
27
  const date = result.value;
29
28
  return ok({
30
- original: rawInput,
31
29
  modifier: 'BEFORE',
32
30
  start: {
33
31
  format: date.format,
@@ -41,13 +39,12 @@ export const before = (cleanedInput, rawInput) => {
41
39
  },
42
40
  });
43
41
  };
44
- export const after = (cleanedInput, rawInput) => {
42
+ export const after = (cleanedInput) => {
45
43
  const result = stringToDate(cleanedInput.slice('after '.length));
46
44
  if (!result.ok)
47
45
  return result;
48
46
  const date = result.value;
49
47
  return ok({
50
- original: rawInput,
51
48
  modifier: 'AFTER',
52
49
  start: {
53
50
  format: date.format,
@@ -61,13 +58,12 @@ export const after = (cleanedInput, rawInput) => {
61
58
  },
62
59
  });
63
60
  };
64
- export const about = (cleanedInput, rawInput) => {
61
+ export const about = (cleanedInput) => {
65
62
  const result = stringToDate(cleanedInput.slice('about '.length));
66
63
  if (!result.ok)
67
64
  return result;
68
65
  const date = result.value;
69
66
  return ok({
70
- original: rawInput,
71
67
  modifier: 'ABOUT',
72
68
  start: {
73
69
  format: date.format,
@@ -81,7 +77,7 @@ export const about = (cleanedInput, rawInput) => {
81
77
  },
82
78
  });
83
79
  };
84
- export const between = (cleanedInput, rawInput) => {
80
+ export const between = (cleanedInput) => {
85
81
  const dates = cleanedInput.slice('between '.length).split(' and ');
86
82
  if (dates.length !== 2)
87
83
  return err('Invalid "BETWEEN" modifier.');
@@ -94,7 +90,6 @@ export const between = (cleanedInput, rawInput) => {
94
90
  const start = startResult.value;
95
91
  const end = endDateResult.value;
96
92
  return ok({
97
- original: rawInput,
98
93
  modifier: 'BETWEEN',
99
94
  start: {
100
95
  format: start.format,
@@ -104,7 +99,7 @@ export const between = (cleanedInput, rawInput) => {
104
99
  end: { format: end.format, minDate: end.minDate, maxDate: end.maxDate },
105
100
  });
106
101
  };
107
- export const from = (cleanedInput, rawInput) => {
102
+ export const from = (cleanedInput) => {
108
103
  const dates = cleanedInput.slice('from '.length).split(' to ');
109
104
  if (dates.length !== 2)
110
105
  return err('Invalid "FROM" modifier.');
@@ -117,7 +112,6 @@ export const from = (cleanedInput, rawInput) => {
117
112
  const start = startResult.value;
118
113
  const end = endDateResult.value;
119
114
  return ok({
120
- original: rawInput,
121
115
  modifier: 'FROM',
122
116
  start: {
123
117
  format: start.format,
@@ -127,14 +121,13 @@ export const from = (cleanedInput, rawInput) => {
127
121
  end: { format: end.format, minDate: end.minDate, maxDate: end.maxDate },
128
122
  });
129
123
  };
130
- export const early = (cleanedInput, rawInput) => {
124
+ export const early = (cleanedInput) => {
131
125
  const result = stringToDate(cleanedInput.slice('early '.length));
132
126
  if (!result.ok)
133
127
  return result;
134
128
  const date = result.value;
135
129
  const { start, half } = getTimes(date);
136
130
  return ok({
137
- original: rawInput,
138
131
  modifier: 'EARLY',
139
132
  start: {
140
133
  format: date.format,
@@ -148,7 +141,7 @@ export const early = (cleanedInput, rawInput) => {
148
141
  },
149
142
  });
150
143
  };
151
- export const mid = (cleanedInput, rawInput) => {
144
+ export const mid = (cleanedInput) => {
152
145
  const result = stringToDate(cleanedInput.slice('mid '.length));
153
146
  if (!result.ok)
154
147
  return result;
@@ -156,7 +149,6 @@ export const mid = (cleanedInput, rawInput) => {
156
149
  console.log(date);
157
150
  const { start, half } = getTimes(date);
158
151
  return ok({
159
- original: rawInput,
160
152
  modifier: 'MID',
161
153
  start: {
162
154
  format: date.format,
@@ -170,14 +162,13 @@ export const mid = (cleanedInput, rawInput) => {
170
162
  },
171
163
  });
172
164
  };
173
- export const late = (cleanedInput, rawInput) => {
165
+ export const late = (cleanedInput) => {
174
166
  const result = stringToDate(cleanedInput.slice('late '.length));
175
167
  if (!result.ok)
176
168
  return result;
177
169
  const date = result.value;
178
170
  const { start, half } = getTimes(date);
179
171
  return ok({
180
- original: rawInput,
181
172
  modifier: 'LATE',
182
173
  start: {
183
174
  format: date.format,
@@ -21,7 +21,6 @@ export type FuzzyDateValue = {
21
21
  maxDate: Date;
22
22
  };
23
23
  export type FuzzyDateModel = {
24
- original: string;
25
24
  modifier: FuzzyDateModifier;
26
25
  start: FuzzyDateValue;
27
26
  end: FuzzyDateValue;
package/dist/index.d.ts CHANGED
@@ -1 +1,2 @@
1
1
  export { FuzzyDate } from './fuzzyDate/fuzzyDate';
2
+ export { FuzzyDateModel } from './fuzzyDate/types';
package/package.json CHANGED
@@ -1,14 +1,14 @@
1
1
  {
2
2
  "name": "@fhss-web-team/fuzzy-dates",
3
- "version": "1.0.0",
3
+ "version": "1.1.1",
4
4
  "description": "Parses imprecise date strings into a structured form that can be normalized, indexed, searched, and ordered while preserving the original input.",
5
- "homepage": "https://github.com/FHSS-Web-Team/CFHG-fuzzy-dates#readme",
5
+ "homepage": "https://github.com/FHSS-Web-Team/fuzzy-dates#readme",
6
6
  "bugs": {
7
- "url": "https://github.com/FHSS-Web-Team/CFHG-fuzzy-dates/issues"
7
+ "url": "https://github.com/FHSS-Web-Team/fuzzy-dates/issues"
8
8
  },
9
9
  "repository": {
10
10
  "type": "git",
11
- "url": "git+https://github.com/FHSS-Web-Team/CFHG-fuzzy-dates.git"
11
+ "url": "git+https://github.com/FHSS-Web-Team/fuzzy-dates.git"
12
12
  },
13
13
  "main": "./dist/index.js",
14
14
  "module": "./dist/index.js",