apextestlist 1.13.14 → 1.14.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/CHANGELOG.md +15 -0
- package/README.md +40 -1
- package/lib/parsers/manifestParser.js +22 -5
- package/lib/parsers/manifestParser.js.map +1 -1
- package/lib/parsers/metadataFilterParser.js +2 -2
- package/lib/parsers/metadataFilterParser.js.map +1 -1
- package/lib/parsers/testSuiteParser.js +8 -11
- package/lib/parsers/testSuiteParser.js.map +1 -1
- package/lib/readers/directorySearcher.js +5 -2
- package/lib/readers/directorySearcher.js.map +1 -1
- package/lib/readers/testSuiteSearcher.js +2 -2
- package/lib/readers/testSuiteSearcher.js.map +1 -1
- package/lib/utils/concurrentQueue.d.ts +11 -0
- package/lib/utils/concurrentQueue.js +49 -0
- package/lib/utils/concurrentQueue.js.map +1 -0
- package/lib/utils/xmlParser.d.ts +14 -0
- package/lib/utils/xmlParser.js +82 -0
- package/lib/utils/xmlParser.js.map +1 -0
- package/lib/utils/yamlParser.d.ts +1 -0
- package/lib/utils/yamlParser.js +79 -0
- package/lib/utils/yamlParser.js.map +1 -0
- package/oclif.manifest.json +1 -1
- package/package.json +65 -18
package/CHANGELOG.md
CHANGED
|
@@ -5,6 +5,21 @@
|
|
|
5
5
|
|
|
6
6
|
All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines.
|
|
7
7
|
|
|
8
|
+
## [1.14.0](https://github.com/wisefoxme/apex-test-list/compare/v1.13.15...v1.14.0) (2026-08-27)
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
### Features
|
|
12
|
+
|
|
13
|
+
* add GitHub Action for listing Apex tests ([#399](https://github.com/wisefoxme/apex-test-list/issues/399)) ([baca2f5](https://github.com/wisefoxme/apex-test-list/commit/baca2f5e51f26a502bf6efa23322a2fe96bde966))
|
|
14
|
+
* replace async, xml2js, yaml, and SDR with in-house parsers ([#398](https://github.com/wisefoxme/apex-test-list/issues/398)) ([001a6c6](https://github.com/wisefoxme/apex-test-list/commit/001a6c6f9f6625d28f1dac5774145fb6b0080292))
|
|
15
|
+
|
|
16
|
+
## [1.13.15](https://github.com/wisefoxme/apex-test-list/compare/v1.13.14...v1.13.15) (2026-08-24)
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
### Bug Fixes
|
|
20
|
+
|
|
21
|
+
* **deps:** bump @oclif/core in the salesforce group ([#395](https://github.com/wisefoxme/apex-test-list/issues/395)) ([9890881](https://github.com/wisefoxme/apex-test-list/commit/98908817b04725b45dabdf84b0f9e3db7c23d72f))
|
|
22
|
+
|
|
8
23
|
## [1.13.14](https://github.com/wisefoxme/apex-test-list/compare/v1.13.13...v1.13.14) (2026-08-09)
|
|
9
24
|
|
|
10
25
|
|
package/README.md
CHANGED
|
@@ -2,11 +2,12 @@
|
|
|
2
2
|
|
|
3
3
|
[](https://www.npmjs.com/package/apextestlist)
|
|
4
4
|
[](https://npmjs.org/package/apextestlist)
|
|
5
|
+
[](https://github.com/marketplace/actions/apex-test-list)
|
|
5
6
|
[](https://raw.githubusercontent.com/wisefoxme/apex-test-list/refs/heads/master/LICENSE)
|
|
6
7
|
[](https://dashboard.stryker-mutator.io/reports/github.com/wisefoxme/apex-test-list/master)
|
|
7
8
|

|
|
8
9
|
|
|
9
|
-
A plugin that generates a list of tests that your automated process should run, so you can save time by not running all tests in your Salesforce org and avoid specifying them manually.
|
|
10
|
+
A plugin that generates a list of tests that your automated process should run, so you can save time by not running all tests in your Salesforce org and avoid specifying them manually. Available as a **Salesforce CLI plugin** for any provider, and as a **native GitHub Action** for GitHub Actions users who want to skip installing the CLI.
|
|
10
11
|
|
|
11
12
|
<!-- TABLE OF CONTENTS -->
|
|
12
13
|
<details>
|
|
@@ -21,6 +22,7 @@ A plugin that generates a list of tests that your automated process should run,
|
|
|
21
22
|
- [Running the Tool](#running-the-tool)
|
|
22
23
|
- [Handling Missing Tests](#handling-missing-tests)
|
|
23
24
|
- [Handling Missing Annotations](#handling-missing-annotations)
|
|
25
|
+
- [GitHub Action](#github-action)
|
|
24
26
|
- [Command Reference](#command-reference)
|
|
25
27
|
- [Issues](#issues)
|
|
26
28
|
- [License](#license)
|
|
@@ -160,6 +162,43 @@ To remove these warnings from the terminal, use:
|
|
|
160
162
|
sf apextests list --no-warnings
|
|
161
163
|
```
|
|
162
164
|
|
|
165
|
+
## GitHub Action
|
|
166
|
+
|
|
167
|
+
For GitHub Actions, this is also available as a native Action — no `sf` CLI or plugin install required:
|
|
168
|
+
|
|
169
|
+
```yaml
|
|
170
|
+
- name: List Apex tests
|
|
171
|
+
id: list
|
|
172
|
+
uses: wisefoxme/apex-test-list@v1
|
|
173
|
+
with:
|
|
174
|
+
manifest: package.xml
|
|
175
|
+
ignore-missing-tests: 'true'
|
|
176
|
+
|
|
177
|
+
- name: Deploy with the specified tests
|
|
178
|
+
run: sf project deploy start -x package.xml ${{ steps.list.outputs.command }}
|
|
179
|
+
```
|
|
180
|
+
|
|
181
|
+
### Inputs
|
|
182
|
+
|
|
183
|
+
| Input | Description | Required | Default |
|
|
184
|
+
| ----------------------------- | ------------------------------------------------------------------------------------------------------------------------ | -------- | ------- |
|
|
185
|
+
| `format` | Output format. Available options: `sf` (default), `sfdx`, or `csv`. | No | `sf` |
|
|
186
|
+
| `manifest` | Path to a manifest XML file (`package.xml`). When set, only classes/triggers declared in it are considered. | No | |
|
|
187
|
+
| `ignore-missing-tests` | Ignore test methods that are not found in any local package directory. | No | `false` |
|
|
188
|
+
| `ignore-package-directory` | Directory to ignore when searching for test annotations, one per line. | No | |
|
|
189
|
+
| `no-warnings` | Do not print warnings for each Apex file missing annotations. | No | `false` |
|
|
190
|
+
| `filter-by-metadata` | Only include tests that explicitly declare metadata dependencies matching changed metadata. Requires `manifest`. | No | `false` |
|
|
191
|
+
| `fail-on-empty` | Fail the action if no test methods are found. | No | `false` |
|
|
192
|
+
|
|
193
|
+
### Outputs
|
|
194
|
+
|
|
195
|
+
| Output | Description |
|
|
196
|
+
| ------------- | ------------------------------------------------------------------------------------- |
|
|
197
|
+
| `tests` | Newline-separated list of Apex test class names. |
|
|
198
|
+
| `test-count` | Number of Apex test class names found. |
|
|
199
|
+
| `command` | The formatted test list, ready to append to a Salesforce CLI deploy/validate command. |
|
|
200
|
+
| `warnings` | Newline-separated list of warnings emitted while listing tests, if any. |
|
|
201
|
+
|
|
163
202
|
## Command Reference
|
|
164
203
|
|
|
165
204
|
```
|
|
@@ -1,6 +1,17 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
import { existsSync } from 'node:fs';
|
|
3
|
-
import {
|
|
3
|
+
import { readFile } from 'node:fs/promises';
|
|
4
|
+
import { findChild, findChildren, parseXml } from '../utils/xmlParser.js';
|
|
5
|
+
// Salesforce's metadata registry resolves type names case-insensitively;
|
|
6
|
+
// manifests may declare them in any case (e.g. "apexclass"), but downstream
|
|
7
|
+
// consumers compare against the canonical capitalization.
|
|
8
|
+
const CANONICAL_TYPE_NAMES = {
|
|
9
|
+
apexclass: 'ApexClass',
|
|
10
|
+
apextrigger: 'ApexTrigger',
|
|
11
|
+
};
|
|
12
|
+
function canonicalTypeName(typeName) {
|
|
13
|
+
return CANONICAL_TYPE_NAMES[typeName.toLowerCase()] ?? typeName;
|
|
14
|
+
}
|
|
4
15
|
/**
|
|
5
16
|
* Given a certain manifest file, reads that file and returns the classes,
|
|
6
17
|
* triggers and test suites members with their types as prefix.
|
|
@@ -15,10 +26,16 @@ export async function extractTypeNamesFromManifestFile(manifestFile) {
|
|
|
15
26
|
if (!manifestFile || !existsSync(manifestFile)) {
|
|
16
27
|
return result;
|
|
17
28
|
}
|
|
18
|
-
const
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
29
|
+
const content = await readFile(manifestFile, 'utf-8');
|
|
30
|
+
const root = parseXml(content);
|
|
31
|
+
for (const typesElement of findChildren(root, 'types')) {
|
|
32
|
+
const nameElement = findChild(typesElement, 'name');
|
|
33
|
+
if (!nameElement)
|
|
34
|
+
continue;
|
|
35
|
+
const typeName = canonicalTypeName(nameElement.text.trim());
|
|
36
|
+
for (const memberElement of findChildren(typesElement, 'members')) {
|
|
37
|
+
result.push(`${typeName}:${memberElement.text.trim()}`);
|
|
38
|
+
}
|
|
22
39
|
}
|
|
23
40
|
return result.sort((a, b) => a.localeCompare(b));
|
|
24
41
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"manifestParser.js","sourceRoot":"","sources":["../../src/parsers/manifestParser.ts"],"names":[],"mappings":"AAAA,YAAY,CAAC;AAEb,OAAO,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AACrC,OAAO,EAAE,YAAY,EAAE,MAAM,
|
|
1
|
+
{"version":3,"file":"manifestParser.js","sourceRoot":"","sources":["../../src/parsers/manifestParser.ts"],"names":[],"mappings":"AAAA,YAAY,CAAC;AAEb,OAAO,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AACrC,OAAO,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAC5C,OAAO,EAAE,SAAS,EAAE,YAAY,EAAE,QAAQ,EAAE,MAAM,uBAAuB,CAAC;AAE1E,yEAAyE;AACzE,4EAA4E;AAC5E,0DAA0D;AAC1D,MAAM,oBAAoB,GAA2B;IACnD,SAAS,EAAE,WAAW;IACtB,WAAW,EAAE,aAAa;CAC3B,CAAC;AAEF,SAAS,iBAAiB,CAAC,QAAgB;IACzC,OAAO,oBAAoB,CAAC,QAAQ,CAAC,WAAW,EAAE,CAAC,IAAI,QAAQ,CAAC;AAClE,CAAC;AAED;;;;;;;;GAQG;AACH,MAAM,CAAC,KAAK,UAAU,gCAAgC,CAAC,YAAoB;IACzE,MAAM,MAAM,GAAa,EAAE,CAAC;IAE5B,IAAI,CAAC,YAAY,IAAI,CAAC,UAAU,CAAC,YAAY,CAAC,EAAE,CAAC;QAC/C,OAAO,MAAM,CAAC;IAChB,CAAC;IAED,MAAM,OAAO,GAAG,MAAM,QAAQ,CAAC,YAAY,EAAE,OAAO,CAAC,CAAC;IACtD,MAAM,IAAI,GAAG,QAAQ,CAAC,OAAO,CAAC,CAAC;IAE/B,KAAK,MAAM,YAAY,IAAI,YAAY,CAAC,IAAI,EAAE,OAAO,CAAC,EAAE,CAAC;QACvD,MAAM,WAAW,GAAG,SAAS,CAAC,YAAY,EAAE,MAAM,CAAC,CAAC;QACpD,IAAI,CAAC,WAAW;YAAE,SAAS;QAE3B,MAAM,QAAQ,GAAG,iBAAiB,CAAC,WAAW,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC,CAAC;QAC5D,KAAK,MAAM,aAAa,IAAI,YAAY,CAAC,YAAY,EAAE,SAAS,CAAC,EAAE,CAAC;YAClE,MAAM,CAAC,IAAI,CAAC,GAAG,QAAQ,IAAI,aAAa,CAAC,IAAI,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC;QAC1D,CAAC;IACH,CAAC;IAED,OAAO,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,aAAa,CAAC,CAAC,CAAC,CAAC,CAAC;AACnD,CAAC"}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { readFile } from 'node:fs/promises';
|
|
2
|
-
import {
|
|
2
|
+
import { parseYaml } from '../utils/yamlParser.js';
|
|
3
3
|
/**
|
|
4
4
|
* Verifies structure matches the test metadata map type.
|
|
5
5
|
*/
|
|
@@ -15,7 +15,7 @@ function isTestMetadataMap(obj) {
|
|
|
15
15
|
*/
|
|
16
16
|
export async function loadTestMetadataDependencies(configPath) {
|
|
17
17
|
const content = await readFile(configPath, 'utf-8');
|
|
18
|
-
const parsed =
|
|
18
|
+
const parsed = parseYaml(content);
|
|
19
19
|
if (isTestMetadataMap(parsed)) {
|
|
20
20
|
return parsed;
|
|
21
21
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"metadataFilterParser.js","sourceRoot":"","sources":["../../src/parsers/metadataFilterParser.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;
|
|
1
|
+
{"version":3,"file":"metadataFilterParser.js","sourceRoot":"","sources":["../../src/parsers/metadataFilterParser.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAG5C,OAAO,EAAE,SAAS,EAAE,MAAM,wBAAwB,CAAC;AAEnD;;GAEG;AACH,SAAS,iBAAiB,CAAC,GAAY;IACrC,IAAI,OAAO,GAAG,KAAK,QAAQ,IAAI,GAAG,KAAK,IAAI;QAAE,OAAO,KAAK,CAAC;IAE1D,OAAO,MAAM,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,KAAK;IAC9B,8IAA8I;IAC9I,CAAC,CAAC,GAAG,EAAE,KAAK,CAAC,EAAE,EAAE,CAAC,OAAO,GAAG,KAAK,QAAQ,IAAI,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,IAAI,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,OAAO,CAAC,KAAK,QAAQ,CAAC,CAC/G,CAAC;AACJ,CAAC;AAED;;GAEG;AACH,MAAM,CAAC,KAAK,UAAU,4BAA4B,CAAC,UAAkB;IACnE,MAAM,OAAO,GAAG,MAAM,QAAQ,CAAC,UAAU,EAAE,OAAO,CAAC,CAAC;IACpD,MAAM,MAAM,GAAY,SAAS,CAAC,OAAO,CAAC,CAAC;IAE3C,IAAI,iBAAiB,CAAC,MAAM,CAAC,EAAE,CAAC;QAC9B,OAAO,MAAM,CAAC;IAChB,CAAC;IAED,MAAM,IAAI,KAAK,CAAC,mDAAmD,CAAC,CAAC;AACvE,CAAC;AAED;;;GAGG;AACH,SAAS,iBAAiB,CAAC,UAAkB,EAAE,OAAe;IAC5D,IAAI,UAAU,CAAC,QAAQ,CAAC,GAAG,CAAC,EAAE,CAAC;QAC7B,MAAM,OAAO,GAAG,UAAU,CAAC,OAAO,CAAC,GAAG,EAAE,KAAK,CAAC,CAAC,OAAO,CAAC,GAAG,EAAE,IAAI,CAAC,CAAC;QAClE,OAAO,IAAI,MAAM,CAAC,IAAI,OAAO,GAAG,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;IAClD,CAAC;IACD,OAAO,UAAU,KAAK,OAAO,CAAC;AAChC,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,mBAAmB,CAAC,OAAwB,EAAE,eAAyB;IACrF,MAAM,QAAQ,GAAa,EAAE,CAAC;IAE9B,KAAK,MAAM,CAAC,SAAS,EAAE,YAAY,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,OAAO,CAAC,EAAE,CAAC;QAChE,MAAM,OAAO,GAAG,eAAe,CAAC,IAAI,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,YAAY,CAAC,IAAI,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,iBAAiB,CAAC,GAAG,EAAE,OAAO,CAAC,CAAC,CAAC,CAAC;QAC/G,IAAI,OAAO,EAAE,CAAC;YACZ,QAAQ,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;QAC3B,CAAC;IACH,CAAC;IAED,OAAO,QAAQ,CAAC;AAClB,CAAC"}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
'use strict';
|
|
2
|
-
import {
|
|
2
|
+
import { findChildren, parseXml } from '../utils/xmlParser.js';
|
|
3
3
|
/**
|
|
4
4
|
* Analyzes the content of a test suite xml file and returns the Apex classes
|
|
5
5
|
* included in it.
|
|
@@ -8,16 +8,13 @@ import { Parser } from 'xml2js';
|
|
|
8
8
|
* @returns a list of test classes names in the test suite
|
|
9
9
|
*/
|
|
10
10
|
export function parseTestSuiteFile(data) {
|
|
11
|
-
const
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
});
|
|
19
|
-
});
|
|
20
|
-
return result.sort();
|
|
11
|
+
const root = parseXml(data);
|
|
12
|
+
if (root.name !== 'ApexTestSuite') {
|
|
13
|
+
throw new Error(`Invalid XML: expected root element "ApexTestSuite", got "${root.name}"`);
|
|
14
|
+
}
|
|
15
|
+
return findChildren(root, 'testClassName')
|
|
16
|
+
.map((element) => element.text.trim())
|
|
17
|
+
.sort();
|
|
21
18
|
}
|
|
22
19
|
/**
|
|
23
20
|
* Parses the line in an Apex file that contains the test suites names.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"testSuiteParser.js","sourceRoot":"","sources":["../../src/parsers/testSuiteParser.ts"],"names":[],"mappings":"AAAA,YAAY,CAAC;AAEb,OAAO,EAAE,
|
|
1
|
+
{"version":3,"file":"testSuiteParser.js","sourceRoot":"","sources":["../../src/parsers/testSuiteParser.ts"],"names":[],"mappings":"AAAA,YAAY,CAAC;AAEb,OAAO,EAAE,YAAY,EAAE,QAAQ,EAAE,MAAM,uBAAuB,CAAC;AAE/D;;;;;;GAMG;AACH,MAAM,UAAU,kBAAkB,CAAC,IAAY;IAC7C,MAAM,IAAI,GAAG,QAAQ,CAAC,IAAI,CAAC,CAAC;IAE5B,IAAI,IAAI,CAAC,IAAI,KAAK,eAAe,EAAE,CAAC;QAClC,MAAM,IAAI,KAAK,CAAC,4DAA4D,IAAI,CAAC,IAAI,GAAG,CAAC,CAAC;IAC5F,CAAC;IAED,OAAO,YAAY,CAAC,IAAI,EAAE,eAAe,CAAC;SACvC,GAAG,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,OAAO,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC;SACrC,IAAI,EAAE,CAAC;AACZ,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,oBAAoB,CAAC,eAAgC;IACnE,IAAI,CAAC,eAAe,IAAI,eAAe,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACrD,OAAO,EAAE,CAAC;IACZ,CAAC;IAED,gCAAgC;IAChC,OAAO,eAAe;SACnB,IAAI,CAAC,GAAG,CAAC;SACT,OAAO,CAAC,wBAAwB,EAAE,EAAE,CAAC;SACrC,OAAO,CAAC,SAAS,EAAE,GAAG,CAAC;SACvB,IAAI,EAAE;SACN,KAAK,CAAC,GAAG,CAAC,CAAC;AAChB,CAAC"}
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
import { readdirSync, readFileSync } from 'node:fs';
|
|
3
3
|
import { basename } from 'node:path';
|
|
4
|
-
import { queue } from 'async';
|
|
5
4
|
import { parseTestsNames } from '../parsers/testNameParser.js';
|
|
6
5
|
import { parseTestSuitesNames } from '../parsers/testSuiteParser.js';
|
|
7
6
|
import { getConcurrencyThreshold } from '../utils/concurrencyThreshold.js';
|
|
7
|
+
import { createQueue } from '../utils/concurrentQueue.js';
|
|
8
8
|
import { TEST_CLASS_ANNOTATION_REGEX, TEST_NAME_REGEX, TEST_SUITE_NAME_REGEX } from '../utils/constants.js';
|
|
9
9
|
/**
|
|
10
10
|
* Given a certain directory, search its contents for files that end with '.cls' or '.trigger'.
|
|
@@ -56,6 +56,9 @@ export async function searchDirectoryForTestClasses(directory, names) {
|
|
|
56
56
|
parseTestSuitesNames(match).forEach((testMethod) => testSuitesNames.add(testMethod));
|
|
57
57
|
}
|
|
58
58
|
}
|
|
59
|
+
// Stryker disable next-line ConditionalExpression,EqualityOperator: String.match()
|
|
60
|
+
// with a global regex returns either null or a non-empty array — the length
|
|
61
|
+
// check is equivalent to a plain truthy check here.
|
|
59
62
|
if (testClassAnnotationMatches && testClassAnnotationMatches.length > 0) {
|
|
60
63
|
hasAnnotation = true;
|
|
61
64
|
testClassesNames.add(basename(fileName).split('.').shift());
|
|
@@ -64,7 +67,7 @@ export async function searchDirectoryForTestClasses(directory, names) {
|
|
|
64
67
|
warnings.push(`File "${fileName}" does not contain @tests, @testsuites, or @istest annotations`);
|
|
65
68
|
}
|
|
66
69
|
};
|
|
67
|
-
const testClassNameProcessor =
|
|
70
|
+
const testClassNameProcessor = createQueue((f, cb) => {
|
|
68
71
|
testClassNameHandler(f);
|
|
69
72
|
cb();
|
|
70
73
|
}, getConcurrencyThreshold());
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"directorySearcher.js","sourceRoot":"","sources":["../../src/readers/directorySearcher.ts"],"names":[],"mappings":"AAAA,YAAY,CAAC;AAEb,OAAO,EAAE,WAAW,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AACpD,OAAO,EAAE,QAAQ,EAAE,MAAM,WAAW,CAAC;AACrC,OAAO,EAAE,
|
|
1
|
+
{"version":3,"file":"directorySearcher.js","sourceRoot":"","sources":["../../src/readers/directorySearcher.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
import { readdirSync, readFileSync } from 'node:fs';
|
|
3
|
-
import { queue } from 'async';
|
|
4
3
|
import { parseTestSuiteFile } from '../parsers/testSuiteParser.js';
|
|
5
4
|
import { getConcurrencyThreshold } from '../utils/concurrencyThreshold.js';
|
|
5
|
+
import { createQueue } from '../utils/concurrentQueue.js';
|
|
6
6
|
import { matchWildcard } from '../utils/matchWildcard.js';
|
|
7
7
|
import { searchDirectoryForTestClasses } from './directorySearcher.js';
|
|
8
8
|
/**
|
|
@@ -44,7 +44,7 @@ export async function searchDirectoryForTestNamesInTestSuites(directory, package
|
|
|
44
44
|
}
|
|
45
45
|
};
|
|
46
46
|
// define the processors
|
|
47
|
-
const testSuiteNameProcessor =
|
|
47
|
+
const testSuiteNameProcessor = createQueue((f, cb) => {
|
|
48
48
|
testSuiteNameHandler(f);
|
|
49
49
|
cb();
|
|
50
50
|
}, getConcurrencyThreshold());
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"testSuiteSearcher.js","sourceRoot":"","sources":["../../src/readers/testSuiteSearcher.ts"],"names":[],"mappings":"AAAA,YAAY,CAAC;AAEb,OAAO,EAAE,WAAW,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AACpD,OAAO,EAAE,
|
|
1
|
+
{"version":3,"file":"testSuiteSearcher.js","sourceRoot":"","sources":["../../src/readers/testSuiteSearcher.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Minimal in-house replacement for async's `queue`: runs a worker over a
|
|
3
|
+
* list of tasks with a concurrency cap, resolving once all tasks finish
|
|
4
|
+
* (or rejecting on the first error).
|
|
5
|
+
*/
|
|
6
|
+
type Worker<T> = (task: T, callback: (error?: Error) => void) => void;
|
|
7
|
+
export interface ConcurrentQueue<T> {
|
|
8
|
+
push(tasks: T | T[]): Promise<void>;
|
|
9
|
+
}
|
|
10
|
+
export declare function createQueue<T>(worker: Worker<T>, concurrency: number): ConcurrentQueue<T>;
|
|
11
|
+
export {};
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
export function createQueue(worker, concurrency) {
|
|
3
|
+
return {
|
|
4
|
+
push(tasks) {
|
|
5
|
+
const items = Array.isArray(tasks) ? tasks : [tasks];
|
|
6
|
+
return new Promise((resolvePromise, reject) => {
|
|
7
|
+
if (items.length === 0) {
|
|
8
|
+
resolvePromise();
|
|
9
|
+
return;
|
|
10
|
+
}
|
|
11
|
+
let index = 0;
|
|
12
|
+
let active = 0;
|
|
13
|
+
let settled = false;
|
|
14
|
+
const runNext = () => {
|
|
15
|
+
while (!settled && active < concurrency && index < items.length) {
|
|
16
|
+
const item = items[index++];
|
|
17
|
+
active++;
|
|
18
|
+
worker(item, (error) => {
|
|
19
|
+
// Stryker disable next-line ConditionalExpression: redundant with
|
|
20
|
+
// runNext()'s own `!settled` check below — even without this early
|
|
21
|
+
// return, a late callback can only ever reach a no-op runNext()
|
|
22
|
+
// call once settled is true, since that check blocks it too.
|
|
23
|
+
if (settled)
|
|
24
|
+
return;
|
|
25
|
+
if (error) {
|
|
26
|
+
settled = true;
|
|
27
|
+
reject(error);
|
|
28
|
+
return;
|
|
29
|
+
}
|
|
30
|
+
active--;
|
|
31
|
+
if (index >= items.length && active === 0) {
|
|
32
|
+
// Stryker disable next-line BooleanLiteral: this branch only
|
|
33
|
+
// fires once every item is dispatched (index >= items.length),
|
|
34
|
+
// which independently blocks runNext()'s while loop from ever
|
|
35
|
+
// dispatching again, regardless of this assignment's value.
|
|
36
|
+
settled = true;
|
|
37
|
+
resolvePromise();
|
|
38
|
+
return;
|
|
39
|
+
}
|
|
40
|
+
runNext();
|
|
41
|
+
});
|
|
42
|
+
}
|
|
43
|
+
};
|
|
44
|
+
runNext();
|
|
45
|
+
});
|
|
46
|
+
},
|
|
47
|
+
};
|
|
48
|
+
}
|
|
49
|
+
//# sourceMappingURL=concurrentQueue.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"concurrentQueue.js","sourceRoot":"","sources":["../../src/utils/concurrentQueue.ts"],"names":[],"mappings":"AAAA,YAAY,CAAC;AAcb,MAAM,UAAU,WAAW,CAAI,MAAiB,EAAE,WAAmB;IACnE,OAAO;QACL,IAAI,CAAC,KAAc;YACjB,MAAM,KAAK,GAAG,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC;YAErD,OAAO,IAAI,OAAO,CAAO,CAAC,cAAc,EAAE,MAAM,EAAE,EAAE;gBAClD,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;oBACvB,cAAc,EAAE,CAAC;oBACjB,OAAO;gBACT,CAAC;gBAED,IAAI,KAAK,GAAG,CAAC,CAAC;gBACd,IAAI,MAAM,GAAG,CAAC,CAAC;gBACf,IAAI,OAAO,GAAG,KAAK,CAAC;gBAEpB,MAAM,OAAO,GAAG,GAAS,EAAE;oBACzB,OAAO,CAAC,OAAO,IAAI,MAAM,GAAG,WAAW,IAAI,KAAK,GAAG,KAAK,CAAC,MAAM,EAAE,CAAC;wBAChE,MAAM,IAAI,GAAG,KAAK,CAAC,KAAK,EAAE,CAAC,CAAC;wBAC5B,MAAM,EAAE,CAAC;wBACT,MAAM,CAAC,IAAI,EAAE,CAAC,KAAK,EAAE,EAAE;4BACrB,kEAAkE;4BAClE,mEAAmE;4BACnE,gEAAgE;4BAChE,6DAA6D;4BAC7D,IAAI,OAAO;gCAAE,OAAO;4BACpB,IAAI,KAAK,EAAE,CAAC;gCACV,OAAO,GAAG,IAAI,CAAC;gCACf,MAAM,CAAC,KAAK,CAAC,CAAC;gCACd,OAAO;4BACT,CAAC;4BACD,MAAM,EAAE,CAAC;4BACT,IAAI,KAAK,IAAI,KAAK,CAAC,MAAM,IAAI,MAAM,KAAK,CAAC,EAAE,CAAC;gCAC1C,6DAA6D;gCAC7D,+DAA+D;gCAC/D,8DAA8D;gCAC9D,4DAA4D;gCAC5D,OAAO,GAAG,IAAI,CAAC;gCACf,cAAc,EAAE,CAAC;gCACjB,OAAO;4BACT,CAAC;4BACD,OAAO,EAAE,CAAC;wBACZ,CAAC,CAAC,CAAC;oBACL,CAAC;gBACH,CAAC,CAAC;gBAEF,OAAO,EAAE,CAAC;YACZ,CAAC,CAAC,CAAC;QACL,CAAC;KACF,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Minimal in-house XML parser. Handles the narrow subset of well-formed XML
|
|
3
|
+
* used by Salesforce metadata files consumed by this plugin (package
|
|
4
|
+
* manifests and test suite files): nested elements, comments, processing
|
|
5
|
+
* instructions, self-closing tags, and basic entity-decoded text content.
|
|
6
|
+
*/
|
|
7
|
+
export interface XmlElement {
|
|
8
|
+
name: string;
|
|
9
|
+
children: XmlElement[];
|
|
10
|
+
text: string;
|
|
11
|
+
}
|
|
12
|
+
export declare function parseXml(xml: string): XmlElement;
|
|
13
|
+
export declare function findChildren(element: XmlElement, name: string): XmlElement[];
|
|
14
|
+
export declare function findChild(element: XmlElement, name: string): XmlElement | undefined;
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
// The tag alternative has no separate "whitespace before attributes" check:
|
|
3
|
+
// [^<>]* already includes whitespace, so an optional leading \s would only
|
|
4
|
+
// ever be satisfied via a redundant backtrack into the tag-name class.
|
|
5
|
+
const TOKEN_REGEX = /<!--[\s\S]*?-->|<\?[\s\S]*?\?>|<\/?[a-zA-Z_][\w.:-]*[^<>]*\/?>/g;
|
|
6
|
+
// Stryker disable next-line Regex: TAG_NAME_REGEX only ever runs on a `token`
|
|
7
|
+
// that is itself a full TOKEN_REGEX match, which always starts with '<' and
|
|
8
|
+
// (once comments/PIs are excluded above) can never contain another '<', so
|
|
9
|
+
// the leading '^' anchor can never change which substring matches.
|
|
10
|
+
const TAG_NAME_REGEX = /^<\/?([a-zA-Z_][\w.:-]*)/;
|
|
11
|
+
function decodeEntities(text) {
|
|
12
|
+
return text
|
|
13
|
+
.replace(/</g, '<')
|
|
14
|
+
.replace(/>/g, '>')
|
|
15
|
+
.replace(/"/g, '"')
|
|
16
|
+
.replace(/'/g, "'")
|
|
17
|
+
.replace(/&/g, '&');
|
|
18
|
+
}
|
|
19
|
+
export function parseXml(xml) {
|
|
20
|
+
const stack = [];
|
|
21
|
+
let root;
|
|
22
|
+
let lastIndex = 0;
|
|
23
|
+
let match;
|
|
24
|
+
const pushText = (raw) => {
|
|
25
|
+
if (!raw.trim() || stack.length === 0)
|
|
26
|
+
return;
|
|
27
|
+
stack[stack.length - 1].text += decodeEntities(raw);
|
|
28
|
+
};
|
|
29
|
+
TOKEN_REGEX.lastIndex = 0;
|
|
30
|
+
while ((match = TOKEN_REGEX.exec(xml)) !== null) {
|
|
31
|
+
pushText(xml.slice(lastIndex, match.index));
|
|
32
|
+
lastIndex = TOKEN_REGEX.lastIndex;
|
|
33
|
+
const token = match[0];
|
|
34
|
+
if (token.startsWith('<!--') || token.startsWith('<?')) {
|
|
35
|
+
continue;
|
|
36
|
+
}
|
|
37
|
+
// TOKEN_REGEX already constrains every non-comment/PI token to this exact
|
|
38
|
+
// tag-name pattern, so the exec() below is guaranteed to match.
|
|
39
|
+
const name = TAG_NAME_REGEX.exec(token)[1];
|
|
40
|
+
if (token.startsWith('</')) {
|
|
41
|
+
const current = stack.pop();
|
|
42
|
+
if (!current || current.name !== name) {
|
|
43
|
+
throw new Error(`Invalid XML: mismatched closing tag "${token}"`);
|
|
44
|
+
}
|
|
45
|
+
// Stryker disable next-line ConditionalExpression: in well-formed,
|
|
46
|
+
// single-root XML the true root's own closing/self-closing token is
|
|
47
|
+
// always the last one processed, so it always overwrites any earlier,
|
|
48
|
+
// premature assignment here regardless of this guard.
|
|
49
|
+
if (stack.length === 0) {
|
|
50
|
+
root = current;
|
|
51
|
+
}
|
|
52
|
+
continue;
|
|
53
|
+
}
|
|
54
|
+
const element = { name, children: [], text: '' };
|
|
55
|
+
if (stack.length > 0) {
|
|
56
|
+
stack[stack.length - 1].children.push(element);
|
|
57
|
+
}
|
|
58
|
+
if (token.endsWith('/>')) {
|
|
59
|
+
// Stryker disable next-line ConditionalExpression: same reasoning as the
|
|
60
|
+
// closing-tag branch above — the last root-setting assignment always wins.
|
|
61
|
+
if (stack.length === 0)
|
|
62
|
+
root = element;
|
|
63
|
+
}
|
|
64
|
+
else {
|
|
65
|
+
stack.push(element);
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
if (stack.length > 0) {
|
|
69
|
+
throw new Error(`Invalid XML: unclosed tag "<${stack[stack.length - 1].name}>"`);
|
|
70
|
+
}
|
|
71
|
+
if (!root) {
|
|
72
|
+
throw new Error('Invalid XML: no root element found');
|
|
73
|
+
}
|
|
74
|
+
return root;
|
|
75
|
+
}
|
|
76
|
+
export function findChildren(element, name) {
|
|
77
|
+
return element.children.filter((child) => child.name === name);
|
|
78
|
+
}
|
|
79
|
+
export function findChild(element, name) {
|
|
80
|
+
return element.children.find((child) => child.name === name);
|
|
81
|
+
}
|
|
82
|
+
//# sourceMappingURL=xmlParser.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"xmlParser.js","sourceRoot":"","sources":["../../src/utils/xmlParser.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function parseYaml(content: string): unknown;
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
/**
|
|
3
|
+
* Minimal in-house YAML parser covering the narrow subset used by this
|
|
4
|
+
* plugin's test-metadata-dependencies file: a flat mapping of scalar keys
|
|
5
|
+
* to either a scalar value or a block sequence of scalars. Not a general
|
|
6
|
+
* YAML implementation.
|
|
7
|
+
*/
|
|
8
|
+
function parseScalar(raw) {
|
|
9
|
+
const text = raw.trim();
|
|
10
|
+
if (text === '' || text === '~' || /^null$/i.test(text))
|
|
11
|
+
return null;
|
|
12
|
+
if (/^true$/i.test(text))
|
|
13
|
+
return true;
|
|
14
|
+
if (/^false$/i.test(text))
|
|
15
|
+
return false;
|
|
16
|
+
if (/^-?\d+(\.\d+)?$/.test(text))
|
|
17
|
+
return Number(text);
|
|
18
|
+
if (text.length >= 2 &&
|
|
19
|
+
((text.startsWith('"') && text.endsWith('"')) || (text.startsWith("'") && text.endsWith("'")))) {
|
|
20
|
+
return text.slice(1, -1);
|
|
21
|
+
}
|
|
22
|
+
return text;
|
|
23
|
+
}
|
|
24
|
+
// No trailing $: rawLine is always a single line (already split on '\n'), and
|
|
25
|
+
// `.` never matches '\n', so `(.*)` already extends to the end of the string.
|
|
26
|
+
const TOP_LEVEL_KEY_REGEX = /^(\S[^:]*):\s*(.*)/;
|
|
27
|
+
const LIST_ITEM_REGEX = /^[ \t]+-\s?(.*)/;
|
|
28
|
+
export function parseYaml(content) {
|
|
29
|
+
const lines = content.replace(/\r\n/g, '\n').split('\n');
|
|
30
|
+
const result = {};
|
|
31
|
+
let currentKey = null;
|
|
32
|
+
let currentList = null;
|
|
33
|
+
let sawKey = false;
|
|
34
|
+
const commitPending = () => {
|
|
35
|
+
if (currentKey !== null) {
|
|
36
|
+
result[currentKey] = currentList ?? null;
|
|
37
|
+
}
|
|
38
|
+
currentKey = null;
|
|
39
|
+
currentList = null;
|
|
40
|
+
};
|
|
41
|
+
// A blank (or whitespace-only) line matches neither LIST_ITEM_REGEX (no
|
|
42
|
+
// dash) nor TOP_LEVEL_KEY_REGEX (no non-whitespace first character), so it
|
|
43
|
+
// is already skipped by the "not a key, not a list item" fallthrough below
|
|
44
|
+
// — no separate blank-line check needed.
|
|
45
|
+
for (const rawLine of lines) {
|
|
46
|
+
const listMatch = LIST_ITEM_REGEX.exec(rawLine);
|
|
47
|
+
// Stryker disable next-line ConditionalExpression: commitPending() always
|
|
48
|
+
// resets currentList before a new key can pick it up, so a list item seen
|
|
49
|
+
// while currentKey is null can never leak into the result either way.
|
|
50
|
+
if (listMatch && currentKey !== null) {
|
|
51
|
+
currentList = currentList ?? [];
|
|
52
|
+
currentList.push(parseScalar(listMatch[1]));
|
|
53
|
+
continue;
|
|
54
|
+
}
|
|
55
|
+
// A line indented with space/tab can never match TOP_LEVEL_KEY_REGEX below
|
|
56
|
+
// (it requires a non-whitespace first character), so it already falls
|
|
57
|
+
// through to the "not a key" branch on its own — no separate guard needed.
|
|
58
|
+
const keyMatch = TOP_LEVEL_KEY_REGEX.exec(rawLine);
|
|
59
|
+
if (!keyMatch) {
|
|
60
|
+
continue;
|
|
61
|
+
}
|
|
62
|
+
commitPending();
|
|
63
|
+
sawKey = true;
|
|
64
|
+
const key = keyMatch[1].trim();
|
|
65
|
+
const inline = keyMatch[2];
|
|
66
|
+
// TOP_LEVEL_KEY_REGEX's `\s*` already consumes any whitespace right after
|
|
67
|
+
// the colon, so `inline` can never be non-empty and whitespace-only.
|
|
68
|
+
if (inline) {
|
|
69
|
+
result[key] = parseScalar(inline);
|
|
70
|
+
}
|
|
71
|
+
else {
|
|
72
|
+
currentKey = key;
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
commitPending();
|
|
76
|
+
// parseScalar() trims internally, so pre-trimming content here is redundant.
|
|
77
|
+
return sawKey ? result : parseScalar(content);
|
|
78
|
+
}
|
|
79
|
+
//# sourceMappingURL=yamlParser.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"yamlParser.js","sourceRoot":"","sources":["../../src/utils/yamlParser.ts"],"names":[],"mappings":"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"}
|
package/oclif.manifest.json
CHANGED
package/package.json
CHANGED
|
@@ -1,35 +1,31 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "apextestlist",
|
|
3
3
|
"description": "A plugin that generates a list of apex test and test suite names for use in CI/CD pipelines.",
|
|
4
|
-
"version": "1.
|
|
4
|
+
"version": "1.14.0",
|
|
5
5
|
"dependencies": {
|
|
6
|
-
"@oclif/core": "4.13.
|
|
6
|
+
"@oclif/core": "4.13.5",
|
|
7
7
|
"@salesforce/core": "8.32.6",
|
|
8
|
-
"@salesforce/sf-plugins-core": "12.2.28"
|
|
9
|
-
"@salesforce/source-deploy-retrieve": "12.37.2",
|
|
10
|
-
"async": "3.2.6",
|
|
11
|
-
"xml2js": "0.6.2",
|
|
12
|
-
"yaml": "2.9.0"
|
|
8
|
+
"@salesforce/sf-plugins-core": "12.2.28"
|
|
13
9
|
},
|
|
14
10
|
"devDependencies": {
|
|
15
|
-
"@
|
|
11
|
+
"@actions/core": "3.0.1",
|
|
12
|
+
"@biomejs/biome": "2.5.9",
|
|
16
13
|
"@commitlint/cli": "19.8.1",
|
|
17
14
|
"@commitlint/config-conventional": "19.8.1",
|
|
18
|
-
"@salesforce/cli-plugins-testkit": "5.3.
|
|
15
|
+
"@salesforce/cli-plugins-testkit": "5.3.66",
|
|
19
16
|
"@salesforce/dev-config": "4.3.3",
|
|
20
17
|
"@stryker-mutator/core": "9.6.1",
|
|
21
18
|
"@stryker-mutator/vitest-runner": "9.6.1",
|
|
22
|
-
"@types/async": "3.2.25",
|
|
23
19
|
"@types/node": "22.20.1",
|
|
24
|
-
"@
|
|
25
|
-
"
|
|
20
|
+
"@vitest/coverage-v8": "4.1.11",
|
|
21
|
+
"esbuild": "0.28.2",
|
|
26
22
|
"husky": "9.1.7",
|
|
27
23
|
"lint-staged": "17.3.0",
|
|
28
|
-
"oclif": "4.23.
|
|
24
|
+
"oclif": "4.23.30",
|
|
29
25
|
"shx": "0.4.0",
|
|
30
26
|
"ts-node": "10.9.2",
|
|
31
27
|
"typescript": "5.9.3",
|
|
32
|
-
"vitest": "4.1.
|
|
28
|
+
"vitest": "4.1.11",
|
|
33
29
|
"wireit": "0.14.13"
|
|
34
30
|
},
|
|
35
31
|
"engines": {
|
|
@@ -37,6 +33,7 @@
|
|
|
37
33
|
},
|
|
38
34
|
"files": [
|
|
39
35
|
"/lib",
|
|
36
|
+
"!/lib/action",
|
|
40
37
|
"/messages",
|
|
41
38
|
"/oclif.manifest.json",
|
|
42
39
|
"/oclif.lock",
|
|
@@ -68,6 +65,7 @@
|
|
|
68
65
|
},
|
|
69
66
|
"scripts": {
|
|
70
67
|
"build": "wireit",
|
|
68
|
+
"build:action": "wireit",
|
|
71
69
|
"clean": "wireit",
|
|
72
70
|
"clean:build": "wireit",
|
|
73
71
|
"clean:package-manager": "wireit",
|
|
@@ -79,8 +77,8 @@
|
|
|
79
77
|
"prepack": "wireit",
|
|
80
78
|
"prepare": "husky",
|
|
81
79
|
"test": "wireit",
|
|
82
|
-
"test:mutation": "
|
|
83
|
-
"test:mutation:incremental": "
|
|
80
|
+
"test:mutation": "wireit",
|
|
81
|
+
"test:mutation:incremental": "wireit",
|
|
84
82
|
"test:nuts": "wireit",
|
|
85
83
|
"test:only": "wireit"
|
|
86
84
|
},
|
|
@@ -91,9 +89,25 @@
|
|
|
91
89
|
"build": {
|
|
92
90
|
"dependencies": [
|
|
93
91
|
"compile",
|
|
94
|
-
"lint"
|
|
92
|
+
"lint",
|
|
93
|
+
"build:action"
|
|
95
94
|
]
|
|
96
95
|
},
|
|
96
|
+
"build:action": {
|
|
97
|
+
"command": "esbuild src/action/index.ts --bundle --minify --platform=node --format=cjs --target=node22 --outfile=dist/action/index.cjs",
|
|
98
|
+
"files": [
|
|
99
|
+
"src/action/**/*.ts",
|
|
100
|
+
"src/core/**/*.ts",
|
|
101
|
+
"src/parsers/**/*.ts",
|
|
102
|
+
"src/readers/**/*.ts",
|
|
103
|
+
"src/utils/**/*.ts",
|
|
104
|
+
"tsconfig.json"
|
|
105
|
+
],
|
|
106
|
+
"output": [
|
|
107
|
+
"dist/action/**"
|
|
108
|
+
],
|
|
109
|
+
"clean": false
|
|
110
|
+
},
|
|
97
111
|
"clean": {
|
|
98
112
|
"command": "shx rm -rf 'reports/*' oclif.manifest.json oclif.lock 'stderr*.txt' 'stdout*.txt' '.stryker-tmp/*'",
|
|
99
113
|
"files": [
|
|
@@ -185,6 +199,39 @@
|
|
|
185
199
|
"lint"
|
|
186
200
|
]
|
|
187
201
|
},
|
|
202
|
+
"test:mutation": {
|
|
203
|
+
"command": "stryker run",
|
|
204
|
+
"files": [
|
|
205
|
+
"src/**/*.ts",
|
|
206
|
+
"test/**/*.ts",
|
|
207
|
+
"**/tsconfig.json",
|
|
208
|
+
"stryker.config.json",
|
|
209
|
+
"vitest.config.ts"
|
|
210
|
+
],
|
|
211
|
+
"output": [
|
|
212
|
+
"reports/mutation/**"
|
|
213
|
+
],
|
|
214
|
+
"dependencies": [
|
|
215
|
+
"lint"
|
|
216
|
+
]
|
|
217
|
+
},
|
|
218
|
+
"test:mutation:incremental": {
|
|
219
|
+
"command": "node scripts/incremental-mutation.mjs",
|
|
220
|
+
"files": [
|
|
221
|
+
"src/**/*.ts",
|
|
222
|
+
"test/**/*.ts",
|
|
223
|
+
"**/tsconfig.json",
|
|
224
|
+
"stryker.config.json",
|
|
225
|
+
"vitest.config.ts",
|
|
226
|
+
"scripts/incremental-mutation.mjs"
|
|
227
|
+
],
|
|
228
|
+
"output": [
|
|
229
|
+
"reports/mutation/**"
|
|
230
|
+
],
|
|
231
|
+
"dependencies": [
|
|
232
|
+
"lint"
|
|
233
|
+
]
|
|
234
|
+
},
|
|
188
235
|
"test:nuts": {
|
|
189
236
|
"command": "vitest run --config ./vitest.nut.config.ts && shx rm -f oclif.manifest.json oclif.lock *.tsbuildinfo",
|
|
190
237
|
"files": [
|
|
@@ -223,4 +270,4 @@
|
|
|
223
270
|
"exports": "./lib/index.js",
|
|
224
271
|
"type": "module",
|
|
225
272
|
"author": "Renato Oliveira"
|
|
226
|
-
}
|
|
273
|
+
}
|