@sun-asterisk/sungen 1.0.23 → 2.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +198 -74
- package/dist/cli/commands/add.d.ts.map +1 -1
- package/dist/cli/commands/add.js +5 -3
- package/dist/cli/commands/add.js.map +1 -1
- package/dist/cli/commands/generate.d.ts.map +1 -1
- package/dist/cli/commands/generate.js +110 -35
- package/dist/cli/commands/generate.js.map +1 -1
- package/dist/cli/index.d.ts +2 -2
- package/dist/cli/index.js +5 -16
- package/dist/cli/index.js.map +1 -1
- package/dist/generators/test-generator/adapters/playwright/templates/steps/actions/frame-enter-action.hbs +1 -0
- package/dist/generators/test-generator/adapters/playwright/templates/steps/actions/frame-exit-action.hbs +1 -0
- package/dist/generators/test-generator/adapters/playwright/templates/steps/actions/keyboard-global-action.hbs +1 -0
- package/dist/generators/test-generator/adapters/playwright/templates/steps/actions/scroll-action.hbs +1 -0
- package/dist/generators/test-generator/adapters/playwright/templates/steps/actions/table-action-in-row.hbs +2 -0
- package/dist/generators/test-generator/adapters/playwright/templates/steps/assertions/label-value-assertion.hbs +2 -0
- package/dist/generators/test-generator/adapters/playwright/templates/steps/assertions/table-cell-by-filter.hbs +3 -0
- package/dist/generators/test-generator/adapters/playwright/templates/steps/assertions/table-cell-by-index.hbs +3 -0
- package/dist/generators/test-generator/adapters/playwright/templates/steps/assertions/table-column-exists.hbs +2 -0
- package/dist/generators/test-generator/adapters/playwright/templates/steps/assertions/table-empty.hbs +2 -0
- package/dist/generators/test-generator/adapters/playwright/templates/steps/assertions/table-row-count.hbs +2 -0
- package/dist/generators/test-generator/adapters/playwright/templates/steps/assertions/table-row-exists.hbs +2 -0
- package/dist/generators/test-generator/adapters/playwright/templates/steps/assertions/table-row-not-exists.hbs +2 -0
- package/dist/generators/test-generator/adapters/playwright/templates/steps/assertions/visible-with-value-assertion.hbs +1 -1
- package/dist/generators/test-generator/adapters/playwright/templates/steps/partials/locator-base.hbs +11 -2
- package/dist/generators/test-generator/adapters/playwright/templates/steps/partials/locator.hbs +11 -2
- package/dist/generators/test-generator/code-generator.d.ts +0 -1
- package/dist/generators/test-generator/code-generator.d.ts.map +1 -1
- package/dist/generators/test-generator/code-generator.js +0 -47
- package/dist/generators/test-generator/code-generator.js.map +1 -1
- package/dist/generators/test-generator/patterns/assertion-patterns.d.ts.map +1 -1
- package/dist/generators/test-generator/patterns/assertion-patterns.js +33 -8
- package/dist/generators/test-generator/patterns/assertion-patterns.js.map +1 -1
- package/dist/generators/test-generator/patterns/index.d.ts +4 -1
- package/dist/generators/test-generator/patterns/index.d.ts.map +1 -1
- package/dist/generators/test-generator/patterns/index.js +17 -5
- package/dist/generators/test-generator/patterns/index.js.map +1 -1
- package/dist/generators/test-generator/patterns/interaction-patterns.js +1 -1
- package/dist/generators/test-generator/patterns/interaction-patterns.js.map +1 -1
- package/dist/generators/test-generator/patterns/keyboard-patterns.d.ts +7 -0
- package/dist/generators/test-generator/patterns/keyboard-patterns.d.ts.map +1 -0
- package/dist/generators/test-generator/patterns/keyboard-patterns.js +47 -0
- package/dist/generators/test-generator/patterns/keyboard-patterns.js.map +1 -0
- package/dist/generators/test-generator/patterns/scope-patterns.d.ts +7 -0
- package/dist/generators/test-generator/patterns/scope-patterns.d.ts.map +1 -0
- package/dist/generators/test-generator/patterns/scope-patterns.js +36 -0
- package/dist/generators/test-generator/patterns/scope-patterns.js.map +1 -0
- package/dist/generators/test-generator/patterns/scroll-patterns.d.ts +7 -0
- package/dist/generators/test-generator/patterns/scroll-patterns.d.ts.map +1 -0
- package/dist/generators/test-generator/patterns/scroll-patterns.js +25 -0
- package/dist/generators/test-generator/patterns/scroll-patterns.js.map +1 -0
- package/dist/generators/test-generator/patterns/table-patterns.d.ts +7 -0
- package/dist/generators/test-generator/patterns/table-patterns.d.ts.map +1 -0
- package/dist/generators/test-generator/patterns/table-patterns.js +192 -0
- package/dist/generators/test-generator/patterns/table-patterns.js.map +1 -0
- package/dist/generators/test-generator/step-mapper.d.ts +1 -3
- package/dist/generators/test-generator/step-mapper.d.ts.map +1 -1
- package/dist/generators/test-generator/step-mapper.js +36 -34
- package/dist/generators/test-generator/step-mapper.js.map +1 -1
- package/dist/generators/test-generator/template-engine.d.ts.map +1 -1
- package/dist/generators/test-generator/template-engine.js +4 -1
- package/dist/generators/test-generator/template-engine.js.map +1 -1
- package/dist/generators/test-generator/types.d.ts +7 -24
- package/dist/generators/test-generator/types.d.ts.map +1 -1
- package/dist/generators/test-generator/types.js +2 -101
- package/dist/generators/test-generator/types.js.map +1 -1
- package/dist/generators/test-generator/utils/selector-resolver.d.ts +14 -0
- package/dist/generators/test-generator/utils/selector-resolver.d.ts.map +1 -1
- package/dist/generators/test-generator/utils/selector-resolver.js +37 -11
- package/dist/generators/test-generator/utils/selector-resolver.js.map +1 -1
- package/dist/orchestrator/project-initializer.d.ts +8 -0
- package/dist/orchestrator/project-initializer.d.ts.map +1 -1
- package/dist/orchestrator/project-initializer.js +343 -32
- package/dist/orchestrator/project-initializer.js.map +1 -1
- package/dist/orchestrator/screen-manager.d.ts +1 -32
- package/dist/orchestrator/screen-manager.d.ts.map +1 -1
- package/dist/orchestrator/screen-manager.js +55 -216
- package/dist/orchestrator/screen-manager.js.map +1 -1
- package/dist/utils/selector-types.d.ts +1 -1
- package/dist/utils/selector-types.d.ts.map +1 -1
- package/dist/utils/selector-types.js +3 -0
- package/dist/utils/selector-types.js.map +1 -1
- package/package.json +2 -2
- package/src/cli/commands/add.ts +5 -3
- package/src/cli/commands/generate.ts +90 -38
- package/src/cli/index.ts +5 -16
- package/src/generators/test-generator/adapters/playwright/templates/steps/actions/frame-enter-action.hbs +1 -0
- package/src/generators/test-generator/adapters/playwright/templates/steps/actions/frame-exit-action.hbs +1 -0
- package/src/generators/test-generator/adapters/playwright/templates/steps/actions/keyboard-global-action.hbs +1 -0
- package/src/generators/test-generator/adapters/playwright/templates/steps/actions/scroll-action.hbs +1 -0
- package/src/generators/test-generator/adapters/playwright/templates/steps/actions/table-action-in-row.hbs +2 -0
- package/src/generators/test-generator/adapters/playwright/templates/steps/assertions/label-value-assertion.hbs +2 -0
- package/src/generators/test-generator/adapters/playwright/templates/steps/assertions/table-cell-by-filter.hbs +3 -0
- package/src/generators/test-generator/adapters/playwright/templates/steps/assertions/table-cell-by-index.hbs +3 -0
- package/src/generators/test-generator/adapters/playwright/templates/steps/assertions/table-column-exists.hbs +2 -0
- package/src/generators/test-generator/adapters/playwright/templates/steps/assertions/table-empty.hbs +2 -0
- package/src/generators/test-generator/adapters/playwright/templates/steps/assertions/table-row-count.hbs +2 -0
- package/src/generators/test-generator/adapters/playwright/templates/steps/assertions/table-row-exists.hbs +2 -0
- package/src/generators/test-generator/adapters/playwright/templates/steps/assertions/table-row-not-exists.hbs +2 -0
- package/src/generators/test-generator/adapters/playwright/templates/steps/assertions/visible-with-value-assertion.hbs +1 -1
- package/src/generators/test-generator/adapters/playwright/templates/steps/partials/locator-base.hbs +11 -2
- package/src/generators/test-generator/adapters/playwright/templates/steps/partials/locator.hbs +11 -2
- package/src/generators/test-generator/code-generator.ts +0 -59
- package/src/generators/test-generator/patterns/assertion-patterns.ts +39 -8
- package/src/generators/test-generator/patterns/index.ts +12 -3
- package/src/generators/test-generator/patterns/interaction-patterns.ts +1 -1
- package/src/generators/test-generator/patterns/keyboard-patterns.ts +51 -0
- package/src/generators/test-generator/patterns/scope-patterns.ts +40 -0
- package/src/generators/test-generator/patterns/scroll-patterns.ts +27 -0
- package/src/generators/test-generator/patterns/table-patterns.ts +232 -0
- package/src/generators/test-generator/step-mapper.ts +39 -34
- package/src/generators/test-generator/template-engine.ts +3 -1
- package/src/generators/test-generator/types.ts +7 -112
- package/src/generators/test-generator/utils/selector-resolver.ts +70 -25
- package/src/orchestrator/project-initializer.ts +345 -32
- package/src/orchestrator/screen-manager.ts +61 -233
- package/src/utils/selector-types.ts +3 -0
- package/dist/cli/commands/cache-clear.d.ts +0 -3
- package/dist/cli/commands/cache-clear.d.ts.map +0 -1
- package/dist/cli/commands/cache-clear.js +0 -24
- package/dist/cli/commands/cache-clear.js.map +0 -1
- package/dist/cli/commands/full.d.ts +0 -3
- package/dist/cli/commands/full.d.ts.map +0 -1
- package/dist/cli/commands/full.js +0 -37
- package/dist/cli/commands/full.js.map +0 -1
- package/dist/cli/commands/live-scan.d.ts +0 -3
- package/dist/cli/commands/live-scan.d.ts.map +0 -1
- package/dist/cli/commands/live-scan.js +0 -78
- package/dist/cli/commands/live-scan.js.map +0 -1
- package/dist/cli/commands/map.d.ts +0 -3
- package/dist/cli/commands/map.d.ts.map +0 -1
- package/dist/cli/commands/map.js +0 -93
- package/dist/cli/commands/map.js.map +0 -1
- package/dist/cli/commands/validate.d.ts +0 -3
- package/dist/cli/commands/validate.d.ts.map +0 -1
- package/dist/cli/commands/validate.js +0 -43
- package/dist/cli/commands/validate.js.map +0 -1
- package/dist/cli/utils.d.ts +0 -6
- package/dist/cli/utils.d.ts.map +0 -1
- package/dist/cli/utils.js +0 -101
- package/dist/cli/utils.js.map +0 -1
- package/dist/config/config-loader.d.ts +0 -51
- package/dist/config/config-loader.d.ts.map +0 -1
- package/dist/config/config-loader.js +0 -216
- package/dist/config/config-loader.js.map +0 -1
- package/dist/config/config-schema.d.ts +0 -121
- package/dist/config/config-schema.d.ts.map +0 -1
- package/dist/config/config-schema.js +0 -7
- package/dist/config/config-schema.js.map +0 -1
- package/dist/core/live-scanner/config-reader.d.ts +0 -10
- package/dist/core/live-scanner/config-reader.d.ts.map +0 -1
- package/dist/core/live-scanner/config-reader.js +0 -87
- package/dist/core/live-scanner/config-reader.js.map +0 -1
- package/dist/core/live-scanner/element-finder.d.ts +0 -20
- package/dist/core/live-scanner/element-finder.d.ts.map +0 -1
- package/dist/core/live-scanner/element-finder.js +0 -486
- package/dist/core/live-scanner/element-finder.js.map +0 -1
- package/dist/core/live-scanner/index.d.ts +0 -8
- package/dist/core/live-scanner/index.d.ts.map +0 -1
- package/dist/core/live-scanner/index.js +0 -33
- package/dist/core/live-scanner/index.js.map +0 -1
- package/dist/core/live-scanner/matrix-reader.d.ts +0 -17
- package/dist/core/live-scanner/matrix-reader.d.ts.map +0 -1
- package/dist/core/live-scanner/matrix-reader.js +0 -60
- package/dist/core/live-scanner/matrix-reader.js.map +0 -1
- package/dist/core/live-scanner/matrix-writer.d.ts +0 -7
- package/dist/core/live-scanner/matrix-writer.d.ts.map +0 -1
- package/dist/core/live-scanner/matrix-writer.js +0 -103
- package/dist/core/live-scanner/matrix-writer.js.map +0 -1
- package/dist/core/live-scanner/role-fallback.d.ts +0 -15
- package/dist/core/live-scanner/role-fallback.d.ts.map +0 -1
- package/dist/core/live-scanner/role-fallback.js +0 -45
- package/dist/core/live-scanner/role-fallback.js.map +0 -1
- package/dist/core/live-scanner/scanner.d.ts +0 -13
- package/dist/core/live-scanner/scanner.d.ts.map +0 -1
- package/dist/core/live-scanner/scanner.js +0 -243
- package/dist/core/live-scanner/scanner.js.map +0 -1
- package/dist/core/live-scanner/step-replayer.d.ts +0 -26
- package/dist/core/live-scanner/step-replayer.d.ts.map +0 -1
- package/dist/core/live-scanner/step-replayer.js +0 -286
- package/dist/core/live-scanner/step-replayer.js.map +0 -1
- package/dist/core/live-scanner/types.d.ts +0 -52
- package/dist/core/live-scanner/types.d.ts.map +0 -1
- package/dist/core/live-scanner/types.js +0 -14
- package/dist/core/live-scanner/types.js.map +0 -1
- package/dist/core/selector-base/annotation-handler.d.ts +0 -45
- package/dist/core/selector-base/annotation-handler.d.ts.map +0 -1
- package/dist/core/selector-base/annotation-handler.js +0 -102
- package/dist/core/selector-base/annotation-handler.js.map +0 -1
- package/dist/core/selector-base/base-generator.d.ts +0 -49
- package/dist/core/selector-base/base-generator.d.ts.map +0 -1
- package/dist/core/selector-base/base-generator.js +0 -214
- package/dist/core/selector-base/base-generator.js.map +0 -1
- package/dist/core/selector-base/gherkin-parser.d.ts +0 -24
- package/dist/core/selector-base/gherkin-parser.d.ts.map +0 -1
- package/dist/core/selector-base/gherkin-parser.js +0 -42
- package/dist/core/selector-base/gherkin-parser.js.map +0 -1
- package/dist/core/selector-mapper/priority-mapper.d.ts +0 -74
- package/dist/core/selector-mapper/priority-mapper.d.ts.map +0 -1
- package/dist/core/selector-mapper/priority-mapper.js +0 -477
- package/dist/core/selector-mapper/priority-mapper.js.map +0 -1
- package/dist/core/ui-scanner/heuristics/base-heuristic.d.ts +0 -91
- package/dist/core/ui-scanner/heuristics/base-heuristic.d.ts.map +0 -1
- package/dist/core/ui-scanner/heuristics/base-heuristic.js +0 -175
- package/dist/core/ui-scanner/heuristics/base-heuristic.js.map +0 -1
- package/dist/core/ui-scanner/react-scanner.d.ts +0 -32
- package/dist/core/ui-scanner/react-scanner.d.ts.map +0 -1
- package/dist/core/ui-scanner/react-scanner.js +0 -163
- package/dist/core/ui-scanner/react-scanner.js.map +0 -1
- package/dist/core/ui-scanner/scanner-interface.d.ts +0 -94
- package/dist/core/ui-scanner/scanner-interface.d.ts.map +0 -1
- package/dist/core/ui-scanner/scanner-interface.js +0 -33
- package/dist/core/ui-scanner/scanner-interface.js.map +0 -1
- package/dist/core/ui-scanner/strict-scanner.d.ts +0 -81
- package/dist/core/ui-scanner/strict-scanner.d.ts.map +0 -1
- package/dist/core/ui-scanner/strict-scanner.js +0 -511
- package/dist/core/ui-scanner/strict-scanner.js.map +0 -1
- package/dist/core/validator/data-validator.d.ts +0 -38
- package/dist/core/validator/data-validator.d.ts.map +0 -1
- package/dist/core/validator/data-validator.js +0 -212
- package/dist/core/validator/data-validator.js.map +0 -1
- package/dist/core/validator/feature-validator.d.ts +0 -27
- package/dist/core/validator/feature-validator.d.ts.map +0 -1
- package/dist/core/validator/feature-validator.js +0 -182
- package/dist/core/validator/feature-validator.js.map +0 -1
- package/dist/core/validator/index.d.ts +0 -46
- package/dist/core/validator/index.d.ts.map +0 -1
- package/dist/core/validator/index.js +0 -17
- package/dist/core/validator/index.js.map +0 -1
- package/dist/core/validator/screen-validator.d.ts +0 -35
- package/dist/core/validator/screen-validator.d.ts.map +0 -1
- package/dist/core/validator/screen-validator.js +0 -195
- package/dist/core/validator/screen-validator.js.map +0 -1
- package/dist/core/validator/selector-validator.d.ts +0 -36
- package/dist/core/validator/selector-validator.d.ts.map +0 -1
- package/dist/core/validator/selector-validator.js +0 -210
- package/dist/core/validator/selector-validator.js.map +0 -1
- package/dist/external/ai-provider.d.ts +0 -60
- package/dist/external/ai-provider.d.ts.map +0 -1
- package/dist/external/ai-provider.js +0 -30
- package/dist/external/ai-provider.js.map +0 -1
- package/dist/external/anthropic-provider.d.ts +0 -29
- package/dist/external/anthropic-provider.d.ts.map +0 -1
- package/dist/external/anthropic-provider.js +0 -85
- package/dist/external/anthropic-provider.js.map +0 -1
- package/dist/generators/cache/cache-manager.d.ts +0 -66
- package/dist/generators/cache/cache-manager.d.ts.map +0 -1
- package/dist/generators/cache/cache-manager.js +0 -286
- package/dist/generators/cache/cache-manager.js.map +0 -1
- package/dist/generators/dsl-writer/index.d.ts +0 -33
- package/dist/generators/dsl-writer/index.d.ts.map +0 -1
- package/dist/generators/dsl-writer/index.js +0 -226
- package/dist/generators/dsl-writer/index.js.map +0 -1
- package/dist/generators/scaffold-generator/index.d.ts +0 -162
- package/dist/generators/scaffold-generator/index.d.ts.map +0 -1
- package/dist/generators/scaffold-generator/index.js +0 -868
- package/dist/generators/scaffold-generator/index.js.map +0 -1
- package/dist/generators/selector-mapper/ai-mapper.d.ts +0 -56
- package/dist/generators/selector-mapper/ai-mapper.d.ts.map +0 -1
- package/dist/generators/selector-mapper/ai-mapper.js +0 -457
- package/dist/generators/selector-mapper/ai-mapper.js.map +0 -1
- package/dist/generators/selector-mapper/hybrid-mapper.d.ts +0 -67
- package/dist/generators/selector-mapper/hybrid-mapper.d.ts.map +0 -1
- package/dist/generators/selector-mapper/hybrid-mapper.js +0 -349
- package/dist/generators/selector-mapper/hybrid-mapper.js.map +0 -1
- package/dist/generators/selector-mapper/index.d.ts +0 -8
- package/dist/generators/selector-mapper/index.d.ts.map +0 -1
- package/dist/generators/selector-mapper/index.js +0 -12
- package/dist/generators/selector-mapper/index.js.map +0 -1
- package/dist/generators/selector-mapper/intelligent-mapper.d.ts +0 -125
- package/dist/generators/selector-mapper/intelligent-mapper.d.ts.map +0 -1
- package/dist/generators/selector-mapper/intelligent-mapper.js +0 -391
- package/dist/generators/selector-mapper/intelligent-mapper.js.map +0 -1
- package/dist/generators/test-generator/ai-step-mapper.d.ts +0 -27
- package/dist/generators/test-generator/ai-step-mapper.d.ts.map +0 -1
- package/dist/generators/test-generator/ai-step-mapper.js +0 -204
- package/dist/generators/test-generator/ai-step-mapper.js.map +0 -1
- package/dist/generators/test-generator/auth-setup-generator.d.ts +0 -18
- package/dist/generators/test-generator/auth-setup-generator.d.ts.map +0 -1
- package/dist/generators/test-generator/auth-setup-generator.js +0 -82
- package/dist/generators/test-generator/auth-setup-generator.js.map +0 -1
- package/dist/generators/test-generator/patterns/legacy-patterns.d.ts +0 -7
- package/dist/generators/test-generator/patterns/legacy-patterns.d.ts.map +0 -1
- package/dist/generators/test-generator/patterns/legacy-patterns.js +0 -98
- package/dist/generators/test-generator/patterns/legacy-patterns.js.map +0 -1
- package/dist/generators/test-generator/templates/auth-setup.ts.hbs +0 -36
- package/dist/generators/ui-model-builder/deep-scanner.d.ts +0 -121
- package/dist/generators/ui-model-builder/deep-scanner.d.ts.map +0 -1
- package/dist/generators/ui-model-builder/deep-scanner.js +0 -1113
- package/dist/generators/ui-model-builder/deep-scanner.js.map +0 -1
- package/dist/generators/ui-model-builder/enhanced-deep-scanner.d.ts +0 -110
- package/dist/generators/ui-model-builder/enhanced-deep-scanner.d.ts.map +0 -1
- package/dist/generators/ui-model-builder/enhanced-deep-scanner.js +0 -608
- package/dist/generators/ui-model-builder/enhanced-deep-scanner.js.map +0 -1
- package/dist/generators/ui-model-builder/react-scanner.d.ts +0 -107
- package/dist/generators/ui-model-builder/react-scanner.d.ts.map +0 -1
- package/dist/generators/ui-model-builder/react-scanner.js +0 -797
- package/dist/generators/ui-model-builder/react-scanner.js.map +0 -1
- package/dist/orchestrator/cache-manager.d.ts +0 -15
- package/dist/orchestrator/cache-manager.d.ts.map +0 -1
- package/dist/orchestrator/cache-manager.js +0 -62
- package/dist/orchestrator/cache-manager.js.map +0 -1
- package/dist/orchestrator/pipeline.d.ts +0 -56
- package/dist/orchestrator/pipeline.d.ts.map +0 -1
- package/dist/orchestrator/pipeline.js +0 -298
- package/dist/orchestrator/pipeline.js.map +0 -1
- package/dist/orchestrator/reporter.d.ts +0 -15
- package/dist/orchestrator/reporter.d.ts.map +0 -1
- package/dist/orchestrator/reporter.js +0 -30
- package/dist/orchestrator/reporter.js.map +0 -1
- package/src/cli/commands/cache-clear.ts +0 -22
- package/src/cli/commands/full.ts +0 -35
- package/src/cli/commands/live-scan.ts +0 -82
- package/src/cli/commands/map.ts +0 -97
- package/src/cli/commands/validate.ts +0 -43
- package/src/cli/utils.ts +0 -106
- package/src/config/ai-providers.yaml +0 -56
- package/src/config/config-loader.ts +0 -248
- package/src/config/config-schema.ts +0 -148
- package/src/config/default.config.yaml +0 -107
- package/src/config/framework.config.yaml +0 -52
- package/src/config/routes.yaml +0 -31
- package/src/core/live-scanner/config-reader.ts +0 -57
- package/src/core/live-scanner/element-finder.ts +0 -541
- package/src/core/live-scanner/index.ts +0 -7
- package/src/core/live-scanner/matrix-reader.ts +0 -65
- package/src/core/live-scanner/matrix-writer.ts +0 -77
- package/src/core/live-scanner/role-fallback.ts +0 -43
- package/src/core/live-scanner/scanner.ts +0 -254
- package/src/core/live-scanner/step-replayer.ts +0 -306
- package/src/core/live-scanner/types.ts +0 -58
- package/src/core/selector-base/annotation-handler.ts +0 -127
- package/src/core/selector-base/base-generator.ts +0 -234
- package/src/core/selector-base/gherkin-parser.ts +0 -57
- package/src/core/selector-mapper/priority-mapper.ts +0 -607
- package/src/core/ui-scanner/heuristics/base-heuristic.ts +0 -216
- package/src/core/ui-scanner/react-scanner.ts +0 -156
- package/src/core/ui-scanner/scanner-interface.ts +0 -133
- package/src/core/ui-scanner/strict-scanner.ts +0 -629
- package/src/core/validator/data-validator.ts +0 -202
- package/src/core/validator/feature-validator.ts +0 -176
- package/src/core/validator/index.ts +0 -57
- package/src/core/validator/screen-validator.ts +0 -209
- package/src/core/validator/selector-validator.ts +0 -209
- package/src/external/ai-provider.ts +0 -90
- package/src/external/anthropic-provider.ts +0 -114
- package/src/generators/README.md +0 -410
- package/src/generators/cache/cache-manager.ts +0 -322
- package/src/generators/dsl-writer/index.ts +0 -253
- package/src/generators/scaffold-generator/index.ts +0 -1019
- package/src/generators/selector-mapper/ai-mapper.ts +0 -528
- package/src/generators/selector-mapper/hybrid-mapper.ts +0 -427
- package/src/generators/selector-mapper/index.ts +0 -10
- package/src/generators/selector-mapper/intelligent-mapper.ts +0 -530
- package/src/generators/test-generator/ai-step-mapper.ts +0 -224
- package/src/generators/test-generator/auth-setup-generator.ts +0 -59
- package/src/generators/test-generator/patterns/legacy-patterns.ts +0 -104
- package/src/generators/test-generator/templates/auth-setup.ts.hbs +0 -36
- package/src/generators/ui-model-builder/deep-scanner.ts +0 -1244
- package/src/generators/ui-model-builder/enhanced-deep-scanner.ts +0 -731
- package/src/generators/ui-model-builder/react-scanner.ts +0 -959
- package/src/orchestrator/cache-manager.ts +0 -32
- package/src/orchestrator/pipeline.ts +0 -354
- package/src/orchestrator/reporter.ts +0 -36
|
@@ -1,82 +0,0 @@
|
|
|
1
|
-
import { Command } from 'commander';
|
|
2
|
-
|
|
3
|
-
export function registerLiveScanCommand(program: Command): void {
|
|
4
|
-
program
|
|
5
|
-
.command('live-scan')
|
|
6
|
-
.description('Scan a live site to discover real selectors for Gherkin element references')
|
|
7
|
-
.requiredOption('-s, --screen <name>', 'Screen name to scan')
|
|
8
|
-
.option('--url <baseUrl>', 'Override base URL (default: read from playwright.config.ts)')
|
|
9
|
-
.option('--headed', 'Launch browser in headed (visible) mode', false)
|
|
10
|
-
.option('--auth-dir <path>', 'Directory containing auth storage state files', 'specs/.auth')
|
|
11
|
-
.option('-f, --force', 'Force rescan all elements, ignoring existing results', false)
|
|
12
|
-
.action(async (options) => {
|
|
13
|
-
try {
|
|
14
|
-
const { LiveScanner } = require('../../core/live-scanner');
|
|
15
|
-
|
|
16
|
-
console.log('\n🔍 Sungen Live Scanner\n');
|
|
17
|
-
console.log(`📍 Screen: ${options.screen}`);
|
|
18
|
-
console.log(`🖥️ Mode: ${options.headed ? 'headed' : 'headless'}`);
|
|
19
|
-
if (options.force) {
|
|
20
|
-
console.log(`🔄 Force mode: rescanning all elements`);
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
const scanner = new LiveScanner({
|
|
24
|
-
baseUrl: options.url,
|
|
25
|
-
screenName: options.screen,
|
|
26
|
-
screensDir: 'qa/screens',
|
|
27
|
-
headed: options.headed,
|
|
28
|
-
authDir: options.authDir,
|
|
29
|
-
force: options.force,
|
|
30
|
-
});
|
|
31
|
-
|
|
32
|
-
const results = await scanner.scan();
|
|
33
|
-
|
|
34
|
-
// Print final summary
|
|
35
|
-
console.log('\n📊 SCAN SUMMARY\n');
|
|
36
|
-
|
|
37
|
-
let totalElements = 0;
|
|
38
|
-
let totalResolved = 0;
|
|
39
|
-
let totalWarnings = 0;
|
|
40
|
-
let totalUnresolved = 0;
|
|
41
|
-
let totalSkipped = 0;
|
|
42
|
-
|
|
43
|
-
for (const result of results) {
|
|
44
|
-
for (const scenario of Object.values(result.scenarios) as any[]) {
|
|
45
|
-
for (const element of Object.values(scenario.elements) as any[]) {
|
|
46
|
-
totalElements++;
|
|
47
|
-
if ((element as any).skipped) {
|
|
48
|
-
totalSkipped++;
|
|
49
|
-
totalResolved++;
|
|
50
|
-
} else if (element.matchMethod === 'unresolved') {
|
|
51
|
-
totalUnresolved++;
|
|
52
|
-
} else {
|
|
53
|
-
totalResolved++;
|
|
54
|
-
if (element.warning) totalWarnings++;
|
|
55
|
-
}
|
|
56
|
-
}
|
|
57
|
-
}
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
console.log(`Total Elements: ${totalElements}`);
|
|
61
|
-
console.log(`Resolved: ${totalResolved}`);
|
|
62
|
-
if (totalSkipped > 0) {
|
|
63
|
-
console.log(`Skipped (cached): ${totalSkipped}`);
|
|
64
|
-
}
|
|
65
|
-
console.log(`Warnings: ${totalWarnings}`);
|
|
66
|
-
console.log(`Unresolved: ${totalUnresolved}`);
|
|
67
|
-
|
|
68
|
-
if (totalUnresolved > 0) {
|
|
69
|
-
console.log(`\n⚠️ ${totalUnresolved} element(s) could not be found on the live site`);
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
if (totalResolved > 0) {
|
|
73
|
-
console.log(`\n✅ Live scan complete. Run 'sungen map --screen ${options.screen}' to generate selectors.`);
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
console.log('');
|
|
77
|
-
} catch (error: any) {
|
|
78
|
-
console.error('\n❌ Live scan failed:', error.message);
|
|
79
|
-
process.exit(1);
|
|
80
|
-
}
|
|
81
|
-
});
|
|
82
|
-
}
|
package/src/cli/commands/map.ts
DELETED
|
@@ -1,97 +0,0 @@
|
|
|
1
|
-
import { Command } from 'commander';
|
|
2
|
-
import { ConfigLoader } from '../../config/config-loader';
|
|
3
|
-
|
|
4
|
-
export function registerMapCommand(program: Command): void {
|
|
5
|
-
program
|
|
6
|
-
.command('map')
|
|
7
|
-
.description('Generate selector and test-data YAML from Gherkin feature files')
|
|
8
|
-
.option('-s, --screen <name>', 'Screen name (reads from qa/screens/<name>/features/)')
|
|
9
|
-
.option('--file <path>', 'Single feature file path (generates selectors next to features folder)')
|
|
10
|
-
.option('-o, --output <dir>', 'Output directory for generated files')
|
|
11
|
-
.option('-f, --force', 'Force overwrite existing YAML files and rescan all elements')
|
|
12
|
-
.option('--skip-live-scan', 'Skip live-scan before mapping (live-scan runs by default)')
|
|
13
|
-
.option('--headed', 'Launch browser in headed mode during live-scan', false)
|
|
14
|
-
.option('--auth-dir <path>', 'Auth storage state directory for live-scan', 'specs/.auth')
|
|
15
|
-
.option('-v, --verbose', 'Detailed output')
|
|
16
|
-
.action(async (options) => {
|
|
17
|
-
try {
|
|
18
|
-
const path = require('path');
|
|
19
|
-
const cliOptions = {
|
|
20
|
-
...program.opts(),
|
|
21
|
-
...options,
|
|
22
|
-
};
|
|
23
|
-
const config = new ConfigLoader().load(cliOptions);
|
|
24
|
-
const { ScaffoldGenerator } = require('../../generators/scaffold-generator');
|
|
25
|
-
|
|
26
|
-
const generator = new ScaffoldGenerator();
|
|
27
|
-
|
|
28
|
-
if (options.screen) {
|
|
29
|
-
const screensDir = options.output || 'qa/screens';
|
|
30
|
-
const forceOverwrite = cliOptions.force || false;
|
|
31
|
-
|
|
32
|
-
// Run live-scan by default before mapping (skip with --skip-live-scan)
|
|
33
|
-
if (!options.skipLiveScan) {
|
|
34
|
-
const { LiveScanner } = require('../../core/live-scanner');
|
|
35
|
-
console.log('🔍 Running live-scan before mapping...\n');
|
|
36
|
-
|
|
37
|
-
const scanner = new LiveScanner({
|
|
38
|
-
screenName: options.screen,
|
|
39
|
-
screensDir,
|
|
40
|
-
headed: options.headed,
|
|
41
|
-
authDir: options.authDir,
|
|
42
|
-
});
|
|
43
|
-
|
|
44
|
-
await scanner.scan();
|
|
45
|
-
console.log('');
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
if (forceOverwrite) {
|
|
49
|
-
console.log(`Mapping screen: ${options.screen} (force: selectors will be overwritten)\n`);
|
|
50
|
-
} else {
|
|
51
|
-
console.log(`Mapping screen: ${options.screen}\n`);
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
const results = generator.processScreen(options.screen, screensDir, forceOverwrite);
|
|
55
|
-
|
|
56
|
-
for (const result of results) {
|
|
57
|
-
console.log(`✓ Mapped ${result.featureFile}.feature`);
|
|
58
|
-
|
|
59
|
-
if (result.selectorsSkipped) {
|
|
60
|
-
console.log(` ⊘ ${path.basename(result.selectorsPath)} (skipped - already exists)`);
|
|
61
|
-
} else {
|
|
62
|
-
console.log(` → ${path.basename(result.selectorsPath)} (${result.elementCount} elements)`);
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
if (result.testDataMerged) {
|
|
66
|
-
console.log(` ↻ ${path.basename(result.testDataPath)} (smart-merged — ${result.dataRefCount} variables)\n`);
|
|
67
|
-
} else {
|
|
68
|
-
console.log(` → ${path.basename(result.testDataPath)} (${result.dataRefCount} variables)\n`);
|
|
69
|
-
}
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
console.log(`Next step: sungen generate --screen ${options.screen}`);
|
|
73
|
-
console.log(' This will create the test specs based on the mapped selectors and test data.');
|
|
74
|
-
} else if (options.file) {
|
|
75
|
-
const deriveOutputDir = (featureFilePath: string): string => {
|
|
76
|
-
const featureDir = path.dirname(featureFilePath);
|
|
77
|
-
if (featureDir.includes('features')) {
|
|
78
|
-
return featureDir.replace(/features\/?$/, 'selectors/screens');
|
|
79
|
-
}
|
|
80
|
-
return path.join(featureDir, '..', 'selectors', 'screens');
|
|
81
|
-
};
|
|
82
|
-
|
|
83
|
-
const outputDir = options.output || deriveOutputDir(options.file);
|
|
84
|
-
const forceOverwrite = cliOptions.force || false;
|
|
85
|
-
console.log(`Mapping from file: ${options.file}\n`);
|
|
86
|
-
const result = generator.processFeatureFile(options.file, outputDir, forceOverwrite);
|
|
87
|
-
console.log(`✓ Generated: ${result.outputPath} (${result.elementCount} elements)`);
|
|
88
|
-
} else {
|
|
89
|
-
console.error('❌ Error: Please specify --screen <name> or --file <path>');
|
|
90
|
-
process.exit(1);
|
|
91
|
-
}
|
|
92
|
-
} catch (error) {
|
|
93
|
-
console.error('❌ Mapping failed:', error);
|
|
94
|
-
process.exit(1);
|
|
95
|
-
}
|
|
96
|
-
});
|
|
97
|
-
}
|
|
@@ -1,43 +0,0 @@
|
|
|
1
|
-
import { Command } from 'commander';
|
|
2
|
-
import { ValidationResult } from '../../core/validator';
|
|
3
|
-
import { printValidationResult } from '../utils';
|
|
4
|
-
|
|
5
|
-
export function registerValidateCommand(program: Command): void {
|
|
6
|
-
program
|
|
7
|
-
.command('validate')
|
|
8
|
-
.description('Validate Gherkin features and selector/test-data mappings')
|
|
9
|
-
.option('-s, --screen <name>', 'Validate specific screen (optional, defaults to all)')
|
|
10
|
-
.option('--json', 'Output results as JSON')
|
|
11
|
-
.option('-v, --verbose', 'Show all checks, not just failures')
|
|
12
|
-
.action(async (options) => {
|
|
13
|
-
try {
|
|
14
|
-
const { ScreenValidator } = require('../../core/validator');
|
|
15
|
-
|
|
16
|
-
const validator = new ScreenValidator({
|
|
17
|
-
verbose: options.verbose,
|
|
18
|
-
});
|
|
19
|
-
|
|
20
|
-
let result: ValidationResult;
|
|
21
|
-
if (options.screen) {
|
|
22
|
-
console.log(`Validating screen: ${options.screen}\n`);
|
|
23
|
-
result = validator.validateScreen(options.screen);
|
|
24
|
-
} else {
|
|
25
|
-
console.log('Validating all screens...\n');
|
|
26
|
-
result = validator.validateAll();
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
if (options.json) {
|
|
30
|
-
console.log(JSON.stringify(result, null, 2));
|
|
31
|
-
} else {
|
|
32
|
-
printValidationResult(result, options.verbose);
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
if (!result.valid) {
|
|
36
|
-
process.exit(1);
|
|
37
|
-
}
|
|
38
|
-
} catch (error) {
|
|
39
|
-
console.error('❌ Validation failed:', error);
|
|
40
|
-
process.exit(1);
|
|
41
|
-
}
|
|
42
|
-
});
|
|
43
|
-
}
|
package/src/cli/utils.ts
DELETED
|
@@ -1,106 +0,0 @@
|
|
|
1
|
-
import { ValidationResult } from '../core/validator';
|
|
2
|
-
|
|
3
|
-
/**
|
|
4
|
-
* Get human-readable description for error code
|
|
5
|
-
*/
|
|
6
|
-
function getErrorDescription(code: string): string {
|
|
7
|
-
switch (code) {
|
|
8
|
-
case 'GHERKIN_SYNTAX_ERROR': return 'Gherkin syntax errors';
|
|
9
|
-
case 'MISSING_PATH_METADATA': return 'missing Path: metadata';
|
|
10
|
-
case 'MISSING_SELECTOR_FILE': return 'missing selector files';
|
|
11
|
-
case 'MISSING_SELECTOR': return 'missing selector definitions';
|
|
12
|
-
case 'MISSING_DATA_FILE': return 'missing test-data files';
|
|
13
|
-
case 'MISSING_DATA_REF': return 'missing data references';
|
|
14
|
-
case 'INVALID_YAML_SYNTAX': return 'invalid YAML syntax';
|
|
15
|
-
case 'INVALID_SELECTOR_TYPE': return 'invalid selector types';
|
|
16
|
-
case 'INVALID_DATA_VALUE': return 'invalid data values';
|
|
17
|
-
case 'EMPTY_FEATURE': return 'empty feature files';
|
|
18
|
-
default: return 'errors';
|
|
19
|
-
}
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
/**
|
|
23
|
-
* Print validation result to console
|
|
24
|
-
*/
|
|
25
|
-
export function printValidationResult(result: ValidationResult, verbose: boolean = false): void {
|
|
26
|
-
for (const fileResult of result.results) {
|
|
27
|
-
if (fileResult.valid) {
|
|
28
|
-
if (verbose) {
|
|
29
|
-
console.log(`✓ ${fileResult.file}`);
|
|
30
|
-
console.log(` ✓ Gherkin syntax valid`);
|
|
31
|
-
if (fileResult.warnings.length === 0) {
|
|
32
|
-
console.log(` ✓ All checks passed`);
|
|
33
|
-
}
|
|
34
|
-
} else {
|
|
35
|
-
console.log(`✓ ${fileResult.file}`);
|
|
36
|
-
}
|
|
37
|
-
} else {
|
|
38
|
-
console.log(`✗ ${fileResult.file}`);
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
for (const warning of fileResult.warnings) {
|
|
42
|
-
const lineInfo = warning.line ? `:${warning.line}` : '';
|
|
43
|
-
console.log(` ⊘ ${warning.message}${lineInfo}`);
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
for (const error of fileResult.errors) {
|
|
47
|
-
const lineInfo = error.line ? `:${error.line}` : '';
|
|
48
|
-
console.log(` ✗ ${error.message}${lineInfo}`);
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
if (!fileResult.valid || (verbose && fileResult.warnings.length > 0)) {
|
|
52
|
-
console.log('');
|
|
53
|
-
}
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
console.log('\nSummary:');
|
|
57
|
-
console.log(` Files: ${result.summary.totalFiles} total, ${result.summary.passedFiles} passed, ${result.summary.failedFiles} failed`);
|
|
58
|
-
console.log(` Errors: ${result.summary.totalErrors}`);
|
|
59
|
-
console.log(` Warnings: ${result.summary.totalWarnings}`);
|
|
60
|
-
|
|
61
|
-
if (result.summary.totalErrors > 0) {
|
|
62
|
-
const errorsByType = new Map<string, number>();
|
|
63
|
-
const errorsByFile = new Map<string, string[]>();
|
|
64
|
-
|
|
65
|
-
for (const fileResult of result.results) {
|
|
66
|
-
for (const error of fileResult.errors) {
|
|
67
|
-
errorsByType.set(error.code, (errorsByType.get(error.code) || 0) + 1);
|
|
68
|
-
|
|
69
|
-
if (error.code === 'MISSING_SELECTOR' || error.code === 'MISSING_DATA_REF') {
|
|
70
|
-
if (!errorsByFile.has(fileResult.file)) {
|
|
71
|
-
errorsByFile.set(fileResult.file, []);
|
|
72
|
-
}
|
|
73
|
-
if (error.element) {
|
|
74
|
-
errorsByFile.get(fileResult.file)!.push(error.element);
|
|
75
|
-
}
|
|
76
|
-
}
|
|
77
|
-
}
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
console.log('\nError Breakdown:');
|
|
81
|
-
for (const [code, count] of errorsByType.entries()) {
|
|
82
|
-
const description = getErrorDescription(code);
|
|
83
|
-
console.log(` ${code}: ${count} ${description}`);
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
if (errorsByType.has('MISSING_SELECTOR_FILE') || errorsByType.has('MISSING_DATA_FILE')) {
|
|
87
|
-
console.log('\n💡 Suggested Fix:');
|
|
88
|
-
console.log(' Run: sungen map --screen <name>');
|
|
89
|
-
console.log(' This will generate missing selector and test-data files');
|
|
90
|
-
} else if (errorsByType.has('MISSING_SELECTOR') || errorsByType.has('MISSING_DATA_REF')) {
|
|
91
|
-
console.log('\n💡 Suggested Fix:');
|
|
92
|
-
if (errorsByType.has('MISSING_SELECTOR')) {
|
|
93
|
-
console.log(' Missing selectors - Add them to the selector YAML files');
|
|
94
|
-
}
|
|
95
|
-
if (errorsByType.has('MISSING_DATA_REF')) {
|
|
96
|
-
console.log(' Missing data refs - Add them to the test-data YAML files');
|
|
97
|
-
}
|
|
98
|
-
}
|
|
99
|
-
}
|
|
100
|
-
|
|
101
|
-
if (result.valid) {
|
|
102
|
-
console.log('\n✅ Validation passed');
|
|
103
|
-
} else {
|
|
104
|
-
console.log('\n❌ Validation failed');
|
|
105
|
-
}
|
|
106
|
-
}
|
|
@@ -1,56 +0,0 @@
|
|
|
1
|
-
# AI Provider Configuration
|
|
2
|
-
|
|
3
|
-
providers:
|
|
4
|
-
# Claude - Best for DSL generation (cheap + fast)
|
|
5
|
-
claude:
|
|
6
|
-
generation:
|
|
7
|
-
model: "claude-3-haiku-20240307"
|
|
8
|
-
temperature: 0.2
|
|
9
|
-
maxTokens: 2048
|
|
10
|
-
vision:
|
|
11
|
-
model: "claude-3-sonnet-20240229"
|
|
12
|
-
temperature: 0.3
|
|
13
|
-
maxTokens: 4096
|
|
14
|
-
|
|
15
|
-
# OpenAI - Best for vision tasks
|
|
16
|
-
openai:
|
|
17
|
-
generation:
|
|
18
|
-
model: "gpt-4o-mini"
|
|
19
|
-
temperature: 0.2
|
|
20
|
-
maxTokens: 2048
|
|
21
|
-
vision:
|
|
22
|
-
model: "gpt-4o"
|
|
23
|
-
temperature: 0.3
|
|
24
|
-
maxTokens: 4096
|
|
25
|
-
|
|
26
|
-
# Gemini - Alternative provider
|
|
27
|
-
gemini:
|
|
28
|
-
generation:
|
|
29
|
-
model: "gemini-1.5-flash"
|
|
30
|
-
temperature: 0.2
|
|
31
|
-
maxTokens: 2048
|
|
32
|
-
vision:
|
|
33
|
-
model: "gemini-1.5-pro"
|
|
34
|
-
temperature: 0.3
|
|
35
|
-
maxTokens: 4096
|
|
36
|
-
|
|
37
|
-
# Default provider for each task type
|
|
38
|
-
defaults:
|
|
39
|
-
generation: "claude"
|
|
40
|
-
vision: "openai"
|
|
41
|
-
analysis: "claude"
|
|
42
|
-
|
|
43
|
-
# Cost optimization (estimated cost per 1M tokens)
|
|
44
|
-
costs:
|
|
45
|
-
claude-haiku:
|
|
46
|
-
input: 0.25
|
|
47
|
-
output: 1.25
|
|
48
|
-
gpt-4o-mini:
|
|
49
|
-
input: 0.15
|
|
50
|
-
output: 0.60
|
|
51
|
-
gpt-4o:
|
|
52
|
-
input: 2.50
|
|
53
|
-
output: 10.00
|
|
54
|
-
gemini-flash:
|
|
55
|
-
input: 0.075
|
|
56
|
-
output: 0.30
|
|
@@ -1,248 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Configuration Loader
|
|
3
|
-
* Loads and merges configuration from multiple sources with priority:
|
|
4
|
-
* CLI Options > Custom Config File > Default Config File
|
|
5
|
-
*/
|
|
6
|
-
|
|
7
|
-
import fs from 'fs';
|
|
8
|
-
import path from 'path';
|
|
9
|
-
import yaml from 'yaml';
|
|
10
|
-
import { FrameworkConfig, CLIOptions, RuntimeConfig } from './config-schema';
|
|
11
|
-
|
|
12
|
-
export class ConfigLoader {
|
|
13
|
-
private defaultConfigPath: string;
|
|
14
|
-
|
|
15
|
-
constructor() {
|
|
16
|
-
this.defaultConfigPath = path.join(__dirname, 'default.config.yaml');
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
/**
|
|
20
|
-
* Load runtime configuration with priority merging
|
|
21
|
-
* Priority: CLI > Custom File > Default File
|
|
22
|
-
*/
|
|
23
|
-
load(cliOptions: CLIOptions = {}): RuntimeConfig {
|
|
24
|
-
// 1. Load default config
|
|
25
|
-
const defaultConfig = this.loadDefaultConfig();
|
|
26
|
-
|
|
27
|
-
// 2. Load custom config file if specified, or look for sungen.config.yaml in CWD
|
|
28
|
-
let fileConfig: Partial<FrameworkConfig> = {};
|
|
29
|
-
let configSource: 'default' | 'file' | 'cli' = 'default';
|
|
30
|
-
|
|
31
|
-
if (cliOptions.config) {
|
|
32
|
-
fileConfig = this.loadCustomConfig(cliOptions.config);
|
|
33
|
-
configSource = 'file';
|
|
34
|
-
} else {
|
|
35
|
-
// Try to load sungen.config.yaml from current working directory
|
|
36
|
-
const defaultConfigPath = path.join(process.cwd(), 'sungen.config.yaml');
|
|
37
|
-
if (fs.existsSync(defaultConfigPath)) {
|
|
38
|
-
fileConfig = this.loadCustomConfig(defaultConfigPath);
|
|
39
|
-
configSource = 'file';
|
|
40
|
-
}
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
// 3. Merge configs: default < file < CLI
|
|
44
|
-
const mergedConfig = this.mergeConfigs(defaultConfig, fileConfig, cliOptions);
|
|
45
|
-
|
|
46
|
-
// Override source if CLI has significant options
|
|
47
|
-
if (Object.keys(cliOptions).length > 0) {
|
|
48
|
-
configSource = 'cli';
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
return {
|
|
52
|
-
...mergedConfig,
|
|
53
|
-
cliOptions,
|
|
54
|
-
configSource
|
|
55
|
-
};
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
/**
|
|
59
|
-
* Load default configuration from default.config.yaml
|
|
60
|
-
*/
|
|
61
|
-
private loadDefaultConfig(): FrameworkConfig {
|
|
62
|
-
try {
|
|
63
|
-
const content = fs.readFileSync(this.defaultConfigPath, 'utf-8');
|
|
64
|
-
return yaml.parse(content) as FrameworkConfig;
|
|
65
|
-
} catch (error) {
|
|
66
|
-
throw new Error(`Failed to load default config: ${error}`);
|
|
67
|
-
}
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
/**
|
|
71
|
-
* Load custom configuration file
|
|
72
|
-
*/
|
|
73
|
-
private loadCustomConfig(configPath: string): Partial<FrameworkConfig> {
|
|
74
|
-
try {
|
|
75
|
-
const fullPath = path.resolve(configPath);
|
|
76
|
-
|
|
77
|
-
if (!fs.existsSync(fullPath)) {
|
|
78
|
-
throw new Error(`Config file not found: ${fullPath}`);
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
const content = fs.readFileSync(fullPath, 'utf-8');
|
|
82
|
-
return yaml.parse(content) as Partial<FrameworkConfig>;
|
|
83
|
-
} catch (error) {
|
|
84
|
-
throw new Error(`Failed to load custom config: ${error}`);
|
|
85
|
-
}
|
|
86
|
-
}
|
|
87
|
-
|
|
88
|
-
/**
|
|
89
|
-
* Merge configurations with priority: CLI > File > Default
|
|
90
|
-
*/
|
|
91
|
-
private mergeConfigs(
|
|
92
|
-
defaultConfig: FrameworkConfig,
|
|
93
|
-
fileConfig: Partial<FrameworkConfig>,
|
|
94
|
-
cliOptions: CLIOptions
|
|
95
|
-
): FrameworkConfig {
|
|
96
|
-
// Deep merge default + file config
|
|
97
|
-
const merged = this.deepMerge(defaultConfig, fileConfig);
|
|
98
|
-
|
|
99
|
-
// Apply CLI overrides (highest priority)
|
|
100
|
-
if (cliOptions.verbose !== undefined) {
|
|
101
|
-
merged.verbose = cliOptions.verbose;
|
|
102
|
-
}
|
|
103
|
-
|
|
104
|
-
if (cliOptions.force !== undefined) {
|
|
105
|
-
merged.force = cliOptions.force;
|
|
106
|
-
}
|
|
107
|
-
|
|
108
|
-
if (cliOptions.depth !== undefined) {
|
|
109
|
-
merged.scanner.maxDepth = cliOptions.depth;
|
|
110
|
-
}
|
|
111
|
-
|
|
112
|
-
if (cliOptions.aiMapper !== undefined) {
|
|
113
|
-
merged.testGenerator.enableAIFallback = cliOptions.aiMapper;
|
|
114
|
-
}
|
|
115
|
-
|
|
116
|
-
if (cliOptions.framework !== undefined) {
|
|
117
|
-
merged.testGenerator.framework = cliOptions.framework;
|
|
118
|
-
}
|
|
119
|
-
|
|
120
|
-
// Selector mapping mode overrides
|
|
121
|
-
if (cliOptions.mode !== undefined) {
|
|
122
|
-
merged.selectorMapping.mode = cliOptions.mode;
|
|
123
|
-
}
|
|
124
|
-
|
|
125
|
-
return merged;
|
|
126
|
-
}
|
|
127
|
-
|
|
128
|
-
/**
|
|
129
|
-
* Deep merge two objects
|
|
130
|
-
*/
|
|
131
|
-
private deepMerge<T>(target: T, source: Partial<T>): T {
|
|
132
|
-
const result = { ...target };
|
|
133
|
-
|
|
134
|
-
for (const key in source) {
|
|
135
|
-
const sourceValue = source[key];
|
|
136
|
-
const targetValue = result[key];
|
|
137
|
-
|
|
138
|
-
if (sourceValue === undefined) {
|
|
139
|
-
continue;
|
|
140
|
-
}
|
|
141
|
-
|
|
142
|
-
if (this.isObject(sourceValue) && this.isObject(targetValue)) {
|
|
143
|
-
result[key] = this.deepMerge(targetValue, sourceValue as any);
|
|
144
|
-
} else {
|
|
145
|
-
result[key] = sourceValue as any;
|
|
146
|
-
}
|
|
147
|
-
}
|
|
148
|
-
|
|
149
|
-
return result;
|
|
150
|
-
}
|
|
151
|
-
|
|
152
|
-
/**
|
|
153
|
-
* Check if value is a plain object
|
|
154
|
-
*/
|
|
155
|
-
private isObject(value: any): value is Record<string, any> {
|
|
156
|
-
return value !== null && typeof value === 'object' && !Array.isArray(value);
|
|
157
|
-
}
|
|
158
|
-
|
|
159
|
-
/**
|
|
160
|
-
* Validate configuration
|
|
161
|
-
*/
|
|
162
|
-
validate(config: RuntimeConfig): void {
|
|
163
|
-
const errors: string[] = [];
|
|
164
|
-
|
|
165
|
-
// Validate required paths
|
|
166
|
-
if (!config.paths.sourceRoot) {
|
|
167
|
-
errors.push('paths.sourceRoot is required');
|
|
168
|
-
}
|
|
169
|
-
|
|
170
|
-
// Validate scanner
|
|
171
|
-
if (!['react', 'vue', 'angular'].includes(config.scanner.framework)) {
|
|
172
|
-
errors.push(`Invalid scanner.framework: ${config.scanner.framework}`);
|
|
173
|
-
}
|
|
174
|
-
|
|
175
|
-
if (config.scanner.maxDepth < 1) {
|
|
176
|
-
errors.push('scanner.maxDepth must be >= 1');
|
|
177
|
-
}
|
|
178
|
-
|
|
179
|
-
// Validate AI provider
|
|
180
|
-
if (!['anthropic', 'copilot', 'openai'].includes(config.selectorMapping.aiProvider)) {
|
|
181
|
-
errors.push(`Invalid selectorMapping.aiProvider: ${config.selectorMapping.aiProvider}`);
|
|
182
|
-
}
|
|
183
|
-
|
|
184
|
-
// Validate test framework
|
|
185
|
-
if (!['playwright', 'appium', 'integration'].includes(config.testGenerator.framework)) {
|
|
186
|
-
errors.push(`Invalid testGenerator.framework: ${config.testGenerator.framework}`);
|
|
187
|
-
}
|
|
188
|
-
|
|
189
|
-
if (errors.length > 0) {
|
|
190
|
-
throw new Error(`Configuration validation failed:\n${errors.join('\n')}`);
|
|
191
|
-
}
|
|
192
|
-
}
|
|
193
|
-
|
|
194
|
-
/**
|
|
195
|
-
* Get configuration value by path (dot notation)
|
|
196
|
-
* Example: get('scanner.maxDepth')
|
|
197
|
-
*/
|
|
198
|
-
get(config: RuntimeConfig, path: string): any {
|
|
199
|
-
return path.split('.').reduce((obj, key) => obj?.[key], config as any);
|
|
200
|
-
}
|
|
201
|
-
|
|
202
|
-
/**
|
|
203
|
-
* Display current configuration (for debugging)
|
|
204
|
-
*/
|
|
205
|
-
display(config: RuntimeConfig): string {
|
|
206
|
-
const displayed = {
|
|
207
|
-
version: config.version,
|
|
208
|
-
source: config.configSource,
|
|
209
|
-
verbose: config.verbose,
|
|
210
|
-
force: config.force,
|
|
211
|
-
scanner: {
|
|
212
|
-
framework: config.scanner.framework,
|
|
213
|
-
maxDepth: config.scanner.maxDepth
|
|
214
|
-
},
|
|
215
|
-
selectorMapping: {
|
|
216
|
-
aiProvider: config.selectorMapping.aiProvider,
|
|
217
|
-
model: config.selectorMapping.model
|
|
218
|
-
},
|
|
219
|
-
testGenerator: {
|
|
220
|
-
framework: config.testGenerator.framework,
|
|
221
|
-
aiProvider: config.testGenerator.aiProvider,
|
|
222
|
-
enableAIFallback: config.testGenerator.enableAIFallback
|
|
223
|
-
},
|
|
224
|
-
cache: {
|
|
225
|
-
enabled: config.cache.enabled
|
|
226
|
-
}
|
|
227
|
-
};
|
|
228
|
-
|
|
229
|
-
return yaml.stringify(displayed);
|
|
230
|
-
}
|
|
231
|
-
}
|
|
232
|
-
|
|
233
|
-
// Singleton instance
|
|
234
|
-
let configLoader: ConfigLoader;
|
|
235
|
-
|
|
236
|
-
export function getConfigLoader(): ConfigLoader {
|
|
237
|
-
if (!configLoader) {
|
|
238
|
-
configLoader = new ConfigLoader();
|
|
239
|
-
}
|
|
240
|
-
return configLoader;
|
|
241
|
-
}
|
|
242
|
-
|
|
243
|
-
export function loadConfig(cliOptions: CLIOptions = {}): RuntimeConfig {
|
|
244
|
-
const loader = getConfigLoader();
|
|
245
|
-
const config = loader.load(cliOptions);
|
|
246
|
-
loader.validate(config);
|
|
247
|
-
return config;
|
|
248
|
-
}
|