@nudojs/parser 0.2.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,23 +1,42 @@
1
1
  {
2
2
  "name": "@nudojs/parser",
3
- "version": "0.2.0",
3
+ "version": "0.3.1",
4
+ "description": "Babel-based parser and directive extraction for Nudo",
4
5
  "type": "module",
5
- "main": "src/index.ts",
6
+ "license": "MIT",
7
+ "keywords": [
8
+ "nudo",
9
+ "type-inference",
10
+ "javascript",
11
+ "parser",
12
+ "babel",
13
+ "directives"
14
+ ],
15
+ "main": "./dist/index.js",
16
+ "types": "./dist/index.d.ts",
6
17
  "exports": {
7
- ".": "./src/index.ts"
18
+ ".": {
19
+ "types": "./dist/index.d.ts",
20
+ "default": "./dist/index.js"
21
+ }
8
22
  },
23
+ "files": [
24
+ "dist"
25
+ ],
9
26
  "repository": {
10
27
  "type": "git",
11
28
  "url": "git+https://github.com/nudojs/nudo.git",
12
29
  "directory": "packages/parser"
13
30
  },
31
+ "homepage": "https://github.com/nudojs/nudo/tree/main/packages/parser",
32
+ "bugs": "https://github.com/nudojs/nudo/issues",
14
33
  "publishConfig": {
15
34
  "access": "public",
16
35
  "provenance": true,
17
36
  "registry": "https://registry.npmjs.org"
18
37
  },
19
38
  "dependencies": {
20
- "@nudojs/core": "0.2.0"
39
+ "@nudojs/core": "0.3.1"
21
40
  },
22
41
  "scripts": {
23
42
  "build": "tsup src/index.ts --format esm --dts"
package/CHANGELOG.md DELETED
@@ -1,27 +0,0 @@
1
- # @nudojs/parser
2
-
3
- ## 0.2.0
4
-
5
- ### Minor Changes
6
-
7
- - 6c38283: docs and ci
8
- - 9f7f819: fix pkg info
9
- - c175f71: version
10
-
11
- ### Patch Changes
12
-
13
- - Updated dependencies [6c38283]
14
- - Updated dependencies [9f7f819]
15
- - Updated dependencies [c175f71]
16
- - @nudojs/core@0.2.0
17
-
18
- ## 0.1.0
19
-
20
- ### Minor Changes
21
-
22
- - Conceptual design and basic implementation.
23
-
24
- ### Patch Changes
25
-
26
- - Updated dependencies
27
- - @nudojs/core@0.1.0
@@ -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,93 +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
- });
76
-
77
- describe("@nudo:returns directive", () => {
78
- it("parses @nudo:returns with type", () => {
79
- const fns = getDirectives(`
80
- /**
81
- * @nudo:returns (T.number)
82
- * @nudo:case "test" (1, 2)
83
- */
84
- function add(a, b) { return a + b; }
85
- `);
86
- expect(fns.length).toBe(1);
87
- const returns = fns[0].directives.find((d) => d.kind === "returns");
88
- expect(returns).toBeDefined();
89
- if (returns && returns.kind === "returns") {
90
- expect(returns.expected).toEqual(T.number);
91
- }
92
- });
93
- });
@@ -1,129 +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 } from "@nudojs/core";
5
-
6
- describe("parseTypeValueExpr", () => {
7
- it("parses T.number", () => {
8
- expect(typeValueEquals(parseTypeValueExpr("T.number"), T.number)).toBe(true);
9
- });
10
-
11
- it("parses T.string", () => {
12
- expect(typeValueEquals(parseTypeValueExpr("T.string"), T.string)).toBe(true);
13
- });
14
-
15
- it("parses T.boolean", () => {
16
- expect(typeValueEquals(parseTypeValueExpr("T.boolean"), T.boolean)).toBe(true);
17
- });
18
-
19
- it("parses numeric literals", () => {
20
- expect(typeValueEquals(parseTypeValueExpr("42"), T.literal(42))).toBe(true);
21
- expect(typeValueEquals(parseTypeValueExpr("-3"), T.literal(-3))).toBe(true);
22
- expect(typeValueEquals(parseTypeValueExpr("1.5"), T.literal(1.5))).toBe(true);
23
- });
24
-
25
- it("parses string literals", () => {
26
- expect(typeValueEquals(parseTypeValueExpr('"hello"'), T.literal("hello"))).toBe(true);
27
- expect(typeValueEquals(parseTypeValueExpr("'world'"), T.literal("world"))).toBe(true);
28
- });
29
-
30
- it("parses boolean literals", () => {
31
- expect(typeValueEquals(parseTypeValueExpr("true"), T.literal(true))).toBe(true);
32
- expect(typeValueEquals(parseTypeValueExpr("false"), T.literal(false))).toBe(true);
33
- });
34
-
35
- it("parses null and undefined", () => {
36
- expect(typeValueEquals(parseTypeValueExpr("null"), T.literal(null))).toBe(true);
37
- expect(typeValueEquals(parseTypeValueExpr("undefined"), T.literal(undefined))).toBe(true);
38
- });
39
-
40
- it("parses T.literal(...)", () => {
41
- expect(typeValueEquals(parseTypeValueExpr("T.literal(42)"), T.literal(42))).toBe(true);
42
- expect(typeValueEquals(parseTypeValueExpr('T.literal("hi")'), T.literal("hi"))).toBe(true);
43
- });
44
-
45
- it("parses T.union(...)", () => {
46
- const result = parseTypeValueExpr("T.union(T.number, T.string)");
47
- const expected = T.union(T.number, T.string);
48
- expect(typeValueEquals(result, expected)).toBe(true);
49
- });
50
- });
51
-
52
- describe("extractDirectives", () => {
53
- it("extracts @nudo:case directives from function", () => {
54
- const source = `
55
- /**
56
- * @nudo:case "concrete" (1, 2)
57
- * @nudo:case "symbolic" (T.number, T.number)
58
- */
59
- function calc(a, b) {
60
- return a + b;
61
- }
62
- `;
63
- const ast = parse(source);
64
- const results = extractDirectives(ast);
65
- expect(results).toHaveLength(1);
66
- expect(results[0].name).toBe("calc");
67
- expect(results[0].directives).toHaveLength(2);
68
-
69
- const d0 = results[0].directives[0];
70
- expect(d0.kind).toBe("case");
71
- expect(d0.name).toBe("concrete");
72
- expect(d0.args).toHaveLength(2);
73
- expect(typeValueEquals(d0.args[0], T.literal(1))).toBe(true);
74
- expect(typeValueEquals(d0.args[1], T.literal(2))).toBe(true);
75
-
76
- const d1 = results[0].directives[1];
77
- expect(d1.name).toBe("symbolic");
78
- expect(typeValueEquals(d1.args[0], T.number)).toBe(true);
79
- expect(typeValueEquals(d1.args[1], T.number)).toBe(true);
80
- });
81
-
82
- it("extracts from multiple functions", () => {
83
- const source = `
84
- /**
85
- * @nudo:case "test" (1)
86
- */
87
- function foo(x) { return x; }
88
-
89
- /**
90
- * @nudo:case "test2" ("hello")
91
- */
92
- function bar(s) { return s; }
93
- `;
94
- const ast = parse(source);
95
- const results = extractDirectives(ast);
96
- expect(results).toHaveLength(2);
97
- expect(results[0].name).toBe("foo");
98
- expect(results[1].name).toBe("bar");
99
- });
100
-
101
- it("ignores functions without directives", () => {
102
- const source = `
103
- function noDirective(x) { return x; }
104
-
105
- /**
106
- * @nudo:case "test" (T.number)
107
- */
108
- function withDirective(x) { return x + 1; }
109
- `;
110
- const ast = parse(source);
111
- const results = extractDirectives(ast);
112
- expect(results).toHaveLength(1);
113
- expect(results[0].name).toBe("withDirective");
114
- });
115
-
116
- it("handles string arguments in case", () => {
117
- const source = `
118
- /**
119
- * @nudo:case "string test" ("hello", "world")
120
- */
121
- function greet(a, b) { return a + b; }
122
- `;
123
- const ast = parse(source);
124
- const results = extractDirectives(ast);
125
- expect(results[0].directives[0].args).toHaveLength(2);
126
- expect(typeValueEquals(results[0].directives[0].args[0], T.literal("hello"))).toBe(true);
127
- expect(typeValueEquals(results[0].directives[0].args[1], T.literal("world"))).toBe(true);
128
- });
129
- });