@rsconcept/domain 2.1.2 → 2.3.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/dist/api-Bf0f_uiI.d.ts +57 -0
- package/dist/diagnostics-CljEzVBV.js +1245 -0
- package/dist/diagnostics-CljEzVBV.js.map +1 -0
- package/dist/{diagnostics-EaIt3zIw.d.ts → diagnostics-Dac5sJhO.d.ts} +4 -4
- package/dist/index.d.ts +2 -2
- package/dist/index.js +3 -3
- package/dist/library/diagnostics.d.ts +1 -1
- package/dist/library/diagnostics.js +1 -1
- package/dist/library/index.d.ts +2 -2
- package/dist/library/index.js +1 -1
- package/dist/library/oss-api.d.ts +1 -1
- package/dist/library/oss-api.js +4 -4
- package/dist/library/oss-api.js.map +1 -1
- package/dist/library/rsengine.d.ts +1 -1
- package/dist/library/rsengine.js +2 -2
- package/dist/library/rsform-api/index.d.ts +299 -0
- package/dist/library/rsform-api/index.js +2 -0
- package/dist/library/rsform.d.ts +2 -2
- package/dist/library/rsform.js.map +1 -1
- package/dist/library/rsmodel-api.d.ts +1 -1
- package/dist/library/rsmodel-api.js +4 -2
- package/dist/library/rsmodel-api.js.map +1 -1
- package/dist/library/rsmodel.d.ts +1 -1
- package/dist/library/structure-planner.d.ts +1 -1
- package/dist/library/structure-planner.js +2 -2
- package/dist/rslang/api.d.ts +2 -58
- package/dist/rslang/api.js +1 -1
- package/dist/rslang/index.js +1 -1
- package/dist/rslang/parser/syntax-errors/index.js +1 -1
- package/dist/rslang/semantic/analyzer.js +2 -2
- package/dist/{syntax-errors-DwPXhpVe.js → syntax-errors-BN_bqTaX.js} +2 -2
- package/dist/{syntax-errors-DwPXhpVe.js.map → syntax-errors-BN_bqTaX.js.map} +1 -1
- package/package.json +3 -3
- package/src/index.ts +1 -0
- package/src/library/index.ts +1 -0
- package/src/library/oss-api.ts +5 -2
- package/src/library/rsform-api/alias.ts +160 -0
- package/src/library/rsform-api/analysis.ts +157 -0
- package/src/library/rsform-api/attribution.ts +87 -0
- package/src/library/rsform-api/cst-type.ts +216 -0
- package/src/library/rsform-api/expression.ts +73 -0
- package/src/library/rsform-api/formal-graph.test.ts +72 -0
- package/src/library/rsform-api/formal-graph.ts +195 -0
- package/src/library/rsform-api/index.ts +53 -0
- package/src/library/rsform-api/semantic-relations.ts +117 -0
- package/src/library/rsform-api/stats.ts +170 -0
- package/src/library/rsform-api/structure.ts +93 -0
- package/src/library/rsform-api/substitution.ts +82 -0
- package/src/library/rsform-api/synthesis.test.ts +126 -0
- package/src/library/rsform-api/synthesis.ts +166 -0
- package/src/library/rsform-api/text-resolution.test.ts +86 -0
- package/src/library/rsform-api/text-resolution.ts +152 -0
- package/src/library/rsform-api/transforms.test.ts +161 -0
- package/src/library/rsform-api/transforms.ts +42 -0
- package/src/library/rsform-api/types.ts +38 -0
- package/src/library/rsform.ts +3 -3
- package/src/library/rsmodel-api.ts +7 -1
- package/dist/diagnostics-CY9sKggB.js +0 -658
- package/dist/diagnostics-CY9sKggB.js.map +0 -1
- package/dist/library/rsform-api.d.ts +0 -103
- package/dist/library/rsform-api.js +0 -2
- package/src/library/rsform-api.ts +0 -755
|
@@ -1,658 +0,0 @@
|
|
|
1
|
-
import { TypeClass, TypeID, basic, bool, constant, isTypification } from "./rslang/semantic/typification.js";
|
|
2
|
-
import { labelType } from "./rslang/labels.js";
|
|
3
|
-
import { applyEntityReferenceMapping } from "./cctext/language-api.js";
|
|
4
|
-
import { RSErrorCode } from "./rslang/error.js";
|
|
5
|
-
import { generateExpressionFromAst } from "./rslang/parser/expression-generator.js";
|
|
6
|
-
import { applyAliasMapping, applyTypificationMapping, extractGlobals, parseRSLangExpression } from "./rslang/api.js";
|
|
7
|
-
import { applyPath } from "./rslang/semantic/typification-api.js";
|
|
8
|
-
import { ValueClass } from "./rslang/semantic/value-class.js";
|
|
9
|
-
import "./rslang/index.js";
|
|
10
|
-
import { CstClass, CstStatus, CstType } from "./library/rsform.js";
|
|
11
|
-
import { EvalStatus } from "./library/rsmodel.js";
|
|
12
|
-
//#region src/library/rsform-api.ts
|
|
13
|
-
/**
|
|
14
|
-
* Module: API for formal representation for systems of concepts.
|
|
15
|
-
*/
|
|
16
|
-
/** Record of {@link CstType} prefixes. */
|
|
17
|
-
const CST_TYPE_PREFIX = {
|
|
18
|
-
[CstType.NOMINAL]: "N",
|
|
19
|
-
[CstType.BASE]: "X",
|
|
20
|
-
[CstType.CONSTANT]: "C",
|
|
21
|
-
[CstType.STRUCTURED]: "S",
|
|
22
|
-
[CstType.AXIOM]: "A",
|
|
23
|
-
[CstType.TERM]: "D",
|
|
24
|
-
[CstType.FUNCTION]: "F",
|
|
25
|
-
[CstType.PREDICATE]: "P",
|
|
26
|
-
[CstType.STATEMENT]: "T"
|
|
27
|
-
};
|
|
28
|
-
/** Record of {@link CstType} to {@link CstClass} mapping. */
|
|
29
|
-
const CST_TYPE_TO_CLASS = {
|
|
30
|
-
[CstType.NOMINAL]: CstClass.NOMINAL,
|
|
31
|
-
[CstType.BASE]: CstClass.BASIC,
|
|
32
|
-
[CstType.CONSTANT]: CstClass.BASIC,
|
|
33
|
-
[CstType.STRUCTURED]: CstClass.BASIC,
|
|
34
|
-
[CstType.TERM]: CstClass.DERIVED,
|
|
35
|
-
[CstType.FUNCTION]: CstClass.DERIVED,
|
|
36
|
-
[CstType.AXIOM]: CstClass.STATEMENT,
|
|
37
|
-
[CstType.PREDICATE]: CstClass.DERIVED,
|
|
38
|
-
[CstType.STATEMENT]: CstClass.STATEMENT
|
|
39
|
-
};
|
|
40
|
-
/** Checks if {@link Constituenta} is a schema issue. */
|
|
41
|
-
function isSchemaIssue(cst) {
|
|
42
|
-
return (cst.diagnostics?.length ?? 0) > 0 || cst.status === CstStatus.INCORRECT || cst.status === CstStatus.INCALCULABLE;
|
|
43
|
-
}
|
|
44
|
-
/** Infers the status of an expression based on parsing and value information. */
|
|
45
|
-
function inferStatus(parse, value) {
|
|
46
|
-
if (!parse) return CstStatus.INCORRECT;
|
|
47
|
-
if (value === null) return CstStatus.INCALCULABLE;
|
|
48
|
-
if (value === ValueClass.PROPERTY) return CstStatus.PROPERTY;
|
|
49
|
-
return CstStatus.VERIFIED;
|
|
50
|
-
}
|
|
51
|
-
/** Infers type of constituent for a given template and arguments. */
|
|
52
|
-
function inferTemplatedType(templateType, args) {
|
|
53
|
-
if (args.length === 0 || args.some((arg) => !arg.value)) return templateType;
|
|
54
|
-
else if (templateType === CstType.PREDICATE) return CstType.AXIOM;
|
|
55
|
-
else return CstType.TERM;
|
|
56
|
-
}
|
|
57
|
-
/** Build alias mapping from template argument bindings. */
|
|
58
|
-
function argumentValuesToMapping(args) {
|
|
59
|
-
const mapping = {};
|
|
60
|
-
for (const arg of args) if (arg.value) mapping[arg.alias] = arg.value;
|
|
61
|
-
return mapping;
|
|
62
|
-
}
|
|
63
|
-
/**
|
|
64
|
-
* Normalize a RSLang expression for duplicate comparison.
|
|
65
|
-
*
|
|
66
|
-
* Returns `null` for basic concepts without formal definitions. Pass a pre-parsed `ast`
|
|
67
|
-
* when the expression was already analyzed to avoid re-parsing.
|
|
68
|
-
*/
|
|
69
|
-
function normalizeExpression(expression, cst_type, ast) {
|
|
70
|
-
if (isBasicConcept(cst_type) && cst_type !== CstType.AXIOM) return null;
|
|
71
|
-
const parsed = ast ?? parseRSLangExpression(expression);
|
|
72
|
-
let normalized = "";
|
|
73
|
-
if (parsed && !parsed.hasError) normalized = generateExpressionFromAst(parsed, { normalize: true });
|
|
74
|
-
else normalized = expression;
|
|
75
|
-
normalized = normalized.replace(/\s+/g, "");
|
|
76
|
-
return normalized === "" ? null : normalized;
|
|
77
|
-
}
|
|
78
|
-
/** Checks if given expression is a template. */
|
|
79
|
-
function inferTemplate(expression) {
|
|
80
|
-
const match = expression.match(/R\d+/g);
|
|
81
|
-
return (match && match?.length > 0) ?? false;
|
|
82
|
-
}
|
|
83
|
-
/** Infers the {@link CstClass} based on the provided {@link CstType} and template status. */
|
|
84
|
-
function inferClass(type, isTemplate = false) {
|
|
85
|
-
if (isTemplate) return CstClass.TEMPLATE;
|
|
86
|
-
return CST_TYPE_TO_CLASS[type];
|
|
87
|
-
}
|
|
88
|
-
/** Check if {@link Constituenta} is a template or a category. */
|
|
89
|
-
function isTemplateCst(cst) {
|
|
90
|
-
return cst.cst_type === CstType.FUNCTION || cst.cst_type === CstType.PREDICATE || cst.cst_type === CstType.STATEMENT;
|
|
91
|
-
}
|
|
92
|
-
/** Apply filter based on start {@link Constituenta} type. */
|
|
93
|
-
function applyFilterCategory(start, items) {
|
|
94
|
-
const startIndex = items.indexOf(start);
|
|
95
|
-
if (startIndex === -1) return [];
|
|
96
|
-
const nextCategoryIndex = items.findIndex((cst, index) => index > startIndex && cst.cst_type === CstType.STATEMENT);
|
|
97
|
-
return items.filter((_, index) => index >= startIndex && (nextCategoryIndex === -1 || index < nextCategoryIndex));
|
|
98
|
-
}
|
|
99
|
-
/** Prefix for alias indicating {@link CstType}. */
|
|
100
|
-
function getCstTypePrefix(type) {
|
|
101
|
-
return CST_TYPE_PREFIX[type];
|
|
102
|
-
}
|
|
103
|
-
/** Guess {@link CstType} from user input hint. */
|
|
104
|
-
function guessCstType(hint) {
|
|
105
|
-
if (hint.length !== 1) return null;
|
|
106
|
-
for (const [type, prefix] of Object.entries(CST_TYPE_PREFIX)) if (hint === prefix) return type;
|
|
107
|
-
return null;
|
|
108
|
-
}
|
|
109
|
-
/** Evaluate if {@link CstType} is basic concept. */
|
|
110
|
-
function isBasicConcept(type) {
|
|
111
|
-
switch (type) {
|
|
112
|
-
case CstType.NOMINAL:
|
|
113
|
-
case CstType.BASE:
|
|
114
|
-
case CstType.CONSTANT:
|
|
115
|
-
case CstType.STRUCTURED:
|
|
116
|
-
case CstType.AXIOM: return true;
|
|
117
|
-
case CstType.TERM:
|
|
118
|
-
case CstType.FUNCTION:
|
|
119
|
-
case CstType.PREDICATE:
|
|
120
|
-
case CstType.STATEMENT: return false;
|
|
121
|
-
}
|
|
122
|
-
}
|
|
123
|
-
/** Evaluate if {@link CstType} is base set or constant set. */
|
|
124
|
-
function isBaseSet(type) {
|
|
125
|
-
switch (type) {
|
|
126
|
-
case CstType.BASE:
|
|
127
|
-
case CstType.CONSTANT: return true;
|
|
128
|
-
case CstType.NOMINAL:
|
|
129
|
-
case CstType.STRUCTURED:
|
|
130
|
-
case CstType.AXIOM:
|
|
131
|
-
case CstType.TERM:
|
|
132
|
-
case CstType.FUNCTION:
|
|
133
|
-
case CstType.PREDICATE:
|
|
134
|
-
case CstType.STATEMENT: return false;
|
|
135
|
-
}
|
|
136
|
-
}
|
|
137
|
-
/** Evaluate if {@link CstType} is a function. */
|
|
138
|
-
function isFunctional(type) {
|
|
139
|
-
switch (type) {
|
|
140
|
-
case CstType.FUNCTION:
|
|
141
|
-
case CstType.PREDICATE: return true;
|
|
142
|
-
case CstType.NOMINAL:
|
|
143
|
-
case CstType.BASE:
|
|
144
|
-
case CstType.CONSTANT:
|
|
145
|
-
case CstType.STRUCTURED:
|
|
146
|
-
case CstType.AXIOM:
|
|
147
|
-
case CstType.TERM:
|
|
148
|
-
case CstType.STATEMENT: return false;
|
|
149
|
-
}
|
|
150
|
-
}
|
|
151
|
-
/** Evaluate if {@link CstType} is logical. */
|
|
152
|
-
function isLogical(type) {
|
|
153
|
-
switch (type) {
|
|
154
|
-
case CstType.AXIOM:
|
|
155
|
-
case CstType.STATEMENT: return true;
|
|
156
|
-
case CstType.NOMINAL:
|
|
157
|
-
case CstType.BASE:
|
|
158
|
-
case CstType.CONSTANT:
|
|
159
|
-
case CstType.STRUCTURED:
|
|
160
|
-
case CstType.TERM:
|
|
161
|
-
case CstType.FUNCTION:
|
|
162
|
-
case CstType.PREDICATE: return false;
|
|
163
|
-
}
|
|
164
|
-
}
|
|
165
|
-
/** Evaluate if {@link Constituenta} can be used produce structure. */
|
|
166
|
-
function canProduceStructure(cst) {
|
|
167
|
-
switch (cst.cst_type) {
|
|
168
|
-
case CstType.NOMINAL:
|
|
169
|
-
case CstType.BASE:
|
|
170
|
-
case CstType.CONSTANT:
|
|
171
|
-
case CstType.AXIOM:
|
|
172
|
-
case CstType.STATEMENT:
|
|
173
|
-
case CstType.PREDICATE: return false;
|
|
174
|
-
}
|
|
175
|
-
if (!cst.effectiveType) return false;
|
|
176
|
-
if (cst.cst_type === CstType.FUNCTION) {
|
|
177
|
-
const result = cst.effectiveType.result;
|
|
178
|
-
return typeCanProduceStructure(result);
|
|
179
|
-
}
|
|
180
|
-
if (!isTypification(cst.effectiveType)) return false;
|
|
181
|
-
return typeCanProduceStructure(cst.effectiveType);
|
|
182
|
-
}
|
|
183
|
-
/** Evaluate if {@link CstType} can have manual typification. */
|
|
184
|
-
function canHaveManualTypification(type) {
|
|
185
|
-
switch (type) {
|
|
186
|
-
case CstType.STRUCTURED:
|
|
187
|
-
case CstType.TERM:
|
|
188
|
-
case CstType.FUNCTION:
|
|
189
|
-
case CstType.PREDICATE: return true;
|
|
190
|
-
case CstType.NOMINAL:
|
|
191
|
-
case CstType.BASE:
|
|
192
|
-
case CstType.CONSTANT:
|
|
193
|
-
case CstType.AXIOM:
|
|
194
|
-
case CstType.STATEMENT: return false;
|
|
195
|
-
}
|
|
196
|
-
}
|
|
197
|
-
/** Validate alias format for a given {@link CstType} (prefix + digits, min length 2). */
|
|
198
|
-
function validateAliasFormat(alias, type) {
|
|
199
|
-
if (alias.length < 2) return false;
|
|
200
|
-
const prefix = getCstTypePrefix(type);
|
|
201
|
-
if (!alias.startsWith(prefix)) return false;
|
|
202
|
-
if (!/^\d+$/.exec(alias.substring(prefix.length))) return false;
|
|
203
|
-
return true;
|
|
204
|
-
}
|
|
205
|
-
/** Validate new alias against {@link CstType} and {@link RSForm}. */
|
|
206
|
-
function validateNewAlias(alias, type, schema) {
|
|
207
|
-
if (!validateAliasFormat(alias, type)) return false;
|
|
208
|
-
if (schema.cstByAlias.has(alias)) return false;
|
|
209
|
-
return true;
|
|
210
|
-
}
|
|
211
|
-
/** Generate alias for new {@link Constituenta} of a given {@link CstType} for current {@link RSForm}. */
|
|
212
|
-
function generateAlias(type, schema, takenAliases = []) {
|
|
213
|
-
const prefix = getCstTypePrefix(type);
|
|
214
|
-
if (schema.items.length <= 0) return `${prefix}1`;
|
|
215
|
-
let index = schema.items.reduce((prev, cst, index) => {
|
|
216
|
-
if (cst.cst_type !== type) return prev;
|
|
217
|
-
index = Number(cst.alias.slice(1 - cst.alias.length)) + 1;
|
|
218
|
-
return Math.max(prev, index);
|
|
219
|
-
}, 1);
|
|
220
|
-
let alias = `${prefix}${index}`;
|
|
221
|
-
while (takenAliases.includes(alias)) {
|
|
222
|
-
index = index + 1;
|
|
223
|
-
alias = `${prefix}${index}`;
|
|
224
|
-
}
|
|
225
|
-
return alias;
|
|
226
|
-
}
|
|
227
|
-
/**
|
|
228
|
-
* Id to pass as `insert_after` when creating a new {@link Constituenta} spawned by `targetId`:
|
|
229
|
-
* after the last existing child of that spawner, or after the spawner itself if none.
|
|
230
|
-
*/
|
|
231
|
-
function inferNewSpawnPosition(schema, targetId) {
|
|
232
|
-
let last = null;
|
|
233
|
-
for (const cst of schema.items) if (cst.spawner === targetId) last = cst.id;
|
|
234
|
-
return last ?? targetId;
|
|
235
|
-
}
|
|
236
|
-
/** Sorts library items relevant for InlineSynthesis with specified {@link RSForm}. */
|
|
237
|
-
function sortItemsForInlineSynthesis(receiver, items) {
|
|
238
|
-
const result = items.filter((item) => item.location === receiver.location);
|
|
239
|
-
for (const item of items) if (item.visible && item.owner === item.owner && !result.includes(item)) result.push(item);
|
|
240
|
-
for (const item of items) if (item.visible && !result.includes(item)) result.push(item);
|
|
241
|
-
for (const item of items) if (!result.includes(item)) result.push(item);
|
|
242
|
-
return result;
|
|
243
|
-
}
|
|
244
|
-
/**
|
|
245
|
-
* Remap formal expressions and terminological entity references in constituent fields.
|
|
246
|
-
* Mutates each element of `items` in place; pass owned or cloned data only.
|
|
247
|
-
*/
|
|
248
|
-
function applyMappingToConstituents(items, mapping, changeAliases) {
|
|
249
|
-
for (const cst of items) {
|
|
250
|
-
if (changeAliases && cst.alias in mapping) cst.alias = mapping[cst.alias];
|
|
251
|
-
cst.definition_formal = applyAliasMapping(cst.definition_formal, mapping);
|
|
252
|
-
cst.typification_manual = applyTypificationMapping(cst.typification_manual, mapping);
|
|
253
|
-
cst.term_raw = applyEntityReferenceMapping(cst.term_raw, mapping);
|
|
254
|
-
cst.definition_raw = applyEntityReferenceMapping(cst.definition_raw, mapping);
|
|
255
|
-
}
|
|
256
|
-
}
|
|
257
|
-
/** Remove alias from expression. */
|
|
258
|
-
function removeAliasReference(expression, alias) {
|
|
259
|
-
const result = expression.replaceAll(new RegExp(`\\b${alias}\\b`, "g"), "DEL");
|
|
260
|
-
return result === "DEL" ? "" : result;
|
|
261
|
-
}
|
|
262
|
-
/** Add alias to expression. */
|
|
263
|
-
function addAliasReference(expression, alias) {
|
|
264
|
-
return expression + " " + alias;
|
|
265
|
-
}
|
|
266
|
-
/** Returns expected {@link TypeClass} of formal definition for {@link CstType}. */
|
|
267
|
-
function typeClassForCstType(cstType) {
|
|
268
|
-
switch (cstType) {
|
|
269
|
-
case CstType.NOMINAL:
|
|
270
|
-
case CstType.BASE:
|
|
271
|
-
case CstType.CONSTANT:
|
|
272
|
-
case CstType.STRUCTURED:
|
|
273
|
-
case CstType.TERM: return TypeClass.typification;
|
|
274
|
-
case CstType.FUNCTION: return TypeClass.function;
|
|
275
|
-
case CstType.PREDICATE: return TypeClass.predicate;
|
|
276
|
-
case CstType.AXIOM:
|
|
277
|
-
case CstType.STATEMENT: return TypeClass.logic;
|
|
278
|
-
}
|
|
279
|
-
}
|
|
280
|
-
/** Checks whether a constituenta type supports formal definitions. */
|
|
281
|
-
function canHaveFormalDefinition(cstType) {
|
|
282
|
-
return cstType !== CstType.BASE && cstType !== CstType.CONSTANT;
|
|
283
|
-
}
|
|
284
|
-
function getAnalysisFor(expression, cstType, schema, alias) {
|
|
285
|
-
if (!canHaveFormalDefinition(cstType)) {
|
|
286
|
-
if (expression.trim().length === 0) {
|
|
287
|
-
const fallbackAlias = alias && alias.length > 0 ? alias : "X0";
|
|
288
|
-
return {
|
|
289
|
-
success: true,
|
|
290
|
-
type: cstType === CstType.BASE ? bool(basic(fallbackAlias)) : bool(constant(fallbackAlias)),
|
|
291
|
-
valueClass: ValueClass.VALUE,
|
|
292
|
-
errors: [],
|
|
293
|
-
ast: null
|
|
294
|
-
};
|
|
295
|
-
}
|
|
296
|
-
return {
|
|
297
|
-
success: false,
|
|
298
|
-
type: null,
|
|
299
|
-
valueClass: null,
|
|
300
|
-
errors: [{
|
|
301
|
-
code: RSErrorCode.definitionNotAllowed,
|
|
302
|
-
from: 0,
|
|
303
|
-
to: Math.max(expression.length, 1),
|
|
304
|
-
params: [cstType, alias ?? ""]
|
|
305
|
-
}],
|
|
306
|
-
ast: null
|
|
307
|
-
};
|
|
308
|
-
}
|
|
309
|
-
return refineAnalysisForDependencyCycles(schema.analyzer.checkFull(expression, {
|
|
310
|
-
expected: typeClassForCstType(cstType),
|
|
311
|
-
isDomain: cstType === CstType.STRUCTURED
|
|
312
|
-
}), expression, schema, alias);
|
|
313
|
-
}
|
|
314
|
-
/**
|
|
315
|
-
* When an untyped / bare F·P reference names a constituent on a definition cycle with the
|
|
316
|
-
* current expression, replace that error with {@link RSDiagnosticCode.schemaDependencyCycle}.
|
|
317
|
-
*
|
|
318
|
-
* Covers both semantic `globalNotTyped` (e.g. `F3[σ]`) and parser `globalFuncWithoutArgs`
|
|
319
|
-
* (bare `P1` / `F1` treated as a call without arguments).
|
|
320
|
-
*
|
|
321
|
-
* Uses a draft dependency graph: incoming edges of the edited constituent are taken from
|
|
322
|
-
* `expression`, so Check works before Save.
|
|
323
|
-
*/
|
|
324
|
-
function refineAnalysisForDependencyCycles(analysis, expression, schema, alias) {
|
|
325
|
-
if (analysis.errors.length === 0 || !schema.graph) return analysis;
|
|
326
|
-
const currentId = alias ? schema.cstByAlias.get(alias)?.id : void 0;
|
|
327
|
-
const expressionGlobals = extractGlobals(expression);
|
|
328
|
-
const draftGraph = currentId !== void 0 ? buildDraftDependencyGraph(schema, currentId, expressionGlobals) : schema.graph;
|
|
329
|
-
let changed = false;
|
|
330
|
-
const errors = analysis.errors.map((error) => {
|
|
331
|
-
if (error.code !== RSErrorCode.globalNotTyped && error.code !== RSErrorCode.globalFuncWithoutArgs) return error;
|
|
332
|
-
const missingAlias = error.params?.[0];
|
|
333
|
-
if (!missingAlias) return error;
|
|
334
|
-
const missing = schema.cstByAlias.get(missingAlias);
|
|
335
|
-
if (!missing) return error;
|
|
336
|
-
const cycleText = resolveDependencyCycleText(schema, draftGraph, currentId, missing.id);
|
|
337
|
-
if (!cycleText) return error;
|
|
338
|
-
changed = true;
|
|
339
|
-
return {
|
|
340
|
-
...error,
|
|
341
|
-
code: RSErrorCode.schemaDependencyCycle,
|
|
342
|
-
params: [cycleText]
|
|
343
|
-
};
|
|
344
|
-
});
|
|
345
|
-
return changed ? {
|
|
346
|
-
...analysis,
|
|
347
|
-
errors
|
|
348
|
-
} : analysis;
|
|
349
|
-
}
|
|
350
|
-
/**
|
|
351
|
-
* Clone the schema graph and replace dependencies of `currentId` with globals from the
|
|
352
|
-
* expression under check (unsaved draft).
|
|
353
|
-
*/
|
|
354
|
-
function buildDraftDependencyGraph(schema, currentId, expressionGlobals) {
|
|
355
|
-
const graph = schema.graph.clone();
|
|
356
|
-
const node = graph.at(currentId);
|
|
357
|
-
if (node) for (const parentId of [...node.inputs]) graph.removeEdge(parentId, currentId);
|
|
358
|
-
else graph.addNode(currentId);
|
|
359
|
-
for (const globalAlias of expressionGlobals) {
|
|
360
|
-
const source = schema.cstByAlias.get(globalAlias);
|
|
361
|
-
if (source) graph.addEdge(source.id, currentId);
|
|
362
|
-
}
|
|
363
|
-
return graph;
|
|
364
|
-
}
|
|
365
|
-
/**
|
|
366
|
-
* Resolve formatted cycle text for an untyped global reference in analysis.
|
|
367
|
-
*
|
|
368
|
-
* Uses `graph` (often a draft graph built from the expression under check). When
|
|
369
|
-
* `currentId` is omitted, falls back to schema diagnostics on `missingId`.
|
|
370
|
-
*
|
|
371
|
-
* @returns Closed alias path such as `F3 → P1 → F3`, or `null` when no shared cycle exists.
|
|
372
|
-
*/
|
|
373
|
-
function resolveDependencyCycleText(schema, graph, currentId, missingId) {
|
|
374
|
-
for (const cycle of graph.findCycles()) {
|
|
375
|
-
const members = new Set(cycle);
|
|
376
|
-
if (!members.has(missingId)) continue;
|
|
377
|
-
if (currentId !== void 0 && !members.has(currentId)) continue;
|
|
378
|
-
return formatDependencyCycle(cycle.map((id) => schema.cstByID.get(id)?.alias ?? String(id)));
|
|
379
|
-
}
|
|
380
|
-
if (currentId === void 0) return (schema.cstByID.get(missingId)?.diagnostics.find((item) => item.code === RSDiagnosticCode.schemaDependencyCycle))?.params?.[0] ?? null;
|
|
381
|
-
return null;
|
|
382
|
-
}
|
|
383
|
-
/** Calculate statistics for {@link RSForm}. */
|
|
384
|
-
function calculateSchemaStats(target) {
|
|
385
|
-
const items = target.items;
|
|
386
|
-
return {
|
|
387
|
-
count_all: items.length,
|
|
388
|
-
count_crucial: items.reduce((sum, cst) => sum + (cst.crucial ? 1 : 0), 0),
|
|
389
|
-
step_complexity: items.reduce((sum, cst) => sum + calculateStepComplexity(cst), 0),
|
|
390
|
-
count_problematic: items.reduce((sum, cst) => sum + (isSchemaIssue(cst) ? 1 : 0), 0),
|
|
391
|
-
count_homonyms: items.reduce((sum, cst) => sum + (hasCstDiagnostic(cst, RSDiagnosticCode.schemaHomonym) ? 1 : 0), 0),
|
|
392
|
-
count_formal_duplicates: items.reduce((sum, cst) => sum + (hasCstDiagnostic(cst, RSDiagnosticCode.schemaFormalDuplicate) ? 1 : 0), 0),
|
|
393
|
-
count_missing_convention: items.reduce((sum, cst) => sum + (isMissingConvention(cst) ? 1 : 0), 0),
|
|
394
|
-
count_type_mismatch: items.reduce((sum, cst) => sum + (cst.is_type_mismatch ? 1 : 0), 0),
|
|
395
|
-
count_incorrect: items.reduce((sum, cst) => sum + (cst.status === CstStatus.INCORRECT ? 1 : 0), 0),
|
|
396
|
-
count_property: items.reduce((sum, cst) => sum + (cst.analysis?.valueClass === ValueClass.PROPERTY ? 1 : 0), 0),
|
|
397
|
-
count_incalculable: items.reduce((sum, cst) => sum + (cst.analysis?.success && cst.analysis.valueClass === null ? 1 : 0), 0),
|
|
398
|
-
count_inherited: items.reduce((sum, cst) => sum + (cst.is_inherited ? 1 : 0), 0),
|
|
399
|
-
count_text_term: items.reduce((sum, cst) => sum + (cst.term_raw ? 1 : 0), 0),
|
|
400
|
-
count_definition: items.reduce((sum, cst) => sum + (cst.definition_raw ? 1 : 0), 0),
|
|
401
|
-
count_convention: items.reduce((sum, cst) => sum + (isBasicConcept(cst.cst_type) && cst.convention ? 1 : 0), 0),
|
|
402
|
-
count_comment: items.reduce((sum, cst) => sum + (!isBasicConcept(cst.cst_type) && !cst.convention ? 1 : 0), 0),
|
|
403
|
-
count_base: items.reduce((sum, cst) => sum + (cst.cst_type === CstType.BASE ? 1 : 0), 0),
|
|
404
|
-
count_constant: items.reduce((sum, cst) => sum + (cst.cst_type === CstType.CONSTANT ? 1 : 0), 0),
|
|
405
|
-
count_structured: items.reduce((sum, cst) => sum + (cst.cst_type === CstType.STRUCTURED ? 1 : 0), 0),
|
|
406
|
-
count_axiom: items.reduce((sum, cst) => sum + (cst.cst_type === CstType.AXIOM ? 1 : 0), 0),
|
|
407
|
-
count_term: items.reduce((sum, cst) => sum + (cst.cst_type === CstType.TERM ? 1 : 0), 0),
|
|
408
|
-
count_function: items.reduce((sum, cst) => sum + (cst.cst_type === CstType.FUNCTION ? 1 : 0), 0),
|
|
409
|
-
count_predicate: items.reduce((sum, cst) => sum + (cst.cst_type === CstType.PREDICATE ? 1 : 0), 0),
|
|
410
|
-
count_statement: items.reduce((sum, cst) => sum + (cst.cst_type === CstType.STATEMENT ? 1 : 0), 0),
|
|
411
|
-
count_nominal: items.reduce((sum, cst) => sum + (cst.cst_type === CstType.NOMINAL ? 1 : 0), 0)
|
|
412
|
-
};
|
|
413
|
-
}
|
|
414
|
-
/** Finds {@link Constituenta} by structure path. */
|
|
415
|
-
function findCstByStructure(schema, target, path) {
|
|
416
|
-
for (const cst of schema.items) {
|
|
417
|
-
if (!cst.spawner_path) continue;
|
|
418
|
-
const absolutePath = resolveAbsoluteSpawnerPath(schema, cst, target.id);
|
|
419
|
-
if (absolutePath?.length === path.length && absolutePath.every((v, i) => v === path[i])) return cst;
|
|
420
|
-
}
|
|
421
|
-
return null;
|
|
422
|
-
}
|
|
423
|
-
/** Retrieves name for piece of target {@link Constituenta} structure. */
|
|
424
|
-
function getStructureName(schema, target, path) {
|
|
425
|
-
const representation = findCstByStructure(schema, target, path);
|
|
426
|
-
if (representation) return `${representation.alias}: ${representation.term_resolved}`;
|
|
427
|
-
if (!isTypification(target.effectiveType)) return "";
|
|
428
|
-
const type = applyPath(target.effectiveType, path);
|
|
429
|
-
if (type?.typeID === TypeID.basic) {
|
|
430
|
-
const cst = schema.cstByAlias.get(type.baseID);
|
|
431
|
-
if (cst?.term_resolved) return `${cst.alias}: ${cst.term_resolved}`;
|
|
432
|
-
}
|
|
433
|
-
return "";
|
|
434
|
-
}
|
|
435
|
-
function calculateStepComplexity(cst) {
|
|
436
|
-
if (cst.cst_type === CstType.AXIOM || cst.cst_type === CstType.NOMINAL || !isBasicConcept(cst.cst_type)) return 0;
|
|
437
|
-
if (cst.cst_type === CstType.BASE || cst.cst_type === CstType.CONSTANT || !cst.effectiveType) return 1;
|
|
438
|
-
const type = cst.effectiveType;
|
|
439
|
-
return calculateTypificationComplexity(type) + 1;
|
|
440
|
-
}
|
|
441
|
-
function calculateTypificationComplexity(type) {
|
|
442
|
-
switch (type.typeID) {
|
|
443
|
-
case TypeID.basic:
|
|
444
|
-
case TypeID.integer:
|
|
445
|
-
case TypeID.anyTypification: return 0;
|
|
446
|
-
case TypeID.tuple: return type.factors.length + type.factors.reduce((sum, factor) => sum + calculateTypificationComplexity(factor), 0);
|
|
447
|
-
case TypeID.collection:
|
|
448
|
-
if (type.base.typeID === TypeID.tuple) {
|
|
449
|
-
let sum = 0;
|
|
450
|
-
type.base.factors.forEach((factor) => {
|
|
451
|
-
sum += calculateTypificationComplexity(factor);
|
|
452
|
-
});
|
|
453
|
-
return sum + type.base.factors.length;
|
|
454
|
-
} else if (type.base.typeID === TypeID.collection) return calculateTypificationComplexity(type.base) + 1;
|
|
455
|
-
return 0;
|
|
456
|
-
}
|
|
457
|
-
}
|
|
458
|
-
function isMissingConvention(cst) {
|
|
459
|
-
if (isBasicConcept(cst.cst_type) && !isLogical(cst.cst_type)) {
|
|
460
|
-
if (!cst.convention || !cst.term_resolved) return true;
|
|
461
|
-
}
|
|
462
|
-
return false;
|
|
463
|
-
}
|
|
464
|
-
function resolveAbsoluteSpawnerPath(schema, cst, targetId) {
|
|
465
|
-
if (!cst.spawner_path || cst.spawner == null) return null;
|
|
466
|
-
if (cst.spawner === targetId) return cst.spawner_path;
|
|
467
|
-
const byId = schema.cstByID ?? new Map(schema.items.map((item) => [item.id, item]));
|
|
468
|
-
const visited = /* @__PURE__ */ new Set([cst.id]);
|
|
469
|
-
let currentPath = [...cst.spawner_path];
|
|
470
|
-
let currentSpawnerId = cst.spawner;
|
|
471
|
-
while (currentSpawnerId != null) {
|
|
472
|
-
if (currentSpawnerId === targetId) return currentPath;
|
|
473
|
-
if (visited.has(currentSpawnerId)) return null;
|
|
474
|
-
visited.add(currentSpawnerId);
|
|
475
|
-
const parent = byId.get(currentSpawnerId);
|
|
476
|
-
if (!parent?.spawner_path || parent.spawner == null) return null;
|
|
477
|
-
currentPath = [...parent.spawner_path, ...currentPath];
|
|
478
|
-
currentSpawnerId = parent.spawner;
|
|
479
|
-
}
|
|
480
|
-
return null;
|
|
481
|
-
}
|
|
482
|
-
/** Evaluate if {@link Typification} can be used to produce structure. */
|
|
483
|
-
function typeCanProduceStructure(type) {
|
|
484
|
-
if (type.typeID === TypeID.basic || type.typeID === TypeID.integer || type.typeID === TypeID.anyTypification) return false;
|
|
485
|
-
else if (type.typeID === TypeID.tuple) return true;
|
|
486
|
-
else return type.base.typeID !== TypeID.basic && type.base.typeID !== TypeID.integer && type.base.typeID !== TypeID.anyTypification;
|
|
487
|
-
}
|
|
488
|
-
//#endregion
|
|
489
|
-
//#region src/library/diagnostics.ts
|
|
490
|
-
/** Origin of a diagnostic. */
|
|
491
|
-
const DiagnosticKind = {
|
|
492
|
-
EXPRESSION: "expression",
|
|
493
|
-
SCHEMA: "schema",
|
|
494
|
-
MODEL: "model"
|
|
495
|
-
};
|
|
496
|
-
/** Schema and model diagnostic codes (same numeric format as {@link RSErrorCode}). */
|
|
497
|
-
const RSDiagnosticCode = {
|
|
498
|
-
schemaHomonym: 35073,
|
|
499
|
-
schemaFormalDuplicate: 35074,
|
|
500
|
-
schemaMissingConvention: 35075,
|
|
501
|
-
schemaMissingTerm: 35076,
|
|
502
|
-
schemaTypeMismatch: 35077,
|
|
503
|
-
schemaDependencyCycle: 35078,
|
|
504
|
-
modelEmpty: 35088,
|
|
505
|
-
modelAxiomFalse: 35089,
|
|
506
|
-
modelInvalidData: 35090,
|
|
507
|
-
modelEvalFail: 35091
|
|
508
|
-
};
|
|
509
|
-
/** Whether a constituent has a schema/model diagnostic with the given code. */
|
|
510
|
-
function hasCstDiagnostic(cst, code) {
|
|
511
|
-
return cst.diagnostics?.some((item) => item.code === code) ?? false;
|
|
512
|
-
}
|
|
513
|
-
/**
|
|
514
|
-
* Populate `diagnostics` on each constituent (homonyms, duplicates, metadata, type mismatch, cycles).
|
|
515
|
-
*
|
|
516
|
-
* Requires normalized formal definitions for duplicate detection (same as Portal loader).
|
|
517
|
-
* When `graph` is provided, dependency cycles are reported as {@link RSDiagnosticCode.schemaDependencyCycle}.
|
|
518
|
-
*/
|
|
519
|
-
function assignSchemaDiagnostics(items, resolveAlias, normalizedDefinitions, graph) {
|
|
520
|
-
const homonymById = detectHomonymDiagnostics(items, resolveAlias);
|
|
521
|
-
const duplicateById = detectFormalDuplicateDiagnostics(items, resolveAlias, normalizedDefinitions);
|
|
522
|
-
const cycleById = graph ? detectDependencyCycleDiagnostics(graph, resolveAlias) : /* @__PURE__ */ new Map();
|
|
523
|
-
for (const cst of items) {
|
|
524
|
-
const diagnostics = [];
|
|
525
|
-
const cycle = cycleById.get(cst.id);
|
|
526
|
-
if (cycle) diagnostics.push(cycle);
|
|
527
|
-
const homonym = homonymById.get(cst.id);
|
|
528
|
-
if (homonym) diagnostics.push(homonym);
|
|
529
|
-
const duplicate = duplicateById.get(cst.id);
|
|
530
|
-
if (duplicate) diagnostics.push(duplicate);
|
|
531
|
-
diagnostics.push(...collectLocalSchemaDiagnostics(cst));
|
|
532
|
-
cst.diagnostics = diagnostics;
|
|
533
|
-
}
|
|
534
|
-
}
|
|
535
|
-
/**
|
|
536
|
-
* Format a closed dependency cycle as `A → B → A`.
|
|
537
|
-
*
|
|
538
|
-
* Rotates the path to start at the lexicographically smallest alias so the same
|
|
539
|
-
* cycle always renders identically regardless of graph traversal order.
|
|
540
|
-
*
|
|
541
|
-
* @param aliases Closed or open alias path from {@link Graph.findCycles}.
|
|
542
|
-
* @returns Human-readable cycle text joined with ` → `.
|
|
543
|
-
*/
|
|
544
|
-
function formatDependencyCycle(aliases) {
|
|
545
|
-
if (aliases.length < 2) return aliases.join(" → ");
|
|
546
|
-
const closed = aliases[0] === aliases[aliases.length - 1];
|
|
547
|
-
const open = closed ? aliases.slice(0, -1) : [...aliases];
|
|
548
|
-
if (open.length === 0) return aliases.join(" → ");
|
|
549
|
-
let bestStart = 0;
|
|
550
|
-
for (let index = 1; index < open.length; index++) {
|
|
551
|
-
const alias = open[index];
|
|
552
|
-
const bestAlias = open[bestStart];
|
|
553
|
-
if (alias !== void 0 && bestAlias !== void 0 && alias < bestAlias) bestStart = index;
|
|
554
|
-
}
|
|
555
|
-
const rotated = [...open.slice(bestStart), ...open.slice(0, bestStart)];
|
|
556
|
-
if (closed) {
|
|
557
|
-
const first = rotated[0];
|
|
558
|
-
if (first !== void 0) rotated.push(first);
|
|
559
|
-
}
|
|
560
|
-
return rotated.join(" → ");
|
|
561
|
-
}
|
|
562
|
-
/**
|
|
563
|
-
* Map each node id that participates in a dependency cycle to a schema diagnostic.
|
|
564
|
-
*
|
|
565
|
-
* `params[0]` is the closed cycle path (`F3 → P1 → F3`).
|
|
566
|
-
*
|
|
567
|
-
* @param graph Constituent dependency graph (provider → dependent edges).
|
|
568
|
-
* @param resolveAlias Maps node id to display alias for cycle formatting.
|
|
569
|
-
* @returns One {@link CstDiagnostic} per node on each cyclic SCC.
|
|
570
|
-
*/
|
|
571
|
-
function detectDependencyCycleDiagnostics(graph, resolveAlias) {
|
|
572
|
-
const result = /* @__PURE__ */ new Map();
|
|
573
|
-
for (const cycle of graph.findCycles()) {
|
|
574
|
-
if (cycle.length < 2) continue;
|
|
575
|
-
const cycleText = formatDependencyCycle(cycle.map((id) => resolveAlias(id)));
|
|
576
|
-
const memberIds = new Set(cycle);
|
|
577
|
-
for (const id of memberIds) result.set(id, {
|
|
578
|
-
kind: DiagnosticKind.SCHEMA,
|
|
579
|
-
code: RSDiagnosticCode.schemaDependencyCycle,
|
|
580
|
-
params: [cycleText]
|
|
581
|
-
});
|
|
582
|
-
}
|
|
583
|
-
return result;
|
|
584
|
-
}
|
|
585
|
-
/** Map a model evaluation status to a compact diagnostic, or `null` when not an issue. */
|
|
586
|
-
function modelStatusCstDiagnostic(status, cstType) {
|
|
587
|
-
const code = modelStatusToCode(status, cstType);
|
|
588
|
-
if (code === null) return null;
|
|
589
|
-
return {
|
|
590
|
-
kind: DiagnosticKind.MODEL,
|
|
591
|
-
code,
|
|
592
|
-
params: [String(status)]
|
|
593
|
-
};
|
|
594
|
-
}
|
|
595
|
-
function collectLocalSchemaDiagnostics(cst) {
|
|
596
|
-
const result = [];
|
|
597
|
-
if (cst.is_type_mismatch) result.push({
|
|
598
|
-
kind: DiagnosticKind.SCHEMA,
|
|
599
|
-
code: RSDiagnosticCode.schemaTypeMismatch,
|
|
600
|
-
params: [cst.typification_manual, labelType(cst.analysis.type)]
|
|
601
|
-
});
|
|
602
|
-
if (isBasicConcept(cst.cst_type) && !isLogical(cst.cst_type)) {
|
|
603
|
-
if (!cst.convention.trim()) result.push({
|
|
604
|
-
kind: DiagnosticKind.SCHEMA,
|
|
605
|
-
code: RSDiagnosticCode.schemaMissingConvention
|
|
606
|
-
});
|
|
607
|
-
if (!cst.term_resolved.trim()) result.push({
|
|
608
|
-
kind: DiagnosticKind.SCHEMA,
|
|
609
|
-
code: RSDiagnosticCode.schemaMissingTerm
|
|
610
|
-
});
|
|
611
|
-
}
|
|
612
|
-
return result;
|
|
613
|
-
}
|
|
614
|
-
function detectGroupedAliasDiagnostics(items, resolveAlias, groupKey, code) {
|
|
615
|
-
const groups = /* @__PURE__ */ new Map();
|
|
616
|
-
for (const cst of items) {
|
|
617
|
-
const key = groupKey(cst);
|
|
618
|
-
if (!key) continue;
|
|
619
|
-
const group = groups.get(key) ?? [];
|
|
620
|
-
group.push(cst);
|
|
621
|
-
groups.set(key, group);
|
|
622
|
-
}
|
|
623
|
-
const result = /* @__PURE__ */ new Map();
|
|
624
|
-
for (const group of groups.values()) {
|
|
625
|
-
if (group.length <= 1) continue;
|
|
626
|
-
for (const cst of group) {
|
|
627
|
-
const aliases = group.filter((other) => other.id !== cst.id).map((other) => resolveAlias(other.id)).join(", ");
|
|
628
|
-
result.set(cst.id, {
|
|
629
|
-
kind: DiagnosticKind.SCHEMA,
|
|
630
|
-
code,
|
|
631
|
-
params: [aliases]
|
|
632
|
-
});
|
|
633
|
-
}
|
|
634
|
-
}
|
|
635
|
-
return result;
|
|
636
|
-
}
|
|
637
|
-
function detectHomonymDiagnostics(items, resolveAlias) {
|
|
638
|
-
return detectGroupedAliasDiagnostics(items, resolveAlias, (cst) => {
|
|
639
|
-
const key = cst.term_resolved.trim().toLocaleLowerCase();
|
|
640
|
-
return key === "" ? void 0 : key;
|
|
641
|
-
}, RSDiagnosticCode.schemaHomonym);
|
|
642
|
-
}
|
|
643
|
-
function detectFormalDuplicateDiagnostics(items, resolveAlias, normalizedDefinitions) {
|
|
644
|
-
return detectGroupedAliasDiagnostics(items, resolveAlias, (cst) => normalizedDefinitions.get(cst.id), RSDiagnosticCode.schemaFormalDuplicate);
|
|
645
|
-
}
|
|
646
|
-
function modelStatusToCode(status, cstType) {
|
|
647
|
-
switch (status) {
|
|
648
|
-
case EvalStatus.EMPTY: return isBasicConcept(cstType) ? RSDiagnosticCode.modelEmpty : null;
|
|
649
|
-
case EvalStatus.AXIOM_FALSE: return RSDiagnosticCode.modelAxiomFalse;
|
|
650
|
-
case EvalStatus.INVALID_DATA: return RSDiagnosticCode.modelInvalidData;
|
|
651
|
-
case EvalStatus.EVAL_FAIL: return RSDiagnosticCode.modelEvalFail;
|
|
652
|
-
default: return null;
|
|
653
|
-
}
|
|
654
|
-
}
|
|
655
|
-
//#endregion
|
|
656
|
-
export { isLogical as A, inferNewSpawnPosition as C, isBaseSet as D, inferTemplatedType as E, removeAliasReference as F, sortItemsForInlineSynthesis as I, typeClassForCstType as L, isTemplateCst as M, normalizeExpression as N, isBasicConcept as O, refineAnalysisForDependencyCycles as P, validateAliasFormat as R, inferClass as S, inferTemplate as T, generateAlias as _, formatDependencyCycle as a, getStructureName as b, addAliasReference as c, argumentValuesToMapping as d, calculateSchemaStats as f, findCstByStructure as g, canProduceStructure as h, detectDependencyCycleDiagnostics as i, isSchemaIssue as j, isFunctional as k, applyFilterCategory as l, canHaveManualTypification as m, RSDiagnosticCode as n, hasCstDiagnostic as o, canHaveFormalDefinition as p, assignSchemaDiagnostics as r, modelStatusCstDiagnostic as s, DiagnosticKind as t, applyMappingToConstituents as u, getAnalysisFor as v, inferStatus as w, guessCstType as x, getCstTypePrefix as y, validateNewAlias as z };
|
|
657
|
-
|
|
658
|
-
//# sourceMappingURL=diagnostics-CY9sKggB.js.map
|