@rsconcept/domain 2.3.0 → 3.0.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/{diagnostics-Dac5sJhO.d.ts → diagnostics-DsEhmFh0.d.ts} +5 -3
- package/dist/{diagnostics-CljEzVBV.js → diagnostics-ndGYbvgh.js} +21 -11
- package/dist/diagnostics-ndGYbvgh.js.map +1 -0
- package/dist/index-DpiTybDB.d.ts +376 -0
- package/dist/index.d.ts +1 -1
- package/dist/index.js +1 -1
- package/dist/library/diagnostics.d.ts +1 -1
- package/dist/library/diagnostics.js +1 -1
- package/dist/library/index.d.ts +5 -4
- package/dist/library/index.js +1 -1
- package/dist/library/index.js.map +1 -1
- package/dist/library/oss-api.d.ts +1 -1
- package/dist/library/oss-api.js.map +1 -1
- package/dist/library/rsengine.d.ts +1 -1
- package/dist/library/rsengine.js +1 -1
- package/dist/library/rsform-api/index.d.ts +2 -299
- package/dist/library/rsform-api/index.js +1 -1
- package/dist/library/rsform.d.ts +1 -1
- package/dist/library/rsmodel-api.d.ts +9 -4
- package/dist/library/rsmodel-api.js +6 -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 +1 -1
- package/dist/library/structure-planner.js.map +1 -1
- package/package.json +1 -1
- package/src/library/diagnostics.ts +20 -9
- package/src/library/oss-api.ts +5 -1
- package/src/library/rsform-api/alias.ts +8 -8
- package/src/library/rsform-api/cst-type.ts +7 -5
- package/src/library/rsform-api/expression.ts +3 -3
- package/src/library/rsform-api/formal-graph.test.ts +2 -2
- package/src/library/rsform-api/formal-graph.ts +6 -10
- package/src/library/rsform-api/index.ts +18 -3
- package/src/library/rsform-api/semantic-relations.ts +4 -7
- package/src/library/rsform-api/stats.ts +6 -5
- package/src/library/rsform-api/structure.ts +12 -6
- package/src/library/rsform-api/substitution.ts +2 -2
- package/src/library/rsform-api/synthesis.test.ts +33 -2
- package/src/library/rsform-api/synthesis.ts +16 -12
- package/src/library/rsform-api/text-resolution.test.ts +2 -4
- package/src/library/rsform-api/text-resolution.ts +8 -8
- package/src/library/rsform-api/types.ts +89 -8
- package/src/library/rsmodel-api.ts +10 -5
- package/src/library/structure-planner.ts +6 -2
- package/src/library/template-instantiation.ts +11 -9
- package/dist/diagnostics-CljEzVBV.js.map +0 -1
|
@@ -3,7 +3,7 @@ import { labelType } from "../rslang/labels.js";
|
|
|
3
3
|
import { splitTemplateDefinition } from "../rslang/api.js";
|
|
4
4
|
import { CstType } from "./rsform.js";
|
|
5
5
|
import "../rslang/index.js";
|
|
6
|
-
import { y as findCstByStructure } from "../diagnostics-
|
|
6
|
+
import { y as findCstByStructure } from "../diagnostics-ndGYbvgh.js";
|
|
7
7
|
//#region src/library/structure-planner.ts
|
|
8
8
|
/** Structure planner for {@link Constituenta}. */
|
|
9
9
|
var StructurePlanner = class {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"structure-planner.js","names":[],"sources":["../../src/library/structure-planner.ts"],"sourcesContent":["import { makeTypePath, TypeID, type TypePath, type Typification } from '../rslang';\nimport { splitTemplateDefinition } from '../rslang/api';\nimport { labelType } from '../rslang/labels';\nimport { bool, type EchelonFunctional, isTypification } from '../rslang/semantic/typification';\n\nimport { type Constituenta, CstType, type RSForm } from './rsform';\nimport { findCstByStructure } from './rsform-api';\n\n/** Represents a node in the structure planner. */\nexport interface SPNode {\n key: string;\n path: TypePath;\n type: Typification;\n parent: number | null;\n definition: string;\n existing: Constituenta | null;\n}\n\n/** Structure planner for {@link Constituenta}. */\nexport class StructurePlanner {\n private items: SPNode[] = [];\n private schema: RSForm;\n private target: Constituenta;\n private rootType: Typification;\n\n constructor(schema: RSForm, target: Constituenta) {\n const eff = target.effectiveType;\n if (eff == null) {\n throw new Error('Invalid typification for target');\n }\n this.schema = schema;\n this.target = target;\n if (target.cst_type === CstType.FUNCTION && !isTypification(eff)) {\n this.rootType = (eff as EchelonFunctional).result;\n } else if (isTypification(eff)) {\n this.rootType = eff as Typification;\n } else {\n throw new Error('Invalid typification for target');\n }\n }\n\n public build(): SPNode[] {\n this.items.push({\n key: 'root',\n path: makeTypePath([]),\n type: this.rootType,\n parent: null,\n definition: labelType(this.target.effectiveType),\n existing: this.target\n });\n this.visit(this.rootType, this.rootType.typeID === TypeID.collection ? [0] : [], 0);\n return this.items;\n }\n\n private visit(type: Typification, path: number[], parent: number) {\n switch (type.typeID) {\n case TypeID.collection:\n if (type.base.typeID === TypeID.tuple) {\n type.base.factors.forEach((factor, index) => {\n const nextPath = [...path, index + 1];\n const nextType = bool(factor);\n const nextNode = this.pushNode(nextPath, nextType, parent);\n this.visit(nextType, nextPath, nextNode);\n });\n } else if (type.base.typeID === TypeID.collection) {\n const nextPath = [...path, 0];\n const nextNode = this.pushNode(nextPath, type.base, parent);\n this.visit(type.base, nextPath, nextNode);\n }\n return;\n case TypeID.tuple:\n type.factors.forEach((factor, index) => {\n const nextPath = [...path, index + 1];\n const nextNode = this.pushNode(nextPath, factor, parent);\n this.visit(factor, nextPath, nextNode);\n });\n return;\n default:\n return;\n }\n }\n\n private pushNode(path: number[], type: Typification, parent: number) {\n const typePath = makeTypePath(path);\n this.items.push({\n key: formatPathText(typePath),\n path: typePath,\n type: type,\n parent: parent,\n definition: produceDefinition(this.target, this.rootType, typePath),\n existing: findCstByStructure(this.schema, this.target, typePath)\n });\n return this.items.length - 1;\n }\n}\n\n// ======= Internals =======\nfunction produceDefinition(target:
|
|
1
|
+
{"version":3,"file":"structure-planner.js","names":[],"sources":["../../src/library/structure-planner.ts"],"sourcesContent":["import { makeTypePath, TypeID, type TypePath, type Typification } from '../rslang';\nimport { splitTemplateDefinition } from '../rslang/api';\nimport { labelType } from '../rslang/labels';\nimport { bool, type EchelonFunctional, isTypification } from '../rslang/semantic/typification';\n\nimport { type Constituenta, CstType, type RSForm } from './rsform';\nimport { findCstByStructure, type FormalOrderFields, type StructureCapableFields } from './rsform-api';\n\n/** Represents a node in the structure planner. */\nexport interface SPNode {\n key: string;\n path: TypePath;\n type: Typification;\n parent: number | null;\n definition: string;\n existing: Constituenta | null;\n}\n\n/** Structure planner for {@link Constituenta}. */\nexport class StructurePlanner {\n private items: SPNode[] = [];\n private schema: RSForm;\n private target: Constituenta;\n private rootType: Typification;\n\n constructor(schema: RSForm, target: Constituenta) {\n const eff = target.effectiveType;\n if (eff == null) {\n throw new Error('Invalid typification for target');\n }\n this.schema = schema;\n this.target = target;\n if (target.cst_type === CstType.FUNCTION && !isTypification(eff)) {\n this.rootType = (eff as EchelonFunctional).result;\n } else if (isTypification(eff)) {\n this.rootType = eff as Typification;\n } else {\n throw new Error('Invalid typification for target');\n }\n }\n\n public build(): SPNode[] {\n this.items.push({\n key: 'root',\n path: makeTypePath([]),\n type: this.rootType,\n parent: null,\n definition: labelType(this.target.effectiveType),\n existing: this.target\n });\n this.visit(this.rootType, this.rootType.typeID === TypeID.collection ? [0] : [], 0);\n return this.items;\n }\n\n private visit(type: Typification, path: number[], parent: number) {\n switch (type.typeID) {\n case TypeID.collection:\n if (type.base.typeID === TypeID.tuple) {\n type.base.factors.forEach((factor, index) => {\n const nextPath = [...path, index + 1];\n const nextType = bool(factor);\n const nextNode = this.pushNode(nextPath, nextType, parent);\n this.visit(nextType, nextPath, nextNode);\n });\n } else if (type.base.typeID === TypeID.collection) {\n const nextPath = [...path, 0];\n const nextNode = this.pushNode(nextPath, type.base, parent);\n this.visit(type.base, nextPath, nextNode);\n }\n return;\n case TypeID.tuple:\n type.factors.forEach((factor, index) => {\n const nextPath = [...path, index + 1];\n const nextNode = this.pushNode(nextPath, factor, parent);\n this.visit(factor, nextPath, nextNode);\n });\n return;\n default:\n return;\n }\n }\n\n private pushNode(path: number[], type: Typification, parent: number) {\n const typePath = makeTypePath(path);\n this.items.push({\n key: formatPathText(typePath),\n path: typePath,\n type: type,\n parent: parent,\n definition: produceDefinition(this.target, this.rootType, typePath),\n existing: findCstByStructure(this.schema, this.target, typePath)\n });\n return this.items.length - 1;\n }\n}\n\n// ======= Internals =======\nfunction produceDefinition(\n target: FormalOrderFields & StructureCapableFields,\n rootType: Typification,\n path: TypePath\n): string {\n let current = rootType;\n let expression = target.alias;\n let index = rootType.typeID === TypeID.collection ? 1 : 0;\n let prefix = '';\n if (target.cst_type === CstType.FUNCTION) {\n prefix = `[${splitTemplateDefinition(target.definition_formal).head}] `;\n const funcType =\n target.effectiveType && !isTypification(target.effectiveType)\n ? (target.effectiveType as EchelonFunctional)\n : null;\n if (funcType) {\n expression = `${expression}[${funcType.args.map(arg => arg.alias).join(', ')}]`;\n }\n }\n\n while (index < path.length) {\n const step = path[index];\n switch (current.typeID) {\n case TypeID.collection:\n if (current.base.typeID === TypeID.tuple) {\n expression = `Pr${step}(${expression})`;\n current = bool(current.base.factors[step - 1]);\n index += 1;\n } else {\n expression = `red(${expression})`;\n current = current.base;\n index += 1;\n }\n break;\n case TypeID.tuple:\n expression = `pr${step}(${expression})`;\n current = current.factors[step - 1];\n index += 1;\n break;\n default:\n return prefix + expression;\n }\n }\n\n return prefix + expression;\n}\n\nfunction formatPathText(path: TypePath): string {\n return path.map(step => String(step)).join('.');\n}\n"],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -3,8 +3,10 @@
|
|
|
3
3
|
*/
|
|
4
4
|
|
|
5
5
|
import { type Graph } from '../graph';
|
|
6
|
+
import { type ExpressionType } from '../rslang';
|
|
6
7
|
import { labelType } from '../rslang/labels';
|
|
7
8
|
|
|
9
|
+
import { type BasicTextCheckFields } from './rsform-api/types';
|
|
8
10
|
import { type Constituenta, type CstType } from './rsform';
|
|
9
11
|
import { isBasicConcept, isLogical } from './rsform-api';
|
|
10
12
|
import { EvalStatus } from './rsmodel';
|
|
@@ -41,8 +43,11 @@ export interface CstDiagnostic {
|
|
|
41
43
|
params?: readonly string[];
|
|
42
44
|
}
|
|
43
45
|
|
|
44
|
-
/** Whether
|
|
45
|
-
export function hasCstDiagnostic(
|
|
46
|
+
/** Whether an item has a schema/model diagnostic with the given code. */
|
|
47
|
+
export function hasCstDiagnostic(
|
|
48
|
+
cst: { diagnostics?: readonly CstDiagnostic[] | null },
|
|
49
|
+
code: RSDiagnosticCode
|
|
50
|
+
): boolean {
|
|
46
51
|
return cst.diagnostics?.some(item => item.code === code) ?? false;
|
|
47
52
|
}
|
|
48
53
|
|
|
@@ -160,7 +165,13 @@ export function modelStatusCstDiagnostic(status: EvalStatus, cstType: CstType):
|
|
|
160
165
|
return { kind: DiagnosticKind.MODEL, code, params: [String(status)] };
|
|
161
166
|
}
|
|
162
167
|
|
|
163
|
-
function collectLocalSchemaDiagnostics(
|
|
168
|
+
function collectLocalSchemaDiagnostics(
|
|
169
|
+
cst: BasicTextCheckFields & {
|
|
170
|
+
is_type_mismatch: boolean;
|
|
171
|
+
typification_manual: string;
|
|
172
|
+
analysis: { type: ExpressionType | null };
|
|
173
|
+
}
|
|
174
|
+
): CstDiagnostic[] {
|
|
164
175
|
const result: CstDiagnostic[] = [];
|
|
165
176
|
if (cst.is_type_mismatch) {
|
|
166
177
|
result.push({
|
|
@@ -180,13 +191,13 @@ function collectLocalSchemaDiagnostics(cst: Constituenta): CstDiagnostic[] {
|
|
|
180
191
|
return result;
|
|
181
192
|
}
|
|
182
193
|
|
|
183
|
-
function detectGroupedAliasDiagnostics(
|
|
184
|
-
items:
|
|
194
|
+
function detectGroupedAliasDiagnostics<T extends { id: number }>(
|
|
195
|
+
items: readonly T[],
|
|
185
196
|
resolveAlias: (id: number) => string,
|
|
186
|
-
groupKey: (cst:
|
|
197
|
+
groupKey: (cst: T) => string | undefined,
|
|
187
198
|
code: RSDiagnosticCode
|
|
188
199
|
): Map<number, CstDiagnostic> {
|
|
189
|
-
const groups = new Map<string,
|
|
200
|
+
const groups = new Map<string, T[]>();
|
|
190
201
|
for (const cst of items) {
|
|
191
202
|
const key = groupKey(cst);
|
|
192
203
|
if (!key) {
|
|
@@ -218,7 +229,7 @@ function detectGroupedAliasDiagnostics(
|
|
|
218
229
|
}
|
|
219
230
|
|
|
220
231
|
function detectHomonymDiagnostics(
|
|
221
|
-
items:
|
|
232
|
+
items: readonly { id: number; term_resolved: string }[],
|
|
222
233
|
resolveAlias: (id: number) => string
|
|
223
234
|
): Map<number, CstDiagnostic> {
|
|
224
235
|
return detectGroupedAliasDiagnostics(
|
|
@@ -233,7 +244,7 @@ function detectHomonymDiagnostics(
|
|
|
233
244
|
}
|
|
234
245
|
|
|
235
246
|
function detectFormalDuplicateDiagnostics(
|
|
236
|
-
items:
|
|
247
|
+
items: readonly { id: number }[],
|
|
237
248
|
resolveAlias: (id: number) => string,
|
|
238
249
|
normalizedDefinitions: ReadonlyMap<number, string>
|
|
239
250
|
): Map<number, CstDiagnostic> {
|
package/src/library/oss-api.ts
CHANGED
|
@@ -10,6 +10,7 @@ import { extractBases } from '../rslang/semantic/typification-api';
|
|
|
10
10
|
import { type LibraryItem } from './library';
|
|
11
11
|
import { NodeType, type OperationSchema, type SubstitutionErrorDescription, SubstitutionErrorType } from './oss';
|
|
12
12
|
import { type Constituenta, CstClass, CstType, type RSForm, type Substitution } from './rsform';
|
|
13
|
+
import { type FormalOrderFields } from './rsform-api';
|
|
13
14
|
|
|
14
15
|
const STARTING_SUB_INDEX = 900; // max semantic index for starting substitution
|
|
15
16
|
|
|
@@ -387,7 +388,10 @@ export class SubstitutionValidator {
|
|
|
387
388
|
return result;
|
|
388
389
|
}
|
|
389
390
|
|
|
390
|
-
private checkEqual(
|
|
391
|
+
private checkEqual(
|
|
392
|
+
left: FormalOrderFields & { schema: number },
|
|
393
|
+
right: FormalOrderFields & { schema: number }
|
|
394
|
+
): boolean {
|
|
391
395
|
const schema1 = this.schemaByID.get(left.schema)!;
|
|
392
396
|
const inputs1 = schema1.graph.at(left.id)!.inputs;
|
|
393
397
|
if (inputs1.some(id => !this.constituents.has(id))) {
|
|
@@ -7,10 +7,10 @@ import { type AliasMapping, applyAliasMapping, applyTypificationMapping } from '
|
|
|
7
7
|
import { type ArgumentValue, CstType, type RSForm } from '../rsform';
|
|
8
8
|
|
|
9
9
|
import { getCstTypePrefix } from './cst-type';
|
|
10
|
-
import { type
|
|
10
|
+
import { type AliasTypedFields } from './types';
|
|
11
11
|
|
|
12
|
-
/** Fields
|
|
13
|
-
export interface
|
|
12
|
+
/** Fields updated in place by alias mapping. */
|
|
13
|
+
export interface MappableFields {
|
|
14
14
|
alias: string;
|
|
15
15
|
definition_formal: string;
|
|
16
16
|
typification_manual: string;
|
|
@@ -77,7 +77,7 @@ export function generateAlias(type: CstType, schema: RSForm, takenAliases: strin
|
|
|
77
77
|
* Remap formal expressions and terminological entity references in constituent fields.
|
|
78
78
|
* Mutates each element of `items` in place; pass owned or cloned data only.
|
|
79
79
|
*/
|
|
80
|
-
export function applyMappingToConstituents<T extends
|
|
80
|
+
export function applyMappingToConstituents<T extends MappableFields>(
|
|
81
81
|
items: T[],
|
|
82
82
|
mapping: AliasMapping,
|
|
83
83
|
changeAliases: boolean
|
|
@@ -94,7 +94,7 @@ export function applyMappingToConstituents<T extends ConstituentaMappableFields>
|
|
|
94
94
|
}
|
|
95
95
|
|
|
96
96
|
/** Highest numeric alias suffix for {@link type} among {@link items} (0 when none). */
|
|
97
|
-
export function maxAliasIndex(items: readonly
|
|
97
|
+
export function maxAliasIndex(items: readonly AliasTypedFields[], type: CstType): number {
|
|
98
98
|
const prefix = getCstTypePrefix(type);
|
|
99
99
|
return items.reduce((max, cst) => {
|
|
100
100
|
if (cst.cst_type !== type) {
|
|
@@ -109,7 +109,7 @@ export function maxAliasIndex(items: readonly AliasTypedConstituenta[], type: Cs
|
|
|
109
109
|
* Build alias → new-alias mapping that renumbers each type sequentially in list order.
|
|
110
110
|
* Matches backend {@code RSFormCached.reset_aliases}.
|
|
111
111
|
*/
|
|
112
|
-
export function buildSequentialAliasMapping(items: readonly
|
|
112
|
+
export function buildSequentialAliasMapping(items: readonly AliasTypedFields[]): AliasMapping {
|
|
113
113
|
const counts: Record<string, number> = {};
|
|
114
114
|
for (const value of Object.values(CstType)) {
|
|
115
115
|
counts[value] = 1;
|
|
@@ -130,8 +130,8 @@ export function buildSequentialAliasMapping(items: readonly AliasTypedConstituen
|
|
|
130
130
|
* Returns an empty mapping when the receiver has no items (aliases kept as-is).
|
|
131
131
|
*/
|
|
132
132
|
export function allocateImportAliases(
|
|
133
|
-
receiver: readonly
|
|
134
|
-
source: readonly
|
|
133
|
+
receiver: readonly AliasTypedFields[],
|
|
134
|
+
source: readonly AliasTypedFields[]
|
|
135
135
|
): AliasMapping {
|
|
136
136
|
if (receiver.length === 0) {
|
|
137
137
|
return {};
|
|
@@ -4,7 +4,9 @@
|
|
|
4
4
|
|
|
5
5
|
import { TypeClass, TypeID, type Typification } from '../../rslang';
|
|
6
6
|
import { type EchelonFunctional, isTypification } from '../../rslang/semantic/typification';
|
|
7
|
-
import {
|
|
7
|
+
import { CstClass, CstType } from '../rsform';
|
|
8
|
+
|
|
9
|
+
import { type StructureCapableFields } from './types';
|
|
8
10
|
|
|
9
11
|
/** Record of {@link CstType} prefixes. */
|
|
10
12
|
const CST_TYPE_PREFIX: Record<CstType, string> = {
|
|
@@ -58,8 +60,8 @@ export function inferClass(type: CstType, isTemplate: boolean = false): CstClass
|
|
|
58
60
|
return CST_TYPE_TO_CLASS[type];
|
|
59
61
|
}
|
|
60
62
|
|
|
61
|
-
/** Check if
|
|
62
|
-
export function isTemplateCst(cst:
|
|
63
|
+
/** Check if item type is a template or a category. */
|
|
64
|
+
export function isTemplateCst(cst: { cst_type: CstType }): boolean {
|
|
63
65
|
return cst.cst_type === CstType.FUNCTION || cst.cst_type === CstType.PREDICATE || cst.cst_type === CstType.STATEMENT;
|
|
64
66
|
}
|
|
65
67
|
|
|
@@ -177,8 +179,8 @@ export function typeClassForCstType(cstType: CstType): TypeClass {
|
|
|
177
179
|
}
|
|
178
180
|
}
|
|
179
181
|
|
|
180
|
-
/** Evaluate if
|
|
181
|
-
export function canProduceStructure(cst:
|
|
182
|
+
/** Evaluate if an item can be used to produce structure. */
|
|
183
|
+
export function canProduceStructure(cst: StructureCapableFields): boolean {
|
|
182
184
|
switch (cst.cst_type) {
|
|
183
185
|
case CstType.NOMINAL:
|
|
184
186
|
case CstType.BASE:
|
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
import { type AstNode } from '../../parsing';
|
|
6
6
|
import { ValueClass } from '../../rslang';
|
|
7
7
|
import { generateExpressionFromAst, parseRSLangExpression } from '../../rslang/api';
|
|
8
|
-
import { type ArgumentValue,
|
|
8
|
+
import { type ArgumentValue, CstStatus, CstType } from '../rsform';
|
|
9
9
|
|
|
10
10
|
import { isBasicConcept } from './cst-type';
|
|
11
11
|
|
|
@@ -61,8 +61,8 @@ export function inferTemplate(expression: string): boolean {
|
|
|
61
61
|
return (match && match?.length > 0) ?? false;
|
|
62
62
|
}
|
|
63
63
|
|
|
64
|
-
/** Apply filter based on start
|
|
65
|
-
export function applyFilterCategory(start:
|
|
64
|
+
/** Apply filter based on start item type within an ordered list. */
|
|
65
|
+
export function applyFilterCategory<T extends { cst_type: CstType }>(start: T, items: readonly T[]): T[] {
|
|
66
66
|
const startIndex = items.indexOf(start);
|
|
67
67
|
if (startIndex === -1) {
|
|
68
68
|
return [];
|
|
@@ -4,9 +4,9 @@ import { CstType } from '../rsform';
|
|
|
4
4
|
|
|
5
5
|
import { buildFormalDependencyGraph, restoreConstituentOrder } from './formal-graph';
|
|
6
6
|
import { computeSemanticRelations } from './semantic-relations';
|
|
7
|
-
import { type
|
|
7
|
+
import { type FormalOrderFields } from './types';
|
|
8
8
|
|
|
9
|
-
function cst(id: number, alias: string, cst_type: CstType, definition_formal = ''):
|
|
9
|
+
function cst(id: number, alias: string, cst_type: CstType, definition_formal = ''): FormalOrderFields {
|
|
10
10
|
return { id, alias, cst_type, definition_formal };
|
|
11
11
|
}
|
|
12
12
|
|
|
@@ -7,13 +7,13 @@ import { extractGlobals } from '../../rslang/api';
|
|
|
7
7
|
import { CstType } from '../rsform';
|
|
8
8
|
|
|
9
9
|
import { computeSemanticRelations } from './semantic-relations';
|
|
10
|
-
import { type
|
|
10
|
+
import { type FormalOrderFields, type SemanticRelations } from './types';
|
|
11
11
|
|
|
12
12
|
/**
|
|
13
13
|
* Build the formal dependency graph: supplier → dependent.
|
|
14
14
|
* Matches backend {@code RSForm.graph_formal}.
|
|
15
15
|
*/
|
|
16
|
-
export function buildFormalDependencyGraph(items: readonly
|
|
16
|
+
export function buildFormalDependencyGraph(items: readonly FormalOrderFields[]): Graph<number> {
|
|
17
17
|
const graph = new Graph<number>();
|
|
18
18
|
const byAlias = new Map(items.map(cst => [cst.alias, cst]));
|
|
19
19
|
for (const cst of items) {
|
|
@@ -36,7 +36,7 @@ export function buildFormalDependencyGraph(items: readonly OrderableConstituenta
|
|
|
36
36
|
*
|
|
37
37
|
* One Kahn pass over the formal dependency graph.
|
|
38
38
|
*/
|
|
39
|
-
export function restoreConstituentOrder<T extends
|
|
39
|
+
export function restoreConstituentOrder<T extends FormalOrderFields>(
|
|
40
40
|
items: readonly T[],
|
|
41
41
|
graph: Graph<number> = buildFormalDependencyGraph(items),
|
|
42
42
|
relations: SemanticRelations = computeSemanticRelations(items, graph)
|
|
@@ -77,9 +77,7 @@ export function restoreConstituentOrder<T extends OrderableConstituenta>(
|
|
|
77
77
|
const pendingChildren: number[] = [];
|
|
78
78
|
|
|
79
79
|
function enqueueSticky(candidateIds: readonly number[]): void {
|
|
80
|
-
const sticky = candidateIds.filter(
|
|
81
|
-
childId => ready.has(childId) && !pendingChildren.includes(childId)
|
|
82
|
-
);
|
|
80
|
+
const sticky = candidateIds.filter(childId => ready.has(childId) && !pendingChildren.includes(childId));
|
|
83
81
|
sticky.sort((left, right) => (rank.get(left) ?? 0) - (rank.get(right) ?? 0));
|
|
84
82
|
pendingChildren.push(...sticky);
|
|
85
83
|
}
|
|
@@ -138,7 +136,7 @@ export function restoreConstituentOrder<T extends OrderableConstituenta>(
|
|
|
138
136
|
return result;
|
|
139
137
|
}
|
|
140
138
|
|
|
141
|
-
function kernelPriority<T extends
|
|
139
|
+
function kernelPriority<T extends FormalOrderFields>(
|
|
142
140
|
items: readonly T[],
|
|
143
141
|
graph: Graph<number>,
|
|
144
142
|
parentOf: Map<number, number>
|
|
@@ -176,9 +174,7 @@ function kernelPriority<T extends OrderableConstituenta>(
|
|
|
176
174
|
const parentId = parentOf.get(cst.id) ?? cst.id;
|
|
177
175
|
const parent = byId.get(parentId);
|
|
178
176
|
return (
|
|
179
|
-
cst.cst_type === CstType.STRUCTURED ||
|
|
180
|
-
cst.cst_type === CstType.AXIOM ||
|
|
181
|
-
parent?.cst_type === CstType.STRUCTURED
|
|
177
|
+
cst.cst_type === CstType.STRUCTURED || cst.cst_type === CstType.AXIOM || parent?.cst_type === CstType.STRUCTURED
|
|
182
178
|
);
|
|
183
179
|
})
|
|
184
180
|
.map(cst => cst.id);
|
|
@@ -8,8 +8,8 @@ export {
|
|
|
8
8
|
applyMappingToConstituents,
|
|
9
9
|
argumentValuesToMapping,
|
|
10
10
|
buildSequentialAliasMapping,
|
|
11
|
-
type ConstituentaMappableFields,
|
|
12
11
|
generateAlias,
|
|
12
|
+
type MappableFields,
|
|
13
13
|
maxAliasIndex,
|
|
14
14
|
removeAliasReference,
|
|
15
15
|
validateAliasFormat,
|
|
@@ -40,7 +40,7 @@ export {
|
|
|
40
40
|
type InlineSynthesisInput,
|
|
41
41
|
type InlineSynthesisResult,
|
|
42
42
|
sortItemsForInlineSynthesis,
|
|
43
|
-
type
|
|
43
|
+
type SynthesizableFields
|
|
44
44
|
} from './synthesis';
|
|
45
45
|
export {
|
|
46
46
|
buildDefinitionReferenceGraph,
|
|
@@ -50,4 +50,19 @@ export {
|
|
|
50
50
|
type TextChangeOptions
|
|
51
51
|
} from './text-resolution';
|
|
52
52
|
export { insertItemAfter, moveIdsInOrder, reorderItemsByIds } from './transforms';
|
|
53
|
-
export type {
|
|
53
|
+
export type {
|
|
54
|
+
AliasTypedFields,
|
|
55
|
+
BasicTextCheckFields,
|
|
56
|
+
DescribableFields,
|
|
57
|
+
DiagnosticSourceFields,
|
|
58
|
+
FormalOrderFields,
|
|
59
|
+
ModelEvalFields,
|
|
60
|
+
SchemaIssueFields,
|
|
61
|
+
SearchableFields,
|
|
62
|
+
SemanticRelations,
|
|
63
|
+
SpawnPathFields,
|
|
64
|
+
StructureCapableFields,
|
|
65
|
+
TemplateParamSourceFields,
|
|
66
|
+
TemplateSourceFields,
|
|
67
|
+
TextResolvableFields
|
|
68
|
+
} from './types';
|
|
@@ -8,16 +8,13 @@ import { CstType } from '../rsform';
|
|
|
8
8
|
|
|
9
9
|
import { isBaseSet, isFunctional } from './cst-type';
|
|
10
10
|
import { inferTemplate } from './expression';
|
|
11
|
-
import { type
|
|
11
|
+
import { type FormalOrderFields, type SemanticRelations } from './types';
|
|
12
12
|
|
|
13
13
|
/**
|
|
14
14
|
* Infer semantic parent/children used for clustering during restore order.
|
|
15
15
|
* Port of backend {@code SemanticInfo}.
|
|
16
16
|
*/
|
|
17
|
-
export function computeSemanticRelations(
|
|
18
|
-
items: readonly OrderableConstituenta[],
|
|
19
|
-
graph: Graph<number>
|
|
20
|
-
): SemanticRelations {
|
|
17
|
+
export function computeSemanticRelations(items: readonly FormalOrderFields[], graph: Graph<number>): SemanticRelations {
|
|
21
18
|
const byId = new Map(items.map(cst => [cst.id, cst]));
|
|
22
19
|
const byAlias = new Map(items.map(cst => [cst.alias, cst]));
|
|
23
20
|
const isTemplate = new Map<number, boolean>();
|
|
@@ -41,7 +38,7 @@ export function computeSemanticRelations(
|
|
|
41
38
|
return !isFunctional(base.cst_type) || splitTemplateDefinition(base.definition_formal).head !== head;
|
|
42
39
|
}
|
|
43
40
|
|
|
44
|
-
function extractSources(target:
|
|
41
|
+
function extractSources(target: FormalOrderFields): Set<number> {
|
|
45
42
|
const sources = new Set<number>();
|
|
46
43
|
if (!isFunctional(target.cst_type)) {
|
|
47
44
|
for (const parentId of graph.at(target.id)?.inputs ?? []) {
|
|
@@ -76,7 +73,7 @@ export function computeSemanticRelations(
|
|
|
76
73
|
return sources;
|
|
77
74
|
}
|
|
78
75
|
|
|
79
|
-
function inferSimple(target:
|
|
76
|
+
function inferSimple(target: FormalOrderFields): boolean {
|
|
80
77
|
if (target.cst_type === CstType.STRUCTURED || isBaseSet(target.cst_type)) {
|
|
81
78
|
return false;
|
|
82
79
|
}
|
|
@@ -4,12 +4,13 @@
|
|
|
4
4
|
|
|
5
5
|
import { TypeID, type Typification, ValueClass } from '../../rslang';
|
|
6
6
|
import { hasCstDiagnostic, RSDiagnosticCode } from '../diagnostics';
|
|
7
|
-
import {
|
|
7
|
+
import { CstStatus, CstType, type RSForm, type RSFormStats } from '../rsform';
|
|
8
8
|
|
|
9
9
|
import { isBasicConcept, isLogical } from './cst-type';
|
|
10
|
+
import { type BasicTextCheckFields, type SchemaIssueFields, type StructureCapableFields } from './types';
|
|
10
11
|
|
|
11
|
-
/** Checks if
|
|
12
|
-
export function isSchemaIssue(cst:
|
|
12
|
+
/** Checks if an item is a schema issue. */
|
|
13
|
+
export function isSchemaIssue(cst: SchemaIssueFields): boolean {
|
|
13
14
|
return (
|
|
14
15
|
(cst.diagnostics?.length ?? 0) > 0 || cst.status === CstStatus.INCORRECT || cst.status === CstStatus.INCALCULABLE
|
|
15
16
|
);
|
|
@@ -125,7 +126,7 @@ export function calculateSchemaStats(target: RSForm): RSFormStats {
|
|
|
125
126
|
return stats;
|
|
126
127
|
}
|
|
127
128
|
|
|
128
|
-
function calculateStepComplexity(cst:
|
|
129
|
+
function calculateStepComplexity(cst: StructureCapableFields): number {
|
|
129
130
|
if (cst.cst_type === CstType.AXIOM || cst.cst_type === CstType.NOMINAL || !isBasicConcept(cst.cst_type)) {
|
|
130
131
|
return 0;
|
|
131
132
|
}
|
|
@@ -162,7 +163,7 @@ function calculateTypificationComplexity(type: Typification): number {
|
|
|
162
163
|
}
|
|
163
164
|
|
|
164
165
|
/** Non-logical basic concept missing convention and/or resolved term (trimmed). */
|
|
165
|
-
function isMissingBasicText(cst:
|
|
166
|
+
function isMissingBasicText(cst: BasicTextCheckFields): boolean {
|
|
166
167
|
if (!isBasicConcept(cst.cst_type) || isLogical(cst.cst_type)) {
|
|
167
168
|
return false;
|
|
168
169
|
}
|
|
@@ -7,6 +7,8 @@ import { isTypification } from '../../rslang/semantic/typification';
|
|
|
7
7
|
import { applyPath } from '../../rslang/semantic/typification-api';
|
|
8
8
|
import { type Constituenta, type RSForm } from '../rsform';
|
|
9
9
|
|
|
10
|
+
import { type SpawnPathFields, type StructureCapableFields } from './types';
|
|
11
|
+
|
|
10
12
|
/**
|
|
11
13
|
* Id to pass as `insert_after` when creating a new {@link Constituenta} spawned by `targetId`:
|
|
12
14
|
* after the last existing child of that spawner, or after the spawner itself if none.
|
|
@@ -21,8 +23,8 @@ export function inferNewSpawnPosition(schema: RSForm, targetId: number): number
|
|
|
21
23
|
return last ?? targetId;
|
|
22
24
|
}
|
|
23
25
|
|
|
24
|
-
/** Finds
|
|
25
|
-
export function findCstByStructure(schema: RSForm, target:
|
|
26
|
+
/** Finds schema item by absolute structure path under `targetId`. */
|
|
27
|
+
export function findCstByStructure(schema: RSForm, target: { id: number }, path: TypePath): Constituenta | null {
|
|
26
28
|
const byId = schema.cstByID ?? new Map(schema.items.map(item => [item.id, item]));
|
|
27
29
|
for (const cst of schema.items) {
|
|
28
30
|
if (!cst.spawner_path) {
|
|
@@ -36,8 +38,12 @@ export function findCstByStructure(schema: RSForm, target: Constituenta, path: T
|
|
|
36
38
|
return null;
|
|
37
39
|
}
|
|
38
40
|
|
|
39
|
-
/** Retrieves name for piece of target
|
|
40
|
-
export function getStructureName(
|
|
41
|
+
/** Retrieves name for piece of target structure. */
|
|
42
|
+
export function getStructureName(
|
|
43
|
+
schema: RSForm,
|
|
44
|
+
target: StructureCapableFields & { id: number },
|
|
45
|
+
path: TypePath
|
|
46
|
+
): string {
|
|
41
47
|
const representation = findCstByStructure(schema, target, path);
|
|
42
48
|
if (representation) {
|
|
43
49
|
return `${representation.alias}: ${representation.term_resolved}`;
|
|
@@ -56,9 +62,9 @@ export function getStructureName(schema: RSForm, target: Constituenta, path: Typ
|
|
|
56
62
|
}
|
|
57
63
|
|
|
58
64
|
function resolveAbsoluteSpawnerPath(
|
|
59
|
-
cst:
|
|
65
|
+
cst: SpawnPathFields,
|
|
60
66
|
targetId: number,
|
|
61
|
-
byId: Map<number,
|
|
67
|
+
byId: Map<number, SpawnPathFields>
|
|
62
68
|
): TypePath | null {
|
|
63
69
|
if (!cst.spawner_path || cst.spawner == null) {
|
|
64
70
|
return null;
|
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
import { type AliasMapping } from '../../rslang/api';
|
|
6
6
|
import { type Attribution, type Substitution } from '../rsform';
|
|
7
7
|
|
|
8
|
-
import { applyMappingToConstituents, type
|
|
8
|
+
import { applyMappingToConstituents, type MappableFields } from './alias';
|
|
9
9
|
import { remapAttributionsUnderSubstitution } from './attribution';
|
|
10
10
|
|
|
11
11
|
/** Result of applying substitutions to a schema fragment. */
|
|
@@ -21,7 +21,7 @@ export interface SubstitutionResult<T> {
|
|
|
21
21
|
* Apply constituenta substitutions: remap attributions, drop originals, rewrite aliases in survivors.
|
|
22
22
|
* Does not resolve texts — call {@link resolveAllConstituentTexts} afterwards.
|
|
23
23
|
*/
|
|
24
|
-
export function applyConstituentSubstitutions<T extends
|
|
24
|
+
export function applyConstituentSubstitutions<T extends MappableFields & { id: number; alias: string }>(
|
|
25
25
|
items: readonly T[],
|
|
26
26
|
attributions: readonly Attribution[],
|
|
27
27
|
substitutions: readonly Substitution[]
|
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
import { describe, expect, it } from 'vitest';
|
|
2
2
|
|
|
3
|
-
import {
|
|
3
|
+
import { LibraryItemType } from '../library';
|
|
4
|
+
import { CstType, type RSForm } from '../rsform';
|
|
4
5
|
|
|
5
|
-
import { inlineSynthesis } from './synthesis';
|
|
6
|
+
import { inlineSynthesis, sortItemsForInlineSynthesis } from './synthesis';
|
|
6
7
|
|
|
7
8
|
function item(partial: {
|
|
8
9
|
id: number;
|
|
@@ -124,3 +125,33 @@ describe('inlineSynthesis', () => {
|
|
|
124
125
|
expect(result.items).not.toBe(receiver);
|
|
125
126
|
});
|
|
126
127
|
});
|
|
128
|
+
|
|
129
|
+
describe('sortItemsForInlineSynthesis', () => {
|
|
130
|
+
function libraryItem(partial: { id: number; location: string; owner: number | null; visible: boolean }) {
|
|
131
|
+
return {
|
|
132
|
+
id: partial.id,
|
|
133
|
+
item_type: LibraryItemType.RSFORM,
|
|
134
|
+
alias: `S${partial.id}`,
|
|
135
|
+
title: `Item ${partial.id}`,
|
|
136
|
+
description: '',
|
|
137
|
+
visible: partial.visible,
|
|
138
|
+
read_only: false,
|
|
139
|
+
location: partial.location,
|
|
140
|
+
access_policy: 'public' as const,
|
|
141
|
+
time_create: '',
|
|
142
|
+
time_update: '',
|
|
143
|
+
owner: partial.owner
|
|
144
|
+
};
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
it('orders by location, then owner+visible, then visible, then rest', () => {
|
|
148
|
+
const receiver = { location: '/a', owner: 1 } as RSForm;
|
|
149
|
+
const sameLocation = libraryItem({ id: 1, location: '/a', owner: 99, visible: false });
|
|
150
|
+
const sameOwnerVisible = libraryItem({ id: 2, location: '/b', owner: 1, visible: true });
|
|
151
|
+
const otherVisible = libraryItem({ id: 3, location: '/c', owner: 2, visible: true });
|
|
152
|
+
const hidden = libraryItem({ id: 4, location: '/d', owner: 2, visible: false });
|
|
153
|
+
|
|
154
|
+
const sorted = sortItemsForInlineSynthesis(receiver, [hidden, otherVisible, sameOwnerVisible, sameLocation]);
|
|
155
|
+
expect(sorted.map(item => item.id)).toEqual([1, 2, 3, 4]);
|
|
156
|
+
});
|
|
157
|
+
});
|
|
@@ -10,23 +10,23 @@ import { type AliasMapping } from '../../rslang/api';
|
|
|
10
10
|
import { type LibraryItem } from '../library';
|
|
11
11
|
import { type Attribution, type CstType, type RSForm, type Substitution } from '../rsform';
|
|
12
12
|
|
|
13
|
-
import { allocateImportAliases, applyMappingToConstituents, type
|
|
13
|
+
import { allocateImportAliases, applyMappingToConstituents, type MappableFields } from './alias';
|
|
14
14
|
import { importAttributions } from './attribution';
|
|
15
15
|
import { applyConstituentSubstitutions, remapSubstitutionsAfterImport } from './substitution';
|
|
16
16
|
import { resolveAllConstituentTexts } from './text-resolution';
|
|
17
|
-
import { type
|
|
17
|
+
import { type AliasTypedFields, type TextResolvableFields } from './types';
|
|
18
18
|
|
|
19
|
-
/**
|
|
20
|
-
export type
|
|
21
|
-
|
|
22
|
-
|
|
19
|
+
/** Field intersection required for embedding / synthesis transforms. */
|
|
20
|
+
export type SynthesizableFields = MappableFields &
|
|
21
|
+
TextResolvableFields &
|
|
22
|
+
AliasTypedFields & {
|
|
23
23
|
id: number;
|
|
24
24
|
alias: string;
|
|
25
25
|
cst_type: CstType;
|
|
26
26
|
};
|
|
27
27
|
|
|
28
28
|
/** Input for {@link inlineSynthesis}. */
|
|
29
|
-
export interface InlineSynthesisInput<T extends
|
|
29
|
+
export interface InlineSynthesisInput<T extends SynthesizableFields> {
|
|
30
30
|
/** Receiver schema constituents (order preserved; imports append). */
|
|
31
31
|
receiverItems: readonly T[];
|
|
32
32
|
/** Receiver attributions (default empty). */
|
|
@@ -49,7 +49,7 @@ export interface InlineSynthesisInput<T extends SynthesizableConstituenta> {
|
|
|
49
49
|
}
|
|
50
50
|
|
|
51
51
|
/** Result of {@link inlineSynthesis}. */
|
|
52
|
-
export interface InlineSynthesisResult<T extends
|
|
52
|
+
export interface InlineSynthesisResult<T extends SynthesizableFields> {
|
|
53
53
|
items: T[];
|
|
54
54
|
attributions: Attribution[];
|
|
55
55
|
/** Updated next-id after inserts. */
|
|
@@ -71,7 +71,7 @@ export interface InlineSynthesisResult<T extends SynthesizableConstituenta> {
|
|
|
71
71
|
* Resolves term/definition entity references on the result.
|
|
72
72
|
* Does not mutate inputs.
|
|
73
73
|
*/
|
|
74
|
-
export function inlineSynthesis<T extends
|
|
74
|
+
export function inlineSynthesis<T extends SynthesizableFields>(
|
|
75
75
|
input: InlineSynthesisInput<T>
|
|
76
76
|
): InlineSynthesisResult<T> {
|
|
77
77
|
const sourceItems = input.sourceItems;
|
|
@@ -147,19 +147,23 @@ export function inlineSynthesis<T extends SynthesizableConstituenta>(
|
|
|
147
147
|
/** Sorts library items relevant for schema embedding with specified {@link RSForm}. */
|
|
148
148
|
export function sortItemsForInlineSynthesis(receiver: RSForm, items: readonly LibraryItem[]): LibraryItem[] {
|
|
149
149
|
const result = items.filter(item => item.location === receiver.location);
|
|
150
|
+
const included = new Set(result);
|
|
150
151
|
for (const item of items) {
|
|
151
|
-
if (item.visible && item.owner === receiver.owner && !
|
|
152
|
+
if (item.visible && item.owner === receiver.owner && !included.has(item)) {
|
|
152
153
|
result.push(item);
|
|
154
|
+
included.add(item);
|
|
153
155
|
}
|
|
154
156
|
}
|
|
155
157
|
for (const item of items) {
|
|
156
|
-
if (item.visible && !
|
|
158
|
+
if (item.visible && !included.has(item)) {
|
|
157
159
|
result.push(item);
|
|
160
|
+
included.add(item);
|
|
158
161
|
}
|
|
159
162
|
}
|
|
160
163
|
for (const item of items) {
|
|
161
|
-
if (!
|
|
164
|
+
if (!included.has(item)) {
|
|
162
165
|
result.push(item);
|
|
166
|
+
included.add(item);
|
|
163
167
|
}
|
|
164
168
|
}
|
|
165
169
|
return result;
|
|
@@ -1,11 +1,9 @@
|
|
|
1
1
|
import { describe, expect, it } from 'vitest';
|
|
2
2
|
|
|
3
3
|
import { resolveConstituentTextChange } from './text-resolution';
|
|
4
|
-
import { type
|
|
4
|
+
import { type TextResolvableFields } from './types';
|
|
5
5
|
|
|
6
|
-
function row(
|
|
7
|
-
data: Partial<ResolvableConstituenta> & Pick<ResolvableConstituenta, 'alias' | 'id'>
|
|
8
|
-
): ResolvableConstituenta {
|
|
6
|
+
function row(data: Partial<TextResolvableFields> & Pick<TextResolvableFields, 'alias' | 'id'>): TextResolvableFields {
|
|
9
7
|
return {
|
|
10
8
|
id: data.id,
|
|
11
9
|
alias: data.alias,
|