@stackweld/core 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.turbo/turbo-build.log +4 -0
- package/.turbo/turbo-lint.log +498 -0
- package/.turbo/turbo-test.log +21 -0
- package/.turbo/turbo-typecheck.log +4 -0
- package/dist/__tests__/compatibility-scorer.test.d.ts +2 -0
- package/dist/__tests__/compatibility-scorer.test.d.ts.map +1 -0
- package/dist/__tests__/compatibility-scorer.test.js +226 -0
- package/dist/__tests__/compatibility-scorer.test.js.map +1 -0
- package/dist/__tests__/rules-engine.test.d.ts +2 -0
- package/dist/__tests__/rules-engine.test.d.ts.map +1 -0
- package/dist/__tests__/rules-engine.test.js +161 -0
- package/dist/__tests__/rules-engine.test.js.map +1 -0
- package/dist/__tests__/scaffold-orchestrator.test.d.ts +2 -0
- package/dist/__tests__/scaffold-orchestrator.test.d.ts.map +1 -0
- package/dist/__tests__/scaffold-orchestrator.test.js +149 -0
- package/dist/__tests__/scaffold-orchestrator.test.js.map +1 -0
- package/dist/__tests__/stack-engine.test.d.ts +2 -0
- package/dist/__tests__/stack-engine.test.d.ts.map +1 -0
- package/dist/__tests__/stack-engine.test.js +278 -0
- package/dist/__tests__/stack-engine.test.js.map +1 -0
- package/dist/db/database.d.ts +9 -0
- package/dist/db/database.d.ts.map +1 -0
- package/dist/db/database.js +106 -0
- package/dist/db/database.js.map +1 -0
- package/dist/db/index.d.ts +2 -0
- package/dist/db/index.d.ts.map +1 -0
- package/dist/db/index.js +2 -0
- package/dist/db/index.js.map +1 -0
- package/dist/engine/compatibility-scorer.d.ts +37 -0
- package/dist/engine/compatibility-scorer.d.ts.map +1 -0
- package/dist/engine/compatibility-scorer.js +178 -0
- package/dist/engine/compatibility-scorer.js.map +1 -0
- package/dist/engine/compose-generator.d.ts +35 -0
- package/dist/engine/compose-generator.d.ts.map +1 -0
- package/dist/engine/compose-generator.js +95 -0
- package/dist/engine/compose-generator.js.map +1 -0
- package/dist/engine/cost-estimator.d.ts +22 -0
- package/dist/engine/cost-estimator.d.ts.map +1 -0
- package/dist/engine/cost-estimator.js +451 -0
- package/dist/engine/cost-estimator.js.map +1 -0
- package/dist/engine/env-analyzer.d.ts +36 -0
- package/dist/engine/env-analyzer.d.ts.map +1 -0
- package/dist/engine/env-analyzer.js +111 -0
- package/dist/engine/env-analyzer.js.map +1 -0
- package/dist/engine/health-checker.d.ts +20 -0
- package/dist/engine/health-checker.d.ts.map +1 -0
- package/dist/engine/health-checker.js +377 -0
- package/dist/engine/health-checker.js.map +1 -0
- package/dist/engine/index.d.ts +11 -0
- package/dist/engine/index.d.ts.map +1 -0
- package/dist/engine/index.js +7 -0
- package/dist/engine/index.js.map +1 -0
- package/dist/engine/infra-generator.d.ts +26 -0
- package/dist/engine/infra-generator.d.ts.map +1 -0
- package/dist/engine/infra-generator.js +751 -0
- package/dist/engine/infra-generator.js.map +1 -0
- package/dist/engine/migration-planner.d.ts +34 -0
- package/dist/engine/migration-planner.d.ts.map +1 -0
- package/dist/engine/migration-planner.js +427 -0
- package/dist/engine/migration-planner.js.map +1 -0
- package/dist/engine/performance-profiler.d.ts +22 -0
- package/dist/engine/performance-profiler.d.ts.map +1 -0
- package/dist/engine/performance-profiler.js +292 -0
- package/dist/engine/performance-profiler.js.map +1 -0
- package/dist/engine/plugin-loader.d.ts +36 -0
- package/dist/engine/plugin-loader.d.ts.map +1 -0
- package/dist/engine/plugin-loader.js +157 -0
- package/dist/engine/plugin-loader.js.map +1 -0
- package/dist/engine/preferences.d.ts +24 -0
- package/dist/engine/preferences.d.ts.map +1 -0
- package/dist/engine/preferences.js +62 -0
- package/dist/engine/preferences.js.map +1 -0
- package/dist/engine/rules-engine.d.ts +31 -0
- package/dist/engine/rules-engine.d.ts.map +1 -0
- package/dist/engine/rules-engine.js +179 -0
- package/dist/engine/rules-engine.js.map +1 -0
- package/dist/engine/runtime-manager.d.ts +65 -0
- package/dist/engine/runtime-manager.d.ts.map +1 -0
- package/dist/engine/runtime-manager.js +181 -0
- package/dist/engine/runtime-manager.js.map +1 -0
- package/dist/engine/scaffold-orchestrator.d.ts +103 -0
- package/dist/engine/scaffold-orchestrator.d.ts.map +1 -0
- package/dist/engine/scaffold-orchestrator.js +934 -0
- package/dist/engine/scaffold-orchestrator.js.map +1 -0
- package/dist/engine/stack-detector.d.ts +21 -0
- package/dist/engine/stack-detector.d.ts.map +1 -0
- package/dist/engine/stack-detector.js +313 -0
- package/dist/engine/stack-detector.js.map +1 -0
- package/dist/engine/stack-differ.d.ts +26 -0
- package/dist/engine/stack-differ.d.ts.map +1 -0
- package/dist/engine/stack-differ.js +80 -0
- package/dist/engine/stack-differ.js.map +1 -0
- package/dist/engine/stack-engine.d.ts +54 -0
- package/dist/engine/stack-engine.d.ts.map +1 -0
- package/dist/engine/stack-engine.js +186 -0
- package/dist/engine/stack-engine.js.map +1 -0
- package/dist/engine/stack-serializer.d.ts +32 -0
- package/dist/engine/stack-serializer.d.ts.map +1 -0
- package/dist/engine/stack-serializer.js +75 -0
- package/dist/engine/stack-serializer.js.map +1 -0
- package/dist/engine/standards-linter.d.ts +34 -0
- package/dist/engine/standards-linter.d.ts.map +1 -0
- package/dist/engine/standards-linter.js +162 -0
- package/dist/engine/standards-linter.js.map +1 -0
- package/dist/engine/tech-installer.d.ts +37 -0
- package/dist/engine/tech-installer.d.ts.map +1 -0
- package/dist/engine/tech-installer.js +508 -0
- package/dist/engine/tech-installer.js.map +1 -0
- package/dist/index.d.ts +39 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +25 -0
- package/dist/index.js.map +1 -0
- package/dist/types/index.d.ts +6 -0
- package/dist/types/index.d.ts.map +1 -0
- package/dist/types/index.js +2 -0
- package/dist/types/index.js.map +1 -0
- package/dist/types/project.d.ts +33 -0
- package/dist/types/project.d.ts.map +1 -0
- package/dist/types/project.js +6 -0
- package/dist/types/project.js.map +1 -0
- package/dist/types/stack.d.ts +29 -0
- package/dist/types/stack.d.ts.map +1 -0
- package/dist/types/stack.js +6 -0
- package/dist/types/stack.js.map +1 -0
- package/dist/types/technology.d.ts +47 -0
- package/dist/types/technology.d.ts.map +1 -0
- package/dist/types/technology.js +6 -0
- package/dist/types/technology.js.map +1 -0
- package/dist/types/template.d.ts +34 -0
- package/dist/types/template.d.ts.map +1 -0
- package/dist/types/template.js +6 -0
- package/dist/types/template.js.map +1 -0
- package/dist/types/validation.d.ts +20 -0
- package/dist/types/validation.d.ts.map +1 -0
- package/dist/types/validation.js +5 -0
- package/dist/types/validation.js.map +1 -0
- package/package.json +39 -0
- package/src/__tests__/compatibility-scorer.test.ts +264 -0
- package/src/__tests__/rules-engine.test.ts +170 -0
- package/src/__tests__/scaffold-orchestrator.test.ts +161 -0
- package/src/__tests__/stack-engine.test.ts +328 -0
- package/src/db/database.ts +112 -0
- package/src/db/index.ts +1 -0
- package/src/engine/compatibility-scorer.ts +222 -0
- package/src/engine/compose-generator.ts +134 -0
- package/src/engine/cost-estimator.ts +498 -0
- package/src/engine/env-analyzer.ts +156 -0
- package/src/engine/health-checker.ts +421 -0
- package/src/engine/index.ts +17 -0
- package/src/engine/infra-generator.ts +837 -0
- package/src/engine/migration-planner.ts +496 -0
- package/src/engine/performance-profiler.ts +354 -0
- package/src/engine/plugin-loader.ts +216 -0
- package/src/engine/preferences.ts +85 -0
- package/src/engine/rules-engine.ts +204 -0
- package/src/engine/runtime-manager.ts +207 -0
- package/src/engine/scaffold-orchestrator.ts +1052 -0
- package/src/engine/stack-detector.ts +345 -0
- package/src/engine/stack-differ.ts +118 -0
- package/src/engine/stack-engine.ts +258 -0
- package/src/engine/stack-serializer.ts +95 -0
- package/src/engine/standards-linter.ts +210 -0
- package/src/engine/tech-installer.ts +650 -0
- package/src/index.ts +78 -0
- package/src/types/index.ts +10 -0
- package/src/types/project.ts +36 -0
- package/src/types/stack.ts +32 -0
- package/src/types/technology.ts +58 -0
- package/src/types/template.ts +37 -0
- package/src/types/validation.ts +22 -0
- package/tsconfig.json +10 -0
- package/tsconfig.tsbuildinfo +1 -0
|
@@ -0,0 +1,278 @@
|
|
|
1
|
+
import * as fs from "node:fs";
|
|
2
|
+
import * as os from "node:os";
|
|
3
|
+
import * as path from "node:path";
|
|
4
|
+
import { afterEach, beforeEach, describe, expect, it } from "vitest";
|
|
5
|
+
import { closeDatabase, getDatabase } from "../db/database.js";
|
|
6
|
+
import { RulesEngine } from "../engine/rules-engine.js";
|
|
7
|
+
import { StackEngine } from "../engine/stack-engine.js";
|
|
8
|
+
// Minimal technology fixtures for testing
|
|
9
|
+
function makeTech(overrides) {
|
|
10
|
+
return {
|
|
11
|
+
category: "backend",
|
|
12
|
+
description: "Test technology",
|
|
13
|
+
website: "https://example.com",
|
|
14
|
+
versions: [{ version: "1.0.0" }],
|
|
15
|
+
defaultVersion: "1.0.0",
|
|
16
|
+
requires: [],
|
|
17
|
+
incompatibleWith: [],
|
|
18
|
+
suggestedWith: [],
|
|
19
|
+
envVars: {},
|
|
20
|
+
configFiles: [],
|
|
21
|
+
lastVerified: "2026-01-01",
|
|
22
|
+
tags: [],
|
|
23
|
+
...overrides,
|
|
24
|
+
};
|
|
25
|
+
}
|
|
26
|
+
const fakeTechs = [
|
|
27
|
+
makeTech({ id: "nodejs", name: "Node.js", category: "runtime" }),
|
|
28
|
+
makeTech({ id: "express", name: "Express", category: "backend", requires: ["nodejs"] }),
|
|
29
|
+
makeTech({ id: "postgresql", name: "PostgreSQL", category: "database", defaultPort: 5432 }),
|
|
30
|
+
makeTech({ id: "redis", name: "Redis", category: "service", defaultPort: 6379 }),
|
|
31
|
+
];
|
|
32
|
+
let tmpDbPath;
|
|
33
|
+
let engine;
|
|
34
|
+
beforeEach(() => {
|
|
35
|
+
// Use a temp file for the database so tests are isolated
|
|
36
|
+
const tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), "stackweld-test-"));
|
|
37
|
+
tmpDbPath = path.join(tmpDir, "test.db");
|
|
38
|
+
// Initialize the database at the temp path
|
|
39
|
+
getDatabase(tmpDbPath);
|
|
40
|
+
const rules = new RulesEngine(fakeTechs);
|
|
41
|
+
engine = new StackEngine(rules);
|
|
42
|
+
});
|
|
43
|
+
afterEach(() => {
|
|
44
|
+
closeDatabase();
|
|
45
|
+
// Clean up temp file
|
|
46
|
+
if (tmpDbPath && fs.existsSync(tmpDbPath)) {
|
|
47
|
+
const dir = path.dirname(tmpDbPath);
|
|
48
|
+
fs.rmSync(dir, { recursive: true, force: true });
|
|
49
|
+
}
|
|
50
|
+
});
|
|
51
|
+
describe("StackEngine", () => {
|
|
52
|
+
describe("create()", () => {
|
|
53
|
+
it("creates a stack and persists it", () => {
|
|
54
|
+
const { stack, validation } = engine.create({
|
|
55
|
+
name: "test-stack",
|
|
56
|
+
technologies: [{ technologyId: "nodejs", version: "1.0.0" }],
|
|
57
|
+
});
|
|
58
|
+
expect(validation.valid).toBe(true);
|
|
59
|
+
expect(stack.name).toBe("test-stack");
|
|
60
|
+
expect(stack.id).toBeTruthy();
|
|
61
|
+
expect(stack.version).toBe(1);
|
|
62
|
+
// Verify it's actually persisted
|
|
63
|
+
const retrieved = engine.get(stack.id);
|
|
64
|
+
expect(retrieved).not.toBeNull();
|
|
65
|
+
expect(retrieved?.name).toBe("test-stack");
|
|
66
|
+
});
|
|
67
|
+
it("auto-resolves dependencies", () => {
|
|
68
|
+
const { stack, validation } = engine.create({
|
|
69
|
+
name: "express-stack",
|
|
70
|
+
technologies: [{ technologyId: "express", version: "1.0.0" }],
|
|
71
|
+
});
|
|
72
|
+
expect(validation.valid).toBe(true);
|
|
73
|
+
// express requires nodejs, which should be auto-resolved
|
|
74
|
+
expect(validation.resolvedDependencies).toContain("nodejs");
|
|
75
|
+
const techIds = stack.technologies.map((t) => t.technologyId);
|
|
76
|
+
expect(techIds).toContain("express");
|
|
77
|
+
expect(techIds).toContain("nodejs");
|
|
78
|
+
});
|
|
79
|
+
it("assigns ports to technologies with defaultPort", () => {
|
|
80
|
+
const { stack, validation } = engine.create({
|
|
81
|
+
name: "db-stack",
|
|
82
|
+
technologies: [
|
|
83
|
+
{ technologyId: "postgresql", version: "1.0.0" },
|
|
84
|
+
{ technologyId: "redis", version: "1.0.0" },
|
|
85
|
+
],
|
|
86
|
+
});
|
|
87
|
+
expect(validation.valid).toBe(true);
|
|
88
|
+
expect(validation.portAssignments.postgresql).toBe(5432);
|
|
89
|
+
expect(validation.portAssignments.redis).toBe(6379);
|
|
90
|
+
});
|
|
91
|
+
it("sets default profile to standard", () => {
|
|
92
|
+
const { stack } = engine.create({
|
|
93
|
+
name: "default-profile",
|
|
94
|
+
technologies: [{ technologyId: "nodejs", version: "1.0.0" }],
|
|
95
|
+
});
|
|
96
|
+
expect(stack.profile).toBe("standard");
|
|
97
|
+
});
|
|
98
|
+
it("sets tags when provided", () => {
|
|
99
|
+
const { stack } = engine.create({
|
|
100
|
+
name: "tagged-stack",
|
|
101
|
+
technologies: [{ technologyId: "nodejs", version: "1.0.0" }],
|
|
102
|
+
tags: ["test", "dev"],
|
|
103
|
+
});
|
|
104
|
+
expect(stack.tags).toEqual(["test", "dev"]);
|
|
105
|
+
});
|
|
106
|
+
});
|
|
107
|
+
describe("list()", () => {
|
|
108
|
+
it("returns empty array when no stacks exist", () => {
|
|
109
|
+
const stacks = engine.list();
|
|
110
|
+
expect(stacks).toEqual([]);
|
|
111
|
+
});
|
|
112
|
+
it("returns saved stacks", () => {
|
|
113
|
+
engine.create({
|
|
114
|
+
name: "stack-a",
|
|
115
|
+
technologies: [{ technologyId: "nodejs", version: "1.0.0" }],
|
|
116
|
+
});
|
|
117
|
+
engine.create({
|
|
118
|
+
name: "stack-b",
|
|
119
|
+
technologies: [{ technologyId: "redis", version: "1.0.0" }],
|
|
120
|
+
});
|
|
121
|
+
const stacks = engine.list();
|
|
122
|
+
expect(stacks.length).toBe(2);
|
|
123
|
+
const names = stacks.map((s) => s.name);
|
|
124
|
+
expect(names).toContain("stack-a");
|
|
125
|
+
expect(names).toContain("stack-b");
|
|
126
|
+
});
|
|
127
|
+
});
|
|
128
|
+
describe("get()", () => {
|
|
129
|
+
it("returns correct stack by ID", () => {
|
|
130
|
+
const { stack: created } = engine.create({
|
|
131
|
+
name: "get-test",
|
|
132
|
+
description: "Testing get",
|
|
133
|
+
technologies: [{ technologyId: "nodejs", version: "1.0.0" }],
|
|
134
|
+
});
|
|
135
|
+
const retrieved = engine.get(created.id);
|
|
136
|
+
expect(retrieved).not.toBeNull();
|
|
137
|
+
expect(retrieved?.id).toBe(created.id);
|
|
138
|
+
expect(retrieved?.name).toBe("get-test");
|
|
139
|
+
expect(retrieved?.description).toBe("Testing get");
|
|
140
|
+
});
|
|
141
|
+
it("returns null for non-existent ID", () => {
|
|
142
|
+
const result = engine.get("non-existent-uuid");
|
|
143
|
+
expect(result).toBeNull();
|
|
144
|
+
});
|
|
145
|
+
it("includes technologies in the returned stack", () => {
|
|
146
|
+
const { stack: created } = engine.create({
|
|
147
|
+
name: "tech-check",
|
|
148
|
+
technologies: [
|
|
149
|
+
{ technologyId: "postgresql", version: "1.0.0" },
|
|
150
|
+
{ technologyId: "redis", version: "1.0.0" },
|
|
151
|
+
],
|
|
152
|
+
});
|
|
153
|
+
const retrieved = engine.get(created.id);
|
|
154
|
+
expect(retrieved?.technologies.length).toBe(2);
|
|
155
|
+
const ids = retrieved?.technologies.map((t) => t.technologyId);
|
|
156
|
+
expect(ids).toContain("postgresql");
|
|
157
|
+
expect(ids).toContain("redis");
|
|
158
|
+
});
|
|
159
|
+
});
|
|
160
|
+
describe("delete()", () => {
|
|
161
|
+
it("removes a stack", () => {
|
|
162
|
+
const { stack } = engine.create({
|
|
163
|
+
name: "to-delete",
|
|
164
|
+
technologies: [{ technologyId: "nodejs", version: "1.0.0" }],
|
|
165
|
+
});
|
|
166
|
+
const deleted = engine.delete(stack.id);
|
|
167
|
+
expect(deleted).toBe(true);
|
|
168
|
+
const retrieved = engine.get(stack.id);
|
|
169
|
+
expect(retrieved).toBeNull();
|
|
170
|
+
});
|
|
171
|
+
it("returns false for non-existent stack", () => {
|
|
172
|
+
const deleted = engine.delete("non-existent-uuid");
|
|
173
|
+
expect(deleted).toBe(false);
|
|
174
|
+
});
|
|
175
|
+
it("does not affect other stacks", () => {
|
|
176
|
+
const { stack: a } = engine.create({
|
|
177
|
+
name: "keep-me",
|
|
178
|
+
technologies: [{ technologyId: "nodejs", version: "1.0.0" }],
|
|
179
|
+
});
|
|
180
|
+
const { stack: b } = engine.create({
|
|
181
|
+
name: "delete-me",
|
|
182
|
+
technologies: [{ technologyId: "redis", version: "1.0.0" }],
|
|
183
|
+
});
|
|
184
|
+
engine.delete(b.id);
|
|
185
|
+
expect(engine.get(a.id)).not.toBeNull();
|
|
186
|
+
expect(engine.get(b.id)).toBeNull();
|
|
187
|
+
});
|
|
188
|
+
});
|
|
189
|
+
describe("update()", () => {
|
|
190
|
+
it("modifies stack fields", () => {
|
|
191
|
+
const { stack } = engine.create({
|
|
192
|
+
name: "original",
|
|
193
|
+
description: "original desc",
|
|
194
|
+
technologies: [{ technologyId: "nodejs", version: "1.0.0" }],
|
|
195
|
+
});
|
|
196
|
+
const result = engine.update(stack.id, {
|
|
197
|
+
name: "updated-name",
|
|
198
|
+
description: "new desc",
|
|
199
|
+
});
|
|
200
|
+
expect(result).not.toBeNull();
|
|
201
|
+
expect(result?.stack.name).toBe("updated-name");
|
|
202
|
+
expect(result?.stack.description).toBe("new desc");
|
|
203
|
+
});
|
|
204
|
+
it("increments version number on update", () => {
|
|
205
|
+
const { stack } = engine.create({
|
|
206
|
+
name: "versioned",
|
|
207
|
+
technologies: [{ technologyId: "nodejs", version: "1.0.0" }],
|
|
208
|
+
});
|
|
209
|
+
expect(stack.version).toBe(1);
|
|
210
|
+
const result = engine.update(stack.id, { name: "versioned-v2" });
|
|
211
|
+
expect(result?.stack.version).toBe(2);
|
|
212
|
+
const result2 = engine.update(stack.id, { name: "versioned-v3" });
|
|
213
|
+
expect(result2?.stack.version).toBe(3);
|
|
214
|
+
});
|
|
215
|
+
it("returns null for non-existent stack", () => {
|
|
216
|
+
const result = engine.update("non-existent", { name: "nope" });
|
|
217
|
+
expect(result).toBeNull();
|
|
218
|
+
});
|
|
219
|
+
it("updates technologies", () => {
|
|
220
|
+
const { stack } = engine.create({
|
|
221
|
+
name: "tech-update",
|
|
222
|
+
technologies: [{ technologyId: "nodejs", version: "1.0.0" }],
|
|
223
|
+
});
|
|
224
|
+
const result = engine.update(stack.id, {
|
|
225
|
+
technologies: [
|
|
226
|
+
{ technologyId: "nodejs", version: "1.0.0" },
|
|
227
|
+
{ technologyId: "redis", version: "1.0.0" },
|
|
228
|
+
],
|
|
229
|
+
});
|
|
230
|
+
const techIds = result?.stack.technologies.map((t) => t.technologyId);
|
|
231
|
+
expect(techIds).toContain("nodejs");
|
|
232
|
+
expect(techIds).toContain("redis");
|
|
233
|
+
});
|
|
234
|
+
});
|
|
235
|
+
describe("version management", () => {
|
|
236
|
+
it("saves a version snapshot on create", () => {
|
|
237
|
+
const { stack } = engine.create({
|
|
238
|
+
name: "versioned-stack",
|
|
239
|
+
technologies: [{ technologyId: "nodejs", version: "1.0.0" }],
|
|
240
|
+
});
|
|
241
|
+
const history = engine.getVersionHistory(stack.id);
|
|
242
|
+
expect(history.length).toBe(1);
|
|
243
|
+
expect(history[0].version).toBe(1);
|
|
244
|
+
expect(history[0].changelog).toBe("Initial creation");
|
|
245
|
+
expect(history[0].snapshot.name).toBe("versioned-stack");
|
|
246
|
+
});
|
|
247
|
+
it("saves a version snapshot on update", () => {
|
|
248
|
+
const { stack } = engine.create({
|
|
249
|
+
name: "multi-version",
|
|
250
|
+
technologies: [{ technologyId: "nodejs", version: "1.0.0" }],
|
|
251
|
+
});
|
|
252
|
+
engine.update(stack.id, { name: "multi-version-v2" });
|
|
253
|
+
const history = engine.getVersionHistory(stack.id);
|
|
254
|
+
expect(history.length).toBe(2);
|
|
255
|
+
// Ordered by version DESC
|
|
256
|
+
expect(history[0].version).toBe(2);
|
|
257
|
+
expect(history[1].version).toBe(1);
|
|
258
|
+
});
|
|
259
|
+
it("returns empty history for non-existent stack", () => {
|
|
260
|
+
const history = engine.getVersionHistory("non-existent");
|
|
261
|
+
expect(history).toEqual([]);
|
|
262
|
+
});
|
|
263
|
+
it("version snapshot contains full stack data", () => {
|
|
264
|
+
const { stack } = engine.create({
|
|
265
|
+
name: "snapshot-check",
|
|
266
|
+
description: "checking snapshots",
|
|
267
|
+
technologies: [{ technologyId: "postgresql", version: "1.0.0" }],
|
|
268
|
+
tags: ["prod"],
|
|
269
|
+
});
|
|
270
|
+
const history = engine.getVersionHistory(stack.id);
|
|
271
|
+
const snapshot = history[0].snapshot;
|
|
272
|
+
expect(snapshot.name).toBe("snapshot-check");
|
|
273
|
+
expect(snapshot.description).toBe("checking snapshots");
|
|
274
|
+
expect(snapshot.tags).toEqual(["prod"]);
|
|
275
|
+
});
|
|
276
|
+
});
|
|
277
|
+
});
|
|
278
|
+
//# sourceMappingURL=stack-engine.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"stack-engine.test.js","sourceRoot":"","sources":["../../src/__tests__/stack-engine.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Database — SQLite persistence layer for stacks, projects, and versions.
|
|
3
|
+
* Uses better-sqlite3 for synchronous, reliable access.
|
|
4
|
+
*/
|
|
5
|
+
import Database from "better-sqlite3";
|
|
6
|
+
export declare function getDatabase(dbPath?: string): Database.Database;
|
|
7
|
+
export declare function closeDatabase(): void;
|
|
8
|
+
export declare function getDefaultDbPath(): string;
|
|
9
|
+
//# sourceMappingURL=database.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"database.d.ts","sourceRoot":"","sources":["../../src/db/database.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAIH,OAAO,QAAQ,MAAM,gBAAgB,CAAC;AA+EtC,wBAAgB,WAAW,CAAC,MAAM,CAAC,EAAE,MAAM,GAAG,QAAQ,CAAC,QAAQ,CAa9D;AAED,wBAAgB,aAAa,IAAI,IAAI,CAKpC;AAED,wBAAgB,gBAAgB,IAAI,MAAM,CAGzC"}
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Database — SQLite persistence layer for stacks, projects, and versions.
|
|
3
|
+
* Uses better-sqlite3 for synchronous, reliable access.
|
|
4
|
+
*/
|
|
5
|
+
import * as fs from "node:fs";
|
|
6
|
+
import * as path from "node:path";
|
|
7
|
+
import Database from "better-sqlite3";
|
|
8
|
+
const SCHEMA = `
|
|
9
|
+
CREATE TABLE IF NOT EXISTS stacks (
|
|
10
|
+
id TEXT PRIMARY KEY,
|
|
11
|
+
name TEXT NOT NULL UNIQUE,
|
|
12
|
+
description TEXT NOT NULL DEFAULT '',
|
|
13
|
+
profile TEXT NOT NULL DEFAULT 'standard',
|
|
14
|
+
version INTEGER NOT NULL DEFAULT 1,
|
|
15
|
+
created_at TEXT NOT NULL DEFAULT (datetime('now')),
|
|
16
|
+
updated_at TEXT NOT NULL DEFAULT (datetime('now')),
|
|
17
|
+
tags TEXT NOT NULL DEFAULT '[]'
|
|
18
|
+
);
|
|
19
|
+
|
|
20
|
+
CREATE TABLE IF NOT EXISTS stack_technologies (
|
|
21
|
+
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
22
|
+
stack_id TEXT NOT NULL REFERENCES stacks(id) ON DELETE CASCADE,
|
|
23
|
+
technology_id TEXT NOT NULL,
|
|
24
|
+
version TEXT NOT NULL,
|
|
25
|
+
port INTEGER,
|
|
26
|
+
config TEXT DEFAULT '{}',
|
|
27
|
+
UNIQUE(stack_id, technology_id)
|
|
28
|
+
);
|
|
29
|
+
|
|
30
|
+
CREATE TABLE IF NOT EXISTS stack_versions (
|
|
31
|
+
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
32
|
+
stack_id TEXT NOT NULL REFERENCES stacks(id) ON DELETE CASCADE,
|
|
33
|
+
version INTEGER NOT NULL,
|
|
34
|
+
changelog TEXT NOT NULL DEFAULT '',
|
|
35
|
+
snapshot TEXT NOT NULL,
|
|
36
|
+
created_at TEXT NOT NULL DEFAULT (datetime('now')),
|
|
37
|
+
UNIQUE(stack_id, version)
|
|
38
|
+
);
|
|
39
|
+
|
|
40
|
+
CREATE TABLE IF NOT EXISTS project_instances (
|
|
41
|
+
id TEXT PRIMARY KEY,
|
|
42
|
+
stack_id TEXT NOT NULL REFERENCES stacks(id),
|
|
43
|
+
name TEXT NOT NULL,
|
|
44
|
+
path TEXT NOT NULL,
|
|
45
|
+
template_id TEXT,
|
|
46
|
+
created_at TEXT NOT NULL DEFAULT (datetime('now')),
|
|
47
|
+
last_opened_at TEXT
|
|
48
|
+
);
|
|
49
|
+
|
|
50
|
+
CREATE TABLE IF NOT EXISTS project_services (
|
|
51
|
+
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
52
|
+
project_id TEXT NOT NULL REFERENCES project_instances(id) ON DELETE CASCADE,
|
|
53
|
+
service_name TEXT NOT NULL,
|
|
54
|
+
technology_id TEXT,
|
|
55
|
+
port INTEGER,
|
|
56
|
+
docker_container_id TEXT,
|
|
57
|
+
status TEXT DEFAULT 'not_started',
|
|
58
|
+
UNIQUE(project_id, service_name)
|
|
59
|
+
);
|
|
60
|
+
|
|
61
|
+
CREATE TABLE IF NOT EXISTS user_tech_notes (
|
|
62
|
+
tech_id TEXT PRIMARY KEY,
|
|
63
|
+
rating INTEGER CHECK(rating >= 1 AND rating <= 5),
|
|
64
|
+
notes TEXT DEFAULT '',
|
|
65
|
+
last_used_at TEXT
|
|
66
|
+
);
|
|
67
|
+
|
|
68
|
+
CREATE INDEX IF NOT EXISTS idx_stack_tech_stack ON stack_technologies(stack_id);
|
|
69
|
+
CREATE INDEX IF NOT EXISTS idx_stack_versions_stack ON stack_versions(stack_id);
|
|
70
|
+
CREATE INDEX IF NOT EXISTS idx_projects_stack ON project_instances(stack_id);
|
|
71
|
+
CREATE INDEX IF NOT EXISTS idx_project_services_project ON project_services(project_id);
|
|
72
|
+
|
|
73
|
+
CREATE TABLE IF NOT EXISTS custom_templates (
|
|
74
|
+
id TEXT PRIMARY KEY,
|
|
75
|
+
name TEXT NOT NULL UNIQUE,
|
|
76
|
+
description TEXT NOT NULL DEFAULT '',
|
|
77
|
+
profile TEXT NOT NULL DEFAULT 'standard',
|
|
78
|
+
technology_ids TEXT NOT NULL DEFAULT '[]',
|
|
79
|
+
created_at TEXT NOT NULL DEFAULT (datetime('now'))
|
|
80
|
+
);
|
|
81
|
+
`;
|
|
82
|
+
let db = null;
|
|
83
|
+
export function getDatabase(dbPath) {
|
|
84
|
+
if (db)
|
|
85
|
+
return db;
|
|
86
|
+
const resolvedPath = dbPath || getDefaultDbPath();
|
|
87
|
+
const dir = path.dirname(resolvedPath);
|
|
88
|
+
if (!fs.existsSync(dir))
|
|
89
|
+
fs.mkdirSync(dir, { recursive: true });
|
|
90
|
+
db = new Database(resolvedPath);
|
|
91
|
+
db.pragma("journal_mode = WAL");
|
|
92
|
+
db.pragma("foreign_keys = ON");
|
|
93
|
+
db.exec(SCHEMA);
|
|
94
|
+
return db;
|
|
95
|
+
}
|
|
96
|
+
export function closeDatabase() {
|
|
97
|
+
if (db) {
|
|
98
|
+
db.close();
|
|
99
|
+
db = null;
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
export function getDefaultDbPath() {
|
|
103
|
+
const home = process.env.HOME || process.env.USERPROFILE || ".";
|
|
104
|
+
return path.join(home, ".stackweld", "stackweld.db");
|
|
105
|
+
}
|
|
106
|
+
//# sourceMappingURL=database.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"database.js","sourceRoot":"","sources":["../../src/db/database.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,KAAK,EAAE,MAAM,SAAS,CAAC;AAC9B,OAAO,KAAK,IAAI,MAAM,WAAW,CAAC;AAClC,OAAO,QAAQ,MAAM,gBAAgB,CAAC;AAEtC,MAAM,MAAM,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAyEd,CAAC;AAEF,IAAI,EAAE,GAA6B,IAAI,CAAC;AAExC,MAAM,UAAU,WAAW,CAAC,MAAe;IACzC,IAAI,EAAE;QAAE,OAAO,EAAE,CAAC;IAElB,MAAM,YAAY,GAAG,MAAM,IAAI,gBAAgB,EAAE,CAAC;IAClD,MAAM,GAAG,GAAG,IAAI,CAAC,OAAO,CAAC,YAAY,CAAC,CAAC;IACvC,IAAI,CAAC,EAAE,CAAC,UAAU,CAAC,GAAG,CAAC;QAAE,EAAE,CAAC,SAAS,CAAC,GAAG,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IAEhE,EAAE,GAAG,IAAI,QAAQ,CAAC,YAAY,CAAC,CAAC;IAChC,EAAE,CAAC,MAAM,CAAC,oBAAoB,CAAC,CAAC;IAChC,EAAE,CAAC,MAAM,CAAC,mBAAmB,CAAC,CAAC;IAC/B,EAAE,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;IAEhB,OAAO,EAAE,CAAC;AACZ,CAAC;AAED,MAAM,UAAU,aAAa;IAC3B,IAAI,EAAE,EAAE,CAAC;QACP,EAAE,CAAC,KAAK,EAAE,CAAC;QACX,EAAE,GAAG,IAAI,CAAC;IACZ,CAAC;AACH,CAAC;AAED,MAAM,UAAU,gBAAgB;IAC9B,MAAM,IAAI,GAAG,OAAO,CAAC,GAAG,CAAC,IAAI,IAAI,OAAO,CAAC,GAAG,CAAC,WAAW,IAAI,GAAG,CAAC;IAChE,OAAO,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,YAAY,EAAE,cAAc,CAAC,CAAC;AACvD,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/db/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,WAAW,EAAE,gBAAgB,EAAE,MAAM,eAAe,CAAC"}
|
package/dist/db/index.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/db/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,WAAW,EAAE,gBAAgB,EAAE,MAAM,eAAe,CAAC"}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Compatibility Scorer — Calculates a 0-100 score for technology combinations.
|
|
3
|
+
* Goes beyond binary compatible/incompatible to show nuanced pairing quality.
|
|
4
|
+
*/
|
|
5
|
+
import type { Technology } from "../types/index.js";
|
|
6
|
+
export interface CompatibilityResult {
|
|
7
|
+
score: number;
|
|
8
|
+
grade: "S" | "A" | "B" | "C" | "D" | "F";
|
|
9
|
+
factors: CompatibilityFactor[];
|
|
10
|
+
recommendation: string;
|
|
11
|
+
}
|
|
12
|
+
export interface CompatibilityFactor {
|
|
13
|
+
label: string;
|
|
14
|
+
points: number;
|
|
15
|
+
description: string;
|
|
16
|
+
}
|
|
17
|
+
export interface StackScoreResult {
|
|
18
|
+
overall: number;
|
|
19
|
+
grade: string;
|
|
20
|
+
pairs: Array<{
|
|
21
|
+
a: string;
|
|
22
|
+
b: string;
|
|
23
|
+
score: number;
|
|
24
|
+
}>;
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* Score the compatibility between two technologies (0-100).
|
|
28
|
+
*/
|
|
29
|
+
export declare function scoreCompatibility(
|
|
30
|
+
techA: Technology,
|
|
31
|
+
techB: Technology,
|
|
32
|
+
): CompatibilityResult;
|
|
33
|
+
/**
|
|
34
|
+
* Score an entire stack by evaluating all unique pairs.
|
|
35
|
+
*/
|
|
36
|
+
export declare function scoreStack(technologies: Technology[]): StackScoreResult;
|
|
37
|
+
//# sourceMappingURL=compatibility-scorer.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"compatibility-scorer.d.ts","sourceRoot":"","sources":["../../src/engine/compatibility-scorer.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAC;AAEpD,MAAM,WAAW,mBAAmB;IAClC,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,CAAC;IACzC,OAAO,EAAE,mBAAmB,EAAE,CAAC;IAC/B,cAAc,EAAE,MAAM,CAAC;CACxB;AAED,MAAM,WAAW,mBAAmB;IAClC,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;IACf,WAAW,EAAE,MAAM,CAAC;CACrB;AAED,MAAM,WAAW,gBAAgB;IAC/B,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,KAAK,CAAC;QAAE,CAAC,EAAE,MAAM,CAAC;QAAC,CAAC,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;CACvD;AA2DD;;GAEG;AACH,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,UAAU,EAAE,KAAK,EAAE,UAAU,GAAG,mBAAmB,CAwG5F;AAED;;GAEG;AACH,wBAAgB,UAAU,CAAC,YAAY,EAAE,UAAU,EAAE,GAAG,gBAAgB,CA0BvE"}
|
|
@@ -0,0 +1,178 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Compatibility Scorer — Calculates a 0-100 score for technology combinations.
|
|
3
|
+
* Goes beyond binary compatible/incompatible to show nuanced pairing quality.
|
|
4
|
+
*/
|
|
5
|
+
// ─── Complementary category pairs ─────────────────────
|
|
6
|
+
const COMPLEMENTARY_PAIRS = new Set([
|
|
7
|
+
"frontend:backend",
|
|
8
|
+
"backend:frontend",
|
|
9
|
+
"database:orm",
|
|
10
|
+
"orm:database",
|
|
11
|
+
"frontend:styling",
|
|
12
|
+
"styling:frontend",
|
|
13
|
+
"frontend:orm",
|
|
14
|
+
"orm:frontend",
|
|
15
|
+
"backend:database",
|
|
16
|
+
"database:backend",
|
|
17
|
+
"runtime:frontend",
|
|
18
|
+
"frontend:runtime",
|
|
19
|
+
"runtime:backend",
|
|
20
|
+
"backend:runtime",
|
|
21
|
+
"backend:auth",
|
|
22
|
+
"auth:backend",
|
|
23
|
+
"frontend:auth",
|
|
24
|
+
"auth:frontend",
|
|
25
|
+
]);
|
|
26
|
+
// ─── Grade thresholds & recommendations ───────────────
|
|
27
|
+
function getGrade(score) {
|
|
28
|
+
if (score >= 90)
|
|
29
|
+
return "S";
|
|
30
|
+
if (score >= 75)
|
|
31
|
+
return "A";
|
|
32
|
+
if (score >= 60)
|
|
33
|
+
return "B";
|
|
34
|
+
if (score >= 45)
|
|
35
|
+
return "C";
|
|
36
|
+
if (score >= 25)
|
|
37
|
+
return "D";
|
|
38
|
+
return "F";
|
|
39
|
+
}
|
|
40
|
+
const RECOMMENDATIONS = {
|
|
41
|
+
S: "Excellent combination — these technologies are designed to work together.",
|
|
42
|
+
A: "Strong pairing with good ecosystem support.",
|
|
43
|
+
B: "Compatible — works well with minor configuration needed.",
|
|
44
|
+
C: "Neutral — no known issues but limited synergy.",
|
|
45
|
+
D: "Weak pairing — consider alternatives.",
|
|
46
|
+
F: "Incompatible — these technologies conflict.",
|
|
47
|
+
};
|
|
48
|
+
// ─── Runtime detection ────────────────────────────────
|
|
49
|
+
function getRuntime(tech) {
|
|
50
|
+
if (tech.category === "runtime")
|
|
51
|
+
return tech.id;
|
|
52
|
+
for (const req of tech.requires) {
|
|
53
|
+
if (["nodejs", "python", "go", "rust", "php", "bun", "deno"].includes(req)) {
|
|
54
|
+
return req;
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
return null;
|
|
58
|
+
}
|
|
59
|
+
// ─── Core scoring ─────────────────────────────────────
|
|
60
|
+
/**
|
|
61
|
+
* Score the compatibility between two technologies (0-100).
|
|
62
|
+
*/
|
|
63
|
+
export function scoreCompatibility(techA, techB) {
|
|
64
|
+
const factors = [];
|
|
65
|
+
let score = 50; // neutral baseline
|
|
66
|
+
// +25 if suggested pairing (either direction)
|
|
67
|
+
const aSuggestsB = techA.suggestedWith.includes(techB.id);
|
|
68
|
+
const bSuggestsA = techB.suggestedWith.includes(techA.id);
|
|
69
|
+
if (aSuggestsB || bSuggestsA) {
|
|
70
|
+
factors.push({
|
|
71
|
+
label: "Suggested pairing",
|
|
72
|
+
points: 25,
|
|
73
|
+
description: aSuggestsB && bSuggestsA
|
|
74
|
+
? `${techA.name} and ${techB.name} mutually recommend each other`
|
|
75
|
+
: aSuggestsB
|
|
76
|
+
? `${techA.name} suggests ${techB.name}`
|
|
77
|
+
: `${techB.name} suggests ${techA.name}`,
|
|
78
|
+
});
|
|
79
|
+
score += 25;
|
|
80
|
+
}
|
|
81
|
+
// +15 if shared runtime
|
|
82
|
+
const runtimeA = getRuntime(techA);
|
|
83
|
+
const runtimeB = getRuntime(techB);
|
|
84
|
+
if (runtimeA && runtimeB && runtimeA === runtimeB && techA.id !== techB.id) {
|
|
85
|
+
const runtimeName = runtimeA === "nodejs" ? "Node.js" : runtimeA;
|
|
86
|
+
factors.push({
|
|
87
|
+
label: "Shared runtime",
|
|
88
|
+
points: 15,
|
|
89
|
+
description: `Both use ${runtimeName}`,
|
|
90
|
+
});
|
|
91
|
+
score += 15;
|
|
92
|
+
}
|
|
93
|
+
// +10 if complementary categories
|
|
94
|
+
const catPair = `${techA.category}:${techB.category}`;
|
|
95
|
+
if (COMPLEMENTARY_PAIRS.has(catPair)) {
|
|
96
|
+
factors.push({
|
|
97
|
+
label: "Complementary categories",
|
|
98
|
+
points: 10,
|
|
99
|
+
description: `${techA.category} + ${techB.category}`,
|
|
100
|
+
});
|
|
101
|
+
score += 10;
|
|
102
|
+
}
|
|
103
|
+
// -50 if incompatible (either direction) — applied after positives, then clamp
|
|
104
|
+
const aIncompatB = techA.incompatibleWith.includes(techB.id);
|
|
105
|
+
const bIncompatA = techB.incompatibleWith.includes(techA.id);
|
|
106
|
+
if (aIncompatB || bIncompatA) {
|
|
107
|
+
factors.push({
|
|
108
|
+
label: "Incompatible",
|
|
109
|
+
points: -50,
|
|
110
|
+
description: aIncompatB && bIncompatA
|
|
111
|
+
? `${techA.name} and ${techB.name} are mutually incompatible`
|
|
112
|
+
: aIncompatB
|
|
113
|
+
? `${techA.name} lists ${techB.name} as incompatible`
|
|
114
|
+
: `${techB.name} lists ${techA.name} as incompatible`,
|
|
115
|
+
});
|
|
116
|
+
score -= 50;
|
|
117
|
+
}
|
|
118
|
+
// -15 if same category AND same runtime (competing technologies)
|
|
119
|
+
if (techA.category === techB.category &&
|
|
120
|
+
techA.id !== techB.id &&
|
|
121
|
+
runtimeA &&
|
|
122
|
+
runtimeB &&
|
|
123
|
+
runtimeA === runtimeB) {
|
|
124
|
+
factors.push({
|
|
125
|
+
label: "Same category and runtime",
|
|
126
|
+
points: -15,
|
|
127
|
+
description: `Both are ${techA.category} technologies for ${runtimeA === "nodejs" ? "Node.js" : runtimeA}`,
|
|
128
|
+
});
|
|
129
|
+
score -= 15;
|
|
130
|
+
}
|
|
131
|
+
// -5 if same default port (minor conflict)
|
|
132
|
+
if (techA.defaultPort &&
|
|
133
|
+
techB.defaultPort &&
|
|
134
|
+
techA.defaultPort === techB.defaultPort &&
|
|
135
|
+
techA.id !== techB.id) {
|
|
136
|
+
factors.push({
|
|
137
|
+
label: "Port conflict",
|
|
138
|
+
points: -5,
|
|
139
|
+
description: `Both default to port ${techA.defaultPort}`,
|
|
140
|
+
});
|
|
141
|
+
score -= 5;
|
|
142
|
+
}
|
|
143
|
+
// Clamp
|
|
144
|
+
score = Math.max(0, Math.min(100, score));
|
|
145
|
+
const grade = getGrade(score);
|
|
146
|
+
return {
|
|
147
|
+
score,
|
|
148
|
+
grade,
|
|
149
|
+
factors,
|
|
150
|
+
recommendation: RECOMMENDATIONS[grade],
|
|
151
|
+
};
|
|
152
|
+
}
|
|
153
|
+
/**
|
|
154
|
+
* Score an entire stack by evaluating all unique pairs.
|
|
155
|
+
*/
|
|
156
|
+
export function scoreStack(technologies) {
|
|
157
|
+
if (technologies.length < 2) {
|
|
158
|
+
return { overall: 100, grade: "S", pairs: [] };
|
|
159
|
+
}
|
|
160
|
+
const pairs = [];
|
|
161
|
+
for (let i = 0; i < technologies.length; i++) {
|
|
162
|
+
for (let j = i + 1; j < technologies.length; j++) {
|
|
163
|
+
const result = scoreCompatibility(technologies[i], technologies[j]);
|
|
164
|
+
pairs.push({
|
|
165
|
+
a: technologies[i].id,
|
|
166
|
+
b: technologies[j].id,
|
|
167
|
+
score: result.score,
|
|
168
|
+
});
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
const overall = pairs.length > 0 ? Math.round(pairs.reduce((sum, p) => sum + p.score, 0) / pairs.length) : 100;
|
|
172
|
+
return {
|
|
173
|
+
overall,
|
|
174
|
+
grade: getGrade(overall),
|
|
175
|
+
pairs,
|
|
176
|
+
};
|
|
177
|
+
}
|
|
178
|
+
//# sourceMappingURL=compatibility-scorer.js.map
|