@nudojs/parser 0.5.1 → 1.0.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/dist/index.d.ts +4 -6
- package/dist/index.js +39 -72
- package/package.json +2 -2
package/dist/index.d.ts
CHANGED
|
@@ -18,7 +18,7 @@ declare function parse(source: string, opts?: {
|
|
|
18
18
|
type CaseDirective = {
|
|
19
19
|
kind: "case";
|
|
20
20
|
name: string;
|
|
21
|
-
/** 无损参数 Abs(case
|
|
21
|
+
/** 无损参数 Abs(case 文法唯一真理源:约束构建器 / 具体字面量) */
|
|
22
22
|
argsAbs: Abs[];
|
|
23
23
|
/** `=> expected` 断言 Abs */
|
|
24
24
|
expected?: Abs;
|
|
@@ -82,14 +82,12 @@ type FunctionWithDirectives = {
|
|
|
82
82
|
directives: Directive[];
|
|
83
83
|
};
|
|
84
84
|
/**
|
|
85
|
-
* case
|
|
86
|
-
*
|
|
85
|
+
* case 实参 / 指令类型表达式唯一文法:约束构建器优先,其余为具体字面量、
|
|
86
|
+
* 结构字面量与箭头函数。`T.*` 文法已物理删除。
|
|
87
87
|
*/
|
|
88
88
|
declare function parseCaseArgExpr(expr: string): Abs;
|
|
89
|
-
/** @deprecated 旧名兼容;等价 parseCaseArgExpr */
|
|
90
|
-
declare function parseTypeValueExpr(expr: string): Abs;
|
|
91
89
|
declare function extractDirectives(ast: Node): FunctionWithDirectives[];
|
|
92
90
|
declare function extractInlineDirectives(node: Node): InlineDirective[];
|
|
93
91
|
declare function extractFileDirectives(ast: Node): FileDirective[];
|
|
94
92
|
|
|
95
|
-
export { type AsDirective, type CaseDirective, type Directive, type EnvDirective, type FileDirective, type FunctionWithDirectives, type InlineDirective, type MockDirective, type MockModuleDirective, type PureDirective, type ReplaceDirective, type SampleDirective, type SinonExpression, type SkipDirective, extractDirectives, extractFileDirectives, extractInlineDirectives, parse, parseCaseArgExpr
|
|
93
|
+
export { type AsDirective, type CaseDirective, type Directive, type EnvDirective, type FileDirective, type FunctionWithDirectives, type InlineDirective, type MockDirective, type MockModuleDirective, type PureDirective, type ReplaceDirective, type SampleDirective, type SinonExpression, type SkipDirective, extractDirectives, extractFileDirectives, extractInlineDirectives, parse, parseCaseArgExpr };
|
package/dist/index.js
CHANGED
|
@@ -14,9 +14,6 @@ import {
|
|
|
14
14
|
mock,
|
|
15
15
|
abs as makeAbs,
|
|
16
16
|
lit as termLit,
|
|
17
|
-
num,
|
|
18
|
-
str,
|
|
19
|
-
bool,
|
|
20
17
|
numLit,
|
|
21
18
|
strLit,
|
|
22
19
|
boolLit,
|
|
@@ -46,17 +43,13 @@ function absLit(v) {
|
|
|
46
43
|
if (v === null) return absNullLit();
|
|
47
44
|
return absUndefLit();
|
|
48
45
|
}
|
|
49
|
-
function absUnion(members) {
|
|
50
|
-
if (members.length === 0) return absExact({ k: "never" });
|
|
51
|
-
return members.reduce((acc, m) => joinAbs(acc, m));
|
|
52
|
-
}
|
|
53
46
|
var CASE_NAME_REGEX = /@nudo:case\s+"([^"]+)"\s*\(/g;
|
|
54
47
|
var MOCK_INLINE_REGEX = /@nudo:mock\s+(\w+)\s*=\s*(.+)/g;
|
|
55
48
|
var MOCK_FROM_REGEX = /@nudo:mock\s+(\w+)\s+from\s+"([^"]+)"/g;
|
|
56
49
|
var PURE_REGEX = /@nudo:pure\b/g;
|
|
57
50
|
var SKIP_REGEX = /@nudo:skip(?:\s+(.+))?/g;
|
|
58
51
|
var SAMPLE_REGEX = /@nudo:sample\s+(\d+)/g;
|
|
59
|
-
var CONSTRAINT_EXPR_RE = /^(number|string|boolean|array|shape|lit|union|fn|partial|pick|omit|record|required|readonly|nonNullable|and)\s*\(/;
|
|
52
|
+
var CONSTRAINT_EXPR_RE = /^(number|string|boolean|any|array|shape|lit|union|fn|partial|pick|omit|record|required|readonly|nonNullable|and)\s*\(/;
|
|
60
53
|
function tryParseConstraint(expr) {
|
|
61
54
|
const s = expr.trim();
|
|
62
55
|
if (!CONSTRAINT_EXPR_RE.test(s)) return void 0;
|
|
@@ -85,15 +78,15 @@ function flattenPreds(preds) {
|
|
|
85
78
|
function constraintSelfEqLit(c, selfIds) {
|
|
86
79
|
const leaves = flattenPreds(c.preds);
|
|
87
80
|
const eqs = leaves.filter((p2) => p2.op === "eq");
|
|
88
|
-
if (eqs.length !== 1) return
|
|
81
|
+
if (eqs.length !== 1) return { found: false };
|
|
89
82
|
const p = eqs[0];
|
|
90
|
-
if (p.op !== "eq") return
|
|
83
|
+
if (p.op !== "eq") return { found: false };
|
|
91
84
|
const isSelf = (t) => t.op === "var" && typeof t.id === "string" && selfIds.includes(t.id);
|
|
92
85
|
const a = p.a;
|
|
93
86
|
const b = p.b;
|
|
94
|
-
if (isSelf(a) && b.op === "lit") return b.value;
|
|
95
|
-
if (isSelf(b) && a.op === "lit") return a.value;
|
|
96
|
-
return
|
|
87
|
+
if (isSelf(a) && b.op === "lit") return { found: true, value: b.value };
|
|
88
|
+
if (isSelf(b) && a.op === "lit") return { found: true, value: a.value };
|
|
89
|
+
return { found: false };
|
|
97
90
|
}
|
|
98
91
|
function constraintToCaseArgAbs(c) {
|
|
99
92
|
if (c.members && c.members.length > 0) {
|
|
@@ -102,10 +95,32 @@ function constraintToCaseArgAbs(c) {
|
|
|
102
95
|
return { shape: { k: "sum", members: parts }, conf: "path" };
|
|
103
96
|
}
|
|
104
97
|
const selfIds = [SELF, "__arg", "__nudo_self__"];
|
|
105
|
-
const
|
|
106
|
-
if (
|
|
107
|
-
|
|
108
|
-
|
|
98
|
+
const litRes = constraintSelfEqLit(c, selfIds);
|
|
99
|
+
if (litRes.found) {
|
|
100
|
+
const lv = litRes.value;
|
|
101
|
+
if (typeof lv === "number" && !Number.isNaN(lv)) return numLit(lv);
|
|
102
|
+
if (typeof lv === "string") return strLit(lv);
|
|
103
|
+
if (typeof lv === "boolean") return boolLit(lv);
|
|
104
|
+
if (lv === null) return absNullLit();
|
|
105
|
+
return absUndefLit();
|
|
106
|
+
}
|
|
107
|
+
if (c.element) {
|
|
108
|
+
return absExact({ k: "arr", element: constraintToCaseArgAbs(c.element) });
|
|
109
|
+
}
|
|
110
|
+
if (c.fields) {
|
|
111
|
+
const slots = {};
|
|
112
|
+
for (const [key, field] of Object.entries(c.fields)) {
|
|
113
|
+
slots[key] = { value: constraintToCaseArgAbs(field.constraint) };
|
|
114
|
+
}
|
|
115
|
+
return absExact({ k: "obj", slots });
|
|
116
|
+
}
|
|
117
|
+
const bareScalar = !c.fields && !c.element && !c.members && !c.fn && c.int !== true && c.preds.length === 0;
|
|
118
|
+
if (bareScalar) {
|
|
119
|
+
if (c.prim === "number" || c.prim === "string" || c.prim === "boolean") {
|
|
120
|
+
return absExact({ k: "prim", type: c.prim });
|
|
121
|
+
}
|
|
122
|
+
if (!c.prim) return absUnknown();
|
|
123
|
+
}
|
|
109
124
|
return constraintToEntryAbs(c, "__arg");
|
|
110
125
|
}
|
|
111
126
|
function parseCaseArgExpr(expr) {
|
|
@@ -117,52 +132,16 @@ function parseCaseArgExpr(expr) {
|
|
|
117
132
|
return absUnknown();
|
|
118
133
|
}
|
|
119
134
|
}
|
|
120
|
-
return
|
|
121
|
-
}
|
|
122
|
-
function parseTypeValueExpr(expr) {
|
|
123
|
-
return parseCaseArgExpr(expr);
|
|
135
|
+
return parseLiteralOrStructure(expr);
|
|
124
136
|
}
|
|
125
|
-
function
|
|
137
|
+
function parseLiteralOrStructure(expr) {
|
|
126
138
|
const s = expr.trim();
|
|
127
|
-
if (s === "T.number") return num();
|
|
128
|
-
if (s === "T.string") return str();
|
|
129
|
-
if (s === "T.boolean") return bool();
|
|
130
|
-
if (s === "T.unknown") return absUnknown();
|
|
131
|
-
if (s === "T.never") return absExact({ k: "never" });
|
|
132
|
-
if (s === "T.null") return absNullLit();
|
|
133
|
-
if (s === "T.undefined") return absUndefLit();
|
|
134
139
|
if (s === "true") return absLit(true);
|
|
135
140
|
if (s === "false") return absLit(false);
|
|
136
141
|
if (s === "null") return absLit(null);
|
|
137
142
|
if (s === "undefined") return absLit(void 0);
|
|
138
|
-
|
|
139
|
-
if (
|
|
140
|
-
return absLit(parsePrimitiveValue(literalMatch[1].trim()));
|
|
141
|
-
}
|
|
142
|
-
if (s.startsWith("T.union(") && s.endsWith(")")) {
|
|
143
|
-
const inner = s.slice("T.union(".length, -1);
|
|
144
|
-
const args = splitTopLevelArgs(inner);
|
|
145
|
-
return absUnion(args.map(parseLegacyTypeExpr));
|
|
146
|
-
}
|
|
147
|
-
if (s.startsWith("T.array(") && s.endsWith(")")) {
|
|
148
|
-
const inner = s.slice("T.array(".length, -1);
|
|
149
|
-
return absExact({ k: "arr", element: parseLegacyTypeExpr(inner) });
|
|
150
|
-
}
|
|
151
|
-
if (s.startsWith("T.tuple(") && s.endsWith(")")) {
|
|
152
|
-
const inner = s.slice("T.tuple(".length, -1).trim();
|
|
153
|
-
if (inner.startsWith("[") && inner.endsWith("]")) {
|
|
154
|
-
const elements = splitTopLevelArgs(inner.slice(1, -1));
|
|
155
|
-
return absExact({ k: "tuple", elements: elements.map(parseLegacyTypeExpr) });
|
|
156
|
-
}
|
|
157
|
-
return absExact({ k: "tuple", elements: [] });
|
|
158
|
-
}
|
|
159
|
-
if (s.startsWith("T.object(") && s.endsWith(")")) {
|
|
160
|
-
const inner = s.slice("T.object(".length, -1).trim();
|
|
161
|
-
if (inner.startsWith("{") && inner.endsWith("}")) {
|
|
162
|
-
return parseObjectLiteral(inner.slice(1, -1).trim());
|
|
163
|
-
}
|
|
164
|
-
return absExact({ k: "obj", slots: {} });
|
|
165
|
-
}
|
|
143
|
+
if (s === "unknown" || s === "any") return absUnknown();
|
|
144
|
+
if (s === "never") return absExact({ k: "never" });
|
|
166
145
|
if (findTopLevelArrow(s) !== -1 || /^function\s*[\w$]*\s*\(/.test(s)) {
|
|
167
146
|
const fnExpr = parseArrowFunctionExpr(s);
|
|
168
147
|
if (fnExpr) {
|
|
@@ -180,7 +159,7 @@ function parseLegacyTypeExpr(expr) {
|
|
|
180
159
|
const content = s.slice(1, -1).trim();
|
|
181
160
|
if (!content) return absExact({ k: "tuple", elements: [] });
|
|
182
161
|
const elements = splitTopLevelArgs(content);
|
|
183
|
-
return absExact({ k: "tuple", elements: elements.map(
|
|
162
|
+
return absExact({ k: "tuple", elements: elements.map((e) => parseCaseArgExpr(e)) });
|
|
184
163
|
}
|
|
185
164
|
return absUnknown();
|
|
186
165
|
}
|
|
@@ -193,21 +172,10 @@ function parseObjectLiteral(content) {
|
|
|
193
172
|
if (colonIdx === -1) continue;
|
|
194
173
|
const key = entry.slice(0, colonIdx).trim().replace(/^["']|["']$/g, "");
|
|
195
174
|
const val = entry.slice(colonIdx + 1).trim();
|
|
196
|
-
slots[key] = { value:
|
|
175
|
+
slots[key] = { value: parseCaseArgExpr(val) };
|
|
197
176
|
}
|
|
198
177
|
return absExact({ k: "obj", slots });
|
|
199
178
|
}
|
|
200
|
-
function parsePrimitiveValue(s) {
|
|
201
|
-
if (s === "true") return true;
|
|
202
|
-
if (s === "false") return false;
|
|
203
|
-
if (s === "null") return null;
|
|
204
|
-
if (s === "undefined") return void 0;
|
|
205
|
-
if (/^-?\d+(\.\d+)?$/.test(s)) return Number(s);
|
|
206
|
-
if (s.startsWith('"') && s.endsWith('"') || s.startsWith("'") && s.endsWith("'")) {
|
|
207
|
-
return s.slice(1, -1);
|
|
208
|
-
}
|
|
209
|
-
return s;
|
|
210
|
-
}
|
|
211
179
|
function splitTopLevelArgs(s) {
|
|
212
180
|
const result = [];
|
|
213
181
|
let depth = 0;
|
|
@@ -622,7 +590,7 @@ function findReplaceSeparator(raw) {
|
|
|
622
590
|
}
|
|
623
591
|
if (ch === " " && depth === 0) {
|
|
624
592
|
const rest = raw.slice(i + 1).trimStart();
|
|
625
|
-
if (
|
|
593
|
+
if (CONSTRAINT_EXPR_RE.test(rest) || rest.startsWith("{") || rest.startsWith("[") || rest.startsWith('"') || rest.startsWith("'") || rest === "true" || rest === "false" || rest === "null" || rest === "undefined" || rest === "unknown" || rest === "any" || rest === "never" || /^-?\d+(\.\d+)?$/.test(rest) || rest.includes("=>") || /^function\s*[\w$]*\s*\(/.test(rest)) {
|
|
626
594
|
return i;
|
|
627
595
|
}
|
|
628
596
|
}
|
|
@@ -673,6 +641,5 @@ export {
|
|
|
673
641
|
extractInlineDirectives,
|
|
674
642
|
parse,
|
|
675
643
|
parseCaseArgExpr,
|
|
676
|
-
parseTypeValueExpr,
|
|
677
644
|
stripTypes
|
|
678
645
|
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@nudojs/parser",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "1.0.0",
|
|
4
4
|
"engines": {
|
|
5
5
|
"node": ">=20"
|
|
6
6
|
},
|
|
@@ -39,7 +39,7 @@
|
|
|
39
39
|
"registry": "https://registry.npmjs.org"
|
|
40
40
|
},
|
|
41
41
|
"dependencies": {
|
|
42
|
-
"@nudojs/core": "2.0
|
|
42
|
+
"@nudojs/core": "2.1.0"
|
|
43
43
|
},
|
|
44
44
|
"scripts": {
|
|
45
45
|
"build": "tsup src/index.ts --format esm --dts"
|