Em dashes (—) and en dashes (–) had spread across comments, docs, tests, and a few UI strings, reading as AI-generated boilerplate rather than house style. Replaced each with punctuation matching its context: colon for explanatory clauses, comma for asides, plain hyphen for numeric/legal ranges (e.g. "21-23§"), "to"/"till" for date ranges, parentheses for paired-dash asides. messages/en.json and messages/sv.json were fixed by hand together to keep sv/en in sync. Left untouched where the dash is the functional subject rather than decorative punctuation: date-range-parser.ts's separator regex, charset-repair.ts's CP1252 byte-mapping table (and its test), the SIE encoding mojibake docs, generic-csv.ts's minus-sign normalizer, the agent system-prompt files that already instruct against em dashes, and a golden iXBRL test fixture compared byte-for-byte. Also fixes two bugs surfaced along the way: an off-by-one in ApiKeysPanel's scope-label split (a leftover from an earlier partial pass), and a charset-repair test that had lost the literal en-dash it exists to verify. Regenerated the agent atom seed migration (skills:generate) since 27 SKILL.md files changed. Added a CLAUDE.md rule against em/en dashes, with an explicit carve-out for the functional-dash cases above. Co-authored-by: Claude Sonnet 5 <noreply@anthropic.com>
83 lines
2.3 KiB
TypeScript
83 lines
2.3 KiB
TypeScript
/**
|
|
* Typed access to the generated taxonomy concept registry.
|
|
*
|
|
* The registry JSON is generated from the official element lists by
|
|
* scripts/generate-taxonomy-registry.ts: never edit it by hand. CI guards
|
|
* staleness via `npm run taxonomy:check`.
|
|
*
|
|
* Taxonomy versions are data, not code: each version is its own generated
|
|
* file selected through lib/bokslut/ixbrl/taxonomy/entry-points.ts, so the
|
|
* September 2026 generation (dimensions instead of tuples) can ship as a new
|
|
* registry + emitter without touching the K2 2024-09-12 path.
|
|
*/
|
|
|
|
import k2Ab20240912 from './generated/k2-ab-2024-09-12.json'
|
|
|
|
export interface TaxonomyConcept {
|
|
/** Namespace prefix (e.g. "se-gen-base"); URI resolved per entry point. */
|
|
ns: string
|
|
/** Official Standardrubrik presentation label. */
|
|
label: string
|
|
abstract: boolean
|
|
dataType: string | null
|
|
balance: 'debit' | 'credit' | null
|
|
periodType: 'duration' | 'instant' | null
|
|
kind: 'item' | 'tuple'
|
|
sections: string[]
|
|
}
|
|
|
|
export interface TaxonomyTupleMember {
|
|
name: string
|
|
ns: string
|
|
required: boolean
|
|
}
|
|
|
|
export interface TaxonomyRegistry {
|
|
_meta: {
|
|
taxonomy: string
|
|
version: string
|
|
revision: string
|
|
conceptCount: number
|
|
tupleCount: number
|
|
}
|
|
concepts: Record<string, TaxonomyConcept>
|
|
tuples: Record<string, { ns: string; members: TaxonomyTupleMember[] }>
|
|
}
|
|
|
|
const REGISTRIES: Record<string, TaxonomyRegistry> = {
|
|
'k2-ab-2024-09-12': k2Ab20240912 as unknown as TaxonomyRegistry,
|
|
}
|
|
|
|
export function getRegistry(id: string): TaxonomyRegistry {
|
|
const registry = REGISTRIES[id]
|
|
if (!registry) {
|
|
throw new Error(
|
|
`Unknown taxonomy registry "${id}": known: ${Object.keys(REGISTRIES).join(', ')}`,
|
|
)
|
|
}
|
|
return registry
|
|
}
|
|
|
|
export function getConcept(
|
|
registry: TaxonomyRegistry,
|
|
name: string,
|
|
): TaxonomyConcept | null {
|
|
return registry.concepts[name] ?? null
|
|
}
|
|
|
|
/**
|
|
* Lookup that throws on unknown concepts. The document builder uses this for
|
|
* every fact it emits, so a typo'd element name fails generation instead of
|
|
* producing an instance Bolagsverket rejects with 4001/4008.
|
|
*/
|
|
export function mustGetConcept(
|
|
registry: TaxonomyRegistry,
|
|
name: string,
|
|
): TaxonomyConcept {
|
|
const concept = registry.concepts[name]
|
|
if (!concept) {
|
|
throw new Error(`Concept "${name}" not in taxonomy ${registry._meta.taxonomy} ${registry._meta.version}`)
|
|
}
|
|
return concept
|
|
}
|