@sun-asterisk/sungen 3.2.16-beta.1 → 3.2.16-beta.10
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/dist/cli/commands/delivery.d.ts.map +1 -1
- package/dist/cli/commands/delivery.js +67 -20
- package/dist/cli/commands/delivery.js.map +1 -1
- package/dist/exporters/feature-parser.d.ts +16 -1
- package/dist/exporters/feature-parser.d.ts.map +1 -1
- package/dist/exporters/feature-parser.js +21 -2
- package/dist/exporters/feature-parser.js.map +1 -1
- package/dist/exporters/matrix/build.d.ts +27 -2
- package/dist/exporters/matrix/build.d.ts.map +1 -1
- package/dist/exporters/matrix/build.js +277 -47
- package/dist/exporters/matrix/build.js.map +1 -1
- package/dist/exporters/matrix/export.d.ts +7 -4
- package/dist/exporters/matrix/export.d.ts.map +1 -1
- package/dist/exporters/matrix/export.js +22 -6
- package/dist/exporters/matrix/export.js.map +1 -1
- package/dist/exporters/matrix/gates.d.ts.map +1 -1
- package/dist/exporters/matrix/gates.js +112 -3
- package/dist/exporters/matrix/gates.js.map +1 -1
- package/dist/exporters/matrix/map-loader.d.ts.map +1 -1
- package/dist/exporters/matrix/map-loader.js +20 -0
- package/dist/exporters/matrix/map-loader.js.map +1 -1
- package/dist/exporters/matrix/render-csv.d.ts +3 -2
- package/dist/exporters/matrix/render-csv.d.ts.map +1 -1
- package/dist/exporters/matrix/render-csv.js +53 -30
- package/dist/exporters/matrix/render-csv.js.map +1 -1
- package/dist/exporters/matrix/render-xlsx.d.ts +32 -8
- package/dist/exporters/matrix/render-xlsx.d.ts.map +1 -1
- package/dist/exporters/matrix/render-xlsx.js +215 -83
- package/dist/exporters/matrix/render-xlsx.js.map +1 -1
- package/dist/exporters/matrix/types.d.ts +53 -7
- package/dist/exporters/matrix/types.d.ts.map +1 -1
- package/dist/exporters/matrix/types.js +2 -2
- package/dist/exporters/matrix/types.js.map +1 -1
- package/dist/exporters/matrix/wording.d.ts +61 -0
- package/dist/exporters/matrix/wording.d.ts.map +1 -0
- package/dist/exporters/matrix/wording.js +221 -0
- package/dist/exporters/matrix/wording.js.map +1 -0
- package/dist/exporters/scenario-merger.d.ts.map +1 -1
- package/dist/exporters/scenario-merger.js +2 -1
- package/dist/exporters/scenario-merger.js.map +1 -1
- package/dist/exporters/spec-parser.d.ts.map +1 -1
- package/dist/exporters/spec-parser.js +2 -1
- package/dist/exporters/spec-parser.js.map +1 -1
- package/dist/harness/audit.d.ts.map +1 -1
- package/dist/harness/audit.js +11 -2
- package/dist/harness/audit.js.map +1 -1
- package/dist/harness/blindspot.d.ts.map +1 -1
- package/dist/harness/blindspot.js +2 -1
- package/dist/harness/blindspot.js.map +1 -1
- package/dist/harness/capability-plan.d.ts.map +1 -1
- package/dist/harness/capability-plan.js +3 -2
- package/dist/harness/capability-plan.js.map +1 -1
- package/dist/harness/feedback.d.ts.map +1 -1
- package/dist/harness/feedback.js +3 -2
- package/dist/harness/feedback.js.map +1 -1
- package/dist/harness/flow-check.d.ts.map +1 -1
- package/dist/harness/flow-check.js +2 -1
- package/dist/harness/flow-check.js.map +1 -1
- package/dist/harness/flow-plan.d.ts.map +1 -1
- package/dist/harness/flow-plan.js +3 -2
- package/dist/harness/flow-plan.js.map +1 -1
- package/dist/harness/intent.d.ts.map +1 -1
- package/dist/harness/intent.js +2 -1
- package/dist/harness/intent.js.map +1 -1
- package/dist/harness/journey.d.ts.map +1 -1
- package/dist/harness/journey.js +3 -2
- package/dist/harness/journey.js.map +1 -1
- package/dist/harness/ledger.d.ts.map +1 -1
- package/dist/harness/ledger.js +3 -2
- package/dist/harness/ledger.js.map +1 -1
- package/dist/harness/manifest.d.ts.map +1 -1
- package/dist/harness/manifest.js +4 -3
- package/dist/harness/manifest.js.map +1 -1
- package/dist/harness/parse.d.ts.map +1 -1
- package/dist/harness/parse.js +16 -3
- package/dist/harness/parse.js.map +1 -1
- package/dist/harness/quality-gates.d.ts.map +1 -1
- package/dist/harness/quality-gates.js +2 -1
- package/dist/harness/quality-gates.js.map +1 -1
- package/dist/harness/read-text.d.ts +22 -0
- package/dist/harness/read-text.d.ts.map +1 -0
- package/dist/harness/read-text.js +64 -0
- package/dist/harness/read-text.js.map +1 -0
- package/dist/harness/script-check.d.ts.map +1 -1
- package/dist/harness/script-check.js +3 -2
- package/dist/harness/script-check.js.map +1 -1
- package/dist/harness/sensors.d.ts.map +1 -1
- package/dist/harness/sensors.js +2 -10
- package/dist/harness/sensors.js.map +1 -1
- package/dist/harness/spec-coverage.d.ts +5 -0
- package/dist/harness/spec-coverage.d.ts.map +1 -1
- package/dist/harness/spec-coverage.js +17 -7
- package/dist/harness/spec-coverage.js.map +1 -1
- package/dist/harness/trace.d.ts.map +1 -1
- package/dist/harness/trace.js +4 -3
- package/dist/harness/trace.js.map +1 -1
- package/dist/harness/viewpoint-ledger.d.ts.map +1 -1
- package/dist/harness/viewpoint-ledger.js +2 -1
- package/dist/harness/viewpoint-ledger.js.map +1 -1
- package/dist/orchestrator/templates/ai-src/commands/create-test.md +9 -0
- package/dist/orchestrator/templates/ai-src/commands/delivery.md +103 -18
- package/dist/orchestrator/templates/ai-src/skills/sungen-delivery/SKILL.md +77 -11
- package/dist/orchestrator/templates/ai-src/skills/sungen-gherkin-syntax/SKILL.md +1 -0
- package/dist/orchestrator/templates/ai-src/skills/sungen-tc-generation/SKILL.md +22 -0
- package/package.json +4 -4
- package/src/cli/commands/delivery.ts +68 -22
- package/src/exporters/feature-parser.ts +21 -2
- package/src/exporters/matrix/build.ts +281 -43
- package/src/exporters/matrix/export.ts +31 -6
- package/src/exporters/matrix/gates.ts +119 -3
- package/src/exporters/matrix/map-loader.ts +22 -1
- package/src/exporters/matrix/render-csv.ts +53 -30
- package/src/exporters/matrix/render-xlsx.ts +216 -85
- package/src/exporters/matrix/types.ts +58 -8
- package/src/exporters/matrix/wording.ts +221 -0
- package/src/exporters/scenario-merger.ts +2 -1
- package/src/exporters/spec-parser.ts +2 -1
- package/src/harness/audit.ts +11 -2
- package/src/harness/blindspot.ts +2 -1
- package/src/harness/capability-plan.ts +3 -2
- package/src/harness/feedback.ts +3 -2
- package/src/harness/flow-check.ts +2 -1
- package/src/harness/flow-plan.ts +3 -2
- package/src/harness/intent.ts +2 -1
- package/src/harness/journey.ts +3 -2
- package/src/harness/ledger.ts +3 -2
- package/src/harness/manifest.ts +4 -3
- package/src/harness/parse.ts +17 -3
- package/src/harness/quality-gates.ts +2 -1
- package/src/harness/read-text.ts +28 -0
- package/src/harness/script-check.ts +3 -2
- package/src/harness/sensors.ts +2 -1
- package/src/harness/spec-coverage.ts +22 -7
- package/src/harness/trace.ts +4 -3
- package/src/harness/viewpoint-ledger.ts +2 -1
- package/src/orchestrator/templates/ai-src/commands/create-test.md +9 -0
- package/src/orchestrator/templates/ai-src/commands/delivery.md +103 -18
- package/src/orchestrator/templates/ai-src/skills/sungen-delivery/SKILL.md +77 -11
- package/src/orchestrator/templates/ai-src/skills/sungen-gherkin-syntax/SKILL.md +1 -0
- package/src/orchestrator/templates/ai-src/skills/sungen-tc-generation/SKILL.md +22 -0
|
@@ -31,6 +31,7 @@ import {
|
|
|
31
31
|
loadMatrixModel,
|
|
32
32
|
approveMatrix,
|
|
33
33
|
writeMatrixDeliverables,
|
|
34
|
+
MatrixFormat,
|
|
34
35
|
hasErrors,
|
|
35
36
|
hasReview,
|
|
36
37
|
} from '../../exporters/matrix/export';
|
|
@@ -621,6 +622,7 @@ function matrixPathsFor(cwd: string, target: DeliveryTarget): MatrixTargetPaths
|
|
|
621
622
|
featureFile: path.join(base, 'features', `${target.featureBaseName}.feature`),
|
|
622
623
|
testDataFile: resolveTestDataPathForTarget(cwd, target),
|
|
623
624
|
specFile: path.join(genBase, `${target.featureBaseName}.spec.ts`),
|
|
625
|
+
specMdFile: path.join(base, 'requirements', 'spec.md'),
|
|
624
626
|
resultsPath: resolveResultsPath(cwd, target),
|
|
625
627
|
mapFile: mapFilePath(base, target.featureBaseName),
|
|
626
628
|
};
|
|
@@ -650,7 +652,7 @@ interface MatrixRunSummary {
|
|
|
650
652
|
async function exportMatrixTarget(
|
|
651
653
|
cwd: string,
|
|
652
654
|
target: DeliveryTarget,
|
|
653
|
-
opts: { check?: boolean; preview?: boolean },
|
|
655
|
+
opts: { check?: boolean; preview?: boolean; format?: MatrixFormat },
|
|
654
656
|
): Promise<MatrixRunSummary | null> {
|
|
655
657
|
const paths = matrixPathsFor(cwd, target);
|
|
656
658
|
const { model, mapMissing, mapErrors } = loadMatrixModel(paths);
|
|
@@ -688,24 +690,38 @@ async function exportMatrixTarget(
|
|
|
688
690
|
return null;
|
|
689
691
|
}
|
|
690
692
|
|
|
691
|
-
const { csvPath, xlsxPath } = await writeMatrixDeliverables(paths, model);
|
|
693
|
+
const { csvPath, xlsxPath } = await writeMatrixDeliverables(paths, model, opts.format ?? 'xlsx');
|
|
692
694
|
const passed = model.items.reduce((a, i) => a + i.resultCounts.passed, 0);
|
|
693
695
|
const failed = model.items.reduce((a, i) => a + i.resultCounts.failed, 0);
|
|
694
|
-
|
|
696
|
+
const written = [xlsxPath, csvPath].filter((p): p is string => !!p).map((p) => path.relative(cwd, p));
|
|
697
|
+
for (const rel of written) log(` ${COLOR.green}→ ${rel}${COLOR.reset}`);
|
|
695
698
|
return {
|
|
696
699
|
label: paths.label,
|
|
697
700
|
items: model.manifest.itemCount,
|
|
698
701
|
variants: model.manifest.variantCount,
|
|
699
702
|
passed,
|
|
700
703
|
failed,
|
|
701
|
-
file:
|
|
704
|
+
file: written.join(' + '),
|
|
702
705
|
};
|
|
703
706
|
}
|
|
704
707
|
|
|
708
|
+
/**
|
|
709
|
+
* One place that accounts for every target the run did NOT write, so a sweep is
|
|
710
|
+
* never silently partial: scaffolds skipped by preflight and units whose gates /
|
|
711
|
+
* missing map stopped the export.
|
|
712
|
+
*/
|
|
713
|
+
function printSkipSummary(skipped: string[], notExported: string[]): void {
|
|
714
|
+
if (skipped.length === 0 && notExported.length === 0) return;
|
|
715
|
+
log(`${COLOR.gray}Not exported (${skipped.length + notExported.length}):${COLOR.reset}`);
|
|
716
|
+
for (const s of skipped) log(` ${COLOR.gray}· ${s}${COLOR.reset}`);
|
|
717
|
+
for (const n of notExported) log(` ${COLOR.gray}· ${n} (see the message above)${COLOR.reset}`);
|
|
718
|
+
log('');
|
|
719
|
+
}
|
|
720
|
+
|
|
705
721
|
function printMatrixSummaryTable(summaries: MatrixRunSummary[]): void {
|
|
706
722
|
log(`\n${COLOR.bold}Delivery matrix export complete${COLOR.reset}\n`);
|
|
707
723
|
const colWidth = Math.max(20, ...summaries.map((s) => s.label.length)) + 1;
|
|
708
|
-
log(` ${'Feature'.padEnd(colWidth)}Items Variants Passed Failed File`);
|
|
724
|
+
log(` ${'Feature'.padEnd(colWidth)}Items Variants Passed Failed File(s)`);
|
|
709
725
|
log(' ' + '-'.repeat(colWidth + 50));
|
|
710
726
|
for (const s of summaries) {
|
|
711
727
|
log(
|
|
@@ -795,9 +811,11 @@ export function registerDeliveryCommand(program: Command): void {
|
|
|
795
811
|
.option('--check', 'Matrix gates only — validate the delivery map, write nothing')
|
|
796
812
|
.option('--approve [ids]', 'Approve proposed groups (all, or a comma-separated id list) + stamp fingerprints')
|
|
797
813
|
.option('--preview', 'Render the matrix despite review-required findings (DRAFT watermark)')
|
|
814
|
+
.option('--format <format>', 'Matrix output format: xlsx (default) | csv | both', 'xlsx')
|
|
798
815
|
.action(async (names: string[], options: {
|
|
799
816
|
skipPreflight?: boolean; continueOnMissing?: boolean; env?: string;
|
|
800
817
|
legacy?: boolean; full?: boolean; check?: boolean; approve?: boolean | string; preview?: boolean;
|
|
818
|
+
format?: string;
|
|
801
819
|
}) => {
|
|
802
820
|
try {
|
|
803
821
|
// Same effect as running with SUNGEN_ENV=<env> — result-file resolution,
|
|
@@ -805,11 +823,19 @@ export function registerDeliveryCommand(program: Command): void {
|
|
|
805
823
|
if (options.env) process.env.SUNGEN_ENV = options.env;
|
|
806
824
|
const cwd = process.cwd();
|
|
807
825
|
|
|
826
|
+
// Matrix output format — one artifact by default (xlsx); csv/both on request.
|
|
827
|
+
const format = (options.format ?? 'xlsx').toLowerCase();
|
|
828
|
+
if (!['xlsx', 'csv', 'both'].includes(format)) {
|
|
829
|
+
console.error(`${COLOR.red}Invalid --format "${options.format}"${COLOR.reset} — use xlsx | csv | both`);
|
|
830
|
+
process.exit(1);
|
|
831
|
+
}
|
|
832
|
+
|
|
808
833
|
// 1. Scope detection — each positional name expands into one target
|
|
809
834
|
// per `.feature` file inside that screen/flow. Passing a specific
|
|
810
835
|
// feature basename (e.g. `home-modal`) narrows to that one file.
|
|
811
836
|
let targets: DeliveryTarget[];
|
|
812
|
-
|
|
837
|
+
const explicitScope = !!(names && names.length > 0);
|
|
838
|
+
if (explicitScope) {
|
|
813
839
|
targets = names.flatMap((n) => resolveTargetsFromArg(cwd, n));
|
|
814
840
|
} else {
|
|
815
841
|
targets = listAllTargets(cwd);
|
|
@@ -822,8 +848,13 @@ export function registerDeliveryCommand(program: Command): void {
|
|
|
822
848
|
const labels = targets.map((t) => t.isFlow ? `flow/${t.featureBaseName}` : t.featureBaseName);
|
|
823
849
|
log(`${COLOR.bold}sungen delivery${COLOR.reset} — exporting ${targets.length} feature(s): ${labels.join(', ')}\n`);
|
|
824
850
|
|
|
825
|
-
// 2. Pre-flight
|
|
851
|
+
// 2. Pre-flight — strictness follows the SCOPE. Naming a unit means "I want
|
|
852
|
+
// this one" (fail loudly); a no-argument sweep means "export everything
|
|
853
|
+
// that is ready", so scaffolded units (added but not yet authored) are
|
|
854
|
+
// skipped with a note instead of aborting the whole run — otherwise one
|
|
855
|
+
// untouched scaffold in a work-in-progress project produces zero files.
|
|
826
856
|
let toExport: DeliveryTarget[];
|
|
857
|
+
const skipped: string[] = [];
|
|
827
858
|
if (options.skipPreflight) {
|
|
828
859
|
toExport = targets;
|
|
829
860
|
} else {
|
|
@@ -832,22 +863,22 @@ export function registerDeliveryCommand(program: Command): void {
|
|
|
832
863
|
|
|
833
864
|
const blockers = checks.filter(hasBlockingMissing);
|
|
834
865
|
if (blockers.length > 0) {
|
|
835
|
-
if (options.continueOnMissing) {
|
|
836
|
-
const passedScreens = new Set(
|
|
837
|
-
checks.filter((c) => !hasBlockingMissing(c)).map((c) => c.screen)
|
|
838
|
-
);
|
|
839
|
-
toExport = targets.filter((t) => {
|
|
840
|
-
const label = t.isFlow ? `flow/${t.featureBaseName}` : t.featureBaseName;
|
|
841
|
-
return passedScreens.has(label);
|
|
842
|
-
});
|
|
843
|
-
log(`${COLOR.yellow}Continuing with ${toExport.length} ready target(s).${COLOR.reset}\n`);
|
|
844
|
-
} else {
|
|
866
|
+
if (explicitScope && !options.continueOnMissing) {
|
|
845
867
|
console.error(
|
|
846
|
-
`${COLOR.red}Aborted:${COLOR.reset} ${blockers.length} target(s) have blocking issues.\n` +
|
|
868
|
+
`${COLOR.red}Aborted:${COLOR.reset} ${blockers.length} named target(s) have blocking issues.\n` +
|
|
847
869
|
`Run the suggested commands above, or use ${COLOR.cyan}--continue-on-missing${COLOR.reset} to skip them.`
|
|
848
870
|
);
|
|
849
871
|
process.exit(1);
|
|
850
872
|
}
|
|
873
|
+
const readyLabels = new Set(
|
|
874
|
+
checks.filter((c) => !hasBlockingMissing(c)).map((c) => c.screen)
|
|
875
|
+
);
|
|
876
|
+
toExport = targets.filter((t) => {
|
|
877
|
+
const label = t.isFlow ? `flow/${t.featureBaseName}` : t.featureBaseName;
|
|
878
|
+
return readyLabels.has(label);
|
|
879
|
+
});
|
|
880
|
+
for (const b of blockers) skipped.push(`${b.screen} (not authored yet — run /sungen:create-test)`);
|
|
881
|
+
log(`${COLOR.yellow}Skipping ${blockers.length} target(s) that have no test cases yet; continuing with ${toExport.length}.${COLOR.reset}\n`);
|
|
851
882
|
} else {
|
|
852
883
|
toExport = targets;
|
|
853
884
|
}
|
|
@@ -883,14 +914,25 @@ export function registerDeliveryCommand(program: Command): void {
|
|
|
883
914
|
}
|
|
884
915
|
|
|
885
916
|
const matrixSummaries: MatrixRunSummary[] = [];
|
|
886
|
-
|
|
917
|
+
const notExported: string[] = [];
|
|
887
918
|
for (const target of toExport) {
|
|
888
|
-
const s = await exportMatrixTarget(cwd, target, {
|
|
919
|
+
const s = await exportMatrixTarget(cwd, target, {
|
|
920
|
+
check: options.check, preview: options.preview, format: format as MatrixFormat,
|
|
921
|
+
});
|
|
889
922
|
if (s) matrixSummaries.push(s);
|
|
890
|
-
else
|
|
923
|
+
else notExported.push(target.isFlow ? `flow/${target.featureBaseName}` : target.featureBaseName);
|
|
891
924
|
}
|
|
892
925
|
if (matrixSummaries.length > 0 && !options.check) printMatrixSummaryTable(matrixSummaries);
|
|
893
|
-
|
|
926
|
+
printSkipSummary(skipped, notExported);
|
|
927
|
+
// A named target that produced nothing is a failure. A sweep is a failure
|
|
928
|
+
// only when it produced nothing at all — units still waiting for a map or
|
|
929
|
+
// an approval are the normal state of a live project. Preflight skips are
|
|
930
|
+
// not counted here: reaching this point in an explicit scope means
|
|
931
|
+
// --continue-on-missing was passed, which IS the opt-in to tolerate them.
|
|
932
|
+
const failed = explicitScope
|
|
933
|
+
? notExported.length > 0
|
|
934
|
+
: matrixSummaries.length === 0;
|
|
935
|
+
if (failed) process.exit(1);
|
|
894
936
|
return;
|
|
895
937
|
}
|
|
896
938
|
|
|
@@ -903,6 +945,10 @@ export function registerDeliveryCommand(program: Command): void {
|
|
|
903
945
|
|
|
904
946
|
// 4. Summary
|
|
905
947
|
printSummaryTable(summaries);
|
|
948
|
+
printSkipSummary(skipped, []);
|
|
949
|
+
// Same rule as the matrix path: every attempted target in an explicit scope
|
|
950
|
+
// must have produced a file; a sweep only fails when nothing was written.
|
|
951
|
+
if (explicitScope ? summaries.length < toExport.length : summaries.length === 0) process.exit(1);
|
|
906
952
|
} catch (err) {
|
|
907
953
|
console.error(`${COLOR.red}Fatal:${COLOR.reset} ${err instanceof Error ? err.message : err}`);
|
|
908
954
|
process.exit(1);
|
|
@@ -172,12 +172,28 @@ export function extractAuthRole(tags: string[]): string | null {
|
|
|
172
172
|
}
|
|
173
173
|
|
|
174
174
|
/**
|
|
175
|
-
*
|
|
175
|
+
* The leading viewpoint/requirement id of a scenario title.
|
|
176
|
+
*
|
|
177
|
+
* The `VP-` prefix is the scheme sungen suggests, NOT a requirement: real projects
|
|
178
|
+
* bring their own (`SEC-123`, `PER-345`, `MS-HP-001`, `VP0-001`), and the harness
|
|
179
|
+
* has always been format-tolerant about it. The exporters were not — a project
|
|
180
|
+
* using `SEC-123` got no id at all, which made every scenario "unaddressable" and
|
|
181
|
+
* blocked the whole delivery matrix at Gate A.
|
|
182
|
+
*
|
|
183
|
+
* Shape: uppercase segments joined by `-`, ending in a number (with an optional
|
|
184
|
+
* letter or sub-code suffix). Requiring the trailing number is what keeps an
|
|
185
|
+
* ordinary title word ("A11y check…") from being mistaken for an id.
|
|
186
|
+
*/
|
|
187
|
+
export const SCENARIO_ID = /^([A-Z][A-Z0-9]*(?:-[A-Z0-9]+)*-\d+(?:[a-zA-Z]|-[A-Z0-9]+)?)/;
|
|
188
|
+
|
|
189
|
+
/**
|
|
190
|
+
* Extract the id and the human-readable name from a scenario title:
|
|
176
191
|
* "VP-UI-001 Modal displays all required fields" →
|
|
177
192
|
* { vpId: "VP-UI-001", category1: "Modal displays all required fields" }
|
|
193
|
+
* "SEC-123 Login is protected" → { vpId: "SEC-123", category1: "Login is protected" }
|
|
178
194
|
*/
|
|
179
195
|
export function splitVpAndName(scenarioName: string): { vpId?: string; category1: string } {
|
|
180
|
-
const match = scenarioName.match(
|
|
196
|
+
const match = scenarioName.match(new RegExp(SCENARIO_ID.source + '\\s+(.+)$'));
|
|
181
197
|
if (match) {
|
|
182
198
|
return { vpId: match[1], category1: match[2] };
|
|
183
199
|
}
|
|
@@ -194,6 +210,9 @@ export function splitVpAndName(scenarioName: string): { vpId?: string; category1
|
|
|
194
210
|
*/
|
|
195
211
|
export function mapVpToCategory2(vpId: string | undefined, scenarioName?: string): string {
|
|
196
212
|
if (!vpId) return 'Function';
|
|
213
|
+
// Compare on the category segment so a project scheme without the `VP-` prefix
|
|
214
|
+
// (`SEC-123`) classifies the same as `VP-SEC-001`.
|
|
215
|
+
vpId = /^VP-/.test(vpId) ? vpId : `VP-${vpId}`;
|
|
197
216
|
if (vpId.startsWith('VP-SEC-')) {
|
|
198
217
|
if (scenarioName && /xss|injection/i.test(scenarioName)) return 'Function';
|
|
199
218
|
return 'Accessing';
|