@rsconcept/domain 2.3.0 → 3.0.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.
Files changed (104) hide show
  1. package/dist/{analyzer-fNhkwO-6.d.ts → analyzer-CzFaWR7w.d.ts} +4 -4
  2. package/dist/{api-Bf0f_uiI.d.ts → api-DgecYHjR.d.ts} +5 -3
  3. package/dist/{arguments-extractor-ngatANBI.d.ts → arguments-extractor-CXWRT5Ou.d.ts} +4 -4
  4. package/dist/{ast-C8sIpKdL.d.ts → ast-D-D6Rq3T.d.ts} +2 -3
  5. package/dist/{ast-annotations-CiIx8qBM.d.ts → ast-annotations-x4PJ_Lhc.d.ts} +4 -4
  6. package/dist/{calculator-DE89LtIM.d.ts → calculator-uPaTV3hc.d.ts} +5 -5
  7. package/dist/cctext/language-api.d.ts +0 -1
  8. package/dist/{diagnostics-CljEzVBV.js → diagnostics-D1Cp21nP.js} +36 -13
  9. package/dist/diagnostics-D1Cp21nP.js.map +1 -0
  10. package/dist/{diagnostics-Dac5sJhO.d.ts → diagnostics-DKyMf6q-.d.ts} +24 -8
  11. package/dist/{expression-generator-CoucLIkE.d.ts → expression-generator-CADzBw-C.d.ts} +3 -2
  12. package/dist/graph/index.d.ts +1 -0
  13. package/dist/index-CnuO4w8e.d.ts +13 -0
  14. package/dist/index-D5RahF1K.d.ts +2 -0
  15. package/dist/index-DCO4mxiO.d.ts +378 -0
  16. package/dist/index-DntDUXW1.d.ts +1 -0
  17. package/dist/index-x0_Y5uPV.d.ts +2 -0
  18. package/dist/index.d.ts +13 -13
  19. package/dist/index.js +1 -1
  20. package/dist/{lezer-tree-iS7LpLBJ.d.ts → lezer-tree-BQZqBT5A.d.ts} +1 -2
  21. package/dist/library/diagnostics.d.ts +1 -1
  22. package/dist/library/diagnostics.js +1 -1
  23. package/dist/library/index.d.ts +5 -5
  24. package/dist/library/index.js +1 -1
  25. package/dist/library/index.js.map +1 -1
  26. package/dist/library/oss-api.d.ts +11 -3
  27. package/dist/library/oss-api.js +45 -4
  28. package/dist/library/oss-api.js.map +1 -1
  29. package/dist/library/oss-layout-api.d.ts +0 -1
  30. package/dist/library/oss.d.ts +21 -16
  31. package/dist/library/oss.js +19 -13
  32. package/dist/library/oss.js.map +1 -1
  33. package/dist/library/rsengine.d.ts +6 -5
  34. package/dist/library/rsengine.js +1 -1
  35. package/dist/library/rsform-api/index.d.ts +2 -299
  36. package/dist/library/rsform-api/index.js +1 -1
  37. package/dist/library/rsform.d.ts +1 -1
  38. package/dist/library/rsmodel-api.d.ts +12 -7
  39. package/dist/library/rsmodel-api.js +6 -2
  40. package/dist/library/rsmodel-api.js.map +1 -1
  41. package/dist/library/rsmodel.d.ts +1 -1
  42. package/dist/library/structure-planner.d.ts +3 -3
  43. package/dist/library/structure-planner.js +1 -1
  44. package/dist/library/structure-planner.js.map +1 -1
  45. package/dist/{parser-Bwd8LxJ1.d.ts → parser-DkejtiOR.d.ts} +1 -2
  46. package/dist/parsing/ast.d.ts +1 -1
  47. package/dist/parsing/index.d.ts +3 -2
  48. package/dist/parsing/lezer-tree.d.ts +1 -1
  49. package/dist/rslang/api.d.ts +2 -2
  50. package/dist/rslang/ast-annotations.d.ts +1 -1
  51. package/dist/rslang/eval/calculator.d.ts +1 -1
  52. package/dist/rslang/eval/evaluation-cache.d.ts +3 -3
  53. package/dist/rslang/eval/evaluator.d.ts +3 -3
  54. package/dist/rslang/eval/value-api.d.ts +1 -1
  55. package/dist/rslang/eval/value.d.ts +1 -1
  56. package/dist/rslang/index.d.ts +11 -10
  57. package/dist/rslang/labels.d.ts +3 -3
  58. package/dist/rslang/parser/expression-generator.d.ts +1 -1
  59. package/dist/rslang/parser/normalize.d.ts +2 -1
  60. package/dist/rslang/parser/parser.d.ts +1 -1
  61. package/dist/rslang/parser/parser.terms.d.ts +1 -40
  62. package/dist/rslang/parser/syntax-errors/index.d.ts +3 -3
  63. package/dist/rslang/semantic/analyzer.d.ts +1 -1
  64. package/dist/rslang/semantic/arguments-extractor.d.ts +1 -1
  65. package/dist/rslang/semantic/type-auditor.d.ts +3 -3
  66. package/dist/rslang/semantic/typification-api.d.ts +1 -2
  67. package/dist/rslang/semantic/typification-parser.d.ts +1 -1
  68. package/dist/rslang/semantic/typification.d.ts +1 -1
  69. package/dist/rslang/semantic/value-auditor.d.ts +2 -2
  70. package/dist/rslang/typification-graph.d.ts +1 -1
  71. package/dist/shared/index.d.ts +1 -0
  72. package/dist/{typification-graph-BY_oGT82.d.ts → typification-graph-CSxDt18X.d.ts} +2 -3
  73. package/dist/{typification-9lNu9R4k.d.ts → typification-hWUoWCba.d.ts} +2 -1
  74. package/dist/{typification-parser-Dytsv9CI.d.ts → typification-parser-DFxj4JiQ.d.ts} +2 -3
  75. package/dist/{value-BduA_ZGp.d.ts → value-XpJOVzMP.d.ts} +2 -1
  76. package/dist/{value-api-CXLl_zg0.d.ts → value-api-Dw8UkwCD.d.ts} +3 -4
  77. package/package.json +8 -8
  78. package/src/library/diagnostics.ts +36 -11
  79. package/src/library/oss-api.test.ts +100 -5
  80. package/src/library/oss-api.ts +76 -6
  81. package/src/library/oss.ts +22 -16
  82. package/src/library/rsform-api/alias.ts +8 -8
  83. package/src/library/rsform-api/cst-type.ts +7 -5
  84. package/src/library/rsform-api/expression.ts +3 -3
  85. package/src/library/rsform-api/formal-graph.test.ts +2 -2
  86. package/src/library/rsform-api/formal-graph.ts +6 -10
  87. package/src/library/rsform-api/index.ts +18 -3
  88. package/src/library/rsform-api/semantic-relations.ts +4 -7
  89. package/src/library/rsform-api/stats.ts +6 -5
  90. package/src/library/rsform-api/structure.ts +12 -6
  91. package/src/library/rsform-api/substitution.ts +2 -2
  92. package/src/library/rsform-api/synthesis.test.ts +33 -2
  93. package/src/library/rsform-api/synthesis.ts +16 -12
  94. package/src/library/rsform-api/text-resolution.test.ts +2 -4
  95. package/src/library/rsform-api/text-resolution.ts +8 -8
  96. package/src/library/rsform-api/types.ts +89 -8
  97. package/src/library/rsmodel-api.ts +10 -5
  98. package/src/library/structure-planner.ts +6 -2
  99. package/src/library/template-instantiation.ts +11 -9
  100. package/dist/diagnostics-CljEzVBV.js.map +0 -1
  101. package/dist/index-BKZ67WMa.d.ts +0 -1
  102. package/dist/index-BVVgDSdq.d.ts +0 -1
  103. package/dist/index-DmtQKWjk.d.ts +0 -1
  104. package/dist/index-_6s0AX1B.d.ts +0 -1
@@ -7,9 +7,11 @@ import { type AliasMapping, applyAliasMapping, applyTypificationMapping, isSetTy
7
7
  import { labelType } from '../rslang/labels';
8
8
  import { extractBases } from '../rslang/semantic/typification-api';
9
9
 
10
+ import { formatDependencyCycle } from './diagnostics';
10
11
  import { type LibraryItem } from './library';
11
12
  import { NodeType, type OperationSchema, type SubstitutionErrorDescription, SubstitutionErrorType } from './oss';
12
13
  import { type Constituenta, CstClass, CstType, type RSForm, type Substitution } from './rsform';
14
+ import { type FormalOrderFields } from './rsform-api';
13
15
 
14
16
  const STARTING_SUB_INDEX = 900; // max semantic index for starting substitution
15
17
 
@@ -100,7 +102,10 @@ export class SubstitutionValidator {
100
102
  if (!this.checkTypes()) {
101
103
  return false;
102
104
  }
103
- if (!this.checkCycles()) {
105
+ if (!this.checkTypificationCycles()) {
106
+ return false;
107
+ }
108
+ if (!this.checkDefinitionCycles()) {
104
109
  return false;
105
110
  }
106
111
  if (!this.checkSubstitutions()) {
@@ -237,7 +242,11 @@ export class SubstitutionValidator {
237
242
  return true;
238
243
  }
239
244
 
240
- private checkCycles(): boolean {
245
+ /**
246
+ * Detect cycles among base/constant sets implied by typifications of non-base
247
+ * constituents under the substitution table.
248
+ */
249
+ private checkTypificationCycles(): boolean {
241
250
  const graph = new Graph();
242
251
  for (const schema of this.schemas) {
243
252
  for (const cst of schema.items) {
@@ -285,6 +294,64 @@ export class SubstitutionValidator {
285
294
  return true;
286
295
  }
287
296
 
297
+ /**
298
+ * Detect logical cycles in formal definitions after applying the substitution table
299
+ * (e.g. D16 := F2[D15] with identification D15 → D16 yields D16 := F2[D16]).
300
+ */
301
+ private checkDefinitionCycles(): boolean {
302
+ const graph = new Graph();
303
+ for (const schema of this.schemas) {
304
+ for (const [id, node] of schema.graph.nodes) {
305
+ graph.addNode(id);
306
+ for (const output of node.outputs) {
307
+ graph.addEdge(id, output);
308
+ }
309
+ }
310
+ }
311
+
312
+ const deleted = new Map<number, number>();
313
+ for (const item of this.substitutions) {
314
+ deleted.set(item.original, item.substitution);
315
+ }
316
+ const resolve = (id: number): number => deleted.get(id) ?? id;
317
+
318
+ const result = new Graph();
319
+ for (const id of graph.nodes.keys()) {
320
+ if (!deleted.has(id)) {
321
+ result.addNode(id);
322
+ }
323
+ }
324
+ for (const substitutionId of deleted.values()) {
325
+ result.addNode(substitutionId);
326
+ }
327
+
328
+ for (const [id, node] of graph.nodes) {
329
+ for (const output of node.outputs) {
330
+ if (deleted.has(output)) {
331
+ continue;
332
+ }
333
+ result.addEdge(resolve(id), output);
334
+ }
335
+ }
336
+
337
+ const cycle = result.findCycle();
338
+ if (cycle !== null) {
339
+ const aliases = cycle.map(id => {
340
+ const cst = this.cstByID.get(id);
341
+ if (!cst) {
342
+ return String(id);
343
+ }
344
+ if (this.schemas.length > 1) {
345
+ const schema = this.schemaByID.get(cst.schema);
346
+ return schema ? `[${schema.alias}]-${cst.alias}` : cst.alias;
347
+ }
348
+ return cst.alias;
349
+ });
350
+ return this.reportError(SubstitutionErrorType.definitionCycle, [formatDependencyCycle(aliases)]);
351
+ }
352
+ return true;
353
+ }
354
+
288
355
  private checkSubstitutions(): boolean {
289
356
  const baseMappings = this.prepareBaseMappings();
290
357
  const typeMappings = this.calculateSubstituteMappings(baseMappings);
@@ -387,7 +454,10 @@ export class SubstitutionValidator {
387
454
  return result;
388
455
  }
389
456
 
390
- private checkEqual(left: Constituenta, right: Constituenta): boolean {
457
+ private checkEqual(
458
+ left: FormalOrderFields & { schema: number },
459
+ right: FormalOrderFields & { schema: number }
460
+ ): boolean {
391
461
  const schema1 = this.schemaByID.get(left.schema)!;
392
462
  const inputs1 = schema1.graph.at(left.id)!.inputs;
393
463
  if (inputs1.some(id => !this.constituents.has(id))) {
@@ -403,10 +473,10 @@ export class SubstitutionValidator {
403
473
  return expression1.replace(/\s+/g, '') === expression2.replace(/\s+/g, '');
404
474
  }
405
475
 
406
- private reportError(errorType: SubstitutionErrorType, params: string[]): boolean {
476
+ private reportError(code: SubstitutionErrorType, params: string[]): boolean {
407
477
  this.errors.push({
408
- errorType: errorType,
409
- params: params
478
+ code,
479
+ params
410
480
  });
411
481
  return false;
412
482
  }
@@ -4,6 +4,7 @@
4
4
 
5
5
  import { type Graph } from '../graph';
6
6
 
7
+ import { RSDiagnosticCode } from './diagnostics';
7
8
  import { type LibraryItem } from './library';
8
9
  import { type NodePosition, type OssLayout } from './oss-layout';
9
10
 
@@ -126,25 +127,30 @@ export interface OperationSchema extends LibraryItem {
126
127
  itemByNodeID: Map<string, OssItem>;
127
128
  }
128
129
 
129
- /** Represents substitution error description. */
130
+ /** Represents substitution error description (same code space as {@link RSDiagnosticCode}). */
130
131
  export interface SubstitutionErrorDescription {
131
- errorType: SubstitutionErrorType;
132
+ code: SubstitutionErrorType;
132
133
  params: string[];
133
134
  }
134
135
 
135
- /** Represents Substitution table error types. */
136
+ /**
137
+ * Substitution-table error codes — aliases into {@link RSDiagnosticCode}.
138
+ * Logical definition cycles reuse {@link RSDiagnosticCode.schemaDependencyCycle}.
139
+ */
136
140
  export const SubstitutionErrorType = {
137
- invalidIDs: 0,
138
- incorrectCst: 1,
139
- invalidClasses: 2,
140
- invalidBasic: 3,
141
- invalidConstant: 4,
142
- typificationCycle: 5,
143
- baseSubstitutionNotSet: 6,
144
- unequalTypification: 7,
145
- unequalExpressions: 8,
146
- unequalArgsCount: 9,
147
- unequalArgs: 10,
148
- invalidNominal: 11
149
- } as const;
141
+ invalidIDs: RSDiagnosticCode.substitutionInvalidIDs,
142
+ incorrectCst: RSDiagnosticCode.substitutionIncorrectCst,
143
+ invalidClasses: RSDiagnosticCode.substitutionInvalidClasses,
144
+ invalidBasic: RSDiagnosticCode.substitutionInvalidBasic,
145
+ invalidConstant: RSDiagnosticCode.substitutionInvalidConstant,
146
+ typificationCycle: RSDiagnosticCode.substitutionTypificationCycle,
147
+ baseSubstitutionNotSet: RSDiagnosticCode.substitutionBaseNotSet,
148
+ unequalTypification: RSDiagnosticCode.substitutionUnequalTypification,
149
+ unequalExpressions: RSDiagnosticCode.substitutionUnequalExpressions,
150
+ unequalArgsCount: RSDiagnosticCode.substitutionUnequalArgsCount,
151
+ unequalArgs: RSDiagnosticCode.substitutionUnequalArgs,
152
+ invalidNominal: RSDiagnosticCode.substitutionInvalidNominal,
153
+ /** Same code as constituent schema dependency cycle. */
154
+ definitionCycle: RSDiagnosticCode.schemaDependencyCycle
155
+ } as const satisfies Record<string, (typeof RSDiagnosticCode)[keyof typeof RSDiagnosticCode]>;
150
156
  export type SubstitutionErrorType = (typeof SubstitutionErrorType)[keyof typeof SubstitutionErrorType];
@@ -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 AliasTypedConstituenta } from './types';
10
+ import { type AliasTypedFields } from './types';
11
11
 
12
- /** Fields of {@link Constituenta} updated in place by alias mapping. */
13
- export interface ConstituentaMappableFields {
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 ConstituentaMappableFields>(
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 AliasTypedConstituenta[], type: CstType): number {
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 AliasTypedConstituenta[]): AliasMapping {
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 AliasTypedConstituenta[],
134
- source: readonly AliasTypedConstituenta[]
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 { type Constituenta, CstClass, CstType } from '../rsform';
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 {@link Constituenta} is a template or a category. */
62
- export function isTemplateCst(cst: Constituenta): boolean {
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 {@link Constituenta} can be used produce structure. */
181
- export function canProduceStructure(cst: Constituenta): boolean {
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, type Constituenta, CstStatus, CstType } from '../rsform';
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 {@link Constituenta} type. */
65
- export function applyFilterCategory(start: Constituenta, items: Constituenta[]): Constituenta[] {
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 OrderableConstituenta } from './types';
7
+ import { type FormalOrderFields } from './types';
8
8
 
9
- function cst(id: number, alias: string, cst_type: CstType, definition_formal = ''): OrderableConstituenta {
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 OrderableConstituenta, type SemanticRelations } from './types';
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 OrderableConstituenta[]): Graph<number> {
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 OrderableConstituenta>(
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 OrderableConstituenta>(
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 SynthesizableConstituenta
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 { AliasTypedConstituenta, OrderableConstituenta, ResolvableConstituenta, SemanticRelations } from './types';
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 OrderableConstituenta, type SemanticRelations } from './types';
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: OrderableConstituenta): Set<number> {
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: OrderableConstituenta): boolean {
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 { type Constituenta, CstStatus, CstType, type RSForm, type RSFormStats } from '../rsform';
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 {@link Constituenta} is a schema issue. */
12
- export function isSchemaIssue(cst: Constituenta): boolean {
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: Constituenta): number {
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: Constituenta): boolean {
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 {@link Constituenta} by structure path. */
25
- export function findCstByStructure(schema: RSForm, target: Constituenta, path: TypePath): Constituenta | null {
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 {@link Constituenta} structure. */
40
- export function getStructureName(schema: RSForm, target: Constituenta, path: TypePath): string {
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: Constituenta,
65
+ cst: SpawnPathFields,
60
66
  targetId: number,
61
- byId: Map<number, Constituenta>
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 ConstituentaMappableFields } from './alias';
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 ConstituentaMappableFields & { id: number; alias: string }>(
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 { CstType } from '../rsform';
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 ConstituentaMappableFields } from './alias';
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 AliasTypedConstituenta, type ResolvableConstituenta } from './types';
17
+ import { type AliasTypedFields, type TextResolvableFields } from './types';
18
18
 
19
- /** Constituent shape required for embedding / synthesis transforms. */
20
- export type SynthesizableConstituenta = ConstituentaMappableFields &
21
- ResolvableConstituenta &
22
- AliasTypedConstituenta & {
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 SynthesizableConstituenta> {
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 SynthesizableConstituenta> {
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 SynthesizableConstituenta>(
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 && !result.includes(item)) {
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 && !result.includes(item)) {
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 (!result.includes(item)) {
164
+ if (!included.has(item)) {
162
165
  result.push(item);
166
+ included.add(item);
163
167
  }
164
168
  }
165
169
  return result;