@rsconcept/domain 2.2.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.
Files changed (55) hide show
  1. package/dist/{diagnostics-Db1F7ruF.d.ts → diagnostics-DsEhmFh0.d.ts} +6 -4
  2. package/dist/{diagnostics-B1OfMra1.js → diagnostics-ndGYbvgh.js} +374 -15
  3. package/dist/diagnostics-ndGYbvgh.js.map +1 -0
  4. package/dist/index-DpiTybDB.d.ts +376 -0
  5. package/dist/index.d.ts +2 -2
  6. package/dist/index.js +2 -2
  7. package/dist/library/diagnostics.d.ts +1 -1
  8. package/dist/library/diagnostics.js +1 -1
  9. package/dist/library/index.d.ts +6 -5
  10. package/dist/library/index.js +1 -1
  11. package/dist/library/index.js.map +1 -1
  12. package/dist/library/oss-api.d.ts +1 -1
  13. package/dist/library/oss-api.js +1 -1
  14. package/dist/library/oss-api.js.map +1 -1
  15. package/dist/library/rsengine.d.ts +1 -1
  16. package/dist/library/rsengine.js +2 -2
  17. package/dist/library/rsform-api/index.d.ts +2 -146
  18. package/dist/library/rsform-api/index.js +2 -2
  19. package/dist/library/rsform.d.ts +2 -2
  20. package/dist/library/rsform.js.map +1 -1
  21. package/dist/library/rsmodel-api.d.ts +9 -4
  22. package/dist/library/rsmodel-api.js +7 -3
  23. package/dist/library/rsmodel-api.js.map +1 -1
  24. package/dist/library/rsmodel.d.ts +1 -1
  25. package/dist/library/structure-planner.d.ts +1 -1
  26. package/dist/library/structure-planner.js +2 -2
  27. package/dist/library/structure-planner.js.map +1 -1
  28. package/package.json +1 -1
  29. package/src/index.ts +1 -0
  30. package/src/library/diagnostics.ts +20 -9
  31. package/src/library/index.ts +1 -0
  32. package/src/library/oss-api.ts +5 -1
  33. package/src/library/rsform-api/alias.ts +60 -4
  34. package/src/library/rsform-api/attribution.ts +87 -0
  35. package/src/library/rsform-api/cst-type.ts +7 -5
  36. package/src/library/rsform-api/expression.ts +3 -3
  37. package/src/library/rsform-api/formal-graph.test.ts +2 -2
  38. package/src/library/rsform-api/formal-graph.ts +6 -10
  39. package/src/library/rsform-api/index.ts +38 -2
  40. package/src/library/rsform-api/semantic-relations.ts +4 -7
  41. package/src/library/rsform-api/stats.ts +6 -5
  42. package/src/library/rsform-api/structure.ts +12 -6
  43. package/src/library/rsform-api/substitution.ts +82 -0
  44. package/src/library/rsform-api/synthesis.test.ts +157 -0
  45. package/src/library/rsform-api/synthesis.ts +149 -6
  46. package/src/library/rsform-api/text-resolution.test.ts +84 -0
  47. package/src/library/rsform-api/text-resolution.ts +152 -0
  48. package/src/library/rsform-api/transforms.test.ts +161 -0
  49. package/src/library/rsform-api/transforms.ts +42 -0
  50. package/src/library/rsform-api/types.ts +102 -4
  51. package/src/library/rsform.ts +1 -1
  52. package/src/library/rsmodel-api.ts +10 -5
  53. package/src/library/structure-planner.ts +6 -2
  54. package/src/library/template-instantiation.ts +11 -9
  55. package/dist/diagnostics-B1OfMra1.js.map +0 -1
@@ -0,0 +1,152 @@
1
+ /**
2
+ * Cascade resolution of constituenta term/definition entity references.
3
+ * Matches backend {@code RSForm.resolve_all_text} / {@code resolve_term_change}.
4
+ */
5
+
6
+ import { type TermContext } from '../../cctext/language';
7
+ import { extractEntities, parseGrammemes, resolveTextReferences } from '../../cctext/language-api';
8
+ import { Graph } from '../../graph';
9
+
10
+ import { type TextResolvableFields } from './types';
11
+
12
+ /** Options controlling which texts to re-resolve after an edit. */
13
+ export interface TextChangeOptions {
14
+ termChanged: boolean;
15
+ termRawChanged: boolean;
16
+ definitionRawChanged: boolean;
17
+ clearTargetForms: boolean;
18
+ }
19
+
20
+ /** Build term-reference graph: referenced constituent → dependent (backend {@code graph_term}). */
21
+ export function buildTermReferenceGraph(items: readonly TextResolvableFields[]): Graph<number> {
22
+ return buildReferenceGraph(items, 'term_raw');
23
+ }
24
+
25
+ /** Build definition-reference graph: referenced constituent → dependent (backend {@code graph_text}). */
26
+ export function buildDefinitionReferenceGraph(items: readonly TextResolvableFields[]): Graph<number> {
27
+ return buildReferenceGraph(items, 'definition_raw');
28
+ }
29
+
30
+ /** Resolve all term and definition texts in topological order. Mutates items in place. */
31
+ export function resolveAllConstituentTexts(items: TextResolvableFields[]): void {
32
+ const graphTerm = buildTermReferenceGraph(items);
33
+ const idToItem = new Map(items.map(item => [item.id, item]));
34
+ const context = buildTermContext(items);
35
+
36
+ for (const id of graphTerm.topologicalOrder()) {
37
+ const row = idToItem.get(id);
38
+ if (!row) {
39
+ continue;
40
+ }
41
+ const resolved = resolveTextReferences(row.term_raw, context);
42
+ if (resolved !== row.term_resolved) {
43
+ row.term_resolved = resolved;
44
+ row.term_forms = [];
45
+ context[row.alias] = { nominal: row.term_resolved, forms: [] };
46
+ }
47
+ }
48
+
49
+ for (const row of items) {
50
+ row.definition_resolved = resolveTextReferences(row.definition_raw, context);
51
+ }
52
+ }
53
+
54
+ /**
55
+ * Resolve texts after a single constituent change, cascading dependents when the term changed.
56
+ * Mutates items in place.
57
+ */
58
+ export function resolveConstituentTextChange(
59
+ items: TextResolvableFields[],
60
+ targetID: number,
61
+ options: TextChangeOptions
62
+ ): void {
63
+ const idToItem = new Map(items.map(item => [item.id, item]));
64
+ const target = idToItem.get(targetID);
65
+ if (!target) {
66
+ throw new Error(`resolveConstituentTextChange: unknown target ${targetID}`);
67
+ }
68
+
69
+ const context = buildTermContext(items);
70
+ if (options.termRawChanged) {
71
+ target.term_resolved = resolveTextReferences(target.term_raw, context);
72
+ if (options.clearTargetForms) {
73
+ target.term_forms = [];
74
+ }
75
+ context[target.alias] = toContextItem(target);
76
+ } else if (options.termChanged) {
77
+ context[target.alias] = toContextItem(target);
78
+ }
79
+
80
+ if (options.definitionRawChanged && !options.termChanged) {
81
+ target.definition_resolved = resolveTextReferences(target.definition_raw, context);
82
+ }
83
+
84
+ if (!options.termChanged) {
85
+ return;
86
+ }
87
+
88
+ const graphTerm = buildTermReferenceGraph(items);
89
+ const graphText = buildDefinitionReferenceGraph(items);
90
+ const expansion = graphTerm.expandAllOutputs([targetID]);
91
+ const expansionSet = new Set(expansion);
92
+
93
+ for (const id of graphTerm.topologicalOrder()) {
94
+ if (!expansionSet.has(id)) {
95
+ continue;
96
+ }
97
+ const expanded = idToItem.get(id);
98
+ if (!expanded) {
99
+ continue;
100
+ }
101
+ const resolved = resolveTextReferences(expanded.term_raw, context);
102
+ if (resolved !== expanded.term_resolved) {
103
+ expanded.term_resolved = resolved;
104
+ expanded.term_forms = [];
105
+ context[expanded.alias] = { nominal: expanded.term_resolved, forms: [] };
106
+ }
107
+ }
108
+
109
+ const updateDefs = new Set([targetID, ...expansion, ...graphText.expandAllOutputs([targetID, ...expansion])]);
110
+ for (const item of items) {
111
+ if (updateDefs.has(item.id)) {
112
+ item.definition_resolved = resolveTextReferences(item.definition_raw, context);
113
+ }
114
+ }
115
+ }
116
+
117
+ // ====== Internals =======
118
+
119
+ function buildReferenceGraph(
120
+ items: readonly TextResolvableFields[],
121
+ field: 'definition_raw' | 'term_raw'
122
+ ): Graph<number> {
123
+ const graph = new Graph<number>();
124
+ const idByAlias = new Map(items.map(row => [row.alias, row.id]));
125
+ for (const row of items) {
126
+ graph.addNode(row.id);
127
+ }
128
+ for (const row of items) {
129
+ for (const entity of extractEntities(row[field])) {
130
+ const source = idByAlias.get(entity);
131
+ if (source !== undefined) {
132
+ graph.addEdge(source, row.id);
133
+ }
134
+ }
135
+ }
136
+ return graph;
137
+ }
138
+
139
+ function buildTermContext(items: readonly TextResolvableFields[]): TermContext {
140
+ const context: TermContext = {};
141
+ for (const row of items) {
142
+ context[row.alias] = toContextItem(row);
143
+ }
144
+ return context;
145
+ }
146
+
147
+ function toContextItem(row: TextResolvableFields): TermContext[string] {
148
+ return {
149
+ nominal: row.term_resolved,
150
+ forms: row.term_forms.map(form => ({ text: form.text, grams: parseGrammemes(form.tags) }))
151
+ };
152
+ }
@@ -0,0 +1,161 @@
1
+ import { describe, expect, it } from 'vitest';
2
+
3
+ import { CstType } from '../rsform';
4
+
5
+ import {
6
+ allocateImportAliases,
7
+ applyConstituentSubstitutions,
8
+ buildSequentialAliasMapping,
9
+ filterAttributions,
10
+ importAttributions,
11
+ insertItemAfter,
12
+ maxAliasIndex,
13
+ moveIdsInOrder,
14
+ remapAttributionsUnderSubstitution,
15
+ remapSubstitutionsAfterImport,
16
+ reorderItemsByIds
17
+ } from './index';
18
+
19
+ describe('maxAliasIndex / sequential and import aliases', () => {
20
+ it('finds max numeric suffix per type', () => {
21
+ expect(
22
+ maxAliasIndex(
23
+ [
24
+ { alias: 'X1', cst_type: CstType.BASE },
25
+ { alias: 'X4', cst_type: CstType.BASE }
26
+ ],
27
+ CstType.BASE
28
+ )
29
+ ).toBe(4);
30
+ expect(maxAliasIndex([{ alias: 'D2', cst_type: CstType.TERM }], CstType.BASE)).toBe(0);
31
+ });
32
+
33
+ it('builds sequential alias mapping in list order', () => {
34
+ const mapping = buildSequentialAliasMapping([
35
+ { alias: 'X9', cst_type: CstType.BASE },
36
+ { alias: 'X1', cst_type: CstType.BASE },
37
+ { alias: 'D5', cst_type: CstType.TERM }
38
+ ]);
39
+ expect(mapping).toEqual({ X9: 'X1', X1: 'X2', D5: 'D1' });
40
+ });
41
+
42
+ it('allocates import aliases only when receiver is non-empty', () => {
43
+ expect(allocateImportAliases([], [{ alias: 'X9', cst_type: CstType.BASE }])).toEqual({});
44
+ expect(
45
+ allocateImportAliases([{ alias: 'X2', cst_type: CstType.BASE }], [{ alias: 'X9', cst_type: CstType.BASE }])
46
+ ).toEqual({ X9: 'X3' });
47
+ });
48
+ });
49
+
50
+ describe('attribution remapping', () => {
51
+ it('remaps attributions under substitution and drops self-loops', () => {
52
+ const remapped = remapAttributionsUnderSubstitution(
53
+ [
54
+ { container: 1, attribute: 10 },
55
+ { container: 2, attribute: 20 },
56
+ { container: 1, attribute: 2 }
57
+ ],
58
+ new Map([
59
+ [1, 2],
60
+ [10, 20]
61
+ ])
62
+ );
63
+ expect(remapped).toEqual([{ container: 2, attribute: 20 }]);
64
+ });
65
+
66
+ it('imports attributions with id map and dedupe against existing', () => {
67
+ const imported = importAttributions(
68
+ [
69
+ { container: 10, attribute: 11 },
70
+ { container: 10, attribute: 99 }
71
+ ],
72
+ new Set([10, 11]),
73
+ { 10: 100, 11: 101 },
74
+ [{ container: 100, attribute: 101 }]
75
+ );
76
+ expect(imported).toEqual([{ container: 100, attribute: 101 }]);
77
+ });
78
+
79
+ it('filters attributions by deleted ids', () => {
80
+ expect(
81
+ filterAttributions(
82
+ [
83
+ { container: 1, attribute: 2 },
84
+ { container: 3, attribute: 4 }
85
+ ],
86
+ new Set([1])
87
+ )
88
+ ).toEqual([{ container: 3, attribute: 4 }]);
89
+ });
90
+ });
91
+
92
+ describe('transforms', () => {
93
+ it('moves ids within order', () => {
94
+ expect(moveIdsInOrder([1, 2, 3, 4], [2, 3], 0)).toEqual([2, 3, 1, 4]);
95
+ expect(moveIdsInOrder([1, 2, 3], [3], 99)).toEqual([1, 2, 3]);
96
+ });
97
+
98
+ it('reorders items by ids', () => {
99
+ const items = [
100
+ { id: 1, alias: 'a' },
101
+ { id: 2, alias: 'b' }
102
+ ];
103
+ expect(reorderItemsByIds(items, [2, 1]).map(i => i.alias)).toEqual(['b', 'a']);
104
+ });
105
+
106
+ it('inserts after id or appends', () => {
107
+ const items = [{ id: 1 }, { id: 2 }];
108
+ insertItemAfter(items, { id: 3 }, 1);
109
+ expect(items.map(i => i.id)).toEqual([1, 3, 2]);
110
+ insertItemAfter(items, { id: 4 }, null);
111
+ expect(items.map(i => i.id)).toEqual([1, 3, 2, 4]);
112
+ });
113
+ });
114
+
115
+ describe('substitution', () => {
116
+ it('applies alias mapping and drops originals', () => {
117
+ const items = [
118
+ {
119
+ id: 1,
120
+ alias: 'X1',
121
+ definition_formal: 'X1',
122
+ typification_manual: '',
123
+ term_raw: 'a',
124
+ definition_raw: '@{X1|nomn,sing}'
125
+ },
126
+ {
127
+ id: 2,
128
+ alias: 'X2',
129
+ definition_formal: 'X2',
130
+ typification_manual: '',
131
+ term_raw: 'b',
132
+ definition_raw: ''
133
+ }
134
+ ];
135
+ const result = applyConstituentSubstitutions(
136
+ items,
137
+ [{ container: 1, attribute: 2 }],
138
+ [{ original: 1, substitution: 2 }]
139
+ );
140
+ expect(result.deletedIds).toEqual(new Set([1]));
141
+ expect(result.items).toHaveLength(1);
142
+ expect(result.items[0].definition_raw).toBe('');
143
+ expect(result.attributions).toEqual([]);
144
+ });
145
+
146
+ it('remaps substitutions after import', () => {
147
+ expect(
148
+ remapSubstitutionsAfterImport(
149
+ [
150
+ { original: 10, substitution: 1 },
151
+ { original: 1, substitution: 10 }
152
+ ],
153
+ new Set([10]),
154
+ { 10: 100 }
155
+ )
156
+ ).toEqual([
157
+ { original: 100, substitution: 1 },
158
+ { original: 1, substitution: 100 }
159
+ ]);
160
+ });
161
+ });
@@ -0,0 +1,42 @@
1
+ /**
2
+ * Pure constituenta list transforms: reorder, move, insert position.
3
+ */
4
+
5
+ /** Rebuild an item list following {@link orderedIds}. Throws if an id is missing. */
6
+ export function reorderItemsByIds<T extends { id: number }>(items: readonly T[], orderedIds: readonly number[]): T[] {
7
+ const byId = new Map(items.map(item => [item.id, item]));
8
+ return orderedIds.map(id => {
9
+ const item = byId.get(id);
10
+ if (!item) {
11
+ throw new Error(`reorderItemsByIds: missing id ${id}`);
12
+ }
13
+ return item;
14
+ });
15
+ }
16
+
17
+ /**
18
+ * Move a subset of ids within an ordered id list.
19
+ * {@link moveTo} is clamped to `[0, rest.length]` (index among non-moving items).
20
+ */
21
+ export function moveIdsInOrder(ids: readonly number[], moving: readonly number[], moveTo: number): number[] {
22
+ const movingSet = new Set(moving);
23
+ const rest = ids.filter(id => !movingSet.has(id));
24
+ const movingItems = ids.filter(id => movingSet.has(id));
25
+ const clamped = Math.max(0, Math.min(moveTo, rest.length));
26
+ return [...rest.slice(0, clamped), ...movingItems, ...rest.slice(clamped)];
27
+ }
28
+
29
+ /** Insert {@link item} after {@link insertAfter}, or append when null/undefined/missing. Mutates {@link items}. */
30
+ export function insertItemAfter<T extends { id: number }>(
31
+ items: T[],
32
+ item: T,
33
+ insertAfter: number | null | undefined
34
+ ): void {
35
+ if (insertAfter === null || insertAfter === undefined) {
36
+ items.push(item);
37
+ return;
38
+ }
39
+ const idx = items.findIndex(row => row.id === insertAfter);
40
+ const insertAt = idx === -1 ? items.length : idx + 1;
41
+ items.splice(insertAt, 0, item);
42
+ }
@@ -1,11 +1,15 @@
1
1
  /**
2
- * Types for restoring constituent declaration order.
2
+ * Capability field slices for schema transforms.
3
+ *
4
+ * Named by concern/task (*Fields), not as subtypes of Constituenta —
5
+ * same idea as ConceptCore's RSConcept / TextConcept split.
3
6
  */
4
7
 
5
- import { type CstType } from '../rsform';
8
+ import { type ExpressionType, type TypePath } from '../../rslang';
9
+ import { type CstStatus, type CstType, type TermForm } from '../rsform';
6
10
 
7
- /** Minimal constituent fields required to restore order. */
8
- export interface OrderableConstituenta {
11
+ /** Fields needed to restore formal dependency order. */
12
+ export interface FormalOrderFields {
9
13
  id: number;
10
14
  alias: string;
11
15
  cst_type: CstType;
@@ -19,3 +23,97 @@ export interface SemanticRelations {
19
23
  /** Semantic children ids for each constituenta. */
20
24
  childrenOf: Map<number, number[]>;
21
25
  }
26
+
27
+ /** Fields needed to resolve term/definition entity references. */
28
+ export interface TextResolvableFields {
29
+ id: number;
30
+ alias: string;
31
+ term_raw: string;
32
+ term_resolved: string;
33
+ term_forms: TermForm[];
34
+ definition_raw: string;
35
+ definition_resolved: string;
36
+ }
37
+
38
+ /** Fields needed to allocate or reset aliases by type. */
39
+ export interface AliasTypedFields {
40
+ alias: string;
41
+ cst_type: CstType;
42
+ }
43
+
44
+ /** Fields needed to decide whether structure can be produced. */
45
+ export interface StructureCapableFields {
46
+ cst_type: CstType;
47
+ effectiveType: ExpressionType | null;
48
+ }
49
+
50
+ /** Fields needed for schema-issue checks (status + diagnostics). */
51
+ export interface SchemaIssueFields {
52
+ status: CstStatus;
53
+ diagnostics?: readonly { code: number }[] | null;
54
+ }
55
+
56
+ /** Fields needed to look up evaluation status for a model item. */
57
+ export interface ModelEvalFields {
58
+ id: number;
59
+ cst_type: CstType;
60
+ }
61
+
62
+ /** Fields needed to check missing convention / resolved term on basics. */
63
+ export interface BasicTextCheckFields {
64
+ cst_type: CstType;
65
+ convention: string;
66
+ term_resolved: string;
67
+ }
68
+
69
+ /** Fields needed to walk spawn paths for structure helpers. */
70
+ export interface SpawnPathFields {
71
+ id: number;
72
+ spawner?: number;
73
+ spawner_path?: TypePath;
74
+ }
75
+
76
+ /** Fields needed to extract template parameters from a bank item. */
77
+ export interface TemplateParamSourceFields {
78
+ definition_formal: string;
79
+ effectiveType: ExpressionType | null;
80
+ }
81
+
82
+ /** Fields copied from a template bank item when instantiating. */
83
+ export interface TemplateSourceFields extends TemplateParamSourceFields {
84
+ alias: string;
85
+ cst_type: CstType;
86
+ crucial: boolean;
87
+ convention: string;
88
+ definition_raw: string;
89
+ term_raw: string;
90
+ term_forms: TermForm[];
91
+ typification_manual: string;
92
+ value_is_property: boolean;
93
+ }
94
+
95
+ /** Fields needed to expand schema/model diagnostics into expressions. */
96
+ export interface DiagnosticSourceFields {
97
+ id: number;
98
+ alias: string;
99
+ cst_type: CstType;
100
+ term_resolved: string;
101
+ convention: string;
102
+ typification_manual: string;
103
+ definition_formal: string;
104
+ }
105
+
106
+ /** Fields needed for text search over constituenta content. */
107
+ export interface SearchableFields {
108
+ alias: string;
109
+ cst_type: CstType;
110
+ term_raw: string;
111
+ term_resolved: string;
112
+ definition_formal: string;
113
+ definition_raw: string;
114
+ definition_resolved: string;
115
+ convention: string;
116
+ }
117
+
118
+ /** Fields needed to build short UI descriptions / labels. */
119
+ export type DescribableFields = SearchableFields;
@@ -68,7 +68,7 @@ export interface Substitution {
68
68
  }
69
69
 
70
70
  /** Represents word form for natural language. */
71
- interface TermForm {
71
+ export interface TermForm {
72
72
  text: string;
73
73
  tags: string;
74
74
  }
@@ -5,8 +5,8 @@ import { type EchelonCollection } from '../rslang/semantic/typification';
5
5
 
6
6
  import { modelStatusCstDiagnostic } from './diagnostics';
7
7
  import { type RSEngine } from './rsengine';
8
- import { type Constituenta, CstType, type RSForm } from './rsform';
9
- import { calculateSchemaStats, isBaseSet, isBasicConcept } from './rsform-api';
8
+ import { CstType, type RSForm } from './rsform';
9
+ import { calculateSchemaStats, isBaseSet, isBasicConcept, type ModelEvalFields } from './rsform-api';
10
10
  import { type BasicBinding, EvalStatus, type RSModelStats } from './rsmodel';
11
11
 
12
12
  const RANDOM_INTEGER_MIN = -100;
@@ -44,7 +44,7 @@ export function validateValueData(data: unknown): data is Value {
44
44
  export function generateRandomValue(
45
45
  type: Typification,
46
46
  basics: Map<number, BasicBinding>,
47
- cstByAlias: Map<string, Constituenta>,
47
+ cstByAlias: Map<string, { id: number }>,
48
48
  setElementsCount: number = DEFAULT_RANDOM_SET_ELEMENTS_COUNT
49
49
  ): Value | null {
50
50
  switch (type.typeID) {
@@ -125,10 +125,15 @@ export function calculateModelStats(schema: RSForm, engine: RSEngine, _engineGen
125
125
  }
126
126
 
127
127
  /** Checks whether evaluation status contributes to model status issues. */
128
- export function isModelIssue(engine: RSEngine, cst: Constituenta): boolean {
128
+ export function isModelIssue(engine: RSEngine, cst: ModelEvalFields): boolean {
129
129
  return modelStatusCstDiagnostic(engine.getCstStatus(cst.id), cst.cst_type) !== null;
130
130
  }
131
131
 
132
+ /** Filters items whose evaluation status contributes to model issues. */
133
+ export function getEvalIssueItems(items: readonly ModelEvalFields[], engine: RSEngine): ModelEvalFields[] {
134
+ return items.filter(cst => isModelIssue(engine, cst));
135
+ }
136
+
132
137
  /** Evaluate if {@link CstType} is interpretable. */
133
138
  export function isInterpretable(type: CstType): boolean {
134
139
  switch (type) {
@@ -325,7 +330,7 @@ export function addValueElement(
325
330
 
326
331
  // ========= Internal functions ==========
327
332
 
328
- function countBaseElements(cst: Constituenta, engine: RSEngine): number {
333
+ function countBaseElements(cst: ModelEvalFields, engine: RSEngine): number {
329
334
  if (!isBasicConcept(cst.cst_type)) {
330
335
  return 0;
331
336
  }
@@ -4,7 +4,7 @@ import { labelType } from '../rslang/labels';
4
4
  import { bool, type EchelonFunctional, isTypification } from '../rslang/semantic/typification';
5
5
 
6
6
  import { type Constituenta, CstType, type RSForm } from './rsform';
7
- import { findCstByStructure } from './rsform-api';
7
+ import { findCstByStructure, type FormalOrderFields, type StructureCapableFields } from './rsform-api';
8
8
 
9
9
  /** Represents a node in the structure planner. */
10
10
  export interface SPNode {
@@ -95,7 +95,11 @@ export class StructurePlanner {
95
95
  }
96
96
 
97
97
  // ======= Internals =======
98
- function produceDefinition(target: Constituenta, rootType: Typification, path: TypePath): string {
98
+ function produceDefinition(
99
+ target: FormalOrderFields & StructureCapableFields,
100
+ rootType: Typification,
101
+ path: TypePath
102
+ ): string {
99
103
  let current = rootType;
100
104
  let expression = target.alias;
101
105
  let index = rootType.typeID === TypeID.collection ? 1 : 0;
@@ -16,14 +16,16 @@ import { labelType } from '../rslang/labels';
16
16
  import { TokenID } from '../rslang/parser/token';
17
17
  import { TypeID } from '../rslang/semantic/typification';
18
18
 
19
- import { type ArgumentValue, type Constituenta, type CstType, type RSForm } from './rsform';
19
+ import { type ArgumentValue, type CstType, type RSForm, type TermForm } from './rsform';
20
20
  import {
21
21
  applyMappingToConstituents,
22
22
  argumentValuesToMapping,
23
23
  generateAlias,
24
24
  inferTemplatedType,
25
25
  isFunctional,
26
- normalizeExpression
26
+ normalizeExpression,
27
+ type TemplateParamSourceFields,
28
+ type TemplateSourceFields
27
29
  } from './rsform-api';
28
30
 
29
31
  /**
@@ -42,7 +44,7 @@ export interface TemplateInstantiationItem {
42
44
  definition_formal: string;
43
45
  definition_raw: string;
44
46
  term_raw: string;
45
- term_forms: Constituenta['term_forms'];
47
+ term_forms: TermForm[];
46
48
  typification_manual: string;
47
49
  value_is_property: boolean;
48
50
  }
@@ -78,9 +80,9 @@ export interface TemplateInstantiationInput {
78
80
  /** Schema that will receive new constituents. */
79
81
  targetSchema: RSForm;
80
82
  /** All constituents of the selected expression-bank RSForm (not only the prototype). */
81
- templateItems: Constituenta[];
83
+ templateItems: TemplateSourceFields[];
82
84
  /** Template constituent chosen in the UI (main expression to add). */
83
- prototype: Constituenta;
85
+ prototype: TemplateSourceFields;
84
86
  /** User bindings from template parameter aliases to target-schema global aliases. */
85
87
  userArgs: ArgumentValue[];
86
88
  /**
@@ -118,10 +120,10 @@ export function planTemplateInstantiation(input: TemplateInstantiationInput): Te
118
120
  */
119
121
  export class TemplateInstantiationPlanner {
120
122
  private readonly targetSchema: RSForm;
121
- private readonly prototype: Constituenta;
123
+ private readonly prototype: TemplateSourceFields;
122
124
  private readonly userArgs: ArgumentValue[];
123
125
  private readonly mainItemTemplate: TemplateInstantiationItem;
124
- private readonly templateByAlias: Map<string, Constituenta>;
126
+ private readonly templateByAlias: Map<string, TemplateSourceFields>;
125
127
  private readonly userMapping: AliasMapping;
126
128
  private readonly depBindings = new Map<string, Map<string, string>>();
127
129
  private readonly depRefs = new Map<string, Set<string>>();
@@ -322,7 +324,7 @@ function formalDefinitionKey(cst_type: CstType, normalized: string): string {
322
324
  }
323
325
 
324
326
  function instantiateTemplateItem(
325
- template: Constituenta,
327
+ template: TemplateSourceFields,
326
328
  args: ArgumentValue[],
327
329
  alias: string
328
330
  ): TemplateInstantiationItem {
@@ -384,7 +386,7 @@ function bindingMapToArgs(params: TemplateParam[], bindings: Map<string, string>
384
386
  }));
385
387
  }
386
388
 
387
- function getTemplateParams(template: Constituenta): TemplateParam[] {
389
+ function getTemplateParams(template: TemplateParamSourceFields): TemplateParam[] {
388
390
  const effectiveType = template.effectiveType;
389
391
  if (effectiveType && (effectiveType.typeID === TypeID.function || effectiveType.typeID === TypeID.predicate)) {
390
392
  return effectiveType.args.map(arg => ({