@dxtmisha/scripts 0.10.15 → 0.11.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.
@@ -0,0 +1,460 @@
1
+ import { createHash } from 'node:crypto'
2
+ import { forEach, isFilled } from '@dxtmisha/functional-basic'
3
+ import { getPackageJson } from '../../functions/getPackageJson'
4
+ import { PropertiesFile } from '../Properties/PropertiesFile'
5
+ import { DesignTypesAi } from './DesignTypesAi'
6
+
7
+ import type { DesignTypesItem, DesignTypesList } from '../../types/designTypes'
8
+
9
+ import { UI_DIR_AI_TYPES_LIST, UI_DIR_CONSTRUCTOR, UI_FILE_AI_TYPES } from '../../config'
10
+
11
+ /**
12
+ * Engine for scanning declaration files, MD5 change tracking, and generating AI-optimized TypeScript type definitions.
13
+ *
14
+ * Движок для сканирования файлов деклараций, отслеживания изменений по MD5 и генерации оптимизированных ИИ определений типов TypeScript.
15
+ */
16
+ export class DesignTypesMake {
17
+ /** Cached combined full type definitions content / Кэшированный объединенный полный контент определений типов */
18
+ protected fullContent?: string
19
+
20
+ /** Cached combined JS content / Кэшированный объединенный JS контент */
21
+ protected fullJsContent?: string
22
+
23
+ /** Cached list of filtered type definition files / Кэшированный список отфильтрованных файлов определений типов */
24
+ protected listByFilter?: DesignTypesList
25
+
26
+ /** Cached list of filtered JavaScript files / Кэшированный список отфильтрованных JavaScript файлов */
27
+ protected listByFilterJs?: DesignTypesList
28
+
29
+ /**
30
+ * Constructor for DesignTypesMake.
31
+ *
32
+ * Конструктор для DesignTypesMake.
33
+ * @param ai instance of DesignTypesAi for AI optimization and directory configuration / экземпляр DesignTypesAi для ИИ оптимизации и конфигурации директории
34
+ */
35
+ constructor(
36
+ protected readonly ai: DesignTypesAi
37
+ ) { }
38
+
39
+ /**
40
+ * Reads processed type definition files, combines them into a single string, and cleans the content.
41
+ *
42
+ * Читает обработанные файлы определений типов, объединяет их в одну строку и очищает контент.
43
+ * @returns combined and cleaned full type definitions content / объединенное и очищенное содержимое полных определений типов
44
+ */
45
+ getFullContent(): string {
46
+ if (this.fullContent === undefined) {
47
+ const files = this.getListByFilter()
48
+ const processedFiles = this.getListAi(files)
49
+
50
+ this.fullContent = this.toOneFile(processedFiles)
51
+ }
52
+
53
+ return this.fullContent
54
+ }
55
+
56
+ /**
57
+ * Gets the combined JS content for all filtered JavaScript files.
58
+ *
59
+ * Получает объединенный JS контент для всех отфильтрованных JavaScript файлов.
60
+ * @returns combined JS content string / строка объединенного JS контента
61
+ */
62
+ getFullJsContent(): string {
63
+ if (this.fullJsContent === undefined) {
64
+ this.fullJsContent = this.toOneFile(this.getListByFilterJs())
65
+ }
66
+
67
+ return this.fullJsContent
68
+ }
69
+
70
+ /**
71
+ * Main method to execute the type definition generation process and save ai-types.md.
72
+ *
73
+ * Основной метод для выполнения процесса генерации определений типов и сохранения ai-types.md.
74
+ * @returns current instance / текущий экземпляр
75
+ */
76
+ async make(): Promise<this> {
77
+ const files = this.getListByFilter()
78
+ const fullJsContent = this.getFullJsContent()
79
+
80
+ const updatedFiles = this.saveList(files)
81
+
82
+ await this.saveListAi(updatedFiles, fullJsContent)
83
+
84
+ return this.makeSave()
85
+ }
86
+
87
+ /**
88
+ * Generates full types content and saves it to ai-types.md.
89
+ *
90
+ * Генерирует полный контент типов и сохраняет его в ai-types.md.
91
+ * @returns current instance / текущий экземпляр
92
+ */
93
+ makeSave(): this {
94
+ const fullContent = this.getFullContent()
95
+
96
+ this.save(fullContent)
97
+
98
+ return this
99
+ }
100
+
101
+ /**
102
+ * Checks if the content contains type definitions.
103
+ *
104
+ * Проверяет, содержит ли контент определения типов.
105
+ * @param content file content / содержимое файла
106
+ */
107
+ protected isContent(content?: string): content is string {
108
+ return Boolean(
109
+ content
110
+ && content.includes('export')
111
+ )
112
+ }
113
+
114
+ /**
115
+ * Checks if the file is a valid declaration file.
116
+ *
117
+ * Проверяет, является ли файл валидным файлом декларации.
118
+ * @param file file name / имя файла
119
+ */
120
+ protected isFile(file: string): boolean {
121
+ return file.endsWith('.d.ts')
122
+ && !file.endsWith('.vue.d.ts')
123
+ && !file.endsWith('wiki.d.ts')
124
+ && !file.endsWith('wikiData.d.ts')
125
+ && (
126
+ !file.includes(`${UI_DIR_CONSTRUCTOR}/`)
127
+ || file.endsWith('/basicTypes.d.ts')
128
+ || file.endsWith('/types.d.ts')
129
+ || file.endsWith('/props.d.ts')
130
+ )
131
+ }
132
+
133
+ /**
134
+ * Checks if the file is a valid JavaScript or TypeScript file.
135
+ *
136
+ * Проверяет, является ли файл валидным JavaScript или TypeScript файлом.
137
+ * @param file file name / имя файла
138
+ */
139
+ protected isFileJs(file: string): boolean {
140
+ return file.endsWith('.js')
141
+ }
142
+
143
+ /**
144
+ * Checks if the content contains JSDoc comments.
145
+ *
146
+ * Проверяет, содержит ли контент JSDoc комментарии.
147
+ * @param content file content / содержимое файла
148
+ */
149
+ protected hasJSDoc(content: string): boolean {
150
+ return content.includes('/**')
151
+ }
152
+
153
+ /**
154
+ * Reads the directory recursively.
155
+ *
156
+ * Читает директорию рекурсивно.
157
+ */
158
+ protected getList() {
159
+ return PropertiesFile.readDirRecursive(this.ai.getDirArray())
160
+ }
161
+
162
+ /**
163
+ * Gets a list of type definition files with cleaned content read from the AI types list directory.
164
+ *
165
+ * Получает список файлов определений типов с очищенным содержимым, прочитанным из директории списка ИИ типов.
166
+ * @param files list of type definition files / список файлов определений типов
167
+ * @returns list of type definition files with cleaned AI content / список файлов определений типов с очищенным ИИ содержимым
168
+ */
169
+ protected getListAi(files: DesignTypesList): DesignTypesList {
170
+ return forEach(files, (item) => {
171
+ const raw = PropertiesFile.readFileOnly([UI_DIR_AI_TYPES_LIST, item.path])
172
+ const content = raw ? raw.replace(/^\/\/ md5:[^\n]*\n?/, '') : item.content
173
+
174
+ return {
175
+ ...item,
176
+ content: content.trim()
177
+ }
178
+ }) as DesignTypesList
179
+ }
180
+
181
+ /**
182
+ * Gets a list of files filtered by a provided checker function.
183
+ *
184
+ * Получает список файлов, отфильтрованный переданной функцией проверки.
185
+ * @param checkFile function to check if the file matches criteria / функция проверки соответствия файла критериям
186
+ */
187
+ protected getListBy(checkFile: (file: string) => boolean): DesignTypesList {
188
+ return forEach(
189
+ this.getList(),
190
+ (file) => {
191
+ if (checkFile(file)) {
192
+ const content = this.readFile(file)
193
+
194
+ if (this.isContent(content)) {
195
+ return {
196
+ path: file,
197
+ content,
198
+ md5: this.getMd5(content)
199
+ }
200
+ }
201
+ }
202
+
203
+ return undefined
204
+ }
205
+ ) as DesignTypesList
206
+ }
207
+
208
+ /**
209
+ * Gets a list of files filtered by criteria.
210
+ *
211
+ * Получает список файлов, отфильтрованный по критериям.
212
+ * @returns list of filtered type definition files / список отфильтрованных файлов определений типов
213
+ */
214
+ protected getListByFilter(): DesignTypesList {
215
+ if (this.listByFilter === undefined) {
216
+ this.listByFilter = this.getListBy(file => this.isFile(file))
217
+ }
218
+
219
+ return this.listByFilter
220
+ }
221
+
222
+ /**
223
+ * Gets a list of JS files filtered by criteria.
224
+ *
225
+ * Получает список JS файлов, отфильтрованный по критериям.
226
+ * @returns list of filtered JavaScript files / список отфильтрованных JavaScript файлов
227
+ */
228
+ protected getListByFilterJs(): DesignTypesList {
229
+ if (this.listByFilterJs === undefined) {
230
+ this.listByFilterJs = this.getListBy(file => this.isFileJs(file))
231
+ }
232
+
233
+ return this.listByFilterJs
234
+ }
235
+
236
+ /**
237
+ * Generates MD5 hash for the given content.
238
+ *
239
+ * Генерирует MD5 хэш для переданного содержимого.
240
+ * @param content file or text content / содержимое файла или текста
241
+ * @returns MD5 hash string / MD5 хэш строка
242
+ */
243
+ protected getMd5(content: string): string {
244
+ return createHash('md5').update(content.trim()).digest('hex')
245
+ }
246
+
247
+ /**
248
+ * Generates the MD5 header string for a type definition file.
249
+ *
250
+ * Генерирует строку заголовка MD5 для файла определений типов.
251
+ * @param md5 MD5 hash string / строка MD5 хэша
252
+ * @param isProcessed flag indicating if file is AI-processed / флаг, указывающий, обработан ли файл ИИ
253
+ * @returns formatted MD5 header string / отформатированная строка заголовка MD5
254
+ */
255
+ protected getMd5Header(md5?: string, isProcessed: boolean = false): string {
256
+ const status = isProcessed ? ' true' : ''
257
+
258
+ return `// md5:${md5 ?? 'none'}${status}`
259
+ }
260
+
261
+ /**
262
+ * Returns the full path segments for a file.
263
+ *
264
+ * Возвращает сегменты полного пути для файла.
265
+ * @param file file name / имя файла
266
+ */
267
+ protected getPath(file: string): string[] {
268
+ return [...this.ai.getDirArray(), file]
269
+ }
270
+
271
+ /**
272
+ * Cleans up the content by removing imports, local exports, and empty lines.
273
+ *
274
+ * Очищает контент, удаляя импорты, локальные экспорты и пустые строки.
275
+ * @param content content to clean / контент для очистки
276
+ */
277
+ protected cleanContent(content: string): string {
278
+ return content
279
+ .replace(/^import\s+(?:{[^}]+}|[^{]+)\s+from\s+['"]\.[^'"]+['"];?/gm, '')
280
+ .replace(/^import\s+['"]\.[^'"]+['"];?/gm, '')
281
+ .replace(/^export\s+(?:\*|{[^}]+})\s+from\s+['"]\.[^'"]+['"];?/gm, '')
282
+ .replace(/^\s*(?:private|protected)\s+[^({]+;/gm, '')
283
+ .replace(/^\s*\/\/.*$/gm, '')
284
+ .replace(/^\s*[\r\n]/gm, '')
285
+ .trim()
286
+ }
287
+
288
+ /**
289
+ * Reads the content of a file.
290
+ *
291
+ * Читает содержимое файла.
292
+ * @param path file path / путь к файлу
293
+ */
294
+ protected readFile(path: string): string | undefined {
295
+ return PropertiesFile.readFileOnly(this.getPath(path))
296
+ }
297
+
298
+ /**
299
+ * Saves the generated content to a file.
300
+ *
301
+ * Сохраняет сгенерированный контент в файл.
302
+ * @param content content to save / контент для сохранения
303
+ */
304
+ protected save(content: string) {
305
+ const packageJson = getPackageJson()
306
+
307
+ if (packageJson) {
308
+ const versionStr = packageJson.version ? ` (v${packageJson.version})` : ''
309
+ PropertiesFile.writeByPath(
310
+ UI_FILE_AI_TYPES,
311
+ [
312
+ `All these methods are in the ${packageJson.name}${versionStr} library.`,
313
+ '',
314
+ content
315
+ ].join('\n')
316
+ )
317
+ }
318
+ }
319
+
320
+ /**
321
+ * Saves a type definition file to the ai-types-list directory with an MD5 header.
322
+ *
323
+ * Сохраняет файл определений типов в директорию ai-types-list с заголовком MD5.
324
+ * @param item type definition file item / элемент файла определений типов
325
+ * @param isProcessed flag indicating if file is AI-processed / флаг, указывающий, обработан ли файл ИИ
326
+ */
327
+ protected saveFile(item: DesignTypesItem, isProcessed: boolean = false) {
328
+ PropertiesFile.writeByPath(
329
+ [UI_DIR_AI_TYPES_LIST, item.path],
330
+ `${this.getMd5Header(item.md5, isProcessed)}\n${item.content}`
331
+ )
332
+ }
333
+
334
+ /**
335
+ * Saves copies of type definition files to the ai-types-list directory with an MD5 header.
336
+ * Returns files that are new, modified, or not yet marked as AI-processed.
337
+ *
338
+ * Сохраняет копии файлов определений типов в директорию ai-types-list с заголовком MD5.
339
+ * Возвращает файлы, которые являются новыми, измененными или еще не отмеченными как обработанные ИИ.
340
+ * @param files list of type definition files / список файлов определений типов
341
+ * @returns list of updated or unprocessed files / список обновленных или необработанных файлов
342
+ */
343
+ protected saveList(files: DesignTypesList): DesignTypesList {
344
+ return forEach(
345
+ files,
346
+ (item) => {
347
+ const targetPath = [UI_DIR_AI_TYPES_LIST, item.path]
348
+ const oldContent = PropertiesFile.readFileOnly(targetPath)
349
+
350
+ if (
351
+ !isFilled(oldContent)
352
+ || !oldContent.startsWith(this.getMd5Header(item.md5))
353
+ ) {
354
+ this.saveFile(item)
355
+
356
+ return item
357
+ }
358
+
359
+ if (
360
+ !oldContent.startsWith(this.getMd5Header(item.md5, true))
361
+ ) {
362
+ return item
363
+ }
364
+
365
+ return undefined
366
+ }
367
+ ) as DesignTypesList
368
+ }
369
+
370
+ /**
371
+ * Processes a list of updated type definition files through AI and saves them with an AI-processed header.
372
+ *
373
+ * Обрабатывает список обновленных файлов определений типов через ИИ и сохраняет их с заголовком ИИ-обработки.
374
+ * @param files list of updated type definition files / список обновленных файлов определений типов
375
+ * @param fullJsContent combined JS content for context / объединенный JS контент для контекста
376
+ */
377
+ protected async saveListAi(
378
+ files: DesignTypesList,
379
+ fullJsContent: string
380
+ ): Promise<void> {
381
+ const total = files.length
382
+
383
+ for (let index = 0; index < total; index += 1) {
384
+ const item = files[index]
385
+ let content = this.cleanContent(item.content)
386
+
387
+ if (isFilled(content)) {
388
+ console.log(`-- processing AI types [${index + 1}/${total}] for ${item.path}...`)
389
+ content = await this.toAiEdit(
390
+ content,
391
+ this.hasJSDoc(content) ? '' : fullJsContent
392
+ )
393
+ }
394
+
395
+ this.saveFile(
396
+ {
397
+ ...item,
398
+ content
399
+ },
400
+ true
401
+ )
402
+ }
403
+ }
404
+
405
+ /**
406
+ * Sends content to AI for optimization.
407
+ *
408
+ * Отправляет контент ИИ для оптимизации.
409
+ * @param content content to optimize / контент для оптимизации
410
+ * @param code code to optimize / код для оптимизации
411
+ * @returns optimized content string / строка оптимизированного контента
412
+ */
413
+ protected async toAiEdit(content: string, code: string): Promise<string> {
414
+ const generate = await this.ai.toAi(
415
+ content,
416
+ 'Goal: Optimize TypeScript type definitions for declarations in `File Content`.\n\n'
417
+ + 'SCOPE & CONTEXT:\n'
418
+ + '- Process STRICTLY entities in `File Content`. Do NOT add unexported entities or code from `File JS Code`.\n'
419
+ + '- Use `File JS Code` ONLY as reference to understand implementation logic for writing JSDoc descriptions.\n'
420
+ + '- AI coding agents will rely EXCLUSIVELY on this output. Ensure complete type contracts and clear JSDoc descriptions.\n'
421
+ + '- Do NOT include file paths, links, or internal imports in the output.\n\n'
422
+ + 'JSDOC RULES:\n'
423
+ + '- MANDATORY FOR ALL CLASSES, METHODS, FUNCTIONS & ACCESSORS: Every `class`, `declare class`, `abstract class`, `function`, `declare function`, method (public/static/abstract), `constructor`, and `get`/`set` accessor MUST ALWAYS have a JSDoc description.\n'
424
+ + ' * Style: Descriptions MUST be maximally clear and informative, yet maximally short and concise. Avoid fluff.\n'
425
+ + ' * Single-Line Preference: Prefer single-line JSDoc format (`/** Description @keywords search_terms */`) to conserve vertical space and reduce file size.\n'
426
+ + ' * Remove `@return` / `@returns`: STRICTLY REMOVE `@return` and `@returns` tags from all JSDoc comments.\n'
427
+ + ' * `@param` Tag: Include `@param` ONLY if critically necessary to clarify parameter behavior; otherwise omit `@param`.\n'
428
+ + ' * AI Search Keywords: Include relevant search tags/keywords (e.g. `@keywords` tag or search terms) to help AI code search easily discover functionality.\n'
429
+ + ' * Allowed tags: PRESERVE ONLY `@example`, `@remarks`, `@note`, `@warning`, `@keywords`, and critical `@param` tags. Remove `@return`/`@returns` and all other tags.\n'
430
+ + ' * If JSDoc is missing: Generate a clear, concise, search-optimized English JSDoc derived from inspecting `File JS Code`.\n'
431
+ + ' * If JSDoc exists: Optimize, condense, translate to English, and apply tag rules.\n'
432
+ + '- TYPES, INTERFACES & ENUMS: Delete JSDoc for simple/obvious types; add or keep concise JSDoc for complex types.\n'
433
+ + '- Place JSDoc directly above declarations. Remove regular inline comments (`//` or `/* */`).\n\n'
434
+ + 'CLEANING & STRUCTURING:\n'
435
+ + '- Remove internal `import` statements and internal re-exports. Keep external package exports.\n'
436
+ + '- Delete non-public content (private/protected members, unexported elements). Keep all public API surfaces.\n'
437
+ + '- Do NOT delete any `type` definitions. Preserve abstract classes.\n'
438
+ + '- Format output tightly without unnecessary blank lines.\n\n'
439
+ + 'OUTPUT FORMAT:\n'
440
+ + 'Return ONLY raw TypeScript code corresponding to `File Content`. No markdown, no code blocks (```), no text explanations.',
441
+ code
442
+ )
443
+
444
+ return generate ?? content
445
+ }
446
+
447
+ /**
448
+ * Combines a list of files into a single string.
449
+ *
450
+ * Объединяет список файлов в одну строку.
451
+ * @param list list of files / список файлов
452
+ */
453
+ protected toOneFile(list: DesignTypesList): string {
454
+ return forEach(
455
+ list,
456
+ item => item.content
457
+ )
458
+ .join('\n\n')
459
+ }
460
+ }
@@ -0,0 +1,90 @@
1
+ import { isFilled } from '@dxtmisha/functional-basic'
2
+
3
+ import { PropertiesFile } from '../Properties/PropertiesFile'
4
+ import { DesignTypesAi } from './DesignTypesAi'
5
+ import { DesignTypesPrompts } from './DesignTypesPrompts'
6
+
7
+ import type { DesignMcpResourceItem } from '../../types/designTypes'
8
+
9
+ import { UI_FILE_AI_DESCRIPTION, UI_FILE_AI_MCP, UI_FILE_AI_TYPES } from '../../config'
10
+
11
+ /**
12
+ * Class for generating, processing, and saving MCP server resources for AI documentation.
13
+ *
14
+ * Класс для генерации, обработки и сохранения ресурсов MCP-сервера для ИИ документации.
15
+ */
16
+ export class DesignTypesMcp {
17
+ /**
18
+ * Constructor for DesignTypesMcp.
19
+ *
20
+ * Конструктор для DesignTypesMcp.
21
+ * @param ai instance of DesignTypesAi for AI interactions / экземпляр DesignTypesAi для ИИ взаимодействия
22
+ * @param prompts instance of DesignTypesPrompts for prompt list management / экземпляр DesignTypesPrompts для управления списком промптов
23
+ * @param isRaw flag disabling AI processing / флаг отключения ИИ обработки
24
+ */
25
+ constructor(
26
+ protected readonly ai: DesignTypesAi,
27
+ protected readonly prompts: DesignTypesPrompts,
28
+ protected readonly isRaw: boolean = false
29
+ ) { }
30
+
31
+ /**
32
+ * Generates and saves MCP server resources file.
33
+ *
34
+ * Генерирует и сохраняет файл ресурсов MCP-сервера.
35
+ * @returns current instance / текущий экземпляр
36
+ */
37
+ async make(): Promise<this> {
38
+ const projectName = this.ai.getProjectName()
39
+ const resources: DesignMcpResourceItem[] = []
40
+
41
+ if (!this.isRaw) {
42
+ resources.push({
43
+ uri: `${projectName}/${UI_FILE_AI_TYPES}`,
44
+ name: `Type Definitions (${projectName})`,
45
+ mimeType: 'text/markdown',
46
+ description: 'TypeScript type definitions and signatures for AI coding assistant.'
47
+ })
48
+
49
+ resources.push({
50
+ uri: `${projectName}/${UI_FILE_AI_DESCRIPTION}`,
51
+ name: `Project Overview (${projectName})`,
52
+ mimeType: 'text/markdown',
53
+ description: 'Project overview, usage guidelines, and mandatory prompt rules for AI coding assistant.'
54
+ })
55
+
56
+ const cache = this.prompts.getCacheList()
57
+
58
+ for (const item of cache) {
59
+ if (
60
+ isFilled(item.name)
61
+ && isFilled(item.description)
62
+ ) {
63
+ resources.push({
64
+ uri: `${projectName}/${item.path}`,
65
+ name: `${item.name} (${projectName})`,
66
+ mimeType: 'text/markdown',
67
+ description: item.description
68
+ })
69
+ }
70
+ }
71
+ }
72
+
73
+ this.saveMcp(resources)
74
+
75
+ return this
76
+ }
77
+
78
+ /**
79
+ * Saves the MCP server resources to a JSON file.
80
+ *
81
+ * Сохраняет ресурсы MCP-сервера в JSON файл.
82
+ * @param data data to save / данные для сохранения
83
+ */
84
+ protected saveMcp(data: object): void {
85
+ PropertiesFile.writeByPath(
86
+ UI_FILE_AI_MCP,
87
+ JSON.stringify(data, null, 2)
88
+ )
89
+ }
90
+ }