@untangle-code/complexity 0.0.0-stage → 0.1.1
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/LICENSE +661 -0
- package/NOTICE +90 -0
- package/README.md +235 -2
- package/THIRD_PARTY_LICENSES.md +24 -0
- package/dist/aggregator.d.ts +28 -0
- package/dist/aggregator.d.ts.map +1 -0
- package/dist/aggregator.js +77 -0
- package/dist/aggregator.js.map +1 -0
- package/dist/assemble.d.ts +50 -0
- package/dist/assemble.d.ts.map +1 -0
- package/dist/assemble.js +43 -0
- package/dist/assemble.js.map +1 -0
- package/dist/cognitive.d.ts +62 -0
- package/dist/cognitive.d.ts.map +1 -0
- package/dist/cognitive.js +62 -0
- package/dist/cognitive.js.map +1 -0
- package/dist/cyclomatic.d.ts +29 -0
- package/dist/cyclomatic.d.ts.map +1 -0
- package/dist/cyclomatic.js +52 -0
- package/dist/cyclomatic.js.map +1 -0
- package/dist/entropy.d.ts +5 -0
- package/dist/entropy.d.ts.map +1 -0
- package/dist/entropy.js +29 -0
- package/dist/entropy.js.map +1 -0
- package/dist/explain.d.ts +22 -0
- package/dist/explain.d.ts.map +1 -0
- package/dist/explain.js +35 -0
- package/dist/explain.js.map +1 -0
- package/dist/halstead.d.ts +23 -0
- package/dist/halstead.d.ts.map +1 -0
- package/dist/halstead.js +24 -0
- package/dist/halstead.js.map +1 -0
- package/dist/index.d.ts +35 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +34 -0
- package/dist/index.js.map +1 -0
- package/dist/ir/build-ir.d.ts +105 -0
- package/dist/ir/build-ir.d.ts.map +1 -0
- package/dist/ir/build-ir.js +267 -0
- package/dist/ir/build-ir.js.map +1 -0
- package/dist/maintainability.d.ts +15 -0
- package/dist/maintainability.d.ts.map +1 -0
- package/dist/maintainability.js +10 -0
- package/dist/maintainability.js.map +1 -0
- package/dist/node-kind-heuristics.d.ts +24 -0
- package/dist/node-kind-heuristics.d.ts.map +1 -0
- package/dist/node-kind-heuristics.js +37 -0
- package/dist/node-kind-heuristics.js.map +1 -0
- package/dist/prose/metrics.d.ts +81 -0
- package/dist/prose/metrics.d.ts.map +1 -0
- package/dist/prose/metrics.js +103 -0
- package/dist/prose/metrics.js.map +1 -0
- package/dist/scope-aggregate.d.ts +229 -0
- package/dist/scope-aggregate.d.ts.map +1 -0
- package/dist/scope-aggregate.js +588 -0
- package/dist/scope-aggregate.js.map +1 -0
- package/dist/scope-identity.d.ts +85 -0
- package/dist/scope-identity.d.ts.map +1 -0
- package/dist/scope-identity.js +144 -0
- package/dist/scope-identity.js.map +1 -0
- package/dist/scope.d.ts +36 -0
- package/dist/scope.d.ts.map +1 -0
- package/dist/scope.js +60 -0
- package/dist/scope.js.map +1 -0
- package/dist/structural.d.ts +30 -0
- package/dist/structural.d.ts.map +1 -0
- package/dist/structural.js +98 -0
- package/dist/structural.js.map +1 -0
- package/dist/syntactic.d.ts +35 -0
- package/dist/syntactic.d.ts.map +1 -0
- package/dist/syntactic.js +143 -0
- package/dist/syntactic.js.map +1 -0
- package/dist/text-lines.d.ts +34 -0
- package/dist/text-lines.d.ts.map +1 -0
- package/dist/text-lines.js +60 -0
- package/dist/text-lines.js.map +1 -0
- package/dist/textual.d.ts +28 -0
- package/dist/textual.d.ts.map +1 -0
- package/dist/textual.js +75 -0
- package/dist/textual.js.map +1 -0
- package/dist/types.d.ts +112 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +2 -0
- package/dist/types.js.map +1 -0
- package/package.json +60 -3
- package/src/aggregator.ts +105 -0
- package/src/assemble.ts +109 -0
- package/src/cognitive.ts +127 -0
- package/src/cyclomatic.ts +78 -0
- package/src/entropy.ts +30 -0
- package/src/explain.ts +64 -0
- package/src/halstead.ts +54 -0
- package/src/index.ts +85 -0
- package/src/ir/build-ir.ts +411 -0
- package/src/maintainability.ts +29 -0
- package/src/node-kind-heuristics.ts +55 -0
- package/src/prose/metrics.ts +201 -0
- package/src/scope-aggregate.ts +775 -0
- package/src/scope-identity.ts +240 -0
- package/src/scope.ts +77 -0
- package/src/structural.ts +132 -0
- package/src/syntactic.ts +183 -0
- package/src/text-lines.ts +90 -0
- package/src/textual.ts +119 -0
- package/src/types.ts +121 -0
|
@@ -0,0 +1,267 @@
|
|
|
1
|
+
import { containsRange, rangeKey } from "../scope.js";
|
|
2
|
+
const FUNCTION_LIKE_SCOPE_KINDS = new Set([
|
|
3
|
+
"function",
|
|
4
|
+
"method",
|
|
5
|
+
"constructor",
|
|
6
|
+
]);
|
|
7
|
+
const LOGICAL_DECISION_KINDS = new Set([
|
|
8
|
+
"logical_and",
|
|
9
|
+
"logical_or",
|
|
10
|
+
"short_circuit",
|
|
11
|
+
]);
|
|
12
|
+
/** Boundary IR kinds whose head expression (condition) can carry logical groups. */
|
|
13
|
+
const CONDITION_BEARING_KINDS = new Set([
|
|
14
|
+
"decision",
|
|
15
|
+
"loop",
|
|
16
|
+
"ternary",
|
|
17
|
+
"switch",
|
|
18
|
+
]);
|
|
19
|
+
function irKindForConstruct(construct) {
|
|
20
|
+
switch (construct) {
|
|
21
|
+
case "if":
|
|
22
|
+
return "decision";
|
|
23
|
+
case "loop":
|
|
24
|
+
return "loop";
|
|
25
|
+
case "catch":
|
|
26
|
+
return "catch";
|
|
27
|
+
case "ternary":
|
|
28
|
+
return "ternary";
|
|
29
|
+
case "switch":
|
|
30
|
+
return "switch";
|
|
31
|
+
case "lambda":
|
|
32
|
+
return "lambda";
|
|
33
|
+
default:
|
|
34
|
+
// Unknown future constructs still nest conservatively (they were
|
|
35
|
+
// emitted as nesting events, so they ARE nesting constructs).
|
|
36
|
+
return "other";
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
function isLogicalDecisionNode(node) {
|
|
40
|
+
return (node.decision !== undefined &&
|
|
41
|
+
LOGICAL_DECISION_KINDS.has(node.decision.kind) &&
|
|
42
|
+
node.nestingBoundary !== true);
|
|
43
|
+
}
|
|
44
|
+
function isConditionBearingBoundary(node) {
|
|
45
|
+
return node.nestingBoundary === true && CONDITION_BEARING_KINDS.has(node.kind);
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* Condition hoisting (see "CONDITION HOISTING" above): a logical node that
|
|
49
|
+
* is a direct child of a condition-bearing boundary moves up EXACTLY ONE
|
|
50
|
+
* level, inserted immediately before its former parent — that places the
|
|
51
|
+
* group at the guard's own ambient depth (the guard's children sit one
|
|
52
|
+
* boundary deeper than the guard itself). Never more than one level: the
|
|
53
|
+
* sweep for `parent` runs before recursing into its children, so a node
|
|
54
|
+
* hoisted out of a grandchild boundary is not swept again by any ancestor.
|
|
55
|
+
*/
|
|
56
|
+
function hoistConditionGroups(parent) {
|
|
57
|
+
const reordered = [];
|
|
58
|
+
for (const child of parent.children) {
|
|
59
|
+
if (isConditionBearingBoundary(child)) {
|
|
60
|
+
const staying = [];
|
|
61
|
+
for (const grandchild of child.children) {
|
|
62
|
+
if (isLogicalDecisionNode(grandchild)) {
|
|
63
|
+
reordered.push(grandchild);
|
|
64
|
+
}
|
|
65
|
+
else {
|
|
66
|
+
staying.push(grandchild);
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
child.children = staying;
|
|
70
|
+
}
|
|
71
|
+
reordered.push(child);
|
|
72
|
+
}
|
|
73
|
+
parent.children = reordered;
|
|
74
|
+
for (const child of parent.children) {
|
|
75
|
+
hoistConditionGroups(child);
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
function isDirectSelfRecursion(call, enclosingScope) {
|
|
79
|
+
if (enclosingScope.name.length === 0)
|
|
80
|
+
return false;
|
|
81
|
+
if (call.calleeName !== enclosingScope.name)
|
|
82
|
+
return false;
|
|
83
|
+
// `foo()` inside function foo, or `this.foo()` inside method foo.
|
|
84
|
+
return call.qualifier === undefined || call.qualifier === "this";
|
|
85
|
+
}
|
|
86
|
+
/**
|
|
87
|
+
* Builds the `ComplexityIRNode` subtree for one symbol scope (kind
|
|
88
|
+
* `"symbol"`, `nestingBoundary` unset, traversal depth 0 — exactly the root
|
|
89
|
+
* shape `computeCognitive` expects), or the whole-file tree (kind `"root"`)
|
|
90
|
+
* when `symbolScopeId` is the file scope's id.
|
|
91
|
+
*
|
|
92
|
+
* Returns `undefined` when `symbolScopeId` does not exist in
|
|
93
|
+
* `facts.symbolScopes` (mirrors `selectSymbolFacts`' stale-id tolerance).
|
|
94
|
+
*
|
|
95
|
+
* Pass the UNFILTERED file facts, not `selectSymbolFacts` output: the
|
|
96
|
+
* builder selects the symbol's own facts AND its descendant scopes' facts
|
|
97
|
+
* itself (a symbol's lambdas nest into its IR — see the module doc).
|
|
98
|
+
*/
|
|
99
|
+
export function buildSymbolIR(facts, symbolScopeId, options = {}) {
|
|
100
|
+
const scopesById = new Map();
|
|
101
|
+
for (const scope of facts.symbolScopes)
|
|
102
|
+
scopesById.set(scope.symbolScopeId, scope);
|
|
103
|
+
const targetScope = scopesById.get(symbolScopeId);
|
|
104
|
+
if (targetScope === undefined)
|
|
105
|
+
return undefined;
|
|
106
|
+
// Target scope plus all transitive descendants (lambdas, local functions,
|
|
107
|
+
// nested classes/methods, ...).
|
|
108
|
+
const childScopesByParent = new Map();
|
|
109
|
+
for (const scope of facts.symbolScopes) {
|
|
110
|
+
if (scope.parentScopeId === undefined)
|
|
111
|
+
continue;
|
|
112
|
+
const siblings = childScopesByParent.get(scope.parentScopeId) ?? [];
|
|
113
|
+
siblings.push(scope);
|
|
114
|
+
childScopesByParent.set(scope.parentScopeId, siblings);
|
|
115
|
+
}
|
|
116
|
+
const relevantScopeIds = new Set([symbolScopeId]);
|
|
117
|
+
const descendantScopes = [];
|
|
118
|
+
const pending = [symbolScopeId];
|
|
119
|
+
while (pending.length > 0) {
|
|
120
|
+
const current = pending.pop();
|
|
121
|
+
for (const child of childScopesByParent.get(current) ?? []) {
|
|
122
|
+
if (relevantScopeIds.has(child.symbolScopeId))
|
|
123
|
+
continue;
|
|
124
|
+
relevantScopeIds.add(child.symbolScopeId);
|
|
125
|
+
descendantScopes.push(child);
|
|
126
|
+
pending.push(child.symbolScopeId);
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
// ---- Proto nodes, deduplicated by range (an if/loop/catch/ternary emits
|
|
130
|
+
// a DecisionFact AND a NestingFact for the same AST node). ----
|
|
131
|
+
const protoByRange = new Map();
|
|
132
|
+
const ensureNode = (key, create, continuation) => {
|
|
133
|
+
const existing = protoByRange.get(key);
|
|
134
|
+
if (existing !== undefined)
|
|
135
|
+
return existing;
|
|
136
|
+
const created = { node: create(), continuation };
|
|
137
|
+
protoByRange.set(key, created);
|
|
138
|
+
return created;
|
|
139
|
+
};
|
|
140
|
+
for (const nesting of facts.nestingEvents) {
|
|
141
|
+
if (!relevantScopeIds.has(nesting.symbolScopeId))
|
|
142
|
+
continue;
|
|
143
|
+
ensureNode(rangeKey(nesting.range), () => ({
|
|
144
|
+
kind: irKindForConstruct(nesting.construct),
|
|
145
|
+
range: nesting.range,
|
|
146
|
+
children: [],
|
|
147
|
+
nestingBoundary: true,
|
|
148
|
+
symbolScopeId: nesting.symbolScopeId,
|
|
149
|
+
}), nesting.continuation);
|
|
150
|
+
}
|
|
151
|
+
for (const decision of facts.decisions) {
|
|
152
|
+
if (!relevantScopeIds.has(decision.symbolScopeId))
|
|
153
|
+
continue;
|
|
154
|
+
const proto = ensureNode(rangeKey(decision.range), () => decisionOnlyNode(decision), false);
|
|
155
|
+
if (proto.node.decision === undefined)
|
|
156
|
+
proto.node.decision = decision;
|
|
157
|
+
}
|
|
158
|
+
for (const scope of descendantScopes) {
|
|
159
|
+
const key = rangeKey(scope.range);
|
|
160
|
+
if (FUNCTION_LIKE_SCOPE_KINDS.has(scope.kind)) {
|
|
161
|
+
// Deduplicates against the adapter's own "lambda" nesting event (same
|
|
162
|
+
// AST node, same range) when the enclosing scope was executable.
|
|
163
|
+
ensureNode(key, () => ({
|
|
164
|
+
kind: "lambda",
|
|
165
|
+
range: scope.range,
|
|
166
|
+
children: [],
|
|
167
|
+
nestingBoundary: true,
|
|
168
|
+
symbolScopeId: scope.symbolScopeId,
|
|
169
|
+
}), false);
|
|
170
|
+
}
|
|
171
|
+
else {
|
|
172
|
+
ensureNode(key, () => ({
|
|
173
|
+
kind: "block",
|
|
174
|
+
range: scope.range,
|
|
175
|
+
children: [],
|
|
176
|
+
symbolScopeId: scope.symbolScopeId,
|
|
177
|
+
}), false);
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
for (const call of options.calls ?? []) {
|
|
181
|
+
if (!relevantScopeIds.has(call.callerScopeId))
|
|
182
|
+
continue;
|
|
183
|
+
const enclosingScope = scopesById.get(call.callerScopeId);
|
|
184
|
+
if (enclosingScope === undefined)
|
|
185
|
+
continue;
|
|
186
|
+
if (!isDirectSelfRecursion(call, enclosingScope))
|
|
187
|
+
continue;
|
|
188
|
+
ensureNode(rangeKey(call.range), () => ({
|
|
189
|
+
kind: "recursion_marker",
|
|
190
|
+
range: call.range,
|
|
191
|
+
children: [],
|
|
192
|
+
symbolScopeId: call.callerScopeId,
|
|
193
|
+
}), false);
|
|
194
|
+
}
|
|
195
|
+
// ---- Containment placement with else-if sibling flattening. ----
|
|
196
|
+
const root = {
|
|
197
|
+
kind: targetScope.kind === "file" ? "root" : "symbol",
|
|
198
|
+
range: targetScope.range,
|
|
199
|
+
children: [],
|
|
200
|
+
symbolScopeId,
|
|
201
|
+
};
|
|
202
|
+
const sorted = [...protoByRange.values()].sort((a, b) => a.node.range.startByte - b.node.range.startByte ||
|
|
203
|
+
b.node.range.endByte - a.node.range.endByte);
|
|
204
|
+
const containmentStack = [];
|
|
205
|
+
// The node each proto was ATTACHED to (differs from the containment parent
|
|
206
|
+
// for continuation nodes — that difference IS the flattening).
|
|
207
|
+
const attachedTo = new Map();
|
|
208
|
+
for (const proto of sorted) {
|
|
209
|
+
if (!containsRange(root.range, proto.node.range))
|
|
210
|
+
continue; // defensive: stray fact outside the symbol
|
|
211
|
+
while (containmentStack.length > 0 &&
|
|
212
|
+
!containsRange(containmentStack[containmentStack.length - 1].node.range, proto.node.range)) {
|
|
213
|
+
containmentStack.pop();
|
|
214
|
+
}
|
|
215
|
+
const containmentParent = containmentStack[containmentStack.length - 1];
|
|
216
|
+
let parent;
|
|
217
|
+
if (proto.continuation && containmentParent !== undefined) {
|
|
218
|
+
// finalParent(else_if) = finalParent(the if it continues); the owning
|
|
219
|
+
// if is exactly the containment parent (nothing sits between an
|
|
220
|
+
// if_statement and the if_statement in its else-clause).
|
|
221
|
+
parent = attachedTo.get(containmentParent) ?? root;
|
|
222
|
+
}
|
|
223
|
+
else {
|
|
224
|
+
parent = containmentParent?.node ?? root;
|
|
225
|
+
}
|
|
226
|
+
parent.children.push(proto.node);
|
|
227
|
+
attachedTo.set(proto, parent);
|
|
228
|
+
containmentStack.push(proto);
|
|
229
|
+
}
|
|
230
|
+
// ---- Condition hoisting (one level; see module doc). ----
|
|
231
|
+
hoistConditionGroups(root);
|
|
232
|
+
return root;
|
|
233
|
+
}
|
|
234
|
+
function decisionOnlyNode(decision) {
|
|
235
|
+
if (decision.kind === "case") {
|
|
236
|
+
// Case bodies nest one level below the switch head (cognitive.ts's
|
|
237
|
+
// documented boundary list includes "case").
|
|
238
|
+
return {
|
|
239
|
+
kind: "case",
|
|
240
|
+
range: decision.range,
|
|
241
|
+
children: [],
|
|
242
|
+
nestingBoundary: true,
|
|
243
|
+
decision,
|
|
244
|
+
symbolScopeId: decision.symbolScopeId,
|
|
245
|
+
};
|
|
246
|
+
}
|
|
247
|
+
if (LOGICAL_DECISION_KINDS.has(decision.kind)) {
|
|
248
|
+
return {
|
|
249
|
+
kind: "logical_sequence",
|
|
250
|
+
range: decision.range,
|
|
251
|
+
children: [],
|
|
252
|
+
decision,
|
|
253
|
+
symbolScopeId: decision.symbolScopeId,
|
|
254
|
+
};
|
|
255
|
+
}
|
|
256
|
+
// guard/if/loop/... decisions normally merge with their nesting event by
|
|
257
|
+
// range; a decision kind without one (e.g. "pattern_alternative") becomes
|
|
258
|
+
// a plain non-boundary decision node.
|
|
259
|
+
return {
|
|
260
|
+
kind: "decision",
|
|
261
|
+
range: decision.range,
|
|
262
|
+
children: [],
|
|
263
|
+
decision,
|
|
264
|
+
symbolScopeId: decision.symbolScopeId,
|
|
265
|
+
};
|
|
266
|
+
}
|
|
267
|
+
//# sourceMappingURL=build-ir.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"build-ir.js","sourceRoot":"","sources":["../../src/ir/build-ir.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* MaintainabilityCalculator (spec.md §16.9). Exact default formula, no
|
|
3
|
+
* comment bonus (v1 deliberately omits it per spec.md §16.9, for
|
|
4
|
+
* cross-language stability), clamped to [0, 100]. The formula string itself
|
|
5
|
+
* is always returned, as required by the work order.
|
|
6
|
+
*/
|
|
7
|
+
import type { MaintainabilityResult } from "./types.js";
|
|
8
|
+
export declare const MAINTAINABILITY_FORMULA = "MI = clamp((171 - 5.2*ln(max(HalsteadVolume,1)) - 0.23*CyclomaticClassic - 16.2*ln(max(SLOC,1))) * 100 / 171, 0, 100)";
|
|
9
|
+
export interface MaintainabilityInput {
|
|
10
|
+
halsteadVolume: number;
|
|
11
|
+
cyclomaticClassic: number;
|
|
12
|
+
sloc: number;
|
|
13
|
+
}
|
|
14
|
+
export declare function computeMaintainability(input: MaintainabilityInput, algorithmVersion?: string): MaintainabilityResult;
|
|
15
|
+
//# sourceMappingURL=maintainability.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"maintainability.d.ts","sourceRoot":"","sources":["../src/maintainability.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,YAAY,CAAC;AAExD,eAAO,MAAM,uBAAuB,0HACqF,CAAC;AAE1H,MAAM,WAAW,oBAAoB;IACnC,cAAc,EAAE,MAAM,CAAC;IACvB,iBAAiB,EAAE,MAAM,CAAC;IAC1B,IAAI,EAAE,MAAM,CAAC;CACd;AAED,wBAAgB,sBAAsB,CACpC,KAAK,EAAE,oBAAoB,EAC3B,gBAAgB,SAAgC,GAC/C,qBAAqB,CAQvB"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
export const MAINTAINABILITY_FORMULA = "MI = clamp((171 - 5.2*ln(max(HalsteadVolume,1)) - 0.23*CyclomaticClassic - 16.2*ln(max(SLOC,1))) * 100 / 171, 0, 100)";
|
|
2
|
+
export function computeMaintainability(input, algorithmVersion = "untangle-maintainability-v1") {
|
|
3
|
+
const volumeTerm = Math.log(Math.max(input.halsteadVolume, 1));
|
|
4
|
+
const slocTerm = Math.log(Math.max(input.sloc, 1));
|
|
5
|
+
const raw = 171 - 5.2 * volumeTerm - 0.23 * input.cyclomaticClassic - 16.2 * slocTerm;
|
|
6
|
+
const scaled = (raw * 100) / 171;
|
|
7
|
+
const value = Math.min(100, Math.max(0, scaled));
|
|
8
|
+
return { value, raw, formula: MAINTAINABILITY_FORMULA, algorithmVersion };
|
|
9
|
+
}
|
|
10
|
+
//# sourceMappingURL=maintainability.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"maintainability.js","sourceRoot":"","sources":["../src/maintainability.ts"],"names":[],"mappings":"AAQA,MAAM,CAAC,MAAM,uBAAuB,GAClC,uHAAuH,CAAC;AAQ1H,MAAM,UAAU,sBAAsB,CACpC,KAA2B,EAC3B,gBAAgB,GAAG,6BAA6B;IAEhD,MAAM,UAAU,GAAG,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,cAAc,EAAE,CAAC,CAAC,CAAC,CAAC;IAC/D,MAAM,QAAQ,GAAG,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC;IACnD,MAAM,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,UAAU,GAAG,IAAI,GAAG,KAAK,CAAC,iBAAiB,GAAG,IAAI,GAAG,QAAQ,CAAC;IACtF,MAAM,MAAM,GAAG,CAAC,GAAG,GAAG,GAAG,CAAC,GAAG,GAAG,CAAC;IACjC,MAAM,KAAK,GAAG,IAAI,CAAC,GAAG,CAAC,GAAG,EAAE,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,MAAM,CAAC,CAAC,CAAC;IAEjD,OAAO,EAAE,KAAK,EAAE,GAAG,EAAE,OAAO,EAAE,uBAAuB,EAAE,gBAAgB,EAAE,CAAC;AAC5E,CAAC"}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Best-effort classification of raw, adapter-specific AST node kind strings
|
|
3
|
+
* (`NodeKindFact.kind`, `ComplexityFacts.nodeKinds`) into the language-neutral
|
|
4
|
+
* buckets `StructuralCalculator`/`SyntacticCalculator` need for
|
|
5
|
+
* `parameter_count`, `return_count`, `exit_point_count`, `statement_count`,
|
|
6
|
+
* `expression_count` and `declaration_count` (spec.md §16.5, §16.8).
|
|
7
|
+
*
|
|
8
|
+
* `ComplexityFacts` deliberately keeps `kind` as an opaque, grammar-specific
|
|
9
|
+
* string (e.g. tree-sitter's `"required_parameter"`, `"return_statement"`) —
|
|
10
|
+
* domain does not define a normalized node-kind taxonomy. This module is
|
|
11
|
+
* Untangle's own, documented, versioned answer to that gap (see README
|
|
12
|
+
* "Entscheidungen" #5); it is intentionally conservative (substring match on
|
|
13
|
+
* common, cross-grammar naming conventions) and is flagged in `openIssues` as
|
|
14
|
+
* a candidate for an additive domain extension once real adapter output
|
|
15
|
+
* exists to validate against.
|
|
16
|
+
*/
|
|
17
|
+
export type NodeKindClass = "parameter" | "return" | "exit" | "statement" | "expression" | "declaration" | "other";
|
|
18
|
+
/** Classifies one raw node-kind string. Order matters: more specific buckets are checked first. */
|
|
19
|
+
export declare function classifyNodeKind(kind: string): NodeKindClass;
|
|
20
|
+
/** True when a raw node-kind string looks like an async construct (best-effort, see module docs). */
|
|
21
|
+
export declare function isAsyncNodeKind(kind: string): boolean;
|
|
22
|
+
/** True when a raw node-kind string looks like an exception construct (best-effort, see module docs). */
|
|
23
|
+
export declare function isExceptionNodeKind(kind: string): boolean;
|
|
24
|
+
//# sourceMappingURL=node-kind-heuristics.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"node-kind-heuristics.d.ts","sourceRoot":"","sources":["../src/node-kind-heuristics.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AACH,MAAM,MAAM,aAAa,GACvB,WAAW,GAAG,QAAQ,GAAG,MAAM,GAAG,WAAW,GAAG,YAAY,GAAG,aAAa,GAAG,OAAO,CAAC;AAazF,mGAAmG;AACnG,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,MAAM,GAAG,aAAa,CAS5D;AAID,qGAAqG;AACrG,wBAAgB,eAAe,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAErD;AAID,yGAAyG;AACzG,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAEzD"}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
const RETURN_MARKERS = ["return_statement", "return"];
|
|
2
|
+
const EXIT_MARKERS = ["throw_statement", "throw", "break_statement", "continue_statement"];
|
|
3
|
+
const PARAMETER_MARKERS = ["parameter"];
|
|
4
|
+
const DECLARATION_MARKERS = ["declaration", "declarator"];
|
|
5
|
+
const STATEMENT_MARKERS = ["statement"];
|
|
6
|
+
const EXPRESSION_MARKERS = ["expression"];
|
|
7
|
+
function matches(normalizedKind, markers) {
|
|
8
|
+
return markers.some((marker) => normalizedKind === marker || normalizedKind.includes(marker));
|
|
9
|
+
}
|
|
10
|
+
/** Classifies one raw node-kind string. Order matters: more specific buckets are checked first. */
|
|
11
|
+
export function classifyNodeKind(kind) {
|
|
12
|
+
const normalized = kind.toLowerCase();
|
|
13
|
+
if (matches(normalized, RETURN_MARKERS))
|
|
14
|
+
return "return";
|
|
15
|
+
if (matches(normalized, EXIT_MARKERS))
|
|
16
|
+
return "exit";
|
|
17
|
+
if (matches(normalized, PARAMETER_MARKERS))
|
|
18
|
+
return "parameter";
|
|
19
|
+
if (matches(normalized, DECLARATION_MARKERS))
|
|
20
|
+
return "declaration";
|
|
21
|
+
if (matches(normalized, STATEMENT_MARKERS))
|
|
22
|
+
return "statement";
|
|
23
|
+
if (matches(normalized, EXPRESSION_MARKERS))
|
|
24
|
+
return "expression";
|
|
25
|
+
return "other";
|
|
26
|
+
}
|
|
27
|
+
const ASYNC_MARKERS = ["async", "await"];
|
|
28
|
+
/** True when a raw node-kind string looks like an async construct (best-effort, see module docs). */
|
|
29
|
+
export function isAsyncNodeKind(kind) {
|
|
30
|
+
return matches(kind.toLowerCase(), ASYNC_MARKERS);
|
|
31
|
+
}
|
|
32
|
+
const EXCEPTION_MARKERS = ["throw_statement", "throw", "try_statement", "catch_clause"];
|
|
33
|
+
/** True when a raw node-kind string looks like an exception construct (best-effort, see module docs). */
|
|
34
|
+
export function isExceptionNodeKind(kind) {
|
|
35
|
+
return matches(kind.toLowerCase(), EXCEPTION_MARKERS);
|
|
36
|
+
}
|
|
37
|
+
//# sourceMappingURL=node-kind-heuristics.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"node-kind-heuristics.js","sourceRoot":"","sources":["../src/node-kind-heuristics.ts"],"names":[],"mappings":"AAmBA,MAAM,cAAc,GAAG,CAAC,kBAAkB,EAAE,QAAQ,CAAC,CAAC;AACtD,MAAM,YAAY,GAAG,CAAC,iBAAiB,EAAE,OAAO,EAAE,iBAAiB,EAAE,oBAAoB,CAAC,CAAC;AAC3F,MAAM,iBAAiB,GAAG,CAAC,WAAW,CAAC,CAAC;AACxC,MAAM,mBAAmB,GAAG,CAAC,aAAa,EAAE,YAAY,CAAC,CAAC;AAC1D,MAAM,iBAAiB,GAAG,CAAC,WAAW,CAAC,CAAC;AACxC,MAAM,kBAAkB,GAAG,CAAC,YAAY,CAAC,CAAC;AAE1C,SAAS,OAAO,CAAC,cAAsB,EAAE,OAA0B;IACjE,OAAO,OAAO,CAAC,IAAI,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,cAAc,KAAK,MAAM,IAAI,cAAc,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC;AAChG,CAAC;AAED,mGAAmG;AACnG,MAAM,UAAU,gBAAgB,CAAC,IAAY;IAC3C,MAAM,UAAU,GAAG,IAAI,CAAC,WAAW,EAAE,CAAC;IACtC,IAAI,OAAO,CAAC,UAAU,EAAE,cAAc,CAAC;QAAE,OAAO,QAAQ,CAAC;IACzD,IAAI,OAAO,CAAC,UAAU,EAAE,YAAY,CAAC;QAAE,OAAO,MAAM,CAAC;IACrD,IAAI,OAAO,CAAC,UAAU,EAAE,iBAAiB,CAAC;QAAE,OAAO,WAAW,CAAC;IAC/D,IAAI,OAAO,CAAC,UAAU,EAAE,mBAAmB,CAAC;QAAE,OAAO,aAAa,CAAC;IACnE,IAAI,OAAO,CAAC,UAAU,EAAE,iBAAiB,CAAC;QAAE,OAAO,WAAW,CAAC;IAC/D,IAAI,OAAO,CAAC,UAAU,EAAE,kBAAkB,CAAC;QAAE,OAAO,YAAY,CAAC;IACjE,OAAO,OAAO,CAAC;AACjB,CAAC;AAED,MAAM,aAAa,GAAG,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC;AAEzC,qGAAqG;AACrG,MAAM,UAAU,eAAe,CAAC,IAAY;IAC1C,OAAO,OAAO,CAAC,IAAI,CAAC,WAAW,EAAE,EAAE,aAAa,CAAC,CAAC;AACpD,CAAC;AAED,MAAM,iBAAiB,GAAG,CAAC,iBAAiB,EAAE,OAAO,EAAE,eAAe,EAAE,cAAc,CAAC,CAAC;AAExF,yGAAyG;AACzG,MAAM,UAAU,mBAAmB,CAAC,IAAY;IAC9C,OAAO,OAAO,CAAC,IAAI,CAAC,WAAW,EAAE,EAAE,iBAAiB,CAAC,CAAC;AACxD,CAAC"}
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Prosa-Metriken (vision.md §1c/§1d, WP-217).
|
|
3
|
+
*
|
|
4
|
+
* WARUM ES DIESE DATEI GIBT
|
|
5
|
+
*
|
|
6
|
+
* Alles andere in diesem Paket rechnet ueber `ComplexityFacts`: Scopes,
|
|
7
|
+
* Entscheidungspunkte, Verschachtelung, Operatoren. Ein Markdown-Dokument
|
|
8
|
+
* hat davon NICHTS — nicht wenig, sondern nichts. Der Prosa-Adapter liefert
|
|
9
|
+
* deshalb leere Facts, und Prosa wird hier ueber ihre EIGENEN Groessen
|
|
10
|
+
* gemessen: Struktur- und Verweislast.
|
|
11
|
+
*
|
|
12
|
+
* Die Trennung ist strukturell, nicht per Konvention: jeder Rueckgabewert
|
|
13
|
+
* ist ein {@link ProseNumberV1}, also ein Objekt. Ein Prosa-Messwert kann
|
|
14
|
+
* dadurch an keiner Stelle stehen, an der `computeCognitive` oder
|
|
15
|
+
* `aggregate` eine Zahl erwarten — der Uebersetzer lehnt es ab, und
|
|
16
|
+
* `assertUntangleMetricNumber` lehnt es zur Laufzeit ab. Vorbild ist
|
|
17
|
+
* `ExternalNumberV1` (domain `types/extensions.ts`), das externe Befunde
|
|
18
|
+
* genauso von Untangle-Metriken fernhaelt.
|
|
19
|
+
*
|
|
20
|
+
* DIE FUENF MASSE, UND WARUM GENAU DIESE
|
|
21
|
+
*
|
|
22
|
+
* Jedes Mass muss ohne Modellannahme lesbar sein — sonst ist es eine
|
|
23
|
+
* erfundene Zahl mit Nachkommastellen. Was hier steht, laesst sich am
|
|
24
|
+
* Dokument nachzaehlen:
|
|
25
|
+
*
|
|
26
|
+
* 1. `sectionDepth` — tiefste benutzte Ueberschriftenebene.
|
|
27
|
+
* 2. `maxSectionLines` — laengster Abschnitt in Zeilen.
|
|
28
|
+
* 3. `linkDensity` — Verweise je 100 Inhaltszeilen.
|
|
29
|
+
* 4. `unresolvedLinkRatio` — Anteil toter relativer Dateiverweise, oder
|
|
30
|
+
* `null`, wenn niemand aufgeloest hat.
|
|
31
|
+
* 5. `repetitionRatio` — Anteil woertlich wiederholter Inhaltszeilen.
|
|
32
|
+
*
|
|
33
|
+
* Dazu der abgeleitete Ordnungsschluessel `structureLoad`: die Summe der
|
|
34
|
+
* Ueberschriftenebenen aller Abschnitte. Bewusst keine gewichtete Mischung
|
|
35
|
+
* ungleicher Groessen — das waere der eine „Quality Score", den vision.md
|
|
36
|
+
* §7.6 ablehnt —, sondern eine abzaehlbare Groesse: die Gesamtzahl der
|
|
37
|
+
* Gliederungsstufen, die das Dokument aufspannt. Ein Dokument mit 40
|
|
38
|
+
* Abschnitten auf Ebene 3 traegt mehr Gliederung als eines mit 40
|
|
39
|
+
* Abschnitten auf Ebene 1, und beide mehr als eines mit vier.
|
|
40
|
+
*
|
|
41
|
+
* DER AUFLOESER
|
|
42
|
+
*
|
|
43
|
+
* `unresolvedLinkRatio` ist der einzige Wert, der etwas ausserhalb des
|
|
44
|
+
* Dokuments braucht. Ohne `resolveLink` bleibt er `null` — ein
|
|
45
|
+
* Zustandsvermerk, kein Messwert von 0. vision.md §1d ist an genau dieser
|
|
46
|
+
* Stelle deutlich: „niemand hat gesucht" darf nie wie ein Befund ueber den
|
|
47
|
+
* Inhalt aussehen. Deshalb ist der Aufloeser ein Parameter und keine
|
|
48
|
+
* Dateizugriffsfunktion in diesem Paket: `@untangle-code/complexity` bleibt
|
|
49
|
+
* frei von I/O.
|
|
50
|
+
*/
|
|
51
|
+
import type { ProseMetricsV1 } from "@untangle-code/domain";
|
|
52
|
+
/**
|
|
53
|
+
* Beantwortet, ob das Ziel eines relativen Dateiverweises existiert.
|
|
54
|
+
* `documentPath` ist der Pfad des VERWEISENDEN Dokuments, damit der
|
|
55
|
+
* Aufloeser relativ dazu suchen kann.
|
|
56
|
+
*/
|
|
57
|
+
export type ProseLinkResolver = (documentPath: string, targetFilePath: string) => boolean;
|
|
58
|
+
export interface ProseMetricsOptions {
|
|
59
|
+
/**
|
|
60
|
+
* Ohne Aufloeser bleibt `unresolvedLinkRatio` `null`. Das ist Absicht:
|
|
61
|
+
* ein ungeprueftes 0 waere die Behauptung, alle Verweise seien heil.
|
|
62
|
+
*/
|
|
63
|
+
resolveLink?: ProseLinkResolver;
|
|
64
|
+
}
|
|
65
|
+
/**
|
|
66
|
+
* Prosa-Metriken eines Dokuments.
|
|
67
|
+
*
|
|
68
|
+
* `path` ist der "/"-normalisierte, repo-relative Pfad; er wird nur
|
|
69
|
+
* durchgereicht (an den Aufloeser und in das Ergebnis), nie geoeffnet.
|
|
70
|
+
*/
|
|
71
|
+
export declare function computeProseMetrics(path: string, content: string, options?: ProseMetricsOptions): ProseMetricsV1;
|
|
72
|
+
/**
|
|
73
|
+
* Ordnet zwei Dokumente nach Strukturlast, absteigend, mit vollstaendig
|
|
74
|
+
* deterministischem Gleichstandsbruch (nie `localeCompare`).
|
|
75
|
+
*
|
|
76
|
+
* `compare` liefert eine Ordnung, keine Bewertung: das Dokument mit der
|
|
77
|
+
* hoechsten Strukturlast ist nicht „das schlechteste", sondern das mit der
|
|
78
|
+
* meisten Gliederung — die Deutung gehoert dem Leser, die Zahl dem Werkzeug.
|
|
79
|
+
*/
|
|
80
|
+
export declare function compareProseByStructureLoad(a: ProseMetricsV1, b: ProseMetricsV1): number;
|
|
81
|
+
//# sourceMappingURL=metrics.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"metrics.d.ts","sourceRoot":"","sources":["../../src/prose/metrics.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAiDG;AACH,OAAO,KAAK,EAEV,cAAc,EAGf,MAAM,uBAAuB,CAAC;AAY/B;;;;GAIG;AACH,MAAM,MAAM,iBAAiB,GAAG,CAAC,YAAY,EAAE,MAAM,EAAE,cAAc,EAAE,MAAM,KAAK,OAAO,CAAC;AAE1F,MAAM,WAAW,mBAAmB;IAClC;;;OAGG;IACH,WAAW,CAAC,EAAE,iBAAiB,CAAC;CACjC;AAiBD;;;;;GAKG;AACH,wBAAgB,mBAAmB,CACjC,IAAI,EAAE,MAAM,EACZ,OAAO,EAAE,MAAM,EACf,OAAO,GAAE,mBAAwB,GAChC,cAAc,CAmEhB;AAED;;;;;;;GAOG;AACH,wBAAgB,2BAA2B,CAAC,CAAC,EAAE,cAAc,EAAE,CAAC,EAAE,cAAc,GAAG,MAAM,CAMxF"}
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
import { PROSE_METRICS_VERSION, classifyLinkTarget, countContentLines, findMarkdownLinks, linkFilePath, makeProseNumber, normalizedContentLines, outlineMarkdown, } from "@untangle-code/domain";
|
|
2
|
+
/** Physische Zeilen ohne Zeilenende; ein abschliessendes `\r` faellt weg. */
|
|
3
|
+
function splitLines(content) {
|
|
4
|
+
return content.split("\n").map((line) => (line.endsWith("\r") ? line.slice(0, -1) : line));
|
|
5
|
+
}
|
|
6
|
+
/**
|
|
7
|
+
* Rundet auf eine Nachkommastelle. Verhaeltniswerte werden gespeichert und
|
|
8
|
+
* verglichen; ohne feste Rundung waeren zwei Laeufe ueber dieselbe Datei
|
|
9
|
+
* durch Gleitkommarauschen nicht bitgleich.
|
|
10
|
+
*/
|
|
11
|
+
function round(value, digits) {
|
|
12
|
+
const factor = 10 ** digits;
|
|
13
|
+
return Math.round(value * factor) / factor;
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* Prosa-Metriken eines Dokuments.
|
|
17
|
+
*
|
|
18
|
+
* `path` ist der "/"-normalisierte, repo-relative Pfad; er wird nur
|
|
19
|
+
* durchgereicht (an den Aufloeser und in das Ergebnis), nie geoeffnet.
|
|
20
|
+
*/
|
|
21
|
+
export function computeProseMetrics(path, content, options = {}) {
|
|
22
|
+
const lines = splitLines(content);
|
|
23
|
+
const outline = outlineMarkdown(lines);
|
|
24
|
+
const sections = outline.map((section) => ({
|
|
25
|
+
breadcrumb: section.breadcrumb,
|
|
26
|
+
level: section.level,
|
|
27
|
+
startLine: section.startLine,
|
|
28
|
+
endLine: section.endLine,
|
|
29
|
+
lines: Math.max(0, section.endLine - section.startLine + 1),
|
|
30
|
+
}));
|
|
31
|
+
const contentLines = countContentLines(lines);
|
|
32
|
+
const rawLinks = findMarkdownLinks(lines);
|
|
33
|
+
const resolver = options.resolveLink;
|
|
34
|
+
const links = rawLinks.map((link) => {
|
|
35
|
+
const kind = classifyLinkTarget(link.target);
|
|
36
|
+
let resolved = null;
|
|
37
|
+
if (kind === "relative_file" && resolver !== undefined) {
|
|
38
|
+
const target = linkFilePath(link.target);
|
|
39
|
+
// Ein Verweis, der nur auf einen Anker im selben Dokument zeigt, hat
|
|
40
|
+
// keinen Dateiteil; er ist nicht "tot", er ist keine Dateikante.
|
|
41
|
+
resolved = target === "" ? true : resolver(path, target);
|
|
42
|
+
}
|
|
43
|
+
return { target: link.target, text: link.text, line: link.line, kind, resolved };
|
|
44
|
+
});
|
|
45
|
+
const resolvable = links.filter((link) => link.resolved !== null);
|
|
46
|
+
const unresolved = resolvable.filter((link) => link.resolved === false);
|
|
47
|
+
const normalized = normalizedContentLines(lines);
|
|
48
|
+
const seen = new Set();
|
|
49
|
+
let repeated = 0;
|
|
50
|
+
for (const line of normalized) {
|
|
51
|
+
if (seen.has(line))
|
|
52
|
+
repeated += 1;
|
|
53
|
+
else
|
|
54
|
+
seen.add(line);
|
|
55
|
+
}
|
|
56
|
+
const depth = sections.reduce((max, section) => Math.max(max, section.level), 0);
|
|
57
|
+
const maxLines = sections.reduce((max, section) => Math.max(max, section.lines), 0);
|
|
58
|
+
const structureLoad = sections.reduce((sum, section) => sum + section.level, 0);
|
|
59
|
+
return {
|
|
60
|
+
schemaVersion: 1,
|
|
61
|
+
metricsVersion: PROSE_METRICS_VERSION,
|
|
62
|
+
path,
|
|
63
|
+
sectionDepth: makeProseNumber(depth, "levels"),
|
|
64
|
+
maxSectionLines: makeProseNumber(maxLines, "lines"),
|
|
65
|
+
linkDensity: makeProseNumber(contentLines === 0 ? 0 : round((links.length / contentLines) * 100, 1), "per_100_lines"),
|
|
66
|
+
unresolvedLinkRatio: resolvable.length === 0
|
|
67
|
+
? null
|
|
68
|
+
: makeProseNumber(round(unresolved.length / resolvable.length, 4), "ratio"),
|
|
69
|
+
repetitionRatio: makeProseNumber(normalized.length === 0 ? 0 : round(repeated / normalized.length, 4), "ratio"),
|
|
70
|
+
structureLoad: makeProseNumber(structureLoad, "count"),
|
|
71
|
+
sectionCount: makeProseNumber(sections.length, "count"),
|
|
72
|
+
contentLines: makeProseNumber(contentLines, "count"),
|
|
73
|
+
sections,
|
|
74
|
+
links,
|
|
75
|
+
};
|
|
76
|
+
}
|
|
77
|
+
/**
|
|
78
|
+
* Ordnet zwei Dokumente nach Strukturlast, absteigend, mit vollstaendig
|
|
79
|
+
* deterministischem Gleichstandsbruch (nie `localeCompare`).
|
|
80
|
+
*
|
|
81
|
+
* `compare` liefert eine Ordnung, keine Bewertung: das Dokument mit der
|
|
82
|
+
* hoechsten Strukturlast ist nicht „das schlechteste", sondern das mit der
|
|
83
|
+
* meisten Gliederung — die Deutung gehoert dem Leser, die Zahl dem Werkzeug.
|
|
84
|
+
*/
|
|
85
|
+
export function compareProseByStructureLoad(a, b) {
|
|
86
|
+
const byLoad = valueOf(b.structureLoad) - valueOf(a.structureLoad);
|
|
87
|
+
if (byLoad !== 0)
|
|
88
|
+
return byLoad;
|
|
89
|
+
const byDepth = valueOf(b.sectionDepth) - valueOf(a.sectionDepth);
|
|
90
|
+
if (byDepth !== 0)
|
|
91
|
+
return byDepth;
|
|
92
|
+
return a.path < b.path ? -1 : a.path > b.path ? 1 : 0;
|
|
93
|
+
}
|
|
94
|
+
/**
|
|
95
|
+
* Der Rohwert eines Prosa-Messwerts fuer die SORTIERUNG innerhalb dieser
|
|
96
|
+
* Familie. Bewusst paketlokal und nicht exportiert: eine allgemein
|
|
97
|
+
* verfuegbare `number`-Entpackung waere genau das Loch, das
|
|
98
|
+
* {@link ProseNumberV1} zumauert.
|
|
99
|
+
*/
|
|
100
|
+
function valueOf(value) {
|
|
101
|
+
return value.value;
|
|
102
|
+
}
|
|
103
|
+
//# sourceMappingURL=metrics.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"metrics.js","sourceRoot":"","sources":["../../src/prose/metrics.ts"],"names":[],"mappings":"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"}
|