@wordpress/private-apis 0.8.1
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.
- package/CHANGELOG.md +21 -0
- package/LICENSE.md +788 -0
- package/README.md +98 -0
- package/build/implementation.js +208 -0
- package/build/implementation.js.map +1 -0
- package/build/index.js +14 -0
- package/build/index.js.map +1 -0
- package/build-module/implementation.js +193 -0
- package/build-module/implementation.js.map +1 -0
- package/build-module/index.js +2 -0
- package/build-module/index.js.map +1 -0
- package/build-types/implementation.d.ts +72 -0
- package/build-types/implementation.d.ts.map +1 -0
- package/build-types/index.d.ts +2 -0
- package/build-types/index.d.ts.map +1 -0
- package/package.json +37 -0
- package/src/implementation.js +220 -0
- package/src/index.js +1 -0
- package/src/test/index.js +308 -0
- package/tsconfig.json +12 -0
- package/tsconfig.tsbuildinfo +1 -0
package/package.json
ADDED
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@wordpress/private-apis",
|
|
3
|
+
"version": "0.8.1",
|
|
4
|
+
"description": "Internal experimental APIs for WordPress core.",
|
|
5
|
+
"author": "The WordPress Contributors",
|
|
6
|
+
"license": "GPL-2.0-or-later",
|
|
7
|
+
"keywords": [
|
|
8
|
+
"wordpress",
|
|
9
|
+
"gutenberg",
|
|
10
|
+
"dom",
|
|
11
|
+
"utils"
|
|
12
|
+
],
|
|
13
|
+
"homepage": "https://github.com/WordPress/gutenberg/tree/HEAD/packages/private-apis/README.md",
|
|
14
|
+
"repository": {
|
|
15
|
+
"type": "git",
|
|
16
|
+
"url": "https://github.com/WordPress/gutenberg.git",
|
|
17
|
+
"directory": "packages/private-apis"
|
|
18
|
+
},
|
|
19
|
+
"bugs": {
|
|
20
|
+
"url": "https://github.com/WordPress/gutenberg/issues"
|
|
21
|
+
},
|
|
22
|
+
"engines": {
|
|
23
|
+
"node": ">=12"
|
|
24
|
+
},
|
|
25
|
+
"main": "build/index.js",
|
|
26
|
+
"module": "build-module/index.js",
|
|
27
|
+
"react-native": "src/index",
|
|
28
|
+
"types": "build-types",
|
|
29
|
+
"sideEffects": false,
|
|
30
|
+
"dependencies": {
|
|
31
|
+
"@babel/runtime": "^7.16.0"
|
|
32
|
+
},
|
|
33
|
+
"publishConfig": {
|
|
34
|
+
"access": "public"
|
|
35
|
+
},
|
|
36
|
+
"gitHead": "1bf01c01a8238ce3a681ad1e517f86033818b78d"
|
|
37
|
+
}
|
|
@@ -0,0 +1,220 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* wordpress/private-apis – the utilities to enable private cross-package
|
|
3
|
+
* exports of private APIs.
|
|
4
|
+
*
|
|
5
|
+
* This "implementation.js" file is needed for the sake of the unit tests. It
|
|
6
|
+
* exports more than the public API of the package to aid in testing.
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* The list of core modules allowed to opt-in to the private APIs.
|
|
11
|
+
*/
|
|
12
|
+
const CORE_MODULES_USING_PRIVATE_APIS = [
|
|
13
|
+
'@wordpress/block-editor',
|
|
14
|
+
'@wordpress/block-library',
|
|
15
|
+
'@wordpress/blocks',
|
|
16
|
+
'@wordpress/components',
|
|
17
|
+
'@wordpress/customize-widgets',
|
|
18
|
+
'@wordpress/data',
|
|
19
|
+
'@wordpress/edit-post',
|
|
20
|
+
'@wordpress/edit-site',
|
|
21
|
+
'@wordpress/edit-widgets',
|
|
22
|
+
'@wordpress/editor',
|
|
23
|
+
];
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* A list of core modules that already opted-in to
|
|
27
|
+
* the privateApis package.
|
|
28
|
+
*
|
|
29
|
+
* @type {string[]}
|
|
30
|
+
*/
|
|
31
|
+
const registeredPrivateApis = [];
|
|
32
|
+
|
|
33
|
+
/*
|
|
34
|
+
* Warning for theme and plugin developers.
|
|
35
|
+
*
|
|
36
|
+
* The use of private developer APIs is intended for use by WordPress Core
|
|
37
|
+
* and the Gutenberg plugin exclusively.
|
|
38
|
+
*
|
|
39
|
+
* Dangerously opting in to using these APIs is NOT RECOMMENDED. Furthermore,
|
|
40
|
+
* the WordPress Core philosophy to strive to maintain backward compatibility
|
|
41
|
+
* for third-party developers DOES NOT APPLY to private APIs.
|
|
42
|
+
*
|
|
43
|
+
* THE CONSENT STRING FOR OPTING IN TO THESE APIS MAY CHANGE AT ANY TIME AND
|
|
44
|
+
* WITHOUT NOTICE. THIS CHANGE WILL BREAK EXISTING THIRD-PARTY CODE. SUCH A
|
|
45
|
+
* CHANGE MAY OCCUR IN EITHER A MAJOR OR MINOR RELEASE.
|
|
46
|
+
*/
|
|
47
|
+
const requiredConsent =
|
|
48
|
+
'I know using unstable features means my plugin or theme will inevitably break on the next WordPress release.';
|
|
49
|
+
|
|
50
|
+
/** @type {boolean} */
|
|
51
|
+
let allowReRegistration;
|
|
52
|
+
// Use try/catch to force "false" if the environment variable is not explicitly
|
|
53
|
+
// set to true (e.g. when building WordPress core).
|
|
54
|
+
try {
|
|
55
|
+
allowReRegistration = process.env.ALLOW_EXPERIMENT_REREGISTRATION ?? false;
|
|
56
|
+
} catch ( error ) {
|
|
57
|
+
allowReRegistration = false;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
/**
|
|
61
|
+
* Called by a @wordpress package wishing to opt-in to accessing or exposing
|
|
62
|
+
* private private APIs.
|
|
63
|
+
*
|
|
64
|
+
* @param {string} consent The consent string.
|
|
65
|
+
* @param {string} moduleName The name of the module that is opting in.
|
|
66
|
+
* @return {{lock: typeof lock, unlock: typeof unlock}} An object containing the lock and unlock functions.
|
|
67
|
+
*/
|
|
68
|
+
export const __dangerousOptInToUnstableAPIsOnlyForCoreModules = (
|
|
69
|
+
consent,
|
|
70
|
+
moduleName
|
|
71
|
+
) => {
|
|
72
|
+
if ( ! CORE_MODULES_USING_PRIVATE_APIS.includes( moduleName ) ) {
|
|
73
|
+
throw new Error(
|
|
74
|
+
`You tried to opt-in to unstable APIs as module "${ moduleName }". ` +
|
|
75
|
+
'This feature is only for JavaScript modules shipped with WordPress core. ' +
|
|
76
|
+
'Please do not use it in plugins and themes as the unstable APIs will be removed ' +
|
|
77
|
+
'without a warning. If you ignore this error and depend on unstable features, ' +
|
|
78
|
+
'your product will inevitably break on one of the next WordPress releases.'
|
|
79
|
+
);
|
|
80
|
+
}
|
|
81
|
+
if (
|
|
82
|
+
! allowReRegistration &&
|
|
83
|
+
registeredPrivateApis.includes( moduleName )
|
|
84
|
+
) {
|
|
85
|
+
// This check doesn't play well with Story Books / Hot Module Reloading
|
|
86
|
+
// and isn't included in the Gutenberg plugin. It only matters in the
|
|
87
|
+
// WordPress core release.
|
|
88
|
+
throw new Error(
|
|
89
|
+
`You tried to opt-in to unstable APIs as module "${ moduleName }" which is already registered. ` +
|
|
90
|
+
'This feature is only for JavaScript modules shipped with WordPress core. ' +
|
|
91
|
+
'Please do not use it in plugins and themes as the unstable APIs will be removed ' +
|
|
92
|
+
'without a warning. If you ignore this error and depend on unstable features, ' +
|
|
93
|
+
'your product will inevitably break on one of the next WordPress releases.'
|
|
94
|
+
);
|
|
95
|
+
}
|
|
96
|
+
if ( consent !== requiredConsent ) {
|
|
97
|
+
throw new Error(
|
|
98
|
+
`You tried to opt-in to unstable APIs without confirming you know the consequences. ` +
|
|
99
|
+
'This feature is only for JavaScript modules shipped with WordPress core. ' +
|
|
100
|
+
'Please do not use it in plugins and themes as the unstable APIs will removed ' +
|
|
101
|
+
'without a warning. If you ignore this error and depend on unstable features, ' +
|
|
102
|
+
'your product will inevitably break on the next WordPress release.'
|
|
103
|
+
);
|
|
104
|
+
}
|
|
105
|
+
registeredPrivateApis.push( moduleName );
|
|
106
|
+
|
|
107
|
+
return {
|
|
108
|
+
lock,
|
|
109
|
+
unlock,
|
|
110
|
+
};
|
|
111
|
+
};
|
|
112
|
+
|
|
113
|
+
/**
|
|
114
|
+
* Binds private data to an object.
|
|
115
|
+
* It does not alter the passed object in any way, only
|
|
116
|
+
* registers it in an internal map of private data.
|
|
117
|
+
*
|
|
118
|
+
* The private data can't be accessed by any other means
|
|
119
|
+
* than the `unlock` function.
|
|
120
|
+
*
|
|
121
|
+
* @example
|
|
122
|
+
* ```js
|
|
123
|
+
* const object = {};
|
|
124
|
+
* const privateData = { a: 1 };
|
|
125
|
+
* lock( object, privateData );
|
|
126
|
+
*
|
|
127
|
+
* object
|
|
128
|
+
* // {}
|
|
129
|
+
*
|
|
130
|
+
* unlock( object );
|
|
131
|
+
* // { a: 1 }
|
|
132
|
+
* ```
|
|
133
|
+
*
|
|
134
|
+
* @param {any} object The object to bind the private data to.
|
|
135
|
+
* @param {any} privateData The private data to bind to the object.
|
|
136
|
+
*/
|
|
137
|
+
function lock( object, privateData ) {
|
|
138
|
+
if ( ! object ) {
|
|
139
|
+
throw new Error( 'Cannot lock an undefined object.' );
|
|
140
|
+
}
|
|
141
|
+
if ( ! ( __private in object ) ) {
|
|
142
|
+
object[ __private ] = {};
|
|
143
|
+
}
|
|
144
|
+
lockedData.set( object[ __private ], privateData );
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
/**
|
|
148
|
+
* Unlocks the private data bound to an object.
|
|
149
|
+
*
|
|
150
|
+
* It does not alter the passed object in any way, only
|
|
151
|
+
* returns the private data paired with it using the `lock()`
|
|
152
|
+
* function.
|
|
153
|
+
*
|
|
154
|
+
* @example
|
|
155
|
+
* ```js
|
|
156
|
+
* const object = {};
|
|
157
|
+
* const privateData = { a: 1 };
|
|
158
|
+
* lock( object, privateData );
|
|
159
|
+
*
|
|
160
|
+
* object
|
|
161
|
+
* // {}
|
|
162
|
+
*
|
|
163
|
+
* unlock( object );
|
|
164
|
+
* // { a: 1 }
|
|
165
|
+
* ```
|
|
166
|
+
*
|
|
167
|
+
* @param {any} object The object to unlock the private data from.
|
|
168
|
+
* @return {any} The private data bound to the object.
|
|
169
|
+
*/
|
|
170
|
+
function unlock( object ) {
|
|
171
|
+
if ( ! object ) {
|
|
172
|
+
throw new Error( 'Cannot unlock an undefined object.' );
|
|
173
|
+
}
|
|
174
|
+
if ( ! ( __private in object ) ) {
|
|
175
|
+
throw new Error(
|
|
176
|
+
'Cannot unlock an object that was not locked before. '
|
|
177
|
+
);
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
return lockedData.get( object[ __private ] );
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
const lockedData = new WeakMap();
|
|
184
|
+
|
|
185
|
+
/**
|
|
186
|
+
* Used by lock() and unlock() to uniquely identify the private data
|
|
187
|
+
* related to a containing object.
|
|
188
|
+
*/
|
|
189
|
+
const __private = Symbol( 'Private API ID' );
|
|
190
|
+
|
|
191
|
+
// Unit tests utilities:
|
|
192
|
+
|
|
193
|
+
/**
|
|
194
|
+
* Private function to allow the unit tests to allow
|
|
195
|
+
* a mock module to access the private APIs.
|
|
196
|
+
*
|
|
197
|
+
* @param {string} name The name of the module.
|
|
198
|
+
*/
|
|
199
|
+
export function allowCoreModule( name ) {
|
|
200
|
+
CORE_MODULES_USING_PRIVATE_APIS.push( name );
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
/**
|
|
204
|
+
* Private function to allow the unit tests to set
|
|
205
|
+
* a custom list of allowed modules.
|
|
206
|
+
*/
|
|
207
|
+
export function resetAllowedCoreModules() {
|
|
208
|
+
while ( CORE_MODULES_USING_PRIVATE_APIS.length ) {
|
|
209
|
+
CORE_MODULES_USING_PRIVATE_APIS.pop();
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
/**
|
|
213
|
+
* Private function to allow the unit tests to reset
|
|
214
|
+
* the list of registered private apis.
|
|
215
|
+
*/
|
|
216
|
+
export function resetRegisteredPrivateApis() {
|
|
217
|
+
while ( registeredPrivateApis.length ) {
|
|
218
|
+
registeredPrivateApis.pop();
|
|
219
|
+
}
|
|
220
|
+
}
|
package/src/index.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { __dangerousOptInToUnstableAPIsOnlyForCoreModules } from './implementation';
|
|
@@ -0,0 +1,308 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Internal dependencies
|
|
3
|
+
*/
|
|
4
|
+
import { __dangerousOptInToUnstableAPIsOnlyForCoreModules } from '../';
|
|
5
|
+
import {
|
|
6
|
+
resetRegisteredPrivateApis,
|
|
7
|
+
resetAllowedCoreModules,
|
|
8
|
+
allowCoreModule,
|
|
9
|
+
} from '../implementation';
|
|
10
|
+
|
|
11
|
+
beforeEach( () => {
|
|
12
|
+
resetRegisteredPrivateApis();
|
|
13
|
+
resetAllowedCoreModules();
|
|
14
|
+
allowCoreModule( '@privateApis/test' );
|
|
15
|
+
allowCoreModule( '@privateApis/test-consumer' );
|
|
16
|
+
} );
|
|
17
|
+
|
|
18
|
+
const requiredConsent =
|
|
19
|
+
'I know using unstable features means my plugin or theme will inevitably break on the next WordPress release.';
|
|
20
|
+
|
|
21
|
+
describe( '__dangerousOptInToUnstableAPIsOnlyForCoreModules', () => {
|
|
22
|
+
it( 'Should require a consent string', () => {
|
|
23
|
+
expect( () => {
|
|
24
|
+
__dangerousOptInToUnstableAPIsOnlyForCoreModules(
|
|
25
|
+
'',
|
|
26
|
+
'@privateApis/test'
|
|
27
|
+
);
|
|
28
|
+
} ).toThrow( /without confirming you know the consequences/ );
|
|
29
|
+
} );
|
|
30
|
+
it( 'Should require a valid @wordpress package name', () => {
|
|
31
|
+
expect( () => {
|
|
32
|
+
__dangerousOptInToUnstableAPIsOnlyForCoreModules(
|
|
33
|
+
requiredConsent,
|
|
34
|
+
'custom_package'
|
|
35
|
+
);
|
|
36
|
+
} ).toThrow(
|
|
37
|
+
/This feature is only for JavaScript modules shipped with WordPress core/
|
|
38
|
+
);
|
|
39
|
+
} );
|
|
40
|
+
it( 'Should not register the same module twice', () => {
|
|
41
|
+
expect( () => {
|
|
42
|
+
__dangerousOptInToUnstableAPIsOnlyForCoreModules(
|
|
43
|
+
requiredConsent,
|
|
44
|
+
'@privateApis/test'
|
|
45
|
+
);
|
|
46
|
+
__dangerousOptInToUnstableAPIsOnlyForCoreModules(
|
|
47
|
+
requiredConsent,
|
|
48
|
+
'@privateApis/test'
|
|
49
|
+
);
|
|
50
|
+
} ).toThrow( /is already registered/ );
|
|
51
|
+
} );
|
|
52
|
+
it( 'Should grant access to unstable APIs when passed both a consent string and a previously unregistered package name', () => {
|
|
53
|
+
const unstableAPIs = __dangerousOptInToUnstableAPIsOnlyForCoreModules(
|
|
54
|
+
requiredConsent,
|
|
55
|
+
'@privateApis/test'
|
|
56
|
+
);
|
|
57
|
+
expect( unstableAPIs.lock ).toEqual( expect.any( Function ) );
|
|
58
|
+
expect( unstableAPIs.unlock ).toEqual( expect.any( Function ) );
|
|
59
|
+
} );
|
|
60
|
+
} );
|
|
61
|
+
|
|
62
|
+
describe( 'lock(), unlock()', () => {
|
|
63
|
+
let lock, unlock;
|
|
64
|
+
beforeEach( () => {
|
|
65
|
+
// This would live in @privateApis/test:
|
|
66
|
+
// Opt-in to private APIs
|
|
67
|
+
const privateApisAPI = __dangerousOptInToUnstableAPIsOnlyForCoreModules(
|
|
68
|
+
requiredConsent,
|
|
69
|
+
'@privateApis/test'
|
|
70
|
+
);
|
|
71
|
+
lock = privateApisAPI.lock;
|
|
72
|
+
unlock = privateApisAPI.unlock;
|
|
73
|
+
} );
|
|
74
|
+
|
|
75
|
+
it( 'Should lock and unlock objects "inside" other objects', () => {
|
|
76
|
+
const object = {};
|
|
77
|
+
const privateData = { secret: 'sh' };
|
|
78
|
+
lock( object, privateData );
|
|
79
|
+
expect( unlock( object ).secret ).toBe( 'sh' );
|
|
80
|
+
} );
|
|
81
|
+
|
|
82
|
+
it( 'Should lock and unlock functions "inside" objects', () => {
|
|
83
|
+
const object = {};
|
|
84
|
+
const privateData = () => 'sh';
|
|
85
|
+
lock( object, privateData );
|
|
86
|
+
expect( unlock( object )() ).toBe( 'sh' );
|
|
87
|
+
} );
|
|
88
|
+
|
|
89
|
+
it( 'Should lock and unlock strings "inside" objects', () => {
|
|
90
|
+
const object = {};
|
|
91
|
+
const privateData = 'sh';
|
|
92
|
+
lock( object, privateData );
|
|
93
|
+
expect( unlock( object ) ).toBe( 'sh' );
|
|
94
|
+
} );
|
|
95
|
+
|
|
96
|
+
it( 'Should lock and unlock objects "inside" functions', () => {
|
|
97
|
+
const fn = function () {};
|
|
98
|
+
const privateData = { secret: 'sh' };
|
|
99
|
+
lock( fn, privateData );
|
|
100
|
+
expect( unlock( fn ).secret ).toBe( 'sh' );
|
|
101
|
+
} );
|
|
102
|
+
|
|
103
|
+
it( 'Should lock and unlock functions "inside" other functions', () => {
|
|
104
|
+
const fn = function () {};
|
|
105
|
+
const privateData = () => 'sh';
|
|
106
|
+
lock( fn, privateData );
|
|
107
|
+
expect( unlock( fn )() ).toBe( 'sh' );
|
|
108
|
+
} );
|
|
109
|
+
|
|
110
|
+
it( 'Should lock and unlock strings "inside" functions', () => {
|
|
111
|
+
const fn = function () {};
|
|
112
|
+
const privateData = 'sh';
|
|
113
|
+
lock( fn, privateData );
|
|
114
|
+
expect( unlock( fn ) ).toBe( 'sh' );
|
|
115
|
+
} );
|
|
116
|
+
|
|
117
|
+
it( 'Should grant other opt-int modules access to locked objects', () => {
|
|
118
|
+
const object = {};
|
|
119
|
+
const privateData = { secret: 'sh' };
|
|
120
|
+
lock( object, privateData );
|
|
121
|
+
|
|
122
|
+
// This would live in @wordpress/core-data:
|
|
123
|
+
// Register the private APIs
|
|
124
|
+
const coreDataPrivateApis =
|
|
125
|
+
__dangerousOptInToUnstableAPIsOnlyForCoreModules(
|
|
126
|
+
requiredConsent,
|
|
127
|
+
'@privateApis/test-consumer'
|
|
128
|
+
);
|
|
129
|
+
|
|
130
|
+
// Get the private APIs registered by @privateApis/test
|
|
131
|
+
expect( coreDataPrivateApis.unlock( object ).secret ).toBe( 'sh' );
|
|
132
|
+
} );
|
|
133
|
+
} );
|
|
134
|
+
|
|
135
|
+
describe( 'Specific use-cases of sharing private APIs', () => {
|
|
136
|
+
let lock, unlock;
|
|
137
|
+
beforeEach( () => {
|
|
138
|
+
// This would live in @privateApis/test:
|
|
139
|
+
// Opt-in to private APIs
|
|
140
|
+
const privateApisAPI = __dangerousOptInToUnstableAPIsOnlyForCoreModules(
|
|
141
|
+
requiredConsent,
|
|
142
|
+
'@privateApis/test'
|
|
143
|
+
);
|
|
144
|
+
lock = privateApisAPI.lock;
|
|
145
|
+
unlock = privateApisAPI.unlock;
|
|
146
|
+
} );
|
|
147
|
+
|
|
148
|
+
it( 'Should enable privately exporting private functions', () => {
|
|
149
|
+
/**
|
|
150
|
+
* Problem: The private __privateFunction should not be publicly
|
|
151
|
+
* exposed to the consumers of package1.
|
|
152
|
+
*/
|
|
153
|
+
function __privateFunction() {}
|
|
154
|
+
/**
|
|
155
|
+
* Solution: Privately lock it inside a publicly exported object.
|
|
156
|
+
*
|
|
157
|
+
* In `package1/index.js` we'd say:
|
|
158
|
+
*
|
|
159
|
+
* ```js
|
|
160
|
+
* export const privateApis = {};
|
|
161
|
+
* lock(privateApis, {
|
|
162
|
+
* __privateFunction
|
|
163
|
+
* });
|
|
164
|
+
* ```
|
|
165
|
+
*
|
|
166
|
+
* Let's simulate in the test code:
|
|
167
|
+
*/
|
|
168
|
+
const privateApis = {};
|
|
169
|
+
const package1Exports = {
|
|
170
|
+
privateApis,
|
|
171
|
+
};
|
|
172
|
+
lock( privateApis, { __privateFunction } );
|
|
173
|
+
|
|
174
|
+
/**
|
|
175
|
+
* Then, in the consumer package we'd say:
|
|
176
|
+
*
|
|
177
|
+
* ```js
|
|
178
|
+
* import { privateApis } from 'package1';
|
|
179
|
+
* const { __privateFunction } = unlock( privateApis );
|
|
180
|
+
* ```
|
|
181
|
+
*
|
|
182
|
+
* Let's simulate that, too:
|
|
183
|
+
*/
|
|
184
|
+
const unlockedFunction = unlock(
|
|
185
|
+
package1Exports.privateApis
|
|
186
|
+
).__privateFunction;
|
|
187
|
+
expect( unlockedFunction ).toBe( __privateFunction );
|
|
188
|
+
} );
|
|
189
|
+
|
|
190
|
+
it( 'Should enable exporting functions with private private arguments', () => {
|
|
191
|
+
/**
|
|
192
|
+
* The publicly exported function does not have any private
|
|
193
|
+
* arguments.
|
|
194
|
+
*
|
|
195
|
+
* @param {any} data The data to log
|
|
196
|
+
*/
|
|
197
|
+
function logData( data ) {
|
|
198
|
+
// Internally, it calls the private version of the function
|
|
199
|
+
// with fixed default values for the private arguments.
|
|
200
|
+
__privateLogData( data, 'plain' );
|
|
201
|
+
}
|
|
202
|
+
/**
|
|
203
|
+
* The private private function is not publicly exported. Instead, it's
|
|
204
|
+
* "locked" inside of the public logData function. It can be unlocked by any
|
|
205
|
+
* participant of the private importing system.
|
|
206
|
+
*
|
|
207
|
+
* @param {any} data The data to log
|
|
208
|
+
* @param {string} __privateFormat The logging format to use.
|
|
209
|
+
*/
|
|
210
|
+
function __privateLogData( data, __privateFormat ) {
|
|
211
|
+
if ( __privateFormat === 'table' ) {
|
|
212
|
+
// eslint-disable-next-line no-console
|
|
213
|
+
console.table( data );
|
|
214
|
+
} else {
|
|
215
|
+
// eslint-disable-next-line no-console
|
|
216
|
+
console.log( data );
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
lock( logData, __privateLogData );
|
|
220
|
+
/**
|
|
221
|
+
* In package/log-data.js:
|
|
222
|
+
*
|
|
223
|
+
* ```js
|
|
224
|
+
* lock( logData, __privateLogData );
|
|
225
|
+
* export logData;
|
|
226
|
+
* ```
|
|
227
|
+
*
|
|
228
|
+
* Then, in package/index.js:
|
|
229
|
+
*
|
|
230
|
+
* ```js
|
|
231
|
+
* export { logData } from './log-data';
|
|
232
|
+
* ```
|
|
233
|
+
*
|
|
234
|
+
* And that's it! The public function is publicly exported, and the
|
|
235
|
+
* private function is available via unlock( logData ):
|
|
236
|
+
*
|
|
237
|
+
* ```js
|
|
238
|
+
* import { logData } from 'package1';
|
|
239
|
+
* const experimenalLogData = unlock( logData );
|
|
240
|
+
* ```
|
|
241
|
+
*/
|
|
242
|
+
expect( unlock( logData ) ).toBe( __privateLogData );
|
|
243
|
+
} );
|
|
244
|
+
|
|
245
|
+
it( 'Should enable exporting React Components with private private properties', () => {
|
|
246
|
+
// eslint-disable-next-line jsdoc/require-param
|
|
247
|
+
/**
|
|
248
|
+
* The publicly exported component does not have any private
|
|
249
|
+
* properties.
|
|
250
|
+
*/
|
|
251
|
+
function DataTable( { data } ) {
|
|
252
|
+
// Internally, it calls the private version of the function
|
|
253
|
+
// with fixed default values for the private arguments.
|
|
254
|
+
return (
|
|
255
|
+
<PrivateDataTable
|
|
256
|
+
data={ data }
|
|
257
|
+
__privateFancyFormatting={ false }
|
|
258
|
+
/>
|
|
259
|
+
);
|
|
260
|
+
}
|
|
261
|
+
// eslint-disable-next-line jsdoc/require-param
|
|
262
|
+
/**
|
|
263
|
+
* The private private component is not publicly exported. Instead, it's
|
|
264
|
+
* "locked" inside of the public logData function. It can be unlocked by any
|
|
265
|
+
* participant of the private importing system.
|
|
266
|
+
*/
|
|
267
|
+
function PrivateDataTable( { data, __privateFancyFormatting } ) {
|
|
268
|
+
const className = __privateFancyFormatting
|
|
269
|
+
? 'savage-css'
|
|
270
|
+
: 'regular-css';
|
|
271
|
+
return (
|
|
272
|
+
<table className={ className }>
|
|
273
|
+
{ data.map( ( row, i ) => (
|
|
274
|
+
<tr key={ i }>
|
|
275
|
+
{ row.map( ( col, j ) => (
|
|
276
|
+
<td key={ j }>{ col }</td>
|
|
277
|
+
) ) }
|
|
278
|
+
</tr>
|
|
279
|
+
) ) }
|
|
280
|
+
</table>
|
|
281
|
+
);
|
|
282
|
+
}
|
|
283
|
+
lock( DataTable, PrivateDataTable );
|
|
284
|
+
/**
|
|
285
|
+
* In package/data-table.js:
|
|
286
|
+
*
|
|
287
|
+
* ```js
|
|
288
|
+
* lock( DataTable, PrivateDataTable );
|
|
289
|
+
* export DataTable;
|
|
290
|
+
* ```
|
|
291
|
+
*
|
|
292
|
+
* Then, in package/index.js:
|
|
293
|
+
*
|
|
294
|
+
* ```js
|
|
295
|
+
* export { DataTable } from './data-table';
|
|
296
|
+
* ```
|
|
297
|
+
*
|
|
298
|
+
* And that's it! The public function is publicly exported, and the
|
|
299
|
+
* private function is available via unlock( logData ):
|
|
300
|
+
*
|
|
301
|
+
* ```js
|
|
302
|
+
* import { DataTable } from 'package1';
|
|
303
|
+
* const PrivateDataTable = unlock( DataTable );
|
|
304
|
+
* ```
|
|
305
|
+
*/
|
|
306
|
+
expect( unlock( DataTable ) ).toBe( PrivateDataTable );
|
|
307
|
+
} );
|
|
308
|
+
} );
|
package/tsconfig.json
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"program":{"fileNames":["../../node_modules/typescript/lib/lib.es5.d.ts","../../node_modules/typescript/lib/lib.es2015.d.ts","../../node_modules/typescript/lib/lib.es2016.d.ts","../../node_modules/typescript/lib/lib.es2017.d.ts","../../node_modules/typescript/lib/lib.es2018.d.ts","../../node_modules/typescript/lib/lib.es2019.d.ts","../../node_modules/typescript/lib/lib.es2020.d.ts","../../node_modules/typescript/lib/lib.es2021.d.ts","../../node_modules/typescript/lib/lib.esnext.d.ts","../../node_modules/typescript/lib/lib.dom.d.ts","../../node_modules/typescript/lib/lib.es2015.core.d.ts","../../node_modules/typescript/lib/lib.es2015.collection.d.ts","../../node_modules/typescript/lib/lib.es2015.generator.d.ts","../../node_modules/typescript/lib/lib.es2015.iterable.d.ts","../../node_modules/typescript/lib/lib.es2015.promise.d.ts","../../node_modules/typescript/lib/lib.es2015.proxy.d.ts","../../node_modules/typescript/lib/lib.es2015.reflect.d.ts","../../node_modules/typescript/lib/lib.es2015.symbol.d.ts","../../node_modules/typescript/lib/lib.es2015.symbol.wellknown.d.ts","../../node_modules/typescript/lib/lib.es2016.array.include.d.ts","../../node_modules/typescript/lib/lib.es2017.object.d.ts","../../node_modules/typescript/lib/lib.es2017.sharedmemory.d.ts","../../node_modules/typescript/lib/lib.es2017.string.d.ts","../../node_modules/typescript/lib/lib.es2017.intl.d.ts","../../node_modules/typescript/lib/lib.es2017.typedarrays.d.ts","../../node_modules/typescript/lib/lib.es2018.asyncgenerator.d.ts","../../node_modules/typescript/lib/lib.es2018.asynciterable.d.ts","../../node_modules/typescript/lib/lib.es2018.intl.d.ts","../../node_modules/typescript/lib/lib.es2018.promise.d.ts","../../node_modules/typescript/lib/lib.es2018.regexp.d.ts","../../node_modules/typescript/lib/lib.es2019.array.d.ts","../../node_modules/typescript/lib/lib.es2019.object.d.ts","../../node_modules/typescript/lib/lib.es2019.string.d.ts","../../node_modules/typescript/lib/lib.es2019.symbol.d.ts","../../node_modules/typescript/lib/lib.es2020.bigint.d.ts","../../node_modules/typescript/lib/lib.es2020.promise.d.ts","../../node_modules/typescript/lib/lib.es2020.sharedmemory.d.ts","../../node_modules/typescript/lib/lib.es2020.string.d.ts","../../node_modules/typescript/lib/lib.es2020.symbol.wellknown.d.ts","../../node_modules/typescript/lib/lib.es2020.intl.d.ts","../../node_modules/typescript/lib/lib.es2021.promise.d.ts","../../node_modules/typescript/lib/lib.es2021.string.d.ts","../../node_modules/typescript/lib/lib.es2021.weakref.d.ts","../../node_modules/typescript/lib/lib.esnext.intl.d.ts","./src/implementation.js","./src/index.js","../../typings/gutenberg-env/index.d.ts"],"fileInfos":[{"version":"aa9fb4c70f369237c2f45f9d969c9a59e0eae9a192962eb48581fe864aa609db","affectsGlobalScope":true},"dc47c4fa66b9b9890cf076304de2a9c5201e94b740cffdf09f87296d877d71f6","7a387c58583dfca701b6c85e0adaf43fb17d590fb16d5b2dc0a2fbd89f35c467","8a12173c586e95f4433e0c6dc446bc88346be73ffe9ca6eec7aa63c8f3dca7f9","5f4e733ced4e129482ae2186aae29fde948ab7182844c3a5a51dd346182c7b06","e6b724280c694a9f588847f754198fb96c43d805f065c3a5b28bbc9594541c84","e21c071ca3e1b4a815d5f04a7475adcaeea5d64367e840dd0154096d705c3940","eb75e89d63b3b72dd9ca8b0cac801cecae5be352307c004adeaa60bc9d6df51f","2cc028cd0bdb35b1b5eb723d84666a255933fffbea607f72cbd0c7c7b4bee144",{"version":"e54c8715a4954cfdc66cd69489f2b725c09ebf37492dbd91cff0a1688b1159e8","affectsGlobalScope":true},{"version":"51b8b27c21c066bf877646e320bf6a722b80d1ade65e686923cd9d4494aef1ca","affectsGlobalScope":true},{"version":"43fb1d932e4966a39a41b464a12a81899d9ae5f2c829063f5571b6b87e6d2f9c","affectsGlobalScope":true},{"version":"cdccba9a388c2ee3fd6ad4018c640a471a6c060e96f1232062223063b0a5ac6a","affectsGlobalScope":true},{"version":"2c8c5ee58f30e7c944e04ab1fb5506fdbb4dd507c9efa6972cf4b91cec90c503","affectsGlobalScope":true},{"version":"2bb4b3927299434052b37851a47bf5c39764f2ba88a888a107b32262e9292b7c","affectsGlobalScope":true},{"version":"810627a82ac06fb5166da5ada4159c4ec11978dfbb0805fe804c86406dab8357","affectsGlobalScope":true},{"version":"62d80405c46c3f4c527ee657ae9d43fda65a0bf582292429aea1e69144a522a6","affectsGlobalScope":true},{"version":"3013574108c36fd3aaca79764002b3717da09725a36a6fc02eac386593110f93","affectsGlobalScope":true},{"version":"75ec0bdd727d887f1b79ed6619412ea72ba3c81d92d0787ccb64bab18d261f14","affectsGlobalScope":true},{"version":"3be5a1453daa63e031d266bf342f3943603873d890ab8b9ada95e22389389006","affectsGlobalScope":true},{"version":"17bb1fc99591b00515502d264fa55dc8370c45c5298f4a5c2083557dccba5a2a","affectsGlobalScope":true},{"version":"7ce9f0bde3307ca1f944119f6365f2d776d281a393b576a18a2f2893a2d75c98","affectsGlobalScope":true},{"version":"6a6b173e739a6a99629a8594bfb294cc7329bfb7b227f12e1f7c11bc163b8577","affectsGlobalScope":true},{"version":"12a310447c5d23c7d0d5ca2af606e3bd08afda69100166730ab92c62999ebb9d","affectsGlobalScope":true},{"version":"b0124885ef82641903d232172577f2ceb5d3e60aed4da1153bab4221e1f6dd4e","affectsGlobalScope":true},{"version":"0eb85d6c590b0d577919a79e0084fa1744c1beba6fd0d4e951432fa1ede5510a","affectsGlobalScope":true},{"version":"da233fc1c8a377ba9e0bed690a73c290d843c2c3d23a7bd7ec5cd3d7d73ba1e0","affectsGlobalScope":true},{"version":"df9c8a72ca8b0ed62f5470b41208a0587f0f73f0a7db28e5a1272cf92537518e","affectsGlobalScope":true},{"version":"bb2d3fb05a1d2ffbca947cc7cbc95d23e1d053d6595391bd325deb265a18d36c","affectsGlobalScope":true},{"version":"c80df75850fea5caa2afe43b9949338ce4e2de086f91713e9af1a06f973872b8","affectsGlobalScope":true},{"version":"9d57b2b5d15838ed094aa9ff1299eecef40b190722eb619bac4616657a05f951","affectsGlobalScope":true},{"version":"6c51b5dd26a2c31dbf37f00cfc32b2aa6a92e19c995aefb5b97a3a64f1ac99de","affectsGlobalScope":true},{"version":"93544ca2f26a48716c1b6c5091842cad63129daac422dfa4bc52460465f22bb1","affectsGlobalScope":true},{"version":"2ad234885a4240522efccd77de6c7d99eecf9b4de0914adb9a35c0c22433f993","affectsGlobalScope":true},{"version":"1b3fe904465430e030c93239a348f05e1be80640d91f2f004c3512c2c2c89f34","affectsGlobalScope":true},{"version":"7435b75fdf3509622e79622dbe5091cf4b09688410ee2034e4fc17d0c99d0862","affectsGlobalScope":true},{"version":"e7e8e1d368290e9295ef18ca23f405cf40d5456fa9f20db6373a61ca45f75f40","affectsGlobalScope":true},{"version":"faf0221ae0465363c842ce6aa8a0cbda5d9296940a8e26c86e04cc4081eea21e","affectsGlobalScope":true},{"version":"06393d13ea207a1bfe08ec8d7be562549c5e2da8983f2ee074e00002629d1871","affectsGlobalScope":true},{"version":"9f1817f7c3f02f6d56e0f403b927e90bb133f371dcebc36fa7d6d208ef6899da","affectsGlobalScope":true},{"version":"cd6efb9467a8b6338ece2e2855e37765700f2cd061ca54b01b33878cf5c7677e","affectsGlobalScope":true},{"version":"fb4416144c1bf0323ccbc9afb0ab289c07312214e8820ad17d709498c865a3fe","affectsGlobalScope":true},{"version":"5b0ca94ec819d68d33da516306c15297acec88efeb0ae9e2b39f71dbd9685ef7","affectsGlobalScope":true},{"version":"4632665b87204bb1caa8b44d165bce0c50dfab177df5b561b345a567cabacf9a","affectsGlobalScope":true},"32781ec6ab273866b7d6e7ee6ffb56def35fd2a4d69f3d3c69d06309d357e8cb","9562b4736c07eaf98388858acff6157eafae0b51df775cbba5bfdf4733de00b3",{"version":"7b1b47a00ea238e04189f6a4796282ea252bf4f3afce92cdeaed4fe01c669a40","affectsGlobalScope":true}],"options":{"allowSyntheticDefaultImports":true,"composite":true,"declaration":true,"declarationDir":"./build-types","declarationMap":true,"emitDeclarationOnly":true,"esModuleInterop":false,"importsNotUsedAsValues":2,"jsx":1,"module":99,"noFallthroughCasesInSwitch":true,"noImplicitReturns":true,"noUnusedLocals":true,"noUnusedParameters":true,"rootDir":"./src","strict":true,"target":99},"fileIdsList":[[45]],"referencedMap":[[46,1]],"exportedModulesMap":[[46,1]],"semanticDiagnosticsPerFile":[10,12,11,2,13,14,15,16,17,18,19,20,3,4,24,21,22,23,25,26,27,5,28,29,30,31,6,32,33,34,35,7,40,36,37,38,39,8,41,42,43,1,9,44,45,46,47]},"version":"4.4.2"}
|