arkanalyzer 1.0.90 → 1.0.91

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 (122) hide show
  1. package/config/arkanalyzer.json +0 -1
  2. package/lib/Config.d.ts +3 -0
  3. package/lib/Config.d.ts.map +1 -1
  4. package/lib/Scene.d.ts +99 -0
  5. package/lib/Scene.d.ts.map +1 -1
  6. package/lib/Scene.js +229 -13
  7. package/lib/callgraph/common/Statistics.js +2 -2
  8. package/lib/callgraph/model/CallGraph.d.ts +2 -2
  9. package/lib/callgraph/model/CallGraph.d.ts.map +1 -1
  10. package/lib/callgraph/model/CallGraph.js +6 -6
  11. package/lib/callgraph/model/CallSite.d.ts +1 -1
  12. package/lib/callgraph/model/CallSite.d.ts.map +1 -1
  13. package/lib/callgraph/model/CallSite.js +2 -2
  14. package/lib/core/base/Ref.d.ts.map +1 -1
  15. package/lib/core/base/Ref.js +6 -1
  16. package/lib/core/common/ArkIRTransformer.d.ts.map +1 -1
  17. package/lib/core/common/ArkIRTransformer.js +5 -0
  18. package/lib/core/common/ArkValueTransformer.d.ts.map +1 -1
  19. package/lib/core/common/ArkValueTransformer.js +2 -1
  20. package/lib/core/common/Const.d.ts +3 -0
  21. package/lib/core/common/Const.d.ts.map +1 -1
  22. package/lib/core/common/Const.js +5 -1
  23. package/lib/core/common/DummyMainCreater.d.ts +25 -12
  24. package/lib/core/common/DummyMainCreater.d.ts.map +1 -1
  25. package/lib/core/common/DummyMainCreater.js +90 -76
  26. package/lib/core/common/EtsConst.d.ts +2 -0
  27. package/lib/core/common/EtsConst.d.ts.map +1 -1
  28. package/lib/core/common/EtsConst.js +133 -125
  29. package/lib/core/common/SdkUtils.d.ts +1 -0
  30. package/lib/core/common/SdkUtils.d.ts.map +1 -1
  31. package/lib/core/common/SdkUtils.js +29 -0
  32. package/lib/core/graph/BaseExplicitGraph.d.ts +2 -0
  33. package/lib/core/graph/BaseExplicitGraph.d.ts.map +1 -1
  34. package/lib/core/graph/BaseExplicitGraph.js +12 -1
  35. package/lib/core/graph/BaseImplicitGraph.d.ts +16 -0
  36. package/lib/core/graph/BaseImplicitGraph.d.ts.map +1 -1
  37. package/lib/core/graph/BaseImplicitGraph.js +21 -0
  38. package/lib/core/graph/FileDepGraph.d.ts +75 -0
  39. package/lib/core/graph/FileDepGraph.d.ts.map +1 -0
  40. package/lib/core/graph/FileDepGraph.js +170 -0
  41. package/lib/core/graph/GraphTraits.d.ts +2 -0
  42. package/lib/core/graph/GraphTraits.d.ts.map +1 -1
  43. package/lib/core/graph/GraphTraits.js +1 -1
  44. package/lib/core/graph/ModuleDepGraph.d.ts +175 -0
  45. package/lib/core/graph/ModuleDepGraph.d.ts.map +1 -0
  46. package/lib/core/graph/ModuleDepGraph.js +421 -0
  47. package/lib/core/graph/Scc.d.ts +1 -3
  48. package/lib/core/graph/Scc.d.ts.map +1 -1
  49. package/lib/core/graph/Scc.js +6 -19
  50. package/lib/core/graph/builder/CfgBuilder.d.ts.map +1 -1
  51. package/lib/core/graph/builder/CfgBuilder.js +7 -1
  52. package/lib/core/graph/builder/TrapBuilder.d.ts +1 -0
  53. package/lib/core/graph/builder/TrapBuilder.d.ts.map +1 -1
  54. package/lib/core/graph/builder/TrapBuilder.js +27 -7
  55. package/lib/core/model/ArkBody.d.ts +1 -0
  56. package/lib/core/model/ArkBody.d.ts.map +1 -1
  57. package/lib/core/model/ArkBody.js +7 -0
  58. package/lib/core/model/ArkClass.d.ts +1 -0
  59. package/lib/core/model/ArkClass.d.ts.map +1 -1
  60. package/lib/core/model/ArkClass.js +37 -0
  61. package/lib/core/model/ArkExport.d.ts +1 -0
  62. package/lib/core/model/ArkExport.d.ts.map +1 -1
  63. package/lib/core/model/ArkExport.js +6 -0
  64. package/lib/core/model/ArkField.d.ts +1 -0
  65. package/lib/core/model/ArkField.d.ts.map +1 -1
  66. package/lib/core/model/ArkField.js +5 -0
  67. package/lib/core/model/ArkFile.d.ts +5 -0
  68. package/lib/core/model/ArkFile.d.ts.map +1 -1
  69. package/lib/core/model/ArkFile.js +30 -0
  70. package/lib/core/model/ArkImport.d.ts +1 -0
  71. package/lib/core/model/ArkImport.d.ts.map +1 -1
  72. package/lib/core/model/ArkImport.js +5 -0
  73. package/lib/core/model/ArkMethod.d.ts +8 -0
  74. package/lib/core/model/ArkMethod.d.ts.map +1 -1
  75. package/lib/core/model/ArkMethod.js +22 -0
  76. package/lib/core/model/ArkModule.d.ts +136 -0
  77. package/lib/core/model/ArkModule.d.ts.map +1 -0
  78. package/lib/core/model/ArkModule.js +250 -0
  79. package/lib/core/model/ArkNamespace.d.ts +1 -0
  80. package/lib/core/model/ArkNamespace.d.ts.map +1 -1
  81. package/lib/core/model/ArkNamespace.js +18 -0
  82. package/lib/core/model/builder/ArkFileBuilder.d.ts +19 -0
  83. package/lib/core/model/builder/ArkFileBuilder.d.ts.map +1 -1
  84. package/lib/core/model/builder/ArkFileBuilder.js +155 -51
  85. package/lib/frontend/FrontendBuilder.d.ts +116 -0
  86. package/lib/frontend/FrontendBuilder.d.ts.map +1 -1
  87. package/lib/frontend/FrontendBuilder.js +256 -0
  88. package/lib/frontend/arktsFrontend/ArktsFrontend.d.ts +11 -0
  89. package/lib/frontend/arktsFrontend/ArktsFrontend.d.ts.map +1 -1
  90. package/lib/frontend/arktsFrontend/ArktsFrontend.js +15 -0
  91. package/lib/frontend/common/MemoryMonitor.d.ts +62 -0
  92. package/lib/frontend/common/MemoryMonitor.d.ts.map +1 -0
  93. package/lib/frontend/common/MemoryMonitor.js +108 -0
  94. package/lib/frontend/common/ModuleAnalysisConfig.d.ts +92 -0
  95. package/lib/frontend/common/ModuleAnalysisConfig.d.ts.map +1 -0
  96. package/lib/frontend/common/ModuleAnalysisConfig.js +144 -0
  97. package/lib/frontend/common/ModuleBuilder.d.ts +497 -0
  98. package/lib/frontend/common/ModuleBuilder.d.ts.map +1 -0
  99. package/lib/frontend/common/ModuleBuilder.js +1458 -0
  100. package/lib/frontend/common/ModuleCache.d.ts +119 -0
  101. package/lib/frontend/common/ModuleCache.d.ts.map +1 -0
  102. package/lib/frontend/common/ModuleCache.js +197 -0
  103. package/lib/frontend/common/ModuleDepth.d.ts +28 -0
  104. package/lib/frontend/common/ModuleDepth.d.ts.map +1 -0
  105. package/lib/frontend/common/ModuleDepth.js +45 -0
  106. package/lib/frontend/cppFrontend/CppFrontend.d.ts +5 -0
  107. package/lib/frontend/cppFrontend/CppFrontend.d.ts.map +1 -1
  108. package/lib/frontend/cppFrontend/CppFrontend.js +11 -1
  109. package/lib/frontend/cppFrontend/model/builder/ArkFileBuilder.d.ts +8 -0
  110. package/lib/frontend/cppFrontend/model/builder/ArkFileBuilder.d.ts.map +1 -1
  111. package/lib/frontend/cppFrontend/model/builder/ArkFileBuilder.js +105 -2
  112. package/lib/index.d.ts +9 -1
  113. package/lib/index.d.ts.map +1 -1
  114. package/lib/index.js +22 -3
  115. package/lib/utils/Canonicalizer.d.ts +105 -0
  116. package/lib/utils/Canonicalizer.d.ts.map +1 -0
  117. package/lib/utils/Canonicalizer.js +520 -0
  118. package/lib/utils/ModuleUtils.js +4 -2
  119. package/lib/utils/entryMethodUtils.d.ts +23 -0
  120. package/lib/utils/entryMethodUtils.d.ts.map +1 -1
  121. package/lib/utils/entryMethodUtils.js +53 -1
  122. package/package.json +1 -1
@@ -1,5 +1,8 @@
1
+ import { Language } from '../core/model/ArkFile';
1
2
  import { ModuleScene, Scene } from '../Scene';
2
3
  import { ArkFile } from '../core/model/ArkFile';
4
+ import { ArkModule } from '../core/model/ArkModule';
5
+ import { ModuleDepthLevel } from './common/ModuleDepth';
3
6
  export interface FrontendParseFailure {
4
7
  filePath: string;
5
8
  reason: unknown;
@@ -22,5 +25,118 @@ export declare class FrontendBuilder {
22
25
  * Builds a single project file into a pre-allocated {@link ArkFile} (the former `if (CXX) … else …` in `Scene`).
23
26
  */
24
27
  static buildProjectFileIntoArkFile(scene: Scene, filePath: string, arkFile: ArkFile): void;
28
+ /**
29
+ * Build all source files of an {@link ArkModule} up to the given {@link ModuleDepthLevel}.
30
+ *
31
+ * Scans the module directory for source files using scene options
32
+ * (supportFileExts / ignoreFileNames), creates an {@link ArkFile} for each file, registers it
33
+ * with the module and scene, and builds it to the requested level. Errors on individual files
34
+ * are logged and do not abort the loop.
35
+ *
36
+ * @param scene - The owning {@link Scene}.
37
+ * @param module - The module whose files are built.
38
+ * @param level - The target depth level.
39
+ */
40
+ static buildModuleFilesToLevel(scene: Scene, module: ArkModule, level: ModuleDepthLevel): void;
41
+ /**
42
+ * Scan the module directory and create path-only {@link ArkFile} shells (no content parsed),
43
+ * registering each with the module and scene.
44
+ *
45
+ * Each shell has language, filePath, projectDir, and fileSignature set, but no ImportInfo /
46
+ * ExportInfo / ArkClass / ArkMethod. This is the META-level baseline; callers subsequently
47
+ * build content via {@link buildArkFileToLevel} (IMPORTS) or {@link upgradeArkFileToLevel}
48
+ * (SIGNATURES / BODIES).
49
+ *
50
+ * @param scene - The owning {@link Scene}.
51
+ * @param module - The module whose directory is scanned.
52
+ * @returns Array of created (and registered) ArkFile shells.
53
+ */
54
+ static createModuleFileShells(scene: Scene, module: ArkModule): ArkFile[];
55
+ /**
56
+ * Dispatch level-aware building to the appropriate frontend.
57
+ *
58
+ * - META: no content is built (only the ArkFile path/basic info created by the caller).
59
+ * - IMPORTS: lightweight import/export parsing only.
60
+ * - SIGNATURES: full namespace/class/method signatures are built (parameters, return types)
61
+ * without method bodies, reusing {@link buildProjectFileIntoArkFile}. The mounted
62
+ * BodyBuilders are released here so the ArkFile holds signatures only (no ArkBody/CFG).
63
+ * - BODIES: same as SIGNATURES but the mounted BodyBuilders are **retained** (not released)
64
+ * so that {@link buildModuleMethodBody} can build method bodies in a subsequent phase.
65
+ */
66
+ private static buildArkFileToLevel;
67
+ /**
68
+ * IMPORTS level: lightweight import/export parsing only.
69
+ */
70
+ static buildImports(arkFile: ArkFile, language: Language): void;
71
+ /**
72
+ * Upgrade an existing ArkFile (whose ImportInfo/ExportInfo were already populated at IMPORTS
73
+ * level) to SIGNATURES or BODIES by building class/method/namespace signatures on top.
74
+ *
75
+ * For ArkTS files, this calls {@link ArktsFrontend.buildProjectFileForSignatures} which builds
76
+ * signatures with `skipImportExport = true`, preserving existing import/export data and
77
+ * avoiding duplication of `export *` re-export entries (whose temp clause keys are
78
+ * process-level auto-increment and cannot be overwritten by `Map.set`).
79
+ *
80
+ * For C++ files, {@link CppFrontend.buildProjectFile} is safe to re-call: C++ ImportInfo uses
81
+ * stable clause keys (`#include "..."` / namespace names) that are overwritten by `Map.set`,
82
+ * and C++ ExportInfo is not produced during the IMPORTS-only phase, so no duplication occurs.
83
+ *
84
+ * After signature building, BodyBuilders are released when the target level is SIGNATURES
85
+ * (no ArkBody/CFG retained). For BODIES, BodyBuilders are retained so that
86
+ * {@link buildModuleMethodBody} can build method bodies in a subsequent phase.
87
+ *
88
+ * @param scene - The owning {@link Scene}.
89
+ * @param arkFile - The ArkFile to upgrade (must already have ImportInfo/ExportInfo).
90
+ * @param language - The language of the file.
91
+ * @param targetLevel - The target depth level (must be > IMPORTS).
92
+ */
93
+ static upgradeArkFileToLevel(scene: Scene, arkFile: ArkFile, language: Language, targetLevel: ModuleDepthLevel): void;
94
+ /**
95
+ * Release the BodyBuilder (or CxxBodyBuilder) mounted on a method, freeing the AST/build
96
+ * context.
97
+ */
98
+ private static freeMethodBodyBuilder;
99
+ /**
100
+ * Release the BodyBuilders mounted during signature building so the ArkFile retains only
101
+ * signatures (no ArkBody/CFG) and does not retain AST/build context in memory. Mirrors the
102
+ * release pattern in {@link Scene.parseAndRegisterSdkFile}.
103
+ */
104
+ private static freeBodyBuildersInFile;
105
+ /**
106
+ * Build method bodies (ArkBody/CFG/Stmt/Expr) for all ArkFiles in the given module, then
107
+ * run default-constructor post-processing. This is the module-scoped equivalent of
108
+ * {@link Scene.buildAllMethodBody} + {@link Scene.updateOrAddDefaultConstructors}, following
109
+ * the same two-phase pattern as {@link Scene.genArkFiles}.
110
+ *
111
+ * Phase 1 (signatures + mounted BodyBuilders) is performed earlier by
112
+ * {@link buildModuleFilesToLevel} at {@link ModuleDepthLevel.BODIES}, which retains the
113
+ * mounted BodyBuilders. This method performs phase 2:
114
+ *
115
+ * 1. Set {@link Scene.buildStage} to {@link SceneBuildStage.CLASS_DONE} (opening the
116
+ * {@link Scene.buildClassDone} gate) so that when BodyBuilder encounters nested/anonymous
117
+ * methods during body construction, their {@link ArkMethod.setBodyBuilder} calls
118
+ * immediately trigger {@link ArkMethod.buildBody} — recursively building nested method
119
+ * bodies. The previous buildStage is restored afterwards so that subsequent SIGNATURES-
120
+ * level module loading is unaffected.
121
+ * 2. Collect all methods in the module's files.
122
+ * 3. Call {@link ArkMethod.buildBody} on each (executes the retained BodyBuilder), then free
123
+ * the BodyBuilder to release AST/build context.
124
+ * 4. Run {@link buildDefaultConstructor} / {@link replaceSuper2Constructor} /
125
+ * {@link addInitInConstructor} on the module's files (gate still open).
126
+ *
127
+ * Calls {@link ModelUtils.dispose} after each module's method bodies are built to release
128
+ * global caches (implicitArkUIBuilderMethods, popMethodSignatureCache) that accumulate during
129
+ * body building.
130
+ *
131
+ * @param module - The module whose files' method bodies are to be built.
132
+ */
133
+ static buildModuleMethodBody(module: ArkModule): void;
134
+ /**
135
+ * Run {@link buildDefaultConstructor} / {@link replaceSuper2Constructor} /
136
+ * {@link addInitInConstructor} on all classes in a file. These create/modify constructors;
137
+ * {@link buildDefaultConstructor} builds bodies directly (without BodyBuilder), and the
138
+ * other two only modify already-built bodies.
139
+ */
140
+ private static processDefaultConstructors;
25
141
  }
26
142
  //# sourceMappingURL=FrontendBuilder.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"FrontendBuilder.d.ts","sourceRoot":"","sources":["../../src/frontend/FrontendBuilder.ts"],"names":[],"mappings":"AAgBA,OAAO,EAAE,WAAW,EAAE,KAAK,EAAE,MAAM,UAAU,CAAC;AAG9C,OAAO,EAAE,OAAO,EAAE,MAAM,uBAAuB,CAAC;AAMhD,MAAM,WAAW,oBAAoB;IACjC,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,EAAE,OAAO,CAAC;CACnB;AAED,MAAM,WAAW,mBAAmB;IAChC,QAAQ,EAAE,OAAO,EAAE,CAAC;IACpB,WAAW,EAAE,oBAAoB,EAAE,CAAC;CACvC;AAED;;;;GAIG;AACH,qBAAa,eAAe;IACxB,OAAO,CAAC,MAAM,CAAC,kBAAkB;IAajC,OAAO,CAAC,MAAM,CAAC,sBAAsB;WAOvB,sBAAsB,CAAC,KAAK,EAAE,KAAK,EAAE,SAAS,EAAE,MAAM,EAAE,GAAG,IAAI;WAW/D,4BAA4B,CAAC,WAAW,EAAE,WAAW,EAAE,SAAS,EAAE,MAAM,EAAE,GAAG,IAAI;IAe/F;;OAEG;WACW,2BAA2B,CAAC,KAAK,EAAE,KAAK,EAAE,QAAQ,EAAE,MAAM,EAAE,OAAO,EAAE,OAAO,GAAG,IAAI;CAOpG"}
1
+ {"version":3,"file":"FrontendBuilder.d.ts","sourceRoot":"","sources":["../../src/frontend/FrontendBuilder.ts"],"names":[],"mappings":"AAiBA,OAAO,EAAE,QAAQ,EAAE,MAAM,uBAAuB,CAAC;AACjD,OAAO,EAAE,WAAW,EAAE,KAAK,EAAmB,MAAM,UAAU,CAAC;AAG/D,OAAO,EAAE,OAAO,EAAE,MAAM,uBAAuB,CAAC;AAChD,OAAO,EAAE,SAAS,EAAE,MAAM,yBAAyB,CAAC;AAOpD,OAAO,EAAE,gBAAgB,EAAE,MAAM,sBAAsB,CAAC;AAQxD,MAAM,WAAW,oBAAoB;IACjC,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,EAAE,OAAO,CAAC;CACnB;AAED,MAAM,WAAW,mBAAmB;IAChC,QAAQ,EAAE,OAAO,EAAE,CAAC;IACpB,WAAW,EAAE,oBAAoB,EAAE,CAAC;CACvC;AAED;;;;GAIG;AACH,qBAAa,eAAe;IACxB,OAAO,CAAC,MAAM,CAAC,kBAAkB;IAajC,OAAO,CAAC,MAAM,CAAC,sBAAsB;WAOvB,sBAAsB,CAAC,KAAK,EAAE,KAAK,EAAE,SAAS,EAAE,MAAM,EAAE,GAAG,IAAI;WAW/D,4BAA4B,CAAC,WAAW,EAAE,WAAW,EAAE,SAAS,EAAE,MAAM,EAAE,GAAG,IAAI;IAe/F;;OAEG;WACW,2BAA2B,CAAC,KAAK,EAAE,KAAK,EAAE,QAAQ,EAAE,MAAM,EAAE,OAAO,EAAE,OAAO,GAAG,IAAI;IAQjG;;;;;;;;;;;OAWG;WACW,uBAAuB,CAAC,KAAK,EAAE,KAAK,EAAE,MAAM,EAAE,SAAS,EAAE,KAAK,EAAE,gBAAgB,GAAG,IAAI;IAWrG;;;;;;;;;;;;OAYG;WACW,sBAAsB,CAAC,KAAK,EAAE,KAAK,EAAE,MAAM,EAAE,SAAS,GAAG,OAAO,EAAE;IA+BhF;;;;;;;;;;OAUG;IACH,OAAO,CAAC,MAAM,CAAC,mBAAmB;IAkBlC;;OAEG;WACW,YAAY,CAAC,OAAO,EAAE,OAAO,EAAE,QAAQ,EAAE,QAAQ,GAAG,IAAI;IAQtE;;;;;;;;;;;;;;;;;;;;;OAqBG;WACW,qBAAqB,CAAC,KAAK,EAAE,KAAK,EAAE,OAAO,EAAE,OAAO,EAAE,QAAQ,EAAE,QAAQ,EAAE,WAAW,EAAE,gBAAgB,GAAG,IAAI;IAW5H;;;OAGG;IACH,OAAO,CAAC,MAAM,CAAC,qBAAqB;IASpC;;;;OAIG;IACH,OAAO,CAAC,MAAM,CAAC,sBAAsB;IAMrC;;;;;;;;;;;;;;;;;;;;;;;;;;;OA2BG;WACW,qBAAqB,CAAC,MAAM,EAAE,SAAS,GAAG,IAAI;IA8B5D;;;;;OAKG;IACH,OAAO,CAAC,MAAM,CAAC,0BAA0B;CAc5C"}
@@ -36,13 +36,27 @@ var __importStar = (this && this.__importStar) || function (mod) {
36
36
  __setModuleDefault(result, mod);
37
37
  return result;
38
38
  };
39
+ var __importDefault = (this && this.__importDefault) || function (mod) {
40
+ return (mod && mod.__esModule) ? mod : { "default": mod };
41
+ };
39
42
  Object.defineProperty(exports, "__esModule", { value: true });
40
43
  exports.FrontendBuilder = void 0;
44
+ const path_1 = __importDefault(require("path"));
41
45
  const ArkFile_1 = require("../core/model/ArkFile");
46
+ const Scene_1 = require("../Scene");
42
47
  const ArktsFrontend_1 = require("./arktsFrontend/ArktsFrontend");
43
48
  const CppFrontend_1 = require("./cppFrontend/CppFrontend");
49
+ const ArkFile_2 = require("../core/model/ArkFile");
50
+ const ArkSignature_1 = require("../core/model/ArkSignature");
51
+ const ModelUtils_1 = require("../core/common/ModelUtils");
44
52
  const FileUtils_1 = require("../utils/FileUtils");
53
+ const getAllFiles_1 = require("../utils/getAllFiles");
45
54
  const logger_1 = __importStar(require("../utils/logger"));
55
+ const ModuleDepth_1 = require("./common/ModuleDepth");
56
+ const ArkMethodBuilder_1 = require("../core/model/builder/ArkMethodBuilder");
57
+ const ArkMethodBuilder_2 = require("./cppFrontend/model/builder/ArkMethodBuilder");
58
+ const TSConst_1 = require("../core/common/TSConst");
59
+ const EtsConst_1 = require("../core/common/EtsConst");
46
60
  const logger = logger_1.default.getLogger(logger_1.LOG_MODULE_TYPE.ARKANALYZER, 'FrontendBuilder');
47
61
  /**
48
62
  * Dispatches language front-ends and exposes a single build entry for {@link Scene} so the scene no longer
@@ -104,5 +118,247 @@ class FrontendBuilder {
104
118
  new ArktsFrontend_1.ArktsFrontend().buildProjectFile(scene, filePath, arkFile);
105
119
  }
106
120
  }
121
+ /**
122
+ * Build all source files of an {@link ArkModule} up to the given {@link ModuleDepthLevel}.
123
+ *
124
+ * Scans the module directory for source files using scene options
125
+ * (supportFileExts / ignoreFileNames), creates an {@link ArkFile} for each file, registers it
126
+ * with the module and scene, and builds it to the requested level. Errors on individual files
127
+ * are logged and do not abort the loop.
128
+ *
129
+ * @param scene - The owning {@link Scene}.
130
+ * @param module - The module whose files are built.
131
+ * @param level - The target depth level.
132
+ */
133
+ static buildModuleFilesToLevel(scene, module, level) {
134
+ const arkFiles = FrontendBuilder.createModuleFileShells(scene, module);
135
+ for (const arkFile of arkFiles) {
136
+ try {
137
+ FrontendBuilder.buildArkFileToLevel(scene, arkFile.getFilePath(), arkFile, arkFile.getLanguage(), level);
138
+ }
139
+ catch (error) {
140
+ logger.error(`Error building ArkFile for ${arkFile.getFilePath()}: ${error}`);
141
+ }
142
+ }
143
+ }
144
+ /**
145
+ * Scan the module directory and create path-only {@link ArkFile} shells (no content parsed),
146
+ * registering each with the module and scene.
147
+ *
148
+ * Each shell has language, filePath, projectDir, and fileSignature set, but no ImportInfo /
149
+ * ExportInfo / ArkClass / ArkMethod. This is the META-level baseline; callers subsequently
150
+ * build content via {@link buildArkFileToLevel} (IMPORTS) or {@link upgradeArkFileToLevel}
151
+ * (SIGNATURES / BODIES).
152
+ *
153
+ * @param scene - The owning {@link Scene}.
154
+ * @param module - The module whose directory is scanned.
155
+ * @returns Array of created (and registered) ArkFile shells.
156
+ */
157
+ static createModuleFileShells(scene, module) {
158
+ var _a, _b;
159
+ const modulePath = module.getModulePath();
160
+ const options = scene.getOptions();
161
+ const supportFileExts = (_a = options === null || options === void 0 ? void 0 : options.supportFileExts) !== null && _a !== void 0 ? _a : ['.ets', '.ts'];
162
+ // Always skip 'oh_modules' subdirectories within a module to avoid duplicate scanning
163
+ // via symlinks: oh_modules packages are registered as separate modules by
164
+ // registerOhModulesModules (which uses fs.readdirSync directly, not getAllFiles).
165
+ const ignoreFileNames = [...((_b = options === null || options === void 0 ? void 0 : options.ignoreFileNames) !== null && _b !== void 0 ? _b : []), EtsConst_1.OH_MODULES];
166
+ const filePaths = (0, getAllFiles_1.getAllFiles)(modulePath, supportFileExts, ignoreFileNames);
167
+ const arkFiles = [];
168
+ for (const filePath of filePaths) {
169
+ try {
170
+ const language = FileUtils_1.FileUtils.getFileLanguage(filePath, scene.getFileLanguages());
171
+ const arkFile = new ArkFile_2.ArkFile(language);
172
+ arkFile.setScene(scene);
173
+ arkFile.setFilePath(filePath);
174
+ arkFile.setProjectDir(scene.getRealProjectDir());
175
+ const fileSignature = new ArkSignature_1.FileSignature(scene.getProjectName(), path_1.default.relative(scene.getRealProjectDir(), filePath));
176
+ arkFile.setFileSignature(fileSignature);
177
+ module.addFile(arkFile);
178
+ arkFile.setArkModule(module);
179
+ scene.setFile(arkFile);
180
+ arkFiles.push(arkFile);
181
+ }
182
+ catch (error) {
183
+ logger.error(`Error creating ArkFile shell for ${filePath}: ${error}`);
184
+ }
185
+ }
186
+ return arkFiles;
187
+ }
188
+ /**
189
+ * Dispatch level-aware building to the appropriate frontend.
190
+ *
191
+ * - META: no content is built (only the ArkFile path/basic info created by the caller).
192
+ * - IMPORTS: lightweight import/export parsing only.
193
+ * - SIGNATURES: full namespace/class/method signatures are built (parameters, return types)
194
+ * without method bodies, reusing {@link buildProjectFileIntoArkFile}. The mounted
195
+ * BodyBuilders are released here so the ArkFile holds signatures only (no ArkBody/CFG).
196
+ * - BODIES: same as SIGNATURES but the mounted BodyBuilders are **retained** (not released)
197
+ * so that {@link buildModuleMethodBody} can build method bodies in a subsequent phase.
198
+ */
199
+ static buildArkFileToLevel(scene, filePath, arkFile, language, level) {
200
+ if (level <= ModuleDepth_1.ModuleDepthLevel.META) {
201
+ return;
202
+ }
203
+ if (level === ModuleDepth_1.ModuleDepthLevel.IMPORTS) {
204
+ FrontendBuilder.buildImports(arkFile, language);
205
+ return;
206
+ }
207
+ // SIGNATURES and BODIES: reuse the full file builder to build signatures and mount
208
+ // BodyBuilders on each method implementation.
209
+ FrontendBuilder.buildProjectFileIntoArkFile(scene, filePath, arkFile);
210
+ if (level < ModuleDepth_1.ModuleDepthLevel.BODIES) {
211
+ // SIGNATURES: release BodyBuilders so only signatures remain (no ArkBody/CFG).
212
+ FrontendBuilder.freeBodyBuildersInFile(arkFile);
213
+ }
214
+ // BODIES: keep BodyBuilders mounted for phase 2 (body building in buildModuleMethodBody).
215
+ }
216
+ /**
217
+ * IMPORTS level: lightweight import/export parsing only.
218
+ */
219
+ static buildImports(arkFile, language) {
220
+ if (language === ArkFile_1.Language.CXX) {
221
+ new CppFrontend_1.CppFrontend().buildProjectFileForImports(arkFile);
222
+ }
223
+ else {
224
+ new ArktsFrontend_1.ArktsFrontend().buildProjectFileForImports(arkFile);
225
+ }
226
+ }
227
+ /**
228
+ * Upgrade an existing ArkFile (whose ImportInfo/ExportInfo were already populated at IMPORTS
229
+ * level) to SIGNATURES or BODIES by building class/method/namespace signatures on top.
230
+ *
231
+ * For ArkTS files, this calls {@link ArktsFrontend.buildProjectFileForSignatures} which builds
232
+ * signatures with `skipImportExport = true`, preserving existing import/export data and
233
+ * avoiding duplication of `export *` re-export entries (whose temp clause keys are
234
+ * process-level auto-increment and cannot be overwritten by `Map.set`).
235
+ *
236
+ * For C++ files, {@link CppFrontend.buildProjectFile} is safe to re-call: C++ ImportInfo uses
237
+ * stable clause keys (`#include "..."` / namespace names) that are overwritten by `Map.set`,
238
+ * and C++ ExportInfo is not produced during the IMPORTS-only phase, so no duplication occurs.
239
+ *
240
+ * After signature building, BodyBuilders are released when the target level is SIGNATURES
241
+ * (no ArkBody/CFG retained). For BODIES, BodyBuilders are retained so that
242
+ * {@link buildModuleMethodBody} can build method bodies in a subsequent phase.
243
+ *
244
+ * @param scene - The owning {@link Scene}.
245
+ * @param arkFile - The ArkFile to upgrade (must already have ImportInfo/ExportInfo).
246
+ * @param language - The language of the file.
247
+ * @param targetLevel - The target depth level (must be > IMPORTS).
248
+ */
249
+ static upgradeArkFileToLevel(scene, arkFile, language, targetLevel) {
250
+ if (language === ArkFile_1.Language.CXX) {
251
+ new CppFrontend_1.CppFrontend().buildProjectFile(scene, arkFile.getFilePath(), arkFile);
252
+ }
253
+ else {
254
+ new ArktsFrontend_1.ArktsFrontend().buildProjectFileForSignatures(arkFile);
255
+ }
256
+ if (targetLevel < ModuleDepth_1.ModuleDepthLevel.BODIES) {
257
+ FrontendBuilder.freeBodyBuildersInFile(arkFile);
258
+ }
259
+ }
260
+ /**
261
+ * Release the BodyBuilder (or CxxBodyBuilder) mounted on a method, freeing the AST/build
262
+ * context.
263
+ */
264
+ static freeMethodBodyBuilder(method) {
265
+ var _a;
266
+ const isCxxFile = ((_a = method.getDeclaringArkFile()) === null || _a === void 0 ? void 0 : _a.getLanguage()) === ArkFile_1.Language.CXX;
267
+ if (isCxxFile) {
268
+ method.freeCxxBodyBuilder();
269
+ }
270
+ else {
271
+ method.freeBodyBuilder();
272
+ }
273
+ }
274
+ /**
275
+ * Release the BodyBuilders mounted during signature building so the ArkFile retains only
276
+ * signatures (no ArkBody/CFG) and does not retain AST/build context in memory. Mirrors the
277
+ * release pattern in {@link Scene.parseAndRegisterSdkFile}.
278
+ */
279
+ static freeBodyBuildersInFile(arkFile) {
280
+ for (const method of ModelUtils_1.ModelUtils.getAllMethodsInFile(arkFile)) {
281
+ FrontendBuilder.freeMethodBodyBuilder(method);
282
+ }
283
+ }
284
+ /**
285
+ * Build method bodies (ArkBody/CFG/Stmt/Expr) for all ArkFiles in the given module, then
286
+ * run default-constructor post-processing. This is the module-scoped equivalent of
287
+ * {@link Scene.buildAllMethodBody} + {@link Scene.updateOrAddDefaultConstructors}, following
288
+ * the same two-phase pattern as {@link Scene.genArkFiles}.
289
+ *
290
+ * Phase 1 (signatures + mounted BodyBuilders) is performed earlier by
291
+ * {@link buildModuleFilesToLevel} at {@link ModuleDepthLevel.BODIES}, which retains the
292
+ * mounted BodyBuilders. This method performs phase 2:
293
+ *
294
+ * 1. Set {@link Scene.buildStage} to {@link SceneBuildStage.CLASS_DONE} (opening the
295
+ * {@link Scene.buildClassDone} gate) so that when BodyBuilder encounters nested/anonymous
296
+ * methods during body construction, their {@link ArkMethod.setBodyBuilder} calls
297
+ * immediately trigger {@link ArkMethod.buildBody} — recursively building nested method
298
+ * bodies. The previous buildStage is restored afterwards so that subsequent SIGNATURES-
299
+ * level module loading is unaffected.
300
+ * 2. Collect all methods in the module's files.
301
+ * 3. Call {@link ArkMethod.buildBody} on each (executes the retained BodyBuilder), then free
302
+ * the BodyBuilder to release AST/build context.
303
+ * 4. Run {@link buildDefaultConstructor} / {@link replaceSuper2Constructor} /
304
+ * {@link addInitInConstructor} on the module's files (gate still open).
305
+ *
306
+ * Calls {@link ModelUtils.dispose} after each module's method bodies are built to release
307
+ * global caches (implicitArkUIBuilderMethods, popMethodSignatureCache) that accumulate during
308
+ * body building.
309
+ *
310
+ * @param module - The module whose files' method bodies are to be built.
311
+ */
312
+ static buildModuleMethodBody(module) {
313
+ const scene = module.getScene();
314
+ const prevStage = scene.getStage();
315
+ scene.setBuildStage(Scene_1.SceneBuildStage.CLASS_DONE);
316
+ try {
317
+ // Phase 2a: build method bodies for all methods in the module's files.
318
+ const methods = [];
319
+ for (const arkFile of module.getFilesMap().values()) {
320
+ methods.push(...ModelUtils_1.ModelUtils.getAllMethodsInFile(arkFile));
321
+ }
322
+ for (const method of methods) {
323
+ try {
324
+ method.buildBody();
325
+ }
326
+ catch (error) {
327
+ logger.error('Error building body:', method.getSignature(), error);
328
+ }
329
+ finally {
330
+ FrontendBuilder.freeMethodBodyBuilder(method);
331
+ }
332
+ }
333
+ // Phase 2b: default-constructor post-processing for the module's files.
334
+ for (const arkFile of module.getFilesMap().values()) {
335
+ FrontendBuilder.processDefaultConstructors(arkFile);
336
+ }
337
+ }
338
+ finally {
339
+ scene.setBuildStage(prevStage);
340
+ ModelUtils_1.ModelUtils.dispose();
341
+ }
342
+ }
343
+ /**
344
+ * Run {@link buildDefaultConstructor} / {@link replaceSuper2Constructor} /
345
+ * {@link addInitInConstructor} on all classes in a file. These create/modify constructors;
346
+ * {@link buildDefaultConstructor} builds bodies directly (without BodyBuilder), and the
347
+ * other two only modify already-built bodies.
348
+ */
349
+ static processDefaultConstructors(arkFile) {
350
+ const initInConstructorFn = arkFile.getLanguage() === ArkFile_1.Language.CXX ? ArkMethodBuilder_2.addInitInConstructor : ArkMethodBuilder_1.addInitInConstructor;
351
+ for (const cls of ModelUtils_1.ModelUtils.getAllClassesInFile(arkFile)) {
352
+ (0, ArkMethodBuilder_1.buildDefaultConstructor)(cls);
353
+ if (cls.isDefaultArkClass()) {
354
+ continue;
355
+ }
356
+ const constructors = cls.getAllMethodsWithName(TSConst_1.CONSTRUCTOR_NAME);
357
+ constructors.forEach(constructor => {
358
+ (0, ArkMethodBuilder_1.replaceSuper2Constructor)(constructor);
359
+ initInConstructorFn(constructor);
360
+ });
361
+ }
362
+ }
107
363
  }
108
364
  exports.FrontendBuilder = FrontendBuilder;
@@ -7,6 +7,17 @@ import { FrontendParseResult } from '../FrontendBuilder';
7
7
  export declare class ArktsFrontend {
8
8
  /** Fills a project {@link ArkFile} from a source file; delegates to {@link buildArkFileFromFile}. */
9
9
  buildProjectFile(scene: Scene, filePath: string, arkFile: ArkFile): void;
10
+ /**
11
+ * Imports-only build for a single ArkTS file: fills ImportInfo/ExportInfo
12
+ * without building ArkClass/ArkMethod/ArkBody.
13
+ */
14
+ buildProjectFileForImports(arkFile: ArkFile): void;
15
+ /**
16
+ * Signatures-only upgrade for a single ArkTS file whose ImportInfo/ExportInfo were already
17
+ * populated by {@link buildProjectFileForImports}. Builds ArkClass/ArkMethod/ArkNamespace
18
+ * signatures on top, skipping the import/export branches to avoid duplicating `export *`.
19
+ */
20
+ buildProjectFileForSignatures(arkFile: ArkFile): void;
10
21
  /**
11
22
  * Non-project SDK file load (e.g. OpenHarmony SDK sources); mirrors the former {@link Scene} path for SDK files.
12
23
  */
@@ -1 +1 @@
1
- {"version":3,"file":"ArktsFrontend.d.ts","sourceRoot":"","sources":["../../../src/frontend/arktsFrontend/ArktsFrontend.ts"],"names":[],"mappings":"AAeA,OAAO,EAAE,KAAK,EAAE,MAAM,aAAa,CAAC;AACpC,OAAO,EAAE,OAAO,EAAE,MAAM,0BAA0B,CAAC;AAEnD,OAAO,EAAwB,mBAAmB,EAAE,MAAM,oBAAoB,CAAC;AAI/E;;GAEG;AACH,qBAAa,aAAa;IAEtB,qGAAqG;IAC9F,gBAAgB,CAAC,KAAK,EAAE,KAAK,EAAE,QAAQ,EAAE,MAAM,EAAE,OAAO,EAAE,OAAO,GAAG,IAAI;IAI/E;;OAEG;WACW,uBAAuB,CAAC,gBAAgB,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,MAAM,GAAG,IAAI;IAIlH,iBAAiB,CAAC,KAAK,EAAE,KAAK,EAAE,SAAS,EAAE,MAAM,EAAE,GAAG,mBAAmB;CAenF"}
1
+ {"version":3,"file":"ArktsFrontend.d.ts","sourceRoot":"","sources":["../../../src/frontend/arktsFrontend/ArktsFrontend.ts"],"names":[],"mappings":"AAeA,OAAO,EAAE,KAAK,EAAE,MAAM,aAAa,CAAC;AACpC,OAAO,EAAE,OAAO,EAAE,MAAM,0BAA0B,CAAC;AAEnD,OAAO,EAAwB,mBAAmB,EAAE,MAAM,oBAAoB,CAAC;AAG/E;;GAEG;AACH,qBAAa,aAAa;IACtB,qGAAqG;IAC9F,gBAAgB,CAAC,KAAK,EAAE,KAAK,EAAE,QAAQ,EAAE,MAAM,EAAE,OAAO,EAAE,OAAO,GAAG,IAAI;IAI/E;;;OAGG;IACI,0BAA0B,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI;IAIzD;;;;OAIG;IACI,6BAA6B,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI;IAI5D;;OAEG;WACW,uBAAuB,CAAC,gBAAgB,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,MAAM,GAAG,IAAI;IAIlH,iBAAiB,CAAC,KAAK,EAAE,KAAK,EAAE,SAAS,EAAE,MAAM,EAAE,GAAG,mBAAmB;CAenF"}
@@ -26,6 +26,21 @@ class ArktsFrontend {
26
26
  buildProjectFile(scene, filePath, arkFile) {
27
27
  (0, ArkFileBuilder_1.buildArkFileFromFile)(filePath, scene.getRealProjectDir(), arkFile, scene.getProjectName());
28
28
  }
29
+ /**
30
+ * Imports-only build for a single ArkTS file: fills ImportInfo/ExportInfo
31
+ * without building ArkClass/ArkMethod/ArkBody.
32
+ */
33
+ buildProjectFileForImports(arkFile) {
34
+ (0, ArkFileBuilder_1.buildImportExportInfoFromFile)(arkFile);
35
+ }
36
+ /**
37
+ * Signatures-only upgrade for a single ArkTS file whose ImportInfo/ExportInfo were already
38
+ * populated by {@link buildProjectFileForImports}. Builds ArkClass/ArkMethod/ArkNamespace
39
+ * signatures on top, skipping the import/export branches to avoid duplicating `export *`.
40
+ */
41
+ buildProjectFileForSignatures(arkFile) {
42
+ (0, ArkFileBuilder_1.buildArkFileSignaturesFromFile)(arkFile);
43
+ }
29
44
  /**
30
45
  * Non-project SDK file load (e.g. OpenHarmony SDK sources); mirrors the former {@link Scene} path for SDK files.
31
46
  */
@@ -0,0 +1,62 @@
1
+ import type { SceneOptions } from '../../Config';
2
+ /**
3
+ * Monitors process memory usage (heapUsed) and determines whether the memory limit has been exceeded.
4
+ *
5
+ * Uses heapUsed (V8 heap used) as the memory metric for cache management. The configured RSS limit
6
+ * ({@link SceneOptions.memoryLimitMB}) is converted to a heapUsed limit via {@link RSS_TO_HEAPUSED_RATIO}.
7
+ *
8
+ * Sampling is throttled: if the last sample was taken less than {@link THROTTLE_MS}
9
+ * milliseconds ago, the cached result is reused to avoid excessive
10
+ * `process.memoryUsage()` calls during rapid module loading.
11
+ *
12
+ * Configuration is read from {@link SceneOptions}:
13
+ * - `memoryLimitMB`: max process memory (RSS) in MB; 0 or undefined disables monitoring.
14
+ * Internally converted to a heapUsed limit: `heapUsedLimit = memoryLimitMB * 1024 * 1024 * RSS_TO_HEAPUSED_RATIO`.
15
+ *
16
+ * @category frontend/common
17
+ */
18
+ export declare class MemoryMonitor {
19
+ private readonly heapUsedLimitBytes;
20
+ private lastSampleTime;
21
+ private cachedUsage;
22
+ /** Minimum interval between consecutive memory samples, in milliseconds. */
23
+ private static readonly THROTTLE_MS;
24
+ /**
25
+ * Ratio for converting an RSS-based memory limit to a heapUsed-based limit.
26
+ * Calibrated from scene_board_ext BODIES-level run (no eviction, no GC):
27
+ * P50 of heapUsed/RSS = 0.911, rounded down to 0.85 for extra safety margin
28
+ * to reduce OOM risk when node --max-old-space-size is close to memoryLimitMB.
29
+ */
30
+ private static readonly RSS_TO_HEAPUSED_RATIO;
31
+ constructor(options?: SceneOptions);
32
+ /** Whether memory monitoring is enabled (memoryLimitMB > 0). */
33
+ isEnabled(): boolean;
34
+ /** Returns the heapUsed limit in bytes (converted from the RSS-based memoryLimitMB). */
35
+ getHeapUsedLimitBytes(): number;
36
+ /**
37
+ * Check whether the current heapUsed exceeds the memory limit.
38
+ *
39
+ * Sampling is throttled: calls within {@link THROTTLE_MS} of the last sample
40
+ * return the cached result.
41
+ */
42
+ isHeapUsedOverLimit(): boolean;
43
+ /**
44
+ * Check whether the current heapUsed exceeds the given target value.
45
+ *
46
+ * Sampling is throttled: calls within {@link THROTTLE_MS} of the last sample
47
+ * return the cached result.
48
+ */
49
+ isHeapUsedOverTarget(targetBytes: number): boolean;
50
+ /**
51
+ * Get the current heapUsed in bytes, bypassing the throttle for one-shot measurements.
52
+ *
53
+ * Unlike {@link isHeapUsedOverTarget} / {@link isHeapUsedOverLimit} (which use throttled sampling),
54
+ * this method always calls `process.memoryUsage()` directly. It is intended for
55
+ * one-shot measurements such as heapUsed recording before/after module loading and
56
+ * real-time heapUsed checks during eviction (each unload/downgrade calls this to
57
+ * decide whether more eviction is needed).
58
+ */
59
+ getCurrentHeapUsed(): number;
60
+ private getUsage;
61
+ }
62
+ //# sourceMappingURL=MemoryMonitor.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"MemoryMonitor.d.ts","sourceRoot":"","sources":["../../../src/frontend/common/MemoryMonitor.ts"],"names":[],"mappings":"AAeA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,cAAc,CAAC;AAEjD;;;;;;;;;;;;;;;GAeG;AACH,qBAAa,aAAa;IACtB,OAAO,CAAC,QAAQ,CAAC,kBAAkB,CAAS;IAC5C,OAAO,CAAC,cAAc,CAAa;IACnC,OAAO,CAAC,WAAW,CAAkD;IAErE,4EAA4E;IAC5E,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,WAAW,CAAM;IAEzC;;;;;OAKG;IACH,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,qBAAqB,CAAQ;gBAEzC,OAAO,CAAC,EAAE,YAAY;IAOlC,gEAAgE;IACzD,SAAS,IAAI,OAAO;IAI3B,wFAAwF;IACjF,qBAAqB,IAAI,MAAM;IAItC;;;;;OAKG;IACI,mBAAmB,IAAI,OAAO;IAOrC;;;;;OAKG;IACI,oBAAoB,CAAC,WAAW,EAAE,MAAM,GAAG,OAAO;IAOzD;;;;;;;;OAQG;IACI,kBAAkB,IAAI,MAAM;IAInC,OAAO,CAAC,QAAQ;CAUnB"}
@@ -0,0 +1,108 @@
1
+ "use strict";
2
+ /*
3
+ * Copyright (c) 2026 Huawei Device Co., Ltd.
4
+ * Licensed under the Apache License, Version 2.0 (the "License");
5
+ * you may not use this file except in compliance with the License.
6
+ * You may obtain a copy of the License at
7
+ *
8
+ * http://www.apache.org/licenses/LICENSE-2.0
9
+ *
10
+ * Unless required by applicable law or agreed to in writing, software
11
+ * distributed under the License is distributed on an "AS IS" BASIS,
12
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ * See the License for the specific language governing permissions and
14
+ * limitations under the License.
15
+ */
16
+ Object.defineProperty(exports, "__esModule", { value: true });
17
+ exports.MemoryMonitor = void 0;
18
+ /**
19
+ * Monitors process memory usage (heapUsed) and determines whether the memory limit has been exceeded.
20
+ *
21
+ * Uses heapUsed (V8 heap used) as the memory metric for cache management. The configured RSS limit
22
+ * ({@link SceneOptions.memoryLimitMB}) is converted to a heapUsed limit via {@link RSS_TO_HEAPUSED_RATIO}.
23
+ *
24
+ * Sampling is throttled: if the last sample was taken less than {@link THROTTLE_MS}
25
+ * milliseconds ago, the cached result is reused to avoid excessive
26
+ * `process.memoryUsage()` calls during rapid module loading.
27
+ *
28
+ * Configuration is read from {@link SceneOptions}:
29
+ * - `memoryLimitMB`: max process memory (RSS) in MB; 0 or undefined disables monitoring.
30
+ * Internally converted to a heapUsed limit: `heapUsedLimit = memoryLimitMB * 1024 * 1024 * RSS_TO_HEAPUSED_RATIO`.
31
+ *
32
+ * @category frontend/common
33
+ */
34
+ class MemoryMonitor {
35
+ constructor(options) {
36
+ var _a;
37
+ this.lastSampleTime = 0;
38
+ this.cachedUsage = null;
39
+ const limitMB = (_a = options === null || options === void 0 ? void 0 : options.memoryLimitMB) !== null && _a !== void 0 ? _a : 0;
40
+ this.heapUsedLimitBytes = limitMB > 0
41
+ ? Math.floor(limitMB * 1024 * 1024 * MemoryMonitor.RSS_TO_HEAPUSED_RATIO)
42
+ : 0;
43
+ }
44
+ /** Whether memory monitoring is enabled (memoryLimitMB > 0). */
45
+ isEnabled() {
46
+ return this.heapUsedLimitBytes > 0;
47
+ }
48
+ /** Returns the heapUsed limit in bytes (converted from the RSS-based memoryLimitMB). */
49
+ getHeapUsedLimitBytes() {
50
+ return this.heapUsedLimitBytes;
51
+ }
52
+ /**
53
+ * Check whether the current heapUsed exceeds the memory limit.
54
+ *
55
+ * Sampling is throttled: calls within {@link THROTTLE_MS} of the last sample
56
+ * return the cached result.
57
+ */
58
+ isHeapUsedOverLimit() {
59
+ if (!this.isEnabled()) {
60
+ return false;
61
+ }
62
+ return this.getUsage().heapUsed >= this.heapUsedLimitBytes;
63
+ }
64
+ /**
65
+ * Check whether the current heapUsed exceeds the given target value.
66
+ *
67
+ * Sampling is throttled: calls within {@link THROTTLE_MS} of the last sample
68
+ * return the cached result.
69
+ */
70
+ isHeapUsedOverTarget(targetBytes) {
71
+ if (!this.isEnabled()) {
72
+ return false;
73
+ }
74
+ return this.getUsage().heapUsed >= targetBytes;
75
+ }
76
+ /**
77
+ * Get the current heapUsed in bytes, bypassing the throttle for one-shot measurements.
78
+ *
79
+ * Unlike {@link isHeapUsedOverTarget} / {@link isHeapUsedOverLimit} (which use throttled sampling),
80
+ * this method always calls `process.memoryUsage()` directly. It is intended for
81
+ * one-shot measurements such as heapUsed recording before/after module loading and
82
+ * real-time heapUsed checks during eviction (each unload/downgrade calls this to
83
+ * decide whether more eviction is needed).
84
+ */
85
+ getCurrentHeapUsed() {
86
+ return process.memoryUsage().heapUsed;
87
+ }
88
+ getUsage() {
89
+ const now = Date.now();
90
+ if (this.cachedUsage && now - this.lastSampleTime < MemoryMonitor.THROTTLE_MS) {
91
+ return this.cachedUsage;
92
+ }
93
+ this.lastSampleTime = now;
94
+ const usage = process.memoryUsage();
95
+ this.cachedUsage = { rss: usage.rss, heapUsed: usage.heapUsed };
96
+ return this.cachedUsage;
97
+ }
98
+ }
99
+ exports.MemoryMonitor = MemoryMonitor;
100
+ /** Minimum interval between consecutive memory samples, in milliseconds. */
101
+ MemoryMonitor.THROTTLE_MS = 50;
102
+ /**
103
+ * Ratio for converting an RSS-based memory limit to a heapUsed-based limit.
104
+ * Calibrated from scene_board_ext BODIES-level run (no eviction, no GC):
105
+ * P50 of heapUsed/RSS = 0.911, rounded down to 0.85 for extra safety margin
106
+ * to reduce OOM risk when node --max-old-space-size is close to memoryLimitMB.
107
+ */
108
+ MemoryMonitor.RSS_TO_HEAPUSED_RATIO = 0.85;