@dxtmisha/scripts 0.4.7 → 0.5.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (140) hide show
  1. package/bin/ai-doc.ts +9 -0
  2. package/package.json +9 -7
  3. package/src/classes/Ai/AiAbstract.ts +94 -13
  4. package/src/classes/Ai/AiDoc.ts +62 -0
  5. package/src/classes/Ai/AiDocItem.ts +20 -0
  6. package/src/classes/Ai/AiDocItemAbstract.ts +198 -0
  7. package/src/classes/Ai/AiDocItemClasses.ts +20 -0
  8. package/src/classes/Ai/AiDocItemComposables.ts +13 -0
  9. package/src/classes/Ai/AiDocType.ts +45 -0
  10. package/src/classes/Ai/AiGoogle.ts +7 -29
  11. package/src/classes/Ai/AiGoogleCli.ts +24 -0
  12. package/src/classes/Ai/AiGoogleCliLite.ts +144 -0
  13. package/src/classes/Ai/AiGoogleLite.ts +77 -0
  14. package/src/classes/BuildItem.ts +176 -0
  15. package/src/classes/Component/ComponentCreator.ts +2 -0
  16. package/src/classes/Component/ComponentItem.ts +3 -1
  17. package/src/classes/Component/ComponentWiki.ts +107 -190
  18. package/src/classes/Component/ComponentWikiFile.ts +102 -15
  19. package/src/classes/Design/DesignCommand.ts +3 -1
  20. package/src/classes/Design/DesignComponent.ts +3 -1
  21. package/src/classes/Design/DesignConstructor.ts +3 -1
  22. package/src/classes/Design/DesignConstructors.ts +3 -1
  23. package/src/classes/Design/DesignReplace.ts +3 -1
  24. package/src/classes/Design/DesignStructure.ts +3 -1
  25. package/src/classes/Design/DesignStructureClasses.ts +3 -1
  26. package/src/classes/Design/DesignStructureItemAbstract.ts +2 -0
  27. package/src/classes/Design/DesignStructureRead.ts +3 -1
  28. package/src/classes/Design/DesignStructureStyles.ts +2 -0
  29. package/src/classes/Design/DesignTypescript.ts +1 -1
  30. package/src/classes/Design/DesignUi.ts +3 -1
  31. package/src/classes/Design/DesignWiki.ts +3 -1
  32. package/src/classes/Git/GitRead.ts +258 -0
  33. package/src/classes/Library/LibraryExport.ts +2 -0
  34. package/src/classes/Library/LibraryFlags.ts +3 -1
  35. package/src/classes/Library/LibraryItems.ts +3 -1
  36. package/src/classes/Library/LibraryMedia.ts +3 -1
  37. package/src/classes/Package/PackageInit.ts +2 -0
  38. package/src/classes/Package/PackageItem.ts +2 -0
  39. package/src/classes/Properties/Properties.ts +3 -1
  40. package/src/classes/Properties/PropertiesCache.ts +3 -1
  41. package/src/classes/Properties/PropertiesConfig.ts +21 -0
  42. package/src/classes/Properties/PropertiesConvector.ts +3 -1
  43. package/src/classes/Properties/PropertiesFile.ts +11 -1
  44. package/src/classes/Properties/PropertiesImport.ts +3 -1
  45. package/src/classes/Properties/PropertiesItems.ts +3 -1
  46. package/src/classes/Properties/PropertiesKeys.ts +3 -1
  47. package/src/classes/Properties/PropertiesMain.ts +3 -1
  48. package/src/classes/Properties/PropertiesPalette.ts +3 -1
  49. package/src/classes/Properties/PropertiesPath.ts +3 -1
  50. package/src/classes/Properties/PropertiesScss.ts +3 -1
  51. package/src/classes/Properties/PropertiesSeparator.ts +3 -1
  52. package/src/classes/Properties/PropertiesSettings.ts +3 -1
  53. package/src/classes/Properties/PropertiesStandard.ts +3 -1
  54. package/src/classes/Properties/PropertiesTool.ts +3 -1
  55. package/src/classes/Properties/PropertiesTypes.ts +3 -1
  56. package/src/classes/Properties/PropertiesValues.ts +2 -0
  57. package/src/classes/Properties/PropertiesWrap.ts +3 -1
  58. package/src/classes/Properties/convector/convectorColor.ts +2 -0
  59. package/src/classes/Properties/convector/convectorFontFamilies.ts +2 -0
  60. package/src/classes/Properties/convector/convectorShadow.ts +3 -1
  61. package/src/classes/Properties/convector/convectorTypography.ts +3 -1
  62. package/src/classes/Properties/to/PropertiesToAbstract.ts +2 -0
  63. package/src/classes/Properties/to/PropertiesToAnimate.ts +3 -1
  64. package/src/classes/Properties/to/PropertiesToClass.ts +2 -0
  65. package/src/classes/Properties/to/PropertiesToClone.ts +3 -1
  66. package/src/classes/Properties/to/PropertiesToComponent.ts +2 -0
  67. package/src/classes/Properties/to/PropertiesToDrag.ts +3 -1
  68. package/src/classes/Properties/to/PropertiesToDuplicate.ts +3 -1
  69. package/src/classes/Properties/to/PropertiesToFull.ts +2 -0
  70. package/src/classes/Properties/to/PropertiesToLink.ts +3 -1
  71. package/src/classes/Properties/to/PropertiesToMedia.ts +3 -1
  72. package/src/classes/Properties/to/PropertiesToMulti.ts +3 -1
  73. package/src/classes/Properties/to/PropertiesToNone.ts +3 -1
  74. package/src/classes/Properties/to/PropertiesToPalette.ts +3 -1
  75. package/src/classes/Properties/to/PropertiesToProperty.ts +3 -1
  76. package/src/classes/Properties/to/PropertiesToRemove.ts +3 -1
  77. package/src/classes/Properties/to/PropertiesToReplace.ts +2 -0
  78. package/src/classes/Properties/to/PropertiesToRoot.ts +2 -0
  79. package/src/classes/Properties/to/PropertiesToSimilar.ts +3 -1
  80. package/src/classes/Properties/to/PropertiesToSort.ts +3 -1
  81. package/src/classes/Properties/to/PropertiesToState.ts +3 -1
  82. package/src/classes/Properties/to/PropertiesToStyle.ts +3 -1
  83. package/src/classes/Properties/to/PropertiesToSub.ts +2 -0
  84. package/src/classes/Properties/to/PropertiesToSubclass.ts +2 -0
  85. package/src/classes/Properties/to/PropertiesToVar.ts +3 -1
  86. package/src/classes/Properties/to/PropertiesToVariable.ts +3 -1
  87. package/src/classes/Styles/Styles.ts +3 -1
  88. package/src/classes/Styles/StylesClasses.ts +3 -1
  89. package/src/classes/Styles/StylesProperties.ts +2 -0
  90. package/src/classes/Styles/StylesRoot.ts +2 -0
  91. package/src/classes/Styles/StylesTool.ts +3 -1
  92. package/src/classes/Styles/to/StylesToAbstract.ts +3 -1
  93. package/src/classes/Styles/to/StylesToAnimate.ts +2 -0
  94. package/src/classes/Styles/to/StylesToClass.ts +2 -0
  95. package/src/classes/Styles/to/StylesToClassFull.ts +2 -0
  96. package/src/classes/Styles/to/StylesToContainer.ts +2 -0
  97. package/src/classes/Styles/to/StylesToMedia.ts +2 -0
  98. package/src/classes/Styles/to/StylesToProperty.ts +3 -1
  99. package/src/classes/Styles/to/StylesToRoot.ts +2 -0
  100. package/src/classes/Styles/to/StylesToSelector.ts +3 -1
  101. package/src/classes/Styles/to/StylesToVar.ts +3 -1
  102. package/src/classes/Styles/to/StylesToVirtual.ts +2 -0
  103. package/src/composables/useAi.ts +3 -0
  104. package/src/config.ts +11 -0
  105. package/src/functions/getComponentPaths.ts +2 -0
  106. package/src/functions/getConfigAi.ts +13 -0
  107. package/src/functions/getConstructorProperties.ts +3 -1
  108. package/src/functions/getNameDirByPaths.ts +2 -0
  109. package/src/functions/toPathStandardSep.ts +2 -0
  110. package/src/library-ai.ts +4 -0
  111. package/src/library.ts +30 -105
  112. package/src/media/ai/ai-doc-types.ts +21 -0
  113. package/src/media/properties/css.ts +4 -1
  114. package/src/media/properties/listSort.ts +1 -1
  115. package/src/media/properties/style.ts +2 -0
  116. package/src/media/templates/component/DesignComponent.vue +1 -1
  117. package/src/media/templates/constructors/ConstructorsDesign.tsx +4 -2
  118. package/src/media/templates/packages/library/package.json +2 -1
  119. package/src/media/templates/prompts/aiDocClassPrompt.en.txt +66 -0
  120. package/src/media/templates/prompts/aiDocClassPrompt.ru.txt +64 -0
  121. package/src/media/templates/prompts/aiDocComposablePrompt.en.txt +67 -0
  122. package/src/media/templates/prompts/aiDocComposablePrompt.ru.txt +67 -0
  123. package/src/media/templates/prompts/aiDocFunctionPrompt.en.txt +57 -0
  124. package/src/media/templates/prompts/aiDocFunctionPrompt.ru.txt +57 -0
  125. package/src/media/templates/prompts/componentPrompt.en.txt +105 -0
  126. package/src/media/templates/prompts/componentPrompt.ru.txt +105 -0
  127. package/src/media/templates/prompts/demoClassEn.mdx +111 -0
  128. package/src/media/templates/prompts/demoClassRu.mdx +111 -0
  129. package/src/media/templates/prompts/demoComponentEn.mdx +282 -0
  130. package/src/media/templates/prompts/demoComponentRu.mdx +282 -0
  131. package/src/media/templates/prompts/demoComposableEn.mdx +103 -0
  132. package/src/media/templates/prompts/demoComposableRu.mdx +103 -0
  133. package/src/media/templates/prompts/demoDocEn.mdx +30 -0
  134. package/src/media/templates/prompts/demoDocRu.mdx +30 -0
  135. package/src/media/templates/viteComponentTemplateConfig.ts +1 -1
  136. package/src/types/aiTypes.ts +19 -0
  137. package/src/types/configTypes.ts +8 -2
  138. package/src/types/gitTypes.ts +59 -0
  139. package/src/media/templates/componentPrompt.en.txt +0 -541
  140. package/src/media/templates/componentPrompt.ru.txt +0 -539
@@ -1,29 +1,28 @@
1
- import { exec } from 'node:child_process'
2
- import { promisify } from 'node:util'
1
+ // export:none
2
+
3
3
  import { getNameDirByPaths } from '../../functions/getNameDirByPaths'
4
4
  import { useAi } from '../../composables/useAi'
5
5
 
6
6
  import { PropertiesConfig } from '../Properties/PropertiesConfig'
7
- import { PropertiesFile } from '../Properties/PropertiesFile'
7
+ import { BuildItem } from '../BuildItem'
8
8
  import { ComponentWikiFile } from './ComponentWikiFile'
9
9
 
10
+ import type { AiAbstract } from '../Ai/AiAbstract'
11
+
10
12
  import {
11
- UI_DIR_DIST,
12
13
  UI_DIR_TEMPORARY,
13
14
  UI_DIR_WIKI,
14
- UI_DIRS_COMPONENTS,
15
- UI_FILE_NAME_VITE,
16
- UI_FILE_NAME_VITE_WORKERS
15
+ UI_DIRS_COMPONENTS
17
16
  } from '../../config'
18
- import { isFilled } from '@dxtmisha/functional'
19
-
20
- // Sample Vite config template path / Путь к шаблону Vite-конфига
21
- const FILE_VITE_SAMPLE = [__dirname, '..', '..', 'media', 'templates', 'viteComponentTemplateConfig.ts']
22
- // Sample AI prompt template path / Путь к шаблону AI-промпта
23
- const FILE_PROMPT_SAMPLE = [__dirname, '..', '..', 'media', 'templates', 'componentPrompt.en.txt']
24
17
 
25
- // Async exec wrapper / Обёртка для асинхронного exec
26
- const execAsync = promisify(exec)
18
+ /** Sample templates directory / Директория с шаблонами */
19
+ const DIR_SAMPLE = [__dirname, '..', '..', 'media', 'templates', 'prompts']
20
+ /** Sample AI prompt template path / Путь к шаблону AI-промпта */
21
+ const FILE_PROMPT_SAMPLE = [...DIR_SAMPLE, 'componentPrompt.en.txt']
22
+ /** Sample demo component MDX path / Путь к MDX демо-компоненту */
23
+ const FILE_DEMO_SAMPLE = [...DIR_SAMPLE, 'demoComponentEn.mdx']
24
+ /** Marker indicating no changes needed / Метка, указывающая на отсутствие изменений */
25
+ const MARK_FULL = '--FULL--'
27
26
 
28
27
  /**
29
28
  * Generates wiki artifacts (code snapshot, stories, mdx) for a component.
@@ -33,24 +32,22 @@ const execAsync = promisify(exec)
33
32
  * Использует временный билд + AI промпт для (пере)создания документации.
34
33
  */
35
34
  export class ComponentWiki {
36
- // Template vite config file / Файл шаблона vite-конфига
37
- protected readonly viteSample: ComponentWikiFile
38
- // Template prompt file / Файл шаблона промпта
39
- protected readonly promptSample: ComponentWikiFile
35
+ protected readonly build: BuildItem
40
36
 
41
- // Aggregated built code file / Файл агрегированного собранного кода
37
+ /** Code file (original or AI regenerated) / Файл кода (оригинал или пересозданный ИИ) */
42
38
  protected readonly codeFile: ComponentWikiFile
43
- // Types file (original or AI regenerated) / Файл типов (оригинал или пересозданный ИИ)
39
+ /** Types file (original or AI regenerated) / Файл типов (оригинал или пересозданный ИИ) */
44
40
  protected readonly typesFile: ComponentWikiFile
45
- // Stories file (Storybook) / Файл сторис (Storybook)
41
+ /** Stories file (Storybook) / Файл сторис (Storybook) */
46
42
  protected readonly storiesFile: ComponentWikiFile
47
- // MDX documentation file / Файл MDX документации
43
+ /** MDX documentation file / Файл MDX документации */
48
44
  protected readonly mdFile: ComponentWikiFile
49
45
 
50
- // Prepared AI prompt file / Файл подготовленного AI промпта
51
- protected readonly promptFile: ComponentWikiFile
52
- // Raw AI output file / Файл «сырого» вывода ИИ
53
- protected readonly aiFile: ComponentWikiFile
46
+ /** AI instance / Экземпляр ИИ */
47
+ protected readonly ai?: AiAbstract
48
+
49
+ /** Description from AI / Описание от ИИ */
50
+ protected description?: string
54
51
 
55
52
  /**
56
53
  * Constructor
@@ -61,38 +58,31 @@ export class ComponentWiki {
61
58
  protected readonly path: string,
62
59
  protected readonly prompt: string = ''
63
60
  ) {
64
- this.viteSample = new ComponentWikiFile(FILE_VITE_SAMPLE)
65
- this.promptSample = new ComponentWikiFile(FILE_PROMPT_SAMPLE)
61
+ this.build = new BuildItem(
62
+ `${this.getRootComponent().join('/')}/index.ts`
63
+ )
66
64
 
67
65
  this.codeFile = new ComponentWikiFile([
68
- ...this.getPathTemporary(),
69
- 'code.txt'
70
- ])
66
+ ...this.getRootComponent(),
67
+ `${this.getName()}.vue`
68
+ ], false, false)
71
69
 
72
70
  this.typesFile = new ComponentWikiFile([
73
71
  ...this.getRootComponent(),
74
72
  'types.ts'
75
- ])
73
+ ], false, false)
76
74
 
77
75
  this.storiesFile = new ComponentWikiFile([
78
76
  ...this.getPathWiki(),
79
77
  `${this.getName()}.stories.ts`
80
- ])
78
+ ], false, false)
81
79
 
82
80
  this.mdFile = new ComponentWikiFile([
83
81
  ...this.getPathWiki(),
84
82
  `${this.getName()}.mdx`
85
- ])
86
-
87
- this.promptFile = new ComponentWikiFile([
88
- ...this.getPathTemporary(),
89
- 'prompt.txt'
90
- ])
83
+ ], true, false)
91
84
 
92
- this.aiFile = new ComponentWikiFile([
93
- ...this.getPathTemporary(),
94
- 'ai.txt'
95
- ])
85
+ this.ai = useAi()
96
86
  }
97
87
 
98
88
  /**
@@ -101,19 +91,26 @@ export class ComponentWiki {
101
91
  * Оркестрирует билд + извлечение файлов + генерацию через ИИ.
102
92
  */
103
93
  make(): void {
104
- console.log('Component wiki:', this.path)
105
-
106
- this.build()
107
- .then((status) => {
108
- if (status) {
109
- this.readAndWriteALlFiles()
110
- this.readAndWritePrompt()
111
-
112
- this.aiGenerate().then(() => console.log('End'))
113
- } else {
114
- console.log('Error!', this.path)
115
- }
116
- })
94
+ console.log('Component wiki:', this.path, '...')
95
+
96
+ if (this.ai) {
97
+ this.build
98
+ .make()
99
+ .then((status) => {
100
+ if (status) {
101
+ this.makeAi()
102
+ this.aiGenerate()
103
+ .then(() => {
104
+ console.log('...', 'End')
105
+ this.build.removeDir()
106
+ })
107
+ } else {
108
+ console.log('Error!', this.path)
109
+ }
110
+ })
111
+ } else {
112
+ console.error('AI is not configured.')
113
+ }
117
114
  }
118
115
 
119
116
  /**
@@ -152,18 +149,6 @@ export class ComponentWiki {
152
149
  ]
153
150
  }
154
151
 
155
- /**
156
- * Returns distribution temp directory path segments.
157
- *
158
- * Возвращает сегменты пути дистрибутива (temp).
159
- */
160
- protected getPathTemporaryDist(): string[] {
161
- return [
162
- ...this.getPathTemporary(),
163
- UI_DIR_DIST
164
- ]
165
- }
166
-
167
152
  /**
168
153
  * Derives component folder name.
169
154
  *
@@ -174,131 +159,39 @@ export class ComponentWiki {
174
159
  }
175
160
 
176
161
  /**
177
- * Saves existing vite config aside (rename) before custom build.
162
+ * Reads the demo file content.
178
163
  *
179
- * Сохраняет существующий vite-конфиг (переименовывает) перед кастомным билдом.
164
+ * Читает содержимое демо-файла.
180
165
  */
181
- protected saveViteConfig() {
182
- if (
183
- !PropertiesFile.is(UI_FILE_NAME_VITE_WORKERS)
184
- ) {
185
- PropertiesFile.rename(
186
- UI_FILE_NAME_VITE,
187
- UI_FILE_NAME_VITE_WORKERS
188
- )
189
- }
166
+ protected readDemo(): string {
167
+ return new ComponentWikiFile(FILE_DEMO_SAMPLE).read()
190
168
  }
191
169
 
192
170
  /**
193
- * Restores original vite config after build.
171
+ * Reads the prompt template.
194
172
  *
195
- * Восстанавливает оригинальный vite-конфиг после билда.
173
+ * Читает шаблон промпта.
196
174
  */
197
- protected resetViteConfig() {
198
- if (
199
- PropertiesFile.is(UI_FILE_NAME_VITE_WORKERS)
200
- ) {
201
- PropertiesFile.removeFile(UI_FILE_NAME_VITE)
202
- PropertiesFile.rename(
203
- UI_FILE_NAME_VITE_WORKERS,
204
- UI_FILE_NAME_VITE
205
- )
206
- }
207
- }
208
-
209
- /**
210
- * Runs build command (npm run build) capturing stdout/stderr.
211
- *
212
- * Запускает команду билда (npm run build), перехватывая stdout/stderr.
213
- */
214
- protected async run(): Promise<boolean> {
215
- try {
216
- const { stdout, stderr } = await execAsync('npm run build')
217
-
218
- console.info(stdout)
219
-
220
- if (stderr) {
221
- console.error('STD error', stderr)
222
- }
223
-
224
- return true
225
- } catch (error) {
226
- console.error('Error', error)
227
- }
228
-
229
- return false
230
- }
231
-
232
- /**
233
- * Prepares temporary vite config, triggers build, then restores original.
234
- *
235
- * Готовит временный vite-конфиг, запускает билд, затем восстанавливает оригинал.
236
- */
237
- protected async build(): Promise<boolean> {
238
- this.saveViteConfig()
239
-
240
- const path = this.getRootComponent().join('/')
241
- const vite = this.viteSample
175
+ protected readPrompt(): string {
176
+ return new ComponentWikiFile(FILE_PROMPT_SAMPLE)
242
177
  .read()
243
- .replace('[path]', path)
244
-
245
- PropertiesFile.writeByPath(UI_FILE_NAME_VITE, vite)
246
-
247
- const status = await this.run()
248
-
249
- this.resetViteConfig()
250
-
251
- return status
178
+ .replace(/\[wikiLanguage]/g, PropertiesConfig.getWikiLanguage())
252
179
  }
253
180
 
254
181
  /**
255
- * Reads built file content and wraps with header comment (file name).
182
+ * Prepares context for AI.
256
183
  *
257
- * Читает содержимое собранного файла и оборачивает заголовком с именем файла.
258
- * @param path relative built file path / относительный путь собранного файла
184
+ * Подготавливает контекст для ИИ.
259
185
  */
260
- protected readFile(path: string): string {
261
- const pathFull = PropertiesFile.joinPath([...this.getPathTemporaryDist(), path])
262
- const content = PropertiesFile.readFileOnly(pathFull)
263
-
264
- return `
265
- // File: ${path}
266
- ${content}
267
- `.trim()
268
- }
269
-
270
- /**
271
- * Aggregates all built files into a single code snapshot file.
272
- *
273
- * Агрегирует все собранные файлы в единый снимок кода.
274
- */
275
- protected readAndWriteALlFiles(): void {
276
- const list = PropertiesFile.readDirRecursive(this.getPathTemporaryDist())
277
- const content: string[] = []
278
-
279
- list.forEach((file) => {
280
- content.push(this.readFile(file))
281
- })
282
-
283
- this.codeFile.write(content.join('\r\n'))
284
- }
285
-
286
- /**
287
- * Builds AI prompt by injecting dynamic code/types/stories/mdx content.
288
- *
289
- * Формирует AI промпт, подставляя динамический код/типы/stories/mdx.
290
- */
291
- protected readAndWritePrompt(): void {
292
- this.promptFile.write(
293
- this.promptSample
294
- .read()
295
- .replace('[code]', this.codeFile.read())
296
- .replace('[types]', this.typesFile.read())
297
- .replace('[stories]', this.storiesFile.read())
298
- .replace('[md]', this.mdFile.read())
299
- .replace(/\[wikiLanguage]/g, PropertiesConfig.getWikiLanguage())
300
- + (isFilled(this.prompt) ? `Additional conditions (these conditions take priority): ${this.prompt}` : '')
301
- )
186
+ protected makeAi(): void {
187
+ if (this.ai) {
188
+ this.ai.addContent(`Code: ${this.build.getCode()}`)
189
+ this.ai.addContent(`Original code: ${this.codeFile.read()}`)
190
+ this.ai.addContent(`Original types.ts: ${this.typesFile.read()}`)
191
+ this.ai.addContent(`Demo (only for template analysis, all data is fake): ${this.readDemo()}`)
192
+ this.ai.addContent(`Original *.stories.ts: ${this.storiesFile.read()}`)
193
+ this.ai.addContent(`Original MDX: ${this.mdFile.read()}`)
194
+ }
302
195
  }
303
196
 
304
197
  /**
@@ -307,19 +200,43 @@ ${content}
307
200
  * Вызывает генерацию через ИИ и делит результат на types / stories / mdx.
308
201
  */
309
202
  protected async aiGenerate(): Promise<void> {
310
- const prompt = this.promptFile.read()
311
- const generate = await useAi()?.generate(prompt)
203
+ if (this.ai) {
204
+ const generate = await this.ai.generate(
205
+ this.readPrompt()
206
+ )
312
207
 
313
- if (generate) {
314
- const files = generate.split('#########')
208
+ if (generate) {
209
+ const read = generate.split('#########')
315
210
 
316
- this.typesFile.write(files[0] ?? '')
317
- this.storiesFile.write(files[1] ?? '')
318
- this.mdFile.write(files[2] ?? '')
211
+ if (read?.[0]) {
212
+ this.description = read[0].trim()
213
+ }
214
+
215
+ if (
216
+ read?.[1]
217
+ && !read[1].match(MARK_FULL)
218
+ ) {
219
+ this.codeFile.write(read[1])
220
+ }
221
+
222
+ if (
223
+ read?.[2]
224
+ && !read[2].match(MARK_FULL)
225
+ ) {
226
+ this.typesFile.write(read[2])
227
+ }
319
228
 
320
- this.aiFile.write(generate)
229
+ if (
230
+ read?.[3]
231
+ && !read[3].match(MARK_FULL)
232
+ ) {
233
+ this.storiesFile.write(read[3])
234
+ }
321
235
 
322
- PropertiesFile.removeDir(this.getPathTemporary())
236
+ if (read?.[4]) {
237
+ this.mdFile.write(read[4])
238
+ }
239
+ }
323
240
  }
324
241
  }
325
242
  }
@@ -1,7 +1,12 @@
1
- import { isFilled } from '@dxtmisha/functional'
1
+ // export:none
2
+
3
+ import { Datetime, isFilled } from '@dxtmisha/functional-basic'
2
4
 
3
5
  import { PropertiesFile } from '../Properties/PropertiesFile'
4
6
 
7
+ /** Regex to match date in content / Регекс для поиска даты в содержимом */
8
+ const DATE_UPDATED_MATCH = /\*\*Date: (.*?)\.\*\*/i
9
+
5
10
  /**
6
11
  * Utility class for reading and writing a single wiki component file.
7
12
  *
@@ -9,41 +14,123 @@ import { PropertiesFile } from '../Properties/PropertiesFile'
9
14
  */
10
15
  export class ComponentWikiFile {
11
16
  /**
12
- * @param paths target file path segments
13
- * @param paths сегменты пути целевого файла
17
+ * Constructor.
18
+ *
19
+ * Конструктор.
20
+ * @param paths target file path segments / сегменты пути целевого файла
21
+ * @param isDate whether to extract date from content / извлекать ли дату из содержимого
22
+ * @param isOld whether to keep old version of file / сохранять ли старую версию файла
14
23
  */
15
24
  constructor(
16
- protected readonly paths: string[]
25
+ protected readonly paths: string[],
26
+ protected readonly isDate: boolean = false,
27
+ protected readonly isOld: boolean = true
17
28
  ) {
18
29
  }
19
30
 
20
- /** Returns absolute path to file / Возвращает абсолютный путь к файлу */
31
+ /**
32
+ * Returns absolute path to file.
33
+ *
34
+ * Возвращает абсолютный путь к файлу.
35
+ */
21
36
  getPath(): string {
22
37
  return PropertiesFile.joinPath(this.paths)
23
38
  }
24
39
 
25
- /** Reads file content as string / Читает содержимое файла как строку */
40
+ /**
41
+ * Returns date from file content.
42
+ *
43
+ * Возвращает дату из содержимого файла.
44
+ */
45
+ getDate(): Datetime {
46
+ const content = this.read()
47
+ return this.extractDateFromContent(content)
48
+ }
49
+
50
+ /**
51
+ * Reads file content as string.
52
+ *
53
+ * Читает содержимое файла как строку.
54
+ */
26
55
  read(): string {
27
56
  return PropertiesFile.readFile<string>(this.paths) ?? ''
28
57
  }
29
58
 
30
- /** Writes content to file / Записывает содержимое в файл */
59
+ /**
60
+ * Writes content to file.
61
+ *
62
+ * Записывает содержимое в файл.
63
+ * @param content content to write / содержимое для записи
64
+ */
31
65
  write(content: string): void {
32
66
  if (isFilled(content)) {
33
67
  const contentOld = this.read()
34
- const contentEdit = content
35
- .trim()
36
- .replace(/^```(ts|md)/, '')
37
- .replace(/```$/, '')
38
- .trim()
68
+ let contentEdit = content.trim()
69
+
70
+ if (contentEdit.startsWith('```')) {
71
+ contentEdit = contentEdit
72
+ .replace(/^```(ts|md)/, '')
73
+ .replace(/```$/, '')
74
+ .trim()
75
+ }
39
76
 
40
77
  if (contentEdit !== contentOld.trim()) {
78
+ if (
79
+ this.isOld
80
+ && isFilled(contentOld.trim())
81
+ ) {
82
+ PropertiesFile.writeByPath(
83
+ `${PropertiesFile.joinPath(this.paths)}__old.txt`,
84
+ contentOld
85
+ )
86
+ }
87
+
41
88
  PropertiesFile.writeByPath(
42
- `${PropertiesFile.joinPath(this.paths)}__old.txt`,
43
- contentOld
89
+ this.paths,
90
+ this.addDate(contentEdit + '\r\n')
44
91
  )
45
- PropertiesFile.writeByPath(this.paths, contentEdit + '\r\n')
46
92
  }
47
93
  }
48
94
  }
95
+
96
+ /**
97
+ * Extracts date from content string.
98
+ *
99
+ * Извлекает дату из строки содержимого.
100
+ * @param content content string / строка содержимого
101
+ */
102
+ protected extractDateFromContent(content: string): Datetime {
103
+ const match = content.match(DATE_UPDATED_MATCH)
104
+ let date = '1970-01-01'
105
+
106
+ if (
107
+ match
108
+ && match?.[1]
109
+ ) {
110
+ date = match[1]
111
+ }
112
+
113
+ return new Datetime(date, 'full')
114
+ }
115
+
116
+ /**
117
+ * Adds current date to content if isDate is true.
118
+ *
119
+ * Добавляет текущую дату в содержимое, если isDate равно true.
120
+ * @param content content string / строка содержимого
121
+ */
122
+ protected addDate(content: string): string {
123
+ if (this.isDate) {
124
+ const date = new Datetime(new Date(), 'full').standard()
125
+ const dateString = `\n\r**Date: ${date}.**\r\n`
126
+
127
+ if (DATE_UPDATED_MATCH.test(content)) {
128
+ return `${content.replace(DATE_UPDATED_MATCH, '').trim()}\r\n${dateString}`
129
+ }
130
+
131
+ return `${content}${dateString}`
132
+ }
133
+
134
+ return content
135
+ }
49
136
  }
@@ -1,4 +1,6 @@
1
- import { toArray } from '@dxtmisha/functional'
1
+ // export:none
2
+
3
+ import { toArray } from '@dxtmisha/functional-basic'
2
4
 
3
5
  import { PropertiesConfig } from '../Properties/PropertiesConfig'
4
6
  import { PropertiesFile } from '../Properties/PropertiesFile'
@@ -1,4 +1,6 @@
1
- import { forEach, isObjectNotArray, toArray, toKebabCase } from '@dxtmisha/functional'
1
+ // export:none
2
+
3
+ import { forEach, isObjectNotArray, toArray, toKebabCase } from '@dxtmisha/functional-basic'
2
4
  import { wikiDescriptions } from '@dxtmisha/wiki/media'
3
5
  import type { StorybookComponentsDescriptionItem } from '@dxtmisha/wiki'
4
6
 
@@ -1,4 +1,6 @@
1
- import { toCamelCaseFirst } from '@dxtmisha/functional'
1
+ // export:none
2
+
3
+ import { toCamelCaseFirst } from '@dxtmisha/functional-basic'
2
4
 
3
5
  import { PropertiesFile } from '../Properties/PropertiesFile'
4
6
 
@@ -1,4 +1,6 @@
1
- import { isFilled } from '@dxtmisha/functional'
1
+ // export:none
2
+
3
+ import { isFilled } from '@dxtmisha/functional-basic'
2
4
 
3
5
  import { PropertiesFile } from '../Properties/PropertiesFile'
4
6
  import { PropertiesCache } from '../Properties/PropertiesCache'
@@ -1,4 +1,6 @@
1
- import { forEach, getColumn, toCamelCase, toCamelCaseFirst } from '@dxtmisha/functional'
1
+ // export:none
2
+
3
+ import { forEach, getColumn, toCamelCase, toCamelCaseFirst } from '@dxtmisha/functional-basic'
2
4
 
3
5
  import { DesignStructure } from './DesignStructure'
4
6
 
@@ -1,4 +1,6 @@
1
- import { toCamelCase, toCamelCaseFirst } from '@dxtmisha/functional'
1
+ // export:none
2
+
3
+ import { toCamelCase, toCamelCaseFirst } from '@dxtmisha/functional-basic'
2
4
 
3
5
  import { PropertiesConfig } from '../Properties/PropertiesConfig'
4
6
  import { PropertiesCache } from '../Properties/PropertiesCache'
@@ -1,4 +1,6 @@
1
- import { forEach, isFilled, isObjectNotArray, toCamelCase } from '@dxtmisha/functional'
1
+ // export:none
2
+
3
+ import { forEach, isFilled, isObjectNotArray, toCamelCase } from '@dxtmisha/functional-basic'
2
4
 
3
5
  import { DesignStructureItemAbstract } from './DesignStructureItemAbstract'
4
6
 
@@ -1,3 +1,5 @@
1
+ // export:none
2
+
1
3
  import { Properties } from '../Properties/Properties'
2
4
  import { PropertiesConfig } from '../Properties/PropertiesConfig'
3
5
 
@@ -1,4 +1,6 @@
1
- import { forEach, isFilled, isObjectNotArray, toCamelCase, uniqueArray } from '@dxtmisha/functional'
1
+ // export:none
2
+
3
+ import { forEach, isFilled, isObjectNotArray, toCamelCase, uniqueArray } from '@dxtmisha/functional-basic'
2
4
 
3
5
  import { DesignStructureItemAbstract } from './DesignStructureItemAbstract'
4
6
 
@@ -1,3 +1,5 @@
1
+ // export:none
2
+
1
3
  import { StylesProperties } from '../Styles/StylesProperties'
2
4
  import { DesignStructureItemAbstract } from './DesignStructureItemAbstract'
3
5
 
@@ -1,4 +1,4 @@
1
- import { forEach } from '@dxtmisha/functional'
1
+ import { forEach } from '@dxtmisha/functional-basic'
2
2
  import ts from 'typescript'
3
3
 
4
4
  import type {
@@ -1,4 +1,6 @@
1
- import { toKebabCase } from '@dxtmisha/functional'
1
+ // export:none
2
+
3
+ import { toKebabCase } from '@dxtmisha/functional-basic'
2
4
 
3
5
  import { DesignComponent } from './DesignComponent'
4
6
  import { LibraryItems } from '../Library/LibraryItems'
@@ -1,4 +1,6 @@
1
- import { toCamelCaseFirst } from '@dxtmisha/functional'
1
+ // export:none
2
+
3
+ import { toCamelCaseFirst } from '@dxtmisha/functional-basic'
2
4
 
3
5
  import { PropertiesConfig } from '../Properties/PropertiesConfig'
4
6
  import { PropertiesFile } from '../Properties/PropertiesFile'