@uwmd/core 1.1.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.
Files changed (214) hide show
  1. package/README.md +79 -0
  2. package/dist/agents/bancroft.d.ts +32 -0
  3. package/dist/agents/bancroft.d.ts.map +1 -0
  4. package/dist/agents/bancroft.js +292 -0
  5. package/dist/agents/bancroft.js.map +1 -0
  6. package/dist/agents/schemas.d.ts +13 -0
  7. package/dist/agents/schemas.d.ts.map +1 -0
  8. package/dist/agents/schemas.js +74 -0
  9. package/dist/agents/schemas.js.map +1 -0
  10. package/dist/bindings.d.ts +85 -0
  11. package/dist/bindings.d.ts.map +1 -0
  12. package/dist/bindings.js +293 -0
  13. package/dist/bindings.js.map +1 -0
  14. package/dist/browser.d.ts +66 -0
  15. package/dist/browser.d.ts.map +1 -0
  16. package/dist/browser.js +53 -0
  17. package/dist/browser.js.map +1 -0
  18. package/dist/calc/builtins.d.ts +4 -0
  19. package/dist/calc/builtins.d.ts.map +1 -0
  20. package/dist/calc/builtins.js +329 -0
  21. package/dist/calc/builtins.js.map +1 -0
  22. package/dist/calc/dependencies.d.ts +34 -0
  23. package/dist/calc/dependencies.d.ts.map +1 -0
  24. package/dist/calc/dependencies.js +101 -0
  25. package/dist/calc/dependencies.js.map +1 -0
  26. package/dist/calc/errors.d.ts +8 -0
  27. package/dist/calc/errors.d.ts.map +1 -0
  28. package/dist/calc/errors.js +18 -0
  29. package/dist/calc/errors.js.map +1 -0
  30. package/dist/calc/evaluator.d.ts +5 -0
  31. package/dist/calc/evaluator.d.ts.map +1 -0
  32. package/dist/calc/evaluator.js +184 -0
  33. package/dist/calc/evaluator.js.map +1 -0
  34. package/dist/calc/index.d.ts +14 -0
  35. package/dist/calc/index.d.ts.map +1 -0
  36. package/dist/calc/index.js +56 -0
  37. package/dist/calc/index.js.map +1 -0
  38. package/dist/calc/parser.d.ts +32 -0
  39. package/dist/calc/parser.d.ts.map +1 -0
  40. package/dist/calc/parser.js +361 -0
  41. package/dist/calc/parser.js.map +1 -0
  42. package/dist/cascade.d.ts +85 -0
  43. package/dist/cascade.d.ts.map +1 -0
  44. package/dist/cascade.js +172 -0
  45. package/dist/cascade.js.map +1 -0
  46. package/dist/cli.d.ts +3 -0
  47. package/dist/cli.d.ts.map +1 -0
  48. package/dist/cli.js +843 -0
  49. package/dist/cli.js.map +1 -0
  50. package/dist/codec.d.ts +25 -0
  51. package/dist/codec.d.ts.map +1 -0
  52. package/dist/codec.js +62 -0
  53. package/dist/codec.js.map +1 -0
  54. package/dist/codecs.d.ts +6 -0
  55. package/dist/codecs.d.ts.map +1 -0
  56. package/dist/codecs.js +12 -0
  57. package/dist/codecs.js.map +1 -0
  58. package/dist/compactor.d.ts +11 -0
  59. package/dist/compactor.d.ts.map +1 -0
  60. package/dist/compactor.js +84 -0
  61. package/dist/compactor.js.map +1 -0
  62. package/dist/context-profiles.d.ts +30 -0
  63. package/dist/context-profiles.d.ts.map +1 -0
  64. package/dist/context-profiles.js +225 -0
  65. package/dist/context-profiles.js.map +1 -0
  66. package/dist/context.d.ts +55 -0
  67. package/dist/context.d.ts.map +1 -0
  68. package/dist/context.js +288 -0
  69. package/dist/context.js.map +1 -0
  70. package/dist/dcf.d.ts +9 -0
  71. package/dist/dcf.d.ts.map +1 -0
  72. package/dist/dcf.js +75 -0
  73. package/dist/dcf.js.map +1 -0
  74. package/dist/debt.d.ts +11 -0
  75. package/dist/debt.d.ts.map +1 -0
  76. package/dist/debt.js +85 -0
  77. package/dist/debt.js.map +1 -0
  78. package/dist/defaults.d.ts +104 -0
  79. package/dist/defaults.d.ts.map +1 -0
  80. package/dist/defaults.js +622 -0
  81. package/dist/defaults.js.map +1 -0
  82. package/dist/derived.d.ts +17 -0
  83. package/dist/derived.d.ts.map +1 -0
  84. package/dist/derived.js +29 -0
  85. package/dist/derived.js.map +1 -0
  86. package/dist/editor.d.ts +76 -0
  87. package/dist/editor.d.ts.map +1 -0
  88. package/dist/editor.js +502 -0
  89. package/dist/editor.js.map +1 -0
  90. package/dist/envelope.d.ts +51 -0
  91. package/dist/envelope.d.ts.map +1 -0
  92. package/dist/envelope.js +213 -0
  93. package/dist/envelope.js.map +1 -0
  94. package/dist/format.d.ts +60 -0
  95. package/dist/format.d.ts.map +1 -0
  96. package/dist/format.js +115 -0
  97. package/dist/format.js.map +1 -0
  98. package/dist/gaps.d.ts +62 -0
  99. package/dist/gaps.d.ts.map +1 -0
  100. package/dist/gaps.js +272 -0
  101. package/dist/gaps.js.map +1 -0
  102. package/dist/index.d.ts +75 -0
  103. package/dist/index.d.ts.map +1 -0
  104. package/dist/index.js +47 -0
  105. package/dist/index.js.map +1 -0
  106. package/dist/init.d.ts +15 -0
  107. package/dist/init.d.ts.map +1 -0
  108. package/dist/init.js +169 -0
  109. package/dist/init.js.map +1 -0
  110. package/dist/integrity-canonical.d.ts +17 -0
  111. package/dist/integrity-canonical.d.ts.map +1 -0
  112. package/dist/integrity-canonical.js +124 -0
  113. package/dist/integrity-canonical.js.map +1 -0
  114. package/dist/integrity.d.ts +54 -0
  115. package/dist/integrity.d.ts.map +1 -0
  116. package/dist/integrity.js +244 -0
  117. package/dist/integrity.js.map +1 -0
  118. package/dist/modules.d.ts +24 -0
  119. package/dist/modules.d.ts.map +1 -0
  120. package/dist/modules.js +322 -0
  121. package/dist/modules.js.map +1 -0
  122. package/dist/negotiation.d.ts +19 -0
  123. package/dist/negotiation.d.ts.map +1 -0
  124. package/dist/negotiation.js +70 -0
  125. package/dist/negotiation.js.map +1 -0
  126. package/dist/opstatement.d.ts +9 -0
  127. package/dist/opstatement.d.ts.map +1 -0
  128. package/dist/opstatement.js +80 -0
  129. package/dist/opstatement.js.map +1 -0
  130. package/dist/packs/excel-emit.d.ts +21 -0
  131. package/dist/packs/excel-emit.d.ts.map +1 -0
  132. package/dist/packs/excel-emit.js +135 -0
  133. package/dist/packs/excel-emit.js.map +1 -0
  134. package/dist/packs/index.d.ts +13 -0
  135. package/dist/packs/index.d.ts.map +1 -0
  136. package/dist/packs/index.js +37 -0
  137. package/dist/packs/index.js.map +1 -0
  138. package/dist/packs/industrial.d.ts +3 -0
  139. package/dist/packs/industrial.d.ts.map +1 -0
  140. package/dist/packs/industrial.js +115 -0
  141. package/dist/packs/industrial.js.map +1 -0
  142. package/dist/packs/multifamily.d.ts +3 -0
  143. package/dist/packs/multifamily.d.ts.map +1 -0
  144. package/dist/packs/multifamily.js +82 -0
  145. package/dist/packs/multifamily.js.map +1 -0
  146. package/dist/packs/office.d.ts +3 -0
  147. package/dist/packs/office.d.ts.map +1 -0
  148. package/dist/packs/office.js +108 -0
  149. package/dist/packs/office.js.map +1 -0
  150. package/dist/packs/retail.d.ts +3 -0
  151. package/dist/packs/retail.d.ts.map +1 -0
  152. package/dist/packs/retail.js +115 -0
  153. package/dist/packs/retail.js.map +1 -0
  154. package/dist/packs/self-storage.d.ts +3 -0
  155. package/dist/packs/self-storage.d.ts.map +1 -0
  156. package/dist/packs/self-storage.js +105 -0
  157. package/dist/packs/self-storage.js.map +1 -0
  158. package/dist/parser.d.ts +15 -0
  159. package/dist/parser.d.ts.map +1 -0
  160. package/dist/parser.js +430 -0
  161. package/dist/parser.js.map +1 -0
  162. package/dist/protocol.d.ts +389 -0
  163. package/dist/protocol.d.ts.map +1 -0
  164. package/dist/protocol.js +714 -0
  165. package/dist/protocol.js.map +1 -0
  166. package/dist/refinement.d.ts +63 -0
  167. package/dist/refinement.d.ts.map +1 -0
  168. package/dist/refinement.js +242 -0
  169. package/dist/refinement.js.map +1 -0
  170. package/dist/renderer.d.ts +22 -0
  171. package/dist/renderer.d.ts.map +1 -0
  172. package/dist/renderer.js +478 -0
  173. package/dist/renderer.js.map +1 -0
  174. package/dist/rentroll.d.ts +21 -0
  175. package/dist/rentroll.d.ts.map +1 -0
  176. package/dist/rentroll.js +256 -0
  177. package/dist/rentroll.js.map +1 -0
  178. package/dist/report.d.ts +29 -0
  179. package/dist/report.d.ts.map +1 -0
  180. package/dist/report.js +924 -0
  181. package/dist/report.js.map +1 -0
  182. package/dist/runner.d.ts +43 -0
  183. package/dist/runner.d.ts.map +1 -0
  184. package/dist/runner.js +288 -0
  185. package/dist/runner.js.map +1 -0
  186. package/dist/sourcesuses.d.ts +14 -0
  187. package/dist/sourcesuses.d.ts.map +1 -0
  188. package/dist/sourcesuses.js +63 -0
  189. package/dist/sourcesuses.js.map +1 -0
  190. package/dist/types.d.ts +248 -0
  191. package/dist/types.d.ts.map +1 -0
  192. package/dist/types.js +15 -0
  193. package/dist/types.js.map +1 -0
  194. package/dist/uwcsv.d.ts +23 -0
  195. package/dist/uwcsv.d.ts.map +1 -0
  196. package/dist/uwcsv.js +877 -0
  197. package/dist/uwcsv.js.map +1 -0
  198. package/dist/uwjson.d.ts +19 -0
  199. package/dist/uwjson.d.ts.map +1 -0
  200. package/dist/uwjson.js +61 -0
  201. package/dist/uwjson.js.map +1 -0
  202. package/dist/uwxml.d.ts +18 -0
  203. package/dist/uwxml.d.ts.map +1 -0
  204. package/dist/uwxml.js +297 -0
  205. package/dist/uwxml.js.map +1 -0
  206. package/dist/validator.d.ts +35 -0
  207. package/dist/validator.d.ts.map +1 -0
  208. package/dist/validator.js +553 -0
  209. package/dist/validator.js.map +1 -0
  210. package/dist/valuation.d.ts +9 -0
  211. package/dist/valuation.d.ts.map +1 -0
  212. package/dist/valuation.js +34 -0
  213. package/dist/valuation.js.map +1 -0
  214. package/package.json +58 -0
@@ -0,0 +1,322 @@
1
+ // Module loader and registry.
2
+ //
3
+ // v1 modules are declarative ModuleManifest objects. This loader validates the
4
+ // protocol-level shape, checks host compatibility, parses safe-expression
5
+ // formulas, enforces dependency presence, and returns an immutable in-process
6
+ // registry. It deliberately does not perform dynamic imports or introduce new
7
+ // asset-class identifiers; those remain v2/RFC concerns.
8
+ import { parseExpression } from './calc/parser.js';
9
+ import { FORMAT_VERSION, PROTOCOL_VERSION, } from './protocol.js';
10
+ const TIERS = [
11
+ 'tier-1-reader',
12
+ 'tier-2-editor',
13
+ 'tier-3-calc-host',
14
+ 'tier-4-agent-host',
15
+ ];
16
+ const ASSET_CLASSES = [
17
+ 'multifamily',
18
+ 'office',
19
+ 'retail',
20
+ 'industrial',
21
+ 'self_storage',
22
+ 'hospitality',
23
+ 'mixed_use',
24
+ 'senior_housing',
25
+ 'student_housing',
26
+ 'land',
27
+ ];
28
+ const DEAL_STAGES = [
29
+ 'scope',
30
+ 'screening',
31
+ 'term_sheet',
32
+ 'full_underwrite',
33
+ 'credit_approval',
34
+ 'closing',
35
+ 'monitoring',
36
+ ];
37
+ const SEVERITIES = ['error', 'warning', 'info'];
38
+ export class ModuleRegistryError extends Error {
39
+ errors;
40
+ constructor(errors) {
41
+ super(errors.map((e) => `${e.code}: ${e.message}`).join('; '));
42
+ this.name = 'ModuleRegistryError';
43
+ this.errors = errors;
44
+ }
45
+ }
46
+ export function loadModuleManifest(candidate, opts = {}) {
47
+ const manifest = candidate;
48
+ const errors = validateModuleManifest(manifest, opts);
49
+ return errors.length
50
+ ? { ok: false, errors }
51
+ : { ok: true, manifest: freezeManifest(manifest), errors: [] };
52
+ }
53
+ export function createModuleRegistry(opts) {
54
+ const loaded = [];
55
+ const errors = [];
56
+ for (const candidate of opts.modules) {
57
+ const result = loadModuleManifest(candidate, { ...opts, alreadyLoaded: loaded });
58
+ if (result.ok && result.manifest) {
59
+ loaded.push(result.manifest);
60
+ }
61
+ else {
62
+ errors.push(...result.errors);
63
+ }
64
+ }
65
+ if (errors.length > 0)
66
+ throw new ModuleRegistryError(errors);
67
+ const byId = new Map();
68
+ const byAssetClassMutable = new Map();
69
+ for (const manifest of loaded) {
70
+ byId.set(manifest.id, manifest);
71
+ for (const assetClass of manifest.asset_classes ?? []) {
72
+ const bucket = byAssetClassMutable.get(assetClass) ?? [];
73
+ bucket.push(manifest);
74
+ byAssetClassMutable.set(assetClass, bucket);
75
+ }
76
+ }
77
+ const byAssetClass = new Map([...byAssetClassMutable.entries()].map(([k, v]) => [k, Object.freeze([...v])]));
78
+ return Object.freeze({
79
+ modules: Object.freeze([...loaded]),
80
+ byId,
81
+ byAssetClass,
82
+ calculationsByAssetClass(asset_class) {
83
+ return [...(byAssetClass.get(asset_class) ?? [])].filter((m) => (m.calculations ?? []).length > 0);
84
+ },
85
+ });
86
+ }
87
+ export function getModuleCalculationsForAssetClass(registry, asset_class) {
88
+ return registry
89
+ .calculationsByAssetClass(asset_class)
90
+ .flatMap((m) => m.calculations ?? []);
91
+ }
92
+ function validateModuleManifest(manifest, opts) {
93
+ const errors = [];
94
+ if (!isRecord(manifest)) {
95
+ return [moduleError('PROTO-MOD-001', 'Module manifest must be an object.')];
96
+ }
97
+ requireString(errors, manifest, 'manifest_version');
98
+ requireString(errors, manifest, 'id');
99
+ requireString(errors, manifest, 'name');
100
+ requireString(errors, manifest, 'version');
101
+ requireString(errors, manifest, 'description');
102
+ requireString(errors, manifest, 'license');
103
+ requireString(errors, manifest, 'requires_protocol');
104
+ requireString(errors, manifest, 'requires_format');
105
+ requireString(errors, manifest, 'requires_tier');
106
+ if (manifest.manifest_version !== '1') {
107
+ errors.push(moduleError('PROTO-MOD-002', 'Unsupported module manifest_version.', 'manifest_version'));
108
+ }
109
+ if (!/^[a-z0-9]+(?:[._-][a-z0-9]+)*$/.test(String(manifest.id ?? ''))) {
110
+ errors.push(moduleError('PROTO-MOD-003', 'Module id must match the v1 identifier pattern.', 'id'));
111
+ }
112
+ if (!/^\d+\.\d+\.\d+(?:-[0-9A-Za-z.-]+)?(?:\+[0-9A-Za-z.-]+)?$/.test(String(manifest.version ?? ''))) {
113
+ errors.push(moduleError('PROTO-MOD-004', 'Module version must be semver.', 'version'));
114
+ }
115
+ if (!Array.isArray(manifest.authors) || manifest.authors.length === 0 || !manifest.authors.every((a) => typeof a === 'string' && a.length > 0)) {
116
+ errors.push(moduleError('PROTO-MOD-005', 'Module authors must be a non-empty string array.', 'authors'));
117
+ }
118
+ if (!TIERS.includes(manifest.requires_tier)) {
119
+ errors.push(moduleError('PROTO-MOD-006', 'Module requires_tier is not a valid viewer tier.', 'requires_tier'));
120
+ }
121
+ if (manifest.asset_classes !== undefined) {
122
+ if (!Array.isArray(manifest.asset_classes)) {
123
+ errors.push(moduleError('PROTO-MOD-007', 'asset_classes must be an array.', 'asset_classes'));
124
+ }
125
+ else {
126
+ for (const assetClass of manifest.asset_classes) {
127
+ if (!ASSET_CLASSES.includes(assetClass)) {
128
+ errors.push(moduleError('PROTO-MOD-008', `Unknown v1 asset class: ${assetClass}`, 'asset_classes'));
129
+ }
130
+ }
131
+ if (new Set(manifest.asset_classes).size !== manifest.asset_classes.length) {
132
+ errors.push(moduleError('PROTO-MOD-009', 'asset_classes must be unique.', 'asset_classes'));
133
+ }
134
+ }
135
+ }
136
+ if (manifest.deal_stages !== undefined) {
137
+ if (!Array.isArray(manifest.deal_stages)) {
138
+ errors.push(moduleError('PROTO-MOD-010', 'deal_stages must be an array.', 'deal_stages'));
139
+ }
140
+ else {
141
+ for (const stage of manifest.deal_stages) {
142
+ if (!DEAL_STAGES.includes(stage)) {
143
+ errors.push(moduleError('PROTO-MOD-011', `Unknown deal stage: ${stage}`, 'deal_stages'));
144
+ }
145
+ }
146
+ }
147
+ }
148
+ validateCalculations(errors, manifest);
149
+ validateValidations(errors, manifest);
150
+ validateDependencies(errors, manifest, opts.alreadyLoaded ?? []);
151
+ validateCompatibility(errors, manifest, opts);
152
+ return errors;
153
+ }
154
+ function validateCalculations(errors, manifest) {
155
+ if (manifest.calculations === undefined)
156
+ return;
157
+ if (!Array.isArray(manifest.calculations)) {
158
+ errors.push(moduleError('PROTO-MOD-012', 'calculations must be an array.', 'calculations'));
159
+ return;
160
+ }
161
+ const ids = new Set();
162
+ for (const [idx, calc] of manifest.calculations.entries()) {
163
+ const pointer = `calculations[${idx}]`;
164
+ if (!isRecord(calc)) {
165
+ errors.push(moduleError('PROTO-MOD-013', 'Calculation declaration must be an object.', pointer));
166
+ continue;
167
+ }
168
+ if (typeof calc.id !== 'string' || !/^[a-z][a-z0-9_]*$/.test(calc.id)) {
169
+ errors.push(moduleError('PROTO-MOD-014', 'Calculation id must match ^[a-z][a-z0-9_]*$.', `${pointer}.id`));
170
+ }
171
+ if (ids.has(String(calc.id))) {
172
+ errors.push(moduleError('PROTO-MOD-015', `Duplicate calculation id: ${String(calc.id)}`, `${pointer}.id`));
173
+ }
174
+ ids.add(String(calc.id));
175
+ if (typeof calc.label !== 'string' || calc.label.length === 0) {
176
+ errors.push(moduleError('PROTO-MOD-016', 'Calculation label is required.', `${pointer}.label`));
177
+ }
178
+ if (typeof calc.formula !== 'string' || calc.formula.length === 0) {
179
+ errors.push(moduleError('PROTO-MOD-017', 'Calculation formula is required.', `${pointer}.formula`));
180
+ }
181
+ else {
182
+ try {
183
+ parseExpression(calc.formula);
184
+ }
185
+ catch (e) {
186
+ errors.push(moduleError('PROTO-MOD-018', `Calculation formula does not parse: ${e instanceof Error ? e.message : String(e)}`, `${pointer}.formula`));
187
+ }
188
+ }
189
+ if (calc.deterministic !== true) {
190
+ errors.push(moduleError('PROTO-MOD-019', 'v1 calculations must declare deterministic: true.', `${pointer}.deterministic`));
191
+ }
192
+ }
193
+ }
194
+ function validateValidations(errors, manifest) {
195
+ if (manifest.validations === undefined)
196
+ return;
197
+ if (!Array.isArray(manifest.validations)) {
198
+ errors.push(moduleError('PROTO-MOD-020', 'validations must be an array.', 'validations'));
199
+ return;
200
+ }
201
+ for (const [idx, rule] of manifest.validations.entries()) {
202
+ const pointer = `validations[${idx}]`;
203
+ if (!isRecord(rule)) {
204
+ errors.push(moduleError('PROTO-MOD-021', 'Validation declaration must be an object.', pointer));
205
+ continue;
206
+ }
207
+ if (typeof rule.code !== 'string' || !/^[A-Z]{2,8}-[A-Z0-9-]+$/.test(rule.code)) {
208
+ errors.push(moduleError('PROTO-MOD-022', 'Validation code must match the module-code pattern.', `${pointer}.code`));
209
+ }
210
+ if (!SEVERITIES.includes(rule.severity)) {
211
+ errors.push(moduleError('PROTO-MOD-023', 'Validation severity is invalid.', `${pointer}.severity`));
212
+ }
213
+ if (typeof rule.message !== 'string' || rule.message.length === 0) {
214
+ errors.push(moduleError('PROTO-MOD-024', 'Validation message is required.', `${pointer}.message`));
215
+ }
216
+ if (typeof rule.rule !== 'string' || rule.rule.length === 0) {
217
+ errors.push(moduleError('PROTO-MOD-025', 'Validation rule is required.', `${pointer}.rule`));
218
+ }
219
+ else {
220
+ try {
221
+ parseExpression(rule.rule);
222
+ }
223
+ catch (e) {
224
+ errors.push(moduleError('PROTO-MOD-026', `Validation rule does not parse: ${e instanceof Error ? e.message : String(e)}`, `${pointer}.rule`));
225
+ }
226
+ }
227
+ }
228
+ }
229
+ function validateDependencies(errors, manifest, alreadyLoaded) {
230
+ const loaded = new Map(alreadyLoaded.map((m) => [m.id, m]));
231
+ for (const dep of manifest.depends_on ?? []) {
232
+ const dependency = loaded.get(dep.id);
233
+ if (!dependency) {
234
+ errors.push(moduleError('PROTO-MOD-027', `Missing module dependency: ${dep.id}`, 'depends_on'));
235
+ continue;
236
+ }
237
+ if (!versionSatisfies(dependency.version, dep.version)) {
238
+ errors.push(moduleError('PROTO-MOD-028', `Module dependency ${dep.id}@${dependency.version} does not satisfy ${dep.version}.`, 'depends_on'));
239
+ }
240
+ }
241
+ }
242
+ function validateCompatibility(errors, manifest, opts) {
243
+ const hostTier = opts.hostTier ?? 'tier-3-calc-host';
244
+ if (TIERS.indexOf(hostTier) < TIERS.indexOf(manifest.requires_tier)) {
245
+ errors.push(moduleError('PROTO-MOD-029', `Host tier ${hostTier} does not satisfy required tier ${manifest.requires_tier}.`, 'requires_tier'));
246
+ }
247
+ const protocolVersion = opts.protocolVersion ?? PROTOCOL_VERSION;
248
+ if (!versionSatisfies(protocolVersion, manifest.requires_protocol)) {
249
+ errors.push(moduleError('PROTO-MOD-030', `Host protocol ${protocolVersion} does not satisfy ${manifest.requires_protocol}.`, 'requires_protocol'));
250
+ }
251
+ const formatVersion = normalizeFormatVersion(opts.formatVersion ?? FORMAT_VERSION);
252
+ if (!versionSatisfies(formatVersion, manifest.requires_format)) {
253
+ errors.push(moduleError('PROTO-MOD-031', `Host format ${formatVersion} does not satisfy ${manifest.requires_format}.`, 'requires_format'));
254
+ }
255
+ }
256
+ function versionSatisfies(version, range) {
257
+ const normalizedVersion = normalizeFormatVersion(version);
258
+ const v = parseSemver(normalizedVersion);
259
+ if (!v)
260
+ return false;
261
+ const trimmed = range.trim();
262
+ if (trimmed === '*' || trimmed === '')
263
+ return true;
264
+ if (trimmed.startsWith('^')) {
265
+ const base = parseSemver(normalizeFormatVersion(trimmed.slice(1)));
266
+ return !!base && v.major === base.major && compareSemver(v, base) >= 0;
267
+ }
268
+ const comparators = trimmed.split(/\s+/).filter(Boolean);
269
+ return comparators.every((part) => {
270
+ const m = /^(>=|>|<=|<|=)?(.+)$/.exec(part);
271
+ if (!m)
272
+ return false;
273
+ const op = m[1] ?? '=';
274
+ const target = parseSemver(normalizeFormatVersion(m[2] ?? ''));
275
+ if (!target)
276
+ return false;
277
+ const cmp = compareSemver(v, target);
278
+ switch (op) {
279
+ case '>': return cmp > 0;
280
+ case '>=': return cmp >= 0;
281
+ case '<': return cmp < 0;
282
+ case '<=': return cmp <= 0;
283
+ default: return cmp === 0;
284
+ }
285
+ });
286
+ }
287
+ function normalizeFormatVersion(version) {
288
+ return /^\d+\.\d+$/.test(version) ? `${version}.0` : version;
289
+ }
290
+ function parseSemver(version) {
291
+ const m = /^(\d+)\.(\d+)\.(\d+)/.exec(version);
292
+ return m ? { major: Number(m[1]), minor: Number(m[2]), patch: Number(m[3]) } : null;
293
+ }
294
+ function compareSemver(a, b) {
295
+ return a.major - b.major || a.minor - b.minor || a.patch - b.patch;
296
+ }
297
+ function requireString(errors, manifest, key) {
298
+ if (typeof manifest[key] !== 'string' || manifest[key].length === 0) {
299
+ errors.push(moduleError('PROTO-MOD-032', `Required string field missing: ${key}`, key));
300
+ }
301
+ }
302
+ function freezeManifest(manifest) {
303
+ return Object.freeze({
304
+ ...manifest,
305
+ authors: Object.freeze([...(manifest.authors ?? [])]),
306
+ asset_classes: manifest.asset_classes ? Object.freeze([...manifest.asset_classes]) : undefined,
307
+ deal_stages: manifest.deal_stages ? Object.freeze([...manifest.deal_stages]) : undefined,
308
+ sections: manifest.sections ? Object.freeze([...manifest.sections]) : undefined,
309
+ calculations: manifest.calculations ? Object.freeze([...manifest.calculations]) : undefined,
310
+ validations: manifest.validations ? Object.freeze([...manifest.validations]) : undefined,
311
+ view_models: manifest.view_models ? Object.freeze([...manifest.view_models]) : undefined,
312
+ agent_layers: manifest.agent_layers ? Object.freeze([...manifest.agent_layers]) : undefined,
313
+ depends_on: manifest.depends_on ? Object.freeze([...manifest.depends_on]) : undefined,
314
+ });
315
+ }
316
+ function isRecord(value) {
317
+ return typeof value === 'object' && value !== null && !Array.isArray(value);
318
+ }
319
+ function moduleError(code, message, pointer) {
320
+ return { category: 'module', code, message, ...(pointer ? { pointer } : {}) };
321
+ }
322
+ //# sourceMappingURL=modules.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"modules.js","sourceRoot":"","sources":["../src/modules.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,19 @@
1
+ import type { RepresentationCapability, RepresentationDirection, RepresentationFidelity } from './protocol.js';
2
+ export interface NegotiationOptions {
3
+ direction?: RepresentationDirection;
4
+ minimum_fidelity?: RepresentationFidelity;
5
+ }
6
+ export interface NegotiatedRepresentation {
7
+ descriptor: RepresentationCapability;
8
+ media_type: string;
9
+ }
10
+ export declare class RepresentationNegotiationError extends Error {
11
+ readonly code: string;
12
+ readonly status: 406 | 415;
13
+ constructor(code: string, status: 406 | 415, message: string);
14
+ }
15
+ /** Selects a registered representation using HTTP Accept semantics. */
16
+ export declare function negotiateRepresentation(accept: string | undefined, descriptors: readonly RepresentationCapability[], options?: NegotiationOptions): NegotiatedRepresentation;
17
+ /** Resolves a request Content-Type to a readable representation. */
18
+ export declare function resolveInputRepresentation(contentType: string, descriptors: readonly RepresentationCapability[]): NegotiatedRepresentation;
19
+ //# sourceMappingURL=negotiation.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"negotiation.d.ts","sourceRoot":"","sources":["../src/negotiation.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,wBAAwB,EACxB,uBAAuB,EACvB,sBAAsB,EACvB,MAAM,eAAe,CAAC;AAEvB,MAAM,WAAW,kBAAkB;IACjC,SAAS,CAAC,EAAE,uBAAuB,CAAC;IACpC,gBAAgB,CAAC,EAAE,sBAAsB,CAAC;CAC3C;AAED,MAAM,WAAW,wBAAwB;IACvC,UAAU,EAAE,wBAAwB,CAAC;IACrC,UAAU,EAAE,MAAM,CAAC;CACpB;AAED,qBAAa,8BAA+B,SAAQ,KAAK;IACvD,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,MAAM,EAAE,GAAG,GAAG,GAAG,CAAC;gBAEf,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,GAAG,GAAG,GAAG,EAAE,OAAO,EAAE,MAAM;CAM7D;AAED,uEAAuE;AACvE,wBAAgB,uBAAuB,CACrC,MAAM,EAAE,MAAM,GAAG,SAAS,EAC1B,WAAW,EAAE,SAAS,wBAAwB,EAAE,EAChD,OAAO,GAAE,kBAAuB,GAC/B,wBAAwB,CA6B1B;AAED,oEAAoE;AACpE,wBAAgB,0BAA0B,CACxC,WAAW,EAAE,MAAM,EACnB,WAAW,EAAE,SAAS,wBAAwB,EAAE,GAC/C,wBAAwB,CAY1B"}
@@ -0,0 +1,70 @@
1
+ export class RepresentationNegotiationError extends Error {
2
+ code;
3
+ status;
4
+ constructor(code, status, message) {
5
+ super(`[${code}] ${message}`);
6
+ this.name = 'RepresentationNegotiationError';
7
+ this.code = code;
8
+ this.status = status;
9
+ }
10
+ }
11
+ /** Selects a registered representation using HTTP Accept semantics. */
12
+ export function negotiateRepresentation(accept, descriptors, options = {}) {
13
+ const ranges = parseAccept(accept ?? '*/*');
14
+ const minimum = fidelityRank(options.minimum_fidelity ?? 'view');
15
+ const candidates = [];
16
+ descriptors.forEach((descriptor, order) => {
17
+ if (options.direction && !descriptor.directions.includes(options.direction))
18
+ return;
19
+ if (fidelityRank(descriptor.fidelity) < minimum)
20
+ return;
21
+ for (const mediaType of descriptor.media_types) {
22
+ const best = ranges
23
+ .filter((range) => mediaRangeMatches(range.mediaRange, mediaType))
24
+ .sort((left, right) => right.specificity - left.specificity || right.q - left.q)[0];
25
+ if (best && best.q > 0) {
26
+ candidates.push({ descriptor, media_type: mediaType, q: best.q, specificity: best.specificity, order });
27
+ }
28
+ }
29
+ });
30
+ const selected = candidates.sort((left, right) => right.q - left.q || right.specificity - left.specificity || left.order - right.order)[0];
31
+ if (!selected) {
32
+ throw new RepresentationNegotiationError('REPRESENTATION_NOT_ACCEPTABLE', 406, `No representation satisfies Accept: ${accept ?? '*/*'}.`);
33
+ }
34
+ return { descriptor: selected.descriptor, media_type: selected.media_type };
35
+ }
36
+ /** Resolves a request Content-Type to a readable representation. */
37
+ export function resolveInputRepresentation(contentType, descriptors) {
38
+ const normalized = contentType.split(';', 1)[0]?.trim().toLowerCase();
39
+ for (const descriptor of descriptors) {
40
+ if (!descriptor.directions.includes('read'))
41
+ continue;
42
+ const mediaType = descriptor.media_types.find((item) => item.toLowerCase() === normalized);
43
+ if (mediaType)
44
+ return { descriptor, media_type: mediaType };
45
+ }
46
+ throw new RepresentationNegotiationError('REPRESENTATION_UNSUPPORTED_MEDIA_TYPE', 415, `No readable representation owns Content-Type: ${contentType}.`);
47
+ }
48
+ function parseAccept(value) {
49
+ return value.split(',').map((part) => {
50
+ const [rawRange = '*/*', ...parameters] = part.trim().split(';');
51
+ const mediaRange = rawRange.toLowerCase();
52
+ const qParameter = parameters.find((parameter) => parameter.trim().toLowerCase().startsWith('q='));
53
+ const parsedQ = qParameter ? Number(qParameter.trim().slice(2)) : 1;
54
+ const q = Number.isFinite(parsedQ) && parsedQ >= 0 && parsedQ <= 1 ? parsedQ : 0;
55
+ const specificity = mediaRange === '*/*' ? 0 : mediaRange.endsWith('/*') ? 1 : 2;
56
+ return { mediaRange, q, specificity };
57
+ });
58
+ }
59
+ function mediaRangeMatches(range, mediaType) {
60
+ const normalized = mediaType.toLowerCase();
61
+ if (range === '*/*')
62
+ return true;
63
+ if (range.endsWith('/*'))
64
+ return normalized.startsWith(`${range.slice(0, -1)}`);
65
+ return range === normalized;
66
+ }
67
+ function fidelityRank(fidelity) {
68
+ return { view: 0, model: 1, source: 2 }[fidelity];
69
+ }
70
+ //# sourceMappingURL=negotiation.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"negotiation.js","sourceRoot":"","sources":["../src/negotiation.ts"],"names":[],"mappings":"AAgBA,MAAM,OAAO,8BAA+B,SAAQ,KAAK;IAC9C,IAAI,CAAS;IACb,MAAM,CAAY;IAE3B,YAAY,IAAY,EAAE,MAAiB,EAAE,OAAe;QAC1D,KAAK,CAAC,IAAI,IAAI,KAAK,OAAO,EAAE,CAAC,CAAC;QAC9B,IAAI,CAAC,IAAI,GAAG,gCAAgC,CAAC;QAC7C,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC;QACjB,IAAI,CAAC,MAAM,GAAG,MAAM,CAAC;IACvB,CAAC;CACF;AAED,uEAAuE;AACvE,MAAM,UAAU,uBAAuB,CACrC,MAA0B,EAC1B,WAAgD,EAChD,UAA8B,EAAE;IAEhC,MAAM,MAAM,GAAG,WAAW,CAAC,MAAM,IAAI,KAAK,CAAC,CAAC;IAC5C,MAAM,OAAO,GAAG,YAAY,CAAC,OAAO,CAAC,gBAAgB,IAAI,MAAM,CAAC,CAAC;IACjE,MAAM,UAAU,GAAwF,EAAE,CAAC;IAE3G,WAAW,CAAC,OAAO,CAAC,CAAC,UAAU,EAAE,KAAK,EAAE,EAAE;QACxC,IAAI,OAAO,CAAC,SAAS,IAAI,CAAC,UAAU,CAAC,UAAU,CAAC,QAAQ,CAAC,OAAO,CAAC,SAAS,CAAC;YAAE,OAAO;QACpF,IAAI,YAAY,CAAC,UAAU,CAAC,QAAQ,CAAC,GAAG,OAAO;YAAE,OAAO;QACxD,KAAK,MAAM,SAAS,IAAI,UAAU,CAAC,WAAW,EAAE,CAAC;YAC/C,MAAM,IAAI,GAAG,MAAM;iBAChB,MAAM,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,iBAAiB,CAAC,KAAK,CAAC,UAAU,EAAE,SAAS,CAAC,CAAC;iBACjE,IAAI,CAAC,CAAC,IAAI,EAAE,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,WAAW,GAAG,IAAI,CAAC,WAAW,IAAI,KAAK,CAAC,CAAC,GAAG,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;YACtF,IAAI,IAAI,IAAI,IAAI,CAAC,CAAC,GAAG,CAAC,EAAE,CAAC;gBACvB,UAAU,CAAC,IAAI,CAAC,EAAE,UAAU,EAAE,UAAU,EAAE,SAAS,EAAE,CAAC,EAAE,IAAI,CAAC,CAAC,EAAE,WAAW,EAAE,IAAI,CAAC,WAAW,EAAE,KAAK,EAAE,CAAC,CAAC;YAC1G,CAAC;QACH,CAAC;IACH,CAAC,CAAC,CAAC;IAEH,MAAM,QAAQ,GAAG,UAAU,CAAC,IAAI,CAC9B,CAAC,IAAI,EAAE,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,CAAC,GAAG,IAAI,CAAC,CAAC,IAAI,KAAK,CAAC,WAAW,GAAG,IAAI,CAAC,WAAW,IAAI,IAAI,CAAC,KAAK,GAAG,KAAK,CAAC,KAAK,CACtG,CAAC,CAAC,CAAC,CAAC;IACL,IAAI,CAAC,QAAQ,EAAE,CAAC;QACd,MAAM,IAAI,8BAA8B,CACtC,+BAA+B,EAC/B,GAAG,EACH,uCAAuC,MAAM,IAAI,KAAK,GAAG,CAC1D,CAAC;IACJ,CAAC;IACD,OAAO,EAAE,UAAU,EAAE,QAAQ,CAAC,UAAU,EAAE,UAAU,EAAE,QAAQ,CAAC,UAAU,EAAE,CAAC;AAC9E,CAAC;AAED,oEAAoE;AACpE,MAAM,UAAU,0BAA0B,CACxC,WAAmB,EACnB,WAAgD;IAEhD,MAAM,UAAU,GAAG,WAAW,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC;IACtE,KAAK,MAAM,UAAU,IAAI,WAAW,EAAE,CAAC;QACrC,IAAI,CAAC,UAAU,CAAC,UAAU,CAAC,QAAQ,CAAC,MAAM,CAAC;YAAE,SAAS;QACtD,MAAM,SAAS,GAAG,UAAU,CAAC,WAAW,CAAC,IAAI,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,WAAW,EAAE,KAAK,UAAU,CAAC,CAAC;QAC3F,IAAI,SAAS;YAAE,OAAO,EAAE,UAAU,EAAE,UAAU,EAAE,SAAS,EAAE,CAAC;IAC9D,CAAC;IACD,MAAM,IAAI,8BAA8B,CACtC,uCAAuC,EACvC,GAAG,EACH,iDAAiD,WAAW,GAAG,CAChE,CAAC;AACJ,CAAC;AAQD,SAAS,WAAW,CAAC,KAAa;IAChC,OAAO,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE;QACnC,MAAM,CAAC,QAAQ,GAAG,KAAK,EAAE,GAAG,UAAU,CAAC,GAAG,IAAI,CAAC,IAAI,EAAE,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;QACjE,MAAM,UAAU,GAAG,QAAQ,CAAC,WAAW,EAAE,CAAC;QAC1C,MAAM,UAAU,GAAG,UAAU,CAAC,IAAI,CAAC,CAAC,SAAS,EAAE,EAAE,CAAC,SAAS,CAAC,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC,UAAU,CAAC,IAAI,CAAC,CAAC,CAAC;QACnG,MAAM,OAAO,GAAG,UAAU,CAAC,CAAC,CAAC,MAAM,CAAC,UAAU,CAAC,IAAI,EAAE,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;QACpE,MAAM,CAAC,GAAG,MAAM,CAAC,QAAQ,CAAC,OAAO,CAAC,IAAI,OAAO,IAAI,CAAC,IAAI,OAAO,IAAI,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC;QACjF,MAAM,WAAW,GAAG,UAAU,KAAK,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,UAAU,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;QACjF,OAAO,EAAE,UAAU,EAAE,CAAC,EAAE,WAAW,EAAE,CAAC;IACxC,CAAC,CAAC,CAAC;AACL,CAAC;AAED,SAAS,iBAAiB,CAAC,KAAa,EAAE,SAAiB;IACzD,MAAM,UAAU,GAAG,SAAS,CAAC,WAAW,EAAE,CAAC;IAC3C,IAAI,KAAK,KAAK,KAAK;QAAE,OAAO,IAAI,CAAC;IACjC,IAAI,KAAK,CAAC,QAAQ,CAAC,IAAI,CAAC;QAAE,OAAO,UAAU,CAAC,UAAU,CAAC,GAAG,KAAK,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC;IAChF,OAAO,KAAK,KAAK,UAAU,CAAC;AAC9B,CAAC;AAED,SAAS,YAAY,CAAC,QAAgC;IACpD,OAAO,EAAE,IAAI,EAAE,CAAC,EAAE,KAAK,EAAE,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,CAAC,QAAQ,CAAC,CAAC;AACpD,CAAC"}
@@ -0,0 +1,9 @@
1
+ import { type DerivedField } from './derived.js';
2
+ type Row = Record<string, unknown>;
3
+ export interface OperatingStatementDerivation {
4
+ fields: DerivedField[];
5
+ }
6
+ /** Foot an operating-statement content block. Pure: never mutates `content`. */
7
+ export declare function deriveOperatingStatement(content: Row): OperatingStatementDerivation;
8
+ export {};
9
+ //# sourceMappingURL=opstatement.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"opstatement.d.ts","sourceRoot":"","sources":["../src/opstatement.ts"],"names":[],"mappings":"AAgBA,OAAO,EAAwB,KAAK,YAAY,EAAE,MAAM,cAAc,CAAC;AAEvE,KAAK,GAAG,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;AAKnC,MAAM,WAAW,4BAA4B;IAC3C,MAAM,EAAE,YAAY,EAAE,CAAC;CACxB;AA6BD,gFAAgF;AAChF,wBAAgB,wBAAwB,CAAC,OAAO,EAAE,GAAG,GAAG,4BAA4B,CAuCnF"}
@@ -0,0 +1,80 @@
1
+ // Deterministic operating-statement footing — the income/expense line items are
2
+ // the inputs; effective gross income, total operating expenses, NOI, and the
3
+ // ratios foot from them. Same role for the operating_statement section that
4
+ // deriveRentRoll plays for rent_roll: one source of truth so the editor, CLI,
5
+ // and Excel converter never disagree.
6
+ //
7
+ // Conventions (standard CRE underwriting):
8
+ // - EGI = GPR − vacancy/credit loss − concessions − loss to lease + other income
9
+ // - OpEx = sum of operating expense lines, EXCLUDING capital expenditures and
10
+ // replacement reserves (both are below-the-line for NOI purposes)
11
+ // - NOI = EGI − OpEx
12
+ // - sub-rollups: other_income.total and utilities.total foot from their breakdowns
13
+ //
14
+ // Per-unit / per-sqft figures depend on the property section and are left as
15
+ // inputs here (this function sees only the operating_statement block).
16
+ import { collector, numOrNull } from './derived.js';
17
+ const num = numOrNull;
18
+ const asObj = (v) => (v !== null && typeof v === 'object' && !Array.isArray(v) ? v : {});
19
+ // Operating-expense lines that sum into total_operating_expenses. Excludes
20
+ // capital_expenditures_actual and replacement_reserves (below the line), the
21
+ // management_fee_pct_egi ratio, and the nested utilities object (added via its
22
+ // own footed total).
23
+ const EXPENSE_LINES = [
24
+ 'real_estate_taxes',
25
+ 'insurance',
26
+ 'management_fees',
27
+ 'payroll_benefits',
28
+ 'repairs_maintenance',
29
+ 'contract_services',
30
+ 'marketing_advertising',
31
+ 'administrative',
32
+ 'professional_fees',
33
+ 'other_expenses',
34
+ ];
35
+ /** Sum the numeric values of an object, skipping the listed keys. */
36
+ function sumExcept(obj, skip) {
37
+ let total = 0;
38
+ for (const [k, v] of Object.entries(obj)) {
39
+ if (skip.includes(k))
40
+ continue;
41
+ total += num(v) ?? 0;
42
+ }
43
+ return total;
44
+ }
45
+ /** Foot an operating-statement content block. Pure: never mutates `content`. */
46
+ export function deriveOperatingStatement(content) {
47
+ const c = collector();
48
+ const income = asObj(content['income']);
49
+ const expenses = asObj(content['expenses']);
50
+ // Income side.
51
+ const otherIncome = asObj(income['other_income']);
52
+ const otherIncomeTotal = sumExcept(otherIncome, ['total']);
53
+ if (Object.keys(otherIncome).length > 0) {
54
+ c.add('income.other_income.total', 'Other Income (total)', 'currency', otherIncomeTotal);
55
+ }
56
+ const gpr = num(income['gross_potential_rent']) ?? 0;
57
+ const vacancy = num(income['less_vacancy_credit_loss']) ?? 0;
58
+ const concessions = num(income['less_concessions']) ?? 0;
59
+ const lossToLease = num(income['less_loss_to_lease']) ?? 0;
60
+ const egi = gpr - vacancy - concessions - lossToLease + otherIncomeTotal;
61
+ c.add('income.vacancy_pct', 'Vacancy %', 'rate', gpr ? vacancy / gpr : null);
62
+ c.add('income.effective_gross_income', 'Effective Gross Income', 'currency', egi);
63
+ // Expense side.
64
+ const utilities = asObj(expenses['utilities']);
65
+ const utilitiesTotal = sumExcept(utilities, ['total']);
66
+ if (Object.keys(utilities).length > 0) {
67
+ c.add('expenses.utilities.total', 'Utilities (total)', 'currency', utilitiesTotal);
68
+ }
69
+ let opex = utilitiesTotal;
70
+ for (const key of EXPENSE_LINES)
71
+ opex += num(expenses[key]) ?? 0;
72
+ c.add('expenses.total_operating_expenses', 'Total Operating Expenses', 'currency', opex);
73
+ // Bottom line.
74
+ const noi = egi - opex;
75
+ c.add('net_operating_income', 'Net Operating Income', 'currency', noi);
76
+ c.add('expense_ratio', 'Expense Ratio', 'rate', egi ? opex / egi : null);
77
+ c.add('noi_margin', 'NOI Margin', 'rate', egi ? noi / egi : null);
78
+ return { fields: c.fields };
79
+ }
80
+ //# sourceMappingURL=opstatement.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"opstatement.js","sourceRoot":"","sources":["../src/opstatement.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,21 @@
1
+ import { type Expr } from '../calc/parser.js';
2
+ export interface ExcelEmitOptions {
3
+ /**
4
+ * Map from calc-engine path (joined with dots, e.g. `noi_model.net_operating_income`)
5
+ * to Excel named range (e.g. `noi`). Bare identifiers are looked up by name.
6
+ */
7
+ namedRanges: ReadonlyMap<string, string>;
8
+ }
9
+ export declare class ExcelEmitError extends Error {
10
+ code: 'EXCEL-EMIT-PATH' | 'EXCEL-EMIT-FN' | 'EXCEL-EMIT-OP';
11
+ constructor(code: 'EXCEL-EMIT-PATH' | 'EXCEL-EMIT-FN' | 'EXCEL-EMIT-OP', message: string);
12
+ }
13
+ /**
14
+ * Emit an Excel formula (without leading `=`) for a parsed expression.
15
+ * Throws ExcelEmitError if the expression references a path not in the map
16
+ * or uses a builtin without a clean Excel equivalent.
17
+ */
18
+ export declare function emitFromAst(expr: Expr, opts: ExcelEmitOptions): string;
19
+ /** Convenience: parse + emit in one call. */
20
+ export declare function emitExcelFormula(formula: string, opts: ExcelEmitOptions): string;
21
+ //# sourceMappingURL=excel-emit.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"excel-emit.d.ts","sourceRoot":"","sources":["../../src/packs/excel-emit.ts"],"names":[],"mappings":"AA2BA,OAAO,EAAmB,KAAK,IAAI,EAAE,MAAM,mBAAmB,CAAC;AAE/D,MAAM,WAAW,gBAAgB;IAC/B;;;OAGG;IACH,WAAW,EAAE,WAAW,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CAC1C;AAED,qBAAa,cAAe,SAAQ,KAAK;IAE9B,IAAI,EAAE,iBAAiB,GAAG,eAAe,GAAG,eAAe;gBAA3D,IAAI,EAAE,iBAAiB,GAAG,eAAe,GAAG,eAAe,EAClE,OAAO,EAAE,MAAM;CAKlB;AAuBD;;;;GAIG;AACH,wBAAgB,WAAW,CAAC,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,gBAAgB,GAAG,MAAM,CA0EtE;AAED,6CAA6C;AAC7C,wBAAgB,gBAAgB,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,gBAAgB,GAAG,MAAM,CAEhF"}