@cparra/apexdocs 3.0.0-beta.1 → 3.0.0-rc.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/LICENSE +1 -1
- package/README.md +442 -325
- package/dist/cli/generate.js +1 -1
- package/dist/index.d.ts +15 -17
- package/examples/markdown/docs/miscellaneous/Url.md +10 -8
- package/examples/markdown/force-app/classes/Url.cls +3 -1
- package/examples/markdown-jsconfig/.forceignore +12 -0
- package/examples/markdown-jsconfig/apexdocs.config.mjs +21 -0
- package/examples/markdown-jsconfig/config/project-scratch-def.json +5 -0
- package/examples/markdown-jsconfig/docs/index.md +12 -0
- package/examples/markdown-jsconfig/docs/miscellaneous/Url.md +315 -0
- package/examples/markdown-jsconfig/force-app/classes/Url.cls +196 -0
- package/examples/markdown-jsconfig/package-lock.json +665 -0
- package/examples/markdown-jsconfig/package.json +15 -0
- package/examples/markdown-jsconfig/sfdx-project.json +12 -0
- package/examples/vitepress/apexdocs.config.ts +7 -2
- package/examples/vitepress/docs/index.md +11 -11
- package/examples/vitepress/docs/miscellaneous/BaseClass.md +1 -1
- package/examples/vitepress/docs/miscellaneous/MultiInheritanceClass.md +2 -2
- package/examples/vitepress/docs/miscellaneous/SampleException.md +1 -1
- package/examples/vitepress/docs/miscellaneous/SampleInterface.md +6 -6
- package/examples/vitepress/docs/miscellaneous/Url.md +3 -3
- package/examples/vitepress/docs/sample-enums/SampleEnum.md +3 -3
- package/examples/vitepress/docs/samplegroup/SampleClass.md +5 -5
- package/examples/vitepress/force-app/main/default/classes/SampleClass.cls +1 -1
- package/package.json +2 -2
- package/src/cli/commands/markdown.ts +1 -3
- package/src/core/markdown/__test__/generating-class-docs.spec.ts +1 -129
- package/src/core/markdown/__test__/generating-docs.spec.ts +111 -0
- package/src/core/markdown/__test__/generating-enum-docs.spec.ts +0 -64
- package/src/core/markdown/__test__/generating-interface-docs.spec.ts +0 -64
- package/src/core/markdown/reflection/__test__/filter-scope.spec.ts +306 -0
- package/src/core/shared/types.d.ts +14 -16
- package/src/index.ts +23 -10
|
@@ -6,70 +6,6 @@ describe('Generates interface documentation', () => {
|
|
|
6
6
|
extendExpect();
|
|
7
7
|
});
|
|
8
8
|
|
|
9
|
-
describe('documentation output', () => {
|
|
10
|
-
it('returns the name of the interface', async () => {
|
|
11
|
-
const input = `
|
|
12
|
-
public interface MyInterface {
|
|
13
|
-
}
|
|
14
|
-
`;
|
|
15
|
-
|
|
16
|
-
const result = await generateDocs([apexBundleFromRawString(input)])();
|
|
17
|
-
expect(result).documentationBundleHasLength(1);
|
|
18
|
-
assertEither(result, (data) => expect(data.docs[0].source.name).toBe('MyInterface'));
|
|
19
|
-
});
|
|
20
|
-
|
|
21
|
-
it('returns the type as interface', async () => {
|
|
22
|
-
const input = `
|
|
23
|
-
public interface MyInterface {
|
|
24
|
-
}
|
|
25
|
-
`;
|
|
26
|
-
|
|
27
|
-
const result = await generateDocs([apexBundleFromRawString(input)])();
|
|
28
|
-
expect(result).documentationBundleHasLength(1);
|
|
29
|
-
assertEither(result, (data) => expect(data.docs[0].source.type).toBe('interface'));
|
|
30
|
-
});
|
|
31
|
-
|
|
32
|
-
it('does not return interfaces out of scope', async () => {
|
|
33
|
-
const input1 = `
|
|
34
|
-
global interface MyInterface {}
|
|
35
|
-
`;
|
|
36
|
-
|
|
37
|
-
const input2 = `
|
|
38
|
-
public interface AnotherInterface {}
|
|
39
|
-
`;
|
|
40
|
-
|
|
41
|
-
const result = await generateDocs([apexBundleFromRawString(input1), apexBundleFromRawString(input2)], {
|
|
42
|
-
scope: ['global'],
|
|
43
|
-
})();
|
|
44
|
-
expect(result).documentationBundleHasLength(1);
|
|
45
|
-
});
|
|
46
|
-
|
|
47
|
-
it('does not return interfaces that have an @ignore in the docs', async () => {
|
|
48
|
-
const input = `
|
|
49
|
-
/**
|
|
50
|
-
* @ignore
|
|
51
|
-
*/
|
|
52
|
-
public interface MyInterface {}`;
|
|
53
|
-
|
|
54
|
-
const result = await generateDocs([apexBundleFromRawString(input)])();
|
|
55
|
-
expect(result).documentationBundleHasLength(0);
|
|
56
|
-
});
|
|
57
|
-
|
|
58
|
-
it('does not return interface methods that have @ignore in the docs', async () => {
|
|
59
|
-
const input = `
|
|
60
|
-
public interface MyInterface {
|
|
61
|
-
/**
|
|
62
|
-
* @ignore
|
|
63
|
-
*/
|
|
64
|
-
void myMethod();
|
|
65
|
-
}`;
|
|
66
|
-
|
|
67
|
-
const result = await generateDocs([apexBundleFromRawString(input)])();
|
|
68
|
-
expect(result).documentationBundleHasLength(1);
|
|
69
|
-
assertEither(result, (data) => expect(data.docs[0].content).not.toContain('myMethod'));
|
|
70
|
-
});
|
|
71
|
-
});
|
|
72
|
-
|
|
73
9
|
describe('documentation content', () => {
|
|
74
10
|
describe('type level information', () => {
|
|
75
11
|
it('generates a heading with the interface name', async () => {
|
|
@@ -0,0 +1,306 @@
|
|
|
1
|
+
import { ParsedFile } from '../../../shared/types';
|
|
2
|
+
import { ClassMirror, EnumMirror, InterfaceMirror, reflect } from '@cparra/apex-reflection';
|
|
3
|
+
import { filterScope } from '../filter-scope';
|
|
4
|
+
|
|
5
|
+
function parsedFileFromRawString(raw: string): ParsedFile {
|
|
6
|
+
const { error, typeMirror } = reflect(raw);
|
|
7
|
+
if (error) {
|
|
8
|
+
throw new Error(error.message);
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
return {
|
|
12
|
+
source: {
|
|
13
|
+
filePath: 'test.cls',
|
|
14
|
+
name: typeMirror!.name,
|
|
15
|
+
type: typeMirror!.type_name,
|
|
16
|
+
},
|
|
17
|
+
type: typeMirror!,
|
|
18
|
+
};
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
describe('When filtering scope', () => {
|
|
22
|
+
it('filters out files with the @ignore annotation', () => {
|
|
23
|
+
const properties: [string, number][] = [
|
|
24
|
+
[
|
|
25
|
+
`
|
|
26
|
+
/**
|
|
27
|
+
* @ignore
|
|
28
|
+
*/
|
|
29
|
+
global class MyClass {}
|
|
30
|
+
`,
|
|
31
|
+
0,
|
|
32
|
+
],
|
|
33
|
+
['global class MyClass {}', 1],
|
|
34
|
+
];
|
|
35
|
+
|
|
36
|
+
for (const [input, expected] of properties) {
|
|
37
|
+
const parsedFile = parsedFileFromRawString(input);
|
|
38
|
+
|
|
39
|
+
const result = filterScope(['global'], [parsedFile]);
|
|
40
|
+
|
|
41
|
+
expect(result).toHaveLength(expected);
|
|
42
|
+
}
|
|
43
|
+
});
|
|
44
|
+
|
|
45
|
+
describe('when scoping a class', () => {
|
|
46
|
+
it('filters out methods tagged with @ignore', () => {
|
|
47
|
+
const properties: [string, number][] = [
|
|
48
|
+
[
|
|
49
|
+
`
|
|
50
|
+
global class MyClass {
|
|
51
|
+
/**
|
|
52
|
+
* @ignore
|
|
53
|
+
*/
|
|
54
|
+
global void myMethod() {}
|
|
55
|
+
}
|
|
56
|
+
`,
|
|
57
|
+
0,
|
|
58
|
+
],
|
|
59
|
+
[
|
|
60
|
+
`
|
|
61
|
+
global class MyClass {
|
|
62
|
+
global void myMethod() {}
|
|
63
|
+
}
|
|
64
|
+
`,
|
|
65
|
+
1,
|
|
66
|
+
],
|
|
67
|
+
];
|
|
68
|
+
|
|
69
|
+
for (const [input, expected] of properties) {
|
|
70
|
+
const parsedFile = parsedFileFromRawString(input);
|
|
71
|
+
|
|
72
|
+
const result = filterScope(['global'], [parsedFile]);
|
|
73
|
+
|
|
74
|
+
expect((result[0].type as ClassMirror).methods).toHaveLength(expected);
|
|
75
|
+
}
|
|
76
|
+
});
|
|
77
|
+
|
|
78
|
+
it('filters out properties tagged with @ignore', () => {
|
|
79
|
+
const properties: [string, number][] = [
|
|
80
|
+
[
|
|
81
|
+
`
|
|
82
|
+
global class MyClass {
|
|
83
|
+
/**
|
|
84
|
+
* @ignore
|
|
85
|
+
*/
|
|
86
|
+
global Integer myProperty { get; set; }
|
|
87
|
+
}
|
|
88
|
+
`,
|
|
89
|
+
0,
|
|
90
|
+
],
|
|
91
|
+
[
|
|
92
|
+
`
|
|
93
|
+
global class MyClass {
|
|
94
|
+
global Integer myProperty { get; set; }
|
|
95
|
+
}
|
|
96
|
+
`,
|
|
97
|
+
1,
|
|
98
|
+
],
|
|
99
|
+
];
|
|
100
|
+
|
|
101
|
+
for (const [input, expected] of properties) {
|
|
102
|
+
const parsedFile = parsedFileFromRawString(input);
|
|
103
|
+
|
|
104
|
+
const result = filterScope(['global'], [parsedFile]);
|
|
105
|
+
|
|
106
|
+
expect((result[0].type as ClassMirror).properties).toHaveLength(expected);
|
|
107
|
+
}
|
|
108
|
+
});
|
|
109
|
+
|
|
110
|
+
it('filters out fields tagged with @ignore', () => {
|
|
111
|
+
const properties: [string, number][] = [
|
|
112
|
+
[
|
|
113
|
+
`
|
|
114
|
+
global class MyClass {
|
|
115
|
+
/**
|
|
116
|
+
* @ignore
|
|
117
|
+
*/
|
|
118
|
+
global Integer myField;
|
|
119
|
+
}
|
|
120
|
+
`,
|
|
121
|
+
0,
|
|
122
|
+
],
|
|
123
|
+
[
|
|
124
|
+
`
|
|
125
|
+
global class MyClass {
|
|
126
|
+
global Integer myField;
|
|
127
|
+
}
|
|
128
|
+
`,
|
|
129
|
+
1,
|
|
130
|
+
],
|
|
131
|
+
];
|
|
132
|
+
|
|
133
|
+
for (const [input, expected] of properties) {
|
|
134
|
+
const parsedFile = parsedFileFromRawString(input);
|
|
135
|
+
|
|
136
|
+
const result = filterScope(['global'], [parsedFile]);
|
|
137
|
+
|
|
138
|
+
expect((result[0].type as ClassMirror).fields).toHaveLength(expected);
|
|
139
|
+
}
|
|
140
|
+
});
|
|
141
|
+
|
|
142
|
+
it('filters out inner classes tagged with @ignore', () => {
|
|
143
|
+
const properties: [string, number][] = [
|
|
144
|
+
[
|
|
145
|
+
`
|
|
146
|
+
global class MyClass {
|
|
147
|
+
/**
|
|
148
|
+
* @ignore
|
|
149
|
+
*/
|
|
150
|
+
global class InnerClass {}
|
|
151
|
+
}
|
|
152
|
+
`,
|
|
153
|
+
0,
|
|
154
|
+
],
|
|
155
|
+
[
|
|
156
|
+
`
|
|
157
|
+
global class MyClass {
|
|
158
|
+
global class InnerClass {}
|
|
159
|
+
}
|
|
160
|
+
`,
|
|
161
|
+
1,
|
|
162
|
+
],
|
|
163
|
+
];
|
|
164
|
+
|
|
165
|
+
for (const [input, expected] of properties) {
|
|
166
|
+
const parsedFile = parsedFileFromRawString(input);
|
|
167
|
+
|
|
168
|
+
const result = filterScope(['global'], [parsedFile]);
|
|
169
|
+
|
|
170
|
+
expect((result[0].type as ClassMirror).classes).toHaveLength(expected);
|
|
171
|
+
}
|
|
172
|
+
});
|
|
173
|
+
|
|
174
|
+
it('filters out inner interfaces tagged with @ignore', () => {
|
|
175
|
+
const properties: [string, number][] = [
|
|
176
|
+
[
|
|
177
|
+
`
|
|
178
|
+
global class MyClass {
|
|
179
|
+
/**
|
|
180
|
+
* @ignore
|
|
181
|
+
*/
|
|
182
|
+
global interface InnerInterface {}
|
|
183
|
+
}
|
|
184
|
+
`,
|
|
185
|
+
0,
|
|
186
|
+
],
|
|
187
|
+
[
|
|
188
|
+
`
|
|
189
|
+
global class MyClass {
|
|
190
|
+
global interface InnerInterface {}
|
|
191
|
+
}
|
|
192
|
+
`,
|
|
193
|
+
1,
|
|
194
|
+
],
|
|
195
|
+
];
|
|
196
|
+
|
|
197
|
+
for (const [input, expected] of properties) {
|
|
198
|
+
const parsedFile = parsedFileFromRawString(input);
|
|
199
|
+
|
|
200
|
+
const result = filterScope(['global'], [parsedFile]);
|
|
201
|
+
|
|
202
|
+
expect((result[0].type as ClassMirror).interfaces).toHaveLength(expected);
|
|
203
|
+
}
|
|
204
|
+
});
|
|
205
|
+
|
|
206
|
+
it('filters out inner enums tagged with @ignore', () => {
|
|
207
|
+
const properties: [string, number][] = [
|
|
208
|
+
[
|
|
209
|
+
`
|
|
210
|
+
global class MyClass {
|
|
211
|
+
/**
|
|
212
|
+
* @ignore
|
|
213
|
+
*/
|
|
214
|
+
global enum InnerEnum {}
|
|
215
|
+
}
|
|
216
|
+
`,
|
|
217
|
+
0,
|
|
218
|
+
],
|
|
219
|
+
[
|
|
220
|
+
`
|
|
221
|
+
global class MyClass {
|
|
222
|
+
global enum InnerEnum {}
|
|
223
|
+
}
|
|
224
|
+
`,
|
|
225
|
+
1,
|
|
226
|
+
],
|
|
227
|
+
];
|
|
228
|
+
|
|
229
|
+
for (const [input, expected] of properties) {
|
|
230
|
+
const parsedFile = parsedFileFromRawString(input);
|
|
231
|
+
|
|
232
|
+
const result = filterScope(['global'], [parsedFile]);
|
|
233
|
+
|
|
234
|
+
expect((result[0].type as ClassMirror).enums).toHaveLength(expected);
|
|
235
|
+
}
|
|
236
|
+
});
|
|
237
|
+
});
|
|
238
|
+
|
|
239
|
+
describe('when scoping an interface', () => {
|
|
240
|
+
it('filters out methods tagged with @ignore', () => {
|
|
241
|
+
const properties: [string, number][] = [
|
|
242
|
+
[
|
|
243
|
+
`
|
|
244
|
+
global interface MyInterface {
|
|
245
|
+
/**
|
|
246
|
+
* @ignore
|
|
247
|
+
*/
|
|
248
|
+
void myMethod();
|
|
249
|
+
}
|
|
250
|
+
`,
|
|
251
|
+
0,
|
|
252
|
+
],
|
|
253
|
+
[
|
|
254
|
+
`
|
|
255
|
+
global interface MyInterface {
|
|
256
|
+
void myMethod();
|
|
257
|
+
}
|
|
258
|
+
`,
|
|
259
|
+
1,
|
|
260
|
+
],
|
|
261
|
+
];
|
|
262
|
+
|
|
263
|
+
for (const [input, expected] of properties) {
|
|
264
|
+
const parsedFile = parsedFileFromRawString(input);
|
|
265
|
+
|
|
266
|
+
const result = filterScope(['global'], [parsedFile]);
|
|
267
|
+
|
|
268
|
+
expect((result[0].type as InterfaceMirror).methods).toHaveLength(expected);
|
|
269
|
+
}
|
|
270
|
+
});
|
|
271
|
+
});
|
|
272
|
+
|
|
273
|
+
describe('when scoping an enum', () => {
|
|
274
|
+
it('never filters out enum values, even if tagged with @ignore', () => {
|
|
275
|
+
const properties: [string, number][] = [
|
|
276
|
+
[
|
|
277
|
+
`
|
|
278
|
+
global enum MyEnum {
|
|
279
|
+
/**
|
|
280
|
+
* @ignore
|
|
281
|
+
*/
|
|
282
|
+
VALUE
|
|
283
|
+
}
|
|
284
|
+
`,
|
|
285
|
+
1,
|
|
286
|
+
],
|
|
287
|
+
[
|
|
288
|
+
`
|
|
289
|
+
global enum MyEnum {
|
|
290
|
+
VALUE
|
|
291
|
+
}
|
|
292
|
+
`,
|
|
293
|
+
1,
|
|
294
|
+
],
|
|
295
|
+
];
|
|
296
|
+
|
|
297
|
+
for (const [input, expected] of properties) {
|
|
298
|
+
const parsedFile = parsedFileFromRawString(input);
|
|
299
|
+
|
|
300
|
+
const result = filterScope(['global'], [parsedFile]);
|
|
301
|
+
|
|
302
|
+
expect((result[0].type as EnumMirror).values).toHaveLength(expected);
|
|
303
|
+
}
|
|
304
|
+
});
|
|
305
|
+
});
|
|
306
|
+
});
|
|
@@ -1,17 +1,5 @@
|
|
|
1
1
|
import { Type } from '@cparra/apex-reflection';
|
|
2
2
|
|
|
3
|
-
export type Generator = 'markdown' | 'openapi';
|
|
4
|
-
|
|
5
|
-
/**
|
|
6
|
-
* The configurable hooks that can be used to modify the output of the generator.
|
|
7
|
-
*/
|
|
8
|
-
export type ConfigurableHooks = {
|
|
9
|
-
transformReferenceGuide: TransformReferenceGuide;
|
|
10
|
-
transformDocs: TransformDocs;
|
|
11
|
-
transformDocPage: TransformDocPage;
|
|
12
|
-
transformReference: TransformReference;
|
|
13
|
-
};
|
|
14
|
-
|
|
15
3
|
type LinkingStrategy =
|
|
16
4
|
// Links will be generated using relative paths.
|
|
17
5
|
| 'relative'
|
|
@@ -24,8 +12,8 @@ type LinkingStrategy =
|
|
|
24
12
|
| 'none';
|
|
25
13
|
|
|
26
14
|
export type UserDefinedMarkdownConfig = {
|
|
27
|
-
targetGenerator: 'markdown';
|
|
28
15
|
sourceDir: string;
|
|
16
|
+
targetGenerator: 'markdown';
|
|
29
17
|
targetDir: string;
|
|
30
18
|
scope: string[];
|
|
31
19
|
defaultGroupName: string;
|
|
@@ -115,11 +103,21 @@ export type PostHookDocumentationBundle = {
|
|
|
115
103
|
docs: DocPageData[];
|
|
116
104
|
};
|
|
117
105
|
|
|
118
|
-
//
|
|
106
|
+
// CONFIGURABLE HOOKS
|
|
107
|
+
|
|
108
|
+
/**
|
|
109
|
+
* The configurable hooks that can be used to modify the output of the generator.
|
|
110
|
+
*/
|
|
111
|
+
export type ConfigurableHooks = {
|
|
112
|
+
transformReferenceGuide: TransformReferenceGuide;
|
|
113
|
+
transformDocs: TransformDocs;
|
|
114
|
+
transformDocPage: TransformDocPage;
|
|
115
|
+
transformReference: TransformReference;
|
|
116
|
+
};
|
|
119
117
|
|
|
120
|
-
type ConfigurableDocPageReference = Omit<DocPageReference, 'source'>;
|
|
118
|
+
export type ConfigurableDocPageReference = Omit<DocPageReference, 'source'>;
|
|
121
119
|
|
|
122
|
-
type ConfigurableDocPageData = Omit<DocPageData, 'source' | 'outputDocPath'>;
|
|
120
|
+
export type ConfigurableDocPageData = Omit<DocPageData, 'source' | 'outputDocPath'>;
|
|
123
121
|
|
|
124
122
|
/**
|
|
125
123
|
* Allows changing where the files are written to.
|
package/src/index.ts
CHANGED
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import { SetOptional } from 'type-fest';
|
|
2
1
|
import type {
|
|
3
2
|
ConfigurableHooks,
|
|
4
3
|
Skip,
|
|
@@ -6,18 +5,18 @@ import type {
|
|
|
6
5
|
ReferenceGuidePageData,
|
|
7
6
|
DocPageData,
|
|
8
7
|
DocPageReference,
|
|
8
|
+
ConfigurableDocPageData,
|
|
9
|
+
TransformReferenceGuide,
|
|
10
|
+
TransformDocs,
|
|
11
|
+
TransformDocPage,
|
|
12
|
+
TransformReference,
|
|
13
|
+
ConfigurableDocPageReference,
|
|
9
14
|
} from './core/shared/types';
|
|
10
15
|
import { defaults } from './defaults';
|
|
11
16
|
|
|
12
|
-
type ConfigurableMarkdownConfig = Omit<
|
|
13
|
-
SetOptional<
|
|
14
|
-
UserDefinedMarkdownConfig,
|
|
15
|
-
'targetDir' | 'scope' | 'defaultGroupName' | 'includeMetadata' | 'sortMembersAlphabetically' | 'linkingStrategy'
|
|
16
|
-
>,
|
|
17
|
-
'targetGenerator'
|
|
18
|
-
>;
|
|
17
|
+
type ConfigurableMarkdownConfig = Omit<Partial<UserDefinedMarkdownConfig>, 'targetGenerator'>;
|
|
19
18
|
|
|
20
|
-
function defineMarkdownConfig(config: ConfigurableMarkdownConfig): UserDefinedMarkdownConfig {
|
|
19
|
+
function defineMarkdownConfig(config: ConfigurableMarkdownConfig): Partial<UserDefinedMarkdownConfig> {
|
|
21
20
|
return {
|
|
22
21
|
...defaults,
|
|
23
22
|
...config,
|
|
@@ -33,4 +32,18 @@ function skip(): Skip {
|
|
|
33
32
|
|
|
34
33
|
// Exports
|
|
35
34
|
|
|
36
|
-
export {
|
|
35
|
+
export {
|
|
36
|
+
defineMarkdownConfig,
|
|
37
|
+
skip,
|
|
38
|
+
TransformReferenceGuide,
|
|
39
|
+
TransformDocs,
|
|
40
|
+
TransformDocPage,
|
|
41
|
+
TransformReference,
|
|
42
|
+
ConfigurableHooks,
|
|
43
|
+
ReferenceGuidePageData,
|
|
44
|
+
DocPageData,
|
|
45
|
+
DocPageReference,
|
|
46
|
+
Skip,
|
|
47
|
+
ConfigurableDocPageData,
|
|
48
|
+
ConfigurableDocPageReference,
|
|
49
|
+
};
|