@@ -6,6 +6,13 @@ createPhase19OverlayPluginRegistry.js
66*/
77import createPhase19OverlayExpansionFramework from '/samples/phase-19/shared/overlay/createPhase19OverlayExpansionFramework.js' ;
88
9+ const PLUGIN_STATES = Object . freeze ( {
10+ REGISTERED : 'registered' ,
11+ INITIALIZED : 'initialized' ,
12+ ACTIVE : 'active' ,
13+ INACTIVE : 'inactive' ,
14+ } ) ;
15+
916function normalizePluginId ( pluginId ) {
1017 return String ( pluginId || '' ) . trim ( ) ;
1118}
@@ -35,6 +42,16 @@ function normalizePluginDefinition(plugin) {
3542 id,
3643 version : String ( plugin . version || '' ) . trim ( ) ,
3744 metadata : Object . freeze ( { ...( plugin . metadata || { } ) } ) ,
45+ init : typeof plugin . init === 'function' ? plugin . init : ( typeof plugin . onInit === 'function' ? plugin . onInit : null ) ,
46+ activate : typeof plugin . activate === 'function'
47+ ? plugin . activate
48+ : ( typeof plugin . onActivate === 'function' ? plugin . onActivate : null ) ,
49+ deactivate : typeof plugin . deactivate === 'function'
50+ ? plugin . deactivate
51+ : ( typeof plugin . onDeactivate === 'function' ? plugin . onDeactivate : null ) ,
52+ destroy : typeof plugin . destroy === 'function'
53+ ? plugin . destroy
54+ : ( typeof plugin . onDestroy === 'function' ? plugin . onDestroy : null ) ,
3855 createOverlayExtension,
3956 extension,
4057 } ) ;
@@ -58,14 +75,133 @@ export default function createPhase19OverlayPluginRegistry({
5875 expansionFramework = createPhase19OverlayExpansionFramework ( ) ,
5976 plugins = [ ] ,
6077} = { } ) {
61- const pluginMap = new Map ( ) ;
62- const pluginExtensionMap = new Map ( ) ;
78+ const pluginRecordMap = new Map ( ) ;
6379 let api = null ;
6480
65- function registerPlugin ( plugin , context = { } ) {
81+ function getPluginRecord ( pluginId ) {
82+ const normalizedPluginId = normalizePluginId ( pluginId ) ;
83+ if ( ! normalizedPluginId ) {
84+ return null ;
85+ }
86+ return pluginRecordMap . get ( normalizedPluginId ) ?? null ;
87+ }
88+
89+ function runLifecycleHook ( record , phase , context = { } ) {
90+ const hook = record ?. plugin ?. [ phase ] ;
91+ if ( typeof hook !== 'function' ) {
92+ return true ;
93+ }
94+ try {
95+ hook ( {
96+ ...context ,
97+ phase,
98+ pluginId : record . plugin . id ,
99+ extensionId : record . extension . id ,
100+ registry : api ,
101+ expansionFramework,
102+ } ) ;
103+ return true ;
104+ } catch {
105+ return false ;
106+ }
107+ }
108+
109+ function initPlugin ( pluginId , context = { } ) {
110+ const record = getPluginRecord ( pluginId ) ;
111+ if ( ! record ) {
112+ return false ;
113+ }
114+ if ( record . state === PLUGIN_STATES . INITIALIZED || record . state === PLUGIN_STATES . ACTIVE || record . state === PLUGIN_STATES . INACTIVE ) {
115+ return false ;
116+ }
117+ if ( record . state !== PLUGIN_STATES . REGISTERED ) {
118+ return false ;
119+ }
120+ if ( ! runLifecycleHook ( record , 'init' , context ) ) {
121+ return false ;
122+ }
123+ record . state = PLUGIN_STATES . INITIALIZED ;
124+ return true ;
125+ }
126+
127+ function activatePlugin ( pluginId , context = { } ) {
128+ const record = getPluginRecord ( pluginId ) ;
129+ if ( ! record ) {
130+ return false ;
131+ }
132+ if ( record . state === PLUGIN_STATES . ACTIVE ) {
133+ return false ;
134+ }
135+ if ( record . state === PLUGIN_STATES . REGISTERED ) {
136+ if ( ! initPlugin ( pluginId , context ) ) {
137+ return false ;
138+ }
139+ }
140+ if ( record . state !== PLUGIN_STATES . INITIALIZED && record . state !== PLUGIN_STATES . INACTIVE ) {
141+ return false ;
142+ }
143+
144+ const registered = expansionFramework . registerExtension ( record . extension ) ;
145+ if ( ! registered || ! registered . id ) {
146+ return false ;
147+ }
148+
149+ if ( ! runLifecycleHook ( record , 'activate' , context ) ) {
150+ expansionFramework . unregisterExtension ( record . extension . id ) ;
151+ return false ;
152+ }
153+
154+ record . state = PLUGIN_STATES . ACTIVE ;
155+ return true ;
156+ }
157+
158+ function deactivatePlugin ( pluginId , context = { } ) {
159+ const record = getPluginRecord ( pluginId ) ;
160+ if ( ! record ) {
161+ return false ;
162+ }
163+ if ( record . state !== PLUGIN_STATES . ACTIVE ) {
164+ return false ;
165+ }
166+ if ( ! runLifecycleHook ( record , 'deactivate' , context ) ) {
167+ return false ;
168+ }
169+
170+ expansionFramework . unregisterExtension ( record . extension . id ) ;
171+ record . state = PLUGIN_STATES . INACTIVE ;
172+ return true ;
173+ }
174+
175+ function destroyPlugin ( pluginId , context = { } ) {
176+ const normalizedPluginId = normalizePluginId ( pluginId ) ;
177+ const record = getPluginRecord ( normalizedPluginId ) ;
178+ if ( ! record ) {
179+ return false ;
180+ }
181+ if ( record . state === PLUGIN_STATES . ACTIVE ) {
182+ if ( ! deactivatePlugin ( normalizedPluginId , context ) ) {
183+ return false ;
184+ }
185+ }
186+ if ( ! runLifecycleHook ( record , 'destroy' , context ) ) {
187+ return false ;
188+ }
189+
190+ expansionFramework . unregisterExtension ( record . extension . id ) ;
191+ pluginRecordMap . delete ( normalizedPluginId ) ;
192+ return true ;
193+ }
194+
195+ function registerPlugin ( plugin , options = { } ) {
196+ const context = options ?. context || { } ;
197+ const autoActivate = options ?. autoActivate !== false ;
66198 const normalizedPlugin = normalizePluginDefinition ( plugin ) ;
67199 const pluginId = normalizedPlugin . id ;
68200
201+ if ( pluginRecordMap . has ( pluginId ) ) {
202+ destroyPlugin ( pluginId , { ...context , reason : 're-register' } ) ;
203+ }
204+
69205 const resolvedExtension = normalizePluginExtension (
70206 normalizedPlugin ,
71207 normalizedPlugin . createOverlayExtension
@@ -78,70 +214,70 @@ export default function createPhase19OverlayPluginRegistry({
78214 : normalizedPlugin . extension
79215 ) ;
80216
81- const existingExtensionId = pluginExtensionMap . get ( pluginId ) ;
82- if ( existingExtensionId ) {
83- expansionFramework . unregisterExtension ( existingExtensionId ) ;
84- }
217+ const record = {
218+ plugin : normalizedPlugin ,
219+ extension : resolvedExtension ,
220+ state : PLUGIN_STATES . REGISTERED ,
221+ } ;
222+ pluginRecordMap . set ( pluginId , record ) ;
85223
86- const registeredExtension = expansionFramework . registerExtension ( resolvedExtension ) ;
87- pluginMap . set ( pluginId , normalizedPlugin ) ;
88- pluginExtensionMap . set ( pluginId , registeredExtension . id ) ;
224+ if ( autoActivate ) {
225+ if ( ! activatePlugin ( pluginId , context ) ) {
226+ pluginRecordMap . delete ( pluginId ) ;
227+ throw new Error ( `Overlay plugin "${ pluginId } " failed lifecycle activation.` ) ;
228+ }
229+ }
89230
90231 return Object . freeze ( {
91232 pluginId,
92- extensionId : registeredExtension . id ,
233+ extensionId : resolvedExtension . id ,
93234 } ) ;
94235 }
95236
96- function unregisterPlugin ( pluginId ) {
97- const normalizedPluginId = normalizePluginId ( pluginId ) ;
98- if ( ! normalizedPluginId || ! pluginMap . has ( normalizedPluginId ) ) {
99- return false ;
100- }
101-
102- const extensionId = pluginExtensionMap . get ( normalizedPluginId ) ;
103- if ( extensionId ) {
104- expansionFramework . unregisterExtension ( extensionId ) ;
105- }
106- pluginExtensionMap . delete ( normalizedPluginId ) ;
107- pluginMap . delete ( normalizedPluginId ) ;
108- return true ;
237+ function unregisterPlugin ( pluginId , context = { } ) {
238+ return destroyPlugin ( pluginId , context ) ;
109239 }
110240
111241 function getPlugin ( pluginId ) {
112- const normalizedPluginId = normalizePluginId ( pluginId ) ;
113- if ( ! normalizedPluginId ) {
114- return null ;
115- }
116- return pluginMap . get ( normalizedPluginId ) ?? null ;
242+ const record = getPluginRecord ( pluginId ) ;
243+ return record ? record . plugin : null ;
244+ }
245+
246+ function getPluginState ( pluginId ) {
247+ const record = getPluginRecord ( pluginId ) ;
248+ return record ?. state || '' ;
117249 }
118250
119251 function getPluginExtensionId ( pluginId ) {
120- const normalizedPluginId = normalizePluginId ( pluginId ) ;
121- if ( ! normalizedPluginId ) {
122- return '' ;
123- }
124- return pluginExtensionMap . get ( normalizedPluginId ) || '' ;
252+ const record = getPluginRecord ( pluginId ) ;
253+ return record ?. extension ?. id || '' ;
125254 }
126255
127256 function listPlugins ( ) {
128257 const entries = [ ] ;
129- for ( const [ pluginId , plugin ] of pluginMap . entries ( ) ) {
258+ for ( const [ pluginId , record ] of pluginRecordMap . entries ( ) ) {
130259 entries . push ( {
131260 id : pluginId ,
132- version : plugin . version ,
133- extensionId : pluginExtensionMap . get ( pluginId ) || '' ,
261+ version : record . plugin . version ,
262+ extensionId : record . extension . id ,
263+ state : record . state ,
134264 } ) ;
135265 }
136266 return Object . freeze ( entries ) ;
137267 }
138268
139269 api = {
140270 registerPlugin,
271+ initPlugin,
272+ activatePlugin,
273+ deactivatePlugin,
274+ destroyPlugin,
141275 unregisterPlugin,
142276 getPlugin,
277+ getPluginState,
143278 getPluginExtensionId,
144279 listPlugins,
280+ states : PLUGIN_STATES ,
145281 getFramework ( ) {
146282 return expansionFramework ;
147283 } ,
0 commit comments