@simplysm/sd-claude 14.0.65 → 14.0.66
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/claude/references/sd-requirement-source-handling.md +64 -0
- package/claude/references/sd-simplysm14/README.md +44 -40
- package/claude/references/sd-simplysm14/apis/angular/README.md +95 -0
- package/claude/references/sd-simplysm14/apis/angular/app-structure.md +49 -0
- package/claude/references/sd-simplysm14/apis/angular/buttons.md +42 -0
- package/claude/references/sd-simplysm14/apis/angular/crud.md +35 -0
- package/claude/references/sd-simplysm14/apis/angular/forms.md +63 -0
- package/claude/references/sd-simplysm14/apis/angular/infrastructure.md +80 -0
- package/claude/references/sd-simplysm14/apis/angular/kanban.md +33 -0
- package/claude/references/sd-simplysm14/apis/angular/layout.md +41 -0
- package/claude/references/sd-simplysm14/apis/angular/modal.md +63 -0
- package/claude/references/sd-simplysm14/apis/angular/routing.md +45 -0
- package/claude/references/sd-simplysm14/apis/angular/select-dropdown.md +35 -0
- package/claude/references/sd-simplysm14/apis/angular/selection-managers.md +50 -0
- package/claude/references/sd-simplysm14/apis/angular/shared-data.md +42 -0
- package/claude/references/sd-simplysm14/apis/angular/sheet.md +52 -0
- package/claude/references/sd-simplysm14/apis/angular/toast.md +46 -0
- package/claude/references/sd-simplysm14/apis/angular/visual.md +41 -0
- package/claude/references/sd-simplysm14/apis/capacitor-plugin-auto-update/README.md +76 -0
- package/claude/references/sd-simplysm14/apis/capacitor-plugin-file-system/README.md +83 -0
- package/claude/references/sd-simplysm14/apis/capacitor-plugin-intent/README.md +80 -0
- package/claude/references/sd-simplysm14/apis/capacitor-plugin-usb-storage/README.md +39 -0
- package/claude/references/sd-simplysm14/apis/core-browser/README.md +112 -0
- package/claude/references/sd-simplysm14/apis/core-common/README.md +53 -0
- package/claude/references/sd-simplysm14/apis/core-common/extensions.md +123 -0
- package/claude/references/sd-simplysm14/apis/core-common/features.md +46 -0
- package/claude/references/sd-simplysm14/apis/core-common/types.md +114 -0
- package/claude/references/sd-simplysm14/apis/core-common/utils.md +158 -0
- package/claude/references/sd-simplysm14/apis/core-node/README.md +12 -0
- package/claude/references/sd-simplysm14/apis/core-node/consola.md +64 -0
- package/claude/references/sd-simplysm14/apis/core-node/cpx.md +52 -0
- package/claude/references/sd-simplysm14/apis/core-node/fs-watcher.md +53 -0
- package/claude/references/sd-simplysm14/apis/core-node/fsx.md +81 -0
- package/claude/references/sd-simplysm14/apis/core-node/pathx.md +55 -0
- package/claude/references/sd-simplysm14/apis/core-node/worker.md +111 -0
- package/claude/references/sd-simplysm14/apis/excel/README.md +81 -0
- package/claude/references/sd-simplysm14/apis/lint/README.md +80 -0
- package/claude/references/sd-simplysm14/apis/orm-common/README.md +33 -0
- package/claude/references/sd-simplysm14/apis/orm-common/db-context.md +77 -0
- package/claude/references/sd-simplysm14/apis/orm-common/executable.md +20 -0
- package/claude/references/sd-simplysm14/apis/orm-common/expr.md +92 -0
- package/claude/references/sd-simplysm14/apis/orm-common/queryable.md +98 -0
- package/claude/references/sd-simplysm14/apis/orm-common/schema-builders.md +128 -0
- package/claude/references/sd-simplysm14/apis/orm-node/README.md +59 -0
- package/claude/references/sd-simplysm14/apis/sd-claude/README.md +9 -0
- package/claude/references/sd-simplysm14/apis/sd-cli/README.md +50 -0
- package/claude/references/sd-simplysm14/apis/sd-cli/sd-config.md +155 -0
- package/claude/references/sd-simplysm14/apis/service-client/README.md +92 -0
- package/claude/references/sd-simplysm14/apis/service-common/README.md +29 -0
- package/claude/references/sd-simplysm14/apis/service-common/app-structure.md +63 -0
- package/claude/references/sd-simplysm14/apis/service-common/messages.md +56 -0
- package/claude/references/sd-simplysm14/apis/service-common/protocol.md +64 -0
- package/claude/references/sd-simplysm14/apis/service-common/service-types.md +43 -0
- package/claude/references/sd-simplysm14/apis/service-server/README.md +20 -0
- package/claude/references/sd-simplysm14/apis/service-server/auth.md +31 -0
- package/claude/references/sd-simplysm14/apis/service-server/builtin-services.md +47 -0
- package/claude/references/sd-simplysm14/apis/service-server/define-service.md +71 -0
- package/claude/references/sd-simplysm14/apis/service-server/internals.md +41 -0
- package/claude/references/sd-simplysm14/apis/service-server/server.md +66 -0
- package/claude/references/sd-simplysm14/apis/storage/README.md +69 -0
- package/claude/references/sd-simplysm14/{client-component.md → manuals/client-component.md} +133 -128
- package/claude/references/sd-simplysm14/manuals/client-crud.md +102 -0
- package/claude/references/sd-simplysm14/manuals/client-demo.md +128 -0
- package/claude/references/sd-simplysm14/manuals/client-rules.md +7 -0
- package/claude/references/sd-simplysm14/{client-setup.md → manuals/client-setup.md} +2 -2
- package/claude/references/sd-simplysm14/{client-tab.md → manuals/client-tab.md} +13 -11
- package/claude/references/sd-simplysm14/{orm-union.md → manuals/orm-union.md} +1 -1
- package/claude/references/sd-simplysm14/manuals/orm.md +75 -0
- package/claude/rules/sd-base-rules.md +172 -79
- package/claude/sd-check-bash.py +5 -0
- package/claude/sd-statusline.py +7 -12
- package/claude/skills/sd-commit/SKILL.md +7 -3
- package/claude/skills/sd-demo/SKILL.md +81 -62
- package/claude/skills/sd-demo/evals/fixtures/empty/.specs/260513120000_warehouse/spec.md +45 -0
- package/claude/skills/sd-demo/evals/fixtures/with-existing-screen/.specs/260513120000_warehouse/spec.md +42 -0
- package/claude/skills/sd-demo/evals/fixtures/with-existing-screen/packages/app/src/screens/dashboard/dashboard.view.ts +33 -0
- package/claude/skills/sd-demo/evals/fixtures/with-master-screen/.specs/260513120000_warehouse/spec.md +45 -0
- package/claude/skills/sd-demo/evals/fixtures/with-master-screen/packages/app/src/screens/dashboard/dashboard.view.ts +33 -0
- package/claude/skills/sd-demo/evals/fixtures/with-modal/.specs/260513120000_warehouse/spec.md +75 -0
- package/claude/skills/sd-demo/evals/fixtures/with-modal/packages/app/src/screens/dashboard/dashboard.view.ts +33 -0
- package/claude/skills/sd-demo/evals/fixtures/with-screens/.specs/260513120000_warehouse/spec.md +45 -0
- package/claude/skills/sd-demo/evals/fixtures/with-screens/packages/app/src/screens/dashboard/dashboard.view.ts +33 -0
- package/claude/skills/sd-demo/evals/golden.jsonl +5 -3
- package/claude/skills/sd-dev/SKILL.md +33 -63
- package/claude/skills/sd-dev/evals/fixtures/case-add/package.json +13 -0
- package/claude/skills/sd-dev/evals/fixtures/case-add/src/index.ts +10 -0
- package/claude/skills/sd-dev/evals/fixtures/case-add/tests/index.test.ts +11 -0
- package/claude/skills/sd-dev/evals/fixtures/case-add/tsconfig.json +12 -0
- package/claude/skills/sd-dev/evals/fixtures/case-bug/package.json +13 -0
- package/claude/skills/sd-dev/evals/fixtures/case-bug/src/index.ts +10 -0
- package/claude/skills/sd-dev/evals/fixtures/case-bug/tests/index.test.ts +11 -0
- package/claude/skills/sd-dev/evals/fixtures/case-bug/tsconfig.json +12 -0
- package/claude/skills/sd-dev/evals/fixtures/case-modify/package.json +13 -0
- package/claude/skills/sd-dev/evals/fixtures/case-modify/src/index.ts +10 -0
- package/claude/skills/sd-dev/evals/fixtures/case-modify/tests/index.test.ts +11 -0
- package/claude/skills/sd-dev/evals/fixtures/case-modify/tsconfig.json +12 -0
- package/claude/skills/sd-dev/evals/golden.jsonl +3 -3
- package/claude/skills/sd-docs/SKILL.md +53 -0
- package/claude/skills/sd-docs/evals/fixtures/new-write/.claude/references/sd-simplysm14/README.md +7 -0
- package/claude/skills/sd-docs/evals/fixtures/new-write/packages/bar/package.json +5 -0
- package/claude/skills/sd-docs/evals/fixtures/new-write/packages/bar/src/index.ts +3 -0
- package/claude/skills/sd-docs/evals/fixtures/new-write/packages/baz/package.json +6 -0
- package/claude/skills/sd-docs/evals/fixtures/new-write/packages/baz/src/index.ts +1 -0
- package/claude/skills/sd-docs/evals/fixtures/new-write/packages/foo/package.json +5 -0
- package/claude/skills/sd-docs/evals/fixtures/new-write/packages/foo/src/index.ts +8 -0
- package/claude/skills/sd-docs/evals/fixtures/update-mixed/.claude/references/sd-simplysm14/README.md +7 -0
- package/claude/skills/sd-docs/evals/fixtures/update-mixed/.claude/references/sd-simplysm14/apis/foo/README.md +3 -0
- package/claude/skills/sd-docs/evals/fixtures/update-mixed/packages/bar/package.json +5 -0
- package/claude/skills/sd-docs/evals/fixtures/update-mixed/packages/bar/src/index.ts +3 -0
- package/claude/skills/sd-docs/evals/fixtures/update-mixed/packages/baz/package.json +6 -0
- package/claude/skills/sd-docs/evals/fixtures/update-mixed/packages/baz/src/index.ts +1 -0
- package/claude/skills/sd-docs/evals/fixtures/update-mixed/packages/foo/package.json +5 -0
- package/claude/skills/sd-docs/evals/fixtures/update-mixed/packages/foo/src/index.ts +8 -0
- package/claude/skills/sd-docs/evals/golden.jsonl +2 -0
- package/claude/skills/sd-docs/references/subagent-prompt.md +100 -0
- package/claude/skills/sd-impl/SKILL.md +125 -46
- package/claude/skills/sd-impl/evals/fixtures/case-new/.specs/260514120000_/352/261/260/353/236/230/354/262/230/spec.md +101 -0
- package/claude/skills/sd-impl/evals/fixtures/case-update/.specs/260514120000_/352/261/260/353/236/230/354/262/230/spec.md +101 -0
- package/claude/skills/sd-impl/evals/fixtures/case-update/src//352/261/260/353/236/230/354/262/230//352/261/260/353/236/230/354/262/230-/353/252/250/353/215/270.txt +1 -0
- package/claude/skills/sd-impl/evals/fixtures/case-update/src//352/261/260/353/236/230/354/262/230//352/261/260/353/236/230/354/262/230-/353/252/251/353/241/235.txt +1 -0
- package/claude/skills/sd-impl/evals/golden.jsonl +2 -3
- package/claude/skills/sd-skill/SKILL.md +3 -3
- package/claude/skills/sd-skill/evals/golden.jsonl +0 -1
- package/claude/skills/sd-skill/references/eval-authoring.md +15 -0
- package/claude/skills/sd-skill/references/eval-run.md +1 -1
- package/claude/skills/sd-skill/references/skill-authoring.md +8 -5
- package/claude/skills/sd-skill/scripts/run_eval.py +39 -60
- package/claude/skills/sd-spec/SKILL.md +163 -105
- package/claude/skills/sd-spec/references/example-spec.md +585 -0
- package/claude/skills/sd-spec/references/spec-authoring.md +287 -0
- package/claude/skills/sd-spec/references/spec-md-template.md +15 -93
- package/claude/skills/sd-unpack/SKILL.md +7 -1
- package/claude/skills/sd-unpack/scripts/handlers/_common.py +10 -0
- package/claude/skills/sd-unpack/scripts/handlers/eml_handler.py +5 -13
- package/claude/skills/sd-unpack/scripts/handlers/msg_handler.py +3 -12
- package/claude/skills/sd-unpack/scripts/handlers/office_com.py +23 -37
- package/claude/skills/sd-unpack/scripts/handlers/office_worker.py +1 -4
- package/claude/skills/sd-unpack/scripts/handlers/pdf_handler.py +4 -13
- package/claude/skills/sd-unpack/scripts/unpack.py +4 -4
- package/claude/skills/sd-use/SKILL.md +1 -0
- package/claude/skills/sd-wip/SKILL.md +38 -0
- package/claude/skills/sd-wip/evals/fixtures/with-artifact/projects/acct/_wip.md +3 -0
- package/claude/skills/sd-wip/evals/fixtures/with-artifact/projects/acct/spec.md +15 -0
- package/claude/skills/sd-wip/evals/fixtures/with-existing-wip/.wips/260101120000_acct.md +6 -0
- package/claude/skills/sd-wip/evals/fixtures/with-existing-wip-for-compact/.wips/260101120000_acct.md +14 -0
- package/claude/skills/sd-wip/evals/golden.jsonl +4 -0
- package/claude/skills/sd-wip/references/compact.md +79 -0
- package/package.json +1 -1
- package/claude/references/sd-simplysm14/orm.md +0 -11
- package/claude/skills/sd-demo/evals/fixtures/basic-single-req/.specs/260503143025/REQ-001-/354/236/205/352/263/240/354/247/200/354/213/234/354/204/234/352/270/264/352/270/211/355/221/234/354/213/234/spec.md +0 -27
- package/claude/skills/sd-demo/evals/fixtures/basic-single-req/.specs/260503143025/overview.md +0 -12
- package/claude/skills/sd-demo/evals/fixtures/basic-single-req/src/components/Button.tsx +0 -12
- package/claude/skills/sd-demo/evals/fixtures/basic-single-req/src/components/Input.tsx +0 -27
- package/claude/skills/sd-demo/evals/fixtures/mock-data-policy/.specs/260503143025/REQ-001-/352/261/260/353/236/230/354/262/230/353/252/251/353/241/235/355/231/224/353/251/264/spec.md +0 -25
- package/claude/skills/sd-demo/evals/fixtures/mock-data-policy/.specs/260503143025/overview.md +0 -12
- package/claude/skills/sd-demo/evals/fixtures/mock-data-policy/src/components/Input.tsx +0 -25
- package/claude/skills/sd-demo/evals/fixtures/mock-data-policy/src/pages/.gitkeep +0 -0
- package/claude/skills/sd-demo/evals/fixtures/multi-req-domain/.specs/260503143025/REQ-001-RTP/354/236/205/353/240/245/355/231/224/353/251/264/spec.md +0 -19
- package/claude/skills/sd-demo/evals/fixtures/multi-req-domain/.specs/260503143025/REQ-002-RTP/354/266/234/353/240/245/355/231/224/353/251/264/spec.md +0 -20
- package/claude/skills/sd-demo/evals/fixtures/multi-req-domain/.specs/260503143025/overview.md +0 -16
- package/claude/skills/sd-demo/evals/fixtures/multi-req-domain/src/components/Button.tsx +0 -6
- package/claude/skills/sd-demo/evals/fixtures/multi-req-domain/src/components/Input.tsx +0 -15
- package/claude/skills/sd-demo/evals/fixtures/multi-req-domain/src/pages/.gitkeep +0 -0
- package/claude/skills/sd-demo/references/demo-md-template.md +0 -92
- package/claude/skills/sd-dev/evals/fixtures/multi-req-stop-after-spec/.docs/20260301_/352/263/240/352/260/235/354/202/254_/354/236/205/352/263/240/354/232/224/354/262/255.eml +0 -5
- package/claude/skills/sd-dev/evals/fixtures/multi-req-stop-after-spec/.docs/20260305_/352/263/240/352/260/235/354/202/254_/354/266/234/352/263/240/354/232/224/354/262/255.eml +0 -6
- package/claude/skills/sd-dev/evals/fixtures/multi-req-stop-after-spec/.docs/20260310_/352/263/240/352/260/235/354/202/254_/352/266/214/355/225/234.eml +0 -6
- package/claude/skills/sd-dev/evals/fixtures/single-req-auto-chain/src/lib/.gitkeep +0 -0
- package/claude/skills/sd-dev/evals/fixtures/start-from-plan/.specs/260503143025/REQ-001-/355/225/240/354/235/270/352/263/204/354/202/260/spec.md +0 -12
- package/claude/skills/sd-dev/evals/fixtures/start-from-plan/src/lib/.gitkeep +0 -0
- package/claude/skills/sd-impl/evals/fixtures/basic-single-r/.specs/260503143025/REQ-001-/354/236/205/352/263/240/354/247/200/354/213/234/354/204/234/352/270/264/352/270/211/355/221/234/354/213/234/plan.md +0 -28
- package/claude/skills/sd-impl/evals/fixtures/basic-single-r/.specs/260503143025/REQ-001-/354/236/205/352/263/240/354/247/200/354/213/234/354/204/234/352/270/264/352/270/211/355/221/234/354/213/234/spec.md +0 -14
- package/claude/skills/sd-impl/evals/fixtures/basic-single-r/src/components/Input.tsx +0 -6
- package/claude/skills/sd-impl/evals/fixtures/basic-single-r/src/pages/.gitkeep +0 -0
- package/claude/skills/sd-impl/evals/fixtures/multi-r/.specs/260503143025/REQ-001-/352/261/260/353/236/230/354/262/230/353/252/251/353/241/235/plan.md +0 -40
- package/claude/skills/sd-impl/evals/fixtures/multi-r/.specs/260503143025/REQ-001-/352/261/260/353/236/230/354/262/230/353/252/251/353/241/235/spec.md +0 -13
- package/claude/skills/sd-impl/evals/fixtures/multi-r/src/components/Input.tsx +0 -25
- package/claude/skills/sd-impl/evals/fixtures/multi-r/src/pages/.gitkeep +0 -0
- package/claude/skills/sd-impl/evals/fixtures/with-test-file/.specs/260503143025/REQ-001-/355/225/240/354/235/270/352/263/204/354/202/260/plan.md +0 -26
- package/claude/skills/sd-impl/evals/fixtures/with-test-file/.specs/260503143025/REQ-001-/355/225/240/354/235/270/352/263/204/354/202/260/spec.md +0 -12
- package/claude/skills/sd-impl/evals/fixtures/with-test-file/src/lib/.gitkeep +0 -0
- package/claude/skills/sd-impl/references/impl-md-template.md +0 -87
- package/claude/skills/sd-impl/references/modes-and-failure.md +0 -65
- package/claude/skills/sd-plan/SKILL.md +0 -130
- package/claude/skills/sd-plan/evals/fixtures/already-implemented/.specs/260503143025/REQ-001-/354/202/254/354/232/251/354/236/220/353/252/251/353/241/235/spec.md +0 -14
- package/claude/skills/sd-plan/evals/fixtures/already-implemented/src/api/user.ts +0 -13
- package/claude/skills/sd-plan/evals/fixtures/already-implemented/src/components/Input.tsx +0 -15
- package/claude/skills/sd-plan/evals/fixtures/already-implemented/src/pages/UserList.tsx +0 -29
- package/claude/skills/sd-plan/evals/fixtures/basic-greenfield/.specs/260503143025/REQ-001-/354/236/205/352/263/240/354/247/200/354/213/234/354/204/234/352/270/264/352/270/211/355/221/234/354/213/234/spec.md +0 -17
- package/claude/skills/sd-plan/evals/fixtures/basic-greenfield/src/components/Input.tsx +0 -6
- package/claude/skills/sd-plan/evals/fixtures/basic-greenfield/src/pages/.gitkeep +0 -0
- package/claude/skills/sd-plan/evals/fixtures/demo-built/.specs/260503143025/DEMO-001-/352/261/260/353/236/230/354/262/230/demo.md +0 -26
- package/claude/skills/sd-plan/evals/fixtures/demo-built/.specs/260503143025/REQ-001-/352/261/260/353/236/230/354/262/230/353/252/251/353/241/235/355/231/224/353/251/264/spec.md +0 -15
- package/claude/skills/sd-plan/evals/fixtures/demo-built/src/components/Input.tsx +0 -25
- package/claude/skills/sd-plan/evals/fixtures/demo-built/src/data/mock-customer.ts +0 -16
- package/claude/skills/sd-plan/evals/fixtures/demo-built/src/pages/CustomerList.tsx +0 -25
- package/claude/skills/sd-plan/evals/golden.jsonl +0 -3
- package/claude/skills/sd-plan/references/plan-md-template.md +0 -138
- package/claude/skills/sd-spec/evals/fixtures/bulk-multi-source/.docs/20260122_/352/263/240/352/260/235/354/202/254_/354/236/205/352/263/240/354/247/200/354/213/234/354/204/234/352/260/234/354/204/240/354/232/224/354/262/255.eml +0 -20
- package/claude/skills/sd-spec/evals/fixtures/bulk-multi-source/.docs/20260205_/352/263/240/352/260/235/354/202/254_/354/266/234/352/263/240/355/231/224/353/251/264/352/264/200/353/240/250.eml +0 -17
- package/claude/skills/sd-spec/evals/fixtures/bulk-multi-source/.docs/20260301_/352/263/240/352/260/235/354/202/254_/352/266/214/355/225/234/354/262/264/352/263/204.eml +0 -18
- package/claude/skills/sd-spec/evals/fixtures/conflict-detection/.docs/20260317_/352/263/240/352/260/235/354/202/254_/352/270/264/352/270/211/354/262/230/353/246/254/353/260/251/354/271/250.eml +0 -17
- package/claude/skills/sd-spec/evals/fixtures/conflict-detection/.docs//355/232/214/354/235/230/353/214/200/353/263/270_20260320.txt +0 -13
- package/claude/skills/sd-spec/evals/fixtures/direct-simple/.gitkeep +0 -0
- package/claude/skills/sd-spec/evals/fixtures/spec-md-input/.specs/260101120000/REQ-001-test/spec.md +0 -19
- package/claude/skills/sd-spec/evals/fixtures/spec-md-input/.specs/260101120000/overview.md +0 -18
- package/claude/skills/sd-spec/evals/golden.jsonl +0 -4
- package/claude/skills/sd-spec/references/overview-md-template.md +0 -89
- package/claude/skills/sd-spec/references/raw-input-handling.md +0 -96
- package/claude/skills/sd-verify/SKILL.md +0 -96
- package/claude/skills/sd-verify/evals/fixtures/all-satisfied/.specs/260503143025/REQ-001-/355/225/240/354/235/270/352/263/204/354/202/260/impl.md +0 -20
- package/claude/skills/sd-verify/evals/fixtures/all-satisfied/.specs/260503143025/REQ-001-/355/225/240/354/235/270/352/263/204/354/202/260/plan.md +0 -14
- package/claude/skills/sd-verify/evals/fixtures/all-satisfied/.specs/260503143025/REQ-001-/355/225/240/354/235/270/352/263/204/354/202/260/spec.md +0 -12
- package/claude/skills/sd-verify/evals/fixtures/all-satisfied/src/lib/discount.test.ts +0 -11
- package/claude/skills/sd-verify/evals/fixtures/all-satisfied/src/lib/discount.ts +0 -7
- package/claude/skills/sd-verify/evals/fixtures/partial-mismatch/.specs/260503143025/REQ-001-/354/202/254/354/232/251/354/236/220/353/252/251/353/241/235/impl.md +0 -21
- package/claude/skills/sd-verify/evals/fixtures/partial-mismatch/.specs/260503143025/REQ-001-/354/202/254/354/232/251/354/236/220/353/252/251/353/241/235/plan.md +0 -21
- package/claude/skills/sd-verify/evals/fixtures/partial-mismatch/.specs/260503143025/REQ-001-/354/202/254/354/232/251/354/236/220/353/252/251/353/241/235/spec.md +0 -12
- package/claude/skills/sd-verify/evals/fixtures/partial-mismatch/src/pages/UserList.tsx +0 -19
- package/claude/skills/sd-verify/evals/fixtures/tdd-only/.specs/260503143025/REQ-001-/352/270/210/354/225/241/352/262/200/354/246/235/impl.md +0 -19
- package/claude/skills/sd-verify/evals/fixtures/tdd-only/.specs/260503143025/REQ-001-/352/270/210/354/225/241/352/262/200/354/246/235/plan.md +0 -14
- package/claude/skills/sd-verify/evals/fixtures/tdd-only/.specs/260503143025/REQ-001-/352/270/210/354/225/241/352/262/200/354/246/235/spec.md +0 -12
- package/claude/skills/sd-verify/evals/fixtures/tdd-only/src/lib/validate-amount.test.ts +0 -10
- package/claude/skills/sd-verify/evals/fixtures/tdd-only/src/lib/validate-amount.ts +0 -7
- package/claude/skills/sd-verify/evals/golden.jsonl +0 -3
- package/claude/skills/sd-verify/references/verify-md-template.md +0 -99
- /package/claude/skills/{sd-demo/evals/fixtures/basic-single-req/src/pages → sd-wip/evals/fixtures/empty}/.gitkeep +0 -0
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
# @simplysm/core-browser
|
|
2
|
+
|
|
3
|
+
브라우저 전용 보강 — `Element`/`HTMLElement` 프로토타입 확장(import 사이드 이펙트) + DOM/파일/네트워크/IndexedDB 헬퍼.
|
|
4
|
+
|
|
5
|
+
> 이 패키지를 import 만 해도 `Element`/`HTMLElement` 프로토타입이 확장된다. SSR 환경에서는 import 자체를 피한다.
|
|
6
|
+
|
|
7
|
+
## 사용 트리거 인덱스
|
|
8
|
+
|
|
9
|
+
- **DOM 탐색/가시성** (`Element` 확장: `findAll`/`findFirst`/`prependChild`/`getParents`/`isOffsetElement`/`isVisible`) — DOM 트리 탐색·삽입·가시성 판정 필요 시.
|
|
10
|
+
- **포커스/탭 이동** (`Element` 확장: `findTabbableParent`/`findFirstTabbableChild`) — 키보드 포커스 흐름 제어 시.
|
|
11
|
+
- **레이아웃/스크롤** (`HTMLElement` 확장: `repaint`/`getRelativeOffset`/`scrollIntoViewIfNeeded`) — 드롭다운/팝업 위치 계산, 고정 헤더 가림 스크롤 보정 시.
|
|
12
|
+
- **클립보드/측정 헬퍼** (`copyElement`/`pasteToElement`/`getBounds`, `ElementBounds`) — copy/paste 이벤트 처리, 다수 요소 경계 일괄 측정 시.
|
|
13
|
+
- **파일 다이얼로그/다운로드** (`openFileDialog`/`downloadBlob`) — 파일 선택 UI, Blob 다운로드 트리거 시.
|
|
14
|
+
- **진행률 fetch** (`fetchUrlBytes`, `DownloadProgress`) — 큰 바이너리 다운로드 + 진행률 콜백 필요 시.
|
|
15
|
+
- **IndexedDB 저장소** (`IndexedDbStore`, `StoreConfig`) — 브라우저 영속 키/값 저장소 (트랜잭션 보장).
|
|
16
|
+
- **IndexedDB 가상 파일시스템** (`IndexedDbVirtualFs`, `VirtualFsEntry`) — `IndexedDbStore` 위에 경로(`/a/b/c`) 기반 파일/디렉토리 모델링.
|
|
17
|
+
|
|
18
|
+
## DOM 탐색/가시성 — `Element` 확장
|
|
19
|
+
|
|
20
|
+
```ts
|
|
21
|
+
el.findAll<T extends Element = Element>(selector: string): T[] // 빈 선택자 → []
|
|
22
|
+
el.findFirst<T extends Element = Element>(selector: string): T | undefined // 빈 선택자 → undefined
|
|
23
|
+
el.prependChild<T extends Element>(child: T): T // 첫 자식으로 삽입
|
|
24
|
+
el.getParents(): Element[] // 가까운 순서
|
|
25
|
+
el.isOffsetElement(): boolean // position: relative/absolute/fixed/sticky
|
|
26
|
+
el.isVisible(): boolean // clientRects 존재 + visibility != hidden + opacity != "0"
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
## 포커스/탭 이동 — `Element` 확장
|
|
30
|
+
|
|
31
|
+
```ts
|
|
32
|
+
el.findTabbableParent(): HTMLElement | undefined // tabbable 라이브러리 사용
|
|
33
|
+
el.findFirstTabbableChild(): HTMLElement | undefined // TreeWalker로 첫 매치
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
## 레이아웃/스크롤 — `HTMLElement` 확장
|
|
37
|
+
|
|
38
|
+
```ts
|
|
39
|
+
el.repaint(): void // offsetHeight 접근으로 강제 reflow
|
|
40
|
+
el.getRelativeOffset(parent: HTMLElement | string): { top; left } // CSS top/left 즉시 사용 가능. transform/border/스크롤 보정. 못 찾으면 ArgumentError
|
|
41
|
+
el.scrollIntoViewIfNeeded(target: { top; left }, offset?): void // 상단/좌측 가림만 보정. 하단/우측은 브라우저 기본
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
`getRelativeOffset` 은 드롭다운/팝업의 absolute 위치 지정 표준 경로. `parent` 는 가장 가까운 offset parent 또는 selector.
|
|
45
|
+
|
|
46
|
+
## 클립보드/측정 헬퍼
|
|
47
|
+
|
|
48
|
+
```ts
|
|
49
|
+
function copyElement(event: ClipboardEvent): void // 대상 내 첫 input/textarea.value → clipboard
|
|
50
|
+
function pasteToElement(event: ClipboardEvent): void // clipboard → 첫 input/textarea.value 교체 + input 이벤트 dispatch
|
|
51
|
+
function getBounds(els: Element[], timeout = 5000): Promise<ElementBounds[]> // IntersectionObserver 기반. 입력 순서 유지. timeout 초과 시 TimeoutError
|
|
52
|
+
|
|
53
|
+
interface ElementBounds { target: Element; top: number; left: number; width: number; height: number; }
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
`copyElement`/`pasteToElement` 는 `<element @copy=... @paste=...>` 이벤트 핸들러로 직결. 커서/선택 영역은 무시하고 전체 값 교체.
|
|
57
|
+
|
|
58
|
+
## 파일 다이얼로그/다운로드
|
|
59
|
+
|
|
60
|
+
```ts
|
|
61
|
+
function openFileDialog(options?: { accept?: string; multiple?: boolean }): Promise<File[] | undefined>
|
|
62
|
+
// 취소 시 undefined, 빈 선택 시 undefined.
|
|
63
|
+
function downloadBlob(blob: Blob, fileName: string): void
|
|
64
|
+
// 파일명: sanitize-filename + 대괄호 제거. 빈 결과는 "download". ObjectURL 1초 후 해제.
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
## 진행률 fetch
|
|
68
|
+
|
|
69
|
+
```ts
|
|
70
|
+
interface DownloadProgress { receivedLength: number; contentLength: number; }
|
|
71
|
+
function fetchUrlBytes(url: string, options?: { onProgress?: (p: DownloadProgress) => void }): Promise<Uint8Array>
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
`Content-Length` 가 있으면 사전 할당(메모리 효율) + 초과/부족 검출, 없으면 청크 수집 후 `bytes.concat`. HTTP 오류·본문 없음·길이 불일치는 모두 throw.
|
|
75
|
+
|
|
76
|
+
## IndexedDB 저장소 — `IndexedDbStore`
|
|
77
|
+
|
|
78
|
+
```ts
|
|
79
|
+
interface StoreConfig { name: string; keyPath: string; }
|
|
80
|
+
|
|
81
|
+
class IndexedDbStore {
|
|
82
|
+
constructor(dbName: string, dbVersion: number, storeConfigs: StoreConfig[]);
|
|
83
|
+
open(): Promise<IDBDatabase>; // versionchange/close 시 자동 무효화
|
|
84
|
+
withStore<R>(name, mode: IDBTransactionMode, fn: (s: IDBObjectStore) => Promise<R>): Promise<R>; // fn throw 시 tx.abort
|
|
85
|
+
get<T>(name, key: IDBValidKey): Promise<T | undefined>;
|
|
86
|
+
put(name, value): Promise<void>;
|
|
87
|
+
delete(name, key: IDBValidKey): Promise<void>;
|
|
88
|
+
getAll<T>(name): Promise<T[]>;
|
|
89
|
+
close(): void;
|
|
90
|
+
}
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
`open()` 은 중복 호출 안전(병행 호출 단일화). `withStore` 의 `fn` 내부 에러는 트랜잭션 abort 후 원본 에러로 reject.
|
|
94
|
+
|
|
95
|
+
## IndexedDB 가상 파일시스템 — `IndexedDbVirtualFs`
|
|
96
|
+
|
|
97
|
+
`IndexedDbStore` 위에 경로 키(`/a/b/c`) 기반 파일/디렉토리 모델. 데이터는 base64 문자열로 저장.
|
|
98
|
+
|
|
99
|
+
```ts
|
|
100
|
+
interface VirtualFsEntry { kind: "file" | "dir"; dataBase64?: string; }
|
|
101
|
+
|
|
102
|
+
class IndexedDbVirtualFs {
|
|
103
|
+
constructor(db: IndexedDbStore, storeName: string, keyField: string);
|
|
104
|
+
getEntry(fullKey: string): Promise<VirtualFsEntry | undefined>;
|
|
105
|
+
putEntry(fullKey: string, kind: "file" | "dir", dataBase64?: string): Promise<void>;
|
|
106
|
+
deleteByPrefix(keyPrefix: string): Promise<boolean>; // 자기 자신 + "/" 하위 재귀 삭제
|
|
107
|
+
listChildren(prefix: string): Promise<{ name: string; isDirectory: boolean }[]>; // 직속 자식만, 중간 경로도 dir 로 노출
|
|
108
|
+
ensureDir(fullKeyBuilder: (path: string) => string, dirPath: string): Promise<void>; // 중간 디렉토리 모두 생성
|
|
109
|
+
}
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
`fullKey`/`keyField`/`fullKeyBuilder` 분리로 멀티 테넌트(예: 사용자별 prefix) 키 스킴을 호출 측에서 결정.
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
# @simplysm/core-common
|
|
2
|
+
|
|
3
|
+
공통 유틸리티(타입·에러·큐·이벤트·변환·확장 메서드·환경변수). simplysm 모든 패키지의 공용 기반.
|
|
4
|
+
|
|
5
|
+
## 사용 트리거 인덱스
|
|
6
|
+
|
|
7
|
+
- **에러 클래스** — throw 시 트리 메시지/원인 체인 필요할 때. `SdError`, `ArgumentError`, `NotImplementedError`, `TimeoutError`.
|
|
8
|
+
- **날짜/시간/UUID/캐시 타입** — `DateTime`, `DateOnly`, `Time`, `Uuid`, `LazyGcMap` 사용 시. (자세히: [types.md](./types.md))
|
|
9
|
+
- **큐·이벤트 features** — 디바운스·직렬 큐, 타입 안전 EventEmitter. (자세히: [features.md](./features.md))
|
|
10
|
+
- **유틸리티 네임스페이스** — `obj`, `str`, `num`, `bytes`, `path`, `json`, `xml`, `wait`, `transfer`, `err`, `dt`, `primitive`. (자세히: [utils.md](./utils.md))
|
|
11
|
+
- **Array/Set/Map 전역 확장 메서드** — `.single()`, `.toMap()`, `.toTree()`, `.distinct()`, `Set.adds()`, `Map.getOrCreate()` 등. (자세히: [extensions.md](./extensions.md))
|
|
12
|
+
- **환경변수** — `env(key)`, `env(key, value)`, `parseBoolEnv(v)`. `process.env` 우선, fallback `import.meta.env`.
|
|
13
|
+
- **템플릿 문자열 태그** — IDE 하이라이팅 + indent trim. `js`, `ts`, `html`, `tsql`, `mysql`, `pgsql`. 동작은 모두 동일(문자열 결합 + 들여쓰기 정규화).
|
|
14
|
+
- **ZIP 처리** — `ZipArchive(data?)`: `get/exists/write/extractAll/compress/close`. 사용 후 반드시 `await archive.close()`.
|
|
15
|
+
- **공통 타입** — `Bytes` (= `Uint8Array`), `PrimitiveTypeMap/Str/Type` (string/number/boolean/DateTime/DateOnly/Time/Uuid/Bytes), `DeepPartial<T>`, `Type<T>` (생성자 타입).
|
|
16
|
+
|
|
17
|
+
## 에러 클래스
|
|
18
|
+
|
|
19
|
+
```typescript
|
|
20
|
+
new SdError(cause: Error, ...messages: string[])
|
|
21
|
+
new SdError(...messages: string[])
|
|
22
|
+
// 메시지는 역순 결합: "상위 => 하위 => 원인". cause stack을 현재 stack에 append.
|
|
23
|
+
|
|
24
|
+
new ArgumentError(argObj)
|
|
25
|
+
new ArgumentError(message, argObj)
|
|
26
|
+
// 인자 객체를 YAML 형식으로 메시지에 포함.
|
|
27
|
+
|
|
28
|
+
new NotImplementedError(message?) // "미구현: <message>"
|
|
29
|
+
new TimeoutError(count?, message?) // "대기 시간 초과(N회 시도): <message>". wait.until 에서 자동 throw.
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
모두 `SdError` 상속. `name` 자동 설정.
|
|
33
|
+
|
|
34
|
+
## 환경변수
|
|
35
|
+
|
|
36
|
+
```typescript
|
|
37
|
+
env("PORT") // string | undefined (process.env → import.meta.env)
|
|
38
|
+
env("PORT", "3000") // void (process.env 에 기록, process 없으면 무시)
|
|
39
|
+
parseBoolEnv(v) // "true"|"1"|"yes"|"on" → true (대소문자 무시)
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
## 템플릿 문자열 태그
|
|
43
|
+
|
|
44
|
+
```typescript
|
|
45
|
+
import { js, ts, html, tsql, mysql, pgsql } from "@simplysm/core-common";
|
|
46
|
+
|
|
47
|
+
const code = ts`
|
|
48
|
+
interface User { name: string; }
|
|
49
|
+
`;
|
|
50
|
+
// → "interface User { name: string; }" (앞뒤 빈 줄·공통 들여쓰기 제거)
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
모두 동일 함수, IDE 하이라이팅 차별화 목적.
|
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
# @simplysm/core-common — extensions
|
|
2
|
+
|
|
3
|
+
`index.ts` 가 import 되면 자동으로 `Array.prototype`, `Set.prototype`, `Map.prototype` 에 메서드를 정의 (`enumerable: false`).
|
|
4
|
+
|
|
5
|
+
## Array (Readonly — 새 배열/값 반환)
|
|
6
|
+
|
|
7
|
+
### 조회
|
|
8
|
+
|
|
9
|
+
```typescript
|
|
10
|
+
arr.single(pred?) // 0 or 1개. 2개 이상이면 ArgumentError. 없으면 undefined.
|
|
11
|
+
arr.first(pred?) // pred 면 find, 없으면 [0]
|
|
12
|
+
arr.last(pred?) // pred 면 역방향 find, 없으면 [length-1]
|
|
13
|
+
arr.filterExists() // null/undefined 제거 → NonNullable<T>[]
|
|
14
|
+
arr.ofType("string"|"number"|"boolean"|"DateTime"|"DateOnly"|"Time"|"Uuid"|"Bytes")
|
|
15
|
+
arr.ofType(SomeClass) // instanceof 또는 constructor 일치
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
### 비동기
|
|
19
|
+
|
|
20
|
+
```typescript
|
|
21
|
+
await arr.filterAsync(asyncPred) // 순차
|
|
22
|
+
await arr.mapAsync(asyncSelector) // 순차
|
|
23
|
+
await arr.mapManyAsync(asyncSelector) // 순차 + 평탄화
|
|
24
|
+
await arr.parallelAsync(fn) // Promise.all (하나 reject 시 전체 reject)
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
### 매핑·평탄화
|
|
28
|
+
|
|
29
|
+
```typescript
|
|
30
|
+
arr.mapMany() // 중첩 배열 1단계 flatten + filterExists
|
|
31
|
+
arr.mapMany(selector) // 매핑 후 flatten
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
### 변환
|
|
35
|
+
|
|
36
|
+
```typescript
|
|
37
|
+
arr.groupBy(keyFn) // [{ key, values }, ...] (객체 key 시 O(n²), 원시 key 는 O(n))
|
|
38
|
+
arr.groupBy(keyFn, valueFn)
|
|
39
|
+
arr.toMap(keyFn) / toMap(keyFn, valFn) // 중복 key 시 ArgumentError
|
|
40
|
+
await arr.toMapAsync(...)
|
|
41
|
+
arr.toArrayMap(keyFn[, valFn]) // Map<K, V[]> (원시 key 권장 — O(n))
|
|
42
|
+
arr.toSetMap(keyFn[, valFn]) // Map<K, Set<V>>
|
|
43
|
+
arr.toMapValues(keyFn, (items) => aggregated)
|
|
44
|
+
arr.toObject(strKeyFn[, valFn]) // 중복 key 시 ArgumentError
|
|
45
|
+
arr.toTree("id", "parentId") // 평면 → 트리 ({...item, children: []}), O(n).
|
|
46
|
+
// parentKey 가 null/undefined 면 루트.
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
### 중복·정렬
|
|
50
|
+
|
|
51
|
+
```typescript
|
|
52
|
+
arr.distinct() // 깊은 equal 비교 (객체 array 는 O(n²))
|
|
53
|
+
arr.distinct(true) // matchAddress: 참조 비교 (Set 기반, O(n))
|
|
54
|
+
arr.distinct({ matchAddress?, keyFn? }) // keyFn 권장 — O(n)
|
|
55
|
+
arr.orderBy(selector?) // 오름차순. string/number/DateTime/DateOnly/Time/undefined 지원
|
|
56
|
+
arr.orderByDesc(selector?)
|
|
57
|
+
arr.shuffle() // Fisher-Yates
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
### 비교·병합
|
|
61
|
+
|
|
62
|
+
```typescript
|
|
63
|
+
arr.diffs(target) // INSERT/DELETE/UPDATE 결과
|
|
64
|
+
arr.diffs(target, { keys: ["id"], excludes? }) // key 기반 매칭 (Map 인덱싱 O(n+m))
|
|
65
|
+
arr.diffs(target, { excludes: [...] })
|
|
66
|
+
// 결과 타입:
|
|
67
|
+
// { source: undefined, target: T } // INSERT
|
|
68
|
+
// { source: T, target: undefined } // DELETE
|
|
69
|
+
// { source: T, target: T } // UPDATE
|
|
70
|
+
|
|
71
|
+
arr.oneWayDiffs(orgItems | Map, keyPropOrFn, {
|
|
72
|
+
includeSame?, excludes?, includes?,
|
|
73
|
+
})
|
|
74
|
+
// 결과: { type: "create"|"update"|"same", item, orgItem }
|
|
75
|
+
|
|
76
|
+
arr.merge(target[, { keys?, excludes? }]) // diffs 후 source 기반에 target 병합·신규 push
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
### 집계
|
|
80
|
+
|
|
81
|
+
```typescript
|
|
82
|
+
arr.sum(selector?) // 숫자 아니면 ArgumentError. 빈 배열 → 0.
|
|
83
|
+
arr.min(selector?) / max(selector?) // string|number. 빈 배열 → undefined
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
### TreeArray 타입
|
|
87
|
+
|
|
88
|
+
```typescript
|
|
89
|
+
type TreeArray<T> = T & { children: TreeArray<T>[] };
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
## Array (Mutable — 원본 변경, `@mutates`)
|
|
93
|
+
|
|
94
|
+
```typescript
|
|
95
|
+
arr.distinctThis(options?) // 원본에서 중복 제거 (역순 splice, O(n))
|
|
96
|
+
arr.orderByThis(selector?) / orderByDescThis(selector?)
|
|
97
|
+
arr.insert(index, ...items)
|
|
98
|
+
arr.remove(itemOrSelector) // 일치 항목 모두 제거. 역순 순회.
|
|
99
|
+
arr.toggle(item) // 있으면 remove, 없으면 push
|
|
100
|
+
arr.clear()
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
모두 `this` 반환 (체이닝 가능, `clear/distinctThis/orderBy*This` 는 변경된 자기 자신).
|
|
104
|
+
|
|
105
|
+
## Set
|
|
106
|
+
|
|
107
|
+
```typescript
|
|
108
|
+
set.adds(...values) // 다중 add, this 반환
|
|
109
|
+
set.toggle(value) // 자동 토글
|
|
110
|
+
set.toggle(value, "add" | "del") // 강제 추가/제거
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
## Map
|
|
114
|
+
|
|
115
|
+
```typescript
|
|
116
|
+
map.getOrCreate(key, defaultValue) // 없으면 set 후 반환
|
|
117
|
+
map.getOrCreate(key, () => expensiveCompute()) // 팩토리 (값이 함수이면 항상 호출됨 — 함수 값을 저장하려면 `() => fn` 으로 한 번 더 감쌀 것)
|
|
118
|
+
map.update(key, (v|undefined) => newV) // 없는 key 도 호출됨 (카운터·배열 push 패턴)
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
## ComparableType
|
|
122
|
+
|
|
123
|
+
`orderBy*` 의 selector 반환 타입: `string | number | boolean | DateTime | DateOnly | Time | undefined`.
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
# @simplysm/core-common — features
|
|
2
|
+
|
|
3
|
+
비동기 큐와 타입 안전 이벤트 이미터.
|
|
4
|
+
|
|
5
|
+
## EventEmitter\<TEvents\>
|
|
6
|
+
|
|
7
|
+
브라우저·Node 공용 (내부 `EventTarget`). 타입 안전.
|
|
8
|
+
|
|
9
|
+
```typescript
|
|
10
|
+
interface MyEvents { data: string; error: Error; done: void; }
|
|
11
|
+
class MyEmitter extends EventEmitter<MyEvents> {}
|
|
12
|
+
|
|
13
|
+
const e = new MyEmitter();
|
|
14
|
+
e.on("data", (d) => ...); // d: string
|
|
15
|
+
e.emit("data", "hello");
|
|
16
|
+
e.emit("done"); // void 이벤트는 인자 없이
|
|
17
|
+
e.off("data", handler);
|
|
18
|
+
e.listenerCount("data"); // 등록된 수
|
|
19
|
+
e.dispose(); // 모든 리스너 제거
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
같은 이벤트에 같은 리스너 중복 등록은 무시.
|
|
23
|
+
|
|
24
|
+
## DebounceQueue extends EventEmitter\<{ error: SdError }\>
|
|
25
|
+
|
|
26
|
+
연속 호출 중 마지막 작업만 실행.
|
|
27
|
+
|
|
28
|
+
```typescript
|
|
29
|
+
const q = new DebounceQueue(300); // 300ms 지연 (생략 시 다음 이벤트 루프)
|
|
30
|
+
q.run(fn); // 이전 대기 함수 교체
|
|
31
|
+
q.on("error", (e) => ...); // 작업 throw 시. 리스너 없으면 logger.error
|
|
32
|
+
q.dispose(); // 타이머·대기 함수 정리
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
실행 도중 들어온 새 요청은 지연 없이 실행 완료 직후 즉시 처리 (놓침 방지).
|
|
36
|
+
|
|
37
|
+
## SerialQueue extends EventEmitter\<{ error: SdError }\>
|
|
38
|
+
|
|
39
|
+
순차 실행, 작업 사이 간격 옵션.
|
|
40
|
+
|
|
41
|
+
```typescript
|
|
42
|
+
const q = new SerialQueue(0); // gap ms (기본 0)
|
|
43
|
+
q.run(asyncFn); // 큐에 추가, 자동 실행
|
|
44
|
+
q.on("error", ...); // 에러는 다음 작업에 영향 X (계속 실행)
|
|
45
|
+
q.dispose(); // 대기 큐 비움 (현재 작업은 완료됨)
|
|
46
|
+
```
|
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
# @simplysm/core-common — types
|
|
2
|
+
|
|
3
|
+
날짜·시간·UUID·만료 캐시 타입.
|
|
4
|
+
|
|
5
|
+
## DateTime (불변)
|
|
6
|
+
|
|
7
|
+
밀리초 정밀도, 로컬 타임존. 모든 변환/산술 메서드는 새 인스턴스 반환.
|
|
8
|
+
|
|
9
|
+
```typescript
|
|
10
|
+
new DateTime() // 현재
|
|
11
|
+
new DateTime(year, month, day, h?, m?, s?, ms?) // month 는 1-12
|
|
12
|
+
new DateTime(tick) // ms epoch
|
|
13
|
+
new DateTime(date) // Date 복사
|
|
14
|
+
DateTime.parse(str) // "yyyy-MM-dd HH:mm:ss" / "yyyyMMddHHmmss" /
|
|
15
|
+
// "yyyy-MM-dd AM|PM HH:mm:ss" / "오전|오후" / ISO 8601
|
|
16
|
+
// 실패 시 ArgumentError
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
Getters: `year/month/day/hour/minute/second/millisecond/tick/dayOfWeek/timezoneOffsetMinutes/isValid` (month 는 1-12, dayOfWeek 는 0-6 일~토).
|
|
20
|
+
|
|
21
|
+
변환: `setYear/setMonth/setDay/setHour/setMinute/setSecond/setMillisecond` — 새 인스턴스. `setMonth` 는 대상 월 일수 초과 시 마지막 일로 클램프. `setDay` 는 JS Date 동작에 따라 월 경계 자동 조정.
|
|
22
|
+
|
|
23
|
+
산술: `addYears/addMonths/addDays/addHours/addMinutes/addSeconds/addMilliseconds`.
|
|
24
|
+
|
|
25
|
+
포맷: `toFormatString(formatStr)` ([date-format 토큰](#date-format-토큰)). `toString()` = `"yyyy-MM-ddTHH:mm:ss.fffzzz"`.
|
|
26
|
+
|
|
27
|
+
## DateOnly (불변)
|
|
28
|
+
|
|
29
|
+
날짜만(yyyy-MM-dd), 로컬 타임존.
|
|
30
|
+
|
|
31
|
+
```typescript
|
|
32
|
+
new DateOnly() // 오늘
|
|
33
|
+
new DateOnly(year, month, day)
|
|
34
|
+
new DateOnly(tick) / new DateOnly(date)
|
|
35
|
+
DateOnly.parse(str) // "yyyy-MM-dd" / "yyyyMMdd" (타임존 무관) /
|
|
36
|
+
// ISO 8601 (UTC → 로컬 변환). 실패 시 ArgumentError
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
Getters: `year/month/day/tick/dayOfWeek/isValid`.
|
|
40
|
+
변환·산술: `setYear/setMonth/setDay`, `addYears/addMonths/addDays`.
|
|
41
|
+
포맷: `toFormatString`, `toString()` = `"yyyy-MM-dd"`.
|
|
42
|
+
|
|
43
|
+
주차 API (ISO 8601 기본: 월요일 시작, 첫 주 최소 4일):
|
|
44
|
+
|
|
45
|
+
```typescript
|
|
46
|
+
d.getWeekSeqOfYear(weekStartDay=1, minDaysInFirstWeek=4) // { year, weekSeq }
|
|
47
|
+
d.getWeekSeqOfMonth(...) // { year, monthSeq, weekSeq }
|
|
48
|
+
d.getWeekSeqStartDate(...) // DateOnly
|
|
49
|
+
d.getBaseYearMonthSeqForWeekSeq(...) // { year, monthSeq }
|
|
50
|
+
DateOnly.getDateByYearWeekSeq({ year, month?, weekSeq }, ...) // 해당 주 시작일
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
## Time (불변)
|
|
54
|
+
|
|
55
|
+
시간만(HH:mm:ss.fff). 24h 순환 — 음수/24h+ 자동 정규화.
|
|
56
|
+
|
|
57
|
+
```typescript
|
|
58
|
+
new Time() // 현재 시각의 시간 부분
|
|
59
|
+
new Time(hour, minute, second?, ms?)
|
|
60
|
+
new Time(tick) / new Time(date)
|
|
61
|
+
Time.parse(str) // "HH:mm:ss[.fff]" / "AM|PM HH:mm:ss[.fff]" / ISO 8601 시간 부분
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
Getters/Setters/Add 메서드는 DateTime 시간부와 유사. `addHours/Minutes/Seconds/Milliseconds` 는 24h 순환.
|
|
65
|
+
|
|
66
|
+
## Uuid
|
|
67
|
+
|
|
68
|
+
UUID v4, `crypto.getRandomValues` 기반.
|
|
69
|
+
|
|
70
|
+
```typescript
|
|
71
|
+
Uuid.generate() // 새 v4
|
|
72
|
+
new Uuid("xxxxxxxx-...") // 형식 검증, 실패 시 ArgumentError
|
|
73
|
+
Uuid.fromBytes(bytes16) // 16바이트 → Uuid (길이 ≠ 16 시 ArgumentError)
|
|
74
|
+
u.toString() // "xxxxxxxx-xxxx-..."
|
|
75
|
+
u.toBytes() // 16바이트 Uint8Array
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
## LazyGcMap
|
|
79
|
+
|
|
80
|
+
LRU 자동 만료 Map. **사용 후 반드시 `dispose()` 호출** — 안 하면 GC 타이머가 살아 메모리 누수.
|
|
81
|
+
|
|
82
|
+
```typescript
|
|
83
|
+
const m = new LazyGcMap<K, V>({
|
|
84
|
+
expireTime: 60_000, // 마지막 접근 이후 ms
|
|
85
|
+
gcInterval?: 6_000, // 기본: expireTime/10, 최소 1000ms
|
|
86
|
+
onExpire?: (k, v) => ... , // 비동기 가능, 에러는 로그
|
|
87
|
+
});
|
|
88
|
+
|
|
89
|
+
m.size; m.has(k); m.get(k); m.set(k, v); m.delete(k); m.clear(); m.dispose();
|
|
90
|
+
m.getOrCreate(k, factory); // dispose 후 호출 시 throw
|
|
91
|
+
m.keys() / m.values() / m.entries(); // Iterator
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
`get`/`getOrCreate` 만 접근시간 갱신(LRU). `has` 는 갱신 X. GC 실행 중 같은 key 재등록 시 새 항목 보존.
|
|
95
|
+
|
|
96
|
+
## date-format 토큰
|
|
97
|
+
|
|
98
|
+
`DateTime/DateOnly/Time#toFormatString(formatStr)` 에서 사용. C# 호환.
|
|
99
|
+
|
|
100
|
+
| 토큰 | 의미 | 예 |
|
|
101
|
+
|------|------|----|
|
|
102
|
+
| `yyyy`/`yy` | 연도 4/2자리 | 2024 / 24 |
|
|
103
|
+
| `MM`/`M` | 월 패딩/미패딩 | 01 / 1 |
|
|
104
|
+
| `ddd` | 한글 요일 | 일~토 |
|
|
105
|
+
| `dd`/`d` | 일 패딩/미패딩 | 01 / 1 |
|
|
106
|
+
| `tt` | AM/PM | AM |
|
|
107
|
+
| `hh`/`h` | 12시간 패딩/미패딩 | 01 / 1 |
|
|
108
|
+
| `HH`/`H` | 24시간 패딩/미패딩 | 14 / 14 |
|
|
109
|
+
| `mm`/`m` | 분 | 30 / 30 |
|
|
110
|
+
| `ss`/`s` | 초 | 45 / 45 |
|
|
111
|
+
| `fff`/`ff`/`f` | 밀리초 3/2/1자리 | 123 / 12 / 1 |
|
|
112
|
+
| `zzz`/`zz`/`z` | 타임존 ±HH:mm / ±HH / ±H | +09:00 |
|
|
113
|
+
|
|
114
|
+
긴 토큰이 먼저 매칭 → 부분 매칭 방지.
|
|
@@ -0,0 +1,158 @@
|
|
|
1
|
+
# @simplysm/core-common — utils
|
|
2
|
+
|
|
3
|
+
네임스페이스 import: `import { obj, str, num, bytes, path, json, xml, wait, transfer, err, dt, primitive } from "@simplysm/core-common";`
|
|
4
|
+
|
|
5
|
+
## obj — 객체 조작
|
|
6
|
+
|
|
7
|
+
### 복사·비교·병합
|
|
8
|
+
|
|
9
|
+
```typescript
|
|
10
|
+
obj.clone(src) // 깊은 복사. 순환 참조·DateTime/DateOnly/Time/Uuid/
|
|
11
|
+
// Uint8Array/Date/RegExp/Error(cause)/Map/Set 지원.
|
|
12
|
+
// 함수/Symbol 은 참조 유지, WeakMap/WeakSet 미지원.
|
|
13
|
+
obj.equal(a, b, opt?) // 깊은 동등. opt: { topLevelIncludes?, topLevelExcludes?,
|
|
14
|
+
// ignoreArrayIndex?, shallow? }
|
|
15
|
+
// include/exclude 는 최상위 객체 키에만 적용. shallow=true 면 1단계 참조 비교.
|
|
16
|
+
obj.merge(source, target, opt?) // 깊은 병합 (불변, 새 객체). opt:
|
|
17
|
+
// { arrayProcess?: "replace"|"concat", useDelTargetNull? }
|
|
18
|
+
obj.merge3(source, origin, target, optionsObj?) // 3-way merge. { conflict, result }
|
|
19
|
+
// optionsObj 는 key별 { keys?, excludes?, ignoreArrayIndex? }
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
### 키 조작
|
|
23
|
+
|
|
24
|
+
```typescript
|
|
25
|
+
obj.omit(o, ["k1","k2"])
|
|
26
|
+
obj.omitByFilter(o, (k) => k.startsWith("_"))
|
|
27
|
+
obj.pick(o, ["k1","k2"])
|
|
28
|
+
obj.keys(o) / obj.entries(o) / obj.fromEntries(pairs) // 타입 안전 Object.* 래퍼
|
|
29
|
+
obj.map(o, (k, v) => [newK | null, newV]) // entry 변환 (newK=null 이면 원래 키 유지)
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
### 체인 경로 (`"a.b[0].c"` 형식)
|
|
33
|
+
|
|
34
|
+
```typescript
|
|
35
|
+
obj.getChainValue(o, "a.b[0].c")
|
|
36
|
+
obj.getChainValue(o, "a.b[0].c", true) // optional: 중간 null 만나면 undefined
|
|
37
|
+
obj.setChainValue(o, "a.b.c", v) // 중간 객체 자동 생성
|
|
38
|
+
obj.deleteChainValue(o, "a.b.c")
|
|
39
|
+
obj.getChainValueByDepth(o, key, depth, optional?) // 같은 key 로 N단계 하강
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
### 변환 (원본 변형 — `@mutates`)
|
|
43
|
+
|
|
44
|
+
```typescript
|
|
45
|
+
obj.clearUndefined(o) // null/undefined 값 키 제거
|
|
46
|
+
obj.clear(o) // 모든 키 제거
|
|
47
|
+
obj.nullToUndefined(o) // 재귀, null → undefined
|
|
48
|
+
obj.unflatten({ "a.b.c": 1 }) // → { a: { b: { c: 1 } } }
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
### 타입 유틸
|
|
52
|
+
|
|
53
|
+
```typescript
|
|
54
|
+
obj.UndefToOptional<T> // { a: string|undefined } → { a?: string|undefined }
|
|
55
|
+
obj.OptionalToUndef<T> // { a?: string } → { a: string|undefined }
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
## str — 문자열
|
|
59
|
+
|
|
60
|
+
```typescript
|
|
61
|
+
str.getKoreanSuffix(text, "을"|"은"|"이"|"와"|"랑"|"로"|"라")
|
|
62
|
+
// 받침 유무로 조사 결정. "로" 는 ㄹ 받침이면 "로".
|
|
63
|
+
str.replaceFullWidth(s) // 전각 영숫자/공백/괄호 → 반각
|
|
64
|
+
str.toPascalCase(s) / toCamelCase(s) / toKebabCase(s) / toSnakeCase(s)
|
|
65
|
+
// case 함수는 기존 -/_ 구분자 보존, 연속 대문자 개별 분리 ("XMLParser" → "x-m-l-parser")
|
|
66
|
+
str.isNullOrEmpty(s) // null|undefined|"" 타입 가드
|
|
67
|
+
str.insert(s, idx, insertStr)
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
## num — 숫자
|
|
71
|
+
|
|
72
|
+
```typescript
|
|
73
|
+
num.parseInt(text) // 비숫자 제거 후 정수 파싱. 선행 - 만 음수 부호, 중간 - 제거. 소수점은 trunc.
|
|
74
|
+
num.parseFloat(text)
|
|
75
|
+
num.parseRoundedInt(text) // float 후 반올림
|
|
76
|
+
num.isNullOrEmpty(v) // null|undefined|0 타입 가드
|
|
77
|
+
num.format(v, { max?, min? }) // 천 단위 + 소수점 자릿수. toLocaleString 기반
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
## bytes — Uint8Array
|
|
81
|
+
|
|
82
|
+
```typescript
|
|
83
|
+
bytes.concat([a, b, ...])
|
|
84
|
+
bytes.toHex(u8) / bytes.fromHex(hex) // 소문자 hex. 홀수 길이/잘못된 문자 시 ArgumentError
|
|
85
|
+
bytes.toBase64(u8) / bytes.fromBase64(b64) // 표준 base64 (+/, = 패딩). 공백 자동 제거
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
## path — POSIX 경로 (브라우저용)
|
|
89
|
+
|
|
90
|
+
```typescript
|
|
91
|
+
path.join(...segs) // 슬래시만 지원, 백슬래시 X
|
|
92
|
+
path.basename(p, ext?)
|
|
93
|
+
path.extname(p) // 숨김 파일(".gitignore")은 빈 문자열
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
## json — 커스텀 타입 지원 JSON
|
|
97
|
+
|
|
98
|
+
```typescript
|
|
99
|
+
json.stringify(obj, { space?, replacer?, redactBytes? })
|
|
100
|
+
// Date/DateTime/DateOnly/Time/Uuid/Set/Map/Error/Uint8Array 를 { __type__, data } 로.
|
|
101
|
+
// redactBytes=true 면 Uint8Array 내용을 "__hidden__"로 (parse 복원 불가).
|
|
102
|
+
// 순환 참조 시 TypeError. 전역 prototype 미수정 (Worker 안전).
|
|
103
|
+
json.parse<T>(str) // __type__ 마커 복원. 모든 null → undefined (simplysm null-free 규칙).
|
|
104
|
+
// 에러 시 SdError. DEV 환경에서만 메시지에 전체 JSON 포함.
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
## xml — fast-xml-parser 래퍼
|
|
108
|
+
|
|
109
|
+
```typescript
|
|
110
|
+
xml.parse(str, { stripTagPrefix? })
|
|
111
|
+
// 결과: 속성은 `$` 객체, 텍스트는 `_` 키, 자식 요소는 배열 (루트 제외).
|
|
112
|
+
// stripTagPrefix=true 면 "ns:tag" → "tag" (속성은 유지).
|
|
113
|
+
xml.stringify(obj, options?) // fast-xml-parser XmlBuilderOptions
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
## wait — 대기
|
|
117
|
+
|
|
118
|
+
```typescript
|
|
119
|
+
await wait.time(ms)
|
|
120
|
+
await wait.until(() => cond, intervalMs=100, maxCount?) // maxCount 초과 시 TimeoutError
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
## transfer — Worker 전송
|
|
124
|
+
|
|
125
|
+
`structuredClone` 미지원 타입 처리. Date/DateTime/DateOnly/Time/Uuid/RegExp/Error(cause/code/detail)/Uint8Array/Map/Set/Array/Object.
|
|
126
|
+
|
|
127
|
+
```typescript
|
|
128
|
+
const { result, transferList } = transfer.encode(data);
|
|
129
|
+
worker.postMessage(result, transferList); // Uint8Array.buffer 가 transferList 에 zero-copy
|
|
130
|
+
const decoded = transfer.decode(event.data);
|
|
131
|
+
```
|
|
132
|
+
|
|
133
|
+
순환 참조 시 `TypeError("순환 참조 감지됨: <path>")`. 같은 객체 다중 참조는 인코딩 결과 캐싱.
|
|
134
|
+
|
|
135
|
+
## err — 에러 메시지
|
|
136
|
+
|
|
137
|
+
```typescript
|
|
138
|
+
err.message(unknownErr) // Error 면 .message, 아니면 String(err)
|
|
139
|
+
```
|
|
140
|
+
|
|
141
|
+
## dt — date-format 저수준
|
|
142
|
+
|
|
143
|
+
`DateTime/DateOnly/Time#toFormatString` 내부에서 사용. 직접 사용 드묾.
|
|
144
|
+
|
|
145
|
+
```typescript
|
|
146
|
+
dt.format(formatStr, { year?, month?, day?, hour?, minute?, second?, millisecond?, timezoneOffsetMinutes? })
|
|
147
|
+
// 토큰은 types.md 의 "date-format 토큰" 참조
|
|
148
|
+
dt.normalizeMonth(year, month, day) // 월 1-12 정규화 + 일 클램프
|
|
149
|
+
dt.convert12To24(rawHour, isPM) // 12시간 → 24시간
|
|
150
|
+
```
|
|
151
|
+
|
|
152
|
+
## primitive — 런타임 타입 추론
|
|
153
|
+
|
|
154
|
+
```typescript
|
|
155
|
+
primitive.typeStr(value)
|
|
156
|
+
// string/number/boolean/DateTime/DateOnly/Time/Uuid/Bytes 중 하나 반환.
|
|
157
|
+
// 미지원 타입은 ArgumentError.
|
|
158
|
+
```
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
## @simplysm/core-node
|
|
2
|
+
|
|
3
|
+
Node.js 전용 유틸·기능 묶음. 파일 IO/glob, 경로 변환, 자식 프로세스 spawn, 파일 시스템 감시, consola 리포터 셋업, worker_threads 타입 안전 래퍼.
|
|
4
|
+
|
|
5
|
+
## 사용 트리거 인덱스
|
|
6
|
+
|
|
7
|
+
- **`fsx` 네임스페이스** — 파일/디렉토리 존재 확인·생성·복사·삭제·읽기·쓰기·JSON·glob·재귀 유틸. 자세히: [fsx.md](./fsx.md)
|
|
8
|
+
- **`pathx` 네임스페이스** — POSIX 경로 변환, 하위 경로 판정, 디렉토리 치환, target 필터링. 자세히: [pathx.md](./pathx.md)
|
|
9
|
+
- **`cpx` 네임스페이스** — 시스템 인코딩 감지 + 자식 프로세스 spawn/spawnSync (인코딩 자동 디코딩, exitCode 기반 reject). 자세히: [cpx.md](./cpx.md)
|
|
10
|
+
- **`FsWatcher`** — chokidar 기반 디바운스/이벤트 병합 + Windows EPERM 자동 복구 파일 감시. 자세히: [fs-watcher.md](./fs-watcher.md)
|
|
11
|
+
- **`setupConsola` / `PrettyReporter` / `createFileReporter` / `withMaxLevel`** — Node 앱 consola 셋업, 컬러 콘솔/JSON 파일 회전 리포터. 자세히: [consola.md](./consola.md)
|
|
12
|
+
- **`Worker` / `createWorker` / `WorkerProxy` / `WorkerModule` / `PromisifyMethods`** — worker_threads 위 타입 안전 RPC 래퍼 (메서드 호출 + 이벤트 send/on). 자세히: [worker.md](./worker.md)
|