@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.
- package/README.md +79 -0
- package/dist/agents/bancroft.d.ts +32 -0
- package/dist/agents/bancroft.d.ts.map +1 -0
- package/dist/agents/bancroft.js +292 -0
- package/dist/agents/bancroft.js.map +1 -0
- package/dist/agents/schemas.d.ts +13 -0
- package/dist/agents/schemas.d.ts.map +1 -0
- package/dist/agents/schemas.js +74 -0
- package/dist/agents/schemas.js.map +1 -0
- package/dist/bindings.d.ts +85 -0
- package/dist/bindings.d.ts.map +1 -0
- package/dist/bindings.js +293 -0
- package/dist/bindings.js.map +1 -0
- package/dist/browser.d.ts +66 -0
- package/dist/browser.d.ts.map +1 -0
- package/dist/browser.js +53 -0
- package/dist/browser.js.map +1 -0
- package/dist/calc/builtins.d.ts +4 -0
- package/dist/calc/builtins.d.ts.map +1 -0
- package/dist/calc/builtins.js +329 -0
- package/dist/calc/builtins.js.map +1 -0
- package/dist/calc/dependencies.d.ts +34 -0
- package/dist/calc/dependencies.d.ts.map +1 -0
- package/dist/calc/dependencies.js +101 -0
- package/dist/calc/dependencies.js.map +1 -0
- package/dist/calc/errors.d.ts +8 -0
- package/dist/calc/errors.d.ts.map +1 -0
- package/dist/calc/errors.js +18 -0
- package/dist/calc/errors.js.map +1 -0
- package/dist/calc/evaluator.d.ts +5 -0
- package/dist/calc/evaluator.d.ts.map +1 -0
- package/dist/calc/evaluator.js +184 -0
- package/dist/calc/evaluator.js.map +1 -0
- package/dist/calc/index.d.ts +14 -0
- package/dist/calc/index.d.ts.map +1 -0
- package/dist/calc/index.js +56 -0
- package/dist/calc/index.js.map +1 -0
- package/dist/calc/parser.d.ts +32 -0
- package/dist/calc/parser.d.ts.map +1 -0
- package/dist/calc/parser.js +361 -0
- package/dist/calc/parser.js.map +1 -0
- package/dist/cascade.d.ts +85 -0
- package/dist/cascade.d.ts.map +1 -0
- package/dist/cascade.js +172 -0
- package/dist/cascade.js.map +1 -0
- package/dist/cli.d.ts +3 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +843 -0
- package/dist/cli.js.map +1 -0
- package/dist/codec.d.ts +25 -0
- package/dist/codec.d.ts.map +1 -0
- package/dist/codec.js +62 -0
- package/dist/codec.js.map +1 -0
- package/dist/codecs.d.ts +6 -0
- package/dist/codecs.d.ts.map +1 -0
- package/dist/codecs.js +12 -0
- package/dist/codecs.js.map +1 -0
- package/dist/compactor.d.ts +11 -0
- package/dist/compactor.d.ts.map +1 -0
- package/dist/compactor.js +84 -0
- package/dist/compactor.js.map +1 -0
- package/dist/context-profiles.d.ts +30 -0
- package/dist/context-profiles.d.ts.map +1 -0
- package/dist/context-profiles.js +225 -0
- package/dist/context-profiles.js.map +1 -0
- package/dist/context.d.ts +55 -0
- package/dist/context.d.ts.map +1 -0
- package/dist/context.js +288 -0
- package/dist/context.js.map +1 -0
- package/dist/dcf.d.ts +9 -0
- package/dist/dcf.d.ts.map +1 -0
- package/dist/dcf.js +75 -0
- package/dist/dcf.js.map +1 -0
- package/dist/debt.d.ts +11 -0
- package/dist/debt.d.ts.map +1 -0
- package/dist/debt.js +85 -0
- package/dist/debt.js.map +1 -0
- package/dist/defaults.d.ts +104 -0
- package/dist/defaults.d.ts.map +1 -0
- package/dist/defaults.js +622 -0
- package/dist/defaults.js.map +1 -0
- package/dist/derived.d.ts +17 -0
- package/dist/derived.d.ts.map +1 -0
- package/dist/derived.js +29 -0
- package/dist/derived.js.map +1 -0
- package/dist/editor.d.ts +76 -0
- package/dist/editor.d.ts.map +1 -0
- package/dist/editor.js +502 -0
- package/dist/editor.js.map +1 -0
- package/dist/envelope.d.ts +51 -0
- package/dist/envelope.d.ts.map +1 -0
- package/dist/envelope.js +213 -0
- package/dist/envelope.js.map +1 -0
- package/dist/format.d.ts +60 -0
- package/dist/format.d.ts.map +1 -0
- package/dist/format.js +115 -0
- package/dist/format.js.map +1 -0
- package/dist/gaps.d.ts +62 -0
- package/dist/gaps.d.ts.map +1 -0
- package/dist/gaps.js +272 -0
- package/dist/gaps.js.map +1 -0
- package/dist/index.d.ts +75 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +47 -0
- package/dist/index.js.map +1 -0
- package/dist/init.d.ts +15 -0
- package/dist/init.d.ts.map +1 -0
- package/dist/init.js +169 -0
- package/dist/init.js.map +1 -0
- package/dist/integrity-canonical.d.ts +17 -0
- package/dist/integrity-canonical.d.ts.map +1 -0
- package/dist/integrity-canonical.js +124 -0
- package/dist/integrity-canonical.js.map +1 -0
- package/dist/integrity.d.ts +54 -0
- package/dist/integrity.d.ts.map +1 -0
- package/dist/integrity.js +244 -0
- package/dist/integrity.js.map +1 -0
- package/dist/modules.d.ts +24 -0
- package/dist/modules.d.ts.map +1 -0
- package/dist/modules.js +322 -0
- package/dist/modules.js.map +1 -0
- package/dist/negotiation.d.ts +19 -0
- package/dist/negotiation.d.ts.map +1 -0
- package/dist/negotiation.js +70 -0
- package/dist/negotiation.js.map +1 -0
- package/dist/opstatement.d.ts +9 -0
- package/dist/opstatement.d.ts.map +1 -0
- package/dist/opstatement.js +80 -0
- package/dist/opstatement.js.map +1 -0
- package/dist/packs/excel-emit.d.ts +21 -0
- package/dist/packs/excel-emit.d.ts.map +1 -0
- package/dist/packs/excel-emit.js +135 -0
- package/dist/packs/excel-emit.js.map +1 -0
- package/dist/packs/index.d.ts +13 -0
- package/dist/packs/index.d.ts.map +1 -0
- package/dist/packs/index.js +37 -0
- package/dist/packs/index.js.map +1 -0
- package/dist/packs/industrial.d.ts +3 -0
- package/dist/packs/industrial.d.ts.map +1 -0
- package/dist/packs/industrial.js +115 -0
- package/dist/packs/industrial.js.map +1 -0
- package/dist/packs/multifamily.d.ts +3 -0
- package/dist/packs/multifamily.d.ts.map +1 -0
- package/dist/packs/multifamily.js +82 -0
- package/dist/packs/multifamily.js.map +1 -0
- package/dist/packs/office.d.ts +3 -0
- package/dist/packs/office.d.ts.map +1 -0
- package/dist/packs/office.js +108 -0
- package/dist/packs/office.js.map +1 -0
- package/dist/packs/retail.d.ts +3 -0
- package/dist/packs/retail.d.ts.map +1 -0
- package/dist/packs/retail.js +115 -0
- package/dist/packs/retail.js.map +1 -0
- package/dist/packs/self-storage.d.ts +3 -0
- package/dist/packs/self-storage.d.ts.map +1 -0
- package/dist/packs/self-storage.js +105 -0
- package/dist/packs/self-storage.js.map +1 -0
- package/dist/parser.d.ts +15 -0
- package/dist/parser.d.ts.map +1 -0
- package/dist/parser.js +430 -0
- package/dist/parser.js.map +1 -0
- package/dist/protocol.d.ts +389 -0
- package/dist/protocol.d.ts.map +1 -0
- package/dist/protocol.js +714 -0
- package/dist/protocol.js.map +1 -0
- package/dist/refinement.d.ts +63 -0
- package/dist/refinement.d.ts.map +1 -0
- package/dist/refinement.js +242 -0
- package/dist/refinement.js.map +1 -0
- package/dist/renderer.d.ts +22 -0
- package/dist/renderer.d.ts.map +1 -0
- package/dist/renderer.js +478 -0
- package/dist/renderer.js.map +1 -0
- package/dist/rentroll.d.ts +21 -0
- package/dist/rentroll.d.ts.map +1 -0
- package/dist/rentroll.js +256 -0
- package/dist/rentroll.js.map +1 -0
- package/dist/report.d.ts +29 -0
- package/dist/report.d.ts.map +1 -0
- package/dist/report.js +924 -0
- package/dist/report.js.map +1 -0
- package/dist/runner.d.ts +43 -0
- package/dist/runner.d.ts.map +1 -0
- package/dist/runner.js +288 -0
- package/dist/runner.js.map +1 -0
- package/dist/sourcesuses.d.ts +14 -0
- package/dist/sourcesuses.d.ts.map +1 -0
- package/dist/sourcesuses.js +63 -0
- package/dist/sourcesuses.js.map +1 -0
- package/dist/types.d.ts +248 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +15 -0
- package/dist/types.js.map +1 -0
- package/dist/uwcsv.d.ts +23 -0
- package/dist/uwcsv.d.ts.map +1 -0
- package/dist/uwcsv.js +877 -0
- package/dist/uwcsv.js.map +1 -0
- package/dist/uwjson.d.ts +19 -0
- package/dist/uwjson.d.ts.map +1 -0
- package/dist/uwjson.js +61 -0
- package/dist/uwjson.js.map +1 -0
- package/dist/uwxml.d.ts +18 -0
- package/dist/uwxml.d.ts.map +1 -0
- package/dist/uwxml.js +297 -0
- package/dist/uwxml.js.map +1 -0
- package/dist/validator.d.ts +35 -0
- package/dist/validator.d.ts.map +1 -0
- package/dist/validator.js +553 -0
- package/dist/validator.js.map +1 -0
- package/dist/valuation.d.ts +9 -0
- package/dist/valuation.d.ts.map +1 -0
- package/dist/valuation.js +34 -0
- package/dist/valuation.js.map +1 -0
- package/package.json +58 -0
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
// AST → Excel formula emitter.
|
|
2
|
+
//
|
|
3
|
+
// Takes a Tier-3 safe expression (parsed by @uwmd/core's calc parser) and a
|
|
4
|
+
// map from calc-engine identifier paths to Excel named ranges. Emits an Excel
|
|
5
|
+
// formula string (without the leading "=") that produces the same number Excel
|
|
6
|
+
// would compute via its own engine.
|
|
7
|
+
//
|
|
8
|
+
// This is what unlocks "write a calc once, consume it everywhere": the web
|
|
9
|
+
// editor evaluates the expression directly via `evaluateCalc()`, while
|
|
10
|
+
// @uwmd/excel emits the same expression as an Excel formula that references
|
|
11
|
+
// workbook-scope named ranges. Both produce identical numbers by construction.
|
|
12
|
+
//
|
|
13
|
+
// Identifier mapping rules:
|
|
14
|
+
// - A calc-engine path like `noi_model.net_operating_income` maps to a
|
|
15
|
+
// named range like `noi`. The map is keyed on the joined path
|
|
16
|
+
// (`section.field.subfield`) and supplied by the caller.
|
|
17
|
+
// - Bare identifiers (no dot path) also look up directly in the map.
|
|
18
|
+
// - If a path isn't in the map, emission fails with EXCEL-EMIT-PATH.
|
|
19
|
+
//
|
|
20
|
+
// Operator / function coverage:
|
|
21
|
+
// - Arithmetic +, -, *, / and parentheses → identical syntax in Excel.
|
|
22
|
+
// - Modulo (%) → MOD(left, right).
|
|
23
|
+
// - Comparison and ternary → IF(test, then, else).
|
|
24
|
+
// - Builtins map to their Excel equivalents (SUM, AVERAGE, MIN, MAX, IF,
|
|
25
|
+
// ROUND, PMT, NPV, IRR). Functions without a clean Excel equivalent
|
|
26
|
+
// (`coalesce`, `avg` with null handling) raise EXCEL-EMIT-FN.
|
|
27
|
+
import { parseExpression } from '../calc/parser.js';
|
|
28
|
+
export class ExcelEmitError extends Error {
|
|
29
|
+
code;
|
|
30
|
+
constructor(code, message) {
|
|
31
|
+
super(message);
|
|
32
|
+
this.code = code;
|
|
33
|
+
this.name = 'ExcelEmitError';
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
const FUNCTION_MAP = {
|
|
37
|
+
sum: 'SUM',
|
|
38
|
+
min: 'MIN',
|
|
39
|
+
max: 'MAX',
|
|
40
|
+
if: 'IF',
|
|
41
|
+
round: 'ROUND',
|
|
42
|
+
pmt: 'PMT',
|
|
43
|
+
npv: 'NPV',
|
|
44
|
+
irr: 'IRR',
|
|
45
|
+
abs: 'ABS',
|
|
46
|
+
floor: 'FLOOR',
|
|
47
|
+
ceil: 'CEILING',
|
|
48
|
+
sqrt: 'SQRT',
|
|
49
|
+
pow: 'POWER',
|
|
50
|
+
log: 'LN',
|
|
51
|
+
exp: 'EXP',
|
|
52
|
+
fv: 'FV',
|
|
53
|
+
pv: 'PV',
|
|
54
|
+
nper: 'NPER',
|
|
55
|
+
};
|
|
56
|
+
/**
|
|
57
|
+
* Emit an Excel formula (without leading `=`) for a parsed expression.
|
|
58
|
+
* Throws ExcelEmitError if the expression references a path not in the map
|
|
59
|
+
* or uses a builtin without a clean Excel equivalent.
|
|
60
|
+
*/
|
|
61
|
+
export function emitFromAst(expr, opts) {
|
|
62
|
+
switch (expr.kind) {
|
|
63
|
+
case 'literal':
|
|
64
|
+
if (expr.value === null)
|
|
65
|
+
return '""';
|
|
66
|
+
if (typeof expr.value === 'boolean')
|
|
67
|
+
return expr.value ? 'TRUE' : 'FALSE';
|
|
68
|
+
if (typeof expr.value === 'string')
|
|
69
|
+
return `"${expr.value.replace(/"/g, '""')}"`;
|
|
70
|
+
return String(expr.value);
|
|
71
|
+
case 'ident': {
|
|
72
|
+
const mapped = opts.namedRanges.get(expr.name);
|
|
73
|
+
if (!mapped) {
|
|
74
|
+
throw new ExcelEmitError('EXCEL-EMIT-PATH', `No Excel named range for identifier '${expr.name}'.`);
|
|
75
|
+
}
|
|
76
|
+
return mapped;
|
|
77
|
+
}
|
|
78
|
+
case 'path': {
|
|
79
|
+
const joined = [expr.head, ...expr.segments].join('.');
|
|
80
|
+
const mapped = opts.namedRanges.get(joined);
|
|
81
|
+
if (!mapped) {
|
|
82
|
+
throw new ExcelEmitError('EXCEL-EMIT-PATH', `No Excel named range for path '${joined}'.`);
|
|
83
|
+
}
|
|
84
|
+
return mapped;
|
|
85
|
+
}
|
|
86
|
+
case 'unary': {
|
|
87
|
+
const inner = emitFromAst(expr.operand, opts);
|
|
88
|
+
if (expr.op === '-')
|
|
89
|
+
return `-(${inner})`;
|
|
90
|
+
return `NOT(${inner})`;
|
|
91
|
+
}
|
|
92
|
+
case 'binary': {
|
|
93
|
+
const left = emitFromAst(expr.left, opts);
|
|
94
|
+
const right = emitFromAst(expr.right, opts);
|
|
95
|
+
switch (expr.op) {
|
|
96
|
+
case '+':
|
|
97
|
+
case '-':
|
|
98
|
+
case '*':
|
|
99
|
+
case '/':
|
|
100
|
+
return `(${left}${expr.op}${right})`;
|
|
101
|
+
case '%':
|
|
102
|
+
return `MOD(${left},${right})`;
|
|
103
|
+
case '==': return `(${left}=${right})`;
|
|
104
|
+
case '!=': return `(${left}<>${right})`;
|
|
105
|
+
case '<':
|
|
106
|
+
case '<=':
|
|
107
|
+
case '>':
|
|
108
|
+
case '>=':
|
|
109
|
+
return `(${left}${expr.op}${right})`;
|
|
110
|
+
case '&&': return `AND(${left},${right})`;
|
|
111
|
+
case '||': return `OR(${left},${right})`;
|
|
112
|
+
}
|
|
113
|
+
throw new ExcelEmitError('EXCEL-EMIT-OP', 'Unreachable: unhandled binary operator.');
|
|
114
|
+
}
|
|
115
|
+
case 'cond': {
|
|
116
|
+
const test = emitFromAst(expr.test, opts);
|
|
117
|
+
const consequent = emitFromAst(expr.consequent, opts);
|
|
118
|
+
const alternate = emitFromAst(expr.else, opts);
|
|
119
|
+
return `IF(${test},${consequent},${alternate})`;
|
|
120
|
+
}
|
|
121
|
+
case 'call': {
|
|
122
|
+
const xlName = FUNCTION_MAP[expr.name];
|
|
123
|
+
if (!xlName) {
|
|
124
|
+
throw new ExcelEmitError('EXCEL-EMIT-FN', `No Excel mapping for function '${expr.name}'.`);
|
|
125
|
+
}
|
|
126
|
+
const args = expr.args.map((a) => emitFromAst(a, opts)).join(',');
|
|
127
|
+
return `${xlName}(${args})`;
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
/** Convenience: parse + emit in one call. */
|
|
132
|
+
export function emitExcelFormula(formula, opts) {
|
|
133
|
+
return emitFromAst(parseExpression(formula), opts);
|
|
134
|
+
}
|
|
135
|
+
//# sourceMappingURL=excel-emit.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"excel-emit.js","sourceRoot":"","sources":["../../src/packs/excel-emit.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import type { ModuleManifest } from '../protocol.js';
|
|
2
|
+
export { MULTIFAMILY_PACK } from './multifamily.js';
|
|
3
|
+
export { OFFICE_PACK } from './office.js';
|
|
4
|
+
export { RETAIL_PACK } from './retail.js';
|
|
5
|
+
export { INDUSTRIAL_PACK } from './industrial.js';
|
|
6
|
+
export { SELF_STORAGE_PACK } from './self-storage.js';
|
|
7
|
+
export { emitFromAst, emitExcelFormula, ExcelEmitError, type ExcelEmitOptions, } from './excel-emit.js';
|
|
8
|
+
/**
|
|
9
|
+
* Look up the built-in calc pack for an asset class. Returns null when no pack
|
|
10
|
+
* is registered (callers may fall back to the multifamily pack or skip metrics).
|
|
11
|
+
*/
|
|
12
|
+
export declare function getPackForAssetClass(asset_class: string): ModuleManifest | null;
|
|
13
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/packs/index.ts"],"names":[],"mappings":"AAOA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,gBAAgB,CAAC;AAOrD,OAAO,EAAE,gBAAgB,EAAE,MAAM,kBAAkB,CAAC;AACpD,OAAO,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAC1C,OAAO,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAC1C,OAAO,EAAE,eAAe,EAAE,MAAM,iBAAiB,CAAC;AAClD,OAAO,EAAE,iBAAiB,EAAE,MAAM,mBAAmB,CAAC;AACtD,OAAO,EACL,WAAW,EACX,gBAAgB,EAChB,cAAc,EACd,KAAK,gBAAgB,GACtB,MAAM,iBAAiB,CAAC;AAezB;;;GAGG;AACH,wBAAgB,oBAAoB,CAAC,WAAW,EAAE,MAAM,GAAG,cAAc,GAAG,IAAI,CAE/E"}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
// Asset-class calc packs — public surface.
|
|
2
|
+
//
|
|
3
|
+
// A "pack" is a ModuleManifest declaring derived-metric calcs (and, in future
|
|
4
|
+
// versions, validations and view models) for a specific asset class. Packs are
|
|
5
|
+
// the modular unit that lets every tool in the ecosystem (web editor, Excel
|
|
6
|
+
// converter, agents, future viewers) consume the same calc definitions.
|
|
7
|
+
import { MULTIFAMILY_PACK } from './multifamily.js';
|
|
8
|
+
import { OFFICE_PACK } from './office.js';
|
|
9
|
+
import { RETAIL_PACK } from './retail.js';
|
|
10
|
+
import { INDUSTRIAL_PACK } from './industrial.js';
|
|
11
|
+
import { SELF_STORAGE_PACK } from './self-storage.js';
|
|
12
|
+
export { MULTIFAMILY_PACK } from './multifamily.js';
|
|
13
|
+
export { OFFICE_PACK } from './office.js';
|
|
14
|
+
export { RETAIL_PACK } from './retail.js';
|
|
15
|
+
export { INDUSTRIAL_PACK } from './industrial.js';
|
|
16
|
+
export { SELF_STORAGE_PACK } from './self-storage.js';
|
|
17
|
+
export { emitFromAst, emitExcelFormula, ExcelEmitError, } from './excel-emit.js';
|
|
18
|
+
/**
|
|
19
|
+
* Built-in calc packs keyed by the asset class they target. Mirrors the
|
|
20
|
+
* defaults REGISTRY in `defaults.ts`. Third-party / module-loaded packs are out
|
|
21
|
+
* of scope for v1 (see RFC 0003) — these are the compiled-in starter packs.
|
|
22
|
+
*/
|
|
23
|
+
const PACK_REGISTRY = Object.freeze({
|
|
24
|
+
multifamily: MULTIFAMILY_PACK,
|
|
25
|
+
office: OFFICE_PACK,
|
|
26
|
+
retail: RETAIL_PACK,
|
|
27
|
+
industrial: INDUSTRIAL_PACK,
|
|
28
|
+
self_storage: SELF_STORAGE_PACK,
|
|
29
|
+
});
|
|
30
|
+
/**
|
|
31
|
+
* Look up the built-in calc pack for an asset class. Returns null when no pack
|
|
32
|
+
* is registered (callers may fall back to the multifamily pack or skip metrics).
|
|
33
|
+
*/
|
|
34
|
+
export function getPackForAssetClass(asset_class) {
|
|
35
|
+
return PACK_REGISTRY[asset_class] ?? null;
|
|
36
|
+
}
|
|
37
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/packs/index.ts"],"names":[],"mappings":"AAAA,2CAA2C;AAC3C,EAAE;AACF,8EAA8E;AAC9E,+EAA+E;AAC/E,4EAA4E;AAC5E,wEAAwE;AAGxE,OAAO,EAAE,gBAAgB,EAAE,MAAM,kBAAkB,CAAC;AACpD,OAAO,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAC1C,OAAO,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAC1C,OAAO,EAAE,eAAe,EAAE,MAAM,iBAAiB,CAAC;AAClD,OAAO,EAAE,iBAAiB,EAAE,MAAM,mBAAmB,CAAC;AAEtD,OAAO,EAAE,gBAAgB,EAAE,MAAM,kBAAkB,CAAC;AACpD,OAAO,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAC1C,OAAO,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAC1C,OAAO,EAAE,eAAe,EAAE,MAAM,iBAAiB,CAAC;AAClD,OAAO,EAAE,iBAAiB,EAAE,MAAM,mBAAmB,CAAC;AACtD,OAAO,EACL,WAAW,EACX,gBAAgB,EAChB,cAAc,GAEf,MAAM,iBAAiB,CAAC;AAEzB;;;;GAIG;AACH,MAAM,aAAa,GAA6C,MAAM,CAAC,MAAM,CAAC;IAC5E,WAAW,EAAE,gBAAgB;IAC7B,MAAM,EAAE,WAAW;IACnB,MAAM,EAAE,WAAW;IACnB,UAAU,EAAE,eAAe;IAC3B,YAAY,EAAE,iBAAiB;CAChC,CAAC,CAAC;AAEH;;;GAGG;AACH,MAAM,UAAU,oBAAoB,CAAC,WAAmB;IACtD,OAAO,aAAa,CAAC,WAAW,CAAC,IAAI,IAAI,CAAC;AAC5C,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"industrial.d.ts","sourceRoot":"","sources":["../../src/packs/industrial.ts"],"names":[],"mappings":"AAgBA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,gBAAgB,CAAC;AAErD,eAAO,MAAM,eAAe,EAAE,cAsG7B,CAAC"}
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
// Canonical industrial calc pack.
|
|
2
|
+
//
|
|
3
|
+
// Single source of truth for the industrial derived metrics. Consumed by the
|
|
4
|
+
// web editor (via @uwmd/core/browser), the @uwmd/excel converter (via
|
|
5
|
+
// emitExcelFormula), conformance tests, and any future asset-class viewer.
|
|
6
|
+
// Add a metric here once and every tool picks it up.
|
|
7
|
+
//
|
|
8
|
+
// Each formula is a Tier-3 safe expression evaluable by `evaluateCalc()`
|
|
9
|
+
// against a parsed .uw.md file. Field paths reference the canonical industrial
|
|
10
|
+
// schema (see UW_FORMAT_SPEC §4 and the Ironwood Logistics example).
|
|
11
|
+
//
|
|
12
|
+
// Industrial measures size in rentable building area (`property.rentable_square_feet`)
|
|
13
|
+
// and occupancy in SF (`rent_roll.occupied_sf` / `total_rentable_sf`), like
|
|
14
|
+
// office. Like retail, it carries an `expense_recovery_ratio` metric — industrial
|
|
15
|
+
// is predominantly NNN, so most operating expenses are recovered from tenants.
|
|
16
|
+
export const INDUSTRIAL_PACK = {
|
|
17
|
+
manifest_version: '1',
|
|
18
|
+
id: 'org.uwmd.pack.industrial',
|
|
19
|
+
name: 'Industrial Starter Pack',
|
|
20
|
+
version: '1.0.0',
|
|
21
|
+
description: 'Twelve derived metrics for industrial underwriting: cap rate, LTV, LTC, DSCR, debt yield, $/sqft, loan/sqft, NOI/sqft, expense ratio, expense recovery ratio, cash-on-cash, occupancy.',
|
|
22
|
+
authors: ['UW Markdown Working Group'],
|
|
23
|
+
license: 'MIT',
|
|
24
|
+
requires_protocol: '^1.0.0',
|
|
25
|
+
requires_format: '^1.1.0',
|
|
26
|
+
requires_tier: 'tier-3-calc-host',
|
|
27
|
+
asset_classes: ['industrial'],
|
|
28
|
+
calculations: [
|
|
29
|
+
{
|
|
30
|
+
id: 'cap_rate',
|
|
31
|
+
label: 'Cap Rate',
|
|
32
|
+
formula: 'noi_model.net_operating_income / valuation.purchase_price',
|
|
33
|
+
unit: '%',
|
|
34
|
+
deterministic: true,
|
|
35
|
+
},
|
|
36
|
+
{
|
|
37
|
+
id: 'ltv',
|
|
38
|
+
label: 'LTV',
|
|
39
|
+
formula: 'debt_structure.loan_amount / valuation.purchase_price',
|
|
40
|
+
unit: '%',
|
|
41
|
+
deterministic: true,
|
|
42
|
+
},
|
|
43
|
+
{
|
|
44
|
+
id: 'ltc',
|
|
45
|
+
label: 'LTC',
|
|
46
|
+
formula: 'debt_structure.loan_amount / sources_uses.uses.total',
|
|
47
|
+
unit: '%',
|
|
48
|
+
deterministic: true,
|
|
49
|
+
},
|
|
50
|
+
{
|
|
51
|
+
id: 'dscr',
|
|
52
|
+
label: 'DSCR',
|
|
53
|
+
formula: 'noi_model.net_operating_income / debt_structure.annual_debt_service',
|
|
54
|
+
unit: 'x',
|
|
55
|
+
deterministic: true,
|
|
56
|
+
},
|
|
57
|
+
{
|
|
58
|
+
id: 'debt_yield',
|
|
59
|
+
label: 'Debt Yield',
|
|
60
|
+
formula: 'noi_model.net_operating_income / debt_structure.loan_amount',
|
|
61
|
+
unit: '%',
|
|
62
|
+
deterministic: true,
|
|
63
|
+
},
|
|
64
|
+
{
|
|
65
|
+
id: 'price_per_sqft',
|
|
66
|
+
label: 'Price / SqFt',
|
|
67
|
+
formula: 'valuation.purchase_price / property.rentable_square_feet',
|
|
68
|
+
unit: '$',
|
|
69
|
+
deterministic: true,
|
|
70
|
+
},
|
|
71
|
+
{
|
|
72
|
+
id: 'loan_per_sqft',
|
|
73
|
+
label: 'Loan / SqFt',
|
|
74
|
+
formula: 'debt_structure.loan_amount / property.rentable_square_feet',
|
|
75
|
+
unit: '$',
|
|
76
|
+
deterministic: true,
|
|
77
|
+
},
|
|
78
|
+
{
|
|
79
|
+
id: 'noi_per_sqft',
|
|
80
|
+
label: 'NOI / SqFt',
|
|
81
|
+
formula: 'noi_model.net_operating_income / property.rentable_square_feet',
|
|
82
|
+
unit: '$',
|
|
83
|
+
deterministic: true,
|
|
84
|
+
},
|
|
85
|
+
{
|
|
86
|
+
id: 'expense_ratio',
|
|
87
|
+
label: 'Operating Expense Ratio',
|
|
88
|
+
formula: 'noi_model.expenses.total_operating_expenses / noi_model.income.effective_gross_income',
|
|
89
|
+
unit: '%',
|
|
90
|
+
deterministic: true,
|
|
91
|
+
},
|
|
92
|
+
{
|
|
93
|
+
id: 'expense_recovery_ratio',
|
|
94
|
+
label: 'Expense Recovery Ratio',
|
|
95
|
+
formula: 'noi_model.income.expense_reimbursements / noi_model.expenses.total_operating_expenses',
|
|
96
|
+
unit: '%',
|
|
97
|
+
deterministic: true,
|
|
98
|
+
},
|
|
99
|
+
{
|
|
100
|
+
id: 'cash_on_cash',
|
|
101
|
+
label: 'Cash-on-Cash',
|
|
102
|
+
formula: '(noi_model.net_operating_income - debt_structure.annual_debt_service) / sources_uses.sources.sponsor_equity',
|
|
103
|
+
unit: '%',
|
|
104
|
+
deterministic: true,
|
|
105
|
+
},
|
|
106
|
+
{
|
|
107
|
+
id: 'occupancy',
|
|
108
|
+
label: 'Occupancy',
|
|
109
|
+
formula: 'rent_roll.occupied_sf / rent_roll.total_rentable_sf',
|
|
110
|
+
unit: '%',
|
|
111
|
+
deterministic: true,
|
|
112
|
+
},
|
|
113
|
+
],
|
|
114
|
+
};
|
|
115
|
+
//# sourceMappingURL=industrial.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"industrial.js","sourceRoot":"","sources":["../../src/packs/industrial.ts"],"names":[],"mappings":"AAAA,kCAAkC;AAClC,EAAE;AACF,6EAA6E;AAC7E,sEAAsE;AACtE,2EAA2E;AAC3E,qDAAqD;AACrD,EAAE;AACF,yEAAyE;AACzE,+EAA+E;AAC/E,qEAAqE;AACrE,EAAE;AACF,uFAAuF;AACvF,4EAA4E;AAC5E,kFAAkF;AAClF,+EAA+E;AAI/E,MAAM,CAAC,MAAM,eAAe,GAAmB;IAC7C,gBAAgB,EAAE,GAAG;IACrB,EAAE,EAAE,0BAA0B;IAC9B,IAAI,EAAE,yBAAyB;IAC/B,OAAO,EAAE,OAAO;IAChB,WAAW,EACT,wLAAwL;IAC1L,OAAO,EAAE,CAAC,2BAA2B,CAAC;IACtC,OAAO,EAAE,KAAK;IACd,iBAAiB,EAAE,QAAQ;IAC3B,eAAe,EAAE,QAAQ;IACzB,aAAa,EAAE,kBAAkB;IACjC,aAAa,EAAE,CAAC,YAAY,CAAC;IAC7B,YAAY,EAAE;QACZ;YACE,EAAE,EAAE,UAAU;YACd,KAAK,EAAE,UAAU;YACjB,OAAO,EAAE,2DAA2D;YACpE,IAAI,EAAE,GAAG;YACT,aAAa,EAAE,IAAI;SACpB;QACD;YACE,EAAE,EAAE,KAAK;YACT,KAAK,EAAE,KAAK;YACZ,OAAO,EAAE,uDAAuD;YAChE,IAAI,EAAE,GAAG;YACT,aAAa,EAAE,IAAI;SACpB;QACD;YACE,EAAE,EAAE,KAAK;YACT,KAAK,EAAE,KAAK;YACZ,OAAO,EAAE,sDAAsD;YAC/D,IAAI,EAAE,GAAG;YACT,aAAa,EAAE,IAAI;SACpB;QACD;YACE,EAAE,EAAE,MAAM;YACV,KAAK,EAAE,MAAM;YACb,OAAO,EAAE,qEAAqE;YAC9E,IAAI,EAAE,GAAG;YACT,aAAa,EAAE,IAAI;SACpB;QACD;YACE,EAAE,EAAE,YAAY;YAChB,KAAK,EAAE,YAAY;YACnB,OAAO,EAAE,6DAA6D;YACtE,IAAI,EAAE,GAAG;YACT,aAAa,EAAE,IAAI;SACpB;QACD;YACE,EAAE,EAAE,gBAAgB;YACpB,KAAK,EAAE,cAAc;YACrB,OAAO,EAAE,0DAA0D;YACnE,IAAI,EAAE,GAAG;YACT,aAAa,EAAE,IAAI;SACpB;QACD;YACE,EAAE,EAAE,eAAe;YACnB,KAAK,EAAE,aAAa;YACpB,OAAO,EAAE,4DAA4D;YACrE,IAAI,EAAE,GAAG;YACT,aAAa,EAAE,IAAI;SACpB;QACD;YACE,EAAE,EAAE,cAAc;YAClB,KAAK,EAAE,YAAY;YACnB,OAAO,EAAE,gEAAgE;YACzE,IAAI,EAAE,GAAG;YACT,aAAa,EAAE,IAAI;SACpB;QACD;YACE,EAAE,EAAE,eAAe;YACnB,KAAK,EAAE,yBAAyB;YAChC,OAAO,EACL,uFAAuF;YACzF,IAAI,EAAE,GAAG;YACT,aAAa,EAAE,IAAI;SACpB;QACD;YACE,EAAE,EAAE,wBAAwB;YAC5B,KAAK,EAAE,wBAAwB;YAC/B,OAAO,EACL,uFAAuF;YACzF,IAAI,EAAE,GAAG;YACT,aAAa,EAAE,IAAI;SACpB;QACD;YACE,EAAE,EAAE,cAAc;YAClB,KAAK,EAAE,cAAc;YACrB,OAAO,EACL,6GAA6G;YAC/G,IAAI,EAAE,GAAG;YACT,aAAa,EAAE,IAAI;SACpB;QACD;YACE,EAAE,EAAE,WAAW;YACf,KAAK,EAAE,WAAW;YAClB,OAAO,EAAE,qDAAqD;YAC9D,IAAI,EAAE,GAAG;YACT,aAAa,EAAE,IAAI;SACpB;KACF;CACF,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"multifamily.d.ts","sourceRoot":"","sources":["../../src/packs/multifamily.ts"],"names":[],"mappings":"AAWA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,gBAAgB,CAAC;AAErD,eAAO,MAAM,gBAAgB,EAAE,cAwE9B,CAAC"}
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
// Canonical multifamily calc pack.
|
|
2
|
+
//
|
|
3
|
+
// Single source of truth for the eight multifamily derived metrics. Consumed
|
|
4
|
+
// by the web editor (via @uwmd/core/browser), the @uwmd/excel converter (via
|
|
5
|
+
// emitExcelFormula), conformance tests, and any future asset-class viewer.
|
|
6
|
+
// Add a metric here once and every tool picks it up.
|
|
7
|
+
//
|
|
8
|
+
// Each formula is a Tier-3 safe expression evaluable by `evaluateCalc()`
|
|
9
|
+
// against a parsed .uw.md file. Field paths reference the canonical
|
|
10
|
+
// multifamily schema (see UW_FORMAT_SPEC §4 and the Parkview example).
|
|
11
|
+
export const MULTIFAMILY_PACK = {
|
|
12
|
+
manifest_version: '1',
|
|
13
|
+
id: 'org.uwmd.pack.multifamily',
|
|
14
|
+
name: 'Multifamily Starter Pack',
|
|
15
|
+
version: '1.0.0',
|
|
16
|
+
description: 'Eight derived metrics for multifamily underwriting: cap rate, LTV, DSCR, debt yield, $/unit, $/sqft, price/unit, cash-on-cash.',
|
|
17
|
+
authors: ['UW Markdown Working Group'],
|
|
18
|
+
license: 'MIT',
|
|
19
|
+
requires_protocol: '^1.0.0',
|
|
20
|
+
requires_format: '^1.1.0',
|
|
21
|
+
requires_tier: 'tier-3-calc-host',
|
|
22
|
+
asset_classes: ['multifamily'],
|
|
23
|
+
calculations: [
|
|
24
|
+
{
|
|
25
|
+
id: 'cap_rate',
|
|
26
|
+
label: 'Cap Rate',
|
|
27
|
+
formula: 'noi_model.net_operating_income / valuation.purchase_price',
|
|
28
|
+
unit: '%',
|
|
29
|
+
deterministic: true,
|
|
30
|
+
},
|
|
31
|
+
{
|
|
32
|
+
id: 'ltv',
|
|
33
|
+
label: 'LTV',
|
|
34
|
+
formula: 'debt_structure.loan_amount / valuation.purchase_price',
|
|
35
|
+
unit: '%',
|
|
36
|
+
deterministic: true,
|
|
37
|
+
},
|
|
38
|
+
{
|
|
39
|
+
id: 'dscr',
|
|
40
|
+
label: 'DSCR',
|
|
41
|
+
formula: 'noi_model.net_operating_income / debt_structure.annual_debt_service',
|
|
42
|
+
unit: 'x',
|
|
43
|
+
deterministic: true,
|
|
44
|
+
},
|
|
45
|
+
{
|
|
46
|
+
id: 'debt_yield',
|
|
47
|
+
label: 'Debt Yield',
|
|
48
|
+
formula: 'noi_model.net_operating_income / debt_structure.loan_amount',
|
|
49
|
+
unit: '%',
|
|
50
|
+
deterministic: true,
|
|
51
|
+
},
|
|
52
|
+
{
|
|
53
|
+
id: 'price_per_unit',
|
|
54
|
+
label: 'Price / Unit',
|
|
55
|
+
formula: 'valuation.purchase_price / property.total_units',
|
|
56
|
+
unit: '$',
|
|
57
|
+
deterministic: true,
|
|
58
|
+
},
|
|
59
|
+
{
|
|
60
|
+
id: 'loan_per_unit',
|
|
61
|
+
label: 'Loan / Unit',
|
|
62
|
+
formula: 'debt_structure.loan_amount / property.total_units',
|
|
63
|
+
unit: '$',
|
|
64
|
+
deterministic: true,
|
|
65
|
+
},
|
|
66
|
+
{
|
|
67
|
+
id: 'loan_per_sqft',
|
|
68
|
+
label: 'Loan / SqFt',
|
|
69
|
+
formula: 'debt_structure.loan_amount / property.total_nra_sqft',
|
|
70
|
+
unit: '$',
|
|
71
|
+
deterministic: true,
|
|
72
|
+
},
|
|
73
|
+
{
|
|
74
|
+
id: 'cash_on_cash',
|
|
75
|
+
label: 'Cash-on-Cash',
|
|
76
|
+
formula: '(noi_model.net_operating_income - debt_structure.annual_debt_service) / sources_uses.sources.equity_sponsor',
|
|
77
|
+
unit: '%',
|
|
78
|
+
deterministic: true,
|
|
79
|
+
},
|
|
80
|
+
],
|
|
81
|
+
};
|
|
82
|
+
//# sourceMappingURL=multifamily.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"multifamily.js","sourceRoot":"","sources":["../../src/packs/multifamily.ts"],"names":[],"mappings":"AAAA,mCAAmC;AACnC,EAAE;AACF,6EAA6E;AAC7E,6EAA6E;AAC7E,2EAA2E;AAC3E,qDAAqD;AACrD,EAAE;AACF,yEAAyE;AACzE,oEAAoE;AACpE,uEAAuE;AAIvE,MAAM,CAAC,MAAM,gBAAgB,GAAmB;IAC9C,gBAAgB,EAAE,GAAG;IACrB,EAAE,EAAE,2BAA2B;IAC/B,IAAI,EAAE,0BAA0B;IAChC,OAAO,EAAE,OAAO;IAChB,WAAW,EACT,gIAAgI;IAClI,OAAO,EAAE,CAAC,2BAA2B,CAAC;IACtC,OAAO,EAAE,KAAK;IACd,iBAAiB,EAAE,QAAQ;IAC3B,eAAe,EAAE,QAAQ;IACzB,aAAa,EAAE,kBAAkB;IACjC,aAAa,EAAE,CAAC,aAAa,CAAC;IAC9B,YAAY,EAAE;QACZ;YACE,EAAE,EAAE,UAAU;YACd,KAAK,EAAE,UAAU;YACjB,OAAO,EAAE,2DAA2D;YACpE,IAAI,EAAE,GAAG;YACT,aAAa,EAAE,IAAI;SACpB;QACD;YACE,EAAE,EAAE,KAAK;YACT,KAAK,EAAE,KAAK;YACZ,OAAO,EAAE,uDAAuD;YAChE,IAAI,EAAE,GAAG;YACT,aAAa,EAAE,IAAI;SACpB;QACD;YACE,EAAE,EAAE,MAAM;YACV,KAAK,EAAE,MAAM;YACb,OAAO,EAAE,qEAAqE;YAC9E,IAAI,EAAE,GAAG;YACT,aAAa,EAAE,IAAI;SACpB;QACD;YACE,EAAE,EAAE,YAAY;YAChB,KAAK,EAAE,YAAY;YACnB,OAAO,EAAE,6DAA6D;YACtE,IAAI,EAAE,GAAG;YACT,aAAa,EAAE,IAAI;SACpB;QACD;YACE,EAAE,EAAE,gBAAgB;YACpB,KAAK,EAAE,cAAc;YACrB,OAAO,EAAE,iDAAiD;YAC1D,IAAI,EAAE,GAAG;YACT,aAAa,EAAE,IAAI;SACpB;QACD;YACE,EAAE,EAAE,eAAe;YACnB,KAAK,EAAE,aAAa;YACpB,OAAO,EAAE,mDAAmD;YAC5D,IAAI,EAAE,GAAG;YACT,aAAa,EAAE,IAAI;SACpB;QACD;YACE,EAAE,EAAE,eAAe;YACnB,KAAK,EAAE,aAAa;YACpB,OAAO,EAAE,sDAAsD;YAC/D,IAAI,EAAE,GAAG;YACT,aAAa,EAAE,IAAI;SACpB;QACD;YACE,EAAE,EAAE,cAAc;YAClB,KAAK,EAAE,cAAc;YACrB,OAAO,EACL,6GAA6G;YAC/G,IAAI,EAAE,GAAG;YACT,aAAa,EAAE,IAAI;SACpB;KACF;CACF,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"office.d.ts","sourceRoot":"","sources":["../../src/packs/office.ts"],"names":[],"mappings":"AAgBA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,gBAAgB,CAAC;AAErD,eAAO,MAAM,WAAW,EAAE,cA8FzB,CAAC"}
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
// Canonical office calc pack.
|
|
2
|
+
//
|
|
3
|
+
// Single source of truth for the office derived metrics. Consumed by the web
|
|
4
|
+
// editor (via @uwmd/core/browser), the @uwmd/excel converter (via
|
|
5
|
+
// emitExcelFormula), conformance tests, and any future asset-class viewer.
|
|
6
|
+
// Add a metric here once and every tool picks it up.
|
|
7
|
+
//
|
|
8
|
+
// Each formula is a Tier-3 safe expression evaluable by `evaluateCalc()`
|
|
9
|
+
// against a parsed .uw.md file. Field paths reference the canonical office
|
|
10
|
+
// schema (see UW_FORMAT_SPEC §4 and the Riverside office example).
|
|
11
|
+
//
|
|
12
|
+
// Office differs from multifamily on three field paths: size is measured in
|
|
13
|
+
// rentable square feet (`property.rentable_square_feet`, not `total_units`),
|
|
14
|
+
// sponsor equity is `sources_uses.sources.sponsor_equity` (not `equity_sponsor`),
|
|
15
|
+
// and the NOI model splits income/expenses into nested objects.
|
|
16
|
+
export const OFFICE_PACK = {
|
|
17
|
+
manifest_version: '1',
|
|
18
|
+
id: 'org.uwmd.pack.office',
|
|
19
|
+
name: 'Office Starter Pack',
|
|
20
|
+
version: '1.0.0',
|
|
21
|
+
description: 'Eleven derived metrics for office underwriting: cap rate, LTV, LTC, DSCR, debt yield, $/sqft, loan/sqft, NOI/sqft, expense ratio, cash-on-cash, occupancy.',
|
|
22
|
+
authors: ['UW Markdown Working Group'],
|
|
23
|
+
license: 'MIT',
|
|
24
|
+
requires_protocol: '^1.0.0',
|
|
25
|
+
requires_format: '^1.1.0',
|
|
26
|
+
requires_tier: 'tier-3-calc-host',
|
|
27
|
+
asset_classes: ['office'],
|
|
28
|
+
calculations: [
|
|
29
|
+
{
|
|
30
|
+
id: 'cap_rate',
|
|
31
|
+
label: 'Cap Rate',
|
|
32
|
+
formula: 'noi_model.net_operating_income / valuation.purchase_price',
|
|
33
|
+
unit: '%',
|
|
34
|
+
deterministic: true,
|
|
35
|
+
},
|
|
36
|
+
{
|
|
37
|
+
id: 'ltv',
|
|
38
|
+
label: 'LTV',
|
|
39
|
+
formula: 'debt_structure.loan_amount / valuation.purchase_price',
|
|
40
|
+
unit: '%',
|
|
41
|
+
deterministic: true,
|
|
42
|
+
},
|
|
43
|
+
{
|
|
44
|
+
id: 'ltc',
|
|
45
|
+
label: 'LTC',
|
|
46
|
+
formula: 'debt_structure.loan_amount / sources_uses.uses.total',
|
|
47
|
+
unit: '%',
|
|
48
|
+
deterministic: true,
|
|
49
|
+
},
|
|
50
|
+
{
|
|
51
|
+
id: 'dscr',
|
|
52
|
+
label: 'DSCR',
|
|
53
|
+
formula: 'noi_model.net_operating_income / debt_structure.annual_debt_service',
|
|
54
|
+
unit: 'x',
|
|
55
|
+
deterministic: true,
|
|
56
|
+
},
|
|
57
|
+
{
|
|
58
|
+
id: 'debt_yield',
|
|
59
|
+
label: 'Debt Yield',
|
|
60
|
+
formula: 'noi_model.net_operating_income / debt_structure.loan_amount',
|
|
61
|
+
unit: '%',
|
|
62
|
+
deterministic: true,
|
|
63
|
+
},
|
|
64
|
+
{
|
|
65
|
+
id: 'price_per_sqft',
|
|
66
|
+
label: 'Price / SqFt',
|
|
67
|
+
formula: 'valuation.purchase_price / property.rentable_square_feet',
|
|
68
|
+
unit: '$',
|
|
69
|
+
deterministic: true,
|
|
70
|
+
},
|
|
71
|
+
{
|
|
72
|
+
id: 'loan_per_sqft',
|
|
73
|
+
label: 'Loan / SqFt',
|
|
74
|
+
formula: 'debt_structure.loan_amount / property.rentable_square_feet',
|
|
75
|
+
unit: '$',
|
|
76
|
+
deterministic: true,
|
|
77
|
+
},
|
|
78
|
+
{
|
|
79
|
+
id: 'noi_per_sqft',
|
|
80
|
+
label: 'NOI / SqFt',
|
|
81
|
+
formula: 'noi_model.net_operating_income / property.rentable_square_feet',
|
|
82
|
+
unit: '$',
|
|
83
|
+
deterministic: true,
|
|
84
|
+
},
|
|
85
|
+
{
|
|
86
|
+
id: 'expense_ratio',
|
|
87
|
+
label: 'Operating Expense Ratio',
|
|
88
|
+
formula: 'noi_model.expenses.total_operating_expenses / noi_model.income.effective_gross_income',
|
|
89
|
+
unit: '%',
|
|
90
|
+
deterministic: true,
|
|
91
|
+
},
|
|
92
|
+
{
|
|
93
|
+
id: 'cash_on_cash',
|
|
94
|
+
label: 'Cash-on-Cash',
|
|
95
|
+
formula: '(noi_model.net_operating_income - debt_structure.annual_debt_service) / sources_uses.sources.sponsor_equity',
|
|
96
|
+
unit: '%',
|
|
97
|
+
deterministic: true,
|
|
98
|
+
},
|
|
99
|
+
{
|
|
100
|
+
id: 'occupancy',
|
|
101
|
+
label: 'Occupancy',
|
|
102
|
+
formula: 'rent_roll.occupied_sf / rent_roll.total_rentable_sf',
|
|
103
|
+
unit: '%',
|
|
104
|
+
deterministic: true,
|
|
105
|
+
},
|
|
106
|
+
],
|
|
107
|
+
};
|
|
108
|
+
//# sourceMappingURL=office.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"office.js","sourceRoot":"","sources":["../../src/packs/office.ts"],"names":[],"mappings":"AAAA,8BAA8B;AAC9B,EAAE;AACF,6EAA6E;AAC7E,kEAAkE;AAClE,2EAA2E;AAC3E,qDAAqD;AACrD,EAAE;AACF,yEAAyE;AACzE,2EAA2E;AAC3E,mEAAmE;AACnE,EAAE;AACF,4EAA4E;AAC5E,6EAA6E;AAC7E,kFAAkF;AAClF,gEAAgE;AAIhE,MAAM,CAAC,MAAM,WAAW,GAAmB;IACzC,gBAAgB,EAAE,GAAG;IACrB,EAAE,EAAE,sBAAsB;IAC1B,IAAI,EAAE,qBAAqB;IAC3B,OAAO,EAAE,OAAO;IAChB,WAAW,EACT,4JAA4J;IAC9J,OAAO,EAAE,CAAC,2BAA2B,CAAC;IACtC,OAAO,EAAE,KAAK;IACd,iBAAiB,EAAE,QAAQ;IAC3B,eAAe,EAAE,QAAQ;IACzB,aAAa,EAAE,kBAAkB;IACjC,aAAa,EAAE,CAAC,QAAQ,CAAC;IACzB,YAAY,EAAE;QACZ;YACE,EAAE,EAAE,UAAU;YACd,KAAK,EAAE,UAAU;YACjB,OAAO,EAAE,2DAA2D;YACpE,IAAI,EAAE,GAAG;YACT,aAAa,EAAE,IAAI;SACpB;QACD;YACE,EAAE,EAAE,KAAK;YACT,KAAK,EAAE,KAAK;YACZ,OAAO,EAAE,uDAAuD;YAChE,IAAI,EAAE,GAAG;YACT,aAAa,EAAE,IAAI;SACpB;QACD;YACE,EAAE,EAAE,KAAK;YACT,KAAK,EAAE,KAAK;YACZ,OAAO,EAAE,sDAAsD;YAC/D,IAAI,EAAE,GAAG;YACT,aAAa,EAAE,IAAI;SACpB;QACD;YACE,EAAE,EAAE,MAAM;YACV,KAAK,EAAE,MAAM;YACb,OAAO,EAAE,qEAAqE;YAC9E,IAAI,EAAE,GAAG;YACT,aAAa,EAAE,IAAI;SACpB;QACD;YACE,EAAE,EAAE,YAAY;YAChB,KAAK,EAAE,YAAY;YACnB,OAAO,EAAE,6DAA6D;YACtE,IAAI,EAAE,GAAG;YACT,aAAa,EAAE,IAAI;SACpB;QACD;YACE,EAAE,EAAE,gBAAgB;YACpB,KAAK,EAAE,cAAc;YACrB,OAAO,EAAE,0DAA0D;YACnE,IAAI,EAAE,GAAG;YACT,aAAa,EAAE,IAAI;SACpB;QACD;YACE,EAAE,EAAE,eAAe;YACnB,KAAK,EAAE,aAAa;YACpB,OAAO,EAAE,4DAA4D;YACrE,IAAI,EAAE,GAAG;YACT,aAAa,EAAE,IAAI;SACpB;QACD;YACE,EAAE,EAAE,cAAc;YAClB,KAAK,EAAE,YAAY;YACnB,OAAO,EAAE,gEAAgE;YACzE,IAAI,EAAE,GAAG;YACT,aAAa,EAAE,IAAI;SACpB;QACD;YACE,EAAE,EAAE,eAAe;YACnB,KAAK,EAAE,yBAAyB;YAChC,OAAO,EACL,uFAAuF;YACzF,IAAI,EAAE,GAAG;YACT,aAAa,EAAE,IAAI;SACpB;QACD;YACE,EAAE,EAAE,cAAc;YAClB,KAAK,EAAE,cAAc;YACrB,OAAO,EACL,6GAA6G;YAC/G,IAAI,EAAE,GAAG;YACT,aAAa,EAAE,IAAI;SACpB;QACD;YACE,EAAE,EAAE,WAAW;YACf,KAAK,EAAE,WAAW;YAClB,OAAO,EAAE,qDAAqD;YAC9D,IAAI,EAAE,GAAG;YACT,aAAa,EAAE,IAAI;SACpB;KACF;CACF,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"retail.d.ts","sourceRoot":"","sources":["../../src/packs/retail.ts"],"names":[],"mappings":"AAgBA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,gBAAgB,CAAC;AAErD,eAAO,MAAM,WAAW,EAAE,cAsGzB,CAAC"}
|