nl2time 0.1.0 → 0.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
@@ -73,11 +73,19 @@ Cultural/ambiguous semantics are explicit `TimeContext` knobs with CLDR-derived
73
73
  | Does "last 3 days" include today? | `partialPeriod: 'include' \| 'exclude'` | `include` |
74
74
  | "At 4" — am or pm? | — | both candidates, plausibility-ordered |
75
75
 
76
+ ## Install
77
+
78
+ [![npm](https://img.shields.io/npm/v/nl2time)](https://www.npmjs.com/package/nl2time)
79
+
80
+ ```
81
+ npm install nl2time
82
+ ```
83
+
76
84
  ## Status
77
85
 
78
- v0.1 — English parsing, en-* describe, core engine with a DST/edge-case battery. Recurrence (`every Tuesday`) is representable in the IR but resolves in v2.
86
+ v0.1 — English parsing, en-* describe, core engine with a DST/edge-case battery, holidays (fixed-date, nth-weekday, computed Easter), business-day spans. Recurrence (`every Tuesday`) is representable in the IR but resolves in v2.
79
87
 
80
- **Corpus** ([corpus/](corpus/), runner exported as `nl2time/corpus`): a bidirectional golden set with per-case license provenance — 41 hand-authored NL→time cases (all passing), a 65-case datetime→NL golden set (all passing; to our knowledge the first published eval set for humanized time generation), and 693 cases imported from Microsoft Recognizers-Text (MIT) of which 12.6% currently pass — the honest coverage baseline the parser climbs against (`npm run eval`, `npm run baselines`). See [corpus/ATTRIBUTIONS.md](corpus/ATTRIBUTIONS.md) and [docs/porting.md](docs/porting.md).
88
+ **Corpus** ([corpus/](corpus/), runner exported as `nl2time/corpus`): a bidirectional golden set with per-case license provenance — 41 hand-authored NL→time cases (100% passing), a 65-case datetime→NL golden set (100% passing; to our knowledge the first published eval set for humanized time generation), and 693 cases imported from Microsoft Recognizers-Text (MIT) of which **80.7% currently pass** — the coverage baseline the parser climbs against (`npm run eval`, `npm run baselines`; every previously-passing case is a CI regression gate). Most remaining failures are documented divergences from upstream idiosyncrasies rather than parser gaps. See [corpus/ATTRIBUTIONS.md](corpus/ATTRIBUTIONS.md) and [docs/porting.md](docs/porting.md).
81
89
 
82
90
  ## Development
83
91
 
package/dist/parse/en.js CHANGED
@@ -125,12 +125,17 @@ function yearAt(tokens, i) {
125
125
  ? t.value
126
126
  : undefined;
127
127
  }
128
- /** "in the morning" / "at night" / "tonight" lookahead. Returns period + consumed. */
129
- function readPeriodSuffix(tokens, i) {
128
+ /** "in the morning" / "at night" / "this morning" / "tonight" lookahead.
129
+ * Returns period + consumed. "this <period>" binds a preceding bare hour
130
+ * exactly like "in the <period>" ("8 this morning" → 8am): the period
131
+ * supplies the meridiem, and the reference day is the anchor either way.
132
+ * Deliberately NOT "last night": that also shifts the day, which a
133
+ * meridiem-only suffix can't express (#9). */
134
+ function readPeriodSuffix(tokens, i, allowThis = true) {
130
135
  let at = i;
131
136
  if (word(tokens[at]) === 'in' || word(tokens[at]) === 'at')
132
137
  at += 1;
133
- if (word(tokens[at]) === 'the')
138
+ if (word(tokens[at]) === 'the' || (allowThis && word(tokens[at]) === 'this'))
134
139
  at += 1;
135
140
  const w = word(tokens[at]);
136
141
  if (w === 'tonight')
@@ -143,6 +148,12 @@ function readPeriodSuffix(tokens, i) {
143
148
  function meridiemFor(period) {
144
149
  return period === 'morning' ? 'am' : 'pm';
145
150
  }
151
+ /** Words that license a following bare number as a clock time
152
+ * ("at 8 this morning", "by 5 this afternoon"). */
153
+ const TIME_PREPOSITIONS = new Set([
154
+ 'at', 'around', 'about', 'by', 'from', 'until', 'till', 'to',
155
+ 'before', 'after', 'since',
156
+ ]);
146
157
  // --- rules -----------------------------------------------------------------
147
158
  /** today / yesterday / tomorrow / tonight / day before yesterday / day after tomorrow */
148
159
  const ruleDeicticDay = (tokens, i) => {
@@ -2353,7 +2364,17 @@ const ruleClockTime = (tokens, i, ctx) => {
2353
2364
  if (after === "o'clock" || after === 'oclock') {
2354
2365
  return withPeriodSuffix({ hour: hn.value, meridiem: 'unknown' }, hn.consumed + 1);
2355
2366
  }
2356
- const ps = readPeriodSuffix(tokens, i + hn.consumed + mc);
2367
+ // A BARE number before "this <period>" is only a clock time when the
2368
+ // number isn't already bound by a preceding noun — "8 this morning"
2369
+ // is 8am, but in "building 4 this afternoon" the 4 is a building
2370
+ // number and the period keeps its range reading (Recognizers
2371
+ // rt-dtm-0523). Utterance start or a time-preposition before the
2372
+ // number licenses the binding; an arbitrary preceding word does not.
2373
+ // The in/at forms ("4 in the afternoon") are explicit enough to bind
2374
+ // regardless, as before.
2375
+ const prevWord = word(tokens[i - 1]);
2376
+ const allowThis = i === 0 || prevWord === undefined || TIME_PREPOSITIONS.has(prevWord);
2377
+ const ps = readPeriodSuffix(tokens, i + hn.consumed + mc, allowThis);
2357
2378
  if (ps) {
2358
2379
  const time = { hour: hn.value, meridiem: meridiemFor(ps.period) };
2359
2380
  if (minute !== undefined)
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "nl2time",
3
- "version": "0.1.0",
3
+ "version": "0.1.1",
4
4
  "description": "Bidirectional natural language ⇄ date/time: parse expressions like 'last week' into concrete intervals, and describe instants as '9pm last night' — deterministic core, optional LLM assist.",
5
5
  "license": "MIT",
6
6
  "type": "module",
@@ -19,6 +19,10 @@
19
19
  "type": "git",
20
20
  "url": "git+https://github.com/AndyFooBlah/nl2time.git"
21
21
  },
22
+ "homepage": "https://github.com/AndyFooBlah/nl2time#readme",
23
+ "bugs": {
24
+ "url": "https://github.com/AndyFooBlah/nl2time/issues"
25
+ },
22
26
  "scripts": {
23
27
  "build": "tsc -p tsconfig.build.json",
24
28
  "prepare": "npm run build",