@nudojs/parser 0.3.0 → 0.3.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.
- package/package.json +11 -4
- package/CHANGELOG.md +0 -43
- package/src/__tests__/directives-inline.test.ts +0 -95
- package/src/__tests__/directives-phase2.test.ts +0 -113
- package/src/__tests__/directives-phase3.test.ts +0 -75
- package/src/__tests__/directives.test.ts +0 -411
- package/src/__tests__/mock-directive.test.ts +0 -115
- package/src/__tests__/sinon-directive.test.ts +0 -200
- package/src/directives.ts +0 -754
- package/src/index.ts +0 -23
- package/src/parse.ts +0 -15
- package/tsconfig.json +0 -9
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@nudojs/parser",
|
|
3
|
-
"version": "0.3.
|
|
3
|
+
"version": "0.3.1",
|
|
4
4
|
"description": "Babel-based parser and directive extraction for Nudo",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|
|
@@ -12,10 +12,17 @@
|
|
|
12
12
|
"babel",
|
|
13
13
|
"directives"
|
|
14
14
|
],
|
|
15
|
-
"main": "
|
|
15
|
+
"main": "./dist/index.js",
|
|
16
|
+
"types": "./dist/index.d.ts",
|
|
16
17
|
"exports": {
|
|
17
|
-
".":
|
|
18
|
+
".": {
|
|
19
|
+
"types": "./dist/index.d.ts",
|
|
20
|
+
"default": "./dist/index.js"
|
|
21
|
+
}
|
|
18
22
|
},
|
|
23
|
+
"files": [
|
|
24
|
+
"dist"
|
|
25
|
+
],
|
|
19
26
|
"repository": {
|
|
20
27
|
"type": "git",
|
|
21
28
|
"url": "git+https://github.com/nudojs/nudo.git",
|
|
@@ -29,7 +36,7 @@
|
|
|
29
36
|
"registry": "https://registry.npmjs.org"
|
|
30
37
|
},
|
|
31
38
|
"dependencies": {
|
|
32
|
-
"@nudojs/core": "0.3.
|
|
39
|
+
"@nudojs/core": "0.3.1"
|
|
33
40
|
},
|
|
34
41
|
"scripts": {
|
|
35
42
|
"build": "tsup src/index.ts --format esm --dts"
|
package/CHANGELOG.md
DELETED
|
@@ -1,43 +0,0 @@
|
|
|
1
|
-
# @nudojs/parser
|
|
2
|
-
|
|
3
|
-
## 0.3.0
|
|
4
|
-
|
|
5
|
-
### Minor Changes
|
|
6
|
-
|
|
7
|
-
- 5786fa5: Improve `@nudo:mock` parsing for sinon-style stubs and share parse/strip with core.
|
|
8
|
-
|
|
9
|
-
- Support `stub().onFirstCall()`, `stub().callsFake(fn)`, and `sinon.`-prefixed chains as the same MockHelper shape TypeValue/Abs already consume.
|
|
10
|
-
- Drop the unused `ReturnsDirective` / `@nudo:returns` directive type (contracts use `@nudo:refine`).
|
|
11
|
-
- `parse()` now strips types unconditionally via core `parseSource` (shared AST cache).
|
|
12
|
-
|
|
13
|
-
### Patch Changes
|
|
14
|
-
|
|
15
|
-
- Updated dependencies [5786fa5]
|
|
16
|
-
- Updated dependencies [5786fa5]
|
|
17
|
-
- @nudojs/core@0.3.0
|
|
18
|
-
|
|
19
|
-
## 0.2.0
|
|
20
|
-
|
|
21
|
-
### Minor Changes
|
|
22
|
-
|
|
23
|
-
- 6c38283: docs and ci
|
|
24
|
-
- 9f7f819: fix pkg info
|
|
25
|
-
- c175f71: version
|
|
26
|
-
|
|
27
|
-
### Patch Changes
|
|
28
|
-
|
|
29
|
-
- Updated dependencies [6c38283]
|
|
30
|
-
- Updated dependencies [9f7f819]
|
|
31
|
-
- Updated dependencies [c175f71]
|
|
32
|
-
- @nudojs/core@0.2.0
|
|
33
|
-
|
|
34
|
-
## 0.1.0
|
|
35
|
-
|
|
36
|
-
### Minor Changes
|
|
37
|
-
|
|
38
|
-
- Conceptual design and basic implementation.
|
|
39
|
-
|
|
40
|
-
### Patch Changes
|
|
41
|
-
|
|
42
|
-
- Updated dependencies
|
|
43
|
-
- @nudojs/core@0.1.0
|
|
@@ -1,95 +0,0 @@
|
|
|
1
|
-
import { describe, it, expect } from "vitest";
|
|
2
|
-
import { parse } from "../parse.ts";
|
|
3
|
-
import { extractInlineDirectives } from "../directives.ts";
|
|
4
|
-
|
|
5
|
-
function getFirstStmtDirectives(source: string) {
|
|
6
|
-
const ast = parse(source);
|
|
7
|
-
const body = ast.program.body;
|
|
8
|
-
for (const stmt of body) {
|
|
9
|
-
const directives = extractInlineDirectives(stmt);
|
|
10
|
-
if (directives.length > 0) return directives;
|
|
11
|
-
}
|
|
12
|
-
return [];
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
describe("extractInlineDirectives", () => {
|
|
16
|
-
it("extracts @nudo:as directive", () => {
|
|
17
|
-
const source = `
|
|
18
|
-
// @nudo:as T.object({ port: T.number })
|
|
19
|
-
const config = JSON.parse(text);
|
|
20
|
-
`;
|
|
21
|
-
const directives = getFirstStmtDirectives(source);
|
|
22
|
-
expect(directives).toHaveLength(1);
|
|
23
|
-
expect(directives[0].kind).toBe("as");
|
|
24
|
-
if (directives[0].kind === "as") {
|
|
25
|
-
expect(directives[0].typeExpr.kind).toBe("object");
|
|
26
|
-
}
|
|
27
|
-
});
|
|
28
|
-
|
|
29
|
-
it("extracts @nudo:replace directive with identifier target", () => {
|
|
30
|
-
const source = `
|
|
31
|
-
// @nudo:replace a T.number
|
|
32
|
-
const x = a + b;
|
|
33
|
-
`;
|
|
34
|
-
const directives = getFirstStmtDirectives(source);
|
|
35
|
-
expect(directives).toHaveLength(1);
|
|
36
|
-
expect(directives[0].kind).toBe("replace");
|
|
37
|
-
if (directives[0].kind === "replace") {
|
|
38
|
-
expect(directives[0].targetSource).toBe("a");
|
|
39
|
-
expect(directives[0].typeExpr.kind).toBe("primitive");
|
|
40
|
-
}
|
|
41
|
-
});
|
|
42
|
-
|
|
43
|
-
it("extracts @nudo:replace directive with member expression target", () => {
|
|
44
|
-
const source = `
|
|
45
|
-
// @nudo:replace res.data T.array(T.number)
|
|
46
|
-
const items = res.data;
|
|
47
|
-
`;
|
|
48
|
-
const directives = getFirstStmtDirectives(source);
|
|
49
|
-
expect(directives).toHaveLength(1);
|
|
50
|
-
if (directives[0].kind === "replace") {
|
|
51
|
-
expect(directives[0].targetSource).toBe("res.data");
|
|
52
|
-
}
|
|
53
|
-
});
|
|
54
|
-
|
|
55
|
-
it("extracts @nudo:replace with call expression target", () => {
|
|
56
|
-
const source = `
|
|
57
|
-
// @nudo:replace JSON.parse(input) T.object({ id: T.number })
|
|
58
|
-
const data = JSON.parse(input);
|
|
59
|
-
`;
|
|
60
|
-
const directives = getFirstStmtDirectives(source);
|
|
61
|
-
expect(directives).toHaveLength(1);
|
|
62
|
-
if (directives[0].kind === "replace") {
|
|
63
|
-
expect(directives[0].targetSource).toBe("JSON.parse(input)");
|
|
64
|
-
}
|
|
65
|
-
});
|
|
66
|
-
|
|
67
|
-
it("extracts multiple directives on the same statement", () => {
|
|
68
|
-
const source = `
|
|
69
|
-
// @nudo:replace a T.number
|
|
70
|
-
// @nudo:replace b T.string
|
|
71
|
-
const x = a + b;
|
|
72
|
-
`;
|
|
73
|
-
const directives = getFirstStmtDirectives(source);
|
|
74
|
-
expect(directives).toHaveLength(2);
|
|
75
|
-
expect(directives[0].kind).toBe("replace");
|
|
76
|
-
expect(directives[1].kind).toBe("replace");
|
|
77
|
-
});
|
|
78
|
-
|
|
79
|
-
it("returns empty for statements without directives", () => {
|
|
80
|
-
const source = `
|
|
81
|
-
const x = 1 + 2;
|
|
82
|
-
`;
|
|
83
|
-
const directives = getFirstStmtDirectives(source);
|
|
84
|
-
expect(directives).toHaveLength(0);
|
|
85
|
-
});
|
|
86
|
-
|
|
87
|
-
it("ignores block comments", () => {
|
|
88
|
-
const source = `
|
|
89
|
-
/* @nudo:as T.number */
|
|
90
|
-
const x = 1;
|
|
91
|
-
`;
|
|
92
|
-
const directives = getFirstStmtDirectives(source);
|
|
93
|
-
expect(directives).toHaveLength(0);
|
|
94
|
-
});
|
|
95
|
-
});
|
|
@@ -1,113 +0,0 @@
|
|
|
1
|
-
import { describe, it, expect } from "vitest";
|
|
2
|
-
import { parse } from "../parse.ts";
|
|
3
|
-
import { extractDirectives, parseTypeValueExpr } from "../directives.ts";
|
|
4
|
-
import { T, typeValueEquals, typeValueToString } from "@nudojs/core";
|
|
5
|
-
|
|
6
|
-
describe("parseTypeValueExpr: Phase 2 enhancements", () => {
|
|
7
|
-
it("parses T.array(T.number)", () => {
|
|
8
|
-
const result = parseTypeValueExpr("T.array(T.number)");
|
|
9
|
-
expect(result.kind).toBe("array");
|
|
10
|
-
if (result.kind === "array") {
|
|
11
|
-
expect(typeValueEquals(result.element, T.number)).toBe(true);
|
|
12
|
-
}
|
|
13
|
-
});
|
|
14
|
-
|
|
15
|
-
it("parses T.tuple([T.number, T.string])", () => {
|
|
16
|
-
const result = parseTypeValueExpr("T.tuple([T.number, T.string])");
|
|
17
|
-
expect(result.kind).toBe("tuple");
|
|
18
|
-
if (result.kind === "tuple") {
|
|
19
|
-
expect(result.elements).toHaveLength(2);
|
|
20
|
-
expect(typeValueEquals(result.elements[0], T.number)).toBe(true);
|
|
21
|
-
expect(typeValueEquals(result.elements[1], T.string)).toBe(true);
|
|
22
|
-
}
|
|
23
|
-
});
|
|
24
|
-
|
|
25
|
-
it("parses T.object({ x: T.number, y: T.string })", () => {
|
|
26
|
-
const result = parseTypeValueExpr("T.object({ x: T.number, y: T.string })");
|
|
27
|
-
expect(result.kind).toBe("object");
|
|
28
|
-
if (result.kind === "object") {
|
|
29
|
-
expect(typeValueEquals(result.properties.x, T.number)).toBe(true);
|
|
30
|
-
expect(typeValueEquals(result.properties.y, T.string)).toBe(true);
|
|
31
|
-
}
|
|
32
|
-
});
|
|
33
|
-
|
|
34
|
-
it("parses nested T.object with T.array", () => {
|
|
35
|
-
const result = parseTypeValueExpr("T.object({ items: T.array(T.number) })");
|
|
36
|
-
expect(result.kind).toBe("object");
|
|
37
|
-
if (result.kind === "object") {
|
|
38
|
-
expect(result.properties.items.kind).toBe("array");
|
|
39
|
-
}
|
|
40
|
-
});
|
|
41
|
-
|
|
42
|
-
it("parses T.object({})", () => {
|
|
43
|
-
const result = parseTypeValueExpr("T.object({})");
|
|
44
|
-
expect(result.kind).toBe("object");
|
|
45
|
-
if (result.kind === "object") {
|
|
46
|
-
expect(Object.keys(result.properties)).toHaveLength(0);
|
|
47
|
-
}
|
|
48
|
-
});
|
|
49
|
-
|
|
50
|
-
it("parses T.tuple([])", () => {
|
|
51
|
-
const result = parseTypeValueExpr("T.tuple([])");
|
|
52
|
-
expect(result.kind).toBe("tuple");
|
|
53
|
-
if (result.kind === "tuple") {
|
|
54
|
-
expect(result.elements).toHaveLength(0);
|
|
55
|
-
}
|
|
56
|
-
});
|
|
57
|
-
});
|
|
58
|
-
|
|
59
|
-
describe("extractDirectives: @nudo:mock", () => {
|
|
60
|
-
it("extracts inline mock directive", () => {
|
|
61
|
-
const source = `
|
|
62
|
-
/**
|
|
63
|
-
* @nudo:mock fetch = T.unknown
|
|
64
|
-
* @nudo:case "test" (1)
|
|
65
|
-
*/
|
|
66
|
-
function foo(x) { return x; }
|
|
67
|
-
`;
|
|
68
|
-
const ast = parse(source);
|
|
69
|
-
const results = extractDirectives(ast);
|
|
70
|
-
expect(results).toHaveLength(1);
|
|
71
|
-
const mocks = results[0].directives.filter((d) => d.kind === "mock");
|
|
72
|
-
expect(mocks).toHaveLength(1);
|
|
73
|
-
expect(mocks[0].kind).toBe("mock");
|
|
74
|
-
if (mocks[0].kind === "mock") {
|
|
75
|
-
expect(mocks[0].name).toBe("fetch");
|
|
76
|
-
expect(mocks[0].expression).toBe("T.unknown");
|
|
77
|
-
}
|
|
78
|
-
});
|
|
79
|
-
|
|
80
|
-
it("extracts mock from file directive", () => {
|
|
81
|
-
const source = `
|
|
82
|
-
/**
|
|
83
|
-
* @nudo:mock utils from "./utils.mock.js"
|
|
84
|
-
* @nudo:case "test" (1)
|
|
85
|
-
*/
|
|
86
|
-
function foo(x) { return x; }
|
|
87
|
-
`;
|
|
88
|
-
const ast = parse(source);
|
|
89
|
-
const results = extractDirectives(ast);
|
|
90
|
-
const mocks = results[0].directives.filter((d) => d.kind === "mock");
|
|
91
|
-
expect(mocks).toHaveLength(1);
|
|
92
|
-
if (mocks[0].kind === "mock") {
|
|
93
|
-
expect(mocks[0].name).toBe("utils");
|
|
94
|
-
expect(mocks[0].fromPath).toBe("./utils.mock.js");
|
|
95
|
-
}
|
|
96
|
-
});
|
|
97
|
-
|
|
98
|
-
it("extracts both mock and case directives", () => {
|
|
99
|
-
const source = `
|
|
100
|
-
/**
|
|
101
|
-
* @nudo:mock helper = T.number
|
|
102
|
-
* @nudo:case "test" (T.number)
|
|
103
|
-
*/
|
|
104
|
-
function foo(x) { return x; }
|
|
105
|
-
`;
|
|
106
|
-
const ast = parse(source);
|
|
107
|
-
const results = extractDirectives(ast);
|
|
108
|
-
const mocks = results[0].directives.filter((d) => d.kind === "mock");
|
|
109
|
-
const cases = results[0].directives.filter((d) => d.kind === "case");
|
|
110
|
-
expect(mocks).toHaveLength(1);
|
|
111
|
-
expect(cases).toHaveLength(1);
|
|
112
|
-
});
|
|
113
|
-
});
|
|
@@ -1,75 +0,0 @@
|
|
|
1
|
-
import { describe, it, expect } from "vitest";
|
|
2
|
-
import { T } from "@nudojs/core";
|
|
3
|
-
import { extractDirectives } from "../directives.ts";
|
|
4
|
-
import { parse } from "../parse.ts";
|
|
5
|
-
|
|
6
|
-
function getDirectives(source: string) {
|
|
7
|
-
const ast = parse(source);
|
|
8
|
-
return extractDirectives(ast);
|
|
9
|
-
}
|
|
10
|
-
|
|
11
|
-
describe("@nudo:pure directive", () => {
|
|
12
|
-
it("parses @nudo:pure", () => {
|
|
13
|
-
const fns = getDirectives(`
|
|
14
|
-
/**
|
|
15
|
-
* @nudo:pure
|
|
16
|
-
* @nudo:case "test" (1, 2)
|
|
17
|
-
*/
|
|
18
|
-
function add(a, b) { return a + b; }
|
|
19
|
-
`);
|
|
20
|
-
expect(fns.length).toBe(1);
|
|
21
|
-
const directives = fns[0].directives;
|
|
22
|
-
expect(directives.some((d) => d.kind === "pure")).toBe(true);
|
|
23
|
-
expect(directives.some((d) => d.kind === "case")).toBe(true);
|
|
24
|
-
});
|
|
25
|
-
});
|
|
26
|
-
|
|
27
|
-
describe("@nudo:skip directive", () => {
|
|
28
|
-
it("parses @nudo:skip without return type", () => {
|
|
29
|
-
const fns = getDirectives(`
|
|
30
|
-
/**
|
|
31
|
-
* @nudo:skip
|
|
32
|
-
*/
|
|
33
|
-
function external() {}
|
|
34
|
-
`);
|
|
35
|
-
expect(fns.length).toBe(1);
|
|
36
|
-
const skip = fns[0].directives.find((d) => d.kind === "skip");
|
|
37
|
-
expect(skip).toBeDefined();
|
|
38
|
-
if (skip && skip.kind === "skip") {
|
|
39
|
-
expect(skip.returns).toBeUndefined();
|
|
40
|
-
}
|
|
41
|
-
});
|
|
42
|
-
|
|
43
|
-
it("parses @nudo:skip with return type", () => {
|
|
44
|
-
const fns = getDirectives(`
|
|
45
|
-
/**
|
|
46
|
-
* @nudo:skip T.number
|
|
47
|
-
*/
|
|
48
|
-
function external() {}
|
|
49
|
-
`);
|
|
50
|
-
expect(fns.length).toBe(1);
|
|
51
|
-
const skip = fns[0].directives.find((d) => d.kind === "skip");
|
|
52
|
-
expect(skip).toBeDefined();
|
|
53
|
-
if (skip && skip.kind === "skip") {
|
|
54
|
-
expect(skip.returns).toEqual(T.number);
|
|
55
|
-
}
|
|
56
|
-
});
|
|
57
|
-
});
|
|
58
|
-
|
|
59
|
-
describe("@nudo:sample directive", () => {
|
|
60
|
-
it("parses @nudo:sample with count", () => {
|
|
61
|
-
const fns = getDirectives(`
|
|
62
|
-
/**
|
|
63
|
-
* @nudo:sample 5
|
|
64
|
-
* @nudo:case "test" (T.number)
|
|
65
|
-
*/
|
|
66
|
-
function loop(n) { return n; }
|
|
67
|
-
`);
|
|
68
|
-
expect(fns.length).toBe(1);
|
|
69
|
-
const sample = fns[0].directives.find((d) => d.kind === "sample");
|
|
70
|
-
expect(sample).toBeDefined();
|
|
71
|
-
if (sample && sample.kind === "sample") {
|
|
72
|
-
expect(sample.count).toBe(5);
|
|
73
|
-
}
|
|
74
|
-
});
|
|
75
|
-
});
|