framework-m-studio 0.10.2__tar.gz → 0.12.0__tar.gz
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.
- {framework_m_studio-0.10.2 → framework_m_studio-0.12.0}/CHANGELOG.md +24 -0
- {framework_m_studio-0.10.2 → framework_m_studio-0.12.0}/PKG-INFO +3 -3
- {framework_m_studio-0.10.2 → framework_m_studio-0.12.0}/pyproject.toml +7 -11
- {framework_m_studio-0.10.2 → framework_m_studio-0.12.0}/src/framework_m_studio/__init__.py +11 -2
- {framework_m_studio-0.10.2 → framework_m_studio-0.12.0}/src/framework_m_studio/app.py +81 -5
- {framework_m_studio-0.10.2 → framework_m_studio-0.12.0}/src/framework_m_studio/cli/deps.py +12 -12
- {framework_m_studio-0.10.2 → framework_m_studio-0.12.0}/src/framework_m_studio/cli/dev.py +6 -6
- {framework_m_studio-0.10.2 → framework_m_studio-0.12.0}/src/framework_m_studio/cli/new.py +3 -3
- framework_m_studio-0.12.0/src/framework_m_studio/cli/release/lockfile_sync.py +41 -0
- {framework_m_studio-0.10.2 → framework_m_studio-0.12.0}/src/framework_m_studio/cli/release/orchestrator.py +9 -35
- {framework_m_studio-0.10.2 → framework_m_studio-0.12.0}/src/framework_m_studio/codegen/__init__.py +2 -4
- framework_m_studio-0.12.0/src/framework_m_studio/codegen/annotation_parser.py +104 -0
- framework_m_studio-0.12.0/src/framework_m_studio/codegen/generator.py +184 -0
- framework_m_studio-0.12.0/src/framework_m_studio/codegen/meta_extractor.py +54 -0
- {framework_m_studio-0.10.2 → framework_m_studio-0.12.0}/src/framework_m_studio/codegen/parser.py +78 -256
- framework_m_studio-0.12.0/src/framework_m_studio/codegen/templates/__init__.py.jinja2 +9 -0
- framework_m_studio-0.12.0/src/framework_m_studio/codegen/templates/controller.py.jinja2 +63 -0
- {framework_m_studio-0.10.2 → framework_m_studio-0.12.0}/src/framework_m_studio/codegen/templates/doctype.py.jinja2 +7 -9
- {framework_m_studio-0.10.2 → framework_m_studio-0.12.0}/src/framework_m_studio/codegen/templates/test_doctype.py.jinja2 +4 -4
- {framework_m_studio-0.10.2 → framework_m_studio-0.12.0}/src/framework_m_studio/codegen/test_generator.py +3 -1
- framework_m_studio-0.12.0/src/framework_m_studio/core/adapters/cst/mutator.py +96 -0
- framework_m_studio-0.12.0/src/framework_m_studio/core/codegen/augmentation_gen.py +68 -0
- framework_m_studio-0.12.0/src/framework_m_studio/core/discovery/pydantic.py +56 -0
- framework_m_studio-0.12.0/src/framework_m_studio/core/discovery/roles.py +59 -0
- framework_m_studio-0.12.0/src/framework_m_studio/core/repositories/fs_mx_repo.py +111 -0
- {framework_m_studio-0.10.2 → framework_m_studio-0.12.0}/src/framework_m_studio/data_elements.py +10 -0
- framework_m_studio-0.12.0/src/framework_m_studio/dev_config.py +259 -0
- framework_m_studio-0.12.0/src/framework_m_studio/doctypes/virtual_doc_type/__init__.py +9 -0
- framework_m_studio-0.12.0/src/framework_m_studio/doctypes/virtual_doc_type/controller.py +29 -0
- framework_m_studio-0.12.0/src/framework_m_studio/doctypes/virtual_doc_type/doctype.py +44 -0
- framework_m_studio-0.12.0/src/framework_m_studio/doctypes/virtual_field/__init__.py +9 -0
- framework_m_studio-0.12.0/src/framework_m_studio/doctypes/virtual_field/controller.py +29 -0
- framework_m_studio-0.12.0/src/framework_m_studio/doctypes/virtual_field/doctype.py +46 -0
- framework_m_studio-0.12.0/src/framework_m_studio/resources/blueprints/standard.json +60 -0
- framework_m_studio-0.12.0/src/framework_m_studio/resources/roles/crm.json +21 -0
- framework_m_studio-0.12.0/src/framework_m_studio/resources/roles/financial.json +21 -0
- framework_m_studio-0.12.0/src/framework_m_studio/resources/roles/hr.json +21 -0
- framework_m_studio-0.12.0/src/framework_m_studio/resources/roles/inventory.json +21 -0
- framework_m_studio-0.12.0/src/framework_m_studio/resources/roles/project.json +13 -0
- framework_m_studio-0.12.0/src/framework_m_studio/resources/roles/standard.json +17 -0
- framework_m_studio-0.12.0/src/framework_m_studio/routers/__init__.py +1 -0
- framework_m_studio-0.12.0/src/framework_m_studio/routers/aggregate.py +55 -0
- framework_m_studio-0.12.0/src/framework_m_studio/routers/doctypes.py +129 -0
- framework_m_studio-0.12.0/src/framework_m_studio/routers/print.py +74 -0
- framework_m_studio-0.12.0/src/framework_m_studio/routers/publish.py +104 -0
- framework_m_studio-0.12.0/src/framework_m_studio/routers/roles.py +20 -0
- framework_m_studio-0.12.0/src/framework_m_studio/routers/shell.py +56 -0
- framework_m_studio-0.12.0/src/framework_m_studio/routes.py +28 -0
- framework_m_studio-0.12.0/src/framework_m_studio/schemas.py +227 -0
- framework_m_studio-0.12.0/src/framework_m_studio/services/__init__.py +0 -0
- framework_m_studio-0.12.0/src/framework_m_studio/services/aggregate.py +38 -0
- framework_m_studio-0.12.0/src/framework_m_studio/services/doctype.py +153 -0
- framework_m_studio-0.12.0/src/framework_m_studio/services/print_service.py +58 -0
- framework_m_studio-0.12.0/src/framework_m_studio/services/publish.py +48 -0
- framework_m_studio-0.12.0/src/framework_m_studio/services/shell.py +72 -0
- framework_m_studio-0.12.0/src/framework_m_studio/services/workspace.py +53 -0
- framework_m_studio-0.12.0/src/framework_m_studio/static/.gitkeep +0 -0
- framework_m_studio-0.12.0/src/framework_m_studio/static/assets/browser-ponyfill-DY7R_jX1.js +2 -0
- framework_m_studio-0.12.0/src/framework_m_studio/static/assets/index-1KLiXoy5.js +124 -0
- framework_m_studio-0.12.0/src/framework_m_studio/static/assets/index-DymRru6K.css +1 -0
- framework_m_studio-0.12.0/src/framework_m_studio/static/assets/vendor-icons-C9MKFQpH.js +1 -0
- framework_m_studio-0.12.0/src/framework_m_studio/static/assets/vendor-react-C1jOJk9g.js +59 -0
- framework_m_studio-0.12.0/src/framework_m_studio/static/assets/vendor-tamagui-BwPfGmbG.js +26 -0
- {framework_m_studio-0.10.2 → framework_m_studio-0.12.0}/src/framework_m_studio/static/index.html +6 -14
- {framework_m_studio-0.10.2 → framework_m_studio-0.12.0}/src/framework_m_studio/templates/app/README.md.template +1 -1
- framework_m_studio-0.12.0/src/framework_m_studio/templates/plugin/Dashboard.tsx.template +69 -0
- framework_m_studio-0.12.0/src/framework_m_studio/templates/plugin/favicon.png +0 -0
- {framework_m_studio-0.10.2 → framework_m_studio-0.12.0}/src/framework_m_studio/templates/plugin/index.tsx.template +4 -12
- {framework_m_studio-0.10.2 → framework_m_studio-0.12.0}/src/framework_m_studio/templates/plugin/package.json.template +5 -4
- framework_m_studio-0.12.0/src/framework_m_studio/templates/plugin/plugin.config.ts.template +55 -0
- {framework_m_studio-0.10.2 → framework_m_studio-0.12.0}/src/framework_m_studio/templates/plugin/vite.config.ts.template +47 -1
- {framework_m_studio-0.10.2 → framework_m_studio-0.12.0}/studio_ui/CHANGELOG.md +7 -0
- {framework_m_studio-0.10.2 → framework_m_studio-0.12.0}/studio_ui/index.html +2 -12
- {framework_m_studio-0.10.2 → framework_m_studio-0.12.0}/studio_ui/package.json +17 -15
- framework_m_studio-0.12.0/studio_ui/public/favicon.png +0 -0
- framework_m_studio-0.12.0/studio_ui/src/App.test.tsx +27 -0
- {framework_m_studio-0.10.2 → framework_m_studio-0.12.0}/studio_ui/src/App.tsx +6 -24
- framework_m_studio-0.12.0/studio_ui/src/components/AggregateTab.test.tsx +42 -0
- framework_m_studio-0.12.0/studio_ui/src/components/AggregateTab.tsx +127 -0
- {framework_m_studio-0.10.2 → framework_m_studio-0.12.0}/studio_ui/src/components/CodePreview.tsx +1 -1
- {framework_m_studio-0.10.2 → framework_m_studio-0.12.0}/studio_ui/src/components/FieldEditor.tsx +46 -24
- framework_m_studio-0.12.0/studio_ui/src/components/MetaEditor.test.tsx +57 -0
- framework_m_studio-0.12.0/studio_ui/src/components/MetaEditor.tsx +257 -0
- framework_m_studio-0.12.0/studio_ui/src/components/MigrationTab.test.tsx +59 -0
- framework_m_studio-0.12.0/studio_ui/src/components/MigrationTab.tsx +117 -0
- framework_m_studio-0.12.0/studio_ui/src/components/PrintTab.test.tsx +49 -0
- framework_m_studio-0.12.0/studio_ui/src/components/PrintTab.tsx +226 -0
- framework_m_studio-0.12.0/studio_ui/src/components/PropertiesPanel.tsx +361 -0
- framework_m_studio-0.12.0/studio_ui/src/designer/DesignerCanvas.test.tsx +94 -0
- framework_m_studio-0.12.0/studio_ui/src/designer/DesignerCanvas.tsx +358 -0
- framework_m_studio-0.12.0/studio_ui/src/designer/components/PaletteItem.tsx +30 -0
- framework_m_studio-0.12.0/studio_ui/src/designer/components/SectionDropZone.tsx +18 -0
- framework_m_studio-0.12.0/studio_ui/src/designer/hooks/useDesignerState.ts +201 -0
- {framework_m_studio-0.10.2 → framework_m_studio-0.12.0}/studio_ui/src/index.css +1 -1
- {framework_m_studio-0.10.2 → framework_m_studio-0.12.0}/studio_ui/src/pages/doctypes/edit.tsx +252 -396
- {framework_m_studio-0.10.2 → framework_m_studio-0.12.0}/studio_ui/src/pages/doctypes/list.tsx +39 -20
- {framework_m_studio-0.10.2 → framework_m_studio-0.12.0}/studio_ui/src/pages/index.ts +0 -1
- {framework_m_studio-0.10.2 → framework_m_studio-0.12.0}/studio_ui/src/providers/data.ts +22 -25
- framework_m_studio-0.12.0/studio_ui/vite.config.ts +74 -0
- {framework_m_studio-0.10.2 → framework_m_studio-0.12.0}/studio_ui/vitest.config.ts +5 -1
- framework_m_studio-0.12.0/tests/codegen/test_annotation_parser.py +66 -0
- framework_m_studio-0.12.0/tests/codegen/test_meta_extractor.py +59 -0
- framework_m_studio-0.12.0/tests/core/adapters/test_cst_mutator.py +96 -0
- framework_m_studio-0.12.0/tests/core/codegen/test_augmentation_gen.py +31 -0
- framework_m_studio-0.12.0/tests/core/discovery/test_pydantic_discovery.py +51 -0
- framework_m_studio-0.12.0/tests/core/discovery/test_role_discovery.py +43 -0
- framework_m_studio-0.12.0/tests/core/repositories/test_fs_mx_repo.py +111 -0
- {framework_m_studio-0.10.2 → framework_m_studio-0.12.0}/tests/core/test_shell.py +40 -0
- framework_m_studio-0.12.0/tests/doctypes/virtual_doc_type/test_virtual_doc_type.py +21 -0
- framework_m_studio-0.12.0/tests/doctypes/virtual_field/test_virtual_field.py +21 -0
- framework_m_studio-0.12.0/tests/test_aggregate_builder_branches.py +15 -0
- framework_m_studio-0.12.0/tests/test_aggregate_generator.py +57 -0
- {framework_m_studio-0.10.2 → framework_m_studio-0.12.0}/tests/test_api_routes.py +241 -29
- {framework_m_studio-0.10.2 → framework_m_studio-0.12.0}/tests/test_builder_shell_routes.py +11 -2
- {framework_m_studio-0.10.2 → framework_m_studio-0.12.0}/tests/test_cli.py +20 -0
- framework_m_studio-0.12.0/tests/test_codegen_cli.py +24 -0
- {framework_m_studio-0.10.2 → framework_m_studio-0.12.0}/tests/test_contrib_cli.py +33 -0
- {framework_m_studio-0.10.2 → framework_m_studio-0.12.0}/tests/test_deps_cli.py +100 -0
- {framework_m_studio-0.10.2 → framework_m_studio-0.12.0}/tests/test_dev_cli_coverage.py +103 -0
- framework_m_studio-0.12.0/tests/test_dev_config.py +428 -0
- framework_m_studio-0.12.0/tests/test_docs_generator_extended.py +245 -0
- framework_m_studio-0.12.0/tests/test_doctype_service_coverage.py +152 -0
- {framework_m_studio-0.10.2 → framework_m_studio-0.12.0}/tests/test_generator.py +8 -91
- {framework_m_studio-0.10.2 → framework_m_studio-0.12.0}/tests/test_git_adapter.py +139 -0
- {framework_m_studio-0.10.2 → framework_m_studio-0.12.0}/tests/test_github_provider.py +54 -0
- {framework_m_studio-0.10.2 → framework_m_studio-0.12.0}/tests/test_live_preview.py +17 -0
- framework_m_studio-0.12.0/tests/test_lockfile_sync.py +79 -0
- {framework_m_studio-0.10.2 → framework_m_studio-0.12.0}/tests/test_new_cli.py +4 -3
- {framework_m_studio-0.10.2 → framework_m_studio-0.12.0}/tests/test_parser.py +220 -63
- {framework_m_studio-0.10.2 → framework_m_studio-0.12.0}/tests/test_print_adapter.py +41 -1
- framework_m_studio-0.12.0/tests/test_print_router_isolated.py +30 -0
- {framework_m_studio-0.10.2 → framework_m_studio-0.12.0}/tests/test_quality_cli.py +117 -0
- framework_m_studio-0.12.0/tests/test_release_orchestrator.py +528 -0
- {framework_m_studio-0.10.2 → framework_m_studio-0.12.0}/tests/test_routes_extended.py +86 -39
- {framework_m_studio-0.10.2 → framework_m_studio-0.12.0}/tests/test_schema_diff.py +52 -0
- {framework_m_studio-0.10.2 → framework_m_studio-0.12.0}/tests/test_studio_codegen_generator.py +2 -2
- framework_m_studio-0.12.0/tests/test_studio_init.py +19 -0
- framework_m_studio-0.12.0/tests/test_transformer.py +304 -0
- {framework_m_studio-0.10.2 → framework_m_studio-0.12.0}/tests/test_uimeta_routes.py +1 -1
- framework_m_studio-0.12.0/tests/test_workspace_coverage.py +72 -0
- framework_m_studio-0.10.2/src/framework_m_studio/codegen/generator.py +0 -295
- framework_m_studio-0.10.2/src/framework_m_studio/routes.py +0 -1326
- framework_m_studio-0.10.2/src/framework_m_studio/static/assets/index-BA2TojqY.css +0 -1
- framework_m_studio-0.10.2/src/framework_m_studio/static/assets/index-Db96rZJC.js +0 -182
- framework_m_studio-0.10.2/src/framework_m_studio/static/favicon.ico +0 -0
- framework_m_studio-0.10.2/src/framework_m_studio/templates/plugin/Dashboard.tsx.template +0 -129
- framework_m_studio-0.10.2/src/framework_m_studio/templates/plugin/plugin.config.ts.template +0 -31
- framework_m_studio-0.10.2/studio_ui/public/favicon.ico +0 -0
- framework_m_studio-0.10.2/studio_ui/src/App.test.tsx +0 -16
- framework_m_studio-0.10.2/studio_ui/src/pages/aggregates/AggregateBuilderPage.tsx +0 -254
- framework_m_studio-0.10.2/studio_ui/src/pages/aggregates/index.ts +0 -1
- framework_m_studio-0.10.2/studio_ui/vite.config.ts +0 -21
- framework_m_studio-0.10.2/tests/test_docs_generator_extended.py +0 -77
- framework_m_studio-0.10.2/tests/test_release_orchestrator.py +0 -233
- framework_m_studio-0.10.2/tests/test_transformer.py +0 -176
- {framework_m_studio-0.10.2 → framework_m_studio-0.12.0}/.gitignore +0 -0
- {framework_m_studio-0.10.2 → framework_m_studio-0.12.0}/LICENSE +0 -0
- {framework_m_studio-0.10.2 → framework_m_studio-0.12.0}/README.md +0 -0
- {framework_m_studio-0.10.2 → framework_m_studio-0.12.0}/docs/api/index.md +0 -0
- {framework_m_studio-0.10.2 → framework_m_studio-0.12.0}/docs/user-guide.md +0 -0
- {framework_m_studio-0.10.2 → framework_m_studio-0.12.0}/src/framework_m_studio/aggregate_builder.py +0 -0
- {framework_m_studio-0.10.2 → framework_m_studio-0.12.0}/src/framework_m_studio/cli/__init__.py +0 -0
- {framework_m_studio-0.10.2 → framework_m_studio-0.12.0}/src/framework_m_studio/cli/codegen.py +0 -0
- {framework_m_studio-0.10.2 → framework_m_studio-0.12.0}/src/framework_m_studio/cli/constants.py +0 -0
- {framework_m_studio-0.10.2 → framework_m_studio-0.12.0}/src/framework_m_studio/cli/contrib.py +0 -0
- {framework_m_studio-0.10.2 → framework_m_studio-0.12.0}/src/framework_m_studio/cli/docs.py +0 -0
- {framework_m_studio-0.10.2 → framework_m_studio-0.12.0}/src/framework_m_studio/cli/quality.py +0 -0
- {framework_m_studio-0.10.2 → framework_m_studio-0.12.0}/src/framework_m_studio/cli/release/__init__.py +0 -0
- {framework_m_studio-0.10.2 → framework_m_studio-0.12.0}/src/framework_m_studio/cli/release/cli.py +0 -0
- {framework_m_studio-0.10.2 → framework_m_studio-0.12.0}/src/framework_m_studio/cli/release/gitops.py +0 -0
- {framework_m_studio-0.10.2 → framework_m_studio-0.12.0}/src/framework_m_studio/cli/release/graph.py +0 -0
- {framework_m_studio-0.10.2 → framework_m_studio-0.12.0}/src/framework_m_studio/cli/release/models.py +0 -0
- {framework_m_studio-0.10.2 → framework_m_studio-0.12.0}/src/framework_m_studio/cli/release/versioning.py +0 -0
- {framework_m_studio-0.10.2 → framework_m_studio-0.12.0}/src/framework_m_studio/cli/studio.py +0 -0
- {framework_m_studio-0.10.2 → framework_m_studio-0.12.0}/src/framework_m_studio/cli/utility.py +0 -0
- {framework_m_studio-0.10.2 → framework_m_studio-0.12.0}/src/framework_m_studio/cli/verify.py +0 -0
- {framework_m_studio-0.10.2 → framework_m_studio-0.12.0}/src/framework_m_studio/codegen/transformer.py +0 -0
- {framework_m_studio-0.10.2 → framework_m_studio-0.12.0}/src/framework_m_studio/core/frontend.py +0 -0
- {framework_m_studio-0.10.2 → framework_m_studio-0.12.0}/src/framework_m_studio/core/gitops.py +0 -0
- /framework_m_studio-0.10.2/src/framework_m_studio/py.typed → /framework_m_studio-0.12.0/src/framework_m_studio/core/repositories/git_mx_repo.py +0 -0
- {framework_m_studio-0.10.2 → framework_m_studio-0.12.0}/src/framework_m_studio/core/shell.py +0 -0
- {framework_m_studio-0.10.2 → framework_m_studio-0.12.0}/src/framework_m_studio/discovery.py +0 -0
- {framework_m_studio-0.10.2 → framework_m_studio-0.12.0}/src/framework_m_studio/docs/ast_parsers.py +0 -0
- {framework_m_studio-0.10.2 → framework_m_studio-0.12.0}/src/framework_m_studio/docs/audit.py +0 -0
- {framework_m_studio-0.10.2 → framework_m_studio-0.12.0}/src/framework_m_studio/docs/exporters.py +0 -0
- {framework_m_studio-0.10.2 → framework_m_studio-0.12.0}/src/framework_m_studio/docs/formatters.py +0 -0
- {framework_m_studio-0.10.2 → framework_m_studio-0.12.0}/src/framework_m_studio/docs/generator.py +0 -0
- {framework_m_studio-0.10.2 → framework_m_studio-0.12.0}/src/framework_m_studio/docs/openapi.py +0 -0
- {framework_m_studio-0.10.2 → framework_m_studio-0.12.0}/src/framework_m_studio/ephemeral.py +0 -0
- {framework_m_studio-0.10.2 → framework_m_studio-0.12.0}/src/framework_m_studio/git/__init__.py +0 -0
- {framework_m_studio-0.10.2 → framework_m_studio-0.12.0}/src/framework_m_studio/git/adapter.py +0 -0
- {framework_m_studio-0.10.2 → framework_m_studio-0.12.0}/src/framework_m_studio/git/github_provider.py +0 -0
- {framework_m_studio-0.10.2 → framework_m_studio-0.12.0}/src/framework_m_studio/git/protocol.py +0 -0
- {framework_m_studio-0.10.2 → framework_m_studio-0.12.0}/src/framework_m_studio/guardrail.py +0 -0
- {framework_m_studio-0.10.2 → framework_m_studio-0.12.0}/src/framework_m_studio/live_preview.py +0 -0
- {framework_m_studio-0.10.2 → framework_m_studio-0.12.0}/src/framework_m_studio/metadata_editor.py +0 -0
- {framework_m_studio-0.10.2 → framework_m_studio-0.12.0}/src/framework_m_studio/print_adapter.py +0 -0
- {framework_m_studio-0.10.2 → framework_m_studio-0.12.0}/src/framework_m_studio/protocol_scanner.py +0 -0
- /framework_m_studio-0.10.2/src/framework_m_studio/static/.gitkeep → /framework_m_studio-0.12.0/src/framework_m_studio/py.typed +0 -0
- {framework_m_studio-0.10.2 → framework_m_studio-0.12.0}/src/framework_m_studio/schema_diff.py +0 -0
- {framework_m_studio-0.10.2 → framework_m_studio-0.12.0}/src/framework_m_studio/sdk_generator.py +0 -0
- {framework_m_studio-0.10.2 → framework_m_studio-0.12.0}/src/framework_m_studio/shell_plugin_config.py +0 -0
- {framework_m_studio-0.10.2 → framework_m_studio-0.12.0}/src/framework_m_studio/sidebar_config.py +0 -0
- {framework_m_studio-0.10.2/src/framework_m_studio/templates/plugin → framework_m_studio-0.12.0/src/framework_m_studio/static}/favicon.png +0 -0
- {framework_m_studio-0.10.2 → framework_m_studio-0.12.0}/src/framework_m_studio/storage/__init__.py +0 -0
- {framework_m_studio-0.10.2 → framework_m_studio-0.12.0}/src/framework_m_studio/storage/file_adapter.py +0 -0
- {framework_m_studio-0.10.2 → framework_m_studio-0.12.0}/src/framework_m_studio/storage/git_api_adapter.py +0 -0
- {framework_m_studio-0.10.2 → framework_m_studio-0.12.0}/src/framework_m_studio/storage/protocol.py +0 -0
- {framework_m_studio-0.10.2 → framework_m_studio-0.12.0}/src/framework_m_studio/templates/app/__init__.py.template +0 -0
- {framework_m_studio-0.10.2 → framework_m_studio-0.12.0}/src/framework_m_studio/templates/app/doctypes_init.py.template +0 -0
- {framework_m_studio-0.10.2 → framework_m_studio-0.12.0}/src/framework_m_studio/templates/app/pyproject.toml.template +0 -0
- {framework_m_studio-0.10.2 → framework_m_studio-0.12.0}/src/framework_m_studio/templates/doctype/__init__.py.template +0 -0
- {framework_m_studio-0.10.2 → framework_m_studio-0.12.0}/src/framework_m_studio/templates/doctype/controller.py.template +0 -0
- {framework_m_studio-0.10.2 → framework_m_studio-0.12.0}/src/framework_m_studio/templates/doctype/doctype.py.template +0 -0
- {framework_m_studio-0.10.2 → framework_m_studio-0.12.0}/src/framework_m_studio/templates/doctype/test.py.template +0 -0
- {framework_m_studio-0.10.2 → framework_m_studio-0.12.0}/src/framework_m_studio/templates/plugin/.gitignore.template +0 -0
- {framework_m_studio-0.10.2 → framework_m_studio-0.12.0}/src/framework_m_studio/templates/plugin/README.md.template +0 -0
- {framework_m_studio-0.10.2 → framework_m_studio-0.12.0}/src/framework_m_studio/templates/plugin/index.html.template +0 -0
- {framework_m_studio-0.10.2 → framework_m_studio-0.12.0}/src/framework_m_studio/templates/plugin/theme.css.template +0 -0
- {framework_m_studio-0.10.2 → framework_m_studio-0.12.0}/src/framework_m_studio/templates/plugin/tsconfig.json.template +0 -0
- {framework_m_studio-0.10.2 → framework_m_studio-0.12.0}/src/framework_m_studio/templates/plugin/vite.config.mfe.ts.template +0 -0
- {framework_m_studio-0.10.2 → framework_m_studio-0.12.0}/src/framework_m_studio/visual_designer.py +0 -0
- {framework_m_studio-0.10.2 → framework_m_studio-0.12.0}/src/framework_m_studio/workspace.py +0 -0
- {framework_m_studio-0.10.2 → framework_m_studio-0.12.0}/studio_ui/.gitignore +0 -0
- {framework_m_studio-0.10.2 → framework_m_studio-0.12.0}/studio_ui/.npmrc +0 -0
- {framework_m_studio-0.10.2 → framework_m_studio-0.12.0}/studio_ui/Dockerfile +0 -0
- {framework_m_studio-0.10.2 → framework_m_studio-0.12.0}/studio_ui/README.md +0 -0
- {framework_m_studio-0.10.2 → framework_m_studio-0.12.0}/studio_ui/eslint.config.js +0 -0
- {framework_m_studio-0.10.2 → framework_m_studio-0.12.0}/studio_ui/pnpm-lock.yaml +0 -0
- {framework_m_studio-0.10.2 → framework_m_studio-0.12.0}/studio_ui/src/App.css +0 -0
- {framework_m_studio-0.10.2 → framework_m_studio-0.12.0}/studio_ui/src/components/AutoForm.tsx +0 -0
- {framework_m_studio-0.10.2 → framework_m_studio-0.12.0}/studio_ui/src/components/AutoTable.tsx +0 -0
- {framework_m_studio-0.10.2 → framework_m_studio-0.12.0}/studio_ui/src/components/ControllerEditor.tsx +0 -0
- {framework_m_studio-0.10.2 → framework_m_studio-0.12.0}/studio_ui/src/components/ERDView.tsx +0 -0
- {framework_m_studio-0.10.2 → framework_m_studio-0.12.0}/studio_ui/src/components/LayoutDesigner.tsx +0 -0
- {framework_m_studio-0.10.2 → framework_m_studio-0.12.0}/studio_ui/src/components/ModuleExplorer.tsx +0 -0
- {framework_m_studio-0.10.2 → framework_m_studio-0.12.0}/studio_ui/src/components/NestedEditorDrawer.tsx +0 -0
- {framework_m_studio-0.10.2 → framework_m_studio-0.12.0}/studio_ui/src/components/SandboxPreview.tsx +0 -0
- {framework_m_studio-0.10.2 → framework_m_studio-0.12.0}/studio_ui/src/components/TableFieldEditor.tsx +0 -0
- {framework_m_studio-0.10.2 → framework_m_studio-0.12.0}/studio_ui/src/components/breadcrumb/index.tsx +0 -0
- {framework_m_studio-0.10.2 → framework_m_studio-0.12.0}/studio_ui/src/components/fields/DefaultFieldComponents.tsx +0 -0
- {framework_m_studio-0.10.2 → framework_m_studio-0.12.0}/studio_ui/src/components/fields/index.ts +0 -0
- {framework_m_studio-0.10.2 → framework_m_studio-0.12.0}/studio_ui/src/components/fields/resolveFieldComponent.ts +0 -0
- {framework_m_studio-0.10.2 → framework_m_studio-0.12.0}/studio_ui/src/components/layout/index.tsx +0 -0
- {framework_m_studio-0.10.2 → framework_m_studio-0.12.0}/studio_ui/src/components/menu/index.tsx +0 -0
- {framework_m_studio-0.10.2 → framework_m_studio-0.12.0}/studio_ui/src/index.tsx +0 -0
- {framework_m_studio-0.10.2 → framework_m_studio-0.12.0}/studio_ui/src/pages/doctypes/index.ts +0 -0
- {framework_m_studio-0.10.2 → framework_m_studio-0.12.0}/studio_ui/src/pages/prints/PrintBuilderPage.tsx +0 -0
- {framework_m_studio-0.10.2 → framework_m_studio-0.12.0}/studio_ui/src/pages/prints/index.ts +0 -0
- {framework_m_studio-0.10.2 → framework_m_studio-0.12.0}/studio_ui/src/pages/shell-config/ShellConfiguratorPage.tsx +0 -0
- {framework_m_studio-0.10.2 → framework_m_studio-0.12.0}/studio_ui/src/pages/shell-config/index.ts +0 -0
- {framework_m_studio-0.10.2 → framework_m_studio-0.12.0}/studio_ui/src/providers/ThemeContext.ts +0 -0
- {framework_m_studio-0.10.2 → framework_m_studio-0.12.0}/studio_ui/src/providers/constants.ts +0 -0
- {framework_m_studio-0.10.2 → framework_m_studio-0.12.0}/studio_ui/src/providers/theme.tsx +0 -0
- {framework_m_studio-0.10.2 → framework_m_studio-0.12.0}/studio_ui/src/providers/useTheme.ts +0 -0
- {framework_m_studio-0.10.2 → framework_m_studio-0.12.0}/studio_ui/src/registry/defaultComponents.ts +0 -0
- {framework_m_studio-0.10.2 → framework_m_studio-0.12.0}/studio_ui/src/registry/fieldComponents.ts +0 -0
- {framework_m_studio-0.10.2 → framework_m_studio-0.12.0}/studio_ui/src/registry/index.ts +0 -0
- {framework_m_studio-0.10.2 → framework_m_studio-0.12.0}/studio_ui/src/services/mock_data.ts +0 -0
- {framework_m_studio-0.10.2 → framework_m_studio-0.12.0}/studio_ui/src/setupTests.ts +0 -0
- {framework_m_studio-0.10.2 → framework_m_studio-0.12.0}/studio_ui/src/utils/mockDataGenerator.ts +0 -0
- {framework_m_studio-0.10.2 → framework_m_studio-0.12.0}/studio_ui/src/vite-env.d.ts +0 -0
- {framework_m_studio-0.10.2 → framework_m_studio-0.12.0}/studio_ui/tsconfig.json +0 -0
- {framework_m_studio-0.10.2 → framework_m_studio-0.12.0}/studio_ui/tsconfig.node.json +0 -0
- {framework_m_studio-0.10.2 → framework_m_studio-0.12.0}/tests/cli/test_new.py +0 -0
- {framework_m_studio-0.10.2 → framework_m_studio-0.12.0}/tests/cli/test_verify.py +0 -0
- {framework_m_studio-0.10.2 → framework_m_studio-0.12.0}/tests/conftest.py +0 -0
- {framework_m_studio-0.10.2 → framework_m_studio-0.12.0}/tests/core/test_frontend.py +0 -0
- {framework_m_studio-0.10.2 → framework_m_studio-0.12.0}/tests/core/test_gitops.py +0 -0
- {framework_m_studio-0.10.2 → framework_m_studio-0.12.0}/tests/test_aggregate_builder.py +0 -0
- {framework_m_studio-0.10.2 → framework_m_studio-0.12.0}/tests/test_cli_openapi.py +0 -0
- {framework_m_studio-0.10.2 → framework_m_studio-0.12.0}/tests/test_cli_utility.py +0 -0
- {framework_m_studio-0.10.2 → framework_m_studio-0.12.0}/tests/test_core_frontend.py +0 -0
- {framework_m_studio-0.10.2 → framework_m_studio-0.12.0}/tests/test_data_elements.py +0 -0
- {framework_m_studio-0.10.2 → framework_m_studio-0.12.0}/tests/test_data_elements_extended.py +0 -0
- {framework_m_studio-0.10.2 → framework_m_studio-0.12.0}/tests/test_dev.py +0 -0
- {framework_m_studio-0.10.2 → framework_m_studio-0.12.0}/tests/test_discovery.py +0 -0
- {framework_m_studio-0.10.2 → framework_m_studio-0.12.0}/tests/test_docs_ast_parsers.py +0 -0
- {framework_m_studio-0.10.2 → framework_m_studio-0.12.0}/tests/test_docs_audit.py +0 -0
- {framework_m_studio-0.10.2 → framework_m_studio-0.12.0}/tests/test_docs_exporters.py +0 -0
- {framework_m_studio-0.10.2 → framework_m_studio-0.12.0}/tests/test_docs_generator.py +0 -0
- {framework_m_studio-0.10.2 → framework_m_studio-0.12.0}/tests/test_docs_generator_enhanced.py +0 -0
- {framework_m_studio-0.10.2 → framework_m_studio-0.12.0}/tests/test_ephemeral.py +0 -0
- {framework_m_studio-0.10.2 → framework_m_studio-0.12.0}/tests/test_frontend_integration.py +0 -0
- {framework_m_studio-0.10.2 → framework_m_studio-0.12.0}/tests/test_git_protocol.py +0 -0
- {framework_m_studio-0.10.2 → framework_m_studio-0.12.0}/tests/test_guardrail.py +0 -0
- {framework_m_studio-0.10.2 → framework_m_studio-0.12.0}/tests/test_metadata_editor.py +0 -0
- {framework_m_studio-0.10.2 → framework_m_studio-0.12.0}/tests/test_multi_repo_workspace.py +0 -0
- {framework_m_studio-0.10.2 → framework_m_studio-0.12.0}/tests/test_protocol_scanner.py +0 -0
- {framework_m_studio-0.10.2 → framework_m_studio-0.12.0}/tests/test_protocol_scanner_extended.py +0 -0
- {framework_m_studio-0.10.2 → framework_m_studio-0.12.0}/tests/test_release_cli.py +0 -0
- {framework_m_studio-0.10.2 → framework_m_studio-0.12.0}/tests/test_release_cli_more.py +0 -0
- {framework_m_studio-0.10.2 → framework_m_studio-0.12.0}/tests/test_release_gitops.py +0 -0
- {framework_m_studio-0.10.2 → framework_m_studio-0.12.0}/tests/test_release_graph.py +0 -0
- {framework_m_studio-0.10.2 → framework_m_studio-0.12.0}/tests/test_release_versioning.py +0 -0
- {framework_m_studio-0.10.2 → framework_m_studio-0.12.0}/tests/test_screenshot_pipeline.py +0 -0
- {framework_m_studio-0.10.2 → framework_m_studio-0.12.0}/tests/test_sdk_generator.py +0 -0
- {framework_m_studio-0.10.2 → framework_m_studio-0.12.0}/tests/test_shell_plugin_config.py +0 -0
- {framework_m_studio-0.10.2 → framework_m_studio-0.12.0}/tests/test_sidebar_routes.py +0 -0
- {framework_m_studio-0.10.2 → framework_m_studio-0.12.0}/tests/test_storage_adapters.py +0 -0
- {framework_m_studio-0.10.2 → framework_m_studio-0.12.0}/tests/test_studio.py +0 -0
- {framework_m_studio-0.10.2 → framework_m_studio-0.12.0}/tests/test_utility_cli.py +0 -0
- {framework_m_studio-0.10.2 → framework_m_studio-0.12.0}/tests/test_utility_cli_enhanced.py +0 -0
- {framework_m_studio-0.10.2 → framework_m_studio-0.12.0}/tests/test_visual_designer.py +0 -0
- {framework_m_studio-0.10.2 → framework_m_studio-0.12.0}/tests/test_workspace.py +0 -0
|
@@ -1,3 +1,27 @@
|
|
|
1
|
+
## framework-m-studio v0.12.0
|
|
2
|
+
|
|
3
|
+
### Features
|
|
4
|
+
|
|
5
|
+
- update plugin scaffolding templates for navigation (83d7e7a)
|
|
6
|
+
- refactor aggregate builder into editor tab (2e1315c)
|
|
7
|
+
- implement aggregate controller generation (7bb53a1)
|
|
8
|
+
- migrate dev configurator and enhance doctype management (d8c2589)
|
|
9
|
+
- implement aggregate designer and codegen locking (160ca87)
|
|
10
|
+
- refactor API to modular routers and add role discovery (b0a37fa)
|
|
11
|
+
- implement code-first MX repositories and AST tools (635da9a)
|
|
12
|
+
|
|
13
|
+
### Bug Fixes
|
|
14
|
+
|
|
15
|
+
- delete aggregate page related exports (dbdd28d)
|
|
16
|
+
- lint backend and frontend (170d500)
|
|
17
|
+
- build error for edit.tsx (36e791b)
|
|
18
|
+
|
|
19
|
+
## framework-m-studio v0.11.0
|
|
20
|
+
|
|
21
|
+
### Features
|
|
22
|
+
|
|
23
|
+
- update scaffolding templates for virtual modules and vite dedupe (6e20d30)
|
|
24
|
+
|
|
1
25
|
## framework-m-studio v0.10.2
|
|
2
26
|
|
|
3
27
|
### Bug Fixes
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: framework-m-studio
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.12.0
|
|
4
4
|
Summary: Framework M Studio - Visual DocType Builder & Developer Tools
|
|
5
5
|
Project-URL: Homepage, https://gitlab.com/castlecraft/framework-m
|
|
6
6
|
Project-URL: Documentation, https://gitlab.com/castlecraft/framework-m#readme
|
|
@@ -20,8 +20,8 @@ Classifier: Typing :: Typed
|
|
|
20
20
|
Requires-Python: >=3.12
|
|
21
21
|
Requires-Dist: bandit>=1.9.4
|
|
22
22
|
Requires-Dist: build>=1.0.0
|
|
23
|
-
Requires-Dist: framework-m-core>=0.
|
|
24
|
-
Requires-Dist: framework-m>=0.
|
|
23
|
+
Requires-Dist: framework-m-core>=0.14.0
|
|
24
|
+
Requires-Dist: framework-m>=0.8.0
|
|
25
25
|
Requires-Dist: honcho>=1.1.0
|
|
26
26
|
Requires-Dist: httpx>=0.27.0
|
|
27
27
|
Requires-Dist: ipython>=9.11.0
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[project]
|
|
2
2
|
name = "framework-m-studio"
|
|
3
|
-
version = "0.
|
|
3
|
+
version = "0.12.0"
|
|
4
4
|
description = "Framework M Studio - Visual DocType Builder & Developer Tools"
|
|
5
5
|
readme = "README.md"
|
|
6
6
|
license = { text = "Apache-2.0" }
|
|
@@ -21,8 +21,8 @@ classifiers = [
|
|
|
21
21
|
]
|
|
22
22
|
|
|
23
23
|
dependencies = [
|
|
24
|
-
"framework-m-core>=0.
|
|
25
|
-
"framework-m>=0.
|
|
24
|
+
"framework-m-core>=0.14.0",
|
|
25
|
+
"framework-m>=0.8.0",
|
|
26
26
|
# Code generation
|
|
27
27
|
"libcst>=1.0.0",
|
|
28
28
|
"jinja2>=3.1.0",
|
|
@@ -125,6 +125,10 @@ filterwarnings = [
|
|
|
125
125
|
[tool.coverage.run]
|
|
126
126
|
source = ["src/framework_m_studio"]
|
|
127
127
|
branch = true
|
|
128
|
+
omit = [
|
|
129
|
+
"*/tests/*",
|
|
130
|
+
"*conftest.py",
|
|
131
|
+
]
|
|
128
132
|
|
|
129
133
|
[tool.mypy]
|
|
130
134
|
python_version = "3.12"
|
|
@@ -140,14 +144,6 @@ exclude = [
|
|
|
140
144
|
"src/doctypes/",
|
|
141
145
|
]
|
|
142
146
|
|
|
143
|
-
[[tool.mypy.overrides]]
|
|
144
|
-
module = "framework_m.core.fields.registry"
|
|
145
|
-
ignore_missing_imports = true
|
|
146
|
-
|
|
147
|
-
[[tool.mypy.overrides]]
|
|
148
|
-
module = "honcho.*"
|
|
149
|
-
ignore_missing_imports = true
|
|
150
|
-
|
|
151
147
|
[[tool.mypy.overrides]]
|
|
152
148
|
module = "yaml"
|
|
153
149
|
ignore_missing_imports = true
|
|
@@ -16,6 +16,15 @@ import importlib.metadata
|
|
|
16
16
|
try:
|
|
17
17
|
__version__ = importlib.metadata.version("framework-m-studio")
|
|
18
18
|
except importlib.metadata.PackageNotFoundError:
|
|
19
|
-
__version__ = "0.0.0"
|
|
19
|
+
__version__ = "0.0.0" # pragma: no cover
|
|
20
20
|
|
|
21
|
-
|
|
21
|
+
app = {
|
|
22
|
+
"name": "framework-m-studio",
|
|
23
|
+
"version": __version__,
|
|
24
|
+
"title": "Studio",
|
|
25
|
+
"description": "Visual DocType Builder & Developer Tools",
|
|
26
|
+
"color": "#8B5CF6",
|
|
27
|
+
"icon": "Paintbrush",
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
__all__ = ["__version__", "app"]
|
|
@@ -10,6 +10,7 @@ Usage:
|
|
|
10
10
|
|
|
11
11
|
from __future__ import annotations
|
|
12
12
|
|
|
13
|
+
import os
|
|
13
14
|
from pathlib import Path
|
|
14
15
|
from typing import Any
|
|
15
16
|
|
|
@@ -18,7 +19,7 @@ from litestar.config.cors import CORSConfig
|
|
|
18
19
|
from litestar.response import File, Redirect
|
|
19
20
|
from litestar.static_files import create_static_files_router
|
|
20
21
|
|
|
21
|
-
from framework_m_studio.routes import
|
|
22
|
+
from framework_m_studio.routes import api_router
|
|
22
23
|
|
|
23
24
|
# Path to static files (built React app)
|
|
24
25
|
STATIC_DIR = Path(__file__).parent / "static"
|
|
@@ -172,6 +173,8 @@ async def list_field_types() -> dict[str, Any]:
|
|
|
172
173
|
try:
|
|
173
174
|
from framework_m_standard.adapters.db.field_registry import FieldRegistry
|
|
174
175
|
|
|
176
|
+
from framework_m_studio.data_elements import DataElementRegistry
|
|
177
|
+
|
|
175
178
|
types_list = []
|
|
176
179
|
for type_info in FieldRegistry.get_instance().get_all_types():
|
|
177
180
|
types_list.append(
|
|
@@ -184,8 +187,81 @@ async def list_field_types() -> dict[str, Any]:
|
|
|
184
187
|
"validators": type_info.validators,
|
|
185
188
|
}
|
|
186
189
|
)
|
|
187
|
-
|
|
188
|
-
|
|
190
|
+
|
|
191
|
+
# Load Blueprints (Data Elements)
|
|
192
|
+
element_registry = DataElementRegistry()
|
|
193
|
+
|
|
194
|
+
# 1. Load OOTB blueprints from Studio resources
|
|
195
|
+
studio_blueprints_dir = Path(__file__).parent / "resources" / "blueprints"
|
|
196
|
+
if studio_blueprints_dir.exists():
|
|
197
|
+
for p in studio_blueprints_dir.glob("*.json"):
|
|
198
|
+
element_registry = DataElementRegistry.merge(
|
|
199
|
+
element_registry, DataElementRegistry.from_json(p)
|
|
200
|
+
)
|
|
201
|
+
|
|
202
|
+
# 2. Load domain-specific blueprints from installed apps
|
|
203
|
+
import importlib.util
|
|
204
|
+
from importlib.metadata import entry_points
|
|
205
|
+
|
|
206
|
+
installed_apps = [
|
|
207
|
+
a.strip()
|
|
208
|
+
for a in os.environ.get("INSTALLED_APPS", "").split(",")
|
|
209
|
+
if a.strip()
|
|
210
|
+
]
|
|
211
|
+
for ep in entry_points(group="framework_m.apps"):
|
|
212
|
+
app_module = ep.module.split(":")[0]
|
|
213
|
+
if app_module not in installed_apps:
|
|
214
|
+
installed_apps.append(app_module)
|
|
215
|
+
|
|
216
|
+
for app_name in installed_apps:
|
|
217
|
+
spec = importlib.util.find_spec(app_name)
|
|
218
|
+
if spec and spec.origin:
|
|
219
|
+
app_blueprints_dir = (
|
|
220
|
+
Path(spec.origin).parent / "resources" / "blueprints"
|
|
221
|
+
)
|
|
222
|
+
if app_blueprints_dir.exists(): # pragma: no cover
|
|
223
|
+
for p in app_blueprints_dir.glob("*.json"): # pragma: no cover
|
|
224
|
+
element_registry = DataElementRegistry.merge(
|
|
225
|
+
element_registry, DataElementRegistry.from_json(p)
|
|
226
|
+
)
|
|
227
|
+
|
|
228
|
+
# 3. Load custom blueprints from project root
|
|
229
|
+
project_blueprints_dir = Path.cwd() / "blueprints"
|
|
230
|
+
if project_blueprints_dir.exists(): # pragma: no cover
|
|
231
|
+
for p in project_blueprints_dir.glob("*.json"): # pragma: no cover
|
|
232
|
+
element_registry = DataElementRegistry.merge(
|
|
233
|
+
element_registry, DataElementRegistry.from_json(p)
|
|
234
|
+
) # pragma: no cover
|
|
235
|
+
|
|
236
|
+
blueprint_list = []
|
|
237
|
+
for elem in element_registry.elements.values():
|
|
238
|
+
# Find base type to inherit ui_widget and pydantic_type
|
|
239
|
+
base_type = next(
|
|
240
|
+
(t for t in types_list if t["name"] == elem.fieldtype), None
|
|
241
|
+
)
|
|
242
|
+
ui_widget = base_type["ui_widget"] if base_type else "text"
|
|
243
|
+
pydantic_type = base_type["pydantic_type"] if base_type else "str"
|
|
244
|
+
|
|
245
|
+
validators: dict[str, Any] = {}
|
|
246
|
+
if elem.validation:
|
|
247
|
+
validators["pattern"] = elem.validation
|
|
248
|
+
if elem.length:
|
|
249
|
+
validators["max_length"] = elem.length
|
|
250
|
+
|
|
251
|
+
blueprint_list.append(
|
|
252
|
+
{
|
|
253
|
+
"name": elem.id,
|
|
254
|
+
"pydantic_type": pydantic_type,
|
|
255
|
+
"label": f"💎 {elem.label}", # Visual indicator for blueprints
|
|
256
|
+
"ui_widget": ui_widget,
|
|
257
|
+
"category": "blueprint",
|
|
258
|
+
"domain": elem.domain,
|
|
259
|
+
"validators": validators if validators else None,
|
|
260
|
+
}
|
|
261
|
+
)
|
|
262
|
+
|
|
263
|
+
return {"field_types": types_list + blueprint_list}
|
|
264
|
+
except ImportError: # pragma: no cover
|
|
189
265
|
# Fallback to static list if framework_m not available
|
|
190
266
|
return {
|
|
191
267
|
"field_types": [
|
|
@@ -273,7 +349,7 @@ def create_app() -> Litestar:
|
|
|
273
349
|
"""Create the Studio Litestar application."""
|
|
274
350
|
route_handlers: list[Any] = [
|
|
275
351
|
studio_api_router,
|
|
276
|
-
|
|
352
|
+
api_router, # All Domain API Routers
|
|
277
353
|
]
|
|
278
354
|
# Always include favicon and redirects
|
|
279
355
|
route_handlers.extend(
|
|
@@ -288,7 +364,7 @@ def create_app() -> Litestar:
|
|
|
288
364
|
# and static assets.
|
|
289
365
|
|
|
290
366
|
# Static assets (js/css/images)
|
|
291
|
-
if STATIC_DIR.exists():
|
|
367
|
+
if STATIC_DIR.exists(): # pragma: no cover
|
|
292
368
|
route_handlers.append(
|
|
293
369
|
create_static_files_router(
|
|
294
370
|
path="/studio/ui/assets",
|
|
@@ -49,8 +49,8 @@ def _check_pnpm_outdated(root: Path) -> list[dict[str, str]]:
|
|
|
49
49
|
"latest": details.get("latest", ""),
|
|
50
50
|
}
|
|
51
51
|
)
|
|
52
|
-
except json.JSONDecodeError:
|
|
53
|
-
pass
|
|
52
|
+
except json.JSONDecodeError: # pragma: no cover
|
|
53
|
+
pass # pragma: no cover
|
|
54
54
|
return outdated
|
|
55
55
|
|
|
56
56
|
|
|
@@ -104,8 +104,8 @@ def _get_workspace_projects(
|
|
|
104
104
|
)
|
|
105
105
|
projects.append(proj_name)
|
|
106
106
|
break
|
|
107
|
-
except Exception:
|
|
108
|
-
pass
|
|
107
|
+
except Exception: # pragma: no cover
|
|
108
|
+
pass # pragma: no cover
|
|
109
109
|
elif manager == "pnpm":
|
|
110
110
|
pkg_json = item / "package.json"
|
|
111
111
|
if pkg_json.exists():
|
|
@@ -123,8 +123,8 @@ def _get_workspace_projects(
|
|
|
123
123
|
and "name" in data
|
|
124
124
|
):
|
|
125
125
|
projects.append(data["name"])
|
|
126
|
-
except Exception:
|
|
127
|
-
pass
|
|
126
|
+
except Exception: # pragma: no cover
|
|
127
|
+
pass # pragma: no cover
|
|
128
128
|
return sorted(set(projects))
|
|
129
129
|
|
|
130
130
|
|
|
@@ -243,18 +243,18 @@ async def deps_upgrade_command(
|
|
|
243
243
|
run_cmd("pnpm update -r", cwd=root_path)
|
|
244
244
|
print("Running pnpm audit fix...")
|
|
245
245
|
run_cmd("pnpm audit fix", cwd=root_path, check=False)
|
|
246
|
-
else:
|
|
247
|
-
print(f"Unknown manager: {manager}", file=sys.stderr)
|
|
248
|
-
return
|
|
246
|
+
else: # pragma: no cover
|
|
247
|
+
print(f"Unknown manager: {manager}", file=sys.stderr) # pragma: no cover
|
|
248
|
+
return # pragma: no cover
|
|
249
249
|
package = "all"
|
|
250
250
|
else:
|
|
251
251
|
if manager == "uv":
|
|
252
252
|
run_cmd(f"uv lock --upgrade-package {package}", cwd=root_path)
|
|
253
253
|
elif manager == "pnpm":
|
|
254
254
|
run_cmd(f"pnpm update -r {package}", cwd=root_path)
|
|
255
|
-
else:
|
|
256
|
-
print(f"Unknown manager: {manager}", file=sys.stderr)
|
|
257
|
-
return
|
|
255
|
+
else: # pragma: no cover
|
|
256
|
+
print(f"Unknown manager: {manager}", file=sys.stderr) # pragma: no cover
|
|
257
|
+
return # pragma: no cover
|
|
258
258
|
|
|
259
259
|
# Check if anything actually changed
|
|
260
260
|
new_uv_mtime = uv_lock.stat().st_mtime if uv_lock.exists() else 0
|
|
@@ -38,12 +38,6 @@ from pathlib import Path
|
|
|
38
38
|
from typing import Annotated, Any
|
|
39
39
|
|
|
40
40
|
import cyclopts
|
|
41
|
-
from framework_m_core.dev_config import (
|
|
42
|
-
get_default_processes,
|
|
43
|
-
load_dev_config_from_toml,
|
|
44
|
-
load_procfile,
|
|
45
|
-
merge_process_configs,
|
|
46
|
-
)
|
|
47
41
|
|
|
48
42
|
from framework_m_studio.cli.constants import (
|
|
49
43
|
DEFAULT_BACKEND_PORT,
|
|
@@ -56,6 +50,12 @@ from framework_m_studio.core.frontend import (
|
|
|
56
50
|
generate_plugin_entry,
|
|
57
51
|
generate_vite_config,
|
|
58
52
|
)
|
|
53
|
+
from framework_m_studio.dev_config import (
|
|
54
|
+
get_default_processes,
|
|
55
|
+
load_dev_config_from_toml,
|
|
56
|
+
load_procfile,
|
|
57
|
+
merge_process_configs,
|
|
58
|
+
)
|
|
59
59
|
|
|
60
60
|
|
|
61
61
|
def _load_honcho_symbols() -> tuple[Any, Any]:
|
|
@@ -399,9 +399,9 @@ def new_doctype_command(
|
|
|
399
399
|
- test_*.py (pytest tests)
|
|
400
400
|
|
|
401
401
|
Examples:
|
|
402
|
-
m new
|
|
403
|
-
m new
|
|
404
|
-
m new
|
|
402
|
+
m new doctype Invoice
|
|
403
|
+
m new doctype Invoice --app myapp
|
|
404
|
+
m new doctype SalesOrder --output ./my_doctypes/sales_order
|
|
405
405
|
"""
|
|
406
406
|
# Detect app if not provided
|
|
407
407
|
detected_app = detect_app(app)
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
"""Lockfile synchronization utilities for release orchestration."""
|
|
2
|
+
|
|
3
|
+
import shutil
|
|
4
|
+
import sys
|
|
5
|
+
from pathlib import Path
|
|
6
|
+
|
|
7
|
+
from framework_m_studio.core.shell import run_cmd
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
def sync_lockfiles(root: Path) -> None:
|
|
11
|
+
"""Synchronize lockfiles for diverse environments."""
|
|
12
|
+
print("📦 Synchronizing lockfiles...")
|
|
13
|
+
if (root / "pnpm-lock.yaml").exists():
|
|
14
|
+
pnpm_bin = shutil.which("pnpm")
|
|
15
|
+
if pnpm_bin:
|
|
16
|
+
try:
|
|
17
|
+
run_cmd([pnpm_bin, "install", "--no-frozen-lockfile"], check=True)
|
|
18
|
+
except Exception as e:
|
|
19
|
+
print(f"Error: pnpm lockfile sync failed: {e}", file=sys.stderr)
|
|
20
|
+
raise
|
|
21
|
+
else:
|
|
22
|
+
raise RuntimeError(
|
|
23
|
+
"pnpm-lock.yaml exists but 'pnpm' tool was not found. "
|
|
24
|
+
"Please install pnpm or ensure it's in your PATH to synchronize lockfiles."
|
|
25
|
+
)
|
|
26
|
+
|
|
27
|
+
if (root / "uv.lock").exists() or (root / "pyproject.toml").exists():
|
|
28
|
+
uv_bin = shutil.which("uv")
|
|
29
|
+
if uv_bin:
|
|
30
|
+
try:
|
|
31
|
+
run_cmd([uv_bin, "lock"], check=True)
|
|
32
|
+
except Exception as e:
|
|
33
|
+
print(f"Error: uv lockfile sync failed: {e}", file=sys.stderr)
|
|
34
|
+
raise
|
|
35
|
+
else:
|
|
36
|
+
# Only fail on uv if we explicitly have a uv.lock or need to generate one
|
|
37
|
+
if (root / "uv.lock").exists():
|
|
38
|
+
raise RuntimeError(
|
|
39
|
+
"uv.lock exists but 'uv' tool was not found. "
|
|
40
|
+
"Please install uv or ensure it's in your PATH to synchronize lockfiles."
|
|
41
|
+
)
|
|
@@ -116,8 +116,8 @@ def compute_release_plan(config: ReleaseConfig, root: Path) -> list[ReleaseUpdat
|
|
|
116
116
|
try:
|
|
117
117
|
if tag_v > file_v:
|
|
118
118
|
current_v = tag_v
|
|
119
|
-
except Exception:
|
|
120
|
-
pass
|
|
119
|
+
except Exception: # pragma: no cover
|
|
120
|
+
pass # pragma: no cover
|
|
121
121
|
|
|
122
122
|
new_v = _bump_version(current_v, bump)
|
|
123
123
|
changelog = _generate_changelog(component_commits, new_v, pkg.name)
|
|
@@ -133,7 +133,7 @@ def compute_release_plan(config: ReleaseConfig, root: Path) -> list[ReleaseUpdat
|
|
|
133
133
|
|
|
134
134
|
# 1. Propagate bumps downstream through the dependency graph
|
|
135
135
|
if not release_updates:
|
|
136
|
-
return []
|
|
136
|
+
return [] # pragma: no cover
|
|
137
137
|
|
|
138
138
|
graph = DependencyGraph(config, root)
|
|
139
139
|
graph.discover_manifest_deps()
|
|
@@ -154,12 +154,14 @@ def prepare_release(
|
|
|
154
154
|
if sbom:
|
|
155
155
|
syft_bin = shutil.which("syft")
|
|
156
156
|
if not syft_bin:
|
|
157
|
-
print(
|
|
157
|
+
print(
|
|
158
|
+
"Warning: 'syft' not found, skipping SBOM.", file=sys.stderr
|
|
159
|
+
) # pragma: no cover
|
|
158
160
|
sbom = False
|
|
159
161
|
else:
|
|
160
162
|
try:
|
|
161
163
|
run_cmd(f"syft scan dir:{root} -o json > {root}/sbom.json")
|
|
162
|
-
except Exception:
|
|
164
|
+
except Exception: # pragma: no cover
|
|
163
165
|
print("Warning: syft failed, skipping SBOM.", file=sys.stderr)
|
|
164
166
|
sbom = False
|
|
165
167
|
|
|
@@ -201,37 +203,9 @@ def prepare_release(
|
|
|
201
203
|
target_file.write_text(new_content)
|
|
202
204
|
|
|
203
205
|
# 3. Synchronize lockfiles for diverse environments
|
|
204
|
-
|
|
205
|
-
if (root / "pnpm-lock.yaml").exists():
|
|
206
|
-
pnpm_bin = shutil.which("pnpm")
|
|
207
|
-
if pnpm_bin:
|
|
208
|
-
# We MUST succeed here to avoid CI frozen-lockfile mismatch
|
|
209
|
-
try:
|
|
210
|
-
run_cmd([pnpm_bin, "install", "--no-frozen-lockfile"], check=True)
|
|
211
|
-
except Exception as e:
|
|
212
|
-
print(f"Error: pnpm lockfile sync failed: {e}", file=sys.stderr)
|
|
213
|
-
raise
|
|
214
|
-
else:
|
|
215
|
-
raise RuntimeError(
|
|
216
|
-
"pnpm-lock.yaml exists but 'pnpm' tool was not found. "
|
|
217
|
-
"Please install pnpm or ensure it's in your PATH to synchronize lockfiles."
|
|
218
|
-
)
|
|
206
|
+
from .lockfile_sync import sync_lockfiles
|
|
219
207
|
|
|
220
|
-
|
|
221
|
-
uv_bin = shutil.which("uv")
|
|
222
|
-
if uv_bin:
|
|
223
|
-
try:
|
|
224
|
-
run_cmd([uv_bin, "lock"], check=True)
|
|
225
|
-
except Exception as e:
|
|
226
|
-
print(f"Error: uv lockfile sync failed: {e}", file=sys.stderr)
|
|
227
|
-
raise
|
|
228
|
-
else:
|
|
229
|
-
# Only fail on uv if we explicitly have a uv.lock or need to generate one
|
|
230
|
-
if (root / "uv.lock").exists():
|
|
231
|
-
raise RuntimeError(
|
|
232
|
-
"uv.lock exists but 'uv' tool was not found. "
|
|
233
|
-
"Please install uv or ensure it's in your PATH to synchronize lockfiles."
|
|
234
|
-
)
|
|
208
|
+
sync_lockfiles(root)
|
|
235
209
|
|
|
236
210
|
|
|
237
211
|
async def create_or_update_mr(
|
{framework_m_studio-0.10.2 → framework_m_studio-0.12.0}/src/framework_m_studio/codegen/__init__.py
RENAMED
|
@@ -9,12 +9,11 @@ This package provides:
|
|
|
9
9
|
|
|
10
10
|
from framework_m_studio.codegen.generator import (
|
|
11
11
|
generate_doctype_source,
|
|
12
|
-
update_doctype_source,
|
|
13
12
|
)
|
|
14
13
|
from framework_m_studio.codegen.parser import (
|
|
15
|
-
ConfigSchema,
|
|
16
14
|
DocTypeSchema,
|
|
17
15
|
FieldSchema,
|
|
16
|
+
MetaSchema,
|
|
18
17
|
parse_doctype,
|
|
19
18
|
)
|
|
20
19
|
from framework_m_studio.codegen.test_generator import (
|
|
@@ -23,12 +22,11 @@ from framework_m_studio.codegen.test_generator import (
|
|
|
23
22
|
)
|
|
24
23
|
|
|
25
24
|
__all__ = [
|
|
26
|
-
"ConfigSchema",
|
|
27
25
|
"DocTypeSchema",
|
|
28
26
|
"FieldSchema",
|
|
27
|
+
"MetaSchema",
|
|
29
28
|
"generate_doctype_source",
|
|
30
29
|
"generate_test",
|
|
31
30
|
"generate_test_file",
|
|
32
31
|
"parse_doctype",
|
|
33
|
-
"update_doctype_source",
|
|
34
32
|
]
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
"""Annotation Parser - Extracts field metadata from LibCST annotation nodes."""
|
|
2
|
+
|
|
3
|
+
from typing import Any
|
|
4
|
+
|
|
5
|
+
import libcst as cst
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
def node_to_source(node: cst.CSTNode) -> str:
|
|
9
|
+
"""Convert CST node to source code string."""
|
|
10
|
+
return cst.Module(body=[]).code_for_node(node)
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
def extract_annotated_metadata(
|
|
14
|
+
type_node: cst.BaseExpression,
|
|
15
|
+
) -> tuple[str | None, str | None, str]:
|
|
16
|
+
"""Extract link_doctype, table_doctype, and base type from Annotated."""
|
|
17
|
+
field_type = node_to_source(type_node)
|
|
18
|
+
|
|
19
|
+
if isinstance(type_node, cst.BinaryOperation):
|
|
20
|
+
left_link, left_table, left_type = extract_annotated_metadata(type_node.left)
|
|
21
|
+
if left_link or left_table:
|
|
22
|
+
return left_link, left_table, left_type
|
|
23
|
+
right_link, right_table, right_type = extract_annotated_metadata(
|
|
24
|
+
type_node.right
|
|
25
|
+
)
|
|
26
|
+
return right_link, right_table, right_type
|
|
27
|
+
|
|
28
|
+
if isinstance(type_node, cst.Subscript):
|
|
29
|
+
subscript_value = node_to_source(type_node.value)
|
|
30
|
+
if subscript_value == "Annotated":
|
|
31
|
+
slice_elements = type_node.slice
|
|
32
|
+
if isinstance(slice_elements, tuple) and len(slice_elements) >= 1:
|
|
33
|
+
first_elem = slice_elements[0]
|
|
34
|
+
if isinstance(first_elem.slice, cst.Index):
|
|
35
|
+
base_type = node_to_source(first_elem.slice.value)
|
|
36
|
+
else:
|
|
37
|
+
base_type = node_to_source(first_elem.slice)
|
|
38
|
+
|
|
39
|
+
for elem in slice_elements[1:]:
|
|
40
|
+
value = (
|
|
41
|
+
elem.slice.value
|
|
42
|
+
if isinstance(elem.slice, cst.Index)
|
|
43
|
+
else elem.slice
|
|
44
|
+
)
|
|
45
|
+
if isinstance(value, cst.Call):
|
|
46
|
+
func_name = node_to_source(value.func)
|
|
47
|
+
if func_name == "Link" and value.args:
|
|
48
|
+
arg_value = node_to_source(value.args[0].value)
|
|
49
|
+
return arg_value.strip("\"'"), None, base_type
|
|
50
|
+
if func_name == "Table" and value.args:
|
|
51
|
+
arg_value = node_to_source(value.args[0].value)
|
|
52
|
+
return None, arg_value.strip("\"'"), base_type
|
|
53
|
+
return None, None, base_type
|
|
54
|
+
|
|
55
|
+
return None, None, field_type
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
def parse_field_call(
|
|
59
|
+
node: cst.Call,
|
|
60
|
+
) -> tuple[str | None, dict[str, Any], str | None, str | None]:
|
|
61
|
+
"""Parse Field(...) call and extract default, validators, description, and label."""
|
|
62
|
+
default_value: str | None = None
|
|
63
|
+
validators: dict[str, Any] = {}
|
|
64
|
+
description: str | None = None
|
|
65
|
+
label: str | None = None
|
|
66
|
+
|
|
67
|
+
for i, arg in enumerate(node.args):
|
|
68
|
+
if arg.keyword is None and i == 0:
|
|
69
|
+
default_value = node_to_source(arg.value)
|
|
70
|
+
continue
|
|
71
|
+
|
|
72
|
+
if isinstance(arg.keyword, cst.Name):
|
|
73
|
+
key = arg.keyword.value
|
|
74
|
+
value_str = node_to_source(arg.value)
|
|
75
|
+
|
|
76
|
+
if key == "ge":
|
|
77
|
+
val = float(value_str)
|
|
78
|
+
validators["min_value"] = int(val) if val == int(val) else val
|
|
79
|
+
elif key == "le":
|
|
80
|
+
val = float(value_str)
|
|
81
|
+
validators["max_value"] = int(val) if val == int(val) else val
|
|
82
|
+
elif key == "gt":
|
|
83
|
+
val = float(value_str)
|
|
84
|
+
validators["min_value"] = int(val) + 1 if val == int(val) else val
|
|
85
|
+
elif key == "lt":
|
|
86
|
+
val = float(value_str)
|
|
87
|
+
validators["max_value"] = int(val) - 1 if val == int(val) else val
|
|
88
|
+
elif key == "min_length":
|
|
89
|
+
validators["min_length"] = int(value_str)
|
|
90
|
+
elif key == "max_length":
|
|
91
|
+
validators["max_length"] = int(value_str)
|
|
92
|
+
elif key in ("pattern", "regex"):
|
|
93
|
+
pattern = value_str
|
|
94
|
+
if pattern.startswith("r"):
|
|
95
|
+
pattern = pattern[1:]
|
|
96
|
+
validators["pattern"] = pattern.strip("\"'")
|
|
97
|
+
elif key == "description":
|
|
98
|
+
description = value_str.strip("\"'")
|
|
99
|
+
elif key == "label":
|
|
100
|
+
label = value_str.strip("\"'")
|
|
101
|
+
elif key == "default":
|
|
102
|
+
default_value = value_str
|
|
103
|
+
|
|
104
|
+
return default_value, validators, description, label
|