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.
Files changed (128) hide show
  1. package/.github/workflows/node.js.yml +1 -1
  2. package/README.md +0 -1
  3. package/changelog/1/26/4.md +10 -0
  4. package/changelog/1/27/0.md +24 -0
  5. package/dist/v1/ColorSafeStringify.min.js +1 -1
  6. package/dist/v1/TinyAdvancedRaffle.min.js +1 -1
  7. package/dist/v1/TinyAfterScrollWatcher.min.js +1 -1
  8. package/dist/v1/TinyAnalogClock.min.js +1 -1
  9. package/dist/v1/TinyArrayComparator.min.js +1 -1
  10. package/dist/v1/TinyArrayPaginator.min.js +1 -1
  11. package/dist/v1/TinyBasicsEs.min.js +1 -1
  12. package/dist/v1/TinyClassManager.min.js +1 -1
  13. package/dist/v1/TinyClipboard.min.js +1 -1
  14. package/dist/v1/TinyColorConverter.min.js +1 -1
  15. package/dist/v1/TinyColorValidator.min.js +1 -1
  16. package/dist/v1/TinyCookieConsent.min.js +1 -1
  17. package/dist/v1/TinyDayNightCycle.min.js +1 -1
  18. package/dist/v1/TinyDomReadyManager.min.js +1 -1
  19. package/dist/v1/TinyDragDropDetector.min.js +1 -1
  20. package/dist/v1/TinyDragger.min.js +1 -1
  21. package/dist/v1/TinyElementObserver.min.js +1 -1
  22. package/dist/v1/TinyEssentials.min.js +1 -1
  23. package/dist/v1/TinyEvents.min.js +1 -1
  24. package/dist/v1/TinyGamepad.min.js +1 -1
  25. package/dist/v1/TinyHtml.min.js +1 -1
  26. package/dist/v1/TinyI18.min.js +1 -1
  27. package/dist/v1/TinyIframeEvents.min.js +1 -1
  28. package/dist/v1/TinyInventory.min.js +1 -1
  29. package/dist/v1/TinyInventoryTrader.min.js +1 -1
  30. package/dist/v1/TinyLevelUp.min.js +1 -1
  31. package/dist/v1/TinyLoadingScreen.min.js +1 -1
  32. package/dist/v1/TinyLocalStorage.min.js +1 -1
  33. package/dist/v1/TinyMaInSys.min.js +1 -1
  34. package/dist/v1/TinyMediaPlayer.min.js +1 -0
  35. package/dist/v1/TinyNeedBar.min.js +1 -1
  36. package/dist/v1/TinyNewWinEvents.min.js +1 -1
  37. package/dist/v1/TinyNotifications.min.js +1 -1
  38. package/dist/v1/TinyNotifyCenter.min.js +1 -1
  39. package/dist/v1/TinyPromiseQueue.min.js +1 -1
  40. package/dist/v1/TinyRadioFm.min.js +1 -0
  41. package/dist/v1/TinyRateLimiter.min.js +1 -1
  42. package/dist/v1/TinySimpleDice.min.js +1 -1
  43. package/dist/v1/TinySmartScroller.min.js +1 -1
  44. package/dist/v1/TinyTextDiffer.min.js +1 -1
  45. package/dist/v1/TinyTextRangeEditor.min.js +1 -1
  46. package/dist/v1/TinyTextarea.min.js +1 -1
  47. package/dist/v1/TinyTimeout.min.js +1 -1
  48. package/dist/v1/TinyToastNotify.min.js +1 -1
  49. package/dist/v1/TinyUploadClicker.min.js +1 -1
  50. package/dist/v1/UltraRandomMsgGen.min.js +1 -1
  51. package/dist/v1/basics/index.cjs +5 -0
  52. package/dist/v1/basics/index.d.mts +5 -1
  53. package/dist/v1/basics/index.mjs +2 -1
  54. package/dist/v1/basics/mediaContent.cjs +644 -0
  55. package/dist/v1/basics/mediaContent.d.mts +296 -0
  56. package/dist/v1/basics/mediaContent.mjs +557 -0
  57. package/dist/v1/build/TinyMediaPlayer.cjs +7 -0
  58. package/dist/v1/build/TinyMediaPlayer.d.mts +3 -0
  59. package/dist/v1/build/TinyMediaPlayer.mjs +2 -0
  60. package/dist/v1/build/TinyRadioFm.cjs +7 -0
  61. package/dist/v1/build/TinyRadioFm.d.mts +3 -0
  62. package/dist/v1/build/TinyRadioFm.mjs +2 -0
  63. package/dist/v1/index.cjs +9 -0
  64. package/dist/v1/index.d.mts +7 -1
  65. package/dist/v1/index.mjs +5 -2
  66. package/dist/v1/libs/ColorSafeStringify.d.mts +1 -1
  67. package/dist/v1/libs/TinyAfterScrollWatcher.cjs +16 -3
  68. package/dist/v1/libs/TinyAfterScrollWatcher.d.mts +7 -3
  69. package/dist/v1/libs/TinyAfterScrollWatcher.mjs +13 -3
  70. package/dist/v1/libs/TinyArrayComparator.cjs +14 -11
  71. package/dist/v1/libs/TinyArrayComparator.d.mts +22 -19
  72. package/dist/v1/libs/TinyArrayComparator.mjs +14 -11
  73. package/dist/v1/libs/TinyArrayPaginator.cjs +23 -16
  74. package/dist/v1/libs/TinyArrayPaginator.d.mts +57 -30
  75. package/dist/v1/libs/TinyArrayPaginator.mjs +22 -16
  76. package/dist/v1/libs/TinyClassManager/TinyPluginInliner.cjs +265 -0
  77. package/dist/v1/libs/TinyClassManager/TinyPluginInliner.d.mts +92 -0
  78. package/dist/v1/libs/TinyClassManager/TinyPluginInliner.mjs +223 -0
  79. package/dist/v1/libs/TinyClassManager.cjs +124 -23
  80. package/dist/v1/libs/TinyClassManager.d.mts +33 -13
  81. package/dist/v1/libs/TinyClassManager.mjs +108 -23
  82. package/dist/v1/libs/TinyColorValidator.d.mts +16 -16
  83. package/dist/v1/libs/TinyDragDropDetector.cjs +9 -34
  84. package/dist/v1/libs/TinyDragDropDetector.d.mts +7 -21
  85. package/dist/v1/libs/TinyDragDropDetector.mjs +9 -24
  86. package/dist/v1/libs/TinyDragger.cjs +5 -5
  87. package/dist/v1/libs/TinyDragger.d.mts +4 -3
  88. package/dist/v1/libs/TinyDragger.mjs +5 -5
  89. package/dist/v1/libs/TinyElementObserver.cjs +6 -21
  90. package/dist/v1/libs/TinyElementObserver.d.mts +6 -15
  91. package/dist/v1/libs/TinyElementObserver.mjs +6 -20
  92. package/dist/v1/libs/TinyEvents.cjs +7 -0
  93. package/dist/v1/libs/TinyEvents.d.mts +4 -0
  94. package/dist/v1/libs/TinyEvents.mjs +6 -0
  95. package/dist/v1/libs/TinyGamepad.cjs +4 -6
  96. package/dist/v1/libs/TinyGamepad.d.mts +1 -1
  97. package/dist/v1/libs/TinyHtml/TinyHtmlIcon.d.mts +1 -1
  98. package/dist/v1/libs/TinyHtml/TinyHtmlTemplate.d.mts +1 -1
  99. package/dist/v1/libs/TinyHtml/TinyHtmlTextarea.d.mts +1 -1
  100. package/dist/v1/libs/TinyHtml/index.d.mts +1 -1
  101. package/dist/v1/libs/TinyHtml.cjs +72 -98
  102. package/dist/v1/libs/TinyHtml.d.mts +15 -32
  103. package/dist/v1/libs/TinyHtml.mjs +53 -77
  104. package/dist/v1/libs/TinyInventory.d.mts +1 -1
  105. package/dist/v1/libs/TinyMediaPlayer.cjs +844 -0
  106. package/dist/v1/libs/TinyMediaPlayer.d.mts +306 -0
  107. package/dist/v1/libs/TinyMediaPlayer.mjs +755 -0
  108. package/dist/v1/libs/TinyRadioFm.cjs +1378 -0
  109. package/dist/v1/libs/TinyRadioFm.d.mts +554 -0
  110. package/dist/v1/libs/TinyRadioFm.mjs +1137 -0
  111. package/dist/v1/libs/TinySmartScroller.cjs +39 -26
  112. package/dist/v1/libs/TinySmartScroller.d.mts +16 -62
  113. package/dist/v1/libs/TinySmartScroller.mjs +35 -26
  114. package/dist/v1/libs/UltraRandomMsgGen.d.mts +7 -7
  115. package/dist/v1/libs/examples/TinyClassManager.cjs +43 -41
  116. package/dist/v1/libs/examples/TinyClassManager.mjs +37 -37
  117. package/docs/v1/README.md +6 -0
  118. package/docs/v1/basics/mediaContent.md +131 -0
  119. package/docs/v1/libs/TinyClassManager/TinyPluginInliner.md +107 -0
  120. package/docs/v1/libs/TinyClassManager.md +69 -70
  121. package/docs/v1/libs/TinyDragDropDetector.md +5 -9
  122. package/docs/v1/libs/TinyElementObserver.md +3 -6
  123. package/docs/v1/libs/TinyEvents.md +1 -1
  124. package/docs/v1/libs/TinyHtml.md +0 -29
  125. package/docs/v1/libs/TinyMediaPlayer.md +100 -0
  126. package/docs/v1/libs/TinyRadioFm.md +141 -0
  127. package/docs/v1/libs/TinySmartScroller.md +3 -3
  128. 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 {any} value - The current element being processed in the array.
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 {any[]} array - The full array being processed.
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 {any[]|Set<any>}
32
+ * @type {ArrayItem[]|Set<ArrayItem>}
20
33
  */
21
34
  #data;
22
35
  /**
23
36
  * Gets current stored array.
24
- * @returns {any[]|Set<any>}
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 {any[]|Set<any>} value - The new array to be used as the data source.
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 {any[]|Set<any>} data - The array to be paginated.
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, any> | GetFilter} [settings.filter=null] - Filtering criteria:
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;