@dxtmisha/scripts 0.9.0 → 0.10.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/CHANGELOG.md +30 -0
- package/package.json +2 -1
- package/src/classes/Ai/AiClaudeAgent.ts +16 -0
- package/src/classes/Ai/AiClaudeAgentLite.ts +86 -0
- package/src/classes/Ai/AiClaudeCliLite.ts +29 -65
- package/src/classes/Ai/AiClaudeLite.ts +19 -7
- package/src/classes/Ai/AiGoogleCliLite.ts +27 -64
- package/src/classes/Ai/AiOpenAi.ts +26 -0
- package/src/classes/Ai/AiOpenAiLite.ts +107 -0
- package/src/classes/Ai/AiZAi.ts +17 -0
- package/src/classes/Ai/AiZAiLite.ts +26 -0
- package/src/classes/Ai/ApiTmp.ts +43 -0
- package/src/classes/Build/BuildPackages.ts +33 -7
- package/src/classes/Design/DesignComponent.ts +1 -1
- package/src/classes/Library/LibraryAiPromptItem.ts +36 -2
- package/src/composables/useAi.ts +15 -0
- package/src/config.ts +2 -0
- package/src/demo/ai.ts +10 -0
- package/src/library-ai.ts +4 -4
- package/src/library.ts +67 -54
- package/src/media/templates/componentDoc/materials/README.md +8 -0
- package/src/media/templates/componentDoc/materials/prompt.txt +28 -0
- package/src/media/templates/componentDoc/wiki/prompt.txt +21 -0
- package/src/media/templates/componentDoc/wiki/run.ts +2 -1
- package/src/media/templates/prompts/aiCodeGlobalPrompt.en.txt +19 -0
- package/src/media/templates/prompts/aiCodeGlobalPrompt.ru.txt +21 -0
- package/src/media/templates/prompts/componentPrompt.en.txt +71 -16
- package/src/media/templates/prompts/componentPrompt.ru.txt +71 -16
- package/src/types/configTypes.ts +9 -2
- package/src/classes/Component/__tests__/ComponentCreator.test.ts +0 -71
- package/src/classes/Component/__tests__/ComponentItem.test.ts +0 -71
- package/src/classes/Git/__tests__/GitRead.test.ts +0 -70
- package/src/composables/__tests__/useAi.test.ts +0 -75
- package/src/functions/__tests__/getComponentPaths.test.ts +0 -19
- package/src/functions/__tests__/getConfigAi.test.ts +0 -26
- package/src/functions/__tests__/getConstructorProperties.test.ts +0 -51
- package/src/functions/__tests__/getDirname.test.ts +0 -31
- package/src/functions/__tests__/getNameDirByPaths.test.ts +0 -40
- package/src/functions/__tests__/getPackageJson.test.ts +0 -34
- package/src/functions/__tests__/hasNativeDirname.test.ts +0 -18
- package/src/functions/__tests__/toPathStandardSep.test.ts +0 -31
- package/src/media/templates/componentDoc/figma/run-figma.ts +0 -26
|
@@ -52,27 +52,79 @@
|
|
|
52
52
|
7. **Events (События)**:
|
|
53
53
|
- Заголовок `## Events`
|
|
54
54
|
- Для каждого события:
|
|
55
|
-
- `###
|
|
56
|
-
-
|
|
55
|
+
- Заголовок `### \`имяСобытия\`` (имя события обязательно должно быть обернуто в обратные кавычки).
|
|
56
|
+
- Краткое текстовое описание того, когда событие срабатывает.
|
|
57
57
|
- **Параметры:**
|
|
58
|
-
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
58
|
+
- Заголовок: `**Параметры:**`
|
|
59
|
+
- Список: `- \`имяПараметра: типПараметра\` — описание параметра.`
|
|
60
|
+
- **Структура сложных типов (если применимо):**
|
|
61
|
+
- Заголовок: `**Структура TypeName:**` (или `**Структура TypeName:** такая же, как для события \`другоеСобытие\``, если они идентичны).
|
|
62
|
+
- Список: `- \`имяПоля: типПоля\` — описание поля.`
|
|
63
|
+
- **Пример кода (если событие сложное):**
|
|
64
|
+
- Примеры кода ОБЯЗАТЕЛЬНО должны быть обернуты в компонент Storybook `<Source />` вместо стандартного markdown-форматирования (три обратные кавычки). Не забудь добавить `import { Source } from '@storybook/addon-docs/blocks';` в самый верх MDX файла, если его там еще нет:
|
|
65
|
+
```md
|
|
66
|
+
<Source
|
|
67
|
+
code={`
|
|
68
|
+
<script setup>
|
|
69
|
+
// пример кода здесь
|
|
70
|
+
</script>
|
|
71
|
+
`}
|
|
72
|
+
language="html"
|
|
73
|
+
/>
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
8. **Expose (Публичные методы и свойства компонента)**:
|
|
62
77
|
- Заголовок `## Expose`
|
|
63
|
-
-
|
|
64
|
-
-
|
|
65
|
-
-
|
|
66
|
-
-
|
|
78
|
+
- Внутри раздела выводи список публичных методов, реактивных ссылок (Refs) и вычисляемых свойств (Computed), доступных через ref компонента, в чистом маркированном формате сигнатур:
|
|
79
|
+
- Для методов: `- `имяМетода(имяПараметра: типПараметра): возвращаемыйТип` — Описание.`
|
|
80
|
+
- Для реактивных переменных/свойств: `- `имяСвойства: ТипСвойства` — Описание.`
|
|
81
|
+
- Стандартные типы возвращаемых значений: `boolean`, `void`, `Ref<any>`, `ComputedRef<any>` и т.д.
|
|
67
82
|
|
|
68
83
|
9. **Slots (Слоты)**:
|
|
69
84
|
- Заголовок `## Slots`
|
|
70
|
-
-
|
|
71
|
-
-
|
|
72
|
-
-
|
|
73
|
-
-
|
|
74
|
-
|
|
75
|
-
|
|
85
|
+
- Внутри раздела выводи список слотов в чистом маркированном формате сигнатур:
|
|
86
|
+
- Для слотов без параметров: `- `имяСлота: Тип` — Описание.`
|
|
87
|
+
- Для слотов с параметрами: `- `имяСлота(имяПараметра: типПараметра): Тип` — Описание.`
|
|
88
|
+
- Стандартный тип возвращаемого значения обычно `VNode` или `any`.
|
|
89
|
+
|
|
90
|
+
### Вспомогательные стили Storybook (storybookStyle.scss):
|
|
91
|
+
При написании сценариев Storybook (`*.stories.ts`) и примеров кода в MDX-документации ОБЯЗАТЕЛЬНО используй предопределенные вспомогательные классы для демонстрации. Эти стили импортируются глобально и имеют префикс `.wiki-storybook-`. Избегай написания кастомных инлайн-стилей или новых CSS-классов для лейаута, позиционирования, заглушек или контейнеров. Используй следующие готовые классы:
|
|
92
|
+
|
|
93
|
+
- **Контейнеры и сетки**:
|
|
94
|
+
- `.wiki-storybook-container` — включает контейнерные запросы (`container-type: inline-size`).
|
|
95
|
+
- `.wiki-storybook-group` — CSS Grid сетка на 12 колонок (`grid-template-columns: repeat(12, 1fr)`) с отступом `8px`. Отлично подходит для демонстрации нескольких вариантов компонента.
|
|
96
|
+
- `.wiki-storybook-flex` — базовая flex-обертка (`display: flex; flex-wrap: wrap`) с отступом `8px`.
|
|
97
|
+
- `.wiki-storybook-flex-align-center` — flex-обертка с центрированием элементов по вертикали (`align-items: center`).
|
|
98
|
+
- `.wiki-storybook-flex-center` — полное центрирование элементов (горизонтальное и вертикальное) с отступом `8px`.
|
|
99
|
+
- `.wiki-storybook-flex-column` — вертикальный flex-контейнер (`display: flex; flex-direction: column`) с отступом `16px`.
|
|
100
|
+
- `.wiki-storybook-decreased` — уменьшает максимальную ширину блока до `72%`.
|
|
101
|
+
- `.wiki-storybook-decreasedX2` — адаптивно уменьшает ширину блока (`64%` на экранах `md`, `48%` на экранах `lg`).
|
|
102
|
+
|
|
103
|
+
- **Демонстрационные карточки (`.wiki-storybook-item`)**:
|
|
104
|
+
Используются для отображения компонентов внутри единого визуального блока (по умолчанию aspect-ratio `1/1`, рамка, скругление углов, скрытый overflow):
|
|
105
|
+
- `.wiki-storybook-item__label` — небольшая плавающая метка в левом верхнем углу (`font-size: 12px`, полупрозрачный размытый фон) для подписи вариаций. Класс `.wiki-storybook-item__label--static` делает метку статичной без абсолютного позиционирования.
|
|
106
|
+
- `&--padding` — добавляет стандартные внутренние отступы `16px`.
|
|
107
|
+
- `&--rectangle` — устанавливает соотношение сторон `16:9` и растягивает блок на все 12 колонок в сетке.
|
|
108
|
+
- `&--widescreen` — соотношение сторон `32:9`, растягивает блок на все 12 колонок в сетке.
|
|
109
|
+
- `&--compact` — соотношение сторон `64:9`, растягивает блок на все 12 колонок в сетке.
|
|
110
|
+
- `&--auto` — автоматическое соотношение сторон, растягивает блок на все 12 колонок в сетке.
|
|
111
|
+
- `&--squared--xs`, `&--squared--sm`, `&--squared--md`, `&--squared--lg`, `&--squared--max` — адаптивное управление шириной квадратных блоков. Например, `--squared--sm` занимает 6 колонок на мобильных, 4 колонки на планшетах (от 640px) и 2 колонки на десктопах (от 1024px).
|
|
112
|
+
- `&--center` — выравнивает содержимое по центру с помощью flex.
|
|
113
|
+
- `&--widthAuto` — устанавливает ширину `auto`.
|
|
114
|
+
- `&--overflowVisible` — сбрасывает `overflow: hidden` на `overflow: visible` (необходимо для выпадающих меню, модалок).
|
|
115
|
+
- `&--rtl` — включает режим отображения справа налево (Right-to-Left).
|
|
116
|
+
|
|
117
|
+
- **Тестовые компоненты и заглушки**:
|
|
118
|
+
- `.wiki-storybook-card` — тестовая карточка (ширина `320px`, скругления, рамка) для симуляции реального интерфейса:
|
|
119
|
+
- `.wiki-storybook-card__image` — обложка высотой 128px.
|
|
120
|
+
- `.wiki-storybook-card__content` — вертикальный flex-контейнер с отступами `16px` и расстоянием `16px`.
|
|
121
|
+
- `.wiki-storybook-card__label` — заголовок с размером шрифта `20px`.
|
|
122
|
+
- `.wiki-storybook-card__information` — серый текст описания (`14px`).
|
|
123
|
+
- `.wiki-storybook-card__actions` — горизонтальный контейнер для кнопок (`8px`).
|
|
124
|
+
- `.wiki-storybook-button` — кнопка-заглушка для обработки кликов. Модификаторы для статусных цветов: `&--success` (зеленый), `&--error` (красный), `&--warning` (желтый), `&--info` (синий).
|
|
125
|
+
- `.wiki-storybook-dummy` — визуальный блок-заглушка (`32px` высотой, полупрозрачный серый).
|
|
126
|
+
- Цвета: `&--color--blue`, `&--color--red`, `&--color--green`.
|
|
127
|
+
- Размеры (высота): `&--size--sm` (`64px`), `&--size--md` (`128px`), `&--size--lg` (`256px`).
|
|
76
128
|
|
|
77
129
|
### Инструкции:
|
|
78
130
|
1. Изучи предоставленный код компонента (включая props, emits, slots, expose).
|
|
@@ -82,6 +134,9 @@
|
|
|
82
134
|
3.2. Старайся сохранять оригинальные описания без изменений.
|
|
83
135
|
4. Используй правильную терминологию (Props, Events, Slots, Expose).
|
|
84
136
|
4.1. Все заголовки должны быть на языке [wikiLanguage].
|
|
137
|
+
4.2. В сценариях Storybook и примерах MDX-кода вы ОБЯЗАНЫ использовать предопределенные классы-помощники разметки из `storybookStyle.scss` (описанные выше) вместо инлайн-стилей или кастомных блоков CSS.
|
|
138
|
+
4.3. Ни при каких обстоятельствах не изменяй оригинальный код компонента, если об этом явно не попросили.
|
|
139
|
+
4.4. Строго следуй всем правилам и инструкциям данного промпта. Никаких галлюцинаций: категорически запрещено придумывать, домысливать или добавлять несуществующие свойства (props), методы (expose), события (events), слоты (slots) или внешние зависимости.
|
|
85
140
|
5. Не добавляй лишних введений или заключений, только MDX.
|
|
86
141
|
6. Верни только полный MDX-код документации без какого-либо дополнительного текста, комментариев или форматирования markdown (```).
|
|
87
142
|
7. Результат должен быть исключительно в виде текста (ответа), не прикрепляй никаких файлов.
|
package/src/types/configTypes.ts
CHANGED
|
@@ -1,5 +1,12 @@
|
|
|
1
1
|
/** AI type for content generation / Тип ИИ для генерации контента */
|
|
2
|
-
export type AiType
|
|
2
|
+
export type AiType
|
|
3
|
+
= | 'claude'
|
|
4
|
+
| 'claude-cli'
|
|
5
|
+
| 'claude-agent'
|
|
6
|
+
| 'gemini'
|
|
7
|
+
| 'gemini-cli'
|
|
8
|
+
| 'openai'
|
|
9
|
+
| 'zai'
|
|
3
10
|
|
|
4
11
|
/** Configuration structure for the design system UI project / Структура конфигурации для проекта дизайн-системы UI */
|
|
5
12
|
export type DesignUiConfig = {
|
|
@@ -40,7 +47,7 @@ export type DesignUiConfig = {
|
|
|
40
47
|
packagePrefix?: string
|
|
41
48
|
|
|
42
49
|
/** AI type for generating content / Тип ИИ для генерации контента */
|
|
43
|
-
aiType?:
|
|
50
|
+
aiType?: AiType
|
|
44
51
|
|
|
45
52
|
/** AI model for generating content / Модель ИИ для генерации контента */
|
|
46
53
|
aiModel?: string
|
|
@@ -1,71 +0,0 @@
|
|
|
1
|
-
import { describe, expect, it, vi, beforeEach } from 'vitest'
|
|
2
|
-
import { ComponentCreator } from '../ComponentCreator'
|
|
3
|
-
import { PropertiesFile } from '../../Properties/PropertiesFile'
|
|
4
|
-
import { ComponentItem } from '../ComponentItem'
|
|
5
|
-
import { getComponentPaths } from '../../../functions/getComponentPaths'
|
|
6
|
-
import { UI_DIRS_COMPONENTS } from '../../../config'
|
|
7
|
-
|
|
8
|
-
vi.mock('../../Properties/PropertiesFile', () => ({
|
|
9
|
-
PropertiesFile: {
|
|
10
|
-
readDirOnlyRecursive: vi.fn(),
|
|
11
|
-
readDir: vi.fn()
|
|
12
|
-
}
|
|
13
|
-
}))
|
|
14
|
-
|
|
15
|
-
vi.mock('../ComponentItem', () => ({
|
|
16
|
-
ComponentItem: vi.fn().mockImplementation(function () {
|
|
17
|
-
return {
|
|
18
|
-
make: vi.fn()
|
|
19
|
-
}
|
|
20
|
-
})
|
|
21
|
-
}))
|
|
22
|
-
|
|
23
|
-
vi.mock('../../../functions/getComponentPaths', () => ({
|
|
24
|
-
getComponentPaths: vi.fn(path => [path, 'full'])
|
|
25
|
-
}))
|
|
26
|
-
|
|
27
|
-
describe('ComponentCreator', () => {
|
|
28
|
-
let creator: ComponentCreator
|
|
29
|
-
|
|
30
|
-
beforeEach(() => {
|
|
31
|
-
vi.clearAllMocks()
|
|
32
|
-
creator = new ComponentCreator()
|
|
33
|
-
})
|
|
34
|
-
|
|
35
|
-
it('make should call ComponentItem.make for each empty directory', () => {
|
|
36
|
-
vi.mocked(PropertiesFile.readDirOnlyRecursive).mockReturnValue(['dir1', 'dir2', 'dir3'])
|
|
37
|
-
vi.mocked(PropertiesFile.readDir).mockImplementation((path) => {
|
|
38
|
-
if (Array.isArray(path) && path[0] === 'dir2') return ['file.ts']
|
|
39
|
-
return []
|
|
40
|
-
})
|
|
41
|
-
|
|
42
|
-
creator.make()
|
|
43
|
-
|
|
44
|
-
expect(ComponentItem).toHaveBeenCalledWith('dir1')
|
|
45
|
-
expect(ComponentItem).not.toHaveBeenCalledWith('dir2')
|
|
46
|
-
expect(ComponentItem).toHaveBeenCalledWith('dir3')
|
|
47
|
-
|
|
48
|
-
const mockInstance1 = vi.mocked(ComponentItem).mock.results[0]?.value
|
|
49
|
-
const mockInstance2 = vi.mocked(ComponentItem).mock.results[1]?.value
|
|
50
|
-
|
|
51
|
-
expect(mockInstance1?.make).toHaveBeenCalled()
|
|
52
|
-
expect(mockInstance2?.make).toHaveBeenCalled()
|
|
53
|
-
})
|
|
54
|
-
|
|
55
|
-
it('getDirs should return only empty directories', () => {
|
|
56
|
-
vi.mocked(PropertiesFile.readDirOnlyRecursive).mockReturnValue(['empty', 'not-empty'])
|
|
57
|
-
vi.mocked(PropertiesFile.readDir).mockImplementation((path) => {
|
|
58
|
-
if (Array.isArray(path) && path[0] === 'not-empty') return ['index.ts']
|
|
59
|
-
return []
|
|
60
|
-
})
|
|
61
|
-
|
|
62
|
-
// Access protected method for testing
|
|
63
|
-
const dirs = (creator as any).getDirs()
|
|
64
|
-
|
|
65
|
-
expect(dirs).toContain('empty')
|
|
66
|
-
expect(dirs).not.toContain('not-empty')
|
|
67
|
-
expect(dirs).toHaveLength(1)
|
|
68
|
-
expect(PropertiesFile.readDirOnlyRecursive).toHaveBeenCalledWith(UI_DIRS_COMPONENTS)
|
|
69
|
-
expect(getComponentPaths).toHaveBeenCalledWith('empty')
|
|
70
|
-
})
|
|
71
|
-
})
|
|
@@ -1,71 +0,0 @@
|
|
|
1
|
-
import { describe, expect, it, vi, beforeEach } from 'vitest'
|
|
2
|
-
import { ComponentItem } from '../ComponentItem'
|
|
3
|
-
import { PropertiesFile } from '../../Properties/PropertiesFile'
|
|
4
|
-
import { toKebabCase } from '@dxtmisha/functional-basic'
|
|
5
|
-
|
|
6
|
-
vi.mock('../../Properties/PropertiesFile', () => ({
|
|
7
|
-
PropertiesFile: {
|
|
8
|
-
splitForDir: vi.fn(path => path.split('/')),
|
|
9
|
-
readFile: vi.fn(),
|
|
10
|
-
writeByPath: vi.fn(),
|
|
11
|
-
chmod: vi.fn(),
|
|
12
|
-
readDirRecursive: vi.fn()
|
|
13
|
-
}
|
|
14
|
-
}))
|
|
15
|
-
|
|
16
|
-
vi.mock('../../../functions/getComponentPaths', () => ({
|
|
17
|
-
getComponentPaths: vi.fn(path => [path, 'full'])
|
|
18
|
-
}))
|
|
19
|
-
|
|
20
|
-
describe('ComponentItem', () => {
|
|
21
|
-
let item: ComponentItem
|
|
22
|
-
const mockPath = 'src/components/TestComponent'
|
|
23
|
-
|
|
24
|
-
beforeEach(() => {
|
|
25
|
-
vi.clearAllMocks()
|
|
26
|
-
item = new ComponentItem(mockPath)
|
|
27
|
-
})
|
|
28
|
-
|
|
29
|
-
it('getName should return the last part of the path', () => {
|
|
30
|
-
const name = (item as any).getName()
|
|
31
|
-
expect(name).toBe('TestComponent')
|
|
32
|
-
expect(PropertiesFile.splitForDir).toHaveBeenCalledWith(mockPath)
|
|
33
|
-
})
|
|
34
|
-
|
|
35
|
-
it('getProjectName should return package name or "Project"', () => {
|
|
36
|
-
vi.mocked(PropertiesFile.readFile).mockReturnValue({ name: 'test-project' })
|
|
37
|
-
const projectName = (item as any).getProjectName()
|
|
38
|
-
expect(projectName).toBe('test-project')
|
|
39
|
-
|
|
40
|
-
vi.mocked(PropertiesFile.readFile).mockReturnValue(undefined)
|
|
41
|
-
expect((item as any).getProjectName()).toBe('Project')
|
|
42
|
-
})
|
|
43
|
-
|
|
44
|
-
it('replacement should replace placeholders correctly', () => {
|
|
45
|
-
vi.mocked(PropertiesFile.readFile).mockReturnValue({ name: 'test-project' })
|
|
46
|
-
const content = 'Name: ComponentDoc, kebab: component-doc, project: [project], path: [path]'
|
|
47
|
-
const result = (item as any).replacement(content)
|
|
48
|
-
|
|
49
|
-
expect(result).toContain('Name: TestComponent')
|
|
50
|
-
expect(result).toContain(`kebab: ${toKebabCase('TestComponent')}`)
|
|
51
|
-
expect(result).toContain('project: test-project')
|
|
52
|
-
expect(result).toContain(`path: ${mockPath}`)
|
|
53
|
-
})
|
|
54
|
-
|
|
55
|
-
it('make should read templates and write files with replacements', () => {
|
|
56
|
-
vi.mocked(PropertiesFile.readDirRecursive).mockReturnValue(['Template.ts'])
|
|
57
|
-
vi.mocked(PropertiesFile.readFile).mockImplementation((path) => {
|
|
58
|
-
if (Array.isArray(path) && path.includes('package.json')) return { name: 'test-project' }
|
|
59
|
-
return 'export class ComponentDoc {}'
|
|
60
|
-
})
|
|
61
|
-
|
|
62
|
-
item.make()
|
|
63
|
-
|
|
64
|
-
expect(PropertiesFile.readDirRecursive).toHaveBeenCalled()
|
|
65
|
-
expect(PropertiesFile.writeByPath).toHaveBeenCalledWith(
|
|
66
|
-
expect.arrayContaining([mockPath, 'Template.ts']),
|
|
67
|
-
'export class TestComponent {}'
|
|
68
|
-
)
|
|
69
|
-
expect(PropertiesFile.chmod).toHaveBeenCalled()
|
|
70
|
-
})
|
|
71
|
-
})
|
|
@@ -1,70 +0,0 @@
|
|
|
1
|
-
import { describe, expect, it, vi, beforeEach } from 'vitest'
|
|
2
|
-
import { GitRead } from '../GitRead'
|
|
3
|
-
import { execSync } from 'node:child_process'
|
|
4
|
-
import { PropertiesFile } from '../../Properties/PropertiesFile'
|
|
5
|
-
|
|
6
|
-
vi.mock('node:child_process', () => ({
|
|
7
|
-
execSync: vi.fn()
|
|
8
|
-
}))
|
|
9
|
-
|
|
10
|
-
vi.mock('../../Properties/PropertiesFile', () => ({
|
|
11
|
-
PropertiesFile: {
|
|
12
|
-
getTime: vi.fn()
|
|
13
|
-
}
|
|
14
|
-
}))
|
|
15
|
-
|
|
16
|
-
describe('GitRead', () => {
|
|
17
|
-
beforeEach(() => {
|
|
18
|
-
vi.clearAllMocks()
|
|
19
|
-
})
|
|
20
|
-
|
|
21
|
-
it('getDirPrefix should return the result of git rev-parse', () => {
|
|
22
|
-
vi.mocked(execSync).mockReturnValue('packages/scripts/' as any)
|
|
23
|
-
const result = GitRead.getDirPrefix()
|
|
24
|
-
expect(execSync).toHaveBeenCalledWith('git rev-parse --show-prefix', expect.anything())
|
|
25
|
-
expect(result).toBe('packages/scripts/')
|
|
26
|
-
})
|
|
27
|
-
|
|
28
|
-
it('getFilesPath should return list of HEAD files', () => {
|
|
29
|
-
vi.mocked(execSync).mockReturnValue('file1.ts\nfile2.ts\n' as any)
|
|
30
|
-
const result = GitRead.getFilesPath()
|
|
31
|
-
expect(result).toEqual(['file1.ts', 'file2.ts'])
|
|
32
|
-
})
|
|
33
|
-
|
|
34
|
-
it('getList should return files with metadata', () => {
|
|
35
|
-
vi.mocked(execSync).mockImplementation((cmd: string) => {
|
|
36
|
-
if (cmd.startsWith('git rev-parse')) return 'prefix/' as any
|
|
37
|
-
if (cmd.startsWith('git ls-tree')) return 'file.ts\n' as any
|
|
38
|
-
if (cmd.startsWith('git log')) return '2023-10-27 12:00:00 +0300' as any
|
|
39
|
-
return '' as any
|
|
40
|
-
})
|
|
41
|
-
|
|
42
|
-
const result = GitRead.getList()
|
|
43
|
-
expect(result[0]).toMatchObject({
|
|
44
|
-
path: 'file.ts',
|
|
45
|
-
pathFull: 'prefix/file.ts',
|
|
46
|
-
date: expect.stringContaining('2023-10-27')
|
|
47
|
-
})
|
|
48
|
-
})
|
|
49
|
-
|
|
50
|
-
it('getListPorcelain should parse git status and metadata', () => {
|
|
51
|
-
vi.mocked(execSync).mockImplementation((cmd: string) => {
|
|
52
|
-
if (cmd.startsWith('git rev-parse')) return 'prefix/' as any
|
|
53
|
-
if (cmd.startsWith('git status')) return 'M file.ts\nA new.ts\n' as any
|
|
54
|
-
return '' as any
|
|
55
|
-
})
|
|
56
|
-
vi.mocked(PropertiesFile.getTime).mockReturnValue('2023-10-27 12:00:00' as any)
|
|
57
|
-
|
|
58
|
-
const result = GitRead.getListPorcelain()
|
|
59
|
-
expect(result).toHaveLength(2)
|
|
60
|
-
expect(result[0]).toMatchObject({
|
|
61
|
-
path: 'file.ts',
|
|
62
|
-
status: 'M'
|
|
63
|
-
})
|
|
64
|
-
})
|
|
65
|
-
|
|
66
|
-
it('splitPath should correctly split string', () => {
|
|
67
|
-
expect(GitRead.splitPath('a/b/c')).toEqual(['a', 'b', 'c'])
|
|
68
|
-
expect(GitRead.splitPath('/a/b/')).toEqual(['a', 'b'])
|
|
69
|
-
})
|
|
70
|
-
})
|
|
@@ -1,75 +0,0 @@
|
|
|
1
|
-
import { describe, expect, it, vi, beforeEach } from 'vitest'
|
|
2
|
-
import { useAi } from '../useAi'
|
|
3
|
-
import { PropertiesConfig } from '../../classes/Properties/PropertiesConfig'
|
|
4
|
-
import { AiGoogle } from '../../classes/Ai/AiGoogle'
|
|
5
|
-
import { AiGoogleCli } from '../../classes/Ai/AiGoogleCli'
|
|
6
|
-
|
|
7
|
-
vi.mock('../../classes/Properties/PropertiesConfig', () => ({
|
|
8
|
-
PropertiesConfig: {
|
|
9
|
-
getAiType: vi.fn()
|
|
10
|
-
}
|
|
11
|
-
}))
|
|
12
|
-
|
|
13
|
-
vi.mock('../../classes/Ai/AiGoogle', () => {
|
|
14
|
-
return {
|
|
15
|
-
AiGoogle: vi.fn().mockImplementation(function () {
|
|
16
|
-
return { name: 'AiGoogleInstance' }
|
|
17
|
-
})
|
|
18
|
-
}
|
|
19
|
-
})
|
|
20
|
-
|
|
21
|
-
vi.mock('../../classes/Ai/AiGoogleCli', () => {
|
|
22
|
-
return {
|
|
23
|
-
AiGoogleCli: vi.fn().mockImplementation(function () {
|
|
24
|
-
return { name: 'AiGoogleCliInstance' }
|
|
25
|
-
})
|
|
26
|
-
}
|
|
27
|
-
})
|
|
28
|
-
|
|
29
|
-
describe('useAi', () => {
|
|
30
|
-
beforeEach(() => {
|
|
31
|
-
vi.clearAllMocks()
|
|
32
|
-
})
|
|
33
|
-
|
|
34
|
-
it('should return an instance of AiGoogle when the type is gemini', () => {
|
|
35
|
-
vi.mocked(PropertiesConfig.getAiType).mockReturnValue('gemini')
|
|
36
|
-
const mockInstance = { name: 'AiGoogleInstance' }
|
|
37
|
-
vi.mocked(AiGoogle).mockImplementation(function () {
|
|
38
|
-
return mockInstance as any
|
|
39
|
-
})
|
|
40
|
-
|
|
41
|
-
const result = useAi()
|
|
42
|
-
|
|
43
|
-
expect(result).toEqual(mockInstance)
|
|
44
|
-
expect(AiGoogle).toHaveBeenCalled()
|
|
45
|
-
})
|
|
46
|
-
|
|
47
|
-
it('should return an instance of AiGoogleCli when the type is gemini-cli', () => {
|
|
48
|
-
vi.mocked(PropertiesConfig.getAiType).mockReturnValue('gemini-cli')
|
|
49
|
-
const mockInstance = { name: 'AiGoogleCliInstance' }
|
|
50
|
-
vi.mocked(AiGoogleCli).mockImplementation(function () {
|
|
51
|
-
return mockInstance as any
|
|
52
|
-
})
|
|
53
|
-
|
|
54
|
-
const result = useAi()
|
|
55
|
-
|
|
56
|
-
expect(result).toEqual(mockInstance)
|
|
57
|
-
expect(AiGoogleCli).toHaveBeenCalled()
|
|
58
|
-
})
|
|
59
|
-
|
|
60
|
-
it('should return undefined for an unknown type', () => {
|
|
61
|
-
vi.mocked(PropertiesConfig.getAiType).mockReturnValue('unknown' as any)
|
|
62
|
-
|
|
63
|
-
const result = useAi()
|
|
64
|
-
|
|
65
|
-
expect(result).toBeUndefined()
|
|
66
|
-
})
|
|
67
|
-
|
|
68
|
-
it('should return undefined if no type is configured', () => {
|
|
69
|
-
vi.mocked(PropertiesConfig.getAiType).mockReturnValue(undefined as any)
|
|
70
|
-
|
|
71
|
-
const result = useAi()
|
|
72
|
-
|
|
73
|
-
expect(result).toBeUndefined()
|
|
74
|
-
})
|
|
75
|
-
})
|
|
@@ -1,19 +0,0 @@
|
|
|
1
|
-
import { describe, expect, it } from 'vitest'
|
|
2
|
-
import { getComponentPaths } from '../getComponentPaths'
|
|
3
|
-
import { UI_DIRS_COMPONENTS } from '../../config'
|
|
4
|
-
|
|
5
|
-
describe('getComponentPaths', () => {
|
|
6
|
-
it('should return an array containing UI_DIRS_COMPONENTS and the given path', () => {
|
|
7
|
-
const path = 'test-component'
|
|
8
|
-
const result = getComponentPaths(path)
|
|
9
|
-
|
|
10
|
-
expect(result).toEqual([...UI_DIRS_COMPONENTS, path])
|
|
11
|
-
})
|
|
12
|
-
|
|
13
|
-
it('it should work with nested paths', () => {
|
|
14
|
-
const path = 'nested/test-component'
|
|
15
|
-
const result = getComponentPaths(path)
|
|
16
|
-
|
|
17
|
-
expect(result).toEqual([...UI_DIRS_COMPONENTS, path])
|
|
18
|
-
})
|
|
19
|
-
})
|
|
@@ -1,26 +0,0 @@
|
|
|
1
|
-
import { describe, expect, it, vi } from 'vitest'
|
|
2
|
-
import { getConfigAi } from '../getConfigAi'
|
|
3
|
-
import { PropertiesConfig } from '../../classes/Properties/PropertiesConfig'
|
|
4
|
-
|
|
5
|
-
vi.mock('../../classes/Properties/PropertiesConfig', () => ({
|
|
6
|
-
PropertiesConfig: {
|
|
7
|
-
getAiKey: vi.fn(),
|
|
8
|
-
getAiModel: vi.fn()
|
|
9
|
-
}
|
|
10
|
-
}))
|
|
11
|
-
|
|
12
|
-
describe('getConfigAi', () => {
|
|
13
|
-
it('should return AI key and model from PropertiesConfig', () => {
|
|
14
|
-
const mockKey = 'test-key'
|
|
15
|
-
const mockModel = 'test-model'
|
|
16
|
-
|
|
17
|
-
vi.mocked(PropertiesConfig.getAiKey).mockReturnValue(mockKey)
|
|
18
|
-
vi.mocked(PropertiesConfig.getAiModel).mockReturnValue(mockModel)
|
|
19
|
-
|
|
20
|
-
const result = getConfigAi()
|
|
21
|
-
|
|
22
|
-
expect(result).toEqual([mockKey, mockModel])
|
|
23
|
-
expect(PropertiesConfig.getAiKey).toHaveBeenCalled()
|
|
24
|
-
expect(PropertiesConfig.getAiModel).toHaveBeenCalled()
|
|
25
|
-
})
|
|
26
|
-
})
|
|
@@ -1,51 +0,0 @@
|
|
|
1
|
-
import { describe, expect, it, vi, beforeEach } from 'vitest'
|
|
2
|
-
import { getConstructorProperties } from '../getConstructorProperties'
|
|
3
|
-
import { PropertiesFile } from '../../classes/Properties/PropertiesFile'
|
|
4
|
-
import { hasNativeDirname } from '../hasNativeDirname'
|
|
5
|
-
|
|
6
|
-
vi.mock('../../classes/Properties/PropertiesFile', () => ({
|
|
7
|
-
PropertiesFile: {
|
|
8
|
-
readFile: vi.fn()
|
|
9
|
-
}
|
|
10
|
-
}))
|
|
11
|
-
|
|
12
|
-
vi.mock('../hasNativeDirname', () => ({
|
|
13
|
-
hasNativeDirname: vi.fn()
|
|
14
|
-
}))
|
|
15
|
-
|
|
16
|
-
describe('getConstructorProperties', () => {
|
|
17
|
-
beforeEach(() => {
|
|
18
|
-
vi.clearAllMocks()
|
|
19
|
-
})
|
|
20
|
-
|
|
21
|
-
it('should return properties for given constructor names', () => {
|
|
22
|
-
const mockItem = { some: 'property' }
|
|
23
|
-
vi.mocked(hasNativeDirname).mockReturnValue(true)
|
|
24
|
-
vi.mocked(PropertiesFile.readFile).mockReturnValue(mockItem)
|
|
25
|
-
|
|
26
|
-
const result = getConstructorProperties(['Button', 'Input'])
|
|
27
|
-
|
|
28
|
-
expect(result).toEqual({
|
|
29
|
-
Button: mockItem,
|
|
30
|
-
Input: mockItem
|
|
31
|
-
})
|
|
32
|
-
expect(PropertiesFile.readFile).toHaveBeenCalledTimes(2)
|
|
33
|
-
})
|
|
34
|
-
|
|
35
|
-
it('should return an empty object if no constructors found or error occurs', () => {
|
|
36
|
-
vi.mocked(hasNativeDirname).mockReturnValue(true)
|
|
37
|
-
vi.mocked(PropertiesFile.readFile).mockReturnValue(undefined)
|
|
38
|
-
|
|
39
|
-
const result = getConstructorProperties(['NonExistent'])
|
|
40
|
-
|
|
41
|
-
expect(result).toEqual({})
|
|
42
|
-
})
|
|
43
|
-
|
|
44
|
-
it('should handles non-native dirname environment', () => {
|
|
45
|
-
vi.mocked(hasNativeDirname).mockReturnValue(false)
|
|
46
|
-
vi.mocked(PropertiesFile.readFile).mockReturnValue({ status: 'ok' })
|
|
47
|
-
|
|
48
|
-
const result = getConstructorProperties(['Button'])
|
|
49
|
-
expect(result).toEqual({ Button: { status: 'ok' } })
|
|
50
|
-
})
|
|
51
|
-
})
|
|
@@ -1,31 +0,0 @@
|
|
|
1
|
-
import { describe, expect, it, vi, beforeEach } from 'vitest'
|
|
2
|
-
import { getDirname } from '../getDirname'
|
|
3
|
-
import { hasNativeDirname } from '../hasNativeDirname'
|
|
4
|
-
|
|
5
|
-
vi.mock('../hasNativeDirname', () => ({
|
|
6
|
-
hasNativeDirname: vi.fn()
|
|
7
|
-
}))
|
|
8
|
-
|
|
9
|
-
// We can't easily mock import.meta.url or __dirname globally in a way that affects the module internally without ESM tricks,
|
|
10
|
-
// but we can at least test that it calls the right path based on hasNativeDirname
|
|
11
|
-
describe('getDirname', () => {
|
|
12
|
-
beforeEach(() => {
|
|
13
|
-
vi.clearAllMocks()
|
|
14
|
-
})
|
|
15
|
-
|
|
16
|
-
it('should return __dirname when hasNativeDirname is true', () => {
|
|
17
|
-
vi.mocked(hasNativeDirname).mockReturnValue(true)
|
|
18
|
-
|
|
19
|
-
// In a vitest environment with native support, __dirname should be defined
|
|
20
|
-
// We expect it to not throw and return a string
|
|
21
|
-
const result = getDirname()
|
|
22
|
-
expect(typeof result).toBe('string')
|
|
23
|
-
})
|
|
24
|
-
|
|
25
|
-
it('should return a path via fileURLToPath when hasNativeDirname is false', () => {
|
|
26
|
-
vi.mocked(hasNativeDirname).mockReturnValue(false)
|
|
27
|
-
|
|
28
|
-
const result = getDirname()
|
|
29
|
-
expect(typeof result).toBe('string')
|
|
30
|
-
})
|
|
31
|
-
})
|
|
@@ -1,40 +0,0 @@
|
|
|
1
|
-
import { describe, expect, it, vi, beforeEach } from 'vitest'
|
|
2
|
-
import { getNameDirByPaths } from '../getNameDirByPaths'
|
|
3
|
-
import { PropertiesFile } from '../../classes/Properties/PropertiesFile'
|
|
4
|
-
|
|
5
|
-
vi.mock('../../classes/Properties/PropertiesFile', () => ({
|
|
6
|
-
PropertiesFile: {
|
|
7
|
-
splitForDir: vi.fn(),
|
|
8
|
-
joinPath: vi.fn()
|
|
9
|
-
}
|
|
10
|
-
}))
|
|
11
|
-
|
|
12
|
-
describe('getNameDirByPaths', () => {
|
|
13
|
-
beforeEach(() => {
|
|
14
|
-
vi.clearAllMocks()
|
|
15
|
-
})
|
|
16
|
-
|
|
17
|
-
it('should return the last directory name from provided paths', () => {
|
|
18
|
-
const mockPaths = ['src', 'components', 'button']
|
|
19
|
-
const mockJoinedPath = 'src/components/button'
|
|
20
|
-
const mockSplitDirs = ['src', 'components', 'button']
|
|
21
|
-
|
|
22
|
-
vi.mocked(PropertiesFile.joinPath).mockReturnValue(mockJoinedPath)
|
|
23
|
-
vi.mocked(PropertiesFile.splitForDir).mockReturnValue(mockSplitDirs)
|
|
24
|
-
|
|
25
|
-
const result = getNameDirByPaths(mockPaths)
|
|
26
|
-
|
|
27
|
-
expect(result).toBe('button')
|
|
28
|
-
expect(PropertiesFile.joinPath).toHaveBeenCalledWith(mockPaths)
|
|
29
|
-
expect(PropertiesFile.splitForDir).toHaveBeenCalledWith(mockJoinedPath)
|
|
30
|
-
})
|
|
31
|
-
|
|
32
|
-
it('should work with a single path segment', () => {
|
|
33
|
-
const mockPaths = ['root']
|
|
34
|
-
vi.mocked(PropertiesFile.joinPath).mockReturnValue('root')
|
|
35
|
-
vi.mocked(PropertiesFile.splitForDir).mockReturnValue(['root'])
|
|
36
|
-
|
|
37
|
-
const result = getNameDirByPaths(mockPaths)
|
|
38
|
-
expect(result).toBe('root')
|
|
39
|
-
})
|
|
40
|
-
})
|
|
@@ -1,34 +0,0 @@
|
|
|
1
|
-
import { describe, expect, it, vi, beforeEach } from 'vitest'
|
|
2
|
-
import { getPackageJson } from '../getPackageJson'
|
|
3
|
-
import { PropertiesFile } from '../../classes/Properties/PropertiesFile'
|
|
4
|
-
import { UI_FILE_PACKAGE } from '../../config'
|
|
5
|
-
|
|
6
|
-
vi.mock('../../classes/Properties/PropertiesFile', () => ({
|
|
7
|
-
PropertiesFile: {
|
|
8
|
-
readFile: vi.fn()
|
|
9
|
-
}
|
|
10
|
-
}))
|
|
11
|
-
|
|
12
|
-
describe('getPackageJson', () => {
|
|
13
|
-
beforeEach(() => {
|
|
14
|
-
vi.clearAllMocks()
|
|
15
|
-
})
|
|
16
|
-
|
|
17
|
-
it('should return package.json content via PropertiesFile.readFile', () => {
|
|
18
|
-
const mockContent = { name: 'test-package', version: '1.0.0' }
|
|
19
|
-
vi.mocked(PropertiesFile.readFile).mockReturnValue(mockContent)
|
|
20
|
-
|
|
21
|
-
const result = getPackageJson()
|
|
22
|
-
|
|
23
|
-
expect(result).toEqual(mockContent)
|
|
24
|
-
expect(PropertiesFile.readFile).toHaveBeenCalledWith(UI_FILE_PACKAGE)
|
|
25
|
-
})
|
|
26
|
-
|
|
27
|
-
it('should return undefined if file reading fails', () => {
|
|
28
|
-
vi.mocked(PropertiesFile.readFile).mockReturnValue(undefined)
|
|
29
|
-
|
|
30
|
-
const result = getPackageJson()
|
|
31
|
-
|
|
32
|
-
expect(result).toBeUndefined()
|
|
33
|
-
})
|
|
34
|
-
})
|
|
@@ -1,18 +0,0 @@
|
|
|
1
|
-
import { describe, expect, it } from 'vitest'
|
|
2
|
-
import { hasNativeDirname } from '../hasNativeDirname'
|
|
3
|
-
|
|
4
|
-
describe('hasNativeDirname', () => {
|
|
5
|
-
it('should return a boolean', () => {
|
|
6
|
-
const result = hasNativeDirname()
|
|
7
|
-
expect(typeof result).toBe('boolean')
|
|
8
|
-
})
|
|
9
|
-
|
|
10
|
-
it('it should return true if __dirname is defined', () => {
|
|
11
|
-
// In vitest/node environment, __dirname is usually defined
|
|
12
|
-
// We can't easily "un-define" it for a negative test without complex environment manipulation,
|
|
13
|
-
// but we can verify it returns true if it's there
|
|
14
|
-
if (typeof __dirname !== 'undefined') {
|
|
15
|
-
expect(hasNativeDirname()).toBe(true)
|
|
16
|
-
}
|
|
17
|
-
})
|
|
18
|
-
})
|