@sushichan044/kg-core 0.6.5 → 0.8.0

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
@@ -13,23 +13,38 @@ or DOM behavior.
13
13
  pnpm add @sushichan044/kg-core
14
14
  ```
15
15
 
16
+ ## Entry points
17
+
18
+ The package is split by what you are doing, so an application only ever sees the
19
+ surface it needs.
20
+
21
+ | Entry | For |
22
+ | ------------------------------ | ----------------------------------------------------------------------------------------------- |
23
+ | `@sushichan044/kg-core` | Running the pipeline and reading what comes out: parse, compose, settings, results, diagnostics |
24
+ | `@sushichan044/kg-core/lint` | Proofreading — running the rules, and writing your own |
25
+ | `@sushichan044/kg-core/plugin` | Supplying an implementation to core: a parser, a composer, or a measurer |
26
+
27
+ A name is exported only when one of those three needs to write it. Helpers core
28
+ keeps for itself are not part of the API.
29
+
16
30
  ## Processing pipeline
17
31
 
18
32
  ```ts
19
33
  import {
20
34
  ComposeError,
21
35
  composeManuscript,
22
- createNovelComposer,
23
- createDefaultProofreadingRules,
24
36
  NovelCompositionSettings,
25
37
  novelComposer,
26
38
  ParseError,
27
39
  parseManuscript,
28
40
  kakuyomuParser,
29
41
  pixivParser,
42
+ } from "@sushichan044/kg-core";
43
+ import {
44
+ createDefaultProofreadingRules,
30
45
  ProofreadError,
31
46
  proofreadManuscript,
32
- } from "@sushichan044/kg-core";
47
+ } from "@sushichan044/kg-core/lint";
33
48
 
34
49
  const parsed = parseManuscript(source, { parser: kakuyomuParser });
35
50
  if (!parsed.ok) throw new Error(ParseError.describe(parsed.error));
@@ -63,17 +78,33 @@ whether it ended naturally, by shrinking, stretching, hanging, forcing, or reach
63
78
  the paragraph end.
64
79
 
65
80
  The composer classifies the core prose classes from JLReq, resolves pair spacing,
66
- and selects line breaks over the whole source paragraph. It prefers natural setting,
67
- then shrinking punctuation space, hanging a comma or full stop, stretching eligible
68
- space, and finally a forced emergency line. The half em that follows a closing
69
- bracket, comma, or full stop is invisible once that character lands at the line end,
70
- so it is the first space spent and it costs the paragraph nothing, which keeps a
71
- line-start bracket at its full em. It owns Japanese line-start and line-end
72
- restrictions, inseparable punctuation, question/exclamation gap suppression, and
73
- ruby placement.
81
+ and selects line breaks over the whole source paragraph. The space between two
82
+ classes follows appendix 表1 of JLReq: a half em before an opening bracket and after
83
+ a closing bracket, comma, or full stop, a quarter em on either side of a middle dot,
84
+ a quarter em between Japanese and a numeral, unit symbol, or Western character, and
85
+ solid where two of those punctuation marks meet.
86
+
87
+ An overflowing line is answered by reducing that space or by hanging a comma or full
88
+ stop; a short line is answered by opening up space where JLReq 3.8.4 and appendix 表6
89
+ allow it — the Japanese-to-Western quarter em first, up to a half, then a solid pair
90
+ between kana, kanji, and the marks that go with them, up to a quarter. Space around
91
+ brackets, commas, full stops, middle dots, hyphens, and an ideographic space is never
92
+ opened up. A line that admits none of these is forced. The choice is made for the
93
+ paragraph rather than line by line,
94
+ minimizing in order the number of forced lines, then stretched, then hanging, then
95
+ shrunk lines that spent visible space. Which space may be reduced, and in which
96
+ order, follows JLReq 3.8.3 and appendix 表3: the space at the line end goes first and
97
+ costs the paragraph nothing, because it is invisible once that character lands there;
98
+ then a middle dot's quarters, then the half em before an opening bracket or after a
99
+ closing bracket or comma, then the Japanese-to-Western quarter down to an eighth. The
100
+ half em after a mid-line full stop marks the end of a sentence and is never reduced,
101
+ and neither is the half em that keeps a line-head opening bracket off the edge.
102
+
103
+ The composer also owns Japanese line-start and line-end restrictions, inseparable
104
+ punctuation, question/exclamation gap suppression, and ruby placement.
74
105
 
75
106
  The composer classifies vertical text before measuring and breaking lines. Following
76
- [JLReq](https://www.w3.org/TR/jlreq/#handling_of_western_text_in_vertical_writing),
107
+ [JLReq](https://www.w3.org/TR/jlreq/#mixed_text_composition_in_vertical_writing_mode),
77
108
  upright Latin initials and abbreviations advance by one em per character, Western
78
109
  words remain unbroken and render sideways, and two ASCII digits form one
79
110
  tate-chu-yoko unit. The resulting `VerticalTextPresentation` is carried by every
@@ -85,6 +116,8 @@ advance by half an em. Supply a synchronous measurer when the caller has more ac
85
116
  font metrics. Base-text requests also include the selected `presentation`:
86
117
 
87
118
  ```ts
119
+ import { createNovelComposer } from "@sushichan044/kg-core/plugin";
120
+
88
121
  const composer = createNovelComposer({
89
122
  measurer: (request) => ({
90
123
  advanceEm: measureWithAvailableFont(request.text, {
@@ -107,6 +140,10 @@ parser result with mismatched `mono` or `jukugo` segment counts is invalid.
107
140
 
108
141
  ## Extensions and validation
109
142
 
143
+ Everything in this section comes from `@sushichan044/kg-core/plugin`, except
144
+ proofreading rules, which are authored against `@sushichan044/kg-core/lint`
145
+ alongside the built-in ones.
146
+
110
147
  Parsers implement `ManuscriptParser`. Composers implement `ManuscriptComposer`
111
148
  and provide Valibot schemas for their settings and layout. Proofreading rules
112
149
  carry `kind: "parsed"` or `kind: "composed"` to declare which manuscript they
@@ -123,6 +160,14 @@ same name, holding its schema and operations: `ManuscriptRange.merge`,
123
160
  inferred from the schemas with `v.InferOutput`; source, display, and grapheme
124
161
  ranges are distinct branded types, and plugin IDs are branded `NamespacedId`.
125
162
 
163
+ A companion object is exported as a value only when one of the three roles
164
+ calls something on it. Concepts you only ever read out of a composed layout —
165
+ `NovelPage`, `ComposedGlyph`, `LineBreakResult`, and the like — are exported as
166
+ types alone, so their schemas are not part of the API. The settings you persist
167
+ and re-validate keep theirs: `NovelCompositionSettings.schema`,
168
+ `ManuscriptAppearanceSettings.schema`, `ManuscriptOffsets.schema`,
169
+ `NovelFlowSettings.schema`, and the appearance picklists.
170
+
126
171
  Processing functions return `ManuscriptResult`: success carries warnings, and
127
172
  failure carries exactly one error from a discriminated union, so callers can
128
173
  `switch` on `error.kind` exhaustively. Each error variant exposes its context
@@ -138,6 +183,10 @@ or recalculate locations.
138
183
 
139
184
  ## Proofreading rules
140
185
 
186
+ Proofreading has its own entry point, `@sushichan044/kg-core/lint`. Nothing in
187
+ the root entry imports from it, so an application that only parses and composes
188
+ never pulls the rules into its bundle.
189
+
141
190
  `createDefaultProofreadingRules()` returns the rules whose answer does not
142
191
  depend on the work: how a paragraph opens and how far it is indented,
143
192
  punctuation before a closing bracket, spacing after `!` and `?`, ellipsis and
@@ -155,7 +204,7 @@ import {
155
204
  consistentNumeralWidthRule,
156
205
  createConsistentKanjiOpeningRule,
157
206
  createDefaultProofreadingRules,
158
- } from "@sushichan044/kg-core";
207
+ } from "@sushichan044/kg-core/lint";
159
208
 
160
209
  const rules = [
161
210
  ...createDefaultProofreadingRules(),