@jeongpd/korean-kinship 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
@@ -3,6 +3,7 @@
3
3
  **Resolve any Korean family-relationship path to its correct kinship term, reverse
4
4
  term, and 촌수 (degree of kinship) — including in-laws and 사돈.**
5
5
 
6
+ [![CI](https://github.com/tiger-dreams/korean-kinship/actions/workflows/ci.yml/badge.svg)](https://github.com/tiger-dreams/korean-kinship/actions/workflows/ci.yml)
6
7
  [![npm version](https://img.shields.io/npm/v/@jeongpd/korean-kinship.svg)](https://www.npmjs.com/package/@jeongpd/korean-kinship)
7
8
  [![license](https://img.shields.io/npm/l/@jeongpd/korean-kinship.svg)](https://github.com/tiger-dreams/korean-kinship/blob/main/LICENSE)
8
9
  [![node](https://img.shields.io/node/v/@jeongpd/korean-kinship.svg)](https://www.npmjs.com/package/@jeongpd/korean-kinship)
@@ -71,6 +72,36 @@ Chain them to describe any relative — `['mother', 'olderSis', 'spouse']` is "
71
72
  `opts.selfGender` (`'M'` or `'F'`) disambiguates terms that depend on the speaker's own
72
73
  gender — e.g. your spouse is 아내 if you're male, 남편 if you're female.
73
74
 
75
+ ## Judging confidence: `source` and `note`
76
+
77
+ This library doesn't decide for you whether an answer is trustworthy enough to show
78
+ as-is — it tells you where the answer came from, and your app decides what to do with
79
+ that:
80
+
81
+ - **`source: 'golden'`** — an exact match against one of the 145 entries ported from a
82
+ real, shipping app and checked against real usage (see [Where this data comes
83
+ from](#where-this-data-comes-from)). This is the answer for the overwhelming
84
+ majority of relationships anyone will actually ask about.
85
+ - **`source: 'fallback-table'`** — a curated Tier-2 entry for a specific pattern beyond
86
+ the 145 (currently empty in v1; see [`src/data/fallback-terms.js`](./src/data/fallback-terms.js)).
87
+ - **`source: 'generic'`** — nothing in either table matched, so `resolve()` computed a
88
+ generic pattern (e.g. `"6촌 손자"`) from 촌수 and generation distance instead of
89
+ failing. It's a defensible answer, not a verified one — Korean doesn't have a
90
+ single dedicated term for every possible relationship past a certain distance.
91
+
92
+ `note`, where present, is the original entry's own usage context (e.g. `"큰아버지의
93
+ 아내"`) — not generated, and only ever present on `'golden'` results.
94
+
95
+ Whether to surface any of this to *your* end users — a "verified" badge, a footnote, or
96
+ nothing at all — is your call, not the library's:
97
+
98
+ ```js
99
+ const result = resolve(path, { selfGender });
100
+ const isVerified = result.source === 'golden';
101
+ // e.g.: render result.label normally either way, but only show a
102
+ // "✓ 검증된 호칭" badge when isVerified — your app, your judgment call.
103
+ ```
104
+
74
105
  ## Other exports
75
106
 
76
107
  Alongside `resolve`, the package exports the underlying data so you can drive your own
@@ -125,6 +156,24 @@ Korean family-tree app, validated against actual usage. See
125
156
  [`docs/DATA_PROVENANCE.md`](./docs/DATA_PROVENANCE.md) for details, or
126
157
  `scripts/import-golden-terms.mjs` for the exact extraction method.
127
158
 
159
+ ## Testing
160
+
161
+ `npm test` runs the full suite (`node --test`, no test framework dependency), covering:
162
+
163
+ - All 145 golden entries, both `selfGender` values, checked field-by-field
164
+ (`label`, `reverseLabel`, `formal`, `chon`) — not just a spot check.
165
+ - A dedicated sweep asserting no relation path ever resolves to an `undefined` or
166
+ empty label, across every golden path plus a broad set of fallback-path
167
+ combinations.
168
+ - The compositional chon-cutoff rule independently re-verified against all 45
169
+ spouse-containing golden entries.
170
+
171
+ CI (see badge above) runs this suite on every push, on Node 18 and 20 — the badge
172
+ reflects the actual current state of `main`, not a claim in this README. Separately,
173
+ `resolve(['father', 'youngerBro'])` was checked against a real, independently
174
+ maintained Android app's own verified data contract before this library was wired
175
+ into production use (see [`docs/DATA_PROVENANCE.md`](./docs/DATA_PROVENANCE.md)).
176
+
128
177
  ## Why not just a lookup table?
129
178
 
130
179
  For the ~145 most common relationships, it is exactly a lookup table — that's Tier 1,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@jeongpd/korean-kinship",
3
- "version": "0.1.0",
3
+ "version": "0.1.1",
4
4
  "description": "Resolve any Korean family-relationship path to its correct kinship term, reverse term, and 촌수 (degree of kinship) — including in-laws and 사돈.",
5
5
  "type": "module",
6
6
  "main": "./src/index.js",
@@ -51,16 +51,20 @@ function baseTerm(generationDelta, terminalGender) {
51
51
  /**
52
52
  * Last-resort label for a path with no Tier-1 or Tier-2 entry.
53
53
  *
54
- * `chon: 0` means "close family, no numeral" in this codebase's convention (the golden
55
- * entries with chon 0 — 장인어른, 며느리, 동서 — never carry a number), so the numeral
56
- * is omitted entirely rather than rendered as a nonsensical "0촌".
54
+ * `chon: 0` means "no numeral" in this codebase's convention (the golden entries with
55
+ * chon 0 — 장인어른, 며느리, 동서 — never carry a number), so the numeral is omitted
56
+ * entirely rather than rendered as a nonsensical "0촌". Note this does NOT mean the
57
+ * relation is necessarily close — the chon-cutoff rule in resolve.js also assigns
58
+ * chon: 0 to any relation reached past the first spouse hop, including genuinely
59
+ * distant ones (e.g. an uncle-by-marriage's own sibling's child) — so the label omits
60
+ * the numeral but must not claim closeness either.
57
61
  */
58
62
  export function genericFallback({ chon, generationDelta, relationClass, terminalGender }) {
59
63
  const base = baseTerm(generationDelta, terminalGender);
60
64
  const numeral = chon > 0 ? `${chon}촌 ` : '';
61
65
 
62
66
  if (relationClass === 'inlaw') {
63
- return chon > 0 ? `인척 ${numeral}${base}` : `가까운 인척 ${base}`;
67
+ return `인척 ${numeral}${base}`;
64
68
  }
65
69
  return `${numeral}${base}`;
66
70
  }