@nextsparkjs/ai-workflow 0.1.0-beta.100
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/LICENSE +21 -0
- package/README.md +115 -0
- package/claude/_docs/workflows-optimizations.md +359 -0
- package/claude/agents/api-tester.md +634 -0
- package/claude/agents/architecture-supervisor.md +1351 -0
- package/claude/agents/backend-developer.md +997 -0
- package/claude/agents/backend-validator.md +417 -0
- package/claude/agents/bdd-docs-writer.md +737 -0
- package/claude/agents/block-developer.md +677 -0
- package/claude/agents/code-reviewer.md +1432 -0
- package/claude/agents/db-developer.md +721 -0
- package/claude/agents/db-validator.md +407 -0
- package/claude/agents/demo-video-generator.md +493 -0
- package/claude/agents/documentation-writer.md +1268 -0
- package/claude/agents/frontend-developer.md +1234 -0
- package/claude/agents/frontend-validator.md +777 -0
- package/claude/agents/functional-validator.md +630 -0
- package/claude/agents/mock-analyst.md +387 -0
- package/claude/agents/product-manager.md +963 -0
- package/claude/agents/qa-automation.md +1762 -0
- package/claude/agents/release-manager.md +634 -0
- package/claude/agents/selectors-translator.md +262 -0
- package/claude/agents/unit-test-writer.md +785 -0
- package/claude/agents/visual-comparator.md +329 -0
- package/claude/agents/workflow-maintainer.md +352 -0
- package/claude/commands/do/README.md +88 -0
- package/claude/commands/do/create-api.md +64 -0
- package/claude/commands/do/create-entity.md +66 -0
- package/claude/commands/do/create-migration.md +64 -0
- package/claude/commands/do/create-plugin.md +56 -0
- package/claude/commands/do/create-theme.md +70 -0
- package/claude/commands/do/mock-data.md +67 -0
- package/claude/commands/do/reset-db.md +71 -0
- package/claude/commands/do/setup-scheduled-action.md +75 -0
- package/claude/commands/do/sync-code-review.md +117 -0
- package/claude/commands/do/update-selectors.md +112 -0
- package/claude/commands/do/use-skills.md +90 -0
- package/claude/commands/do/validate-blocks.md +69 -0
- package/claude/commands/how-to/README.md +261 -0
- package/claude/commands/how-to/add-metadata.md +692 -0
- package/claude/commands/how-to/add-taxonomies.md +806 -0
- package/claude/commands/how-to/add-translations.md +571 -0
- package/claude/commands/how-to/create-api.md +577 -0
- package/claude/commands/how-to/create-block.md +575 -0
- package/claude/commands/how-to/create-child-entities.md +771 -0
- package/claude/commands/how-to/create-entity.md +597 -0
- package/claude/commands/how-to/create-migrations.md +605 -0
- package/claude/commands/how-to/create-plugin.md +654 -0
- package/claude/commands/how-to/customize-app.md +481 -0
- package/claude/commands/how-to/customize-dashboard.md +553 -0
- package/claude/commands/how-to/customize-theme.md +438 -0
- package/claude/commands/how-to/define-features-flows.md +632 -0
- package/claude/commands/how-to/deploy.md +507 -0
- package/claude/commands/how-to/handle-file-uploads.md +746 -0
- package/claude/commands/how-to/implement-search.md +1001 -0
- package/claude/commands/how-to/install-plugins.md +352 -0
- package/claude/commands/how-to/manage-test-coverage.md +984 -0
- package/claude/commands/how-to/run-tests.md +400 -0
- package/claude/commands/how-to/set-app-languages.md +601 -0
- package/claude/commands/how-to/set-plans-and-permissions.md +575 -0
- package/claude/commands/how-to/set-scheduled-actions.md +527 -0
- package/claude/commands/how-to/set-user-roles-and-permissions.md +550 -0
- package/claude/commands/how-to/setup-authentication.md +388 -0
- package/claude/commands/how-to/setup-claude-code.md +440 -0
- package/claude/commands/how-to/setup-database.md +274 -0
- package/claude/commands/how-to/setup-email-providers.md +598 -0
- package/claude/commands/how-to/setup-mobile-dev.md +627 -0
- package/claude/commands/how-to/start.md +500 -0
- package/claude/commands/how-to/use-devtools.md +639 -0
- package/claude/commands/how-to/use-superadmin.md +622 -0
- package/claude/commands/session/README.md +193 -0
- package/claude/commands/session/block-create.md +190 -0
- package/claude/commands/session/block-list.md +203 -0
- package/claude/commands/session/block-update.md +192 -0
- package/claude/commands/session/block-validate.md +218 -0
- package/claude/commands/session/changelog.md +115 -0
- package/claude/commands/session/close.md +225 -0
- package/claude/commands/session/commit.md +174 -0
- package/claude/commands/session/db-entity.md +206 -0
- package/claude/commands/session/db-fix.md +212 -0
- package/claude/commands/session/db-sample.md +206 -0
- package/claude/commands/session/demo.md +178 -0
- package/claude/commands/session/doc-bdd.md +207 -0
- package/claude/commands/session/doc-feature.md +218 -0
- package/claude/commands/session/doc-read.md +225 -0
- package/claude/commands/session/execute.md +204 -0
- package/claude/commands/session/explain.md +202 -0
- package/claude/commands/session/fix-bug.md +210 -0
- package/claude/commands/session/fix-build.md +182 -0
- package/claude/commands/session/fix-test.md +189 -0
- package/claude/commands/session/pending.md +232 -0
- package/claude/commands/session/refine.md +188 -0
- package/claude/commands/session/resume.md +192 -0
- package/claude/commands/session/review.md +192 -0
- package/claude/commands/session/scope-change.md +181 -0
- package/claude/commands/session/start-blocks.md +347 -0
- package/claude/commands/session/start.md +604 -0
- package/claude/commands/session/status.md +169 -0
- package/claude/commands/session/test-fix.md +221 -0
- package/claude/commands/session/test-run.md +203 -0
- package/claude/commands/session/test-write.md +242 -0
- package/claude/commands/session/validate.md +162 -0
- package/claude/config/context.json +40 -0
- package/claude/config/github.json +69 -0
- package/claude/config/github.schema.json +106 -0
- package/claude/config/team.json +46 -0
- package/claude/config/team.schema.json +106 -0
- package/claude/config/workspace.json +43 -0
- package/claude/config/workspace.schema.json +75 -0
- package/claude/skills/README.md +228 -0
- package/claude/skills/accessibility/SKILL.md +573 -0
- package/claude/skills/api-bypass-layers/SKILL.md +550 -0
- package/claude/skills/asana-integration/SKILL.md +499 -0
- package/claude/skills/better-auth/SKILL.md +666 -0
- package/claude/skills/billing-subscriptions/SKILL.md +660 -0
- package/claude/skills/block-decision-matrix/SKILL.md +359 -0
- package/claude/skills/clickup-integration/SKILL.md +434 -0
- package/claude/skills/core-theme-responsibilities/SKILL.md +485 -0
- package/claude/skills/create-plugin/SKILL.md +425 -0
- package/claude/skills/create-theme/SKILL.md +331 -0
- package/claude/skills/cypress-api/SKILL.md +511 -0
- package/claude/skills/cypress-api/scripts/generate-api-controller.py +329 -0
- package/claude/skills/cypress-api/scripts/generate-api-test.py +930 -0
- package/claude/skills/cypress-e2e/SKILL.md +526 -0
- package/claude/skills/cypress-e2e/scripts/extract-selectors.py +383 -0
- package/claude/skills/cypress-e2e/scripts/generate-uat-test.py +788 -0
- package/claude/skills/cypress-selectors/SKILL.md +309 -0
- package/claude/skills/cypress-selectors/scripts/extract-missing.py +243 -0
- package/claude/skills/cypress-selectors/scripts/generate-block-selectors.py +283 -0
- package/claude/skills/cypress-selectors/scripts/validate-selectors.py +145 -0
- package/claude/skills/database-migrations/SKILL.md +335 -0
- package/claude/skills/database-migrations/scripts/generate-sample-data.py +284 -0
- package/claude/skills/database-migrations/scripts/validate-migration.py +323 -0
- package/claude/skills/design-system/SKILL.md +682 -0
- package/claude/skills/documentation/SKILL.md +540 -0
- package/claude/skills/entity-api/SKILL.md +482 -0
- package/claude/skills/entity-system/SKILL.md +635 -0
- package/claude/skills/entity-system/scripts/generate-child-migration.py +298 -0
- package/claude/skills/entity-system/scripts/generate-metas-migration.py +233 -0
- package/claude/skills/entity-system/scripts/generate-migration.py +382 -0
- package/claude/skills/entity-system/scripts/generate-sample-data.py +418 -0
- package/claude/skills/entity-system/scripts/scaffold-entity.py +661 -0
- package/claude/skills/github/SKILL.md +467 -0
- package/claude/skills/i18n-nextintl/SKILL.md +302 -0
- package/claude/skills/i18n-nextintl/scripts/add-translation.py +243 -0
- package/claude/skills/i18n-nextintl/scripts/extract-hardcoded.py +246 -0
- package/claude/skills/i18n-nextintl/scripts/validate-translations.py +260 -0
- package/claude/skills/impact-analysis/SKILL.md +203 -0
- package/claude/skills/jest-unit/SKILL.md +306 -0
- package/claude/skills/jest-unit/references/component-testing.md +371 -0
- package/claude/skills/jest-unit/references/mocking-patterns.md +380 -0
- package/claude/skills/jest-unit/references/service-hook-testing.md +454 -0
- package/claude/skills/jira-integration/SKILL.md +539 -0
- package/claude/skills/media-library/SKILL.md +743 -0
- package/claude/skills/mock-analysis/SKILL.md +276 -0
- package/claude/skills/monorepo-architecture/SKILL.md +162 -0
- package/claude/skills/nextjs-api-development/SKILL.md +364 -0
- package/claude/skills/nextjs-api-development/scripts/generate-crud-tests.py +456 -0
- package/claude/skills/nextjs-api-development/scripts/scaffold-endpoint.py +481 -0
- package/claude/skills/nextjs-api-development/scripts/validate-api.py +283 -0
- package/claude/skills/notion-integration/SKILL.md +641 -0
- package/claude/skills/npm-development-workflow/SKILL.md +480 -0
- package/claude/skills/page-builder-blocks/SKILL.md +530 -0
- package/claude/skills/page-builder-blocks/scripts/scaffold-block.py +444 -0
- package/claude/skills/permissions-system/SKILL.md +619 -0
- package/claude/skills/plugins/SKILL.md +340 -0
- package/claude/skills/plugins/references/plugin-templates.md +414 -0
- package/claude/skills/plugins/references/plugin-testing.md +353 -0
- package/claude/skills/plugins/references/plugin-types.md +198 -0
- package/claude/skills/plugins/scripts/scaffold-plugin.py +443 -0
- package/claude/skills/pom-patterns/SKILL.md +452 -0
- package/claude/skills/pom-patterns/scripts/generate-pom.py +392 -0
- package/claude/skills/rate-limiting/SKILL.md +342 -0
- package/claude/skills/react-best-practices/AGENTS.md +2410 -0
- package/claude/skills/react-best-practices/README.md +123 -0
- package/claude/skills/react-best-practices/SKILL.md +125 -0
- package/claude/skills/react-best-practices/metadata.json +15 -0
- package/claude/skills/react-best-practices/rules/_sections.md +46 -0
- package/claude/skills/react-best-practices/rules/_template.md +28 -0
- package/claude/skills/react-best-practices/rules/advanced-event-handler-refs.md +55 -0
- package/claude/skills/react-best-practices/rules/advanced-use-latest.md +49 -0
- package/claude/skills/react-best-practices/rules/async-api-routes.md +38 -0
- package/claude/skills/react-best-practices/rules/async-defer-await.md +80 -0
- package/claude/skills/react-best-practices/rules/async-dependencies.md +36 -0
- package/claude/skills/react-best-practices/rules/async-parallel.md +28 -0
- package/claude/skills/react-best-practices/rules/async-suspense-boundaries.md +99 -0
- package/claude/skills/react-best-practices/rules/bundle-barrel-imports.md +59 -0
- package/claude/skills/react-best-practices/rules/bundle-conditional.md +31 -0
- package/claude/skills/react-best-practices/rules/bundle-defer-third-party.md +49 -0
- package/claude/skills/react-best-practices/rules/bundle-dynamic-imports.md +35 -0
- package/claude/skills/react-best-practices/rules/bundle-preload.md +50 -0
- package/claude/skills/react-best-practices/rules/client-event-listeners.md +74 -0
- package/claude/skills/react-best-practices/rules/client-localstorage-schema.md +71 -0
- package/claude/skills/react-best-practices/rules/client-passive-event-listeners.md +48 -0
- package/claude/skills/react-best-practices/rules/client-swr-dedup.md +56 -0
- package/claude/skills/react-best-practices/rules/js-batch-dom-css.md +82 -0
- package/claude/skills/react-best-practices/rules/js-cache-function-results.md +80 -0
- package/claude/skills/react-best-practices/rules/js-cache-property-access.md +28 -0
- package/claude/skills/react-best-practices/rules/js-cache-storage.md +70 -0
- package/claude/skills/react-best-practices/rules/js-combine-iterations.md +32 -0
- package/claude/skills/react-best-practices/rules/js-early-exit.md +50 -0
- package/claude/skills/react-best-practices/rules/js-hoist-regexp.md +45 -0
- package/claude/skills/react-best-practices/rules/js-index-maps.md +37 -0
- package/claude/skills/react-best-practices/rules/js-length-check-first.md +49 -0
- package/claude/skills/react-best-practices/rules/js-min-max-loop.md +82 -0
- package/claude/skills/react-best-practices/rules/js-set-map-lookups.md +24 -0
- package/claude/skills/react-best-practices/rules/js-tosorted-immutable.md +57 -0
- package/claude/skills/react-best-practices/rules/rendering-activity.md +26 -0
- package/claude/skills/react-best-practices/rules/rendering-animate-svg-wrapper.md +47 -0
- package/claude/skills/react-best-practices/rules/rendering-conditional-render.md +40 -0
- package/claude/skills/react-best-practices/rules/rendering-content-visibility.md +38 -0
- package/claude/skills/react-best-practices/rules/rendering-hoist-jsx.md +46 -0
- package/claude/skills/react-best-practices/rules/rendering-hydration-no-flicker.md +82 -0
- package/claude/skills/react-best-practices/rules/rendering-svg-precision.md +28 -0
- package/claude/skills/react-best-practices/rules/rerender-defer-reads.md +39 -0
- package/claude/skills/react-best-practices/rules/rerender-dependencies.md +45 -0
- package/claude/skills/react-best-practices/rules/rerender-derived-state.md +29 -0
- package/claude/skills/react-best-practices/rules/rerender-functional-setstate.md +74 -0
- package/claude/skills/react-best-practices/rules/rerender-lazy-state-init.md +58 -0
- package/claude/skills/react-best-practices/rules/rerender-memo.md +44 -0
- package/claude/skills/react-best-practices/rules/rerender-transitions.md +40 -0
- package/claude/skills/react-best-practices/rules/server-after-nonblocking.md +73 -0
- package/claude/skills/react-best-practices/rules/server-cache-lru.md +41 -0
- package/claude/skills/react-best-practices/rules/server-cache-react.md +76 -0
- package/claude/skills/react-best-practices/rules/server-parallel-fetching.md +83 -0
- package/claude/skills/react-best-practices/rules/server-serialization.md +38 -0
- package/claude/skills/react-patterns/SKILL.md +688 -0
- package/claude/skills/registry-system/SKILL.md +331 -0
- package/claude/skills/scheduled-actions/SKILL.md +671 -0
- package/claude/skills/scope-enforcement/SKILL.md +542 -0
- package/claude/skills/scope-enforcement/scripts/validate-scope.py +357 -0
- package/claude/skills/server-actions/SKILL.md +493 -0
- package/claude/skills/service-layer/SKILL.md +587 -0
- package/claude/skills/session-management/SKILL.md +266 -0
- package/claude/skills/session-management/scripts/create-session.py +166 -0
- package/claude/skills/session-management/scripts/iteration-close.sh +105 -0
- package/claude/skills/session-management/scripts/iteration-init.sh +180 -0
- package/claude/skills/session-management/scripts/session-archive.sh +87 -0
- package/claude/skills/session-management/scripts/session-close.sh +133 -0
- package/claude/skills/session-management/scripts/session-init.sh +225 -0
- package/claude/skills/session-management/scripts/session-list.sh +163 -0
- package/claude/skills/session-management/scripts/split-plan.sh +116 -0
- package/claude/skills/shadcn-components/SKILL.md +586 -0
- package/claude/skills/shadcn-theming/SKILL.md +446 -0
- package/claude/skills/suspense-loading/SKILL.md +280 -0
- package/claude/skills/tailwind-theming/SKILL.md +507 -0
- package/claude/skills/tanstack-query/SKILL.md +608 -0
- package/claude/skills/test-coverage/SKILL.md +239 -0
- package/claude/skills/web-design-guidelines/SKILL.md +39 -0
- package/claude/skills/zod-validation/SKILL.md +537 -0
- package/claude/templates/blocks/progress.md +86 -0
- package/claude/templates/iteration/changes.md +61 -0
- package/claude/templates/iteration/progress.md +55 -0
- package/claude/templates/log.md +31 -0
- package/claude/templates/story/context.md +77 -0
- package/claude/templates/story/pendings.md +37 -0
- package/claude/templates/story/plan.md +299 -0
- package/claude/templates/story/requirements.md +109 -0
- package/claude/templates/story/scope.json +10 -0
- package/claude/templates/story/tests.md +91 -0
- package/claude/templates/task/progress.md +58 -0
- package/claude/templates/task/requirements.md +54 -0
- package/claude/workflows/README.md +154 -0
- package/claude/workflows/blocks.md +614 -0
- package/claude/workflows/story.md +1207 -0
- package/claude/workflows/task.md +927 -0
- package/claude/workflows/tweak.md +527 -0
- package/cursor/.gitkeep +0 -0
- package/package.json +35 -0
- package/scripts/postinstall.mjs +198 -0
- package/scripts/setup.mjs +282 -0
- package/scripts/sync.mjs +209 -0
|
@@ -0,0 +1,418 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""
|
|
3
|
+
Generate Sample Data Script
|
|
4
|
+
|
|
5
|
+
Generates coherent sample data for an entity based on its field configuration.
|
|
6
|
+
|
|
7
|
+
Usage:
|
|
8
|
+
python generate-sample-data.py --entity ENTITY_NAME [--theme THEME] [--count COUNT]
|
|
9
|
+
|
|
10
|
+
Options:
|
|
11
|
+
--entity ENTITY_NAME Name of the entity (kebab-case)
|
|
12
|
+
--theme THEME Theme name (default: from NEXT_PUBLIC_ACTIVE_THEME or 'default')
|
|
13
|
+
--count COUNT Number of records to generate (default: 10)
|
|
14
|
+
--output OUTPUT Output file (default: migrations/sample_data.json)
|
|
15
|
+
--format FORMAT Output format: json, sql, csv (default: json)
|
|
16
|
+
"""
|
|
17
|
+
|
|
18
|
+
import os
|
|
19
|
+
import sys
|
|
20
|
+
import argparse
|
|
21
|
+
import json
|
|
22
|
+
import re
|
|
23
|
+
import random
|
|
24
|
+
import uuid
|
|
25
|
+
from pathlib import Path
|
|
26
|
+
from datetime import datetime, timedelta
|
|
27
|
+
from typing import Dict, List, Any, Optional
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
def get_active_theme() -> str:
|
|
31
|
+
"""Get active theme from environment or default."""
|
|
32
|
+
return os.environ.get('NEXT_PUBLIC_ACTIVE_THEME', 'default')
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
def to_snake_case(name: str) -> str:
|
|
36
|
+
"""Convert kebab-case to snake_case."""
|
|
37
|
+
return name.replace('-', '_')
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
def to_camel_case(name: str) -> str:
|
|
41
|
+
"""Convert kebab-case to camelCase."""
|
|
42
|
+
components = name.split('-')
|
|
43
|
+
return components[0] + ''.join(x.title() for x in components[1:])
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
# Sample data generators
|
|
47
|
+
SAMPLE_TITLES = [
|
|
48
|
+
"Important Project",
|
|
49
|
+
"Client Meeting Notes",
|
|
50
|
+
"Quarterly Review",
|
|
51
|
+
"Budget Analysis",
|
|
52
|
+
"Marketing Campaign",
|
|
53
|
+
"Product Launch",
|
|
54
|
+
"Team Building Event",
|
|
55
|
+
"Research Report",
|
|
56
|
+
"Strategic Planning",
|
|
57
|
+
"Customer Feedback",
|
|
58
|
+
"Sales Pipeline",
|
|
59
|
+
"Development Sprint",
|
|
60
|
+
"Quality Assurance",
|
|
61
|
+
"Documentation Update",
|
|
62
|
+
"Training Session",
|
|
63
|
+
]
|
|
64
|
+
|
|
65
|
+
SAMPLE_DESCRIPTIONS = [
|
|
66
|
+
"This is a detailed description of the item with important information.",
|
|
67
|
+
"Contains key insights and analysis for stakeholders.",
|
|
68
|
+
"Requires immediate attention and follow-up actions.",
|
|
69
|
+
"Comprehensive overview of the current situation.",
|
|
70
|
+
"Summary of findings from the recent investigation.",
|
|
71
|
+
"Action items and next steps outlined here.",
|
|
72
|
+
"Overview of progress made and remaining tasks.",
|
|
73
|
+
"Key deliverables and milestones listed.",
|
|
74
|
+
"Critical information for decision making.",
|
|
75
|
+
"Background context and historical data included.",
|
|
76
|
+
]
|
|
77
|
+
|
|
78
|
+
SAMPLE_TAGS = [
|
|
79
|
+
"urgent", "important", "review", "pending", "completed",
|
|
80
|
+
"high-priority", "low-priority", "in-progress", "blocked",
|
|
81
|
+
"client", "internal", "external", "documentation", "feature",
|
|
82
|
+
"bug", "enhancement", "research", "planning", "marketing"
|
|
83
|
+
]
|
|
84
|
+
|
|
85
|
+
|
|
86
|
+
def parse_fields_file(fields_path: Path) -> List[Dict]:
|
|
87
|
+
"""Parse TypeScript fields file to extract field definitions."""
|
|
88
|
+
fields = []
|
|
89
|
+
|
|
90
|
+
if not fields_path.exists():
|
|
91
|
+
print(f"Warning: Fields file not found: {fields_path}")
|
|
92
|
+
return fields
|
|
93
|
+
|
|
94
|
+
with open(fields_path, 'r', encoding='utf-8') as f:
|
|
95
|
+
content = f.read()
|
|
96
|
+
|
|
97
|
+
# Find field blocks
|
|
98
|
+
field_pattern = re.compile(
|
|
99
|
+
r'\{[^}]*name:\s*[\'"](\w+)[\'"][^}]*type:\s*[\'"](\w+(?:-\w+)?)[\'"][^}]*\}',
|
|
100
|
+
re.DOTALL
|
|
101
|
+
)
|
|
102
|
+
|
|
103
|
+
for match in field_pattern.finditer(content):
|
|
104
|
+
name = match.group(1)
|
|
105
|
+
field_type = match.group(2)
|
|
106
|
+
|
|
107
|
+
# Skip system fields
|
|
108
|
+
if name in ['id', 'createdAt', 'updatedAt', 'created_at', 'updated_at', 'userId', 'user_id']:
|
|
109
|
+
continue
|
|
110
|
+
|
|
111
|
+
field_def = {
|
|
112
|
+
'name': name,
|
|
113
|
+
'type': field_type,
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
# Extract default value
|
|
117
|
+
default_pattern = re.compile(
|
|
118
|
+
rf'name:\s*[\'"]{name}[\'"][^}}]*defaultValue:\s*[\'"]?(\w+)[\'"]?',
|
|
119
|
+
re.DOTALL
|
|
120
|
+
)
|
|
121
|
+
default_match = default_pattern.search(content)
|
|
122
|
+
if default_match:
|
|
123
|
+
field_def['defaultValue'] = default_match.group(1)
|
|
124
|
+
|
|
125
|
+
# Extract options for select fields
|
|
126
|
+
if field_type == 'select':
|
|
127
|
+
options_pattern = re.compile(
|
|
128
|
+
rf'name:\s*[\'"]{name}[\'"][^}}]*options:\s*\[(.*?)\]',
|
|
129
|
+
re.DOTALL
|
|
130
|
+
)
|
|
131
|
+
options_match = options_pattern.search(content)
|
|
132
|
+
if options_match:
|
|
133
|
+
options_str = options_match.group(1)
|
|
134
|
+
values = re.findall(r'value:\s*[\'"](\w+(?:-\w+)?)[\'"]', options_str)
|
|
135
|
+
field_def['options'] = values
|
|
136
|
+
|
|
137
|
+
fields.append(field_def)
|
|
138
|
+
|
|
139
|
+
return fields
|
|
140
|
+
|
|
141
|
+
|
|
142
|
+
def generate_value(field: Dict, index: int) -> Any:
|
|
143
|
+
"""Generate a sample value for a field."""
|
|
144
|
+
field_type = field['type']
|
|
145
|
+
name = field['name'].lower()
|
|
146
|
+
|
|
147
|
+
# Title-like fields
|
|
148
|
+
if name in ['title', 'name', 'subject']:
|
|
149
|
+
base = random.choice(SAMPLE_TITLES)
|
|
150
|
+
return f"{base} #{index + 1}"
|
|
151
|
+
|
|
152
|
+
# Description-like fields
|
|
153
|
+
if name in ['description', 'content', 'body', 'notes', 'summary']:
|
|
154
|
+
return random.choice(SAMPLE_DESCRIPTIONS)
|
|
155
|
+
|
|
156
|
+
# Select fields
|
|
157
|
+
if field_type == 'select' and 'options' in field:
|
|
158
|
+
return random.choice(field['options'])
|
|
159
|
+
|
|
160
|
+
# Type-based generation
|
|
161
|
+
if field_type == 'text':
|
|
162
|
+
return f"Sample text value {index + 1}"
|
|
163
|
+
|
|
164
|
+
elif field_type == 'textarea':
|
|
165
|
+
return random.choice(SAMPLE_DESCRIPTIONS)
|
|
166
|
+
|
|
167
|
+
elif field_type == 'number':
|
|
168
|
+
return round(random.uniform(1, 100), 2)
|
|
169
|
+
|
|
170
|
+
elif field_type == 'boolean':
|
|
171
|
+
return random.choice([True, False])
|
|
172
|
+
|
|
173
|
+
elif field_type == 'date':
|
|
174
|
+
days_offset = random.randint(-30, 30)
|
|
175
|
+
date = datetime.now() + timedelta(days=days_offset)
|
|
176
|
+
return date.strftime('%Y-%m-%d')
|
|
177
|
+
|
|
178
|
+
elif field_type == 'datetime':
|
|
179
|
+
days_offset = random.randint(-30, 30)
|
|
180
|
+
hours_offset = random.randint(0, 23)
|
|
181
|
+
date = datetime.now() + timedelta(days=days_offset, hours=hours_offset)
|
|
182
|
+
return date.isoformat()
|
|
183
|
+
|
|
184
|
+
elif field_type == 'email':
|
|
185
|
+
return f"user{index + 1}@example.com"
|
|
186
|
+
|
|
187
|
+
elif field_type == 'url':
|
|
188
|
+
return f"https://example.com/resource/{index + 1}"
|
|
189
|
+
|
|
190
|
+
elif field_type == 'tags':
|
|
191
|
+
num_tags = random.randint(1, 4)
|
|
192
|
+
return random.sample(SAMPLE_TAGS, num_tags)
|
|
193
|
+
|
|
194
|
+
elif field_type == 'multiselect' and 'options' in field:
|
|
195
|
+
num_selections = random.randint(1, min(3, len(field['options'])))
|
|
196
|
+
return random.sample(field['options'], num_selections)
|
|
197
|
+
|
|
198
|
+
elif field_type == 'phone':
|
|
199
|
+
return f"+1-555-{random.randint(100, 999)}-{random.randint(1000, 9999)}"
|
|
200
|
+
|
|
201
|
+
elif field_type == 'rating':
|
|
202
|
+
return random.randint(1, 5)
|
|
203
|
+
|
|
204
|
+
elif field_type == 'range':
|
|
205
|
+
return round(random.uniform(0, 100), 1)
|
|
206
|
+
|
|
207
|
+
elif field_type == 'json':
|
|
208
|
+
return {"key": f"value_{index}", "nested": {"count": index}}
|
|
209
|
+
|
|
210
|
+
elif field_type in ['relation', 'reference', 'user']:
|
|
211
|
+
return str(uuid.uuid4())
|
|
212
|
+
|
|
213
|
+
elif field_type in ['file', 'image', 'video', 'audio']:
|
|
214
|
+
return {
|
|
215
|
+
"url": f"https://storage.example.com/{field_type}/{index + 1}",
|
|
216
|
+
"name": f"sample_{field_type}_{index + 1}",
|
|
217
|
+
"size": random.randint(1000, 10000000)
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
elif field_type == 'currency':
|
|
221
|
+
return random.choice(['USD', 'EUR', 'GBP', 'JPY', 'CAD'])
|
|
222
|
+
|
|
223
|
+
elif field_type == 'country':
|
|
224
|
+
return random.choice(['US', 'GB', 'CA', 'DE', 'FR', 'JP', 'AU'])
|
|
225
|
+
|
|
226
|
+
elif field_type == 'timezone':
|
|
227
|
+
return random.choice([
|
|
228
|
+
'America/New_York', 'America/Los_Angeles', 'Europe/London',
|
|
229
|
+
'Europe/Paris', 'Asia/Tokyo', 'Australia/Sydney'
|
|
230
|
+
])
|
|
231
|
+
|
|
232
|
+
elif field_type == 'address':
|
|
233
|
+
return {
|
|
234
|
+
"street": f"{random.randint(100, 9999)} Main Street",
|
|
235
|
+
"city": random.choice(['New York', 'Los Angeles', 'Chicago', 'Houston']),
|
|
236
|
+
"state": random.choice(['NY', 'CA', 'IL', 'TX']),
|
|
237
|
+
"zip": f"{random.randint(10000, 99999)}",
|
|
238
|
+
"country": "US"
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
# Default
|
|
242
|
+
return f"value_{index + 1}"
|
|
243
|
+
|
|
244
|
+
|
|
245
|
+
def generate_sample_data(entity_slug: str, fields: List[Dict], count: int) -> List[Dict]:
|
|
246
|
+
"""Generate sample data records."""
|
|
247
|
+
records = []
|
|
248
|
+
|
|
249
|
+
for i in range(count):
|
|
250
|
+
record = {
|
|
251
|
+
"id": str(uuid.uuid4()),
|
|
252
|
+
"userId": str(uuid.uuid4()), # Placeholder - should be replaced with real user ID
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
for field in fields:
|
|
256
|
+
# Use snake_case for database compatibility
|
|
257
|
+
key = to_snake_case(field['name'])
|
|
258
|
+
record[key] = generate_value(field, i)
|
|
259
|
+
|
|
260
|
+
# Add timestamps
|
|
261
|
+
created_days_ago = random.randint(0, 60)
|
|
262
|
+
updated_days_ago = random.randint(0, created_days_ago)
|
|
263
|
+
|
|
264
|
+
created_at = datetime.now() - timedelta(days=created_days_ago)
|
|
265
|
+
updated_at = datetime.now() - timedelta(days=updated_days_ago)
|
|
266
|
+
|
|
267
|
+
record["created_at"] = created_at.isoformat()
|
|
268
|
+
record["updated_at"] = updated_at.isoformat()
|
|
269
|
+
|
|
270
|
+
records.append(record)
|
|
271
|
+
|
|
272
|
+
return records
|
|
273
|
+
|
|
274
|
+
|
|
275
|
+
def format_json(records: List[Dict]) -> str:
|
|
276
|
+
"""Format as JSON."""
|
|
277
|
+
return json.dumps(records, indent=2)
|
|
278
|
+
|
|
279
|
+
|
|
280
|
+
def format_sql(entity_slug: str, records: List[Dict]) -> str:
|
|
281
|
+
"""Format as SQL INSERT statements."""
|
|
282
|
+
table_name = to_snake_case(entity_slug)
|
|
283
|
+
|
|
284
|
+
if not records:
|
|
285
|
+
return "-- No records to insert"
|
|
286
|
+
|
|
287
|
+
columns = list(records[0].keys())
|
|
288
|
+
sql_lines = [f"-- Sample data for {table_name}", ""]
|
|
289
|
+
|
|
290
|
+
for record in records:
|
|
291
|
+
values = []
|
|
292
|
+
for col in columns:
|
|
293
|
+
val = record[col]
|
|
294
|
+
if val is None:
|
|
295
|
+
values.append("NULL")
|
|
296
|
+
elif isinstance(val, bool):
|
|
297
|
+
values.append("TRUE" if val else "FALSE")
|
|
298
|
+
elif isinstance(val, (int, float)):
|
|
299
|
+
values.append(str(val))
|
|
300
|
+
elif isinstance(val, (list, dict)):
|
|
301
|
+
json_str = json.dumps(val).replace("'", "''")
|
|
302
|
+
values.append(f"'{json_str}'::jsonb")
|
|
303
|
+
else:
|
|
304
|
+
escaped = str(val).replace("'", "''")
|
|
305
|
+
values.append(f"'{escaped}'")
|
|
306
|
+
|
|
307
|
+
sql_lines.append(
|
|
308
|
+
f'INSERT INTO "{table_name}" ({", ".join(f\'"{c}\'" for c in columns)}) '
|
|
309
|
+
f'VALUES ({", ".join(values)});'
|
|
310
|
+
)
|
|
311
|
+
|
|
312
|
+
return "\n".join(sql_lines)
|
|
313
|
+
|
|
314
|
+
|
|
315
|
+
def format_csv(records: List[Dict]) -> str:
|
|
316
|
+
"""Format as CSV."""
|
|
317
|
+
if not records:
|
|
318
|
+
return ""
|
|
319
|
+
|
|
320
|
+
columns = list(records[0].keys())
|
|
321
|
+
lines = [",".join(columns)]
|
|
322
|
+
|
|
323
|
+
for record in records:
|
|
324
|
+
values = []
|
|
325
|
+
for col in columns:
|
|
326
|
+
val = record[col]
|
|
327
|
+
if val is None:
|
|
328
|
+
values.append("")
|
|
329
|
+
elif isinstance(val, (list, dict)):
|
|
330
|
+
json_str = json.dumps(val).replace('"', '""')
|
|
331
|
+
values.append(f'"{json_str}"')
|
|
332
|
+
elif isinstance(val, str) and (',' in val or '"' in val or '\n' in val):
|
|
333
|
+
escaped = val.replace('"', '""')
|
|
334
|
+
values.append(f'"{escaped}"')
|
|
335
|
+
else:
|
|
336
|
+
values.append(str(val))
|
|
337
|
+
lines.append(",".join(values))
|
|
338
|
+
|
|
339
|
+
return "\n".join(lines)
|
|
340
|
+
|
|
341
|
+
|
|
342
|
+
def main():
|
|
343
|
+
parser = argparse.ArgumentParser(description='Generate sample data for entity')
|
|
344
|
+
parser.add_argument('--entity', required=True, help='Entity name (kebab-case)')
|
|
345
|
+
parser.add_argument('--theme', default=None, help='Theme name')
|
|
346
|
+
parser.add_argument('--count', type=int, default=10, help='Number of records')
|
|
347
|
+
parser.add_argument('--output', help='Output file')
|
|
348
|
+
parser.add_argument('--format', choices=['json', 'sql', 'csv'], default='json')
|
|
349
|
+
parser.add_argument('--seed', type=int, help='Random seed for reproducibility')
|
|
350
|
+
|
|
351
|
+
args = parser.parse_args()
|
|
352
|
+
|
|
353
|
+
# Set seed for reproducibility
|
|
354
|
+
if args.seed:
|
|
355
|
+
random.seed(args.seed)
|
|
356
|
+
|
|
357
|
+
theme = args.theme or get_active_theme()
|
|
358
|
+
entity_slug = args.entity.lower()
|
|
359
|
+
|
|
360
|
+
# Find fields file
|
|
361
|
+
fields_path = Path(f'contents/themes/{theme}/entities/{entity_slug}/{entity_slug}.fields.ts')
|
|
362
|
+
|
|
363
|
+
print(f"\nGenerating sample data for: {entity_slug}")
|
|
364
|
+
print(f"Theme: {theme}")
|
|
365
|
+
print(f"Count: {args.count}")
|
|
366
|
+
print(f"Format: {args.format}")
|
|
367
|
+
|
|
368
|
+
# Parse fields
|
|
369
|
+
fields = parse_fields_file(fields_path)
|
|
370
|
+
print(f"Found {len(fields)} fields")
|
|
371
|
+
|
|
372
|
+
if not fields:
|
|
373
|
+
print("\nWarning: No fields found. Generating minimal sample data.")
|
|
374
|
+
fields = [
|
|
375
|
+
{'name': 'title', 'type': 'text'},
|
|
376
|
+
{'name': 'description', 'type': 'textarea'},
|
|
377
|
+
{'name': 'status', 'type': 'select', 'options': ['draft', 'active', 'archived']},
|
|
378
|
+
]
|
|
379
|
+
|
|
380
|
+
# Generate sample data
|
|
381
|
+
records = generate_sample_data(entity_slug, fields, args.count)
|
|
382
|
+
|
|
383
|
+
# Format output
|
|
384
|
+
if args.format == 'json':
|
|
385
|
+
output = format_json(records)
|
|
386
|
+
elif args.format == 'sql':
|
|
387
|
+
output = format_sql(entity_slug, records)
|
|
388
|
+
elif args.format == 'csv':
|
|
389
|
+
output = format_csv(records)
|
|
390
|
+
else:
|
|
391
|
+
output = format_json(records)
|
|
392
|
+
|
|
393
|
+
# Write output
|
|
394
|
+
if args.output:
|
|
395
|
+
output_path = Path(args.output)
|
|
396
|
+
output_path.parent.mkdir(parents=True, exist_ok=True)
|
|
397
|
+
with open(output_path, 'w', encoding='utf-8') as f:
|
|
398
|
+
f.write(output)
|
|
399
|
+
print(f"\nSample data written to: {output_path}")
|
|
400
|
+
else:
|
|
401
|
+
# Default output location
|
|
402
|
+
default_output = Path(f'contents/themes/{theme}/entities/{entity_slug}/migrations/sample_data.json')
|
|
403
|
+
if args.format != 'json':
|
|
404
|
+
ext = args.format
|
|
405
|
+
default_output = default_output.with_suffix(f'.{ext}')
|
|
406
|
+
|
|
407
|
+
default_output.parent.mkdir(parents=True, exist_ok=True)
|
|
408
|
+
with open(default_output, 'w', encoding='utf-8') as f:
|
|
409
|
+
f.write(output)
|
|
410
|
+
print(f"\nSample data written to: {default_output}")
|
|
411
|
+
|
|
412
|
+
print(f"Generated {len(records)} records")
|
|
413
|
+
|
|
414
|
+
return 0
|
|
415
|
+
|
|
416
|
+
|
|
417
|
+
if __name__ == '__main__':
|
|
418
|
+
sys.exit(main())
|