atdd 0.6.1__tar.gz → 0.7.1__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.
- {atdd-0.6.1/src/atdd.egg-info → atdd-0.7.1}/PKG-INFO +1 -1
- {atdd-0.6.1 → atdd-0.7.1}/pyproject.toml +3 -1
- {atdd-0.6.1 → atdd-0.7.1}/src/atdd/coach/commands/inventory.py +10 -3
- {atdd-0.6.1 → atdd-0.7.1}/src/atdd/coach/schemas/config.schema.json +11 -0
- atdd-0.7.1/src/atdd/coach/utils/locale_phase.py +97 -0
- {atdd-0.6.1 → atdd-0.7.1}/src/atdd/coach/validators/shared_fixtures.py +49 -0
- atdd-0.7.1/src/atdd/coder/validators/test_i18n_runtime.py +171 -0
- atdd-0.7.1/src/atdd/tester/schemas/locale_manifest.schema.json +53 -0
- atdd-0.7.1/src/atdd/tester/validators/test_locale_coverage.py +451 -0
- {atdd-0.6.1 → atdd-0.7.1/src/atdd.egg-info}/PKG-INFO +1 -1
- {atdd-0.6.1 → atdd-0.7.1}/src/atdd.egg-info/SOURCES.txt +4 -0
- {atdd-0.6.1 → atdd-0.7.1}/LICENSE +0 -0
- {atdd-0.6.1 → atdd-0.7.1}/README.md +0 -0
- {atdd-0.6.1 → atdd-0.7.1}/setup.cfg +0 -0
- {atdd-0.6.1 → atdd-0.7.1}/src/atdd/__init__.py +0 -0
- {atdd-0.6.1 → atdd-0.7.1}/src/atdd/__main__.py +0 -0
- {atdd-0.6.1 → atdd-0.7.1}/src/atdd/cli.py +0 -0
- {atdd-0.6.1 → atdd-0.7.1}/src/atdd/coach/__init__.py +0 -0
- {atdd-0.6.1 → atdd-0.7.1}/src/atdd/coach/commands/__init__.py +0 -0
- {atdd-0.6.1 → atdd-0.7.1}/src/atdd/coach/commands/add_persistence_metadata.py +0 -0
- {atdd-0.6.1 → atdd-0.7.1}/src/atdd/coach/commands/analyze_migrations.py +0 -0
- {atdd-0.6.1 → atdd-0.7.1}/src/atdd/coach/commands/consumers.py +0 -0
- {atdd-0.6.1 → atdd-0.7.1}/src/atdd/coach/commands/gate.py +0 -0
- {atdd-0.6.1 → atdd-0.7.1}/src/atdd/coach/commands/infer_governance_status.py +0 -0
- {atdd-0.6.1 → atdd-0.7.1}/src/atdd/coach/commands/initializer.py +0 -0
- {atdd-0.6.1 → atdd-0.7.1}/src/atdd/coach/commands/interface.py +0 -0
- {atdd-0.6.1 → atdd-0.7.1}/src/atdd/coach/commands/migration.py +0 -0
- {atdd-0.6.1 → atdd-0.7.1}/src/atdd/coach/commands/registry.py +0 -0
- {atdd-0.6.1 → atdd-0.7.1}/src/atdd/coach/commands/session.py +0 -0
- {atdd-0.6.1 → atdd-0.7.1}/src/atdd/coach/commands/sync.py +0 -0
- {atdd-0.6.1 → atdd-0.7.1}/src/atdd/coach/commands/test_interface.py +0 -0
- {atdd-0.6.1 → atdd-0.7.1}/src/atdd/coach/commands/test_runner.py +0 -0
- {atdd-0.6.1 → atdd-0.7.1}/src/atdd/coach/commands/tests/__init__.py +0 -0
- {atdd-0.6.1 → atdd-0.7.1}/src/atdd/coach/commands/tests/test_telemetry_array_validation.py +0 -0
- {atdd-0.6.1 → atdd-0.7.1}/src/atdd/coach/commands/traceability.py +0 -0
- {atdd-0.6.1 → atdd-0.7.1}/src/atdd/coach/conventions/session.convention.yaml +0 -0
- {atdd-0.6.1 → atdd-0.7.1}/src/atdd/coach/overlays/__init__.py +0 -0
- {atdd-0.6.1 → atdd-0.7.1}/src/atdd/coach/overlays/claude.md +0 -0
- {atdd-0.6.1 → atdd-0.7.1}/src/atdd/coach/schemas/manifest.schema.json +0 -0
- {atdd-0.6.1 → atdd-0.7.1}/src/atdd/coach/templates/ATDD.md +0 -0
- {atdd-0.6.1 → atdd-0.7.1}/src/atdd/coach/templates/SESSION-TEMPLATE.md +0 -0
- {atdd-0.6.1 → atdd-0.7.1}/src/atdd/coach/utils/__init__.py +0 -0
- {atdd-0.6.1 → atdd-0.7.1}/src/atdd/coach/utils/config.py +0 -0
- {atdd-0.6.1 → atdd-0.7.1}/src/atdd/coach/utils/coverage_phase.py +0 -0
- {atdd-0.6.1 → atdd-0.7.1}/src/atdd/coach/utils/graph/__init__.py +0 -0
- {atdd-0.6.1 → atdd-0.7.1}/src/atdd/coach/utils/graph/urn.py +0 -0
- {atdd-0.6.1 → atdd-0.7.1}/src/atdd/coach/utils/repo.py +0 -0
- {atdd-0.6.1 → atdd-0.7.1}/src/atdd/coach/utils/train_spec_phase.py +0 -0
- {atdd-0.6.1 → atdd-0.7.1}/src/atdd/coach/validators/__init__.py +0 -0
- {atdd-0.6.1 → atdd-0.7.1}/src/atdd/coach/validators/test_enrich_wagon_registry.py +0 -0
- {atdd-0.6.1 → atdd-0.7.1}/src/atdd/coach/validators/test_registry.py +0 -0
- {atdd-0.6.1 → atdd-0.7.1}/src/atdd/coach/validators/test_release_versioning.py +0 -0
- {atdd-0.6.1 → atdd-0.7.1}/src/atdd/coach/validators/test_session_validation.py +0 -0
- {atdd-0.6.1 → atdd-0.7.1}/src/atdd/coach/validators/test_traceability.py +0 -0
- {atdd-0.6.1 → atdd-0.7.1}/src/atdd/coach/validators/test_train_registry.py +0 -0
- {atdd-0.6.1 → atdd-0.7.1}/src/atdd/coach/validators/test_update_feature_paths.py +0 -0
- {atdd-0.6.1 → atdd-0.7.1}/src/atdd/coach/validators/test_validate_contract_consumers.py +0 -0
- {atdd-0.6.1 → atdd-0.7.1}/src/atdd/coder/__init__.py +0 -0
- {atdd-0.6.1 → atdd-0.7.1}/src/atdd/coder/conventions/adapter.recipe.yaml +0 -0
- {atdd-0.6.1 → atdd-0.7.1}/src/atdd/coder/conventions/backend.convention.yaml +0 -0
- {atdd-0.6.1 → atdd-0.7.1}/src/atdd/coder/conventions/boundaries.convention.yaml +0 -0
- {atdd-0.6.1 → atdd-0.7.1}/src/atdd/coder/conventions/commons.convention.yaml +0 -0
- {atdd-0.6.1 → atdd-0.7.1}/src/atdd/coder/conventions/complexity.recipe.yaml +0 -0
- {atdd-0.6.1 → atdd-0.7.1}/src/atdd/coder/conventions/component-naming.convention.yaml +0 -0
- {atdd-0.6.1 → atdd-0.7.1}/src/atdd/coder/conventions/coverage.convention.yaml +0 -0
- {atdd-0.6.1 → atdd-0.7.1}/src/atdd/coder/conventions/design.convention.yaml +0 -0
- {atdd-0.6.1 → atdd-0.7.1}/src/atdd/coder/conventions/design.recipe.yaml +0 -0
- {atdd-0.6.1 → atdd-0.7.1}/src/atdd/coder/conventions/dto.convention.yaml +0 -0
- {atdd-0.6.1 → atdd-0.7.1}/src/atdd/coder/conventions/frontend.convention.yaml +0 -0
- {atdd-0.6.1 → atdd-0.7.1}/src/atdd/coder/conventions/green.convention.yaml +0 -0
- {atdd-0.6.1 → atdd-0.7.1}/src/atdd/coder/conventions/presentation.convention.yaml +0 -0
- {atdd-0.6.1 → atdd-0.7.1}/src/atdd/coder/conventions/refactor.convention.yaml +0 -0
- {atdd-0.6.1 → atdd-0.7.1}/src/atdd/coder/conventions/technology.convention.yaml +0 -0
- {atdd-0.6.1 → atdd-0.7.1}/src/atdd/coder/conventions/tests/__init__.py +0 -0
- {atdd-0.6.1 → atdd-0.7.1}/src/atdd/coder/conventions/tests/test_adapter_recipe.py +0 -0
- {atdd-0.6.1 → atdd-0.7.1}/src/atdd/coder/conventions/tests/test_complexity_recipe.py +0 -0
- {atdd-0.6.1 → atdd-0.7.1}/src/atdd/coder/conventions/tests/test_component_taxonomy.py +0 -0
- {atdd-0.6.1 → atdd-0.7.1}/src/atdd/coder/conventions/tests/test_component_urn_naming.py +0 -0
- {atdd-0.6.1 → atdd-0.7.1}/src/atdd/coder/conventions/tests/test_thinness_recipe.py +0 -0
- {atdd-0.6.1 → atdd-0.7.1}/src/atdd/coder/conventions/thinness.recipe.yaml +0 -0
- {atdd-0.6.1 → atdd-0.7.1}/src/atdd/coder/conventions/train.convention.yaml +0 -0
- {atdd-0.6.1 → atdd-0.7.1}/src/atdd/coder/conventions/verification.protocol.yaml +0 -0
- {atdd-0.6.1 → atdd-0.7.1}/src/atdd/coder/schemas/design_system.schema.json +0 -0
- {atdd-0.6.1 → atdd-0.7.1}/src/atdd/coder/validators/__init__.py +0 -0
- {atdd-0.6.1 → atdd-0.7.1}/src/atdd/coder/validators/conftest.py +0 -0
- {atdd-0.6.1 → atdd-0.7.1}/src/atdd/coder/validators/test_commons_structure.py +0 -0
- {atdd-0.6.1 → atdd-0.7.1}/src/atdd/coder/validators/test_complexity.py +0 -0
- {atdd-0.6.1 → atdd-0.7.1}/src/atdd/coder/validators/test_cross_language_consistency.py +0 -0
- {atdd-0.6.1 → atdd-0.7.1}/src/atdd/coder/validators/test_design_system_compliance.py +0 -0
- {atdd-0.6.1 → atdd-0.7.1}/src/atdd/coder/validators/test_dto_testing_patterns.py +0 -0
- {atdd-0.6.1 → atdd-0.7.1}/src/atdd/coder/validators/test_green_cross_stack_layers.py +0 -0
- {atdd-0.6.1 → atdd-0.7.1}/src/atdd/coder/validators/test_green_layer_dependencies.py +0 -0
- {atdd-0.6.1 → atdd-0.7.1}/src/atdd/coder/validators/test_green_python_layer_structure.py +0 -0
- {atdd-0.6.1 → atdd-0.7.1}/src/atdd/coder/validators/test_green_supabase_layer_structure.py +0 -0
- {atdd-0.6.1 → atdd-0.7.1}/src/atdd/coder/validators/test_hierarchy_coverage.py +0 -0
- {atdd-0.6.1 → atdd-0.7.1}/src/atdd/coder/validators/test_import_boundaries.py +0 -0
- {atdd-0.6.1 → atdd-0.7.1}/src/atdd/coder/validators/test_init_file_urns.py +0 -0
- {atdd-0.6.1 → atdd-0.7.1}/src/atdd/coder/validators/test_preact_layer_boundaries.py +0 -0
- {atdd-0.6.1 → atdd-0.7.1}/src/atdd/coder/validators/test_presentation_convention.py +0 -0
- {atdd-0.6.1 → atdd-0.7.1}/src/atdd/coder/validators/test_python_architecture.py +0 -0
- {atdd-0.6.1 → atdd-0.7.1}/src/atdd/coder/validators/test_quality_metrics.py +0 -0
- {atdd-0.6.1 → atdd-0.7.1}/src/atdd/coder/validators/test_station_master_pattern.py +0 -0
- {atdd-0.6.1 → atdd-0.7.1}/src/atdd/coder/validators/test_train_infrastructure.py +0 -0
- {atdd-0.6.1 → atdd-0.7.1}/src/atdd/coder/validators/test_train_urns.py +0 -0
- {atdd-0.6.1 → atdd-0.7.1}/src/atdd/coder/validators/test_typescript_architecture.py +0 -0
- {atdd-0.6.1 → atdd-0.7.1}/src/atdd/coder/validators/test_usecase_structure.py +0 -0
- {atdd-0.6.1 → atdd-0.7.1}/src/atdd/coder/validators/test_wagon_boundaries.py +0 -0
- {atdd-0.6.1 → atdd-0.7.1}/src/atdd/conftest.py +0 -0
- {atdd-0.6.1 → atdd-0.7.1}/src/atdd/planner/__init__.py +0 -0
- {atdd-0.6.1 → atdd-0.7.1}/src/atdd/planner/conventions/acceptance.convention.yaml +0 -0
- {atdd-0.6.1 → atdd-0.7.1}/src/atdd/planner/conventions/appendix.convention.yaml +0 -0
- {atdd-0.6.1 → atdd-0.7.1}/src/atdd/planner/conventions/artifact-naming.convention.yaml +0 -0
- {atdd-0.6.1 → atdd-0.7.1}/src/atdd/planner/conventions/component.convention.yaml +0 -0
- {atdd-0.6.1 → atdd-0.7.1}/src/atdd/planner/conventions/coverage.convention.yaml +0 -0
- {atdd-0.6.1 → atdd-0.7.1}/src/atdd/planner/conventions/criteria.convention.yaml +0 -0
- {atdd-0.6.1 → atdd-0.7.1}/src/atdd/planner/conventions/feature.convention.yaml +0 -0
- {atdd-0.6.1 → atdd-0.7.1}/src/atdd/planner/conventions/interface.convention.yaml +0 -0
- {atdd-0.6.1 → atdd-0.7.1}/src/atdd/planner/conventions/steps.convention.yaml +0 -0
- {atdd-0.6.1 → atdd-0.7.1}/src/atdd/planner/conventions/train.convention.yaml +0 -0
- {atdd-0.6.1 → atdd-0.7.1}/src/atdd/planner/conventions/wagon.convention.yaml +0 -0
- {atdd-0.6.1 → atdd-0.7.1}/src/atdd/planner/conventions/wmbt.convention.yaml +0 -0
- {atdd-0.6.1 → atdd-0.7.1}/src/atdd/planner/schemas/acceptance.schema.json +0 -0
- {atdd-0.6.1 → atdd-0.7.1}/src/atdd/planner/schemas/appendix.schema.json +0 -0
- {atdd-0.6.1 → atdd-0.7.1}/src/atdd/planner/schemas/component.schema.json +0 -0
- {atdd-0.6.1 → atdd-0.7.1}/src/atdd/planner/schemas/feature.schema.json +0 -0
- {atdd-0.6.1 → atdd-0.7.1}/src/atdd/planner/schemas/train.schema.json +0 -0
- {atdd-0.6.1 → atdd-0.7.1}/src/atdd/planner/schemas/wagon.schema.json +0 -0
- {atdd-0.6.1 → atdd-0.7.1}/src/atdd/planner/schemas/wmbt.schema.json +0 -0
- {atdd-0.6.1 → atdd-0.7.1}/src/atdd/planner/validators/__init__.py +0 -0
- {atdd-0.6.1 → atdd-0.7.1}/src/atdd/planner/validators/conftest.py +0 -0
- {atdd-0.6.1 → atdd-0.7.1}/src/atdd/planner/validators/test_draft_wagon_registry.py +0 -0
- {atdd-0.6.1 → atdd-0.7.1}/src/atdd/planner/validators/test_hierarchy_coverage.py +0 -0
- {atdd-0.6.1 → atdd-0.7.1}/src/atdd/planner/validators/test_plan_cross_refs.py +0 -0
- {atdd-0.6.1 → atdd-0.7.1}/src/atdd/planner/validators/test_plan_uniqueness.py +0 -0
- {atdd-0.6.1 → atdd-0.7.1}/src/atdd/planner/validators/test_plan_urn_resolution.py +0 -0
- {atdd-0.6.1 → atdd-0.7.1}/src/atdd/planner/validators/test_plan_wagons.py +0 -0
- {atdd-0.6.1 → atdd-0.7.1}/src/atdd/planner/validators/test_train_validation.py +0 -0
- {atdd-0.6.1 → atdd-0.7.1}/src/atdd/planner/validators/test_wagon_urn_chain.py +0 -0
- {atdd-0.6.1 → atdd-0.7.1}/src/atdd/planner/validators/test_wmbt_consistency.py +0 -0
- {atdd-0.6.1 → atdd-0.7.1}/src/atdd/planner/validators/test_wmbt_vocabulary.py +0 -0
- {atdd-0.6.1 → atdd-0.7.1}/src/atdd/tester/__init__.py +0 -0
- {atdd-0.6.1 → atdd-0.7.1}/src/atdd/tester/conventions/artifact.convention.yaml +0 -0
- {atdd-0.6.1 → atdd-0.7.1}/src/atdd/tester/conventions/contract.convention.yaml +0 -0
- {atdd-0.6.1 → atdd-0.7.1}/src/atdd/tester/conventions/coverage.convention.yaml +0 -0
- {atdd-0.6.1 → atdd-0.7.1}/src/atdd/tester/conventions/filename.convention.yaml +0 -0
- {atdd-0.6.1 → atdd-0.7.1}/src/atdd/tester/conventions/migration.convention.yaml +0 -0
- {atdd-0.6.1 → atdd-0.7.1}/src/atdd/tester/conventions/red.convention.yaml +0 -0
- {atdd-0.6.1 → atdd-0.7.1}/src/atdd/tester/conventions/routing.convention.yaml +0 -0
- {atdd-0.6.1 → atdd-0.7.1}/src/atdd/tester/conventions/security.convention.yaml +0 -0
- {atdd-0.6.1 → atdd-0.7.1}/src/atdd/tester/conventions/telemetry.convention.yaml +0 -0
- {atdd-0.6.1 → atdd-0.7.1}/src/atdd/tester/schemas/a11y.tmpl.json +0 -0
- {atdd-0.6.1 → atdd-0.7.1}/src/atdd/tester/schemas/artifact.schema.json +0 -0
- {atdd-0.6.1 → atdd-0.7.1}/src/atdd/tester/schemas/contract.schema.json +0 -0
- {atdd-0.6.1 → atdd-0.7.1}/src/atdd/tester/schemas/contract.tmpl.json +0 -0
- {atdd-0.6.1 → atdd-0.7.1}/src/atdd/tester/schemas/db.tmpl.json +0 -0
- {atdd-0.6.1 → atdd-0.7.1}/src/atdd/tester/schemas/e2e.tmpl.json +0 -0
- {atdd-0.6.1 → atdd-0.7.1}/src/atdd/tester/schemas/edge_function.tmpl.json +0 -0
- {atdd-0.6.1 → atdd-0.7.1}/src/atdd/tester/schemas/event.tmpl.json +0 -0
- {atdd-0.6.1 → atdd-0.7.1}/src/atdd/tester/schemas/http.tmpl.json +0 -0
- {atdd-0.6.1 → atdd-0.7.1}/src/atdd/tester/schemas/job.tmpl.json +0 -0
- {atdd-0.6.1 → atdd-0.7.1}/src/atdd/tester/schemas/load.tmpl.json +0 -0
- {atdd-0.6.1 → atdd-0.7.1}/src/atdd/tester/schemas/metric.tmpl.json +0 -0
- {atdd-0.6.1 → atdd-0.7.1}/src/atdd/tester/schemas/pack.schema.json +0 -0
- {atdd-0.6.1 → atdd-0.7.1}/src/atdd/tester/schemas/realtime.tmpl.json +0 -0
- {atdd-0.6.1 → atdd-0.7.1}/src/atdd/tester/schemas/rls.tmpl.json +0 -0
- {atdd-0.6.1 → atdd-0.7.1}/src/atdd/tester/schemas/script.tmpl.json +0 -0
- {atdd-0.6.1 → atdd-0.7.1}/src/atdd/tester/schemas/sec.tmpl.json +0 -0
- {atdd-0.6.1 → atdd-0.7.1}/src/atdd/tester/schemas/storage.tmpl.json +0 -0
- {atdd-0.6.1 → atdd-0.7.1}/src/atdd/tester/schemas/telemetry.schema.json +0 -0
- {atdd-0.6.1 → atdd-0.7.1}/src/atdd/tester/schemas/telemetry_tracking_manifest.schema.json +0 -0
- {atdd-0.6.1 → atdd-0.7.1}/src/atdd/tester/schemas/test_filename.schema.json +0 -0
- {atdd-0.6.1 → atdd-0.7.1}/src/atdd/tester/schemas/test_intent.schema.json +0 -0
- {atdd-0.6.1 → atdd-0.7.1}/src/atdd/tester/schemas/unit.tmpl.json +0 -0
- {atdd-0.6.1 → atdd-0.7.1}/src/atdd/tester/schemas/visual.tmpl.json +0 -0
- {atdd-0.6.1 → atdd-0.7.1}/src/atdd/tester/schemas/ws.tmpl.json +0 -0
- {atdd-0.6.1 → atdd-0.7.1}/src/atdd/tester/utils/__init__.py +0 -0
- {atdd-0.6.1 → atdd-0.7.1}/src/atdd/tester/utils/filename.py +0 -0
- {atdd-0.6.1 → atdd-0.7.1}/src/atdd/tester/validators/__init__.py +0 -0
- {atdd-0.6.1 → atdd-0.7.1}/src/atdd/tester/validators/cleanup_duplicate_headers.py +0 -0
- {atdd-0.6.1 → atdd-0.7.1}/src/atdd/tester/validators/cleanup_duplicate_headers_v2.py +0 -0
- {atdd-0.6.1 → atdd-0.7.1}/src/atdd/tester/validators/conftest.py +0 -0
- {atdd-0.6.1 → atdd-0.7.1}/src/atdd/tester/validators/coverage_gap_report.py +0 -0
- {atdd-0.6.1 → atdd-0.7.1}/src/atdd/tester/validators/fix_dual_ac_references.py +0 -0
- {atdd-0.6.1 → atdd-0.7.1}/src/atdd/tester/validators/remove_duplicate_lines.py +0 -0
- {atdd-0.6.1 → atdd-0.7.1}/src/atdd/tester/validators/test_acceptance_urn_filename_mapping.py +0 -0
- {atdd-0.6.1 → atdd-0.7.1}/src/atdd/tester/validators/test_acceptance_urn_separator.py +0 -0
- {atdd-0.6.1 → atdd-0.7.1}/src/atdd/tester/validators/test_artifact_naming_category.py +0 -0
- {atdd-0.6.1 → atdd-0.7.1}/src/atdd/tester/validators/test_contract_schema_compliance.py +0 -0
- {atdd-0.6.1 → atdd-0.7.1}/src/atdd/tester/validators/test_contract_security.py +0 -0
- {atdd-0.6.1 → atdd-0.7.1}/src/atdd/tester/validators/test_contracts_structure.py +0 -0
- {atdd-0.6.1 → atdd-0.7.1}/src/atdd/tester/validators/test_coverage_adequacy.py +0 -0
- {atdd-0.6.1 → atdd-0.7.1}/src/atdd/tester/validators/test_dual_ac_reference.py +0 -0
- {atdd-0.6.1 → atdd-0.7.1}/src/atdd/tester/validators/test_fixture_validity.py +0 -0
- {atdd-0.6.1 → atdd-0.7.1}/src/atdd/tester/validators/test_hierarchy_coverage.py +0 -0
- {atdd-0.6.1 → atdd-0.7.1}/src/atdd/tester/validators/test_isolation.py +0 -0
- {atdd-0.6.1 → atdd-0.7.1}/src/atdd/tester/validators/test_migration_coverage.py +0 -0
- {atdd-0.6.1 → atdd-0.7.1}/src/atdd/tester/validators/test_migration_criteria.py +0 -0
- {atdd-0.6.1 → atdd-0.7.1}/src/atdd/tester/validators/test_migration_generation.py +0 -0
- {atdd-0.6.1 → atdd-0.7.1}/src/atdd/tester/validators/test_python_test_naming.py +0 -0
- {atdd-0.6.1 → atdd-0.7.1}/src/atdd/tester/validators/test_red_layer_validation.py +0 -0
- {atdd-0.6.1 → atdd-0.7.1}/src/atdd/tester/validators/test_red_python_layer_structure.py +0 -0
- {atdd-0.6.1 → atdd-0.7.1}/src/atdd/tester/validators/test_red_supabase_layer_structure.py +0 -0
- {atdd-0.6.1 → atdd-0.7.1}/src/atdd/tester/validators/test_telemetry_structure.py +0 -0
- {atdd-0.6.1 → atdd-0.7.1}/src/atdd/tester/validators/test_train_backend_e2e.py +0 -0
- {atdd-0.6.1 → atdd-0.7.1}/src/atdd/tester/validators/test_train_frontend_e2e.py +0 -0
- {atdd-0.6.1 → atdd-0.7.1}/src/atdd/tester/validators/test_train_frontend_python.py +0 -0
- {atdd-0.6.1 → atdd-0.7.1}/src/atdd/tester/validators/test_typescript_test_naming.py +0 -0
- {atdd-0.6.1 → atdd-0.7.1}/src/atdd/tester/validators/test_typescript_test_structure.py +0 -0
- {atdd-0.6.1 → atdd-0.7.1}/src/atdd/version_check.py +0 -0
- {atdd-0.6.1 → atdd-0.7.1}/src/atdd.egg-info/dependency_links.txt +0 -0
- {atdd-0.6.1 → atdd-0.7.1}/src/atdd.egg-info/entry_points.txt +0 -0
- {atdd-0.6.1 → atdd-0.7.1}/src/atdd.egg-info/requires.txt +0 -0
- {atdd-0.6.1 → atdd-0.7.1}/src/atdd.egg-info/top_level.txt +0 -0
|
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "atdd"
|
|
7
|
-
version = "0.
|
|
7
|
+
version = "0.7.1"
|
|
8
8
|
description = "ATDD Platform - Acceptance Test Driven Development toolkit"
|
|
9
9
|
requires-python = ">=3.10"
|
|
10
10
|
readme = "README.md"
|
|
@@ -39,4 +39,6 @@ markers = [
|
|
|
39
39
|
"tester: marks tests as tester validators",
|
|
40
40
|
"platform: marks tests as platform validators",
|
|
41
41
|
"security: marks tests as security validators",
|
|
42
|
+
"locale: marks tests as localization validators (Localization Manifest Spec v1)",
|
|
43
|
+
"coder: marks tests as coder phase validators",
|
|
42
44
|
]
|
|
@@ -148,9 +148,16 @@ class RepositoryInventory:
|
|
|
148
148
|
by_theme[theme] += 1
|
|
149
149
|
|
|
150
150
|
# Gap analysis
|
|
151
|
-
expectations = train.get("expectations"
|
|
152
|
-
test_fields = train.get("test"
|
|
153
|
-
code_fields = train.get("code"
|
|
151
|
+
expectations = train.get("expectations")
|
|
152
|
+
test_fields = train.get("test")
|
|
153
|
+
code_fields = train.get("code")
|
|
154
|
+
|
|
155
|
+
if not isinstance(expectations, dict):
|
|
156
|
+
expectations = {}
|
|
157
|
+
if test_fields is None:
|
|
158
|
+
test_fields = {}
|
|
159
|
+
if code_fields is None:
|
|
160
|
+
code_fields = {}
|
|
154
161
|
|
|
155
162
|
# Normalize test/code to dict form
|
|
156
163
|
if isinstance(test_fields, str):
|
|
@@ -121,6 +121,17 @@
|
|
|
121
121
|
}
|
|
122
122
|
},
|
|
123
123
|
"additionalProperties": false
|
|
124
|
+
},
|
|
125
|
+
"localization": {
|
|
126
|
+
"type": "object",
|
|
127
|
+
"description": "Localization validation settings (Localization Manifest Spec v1)",
|
|
128
|
+
"properties": {
|
|
129
|
+
"manifest": {
|
|
130
|
+
"type": "string",
|
|
131
|
+
"description": "Path to localization manifest.json relative to repo root (e.g., web/locales/manifest.json)"
|
|
132
|
+
}
|
|
133
|
+
},
|
|
134
|
+
"additionalProperties": false
|
|
124
135
|
}
|
|
125
136
|
},
|
|
126
137
|
"required": ["version", "release"],
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Localization Manifest Spec v1 Rollout Phase Controller.
|
|
3
|
+
|
|
4
|
+
Manages the phased rollout of localization validation rules:
|
|
5
|
+
- Phase 1 (WARNINGS_ONLY): All validators emit warnings only
|
|
6
|
+
- Phase 2 (TESTER_ENFORCEMENT): Tester phase validators (LOCALE-TEST-*) strict
|
|
7
|
+
- Phase 3 (FULL_ENFORCEMENT): All validators including Coder (LOCALE-CODE-*) strict
|
|
8
|
+
|
|
9
|
+
Usage in validators:
|
|
10
|
+
from atdd.coach.utils.locale_phase import LocalePhase, should_enforce_locale
|
|
11
|
+
|
|
12
|
+
if should_enforce_locale(LocalePhase.TESTER_ENFORCEMENT):
|
|
13
|
+
assert condition, "Error message"
|
|
14
|
+
else:
|
|
15
|
+
if not condition:
|
|
16
|
+
emit_locale_warning("LOCALE-TEST-1.1", "Warning message", LocalePhase.TESTER_ENFORCEMENT)
|
|
17
|
+
"""
|
|
18
|
+
|
|
19
|
+
from enum import IntEnum
|
|
20
|
+
from typing import Optional
|
|
21
|
+
import warnings
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
class LocalePhase(IntEnum):
|
|
25
|
+
"""
|
|
26
|
+
Rollout phases for Localization Manifest Spec v1.
|
|
27
|
+
|
|
28
|
+
Phases are ordered by strictness level:
|
|
29
|
+
- WARNINGS_ONLY (1): All new validators emit warnings, no assertions
|
|
30
|
+
- TESTER_ENFORCEMENT (2): Tester phase validators (LOCALE-TEST-*) strict
|
|
31
|
+
- FULL_ENFORCEMENT (3): All validators including Coder (LOCALE-CODE-*) strict
|
|
32
|
+
"""
|
|
33
|
+
WARNINGS_ONLY = 1
|
|
34
|
+
TESTER_ENFORCEMENT = 2
|
|
35
|
+
FULL_ENFORCEMENT = 3
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
# Current rollout phase - update this to advance through phases
|
|
39
|
+
CURRENT_LOCALE_PHASE = LocalePhase.WARNINGS_ONLY
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
def should_enforce_locale(validator_phase: LocalePhase) -> bool:
|
|
43
|
+
"""
|
|
44
|
+
Check if a locale validator should enforce strict mode.
|
|
45
|
+
|
|
46
|
+
Args:
|
|
47
|
+
validator_phase: The phase at which this validator becomes strict
|
|
48
|
+
|
|
49
|
+
Returns:
|
|
50
|
+
True if current phase >= validator_phase (should enforce)
|
|
51
|
+
False if current phase < validator_phase (should warn only)
|
|
52
|
+
|
|
53
|
+
Example:
|
|
54
|
+
# This validator becomes strict in Phase 2
|
|
55
|
+
if should_enforce_locale(LocalePhase.TESTER_ENFORCEMENT):
|
|
56
|
+
assert all_keys_match, "Keys must match reference locale"
|
|
57
|
+
else:
|
|
58
|
+
if not all_keys_match:
|
|
59
|
+
emit_locale_warning("LOCALE-TEST-1.4", "Keys don't match", LocalePhase.TESTER_ENFORCEMENT)
|
|
60
|
+
"""
|
|
61
|
+
return CURRENT_LOCALE_PHASE >= validator_phase
|
|
62
|
+
|
|
63
|
+
|
|
64
|
+
def get_current_locale_phase() -> LocalePhase:
|
|
65
|
+
"""Get the current locale rollout phase."""
|
|
66
|
+
return CURRENT_LOCALE_PHASE
|
|
67
|
+
|
|
68
|
+
|
|
69
|
+
def get_locale_phase_name(phase: Optional[LocalePhase] = None) -> str:
|
|
70
|
+
"""Get human-readable name for a locale phase."""
|
|
71
|
+
phase = phase or CURRENT_LOCALE_PHASE
|
|
72
|
+
return {
|
|
73
|
+
LocalePhase.WARNINGS_ONLY: "Phase 1: Warnings Only",
|
|
74
|
+
LocalePhase.TESTER_ENFORCEMENT: "Phase 2: Tester Enforcement",
|
|
75
|
+
LocalePhase.FULL_ENFORCEMENT: "Phase 3: Full Enforcement",
|
|
76
|
+
}.get(phase, "Unknown Phase")
|
|
77
|
+
|
|
78
|
+
|
|
79
|
+
def emit_locale_warning(
|
|
80
|
+
spec_id: str,
|
|
81
|
+
message: str,
|
|
82
|
+
validator_phase: LocalePhase = LocalePhase.TESTER_ENFORCEMENT
|
|
83
|
+
) -> None:
|
|
84
|
+
"""
|
|
85
|
+
Emit a locale validation warning with phase context.
|
|
86
|
+
|
|
87
|
+
Args:
|
|
88
|
+
spec_id: The SPEC ID (e.g., "LOCALE-TEST-1.1")
|
|
89
|
+
message: The warning message
|
|
90
|
+
validator_phase: Phase when this becomes an error
|
|
91
|
+
"""
|
|
92
|
+
phase_name = get_locale_phase_name(validator_phase)
|
|
93
|
+
warnings.warn(
|
|
94
|
+
f"[{spec_id}] {message} (will become error in {phase_name})",
|
|
95
|
+
category=UserWarning,
|
|
96
|
+
stacklevel=3
|
|
97
|
+
)
|
|
@@ -599,3 +599,52 @@ def wagon_to_train_mapping(train_files: List[Tuple[Path, Dict]]) -> Dict[str, Li
|
|
|
599
599
|
mapping[wagon_slug].append(train_id)
|
|
600
600
|
|
|
601
601
|
return mapping
|
|
602
|
+
|
|
603
|
+
|
|
604
|
+
# ============================================================================
|
|
605
|
+
# LOCALIZATION FIXTURES (Localization Manifest Spec v1)
|
|
606
|
+
# ============================================================================
|
|
607
|
+
|
|
608
|
+
|
|
609
|
+
@pytest.fixture(scope="module")
|
|
610
|
+
def locale_manifest_path(atdd_config: Dict[str, Any]) -> Optional[Path]:
|
|
611
|
+
"""
|
|
612
|
+
Get path to localization manifest file from config.
|
|
613
|
+
|
|
614
|
+
Returns:
|
|
615
|
+
Path to manifest file, or None if localization not configured
|
|
616
|
+
"""
|
|
617
|
+
manifest_rel = atdd_config.get("localization", {}).get("manifest")
|
|
618
|
+
if not manifest_rel:
|
|
619
|
+
return None
|
|
620
|
+
return REPO_ROOT / manifest_rel
|
|
621
|
+
|
|
622
|
+
|
|
623
|
+
@pytest.fixture(scope="module")
|
|
624
|
+
def locale_manifest(locale_manifest_path: Optional[Path]) -> Optional[Dict[str, Any]]:
|
|
625
|
+
"""
|
|
626
|
+
Load localization manifest from configured path.
|
|
627
|
+
|
|
628
|
+
Returns:
|
|
629
|
+
Manifest dict with reference, locales, namespaces, or None if not configured
|
|
630
|
+
"""
|
|
631
|
+
if locale_manifest_path is None:
|
|
632
|
+
return None
|
|
633
|
+
if not locale_manifest_path.exists():
|
|
634
|
+
return None
|
|
635
|
+
|
|
636
|
+
with open(locale_manifest_path) as f:
|
|
637
|
+
return json.load(f)
|
|
638
|
+
|
|
639
|
+
|
|
640
|
+
@pytest.fixture(scope="module")
|
|
641
|
+
def locales_dir(locale_manifest_path: Optional[Path]) -> Optional[Path]:
|
|
642
|
+
"""
|
|
643
|
+
Get locales directory (parent of manifest file).
|
|
644
|
+
|
|
645
|
+
Returns:
|
|
646
|
+
Path to locales directory, or None if not configured
|
|
647
|
+
"""
|
|
648
|
+
if locale_manifest_path is None:
|
|
649
|
+
return None
|
|
650
|
+
return locale_manifest_path.parent
|
|
@@ -0,0 +1,171 @@
|
|
|
1
|
+
"""
|
|
2
|
+
i18n runtime validation (Localization Manifest Spec v1).
|
|
3
|
+
|
|
4
|
+
Validates that runtime code uses the centralized locale manifest:
|
|
5
|
+
- LOCALE-CODE-2.1: i18nConfig.ts imports from manifest (not hardcoded arrays)
|
|
6
|
+
- LOCALE-CODE-2.2: LanguageSwitcher uses shared SUPPORTED_LOCALES
|
|
7
|
+
"""
|
|
8
|
+
|
|
9
|
+
import re
|
|
10
|
+
import pytest
|
|
11
|
+
from pathlib import Path
|
|
12
|
+
from typing import Optional
|
|
13
|
+
|
|
14
|
+
from atdd.coach.utils.locale_phase import (
|
|
15
|
+
LocalePhase,
|
|
16
|
+
should_enforce_locale,
|
|
17
|
+
emit_locale_warning,
|
|
18
|
+
)
|
|
19
|
+
from atdd.coach.utils.repo import find_repo_root
|
|
20
|
+
|
|
21
|
+
# Path constants
|
|
22
|
+
REPO_ROOT = find_repo_root()
|
|
23
|
+
WEB_DIR = REPO_ROOT / "web"
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
def _find_file(base_dir: Path, *possible_paths: str) -> Optional[Path]:
|
|
27
|
+
"""Find first existing file from list of possible paths."""
|
|
28
|
+
for rel_path in possible_paths:
|
|
29
|
+
full_path = base_dir / rel_path
|
|
30
|
+
if full_path.exists():
|
|
31
|
+
return full_path
|
|
32
|
+
return None
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
def _read_file_content(path: Path) -> Optional[str]:
|
|
36
|
+
"""Read file content, return None on error."""
|
|
37
|
+
try:
|
|
38
|
+
return path.read_text()
|
|
39
|
+
except Exception:
|
|
40
|
+
return None
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
@pytest.mark.locale
|
|
44
|
+
@pytest.mark.coder
|
|
45
|
+
def test_i18n_config_uses_manifest(locale_manifest, locale_manifest_path):
|
|
46
|
+
"""
|
|
47
|
+
LOCALE-CODE-2.1: i18nConfig.ts imports from manifest (not hardcoded arrays)
|
|
48
|
+
|
|
49
|
+
Given: Web application with i18n configuration
|
|
50
|
+
When: Checking i18nConfig.ts or i18n.ts
|
|
51
|
+
Then: Configuration imports locales from manifest or shared constant
|
|
52
|
+
NOT hardcoded locale arrays like ['en', 'es', 'fr']
|
|
53
|
+
"""
|
|
54
|
+
if locale_manifest is None:
|
|
55
|
+
pytest.skip("Localization not configured")
|
|
56
|
+
|
|
57
|
+
i18n_config = _find_file(
|
|
58
|
+
WEB_DIR,
|
|
59
|
+
"src/i18nConfig.ts",
|
|
60
|
+
"src/i18n/config.ts",
|
|
61
|
+
"src/i18n.ts",
|
|
62
|
+
"src/lib/i18n.ts",
|
|
63
|
+
"src/config/i18n.ts",
|
|
64
|
+
)
|
|
65
|
+
|
|
66
|
+
if i18n_config is None:
|
|
67
|
+
pytest.skip("No i18n config file found in web/src/")
|
|
68
|
+
|
|
69
|
+
content = _read_file_content(i18n_config)
|
|
70
|
+
if content is None:
|
|
71
|
+
pytest.skip(f"Cannot read {i18n_config}")
|
|
72
|
+
|
|
73
|
+
hardcoded_array_pattern = re.compile(
|
|
74
|
+
r"(?:locales|supportedLocales|SUPPORTED_LOCALES|languages)\s*[=:]\s*\[\s*['\"][a-z]{2}",
|
|
75
|
+
re.IGNORECASE
|
|
76
|
+
)
|
|
77
|
+
|
|
78
|
+
if hardcoded_array_pattern.search(content):
|
|
79
|
+
manifest_import_patterns = [
|
|
80
|
+
r"from\s+['\"].*manifest",
|
|
81
|
+
r"import.*manifest",
|
|
82
|
+
r"require\s*\(\s*['\"].*manifest",
|
|
83
|
+
r"SUPPORTED_LOCALES",
|
|
84
|
+
r"getSupportedLocales",
|
|
85
|
+
]
|
|
86
|
+
|
|
87
|
+
has_manifest_usage = any(
|
|
88
|
+
re.search(pattern, content, re.IGNORECASE)
|
|
89
|
+
for pattern in manifest_import_patterns
|
|
90
|
+
)
|
|
91
|
+
|
|
92
|
+
if not has_manifest_usage:
|
|
93
|
+
msg = (
|
|
94
|
+
f"i18n config has hardcoded locale array: {i18n_config.relative_to(REPO_ROOT)}\n"
|
|
95
|
+
f" Should import from manifest.json or use shared SUPPORTED_LOCALES constant"
|
|
96
|
+
)
|
|
97
|
+
if should_enforce_locale(LocalePhase.FULL_ENFORCEMENT):
|
|
98
|
+
pytest.fail(msg)
|
|
99
|
+
else:
|
|
100
|
+
emit_locale_warning("LOCALE-CODE-2.1", msg, LocalePhase.FULL_ENFORCEMENT)
|
|
101
|
+
pytest.skip(msg)
|
|
102
|
+
|
|
103
|
+
|
|
104
|
+
@pytest.mark.locale
|
|
105
|
+
@pytest.mark.coder
|
|
106
|
+
def test_language_switcher_uses_shared_locales(locale_manifest, locale_manifest_path):
|
|
107
|
+
"""
|
|
108
|
+
LOCALE-CODE-2.2: LanguageSwitcher uses shared SUPPORTED_LOCALES
|
|
109
|
+
|
|
110
|
+
Given: Web application with language switcher component
|
|
111
|
+
When: Checking LanguageSwitcher component
|
|
112
|
+
Then: Component imports locales from shared constant or manifest
|
|
113
|
+
NOT hardcoded locale arrays
|
|
114
|
+
"""
|
|
115
|
+
if locale_manifest is None:
|
|
116
|
+
pytest.skip("Localization not configured")
|
|
117
|
+
|
|
118
|
+
switcher_patterns = [
|
|
119
|
+
"src/components/LanguageSwitcher.tsx",
|
|
120
|
+
"src/components/LocaleSwitcher.tsx",
|
|
121
|
+
"src/components/ui/LanguageSwitcher.tsx",
|
|
122
|
+
"src/components/common/LanguageSwitcher.tsx",
|
|
123
|
+
"src/features/i18n/LanguageSwitcher.tsx",
|
|
124
|
+
]
|
|
125
|
+
|
|
126
|
+
switcher_file = _find_file(WEB_DIR, *switcher_patterns)
|
|
127
|
+
|
|
128
|
+
if switcher_file is None:
|
|
129
|
+
switcher_files = list(WEB_DIR.rglob("*[Ll]anguage*[Ss]witcher*.tsx"))
|
|
130
|
+
if not switcher_files:
|
|
131
|
+
switcher_files = list(WEB_DIR.rglob("*[Ll]ocale*[Ss]witcher*.tsx"))
|
|
132
|
+
if switcher_files:
|
|
133
|
+
switcher_file = switcher_files[0]
|
|
134
|
+
|
|
135
|
+
if switcher_file is None:
|
|
136
|
+
pytest.skip("No LanguageSwitcher component found")
|
|
137
|
+
|
|
138
|
+
content = _read_file_content(switcher_file)
|
|
139
|
+
if content is None:
|
|
140
|
+
pytest.skip(f"Cannot read {switcher_file}")
|
|
141
|
+
|
|
142
|
+
hardcoded_array_pattern = re.compile(
|
|
143
|
+
r"(?:locales|languages|options)\s*[=:]\s*\[\s*(?:\{[^}]*locale[^}]*['\"][a-z]{2}|['\"][a-z]{2})",
|
|
144
|
+
re.IGNORECASE
|
|
145
|
+
)
|
|
146
|
+
|
|
147
|
+
if hardcoded_array_pattern.search(content):
|
|
148
|
+
shared_patterns = [
|
|
149
|
+
r"SUPPORTED_LOCALES",
|
|
150
|
+
r"getSupportedLocales",
|
|
151
|
+
r"from\s+['\"].*manifest",
|
|
152
|
+
r"from\s+['\"].*i18n",
|
|
153
|
+
r"from\s+['\"].*config",
|
|
154
|
+
r"useLocales",
|
|
155
|
+
]
|
|
156
|
+
|
|
157
|
+
has_shared_usage = any(
|
|
158
|
+
re.search(pattern, content, re.IGNORECASE)
|
|
159
|
+
for pattern in shared_patterns
|
|
160
|
+
)
|
|
161
|
+
|
|
162
|
+
if not has_shared_usage:
|
|
163
|
+
msg = (
|
|
164
|
+
f"LanguageSwitcher has hardcoded locale array: {switcher_file.relative_to(REPO_ROOT)}\n"
|
|
165
|
+
f" Should import from shared SUPPORTED_LOCALES or manifest"
|
|
166
|
+
)
|
|
167
|
+
if should_enforce_locale(LocalePhase.FULL_ENFORCEMENT):
|
|
168
|
+
pytest.fail(msg)
|
|
169
|
+
else:
|
|
170
|
+
emit_locale_warning("LOCALE-CODE-2.2", msg, LocalePhase.FULL_ENFORCEMENT)
|
|
171
|
+
pytest.skip(msg)
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "http://json-schema.org/draft-07/schema#",
|
|
3
|
+
"$id": "https://atdd.dev/schemas/tester/locale_manifest.schema.json",
|
|
4
|
+
"title": "Locale Manifest",
|
|
5
|
+
"description": "Schema for localization manifest.json - single source of truth for supported locales and namespaces (Localization Manifest Spec v1)",
|
|
6
|
+
"type": "object",
|
|
7
|
+
"required": ["reference", "locales", "namespaces"],
|
|
8
|
+
"properties": {
|
|
9
|
+
"reference": {
|
|
10
|
+
"type": "string",
|
|
11
|
+
"pattern": "^[a-z]{2}(-[A-Z]{2})?$",
|
|
12
|
+
"description": "Reference locale code (e.g., 'en', 'en-US'). All other locales must match this locale's keys."
|
|
13
|
+
},
|
|
14
|
+
"locales": {
|
|
15
|
+
"type": "array",
|
|
16
|
+
"minItems": 1,
|
|
17
|
+
"items": {
|
|
18
|
+
"type": "string",
|
|
19
|
+
"pattern": "^[a-z]{2}(-[A-Z]{2})?$"
|
|
20
|
+
},
|
|
21
|
+
"uniqueItems": true,
|
|
22
|
+
"description": "List of supported locale codes. Must include the reference locale."
|
|
23
|
+
},
|
|
24
|
+
"namespaces": {
|
|
25
|
+
"type": "array",
|
|
26
|
+
"minItems": 1,
|
|
27
|
+
"items": {
|
|
28
|
+
"type": "string",
|
|
29
|
+
"pattern": "^[a-z][a-z0-9_-]*$"
|
|
30
|
+
},
|
|
31
|
+
"uniqueItems": true,
|
|
32
|
+
"description": "Required namespaces that must exist for all locales (e.g., 'common', 'ui', 'errors')"
|
|
33
|
+
},
|
|
34
|
+
"optional_namespaces": {
|
|
35
|
+
"type": "array",
|
|
36
|
+
"items": {
|
|
37
|
+
"type": "string",
|
|
38
|
+
"pattern": "^[a-z][a-z0-9_-]*$"
|
|
39
|
+
},
|
|
40
|
+
"uniqueItems": true,
|
|
41
|
+
"description": "Optional namespaces that may not exist for all locales. If present, must match reference keys."
|
|
42
|
+
}
|
|
43
|
+
},
|
|
44
|
+
"additionalProperties": false,
|
|
45
|
+
"examples": [
|
|
46
|
+
{
|
|
47
|
+
"reference": "en",
|
|
48
|
+
"locales": ["en", "es", "fr", "de", "ja"],
|
|
49
|
+
"namespaces": ["common", "ui", "errors"],
|
|
50
|
+
"optional_namespaces": ["landing", "marketing"]
|
|
51
|
+
}
|
|
52
|
+
]
|
|
53
|
+
}
|