@glasstrace/sdk 0.2.0 → 0.2.1
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/adapters/drizzle.js +2 -0
- package/dist/adapters/drizzle.js.map +1 -1
- package/dist/chunk-CUFIV225.js +14083 -0
- package/dist/chunk-CUFIV225.js.map +1 -0
- package/dist/chunk-PZ5AY32C.js +10 -0
- package/dist/chunk-PZ5AY32C.js.map +1 -0
- package/dist/cli/init.cjs +13855 -4
- package/dist/cli/init.cjs.map +1 -1
- package/dist/cli/init.js +2 -1
- package/dist/cli/init.js.map +1 -1
- package/dist/index.cjs +14014 -117
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +119 -1
- package/dist/index.d.ts +119 -1
- package/dist/index.js +13 -15
- package/dist/index.js.map +1 -1
- package/package.json +2 -4
- package/dist/chunk-BKMITIEZ.js +0 -169
- package/dist/chunk-BKMITIEZ.js.map +0 -1
package/dist/chunk-BKMITIEZ.js
DELETED
|
@@ -1,169 +0,0 @@
|
|
|
1
|
-
// src/import-graph.ts
|
|
2
|
-
import * as fs from "fs/promises";
|
|
3
|
-
import * as fsSync from "fs";
|
|
4
|
-
import * as path from "path";
|
|
5
|
-
import * as crypto from "crypto";
|
|
6
|
-
import { createBuildHash } from "@glasstrace/protocol";
|
|
7
|
-
var MAX_TEST_FILES = 5e3;
|
|
8
|
-
var EXCLUDED_DIRS = /* @__PURE__ */ new Set(["node_modules", ".next", ".git", "dist", ".turbo"]);
|
|
9
|
-
var DEFAULT_TEST_PATTERNS = [
|
|
10
|
-
/\.test\.tsx?$/,
|
|
11
|
-
/\.spec\.tsx?$/
|
|
12
|
-
];
|
|
13
|
-
function globToRegExp(glob) {
|
|
14
|
-
const DOUBLE_STAR_PLACEHOLDER = "\0DSTAR\0";
|
|
15
|
-
const regexStr = glob.replace(/\*\*\//g, DOUBLE_STAR_PLACEHOLDER).replace(/[.+?^${}()|[\]\\]/g, "\\$&").replace(/\*/g, "[^/]+").replace(new RegExp(DOUBLE_STAR_PLACEHOLDER.replace(/\0/g, "\\0"), "g"), "(?:.+/)?");
|
|
16
|
-
return new RegExp("^" + regexStr + "$");
|
|
17
|
-
}
|
|
18
|
-
function loadCustomTestPatterns(projectRoot) {
|
|
19
|
-
const configNames = [
|
|
20
|
-
"vitest.config.ts",
|
|
21
|
-
"vitest.config.js",
|
|
22
|
-
"vitest.config.mts",
|
|
23
|
-
"vitest.config.mjs",
|
|
24
|
-
"vite.config.ts",
|
|
25
|
-
"vite.config.js",
|
|
26
|
-
"vite.config.mts",
|
|
27
|
-
"vite.config.mjs",
|
|
28
|
-
"jest.config.ts",
|
|
29
|
-
"jest.config.js",
|
|
30
|
-
"jest.config.mts",
|
|
31
|
-
"jest.config.mjs"
|
|
32
|
-
];
|
|
33
|
-
for (const name of configNames) {
|
|
34
|
-
const configPath = path.join(projectRoot, name);
|
|
35
|
-
let content;
|
|
36
|
-
try {
|
|
37
|
-
content = fsSync.readFileSync(configPath, "utf-8");
|
|
38
|
-
} catch {
|
|
39
|
-
continue;
|
|
40
|
-
}
|
|
41
|
-
try {
|
|
42
|
-
const isJest = name.startsWith("jest.");
|
|
43
|
-
let includeMatch = null;
|
|
44
|
-
if (isJest) {
|
|
45
|
-
includeMatch = /testMatch\s*:\s*\[([^\]]*)\]/s.exec(content);
|
|
46
|
-
} else {
|
|
47
|
-
const testBlockMatch = /\btest\s*[:{]\s*/s.exec(content);
|
|
48
|
-
if (testBlockMatch) {
|
|
49
|
-
const afterTest = content.slice(testBlockMatch.index, testBlockMatch.index + 500);
|
|
50
|
-
includeMatch = /include\s*:\s*\[([^\]]*)\]/s.exec(afterTest);
|
|
51
|
-
}
|
|
52
|
-
}
|
|
53
|
-
if (!includeMatch) {
|
|
54
|
-
continue;
|
|
55
|
-
}
|
|
56
|
-
const arrayContent = includeMatch[1];
|
|
57
|
-
const stringRegex = /['"]([^'"]+)['"]/g;
|
|
58
|
-
const patterns = [];
|
|
59
|
-
let match;
|
|
60
|
-
match = stringRegex.exec(arrayContent);
|
|
61
|
-
while (match !== null) {
|
|
62
|
-
patterns.push(globToRegExp(match[1]));
|
|
63
|
-
match = stringRegex.exec(arrayContent);
|
|
64
|
-
}
|
|
65
|
-
if (patterns.length > 0) {
|
|
66
|
-
return patterns;
|
|
67
|
-
}
|
|
68
|
-
} catch {
|
|
69
|
-
continue;
|
|
70
|
-
}
|
|
71
|
-
}
|
|
72
|
-
return [];
|
|
73
|
-
}
|
|
74
|
-
async function discoverTestFiles(projectRoot) {
|
|
75
|
-
const customPatterns = loadCustomTestPatterns(projectRoot);
|
|
76
|
-
const testPatterns = [...DEFAULT_TEST_PATTERNS, ...customPatterns];
|
|
77
|
-
const results = [];
|
|
78
|
-
try {
|
|
79
|
-
await walkForTests(projectRoot, projectRoot, results, testPatterns);
|
|
80
|
-
} catch {
|
|
81
|
-
return [];
|
|
82
|
-
}
|
|
83
|
-
return results.slice(0, MAX_TEST_FILES);
|
|
84
|
-
}
|
|
85
|
-
async function walkForTests(baseDir, currentDir, results, testPatterns) {
|
|
86
|
-
if (results.length >= MAX_TEST_FILES) {
|
|
87
|
-
return;
|
|
88
|
-
}
|
|
89
|
-
let entries;
|
|
90
|
-
try {
|
|
91
|
-
entries = await fs.readdir(currentDir, { withFileTypes: true });
|
|
92
|
-
} catch {
|
|
93
|
-
return;
|
|
94
|
-
}
|
|
95
|
-
for (const entry of entries) {
|
|
96
|
-
if (results.length >= MAX_TEST_FILES) {
|
|
97
|
-
return;
|
|
98
|
-
}
|
|
99
|
-
const fullPath = path.join(currentDir, entry.name);
|
|
100
|
-
if (entry.isDirectory()) {
|
|
101
|
-
if (EXCLUDED_DIRS.has(entry.name)) {
|
|
102
|
-
continue;
|
|
103
|
-
}
|
|
104
|
-
await walkForTests(baseDir, fullPath, results, testPatterns);
|
|
105
|
-
} else if (entry.isFile()) {
|
|
106
|
-
const relativePath = path.relative(baseDir, fullPath).replace(/\\/g, "/");
|
|
107
|
-
const isTestFile = testPatterns.some((p) => p.test(entry.name) || p.test(relativePath)) || relativePath.includes("__tests__");
|
|
108
|
-
if (isTestFile && (entry.name.endsWith(".ts") || entry.name.endsWith(".tsx"))) {
|
|
109
|
-
results.push(relativePath);
|
|
110
|
-
}
|
|
111
|
-
}
|
|
112
|
-
}
|
|
113
|
-
}
|
|
114
|
-
function extractImports(fileContent) {
|
|
115
|
-
const seen = /* @__PURE__ */ new Set();
|
|
116
|
-
const imports = [];
|
|
117
|
-
const addUnique = (importPath) => {
|
|
118
|
-
if (!seen.has(importPath)) {
|
|
119
|
-
seen.add(importPath);
|
|
120
|
-
imports.push(importPath);
|
|
121
|
-
}
|
|
122
|
-
};
|
|
123
|
-
const esImportRegex = /import\s+(?:(?:[\w*{}\s,]+)\s+from\s+)?['"]([^'"]+)['"]/g;
|
|
124
|
-
let match;
|
|
125
|
-
match = esImportRegex.exec(fileContent);
|
|
126
|
-
while (match !== null) {
|
|
127
|
-
addUnique(match[1]);
|
|
128
|
-
match = esImportRegex.exec(fileContent);
|
|
129
|
-
}
|
|
130
|
-
const requireRegex = /require\s*\(\s*['"]([^'"]+)['"]\s*\)/g;
|
|
131
|
-
match = requireRegex.exec(fileContent);
|
|
132
|
-
while (match !== null) {
|
|
133
|
-
addUnique(match[1]);
|
|
134
|
-
match = requireRegex.exec(fileContent);
|
|
135
|
-
}
|
|
136
|
-
const dynamicImportRegex = /import\s*\(\s*['"]([^'"]+)['"]\s*\)/g;
|
|
137
|
-
match = dynamicImportRegex.exec(fileContent);
|
|
138
|
-
while (match !== null) {
|
|
139
|
-
addUnique(match[1]);
|
|
140
|
-
match = dynamicImportRegex.exec(fileContent);
|
|
141
|
-
}
|
|
142
|
-
return imports;
|
|
143
|
-
}
|
|
144
|
-
async function buildImportGraph(projectRoot) {
|
|
145
|
-
const testFiles = await discoverTestFiles(projectRoot);
|
|
146
|
-
const graph = {};
|
|
147
|
-
for (const testFile of testFiles) {
|
|
148
|
-
const fullPath = path.join(projectRoot, testFile);
|
|
149
|
-
try {
|
|
150
|
-
const content = await fs.readFile(fullPath, "utf-8");
|
|
151
|
-
const imports = extractImports(content);
|
|
152
|
-
graph[testFile] = imports;
|
|
153
|
-
} catch {
|
|
154
|
-
continue;
|
|
155
|
-
}
|
|
156
|
-
}
|
|
157
|
-
const sortedKeys = Object.keys(graph).sort();
|
|
158
|
-
const serialized = sortedKeys.map((key) => `${key}:${JSON.stringify(graph[key])}`).join("\n");
|
|
159
|
-
const hashHex = crypto.createHash("sha256").update(serialized).digest("hex");
|
|
160
|
-
const buildHash = createBuildHash(hashHex);
|
|
161
|
-
return { buildHash, graph };
|
|
162
|
-
}
|
|
163
|
-
|
|
164
|
-
export {
|
|
165
|
-
discoverTestFiles,
|
|
166
|
-
extractImports,
|
|
167
|
-
buildImportGraph
|
|
168
|
-
};
|
|
169
|
-
//# sourceMappingURL=chunk-BKMITIEZ.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/import-graph.ts"],"sourcesContent":["import * as fs from \"node:fs/promises\";\nimport * as fsSync from \"node:fs\";\nimport * as path from \"node:path\";\nimport * as crypto from \"node:crypto\";\nimport { createBuildHash, type ImportGraphPayload } from \"@glasstrace/protocol\";\n\n/** Maximum number of test files to process to prevent runaway in large projects */\nconst MAX_TEST_FILES = 5000;\n\n/** Directories to exclude from test file discovery */\nconst EXCLUDED_DIRS = new Set([\"node_modules\", \".next\", \".git\", \"dist\", \".turbo\"]);\n\n/** Conventional test file patterns */\nconst DEFAULT_TEST_PATTERNS = [\n /\\.test\\.tsx?$/,\n /\\.spec\\.tsx?$/,\n];\n\n/**\n * Converts a glob pattern (e.g. \"e2e/**\\/*.ts\") to an anchored RegExp.\n * Uses a placeholder to avoid `*` replacement corrupting the `**\\/` output.\n *\n * @param glob - A file glob pattern such as \"src/**\\/*.test.ts\".\n * @returns A RegExp that matches paths against the glob from start to end.\n */\nfunction globToRegExp(glob: string): RegExp {\n const DOUBLE_STAR_PLACEHOLDER = \"\\0DSTAR\\0\";\n const regexStr = glob\n .replace(/\\*\\*\\//g, DOUBLE_STAR_PLACEHOLDER) // protect **/ first\n .replace(/[.+?^${}()|[\\]\\\\]/g, \"\\\\$&\") // escape all regex metacharacters (except *)\n .replace(/\\*/g, \"[^/]+\")\n .replace(new RegExp(DOUBLE_STAR_PLACEHOLDER.replace(/\\0/g, \"\\\\0\"), \"g\"), \"(?:.+/)?\");\n return new RegExp(\"^\" + regexStr + \"$\");\n}\n\n/**\n * Attempts to read include patterns from vitest.config.*, vite.config.*,\n * or jest.config.* files. Returns additional RegExp patterns extracted\n * from the config, or an empty array if no config is found or parsing fails.\n * This is best-effort — it reads the config as text and extracts patterns\n * via regex, without evaluating the JS.\n *\n * For Vitest/Vite configs, looks for `test.include` arrays.\n * For Jest configs, looks for `testMatch` arrays.\n * Does not support `testRegex` (string-based Jest pattern) — that is\n * left as future work.\n */\nfunction loadCustomTestPatterns(projectRoot: string): RegExp[] {\n const configNames = [\n \"vitest.config.ts\",\n \"vitest.config.js\",\n \"vitest.config.mts\",\n \"vitest.config.mjs\",\n \"vite.config.ts\",\n \"vite.config.js\",\n \"vite.config.mts\",\n \"vite.config.mjs\",\n \"jest.config.ts\",\n \"jest.config.js\",\n \"jest.config.mts\",\n \"jest.config.mjs\",\n ];\n\n for (const name of configNames) {\n const configPath = path.join(projectRoot, name);\n let content: string;\n try {\n content = fsSync.readFileSync(configPath, \"utf-8\");\n } catch {\n // Config file does not exist at this path — try next candidate\n continue;\n }\n\n try {\n const isJest = name.startsWith(\"jest.\");\n let includeMatch: RegExpExecArray | null = null;\n\n if (isJest) {\n // Jest: look for testMatch: [...]\n includeMatch = /testMatch\\s*:\\s*\\[([^\\]]*)\\]/s.exec(content);\n } else {\n // Vitest/Vite: look for `test` block's `include` to avoid\n // matching `coverage.include` or other unrelated arrays.\n // Strategy: find `test` property, then look for `include` within\n // the next ~500 chars (heuristic to stay within the test block).\n const testBlockMatch = /\\btest\\s*[:{]\\s*/s.exec(content);\n if (testBlockMatch) {\n const afterTest = content.slice(testBlockMatch.index, testBlockMatch.index + 500);\n includeMatch = /include\\s*:\\s*\\[([^\\]]*)\\]/s.exec(afterTest);\n }\n }\n\n if (!includeMatch) {\n continue;\n }\n\n const arrayContent = includeMatch[1];\n const stringRegex = /['\"]([^'\"]+)['\"]/g;\n const patterns: RegExp[] = [];\n let match: RegExpExecArray | null;\n match = stringRegex.exec(arrayContent);\n while (match !== null) {\n patterns.push(globToRegExp(match[1]));\n match = stringRegex.exec(arrayContent);\n }\n\n if (patterns.length > 0) {\n return patterns;\n }\n } catch {\n // Regex-based config parsing failed — fall through to next config file\n continue;\n }\n }\n\n return [];\n}\n\n/**\n * Discovers test files by scanning the project directory for conventional\n * test file patterns. Also reads vitest/jest config files for custom include\n * patterns and merges them with the defaults. Excludes node_modules/ and .next/.\n *\n * @param projectRoot - Absolute path to the project root directory.\n * @returns Relative POSIX paths from projectRoot, capped at {@link MAX_TEST_FILES}.\n */\nexport async function discoverTestFiles(\n projectRoot: string,\n): Promise<string[]> {\n const customPatterns = loadCustomTestPatterns(projectRoot);\n const testPatterns = [...DEFAULT_TEST_PATTERNS, ...customPatterns];\n const results: string[] = [];\n\n try {\n await walkForTests(projectRoot, projectRoot, results, testPatterns);\n } catch {\n // Project root directory does not exist or is unreadable — return empty\n return [];\n }\n\n return results.slice(0, MAX_TEST_FILES);\n}\n\n/** Recursively walks directories, collecting test file paths into `results`. */\nasync function walkForTests(\n baseDir: string,\n currentDir: string,\n results: string[],\n testPatterns: RegExp[],\n): Promise<void> {\n if (results.length >= MAX_TEST_FILES) {\n return;\n }\n\n let entries: import(\"node:fs\").Dirent[];\n try {\n entries = await fs.readdir(currentDir, { withFileTypes: true });\n } catch {\n // Directory is unreadable (permissions, broken symlink) — skip subtree\n return;\n }\n\n for (const entry of entries) {\n if (results.length >= MAX_TEST_FILES) {\n return;\n }\n\n const fullPath = path.join(currentDir, entry.name);\n\n if (entry.isDirectory()) {\n if (EXCLUDED_DIRS.has(entry.name)) {\n continue;\n }\n await walkForTests(baseDir, fullPath, results, testPatterns);\n } else if (entry.isFile()) {\n const relativePath = path.relative(baseDir, fullPath).replace(/\\\\/g, \"/\");\n\n // Check if it matches test patterns or is in __tests__\n const isTestFile =\n testPatterns.some((p) => p.test(entry.name) || p.test(relativePath)) ||\n relativePath.includes(\"__tests__\");\n\n if (isTestFile && (entry.name.endsWith(\".ts\") || entry.name.endsWith(\".tsx\"))) {\n results.push(relativePath);\n }\n }\n }\n}\n\n/**\n * Extracts import paths from file content using regex.\n * Handles ES module imports, CommonJS requires, and dynamic imports.\n *\n * @param fileContent - The full text content of a TypeScript/JavaScript file.\n * @returns An array of import path strings as written in the source (e.g. \"./foo\", \"react\").\n */\nexport function extractImports(fileContent: string): string[] {\n const seen = new Set<string>();\n const imports: string[] = [];\n\n /** Adds a path to the result if not already present. */\n const addUnique = (importPath: string): void => {\n if (!seen.has(importPath)) {\n seen.add(importPath);\n imports.push(importPath);\n }\n };\n\n // ES module: import ... from 'path' or import 'path'\n const esImportRegex = /import\\s+(?:(?:[\\w*{}\\s,]+)\\s+from\\s+)?['\"]([^'\"]+)['\"]/g;\n let match: RegExpExecArray | null;\n\n match = esImportRegex.exec(fileContent);\n while (match !== null) {\n addUnique(match[1]);\n match = esImportRegex.exec(fileContent);\n }\n\n // CommonJS: require('path')\n const requireRegex = /require\\s*\\(\\s*['\"]([^'\"]+)['\"]\\s*\\)/g;\n match = requireRegex.exec(fileContent);\n while (match !== null) {\n addUnique(match[1]);\n match = requireRegex.exec(fileContent);\n }\n\n // Dynamic import: import('path')\n const dynamicImportRegex = /import\\s*\\(\\s*['\"]([^'\"]+)['\"]\\s*\\)/g;\n match = dynamicImportRegex.exec(fileContent);\n while (match !== null) {\n addUnique(match[1]);\n match = dynamicImportRegex.exec(fileContent);\n }\n\n return imports;\n}\n\n/**\n * Builds an import graph mapping test file paths to their imported module paths.\n *\n * Discovers test files, reads each, extracts imports, and builds a graph.\n * Computes a deterministic buildHash from the serialized graph content.\n * Individual file read failures are silently skipped.\n *\n * @param projectRoot - Absolute path to the project root directory.\n * @returns An {@link ImportGraphPayload} containing the graph and a deterministic buildHash.\n */\nexport async function buildImportGraph(\n projectRoot: string,\n): Promise<ImportGraphPayload> {\n const testFiles = await discoverTestFiles(projectRoot);\n const graph: Record<string, string[]> = {};\n\n for (const testFile of testFiles) {\n const fullPath = path.join(projectRoot, testFile);\n try {\n const content = await fs.readFile(fullPath, \"utf-8\");\n const imports = extractImports(content);\n graph[testFile] = imports;\n } catch {\n // File is unreadable (permissions, deleted between discovery and read) — skip\n continue;\n }\n }\n\n // Compute deterministic build hash from graph content\n const sortedKeys = Object.keys(graph).sort();\n const serialized = sortedKeys\n .map((key) => `${key}:${JSON.stringify(graph[key])}`)\n .join(\"\\n\");\n const hashHex = crypto\n .createHash(\"sha256\")\n .update(serialized)\n .digest(\"hex\");\n const buildHash = createBuildHash(hashHex);\n\n return { buildHash, graph };\n}\n"],"mappings":"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","names":[]}
|