@monoes/monograph 1.6.11 → 1.6.13

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 (88) hide show
  1. package/dist/src/analysis/changed-files.d.ts.map +1 -1
  2. package/dist/src/analysis/changed-files.js +1 -0
  3. package/dist/src/analysis/changed-files.js.map +1 -1
  4. package/dist/src/analysis/churn.d.ts.map +1 -1
  5. package/dist/src/analysis/churn.js +4 -1
  6. package/dist/src/analysis/churn.js.map +1 -1
  7. package/dist/src/analysis/git-changed-files.d.ts.map +1 -1
  8. package/dist/src/analysis/git-changed-files.js +10 -2
  9. package/dist/src/analysis/git-changed-files.js.map +1 -1
  10. package/dist/src/graph/hotspots.js +1 -1
  11. package/dist/src/graph/hotspots.js.map +1 -1
  12. package/dist/src/pipeline/build-lock.d.ts.map +1 -1
  13. package/dist/src/pipeline/build-lock.js +29 -3
  14. package/dist/src/pipeline/build-lock.js.map +1 -1
  15. package/dist/src/pipeline/orchestrator.d.ts.map +1 -1
  16. package/dist/src/pipeline/orchestrator.js +6 -1
  17. package/dist/src/pipeline/orchestrator.js.map +1 -1
  18. package/dist/src/pipeline/phases/orm-helpers.d.ts +11 -0
  19. package/dist/src/pipeline/phases/orm-helpers.d.ts.map +1 -0
  20. package/dist/src/pipeline/phases/orm-helpers.js +72 -0
  21. package/dist/src/pipeline/phases/orm-helpers.js.map +1 -0
  22. package/dist/src/pipeline/phases/orm-mongoose.d.ts +8 -0
  23. package/dist/src/pipeline/phases/orm-mongoose.d.ts.map +1 -0
  24. package/dist/src/pipeline/phases/orm-mongoose.js +51 -0
  25. package/dist/src/pipeline/phases/orm-mongoose.js.map +1 -0
  26. package/dist/src/pipeline/phases/orm-prisma.d.ts +8 -0
  27. package/dist/src/pipeline/phases/orm-prisma.d.ts.map +1 -0
  28. package/dist/src/pipeline/phases/orm-prisma.js +41 -0
  29. package/dist/src/pipeline/phases/orm-prisma.js.map +1 -0
  30. package/dist/src/pipeline/phases/orm-sequelize.d.ts +12 -0
  31. package/dist/src/pipeline/phases/orm-sequelize.d.ts.map +1 -0
  32. package/dist/src/pipeline/phases/orm-sequelize.js +97 -0
  33. package/dist/src/pipeline/phases/orm-sequelize.js.map +1 -0
  34. package/dist/src/pipeline/phases/orm-sqlalchemy.d.ts +8 -0
  35. package/dist/src/pipeline/phases/orm-sqlalchemy.d.ts.map +1 -0
  36. package/dist/src/pipeline/phases/orm-sqlalchemy.js +42 -0
  37. package/dist/src/pipeline/phases/orm-sqlalchemy.js.map +1 -0
  38. package/dist/src/pipeline/phases/orm-typeorm.d.ts +10 -0
  39. package/dist/src/pipeline/phases/orm-typeorm.d.ts.map +1 -0
  40. package/dist/src/pipeline/phases/orm-typeorm.js +52 -0
  41. package/dist/src/pipeline/phases/orm-typeorm.js.map +1 -0
  42. package/dist/src/pipeline/phases/orm.d.ts.map +1 -1
  43. package/dist/src/pipeline/phases/orm.js +6 -336
  44. package/dist/src/pipeline/phases/orm.js.map +1 -1
  45. package/dist/src/pipeline/phases/scope-resolution-edges.d.ts +9 -0
  46. package/dist/src/pipeline/phases/scope-resolution-edges.d.ts.map +1 -0
  47. package/dist/src/pipeline/phases/scope-resolution-edges.js +30 -0
  48. package/dist/src/pipeline/phases/scope-resolution-edges.js.map +1 -0
  49. package/dist/src/pipeline/phases/scope-resolution-function-index.d.ts +31 -0
  50. package/dist/src/pipeline/phases/scope-resolution-function-index.d.ts.map +1 -0
  51. package/dist/src/pipeline/phases/scope-resolution-function-index.js +96 -0
  52. package/dist/src/pipeline/phases/scope-resolution-function-index.js.map +1 -0
  53. package/dist/src/pipeline/phases/scope-resolution-target.d.ts +6 -0
  54. package/dist/src/pipeline/phases/scope-resolution-target.d.ts.map +1 -0
  55. package/dist/src/pipeline/phases/scope-resolution-target.js +69 -0
  56. package/dist/src/pipeline/phases/scope-resolution-target.js.map +1 -0
  57. package/dist/src/pipeline/phases/scope-resolution.d.ts.map +1 -1
  58. package/dist/src/pipeline/phases/scope-resolution.js +3 -189
  59. package/dist/src/pipeline/phases/scope-resolution.js.map +1 -1
  60. package/dist/src/staleness/git-staleness.d.ts.map +1 -1
  61. package/dist/src/staleness/git-staleness.js +7 -1
  62. package/dist/src/staleness/git-staleness.js.map +1 -1
  63. package/dist/src/storage/fts-store-hybrid.d.ts +17 -0
  64. package/dist/src/storage/fts-store-hybrid.d.ts.map +1 -0
  65. package/dist/src/storage/fts-store-hybrid.js +119 -0
  66. package/dist/src/storage/fts-store-hybrid.js.map +1 -0
  67. package/dist/src/storage/fts-store-search.d.ts +29 -0
  68. package/dist/src/storage/fts-store-search.d.ts.map +1 -0
  69. package/dist/src/storage/fts-store-search.js +177 -0
  70. package/dist/src/storage/fts-store-search.js.map +1 -0
  71. package/dist/src/storage/fts-store-terms.d.ts +8 -0
  72. package/dist/src/storage/fts-store-terms.d.ts.map +1 -0
  73. package/dist/src/storage/fts-store-terms.js +174 -0
  74. package/dist/src/storage/fts-store-terms.js.map +1 -0
  75. package/dist/src/storage/fts-store.d.ts +12 -46
  76. package/dist/src/storage/fts-store.d.ts.map +1 -1
  77. package/dist/src/storage/fts-store.js +11 -459
  78. package/dist/src/storage/fts-store.js.map +1 -1
  79. package/dist/src/web/api-queries.d.ts +89 -0
  80. package/dist/src/web/api-queries.d.ts.map +1 -0
  81. package/dist/src/web/api-queries.js +245 -0
  82. package/dist/src/web/api-queries.js.map +1 -0
  83. package/dist/src/web/api.d.ts +2 -87
  84. package/dist/src/web/api.d.ts.map +1 -1
  85. package/dist/src/web/api.js +3 -244
  86. package/dist/src/web/api.js.map +1 -1
  87. package/dist/tsconfig.tsbuildinfo +1 -1
  88. package/package.json +1 -1
@@ -0,0 +1 @@
1
+ {"version":3,"file":"orm-sequelize.d.ts","sourceRoot":"","sources":["../../../../src/pipeline/phases/orm-sequelize.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,aAAa,EAAE,MAAM,gBAAgB,CAAC;AAEnE,OAAO,KAAK,EAAE,SAAS,EAAY,MAAM,UAAU,CAAC;AAKpD,kEAAkE;AAClE,eAAO,MAAM,kBAAkB,QAAiD,CAAC;AAEjF,wFAAwF;AACxF,eAAO,MAAM,iBAAiB,QAA2B,CAAC;AAE1D,uDAAuD;AACvD,eAAO,MAAM,mBAAmB,QAA4C,CAAC;AAE7E,2GAA2G;AAC3G,eAAO,MAAM,kBAAkB,QACmD,CAAC;AAEnF,wBAAgB,uBAAuB,CACrC,MAAM,EAAE,MAAM,EACd,QAAQ,EAAE,MAAM,EAChB,QAAQ,EAAE,MAAM,EAChB,QAAQ,EAAE,SAAS,EAAE,EACrB,WAAW,EAAE,aAAa,EAAE,EAC5B,UAAU,EAAE,aAAa,EAAE,EAC3B,KAAK,EAAE,aAAa,EAAE,GACrB,IAAI,CAkHN"}
@@ -0,0 +1,97 @@
1
+ import { makeId, toNormLabel } from '../../types.js';
2
+ import { addField, extractBraceBlock } from './orm-helpers.js';
3
+ // Split out of orm.ts (file-size sweep). Pure move: no behaviour change.
4
+ /** Sequelize: class Foo extends Model (or extends Model.Model) */
5
+ export const SEQUELIZE_CLASS_RE = /class\s+(\w+)\s+extends\s+(?:\w+\.)?Model\b/g;
6
+ /** Sequelize Model.init({ field: ... }, { sequelize }) — capture the first arg block */
7
+ export const SEQUELIZE_INIT_RE = /(\w+)\.init\s*\(\s*\{/g;
8
+ /** Sequelize sequelize.define('ModelName', { ... }) */
9
+ export const SEQUELIZE_DEFINE_RE = /\.define\s*\(\s*['"](\w+)['"]\s*,\s*\{/g;
10
+ /** Sequelize field inside init/define block: fieldName: DataTypes.X or fieldName: { type: DataTypes.X } */
11
+ export const SEQUELIZE_FIELD_RE = /(\w+)\s*:\s*(?:\{[^}]*type\s*:\s*(?:DataTypes\.)?(\w+)|(?:DataTypes\.)?(\w+))/g;
12
+ export function detectSequelizeEntities(source, filePath, language, entities, entityNodes, fieldNodes, edges) {
13
+ // Track entity names we've already registered to avoid duplicates.
14
+ const registeredNames = new Set();
15
+ function registerEntity(entityName) {
16
+ const entityNodeId = makeId('entity', entityName + filePath);
17
+ if (registeredNames.has(entityName))
18
+ return entityNodeId;
19
+ registeredNames.add(entityName);
20
+ const entityNode = {
21
+ id: entityNodeId,
22
+ label: 'Entity',
23
+ name: entityName,
24
+ normLabel: toNormLabel(entityName),
25
+ filePath,
26
+ startLine: 0,
27
+ endLine: 0,
28
+ isExported: true,
29
+ language,
30
+ };
31
+ entityNodes.push(entityNode);
32
+ return entityNodeId;
33
+ }
34
+ // Collect class names that extend Model so we can match them in .init() calls.
35
+ const modelClasses = new Set();
36
+ const classRe = new RegExp(SEQUELIZE_CLASS_RE.source, 'g');
37
+ let cm;
38
+ while ((cm = classRe.exec(source)) !== null) {
39
+ modelClasses.add(cm[1]);
40
+ }
41
+ // Handle: ClassName.init({ ... }, { sequelize })
42
+ const initRe = new RegExp(SEQUELIZE_INIT_RE.source, 'g');
43
+ let im;
44
+ while ((im = initRe.exec(source)) !== null) {
45
+ const candidateName = im[1];
46
+ // Only treat as Sequelize if it's a known Model subclass OR if DataTypes appears in the block.
47
+ const blockStart = im.index + im[0].length - 1; // position of the opening '{'
48
+ const block = extractBraceBlock(source, blockStart, 4000);
49
+ if (!block)
50
+ continue;
51
+ if (!modelClasses.has(candidateName) && !block.includes('DataTypes'))
52
+ continue;
53
+ const entityNodeId = registerEntity(candidateName);
54
+ const fields = [];
55
+ const fieldRe = new RegExp(SEQUELIZE_FIELD_RE.source, 'g');
56
+ let fm;
57
+ const seen = new Set();
58
+ while ((fm = fieldRe.exec(block)) !== null) {
59
+ const fieldName = fm[1];
60
+ const fieldType = fm[2] ?? fm[3] ?? 'DataType';
61
+ if (seen.has(fieldName))
62
+ continue;
63
+ if (['type', 'allowNull', 'defaultValue', 'primaryKey', 'unique', 'references'].includes(fieldName))
64
+ continue;
65
+ seen.add(fieldName);
66
+ addField(candidateName, fieldName, fieldType, filePath, language, entityNodeId, fields, fieldNodes, edges);
67
+ }
68
+ entities.push({ name: candidateName, filePath, fields, entityNodeId });
69
+ }
70
+ // Handle: sequelize.define('ModelName', { ... })
71
+ const defineRe = new RegExp(SEQUELIZE_DEFINE_RE.source, 'g');
72
+ let dm;
73
+ while ((dm = defineRe.exec(source)) !== null) {
74
+ const entityName = dm[1];
75
+ const blockStart = dm.index + dm[0].length - 1;
76
+ const block = extractBraceBlock(source, blockStart, 4000);
77
+ const entityNodeId = registerEntity(entityName);
78
+ const fields = [];
79
+ if (block) {
80
+ const fieldRe = new RegExp(SEQUELIZE_FIELD_RE.source, 'g');
81
+ let fm;
82
+ const seen = new Set();
83
+ while ((fm = fieldRe.exec(block)) !== null) {
84
+ const fieldName = fm[1];
85
+ const fieldType = fm[2] ?? fm[3] ?? 'DataType';
86
+ if (seen.has(fieldName))
87
+ continue;
88
+ if (['type', 'allowNull', 'defaultValue', 'primaryKey', 'unique', 'references'].includes(fieldName))
89
+ continue;
90
+ seen.add(fieldName);
91
+ addField(entityName, fieldName, fieldType, filePath, language, entityNodeId, fields, fieldNodes, edges);
92
+ }
93
+ }
94
+ entities.push({ name: entityName, filePath, fields, entityNodeId });
95
+ }
96
+ }
97
+ //# sourceMappingURL=orm-sequelize.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"orm-sequelize.js","sourceRoot":"","sources":["../../../../src/pipeline/phases/orm-sequelize.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,8 @@
1
+ import type { MonographEdge, MonographNode } from '../../types.js';
2
+ import type { EntityDef } from './orm.js';
3
+ /** SQLAlchemy: class Foo(Base) or class Foo(db.Model) etc. */
4
+ export declare const SQLALCHEMY_CLASS_RE: RegExp;
5
+ /** SQLAlchemy column: fieldName = Column( */
6
+ export declare const SQLALCHEMY_COLUMN_RE: RegExp;
7
+ export declare function detectSQLAlchemyEntities(source: string, filePath: string, language: string, entities: EntityDef[], entityNodes: MonographNode[], fieldNodes: MonographNode[], edges: MonographEdge[]): void;
8
+ //# sourceMappingURL=orm-sqlalchemy.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"orm-sqlalchemy.d.ts","sourceRoot":"","sources":["../../../../src/pipeline/phases/orm-sqlalchemy.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,aAAa,EAAE,MAAM,gBAAgB,CAAC;AAEnE,OAAO,KAAK,EAAE,SAAS,EAAY,MAAM,UAAU,CAAC;AAKpD,8DAA8D;AAC9D,eAAO,MAAM,mBAAmB,QAAwC,CAAC;AAEzE,6CAA6C;AAC7C,eAAO,MAAM,oBAAoB,QAAiD,CAAC;AAEnF,wBAAgB,wBAAwB,CACtC,MAAM,EAAE,MAAM,EACd,QAAQ,EAAE,MAAM,EAChB,QAAQ,EAAE,MAAM,EAChB,QAAQ,EAAE,SAAS,EAAE,EACrB,WAAW,EAAE,aAAa,EAAE,EAC5B,UAAU,EAAE,aAAa,EAAE,EAC3B,KAAK,EAAE,aAAa,EAAE,GACrB,IAAI,CAgDN"}
@@ -0,0 +1,42 @@
1
+ import { makeId, toNormLabel } from '../../types.js';
2
+ import { addField } from './orm-helpers.js';
3
+ // Split out of orm.ts (file-size sweep). Pure move: no behaviour change.
4
+ /** SQLAlchemy: class Foo(Base) or class Foo(db.Model) etc. */
5
+ export const SQLALCHEMY_CLASS_RE = /class\s+(\w+)\s*\([^)]*Base[^)]*\)/g;
6
+ /** SQLAlchemy column: fieldName = Column( */
7
+ export const SQLALCHEMY_COLUMN_RE = /(\w+)\s*(?::\s*[\w[\]]+)?\s*=\s*Column\s*\(/g;
8
+ export function detectSQLAlchemyEntities(source, filePath, language, entities, entityNodes, fieldNodes, edges) {
9
+ const classRe = new RegExp(SQLALCHEMY_CLASS_RE.source, 'g');
10
+ let m;
11
+ while ((m = classRe.exec(source)) !== null) {
12
+ const entityName = m[1];
13
+ const entityNodeId = makeId('entity', entityName + filePath);
14
+ const entityNode = {
15
+ id: entityNodeId,
16
+ label: 'Entity',
17
+ name: entityName,
18
+ normLabel: toNormLabel(entityName),
19
+ filePath,
20
+ startLine: 0,
21
+ endLine: 0,
22
+ isExported: true,
23
+ language,
24
+ };
25
+ entityNodes.push(entityNode);
26
+ const fields = [];
27
+ // Scope column scan to this class's body — slice from the match end to the next
28
+ // unindented `class ` keyword or end-of-string to avoid assigning columns from
29
+ // other classes to this entity.
30
+ const classBodyStart = m.index + m[0].length;
31
+ const nextClassIdx = source.indexOf('\nclass ', classBodyStart);
32
+ const classBody = nextClassIdx >= 0 ? source.slice(classBodyStart, nextClassIdx) : source.slice(classBodyStart);
33
+ const columnRe = new RegExp(SQLALCHEMY_COLUMN_RE.source, 'g');
34
+ let cm;
35
+ while ((cm = columnRe.exec(classBody)) !== null) {
36
+ const fieldName = cm[1];
37
+ addField(entityName, fieldName, 'Column', filePath, language, entityNodeId, fields, fieldNodes, edges);
38
+ }
39
+ entities.push({ name: entityName, filePath, fields, entityNodeId });
40
+ }
41
+ }
42
+ //# sourceMappingURL=orm-sqlalchemy.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"orm-sqlalchemy.js","sourceRoot":"","sources":["../../../../src/pipeline/phases/orm-sqlalchemy.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAC;AAErD,OAAO,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAE5C,yEAAyE;AAEzE,8DAA8D;AAC9D,MAAM,CAAC,MAAM,mBAAmB,GAAG,qCAAqC,CAAC;AAEzE,6CAA6C;AAC7C,MAAM,CAAC,MAAM,oBAAoB,GAAG,8CAA8C,CAAC;AAEnF,MAAM,UAAU,wBAAwB,CACtC,MAAc,EACd,QAAgB,EAChB,QAAgB,EAChB,QAAqB,EACrB,WAA4B,EAC5B,UAA2B,EAC3B,KAAsB;IAEtB,MAAM,OAAO,GAAG,IAAI,MAAM,CAAC,mBAAmB,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;IAC5D,IAAI,CAAyB,CAAC;IAE9B,OAAO,CAAC,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,KAAK,IAAI,EAAE,CAAC;QAC3C,MAAM,UAAU,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC;QACxB,MAAM,YAAY,GAAG,MAAM,CAAC,QAAQ,EAAE,UAAU,GAAG,QAAQ,CAAC,CAAC;QAE7D,MAAM,UAAU,GAAkB;YAChC,EAAE,EAAE,YAAY;YAChB,KAAK,EAAE,QAAQ;YACf,IAAI,EAAE,UAAU;YAChB,SAAS,EAAE,WAAW,CAAC,UAAU,CAAC;YAClC,QAAQ;YACR,SAAS,EAAE,CAAC;YACZ,OAAO,EAAE,CAAC;YACV,UAAU,EAAE,IAAI;YAChB,QAAQ;SACT,CAAC;QACF,WAAW,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;QAE7B,MAAM,MAAM,GAAe,EAAE,CAAC;QAC9B,gFAAgF;QAChF,+EAA+E;QAC/E,gCAAgC;QAChC,MAAM,cAAc,GAAG,CAAC,CAAC,KAAK,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC;QAC7C,MAAM,YAAY,GAAG,MAAM,CAAC,OAAO,CAAC,UAAU,EAAE,cAAc,CAAC,CAAC;QAChE,MAAM,SAAS,GACb,YAAY,IAAI,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,cAAc,EAAE,YAAY,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,cAAc,CAAC,CAAC;QAChG,MAAM,QAAQ,GAAG,IAAI,MAAM,CAAC,oBAAoB,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;QAC9D,IAAI,EAA0B,CAAC;QAC/B,OAAO,CAAC,EAAE,GAAG,QAAQ,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC,KAAK,IAAI,EAAE,CAAC;YAChD,MAAM,SAAS,GAAG,EAAE,CAAC,CAAC,CAAC,CAAC;YACxB,QAAQ,CACN,UAAU,EACV,SAAS,EACT,QAAQ,EACR,QAAQ,EACR,QAAQ,EACR,YAAY,EACZ,MAAM,EACN,UAAU,EACV,KAAK,CACN,CAAC;QACJ,CAAC;QAED,QAAQ,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,UAAU,EAAE,QAAQ,EAAE,MAAM,EAAE,YAAY,EAAE,CAAC,CAAC;IACtE,CAAC;AACH,CAAC"}
@@ -0,0 +1,10 @@
1
+ import type { MonographEdge, MonographNode } from '../../types.js';
2
+ import type { EntityDef } from './orm.js';
3
+ /** TypeORM: @Entity() decorator before a class */
4
+ export declare const TYPEORM_ENTITY_RE: RegExp;
5
+ /** TypeORM/MikroORM column decorator (matches the decorator line only) */
6
+ export declare const TYPEORM_COLUMN_DECORATOR_RE: RegExp;
7
+ /** Property declaration after a TypeORM column decorator */
8
+ export declare const TYPEORM_PROP_RE: RegExp;
9
+ export declare function detectTypeOrmEntities(source: string, filePath: string, language: string, entities: EntityDef[], entityNodes: MonographNode[], fieldNodes: MonographNode[], edges: MonographEdge[]): void;
10
+ //# sourceMappingURL=orm-typeorm.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"orm-typeorm.d.ts","sourceRoot":"","sources":["../../../../src/pipeline/phases/orm-typeorm.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,aAAa,EAAE,MAAM,gBAAgB,CAAC;AAEnE,OAAO,KAAK,EAAE,SAAS,EAAY,MAAM,UAAU,CAAC;AAKpD,kDAAkD;AAClD,eAAO,MAAM,iBAAiB,QACwC,CAAC;AAEvE,0EAA0E;AAC1E,eAAO,MAAM,2BAA2B,QAC+H,CAAC;AAExK,4DAA4D;AAC5D,eAAO,MAAM,eAAe,QAA8B,CAAC;AAE3D,wBAAgB,qBAAqB,CACnC,MAAM,EAAE,MAAM,EACd,QAAQ,EAAE,MAAM,EAChB,QAAQ,EAAE,MAAM,EAChB,QAAQ,EAAE,SAAS,EAAE,EACrB,WAAW,EAAE,aAAa,EAAE,EAC5B,UAAU,EAAE,aAAa,EAAE,EAC3B,KAAK,EAAE,aAAa,EAAE,GACrB,IAAI,CAsDN"}
@@ -0,0 +1,52 @@
1
+ import { makeId, toNormLabel } from '../../types.js';
2
+ import { addField } from './orm-helpers.js';
3
+ // Split out of orm.ts (file-size sweep). Pure move: no behaviour change.
4
+ /** TypeORM: @Entity() decorator before a class */
5
+ export const TYPEORM_ENTITY_RE = /@Entity\s*\([^)]*\)\s*(?:export\s+)?(?:abstract\s+)?class\s+(\w+)/g;
6
+ /** TypeORM/MikroORM column decorator (matches the decorator line only) */
7
+ export const TYPEORM_COLUMN_DECORATOR_RE = /@(?:Primary(?:Generated)?Column|Column|CreateDateColumn|UpdateDateColumn|DeleteDateColumn|Property|PrimaryKey|ManyToOne|OneToMany|ManyToMany|OneToOne)\s*\([^)]*\)/g;
8
+ /** Property declaration after a TypeORM column decorator */
9
+ export const TYPEORM_PROP_RE = /(\w+)\s*[!?]?\s*:\s*(\w+)/;
10
+ export function detectTypeOrmEntities(source, filePath, language, entities, entityNodes, fieldNodes, edges) {
11
+ const entityRe = new RegExp(TYPEORM_ENTITY_RE.source, 'g');
12
+ const lines = source.split('\n');
13
+ let m;
14
+ while ((m = entityRe.exec(source)) !== null) {
15
+ const entityName = m[1];
16
+ const entityNodeId = makeId('entity', entityName + filePath);
17
+ const entityNode = {
18
+ id: entityNodeId,
19
+ label: 'Entity',
20
+ name: entityName,
21
+ normLabel: toNormLabel(entityName),
22
+ filePath,
23
+ startLine: 0,
24
+ endLine: 0,
25
+ isExported: true,
26
+ language,
27
+ };
28
+ entityNodes.push(entityNode);
29
+ const fields = [];
30
+ const colDecRe = new RegExp(TYPEORM_COLUMN_DECORATOR_RE.source, 'g');
31
+ for (let i = 0; i < lines.length; i++) {
32
+ const line = lines[i];
33
+ if (colDecRe.test(line)) {
34
+ colDecRe.lastIndex = 0; // reset after test
35
+ // Look at the next non-empty line for the property declaration
36
+ for (let j = i + 1; j < Math.min(i + 4, lines.length); j++) {
37
+ const propLine = lines[j].trim();
38
+ if (!propLine || propLine.startsWith('@') || propLine.startsWith('//'))
39
+ continue;
40
+ const pm = TYPEORM_PROP_RE.exec(propLine);
41
+ if (pm) {
42
+ addField(entityName, pm[1], pm[2], filePath, language, entityNodeId, fields, fieldNodes, edges);
43
+ }
44
+ break;
45
+ }
46
+ }
47
+ colDecRe.lastIndex = 0; // always reset
48
+ }
49
+ entities.push({ name: entityName, filePath, fields, entityNodeId });
50
+ }
51
+ }
52
+ //# sourceMappingURL=orm-typeorm.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"orm-typeorm.js","sourceRoot":"","sources":["../../../../src/pipeline/phases/orm-typeorm.ts"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"orm.d.ts","sourceRoot":"","sources":["../../../../src/pipeline/phases/orm.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAKjD,MAAM,WAAW,QAAQ;IACvB,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;CACrB;AAED,MAAM,WAAW,SAAS;IACxB,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,EAAE,QAAQ,EAAE,CAAC;IACnB,YAAY,EAAE,MAAM,CAAC;CACtB;AAED,MAAM,WAAW,SAAS;IACxB,QAAQ,EAAE,SAAS,EAAE,CAAC;CACvB;AAoDD,eAAO,MAAM,QAAQ,EAAE,aAAa,CAAC,SAAS,CAwF7C,CAAC"}
1
+ {"version":3,"file":"orm.d.ts","sourceRoot":"","sources":["../../../../src/pipeline/phases/orm.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAWjD,MAAM,WAAW,QAAQ;IACvB,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;CACrB;AAED,MAAM,WAAW,SAAS;IACxB,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,EAAE,QAAQ,EAAE,CAAC;IACnB,YAAY,EAAE,MAAM,CAAC;CACtB;AAED,MAAM,WAAW,SAAS;IACxB,QAAQ,EAAE,SAAS,EAAE,CAAC;CACvB;AAQD,eAAO,MAAM,QAAQ,EAAE,aAAa,CAAC,SAAS,CAwF7C,CAAC"}
@@ -1,37 +1,14 @@
1
- import { readFileSync, statSync } from 'node:fs';
2
1
  import { basename, extname } from 'node:path';
3
2
  import { insertEdges } from '../../storage/edge-store.js';
4
3
  import { insertNodes } from '../../storage/node-store.js';
5
- import { makeId, toNormLabel } from '../../types.js';
4
+ import { langFromExt, safeReadSource } from './orm-helpers.js';
5
+ import { detectMongooseEntities } from './orm-mongoose.js';
6
+ import { detectPrismaEntities } from './orm-prisma.js';
7
+ import { detectSequelizeEntities } from './orm-sequelize.js';
8
+ import { detectSQLAlchemyEntities } from './orm-sqlalchemy.js';
9
+ import { detectTypeOrmEntities } from './orm-typeorm.js';
6
10
  // ── Supported code extensions ─────────────────────────────────────────────────
7
11
  const TS_JS_EXTENSIONS = new Set(['.ts', '.tsx', '.js', '.jsx', '.mjs', '.cjs']);
8
- // ── Regex patterns ────────────────────────────────────────────────────────────
9
- /** TypeORM: @Entity() decorator before a class */
10
- const TYPEORM_ENTITY_RE = /@Entity\s*\([^)]*\)\s*(?:export\s+)?(?:abstract\s+)?class\s+(\w+)/g;
11
- /** TypeORM/MikroORM column decorator (matches the decorator line only) */
12
- const TYPEORM_COLUMN_DECORATOR_RE = /@(?:Primary(?:Generated)?Column|Column|CreateDateColumn|UpdateDateColumn|DeleteDateColumn|Property|PrimaryKey|ManyToOne|OneToMany|ManyToMany|OneToOne)\s*\([^)]*\)/g;
13
- /** Property declaration after a TypeORM column decorator */
14
- const TYPEORM_PROP_RE = /(\w+)\s*[!?]?\s*:\s*(\w+)/;
15
- /** Prisma model block: model Name { ... } */
16
- const PRISMA_MODEL_RE = /^model\s+(\w+)\s*\{([^}]+)\}/gm;
17
- /** Prisma field line inside a model block */
18
- const PRISMA_FIELD_RE = /^\s+(\w+)\s+(\w+)/gm;
19
- /** Mongoose: const XxxSchema = new Schema({ */
20
- const MONGOOSE_SCHEMA_RE = /(?:const|let|var)\s+(\w*[Ss]chema)\s*=\s*new\s+(?:\w+\.)?Schema\s*\(\s*\{/g;
21
- /** Mongoose field inside a Schema object: fieldName: { type: SomeType } or fieldName: SomeType */
22
- const MONGOOSE_FIELD_RE = /(\w+)\s*:\s*(?:\{[^}]*type\s*:\s*(\w+)|(\w+))/g;
23
- /** Sequelize: class Foo extends Model (or extends Model.Model) */
24
- const SEQUELIZE_CLASS_RE = /class\s+(\w+)\s+extends\s+(?:\w+\.)?Model\b/g;
25
- /** Sequelize Model.init({ field: ... }, { sequelize }) — capture the first arg block */
26
- const SEQUELIZE_INIT_RE = /(\w+)\.init\s*\(\s*\{/g;
27
- /** Sequelize sequelize.define('ModelName', { ... }) */
28
- const SEQUELIZE_DEFINE_RE = /\.define\s*\(\s*['"](\w+)['"]\s*,\s*\{/g;
29
- /** Sequelize field inside init/define block: fieldName: DataTypes.X or fieldName: { type: DataTypes.X } */
30
- const SEQUELIZE_FIELD_RE = /(\w+)\s*:\s*(?:\{[^}]*type\s*:\s*(?:DataTypes\.)?(\w+)|(?:DataTypes\.)?(\w+))/g;
31
- /** SQLAlchemy: class Foo(Base) or class Foo(db.Model) etc. */
32
- const SQLALCHEMY_CLASS_RE = /class\s+(\w+)\s*\([^)]*Base[^)]*\)/g;
33
- /** SQLAlchemy column: fieldName = Column( */
34
- const SQLALCHEMY_COLUMN_RE = /(\w+)\s*(?::\s*[\w[\]]+)?\s*=\s*Column\s*\(/g;
35
12
  // ── Phase ─────────────────────────────────────────────────────────────────────
36
13
  export const ormPhase = {
37
14
  name: 'orm',
@@ -78,311 +55,4 @@ export const ormPhase = {
78
55
  return { entities };
79
56
  },
80
57
  };
81
- // ── Detectors ─────────────────────────────────────────────────────────────────
82
- function detectTypeOrmEntities(source, filePath, language, entities, entityNodes, fieldNodes, edges) {
83
- const entityRe = new RegExp(TYPEORM_ENTITY_RE.source, 'g');
84
- const lines = source.split('\n');
85
- let m;
86
- while ((m = entityRe.exec(source)) !== null) {
87
- const entityName = m[1];
88
- const entityNodeId = makeId('entity', entityName + filePath);
89
- const entityNode = {
90
- id: entityNodeId,
91
- label: 'Entity',
92
- name: entityName,
93
- normLabel: toNormLabel(entityName),
94
- filePath,
95
- startLine: 0,
96
- endLine: 0,
97
- isExported: true,
98
- language,
99
- };
100
- entityNodes.push(entityNode);
101
- const fields = [];
102
- const colDecRe = new RegExp(TYPEORM_COLUMN_DECORATOR_RE.source, 'g');
103
- for (let i = 0; i < lines.length; i++) {
104
- const line = lines[i];
105
- if (colDecRe.test(line)) {
106
- colDecRe.lastIndex = 0; // reset after test
107
- // Look at the next non-empty line for the property declaration
108
- for (let j = i + 1; j < Math.min(i + 4, lines.length); j++) {
109
- const propLine = lines[j].trim();
110
- if (!propLine || propLine.startsWith('@') || propLine.startsWith('//'))
111
- continue;
112
- const pm = TYPEORM_PROP_RE.exec(propLine);
113
- if (pm) {
114
- addField(entityName, pm[1], pm[2], filePath, language, entityNodeId, fields, fieldNodes, edges);
115
- }
116
- break;
117
- }
118
- }
119
- colDecRe.lastIndex = 0; // always reset
120
- }
121
- entities.push({ name: entityName, filePath, fields, entityNodeId });
122
- }
123
- }
124
- function detectPrismaEntities(source, filePath, language, entities, entityNodes, fieldNodes, edges) {
125
- const modelRe = new RegExp(PRISMA_MODEL_RE.source, 'gm');
126
- let m;
127
- while ((m = modelRe.exec(source)) !== null) {
128
- const entityName = m[1];
129
- const body = m[2];
130
- const entityNodeId = makeId('entity', entityName + filePath);
131
- const entityNode = {
132
- id: entityNodeId,
133
- label: 'Entity',
134
- name: entityName,
135
- normLabel: toNormLabel(entityName),
136
- filePath,
137
- startLine: 0,
138
- endLine: 0,
139
- isExported: true,
140
- language,
141
- };
142
- entityNodes.push(entityNode);
143
- const fields = [];
144
- const fieldRe = new RegExp(PRISMA_FIELD_RE.source, 'gm');
145
- let fm;
146
- while ((fm = fieldRe.exec(body)) !== null) {
147
- const fieldName = fm[1];
148
- const fieldType = fm[2];
149
- // Skip Prisma keywords
150
- if (['model', 'enum', 'type', 'datasource', 'generator'].includes(fieldName))
151
- continue;
152
- addField(entityName, fieldName, fieldType, filePath, language, entityNodeId, fields, fieldNodes, edges);
153
- }
154
- entities.push({ name: entityName, filePath, fields, entityNodeId });
155
- }
156
- }
157
- function detectMongooseEntities(source, filePath, language, entities, entityNodes, fieldNodes, edges) {
158
- const schemaRe = new RegExp(MONGOOSE_SCHEMA_RE.source, 'g');
159
- let m;
160
- while ((m = schemaRe.exec(source)) !== null) {
161
- const schemaVarName = m[1];
162
- // Remove 'Schema' suffix to get entity name
163
- const entityName = schemaVarName.replace(/[Ss]chema$/, '') || schemaVarName;
164
- const entityNodeId = makeId('entity', entityName + filePath);
165
- const entityNode = {
166
- id: entityNodeId,
167
- label: 'Entity',
168
- name: entityName,
169
- normLabel: toNormLabel(entityName),
170
- filePath,
171
- startLine: 0,
172
- endLine: 0,
173
- isExported: true,
174
- language,
175
- };
176
- entityNodes.push(entityNode);
177
- // Extract a block after the Schema({ starting point
178
- const blockStart = m.index + m[0].length;
179
- const block = extractBraceBlock(source, blockStart - 1, 4000);
180
- const fields = [];
181
- if (block) {
182
- const fieldRe = new RegExp(MONGOOSE_FIELD_RE.source, 'g');
183
- let fm;
184
- const seen = new Set();
185
- while ((fm = fieldRe.exec(block)) !== null) {
186
- const fieldName = fm[1];
187
- const fieldType = fm[2] ?? fm[3] ?? 'Mixed';
188
- if (seen.has(fieldName))
189
- continue;
190
- // Skip obvious non-field keys
191
- if (['type', 'required', 'default', 'ref', 'index', 'unique', 'enum'].includes(fieldName))
192
- continue;
193
- seen.add(fieldName);
194
- addField(entityName, fieldName, fieldType, filePath, language, entityNodeId, fields, fieldNodes, edges);
195
- }
196
- }
197
- entities.push({ name: entityName, filePath, fields, entityNodeId });
198
- }
199
- }
200
- function detectSequelizeEntities(source, filePath, language, entities, entityNodes, fieldNodes, edges) {
201
- // Track entity names we've already registered to avoid duplicates.
202
- const registeredNames = new Set();
203
- function registerEntity(entityName) {
204
- const entityNodeId = makeId('entity', entityName + filePath);
205
- if (registeredNames.has(entityName))
206
- return entityNodeId;
207
- registeredNames.add(entityName);
208
- const entityNode = {
209
- id: entityNodeId,
210
- label: 'Entity',
211
- name: entityName,
212
- normLabel: toNormLabel(entityName),
213
- filePath,
214
- startLine: 0,
215
- endLine: 0,
216
- isExported: true,
217
- language,
218
- };
219
- entityNodes.push(entityNode);
220
- return entityNodeId;
221
- }
222
- // Collect class names that extend Model so we can match them in .init() calls.
223
- const modelClasses = new Set();
224
- const classRe = new RegExp(SEQUELIZE_CLASS_RE.source, 'g');
225
- let cm;
226
- while ((cm = classRe.exec(source)) !== null) {
227
- modelClasses.add(cm[1]);
228
- }
229
- // Handle: ClassName.init({ ... }, { sequelize })
230
- const initRe = new RegExp(SEQUELIZE_INIT_RE.source, 'g');
231
- let im;
232
- while ((im = initRe.exec(source)) !== null) {
233
- const candidateName = im[1];
234
- // Only treat as Sequelize if it's a known Model subclass OR if DataTypes appears in the block.
235
- const blockStart = im.index + im[0].length - 1; // position of the opening '{'
236
- const block = extractBraceBlock(source, blockStart, 4000);
237
- if (!block)
238
- continue;
239
- if (!modelClasses.has(candidateName) && !block.includes('DataTypes'))
240
- continue;
241
- const entityNodeId = registerEntity(candidateName);
242
- const fields = [];
243
- const fieldRe = new RegExp(SEQUELIZE_FIELD_RE.source, 'g');
244
- let fm;
245
- const seen = new Set();
246
- while ((fm = fieldRe.exec(block)) !== null) {
247
- const fieldName = fm[1];
248
- const fieldType = fm[2] ?? fm[3] ?? 'DataType';
249
- if (seen.has(fieldName))
250
- continue;
251
- if (['type', 'allowNull', 'defaultValue', 'primaryKey', 'unique', 'references'].includes(fieldName))
252
- continue;
253
- seen.add(fieldName);
254
- addField(candidateName, fieldName, fieldType, filePath, language, entityNodeId, fields, fieldNodes, edges);
255
- }
256
- entities.push({ name: candidateName, filePath, fields, entityNodeId });
257
- }
258
- // Handle: sequelize.define('ModelName', { ... })
259
- const defineRe = new RegExp(SEQUELIZE_DEFINE_RE.source, 'g');
260
- let dm;
261
- while ((dm = defineRe.exec(source)) !== null) {
262
- const entityName = dm[1];
263
- const blockStart = dm.index + dm[0].length - 1;
264
- const block = extractBraceBlock(source, blockStart, 4000);
265
- const entityNodeId = registerEntity(entityName);
266
- const fields = [];
267
- if (block) {
268
- const fieldRe = new RegExp(SEQUELIZE_FIELD_RE.source, 'g');
269
- let fm;
270
- const seen = new Set();
271
- while ((fm = fieldRe.exec(block)) !== null) {
272
- const fieldName = fm[1];
273
- const fieldType = fm[2] ?? fm[3] ?? 'DataType';
274
- if (seen.has(fieldName))
275
- continue;
276
- if (['type', 'allowNull', 'defaultValue', 'primaryKey', 'unique', 'references'].includes(fieldName))
277
- continue;
278
- seen.add(fieldName);
279
- addField(entityName, fieldName, fieldType, filePath, language, entityNodeId, fields, fieldNodes, edges);
280
- }
281
- }
282
- entities.push({ name: entityName, filePath, fields, entityNodeId });
283
- }
284
- }
285
- function detectSQLAlchemyEntities(source, filePath, language, entities, entityNodes, fieldNodes, edges) {
286
- const classRe = new RegExp(SQLALCHEMY_CLASS_RE.source, 'g');
287
- let m;
288
- while ((m = classRe.exec(source)) !== null) {
289
- const entityName = m[1];
290
- const entityNodeId = makeId('entity', entityName + filePath);
291
- const entityNode = {
292
- id: entityNodeId,
293
- label: 'Entity',
294
- name: entityName,
295
- normLabel: toNormLabel(entityName),
296
- filePath,
297
- startLine: 0,
298
- endLine: 0,
299
- isExported: true,
300
- language,
301
- };
302
- entityNodes.push(entityNode);
303
- const fields = [];
304
- // Scope column scan to this class's body — slice from the match end to the next
305
- // unindented `class ` keyword or end-of-string to avoid assigning columns from
306
- // other classes to this entity.
307
- const classBodyStart = m.index + m[0].length;
308
- const nextClassIdx = source.indexOf('\nclass ', classBodyStart);
309
- const classBody = nextClassIdx >= 0 ? source.slice(classBodyStart, nextClassIdx) : source.slice(classBodyStart);
310
- const columnRe = new RegExp(SQLALCHEMY_COLUMN_RE.source, 'g');
311
- let cm;
312
- while ((cm = columnRe.exec(classBody)) !== null) {
313
- const fieldName = cm[1];
314
- addField(entityName, fieldName, 'Column', filePath, language, entityNodeId, fields, fieldNodes, edges);
315
- }
316
- entities.push({ name: entityName, filePath, fields, entityNodeId });
317
- }
318
- }
319
- // ── Helpers ───────────────────────────────────────────────────────────────────
320
- function addField(entityName, fieldName, fieldType, filePath, language, entityNodeId, fields, fieldNodes, edges) {
321
- const fieldNodeId = makeId('field', entityName + fieldName + filePath);
322
- const fieldNode = {
323
- id: fieldNodeId,
324
- label: 'Field',
325
- name: fieldName,
326
- normLabel: toNormLabel(fieldName),
327
- filePath,
328
- startLine: 0,
329
- endLine: 0,
330
- isExported: false,
331
- language,
332
- properties: { declaredType: fieldType },
333
- };
334
- fieldNodes.push(fieldNode);
335
- const edgeId = makeId(entityNodeId, fieldNodeId, 'has_field');
336
- edges.push({
337
- id: edgeId,
338
- sourceId: entityNodeId,
339
- targetId: fieldNodeId,
340
- relation: 'HAS_FIELD',
341
- confidence: 'EXTRACTED',
342
- confidenceScore: 0.9,
343
- });
344
- fields.push({ name: fieldName, type: fieldType, fieldNodeId });
345
- }
346
- /**
347
- * Extracts a balanced brace block from source starting at the position of the
348
- * opening `{`. Returns the content between the braces (not including the braces).
349
- */
350
- function extractBraceBlock(source, openPos, maxLen) {
351
- // Find the opening brace at or after openPos
352
- const start = source.indexOf('{', openPos);
353
- if (start === -1)
354
- return undefined;
355
- let depth = 0;
356
- let i = start;
357
- const end = Math.min(start + maxLen, source.length);
358
- for (; i < end; i++) {
359
- if (source[i] === '{')
360
- depth++;
361
- else if (source[i] === '}') {
362
- depth--;
363
- if (depth === 0)
364
- return source.slice(start + 1, i);
365
- }
366
- }
367
- // Return partial block if not closed within maxLen
368
- return source.slice(start + 1, i);
369
- }
370
- function safeReadSource(absPath, maxBytes) {
371
- try {
372
- const stat = statSync(absPath);
373
- if (stat.size > maxBytes)
374
- return undefined;
375
- return readFileSync(absPath, 'utf-8');
376
- }
377
- catch {
378
- return undefined;
379
- }
380
- }
381
- function langFromExt(ext) {
382
- if (ext === '.ts' || ext === '.tsx')
383
- return 'typescript';
384
- if (ext === '.js' || ext === '.jsx' || ext === '.mjs' || ext === '.cjs')
385
- return 'javascript';
386
- return 'unknown';
387
- }
388
58
  //# sourceMappingURL=orm.js.map