[READ-ONLY] Mirror of https://github.com/sxzz/hanji. 一字之間,照見五地字形 hanji.sxzz.moe
chinese-characters cjk han hanja hanji hanzi kanji
Something went wrong. Try again.
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161import { readFileSync } from 'node:fs'import { join } from 'node:path'import { describe, expect, it } from 'vitest'import { DATA_DIR } from '../scripts/sources.ts'import { formsOf } from '../shared/links.ts'import { listingOptionsFor } from '../shared/listings.ts'import { overprintCommonGroups } from '../shared/overprint.ts'import { glyphSignature, projectSignature, signatureIndexOf, varietyOf,} from '../shared/row.ts'import { applyKoreanColumnDefault, COLUMNS, REGIONS, type CharRow, type CharsData, type Column, type Region,} from '../shared/types.ts'
const data: CharsData = JSON.parse( readFileSync(join(DATA_DIR, 'chars.json'), 'utf8'),)const rows = new Map(data.rows.map((row) => [row.key, row]))const row = (key: string): CharRow => { const found = rows.get(key) if (!found) throw new Error(`${key} is not listed`) return found}
/** Indices of the regions left when `hidden` are switched off. */const without = (...hidden: Region[]) => REGIONS.filter((region) => !hidden.includes(region)).map((region) => REGIONS.indexOf(region), )
const ALL_COLUMNS = [...REGIONS].map((region) => REGIONS.indexOf(region))
describe('overprint emphasis from common-region filters', () => { const columns: Column[] = ['cn', 'jp', 'hk', 'tw']
it('uses displayed group numbers when the region order changes', () => { expect(overprintCommonGroups(row('返'), columns, ['jp'])).toEqual( new Set([1]), ) })
it('keeps every selected form prominent and deduplicates shared forms', () => { expect(overprintCommonGroups(row('國'), columns, ['hk', 'tw'])).toEqual( new Set([1]), ) expect(overprintCommonGroups(row('國'), columns, ['cn', 'tw'])).toEqual( new Set([0, 1]), ) })
it('ignores hidden and unknown regions and clears emphasis with the filter', () => { for (const selected of [[], ['kr'], ['unknown']]) expect(overprintCommonGroups(row('返'), columns, selected)).toEqual( new Set(), ) expect( overprintCommonGroups(row('返'), ['jp', 'hk', 'tw'], ['jp']), ).toEqual(new Set([0])) })
it('does not promote an unlisted reference form in the hero', () => { const unlisted: CharRow = { ...row('返'), tier: [1, 1, 1, 0, 0] } expect(overprintCommonGroups(unlisted, columns, ['jp'])).toEqual(new Set()) })})
describe('locale-aware column defaults', () => { it('shows Korea for Korean while preserving every other hidden column', () => { expect(applyKoreanColumnDefault(['cn', 'kr'], true)).toEqual(['cn']) expect(applyKoreanColumnDefault(['cn'], false)).toEqual(['cn', 'kr']) })})
describe('reading a partition over the columns on show', () => { it('leaves a full row exactly as the data ships it', () => { for (const key of ['返', '骨', '海', '的']) expect(projectSignature(row(key).glyph, ALL_COLUMNS)).toBe(row(key).glyph) })
it('renumbers from the first column still on show', () => { // 骨 runs CN | HK | TW | HK | HK. Drop the mainland and HK leads. expect(projectSignature(row('骨').glyph, without('cn'))).toBe('0100') expect(varietyOf(projectSignature(row('骨').glyph, without('cn')))).toBe(2) })
it('merges regions that only ever differed through a hidden column', () => { // In the original four columns 海 differs only in Japan; Korea is also // different, but is hidden by default. expect(row('海').glyph).toBe('00012') expect(projectSignature(row('海').glyph, without('jp', 'kr'))).toBe('000') })
it('keeps a genuine disagreement when an unrelated column goes', () => { expect(projectSignature(row('返').glyph, without('jp', 'kr'))).toBe('012') })
it('compares the kyujitai on the same numbering as the regions', () => { // 國: the mainland and Japan write 国, Hong Kong and Taiwan write 國 -- // and so does the Japanese old form. expect(glyphSignature(row('國'))).toBe('011011') const columns = (...keep: Column[]) => keep.map(signatureIndexOf) expect( projectSignature(glyphSignature(row('國')), columns('hk', 'tw', 'old')), ).toBe('000') expect( projectSignature(glyphSignature(row('國')), columns('cn', 'old')), ).toBe('01') })
it('has nothing to say about a row with no old form', () => { expect(glyphSignature(row('返'))).toBe(row('返').glyph) })})
describe('controls that belong to a hidden column', () => { it('offers every listing choice while every column is on show', () => { expect(listingOptionsFor([...COLUMNS])).toHaveLength(10) })
it('drops the levels of a region that is off the page', () => { const ids = listingOptionsFor(['cn', 'hk', 'tw', 'old']).map((o) => o.id) expect(ids).not.toContain('jp1') expect(ids).not.toContain('jp2') // The old forms are a column of their own and stay on their own terms. expect(ids).toContain('old') })
it('drops the old-form choice with the old-form column', () => { expect(listingOptionsFor([...REGIONS]).map((o) => o.id)).not.toContain( 'old', ) })
it('does not offer the Korean list while its default-hidden column is off', () => { expect( listingOptionsFor(['cn', 'hk', 'tw', 'jp', 'old']).map((o) => o.id), ).not.toContain('kr1') })})
describe('outside references follow the columns on show', () => { it('lists every form by default', () => { expect(formsOf(row('國')).map((form) => form.char)).toContain('国') })
it('leaves out a form only a hidden region writes', () => { expect( formsOf(row('國'), ['hk', 'tw']).map((form) => form.char), ).not.toContain('国') })})