@supersoniks/concorde 5.1.1 → 5.1.3

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.
Files changed (494) hide show
  1. package/.agents/skills/concorde-docs/SKILL.md +153 -0
  2. package/.agents/skills/{concorde-component-docs/template.md → concorde-docs/templates/component.md} +6 -2
  3. package/.agents/skills/concorde-docs/templates/decorator.md +43 -0
  4. package/.agents/skills/concorde-docs/templates/guide.md +25 -0
  5. package/PLAN-DOCS-AGENTS.md +80 -0
  6. package/README.md +4 -4
  7. package/ai/README.md +29 -41
  8. package/ai/skills/concorde/SKILL.md +54 -324
  9. package/ai/skills/concorde/rules/composition.md +32 -0
  10. package/ai/skills/concorde/rules/data.md +47 -0
  11. package/ai/skills/concorde/rules/http.md +25 -0
  12. package/ai/skills/concorde/rules/lists-forms.md +35 -0
  13. package/ai/skills/concorde/rules/styling.md +46 -0
  14. package/ai/skills/concorde/rules/troubleshooting.md +45 -0
  15. package/build-infos.json +1 -1
  16. package/concorde-core.bundle.js +21 -21
  17. package/concorde-core.es.js +977 -980
  18. package/custom-elements-manifest.public.config.mjs +8 -0
  19. package/{.tmp-cem/custom-elements.json → custom-elements.json} +11758 -8904
  20. package/dist/concorde-core.bundle.js +21 -21
  21. package/dist/concorde-core.es.js +977 -980
  22. package/dist/docs-mock-api-sw.js +58 -223
  23. package/dist/docs-mock-api-sw.js.map +4 -4
  24. package/dist/img/concorde/plane_01.jpg +0 -0
  25. package/dist/img/concorde/plane_02.jpg +0 -0
  26. package/dist/img/concorde/plane_03.jpg +0 -0
  27. package/dist/img/concorde/plane_04.jpg +0 -0
  28. package/dist/img/concorde/plane_05.jpg +0 -0
  29. package/dist/img/concorde/plane_06.jpg +0 -0
  30. package/dist/img/concorde/plane_07.jpg +0 -0
  31. package/dist/img/concorde/plane_08.jpg +0 -0
  32. package/dist/img/concorde/plane_09.jpg +0 -0
  33. package/dist/img/concorde/plane_10.jpg +0 -0
  34. package/dist/img/concorde/plane_11.jpg +0 -0
  35. package/dist/img/concorde/plane_12.jpg +0 -0
  36. package/dist/img/concorde/plane_13.jpg +0 -0
  37. package/dist/img/og-concorde.jpg +0 -0
  38. package/dist/robots.txt +11 -10
  39. package/docs/.htaccess +82 -0
  40. package/docs/404.html +15 -0
  41. package/docs/404.md +5 -0
  42. package/docs/about.html +111 -0
  43. package/docs/about.md +22 -0
  44. package/docs/assets/{index-Bb-_LRyY.js → index-6sS76xWj.js} +2625 -3158
  45. package/docs/assets/index-DkdPbH0F.css +1 -0
  46. package/docs/core/components/functional/date/date.html +211 -0
  47. package/docs/core/components/functional/date/date.md +150 -0
  48. package/docs/core/components/functional/fetch/fetch.html +180 -0
  49. package/docs/core/components/functional/fetch/fetch.md +108 -0
  50. package/docs/core/components/functional/if/if.html +65 -0
  51. package/docs/core/components/functional/if/if.md +34 -0
  52. package/docs/core/components/functional/jsonata/jsonata.html +110 -0
  53. package/docs/core/components/functional/jsonata/jsonata.md +61 -0
  54. package/docs/core/components/functional/list/list.html +200 -0
  55. package/docs/core/components/functional/list/list.md +125 -0
  56. package/docs/core/components/functional/mix/mix.html +78 -0
  57. package/docs/core/components/functional/mix/mix.md +46 -0
  58. package/docs/core/components/functional/queue/queue.html +155 -0
  59. package/docs/core/components/functional/queue/queue.md +51 -0
  60. package/docs/core/components/functional/router/router.html +154 -0
  61. package/docs/core/components/functional/router/router.md +93 -0
  62. package/docs/core/components/functional/sdui/sdui-extension-points.html +127 -0
  63. package/docs/core/components/functional/sdui/sdui-extension-points.md +94 -0
  64. package/docs/core/components/functional/sdui/sdui.html +397 -0
  65. package/docs/core/components/functional/sdui/sdui.md +307 -0
  66. package/docs/core/components/functional/states/states.html +141 -0
  67. package/docs/core/components/functional/states/states.md +112 -0
  68. package/docs/core/components/functional/submit/submit.html +178 -0
  69. package/docs/core/components/functional/submit/submit.md +106 -0
  70. package/docs/core/components/functional/subscriber/subscriber.html +68 -0
  71. package/docs/core/components/functional/subscriber/subscriber.md +91 -0
  72. package/docs/core/components/functional/translation/translation.html +60 -0
  73. package/docs/core/components/functional/translation/translation.md +38 -0
  74. package/docs/core/components/functional/value/value.html +81 -0
  75. package/docs/core/components/functional/value/value.md +47 -0
  76. package/docs/core/components/ui/alert/alert.html +201 -0
  77. package/docs/core/components/ui/alert/alert.md +186 -0
  78. package/docs/core/components/ui/alert-messages/alert-messages.html +132 -0
  79. package/docs/core/components/ui/alert-messages/alert-messages.md +85 -0
  80. package/docs/core/components/ui/badge/badge.html +197 -0
  81. package/docs/core/components/ui/badge/badge.md +181 -0
  82. package/docs/core/components/ui/button/button.html +309 -0
  83. package/docs/core/components/ui/button/button.md +216 -0
  84. package/docs/core/components/ui/captcha/captcha.html +80 -0
  85. package/docs/core/components/ui/captcha/captcha.md +56 -0
  86. package/docs/core/components/ui/card/card.html +254 -0
  87. package/docs/core/components/ui/card/card.md +215 -0
  88. package/docs/core/components/ui/divider/divider.html +144 -0
  89. package/docs/core/components/ui/divider/divider.md +126 -0
  90. package/docs/core/components/ui/form/checkbox/checkbox.html +200 -0
  91. package/docs/core/components/ui/form/checkbox/checkbox.md +125 -0
  92. package/docs/core/components/ui/form/fieldset/fieldset.html +238 -0
  93. package/docs/core/components/ui/form/fieldset/fieldset.md +161 -0
  94. package/docs/core/components/ui/form/form-actions/form-actions.html +122 -0
  95. package/docs/core/components/ui/form/form-actions/form-actions.md +98 -0
  96. package/docs/core/components/ui/form/form-layout/form-layout.html +115 -0
  97. package/docs/core/components/ui/form/form-layout/form-layout.md +109 -0
  98. package/docs/core/components/ui/form/input/input.html +235 -0
  99. package/docs/core/components/ui/form/input/input.md +142 -0
  100. package/docs/core/components/ui/form/radio/radio.html +144 -0
  101. package/docs/core/components/ui/form/radio/radio.md +78 -0
  102. package/docs/core/components/ui/form/select/select.html +178 -0
  103. package/docs/core/components/ui/form/select/select.md +86 -0
  104. package/docs/core/components/ui/form/switch/switch.html +146 -0
  105. package/docs/core/components/ui/form/switch/switch.md +80 -0
  106. package/docs/core/components/ui/form/textarea/textarea.html +162 -0
  107. package/docs/core/components/ui/form/textarea/textarea.md +82 -0
  108. package/docs/core/components/ui/group/group.html +113 -0
  109. package/docs/core/components/ui/group/group.md +77 -0
  110. package/docs/core/components/ui/icon/icon.html +223 -0
  111. package/docs/core/components/ui/icon/icon.md +214 -0
  112. package/docs/core/components/ui/image/image.html +194 -0
  113. package/docs/core/components/ui/image/image.md +167 -0
  114. package/docs/core/components/ui/link/link.html +101 -0
  115. package/docs/core/components/ui/link/link.md +81 -0
  116. package/docs/core/components/ui/loader/loader.html +114 -0
  117. package/docs/core/components/ui/loader/loader.md +87 -0
  118. package/docs/core/components/ui/menu/menu.html +395 -0
  119. package/docs/core/components/ui/menu/menu.md +370 -0
  120. package/docs/core/components/ui/modal/modal.html +324 -0
  121. package/docs/core/components/ui/modal/modal.md +211 -0
  122. package/docs/core/components/ui/pop/pop.html +250 -0
  123. package/docs/core/components/ui/pop/pop.md +216 -0
  124. package/docs/core/components/ui/progress/progress.html +132 -0
  125. package/docs/core/components/ui/progress/progress.md +109 -0
  126. package/docs/core/components/ui/table/table.html +333 -0
  127. package/docs/core/components/ui/table/table.md +267 -0
  128. package/docs/core/components/ui/theme/theme.html +116 -0
  129. package/docs/core/components/ui/theme/theme.md +97 -0
  130. package/docs/core/components/ui/toast/toast.html +185 -0
  131. package/docs/core/components/ui/toast/toast.md +147 -0
  132. package/docs/core/components/ui/tooltip/tooltip.html +112 -0
  133. package/docs/core/components/ui/tooltip/tooltip.md +89 -0
  134. package/docs/custom-elements.json +16559 -0
  135. package/docs/docs/decorators/ancestor-attribute.html +71 -0
  136. package/docs/docs/decorators/ancestor-attribute.md +59 -0
  137. package/docs/docs/decorators/auto-subscribe.html +61 -0
  138. package/docs/docs/decorators/auto-subscribe.md +40 -0
  139. package/docs/docs/decorators/bind.html +87 -0
  140. package/docs/docs/decorators/bind.md +76 -0
  141. package/docs/docs/decorators/get.html +166 -0
  142. package/docs/docs/decorators/get.md +160 -0
  143. package/docs/docs/decorators/handle.html +139 -0
  144. package/docs/docs/decorators/handle.md +119 -0
  145. package/docs/docs/decorators/on-assign.html +72 -0
  146. package/docs/docs/decorators/on-assign.md +63 -0
  147. package/docs/docs/decorators/patch.html +76 -0
  148. package/docs/docs/decorators/patch.md +44 -0
  149. package/docs/docs/decorators/post.html +150 -0
  150. package/docs/docs/decorators/post.md +134 -0
  151. package/docs/docs/decorators/publish.html +74 -0
  152. package/docs/docs/decorators/publish.md +56 -0
  153. package/docs/docs/decorators/put.html +83 -0
  154. package/docs/docs/decorators/put.md +51 -0
  155. package/docs/docs/decorators/subscribe.html +91 -0
  156. package/docs/docs/decorators/subscribe.md +87 -0
  157. package/docs/docs/decorators/wait-for-ancestors.html +82 -0
  158. package/docs/docs/decorators/wait-for-ancestors.md +76 -0
  159. package/docs/docs/directives/sub.html +79 -0
  160. package/docs/docs/directives/sub.md +75 -0
  161. package/docs/docs/directives/t.html +91 -0
  162. package/docs/docs/directives/t.md +73 -0
  163. package/docs/docs/getting-started/ai-agents.html +130 -0
  164. package/docs/docs/getting-started/ai-agents.md +50 -0
  165. package/docs/docs/getting-started/components.html +27 -0
  166. package/docs/docs/getting-started/create-a-component.html +108 -0
  167. package/{src/docs/_getting-started → docs/docs/getting-started}/create-a-component.md +3 -6
  168. package/docs/docs/getting-started/dataFlow.html +174 -0
  169. package/{src/docs/_core-concept → docs/docs/getting-started}/dataFlow.md +18 -19
  170. package/docs/docs/getting-started/installation.html +69 -0
  171. package/docs/docs/getting-started/installation.md +36 -0
  172. package/docs/docs/getting-started/my-first-component.html +180 -0
  173. package/{src/docs/_getting-started → docs/docs/getting-started}/my-first-component.md +5 -14
  174. package/docs/docs/getting-started/start.html +47 -0
  175. package/{src/docs/_getting-started → docs/docs/getting-started}/start.md +1 -13
  176. package/docs/docs/getting-started/theming.html +334 -0
  177. package/docs/docs/index.html +99 -0
  178. package/docs/docs/misc/api-configuration.html +149 -0
  179. package/{src/docs/_misc → docs/docs/misc}/api-configuration.md +10 -12
  180. package/docs/docs/misc/dataProviderKey.html +136 -0
  181. package/{src/docs/_misc → docs/docs/misc}/dataProviderKey.md +4 -4
  182. package/docs/docs/misc/docs-mock-api.html +155 -0
  183. package/{src/docs/_misc → docs/docs/misc}/docs-mock-api.md +12 -13
  184. package/docs/docs/misc/dynamic-path.html +181 -0
  185. package/{src/docs/_misc → docs/docs/misc}/dynamic-path.md +8 -8
  186. package/docs/docs/misc/endpoint.html +51 -0
  187. package/{src/docs/_misc → docs/docs/misc}/endpoint.md +8 -8
  188. package/docs/docs/misc/html-integration.html +45 -0
  189. package/{src/docs/_misc → docs/docs/misc}/html-integration.md +4 -5
  190. package/docs/docs-mock-api-sw.js +58 -223
  191. package/docs/docs-mock-api-sw.js.map +4 -4
  192. package/docs/hubs/decorators.html +438 -0
  193. package/docs/hubs/form-components.html +404 -0
  194. package/docs/hubs/remote-data.html +367 -0
  195. package/docs/img/archive/concorde-001-2cv.webp +0 -0
  196. package/docs/img/archive/concorde-red-arrows-2002-poster.jpg +0 -0
  197. package/docs/img/archive/concorde-red-arrows-2002.webm +0 -0
  198. package/docs/img/archive/credits.json +28 -0
  199. package/docs/img/concorde/plane_01.jpg +0 -0
  200. package/docs/img/concorde/plane_02.jpg +0 -0
  201. package/docs/img/concorde/plane_03.jpg +0 -0
  202. package/docs/img/concorde/plane_04.jpg +0 -0
  203. package/docs/img/concorde/plane_05.jpg +0 -0
  204. package/docs/img/concorde/plane_06.jpg +0 -0
  205. package/docs/img/concorde/plane_07.jpg +0 -0
  206. package/docs/img/concorde/plane_08.jpg +0 -0
  207. package/docs/img/concorde/plane_09.jpg +0 -0
  208. package/docs/img/concorde/plane_10.jpg +0 -0
  209. package/docs/img/concorde/plane_11.jpg +0 -0
  210. package/docs/img/concorde/plane_12.jpg +0 -0
  211. package/docs/img/concorde/plane_13.jpg +0 -0
  212. package/docs/img/og-concorde.jpg +0 -0
  213. package/docs/index.html +184 -68
  214. package/docs/index.md +22 -0
  215. package/docs/llms-full.txt +5779 -0
  216. package/docs/llms.txt +108 -0
  217. package/docs/privacy.html +122 -0
  218. package/docs/privacy.md +32 -0
  219. package/docs/robots.txt +11 -10
  220. package/docs/sitemap.xml +243 -0
  221. package/docs/src/core/components/functional/date/date.md +150 -0
  222. package/docs/src/core/components/functional/fetch/fetch.md +108 -0
  223. package/docs/src/core/components/functional/if/if.md +34 -0
  224. package/docs/src/core/components/functional/jsonata/jsonata.md +61 -0
  225. package/docs/src/core/components/functional/list/list.md +125 -0
  226. package/docs/src/core/components/functional/mix/mix.md +46 -0
  227. package/docs/src/core/components/functional/queue/queue.md +51 -0
  228. package/docs/src/core/components/functional/router/router.md +93 -0
  229. package/docs/src/core/components/functional/sdui/component-catalog.gaps.json +511 -0
  230. package/docs/src/core/components/functional/sdui/component-catalog.json +3103 -0
  231. package/docs/src/core/components/functional/sdui/default-library.json +108 -0
  232. package/docs/src/core/components/functional/sdui/example.json +32 -0
  233. package/docs/src/core/components/functional/sdui/sdui-extension-points.md +94 -0
  234. package/docs/src/core/components/functional/sdui/sdui.md +307 -0
  235. package/docs/src/core/components/functional/states/states.md +112 -0
  236. package/docs/src/core/components/functional/submit/submit.md +106 -0
  237. package/docs/src/core/components/functional/subscriber/subscriber.md +91 -0
  238. package/docs/src/core/components/functional/translation/translation.md +38 -0
  239. package/docs/src/core/components/functional/value/value.md +47 -0
  240. package/docs/src/core/components/ui/alert/alert.md +186 -0
  241. package/docs/src/core/components/ui/alert-messages/alert-messages.md +85 -0
  242. package/docs/src/core/components/ui/badge/badge.md +181 -0
  243. package/docs/src/core/components/ui/button/button.md +216 -0
  244. package/docs/src/core/components/ui/captcha/captcha.md +56 -0
  245. package/docs/src/core/components/ui/card/card.md +215 -0
  246. package/docs/src/core/components/ui/divider/divider.md +126 -0
  247. package/docs/src/core/components/ui/form/checkbox/checkbox.md +125 -0
  248. package/docs/src/core/components/ui/form/fieldset/fieldset.md +161 -0
  249. package/docs/src/core/components/ui/form/form-actions/form-actions.md +98 -0
  250. package/docs/src/core/components/ui/form/form-layout/form-layout.md +109 -0
  251. package/docs/src/core/components/ui/form/input/input.md +142 -0
  252. package/docs/src/core/components/ui/form/radio/radio.md +78 -0
  253. package/docs/src/core/components/ui/form/select/select.md +86 -0
  254. package/docs/src/core/components/ui/form/switch/switch.md +80 -0
  255. package/docs/src/core/components/ui/form/textarea/textarea.md +82 -0
  256. package/docs/src/core/components/ui/group/group.md +77 -0
  257. package/docs/src/core/components/ui/icon/icon.md +214 -0
  258. package/docs/src/core/components/ui/icon/icons.json +1 -0
  259. package/docs/src/core/components/ui/image/image.md +167 -0
  260. package/docs/src/core/components/ui/link/link.md +81 -0
  261. package/docs/src/core/components/ui/loader/loader.md +87 -0
  262. package/docs/src/core/components/ui/menu/menu.md +370 -0
  263. package/docs/src/core/components/ui/modal/modal.md +211 -0
  264. package/docs/src/core/components/ui/pop/pop.md +216 -0
  265. package/docs/src/core/components/ui/progress/progress.md +109 -0
  266. package/docs/src/core/components/ui/table/table.md +267 -0
  267. package/docs/src/core/components/ui/theme/theme.md +97 -0
  268. package/docs/src/core/components/ui/toast/toast.md +147 -0
  269. package/docs/src/core/components/ui/tooltip/tooltip.md +89 -0
  270. package/docs/src/docs/decorators/ancestor-attribute.md +59 -0
  271. package/docs/src/docs/decorators/auto-subscribe.md +40 -0
  272. package/docs/src/docs/decorators/bind.md +76 -0
  273. package/docs/src/docs/decorators/get.md +160 -0
  274. package/docs/src/docs/decorators/handle.md +119 -0
  275. package/docs/src/docs/decorators/on-assign.md +63 -0
  276. package/docs/src/docs/decorators/patch.md +44 -0
  277. package/docs/src/docs/decorators/post.md +134 -0
  278. package/docs/src/docs/decorators/publish.md +56 -0
  279. package/docs/src/docs/decorators/put.md +51 -0
  280. package/docs/src/docs/decorators/subscribe.md +87 -0
  281. package/docs/src/docs/decorators/wait-for-ancestors.md +76 -0
  282. package/docs/src/docs/directives/sub.md +75 -0
  283. package/docs/src/docs/directives/t.md +73 -0
  284. package/docs/src/docs/getting-started/ai-agents.md +50 -0
  285. package/docs/src/docs/getting-started/components.md +5 -0
  286. package/docs/src/docs/getting-started/create-a-component.md +136 -0
  287. package/docs/src/docs/getting-started/dataFlow.md +87 -0
  288. package/docs/src/docs/getting-started/installation.md +36 -0
  289. package/docs/src/docs/getting-started/my-first-component.md +227 -0
  290. package/docs/src/docs/getting-started/start.md +35 -0
  291. package/docs/src/docs/getting-started/theming.md +253 -0
  292. package/docs/src/docs/misc/api-configuration.md +79 -0
  293. package/docs/src/docs/misc/dataProviderKey.md +168 -0
  294. package/docs/src/docs/misc/docs-mock-api.md +62 -0
  295. package/docs/src/docs/misc/dynamic-path.md +71 -0
  296. package/docs/src/docs/misc/endpoint.md +45 -0
  297. package/docs/src/docs/misc/html-integration.md +14 -0
  298. package/docs/src/docs/search/docs-search.json +10332 -0
  299. package/docs/src/tag-list.json +1 -0
  300. package/docs/src/tsconfig-model.json +23 -0
  301. package/docs/src/tsconfig.json +1359 -0
  302. package/index.html +157 -5
  303. package/package.json +8 -4
  304. package/public/docs-mock-api-sw.js +58 -223
  305. package/public/docs-mock-api-sw.js.map +4 -4
  306. package/public/img/concorde/plane_01.jpg +0 -0
  307. package/public/img/concorde/plane_02.jpg +0 -0
  308. package/public/img/concorde/plane_03.jpg +0 -0
  309. package/public/img/concorde/plane_04.jpg +0 -0
  310. package/public/img/concorde/plane_05.jpg +0 -0
  311. package/public/img/concorde/plane_06.jpg +0 -0
  312. package/public/img/concorde/plane_07.jpg +0 -0
  313. package/public/img/concorde/plane_08.jpg +0 -0
  314. package/public/img/concorde/plane_09.jpg +0 -0
  315. package/public/img/concorde/plane_10.jpg +0 -0
  316. package/public/img/concorde/plane_11.jpg +0 -0
  317. package/public/img/concorde/plane_12.jpg +0 -0
  318. package/public/img/concorde/plane_13.jpg +0 -0
  319. package/public/img/og-concorde.jpg +0 -0
  320. package/public/robots.txt +11 -10
  321. package/scripts/ai-init.mjs +104 -379
  322. package/scripts/ai-init.test.mjs +81 -239
  323. package/scripts/docs-markdown-vite-plugin.ts +43 -0
  324. package/scripts/docs-public-url.mjs +56 -0
  325. package/scripts/docs.htaccess +82 -0
  326. package/scripts/generate-cem.mjs +244 -0
  327. package/scripts/generate-cem.test.mjs +122 -0
  328. package/scripts/generate-crawl-docs.mjs +233 -118
  329. package/scripts/generate-crawl-docs.test.mjs +124 -0
  330. package/scripts/generate-sdui-catalog.mjs +11 -10
  331. package/scripts/post-build-docs.js +37 -50
  332. package/scripts/pre-publish.mjs +2 -1
  333. package/scripts/site-pages.mjs +212 -0
  334. package/scripts/site-pages.test.mjs +116 -0
  335. package/site-pages/about.md +22 -0
  336. package/site-pages/privacy.md +32 -0
  337. package/src/core/components/functional/date/date.md +91 -231
  338. package/src/core/components/functional/fetch/fetch.md +66 -83
  339. package/src/core/components/functional/if/if.md +28 -3
  340. package/src/core/components/functional/jsonata/jsonata.md +42 -37
  341. package/src/core/components/functional/list/list.md +103 -43
  342. package/src/core/components/functional/mix/mix.md +31 -26
  343. package/src/core/components/functional/queue/queue.demo.ts +10 -7
  344. package/src/core/components/functional/queue/queue.md +40 -61
  345. package/src/core/components/functional/router/router.demo.ts +16 -16
  346. package/src/core/components/functional/router/router.md +64 -65
  347. package/src/core/components/functional/sdui/component-catalog.gaps.json +1 -1
  348. package/src/core/components/functional/sdui/component-catalog.json +1 -1
  349. package/src/core/components/functional/sdui/example.json +19 -86
  350. package/src/core/components/functional/sdui/sdui-extension-points.md +1 -1
  351. package/src/core/components/functional/sdui/sdui.md +187 -358
  352. package/src/core/components/functional/states/states.demo.ts +21 -22
  353. package/src/core/components/functional/states/states.md +86 -61
  354. package/src/core/components/functional/states/states.ts +1 -1
  355. package/src/core/components/functional/submit/submit.md +64 -72
  356. package/src/core/components/functional/translation/translation.md +38 -0
  357. package/src/core/components/functional/value/value.md +34 -22
  358. package/src/core/components/ui/alert/alert.md +48 -58
  359. package/src/core/components/ui/badge/badge.md +27 -34
  360. package/src/core/components/ui/button/button.md +139 -106
  361. package/src/core/components/ui/captcha/captcha.md +17 -32
  362. package/src/core/components/ui/card/card.md +6 -6
  363. package/src/core/components/ui/divider/divider.md +8 -11
  364. package/src/core/components/ui/form/checkbox/checkbox.md +90 -42
  365. package/src/core/components/ui/form/fieldset/fieldset.md +31 -75
  366. package/src/core/components/ui/form/form-actions/form-actions.md +14 -16
  367. package/src/core/components/ui/form/form-layout/form-layout.md +19 -29
  368. package/src/core/components/ui/form/input/input.md +95 -95
  369. package/src/core/components/ui/form/radio/radio.md +55 -34
  370. package/src/core/components/ui/form/select/select.md +60 -45
  371. package/src/core/components/ui/form/switch/switch.md +57 -34
  372. package/src/core/components/ui/form/textarea/textarea.md +55 -38
  373. package/src/core/components/ui/group/group.md +35 -33
  374. package/src/core/components/ui/icon/icon.md +4 -4
  375. package/src/core/components/ui/image/image.md +41 -107
  376. package/src/core/components/ui/link/link.md +6 -6
  377. package/src/core/components/ui/loader/loader.md +30 -55
  378. package/src/core/components/ui/menu/menu.md +27 -27
  379. package/src/core/components/ui/modal/modal.md +72 -96
  380. package/src/core/components/ui/pop/pop.md +80 -158
  381. package/src/core/components/ui/progress/progress.md +2 -2
  382. package/src/core/components/ui/table/table.md +91 -255
  383. package/src/core/components/ui/theme/theme.md +11 -36
  384. package/src/core/components/ui/toast/toast.md +48 -117
  385. package/src/core/components/ui/tooltip/tooltip.md +27 -62
  386. package/src/core/decorators/subscriber/bind.ts +9 -14
  387. package/src/core/utils/LocationHandler.spec.ts +80 -0
  388. package/src/core/utils/LocationHandler.ts +5 -9
  389. package/src/docs/components/docs-demo-sources.ts +55 -140
  390. package/src/docs/components/docs-lit-demo.ts +1 -3
  391. package/src/docs/components/docs-source-link.ts +0 -82
  392. package/src/docs/decorators/ancestor-attribute.md +59 -0
  393. package/src/docs/decorators/auto-subscribe.md +40 -0
  394. package/src/docs/decorators/bind.md +76 -0
  395. package/src/docs/decorators/get.md +160 -0
  396. package/src/docs/decorators/handle.md +119 -0
  397. package/src/docs/decorators/on-assign.md +63 -0
  398. package/src/docs/decorators/patch.md +44 -0
  399. package/src/docs/decorators/post.md +134 -0
  400. package/src/docs/decorators/publish.md +56 -0
  401. package/src/docs/decorators/put.md +51 -0
  402. package/src/docs/decorators/subscribe.md +87 -0
  403. package/src/docs/decorators/wait-for-ancestors.md +76 -0
  404. package/src/docs/directives/sub.md +75 -0
  405. package/src/docs/directives/t.md +73 -0
  406. package/src/docs/docs-location.spec.ts +56 -0
  407. package/src/docs/docs-location.ts +133 -32
  408. package/src/docs/docs.ts +1 -2
  409. package/src/docs/example/decorators-demo-bind-demos.ts +83 -135
  410. package/src/docs/example/decorators-demo-geo.ts +30 -19
  411. package/src/docs/example/decorators-demo-post.ts +88 -186
  412. package/src/docs/example/decorators-demo-subscribe-publish-get-demos.ts +165 -268
  413. package/src/docs/example/decorators-demo.ts +85 -98
  414. package/src/docs/example/docs-api-config-demos.ts +19 -20
  415. package/src/docs/example/docs-flight-demos.ts +147 -0
  416. package/src/docs/example/docs-jsonata-demos.ts +52 -52
  417. package/src/docs/example/docs-list-demos.ts +43 -123
  418. package/src/docs/example/docs-provider-keys.ts +21 -28
  419. package/src/docs/example/docs-queue-demos.ts +37 -77
  420. package/src/docs/example/docs-router-demos.ts +20 -25
  421. package/src/docs/example/docs-submit-demos.ts +48 -48
  422. package/src/docs/example/docs-toggle-demos.ts +4 -3
  423. package/src/docs/getting-started/ai-agents.md +50 -0
  424. package/src/docs/getting-started/components.md +5 -0
  425. package/src/docs/getting-started/create-a-component.md +136 -0
  426. package/src/docs/getting-started/dataFlow.md +87 -0
  427. package/src/docs/getting-started/installation.md +36 -0
  428. package/src/docs/getting-started/my-first-component.md +227 -0
  429. package/src/docs/getting-started/start.md +35 -0
  430. package/src/docs/getting-started/theming.md +253 -0
  431. package/src/docs/header/header.ts +11 -6
  432. package/src/docs/home/catalog.ts +1 -1
  433. package/src/docs/home/home.ts +20 -11
  434. package/src/docs/layout.ts +12 -13
  435. package/src/docs/misc/api-configuration.md +79 -0
  436. package/src/docs/misc/dataProviderKey.md +168 -0
  437. package/src/docs/misc/docs-mock-api.md +62 -0
  438. package/src/docs/misc/dynamic-path.md +71 -0
  439. package/src/docs/misc/endpoint.md +45 -0
  440. package/src/docs/misc/html-integration.md +14 -0
  441. package/src/docs/mock-api/api-config-mock.ts +5 -0
  442. package/src/docs/mock-api/fixtures.ts +0 -278
  443. package/src/docs/mock-api/flights.ts +89 -0
  444. package/src/docs/mock-api/router.ts +3 -4
  445. package/src/docs/mock-api/urls.ts +1 -2
  446. package/src/docs/navigation/navigation.ts +82 -103
  447. package/src/docs/navigation/toc.ts +7 -4
  448. package/src/docs/search/docs-search.json +2804 -5024
  449. package/src/docs/search/markdown-renderer.ts +31 -8
  450. package/src/docs/search/page.ts +9 -6
  451. package/src/docs/search/search.ts +154 -122
  452. package/src/docs/tailwind/css/docs/content.css +4 -5
  453. package/src/tsconfig.json +11 -5
  454. package/src/tsconfig.tsbuildinfo +1 -1
  455. package/vite.config.mts +11 -2
  456. package/.agents/skills/concorde-component-docs/SKILL.md +0 -194
  457. package/ai/AGENTS.md +0 -56
  458. package/ai/cursor/rules/concorde-menu.mdc +0 -15
  459. package/ai/cursor/rules/concorde-scope.mdc +0 -14
  460. package/ai/cursor/rules/concorde-theme.mdc +0 -13
  461. package/ai/cursor/rules/concorde.mdc +0 -66
  462. package/ai/jetbrains/rules/concorde.md +0 -53
  463. package/ai/skills/concorde-get-set-dp/SKILL.md +0 -194
  464. package/ai/skills/concorde-imports/SKILL.md +0 -78
  465. package/ai/skills/concorde-menu/SKILL.md +0 -74
  466. package/ai/skills/concorde-scope/SKILL.md +0 -70
  467. package/ai/skills/concorde-theme/SKILL.md +0 -57
  468. package/docs/assets/index-CD4WyL6o.css +0 -1
  469. package/src/core/components/ui/form/input-autocomplete/input-autocomplete.md +0 -29
  470. package/src/docs/_core-concept/overview.md +0 -57
  471. package/src/docs/_core-concept/subscriber.md +0 -75
  472. package/src/docs/_decorators/ancestor-attribute.md +0 -128
  473. package/src/docs/_decorators/auto-subscribe.md +0 -202
  474. package/src/docs/_decorators/bind.md +0 -167
  475. package/src/docs/_decorators/get.md +0 -162
  476. package/src/docs/_decorators/handle.md +0 -175
  477. package/src/docs/_decorators/on-assign.md +0 -390
  478. package/src/docs/_decorators/patch.md +0 -70
  479. package/src/docs/_decorators/post.md +0 -146
  480. package/src/docs/_decorators/publish.md +0 -55
  481. package/src/docs/_decorators/put.md +0 -70
  482. package/src/docs/_decorators/subscribe.md +0 -100
  483. package/src/docs/_decorators/wait-for-ancestors.md +0 -163
  484. package/src/docs/_directives/sub.md +0 -91
  485. package/src/docs/_getting-started/ai-agents.md +0 -76
  486. package/src/docs/_getting-started/concorde-manual-install.md +0 -133
  487. package/src/docs/_getting-started/concorde-outside.md +0 -33
  488. package/src/docs/_getting-started/my-first-subscriber.md +0 -120
  489. package/src/docs/_getting-started/pubsub.md +0 -37
  490. package/src/docs/_misc/formelement-subscriber-removal.md +0 -115
  491. package/src/docs/example/docs-input-autocomplete-demos.ts +0 -110
  492. package/src/docs/example/docs-joke-demos.ts +0 -297
  493. /package/{src/docs/_getting-started → docs/docs/getting-started}/components.md +0 -0
  494. /package/{src/docs/_getting-started → docs/docs/getting-started}/theming.md +0 -0
@@ -0,0 +1,124 @@
1
+ import assert from "node:assert/strict";
2
+ import fs from "node:fs";
3
+ import os from "node:os";
4
+ import path from "path";
5
+ import test from "node:test";
6
+ import {
7
+ generateHomepageMarkdown,
8
+ generateHtaccess,
9
+ generateNotFoundHtml,
10
+ generateNotFoundMarkdown,
11
+ pagePath,
12
+ writeAgentSiteArtifacts,
13
+ } from "./generate-crawl-docs.mjs";
14
+
15
+ function stripTags(html) {
16
+ return html
17
+ .replace(/<script[\s\S]*?<\/script>/gi, " ")
18
+ .replace(/<style[\s\S]*?<\/style>/gi, " ")
19
+ .replace(/<[^>]+>/g, " ")
20
+ .replace(/\s+/g, " ")
21
+ .trim();
22
+ }
23
+
24
+ test("pagePath builds pretty public pathnames", () => {
25
+ assert.equal(
26
+ pagePath("docs/getting-started/start.md"),
27
+ "/docs/getting-started/start",
28
+ );
29
+ assert.equal(
30
+ pagePath("core/components/ui/button/button.md"),
31
+ "/core/components/ui/button",
32
+ );
33
+ assert.equal(
34
+ pagePath("core/components/functional/sdui/sdui-extension-points.md"),
35
+ "/core/components/functional/sdui/sdui-extension-points",
36
+ );
37
+ });
38
+
39
+ test("homepage Markdown meets Accept negotiation body requirements", () => {
40
+ const md = generateHomepageMarkdown();
41
+ assert.match(md, /^# Concorde by Supersoniks/m);
42
+ assert.match(md, /@supersoniks\/concorde/);
43
+ assert.match(md, /llms\.txt/);
44
+ assert.match(md, /Accept: text\/markdown/);
45
+ assert.match(md, /docs\/getting-started\/start/);
46
+ assert.doesNotMatch(md, /\/crawl\//);
47
+ assert.doesNotMatch(md, /\/docs\/_getting-started\//);
48
+ assert.ok(md.length >= 500, `expected ≥500 chars, got ${md.length}`);
49
+ });
50
+
51
+ test("404 Markdown explains the error and links agent entry points", () => {
52
+ const md = generateNotFoundMarkdown();
53
+ assert.ok(md.length >= 20);
54
+ assert.match(md, /not found/i);
55
+ assert.match(md, /llms\.txt|sitemap\.xml|docs\/index/);
56
+ assert.doesNotMatch(md, /\/crawl\//);
57
+ assert.match(md, /https:\/\/concorde\.supersoniks\.org/);
58
+ });
59
+
60
+ test("404 HTML keeps a human-readable fallback", () => {
61
+ const html = generateNotFoundHtml();
62
+ assert.match(html, /<h1>Page not found<\/h1>/);
63
+ assert.match(html, /llms\.txt/);
64
+ assert.doesNotMatch(html, /\/crawl\//);
65
+ });
66
+
67
+ test("htaccess maps components and negotiates Markdown/HTML", () => {
68
+ const conf = generateHtaccess();
69
+ assert.match(conf, /RewriteEngine On/);
70
+ assert.match(conf, /text\/markdown/);
71
+ assert.match(conf, /index\.md/);
72
+ assert.match(conf, /ErrorDocument 404 \/404\.md/);
73
+ assert.match(conf, /\$1\/\$2\/\$2\.md/);
74
+ assert.match(conf, /Googlebot/);
75
+ assert.match(conf, /index\.html \[END\]/);
76
+ assert.match(conf, /DirectorySlash Off/);
77
+ assert.doesNotMatch(conf, /docs\/_/);
78
+ assert.doesNotMatch(conf, /THE_REQUEST/);
79
+ assert.doesNotMatch(conf, /\^crawl\//);
80
+ });
81
+
82
+ test("writeAgentSiteArtifacts emits negotiation files", () => {
83
+ const dir = fs.mkdtempSync(path.join(os.tmpdir(), "concorde-agent-"));
84
+ try {
85
+ writeAgentSiteArtifacts(dir);
86
+ for (const name of ["index.md", "404.md", "404.html", ".htaccess"]) {
87
+ const filePath = path.join(dir, name);
88
+ assert.ok(fs.existsSync(filePath), `missing ${name}`);
89
+ assert.ok(fs.statSync(filePath).size > 20, `${name} too small`);
90
+ }
91
+ } finally {
92
+ fs.rmSync(dir, { recursive: true, force: true });
93
+ }
94
+ });
95
+
96
+ test("source index.html ships ≥500 chars of meaningful agent content with H1", () => {
97
+ const indexPath = path.resolve("index.html");
98
+ const html = fs.readFileSync(indexPath, "utf8");
99
+ assert.match(html, /id="docs-agent-content"/);
100
+ assert.match(html, /<h1>Concorde by Supersoniks<\/h1>/);
101
+ assert.match(html, /href="\/docs\/getting-started\/start"/);
102
+ assert.doesNotMatch(html, /\/docs\/_getting-started\//);
103
+ assert.doesNotMatch(html, /\/crawl\//);
104
+
105
+ const section = html.match(
106
+ /<section id="docs-agent-content"[^>]*>([\s\S]*?)<\/section>/,
107
+ );
108
+ assert.ok(section, "docs-agent-content section missing");
109
+ const text = stripTags(section[1]);
110
+ assert.ok(
111
+ text.length >= 500,
112
+ `agent section text expected ≥500 chars, got ${text.length}`,
113
+ );
114
+ });
115
+
116
+ test("public robots.txt allows pathnames and drops /crawl/", () => {
117
+ const robots = fs.readFileSync(path.resolve("public/robots.txt"), "utf8");
118
+ assert.match(robots, /Allow: \//);
119
+ assert.match(robots, /Allow: \/docs\//);
120
+ assert.match(robots, /Allow: \/core\//);
121
+ assert.match(robots, /Allow: \/llms\.txt/);
122
+ assert.doesNotMatch(robots, /Allow: \/crawl\//);
123
+ assert.doesNotMatch(robots, /Googlebot[\s\S]*Disallow: \//);
124
+ });
@@ -14,7 +14,7 @@ import { fileURLToPath } from "url";
14
14
  const __dirname = path.dirname(fileURLToPath(import.meta.url));
15
15
  const ROOT = path.resolve(__dirname, "..");
16
16
  const CEM_DIR = path.join(ROOT, ".tmp-cem");
17
- const CEM_PATH = path.join(CEM_DIR, "custom-elements.json");
17
+ export const CEM_PATH = path.join(CEM_DIR, "custom-elements.json");
18
18
  const OUT_CATALOG = path.join(
19
19
  ROOT,
20
20
  "src/core/components/functional/sdui/component-catalog.json"
@@ -24,7 +24,7 @@ const OUT_GAPS = path.join(
24
24
  "src/core/components/functional/sdui/component-catalog.gaps.json"
25
25
  );
26
26
 
27
- function extractTagNameFromSource(filePath) {
27
+ export function extractTagNameFromSource(filePath) {
28
28
  if (!fs.existsSync(filePath)) return undefined;
29
29
  const src = fs.readFileSync(filePath, "utf8");
30
30
  const literal = src.match(/@customElement\(\s*["'`]([^"'`]+)["'`]\s*\)/);
@@ -176,8 +176,12 @@ export function cemToCatalog(cem, { resolveTagName } = {}) {
176
176
  };
177
177
  }
178
178
 
179
- function runCem() {
179
+ export function runCem(
180
+ configPath = path.join(ROOT, "custom-elements-manifest.config.mjs"),
181
+ ) {
180
182
  fs.mkdirSync(CEM_DIR, { recursive: true });
183
+ const pkgPath = path.join(ROOT, "package.json");
184
+ const pkgBefore = fs.readFileSync(pkgPath, "utf8");
181
185
  const cemBin = path.join(
182
186
  ROOT,
183
187
  "node_modules/@custom-elements-manifest/analyzer/cem.js"
@@ -188,16 +192,13 @@ function runCem() {
188
192
  cemBin,
189
193
  "analyze",
190
194
  "--config",
191
- path.join(ROOT, "custom-elements-manifest.config.mjs"),
195
+ configPath,
192
196
  ],
193
197
  { cwd: ROOT, stdio: ["ignore", "pipe", "pipe"] }
194
198
  );
195
- // Ne pas laisser cem écrire customElements dans package.json
196
- const pkgPath = path.join(ROOT, "package.json");
197
- const pkg = JSON.parse(fs.readFileSync(pkgPath, "utf8"));
198
- if (pkg.customElements) {
199
- delete pkg.customElements;
200
- fs.writeFileSync(pkgPath, JSON.stringify(pkg, null, 2) + "\n");
199
+ // cem may rewrite package.json (customElements): keep it as it was
200
+ if (fs.readFileSync(pkgPath, "utf8") !== pkgBefore) {
201
+ fs.writeFileSync(pkgPath, pkgBefore);
201
202
  }
202
203
  }
203
204
 
@@ -1,57 +1,62 @@
1
1
  import fs from "fs";
2
2
  import path from "path";
3
3
  import { generateCrawlDocs } from "./generate-crawl-docs.mjs";
4
+ import { generateCem } from "./generate-cem.mjs";
4
5
 
5
6
  const src = path.resolve("src");
6
7
  const docs = path.resolve("docs");
7
- /**
8
- * lister les fichiers d'un répertoire de manière récursive
9
- */
8
+
10
9
  function listFiles(dir) {
11
10
  let files = [];
12
11
  let list = fs.readdirSync(dir);
13
12
  list.forEach((file) => {
14
- const path = dir + "/" + file;
15
- let stat = fs.statSync(path);
13
+ const filePath = dir + "/" + file;
14
+ let stat = fs.statSync(filePath);
16
15
  if (stat && stat.isDirectory()) {
17
- files = files.concat(listFiles(path));
16
+ files = files.concat(listFiles(filePath));
18
17
  } else {
19
- files.push(path);
18
+ files.push(filePath);
20
19
  }
21
20
  });
22
21
  return files;
23
22
  }
24
23
 
24
+ function ensureCopy(absSrc, absDest) {
25
+ fs.mkdirSync(path.dirname(absDest), { recursive: true });
26
+ fs.copyFileSync(absSrc, absDest);
27
+ }
28
+
25
29
  /**
26
- * copier toues les fichiers .md présents dans le répertpoire src et ses sous dossiers de manière récurcive vers dossier docs en respectant l'arborescence qu'il y avait dans le dossier src
27
- * il faut creer le chemin si il n'existe pas avant de copier le fichier
30
+ * Publish markdown at the public pathname (`/docs/…/page.md`, `/core/…/page.md`)
31
+ * and keep a `/src/…` copy for non-md assets (and legacy MD until 301).
28
32
  */
29
33
  function copyDocs() {
30
- let files = listFiles(src);
34
+ const files = listFiles(src);
31
35
  for (const file of files) {
32
- if (file.indexOf(".md") != -1 || file.indexOf(".json") != -1) {
33
- let idx = file.indexOf("src/");
34
- let dest = file.substring(idx);
35
- let split = dest.split("/");
36
- let dir = path.resolve(docs);
37
- for (let i = 0; i < split.length - 1; i++) {
38
- dir += "/" + split[i];
39
- if (!fs.existsSync(dir)) {
40
- fs.mkdirSync(dir);
41
- }
42
- }
43
- dir += "/" + split[split.length - 1];
44
- fs.copyFileSync(file, dir);
36
+ const isMd = /\.mdx?$/i.test(file);
37
+ const isJson = file.endsWith(".json");
38
+ if (!isMd && !isJson) continue;
39
+
40
+ const idx = file.indexOf("src/");
41
+ if (idx === -1) continue;
42
+ const underSrc = file.substring(idx); // src/docs/…/x.md
43
+ const withoutSrc = underSrc.replace(/^src\//, ""); // docs/…/x.md
44
+
45
+ // Always keep under docs/src/… (json + legacy md paths)
46
+ ensureCopy(file, path.join(docs, underSrc));
47
+
48
+ // Public MD URLs: /docs/… and /core/… (+ .md)
49
+ if (isMd && /^(docs|core)\//.test(withoutSrc)) {
50
+ ensureCopy(file, path.join(docs, withoutSrc));
45
51
  }
46
52
  }
47
53
  }
54
+
48
55
  copyDocs();
56
+ // Custom Elements Manifest, served at /custom-elements.json
57
+ fs.copyFileSync(generateCem(), path.join(docs, "custom-elements.json"));
49
58
  generateCrawlDocs();
50
59
 
51
- /**
52
- * Par rapport au projet, regarder si ../concorde_doc existe et si oui, remplacer le contenu de /concorde_doc par celui de contenu dans docs/ en dehors des fichiers spécifiques à git .git .gitignore .gitattributes)
53
- */
54
-
55
60
  function copyToConcordeDoc() {
56
61
  let concordeDoc = path.resolve("../concorde_doc");
57
62
 
@@ -60,15 +65,17 @@ function copyToConcordeDoc() {
60
65
  }
61
66
 
62
67
  try {
63
- /* first remove all files/foilders in concorde_doc except .git folder and .gitignore file */
64
68
  let files = listFiles(concordeDoc);
65
69
  for (const file of files) {
66
70
  if (file.indexOf(".git") == -1) {
67
71
  fs.unlinkSync(file);
68
72
  }
69
73
  }
74
+ const legacyCrawl = path.join(concordeDoc, "crawl");
75
+ if (fs.existsSync(legacyCrawl)) {
76
+ fs.rmSync(legacyCrawl, { recursive: true, force: true });
77
+ }
70
78
 
71
- /*then copy the new files*/
72
79
  files = listFiles(docs);
73
80
  for (const file of files) {
74
81
  let idx = file.indexOf("docs/") + 5;
@@ -95,29 +102,9 @@ function copyToConcordeDoc() {
95
102
  console.warn(
96
103
  "copyToConcordeDoc: skipped (",
97
104
  err.code || err.message,
98
- ") — docs/ and docs/crawl/ were still generated.",
105
+ ") — docs/ pathnames (HTML + MD + hubs) were still generated.",
99
106
  );
100
107
  }
101
108
  }
102
109
 
103
110
  copyToConcordeDoc();
104
-
105
- /**
106
- * dans ../concorde_doc, faire un git add, commit et push
107
- */
108
- /*
109
- function gitConcordeDoc() {
110
- let concordeDoc = path.resolve("../concorde_doc");
111
- if (fs.existsSync(concordeDoc)) {
112
- exec("cd " + concordeDoc + " && git add . && git commit -m 'update doc' && git push", (error, stdout, stderr) => {
113
- if (error) {
114
- console.error(`exec error: ${error}`);
115
- return;
116
- }
117
- console.log(`stdout: ${stdout}`);
118
- console.error(`stderr: ${stderr}`);
119
- });
120
- }
121
- }
122
-
123
- gitConcordeDoc(); */
@@ -4,8 +4,9 @@ import fs from "fs";
4
4
  const requiredFiles = [
5
5
  'concorde-core.bundle.js',
6
6
  'concorde-core.es.js',
7
- 'ai/AGENTS.md',
7
+ 'ai/skills/concorde/SKILL.md',
8
8
  'scripts/ai-init.mjs',
9
+ 'custom-elements.json',
9
10
  ];
10
11
 
11
12
  let allFilesExist = true;
@@ -0,0 +1,212 @@
1
+ /**
2
+ * Homepage JSON-LD and the root site pages (/about, /privacy).
3
+ *
4
+ * Page content lives in site-pages/*.md: the SPA renders it at /about, and
5
+ * the build publishes `slug.md` + `slug.html` (SPA shell with the page
6
+ * inlined for crawlers and link previews).
7
+ */
8
+ import fs from "fs";
9
+ import { fileURLToPath } from "url";
10
+
11
+ export const SITE_ORIGIN = "https://concorde.supersoniks.org";
12
+ export const NPM_URL = "https://www.npmjs.com/package/@supersoniks/concorde";
13
+
14
+ /** Publisher details, from https://supersoniks.com/mentions-legales */
15
+ export const ORGANIZATION = {
16
+ name: "Supersoniks",
17
+ legalName: "SUPERSONIKS",
18
+ url: "https://supersoniks.com/",
19
+ contactUrl: "https://supersoniks.com/un-projet",
20
+ telephone: "+33 2 47 68 93 25",
21
+ streetAddress: "22 rue du Docteur Bretonneau",
22
+ postalCode: "37000",
23
+ addressLocality: "Tours",
24
+ addressCountry: "FR",
25
+ sameAs: [
26
+ "https://www.linkedin.com/company/supersoniks/",
27
+ "https://www.facebook.com/supersoniks",
28
+ "https://www.instagram.com/agencesupersoniks/",
29
+ ],
30
+ };
31
+
32
+ function escapeHtml(text) {
33
+ return String(text)
34
+ .replace(/&/g, "&amp;")
35
+ .replace(/</g, "&lt;")
36
+ .replace(/>/g, "&gt;")
37
+ .replace(/"/g, "&quot;");
38
+ }
39
+
40
+ /* -------------------------------------------------------------------------- */
41
+ /* JSON-LD */
42
+ /* -------------------------------------------------------------------------- */
43
+
44
+ export function organizationJsonLd() {
45
+ return {
46
+ "@type": "Organization",
47
+ "@id": `${ORGANIZATION.url}#organization`,
48
+ name: ORGANIZATION.name,
49
+ legalName: ORGANIZATION.legalName,
50
+ url: ORGANIZATION.url,
51
+ telephone: ORGANIZATION.telephone,
52
+ address: {
53
+ "@type": "PostalAddress",
54
+ streetAddress: ORGANIZATION.streetAddress,
55
+ postalCode: ORGANIZATION.postalCode,
56
+ addressLocality: ORGANIZATION.addressLocality,
57
+ addressCountry: ORGANIZATION.addressCountry,
58
+ },
59
+ contactPoint: {
60
+ "@type": "ContactPoint",
61
+ contactType: "customer service",
62
+ telephone: ORGANIZATION.telephone,
63
+ url: ORGANIZATION.contactUrl,
64
+ availableLanguage: ["fr", "en"],
65
+ },
66
+ sameAs: ORGANIZATION.sameAs,
67
+ };
68
+ }
69
+
70
+ /** Homepage graph: WebSite + SoftwareApplication + Organization. */
71
+ export function homepageJsonLd() {
72
+ const org = { "@id": `${ORGANIZATION.url}#organization` };
73
+ return {
74
+ "@context": "https://schema.org",
75
+ "@graph": [
76
+ {
77
+ "@type": "WebSite",
78
+ "@id": `${SITE_ORIGIN}/#website`,
79
+ name: "Concorde",
80
+ alternateName: "Concorde by Supersoniks",
81
+ url: `${SITE_ORIGIN}/`,
82
+ inLanguage: "en",
83
+ publisher: org,
84
+ },
85
+ {
86
+ "@type": "SoftwareApplication",
87
+ "@id": `${SITE_ORIGIN}/#software`,
88
+ name: "Concorde",
89
+ alternateName: "@supersoniks/concorde",
90
+ description:
91
+ "Concorde is an open-source web components framework built on Lit: UI components, data binding, forms, routing helpers and theming that work in React, Vue, PHP or plain HTML.",
92
+ url: `${SITE_ORIGIN}/`,
93
+ applicationCategory: "DeveloperApplication",
94
+ applicationSubCategory: "Web components framework",
95
+ operatingSystem: "Any (web browser)",
96
+ programmingLanguage: "TypeScript",
97
+ license: "https://opensource.org/licenses/MIT",
98
+ downloadUrl: NPM_URL,
99
+ softwareHelp: `${SITE_ORIGIN}/docs/getting-started/start`,
100
+ image: `${SITE_ORIGIN}/img/og-concorde.jpg`,
101
+ offers: { "@type": "Offer", price: "0", priceCurrency: "EUR" },
102
+ author: org,
103
+ publisher: org,
104
+ sameAs: [NPM_URL],
105
+ },
106
+ organizationJsonLd(),
107
+ ],
108
+ };
109
+ }
110
+
111
+ /* -------------------------------------------------------------------------- */
112
+ /* Site pages: /about, /privacy */
113
+ /* -------------------------------------------------------------------------- */
114
+
115
+ const SITE_PAGES_DIR = fileURLToPath(new URL("../site-pages/", import.meta.url));
116
+
117
+ export const STATIC_PAGES = [
118
+ {
119
+ slug: "about",
120
+ title: "About Concorde — web components framework by Supersoniks",
121
+ description:
122
+ "Concorde is an open-source Lit web components framework designed and maintained by Supersoniks, Tours, France.",
123
+ },
124
+ {
125
+ slug: "privacy",
126
+ title: "Privacy notice — Concorde by Supersoniks",
127
+ description:
128
+ "Privacy notice of the Concorde documentation site: no cookies, no analytics, third-party hosts and your GDPR rights.",
129
+ },
130
+ ].map((page) => ({
131
+ ...page,
132
+ markdown: fs.readFileSync(`${SITE_PAGES_DIR}${page.slug}.md`, "utf8"),
133
+ }));
134
+
135
+ function pageJsonLd(page) {
136
+ return {
137
+ "@context": "https://schema.org",
138
+ "@type": page.slug === "about" ? "AboutPage" : "WebPage",
139
+ name: page.title,
140
+ description: page.description,
141
+ url: `${SITE_ORIGIN}/${page.slug}`,
142
+ isPartOf: { "@type": "WebSite", name: "Concorde", url: `${SITE_ORIGIN}/` },
143
+ publisher: organizationJsonLd(),
144
+ };
145
+ }
146
+
147
+ function replaceOnce(html, re, replacement, what) {
148
+ if (!re.test(html)) throw new Error(`site page shell: ${what} not found`);
149
+ return html.replace(re, () => replacement);
150
+ }
151
+
152
+ /**
153
+ * `slug.html`: the SPA shell (built docs/index.html) with the page's
154
+ * metadata and its rendered content in the no-JS section. Browsers boot the
155
+ * SPA, which renders the same Markdown; crawlers read the inline copy.
156
+ */
157
+ export function renderSitePage(page, bodyHtml, shellHtml) {
158
+ const url = `${SITE_ORIGIN}/${page.slug}`;
159
+ const title = escapeHtml(page.title);
160
+ const description = escapeHtml(page.description);
161
+ let html = shellHtml;
162
+ html = replaceOnce(html, /<title>[\s\S]*?<\/title>/, `<title>${title}</title>`, "title");
163
+ html = replaceOnce(
164
+ html,
165
+ /<meta\s+name="description"\s+content="[^"]*"\s*\/?>/,
166
+ `<meta name="description" content="${description}" />`,
167
+ "description",
168
+ );
169
+ html = replaceOnce(
170
+ html,
171
+ /<link rel="canonical" href="[^"]*"\s*\/?>/,
172
+ `<link rel="canonical" href="${url}" />`,
173
+ "canonical",
174
+ );
175
+ html = replaceOnce(
176
+ html,
177
+ /<link rel="alternate" type="text\/markdown" href="[^"]*"/,
178
+ `<link rel="alternate" type="text/markdown" href="/${page.slug}.md"`,
179
+ "markdown alternate",
180
+ );
181
+ html = replaceOnce(
182
+ html,
183
+ /<meta property="og:title" content="[^"]*"/,
184
+ `<meta property="og:title" content="${title}"`,
185
+ "og:title",
186
+ );
187
+ html = replaceOnce(
188
+ html,
189
+ /<meta property="og:description" content="[^"]*"/,
190
+ `<meta property="og:description" content="${description}"`,
191
+ "og:description",
192
+ );
193
+ html = replaceOnce(
194
+ html,
195
+ /<meta property="og:url" content="[^"]*"/,
196
+ `<meta property="og:url" content="${url}"`,
197
+ "og:url",
198
+ );
199
+ html = replaceOnce(
200
+ html,
201
+ /<script type="application\/ld\+json">[\s\S]*?<\/script>/,
202
+ `<script type="application/ld+json">${JSON.stringify(pageJsonLd(page))}</script>`,
203
+ "JSON-LD",
204
+ );
205
+ html = replaceOnce(
206
+ html,
207
+ /<section id="docs-agent-content"([^>]*)>[\s\S]*?<\/section>/,
208
+ `<section id="docs-agent-content" aria-hidden="true">\n${bodyHtml}\n </section>`,
209
+ "page section",
210
+ );
211
+ return html;
212
+ }
@@ -0,0 +1,116 @@
1
+ import assert from "node:assert/strict";
2
+ import fs from "node:fs";
3
+ import os from "node:os";
4
+ import path from "path";
5
+ import test from "node:test";
6
+ import { STATIC_PAGES, homepageJsonLd } from "./site-pages.mjs";
7
+ import {
8
+ generateHomepageMarkdown,
9
+ generateHtaccess,
10
+ generateSitemap,
11
+ writeAgentSiteArtifacts,
12
+ } from "./generate-crawl-docs.mjs";
13
+
14
+ function stripTags(html) {
15
+ return html
16
+ .replace(/<[^>]+>/g, " ")
17
+ .replace(/\s+/g, " ")
18
+ .trim();
19
+ }
20
+
21
+ test("homepage JSON-LD has SoftwareApplication and complete Organization", () => {
22
+ const ld = homepageJsonLd();
23
+ assert.equal(ld["@context"], "https://schema.org");
24
+ const byType = Object.fromEntries(ld["@graph"].map((n) => [n["@type"], n]));
25
+ const app = byType.SoftwareApplication;
26
+ assert.ok(app.name && app.description && app.url && app.offers);
27
+ assert.equal(app.publisher["@id"], byType.Organization["@id"]);
28
+ const org = byType.Organization;
29
+ assert.equal(org.url, "https://supersoniks.com/");
30
+ assert.equal(org.address["@type"], "PostalAddress");
31
+ assert.equal(org.address.addressLocality, "Tours");
32
+ assert.equal(org.contactPoint["@type"], "ContactPoint");
33
+ assert.ok(org.contactPoint.contactType && org.contactPoint.telephone);
34
+ assert.ok(org.sameAs.every((u) => u.startsWith("https://")));
35
+ });
36
+
37
+ test("source index.html embeds the generated JSON-LD and Open Graph tags", () => {
38
+ const html = fs.readFileSync(path.resolve("index.html"), "utf8");
39
+ const block = html.match(
40
+ /<script type="application\/ld\+json">([\s\S]*?)<\/script>/,
41
+ );
42
+ assert.ok(block, "JSON-LD script missing");
43
+ assert.deepEqual(JSON.parse(block[1]), homepageJsonLd());
44
+ for (const prop of ["og:type", "og:title", "og:description", "og:url", "og:image"]) {
45
+ assert.match(html, new RegExp(`<meta property="${prop}" content="[^"]+"`), prop);
46
+ }
47
+ assert.match(
48
+ html,
49
+ /<meta property="og:image" content="https:\/\/concorde\.supersoniks\.org\/img\/og-concorde\.jpg"/,
50
+ );
51
+ assert.ok(fs.existsSync(path.resolve("public/img/og-concorde.jpg")));
52
+ assert.match(html, /<meta name="twitter:card" content="summary_large_image"/);
53
+ assert.match(html, /href="\/about"/);
54
+ assert.match(html, /href="\/privacy"/);
55
+ });
56
+
57
+ test("site page Markdown is read from site-pages/", () => {
58
+ assert.deepEqual(
59
+ STATIC_PAGES.map((p) => p.slug),
60
+ ["about", "privacy"],
61
+ );
62
+ for (const { slug, markdown } of STATIC_PAGES) {
63
+ assert.equal(
64
+ markdown,
65
+ fs.readFileSync(path.resolve(`site-pages/${slug}.md`), "utf8"),
66
+ );
67
+ assert.match(markdown, /^# /);
68
+ }
69
+ });
70
+
71
+ test("site pages are SPA shells with their own metadata and inline content", () => {
72
+ const dir = fs.mkdtempSync(path.join(os.tmpdir(), "concorde-pages-"));
73
+ try {
74
+ writeAgentSiteArtifacts(dir);
75
+ for (const { slug } of STATIC_PAGES) {
76
+ const md = fs.readFileSync(path.join(dir, `${slug}.md`), "utf8");
77
+ const html = fs.readFileSync(path.join(dir, `${slug}.html`), "utf8");
78
+ assert.ok(md.length >= 500, `${slug}.md too short (${md.length})`);
79
+ const section = html.match(
80
+ /<section id="docs-agent-content"[^>]*>([\s\S]*?)<\/section>/,
81
+ );
82
+ assert.ok(section, `${slug}.html page section missing`);
83
+ assert.ok(stripTags(section[1]).length >= 500, `${slug}.html too short`);
84
+ assert.match(section[1], /<h1/);
85
+ assert.doesNotMatch(section[1], /<h1>Concorde by Supersoniks<\/h1>/);
86
+ assert.match(html, /<sonic-router>/, "SPA shell expected");
87
+ const url = `https://concorde\\.supersoniks\\.org/${slug}`;
88
+ assert.match(html, new RegExp(`<link rel="canonical" href="${url}" />`));
89
+ assert.match(html, new RegExp(`<meta property="og:url" content="${url}"`));
90
+ assert.match(html, new RegExp(`href="/${slug}\\.md"`));
91
+ assert.equal((html.match(/<title>/g) || []).length, 1);
92
+ const ld = JSON.parse(
93
+ html.match(/<script type="application\/ld\+json">([\s\S]*?)<\/script>/)[1],
94
+ );
95
+ assert.equal(ld.url, `https://concorde.supersoniks.org/${slug}`);
96
+ assert.equal(ld.publisher.address.addressLocality, "Tours");
97
+ }
98
+ } finally {
99
+ fs.rmSync(dir, { recursive: true, force: true });
100
+ }
101
+ });
102
+
103
+ test("sitemap and homepage Markdown link the site pages", () => {
104
+ const xml = generateSitemap([], []);
105
+ const md = generateHomepageMarkdown();
106
+ for (const slug of ["about", "privacy"]) {
107
+ assert.match(xml, new RegExp(`<loc>https://concorde\\.supersoniks\\.org/${slug}</loc>`));
108
+ assert.match(md, new RegExp(`https://concorde\\.supersoniks\\.org/${slug}\\)`));
109
+ }
110
+ });
111
+
112
+ test("htaccess serves site pages as HTML or Markdown", () => {
113
+ const conf = generateHtaccess();
114
+ assert.match(conf, /\^\(about\|privacy\)\$ \/\$1\.md \[END\]/);
115
+ assert.match(conf, /\^\(about\|privacy\)\$ \/\$1\.html \[END\]/);
116
+ });
@@ -0,0 +1,22 @@
1
+ # About Concorde
2
+
3
+ Concorde is an open-source web components framework built on [Lit](https://lit.dev). It is designed, written and maintained by [Supersoniks](https://supersoniks.com/), a company based in Tours, France, which uses it in production.
4
+
5
+ ## Why it exists
6
+
7
+ Supersoniks works on many stacks: PHP back offices, static pages, React and Vue front ends. Rewriting the same buttons, forms and data lists for each stack was slow and led to inconsistent interfaces. Concorde solves this with standard custom elements (`sonic-*`) that work the same way in any host page, plus a small data layer (DataProvider, decorators) that connects components to each other and to REST APIs without a framework.
8
+
9
+ ## What it includes
10
+
11
+ - UI components: buttons, inputs, selects, checkboxes, modals, toasts, cards, menus, tooltips and more.
12
+ - Data components: lists, queues, fetch, submit, router, states and server-driven UI from JSON.
13
+ - Lit decorators such as `@get`, `@post`, `@subscribe` and `@bind`.
14
+ - Theming through CSS custom properties, with light and dark modes.
15
+
16
+ ## Licence and distribution
17
+
18
+ Concorde is published on npm as [`@supersoniks/concorde`](https://www.npmjs.com/package/@supersoniks/concorde) under the MIT licence. This site (https://concorde.supersoniks.org) is its official documentation.
19
+
20
+ ## Publisher
21
+
22
+ Supersoniks, 22 rue du Docteur Bretonneau, 37000 Tours, France · +33 2 47 68 93 25 · [contact Supersoniks](https://supersoniks.com/un-projet). See also the [privacy notice](/privacy).