@sushichan044/kg-core 0.6.5 → 0.7.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,29 @@ 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 stretching eligible space; a line that admits none
89
+ of these is forced. The choice is made for the paragraph rather than line by line,
90
+ minimizing in order the number of forced lines, then stretched, then hanging, then
91
+ shrunk lines that spent visible space. Which space may be reduced, and in which
92
+ order, follows JLReq 3.8.3 and appendix 表3: the space at the line end goes first and
93
+ costs the paragraph nothing, because it is invisible once that character lands there;
94
+ then a middle dot's quarters, then the half em before an opening bracket or after a
95
+ closing bracket or comma, then the Japanese-to-Western quarter down to an eighth. The
96
+ half em after a mid-line full stop marks the end of a sentence and is never reduced,
97
+ and neither is the half em that keeps a line-head opening bracket off the edge.
98
+
99
+ The composer also owns Japanese line-start and line-end restrictions, inseparable
100
+ punctuation, question/exclamation gap suppression, and ruby placement.
74
101
 
75
102
  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),
103
+ [JLReq](https://www.w3.org/TR/jlreq/#mixed_text_composition_in_vertical_writing_mode),
77
104
  upright Latin initials and abbreviations advance by one em per character, Western
78
105
  words remain unbroken and render sideways, and two ASCII digits form one
79
106
  tate-chu-yoko unit. The resulting `VerticalTextPresentation` is carried by every
@@ -85,6 +112,8 @@ advance by half an em. Supply a synchronous measurer when the caller has more ac
85
112
  font metrics. Base-text requests also include the selected `presentation`:
86
113
 
87
114
  ```ts
115
+ import { createNovelComposer } from "@sushichan044/kg-core/plugin";
116
+
88
117
  const composer = createNovelComposer({
89
118
  measurer: (request) => ({
90
119
  advanceEm: measureWithAvailableFont(request.text, {
@@ -107,6 +136,10 @@ parser result with mismatched `mono` or `jukugo` segment counts is invalid.
107
136
 
108
137
  ## Extensions and validation
109
138
 
139
+ Everything in this section comes from `@sushichan044/kg-core/plugin`, except
140
+ proofreading rules, which are authored against `@sushichan044/kg-core/lint`
141
+ alongside the built-in ones.
142
+
110
143
  Parsers implement `ManuscriptParser`. Composers implement `ManuscriptComposer`
111
144
  and provide Valibot schemas for their settings and layout. Proofreading rules
112
145
  carry `kind: "parsed"` or `kind: "composed"` to declare which manuscript they
@@ -123,6 +156,14 @@ same name, holding its schema and operations: `ManuscriptRange.merge`,
123
156
  inferred from the schemas with `v.InferOutput`; source, display, and grapheme
124
157
  ranges are distinct branded types, and plugin IDs are branded `NamespacedId`.
125
158
 
159
+ A companion object is exported as a value only when one of the three roles
160
+ calls something on it. Concepts you only ever read out of a composed layout —
161
+ `NovelPage`, `ComposedGlyph`, `LineBreakResult`, and the like — are exported as
162
+ types alone, so their schemas are not part of the API. The settings you persist
163
+ and re-validate keep theirs: `NovelCompositionSettings.schema`,
164
+ `ManuscriptAppearanceSettings.schema`, `ManuscriptOffsets.schema`,
165
+ `NovelFlowSettings.schema`, and the appearance picklists.
166
+
126
167
  Processing functions return `ManuscriptResult`: success carries warnings, and
127
168
  failure carries exactly one error from a discriminated union, so callers can
128
169
  `switch` on `error.kind` exhaustively. Each error variant exposes its context
@@ -138,6 +179,10 @@ or recalculate locations.
138
179
 
139
180
  ## Proofreading rules
140
181
 
182
+ Proofreading has its own entry point, `@sushichan044/kg-core/lint`. Nothing in
183
+ the root entry imports from it, so an application that only parses and composes
184
+ never pulls the rules into its bundle.
185
+
141
186
  `createDefaultProofreadingRules()` returns the rules whose answer does not
142
187
  depend on the work: how a paragraph opens and how far it is indented,
143
188
  punctuation before a closing bracket, spacing after `!` and `?`, ellipsis and
@@ -155,7 +200,7 @@ import {
155
200
  consistentNumeralWidthRule,
156
201
  createConsistentKanjiOpeningRule,
157
202
  createDefaultProofreadingRules,
158
- } from "@sushichan044/kg-core";
203
+ } from "@sushichan044/kg-core/lint";
159
204
 
160
205
  const rules = [
161
206
  ...createDefaultProofreadingRules(),