kalo-cli 0.2.27 → 0.3.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/README.md +80 -46
- package/bin/kalo.ts +3 -2
- package/package.json +2 -1
- package/plopfile.ts +182 -25
- package/dist/docs/app.js +0 -42644
- package/dist/docs/index.html +0 -32
- package/generators/constants.ts +0 -52
- package/generators/generator/django-app/index.ts +0 -72
- package/generators/generator/django-app/templates/admin.py.hbs +0 -6
- package/generators/generator/django-app/templates/apps.py.hbs +0 -9
- package/generators/generator/django-app/templates/init.py.hbs +0 -0
- package/generators/generator/django-app/templates/models_init.py.hbs +0 -2
- package/generators/generator/django-app/templates/urls.py.hbs +0 -8
- package/generators/generator/django-app/templates/views.py.hbs +0 -5
- package/generators/generator/django-channel/index.ts +0 -80
- package/generators/generator/django-channel/templates/consumer.py.hbs +0 -47
- package/generators/generator/django-channel/templates/routing.py.hbs +0 -8
- package/generators/generator/django-form/index.ts +0 -64
- package/generators/generator/django-form/templates/form.py.hbs +0 -15
- package/generators/generator/django-form/templates/forms_file.py.hbs +0 -6
- package/generators/generator/django-form/templates/model_form.py.hbs +0 -19
- package/generators/generator/django-view/index.ts +0 -96
- package/generators/generator/django-view/templates/view_cbv.py.hbs +0 -14
- package/generators/generator/django-view/templates/view_fbv.py.hbs +0 -10
- package/generators/generator/django-view/templates/view_template.html.hbs +0 -8
- package/generators/generator/main/index.ts +0 -70
- package/generators/generator/wagtail-admin/index.ts +0 -124
- package/generators/generator/wagtail-admin/templates/admin_view.html.hbs +0 -21
- package/generators/generator/wagtail-admin/templates/admin_view.py.hbs +0 -15
- package/generators/generator/wagtail-admin/templates/component.html.hbs +0 -6
- package/generators/generator/wagtail-admin/templates/component.py.hbs +0 -11
- package/generators/generator/wagtail-admin/templates/wagtail_hooks.py.hbs +0 -18
- package/generators/generator/wagtail-block/index.ts +0 -53
- package/generators/generator/wagtail-block/templates/block_class.py.hbs +0 -16
- package/generators/generator/wagtail-block/templates/block_template.html.hbs +0 -5
- package/generators/generator/wagtail-page/actions/model.ts +0 -20
- package/generators/generator/wagtail-page/actions/orderable.ts +0 -23
- package/generators/generator/wagtail-page/actions/page.ts +0 -42
- package/generators/generator/wagtail-page/actions/snippet.ts +0 -20
- package/generators/generator/wagtail-page/index.ts +0 -63
- package/generators/generator/wagtail-page/templates/django_model.py.hbs +0 -21
- package/generators/generator/wagtail-page/templates/orderable_model.py.hbs +0 -27
- package/generators/generator/wagtail-page/templates/page_pair_model.py.hbs +0 -69
- package/generators/generator/wagtail-page/templates/page_template.html.hbs +0 -14
- package/generators/generator/wagtail-page/templates/snippet_model.py.hbs +0 -29
- package/generators/ia/ai-enhancer/index.ts +0 -319
- package/generators/ia/docs/index.ts +0 -36
- package/generators/ia/docs/keywords.json +0 -1158
- package/generators/ia/help/index.ts +0 -85
- package/generators/main/index.ts +0 -422
- package/generators/utils/ai/common.ts +0 -141
- package/generators/utils/ai/index.ts +0 -2
- package/generators/utils/analysis.ts +0 -88
- package/generators/utils/code-manipulation.ts +0 -229
- package/generators/utils/config.ts +0 -43
- package/generators/utils/filesystem.ts +0 -131
- package/generators/utils/index.ts +0 -35
- package/generators/utils/plop-actions.ts +0 -104
- package/generators/utils/search.ts +0 -24
- package/tsconfig.json +0 -29
package/dist/docs/index.html
DELETED
|
@@ -1,32 +0,0 @@
|
|
|
1
|
-
<!doctype html>
|
|
2
|
-
<html lang="fr">
|
|
3
|
-
<head>
|
|
4
|
-
<meta charset="utf-8" />
|
|
5
|
-
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
|
6
|
-
<title>Documentation Keywords</title>
|
|
7
|
-
<style>
|
|
8
|
-
body { font-family: system-ui, -apple-system, sans-serif; max-width: 900px; margin: 0 auto; padding: 2rem; background: #f9fafb; color: #1f2937; }
|
|
9
|
-
h1 { text-align: center; margin-bottom: 2rem; color: #111827; }
|
|
10
|
-
.search-container { position: sticky; top: 1rem; z-index: 10; background: #f9fafb; padding-bottom: 1rem; }
|
|
11
|
-
.search-box { width: 100%; padding: 1rem; font-size: 1.1rem; border: 2px solid #e5e7eb; border-radius: 12px; box-shadow: 0 1px 2px 0 rgba(0, 0, 0, 0.05); transition: border-color 0.2s; box-sizing: border-box; }
|
|
12
|
-
.search-box:focus { outline: none; border-color: #3b82f6; box-shadow: 0 0 0 3px rgba(59, 130, 246, 0.1); }
|
|
13
|
-
.card { background: white; padding: 1.5rem; margin-bottom: 1.5rem; border-radius: 12px; box-shadow: 0 1px 3px 0 rgba(0, 0, 0, 0.1), 0 1px 2px 0 rgba(0, 0, 0, 0.06); border: 1px solid #f3f4f6; transition: transform 0.2s; }
|
|
14
|
-
.card:hover { transform: translateY(-2px); box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1), 0 2px 4px -1px rgba(0, 0, 0, 0.06); }
|
|
15
|
-
.tags { display: flex; flex-wrap: wrap; gap: 0.5rem; margin-bottom: 1rem; }
|
|
16
|
-
.tag { background: #eff6ff; color: #1d4ed8; padding: 0.25rem 0.75rem; border-radius: 9999px; font-size: 0.875rem; font-weight: 500; }
|
|
17
|
-
.instruction { font-size: 1.05rem; margin-bottom: 1rem; line-height: 1.6; }
|
|
18
|
-
.doc-section { margin-top: 1rem; padding-top: 1rem; border-top: 1px solid #f3f4f6; }
|
|
19
|
-
.doc-content { color: #4b5563; line-height: 1.6; margin-bottom: 0.5rem; }
|
|
20
|
-
.official-doc { background-color: #f0fdf4; border: 1px solid #bbf7d0; padding: 1rem; border-radius: 8px; margin-top: 1rem; color: #166534; }
|
|
21
|
-
.official-label { display: block; font-weight: 600; color: #15803d; margin-bottom: 0.5rem; font-size: 0.9rem; text-transform: uppercase; letter-spacing: 0.05em; }
|
|
22
|
-
.label { font-weight: 600; color: #111827; margin-right: 0.5rem; }
|
|
23
|
-
.search-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 1rem; margin-bottom: 1rem; }
|
|
24
|
-
@media (max-width: 640px) { .search-grid { grid-template-columns: 1fr; } }
|
|
25
|
-
.empty-state { text-align: center; color: #6b7280; margin-top: 3rem; font-size: 1.1rem; }
|
|
26
|
-
</style>
|
|
27
|
-
</head>
|
|
28
|
-
<body>
|
|
29
|
-
<div id="root"></div>
|
|
30
|
-
<script type="module" src="./app.js"></script>
|
|
31
|
-
</body>
|
|
32
|
-
</html>
|
package/generators/constants.ts
DELETED
|
@@ -1,52 +0,0 @@
|
|
|
1
|
-
export const WAGTAIL_PAGE_TYPES = [
|
|
2
|
-
{ name: 'Paire de Pages Standard (Index + Detail) : Pour une structure hiérarchique (ex: Liste de blog -> Article de blog).', value: 'page_pair' },
|
|
3
|
-
{ name: 'Modèle Orderable : Pour gérer des listes ordonnées d\'éléments dans une page (ex: Carrousel, Galerie).', value: 'orderable' },
|
|
4
|
-
{ name: 'Snippet Wagtail : Pour du contenu réutilisable hors arborescence (ex: Catégories, Auteurs, Publicités).', value: 'snippet' },
|
|
5
|
-
{ name: 'Modèle Django Standard : Une table de base de données classique sans fonctionnalités CMS Wagtail.', value: 'model' },
|
|
6
|
-
];
|
|
7
|
-
|
|
8
|
-
export const MAIN_COMPONENT_TYPES = [
|
|
9
|
-
{ name: 'Modifier une classe existante (AI Enhancer)', value: 'ai_enhancer' },
|
|
10
|
-
...WAGTAIL_PAGE_TYPES,
|
|
11
|
-
{ name: 'Block StreamField', value: 'block' },
|
|
12
|
-
{ name: 'Vue Django (FBV/CBV)', value: 'view' },
|
|
13
|
-
{ name: 'Formulaire Django', value: 'form' },
|
|
14
|
-
{ name: 'Consumer Django Channel', value: 'channel' },
|
|
15
|
-
{ name: 'Extension Admin Wagtail', value: 'admin_ext' },
|
|
16
|
-
];
|
|
17
|
-
|
|
18
|
-
export const VIEW_TYPES = [
|
|
19
|
-
{ name: 'Vue basée sur une fonction (FBV) : Idéale pour une logique sur-mesure simple sans l\'abstraction des classes.', value: 'fbv' },
|
|
20
|
-
{ name: 'TemplateView (CBV) : Affiche une page HTML statique ou avec des données contextuelles simples.', value: 'TemplateView' },
|
|
21
|
-
{ name: 'ListView (CBV) : Génère une page listant plusieurs objets d\'un modèle (ex: catalogue, blog).', value: 'ListView' },
|
|
22
|
-
{ name: 'DetailView (CBV) : Affiche les informations détaillées d\'un objet unique (ex: fiche produit, article).', value: 'DetailView' },
|
|
23
|
-
{ name: 'CreateView (CBV) : Génère un formulaire pour ajouter une nouvelle entrée dans la base de données.', value: 'CreateView' },
|
|
24
|
-
{ name: 'UpdateView (CBV) : Génère un formulaire pré-rempli pour modifier une entrée existante.', value: 'UpdateView' },
|
|
25
|
-
{ name: 'DeleteView (CBV) : Affiche une page de confirmation avant la suppression définitive d\'un objet.', value: 'DeleteView' },
|
|
26
|
-
];
|
|
27
|
-
|
|
28
|
-
export const FORM_TYPES = [
|
|
29
|
-
{ name: 'Formulaire Standard (forms.Form) : Pour traiter des données génériques (ex: recherche, contact).', value: 'form' },
|
|
30
|
-
{ name: 'Formulaire de Modèle (forms.ModelForm) : Crée automatiquement des champs basés sur un modèle existant.', value: 'model_form' },
|
|
31
|
-
];
|
|
32
|
-
|
|
33
|
-
export const ADMIN_EXT_TYPES = [
|
|
34
|
-
{ name: 'Vue d\'Administration (Page Personnalisée) : Ajoute une page complète dans le menu admin Wagtail.', value: 'view' },
|
|
35
|
-
{ name: 'Composant Template (Panneau UI) : Crée un élément d\'interface réutilisable (Panel) pour les formulaires d\'édition.', value: 'component' },
|
|
36
|
-
];
|
|
37
|
-
|
|
38
|
-
export const CHANNEL_TYPES = [
|
|
39
|
-
{ name: 'Consumer Websocket Asynchrone : Pour haute performance (chat, notifications) avec asyncio.', value: 'async' },
|
|
40
|
-
{ name: 'Consumer Websocket Synchrone : Pour logique bloquante standard ou code hérité.', value: 'sync' },
|
|
41
|
-
];
|
|
42
|
-
|
|
43
|
-
export const AI_PROVIDER_TYPES = ['Qwen', 'Gemini'];
|
|
44
|
-
|
|
45
|
-
export const AI_TEMP_TYPES = [
|
|
46
|
-
{ name: 'Strict & Précis (0.1)', value: 0.1 },
|
|
47
|
-
{ name: 'Équilibré (0.5)', value: 0.5 },
|
|
48
|
-
{ name: 'Créatif (0.9)', value: 0.9 }
|
|
49
|
-
];
|
|
50
|
-
|
|
51
|
-
export const EXIT_VALUE = '__EXIT__';
|
|
52
|
-
export const BACK_VALUE = '__BACK__';
|
|
@@ -1,72 +0,0 @@
|
|
|
1
|
-
import { PlopGeneratorConfig } from 'plop';
|
|
2
|
-
import * as path from 'path';
|
|
3
|
-
import { resolveAppPaths } from '../../utils/filesystem.ts';
|
|
4
|
-
|
|
5
|
-
/**
|
|
6
|
-
* Generator configuration for creating a new Django Application.
|
|
7
|
-
* Sets up the standard directory structure, models, views, urls, and admin files.
|
|
8
|
-
*
|
|
9
|
-
* @type {PlopGeneratorConfig}
|
|
10
|
-
*/
|
|
11
|
-
export const djangoAppGenerator: PlopGeneratorConfig = {
|
|
12
|
-
description: 'Créer une nouvelle application Django avec la structure standard',
|
|
13
|
-
prompts: [
|
|
14
|
-
{
|
|
15
|
-
type: 'input',
|
|
16
|
-
name: 'name',
|
|
17
|
-
message: 'Quel est le nom de l\'application Django ? (Cela créera un dossier avec models, views, urls pour une fonctionnalité)',
|
|
18
|
-
validate: (value) => {
|
|
19
|
-
if (/.+/.test(value)) {
|
|
20
|
-
return true;
|
|
21
|
-
}
|
|
22
|
-
return 'Le nom est requis';
|
|
23
|
-
},
|
|
24
|
-
},
|
|
25
|
-
],
|
|
26
|
-
actions: (data: any) => {
|
|
27
|
-
const { appDir, appPath } = resolveAppPaths(data.config, data.name);
|
|
28
|
-
return [
|
|
29
|
-
{
|
|
30
|
-
type: 'add',
|
|
31
|
-
path: `${appDir}/__init__.py`,
|
|
32
|
-
templateFile: 'generators/generator/django-app/templates/init.py.hbs',
|
|
33
|
-
skipIfExists: true,
|
|
34
|
-
},
|
|
35
|
-
{
|
|
36
|
-
type: 'add',
|
|
37
|
-
path: `${appPath}/__init__.py`,
|
|
38
|
-
templateFile: 'generators/generator/django-app/templates/init.py.hbs',
|
|
39
|
-
},
|
|
40
|
-
{
|
|
41
|
-
type: 'add',
|
|
42
|
-
path: `${appPath}/apps.py`,
|
|
43
|
-
templateFile: 'generators/generator/django-app/templates/apps.py.hbs',
|
|
44
|
-
},
|
|
45
|
-
{
|
|
46
|
-
type: 'add',
|
|
47
|
-
path: `${appPath}/models/__init__.py`,
|
|
48
|
-
templateFile: 'generators/generator/django-app/templates/models_init.py.hbs',
|
|
49
|
-
},
|
|
50
|
-
{
|
|
51
|
-
type: 'add',
|
|
52
|
-
path: `${appPath}/tests/__init__.py`,
|
|
53
|
-
templateFile: 'generators/generator/django-app/templates/init.py.hbs',
|
|
54
|
-
},
|
|
55
|
-
{
|
|
56
|
-
type: 'add',
|
|
57
|
-
path: `${appPath}/views.py`,
|
|
58
|
-
templateFile: 'generators/generator/django-app/templates/views.py.hbs',
|
|
59
|
-
},
|
|
60
|
-
{
|
|
61
|
-
type: 'add',
|
|
62
|
-
path: `${appPath}/urls.py`,
|
|
63
|
-
templateFile: 'generators/generator/django-app/templates/urls.py.hbs',
|
|
64
|
-
},
|
|
65
|
-
{
|
|
66
|
-
type: 'add',
|
|
67
|
-
path: `${appPath}/admin.py`,
|
|
68
|
-
templateFile: 'generators/generator/django-app/templates/admin.py.hbs',
|
|
69
|
-
},
|
|
70
|
-
];
|
|
71
|
-
},
|
|
72
|
-
};
|
|
@@ -1,9 +0,0 @@
|
|
|
1
|
-
from django.apps import AppConfig
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
class {{pascalCase name}}Config(AppConfig):
|
|
5
|
-
default_auto_field = 'django.db.models.BigAutoField'
|
|
6
|
-
name = 'app.{{name}}'
|
|
7
|
-
|
|
8
|
-
# <!-- CLASS = {{pascalCase name}}Config START AI_GENERATED -->
|
|
9
|
-
# <!-- CLASS = {{pascalCase name}}Config END AI_GENERATED -->
|
|
File without changes
|
|
@@ -1,80 +0,0 @@
|
|
|
1
|
-
import { PlopGeneratorConfig } from 'plop';
|
|
2
|
-
import * as path from 'path';
|
|
3
|
-
import { ensureSuffix, createAppendActions } from '../../utils/plop-actions.ts';
|
|
4
|
-
import { resolveAppPaths } from '../../utils/filesystem.ts';
|
|
5
|
-
import { CHANNEL_TYPES } from '../../constants.ts';
|
|
6
|
-
import { searchChoices } from '../../utils/search.ts';
|
|
7
|
-
|
|
8
|
-
/**
|
|
9
|
-
* Generator configuration for creating a Django Channel Consumer and Routing.
|
|
10
|
-
* Supports Async and Sync Websocket Consumers.
|
|
11
|
-
* Automatically configures routing and adds tests.
|
|
12
|
-
*
|
|
13
|
-
* @type {PlopGeneratorConfig}
|
|
14
|
-
*/
|
|
15
|
-
export const djangoChannelGenerator: PlopGeneratorConfig = {
|
|
16
|
-
description: 'Créer un Consumer Django Channel et son routing',
|
|
17
|
-
prompts: [
|
|
18
|
-
{
|
|
19
|
-
type: 'autocomplete',
|
|
20
|
-
name: 'type',
|
|
21
|
-
message: 'Quel type de consumer voulez-vous créer ?',
|
|
22
|
-
source: (answers, input) => searchChoices(input, CHANNEL_TYPES),
|
|
23
|
-
},
|
|
24
|
-
{
|
|
25
|
-
type: 'input',
|
|
26
|
-
name: 'name',
|
|
27
|
-
message: 'Nom du Consumer (ex: ChatConsumer) :',
|
|
28
|
-
validate: (value) => {
|
|
29
|
-
return true;
|
|
30
|
-
},
|
|
31
|
-
},
|
|
32
|
-
{
|
|
33
|
-
type: 'input',
|
|
34
|
-
name: 'route',
|
|
35
|
-
message: 'Préfixe de la route URL (ex: chat -> ws/chat/room_name/) :',
|
|
36
|
-
default: 'chat',
|
|
37
|
-
},
|
|
38
|
-
{
|
|
39
|
-
type: 'input',
|
|
40
|
-
name: 'app',
|
|
41
|
-
message: 'Nom de l\'application cible',
|
|
42
|
-
},
|
|
43
|
-
],
|
|
44
|
-
actions: (data: any) => {
|
|
45
|
-
const actions = [];
|
|
46
|
-
const { appPath } = resolveAppPaths(data.config, data.app);
|
|
47
|
-
const isAsync = data.type === 'async';
|
|
48
|
-
data.isAsync = isAsync;
|
|
49
|
-
|
|
50
|
-
// Ensure suffix
|
|
51
|
-
data.name = ensureSuffix(data.name, 'Consumer');
|
|
52
|
-
|
|
53
|
-
// Ensure consumers.py exists and Append Consumer
|
|
54
|
-
actions.push(...createAppendActions({
|
|
55
|
-
path: `${appPath}/consumers.py`,
|
|
56
|
-
templateFile: 'generators/generator/django-channel/templates/consumer.py.hbs',
|
|
57
|
-
dumbTemplate: 'import json\nfrom channels.generic.websocket import AsyncWebsocketConsumer, WebsocketConsumer\n\n',
|
|
58
|
-
dumbData: {},
|
|
59
|
-
}));
|
|
60
|
-
|
|
61
|
-
// Ensure routing.py exists
|
|
62
|
-
actions.push({
|
|
63
|
-
type: 'add',
|
|
64
|
-
path: `${appPath}/routing.py`,
|
|
65
|
-
templateFile: 'generators/generator/django-channel/templates/routing.py.hbs',
|
|
66
|
-
skipIfExists: true,
|
|
67
|
-
});
|
|
68
|
-
|
|
69
|
-
// Append to websocket_urlpatterns in routing.py
|
|
70
|
-
// We look for the closing bracket of websocket_urlpatterns list
|
|
71
|
-
actions.push({
|
|
72
|
-
type: 'modify',
|
|
73
|
-
path: `${appPath}/routing.py`,
|
|
74
|
-
pattern: /(websocket_urlpatterns\s*=\s*\[)/,
|
|
75
|
-
template: '$1\n re_path(r\'ws/{{ route }}/(?P<room_name>\\w+)/$\', consumers.{{ name }}.as_asgi()),',
|
|
76
|
-
});
|
|
77
|
-
|
|
78
|
-
return actions;
|
|
79
|
-
},
|
|
80
|
-
};
|
|
@@ -1,47 +0,0 @@
|
|
|
1
|
-
import json
|
|
2
|
-
from channels.generic.websocket import {{#if isAsync}}AsyncWebsocketConsumer{{else}}WebsocketConsumer{{/if}}
|
|
3
|
-
|
|
4
|
-
class {{ name }}({{#if isAsync}}AsyncWebsocketConsumer{{else}}WebsocketConsumer{{/if}}):
|
|
5
|
-
# <!-- CLASS = {{ name }} START AI_GENERATED -->
|
|
6
|
-
# <!-- CLASS = {{ name }} END AI_GENERATED -->
|
|
7
|
-
{{#if isAsync}}async {{/if}}def connect(self):
|
|
8
|
-
self.room_name = self.scope['url_route']['kwargs']['room_name']
|
|
9
|
-
self.room_group_name = 'chat_%s' % self.room_name
|
|
10
|
-
|
|
11
|
-
# Join room group
|
|
12
|
-
{{#if isAsync}}await {{/if}}self.channel_layer.group_add(
|
|
13
|
-
self.room_group_name,
|
|
14
|
-
self.channel_name
|
|
15
|
-
)
|
|
16
|
-
|
|
17
|
-
{{#if isAsync}}await {{/if}}self.accept()
|
|
18
|
-
|
|
19
|
-
{{#if isAsync}}async {{/if}}def disconnect(self, close_code):
|
|
20
|
-
# Leave room group
|
|
21
|
-
{{#if isAsync}}await {{/if}}self.channel_layer.group_discard(
|
|
22
|
-
self.room_group_name,
|
|
23
|
-
self.channel_name
|
|
24
|
-
)
|
|
25
|
-
|
|
26
|
-
# Receive message from WebSocket
|
|
27
|
-
{{#if isAsync}}async {{/if}}def receive(self, text_data):
|
|
28
|
-
text_data_json = json.loads(text_data)
|
|
29
|
-
message = text_data_json['message']
|
|
30
|
-
|
|
31
|
-
# Send message to room group
|
|
32
|
-
{{#if isAsync}}await {{/if}}self.channel_layer.group_send(
|
|
33
|
-
self.room_group_name,
|
|
34
|
-
{
|
|
35
|
-
'type': 'chat_message',
|
|
36
|
-
'message': message
|
|
37
|
-
}
|
|
38
|
-
)
|
|
39
|
-
|
|
40
|
-
# Receive message from room group
|
|
41
|
-
{{#if isAsync}}async {{/if}}def chat_message(self, event):
|
|
42
|
-
message = event['message']
|
|
43
|
-
|
|
44
|
-
# Send message to WebSocket
|
|
45
|
-
{{#if isAsync}}await {{/if}}self.send(text_data=json.dumps({
|
|
46
|
-
'message': message
|
|
47
|
-
}))
|
|
@@ -1,8 +0,0 @@
|
|
|
1
|
-
from django.urls import re_path
|
|
2
|
-
from . import consumers
|
|
3
|
-
|
|
4
|
-
websocket_urlpatterns = [
|
|
5
|
-
# <!-- CLASS = {{pascalCase name}}Routing START AI_GENERATED -->
|
|
6
|
-
# <!-- CLASS = {{pascalCase name}}Routing END AI_GENERATED -->
|
|
7
|
-
# re_path(r'ws/chat/(?P<room_name>\w+)/$', consumers.ChatConsumer.as_asgi()),
|
|
8
|
-
]
|
|
@@ -1,64 +0,0 @@
|
|
|
1
|
-
import { PlopGeneratorConfig } from 'plop';
|
|
2
|
-
import * as path from 'path';
|
|
3
|
-
import { ensureSuffix, createAppendActions } from '../../utils/plop-actions.ts';
|
|
4
|
-
import { resolveAppPaths } from '../../utils/filesystem.ts';
|
|
5
|
-
import { FORM_TYPES } from '../../constants.ts';
|
|
6
|
-
import { searchChoices } from '../../utils/search.ts';
|
|
7
|
-
|
|
8
|
-
/**
|
|
9
|
-
* Generator configuration for creating a Django Form or ModelForm.
|
|
10
|
-
* Handles standard forms and model-bound forms.
|
|
11
|
-
*
|
|
12
|
-
* @type {PlopGeneratorConfig}
|
|
13
|
-
*/
|
|
14
|
-
export const djangoFormGenerator: PlopGeneratorConfig = {
|
|
15
|
-
description: 'Créer un Formulaire Django ou un ModelForm',
|
|
16
|
-
prompts: [
|
|
17
|
-
{
|
|
18
|
-
type: 'autocomplete',
|
|
19
|
-
name: 'type',
|
|
20
|
-
message: 'Quel type de formulaire voulez-vous créer ?',
|
|
21
|
-
source: (answers, input) => searchChoices(input, FORM_TYPES),
|
|
22
|
-
},
|
|
23
|
-
{
|
|
24
|
-
type: 'input',
|
|
25
|
-
name: 'name',
|
|
26
|
-
message: 'Nom du Formulaire (ex: ContactForm, UserProfileForm) :',
|
|
27
|
-
validate: (value) => {
|
|
28
|
-
return true;
|
|
29
|
-
},
|
|
30
|
-
},
|
|
31
|
-
{
|
|
32
|
-
type: 'input',
|
|
33
|
-
name: 'model',
|
|
34
|
-
message: 'Nom du Modèle associé (ex: UserProfile) :',
|
|
35
|
-
when: (answers) => answers.type === 'model_form',
|
|
36
|
-
},
|
|
37
|
-
{
|
|
38
|
-
type: 'input',
|
|
39
|
-
name: 'app',
|
|
40
|
-
message: 'Nom de l\'application cible',
|
|
41
|
-
},
|
|
42
|
-
],
|
|
43
|
-
actions: (data: any) => {
|
|
44
|
-
const actions = [];
|
|
45
|
-
const { appPath } = resolveAppPaths(data.config, data.app);
|
|
46
|
-
const isModelForm = data.type === 'model_form';
|
|
47
|
-
|
|
48
|
-
// Ensure suffix
|
|
49
|
-
data.name = ensureSuffix(data.name, 'Form');
|
|
50
|
-
|
|
51
|
-
const templateFile = isModelForm
|
|
52
|
-
? 'generators/django-form/templates/model_form.py.hbs'
|
|
53
|
-
: 'generators/django-form/templates/form.py.hbs';
|
|
54
|
-
|
|
55
|
-
actions.push(...createAppendActions({
|
|
56
|
-
path: `${appPath}/forms.py`,
|
|
57
|
-
templateFile,
|
|
58
|
-
dumbTemplateFile: 'generators/django-form/templates/forms_file.py.hbs',
|
|
59
|
-
dumbData: data,
|
|
60
|
-
}));
|
|
61
|
-
|
|
62
|
-
return actions;
|
|
63
|
-
},
|
|
64
|
-
};
|
|
@@ -1,15 +0,0 @@
|
|
|
1
|
-
|
|
2
|
-
from django import forms
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
class {{ name }}(forms.Form):
|
|
6
|
-
# TODO: Define form fields here
|
|
7
|
-
# name = forms.CharField(max_length=100)
|
|
8
|
-
# message = forms.CharField(widget=forms.Textarea)
|
|
9
|
-
|
|
10
|
-
# <!-- CLASS = {{ name }} START AI_GENERATED -->
|
|
11
|
-
# <!-- CLASS = {{ name }} END AI_GENERATED -->
|
|
12
|
-
def clean(self):
|
|
13
|
-
cleaned_data = super().clean()
|
|
14
|
-
# TODO: Add custom validation logic
|
|
15
|
-
return cleaned_data
|
|
@@ -1,19 +0,0 @@
|
|
|
1
|
-
|
|
2
|
-
from django import forms
|
|
3
|
-
{{#if model}}from .models import {{ model }}{{/if}}
|
|
4
|
-
|
|
5
|
-
class {{ name }}(forms.ModelForm):
|
|
6
|
-
class Meta:
|
|
7
|
-
|
|
8
|
-
{{#if model}} model = {{ model }}{{/if}}
|
|
9
|
-
{{#unless model}} # model = YourModel{{/unless}}
|
|
10
|
-
fields = '__all__' # TODO: Specify explicit fields ['field1', 'field2']
|
|
11
|
-
# widgets = {
|
|
12
|
-
# 'field_name': forms.TextInput(attrs={'class': 'form-control'}),
|
|
13
|
-
# }
|
|
14
|
-
# <!-- CLASS = {{ name }} START AI_GENERATED -->
|
|
15
|
-
# <!-- CLASS = {{ name }} END AI_GENERATED -->
|
|
16
|
-
def clean(self):
|
|
17
|
-
cleaned_data = super().clean()
|
|
18
|
-
# TODO: Add custom validation logic
|
|
19
|
-
return cleaned_data
|
|
@@ -1,96 +0,0 @@
|
|
|
1
|
-
import { PlopGeneratorConfig } from 'plop';
|
|
2
|
-
import { createAppendActions, ensureSuffix } from '../../utils/plop-actions.ts';
|
|
3
|
-
import { VIEW_TYPES } from '../../constants.ts';
|
|
4
|
-
import { searchChoices } from '../../utils/search.ts';
|
|
5
|
-
import { resolveAppPaths } from '../../utils/filesystem.ts';
|
|
6
|
-
|
|
7
|
-
/**
|
|
8
|
-
* Generator configuration for creating Django Views.
|
|
9
|
-
* Supports Function-Based Views (FBV) and Class-Based Views (CBV) including:
|
|
10
|
-
* - TemplateView, ListView, DetailView, CreateView, UpdateView, DeleteView.
|
|
11
|
-
* Handles automatic suffixing logic for naming conventions.
|
|
12
|
-
*
|
|
13
|
-
* @type {PlopGeneratorConfig}
|
|
14
|
-
*/
|
|
15
|
-
export const djangoViewGenerator: PlopGeneratorConfig = {
|
|
16
|
-
description: 'Créer une Vue Django (FBV ou CBV)',
|
|
17
|
-
prompts: [
|
|
18
|
-
{
|
|
19
|
-
type: 'autocomplete',
|
|
20
|
-
name: 'type',
|
|
21
|
-
message: 'Quel type de vue voulez-vous créer ?',
|
|
22
|
-
source: (answers, input) => searchChoices(input, VIEW_TYPES),
|
|
23
|
-
},
|
|
24
|
-
{
|
|
25
|
-
type: 'input',
|
|
26
|
-
name: 'name',
|
|
27
|
-
message: 'Nom de la Vue (ex: UserProfile, ProductList) :',
|
|
28
|
-
validate: (value, answers) => {
|
|
29
|
-
return true;
|
|
30
|
-
}
|
|
31
|
-
},
|
|
32
|
-
{
|
|
33
|
-
type: 'input',
|
|
34
|
-
name: 'app',
|
|
35
|
-
message: 'Nom de l\'application cible',
|
|
36
|
-
},
|
|
37
|
-
],
|
|
38
|
-
actions: (data: any) => {
|
|
39
|
-
const actions = [];
|
|
40
|
-
const { appPath } = resolveAppPaths(data.config, data.app);
|
|
41
|
-
const isCBV = data.type !== 'fbv';
|
|
42
|
-
|
|
43
|
-
// Helper to ensure correct suffix for CBV
|
|
44
|
-
if (isCBV) {
|
|
45
|
-
let suffix = data.type; // e.g. ListView, DetailView
|
|
46
|
-
if (data.type === 'TemplateView') {
|
|
47
|
-
suffix = 'View';
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
if (!data.name.endsWith(suffix)) {
|
|
51
|
-
// Check if it ends with the "Type" part (e.g. "List" for "ListView")
|
|
52
|
-
const typePrefix = suffix.replace(/View$/, ''); // "List"
|
|
53
|
-
|
|
54
|
-
if (typePrefix && data.name.endsWith(typePrefix)) {
|
|
55
|
-
// e.g. ProductList + ListView -> ProductListView
|
|
56
|
-
data.name = `${data.name}View`;
|
|
57
|
-
} else if (data.name.endsWith('View')) {
|
|
58
|
-
// e.g. ProductView + ListView -> ProductListView
|
|
59
|
-
data.name = data.name.replace(/View$/, suffix);
|
|
60
|
-
} else {
|
|
61
|
-
// e.g. Product + ListView -> ProductListView
|
|
62
|
-
data.name = `${data.name}${suffix}`;
|
|
63
|
-
}
|
|
64
|
-
}
|
|
65
|
-
} else {
|
|
66
|
-
// FBV
|
|
67
|
-
data.name = ensureSuffix(data.name, '_view');
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
// Helper for template name
|
|
71
|
-
data.templateName = data.name.replace(/View$/, '');
|
|
72
|
-
|
|
73
|
-
// Append to views.py
|
|
74
|
-
const templateFile = isCBV
|
|
75
|
-
? 'generators/generator/django-view/templates/view_cbv.py.hbs'
|
|
76
|
-
: 'generators/generator/django-view/templates/view_fbv.py.hbs';
|
|
77
|
-
|
|
78
|
-
actions.push(...createAppendActions({
|
|
79
|
-
path: `${appPath}/views.py`,
|
|
80
|
-
templateFile,
|
|
81
|
-
dumbTemplate: 'from django.shortcuts import render\n\n',
|
|
82
|
-
dumbData: {},
|
|
83
|
-
appendData: isCBV ? { viewType: data.type } : undefined
|
|
84
|
-
}));
|
|
85
|
-
|
|
86
|
-
// Create Template
|
|
87
|
-
actions.push({
|
|
88
|
-
type: 'add',
|
|
89
|
-
path: `${appPath}/templates/${data.app}/{{snakeCase templateName}}.html`, // Clean filename
|
|
90
|
-
templateFile: 'generators/generator/django-view/templates/view_template.html.hbs',
|
|
91
|
-
skipIfExists: true,
|
|
92
|
-
});
|
|
93
|
-
|
|
94
|
-
return actions;
|
|
95
|
-
},
|
|
96
|
-
};
|
|
@@ -1,14 +0,0 @@
|
|
|
1
|
-
|
|
2
|
-
from django.views.generic import {{viewType}}
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
class {{pascalCase name}}({{viewType}}):
|
|
6
|
-
"""
|
|
7
|
-
Class-based view for {{name}}.
|
|
8
|
-
"""
|
|
9
|
-
template_name = '{{app}}/{{snakeCase name}}.html'
|
|
10
|
-
|
|
11
|
-
# <!-- CLASS = {{pascalCase name}} START AI_GENERATED -->
|
|
12
|
-
# <!-- CLASS = {{pascalCase name}} END AI_GENERATED -->
|
|
13
|
-
# context_object_name = '{{snakeCase name}}'
|
|
14
|
-
# model = MyModel
|
|
@@ -1,70 +0,0 @@
|
|
|
1
|
-
import { NodePlopAPI } from 'plop';
|
|
2
|
-
import { djangoAppGenerator } from '../django-app/index.ts';
|
|
3
|
-
import { wagtailPageGenerator } from '../wagtail-page/index.ts';
|
|
4
|
-
import { wagtailBlockGenerator } from '../wagtail-block/index.ts';
|
|
5
|
-
import { djangoViewGenerator } from '../django-view/index.ts';
|
|
6
|
-
import { djangoFormGenerator } from '../django-form/index.ts';
|
|
7
|
-
import { wagtailAdminGenerator } from '../wagtail-admin/index.ts';
|
|
8
|
-
import { djangoChannelGenerator } from '../django-channel/index.ts';
|
|
9
|
-
import { aiEnhancerGenerator } from '../../ia/ai-enhancer/index.ts';
|
|
10
|
-
import { helpGenerator } from '../../ia/help/index.ts';
|
|
11
|
-
import { searchChoices } from '../../utils/search.ts';
|
|
12
|
-
import {
|
|
13
|
-
MAIN_COMPONENT_TYPES,
|
|
14
|
-
EXIT_VALUE,
|
|
15
|
-
BACK_VALUE
|
|
16
|
-
} from '../../constants.ts';
|
|
17
|
-
|
|
18
|
-
const handleInput = (value: any) => {
|
|
19
|
-
if (value === EXIT_VALUE || (typeof value === 'string' && value.toLowerCase() === 'exit')) {
|
|
20
|
-
return EXIT_VALUE;
|
|
21
|
-
}
|
|
22
|
-
return value;
|
|
23
|
-
};
|
|
24
|
-
|
|
25
|
-
export default function (plop: NodePlopAPI) {
|
|
26
|
-
// Register Sub-Generators
|
|
27
|
-
plop.setGenerator('django-app', djangoAppGenerator);
|
|
28
|
-
plop.setGenerator('wagtail-page', wagtailPageGenerator);
|
|
29
|
-
plop.setGenerator('wagtail-block', wagtailBlockGenerator);
|
|
30
|
-
plop.setGenerator('django-view', djangoViewGenerator);
|
|
31
|
-
plop.setGenerator('django-form', djangoFormGenerator);
|
|
32
|
-
plop.setGenerator('wagtail-admin', wagtailAdminGenerator);
|
|
33
|
-
plop.setGenerator('django-channel', djangoChannelGenerator);
|
|
34
|
-
plop.setGenerator('ai-enhancer', aiEnhancerGenerator);
|
|
35
|
-
plop.setGenerator('help', helpGenerator);
|
|
36
|
-
|
|
37
|
-
// Register Main Generator (Menu)
|
|
38
|
-
plop.setGenerator('main', {
|
|
39
|
-
description: 'Main Entry Point',
|
|
40
|
-
prompts: [
|
|
41
|
-
{
|
|
42
|
-
type: 'autocomplete',
|
|
43
|
-
name: 'generatorType',
|
|
44
|
-
message: 'What do you want to do?',
|
|
45
|
-
source: async (answers, input) => {
|
|
46
|
-
const choices = [
|
|
47
|
-
{ name: 'Django App (Create new app)', value: 'django-app' },
|
|
48
|
-
{ name: 'Wagtail Page (Models, Templates)', value: 'wagtail-page' },
|
|
49
|
-
{ name: 'Wagtail Block (StreamField Blocks)', value: 'wagtail-block' },
|
|
50
|
-
{ name: 'Django View (CBV, FBV, Templates)', value: 'django-view' },
|
|
51
|
-
{ name: 'Django Form (ModelForm, Form)', value: 'django-form' },
|
|
52
|
-
{ name: 'Wagtail Admin (Snippets, ModelAdmin)', value: 'wagtail-admin' },
|
|
53
|
-
{ name: 'Django Channels (Consumers, Routing)', value: 'django-channel' },
|
|
54
|
-
{ name: 'AI Enhancer (Modify code with AI)', value: 'ai-enhancer' },
|
|
55
|
-
{ name: 'Help / Search Instructions', value: 'help' },
|
|
56
|
-
{ name: 'Exit', value: EXIT_VALUE }
|
|
57
|
-
];
|
|
58
|
-
return searchChoices(input, choices);
|
|
59
|
-
},
|
|
60
|
-
filter: handleInput
|
|
61
|
-
}
|
|
62
|
-
],
|
|
63
|
-
actions: (data) => {
|
|
64
|
-
if (data.generatorType === EXIT_VALUE) return [];
|
|
65
|
-
|
|
66
|
-
console.log(`\nTo use this generator, please run:\n kalo ${data.generatorType}\n`);
|
|
67
|
-
return [];
|
|
68
|
-
}
|
|
69
|
-
});
|
|
70
|
-
}
|