@cparra/apexdocs 3.12.2 → 3.13.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
@@ -84,6 +84,12 @@ Run the following command to generate markdown files for your global Salesforce
84
84
 
85
85
  ```bash
86
86
  apexdocs markdown -s force-app
87
+
88
+ # Use sfdx-project.json as the source of directories
89
+ apexdocs markdown --useSfdxProjectJson
90
+
91
+ # Specify multiple source directories
92
+ apexdocs markdown --sourceDirs force-app force-lwc force-utils
87
93
  ```
88
94
 
89
95
  #### OpenApi
@@ -111,21 +117,31 @@ apexdocs changelog --previousVersionDir force-app-previous --currentVersionDir f
111
117
 
112
118
  #### Flags
113
119
 
114
- | Flag | Alias | Description | Default | Required |
115
- |----------------------------|-------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|------------------|----------|
116
- | `--sourceDir` | `-s` | The directory where the source files are located. | N/A | Yes |
117
- | `--targetDir` | `-t` | The directory where the generated files will be placed. | `docs` | No |
118
- | `--scope` | `-p` | A list of scopes to document. Values should be separated by a space, e.g --scope global public namespaceaccessible. | `[global]` | No |
119
- | `--customObjectVisibility` | `-v` | Controls which custom objects are documented. Values should be separated by a space. | `[public]` | No |
120
- | `--defaultGroupName` | N/A | The default group name to use when a group is not specified. | `Miscellaneous` | No |
121
- | `--namespace` | N/A | The package namespace, if any. If provided, it will be added to the generated files. | N/A | No |
122
- | `--sortAlphabetically` | N/A | Sorts files appearing in the Reference Guide alphabetically, as well as the members of a class, interface or enum alphabetically. If false, the members will be displayed in the same order as the code. | `false` | No |
123
- | `--includeMetadata ` | N/A | Whether to include the file's meta.xml information: Whether it is active and and the API version | `false` | No |
124
- | `--linkingStrategy` | N/A | The strategy to use when linking to other classes. Possible values are `relative`, `no-link`, and `none` | `relative` | No |
125
- | `--customObjectsGroupName` | N/A | The name under which custom objects will be grouped in the Reference Guide | `Custom Objects` | No |
126
- | `--triggersGroupName` | N/A | The name under which triggers will be grouped in the Reference Guide | `Triggers` | No |
127
- | `--includeFieldSecurityMetadata` | N/A | Whether to include the compliance category and security classification for fields in the generated files. | `false` | No |
128
- | `--includeInlineHelpTextMetadata` | N/A | Whether to include the inline help text for fields in the generated files. | `false` | No |
120
+ | Flag | Alias | Description | Default | Required |
121
+ |-----------------------------------|-------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|------------------|----------|
122
+ | `--sourceDir` | `-s` | The directory where the source files are located. | N/A | * |
123
+ | `--sourceDirs` | N/A | Multiple source directories (space-separated). Cannot be used with `--sourceDir` or `--useSfdxProjectJson`. | N/A | * |
124
+ | `--useSfdxProjectJson` | N/A | Read source directories from `sfdx-project.json` packageDirectories. Cannot be used with `--sourceDir` or `--sourceDirs`. | `false` | * |
125
+ | `--sfdxProjectPath` | N/A | Path to directory containing `sfdx-project.json` (defaults to current directory). Only used with `--useSfdxProjectJson`. | `process.cwd()` | No |
126
+ | `--targetDir` | `-t` | The directory where the generated files will be placed. | `docs` | No |
127
+ | `--scope` | `-p` | A list of scopes to document. Values should be separated by a space, e.g --scope global public namespaceaccessible. | `[global]` | No |
128
+ | `--customObjectVisibility` | `-v` | Controls which custom objects are documented. Values should be separated by a space. | `[public]` | No |
129
+ | `--defaultGroupName` | N/A | The default group name to use when a group is not specified. | `Miscellaneous` | No |
130
+ | `--namespace` | N/A | The package namespace, if any. If provided, it will be added to the generated files. | N/A | No |
131
+ | `--sortAlphabetically` | N/A | Sorts files appearing in the Reference Guide alphabetically, as well as the members of a class, interface or enum alphabetically. If false, the members will be displayed in the same order as the code. | `false` | No |
132
+ | `--includeMetadata ` | N/A | Whether to include the file's meta.xml information: Whether it is active and and the API version | `false` | No |
133
+ | `--linkingStrategy` | N/A | The strategy to use when linking to other classes. Possible values are `relative`, `no-link`, and `none` | `relative` | No |
134
+ | `--customObjectsGroupName` | N/A | The name under which custom objects will be grouped in the Reference Guide | `Custom Objects` | No |
135
+ | `--triggersGroupName` | N/A | The name under which triggers will be grouped in the Reference Guide | `Triggers` | No |
136
+ | `--includeFieldSecurityMetadata` | N/A | Whether to include the compliance category and security classification for fields in the generated files. | `false` | No |
137
+ | `--includeInlineHelpTextMetadata` | N/A | Whether to include the inline help text for fields in the generated files. | `false` | No |
138
+
139
+ > **Note:** The `*` in the Required column indicates that **one** of the source directory options must be specified:
140
+ > - `--sourceDir` (single directory)
141
+ > - `--sourceDirs` (multiple directories)
142
+ > - `--useSfdxProjectJson` (read from sfdx-project.json)
143
+ >
144
+ > These options are mutually exclusive - you cannot use more than one at the same time.
129
145
 
130
146
  ##### Linking Strategy
131
147
 
@@ -365,7 +381,8 @@ having to copy-paste the same text across multiple classes, polluting your
365
381
  source code.
366
382
 
367
383
  A macro can be defined in your documentation using the `{{macro_name}}` syntax.
368
- In the configuration file, you can then define the macro behavior as a key-value pair, where the key is the name of the macro, and the value is a function that returns the text to inject in place of the macro.
384
+ In the configuration file, you can then define the macro behavior as a key-value pair, where the key is the name of the
385
+ macro, and the value is a function that returns the text to inject in place of the macro.
369
386
 
370
387
  **Type**
371
388
 
@@ -379,7 +396,8 @@ type MacroSourceMetadata = {
379
396
  type MacroFunction = (metadata: MacroSourceMetadata) => string;
380
397
  ```
381
398
 
382
- Notice that the `metadata` object contains information about the source of the file for which the macro is being injected. This allows you to optionally
399
+ Notice that the `metadata` object contains information about the source of the file for which the macro is being
400
+ injected. This allows you to optionally
383
401
  return different text based on the source of the file.
384
402
 
385
403
  Example: Injecting a copyright notice
@@ -402,13 +420,14 @@ And then in your source code, you can use the macro like this:
402
420
  * @description This is a class
403
421
  */
404
422
  public class MyClass {
405
- //...
423
+ //...
406
424
  }
407
425
  ```
408
426
 
409
427
  ##### **transformReferenceGuide**
410
428
 
411
- Allows changing the frontmatter and content of the reference guide, or if creating a reference guide page altogether should be skipped.
429
+ Allows changing the frontmatter and content of the reference guide, or if creating a reference guide page altogether
430
+ should be skipped.
412
431
 
413
432
  **Type**
414
433
 
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env node
2
2
  'use strict';
3
3
 
4
- var logger$1 = require('../logger-B8yR_O0h.js');
4
+ var logger$1 = require('../logger-BiPQ_i9-.js');
5
5
  var require$$0 = require('yargs');
6
6
  var cosmiconfig = require('cosmiconfig');
7
7
  var E = require('fp-ts/Either');
@@ -43,12 +43,34 @@ function _interopNamespaceDefault(e) {
43
43
 
44
44
  var E__namespace = /*#__PURE__*/_interopNamespaceDefault(E);
45
45
 
46
+ function validateMarkdownArgs(argv) {
47
+ const hasSourceDir = argv.sourceDir && (typeof argv.sourceDir === "string" || Array.isArray(argv.sourceDir) && argv.sourceDir.length > 0);
48
+ const hasUseSfdxProjectJson = argv.useSfdxProjectJson;
49
+ if (!hasSourceDir && !hasUseSfdxProjectJson) {
50
+ throw new Error("Must specify one of: --sourceDir or --useSfdxProjectJson");
51
+ }
52
+ return true;
53
+ }
46
54
  const markdownOptions = {
47
55
  sourceDir: {
48
56
  type: "string",
57
+ array: true,
49
58
  alias: "s",
50
- demandOption: true,
51
- describe: "The directory location which contains your apex .cls classes."
59
+ demandOption: false,
60
+ describe: "The directory location(s) which contain your apex .cls classes. Can specify a single directory or multiple directories. Cannot be used with useSfdxProjectJson.",
61
+ conflicts: ["useSfdxProjectJson"]
62
+ },
63
+ useSfdxProjectJson: {
64
+ type: "boolean",
65
+ demandOption: false,
66
+ describe: "Read source directories from sfdx-project.json packageDirectories. Cannot be used with sourceDir.",
67
+ conflicts: ["sourceDir"]
68
+ },
69
+ sfdxProjectPath: {
70
+ type: "string",
71
+ demandOption: false,
72
+ describe: "Path to the directory containing sfdx-project.json (defaults to current working directory). Only used with useSfdxProjectJson.",
73
+ implies: "useSfdxProjectJson"
52
74
  },
53
75
  targetDir: {
54
76
  type: "string",
@@ -122,12 +144,34 @@ const markdownOptions = {
122
144
  }
123
145
  };
124
146
 
147
+ function validateOpenApiArgs(argv) {
148
+ const hasSourceDir = argv.sourceDir && (typeof argv.sourceDir === "string" || Array.isArray(argv.sourceDir) && argv.sourceDir.length > 0);
149
+ const hasUseSfdxProjectJson = argv.useSfdxProjectJson;
150
+ if (!hasSourceDir && !hasUseSfdxProjectJson) {
151
+ throw new Error("Must specify one of: --sourceDir or --useSfdxProjectJson");
152
+ }
153
+ return true;
154
+ }
125
155
  const openApiOptions = {
126
156
  sourceDir: {
127
157
  type: "string",
158
+ array: true,
128
159
  alias: "s",
129
- demandOption: true,
130
- describe: "The directory location which contains your apex .cls classes."
160
+ demandOption: false,
161
+ describe: "The directory location(s) which contain your apex .cls classes. Can specify a single directory or multiple directories. Cannot be used with useSfdxProjectJson.",
162
+ conflicts: ["useSfdxProjectJson"]
163
+ },
164
+ useSfdxProjectJson: {
165
+ type: "boolean",
166
+ demandOption: false,
167
+ describe: "Read source directories from sfdx-project.json packageDirectories. Cannot be used with sourceDir.",
168
+ conflicts: ["sourceDir"]
169
+ },
170
+ sfdxProjectPath: {
171
+ type: "string",
172
+ demandOption: false,
173
+ describe: "Path to the directory containing sfdx-project.json (defaults to current working directory). Only used with useSfdxProjectJson.",
174
+ implies: "useSfdxProjectJson"
131
175
  },
132
176
  targetDir: {
133
177
  type: "string",
@@ -156,18 +200,31 @@ const openApiOptions = {
156
200
  }
157
201
  };
158
202
 
203
+ function validateChangelogArgs(argv) {
204
+ const hasPreviousVersionDir = argv.previousVersionDir && (typeof argv.previousVersionDir === "string" || Array.isArray(argv.previousVersionDir) && argv.previousVersionDir.length > 0);
205
+ const hasCurrentVersionDir = argv.currentVersionDir && (typeof argv.currentVersionDir === "string" || Array.isArray(argv.currentVersionDir) && argv.currentVersionDir.length > 0);
206
+ if (!hasPreviousVersionDir) {
207
+ throw new Error("Must specify --previousVersionDir");
208
+ }
209
+ if (!hasCurrentVersionDir) {
210
+ throw new Error("Must specify --currentVersionDir");
211
+ }
212
+ return true;
213
+ }
159
214
  const changeLogOptions = {
160
215
  previousVersionDir: {
161
216
  type: "string",
217
+ array: true,
162
218
  alias: "p",
163
- demandOption: true,
164
- describe: "The directory location of the previous version of the source code."
219
+ demandOption: false,
220
+ describe: "The directory location(s) of the previous version of the source code. Can specify a single directory or multiple directories."
165
221
  },
166
222
  currentVersionDir: {
167
223
  type: "string",
224
+ array: true,
168
225
  alias: "c",
169
- demandOption: true,
170
- describe: "The directory location of the current version of the source code."
226
+ demandOption: false,
227
+ describe: "The directory location(s) of the current version of the source code. Can specify a single directory or multiple directories."
171
228
  },
172
229
  targetDir: {
173
230
  type: "string",
@@ -297,11 +354,23 @@ function extractArgsForCommandProvidedThroughCli(extractFromProcessFn, config) {
297
354
  const mergedConfig = __spreadProps(__spreadValues(__spreadValues({}, config.config), cliArgs), { targetGenerator: commandName });
298
355
  switch (mergedConfig.targetGenerator) {
299
356
  case "markdown":
300
- return E__namespace.right(__spreadValues(__spreadValues({}, configOnlyMarkdownDefaults), mergedConfig));
357
+ return _function.pipe(
358
+ logger$1.validateSourceDirectoryConfig(extractSourceDirectoryConfig(mergedConfig)),
359
+ E__namespace.mapLeft((error) => new Error(`Invalid markdown configuration: ${error.message}`)),
360
+ E__namespace.map(() => __spreadValues(__spreadValues({}, configOnlyMarkdownDefaults), mergedConfig))
361
+ );
301
362
  case "openapi":
302
- return E__namespace.right(__spreadValues(__spreadValues({}, configOnlyOpenApiDefaults), mergedConfig));
363
+ return _function.pipe(
364
+ logger$1.validateSourceDirectoryConfig(extractSourceDirectoryConfig(mergedConfig)),
365
+ E__namespace.mapLeft((error) => new Error(`Invalid openapi configuration: ${error.message}`)),
366
+ E__namespace.map(() => __spreadValues(__spreadValues({}, configOnlyOpenApiDefaults), mergedConfig))
367
+ );
303
368
  case "changelog":
304
- return E__namespace.right(__spreadValues(__spreadValues({}, configOnlyChangelogDefaults), mergedConfig));
369
+ return _function.pipe(
370
+ validateChangelogConfig(mergedConfig),
371
+ E__namespace.mapLeft((error) => new Error(`Invalid changelog configuration: ${error.message}`)),
372
+ E__namespace.map(() => __spreadValues(__spreadValues({}, configOnlyChangelogDefaults), mergedConfig))
373
+ );
305
374
  default:
306
375
  return E__namespace.left(new Error(`Invalid command provided: ${mergedConfig.targetGenerator}`));
307
376
  }
@@ -317,12 +386,26 @@ function extractArgsForCommandsProvidedInConfig(extractFromProcessFn, config) {
317
386
  E__namespace.map((cliArgs) => {
318
387
  return cliArgs;
319
388
  }),
320
- E__namespace.map((cliArgs) => __spreadValues(__spreadValues(__spreadValues({}, configOnlyMarkdownDefaults), generatorConfig), cliArgs))
389
+ E__namespace.flatMap((cliArgs) => {
390
+ const mergedConfig = __spreadValues(__spreadValues(__spreadValues({}, configOnlyMarkdownDefaults), generatorConfig), cliArgs);
391
+ return _function.pipe(
392
+ logger$1.validateSourceDirectoryConfig(extractSourceDirectoryConfig(mergedConfig)),
393
+ E__namespace.mapLeft((error) => new Error(`Invalid markdown configuration: ${error.message}`)),
394
+ E__namespace.map(() => mergedConfig)
395
+ );
396
+ })
321
397
  );
322
398
  case "openapi":
323
399
  return _function.pipe(
324
400
  extractMultiCommandConfig(extractFromProcessFn, "openapi", generatorConfig),
325
- E__namespace.map((cliArgs) => __spreadValues(__spreadValues(__spreadValues({}, configOnlyOpenApiDefaults), generatorConfig), cliArgs))
401
+ E__namespace.flatMap((cliArgs) => {
402
+ const mergedConfig = __spreadValues(__spreadValues(__spreadValues({}, configOnlyOpenApiDefaults), generatorConfig), cliArgs);
403
+ return _function.pipe(
404
+ logger$1.validateSourceDirectoryConfig(extractSourceDirectoryConfig(mergedConfig)),
405
+ E__namespace.mapLeft((error) => new Error(`Invalid openapi configuration: ${error.message}`)),
406
+ E__namespace.map(() => mergedConfig)
407
+ );
408
+ })
326
409
  );
327
410
  case "changelog":
328
411
  return _function.pipe(
@@ -330,7 +413,14 @@ function extractArgsForCommandsProvidedInConfig(extractFromProcessFn, config) {
330
413
  E__namespace.map((cliArgs) => {
331
414
  return cliArgs;
332
415
  }),
333
- E__namespace.map((cliArgs) => __spreadValues(__spreadValues(__spreadValues({}, configOnlyChangelogDefaults), generatorConfig), cliArgs))
416
+ E__namespace.flatMap((cliArgs) => {
417
+ const mergedConfig = __spreadValues(__spreadValues(__spreadValues({}, configOnlyChangelogDefaults), generatorConfig), cliArgs);
418
+ return _function.pipe(
419
+ validateChangelogConfig(mergedConfig),
420
+ E__namespace.mapLeft((error) => new Error(`Invalid changelog configuration: ${error.message}`)),
421
+ E__namespace.map(() => mergedConfig)
422
+ );
423
+ })
334
424
  );
335
425
  }
336
426
  });
@@ -360,15 +450,15 @@ function extractYargsDemandingCommand(extractFromProcessFn, config) {
360
450
  return yargs.config(config.config).command(
361
451
  "markdown",
362
452
  "Generate documentation from Apex classes as a Markdown site.",
363
- (yargs2) => yargs2.options(markdownOptions)
453
+ (yargs2) => yargs2.options(markdownOptions).check(validateMarkdownArgs)
364
454
  ).command(
365
455
  "openapi",
366
456
  "Generate an OpenApi REST specification from Apex classes.",
367
- () => yargs.options(openApiOptions)
457
+ (yargs2) => yargs2.options(openApiOptions).check(validateOpenApiArgs)
368
458
  ).command(
369
459
  "changelog",
370
460
  "Generate a changelog from 2 versions of the source code.",
371
- () => yargs.options(changeLogOptions)
461
+ (yargs2) => yargs2.options(changeLogOptions).check(validateChangelogArgs)
372
462
  ).demandCommand().parseSync(extractFromProcessFn());
373
463
  }
374
464
  function extractMultiCommandConfig(extractFromProcessFn, command, config) {
@@ -382,13 +472,45 @@ function extractMultiCommandConfig(extractFromProcessFn, command, config) {
382
472
  return changeLogOptions;
383
473
  }
384
474
  }
475
+ function getValidationFunction(generator) {
476
+ switch (generator) {
477
+ case "markdown":
478
+ return validateMarkdownArgs;
479
+ case "openapi":
480
+ return validateOpenApiArgs;
481
+ case "changelog":
482
+ return validateChangelogArgs;
483
+ }
484
+ }
385
485
  const options = getOptions(command);
486
+ const validator = getValidationFunction(command);
386
487
  return E__namespace.tryCatch(() => {
387
- return yargs(extractFromProcessFn()).config(config).options(options).fail((msg) => {
488
+ return yargs(extractFromProcessFn()).config(config).options(options).check(validator).fail((msg) => {
388
489
  throw new Error(`Invalid configuration for command "${command}": ${msg}`);
389
490
  }).parseSync();
390
491
  }, E__namespace.toError);
391
492
  }
493
+ function extractSourceDirectoryConfig(config) {
494
+ return {
495
+ sourceDir: config.sourceDir,
496
+ useSfdxProjectJson: config.useSfdxProjectJson,
497
+ sfdxProjectPath: config.sfdxProjectPath
498
+ };
499
+ }
500
+ function validateChangelogConfig(config) {
501
+ const previousVersionConfig = {
502
+ sourceDir: config.previousVersionDir
503
+ };
504
+ const currentVersionConfig = {
505
+ sourceDir: config.currentVersionDir
506
+ };
507
+ return _function.pipe(
508
+ E__namespace.Do,
509
+ E__namespace.bind("previousValid", () => logger$1.validateSourceDirectoryConfig(previousVersionConfig)),
510
+ E__namespace.bind("currentValid", () => logger$1.validateSourceDirectoryConfig(currentVersionConfig)),
511
+ E__namespace.map(() => config)
512
+ );
513
+ }
392
514
 
393
515
  var __async = (__this, __arguments, generator) => {
394
516
  return new Promise((resolve, reject) => {
package/dist/index.d.ts CHANGED
@@ -20,7 +20,9 @@ type MacroSourceMetadata = {
20
20
  type MacroFunction = (metadata: MacroSourceMetadata) => string;
21
21
 
22
22
  type CliConfigurableMarkdownConfig = {
23
- sourceDir: string;
23
+ sourceDir?: string | string[];
24
+ useSfdxProjectJson?: boolean;
25
+ sfdxProjectPath?: string;
24
26
  targetDir: string;
25
27
  scope: string[];
26
28
  customObjectVisibility: string[];
@@ -45,7 +47,9 @@ type UserDefinedMarkdownConfig = {
45
47
 
46
48
  type UserDefinedOpenApiConfig = {
47
49
  targetGenerator: 'openapi';
48
- sourceDir: string;
50
+ sourceDir?: string | string[];
51
+ useSfdxProjectJson?: boolean;
52
+ sfdxProjectPath?: string;
49
53
  targetDir: string;
50
54
  fileName: string;
51
55
  namespace?: string;
@@ -56,8 +60,8 @@ type UserDefinedOpenApiConfig = {
56
60
 
57
61
  type UserDefinedChangelogConfig = {
58
62
  targetGenerator: 'changelog';
59
- previousVersionDir: string;
60
- currentVersionDir: string;
63
+ previousVersionDir?: string | string[];
64
+ currentVersionDir?: string | string[];
61
65
  targetDir: string;
62
66
  fileName: string;
63
67
  scope: string[];
package/dist/index.js CHANGED
@@ -1,6 +1,6 @@
1
1
  'use strict';
2
2
 
3
- var logger = require('./logger-B8yR_O0h.js');
3
+ var logger = require('./logger-BiPQ_i9-.js');
4
4
  var E = require('fp-ts/Either');
5
5
  require('fp-ts/function');
6
6
  require('fp-ts/TaskEither');
@@ -3829,8 +3829,9 @@ var __async$2 = (__this, __arguments, generator) => {
3829
3829
  };
3830
3830
  function openApi(logger, fileBodies, config) {
3831
3831
  return __async$2(this, null, function* () {
3832
+ const sourceDirectory = (Array.isArray(config.sourceDir) ? config.sourceDir[0] : config.sourceDir) || (fileBodies.length > 0 ? fileBodies[0].filePath.split("/").slice(0, -1).join("/") : process.cwd());
3832
3833
  OpenApiSettings.build({
3833
- sourceDirectory: config.sourceDir,
3834
+ sourceDirectory,
3834
3835
  outputDir: config.targetDir,
3835
3836
  openApiFileName: config.fileName,
3836
3837
  openApiTitle: config.title,
@@ -4779,9 +4780,11 @@ function processFiles(fileSystem) {
4779
4780
  )
4780
4781
  };
4781
4782
  const convertersToUse = componentTypesToRetrieve.map((componentType) => converters[componentType]);
4782
- return (rootPath, exclude) => {
4783
+ return (rootPaths, exclude) => {
4784
+ const paths = Array.isArray(rootPaths) ? rootPaths : [rootPaths];
4785
+ const allComponents = paths.flatMap((path) => fileSystem.getComponents(path));
4783
4786
  return _function.pipe(
4784
- fileSystem.getComponents(rootPath),
4787
+ allComponents,
4785
4788
  (components) => {
4786
4789
  return components.map((component) => {
4787
4790
  const pathLocation = component.type.name === "ApexClass" ? component.content : component.xml;
@@ -4827,6 +4830,132 @@ class DefaultFileSystem {
4827
4830
  }
4828
4831
  }
4829
4832
 
4833
+ function createSfdxProjectReadError(message, cause) {
4834
+ return {
4835
+ _tag: "SfdxProjectReadError",
4836
+ message,
4837
+ cause
4838
+ };
4839
+ }
4840
+ function readSfdxProjectConfig(projectRoot) {
4841
+ const sfdxProjectPath = path__namespace.join(projectRoot, "sfdx-project.json");
4842
+ return _function.pipe(
4843
+ E__namespace.tryCatch(
4844
+ () => {
4845
+ if (!fs__namespace.existsSync(sfdxProjectPath)) {
4846
+ throw new Error(`sfdx-project.json not found at ${sfdxProjectPath}`);
4847
+ }
4848
+ return fs__namespace.readFileSync(sfdxProjectPath, "utf8");
4849
+ },
4850
+ (error) => createSfdxProjectReadError(`Failed to read sfdx-project.json: ${error}`, error)
4851
+ ),
4852
+ E__namespace.flatMap(
4853
+ (content) => E__namespace.tryCatch(
4854
+ () => JSON.parse(content),
4855
+ (error) => createSfdxProjectReadError(`Failed to parse sfdx-project.json: ${error}`, error)
4856
+ )
4857
+ ),
4858
+ E__namespace.flatMap((config) => {
4859
+ if (!config.packageDirectories || !Array.isArray(config.packageDirectories)) {
4860
+ return E__namespace.left(
4861
+ createSfdxProjectReadError("sfdx-project.json does not contain a valid packageDirectories array")
4862
+ );
4863
+ }
4864
+ return E__namespace.right(config);
4865
+ })
4866
+ );
4867
+ }
4868
+ function getSfdxSourceDirectories(projectRoot, absolutePaths = true) {
4869
+ return _function.pipe(
4870
+ readSfdxProjectConfig(projectRoot),
4871
+ E__namespace.map((config) => config.packageDirectories.map((dir) => dir.path)),
4872
+ E__namespace.map((paths) => {
4873
+ if (absolutePaths) {
4874
+ return paths.map((dirPath) => path__namespace.resolve(projectRoot, dirPath));
4875
+ }
4876
+ return paths;
4877
+ }),
4878
+ E__namespace.flatMap((paths) => {
4879
+ const nonExistentPaths = paths.filter((dirPath) => !fs__namespace.existsSync(dirPath));
4880
+ if (nonExistentPaths.length > 0) {
4881
+ return E__namespace.left(
4882
+ createSfdxProjectReadError(
4883
+ `The following package directories do not exist: ${nonExistentPaths.join(", ")}`
4884
+ )
4885
+ );
4886
+ }
4887
+ return E__namespace.right(paths);
4888
+ })
4889
+ );
4890
+ }
4891
+
4892
+ function createSourceDirectoryResolutionError(message, cause) {
4893
+ return {
4894
+ _tag: "SourceDirectoryResolutionError",
4895
+ message,
4896
+ cause
4897
+ };
4898
+ }
4899
+ function resolveSourceDirectories(config) {
4900
+ const { sourceDir, useSfdxProjectJson, sfdxProjectPath } = config;
4901
+ const hasSourceDir = sourceDir && (typeof sourceDir === "string" || Array.isArray(sourceDir) && sourceDir.length > 0);
4902
+ const methodsSpecified = [hasSourceDir, useSfdxProjectJson].filter(Boolean).length;
4903
+ if (methodsSpecified === 0) {
4904
+ return E__namespace.left(
4905
+ createSourceDirectoryResolutionError(
4906
+ "No source directory method specified. Must provide one of: sourceDir or useSfdxProjectJson."
4907
+ )
4908
+ );
4909
+ }
4910
+ if (methodsSpecified > 1) {
4911
+ return E__namespace.left(
4912
+ createSourceDirectoryResolutionError(
4913
+ "Multiple source directory methods specified. Only one of sourceDir or useSfdxProjectJson can be used."
4914
+ )
4915
+ );
4916
+ }
4917
+ if (sourceDir) {
4918
+ if (typeof sourceDir === "string") {
4919
+ return E__namespace.right([sourceDir]);
4920
+ } else if (Array.isArray(sourceDir)) {
4921
+ return E__namespace.right(sourceDir);
4922
+ }
4923
+ }
4924
+ if (useSfdxProjectJson) {
4925
+ const projectPath = sfdxProjectPath || process.cwd();
4926
+ return _function.pipe(
4927
+ getSfdxSourceDirectories(projectPath),
4928
+ E__namespace.mapLeft(
4929
+ (sfdxError) => createSourceDirectoryResolutionError(
4930
+ `Failed to read source directories from sfdx-project.json: ${sfdxError.message}`,
4931
+ sfdxError
4932
+ )
4933
+ )
4934
+ );
4935
+ }
4936
+ return E__namespace.left(createSourceDirectoryResolutionError("Invalid source directory configuration."));
4937
+ }
4938
+ function validateSourceDirectoryConfig(config) {
4939
+ const { sourceDir, useSfdxProjectJson, sfdxProjectPath } = config;
4940
+ if (sourceDir && useSfdxProjectJson) {
4941
+ return E__namespace.left(
4942
+ createSourceDirectoryResolutionError("Cannot specify both sourceDir and useSfdxProjectJson. Use only one.")
4943
+ );
4944
+ }
4945
+ if (sfdxProjectPath && !useSfdxProjectJson) {
4946
+ return E__namespace.left(createSourceDirectoryResolutionError("sfdxProjectPath can only be used with useSfdxProjectJson."));
4947
+ }
4948
+ if (Array.isArray(sourceDir) && sourceDir.length === 0) {
4949
+ return E__namespace.left(
4950
+ createSourceDirectoryResolutionError("sourceDir array cannot be empty. Provide at least one directory.")
4951
+ );
4952
+ }
4953
+ return E__namespace.right(config);
4954
+ }
4955
+ function resolveAndValidateSourceDirectories(config) {
4956
+ return _function.pipe(validateSourceDirectoryConfig(config), E__namespace.flatMap(resolveSourceDirectories));
4957
+ }
4958
+
4830
4959
  var __async = (__this, __arguments, generator) => {
4831
4960
  return new Promise((resolve, reject) => {
4832
4961
  var fulfilled = (value) => {
@@ -4874,11 +5003,15 @@ const readFiles = processFiles(new DefaultFileSystem());
4874
5003
  function processMarkdown(config) {
4875
5004
  return __async(this, null, function* () {
4876
5005
  return _function.pipe(
4877
- E__namespace.tryCatch(
4878
- () => readFiles(allComponentTypes, {
4879
- includeMetadata: config.includeMetadata
4880
- })(config.sourceDir, config.exclude),
4881
- (e) => new FileReadingError("An error occurred while reading files.", e)
5006
+ resolveAndValidateSourceDirectories(config),
5007
+ E__namespace.mapLeft((error) => new FileReadingError(`Failed to resolve source directories: ${error.message}`, error)),
5008
+ E__namespace.flatMap(
5009
+ (sourceDirs) => E__namespace.tryCatch(
5010
+ () => readFiles(allComponentTypes, {
5011
+ includeMetadata: config.includeMetadata
5012
+ })(sourceDirs, config.exclude),
5013
+ (e) => new FileReadingError("An error occurred while reading files.", e)
5014
+ )
4882
5015
  ),
4883
5016
  TE__namespace.fromEither,
4884
5017
  TE__namespace.flatMap((fileBodies) => generate$1(fileBodies, config)),
@@ -4889,20 +5022,59 @@ function processMarkdown(config) {
4889
5022
  }
4890
5023
  function processOpenApi(config, logger) {
4891
5024
  return __async(this, null, function* () {
4892
- const fileBodies = readFiles(["ApexClass"])(config.sourceDir, config.exclude);
4893
- return openApi(logger, fileBodies, config);
5025
+ return _function.pipe(
5026
+ resolveAndValidateSourceDirectories(config),
5027
+ E__namespace.mapLeft((error) => new FileReadingError(`Failed to resolve source directories: ${error.message}`, error)),
5028
+ TE__namespace.fromEither,
5029
+ TE__namespace.flatMap(
5030
+ (sourceDirs) => TE__namespace.tryCatch(
5031
+ () => {
5032
+ const fileBodies = readFiles(["ApexClass"])(sourceDirs, config.exclude);
5033
+ return openApi(logger, fileBodies, config);
5034
+ },
5035
+ (e) => new FileReadingError("An error occurred while generating OpenAPI documentation.", e)
5036
+ )
5037
+ )
5038
+ );
4894
5039
  });
4895
5040
  }
4896
5041
  function processChangeLog(config) {
4897
5042
  return __async(this, null, function* () {
4898
5043
  function loadFiles() {
4899
- return [
4900
- readFiles(allComponentTypes)(config.previousVersionDir, config.exclude),
4901
- readFiles(allComponentTypes)(config.currentVersionDir, config.exclude)
4902
- ];
5044
+ const previousVersionConfig = {
5045
+ sourceDir: config.previousVersionDir
5046
+ };
5047
+ const currentVersionConfig = {
5048
+ sourceDir: config.currentVersionDir
5049
+ };
5050
+ return _function.pipe(
5051
+ E__namespace.Do,
5052
+ E__namespace.bind(
5053
+ "previousVersionDirs",
5054
+ () => _function.pipe(
5055
+ resolveAndValidateSourceDirectories(previousVersionConfig),
5056
+ E__namespace.mapLeft(
5057
+ (error) => new FileReadingError(`Failed to resolve previous version source directories: ${error.message}`, error)
5058
+ )
5059
+ )
5060
+ ),
5061
+ E__namespace.bind(
5062
+ "currentVersionDirs",
5063
+ () => _function.pipe(
5064
+ resolveAndValidateSourceDirectories(currentVersionConfig),
5065
+ E__namespace.mapLeft(
5066
+ (error) => new FileReadingError(`Failed to resolve current version source directories: ${error.message}`, error)
5067
+ )
5068
+ )
5069
+ ),
5070
+ E__namespace.map(({ previousVersionDirs, currentVersionDirs }) => [
5071
+ readFiles(allComponentTypes)(previousVersionDirs, config.exclude),
5072
+ readFiles(allComponentTypes)(currentVersionDirs, config.exclude)
5073
+ ])
5074
+ );
4903
5075
  }
4904
5076
  return _function.pipe(
4905
- E__namespace.tryCatch(loadFiles, (e) => new FileReadingError("An error occurred while reading files.", e)),
5077
+ loadFiles(),
4906
5078
  TE__namespace.fromEither,
4907
5079
  TE__namespace.flatMap(([previous, current]) => generate(previous, current, config)),
4908
5080
  TE__namespace.mapLeft(toErrors)
@@ -4978,3 +5150,4 @@ exports.changeLogDefaults = changeLogDefaults;
4978
5150
  exports.markdownDefaults = markdownDefaults;
4979
5151
  exports.openApiDefaults = openApiDefaults;
4980
5152
  exports.skip = skip;
5153
+ exports.validateSourceDirectoryConfig = validateSourceDirectoryConfig;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cparra/apexdocs",
3
- "version": "3.12.2",
3
+ "version": "3.13.0",
4
4
  "description": "Library with CLI capabilities to generate documentation for Salesforce Apex classes.",
5
5
  "keywords": [
6
6
  "apex",