kalo-cli 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (56) hide show
  1. package/README.md +47 -0
  2. package/bin/kalo.ts +17 -0
  3. package/generators/ai-enhancer/index.ts +281 -0
  4. package/generators/ai-enhancer/keywords.json +1158 -0
  5. package/generators/constants.ts +52 -0
  6. package/generators/django-app/index.ts +67 -0
  7. package/generators/django-app/templates/admin.py.hbs +6 -0
  8. package/generators/django-app/templates/apps.py.hbs +9 -0
  9. package/generators/django-app/templates/init.py.hbs +0 -0
  10. package/generators/django-app/templates/models_init.py.hbs +2 -0
  11. package/generators/django-app/templates/urls.py.hbs +8 -0
  12. package/generators/django-app/templates/views.py.hbs +5 -0
  13. package/generators/django-channel/index.ts +78 -0
  14. package/generators/django-channel/templates/consumer.py.hbs +47 -0
  15. package/generators/django-channel/templates/routing.py.hbs +8 -0
  16. package/generators/django-form/index.ts +62 -0
  17. package/generators/django-form/templates/form.py.hbs +12 -0
  18. package/generators/django-form/templates/forms_file.py.hbs +6 -0
  19. package/generators/django-form/templates/model_form.py.hbs +18 -0
  20. package/generators/django-view/index.ts +95 -0
  21. package/generators/django-view/templates/view_cbv.py.hbs +11 -0
  22. package/generators/django-view/templates/view_fbv.py.hbs +7 -0
  23. package/generators/django-view/templates/view_template.html.hbs +8 -0
  24. package/generators/docs/index.ts +36 -0
  25. package/generators/help/index.ts +84 -0
  26. package/generators/main/index.ts +429 -0
  27. package/generators/utils/ai/common.ts +141 -0
  28. package/generators/utils/ai/index.ts +2 -0
  29. package/generators/utils/analysis.ts +82 -0
  30. package/generators/utils/code-manipulation.ts +119 -0
  31. package/generators/utils/filesystem.ts +64 -0
  32. package/generators/utils/index.ts +47 -0
  33. package/generators/utils/plop-actions.ts +61 -0
  34. package/generators/utils/search.ts +24 -0
  35. package/generators/wagtail-admin/index.ts +122 -0
  36. package/generators/wagtail-admin/templates/admin_view.html.hbs +21 -0
  37. package/generators/wagtail-admin/templates/admin_view.py.hbs +15 -0
  38. package/generators/wagtail-admin/templates/component.html.hbs +6 -0
  39. package/generators/wagtail-admin/templates/component.py.hbs +11 -0
  40. package/generators/wagtail-admin/templates/wagtail_hooks.py.hbs +18 -0
  41. package/generators/wagtail-block/index.ts +55 -0
  42. package/generators/wagtail-block/templates/block_class.py.hbs +13 -0
  43. package/generators/wagtail-block/templates/block_template.html.hbs +5 -0
  44. package/generators/wagtail-page/actions/model.ts +18 -0
  45. package/generators/wagtail-page/actions/orderable.ts +21 -0
  46. package/generators/wagtail-page/actions/page.ts +40 -0
  47. package/generators/wagtail-page/actions/snippet.ts +19 -0
  48. package/generators/wagtail-page/index.ts +63 -0
  49. package/generators/wagtail-page/templates/django_model.py.hbs +18 -0
  50. package/generators/wagtail-page/templates/orderable_model.py.hbs +21 -0
  51. package/generators/wagtail-page/templates/page_pair_model.py.hbs +62 -0
  52. package/generators/wagtail-page/templates/page_template.html.hbs +14 -0
  53. package/generators/wagtail-page/templates/snippet_model.py.hbs +24 -0
  54. package/package.json +47 -0
  55. package/plopfile.ts +26 -0
  56. package/tsconfig.json +29 -0
@@ -0,0 +1,19 @@
1
+ import { ActionType } from 'plop';
2
+ import { createAppendActions, ensureSuffix } from '../../utils/plop-actions';
3
+
4
+ /**
5
+ * Generates Plop actions for creating a Wagtail Snippet.
6
+ *
7
+ * @param {any} data - The prompt answers data.
8
+ * @returns {ActionType[]} An array of Plop actions to create snippet files and tests.
9
+ */
10
+ export const getSnippetActions = (data: any): ActionType[] => {
11
+ const appPath = `app/${data.app}`;
12
+
13
+ data.name = ensureSuffix(data.name, 'Snippet');
14
+
15
+ return createAppendActions({
16
+ path: `${appPath}/models/snippets.py`,
17
+ templateFile: 'generators/wagtail-page/templates/snippet_model.py.hbs'
18
+ });
19
+ };
@@ -0,0 +1,63 @@
1
+ import { PlopGeneratorConfig } from 'plop';
2
+ import { getPageActions } from './actions/page';
3
+ import { getOrderableActions } from './actions/orderable';
4
+ import { getSnippetActions } from './actions/snippet';
5
+ import { getModelActions } from './actions/model';
6
+ import { WAGTAIL_PAGE_TYPES } from '../constants';
7
+ import { searchChoices } from '../utils/search';
8
+
9
+ /**
10
+ * Generator configuration for Wagtail Page Models and related components.
11
+ * Supports creation of:
12
+ * - Page Pairs (Index + Detail)
13
+ * - Orderable Models
14
+ * - Snippets
15
+ * - Standard Django Models
16
+ * Delegates action generation to specialized action helpers.
17
+ *
18
+ * @type {PlopGeneratorConfig}
19
+ */
20
+ export const wagtailPageGenerator: PlopGeneratorConfig = {
21
+ description: 'Créer un modèle Wagtail Page (Paire Index/Detail), Orderable, ou Snippet',
22
+ prompts: [
23
+ {
24
+ type: 'autocomplete',
25
+ name: 'type',
26
+ message: 'Quel type de modèle voulez-vous créer ?',
27
+ source: (answers, input) => searchChoices(input, WAGTAIL_PAGE_TYPES),
28
+ },
29
+ {
30
+ type: 'input',
31
+ name: 'name',
32
+ message: (answers) => {
33
+ if (answers.type === 'page_pair') return 'Nom de base (ex: Blog -> BlogIndexPage, BlogPage) :';
34
+ if (answers.type === 'orderable') return 'Nom de l\'Orderable (ex: GalleryImage -> GalleryImageOrderable) :';
35
+ if (answers.type === 'snippet') return 'Nom du Snippet (ex: Category -> CategorySnippet) :';
36
+ return 'Nom du Modèle (ex: Product -> Product) :';
37
+ },
38
+ validate: (value, answers) => {
39
+ if (!value) return 'Le nom est requis';
40
+ return true;
41
+ }
42
+ },
43
+ {
44
+ type: 'input',
45
+ name: 'app',
46
+ message: 'Nom de l\'application cible',
47
+ },
48
+ ],
49
+ actions: (data) => {
50
+ switch (data.type) {
51
+ case 'page_pair':
52
+ return getPageActions(data);
53
+ case 'orderable':
54
+ return getOrderableActions(data);
55
+ case 'snippet':
56
+ return getSnippetActions(data);
57
+ case 'model':
58
+ return getModelActions(data);
59
+ default:
60
+ return [];
61
+ }
62
+ },
63
+ };
@@ -0,0 +1,18 @@
1
+
2
+ class {{pascalCase name}}(models.Model):
3
+ """
4
+ {{pascalCase name}} standard Django model.
5
+ """
6
+
7
+ # <!-- CLASS = {{pascalCase name}} END AI_GENERATED_DJANGO_MODEL -->
8
+ # <!-- CLASS = {{pascalCase name}} START AI_GENERATED_DJANGO_MODEL -->
9
+
10
+ # Database fields
11
+ name = models.CharField(max_length=255)
12
+
13
+ class Meta:
14
+ verbose_name = "{{titleCase name}}"
15
+ verbose_name_plural = "{{titleCase name}}s"
16
+
17
+ def __str__(self):
18
+ return self.name
@@ -0,0 +1,21 @@
1
+
2
+ class {{pascalCase name}}(Orderable):
3
+ """
4
+ {{pascalCase name}} orderable model.
5
+ """
6
+ # page = ParentalKey('app_label.PageModel', related_name='related_items', on_delete=models.CASCADE)
7
+
8
+ # <!-- CLASS = {{pascalCase name}} START AI_GENERATED_ORDERABLE_MODEL -->
9
+ # <!-- CLASS = {{pascalCase name}} END AI_GENERATED_ORDERABLE_MODEL -->
10
+
11
+ # Database fields
12
+ sort_order = models.IntegerField(null=True, blank=True, editable=False)
13
+ # Add your fields here
14
+
15
+ panels = [
16
+ # FieldPanel('field_name'),
17
+ ]
18
+
19
+ class Meta:
20
+ verbose_name = "{{titleCase name}}"
21
+ verbose_name_plural = "{{titleCase name}}s"
@@ -0,0 +1,62 @@
1
+
2
+ class {{pascalCase baseName}}IndexPage(Page):
3
+ """
4
+ Index page for {{pascalCase baseName}}.
5
+ """
6
+
7
+ # Parent page / subpage type rules
8
+ subpage_types = ['{{pascalCase baseName}}Page']
9
+
10
+ # Database fields
11
+ intro = models.CharField(max_length=250, blank=True)
12
+ body = RichTextField(blank=True)
13
+
14
+ # Editor panels configuration
15
+ content_panels = Page.content_panels + [
16
+ FieldPanel('intro'),
17
+ FieldPanel('body'),
18
+ ]
19
+
20
+ # <!-- CLASS = {{pascalCase baseName}}IndexPage START AI_GENERATED_PAGE_INDEX -->
21
+ # <!-- CLASS = {{pascalCase baseName}}IndexPage END AI_GENERATED_PAGE_INDEX -->
22
+
23
+ # Search index configuration
24
+ search_fields = Page.search_fields + [
25
+ index.SearchField('intro'),
26
+ index.SearchField('body'),
27
+ ]
28
+
29
+ class Meta:
30
+ verbose_name = "{{titleCase baseName}} Index"
31
+
32
+
33
+ class {{pascalCase baseName}}Page(Page):
34
+ """
35
+ Detail page for {{pascalCase baseName}}.
36
+ """
37
+
38
+ # Parent page / subpage type rules
39
+ parent_page_types = ['{{pascalCase baseName}}IndexPage']
40
+
41
+ # Database fields
42
+ intro = models.CharField(max_length=250, blank=True)
43
+ body = RichTextField(blank=True)
44
+
45
+ # Editor panels configuration
46
+ content_panels = Page.content_panels + [
47
+ FieldPanel('intro'),
48
+ FieldPanel('body'),
49
+ ]
50
+
51
+ # <!-- CLASS = {{pascalCase baseName}}Page START AI_GENERATED_PAGE -->
52
+ # <!-- CLASS = {{pascalCase baseName}}Page END AI_GENERATED_PAGE -->
53
+
54
+
55
+ # Search index configuration
56
+ search_fields = Page.search_fields + [
57
+ index.SearchField('intro'),
58
+ index.SearchField('body'),
59
+ ]
60
+
61
+ class Meta:
62
+ verbose_name = "{{titleCase baseName}}"
@@ -0,0 +1,14 @@
1
+
2
+ {% extends "base.html" %}
3
+ {% load wagtailcore_tags %}
4
+
5
+ {% block content %}
6
+ <h1>\{{ page.title }}</h1>
7
+
8
+ <div class="intro">\{{ page.intro|richtext }}</div>
9
+
10
+ \{{ page.body|richtext }}
11
+ {% endblock %}
12
+
13
+ <!-- CLASS = {{pascalCase name}} START AI_GENERATED_PAGE_TEMPLATE -->
14
+ <!-- CLASS = {{pascalCase name}} END AI_GENERATED_PAGE_TEMPLATE -->
@@ -0,0 +1,24 @@
1
+
2
+ @register_snippet
3
+ class {{pascalCase name}}(models.Model):
4
+
5
+ """
6
+ {{pascalCase name}} snippet.
7
+ """
8
+ text = models.CharField(max_length=255)
9
+
10
+ panels = [
11
+ FieldPanel('text'),
12
+ ]
13
+ # <!-- CLASS = {{pascalCase name}} START AI_GENERATED_SNIPPET -->
14
+ # <!-- CLASS = {{pascalCase name}} END AI_GENERATED_SNIPPET -->
15
+
16
+ def __str__(self):
17
+ return self.text
18
+
19
+ def save(self, *args, **kwargs):
20
+ super().save(*args, **kwargs)
21
+
22
+ class Meta:
23
+ verbose_name = "{{sentenceCase name}}"
24
+ verbose_name_plural = "{{sentenceCase name}}s"
package/package.json ADDED
@@ -0,0 +1,47 @@
1
+ {
2
+ "name": "kalo-cli",
3
+ "version": "0.1.0",
4
+ "description": "Générateur de code structuré et uniforme pour Django et Wagtail",
5
+ "bin": {
6
+ "kalo": "./bin/kalo.ts"
7
+ },
8
+ "type": "module",
9
+ "scripts": {
10
+ "kalo": "bun bin/kalo.ts",
11
+ "doc": "bun run --port 3333 docs-site/index.html"
12
+ },
13
+ "keywords": [
14
+ "django",
15
+ "wagtail",
16
+ "generator",
17
+ "plop",
18
+ "cli",
19
+ "bun"
20
+ ],
21
+ "files": [
22
+ "bin",
23
+ "generators",
24
+ "utils",
25
+ "plopfile.ts",
26
+ "tsconfig.json"
27
+ ],
28
+ "devDependencies": {
29
+ "@types/bun": "latest"
30
+ },
31
+ "peerDependencies": {
32
+ "typescript": "^5"
33
+ },
34
+ "dependencies": {
35
+ "@types/react": "^19.2.9",
36
+ "@types/react-dom": "^19.2.3",
37
+ "@types/react-syntax-highlighter": "^15.5.13",
38
+ "inquirer-autocomplete-prompt": "^3.0.1",
39
+ "minimist": "^1.2.8",
40
+ "plop": "^4.0.5",
41
+ "react": "^19.2.3",
42
+ "react-dom": "^19.2.3",
43
+ "react-syntax-highlighter": "^16.1.0",
44
+ "serve": "^14.2.5",
45
+ "tsx": "^4.21.0"
46
+ }
47
+ }
package/plopfile.ts ADDED
@@ -0,0 +1,26 @@
1
+ import { NodePlopAPI } from 'plop';
2
+ import autocompletePrompt from 'inquirer-autocomplete-prompt';
3
+ import registerGenerators from './generators/main';
4
+
5
+ /**
6
+ * Primary Plopfile entry point.
7
+ * Registers all generators and helpers.
8
+ *
9
+ * @param {NodePlopAPI} plop - The Plop API instance.
10
+ */
11
+ export default function (plop: NodePlopAPI) {
12
+ // Register Prompts
13
+ plop.setPrompt('autocomplete', autocompletePrompt);
14
+
15
+ // Global Helpers
16
+ plop.setHelper('upperCase', (txt) => txt.toUpperCase());
17
+ plop.setHelper('snakeCase', (txt) => {
18
+ return txt && txt.match(/[A-Z]{2,}(?=[A-Z][a-z]+[0-9]*|\b)|[A-Z]?[a-z]+[0-9]*|[A-Z]|[0-9]+/g)
19
+ ?.map(x => x.toLowerCase())
20
+ .join('_');
21
+ });
22
+
23
+ // --- Register Generators ---
24
+ // The 'main' generator module now handles registering 'main' and 'help' generators.
25
+ registerGenerators(plop);
26
+ }
package/tsconfig.json ADDED
@@ -0,0 +1,29 @@
1
+ {
2
+ "compilerOptions": {
3
+ // Environment setup & latest features
4
+ "lib": ["ESNext"],
5
+ "target": "ESNext",
6
+ "module": "Preserve",
7
+ "moduleDetection": "force",
8
+ "jsx": "react-jsx",
9
+ "allowJs": true,
10
+
11
+ // Bundler mode
12
+ "moduleResolution": "bundler",
13
+ "allowImportingTsExtensions": true,
14
+ "verbatimModuleSyntax": true,
15
+ "noEmit": true,
16
+
17
+ // Best practices
18
+ "strict": true,
19
+ "skipLibCheck": true,
20
+ "noFallthroughCasesInSwitch": true,
21
+ "noUncheckedIndexedAccess": true,
22
+ "noImplicitOverride": true,
23
+
24
+ // Some stricter flags (disabled by default)
25
+ "noUnusedLocals": false,
26
+ "noUnusedParameters": false,
27
+ "noPropertyAccessFromIndexSignature": false
28
+ }
29
+ }