@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 CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@nudojs/parser",
3
- "version": "0.3.0",
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": "src/index.ts",
15
+ "main": "./dist/index.js",
16
+ "types": "./dist/index.d.ts",
16
17
  "exports": {
17
- ".": "./src/index.ts"
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.0"
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
- });