-
Notifications
You must be signed in to change notification settings - Fork 4.3k
/
implementation.js
220 lines (206 loc) · 6.43 KB
/
implementation.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
/**
* wordpress/private-apis – the utilities to enable private cross-package
* exports of private APIs.
*
* This "implementation.js" file is needed for the sake of the unit tests. It
* exports more than the public API of the package to aid in testing.
*/
/**
* The list of core modules allowed to opt-in to the private APIs.
*/
const CORE_MODULES_USING_PRIVATE_APIS = [
'@wordpress/block-editor',
'@wordpress/block-library',
'@wordpress/blocks',
'@wordpress/components',
'@wordpress/customize-widgets',
'@wordpress/data',
'@wordpress/edit-post',
'@wordpress/edit-site',
'@wordpress/edit-widgets',
'@wordpress/editor',
];
/**
* A list of core modules that already opted-in to
* the privateApis package.
*
* @type {string[]}
*/
const registeredPrivateApis = [];
/*
* Warning for theme and plugin developers.
*
* The use of private developer APIs is intended for use by WordPress Core
* and the Gutenberg plugin exclusively.
*
* Dangerously opting in to using these APIs is NOT RECOMMENDED. Furthermore,
* the WordPress Core philosophy to strive to maintain backward compatibility
* for third-party developers DOES NOT APPLY to private APIs.
*
* THE CONSENT STRING FOR OPTING IN TO THESE APIS MAY CHANGE AT ANY TIME AND
* WITHOUT NOTICE. THIS CHANGE WILL BREAK EXISTING THIRD-PARTY CODE. SUCH A
* CHANGE MAY OCCUR IN EITHER A MAJOR OR MINOR RELEASE.
*/
const requiredConsent =
'I know using unstable features means my plugin or theme will inevitably break on the next WordPress release.';
/** @type {boolean} */
let allowReRegistration;
// Use try/catch to force "false" if the environment variable is not explicitly
// set to true (e.g. when building WordPress core).
try {
allowReRegistration = process.env.ALLOW_EXPERIMENT_REREGISTRATION ?? false;
} catch ( error ) {
allowReRegistration = false;
}
/**
* Called by a @wordpress package wishing to opt-in to accessing or exposing
* private private APIs.
*
* @param {string} consent The consent string.
* @param {string} moduleName The name of the module that is opting in.
* @return {{lock: typeof lock, unlock: typeof unlock}} An object containing the lock and unlock functions.
*/
export const __dangerousOptInToUnstableAPIsOnlyForCoreModules = (
consent,
moduleName
) => {
if ( ! CORE_MODULES_USING_PRIVATE_APIS.includes( moduleName ) ) {
throw new Error(
`You tried to opt-in to unstable APIs as module "${ moduleName }". ` +
'This feature is only for JavaScript modules shipped with WordPress core. ' +
'Please do not use it in plugins and themes as the unstable APIs will be removed ' +
'without a warning. If you ignore this error and depend on unstable features, ' +
'your product will inevitably break on one of the next WordPress releases.'
);
}
if (
! allowReRegistration &&
registeredPrivateApis.includes( moduleName )
) {
// This check doesn't play well with Story Books / Hot Module Reloading
// and isn't included in the Gutenberg plugin. It only matters in the
// WordPress core release.
throw new Error(
`You tried to opt-in to unstable APIs as module "${ moduleName }" which is already registered. ` +
'This feature is only for JavaScript modules shipped with WordPress core. ' +
'Please do not use it in plugins and themes as the unstable APIs will be removed ' +
'without a warning. If you ignore this error and depend on unstable features, ' +
'your product will inevitably break on one of the next WordPress releases.'
);
}
if ( consent !== requiredConsent ) {
throw new Error(
`You tried to opt-in to unstable APIs without confirming you know the consequences. ` +
'This feature is only for JavaScript modules shipped with WordPress core. ' +
'Please do not use it in plugins and themes as the unstable APIs will removed ' +
'without a warning. If you ignore this error and depend on unstable features, ' +
'your product will inevitably break on the next WordPress release.'
);
}
registeredPrivateApis.push( moduleName );
return {
lock,
unlock,
};
};
/**
* Binds private data to an object.
* It does not alter the passed object in any way, only
* registers it in an internal map of private data.
*
* The private data can't be accessed by any other means
* than the `unlock` function.
*
* @example
* ```js
* const object = {};
* const privateData = { a: 1 };
* lock( object, privateData );
*
* object
* // {}
*
* unlock( object );
* // { a: 1 }
* ```
*
* @param {any} object The object to bind the private data to.
* @param {any} privateData The private data to bind to the object.
*/
function lock( object, privateData ) {
if ( ! object ) {
throw new Error( 'Cannot lock an undefined object.' );
}
if ( ! ( __private in object ) ) {
object[ __private ] = {};
}
lockedData.set( object[ __private ], privateData );
}
/**
* Unlocks the private data bound to an object.
*
* It does not alter the passed object in any way, only
* returns the private data paired with it using the `lock()`
* function.
*
* @example
* ```js
* const object = {};
* const privateData = { a: 1 };
* lock( object, privateData );
*
* object
* // {}
*
* unlock( object );
* // { a: 1 }
* ```
*
* @param {any} object The object to unlock the private data from.
* @return {any} The private data bound to the object.
*/
function unlock( object ) {
if ( ! object ) {
throw new Error( 'Cannot unlock an undefined object.' );
}
if ( ! ( __private in object ) ) {
throw new Error(
'Cannot unlock an object that was not locked before. '
);
}
return lockedData.get( object[ __private ] );
}
const lockedData = new WeakMap();
/**
* Used by lock() and unlock() to uniquely identify the private data
* related to a containing object.
*/
const __private = Symbol( 'Private API ID' );
// Unit tests utilities:
/**
* Private function to allow the unit tests to allow
* a mock module to access the private APIs.
*
* @param {string} name The name of the module.
*/
export function allowCoreModule( name ) {
CORE_MODULES_USING_PRIVATE_APIS.push( name );
}
/**
* Private function to allow the unit tests to set
* a custom list of allowed modules.
*/
export function resetAllowedCoreModules() {
while ( CORE_MODULES_USING_PRIVATE_APIS.length ) {
CORE_MODULES_USING_PRIVATE_APIS.pop();
}
}
/**
* Private function to allow the unit tests to reset
* the list of registered private apis.
*/
export function resetRegisteredPrivateApis() {
while ( registeredPrivateApis.length ) {
registeredPrivateApis.pop();
}
}