tiny-essentials 1.26.3 → 1.27.0
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/.github/workflows/node.js.yml +1 -1
- package/README.md +0 -1
- package/changelog/1/26/4.md +10 -0
- package/changelog/1/27/0.md +24 -0
- package/dist/v1/ColorSafeStringify.min.js +1 -1
- package/dist/v1/TinyAdvancedRaffle.min.js +1 -1
- package/dist/v1/TinyAfterScrollWatcher.min.js +1 -1
- package/dist/v1/TinyAnalogClock.min.js +1 -1
- package/dist/v1/TinyArrayComparator.min.js +1 -1
- package/dist/v1/TinyArrayPaginator.min.js +1 -1
- package/dist/v1/TinyBasicsEs.min.js +1 -1
- package/dist/v1/TinyClassManager.min.js +1 -1
- package/dist/v1/TinyClipboard.min.js +1 -1
- package/dist/v1/TinyColorConverter.min.js +1 -1
- package/dist/v1/TinyColorValidator.min.js +1 -1
- package/dist/v1/TinyCookieConsent.min.js +1 -1
- package/dist/v1/TinyDayNightCycle.min.js +1 -1
- package/dist/v1/TinyDomReadyManager.min.js +1 -1
- package/dist/v1/TinyDragDropDetector.min.js +1 -1
- package/dist/v1/TinyDragger.min.js +1 -1
- package/dist/v1/TinyElementObserver.min.js +1 -1
- package/dist/v1/TinyEssentials.min.js +1 -1
- package/dist/v1/TinyEvents.min.js +1 -1
- package/dist/v1/TinyGamepad.min.js +1 -1
- package/dist/v1/TinyHtml.min.js +1 -1
- package/dist/v1/TinyI18.min.js +1 -1
- package/dist/v1/TinyIframeEvents.min.js +1 -1
- package/dist/v1/TinyInventory.min.js +1 -1
- package/dist/v1/TinyInventoryTrader.min.js +1 -1
- package/dist/v1/TinyLevelUp.min.js +1 -1
- package/dist/v1/TinyLoadingScreen.min.js +1 -1
- package/dist/v1/TinyLocalStorage.min.js +1 -1
- package/dist/v1/TinyMaInSys.min.js +1 -1
- package/dist/v1/TinyMediaPlayer.min.js +1 -0
- package/dist/v1/TinyNeedBar.min.js +1 -1
- package/dist/v1/TinyNewWinEvents.min.js +1 -1
- package/dist/v1/TinyNotifications.min.js +1 -1
- package/dist/v1/TinyNotifyCenter.min.js +1 -1
- package/dist/v1/TinyPromiseQueue.min.js +1 -1
- package/dist/v1/TinyRadioFm.min.js +1 -0
- package/dist/v1/TinyRateLimiter.min.js +1 -1
- package/dist/v1/TinySimpleDice.min.js +1 -1
- package/dist/v1/TinySmartScroller.min.js +1 -1
- package/dist/v1/TinyTextDiffer.min.js +1 -1
- package/dist/v1/TinyTextRangeEditor.min.js +1 -1
- package/dist/v1/TinyTextarea.min.js +1 -1
- package/dist/v1/TinyTimeout.min.js +1 -1
- package/dist/v1/TinyToastNotify.min.js +1 -1
- package/dist/v1/TinyUploadClicker.min.js +1 -1
- package/dist/v1/UltraRandomMsgGen.min.js +1 -1
- package/dist/v1/basics/index.cjs +5 -0
- package/dist/v1/basics/index.d.mts +5 -1
- package/dist/v1/basics/index.mjs +2 -1
- package/dist/v1/basics/mediaContent.cjs +644 -0
- package/dist/v1/basics/mediaContent.d.mts +296 -0
- package/dist/v1/basics/mediaContent.mjs +557 -0
- package/dist/v1/build/TinyMediaPlayer.cjs +7 -0
- package/dist/v1/build/TinyMediaPlayer.d.mts +3 -0
- package/dist/v1/build/TinyMediaPlayer.mjs +2 -0
- package/dist/v1/build/TinyRadioFm.cjs +7 -0
- package/dist/v1/build/TinyRadioFm.d.mts +3 -0
- package/dist/v1/build/TinyRadioFm.mjs +2 -0
- package/dist/v1/index.cjs +9 -0
- package/dist/v1/index.d.mts +7 -1
- package/dist/v1/index.mjs +5 -2
- package/dist/v1/libs/ColorSafeStringify.d.mts +1 -1
- package/dist/v1/libs/TinyAfterScrollWatcher.cjs +16 -3
- package/dist/v1/libs/TinyAfterScrollWatcher.d.mts +7 -3
- package/dist/v1/libs/TinyAfterScrollWatcher.mjs +13 -3
- package/dist/v1/libs/TinyArrayComparator.cjs +14 -11
- package/dist/v1/libs/TinyArrayComparator.d.mts +22 -19
- package/dist/v1/libs/TinyArrayComparator.mjs +14 -11
- package/dist/v1/libs/TinyArrayPaginator.cjs +23 -16
- package/dist/v1/libs/TinyArrayPaginator.d.mts +57 -30
- package/dist/v1/libs/TinyArrayPaginator.mjs +22 -16
- package/dist/v1/libs/TinyClassManager/TinyPluginInliner.cjs +265 -0
- package/dist/v1/libs/TinyClassManager/TinyPluginInliner.d.mts +92 -0
- package/dist/v1/libs/TinyClassManager/TinyPluginInliner.mjs +223 -0
- package/dist/v1/libs/TinyClassManager.cjs +124 -23
- package/dist/v1/libs/TinyClassManager.d.mts +33 -13
- package/dist/v1/libs/TinyClassManager.mjs +108 -23
- package/dist/v1/libs/TinyColorValidator.d.mts +16 -16
- package/dist/v1/libs/TinyDragDropDetector.cjs +9 -34
- package/dist/v1/libs/TinyDragDropDetector.d.mts +7 -21
- package/dist/v1/libs/TinyDragDropDetector.mjs +9 -24
- package/dist/v1/libs/TinyDragger.cjs +5 -5
- package/dist/v1/libs/TinyDragger.d.mts +4 -3
- package/dist/v1/libs/TinyDragger.mjs +5 -5
- package/dist/v1/libs/TinyElementObserver.cjs +6 -21
- package/dist/v1/libs/TinyElementObserver.d.mts +6 -15
- package/dist/v1/libs/TinyElementObserver.mjs +6 -20
- package/dist/v1/libs/TinyEvents.cjs +7 -0
- package/dist/v1/libs/TinyEvents.d.mts +4 -0
- package/dist/v1/libs/TinyEvents.mjs +6 -0
- package/dist/v1/libs/TinyGamepad.cjs +4 -6
- package/dist/v1/libs/TinyGamepad.d.mts +1 -1
- package/dist/v1/libs/TinyHtml/TinyHtmlIcon.d.mts +1 -1
- package/dist/v1/libs/TinyHtml/TinyHtmlTemplate.d.mts +1 -1
- package/dist/v1/libs/TinyHtml/TinyHtmlTextarea.d.mts +1 -1
- package/dist/v1/libs/TinyHtml/index.d.mts +1 -1
- package/dist/v1/libs/TinyHtml.cjs +72 -98
- package/dist/v1/libs/TinyHtml.d.mts +15 -32
- package/dist/v1/libs/TinyHtml.mjs +53 -77
- package/dist/v1/libs/TinyInventory.d.mts +1 -1
- package/dist/v1/libs/TinyMediaPlayer.cjs +844 -0
- package/dist/v1/libs/TinyMediaPlayer.d.mts +306 -0
- package/dist/v1/libs/TinyMediaPlayer.mjs +755 -0
- package/dist/v1/libs/TinyRadioFm.cjs +1378 -0
- package/dist/v1/libs/TinyRadioFm.d.mts +554 -0
- package/dist/v1/libs/TinyRadioFm.mjs +1137 -0
- package/dist/v1/libs/TinySmartScroller.cjs +39 -26
- package/dist/v1/libs/TinySmartScroller.d.mts +16 -62
- package/dist/v1/libs/TinySmartScroller.mjs +35 -26
- package/dist/v1/libs/UltraRandomMsgGen.d.mts +7 -7
- package/dist/v1/libs/examples/TinyClassManager.cjs +43 -41
- package/dist/v1/libs/examples/TinyClassManager.mjs +37 -37
- package/docs/v1/README.md +6 -0
- package/docs/v1/basics/mediaContent.md +131 -0
- package/docs/v1/libs/TinyClassManager/TinyPluginInliner.md +107 -0
- package/docs/v1/libs/TinyClassManager.md +69 -70
- package/docs/v1/libs/TinyDragDropDetector.md +5 -9
- package/docs/v1/libs/TinyElementObserver.md +3 -6
- package/docs/v1/libs/TinyEvents.md +1 -1
- package/docs/v1/libs/TinyHtml.md +0 -29
- package/docs/v1/libs/TinyMediaPlayer.md +100 -0
- package/docs/v1/libs/TinyRadioFm.md +141 -0
- package/docs/v1/libs/TinySmartScroller.md +3 -3
- package/package.json +40 -22
|
@@ -2,33 +2,46 @@
|
|
|
2
2
|
* A predicate function used to determine whether an item should be included in the filtered results.
|
|
3
3
|
* Works similarly to the callback function of `Array.prototype.filter`.
|
|
4
4
|
*
|
|
5
|
+
* @template {any} ArrayItem
|
|
5
6
|
* @callback GetFilter
|
|
6
|
-
* @param {
|
|
7
|
+
* @param {ArrayItem} value - The current element being processed in the array.
|
|
7
8
|
* @param {number} index - The index of the current element within the array.
|
|
8
|
-
* @param {
|
|
9
|
+
* @param {ArrayItem[]} array - The full array being processed.
|
|
9
10
|
* @returns {boolean} Returns `true` to include the element in the results, or `false` to exclude it.
|
|
10
11
|
*/
|
|
12
|
+
/**
|
|
13
|
+
* @template {any} ArrayItem
|
|
14
|
+
* @typedef {Object} GetterResult
|
|
15
|
+
* @property {ArrayItem[]} items - The subset of items for the requested page.
|
|
16
|
+
* @property {number} page - The current (validated) page number.
|
|
17
|
+
* @property {number} perPage - Number of items per page used in the calculation.
|
|
18
|
+
* @property {number} totalItems - Total number of items in the filtered data.
|
|
19
|
+
* @property {number} totalPages - Total number of pages available.
|
|
20
|
+
* @property {boolean} hasPrev - Whether a previous page exists.
|
|
21
|
+
* @property {boolean} hasNext - Whether a next page exists.
|
|
22
|
+
*/
|
|
11
23
|
/**
|
|
12
24
|
* A encapsulated wrapper for array pagination.
|
|
13
25
|
* Provides methods to retrieve paginated results with metadata,
|
|
14
26
|
* while keeping the source array safe from direct modifications.
|
|
27
|
+
* @template {any} ArrayItem
|
|
15
28
|
*/
|
|
16
29
|
class TinyArrayPaginator {
|
|
17
30
|
/**
|
|
18
31
|
* Internal storage for the paginated data source.
|
|
19
|
-
* @type {
|
|
32
|
+
* @type {ArrayItem[]|Set<ArrayItem>}
|
|
20
33
|
*/
|
|
21
34
|
#data;
|
|
22
35
|
/**
|
|
23
36
|
* Gets current stored array.
|
|
24
|
-
* @returns {
|
|
37
|
+
* @returns {ArrayItem[]|Set<ArrayItem>}
|
|
25
38
|
*/
|
|
26
39
|
get data() {
|
|
27
40
|
return this.#data;
|
|
28
41
|
}
|
|
29
42
|
/**
|
|
30
43
|
* Replaces the current data array.
|
|
31
|
-
* @param {
|
|
44
|
+
* @param {ArrayItem[]|Set<ArrayItem>} value - The new array to be used as the data source.
|
|
32
45
|
* @throws {TypeError} If the provided value is not an array.
|
|
33
46
|
*/
|
|
34
47
|
set data(value) {
|
|
@@ -45,7 +58,7 @@ class TinyArrayPaginator {
|
|
|
45
58
|
}
|
|
46
59
|
/**
|
|
47
60
|
* Creates a new paginator instance for the given data array.
|
|
48
|
-
* @param {
|
|
61
|
+
* @param {ArrayItem[]|Set<ArrayItem>} data - The array to be paginated.
|
|
49
62
|
* @throws {TypeError} If the provided data is not an array.
|
|
50
63
|
*/
|
|
51
64
|
constructor(data) {
|
|
@@ -58,18 +71,10 @@ class TinyArrayPaginator {
|
|
|
58
71
|
* @param {Object} settings
|
|
59
72
|
* @param {number} settings.page - The page number (1-based index).
|
|
60
73
|
* @param {number} settings.perPage - Items per page.
|
|
61
|
-
* @param {Record<string,
|
|
74
|
+
* @param {Record<string, ArrayItem|RegExp> | GetFilter<ArrayItem>} [settings.filter=null] - Filtering criteria:
|
|
62
75
|
* - Object: key-value pairs for exact match, substring match, or RegExp
|
|
63
76
|
* - Function: custom filter function returning true for items to include
|
|
64
|
-
* @returns {
|
|
65
|
-
* items: any[], // The subset of items for the requested page.
|
|
66
|
-
* page: number, // The current (validated) page number.
|
|
67
|
-
* perPage: number, // Number of items per page used in the calculation.
|
|
68
|
-
* totalItems: number, // Total number of items in the filtered data.
|
|
69
|
-
* totalPages: number, // Total number of pages available.
|
|
70
|
-
* hasPrev: boolean, // Whether a previous page exists.
|
|
71
|
-
* hasNext: boolean // Whether a next page exists.
|
|
72
|
-
* }}
|
|
77
|
+
* @returns {GetterResult<ArrayItem>}
|
|
73
78
|
*/
|
|
74
79
|
get({ page, perPage, filter }) {
|
|
75
80
|
if (!Number.isInteger(page) || page < 1)
|
|
@@ -84,6 +89,7 @@ class TinyArrayPaginator {
|
|
|
84
89
|
}
|
|
85
90
|
else if (typeof filter === 'object') {
|
|
86
91
|
dataToUse = data.filter((item) => Object.entries(filter).every(([key, value]) => {
|
|
92
|
+
// @ts-ignore
|
|
87
93
|
const v = item[key];
|
|
88
94
|
if (value instanceof RegExp)
|
|
89
95
|
return value.test(v);
|
|
@@ -0,0 +1,265 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var promises = require('fs/promises');
|
|
4
|
+
var path = require('path');
|
|
5
|
+
var module$1 = require('module');
|
|
6
|
+
|
|
7
|
+
var _documentCurrentScript = typeof document !== 'undefined' ? document.currentScript : null;
|
|
8
|
+
// Enables resolving paths inside node_modules natively
|
|
9
|
+
const require$1 = module$1.createRequire((typeof document === 'undefined' ? require('u' + 'rl').pathToFileURL(__filename).href : (_documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === 'SCRIPT' && _documentCurrentScript.src || new URL('v1/libs/TinyClassManager/TinyPluginInliner.cjs', document.baseURI).href)));
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* @typedef {Object} RootReplacement
|
|
13
|
+
* @property {string} from - The directory name to replace (e.g., 'src').
|
|
14
|
+
* @property {string} to - The directory name to insert (e.g., 'dist').
|
|
15
|
+
*/
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* @typedef {Object} InlinerConfig
|
|
19
|
+
* @property {string} entryPoint - The absolute or relative path to the entry file.
|
|
20
|
+
* @property {string} outDir - The absolute or relative path to the output directory.
|
|
21
|
+
* @property {string} outFileName - The name of the generated bundle file.
|
|
22
|
+
* @property {RootReplacement} [rootReplacement] - Optional customization to remap project import roots.
|
|
23
|
+
*/
|
|
24
|
+
|
|
25
|
+
class TinyPluginInliner {
|
|
26
|
+
/**
|
|
27
|
+
* Creates an instance of the TinyPluginInliner.
|
|
28
|
+
*
|
|
29
|
+
* @param {InlinerConfig} config - The configuration object for the build process.
|
|
30
|
+
*/
|
|
31
|
+
constructor(config) {
|
|
32
|
+
this.config = config;
|
|
33
|
+
this.entryFile = path.resolve(config.entryPoint);
|
|
34
|
+
this.outDir = path.resolve(config.outDir);
|
|
35
|
+
this.outFile = path.join(this.outDir, config.outFileName);
|
|
36
|
+
this.entryDir = path.dirname(this.entryFile);
|
|
37
|
+
|
|
38
|
+
this.hoistedImports = new Set();
|
|
39
|
+
this.hoistedTypedefs = new Set();
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* Rewrites all import paths (both standard and inside JSDocs) in a given code string.
|
|
44
|
+
* Handles local path root replacements and NPM package absolute path conversion.
|
|
45
|
+
*
|
|
46
|
+
* @private
|
|
47
|
+
* @param {string} code - The source code containing imports.
|
|
48
|
+
* @param {string} sourceDir - The absolute directory of the file being processed.
|
|
49
|
+
* @param {boolean} isNpm - Whether this code comes from an external NPM package.
|
|
50
|
+
* @param {string|null} npmPackageName - The name of the NPM package, if applicable.
|
|
51
|
+
* @returns {string} The code with all paths corrected.
|
|
52
|
+
*/
|
|
53
|
+
_rewritePathsInString(code, sourceDir, isNpm, npmPackageName) {
|
|
54
|
+
/**
|
|
55
|
+
* @param {string} match
|
|
56
|
+
* @param {string} prefix
|
|
57
|
+
* @param {string} importPath
|
|
58
|
+
* @param {string} suffix
|
|
59
|
+
*/
|
|
60
|
+
const replacer = (match, prefix, importPath, suffix) => {
|
|
61
|
+
// Ignore absolute external imports (e.g., 'discord.js')
|
|
62
|
+
if (!importPath.startsWith('.')) return match;
|
|
63
|
+
|
|
64
|
+
const absoluteTarget = path.resolve(sourceDir, importPath);
|
|
65
|
+
|
|
66
|
+
if (isNpm) {
|
|
67
|
+
// If it's a relative import inside an NPM package, map it back to an absolute NPM path
|
|
68
|
+
const packageRootMarker = `node_modules${path.sep}${npmPackageName}`;
|
|
69
|
+
const markerIndex = absoluteTarget.lastIndexOf(packageRootMarker);
|
|
70
|
+
|
|
71
|
+
if (markerIndex !== -1) {
|
|
72
|
+
const packageRootPath = absoluteTarget.substring(
|
|
73
|
+
0,
|
|
74
|
+
markerIndex + packageRootMarker.length,
|
|
75
|
+
);
|
|
76
|
+
let subPath = path.relative(packageRootPath, absoluteTarget);
|
|
77
|
+
subPath = subPath.split(path.sep).join(path.posix.sep);
|
|
78
|
+
const finalNpmImport = `${npmPackageName}/${subPath}`;
|
|
79
|
+
|
|
80
|
+
return `${prefix}${finalNpmImport}${suffix}`;
|
|
81
|
+
}
|
|
82
|
+
return match; // Fallback
|
|
83
|
+
} else {
|
|
84
|
+
// Local project file
|
|
85
|
+
let modifiedTarget = absoluteTarget;
|
|
86
|
+
|
|
87
|
+
// Applies the customizable project root replacement (e.g., 'src' to 'dist')
|
|
88
|
+
if (this.config.rootReplacement) {
|
|
89
|
+
const fromStr = `${path.sep}${this.config.rootReplacement.from}${path.sep}`;
|
|
90
|
+
const toStr = `${path.sep}${this.config.rootReplacement.to}${path.sep}`;
|
|
91
|
+
modifiedTarget = modifiedTarget.replace(fromStr, toStr);
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
// Calculate relative path from the new output directory
|
|
95
|
+
let newRelativePath = path.relative(this.outDir, modifiedTarget);
|
|
96
|
+
newRelativePath = newRelativePath.split(path.sep).join(path.posix.sep);
|
|
97
|
+
|
|
98
|
+
// Ensure it starts with './' if it's in the same directory
|
|
99
|
+
if (!newRelativePath.startsWith('.')) {
|
|
100
|
+
newRelativePath = `./${newRelativePath}`;
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
return `${prefix}${newRelativePath}${suffix}`;
|
|
104
|
+
}
|
|
105
|
+
};
|
|
106
|
+
|
|
107
|
+
// Corrects standard imports: from '../path'
|
|
108
|
+
let result = code.replace(/(from\s+['"])([^'"]+)(['"])/g, replacer);
|
|
109
|
+
|
|
110
|
+
// Corrects JSDoc typedef imports: import('../path')
|
|
111
|
+
result = result.replace(/(import\s*\(\s*['"])([^'"]+)(['"]\s*\))/g, replacer);
|
|
112
|
+
|
|
113
|
+
return result;
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
/**
|
|
117
|
+
* Extracts and hoists already-corrected imports and typedefs.
|
|
118
|
+
*
|
|
119
|
+
* @private
|
|
120
|
+
* @param {string} code - The source code to parse.
|
|
121
|
+
* @returns {string} The code with imports and typedefs removed.
|
|
122
|
+
*/
|
|
123
|
+
_extractAndHoist(code) {
|
|
124
|
+
let processedCode = code;
|
|
125
|
+
|
|
126
|
+
// Hoist imports
|
|
127
|
+
const importRegex = /^import\s+[^;]+;/gm;
|
|
128
|
+
const imports = processedCode.match(importRegex) || [];
|
|
129
|
+
for (const imp of imports) this.hoistedImports.add(imp.trim());
|
|
130
|
+
processedCode = processedCode.replace(importRegex, '').trim();
|
|
131
|
+
|
|
132
|
+
// Hoist typedefs
|
|
133
|
+
const typedefRegex = /\/\*\*[\s\S]*?@typedef[\s\S]*?\*\//g;
|
|
134
|
+
const typedefs = processedCode.match(typedefRegex) || [];
|
|
135
|
+
for (const def of typedefs) this.hoistedTypedefs.add(def.trim());
|
|
136
|
+
processedCode = processedCode.replace(typedefRegex, '').trim();
|
|
137
|
+
|
|
138
|
+
return processedCode;
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
/**
|
|
142
|
+
* Cleans up the plugin code to be safely injected into the .insert() method.
|
|
143
|
+
*
|
|
144
|
+
* @private
|
|
145
|
+
* @param {string} code - The raw plugin code.
|
|
146
|
+
* @param {string} pluginName - The name of the plugin class/variable.
|
|
147
|
+
* @returns {string} The formatted plugin code.
|
|
148
|
+
*/
|
|
149
|
+
_formatPluginCode(code, pluginName) {
|
|
150
|
+
let cleanCode = code;
|
|
151
|
+
|
|
152
|
+
// Remove exports and declarations
|
|
153
|
+
cleanCode = cleanCode.replace(new RegExp(`export\\s+default\\s+${pluginName};`), '');
|
|
154
|
+
cleanCode = cleanCode.replace(new RegExp(`const\\s+${pluginName}\\s*=\\s*`), '');
|
|
155
|
+
|
|
156
|
+
// Remove the JSDoc block specifically targeting the (Base) => wrapper
|
|
157
|
+
cleanCode = cleanCode.replace(/\/\*\*[\s\S]*?\*\/\s*(\(Base\)\s*=>)/, '$1');
|
|
158
|
+
|
|
159
|
+
// Remove trailing semicolon
|
|
160
|
+
cleanCode = cleanCode.trim();
|
|
161
|
+
if (cleanCode.endsWith(';')) cleanCode = cleanCode.slice(0, -1);
|
|
162
|
+
|
|
163
|
+
// Fix the @extends JSDoc
|
|
164
|
+
cleanCode = cleanCode.replace(/@extends\s+\{[A-Za-z0-9_]+</g, '@extends {Base<');
|
|
165
|
+
|
|
166
|
+
return cleanCode;
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
/**
|
|
170
|
+
* Executes the build process.
|
|
171
|
+
*
|
|
172
|
+
* @returns {Promise<void>}
|
|
173
|
+
*/
|
|
174
|
+
async build() {
|
|
175
|
+
try {
|
|
176
|
+
let entryContent = await promises.readFile(this.entryFile, 'utf8');
|
|
177
|
+
|
|
178
|
+
// Find all plugins being inserted
|
|
179
|
+
const insertRegex = /\.insert\(\s*([a-zA-Z0-9_]+)\s*\)/g;
|
|
180
|
+
const pluginsToInline = [...entryContent.matchAll(insertRegex)].map((m) => m[1]);
|
|
181
|
+
|
|
182
|
+
if (pluginsToInline.length === 0) {
|
|
183
|
+
console.log('No plugins found to inline.');
|
|
184
|
+
return;
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
// 1. Identify original import paths for the plugins before any modifications
|
|
188
|
+
const pluginTargets = [];
|
|
189
|
+
const entryImportRegex = /^import\s+[^;]+;/gm;
|
|
190
|
+
const entryImportsMatch = entryContent.match(entryImportRegex) || [];
|
|
191
|
+
|
|
192
|
+
for (const pluginName of pluginsToInline) {
|
|
193
|
+
const importLine = entryImportsMatch.find((imp) => imp.includes(` ${pluginName} `));
|
|
194
|
+
if (importLine) {
|
|
195
|
+
const pathMatch = importLine.match(/from\s+['"]([^'"]+)['"]/);
|
|
196
|
+
if (pathMatch) {
|
|
197
|
+
pluginTargets.push({
|
|
198
|
+
name: pluginName,
|
|
199
|
+
importPath: pathMatch[1],
|
|
200
|
+
originalImportLine: importLine,
|
|
201
|
+
});
|
|
202
|
+
// Remove the plugin import line so it isn't rewritten and hoisted normally
|
|
203
|
+
entryContent = entryContent.replace(importLine, '');
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
// 2. Rewrite paths and hoist from the main entry file
|
|
209
|
+
entryContent = this._rewritePathsInString(entryContent, this.entryDir, false, null);
|
|
210
|
+
entryContent = this._extractAndHoist(entryContent);
|
|
211
|
+
|
|
212
|
+
// 3. Process each plugin using their original import paths
|
|
213
|
+
for (const target of pluginTargets) {
|
|
214
|
+
const isNpm = !target.importPath.startsWith('.');
|
|
215
|
+
let pluginFullPath;
|
|
216
|
+
let npmPackageName = null;
|
|
217
|
+
|
|
218
|
+
if (isNpm) {
|
|
219
|
+
// Identify NPM package name (handles @scope/package as well)
|
|
220
|
+
const parts = target.importPath.split('/');
|
|
221
|
+
npmPackageName = target.importPath.startsWith('@') ? `${parts[0]}/${parts[1]}` : parts[0];
|
|
222
|
+
|
|
223
|
+
try {
|
|
224
|
+
// Locate the physical file inside node_modules
|
|
225
|
+
pluginFullPath = require$1.resolve(target.importPath, { paths: [this.entryDir] });
|
|
226
|
+
} catch (e) {
|
|
227
|
+
console.error(`Error: Could not resolve NPM module: ${target.importPath}`);
|
|
228
|
+
throw e;
|
|
229
|
+
}
|
|
230
|
+
} else {
|
|
231
|
+
pluginFullPath = path.resolve(this.entryDir, target.importPath);
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
const pluginSourceDir = path.dirname(pluginFullPath);
|
|
235
|
+
let pluginCode = await promises.readFile(pluginFullPath, 'utf8');
|
|
236
|
+
|
|
237
|
+
// Rewrite internal paths (handles NPM isolation vs Local Root Replacement)
|
|
238
|
+
pluginCode = this._rewritePathsInString(pluginCode, pluginSourceDir, isNpm, npmPackageName);
|
|
239
|
+
|
|
240
|
+
// Hoist dependencies
|
|
241
|
+
pluginCode = this._extractAndHoist(pluginCode);
|
|
242
|
+
|
|
243
|
+
// Format and inject
|
|
244
|
+
pluginCode = this._formatPluginCode(pluginCode, target.name);
|
|
245
|
+
const insertTarget = new RegExp(`\\.insert\\(\\s*${target.name}\\s*\\)`, 'g');
|
|
246
|
+
entryContent = entryContent.replace(insertTarget, `.insert(\n${pluginCode}\n)`);
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
// 4. Final Assembly
|
|
250
|
+
const finalImports = [...this.hoistedImports].join('\n');
|
|
251
|
+
const finalTypedefs = [...this.hoistedTypedefs].join('\n\n');
|
|
252
|
+
const finalOutput = `${finalImports}\n\n${finalTypedefs}\n\n${entryContent}`;
|
|
253
|
+
|
|
254
|
+
await promises.mkdir(this.outDir, { recursive: true });
|
|
255
|
+
await promises.writeFile(this.outFile, finalOutput, 'utf8');
|
|
256
|
+
|
|
257
|
+
console.log('Build successful! Imports corrected (including JSDoc and NPM modules).');
|
|
258
|
+
} catch (error) {
|
|
259
|
+
console.error('Build failed:', error);
|
|
260
|
+
process.exit(1);
|
|
261
|
+
}
|
|
262
|
+
}
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
module.exports = TinyPluginInliner;
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
export default TinyPluginInliner;
|
|
2
|
+
export type RootReplacement = {
|
|
3
|
+
/**
|
|
4
|
+
* - The directory name to replace (e.g., 'src').
|
|
5
|
+
*/
|
|
6
|
+
from: string;
|
|
7
|
+
/**
|
|
8
|
+
* - The directory name to insert (e.g., 'dist').
|
|
9
|
+
*/
|
|
10
|
+
to: string;
|
|
11
|
+
};
|
|
12
|
+
export type InlinerConfig = {
|
|
13
|
+
/**
|
|
14
|
+
* - The absolute or relative path to the entry file.
|
|
15
|
+
*/
|
|
16
|
+
entryPoint: string;
|
|
17
|
+
/**
|
|
18
|
+
* - The absolute or relative path to the output directory.
|
|
19
|
+
*/
|
|
20
|
+
outDir: string;
|
|
21
|
+
/**
|
|
22
|
+
* - The name of the generated bundle file.
|
|
23
|
+
*/
|
|
24
|
+
outFileName: string;
|
|
25
|
+
/**
|
|
26
|
+
* - Optional customization to remap project import roots.
|
|
27
|
+
*/
|
|
28
|
+
rootReplacement?: RootReplacement | undefined;
|
|
29
|
+
};
|
|
30
|
+
/**
|
|
31
|
+
* @typedef {Object} RootReplacement
|
|
32
|
+
* @property {string} from - The directory name to replace (e.g., 'src').
|
|
33
|
+
* @property {string} to - The directory name to insert (e.g., 'dist').
|
|
34
|
+
*/
|
|
35
|
+
/**
|
|
36
|
+
* @typedef {Object} InlinerConfig
|
|
37
|
+
* @property {string} entryPoint - The absolute or relative path to the entry file.
|
|
38
|
+
* @property {string} outDir - The absolute or relative path to the output directory.
|
|
39
|
+
* @property {string} outFileName - The name of the generated bundle file.
|
|
40
|
+
* @property {RootReplacement} [rootReplacement] - Optional customization to remap project import roots.
|
|
41
|
+
*/
|
|
42
|
+
declare class TinyPluginInliner {
|
|
43
|
+
/**
|
|
44
|
+
* Creates an instance of the TinyPluginInliner.
|
|
45
|
+
*
|
|
46
|
+
* @param {InlinerConfig} config - The configuration object for the build process.
|
|
47
|
+
*/
|
|
48
|
+
constructor(config: InlinerConfig);
|
|
49
|
+
config: InlinerConfig;
|
|
50
|
+
entryFile: string;
|
|
51
|
+
outDir: string;
|
|
52
|
+
outFile: string;
|
|
53
|
+
entryDir: string;
|
|
54
|
+
hoistedImports: Set<any>;
|
|
55
|
+
hoistedTypedefs: Set<any>;
|
|
56
|
+
/**
|
|
57
|
+
* Rewrites all import paths (both standard and inside JSDocs) in a given code string.
|
|
58
|
+
* Handles local path root replacements and NPM package absolute path conversion.
|
|
59
|
+
*
|
|
60
|
+
* @private
|
|
61
|
+
* @param {string} code - The source code containing imports.
|
|
62
|
+
* @param {string} sourceDir - The absolute directory of the file being processed.
|
|
63
|
+
* @param {boolean} isNpm - Whether this code comes from an external NPM package.
|
|
64
|
+
* @param {string|null} npmPackageName - The name of the NPM package, if applicable.
|
|
65
|
+
* @returns {string} The code with all paths corrected.
|
|
66
|
+
*/
|
|
67
|
+
private _rewritePathsInString;
|
|
68
|
+
/**
|
|
69
|
+
* Extracts and hoists already-corrected imports and typedefs.
|
|
70
|
+
*
|
|
71
|
+
* @private
|
|
72
|
+
* @param {string} code - The source code to parse.
|
|
73
|
+
* @returns {string} The code with imports and typedefs removed.
|
|
74
|
+
*/
|
|
75
|
+
private _extractAndHoist;
|
|
76
|
+
/**
|
|
77
|
+
* Cleans up the plugin code to be safely injected into the .insert() method.
|
|
78
|
+
*
|
|
79
|
+
* @private
|
|
80
|
+
* @param {string} code - The raw plugin code.
|
|
81
|
+
* @param {string} pluginName - The name of the plugin class/variable.
|
|
82
|
+
* @returns {string} The formatted plugin code.
|
|
83
|
+
*/
|
|
84
|
+
private _formatPluginCode;
|
|
85
|
+
/**
|
|
86
|
+
* Executes the build process.
|
|
87
|
+
*
|
|
88
|
+
* @returns {Promise<void>}
|
|
89
|
+
*/
|
|
90
|
+
build(): Promise<void>;
|
|
91
|
+
}
|
|
92
|
+
//# sourceMappingURL=TinyPluginInliner.d.mts.map
|
|
@@ -0,0 +1,223 @@
|
|
|
1
|
+
import { readFile, mkdir, writeFile } from 'fs/promises';
|
|
2
|
+
import { resolve, sep, join, dirname, relative, posix } from 'path';
|
|
3
|
+
import { createRequire } from 'module';
|
|
4
|
+
// Enables resolving paths inside node_modules natively
|
|
5
|
+
const require = createRequire(import.meta.url);
|
|
6
|
+
/**
|
|
7
|
+
* @typedef {Object} RootReplacement
|
|
8
|
+
* @property {string} from - The directory name to replace (e.g., 'src').
|
|
9
|
+
* @property {string} to - The directory name to insert (e.g., 'dist').
|
|
10
|
+
*/
|
|
11
|
+
/**
|
|
12
|
+
* @typedef {Object} InlinerConfig
|
|
13
|
+
* @property {string} entryPoint - The absolute or relative path to the entry file.
|
|
14
|
+
* @property {string} outDir - The absolute or relative path to the output directory.
|
|
15
|
+
* @property {string} outFileName - The name of the generated bundle file.
|
|
16
|
+
* @property {RootReplacement} [rootReplacement] - Optional customization to remap project import roots.
|
|
17
|
+
*/
|
|
18
|
+
class TinyPluginInliner {
|
|
19
|
+
/**
|
|
20
|
+
* Creates an instance of the TinyPluginInliner.
|
|
21
|
+
*
|
|
22
|
+
* @param {InlinerConfig} config - The configuration object for the build process.
|
|
23
|
+
*/
|
|
24
|
+
constructor(config) {
|
|
25
|
+
this.config = config;
|
|
26
|
+
this.entryFile = resolve(config.entryPoint);
|
|
27
|
+
this.outDir = resolve(config.outDir);
|
|
28
|
+
this.outFile = join(this.outDir, config.outFileName);
|
|
29
|
+
this.entryDir = dirname(this.entryFile);
|
|
30
|
+
this.hoistedImports = new Set();
|
|
31
|
+
this.hoistedTypedefs = new Set();
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* Rewrites all import paths (both standard and inside JSDocs) in a given code string.
|
|
35
|
+
* Handles local path root replacements and NPM package absolute path conversion.
|
|
36
|
+
*
|
|
37
|
+
* @private
|
|
38
|
+
* @param {string} code - The source code containing imports.
|
|
39
|
+
* @param {string} sourceDir - The absolute directory of the file being processed.
|
|
40
|
+
* @param {boolean} isNpm - Whether this code comes from an external NPM package.
|
|
41
|
+
* @param {string|null} npmPackageName - The name of the NPM package, if applicable.
|
|
42
|
+
* @returns {string} The code with all paths corrected.
|
|
43
|
+
*/
|
|
44
|
+
_rewritePathsInString(code, sourceDir, isNpm, npmPackageName) {
|
|
45
|
+
/**
|
|
46
|
+
* @param {string} match
|
|
47
|
+
* @param {string} prefix
|
|
48
|
+
* @param {string} importPath
|
|
49
|
+
* @param {string} suffix
|
|
50
|
+
*/
|
|
51
|
+
const replacer = (match, prefix, importPath, suffix) => {
|
|
52
|
+
// Ignore absolute external imports (e.g., 'discord.js')
|
|
53
|
+
if (!importPath.startsWith('.'))
|
|
54
|
+
return match;
|
|
55
|
+
const absoluteTarget = resolve(sourceDir, importPath);
|
|
56
|
+
if (isNpm) {
|
|
57
|
+
// If it's a relative import inside an NPM package, map it back to an absolute NPM path
|
|
58
|
+
const packageRootMarker = `node_modules${sep}${npmPackageName}`;
|
|
59
|
+
const markerIndex = absoluteTarget.lastIndexOf(packageRootMarker);
|
|
60
|
+
if (markerIndex !== -1) {
|
|
61
|
+
const packageRootPath = absoluteTarget.substring(0, markerIndex + packageRootMarker.length);
|
|
62
|
+
let subPath = relative(packageRootPath, absoluteTarget);
|
|
63
|
+
subPath = subPath.split(sep).join(posix.sep);
|
|
64
|
+
const finalNpmImport = `${npmPackageName}/${subPath}`;
|
|
65
|
+
return `${prefix}${finalNpmImport}${suffix}`;
|
|
66
|
+
}
|
|
67
|
+
return match; // Fallback
|
|
68
|
+
}
|
|
69
|
+
else {
|
|
70
|
+
// Local project file
|
|
71
|
+
let modifiedTarget = absoluteTarget;
|
|
72
|
+
// Applies the customizable project root replacement (e.g., 'src' to 'dist')
|
|
73
|
+
if (this.config.rootReplacement) {
|
|
74
|
+
const fromStr = `${sep}${this.config.rootReplacement.from}${sep}`;
|
|
75
|
+
const toStr = `${sep}${this.config.rootReplacement.to}${sep}`;
|
|
76
|
+
modifiedTarget = modifiedTarget.replace(fromStr, toStr);
|
|
77
|
+
}
|
|
78
|
+
// Calculate relative path from the new output directory
|
|
79
|
+
let newRelativePath = relative(this.outDir, modifiedTarget);
|
|
80
|
+
newRelativePath = newRelativePath.split(sep).join(posix.sep);
|
|
81
|
+
// Ensure it starts with './' if it's in the same directory
|
|
82
|
+
if (!newRelativePath.startsWith('.')) {
|
|
83
|
+
newRelativePath = `./${newRelativePath}`;
|
|
84
|
+
}
|
|
85
|
+
return `${prefix}${newRelativePath}${suffix}`;
|
|
86
|
+
}
|
|
87
|
+
};
|
|
88
|
+
// Corrects standard imports: from '../path'
|
|
89
|
+
let result = code.replace(/(from\s+['"])([^'"]+)(['"])/g, replacer);
|
|
90
|
+
// Corrects JSDoc typedef imports: import('../path')
|
|
91
|
+
result = result.replace(/(import\s*\(\s*['"])([^'"]+)(['"]\s*\))/g, replacer);
|
|
92
|
+
return result;
|
|
93
|
+
}
|
|
94
|
+
/**
|
|
95
|
+
* Extracts and hoists already-corrected imports and typedefs.
|
|
96
|
+
*
|
|
97
|
+
* @private
|
|
98
|
+
* @param {string} code - The source code to parse.
|
|
99
|
+
* @returns {string} The code with imports and typedefs removed.
|
|
100
|
+
*/
|
|
101
|
+
_extractAndHoist(code) {
|
|
102
|
+
let processedCode = code;
|
|
103
|
+
// Hoist imports
|
|
104
|
+
const importRegex = /^import\s+[^;]+;/gm;
|
|
105
|
+
const imports = processedCode.match(importRegex) || [];
|
|
106
|
+
for (const imp of imports)
|
|
107
|
+
this.hoistedImports.add(imp.trim());
|
|
108
|
+
processedCode = processedCode.replace(importRegex, '').trim();
|
|
109
|
+
// Hoist typedefs
|
|
110
|
+
const typedefRegex = /\/\*\*[\s\S]*?@typedef[\s\S]*?\*\//g;
|
|
111
|
+
const typedefs = processedCode.match(typedefRegex) || [];
|
|
112
|
+
for (const def of typedefs)
|
|
113
|
+
this.hoistedTypedefs.add(def.trim());
|
|
114
|
+
processedCode = processedCode.replace(typedefRegex, '').trim();
|
|
115
|
+
return processedCode;
|
|
116
|
+
}
|
|
117
|
+
/**
|
|
118
|
+
* Cleans up the plugin code to be safely injected into the .insert() method.
|
|
119
|
+
*
|
|
120
|
+
* @private
|
|
121
|
+
* @param {string} code - The raw plugin code.
|
|
122
|
+
* @param {string} pluginName - The name of the plugin class/variable.
|
|
123
|
+
* @returns {string} The formatted plugin code.
|
|
124
|
+
*/
|
|
125
|
+
_formatPluginCode(code, pluginName) {
|
|
126
|
+
let cleanCode = code;
|
|
127
|
+
// Remove exports and declarations
|
|
128
|
+
cleanCode = cleanCode.replace(new RegExp(`export\\s+default\\s+${pluginName};`), '');
|
|
129
|
+
cleanCode = cleanCode.replace(new RegExp(`const\\s+${pluginName}\\s*=\\s*`), '');
|
|
130
|
+
// Remove the JSDoc block specifically targeting the (Base) => wrapper
|
|
131
|
+
cleanCode = cleanCode.replace(/\/\*\*[\s\S]*?\*\/\s*(\(Base\)\s*=>)/, '$1');
|
|
132
|
+
// Remove trailing semicolon
|
|
133
|
+
cleanCode = cleanCode.trim();
|
|
134
|
+
if (cleanCode.endsWith(';'))
|
|
135
|
+
cleanCode = cleanCode.slice(0, -1);
|
|
136
|
+
// Fix the @extends JSDoc
|
|
137
|
+
cleanCode = cleanCode.replace(/@extends\s+\{[A-Za-z0-9_]+</g, '@extends {Base<');
|
|
138
|
+
return cleanCode;
|
|
139
|
+
}
|
|
140
|
+
/**
|
|
141
|
+
* Executes the build process.
|
|
142
|
+
*
|
|
143
|
+
* @returns {Promise<void>}
|
|
144
|
+
*/
|
|
145
|
+
async build() {
|
|
146
|
+
try {
|
|
147
|
+
let entryContent = await readFile(this.entryFile, 'utf8');
|
|
148
|
+
// Find all plugins being inserted
|
|
149
|
+
const insertRegex = /\.insert\(\s*([a-zA-Z0-9_]+)\s*\)/g;
|
|
150
|
+
const pluginsToInline = [...entryContent.matchAll(insertRegex)].map((m) => m[1]);
|
|
151
|
+
if (pluginsToInline.length === 0) {
|
|
152
|
+
console.log('No plugins found to inline.');
|
|
153
|
+
return;
|
|
154
|
+
}
|
|
155
|
+
// 1. Identify original import paths for the plugins before any modifications
|
|
156
|
+
const pluginTargets = [];
|
|
157
|
+
const entryImportRegex = /^import\s+[^;]+;/gm;
|
|
158
|
+
const entryImportsMatch = entryContent.match(entryImportRegex) || [];
|
|
159
|
+
for (const pluginName of pluginsToInline) {
|
|
160
|
+
const importLine = entryImportsMatch.find((imp) => imp.includes(` ${pluginName} `));
|
|
161
|
+
if (importLine) {
|
|
162
|
+
const pathMatch = importLine.match(/from\s+['"]([^'"]+)['"]/);
|
|
163
|
+
if (pathMatch) {
|
|
164
|
+
pluginTargets.push({
|
|
165
|
+
name: pluginName,
|
|
166
|
+
importPath: pathMatch[1],
|
|
167
|
+
originalImportLine: importLine,
|
|
168
|
+
});
|
|
169
|
+
// Remove the plugin import line so it isn't rewritten and hoisted normally
|
|
170
|
+
entryContent = entryContent.replace(importLine, '');
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
// 2. Rewrite paths and hoist from the main entry file
|
|
175
|
+
entryContent = this._rewritePathsInString(entryContent, this.entryDir, false, null);
|
|
176
|
+
entryContent = this._extractAndHoist(entryContent);
|
|
177
|
+
// 3. Process each plugin using their original import paths
|
|
178
|
+
for (const target of pluginTargets) {
|
|
179
|
+
const isNpm = !target.importPath.startsWith('.');
|
|
180
|
+
let pluginFullPath;
|
|
181
|
+
let npmPackageName = null;
|
|
182
|
+
if (isNpm) {
|
|
183
|
+
// Identify NPM package name (handles @scope/package as well)
|
|
184
|
+
const parts = target.importPath.split('/');
|
|
185
|
+
npmPackageName = target.importPath.startsWith('@') ? `${parts[0]}/${parts[1]}` : parts[0];
|
|
186
|
+
try {
|
|
187
|
+
// Locate the physical file inside node_modules
|
|
188
|
+
pluginFullPath = require.resolve(target.importPath, { paths: [this.entryDir] });
|
|
189
|
+
}
|
|
190
|
+
catch (e) {
|
|
191
|
+
console.error(`Error: Could not resolve NPM module: ${target.importPath}`);
|
|
192
|
+
throw e;
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
else {
|
|
196
|
+
pluginFullPath = resolve(this.entryDir, target.importPath);
|
|
197
|
+
}
|
|
198
|
+
const pluginSourceDir = dirname(pluginFullPath);
|
|
199
|
+
let pluginCode = await readFile(pluginFullPath, 'utf8');
|
|
200
|
+
// Rewrite internal paths (handles NPM isolation vs Local Root Replacement)
|
|
201
|
+
pluginCode = this._rewritePathsInString(pluginCode, pluginSourceDir, isNpm, npmPackageName);
|
|
202
|
+
// Hoist dependencies
|
|
203
|
+
pluginCode = this._extractAndHoist(pluginCode);
|
|
204
|
+
// Format and inject
|
|
205
|
+
pluginCode = this._formatPluginCode(pluginCode, target.name);
|
|
206
|
+
const insertTarget = new RegExp(`\\.insert\\(\\s*${target.name}\\s*\\)`, 'g');
|
|
207
|
+
entryContent = entryContent.replace(insertTarget, `.insert(\n${pluginCode}\n)`);
|
|
208
|
+
}
|
|
209
|
+
// 4. Final Assembly
|
|
210
|
+
const finalImports = [...this.hoistedImports].join('\n');
|
|
211
|
+
const finalTypedefs = [...this.hoistedTypedefs].join('\n\n');
|
|
212
|
+
const finalOutput = `${finalImports}\n\n${finalTypedefs}\n\n${entryContent}`;
|
|
213
|
+
await mkdir(this.outDir, { recursive: true });
|
|
214
|
+
await writeFile(this.outFile, finalOutput, 'utf8');
|
|
215
|
+
console.log('Build successful! Imports corrected (including JSDoc and NPM modules).');
|
|
216
|
+
}
|
|
217
|
+
catch (error) {
|
|
218
|
+
console.error('Build failed:', error);
|
|
219
|
+
process.exit(1);
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
export default TinyPluginInliner;
|