@nudojs/service 0.2.0 → 0.2.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,165 @@
1
+ import { describe, it, expect } from "vitest";
2
+ import { typeValueToString } from "@nudojs/core";
3
+ import { analyzeFile } from "../analyzer.ts";
4
+
5
+ describe("@nudo:as directive", () => {
6
+ it("overrides VariableDeclaration init value", () => {
7
+ const source = `
8
+ /// @nudo:env es
9
+
10
+ /**
11
+ * @nudo:case "test" (T.string)
12
+ */
13
+ function loadConfig(path) {
14
+ // @nudo:as T.object({ port: T.number, host: T.string })
15
+ const config = JSON.parse(path);
16
+ return config;
17
+ }
18
+ `;
19
+ const result = analyzeFile("/test/as.js", source);
20
+ const res = typeValueToString(result.functions[0].cases[0].result);
21
+ expect(res).toContain("port: number");
22
+ expect(res).toContain("host: string");
23
+ });
24
+
25
+ it("overrides ReturnStatement value", () => {
26
+ const source = `
27
+ /// @nudo:env es
28
+
29
+ /**
30
+ * @nudo:case "test" (T.string)
31
+ */
32
+ function loadConfig(path) {
33
+ // @nudo:as T.object({ name: T.string, age: T.number })
34
+ return JSON.parse(path);
35
+ }
36
+ `;
37
+ const result = analyzeFile("/test/as.js", source);
38
+ const res = typeValueToString(result.functions[0].cases[0].result);
39
+ expect(res).toContain("name: string");
40
+ expect(res).toContain("age: number");
41
+ });
42
+
43
+ it("does not affect statements without @nudo:as", () => {
44
+ const source = `
45
+ /// @nudo:env es
46
+
47
+ /**
48
+ * @nudo:case "test" (5)
49
+ */
50
+ function add(x) {
51
+ // @nudo:as T.string
52
+ const a = x + 1;
53
+ const b = x + 2;
54
+ return b;
55
+ }
56
+ `;
57
+ const result = analyzeFile("/test/as.js", source);
58
+ expect(typeValueToString(result.functions[0].cases[0].result)).toBe("7");
59
+ });
60
+ });
61
+
62
+ describe("@nudo:replace directive", () => {
63
+ it("replaces a sub-expression by source text match", () => {
64
+ const source = `
65
+ /// @nudo:env es
66
+
67
+ /**
68
+ * @nudo:case "test" (T.string)
69
+ */
70
+ function process(input) {
71
+ // @nudo:replace JSON.parse(input) T.object({ id: T.number })
72
+ const data = JSON.parse(input);
73
+ return data.id;
74
+ }
75
+ `;
76
+ const result = analyzeFile("/test/replace.js", source);
77
+ expect(typeValueToString(result.functions[0].cases[0].result)).toBe("number");
78
+ });
79
+
80
+ it("replaces only the matching sub-expression, not the whole line", () => {
81
+ const source = `
82
+ /**
83
+ * @nudo:case "test" (5, 10)
84
+ */
85
+ function compute(a, b) {
86
+ // @nudo:replace a T.literal(100)
87
+ const result = a + b;
88
+ return result;
89
+ }
90
+ `;
91
+ const result = analyzeFile("/test/replace.js", source);
92
+ expect(typeValueToString(result.functions[0].cases[0].result)).toBe("110");
93
+ });
94
+
95
+ it("does not match partial identifiers", () => {
96
+ const source = `
97
+ /**
98
+ * @nudo:case "test" ()
99
+ */
100
+ function test() {
101
+ const aa = 1;
102
+ const a = 2;
103
+ // @nudo:replace a T.literal(99)
104
+ const result = aa + a;
105
+ return result;
106
+ }
107
+ `;
108
+ const result = analyzeFile("/test/replace.js", source);
109
+ expect(typeValueToString(result.functions[0].cases[0].result)).toBe("100");
110
+ });
111
+
112
+ it("supports member expression replacement", () => {
113
+ const source = `
114
+ /**
115
+ * @nudo:case "test" (T.object({ data: T.unknown }))
116
+ */
117
+ function process(res) {
118
+ // @nudo:replace res.data T.array(T.object({ id: T.number, name: T.string }))
119
+ const items = res.data;
120
+ return items;
121
+ }
122
+ `;
123
+ const result = analyzeFile("/test/replace.js", source);
124
+ const res = typeValueToString(result.functions[0].cases[0].result);
125
+ expect(res).toContain("id: number");
126
+ expect(res).toContain("name: string");
127
+ });
128
+
129
+ it("replacement only affects the next statement", () => {
130
+ const source = `
131
+ /**
132
+ * @nudo:case "test" (5, 10)
133
+ */
134
+ function compute(a, b) {
135
+ // @nudo:replace a T.literal(100)
136
+ const x = a + b;
137
+ const y = a + b;
138
+ return y;
139
+ }
140
+ `;
141
+ const result = analyzeFile("/test/replace.js", source);
142
+ expect(typeValueToString(result.functions[0].cases[0].result)).toBe("15");
143
+ });
144
+ });
145
+
146
+ describe("@nudo:as and @nudo:replace coexistence", () => {
147
+ it("both can be used in the same function", () => {
148
+ const source = `
149
+ /// @nudo:env es
150
+
151
+ /**
152
+ * @nudo:case "test" (T.string)
153
+ */
154
+ function process(input) {
155
+ // @nudo:as T.object({ name: T.string, score: T.number })
156
+ const data = JSON.parse(input);
157
+ // @nudo:replace data.score T.literal(100)
158
+ const result = data.score;
159
+ return result;
160
+ }
161
+ `;
162
+ const result = analyzeFile("/test/both.js", source);
163
+ expect(typeValueToString(result.functions[0].cases[0].result)).toBe("100");
164
+ });
165
+ });