@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.
Files changed (115) hide show
  1. package/CHANGELOG.md +196 -0
  2. package/LICENSE +21 -0
  3. package/README.md +593 -0
  4. package/dist/addressability.d.ts +245 -0
  5. package/dist/addressability.d.ts.map +1 -0
  6. package/dist/addressability.js +567 -0
  7. package/dist/addressability.js.map +1 -0
  8. package/dist/checker.d.ts +159 -0
  9. package/dist/checker.d.ts.map +1 -0
  10. package/dist/checker.js +177 -0
  11. package/dist/checker.js.map +1 -0
  12. package/dist/cli.d.ts +149 -0
  13. package/dist/cli.d.ts.map +1 -0
  14. package/dist/cli.js +1049 -0
  15. package/dist/cli.js.map +1 -0
  16. package/dist/copy-gate.d.ts +107 -0
  17. package/dist/copy-gate.d.ts.map +1 -0
  18. package/dist/copy-gate.js +132 -0
  19. package/dist/copy-gate.js.map +1 -0
  20. package/dist/fingerprint.d.ts +61 -0
  21. package/dist/fingerprint.d.ts.map +1 -0
  22. package/dist/fingerprint.js +64 -0
  23. package/dist/fingerprint.js.map +1 -0
  24. package/dist/index.d.ts +47 -0
  25. package/dist/index.d.ts.map +1 -0
  26. package/dist/index.js +63 -0
  27. package/dist/index.js.map +1 -0
  28. package/dist/locale-coverage.d.ts +227 -0
  29. package/dist/locale-coverage.d.ts.map +1 -0
  30. package/dist/locale-coverage.js +414 -0
  31. package/dist/locale-coverage.js.map +1 -0
  32. package/dist/passage.d.ts +294 -0
  33. package/dist/passage.d.ts.map +1 -0
  34. package/dist/passage.js +463 -0
  35. package/dist/passage.js.map +1 -0
  36. package/dist/path-exclusions.d.ts +114 -0
  37. package/dist/path-exclusions.d.ts.map +1 -0
  38. package/dist/path-exclusions.js +213 -0
  39. package/dist/path-exclusions.js.map +1 -0
  40. package/dist/registry.d.ts +61 -0
  41. package/dist/registry.d.ts.map +1 -0
  42. package/dist/registry.js +64 -0
  43. package/dist/registry.js.map +1 -0
  44. package/dist/resolve.d.ts +33 -0
  45. package/dist/resolve.d.ts.map +1 -0
  46. package/dist/resolve.js +133 -0
  47. package/dist/resolve.js.map +1 -0
  48. package/dist/scan.d.ts +457 -0
  49. package/dist/scan.d.ts.map +1 -0
  50. package/dist/scan.js +1698 -0
  51. package/dist/scan.js.map +1 -0
  52. package/dist/schema.d.ts +81 -0
  53. package/dist/schema.d.ts.map +1 -0
  54. package/dist/schema.js +482 -0
  55. package/dist/schema.js.map +1 -0
  56. package/dist/types.d.ts +268 -0
  57. package/dist/types.d.ts.map +1 -0
  58. package/dist/types.js +40 -0
  59. package/dist/types.js.map +1 -0
  60. package/dist/voice/checker.d.ts +186 -0
  61. package/dist/voice/checker.d.ts.map +1 -0
  62. package/dist/voice/checker.js +483 -0
  63. package/dist/voice/checker.js.map +1 -0
  64. package/dist/voice/derivation-coverage.d.ts +168 -0
  65. package/dist/voice/derivation-coverage.d.ts.map +1 -0
  66. package/dist/voice/derivation-coverage.js +181 -0
  67. package/dist/voice/derivation-coverage.js.map +1 -0
  68. package/dist/voice/fields.d.ts +107 -0
  69. package/dist/voice/fields.d.ts.map +1 -0
  70. package/dist/voice/fields.js +144 -0
  71. package/dist/voice/fields.js.map +1 -0
  72. package/dist/voice/index.d.ts +19 -0
  73. package/dist/voice/index.d.ts.map +1 -0
  74. package/dist/voice/index.js +24 -0
  75. package/dist/voice/index.js.map +1 -0
  76. package/dist/voice/internal/parse-template.d.ts +27 -0
  77. package/dist/voice/internal/parse-template.d.ts.map +1 -0
  78. package/dist/voice/internal/parse-template.js +111 -0
  79. package/dist/voice/internal/parse-template.js.map +1 -0
  80. package/dist/voice/internal/pattern-safety.d.ts +111 -0
  81. package/dist/voice/internal/pattern-safety.d.ts.map +1 -0
  82. package/dist/voice/internal/pattern-safety.js +278 -0
  83. package/dist/voice/internal/pattern-safety.js.map +1 -0
  84. package/dist/voice/schema.d.ts +65 -0
  85. package/dist/voice/schema.d.ts.map +1 -0
  86. package/dist/voice/schema.js +535 -0
  87. package/dist/voice/schema.js.map +1 -0
  88. package/dist/voice/types.d.ts +282 -0
  89. package/dist/voice/types.d.ts.map +1 -0
  90. package/dist/voice/types.js +37 -0
  91. package/dist/voice/types.js.map +1 -0
  92. package/package.json +72 -0
  93. package/src/addressability.ts +664 -0
  94. package/src/checker.ts +293 -0
  95. package/src/cli.ts +1166 -0
  96. package/src/copy-gate.ts +197 -0
  97. package/src/fingerprint.ts +66 -0
  98. package/src/index.ts +163 -0
  99. package/src/locale-coverage.ts +512 -0
  100. package/src/passage.ts +644 -0
  101. package/src/path-exclusions.ts +265 -0
  102. package/src/registry.ts +103 -0
  103. package/src/resolve.ts +172 -0
  104. package/src/scan.ts +1959 -0
  105. package/src/schema.ts +528 -0
  106. package/src/types.ts +301 -0
  107. package/src/voice/checker.ts +590 -0
  108. package/src/voice/derivation-coverage.ts +217 -0
  109. package/src/voice/fields.ts +160 -0
  110. package/src/voice/index.ts +55 -0
  111. package/src/voice/internal/parse-template.ts +114 -0
  112. package/src/voice/internal/pattern-safety.ts +336 -0
  113. package/src/voice/schema.ts +585 -0
  114. package/src/voice/types.ts +329 -0
  115. 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
+ }