@ophan/core 0.0.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.
Files changed (47) hide show
  1. package/README.md +107 -0
  2. package/dist/index.d.ts +115 -0
  3. package/dist/index.d.ts.map +1 -0
  4. package/dist/index.js +715 -0
  5. package/dist/index.test.d.ts +2 -0
  6. package/dist/index.test.d.ts.map +1 -0
  7. package/dist/index.test.js +492 -0
  8. package/dist/parsers/__fixtures__/arrow-functions.d.ts +5 -0
  9. package/dist/parsers/__fixtures__/arrow-functions.d.ts.map +1 -0
  10. package/dist/parsers/__fixtures__/arrow-functions.js +16 -0
  11. package/dist/parsers/__fixtures__/class-methods.d.ts +6 -0
  12. package/dist/parsers/__fixtures__/class-methods.d.ts.map +1 -0
  13. package/dist/parsers/__fixtures__/class-methods.js +12 -0
  14. package/dist/parsers/__fixtures__/no-functions.d.ts +9 -0
  15. package/dist/parsers/__fixtures__/no-functions.d.ts.map +1 -0
  16. package/dist/parsers/__fixtures__/no-functions.js +4 -0
  17. package/dist/parsers/index.d.ts +3 -0
  18. package/dist/parsers/index.d.ts.map +1 -0
  19. package/dist/parsers/index.js +18 -0
  20. package/dist/parsers/python.d.ts +8 -0
  21. package/dist/parsers/python.d.ts.map +1 -0
  22. package/dist/parsers/python.js +137 -0
  23. package/dist/parsers/python.test.d.ts +2 -0
  24. package/dist/parsers/python.test.d.ts.map +1 -0
  25. package/dist/parsers/python.test.js +96 -0
  26. package/dist/parsers/registry.d.ts +8 -0
  27. package/dist/parsers/registry.d.ts.map +1 -0
  28. package/dist/parsers/registry.js +68 -0
  29. package/dist/parsers/types.d.ts +10 -0
  30. package/dist/parsers/types.d.ts.map +1 -0
  31. package/dist/parsers/types.js +18 -0
  32. package/dist/parsers/typescript.d.ts +8 -0
  33. package/dist/parsers/typescript.d.ts.map +1 -0
  34. package/dist/parsers/typescript.js +110 -0
  35. package/dist/parsers/typescript.test.d.ts +2 -0
  36. package/dist/parsers/typescript.test.d.ts.map +1 -0
  37. package/dist/parsers/typescript.test.js +106 -0
  38. package/dist/schemas.d.ts +100 -0
  39. package/dist/schemas.d.ts.map +1 -0
  40. package/dist/schemas.js +128 -0
  41. package/dist/shared.d.ts +12 -0
  42. package/dist/shared.d.ts.map +1 -0
  43. package/dist/shared.js +10 -0
  44. package/dist/test-utils.d.ts +46 -0
  45. package/dist/test-utils.d.ts.map +1 -0
  46. package/dist/test-utils.js +141 -0
  47. package/package.json +37 -0
@@ -0,0 +1,100 @@
1
+ import { z } from "zod";
2
+ export declare const AnalysisType: z.ZodEnum<{
3
+ documentation: "documentation";
4
+ security: "security";
5
+ }>;
6
+ export type AnalysisType = z.infer<typeof AnalysisType>;
7
+ export declare const KNOWN_DATA_TAGS: readonly ["user_input", "pii", "credentials", "database", "external_api", "file_system", "config", "internal"];
8
+ export type KnownDataTag = (typeof KNOWN_DATA_TAGS)[number];
9
+ export declare const KNOWN_SECURITY_FLAGS: readonly ["sql_injection", "xss", "hardcoded_secret", "unsanitized_input", "path_traversal", "prototype_pollution", "command_injection", "pickle_deserialization", "eval_exec", "insecure_subprocess"];
10
+ export type KnownSecurityFlag = (typeof KNOWN_SECURITY_FLAGS)[number];
11
+ export declare const ParamSchema: z.ZodObject<{
12
+ name: z.ZodString;
13
+ type: z.ZodString;
14
+ description: z.ZodString;
15
+ }, z.core.$strip>;
16
+ export type Param = z.infer<typeof ParamSchema>;
17
+ export declare const ReturnsSchema: z.ZodObject<{
18
+ type: z.ZodString;
19
+ description: z.ZodString;
20
+ }, z.core.$strip>;
21
+ export type Returns = z.infer<typeof ReturnsSchema>;
22
+ /** Documentation analysis: description, parameters, return type */
23
+ export declare const DocumentationAnalysis: z.ZodObject<{
24
+ description: z.ZodString;
25
+ params: z.ZodArray<z.ZodObject<{
26
+ name: z.ZodString;
27
+ type: z.ZodString;
28
+ description: z.ZodString;
29
+ }, z.core.$strip>>;
30
+ returns: z.ZodObject<{
31
+ type: z.ZodString;
32
+ description: z.ZodString;
33
+ }, z.core.$strip>;
34
+ }, z.core.$strip>;
35
+ export type DocumentationAnalysis = z.infer<typeof DocumentationAnalysis>;
36
+ /**
37
+ * Security analysis: data flow tags and security vulnerability flags.
38
+ * Both fields use z.string() arrays (not enums) — open with known values.
39
+ * Unknown values from Claude are preserved, not rejected.
40
+ */
41
+ export declare const SecurityAnalysis: z.ZodObject<{
42
+ dataTags: z.ZodArray<z.ZodString>;
43
+ securityFlags: z.ZodArray<z.ZodString>;
44
+ }, z.core.$strip>;
45
+ export type SecurityAnalysis = z.infer<typeof SecurityAnalysis>;
46
+ export declare const TypedAnalysis: z.ZodDiscriminatedUnion<[z.ZodObject<{
47
+ analysisType: z.ZodLiteral<"documentation">;
48
+ data: z.ZodObject<{
49
+ description: z.ZodString;
50
+ params: z.ZodArray<z.ZodObject<{
51
+ name: z.ZodString;
52
+ type: z.ZodString;
53
+ description: z.ZodString;
54
+ }, z.core.$strip>>;
55
+ returns: z.ZodObject<{
56
+ type: z.ZodString;
57
+ description: z.ZodString;
58
+ }, z.core.$strip>;
59
+ }, z.core.$strip>;
60
+ }, z.core.$strip>, z.ZodObject<{
61
+ analysisType: z.ZodLiteral<"security">;
62
+ data: z.ZodObject<{
63
+ dataTags: z.ZodArray<z.ZodString>;
64
+ securityFlags: z.ZodArray<z.ZodString>;
65
+ }, z.core.$strip>;
66
+ }, z.core.$strip>], "analysisType">;
67
+ export type TypedAnalysis = z.infer<typeof TypedAnalysis>;
68
+ /**
69
+ * Validates the raw JSON response from Claude's analysis.
70
+ * The prompt returns a flat object per function with all fields combined.
71
+ * We validate here, then split into separate analysis type rows on storage.
72
+ *
73
+ * Uses .catch() defaults so partial/malformed responses degrade gracefully
74
+ * instead of rejecting entire batches.
75
+ */
76
+ export declare const ClaudeAnalysisResponse: z.ZodObject<{
77
+ name: z.ZodString;
78
+ description: z.ZodCatch<z.ZodString>;
79
+ params: z.ZodCatch<z.ZodArray<z.ZodObject<{
80
+ name: z.ZodString;
81
+ type: z.ZodString;
82
+ description: z.ZodString;
83
+ }, z.core.$strip>>>;
84
+ returns: z.ZodCatch<z.ZodObject<{
85
+ type: z.ZodString;
86
+ description: z.ZodString;
87
+ }, z.core.$strip>>;
88
+ dataTags: z.ZodCatch<z.ZodArray<z.ZodString>>;
89
+ securityFlags: z.ZodCatch<z.ZodArray<z.ZodString>>;
90
+ }, z.core.$strip>;
91
+ export type ClaudeAnalysisResponse = z.infer<typeof ClaudeAnalysisResponse>;
92
+ /**
93
+ * Each analysis type has an independent schema version.
94
+ * Bump when the JSON shape changes. Old rows remain readable.
95
+ * Stored alongside each row for forward-compatibility.
96
+ */
97
+ export declare const SCHEMA_VERSIONS: Record<AnalysisType, number>;
98
+ export declare const SECURITY_FLAG_LABELS: Record<string, string>;
99
+ export declare const DATA_TAG_LABELS: Record<string, string>;
100
+ //# sourceMappingURL=schemas.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"schemas.d.ts","sourceRoot":"","sources":["../src/schemas.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAIxB,eAAO,MAAM,YAAY;;;EAAwC,CAAC;AAClE,MAAM,MAAM,YAAY,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,YAAY,CAAC,CAAC;AAaxD,eAAO,MAAM,eAAe,gHASlB,CAAC;AACX,MAAM,MAAM,YAAY,GAAG,CAAC,OAAO,eAAe,CAAC,CAAC,MAAM,CAAC,CAAC;AAE5D,eAAO,MAAM,oBAAoB,wMAWvB,CAAC;AACX,MAAM,MAAM,iBAAiB,GAAG,CAAC,OAAO,oBAAoB,CAAC,CAAC,MAAM,CAAC,CAAC;AAItE,eAAO,MAAM,WAAW;;;;iBAItB,CAAC;AACH,MAAM,MAAM,KAAK,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,WAAW,CAAC,CAAC;AAEhD,eAAO,MAAM,aAAa;;;iBAGxB,CAAC;AACH,MAAM,MAAM,OAAO,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,aAAa,CAAC,CAAC;AAEpD,mEAAmE;AACnE,eAAO,MAAM,qBAAqB;;;;;;;;;;;iBAIhC,CAAC;AACH,MAAM,MAAM,qBAAqB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,qBAAqB,CAAC,CAAC;AAE1E;;;;GAIG;AACH,eAAO,MAAM,gBAAgB;;;iBAG3B,CAAC;AACH,MAAM,MAAM,gBAAgB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,gBAAgB,CAAC,CAAC;AAIhE,eAAO,MAAM,aAAa;;;;;;;;;;;;;;;;;;;;mCASxB,CAAC;AACH,MAAM,MAAM,aAAa,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,aAAa,CAAC,CAAC;AAI1D;;;;;;;GAOG;AACH,eAAO,MAAM,sBAAsB;;;;;;;;;;;;;;iBAOjC,CAAC;AACH,MAAM,MAAM,sBAAsB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,sBAAsB,CAAC,CAAC;AAI5E;;;;GAIG;AACH,eAAO,MAAM,eAAe,EAAE,MAAM,CAAC,YAAY,EAAE,MAAM,CAGxD,CAAC;AAQF,eAAO,MAAM,oBAAoB,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAWvD,CAAC;AAEF,eAAO,MAAM,eAAe,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CASlD,CAAC"}
@@ -0,0 +1,128 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.DATA_TAG_LABELS = exports.SECURITY_FLAG_LABELS = exports.SCHEMA_VERSIONS = exports.ClaudeAnalysisResponse = exports.TypedAnalysis = exports.SecurityAnalysis = exports.DocumentationAnalysis = exports.ReturnsSchema = exports.ParamSchema = exports.KNOWN_SECURITY_FLAGS = exports.KNOWN_DATA_TAGS = exports.AnalysisType = void 0;
4
+ const zod_1 = require("zod");
5
+ // ============ ANALYSIS TYPE ENUM ============
6
+ exports.AnalysisType = zod_1.z.enum(["documentation", "security"]);
7
+ // ============ KNOWN VALUE SETS ============
8
+ //
9
+ // These are the values we prompt Claude for and have display labels for.
10
+ // They are NOT used for validation — all schemas accept arbitrary strings.
11
+ // This "open with known values" design means:
12
+ // - Claude can return new flags/tags we haven't seen before
13
+ // - Unknown values are stored, synced, and displayed (using the raw string as fallback label)
14
+ // - No data is ever silently dropped due to enum mismatch
15
+ // - New known values are added here + in LABELS maps when we want display names
16
+ // - UI code uses LABELS maps for display, falling back to raw string for unknown values
17
+ exports.KNOWN_DATA_TAGS = [
18
+ "user_input",
19
+ "pii",
20
+ "credentials",
21
+ "database",
22
+ "external_api",
23
+ "file_system",
24
+ "config",
25
+ "internal",
26
+ ];
27
+ exports.KNOWN_SECURITY_FLAGS = [
28
+ "sql_injection",
29
+ "xss",
30
+ "hardcoded_secret",
31
+ "unsanitized_input",
32
+ "path_traversal",
33
+ "prototype_pollution",
34
+ "command_injection",
35
+ "pickle_deserialization",
36
+ "eval_exec",
37
+ "insecure_subprocess",
38
+ ];
39
+ // ============ ANALYSIS PAYLOADS ============
40
+ exports.ParamSchema = zod_1.z.object({
41
+ name: zod_1.z.string(),
42
+ type: zod_1.z.string(),
43
+ description: zod_1.z.string(),
44
+ });
45
+ exports.ReturnsSchema = zod_1.z.object({
46
+ type: zod_1.z.string(),
47
+ description: zod_1.z.string(),
48
+ });
49
+ /** Documentation analysis: description, parameters, return type */
50
+ exports.DocumentationAnalysis = zod_1.z.object({
51
+ description: zod_1.z.string(),
52
+ params: zod_1.z.array(exports.ParamSchema),
53
+ returns: exports.ReturnsSchema,
54
+ });
55
+ /**
56
+ * Security analysis: data flow tags and security vulnerability flags.
57
+ * Both fields use z.string() arrays (not enums) — open with known values.
58
+ * Unknown values from Claude are preserved, not rejected.
59
+ */
60
+ exports.SecurityAnalysis = zod_1.z.object({
61
+ dataTags: zod_1.z.array(zod_1.z.string()),
62
+ securityFlags: zod_1.z.array(zod_1.z.string()),
63
+ });
64
+ // ============ DISCRIMINATED UNION ============
65
+ exports.TypedAnalysis = zod_1.z.discriminatedUnion("analysisType", [
66
+ zod_1.z.object({
67
+ analysisType: zod_1.z.literal("documentation"),
68
+ data: exports.DocumentationAnalysis,
69
+ }),
70
+ zod_1.z.object({
71
+ analysisType: zod_1.z.literal("security"),
72
+ data: exports.SecurityAnalysis,
73
+ }),
74
+ ]);
75
+ // ============ CLAUDE RESPONSE VALIDATOR ============
76
+ /**
77
+ * Validates the raw JSON response from Claude's analysis.
78
+ * The prompt returns a flat object per function with all fields combined.
79
+ * We validate here, then split into separate analysis type rows on storage.
80
+ *
81
+ * Uses .catch() defaults so partial/malformed responses degrade gracefully
82
+ * instead of rejecting entire batches.
83
+ */
84
+ exports.ClaudeAnalysisResponse = zod_1.z.object({
85
+ name: zod_1.z.string(),
86
+ description: zod_1.z.string().catch(""),
87
+ params: zod_1.z.array(exports.ParamSchema).catch([]),
88
+ returns: exports.ReturnsSchema.catch({ type: "unknown", description: "" }),
89
+ dataTags: zod_1.z.array(zod_1.z.string()).catch([]),
90
+ securityFlags: zod_1.z.array(zod_1.z.string()).catch([]),
91
+ });
92
+ // ============ SCHEMA VERSIONS ============
93
+ /**
94
+ * Each analysis type has an independent schema version.
95
+ * Bump when the JSON shape changes. Old rows remain readable.
96
+ * Stored alongside each row for forward-compatibility.
97
+ */
98
+ exports.SCHEMA_VERSIONS = {
99
+ documentation: 1,
100
+ security: 1,
101
+ };
102
+ // ============ DISPLAY LABELS ============
103
+ //
104
+ // Label maps for known values. UI code should use these for display,
105
+ // falling back to the raw string for unknown values:
106
+ // SECURITY_FLAG_LABELS[flag] ?? flag
107
+ exports.SECURITY_FLAG_LABELS = {
108
+ sql_injection: "SQL Injection",
109
+ xss: "XSS",
110
+ hardcoded_secret: "Hardcoded Secret",
111
+ unsanitized_input: "Unsanitized Input",
112
+ path_traversal: "Path Traversal",
113
+ prototype_pollution: "Prototype Pollution",
114
+ command_injection: "Command Injection",
115
+ pickle_deserialization: "Pickle Deserialization",
116
+ eval_exec: "Eval/Exec",
117
+ insecure_subprocess: "Insecure Subprocess",
118
+ };
119
+ exports.DATA_TAG_LABELS = {
120
+ user_input: "User Input",
121
+ pii: "PII",
122
+ credentials: "Credentials",
123
+ database: "Database",
124
+ external_api: "External API",
125
+ file_system: "File System",
126
+ config: "Config",
127
+ internal: "Internal",
128
+ };
@@ -0,0 +1,12 @@
1
+ export interface FunctionInfo {
2
+ name: string;
3
+ filePath: string;
4
+ startLine: number;
5
+ endLine: number;
6
+ sourceCode: string;
7
+ contentHash: string;
8
+ language: string;
9
+ entityType: string;
10
+ }
11
+ export declare function computeHash(str: string): string;
12
+ //# sourceMappingURL=shared.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"shared.d.ts","sourceRoot":"","sources":["../src/shared.ts"],"names":[],"mappings":"AAOA,MAAM,WAAW,YAAY;IAC3B,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,EAAE,MAAM,CAAC;IAClB,OAAO,EAAE,MAAM,CAAC;IAChB,UAAU,EAAE,MAAM,CAAC;IACnB,WAAW,EAAE,MAAM,CAAC;IACpB,QAAQ,EAAE,MAAM,CAAC;IACjB,UAAU,EAAE,MAAM,CAAC;CACpB;AAID,wBAAgB,WAAW,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAE/C"}
package/dist/shared.js ADDED
@@ -0,0 +1,10 @@
1
+ "use strict";
2
+ // Shared types and utilities used by both the parser modules and the main analysis engine.
3
+ // This file exists to avoid circular dependencies between index.ts and parsers/.
4
+ Object.defineProperty(exports, "__esModule", { value: true });
5
+ exports.computeHash = computeHash;
6
+ const crypto_1 = require("crypto");
7
+ // ============ UTILITIES ============
8
+ function computeHash(str) {
9
+ return (0, crypto_1.createHash)("sha256").update(str).digest("hex");
10
+ }
@@ -0,0 +1,46 @@
1
+ import Database from "better-sqlite3";
2
+ /**
3
+ * Creates an in-memory SQLite database with the current ophan schema.
4
+ * Use for merge, import, GC, and findMissingHashes tests.
5
+ */
6
+ export declare function createTestDb(): Database.Database;
7
+ /**
8
+ * Creates an in-memory DB with the OLD (pre-analysis-type) schema.
9
+ * Used to test migrateToAnalysisTypes().
10
+ */
11
+ export declare function createLegacyTestDb(): Database.Database;
12
+ /** Returns JSON string for a documentation analysis payload. */
13
+ export declare function makeDocAnalysisJson(overrides?: Partial<{
14
+ description: string;
15
+ params: {
16
+ name: string;
17
+ type: string;
18
+ description: string;
19
+ }[];
20
+ returns: {
21
+ type: string;
22
+ description: string;
23
+ };
24
+ }>): string;
25
+ /** Returns JSON string for a security analysis payload. */
26
+ export declare function makeSecAnalysisJson(overrides?: Partial<{
27
+ dataTags: string[];
28
+ securityFlags: string[];
29
+ }>): string;
30
+ /** Inserts a matched pair of documentation + security rows for a content_hash. */
31
+ export declare function insertAnalysisPair(db: Database.Database, contentHash: string, options?: {
32
+ language?: string;
33
+ entityType?: string;
34
+ syncedAt?: number | null;
35
+ lastSeenAt?: number;
36
+ createdAt?: number;
37
+ doc?: Parameters<typeof makeDocAnalysisJson>[0];
38
+ sec?: Parameters<typeof makeSecAnalysisJson>[0];
39
+ }): void;
40
+ /** Inserts a file_functions row. */
41
+ export declare function insertFileFunction(db: Database.Database, filePath: string, functionName: string, contentHash: string, options?: {
42
+ mtime?: number;
43
+ language?: string;
44
+ entityType?: string;
45
+ }): void;
46
+ //# sourceMappingURL=test-utils.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"test-utils.d.ts","sourceRoot":"","sources":["../src/test-utils.ts"],"names":[],"mappings":"AAAA,OAAO,QAAQ,MAAM,gBAAgB,CAAC;AAEtC;;;GAGG;AACH,wBAAgB,YAAY,IAAI,QAAQ,CAAC,QAAQ,CAsDhD;AAED;;;GAGG;AACH,wBAAgB,kBAAkB,IAAI,QAAQ,CAAC,QAAQ,CA2CtD;AAED,gEAAgE;AAChE,wBAAgB,mBAAmB,CACjC,SAAS,GAAE,OAAO,CAAC;IACjB,WAAW,EAAE,MAAM,CAAC;IACpB,MAAM,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAC;QAAC,WAAW,EAAE,MAAM,CAAA;KAAE,EAAE,CAAC;IAC9D,OAAO,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,WAAW,EAAE,MAAM,CAAA;KAAE,CAAC;CAChD,CAAM,GACN,MAAM,CAQR;AAED,2DAA2D;AAC3D,wBAAgB,mBAAmB,CACjC,SAAS,GAAE,OAAO,CAAC;IACjB,QAAQ,EAAE,MAAM,EAAE,CAAC;IACnB,aAAa,EAAE,MAAM,EAAE,CAAC;CACzB,CAAM,GACN,MAAM,CAKR;AAED,kFAAkF;AAClF,wBAAgB,kBAAkB,CAChC,EAAE,EAAE,QAAQ,CAAC,QAAQ,EACrB,WAAW,EAAE,MAAM,EACnB,OAAO,GAAE;IACP,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,GAAG,CAAC,EAAE,UAAU,CAAC,OAAO,mBAAmB,CAAC,CAAC,CAAC,CAAC,CAAC;IAChD,GAAG,CAAC,EAAE,UAAU,CAAC,OAAO,mBAAmB,CAAC,CAAC,CAAC,CAAC,CAAC;CAC5C,GACL,IAAI,CAmCN;AAED,oCAAoC;AACpC,wBAAgB,kBAAkB,CAChC,EAAE,EAAE,QAAQ,CAAC,QAAQ,EACrB,QAAQ,EAAE,MAAM,EAChB,YAAY,EAAE,MAAM,EACpB,WAAW,EAAE,MAAM,EACnB,OAAO,GAAE;IACP,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,UAAU,CAAC,EAAE,MAAM,CAAC;CAChB,GACL,IAAI,CAYN"}
@@ -0,0 +1,141 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.createTestDb = createTestDb;
7
+ exports.createLegacyTestDb = createLegacyTestDb;
8
+ exports.makeDocAnalysisJson = makeDocAnalysisJson;
9
+ exports.makeSecAnalysisJson = makeSecAnalysisJson;
10
+ exports.insertAnalysisPair = insertAnalysisPair;
11
+ exports.insertFileFunction = insertFileFunction;
12
+ const better_sqlite3_1 = __importDefault(require("better-sqlite3"));
13
+ /**
14
+ * Creates an in-memory SQLite database with the current ophan schema.
15
+ * Use for merge, import, GC, and findMissingHashes tests.
16
+ */
17
+ function createTestDb() {
18
+ const db = new better_sqlite3_1.default(":memory:");
19
+ db.exec(`
20
+ CREATE TABLE function_analysis (
21
+ content_hash TEXT NOT NULL,
22
+ analysis_type TEXT NOT NULL,
23
+ analysis JSON NOT NULL,
24
+ model_version TEXT NOT NULL,
25
+ schema_version INTEGER NOT NULL DEFAULT 1,
26
+ created_at INTEGER NOT NULL,
27
+ last_seen_at INTEGER NOT NULL,
28
+ language TEXT NOT NULL DEFAULT 'typescript',
29
+ entity_type TEXT NOT NULL DEFAULT 'function',
30
+ synced_at INTEGER,
31
+ PRIMARY KEY (content_hash, analysis_type)
32
+ )
33
+ `);
34
+ db.exec(`
35
+ CREATE TABLE file_functions (
36
+ file_path TEXT NOT NULL,
37
+ function_name TEXT NOT NULL,
38
+ content_hash TEXT NOT NULL,
39
+ file_mtime INTEGER NOT NULL,
40
+ language TEXT NOT NULL DEFAULT 'typescript',
41
+ entity_type TEXT NOT NULL DEFAULT 'function'
42
+ )
43
+ `);
44
+ db.exec(`
45
+ CREATE TABLE function_gc (
46
+ content_hash TEXT NOT NULL,
47
+ analysis_type TEXT,
48
+ gc_at INTEGER NOT NULL,
49
+ synced_at INTEGER
50
+ )
51
+ `);
52
+ db.exec(`
53
+ CREATE TABLE sync_meta (
54
+ key TEXT PRIMARY KEY,
55
+ value TEXT NOT NULL
56
+ )
57
+ `);
58
+ db.exec("CREATE INDEX idx_file_functions_path ON file_functions(file_path)");
59
+ db.exec("CREATE INDEX idx_file_functions_hash ON file_functions(content_hash)");
60
+ return db;
61
+ }
62
+ /**
63
+ * Creates an in-memory DB with the OLD (pre-analysis-type) schema.
64
+ * Used to test migrateToAnalysisTypes().
65
+ */
66
+ function createLegacyTestDb() {
67
+ const db = new better_sqlite3_1.default(":memory:");
68
+ db.exec(`
69
+ CREATE TABLE function_analysis (
70
+ content_hash TEXT PRIMARY KEY,
71
+ analysis JSON NOT NULL,
72
+ model_version TEXT NOT NULL,
73
+ created_at INTEGER NOT NULL,
74
+ last_seen_at INTEGER NOT NULL,
75
+ language TEXT,
76
+ entity_type TEXT,
77
+ synced_at INTEGER
78
+ )
79
+ `);
80
+ db.exec(`
81
+ CREATE TABLE file_functions (
82
+ file_path TEXT NOT NULL,
83
+ function_name TEXT NOT NULL,
84
+ content_hash TEXT NOT NULL,
85
+ file_mtime INTEGER NOT NULL,
86
+ language TEXT NOT NULL DEFAULT 'typescript',
87
+ entity_type TEXT NOT NULL DEFAULT 'function'
88
+ )
89
+ `);
90
+ db.exec(`
91
+ CREATE TABLE function_gc (
92
+ content_hash TEXT NOT NULL,
93
+ gc_at INTEGER NOT NULL,
94
+ synced_at INTEGER
95
+ )
96
+ `);
97
+ db.exec(`
98
+ CREATE TABLE sync_meta (
99
+ key TEXT PRIMARY KEY,
100
+ value TEXT NOT NULL
101
+ )
102
+ `);
103
+ return db;
104
+ }
105
+ /** Returns JSON string for a documentation analysis payload. */
106
+ function makeDocAnalysisJson(overrides = {}) {
107
+ return JSON.stringify({
108
+ description: overrides.description ?? "Test function description",
109
+ params: overrides.params ?? [
110
+ { name: "x", type: "number", description: "input" },
111
+ ],
112
+ returns: overrides.returns ?? { type: "number", description: "output" },
113
+ });
114
+ }
115
+ /** Returns JSON string for a security analysis payload. */
116
+ function makeSecAnalysisJson(overrides = {}) {
117
+ return JSON.stringify({
118
+ dataTags: overrides.dataTags ?? ["internal"],
119
+ securityFlags: overrides.securityFlags ?? [],
120
+ });
121
+ }
122
+ /** Inserts a matched pair of documentation + security rows for a content_hash. */
123
+ function insertAnalysisPair(db, contentHash, options = {}) {
124
+ const now = Math.floor(Date.now() / 1000);
125
+ const language = options.language ?? "typescript";
126
+ const entityType = options.entityType ?? "function";
127
+ const createdAt = options.createdAt ?? now;
128
+ const lastSeenAt = options.lastSeenAt ?? now;
129
+ const syncedAt = options.syncedAt ?? null;
130
+ db.prepare(`INSERT INTO function_analysis
131
+ (content_hash, analysis_type, analysis, model_version, schema_version, created_at, last_seen_at, language, entity_type, synced_at)
132
+ VALUES (?, 'documentation', ?, 'test-model', 1, ?, ?, ?, ?, ?)`).run(contentHash, makeDocAnalysisJson(options.doc), createdAt, lastSeenAt, language, entityType, syncedAt);
133
+ db.prepare(`INSERT INTO function_analysis
134
+ (content_hash, analysis_type, analysis, model_version, schema_version, created_at, last_seen_at, language, entity_type, synced_at)
135
+ VALUES (?, 'security', ?, 'test-model', 1, ?, ?, ?, ?, ?)`).run(contentHash, makeSecAnalysisJson(options.sec), createdAt, lastSeenAt, language, entityType, syncedAt);
136
+ }
137
+ /** Inserts a file_functions row. */
138
+ function insertFileFunction(db, filePath, functionName, contentHash, options = {}) {
139
+ db.prepare(`INSERT INTO file_functions (file_path, function_name, content_hash, file_mtime, language, entity_type)
140
+ VALUES (?, ?, ?, ?, ?, ?)`).run(filePath, functionName, contentHash, options.mtime ?? Date.now(), options.language ?? "typescript", options.entityType ?? "function");
141
+ }
package/package.json ADDED
@@ -0,0 +1,37 @@
1
+ {
2
+ "name": "@ophan/core",
3
+ "version": "0.0.1",
4
+ "main": "./src/index.ts",
5
+ "types": "./src/index.ts",
6
+ "exports": {
7
+ ".": "./src/index.ts",
8
+ "./schemas": "./src/schemas.ts",
9
+ "./test-utils": "./src/test-utils.ts"
10
+ },
11
+ "files": ["dist"],
12
+ "publishConfig": {
13
+ "main": "./dist/index.js",
14
+ "types": "./dist/index.d.ts",
15
+ "exports": {
16
+ ".": "./dist/index.js",
17
+ "./schemas": "./dist/schemas.js"
18
+ }
19
+ },
20
+ "scripts": {
21
+ "build": "tsc",
22
+ "test": "vitest run"
23
+ },
24
+ "dependencies": {
25
+ "@anthropic-ai/sdk": "^0.71.2",
26
+ "better-sqlite3": "^12.5.0",
27
+ "glob": "^13.0.0",
28
+ "p-retry": "^7.1.1",
29
+ "typescript": "^5.9.3",
30
+ "zod": "^4.3.6"
31
+ },
32
+ "devDependencies": {
33
+ "@types/better-sqlite3": "^7.6.13",
34
+ "@types/node": "^25.0.3",
35
+ "vitest": "^3.0.5"
36
+ }
37
+ }