@nac3/forge-cli 0.2.0-alpha.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +45 -0
- package/README.md +371 -0
- package/dist/bin/yf.d.ts +5 -0
- package/dist/bin/yf.d.ts.map +1 -0
- package/dist/bin/yf.js +86 -0
- package/dist/bin/yf.js.map +1 -0
- package/dist/chat/claude.d.ts +100 -0
- package/dist/chat/claude.d.ts.map +1 -0
- package/dist/chat/claude.js +228 -0
- package/dist/chat/claude.js.map +1 -0
- package/dist/chat/ingest_session.d.ts +97 -0
- package/dist/chat/ingest_session.d.ts.map +1 -0
- package/dist/chat/ingest_session.js +99 -0
- package/dist/chat/ingest_session.js.map +1 -0
- package/dist/chat/panel.d.ts +15 -0
- package/dist/chat/panel.d.ts.map +1 -0
- package/dist/chat/panel.js +1526 -0
- package/dist/chat/panel.js.map +1 -0
- package/dist/chat/persistence.d.ts +37 -0
- package/dist/chat/persistence.d.ts.map +1 -0
- package/dist/chat/persistence.js +91 -0
- package/dist/chat/persistence.js.map +1 -0
- package/dist/chat/server.d.ts +34 -0
- package/dist/chat/server.d.ts.map +1 -0
- package/dist/chat/server.js +1540 -0
- package/dist/chat/server.js.map +1 -0
- package/dist/chat/spec_extract.d.ts +35 -0
- package/dist/chat/spec_extract.d.ts.map +1 -0
- package/dist/chat/spec_extract.js +152 -0
- package/dist/chat/spec_extract.js.map +1 -0
- package/dist/chat/spec_plan.d.ts +65 -0
- package/dist/chat/spec_plan.d.ts.map +1 -0
- package/dist/chat/spec_plan.js +160 -0
- package/dist/chat/spec_plan.js.map +1 -0
- package/dist/chat/spec_scaffold.d.ts +95 -0
- package/dist/chat/spec_scaffold.d.ts.map +1 -0
- package/dist/chat/spec_scaffold.js +220 -0
- package/dist/chat/spec_scaffold.js.map +1 -0
- package/dist/chat/tools/git.d.ts +59 -0
- package/dist/chat/tools/git.d.ts.map +1 -0
- package/dist/chat/tools/git.js +313 -0
- package/dist/chat/tools/git.js.map +1 -0
- package/dist/chat/tools/github.d.ts +59 -0
- package/dist/chat/tools/github.d.ts.map +1 -0
- package/dist/chat/tools/github.js +310 -0
- package/dist/chat/tools/github.js.map +1 -0
- package/dist/chat/tools/lifecycle.d.ts +82 -0
- package/dist/chat/tools/lifecycle.d.ts.map +1 -0
- package/dist/chat/tools/lifecycle.js +295 -0
- package/dist/chat/tools/lifecycle.js.map +1 -0
- package/dist/chat/tools/manual.d.ts +26 -0
- package/dist/chat/tools/manual.d.ts.map +1 -0
- package/dist/chat/tools/manual.js +164 -0
- package/dist/chat/tools/manual.js.map +1 -0
- package/dist/chat/tools/reader.d.ts +80 -0
- package/dist/chat/tools/reader.d.ts.map +1 -0
- package/dist/chat/tools/reader.js +471 -0
- package/dist/chat/tools/reader.js.map +1 -0
- package/dist/chat/tools.d.ts +106 -0
- package/dist/chat/tools.d.ts.map +1 -0
- package/dist/chat/tools.js +587 -0
- package/dist/chat/tools.js.map +1 -0
- package/dist/codegen/e2e.d.ts +106 -0
- package/dist/codegen/e2e.d.ts.map +1 -0
- package/dist/codegen/e2e.js +931 -0
- package/dist/codegen/e2e.js.map +1 -0
- package/dist/codegen/v3_flow_emit.d.ts +70 -0
- package/dist/codegen/v3_flow_emit.d.ts.map +1 -0
- package/dist/codegen/v3_flow_emit.js +225 -0
- package/dist/codegen/v3_flow_emit.js.map +1 -0
- package/dist/commands/_stub.d.ts +2 -0
- package/dist/commands/_stub.d.ts.map +1 -0
- package/dist/commands/_stub.js +21 -0
- package/dist/commands/_stub.js.map +1 -0
- package/dist/commands/app.d.ts +31 -0
- package/dist/commands/app.d.ts.map +1 -0
- package/dist/commands/app.js +331 -0
- package/dist/commands/app.js.map +1 -0
- package/dist/commands/chat.d.ts +18 -0
- package/dist/commands/chat.d.ts.map +1 -0
- package/dist/commands/chat.js +76 -0
- package/dist/commands/chat.js.map +1 -0
- package/dist/commands/deploy.d.ts +21 -0
- package/dist/commands/deploy.d.ts.map +1 -0
- package/dist/commands/deploy.js +121 -0
- package/dist/commands/deploy.js.map +1 -0
- package/dist/commands/doctor.d.ts +14 -0
- package/dist/commands/doctor.d.ts.map +1 -0
- package/dist/commands/doctor.js +280 -0
- package/dist/commands/doctor.js.map +1 -0
- package/dist/commands/figma.d.ts +32 -0
- package/dist/commands/figma.d.ts.map +1 -0
- package/dist/commands/figma.js +141 -0
- package/dist/commands/figma.js.map +1 -0
- package/dist/commands/gen-flow-tests.d.ts +8 -0
- package/dist/commands/gen-flow-tests.d.ts.map +1 -0
- package/dist/commands/gen-flow-tests.js +78 -0
- package/dist/commands/gen-flow-tests.js.map +1 -0
- package/dist/commands/gen-tests.d.ts +9 -0
- package/dist/commands/gen-tests.d.ts.map +1 -0
- package/dist/commands/gen-tests.js +118 -0
- package/dist/commands/gen-tests.js.map +1 -0
- package/dist/commands/license.d.ts +14 -0
- package/dist/commands/license.d.ts.map +1 -0
- package/dist/commands/license.js +182 -0
- package/dist/commands/license.js.map +1 -0
- package/dist/commands/log.d.ts +19 -0
- package/dist/commands/log.d.ts.map +1 -0
- package/dist/commands/log.js +101 -0
- package/dist/commands/log.js.map +1 -0
- package/dist/commands/migrate.d.ts +118 -0
- package/dist/commands/migrate.d.ts.map +1 -0
- package/dist/commands/migrate.js +1410 -0
- package/dist/commands/migrate.js.map +1 -0
- package/dist/commands/mobile.d.ts +27 -0
- package/dist/commands/mobile.d.ts.map +1 -0
- package/dist/commands/mobile.js +90 -0
- package/dist/commands/mobile.js.map +1 -0
- package/dist/commands/new.d.ts +32 -0
- package/dist/commands/new.d.ts.map +1 -0
- package/dist/commands/new.js +107 -0
- package/dist/commands/new.js.map +1 -0
- package/dist/commands/pilot.d.ts +8 -0
- package/dist/commands/pilot.d.ts.map +1 -0
- package/dist/commands/pilot.js +104 -0
- package/dist/commands/pilot.js.map +1 -0
- package/dist/commands/projects.d.ts +21 -0
- package/dist/commands/projects.d.ts.map +1 -0
- package/dist/commands/projects.js +238 -0
- package/dist/commands/projects.js.map +1 -0
- package/dist/commands/publish.d.ts +35 -0
- package/dist/commands/publish.d.ts.map +1 -0
- package/dist/commands/publish.js +194 -0
- package/dist/commands/publish.js.map +1 -0
- package/dist/commands/repo.d.ts +59 -0
- package/dist/commands/repo.d.ts.map +1 -0
- package/dist/commands/repo.js +178 -0
- package/dist/commands/repo.js.map +1 -0
- package/dist/commands/review-screens.d.ts +28 -0
- package/dist/commands/review-screens.d.ts.map +1 -0
- package/dist/commands/review-screens.js +345 -0
- package/dist/commands/review-screens.js.map +1 -0
- package/dist/commands/scenarios.d.ts +23 -0
- package/dist/commands/scenarios.d.ts.map +1 -0
- package/dist/commands/scenarios.js +304 -0
- package/dist/commands/scenarios.js.map +1 -0
- package/dist/commands/ship.d.ts +18 -0
- package/dist/commands/ship.d.ts.map +1 -0
- package/dist/commands/ship.js +41 -0
- package/dist/commands/ship.js.map +1 -0
- package/dist/commands/test.d.ts +29 -0
- package/dist/commands/test.d.ts.map +1 -0
- package/dist/commands/test.js +62 -0
- package/dist/commands/test.js.map +1 -0
- package/dist/commands/tunnel.d.ts +22 -0
- package/dist/commands/tunnel.d.ts.map +1 -0
- package/dist/commands/tunnel.js +77 -0
- package/dist/commands/tunnel.js.map +1 -0
- package/dist/commands/validate.d.ts +14 -0
- package/dist/commands/validate.d.ts.map +1 -0
- package/dist/commands/validate.js +51 -0
- package/dist/commands/validate.js.map +1 -0
- package/dist/commands/vault.d.ts +32 -0
- package/dist/commands/vault.d.ts.map +1 -0
- package/dist/commands/vault.js +489 -0
- package/dist/commands/vault.js.map +1 -0
- package/dist/commands/voice.d.ts +16 -0
- package/dist/commands/voice.d.ts.map +1 -0
- package/dist/commands/voice.js +69 -0
- package/dist/commands/voice.js.map +1 -0
- package/dist/core/cascade_router.d.ts +90 -0
- package/dist/core/cascade_router.d.ts.map +1 -0
- package/dist/core/cascade_router.js +131 -0
- package/dist/core/cascade_router.js.map +1 -0
- package/dist/core/cf_tunnel.d.ts +52 -0
- package/dist/core/cf_tunnel.d.ts.map +1 -0
- package/dist/core/cf_tunnel.js +134 -0
- package/dist/core/cf_tunnel.js.map +1 -0
- package/dist/core/gha_dispatcher.d.ts +48 -0
- package/dist/core/gha_dispatcher.d.ts.map +1 -0
- package/dist/core/gha_dispatcher.js +198 -0
- package/dist/core/gha_dispatcher.js.map +1 -0
- package/dist/core/logger.d.ts +89 -0
- package/dist/core/logger.d.ts.map +1 -0
- package/dist/core/logger.js +245 -0
- package/dist/core/logger.js.map +1 -0
- package/dist/core/mode.d.ts +26 -0
- package/dist/core/mode.d.ts.map +1 -0
- package/dist/core/mode.js +122 -0
- package/dist/core/mode.js.map +1 -0
- package/dist/core/pairing.d.ts +40 -0
- package/dist/core/pairing.d.ts.map +1 -0
- package/dist/core/pairing.js +145 -0
- package/dist/core/pairing.js.map +1 -0
- package/dist/core/pilot_setup.d.ts +29 -0
- package/dist/core/pilot_setup.d.ts.map +1 -0
- package/dist/core/pilot_setup.js +119 -0
- package/dist/core/pilot_setup.js.map +1 -0
- package/dist/core/polar.d.ts +81 -0
- package/dist/core/polar.d.ts.map +1 -0
- package/dist/core/polar.js +175 -0
- package/dist/core/polar.js.map +1 -0
- package/dist/core/project_picker.d.ts +56 -0
- package/dist/core/project_picker.d.ts.map +1 -0
- package/dist/core/project_picker.js +86 -0
- package/dist/core/project_picker.js.map +1 -0
- package/dist/core/projects.d.ts +58 -0
- package/dist/core/projects.d.ts.map +1 -0
- package/dist/core/projects.js +146 -0
- package/dist/core/projects.js.map +1 -0
- package/dist/core/projects_sync.d.ts +80 -0
- package/dist/core/projects_sync.d.ts.map +1 -0
- package/dist/core/projects_sync.js +278 -0
- package/dist/core/projects_sync.js.map +1 -0
- package/dist/core/remote_runner.d.ts +70 -0
- package/dist/core/remote_runner.d.ts.map +1 -0
- package/dist/core/remote_runner.js +133 -0
- package/dist/core/remote_runner.js.map +1 -0
- package/dist/core/repo_state.d.ts +24 -0
- package/dist/core/repo_state.d.ts.map +1 -0
- package/dist/core/repo_state.js +109 -0
- package/dist/core/repo_state.js.map +1 -0
- package/dist/core/target.d.ts +31 -0
- package/dist/core/target.d.ts.map +1 -0
- package/dist/core/target.js +121 -0
- package/dist/core/target.js.map +1 -0
- package/dist/deploy/aws.d.ts +43 -0
- package/dist/deploy/aws.d.ts.map +1 -0
- package/dist/deploy/aws.js +173 -0
- package/dist/deploy/aws.js.map +1 -0
- package/dist/figma/api.d.ts +35 -0
- package/dist/figma/api.d.ts.map +1 -0
- package/dist/figma/api.js +40 -0
- package/dist/figma/api.js.map +1 -0
- package/dist/figma/decorator.d.ts +74 -0
- package/dist/figma/decorator.d.ts.map +1 -0
- package/dist/figma/decorator.js +210 -0
- package/dist/figma/decorator.js.map +1 -0
- package/dist/figma/heuristics.d.ts +29 -0
- package/dist/figma/heuristics.d.ts.map +1 -0
- package/dist/figma/heuristics.js +110 -0
- package/dist/figma/heuristics.js.map +1 -0
- package/dist/figma/normalize.d.ts +33 -0
- package/dist/figma/normalize.d.ts.map +1 -0
- package/dist/figma/normalize.js +101 -0
- package/dist/figma/normalize.js.map +1 -0
- package/dist/figma/tokens.d.ts +23 -0
- package/dist/figma/tokens.d.ts.map +1 -0
- package/dist/figma/tokens.js +111 -0
- package/dist/figma/tokens.js.map +1 -0
- package/dist/figma/types.d.ts +118 -0
- package/dist/figma/types.d.ts.map +1 -0
- package/dist/figma/types.js +12 -0
- package/dist/figma/types.js.map +1 -0
- package/dist/i18n/index.d.ts +48 -0
- package/dist/i18n/index.d.ts.map +1 -0
- package/dist/i18n/index.js +135 -0
- package/dist/i18n/index.js.map +1 -0
- package/dist/i18n/types.d.ts +52 -0
- package/dist/i18n/types.d.ts.map +1 -0
- package/dist/i18n/types.js +85 -0
- package/dist/i18n/types.js.map +1 -0
- package/dist/index.d.ts +12 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +11 -0
- package/dist/index.js.map +1 -0
- package/dist/lan/mdns_packet.d.ts +74 -0
- package/dist/lan/mdns_packet.d.ts.map +1 -0
- package/dist/lan/mdns_packet.js +247 -0
- package/dist/lan/mdns_packet.js.map +1 -0
- package/dist/lan/mdns_service.d.ts +102 -0
- package/dist/lan/mdns_service.d.ts.map +1 -0
- package/dist/lan/mdns_service.js +206 -0
- package/dist/lan/mdns_service.js.map +1 -0
- package/dist/license/activate.d.ts +33 -0
- package/dist/license/activate.d.ts.map +1 -0
- package/dist/license/activate.js +135 -0
- package/dist/license/activate.js.map +1 -0
- package/dist/license/fingerprint.d.ts +2 -0
- package/dist/license/fingerprint.d.ts.map +1 -0
- package/dist/license/fingerprint.js +29 -0
- package/dist/license/fingerprint.js.map +1 -0
- package/dist/license/hito4_client.d.ts +24 -0
- package/dist/license/hito4_client.d.ts.map +1 -0
- package/dist/license/hito4_client.js +103 -0
- package/dist/license/hito4_client.js.map +1 -0
- package/dist/license/index.d.ts +22 -0
- package/dist/license/index.d.ts.map +1 -0
- package/dist/license/index.js +125 -0
- package/dist/license/index.js.map +1 -0
- package/dist/license/types.d.ts +38 -0
- package/dist/license/types.d.ts.map +1 -0
- package/dist/license/types.js +9 -0
- package/dist/license/types.js.map +1 -0
- package/dist/migrate/ai-apply.d.ts +198 -0
- package/dist/migrate/ai-apply.d.ts.map +1 -0
- package/dist/migrate/ai-apply.js +833 -0
- package/dist/migrate/ai-apply.js.map +1 -0
- package/dist/migrate/ai-decorator.d.ts +87 -0
- package/dist/migrate/ai-decorator.d.ts.map +1 -0
- package/dist/migrate/ai-decorator.js +203 -0
- package/dist/migrate/ai-decorator.js.map +1 -0
- package/dist/migrate/apply.d.ts +28 -0
- package/dist/migrate/apply.d.ts.map +1 -0
- package/dist/migrate/apply.js +119 -0
- package/dist/migrate/apply.js.map +1 -0
- package/dist/migrate/audit.d.ts +9 -0
- package/dist/migrate/audit.d.ts.map +1 -0
- package/dist/migrate/audit.js +197 -0
- package/dist/migrate/audit.js.map +1 -0
- package/dist/migrate/diff.d.ts +28 -0
- package/dist/migrate/diff.d.ts.map +1 -0
- package/dist/migrate/diff.js +154 -0
- package/dist/migrate/diff.js.map +1 -0
- package/dist/migrate/html-orchestrator.d.ts +81 -0
- package/dist/migrate/html-orchestrator.d.ts.map +1 -0
- package/dist/migrate/html-orchestrator.js +233 -0
- package/dist/migrate/html-orchestrator.js.map +1 -0
- package/dist/migrate/html-walker.d.ts +93 -0
- package/dist/migrate/html-walker.d.ts.map +1 -0
- package/dist/migrate/html-walker.js +288 -0
- package/dist/migrate/html-walker.js.map +1 -0
- package/dist/migrate/js-template-walker.d.ts +118 -0
- package/dist/migrate/js-template-walker.d.ts.map +1 -0
- package/dist/migrate/js-template-walker.js +644 -0
- package/dist/migrate/js-template-walker.js.map +1 -0
- package/dist/migrate/manifest-validator.d.ts +30 -0
- package/dist/migrate/manifest-validator.d.ts.map +1 -0
- package/dist/migrate/manifest-validator.js +261 -0
- package/dist/migrate/manifest-validator.js.map +1 -0
- package/dist/migrate/overrides.d.ts +58 -0
- package/dist/migrate/overrides.d.ts.map +1 -0
- package/dist/migrate/overrides.js +193 -0
- package/dist/migrate/overrides.js.map +1 -0
- package/dist/migrate/plugin-scope.d.ts +42 -0
- package/dist/migrate/plugin-scope.d.ts.map +1 -0
- package/dist/migrate/plugin-scope.js +94 -0
- package/dist/migrate/plugin-scope.js.map +1 -0
- package/dist/migrate/types.d.ts +45 -0
- package/dist/migrate/types.d.ts.map +1 -0
- package/dist/migrate/types.js +9 -0
- package/dist/migrate/types.js.map +1 -0
- package/dist/migrate/verb-inference.d.ts +37 -0
- package/dist/migrate/verb-inference.d.ts.map +1 -0
- package/dist/migrate/verb-inference.js +274 -0
- package/dist/migrate/verb-inference.js.map +1 -0
- package/dist/nac3/attrs.d.ts +87 -0
- package/dist/nac3/attrs.d.ts.map +1 -0
- package/dist/nac3/attrs.js +134 -0
- package/dist/nac3/attrs.js.map +1 -0
- package/dist/nac3/scenario_dsl.d.ts +71 -0
- package/dist/nac3/scenario_dsl.d.ts.map +1 -0
- package/dist/nac3/scenario_dsl.js +191 -0
- package/dist/nac3/scenario_dsl.js.map +1 -0
- package/dist/nac3/tokens.d.ts +126 -0
- package/dist/nac3/tokens.d.ts.map +1 -0
- package/dist/nac3/tokens.js +138 -0
- package/dist/nac3/tokens.js.map +1 -0
- package/dist/reader/parsers/csv.d.ts +42 -0
- package/dist/reader/parsers/csv.d.ts.map +1 -0
- package/dist/reader/parsers/csv.js +221 -0
- package/dist/reader/parsers/csv.js.map +1 -0
- package/dist/reader/parsers/docx.d.ts +31 -0
- package/dist/reader/parsers/docx.d.ts.map +1 -0
- package/dist/reader/parsers/docx.js +51 -0
- package/dist/reader/parsers/docx.js.map +1 -0
- package/dist/reader/parsers/epub.d.ts +39 -0
- package/dist/reader/parsers/epub.d.ts.map +1 -0
- package/dist/reader/parsers/epub.js +265 -0
- package/dist/reader/parsers/epub.js.map +1 -0
- package/dist/reader/parsers/html.d.ts +40 -0
- package/dist/reader/parsers/html.d.ts.map +1 -0
- package/dist/reader/parsers/html.js +386 -0
- package/dist/reader/parsers/html.js.map +1 -0
- package/dist/reader/parsers/md.d.ts +30 -0
- package/dist/reader/parsers/md.d.ts.map +1 -0
- package/dist/reader/parsers/md.js +199 -0
- package/dist/reader/parsers/md.js.map +1 -0
- package/dist/reader/parsers/pdf.d.ts +39 -0
- package/dist/reader/parsers/pdf.d.ts.map +1 -0
- package/dist/reader/parsers/pdf.js +220 -0
- package/dist/reader/parsers/pdf.js.map +1 -0
- package/dist/reader/parsers/rtf.d.ts +37 -0
- package/dist/reader/parsers/rtf.d.ts.map +1 -0
- package/dist/reader/parsers/rtf.js +347 -0
- package/dist/reader/parsers/rtf.js.map +1 -0
- package/dist/reader/parsers/source.d.ts +32 -0
- package/dist/reader/parsers/source.d.ts.map +1 -0
- package/dist/reader/parsers/source.js +122 -0
- package/dist/reader/parsers/source.js.map +1 -0
- package/dist/reader/parsers/txt.d.ts +25 -0
- package/dist/reader/parsers/txt.d.ts.map +1 -0
- package/dist/reader/parsers/txt.js +56 -0
- package/dist/reader/parsers/txt.js.map +1 -0
- package/dist/reader/parsers/xlsx.d.ts +33 -0
- package/dist/reader/parsers/xlsx.d.ts.map +1 -0
- package/dist/reader/parsers/xlsx.js +143 -0
- package/dist/reader/parsers/xlsx.js.map +1 -0
- package/dist/reader/registry.d.ts +39 -0
- package/dist/reader/registry.d.ts.map +1 -0
- package/dist/reader/registry.js +172 -0
- package/dist/reader/registry.js.map +1 -0
- package/dist/reader/search.d.ts +27 -0
- package/dist/reader/search.d.ts.map +1 -0
- package/dist/reader/search.js +77 -0
- package/dist/reader/search.js.map +1 -0
- package/dist/reader/state.d.ts +56 -0
- package/dist/reader/state.d.ts.map +1 -0
- package/dist/reader/state.js +179 -0
- package/dist/reader/state.js.map +1 -0
- package/dist/reader/types.d.ts +119 -0
- package/dist/reader/types.d.ts.map +1 -0
- package/dist/reader/types.js +23 -0
- package/dist/reader/types.js.map +1 -0
- package/dist/ship/run.d.ts +26 -0
- package/dist/ship/run.d.ts.map +1 -0
- package/dist/ship/run.js +123 -0
- package/dist/ship/run.js.map +1 -0
- package/dist/template/index.d.ts +50 -0
- package/dist/template/index.d.ts.map +1 -0
- package/dist/template/index.js +140 -0
- package/dist/template/index.js.map +1 -0
- package/dist/ui/colors.d.ts +13 -0
- package/dist/ui/colors.d.ts.map +1 -0
- package/dist/ui/colors.js +26 -0
- package/dist/ui/colors.js.map +1 -0
- package/dist/validate/index.d.ts +19 -0
- package/dist/validate/index.d.ts.map +1 -0
- package/dist/validate/index.js +181 -0
- package/dist/validate/index.js.map +1 -0
- package/dist/vault/catalog.d.ts +55 -0
- package/dist/vault/catalog.d.ts.map +1 -0
- package/dist/vault/catalog.js +424 -0
- package/dist/vault/catalog.js.map +1 -0
- package/dist/vault/crypto.d.ts +82 -0
- package/dist/vault/crypto.d.ts.map +1 -0
- package/dist/vault/crypto.js +173 -0
- package/dist/vault/crypto.js.map +1 -0
- package/dist/vault/git_askpass.d.ts +26 -0
- package/dist/vault/git_askpass.d.ts.map +1 -0
- package/dist/vault/git_askpass.js +104 -0
- package/dist/vault/git_askpass.js.map +1 -0
- package/dist/vault/migrator.d.ts +57 -0
- package/dist/vault/migrator.d.ts.map +1 -0
- package/dist/vault/migrator.js +204 -0
- package/dist/vault/migrator.js.map +1 -0
- package/dist/vault/redactor.d.ts +73 -0
- package/dist/vault/redactor.d.ts.map +1 -0
- package/dist/vault/redactor.js +182 -0
- package/dist/vault/redactor.js.map +1 -0
- package/dist/vault/store.d.ts +132 -0
- package/dist/vault/store.d.ts.map +1 -0
- package/dist/vault/store.js +335 -0
- package/dist/vault/store.js.map +1 -0
- package/dist/version.d.ts +8 -0
- package/dist/version.d.ts.map +1 -0
- package/dist/version.js +8 -0
- package/dist/version.js.map +1 -0
- package/dist/voice/chunker.d.ts +43 -0
- package/dist/voice/chunker.d.ts.map +1 -0
- package/dist/voice/chunker.js +133 -0
- package/dist/voice/chunker.js.map +1 -0
- package/dist/voice/config.d.ts +14 -0
- package/dist/voice/config.d.ts.map +1 -0
- package/dist/voice/config.js +51 -0
- package/dist/voice/config.js.map +1 -0
- package/dist/voice/intents.d.ts +71 -0
- package/dist/voice/intents.d.ts.map +1 -0
- package/dist/voice/intents.js +0 -0
- package/dist/voice/intents.js.map +1 -0
- package/dist/voice/providers/elevenlabs.d.ts +53 -0
- package/dist/voice/providers/elevenlabs.d.ts.map +1 -0
- package/dist/voice/providers/elevenlabs.js +159 -0
- package/dist/voice/providers/elevenlabs.js.map +1 -0
- package/dist/voice/providers/google.d.ts +56 -0
- package/dist/voice/providers/google.d.ts.map +1 -0
- package/dist/voice/providers/google.js +253 -0
- package/dist/voice/providers/google.js.map +1 -0
- package/dist/voice/providers/whisper.d.ts +44 -0
- package/dist/voice/providers/whisper.d.ts.map +1 -0
- package/dist/voice/providers/whisper.js +179 -0
- package/dist/voice/providers/whisper.js.map +1 -0
- package/dist/voice/registry.d.ts +35 -0
- package/dist/voice/registry.d.ts.map +1 -0
- package/dist/voice/registry.js +48 -0
- package/dist/voice/registry.js.map +1 -0
- package/dist/voice/router.d.ts +62 -0
- package/dist/voice/router.d.ts.map +1 -0
- package/dist/voice/router.js +175 -0
- package/dist/voice/router.js.map +1 -0
- package/dist/voice/types.d.ts +116 -0
- package/dist/voice/types.d.ts.map +1 -0
- package/dist/voice/types.js +22 -0
- package/dist/voice/types.js.map +1 -0
- package/dist/voice/voiceprint/enrollment.d.ts +36 -0
- package/dist/voice/voiceprint/enrollment.d.ts.map +1 -0
- package/dist/voice/voiceprint/enrollment.js +71 -0
- package/dist/voice/voiceprint/enrollment.js.map +1 -0
- package/dist/voice/voiceprint/identify.d.ts +16 -0
- package/dist/voice/voiceprint/identify.d.ts.map +1 -0
- package/dist/voice/voiceprint/identify.js +20 -0
- package/dist/voice/voiceprint/identify.js.map +1 -0
- package/dist/voice/voiceprint/liveness.d.ts +90 -0
- package/dist/voice/voiceprint/liveness.d.ts.map +1 -0
- package/dist/voice/voiceprint/liveness.js +251 -0
- package/dist/voice/voiceprint/liveness.js.map +1 -0
- package/dist/voice/voiceprint/match.d.ts +54 -0
- package/dist/voice/voiceprint/match.d.ts.map +1 -0
- package/dist/voice/voiceprint/match.js +88 -0
- package/dist/voice/voiceprint/match.js.map +1 -0
- package/dist/voice/voiceprint/providers/local-mfcc-stub.d.ts +44 -0
- package/dist/voice/voiceprint/providers/local-mfcc-stub.d.ts.map +1 -0
- package/dist/voice/voiceprint/providers/local-mfcc-stub.js +92 -0
- package/dist/voice/voiceprint/providers/local-mfcc-stub.js.map +1 -0
- package/dist/voice/voiceprint/store.d.ts +60 -0
- package/dist/voice/voiceprint/store.d.ts.map +1 -0
- package/dist/voice/voiceprint/store.js +155 -0
- package/dist/voice/voiceprint/store.js.map +1 -0
- package/dist/voice/voiceprint/trust.d.ts +90 -0
- package/dist/voice/voiceprint/trust.d.ts.map +1 -0
- package/dist/voice/voiceprint/trust.js +150 -0
- package/dist/voice/voiceprint/trust.js.map +1 -0
- package/dist/voice/voiceprint/types.d.ts +100 -0
- package/dist/voice/voiceprint/types.d.ts.map +1 -0
- package/dist/voice/voiceprint/types.js +23 -0
- package/dist/voice/voiceprint/types.js.map +1 -0
- package/dist/voice/wake.d.ts +64 -0
- package/dist/voice/wake.d.ts.map +1 -0
- package/dist/voice/wake.js +143 -0
- package/dist/voice/wake.js.map +1 -0
- package/docs/manuals/manual.ar.html +91 -0
- package/docs/manuals/manual.de.html +100 -0
- package/docs/manuals/manual.en.html +118 -0
- package/docs/manuals/manual.es.html +120 -0
- package/docs/manuals/manual.fr.html +102 -0
- package/docs/manuals/manual.hi.html +93 -0
- package/docs/manuals/manual.it.html +93 -0
- package/docs/manuals/manual.ja.html +97 -0
- package/docs/manuals/manual.pt.html +103 -0
- package/docs/manuals/manual.zh.html +89 -0
- package/package.json +94 -0
- package/src/i18n/catalogs/ar.json +86 -0
- package/src/i18n/catalogs/de.json +86 -0
- package/src/i18n/catalogs/en.json +86 -0
- package/src/i18n/catalogs/es.json +86 -0
- package/src/i18n/catalogs/fr.json +86 -0
- package/src/i18n/catalogs/hi.json +86 -0
- package/src/i18n/catalogs/it.json +86 -0
- package/src/i18n/catalogs/ja.json +86 -0
- package/src/i18n/catalogs/pt.json +86 -0
- package/src/i18n/catalogs/zh.json +86 -0
- package/templates/react-app/README.md +43 -0
- package/templates/react-app/index.html +12 -0
- package/templates/react-app/package.json +35 -0
- package/templates/react-app/src/App.tsx +106 -0
- package/templates/react-app/src/main.tsx +21 -0
- package/templates/react-app/src/nac/manifest.ts +46 -0
- package/templates/react-app/src/styles.css +68 -0
- package/templates/react-app/tsconfig.json +19 -0
- package/templates/react-app/vite.config.ts +12 -0
- package/templates/react-app/yujin.forge.json +15 -0
|
@@ -0,0 +1,644 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Yujin Forge -- JS-template walker.
|
|
3
|
+
*
|
|
4
|
+
* Many real-world apps render HTML via JS string templates rather
|
|
5
|
+
* than authoring it in static HTML. Common patterns:
|
|
6
|
+
*
|
|
7
|
+
* var html = '<button class="cta save" aria-label="Save invoice '
|
|
8
|
+
* + escapeHtml(inv.id) + '">Save</button>';
|
|
9
|
+
*
|
|
10
|
+
* var html = `<tr data-id="${row.id}">
|
|
11
|
+
* <td>${row.name}</td>
|
|
12
|
+
* <td><button class="del" aria-label="Delete row ${row.id}">Delete</button></td>
|
|
13
|
+
* </tr>`;
|
|
14
|
+
*
|
|
15
|
+
* The HTML walker (html-walker.ts) operates on parsed DOM trees and
|
|
16
|
+
* misses these because the elements only materialise at runtime when
|
|
17
|
+
* the JS executes. This walker scans .js / .ts source as text, finds
|
|
18
|
+
* HTML opening tags inside string literals (single-quote concat OR
|
|
19
|
+
* template literal), classifies each one, identifies the *dynamic
|
|
20
|
+
* id expression* (typically the JS expression that wraps the row's
|
|
21
|
+
* unique identifier and appears inside the aria-label), and rewrites
|
|
22
|
+
* the source by inserting `data-nac-id=` / `data-nac-role=` /
|
|
23
|
+
* `data-nac-action=` attributes -- with the same JS expression
|
|
24
|
+
* woven into the nac_id so each rendered row gets a unique id.
|
|
25
|
+
*
|
|
26
|
+
* The walker is deliberately scoped to recognise patterns we see in
|
|
27
|
+
* production codebases. Patterns we cannot decode (heavily computed
|
|
28
|
+
* tags, dynamic role assignment, JSX in .js without typescript
|
|
29
|
+
* tooling) are flagged low-confidence and reported -- never
|
|
30
|
+
* silently mis-decorated.
|
|
31
|
+
*
|
|
32
|
+
* ASCII-only.
|
|
33
|
+
*/
|
|
34
|
+
import { promises as fs } from 'node:fs';
|
|
35
|
+
import path from 'node:path';
|
|
36
|
+
import crypto from 'node:crypto';
|
|
37
|
+
import { inferVerb } from './verb-inference.js';
|
|
38
|
+
import { parse } from 'node-html-parser';
|
|
39
|
+
/** Convert UTF-16 offset to {line, col} (both 1-based). */
|
|
40
|
+
function offsetToLineCol(source, off) {
|
|
41
|
+
let line = 1, col = 1;
|
|
42
|
+
for (let i = 0; i < off && i < source.length; i++) {
|
|
43
|
+
if (source.charCodeAt(i) === 10) {
|
|
44
|
+
line++;
|
|
45
|
+
col = 1;
|
|
46
|
+
}
|
|
47
|
+
else
|
|
48
|
+
col++;
|
|
49
|
+
}
|
|
50
|
+
return { line, col };
|
|
51
|
+
}
|
|
52
|
+
const ELIGIBLE_TAGS = new Set([
|
|
53
|
+
'button', 'input', 'textarea', 'select', 'a', 'form',
|
|
54
|
+
'main', 'section', 'aside', 'nav', 'article', 'header', 'footer',
|
|
55
|
+
]);
|
|
56
|
+
/**
|
|
57
|
+
* Find every <tag ...> opening that appears inside a JS string
|
|
58
|
+
* literal (single, double, or template). Returns the structural
|
|
59
|
+
* extraction with whatever we could parse statically.
|
|
60
|
+
*
|
|
61
|
+
* The matcher is tolerant: it does not require a closing tag in the
|
|
62
|
+
* same string (real templates often split a single element across
|
|
63
|
+
* many concatenations). It looks at the opening tag + the immediate
|
|
64
|
+
* concatenation neighbourhood for the dynamic-id expression.
|
|
65
|
+
*/
|
|
66
|
+
export function scanJsTemplates(filePath, source) {
|
|
67
|
+
const candidates = [];
|
|
68
|
+
/* Regex: opening tag inside ANY string-quote context. We find the
|
|
69
|
+
tag via opening `<word` and then capture attributes up to `>`. */
|
|
70
|
+
/* tag: alpha, 1+; attrs: anything up to a closing `>` that is not
|
|
71
|
+
inside a string. We accept multi-line tags (the `s` flag). */
|
|
72
|
+
const tagRe = /<([a-zA-Z][a-zA-Z0-9]*)(\s[^>]*?)?(\/?)\s*>/gs;
|
|
73
|
+
/* JS string literal detector: we want to skip tags that appear in
|
|
74
|
+
code (outside strings) and only consider those inside a quote.
|
|
75
|
+
Heuristic: walk back to the nearest UNCLOSED quote on the same
|
|
76
|
+
enclosed scope. We use a lightweight state machine. */
|
|
77
|
+
const inString = computeStringScopes(source);
|
|
78
|
+
let m;
|
|
79
|
+
while ((m = tagRe.exec(source)) !== null) {
|
|
80
|
+
const offset = m.index;
|
|
81
|
+
const stringScope = inString[offset];
|
|
82
|
+
if (!stringScope)
|
|
83
|
+
continue;
|
|
84
|
+
const tagName = m[1] ?? '';
|
|
85
|
+
if (!tagName)
|
|
86
|
+
continue;
|
|
87
|
+
const tag = tagName.toLowerCase();
|
|
88
|
+
if (!ELIGIBLE_TAGS.has(tag))
|
|
89
|
+
continue;
|
|
90
|
+
const attrsRaw = (m[2] ?? '');
|
|
91
|
+
const openingTagText = m[0];
|
|
92
|
+
/* Skip elements that ALREADY carry data-nac-id literal in the
|
|
93
|
+
attrs region of THIS opening tag. We check the literal text;
|
|
94
|
+
interpolated decoration is rare. */
|
|
95
|
+
const alreadyDecorated = /data-nac-id\s*=/.test(attrsRaw);
|
|
96
|
+
/* Skip <a> without onclick / role=button -- bare navigation. */
|
|
97
|
+
if (tag === 'a' && !/onclick=|role\s*=\s*['"]button['"]/.test(attrsRaw))
|
|
98
|
+
continue;
|
|
99
|
+
/* Skip <input type="hidden"> */
|
|
100
|
+
if (tag === 'input' && /type\s*=\s*['"]hidden['"]/.test(attrsRaw))
|
|
101
|
+
continue;
|
|
102
|
+
const role = classifyRole(tag, attrsRaw);
|
|
103
|
+
const ariaStatic = extractStaticAriaLabel(attrsRaw);
|
|
104
|
+
const textStatic = extractStaticText(source, offset, openingTagText, m[3] === '/');
|
|
105
|
+
const verb = inferVerbFromAttrs(role, tag, ariaStatic, textStatic, attrsRaw);
|
|
106
|
+
const dynamicIdExpr = detectDynamicIdExpr(source, offset, openingTagText);
|
|
107
|
+
const plugin = derivePluginSlug(filePath, source, offset);
|
|
108
|
+
const proposedId = buildProposedIdTemplate(plugin, role, verb, tag, dynamicIdExpr, ariaStatic, textStatic);
|
|
109
|
+
const conf = computeConfidence({
|
|
110
|
+
role, verb, ariaStatic, textStatic, dynamicIdExpr,
|
|
111
|
+
});
|
|
112
|
+
const { line } = offsetToLineCol(source, offset);
|
|
113
|
+
const fp = computeFingerprint(filePath, tag, role, ariaStatic, textStatic, dynamicIdExpr);
|
|
114
|
+
candidates.push({
|
|
115
|
+
fingerprint: fp,
|
|
116
|
+
filePath,
|
|
117
|
+
offset,
|
|
118
|
+
line,
|
|
119
|
+
tag,
|
|
120
|
+
static_attrs: attrsRaw,
|
|
121
|
+
dynamic_id_expr: dynamicIdExpr,
|
|
122
|
+
role,
|
|
123
|
+
verb,
|
|
124
|
+
already_decorated: alreadyDecorated,
|
|
125
|
+
plugin,
|
|
126
|
+
proposed_id_template: proposedId,
|
|
127
|
+
confidence: conf,
|
|
128
|
+
text_static: textStatic,
|
|
129
|
+
aria_label_static: ariaStatic,
|
|
130
|
+
opening_tag_text: openingTagText,
|
|
131
|
+
});
|
|
132
|
+
}
|
|
133
|
+
return { filePath, candidates };
|
|
134
|
+
}
|
|
135
|
+
/* ----------------------------------------------------------------
|
|
136
|
+
JS string-scope detection.
|
|
137
|
+
|
|
138
|
+
We classify every character offset as "inside a string?" yes/no.
|
|
139
|
+
The marker is conservative: we only flag clear string regions
|
|
140
|
+
(single / double / backtick quoted) and treat anything we are
|
|
141
|
+
unsure about as NOT a string. The tradeoff is occasional missed
|
|
142
|
+
decoration vs accidentally rewriting non-string code; we always
|
|
143
|
+
prefer the safe side.
|
|
144
|
+
|
|
145
|
+
Caveat: template literals can contain ${expr} which is JS code.
|
|
146
|
+
We treat the entire template literal as a string scope for the
|
|
147
|
+
purpose of "is this a string?" -- the resulting HTML attr
|
|
148
|
+
injection inside a ${} would be syntactically wrong, but in
|
|
149
|
+
practice template literals carry the entire HTML in the literal
|
|
150
|
+
region, not in ${}.
|
|
151
|
+
---------------------------------------------------------------- */
|
|
152
|
+
function computeStringScopes(source) {
|
|
153
|
+
const len = source.length;
|
|
154
|
+
const inStr = new Uint8Array(len);
|
|
155
|
+
/* Track the last non-whitespace, non-comment token to disambiguate
|
|
156
|
+
`/` as division vs regex literal. After certain tokens (= ( , [
|
|
157
|
+
{ ; ! & | ? : return etc.) a `/` starts a regex; after others
|
|
158
|
+
(identifier, ) ] number, etc.) it's division. */
|
|
159
|
+
let lastSignificant = '';
|
|
160
|
+
const regexPreceders = new Set([
|
|
161
|
+
'', '=', '(', ',', '[', '{', ';', '!', '&', '|', '?', ':', '+',
|
|
162
|
+
'-', '*', '/', '%', '<', '>', '~', '^',
|
|
163
|
+
'return', 'typeof', 'delete', 'void', 'in', 'of', 'new', 'throw',
|
|
164
|
+
'instanceof', 'yield', 'await', 'else', 'do', 'case',
|
|
165
|
+
]);
|
|
166
|
+
let i = 0;
|
|
167
|
+
while (i < len) {
|
|
168
|
+
const c = source.charCodeAt(i);
|
|
169
|
+
/* Skip single-line comments */
|
|
170
|
+
if (c === 47 /* / */ && i + 1 < len && source.charCodeAt(i + 1) === 47) {
|
|
171
|
+
while (i < len && source.charCodeAt(i) !== 10)
|
|
172
|
+
i++;
|
|
173
|
+
continue;
|
|
174
|
+
}
|
|
175
|
+
/* Skip block comments */
|
|
176
|
+
if (c === 47 && i + 1 < len && source.charCodeAt(i + 1) === 42) {
|
|
177
|
+
i += 2;
|
|
178
|
+
while (i < len - 1 && !(source.charCodeAt(i) === 42 && source.charCodeAt(i + 1) === 47))
|
|
179
|
+
i++;
|
|
180
|
+
i += 2;
|
|
181
|
+
continue;
|
|
182
|
+
}
|
|
183
|
+
/* Regex literal? `/` not part of `//` or `/*` -- already
|
|
184
|
+
handled above. Disambiguate by the last significant token. */
|
|
185
|
+
if (c === 47 && regexPreceders.has(lastSignificant)) {
|
|
186
|
+
/* Walk forward until the closing `/` (not in a char class,
|
|
187
|
+
not escaped). */
|
|
188
|
+
i++;
|
|
189
|
+
let inClass = false;
|
|
190
|
+
while (i < len) {
|
|
191
|
+
const cc = source.charCodeAt(i);
|
|
192
|
+
if (cc === 92 /* \ */) {
|
|
193
|
+
i += 2;
|
|
194
|
+
continue;
|
|
195
|
+
}
|
|
196
|
+
if (cc === 91 /* [ */) {
|
|
197
|
+
inClass = true;
|
|
198
|
+
i++;
|
|
199
|
+
continue;
|
|
200
|
+
}
|
|
201
|
+
if (cc === 93 /* ] */) {
|
|
202
|
+
inClass = false;
|
|
203
|
+
i++;
|
|
204
|
+
continue;
|
|
205
|
+
}
|
|
206
|
+
if (cc === 47 && !inClass) {
|
|
207
|
+
i++;
|
|
208
|
+
break;
|
|
209
|
+
}
|
|
210
|
+
if (cc === 10 /* newline */)
|
|
211
|
+
break; /* regex can't span lines */
|
|
212
|
+
i++;
|
|
213
|
+
}
|
|
214
|
+
/* Optional flags */
|
|
215
|
+
while (i < len && /[gimsuy]/.test(source[i] || ''))
|
|
216
|
+
i++;
|
|
217
|
+
lastSignificant = '/regex/';
|
|
218
|
+
continue;
|
|
219
|
+
}
|
|
220
|
+
/* String quote? */
|
|
221
|
+
if (c === 34 /* " */ || c === 39 /* ' */ || c === 96 /* ` */) {
|
|
222
|
+
const quote = c;
|
|
223
|
+
const start = i;
|
|
224
|
+
i++;
|
|
225
|
+
while (i < len) {
|
|
226
|
+
const cc = source.charCodeAt(i);
|
|
227
|
+
if (cc === 92 /* \ */) {
|
|
228
|
+
i += 2;
|
|
229
|
+
continue;
|
|
230
|
+
}
|
|
231
|
+
if (cc === quote) {
|
|
232
|
+
i++;
|
|
233
|
+
break;
|
|
234
|
+
}
|
|
235
|
+
if (quote === 96 && cc === 36 /* $ */ && i + 1 < len && source.charCodeAt(i + 1) === 123 /* { */) {
|
|
236
|
+
let depth = 1;
|
|
237
|
+
i += 2;
|
|
238
|
+
while (i < len && depth > 0) {
|
|
239
|
+
const cd = source.charCodeAt(i);
|
|
240
|
+
if (cd === 123)
|
|
241
|
+
depth++;
|
|
242
|
+
else if (cd === 125)
|
|
243
|
+
depth--;
|
|
244
|
+
i++;
|
|
245
|
+
}
|
|
246
|
+
continue;
|
|
247
|
+
}
|
|
248
|
+
i++;
|
|
249
|
+
}
|
|
250
|
+
for (let k = start; k < i; k++)
|
|
251
|
+
inStr[k] = 1;
|
|
252
|
+
lastSignificant = 'string';
|
|
253
|
+
continue;
|
|
254
|
+
}
|
|
255
|
+
/* Track the last significant token for regex disambiguation.
|
|
256
|
+
Whitespace + newlines do NOT reset it. */
|
|
257
|
+
if (c > 32) {
|
|
258
|
+
/* Identifier or keyword? Walk to capture full word. */
|
|
259
|
+
if ((c >= 65 && c <= 90) || (c >= 97 && c <= 122) || c === 95 || c === 36) {
|
|
260
|
+
let j = i;
|
|
261
|
+
while (j < len) {
|
|
262
|
+
const cj = source.charCodeAt(j);
|
|
263
|
+
if ((cj >= 65 && cj <= 90) || (cj >= 97 && cj <= 122) ||
|
|
264
|
+
(cj >= 48 && cj <= 57) || cj === 95 || cj === 36)
|
|
265
|
+
j++;
|
|
266
|
+
else
|
|
267
|
+
break;
|
|
268
|
+
}
|
|
269
|
+
lastSignificant = source.slice(i, j);
|
|
270
|
+
i = j;
|
|
271
|
+
continue;
|
|
272
|
+
}
|
|
273
|
+
/* Number? */
|
|
274
|
+
if (c >= 48 && c <= 57) {
|
|
275
|
+
while (i < len) {
|
|
276
|
+
const ci = source.charCodeAt(i);
|
|
277
|
+
if ((ci >= 48 && ci <= 57) || ci === 46)
|
|
278
|
+
i++;
|
|
279
|
+
else
|
|
280
|
+
break;
|
|
281
|
+
}
|
|
282
|
+
lastSignificant = '0';
|
|
283
|
+
continue;
|
|
284
|
+
}
|
|
285
|
+
/* Punctuation: record the single char. */
|
|
286
|
+
lastSignificant = source[i] || '';
|
|
287
|
+
}
|
|
288
|
+
i++;
|
|
289
|
+
}
|
|
290
|
+
return inStr;
|
|
291
|
+
}
|
|
292
|
+
/* ---- classification + inference helpers ---- */
|
|
293
|
+
function classifyRole(tag, attrsRaw) {
|
|
294
|
+
if (tag === 'input' || tag === 'textarea' || tag === 'select')
|
|
295
|
+
return 'field';
|
|
296
|
+
if (['main', 'section', 'aside', 'nav', 'article', 'header', 'footer', 'form'].includes(tag))
|
|
297
|
+
return 'region';
|
|
298
|
+
const role = /(?:^|\s)role\s*=\s*["']([^"']+)["']/.exec(attrsRaw)?.[1]?.toLowerCase();
|
|
299
|
+
if (role === 'tab')
|
|
300
|
+
return 'tab';
|
|
301
|
+
if (role === 'option')
|
|
302
|
+
return 'option';
|
|
303
|
+
return 'action';
|
|
304
|
+
}
|
|
305
|
+
function extractStaticAriaLabel(attrsRaw) {
|
|
306
|
+
/* Grab the aria-label value as a literal string up to the first
|
|
307
|
+
interpolation marker. We accept aria-label="..." and
|
|
308
|
+
aria-label='...'. */
|
|
309
|
+
const m = /aria-label\s*=\s*(["'])((?:\\.|(?!\1).)*)\1/.exec(attrsRaw);
|
|
310
|
+
if (!m || typeof m[2] !== 'string')
|
|
311
|
+
return null;
|
|
312
|
+
return m[2].trim() || null;
|
|
313
|
+
}
|
|
314
|
+
function extractStaticText(source, openTagOffset, openingTagText, isSelfClosing) {
|
|
315
|
+
if (isSelfClosing)
|
|
316
|
+
return null;
|
|
317
|
+
/* Find the matching `</tag>` in the rest of the source. We only
|
|
318
|
+
pull the LITERAL text between the open + close tags if the
|
|
319
|
+
close tag exists in the same string scope and no interpolation
|
|
320
|
+
splits the inner. This is best-effort. */
|
|
321
|
+
const tagMatch = /^<([a-zA-Z][a-zA-Z0-9]*)/.exec(openingTagText);
|
|
322
|
+
if (!tagMatch || !tagMatch[1])
|
|
323
|
+
return null;
|
|
324
|
+
const tag = tagMatch[1].toLowerCase();
|
|
325
|
+
const start = openTagOffset + openingTagText.length;
|
|
326
|
+
const closeRe = new RegExp('</' + tag + '\\s*>', 'gi');
|
|
327
|
+
closeRe.lastIndex = start;
|
|
328
|
+
const cm = closeRe.exec(source);
|
|
329
|
+
if (!cm)
|
|
330
|
+
return null;
|
|
331
|
+
const innerRaw = source.slice(start, cm.index);
|
|
332
|
+
/* If inner has unbalanced quotes or string-boundary chars + JS
|
|
333
|
+
concatenation operators, bail. */
|
|
334
|
+
if (/['"`]\s*\+|\+\s*['"`]/.test(innerRaw)) {
|
|
335
|
+
/* Has concatenation -- the text is dynamic. Extract the
|
|
336
|
+
leading literal portion only. */
|
|
337
|
+
const leading = innerRaw.split(/['"`]\s*\+/)[0] ?? '';
|
|
338
|
+
return leading.replace(/[<>]/g, '').trim().slice(0, 80) || null;
|
|
339
|
+
}
|
|
340
|
+
return innerRaw.replace(/[<>]/g, '').trim().slice(0, 80) || null;
|
|
341
|
+
}
|
|
342
|
+
function inferVerbFromAttrs(role, tag, aria, text, attrsRaw) {
|
|
343
|
+
if (role !== 'action' && role !== 'tab')
|
|
344
|
+
return null;
|
|
345
|
+
/* Build a minimal DOM stub so we can reuse the same L1-L5
|
|
346
|
+
classifier the HTML walker uses. */
|
|
347
|
+
const stub = parse('<' + tag + ' '
|
|
348
|
+
+ (attrsRaw.replace(/\$\{[^}]*\}/g, '*').replace(/['"]\s*\+\s*[^+]*\+\s*['"]/g, '*'))
|
|
349
|
+
+ '>' + (text ?? aria ?? '') + '</' + tag + '>');
|
|
350
|
+
const el = stub.firstChild;
|
|
351
|
+
if (!el)
|
|
352
|
+
return null;
|
|
353
|
+
const hit = inferVerb(el);
|
|
354
|
+
return hit?.verb ?? null;
|
|
355
|
+
}
|
|
356
|
+
function detectDynamicIdExpr(source, openTagOffset, openingTagText) {
|
|
357
|
+
/* Layered detection. Each layer scans the opening tag (+ a bit
|
|
358
|
+
of slack) for an interpolation pattern. First hit wins.
|
|
359
|
+
Layers in priority order:
|
|
360
|
+
L1 aria-label="...${EXPR}..." (strongest signal)
|
|
361
|
+
L2 data-*-id / data-*-key="...EXPR..."
|
|
362
|
+
L3 id="...EXPR..."
|
|
363
|
+
L4 most-frequent expression in opening tag (fallback) */
|
|
364
|
+
/* L1: aria-label interpolation */
|
|
365
|
+
const fromAria = extractInterpolationInAttr(source, openTagOffset, openingTagText, /aria-label/);
|
|
366
|
+
if (fromAria)
|
|
367
|
+
return fromAria;
|
|
368
|
+
/* L2: data-*-id / data-key / data-row-id / etc. */
|
|
369
|
+
const fromDataId = extractInterpolationInAttr(source, openTagOffset, openingTagText, /data-([a-z0-9_-]*)(id|key|row-id|item-id|line-id|invoice-id|order-id|user-id)/i);
|
|
370
|
+
if (fromDataId)
|
|
371
|
+
return fromDataId;
|
|
372
|
+
/* L3: id="...EXPR..." */
|
|
373
|
+
const fromId = extractInterpolationInAttr(source, openTagOffset, openingTagText, /\bid\b/);
|
|
374
|
+
if (fromId)
|
|
375
|
+
return fromId;
|
|
376
|
+
/* L4: most-frequent JS interpolation in the opening tag.
|
|
377
|
+
If the row identity isn't tagged in any attr, we look at every
|
|
378
|
+
`'..' + EXPR + '..'` chunk inside the opening tag and pick the
|
|
379
|
+
EXPR that appears most often. Tied counts break in favour of
|
|
380
|
+
the shortest expression (heuristic: `inv.id` beats
|
|
381
|
+
`escapeHtml(inv.client_name)`).
|
|
382
|
+
|
|
383
|
+
CRITICAL: window stays WITHIN the opening tag. Going past the
|
|
384
|
+
`>` includes interpolations from sibling tags and ends up
|
|
385
|
+
picking the wrong dynamic id. */
|
|
386
|
+
const exprs = collectInterpolations(openingTagText);
|
|
387
|
+
if (exprs.length > 0) {
|
|
388
|
+
const counts = new Map();
|
|
389
|
+
for (const e of exprs)
|
|
390
|
+
counts.set(e, (counts.get(e) || 0) + 1);
|
|
391
|
+
const ranked = [...counts.entries()].sort((a, b) => {
|
|
392
|
+
if (b[1] !== a[1])
|
|
393
|
+
return b[1] - a[1];
|
|
394
|
+
return a[0].length - b[0].length;
|
|
395
|
+
});
|
|
396
|
+
const winner = ranked[0];
|
|
397
|
+
if (winner && winner[1] >= 1)
|
|
398
|
+
return winner[0];
|
|
399
|
+
}
|
|
400
|
+
return null;
|
|
401
|
+
}
|
|
402
|
+
/**
|
|
403
|
+
* Find the first JS expression interpolated inside the value of the
|
|
404
|
+
* first attribute whose name matches `attrPattern`. Returns null if
|
|
405
|
+
* the attribute is absent or has no interpolation.
|
|
406
|
+
*
|
|
407
|
+
* The interpolation can be either string-concat (`'..' + EXPR + '..'`
|
|
408
|
+
* OR `".." + EXPR + ".."`, possibly with mismatched HTML/JS quotes)
|
|
409
|
+
* or template-literal (`${EXPR}`).
|
|
410
|
+
*
|
|
411
|
+
* Critical detail: the HTML attribute quote and the JS-string quote
|
|
412
|
+
* may differ. Common case: JS string uses `'` (single) and HTML
|
|
413
|
+
* attribute uses `"` (double). The detector must not assume they
|
|
414
|
+
* match.
|
|
415
|
+
*/
|
|
416
|
+
function extractInterpolationInAttr(source, openTagOffset, openingTagText, attrPattern) {
|
|
417
|
+
const re = new RegExp(`(${attrPattern.source})\\s*=\\s*['"]`, attrPattern.flags || 'i');
|
|
418
|
+
const m = re.exec(openingTagText);
|
|
419
|
+
if (!m)
|
|
420
|
+
return null;
|
|
421
|
+
const attrStartRel = m.index;
|
|
422
|
+
const valStartRel = attrStartRel + m[0].length - 1; /* index of the opening HTML-attr quote */
|
|
423
|
+
const htmlQuote = openingTagText[valStartRel] || '"';
|
|
424
|
+
/* Find the matching closing HTML-attr quote in openingTagText.
|
|
425
|
+
We do NOT respect JS-string boundaries here -- we just look
|
|
426
|
+
for the next char === htmlQuote that is not preceded by `\`. */
|
|
427
|
+
let valEndRel = valStartRel + 1;
|
|
428
|
+
while (valEndRel < openingTagText.length) {
|
|
429
|
+
const ch = openingTagText[valEndRel];
|
|
430
|
+
if (ch === htmlQuote && openingTagText[valEndRel - 1] !== '\\')
|
|
431
|
+
break;
|
|
432
|
+
valEndRel++;
|
|
433
|
+
}
|
|
434
|
+
if (valEndRel >= openingTagText.length)
|
|
435
|
+
return null;
|
|
436
|
+
/* The attribute value region spans [valStartRel+1, valEndRel)
|
|
437
|
+
in openingTagText. Within this region, look for any concat
|
|
438
|
+
or template interpolation. */
|
|
439
|
+
const valRegion = openingTagText.slice(valStartRel + 1, valEndRel);
|
|
440
|
+
/* concat interpolation: '<quote> + EXPR + <quote>' where
|
|
441
|
+
<quote> is either ' or ". The JS string could have been
|
|
442
|
+
opened with EITHER. We accept either inside the value. */
|
|
443
|
+
const concatRe = /(['"`])\s*\+\s*([^+]+?)\s*\+\s*\1/;
|
|
444
|
+
const cm = concatRe.exec(valRegion);
|
|
445
|
+
if (cm && cm[2])
|
|
446
|
+
return cm[2].trim();
|
|
447
|
+
/* template literal interpolation */
|
|
448
|
+
const tplRe = /\$\{([^}]+)\}/;
|
|
449
|
+
const tm = tplRe.exec(valRegion);
|
|
450
|
+
if (tm && tm[1])
|
|
451
|
+
return tm[1].trim();
|
|
452
|
+
return null;
|
|
453
|
+
}
|
|
454
|
+
/**
|
|
455
|
+
* Collect every JS expression that appears as an interpolation
|
|
456
|
+
* (either `' + EXPR + '` style concat OR `${EXPR}` template) within
|
|
457
|
+
* the given source slice. Used by the L4 fallback heuristic to
|
|
458
|
+
* pick the row identity by frequency.
|
|
459
|
+
*/
|
|
460
|
+
function collectInterpolations(slice) {
|
|
461
|
+
const out = [];
|
|
462
|
+
/* concat pattern */
|
|
463
|
+
const concatRe = /['"]\s*\+\s*([^+'"]+?)\s*\+\s*['"]/g;
|
|
464
|
+
let cm;
|
|
465
|
+
while ((cm = concatRe.exec(slice)) !== null) {
|
|
466
|
+
const e = (cm[1] ?? '').trim();
|
|
467
|
+
if (e && e.length < 100)
|
|
468
|
+
out.push(e);
|
|
469
|
+
}
|
|
470
|
+
/* template literal pattern */
|
|
471
|
+
const tplRe = /\$\{([^}]+)\}/g;
|
|
472
|
+
let tm;
|
|
473
|
+
while ((tm = tplRe.exec(slice)) !== null) {
|
|
474
|
+
const e = (tm[1] ?? '').trim();
|
|
475
|
+
if (e && e.length < 100)
|
|
476
|
+
out.push(e);
|
|
477
|
+
}
|
|
478
|
+
return out;
|
|
479
|
+
}
|
|
480
|
+
function derivePluginSlug(filePath, source, openTagOffset) {
|
|
481
|
+
/* Look backward for a function name + try to derive a slug from
|
|
482
|
+
it OR from filename. */
|
|
483
|
+
const fnRe = /function\s+(render[A-Z][a-zA-Z0-9_]*)\s*\(/g;
|
|
484
|
+
let lastFn = null;
|
|
485
|
+
let fm;
|
|
486
|
+
while ((fm = fnRe.exec(source)) !== null) {
|
|
487
|
+
if (fm.index >= openTagOffset)
|
|
488
|
+
break;
|
|
489
|
+
lastFn = fm[1] ?? null;
|
|
490
|
+
}
|
|
491
|
+
if (lastFn) {
|
|
492
|
+
const slug = lastFn
|
|
493
|
+
.replace(/^render/, '')
|
|
494
|
+
.replace(/([A-Z])/g, '_$1')
|
|
495
|
+
.toLowerCase()
|
|
496
|
+
.replace(/^_+/, '');
|
|
497
|
+
if (slug)
|
|
498
|
+
return slug;
|
|
499
|
+
}
|
|
500
|
+
return path.basename(filePath)
|
|
501
|
+
.replace(/\.(js|jsx|ts|tsx|mjs)$/, '')
|
|
502
|
+
.toLowerCase()
|
|
503
|
+
.replace(/[^a-z0-9_]+/g, '_')
|
|
504
|
+
.replace(/^_+|_+$/g, '') || 'page';
|
|
505
|
+
}
|
|
506
|
+
function buildProposedIdTemplate(plugin, role, verb, tag, dynamicIdExpr, aria, text) {
|
|
507
|
+
const stem = (aria ?? text ?? verb ?? tag)
|
|
508
|
+
.toLowerCase()
|
|
509
|
+
.replace(/[^a-z0-9]+/g, '_')
|
|
510
|
+
.replace(/^_+|_+$/g, '')
|
|
511
|
+
.slice(0, 24);
|
|
512
|
+
const base = plugin + '.' + role + '_' + (verb ?? tag);
|
|
513
|
+
if (dynamicIdExpr) {
|
|
514
|
+
/* Encode the dynamic id as a template marker {{EXPR}}. The
|
|
515
|
+
rewriter weaves it back into the source as a real JS concat. */
|
|
516
|
+
return base + '.{{' + dynamicIdExpr + '}}';
|
|
517
|
+
}
|
|
518
|
+
if (stem && stem !== (verb ?? tag))
|
|
519
|
+
return base + '.' + stem;
|
|
520
|
+
return base;
|
|
521
|
+
}
|
|
522
|
+
function computeConfidence(args) {
|
|
523
|
+
let conf = 0.4; // base
|
|
524
|
+
if (args.role === 'field' || args.role === 'region')
|
|
525
|
+
conf += 0.35;
|
|
526
|
+
if (args.verb)
|
|
527
|
+
conf += 0.25;
|
|
528
|
+
if (args.ariaStatic)
|
|
529
|
+
conf += 0.15;
|
|
530
|
+
if (args.dynamicIdExpr)
|
|
531
|
+
conf += 0.10; // unique-per-row
|
|
532
|
+
return Math.min(1, conf);
|
|
533
|
+
}
|
|
534
|
+
function computeFingerprint(filePath, tag, role, aria, text, dynamicIdExpr) {
|
|
535
|
+
const seed = JSON.stringify({
|
|
536
|
+
file: filePath, tag, role,
|
|
537
|
+
aria: (aria ?? '').slice(0, 60),
|
|
538
|
+
text: (text ?? '').slice(0, 60),
|
|
539
|
+
dyn: dynamicIdExpr ?? '',
|
|
540
|
+
});
|
|
541
|
+
return crypto.createHash('sha256').update(seed).digest('hex').slice(0, 16);
|
|
542
|
+
}
|
|
543
|
+
/**
|
|
544
|
+
* Rewrite a JS source string by injecting NAC attrs into the
|
|
545
|
+
* opening tags identified by `decisions`. Decisions must reference
|
|
546
|
+
* the SAME source you read (offsets are absolute).
|
|
547
|
+
*
|
|
548
|
+
* For dynamic id templates of the form "<base>.{{EXPR}}", the
|
|
549
|
+
* inserted attrs use JS string-concatenation that weaves EXPR back
|
|
550
|
+
* into the rendered HTML:
|
|
551
|
+
*
|
|
552
|
+
* ' data-nac-id="<base>.' + escapeHtml(EXPR) + '" '
|
|
553
|
+
*
|
|
554
|
+
* (We use escapeHtml when the source defines such a helper; we
|
|
555
|
+
* fall back to inline `String(...)` otherwise. The detection runs
|
|
556
|
+
* once per file.)
|
|
557
|
+
*/
|
|
558
|
+
export function applyJsDecisions(source, decisions) {
|
|
559
|
+
if (decisions.length === 0)
|
|
560
|
+
return source;
|
|
561
|
+
/* Determine helper name */
|
|
562
|
+
const hasEscapeHtml = /\bfunction\s+escapeHtml\b|escapeHtml\s*=/.test(source);
|
|
563
|
+
const escape = hasEscapeHtml ? 'escapeHtml' : 'String';
|
|
564
|
+
/* Sort decisions DESC by offset so earlier injections do not
|
|
565
|
+
shift later positions. */
|
|
566
|
+
const sorted = [...decisions].sort((a, b) => b.offset - a.offset);
|
|
567
|
+
let out = source;
|
|
568
|
+
for (const d of sorted) {
|
|
569
|
+
const opening = out.slice(d.offset, d.offset + d.opening_tag_text.length);
|
|
570
|
+
if (opening !== d.opening_tag_text) {
|
|
571
|
+
/* The source has changed under us -- skip this decision. */
|
|
572
|
+
continue;
|
|
573
|
+
}
|
|
574
|
+
/* The opening text ends with `>` (or `/>`). Insert before that. */
|
|
575
|
+
const last = opening.lastIndexOf('>');
|
|
576
|
+
const isSelfClose = opening[last - 1] === '/';
|
|
577
|
+
const insertAt = d.offset + (isSelfClose ? last - 1 : last);
|
|
578
|
+
/* Compose the attr injection. */
|
|
579
|
+
const inj = composeAttrInjection(d, escape);
|
|
580
|
+
out = out.slice(0, insertAt) + inj + out.slice(insertAt);
|
|
581
|
+
}
|
|
582
|
+
return out;
|
|
583
|
+
}
|
|
584
|
+
function composeAttrInjection(d, escape) {
|
|
585
|
+
/* Detect the JS-string kind of the surrounding context by
|
|
586
|
+
inspecting the opening_tag_text. */
|
|
587
|
+
const inConcatString = /['"]\s*\+\s*[^+]+\+\s*['"]/.test(d.opening_tag_text);
|
|
588
|
+
const inTemplateString = /\$\{[^}]+\}/.test(d.opening_tag_text);
|
|
589
|
+
const idTemplate = d.nac_id_template;
|
|
590
|
+
const m = /^(.+?)\.\{\{(.+)\}\}$/.exec(idTemplate);
|
|
591
|
+
if (m) {
|
|
592
|
+
const base = m[1] ?? '';
|
|
593
|
+
const expr = m[2] ?? '';
|
|
594
|
+
/* If the expression already includes a function call (looks like
|
|
595
|
+
`escapeHtml(...)`, `String(...)`, `Number(...)`, etc.), do NOT
|
|
596
|
+
wrap again -- double-wrapping produces nonsense like
|
|
597
|
+
`escapeHtml(escapeHtml(x))`. We detect a leading identifier
|
|
598
|
+
followed by `(`. */
|
|
599
|
+
const exprIsCall = /^[A-Za-z_$][\w$]*\s*\(/.test(expr);
|
|
600
|
+
const safeExpr = exprIsCall ? expr : `${escape}(${expr})`;
|
|
601
|
+
if (inTemplateString || (!inConcatString && /`/.test(d.opening_tag_text))) {
|
|
602
|
+
/* Template literal form: ` data-nac-id="<base>.${EXPR}" data-nac-role="<role>"...` */
|
|
603
|
+
let inj = ` data-nac-id="${base}.\${${expr}}" data-nac-role="${d.role}"`;
|
|
604
|
+
if (d.verb)
|
|
605
|
+
inj += ` data-nac-action="${d.verb}"`;
|
|
606
|
+
return inj;
|
|
607
|
+
}
|
|
608
|
+
/* Default: single-quote string concat. Detect the surrounding
|
|
609
|
+
JS-quote (the JS-string this opening tag lives in) by
|
|
610
|
+
inspecting how the existing string is composed. We use `'`
|
|
611
|
+
by default since invoice-app + most jQuery-era code uses
|
|
612
|
+
single-quoted JS strings. */
|
|
613
|
+
let inj = ' data-nac-id="' + base + '.\' + ' + safeExpr + ' + \'" data-nac-role="' + d.role + '"';
|
|
614
|
+
if (d.verb)
|
|
615
|
+
inj += ' data-nac-action="' + d.verb + '"';
|
|
616
|
+
return inj;
|
|
617
|
+
}
|
|
618
|
+
/* Static id */
|
|
619
|
+
if (inTemplateString) {
|
|
620
|
+
let inj = ` data-nac-id="${idTemplate}" data-nac-role="${d.role}"`;
|
|
621
|
+
if (d.verb)
|
|
622
|
+
inj += ` data-nac-action="${d.verb}"`;
|
|
623
|
+
return inj;
|
|
624
|
+
}
|
|
625
|
+
let inj = ' data-nac-id="' + idTemplate + '" data-nac-role="' + d.role + '"';
|
|
626
|
+
if (d.verb)
|
|
627
|
+
inj += ' data-nac-action="' + d.verb + '"';
|
|
628
|
+
return inj;
|
|
629
|
+
}
|
|
630
|
+
/* ---- File-level helpers ---- */
|
|
631
|
+
export async function scanJsFile(filePath) {
|
|
632
|
+
const source = await fs.readFile(filePath, 'utf-8');
|
|
633
|
+
return scanJsTemplates(filePath, source);
|
|
634
|
+
}
|
|
635
|
+
export async function applyJsDecisionsToFile(filePath, decisions, options = {}) {
|
|
636
|
+
const source = await fs.readFile(filePath, 'utf-8');
|
|
637
|
+
const out = applyJsDecisions(source, decisions);
|
|
638
|
+
if (!options.dryRun && out !== source) {
|
|
639
|
+
await fs.writeFile(filePath, out, 'utf-8');
|
|
640
|
+
return { source: out, wrote: true };
|
|
641
|
+
}
|
|
642
|
+
return { source: out, wrote: false };
|
|
643
|
+
}
|
|
644
|
+
//# sourceMappingURL=js-template-walker.js.map
|