@glubean/scanner 0.1.2

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.
@@ -0,0 +1,84 @@
1
+ /**
2
+ * @module @glubean/scanner
3
+ *
4
+ * Scanner for Glubean test files.
5
+ *
6
+ * Supports two extraction modes:
7
+ * - **Static analysis**: Uses regex patterns to extract metadata
8
+ * without importing files. Works everywhere.
9
+ * - **Runtime extraction**: Imports test files via tsx subprocess and reads
10
+ * metadata from the SDK's global registry (100% accurate).
11
+ *
12
+ * @example Static analysis (default)
13
+ * ```ts
14
+ * import { createScanner } from "@glubean/scanner";
15
+ *
16
+ * const scanner = createScanner();
17
+ * const result = await scanner.scan("./tests");
18
+ * console.log(`Found ${result.testCount} tests`);
19
+ * ```
20
+ *
21
+ * @example Pure static analysis (no file system)
22
+ * ```ts
23
+ * import { extractFromSource } from "@glubean/scanner";
24
+ *
25
+ * const content = fs.readFileSync("test.ts", "utf-8");
26
+ * const exports = extractFromSource(content);
27
+ * ```
28
+ */
29
+ export { isSpecVersionSupported, SPEC_VERSION, SUPPORTED_SPEC_VERSIONS } from "./spec.js";
30
+ export type { BundleMetadata, ExportMeta, FileMeta, ScanOptions, ScanResult, ValidationResult } from "./types.js";
31
+ export { Scanner } from "./scanner.js";
32
+ export type { FileSystem, Hasher, MetadataExtractor } from "./scanner.js";
33
+ export { createStaticExtractor, extractAliasesFromSource, extractFromSource, isGlubeanFile } from "./extractor-static.js";
34
+ export { nodeFs, nodeHasher } from "./fs.js";
35
+ import { Scanner } from "./scanner.js";
36
+ import type { ScanOptions, ScanResult, ValidationResult } from "./types.js";
37
+ /**
38
+ * Validate that a directory is a valid Glubean project.
39
+ *
40
+ * @param dir Directory to validate
41
+ * @returns Validation result with errors and warnings
42
+ *
43
+ * @example
44
+ * ```ts
45
+ * const result = await validate("./tests");
46
+ * if (!result.valid) {
47
+ * console.error("Errors:", result.errors);
48
+ * }
49
+ * ```
50
+ */
51
+ export declare function validate(dir: string): Promise<ValidationResult>;
52
+ /**
53
+ * Scan a directory for Glubean test files.
54
+ *
55
+ * Uses static analysis by default. For runtime extraction,
56
+ * create a Scanner with a custom MetadataExtractor.
57
+ *
58
+ * @param dir Directory to scan
59
+ * @param options Scan options
60
+ * @returns Scan result with file metadata and test counts
61
+ *
62
+ * @example
63
+ * ```ts
64
+ * const result = await scan("./tests");
65
+ * console.log(`Found ${result.testCount} tests`);
66
+ * ```
67
+ */
68
+ export declare function scan(dir: string, options?: ScanOptions): Promise<ScanResult>;
69
+ /**
70
+ * Create a scanner with static analysis extraction.
71
+ *
72
+ * Uses regex-based static analysis to extract metadata without importing files.
73
+ *
74
+ * @param specVersion Spec version to use for scanning
75
+ * @returns New Scanner instance
76
+ *
77
+ * @example
78
+ * ```ts
79
+ * const scanner = createScanner("2.0");
80
+ * const result = await scanner.scan("./tests");
81
+ * ```
82
+ */
83
+ export declare function createScanner(specVersion?: string): Scanner;
84
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;AAGH,OAAO,EAAE,sBAAsB,EAAE,YAAY,EAAE,uBAAuB,EAAE,MAAM,WAAW,CAAC;AAG1F,YAAY,EAAE,cAAc,EAAE,UAAU,EAAE,QAAQ,EAAE,WAAW,EAAE,UAAU,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAC;AAGlH,OAAO,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AACvC,YAAY,EAAE,UAAU,EAAE,MAAM,EAAE,iBAAiB,EAAE,MAAM,cAAc,CAAC;AAG1E,OAAO,EAAE,qBAAqB,EAAE,wBAAwB,EAAE,iBAAiB,EAAE,aAAa,EAAE,MAAM,uBAAuB,CAAC;AAG1H,OAAO,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AAK7C,OAAO,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AAEvC,OAAO,KAAK,EAAE,WAAW,EAAE,UAAU,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAC;AAU5E;;;;;;;;;;;;;GAaG;AACH,wBAAgB,QAAQ,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,gBAAgB,CAAC,CAE/D;AAED;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,IAAI,CAAC,GAAG,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,WAAW,GAAG,OAAO,CAAC,UAAU,CAAC,CAE5E;AAED;;;;;;;;;;;;;GAaG;AACH,wBAAgB,aAAa,CAAC,WAAW,GAAE,MAAqB,GAAG,OAAO,CAGzE"}
package/dist/index.js ADDED
@@ -0,0 +1,98 @@
1
+ /**
2
+ * @module @glubean/scanner
3
+ *
4
+ * Scanner for Glubean test files.
5
+ *
6
+ * Supports two extraction modes:
7
+ * - **Static analysis**: Uses regex patterns to extract metadata
8
+ * without importing files. Works everywhere.
9
+ * - **Runtime extraction**: Imports test files via tsx subprocess and reads
10
+ * metadata from the SDK's global registry (100% accurate).
11
+ *
12
+ * @example Static analysis (default)
13
+ * ```ts
14
+ * import { createScanner } from "@glubean/scanner";
15
+ *
16
+ * const scanner = createScanner();
17
+ * const result = await scanner.scan("./tests");
18
+ * console.log(`Found ${result.testCount} tests`);
19
+ * ```
20
+ *
21
+ * @example Pure static analysis (no file system)
22
+ * ```ts
23
+ * import { extractFromSource } from "@glubean/scanner";
24
+ *
25
+ * const content = fs.readFileSync("test.ts", "utf-8");
26
+ * const exports = extractFromSource(content);
27
+ * ```
28
+ */
29
+ // Re-export spec constants
30
+ export { isSpecVersionSupported, SPEC_VERSION, SUPPORTED_SPEC_VERSIONS } from "./spec.js";
31
+ // Re-export Scanner class and interfaces
32
+ export { Scanner } from "./scanner.js";
33
+ // Re-export static analysis extractor
34
+ export { createStaticExtractor, extractAliasesFromSource, extractFromSource, isGlubeanFile } from "./extractor-static.js";
35
+ // Re-export file system implementations
36
+ export { nodeFs, nodeHasher } from "./fs.js";
37
+ // Imports for convenience functions
38
+ import { nodeFs, nodeHasher } from "./fs.js";
39
+ import { createStaticExtractor } from "./extractor-static.js";
40
+ import { Scanner } from "./scanner.js";
41
+ import { SPEC_VERSION } from "./spec.js";
42
+ // Default scanner instance (static analysis)
43
+ const defaultScanner = new Scanner(nodeFs, nodeHasher, SPEC_VERSION, createStaticExtractor((path) => nodeFs.readText(path)));
44
+ /**
45
+ * Validate that a directory is a valid Glubean project.
46
+ *
47
+ * @param dir Directory to validate
48
+ * @returns Validation result with errors and warnings
49
+ *
50
+ * @example
51
+ * ```ts
52
+ * const result = await validate("./tests");
53
+ * if (!result.valid) {
54
+ * console.error("Errors:", result.errors);
55
+ * }
56
+ * ```
57
+ */
58
+ export function validate(dir) {
59
+ return defaultScanner.validate(dir);
60
+ }
61
+ /**
62
+ * Scan a directory for Glubean test files.
63
+ *
64
+ * Uses static analysis by default. For runtime extraction,
65
+ * create a Scanner with a custom MetadataExtractor.
66
+ *
67
+ * @param dir Directory to scan
68
+ * @param options Scan options
69
+ * @returns Scan result with file metadata and test counts
70
+ *
71
+ * @example
72
+ * ```ts
73
+ * const result = await scan("./tests");
74
+ * console.log(`Found ${result.testCount} tests`);
75
+ * ```
76
+ */
77
+ export function scan(dir, options) {
78
+ return defaultScanner.scan(dir, options);
79
+ }
80
+ /**
81
+ * Create a scanner with static analysis extraction.
82
+ *
83
+ * Uses regex-based static analysis to extract metadata without importing files.
84
+ *
85
+ * @param specVersion Spec version to use for scanning
86
+ * @returns New Scanner instance
87
+ *
88
+ * @example
89
+ * ```ts
90
+ * const scanner = createScanner("2.0");
91
+ * const result = await scanner.scan("./tests");
92
+ * ```
93
+ */
94
+ export function createScanner(specVersion = SPEC_VERSION) {
95
+ const extractor = createStaticExtractor((path) => nodeFs.readText(path));
96
+ return new Scanner(nodeFs, nodeHasher, specVersion, extractor);
97
+ }
98
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;AAEH,2BAA2B;AAC3B,OAAO,EAAE,sBAAsB,EAAE,YAAY,EAAE,uBAAuB,EAAE,MAAM,WAAW,CAAC;AAK1F,yCAAyC;AACzC,OAAO,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AAGvC,sCAAsC;AACtC,OAAO,EAAE,qBAAqB,EAAE,wBAAwB,EAAE,iBAAiB,EAAE,aAAa,EAAE,MAAM,uBAAuB,CAAC;AAE1H,wCAAwC;AACxC,OAAO,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AAE7C,oCAAoC;AACpC,OAAO,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AAC7C,OAAO,EAAE,qBAAqB,EAAE,MAAM,uBAAuB,CAAC;AAC9D,OAAO,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AACvC,OAAO,EAAE,YAAY,EAAE,MAAM,WAAW,CAAC;AAGzC,6CAA6C;AAC7C,MAAM,cAAc,GAAG,IAAI,OAAO,CAChC,MAAM,EACN,UAAU,EACV,YAAY,EACZ,qBAAqB,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,MAAM,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,CACvD,CAAC;AAEF;;;;;;;;;;;;;GAaG;AACH,MAAM,UAAU,QAAQ,CAAC,GAAW;IAClC,OAAO,cAAc,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC;AACtC,CAAC;AAED;;;;;;;;;;;;;;;GAeG;AACH,MAAM,UAAU,IAAI,CAAC,GAAW,EAAE,OAAqB;IACrD,OAAO,cAAc,CAAC,IAAI,CAAC,GAAG,EAAE,OAAO,CAAC,CAAC;AAC3C,CAAC;AAED;;;;;;;;;;;;;GAaG;AACH,MAAM,UAAU,aAAa,CAAC,cAAsB,YAAY;IAC9D,MAAM,SAAS,GAAG,qBAAqB,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,MAAM,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC;IACzE,OAAO,IAAI,OAAO,CAAC,MAAM,EAAE,UAAU,EAAE,WAAW,EAAE,SAAS,CAAC,CAAC;AACjE,CAAC"}
@@ -0,0 +1,64 @@
1
+ /**
2
+ * Core scanner logic for extracting test metadata from source files.
3
+ *
4
+ * This module uses runtime extraction - it imports test files and reads
5
+ * metadata from the SDK's global registry instead of static analysis.
6
+ */
7
+ import type { ExportMeta, ScanOptions, ScanResult, ValidationResult } from "./types.js";
8
+ /** File system interface for runtime abstraction */
9
+ export interface FileSystem {
10
+ /** Check if a path exists */
11
+ exists(path: string): Promise<boolean>;
12
+ /** Read file as text */
13
+ readText(path: string): Promise<string>;
14
+ /** Read file as bytes (for hashing) */
15
+ readBytes(path: string): Promise<Uint8Array>;
16
+ /** Walk directory recursively, yielding file paths */
17
+ walk(dir: string, options: {
18
+ extensions: string[];
19
+ skipDirs: string[];
20
+ }): AsyncIterable<string>;
21
+ /** Join path segments */
22
+ join(...segments: string[]): string;
23
+ /** Get relative path from base to target */
24
+ relative(base: string, target: string): string;
25
+ /** Resolve path to absolute */
26
+ resolve?(path: string): string;
27
+ }
28
+ /** Hash function interface */
29
+ export interface Hasher {
30
+ /** Calculate SHA-256 hash of content, returns "sha256-..." */
31
+ sha256(content: Uint8Array): Promise<string>;
32
+ }
33
+ /** Metadata extractor interface (runtime-specific) */
34
+ export type MetadataExtractor = (filePath: string, customFns?: string[]) => Promise<ExportMeta[]>;
35
+ /**
36
+ * Scanner class for extracting test metadata from a directory.
37
+ *
38
+ * Uses runtime extraction: imports test files and reads from SDK registry.
39
+ */
40
+ export declare class Scanner {
41
+ private readonly specVersion;
42
+ private readonly fs;
43
+ private readonly hasher;
44
+ private readonly extractor?;
45
+ constructor(fs: FileSystem, hasher: Hasher, specVersion?: string, extractor?: MetadataExtractor);
46
+ /**
47
+ * Collect custom function names from `.extend()` calls across all .ts files.
48
+ * Returns an array of alias names (e.g. ["browserTest", "screenshotTest"]).
49
+ */
50
+ private collectAliases;
51
+ /**
52
+ * Validate that a directory is a valid Glubean project.
53
+ */
54
+ validate(dir: string): Promise<ValidationResult>;
55
+ /**
56
+ * Scan a directory for Glubean test files using runtime extraction.
57
+ *
58
+ * This imports each test file in a subprocess and reads metadata from
59
+ * the SDK's global registry, ensuring accurate extraction without
60
+ * regex-based parsing.
61
+ */
62
+ scan(dir: string, options?: ScanOptions): Promise<ScanResult>;
63
+ }
64
+ //# sourceMappingURL=scanner.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"scanner.d.ts","sourceRoot":"","sources":["../src/scanner.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAIH,OAAO,KAAK,EAAE,UAAU,EAAY,WAAW,EAAE,UAAU,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAC;AAElG,oDAAoD;AACpD,MAAM,WAAW,UAAU;IACzB,6BAA6B;IAC7B,MAAM,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;IACvC,wBAAwB;IACxB,QAAQ,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC;IACxC,uCAAuC;IACvC,SAAS,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,UAAU,CAAC,CAAC;IAC7C,sDAAsD;IACtD,IAAI,CACF,GAAG,EAAE,MAAM,EACX,OAAO,EAAE;QAAE,UAAU,EAAE,MAAM,EAAE,CAAC;QAAC,QAAQ,EAAE,MAAM,EAAE,CAAA;KAAE,GACpD,aAAa,CAAC,MAAM,CAAC,CAAC;IACzB,yBAAyB;IACzB,IAAI,CAAC,GAAG,QAAQ,EAAE,MAAM,EAAE,GAAG,MAAM,CAAC;IACpC,4CAA4C;IAC5C,QAAQ,CAAC,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,MAAM,CAAC;IAC/C,+BAA+B;IAC/B,OAAO,CAAC,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAAC;CAChC;AAED,8BAA8B;AAC9B,MAAM,WAAW,MAAM;IACrB,8DAA8D;IAC9D,MAAM,CAAC,OAAO,EAAE,UAAU,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC;CAC9C;AAED,sDAAsD;AACtD,MAAM,MAAM,iBAAiB,GAAG,CAAC,QAAQ,EAAE,MAAM,EAAE,SAAS,CAAC,EAAE,MAAM,EAAE,KAAK,OAAO,CAAC,UAAU,EAAE,CAAC,CAAC;AAQlG;;;;GAIG;AACH,qBAAa,OAAO;IAClB,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAS;IACrC,OAAO,CAAC,QAAQ,CAAC,EAAE,CAAa;IAChC,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAS;IAChC,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAC,CAAoB;gBAG7C,EAAE,EAAE,UAAU,EACd,MAAM,EAAE,MAAM,EACd,WAAW,GAAE,MAAqB,EAClC,SAAS,CAAC,EAAE,iBAAiB;IAiB/B;;;OAGG;YACW,cAAc;IAmB5B;;OAEG;IACG,QAAQ,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,gBAAgB,CAAC;IAsEtD;;;;;;OAMG;IACG,IAAI,CAAC,GAAG,EAAE,MAAM,EAAE,OAAO,GAAE,WAAgB,GAAG,OAAO,CAAC,UAAU,CAAC;CAuFxE"}
@@ -0,0 +1,192 @@
1
+ /**
2
+ * Core scanner logic for extracting test metadata from source files.
3
+ *
4
+ * This module uses runtime extraction - it imports test files and reads
5
+ * metadata from the SDK's global registry instead of static analysis.
6
+ */
7
+ import { isSpecVersionSupported, SPEC_VERSION, SUPPORTED_SPEC_VERSIONS } from "./spec.js";
8
+ import { extractAliasesFromSource } from "./extractor-static.js";
9
+ const DEFAULT_SKIP_DIRS = ["node_modules", ".git", "dist", "build"];
10
+ const DEFAULT_EXTENSIONS = [".ts"];
11
+ // File detection uses the `.test.ts` extension as the convention.
12
+ // All *.test.ts files in scanned directories are considered Glubean test files.
13
+ /**
14
+ * Scanner class for extracting test metadata from a directory.
15
+ *
16
+ * Uses runtime extraction: imports test files and reads from SDK registry.
17
+ */
18
+ export class Scanner {
19
+ specVersion;
20
+ fs;
21
+ hasher;
22
+ extractor;
23
+ constructor(fs, hasher, specVersion = SPEC_VERSION, extractor) {
24
+ if (!isSpecVersionSupported(specVersion)) {
25
+ throw new Error(`Unsupported spec version: ${specVersion}. Supported: ${SUPPORTED_SPEC_VERSIONS.join(", ")}`);
26
+ }
27
+ this.fs = fs;
28
+ this.hasher = hasher;
29
+ this.specVersion = specVersion;
30
+ this.extractor = extractor;
31
+ }
32
+ /**
33
+ * Collect custom function names from `.extend()` calls across all .ts files.
34
+ * Returns an array of alias names (e.g. ["browserTest", "screenshotTest"]).
35
+ */
36
+ async collectAliases(dir, skipDirs = DEFAULT_SKIP_DIRS, extensions = DEFAULT_EXTENSIONS) {
37
+ const aliases = new Set();
38
+ try {
39
+ for await (const filePath of this.fs.walk(dir, { extensions, skipDirs })) {
40
+ const content = await this.fs.readText(filePath);
41
+ for (const alias of extractAliasesFromSource(content)) {
42
+ aliases.add(alias);
43
+ }
44
+ }
45
+ }
46
+ catch {
47
+ // Non-fatal — continue without aliases
48
+ }
49
+ return aliases.size > 0 ? [...aliases] : undefined;
50
+ }
51
+ /**
52
+ * Validate that a directory is a valid Glubean project.
53
+ */
54
+ async validate(dir) {
55
+ const errors = [];
56
+ const warnings = [];
57
+ let detectedSpecVersion;
58
+ // Check for package.json
59
+ const packageJsonPath = this.fs.join(dir, "package.json");
60
+ const hasPackageJson = await this.fs.exists(packageJsonPath);
61
+ if (!hasPackageJson) {
62
+ warnings.push("No package.json found - are you sure this is a Glubean project?");
63
+ }
64
+ else {
65
+ // Try to detect SDK version from package.json
66
+ try {
67
+ const content = await this.fs.readText(packageJsonPath);
68
+ const json = JSON.parse(content);
69
+ // Check dependencies for @glubean/sdk
70
+ const deps = { ...json.dependencies, ...json.devDependencies };
71
+ const sdkDep = deps["@glubean/sdk"];
72
+ if (sdkDep) {
73
+ // Extract version from dep like "^0.12.0" or "workspace:*"
74
+ const versionMatch = sdkDep.match(/(\d+)\.\d+\.\d+/);
75
+ if (versionMatch) {
76
+ const majorVersion = parseInt(versionMatch[1]);
77
+ detectedSpecVersion = majorVersion >= 2 ? "2.0" : "1.0";
78
+ }
79
+ }
80
+ }
81
+ catch {
82
+ warnings.push("Failed to parse package.json");
83
+ }
84
+ }
85
+ // Check for at least one *.test.ts file
86
+ let foundTestFile = false;
87
+ try {
88
+ for await (const filePath of this.fs.walk(dir, {
89
+ extensions: DEFAULT_EXTENSIONS,
90
+ skipDirs: DEFAULT_SKIP_DIRS,
91
+ })) {
92
+ if (filePath.endsWith(".test.ts")) {
93
+ foundTestFile = true;
94
+ break;
95
+ }
96
+ }
97
+ }
98
+ catch (err) {
99
+ errors.push(`Failed to scan directory: ${err}`);
100
+ }
101
+ if (!foundTestFile) {
102
+ errors.push("No *.test.ts files found. " +
103
+ "Ensure your test files are named *.test.ts.");
104
+ }
105
+ return {
106
+ valid: errors.length === 0,
107
+ errors,
108
+ warnings,
109
+ detectedSpecVersion: detectedSpecVersion || this.specVersion,
110
+ };
111
+ }
112
+ /**
113
+ * Scan a directory for Glubean test files using runtime extraction.
114
+ *
115
+ * This imports each test file in a subprocess and reads metadata from
116
+ * the SDK's global registry, ensuring accurate extraction without
117
+ * regex-based parsing.
118
+ */
119
+ async scan(dir, options = {}) {
120
+ const specVersion = options.specVersion || this.specVersion;
121
+ const skipDirs = options.skipDirs || DEFAULT_SKIP_DIRS;
122
+ const extensions = options.extensions || DEFAULT_EXTENSIONS;
123
+ const files = {};
124
+ let testCount = 0;
125
+ const allTags = new Set();
126
+ const warnings = [];
127
+ // Optionally validate first
128
+ if (options.requirePackageJson) {
129
+ const validation = await this.validate(dir);
130
+ if (!validation.valid) {
131
+ throw new Error(`Invalid Glubean project: ${validation.errors.join("; ")}`);
132
+ }
133
+ warnings.push(...validation.warnings);
134
+ }
135
+ else {
136
+ // Just check package.json for warning
137
+ const packageJsonPath = this.fs.join(dir, "package.json");
138
+ const hasPackageJson = await this.fs.exists(packageJsonPath);
139
+ if (!hasPackageJson) {
140
+ warnings.push("No package.json found in root directory");
141
+ }
142
+ }
143
+ if (!this.extractor) {
144
+ throw new Error("No metadata extractor configured. Use createScanner() for the default extractor.");
145
+ }
146
+ // Phase 1: collect .extend() aliases from all .ts files
147
+ const aliases = await this.collectAliases(dir, skipDirs, extensions);
148
+ // Phase 2: collect all *.test.ts files
149
+ const testFiles = [];
150
+ for await (const filePath of this.fs.walk(dir, { extensions, skipDirs })) {
151
+ if (!filePath.endsWith(".test.ts"))
152
+ continue;
153
+ testFiles.push(filePath);
154
+ }
155
+ // Extract metadata from each file using runtime extraction
156
+ for (const filePath of testFiles) {
157
+ try {
158
+ const exports = await this.extractor(filePath, aliases);
159
+ if (exports.length > 0) {
160
+ const relativePath = this.fs.relative(dir, filePath);
161
+ const contentBytes = await this.fs.readBytes(filePath);
162
+ const hash = await this.hasher.sha256(contentBytes);
163
+ files[relativePath] = { hash, exports };
164
+ // Count tests and collect tags
165
+ for (const exp of exports) {
166
+ testCount += 1;
167
+ // Collect tags
168
+ if (exp.tags) {
169
+ exp.tags.forEach((tag) => allTags.add(tag));
170
+ }
171
+ }
172
+ }
173
+ }
174
+ catch (err) {
175
+ warnings.push(`Failed to extract metadata from ${filePath}: ${err}`);
176
+ }
177
+ }
178
+ if (Object.keys(files).length === 0) {
179
+ warnings.push("No Glubean test files found. " +
180
+ "Ensure your test files are named *.test.ts and export test().");
181
+ }
182
+ return {
183
+ specVersion,
184
+ files,
185
+ testCount,
186
+ fileCount: Object.keys(files).length,
187
+ tags: Array.from(allTags),
188
+ warnings,
189
+ };
190
+ }
191
+ }
192
+ //# sourceMappingURL=scanner.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"scanner.js","sourceRoot":"","sources":["../src/scanner.ts"],"names":[],"mappings":"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"}
package/dist/spec.d.ts ADDED
@@ -0,0 +1,31 @@
1
+ /**
2
+ * Glubean Spec Version
3
+ *
4
+ * This defines the contract between SDK, Scanner, and Runner.
5
+ * - Major version: Breaking changes (Scanner/Runner may not be compatible)
6
+ * - Minor version: New features (backward compatible)
7
+ *
8
+ * History:
9
+ * - 1.0: Initial release
10
+ * - testCase(meta, fn) and testSuite(meta, config)
11
+ * - TestContext: vars, secrets, log, assert, trace
12
+ * - TestCaseMeta: id, name, description, tags, timeout, only, skip
13
+ * - TestSuiteMeta: id, name, description, tags, only, skip
14
+ *
15
+ * - 2.0: Unified Builder API
16
+ * - test(meta, fn) for simple tests (replaces testCase)
17
+ * - test(id).step().build() for multi-step tests (replaces testSuite)
18
+ * - Global registry for runtime metadata extraction
19
+ * - Legacy testCase/testSuite API removed
20
+ */
21
+ export declare const SPEC_VERSION = "2.0";
22
+ /**
23
+ * Supported spec versions for scanning.
24
+ * Scanner can read test files from these versions.
25
+ */
26
+ export declare const SUPPORTED_SPEC_VERSIONS: readonly ["1.0", "2.0"];
27
+ /**
28
+ * Check if a spec version is supported by this scanner.
29
+ */
30
+ export declare function isSpecVersionSupported(version: string): boolean;
31
+ //# sourceMappingURL=spec.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"spec.d.ts","sourceRoot":"","sources":["../src/spec.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;GAmBG;AACH,eAAO,MAAM,YAAY,QAAQ,CAAC;AAElC;;;GAGG;AACH,eAAO,MAAM,uBAAuB,yBAA0B,CAAC;AAE/D;;GAEG;AACH,wBAAgB,sBAAsB,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAI/D"}
package/dist/spec.js ADDED
@@ -0,0 +1,33 @@
1
+ /**
2
+ * Glubean Spec Version
3
+ *
4
+ * This defines the contract between SDK, Scanner, and Runner.
5
+ * - Major version: Breaking changes (Scanner/Runner may not be compatible)
6
+ * - Minor version: New features (backward compatible)
7
+ *
8
+ * History:
9
+ * - 1.0: Initial release
10
+ * - testCase(meta, fn) and testSuite(meta, config)
11
+ * - TestContext: vars, secrets, log, assert, trace
12
+ * - TestCaseMeta: id, name, description, tags, timeout, only, skip
13
+ * - TestSuiteMeta: id, name, description, tags, only, skip
14
+ *
15
+ * - 2.0: Unified Builder API
16
+ * - test(meta, fn) for simple tests (replaces testCase)
17
+ * - test(id).step().build() for multi-step tests (replaces testSuite)
18
+ * - Global registry for runtime metadata extraction
19
+ * - Legacy testCase/testSuite API removed
20
+ */
21
+ export const SPEC_VERSION = "2.0";
22
+ /**
23
+ * Supported spec versions for scanning.
24
+ * Scanner can read test files from these versions.
25
+ */
26
+ export const SUPPORTED_SPEC_VERSIONS = ["1.0", "2.0"];
27
+ /**
28
+ * Check if a spec version is supported by this scanner.
29
+ */
30
+ export function isSpecVersionSupported(version) {
31
+ return SUPPORTED_SPEC_VERSIONS.includes(version);
32
+ }
33
+ //# sourceMappingURL=spec.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"spec.js","sourceRoot":"","sources":["../src/spec.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;GAmBG;AACH,MAAM,CAAC,MAAM,YAAY,GAAG,KAAK,CAAC;AAElC;;;GAGG;AACH,MAAM,CAAC,MAAM,uBAAuB,GAAG,CAAC,KAAK,EAAE,KAAK,CAAU,CAAC;AAE/D;;GAEG;AACH,MAAM,UAAU,sBAAsB,CAAC,OAAe;IACpD,OAAO,uBAAuB,CAAC,QAAQ,CACrC,OAAmD,CACpD,CAAC;AACJ,CAAC"}
@@ -0,0 +1,24 @@
1
+ /**
2
+ * Pure static analysis entry point for Glubean test files.
3
+ *
4
+ * This module re-exports the pure regex-based extractor and SDK import
5
+ * detection utilities. It has **no runtime dependencies** — no file system
6
+ * access — making it safe to consume from constrained environments
7
+ * such as the VSCode extension.
8
+ *
9
+ * @example
10
+ * ```ts
11
+ * import { extractFromSource, isGlubeanFile } from "@glubean/scanner/static";
12
+ *
13
+ * const code = await fs.readFile("tests/api.test.ts", "utf-8");
14
+ * if (isGlubeanFile(code)) {
15
+ * const tests = extractFromSource(code);
16
+ * console.log(`Found ${tests.length} tests`);
17
+ * }
18
+ * ```
19
+ *
20
+ * @module static
21
+ */
22
+ export { createStaticExtractor, extractAliasesFromSource, extractFromSource, isGlubeanFile, } from "./extractor-static.js";
23
+ export type { ExportMeta } from "./types.js";
24
+ //# sourceMappingURL=static.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"static.d.ts","sourceRoot":"","sources":["../src/static.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;GAoBG;AAEH,OAAO,EACL,qBAAqB,EACrB,wBAAwB,EACxB,iBAAiB,EACjB,aAAa,GACd,MAAM,uBAAuB,CAAC;AAE/B,YAAY,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC"}
package/dist/static.js ADDED
@@ -0,0 +1,23 @@
1
+ /**
2
+ * Pure static analysis entry point for Glubean test files.
3
+ *
4
+ * This module re-exports the pure regex-based extractor and SDK import
5
+ * detection utilities. It has **no runtime dependencies** — no file system
6
+ * access — making it safe to consume from constrained environments
7
+ * such as the VSCode extension.
8
+ *
9
+ * @example
10
+ * ```ts
11
+ * import { extractFromSource, isGlubeanFile } from "@glubean/scanner/static";
12
+ *
13
+ * const code = await fs.readFile("tests/api.test.ts", "utf-8");
14
+ * if (isGlubeanFile(code)) {
15
+ * const tests = extractFromSource(code);
16
+ * console.log(`Found ${tests.length} tests`);
17
+ * }
18
+ * ```
19
+ *
20
+ * @module static
21
+ */
22
+ export { createStaticExtractor, extractAliasesFromSource, extractFromSource, isGlubeanFile, } from "./extractor-static.js";
23
+ //# sourceMappingURL=static.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"static.js","sourceRoot":"","sources":["../src/static.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;GAoBG;AAEH,OAAO,EACL,qBAAqB,EACrB,wBAAwB,EACxB,iBAAiB,EACjB,aAAa,GACd,MAAM,uBAAuB,CAAC"}