@nudojs/parser 1.0.0 → 1.1.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/README.md CHANGED
@@ -4,15 +4,15 @@ Babel-based parser and directive extraction for [Nudo](https://github.com/nudojs
4
4
 
5
5
  ## What is Nudo?
6
6
 
7
- Nudo is a type inference engine for JavaScript. Instead of a separate type system, it runs your code with symbolic type values via abstract interpretation — no TypeScript, no build step.
7
+ Nudo is a type inference engine for JavaScript. The type system is Abs (`shape × term × pred × conf`); analysis runs Abs-native via abstract interpretation — no TypeScript, no build step.
8
8
 
9
9
  ## This package
10
10
 
11
11
  `@nudojs/parser` handles source code parsing and Nudo directive extraction:
12
12
 
13
13
  - **Parsing** — wraps Babel parser for JavaScript/TypeScript source files
14
- - **Directives** — extracts `@nudo:case`, `@nudo:mock`, `@nudo:pure`, `@nudo:skip`, `@nudo:sample`, `@nudo:env`, `@nudo:mock-module`, `@nudo:as`, and `@nudo:replace` from comments. `@nudo:refine` / `@nudo:import` are parsed in `@nudojs/core` (`algebra/refine.ts`).
15
- - **Type expressions** — parses inline type value expressions used in directives
14
+ - **Directives** — extracts `@nudo:case`, `@nudo:mock`, `@nudo:pure`, `@nudo:skip`, `@nudo:sample`, `@nudo:env`, `@nudo:mock-module`, `@nudo:as`, and `@nudo:replace` from comments. `@nudo:contract` / `@nudo:import` are parsed in `@nudojs/core` (`algebra/refine.ts`).
15
+ - **Case arg expressions** — parses constraint builders and concrete literals used in directives
16
16
 
17
17
  ## Install
18
18
 
package/dist/index.d.ts CHANGED
@@ -1,9 +1,13 @@
1
- import { File, Node } from '@babel/types';
1
+ import { File, Node, AssignmentExpression, Expression, Identifier, MemberExpression, Program, ClassBody, VariableDeclarator, ExportSpecifier, ExportDefaultSpecifier, ExportNamespaceSpecifier, Statement } from '@babel/types';
2
2
  import { Abs, MockHelper } from '@nudojs/core';
3
3
  export { stripTypes } from '@nudojs/core';
4
4
 
5
5
  /**
6
- * 与 core `parseSource` 同一实现与 AST LRU:
6
+ * 所有权:Babel 解析与 TS 剥除的**实现**在 `@nudojs/core`
7
+ * (`algebra/parse-source.ts` / `strip-types.ts`)—— core 代数层
8
+ * (check/scan/generalize)需要 AST 且不能反向依赖本包。本包职责是
9
+ * `@nudo:` 指令抽取与 AST 卫兵;`parse()` 是宿主入口,委托 core 同一实现与 AST LRU。
10
+ *
7
11
  * 决策:parse() 统一做 TS 剥除(不按 .ts 路径开关)。理由:parse() 的产物被
8
12
  * CLI/service/LSP/evaluator 全链消费,按调用方 opt-in 会漏掉无法感知文件扩展名
9
13
  * 的消费方(analyzer 的模块解析、LSP 等);对纯 JS 源码剥除是结构性 no-op,
@@ -15,6 +19,91 @@ declare function parse(source: string, opts?: {
15
19
  errorRecovery?: boolean;
16
20
  }): File;
17
21
 
22
+ /** File → its Program; Program → itself. Replaces `(ast as File).program ?? ast`. */
23
+ declare function asProgram(ast: Node | File | Program | null | undefined): Program | undefined;
24
+ /** Top-level statements of a File/Program (empty when neither). */
25
+ declare function programBody(ast: Node | File | Program | null | undefined): Statement[];
26
+ declare function asIdentifier(node: Node | null | undefined): Identifier | undefined;
27
+ declare function asExpression(node: Node | null | undefined): Expression | undefined;
28
+ declare function asAssignmentExpression(node: Node | null | undefined): AssignmentExpression | undefined;
29
+ /** Identifier.name, else StringLiteral.value (module string export names). */
30
+ declare function nameOrStringValue(node: Node | null | undefined): string | undefined;
31
+ /** Identifier.name only (undefined for string export names). */
32
+ declare function identifierName(node: Node | null | undefined): string | undefined;
33
+ /** VariableDeclaration.declarations; empty for other nodes. */
34
+ declare function getDeclarations(node: Node | null | undefined): VariableDeclarator[];
35
+ /** First declarator's init (fn-binding extraction). */
36
+ declare function getDeclaratorInit(node: Node | null | undefined): Expression | undefined;
37
+ /** First declarator of a VariableDeclaration, narrowed to Identifier id. */
38
+ declare function getFirstDeclaratorId(node: Node | null | undefined): Identifier | undefined;
39
+ /** VariableDeclarator id narrowed to Identifier. */
40
+ declare function getDeclaratorId(node: Node | null | undefined): Identifier | undefined;
41
+ /** Inner declaration of `export default` / `export …` (undefined for other nodes). */
42
+ declare function getExportDeclaration(node: Node | null | undefined): Node | undefined;
43
+ /**
44
+ * Unwrap an export form: named/default exports yield their inner declaration
45
+ * with `exported: true`; any other statement is returned as-is with `exported: false`.
46
+ */
47
+ declare function unwrapExport(node: Node | null | undefined): {
48
+ declaration: Node;
49
+ exported: boolean;
50
+ };
51
+ /** ExportNamedDeclaration.specifiers (empty for other nodes). */
52
+ declare function getExportSpecifiers(node: Node | null | undefined): (ExportSpecifier | ExportDefaultSpecifier | ExportNamespaceSpecifier)[];
53
+ /** ExportSpecifier local name — Identifier only (matches `local.name`). */
54
+ declare function exportSpecifierLocalName(spec: Node | null | undefined): string | undefined;
55
+ /** ExportSpecifier exported name (`exported.name ?? exported.value`). */
56
+ declare function exportSpecifierExportedName(spec: Node | null | undefined): string | number | undefined;
57
+ /** ExpressionStatement.expression. */
58
+ declare function getExpressionStatementExpression(node: Node | null | undefined): Expression | undefined;
59
+ /** Function/Class declaration or expression `id?.name`. */
60
+ declare function fnOrClassIdName(node: Node | null | undefined): string | undefined;
61
+ /** ClassDeclaration/ClassExpression `id?.name`. */
62
+ declare function classIdName(node: Node | null | undefined): string | undefined;
63
+ /** `id.loc` of a named function/class (undefined when anonymous or unlocated). */
64
+ declare function fnOrClassIdLoc(node: Node | null | undefined): Node["loc"];
65
+ /** Non-computed member property key text (Identifier.name or StringLiteral.value). */
66
+ declare function memberPropertyKey(member: Node | null | undefined): string | null;
67
+ /** Identifier name of a non-computed member's object (e.g. `module` in `module.exports`). */
68
+ declare function memberObjectName(member: Node | null | undefined): string | undefined;
69
+ /** Identifier name of a non-computed member's property (e.g. `exports`). */
70
+ declare function memberPropertyName(member: Node | null | undefined): string | undefined;
71
+ /** `module.exports` / `module["exports"]` is rejected here: computed keys return false. */
72
+ declare function isModuleExportsMember(member: Node | null | undefined): boolean;
73
+ declare function asMemberExpression(node: Node | null | undefined): MemberExpression | undefined;
74
+ /** Class body members; empty when node is not a class. */
75
+ declare function getClassMembers(node: Node | null | undefined): ClassBody["body"];
76
+ /**
77
+ * `key.name ?? key.value` on a class/object member key.
78
+ * Handles Identifier / StringLiteral / NumericLiteral and ESTree-shaped keys.
79
+ */
80
+ declare function classMemberKeyName(member: Node | null | undefined): string | number | undefined;
81
+ /** Key node of a class member (for range selection). */
82
+ declare function classMemberKey(member: Node | null | undefined): Node | undefined;
83
+ type InstanceMethod = {
84
+ name: string;
85
+ node: Node;
86
+ };
87
+ /**
88
+ * Instance methods of a class-like node. Accepts Babel `ClassMethod` /
89
+ * `TSDeclareMethod` and ESTree `MethodDefinition` (whose function lives in `value`).
90
+ * Skips getters/setters/constructors and static members.
91
+ */
92
+ declare function classInstanceMethods(node: Node | null | undefined): InstanceMethod[];
93
+ /** Class/TSDeclare method function node (ESTree MethodDefinition → its `value`). */
94
+ declare function methodFunctionNode(member: Node | null | undefined): Node | undefined;
95
+ /**
96
+ * Parameter display label: `name`, `...rest`, or `_`.
97
+ * Non-identifier rest arguments keep the historical `...undefined` string form.
98
+ */
99
+ declare function paramDisplayName(param: Node | null | undefined): string;
100
+ /** RestElement argument name, else plain Identifier name. */
101
+ declare function paramName(param: Node | null | undefined): string | undefined;
102
+ /** CJS/ESM default interop: callable module or `{ default }` wrapper. */
103
+ declare function unwrapDefaultExport<T>(mod: T | {
104
+ default: T;
105
+ }): T;
106
+
18
107
  type CaseDirective = {
19
108
  kind: "case";
20
109
  name: string;
@@ -90,4 +179,4 @@ declare function extractDirectives(ast: Node): FunctionWithDirectives[];
90
179
  declare function extractInlineDirectives(node: Node): InlineDirective[];
91
180
  declare function extractFileDirectives(ast: Node): FileDirective[];
92
181
 
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 };
182
+ export { type AsDirective, type CaseDirective, type Directive, type EnvDirective, type FileDirective, type FunctionWithDirectives, type InlineDirective, type InstanceMethod, type MockDirective, type MockModuleDirective, type PureDirective, type ReplaceDirective, type SampleDirective, type SinonExpression, type SkipDirective, asAssignmentExpression, asExpression, asIdentifier, asMemberExpression, asProgram, classIdName, classInstanceMethods, classMemberKey, classMemberKeyName, exportSpecifierExportedName, exportSpecifierLocalName, extractDirectives, extractFileDirectives, extractInlineDirectives, fnOrClassIdLoc, fnOrClassIdName, getClassMembers, getDeclarations, getDeclaratorId, getDeclaratorInit, getExportDeclaration, getExportSpecifiers, getExpressionStatementExpression, getFirstDeclaratorId, identifierName, isModuleExportsMember, memberObjectName, memberPropertyKey, memberPropertyName, methodFunctionNode, nameOrStringValue, paramDisplayName, paramName, parse, parseCaseArgExpr, programBody, unwrapDefaultExport, unwrapExport };
package/dist/index.js CHANGED
@@ -7,6 +7,173 @@ function parse(source, opts) {
7
7
  // src/index.ts
8
8
  import { stripTypes } from "@nudojs/core";
9
9
 
10
+ // src/ast-guards.ts
11
+ import { isExpression } from "@babel/types";
12
+ function asProgram(ast) {
13
+ if (!ast) return void 0;
14
+ if (ast.type === "File") return ast.program;
15
+ if (ast.type === "Program") return ast;
16
+ return void 0;
17
+ }
18
+ function programBody(ast) {
19
+ return asProgram(ast)?.body ?? [];
20
+ }
21
+ function asIdentifier(node) {
22
+ return node?.type === "Identifier" ? node : void 0;
23
+ }
24
+ function asExpression(node) {
25
+ return node && isExpression(node) ? node : void 0;
26
+ }
27
+ function asAssignmentExpression(node) {
28
+ return node?.type === "AssignmentExpression" ? node : void 0;
29
+ }
30
+ function nameOrStringValue(node) {
31
+ if (!node) return void 0;
32
+ if (node.type === "Identifier") return node.name;
33
+ if (node.type === "StringLiteral") return node.value;
34
+ return void 0;
35
+ }
36
+ function identifierName(node) {
37
+ return node?.type === "Identifier" ? node.name : void 0;
38
+ }
39
+ function getDeclarations(node) {
40
+ return node?.type === "VariableDeclaration" ? node.declarations : [];
41
+ }
42
+ function getDeclaratorInit(node) {
43
+ const decl = node?.type === "VariableDeclarator" ? node : void 0;
44
+ return decl?.init ?? void 0;
45
+ }
46
+ function getFirstDeclaratorId(node) {
47
+ const decl = getDeclarations(node)[0];
48
+ return decl?.id.type === "Identifier" ? decl.id : void 0;
49
+ }
50
+ function getDeclaratorId(node) {
51
+ const decl = node?.type === "VariableDeclarator" ? node : void 0;
52
+ return decl?.id.type === "Identifier" ? decl.id : void 0;
53
+ }
54
+ function getExportDeclaration(node) {
55
+ if (!node) return void 0;
56
+ if (node.type === "ExportNamedDeclaration" || node.type === "ExportDefaultDeclaration") {
57
+ return node.declaration ?? void 0;
58
+ }
59
+ return void 0;
60
+ }
61
+ function unwrapExport(node) {
62
+ if (node?.type === "ExportNamedDeclaration" && node.declaration) {
63
+ return { declaration: node.declaration, exported: true };
64
+ }
65
+ if (node?.type === "ExportDefaultDeclaration") {
66
+ return { declaration: node.declaration, exported: true };
67
+ }
68
+ return { declaration: node, exported: false };
69
+ }
70
+ function getExportSpecifiers(node) {
71
+ return node?.type === "ExportNamedDeclaration" ? node.specifiers : [];
72
+ }
73
+ function exportSpecifierLocalName(spec) {
74
+ return spec?.type === "ExportSpecifier" ? identifierName(spec.local) : void 0;
75
+ }
76
+ function exportSpecifierExportedName(spec) {
77
+ if (spec?.type !== "ExportSpecifier") return void 0;
78
+ const exported = spec.exported;
79
+ return exported.type === "Identifier" ? exported.name : exported.value;
80
+ }
81
+ function getExpressionStatementExpression(node) {
82
+ return node?.type === "ExpressionStatement" ? node.expression : void 0;
83
+ }
84
+ function fnOrClassIdName(node) {
85
+ if (!node) return void 0;
86
+ if (node.type === "FunctionDeclaration" || node.type === "FunctionExpression" || node.type === "ClassDeclaration" || node.type === "ClassExpression" || node.type === "TSDeclareFunction") {
87
+ return node.id?.name;
88
+ }
89
+ return void 0;
90
+ }
91
+ function classIdName(node) {
92
+ if (!node) return void 0;
93
+ if (node.type === "ClassDeclaration" || node.type === "ClassExpression") {
94
+ return node.id?.name;
95
+ }
96
+ return void 0;
97
+ }
98
+ function fnOrClassIdLoc(node) {
99
+ if (!node) return void 0;
100
+ if (node.type === "FunctionDeclaration" || node.type === "FunctionExpression" || node.type === "ClassDeclaration" || node.type === "ClassExpression" || node.type === "TSDeclareFunction") {
101
+ return node.id?.loc ?? void 0;
102
+ }
103
+ return void 0;
104
+ }
105
+ function memberPropertyKey(member) {
106
+ if (member?.type !== "MemberExpression" || member.computed) return null;
107
+ return nameOrStringValue(member.property) ?? null;
108
+ }
109
+ function memberObjectName(member) {
110
+ if (member?.type !== "MemberExpression") return void 0;
111
+ return identifierName(member.object);
112
+ }
113
+ function memberPropertyName(member) {
114
+ if (member?.type !== "MemberExpression" || member.computed) return void 0;
115
+ return identifierName(member.property);
116
+ }
117
+ function isModuleExportsMember(member) {
118
+ return memberObjectName(member) === "module" && memberPropertyName(member) === "exports";
119
+ }
120
+ function asMemberExpression(node) {
121
+ return node?.type === "MemberExpression" ? node : void 0;
122
+ }
123
+ function getClassMembers(node) {
124
+ if (node?.type === "ClassDeclaration" || node?.type === "ClassExpression") {
125
+ return node.body.body;
126
+ }
127
+ return [];
128
+ }
129
+ function classMemberKeyName(member) {
130
+ const key = member?.key;
131
+ return key?.name ?? key?.value;
132
+ }
133
+ function classMemberKey(member) {
134
+ return member?.key ?? void 0;
135
+ }
136
+ function classInstanceMethods(node) {
137
+ const out = [];
138
+ for (const raw of getClassMembers(node)) {
139
+ const m = raw;
140
+ const isMethod = m.type === "MethodDefinition" || m.type === "ClassMethod" || m.type === "TSDeclareMethod";
141
+ if (!isMethod) continue;
142
+ if (m.kind && m.kind !== "method") continue;
143
+ if (m.static) continue;
144
+ const keyName = m.key?.type === "Identifier" ? m.key.name : void 0;
145
+ if (!keyName) continue;
146
+ const methodNode = m.type === "MethodDefinition" ? m.value ?? void 0 : raw;
147
+ if (!methodNode) continue;
148
+ out.push({ name: keyName, node: methodNode });
149
+ }
150
+ return out;
151
+ }
152
+ function methodFunctionNode(member) {
153
+ const m = member;
154
+ if (!m) return void 0;
155
+ return m.type === "MethodDefinition" ? m.value ?? void 0 : member;
156
+ }
157
+ function paramDisplayName(param) {
158
+ if (!param) return "_";
159
+ if (param.type === "Identifier") return param.name;
160
+ if (param.type === "RestElement") {
161
+ const arg = param.argument;
162
+ return `...${arg.name}`;
163
+ }
164
+ return "_";
165
+ }
166
+ function paramName(param) {
167
+ if (!param) return void 0;
168
+ if (param.type === "Identifier") return param.name;
169
+ if (param.type === "RestElement") return identifierName(param.argument);
170
+ return void 0;
171
+ }
172
+ function unwrapDefaultExport(mod) {
173
+ if (typeof mod === "function") return mod;
174
+ return mod.default;
175
+ }
176
+
10
177
  // src/directives.ts
11
178
  import {
12
179
  stub,
@@ -636,10 +803,43 @@ function extractFileDirectives(ast) {
636
803
  return results;
637
804
  }
638
805
  export {
806
+ asAssignmentExpression,
807
+ asExpression,
808
+ asIdentifier,
809
+ asMemberExpression,
810
+ asProgram,
811
+ classIdName,
812
+ classInstanceMethods,
813
+ classMemberKey,
814
+ classMemberKeyName,
815
+ exportSpecifierExportedName,
816
+ exportSpecifierLocalName,
639
817
  extractDirectives,
640
818
  extractFileDirectives,
641
819
  extractInlineDirectives,
820
+ fnOrClassIdLoc,
821
+ fnOrClassIdName,
822
+ getClassMembers,
823
+ getDeclarations,
824
+ getDeclaratorId,
825
+ getDeclaratorInit,
826
+ getExportDeclaration,
827
+ getExportSpecifiers,
828
+ getExpressionStatementExpression,
829
+ getFirstDeclaratorId,
830
+ identifierName,
831
+ isModuleExportsMember,
832
+ memberObjectName,
833
+ memberPropertyKey,
834
+ memberPropertyName,
835
+ methodFunctionNode,
836
+ nameOrStringValue,
837
+ paramDisplayName,
838
+ paramName,
642
839
  parse,
643
840
  parseCaseArgExpr,
644
- stripTypes
841
+ programBody,
842
+ stripTypes,
843
+ unwrapDefaultExport,
844
+ unwrapExport
645
845
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@nudojs/parser",
3
- "version": "1.0.0",
3
+ "version": "1.1.0",
4
4
  "engines": {
5
5
  "node": ">=20"
6
6
  },
@@ -39,7 +39,8 @@
39
39
  "registry": "https://registry.npmjs.org"
40
40
  },
41
41
  "dependencies": {
42
- "@nudojs/core": "2.1.0"
42
+ "@nudojs/core": "1.1.0",
43
+ "@babel/types": "^8.0.6"
43
44
  },
44
45
  "scripts": {
45
46
  "build": "tsup src/index.ts --format esm --dts"