@memoarchitect/tools 0.4.4 → 0.4.6

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 (154) hide show
  1. package/README.md +17 -9
  2. package/package.json +25 -24
  3. package/packages/tools/lib/bin/memo.js +0 -0
  4. package/packages/tools/lib/commands/dev.d.ts.map +1 -1
  5. package/packages/tools/lib/commands/dev.js +6 -1
  6. package/packages/tools/lib/commands/dev.js.map +1 -1
  7. package/packages/tools/lib/dhf/template-resolver.d.ts +1 -1
  8. package/packages/tools/lib/dhf/template-resolver.d.ts.map +1 -1
  9. package/packages/tools/lib/dhf/template-resolver.js +20 -16
  10. package/packages/tools/lib/dhf/template-resolver.js.map +1 -1
  11. package/packages/tools/lib/language/generated/ast.d.ts +1380 -115
  12. package/packages/tools/lib/language/generated/ast.d.ts.map +1 -1
  13. package/packages/tools/lib/language/generated/ast.js +1468 -843
  14. package/packages/tools/lib/language/generated/ast.js.map +1 -1
  15. package/packages/tools/lib/language/generated/grammar.d.ts +1 -1
  16. package/packages/tools/lib/language/generated/grammar.d.ts.map +1 -1
  17. package/packages/tools/lib/language/generated/grammar.js +97 -329
  18. package/packages/tools/lib/language/generated/grammar.js.map +1 -1
  19. package/packages/tools/lib/language/generated/module.d.ts +1 -1
  20. package/packages/tools/lib/language/generated/module.js +1 -1
  21. package/packages/tools/lib/model/ontology-loader.js +1 -1
  22. package/packages/tools/lib/model/ontology-loader.js.map +1 -1
  23. package/packages/tools/lib/model/paths.d.ts +6 -4
  24. package/packages/tools/lib/model/paths.d.ts.map +1 -1
  25. package/packages/tools/lib/model/paths.js +20 -9
  26. package/packages/tools/lib/model/paths.js.map +1 -1
  27. package/packages/tools/lib/__tests__/archetype-parsing.test.d.ts +0 -2
  28. package/packages/tools/lib/__tests__/archetype-parsing.test.d.ts.map +0 -1
  29. package/packages/tools/lib/__tests__/archetype-parsing.test.js +0 -42
  30. package/packages/tools/lib/__tests__/archetype-parsing.test.js.map +0 -1
  31. package/packages/tools/lib/__tests__/architecture-discovery.test.d.ts +0 -2
  32. package/packages/tools/lib/__tests__/architecture-discovery.test.d.ts.map +0 -1
  33. package/packages/tools/lib/__tests__/architecture-discovery.test.js +0 -82
  34. package/packages/tools/lib/__tests__/architecture-discovery.test.js.map +0 -1
  35. package/packages/tools/lib/__tests__/behavior.test.d.ts +0 -2
  36. package/packages/tools/lib/__tests__/behavior.test.d.ts.map +0 -1
  37. package/packages/tools/lib/__tests__/behavior.test.js +0 -766
  38. package/packages/tools/lib/__tests__/behavior.test.js.map +0 -1
  39. package/packages/tools/lib/__tests__/builder.test.d.ts +0 -2
  40. package/packages/tools/lib/__tests__/builder.test.d.ts.map +0 -1
  41. package/packages/tools/lib/__tests__/builder.test.js +0 -728
  42. package/packages/tools/lib/__tests__/builder.test.js.map +0 -1
  43. package/packages/tools/lib/__tests__/config-loader.test.d.ts +0 -2
  44. package/packages/tools/lib/__tests__/config-loader.test.d.ts.map +0 -1
  45. package/packages/tools/lib/__tests__/config-loader.test.js +0 -196
  46. package/packages/tools/lib/__tests__/config-loader.test.js.map +0 -1
  47. package/packages/tools/lib/__tests__/conformance.test.d.ts +0 -2
  48. package/packages/tools/lib/__tests__/conformance.test.d.ts.map +0 -1
  49. package/packages/tools/lib/__tests__/conformance.test.js +0 -467
  50. package/packages/tools/lib/__tests__/conformance.test.js.map +0 -1
  51. package/packages/tools/lib/__tests__/constraint-eval.test.d.ts +0 -2
  52. package/packages/tools/lib/__tests__/constraint-eval.test.d.ts.map +0 -1
  53. package/packages/tools/lib/__tests__/constraint-eval.test.js +0 -195
  54. package/packages/tools/lib/__tests__/constraint-eval.test.js.map +0 -1
  55. package/packages/tools/lib/__tests__/constraint-grammar.test.d.ts +0 -2
  56. package/packages/tools/lib/__tests__/constraint-grammar.test.d.ts.map +0 -1
  57. package/packages/tools/lib/__tests__/constraint-grammar.test.js +0 -163
  58. package/packages/tools/lib/__tests__/constraint-grammar.test.js.map +0 -1
  59. package/packages/tools/lib/__tests__/constraint-loader.test.d.ts +0 -2
  60. package/packages/tools/lib/__tests__/constraint-loader.test.d.ts.map +0 -1
  61. package/packages/tools/lib/__tests__/constraint-loader.test.js +0 -150
  62. package/packages/tools/lib/__tests__/constraint-loader.test.js.map +0 -1
  63. package/packages/tools/lib/__tests__/csv-io.test.d.ts +0 -2
  64. package/packages/tools/lib/__tests__/csv-io.test.d.ts.map +0 -1
  65. package/packages/tools/lib/__tests__/csv-io.test.js +0 -317
  66. package/packages/tools/lib/__tests__/csv-io.test.js.map +0 -1
  67. package/packages/tools/lib/__tests__/dhf-doc-store.test.d.ts +0 -2
  68. package/packages/tools/lib/__tests__/dhf-doc-store.test.d.ts.map +0 -1
  69. package/packages/tools/lib/__tests__/dhf-doc-store.test.js +0 -94
  70. package/packages/tools/lib/__tests__/dhf-doc-store.test.js.map +0 -1
  71. package/packages/tools/lib/__tests__/dhf-template-resolver.test.d.ts +0 -2
  72. package/packages/tools/lib/__tests__/dhf-template-resolver.test.d.ts.map +0 -1
  73. package/packages/tools/lib/__tests__/dhf-template-resolver.test.js +0 -39
  74. package/packages/tools/lib/__tests__/dhf-template-resolver.test.js.map +0 -1
  75. package/packages/tools/lib/__tests__/dhf.test.d.ts +0 -2
  76. package/packages/tools/lib/__tests__/dhf.test.d.ts.map +0 -1
  77. package/packages/tools/lib/__tests__/dhf.test.js +0 -393
  78. package/packages/tools/lib/__tests__/dhf.test.js.map +0 -1
  79. package/packages/tools/lib/__tests__/dimension-filter.test.d.ts +0 -2
  80. package/packages/tools/lib/__tests__/dimension-filter.test.d.ts.map +0 -1
  81. package/packages/tools/lib/__tests__/dimension-filter.test.js +0 -85
  82. package/packages/tools/lib/__tests__/dimension-filter.test.js.map +0 -1
  83. package/packages/tools/lib/__tests__/dsm.test.d.ts +0 -2
  84. package/packages/tools/lib/__tests__/dsm.test.d.ts.map +0 -1
  85. package/packages/tools/lib/__tests__/dsm.test.js +0 -112
  86. package/packages/tools/lib/__tests__/dsm.test.js.map +0 -1
  87. package/packages/tools/lib/__tests__/e2e-workflow.test.d.ts +0 -2
  88. package/packages/tools/lib/__tests__/e2e-workflow.test.d.ts.map +0 -1
  89. package/packages/tools/lib/__tests__/e2e-workflow.test.js +0 -707
  90. package/packages/tools/lib/__tests__/e2e-workflow.test.js.map +0 -1
  91. package/packages/tools/lib/__tests__/file-watcher.test.d.ts +0 -2
  92. package/packages/tools/lib/__tests__/file-watcher.test.d.ts.map +0 -1
  93. package/packages/tools/lib/__tests__/file-watcher.test.js +0 -31
  94. package/packages/tools/lib/__tests__/file-watcher.test.js.map +0 -1
  95. package/packages/tools/lib/__tests__/impact.test.d.ts +0 -2
  96. package/packages/tools/lib/__tests__/impact.test.d.ts.map +0 -1
  97. package/packages/tools/lib/__tests__/impact.test.js +0 -82
  98. package/packages/tools/lib/__tests__/impact.test.js.map +0 -1
  99. package/packages/tools/lib/__tests__/importer.test.d.ts +0 -2
  100. package/packages/tools/lib/__tests__/importer.test.d.ts.map +0 -1
  101. package/packages/tools/lib/__tests__/importer.test.js +0 -336
  102. package/packages/tools/lib/__tests__/importer.test.js.map +0 -1
  103. package/packages/tools/lib/__tests__/kind-registry.test.d.ts +0 -2
  104. package/packages/tools/lib/__tests__/kind-registry.test.d.ts.map +0 -1
  105. package/packages/tools/lib/__tests__/kind-registry.test.js +0 -132
  106. package/packages/tools/lib/__tests__/kind-registry.test.js.map +0 -1
  107. package/packages/tools/lib/__tests__/llm.test.d.ts +0 -2
  108. package/packages/tools/lib/__tests__/llm.test.d.ts.map +0 -1
  109. package/packages/tools/lib/__tests__/llm.test.js +0 -275
  110. package/packages/tools/lib/__tests__/llm.test.js.map +0 -1
  111. package/packages/tools/lib/__tests__/manifest-resolver.test.d.ts +0 -2
  112. package/packages/tools/lib/__tests__/manifest-resolver.test.d.ts.map +0 -1
  113. package/packages/tools/lib/__tests__/manifest-resolver.test.js +0 -97
  114. package/packages/tools/lib/__tests__/manifest-resolver.test.js.map +0 -1
  115. package/packages/tools/lib/__tests__/markdown-to-ir.test.d.ts +0 -2
  116. package/packages/tools/lib/__tests__/markdown-to-ir.test.d.ts.map +0 -1
  117. package/packages/tools/lib/__tests__/markdown-to-ir.test.js +0 -74
  118. package/packages/tools/lib/__tests__/markdown-to-ir.test.js.map +0 -1
  119. package/packages/tools/lib/__tests__/methodology-scope.test.d.ts +0 -2
  120. package/packages/tools/lib/__tests__/methodology-scope.test.d.ts.map +0 -1
  121. package/packages/tools/lib/__tests__/methodology-scope.test.js +0 -59
  122. package/packages/tools/lib/__tests__/methodology-scope.test.js.map +0 -1
  123. package/packages/tools/lib/__tests__/parser.test.d.ts +0 -2
  124. package/packages/tools/lib/__tests__/parser.test.d.ts.map +0 -1
  125. package/packages/tools/lib/__tests__/parser.test.js +0 -938
  126. package/packages/tools/lib/__tests__/parser.test.js.map +0 -1
  127. package/packages/tools/lib/__tests__/plugin.test.d.ts +0 -2
  128. package/packages/tools/lib/__tests__/plugin.test.d.ts.map +0 -1
  129. package/packages/tools/lib/__tests__/plugin.test.js +0 -308
  130. package/packages/tools/lib/__tests__/plugin.test.js.map +0 -1
  131. package/packages/tools/lib/__tests__/relationship-registry.test.d.ts +0 -2
  132. package/packages/tools/lib/__tests__/relationship-registry.test.d.ts.map +0 -1
  133. package/packages/tools/lib/__tests__/relationship-registry.test.js +0 -96
  134. package/packages/tools/lib/__tests__/relationship-registry.test.js.map +0 -1
  135. package/packages/tools/lib/__tests__/rule-registry.test.d.ts +0 -2
  136. package/packages/tools/lib/__tests__/rule-registry.test.d.ts.map +0 -1
  137. package/packages/tools/lib/__tests__/rule-registry.test.js +0 -53
  138. package/packages/tools/lib/__tests__/rule-registry.test.js.map +0 -1
  139. package/packages/tools/lib/__tests__/toolchain.test.d.ts +0 -2
  140. package/packages/tools/lib/__tests__/toolchain.test.d.ts.map +0 -1
  141. package/packages/tools/lib/__tests__/toolchain.test.js +0 -94
  142. package/packages/tools/lib/__tests__/toolchain.test.js.map +0 -1
  143. package/packages/tools/lib/__tests__/view-deriver-samples.test.d.ts +0 -2
  144. package/packages/tools/lib/__tests__/view-deriver-samples.test.d.ts.map +0 -1
  145. package/packages/tools/lib/__tests__/view-deriver-samples.test.js +0 -39
  146. package/packages/tools/lib/__tests__/view-deriver-samples.test.js.map +0 -1
  147. package/packages/tools/lib/__tests__/view-kinds.test.d.ts +0 -2
  148. package/packages/tools/lib/__tests__/view-kinds.test.d.ts.map +0 -1
  149. package/packages/tools/lib/__tests__/view-kinds.test.js +0 -263
  150. package/packages/tools/lib/__tests__/view-kinds.test.js.map +0 -1
  151. package/packages/tools/lib/__tests__/view-layout-store.test.d.ts +0 -2
  152. package/packages/tools/lib/__tests__/view-layout-store.test.d.ts.map +0 -1
  153. package/packages/tools/lib/__tests__/view-layout-store.test.js +0 -61
  154. package/packages/tools/lib/__tests__/view-layout-store.test.js.map +0 -1
@@ -1,707 +0,0 @@
1
- // ─── E2E CLI Workflow Tests ───────────────────────────────────────────────────
2
- //
3
- // Tests the full workflow: init → parse → validate → completeness → export
4
- // Uses a temp directory so tests are isolated from the real filesystem.
5
- // ─────────────────────────────────────────────────────────────────────────────
6
- import { describe, it, expect, beforeAll, afterAll } from 'vitest';
7
- import { execSync } from 'node:child_process';
8
- import { mkdtempSync, existsSync, readFileSync, rmSync, writeFileSync, mkdirSync, readdirSync } from 'node:fs';
9
- import { join, relative } from 'node:path';
10
- import { tmpdir } from 'node:os';
11
- import { VENDOR_ONTOLOGY_PACKAGES_DIR } from '@memoarchitect/tools';
12
- import { parse as parseYaml } from 'yaml';
13
- const CLI_PATH = join(__dirname, '../../lib/bin/memo.js');
14
- const REPO_ROOT = join(__dirname, '../../../..');
15
- function run(cmd, cwd) {
16
- return execSync(`node ${CLI_PATH} ${cmd}`, {
17
- cwd,
18
- encoding: 'utf-8',
19
- timeout: 30_000,
20
- env: { ...process.env, NO_COLOR: '1' },
21
- });
22
- }
23
- function runMayFail(cmd, cwd) {
24
- try {
25
- const stdout = execSync(`node ${CLI_PATH} ${cmd}`, {
26
- cwd,
27
- encoding: 'utf-8',
28
- timeout: 30_000,
29
- env: { ...process.env, NO_COLOR: '1' },
30
- stdio: ['pipe', 'pipe', 'pipe'],
31
- });
32
- return { stdout, exitCode: 0 };
33
- }
34
- catch (err) {
35
- // execSync throws on non-zero exit; stdout is still available
36
- return { stdout: (err.stdout || '') + (err.stderr || ''), exitCode: err.status || 1 };
37
- }
38
- }
39
- describe('E2E: memo init → validate → export', () => {
40
- let tmpDir;
41
- beforeAll(() => {
42
- tmpDir = mkdtempSync(join(tmpdir(), 'memo-e2e-'));
43
- });
44
- afterAll(() => {
45
- rmSync(tmpDir, { recursive: true, force: true });
46
- });
47
- it('memo init creates project structure with memo.package.yaml', () => {
48
- const output = run('init test-device', tmpDir);
49
- expect(output).toContain('Creating MEMO project: test-device');
50
- expect(output).toContain('Project created');
51
- const projectDir = join(tmpDir, 'test-device');
52
- expect(existsSync(projectDir)).toBe(true);
53
- expect(existsSync(join(projectDir, 'memo.package.yaml'))).toBe(true);
54
- const starterPath = join(projectDir, 'src', 'catalog', 'starter.sysml');
55
- expect(existsSync(starterPath)).toBe(true);
56
- expect(readdirSync(join(projectDir, 'src', 'documents'))).toEqual(['.gitkeep']);
57
- // Check new-format config content
58
- const config = parseYaml(readFileSync(join(projectDir, 'memo.package.yaml'), 'utf-8'));
59
- expect(config).toMatchObject({
60
- name: 'test-device',
61
- type: 'device',
62
- extends: '@memoarchitect/medical-modeling-profile',
63
- });
64
- expect(readFileSync(starterPath, 'utf-8')).toContain('import memo_medical_device_library::*');
65
- expect(existsSync(join(projectDir, 'memo.lock.yaml'))).toBe(true);
66
- const lock = readFileSync(join(projectDir, 'memo.lock.yaml'), 'utf-8');
67
- expect(lock).not.toContain('test-device');
68
- });
69
- it('memo init with no name initializes the current directory', () => {
70
- const projectDir = join(tmpDir, 'inplace-device');
71
- mkdirSync(projectDir);
72
- const output = run('init', projectDir);
73
- expect(output).toContain('Creating MEMO project: inplace-device');
74
- expect(output).toContain('Project created in current directory');
75
- expect(existsSync(join(projectDir, 'memo.package.yaml'))).toBe(true);
76
- expect(existsSync(join(projectDir, 'src', 'catalog', 'starter.sysml'))).toBe(true);
77
- const config = parseYaml(readFileSync(join(projectDir, 'memo.package.yaml'), 'utf-8'));
78
- expect(config.name).toBe('inplace-device');
79
- // Second init in the same directory must refuse
80
- const { exitCode, stdout } = runMayFail('init', projectDir);
81
- expect(exitCode).not.toBe(0);
82
- expect(stdout).toContain('already a MEMO project');
83
- });
84
- it('memo init refuses to overwrite existing directory', () => {
85
- const { exitCode } = runMayFail('init test-device', tmpDir);
86
- expect(exitCode).not.toBe(0);
87
- });
88
- it('memo init --ontology selects a different ontology', () => {
89
- // Run from REPO_ROOT so ontology packages are discoverable
90
- const output = run(`init ${join(tmpDir, 'test-core-device')} --ontology @memoarchitect/ontology`, REPO_ROOT);
91
- expect(output).toContain('Creating MEMO project');
92
- expect(output).toContain('Project created');
93
- const projectDir = join(tmpDir, 'test-core-device');
94
- const config = parseYaml(readFileSync(join(projectDir, 'memo.package.yaml'), 'utf-8'));
95
- expect(config.extends).toBe('@memoarchitect/ontology');
96
- // SysML should import the ontology
97
- const sysml = readFileSync(join(projectDir, 'src', 'catalog', 'starter.sysml'), 'utf-8');
98
- expect(sysml).toContain('import memo_medical_device_library::*');
99
- expect(existsSync(join(projectDir, 'memo.lock.yaml'))).toBe(true);
100
- expect(readFileSync(join(projectDir, 'memo.lock.yaml'), 'utf-8')).not.toContain('test-core-device');
101
- });
102
- it('memo init inside the workspace locks against the resolved ontology', () => {
103
- const projectDir = join(REPO_ROOT, 'tmp-e2e-lock-device');
104
- try {
105
- const output = run(`init ${projectDir}`, REPO_ROOT);
106
- expect(output).toContain('Created memo.lock.yaml');
107
- const lock = readFileSync(join(projectDir, 'memo.lock.yaml'), 'utf-8');
108
- expect(lock).toContain('ontology: "@memoarchitect/medical-modeling-profile"');
109
- expect(lock).not.toContain('tmp-e2e-lock-device');
110
- }
111
- finally {
112
- rmSync(projectDir, { recursive: true, force: true });
113
- }
114
- });
115
- it('memo init --ontology rejects unknown ontology', () => {
116
- // Run from REPO_ROOT so ontology packages are discoverable (and validation triggers)
117
- const { exitCode, stdout } = runMayFail(`init ${join(tmpDir, 'test-bad')} --ontology @memoarchitect/nonexistent`, REPO_ROOT);
118
- expect(exitCode).not.toBe(0);
119
- expect(stdout).toContain('not found');
120
- });
121
- it('memo init --list-ontologies shows available packages', () => {
122
- // Run from REPO_ROOT so packages are discoverable
123
- const output = run('init --list-ontologies', REPO_ROOT);
124
- expect(output).toContain('@memoarchitect/ontology');
125
- expect(output).toContain('@memoarchitect/medical-modeling-profile');
126
- expect(output).toContain('(default)');
127
- });
128
- it('memo init --archetype samd creates project with archetype pinned', () => {
129
- const projectDir = join(tmpDir, 'test-samd');
130
- const output = run(`init ${projectDir} --archetype samd`, REPO_ROOT);
131
- expect(output).toContain('Creating MEMO project');
132
- expect(output).toContain('Project created');
133
- const config = parseYaml(readFileSync(join(projectDir, 'memo.package.yaml'), 'utf-8'));
134
- expect(config.archetype).toBe('samd');
135
- });
136
- it('memo init --archetype blank creates project without archetype field', () => {
137
- const projectDir = join(tmpDir, 'test-blank');
138
- const output = run(`init ${projectDir} --archetype blank`, REPO_ROOT);
139
- expect(output).toContain('Project created');
140
- const config = parseYaml(readFileSync(join(projectDir, 'memo.package.yaml'), 'utf-8'));
141
- expect(config.archetype).toBeUndefined();
142
- });
143
- it('memo init --archetype rejects unknown archetype', () => {
144
- const projectDir = join(tmpDir, 'test-bad-arch');
145
- const { exitCode, stdout } = runMayFail(`init ${projectDir} --archetype nonexistent`, REPO_ROOT);
146
- expect(exitCode).not.toBe(0);
147
- expect(stdout).toContain('Unknown archetype');
148
- });
149
- it('memo init --list-ontologies shows archetypes from SysML', () => {
150
- const output = run('init --list-ontologies', REPO_ROOT);
151
- expect(output).toContain('device archetypes');
152
- expect(output).toContain('samd');
153
- expect(output).toContain('connected');
154
- expect(output).toContain('monitoring');
155
- expect(output).toContain('infusion_pump');
156
- expect(output).toContain('blank');
157
- });
158
- it('memo init --from-example gpca-pump copies example project', () => {
159
- const projectDir = join(tmpDir, 'test-from-example');
160
- const output = run(`init ${projectDir} --from-example gpca-pump`, REPO_ROOT);
161
- expect(output).toContain('Creating project from example');
162
- expect(output).toContain('gpca-pump');
163
- expect(output).toContain('Project created');
164
- expect(existsSync(join(projectDir, 'memo.config.yaml'))).toBe(true);
165
- expect(existsSync(join(projectDir, 'model'))).toBe(true);
166
- const modelDir = join(projectDir, 'model');
167
- const modelEntries = readdirSync(modelDir);
168
- expect(modelEntries).toEqual(expect.arrayContaining(['catalog', 'samples', 'views']));
169
- expect(modelEntries.some(f => f.endsWith('.sysml'))).toBe(false);
170
- const catalogFiles = readdirSync(join(modelDir, 'catalog'));
171
- expect(catalogFiles.some(f => f.endsWith('.sysml'))).toBe(true);
172
- });
173
- it('memo init --example gpca matches gpca-pump by prefix', () => {
174
- const projectDir = join(tmpDir, 'test-example-prefix');
175
- const output = run(`init ${projectDir} --example gpca`, REPO_ROOT);
176
- expect(output).toContain('Creating project from example');
177
- expect(output).toContain('gpca-pump');
178
- expect(existsSync(join(projectDir, 'memo.config.yaml'))).toBe(true);
179
- });
180
- it('memo init --example with no name copies into the current (empty) directory', () => {
181
- const projectDir = join(tmpDir, 'test-example-inplace');
182
- mkdirSync(projectDir);
183
- const output = run('init --example gpca', projectDir);
184
- expect(output).toContain('Project created in current directory');
185
- expect(existsSync(join(projectDir, 'memo.config.yaml'))).toBe(true);
186
- expect(existsSync(join(projectDir, 'model'))).toBe(true);
187
- // Refuses to copy into a non-empty directory
188
- const { exitCode, stdout } = runMayFail('init --example gpca', projectDir);
189
- expect(exitCode).not.toBe(0);
190
- expect(stdout).toContain('already a MEMO project');
191
- });
192
- it('memo init --from-example rejects unknown example', () => {
193
- const projectDir = join(tmpDir, 'test-bad-example');
194
- const { exitCode, stdout } = runMayFail(`init ${projectDir} --from-example nonexistent`, REPO_ROOT);
195
- expect(exitCode).not.toBe(0);
196
- expect(stdout).toContain('Unknown example');
197
- });
198
- it('memo init --list-ontologies shows available examples', () => {
199
- const output = run('init --list-ontologies', REPO_ROOT);
200
- expect(output).toContain('Available examples');
201
- expect(output).toContain('gpca-pump');
202
- });
203
- });
204
- describe('E2E: ontology lock + change detection', () => {
205
- let projectDir;
206
- beforeAll(() => {
207
- // Create a test project inside the monorepo so config resolution finds ontology packages
208
- projectDir = join(REPO_ROOT, '.test-lock-' + process.pid);
209
- rmSync(projectDir, { recursive: true, force: true });
210
- mkdirSync(projectDir, { recursive: true });
211
- mkdirSync(join(projectDir, 'model'), { recursive: true });
212
- writeFileSync(join(projectDir, 'memo.config.yaml'), `
213
- projectName: lock-test
214
- projectType: device
215
- extends: "@memoarchitect/medical-modeling-profile"
216
- `);
217
- writeFileSync(join(projectDir, 'model', 'device.sysml'), `
218
- package LockTest {
219
- import memo_medical_device_library::*;
220
- part sys : System {
221
- attribute redefines name = "Lock Test";
222
- }
223
- }
224
- `);
225
- });
226
- afterAll(() => {
227
- rmSync(projectDir, { recursive: true, force: true });
228
- });
229
- it('memo lock creates memo.lock.yaml', () => {
230
- const output = run('lock', projectDir);
231
- expect(output).toContain('Lock file written');
232
- expect(output).toContain('@memoarchitect/medical-modeling-profile');
233
- expect(existsSync(join(projectDir, 'memo.lock.yaml'))).toBe(true);
234
- const lock = readFileSync(join(projectDir, 'memo.lock.yaml'), 'utf-8');
235
- expect(lock).toContain('ontology: "@memoarchitect/medical-modeling-profile"');
236
- expect(lock).toContain('version:');
237
- expect(lock).toContain('lockedAt:');
238
- expect(lock).toContain('packages:');
239
- // Should have the ontology packages in the chain
240
- expect(lock).toContain('@memoarchitect/ontology');
241
- expect(lock).toContain('@memoarchitect/medical-modeling-profile');
242
- });
243
- it('memo validate succeeds with matching lock', () => {
244
- // Lock file was created in previous test
245
- const { stdout, exitCode } = runMayFail('validate', projectDir);
246
- expect(stdout).toContain('locked to');
247
- expect(stdout).toContain('Model:');
248
- expect(exitCode).toBe(0);
249
- });
250
- it('memo validate fails when ontology ID changes', () => {
251
- // Tamper the lock file to simulate an ontology change
252
- const lockPath = join(projectDir, 'memo.lock.yaml');
253
- const lock = readFileSync(lockPath, 'utf-8');
254
- writeFileSync(lockPath, lock.replace('@memoarchitect/medical-modeling-profile', '@memoarchitect/some-other-ontology'));
255
- const { stdout, exitCode } = runMayFail('validate', projectDir);
256
- expect(exitCode).not.toBe(0);
257
- expect(stdout).toContain('Ontology mismatch');
258
- expect(stdout).toContain('@memoarchitect/some-other-ontology');
259
- // Restore the lock file for subsequent tests
260
- writeFileSync(lockPath, lock);
261
- });
262
- it('memo validate fails when ontology version changes', () => {
263
- const lockPath = join(projectDir, 'memo.lock.yaml');
264
- const lock = readFileSync(lockPath, 'utf-8');
265
- writeFileSync(lockPath, lock.replace(/version: "[^"]+"\nlockedAt/, 'version: "99.0.0"\nlockedAt'));
266
- const { stdout, exitCode } = runMayFail('validate', projectDir);
267
- expect(exitCode).not.toBe(0);
268
- expect(stdout).toContain('version changed');
269
- // Restore
270
- writeFileSync(lockPath, lock);
271
- });
272
- it('memo lock regenerates after ontology changes', () => {
273
- // First tamper the lock
274
- const lockPath = join(projectDir, 'memo.lock.yaml');
275
- const oldLock = readFileSync(lockPath, 'utf-8');
276
- writeFileSync(lockPath, oldLock.replace('@memoarchitect/medical-modeling-profile', '@memoarchitect/some-other-ontology'));
277
- // Verify validate fails
278
- const { exitCode: fail } = runMayFail('validate', projectDir);
279
- expect(fail).not.toBe(0);
280
- // Regenerate lock
281
- const output = run('lock', projectDir);
282
- expect(output).toContain('Lock file written');
283
- // Now validate should pass
284
- const { exitCode: pass } = runMayFail('validate', projectDir);
285
- expect(pass).toBe(0);
286
- });
287
- });
288
- describe('E2E: custom model validation', () => {
289
- let projectDir;
290
- beforeAll(() => {
291
- // Create a test project inside the monorepo so config resolution finds @memoarchitect/medical-modeling-profile
292
- projectDir = join(REPO_ROOT, '.test-custom-device-' + process.pid);
293
- rmSync(projectDir, { recursive: true, force: true });
294
- mkdirSync(projectDir, { recursive: true });
295
- mkdirSync(join(projectDir, 'model'), { recursive: true });
296
- // Write a minimal config that extends @memoarchitect/medical-modeling-profile
297
- writeFileSync(join(projectDir, 'memo.config.yaml'), `
298
- projectName: custom-device
299
- projectType: device
300
- extends: "@memoarchitect/medical-modeling-profile"
301
- `);
302
- // Write a SysML model with elements and a traced relationship
303
- writeFileSync(join(projectDir, 'model', 'device.sysml'), `
304
- package CustomDevice {
305
- import memo_medical_device_library::*;
306
-
307
- part mySystem : System {
308
- attribute redefines name = "Custom Device";
309
- }
310
-
311
- part need1 : Requirement {
312
- attribute redefines source = "User";
313
- attribute redefines reqId = "REQ-001";
314
- attribute redefines statement = "User need 1";
315
- }
316
-
317
- part sysReq1 : Requirement {
318
- attribute redefines source = "System";
319
- attribute redefines reqId = "REQ-002";
320
- attribute redefines statement = "System requirement 1";
321
- }
322
-
323
- connection : TraceTo connect source ::> sysReq1 to target ::> need1;
324
- }
325
- `);
326
- });
327
- afterAll(() => {
328
- rmSync(projectDir, { recursive: true, force: true });
329
- });
330
- it('validates a custom model with elements and relationships', () => {
331
- const { stdout } = runMayFail('validate', projectDir);
332
- expect(stdout).toContain('Model:');
333
- expect(stdout).toContain('3 elements');
334
- expect(stdout).toContain('1 relationships');
335
- expect(stdout).toContain('Completeness by Layer');
336
- });
337
- });
338
- describe('E2E: memo install', () => {
339
- let projectDir;
340
- let fakeOntologyDir;
341
- beforeAll(() => {
342
- // Create a project inside the monorepo for config resolution
343
- projectDir = join(REPO_ROOT, '.test-install-' + process.pid);
344
- rmSync(projectDir, { recursive: true, force: true });
345
- // Use memo init to create a properly configured project
346
- run(`init ${projectDir}`, REPO_ROOT);
347
- // Create a fake local ontology package to install
348
- fakeOntologyDir = join(REPO_ROOT, '.test-fake-ontology-' + process.pid);
349
- rmSync(fakeOntologyDir, { recursive: true, force: true });
350
- mkdirSync(fakeOntologyDir, { recursive: true });
351
- writeFileSync(join(fakeOntologyDir, 'memo.package.yaml'), `
352
- name: "@test/fake-ontology"
353
- version: "1.0.0"
354
- type: ontology
355
- extends: "@memoarchitect/ontology"
356
- description: "Fake ontology for testing memo install"
357
- `);
358
- mkdirSync(join(fakeOntologyDir, 'sysml', 'custom'), { recursive: true });
359
- writeFileSync(join(fakeOntologyDir, 'sysml', 'custom', 'custom.sysml'), `
360
- package FakeOntology {
361
- part def CustomKind { }
362
- }
363
- `);
364
- });
365
- afterAll(() => {
366
- rmSync(projectDir, { recursive: true, force: true });
367
- rmSync(fakeOntologyDir, { recursive: true, force: true });
368
- });
369
- it('memo install with no source uses the lock and leaves resolvable content alone', () => {
370
- const output = run('install', projectDir);
371
- expect(output).toContain('already resolvable');
372
- expect(output).toContain('@memoarchitect/ontology');
373
- });
374
- it('memo install --mode local symlinks a local package into memo_packages/', () => {
375
- const output = run(`install ${fakeOntologyDir} --mode local`, projectDir);
376
- expect(output).toContain('Installing package (local)');
377
- expect(output).toContain('Installed @test/fake-ontology');
378
- // Check symlink was created
379
- const linkPath = join(projectDir, 'memo_packages', 'fake-ontology');
380
- expect(existsSync(linkPath)).toBe(true);
381
- // Check memo.package.yaml has the dependency
382
- const config = readFileSync(join(projectDir, 'memo.package.yaml'), 'utf-8');
383
- expect(config).toContain('@test/fake-ontology');
384
- });
385
- it('memo install --mode local refuses non-existent path', () => {
386
- const { exitCode, stdout } = runMayFail('install /nonexistent/path --mode local', projectDir);
387
- expect(exitCode).not.toBe(0);
388
- expect(stdout).toContain('does not exist');
389
- });
390
- it('memo install detects local paths automatically', () => {
391
- // Create another fake package
392
- const anotherDir = join(REPO_ROOT, '.test-another-ontology-' + process.pid);
393
- rmSync(anotherDir, { recursive: true, force: true });
394
- mkdirSync(anotherDir, { recursive: true });
395
- writeFileSync(join(anotherDir, 'memo.package.yaml'), `
396
- name: "@test/another-ontology"
397
- version: "2.0.0"
398
- type: ontology
399
- description: "Another fake ontology"
400
- `);
401
- try {
402
- const output = run(`install ${anotherDir}`, projectDir);
403
- expect(output).toContain('Installing package (local)');
404
- expect(output).toContain('Installed @test/another-ontology');
405
- }
406
- finally {
407
- rmSync(anotherDir, { recursive: true, force: true });
408
- }
409
- });
410
- it('memo install requires a project config', () => {
411
- const emptyDir = mkdtempSync(join(tmpdir(), 'memo-empty-'));
412
- try {
413
- const { exitCode, stdout } = runMayFail('install some-package', emptyDir);
414
- expect(exitCode).not.toBe(0);
415
- expect(stdout).toContain('No memo.package.yaml');
416
- }
417
- finally {
418
- rmSync(emptyDir, { recursive: true, force: true });
419
- }
420
- });
421
- });
422
- describe('DD-3: kpar round-trip (GPCA pump)', () => {
423
- const GPCA_DIR = join(REPO_ROOT, 'memo', 'src', 'examples', 'gpca-pump');
424
- let extractDir;
425
- function collectSysmlFiles(dir) {
426
- const files = [];
427
- for (const entry of readdirSync(dir, { withFileTypes: true })) {
428
- const full = join(dir, entry.name);
429
- if (entry.isDirectory()) {
430
- files.push(...collectSysmlFiles(full));
431
- }
432
- else if (entry.name.endsWith('.sysml')) {
433
- files.push(full);
434
- }
435
- }
436
- return files;
437
- }
438
- beforeAll(() => {
439
- extractDir = mkdtempSync(join(tmpdir(), 'memo-kpar-roundtrip-'));
440
- run('pack', GPCA_DIR);
441
- });
442
- afterAll(() => {
443
- rmSync(extractDir, { recursive: true, force: true });
444
- rmSync(join(GPCA_DIR, 'gpca-pump.kpar'), { force: true });
445
- });
446
- it('produces a .kpar file', () => {
447
- expect(existsSync(join(GPCA_DIR, 'gpca-pump.kpar'))).toBe(true);
448
- });
449
- it('kpar extracts without errors', () => {
450
- execSync(`gunzip -c "${join(GPCA_DIR, 'gpca-pump.kpar')}" | tar xf -`, { cwd: extractDir });
451
- expect(existsSync(join(extractDir, 'manifest.json'))).toBe(true);
452
- });
453
- it('manifest lists all source SysML files', () => {
454
- const manifest = JSON.parse(readFileSync(join(extractDir, 'manifest.json'), 'utf-8'));
455
- // The kpar packs every source dir of the project (model/ + methodology/).
456
- const sourceFiles = [
457
- ...collectSysmlFiles(join(GPCA_DIR, 'model')),
458
- ...collectSysmlFiles(join(GPCA_DIR, 'methodology')),
459
- ];
460
- const manifestSysml = manifest.files.filter((f) => f.endsWith('.sysml'));
461
- expect(manifest.format).toBe('kpar');
462
- expect(manifestSysml.length).toBe(sourceFiles.length);
463
- for (const src of sourceFiles) {
464
- const rel = relative(GPCA_DIR, src);
465
- expect(manifestSysml).toContain(rel);
466
- }
467
- });
468
- it('extracted SysML files are byte-identical to source', () => {
469
- const sourceFiles = collectSysmlFiles(join(GPCA_DIR, 'model'));
470
- expect(sourceFiles.length).toBeGreaterThanOrEqual(10);
471
- const diffs = [];
472
- for (const src of sourceFiles) {
473
- const rel = relative(GPCA_DIR, src);
474
- const extracted = join(extractDir, rel);
475
- if (!existsSync(extracted)) {
476
- diffs.push(`MISSING: ${rel}`);
477
- continue;
478
- }
479
- const srcContent = readFileSync(src);
480
- const extContent = readFileSync(extracted);
481
- if (!srcContent.equals(extContent)) {
482
- diffs.push(`CHANGED: ${rel}`);
483
- }
484
- }
485
- if (diffs.length > 0) {
486
- throw new Error(`Round-trip diff is not empty:\n${diffs.join('\n')}`);
487
- }
488
- expect(diffs).toHaveLength(0);
489
- });
490
- it('config file survives round-trip', () => {
491
- const srcConfig = readFileSync(join(GPCA_DIR, 'memo.config.yaml'), 'utf-8');
492
- const extConfig = readFileSync(join(extractDir, 'memo.config.yaml'), 'utf-8');
493
- expect(extConfig).toBe(srcConfig);
494
- });
495
- });
496
- describe('DD-5: sysand publish --dry-run', () => {
497
- it('memo sysand publish --dry-run succeeds for ontology', () => {
498
- const pkgDir = join(REPO_ROOT, VENDOR_ONTOLOGY_PACKAGES_DIR, 'ontology');
499
- const output = run('sysand publish --dry-run --package @memoarchitect/ontology', pkgDir);
500
- expect(output).toContain('PASS');
501
- expect(output).toContain('.kpar');
502
- expect(output).toContain('All packages pass dry-run');
503
- });
504
- it('memo sysand publish --dry-run fails gracefully outside a project', () => {
505
- const tmpDir = mkdtempSync(join(tmpdir(), 'memo-publish-'));
506
- const { exitCode } = runMayFail('sysand publish --dry-run', tmpDir);
507
- rmSync(tmpDir, { recursive: true, force: true });
508
- expect(exitCode).not.toBe(0);
509
- });
510
- });
511
- describe('E2E: import ea/cameo/sysand/owl', () => {
512
- let tmpDir;
513
- beforeAll(() => {
514
- tmpDir = mkdtempSync(join(tmpdir(), 'memo-import-e2e-'));
515
- });
516
- afterAll(() => {
517
- rmSync(tmpDir, { recursive: true, force: true });
518
- });
519
- it('memo import ea imports from EA JSON export', () => {
520
- const eaJson = JSON.stringify({
521
- elements: [
522
- { id: 1, name: 'Overheating', type: 'Class', stereotype: 'Hazard', notes: 'Thermal hazard' },
523
- { id: 2, name: 'Temp Monitor', type: 'Class', stereotype: 'RiskControl' },
524
- ],
525
- connectors: [
526
- { id: 1, sourceId: 2, targetId: 1, type: 'Dependency', stereotype: 'mitigates' },
527
- ],
528
- });
529
- writeFileSync(join(tmpDir, 'ea-export.json'), eaJson);
530
- const output = run(`import ea ea-export.json --dry-run`, tmpDir);
531
- expect(output).toContain('Sparx EA');
532
- expect(output).toContain('2 mapped');
533
- expect(output).toContain('Overheating : Hazard');
534
- expect(output).toContain('Temp_Monitor : RiskControl');
535
- expect(output).toContain('Mitigates');
536
- });
537
- it('memo import cameo imports from Cameo JSON export', () => {
538
- const cameoJson = JSON.stringify({
539
- elements: [
540
- { id: 'e1', name: 'Shock Hazard', type: 'uml:Class', stereotypes: ['Hazard'] },
541
- { id: 'e2', name: 'Insulation', type: 'uml:Class', stereotypes: ['RiskControl'] },
542
- ],
543
- relationships: [
544
- { id: 'r1', sourceId: 'e2', targetId: 'e1', type: 'sysml:Satisfy' },
545
- ],
546
- });
547
- writeFileSync(join(tmpDir, 'cameo-export.json'), cameoJson);
548
- const output = run(`import cameo cameo-export.json --dry-run`, tmpDir);
549
- expect(output).toContain('MagicDraw/Cameo');
550
- expect(output).toContain('2 mapped');
551
- expect(output).toContain('Shock_Hazard : Hazard');
552
- expect(output).toContain('Insulation : RiskControl');
553
- });
554
- it('memo import owl imports from OWL/Turtle', () => {
555
- const turtle = `
556
- @prefix memo: <https://example.org/memo#> .
557
- @prefix owl: <http://www.w3.org/2002/07/owl#> .
558
- @prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> .
559
- @prefix dcterms: <http://purl.org/dc/terms/> .
560
-
561
- <https://example.org/memo> a owl:Ontology ;
562
- dcterms:title "Test OWL Import" ;
563
- owl:versionInfo "1.0.0" ;
564
- .
565
-
566
- memo:Hazard a owl:Class ;
567
- rdfs:label "Hazard" ;
568
- memo:layer "risk" ;
569
- memo:sysmlConstruct "part def" ;
570
- .
571
-
572
- memo:mitigates a owl:ObjectProperty ;
573
- rdfs:label "mitigates" ;
574
- .
575
- `;
576
- writeFileSync(join(tmpDir, 'test-ontology.ttl'), turtle);
577
- const output = run(`import owl test-ontology.ttl --dry-run`, tmpDir);
578
- expect(output).toContain('OWL/JSON-LD');
579
- expect(output).toContain('Classes: 1');
580
- expect(output).toContain('Properties: 1');
581
- expect(output).toContain('part def Hazard');
582
- expect(output).toContain('connection def Mitigates');
583
- });
584
- it('memo import owl --package-dir creates ontology package', () => {
585
- const turtle = `
586
- @prefix memo: <https://example.org/memo#> .
587
- @prefix owl: <http://www.w3.org/2002/07/owl#> .
588
- @prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> .
589
-
590
- memo:Hazard a owl:Class ;
591
- rdfs:label "Hazard" ;
592
- memo:layer "risk" ;
593
- .
594
-
595
- memo:Requirement a owl:Class ;
596
- rdfs:label "Requirement" ;
597
- memo:layer "requirements" ;
598
- .
599
- `;
600
- writeFileSync(join(tmpDir, 'pkg-test.ttl'), turtle);
601
- const pkgDir = join(tmpDir, 'imported-pkg');
602
- run(`import owl pkg-test.ttl --package-dir ${pkgDir} --package test_pkg`, tmpDir);
603
- expect(existsSync(join(pkgDir, 'memo.package.yaml'))).toBe(true);
604
- expect(existsSync(join(pkgDir, '.project.json'))).toBe(true);
605
- expect(existsSync(join(pkgDir, 'sysml', 'index.sysml'))).toBe(true);
606
- expect(existsSync(join(pkgDir, 'sysml', 'risk', 'risk.sysml'))).toBe(true);
607
- expect(existsSync(join(pkgDir, 'sysml', 'requirements', 'requirements.sysml'))).toBe(true);
608
- });
609
- });
610
- describe('E2E: memo check --sysml-compat', () => {
611
- let tmpDir;
612
- beforeAll(() => {
613
- tmpDir = mkdtempSync(join(tmpdir(), 'memo-check-'));
614
- run('init test-check --template medical', tmpDir);
615
- });
616
- afterAll(() => {
617
- rmSync(tmpDir, { recursive: true, force: true });
618
- });
619
- it('memo check --sysml-compat produces text report', () => {
620
- const result = runMayFail('check --sysml-compat test-check', tmpDir);
621
- expect(result.stdout).toContain('SysML Compatibility Check');
622
- });
623
- it('memo check --sysml-compat --format json produces valid JSON', () => {
624
- const result = runMayFail('check --sysml-compat --format json test-check', tmpDir);
625
- const report = JSON.parse(result.stdout);
626
- expect(report.tool).toBe('memo-sysml-compat');
627
- expect(report.summary).toBeDefined();
628
- expect(typeof report.summary.compatible).toBe('boolean');
629
- expect(typeof report.summary.elements).toBe('number');
630
- expect(Array.isArray(report.findings)).toBe(true);
631
- });
632
- it('memo check without --sysml-compat shows usage', () => {
633
- const result = runMayFail('check test-check', tmpDir);
634
- expect(result.stdout).toContain('--sysml-compat');
635
- });
636
- });
637
- describe('E2E: memo round-trip', () => {
638
- let tmpDir;
639
- beforeAll(() => {
640
- tmpDir = mkdtempSync(join(tmpdir(), 'memo-rt-'));
641
- run('init test-rt --template medical', tmpDir);
642
- });
643
- afterAll(() => {
644
- rmSync(tmpDir, { recursive: true, force: true });
645
- });
646
- it('memo round-trip --tool syson produces text report', () => {
647
- const result = runMayFail('round-trip --tool syson test-rt', tmpDir);
648
- expect(result.stdout).toContain('Round-Trip Conformance');
649
- expect(result.stdout).toContain('syson');
650
- });
651
- it('memo round-trip --format json produces valid JSON', () => {
652
- const result = runMayFail('round-trip --tool syson --format json test-rt', tmpDir);
653
- const report = JSON.parse(result.stdout);
654
- expect(report.tool).toBe('syson');
655
- expect(report.summary).toBeDefined();
656
- expect(typeof report.summary.conformant).toBe('boolean');
657
- expect(typeof report.summary.elementsLost).toBe('number');
658
- expect(Array.isArray(report.diffs)).toBe(true);
659
- });
660
- it('memo round-trip defaults to syson tool', () => {
661
- const result = runMayFail('round-trip --format json test-rt', tmpDir);
662
- const report = JSON.parse(result.stdout);
663
- expect(report.tool).toBe('syson');
664
- });
665
- });
666
- describe('I-1: memo ontology add-kind', () => {
667
- let tmpDir;
668
- beforeAll(() => {
669
- tmpDir = mkdtempSync(join(tmpdir(), 'memo-add-kind-'));
670
- });
671
- afterAll(() => {
672
- rmSync(tmpDir, { recursive: true, force: true });
673
- });
674
- it('writes a parser-valid .sysml file for a simple layer', () => {
675
- run('ontology add-kind MyHazard --layer risk', tmpDir);
676
- const outPath = join(tmpDir, 'ontology', 'risk', 'MyHazard.sysml');
677
- expect(existsSync(outPath)).toBe(true);
678
- const content = readFileSync(outPath, 'utf-8');
679
- expect(content).toContain('part def MyHazard specializes TraceableElement');
680
- expect(content).toContain('package risk {');
681
- expect(content).toContain('private import memo::core::common::*;');
682
- });
683
- it('supports nested layer paths', () => {
684
- run('ontology add-kind SafetyControl --layer architecture/risk', tmpDir);
685
- const outPath = join(tmpDir, 'ontology', 'architecture', 'risk', 'SafetyControl.sysml');
686
- expect(existsSync(outPath)).toBe(true);
687
- const content = readFileSync(outPath, 'utf-8');
688
- expect(content).toContain('package architecture {');
689
- expect(content).toContain('package risk {');
690
- expect(content).toContain('part def SafetyControl specializes TraceableElement');
691
- });
692
- it('rejects non-PascalCase kind names', () => {
693
- const result = runMayFail('ontology add-kind lowercase --layer risk', tmpDir);
694
- expect(result.exitCode).not.toBe(0);
695
- });
696
- it('refuses to overwrite an existing file', () => {
697
- // MyHazard.sysml already exists from the first test — second call must fail
698
- const result = runMayFail('ontology add-kind MyHazard --layer risk', tmpDir);
699
- expect(result.exitCode).not.toBe(0);
700
- });
701
- it('does not write any YAML or JSON files', () => {
702
- const entries = readdirSync(join(tmpDir, 'ontology', 'risk'));
703
- const nonSysml = entries.filter(f => !f.endsWith('.sysml'));
704
- expect(nonSysml).toHaveLength(0);
705
- });
706
- });
707
- //# sourceMappingURL=e2e-workflow.test.js.map