• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1/*
2 * Copyright (c) 2025 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 *     http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16import * as fs from 'fs';
17import * as ts from 'typescript';
18
19export interface CompileEvent {
20  createSubEvent?: (eventName: string) => CompileEvent;
21  createEvent: (eventName: string) => CompileEvent;
22  startAsyncEvent?: () => void;
23  start: () => void;
24  stopAsyncEvent?: () => void;
25  stop: () => void;
26  setTotalTime: (time: number) => void;
27}
28
29interface Event {
30  // id: Unique identifier of the event.
31  id: string;
32  // name: The name of the event. Duplicates exist.
33  name: string;
34  startTime: number;
35  endTime: number;
36  parentEvent: string;
37  parentId: string;
38  duration: number;
39}
40
41export enum AnalyzeMode {
42  DEFAULT,
43  VERBOSE,
44  FALSE,
45  TRACE
46}
47
48export enum ExternalEventType {
49  TSC,
50  ES2ABC
51}
52
53let asyncEvents: Map<string, CompileEvent> = new Map();
54
55export function isNeedPerformanceDotting(projectConfig: Object): boolean {
56  return projectConfig.perf === AnalyzeMode.TRACE || projectConfig.perf === AnalyzeMode.VERBOSE;
57}
58
59export function getHookEventFactory(share: Object, pluginName: string, hookName: string): CompileEvent | undefined {
60  if (typeof share.getHookEventFactory === 'function' && isNeedPerformanceDotting(share.projectConfig)) {
61    return share.getHookEventFactory(pluginName, hookName);
62  } else {
63    return undefined;
64  }
65}
66
67export function createAndStartEvent(eventOrEventFactory: CompileEvent | undefined, eventName: string,
68  isAsyncEvent = false): CompileEvent | undefined {
69  if (eventOrEventFactory === undefined || eventOrEventFactory === null) {
70    return undefined;
71  }
72  let event: CompileEvent;
73  if (isSubEvent(eventOrEventFactory)) {
74    event = eventOrEventFactory.createSubEvent(eventName);
75  } else {
76    event = eventOrEventFactory.createEvent(eventName);
77  }
78  if (isAsyncEvent) {
79    event.startAsyncEvent();
80  } else {
81    event.start();
82  }
83  return event;
84}
85
86function isSubEvent(event: CompileEvent): boolean {
87  return typeof event.createSubEvent === 'function';
88}
89
90export function stopEvent(event: CompileEvent | undefined, isAsyncEvent: boolean = false): void {
91  if (event === undefined || event === null) {
92    return;
93  }
94  if (isAsyncEvent) {
95    event.stopAsyncEvent();
96  } else {
97    event.stop();
98  }
99}
100
101export function processExternalEvents(projectConfig: Object, eventType: number, externalEventsInfo: Object): void {
102  if (!isNeedPerformanceDotting(projectConfig)) {
103    return;
104  }
105  const isTsc: boolean = isTscEvents(eventType);
106  const { parentEvent, filePath } = externalEventsInfo;
107  let events: Event[] = isTsc ? ts.PerformanceDotting.getEventData() :
108    (fs.existsSync(filePath) ? JSON.parse(fs.readFileSync(filePath, 'utf-8')) : []);
109  if (events && events.length) {
110    events = events.sort((a, b) => a.startTime - b.startTime);
111    asyncEvents.set(isTsc ? events[0].parentId : events[0].parentEvent, parentEvent);
112    for (const event of events) {
113      setTotalTime(event, isTsc);
114    }
115  }
116  asyncEvents.clear();
117}
118
119function isTscEvents(eventType: number): boolean {
120  return eventType === ExternalEventType.TSC;
121}
122
123function setTotalTime(event: Event, isTsc: boolean): void {
124  const parentEvent: CompileEvent | undefined = getCurrentAsyncEvent(isTsc ? event.parentId : event.parentEvent);
125  if (parentEvent) {
126    const subEvent: CompileEvent = parentEvent.createSubEvent(event.name);
127    subEvent.start();
128    subEvent.stop();
129    subEvent.setTotalTime(event.duration);
130    asyncEvents.set(isTsc ? event.id : event.name, subEvent);
131  }
132}
133
134function getCurrentAsyncEvent(eventName): CompileEvent | undefined {
135  if (asyncEvents && asyncEvents.has(eventName)) {
136    return asyncEvents.get(eventName);
137  }
138  return undefined;
139}
140
141export function cleanUpAsyncEvents(): void {
142  asyncEvents.clear();
143}