@supersoniks/concorde 5.1.1 → 5.1.3-immutable.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/.agents/skills/concorde-docs/SKILL.md +153 -0
- package/.agents/skills/{concorde-component-docs/template.md → concorde-docs/templates/component.md} +6 -2
- package/.agents/skills/concorde-docs/templates/decorator.md +43 -0
- package/.agents/skills/concorde-docs/templates/guide.md +25 -0
- package/.claude/skills +1 -0
- package/.github/workflows/ci.yml +21 -0
- package/.github-export-ignore +30 -0
- package/CONTRIBUTING.md +59 -0
- package/DEV.md +54 -0
- package/LICENSE +21 -0
- package/OPEN_SOURCE_CHECKPOINT.md +133 -0
- package/README.md +4 -4
- package/ai/README.md +29 -41
- package/ai/skills/concorde/SKILL.md +54 -324
- package/ai/skills/concorde/rules/composition.md +32 -0
- package/ai/skills/concorde/rules/data.md +47 -0
- package/ai/skills/concorde/rules/http.md +25 -0
- package/ai/skills/concorde/rules/lists-forms.md +35 -0
- package/ai/skills/concorde/rules/styling.md +46 -0
- package/ai/skills/concorde/rules/troubleshooting.md +45 -0
- package/build-infos.json +1 -1
- package/concorde-core.bundle.js +177 -177
- package/concorde-core.es.js +4993 -4833
- package/custom-elements-manifest.public.config.mjs +8 -0
- package/{.tmp-cem/custom-elements.json → custom-elements.json} +11758 -8904
- package/dist/concorde-core.bundle.js +177 -177
- package/dist/concorde-core.es.js +4993 -4833
- package/dist/docs-mock-api-sw.js +58 -223
- package/dist/docs-mock-api-sw.js.map +4 -4
- package/dist/img/concorde/plane_01.jpg +0 -0
- package/dist/img/concorde/plane_02.jpg +0 -0
- package/dist/img/concorde/plane_03.jpg +0 -0
- package/dist/img/concorde/plane_04.jpg +0 -0
- package/dist/img/concorde/plane_05.jpg +0 -0
- package/dist/img/concorde/plane_06.jpg +0 -0
- package/dist/img/concorde/plane_07.jpg +0 -0
- package/dist/img/concorde/plane_08.jpg +0 -0
- package/dist/img/concorde/plane_09.jpg +0 -0
- package/dist/img/concorde/plane_10.jpg +0 -0
- package/dist/img/concorde/plane_11.jpg +0 -0
- package/dist/img/concorde/plane_12.jpg +0 -0
- package/dist/img/concorde/plane_13.jpg +0 -0
- package/dist/img/og-concorde.jpg +0 -0
- package/dist/robots.txt +11 -10
- package/docs/assets/index-D_alEsng.js +12122 -0
- package/docs/crawl/core/components/functional/date/date.html +190 -0
- package/docs/crawl/core/components/functional/fetch/fetch.html +109 -0
- package/docs/crawl/core/components/functional/if/if.html +27 -0
- package/docs/crawl/core/components/functional/jsonata/jsonata.html +79 -0
- package/docs/crawl/core/components/functional/list/list.html +70 -0
- package/docs/crawl/core/components/functional/mix/mix.html +45 -0
- package/docs/crawl/core/components/functional/queue/queue.html +96 -0
- package/docs/crawl/core/components/functional/router/router.html +106 -0
- package/docs/crawl/core/components/functional/sdui/sdui-extension-points.html +126 -0
- package/docs/crawl/core/components/functional/sdui/sdui.html +368 -0
- package/docs/crawl/core/components/functional/states/states.html +66 -0
- package/docs/crawl/core/components/functional/submit/submit.html +160 -0
- package/docs/crawl/core/components/functional/subscriber/subscriber.html +67 -0
- package/docs/crawl/core/components/functional/value/value.html +51 -0
- package/docs/crawl/core/components/ui/alert/alert.html +211 -0
- package/docs/crawl/core/components/ui/alert-messages/alert-messages.html +131 -0
- package/docs/crawl/core/components/ui/badge/badge.html +197 -0
- package/docs/crawl/core/components/ui/button/button.html +150 -0
- package/docs/crawl/core/components/ui/captcha/captcha.html +112 -0
- package/docs/crawl/core/components/ui/card/card.html +253 -0
- package/docs/crawl/core/components/ui/divider/divider.html +144 -0
- package/docs/crawl/core/components/ui/form/checkbox/checkbox.html +73 -0
- package/docs/crawl/core/components/ui/form/fieldset/fieldset.html +266 -0
- package/docs/crawl/core/components/ui/form/form-actions/form-actions.html +122 -0
- package/docs/crawl/core/components/ui/form/form-layout/form-layout.html +121 -0
- package/docs/crawl/core/components/ui/form/input/input.html +109 -0
- package/docs/crawl/core/components/ui/form/input-autocomplete/input-autocomplete.html +38 -0
- package/docs/crawl/core/components/ui/form/radio/radio.html +56 -0
- package/docs/crawl/core/components/ui/form/select/select.html +73 -0
- package/docs/crawl/core/components/ui/form/switch/switch.html +56 -0
- package/docs/crawl/core/components/ui/form/textarea/textarea.html +59 -0
- package/docs/crawl/core/components/ui/group/group.html +104 -0
- package/docs/crawl/core/components/ui/icon/icon.html +222 -0
- package/docs/crawl/core/components/ui/image/image.html +298 -0
- package/docs/crawl/core/components/ui/link/link.html +100 -0
- package/docs/crawl/core/components/ui/loader/loader.html +124 -0
- package/docs/crawl/core/components/ui/menu/menu.html +394 -0
- package/docs/crawl/core/components/ui/modal/modal.html +342 -0
- package/docs/crawl/core/components/ui/pop/pop.html +296 -0
- package/docs/crawl/core/components/ui/progress/progress.html +131 -0
- package/docs/crawl/core/components/ui/table/table.html +545 -0
- package/docs/crawl/core/components/ui/theme/theme.html +131 -0
- package/docs/crawl/core/components/ui/toast/toast.html +233 -0
- package/docs/crawl/core/components/ui/tooltip/tooltip.html +140 -0
- package/docs/crawl/docs/_core-concept/dataFlow.html +177 -0
- package/docs/crawl/docs/_core-concept/overview.html +66 -0
- package/docs/crawl/docs/_core-concept/subscriber.html +75 -0
- package/docs/crawl/docs/_decorators/ancestor-attribute.html +117 -0
- package/docs/crawl/docs/_decorators/auto-subscribe.html +202 -0
- package/docs/crawl/docs/_decorators/bind.html +141 -0
- package/docs/crawl/docs/_decorators/get.html +149 -0
- package/docs/crawl/docs/_decorators/handle.html +165 -0
- package/docs/crawl/docs/_decorators/on-assign.html +355 -0
- package/docs/crawl/docs/_decorators/patch.html +78 -0
- package/docs/crawl/docs/_decorators/post.html +139 -0
- package/docs/crawl/docs/_decorators/publish.html +61 -0
- package/docs/crawl/docs/_decorators/put.html +78 -0
- package/docs/crawl/docs/_decorators/subscribe.html +109 -0
- package/docs/crawl/docs/_decorators/wait-for-ancestors.html +137 -0
- package/docs/crawl/docs/_directives/sub.html +93 -0
- package/docs/crawl/docs/_getting-started/ai-agents.html +173 -0
- package/docs/crawl/docs/_getting-started/concorde-manual-install.html +100 -0
- package/docs/crawl/docs/_getting-started/concorde-outside.html +58 -0
- package/docs/crawl/docs/_getting-started/create-a-component.html +111 -0
- package/docs/crawl/docs/_getting-started/my-first-component.html +189 -0
- package/docs/crawl/docs/_getting-started/my-first-subscriber.html +110 -0
- package/docs/crawl/docs/_getting-started/pubsub.html +62 -0
- package/docs/crawl/docs/_getting-started/start.html +76 -0
- package/docs/crawl/docs/_getting-started/theming.html +333 -0
- package/docs/crawl/docs/_misc/api-configuration.html +149 -0
- package/docs/crawl/docs/_misc/dataProviderKey.html +135 -0
- package/docs/crawl/docs/_misc/docs-mock-api.html +158 -0
- package/docs/crawl/docs/_misc/dynamic-path.html +180 -0
- package/docs/crawl/docs/_misc/endpoint.html +50 -0
- package/docs/crawl/docs/_misc/formelement-subscriber-removal.html +138 -0
- package/docs/crawl/docs/_misc/html-integration.html +48 -0
- package/docs/crawl/hubs/decorators.html +547 -0
- package/docs/crawl/hubs/form-components.html +381 -0
- package/docs/crawl/hubs/remote-data.html +452 -0
- package/docs/crawl/index.html +103 -0
- package/docs/index.html +1 -1
- package/docs/llms-full.txt +7174 -0
- package/docs/llms.txt +98 -0
- package/docs/sitemap.xml +243 -0
- package/docs/src/core/components/functional/date/date.md +290 -0
- package/docs/src/core/components/functional/fetch/fetch.md +125 -0
- package/docs/src/core/components/functional/if/if.md +9 -0
- package/docs/src/core/components/functional/jsonata/jsonata.md +56 -0
- package/docs/src/core/components/functional/list/list.md +65 -0
- package/docs/src/core/components/functional/mix/mix.md +41 -0
- package/docs/src/core/components/functional/queue/queue.md +72 -0
- package/docs/src/core/components/functional/router/router.md +94 -0
- package/docs/src/core/components/functional/sdui/component-catalog.gaps.json +511 -0
- package/docs/src/core/components/functional/sdui/component-catalog.json +3103 -0
- package/docs/src/core/components/functional/sdui/default-library.json +108 -0
- package/docs/src/core/components/functional/sdui/example.json +99 -0
- package/docs/src/core/components/functional/sdui/sdui-extension-points.md +94 -0
- package/docs/src/core/components/functional/sdui/sdui.md +478 -0
- package/docs/src/core/components/functional/states/states.md +87 -0
- package/docs/src/core/components/functional/submit/submit.md +114 -0
- package/docs/src/core/components/functional/subscriber/subscriber.md +91 -0
- package/docs/src/core/components/functional/value/value.md +35 -0
- package/docs/src/core/components/ui/alert/alert.md +196 -0
- package/docs/src/core/components/ui/alert-messages/alert-messages.md +85 -0
- package/docs/src/core/components/ui/badge/badge.md +188 -0
- package/docs/src/core/components/ui/button/button.md +183 -0
- package/docs/src/core/components/ui/captcha/captcha.md +71 -0
- package/docs/src/core/components/ui/card/card.md +215 -0
- package/docs/src/core/components/ui/divider/divider.md +129 -0
- package/docs/src/core/components/ui/form/checkbox/checkbox.md +77 -0
- package/docs/src/core/components/ui/form/fieldset/fieldset.md +205 -0
- package/docs/src/core/components/ui/form/form-actions/form-actions.md +100 -0
- package/docs/src/core/components/ui/form/form-layout/form-layout.md +119 -0
- package/docs/src/core/components/ui/form/input/input.md +142 -0
- package/docs/src/core/components/ui/form/radio/radio.md +57 -0
- package/docs/src/core/components/ui/form/select/select.md +71 -0
- package/docs/src/core/components/ui/form/switch/switch.md +57 -0
- package/docs/src/core/components/ui/form/textarea/textarea.md +65 -0
- package/docs/src/core/components/ui/group/group.md +75 -0
- package/docs/src/core/components/ui/icon/icon.md +214 -0
- package/docs/src/core/components/ui/icon/icons.json +1 -0
- package/docs/src/core/components/ui/image/image.md +233 -0
- package/docs/src/core/components/ui/link/link.md +81 -0
- package/docs/src/core/components/ui/loader/loader.md +112 -0
- package/docs/src/core/components/ui/menu/menu.md +370 -0
- package/docs/src/core/components/ui/modal/modal.md +235 -0
- package/docs/src/core/components/ui/pop/pop.md +294 -0
- package/docs/src/core/components/ui/progress/progress.md +109 -0
- package/docs/src/core/components/ui/table/table.md +431 -0
- package/docs/src/core/components/ui/theme/theme.md +122 -0
- package/docs/src/core/components/ui/toast/toast.md +216 -0
- package/docs/src/core/components/ui/tooltip/tooltip.md +124 -0
- package/{src → docs/src}/docs/_core-concept/subscriber.md +0 -0
- package/{src → docs/src}/docs/_getting-started/my-first-subscriber.md +0 -0
- package/{src → docs/src}/docs/_getting-started/pubsub.md +0 -0
- package/docs/src/docs/_getting-started/theming.md +253 -0
- package/docs/src/docs/search/docs-search.json +12242 -0
- package/docs/src/tag-list.json +1 -0
- package/docs/src/tsconfig-model.json +23 -0
- package/docs/src/tsconfig.declarations.json +22 -0
- package/docs/src/tsconfig.emit.json +23 -0
- package/docs/src/tsconfig.json +1332 -0
- package/gitlab/job_github_mirror.sh +39 -0
- package/index.html +157 -5
- package/package.json +22 -4
- package/public/docs-mock-api-sw.js +58 -223
- package/public/docs-mock-api-sw.js.map +4 -4
- package/public/img/concorde/plane_01.jpg +0 -0
- package/public/img/concorde/plane_02.jpg +0 -0
- package/public/img/concorde/plane_03.jpg +0 -0
- package/public/img/concorde/plane_04.jpg +0 -0
- package/public/img/concorde/plane_05.jpg +0 -0
- package/public/img/concorde/plane_06.jpg +0 -0
- package/public/img/concorde/plane_07.jpg +0 -0
- package/public/img/concorde/plane_08.jpg +0 -0
- package/public/img/concorde/plane_09.jpg +0 -0
- package/public/img/concorde/plane_10.jpg +0 -0
- package/public/img/concorde/plane_11.jpg +0 -0
- package/public/img/concorde/plane_12.jpg +0 -0
- package/public/img/concorde/plane_13.jpg +0 -0
- package/public/img/og-concorde.jpg +0 -0
- package/public/robots.txt +11 -10
- package/scripts/ai-init.mjs +104 -379
- package/scripts/ai-init.test.mjs +81 -239
- package/scripts/docs-markdown-vite-plugin.ts +43 -0
- package/scripts/docs-public-url.mjs +56 -0
- package/scripts/docs.htaccess +82 -0
- package/scripts/generate-cem.mjs +244 -0
- package/scripts/generate-cem.test.mjs +122 -0
- package/scripts/generate-crawl-docs.mjs +233 -118
- package/scripts/generate-crawl-docs.test.mjs +124 -0
- package/scripts/generate-sdui-catalog.mjs +11 -10
- package/scripts/github-export.mjs +150 -0
- package/scripts/post-build-docs.js +37 -50
- package/scripts/post-build.mjs +0 -0
- package/scripts/pre-publish.mjs +2 -1
- package/scripts/site-pages.mjs +212 -0
- package/scripts/site-pages.test.mjs +116 -0
- package/site-pages/about.md +22 -0
- package/site-pages/privacy.md +32 -0
- package/src/core/components/functional/date/date.md +91 -231
- package/src/core/components/functional/example/example.ts +3 -1
- package/src/core/components/functional/fetch/fetch.md +66 -83
- package/src/core/components/functional/if/if.md +28 -3
- package/src/core/components/functional/if/if.ts +0 -0
- package/src/core/components/functional/jsonata/jsonata.md +42 -37
- package/src/core/components/functional/list/list.demo.ts +0 -0
- package/src/core/components/functional/list/list.md +103 -43
- package/src/core/components/functional/list/list.ts +17 -4
- package/src/core/components/functional/mix/mix.md +31 -26
- package/src/core/components/functional/queue/queue.demo.ts +10 -7
- package/src/core/components/functional/queue/queue.md +40 -61
- package/src/core/components/functional/router/router.demo.ts +16 -16
- package/src/core/components/functional/router/router.md +64 -65
- package/src/core/components/functional/router/router.ts +0 -0
- package/src/core/components/functional/sdui/SDUIDescriptorTransformer.ts +0 -0
- package/src/core/components/functional/sdui/component-catalog.gaps.json +1 -1
- package/src/core/components/functional/sdui/component-catalog.json +2 -2
- package/src/core/components/functional/sdui/example.json +19 -86
- package/src/core/components/functional/sdui/sdui-extension-points.md +1 -1
- package/src/core/components/functional/sdui/sdui-immutable.spec.ts +74 -0
- package/src/core/components/functional/sdui/sdui.md +187 -358
- package/src/core/components/functional/sdui/sdui.ts +33 -8
- package/src/core/components/functional/sdui/types.ts +0 -0
- package/src/core/components/functional/states/states.demo.ts +21 -22
- package/src/core/components/functional/states/states.md +86 -61
- package/src/core/components/functional/states/states.ts +1 -1
- package/src/core/components/functional/submit/submit.md +64 -72
- package/src/core/components/functional/submit/submit.spec.ts +60 -0
- package/src/core/components/functional/submit/submit.ts +6 -3
- package/src/core/components/functional/subscriber/subscriber.ts +0 -0
- package/src/core/components/functional/translation/translation.md +38 -0
- package/src/core/components/functional/value/value.md +34 -22
- package/src/core/components/functional/value/value.ts +0 -0
- package/src/core/components/ui/_css/size.ts +0 -0
- package/src/core/components/ui/alert/alert.md +48 -58
- package/src/core/components/ui/badge/badge.md +27 -34
- package/src/core/components/ui/button/button.md +139 -106
- package/src/core/components/ui/captcha/altchaStyles.ts +0 -0
- package/src/core/components/ui/captcha/captcha.md +17 -32
- package/src/core/components/ui/card/card.md +6 -6
- package/src/core/components/ui/divider/divider.md +8 -11
- package/src/core/components/ui/form/checkbox/checkbox.md +90 -42
- package/src/core/components/ui/form/fieldset/fieldset.md +31 -75
- package/src/core/components/ui/form/form-actions/form-actions.md +14 -16
- package/src/core/components/ui/form/form-layout/form-layout.md +19 -29
- package/src/core/components/ui/form/input/input.md +108 -90
- package/src/core/components/ui/form/input/input.ts +8 -2
- package/src/core/components/ui/form/radio/radio.md +65 -30
- package/src/core/components/ui/form/select/select.md +60 -45
- package/src/core/components/ui/form/switch/switch.md +57 -34
- package/src/core/components/ui/form/textarea/textarea.md +55 -38
- package/src/core/components/ui/group/group.md +35 -33
- package/src/core/components/ui/icon/icon.md +4 -4
- package/src/core/components/ui/image/image.md +41 -107
- package/src/core/components/ui/link/link.md +6 -6
- package/src/core/components/ui/loader/loader.md +30 -55
- package/src/core/components/ui/menu/menu.md +27 -27
- package/src/core/components/ui/modal/modal.md +72 -96
- package/src/core/components/ui/pop/pop.md +80 -158
- package/src/core/components/ui/progress/progress.md +2 -2
- package/src/core/components/ui/table/table.md +91 -255
- package/src/core/components/ui/theme/theme.md +11 -36
- package/src/core/components/ui/toast/toast.md +48 -117
- package/src/core/components/ui/tooltip/tooltip.md +27 -62
- package/src/core/decorators/subscriber/bind.ts +9 -14
- package/src/core/decorators/subscriber/subscribe.ts +15 -9
- package/src/core/decorators/subscriber/subscribe.type-test.ts +14 -5
- package/src/core/mixins/Subscriber.ts +0 -0
- package/src/core/utils/DataBindObserver.ts +0 -0
- package/src/core/utils/LocationHandler.spec.ts +80 -0
- package/src/core/utils/LocationHandler.ts +5 -9
- package/src/core/utils/Objects.ts +0 -0
- package/src/core/utils/PublisherProxy.ts +166 -125
- package/src/core/utils/deepReadonly.spec.ts +66 -0
- package/src/core/utils/deepReadonly.ts +71 -0
- package/src/core/utils/immutableValue.spec.ts +54 -0
- package/src/core/utils/immutableValue.ts +102 -0
- package/src/core/utils/nestedDotForm.spec.ts +88 -0
- package/src/core/utils/publisherImmutable.spec.ts +76 -0
- package/src/core/utils/route.ts +0 -0
- package/src/core/utils/strictGet.spec.ts +61 -0
- package/src/core/utils/strictGet.ts +102 -0
- package/src/css.d.ts +19 -0
- package/src/docs/components/docs-demo-sources.ts +55 -140
- package/src/docs/components/docs-lit-demo.ts +1 -3
- package/src/docs/components/docs-source-link.ts +0 -82
- package/src/docs/decorators/ancestor-attribute.md +59 -0
- package/src/docs/decorators/auto-subscribe.md +40 -0
- package/src/docs/decorators/bind.md +76 -0
- package/src/docs/decorators/get.md +160 -0
- package/src/docs/decorators/handle.md +119 -0
- package/src/docs/decorators/on-assign.md +63 -0
- package/src/docs/decorators/patch.md +44 -0
- package/src/docs/decorators/post.md +134 -0
- package/src/docs/decorators/publish.md +56 -0
- package/src/docs/decorators/put.md +51 -0
- package/src/docs/decorators/subscribe.md +87 -0
- package/src/docs/decorators/wait-for-ancestors.md +76 -0
- package/src/docs/directives/sub.md +75 -0
- package/src/docs/directives/t.md +73 -0
- package/src/docs/docs-location.spec.ts +56 -0
- package/src/docs/docs-location.ts +133 -32
- package/src/docs/docs.ts +1 -2
- package/src/docs/example/decorators-demo-bind-demos.ts +83 -135
- package/src/docs/example/decorators-demo-geo.ts +30 -19
- package/src/docs/example/decorators-demo-post.ts +88 -186
- package/src/docs/example/decorators-demo-subscribe-publish-get-demos.ts +165 -268
- package/src/docs/example/decorators-demo.ts +85 -98
- package/src/docs/example/docs-api-config-demos.ts +19 -20
- package/src/docs/example/docs-flight-demos.ts +147 -0
- package/src/docs/example/docs-jsonata-demos.ts +52 -52
- package/src/docs/example/docs-list-demos.ts +43 -123
- package/src/docs/example/docs-provider-keys.ts +21 -28
- package/src/docs/example/docs-queue-demos.ts +37 -77
- package/src/docs/example/docs-router-demos.ts +20 -25
- package/src/docs/example/docs-submit-demos.ts +48 -48
- package/src/docs/example/docs-toggle-demos.ts +4 -3
- package/src/docs/example/users.ts +0 -0
- package/src/docs/getting-started/ai-agents.md +50 -0
- package/src/docs/getting-started/create-a-component.md +136 -0
- package/src/docs/getting-started/dataFlow.md +87 -0
- package/src/docs/getting-started/installation.md +36 -0
- package/src/docs/getting-started/my-first-component.md +227 -0
- package/src/docs/getting-started/start.md +35 -0
- package/src/docs/header/header.ts +11 -6
- package/src/docs/home/catalog.ts +1 -1
- package/src/docs/home/home.ts +20 -11
- package/src/docs/layout.ts +12 -13
- package/src/docs/misc/api-configuration.md +79 -0
- package/src/docs/misc/dataProviderKey.md +168 -0
- package/src/docs/misc/docs-mock-api.md +62 -0
- package/src/docs/misc/dynamic-path.md +71 -0
- package/src/docs/misc/endpoint.md +45 -0
- package/src/docs/misc/html-integration.md +14 -0
- package/src/docs/misc/publisher-get-immutability-docs-crawl.json +902 -0
- package/src/docs/misc/publisher-get-immutability-docs-recheck.json +13 -0
- package/src/docs/misc/publisher-get-immutability-study.md +229 -0
- package/src/docs/mock-api/api-config-mock.ts +5 -0
- package/src/docs/mock-api/fixtures.ts +0 -278
- package/src/docs/mock-api/flights.ts +89 -0
- package/src/docs/mock-api/router.ts +3 -4
- package/src/docs/mock-api/urls.ts +1 -2
- package/src/docs/navigation/navigation.ts +84 -101
- package/src/docs/navigation/toc.ts +7 -4
- package/src/docs/search/docs-search.json +3188 -5153
- package/src/docs/search/markdown-renderer.ts +31 -8
- package/src/docs/search/page.ts +9 -6
- package/src/docs/search/search.ts +154 -122
- package/src/docs/tailwind/css/docs/content.css +4 -5
- package/src/tsconfig.declarations.json +22 -0
- package/src/tsconfig.emit.json +23 -0
- package/src/tsconfig.json +53 -5
- package/src/tsconfig.tsbuildinfo +1 -1
- package/vite.config.mts +11 -2
- package/.agents/skills/concorde-component-docs/SKILL.md +0 -194
- package/.taste-skill/after/desktop-fold.jpg +0 -0
- package/.taste-skill/after/desktop-page-01.jpg +0 -0
- package/.taste-skill/after/desktop-page-02.jpg +0 -0
- package/.taste-skill/after/desktop-page-03.jpg +0 -0
- package/.taste-skill/after/mobile-fold.jpg +0 -0
- package/.taste-skill/after/mobile-page-01.jpg +0 -0
- package/.taste-skill/after/report.json +0 -4103
- package/.taste-skill/after/tablet-fold.jpg +0 -0
- package/.taste-skill/after/tablet-page-01.jpg +0 -0
- package/.taste-skill/after/tablet-page-02.jpg +0 -0
- package/.taste-skill/before/desktop-fold.jpg +0 -0
- package/.taste-skill/before/desktop-page-01.jpg +0 -0
- package/.taste-skill/before/desktop-page-02.jpg +0 -0
- package/.taste-skill/before/mobile-fold.jpg +0 -0
- package/.taste-skill/before/mobile-page-01.jpg +0 -0
- package/.taste-skill/before/report.json +0 -2556
- package/.taste-skill/before/tablet-fold.jpg +0 -0
- package/.taste-skill/before/tablet-page-01.jpg +0 -0
- package/.taste-skill/direction.json +0 -510
- package/.taste-skill/notes.md +0 -84
- package/.taste-skill/prod/desktop-fold.jpg +0 -0
- package/.taste-skill/prod/desktop-page-01.jpg +0 -0
- package/.taste-skill/prod/desktop-page-02.jpg +0 -0
- package/.taste-skill/prod/desktop-page-03.jpg +0 -0
- package/.taste-skill/prod/mobile-fold.jpg +0 -0
- package/.taste-skill/prod/mobile-page-01.jpg +0 -0
- package/.taste-skill/prod/mobile-page-02.jpg +0 -0
- package/.taste-skill/prod/report.json +0 -1973
- package/.taste-skill/prod/tablet-fold.jpg +0 -0
- package/.taste-skill/prod/tablet-page-01.jpg +0 -0
- package/.taste-skill/prod/tablet-page-02.jpg +0 -0
- package/AUDIT.md +0 -228
- package/PLAN-AMELIORATION.md +0 -220
- package/ai/AGENTS.md +0 -56
- package/ai/cursor/rules/concorde-menu.mdc +0 -15
- package/ai/cursor/rules/concorde-scope.mdc +0 -14
- package/ai/cursor/rules/concorde-theme.mdc +0 -13
- package/ai/cursor/rules/concorde.mdc +0 -66
- package/ai/jetbrains/rules/concorde.md +0 -53
- package/ai/skills/concorde-get-set-dp/SKILL.md +0 -194
- package/ai/skills/concorde-imports/SKILL.md +0 -78
- package/ai/skills/concorde-menu/SKILL.md +0 -74
- package/ai/skills/concorde-scope/SKILL.md +0 -70
- package/ai/skills/concorde-theme/SKILL.md +0 -57
- package/docs/assets/index-Bb-_LRyY.js +0 -12280
- package/src/docs/example/docs-input-autocomplete-demos.ts +0 -110
- package/src/docs/example/docs-joke-demos.ts +0 -297
- /package/{src → docs/src}/core/components/ui/form/input-autocomplete/input-autocomplete.md +0 -0
- /package/{src → docs/src}/docs/_core-concept/dataFlow.md +0 -0
- /package/{src → docs/src}/docs/_core-concept/overview.md +0 -0
- /package/{src → docs/src}/docs/_decorators/ancestor-attribute.md +0 -0
- /package/{src → docs/src}/docs/_decorators/auto-subscribe.md +0 -0
- /package/{src → docs/src}/docs/_decorators/bind.md +0 -0
- /package/{src → docs/src}/docs/_decorators/get.md +0 -0
- /package/{src → docs/src}/docs/_decorators/handle.md +0 -0
- /package/{src → docs/src}/docs/_decorators/on-assign.md +0 -0
- /package/{src → docs/src}/docs/_decorators/patch.md +0 -0
- /package/{src → docs/src}/docs/_decorators/post.md +0 -0
- /package/{src → docs/src}/docs/_decorators/publish.md +0 -0
- /package/{src → docs/src}/docs/_decorators/put.md +0 -0
- /package/{src → docs/src}/docs/_decorators/subscribe.md +0 -0
- /package/{src → docs/src}/docs/_decorators/wait-for-ancestors.md +0 -0
- /package/{src → docs/src}/docs/_directives/sub.md +0 -0
- /package/{src → docs/src}/docs/_getting-started/ai-agents.md +0 -0
- /package/{src → docs/src}/docs/_getting-started/concorde-manual-install.md +0 -0
- /package/{src → docs/src}/docs/_getting-started/concorde-outside.md +0 -0
- /package/{src → docs/src}/docs/_getting-started/create-a-component.md +0 -0
- /package/{src → docs/src}/docs/_getting-started/my-first-component.md +0 -0
- /package/{src → docs/src}/docs/_getting-started/start.md +0 -0
- /package/{src → docs/src}/docs/_misc/api-configuration.md +0 -0
- /package/{src → docs/src}/docs/_misc/dataProviderKey.md +0 -0
- /package/{src → docs/src}/docs/_misc/docs-mock-api.md +0 -0
- /package/{src → docs/src}/docs/_misc/dynamic-path.md +0 -0
- /package/{src → docs/src}/docs/_misc/endpoint.md +0 -0
- /package/{src → docs/src}/docs/_misc/formelement-subscriber-removal.md +0 -0
- /package/{src → docs/src}/docs/_misc/html-integration.md +0 -0
- /package/src/docs/{_getting-started → getting-started}/components.md +0 -0
- /package/src/docs/{_getting-started → getting-started}/theming.md +0 -0
|
@@ -0,0 +1,229 @@
|
|
|
1
|
+
# Étude — immutabilité DataProvider / `get()` (REDMINE-79567)
|
|
2
|
+
|
|
3
|
+
> **Nature :** étude d’opportunité + ADR de direction.
|
|
4
|
+
> Branche : `79567_publisher_get_immutability_study`.
|
|
5
|
+
> **Recadrage (oct. 2026) :** la cible n’est plus un empilement de gardes opt-in, mais un **store immutable** clair.
|
|
6
|
+
|
|
7
|
+
## 0. Décision de direction (ADR)
|
|
8
|
+
|
|
9
|
+
### Contrat cible
|
|
10
|
+
|
|
11
|
+
> **Le publisher possède les données. On ne mute jamais. On remplace.**
|
|
12
|
+
|
|
13
|
+
| API | Comportement |
|
|
14
|
+
|-----|----------------|
|
|
15
|
+
| `set(value)` / `update(recipe)` | Ownership à l’entrée : copie (clone / Immer `produce`), commit, puis **freeze** (ou équivalent) de la valeur stockée |
|
|
16
|
+
| `get()` | Vue **lecture seule** de la valeur commitée — muter → erreur nette |
|
|
17
|
+
| Écritures | Uniquement `set` / `setIn` / `update` — plus de patch in-place de `_value_` |
|
|
18
|
+
| Comportement | **Un seul** en prod (pas de mode « soft » comme design final) |
|
|
19
|
+
|
|
20
|
+
### Ce qu’on ne garde pas comme design produit
|
|
21
|
+
|
|
22
|
+
Empiler `DeepReadonly` + `strictGet` warn/throw + clone parfois = **pansements** autour d’un moteur encore mutable. Utile en **radar de migration**, pas comme architecture cible.
|
|
23
|
+
|
|
24
|
+
### Conséquence technique
|
|
25
|
+
|
|
26
|
+
Refonte du moteur `PublisherProxy` : plus de `_value_[k] = …` / `delete _value_[k]` / sync parent par mutation. Updates **immutables** (Immer ou `setIn` maison) sur tout chemin d’écriture (y compris traps Proxy / sous-proxies).
|
|
27
|
+
|
|
28
|
+
---
|
|
29
|
+
|
|
30
|
+
## 1. Problème (rappel)
|
|
31
|
+
|
|
32
|
+
Aujourd’hui `get()` renvoie la **référence live** de `_value_`. Une mutation locale (`cart.items.push…`) contourne `set` et les listeners → état partagé / UI désynchronisés.
|
|
33
|
+
|
|
34
|
+
Écritures « officielles » (`set`, sous-proxies, `publisher.clé = …`) notifient ; le trou est **get + mutation** et **réutilisation de la ref passée à `set`**.
|
|
35
|
+
|
|
36
|
+
Fichier central : `src/core/utils/PublisherProxy.ts`.
|
|
37
|
+
|
|
38
|
+
---
|
|
39
|
+
|
|
40
|
+
## 2. Alternatives évaluées
|
|
41
|
+
|
|
42
|
+
| | Approche | Verdict |
|
|
43
|
+
|---|----------|---------|
|
|
44
|
+
| A | Freeze live **sans** refonte `set` | **Non** — casse le moteur actuel |
|
|
45
|
+
| B | Clone / Proxy readonly à chaque `get()` | **Non** comme défaut — cher, identité cassée |
|
|
46
|
+
| C | Clone défensif seul sans freeze | **Insuffisant** — n’enseigne pas le contrat |
|
|
47
|
+
| D | `strictGet` opt-in warn/throw | **Outil de migration** seulement |
|
|
48
|
+
| E | Lint / convention seule | **Complément**, pas une garantie |
|
|
49
|
+
| F | **Store immutable** (set ownership + get readonly + updates immutables) | **Cible** |
|
|
50
|
+
|
|
51
|
+
### Perf (ordre de grandeur)
|
|
52
|
+
|
|
53
|
+
1. Status quo / typage seul — 0 runtime
|
|
54
|
+
2. Proxy `strictGet` — faible, sur `get`
|
|
55
|
+
3. Freeze **après** commit immutable — lectures cheap ; coût sur **écritures**
|
|
56
|
+
4. Deep clone à chaque `get` — à éviter
|
|
57
|
+
5. Freeze live + mute in-place — incompatible
|
|
58
|
+
|
|
59
|
+
Le modèle F met le coût là où il est acceptable (écritures), avec une sémantique nette.
|
|
60
|
+
|
|
61
|
+
---
|
|
62
|
+
|
|
63
|
+
## 3. Cible — store immutable (détail)
|
|
64
|
+
|
|
65
|
+
### 3.1 Moteur Concorde à réécrire
|
|
66
|
+
|
|
67
|
+
- `set` / traps Proxy / sync parent-enfant : **immutable updates** uniquement.
|
|
68
|
+
- Après commit : freeze deep (ou structure déjà immutable).
|
|
69
|
+
- `get()` / `onAssign` : renvoient la valeur frozen (même ref tant que le commit n’a pas changé → `get() === get()` OK entre deux `set`).
|
|
70
|
+
- API `update(draft => { … })` (Immer) recommandée pour les updates nested ergonomiques.
|
|
71
|
+
- Valeurs non clonables (`EventSource`, instances, fonctions) : **hors store** ou wrappers documentés (ex. Mercure / laqueue).
|
|
72
|
+
|
|
73
|
+
### 3.2 Surface apps
|
|
74
|
+
|
|
75
|
+
- Interdit : muter après `get`, muter la ref passée à `set`, `.sort()` in-place dans `onAssign`.
|
|
76
|
+
- Obligatoire : `const next = …; set(next)` ou `update(draft => …)`.
|
|
77
|
+
|
|
78
|
+
### 3.3 Rôle du spike actuel sur cette branche
|
|
79
|
+
|
|
80
|
+
Déjà présent (ne pas confondre avec la cible) :
|
|
81
|
+
|
|
82
|
+
- `DeepReadonly` sur `get` / `onAssign` (typage).
|
|
83
|
+
- `PublisherManager.strictGet = "off" | "warn" | "throw"` (Proxy sur le résultat de `get`, **sans** freeze de `_value_`).
|
|
84
|
+
|
|
85
|
+
→ **Radar** pour lister les mutations pendant la migration vers F. Destiné à disparaître ou à se réduire une fois le moteur immutable en place.
|
|
86
|
+
|
|
87
|
+
---
|
|
88
|
+
|
|
89
|
+
## 4. Canal de livraison — dist-tag npm (reco)
|
|
90
|
+
|
|
91
|
+
Oui : publier le chantier sur un **dist-tag npm dédié**, pas sur `latest`, le temps d’un usage approfondi.
|
|
92
|
+
|
|
93
|
+
### Pourquoi c’est adapté ici
|
|
94
|
+
|
|
95
|
+
- Breaking **moteur + contrat** : les apps ne doivent pas le prendre par un bump semver « normal » par erreur.
|
|
96
|
+
- Billetterie / smart-belt / lecovoit / laqueue peuvent opter **explicitement** :
|
|
97
|
+
`"@supersoniks/concorde": "npm:@supersoniks/concorde@immutable"`
|
|
98
|
+
ou version `5.x.x-immutable.n` + tag `immutable`.
|
|
99
|
+
- CI / smokes sur le tag sans bloquer prod `latest`.
|
|
100
|
+
- Feedback réel (perf panier, Mercure, placement) avant major.
|
|
101
|
+
|
|
102
|
+
### Proposition de tags
|
|
103
|
+
|
|
104
|
+
| Tag | Usage |
|
|
105
|
+
|-----|--------|
|
|
106
|
+
| `latest` | Ligne stable actuelle (mutable + éventuellement radar `strictGet` si un jour mergé à part) |
|
|
107
|
+
| `immutable` (ou `next-immutable`) | Ligne de dev du store immutable — **usage approfondi** |
|
|
108
|
+
| (plus tard) `latest` major | Quand la migration Billetterie + checklist sont vertes |
|
|
109
|
+
|
|
110
|
+
Versions du type `6.0.0-immutable.1`, `.2`, … (prerelease) : claires dans le lockfile, republish fréquentes OK.
|
|
111
|
+
|
|
112
|
+
### Ce qu’il ne faut pas faire
|
|
113
|
+
|
|
114
|
+
- Remplacer `latest` trop tôt.
|
|
115
|
+
- Multiplier les tags flous (`test`, `julien`, …) — **un** tag métier `immutable`.
|
|
116
|
+
- Laisser `strictGet` opt-in comme « la » release : ce n’est pas le produit final.
|
|
117
|
+
|
|
118
|
+
### Avis
|
|
119
|
+
|
|
120
|
+
**Go dist-tag `immutable`.** C’est le bon niveau de netteté : chantier puissant isolé, adoption volontaire, mesure avant major. Le spike `strictGet` peut vivre sur la même branche/tag comme aide à la migration, documenté comme temporaire.
|
|
121
|
+
|
|
122
|
+
---
|
|
123
|
+
|
|
124
|
+
## 5. Impact consommateurs (rappel audit)
|
|
125
|
+
|
|
126
|
+
| Projet | Volume / note | Priorité migration |
|
|
127
|
+
|--------|----------------|-------------------|
|
|
128
|
+
| **la-billetterie** | ~860 fichiers dp, ~216 get / ~392 set ; cart, AC, placing, forms | **P0** |
|
|
129
|
+
| smart-belt-drive | Peu de get ; `onAssign` + `.sort()` in-place | P1 |
|
|
130
|
+
| lecovoit | Peu de get, surtout set | P2 |
|
|
131
|
+
| laqueue | Très peu ; Mercure / non-clonables à traiter | P2 |
|
|
132
|
+
| link / starter | Faible | P3 |
|
|
133
|
+
|
|
134
|
+
Zones Billetterie chaudes : `access-control/**`, `utils/cart.ts` + `components/cart/**`, `placing/**`, subscription / tarifs, forms, ~300 `onAssign`, legacy `lb_placement` JS.
|
|
135
|
+
|
|
136
|
+
---
|
|
137
|
+
|
|
138
|
+
## 6. Plan recadré
|
|
139
|
+
|
|
140
|
+
```
|
|
141
|
+
Phase 0 Étude + ADR direction immutable ✅
|
|
142
|
+
Phase 1 Radar DeepReadonly + strictGet ✅
|
|
143
|
+
Phase 2 Moteur immutable sur branche ✅ → publish npm tag `immutable`
|
|
144
|
+
Phase 3 App pilote sur le tag
|
|
145
|
+
Phase 4 Billetterie (puis SBD, lecovoit, laqueue) sur le tag
|
|
146
|
+
Phase 5 Major Concorde sur `latest` quand go-live OK
|
|
147
|
+
```
|
|
148
|
+
|
|
149
|
+
### Critères go-live major
|
|
150
|
+
|
|
151
|
+
- Smokes Billetterie (panier, placing, AC, forms, abonnements, submit, localStorage) verts sur le tag.
|
|
152
|
+
- Pas de régression perf au-delà du seuil convenu sur écritures panier / scan.
|
|
153
|
+
- Doc dataFlow = contrat immutable uniquement.
|
|
154
|
+
- Stratégie explicite pour non-clonables.
|
|
155
|
+
- `strictGet` retiré ou réduit à un assert interne inutile en prod.
|
|
156
|
+
|
|
157
|
+
---
|
|
158
|
+
|
|
159
|
+
## 7. Verdict
|
|
160
|
+
|
|
161
|
+
| Question | Réponse |
|
|
162
|
+
|----------|---------|
|
|
163
|
+
| Problème de contrat réel ? | **Oui** |
|
|
164
|
+
| Design cible ? | **Store immutable** (F), pas la pile de gardes |
|
|
165
|
+
| Freeze live sans refonte ? | **Non** |
|
|
166
|
+
| Clone à chaque `get` ? | **Non** |
|
|
167
|
+
| `strictGet` / `DeepReadonly` ? | **Radar de migration**, pas la cible |
|
|
168
|
+
| Publier sur un tag npm dédié pendant le dev ? | **Oui — `immutable`** |
|
|
169
|
+
| Ce ticket 79567 | Étude + direction ; chantier moteur = ticket(s) d’implémentation + tag |
|
|
170
|
+
|
|
171
|
+
## 8. Suite immédiate
|
|
172
|
+
|
|
173
|
+
1. Publish dist-tag npm `immutable` depuis cette branche.
|
|
174
|
+
2. App pilote (starter / module Billetterie borné).
|
|
175
|
+
3. Migration Billetterie + smokes.
|
|
176
|
+
4. Major sur `latest` quand critères § go-live OK.
|
|
177
|
+
|
|
178
|
+
## 9. Implémenté sur la branche
|
|
179
|
+
|
|
180
|
+
- Helpers : `src/core/utils/immutableValue.ts` (`takeOwnership`, `deepFreeze`, `setAtKey`, `deleteAtKey`)
|
|
181
|
+
- `PublisherProxy.set` : ownership + freeze ; sync parent immutable (plus de `_value_[k] =`)
|
|
182
|
+
- Traps Proxy `set` / `deleteProperty` : via `set` / rebuild
|
|
183
|
+
- `get()` : valeur frozen (même ref jusqu’au prochain `set`)
|
|
184
|
+
- Non-clonable : warn + stocké tel quel sans freeze
|
|
185
|
+
- Specs : `immutableValue.spec.ts`, `publisherImmutable.spec.ts`, etc.
|
|
186
|
+
- Correctifs doc/runtime déjà livrés sur la branche : boucle `sonic-list` / `_metadata_`, clone SDUI, shallow-copy submit, `sameValueAs` en dot-notation
|
|
187
|
+
|
|
188
|
+
## 10. Crawl docs rendu — branche vs `master` (29 oct. 2026)
|
|
189
|
+
|
|
190
|
+
Comparaison automatisée des pages de la nav docs : **A** = branche `79567_publisher_get_immutability_study`, **B** = `master`.
|
|
191
|
+
|
|
192
|
+
Métriques : `bodyChars`, sections `h2`, blocs `sonic-code` (radios/inputs/lists/sdui + hauteurs interactives), `docs-lit-demo`, erreurs console (hors bruit SW 404).
|
|
193
|
+
|
|
194
|
+
Artefacts JSON (bruts) :
|
|
195
|
+
|
|
196
|
+
- `src/docs/misc/publisher-get-immutability-docs-crawl.json` — 68 pages (crawl parallèle initial)
|
|
197
|
+
- `src/docs/misc/publisher-get-immutability-docs-recheck.json` — 43 pages à risque (crawl séquentiel)
|
|
198
|
+
|
|
199
|
+
### Résultat
|
|
200
|
+
|
|
201
|
+
| Passe | Pages | Diffs structurantes (error) | Notes |
|
|
202
|
+
|-------|------:|----------------------------:|-------|
|
|
203
|
+
| Recheck séquentiel | 43 | **0** | Pas de contrôle disparu, pas de preview collapsée, pas d’erreur freeze |
|
|
204
|
+
| Crawl parallèle 68 | 68 | **0** error | 5 pages avec diffs info/warn uniquement |
|
|
205
|
+
|
|
206
|
+
### Diffs relevés (pas de régression immutable)
|
|
207
|
+
|
|
208
|
+
| Page | Nature | Action |
|
|
209
|
+
|------|--------|--------|
|
|
210
|
+
| `/core/components/ui/form/radio` | Section **Nested keys** ajoutée sur la branche | Doc volontaire — à garder ou retirer selon review doc |
|
|
211
|
+
| `/core/components/ui/form/input` | Idem Nested keys + `sameValueAs` dot-notation | Idem |
|
|
212
|
+
| `/docs/directives/t` | Contenu plus riche sur A (sections Import/Usage/…) | Hors immutable — écart de contenu markdown ; vérifier si attendu sur la branche |
|
|
213
|
+
| `/docs/misc/dataProviderKey` | Faux positif crawl parallèle (`bodyChars: 0`) | **Revalidé OK** au recheck / visite manuelle (2615 chars, 9 codes) |
|
|
214
|
+
| `/docs/misc/html-integration` | Console `498` ponctuelle au crawl parallèle | **Revalidé OK** (même rendu A/B, 838 chars) — bruit réseau, pas un gel publisher |
|
|
215
|
+
|
|
216
|
+
### Correctifs déjà faits (hors crawl, signalés avant)
|
|
217
|
+
|
|
218
|
+
- `sonic-list` boucle infinie (`_metadata_`)
|
|
219
|
+
- SDUI mute sur descripteur frozen
|
|
220
|
+
- Submit `delete` sur `get()` frozen
|
|
221
|
+
|
|
222
|
+
### À corriger ultérieurement (backlog crawl)
|
|
223
|
+
|
|
224
|
+
1. **Décider** du sort des sections Nested keys radio/input (ajoutées pendant le debug) — doc only.
|
|
225
|
+
2. **Vérifier** l’écart markdown `docs/directives/t` vs `master` (pas lié au store).
|
|
226
|
+
3. Rejouer le crawl séquentiel après les prochains correctifs moteur avant publish tag `immutable`.
|
|
227
|
+
4. Optionnel : intégrer le script de crawl dans un smoke CI docs (ports dédiés + Chromium system).
|
|
228
|
+
|
|
229
|
+
**Verdict crawl :** pas de régression de rendu docs imputable au store immutable sur l’échantillon recheck (43 pages). Les seuls écarts stables sont documentaires (Nested keys, éventuellement `t`).
|
|
@@ -15,6 +15,11 @@ export const DOCS_MOCK_EVENTS_API_TOKEN = "docs-mock-events-token";
|
|
|
15
15
|
const WORDING_CATALOG: Record<string, Record<string, string>> = {
|
|
16
16
|
"api-config.greeting": { fr: "Bonjour", en: "Hello" },
|
|
17
17
|
"api-config.farewell": { fr: "Au revoir", en: "Goodbye" },
|
|
18
|
+
"flight.boarding": { fr: "Embarquement immédiat", en: "Now boarding" },
|
|
19
|
+
"flight.gate": {
|
|
20
|
+
fr: "Rendez-vous porte <strong>B12</strong>",
|
|
21
|
+
en: "Please proceed to gate <strong>B12</strong>",
|
|
22
|
+
},
|
|
18
23
|
"api-config.hint": {
|
|
19
24
|
fr: "Libellés servis par le mock /wording/labels",
|
|
20
25
|
en: "Labels served by mock /wording/labels",
|
|
@@ -97,281 +97,3 @@ export const DOCS_GEO_COMMUNES: GeoCommuneRow[] = [
|
|
|
97
97
|
{ nom: "Montpellier", code: "34172" },
|
|
98
98
|
{ nom: "Rennes", code: "35238" },
|
|
99
99
|
];
|
|
100
|
-
|
|
101
|
-
/** JokeAPI-style content flags (checkbox / radio / switch blacklist demos). */
|
|
102
|
-
export type DocsJokeFlagKey =
|
|
103
|
-
| "nsfw"
|
|
104
|
-
| "religious"
|
|
105
|
-
| "political"
|
|
106
|
-
| "racist"
|
|
107
|
-
| "sexist"
|
|
108
|
-
| "explicit";
|
|
109
|
-
|
|
110
|
-
/** Forme proche de JokeAPI v2 (`key="jokes"` sur sonic-queue / list). */
|
|
111
|
-
export type DocsJokeItem = {
|
|
112
|
-
categories: string[];
|
|
113
|
-
createdAt: string;
|
|
114
|
-
id: number;
|
|
115
|
-
joke: string;
|
|
116
|
-
lang: "fr" | "en";
|
|
117
|
-
flags: Record<DocsJokeFlagKey, boolean>;
|
|
118
|
-
safe: boolean;
|
|
119
|
-
type: string;
|
|
120
|
-
setup?: string;
|
|
121
|
-
delivery?: string;
|
|
122
|
-
};
|
|
123
|
-
|
|
124
|
-
const jokeFlags = (
|
|
125
|
-
partial: Partial<Record<DocsJokeFlagKey, boolean>> = {},
|
|
126
|
-
): Record<DocsJokeFlagKey, boolean> => ({
|
|
127
|
-
nsfw: false,
|
|
128
|
-
religious: false,
|
|
129
|
-
political: false,
|
|
130
|
-
racist: false,
|
|
131
|
-
sexist: false,
|
|
132
|
-
explicit: false,
|
|
133
|
-
...partial,
|
|
134
|
-
});
|
|
135
|
-
|
|
136
|
-
export type DocsJokeApiResponse = {
|
|
137
|
-
error: boolean;
|
|
138
|
-
amount: number;
|
|
139
|
-
jokes: DocsJokeItem[];
|
|
140
|
-
};
|
|
141
|
-
|
|
142
|
-
const SAMPLE_JOKES: DocsJokeItem[] = [
|
|
143
|
-
{
|
|
144
|
-
categories: ["Programming"],
|
|
145
|
-
createdAt: "2020-01-01 00:00:00",
|
|
146
|
-
id: 1,
|
|
147
|
-
lang: "en",
|
|
148
|
-
joke: "Why do programmers prefer dark mode? Because light attracts bugs.",
|
|
149
|
-
flags: jokeFlags(),
|
|
150
|
-
safe: true,
|
|
151
|
-
type: "single",
|
|
152
|
-
},
|
|
153
|
-
{
|
|
154
|
-
categories: ["Misc"],
|
|
155
|
-
createdAt: "2020-01-02 00:00:00",
|
|
156
|
-
id: 2,
|
|
157
|
-
lang: "en",
|
|
158
|
-
joke: "I told my computer I needed a break — it said: no problem, I'll go to sleep.",
|
|
159
|
-
flags: jokeFlags({ nsfw: true }),
|
|
160
|
-
safe: false,
|
|
161
|
-
type: "single",
|
|
162
|
-
},
|
|
163
|
-
{
|
|
164
|
-
categories: ["Pun"],
|
|
165
|
-
createdAt: "2020-01-03 00:00:00",
|
|
166
|
-
id: 3,
|
|
167
|
-
lang: "en",
|
|
168
|
-
joke: "Concorde docs run offline: even the API is a local joke.",
|
|
169
|
-
flags: jokeFlags(),
|
|
170
|
-
safe: true,
|
|
171
|
-
type: "single",
|
|
172
|
-
},
|
|
173
|
-
{
|
|
174
|
-
categories: ["Animals"],
|
|
175
|
-
createdAt: "2020-01-04 00:00:00",
|
|
176
|
-
id: 4,
|
|
177
|
-
lang: "en",
|
|
178
|
-
joke: "The dog ate my homework and my pull request.",
|
|
179
|
-
flags: jokeFlags({ political: true }),
|
|
180
|
-
safe: true,
|
|
181
|
-
type: "single",
|
|
182
|
-
},
|
|
183
|
-
{
|
|
184
|
-
categories: ["Animals", "Pun"],
|
|
185
|
-
createdAt: "2020-01-05 00:00:00",
|
|
186
|
-
id: 5,
|
|
187
|
-
lang: "fr",
|
|
188
|
-
joke: "Quel est le chien préféré des développeurs ? Le labrador Retriever.",
|
|
189
|
-
flags: jokeFlags(),
|
|
190
|
-
safe: true,
|
|
191
|
-
type: "single",
|
|
192
|
-
},
|
|
193
|
-
{
|
|
194
|
-
categories: ["Animals"],
|
|
195
|
-
createdAt: "2020-01-06 00:00:00",
|
|
196
|
-
id: 6,
|
|
197
|
-
lang: "fr",
|
|
198
|
-
joke: "Un chat et un chien discutent de TypeScript : le chien dit « woof », le chat compile.",
|
|
199
|
-
flags: jokeFlags({ racist: true }),
|
|
200
|
-
safe: false,
|
|
201
|
-
type: "single",
|
|
202
|
-
},
|
|
203
|
-
{
|
|
204
|
-
categories: ["Misc"],
|
|
205
|
-
createdAt: "2020-01-07 00:00:00",
|
|
206
|
-
id: 7,
|
|
207
|
-
lang: "fr",
|
|
208
|
-
joke: "Pourquoi les blagues offline sont-elles fiables ? Parce qu'elles passent par le Service Worker.",
|
|
209
|
-
flags: jokeFlags({ religious: true }),
|
|
210
|
-
safe: true,
|
|
211
|
-
type: "single",
|
|
212
|
-
},
|
|
213
|
-
{
|
|
214
|
-
categories: ["Programming"],
|
|
215
|
-
createdAt: "2020-01-08 00:00:00",
|
|
216
|
-
id: 8,
|
|
217
|
-
lang: "fr",
|
|
218
|
-
joke: "Mon compilateur et mon chien : tous deux ignorent mes commandes jusqu'au build.",
|
|
219
|
-
flags: jokeFlags({ sexist: true }),
|
|
220
|
-
safe: false,
|
|
221
|
-
type: "single",
|
|
222
|
-
},
|
|
223
|
-
{
|
|
224
|
-
categories: ["Misc"],
|
|
225
|
-
createdAt: "2020-01-09 00:00:00",
|
|
226
|
-
id: 9,
|
|
227
|
-
lang: "en",
|
|
228
|
-
joke: "A SQL query walks into a bar, walks up to two tables and asks: Can I join you?",
|
|
229
|
-
flags: jokeFlags({ explicit: true }),
|
|
230
|
-
safe: false,
|
|
231
|
-
type: "single",
|
|
232
|
-
},
|
|
233
|
-
{
|
|
234
|
-
categories: ["Pun"],
|
|
235
|
-
createdAt: "2020-01-10 00:00:00",
|
|
236
|
-
id: 10,
|
|
237
|
-
lang: "fr",
|
|
238
|
-
joke: "J'ai cherché « chien » dans la doc : le mock API a répondu.",
|
|
239
|
-
flags: jokeFlags(),
|
|
240
|
-
safe: true,
|
|
241
|
-
type: "single",
|
|
242
|
-
},
|
|
243
|
-
{
|
|
244
|
-
categories: ["Misc"],
|
|
245
|
-
createdAt: "2020-01-11 00:00:00",
|
|
246
|
-
id: 11,
|
|
247
|
-
lang: "en",
|
|
248
|
-
joke: "There are only two hard things in Computer Science: cache invalidation and naming things.",
|
|
249
|
-
flags: jokeFlags({ political: true, explicit: true }),
|
|
250
|
-
safe: false,
|
|
251
|
-
type: "single",
|
|
252
|
-
},
|
|
253
|
-
{
|
|
254
|
-
categories: ["Animals"],
|
|
255
|
-
createdAt: "2020-01-12 00:00:00",
|
|
256
|
-
id: 12,
|
|
257
|
-
lang: "fr",
|
|
258
|
-
joke: "Le golden retriever a récupéré la donnée du publisher.",
|
|
259
|
-
flags: jokeFlags({ racist: true, sexist: true }),
|
|
260
|
-
safe: false,
|
|
261
|
-
type: "two-liner",
|
|
262
|
-
setup: "Pourquoi le chien aime Concorde ?",
|
|
263
|
-
delivery: "Parce qu'il sait fetch.",
|
|
264
|
-
},
|
|
265
|
-
{
|
|
266
|
-
categories: ["Misc"],
|
|
267
|
-
createdAt: "2020-01-13 00:00:00",
|
|
268
|
-
id: 13,
|
|
269
|
-
lang: "en",
|
|
270
|
-
joke: "My code and my conscience: both have too many warnings.",
|
|
271
|
-
flags: jokeFlags(),
|
|
272
|
-
safe: true,
|
|
273
|
-
type: "single",
|
|
274
|
-
},
|
|
275
|
-
{
|
|
276
|
-
categories: ["Programming"],
|
|
277
|
-
createdAt: "2020-01-14 00:00:00",
|
|
278
|
-
id: 14,
|
|
279
|
-
lang: "en",
|
|
280
|
-
joke: "Git blame is just a mirror.",
|
|
281
|
-
flags: jokeFlags({ religious: true, political: true }),
|
|
282
|
-
safe: false,
|
|
283
|
-
type: "single",
|
|
284
|
-
},
|
|
285
|
-
];
|
|
286
|
-
|
|
287
|
-
/** `blacklistFlags` from queue filter form (comma-separated or repeated param). */
|
|
288
|
-
export function parseBlacklistFlags(url: URL): DocsJokeFlagKey[] {
|
|
289
|
-
const keys = new Set<DocsJokeFlagKey>();
|
|
290
|
-
const valid: DocsJokeFlagKey[] = [
|
|
291
|
-
"nsfw",
|
|
292
|
-
"religious",
|
|
293
|
-
"political",
|
|
294
|
-
"racist",
|
|
295
|
-
"sexist",
|
|
296
|
-
"explicit",
|
|
297
|
-
];
|
|
298
|
-
const add = (raw: string) => {
|
|
299
|
-
raw
|
|
300
|
-
.split(",")
|
|
301
|
-
.map((s) => s.trim().toLowerCase())
|
|
302
|
-
.forEach((part) => {
|
|
303
|
-
if (valid.includes(part as DocsJokeFlagKey)) keys.add(part as DocsJokeFlagKey);
|
|
304
|
-
});
|
|
305
|
-
};
|
|
306
|
-
url.searchParams.getAll("blacklistFlags").forEach(add);
|
|
307
|
-
const single = url.searchParams.get("blacklistFlags");
|
|
308
|
-
if (single) add(single);
|
|
309
|
-
return [...keys];
|
|
310
|
-
}
|
|
311
|
-
|
|
312
|
-
/** Exclude jokes that match any blacklisted flag (JokeAPI-style). */
|
|
313
|
-
export function applyJokeBlacklist(
|
|
314
|
-
jokes: DocsJokeItem[],
|
|
315
|
-
blacklist: DocsJokeFlagKey[],
|
|
316
|
-
): DocsJokeItem[] {
|
|
317
|
-
if (!blacklist.length) return jokes;
|
|
318
|
-
return jokes.filter(
|
|
319
|
-
(j) => !blacklist.some((flag) => j.flags[flag] === true),
|
|
320
|
-
);
|
|
321
|
-
}
|
|
322
|
-
|
|
323
|
-
/** Filtre doc joke queue (`contains`, `lang`, `blacklistFlags` via `dataFilterProvider`). */
|
|
324
|
-
export function filterDocsJokes(
|
|
325
|
-
jokes: DocsJokeItem[],
|
|
326
|
-
url: URL,
|
|
327
|
-
): DocsJokeItem[] {
|
|
328
|
-
let pool = jokes;
|
|
329
|
-
const contains = url.searchParams.get("contains")?.trim().toLowerCase();
|
|
330
|
-
if (contains) {
|
|
331
|
-
pool = pool.filter((j) => {
|
|
332
|
-
const haystack = [j.joke, j.setup, j.delivery, ...j.categories]
|
|
333
|
-
.filter(Boolean)
|
|
334
|
-
.join(" ")
|
|
335
|
-
.toLowerCase();
|
|
336
|
-
return haystack.includes(contains);
|
|
337
|
-
});
|
|
338
|
-
}
|
|
339
|
-
const lang = url.searchParams.get("lang")?.trim().toLowerCase();
|
|
340
|
-
if (lang === "fr" || lang === "en") {
|
|
341
|
-
pool = pool.filter((j) => j.lang === lang);
|
|
342
|
-
}
|
|
343
|
-
pool = applyJokeBlacklist(pool, parseBlacklistFlags(url));
|
|
344
|
-
return pool;
|
|
345
|
-
}
|
|
346
|
-
|
|
347
|
-
/**
|
|
348
|
-
* Réponse type JokeAPI v2.
|
|
349
|
-
* - `amount` : taille du lot si pas de `offset`
|
|
350
|
-
* - `offset` + `limit` / `per_page` : pagination (sonic-queue lazy)
|
|
351
|
-
* - `contains`, `lang`, `blacklistFlags` : filtres formulaire (queue « Remove following jokes »)
|
|
352
|
-
*/
|
|
353
|
-
export function buildJokeApiResponse(url: URL): DocsJokeApiResponse {
|
|
354
|
-
const pool = filterDocsJokes(SAMPLE_JOKES, url);
|
|
355
|
-
const amount = Math.max(
|
|
356
|
-
1,
|
|
357
|
-
parseInt(url.searchParams.get("amount") || "10", 10),
|
|
358
|
-
);
|
|
359
|
-
const hasOffset = url.searchParams.has("offset");
|
|
360
|
-
const limit = Math.max(
|
|
361
|
-
1,
|
|
362
|
-
parseInt(
|
|
363
|
-
url.searchParams.get("limit") ||
|
|
364
|
-
url.searchParams.get("per_page") ||
|
|
365
|
-
String(amount),
|
|
366
|
-
10,
|
|
367
|
-
),
|
|
368
|
-
);
|
|
369
|
-
const offset = Math.max(0, parseInt(url.searchParams.get("offset") || "0", 10));
|
|
370
|
-
const start = hasOffset ? offset : 0;
|
|
371
|
-
const count = hasOffset ? limit : amount;
|
|
372
|
-
const jokes = pool.slice(start, start + count).map((j, i) => ({
|
|
373
|
-
...j,
|
|
374
|
-
id: start + i + 1,
|
|
375
|
-
}));
|
|
376
|
-
return { error: false, amount: jokes.length, jokes };
|
|
377
|
-
}
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
/** Fictional flight board for list / queue filter demos (`key="flights"`). */
|
|
2
|
+
export type DocsFlightStatus =
|
|
3
|
+
| "on-time"
|
|
4
|
+
| "boarding"
|
|
5
|
+
| "delayed"
|
|
6
|
+
| "landed"
|
|
7
|
+
| "cancelled";
|
|
8
|
+
|
|
9
|
+
export type DocsFlight = {
|
|
10
|
+
id: number;
|
|
11
|
+
code: string;
|
|
12
|
+
direction: "departures" | "arrivals";
|
|
13
|
+
airport: string;
|
|
14
|
+
city: string;
|
|
15
|
+
time: string;
|
|
16
|
+
gate: string;
|
|
17
|
+
status: DocsFlightStatus;
|
|
18
|
+
};
|
|
19
|
+
|
|
20
|
+
const row = (
|
|
21
|
+
code: string,
|
|
22
|
+
direction: DocsFlight["direction"],
|
|
23
|
+
airport: string,
|
|
24
|
+
city: string,
|
|
25
|
+
time: string,
|
|
26
|
+
gate: string,
|
|
27
|
+
status: DocsFlightStatus,
|
|
28
|
+
): Omit<DocsFlight, "id"> => ({
|
|
29
|
+
code,
|
|
30
|
+
direction,
|
|
31
|
+
airport,
|
|
32
|
+
city,
|
|
33
|
+
time,
|
|
34
|
+
gate,
|
|
35
|
+
status,
|
|
36
|
+
});
|
|
37
|
+
|
|
38
|
+
const FLIGHTS: Omit<DocsFlight, "id">[] = [
|
|
39
|
+
row("CN 001", "departures", "JFK", "New York", "08:15", "B12", "boarding"),
|
|
40
|
+
row("CN 014", "departures", "LHR", "London", "08:40", "A03", "on-time"),
|
|
41
|
+
row("CN 102", "departures", "GIG", "Rio de Janeiro", "09:05", "C21", "delayed"),
|
|
42
|
+
row("CN 220", "departures", "DKR", "Dakar", "09:30", "C07", "on-time"),
|
|
43
|
+
row("CN 305", "departures", "IAD", "Washington", "10:10", "B04", "cancelled"),
|
|
44
|
+
row("CN 412", "departures", "BAH", "Bahrain", "10:45", "D02", "delayed"),
|
|
45
|
+
row("CN 518", "departures", "SIN", "Singapore", "11:20", "D14", "on-time"),
|
|
46
|
+
row("CN 633", "departures", "YUL", "Montreal", "12:00", "A11", "on-time"),
|
|
47
|
+
row("CN 002", "arrivals", "JFK", "New York", "07:50", "B10", "landed"),
|
|
48
|
+
row("CN 015", "arrivals", "LHR", "London", "08:25", "A05", "landed"),
|
|
49
|
+
row("CN 103", "arrivals", "GIG", "Rio de Janeiro", "09:15", "C20", "delayed"),
|
|
50
|
+
row("CN 221", "arrivals", "DKR", "Dakar", "09:55", "C08", "on-time"),
|
|
51
|
+
row("CN 306", "arrivals", "IAD", "Washington", "10:35", "B06", "on-time"),
|
|
52
|
+
row("CN 413", "arrivals", "BAH", "Bahrain", "11:05", "D03", "cancelled"),
|
|
53
|
+
row("CN 519", "arrivals", "SIN", "Singapore", "11:40", "D15", "delayed"),
|
|
54
|
+
row("CN 634", "arrivals", "YUL", "Montreal", "12:30", "A12", "on-time"),
|
|
55
|
+
];
|
|
56
|
+
|
|
57
|
+
/**
|
|
58
|
+
* `GET /flights` — filters:
|
|
59
|
+
* - `direction`: `departures` · `arrivals`
|
|
60
|
+
* - `q`: substring on code / city / airport
|
|
61
|
+
* - `status`: comma-separated statuses to keep (`all` or empty = no filter)
|
|
62
|
+
* - `offset` + `limit`: pagination for sonic-queue
|
|
63
|
+
*/
|
|
64
|
+
export function buildFlightsResponse(url: URL): { flights: DocsFlight[] } {
|
|
65
|
+
const p = url.searchParams;
|
|
66
|
+
let pool = FLIGHTS.map((f, i) => ({ ...f, id: i + 1 }));
|
|
67
|
+
|
|
68
|
+
const direction = p.get("direction");
|
|
69
|
+
if (direction === "departures" || direction === "arrivals") {
|
|
70
|
+
pool = pool.filter((f) => f.direction === direction);
|
|
71
|
+
}
|
|
72
|
+
const q = p.get("q")?.trim().toLowerCase();
|
|
73
|
+
if (q) {
|
|
74
|
+
pool = pool.filter((f) =>
|
|
75
|
+
[f.code, f.city, f.airport].join(" ").toLowerCase().includes(q),
|
|
76
|
+
);
|
|
77
|
+
}
|
|
78
|
+
const statuses = (p.get("status") || "")
|
|
79
|
+
.split(",")
|
|
80
|
+
.map((s) => s.trim())
|
|
81
|
+
.filter((s) => s && s !== "all");
|
|
82
|
+
if (statuses.length) {
|
|
83
|
+
pool = pool.filter((f) => statuses.includes(f.status));
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
const offset = Math.max(0, parseInt(p.get("offset") || "0", 10));
|
|
87
|
+
const limit = Math.max(1, parseInt(p.get("limit") || "20", 10));
|
|
88
|
+
return { flights: pool.slice(offset, offset + limit) };
|
|
89
|
+
}
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { handleApiConfigMockRequest } from "./api-config-mock";
|
|
2
|
+
import { buildFlightsResponse } from "./flights";
|
|
2
3
|
import {
|
|
3
4
|
DOCS_GEO_COMMUNES,
|
|
4
5
|
DOCS_REQRES_USERS,
|
|
5
|
-
buildJokeApiResponse,
|
|
6
6
|
filterDocsUsers,
|
|
7
7
|
type GeoCommuneRow,
|
|
8
8
|
type ReqresUserResponse,
|
|
@@ -291,9 +291,8 @@ export async function handleDocsMockApiRequest(
|
|
|
291
291
|
});
|
|
292
292
|
}
|
|
293
293
|
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
return json(buildJokeApiResponse(url));
|
|
294
|
+
if (subPath === "/flights") {
|
|
295
|
+
return json(buildFlightsResponse(url));
|
|
297
296
|
}
|
|
298
297
|
|
|
299
298
|
return json({ error: "Not found", path: subPath }, { status: 404 });
|
|
@@ -7,5 +7,4 @@ export const DOCS_MOCK_REQRES_SERVICE = DOCS_MOCK_API_BASE;
|
|
|
7
7
|
/** Remplace https://geo.api.gouv.fr/ — chemins `communes?…`. */
|
|
8
8
|
export const DOCS_MOCK_GEO_SERVICE = `${DOCS_MOCK_API_BASE}/geo/`;
|
|
9
9
|
|
|
10
|
-
|
|
11
|
-
export const DOCS_MOCK_JOKES_SERVICE = `${DOCS_MOCK_API_BASE}/jokes`;
|
|
10
|
+
|