@clossys/writer 0.3.2
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/CHANGELOG.md +196 -0
- package/LICENSE +21 -0
- package/README.md +593 -0
- package/dist/addressability.d.ts +245 -0
- package/dist/addressability.d.ts.map +1 -0
- package/dist/addressability.js +567 -0
- package/dist/addressability.js.map +1 -0
- package/dist/checker.d.ts +159 -0
- package/dist/checker.d.ts.map +1 -0
- package/dist/checker.js +177 -0
- package/dist/checker.js.map +1 -0
- package/dist/cli.d.ts +149 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +1049 -0
- package/dist/cli.js.map +1 -0
- package/dist/copy-gate.d.ts +107 -0
- package/dist/copy-gate.d.ts.map +1 -0
- package/dist/copy-gate.js +132 -0
- package/dist/copy-gate.js.map +1 -0
- package/dist/fingerprint.d.ts +61 -0
- package/dist/fingerprint.d.ts.map +1 -0
- package/dist/fingerprint.js +64 -0
- package/dist/fingerprint.js.map +1 -0
- package/dist/index.d.ts +47 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +63 -0
- package/dist/index.js.map +1 -0
- package/dist/locale-coverage.d.ts +227 -0
- package/dist/locale-coverage.d.ts.map +1 -0
- package/dist/locale-coverage.js +414 -0
- package/dist/locale-coverage.js.map +1 -0
- package/dist/passage.d.ts +294 -0
- package/dist/passage.d.ts.map +1 -0
- package/dist/passage.js +463 -0
- package/dist/passage.js.map +1 -0
- package/dist/path-exclusions.d.ts +114 -0
- package/dist/path-exclusions.d.ts.map +1 -0
- package/dist/path-exclusions.js +213 -0
- package/dist/path-exclusions.js.map +1 -0
- package/dist/registry.d.ts +61 -0
- package/dist/registry.d.ts.map +1 -0
- package/dist/registry.js +64 -0
- package/dist/registry.js.map +1 -0
- package/dist/resolve.d.ts +33 -0
- package/dist/resolve.d.ts.map +1 -0
- package/dist/resolve.js +133 -0
- package/dist/resolve.js.map +1 -0
- package/dist/scan.d.ts +457 -0
- package/dist/scan.d.ts.map +1 -0
- package/dist/scan.js +1698 -0
- package/dist/scan.js.map +1 -0
- package/dist/schema.d.ts +81 -0
- package/dist/schema.d.ts.map +1 -0
- package/dist/schema.js +482 -0
- package/dist/schema.js.map +1 -0
- package/dist/types.d.ts +268 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +40 -0
- package/dist/types.js.map +1 -0
- package/dist/voice/checker.d.ts +186 -0
- package/dist/voice/checker.d.ts.map +1 -0
- package/dist/voice/checker.js +483 -0
- package/dist/voice/checker.js.map +1 -0
- package/dist/voice/derivation-coverage.d.ts +168 -0
- package/dist/voice/derivation-coverage.d.ts.map +1 -0
- package/dist/voice/derivation-coverage.js +181 -0
- package/dist/voice/derivation-coverage.js.map +1 -0
- package/dist/voice/fields.d.ts +107 -0
- package/dist/voice/fields.d.ts.map +1 -0
- package/dist/voice/fields.js +144 -0
- package/dist/voice/fields.js.map +1 -0
- package/dist/voice/index.d.ts +19 -0
- package/dist/voice/index.d.ts.map +1 -0
- package/dist/voice/index.js +24 -0
- package/dist/voice/index.js.map +1 -0
- package/dist/voice/internal/parse-template.d.ts +27 -0
- package/dist/voice/internal/parse-template.d.ts.map +1 -0
- package/dist/voice/internal/parse-template.js +111 -0
- package/dist/voice/internal/parse-template.js.map +1 -0
- package/dist/voice/internal/pattern-safety.d.ts +111 -0
- package/dist/voice/internal/pattern-safety.d.ts.map +1 -0
- package/dist/voice/internal/pattern-safety.js +278 -0
- package/dist/voice/internal/pattern-safety.js.map +1 -0
- package/dist/voice/schema.d.ts +65 -0
- package/dist/voice/schema.d.ts.map +1 -0
- package/dist/voice/schema.js +535 -0
- package/dist/voice/schema.js.map +1 -0
- package/dist/voice/types.d.ts +282 -0
- package/dist/voice/types.d.ts.map +1 -0
- package/dist/voice/types.js +37 -0
- package/dist/voice/types.js.map +1 -0
- package/package.json +72 -0
- package/src/addressability.ts +664 -0
- package/src/checker.ts +293 -0
- package/src/cli.ts +1166 -0
- package/src/copy-gate.ts +197 -0
- package/src/fingerprint.ts +66 -0
- package/src/index.ts +163 -0
- package/src/locale-coverage.ts +512 -0
- package/src/passage.ts +644 -0
- package/src/path-exclusions.ts +265 -0
- package/src/registry.ts +103 -0
- package/src/resolve.ts +172 -0
- package/src/scan.ts +1959 -0
- package/src/schema.ts +528 -0
- package/src/types.ts +301 -0
- package/src/voice/checker.ts +590 -0
- package/src/voice/derivation-coverage.ts +217 -0
- package/src/voice/fields.ts +160 -0
- package/src/voice/index.ts +55 -0
- package/src/voice/internal/parse-template.ts +114 -0
- package/src/voice/internal/pattern-safety.ts +336 -0
- package/src/voice/schema.ts +585 -0
- package/src/voice/types.ts +329 -0
- package/templates/voice-record.template.jsonc +135 -0
|
@@ -0,0 +1,282 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Plain TypeScript types for @clossys/writer/voice's four entities: voice
|
|
3
|
+
* rules, a glossary entry, a claim, and the `VoiceRecord` that binds them
|
|
4
|
+
* together for one consumer. Pure data — no validation logic lives here
|
|
5
|
+
* (see `schema.ts`) and no I/O.
|
|
6
|
+
*
|
|
7
|
+
* No runtime schema library. That follows this repository's own
|
|
8
|
+
* precedent: `@example/catalog`, `@example/policy`, and
|
|
9
|
+
* `@example/ui/tokens` all ship zero runtime dependencies; only
|
|
10
|
+
* `@example/ui` carries any, and only because it wraps React
|
|
11
|
+
* primitives it genuinely cannot hand-roll. `@clossys/writer/voice`'s
|
|
12
|
+
* entire job is dependency-free data shape validation — the same job
|
|
13
|
+
* `@example/policy`'s `validate.ts` already does, in plain type
|
|
14
|
+
* guards, for a smaller shape. `schema.ts` follows that file's pattern
|
|
15
|
+
* closely rather than pulling in a schema library (and its own major-
|
|
16
|
+
* version churn, a real cost for a *public* package's consumers) for what
|
|
17
|
+
* one file of type guards already covers.
|
|
18
|
+
*
|
|
19
|
+
* This file ships no example content of a real voice. Every field here is
|
|
20
|
+
* either required-and-generic or a structural placeholder — filling in an
|
|
21
|
+
* actual person rule, glossary, or claims register is a consumer's job,
|
|
22
|
+
* the same split `@example/ui/tokens` draws between `tokens.css`
|
|
23
|
+
* (neutral machinery) and a consumer's own `brand.css` (real values). See
|
|
24
|
+
* "The single most important constraint" in the README.
|
|
25
|
+
*/
|
|
26
|
+
/** Descriptive only. Never mechanically checked — see README. */
|
|
27
|
+
export type FormalityLevel = "casual" | "neutral" | "formal";
|
|
28
|
+
/**
|
|
29
|
+
* The valid `FormalityLevel` values, in declaration order — exported as a
|
|
30
|
+
* list, mirroring `@example/policy`'s `DIGEST_ALGORITHMS`, so
|
|
31
|
+
* `schema.ts` never hardcodes them as a second, separately-maintained
|
|
32
|
+
* literal check.
|
|
33
|
+
*/
|
|
34
|
+
export declare const FORMALITY_LEVELS: readonly FormalityLevel[];
|
|
35
|
+
/**
|
|
36
|
+
* A "person" rule, e.g. "always address the reader as you, never refer to
|
|
37
|
+
* the product/company as I". `description` is for humans — it is never
|
|
38
|
+
* parsed. `forbiddenPronouns` is the ONLY part of this rule the checker
|
|
39
|
+
* actually evaluates: a plain list of pronouns that, if they appear in
|
|
40
|
+
* copy, contradict the rule. Matched case-insensitively, whole-word only —
|
|
41
|
+
* except a single-letter, uppercase entry (e.g. `"I"`), which `checker.ts`
|
|
42
|
+
* matches case-sensitively so it cannot collide with an unrelated
|
|
43
|
+
* lowercase letter (a roman numeral, a loop variable in quoted code).
|
|
44
|
+
*
|
|
45
|
+
* This is deliberately a word list, not a `"first" | "second" | "third"`
|
|
46
|
+
* enum the checker tries to infer grammar from. A word list is auditable —
|
|
47
|
+
* a reader can see exactly what will be flagged — and it is the same
|
|
48
|
+
* mechanism the glossary check already uses, rather than a second,
|
|
49
|
+
* differently-shaped piece of pseudo-grammar logic.
|
|
50
|
+
*/
|
|
51
|
+
export interface PersonRule {
|
|
52
|
+
description: string;
|
|
53
|
+
forbiddenPronouns: string[];
|
|
54
|
+
}
|
|
55
|
+
/**
|
|
56
|
+
* A "tense" rule. Same shape and same honesty as `PersonRule`:
|
|
57
|
+
* `forbiddenMarkers` is a plain word list (e.g. `["will", "shall"]` to
|
|
58
|
+
* steer away from future-tense promises), not an attempt at real
|
|
59
|
+
* grammatical tense parsing — see the README's "what this checker does not
|
|
60
|
+
* attempt" section for why that line is drawn here.
|
|
61
|
+
*/
|
|
62
|
+
export interface TenseRule {
|
|
63
|
+
description: string;
|
|
64
|
+
forbiddenMarkers: string[];
|
|
65
|
+
}
|
|
66
|
+
/**
|
|
67
|
+
* The full rules block of a `VoiceRecord`. `person` and `tense` are
|
|
68
|
+
* mechanically checkable (via their word lists, when populated).
|
|
69
|
+
* `formality` and `tone` are metadata for a human writer/reviewer only —
|
|
70
|
+
* the checker never reads them. See README, "Be honest about what is and
|
|
71
|
+
* is not mechanically checkable."
|
|
72
|
+
*/
|
|
73
|
+
export interface VoiceRules {
|
|
74
|
+
person: PersonRule;
|
|
75
|
+
tense: TenseRule;
|
|
76
|
+
formality: FormalityLevel;
|
|
77
|
+
/** Free-text tone descriptors, e.g. `["warm", "direct", "no jargon"]`. */
|
|
78
|
+
tone: string[];
|
|
79
|
+
}
|
|
80
|
+
export type GlossaryStatus = "forbidden" | "preferred";
|
|
81
|
+
/** The valid `GlossaryStatus` values, in declaration order. See `FORMALITY_LEVELS`'s doc comment for why this is a list, not a repeated literal check. */
|
|
82
|
+
export declare const GLOSSARY_STATUSES: readonly GlossaryStatus[];
|
|
83
|
+
/**
|
|
84
|
+
* One glossary entry. Only `status: "forbidden"` entries are ever actively
|
|
85
|
+
* scanned for by the checker — see README for why `"preferred"` entries are
|
|
86
|
+
* documentation-only (detecting "did you use the sanctioned synonym" would
|
|
87
|
+
* require real synonym/paraphrase detection, which this package does not
|
|
88
|
+
* attempt and will not claim to).
|
|
89
|
+
*/
|
|
90
|
+
export interface GlossaryEntry {
|
|
91
|
+
term: string;
|
|
92
|
+
status: GlossaryStatus;
|
|
93
|
+
/** Required — a forbidden or preferred term with no stated reason is not auditable. */
|
|
94
|
+
reason: string;
|
|
95
|
+
/** Suggested replacement, shown in a finding's message when `status` is `"forbidden"`. */
|
|
96
|
+
alternative?: string;
|
|
97
|
+
/** Default `false` — most house-style terms are meant to be caught regardless of capitalization. */
|
|
98
|
+
caseSensitive: boolean;
|
|
99
|
+
/** See `VoiceChannel`'s doc comment. Omitted (the default) means this entry applies regardless of channel. */
|
|
100
|
+
channel?: VoiceChannel;
|
|
101
|
+
}
|
|
102
|
+
/**
|
|
103
|
+
* A consumer-supplied channel tag (e.g. `"linkedin"`, `"x"`, `"hn"`) a rule
|
|
104
|
+
* can be scoped to, so different channels can carry different banned sets —
|
|
105
|
+
* the same seam `CopyLocale` (`../types.ts`) draws for locale, and the same
|
|
106
|
+
* plain-opaque-string pattern `Claim.factRef`/`CopyEntry.factRef` draw for
|
|
107
|
+
* `strategy`'s facts registry. This package does NOT define what a channel
|
|
108
|
+
* IS, does not enumerate valid channels, and never interprets one beyond an
|
|
109
|
+
* exact string-equality comparison against `VoiceCheckOptions.channel` (see
|
|
110
|
+
* `checker.ts`) — that taxonomy is entirely consumer policy. Validated for
|
|
111
|
+
* SHAPE only (a non-empty, non-whitespace-only string) — see `schema.ts`'s
|
|
112
|
+
* `validateChannelShape`.
|
|
113
|
+
*/
|
|
114
|
+
export type VoiceChannel = string;
|
|
115
|
+
/**
|
|
116
|
+
* Three severity tiers, replacing the previous two-value `"error" | "warning"`
|
|
117
|
+
* union (still both present, unchanged in meaning — this is a strictly
|
|
118
|
+
* additive change; see `VOICE_SEVERITIES`' own note on backward
|
|
119
|
+
* compatibility). Every tier is reported identically in `VoiceFinding[]`;
|
|
120
|
+
* what differs is what a CALLER should do with each one, which this package
|
|
121
|
+
* documents explicitly rather than leaving implicit (see the README,
|
|
122
|
+
* "Severity tiers and the exit-code mapping"):
|
|
123
|
+
*
|
|
124
|
+
* - `"error"` — FAILS CI. This package's own documented idiom
|
|
125
|
+
* (`report.findings.some(f => f.severity === "error")`) treats this,
|
|
126
|
+
* and only this, tier as build-breaking. Unchanged from before this
|
|
127
|
+
* addition: every finding this package's OWN dimensions (glossary,
|
|
128
|
+
* person, claims) already produced at `"error"` still does.
|
|
129
|
+
* - `"warning"` — fails only a NARROWER, editorial gate — a stricter,
|
|
130
|
+
* consumer-owned check (e.g. "block merge to a marketing branch", "flag
|
|
131
|
+
* for a copy reviewer") that is not this package's CI idiom and that
|
|
132
|
+
* this package does not implement. The tense dimension already produces
|
|
133
|
+
* `"warning"` findings; nothing about their behavior changes here — this
|
|
134
|
+
* is a documentation clarification of a name that was already in use,
|
|
135
|
+
* not a new runtime behavior for existing findings.
|
|
136
|
+
* - `"advisory"` — purely informational. Never fails anything, including
|
|
137
|
+
* the narrower editorial gate above. Exists so a genuinely optional
|
|
138
|
+
* style nudge (worth a human's attention, never worth blocking on) has
|
|
139
|
+
* a home that isn't a `"warning"` a consumer's own tooling might
|
|
140
|
+
* mistakenly treat as gate-worthy.
|
|
141
|
+
*
|
|
142
|
+
* Only `PatternRule.severity` (below) requires an author to pick one of
|
|
143
|
+
* these explicitly today — every other dimension's severity remains
|
|
144
|
+
* hardcoded by `checker.ts`, exactly as before.
|
|
145
|
+
*/
|
|
146
|
+
export type VoiceSeverity = "error" | "warning" | "advisory";
|
|
147
|
+
/** The valid `VoiceSeverity` values, in documented-precedence order (most to least CI-blocking). See `FORMALITY_LEVELS`'s doc comment for why this is a list, not a repeated literal check. */
|
|
148
|
+
export declare const VOICE_SEVERITIES: readonly VoiceSeverity[];
|
|
149
|
+
/**
|
|
150
|
+
* One claim a consumer's copy might make, e.g. "fastest sync in its
|
|
151
|
+
* class". `factRef` is the seam into a separate, not-yet-existent
|
|
152
|
+
* `strategy` package's `facts` registry — see README, "The `factRef`
|
|
153
|
+
* seam", for why it is a plain opaque string and never a typed import.
|
|
154
|
+
*
|
|
155
|
+
* `matchPhrases` are the literal, verbatim phrases the checker searches
|
|
156
|
+
* copy for to decide this claim is being made. When empty, the checker
|
|
157
|
+
* falls back to searching for `text` itself. Matching is literal and
|
|
158
|
+
* case-insensitive — a paraphrase of the claim that never uses one of
|
|
159
|
+
* these phrases is not detected. See README's limits section.
|
|
160
|
+
*/
|
|
161
|
+
export interface Claim {
|
|
162
|
+
id: string;
|
|
163
|
+
/** Human-readable statement of the claim, for the register itself and as the default match phrase. */
|
|
164
|
+
text: string;
|
|
165
|
+
matchPhrases: string[];
|
|
166
|
+
/**
|
|
167
|
+
* Opaque plain-string reference into a consumer's own facts registry.
|
|
168
|
+
* Never validated by this package — see README, "The `factRef` seam".
|
|
169
|
+
*/
|
|
170
|
+
factRef?: string;
|
|
171
|
+
/** Default `true`: most claims in a register are there because they need backing. */
|
|
172
|
+
requiresSupport: boolean;
|
|
173
|
+
}
|
|
174
|
+
/**
|
|
175
|
+
* A regex pattern, serialized as its two `RegExp` constructor arguments —
|
|
176
|
+
* NEVER a real `RegExp` instance — because a `VoiceRecord` is checked-in
|
|
177
|
+
* JSON data, not code: `JSON.stringify`/`JSON.parse` round-trips a `RegExp`
|
|
178
|
+
* as `{}`, silently losing both the source and the flags. This package
|
|
179
|
+
* stores the two strings a `new RegExp(source, flags)` call actually needs,
|
|
180
|
+
* and constructs the real object only at validation/check time — see
|
|
181
|
+
* `internal/pattern-safety.ts`.
|
|
182
|
+
*/
|
|
183
|
+
export interface VoicePattern {
|
|
184
|
+
/**
|
|
185
|
+
* The regex source, e.g. `"\\u2014"` for a hard em-dash ban, or
|
|
186
|
+
* `"\\b(deep dive|dive deep)\\b"` for alternation, or `"\\bit'?s\\b"` for
|
|
187
|
+
* an optional apostrophe. Never includes the enclosing `/.../` delimiters
|
|
188
|
+
* — this is `RegExp`'s own `source` argument. Restricted at validation
|
|
189
|
+
* time — see `internal/pattern-safety.ts`'s top doc comment for the full,
|
|
190
|
+
* documented regex-safety gate this package applies before ever
|
|
191
|
+
* constructing a real `RegExp` from this string.
|
|
192
|
+
*/
|
|
193
|
+
source: string;
|
|
194
|
+
/**
|
|
195
|
+
* Regex flags, restricted to a safe, documented subset (`i`, `u`, `s` —
|
|
196
|
+
* see `internal/pattern-safety.ts`). Omit for no flags. Never include `g`
|
|
197
|
+
* or `y`: this package always does its own match-counting pass and never
|
|
198
|
+
* accepts a caller-supplied global/sticky flag — see that file's doc
|
|
199
|
+
* comment for why.
|
|
200
|
+
*/
|
|
201
|
+
flags?: string;
|
|
202
|
+
}
|
|
203
|
+
/**
|
|
204
|
+
* A regex-based voice rule — the alternation, optional-apostrophe, and
|
|
205
|
+
* punctuation-ban gaps `GlossaryEntry`'s literal term matching cannot
|
|
206
|
+
* express (see the README, "Pattern rules vs. the glossary"). A hard
|
|
207
|
+
* character ban (a U+2014 em dash, say) is just a pattern with no
|
|
208
|
+
* alternation at all — `PatternRule` subsumes that case rather than this
|
|
209
|
+
* package growing a second, distinct "punctuation rule" type.
|
|
210
|
+
*
|
|
211
|
+
* SAFETY. `pattern` is caller-supplied regex, which can hang a scanner via
|
|
212
|
+
* catastrophic backtracking if accepted unbounded. This package's position:
|
|
213
|
+
* bound the pattern AT REGISTRATION TIME, never at run time — there is no
|
|
214
|
+
* runtime timeout anywhere in this package. See
|
|
215
|
+
* `internal/pattern-safety.ts`'s top doc comment for the full, honest
|
|
216
|
+
* accounting of exactly what is rejected and what known gap remains.
|
|
217
|
+
* `schema.ts`'s `validateVoiceRecordShape` and `checker.ts`'s `checkCopy`
|
|
218
|
+
* BOTH run this gate — the former at registration, the latter as
|
|
219
|
+
* defense-in-depth, since `checkCopy` does not otherwise trust its
|
|
220
|
+
* `VoiceRecord` argument (see that file's own doc comment). Either way, a
|
|
221
|
+
* pattern that fails this gate is reported as a real, unmissable,
|
|
222
|
+
* non-waivable `"pattern:invalid-rule"` finding — never a silent skip. See
|
|
223
|
+
* the `types.ts` header comment's core rule: a check that cannot run must
|
|
224
|
+
* fail, not pass.
|
|
225
|
+
*/
|
|
226
|
+
export interface PatternRule {
|
|
227
|
+
id: string;
|
|
228
|
+
description: string;
|
|
229
|
+
pattern: VoicePattern;
|
|
230
|
+
severity: VoiceSeverity;
|
|
231
|
+
/** Required — an unauditable pattern rule is exactly the mistake `GlossaryEntry.reason` already guards against. */
|
|
232
|
+
reason: string;
|
|
233
|
+
/** Suggested replacement, shown in a finding's message. */
|
|
234
|
+
alternative?: string;
|
|
235
|
+
/** See `VoiceChannel`'s doc comment. Omitted (the default) means this rule applies regardless of channel. */
|
|
236
|
+
channel?: VoiceChannel;
|
|
237
|
+
}
|
|
238
|
+
/**
|
|
239
|
+
* One consumer's complete, bound voice: an identifier, its rules, its
|
|
240
|
+
* glossary, its claims register, and (optionally) its regex pattern rules.
|
|
241
|
+
* This is the "brand.css" of this package — foundry ships the schema this
|
|
242
|
+
* conforms to, never a real instance of it. See README, "The single most
|
|
243
|
+
* important constraint".
|
|
244
|
+
*
|
|
245
|
+
* `patterns` is OPTIONAL AT THE TYPE LEVEL — unlike `glossary`/`claims`,
|
|
246
|
+
* which are required fields that `validateVoiceRecordShape` merely treats
|
|
247
|
+
* leniently (`undefined` defaults to `[]`) — specifically so every existing
|
|
248
|
+
* `VoiceRecord` object literal anywhere (this package's own tests, a
|
|
249
|
+
* consumer's already-written code) keeps compiling unchanged. Runtime
|
|
250
|
+
* behavior is identical to `glossary`/`claims` either way: omitted means
|
|
251
|
+
* `[]`, once a value has passed through `parseVoiceRecord`/`buildVoiceRecord`
|
|
252
|
+
* (`schema.ts`). See `checker.ts` for why `checkCopy` itself still reads it
|
|
253
|
+
* as `record.patterns ?? []`, since it does not require a `VoiceRecord` to
|
|
254
|
+
* have been built via `parseVoiceRecord` first.
|
|
255
|
+
*/
|
|
256
|
+
export interface VoiceRecord {
|
|
257
|
+
id: string;
|
|
258
|
+
rules: VoiceRules;
|
|
259
|
+
glossary: GlossaryEntry[];
|
|
260
|
+
claims: Claim[];
|
|
261
|
+
patterns?: PatternRule[];
|
|
262
|
+
}
|
|
263
|
+
/**
|
|
264
|
+
* One thing a validator or the checker found wrong (or, at `"warning"`,
|
|
265
|
+
* worth a look). Deliberately the same shape as `@example/policy`'s
|
|
266
|
+
* `Finding` — `rule` / `severity` / `message` / optional `path` — so a
|
|
267
|
+
* caller already handling one kind of finding in this repo's ecosystem
|
|
268
|
+
* does not need a second mental model for this package's. Defined fresh
|
|
269
|
+
* here, not imported: this package has zero runtime dependency on
|
|
270
|
+
* `@example/policy`, on purpose (see README, "Requirements").
|
|
271
|
+
*/
|
|
272
|
+
export interface VoiceFinding {
|
|
273
|
+
/** Stable identifier for the rule that produced this finding, e.g. `"glossary:forbidden-term"`. */
|
|
274
|
+
rule: string;
|
|
275
|
+
/** See `VoiceSeverity`'s own doc comment for what each of the three tiers means for CI and for a narrower editorial gate. */
|
|
276
|
+
severity: VoiceSeverity;
|
|
277
|
+
/** Human-readable description of the problem. */
|
|
278
|
+
message: string;
|
|
279
|
+
/** The specific term/pronoun/marker/claim/pattern id this finding is about, when there is a single clear one. */
|
|
280
|
+
path?: string;
|
|
281
|
+
}
|
|
282
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/voice/types.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Plain TypeScript types for @clossys/writer/voice's four entities: voice
|
|
3
|
+
* rules, a glossary entry, a claim, and the `VoiceRecord` that binds them
|
|
4
|
+
* together for one consumer. Pure data — no validation logic lives here
|
|
5
|
+
* (see `schema.ts`) and no I/O.
|
|
6
|
+
*
|
|
7
|
+
* No runtime schema library. That follows this repository's own
|
|
8
|
+
* precedent: `@example/catalog`, `@example/policy`, and
|
|
9
|
+
* `@example/ui/tokens` all ship zero runtime dependencies; only
|
|
10
|
+
* `@example/ui` carries any, and only because it wraps React
|
|
11
|
+
* primitives it genuinely cannot hand-roll. `@clossys/writer/voice`'s
|
|
12
|
+
* entire job is dependency-free data shape validation — the same job
|
|
13
|
+
* `@example/policy`'s `validate.ts` already does, in plain type
|
|
14
|
+
* guards, for a smaller shape. `schema.ts` follows that file's pattern
|
|
15
|
+
* closely rather than pulling in a schema library (and its own major-
|
|
16
|
+
* version churn, a real cost for a *public* package's consumers) for what
|
|
17
|
+
* one file of type guards already covers.
|
|
18
|
+
*
|
|
19
|
+
* This file ships no example content of a real voice. Every field here is
|
|
20
|
+
* either required-and-generic or a structural placeholder — filling in an
|
|
21
|
+
* actual person rule, glossary, or claims register is a consumer's job,
|
|
22
|
+
* the same split `@example/ui/tokens` draws between `tokens.css`
|
|
23
|
+
* (neutral machinery) and a consumer's own `brand.css` (real values). See
|
|
24
|
+
* "The single most important constraint" in the README.
|
|
25
|
+
*/
|
|
26
|
+
/**
|
|
27
|
+
* The valid `FormalityLevel` values, in declaration order — exported as a
|
|
28
|
+
* list, mirroring `@example/policy`'s `DIGEST_ALGORITHMS`, so
|
|
29
|
+
* `schema.ts` never hardcodes them as a second, separately-maintained
|
|
30
|
+
* literal check.
|
|
31
|
+
*/
|
|
32
|
+
export const FORMALITY_LEVELS = ["casual", "neutral", "formal"];
|
|
33
|
+
/** The valid `GlossaryStatus` values, in declaration order. See `FORMALITY_LEVELS`'s doc comment for why this is a list, not a repeated literal check. */
|
|
34
|
+
export const GLOSSARY_STATUSES = ["forbidden", "preferred"];
|
|
35
|
+
/** The valid `VoiceSeverity` values, in documented-precedence order (most to least CI-blocking). See `FORMALITY_LEVELS`'s doc comment for why this is a list, not a repeated literal check. */
|
|
36
|
+
export const VOICE_SEVERITIES = ["error", "warning", "advisory"];
|
|
37
|
+
//# sourceMappingURL=types.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/voice/types.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AASH;;;;;GAKG;AACH,MAAM,CAAC,MAAM,gBAAgB,GAA8B,CAAC,QAAQ,EAAE,SAAS,EAAE,QAAQ,CAAC,CAAC;AAwD3F,0JAA0J;AAC1J,MAAM,CAAC,MAAM,iBAAiB,GAA8B,CAAC,WAAW,EAAE,WAAW,CAAC,CAAC;AA6EvF,+LAA+L;AAC/L,MAAM,CAAC,MAAM,gBAAgB,GAA6B,CAAC,OAAO,EAAE,SAAS,EAAE,UAAU,CAAC,CAAC"}
|
package/package.json
ADDED
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@clossys/writer",
|
|
3
|
+
"version": "0.3.2",
|
|
4
|
+
"private": false,
|
|
5
|
+
"license": "MIT",
|
|
6
|
+
"type": "module",
|
|
7
|
+
"main": "./dist/index.js",
|
|
8
|
+
"module": "./dist/index.js",
|
|
9
|
+
"types": "./dist/index.d.ts",
|
|
10
|
+
"exports": {
|
|
11
|
+
".": {
|
|
12
|
+
"types": "./dist/index.d.ts",
|
|
13
|
+
"import": "./dist/index.js"
|
|
14
|
+
},
|
|
15
|
+
"./voice": {
|
|
16
|
+
"types": "./dist/voice/index.d.ts",
|
|
17
|
+
"import": "./dist/voice/index.js"
|
|
18
|
+
},
|
|
19
|
+
"./voice-record.template.jsonc": "./templates/voice-record.template.jsonc"
|
|
20
|
+
},
|
|
21
|
+
"bin": {
|
|
22
|
+
"writer-check": "./dist/cli.js"
|
|
23
|
+
},
|
|
24
|
+
"files": [
|
|
25
|
+
"dist",
|
|
26
|
+
"src",
|
|
27
|
+
"!src/**/*.test.ts",
|
|
28
|
+
"templates",
|
|
29
|
+
"CHANGELOG.md",
|
|
30
|
+
"README.md",
|
|
31
|
+
"LICENSE"
|
|
32
|
+
],
|
|
33
|
+
"sideEffects": false,
|
|
34
|
+
"description": "The writer role: is it well said? A consumer-owned language system: voice rules, glossary and claims validation, addressable copy records, source traceability, locale coverage, and passage-layer composition — five gates reachable from one bin. Ships machinery and templates, never a consumer's actual copy or voice.",
|
|
35
|
+
"keywords": [
|
|
36
|
+
"writer",
|
|
37
|
+
"copy",
|
|
38
|
+
"content",
|
|
39
|
+
"voice",
|
|
40
|
+
"i18n",
|
|
41
|
+
"content-checker",
|
|
42
|
+
"typescript"
|
|
43
|
+
],
|
|
44
|
+
"author": "Calvin Hung",
|
|
45
|
+
"repository": {
|
|
46
|
+
"type": "git",
|
|
47
|
+
"url": "git+https://github.com/clossys/foundry.git",
|
|
48
|
+
"directory": "packages/writer"
|
|
49
|
+
},
|
|
50
|
+
"bugs": {
|
|
51
|
+
"url": "https://github.com/clossys/foundry/issues"
|
|
52
|
+
},
|
|
53
|
+
"homepage": "https://github.com/clossys/foundry/tree/main/packages/writer#readme",
|
|
54
|
+
"engines": {
|
|
55
|
+
"node": ">=20"
|
|
56
|
+
},
|
|
57
|
+
"scripts": {
|
|
58
|
+
"build": "tsc -p tsconfig.json",
|
|
59
|
+
"prepublishOnly": "node ../../scripts/check-name-collision.mjs . && npm run build",
|
|
60
|
+
"typecheck": "tsc -p tsconfig.json --noEmit",
|
|
61
|
+
"test": "vitest run"
|
|
62
|
+
},
|
|
63
|
+
"devDependencies": {
|
|
64
|
+
"@types/node": "^22.10.0",
|
|
65
|
+
"typescript": "~6.0.0",
|
|
66
|
+
"vitest": "^4.1.9"
|
|
67
|
+
},
|
|
68
|
+
"publishConfig": {
|
|
69
|
+
"registry": "https://registry.npmjs.org",
|
|
70
|
+
"access": "public"
|
|
71
|
+
}
|
|
72
|
+
}
|