@lippelt/srd-core 0.1.1 → 0.1.3

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
@@ -1,8 +1,8 @@
1
1
  # @lippelt/srd-core
2
2
 
3
- Contrato + registry para sistemas de RPG plugáveis. Cada sistema (D&D 5e, Pathfinder, Lancer, etc) ships como seu próprio pacote (`@lippelt/srd-*`), implementando o contrato `System` definido aqui.
3
+ Contrato + registro para sistemas de RPG plugáveis. Cada sistema (D&D 5e, Pathfinder, Lancer etc) é distribuído como seu próprio pacote (`@lippelt/srd-*`), implementando o contrato `System` definido aqui.
4
4
 
5
- Pensado pra ser consumido por painéis de mesa, ferramentas de jogo e VTTs leves — agnóstico de UI.
5
+ Pensado para ser consumido por painéis de mesa, ferramentas de jogo e VTTs leves — **agnóstico de UI**.
6
6
 
7
7
  ## Instalação
8
8
 
@@ -26,9 +26,9 @@ const result = sys?.rules?.roll?.('attack', { modifier: 5, targetAC: 18, advanta
26
26
  ## API
27
27
 
28
28
  - `register(system: System): void` — registra um sistema. Idempotente (mesma referência); colisão de id com instância diferente lança erro.
29
- - `getSystem(id: SystemId): System | null` — resolve sync; retorna `null` se não registrado.
29
+ - `getSystem(id: SystemId): System | null` — resolve síncrono; retorna `null` se não registrado.
30
30
  - `listRegisteredSystems(): SystemId[]` — todos os ids atualmente registrados.
31
- - `clearRegistry(): void` — limpa o registry (útil em testes).
31
+ - `clearRegistry(): void` — limpa o registro (útil em testes).
32
32
 
33
33
  ## Contrato `System`
34
34
 
@@ -41,13 +41,15 @@ interface System {
41
41
  dicePresets: DicePreset[]
42
42
  conditions: ConditionDef[]
43
43
  trackerFields: TrackerField[]
44
- rules?: SystemRules // opcional — rolls customizados (advantage, crit, damage)
44
+ rules?: SystemRules // opcional — rolagens customizadas (vantagem, crítico, dano)
45
45
  }
46
46
  ```
47
47
 
48
+ > Os nomes dos campos no contrato permanecem em inglês por serem identificadores de código (consumidos por TypeScript em qualquer idioma de projeto).
49
+
48
50
  ### `DicePreset`
49
51
 
50
- Botões rápidos de rolagem por categoria (`check`, `attack`, `damage`, `save`, `special`):
52
+ Botões de rolagem rápida por categoria (`check`, `attack`, `damage`, `save`, `special`):
51
53
 
52
54
  ```ts
53
55
  { id: 'd20-adv', label: 'd20 com vantagem', notation: '2d20kh1', category: 'check' }
@@ -55,10 +57,10 @@ Botões rápidos de rolagem por categoria (`check`, `attack`, `damage`, `save`,
55
57
 
56
58
  ### `ConditionDef`
57
59
 
58
- Status/condições do sistema:
60
+ Condições/estados do sistema:
59
61
 
60
62
  ```ts
61
- { id: 'poisoned', label: 'Envenenado', summary: 'Desvantagem em ataques e testes de atributo.' }
63
+ { id: 'poisoned', label: 'Envenenado', summary: 'Desvantagem em ataques e testes de habilidade.' }
62
64
  ```
63
65
 
64
66
  ### `TrackerField`
@@ -72,7 +74,7 @@ Campos numéricos/booleanos extras por combatente:
72
74
 
73
75
  ### `SystemRules` (opcional)
74
76
 
75
- Funções puras de roll/dano que vão além da notação `NdM±K`:
77
+ Funções puras de rolagem/dano que vão além da notação `NdM±K`:
76
78
 
77
79
  ```ts
78
80
  rules?: {
@@ -83,6 +85,25 @@ rules?: {
83
85
 
84
86
  `kind` é convenção do sistema (ex.: `'attack'`, `'save'`, `'damage'`).
85
87
 
88
+ ### `SystemNpcHooks` (opcional, v0.1.3+)
89
+
90
+ Hooks consumidos pelo [`@lippelt/srd-npcgen`](https://www.npmjs.com/package/@lippelt/srd-npcgen) pra refinar a geração de NPCs por sistema. Cada um é independente:
91
+
92
+ ```ts
93
+ npc?: {
94
+ /** Override da progressão de ataque (PF2: level + rank bonus). */
95
+ attackProgression?: (level: number, role: string) => number
96
+ /** Override do nº de dados de cantrip (PF2 heightening). */
97
+ cantripDamageDice?: (level: number) => number
98
+ /** Lista canônica de perícias do sistema. */
99
+ skills?: readonly string[]
100
+ /** Idiomas default pra um tipo de criatura no setting. */
101
+ defaultLanguages?: (creatureType: string) => string[]
102
+ }
103
+ ```
104
+
105
+ Sem hook, o npcgen usa defaults d20 genéricos.
106
+
86
107
  ## Sistemas implementados
87
108
 
88
109
  Veja o monorepo [gmcr-srd-systems](https://github.com/flippelt/gmcr-srd-systems): D&D 3.5, D&D 5e (2014/2024), Pathfinder 1e/2e, Starfinder 1e/2e, Lancer, GUMSHOE, Daggerheart, Candela Obscura.
package/dist/index.cjs CHANGED
@@ -23,9 +23,86 @@ __export(index_exports, {
23
23
  clearRegistry: () => clearRegistry,
24
24
  getSystem: () => getSystem,
25
25
  listRegisteredSystems: () => listRegisteredSystems,
26
- register: () => register
26
+ register: () => register,
27
+ validateSystem: () => validateSystem
27
28
  });
28
29
  module.exports = __toCommonJS(index_exports);
30
+
31
+ // src/validate.ts
32
+ var ID_RE = /^[a-z0-9][a-z0-9.-]*$/;
33
+ var TRACKER_KINDS = /* @__PURE__ */ new Set(["integer", "maxCurrent", "boolean"]);
34
+ var isNonEmptyString = (v) => typeof v === "string" && v.length > 0;
35
+ function validateSystem(sys) {
36
+ const errors = [];
37
+ const check = (ok, msg) => {
38
+ if (!ok) errors.push(msg);
39
+ };
40
+ check(isNonEmptyString(sys?.id), "id ausente ou vazio");
41
+ if (isNonEmptyString(sys?.id)) {
42
+ check(ID_RE.test(sys.id), `id "${sys.id}" deve ser min\xFAsculo (a-z 0-9 . -), sem espa\xE7os`);
43
+ }
44
+ check(isNonEmptyString(sys?.name), "name ausente ou vazio");
45
+ check(isNonEmptyString(sys?.ruleVersion), "ruleVersion ausente ou vazio");
46
+ if (!Array.isArray(sys?.dicePresets)) {
47
+ errors.push("dicePresets deve ser um array");
48
+ } else {
49
+ const seen = /* @__PURE__ */ new Set();
50
+ sys.dicePresets.forEach((p, i) => {
51
+ check(isNonEmptyString(p?.id), `dicePresets[${i}].id ausente ou vazio`);
52
+ check(isNonEmptyString(p?.label), `dicePresets[${i}].label ausente ou vazio`);
53
+ check(isNonEmptyString(p?.notation), `dicePresets[${i}].notation ausente ou vazio`);
54
+ if (isNonEmptyString(p?.id)) {
55
+ check(!seen.has(p.id), `dicePresets: id duplicado "${p.id}"`);
56
+ seen.add(p.id);
57
+ }
58
+ });
59
+ }
60
+ if (!Array.isArray(sys?.conditions)) {
61
+ errors.push("conditions deve ser um array");
62
+ } else {
63
+ const seen = /* @__PURE__ */ new Set();
64
+ sys.conditions.forEach((c, i) => {
65
+ check(isNonEmptyString(c?.id), `conditions[${i}].id ausente ou vazio`);
66
+ check(isNonEmptyString(c?.label), `conditions[${i}].label ausente ou vazio`);
67
+ if (isNonEmptyString(c?.id)) {
68
+ check(!seen.has(c.id), `conditions: id duplicado "${c.id}"`);
69
+ seen.add(c.id);
70
+ }
71
+ });
72
+ }
73
+ if (!Array.isArray(sys?.trackerFields)) {
74
+ errors.push("trackerFields deve ser um array");
75
+ } else {
76
+ const seen = /* @__PURE__ */ new Set();
77
+ sys.trackerFields.forEach((f, i) => {
78
+ check(isNonEmptyString(f?.key), `trackerFields[${i}].key ausente ou vazio`);
79
+ check(isNonEmptyString(f?.label), `trackerFields[${i}].label ausente ou vazio`);
80
+ check(
81
+ TRACKER_KINDS.has(f?.kind),
82
+ `trackerFields[${i}] (${f?.key ?? "?"}): kind inv\xE1lido "${f?.kind}"`
83
+ );
84
+ if (isNonEmptyString(f?.key)) {
85
+ check(!seen.has(f.key), `trackerFields: key duplicada "${f.key}"`);
86
+ seen.add(f.key);
87
+ }
88
+ const { min, max, default: def } = f ?? {};
89
+ if (typeof min === "number" && typeof max === "number") {
90
+ check(min <= max, `trackerFields[${i}] (${f.key}): min (${min}) > max (${max})`);
91
+ }
92
+ if (typeof def === "number") {
93
+ if (typeof min === "number") {
94
+ check(def >= min, `trackerFields[${i}] (${f.key}): default (${def}) < min (${min})`);
95
+ }
96
+ if (typeof max === "number") {
97
+ check(def <= max, `trackerFields[${i}] (${f.key}): default (${def}) > max (${max})`);
98
+ }
99
+ }
100
+ });
101
+ }
102
+ return { valid: errors.length === 0, errors };
103
+ }
104
+
105
+ // src/index.ts
29
106
  var registry = /* @__PURE__ */ new Map();
30
107
  function register(system) {
31
108
  const existing = registry.get(system.id);
@@ -50,6 +127,7 @@ function clearRegistry() {
50
127
  clearRegistry,
51
128
  getSystem,
52
129
  listRegisteredSystems,
53
- register
130
+ register,
131
+ validateSystem
54
132
  });
55
133
  //# sourceMappingURL=index.cjs.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/index.ts"],"sourcesContent":["/**\n * @lippelt/srd-core — contrato + registry para sistemas RPG plugáveis.\n *\n * Padrão de uso (lado do consumidor):\n *\n * import { register, getSystem } from '@lippelt/srd-core'\n * import { dnd5e2014 } from '@lippelt/srd-dnd5e-2014'\n *\n * register(dnd5e2014)\n * const sys = getSystem('dnd5e-2014') // System | null\n */\n\nexport type {\n System,\n SystemId,\n SystemRules,\n DicePreset,\n ConditionDef,\n TrackerField,\n RollResult,\n} from './types.js'\n\nimport type { System, SystemId } from './types.js'\n\nconst registry = new Map<SystemId, System>()\n\n/**\n * Registra um sistema. Idempotente: registrar o mesmo `system` (mesma\n * referência) duas vezes é no-op. Registrar uma instância DIFERENTE com\n * id já existente lança erro — proteção contra conflitos.\n */\nexport function register(system: System): void {\n const existing = registry.get(system.id)\n if (existing && existing !== system) {\n throw new Error(\n `[gmcr-srd-core] sistema \"${system.id}\" já registrado por outra instância`,\n )\n }\n registry.set(system.id, system)\n}\n\n/** Resolve um sistema pelo id, ou null se não registrado. */\nexport function getSystem(id: SystemId): System | null {\n return registry.get(id) ?? null\n}\n\n/** Lista os ids de sistemas atualmente registrados. */\nexport function listRegisteredSystems(): SystemId[] {\n return [...registry.keys()]\n}\n\n/** Remove todos os registros. Útil em testes; raro em produção. */\nexport function clearRegistry(): void {\n registry.clear()\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAwBA,IAAM,WAAW,oBAAI,IAAsB;AAOpC,SAAS,SAAS,QAAsB;AAC7C,QAAM,WAAW,SAAS,IAAI,OAAO,EAAE;AACvC,MAAI,YAAY,aAAa,QAAQ;AACnC,UAAM,IAAI;AAAA,MACR,4BAA4B,OAAO,EAAE;AAAA,IACvC;AAAA,EACF;AACA,WAAS,IAAI,OAAO,IAAI,MAAM;AAChC;AAGO,SAAS,UAAU,IAA6B;AACrD,SAAO,SAAS,IAAI,EAAE,KAAK;AAC7B;AAGO,SAAS,wBAAoC;AAClD,SAAO,CAAC,GAAG,SAAS,KAAK,CAAC;AAC5B;AAGO,SAAS,gBAAsB;AACpC,WAAS,MAAM;AACjB;","names":[]}
1
+ {"version":3,"sources":["../src/index.ts","../src/validate.ts"],"sourcesContent":["/**\n * @lippelt/srd-core — contrato + registry para sistemas RPG plugáveis.\n *\n * Padrão de uso (lado do consumidor):\n *\n * import { register, getSystem } from '@lippelt/srd-core'\n * import { dnd5e2014 } from '@lippelt/srd-dnd5e-2014'\n *\n * register(dnd5e2014)\n * const sys = getSystem('dnd5e-2014') // System | null\n */\n\nexport type {\n System,\n SystemId,\n SystemRules,\n SystemNpcHooks,\n DicePreset,\n ConditionDef,\n TrackerField,\n RollResult,\n} from './types.js'\n\nexport { validateSystem } from './validate.js'\nexport type { SystemValidationResult } from './validate.js'\n\nimport type { System, SystemId } from './types.js'\n\nconst registry = new Map<SystemId, System>()\n\n/**\n * Registra um sistema. Idempotente: registrar o mesmo `system` (mesma\n * referência) duas vezes é no-op. Registrar uma instância DIFERENTE com\n * id já existente lança erro — proteção contra conflitos.\n */\nexport function register(system: System): void {\n const existing = registry.get(system.id)\n if (existing && existing !== system) {\n throw new Error(\n `[gmcr-srd-core] sistema \"${system.id}\" já registrado por outra instância`,\n )\n }\n registry.set(system.id, system)\n}\n\n/** Resolve um sistema pelo id, ou null se não registrado. */\nexport function getSystem(id: SystemId): System | null {\n return registry.get(id) ?? null\n}\n\n/** Lista os ids de sistemas atualmente registrados. */\nexport function listRegisteredSystems(): SystemId[] {\n return [...registry.keys()]\n}\n\n/** Remove todos os registros. Útil em testes; raro em produção. */\nexport function clearRegistry(): void {\n registry.clear()\n}\n","/**\n * Validação de integridade de um `System`.\n *\n * Garante que um pacote de sistema cumpre o contrato antes de ser registrado:\n * campos obrigatórios presentes, ids/keys únicos e não-vazios, `kind` de\n * tracker válido e limites (min ≤ default ≤ max) coerentes. Pura — não\n * registra nada nem toca em estado global.\n *\n * Serve tanto para o consumidor (validar na hora de `register`) quanto como\n * rede de segurança nos testes de cada pacote de sistema.\n */\nimport type { System } from './types.js'\n\nexport interface SystemValidationResult {\n valid: boolean\n errors: string[]\n}\n\n// Ids estáveis: minúsculas, dígitos, hífen e ponto (ex.: 'dnd-3.5',\n// 'pathfinder-2e', 'lancer'). Sem espaços nem maiúsculas.\nconst ID_RE = /^[a-z0-9][a-z0-9.-]*$/\nconst TRACKER_KINDS = new Set(['integer', 'maxCurrent', 'boolean'])\n\nconst isNonEmptyString = (v: unknown): v is string =>\n typeof v === 'string' && v.length > 0\n\nexport function validateSystem(sys: System): SystemValidationResult {\n const errors: string[] = []\n const check = (ok: boolean, msg: string) => {\n if (!ok) errors.push(msg)\n }\n\n // --- Identidade ---\n check(isNonEmptyString(sys?.id), 'id ausente ou vazio')\n if (isNonEmptyString(sys?.id)) {\n check(ID_RE.test(sys.id), `id \"${sys.id}\" deve ser minúsculo (a-z 0-9 . -), sem espaços`)\n }\n check(isNonEmptyString(sys?.name), 'name ausente ou vazio')\n check(isNonEmptyString(sys?.ruleVersion), 'ruleVersion ausente ou vazio')\n\n // --- Dice presets (id único; id/label/notation obrigatórios) ---\n if (!Array.isArray(sys?.dicePresets)) {\n errors.push('dicePresets deve ser um array')\n } else {\n const seen = new Set<string>()\n sys.dicePresets.forEach((p, i) => {\n check(isNonEmptyString(p?.id), `dicePresets[${i}].id ausente ou vazio`)\n check(isNonEmptyString(p?.label), `dicePresets[${i}].label ausente ou vazio`)\n check(isNonEmptyString(p?.notation), `dicePresets[${i}].notation ausente ou vazio`)\n if (isNonEmptyString(p?.id)) {\n check(!seen.has(p.id), `dicePresets: id duplicado \"${p.id}\"`)\n seen.add(p.id)\n }\n })\n }\n\n // --- Conditions (id único; id/label obrigatórios) ---\n if (!Array.isArray(sys?.conditions)) {\n errors.push('conditions deve ser um array')\n } else {\n const seen = new Set<string>()\n sys.conditions.forEach((c, i) => {\n check(isNonEmptyString(c?.id), `conditions[${i}].id ausente ou vazio`)\n check(isNonEmptyString(c?.label), `conditions[${i}].label ausente ou vazio`)\n if (isNonEmptyString(c?.id)) {\n check(!seen.has(c.id), `conditions: id duplicado \"${c.id}\"`)\n seen.add(c.id)\n }\n })\n }\n\n // --- Tracker fields (key única; kind válido; min ≤ default ≤ max) ---\n if (!Array.isArray(sys?.trackerFields)) {\n errors.push('trackerFields deve ser um array')\n } else {\n const seen = new Set<string>()\n sys.trackerFields.forEach((f, i) => {\n check(isNonEmptyString(f?.key), `trackerFields[${i}].key ausente ou vazio`)\n check(isNonEmptyString(f?.label), `trackerFields[${i}].label ausente ou vazio`)\n check(\n TRACKER_KINDS.has(f?.kind as string),\n `trackerFields[${i}] (${f?.key ?? '?'}): kind inválido \"${f?.kind}\"`,\n )\n if (isNonEmptyString(f?.key)) {\n check(!seen.has(f.key), `trackerFields: key duplicada \"${f.key}\"`)\n seen.add(f.key)\n }\n const { min, max, default: def } = f ?? {}\n if (typeof min === 'number' && typeof max === 'number') {\n check(min <= max, `trackerFields[${i}] (${f.key}): min (${min}) > max (${max})`)\n }\n if (typeof def === 'number') {\n if (typeof min === 'number') {\n check(def >= min, `trackerFields[${i}] (${f.key}): default (${def}) < min (${min})`)\n }\n if (typeof max === 'number') {\n check(def <= max, `trackerFields[${i}] (${f.key}): default (${def}) > max (${max})`)\n }\n }\n })\n }\n\n return { valid: errors.length === 0, errors }\n}\n"],"mappings":"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","names":[]}
package/dist/index.d.cts CHANGED
@@ -82,6 +82,45 @@ interface SystemRules {
82
82
  notes?: string[];
83
83
  };
84
84
  }
85
+ /**
86
+ * Hooks opcionais para refinar a geração de NPCs por sistema. Quando o
87
+ * `@lippelt/srd-npcgen` encontra um destes preenchidos em `System.npc`,
88
+ * usa em vez dos defaults genéricos da família d20.
89
+ *
90
+ * Cada hook é puro e independente — implemente só os que fizerem sentido
91
+ * pra mecânica do seu sistema.
92
+ */
93
+ interface SystemNpcHooks {
94
+ /**
95
+ * Override da progressão de ataque (default 5e: prof = 2 + ⌊(lvl−1)/4⌋).
96
+ *
97
+ * PF2e/SF2e devem retornar `level + bônus de patente` (rank bonus):
98
+ * trained +2, expert +4, master +6, legendary +8.
99
+ *
100
+ * `role` é o id do arquétipo (ex.: 'soldier', 'caster').
101
+ */
102
+ attackProgression?: (level: number, role: string) => number;
103
+ /**
104
+ * Override da quantidade de dados de cantrip pra casters. Default 5e:
105
+ * 1 (lvl 1-4) → 2 (5-10) → 3 (11-16) → 4 (17+).
106
+ *
107
+ * PF2e segue padrão diferente (heightening de cantrips a cada 2 níveis).
108
+ */
109
+ cantripDamageDice?: (level: number) => number;
110
+ /**
111
+ * Lista canônica de perícias do sistema (snake-case ou camelCase). O
112
+ * npcgen pode usar pra validar/expandir o set de perícias proficient
113
+ * por arquétipo.
114
+ */
115
+ skills?: readonly string[];
116
+ /**
117
+ * Idiomas default pra um tipo de criatura no setting do sistema. Quando
118
+ * preenchido, sobrescreve o default genérico do npcgen.
119
+ *
120
+ * Útil pra settings com idiomas exóticos (ex.: SF tem Vesk, Ysoki etc.).
121
+ */
122
+ defaultLanguages?: (creatureType: string) => string[];
123
+ }
85
124
  interface System {
86
125
  id: SystemId;
87
126
  /** Nome humano (ex: "Dungeons & Dragons 5e (2014)"). */
@@ -98,7 +137,27 @@ interface System {
98
137
  trackerFields: TrackerField[];
99
138
  /** Regras automatizáveis (opcionais). */
100
139
  rules?: SystemRules;
140
+ /** Hooks pra refinar a geração de NPCs (consumidos pelo @lippelt/srd-npcgen). */
141
+ npc?: SystemNpcHooks;
142
+ }
143
+
144
+ /**
145
+ * Validação de integridade de um `System`.
146
+ *
147
+ * Garante que um pacote de sistema cumpre o contrato antes de ser registrado:
148
+ * campos obrigatórios presentes, ids/keys únicos e não-vazios, `kind` de
149
+ * tracker válido e limites (min ≤ default ≤ max) coerentes. Pura — não
150
+ * registra nada nem toca em estado global.
151
+ *
152
+ * Serve tanto para o consumidor (validar na hora de `register`) quanto como
153
+ * rede de segurança nos testes de cada pacote de sistema.
154
+ */
155
+
156
+ interface SystemValidationResult {
157
+ valid: boolean;
158
+ errors: string[];
101
159
  }
160
+ declare function validateSystem(sys: System): SystemValidationResult;
102
161
 
103
162
  /**
104
163
  * @lippelt/srd-core — contrato + registry para sistemas RPG plugáveis.
@@ -125,4 +184,4 @@ declare function listRegisteredSystems(): SystemId[];
125
184
  /** Remove todos os registros. Útil em testes; raro em produção. */
126
185
  declare function clearRegistry(): void;
127
186
 
128
- export { type ConditionDef, type DicePreset, type RollResult, type System, type SystemId, type SystemRules, type TrackerField, clearRegistry, getSystem, listRegisteredSystems, register };
187
+ export { type ConditionDef, type DicePreset, type RollResult, type System, type SystemId, type SystemNpcHooks, type SystemRules, type SystemValidationResult, type TrackerField, clearRegistry, getSystem, listRegisteredSystems, register, validateSystem };
package/dist/index.d.ts CHANGED
@@ -82,6 +82,45 @@ interface SystemRules {
82
82
  notes?: string[];
83
83
  };
84
84
  }
85
+ /**
86
+ * Hooks opcionais para refinar a geração de NPCs por sistema. Quando o
87
+ * `@lippelt/srd-npcgen` encontra um destes preenchidos em `System.npc`,
88
+ * usa em vez dos defaults genéricos da família d20.
89
+ *
90
+ * Cada hook é puro e independente — implemente só os que fizerem sentido
91
+ * pra mecânica do seu sistema.
92
+ */
93
+ interface SystemNpcHooks {
94
+ /**
95
+ * Override da progressão de ataque (default 5e: prof = 2 + ⌊(lvl−1)/4⌋).
96
+ *
97
+ * PF2e/SF2e devem retornar `level + bônus de patente` (rank bonus):
98
+ * trained +2, expert +4, master +6, legendary +8.
99
+ *
100
+ * `role` é o id do arquétipo (ex.: 'soldier', 'caster').
101
+ */
102
+ attackProgression?: (level: number, role: string) => number;
103
+ /**
104
+ * Override da quantidade de dados de cantrip pra casters. Default 5e:
105
+ * 1 (lvl 1-4) → 2 (5-10) → 3 (11-16) → 4 (17+).
106
+ *
107
+ * PF2e segue padrão diferente (heightening de cantrips a cada 2 níveis).
108
+ */
109
+ cantripDamageDice?: (level: number) => number;
110
+ /**
111
+ * Lista canônica de perícias do sistema (snake-case ou camelCase). O
112
+ * npcgen pode usar pra validar/expandir o set de perícias proficient
113
+ * por arquétipo.
114
+ */
115
+ skills?: readonly string[];
116
+ /**
117
+ * Idiomas default pra um tipo de criatura no setting do sistema. Quando
118
+ * preenchido, sobrescreve o default genérico do npcgen.
119
+ *
120
+ * Útil pra settings com idiomas exóticos (ex.: SF tem Vesk, Ysoki etc.).
121
+ */
122
+ defaultLanguages?: (creatureType: string) => string[];
123
+ }
85
124
  interface System {
86
125
  id: SystemId;
87
126
  /** Nome humano (ex: "Dungeons & Dragons 5e (2014)"). */
@@ -98,7 +137,27 @@ interface System {
98
137
  trackerFields: TrackerField[];
99
138
  /** Regras automatizáveis (opcionais). */
100
139
  rules?: SystemRules;
140
+ /** Hooks pra refinar a geração de NPCs (consumidos pelo @lippelt/srd-npcgen). */
141
+ npc?: SystemNpcHooks;
142
+ }
143
+
144
+ /**
145
+ * Validação de integridade de um `System`.
146
+ *
147
+ * Garante que um pacote de sistema cumpre o contrato antes de ser registrado:
148
+ * campos obrigatórios presentes, ids/keys únicos e não-vazios, `kind` de
149
+ * tracker válido e limites (min ≤ default ≤ max) coerentes. Pura — não
150
+ * registra nada nem toca em estado global.
151
+ *
152
+ * Serve tanto para o consumidor (validar na hora de `register`) quanto como
153
+ * rede de segurança nos testes de cada pacote de sistema.
154
+ */
155
+
156
+ interface SystemValidationResult {
157
+ valid: boolean;
158
+ errors: string[];
101
159
  }
160
+ declare function validateSystem(sys: System): SystemValidationResult;
102
161
 
103
162
  /**
104
163
  * @lippelt/srd-core — contrato + registry para sistemas RPG plugáveis.
@@ -125,4 +184,4 @@ declare function listRegisteredSystems(): SystemId[];
125
184
  /** Remove todos os registros. Útil em testes; raro em produção. */
126
185
  declare function clearRegistry(): void;
127
186
 
128
- export { type ConditionDef, type DicePreset, type RollResult, type System, type SystemId, type SystemRules, type TrackerField, clearRegistry, getSystem, listRegisteredSystems, register };
187
+ export { type ConditionDef, type DicePreset, type RollResult, type System, type SystemId, type SystemNpcHooks, type SystemRules, type SystemValidationResult, type TrackerField, clearRegistry, getSystem, listRegisteredSystems, register, validateSystem };
package/dist/index.js CHANGED
@@ -1,3 +1,77 @@
1
+ // src/validate.ts
2
+ var ID_RE = /^[a-z0-9][a-z0-9.-]*$/;
3
+ var TRACKER_KINDS = /* @__PURE__ */ new Set(["integer", "maxCurrent", "boolean"]);
4
+ var isNonEmptyString = (v) => typeof v === "string" && v.length > 0;
5
+ function validateSystem(sys) {
6
+ const errors = [];
7
+ const check = (ok, msg) => {
8
+ if (!ok) errors.push(msg);
9
+ };
10
+ check(isNonEmptyString(sys?.id), "id ausente ou vazio");
11
+ if (isNonEmptyString(sys?.id)) {
12
+ check(ID_RE.test(sys.id), `id "${sys.id}" deve ser min\xFAsculo (a-z 0-9 . -), sem espa\xE7os`);
13
+ }
14
+ check(isNonEmptyString(sys?.name), "name ausente ou vazio");
15
+ check(isNonEmptyString(sys?.ruleVersion), "ruleVersion ausente ou vazio");
16
+ if (!Array.isArray(sys?.dicePresets)) {
17
+ errors.push("dicePresets deve ser um array");
18
+ } else {
19
+ const seen = /* @__PURE__ */ new Set();
20
+ sys.dicePresets.forEach((p, i) => {
21
+ check(isNonEmptyString(p?.id), `dicePresets[${i}].id ausente ou vazio`);
22
+ check(isNonEmptyString(p?.label), `dicePresets[${i}].label ausente ou vazio`);
23
+ check(isNonEmptyString(p?.notation), `dicePresets[${i}].notation ausente ou vazio`);
24
+ if (isNonEmptyString(p?.id)) {
25
+ check(!seen.has(p.id), `dicePresets: id duplicado "${p.id}"`);
26
+ seen.add(p.id);
27
+ }
28
+ });
29
+ }
30
+ if (!Array.isArray(sys?.conditions)) {
31
+ errors.push("conditions deve ser um array");
32
+ } else {
33
+ const seen = /* @__PURE__ */ new Set();
34
+ sys.conditions.forEach((c, i) => {
35
+ check(isNonEmptyString(c?.id), `conditions[${i}].id ausente ou vazio`);
36
+ check(isNonEmptyString(c?.label), `conditions[${i}].label ausente ou vazio`);
37
+ if (isNonEmptyString(c?.id)) {
38
+ check(!seen.has(c.id), `conditions: id duplicado "${c.id}"`);
39
+ seen.add(c.id);
40
+ }
41
+ });
42
+ }
43
+ if (!Array.isArray(sys?.trackerFields)) {
44
+ errors.push("trackerFields deve ser um array");
45
+ } else {
46
+ const seen = /* @__PURE__ */ new Set();
47
+ sys.trackerFields.forEach((f, i) => {
48
+ check(isNonEmptyString(f?.key), `trackerFields[${i}].key ausente ou vazio`);
49
+ check(isNonEmptyString(f?.label), `trackerFields[${i}].label ausente ou vazio`);
50
+ check(
51
+ TRACKER_KINDS.has(f?.kind),
52
+ `trackerFields[${i}] (${f?.key ?? "?"}): kind inv\xE1lido "${f?.kind}"`
53
+ );
54
+ if (isNonEmptyString(f?.key)) {
55
+ check(!seen.has(f.key), `trackerFields: key duplicada "${f.key}"`);
56
+ seen.add(f.key);
57
+ }
58
+ const { min, max, default: def } = f ?? {};
59
+ if (typeof min === "number" && typeof max === "number") {
60
+ check(min <= max, `trackerFields[${i}] (${f.key}): min (${min}) > max (${max})`);
61
+ }
62
+ if (typeof def === "number") {
63
+ if (typeof min === "number") {
64
+ check(def >= min, `trackerFields[${i}] (${f.key}): default (${def}) < min (${min})`);
65
+ }
66
+ if (typeof max === "number") {
67
+ check(def <= max, `trackerFields[${i}] (${f.key}): default (${def}) > max (${max})`);
68
+ }
69
+ }
70
+ });
71
+ }
72
+ return { valid: errors.length === 0, errors };
73
+ }
74
+
1
75
  // src/index.ts
2
76
  var registry = /* @__PURE__ */ new Map();
3
77
  function register(system) {
@@ -22,6 +96,7 @@ export {
22
96
  clearRegistry,
23
97
  getSystem,
24
98
  listRegisteredSystems,
25
- register
99
+ register,
100
+ validateSystem
26
101
  };
27
102
  //# sourceMappingURL=index.js.map
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/index.ts"],"sourcesContent":["/**\n * @lippelt/srd-core — contrato + registry para sistemas RPG plugáveis.\n *\n * Padrão de uso (lado do consumidor):\n *\n * import { register, getSystem } from '@lippelt/srd-core'\n * import { dnd5e2014 } from '@lippelt/srd-dnd5e-2014'\n *\n * register(dnd5e2014)\n * const sys = getSystem('dnd5e-2014') // System | null\n */\n\nexport type {\n System,\n SystemId,\n SystemRules,\n DicePreset,\n ConditionDef,\n TrackerField,\n RollResult,\n} from './types.js'\n\nimport type { System, SystemId } from './types.js'\n\nconst registry = new Map<SystemId, System>()\n\n/**\n * Registra um sistema. Idempotente: registrar o mesmo `system` (mesma\n * referência) duas vezes é no-op. Registrar uma instância DIFERENTE com\n * id já existente lança erro — proteção contra conflitos.\n */\nexport function register(system: System): void {\n const existing = registry.get(system.id)\n if (existing && existing !== system) {\n throw new Error(\n `[gmcr-srd-core] sistema \"${system.id}\" já registrado por outra instância`,\n )\n }\n registry.set(system.id, system)\n}\n\n/** Resolve um sistema pelo id, ou null se não registrado. */\nexport function getSystem(id: SystemId): System | null {\n return registry.get(id) ?? null\n}\n\n/** Lista os ids de sistemas atualmente registrados. */\nexport function listRegisteredSystems(): SystemId[] {\n return [...registry.keys()]\n}\n\n/** Remove todos os registros. Útil em testes; raro em produção. */\nexport function clearRegistry(): void {\n registry.clear()\n}\n"],"mappings":";AAwBA,IAAM,WAAW,oBAAI,IAAsB;AAOpC,SAAS,SAAS,QAAsB;AAC7C,QAAM,WAAW,SAAS,IAAI,OAAO,EAAE;AACvC,MAAI,YAAY,aAAa,QAAQ;AACnC,UAAM,IAAI;AAAA,MACR,4BAA4B,OAAO,EAAE;AAAA,IACvC;AAAA,EACF;AACA,WAAS,IAAI,OAAO,IAAI,MAAM;AAChC;AAGO,SAAS,UAAU,IAA6B;AACrD,SAAO,SAAS,IAAI,EAAE,KAAK;AAC7B;AAGO,SAAS,wBAAoC;AAClD,SAAO,CAAC,GAAG,SAAS,KAAK,CAAC;AAC5B;AAGO,SAAS,gBAAsB;AACpC,WAAS,MAAM;AACjB;","names":[]}
1
+ {"version":3,"sources":["../src/validate.ts","../src/index.ts"],"sourcesContent":["/**\n * Validação de integridade de um `System`.\n *\n * Garante que um pacote de sistema cumpre o contrato antes de ser registrado:\n * campos obrigatórios presentes, ids/keys únicos e não-vazios, `kind` de\n * tracker válido e limites (min ≤ default ≤ max) coerentes. Pura — não\n * registra nada nem toca em estado global.\n *\n * Serve tanto para o consumidor (validar na hora de `register`) quanto como\n * rede de segurança nos testes de cada pacote de sistema.\n */\nimport type { System } from './types.js'\n\nexport interface SystemValidationResult {\n valid: boolean\n errors: string[]\n}\n\n// Ids estáveis: minúsculas, dígitos, hífen e ponto (ex.: 'dnd-3.5',\n// 'pathfinder-2e', 'lancer'). Sem espaços nem maiúsculas.\nconst ID_RE = /^[a-z0-9][a-z0-9.-]*$/\nconst TRACKER_KINDS = new Set(['integer', 'maxCurrent', 'boolean'])\n\nconst isNonEmptyString = (v: unknown): v is string =>\n typeof v === 'string' && v.length > 0\n\nexport function validateSystem(sys: System): SystemValidationResult {\n const errors: string[] = []\n const check = (ok: boolean, msg: string) => {\n if (!ok) errors.push(msg)\n }\n\n // --- Identidade ---\n check(isNonEmptyString(sys?.id), 'id ausente ou vazio')\n if (isNonEmptyString(sys?.id)) {\n check(ID_RE.test(sys.id), `id \"${sys.id}\" deve ser minúsculo (a-z 0-9 . -), sem espaços`)\n }\n check(isNonEmptyString(sys?.name), 'name ausente ou vazio')\n check(isNonEmptyString(sys?.ruleVersion), 'ruleVersion ausente ou vazio')\n\n // --- Dice presets (id único; id/label/notation obrigatórios) ---\n if (!Array.isArray(sys?.dicePresets)) {\n errors.push('dicePresets deve ser um array')\n } else {\n const seen = new Set<string>()\n sys.dicePresets.forEach((p, i) => {\n check(isNonEmptyString(p?.id), `dicePresets[${i}].id ausente ou vazio`)\n check(isNonEmptyString(p?.label), `dicePresets[${i}].label ausente ou vazio`)\n check(isNonEmptyString(p?.notation), `dicePresets[${i}].notation ausente ou vazio`)\n if (isNonEmptyString(p?.id)) {\n check(!seen.has(p.id), `dicePresets: id duplicado \"${p.id}\"`)\n seen.add(p.id)\n }\n })\n }\n\n // --- Conditions (id único; id/label obrigatórios) ---\n if (!Array.isArray(sys?.conditions)) {\n errors.push('conditions deve ser um array')\n } else {\n const seen = new Set<string>()\n sys.conditions.forEach((c, i) => {\n check(isNonEmptyString(c?.id), `conditions[${i}].id ausente ou vazio`)\n check(isNonEmptyString(c?.label), `conditions[${i}].label ausente ou vazio`)\n if (isNonEmptyString(c?.id)) {\n check(!seen.has(c.id), `conditions: id duplicado \"${c.id}\"`)\n seen.add(c.id)\n }\n })\n }\n\n // --- Tracker fields (key única; kind válido; min ≤ default ≤ max) ---\n if (!Array.isArray(sys?.trackerFields)) {\n errors.push('trackerFields deve ser um array')\n } else {\n const seen = new Set<string>()\n sys.trackerFields.forEach((f, i) => {\n check(isNonEmptyString(f?.key), `trackerFields[${i}].key ausente ou vazio`)\n check(isNonEmptyString(f?.label), `trackerFields[${i}].label ausente ou vazio`)\n check(\n TRACKER_KINDS.has(f?.kind as string),\n `trackerFields[${i}] (${f?.key ?? '?'}): kind inválido \"${f?.kind}\"`,\n )\n if (isNonEmptyString(f?.key)) {\n check(!seen.has(f.key), `trackerFields: key duplicada \"${f.key}\"`)\n seen.add(f.key)\n }\n const { min, max, default: def } = f ?? {}\n if (typeof min === 'number' && typeof max === 'number') {\n check(min <= max, `trackerFields[${i}] (${f.key}): min (${min}) > max (${max})`)\n }\n if (typeof def === 'number') {\n if (typeof min === 'number') {\n check(def >= min, `trackerFields[${i}] (${f.key}): default (${def}) < min (${min})`)\n }\n if (typeof max === 'number') {\n check(def <= max, `trackerFields[${i}] (${f.key}): default (${def}) > max (${max})`)\n }\n }\n })\n }\n\n return { valid: errors.length === 0, errors }\n}\n","/**\n * @lippelt/srd-core — contrato + registry para sistemas RPG plugáveis.\n *\n * Padrão de uso (lado do consumidor):\n *\n * import { register, getSystem } from '@lippelt/srd-core'\n * import { dnd5e2014 } from '@lippelt/srd-dnd5e-2014'\n *\n * register(dnd5e2014)\n * const sys = getSystem('dnd5e-2014') // System | null\n */\n\nexport type {\n System,\n SystemId,\n SystemRules,\n SystemNpcHooks,\n DicePreset,\n ConditionDef,\n TrackerField,\n RollResult,\n} from './types.js'\n\nexport { validateSystem } from './validate.js'\nexport type { SystemValidationResult } from './validate.js'\n\nimport type { System, SystemId } from './types.js'\n\nconst registry = new Map<SystemId, System>()\n\n/**\n * Registra um sistema. Idempotente: registrar o mesmo `system` (mesma\n * referência) duas vezes é no-op. Registrar uma instância DIFERENTE com\n * id já existente lança erro — proteção contra conflitos.\n */\nexport function register(system: System): void {\n const existing = registry.get(system.id)\n if (existing && existing !== system) {\n throw new Error(\n `[gmcr-srd-core] sistema \"${system.id}\" já registrado por outra instância`,\n )\n }\n registry.set(system.id, system)\n}\n\n/** Resolve um sistema pelo id, ou null se não registrado. */\nexport function getSystem(id: SystemId): System | null {\n return registry.get(id) ?? null\n}\n\n/** Lista os ids de sistemas atualmente registrados. */\nexport function listRegisteredSystems(): SystemId[] {\n return [...registry.keys()]\n}\n\n/** Remove todos os registros. Útil em testes; raro em produção. */\nexport function clearRegistry(): void {\n registry.clear()\n}\n"],"mappings":";AAoBA,IAAM,QAAQ;AACd,IAAM,gBAAgB,oBAAI,IAAI,CAAC,WAAW,cAAc,SAAS,CAAC;AAElE,IAAM,mBAAmB,CAAC,MACxB,OAAO,MAAM,YAAY,EAAE,SAAS;AAE/B,SAAS,eAAe,KAAqC;AAClE,QAAM,SAAmB,CAAC;AAC1B,QAAM,QAAQ,CAAC,IAAa,QAAgB;AAC1C,QAAI,CAAC,GAAI,QAAO,KAAK,GAAG;AAAA,EAC1B;AAGA,QAAM,iBAAiB,KAAK,EAAE,GAAG,qBAAqB;AACtD,MAAI,iBAAiB,KAAK,EAAE,GAAG;AAC7B,UAAM,MAAM,KAAK,IAAI,EAAE,GAAG,OAAO,IAAI,EAAE,uDAAiD;AAAA,EAC1F;AACA,QAAM,iBAAiB,KAAK,IAAI,GAAG,uBAAuB;AAC1D,QAAM,iBAAiB,KAAK,WAAW,GAAG,8BAA8B;AAGxE,MAAI,CAAC,MAAM,QAAQ,KAAK,WAAW,GAAG;AACpC,WAAO,KAAK,+BAA+B;AAAA,EAC7C,OAAO;AACL,UAAM,OAAO,oBAAI,IAAY;AAC7B,QAAI,YAAY,QAAQ,CAAC,GAAG,MAAM;AAChC,YAAM,iBAAiB,GAAG,EAAE,GAAG,eAAe,CAAC,uBAAuB;AACtE,YAAM,iBAAiB,GAAG,KAAK,GAAG,eAAe,CAAC,0BAA0B;AAC5E,YAAM,iBAAiB,GAAG,QAAQ,GAAG,eAAe,CAAC,6BAA6B;AAClF,UAAI,iBAAiB,GAAG,EAAE,GAAG;AAC3B,cAAM,CAAC,KAAK,IAAI,EAAE,EAAE,GAAG,8BAA8B,EAAE,EAAE,GAAG;AAC5D,aAAK,IAAI,EAAE,EAAE;AAAA,MACf;AAAA,IACF,CAAC;AAAA,EACH;AAGA,MAAI,CAAC,MAAM,QAAQ,KAAK,UAAU,GAAG;AACnC,WAAO,KAAK,8BAA8B;AAAA,EAC5C,OAAO;AACL,UAAM,OAAO,oBAAI,IAAY;AAC7B,QAAI,WAAW,QAAQ,CAAC,GAAG,MAAM;AAC/B,YAAM,iBAAiB,GAAG,EAAE,GAAG,cAAc,CAAC,uBAAuB;AACrE,YAAM,iBAAiB,GAAG,KAAK,GAAG,cAAc,CAAC,0BAA0B;AAC3E,UAAI,iBAAiB,GAAG,EAAE,GAAG;AAC3B,cAAM,CAAC,KAAK,IAAI,EAAE,EAAE,GAAG,6BAA6B,EAAE,EAAE,GAAG;AAC3D,aAAK,IAAI,EAAE,EAAE;AAAA,MACf;AAAA,IACF,CAAC;AAAA,EACH;AAGA,MAAI,CAAC,MAAM,QAAQ,KAAK,aAAa,GAAG;AACtC,WAAO,KAAK,iCAAiC;AAAA,EAC/C,OAAO;AACL,UAAM,OAAO,oBAAI,IAAY;AAC7B,QAAI,cAAc,QAAQ,CAAC,GAAG,MAAM;AAClC,YAAM,iBAAiB,GAAG,GAAG,GAAG,iBAAiB,CAAC,wBAAwB;AAC1E,YAAM,iBAAiB,GAAG,KAAK,GAAG,iBAAiB,CAAC,0BAA0B;AAC9E;AAAA,QACE,cAAc,IAAI,GAAG,IAAc;AAAA,QACnC,iBAAiB,CAAC,MAAM,GAAG,OAAO,GAAG,wBAAqB,GAAG,IAAI;AAAA,MACnE;AACA,UAAI,iBAAiB,GAAG,GAAG,GAAG;AAC5B,cAAM,CAAC,KAAK,IAAI,EAAE,GAAG,GAAG,iCAAiC,EAAE,GAAG,GAAG;AACjE,aAAK,IAAI,EAAE,GAAG;AAAA,MAChB;AACA,YAAM,EAAE,KAAK,KAAK,SAAS,IAAI,IAAI,KAAK,CAAC;AACzC,UAAI,OAAO,QAAQ,YAAY,OAAO,QAAQ,UAAU;AACtD,cAAM,OAAO,KAAK,iBAAiB,CAAC,MAAM,EAAE,GAAG,WAAW,GAAG,YAAY,GAAG,GAAG;AAAA,MACjF;AACA,UAAI,OAAO,QAAQ,UAAU;AAC3B,YAAI,OAAO,QAAQ,UAAU;AAC3B,gBAAM,OAAO,KAAK,iBAAiB,CAAC,MAAM,EAAE,GAAG,eAAe,GAAG,YAAY,GAAG,GAAG;AAAA,QACrF;AACA,YAAI,OAAO,QAAQ,UAAU;AAC3B,gBAAM,OAAO,KAAK,iBAAiB,CAAC,MAAM,EAAE,GAAG,eAAe,GAAG,YAAY,GAAG,GAAG;AAAA,QACrF;AAAA,MACF;AAAA,IACF,CAAC;AAAA,EACH;AAEA,SAAO,EAAE,OAAO,OAAO,WAAW,GAAG,OAAO;AAC9C;;;AC3EA,IAAM,WAAW,oBAAI,IAAsB;AAOpC,SAAS,SAAS,QAAsB;AAC7C,QAAM,WAAW,SAAS,IAAI,OAAO,EAAE;AACvC,MAAI,YAAY,aAAa,QAAQ;AACnC,UAAM,IAAI;AAAA,MACR,4BAA4B,OAAO,EAAE;AAAA,IACvC;AAAA,EACF;AACA,WAAS,IAAI,OAAO,IAAI,MAAM;AAChC;AAGO,SAAS,UAAU,IAA6B;AACrD,SAAO,SAAS,IAAI,EAAE,KAAK;AAC7B;AAGO,SAAS,wBAAoC;AAClD,SAAO,CAAC,GAAG,SAAS,KAAK,CAAC;AAC5B;AAGO,SAAS,gBAAsB;AACpC,WAAS,MAAM;AACjB;","names":[]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lippelt/srd-core",
3
- "version": "0.1.1",
3
+ "version": "0.1.3",
4
4
  "description": "Plugin core for tabletop RPG system modules (types + registry). Each system ships in its own package.",
5
5
  "type": "module",
6
6
  "main": "./dist/index.cjs",