@qa-ai-stlc/explorer 0.5.1 → 0.6.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/dist/analyze-static-routes.d.ts +32 -0
- package/dist/analyze-static-routes.d.ts.map +1 -0
- package/dist/analyze-static-routes.js +113 -0
- package/dist/analyze-static-routes.js.map +1 -0
- package/dist/analyze-static-source.d.ts +3 -0
- package/dist/analyze-static-source.d.ts.map +1 -1
- package/dist/analyze-static-source.js +5 -2
- package/dist/analyze-static-source.js.map +1 -1
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -0
- package/dist/index.js.map +1 -1
- package/package.json +3 -3
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import type { RouteMap } from '@qa-ai-stlc/schemas';
|
|
2
|
+
import { type StaticSourceFile } from './analyze-static-source.js';
|
|
3
|
+
export interface StaticRouteFinding {
|
|
4
|
+
readonly path: string;
|
|
5
|
+
readonly filePath: string;
|
|
6
|
+
readonly line: number;
|
|
7
|
+
}
|
|
8
|
+
export interface AnalyzeStaticRoutesOptions {
|
|
9
|
+
readonly files: readonly StaticSourceFile[];
|
|
10
|
+
}
|
|
11
|
+
export interface AnalyzeStaticRoutesResult {
|
|
12
|
+
readonly routes: readonly StaticRouteFinding[];
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* Extracts client-side route declarations — React Router's `<Route path="...">` JSX, and Vue
|
|
16
|
+
* Router's/Angular's `path: '...'` route-config objects under a `routes` array — from raw source
|
|
17
|
+
* text (development plan 6.1.2), the same lightweight lexical scan `analyzeStaticSource` uses
|
|
18
|
+
* rather than a per-framework AST parser (`@babel/parser`, `vue/compiler-sfc`, `@angular/compiler`).
|
|
19
|
+
* Seeds routes the crawler cannot discover by following links alone: a route reachable only by a
|
|
20
|
+
* programmatic `navigate()` call, or one behind a condition the crawler never satisfies.
|
|
21
|
+
*/
|
|
22
|
+
export declare function analyzeStaticRoutes(options: AnalyzeStaticRoutesOptions): AnalyzeStaticRoutesResult;
|
|
23
|
+
/**
|
|
24
|
+
* Merges statically-extracted routes into a crawler-produced `RouteMap` (development plan 6.1.2's
|
|
25
|
+
* "merge does not duplicate routes the crawler already found"): each finding's path is resolved
|
|
26
|
+
* against the route map's own `startUrl` origin and normalized the same way the crawler's own
|
|
27
|
+
* routes are, so a route both sides found lands on the identical URL and is added only once. A
|
|
28
|
+
* static route's `sourceLocation` is the only place a developer can be pointed at for it — there
|
|
29
|
+
* is no live navigation, unlike a `link`/`sitemap` route.
|
|
30
|
+
*/
|
|
31
|
+
export declare function mergeStaticRoutes(routeMap: RouteMap, staticRoutes: readonly StaticRouteFinding[]): RouteMap;
|
|
32
|
+
//# sourceMappingURL=analyze-static-routes.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"analyze-static-routes.d.ts","sourceRoot":"","sources":["../src/analyze-static-routes.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAmB,QAAQ,EAAE,MAAM,qBAAqB,CAAC;AACrE,OAAO,EAAkC,KAAK,gBAAgB,EAAE,MAAM,4BAA4B,CAAC;AAGnG,MAAM,WAAW,kBAAkB;IACjC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;CACvB;AAED,MAAM,WAAW,0BAA0B;IACzC,QAAQ,CAAC,KAAK,EAAE,SAAS,gBAAgB,EAAE,CAAC;CAC7C;AAED,MAAM,WAAW,yBAAyB;IACxC,QAAQ,CAAC,MAAM,EAAE,SAAS,kBAAkB,EAAE,CAAC;CAChD;AA2ED;;;;;;;GAOG;AACH,wBAAgB,mBAAmB,CAAC,OAAO,EAAE,0BAA0B,GAAG,yBAAyB,CAMlG;AAED;;;;;;;GAOG;AACH,wBAAgB,iBAAiB,CAAC,QAAQ,EAAE,QAAQ,EAAE,YAAY,EAAE,SAAS,kBAAkB,EAAE,GAAG,QAAQ,CAmB3G"}
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
// Copyright The QA-AI-STLC Authors
|
|
2
|
+
// SPDX-License-Identifier: Apache-2.0
|
|
3
|
+
import { lineNumberAt, literalAttribute } from './analyze-static-source.js';
|
|
4
|
+
import { normalizeUrl } from './allowlist.js';
|
|
5
|
+
// React Router's own JSX form: `<Route path="/tasks/:id" ...>`. A nested `<Route>` inside a
|
|
6
|
+
// layout route's children is still matched, since this scans the whole file rather than one tree.
|
|
7
|
+
const REACT_ROUTE_TAG = /<Route\b([^>]*)>/g;
|
|
8
|
+
// Vue Router's `createRouter({ routes: [...] })` and Angular's `const routes: Routes = [...]`
|
|
9
|
+
// (development plan 6.1.2's route-config shape) declare a route array under the identifier
|
|
10
|
+
// "routes", as either an object property or a variable, with or without a type annotation between
|
|
11
|
+
// the name and the array. `[`/`]` are deliberately excluded from the optional type-annotation
|
|
12
|
+
// class so it can never swallow the array's own opening bracket.
|
|
13
|
+
const ROUTES_ARRAY_DECLARATION = /\broutes\s*(?::\s*[\w.<>]+\s*)?[:=]\s*\[/g;
|
|
14
|
+
// A literal `path` value inside a route-config object. Matches nested routes (a `children` array)
|
|
15
|
+
// too, since they sit inside the same outer `[...]` span this pattern is applied against.
|
|
16
|
+
const PATH_PROPERTY = /\bpath\s*:\s*(['"])([^'"]*)\1/g;
|
|
17
|
+
function findMatchingBracket(content, openIndex) {
|
|
18
|
+
let depth = 0;
|
|
19
|
+
for (let i = openIndex; i < content.length; i += 1) {
|
|
20
|
+
if (content[i] === '[') {
|
|
21
|
+
depth += 1;
|
|
22
|
+
}
|
|
23
|
+
else if (content[i] === ']') {
|
|
24
|
+
depth -= 1;
|
|
25
|
+
if (depth === 0) {
|
|
26
|
+
return i;
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
return content.length - 1;
|
|
31
|
+
}
|
|
32
|
+
function findReactRouterRoutes(file) {
|
|
33
|
+
const findings = [];
|
|
34
|
+
for (const match of file.content.matchAll(REACT_ROUTE_TAG)) {
|
|
35
|
+
// The capturing group is not inside an alternation, so it always participates once the
|
|
36
|
+
// pattern matches at all; the cast documents that instead of a defensive, untestable branch.
|
|
37
|
+
// eslint-disable-next-line @typescript-eslint/non-nullable-type-assertion-style
|
|
38
|
+
const attrs = match[1];
|
|
39
|
+
const path = literalAttribute(attrs, 'path');
|
|
40
|
+
if (path === undefined) {
|
|
41
|
+
continue;
|
|
42
|
+
}
|
|
43
|
+
findings.push({ path, filePath: file.filePath, line: lineNumberAt(file.content, match.index) });
|
|
44
|
+
}
|
|
45
|
+
return findings;
|
|
46
|
+
}
|
|
47
|
+
// A route-config array can be declared more than once in a file (a parent `routes` and a nested
|
|
48
|
+
// `children: [...]`, which the outer array already covers); `coveredUntil` stops a later
|
|
49
|
+
// declaration match that starts inside an already-scanned span from being scanned twice.
|
|
50
|
+
function findConfigObjectRoutes(file) {
|
|
51
|
+
const findings = [];
|
|
52
|
+
let coveredUntil = -1;
|
|
53
|
+
for (const declaration of file.content.matchAll(ROUTES_ARRAY_DECLARATION)) {
|
|
54
|
+
const openIndex = declaration.index + declaration[0].length - 1;
|
|
55
|
+
if (openIndex <= coveredUntil) {
|
|
56
|
+
continue;
|
|
57
|
+
}
|
|
58
|
+
const closeIndex = findMatchingBracket(file.content, openIndex);
|
|
59
|
+
coveredUntil = closeIndex;
|
|
60
|
+
const span = file.content.slice(openIndex, closeIndex + 1);
|
|
61
|
+
for (const pathMatch of span.matchAll(PATH_PROPERTY)) {
|
|
62
|
+
// Group 2 always participates when PATH_PROPERTY matches at all (it is not inside an
|
|
63
|
+
// alternation); the cast documents that instead of a defensive, untestable branch.
|
|
64
|
+
// eslint-disable-next-line @typescript-eslint/non-nullable-type-assertion-style
|
|
65
|
+
const path = pathMatch[2];
|
|
66
|
+
const absoluteIndex = openIndex + pathMatch.index;
|
|
67
|
+
findings.push({ path, filePath: file.filePath, line: lineNumberAt(file.content, absoluteIndex) });
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
return findings;
|
|
71
|
+
}
|
|
72
|
+
/**
|
|
73
|
+
* Extracts client-side route declarations — React Router's `<Route path="...">` JSX, and Vue
|
|
74
|
+
* Router's/Angular's `path: '...'` route-config objects under a `routes` array — from raw source
|
|
75
|
+
* text (development plan 6.1.2), the same lightweight lexical scan `analyzeStaticSource` uses
|
|
76
|
+
* rather than a per-framework AST parser (`@babel/parser`, `vue/compiler-sfc`, `@angular/compiler`).
|
|
77
|
+
* Seeds routes the crawler cannot discover by following links alone: a route reachable only by a
|
|
78
|
+
* programmatic `navigate()` call, or one behind a condition the crawler never satisfies.
|
|
79
|
+
*/
|
|
80
|
+
export function analyzeStaticRoutes(options) {
|
|
81
|
+
const routes = options.files.flatMap((file) => [
|
|
82
|
+
...findReactRouterRoutes(file),
|
|
83
|
+
...findConfigObjectRoutes(file),
|
|
84
|
+
]);
|
|
85
|
+
return { routes };
|
|
86
|
+
}
|
|
87
|
+
/**
|
|
88
|
+
* Merges statically-extracted routes into a crawler-produced `RouteMap` (development plan 6.1.2's
|
|
89
|
+
* "merge does not duplicate routes the crawler already found"): each finding's path is resolved
|
|
90
|
+
* against the route map's own `startUrl` origin and normalized the same way the crawler's own
|
|
91
|
+
* routes are, so a route both sides found lands on the identical URL and is added only once. A
|
|
92
|
+
* static route's `sourceLocation` is the only place a developer can be pointed at for it — there
|
|
93
|
+
* is no live navigation, unlike a `link`/`sitemap` route.
|
|
94
|
+
*/
|
|
95
|
+
export function mergeStaticRoutes(routeMap, staticRoutes) {
|
|
96
|
+
const origin = new URL(routeMap.startUrl).origin;
|
|
97
|
+
const knownUrls = new Set(routeMap.routes.map((route) => normalizeUrl(route.url)));
|
|
98
|
+
const added = [];
|
|
99
|
+
for (const finding of staticRoutes) {
|
|
100
|
+
const url = normalizeUrl(new URL(finding.path, origin).toString());
|
|
101
|
+
if (knownUrls.has(url)) {
|
|
102
|
+
continue;
|
|
103
|
+
}
|
|
104
|
+
knownUrls.add(url);
|
|
105
|
+
added.push({
|
|
106
|
+
url,
|
|
107
|
+
discoveredVia: 'static',
|
|
108
|
+
sourceLocation: { filePath: finding.filePath, line: finding.line },
|
|
109
|
+
});
|
|
110
|
+
}
|
|
111
|
+
return { ...routeMap, routes: [...routeMap.routes, ...added] };
|
|
112
|
+
}
|
|
113
|
+
//# sourceMappingURL=analyze-static-routes.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"analyze-static-routes.js","sourceRoot":"","sources":["../src/analyze-static-routes.ts"],"names":[],"mappings":"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"}
|
|
@@ -12,6 +12,9 @@ export interface AnalyzeStaticSourceOptions {
|
|
|
12
12
|
export interface AnalyzeStaticSourceResult {
|
|
13
13
|
readonly elements: readonly SelectorElement[];
|
|
14
14
|
}
|
|
15
|
+
export declare function literalAttribute(attrs: string, name: string): string | undefined;
|
|
16
|
+
/** Exported for analyze-static-routes.ts (P1-19): both scan the same raw source text for findings. */
|
|
17
|
+
export declare function lineNumberAt(content: string, index: number): number;
|
|
15
18
|
/**
|
|
16
19
|
* Extracts `data-testid`, `aria-label` and `role` from literal (never dynamically bound) HTML-shaped
|
|
17
20
|
* attributes across React, Angular and Vue sources (development plan 6.1.2), and turns each finding
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"analyze-static-source.d.ts","sourceRoot":"","sources":["../src/analyze-static-source.ts"],"names":[],"mappings":"AAGA,OAAO,EAAyB,KAAK,KAAK,EAAE,MAAM,kBAAkB,CAAC;AACrE,OAAO,KAAK,EAA4C,eAAe,EAAE,MAAM,qBAAqB,CAAC;AAGrG,MAAM,WAAW,gBAAgB;IAC/B,8FAA8F;IAC9F,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;CAC1B;AAED,MAAM,WAAW,0BAA0B;IACzC,QAAQ,CAAC,KAAK,EAAE,SAAS,gBAAgB,EAAE,CAAC;IAC5C,QAAQ,CAAC,KAAK,CAAC,EAAE,KAAK,CAAC;CACxB;AAED,MAAM,WAAW,yBAAyB;IACxC,QAAQ,CAAC,QAAQ,EAAE,SAAS,eAAe,EAAE,CAAC;CAC/C;
|
|
1
|
+
{"version":3,"file":"analyze-static-source.d.ts","sourceRoot":"","sources":["../src/analyze-static-source.ts"],"names":[],"mappings":"AAGA,OAAO,EAAyB,KAAK,KAAK,EAAE,MAAM,kBAAkB,CAAC;AACrE,OAAO,KAAK,EAA4C,eAAe,EAAE,MAAM,qBAAqB,CAAC;AAGrG,MAAM,WAAW,gBAAgB;IAC/B,8FAA8F;IAC9F,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;CAC1B;AAED,MAAM,WAAW,0BAA0B;IACzC,QAAQ,CAAC,KAAK,EAAE,SAAS,gBAAgB,EAAE,CAAC;IAC5C,QAAQ,CAAC,KAAK,CAAC,EAAE,KAAK,CAAC;CACxB;AAED,MAAM,WAAW,yBAAyB;IACxC,QAAQ,CAAC,QAAQ,EAAE,SAAS,eAAe,EAAE,CAAC;CAC/C;AA0BD,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAIhF;AAED,sGAAsG;AACtG,wBAAgB,YAAY,CAAC,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,MAAM,CAQnE;AAsFD;;;;;;;GAOG;AACH,wBAAgB,mBAAmB,CAAC,OAAO,EAAE,0BAA0B,GAAG,yBAAyB,CAuBlG"}
|
|
@@ -22,12 +22,15 @@ const KIND_BY_ROLE = {
|
|
|
22
22
|
// `:name=`/`v-bind:name=` and Angular's `[attr.name]=`/`[name]=` bindings never are — so a bound,
|
|
23
23
|
// non-literal value (a JS expression, not stable text) is never captured as one. The attrs chunk
|
|
24
24
|
// is padded with a leading space so an attribute at the very start of it still matches.
|
|
25
|
-
|
|
25
|
+
// Exported for analyze-static-routes.ts (P1-19), which reads the same literal-attribute shape
|
|
26
|
+
// out of a `<Route path="...">` tag.
|
|
27
|
+
export function literalAttribute(attrs, name) {
|
|
26
28
|
const pattern = new RegExp(`(?<=\\s)${name}\\s*=\\s*(?:"([^"]*)"|'([^']*)')`, 'u');
|
|
27
29
|
const match = pattern.exec(` ${attrs}`);
|
|
28
30
|
return match?.[1] ?? match?.[2];
|
|
29
31
|
}
|
|
30
|
-
|
|
32
|
+
/** Exported for analyze-static-routes.ts (P1-19): both scan the same raw source text for findings. */
|
|
33
|
+
export function lineNumberAt(content, index) {
|
|
31
34
|
let line = 1;
|
|
32
35
|
for (let i = 0; i < index; i += 1) {
|
|
33
36
|
if (content[i] === '\n') {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"analyze-static-source.js","sourceRoot":"","sources":["../src/analyze-static-source.ts"],"names":[],"mappings":"AAAA,mCAAmC;AACnC,sCAAsC;AAEtC,OAAO,EAAE,QAAQ,EAAE,WAAW,EAAc,MAAM,kBAAkB,CAAC;AAErE,OAAO,EAAE,kBAAkB,EAAE,MAAM,aAAa,CAAC;AAiBjD,MAAM,QAAQ,GAAqD;IACjE,MAAM,EAAE,QAAQ;IAChB,CAAC,EAAE,MAAM;IACT,KAAK,EAAE,OAAO;IACd,MAAM,EAAE,QAAQ;IAChB,QAAQ,EAAE,UAAU;CACrB,CAAC;AAEF,0FAA0F;AAC1F,+FAA+F;AAC/F,+FAA+F;AAC/F,iFAAiF;AACjF,MAAM,YAAY,GAAqD;IACrE,MAAM,EAAE,QAAQ;IAChB,IAAI,EAAE,MAAM;CACb,CAAC;AAEF,kGAAkG;AAClG,gGAAgG;AAChG,kGAAkG;AAClG,iGAAiG;AACjG,wFAAwF;AACxF,
|
|
1
|
+
{"version":3,"file":"analyze-static-source.js","sourceRoot":"","sources":["../src/analyze-static-source.ts"],"names":[],"mappings":"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"}
|
package/dist/index.d.ts
CHANGED
|
@@ -2,6 +2,7 @@ export * from './accessibility-tree.js';
|
|
|
2
2
|
export * from './allowlist.js';
|
|
3
3
|
export * from './analyze-page.js';
|
|
4
4
|
export * from './analyze-pages.js';
|
|
5
|
+
export * from './analyze-static-routes.js';
|
|
5
6
|
export * from './analyze-static-source.js';
|
|
6
7
|
export * from './build-missing-test-id-report.js';
|
|
7
8
|
export * from './build-selector-registry.js';
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAGA,cAAc,yBAAyB,CAAC;AACxC,cAAc,gBAAgB,CAAC;AAC/B,cAAc,mBAAmB,CAAC;AAClC,cAAc,oBAAoB,CAAC;AACnC,cAAc,4BAA4B,CAAC;AAC3C,cAAc,mCAAmC,CAAC;AAClD,cAAc,8BAA8B,CAAC;AAC7C,cAAc,YAAY,CAAC;AAC3B,cAAc,oBAAoB,CAAC;AACnC,cAAc,8BAA8B,CAAC;AAC7C,cAAc,eAAe,CAAC;AAC9B,cAAc,aAAa,CAAC;AAC5B,cAAc,gBAAgB,CAAC;AAC/B,cAAc,oBAAoB,CAAC;AACnC,cAAc,gBAAgB,CAAC;AAC/B,cAAc,kBAAkB,CAAC;AACjC,cAAc,gBAAgB,CAAC;AAC/B,cAAc,wBAAwB,CAAC;AACvC,cAAc,0BAA0B,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAGA,cAAc,yBAAyB,CAAC;AACxC,cAAc,gBAAgB,CAAC;AAC/B,cAAc,mBAAmB,CAAC;AAClC,cAAc,oBAAoB,CAAC;AACnC,cAAc,4BAA4B,CAAC;AAC3C,cAAc,4BAA4B,CAAC;AAC3C,cAAc,mCAAmC,CAAC;AAClD,cAAc,8BAA8B,CAAC;AAC7C,cAAc,YAAY,CAAC;AAC3B,cAAc,oBAAoB,CAAC;AACnC,cAAc,8BAA8B,CAAC;AAC7C,cAAc,eAAe,CAAC;AAC9B,cAAc,aAAa,CAAC;AAC5B,cAAc,gBAAgB,CAAC;AAC/B,cAAc,oBAAoB,CAAC;AACnC,cAAc,gBAAgB,CAAC;AAC/B,cAAc,kBAAkB,CAAC;AACjC,cAAc,gBAAgB,CAAC;AAC/B,cAAc,wBAAwB,CAAC;AACvC,cAAc,0BAA0B,CAAC"}
|
package/dist/index.js
CHANGED
|
@@ -4,6 +4,7 @@ export * from './accessibility-tree.js';
|
|
|
4
4
|
export * from './allowlist.js';
|
|
5
5
|
export * from './analyze-page.js';
|
|
6
6
|
export * from './analyze-pages.js';
|
|
7
|
+
export * from './analyze-static-routes.js';
|
|
7
8
|
export * from './analyze-static-source.js';
|
|
8
9
|
export * from './build-missing-test-id-report.js';
|
|
9
10
|
export * from './build-selector-registry.js';
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,mCAAmC;AACnC,sCAAsC;AAEtC,cAAc,yBAAyB,CAAC;AACxC,cAAc,gBAAgB,CAAC;AAC/B,cAAc,mBAAmB,CAAC;AAClC,cAAc,oBAAoB,CAAC;AACnC,cAAc,4BAA4B,CAAC;AAC3C,cAAc,mCAAmC,CAAC;AAClD,cAAc,8BAA8B,CAAC;AAC7C,cAAc,YAAY,CAAC;AAC3B,cAAc,oBAAoB,CAAC;AACnC,cAAc,8BAA8B,CAAC;AAC7C,cAAc,eAAe,CAAC;AAC9B,cAAc,aAAa,CAAC;AAC5B,cAAc,gBAAgB,CAAC;AAC/B,cAAc,oBAAoB,CAAC;AACnC,cAAc,gBAAgB,CAAC;AAC/B,cAAc,kBAAkB,CAAC;AACjC,cAAc,gBAAgB,CAAC;AAC/B,cAAc,wBAAwB,CAAC;AACvC,cAAc,0BAA0B,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,mCAAmC;AACnC,sCAAsC;AAEtC,cAAc,yBAAyB,CAAC;AACxC,cAAc,gBAAgB,CAAC;AAC/B,cAAc,mBAAmB,CAAC;AAClC,cAAc,oBAAoB,CAAC;AACnC,cAAc,4BAA4B,CAAC;AAC3C,cAAc,4BAA4B,CAAC;AAC3C,cAAc,mCAAmC,CAAC;AAClD,cAAc,8BAA8B,CAAC;AAC7C,cAAc,YAAY,CAAC;AAC3B,cAAc,oBAAoB,CAAC;AACnC,cAAc,8BAA8B,CAAC;AAC7C,cAAc,eAAe,CAAC;AAC9B,cAAc,aAAa,CAAC;AAC5B,cAAc,gBAAgB,CAAC;AAC/B,cAAc,oBAAoB,CAAC;AACnC,cAAc,gBAAgB,CAAC;AAC/B,cAAc,kBAAkB,CAAC;AACjC,cAAc,gBAAgB,CAAC;AAC/B,cAAc,wBAAwB,CAAC;AACvC,cAAc,0BAA0B,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@qa-ai-stlc/explorer",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.6.0",
|
|
4
4
|
"description": "The crawler: route discovery in safe mode, redacted request logging, and the route map every later explorer phase builds on.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "Apache-2.0",
|
|
@@ -28,8 +28,8 @@
|
|
|
28
28
|
"clean": "node ../../scripts/clean-dir.mjs dist"
|
|
29
29
|
},
|
|
30
30
|
"dependencies": {
|
|
31
|
-
"@qa-ai-stlc/core": "0.4.
|
|
32
|
-
"@qa-ai-stlc/schemas": "0.
|
|
31
|
+
"@qa-ai-stlc/core": "0.4.1",
|
|
32
|
+
"@qa-ai-stlc/schemas": "0.6.0"
|
|
33
33
|
},
|
|
34
34
|
"devDependencies": {
|
|
35
35
|
"@qa-ai-stlc/test-utils": "0.0.0"
|