Skip to content

Commit 9ec4614

Browse files
authored
fix(lint): ensure all exported types report private type dependency errors (#756)
1 parent eb93803 commit 9ec4614

File tree

2 files changed

+198
-5
lines changed

2 files changed

+198
-5
lines changed

src/visibility.rs

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -158,9 +158,8 @@ impl SymbolVisibility {
158158
}
159159

160160
for dep_symbol_id in dep_symbol_ids {
161-
if !root_exported_ids.contains_key(&dep_symbol_id)
162-
&& non_exported_public_ids.insert(dep_symbol_id)
163-
{
161+
if !root_exported_ids.contains_key(&dep_symbol_id) {
162+
// always record this as a dependency of the current symbol
164163
if let Some(dep_ids) = root_exported_ids.get_mut(&original_id) {
165164
dep_ids.add(
166165
decl_symbol.unique_id(),
@@ -170,8 +169,11 @@ impl SymbolVisibility {
170169
);
171170
}
172171

173-
// examine the private types of this private type
174-
pending_symbol_ids.push(dep_symbol_id);
172+
// only analyze this private type's dependencies once
173+
if non_exported_public_ids.insert(dep_symbol_id) {
174+
// examine the private types of this private type
175+
pending_symbol_ids.push(dep_symbol_id);
176+
}
175177
}
176178
}
177179
}
Lines changed: 191 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,191 @@
1+
# mod.ts
2+
import { PrivateInterface } from "./private.ts";
3+
4+
/** Class A */
5+
export class ClassA {
6+
/** property a */
7+
prop: PrivateInterface;
8+
}
9+
10+
/** Class B */
11+
export class ClassB {
12+
/** property b */
13+
prop: PrivateInterface;
14+
}
15+
16+
# private.ts
17+
export interface PrivateInterface {
18+
value: string;
19+
}
20+
21+
# diagnostics
22+
error[private-type-ref]: public type 'ClassA.prototype.prop' references private type 'PrivateInterface'
23+
--> /mod.ts:6:3
24+
|
25+
6 | prop: PrivateInterface;
26+
| ^
27+
= hint: make the referenced type public or remove the reference
28+
|
29+
1 | export interface PrivateInterface {
30+
| - this is the referenced type
31+
|
32+
33+
info: to ensure documentation is complete all types that are exposed in the public API must be public
34+
35+
36+
error[private-type-ref]: public type 'ClassB.prototype.prop' references private type 'PrivateInterface'
37+
--> /mod.ts:12:3
38+
|
39+
12 | prop: PrivateInterface;
40+
| ^
41+
= hint: make the referenced type public or remove the reference
42+
|
43+
1 | export interface PrivateInterface {
44+
| - this is the referenced type
45+
|
46+
47+
info: to ensure documentation is complete all types that are exposed in the public API must be public
48+
49+
# output.txt
50+
Defined in file:///mod.ts:4:1
51+
52+
class ClassA
53+
Class A
54+
55+
prop: PrivateInterface
56+
property a
57+
58+
Defined in file:///mod.ts:10:1
59+
60+
class ClassB
61+
Class B
62+
63+
prop: PrivateInterface
64+
property b
65+
66+
Defined in file:///mod.ts:1:1
67+
68+
69+
70+
# output.json
71+
[
72+
{
73+
"name": "ClassA",
74+
"isDefault": false,
75+
"location": {
76+
"filename": "file:///mod.ts",
77+
"line": 4,
78+
"col": 0,
79+
"byteIndex": 65
80+
},
81+
"declarationKind": "export",
82+
"jsDoc": {
83+
"doc": "Class A"
84+
},
85+
"kind": "class",
86+
"classDef": {
87+
"isAbstract": false,
88+
"constructors": [],
89+
"properties": [
90+
{
91+
"jsDoc": {
92+
"doc": "property a"
93+
},
94+
"tsType": {
95+
"repr": "PrivateInterface",
96+
"kind": "typeRef",
97+
"typeRef": {
98+
"typeParams": null,
99+
"typeName": "PrivateInterface"
100+
}
101+
},
102+
"readonly": false,
103+
"accessibility": null,
104+
"optional": false,
105+
"isAbstract": false,
106+
"isStatic": false,
107+
"name": "prop",
108+
"location": {
109+
"filename": "file:///mod.ts",
110+
"line": 6,
111+
"col": 2,
112+
"byteIndex": 109
113+
}
114+
}
115+
],
116+
"indexSignatures": [],
117+
"methods": [],
118+
"extends": null,
119+
"implements": [],
120+
"typeParams": [],
121+
"superTypeParams": []
122+
}
123+
},
124+
{
125+
"name": "ClassB",
126+
"isDefault": false,
127+
"location": {
128+
"filename": "file:///mod.ts",
129+
"line": 10,
130+
"col": 0,
131+
"byteIndex": 151
132+
},
133+
"declarationKind": "export",
134+
"jsDoc": {
135+
"doc": "Class B"
136+
},
137+
"kind": "class",
138+
"classDef": {
139+
"isAbstract": false,
140+
"constructors": [],
141+
"properties": [
142+
{
143+
"jsDoc": {
144+
"doc": "property b"
145+
},
146+
"tsType": {
147+
"repr": "PrivateInterface",
148+
"kind": "typeRef",
149+
"typeRef": {
150+
"typeParams": null,
151+
"typeName": "PrivateInterface"
152+
}
153+
},
154+
"readonly": false,
155+
"accessibility": null,
156+
"optional": false,
157+
"isAbstract": false,
158+
"isStatic": false,
159+
"name": "prop",
160+
"location": {
161+
"filename": "file:///mod.ts",
162+
"line": 12,
163+
"col": 2,
164+
"byteIndex": 195
165+
}
166+
}
167+
],
168+
"indexSignatures": [],
169+
"methods": [],
170+
"extends": null,
171+
"implements": [],
172+
"typeParams": [],
173+
"superTypeParams": []
174+
}
175+
},
176+
{
177+
"name": "PrivateInterface",
178+
"location": {
179+
"filename": "file:///mod.ts",
180+
"line": 1,
181+
"col": 0,
182+
"byteIndex": 0
183+
},
184+
"declarationKind": "private",
185+
"kind": "import",
186+
"importDef": {
187+
"src": "file:///private.ts",
188+
"imported": "PrivateInterface"
189+
}
190+
}
191+
]

0 commit comments

Comments
 (0)