@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,256 @@
1
+ // Deterministic rent-roll footing — the single source of truth for rolling a
2
+ // unit-level (multifamily) or tenant-level (commercial) schedule up into the
3
+ // section's totals (GPR, in-place rent, occupancy, leased SF, WALT, per-SF, and
4
+ // the unit-mix / tenant-concentration summaries).
5
+ //
6
+ // Why this lives in core, not the editor: per invariant #4 (Excel ↔ calc-engine
7
+ // parity, one source drives both), any value the file stores must be derivable
8
+ // the same way everywhere. The web editor calls deriveRentRoll() to lock these
9
+ // totals to their line items; the CLI and Excel converter can call the identical
10
+ // function so they never disagree.
11
+ //
12
+ // This is *not* AI math — it is plain deterministic arithmetic over line items,
13
+ // exactly like the calc packs. It does no I/O and mutates nothing.
14
+ //
15
+ // Field-name tolerance: real files use two commercial naming conventions (the
16
+ // format spec's `nra_sqft`/`base_rent_annual` and the worked-example's
17
+ // `leased_sf`/`annual_base_rent`). deriveRentRoll reads either and writes back
18
+ // to whichever total keys already exist in the block, falling back to the spec
19
+ // name when the block is new.
20
+ import { collector, numOrNull } from './derived.js';
21
+ const num = numOrNull;
22
+ const lower = (v) => (typeof v === 'string' ? v.toLowerCase() : '');
23
+ /** First key in `keys` that exists on `content`, else `keys[0]` (the default to write). */
24
+ function pickKey(content, keys) {
25
+ for (const k of keys)
26
+ if (k in content)
27
+ return k;
28
+ return keys[0];
29
+ }
30
+ /** First finite number among `keys` on `row`. */
31
+ function firstNum(row, keys) {
32
+ for (const k of keys) {
33
+ const n = num(row[k]);
34
+ if (n != null)
35
+ return n;
36
+ }
37
+ return null;
38
+ }
39
+ /** Detect the rent-roll variant from explicit type or line-item shape. */
40
+ export function rentRollVariant(content) {
41
+ const t = lower(content['rent_roll_type']);
42
+ if (t === 'commercial')
43
+ return 'commercial';
44
+ if (t === 'multifamily')
45
+ return 'multifamily';
46
+ return Array.isArray(content['tenants']) ? 'commercial' : 'multifamily';
47
+ }
48
+ /** Foot a rent-roll content block. Pure: never mutates `content`. */
49
+ export function deriveRentRoll(content) {
50
+ const variant = rentRollVariant(content);
51
+ if (variant === 'commercial')
52
+ return deriveCommercial(content);
53
+ return deriveMultifamily(content);
54
+ }
55
+ // ─── Multifamily ──────────────────────────────────────────────────────────────
56
+ // Unit statuses that contribute contractual in-place rent (a unit on notice is
57
+ // still paying; vacant/model/down units are not).
58
+ const PAYING = new Set(['occupied', 'notice', 'holdover', '']);
59
+ function deriveMultifamily(content) {
60
+ const units = content['units'];
61
+ if (Array.isArray(units) && units.length > 0) {
62
+ return deriveMultifamilyFromUnits(content, units);
63
+ }
64
+ const mix = content['unit_mix_summary'];
65
+ if (Array.isArray(mix) && mix.length > 0) {
66
+ return deriveMultifamilyFromMix(content, mix);
67
+ }
68
+ return { variant: 'multifamily', basis: 'none', fields: [] };
69
+ }
70
+ function deriveMultifamilyFromUnits(_content, units) {
71
+ const c = collector();
72
+ const n = units.length;
73
+ let occ = 0;
74
+ let vac = 0;
75
+ let notice = 0;
76
+ let model = 0;
77
+ let down = 0;
78
+ let mtm = 0;
79
+ let gprM = 0;
80
+ let inplaceM = 0;
81
+ let concM = 0;
82
+ for (const u of units) {
83
+ const status = lower(u['status']);
84
+ if (status === 'occupied')
85
+ occ++;
86
+ else if (status === 'vacant')
87
+ vac++;
88
+ else if (status === 'notice')
89
+ notice++;
90
+ else if (status === 'model')
91
+ model++;
92
+ else if (status === 'down')
93
+ down++;
94
+ const market = num(u['market_rent']);
95
+ const contract = num(u['monthly_rent']);
96
+ gprM += market ?? contract ?? 0;
97
+ if (PAYING.has(status))
98
+ inplaceM += contract ?? 0;
99
+ concM += num(u['concession_monthly_equiv']) ?? 0;
100
+ if (u['is_month_to_month'] === true)
101
+ mtm++;
102
+ }
103
+ c.add('total_units', 'Total Units', 'count', n);
104
+ c.add('occupied_units', 'Occupied Units', 'count', occ);
105
+ c.add('vacant_units', 'Vacant Units', 'count', vac);
106
+ if (notice > 0)
107
+ c.add('notice_units', 'Units on Notice', 'count', notice);
108
+ if (model > 0)
109
+ c.add('model_units', 'Model Units', 'count', model);
110
+ if (down > 0)
111
+ c.add('down_units', 'Down Units', 'count', down);
112
+ c.add('physical_occupancy_pct', 'Physical Occupancy', 'rate', n ? occ / n : null);
113
+ c.add('gross_potential_rent_monthly', 'GPR (monthly)', 'currency', gprM);
114
+ c.add('gross_potential_rent_annual', 'GPR (annual)', 'currency', gprM * 12);
115
+ c.add('in_place_rent_monthly', 'In-Place Rent (monthly)', 'currency', inplaceM);
116
+ c.add('in_place_rent_annual', 'In-Place Rent (annual)', 'currency', inplaceM * 12);
117
+ c.add('loss_to_lease_monthly', 'Loss to Lease (monthly)', 'currency', gprM - inplaceM);
118
+ c.add('loss_to_lease_pct', 'Loss to Lease %', 'rate', gprM ? (gprM - inplaceM) / gprM : null);
119
+ c.add('concessions_monthly', 'Concessions (monthly)', 'currency', concM);
120
+ c.add('concessions_annual', 'Concessions (annual)', 'currency', concM * 12);
121
+ c.add('net_effective_rent_monthly', 'Net Effective Rent (monthly)', 'currency', inplaceM - concM);
122
+ c.add('month_to_month_units', 'Month-to-Month Units', 'count', mtm);
123
+ c.add('month_to_month_pct', 'Month-to-Month %', 'rate', n ? mtm / n : null);
124
+ return {
125
+ variant: 'multifamily',
126
+ basis: 'units',
127
+ fields: c.fields,
128
+ unit_mix_summary: buildUnitMix(units, n),
129
+ };
130
+ }
131
+ function buildUnitMix(units, total) {
132
+ const groups = new Map();
133
+ for (const u of units) {
134
+ const key = typeof u['unit_type'] === 'string' ? u['unit_type'] : 'Unknown';
135
+ const list = groups.get(key);
136
+ if (list)
137
+ list.push(u);
138
+ else
139
+ groups.set(key, [u]);
140
+ }
141
+ const mean = (xs) => xs.length ? xs.reduce((a, b) => a + b, 0) / xs.length : null;
142
+ return [...groups.entries()].map(([unit_type, us]) => {
143
+ const count = us.length;
144
+ const sqfts = us.map((u) => num(u['sqft'])).filter((x) => x != null);
145
+ const occupiedRents = us
146
+ .filter((u) => PAYING.has(lower(u['status'])))
147
+ .map((u) => num(u['monthly_rent']))
148
+ .filter((x) => x != null);
149
+ const markets = us.map((u) => num(u['market_rent'])).filter((x) => x != null);
150
+ const occInGroup = us.filter((u) => lower(u['status']) === 'occupied').length;
151
+ const avgSqft = mean(sqfts);
152
+ const avgInplace = mean(occupiedRents);
153
+ const avgMarket = mean(markets);
154
+ const row = { unit_type, count };
155
+ row['avg_sqft'] = avgSqft == null ? null : Math.round(avgSqft);
156
+ row['avg_rent_inplace'] = avgInplace == null ? 0 : Math.round(avgInplace);
157
+ row['avg_rent_market'] = avgMarket == null ? null : Math.round(avgMarket);
158
+ row['occupancy_pct'] = count ? Math.round((occInGroup / count) * 1e4) / 1e4 : 0;
159
+ row['pct_of_total'] = total ? Math.round((count / total) * 1e4) / 1e4 : 0;
160
+ return row;
161
+ });
162
+ }
163
+ function deriveMultifamilyFromMix(_content, mix) {
164
+ const c = collector();
165
+ let total = 0;
166
+ let gprM = 0;
167
+ let inplaceM = 0;
168
+ let occWeighted = 0;
169
+ for (const m of mix) {
170
+ const count = num(m['count']) ?? 0;
171
+ const inplace = num(m['avg_rent_inplace']) ?? 0;
172
+ const market = num(m['avg_rent_market']) ?? inplace;
173
+ const occ = num(m['occupancy_pct']) ?? 1;
174
+ total += count;
175
+ gprM += count * market;
176
+ inplaceM += count * occ * inplace;
177
+ occWeighted += count * occ;
178
+ }
179
+ c.add('total_units', 'Total Units', 'count', total);
180
+ c.add('occupied_units', 'Occupied Units', 'count', occWeighted);
181
+ c.add('physical_occupancy_pct', 'Physical Occupancy', 'rate', total ? occWeighted / total : null);
182
+ c.add('gross_potential_rent_monthly', 'GPR (monthly)', 'currency', gprM);
183
+ c.add('gross_potential_rent_annual', 'GPR (annual)', 'currency', gprM * 12);
184
+ c.add('in_place_rent_monthly', 'In-Place Rent (monthly)', 'currency', inplaceM);
185
+ c.add('in_place_rent_annual', 'In-Place Rent (annual)', 'currency', inplaceM * 12);
186
+ c.add('loss_to_lease_monthly', 'Loss to Lease (monthly)', 'currency', gprM - inplaceM);
187
+ c.add('loss_to_lease_pct', 'Loss to Lease %', 'rate', gprM ? (gprM - inplaceM) / gprM : null);
188
+ return { variant: 'multifamily', basis: 'unit_mix_summary', fields: c.fields };
189
+ }
190
+ // ─── Commercial ─────────────────────────────────────────────────────────────
191
+ const SF_KEYS = ['leased_sf', 'nra_sqft'];
192
+ const RENT_KEYS = ['annual_base_rent', 'base_rent_annual'];
193
+ const TERM_KEYS = ['remaining_term_years', 'lease_term_years'];
194
+ function deriveCommercial(content) {
195
+ const tenants = content['tenants'];
196
+ if (!Array.isArray(tenants) || tenants.length === 0) {
197
+ return { variant: 'commercial', basis: 'none', fields: [] };
198
+ }
199
+ const rows = tenants;
200
+ const c = collector();
201
+ let allSf = 0;
202
+ let leasedSf = 0;
203
+ let inplaceA = 0;
204
+ let waltNum = 0;
205
+ let waltDen = 0;
206
+ for (const t of rows) {
207
+ const sf = firstNum(t, SF_KEYS) ?? 0;
208
+ const vacantSf = num(t['vacant_sf']) ?? 0;
209
+ const rent = firstNum(t, RENT_KEYS) ?? 0;
210
+ const leased = rent > 0 && lower(t['status']) !== 'vacant';
211
+ allSf += sf + vacantSf;
212
+ if (leased) {
213
+ leasedSf += sf;
214
+ inplaceA += rent;
215
+ const term = firstNum(t, TERM_KEYS);
216
+ if (term != null && rent > 0) {
217
+ waltNum += term * rent;
218
+ waltDen += rent;
219
+ }
220
+ }
221
+ }
222
+ const totalKey = pickKey(content, ['total_rentable_sf', 'total_nra_sqft']);
223
+ const total = num(content[totalKey]) ?? allSf;
224
+ const vacantSf = Math.max(total - leasedSf, 0);
225
+ c.add(pickKey(content, ['occupied_sf', 'leased_sqft']), 'Occupied SF', 'count', leasedSf);
226
+ c.add('vacant_sf', 'Vacant SF', 'count', vacantSf);
227
+ c.add(totalKey, 'Total Rentable SF', 'count', total);
228
+ c.add(pickKey(content, ['occupancy_pct', 'physical_occupancy_pct']), 'Physical Occupancy', 'rate', total ? leasedSf / total : null);
229
+ c.add('in_place_rent_annual', 'In-Place Rent (annual)', 'currency', inplaceA);
230
+ c.add(pickKey(content, ['weighted_avg_rent_psf', 'in_place_rent_per_sqft']), 'In-Place Rent PSF', 'psf', leasedSf ? inplaceA / leasedSf : null);
231
+ c.add('weighted_avg_lease_term_years', 'WALT (years)', 'rate', waltDen ? waltNum / waltDen : null);
232
+ return {
233
+ variant: 'commercial',
234
+ basis: 'tenants',
235
+ fields: c.fields,
236
+ tenant_concentration: buildConcentration(rows, total, inplaceA),
237
+ };
238
+ }
239
+ function buildConcentration(tenants, totalSf, totalIncome) {
240
+ return tenants
241
+ .map((t) => {
242
+ const name = typeof t['tenant_name'] === 'string' ? t['tenant_name'] : null;
243
+ const sf = firstNum(t, SF_KEYS) ?? 0;
244
+ const rent = firstNum(t, RENT_KEYS) ?? 0;
245
+ return { name, sf, rent };
246
+ })
247
+ .filter((t) => t.name && t.rent > 0)
248
+ .sort((a, b) => b.rent - a.rent)
249
+ .slice(0, 5)
250
+ .map((t) => ({
251
+ tenant_name: t.name,
252
+ pct_of_nra: totalSf ? Math.round((t.sf / totalSf) * 1e4) / 1e4 : 0,
253
+ pct_of_income: totalIncome ? Math.round((t.rent / totalIncome) * 1e4) / 1e4 : 0,
254
+ }));
255
+ }
256
+ //# sourceMappingURL=rentroll.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"rentroll.js","sourceRoot":"","sources":["../src/rentroll.ts"],"names":[],"mappings":"AAAA,6EAA6E;AAC7E,6EAA6E;AAC7E,gFAAgF;AAChF,kDAAkD;AAClD,EAAE;AACF,gFAAgF;AAChF,+EAA+E;AAC/E,+EAA+E;AAC/E,iFAAiF;AACjF,mCAAmC;AACnC,EAAE;AACF,gFAAgF;AAChF,mEAAmE;AACnE,EAAE;AACF,8EAA8E;AAC9E,uEAAuE;AACvE,+EAA+E;AAC/E,+EAA+E;AAC/E,8BAA8B;AAE9B,OAAO,EAAE,SAAS,EAAE,SAAS,EAAqB,MAAM,cAAc,CAAC;AAsBvE,MAAM,GAAG,GAAG,SAAS,CAAC;AACtB,MAAM,KAAK,GAAG,CAAC,CAAU,EAAU,EAAE,CAAC,CAAC,OAAO,CAAC,KAAK,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,WAAW,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC;AAErF,2FAA2F;AAC3F,SAAS,OAAO,CAAC,OAAY,EAAE,IAAc;IAC3C,KAAK,MAAM,CAAC,IAAI,IAAI;QAAE,IAAI,CAAC,IAAI,OAAO;YAAE,OAAO,CAAC,CAAC;IACjD,OAAO,IAAI,CAAC,CAAC,CAAC,CAAC;AACjB,CAAC;AAED,iDAAiD;AACjD,SAAS,QAAQ,CAAC,GAAQ,EAAE,IAAc;IACxC,KAAK,MAAM,CAAC,IAAI,IAAI,EAAE,CAAC;QACrB,MAAM,CAAC,GAAG,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC;QACtB,IAAI,CAAC,IAAI,IAAI;YAAE,OAAO,CAAC,CAAC;IAC1B,CAAC;IACD,OAAO,IAAI,CAAC;AACd,CAAC;AAED,0EAA0E;AAC1E,MAAM,UAAU,eAAe,CAAC,OAAY;IAC1C,MAAM,CAAC,GAAG,KAAK,CAAC,OAAO,CAAC,gBAAgB,CAAC,CAAC,CAAC;IAC3C,IAAI,CAAC,KAAK,YAAY;QAAE,OAAO,YAAY,CAAC;IAC5C,IAAI,CAAC,KAAK,aAAa;QAAE,OAAO,aAAa,CAAC;IAC9C,OAAO,KAAK,CAAC,OAAO,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,aAAa,CAAC;AAC1E,CAAC;AAED,qEAAqE;AACrE,MAAM,UAAU,cAAc,CAAC,OAAY;IACzC,MAAM,OAAO,GAAG,eAAe,CAAC,OAAO,CAAC,CAAC;IACzC,IAAI,OAAO,KAAK,YAAY;QAAE,OAAO,gBAAgB,CAAC,OAAO,CAAC,CAAC;IAC/D,OAAO,iBAAiB,CAAC,OAAO,CAAC,CAAC;AACpC,CAAC;AAED,iFAAiF;AAEjF,+EAA+E;AAC/E,kDAAkD;AAClD,MAAM,MAAM,GAAG,IAAI,GAAG,CAAC,CAAC,UAAU,EAAE,QAAQ,EAAE,UAAU,EAAE,EAAE,CAAC,CAAC,CAAC;AAE/D,SAAS,iBAAiB,CAAC,OAAY;IACrC,MAAM,KAAK,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;IAC/B,IAAI,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,IAAI,KAAK,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QAC7C,OAAO,0BAA0B,CAAC,OAAO,EAAE,KAAc,CAAC,CAAC;IAC7D,CAAC;IACD,MAAM,GAAG,GAAG,OAAO,CAAC,kBAAkB,CAAC,CAAC;IACxC,IAAI,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC,IAAI,GAAG,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QACzC,OAAO,wBAAwB,CAAC,OAAO,EAAE,GAAY,CAAC,CAAC;IACzD,CAAC;IACD,OAAO,EAAE,OAAO,EAAE,aAAa,EAAE,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,EAAE,EAAE,CAAC;AAC/D,CAAC;AAED,SAAS,0BAA0B,CAAC,QAAa,EAAE,KAAY;IAC7D,MAAM,CAAC,GAAG,SAAS,EAAE,CAAC;IACtB,MAAM,CAAC,GAAG,KAAK,CAAC,MAAM,CAAC;IACvB,IAAI,GAAG,GAAG,CAAC,CAAC;IACZ,IAAI,GAAG,GAAG,CAAC,CAAC;IACZ,IAAI,MAAM,GAAG,CAAC,CAAC;IACf,IAAI,KAAK,GAAG,CAAC,CAAC;IACd,IAAI,IAAI,GAAG,CAAC,CAAC;IACb,IAAI,GAAG,GAAG,CAAC,CAAC;IACZ,IAAI,IAAI,GAAG,CAAC,CAAC;IACb,IAAI,QAAQ,GAAG,CAAC,CAAC;IACjB,IAAI,KAAK,GAAG,CAAC,CAAC;IAEd,KAAK,MAAM,CAAC,IAAI,KAAK,EAAE,CAAC;QACtB,MAAM,MAAM,GAAG,KAAK,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC;QAClC,IAAI,MAAM,KAAK,UAAU;YAAE,GAAG,EAAE,CAAC;aAC5B,IAAI,MAAM,KAAK,QAAQ;YAAE,GAAG,EAAE,CAAC;aAC/B,IAAI,MAAM,KAAK,QAAQ;YAAE,MAAM,EAAE,CAAC;aAClC,IAAI,MAAM,KAAK,OAAO;YAAE,KAAK,EAAE,CAAC;aAChC,IAAI,MAAM,KAAK,MAAM;YAAE,IAAI,EAAE,CAAC;QAEnC,MAAM,MAAM,GAAG,GAAG,CAAC,CAAC,CAAC,aAAa,CAAC,CAAC,CAAC;QACrC,MAAM,QAAQ,GAAG,GAAG,CAAC,CAAC,CAAC,cAAc,CAAC,CAAC,CAAC;QACxC,IAAI,IAAI,MAAM,IAAI,QAAQ,IAAI,CAAC,CAAC;QAChC,IAAI,MAAM,CAAC,GAAG,CAAC,MAAM,CAAC;YAAE,QAAQ,IAAI,QAAQ,IAAI,CAAC,CAAC;QAClD,KAAK,IAAI,GAAG,CAAC,CAAC,CAAC,0BAA0B,CAAC,CAAC,IAAI,CAAC,CAAC;QACjD,IAAI,CAAC,CAAC,mBAAmB,CAAC,KAAK,IAAI;YAAE,GAAG,EAAE,CAAC;IAC7C,CAAC;IAED,CAAC,CAAC,GAAG,CAAC,aAAa,EAAE,aAAa,EAAE,OAAO,EAAE,CAAC,CAAC,CAAC;IAChD,CAAC,CAAC,GAAG,CAAC,gBAAgB,EAAE,gBAAgB,EAAE,OAAO,EAAE,GAAG,CAAC,CAAC;IACxD,CAAC,CAAC,GAAG,CAAC,cAAc,EAAE,cAAc,EAAE,OAAO,EAAE,GAAG,CAAC,CAAC;IACpD,IAAI,MAAM,GAAG,CAAC;QAAE,CAAC,CAAC,GAAG,CAAC,cAAc,EAAE,iBAAiB,EAAE,OAAO,EAAE,MAAM,CAAC,CAAC;IAC1E,IAAI,KAAK,GAAG,CAAC;QAAE,CAAC,CAAC,GAAG,CAAC,aAAa,EAAE,aAAa,EAAE,OAAO,EAAE,KAAK,CAAC,CAAC;IACnE,IAAI,IAAI,GAAG,CAAC;QAAE,CAAC,CAAC,GAAG,CAAC,YAAY,EAAE,YAAY,EAAE,OAAO,EAAE,IAAI,CAAC,CAAC;IAC/D,CAAC,CAAC,GAAG,CAAC,wBAAwB,EAAE,oBAAoB,EAAE,MAAM,EAAE,CAAC,CAAC,CAAC,CAAC,GAAG,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC;IAClF,CAAC,CAAC,GAAG,CAAC,8BAA8B,EAAE,eAAe,EAAE,UAAU,EAAE,IAAI,CAAC,CAAC;IACzE,CAAC,CAAC,GAAG,CAAC,6BAA6B,EAAE,cAAc,EAAE,UAAU,EAAE,IAAI,GAAG,EAAE,CAAC,CAAC;IAC5E,CAAC,CAAC,GAAG,CAAC,uBAAuB,EAAE,yBAAyB,EAAE,UAAU,EAAE,QAAQ,CAAC,CAAC;IAChF,CAAC,CAAC,GAAG,CAAC,sBAAsB,EAAE,wBAAwB,EAAE,UAAU,EAAE,QAAQ,GAAG,EAAE,CAAC,CAAC;IACnF,CAAC,CAAC,GAAG,CAAC,uBAAuB,EAAE,yBAAyB,EAAE,UAAU,EAAE,IAAI,GAAG,QAAQ,CAAC,CAAC;IACvF,CAAC,CAAC,GAAG,CAAC,mBAAmB,EAAE,iBAAiB,EAAE,MAAM,EAAE,IAAI,CAAC,CAAC,CAAC,CAAC,IAAI,GAAG,QAAQ,CAAC,GAAG,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC;IAC9F,CAAC,CAAC,GAAG,CAAC,qBAAqB,EAAE,uBAAuB,EAAE,UAAU,EAAE,KAAK,CAAC,CAAC;IACzE,CAAC,CAAC,GAAG,CAAC,oBAAoB,EAAE,sBAAsB,EAAE,UAAU,EAAE,KAAK,GAAG,EAAE,CAAC,CAAC;IAC5E,CAAC,CAAC,GAAG,CAAC,4BAA4B,EAAE,8BAA8B,EAAE,UAAU,EAAE,QAAQ,GAAG,KAAK,CAAC,CAAC;IAClG,CAAC,CAAC,GAAG,CAAC,sBAAsB,EAAE,sBAAsB,EAAE,OAAO,EAAE,GAAG,CAAC,CAAC;IACpE,CAAC,CAAC,GAAG,CAAC,oBAAoB,EAAE,kBAAkB,EAAE,MAAM,EAAE,CAAC,CAAC,CAAC,CAAC,GAAG,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC;IAE5E,OAAO;QACL,OAAO,EAAE,aAAa;QACtB,KAAK,EAAE,OAAO;QACd,MAAM,EAAE,CAAC,CAAC,MAAM;QAChB,gBAAgB,EAAE,YAAY,CAAC,KAAK,EAAE,CAAC,CAAC;KACzC,CAAC;AACJ,CAAC;AAED,SAAS,YAAY,CAAC,KAAY,EAAE,KAAa;IAC/C,MAAM,MAAM,GAAG,IAAI,GAAG,EAAiB,CAAC;IACxC,KAAK,MAAM,CAAC,IAAI,KAAK,EAAE,CAAC;QACtB,MAAM,GAAG,GAAG,OAAO,CAAC,CAAC,WAAW,CAAC,KAAK,QAAQ,CAAC,CAAC,CAAE,CAAC,CAAC,WAAW,CAAY,CAAC,CAAC,CAAC,SAAS,CAAC;QACxF,MAAM,IAAI,GAAG,MAAM,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;QAC7B,IAAI,IAAI;YAAE,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;;YAClB,MAAM,CAAC,GAAG,CAAC,GAAG,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC;IAC5B,CAAC;IAED,MAAM,IAAI,GAAG,CAAC,EAAY,EAAiB,EAAE,CAC3C,EAAE,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC,GAAG,EAAE,CAAC,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC;IAE/D,OAAO,CAAC,GAAG,MAAM,CAAC,OAAO,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,SAAS,EAAE,EAAE,CAAC,EAAE,EAAE;QACnD,MAAM,KAAK,GAAG,EAAE,CAAC,MAAM,CAAC;QACxB,MAAM,KAAK,GAAG,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAe,EAAE,CAAC,CAAC,IAAI,IAAI,CAAC,CAAC;QAClF,MAAM,aAAa,GAAG,EAAE;aACrB,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,MAAM,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC;aAC7C,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,cAAc,CAAC,CAAC,CAAC;aAClC,MAAM,CAAC,CAAC,CAAC,EAAe,EAAE,CAAC,CAAC,IAAI,IAAI,CAAC,CAAC;QACzC,MAAM,OAAO,GAAG,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,aAAa,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAe,EAAE,CAAC,CAAC,IAAI,IAAI,CAAC,CAAC;QAC3F,MAAM,UAAU,GAAG,EAAE,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,KAAK,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,KAAK,UAAU,CAAC,CAAC,MAAM,CAAC;QAC9E,MAAM,OAAO,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC;QAC5B,MAAM,UAAU,GAAG,IAAI,CAAC,aAAa,CAAC,CAAC;QACvC,MAAM,SAAS,GAAG,IAAI,CAAC,OAAO,CAAC,CAAC;QAEhC,MAAM,GAAG,GAAQ,EAAE,SAAS,EAAE,KAAK,EAAE,CAAC;QACtC,GAAG,CAAC,UAAU,CAAC,GAAG,OAAO,IAAI,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;QAC/D,GAAG,CAAC,kBAAkB,CAAC,GAAG,UAAU,IAAI,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,UAAU,CAAC,CAAC;QAC1E,GAAG,CAAC,iBAAiB,CAAC,GAAG,SAAS,IAAI,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,SAAS,CAAC,CAAC;QAC1E,GAAG,CAAC,eAAe,CAAC,GAAG,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,UAAU,GAAG,KAAK,CAAC,GAAG,GAAG,CAAC,GAAG,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC;QAChF,GAAG,CAAC,cAAc,CAAC,GAAG,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,KAAK,GAAG,KAAK,CAAC,GAAG,GAAG,CAAC,GAAG,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC;QAC1E,OAAO,GAAG,CAAC;IACb,CAAC,CAAC,CAAC;AACL,CAAC;AAED,SAAS,wBAAwB,CAAC,QAAa,EAAE,GAAU;IACzD,MAAM,CAAC,GAAG,SAAS,EAAE,CAAC;IACtB,IAAI,KAAK,GAAG,CAAC,CAAC;IACd,IAAI,IAAI,GAAG,CAAC,CAAC;IACb,IAAI,QAAQ,GAAG,CAAC,CAAC;IACjB,IAAI,WAAW,GAAG,CAAC,CAAC;IAEpB,KAAK,MAAM,CAAC,IAAI,GAAG,EAAE,CAAC;QACpB,MAAM,KAAK,GAAG,GAAG,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,CAAC;QACnC,MAAM,OAAO,GAAG,GAAG,CAAC,CAAC,CAAC,kBAAkB,CAAC,CAAC,IAAI,CAAC,CAAC;QAChD,MAAM,MAAM,GAAG,GAAG,CAAC,CAAC,CAAC,iBAAiB,CAAC,CAAC,IAAI,OAAO,CAAC;QACpD,MAAM,GAAG,GAAG,GAAG,CAAC,CAAC,CAAC,eAAe,CAAC,CAAC,IAAI,CAAC,CAAC;QACzC,KAAK,IAAI,KAAK,CAAC;QACf,IAAI,IAAI,KAAK,GAAG,MAAM,CAAC;QACvB,QAAQ,IAAI,KAAK,GAAG,GAAG,GAAG,OAAO,CAAC;QAClC,WAAW,IAAI,KAAK,GAAG,GAAG,CAAC;IAC7B,CAAC;IAED,CAAC,CAAC,GAAG,CAAC,aAAa,EAAE,aAAa,EAAE,OAAO,EAAE,KAAK,CAAC,CAAC;IACpD,CAAC,CAAC,GAAG,CAAC,gBAAgB,EAAE,gBAAgB,EAAE,OAAO,EAAE,WAAW,CAAC,CAAC;IAChE,CAAC,CAAC,GAAG,CAAC,wBAAwB,EAAE,oBAAoB,EAAE,MAAM,EAAE,KAAK,CAAC,CAAC,CAAC,WAAW,GAAG,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC;IAClG,CAAC,CAAC,GAAG,CAAC,8BAA8B,EAAE,eAAe,EAAE,UAAU,EAAE,IAAI,CAAC,CAAC;IACzE,CAAC,CAAC,GAAG,CAAC,6BAA6B,EAAE,cAAc,EAAE,UAAU,EAAE,IAAI,GAAG,EAAE,CAAC,CAAC;IAC5E,CAAC,CAAC,GAAG,CAAC,uBAAuB,EAAE,yBAAyB,EAAE,UAAU,EAAE,QAAQ,CAAC,CAAC;IAChF,CAAC,CAAC,GAAG,CAAC,sBAAsB,EAAE,wBAAwB,EAAE,UAAU,EAAE,QAAQ,GAAG,EAAE,CAAC,CAAC;IACnF,CAAC,CAAC,GAAG,CAAC,uBAAuB,EAAE,yBAAyB,EAAE,UAAU,EAAE,IAAI,GAAG,QAAQ,CAAC,CAAC;IACvF,CAAC,CAAC,GAAG,CAAC,mBAAmB,EAAE,iBAAiB,EAAE,MAAM,EAAE,IAAI,CAAC,CAAC,CAAC,CAAC,IAAI,GAAG,QAAQ,CAAC,GAAG,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC;IAE9F,OAAO,EAAE,OAAO,EAAE,aAAa,EAAE,KAAK,EAAE,kBAAkB,EAAE,MAAM,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC;AACjF,CAAC;AAED,+EAA+E;AAE/E,MAAM,OAAO,GAAG,CAAC,WAAW,EAAE,UAAU,CAAC,CAAC;AAC1C,MAAM,SAAS,GAAG,CAAC,kBAAkB,EAAE,kBAAkB,CAAC,CAAC;AAC3D,MAAM,SAAS,GAAG,CAAC,sBAAsB,EAAE,kBAAkB,CAAC,CAAC;AAE/D,SAAS,gBAAgB,CAAC,OAAY;IACpC,MAAM,OAAO,GAAG,OAAO,CAAC,SAAS,CAAC,CAAC;IACnC,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,OAAO,CAAC,IAAI,OAAO,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACpD,OAAO,EAAE,OAAO,EAAE,YAAY,EAAE,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,EAAE,EAAE,CAAC;IAC9D,CAAC;IACD,MAAM,IAAI,GAAG,OAAgB,CAAC;IAC9B,MAAM,CAAC,GAAG,SAAS,EAAE,CAAC;IAEtB,IAAI,KAAK,GAAG,CAAC,CAAC;IACd,IAAI,QAAQ,GAAG,CAAC,CAAC;IACjB,IAAI,QAAQ,GAAG,CAAC,CAAC;IACjB,IAAI,OAAO,GAAG,CAAC,CAAC;IAChB,IAAI,OAAO,GAAG,CAAC,CAAC;IAEhB,KAAK,MAAM,CAAC,IAAI,IAAI,EAAE,CAAC;QACrB,MAAM,EAAE,GAAG,QAAQ,CAAC,CAAC,EAAE,OAAO,CAAC,IAAI,CAAC,CAAC;QACrC,MAAM,QAAQ,GAAG,GAAG,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC,IAAI,CAAC,CAAC;QAC1C,MAAM,IAAI,GAAG,QAAQ,CAAC,CAAC,EAAE,SAAS,CAAC,IAAI,CAAC,CAAC;QACzC,MAAM,MAAM,GAAG,IAAI,GAAG,CAAC,IAAI,KAAK,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,KAAK,QAAQ,CAAC;QAC3D,KAAK,IAAI,EAAE,GAAG,QAAQ,CAAC;QACvB,IAAI,MAAM,EAAE,CAAC;YACX,QAAQ,IAAI,EAAE,CAAC;YACf,QAAQ,IAAI,IAAI,CAAC;YACjB,MAAM,IAAI,GAAG,QAAQ,CAAC,CAAC,EAAE,SAAS,CAAC,CAAC;YACpC,IAAI,IAAI,IAAI,IAAI,IAAI,IAAI,GAAG,CAAC,EAAE,CAAC;gBAC7B,OAAO,IAAI,IAAI,GAAG,IAAI,CAAC;gBACvB,OAAO,IAAI,IAAI,CAAC;YAClB,CAAC;QACH,CAAC;IACH,CAAC;IAED,MAAM,QAAQ,GAAG,OAAO,CAAC,OAAO,EAAE,CAAC,mBAAmB,EAAE,gBAAgB,CAAC,CAAC,CAAC;IAC3E,MAAM,KAAK,GAAG,GAAG,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC,IAAI,KAAK,CAAC;IAC9C,MAAM,QAAQ,GAAG,IAAI,CAAC,GAAG,CAAC,KAAK,GAAG,QAAQ,EAAE,CAAC,CAAC,CAAC;IAE/C,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,OAAO,EAAE,CAAC,aAAa,EAAE,aAAa,CAAC,CAAC,EAAE,aAAa,EAAE,OAAO,EAAE,QAAQ,CAAC,CAAC;IAC1F,CAAC,CAAC,GAAG,CAAC,WAAW,EAAE,WAAW,EAAE,OAAO,EAAE,QAAQ,CAAC,CAAC;IACnD,CAAC,CAAC,GAAG,CAAC,QAAQ,EAAE,mBAAmB,EAAE,OAAO,EAAE,KAAK,CAAC,CAAC;IACrD,CAAC,CAAC,GAAG,CACH,OAAO,CAAC,OAAO,EAAE,CAAC,eAAe,EAAE,wBAAwB,CAAC,CAAC,EAC7D,oBAAoB,EACpB,MAAM,EACN,KAAK,CAAC,CAAC,CAAC,QAAQ,GAAG,KAAK,CAAC,CAAC,CAAC,IAAI,CAChC,CAAC;IACF,CAAC,CAAC,GAAG,CAAC,sBAAsB,EAAE,wBAAwB,EAAE,UAAU,EAAE,QAAQ,CAAC,CAAC;IAC9E,CAAC,CAAC,GAAG,CACH,OAAO,CAAC,OAAO,EAAE,CAAC,uBAAuB,EAAE,wBAAwB,CAAC,CAAC,EACrE,mBAAmB,EACnB,KAAK,EACL,QAAQ,CAAC,CAAC,CAAC,QAAQ,GAAG,QAAQ,CAAC,CAAC,CAAC,IAAI,CACtC,CAAC;IACF,CAAC,CAAC,GAAG,CACH,+BAA+B,EAC/B,cAAc,EACd,MAAM,EACN,OAAO,CAAC,CAAC,CAAC,OAAO,GAAG,OAAO,CAAC,CAAC,CAAC,IAAI,CACnC,CAAC;IAEF,OAAO;QACL,OAAO,EAAE,YAAY;QACrB,KAAK,EAAE,SAAS;QAChB,MAAM,EAAE,CAAC,CAAC,MAAM;QAChB,oBAAoB,EAAE,kBAAkB,CAAC,IAAI,EAAE,KAAK,EAAE,QAAQ,CAAC;KAChE,CAAC;AACJ,CAAC;AAED,SAAS,kBAAkB,CAAC,OAAc,EAAE,OAAe,EAAE,WAAmB;IAC9E,OAAO,OAAO;SACX,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE;QACT,MAAM,IAAI,GAAG,OAAO,CAAC,CAAC,aAAa,CAAC,KAAK,QAAQ,CAAC,CAAC,CAAE,CAAC,CAAC,aAAa,CAAY,CAAC,CAAC,CAAC,IAAI,CAAC;QACxF,MAAM,EAAE,GAAG,QAAQ,CAAC,CAAC,EAAE,OAAO,CAAC,IAAI,CAAC,CAAC;QACrC,MAAM,IAAI,GAAG,QAAQ,CAAC,CAAC,EAAE,SAAS,CAAC,IAAI,CAAC,CAAC;QACzC,OAAO,EAAE,IAAI,EAAE,EAAE,EAAE,IAAI,EAAE,CAAC;IAC5B,CAAC,CAAC;SACD,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,IAAI,CAAC,CAAC,IAAI,GAAG,CAAC,CAAC;SACnC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,GAAG,CAAC,CAAC,IAAI,CAAC;SAC/B,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC;SACX,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;QACX,WAAW,EAAE,CAAC,CAAC,IAAI;QACnB,UAAU,EAAE,OAAO,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,EAAE,GAAG,OAAO,CAAC,GAAG,GAAG,CAAC,GAAG,GAAG,CAAC,CAAC,CAAC,CAAC;QAClE,aAAa,EAAE,WAAW,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,IAAI,GAAG,WAAW,CAAC,GAAG,GAAG,CAAC,GAAG,GAAG,CAAC,CAAC,CAAC,CAAC;KAChF,CAAC,CAAC,CAAC;AACR,CAAC"}
@@ -0,0 +1,29 @@
1
+ import type { ParsedUWFile } from './types.js';
2
+ import type { RenderTier } from './renderer.js';
3
+ export interface ReportOptions {
4
+ /** 'screener' → §7.1 Lender Package; 'analyst' → §7.2 Credit Memo.
5
+ * Defaults to the file's frontmatter `tier`, else 'screener'. */
6
+ tier?: RenderTier;
7
+ /** Cover-page "Prepared by" line. Defaults to frontmatter `created_by`. */
8
+ preparedBy?: string;
9
+ /** Cover-page date (ISO string). Defaults to frontmatter `last_modified`. */
10
+ preparedDate?: string;
11
+ /** Emit only the <article> fragment (no <html> shell / <style>). The host
12
+ * must include REPORT_CSS itself. Used by web tools for live preview. */
13
+ fragment?: boolean;
14
+ /** Replace the standard disclaimer text (§7.1 item 10). */
15
+ disclaimer?: string;
16
+ }
17
+ export interface ReportResult {
18
+ html: string;
19
+ title: string;
20
+ tier: RenderTier;
21
+ /** Spec section ids that produced content, in render order. */
22
+ sectionsRendered: string[];
23
+ /** Spec section ids skipped because the file has no data for them. */
24
+ sectionsSkipped: string[];
25
+ }
26
+ /** Render the lender package / credit memo HTML for a parsed .uw.md file. */
27
+ export declare function renderReportHtml(parsed: ParsedUWFile, opts?: ReportOptions): ReportResult;
28
+ export declare const REPORT_CSS = "\n:root {\n --rpt-ink: #1a2332;\n --rpt-muted: #5b6b7f;\n --rpt-accent: #1e3a5f;\n --rpt-accent-soft: #eef2f7;\n --rpt-rule: #d7dee8;\n --rpt-ok: #1d6f42;\n --rpt-warn: #8a6d1a;\n --rpt-error: #9b2226;\n --rpt-paper: #ffffff;\n}\n.uwmd-report {\n font-family: \"Source Sans 3\", \"Segoe UI\", system-ui, -apple-system, sans-serif;\n color: var(--rpt-ink);\n background: var(--rpt-paper);\n max-width: 52rem;\n margin: 0 auto;\n padding: 2rem 2.5rem;\n font-size: 0.875rem;\n line-height: 1.55;\n}\n.uwmd-report h1, .uwmd-report h2, .uwmd-report h3 {\n font-family: Georgia, \"Times New Roman\", serif;\n color: var(--rpt-accent);\n font-weight: 600;\n margin: 0;\n}\n.uwmd-report h3 { font-size: 0.95rem; margin: 1.1rem 0 0.4rem; }\n\n/* Cover */\n.rpt-cover { padding: 5rem 0 3rem; }\n.rpt-cover-rule { height: 4px; width: 4.5rem; background: var(--rpt-accent); margin-bottom: 2.25rem; }\n.rpt-cover-doc {\n text-transform: uppercase; letter-spacing: 0.22em; font-size: 0.72rem;\n color: var(--rpt-muted); margin: 0 0 0.6rem;\n}\n.rpt-cover h1 { font-size: 2.1rem; line-height: 1.15; }\n.rpt-cover-address { color: var(--rpt-muted); font-size: 1rem; margin: 0.5rem 0 2.5rem; }\n.rpt-cover-facts {\n display: grid; grid-template-columns: repeat(3, 1fr); gap: 1px;\n background: var(--rpt-rule); border: 1px solid var(--rpt-rule); margin-bottom: 3rem;\n}\n.rpt-cover-fact { background: var(--rpt-paper); padding: 0.7rem 0.9rem; }\n.rpt-cover-fact span { display: block; font-size: 0.68rem; text-transform: uppercase; letter-spacing: 0.08em; color: var(--rpt-muted); }\n.rpt-cover-fact strong { font-size: 1rem; font-variant-numeric: tabular-nums; }\n.rpt-cover-foot { color: var(--rpt-muted); font-size: 0.78rem; }\n.rpt-cover-foot p { margin: 0.15rem 0; }\n\n/* Sections */\n.rpt-section { margin: 2.25rem 0; }\n.rpt-section-head { border-bottom: 2px solid var(--rpt-accent); padding-bottom: 0.35rem; margin-bottom: 0.9rem; }\n.rpt-section-head h2 { font-size: 1.25rem; }\n.rpt-subtitle { color: var(--rpt-muted); font-size: 0.78rem; margin: 0.2rem 0 0; }\n.rpt-prose { margin: 0.5rem 0; }\n.rpt-status, .rpt-note { font-size: 0.82rem; color: var(--rpt-muted); margin: 0.6rem 0 0; }\n.rpt-flags { margin: 0.5rem 0 0; }\n.rpt-list { margin: 0.3rem 0 0 1.1rem; padding: 0; }\n.rpt-list li { margin: 0.25rem 0; }\n\n/* Metric grid */\n.rpt-metric-grid {\n display: grid; grid-template-columns: repeat(3, 1fr); gap: 1px;\n background: var(--rpt-rule); border: 1px solid var(--rpt-rule); margin: 0.9rem 0;\n}\n.rpt-metric { background: var(--rpt-accent-soft); padding: 0.65rem 0.85rem; }\n.rpt-metric span { display: block; font-size: 0.66rem; text-transform: uppercase; letter-spacing: 0.08em; color: var(--rpt-muted); }\n.rpt-metric strong { font-size: 1.05rem; font-variant-numeric: tabular-nums; color: var(--rpt-accent); }\n\n/* Tables */\n.uwmd-report table { border-collapse: collapse; width: 100%; margin: 0.6rem 0; font-variant-numeric: tabular-nums; }\n.rpt-table th, .rpt-table td { padding: 0.32rem 0.55rem; border-bottom: 1px solid var(--rpt-rule); }\n.rpt-table thead th {\n background: var(--rpt-accent); color: #fff; font-size: 0.7rem; text-transform: uppercase;\n letter-spacing: 0.06em; text-align: left; font-weight: 600;\n}\n.rpt-table tbody tr:nth-child(even) { background: #f7f9fc; }\n.rpt-table tfoot td { font-weight: 700; border-top: 2px solid var(--rpt-accent); border-bottom: none; }\n.al-right { text-align: right; }\n.al-center { text-align: center; }\n.al-left { text-align: left; }\n.rpt-kv th { text-align: left; font-weight: 600; color: var(--rpt-muted); width: 46%; padding: 0.28rem 0.55rem 0.28rem 0; border-bottom: 1px solid var(--rpt-rule); font-size: 0.8rem; }\n.rpt-kv td { padding: 0.28rem 0; border-bottom: 1px solid var(--rpt-rule); }\n.rpt-kv--compact th, .rpt-kv--compact td { font-size: 0.78rem; padding-top: 0.22rem; padding-bottom: 0.22rem; }\n.rpt-totals { margin-top: -0.4rem; }\n.rpt-total-row td { font-weight: 700; padding: 0.32rem 0.55rem; border-bottom: 1px solid var(--rpt-rule); }\n.rpt-noi-row td { border-top: 2px solid var(--rpt-accent); font-size: 0.95rem; color: var(--rpt-accent); }\n.rpt-basis { font-size: 0.74rem; color: var(--rpt-muted); }\n\n/* Layout */\n.rpt-cols { display: grid; grid-template-columns: 1fr 1fr; gap: 0 1.6rem; align-items: start; }\n.rpt-cols--proforma { grid-template-columns: 3fr 2fr; }\n@media (max-width: 640px) { .rpt-cols, .rpt-cols--proforma { grid-template-columns: 1fr; } }\n\n/* Badges */\n.rpt-badge {\n display: inline-block; font-size: 0.66rem; font-weight: 600; letter-spacing: 0.04em;\n padding: 0.12rem 0.5rem; border-radius: 999px; border: 1px solid var(--rpt-rule);\n background: var(--rpt-accent-soft); color: var(--rpt-muted); margin: 0.1rem 0;\n}\n.rpt-badge--ok { color: var(--rpt-ok); border-color: #bcd9c8; background: #ecf6f0; }\n.rpt-badge--warn { color: var(--rpt-warn); border-color: #e4d5a3; background: #faf5e3; }\n.rpt-badge--error { color: var(--rpt-error); border-color: #e5b4b6; background: #fbeaeb; }\n.rpt-badge--info { color: var(--rpt-accent); border-color: #c3d2e4; background: var(--rpt-accent-soft); }\n\n/* Disclaimer */\n.rpt-disclaimer { margin-top: 1.2rem; padding: 0.9rem 1.1rem; background: var(--rpt-accent-soft); border-left: 3px solid var(--rpt-accent); }\n.rpt-disclaimer h3 { margin-top: 0; }\n.rpt-disclaimer p { font-size: 0.76rem; color: var(--rpt-muted); margin: 0.3rem 0 0; }\n.rpt-amenities { margin: 0.6rem 0 0; }\n\n/* Print */\n@page { size: letter; margin: 0.75in; }\n@media print {\n .uwmd-report { max-width: none; padding: 0; font-size: 10pt; }\n .rpt-cover { page-break-after: always; padding-top: 2.5in; }\n .rpt-section { break-inside: avoid-page; margin: 1.4rem 0; }\n .rpt-section-head { break-after: avoid-page; }\n .rpt-table thead th { background: var(--rpt-accent) !important; -webkit-print-color-adjust: exact; print-color-adjust: exact; }\n .rpt-metric, .rpt-disclaimer, .rpt-badge { -webkit-print-color-adjust: exact; print-color-adjust: exact; }\n a { color: inherit; text-decoration: none; }\n}\n";
29
+ //# sourceMappingURL=report.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"report.d.ts","sourceRoot":"","sources":["../src/report.ts"],"names":[],"mappings":"AAUA,OAAO,KAAK,EAAE,YAAY,EAAW,MAAM,YAAY,CAAC;AAGxD,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,eAAe,CAAC;AAUhD,MAAM,WAAW,aAAa;IAC5B;sEACkE;IAClE,IAAI,CAAC,EAAE,UAAU,CAAC;IAClB,2EAA2E;IAC3E,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,6EAA6E;IAC7E,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB;8EAC0E;IAC1E,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,2DAA2D;IAC3D,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAED,MAAM,WAAW,YAAY;IAC3B,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,UAAU,CAAC;IACjB,+DAA+D;IAC/D,gBAAgB,EAAE,MAAM,EAAE,CAAC;IAC3B,sEAAsE;IACtE,eAAe,EAAE,MAAM,EAAE,CAAC;CAC3B;AAUD,6EAA6E;AAC7E,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,YAAY,EAAE,IAAI,GAAE,aAAkB,GAAG,YAAY,CA+D7F;AA24BD,eAAO,MAAM,UAAU,q9LA0HtB,CAAC"}