@mnaoumov/create-obsidian-plugin 1.0.2 → 1.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (683) hide show
  1. package/README.md +46 -8
  2. package/dist/main.js +1838 -1007
  3. package/package.json +15 -5
  4. package/src/main.ts +133 -25
  5. package/templates/default/{parcel-transformer-inline-imports.cjs.ejs → (bundlers)/parcel-transformer-inline-imports.cjs.ejs} +1 -1
  6. package/templates/default/{CONTRIBUTING.md.ejs → (contributing)/CONTRIBUTING.md.ejs} +1 -0
  7. package/templates/default/{CONTRIBUTING.md@demo-vault_dev-utils.ejs → (contributing)/CONTRIBUTING.md@demo-vault_framework.ejs} +1 -1
  8. package/templates/default/(contributing)/CONTRIBUTING.md@filing_bug-and-feature.ejs +6 -0
  9. package/templates/default/{.prettierignore.ejs → (format)/.prettierignore.ejs} +1 -0
  10. package/templates/default/(format)/.prettierignore@ignores_docs-showcase.ejs +3 -0
  11. package/templates/default/(format)/biome.jsonc_framework.ejs +16 -0
  12. package/templates/default/(format)/biome.jsonc_framework@excludes_docs-showcase.ejs +1 -0
  13. package/templates/default/{biome.jsonc.ejs → (format)/biome.jsonc_standalone.ejs} +1 -1
  14. package/templates/default/(format)/dprint.json_framework.ejs +10 -0
  15. package/templates/default/(format)/dprint.json_framework@excludes_docs-showcase.ejs +2 -0
  16. package/templates/default/{dprint.json_standalone.ejs → (format)/dprint.json_standalone.ejs} +1 -0
  17. package/templates/default/(format)/prettier.config.mjs_framework.ejs +3 -0
  18. package/templates/default/{cspell.json.ejs → (lint)/cspell.json.ejs} +11 -2
  19. package/templates/default/(lint)/cspell.json@ignore-paths_docs-showcase.ejs +1 -0
  20. package/templates/default/{eslint.config.mts_standalone.ejs → (lint)/eslint.config.mts_standalone.ejs} +9 -0
  21. package/templates/default/{package.json@targets_parcel.ejs → (package)/package.json@targets_parcel-targets.ejs} +0 -5
  22. package/templates/default/(package)/package.json@targets_parcel.ejs +5 -0
  23. package/templates/default/(readme)/README.md.ejs +38 -0
  24. package/templates/default/{README.md@demo-vault_dev-utils.ejs → (readme)/README.md@demo-vault_framework.ejs} +1 -1
  25. package/templates/default/(readme)/README.md@preset_docs-showcase.ejs +4 -0
  26. package/templates/default/(readme)/README.md@preset_framework.ejs +6 -0
  27. package/templates/default/(readme)/README.md@support_bug-and-feature.ejs +11 -0
  28. package/templates/default/(readme)/README.md@support_bug-and-feature@bug-report_has-bug-report-command.ejs +2 -0
  29. package/templates/default/(test)/jest.config.ts_framework.ejs +31 -0
  30. package/templates/default/{scripts/rollup.config.ts@lint-out-dir_dev-utils.ejs → (test)/jest.config.ts_framework@lint-root-dir_framework.ejs} +1 -1
  31. package/templates/default/(test)/jest.config.ts_framework@ts-jest-tsconfig_solid.ejs +8 -0
  32. package/templates/default/{jest.config.ts.ejs → (test)/jest.config.ts_standalone.ejs} +0 -1
  33. package/templates/default/{vitest.config.ts_standalone.ejs → (test)/vitest.config.ts_standalone.ejs} +11 -2
  34. package/templates/default/(test)/wdio.conf.mts.ejs +5 -0
  35. package/templates/default/{wdio.conf.ts.ejs → (test)/wdio.conf.ts.ejs} +4 -4
  36. package/templates/default/{tsconfig.json_dev-utils.ejs → (tsconfig)/(framework)/tsconfig.json_framework.ejs} +2 -2
  37. package/templates/default/(tsconfig)/(framework)/tsconfig.json_framework@exclude_docs-showcase.ejs +4 -0
  38. package/templates/default/(tsconfig)/(framework)/tsconfig.json_framework@include_wdio-obsidian.ejs +1 -0
  39. package/templates/default/(tsconfig)/(framework)/tsconfig.json_framework@types_toolkit-styles.ejs +2 -0
  40. package/templates/default/(tsconfig)/(framework)/tsconfig.json_framework@types_wasm.ejs +2 -0
  41. package/templates/default/{tsconfig.json_standalone.ejs → (tsconfig)/(standalone)/tsconfig.json_standalone.ejs} +1 -1
  42. package/templates/default/.github/ISSUE_TEMPLATE/bug_report.yml.ejs +62 -24
  43. package/templates/default/.github/ISSUE_TEMPLATE/config.yml.ejs +4 -0
  44. package/templates/default/.github/workflows/attest-release-assets.yml.ejs +1 -11
  45. package/templates/default/.github/workflows/ci.yml_framework.ejs +19 -0
  46. package/templates/default/.github/workflows/ci.yml_framework@job-permissions_measured-coverage-badge.ejs +3 -0
  47. package/templates/default/.github/workflows/ci.yml_framework@with_measured-coverage-badge.ejs +1 -0
  48. package/templates/default/.github/workflows/{ci.yml.ejs → ci.yml_standalone.ejs} +1 -1
  49. package/templates/default/.github/workflows/release.yml_framework.ejs +19 -0
  50. package/templates/default/.github/workflows/{release.yml.ejs → release.yml_standalone.ejs} +1 -1
  51. package/templates/default/.gitignore_common.ejs +1 -0
  52. package/templates/default/.gitignore_wdio-obsidian.ejs +2 -0
  53. package/templates/default/.nvmrc.ejs +1 -0
  54. package/templates/default/demo-vault/.gitignore.ejs +4 -4
  55. package/templates/default/demo-vault/00 Start.md.ejs +1 -1
  56. package/templates/default/demo-vault/01 Sample commands.md.ejs +4 -4
  57. package/templates/default/demo-vault/02 Settings.md.ejs +2 -2
  58. package/templates/default/demo-vault/03 WebAssembly.md.ejs +2 -2
  59. package/templates/default/demo-vault/README.md.ejs +1 -1
  60. package/templates/default/demo-vault/_assets/CodeScriptToolkit/demoSetup.ts.ejs +1 -1
  61. package/templates/default/demo-vault/_assets/CodeScriptToolkit/startup.ts.ejs +4 -4
  62. package/templates/default/scripts/{build.ts@bundler_cli-bundler.ejs → (build)/(cli-bundler)/build.ts@bundler_cli-bundler.ejs} +1 -1
  63. package/templates/default/scripts/{dev.ts.ejs → (build)/(dev)/dev.ts.ejs} +1 -1
  64. package/templates/default/scripts/(build)/(dev)/dev.ts@bundler_adapter-cli.ejs +6 -0
  65. package/templates/default/scripts/(build)/(dev)/dev.ts@bundler_adapter-cli@run_rollup.ejs +3 -0
  66. package/templates/default/scripts/(build)/(dev)/dev.ts@bundler_adapter-cli@run_vite.ejs +3 -0
  67. package/templates/default/scripts/(build)/(dev)/dev.ts@bundler_adapter-cli@run_webpack.ejs +3 -0
  68. package/templates/default/scripts/(build)/(dev)/dev.ts@bundler_esbuild.ejs +3 -0
  69. package/templates/default/scripts/(build)/(dev)/dev.ts@bundler_esbuild@preset_framework.ejs +5 -0
  70. package/templates/default/scripts/(build)/(dev)/dev.ts@bundler_parcel-adapter.ejs +5 -0
  71. package/templates/default/scripts/(build)/(esbuild)/build.ts@bundler_esbuild.ejs +3 -0
  72. package/templates/default/scripts/(build)/(esbuild)/build.ts@bundler_esbuild@import_tailwind.ejs +1 -0
  73. package/templates/default/scripts/(build)/(esbuild)/build.ts@bundler_esbuild@preset_framework.ejs +5 -0
  74. package/templates/default/scripts/(build)/build-clean.ts.ejs +4 -0
  75. package/templates/default/scripts/(build)/build-compile-typescript.ts.ejs +14 -0
  76. package/templates/default/scripts/(build)/build-compile.ts.ejs +4 -0
  77. package/templates/default/scripts/(build)/build-options.ts.ejs +9 -0
  78. package/templates/default/scripts/(build)/build-styles.ts.ejs +9 -0
  79. package/templates/default/scripts/{build.ts.ejs → (build)/build.ts.ejs} +2 -2
  80. package/templates/default/scripts/(build)/build.ts@bundler_adapter-cli.ejs +11 -0
  81. package/templates/default/scripts/(build)/build.ts@bundler_adapter-cli@run_rollup.ejs +1 -0
  82. package/templates/default/scripts/(build)/build.ts@bundler_adapter-cli@run_vite.ejs +1 -0
  83. package/templates/default/scripts/(build)/build.ts@bundler_adapter-cli@run_webpack.ejs +1 -0
  84. package/templates/default/scripts/(build)/build.ts@bundler_parcel-adapter.ejs +5 -0
  85. package/templates/default/scripts/(format)/format-check.ts@tool_biome-formatter.ejs +3 -0
  86. package/templates/default/scripts/(format)/format-check.ts@tool_biome-formatter@preset_framework.ejs +7 -0
  87. package/templates/default/scripts/(format)/format-check.ts@tool_dprint.ejs +3 -0
  88. package/templates/default/scripts/(format)/format-check.ts@tool_dprint@preset_framework.ejs +7 -0
  89. package/templates/default/scripts/(format)/format-check.ts@tool_prettier.ejs +3 -0
  90. package/templates/default/scripts/(format)/format-check.ts@tool_prettier@preset_framework.ejs +7 -0
  91. package/templates/default/scripts/(format)/format.ts@tool_biome-formatter.ejs +3 -0
  92. package/templates/default/scripts/(format)/format.ts@tool_biome-formatter@preset_framework.ejs +7 -0
  93. package/templates/default/scripts/(format)/format.ts@tool_dprint.ejs +3 -0
  94. package/templates/default/scripts/(format)/format.ts@tool_dprint@preset_framework.ejs +7 -0
  95. package/templates/default/scripts/(format)/format.ts@tool_prettier.ejs +3 -0
  96. package/templates/default/scripts/(format)/format.ts@tool_prettier@preset_framework.ejs +7 -0
  97. package/templates/default/scripts/(lint)/(markdown)/lint-md-fix.ts_framework.ejs +7 -0
  98. package/templates/default/scripts/(lint)/(markdown)/lint-md.ts_framework.ejs +7 -0
  99. package/templates/default/scripts/{markdownlint-cli2-config.ts_dev-utils.ejs → (lint)/(markdown)/markdownlint-cli2-config.ts_framework.ejs} +4 -4
  100. package/templates/default/scripts/{markdownlint-cli2-config.ts_standalone.ejs → (lint)/(markdown)/markdownlint-cli2-config.ts_standalone.ejs} +3 -6
  101. package/templates/default/scripts/{eslint-config.ts.ejs → (lint)/eslint-config.ts.ejs} +3 -14
  102. package/templates/default/scripts/(lint)/eslint-config.ts@ignores_docs-showcase.ejs +4 -0
  103. package/templates/default/scripts/{find-overexposed-fix.ts.ejs → (lint)/find-overexposed-fix.ts.ejs} +4 -4
  104. package/templates/default/scripts/{find-overexposed.ts.ejs → (lint)/find-overexposed.ts.ejs} +3 -3
  105. package/templates/default/scripts/{lint-fix.ts.ejs → (lint)/lint-fix.ts.ejs} +2 -2
  106. package/templates/default/scripts/(lint)/lint-fix.ts@tool_biome-linter.ejs +3 -0
  107. package/templates/default/scripts/(lint)/lint-fix.ts@tool_biome-linter@preset_framework.ejs +7 -0
  108. package/templates/default/scripts/(lint)/lint-fix.ts@tool_eslint.ejs +3 -0
  109. package/templates/default/scripts/(lint)/lint-fix.ts@tool_eslint@preset_framework.ejs +7 -0
  110. package/templates/default/scripts/{lint.ts.ejs → (lint)/lint.ts.ejs} +2 -2
  111. package/templates/default/scripts/(lint)/lint.ts@tool_biome-linter.ejs +3 -0
  112. package/templates/default/scripts/(lint)/lint.ts@tool_biome-linter@preset_framework.ejs +7 -0
  113. package/templates/default/scripts/(lint)/lint.ts@tool_eslint.ejs +3 -0
  114. package/templates/default/scripts/(lint)/lint.ts@tool_eslint@preset_framework.ejs +7 -0
  115. package/templates/default/scripts/{rollup.config.ts.ejs → (rollup)/(standalone)/rollup.config.ts_standalone.ejs} +4 -4
  116. package/templates/default/scripts/(rollup)/rollup.config.ts_framework.ejs +49 -0
  117. package/templates/default/scripts/(rollup)/rollup.config.ts_framework@import_rollup-json.ejs +1 -0
  118. package/templates/default/scripts/(rollup)/rollup.config.ts_framework@import_scss.ejs +1 -0
  119. package/templates/default/scripts/(rollup)/rollup.config.ts_framework@plugin_rollup-json.ejs +2 -0
  120. package/templates/default/scripts/(rollup)/rollup.config.ts_framework@plugin_scss.ejs +3 -0
  121. package/templates/default/scripts/(rollup)/rollup.config.ts_framework@unwrap_rollup-json.ejs +1 -0
  122. package/templates/default/scripts/(rollup)/rollup.config.ts_framework@unwrap_scss.ejs +1 -0
  123. package/templates/default/scripts/(test)/(e2e)/test-e2e.ts@tool_obsidian-test.ejs +2 -0
  124. package/templates/default/scripts/(test)/(e2e)/test-e2e.ts@tool_obsidian-test@preset_framework.ejs +4 -0
  125. package/templates/default/scripts/(test)/(e2e)/test-e2e.ts@tool_wdio-obsidian.ejs +2 -0
  126. package/templates/default/scripts/(test)/(e2e)/test-e2e.ts@tool_wdio-obsidian@preset_framework.ejs +5 -0
  127. package/templates/default/scripts/{demo-vault-global-setup.ts.ejs → (test)/(integration)/demo-vault-global-setup.ts.ejs} +7 -4
  128. package/templates/default/scripts/(test)/(integration)/test-integration-android.ts.ejs +8 -0
  129. package/templates/default/scripts/(test)/(integration)/test-integration-demo-vault.ts.ejs +8 -0
  130. package/templates/default/scripts/(test)/(integration)/test-integration-desktop-performance.ts.ejs +8 -0
  131. package/templates/default/scripts/(test)/(integration)/test-integration-desktop.ts.ejs +8 -0
  132. package/templates/default/scripts/(test)/(integration)/test-integration-no-app.ts.ejs +8 -0
  133. package/templates/default/scripts/{test-integration.ts.ejs → (test)/(integration)/test-integration.ts.ejs} +2 -2
  134. package/templates/default/scripts/{stylesheet-stub.ts.ejs → (test)/stylesheet-stub.ts.ejs} +1 -1
  135. package/templates/default/scripts/(test)/test-coverage.ts.ejs +2 -0
  136. package/templates/default/scripts/(test)/test-coverage.ts@tool_jest.ejs +5 -0
  137. package/templates/default/scripts/(test)/test-coverage.ts@tool_vitest.ejs +8 -0
  138. package/templates/default/scripts/(test)/test-watch.ts_framework@tool_jest.ejs +5 -0
  139. package/templates/default/scripts/(test)/test-watch.ts_framework@tool_vitest.ejs +8 -0
  140. package/templates/default/scripts/(test)/test.ts_framework@tool_jest.ejs +5 -0
  141. package/templates/default/scripts/(test)/test.ts_framework@tool_vitest.ejs +8 -0
  142. package/templates/default/scripts/{vitest-config.ts.ejs → (test)/vitest-config.ts.ejs} +3 -2
  143. package/templates/default/scripts/(test)/vitest-config.ts@edit-context_docs-showcase.ejs +3 -0
  144. package/templates/default/scripts/{vitest-config.ts@post-config_solid.ejs → (test)/vitest-config.ts@post-config_solid.ejs} +6 -8
  145. package/templates/default/scripts/(vite)/vite.config.ts_framework.ejs +10 -0
  146. package/templates/default/scripts/{vite.config.ts.ejs → (vite)/vite.config.ts_standalone.ejs} +5 -8
  147. package/templates/default/scripts/(webpack)/webpack.config.ts_framework.ejs +19 -0
  148. package/templates/default/scripts/(webpack)/webpack.config.ts_framework@import_scss.ejs +1 -0
  149. package/templates/default/scripts/(webpack)/webpack.config.ts_framework@plugin_scss.ejs +1 -0
  150. package/templates/default/scripts/(webpack)/webpack.config.ts_framework@rule_scss.ejs +4 -0
  151. package/templates/default/scripts/{webpack.config.ts.ejs → (webpack)/webpack.config.ts_standalone.ejs} +4 -4
  152. package/templates/default/scripts/commit.ts_framework.ejs +3 -0
  153. package/templates/default/scripts/commitlint-config.ts_framework.ejs +1 -0
  154. package/templates/default/scripts/gate.ts.ejs +3 -3
  155. package/templates/default/scripts/nano-staged-config.ts_toolkit-nano-staged.ejs +3 -0
  156. package/templates/default/scripts/prepare.ts_framework.ejs +3 -0
  157. package/templates/default/scripts/spellcheck.ts_framework.ejs +7 -0
  158. package/templates/default/scripts/{version.ts_dev-utils.ejs → version.ts_framework.ejs} +3 -3
  159. package/templates/default/scripts/version.ts_standalone.ejs +4 -4
  160. package/templates/default/src/(main)/main.ts@import_tailwind.ejs +1 -0
  161. package/templates/default/src/(main)/main.ts@import_tailwind@preset_framework.ejs +1 -0
  162. package/templates/default/src/{plugin.ts_enhanced.ejs → (plugin)/(all-in-one)/plugin.ts_all-in-one.ejs} +7 -5
  163. package/templates/default/src/(plugin)/(all-in-one)/plugin.ts_all-in-one@bug-report-handler_has-bug-report-command.ejs +7 -0
  164. package/templates/default/src/(plugin)/(all-in-one)/plugin.ts_all-in-one@bug-report-import_has-bug-report-command.ejs +1 -0
  165. package/templates/default/src/(plugin)/(all-in-one)/plugin.ts_all-in-one@import2_css-modules.ejs +1 -0
  166. package/templates/default/src/(plugin)/(all-in-one)/plugin.ts_all-in-one@import2_docs-showcase.ejs +1 -0
  167. package/templates/default/src/(plugin)/(all-in-one)/plugin.ts_all-in-one@onload_css-modules.ejs +1 -0
  168. package/templates/default/src/(plugin)/(all-in-one)/plugin.ts_all-in-one@onload_docs-showcase.ejs +3 -0
  169. package/templates/default/src/{plugin.ts_demo.ejs → (plugin)/(demo)/plugin.ts_demo.ejs} +18 -16
  170. package/templates/default/src/(plugin)/(demo)/plugin.ts_demo@bug-report-handler_has-bug-report-command.ejs +7 -0
  171. package/templates/default/src/(plugin)/(demo)/plugin.ts_demo@bug-report-import_has-bug-report-command.ejs +1 -0
  172. package/templates/default/src/(plugin)/(demo)/plugin.ts_demo@import_css-modules.ejs +1 -0
  173. package/templates/default/src/(plugin)/(demo)/plugin.ts_demo@onload_css-modules.ejs +1 -0
  174. package/templates/default/src/{plugin.ts_standalone.ejs → (plugin)/(standalone)/plugin.ts_standalone.ejs} +5 -3
  175. package/templates/default/src/(plugin)/(standalone)/plugin.ts_standalone@import_css-modules.ejs +1 -0
  176. package/templates/default/src/(plugin)/(standalone)/plugin.ts_standalone@onload_css-modules.ejs +1 -0
  177. package/templates/default/src/{plugin-settings-component.test.ts_enhanced.ejs → (settings)/plugin-settings-component.test.ts_all-in-one.ejs} +4 -4
  178. package/templates/default/src/{plugin-settings-component.test.ts_demo.ejs → (settings)/plugin-settings-component.test.ts_demo.ejs} +5 -5
  179. package/templates/default/src/{plugin-settings-component.ts_enhanced.ejs → (settings)/plugin-settings-component.ts_all-in-one.ejs} +3 -3
  180. package/templates/default/src/{plugin-settings-component.ts_demo.ejs → (settings)/plugin-settings-component.ts_demo.ejs} +9 -7
  181. package/templates/default/src/{plugin-settings-tab.ts_enhanced.ejs → (settings)/plugin-settings-tab.ts_all-in-one.ejs} +1 -1
  182. package/templates/default/src/{plugin-settings-tab.ts_demo.ejs → (settings)/plugin-settings-tab.ts_demo.ejs} +5 -5
  183. package/templates/default/src/{plugin-settings.ts_demo.ejs → (settings)/plugin-settings.ts_demo.ejs} +2 -2
  184. package/templates/default/src/demo-vault-buttons.demo-vault.integration.test.ts.ejs +2 -2
  185. package/templates/default/src/demo-vault.no-app.integration.test.ts.ejs +3 -3
  186. package/templates/default/src/docs-showcase.desktop.integration.test.ts.ejs +77 -0
  187. package/templates/default/src/editor-extensions/{sample-state-field.ts_dev-utils.ejs → sample-state-field.ts_framework.ejs} +1 -1
  188. package/templates/default/src/lit-elements/sample-lit-element.ts.ejs +1 -1
  189. package/templates/default/src/modals/sample-suggest-modal.ts.ejs +2 -2
  190. package/templates/default/src/plugin.test.ts_jest.ejs +3 -0
  191. package/templates/default/src/plugin.test.ts_jest@bug-report-import_has-bug-report-command.ejs +4 -0
  192. package/templates/default/src/plugin.test.ts_jest@bug-report-test_has-bug-report-command.ejs +16 -0
  193. package/templates/default/src/plugin.test.ts_jest@bug-report-type-import_has-bug-report-command.ejs +2 -0
  194. package/templates/default/src/plugin.test.ts_vitest.ejs +3 -0
  195. package/templates/default/src/plugin.test.ts_vitest@bug-report-import_has-bug-report-command.ejs +4 -0
  196. package/templates/default/src/plugin.test.ts_vitest@bug-report-test_has-bug-report-command.ejs +16 -0
  197. package/templates/default/src/plugin.test.ts_vitest@bug-report-type-import_has-bug-report-command.ejs +2 -0
  198. package/templates/default/src/preact-components/{sample-preact-component.tsx_dev-utils.ejs → sample-preact-component.tsx_framework.ejs} +1 -1
  199. package/templates/default/src/preact-components/sample-preact-component.tsx_standalone.ejs +1 -1
  200. package/templates/default/src/react-components/{sample-react-component.tsx_dev-utils.ejs → sample-react-component.tsx_framework.ejs} +2 -2
  201. package/templates/default/src/react-components/sample-react-component.tsx_standalone.ejs +1 -1
  202. package/templates/default/src/solid-components/{sample-solid-component.tsx_dev-utils.ejs → sample-solid-component.tsx_framework.ejs} +1 -1
  203. package/templates/default/src/solid-components/sample-solid-component.tsx_standalone.ejs +1 -1
  204. package/templates/default/src/styles/css-modules.d.ts.ejs +9 -3
  205. package/templates/default/src/styles/{main.css_dev-utils.ejs → main.css_framework.ejs} +3 -3
  206. package/templates/default/src/styles/main.module.css.ejs +4 -2
  207. package/templates/default/src/styles/{main.scss_dev-utils.ejs → main.scss_framework.ejs} +3 -3
  208. package/templates/default/src/styles/sample-css-module-command.ts.ejs +30 -0
  209. package/templates/default/src/svelte-components/sample-svelte-component.d.ts.ejs +2 -2
  210. package/templates/default/src/views/{sample-react-view.tsx_dev-utils.ejs → sample-react-view.tsx_framework.ejs} +1 -1
  211. package/templates/default/src/views/sample-view.ts.ejs +2 -1
  212. package/templates/default/src/wasm/answer.ts_wasm-adapter.ejs +18 -0
  213. package/templates/docs-showcase/files/src/docs/README.md +511 -0
  214. package/templates/docs-showcase/files/src/docs/entry.d.ts +8 -0
  215. package/templates/docs-showcase/files/src/docs/entry.js +4 -0
  216. package/templates/docs-showcase/files/src/docs/host.ts +449 -0
  217. package/templates/docs-showcase/files/src/docs/index.ts +699 -0
  218. package/templates/docs-showcase/files/src/docs/plugins/editor/communicating-with-editor-extensions/01-intro.ts +21 -0
  219. package/templates/docs-showcase/files/src/docs/plugins/editor/communicating-with-editor-extensions/03-state-field.ts +32 -0
  220. package/templates/docs-showcase/files/src/docs/plugins/editor/decorations/01-widgets.ts +23 -0
  221. package/templates/docs-showcase/files/src/docs/plugins/editor/decorations/02-widgets.ts +20 -0
  222. package/templates/docs-showcase/files/src/docs/plugins/editor/decorations/04-state-fields.ts +57 -0
  223. package/templates/docs-showcase/files/src/docs/plugins/editor/decorations/05-view-plugins.ts +79 -0
  224. package/templates/docs-showcase/files/src/docs/plugins/editor/editor/01-intro.ts +26 -0
  225. package/templates/docs-showcase/files/src/docs/plugins/editor/editor/03-replace-current-selection.ts +26 -0
  226. package/templates/docs-showcase/files/src/docs/plugins/editor/markdown-post-processing/01-intro.ts +39 -0
  227. package/templates/docs-showcase/files/src/docs/plugins/editor/state-fields/01-defining-state-effects.ts +19 -0
  228. package/templates/docs-showcase/files/src/docs/plugins/editor/state-fields/02-defining-a-state-field.ts +35 -0
  229. package/templates/docs-showcase/files/src/docs/plugins/editor/state-fields/04-dispatching-state-effects.ts +34 -0
  230. package/templates/docs-showcase/files/src/docs/plugins/editor/state-management/01-state-changes.ts +21 -0
  231. package/templates/docs-showcase/files/src/docs/plugins/editor/state-management/02-state-changes.ts +23 -0
  232. package/templates/docs-showcase/files/src/docs/plugins/editor/view-plugins/01-creating-a-view-plugin.ts +36 -0
  233. package/templates/docs-showcase/files/src/docs/plugins/events/01-intro.ts +21 -0
  234. package/templates/docs-showcase/files/src/docs/plugins/getting-started/anatomy-of-a-plugin/01-intro.ts +22 -0
  235. package/templates/docs-showcase/files/src/docs/plugins/getting-started/anatomy-of-a-plugin/02-plugin-lifecycle.ts +22 -0
  236. package/templates/docs-showcase/files/src/docs/plugins/getting-started/build-a-plugin/06-step-5-update-the-source-code.ts +19 -0
  237. package/templates/docs-showcase/files/src/docs/plugins/getting-started/build-a-plugin/07-step-5-update-the-source-code.ts +21 -0
  238. package/templates/docs-showcase/files/src/docs/plugins/getting-started/mobile-development/03-platform-specific-features.ts +25 -0
  239. package/templates/docs-showcase/files/src/docs/plugins/getting-started/use-react-in-your-plugin/03-configure-your-plugin.ts +23 -0
  240. package/templates/docs-showcase/files/src/docs/plugins/guides/build-a-bases-view/01-step-1-sample-plugin-setup.ts +18 -0
  241. package/templates/docs-showcase/files/src/docs/plugins/guides/build-a-bases-view/02-step-2-create-and-register-the-bases-vie.ts +46 -0
  242. package/templates/docs-showcase/files/src/docs/plugins/guides/build-a-bases-view/03-step-3-add-configuration.ts +40 -0
  243. package/templates/docs-showcase/files/src/docs/plugins/guides/defer-views/04-accessing-your-customview-without-reveal.ts +26 -0
  244. package/templates/docs-showcase/files/src/docs/plugins/guides/manage-plugin-lifecycle/01-overview.ts +26 -0
  245. package/templates/docs-showcase/files/src/docs/plugins/guides/manage-plugin-lifecycle/02-overview.ts +30 -0
  246. package/templates/docs-showcase/files/src/docs/plugins/guides/manage-plugin-lifecycle/03-automatic-resource-management-with-compo.ts +26 -0
  247. package/templates/docs-showcase/files/src/docs/plugins/guides/manage-plugin-lifecycle/04-registerevent-eventref.ts +22 -0
  248. package/templates/docs-showcase/files/src/docs/plugins/guides/manage-plugin-lifecycle/05-registerinterval-id.ts +21 -0
  249. package/templates/docs-showcase/files/src/docs/plugins/guides/manage-plugin-lifecycle/06-registerdomevent-el-event-handler.ts +20 -0
  250. package/templates/docs-showcase/files/src/docs/plugins/guides/manage-plugin-lifecycle/08-understanding-the-lifecycle-of-objects.ts +29 -0
  251. package/templates/docs-showcase/files/src/docs/plugins/guides/manage-plugin-lifecycle/14-componentized-modal-example.ts +37 -0
  252. package/templates/docs-showcase/files/src/docs/plugins/guides/optimize-plugin-load-time/01-option-a-check-if-the-layout-is-ready.ts +29 -0
  253. package/templates/docs-showcase/files/src/docs/plugins/guides/optimize-plugin-load-time/02-option-b-register-the-handler-once-the-l.ts +27 -0
  254. package/templates/docs-showcase/files/src/docs/plugins/guides/store-secrets/03-step-3-retrieve-the-secret-value.ts +22 -0
  255. package/templates/docs-showcase/files/src/docs/plugins/releasing/plugin-guidelines/01-use-setheading-instead-of-a-h1-h2.ts +20 -0
  256. package/templates/docs-showcase/files/src/docs/plugins/releasing/plugin-guidelines/03-clean-up-resources-when-plugin-unloads.ts +23 -0
  257. package/templates/docs-showcase/files/src/docs/plugins/releasing/plugin-guidelines/04-avoid-accessing-workspace-activeleaf-dir.ts +24 -0
  258. package/templates/docs-showcase/files/src/docs/plugins/releasing/plugin-guidelines/05-avoid-accessing-workspace-activeleaf-dir.ts +22 -0
  259. package/templates/docs-showcase/files/src/docs/plugins/releasing/plugin-guidelines/10-avoid-iterating-all-files-to-find-a-file.ts +20 -0
  260. package/templates/docs-showcase/files/src/docs/plugins/releasing/plugin-guidelines/11-avoid-iterating-all-files-to-find-a-file.ts +20 -0
  261. package/templates/docs-showcase/files/src/docs/plugins/releasing/plugin-guidelines/13-use-normalizepath-to-clean-up-user-defin.ts +18 -0
  262. package/templates/docs-showcase/files/src/docs/plugins/releasing/plugin-guidelines/15-no-hardcoded-styling.ts +21 -0
  263. package/templates/docs-showcase/files/src/docs/plugins/releasing/plugin-guidelines/16-no-hardcoded-styling.ts +19 -0
  264. package/templates/docs-showcase/files/src/docs/plugins/releasing/plugin-guidelines/17-no-hardcoded-styling.ts +14 -0
  265. package/templates/docs-showcase/files/src/docs/plugins/releasing/plugin-guidelines/18-prefer-async-await-over-promise.ts +24 -0
  266. package/templates/docs-showcase/files/src/docs/plugins/releasing/plugin-guidelines/19-prefer-async-await-over-promise.ts +27 -0
  267. package/templates/docs-showcase/files/src/docs/plugins/user-interface/commands/01-intro.ts +25 -0
  268. package/templates/docs-showcase/files/src/docs/plugins/user-interface/commands/03-editor-commands.ts +27 -0
  269. package/templates/docs-showcase/files/src/docs/plugins/user-interface/commands/05-hot-keys.ts +25 -0
  270. package/templates/docs-showcase/files/src/docs/plugins/user-interface/context-menus/01-intro.ts +41 -0
  271. package/templates/docs-showcase/files/src/docs/plugins/user-interface/html-elements/02-create-html-elements-using-createel.ts +19 -0
  272. package/templates/docs-showcase/files/src/docs/plugins/user-interface/html-elements/03-create-html-elements-using-createel.ts +21 -0
  273. package/templates/docs-showcase/files/src/docs/plugins/user-interface/html-elements/04-style-your-elements.ts +14 -0
  274. package/templates/docs-showcase/files/src/docs/plugins/user-interface/html-elements/05-style-your-elements.ts +21 -0
  275. package/templates/docs-showcase/files/src/docs/plugins/user-interface/html-elements/06-conditional-styles.ts +19 -0
  276. package/templates/docs-showcase/files/src/docs/plugins/user-interface/icons/01-use-icons.ts +20 -0
  277. package/templates/docs-showcase/files/src/docs/plugins/user-interface/icons/02-use-icons.ts +14 -0
  278. package/templates/docs-showcase/files/src/docs/plugins/user-interface/icons/03-add-your-own-icon.ts +23 -0
  279. package/templates/docs-showcase/files/src/docs/plugins/user-interface/modals/01-intro.ts +20 -0
  280. package/templates/docs-showcase/files/src/docs/plugins/user-interface/modals/02-intro.ts +26 -0
  281. package/templates/docs-showcase/files/src/docs/plugins/user-interface/modals/03-accept-user-input.ts +38 -0
  282. package/templates/docs-showcase/files/src/docs/plugins/user-interface/modals/04-accept-user-input.ts +22 -0
  283. package/templates/docs-showcase/files/src/docs/plugins/user-interface/modals/05-select-from-list-of-suggestions.ts +56 -0
  284. package/templates/docs-showcase/files/src/docs/plugins/user-interface/modals/06-approximate-string-matching-results.ts +28 -0
  285. package/templates/docs-showcase/files/src/docs/plugins/user-interface/modals/07-custom-rendering-of-fuzzy-search-results.ts +41 -0
  286. package/templates/docs-showcase/files/src/docs/plugins/user-interface/ribbon-actions/01-intro.ts +21 -0
  287. package/templates/docs-showcase/files/src/docs/plugins/user-interface/right-to-left/01-use-fallback-values-when-necessary.ts +14 -0
  288. package/templates/docs-showcase/files/src/docs/plugins/user-interface/right-to-left/02-global-selectors.ts +14 -0
  289. package/templates/docs-showcase/files/src/docs/plugins/user-interface/right-to-left/03-icons-are-mirrored-automatically.ts +14 -0
  290. package/templates/docs-showcase/files/src/docs/plugins/user-interface/settings/09-toggle.ts +20 -0
  291. package/templates/docs-showcase/files/src/docs/plugins/user-interface/settings/10-text.ts +23 -0
  292. package/templates/docs-showcase/files/src/docs/plugins/user-interface/settings/11-textarea.ts +23 -0
  293. package/templates/docs-showcase/files/src/docs/plugins/user-interface/settings/12-number.ts +23 -0
  294. package/templates/docs-showcase/files/src/docs/plugins/user-interface/settings/13-slider.ts +23 -0
  295. package/templates/docs-showcase/files/src/docs/plugins/user-interface/settings/14-dropdown.ts +28 -0
  296. package/templates/docs-showcase/files/src/docs/plugins/user-interface/settings/15-file.ts +27 -0
  297. package/templates/docs-showcase/files/src/docs/plugins/user-interface/settings/16-folder.ts +23 -0
  298. package/templates/docs-showcase/files/src/docs/plugins/user-interface/settings/17-color-picker.ts +20 -0
  299. package/templates/docs-showcase/files/src/docs/plugins/user-interface/settings/18-validating-input.ts +28 -0
  300. package/templates/docs-showcase/files/src/docs/plugins/user-interface/settings/23-groups.ts +27 -0
  301. package/templates/docs-showcase/files/src/docs/plugins/user-interface/settings/32-cleanup.ts +30 -0
  302. package/templates/docs-showcase/files/src/docs/plugins/user-interface/settings/33-no-top-level-heading.ts +27 -0
  303. package/templates/docs-showcase/files/src/docs/plugins/user-interface/settings/34-headings-only-when-there-are-multiple-se.ts +26 -0
  304. package/templates/docs-showcase/files/src/docs/plugins/user-interface/settings/36-headings.ts +20 -0
  305. package/templates/docs-showcase/files/src/docs/plugins/user-interface/settings/38-moment-format.ts +42 -0
  306. package/templates/docs-showcase/files/src/docs/plugins/user-interface/settings/39-buttons.ts +26 -0
  307. package/templates/docs-showcase/files/src/docs/plugins/user-interface/settings/40-extra-button.ts +28 -0
  308. package/templates/docs-showcase/files/src/docs/plugins/user-interface/settings/41-progress-bar.ts +23 -0
  309. package/templates/docs-showcase/files/src/docs/plugins/user-interface/status-bar/01-intro.ts +20 -0
  310. package/templates/docs-showcase/files/src/docs/plugins/user-interface/status-bar/02-intro.ts +25 -0
  311. package/templates/docs-showcase/files/src/docs/plugins/user-interface/views/01-intro.ts +39 -0
  312. package/templates/docs-showcase/files/src/docs/plugins/user-interface/workspace/05-inspect-the-workspace.ts +23 -0
  313. package/templates/docs-showcase/files/src/docs/plugins/user-interface/workspace/06-leaf-groups.ts +19 -0
  314. package/templates/docs-showcase/files/src/docs/plugins/vault/02-read-files.ts +37 -0
  315. package/templates/docs-showcase/files/src/docs/plugins/vault/03-modify-files.ts +19 -0
  316. package/templates/docs-showcase/files/src/docs/plugins/vault/04-modify-files.ts +22 -0
  317. package/templates/docs-showcase/files/src/docs/plugins/vault/05-is-it-a-file-or-folder.ts +25 -0
  318. package/templates/docs-showcase/files/src/docs/reference/css-variables/about-styling/01-for-plugins.ts +14 -0
  319. package/templates/docs-showcase/files/src/docs/reference/css-variables/about-styling/02-for-themes-and-snippets.ts +14 -0
  320. package/templates/docs-showcase/files/src/docs/reference/css-variables/publish/site-fonts/01-intro.ts +14 -0
  321. package/templates/docs-showcase/files/src/docs/reference/typescript-api/command/callback/01-example.ts +24 -0
  322. package/templates/docs-showcase/files/src/docs/reference/typescript-api/debounce/01-example.ts +24 -0
  323. package/templates/docs-showcase/files/src/docs/reference/typescript-api/vault/process/01-example.ts +22 -0
  324. package/templates/docs-showcase/files/src/docs/themes/app-themes/build-a-theme/05-step-4-change-the-font.ts +14 -0
  325. package/templates/docs-showcase/files/src/docs/themes/app-themes/build-a-theme/06-step-5-change-the-background-color.ts +14 -0
  326. package/templates/docs-showcase/files/src/docs/themes/app-themes/build-a-theme/07-step-6-change-the-input-hover-border-col.ts +14 -0
  327. package/templates/docs-showcase/files/src/docs/themes/app-themes/build-a-theme/08-step-7-discover-css-variables-in-use.ts +14 -0
  328. package/templates/docs-showcase/files/src/docs/themes/app-themes/embed-fonts-and-images-in-your-theme/02-use-data-urls.ts +14 -0
  329. package/templates/docs-showcase/files/src/docs/themes/app-themes/theme-guidelines/01-use-css-variables.ts +14 -0
  330. package/templates/docs-showcase/files/src/docs/themes/obsidian-publish-themes/best-practices-for-publish-themes/01-small-screens-and-mobile-devices.ts +14 -0
  331. package/templates/docs-showcase/files/src/docs/themes/obsidian-publish-themes/build-a-publish-theme/01-intro.ts +14 -0
  332. package/templates/docs-showcase/files/src/docs/tsconfig.json +25 -0
  333. package/templates/docs-showcase/host/entry.d.ts +8 -0
  334. package/templates/docs-showcase/host/entry.js +4 -0
  335. package/templates/docs-showcase/host/host.ts +449 -0
  336. package/templates/docs-showcase/host/tsconfig.json +25 -0
  337. package/templates/docs-showcase/snippets.json +3566 -0
  338. package/templates/official-sample/README.md +9 -0
  339. package/templates/official-sample/files/.editorconfig.vendored +11 -0
  340. package/templates/official-sample/files/.github/workflows/lint.yml.vendored +27 -0
  341. package/templates/official-sample/files/.github/workflows/release.yml.vendored +50 -0
  342. package/templates/official-sample/files/.gitignore.vendored +22 -0
  343. package/templates/official-sample/files/.npmrc.vendored +1 -0
  344. package/templates/official-sample/files/AGENTS.md.vendored +269 -0
  345. package/templates/official-sample/files/LICENSE.vendored +5 -0
  346. package/templates/official-sample/files/README.md.vendored +92 -0
  347. package/templates/official-sample/files/esbuild.config.mjs.vendored +49 -0
  348. package/templates/official-sample/files/eslint.config.mts.vendored +32 -0
  349. package/templates/official-sample/files/manifest.json.vendored +11 -0
  350. package/templates/official-sample/files/package-lock.json.vendored +5053 -0
  351. package/templates/official-sample/files/package.json.vendored +27 -0
  352. package/templates/official-sample/files/src/main.ts.vendored +114 -0
  353. package/templates/official-sample/files/src/settings.ts.vendored +38 -0
  354. package/templates/official-sample/files/styles.css.vendored +8 -0
  355. package/templates/official-sample/files/tsconfig.json.vendored +19 -0
  356. package/templates/official-sample/files/version-bump.mjs.vendored +17 -0
  357. package/templates/official-sample/files/versions.json.vendored +3 -0
  358. package/upstreams.json +35 -0
  359. package/templates/default/README.md.ejs +0 -28
  360. package/templates/default/README.md@preset_dev-utils.ejs +0 -12
  361. package/templates/default/demo-vault/Materials/01 Sample commands/Scratch note.md.ejs +0 -5
  362. package/templates/default/dprint.json_dev-utils.ejs +0 -10
  363. package/templates/default/jest.config.ts@lint-root-dir_dev-utils.ejs +0 -1
  364. package/templates/default/scripts/build-clean.ts.ejs +0 -4
  365. package/templates/default/scripts/build-compile.ts.ejs +0 -4
  366. package/templates/default/scripts/build-styles.ts.ejs +0 -12
  367. package/templates/default/scripts/build.ts@bundler_cli-bundler@import_tailwind.ejs +0 -2
  368. package/templates/default/scripts/build.ts@bundler_cli-bundler@lint-build-styles_dev-utils.ejs +0 -1
  369. package/templates/default/scripts/build.ts@bundler_esbuild.ejs +0 -3
  370. package/templates/default/scripts/build.ts@bundler_esbuild@dev-utils-pre-build_tailwind.ejs +0 -2
  371. package/templates/default/scripts/build.ts@bundler_esbuild@lint-build-styles_dev-utils.ejs +0 -1
  372. package/templates/default/scripts/build.ts@bundler_esbuild@preset_dev-utils.ejs +0 -7
  373. package/templates/default/scripts/commit.ts_dev-utils.ejs +0 -3
  374. package/templates/default/scripts/dev.ts@bundler_esbuild.ejs +0 -3
  375. package/templates/default/scripts/dev.ts@bundler_esbuild@dev-utils-pre-build_tailwind.ejs +0 -2
  376. package/templates/default/scripts/dev.ts@bundler_esbuild@lint-build-styles_dev-utils.ejs +0 -1
  377. package/templates/default/scripts/dev.ts@bundler_esbuild@preset_dev-utils.ejs +0 -7
  378. package/templates/default/scripts/esbuild-plugins.ts.ejs +0 -20
  379. package/templates/default/scripts/esbuild-plugins.ts@dev-utils-import_vue.ejs +0 -2
  380. package/templates/default/scripts/esbuild-plugins.ts@dev-utils-plugin_vue.ejs +0 -1
  381. package/templates/default/scripts/esbuild-plugins.ts@dev-utils-plugin_wasm.ejs +0 -13
  382. package/templates/default/scripts/format-check.ts@tool_dprint.ejs +0 -3
  383. package/templates/default/scripts/format-check.ts@tool_dprint@preset_dev-utils.ejs +0 -7
  384. package/templates/default/scripts/format.ts@tool_dprint.ejs +0 -3
  385. package/templates/default/scripts/format.ts@tool_dprint@preset_dev-utils.ejs +0 -7
  386. package/templates/default/scripts/lint-fix.ts@tool_eslint.ejs +0 -3
  387. package/templates/default/scripts/lint-fix.ts@tool_eslint@preset_dev-utils.ejs +0 -7
  388. package/templates/default/scripts/lint-md-fix.ts_dev-utils.ejs +0 -7
  389. package/templates/default/scripts/lint-md.ts_dev-utils.ejs +0 -7
  390. package/templates/default/scripts/lint.ts@tool_eslint.ejs +0 -3
  391. package/templates/default/scripts/lint.ts@tool_eslint@preset_dev-utils.ejs +0 -7
  392. package/templates/default/scripts/prepare.ts_dev-utils.ejs +0 -3
  393. package/templates/default/scripts/spellcheck.ts_dev-utils.ejs +0 -7
  394. package/templates/default/scripts/test-coverage.ts.ejs +0 -8
  395. package/templates/default/scripts/test-integration-android.ts.ejs +0 -8
  396. package/templates/default/scripts/test-integration-demo-vault.ts.ejs +0 -8
  397. package/templates/default/scripts/test-integration-desktop-performance.ts.ejs +0 -8
  398. package/templates/default/scripts/test-integration-desktop.ts.ejs +0 -8
  399. package/templates/default/scripts/test-integration-no-app.ts.ejs +0 -8
  400. package/templates/default/scripts/test-watch.ts_dev-utils@tool_jest.ejs +0 -13
  401. package/templates/default/scripts/test-watch.ts_dev-utils@tool_vitest.ejs +0 -8
  402. package/templates/default/scripts/test.ts_dev-utils@tool_jest.ejs +0 -13
  403. package/templates/default/scripts/test.ts_dev-utils@tool_vitest.ejs +0 -8
  404. package/templates/default/scripts/vite.config.ts@lint-empty-out-dir_dev-utils.ejs +0 -1
  405. package/templates/default/scripts/vite.config.ts@lint-out-dir_dev-utils.ejs +0 -1
  406. package/templates/default/scripts/webpack.config.ts@lint-webpack-default_dev-utils.ejs +0 -1
  407. package/templates/default/src/main.ts@import_css-modules.ejs +0 -1
  408. package/templates/default/src/views/sample-preact-view.tsx_dev-utils.ejs +0 -45
  409. package/templates/default/tsconfig.json_dev-utils@compiler-options_preact.ejs +0 -2
  410. package/templates/default/tsconfig.json_dev-utils@compiler-options_react.ejs +0 -1
  411. package/templates/default/tsconfig.json_dev-utils@compiler-options_solid.ejs +0 -2
  412. /package/templates/default/{.parcelrc.ejs → (bundlers)/.parcelrc.ejs} +0 -0
  413. /package/templates/default/{.parcelrc@transformers_svelte.ejs → (bundlers)/.parcelrc@transformers_svelte.ejs} +0 -0
  414. /package/templates/default/{babel.config.json.ejs → (bundlers)/babel.config.json.ejs} +0 -0
  415. /package/templates/default/{babel.config.mjs.ejs → (bundlers)/babel.config.mjs.ejs} +0 -0
  416. /package/templates/default/{parcel-namer-obsidian.cjs.ejs → (bundlers)/parcel-namer-obsidian.cjs.ejs} +0 -0
  417. /package/templates/default/{parcel-resolver-obsidian.cjs.ejs → (bundlers)/parcel-resolver-obsidian.cjs.ejs} +0 -0
  418. /package/templates/default/{parcel-transformer-svelte.cjs.ejs → (bundlers)/parcel-transformer-svelte.cjs.ejs} +0 -0
  419. /package/templates/default/{postcss.config.cjs.ejs → (bundlers)/postcss.config.cjs.ejs} +0 -0
  420. /package/templates/default/{rollup.config.mjs.ejs → (bundlers)/rollup.config.mjs.ejs} +0 -0
  421. /package/templates/default/{vite.config.ts.ejs → (bundlers)/vite.config.ts.ejs} +0 -0
  422. /package/templates/default/{webpack.config.ts.ejs → (bundlers)/webpack.config.ts.ejs} +0 -0
  423. /package/templates/default/{CONTRIBUTING.md@scripts_biome-formatter.ejs → (contributing)/CONTRIBUTING.md@scripts_biome-formatter.ejs} +0 -0
  424. /package/templates/default/{CONTRIBUTING.md@scripts_biome-linter.ejs → (contributing)/CONTRIBUTING.md@scripts_biome-linter.ejs} +0 -0
  425. /package/templates/default/{CONTRIBUTING.md@scripts_conventional-commits.ejs → (contributing)/CONTRIBUTING.md@scripts_conventional-commits.ejs} +0 -0
  426. /package/templates/default/{CONTRIBUTING.md@scripts_cspell.ejs → (contributing)/CONTRIBUTING.md@scripts_cspell.ejs} +0 -0
  427. /package/templates/default/{CONTRIBUTING.md@scripts_dprint.ejs → (contributing)/CONTRIBUTING.md@scripts_dprint.ejs} +0 -0
  428. /package/templates/default/{CONTRIBUTING.md@scripts_eslint.ejs → (contributing)/CONTRIBUTING.md@scripts_eslint.ejs} +0 -0
  429. /package/templates/default/{CONTRIBUTING.md@scripts_dev-utils.ejs → (contributing)/CONTRIBUTING.md@scripts_framework.ejs} +0 -0
  430. /package/templates/default/{CONTRIBUTING.md@scripts_jest.ejs → (contributing)/CONTRIBUTING.md@scripts_jest.ejs} +0 -0
  431. /package/templates/default/{CONTRIBUTING.md@scripts_markdownlint.ejs → (contributing)/CONTRIBUTING.md@scripts_markdownlint.ejs} +0 -0
  432. /package/templates/default/{CONTRIBUTING.md@scripts_prettier.ejs → (contributing)/CONTRIBUTING.md@scripts_prettier.ejs} +0 -0
  433. /package/templates/default/{CONTRIBUTING.md@scripts_vitest.ejs → (contributing)/CONTRIBUTING.md@scripts_vitest.ejs} +0 -0
  434. /package/templates/default/{prettier.config.mjs.ejs → (format)/prettier.config.mjs_standalone.ejs} +0 -0
  435. /package/templates/default/{.depcheckrc.json.ejs → (lint)/.depcheckrc.json.ejs} +0 -0
  436. /package/templates/default/{.markdownlint-cli2.mjs.ejs → (lint)/.markdownlint-cli2.mjs.ejs} +0 -0
  437. /package/templates/default/{eslint.config.mts_dev-utils.ejs → (lint)/eslint.config.mts_framework.ejs} +0 -0
  438. /package/templates/default/{eslint.config.mts_standalone@extra-files_has-e2e.ejs → (lint)/eslint.config.mts_standalone@extra-files_has-e2e.ejs} +0 -0
  439. /package/templates/default/{linkinator.config.json.ejs → (lint)/linkinator.config.json.ejs} +0 -0
  440. /package/templates/default/{.npmrc.ejs → (package)/.npmrc.ejs} +0 -0
  441. /package/templates/default/{package.json.ejs → (package)/package.json.ejs} +0 -0
  442. /package/templates/default/{pinned-versions.json.ejs → (package)/pinned-versions.json.ejs} +0 -0
  443. /package/templates/default/{pnpm-workspace.yaml.ejs → (package)/pnpm-workspace.yaml.ejs} +0 -0
  444. /package/templates/default/{README.md@support_has-funding.ejs → (readme)/README.md@support_has-funding.ejs} +0 -0
  445. /package/templates/default/{jest.config.ts@ts-jest-tsconfig_solid.ejs → (test)/jest.config.ts_standalone@ts-jest-tsconfig_solid.ejs} +0 -0
  446. /package/templates/default/{vitest.config.ts_dev-utils.ejs → (test)/vitest.config.ts_framework.ejs} +0 -0
  447. /package/templates/default/{vitest.config.ts_standalone@jsx_solid.ejs → (test)/vitest.config.ts_standalone@jsx_solid.ejs} +0 -0
  448. /package/templates/default/{tsconfig.json_dev-utils@compiler-options_i18next.ejs → (tsconfig)/(framework)/tsconfig.json_framework@compiler-options_i18next.ejs} +0 -0
  449. /package/templates/default/{tsconfig.json_dev-utils@compiler-options_lit.ejs → (tsconfig)/(framework)/tsconfig.json_framework@compiler-options_lit.ejs} +0 -0
  450. /package/templates/default/{tsconfig.json_dev-utils@include_has-e2e.ejs → (tsconfig)/(framework)/tsconfig.json_framework@include_has-e2e.ejs} +0 -0
  451. /package/templates/default/{tsconfig.json_dev-utils@include_svelte.ejs → (tsconfig)/(framework)/tsconfig.json_framework@include_svelte.ejs} +0 -0
  452. /package/templates/default/{tsconfig.json_dev-utils@include_vue.ejs → (tsconfig)/(framework)/tsconfig.json_framework@include_vue.ejs} +0 -0
  453. /package/templates/default/{tsconfig.json_dev-utils@types_jest.ejs → (tsconfig)/(framework)/tsconfig.json_framework@types_jest.ejs} +0 -0
  454. /package/templates/default/{tsconfig.json_dev-utils@types_svelte.ejs → (tsconfig)/(framework)/tsconfig.json_framework@types_svelte.ejs} +0 -0
  455. /package/templates/default/{tsconfig.json_dev-utils@types_wdio-obsidian.ejs → (tsconfig)/(framework)/tsconfig.json_framework@types_wdio-obsidian.ejs} +0 -0
  456. /package/templates/default/{tsconfig.json_dev-utils@types_with-unofficial.ejs → (tsconfig)/(framework)/tsconfig.json_framework@types_with-unofficial.ejs} +0 -0
  457. /package/templates/default/{tsconfig.json_standalone@compiler-options_i18next.ejs → (tsconfig)/(standalone)/tsconfig.json_standalone@compiler-options_i18next.ejs} +0 -0
  458. /package/templates/default/{tsconfig.json_standalone@compiler-options_lit.ejs → (tsconfig)/(standalone)/tsconfig.json_standalone@compiler-options_lit.ejs} +0 -0
  459. /package/templates/default/{tsconfig.json_standalone@compiler-options_preact.ejs → (tsconfig)/(standalone)/tsconfig.json_standalone@compiler-options_preact.ejs} +0 -0
  460. /package/templates/default/{tsconfig.json_standalone@compiler-options_react.ejs → (tsconfig)/(standalone)/tsconfig.json_standalone@compiler-options_react.ejs} +0 -0
  461. /package/templates/default/{tsconfig.json_standalone@compiler-options_solid.ejs → (tsconfig)/(standalone)/tsconfig.json_standalone@compiler-options_solid.ejs} +0 -0
  462. /package/templates/default/{tsconfig.json_standalone@include-extra_preact.ejs → (tsconfig)/(standalone)/tsconfig.json_standalone@include-extra_preact.ejs} +0 -0
  463. /package/templates/default/{tsconfig.json_standalone@include-extra_react.ejs → (tsconfig)/(standalone)/tsconfig.json_standalone@include-extra_react.ejs} +0 -0
  464. /package/templates/default/{tsconfig.json_standalone@include-extra_solid.ejs → (tsconfig)/(standalone)/tsconfig.json_standalone@include-extra_solid.ejs} +0 -0
  465. /package/templates/default/{tsconfig.json_standalone@include_has-e2e.ejs → (tsconfig)/(standalone)/tsconfig.json_standalone@include_has-e2e.ejs} +0 -0
  466. /package/templates/default/{tsconfig.json_standalone@include_svelte.ejs → (tsconfig)/(standalone)/tsconfig.json_standalone@include_svelte.ejs} +0 -0
  467. /package/templates/default/{tsconfig.json_standalone@include_vue.ejs → (tsconfig)/(standalone)/tsconfig.json_standalone@include_vue.ejs} +0 -0
  468. /package/templates/default/{tsconfig.json_standalone@types_jest.ejs → (tsconfig)/(standalone)/tsconfig.json_standalone@types_jest.ejs} +0 -0
  469. /package/templates/default/{tsconfig.json_standalone@types_svelte.ejs → (tsconfig)/(standalone)/tsconfig.json_standalone@types_svelte.ejs} +0 -0
  470. /package/templates/default/{tsconfig.json_standalone@types_wdio-obsidian.ejs → (tsconfig)/(standalone)/tsconfig.json_standalone@types_wdio-obsidian.ejs} +0 -0
  471. /package/templates/default/{tsconfig.json_standalone@types_with-unofficial.ejs → (tsconfig)/(standalone)/tsconfig.json_standalone@types_with-unofficial.ejs} +0 -0
  472. /package/templates/default/.github/workflows/{ci.yml@steps_biome-linter.ejs → ci.yml_standalone@steps_biome-linter.ejs} +0 -0
  473. /package/templates/default/.github/workflows/{ci.yml@steps_cspell.ejs → ci.yml_standalone@steps_cspell.ejs} +0 -0
  474. /package/templates/default/.github/workflows/{ci.yml@steps_dprint.ejs → ci.yml_standalone@steps_dprint.ejs} +0 -0
  475. /package/templates/default/.github/workflows/{ci.yml@steps_eslint.ejs → ci.yml_standalone@steps_eslint.ejs} +0 -0
  476. /package/templates/default/.github/workflows/{ci.yml@steps_jest.ejs → ci.yml_standalone@steps_jest.ejs} +0 -0
  477. /package/templates/default/.github/workflows/{ci.yml@steps_markdownlint.ejs → ci.yml_standalone@steps_markdownlint.ejs} +0 -0
  478. /package/templates/default/.github/workflows/{ci.yml@steps_prettier.ejs → ci.yml_standalone@steps_prettier.ejs} +0 -0
  479. /package/templates/default/.github/workflows/{ci.yml@steps_vitest.ejs → ci.yml_standalone@steps_vitest.ejs} +0 -0
  480. /package/templates/default/{.gitignore_tailwind.ejs → .gitignore_tailwind-cli.ejs} +0 -0
  481. /package/templates/default/e2e/{sample.spec.ts_obsidian-test@lint-no-void-disable_dev-utils.ejs → sample.spec.ts_obsidian-test@lint-no-void-disable_framework.ejs} +0 -0
  482. /package/templates/default/e2e/{sample.spec.ts_obsidian-test@lint-no-void-enable_dev-utils.ejs → sample.spec.ts_obsidian-test@lint-no-void-enable_framework.ejs} +0 -0
  483. /package/templates/default/scripts/{build.ts@bundler_cli-bundler@compile_svelte.ejs → (build)/(cli-bundler)/build.ts@bundler_cli-bundler@compile_svelte.ejs} +0 -0
  484. /package/templates/default/scripts/{build.ts@bundler_cli-bundler@fs-import_hot-reload-plugin.ejs → (build)/(cli-bundler)/build.ts@bundler_cli-bundler@fs-import_hot-reload-plugin.ejs} +0 -0
  485. /package/templates/default/scripts/{build.ts@bundler_cli-bundler@hot-reload_hot-reload-plugin.ejs → (build)/(cli-bundler)/build.ts@bundler_cli-bundler@hot-reload_hot-reload-plugin.ejs} +0 -0
  486. /package/templates/default/scripts/{build.ts@bundler_esbuild@import_tailwind.ejs → (build)/(cli-bundler)/build.ts@bundler_cli-bundler@import_tailwind.ejs} +0 -0
  487. /package/templates/default/scripts/{build.ts@bundler_cli-bundler@reload_obsidian-cli.ejs → (build)/(cli-bundler)/build.ts@bundler_cli-bundler@reload_obsidian-cli.ejs} +0 -0
  488. /package/templates/default/scripts/{build.ts@bundler_cli-bundler@run_parcel.ejs → (build)/(cli-bundler)/build.ts@bundler_cli-bundler@run_parcel.ejs} +0 -0
  489. /package/templates/default/scripts/{build.ts@bundler_cli-bundler@run_rollup.ejs → (build)/(cli-bundler)/build.ts@bundler_cli-bundler@run_rollup.ejs} +0 -0
  490. /package/templates/default/scripts/{build.ts@bundler_cli-bundler@run_vite.ejs → (build)/(cli-bundler)/build.ts@bundler_cli-bundler@run_vite.ejs} +0 -0
  491. /package/templates/default/scripts/{build.ts@bundler_cli-bundler@run_webpack.ejs → (build)/(cli-bundler)/build.ts@bundler_cli-bundler@run_webpack.ejs} +0 -0
  492. /package/templates/default/scripts/{dev.ts@bundler_cli-bundler.ejs → (build)/(dev)/dev.ts@bundler_cli-bundler.ejs} +0 -0
  493. /package/templates/default/scripts/{dev.ts@bundler_esbuild@preset_standalone.ejs → (build)/(dev)/dev.ts@bundler_esbuild@preset_standalone.ejs} +0 -0
  494. /package/templates/default/scripts/{build.ts@bundler_esbuild@compile_svelte.ejs → (build)/(esbuild)/build.ts@bundler_esbuild@compile_svelte.ejs} +0 -0
  495. /package/templates/default/scripts/{build.ts@bundler_esbuild@fs-import_hot-reload-plugin.ejs → (build)/(esbuild)/build.ts@bundler_esbuild@fs-import_hot-reload-plugin.ejs} +0 -0
  496. /package/templates/default/scripts/{build.ts@bundler_esbuild@hot-reload_hot-reload-plugin.ejs → (build)/(esbuild)/build.ts@bundler_esbuild@hot-reload_hot-reload-plugin.ejs} +0 -0
  497. /package/templates/default/scripts/{build.ts@bundler_esbuild@import_postcss.ejs → (build)/(esbuild)/build.ts@bundler_esbuild@import_postcss.ejs} +0 -0
  498. /package/templates/default/scripts/{build.ts@bundler_esbuild@import_scss.ejs → (build)/(esbuild)/build.ts@bundler_esbuild@import_scss.ejs} +0 -0
  499. /package/templates/default/scripts/{build.ts@bundler_esbuild@import_solid.ejs → (build)/(esbuild)/build.ts@bundler_esbuild@import_solid.ejs} +0 -0
  500. /package/templates/default/scripts/{build.ts@bundler_esbuild@import_svelte.ejs → (build)/(esbuild)/build.ts@bundler_esbuild@import_svelte.ejs} +0 -0
  501. /package/templates/default/scripts/{build.ts@bundler_esbuild@import_vue.ejs → (build)/(esbuild)/build.ts@bundler_esbuild@import_vue.ejs} +0 -0
  502. /package/templates/default/scripts/{build.ts@bundler_esbuild@options_preact.ejs → (build)/(esbuild)/build.ts@bundler_esbuild@options_preact.ejs} +0 -0
  503. /package/templates/default/scripts/{build.ts@bundler_esbuild@options_react.ejs → (build)/(esbuild)/build.ts@bundler_esbuild@options_react.ejs} +0 -0
  504. /package/templates/default/scripts/{build.ts@bundler_esbuild@options_wasm.ejs → (build)/(esbuild)/build.ts@bundler_esbuild@options_wasm.ejs} +0 -0
  505. /package/templates/default/scripts/{build.ts@bundler_esbuild@plugin_postcss.ejs → (build)/(esbuild)/build.ts@bundler_esbuild@plugin_postcss.ejs} +0 -0
  506. /package/templates/default/scripts/{build.ts@bundler_esbuild@plugin_scss.ejs → (build)/(esbuild)/build.ts@bundler_esbuild@plugin_scss.ejs} +0 -0
  507. /package/templates/default/scripts/{build.ts@bundler_esbuild@plugin_solid.ejs → (build)/(esbuild)/build.ts@bundler_esbuild@plugin_solid.ejs} +0 -0
  508. /package/templates/default/scripts/{build.ts@bundler_esbuild@plugin_svelte.ejs → (build)/(esbuild)/build.ts@bundler_esbuild@plugin_svelte.ejs} +0 -0
  509. /package/templates/default/scripts/{build.ts@bundler_esbuild@plugin_vue.ejs → (build)/(esbuild)/build.ts@bundler_esbuild@plugin_vue.ejs} +0 -0
  510. /package/templates/default/scripts/{build.ts@bundler_esbuild@preset_standalone.ejs → (build)/(esbuild)/build.ts@bundler_esbuild@preset_standalone.ejs} +0 -0
  511. /package/templates/default/scripts/{build.ts@bundler_esbuild@reload_obsidian-cli.ejs → (build)/(esbuild)/build.ts@bundler_esbuild@reload_obsidian-cli.ejs} +0 -0
  512. /package/templates/default/scripts/{format-check.ts.ejs → (format)/format-check.ts.ejs} +0 -0
  513. /package/templates/default/scripts/{format-check.ts@tool_biome-formatter.ejs → (format)/format-check.ts@tool_biome-formatter@preset_standalone.ejs} +0 -0
  514. /package/templates/default/scripts/{format-check.ts@tool_dprint@preset_standalone.ejs → (format)/format-check.ts@tool_dprint@preset_standalone.ejs} +0 -0
  515. /package/templates/default/scripts/{format-check.ts@tool_prettier.ejs → (format)/format-check.ts@tool_prettier@preset_standalone.ejs} +0 -0
  516. /package/templates/default/scripts/{format.ts.ejs → (format)/format.ts.ejs} +0 -0
  517. /package/templates/default/scripts/{format.ts@tool_biome-formatter.ejs → (format)/format.ts@tool_biome-formatter@preset_standalone.ejs} +0 -0
  518. /package/templates/default/scripts/{format.ts@tool_dprint@preset_standalone.ejs → (format)/format.ts@tool_dprint@preset_standalone.ejs} +0 -0
  519. /package/templates/default/scripts/{format.ts@tool_prettier.ejs → (format)/format.ts@tool_prettier@preset_standalone.ejs} +0 -0
  520. /package/templates/default/scripts/{prettier.config.ts.ejs → (format)/prettier.config.ts.ejs} +0 -0
  521. /package/templates/default/scripts/{lint-md-fix.ts_standalone.ejs → (lint)/(markdown)/lint-md-fix.ts_standalone.ejs} +0 -0
  522. /package/templates/default/scripts/{lint-md.ts_standalone.ejs → (lint)/(markdown)/lint-md.ts_standalone.ejs} +0 -0
  523. /package/templates/default/scripts/{eslint-config.ts@extra-files_has-e2e.ejs → (lint)/eslint-config.ts@extra-files_has-e2e.ejs} +0 -0
  524. /package/templates/default/scripts/{lint-fix.ts@tool_biome-linter.ejs → (lint)/lint-fix.ts@tool_biome-linter@preset_standalone.ejs} +0 -0
  525. /package/templates/default/scripts/{lint-fix.ts@tool_eslint@preset_standalone.ejs → (lint)/lint-fix.ts@tool_eslint@preset_standalone.ejs} +0 -0
  526. /package/templates/default/scripts/{lint.ts@tool_biome-linter.ejs → (lint)/lint.ts@tool_biome-linter@preset_standalone.ejs} +0 -0
  527. /package/templates/default/scripts/{lint.ts@tool_eslint@preset_standalone.ejs → (lint)/lint.ts@tool_eslint@preset_standalone.ejs} +0 -0
  528. /package/templates/default/scripts/{rollup.config.ts@import_rollup-babel.ejs → (rollup)/(standalone)/rollup.config.ts_standalone@import_rollup-babel.ejs} +0 -0
  529. /package/templates/default/scripts/{rollup.config.ts@import_rollup-json.ejs → (rollup)/(standalone)/rollup.config.ts_standalone@import_rollup-json.ejs} +0 -0
  530. /package/templates/default/scripts/{rollup.config.ts@import_rollup-postcss.ejs → (rollup)/(standalone)/rollup.config.ts_standalone@import_rollup-postcss.ejs} +0 -0
  531. /package/templates/default/scripts/{rollup.config.ts@import_scss.ejs → (rollup)/(standalone)/rollup.config.ts_standalone@import_scss.ejs} +0 -0
  532. /package/templates/default/scripts/{rollup.config.ts@import_svelte.ejs → (rollup)/(standalone)/rollup.config.ts_standalone@import_svelte.ejs} +0 -0
  533. /package/templates/default/scripts/{rollup.config.ts@import_vue.ejs → (rollup)/(standalone)/rollup.config.ts_standalone@import_vue.ejs} +0 -0
  534. /package/templates/default/scripts/{rollup.config.ts@import_wasm.ejs → (rollup)/(standalone)/rollup.config.ts_standalone@import_wasm.ejs} +0 -0
  535. /package/templates/default/scripts/{rollup.config.ts@post-plugin_preact.ejs → (rollup)/(standalone)/rollup.config.ts_standalone@post-plugin_preact.ejs} +0 -0
  536. /package/templates/default/scripts/{rollup.config.ts@post-plugin_react.ejs → (rollup)/(standalone)/rollup.config.ts_standalone@post-plugin_react.ejs} +0 -0
  537. /package/templates/default/scripts/{rollup.config.ts@post-plugin_rollup-json.ejs → (rollup)/(standalone)/rollup.config.ts_standalone@post-plugin_rollup-json.ejs} +0 -0
  538. /package/templates/default/scripts/{rollup.config.ts@post-plugin_rollup-postcss.ejs → (rollup)/(standalone)/rollup.config.ts_standalone@post-plugin_rollup-postcss.ejs} +0 -0
  539. /package/templates/default/scripts/{rollup.config.ts@post-plugin_scss.ejs → (rollup)/(standalone)/rollup.config.ts_standalone@post-plugin_scss.ejs} +0 -0
  540. /package/templates/default/scripts/{rollup.config.ts@post-plugin_solid.ejs → (rollup)/(standalone)/rollup.config.ts_standalone@post-plugin_solid.ejs} +0 -0
  541. /package/templates/default/scripts/{rollup.config.ts@post-plugin_wasm.ejs → (rollup)/(standalone)/rollup.config.ts_standalone@post-plugin_wasm.ejs} +0 -0
  542. /package/templates/default/scripts/{rollup.config.ts@pre-plugin_svelte.ejs → (rollup)/(standalone)/rollup.config.ts_standalone@pre-plugin_svelte.ejs} +0 -0
  543. /package/templates/default/scripts/{rollup.config.ts@pre-plugin_vue.ejs → (rollup)/(standalone)/rollup.config.ts_standalone@pre-plugin_vue.ejs} +0 -0
  544. /package/templates/default/scripts/{rollup.config.ts@unwrap_rollup-babel.ejs → (rollup)/(standalone)/rollup.config.ts_standalone@unwrap_rollup-babel.ejs} +0 -0
  545. /package/templates/default/scripts/{rollup.config.ts@unwrap_rollup-json.ejs → (rollup)/(standalone)/rollup.config.ts_standalone@unwrap_rollup-json.ejs} +0 -0
  546. /package/templates/default/scripts/{rollup.config.ts@unwrap_rollup-postcss.ejs → (rollup)/(standalone)/rollup.config.ts_standalone@unwrap_rollup-postcss.ejs} +0 -0
  547. /package/templates/default/scripts/{rollup.config.ts@unwrap_scss.ejs → (rollup)/(standalone)/rollup.config.ts_standalone@unwrap_scss.ejs} +0 -0
  548. /package/templates/default/scripts/{rollup.config.ts@unwrap_svelte.ejs → (rollup)/(standalone)/rollup.config.ts_standalone@unwrap_svelte.ejs} +0 -0
  549. /package/templates/default/scripts/{rollup.config.ts@unwrap_vue.ejs → (rollup)/(standalone)/rollup.config.ts_standalone@unwrap_vue.ejs} +0 -0
  550. /package/templates/default/scripts/{rollup.config.ts@unwrap_wasm.ejs → (rollup)/(standalone)/rollup.config.ts_standalone@unwrap_wasm.ejs} +0 -0
  551. /package/templates/default/scripts/{babel.config.ts_rollup.ejs → (rollup)/babel.config.ts_rollup.ejs} +0 -0
  552. /package/templates/default/scripts/{babel.config.ts_rollup@babel-plugin_preact.ejs → (rollup)/babel.config.ts_rollup@babel-plugin_preact.ejs} +0 -0
  553. /package/templates/default/scripts/{babel.config.ts_rollup@babel-preset_react.ejs → (rollup)/babel.config.ts_rollup@babel-preset_react.ejs} +0 -0
  554. /package/templates/default/scripts/{babel.config.ts_rollup@babel-preset_solid.ejs → (rollup)/babel.config.ts_rollup@babel-preset_solid.ejs} +0 -0
  555. /package/templates/default/scripts/{test-e2e.ts.ejs → (test)/(e2e)/test-e2e.ts.ejs} +0 -0
  556. /package/templates/default/scripts/{test-e2e.ts@tool_obsidian-test.ejs → (test)/(e2e)/test-e2e.ts@tool_obsidian-test@preset_standalone.ejs} +0 -0
  557. /package/templates/default/scripts/{test-e2e.ts@tool_wdio-obsidian.ejs → (test)/(e2e)/test-e2e.ts@tool_wdio-obsidian@preset_standalone.ejs} +0 -0
  558. /package/templates/default/scripts/{framework-component-stub.ts.ejs → (test)/framework-component-stub.ts.ejs} +0 -0
  559. /package/templates/default/scripts/{test-watch.ts_dev-utils.ejs → (test)/test-watch.ts_framework.ejs} +0 -0
  560. /package/templates/default/scripts/{test-watch.ts_standalone.ejs → (test)/test-watch.ts_standalone.ejs} +0 -0
  561. /package/templates/default/scripts/{test-watch.ts_standalone@tool_jest.ejs → (test)/test-watch.ts_standalone@tool_jest.ejs} +0 -0
  562. /package/templates/default/scripts/{test-watch.ts_standalone@tool_vitest.ejs → (test)/test-watch.ts_standalone@tool_vitest.ejs} +0 -0
  563. /package/templates/default/scripts/{test.ts_dev-utils.ejs → (test)/test.ts_framework.ejs} +0 -0
  564. /package/templates/default/scripts/{test.ts_standalone.ejs → (test)/test.ts_standalone.ejs} +0 -0
  565. /package/templates/default/scripts/{test.ts_standalone@tool_jest.ejs → (test)/test.ts_standalone@tool_jest.ejs} +0 -0
  566. /package/templates/default/scripts/{test.ts_standalone@tool_vitest.ejs → (test)/test.ts_standalone@tool_vitest.ejs} +0 -0
  567. /package/templates/default/scripts/{wasm-module-stub.ts.ejs → (test)/wasm-module-stub.ts.ejs} +0 -0
  568. /package/templates/default/scripts/{vite.config.ts@import_preact.ejs → (vite)/vite.config.ts_standalone@import_preact.ejs} +0 -0
  569. /package/templates/default/scripts/{vite.config.ts@import_react.ejs → (vite)/vite.config.ts_standalone@import_react.ejs} +0 -0
  570. /package/templates/default/scripts/{vite.config.ts@import_solid.ejs → (vite)/vite.config.ts_standalone@import_solid.ejs} +0 -0
  571. /package/templates/default/scripts/{vite.config.ts@import_svelte.ejs → (vite)/vite.config.ts_standalone@import_svelte.ejs} +0 -0
  572. /package/templates/default/scripts/{vite.config.ts@import_vue.ejs → (vite)/vite.config.ts_standalone@import_vue.ejs} +0 -0
  573. /package/templates/default/scripts/{vite.config.ts@plugin_preact.ejs → (vite)/vite.config.ts_standalone@plugin_preact.ejs} +0 -0
  574. /package/templates/default/scripts/{vite.config.ts@plugin_react.ejs → (vite)/vite.config.ts_standalone@plugin_react.ejs} +0 -0
  575. /package/templates/default/scripts/{vite.config.ts@plugin_solid.ejs → (vite)/vite.config.ts_standalone@plugin_solid.ejs} +0 -0
  576. /package/templates/default/scripts/{vite.config.ts@plugin_svelte.ejs → (vite)/vite.config.ts_standalone@plugin_svelte.ejs} +0 -0
  577. /package/templates/default/scripts/{vite.config.ts@plugin_vue.ejs → (vite)/vite.config.ts_standalone@plugin_vue.ejs} +0 -0
  578. /package/templates/default/scripts/{webpack.config.ts@import_svelte.ejs → (webpack)/webpack.config.ts_standalone@import_svelte.ejs} +0 -0
  579. /package/templates/default/scripts/{webpack.config.ts@import_vue.ejs → (webpack)/webpack.config.ts_standalone@import_vue.ejs} +0 -0
  580. /package/templates/default/scripts/{webpack.config.ts@import_webpack-css-extract.ejs → (webpack)/webpack.config.ts_standalone@import_webpack-css-extract.ejs} +0 -0
  581. /package/templates/default/scripts/{webpack.config.ts@plugin_vue.ejs → (webpack)/webpack.config.ts_standalone@plugin_vue.ejs} +0 -0
  582. /package/templates/default/scripts/{webpack.config.ts@plugin_webpack-css-extract.ejs → (webpack)/webpack.config.ts_standalone@plugin_webpack-css-extract.ejs} +0 -0
  583. /package/templates/default/scripts/{webpack.config.ts@rule_css-modules.ejs → (webpack)/webpack.config.ts_standalone@rule_css-modules.ejs} +0 -0
  584. /package/templates/default/scripts/{webpack.config.ts@rule_css.ejs → (webpack)/webpack.config.ts_standalone@rule_css.ejs} +0 -0
  585. /package/templates/default/scripts/{webpack.config.ts@rule_postcss.ejs → (webpack)/webpack.config.ts_standalone@rule_postcss.ejs} +0 -0
  586. /package/templates/default/scripts/{webpack.config.ts@rule_scss.ejs → (webpack)/webpack.config.ts_standalone@rule_scss.ejs} +0 -0
  587. /package/templates/default/scripts/{webpack.config.ts@rule_solid.ejs → (webpack)/webpack.config.ts_standalone@rule_solid.ejs} +0 -0
  588. /package/templates/default/scripts/{webpack.config.ts@rule_svelte.ejs → (webpack)/webpack.config.ts_standalone@rule_svelte.ejs} +0 -0
  589. /package/templates/default/scripts/{webpack.config.ts@rule_tailwind.ejs → (webpack)/webpack.config.ts_standalone@rule_tailwind.ejs} +0 -0
  590. /package/templates/default/scripts/{webpack.config.ts@rule_vue.ejs → (webpack)/webpack.config.ts_standalone@rule_vue.ejs} +0 -0
  591. /package/templates/default/scripts/{webpack.config.ts@rule_wasm.ejs → (webpack)/webpack.config.ts_standalone@rule_wasm.ejs} +0 -0
  592. /package/templates/default/scripts/{webpack.config.ts@ts-loader-compiler-options_vue.ejs → (webpack)/webpack.config.ts_standalone@ts-loader-compiler-options_vue.ejs} +0 -0
  593. /package/templates/default/scripts/{webpack.config.ts@ts-loader-options_vue.ejs → (webpack)/webpack.config.ts_standalone@ts-loader-options_vue.ejs} +0 -0
  594. /package/templates/default/scripts/{commitlint-config.ts.ejs → commitlint-config.ts_standalone.ejs} +0 -0
  595. /package/templates/default/scripts/{nano-staged-config.ts.ejs → nano-staged-config.ts_inline-nano-staged.ejs} +0 -0
  596. /package/templates/default/src/{main.test.ts.ejs → (main)/main.test.ts.ejs} +0 -0
  597. /package/templates/default/src/{main.test.ts@test-imports_vitest.ejs → (main)/main.test.ts@test-imports_vitest.ejs} +0 -0
  598. /package/templates/default/src/{main.ts.ejs → (main)/main.ts.ejs} +0 -0
  599. /package/templates/default/src/{main.ts@import_css.ejs → (main)/main.ts@import_css.ejs} +0 -0
  600. /package/templates/default/src/{main.ts@import_postcss.ejs → (main)/main.ts@import_postcss.ejs} +0 -0
  601. /package/templates/default/src/{main.ts@import_scss.ejs → (main)/main.ts@import_scss.ejs} +0 -0
  602. /package/templates/default/src/{main.ts@import_tailwind.ejs → (main)/main.ts@import_tailwind@preset_standalone.ejs} +0 -0
  603. /package/templates/default/src/{plugin.ts_enhanced@import2_codemirror.ejs → (plugin)/(all-in-one)/plugin.ts_all-in-one@import2_codemirror.ejs} +0 -0
  604. /package/templates/default/src/{plugin.ts_enhanced@import2_i18next.ejs → (plugin)/(all-in-one)/plugin.ts_all-in-one@import2_i18next.ejs} +0 -0
  605. /package/templates/default/src/{plugin.ts_demo@import_lit.ejs → (plugin)/(all-in-one)/plugin.ts_all-in-one@import2_lit.ejs} +0 -0
  606. /package/templates/default/src/{plugin.ts_demo@import_preact.ejs → (plugin)/(all-in-one)/plugin.ts_all-in-one@import2_preact.ejs} +0 -0
  607. /package/templates/default/src/{plugin.ts_demo@import_react.ejs → (plugin)/(all-in-one)/plugin.ts_all-in-one@import2_react.ejs} +0 -0
  608. /package/templates/default/src/{plugin.ts_demo@import_solid.ejs → (plugin)/(all-in-one)/plugin.ts_all-in-one@import2_solid.ejs} +0 -0
  609. /package/templates/default/src/{plugin.ts_demo@import_svelte.ejs → (plugin)/(all-in-one)/plugin.ts_all-in-one@import2_svelte.ejs} +0 -0
  610. /package/templates/default/src/{plugin.ts_enhanced@import2_typesafe-i18n.ejs → (plugin)/(all-in-one)/plugin.ts_all-in-one@import2_typesafe-i18n.ejs} +0 -0
  611. /package/templates/default/src/{plugin.ts_demo@import_vue.ejs → (plugin)/(all-in-one)/plugin.ts_all-in-one@import2_vue.ejs} +0 -0
  612. /package/templates/default/src/{plugin.ts_demo@import_wasm.ejs → (plugin)/(all-in-one)/plugin.ts_all-in-one@import2_wasm.ejs} +0 -0
  613. /package/templates/default/src/{plugin.ts_demo@method_ui-view.ejs → (plugin)/(all-in-one)/plugin.ts_all-in-one@method_ui-view.ejs} +0 -0
  614. /package/templates/default/src/{plugin.ts_enhanced@onload_codemirror.ejs → (plugin)/(all-in-one)/plugin.ts_all-in-one@onload_codemirror.ejs} +0 -0
  615. /package/templates/default/src/{plugin.ts_demo@onload_i18next.ejs → (plugin)/(all-in-one)/plugin.ts_all-in-one@onload_i18next.ejs} +0 -0
  616. /package/templates/default/src/{plugin.ts_demo@onload_lit.ejs → (plugin)/(all-in-one)/plugin.ts_all-in-one@onload_lit.ejs} +0 -0
  617. /package/templates/default/src/{plugin.ts_demo@onload_preact.ejs → (plugin)/(all-in-one)/plugin.ts_all-in-one@onload_preact.ejs} +0 -0
  618. /package/templates/default/src/{plugin.ts_demo@onload_react.ejs → (plugin)/(all-in-one)/plugin.ts_all-in-one@onload_react.ejs} +0 -0
  619. /package/templates/default/src/{plugin.ts_demo@onload_solid.ejs → (plugin)/(all-in-one)/plugin.ts_all-in-one@onload_solid.ejs} +0 -0
  620. /package/templates/default/src/{plugin.ts_demo@onload_svelte.ejs → (plugin)/(all-in-one)/plugin.ts_all-in-one@onload_svelte.ejs} +0 -0
  621. /package/templates/default/src/{plugin.ts_demo@onload_typesafe-i18n.ejs → (plugin)/(all-in-one)/plugin.ts_all-in-one@onload_typesafe-i18n.ejs} +0 -0
  622. /package/templates/default/src/{plugin.ts_demo@onload_vue.ejs → (plugin)/(all-in-one)/plugin.ts_all-in-one@onload_vue.ejs} +0 -0
  623. /package/templates/default/src/{plugin.ts_demo@onload_wasm.ejs → (plugin)/(all-in-one)/plugin.ts_all-in-one@onload_wasm.ejs} +0 -0
  624. /package/templates/default/src/{plugin.ts_demo@import_i18next.ejs → (plugin)/(demo)/plugin.ts_demo@import_i18next.ejs} +0 -0
  625. /package/templates/default/src/{plugin.ts_enhanced@import2_lit.ejs → (plugin)/(demo)/plugin.ts_demo@import_lit.ejs} +0 -0
  626. /package/templates/default/src/{plugin.ts_enhanced@import2_preact.ejs → (plugin)/(demo)/plugin.ts_demo@import_preact.ejs} +0 -0
  627. /package/templates/default/src/{plugin.ts_enhanced@import2_react.ejs → (plugin)/(demo)/plugin.ts_demo@import_react.ejs} +0 -0
  628. /package/templates/default/src/{plugin.ts_enhanced@import2_solid.ejs → (plugin)/(demo)/plugin.ts_demo@import_solid.ejs} +0 -0
  629. /package/templates/default/src/{plugin.ts_enhanced@import2_svelte.ejs → (plugin)/(demo)/plugin.ts_demo@import_svelte.ejs} +0 -0
  630. /package/templates/default/src/{plugin.ts_demo@import_typesafe-i18n.ejs → (plugin)/(demo)/plugin.ts_demo@import_typesafe-i18n.ejs} +0 -0
  631. /package/templates/default/src/{plugin.ts_enhanced@import2_vue.ejs → (plugin)/(demo)/plugin.ts_demo@import_vue.ejs} +0 -0
  632. /package/templates/default/src/{plugin.ts_enhanced@import2_wasm.ejs → (plugin)/(demo)/plugin.ts_demo@import_wasm.ejs} +0 -0
  633. /package/templates/default/src/{plugin.ts_enhanced@method_ui-view.ejs → (plugin)/(demo)/plugin.ts_demo@method_ui-view.ejs} +0 -0
  634. /package/templates/default/src/{plugin.ts_enhanced@onload_i18next.ejs → (plugin)/(demo)/plugin.ts_demo@onload_i18next.ejs} +0 -0
  635. /package/templates/default/src/{plugin.ts_enhanced@onload_lit.ejs → (plugin)/(demo)/plugin.ts_demo@onload_lit.ejs} +0 -0
  636. /package/templates/default/src/{plugin.ts_enhanced@onload_preact.ejs → (plugin)/(demo)/plugin.ts_demo@onload_preact.ejs} +0 -0
  637. /package/templates/default/src/{plugin.ts_enhanced@onload_react.ejs → (plugin)/(demo)/plugin.ts_demo@onload_react.ejs} +0 -0
  638. /package/templates/default/src/{plugin.ts_enhanced@onload_solid.ejs → (plugin)/(demo)/plugin.ts_demo@onload_solid.ejs} +0 -0
  639. /package/templates/default/src/{plugin.ts_enhanced@onload_svelte.ejs → (plugin)/(demo)/plugin.ts_demo@onload_svelte.ejs} +0 -0
  640. /package/templates/default/src/{plugin.ts_enhanced@onload_typesafe-i18n.ejs → (plugin)/(demo)/plugin.ts_demo@onload_typesafe-i18n.ejs} +0 -0
  641. /package/templates/default/src/{plugin.ts_enhanced@onload_vue.ejs → (plugin)/(demo)/plugin.ts_demo@onload_vue.ejs} +0 -0
  642. /package/templates/default/src/{plugin.ts_enhanced@onload_wasm.ejs → (plugin)/(demo)/plugin.ts_demo@onload_wasm.ejs} +0 -0
  643. /package/templates/default/src/{plugin.ts_standalone@import_codemirror.ejs → (plugin)/(standalone)/plugin.ts_standalone@import_codemirror.ejs} +0 -0
  644. /package/templates/default/src/{plugin.ts_standalone@import_i18next.ejs → (plugin)/(standalone)/plugin.ts_standalone@import_i18next.ejs} +0 -0
  645. /package/templates/default/src/{plugin.ts_standalone@import_lit.ejs → (plugin)/(standalone)/plugin.ts_standalone@import_lit.ejs} +0 -0
  646. /package/templates/default/src/{plugin.ts_standalone@import_preact.ejs → (plugin)/(standalone)/plugin.ts_standalone@import_preact.ejs} +0 -0
  647. /package/templates/default/src/{plugin.ts_standalone@import_react.ejs → (plugin)/(standalone)/plugin.ts_standalone@import_react.ejs} +0 -0
  648. /package/templates/default/src/{plugin.ts_standalone@import_solid.ejs → (plugin)/(standalone)/plugin.ts_standalone@import_solid.ejs} +0 -0
  649. /package/templates/default/src/{plugin.ts_standalone@import_svelte.ejs → (plugin)/(standalone)/plugin.ts_standalone@import_svelte.ejs} +0 -0
  650. /package/templates/default/src/{plugin.ts_standalone@import_typesafe-i18n.ejs → (plugin)/(standalone)/plugin.ts_standalone@import_typesafe-i18n.ejs} +0 -0
  651. /package/templates/default/src/{plugin.ts_standalone@import_vue.ejs → (plugin)/(standalone)/plugin.ts_standalone@import_vue.ejs} +0 -0
  652. /package/templates/default/src/{plugin.ts_standalone@import_wasm.ejs → (plugin)/(standalone)/plugin.ts_standalone@import_wasm.ejs} +0 -0
  653. /package/templates/default/src/{plugin.ts_standalone@method_ui-view.ejs → (plugin)/(standalone)/plugin.ts_standalone@method_ui-view.ejs} +0 -0
  654. /package/templates/default/src/{plugin.ts_standalone@onload_codemirror.ejs → (plugin)/(standalone)/plugin.ts_standalone@onload_codemirror.ejs} +0 -0
  655. /package/templates/default/src/{plugin.ts_standalone@onload_i18next.ejs → (plugin)/(standalone)/plugin.ts_standalone@onload_i18next.ejs} +0 -0
  656. /package/templates/default/src/{plugin.ts_standalone@onload_lit.ejs → (plugin)/(standalone)/plugin.ts_standalone@onload_lit.ejs} +0 -0
  657. /package/templates/default/src/{plugin.ts_standalone@onload_preact.ejs → (plugin)/(standalone)/plugin.ts_standalone@onload_preact.ejs} +0 -0
  658. /package/templates/default/src/{plugin.ts_standalone@onload_react.ejs → (plugin)/(standalone)/plugin.ts_standalone@onload_react.ejs} +0 -0
  659. /package/templates/default/src/{plugin.ts_standalone@onload_solid.ejs → (plugin)/(standalone)/plugin.ts_standalone@onload_solid.ejs} +0 -0
  660. /package/templates/default/src/{plugin.ts_standalone@onload_svelte.ejs → (plugin)/(standalone)/plugin.ts_standalone@onload_svelte.ejs} +0 -0
  661. /package/templates/default/src/{plugin.ts_standalone@onload_typesafe-i18n.ejs → (plugin)/(standalone)/plugin.ts_standalone@onload_typesafe-i18n.ejs} +0 -0
  662. /package/templates/default/src/{plugin.ts_standalone@onload_vue.ejs → (plugin)/(standalone)/plugin.ts_standalone@onload_vue.ejs} +0 -0
  663. /package/templates/default/src/{plugin.ts_standalone@onload_wasm.ejs → (plugin)/(standalone)/plugin.ts_standalone@onload_wasm.ejs} +0 -0
  664. /package/templates/default/src/{plugin-settings-component.test.ts_demo@test-imports_vitest.ejs → (settings)/plugin-settings-component.test.ts_all-in-one@test-imports_vitest.ejs} +0 -0
  665. /package/templates/default/src/{plugin-settings-component.test.ts_enhanced@test-imports_vitest.ejs → (settings)/plugin-settings-component.test.ts_demo@test-imports_vitest.ejs} +0 -0
  666. /package/templates/default/src/{plugin-settings.test.ts_demo.ejs → (settings)/plugin-settings.test.ts_demo.ejs} +0 -0
  667. /package/templates/default/src/{plugin-settings.test.ts_demo@test-imports_vitest.ejs → (settings)/plugin-settings.test.ts_demo@test-imports_vitest.ejs} +0 -0
  668. /package/templates/default/src/{plugin-settings.ts_enhanced.ejs → (settings)/plugin-settings.ts_all-in-one.ejs} +0 -0
  669. /package/templates/default/src/{settings.ts.ejs → (settings)/settings.ts.ejs} +0 -0
  670. /package/templates/default/src/styles/{main.css_dev-utils@content_tailwind.ejs → main.css_framework@content_tailwind.ejs} +0 -0
  671. /package/templates/default/src/views/{sample-lit-view.ts@lint-register-element_dev-utils.ejs → sample-lit-view.ts@lint-register-element_framework.ejs} +0 -0
  672. /package/templates/default/src/views/{sample-preact-view.tsx_standalone.ejs → sample-preact-view.tsx.ejs} +0 -0
  673. /package/templates/default/src/views/{sample-solid-view.tsx_dev-utils.ejs → sample-solid-view.tsx_framework.ejs} +0 -0
  674. /package/templates/default/src/wasm/{answer.ts_esbuild.ejs → answer.ts_wasm-esbuild.ejs} +0 -0
  675. /package/templates/default/src/wasm/{answer.ts_parcel.ejs → answer.ts_wasm-parcel.ejs} +0 -0
  676. /package/templates/default/src/wasm/{answer.ts_rollup.ejs → answer.ts_wasm-rollup.ejs} +0 -0
  677. /package/templates/default/src/wasm/{answer.ts_vite.ejs → answer.ts_wasm-vite.ejs} +0 -0
  678. /package/templates/default/src/wasm/{answer.ts_webpack.ejs → answer.ts_wasm-webpack.ejs} +0 -0
  679. /package/templates/default/src/{wasm.d.ts_esbuild.ejs → wasm.d.ts_wasm-esbuild.ejs} +0 -0
  680. /package/templates/default/src/{wasm.d.ts_parcel.ejs → wasm.d.ts_wasm-parcel.ejs} +0 -0
  681. /package/templates/default/src/{wasm.d.ts_rollup.ejs → wasm.d.ts_wasm-rollup.ejs} +0 -0
  682. /package/templates/default/src/{wasm.d.ts_vite.ejs → wasm.d.ts_wasm-vite.ejs} +0 -0
  683. /package/templates/default/src/{wasm.d.ts_webpack.ejs → wasm.d.ts_wasm-webpack.ejs} +0 -0
package/dist/main.js CHANGED
@@ -5,7 +5,7 @@ import {
5
5
  cancel as cancel3,
6
6
  confirm,
7
7
  intro,
8
- log as log4,
8
+ log as log5,
9
9
  note,
10
10
  outro,
11
11
  select as select2,
@@ -15,23 +15,17 @@ import {
15
15
  import { spawn } from "node:child_process";
16
16
  import {
17
17
  chmodSync,
18
- existsSync as existsSync6,
19
- readFileSync as readFileSync6,
18
+ existsSync as existsSync8,
19
+ readFileSync as readFileSync8,
20
20
  writeFileSync as writeFileSync2
21
21
  } from "node:fs";
22
22
  import {
23
- join as join5,
23
+ join as join9,
24
24
  resolve as resolvePath
25
25
  } from "node:path";
26
26
  import { compare } from "semver";
27
27
 
28
- // src/cli-args.ts
29
- import {
30
- existsSync,
31
- readFileSync
32
- } from "node:fs";
33
-
34
- // src/clack-select.ts
28
+ // src/prompts/clack-select.ts
35
29
  import {
36
30
  SelectPrompt,
37
31
  settings
@@ -41,11 +35,11 @@ import {
41
35
  S_BAR_END,
42
36
  S_RADIO_ACTIVE,
43
37
  S_RADIO_INACTIVE,
44
- symbol
38
+ symbol as $symbol
45
39
  } from "@clack/prompts";
46
40
  import { styleText } from "node:util";
47
41
 
48
- // src/clack-utils.ts
42
+ // src/prompts/clack-utils.ts
49
43
  import {
50
44
  cancel,
51
45
  isCancel
@@ -80,14 +74,14 @@ function throwGoBackOnCancel(value) {
80
74
  return value;
81
75
  }
82
76
 
83
- // src/clack-select.ts
77
+ // src/prompts/clack-select.ts
84
78
  async function select(opts) {
85
79
  const selectOpts = {
86
80
  options: opts.options,
87
81
  render() {
88
82
  const withGuide = settings.withGuide;
89
83
  const header = `${withGuide ? `${styleText("gray", S_BAR)}
90
- ` : ""}${symbol(this.state)} ${opts.message}
84
+ ` : ""}${$symbol(this.state)} ${opts.message}
91
85
  `;
92
86
  const selected = this.options[this.cursor];
93
87
  switch (this.state) {
@@ -168,309 +162,173 @@ function resolveFeature(options, value) {
168
162
  return option;
169
163
  }
170
164
 
171
- // src/features/api-subset/official.ts
172
- var Official = class extends FeatureOption {
173
- constructor() {
174
- super({ promptHint: "Stable, documented API only", promptLabel: "Official API", settingValue: "official" });
175
- }
176
- };
177
-
178
- // src/features/api-subset/with-unofficial.ts
179
- var WithUnofficial = class extends FeatureOption {
165
+ // src/features/preset/official-sample.ts
166
+ var OFFICIAL_SAMPLE_PRESET = "official-sample";
167
+ var OFFICIAL_SAMPLE_ANSWER_KEYS = [
168
+ "authorGitHubName",
169
+ "authorName",
170
+ "defaultBranch",
171
+ "fundingPlatform",
172
+ "fundingUrl",
173
+ "fundingUsername",
174
+ "pluginDescription",
175
+ "pluginId",
176
+ "pluginName",
177
+ "preset"
178
+ ];
179
+ var OfficialSample = class extends FeatureOption {
180
180
  constructor() {
181
- super({ promptHint: "Includes internal undocumented APIs (for experienced devs)", promptLabel: "Official + Unofficial", settingValue: "with-unofficial" });
182
- }
183
- configure(builder) {
184
- builder.addPackage("@obsidian-typings/obsidian-public-latest");
181
+ super({
182
+ promptHint: "Exactly obsidianmd/obsidian-sample-plugin, with your plugin's id, name, author and description filled in",
183
+ promptLabel: "Official sample plugin",
184
+ settingValue: OFFICIAL_SAMPLE_PRESET
185
+ });
185
186
  }
186
187
  };
187
-
188
- // src/features/api-subset/index.ts
189
- var API_SUBSET_OPTIONS = [new Official(), new WithUnofficial()];
190
- async function promptApiSubset(savedValue) {
191
- return promptFeature({ defaultOption: new Official(), message: "Obsidian API subset", options: API_SUBSET_OPTIONS, savedValue });
188
+ function isOfficialSamplePreset(preset) {
189
+ return preset === OFFICIAL_SAMPLE_PRESET;
192
190
  }
193
191
 
194
- // src/features/preset/is-dev-utils-preset.ts
195
- var DEV_UTILS_PRESETS = /* @__PURE__ */ new Set(["demo", "enhanced"]);
196
- function isDevUtilsPreset(preset) {
197
- return DEV_UTILS_PRESETS.has(preset);
198
- }
192
+ // src/answers/cli-args.ts
193
+ import {
194
+ existsSync,
195
+ readFileSync
196
+ } from "node:fs";
199
197
 
200
- // src/features/bundler/esbuild.ts
201
- var Esbuild = class extends FeatureOption {
202
- constructor() {
203
- super({ promptHint: "Fast and simple (recommended)", promptLabel: "esbuild", settingValue: "esbuild" });
204
- }
205
- configure(builder, answers) {
206
- builder.addPackage("esbuild");
207
- if (isDevUtilsPreset(answers.preset)) {
208
- builder.addFiles(["scripts/esbuild-plugins.ts"]);
198
+ // src/directory/directory-constraints.ts
199
+ var CORE_FEATURE_NAMES = [
200
+ "Audio recorder",
201
+ "Backlinks",
202
+ "Bases",
203
+ "Bookmarks",
204
+ "Canvas",
205
+ "Command palette",
206
+ "Daily notes",
207
+ "File recovery",
208
+ "Files",
209
+ "Footnotes",
210
+ "Format converter",
211
+ "Graph view",
212
+ "Live Preview",
213
+ "Note composer",
214
+ "Outgoing links",
215
+ "Outline",
216
+ "Page preview",
217
+ "Properties view",
218
+ "Publish",
219
+ "Quick Switcher",
220
+ "Random note",
221
+ "Reading view",
222
+ "Search",
223
+ "Slash commands",
224
+ "Slides",
225
+ "Source mode",
226
+ "Sync",
227
+ "Tags view",
228
+ "Templates",
229
+ "Unique note creator",
230
+ "Web viewer",
231
+ "Word count",
232
+ "Workspaces"
233
+ ];
234
+ var MAX_DESCRIPTION_LENGTH = 250;
235
+ var MIN_DESCRIPTION_LENGTH = 10;
236
+ var ALLOWED_ID_CHARACTERS = /^[a-z0-9-]+$/;
237
+ var ALLOWED_NAME_CHARACTERS = /^[A-Za-z0-9 \-+()]+$/;
238
+ var EMOJI = /\p{Extended_Pictographic}/u;
239
+ var OBSIDIAN_WORD = /\bobsidian\b/i;
240
+ var OBSIDIAN_NAME_VARIANTS = /obsi|sidian/i;
241
+ var SELF_REFERENCE_PATTERNS = [
242
+ /\bthis plugin\b/i,
243
+ /\bthis is a plugin\b/i,
244
+ /\ba plugin (?:that|which)\b/i,
245
+ /^the plugin\b/i,
246
+ /^plugin\b/i
247
+ ];
248
+ function findUnlistableManifestAnswers(answers) {
249
+ const checked = [
250
+ { key: "pluginId", message: validatePluginId(answers.pluginId), value: answers.pluginId },
251
+ { key: "pluginName", message: validatePluginName(answers.pluginName), value: answers.pluginName },
252
+ { key: "pluginDescription", message: validatePluginDescription(answers.pluginDescription), value: answers.pluginDescription }
253
+ ];
254
+ const problems = [];
255
+ for (const { key, message, value } of checked) {
256
+ if (message !== void 0) {
257
+ problems.push({ key, message, value });
209
258
  }
210
259
  }
211
- };
212
-
213
- // src/features/bundler/parcel.ts
214
- var Parcel = class extends FeatureOption {
215
- constructor() {
216
- super({ promptHint: "Zero-config bundler", promptLabel: "Parcel", settingValue: "parcel" });
260
+ return problems;
261
+ }
262
+ function validatePluginDescription(input) {
263
+ if (!input) {
264
+ return "Should not be empty";
217
265
  }
218
- configure(builder) {
219
- builder.addPackage("parcel").addDepcheckIgnore("parcel", "run as a CLI by the build script.").addPackage("@parcel/config-default").addDepcheckIgnore("@parcel/config-default", "extended by name in `.parcelrc`.").addPackage("@parcel/plugin").addFiles([
220
- ".parcelrc",
221
- "parcel-namer-obsidian.cjs",
222
- "parcel-resolver-obsidian.cjs",
223
- "parcel-transformer-inline-imports.cjs"
224
- ]);
225
- builder.addPartial("cli-bundler");
266
+ if (EMOJI.test(input)) {
267
+ return "Should not contain emoji -- the Community directory rejects them, though it does accept ordinary punctuation such as backticks, em dashes and parentheses";
226
268
  }
227
- };
228
-
229
- // src/features/bundler/rollup.ts
230
- var Rollup = class extends FeatureOption {
231
- constructor() {
232
- super({ promptHint: "Flexible with plugin ecosystem", promptLabel: "Rollup", settingValue: "rollup" });
269
+ if (OBSIDIAN_WORD.test(input)) {
270
+ return 'Should not contain the word "Obsidian" -- the Community directory rejects it as implied by the plugin directory, even though no Obsidian document says so';
233
271
  }
234
- configure(builder) {
235
- builder.addPackage("@rollup/plugin-commonjs").addPackage("@rollup/plugin-node-resolve").addPackage("@rollup/plugin-typescript").addPackage("@rollup/plugin-terser").addPackage("rollup").addFiles([
236
- "rollup.config.mjs",
237
- "scripts/rollup.config.ts"
238
- ]);
239
- builder.addPartial("cli-bundler");
272
+ if (SELF_REFERENCE_PATTERNS.some((pattern) => pattern.test(input))) {
273
+ return 'Should say what the plugin does rather than refer to itself -- the Community directory rejects "This plugin..." and "a plugin that...". Naming another plugin is fine';
240
274
  }
241
- };
242
-
243
- // src/features/bundler/vite.ts
244
- var Vite = class extends FeatureOption {
245
- constructor() {
246
- super({ promptHint: "Modern dev server with HMR", promptLabel: "Vite", settingValue: "vite" });
275
+ if (input.length < MIN_DESCRIPTION_LENGTH) {
276
+ return `Should be at least ${String(MIN_DESCRIPTION_LENGTH)} characters, so it says what the plugin does`;
247
277
  }
248
- configure(builder) {
249
- builder.addPackage("vite").addFiles([
250
- "vite.config.ts",
251
- "scripts/vite.config.ts"
252
- ]);
253
- builder.addPartial("cli-bundler");
278
+ if (input.length > MAX_DESCRIPTION_LENGTH) {
279
+ return `Should be at most ${String(MAX_DESCRIPTION_LENGTH)} characters -- the Community directory rejects a longer one`;
254
280
  }
255
- };
256
-
257
- // src/features/bundler/webpack.ts
258
- var Webpack = class extends FeatureOption {
259
- constructor() {
260
- super({ promptHint: "Mature bundler with broad plugin support", promptLabel: "Webpack", settingValue: "webpack" });
281
+ if (!/^[A-Z]/.test(input)) {
282
+ return 'Should start with a capital letter, ideally on an action verb: "Translates selected text...", "Imports notes from..."';
261
283
  }
262
- configure(builder) {
263
- builder.addPackage("webpack").addPackage("webpack-cli").addDepcheckIgnore("webpack-cli", "what `npx webpack` in the build script runs.").addPackage("terser-webpack-plugin").addPackage("ts-loader").addDepcheckIgnore("ts-loader", "named as a loader string in `scripts/webpack.config.ts`.").addFiles([
264
- "webpack.config.ts",
265
- "scripts/webpack.config.ts"
266
- ]);
267
- builder.addPartial("cli-bundler");
284
+ if (!input.endsWith(".")) {
285
+ return "Should end with a dot";
268
286
  }
269
- };
270
-
271
- // src/features/bundler/index.ts
272
- var BUNDLER_OPTIONS = [new Esbuild(), new Parcel(), new Rollup(), new Vite(), new Webpack()];
273
- async function promptBundler(savedValue) {
274
- return promptFeature({ defaultOption: new Esbuild(), message: "Bundler", options: BUNDLER_OPTIONS, savedValue });
275
- }
276
-
277
- // src/features/git-hooks.ts
278
- function addHusky(builder) {
279
- builder.addPackage("husky").addDepcheckIgnore("husky", "run as a CLI by `scripts/prepare.ts`; the hooks in `.husky/` are its output.").addScript("prepare").addFiles(["scripts/prepare.ts"]);
280
- }
281
- function addStagedFilesHook(builder) {
282
- addHusky(builder);
283
- builder.addPackage("nano-staged").addDepcheckIgnore("nano-staged", "`.husky/pre-commit` runs it; configured by `scripts/nano-staged-config.ts`.").addFiles([
284
- ".husky/pre-commit",
285
- ".nano-staged.mjs",
286
- "scripts/nano-staged-config.ts"
287
- ]);
287
+ return void 0;
288
288
  }
289
-
290
- // src/features/commit-linting/conventional-commits.ts
291
- var ConventionalCommits = class extends FeatureOption {
292
- constructor() {
293
- super({ promptHint: "commitlint + a husky commit-msg hook", promptLabel: "Conventional Commits", settingValue: "conventional-commits" });
289
+ function validatePluginId(input) {
290
+ if (!input) {
291
+ return "Should not be empty";
294
292
  }
295
- configure(builder) {
296
- addHusky(builder);
297
- builder.addPackage("@commitlint/cli").addDepcheckIgnore("@commitlint/cli", "`.husky/commit-msg` runs it as the `commitlint` binary.").addPackage("@commitlint/config-conventional").addDepcheckIgnore("@commitlint/config-conventional", "extended by name (a string in the `extends` of `scripts/commitlint-config.ts`), never imported.").addPackage("@commitlint/types").addPackage("czg").addDepcheckIgnore("czg", "run as a CLI by `scripts/commit.ts`.").addScript("commit").addFiles([
298
- "commitlint.config.ts",
299
- "scripts/commit.ts",
300
- "scripts/commitlint-config.ts",
301
- ".husky/commit-msg"
302
- ]);
293
+ if (!ALLOWED_ID_CHARACTERS.test(input)) {
294
+ return "Should contain only lowercase English letters, digits and hyphens";
303
295
  }
304
- };
305
-
306
- // src/features/commit-linting/none.ts
307
- var None = class extends FeatureOption {
308
- constructor() {
309
- super({ promptHint: "No commit linting", promptLabel: "(none)", settingValue: "none" });
296
+ if (!/^[a-z]/.test(input)) {
297
+ return "Should start with a letter";
310
298
  }
311
- };
312
-
313
- // src/features/commit-linting/index.ts
314
- var COMMIT_LINTING_OPTIONS = [new None(), new ConventionalCommits()];
315
- async function promptCommitLinting(savedValue) {
316
- return promptFeature({ defaultOption: new ConventionalCommits(), message: "Commit linting", options: COMMIT_LINTING_OPTIONS, savedValue });
317
- }
318
-
319
- // src/features/coverage-badge/coverage-badge.ts
320
- var CoverageBadge = class extends FeatureOption {
321
- constructor() {
322
- super({ promptHint: 'A "coverage: 100%" README badge', promptLabel: "Coverage badge", settingValue: "coverage-badge" });
299
+ if (!/[a-z0-9]$/.test(input)) {
300
+ return "Should end with a letter or digit";
323
301
  }
324
- configure(builder, answers) {
325
- builder.addBadge(
326
- `[![Coverage: 100%](https://img.shields.io/badge/coverage-100%25-brightgreen)](https://github.com/${answers.authorGitHubName}/obsidian-${answers.pluginId})`
327
- );
302
+ if (input.includes("obsidian")) {
303
+ return 'Should not contain "obsidian" anywhere -- the Community directory rejects it as implied by the plugin directory, and an id can never be changed once the plugin is published';
328
304
  }
329
- };
330
-
331
- // src/features/coverage-badge/none.ts
332
- var None2 = class extends FeatureOption {
333
- constructor() {
334
- super({ promptHint: "No coverage badge", promptLabel: "(none)", settingValue: "none" });
305
+ if (input.endsWith("plugin")) {
306
+ return 'Should not end with "plugin" -- the Community directory rejects it as implied, and an id can never be changed once the plugin is published';
335
307
  }
336
- };
337
-
338
- // src/features/coverage-badge/index.ts
339
- var COVERAGE_BADGE_OPTIONS = [new None2(), new CoverageBadge()];
340
- async function promptCoverageBadge(savedValue) {
341
- return promptFeature({ defaultOption: new None2(), message: "Coverage badge", options: COVERAGE_BADGE_OPTIONS, savedValue });
308
+ return void 0;
342
309
  }
343
-
344
- // src/features/e2e-test-runner/none.ts
345
- var None3 = class extends FeatureOption {
346
- constructor() {
347
- super({ promptHint: "No E2E testing", promptLabel: "(none)", settingValue: "none" });
348
- }
349
- };
350
-
351
- // src/features/e2e-test-runner/obsidian-test.ts
352
- var ObsidianTest = class extends FeatureOption {
353
- constructor() {
354
- super({ promptHint: "Tests run inside Obsidian with real app APIs", promptLabel: "obsidian-test", settingValue: "obsidian-test" });
310
+ function validatePluginName(input) {
311
+ if (!input) {
312
+ return "Should not be empty";
355
313
  }
356
- configure(builder) {
357
- builder.addPackage("obsidian-test").addScript("test:e2e").addFiles([
358
- "e2e/sample.spec.ts",
359
- "scripts/test-e2e.ts"
360
- ]).addPartial("has-e2e");
314
+ if (OBSIDIAN_NAME_VARIANTS.test(input)) {
315
+ return 'Should not contain "Obsidian" or an abbreviation of it ("Obsi", "sidian") -- the Community directory rejects it as implied by the plugin directory';
361
316
  }
362
- };
363
-
364
- // src/features/e2e-test-runner/wdio-obsidian.ts
365
- var WdioObsidian = class extends FeatureOption {
366
- constructor() {
367
- super({ promptHint: "WebdriverIO service for Obsidian, multi-version & CI/CD", promptLabel: "wdio-obsidian", settingValue: "wdio-obsidian" });
368
- }
369
- configure(builder) {
370
- builder.addPackage("@wdio/cli").addDepcheckIgnore("@wdio/cli", "run as the `wdio` CLI by `scripts/test-e2e.ts`.").addPackage("@wdio/globals").addPackage("@wdio/mocha-framework").addPackage("expect-webdriverio").addPackage("wdio-obsidian-service").addScript("test:e2e").addFiles([
371
- "wdio.conf.ts",
372
- "e2e/sample.spec.ts",
373
- "scripts/test-e2e.ts"
374
- ]).addPartial("has-e2e");
375
- }
376
- };
377
-
378
- // src/features/e2e-test-runner/index.ts
379
- var E2E_TEST_RUNNER_OPTIONS = [new None3(), new ObsidianTest(), new WdioObsidian()];
380
- async function promptE2eTestRunner(savedValue) {
381
- return promptFeature({ defaultOption: new None3(), message: "E2E testing", options: E2E_TEST_RUNNER_OPTIONS, savedValue });
382
- }
383
-
384
- // src/features/editor-extensions/code-mirror.ts
385
- var CodeMirror = class extends FeatureOption {
386
- constructor() {
387
- super({ promptHint: "CodeMirror 6 state fields, view plugins, decorations", promptLabel: "CodeMirror", settingValue: "codemirror" });
388
- }
389
- configure(builder) {
390
- builder.addPackage("@codemirror/state").addPackage("@codemirror/view").addFiles([
391
- "src/editor-extensions/sample-state-field.ts",
392
- "src/editor-extensions/sample-view-plugin.ts",
393
- "src/editor-extensions/sample-widget.ts",
394
- "src/editor-suggests/sample-editor-suggest.ts"
395
- ]);
396
- }
397
- };
398
-
399
- // src/features/editor-extensions/none.ts
400
- var None4 = class extends FeatureOption {
401
- constructor() {
402
- super({ promptHint: "No editor extensions", promptLabel: "(none)", settingValue: "none" });
403
- }
404
- };
405
-
406
- // src/features/editor-extensions/index.ts
407
- var EDITOR_EXTENSIONS_OPTIONS = [new None4(), new CodeMirror()];
408
- async function promptEditorExtensions(savedValue) {
409
- return promptFeature({ defaultOption: new None4(), message: "Editor extensions", options: EDITOR_EXTENSIONS_OPTIONS, savedValue });
410
- }
411
-
412
- // src/features/formatter/biome.ts
413
- var Biome = class extends FeatureOption {
414
- constructor() {
415
- super({ partialName: "biome-formatter", promptHint: "Fast formatter (pairs with Biome linter)", promptLabel: "Biome", settingValue: "biome" });
416
- }
417
- configure(builder, answers) {
418
- if (answers.linter !== "biome") {
419
- builder.addLintStagedCommand("*.{ts,tsx,mts}", "biome format --write --no-errors-on-unmatched");
420
- }
421
- builder.addPackage("@biomejs/biome").addDepcheckIgnore("@biomejs/biome", "run as the `biome` CLI by the format and lint scripts, configured by `biome.jsonc`.").addScript("format").addScript("format:check").addFiles([
422
- "biome.jsonc",
423
- "scripts/format.ts",
424
- "scripts/format-check.ts"
425
- ]);
426
- }
427
- };
428
-
429
- // src/features/formatter/dprint.ts
430
- var Dprint = class extends FeatureOption {
431
- constructor() {
432
- super({ promptHint: "Fast, pluggable, written in Rust", promptLabel: "dprint", settingValue: "dprint" });
433
- }
434
- configure(builder) {
435
- builder.addLintStagedCommand("*.{ts,tsx,mts}", "dprint fmt").addPackage("dprint").addDepcheckIgnore("dprint", "run as a CLI by the format scripts, configured by `dprint.json`.").addScript("format").addScript("format:check").addFiles([
436
- "dprint.json",
437
- "scripts/format.ts",
438
- "scripts/format-check.ts"
439
- ]);
440
- }
441
- };
442
-
443
- // src/features/formatter/none.ts
444
- var None5 = class extends FeatureOption {
445
- constructor() {
446
- super({ promptHint: "No formatting", promptLabel: "(none)", settingValue: "none" });
317
+ if (input.toLowerCase().includes("plugin")) {
318
+ return 'Should not contain "Plugin" -- the Community directory rejects it as implied by the plugin directory';
447
319
  }
448
- };
449
-
450
- // src/features/formatter/prettier.ts
451
- var Prettier = class extends FeatureOption {
452
- constructor() {
453
- super({ promptHint: "Opinionated, widely adopted", promptLabel: "Prettier", settingValue: "prettier" });
320
+ const coreName = findCoreFeatureName(input);
321
+ if (coreName !== void 0) {
322
+ return `Should not be the name of an Obsidian core plugin or core feature -- "${coreName}" is one, and the Community directory rejects a name that takes it`;
454
323
  }
455
- configure(builder) {
456
- builder.addLintStagedCommand("*.{ts,tsx,mts}", "prettier --write").addPackage("prettier").addScript("format").addScript("format:check").addFiles([
457
- ".prettierignore",
458
- "prettier.config.mjs",
459
- "scripts/prettier.config.ts",
460
- "scripts/format.ts",
461
- "scripts/format-check.ts"
462
- ]);
324
+ if (!ALLOWED_NAME_CHARACTERS.test(input)) {
325
+ return "Should use Basic Latin letters and digits only, with hyphens, plus signs and parentheses the only punctuation the Community directory accepts";
463
326
  }
464
- };
465
-
466
- // src/features/formatter/index.ts
467
- var FORMATTER_OPTIONS = [new None5(), new Biome(), new Dprint(), new Prettier()];
468
- var FORMATTERS_NEEDING_INITIAL_FORMAT = /* @__PURE__ */ new Set(["biome", "prettier"]);
469
- function needsInitialFormat(formatter) {
470
- return FORMATTERS_NEEDING_INITIAL_FORMAT.has(formatter);
327
+ return void 0;
471
328
  }
472
- async function promptFormatter(savedValue) {
473
- return promptFeature({ defaultOption: new Dprint(), message: "Formatter", options: FORMATTER_OPTIONS, savedValue });
329
+ function findCoreFeatureName(name) {
330
+ const normalized = name.trim().toLowerCase();
331
+ return CORE_FEATURE_NAMES.find((candidate) => candidate.toLowerCase() === normalized);
474
332
  }
475
333
 
476
334
  // src/features/funding-platform/funding-platform-option.ts
@@ -546,186 +404,534 @@ var Custom = class extends FundingPlatformOption {
546
404
  }
547
405
  };
548
406
 
549
- // src/features/funding-platform/github-sponsors.ts
550
- var GitHubSponsors = class extends FundingPlatformOption {
407
+ // src/features/funding-platform/github-sponsors.ts
408
+ var GitHubSponsors = class extends FundingPlatformOption {
409
+ constructor() {
410
+ super({
411
+ badgeColor: "ea4aaa",
412
+ badgeLabel: "GitHub Sponsors",
413
+ badgeLogo: "githubsponsors",
414
+ badgeLogoColor: "white",
415
+ fundingYmlKey: "github",
416
+ promptHint: "github.com/sponsors/<username>",
417
+ promptLabel: "GitHub Sponsors",
418
+ settingValue: "github-sponsors"
419
+ });
420
+ }
421
+ getUrl(answers) {
422
+ return `https://github.com/sponsors/${answers.fundingUsername}`;
423
+ }
424
+ };
425
+
426
+ // src/features/funding-platform/ko-fi.ts
427
+ var KoFi = class extends FundingPlatformOption {
428
+ constructor() {
429
+ super({
430
+ badgeColor: "ff5e5b",
431
+ badgeLabel: "Ko-fi",
432
+ badgeLogo: "kofi",
433
+ badgeLogoColor: "white",
434
+ fundingYmlKey: "ko_fi",
435
+ promptHint: "ko-fi.com/<username>",
436
+ promptLabel: "Ko-fi",
437
+ settingValue: "ko-fi"
438
+ });
439
+ }
440
+ getUrl(answers) {
441
+ return `https://ko-fi.com/${answers.fundingUsername}`;
442
+ }
443
+ };
444
+
445
+ // src/features/funding-platform/liberapay.ts
446
+ var Liberapay = class extends FundingPlatformOption {
447
+ constructor() {
448
+ super({
449
+ badgeColor: "f6c915",
450
+ badgeLabel: "Liberapay",
451
+ badgeLogo: "liberapay",
452
+ badgeLogoColor: "black",
453
+ fundingYmlKey: "liberapay",
454
+ promptHint: "liberapay.com/<username>",
455
+ promptLabel: "Liberapay",
456
+ settingValue: "liberapay"
457
+ });
458
+ }
459
+ getUrl(answers) {
460
+ return `https://liberapay.com/${answers.fundingUsername}`;
461
+ }
462
+ };
463
+
464
+ // src/features/funding-platform/none.ts
465
+ var None = class extends FundingPlatformOption {
466
+ constructor() {
467
+ super({
468
+ badgeColor: "",
469
+ badgeLabel: "",
470
+ fundingYmlKey: "",
471
+ promptHint: "No funding link, FUNDING.yml or badge",
472
+ promptLabel: "(none)",
473
+ settingValue: "none"
474
+ });
475
+ }
476
+ getUrl() {
477
+ return "";
478
+ }
479
+ };
480
+
481
+ // src/features/funding-platform/open-collective.ts
482
+ var OpenCollective = class extends FundingPlatformOption {
483
+ constructor() {
484
+ super({
485
+ badgeColor: "7fadf2",
486
+ badgeLabel: "Open Collective",
487
+ badgeLogo: "opencollective",
488
+ badgeLogoColor: "white",
489
+ fundingYmlKey: "open_collective",
490
+ promptHint: "opencollective.com/<username>",
491
+ promptLabel: "Open Collective",
492
+ settingValue: "open-collective"
493
+ });
494
+ }
495
+ getUrl(answers) {
496
+ return `https://opencollective.com/${answers.fundingUsername}`;
497
+ }
498
+ };
499
+
500
+ // src/features/funding-platform/patreon.ts
501
+ var Patreon = class extends FundingPlatformOption {
502
+ constructor() {
503
+ super({
504
+ badgeColor: "f96854",
505
+ badgeLabel: "Patreon",
506
+ badgeLogo: "patreon",
507
+ badgeLogoColor: "white",
508
+ fundingYmlKey: "patreon",
509
+ promptHint: "patreon.com/<username>",
510
+ promptLabel: "Patreon",
511
+ settingValue: "patreon"
512
+ });
513
+ }
514
+ getUrl(answers) {
515
+ return `https://www.patreon.com/${answers.fundingUsername}`;
516
+ }
517
+ };
518
+
519
+ // src/features/funding-platform/polar.ts
520
+ var Polar = class extends FundingPlatformOption {
521
+ constructor() {
522
+ super({
523
+ badgeColor: "0062ff",
524
+ badgeLabel: "Polar",
525
+ fundingYmlKey: "polar",
526
+ promptHint: "polar.sh/<username>",
527
+ promptLabel: "Polar",
528
+ settingValue: "polar"
529
+ });
530
+ }
531
+ getUrl(answers) {
532
+ return `https://polar.sh/${answers.fundingUsername}`;
533
+ }
534
+ };
535
+
536
+ // src/features/funding-platform/thanks-dev.ts
537
+ var ThanksDev = class extends FundingPlatformOption {
538
+ constructor() {
539
+ super({
540
+ badgeColor: "000000",
541
+ badgeLabel: "thanks.dev",
542
+ fundingYmlKey: "thanks_dev",
543
+ promptHint: "thanks.dev/<username>, e.g. u/gh/<GitHub username>",
544
+ promptLabel: "thanks.dev",
545
+ settingValue: "thanks-dev"
546
+ });
547
+ }
548
+ getUrl(answers) {
549
+ return `https://thanks.dev/${answers.fundingUsername}`;
550
+ }
551
+ };
552
+
553
+ // src/features/funding-platform/index.ts
554
+ var FUNDING_PLATFORM_OPTIONS = [
555
+ new None(),
556
+ new BuyMeACoffee(),
557
+ new GitHubSponsors(),
558
+ new KoFi(),
559
+ new Liberapay(),
560
+ new OpenCollective(),
561
+ new Patreon(),
562
+ new Polar(),
563
+ new ThanksDev(),
564
+ new Custom()
565
+ ];
566
+ function asksFundingUsername(platform) {
567
+ return platform !== void 0 && platform !== "none" && platform !== "custom";
568
+ }
569
+ async function promptFundingPlatform(savedValue) {
570
+ return promptFeature({ defaultOption: new BuyMeACoffee(), message: "Funding platform", options: FUNDING_PLATFORM_OPTIONS, savedValue });
571
+ }
572
+ function resolveFunding(answers) {
573
+ const option = FUNDING_PLATFORM_OPTIONS.find((candidate) => candidate.settingValue === answers.fundingPlatform);
574
+ if (!option?.getUrl(answers)) {
575
+ return null;
576
+ }
577
+ return option;
578
+ }
579
+ function validateFundingUsername(value) {
580
+ if (!value) {
581
+ return "Should not be empty";
582
+ }
583
+ if (!/^[\w./-]+$/.test(value)) {
584
+ return "Use only letters, digits, `.`, `_`, `-` and `/`";
585
+ }
586
+ return void 0;
587
+ }
588
+
589
+ // src/prompts/prompts.ts
590
+ import {
591
+ cancel as cancel2,
592
+ log
593
+ } from "@clack/prompts";
594
+ import { styleText as styleText3 } from "node:util";
595
+
596
+ // src/features/api-subset/official.ts
597
+ var Official = class extends FeatureOption {
598
+ constructor() {
599
+ super({ promptHint: "Stable, documented API only", promptLabel: "Official API", settingValue: "official" });
600
+ }
601
+ };
602
+
603
+ // src/features/api-subset/with-unofficial.ts
604
+ var WithUnofficial = class extends FeatureOption {
605
+ constructor() {
606
+ super({ promptHint: "Includes internal undocumented APIs (for experienced devs)", promptLabel: "Official + Unofficial", settingValue: "with-unofficial" });
607
+ }
608
+ configure(builder) {
609
+ builder.addPackage("@obsidian-typings/obsidian-public-latest");
610
+ }
611
+ };
612
+
613
+ // src/features/api-subset/index.ts
614
+ var API_SUBSET_OPTIONS = [new Official(), new WithUnofficial()];
615
+ async function promptApiSubset(savedValue) {
616
+ return promptFeature({ defaultOption: new Official(), message: "Obsidian API subset", options: API_SUBSET_OPTIONS, savedValue });
617
+ }
618
+
619
+ // src/features/preset/is-framework-preset.ts
620
+ var FRAMEWORK_PRESETS = /* @__PURE__ */ new Set(["all-in-one", "demo", "docs-showcase"]);
621
+ function isFrameworkPreset(preset) {
622
+ return FRAMEWORK_PRESETS.has(preset);
623
+ }
624
+
625
+ // src/features/bundler/esbuild.ts
626
+ var Esbuild = class extends FeatureOption {
627
+ constructor() {
628
+ super({ promptHint: "Fast and simple (recommended)", promptLabel: "esbuild", settingValue: "esbuild" });
629
+ }
630
+ configure(builder, answers) {
631
+ if (isFrameworkPreset(answers.preset)) {
632
+ return;
633
+ }
634
+ builder.addPackage("esbuild");
635
+ }
636
+ };
637
+
638
+ // src/features/bundler/parcel.ts
639
+ var Parcel = class extends FeatureOption {
640
+ constructor() {
641
+ super({ promptHint: "Zero-config bundler", promptLabel: "Parcel", settingValue: "parcel" });
642
+ }
643
+ configure(builder, answers) {
644
+ if (isFrameworkPreset(answers.preset)) {
645
+ builder.addPackage("@parcel/core").addPackage("@parcel/config-default").addDepcheckIgnore("@parcel/config-default", "extended by name by the `.parcelrc` obsidian-dev-toolkit writes.").addPackage("@parcel/plugin").addDepcheckIgnore("@parcel/plugin", "the base of the parcel plugins obsidian-dev-toolkit registers; nothing here imports it.").addPartial("parcel-adapter");
646
+ return;
647
+ }
648
+ builder.addPackage("parcel").addDepcheckIgnore("parcel", "run as a CLI by the build script.").addPackage("@parcel/config-default").addDepcheckIgnore("@parcel/config-default", "extended by name in `.parcelrc`.").addPackage("@parcel/plugin").addFiles([
649
+ ".parcelrc",
650
+ "parcel-namer-obsidian.cjs",
651
+ "parcel-resolver-obsidian.cjs",
652
+ "parcel-transformer-inline-imports.cjs"
653
+ ]).addPartial("parcel-targets").addPartial("cli-bundler");
654
+ }
655
+ };
656
+
657
+ // src/features/bundler/rollup.ts
658
+ var Rollup = class extends FeatureOption {
659
+ constructor() {
660
+ super({ promptHint: "Flexible with plugin ecosystem", promptLabel: "Rollup", settingValue: "rollup" });
661
+ }
662
+ configure(builder, answers) {
663
+ builder.addPackage("@rollup/plugin-commonjs").addPackage("@rollup/plugin-node-resolve").addPackage("rollup").addFiles([
664
+ "rollup.config.mjs",
665
+ "scripts/rollup.config.ts"
666
+ ]);
667
+ if (isFrameworkPreset(answers.preset)) {
668
+ builder.addPackage("esbuild").addDepcheckIgnore("esbuild", "the peer dependency `rollup-plugin-esbuild` runs; nothing imports it.").addPackage("rollup-plugin-esbuild").addPartial("adapter-cli");
669
+ return;
670
+ }
671
+ builder.addPackage("@rollup/plugin-typescript").addPackage("@rollup/plugin-terser").addPartial("cli-bundler");
672
+ }
673
+ };
674
+
675
+ // src/features/bundler/vite.ts
676
+ var Vite = class extends FeatureOption {
677
+ constructor() {
678
+ super({ promptHint: "Modern dev server with HMR", promptLabel: "Vite", settingValue: "vite" });
679
+ }
680
+ configure(builder, answers) {
681
+ builder.addPackage("vite").addFiles([
682
+ "vite.config.ts",
683
+ "scripts/vite.config.ts"
684
+ ]);
685
+ builder.addPartial(isFrameworkPreset(answers.preset) ? "adapter-cli" : "cli-bundler");
686
+ }
687
+ };
688
+
689
+ // src/features/bundler/webpack.ts
690
+ var Webpack = class extends FeatureOption {
691
+ constructor() {
692
+ super({ promptHint: "Mature bundler with broad plugin support", promptLabel: "Webpack", settingValue: "webpack" });
693
+ }
694
+ configure(builder, answers) {
695
+ builder.addPackage("webpack").addPackage("webpack-cli").addDepcheckIgnore("webpack-cli", "what the build script runs as the `webpack` command.").addFiles([
696
+ "webpack.config.ts",
697
+ "scripts/webpack.config.ts"
698
+ ]);
699
+ if (isFrameworkPreset(answers.preset)) {
700
+ builder.addPackage("esbuild-loader").addDepcheckIgnore("esbuild-loader", "named as a loader string in `scripts/webpack.config.ts`.").addPartial("adapter-cli");
701
+ return;
702
+ }
703
+ builder.addPackage("terser-webpack-plugin").addPackage("ts-loader").addDepcheckIgnore("ts-loader", "named as a loader string in `scripts/webpack.config.ts`.").addPartial("cli-bundler");
704
+ }
705
+ };
706
+
707
+ // src/features/bundler/index.ts
708
+ var BUNDLER_OPTIONS = [new Esbuild(), new Parcel(), new Rollup(), new Vite(), new Webpack()];
709
+ async function promptBundler(savedValue) {
710
+ return promptFeature({ defaultOption: new Esbuild(), message: "Bundler", options: BUNDLER_OPTIONS, savedValue });
711
+ }
712
+
713
+ // src/features/git-hooks.ts
714
+ var INITIAL_COMMIT_MESSAGE = "chore: initial commit from create-obsidian-plugin";
715
+ function addHusky(builder) {
716
+ builder.addPackage("husky").addDepcheckIgnore("husky", "run as a CLI by `scripts/prepare.ts`; the hooks in `.husky/` are its output.").addScript("prepare").addFiles(["scripts/prepare.ts"]);
717
+ }
718
+ function addStagedFilesHook(builder, preset) {
719
+ addHusky(builder);
720
+ builder.addPartial(usesToolkitNanoStagedConfig(preset) ? "toolkit-nano-staged" : "inline-nano-staged");
721
+ builder.addPackage("nano-staged").addDepcheckIgnore("nano-staged", "`.husky/pre-commit` runs it; configured by `scripts/nano-staged-config.ts`.").addFiles([
722
+ ".husky/pre-commit",
723
+ ".nano-staged.mjs",
724
+ "scripts/nano-staged-config.ts"
725
+ ]);
726
+ }
727
+ function usesToolkitNanoStagedConfig(preset) {
728
+ return isFrameworkPreset(preset);
729
+ }
730
+
731
+ // src/features/commit-linting/conventional-commits.ts
732
+ var ConventionalCommits = class extends FeatureOption {
733
+ constructor() {
734
+ super({ promptHint: "commitlint + a husky commit-msg hook", promptLabel: "Conventional Commits", settingValue: "conventional-commits" });
735
+ }
736
+ configure(builder, answers) {
737
+ addHusky(builder);
738
+ builder.addPackage("@commitlint/cli").addDepcheckIgnore("@commitlint/cli", "`.husky/commit-msg` runs it as the `commitlint` binary.").addPackage("czg").addDepcheckIgnore("czg", "run as a CLI by `scripts/commit.ts`.").addScript("commit").addFiles([
739
+ "commitlint.config.ts",
740
+ "scripts/commit.ts",
741
+ "scripts/commitlint-config.ts",
742
+ ".husky/commit-msg"
743
+ ]);
744
+ if (isFrameworkPreset(answers.preset)) {
745
+ return;
746
+ }
747
+ builder.addPackage("@commitlint/config-conventional").addDepcheckIgnore("@commitlint/config-conventional", "extended by name (a string in the `extends` of `scripts/commitlint-config.ts`), never imported.").addPackage("@commitlint/types");
748
+ }
749
+ };
750
+
751
+ // src/features/commit-linting/none.ts
752
+ var None2 = class extends FeatureOption {
753
+ constructor() {
754
+ super({ promptHint: "No commit linting", promptLabel: "(none)", settingValue: "none" });
755
+ }
756
+ };
757
+
758
+ // src/features/commit-linting/index.ts
759
+ var COMMIT_LINTING_OPTIONS = [new None2(), new ConventionalCommits()];
760
+ async function promptCommitLinting(savedValue) {
761
+ return promptFeature({ defaultOption: new ConventionalCommits(), message: "Commit linting", options: COMMIT_LINTING_OPTIONS, savedValue });
762
+ }
763
+
764
+ // src/features/coverage-badge/coverage-badge.ts
765
+ var CoverageBadge = class extends FeatureOption {
766
+ constructor() {
767
+ super({ promptHint: "A coverage README badge, measured by CI where the project has one", promptLabel: "Coverage badge", settingValue: "coverage-badge" });
768
+ }
769
+ configure(builder, answers) {
770
+ const repoUrl = `https://github.com/${answers.authorGitHubName}/obsidian-${answers.pluginId}`;
771
+ if (!isMeasured(answers)) {
772
+ builder.addBadge(`[![Coverage: 100%](https://img.shields.io/badge/coverage-100%25-brightgreen)](${repoUrl})`);
773
+ return;
774
+ }
775
+ builder.addPartial("measured-coverage-badge").addBadge(
776
+ `[![Coverage](https://raw.githubusercontent.com/${answers.authorGitHubName}/obsidian-${answers.pluginId}/badges/coverage.svg)](${repoUrl}/actions/workflows/ci.yml)`
777
+ );
778
+ }
779
+ };
780
+ var CI_ANSWERS = /* @__PURE__ */ new Set(["ci", "ci-and-release"]);
781
+ var MEASURING_TEST_RUNNERS = /* @__PURE__ */ new Set(["jest", "vitest"]);
782
+ function isMeasured(answers) {
783
+ return isFrameworkPreset(answers.preset) && CI_ANSWERS.has(answers.gitHubActions) && MEASURING_TEST_RUNNERS.has(answers.testRunner);
784
+ }
785
+
786
+ // src/features/coverage-badge/none.ts
787
+ var None3 = class extends FeatureOption {
788
+ constructor() {
789
+ super({ promptHint: "No coverage badge", promptLabel: "(none)", settingValue: "none" });
790
+ }
791
+ };
792
+
793
+ // src/features/coverage-badge/index.ts
794
+ var COVERAGE_BADGE_OPTIONS = [new None3(), new CoverageBadge()];
795
+ async function promptCoverageBadge(savedValue) {
796
+ return promptFeature({ defaultOption: new None3(), message: "Coverage badge", options: COVERAGE_BADGE_OPTIONS, savedValue });
797
+ }
798
+
799
+ // src/features/e2e-test-runner/none.ts
800
+ var None4 = class extends FeatureOption {
801
+ constructor() {
802
+ super({ promptHint: "No E2E testing", promptLabel: "(none)", settingValue: "none" });
803
+ }
804
+ };
805
+
806
+ // src/features/e2e-test-runner/obsidian-test.ts
807
+ var ObsidianTest = class extends FeatureOption {
551
808
  constructor() {
552
- super({
553
- badgeColor: "ea4aaa",
554
- badgeLabel: "GitHub Sponsors",
555
- badgeLogo: "githubsponsors",
556
- badgeLogoColor: "white",
557
- fundingYmlKey: "github",
558
- promptHint: "github.com/sponsors/<username>",
559
- promptLabel: "GitHub Sponsors",
560
- settingValue: "github-sponsors"
561
- });
809
+ super({ promptHint: "Tests run inside Obsidian with real app APIs", promptLabel: "obsidian-test", settingValue: "obsidian-test" });
562
810
  }
563
- getUrl(answers) {
564
- return `https://github.com/sponsors/${answers.fundingUsername}`;
811
+ configure(builder) {
812
+ builder.addPackage("obsidian-test").addScript("test:e2e").addFiles([
813
+ "e2e/sample.spec.ts",
814
+ "scripts/test-e2e.ts"
815
+ ]).addPartial("has-e2e");
565
816
  }
566
817
  };
567
818
 
568
- // src/features/funding-platform/ko-fi.ts
569
- var KoFi = class extends FundingPlatformOption {
819
+ // src/features/e2e-test-runner/wdio-obsidian.ts
820
+ var WdioObsidian = class extends FeatureOption {
570
821
  constructor() {
571
- super({
572
- badgeColor: "ff5e5b",
573
- badgeLabel: "Ko-fi",
574
- badgeLogo: "kofi",
575
- badgeLogoColor: "white",
576
- fundingYmlKey: "ko_fi",
577
- promptHint: "ko-fi.com/<username>",
578
- promptLabel: "Ko-fi",
579
- settingValue: "ko-fi"
580
- });
822
+ super({ promptHint: "WebdriverIO service for Obsidian, multi-version & CI/CD", promptLabel: "wdio-obsidian", settingValue: "wdio-obsidian" });
581
823
  }
582
- getUrl(answers) {
583
- return `https://ko-fi.com/${answers.fundingUsername}`;
824
+ configure(builder, answers) {
825
+ builder.addPackage("@wdio/cli").addDepcheckIgnore("@wdio/cli", "run as the `wdio` CLI by `scripts/test-e2e.ts`.").addPackage("@wdio/globals").addPackage("@wdio/local-runner").addDepcheckIgnore("@wdio/local-runner", "loaded by name by wdio for the config's `runner: 'local'`.").addPackage("@wdio/mocha-framework").addPackage("expect-webdriverio").addPackage("wdio-obsidian-service").addScript("test:e2e").addFiles([
826
+ "e2e/sample.spec.ts",
827
+ "scripts/test-e2e.ts"
828
+ ]).addPartial("has-e2e");
829
+ if (isFrameworkPreset(answers.preset)) {
830
+ builder.addPackage("wdio-obsidian-reporter").addDepcheckIgnore("wdio-obsidian-reporter", "loaded by name by wdio for the `obsidian` reporter `defineWdioObsidianConfig` names.").addFiles(["wdio.conf.mts"]);
831
+ return;
832
+ }
833
+ builder.addFiles(["wdio.conf.ts"]);
584
834
  }
585
835
  };
586
836
 
587
- // src/features/funding-platform/liberapay.ts
588
- var Liberapay = class extends FundingPlatformOption {
837
+ // src/features/e2e-test-runner/index.ts
838
+ var E2E_TEST_RUNNER_OPTIONS = [new None4(), new ObsidianTest(), new WdioObsidian()];
839
+ async function promptE2eTestRunner(savedValue) {
840
+ return promptFeature({ defaultOption: new None4(), message: "E2E testing", options: E2E_TEST_RUNNER_OPTIONS, savedValue });
841
+ }
842
+
843
+ // src/features/editor-extensions/code-mirror.ts
844
+ var CodeMirror = class extends FeatureOption {
589
845
  constructor() {
590
- super({
591
- badgeColor: "f6c915",
592
- badgeLabel: "Liberapay",
593
- badgeLogo: "liberapay",
594
- badgeLogoColor: "black",
595
- fundingYmlKey: "liberapay",
596
- promptHint: "liberapay.com/<username>",
597
- promptLabel: "Liberapay",
598
- settingValue: "liberapay"
599
- });
846
+ super({ promptHint: "CodeMirror 6 state fields, view plugins, decorations", promptLabel: "CodeMirror", settingValue: "codemirror" });
600
847
  }
601
- getUrl(answers) {
602
- return `https://liberapay.com/${answers.fundingUsername}`;
848
+ configure(builder) {
849
+ builder.addPackage("@codemirror/state").addPackage("@codemirror/view").addFiles([
850
+ "src/editor-extensions/sample-state-field.ts",
851
+ "src/editor-extensions/sample-view-plugin.ts",
852
+ "src/editor-extensions/sample-widget.ts",
853
+ "src/editor-suggests/sample-editor-suggest.ts"
854
+ ]);
603
855
  }
604
856
  };
605
857
 
606
- // src/features/funding-platform/none.ts
607
- var None6 = class extends FundingPlatformOption {
858
+ // src/features/editor-extensions/none.ts
859
+ var None5 = class extends FeatureOption {
608
860
  constructor() {
609
- super({
610
- badgeColor: "",
611
- badgeLabel: "",
612
- fundingYmlKey: "",
613
- promptHint: "No funding link, FUNDING.yml or badge",
614
- promptLabel: "(none)",
615
- settingValue: "none"
616
- });
617
- }
618
- getUrl() {
619
- return "";
861
+ super({ promptHint: "No editor extensions", promptLabel: "(none)", settingValue: "none" });
620
862
  }
621
863
  };
622
864
 
623
- // src/features/funding-platform/open-collective.ts
624
- var OpenCollective = class extends FundingPlatformOption {
865
+ // src/features/editor-extensions/index.ts
866
+ var EDITOR_EXTENSIONS_OPTIONS = [new None5(), new CodeMirror()];
867
+ async function promptEditorExtensions(savedValue) {
868
+ return promptFeature({ defaultOption: new None5(), message: "Editor extensions", options: EDITOR_EXTENSIONS_OPTIONS, savedValue });
869
+ }
870
+
871
+ // src/features/formatter/biome.ts
872
+ var Biome = class extends FeatureOption {
625
873
  constructor() {
626
- super({
627
- badgeColor: "7fadf2",
628
- badgeLabel: "Open Collective",
629
- badgeLogo: "opencollective",
630
- badgeLogoColor: "white",
631
- fundingYmlKey: "open_collective",
632
- promptHint: "opencollective.com/<username>",
633
- promptLabel: "Open Collective",
634
- settingValue: "open-collective"
635
- });
874
+ super({ partialName: "biome-formatter", promptHint: "Fast formatter (pairs with Biome linter)", promptLabel: "Biome", settingValue: "biome" });
636
875
  }
637
- getUrl(answers) {
638
- return `https://opencollective.com/${answers.fundingUsername}`;
876
+ configure(builder, answers) {
877
+ if (answers.linter !== "biome") {
878
+ builder.addLintStagedCommand("*.{ts,tsx,mts}", "biome format --write --no-errors-on-unmatched");
879
+ }
880
+ builder.addPackage("@biomejs/biome").addDepcheckIgnore("@biomejs/biome", "run as the `biome` CLI by the format and lint scripts, configured by `biome.jsonc`.").addScript("format").addScript("format:check").addFiles([
881
+ "biome.jsonc",
882
+ "scripts/format.ts",
883
+ "scripts/format-check.ts"
884
+ ]);
639
885
  }
640
886
  };
641
887
 
642
- // src/features/funding-platform/patreon.ts
643
- var Patreon = class extends FundingPlatformOption {
888
+ // src/features/formatter/dprint.ts
889
+ var Dprint = class extends FeatureOption {
644
890
  constructor() {
645
- super({
646
- badgeColor: "f96854",
647
- badgeLabel: "Patreon",
648
- badgeLogo: "patreon",
649
- badgeLogoColor: "white",
650
- fundingYmlKey: "patreon",
651
- promptHint: "patreon.com/<username>",
652
- promptLabel: "Patreon",
653
- settingValue: "patreon"
654
- });
891
+ super({ promptHint: "Fast, pluggable, written in Rust", promptLabel: "dprint", settingValue: "dprint" });
655
892
  }
656
- getUrl(answers) {
657
- return `https://www.patreon.com/${answers.fundingUsername}`;
893
+ configure(builder) {
894
+ builder.addLintStagedCommand("*.{ts,tsx,mts}", "dprint fmt").addPackage("dprint").addDepcheckIgnore("dprint", "run as a CLI by the format scripts, configured by `dprint.json`.").addScript("format").addScript("format:check").addFiles([
895
+ "dprint.json",
896
+ "scripts/format.ts",
897
+ "scripts/format-check.ts"
898
+ ]);
658
899
  }
659
900
  };
660
901
 
661
- // src/features/funding-platform/polar.ts
662
- var Polar = class extends FundingPlatformOption {
902
+ // src/features/formatter/none.ts
903
+ var None6 = class extends FeatureOption {
663
904
  constructor() {
664
- super({
665
- badgeColor: "0062ff",
666
- badgeLabel: "Polar",
667
- fundingYmlKey: "polar",
668
- promptHint: "polar.sh/<username>",
669
- promptLabel: "Polar",
670
- settingValue: "polar"
671
- });
672
- }
673
- getUrl(answers) {
674
- return `https://polar.sh/${answers.fundingUsername}`;
905
+ super({ promptHint: "No formatting", promptLabel: "(none)", settingValue: "none" });
675
906
  }
676
907
  };
677
908
 
678
- // src/features/funding-platform/thanks-dev.ts
679
- var ThanksDev = class extends FundingPlatformOption {
909
+ // src/features/formatter/prettier.ts
910
+ var Prettier = class extends FeatureOption {
680
911
  constructor() {
681
- super({
682
- badgeColor: "000000",
683
- badgeLabel: "thanks.dev",
684
- fundingYmlKey: "thanks_dev",
685
- promptHint: "thanks.dev/<username>, e.g. u/gh/<GitHub username>",
686
- promptLabel: "thanks.dev",
687
- settingValue: "thanks-dev"
688
- });
912
+ super({ promptHint: "Opinionated, widely adopted", promptLabel: "Prettier", settingValue: "prettier" });
689
913
  }
690
- getUrl(answers) {
691
- return `https://thanks.dev/${answers.fundingUsername}`;
914
+ configure(builder, answers) {
915
+ builder.addLintStagedCommand("*.{ts,tsx,mts}", "prettier --write").addPackage("prettier").addScript("format").addScript("format:check").addFiles([
916
+ ".prettierignore",
917
+ "prettier.config.mjs",
918
+ "scripts/format.ts",
919
+ "scripts/format-check.ts"
920
+ ]);
921
+ if (!isFrameworkPreset(answers.preset)) {
922
+ builder.addFiles(["scripts/prettier.config.ts"]);
923
+ }
692
924
  }
693
925
  };
694
926
 
695
- // src/features/funding-platform/index.ts
696
- var FUNDING_PLATFORM_OPTIONS = [
697
- new None6(),
698
- new BuyMeACoffee(),
699
- new GitHubSponsors(),
700
- new KoFi(),
701
- new Liberapay(),
702
- new OpenCollective(),
703
- new Patreon(),
704
- new Polar(),
705
- new ThanksDev(),
706
- new Custom()
707
- ];
708
- function asksFundingUsername(platform) {
709
- return platform !== void 0 && platform !== "none" && platform !== "custom";
710
- }
711
- async function promptFundingPlatform(savedValue) {
712
- return promptFeature({ defaultOption: new BuyMeACoffee(), message: "Funding platform", options: FUNDING_PLATFORM_OPTIONS, savedValue });
713
- }
714
- function resolveFunding(answers) {
715
- const option = FUNDING_PLATFORM_OPTIONS.find((candidate) => candidate.settingValue === answers.fundingPlatform);
716
- if (!option?.getUrl(answers)) {
717
- return null;
718
- }
719
- return option;
927
+ // src/features/formatter/index.ts
928
+ var FORMATTER_OPTIONS = [new None6(), new Biome(), new Dprint(), new Prettier()];
929
+ var FORMATTERS_NEEDING_INITIAL_FORMAT = /* @__PURE__ */ new Set(["biome", "prettier"]);
930
+ function needsInitialFormat(formatter) {
931
+ return FORMATTERS_NEEDING_INITIAL_FORMAT.has(formatter);
720
932
  }
721
- function validateFundingUsername(value) {
722
- if (!value) {
723
- return "Should not be empty";
724
- }
725
- if (!/^[\w./-]+$/.test(value)) {
726
- return "Use only letters, digits, `.`, `_`, `-` and `/`";
727
- }
728
- return void 0;
933
+ async function promptFormatter(savedValue) {
934
+ return promptFeature({ defaultOption: new Dprint(), message: "Formatter", options: FORMATTER_OPTIONS, savedValue });
729
935
  }
730
936
 
731
937
  // src/features/git-hub-actions/ci-and-release.ts
@@ -772,12 +978,15 @@ var BugAndFeature = class extends FeatureOption {
772
978
  // The real plugins' names, underscores and all. They used to be emitted as `bug-report.yml` and
773
979
  // `feature-request.yml`, because any `_` in a basename was read as the partial marker and the render
774
980
  // Loop silently skipped both forms; `isPartialTemplatePath` now reads only a kebab-case tail as one.
775
- configure(builder) {
981
+ configure(builder, answers) {
776
982
  builder.addFiles([
777
983
  ".github/ISSUE_TEMPLATE/bug_report.yml",
778
984
  ".github/ISSUE_TEMPLATE/config.yml",
779
985
  ".github/ISSUE_TEMPLATE/feature_request.yml"
780
986
  ]);
987
+ if (isFrameworkPreset(answers.preset)) {
988
+ builder.addPartial("has-bug-report-command");
989
+ }
781
990
  }
782
991
  };
783
992
 
@@ -806,6 +1015,11 @@ var None9 = class extends FeatureOption {
806
1015
  constructor() {
807
1016
  super({ promptHint: "No hot reload support", promptLabel: "(none)", settingValue: "none" });
808
1017
  }
1018
+ configure(builder, answers) {
1019
+ if (isFrameworkPreset(answers.preset)) {
1020
+ builder.addBuildOption("reload", "false");
1021
+ }
1022
+ }
809
1023
  };
810
1024
 
811
1025
  // src/features/hot-reload/obsidian-cli.ts
@@ -813,6 +1027,11 @@ var ObsidianCli = class extends FeatureOption {
813
1027
  constructor() {
814
1028
  super({ promptHint: "Reloads via obsidian plugin:reload CLI command", promptLabel: "Obsidian CLI", settingValue: "obsidian-cli" });
815
1029
  }
1030
+ configure(builder, answers) {
1031
+ if (isFrameworkPreset(answers.preset)) {
1032
+ builder.addBuildOption("reload", "'obsidian-cli'");
1033
+ }
1034
+ }
816
1035
  };
817
1036
 
818
1037
  // src/features/hot-reload/index.ts
@@ -889,7 +1108,7 @@ var Eslint = class extends FeatureOption {
889
1108
  "scripts/lint.ts",
890
1109
  "scripts/lint-fix.ts"
891
1110
  ]);
892
- if (isDevUtilsPreset(answers.preset)) {
1111
+ if (isFrameworkPreset(answers.preset)) {
893
1112
  builder.addDepcheckIgnore("typescript-eslint", "imported by nothing here -- the shared config brings its own -- but the `typescript` pin's check reads its `package.json` for the peer range.").addFiles(["scripts/eslint-config.ts"]);
894
1113
  return;
895
1114
  }
@@ -918,7 +1137,7 @@ var Markdownlint = class extends FeatureOption {
918
1137
  configure(builder, answers) {
919
1138
  builder.addLintStagedCommand("*.md", "markdownlint-cli2 --fix").addPackage("markdownlint-cli2").addDepcheckIgnore("markdownlint-cli2", "run as a CLI by the `lint:md` scripts, configured by `.markdownlint-cli2.mjs`.").addPackage("linkinator").addDepcheckIgnore("linkinator", "run as a CLI by the `lint:md` scripts.").addScript("lint:md").addScript("lint:md:fix").addFiles([
920
1139
  // `markdownlint-cli2` only discovers a config named `.markdownlint-cli2.{jsonc,yaml,cjs,mjs}`, and
921
- // So does obsidian-dev-utils' runner -- which copies its own `.mjs` in when it finds none, pointing
1140
+ // So does the toolkit's runner -- which copies its own `.mjs` in when it finds none, pointing
922
1141
  // At a `scripts/markdownlint-cli2-config.ts` that then has to exist. Hence this shape rather than a
923
1142
  // Single `.mts` that nothing reads.
924
1143
  ".markdownlint-cli2.mjs",
@@ -929,7 +1148,7 @@ var Markdownlint = class extends FeatureOption {
929
1148
  // Repository, which 404 until the user pushes it.
930
1149
  "linkinator.config.json"
931
1150
  ]);
932
- if (isDevUtilsPreset(answers.preset)) {
1151
+ if (isFrameworkPreset(answers.preset)) {
933
1152
  return;
934
1153
  }
935
1154
  builder.addPackage("markdownlint").addPackage("markdownlint-rule-relative-links");
@@ -1026,23 +1245,22 @@ var DEMO_VAULT_TEMPLATE_FILES = [
1026
1245
  "demo-vault/00 Start.md",
1027
1246
  "demo-vault/01 Sample commands.md",
1028
1247
  "demo-vault/02 Settings.md",
1029
- "demo-vault/Materials/01 Sample commands/Scratch note.md",
1030
1248
  "demo-vault/README.md",
1031
1249
  "demo-vault/_assets/CodeScriptToolkit/demoSetup.ts",
1032
1250
  "demo-vault/_assets/CodeScriptToolkit/startup.ts"
1033
1251
  ];
1034
1252
 
1035
- // src/features/preset/demo.ts
1036
- var Demo = class extends FeatureOption {
1253
+ // src/features/preset/all-in-one.ts
1254
+ var AllInOne = class extends FeatureOption {
1037
1255
  constructor() {
1038
- super({ promptHint: "All features enabled for demonstration", promptLabel: "Demo", settingValue: "demo" });
1256
+ super({
1257
+ promptHint: "Recommended. The author's framework: @mnaoumov/obsidian-lib, a library of ready-made helpers for settings, commands, modals, notices, file and link handling, and more, plus the @mnaoumov toolkits for building, linting, testing and releases",
1258
+ promptLabel: "All-in-one Framework",
1259
+ settingValue: "all-in-one"
1260
+ });
1039
1261
  }
1040
- configure(builder) {
1041
- builder.addPackage("@tsconfig/strictest").addPackage("moment").addDepcheckIgnore("moment", "imported through `obsidian` rather than directly, and the typings of `obsidian` resolve it by name.").addPackage("obsidian-dev-utils").addPackage("obsidian-integration-testing").addScript("dev").addScript("build").addScript("build:clean").addScript("build:compile").addScript("find-overexposed").addScript("find-overexposed:fix").addScript("version").addScript("gate").addFiles([
1042
- // Not gated on the gitHubActions answer, and deliberately so: this attests the assets of a
1043
- // Published RELEASE, and the release flow is the preset's, not CI's. Every plugin compared here
1044
- // Ships this workflow -- they have no ci.yml at all.
1045
- ".github/workflows/attest-release-assets.yml",
1262
+ configure(builder, answers) {
1263
+ builder.addPackage("@tsconfig/strictest").addPackage("@mnaoumov/obsidian-lib").addPackage("@mnaoumov/obsidian-dev-toolkit").addPackage("@mnaoumov/typescript-dev-toolkit").addPackage("obsidian-integration-testing").addScript("dev").addScript("build").addScript("build:clean").addScript("build:compile").addScript("find-overexposed").addScript("find-overexposed:fix").addScript("version").addScript("gate").addFiles([
1046
1264
  // Not gated on the answers either: the shared ESLint config's `obsidianmd/validate-license` compares
1047
1265
  // The LICENSE year with the current one, so without this bump every project turns red on 1 January.
1048
1266
  ".github/workflows/update-license-year.yml",
@@ -1054,28 +1272,24 @@ var Demo = class extends FeatureOption {
1054
1272
  "scripts/dev.ts",
1055
1273
  "scripts/gate.ts",
1056
1274
  "scripts/version.ts",
1057
- "src/modals/sample-form-modal.ts",
1058
- "src/modals/sample-suggest-modal.ts",
1059
1275
  "src/plugin-settings.ts",
1060
1276
  "src/plugin-settings-component.ts",
1061
1277
  "src/plugin-settings-tab.ts",
1062
- "src/views/sample-view.ts",
1063
1278
  ...DEMO_VAULT_TEMPLATE_FILES
1064
- ]).addPartial("dev-utils");
1279
+ ]).addPartial("framework");
1280
+ if (answers.gitHubActions !== "ci-and-release") {
1281
+ builder.addFiles([".github/workflows/attest-release-assets.yml"]);
1282
+ }
1065
1283
  }
1066
1284
  };
1067
1285
 
1068
- // src/features/preset/enhanced.ts
1069
- var Enhanced = class extends FeatureOption {
1286
+ // src/features/preset/demo.ts
1287
+ var Demo = class extends FeatureOption {
1070
1288
  constructor() {
1071
- super({ promptHint: "Recommended. Uses obsidian-dev-utils for settings, linting, and more", promptLabel: "Enhanced", settingValue: "enhanced" });
1289
+ super({ promptHint: "All features enabled for demonstration", promptLabel: "Demo", settingValue: "demo" });
1072
1290
  }
1073
- configure(builder) {
1074
- builder.addPackage("@tsconfig/strictest").addPackage("obsidian-dev-utils").addPackage("obsidian-integration-testing").addScript("dev").addScript("build").addScript("build:clean").addScript("build:compile").addScript("find-overexposed").addScript("find-overexposed:fix").addScript("version").addScript("gate").addFiles([
1075
- // Not gated on the gitHubActions answer, and deliberately so: this attests the assets of a
1076
- // Published RELEASE, and the release flow is the preset's, not CI's. Every plugin compared here
1077
- // Ships this workflow -- they have no ci.yml at all.
1078
- ".github/workflows/attest-release-assets.yml",
1291
+ configure(builder, answers) {
1292
+ builder.addPackage("@tsconfig/strictest").addPackage("moment").addDepcheckIgnore("moment", "imported through `obsidian` rather than directly, and the typings of `obsidian` resolve it by name.").addPackage("@mnaoumov/obsidian-lib").addPackage("@mnaoumov/typescript-lib").addPackage("@mnaoumov/obsidian-dev-toolkit").addPackage("@mnaoumov/typescript-dev-toolkit").addPackage("obsidian-integration-testing").addScript("dev").addScript("build").addScript("build:clean").addScript("build:compile").addScript("find-overexposed").addScript("find-overexposed:fix").addScript("version").addScript("gate").addFiles([
1079
1293
  // Not gated on the answers either: the shared ESLint config's `obsidianmd/validate-license` compares
1080
1294
  // The LICENSE year with the current one, so without this bump every project turns red on 1 January.
1081
1295
  ".github/workflows/update-license-year.yml",
@@ -1087,18 +1301,43 @@ var Enhanced = class extends FeatureOption {
1087
1301
  "scripts/dev.ts",
1088
1302
  "scripts/gate.ts",
1089
1303
  "scripts/version.ts",
1304
+ "src/modals/sample-form-modal.ts",
1305
+ "src/modals/sample-suggest-modal.ts",
1090
1306
  "src/plugin-settings.ts",
1091
1307
  "src/plugin-settings-component.ts",
1092
1308
  "src/plugin-settings-tab.ts",
1309
+ "src/views/sample-view.ts",
1093
1310
  ...DEMO_VAULT_TEMPLATE_FILES
1094
- ]).addPartial("dev-utils");
1311
+ ]).addPartial("framework");
1312
+ if (answers.gitHubActions !== "ci-and-release") {
1313
+ builder.addFiles([".github/workflows/attest-release-assets.yml"]);
1314
+ }
1315
+ }
1316
+ };
1317
+
1318
+ // src/features/preset/docs-showcase.ts
1319
+ var DOCS_SHOWCASE_PRESET = "docs-showcase";
1320
+ var DocsShowcase = class extends FeatureOption {
1321
+ constructor() {
1322
+ super({
1323
+ promptHint: "The All-in-one Framework project, plus every code block of the Obsidian developer docs as a command you can run",
1324
+ promptLabel: "Developer docs showcase",
1325
+ settingValue: DOCS_SHOWCASE_PRESET
1326
+ });
1327
+ }
1328
+ configure(builder, answers) {
1329
+ new AllInOne().configure(builder, answers);
1330
+ builder.addPartial("all-in-one").addPackage("@codemirror/language").addPackage("@codemirror/state").addPackage("@codemirror/view").addScript("build:compile:typescript").addFiles(["scripts/build-compile-typescript.ts"]);
1331
+ if (answers.testRunner === "vitest") {
1332
+ builder.addFiles(["src/docs-showcase.desktop.integration.test.ts"]);
1333
+ }
1095
1334
  }
1096
1335
  };
1097
1336
 
1098
1337
  // src/features/preset/standalone.ts
1099
1338
  var Standalone = class extends FeatureOption {
1100
1339
  constructor() {
1101
- super({ promptHint: "Standalone plugin without obsidian-dev-utils dependency", promptLabel: "Standalone", settingValue: "standalone" });
1340
+ super({ promptHint: "Standalone plugin without the @mnaoumov library dependencies", promptLabel: "Standalone", settingValue: "standalone" });
1102
1341
  }
1103
1342
  configure(builder) {
1104
1343
  builder.addScript("dev").addScript("build").addScript("version").addFiles([
@@ -1111,9 +1350,10 @@ var Standalone = class extends FeatureOption {
1111
1350
  };
1112
1351
 
1113
1352
  // src/features/preset/index.ts
1114
- var PRESET_OPTIONS = [new Demo(), new Enhanced(), new Standalone()];
1353
+ var PRESET_OPTIONS = [new AllInOne(), new Demo(), new DocsShowcase(), new Standalone()];
1354
+ var PRESET_PROMPT_OPTIONS = [...PRESET_OPTIONS, new OfficialSample()];
1115
1355
  async function promptPreset(savedValue) {
1116
- return promptFeature({ defaultOption: new Enhanced(), message: "Choose a preset", options: PRESET_OPTIONS, savedValue });
1356
+ return promptFeature({ defaultOption: new AllInOne(), message: "Choose a preset", options: PRESET_PROMPT_OPTIONS, savedValue });
1117
1357
  }
1118
1358
 
1119
1359
  // src/features/spell-checker/cspell.ts
@@ -1142,16 +1382,25 @@ async function promptSpellChecker(savedValue) {
1142
1382
  return promptFeature({ defaultOption: new Cspell(), message: "Spell checker", options: SPELL_CHECKER_OPTIONS, savedValue });
1143
1383
  }
1144
1384
 
1385
+ // src/features/styling/toolkit-styles.ts
1386
+ function addToolkitStyles(builder, bundler, flag) {
1387
+ builder.addBuildStyles(flag).addPartial("toolkit-styles");
1388
+ if (bundler === "webpack") {
1389
+ builder.addPackage("css-loader").addDepcheckIgnore("css-loader", "resolved by name by obsidian-dev-toolkit's webpack plugin for the stylesheet rule.").addPackage("mini-css-extract-plugin").addDepcheckIgnore("mini-css-extract-plugin", "applied by obsidian-dev-toolkit's webpack plugin to extract `styles.css`.");
1390
+ }
1391
+ }
1392
+
1145
1393
  // src/features/styling/css-modules.ts
1146
1394
  var CssModules = class extends FeatureOption {
1147
1395
  constructor() {
1148
1396
  super({ promptHint: "Scoped CSS with .module.css files", promptLabel: "CSS Modules", settingValue: "css-modules" });
1149
1397
  }
1150
1398
  configure(builder, answers) {
1151
- builder.addFiles([
1152
- "src/styles/main.module.css",
1153
- "src/styles/css-modules.d.ts"
1154
- ]);
1399
+ builder.addFiles(["src/styles/css-modules.d.ts", "src/styles/main.module.css", "src/styles/sample-css-module-command.ts"]);
1400
+ if (isFrameworkPreset(answers.preset)) {
1401
+ addToolkitStyles(builder, answers.bundler, "cssModules");
1402
+ return;
1403
+ }
1155
1404
  if (answers.bundler === "rollup") {
1156
1405
  builder.addPackage("rollup-plugin-postcss").addPartial("rollup-postcss");
1157
1406
  }
@@ -1167,7 +1416,12 @@ var Css = class extends FeatureOption {
1167
1416
  super({ promptHint: "Plain CSS styles", promptLabel: "CSS", settingValue: "css" });
1168
1417
  }
1169
1418
  configure(builder, answers) {
1170
- builder.addFiles(["src/styles/main.css", "src/styles/styles.d.ts"]);
1419
+ builder.addFiles(["src/styles/main.css"]);
1420
+ if (isFrameworkPreset(answers.preset)) {
1421
+ addToolkitStyles(builder, answers.bundler);
1422
+ return;
1423
+ }
1424
+ builder.addFiles(["src/styles/styles.d.ts"]);
1171
1425
  if (answers.bundler === "rollup") {
1172
1426
  builder.addPackage("rollup-plugin-postcss").addPartial("rollup-postcss");
1173
1427
  }
@@ -1193,9 +1447,13 @@ var PostCss = class extends FeatureOption {
1193
1447
  builder.addPackage("autoprefixer").addPackage("postcss").addFiles([
1194
1448
  "postcss.config.cjs",
1195
1449
  "scripts/postcss.config.ts",
1196
- "src/styles/main.css",
1197
- "src/styles/styles.d.ts"
1450
+ "src/styles/main.css"
1198
1451
  ]);
1452
+ if (isFrameworkPreset(answers.preset)) {
1453
+ addToolkitStyles(builder, answers.bundler, "postcss");
1454
+ return;
1455
+ }
1456
+ builder.addFiles(["src/styles/styles.d.ts"]);
1199
1457
  if (answers.bundler === "esbuild") {
1200
1458
  builder.addPackage("esbuild-postcss");
1201
1459
  }
@@ -1226,8 +1484,13 @@ var Scss = class extends FeatureOption {
1226
1484
  super({ promptHint: "Sass/SCSS preprocessor", promptLabel: "SCSS", settingValue: "scss" });
1227
1485
  }
1228
1486
  configure(builder, answers) {
1229
- builder.addFiles(["src/styles/main.scss", "src/styles/styles.d.ts"]);
1230
- const plugin = isDevUtilsPreset(answers.preset) && answers.bundler === "esbuild" ? void 0 : SCSS_PLUGINS[answers.bundler];
1487
+ builder.addFiles(["src/styles/main.scss"]);
1488
+ if (isFrameworkPreset(answers.preset)) {
1489
+ builder.addPartial("toolkit-styles");
1490
+ } else {
1491
+ builder.addFiles(["src/styles/styles.d.ts"]);
1492
+ }
1493
+ const plugin = isFrameworkPreset(answers.preset) && answers.bundler === "esbuild" ? void 0 : SCSS_PLUGINS[answers.bundler];
1231
1494
  if (plugin) {
1232
1495
  builder.addPackage(plugin);
1233
1496
  const depcheckReason = SCSS_PLUGIN_DEPCHECK_REASONS[answers.bundler];
@@ -1239,7 +1502,10 @@ var Scss = class extends FeatureOption {
1239
1502
  builder.addPackage("sass-embedded").addDepcheckIgnore("sass-embedded", "the Sass compiler `esbuild-sass-plugin` peers on; nothing imports it directly.");
1240
1503
  }
1241
1504
  if (answers.bundler === "webpack") {
1242
- builder.addPackage("css-loader").addDepcheckIgnore("css-loader", "named as a loader string in `scripts/webpack.config.ts`.").addPackage("mini-css-extract-plugin").addPackage("sass").addDepcheckIgnore("sass", "the Sass compiler `sass-loader` resolves by name; nothing imports it directly.").addPartial("webpack-css-extract");
1505
+ builder.addPackage("css-loader").addDepcheckIgnore("css-loader", "named as a loader string in `scripts/webpack.config.ts`.").addPackage("mini-css-extract-plugin").addPackage("sass").addDepcheckIgnore("sass", "the Sass compiler `sass-loader` resolves by name; nothing imports it directly.");
1506
+ if (!isFrameworkPreset(answers.preset)) {
1507
+ builder.addPartial("webpack-css-extract");
1508
+ }
1243
1509
  }
1244
1510
  }
1245
1511
  };
@@ -1250,11 +1516,16 @@ var Tailwind = class extends FeatureOption {
1250
1516
  super({ promptHint: "Utility-first CSS framework", promptLabel: "Tailwind CSS", settingValue: "tailwind" });
1251
1517
  }
1252
1518
  configure(builder, answers) {
1253
- builder.addPackage("@tailwindcss/cli").addDepcheckIgnore("@tailwindcss/cli", "run as a CLI by `scripts/build-styles.ts`.").addPackage("tailwindcss").addDepcheckIgnore("tailwindcss", 'imported by `src/styles/main.css` (`@import "tailwindcss"`), which depcheck does not read.').addScript("build:styles").addFiles([
1519
+ builder.addPackage("tailwindcss").addDepcheckIgnore("tailwindcss", 'imported by `src/styles/main.css` (`@import "tailwindcss"`), which depcheck does not read.').addFiles(["src/styles/main.css"]);
1520
+ if (isFrameworkPreset(answers.preset)) {
1521
+ builder.addPackage("@tailwindcss/postcss").addDepcheckIgnore("@tailwindcss/postcss", "loaded by obsidian-dev-toolkit for its `styles.tailwind` build option.");
1522
+ addToolkitStyles(builder, answers.bundler, "tailwind");
1523
+ return;
1524
+ }
1525
+ builder.addPackage("@tailwindcss/cli").addDepcheckIgnore("@tailwindcss/cli", "run as a CLI by `scripts/build-styles.ts`.").addScript("build:styles").addFiles([
1254
1526
  "scripts/build-styles.ts",
1255
- "src/styles/main.css",
1256
1527
  "src/styles/styles.d.ts"
1257
- ]);
1528
+ ]).addPartial("tailwind-cli");
1258
1529
  if (answers.bundler === "rollup") {
1259
1530
  builder.addPackage("rollup-plugin-postcss").addPartial("rollup-postcss");
1260
1531
  }
@@ -1273,12 +1544,12 @@ async function promptStyling(savedValue) {
1273
1544
  // src/features/test-runner/sample-unit-tests.ts
1274
1545
  function addSampleUnitTests(builder, answers) {
1275
1546
  builder.addFiles(["src/main.test.ts"]);
1276
- if (!isDevUtilsPreset(answers.preset)) {
1547
+ if (!isFrameworkPreset(answers.preset)) {
1277
1548
  return;
1278
1549
  }
1279
- builder.addFiles(["src/plugin-settings-component.test.ts"]);
1550
+ builder.addFiles(["src/plugin-settings-component.test.ts"]).addPackage("@mnaoumov/typescript-lib");
1280
1551
  if (answers.preset === "demo") {
1281
- builder.addFiles(["src/plugin-settings.test.ts"]);
1552
+ builder.addFiles(["src/plugin-settings.test.ts"]).addPackage("@mnaoumov/typescript-test-toolkit");
1282
1553
  }
1283
1554
  }
1284
1555
 
@@ -1288,7 +1559,9 @@ var Jest = class extends FeatureOption {
1288
1559
  super({ promptHint: "Feature-rich, widely adopted", promptLabel: "Jest", settingValue: "jest" });
1289
1560
  }
1290
1561
  configure(builder, answers) {
1291
- builder.addPackage("@types/jest").addPackage("jest").addPackage("jest-environment-jsdom").addDepcheckIgnore("jest-environment-jsdom", "named by `testEnvironment` in `jest.config.ts`, never imported.").addPackage("obsidian-test-mocks").addPackage("ts-jest").addScript("test").addScript("test:watch").addFiles([
1562
+ const isFramework = isFrameworkPreset(answers.preset);
1563
+ const configNames = isFramework ? "`defineObsidianPluginJestConfig` from @mnaoumov/obsidian-dev-toolkit" : "`jest.config.ts`";
1564
+ builder.addPackage("@types/jest").addPackage("jest").addPackage("jest-environment-jsdom").addDepcheckIgnore("jest-environment-jsdom", `named by \`testEnvironment\` in ${configNames}, never imported.`).addPackage("obsidian-test-mocks").addPackage("ts-jest").addDepcheckIgnore("ts-jest", `named as the TypeScript transform by ${configNames}, never imported.`).addScript("test").addScript("test:watch").addFiles([
1292
1565
  "jest.config.ts",
1293
1566
  "scripts/framework-component-stub.ts",
1294
1567
  "scripts/stylesheet-stub.ts",
@@ -1297,6 +1570,9 @@ var Jest = class extends FeatureOption {
1297
1570
  "scripts/test.ts",
1298
1571
  "scripts/test-watch.ts"
1299
1572
  ]);
1573
+ if (isFramework) {
1574
+ builder.addDepcheckIgnore("obsidian-test-mocks", "mapped onto `obsidian` and loaded as a setup file by name by `defineObsidianPluginJestConfig` from @mnaoumov/obsidian-dev-toolkit.").addPackage("@jest/globals").addDepcheckIgnore("@jest/globals", "imported by `@mnaoumov/obsidian-dev-toolkit/jest-setup`, which `defineObsidianPluginJestConfig` loads.").addScript("test:coverage").addFiles(["scripts/test-coverage.ts"]);
1575
+ }
1300
1576
  addSampleUnitTests(builder, answers);
1301
1577
  }
1302
1578
  };
@@ -1316,23 +1592,23 @@ var Vitest = class extends FeatureOption {
1316
1592
  configure(builder, answers) {
1317
1593
  builder.addPackage("jsdom").addPackage("obsidian-test-mocks").addDepcheckIgnore(
1318
1594
  "obsidian-test-mocks",
1319
- isDevUtilsPreset(answers.preset) ? "aliased and loaded as a setup file by name by `defineObsidianPluginVitestConfig` from obsidian-dev-utils." : "aliased and loaded as a setup file by name in `vitest.config.ts`."
1595
+ isFrameworkPreset(answers.preset) ? "aliased and loaded as a setup file by name by `defineObsidianPluginVitestConfig` from @mnaoumov/obsidian-dev-toolkit." : "aliased and loaded as a setup file by name in `vitest.config.ts`."
1320
1596
  ).addPackage("vitest").addScript("test").addScript("test:watch").addFiles([
1321
1597
  "vitest.config.ts",
1322
1598
  "src/plugin.test.ts",
1323
1599
  "scripts/test.ts",
1324
1600
  "scripts/test-watch.ts",
1325
- // Both presets, not just the dev-utils ones: the emitted `src/plugin.ts` reaches `src/wasm/answer.ts`
1326
- // On every preset when the `wasm` answer is chosen, so every vitest config aliases `.wasm` to
1327
- // This stub. `framework-component-stub.ts` is dev-utils-only because only those presets' `plugin.ts`
1328
- // Reaches a single-file component.
1601
+ // Both presets, not just the framework ones: the emitted `src/plugin.ts` reaches `src/wasm/answer.ts`
1602
+ // On every preset when the `wasm` answer is chosen, and registers the answered view, which may be a
1603
+ // Single-file component. So every vitest config aliases `.wasm` and `.svelte` / `.vue` to these stubs.
1329
1604
  "scripts/wasm-module-stub.ts",
1605
+ "scripts/framework-component-stub.ts",
1330
1606
  // `src/main.test.ts` imports `src/main.ts`, which imports the stylesheet -- and on `tailwind` that
1331
1607
  // File does not exist until the first build. See the stub's own comment.
1332
1608
  "scripts/stylesheet-stub.ts"
1333
1609
  ]);
1334
1610
  addSampleUnitTests(builder, answers);
1335
- if (!isDevUtilsPreset(answers.preset)) {
1611
+ if (!isFrameworkPreset(answers.preset)) {
1336
1612
  return;
1337
1613
  }
1338
1614
  builder.addPackage("@vitest/coverage-v8").addScript("test:coverage").addScript("test:integration").addScript("test:integration:android").addScript("test:integration:demo-vault").addScript("test:integration:desktop").addScript("test:integration:desktop:performance").addScript("test:integration:no-app").addFiles([
@@ -1340,7 +1616,6 @@ var Vitest = class extends FeatureOption {
1340
1616
  "scripts/test-integration-desktop.ts",
1341
1617
  "scripts/test-integration-desktop-performance.ts",
1342
1618
  "scripts/demo-vault-global-setup.ts",
1343
- "scripts/framework-component-stub.ts",
1344
1619
  "scripts/test-coverage.ts",
1345
1620
  "scripts/test-integration.ts",
1346
1621
  "scripts/test-integration-demo-vault.ts",
@@ -1392,6 +1667,10 @@ var Preact = class extends FeatureOption {
1392
1667
  "src/preact-components/sample-preact-component.tsx",
1393
1668
  "src/views/sample-preact-view.tsx"
1394
1669
  ]);
1670
+ if (isFrameworkPreset(answers.preset)) {
1671
+ builder.addBuildFramework("preact").addTsconfigExtends("@mnaoumov/obsidian-dev-toolkit/tsconfig/preact.json");
1672
+ return;
1673
+ }
1395
1674
  const plugin = BUILD_PLUGINS[answers.bundler];
1396
1675
  if (plugin) {
1397
1676
  builder.addPackage(plugin);
@@ -1419,6 +1698,10 @@ var React = class extends FeatureOption {
1419
1698
  "src/react-components/sample-react-component.tsx",
1420
1699
  "src/views/sample-react-view.tsx"
1421
1700
  ]);
1701
+ if (isFrameworkPreset(answers.preset)) {
1702
+ builder.addBuildFramework("react").addTsconfigExtends("@mnaoumov/obsidian-dev-toolkit/tsconfig/react.json");
1703
+ return;
1704
+ }
1422
1705
  const plugin = BUILD_PLUGINS2[answers.bundler];
1423
1706
  if (plugin) {
1424
1707
  builder.addPackage(plugin);
@@ -1446,6 +1729,10 @@ var Solid = class extends FeatureOption {
1446
1729
  "src/solid-components/sample-solid-component.tsx",
1447
1730
  "src/views/sample-solid-view.tsx"
1448
1731
  ]);
1732
+ if (isFrameworkPreset(answers.preset)) {
1733
+ builder.addBuildFramework("solid").addTsconfigExtends("@mnaoumov/obsidian-dev-toolkit/tsconfig/solid.json").addPackage("@babel/core").addDepcheckIgnore("@babel/core", "loaded by obsidian-dev-toolkit to compile Solid's JSX.").addPackage("babel-preset-solid").addDepcheckIgnore("babel-preset-solid", "loaded by obsidian-dev-toolkit to compile Solid's JSX.");
1734
+ return;
1735
+ }
1449
1736
  const plugin = BUILD_PLUGINS3[answers.bundler];
1450
1737
  if (plugin) {
1451
1738
  builder.addPackage(plugin);
@@ -1487,16 +1774,17 @@ var Svelte = class extends FeatureOption {
1487
1774
  "src/svelte-components/sample-svelte-component.svelte",
1488
1775
  "src/views/sample-svelte-view.ts"
1489
1776
  ]);
1490
- const isDevUtilsEsbuild = isDevUtilsPreset(answers.preset) && answers.bundler === "esbuild";
1777
+ builder.addPackage("svelte-check");
1778
+ if (isFrameworkPreset(answers.preset)) {
1779
+ builder.addBuildFramework("svelte").addTsconfigExtends("@mnaoumov/obsidian-dev-toolkit/tsconfig/svelte.json").addDepcheckIgnore("svelte-check", "run as a CLI by typescript-dev-toolkit's `build:compile`, which refuses to build without it declared.");
1780
+ return;
1781
+ }
1491
1782
  const plugin = getBuildPlugin(answers.bundler);
1492
- if (plugin !== null && !isDevUtilsEsbuild) {
1783
+ if (plugin !== null) {
1493
1784
  builder.addPackage(plugin);
1494
1785
  }
1495
- builder.addPackage("svelte-check").addDepcheckIgnore(
1496
- "svelte-check",
1497
- isDevUtilsEsbuild ? "run as a CLI by obsidian-dev-utils' `build:compile`, which refuses to build without it declared." : "run as a CLI by `scripts/build.ts`."
1498
- );
1499
- if (!isDevUtilsEsbuild && SVELTE_PREPROCESS_BUNDLERS.has(answers.bundler)) {
1786
+ builder.addDepcheckIgnore("svelte-check", "run as a CLI by `scripts/build.ts`.");
1787
+ if (SVELTE_PREPROCESS_BUNDLERS.has(answers.bundler)) {
1500
1788
  builder.addPackage("svelte-preprocess");
1501
1789
  }
1502
1790
  if (answers.bundler === "webpack") {
@@ -1527,11 +1815,19 @@ var Vue = class extends FeatureOption {
1527
1815
  super({ promptHint: "Progressive framework with SFC", promptLabel: "Vue", settingValue: "vue" });
1528
1816
  }
1529
1817
  configure(builder, answers) {
1530
- builder.addPackage("vue").addPackage(getBuildPlugin2(answers.bundler)).addPartial("ui-view").addSentenceCaseBrand("Vue").addFiles([
1818
+ builder.addPackage("vue").addPartial("ui-view").addSentenceCaseBrand("Vue").addFiles([
1531
1819
  "src/vue-components/sample-vue-component.d.ts",
1532
1820
  "src/vue-components/sample-vue-component.vue",
1533
1821
  "src/views/sample-vue-view.ts"
1534
1822
  ]);
1823
+ if (isFrameworkPreset(answers.preset)) {
1824
+ builder.addBuildFramework("vue").addPackage("unplugin-vue").addDepcheckIgnore("unplugin-vue", "loaded by obsidian-dev-toolkit to compile `.vue` components.");
1825
+ if (answers.bundler === "parcel") {
1826
+ builder.addPackage("@parcel/transformer-vue").addDepcheckIgnore("@parcel/transformer-vue", "resolved by name by `@parcel/config-default` for `.vue`; nothing imports it.");
1827
+ }
1828
+ return;
1829
+ }
1830
+ builder.addPackage(getBuildPlugin2(answers.bundler));
1535
1831
  if (answers.bundler === "rollup") {
1536
1832
  builder.addPackage("@babel/core").addPackage("@babel/preset-typescript").addPackage("@rollup/plugin-babel").addDepcheckIgnore("@babel/preset-typescript", "named as a string in `scripts/rollup.config.ts`, never imported.").addPartial("rollup-babel");
1537
1833
  }
@@ -1545,261 +1841,76 @@ function getBuildPlugin2(bundler) {
1545
1841
  if (!plugin) {
1546
1842
  throw new Error(`Unsupported bundler for Vue: ${bundler}`);
1547
1843
  }
1548
- return plugin;
1549
- }
1550
-
1551
- // src/features/ui-framework/index.ts
1552
- var UI_FRAMEWORK_OPTIONS = [new None16(), new Lit(), new Preact(), new React(), new Solid(), new Svelte(), new Vue()];
1553
- async function promptUiFramework(savedValue) {
1554
- return promptFeature({ defaultOption: new None16(), message: "UI framework", options: UI_FRAMEWORK_OPTIONS, savedValue });
1555
- }
1556
-
1557
- // src/features/wasm-support/none.ts
1558
- var None17 = class extends FeatureOption {
1559
- constructor() {
1560
- super({ promptHint: "No WASM", promptLabel: "(none)", settingValue: "none" });
1561
- }
1562
- };
1563
-
1564
- // src/features/wasm-support/wasm.ts
1565
- var WASM_PLUGINS = {
1566
- esbuild: null,
1567
- parcel: null,
1568
- rollup: "@rollup/plugin-wasm",
1569
- vite: null,
1570
- webpack: null
1571
- };
1572
- var Wasm = class extends FeatureOption {
1573
- constructor() {
1574
- super({ promptHint: "Import and use .wasm modules", promptLabel: "WASM", settingValue: "wasm" });
1575
- }
1576
- configure(builder, answers) {
1577
- const plugin = getWasmPlugin(answers.bundler);
1578
- if (plugin !== null) {
1579
- builder.addPackage(plugin);
1580
- }
1581
- builder.addSentenceCaseBrand("WASM");
1582
- builder.addFiles([
1583
- // The one binary in the template tree, copied verbatim (see `ASSET_EXTENSIONS`). 39 bytes, one
1584
- // Export, `answer()`, returning 42 -- the sample module from CodeScript Toolkit's demo vault.
1585
- "src/wasm/module.wasm",
1586
- // Its source in WebAssembly text format. Documentation only: nothing in the build reads it, and it
1587
- // Is here so the binary beside it is not opaque.
1588
- "src/wasm/module.wat",
1589
- "src/wasm.d.ts",
1590
- "src/wasm/answer.ts",
1591
- "src/wasm/sample-command.ts",
1592
- "src/wasm/README.md"
1593
- ]);
1594
- if (isDevUtilsPreset(answers.preset)) {
1595
- builder.addFiles(["demo-vault/03 WebAssembly.md"]);
1596
- }
1597
- }
1598
- };
1599
- function getWasmPlugin(bundler) {
1600
- if (!Object.hasOwn(WASM_PLUGINS, bundler)) {
1601
- throw new Error(`Unsupported bundler for WASM: ${bundler}`);
1602
- }
1603
- return WASM_PLUGINS[bundler] ?? null;
1604
- }
1605
-
1606
- // src/features/wasm-support/index.ts
1607
- var WASM_SUPPORT_OPTIONS = [new None17(), new Wasm()];
1608
- async function promptWasmSupport(savedValue) {
1609
- return promptFeature({ defaultOption: new None17(), message: "WebAssembly support", options: WASM_SUPPORT_OPTIONS, savedValue });
1610
- }
1611
-
1612
- // src/answer-space.ts
1613
- var SAMPLE_FUNDING_URL = "https://example.com/support-testuser";
1614
- var SAMPLE_OBSIDIAN_CONFIG_FOLDER = "demo-vault/.obsidian";
1615
- var ANSWER_SPACE = [
1616
- toDimension("apiSubset", API_SUBSET_OPTIONS),
1617
- toDimension("bundler", BUNDLER_OPTIONS),
1618
- toDimension("commitLinting", COMMIT_LINTING_OPTIONS),
1619
- toDimension("coverageBadge", COVERAGE_BADGE_OPTIONS),
1620
- toDimension("e2eTestRunner", E2E_TEST_RUNNER_OPTIONS),
1621
- toDimension("editorExtensions", EDITOR_EXTENSIONS_OPTIONS),
1622
- toDimension("formatter", FORMATTER_OPTIONS),
1623
- toDimension("fundingPlatform", FUNDING_PLATFORM_OPTIONS),
1624
- toValueDimension("fundingUrl", ["", SAMPLE_FUNDING_URL]),
1625
- toDimension("gitHubActions", GITHUB_ACTIONS_OPTIONS),
1626
- toDimension("gitHubIssueTemplates", GITHUB_ISSUE_TEMPLATES_OPTIONS),
1627
- toDimension("hotReload", HOT_RELOAD_OPTIONS),
1628
- toDimension("internationalization", INTERNATIONALIZATION_OPTIONS),
1629
- toDimension("linter", LINTER_OPTIONS),
1630
- toDimension("markdownLinter", MARKDOWN_LINTER_OPTIONS),
1631
- toValueDimension("obsidianConfigFolder", ["", SAMPLE_OBSIDIAN_CONFIG_FOLDER]),
1632
- toDimension("packageManager", PACKAGE_MANAGER_OPTIONS),
1633
- toDimension("platformSupport", PLATFORM_SUPPORT_OPTIONS),
1634
- toDimension("preset", PRESET_OPTIONS),
1635
- toDimension("spellChecker", SPELL_CHECKER_OPTIONS),
1636
- toDimension("styling", STYLING_OPTIONS),
1637
- toDimension("testRunner", TEST_RUNNER_OPTIONS),
1638
- toDimension("uiFramework", UI_FRAMEWORK_OPTIONS),
1639
- toDimension("wasmSupport", WASM_SUPPORT_OPTIONS)
1640
- ];
1641
- var ANSWER_SPACE_SIZE = ANSWER_SPACE.reduce((size, dimension) => size * dimension.values.length, 1);
1642
- var ANSWER_SPACE_DIMENSION_SIZES = ANSWER_SPACE.map((dimension) => dimension.values.length);
1643
- function toDimension(answerKey, options) {
1644
- return {
1645
- answerKey,
1646
- values: options.map((option) => option.settingValue)
1647
- };
1648
- }
1649
- function toValueDimension(answerKey, values) {
1650
- return { answerKey, values };
1651
- }
1652
-
1653
- // src/answers.ts
1654
- var CONFIG_FILE_NAME = ".create-obsidian-plugin.json";
1655
- function getPluginShortName(pluginId) {
1656
- return pluginId.split("-").map((word) => (word[0] ?? "").toUpperCase() + word.slice(1)).join("");
1657
- }
1658
-
1659
- // src/directory-constraints.ts
1660
- var CORE_FEATURE_NAMES = [
1661
- "Audio recorder",
1662
- "Backlinks",
1663
- "Bases",
1664
- "Bookmarks",
1665
- "Canvas",
1666
- "Command palette",
1667
- "Daily notes",
1668
- "File recovery",
1669
- "Files",
1670
- "Footnotes",
1671
- "Format converter",
1672
- "Graph view",
1673
- "Live Preview",
1674
- "Note composer",
1675
- "Outgoing links",
1676
- "Outline",
1677
- "Page preview",
1678
- "Properties view",
1679
- "Publish",
1680
- "Quick Switcher",
1681
- "Random note",
1682
- "Reading view",
1683
- "Search",
1684
- "Slash commands",
1685
- "Slides",
1686
- "Source mode",
1687
- "Sync",
1688
- "Tags view",
1689
- "Templates",
1690
- "Unique note creator",
1691
- "Web viewer",
1692
- "Word count",
1693
- "Workspaces"
1694
- ];
1695
- var MAX_DESCRIPTION_LENGTH = 250;
1696
- var MIN_DESCRIPTION_LENGTH = 10;
1697
- var ALLOWED_ID_CHARACTERS = /^[a-z0-9-]+$/;
1698
- var ALLOWED_NAME_CHARACTERS = /^[A-Za-z0-9 \-+()]+$/;
1699
- var EMOJI = /\p{Extended_Pictographic}/u;
1700
- var OBSIDIAN_WORD = /\bobsidian\b/i;
1701
- var OBSIDIAN_NAME_VARIANTS = /obsi|sidian/i;
1702
- var SELF_REFERENCE_PATTERNS = [
1703
- /\bthis plugin\b/i,
1704
- /\bthis is a plugin\b/i,
1705
- /\ba plugin (?:that|which)\b/i,
1706
- /^the plugin\b/i,
1707
- /^plugin\b/i
1708
- ];
1709
- function findUnlistableManifestAnswers(answers) {
1710
- const checked = [
1711
- { key: "pluginId", message: validatePluginId(answers.pluginId), value: answers.pluginId },
1712
- { key: "pluginName", message: validatePluginName(answers.pluginName), value: answers.pluginName },
1713
- { key: "pluginDescription", message: validatePluginDescription(answers.pluginDescription), value: answers.pluginDescription }
1714
- ];
1715
- const problems = [];
1716
- for (const { key, message, value } of checked) {
1717
- if (message !== void 0) {
1718
- problems.push({ key, message, value });
1719
- }
1720
- }
1721
- return problems;
1722
- }
1723
- function validatePluginDescription(input) {
1724
- if (!input) {
1725
- return "Should not be empty";
1726
- }
1727
- if (EMOJI.test(input)) {
1728
- return "Should not contain emoji -- the Community directory rejects them, though it does accept ordinary punctuation such as backticks, em dashes and parentheses";
1729
- }
1730
- if (OBSIDIAN_WORD.test(input)) {
1731
- return 'Should not contain the word "Obsidian" -- the Community directory rejects it as implied by the plugin directory, even though no Obsidian document says so';
1732
- }
1733
- if (SELF_REFERENCE_PATTERNS.some((pattern) => pattern.test(input))) {
1734
- return 'Should say what the plugin does rather than refer to itself -- the Community directory rejects "This plugin..." and "a plugin that...". Naming another plugin is fine';
1735
- }
1736
- if (input.length < MIN_DESCRIPTION_LENGTH) {
1737
- return `Should be at least ${String(MIN_DESCRIPTION_LENGTH)} characters, so it says what the plugin does`;
1738
- }
1739
- if (input.length > MAX_DESCRIPTION_LENGTH) {
1740
- return `Should be at most ${String(MAX_DESCRIPTION_LENGTH)} characters -- the Community directory rejects a longer one`;
1741
- }
1742
- if (!/^[A-Z]/.test(input)) {
1743
- return 'Should start with a capital letter, ideally on an action verb: "Translates selected text...", "Imports notes from..."';
1744
- }
1745
- if (!input.endsWith(".")) {
1746
- return "Should end with a dot";
1747
- }
1748
- return void 0;
1749
- }
1750
- function validatePluginId(input) {
1751
- if (!input) {
1752
- return "Should not be empty";
1753
- }
1754
- if (!ALLOWED_ID_CHARACTERS.test(input)) {
1755
- return "Should contain only lowercase English letters, digits and hyphens";
1756
- }
1757
- if (!/^[a-z]/.test(input)) {
1758
- return "Should start with a letter";
1759
- }
1760
- if (!/[a-z0-9]$/.test(input)) {
1761
- return "Should end with a letter or digit";
1762
- }
1763
- if (input.includes("obsidian")) {
1764
- return 'Should not contain "obsidian" anywhere -- the Community directory rejects it as implied by the plugin directory, and an id can never be changed once the plugin is published';
1765
- }
1766
- if (input.endsWith("plugin")) {
1767
- return 'Should not end with "plugin" -- the Community directory rejects it as implied, and an id can never be changed once the plugin is published';
1768
- }
1769
- return void 0;
1844
+ return plugin;
1770
1845
  }
1771
- function validatePluginName(input) {
1772
- if (!input) {
1773
- return "Should not be empty";
1774
- }
1775
- if (OBSIDIAN_NAME_VARIANTS.test(input)) {
1776
- return 'Should not contain "Obsidian" or an abbreviation of it ("Obsi", "sidian") -- the Community directory rejects it as implied by the plugin directory';
1846
+
1847
+ // src/features/ui-framework/index.ts
1848
+ var UI_FRAMEWORK_OPTIONS = [new None16(), new Lit(), new Preact(), new React(), new Solid(), new Svelte(), new Vue()];
1849
+ async function promptUiFramework(savedValue) {
1850
+ return promptFeature({ defaultOption: new None16(), message: "UI framework", options: UI_FRAMEWORK_OPTIONS, savedValue });
1851
+ }
1852
+
1853
+ // src/features/wasm-support/none.ts
1854
+ var None17 = class extends FeatureOption {
1855
+ constructor() {
1856
+ super({ promptHint: "No WASM", promptLabel: "(none)", settingValue: "none" });
1777
1857
  }
1778
- if (input.toLowerCase().includes("plugin")) {
1779
- return 'Should not contain "Plugin" -- the Community directory rejects it as implied by the plugin directory';
1858
+ };
1859
+
1860
+ // src/features/wasm-support/wasm.ts
1861
+ var WASM_PLUGINS = {
1862
+ esbuild: null,
1863
+ parcel: null,
1864
+ rollup: "@rollup/plugin-wasm",
1865
+ vite: null,
1866
+ webpack: null
1867
+ };
1868
+ var Wasm = class extends FeatureOption {
1869
+ constructor() {
1870
+ super({ promptHint: "Import and use .wasm modules", promptLabel: "WASM", settingValue: "wasm" });
1780
1871
  }
1781
- const coreName = findCoreFeatureName(input);
1782
- if (coreName !== void 0) {
1783
- return `Should not be the name of an Obsidian core plugin or core feature -- "${coreName}" is one, and the Community directory rejects a name that takes it`;
1872
+ configure(builder, answers) {
1873
+ const isFramework = isFrameworkPreset(answers.preset);
1874
+ if (isFramework) {
1875
+ builder.addBuildOption("wasm", "true").addPartial("wasm-adapter");
1876
+ } else {
1877
+ const plugin = getWasmPlugin(answers.bundler);
1878
+ if (plugin !== null) {
1879
+ builder.addPackage(plugin);
1880
+ }
1881
+ builder.addFiles(["src/wasm.d.ts"]).addPartial(`wasm-${answers.bundler}`);
1882
+ }
1883
+ builder.addSentenceCaseBrand("WASM");
1884
+ builder.addFiles([
1885
+ // The one binary in the template tree, copied verbatim (see `ASSET_EXTENSIONS`). 39 bytes, one
1886
+ // Export, `answer()`, returning 42 -- the sample module from `CodeScript Toolkit`'s demo vault.
1887
+ "src/wasm/module.wasm",
1888
+ // Its source in WebAssembly text format. Documentation only: nothing in the build reads it, and it
1889
+ // Is here so the binary beside it is not opaque.
1890
+ "src/wasm/module.wat",
1891
+ "src/wasm/answer.ts",
1892
+ "src/wasm/sample-command.ts",
1893
+ "src/wasm/README.md"
1894
+ ]);
1895
+ if (isFramework) {
1896
+ builder.addFiles(["demo-vault/03 WebAssembly.md"]);
1897
+ }
1784
1898
  }
1785
- if (!ALLOWED_NAME_CHARACTERS.test(input)) {
1786
- return "Should use Basic Latin letters and digits only, with hyphens, plus signs and parentheses the only punctuation the Community directory accepts";
1899
+ };
1900
+ function getWasmPlugin(bundler) {
1901
+ if (!Object.hasOwn(WASM_PLUGINS, bundler)) {
1902
+ throw new Error(`Unsupported bundler for WASM: ${bundler}`);
1787
1903
  }
1788
- return void 0;
1789
- }
1790
- function findCoreFeatureName(name) {
1791
- const normalized = name.trim().toLowerCase();
1792
- return CORE_FEATURE_NAMES.find((candidate) => candidate.toLowerCase() === normalized);
1904
+ return WASM_PLUGINS[bundler] ?? null;
1793
1905
  }
1794
1906
 
1795
- // src/prompts.ts
1796
- import {
1797
- cancel as cancel2,
1798
- log
1799
- } from "@clack/prompts";
1800
- import { styleText as styleText3 } from "node:util";
1907
+ // src/features/wasm-support/index.ts
1908
+ var WASM_SUPPORT_OPTIONS = [new None17(), new Wasm()];
1909
+ async function promptWasmSupport(savedValue) {
1910
+ return promptFeature({ defaultOption: new None17(), message: "WebAssembly support", options: WASM_SUPPORT_OPTIONS, savedValue });
1911
+ }
1801
1912
 
1802
- // src/clack-text.ts
1913
+ // src/prompts/clack-text.ts
1803
1914
  import {
1804
1915
  settings as settings2,
1805
1916
  TextPrompt
@@ -1807,7 +1918,7 @@ import {
1807
1918
  import {
1808
1919
  S_BAR as S_BAR2,
1809
1920
  S_BAR_END as S_BAR_END2,
1810
- symbol as symbol2
1921
+ symbol as $symbol2
1811
1922
  } from "@clack/prompts";
1812
1923
  import { styleText as styleText2 } from "node:util";
1813
1924
  var TextPromptWithCompletion = class extends TextPrompt {
@@ -1836,7 +1947,7 @@ async function text(opts) {
1836
1947
  render() {
1837
1948
  const withGuide = settings2.withGuide;
1838
1949
  const header = `${withGuide ? `${styleText2("gray", S_BAR2)}
1839
- ` : ""}${symbol2(this.state)} ${opts.message}
1950
+ ` : ""}${$symbol2(this.state)} ${opts.message}
1840
1951
  `;
1841
1952
  const placeholderDisplay = opts.placeholder ? styleText2("inverse", opts.placeholder[0] ?? "") + styleText2("dim", opts.placeholder.slice(1)) : styleText2(["inverse", "hidden"], "_");
1842
1953
  const input = this.userInput ? this.userInputWithCursor : placeholderDisplay;
@@ -1890,7 +2001,31 @@ ${barEnd}
1890
2001
  return throwGoBackOnCancel(result) ?? "";
1891
2002
  }
1892
2003
 
1893
- // src/prompts.ts
2004
+ // src/prompts/prompts.ts
2005
+ var MAX_HINTED_CHANGES = 3;
2006
+ var TOOLING_QUESTIONS = {
2007
+ bundler: { message: "Bundler", options: BUNDLER_OPTIONS },
2008
+ uiFramework: { message: "UI framework", options: UI_FRAMEWORK_OPTIONS },
2009
+ linter: { message: "Linter", options: LINTER_OPTIONS },
2010
+ formatter: { message: "Formatter", options: FORMATTER_OPTIONS },
2011
+ spellChecker: { message: "Spell checker", options: SPELL_CHECKER_OPTIONS },
2012
+ markdownLinter: { message: "Markdown linter", options: MARKDOWN_LINTER_OPTIONS },
2013
+ testRunner: { message: "Unit testing", options: TEST_RUNNER_OPTIONS },
2014
+ e2eTestRunner: { message: "E2E testing", options: E2E_TEST_RUNNER_OPTIONS },
2015
+ editorExtensions: { message: "Editor extensions", options: EDITOR_EXTENSIONS_OPTIONS },
2016
+ styling: { message: "Styling", options: STYLING_OPTIONS },
2017
+ wasmSupport: { message: "WebAssembly support", options: WASM_SUPPORT_OPTIONS },
2018
+ commitLinting: { message: "Commit linting", options: COMMIT_LINTING_OPTIONS },
2019
+ hotReload: { message: "Hot reload", options: HOT_RELOAD_OPTIONS },
2020
+ internationalization: { message: "Internationalization", options: INTERNATIONALIZATION_OPTIONS },
2021
+ gitHubActions: { message: "GitHub Actions", options: GITHUB_ACTIONS_OPTIONS },
2022
+ gitHubIssueTemplates: { message: "GitHub issue templates", options: GITHUB_ISSUE_TEMPLATES_OPTIONS },
2023
+ coverageBadge: { message: "Coverage badge", options: COVERAGE_BADGE_OPTIONS },
2024
+ apiSubset: { message: "Obsidian API subset", options: API_SUBSET_OPTIONS },
2025
+ packageManager: { message: "Package manager", options: PACKAGE_MANAGER_OPTIONS },
2026
+ platformSupport: { message: "Platform support", options: PLATFORM_SUPPORT_OPTIONS }
2027
+ };
2028
+ var API_SUBSET_PRESETS = ["all-in-one", "docs-showcase"];
1894
2029
  var DEFAULT_PLUGIN_ID = "my-awesome-helper";
1895
2030
  function getDefaultAnswers(defaults) {
1896
2031
  const pluginId = defaults?.pluginId ?? DEFAULT_PLUGIN_ID;
@@ -1909,10 +2044,10 @@ function getDefaultAnswers(defaults) {
1909
2044
  function makePluginName(pluginId) {
1910
2045
  return extractWords(pluginId).join(" ");
1911
2046
  }
1912
- async function promptAnswers(defaults) {
2047
+ async function promptAnswers(defaults, supplied = defaults ?? {}) {
1913
2048
  showHotkeyHints();
1914
2049
  const defaultTooling = getDefaultTooling();
1915
- const steps = skipSuppliedAnswers(buildPromptSteps(defaults ?? {}, defaultTooling), defaults ?? {});
2050
+ const steps = skipSuppliedAnswers(buildPromptSteps(defaults ?? {}, supplied, defaultTooling), supplied);
1916
2051
  const answers = await runPromptSteps(steps);
1917
2052
  return buildAnswers(answers, defaultTooling);
1918
2053
  }
@@ -1922,6 +2057,9 @@ function validateNotEmpty(value) {
1922
2057
  }
1923
2058
  return void 0;
1924
2059
  }
2060
+ function asksApiSubset(preset) {
2061
+ return API_SUBSET_PRESETS.includes(preset ?? "");
2062
+ }
1925
2063
  function buildAnswers(answers, defaultTooling) {
1926
2064
  function get(key, fallback) {
1927
2065
  return answers.get(key) ?? fallback;
@@ -1931,7 +2069,7 @@ function buildAnswers(answers, defaultTooling) {
1931
2069
  apiSubset: get("apiSubset", defaultTooling.apiSubset),
1932
2070
  authorGitHubName: get("authorGitHubName", "johndoe"),
1933
2071
  authorName: get("authorName", "John Doe"),
1934
- bundler: get("bundler", "esbuild"),
2072
+ bundler: get("bundler", defaultTooling.bundler),
1935
2073
  commitLinting: get("commitLinting", defaultTooling.commitLinting),
1936
2074
  coverageBadge: get("coverageBadge", defaultTooling.coverageBadge),
1937
2075
  currentYear: (/* @__PURE__ */ new Date()).getFullYear(),
@@ -1949,154 +2087,165 @@ function buildAnswers(answers, defaultTooling) {
1949
2087
  linter: get("linter", defaultTooling.linter),
1950
2088
  markdownLinter: get("markdownLinter", defaultTooling.markdownLinter),
1951
2089
  obsidianConfigFolder: get("obsidianConfigFolder", ""),
1952
- packageManager: get("packageManager", "npm"),
1953
- platformSupport: get("platformSupport", "desktop-only"),
2090
+ packageManager: get("packageManager", defaultTooling.packageManager),
2091
+ platformSupport: get("platformSupport", defaultTooling.platformSupport),
1954
2092
  pluginDescription: get("pluginDescription", "Does something awesome."),
1955
2093
  pluginId,
1956
2094
  pluginName: get("pluginName", makePluginName(pluginId)),
1957
- preset: get("preset", "enhanced"),
2095
+ preset: get("preset", "all-in-one"),
1958
2096
  spellChecker: get("spellChecker", defaultTooling.spellChecker),
1959
2097
  styling: get("styling", defaultTooling.styling),
1960
2098
  testRunner: get("testRunner", defaultTooling.testRunner),
1961
- uiFramework: get("uiFramework", "none"),
2099
+ uiFramework: get("uiFramework", defaultTooling.uiFramework),
1962
2100
  wasmSupport: get("wasmSupport", defaultTooling.wasmSupport)
1963
2101
  };
1964
2102
  }
1965
- function buildPromptSteps(d, defaultTooling) {
2103
+ function buildPromptSteps(d, supplied, defaultTooling) {
1966
2104
  function isCustomize(answers) {
1967
2105
  return answers.get("toolingMode") === "customize";
1968
2106
  }
1969
2107
  function skipUnlessCustomize(answers) {
1970
2108
  return !isCustomize(answers);
1971
2109
  }
2110
+ function tooling(key, answers) {
2111
+ if (answers.get("toolingMode") === "defaults" && supplied[key] === void 0) {
2112
+ return defaultTooling[key];
2113
+ }
2114
+ return d[key] ?? defaultTooling[key];
2115
+ }
2116
+ function changes(answers) {
2117
+ return findToolingChanges(d, supplied, defaultTooling, answers.get("preset"));
2118
+ }
1972
2119
  return [
1973
2120
  {
1974
- defaultValue: () => d.preset ?? "enhanced",
2121
+ defaultValue: () => d.preset ?? "all-in-one",
1975
2122
  key: "preset",
1976
2123
  prompt: (saved) => promptPreset(saved)
1977
2124
  },
1978
2125
  {
1979
- defaultValue: () => "defaults",
2126
+ // A skipped `Tooling` keeps what was saved, which is what the question offers first when there is any.
2127
+ defaultValue: (answers) => changes(answers).length > 0 ? "keep" : "defaults",
1980
2128
  key: "toolingMode",
1981
- prompt: () => promptToolingMode(),
1982
- skip: (answers) => answers.get("preset") === "demo"
2129
+ prompt: (saved, answers) => promptToolingMode(saved, changes(answers)),
2130
+ // The official sample is upstream's tooling as it is, so there is nothing to customize.
2131
+ skip: (answers) => answers.get("preset") === "demo" || isOfficialSamplePreset(answers.get("preset"))
1983
2132
  },
1984
2133
  {
1985
- defaultValue: (answers) => answers.get("preset") === "demo" ? "esbuild" : d.bundler ?? "esbuild",
2134
+ defaultValue: (answers) => answers.get("preset") === "demo" ? "esbuild" : tooling("bundler", answers),
1986
2135
  key: "bundler",
1987
2136
  prompt: (saved) => promptBundler(saved),
1988
2137
  skip: skipUnlessCustomize
1989
2138
  },
1990
2139
  {
1991
- defaultValue: (answers) => answers.get("preset") === "demo" ? "none" : d.uiFramework ?? "none",
2140
+ defaultValue: (answers) => answers.get("preset") === "demo" ? "none" : tooling("uiFramework", answers),
1992
2141
  key: "uiFramework",
1993
2142
  prompt: (saved) => promptUiFramework(saved),
1994
2143
  skip: skipUnlessCustomize
1995
2144
  },
1996
2145
  {
1997
- defaultValue: () => d.linter ?? defaultTooling.linter,
2146
+ defaultValue: (answers) => tooling("linter", answers),
1998
2147
  key: "linter",
1999
2148
  prompt: (saved) => promptLinter(saved),
2000
2149
  skip: skipUnlessCustomize
2001
2150
  },
2002
2151
  {
2003
- defaultValue: () => d.formatter ?? defaultTooling.formatter,
2152
+ defaultValue: (answers) => tooling("formatter", answers),
2004
2153
  key: "formatter",
2005
2154
  prompt: (saved) => promptFormatter(saved),
2006
2155
  skip: skipUnlessCustomize
2007
2156
  },
2008
2157
  {
2009
- defaultValue: () => d.spellChecker ?? defaultTooling.spellChecker,
2158
+ defaultValue: (answers) => tooling("spellChecker", answers),
2010
2159
  key: "spellChecker",
2011
2160
  prompt: (saved) => promptSpellChecker(saved),
2012
2161
  skip: skipUnlessCustomize
2013
2162
  },
2014
2163
  {
2015
- defaultValue: () => d.markdownLinter ?? defaultTooling.markdownLinter,
2164
+ defaultValue: (answers) => tooling("markdownLinter", answers),
2016
2165
  key: "markdownLinter",
2017
2166
  prompt: (saved) => promptMarkdownLinter(saved),
2018
2167
  skip: skipUnlessCustomize
2019
2168
  },
2020
2169
  {
2021
- defaultValue: () => d.testRunner ?? defaultTooling.testRunner,
2170
+ defaultValue: (answers) => tooling("testRunner", answers),
2022
2171
  key: "testRunner",
2023
2172
  prompt: (saved) => promptTestRunner(saved),
2024
2173
  skip: skipUnlessCustomize
2025
2174
  },
2026
2175
  {
2027
- defaultValue: () => d.e2eTestRunner ?? defaultTooling.e2eTestRunner,
2176
+ defaultValue: (answers) => tooling("e2eTestRunner", answers),
2028
2177
  key: "e2eTestRunner",
2029
2178
  prompt: (saved) => promptE2eTestRunner(saved),
2030
2179
  skip: skipUnlessCustomize
2031
2180
  },
2032
2181
  {
2033
- defaultValue: () => d.editorExtensions ?? defaultTooling.editorExtensions,
2182
+ defaultValue: (answers) => tooling("editorExtensions", answers),
2034
2183
  key: "editorExtensions",
2035
2184
  prompt: (saved) => promptEditorExtensions(saved),
2036
2185
  skip: skipUnlessCustomize
2037
2186
  },
2038
2187
  {
2039
- defaultValue: () => d.styling ?? defaultTooling.styling,
2188
+ defaultValue: (answers) => tooling("styling", answers),
2040
2189
  key: "styling",
2041
2190
  prompt: (saved) => promptStyling(saved),
2042
2191
  skip: skipUnlessCustomize
2043
2192
  },
2044
2193
  {
2045
- defaultValue: () => d.wasmSupport ?? defaultTooling.wasmSupport,
2194
+ defaultValue: (answers) => tooling("wasmSupport", answers),
2046
2195
  key: "wasmSupport",
2047
2196
  prompt: (saved) => promptWasmSupport(saved),
2048
2197
  skip: skipUnlessCustomize
2049
2198
  },
2050
2199
  {
2051
- defaultValue: () => d.commitLinting ?? defaultTooling.commitLinting,
2200
+ defaultValue: (answers) => tooling("commitLinting", answers),
2052
2201
  key: "commitLinting",
2053
2202
  prompt: (saved) => promptCommitLinting(saved),
2054
2203
  skip: skipUnlessCustomize
2055
2204
  },
2056
2205
  {
2057
- defaultValue: () => d.hotReload ?? defaultTooling.hotReload,
2206
+ defaultValue: (answers) => tooling("hotReload", answers),
2058
2207
  key: "hotReload",
2059
2208
  prompt: (saved) => promptHotReload(saved),
2060
2209
  skip: skipUnlessCustomize
2061
2210
  },
2062
2211
  {
2063
- defaultValue: () => d.internationalization ?? defaultTooling.internationalization,
2212
+ defaultValue: (answers) => tooling("internationalization", answers),
2064
2213
  key: "internationalization",
2065
2214
  prompt: (saved) => promptInternationalization(saved),
2066
2215
  skip: skipUnlessCustomize
2067
2216
  },
2068
2217
  {
2069
- defaultValue: () => d.gitHubActions ?? defaultTooling.gitHubActions,
2218
+ defaultValue: (answers) => tooling("gitHubActions", answers),
2070
2219
  key: "gitHubActions",
2071
2220
  prompt: (saved) => promptGitHubActions(saved),
2072
2221
  skip: skipUnlessCustomize
2073
2222
  },
2074
2223
  {
2075
- defaultValue: () => d.gitHubIssueTemplates ?? defaultTooling.gitHubIssueTemplates,
2224
+ defaultValue: (answers) => tooling("gitHubIssueTemplates", answers),
2076
2225
  key: "gitHubIssueTemplates",
2077
2226
  prompt: (saved) => promptGitHubIssueTemplates(saved),
2078
2227
  skip: skipUnlessCustomize
2079
2228
  },
2080
2229
  {
2081
- defaultValue: () => d.coverageBadge ?? defaultTooling.coverageBadge,
2230
+ defaultValue: (answers) => tooling("coverageBadge", answers),
2082
2231
  key: "coverageBadge",
2083
2232
  prompt: (saved) => promptCoverageBadge(saved),
2084
2233
  skip: skipUnlessCustomize
2085
2234
  },
2086
2235
  {
2087
- defaultValue: () => d.apiSubset ?? defaultTooling.apiSubset,
2236
+ defaultValue: (answers) => tooling("apiSubset", answers),
2088
2237
  key: "apiSubset",
2089
2238
  prompt: (saved) => promptApiSubset(saved),
2090
- skip: (answers) => !(isCustomize(answers) && answers.get("preset") === "enhanced")
2239
+ skip: (answers) => !(isCustomize(answers) && asksApiSubset(answers.get("preset")))
2091
2240
  },
2092
2241
  {
2093
- defaultValue: () => d.packageManager ?? "npm",
2242
+ defaultValue: (answers) => tooling("packageManager", answers),
2094
2243
  key: "packageManager",
2095
2244
  prompt: (saved) => promptPackageManager(saved),
2096
2245
  skip: skipUnlessCustomize
2097
2246
  },
2098
2247
  {
2099
- defaultValue: () => d.platformSupport ?? "desktop-only",
2248
+ defaultValue: (answers) => tooling("platformSupport", answers),
2100
2249
  key: "platformSupport",
2101
2250
  prompt: (saved) => promptPlatformSupport(saved),
2102
2251
  skip: skipUnlessCustomize
@@ -2187,37 +2336,59 @@ function buildPromptSteps(d, defaultTooling) {
2187
2336
  defaultValue: saved || void 0,
2188
2337
  message: "Path to test vault config folder (.obsidian, by default, but it is configurable in Obsidian settings). This enables auto-update of your plugin in your test vault during dev. Leave empty if you prefer to update the plugin manually.",
2189
2338
  placeholder: saved || "path/to/test-vault/.obsidian"
2190
- })
2339
+ }),
2340
+ // Upstream builds into the project folder and copies nothing into a vault.
2341
+ skip: (answers) => isOfficialSamplePreset(answers.get("preset"))
2191
2342
  }
2192
2343
  ];
2193
2344
  }
2345
+ function describeChanges(changes, describe) {
2346
+ const named = changes.slice(0, MAX_HINTED_CHANGES).map(describe).join(", ");
2347
+ const rest = changes.length - MAX_HINTED_CHANGES;
2348
+ return rest > 0 ? `${named}, and ${String(rest)} more` : named;
2349
+ }
2194
2350
  function extractWords(pluginId) {
2195
2351
  return pluginId.split("-").map((w) => (w[0] ?? "").toUpperCase() + w.slice(1));
2196
2352
  }
2353
+ function findToolingChanges(d, supplied, defaultTooling, preset) {
2354
+ const changes = [];
2355
+ for (const [key, question] of Object.entries(TOOLING_QUESTIONS)) {
2356
+ const saved = d[key];
2357
+ if (saved === void 0 || supplied[key] !== void 0 || saved === defaultTooling[key]) {
2358
+ continue;
2359
+ }
2360
+ if (key === "apiSubset" && !asksApiSubset(preset)) {
2361
+ continue;
2362
+ }
2363
+ changes.push({
2364
+ question: question.message,
2365
+ recommended: getOptionLabel(question, defaultTooling[key]),
2366
+ saved: getOptionLabel(question, saved)
2367
+ });
2368
+ }
2369
+ return changes;
2370
+ }
2197
2371
  function getDefaultAnswersBase(pluginId) {
2198
2372
  return {
2199
2373
  ...getDefaultTooling(),
2200
2374
  authorGitHubName: "johndoe",
2201
2375
  authorName: "John Doe",
2202
- bundler: "esbuild",
2203
2376
  currentYear: (/* @__PURE__ */ new Date()).getFullYear(),
2204
2377
  defaultBranch: "main",
2205
2378
  fundingPlatform: "buy-me-a-coffee",
2206
2379
  fundingUrl: "",
2207
2380
  fundingUsername: "johndoe",
2208
2381
  obsidianConfigFolder: "",
2209
- packageManager: "npm",
2210
- platformSupport: "desktop-only",
2211
2382
  pluginDescription: "Does something awesome.",
2212
2383
  pluginId,
2213
2384
  pluginName: makePluginName(pluginId),
2214
- preset: "enhanced",
2215
- uiFramework: "none"
2385
+ preset: "all-in-one"
2216
2386
  };
2217
2387
  }
2218
2388
  function getDefaultTooling() {
2219
2389
  return {
2220
2390
  apiSubset: "official",
2391
+ bundler: "esbuild",
2221
2392
  commitLinting: "conventional-commits",
2222
2393
  coverageBadge: "none",
2223
2394
  e2eTestRunner: "none",
@@ -2229,12 +2400,18 @@ function getDefaultTooling() {
2229
2400
  internationalization: "none",
2230
2401
  linter: "eslint",
2231
2402
  markdownLinter: "markdownlint",
2403
+ packageManager: "npm",
2404
+ platformSupport: "desktop-only",
2232
2405
  spellChecker: "cspell",
2233
2406
  styling: "scss",
2234
2407
  testRunner: "vitest",
2408
+ uiFramework: "none",
2235
2409
  wasmSupport: "none"
2236
2410
  };
2237
2411
  }
2412
+ function getOptionLabel(question, value) {
2413
+ return question.options.find((option) => option.settingValue === value)?.promptLabel ?? value;
2414
+ }
2238
2415
  function promptPluginDescription(saved) {
2239
2416
  const value = saved || void 0;
2240
2417
  return text({
@@ -2253,13 +2430,29 @@ function promptPluginName(saved) {
2253
2430
  validate: validatePluginName
2254
2431
  });
2255
2432
  }
2256
- async function promptToolingMode() {
2433
+ async function promptToolingMode(savedValue, changes) {
2434
+ const customize = { hint: "Choose each tool individually", label: "Customize", value: "customize" };
2435
+ if (changes.length === 0) {
2436
+ return select({
2437
+ initialValue: savedValue,
2438
+ message: "Tooling",
2439
+ options: [
2440
+ customize,
2441
+ { hint: "ESLint, dprint, SCSS, Vitest, and more", label: "Use recommended defaults", value: "defaults" }
2442
+ ]
2443
+ });
2444
+ }
2257
2445
  return select({
2258
- initialValue: "defaults",
2446
+ initialValue: savedValue,
2259
2447
  message: "Tooling",
2260
2448
  options: [
2261
- { hint: "Choose each tool individually", label: "Customize", value: "customize" },
2262
- { hint: "ESLint, dprint, SCSS, Vitest, and more", label: "Use recommended defaults", value: "defaults" }
2449
+ { hint: describeChanges(changes, (change) => `${change.question}: ${change.saved}`), label: "Keep current tooling", value: "keep" },
2450
+ customize,
2451
+ {
2452
+ hint: describeChanges(changes, (change) => `${change.question}: ${change.saved} -> ${change.recommended}`),
2453
+ label: "Use recommended defaults",
2454
+ value: "defaults"
2455
+ }
2263
2456
  ]
2264
2457
  });
2265
2458
  }
@@ -2275,7 +2468,7 @@ async function runPromptSteps(steps) {
2275
2468
  }
2276
2469
  try {
2277
2470
  const savedValue = answers.get(step.key) ?? step.defaultValue(answers);
2278
- answers.set(step.key, await step.prompt(savedValue));
2471
+ answers.set(step.key, await step.prompt(savedValue, answers));
2279
2472
  i++;
2280
2473
  } catch (error) {
2281
2474
  if (!(error instanceof GoBackError)) {
@@ -2315,7 +2508,70 @@ function skipSuppliedAnswers(steps, supplied) {
2315
2508
  }));
2316
2509
  }
2317
2510
 
2318
- // src/cli-args.ts
2511
+ // src/answers/answer-space.ts
2512
+ var SAMPLE_FUNDING_URL = "https://example.com/support-testuser";
2513
+ var SAMPLE_OBSIDIAN_CONFIG_FOLDER = "demo-vault/.obsidian";
2514
+ var ANSWER_SPACE = [
2515
+ toDimension("apiSubset", API_SUBSET_OPTIONS),
2516
+ toDimension("bundler", BUNDLER_OPTIONS),
2517
+ toDimension("commitLinting", COMMIT_LINTING_OPTIONS),
2518
+ toDimension("coverageBadge", COVERAGE_BADGE_OPTIONS),
2519
+ toDimension("e2eTestRunner", E2E_TEST_RUNNER_OPTIONS),
2520
+ toDimension("editorExtensions", EDITOR_EXTENSIONS_OPTIONS),
2521
+ toDimension("formatter", FORMATTER_OPTIONS),
2522
+ toDimension("fundingPlatform", FUNDING_PLATFORM_OPTIONS),
2523
+ toValueDimension("fundingUrl", ["", SAMPLE_FUNDING_URL]),
2524
+ toDimension("gitHubActions", GITHUB_ACTIONS_OPTIONS),
2525
+ toDimension("gitHubIssueTemplates", GITHUB_ISSUE_TEMPLATES_OPTIONS),
2526
+ toDimension("hotReload", HOT_RELOAD_OPTIONS),
2527
+ toDimension("internationalization", INTERNATIONALIZATION_OPTIONS),
2528
+ toDimension("linter", LINTER_OPTIONS),
2529
+ toDimension("markdownLinter", MARKDOWN_LINTER_OPTIONS),
2530
+ toValueDimension("obsidianConfigFolder", ["", SAMPLE_OBSIDIAN_CONFIG_FOLDER]),
2531
+ toDimension("packageManager", PACKAGE_MANAGER_OPTIONS),
2532
+ toDimension("platformSupport", PLATFORM_SUPPORT_OPTIONS),
2533
+ toDimension("preset", PRESET_OPTIONS),
2534
+ toDimension("spellChecker", SPELL_CHECKER_OPTIONS),
2535
+ toDimension("styling", STYLING_OPTIONS),
2536
+ toDimension("testRunner", TEST_RUNNER_OPTIONS),
2537
+ toDimension("uiFramework", UI_FRAMEWORK_OPTIONS),
2538
+ toDimension("wasmSupport", WASM_SUPPORT_OPTIONS)
2539
+ ];
2540
+ var ANSWER_SPACE_SIZE = ANSWER_SPACE.reduce((size, dimension) => size * dimension.values.length, 1);
2541
+ var ANSWER_SPACE_DIMENSION_SIZES = ANSWER_SPACE.map((dimension) => dimension.values.length);
2542
+ function toDimension(answerKey, options) {
2543
+ return {
2544
+ answerKey,
2545
+ values: options.map((option) => option.settingValue)
2546
+ };
2547
+ }
2548
+ function toValueDimension(answerKey, values) {
2549
+ return { answerKey, values };
2550
+ }
2551
+
2552
+ // src/answers/answers.ts
2553
+ var CONFIG_FILE_NAME = ".create-obsidian-plugin.json";
2554
+ function getPluginShortName(pluginId) {
2555
+ return pluginId.split("-").map((word) => (word[0] ?? "").toUpperCase() + word.slice(1)).join("");
2556
+ }
2557
+
2558
+ // src/answers/deprecated-answers.ts
2559
+ import { log as log2 } from "@clack/prompts";
2560
+ var DEPRECATED_ANSWER_VALUES = {
2561
+ preset: {
2562
+ enhanced: "all-in-one"
2563
+ }
2564
+ };
2565
+ function resolveDeprecatedAnswer(key, value, source) {
2566
+ const replacement = DEPRECATED_ANSWER_VALUES[key]?.[value];
2567
+ if (replacement === void 0) {
2568
+ return value;
2569
+ }
2570
+ log2.warn(`${key} "${value}" in ${source} is deprecated and was read as "${replacement}". Use "${replacement}" instead.`);
2571
+ return replacement;
2572
+ }
2573
+
2574
+ // src/answers/cli-args.ts
2319
2575
  var COMPUTED_ANSWER_KEYS = ["currentYear"];
2320
2576
  var DERIVED_TEMPLATE_KEYS = ["pluginShortName"];
2321
2577
  var REFUSED_KEYS = [...COMPUTED_ANSWER_KEYS, ...DERIVED_TEMPLATE_KEYS];
@@ -2323,6 +2579,7 @@ var ANSWERS_FILE_PREFIX = "--answersFile=";
2323
2579
  var CUSTOM_TEMPLATE_PREFIX = "--customTemplate=";
2324
2580
  var MODE_PREFIX = "--mode=";
2325
2581
  var MODES = ["create" /* Create */, "update" /* Update */];
2582
+ var MODE_BY_VALUE = new Map(MODES.map((mode) => [mode, mode]));
2326
2583
  var FLAG_PREFIX_LENGTH = 2;
2327
2584
  var FREE_TEXT_VALIDATORS = {
2328
2585
  authorGitHubName: validateNotEmpty,
@@ -2334,6 +2591,9 @@ var FREE_TEXT_VALIDATORS = {
2334
2591
  pluginName: validatePluginName
2335
2592
  };
2336
2593
  var DEMO_PINNED_ANSWER_KEYS = ["bundler", "uiFramework"];
2594
+ var VALUES_OUTSIDE_ANSWER_SPACE = {
2595
+ preset: [OFFICIAL_SAMPLE_PRESET]
2596
+ };
2337
2597
  function assertValidAnswer(key, value) {
2338
2598
  const dimension = findChoiceDimension(key);
2339
2599
  if (dimension) {
@@ -2366,6 +2626,8 @@ function getHelpText() {
2366
2626
  " --customTemplate=<dir> Layer your own templates over the built-in ones: a directory",
2367
2627
  " mirroring templates/default, plus an overlay.json. Recorded in the",
2368
2628
  " project and re-applied on update; pass it empty to drop it.",
2629
+ " --latest With --preset=official-sample: copy obsidianmd/obsidian-sample-plugin",
2630
+ " as it is upstream today, not the snapshot this release vendored.",
2369
2631
  "",
2370
2632
  "Answers (any of these may be given as --<key>=<value>):"
2371
2633
  ];
@@ -2380,6 +2642,7 @@ function parseCliArgs(argv) {
2380
2642
  let answersFilePath = null;
2381
2643
  let customTemplate;
2382
2644
  let force = false;
2645
+ let latest = false;
2383
2646
  let mode;
2384
2647
  let showHelp = false;
2385
2648
  let useDefaults = false;
@@ -2404,27 +2667,40 @@ function parseCliArgs(argv) {
2404
2667
  force = true;
2405
2668
  continue;
2406
2669
  }
2670
+ if (argument === "--latest") {
2671
+ latest = true;
2672
+ continue;
2673
+ }
2407
2674
  if (argument.startsWith(MODE_PREFIX)) {
2408
2675
  mode = toMode(argument.slice(MODE_PREFIX.length));
2409
2676
  continue;
2410
2677
  }
2411
- const [rawKey, value] = splitFlag(argument);
2678
+ const [rawKey, rawValue] = splitFlag(argument);
2412
2679
  const key = toAnswerKey(rawKey);
2413
- assertValidAnswer(key, value);
2414
- flagAnswers[key] = value;
2680
+ flagAnswers[key] = resolveAnswer(key, rawValue, `--${key}`);
2415
2681
  }
2416
2682
  const fileAnswers = answersFilePath === null ? {} : readAnswersFile(answersFilePath);
2417
- const answers = { ...fileAnswers, ...flagAnswers };
2683
+ const isOfficialSample = isOfficialSamplePreset(flagAnswers.preset ?? fileAnswers.preset);
2684
+ if (isOfficialSample) {
2685
+ assertNoOfficialSampleConflict(flagAnswers);
2686
+ }
2687
+ const answers = { ...isOfficialSample ? pickOfficialSampleAnswers(fileAnswers) : fileAnswers, ...flagAnswers };
2418
2688
  assertNoDemoConflict(answers);
2419
2689
  return {
2420
2690
  answers,
2421
2691
  customTemplate,
2422
2692
  force,
2693
+ latest,
2423
2694
  mode,
2424
2695
  showHelp,
2425
2696
  useDefaults
2426
2697
  };
2427
2698
  }
2699
+ function resolveAnswer(key, value, source) {
2700
+ const resolved = resolveDeprecatedAnswer(key, value, source);
2701
+ assertValidAnswer(key, resolved);
2702
+ return resolved;
2703
+ }
2428
2704
  function toAnswerKey(key) {
2429
2705
  if (REFUSED_KEYS.includes(key)) {
2430
2706
  throw new Error(`${key} is computed by the generator, not answered, so it cannot be set.`);
@@ -2445,12 +2721,23 @@ function assertNoDemoConflict(answers) {
2445
2721
  }
2446
2722
  }
2447
2723
  }
2724
+ function assertNoOfficialSampleConflict(answers) {
2725
+ const conflicting = Object.keys(answers).filter((key) => answers[key] !== void 0 && !OFFICIAL_SAMPLE_ANSWER_KEYS.includes(key));
2726
+ if (conflicting.length > 0) {
2727
+ const flags = conflicting.map((key) => `--${key}`).join(", ");
2728
+ throw new Error(`preset=official-sample copies obsidianmd/obsidian-sample-plugin as it is, so it takes no ${conflicting.join(", ")}. Drop ${flags}, or choose another preset.`);
2729
+ }
2730
+ }
2448
2731
  function findChoiceDimension(key) {
2449
2732
  const dimension = ANSWER_SPACE.find((candidate) => candidate.answerKey === key);
2450
2733
  if (!dimension || dimension.values.includes("")) {
2451
2734
  return null;
2452
2735
  }
2453
- return dimension;
2736
+ const extraValues = VALUES_OUTSIDE_ANSWER_SPACE[key];
2737
+ return extraValues ? { ...dimension, values: [...dimension.values, ...extraValues] } : dimension;
2738
+ }
2739
+ function pickOfficialSampleAnswers(answers) {
2740
+ return Object.fromEntries(Object.entries(answers).filter(([key]) => OFFICIAL_SAMPLE_ANSWER_KEYS.includes(key)));
2454
2741
  }
2455
2742
  function readAnswersFile(path) {
2456
2743
  if (!existsSync(path)) {
@@ -2477,8 +2764,7 @@ function readAnswersFile(path) {
2477
2764
  throw new Error(`${rawKey} in ${path} should be a string, got ${typeof value}.`);
2478
2765
  }
2479
2766
  const key = toAnswerKey(rawKey);
2480
- assertValidAnswer(key, value);
2481
- answers[key] = value;
2767
+ answers[key] = resolveAnswer(key, value, path);
2482
2768
  }
2483
2769
  return answers;
2484
2770
  }
@@ -2493,13 +2779,14 @@ function splitFlag(argument) {
2493
2779
  return [argument.slice(FLAG_PREFIX_LENGTH, separatorIndex), argument.slice(separatorIndex + 1)];
2494
2780
  }
2495
2781
  function toMode(value) {
2496
- if (!MODES.includes(value)) {
2782
+ const mode = MODE_BY_VALUE.get(value);
2783
+ if (mode === void 0) {
2497
2784
  throw new Error(`"${value}" is not a mode. It accepts: ${MODES.join(", ")}.`);
2498
2785
  }
2499
- return value;
2786
+ return mode;
2500
2787
  }
2501
2788
 
2502
- // src/answers-export.ts
2789
+ // src/answers/answers-export.ts
2503
2790
  var CREATE_COMMANDS = {
2504
2791
  bun: { prefix: "bun create @mnaoumov/obsidian-plugin", separator: "" },
2505
2792
  npm: { prefix: "npm create @mnaoumov/obsidian-plugin", separator: " --" },
@@ -2536,6 +2823,9 @@ function formatCreateScript(answers, shell, customTemplate) {
2536
2823
  }
2537
2824
  function getExportableKeys(answers) {
2538
2825
  const keys = getAnswerableKeys();
2826
+ if (isOfficialSamplePreset(answers.preset)) {
2827
+ return keys.filter((key) => OFFICIAL_SAMPLE_ANSWER_KEYS.includes(key));
2828
+ }
2539
2829
  if (answers.preset !== "demo") {
2540
2830
  return keys;
2541
2831
  }
@@ -2554,7 +2844,7 @@ function quote(value, shell) {
2554
2844
  return `'${value.replaceAll("'", "'\\''")}'`;
2555
2845
  }
2556
2846
 
2557
- // src/directory-registry.ts
2847
+ // src/directory/directory-registry.ts
2558
2848
  var COMMUNITY_PLUGINS_JSON_URL = "https://raw.githubusercontent.com/obsidianmd/obsidian-releases/master/community-plugins.json";
2559
2849
  async function fetchCommunityPluginIds() {
2560
2850
  try {
@@ -2589,49 +2879,51 @@ function validatePluginIdIsUnlisted(pluginId, listedIds) {
2589
2879
  return `"${pluginId}" is already the id of a plugin in the Community directory -- the directory requires every id to be unique, and an id can never be changed once the plugin is published`;
2590
2880
  }
2591
2881
 
2592
- // src/overlay.ts
2593
- import {
2594
- existsSync as existsSync4,
2595
- readdirSync as readdirSync2,
2596
- readFileSync as readFileSync4,
2597
- statSync as statSync2
2598
- } from "node:fs";
2599
- import {
2600
- isAbsolute,
2601
- join as join3,
2602
- relative,
2603
- resolve
2604
- } from "node:path";
2605
-
2606
- // src/plan-checks.ts
2607
- import {
2608
- existsSync as existsSync3,
2609
- readdirSync,
2610
- readFileSync as readFileSync3,
2611
- statSync
2612
- } from "node:fs";
2613
- import {
2614
- extname as extname2,
2615
- join as join2
2616
- } from "node:path";
2882
+ // src/official-sample.ts
2883
+ import { join as join5 } from "node:path";
2617
2884
 
2618
2885
  // src/templates.ts
2619
- import { log as log3 } from "@clack/prompts";
2886
+ import { log as log4 } from "@clack/prompts";
2620
2887
  import ejs from "ejs";
2621
2888
  import { createHash } from "node:crypto";
2622
2889
  import {
2623
- existsSync as existsSync2,
2890
+ existsSync as existsSync4,
2624
2891
  mkdirSync,
2625
- readFileSync as readFileSync2,
2892
+ readFileSync as readFileSync3,
2626
2893
  writeFileSync
2627
2894
  } from "node:fs";
2628
2895
  import {
2629
2896
  dirname,
2630
2897
  extname,
2631
- join
2898
+ join as join3
2632
2899
  } from "node:path";
2633
2900
  import { fileURLToPath } from "node:url";
2634
2901
 
2902
+ // src/docs-showcase/docs-showcase-files.ts
2903
+ import {
2904
+ existsSync as existsSync2,
2905
+ readdirSync,
2906
+ readFileSync as readFileSync2
2907
+ } from "node:fs";
2908
+ import {
2909
+ join,
2910
+ relative
2911
+ } from "node:path";
2912
+ var DOCS_SHOWCASE_TREE_DIR = join("src", "docs");
2913
+ var DOCS_SHOWCASE_FILES_DIR = join("templates", "docs-showcase", "files");
2914
+ var DOCS_SHOWCASE_HOST_DIR = join("templates", "docs-showcase", "host");
2915
+ var DOCS_SHOWCASE_REPORT_PATH = join("templates", "docs-showcase", "snippets.json");
2916
+ function readDocsShowcaseFiles(packageRoot) {
2917
+ const filesDir = join(packageRoot, DOCS_SHOWCASE_FILES_DIR);
2918
+ if (!existsSync2(filesDir)) {
2919
+ return [];
2920
+ }
2921
+ return readdirSync(filesDir, { recursive: true, withFileTypes: true }).filter((entry) => entry.isFile()).map((entry) => join(entry.parentPath, entry.name)).sort((a, b) => a.localeCompare(b)).map((fullPath) => ({
2922
+ content: readFileSync2(fullPath, "utf-8"),
2923
+ destinationPath: relative(filesDir, fullPath).replaceAll("\\", "/")
2924
+ }));
2925
+ }
2926
+
2635
2927
  // src/template-builder.ts
2636
2928
  var PARTIAL_NAME_PATTERN = /^[a-z0-9]+(?:-[a-z0-9]+)*$/;
2637
2929
  var Dependency = class {
@@ -2647,10 +2939,31 @@ var Dependency = class {
2647
2939
  this.version = version;
2648
2940
  }
2649
2941
  };
2942
+ var FRAMEWORKS_ESBUILD_COMPILES_UNASKED = /* @__PURE__ */ new Set(["preact", "react", "svelte"]);
2650
2943
  var TemplateBuilder = class {
2651
2944
  get badges() {
2652
2945
  return [...this._badges];
2653
2946
  }
2947
+ /**
2948
+ * The options every obsidian-dev-toolkit bundler adapter takes, as `key: <TypeScript literal>` source, sorted by key.
2949
+ *
2950
+ * `framework` is a single value, and only `preset: demo` registers more than one, a set it builds only with esbuild.
2951
+ * There the toolkit compiles Svelte, React and Preact unasked, so the framework that needs the option is the one
2952
+ * passed.
2953
+ */
2954
+ get buildOptions() {
2955
+ const options = new Map(this._buildOptions);
2956
+ const frameworks = [...this._buildFrameworks];
2957
+ const framework = frameworks.length > 1 ? frameworks.find((name) => !FRAMEWORKS_ESBUILD_COMPILES_UNASKED.has(name)) : frameworks[0];
2958
+ if (framework !== void 0) {
2959
+ options.set("framework", `'${framework}'`);
2960
+ }
2961
+ if (this._buildStyles !== null) {
2962
+ const flags = [...this._buildStyles].sort((a, b) => a.localeCompare(b));
2963
+ options.set("styles", flags.length === 0 ? "{}" : `{ ${flags.map((flag) => `${flag}: true`).join(", ")} }`);
2964
+ }
2965
+ return [...options.entries()].map(([key, value]) => ({ key, value })).sort((a, b) => a.key.localeCompare(b.key));
2966
+ }
2654
2967
  get depcheckIgnores() {
2655
2968
  return [...this._depcheckIgnores.entries()].map(([packageName, reason]) => ({ packageName, reason })).sort((a, b) => a.packageName.localeCompare(b.packageName));
2656
2969
  }
@@ -2658,7 +2971,7 @@ var TemplateBuilder = class {
2658
2971
  return [...this._dependencies.values()].sort((a, b) => a.packageName.localeCompare(b.packageName));
2659
2972
  }
2660
2973
  get lintStagedPatterns() {
2661
- return [...this._lintStagedPatterns.entries()].map(([pattern, commands]) => ({ commands: [...commands], pattern }));
2974
+ return [...this._lintStagedPatterns.entries()].map(([pattern, commands]) => ({ commands: [...commands], pattern })).sort((a, b) => a.pattern.localeCompare(b.pattern));
2662
2975
  }
2663
2976
  get partials() {
2664
2977
  return new Set(this._partials);
@@ -2672,7 +2985,16 @@ var TemplateBuilder = class {
2672
2985
  get templateFiles() {
2673
2986
  return new Set(this._templateFiles);
2674
2987
  }
2988
+ /**
2989
+ * The configs the emitted `tsconfig.json` extends after its base, in registration order.
2990
+ */
2991
+ get tsconfigExtends() {
2992
+ return [...this._tsconfigExtends];
2993
+ }
2675
2994
  _badges = [];
2995
+ _buildFrameworks = /* @__PURE__ */ new Set();
2996
+ _buildOptions = /* @__PURE__ */ new Map();
2997
+ _buildStyles = null;
2676
2998
  _depcheckIgnores = /* @__PURE__ */ new Map();
2677
2999
  _dependencies = /* @__PURE__ */ new Map();
2678
3000
  _lintStagedPatterns = /* @__PURE__ */ new Map();
@@ -2680,6 +3002,7 @@ var TemplateBuilder = class {
2680
3002
  _scripts = {};
2681
3003
  _sentenceCaseBrands = /* @__PURE__ */ new Set();
2682
3004
  _templateFiles = /* @__PURE__ */ new Set();
3005
+ _tsconfigExtends = /* @__PURE__ */ new Set();
2683
3006
  /**
2684
3007
  * Registers a README badge, rendered in registration order on the line under the title.
2685
3008
  *
@@ -2691,6 +3014,35 @@ var TemplateBuilder = class {
2691
3014
  this._badges.push(markdown);
2692
3015
  return this;
2693
3016
  }
3017
+ /**
3018
+ * Registers a UI framework the obsidian-dev-toolkit bundler adapters compile, through their `framework` option.
3019
+ */
3020
+ addBuildFramework(framework) {
3021
+ this._buildFrameworks.add(framework);
3022
+ return this;
3023
+ }
3024
+ /**
3025
+ * Registers an obsidian-dev-toolkit bundler adapter option other than `framework` and `styles`.
3026
+ *
3027
+ * @param key - The option name.
3028
+ * @param value - The option's value, as TypeScript source.
3029
+ */
3030
+ addBuildOption(key, value) {
3031
+ this._buildOptions.set(key, value);
3032
+ return this;
3033
+ }
3034
+ /**
3035
+ * Turns on the adapters' `styles` option, which compiles the project's plain stylesheets, with a flag of it if given.
3036
+ *
3037
+ * @param flag - `postcss`, `tailwind` or `cssModules`; omitted, the stylesheets are compiled as plain CSS.
3038
+ */
3039
+ addBuildStyles(flag) {
3040
+ this._buildStyles ??= /* @__PURE__ */ new Set();
3041
+ if (flag !== void 0) {
3042
+ this._buildStyles.add(flag);
3043
+ }
3044
+ return this;
3045
+ }
2694
3046
  /**
2695
3047
  * Registers a declared package that depcheck reports as unused although it is not -- one only ever
2696
3048
  * invoked as a CLI, named as a string in a config, or reached by a compiler option.
@@ -2718,6 +3070,11 @@ var TemplateBuilder = class {
2718
3070
  * The commands are collected here rather than concatenated from template partials because a partial can
2719
3071
  * only ever emit `'<command>',` -- and the trailing comma the last one leaves behind is exactly what the
2720
3072
  * generated formatter config strips, so the file failed its own `format:check`.
3073
+ *
3074
+ * The patterns are rendered sorted, not in registration order: they become the keys of the emitted
3075
+ * `nano-staged-config.ts` object, which the shared ESLint config's `perfectionist/sort-objects` checks,
3076
+ * and answers register them in question order (markdownlint's `*.md` before the `*.{ts,tsx,mts}` that
3077
+ * `preset: demo` forces in). Commands under one pattern keep their order, since nano-staged runs them so.
2721
3078
  */
2722
3079
  addLintStagedCommand(pattern, command) {
2723
3080
  const commands = this._lintStagedPatterns.get(pattern) ?? [];
@@ -2755,13 +3112,69 @@ var TemplateBuilder = class {
2755
3112
  this._sentenceCaseBrands.add(brand);
2756
3113
  return this;
2757
3114
  }
3115
+ /**
3116
+ * Registers a config the emitted `tsconfig.json` extends after its base, such as a framework's JSX preset.
3117
+ *
3118
+ * Collected here rather than composed from partials for the same reason as {@link addLintStagedCommand}: the
3119
+ * `extends` value is a list whose last entry must not carry a comma, and a single entry is written as a plain string.
3120
+ */
3121
+ addTsconfigExtends(config) {
3122
+ this._tsconfigExtends.add(config);
3123
+ return this;
3124
+ }
2758
3125
  };
2759
3126
 
3127
+ // src/template-index.ts
3128
+ import {
3129
+ existsSync as existsSync3,
3130
+ readdirSync as readdirSync2,
3131
+ statSync
3132
+ } from "node:fs";
3133
+ import { join as join2 } from "node:path";
3134
+ var GROUP_FOLDER_PATTERN = /^\(.+\)$/;
3135
+ function getLogicalTemplatePath(physicalPath) {
3136
+ return physicalPath.split("/").filter((segment) => !GROUP_FOLDER_PATTERN.test(segment)).join("/");
3137
+ }
3138
+ function indexTemplateDir(root) {
3139
+ const index = /* @__PURE__ */ new Map();
3140
+ for (const physicalPath of walkFiles(root, "")) {
3141
+ const logicalPath = getLogicalTemplatePath(physicalPath);
3142
+ const existing = index.get(logicalPath);
3143
+ if (existing !== void 0) {
3144
+ throw new Error(`Two templates in ${root} resolve to ${logicalPath}: ${existing} and ${physicalPath}.`);
3145
+ }
3146
+ index.set(logicalPath, physicalPath);
3147
+ }
3148
+ return index;
3149
+ }
3150
+ function walkFiles(root, relativeDir) {
3151
+ const absoluteDir = join2(root, relativeDir);
3152
+ if (!existsSync3(absoluteDir)) {
3153
+ return [];
3154
+ }
3155
+ const found = [];
3156
+ for (const entry of readdirSync2(absoluteDir)) {
3157
+ const relativePath = relativeDir === "" ? entry : `${relativeDir}/${entry}`;
3158
+ if (statSync(join2(root, relativePath)).isDirectory()) {
3159
+ found.push(...walkFiles(root, relativePath));
3160
+ } else {
3161
+ found.push(relativePath);
3162
+ }
3163
+ }
3164
+ return found;
3165
+ }
3166
+
2760
3167
  // src/versions.ts
2761
- import { log as log2 } from "@clack/prompts";
3168
+ import { log as log3 } from "@clack/prompts";
3169
+ import {
3170
+ maxSatisfying,
3171
+ minVersion,
3172
+ subset,
3173
+ validRange
3174
+ } from "semver";
2762
3175
  var PINNED_VERSIONS = {
2763
3176
  "@babel/core": {
2764
- check: `node -e "process.stdout.write(require('@rollup/plugin-babel/package.json').peerDependencies['@babel/core'])"`,
3177
+ check: `node -e "const fs=require('node:fs');process.stdout.write(JSON.parse(fs.readFileSync('node_modules/@rollup/plugin-babel/package.json','utf8')).peerDependencies['@babel/core'])"`,
2765
3178
  checkRequires: "@rollup/plugin-babel",
2766
3179
  expect: "^7.0.0",
2767
3180
  manualCheck: null,
@@ -2771,7 +3184,7 @@ var PINNED_VERSIONS = {
2771
3184
  why: "@babel/core is only ever added alongside @rollup/plugin-babel, whose newest release still peers on `^7.0.0` while the registry tags 8.x as latest. Resolving latest therefore produced an `npm install` that fails outright with ERESOLVE for rollup with preact, react or solid. The check reads the peer range @rollup/plugin-babel itself declares, so the pin retires itself when that widens to ^8."
2772
3185
  },
2773
3186
  "@babel/plugin-transform-react-jsx": {
2774
- check: `node -e "process.stdout.write(require('@rollup/plugin-babel/package.json').peerDependencies['@babel/core'])"`,
3187
+ check: `node -e "const fs=require('node:fs');process.stdout.write(JSON.parse(fs.readFileSync('node_modules/@rollup/plugin-babel/package.json','utf8')).peerDependencies['@babel/core'])"`,
2775
3188
  checkRequires: "@rollup/plugin-babel",
2776
3189
  expect: "^7.0.0",
2777
3190
  manualCheck: null,
@@ -2781,7 +3194,7 @@ var PINNED_VERSIONS = {
2781
3194
  why: "Held on 7.x for the same reason as @babel/core, and it has to move as one set: 8.0.1 peers on `@babel/core@^8.0.0`, so pinning core to 7 without pinning this one just moves the ERESOLVE. Only ever added for rollup + preact, which is exactly where @rollup/plugin-babel forces 7."
2782
3195
  },
2783
3196
  "@babel/preset-react": {
2784
- check: `node -e "process.stdout.write(require('@rollup/plugin-babel/package.json').peerDependencies['@babel/core'])"`,
3197
+ check: `node -e "const fs=require('node:fs');process.stdout.write(JSON.parse(fs.readFileSync('node_modules/@rollup/plugin-babel/package.json','utf8')).peerDependencies['@babel/core'])"`,
2785
3198
  checkRequires: "@rollup/plugin-babel",
2786
3199
  expect: "^7.0.0",
2787
3200
  manualCheck: null,
@@ -2791,7 +3204,7 @@ var PINNED_VERSIONS = {
2791
3204
  why: "Held on 7.x for the same reason as @babel/core, and it has to move as one set: 8.0.1 peers on `@babel/core@^8.0.0`. Only ever added for rollup + react, which is exactly where @rollup/plugin-babel forces 7."
2792
3205
  },
2793
3206
  "@babel/preset-typescript": {
2794
- check: `node -e "process.stdout.write(require('@rollup/plugin-babel/package.json').peerDependencies['@babel/core'])"`,
3207
+ check: `node -e "const fs=require('node:fs');process.stdout.write(JSON.parse(fs.readFileSync('node_modules/@rollup/plugin-babel/package.json','utf8')).peerDependencies['@babel/core'])"`,
2795
3208
  checkRequires: "@rollup/plugin-babel",
2796
3209
  expect: "^7.0.0",
2797
3210
  manualCheck: null,
@@ -2813,23 +3226,73 @@ var PINNED_VERSIONS = {
2813
3226
  "@codemirror/state": {
2814
3227
  check: `node -e "process.stdout.write(require('obsidian/package.json').peerDependencies['@codemirror/state'])"`,
2815
3228
  checkRequires: "obsidian",
2816
- expect: "6.5.0",
3229
+ expect: "6.7.6",
2817
3230
  manualCheck: null,
2818
3231
  needsOverride: true,
2819
3232
  section: "devDependencies",
2820
- version: "6.5.0",
3233
+ version: "6.7.6",
2821
3234
  why: "obsidian peers on this exact version. Anything else fails npm install with ERESOLVE, and a second copy in the tree breaks editor extensions at runtime."
2822
3235
  },
2823
3236
  "@codemirror/view": {
2824
3237
  check: `node -e "process.stdout.write(require('obsidian/package.json').peerDependencies['@codemirror/view'])"`,
2825
3238
  checkRequires: "obsidian",
2826
- expect: "6.38.6",
3239
+ expect: "6.43.13",
2827
3240
  manualCheck: null,
2828
3241
  needsOverride: true,
2829
3242
  section: "devDependencies",
2830
- version: "6.38.6",
3243
+ version: "6.43.13",
2831
3244
  why: "obsidian peers on this exact version. Anything else fails npm install with ERESOLVE, and a second copy in the tree breaks editor extensions at runtime."
2832
3245
  },
3246
+ "@wdio/cli": {
3247
+ check: `node -e "const fs=require('node:fs');process.stdout.write(JSON.parse(fs.readFileSync('node_modules/wdio-obsidian-service/package.json','utf8')).peerDependencies.webdriverio)"`,
3248
+ checkRequires: "wdio-obsidian-service",
3249
+ expect: "^9.18.1",
3250
+ manualCheck: null,
3251
+ needsOverride: false,
3252
+ section: "devDependencies",
3253
+ version: "^9.32.0",
3254
+ why: "wdio-obsidian-service peers on `webdriverio ^9.18.1`, while the registry tags wdio 10 as latest. Resolving latest installed a webdriverio 10 tree beside the service and failed `npm install` with ERESOLVE. The wdio packages move as one set, and the check reads the service's own peer range, so the pin retires itself when that moves to ^10."
3255
+ },
3256
+ "@wdio/globals": {
3257
+ check: `node -e "const fs=require('node:fs');process.stdout.write(JSON.parse(fs.readFileSync('node_modules/wdio-obsidian-service/package.json','utf8')).peerDependencies.webdriverio)"`,
3258
+ checkRequires: "wdio-obsidian-service",
3259
+ expect: "^9.18.1",
3260
+ manualCheck: null,
3261
+ needsOverride: false,
3262
+ section: "devDependencies",
3263
+ version: "^9.31.3",
3264
+ why: "wdio-obsidian-service peers on `webdriverio ^9.18.1`, while the registry tags wdio 10 as latest. Resolving latest installed a webdriverio 10 tree beside the service and failed `npm install` with ERESOLVE. The wdio packages move as one set, and the check reads the service's own peer range, so the pin retires itself when that moves to ^10."
3265
+ },
3266
+ "@wdio/local-runner": {
3267
+ check: `node -e "const fs=require('node:fs');process.stdout.write(JSON.parse(fs.readFileSync('node_modules/wdio-obsidian-service/package.json','utf8')).peerDependencies.webdriverio)"`,
3268
+ checkRequires: "wdio-obsidian-service",
3269
+ expect: "^9.18.1",
3270
+ manualCheck: null,
3271
+ needsOverride: false,
3272
+ section: "devDependencies",
3273
+ version: "^9.32.0",
3274
+ why: "wdio-obsidian-service peers on `webdriverio ^9.18.1`, while the registry tags wdio 10 as latest. Resolving latest installed a webdriverio 10 tree beside the service and failed `npm install` with ERESOLVE. The wdio packages move as one set, and the check reads the service's own peer range, so the pin retires itself when that moves to ^10."
3275
+ },
3276
+ "@wdio/mocha-framework": {
3277
+ check: `node -e "const fs=require('node:fs');process.stdout.write(JSON.parse(fs.readFileSync('node_modules/wdio-obsidian-service/package.json','utf8')).peerDependencies.webdriverio)"`,
3278
+ checkRequires: "wdio-obsidian-service",
3279
+ expect: "^9.18.1",
3280
+ manualCheck: null,
3281
+ needsOverride: false,
3282
+ section: "devDependencies",
3283
+ version: "^9.32.0",
3284
+ why: "wdio-obsidian-service peers on `webdriverio ^9.18.1`, while the registry tags wdio 10 as latest. Resolving latest installed a webdriverio 10 tree beside the service and failed `npm install` with ERESOLVE. The wdio packages move as one set, and the check reads the service's own peer range, so the pin retires itself when that moves to ^10."
3285
+ },
3286
+ "expect-webdriverio": {
3287
+ check: `node -e "const fs=require('node:fs');process.stdout.write(JSON.parse(fs.readFileSync('node_modules/wdio-obsidian-service/package.json','utf8')).peerDependencies.webdriverio)"`,
3288
+ checkRequires: "wdio-obsidian-service",
3289
+ expect: "^9.18.1",
3290
+ manualCheck: null,
3291
+ needsOverride: false,
3292
+ section: "devDependencies",
3293
+ version: "^6.1.0",
3294
+ why: "Held on 6.x with the wdio packages: expect-webdriverio 7 and later peer on `webdriverio ^10`, and @wdio/globals 9 peers on `expect-webdriverio ^6`. wdio-obsidian-service peers on `webdriverio ^9.18.1`, while the registry tags wdio 10 as latest. Resolving latest installed a webdriverio 10 tree beside the service and failed `npm install` with ERESOLVE. The wdio packages move as one set, and the check reads the service's own peer range, so the pin retires itself when that moves to ^10."
3295
+ },
2833
3296
  "moment": {
2834
3297
  check: null,
2835
3298
  checkRequires: null,
@@ -2856,17 +3319,25 @@ var ADVISORY_OVERRIDES = {
2856
3319
  check: `node -e "const fs=require('node:fs');process.stdout.write(JSON.parse(fs.readFileSync('node_modules/@wdio/utils/package.json','utf8')).dependencies['@puppeteer/browsers'])"`,
2857
3320
  expect: "^2.2.0",
2858
3321
  manualCheck: "The check reads @wdio/utils's own declared range, not a version, because that range is what makes the override necessary. When it moves to ^3 or later, @wdio/utils no longer pulls extract-zip in and both this override and this entry can go.",
2859
- requires: ["obsidian-dev-utils", "wdio-obsidian-service"],
3322
+ requires: ["obsidian-integration-testing", "wdio-obsidian-service"],
2860
3323
  spec: "^3.2.1",
2861
3324
  why: "Clears GHSA-jmr9-qjv8-65gv (extract-zip unvalidated symlink path traversal). extract-zip is vulnerable at every published version, so there is nothing to override it to, and the direct dependency cannot be bumped either: even the newest webdriverio reaches extract-zip through @wdio/utils -> @puppeteer/browsers ^2.x. @puppeteer/browsers@3 replaced extract-zip with modern-tar, so forcing 3.x on @wdio/utils, the only consumer left on 2.x, removes the subtree. @wdio/utils imports only install, canDownload, resolveBuildId, detectBrowserPlatform, Browser, ChromeReleaseChannel, computeExecutablePath and the InstallOptions type, all still exported by 3.x, and both packages are ESM-only. Never take the `npm audit fix --force` remedy: it downgrades obsidian-integration-testing to 1.1.2."
2862
3325
  },
2863
3326
  "deepmerge-ts": {
2864
- check: `node -e "const fs=require('node:fs');process.stdout.write(JSON.parse(fs.readFileSync('node_modules/@wdio/utils/package.json','utf8')).dependencies['deepmerge-ts'])"`,
3327
+ check: `node -e "const fs=require('node:fs');const path=['node_modules/obsidian-integration-testing/node_modules/@wdio/utils/package.json','node_modules/@wdio/utils/package.json'].find((candidate)=>fs.existsSync(candidate));process.stdout.write(JSON.parse(fs.readFileSync(path,'utf8')).dependencies['deepmerge-ts'])"`,
2865
3328
  expect: "^7.0.3",
2866
- manualCheck: "The check reads the range @wdio/utils declares, which is what forces the override. When it moves to ^8 or later the override and this entry can go. Before lifting it, re-run the deepmergeCustom probe: @wdio/config passes a `mergeArrays` handler that reads `meta.key`, and that is the API 8.0.0 renamed.",
2867
- requires: ["obsidian-dev-utils", "wdio-obsidian-service"],
3329
+ manualCheck: "The check reads the range declared by the @wdio/utils that obsidian-integration-testing reaches, nested under it when the project also has a newer wdio, which is what forces the override. When it moves to ^8 or later the override and this entry can go. Before lifting it, re-run the deepmergeCustom probe: @wdio/config passes a `mergeArrays` handler that reads `meta.key`, and that is the API 8.0.0 renamed.",
3330
+ requires: ["obsidian-integration-testing"],
2868
3331
  spec: "^8.0.2",
2869
- why: "Clears GHSA-ggr8-5vv4-36mx (stack exhaustion merging recursive object graphs), patched in 8.0.0. Every wdio package still declares ^7.0.3, including the newest, so no direct bump reaches it and `npm audit fix --force` only offers a downgrade of obsidian-integration-testing to 1.1.2. The forced major is safe for these consumers: 8.0.0 breaks by renaming the mergeInfo system and aligning the customization shorthand, and both surfaces were measured to behave identically on 7.1.6 and 8.0.1 in the exact shapes the tree uses -- @wdio/config's `deepmergeCustom` with a `mergeArrays` handler reading `meta.key` and returning `utils.actions.defaultMerge`, and webdriver's `deepmergeCustom({ mergeArrays: false })`. A scan of the whole installed tree found no other binding than `deepmerge` and `deepmergeCustom`."
3332
+ why: "Clears GHSA-ggr8-5vv4-36mx (stack exhaustion merging recursive object graphs), patched in 8.0.0. @wdio/utils declares ^7.0.3 up to 9.30, and obsidian-integration-testing pins webdriverio 9.27.0, so no direct bump reaches it and `npm audit fix --force` only offers a downgrade of obsidian-integration-testing to 1.1.2. The forced major is safe for these consumers: 8.0.0 breaks by renaming the mergeInfo system and aligning the customization shorthand, and both surfaces were measured to behave identically on 7.1.6 and 8.0.1 in the exact shapes the tree uses -- @wdio/config's `deepmergeCustom` with a `mergeArrays` handler reading `meta.key` and returning `utils.actions.defaultMerge`, and webdriver's `deepmergeCustom({ mergeArrays: false })`. A scan of the whole installed tree found no other binding than `deepmerge` and `deepmergeCustom`."
3333
+ },
3334
+ "re2js": {
3335
+ check: `node -e "const fs=require('node:fs');process.stdout.write(JSON.parse(fs.readFileSync('node_modules/markdownlint/package.json','utf8')).dependencies.re2js)"`,
3336
+ expect: "2.8.6",
3337
+ manualCheck: "The check reads the exact re2js pin of the installed markdownlint, which moves only when a markdownlint-cli2 release pins a newer markdownlint. When it reads 2.8.7 or later, drop the override and this entry and re-run `npm audit`.",
3338
+ requires: ["markdownlint", "markdownlint-cli2", "@mnaoumov/typescript-dev-toolkit", "@mnaoumov/obsidian-dev-toolkit"],
3339
+ spec: "^2.9.1",
3340
+ why: "Clears GHSA-gg6h-894w-4m9c (RE2JS quadratic-time denial of service in lookbehind matching, >=2.2.0 <2.8.7). Reached only through markdownlint, whose newest release 0.42.0 pins re2js at the exact 2.8.6, and markdownlint-cli2 0.24.0 pins that markdownlint exactly in turn, so no bump reaches the fix. The toolkits reach it through their own markdownlint-cli2. 2.9.1 is the version markdownlint itself moved to upstream, so the forced minor is the one it is tested against. Never take the `npm audit fix --force` remedy: it downgrades the toolkit packages."
2870
3341
  },
2871
3342
  "serialize-javascript": {
2872
3343
  check: `node -e "const fs=require('node:fs');process.stdout.write(JSON.parse(fs.readFileSync('node_modules/mocha/package.json','utf8')).dependencies['serialize-javascript'])"`,
@@ -2882,6 +3353,8 @@ var FALLBACK_MIN_APP_VERSION = "1.13.0";
2882
3353
  var FALLBACK_VERSION = "latest";
2883
3354
  var JSON_INDENT_SPACES2 = 2;
2884
3355
  var REGISTRY_URL = "https://registry.npmjs.org";
3356
+ var ABBREVIATED_PACKUMENT_MEDIA_TYPE = "application/vnd.npm.install-v1+json";
3357
+ var CONSTRAINING_PACKAGES = ["@mnaoumov/obsidian-dev-toolkit", "@mnaoumov/typescript-dev-toolkit"];
2885
3358
  function buildOverrides(dependencies) {
2886
3359
  const overrides = {};
2887
3360
  for (const packageName of getPinnedPackageNames(dependencies)) {
@@ -2985,22 +3458,68 @@ async function resolveVersions(dependencies) {
2985
3458
  }
2986
3459
  unresolved.push(dependency.packageName);
2987
3460
  }
2988
- const fetched = await Promise.all(unresolved.map(fetchLatestVersion));
2989
3461
  const failed = [];
2990
- for (const [index, version] of fetched.entries()) {
2991
- const packageName = unresolved[index] ?? "";
2992
- if (version === null) {
3462
+ const constraints = /* @__PURE__ */ new Map();
3463
+ function record(packageName, resolution) {
3464
+ if (resolution === null) {
2993
3465
  failed.push(packageName);
2994
3466
  resolved.set(packageName, FALLBACK_VERSION);
3467
+ return;
3468
+ }
3469
+ resolved.set(packageName, resolution.spec);
3470
+ if (resolution.heldBelow !== null) {
3471
+ log3.info(`Holding ${packageName} on ${resolution.spec}, the range ${resolution.heldBy ?? ""} declares, rather than the latest ${resolution.heldBelow}.`);
3472
+ }
3473
+ }
3474
+ for (const constrainer of CONSTRAINING_PACKAGES) {
3475
+ if (!unresolved.includes(constrainer)) {
3476
+ continue;
3477
+ }
3478
+ const resolution = await resolveWithin(constrainer, constraints.get(constrainer));
3479
+ record(constrainer, resolution);
3480
+ if (resolution === null) {
2995
3481
  continue;
2996
3482
  }
2997
- resolved.set(packageName, `^${version}`);
3483
+ const manifest = await fetchManifest(constrainer, resolution.version);
3484
+ for (const [packageName, range] of Object.entries({ ...manifest?.peerDependencies, ...manifest?.dependencies })) {
3485
+ if (!constraints.has(packageName)) {
3486
+ constraints.set(packageName, { by: constrainer, range });
3487
+ }
3488
+ }
3489
+ }
3490
+ const rest = unresolved.filter((packageName) => !CONSTRAINING_PACKAGES.includes(packageName));
3491
+ const resolutions = await Promise.all(rest.map((packageName) => resolveWithin(packageName, constraints.get(packageName))));
3492
+ for (const [index, resolution] of resolutions.entries()) {
3493
+ record(rest[index] ?? "", resolution);
2998
3494
  }
2999
3495
  if (failed.length > 0) {
3000
- log2.warn(`Could not look up the latest version of ${failed.join(", ")}. Falling back to "${FALLBACK_VERSION}".`);
3496
+ log3.warn(`Could not look up the latest version of ${failed.join(", ")}. Falling back to "${FALLBACK_VERSION}".`);
3001
3497
  }
3002
3498
  return resolved;
3003
3499
  }
3500
+ async function fetchManifest(packageName, version) {
3501
+ try {
3502
+ const response = await fetch(`${REGISTRY_URL}/${packageName}/${version}`);
3503
+ if (!response.ok) {
3504
+ return null;
3505
+ }
3506
+ return await response.json();
3507
+ } catch {
3508
+ return null;
3509
+ }
3510
+ }
3511
+ async function fetchPublishedVersions(packageName) {
3512
+ try {
3513
+ const response = await fetch(`${REGISTRY_URL}/${packageName}`, { headers: { accept: ABBREVIATED_PACKUMENT_MEDIA_TYPE } });
3514
+ if (!response.ok) {
3515
+ return null;
3516
+ }
3517
+ const packument = await response.json();
3518
+ return Object.keys(packument.versions ?? {});
3519
+ } catch {
3520
+ return null;
3521
+ }
3522
+ }
3004
3523
  function getAdvisoryOverrides(dependencies) {
3005
3524
  return Object.entries(ADVISORY_OVERRIDES).filter(([, advisoryOverride]) => advisoryOverride.requires.some((packageName) => hasPackage(dependencies, packageName))).sort(([a], [b]) => a.localeCompare(b));
3006
3525
  }
@@ -3010,11 +3529,31 @@ function getPinnedPackageNames(dependencies) {
3010
3529
  function hasPackage(dependencies, packageName) {
3011
3530
  return dependencies.some((dependency) => dependency.packageName === packageName);
3012
3531
  }
3532
+ function isCaretWithin(version, range) {
3533
+ if (version === null || validRange(range) === null) {
3534
+ return false;
3535
+ }
3536
+ return subset(`^${version}`, range);
3537
+ }
3538
+ async function resolveWithin(packageName, constraint) {
3539
+ const latest = await fetchLatestVersion(packageName);
3540
+ if (constraint === void 0 || isCaretWithin(latest, constraint.range)) {
3541
+ return latest === null ? null : { heldBelow: null, heldBy: null, spec: `^${latest}`, version: latest };
3542
+ }
3543
+ const versions = await fetchPublishedVersions(packageName);
3544
+ const newest = versions === null ? null : maxSatisfying(versions, constraint.range);
3545
+ if (newest === null) {
3546
+ return { heldBelow: latest, heldBy: constraint.by, spec: constraint.range, version: minVersion(constraint.range)?.version ?? constraint.range };
3547
+ }
3548
+ const spec = isCaretWithin(newest, constraint.range) ? `^${newest}` : constraint.range;
3549
+ return { heldBelow: latest, heldBy: constraint.by, spec, version: newest };
3550
+ }
3013
3551
 
3014
3552
  // src/templates.ts
3015
3553
  var ASSET_EXTENSIONS = /* @__PURE__ */ new Set([".wasm"]);
3016
3554
  var JSON_INDENT_SPACES3 = 2;
3017
3555
  var UNRESOLVED_VERSION = "latest";
3556
+ var TOOLKIT_WORKFLOW_REF = "3.0.0";
3018
3557
  var BASE_TEMPLATE_FILES = [
3019
3558
  // Never empty: `tslib` and `typescript` below are false positives on every answer set.
3020
3559
  ".depcheckrc.json",
@@ -3023,6 +3562,9 @@ var BASE_TEMPLATE_FILES = [
3023
3562
  ".gitattributes",
3024
3563
  ".gitignore",
3025
3564
  ".npmrc",
3565
+ // The same Node major as this repo's own `.nvmrc`. Every CI workflow reads it, the toolkit's reusable ones by
3566
+ // Default, and without it they fall back to the latest LTS, which is not the version the project is developed on.
3567
+ ".nvmrc",
3026
3568
  "CONTRIBUTING.md",
3027
3569
  "LICENSE",
3028
3570
  "README.md",
@@ -3080,7 +3622,9 @@ var DEMO_OVERRIDES = [
3080
3622
  { answerKey: "spellChecker", demoValue: "cspell", options: SPELL_CHECKER_OPTIONS },
3081
3623
  { answerKey: "styling", demoValue: "scss", options: STYLING_OPTIONS }
3082
3624
  ];
3083
- function buildTemplate(answers, overlay = null) {
3625
+ var DEMO_PINNED_ANSWERS = { bundler: "esbuild", uiFramework: "none" };
3626
+ function buildTemplate(givenAnswers, overlay = null) {
3627
+ const answers = pinPresetAnswers(givenAnswers);
3084
3628
  const builder = new TemplateBuilder();
3085
3629
  builder.addFiles(BASE_TEMPLATE_FILES).addPackage("@types/node").addPackage("jiti").addPackage("obsidian").addPackage("tslib").addDepcheckIgnore("tslib", "never imported by name: `importHelpers: true` in `tsconfig.json` makes the compiled output import it.").addPackage("typescript").addDepcheckIgnore("typescript", "the compiler `tsconfig.json` configures, reached by `tsc`, by the TypeScript step of the bundler and by the editor rather than by an import.").addSentenceCaseBrand(answers.pluginName).addPartial("common");
3086
3630
  const funding = resolveFunding(answers);
@@ -3114,45 +3658,53 @@ function buildTemplate(answers, overlay = null) {
3114
3658
  builder.addPartial(option.partialName);
3115
3659
  }
3116
3660
  }
3661
+ if (builder.lintStagedPatterns.length > 0) {
3662
+ addStagedFilesHook(builder, answers.preset);
3663
+ }
3664
+ if (isFrameworkPreset(answers.preset) && builder.buildOptions.length > 0) {
3665
+ builder.addFiles(["scripts/build-options.ts"]);
3666
+ }
3117
3667
  if (overlay) {
3118
3668
  applyOverlay(builder, overlay);
3119
3669
  }
3120
- if (builder.lintStagedPatterns.length > 0) {
3121
- addStagedFilesHook(builder);
3122
- }
3123
3670
  return builder;
3124
3671
  }
3125
- function copyTemplates(answers, targetDir, currentVersion, existingConfig, resolvedVersions = /* @__PURE__ */ new Map(), minAppVersion = FALLBACK_MIN_APP_VERSION, overlay = null, projectFormatter) {
3126
- const templatesDir = join(getScriptDir(), "..", "templates", "default");
3672
+ function copyTemplates(givenAnswers, targetDir, currentVersion, existingConfig, resolvedVersions = /* @__PURE__ */ new Map(), minAppVersion = FALLBACK_MIN_APP_VERSION, overlay = null, projectFormatter) {
3673
+ const answers = pinPresetAnswers(givenAnswers);
3674
+ const templatesDir = join3(getScriptDir(), "..", "templates", "default");
3675
+ const overlayIndex = overlay ? indexTemplateDir(overlay.dir) : null;
3676
+ const builtInIndex = getBuiltInTemplateIndex(templatesDir);
3127
3677
  function findTemplate(relativePath) {
3128
- if (overlay) {
3129
- const overlayPath = join(overlay.dir, relativePath);
3130
- if (existsSync2(overlayPath)) {
3131
- return overlayPath;
3132
- }
3678
+ const overlayPath = overlayIndex?.get(relativePath);
3679
+ if (overlay && overlayPath !== void 0) {
3680
+ return join3(overlay.dir, overlayPath);
3133
3681
  }
3134
- const builtInPath = join(templatesDir, relativePath);
3135
- return existsSync2(builtInPath) ? builtInPath : null;
3682
+ const builtInPath = builtInIndex.get(relativePath);
3683
+ return builtInPath === void 0 ? null : join3(templatesDir, builtInPath);
3136
3684
  }
3137
- const newConfig = {
3138
- fileHashes: {},
3139
- generatorVersion: currentVersion
3140
- };
3141
3685
  const builder = buildTemplate(answers, overlay);
3142
3686
  const templateFiles = builder.templateFiles;
3143
3687
  const partials = builder.partials;
3144
3688
  const dependencies = builder.dependencies;
3689
+ const hasBuildOptions = templateFiles.has("scripts/build-options.ts");
3145
3690
  let currentTemplatePath = "";
3146
3691
  let renderRoot = "";
3147
3692
  const templateContext = {
3148
3693
  ...answers,
3149
3694
  ...getFundingTemplateContext(answers),
3150
3695
  _badges: builder.badges,
3696
+ _buildOptionsArgument: hasBuildOptions ? "buildOptions" : "",
3697
+ _buildOptionsImport: hasBuildOptions ? "\nimport { buildOptions } from './build-options.ts';\n" : "",
3698
+ _buildOptionsLiteral: toObjectLiteral(builder.buildOptions),
3699
+ _cspellIdentityWords: getCspellIdentityWords(answers),
3151
3700
  _depcheckIgnores: builder.depcheckIgnores,
3152
3701
  _dependencies: dependencies.map((dependency) => ({
3153
3702
  packageName: dependency.packageName,
3154
3703
  version: dependency.version ?? resolvedVersions.get(dependency.packageName) ?? PINNED_VERSIONS[dependency.packageName]?.version ?? UNRESOLVED_VERSION
3155
3704
  })),
3705
+ // The README's `support` seam opens `## Support` in the funding partial, so the issue-filing partial
3706
+ // After it opens the section itself only when there is no funding.
3707
+ _hasFunding: partials.has("has-funding"),
3156
3708
  _lintStagedPatterns: builder.lintStagedPatterns,
3157
3709
  _minAppVersion: minAppVersion,
3158
3710
  _overrides: Object.entries(buildOverrides(dependencies)).map(([packageName, spec]) => ({ packageName, spec })),
@@ -3161,6 +3713,8 @@ function copyTemplates(answers, targetDir, currentVersion, existingConfig, resol
3161
3713
  _resolutions: Object.entries(buildResolutions(dependencies)).map(([packageName, spec]) => ({ packageName, spec })),
3162
3714
  _scripts: builder.scripts,
3163
3715
  _sentenceCaseBrands: builder.sentenceCaseBrands,
3716
+ _toolkitWorkflowRef: TOOLKIT_WORKFLOW_REF,
3717
+ _tsconfigExtendsJson: toTsconfigExtendsJson(builder.tsconfigExtends),
3164
3718
  pluginShortName: getPluginShortName(answers.pluginId),
3165
3719
  render(options) {
3166
3720
  const { indentLevel, section } = typeof options === "string" ? { indentLevel: 0, section: options } : { indentLevel: 0, section: void 0, ...options };
@@ -3176,7 +3730,7 @@ function copyTemplates(answers, targetDir, currentVersion, existingConfig, resol
3176
3730
  }
3177
3731
  currentTemplatePath = partialPath;
3178
3732
  renderRoot = previousRenderRoot || partialPath;
3179
- let rendered = ejs.render(readFileSync2(fullPath, "utf-8"), templateContext);
3733
+ let rendered = ejs.render(readFileSync3(fullPath, "utf-8"), templateContext);
3180
3734
  if (indentLevel > 0) {
3181
3735
  const indent = " ".repeat(indentLevel);
3182
3736
  rendered = rendered.replaceAll(/^(?<Content>.+)$/gm, `${indent}$<Content>`);
@@ -3192,7 +3746,7 @@ function copyTemplates(answers, targetDir, currentVersion, existingConfig, resol
3192
3746
  *
3193
3747
  * A section that contributes imports emits them in PARTIAL order, which is the order the answers were
3194
3748
  * registered in {@link FEATURE_REGISTRIES} -- and that has nothing to do with the order an
3195
- * import-sorting lint rule wants. The obsidian-dev-utils presets now adopt that package's shared
3749
+ * import-sorting lint rule wants. The toolkit presets now adopt obsidian-dev-toolkit's shared
3196
3750
  * ESLint config, which sorts imports as an ERROR, so `uiFramework=lit editorExtensions=codemirror`
3197
3751
  * emitted a `src/plugin.ts` that was red the moment it was generated. The sorting cannot be pushed
3198
3752
  * into the partials: each one knows only itself, and which others are beside it is the answer set.
@@ -3201,75 +3755,40 @@ function copyTemplates(answers, targetDir, currentVersion, existingConfig, resol
3201
3755
  return sortImportStatements(text3);
3202
3756
  }
3203
3757
  };
3204
- const skipped = [];
3205
- const updated = [];
3206
- const created = [];
3207
- const written = [];
3758
+ const renderedFiles = [];
3208
3759
  for (const registeredPath of templateFiles) {
3209
3760
  const destinationPath = getDestinationPath(registeredPath, answers);
3210
- const fullDestinationPath = join(targetDir, destinationPath);
3211
3761
  const isAsset = ASSET_EXTENSIONS.has(extname(registeredPath));
3212
3762
  const ejsPath = findTemplate(`${registeredPath}.ejs`);
3213
3763
  let rendered;
3214
3764
  if (isAsset) {
3215
3765
  currentTemplatePath = registeredPath;
3216
- rendered = readFileSync2(findTemplate(registeredPath) ?? join(templatesDir, registeredPath));
3766
+ rendered = readFileSync3(findTemplate(registeredPath) ?? join3(templatesDir, registeredPath));
3217
3767
  } else if (ejsPath === null) {
3218
3768
  currentTemplatePath = `${registeredPath}.ejs`;
3219
3769
  rendered = templateContext["render"]();
3220
3770
  } else {
3221
3771
  currentTemplatePath = `${registeredPath}.ejs`;
3222
3772
  try {
3223
- rendered = ejs.render(readFileSync2(ejsPath, "utf-8"), templateContext);
3773
+ rendered = ejs.render(readFileSync3(ejsPath, "utf-8"), templateContext);
3224
3774
  } catch (error) {
3225
3775
  if (overlay && ejsPath.startsWith(overlay.dir)) {
3226
3776
  throw new Error(`${ejsPath} failed to render: ${error instanceof Error ? error.message : String(error)}`, { cause: error });
3227
3777
  }
3228
- rendered = readFileSync2(ejsPath, "utf-8");
3229
- }
3230
- }
3231
- const newHash = sha256(rendered);
3232
- if (existingConfig && existsSync2(fullDestinationPath)) {
3233
- const currentContent = isAsset ? readFileSync2(fullDestinationPath) : readFileSync2(fullDestinationPath, "utf-8");
3234
- const currentHash = sha256(currentContent);
3235
- const originalHash = existingConfig.fileHashes[destinationPath];
3236
- if (matchesRender(currentHash, newHash, projectFormatter, destinationPath, rendered)) {
3237
- newConfig.fileHashes[destinationPath] = currentHash;
3238
- continue;
3239
- }
3240
- if (originalHash === void 0) {
3241
- skipped.push(destinationPath);
3242
- continue;
3243
- }
3244
- if (currentHash !== originalHash) {
3245
- skipped.push(destinationPath);
3246
- newConfig.fileHashes[destinationPath] = originalHash;
3247
- continue;
3778
+ rendered = readFileSync3(ejsPath, "utf-8");
3248
3779
  }
3249
- updated.push(destinationPath);
3250
- } else {
3251
- created.push(destinationPath);
3252
- }
3253
- newConfig.fileHashes[destinationPath] = newHash;
3254
- const destDir = dirname(fullDestinationPath);
3255
- if (!existsSync2(destDir)) {
3256
- mkdirSync(destDir, { recursive: true });
3257
3780
  }
3258
- writeFileSync(fullDestinationPath, rendered);
3259
- written.push(destinationPath);
3781
+ renderedFiles.push({ content: rendered, destinationPath });
3260
3782
  }
3261
- formatWrittenFiles(projectFormatter, targetDir, written, newConfig);
3262
- const configPath = join(targetDir, CONFIG_FILE_NAME);
3263
- writeFileSync(configPath, `${JSON.stringify(newConfig, null, JSON_INDENT_SPACES3)}
3264
- `);
3265
- if (existingConfig) {
3266
- logUpdateSummary(updated, created, skipped);
3783
+ if (answers.preset === DOCS_SHOWCASE_PRESET) {
3784
+ renderedFiles.push(...readDocsShowcaseFiles(join3(getScriptDir(), "..")));
3267
3785
  }
3268
- return newConfig;
3786
+ return writeGeneratedFiles(renderedFiles, targetDir, currentVersion, existingConfig, projectFormatter);
3269
3787
  }
3270
3788
  function getDestinationPath(templatePath, answers) {
3271
3789
  return templatePath.replace(/%= (?<AnswerKey>.+?) %/g, (_match, ...args) => String(answers[String(args[0])]));
3272
3790
  }
3791
+ var builtInTemplateIndexes = /* @__PURE__ */ new Map();
3273
3792
  function getScriptDir() {
3274
3793
  return dirname(fileURLToPath(import.meta.url));
3275
3794
  }
@@ -3279,20 +3798,23 @@ function isPartialTemplatePath(templatePath) {
3279
3798
  return markerIndex > 0 && PARTIAL_NAME_PATTERN.test(fileName.slice(markerIndex + 1));
3280
3799
  }
3281
3800
  function loadConfig(dir) {
3282
- const configPath = join(dir, CONFIG_FILE_NAME);
3283
- if (!existsSync2(configPath)) {
3801
+ const configPath = join3(dir, CONFIG_FILE_NAME);
3802
+ if (!existsSync4(configPath)) {
3284
3803
  return null;
3285
3804
  }
3286
- const parsed = JSON.parse(readFileSync2(configPath, "utf-8"));
3805
+ const parsed = JSON.parse(readFileSync3(configPath, "utf-8"));
3287
3806
  const raw = parsed;
3288
3807
  migrateAnswers(raw);
3289
3808
  return parsed;
3290
3809
  }
3810
+ function pinPresetAnswers(answers) {
3811
+ return answers.preset === "demo" ? { ...answers, ...DEMO_PINNED_ANSWERS } : answers;
3812
+ }
3291
3813
  function recordHashesOnDisk(targetDir, config) {
3292
3814
  const fileHashes = {};
3293
3815
  for (const [destinationPath, hash] of Object.entries(config.fileHashes)) {
3294
- const fullPath = join(targetDir, destinationPath);
3295
- fileHashes[destinationPath] = existsSync2(fullPath) ? sha256(readFileSync2(fullPath)) : hash;
3816
+ const fullPath = join3(targetDir, destinationPath);
3817
+ fileHashes[destinationPath] = existsSync4(fullPath) ? sha256(readFileSync3(fullPath)) : hash;
3296
3818
  }
3297
3819
  return { ...config, fileHashes };
3298
3820
  }
@@ -3321,6 +3843,56 @@ function sortImportStatements(text3) {
3321
3843
  return `${statements.join("\n")}
3322
3844
  `;
3323
3845
  }
3846
+ function writeGeneratedFiles(files, targetDir, currentVersion, existingConfig, projectFormatter) {
3847
+ const newConfig = {
3848
+ fileHashes: {},
3849
+ generatorVersion: currentVersion
3850
+ };
3851
+ const skipped = [];
3852
+ const updated = [];
3853
+ const created = [];
3854
+ const written = [];
3855
+ for (const { content: rendered, destinationPath } of files) {
3856
+ const fullDestinationPath = join3(targetDir, destinationPath);
3857
+ const newHash = sha256(rendered);
3858
+ if (existingConfig && existsSync4(fullDestinationPath)) {
3859
+ const currentContent = Buffer.isBuffer(rendered) ? readFileSync3(fullDestinationPath) : readFileSync3(fullDestinationPath, "utf-8");
3860
+ const currentHash = sha256(currentContent);
3861
+ const originalHash = existingConfig.fileHashes[destinationPath];
3862
+ if (matchesRender(currentHash, newHash, projectFormatter, destinationPath, rendered)) {
3863
+ newConfig.fileHashes[destinationPath] = currentHash;
3864
+ continue;
3865
+ }
3866
+ if (originalHash === void 0) {
3867
+ skipped.push(destinationPath);
3868
+ continue;
3869
+ }
3870
+ if (currentHash !== originalHash) {
3871
+ skipped.push(destinationPath);
3872
+ newConfig.fileHashes[destinationPath] = originalHash;
3873
+ continue;
3874
+ }
3875
+ updated.push(destinationPath);
3876
+ } else {
3877
+ created.push(destinationPath);
3878
+ }
3879
+ newConfig.fileHashes[destinationPath] = newHash;
3880
+ const destDir = dirname(fullDestinationPath);
3881
+ if (!existsSync4(destDir)) {
3882
+ mkdirSync(destDir, { recursive: true });
3883
+ }
3884
+ writeFileSync(fullDestinationPath, rendered);
3885
+ written.push(destinationPath);
3886
+ }
3887
+ formatWrittenFiles(projectFormatter, targetDir, written, newConfig);
3888
+ const configPath = join3(targetDir, CONFIG_FILE_NAME);
3889
+ writeFileSync(configPath, `${JSON.stringify(newConfig, null, JSON_INDENT_SPACES3)}
3890
+ `);
3891
+ if (existingConfig) {
3892
+ logUpdateSummary(updated, created, skipped);
3893
+ }
3894
+ return newConfig;
3895
+ }
3324
3896
  function applyOverlay(builder, overlay) {
3325
3897
  builder.addFiles([...overlay.files]);
3326
3898
  for (const packageName of overlay.packages) {
@@ -3343,8 +3915,20 @@ function formatWrittenFiles(projectFormatter, targetDir, written, config) {
3343
3915
  }
3344
3916
  projectFormatter.formatFiles(textFiles);
3345
3917
  for (const destinationPath of textFiles) {
3346
- config.fileHashes[destinationPath] = sha256(readFileSync2(join(targetDir, destinationPath)));
3918
+ config.fileHashes[destinationPath] = sha256(readFileSync3(join3(targetDir, destinationPath)));
3919
+ }
3920
+ }
3921
+ function getBuiltInTemplateIndex(templatesDir) {
3922
+ let index = builtInTemplateIndexes.get(templatesDir);
3923
+ if (index === void 0) {
3924
+ index = indexTemplateDir(templatesDir);
3925
+ builtInTemplateIndexes.set(templatesDir, index);
3347
3926
  }
3927
+ return index;
3928
+ }
3929
+ function getCspellIdentityWords(answers) {
3930
+ const words = [answers.authorGitHubName, "mnaoumov"];
3931
+ return words.filter((word, index) => words.findIndex((other) => other.toLowerCase() === word.toLowerCase()) === index);
3348
3932
  }
3349
3933
  function getFundingTemplateContext(answers) {
3350
3934
  const funding = resolveFunding(answers);
@@ -3363,25 +3947,25 @@ function importedModule(block) {
3363
3947
  }
3364
3948
  function logUpdateSummary(updated, created, skipped) {
3365
3949
  if (updated.length > 0) {
3366
- log3.success(`Updated ${String(updated.length)} file(s):`);
3950
+ log4.success(`Updated ${String(updated.length)} file(s):`);
3367
3951
  for (const f of updated) {
3368
- log3.info(` ${f}`);
3952
+ log4.info(` ${f}`);
3369
3953
  }
3370
3954
  }
3371
3955
  if (created.length > 0) {
3372
- log3.success(`Created ${String(created.length)} new file(s):`);
3956
+ log4.success(`Created ${String(created.length)} new file(s):`);
3373
3957
  for (const f of created) {
3374
- log3.info(` ${f}`);
3958
+ log4.info(` ${f}`);
3375
3959
  }
3376
3960
  }
3377
3961
  if (skipped.length > 0) {
3378
- log3.warn(`Skipped ${String(skipped.length)} file(s) with local modifications:`);
3962
+ log4.warn(`Skipped ${String(skipped.length)} file(s) with local modifications:`);
3379
3963
  for (const f of skipped) {
3380
- log3.info(` ${f}`);
3964
+ log4.info(` ${f}`);
3381
3965
  }
3382
3966
  }
3383
3967
  if (updated.length === 0 && created.length === 0) {
3384
- log3.info("Everything is already up to date.");
3968
+ log4.info("Everything is already up to date.");
3385
3969
  }
3386
3970
  }
3387
3971
  function matchesRender(currentHash, newHash, projectFormatter, destinationPath, rendered) {
@@ -3416,6 +4000,11 @@ function migrateAnswers(raw) {
3416
4000
  answers["fundingUsername"] ??= answers["authorGitHubName"];
3417
4001
  answers["coverageBadge"] ??= "none";
3418
4002
  delete answers["pluginShortName"];
4003
+ for (const [key, value] of Object.entries(answers)) {
4004
+ if (typeof value === "string") {
4005
+ answers[key] = resolveDeprecatedAnswer(key, value, CONFIG_FILE_NAME);
4006
+ }
4007
+ }
3419
4008
  }
3420
4009
  function migrateFundingAnswers(answers) {
3421
4010
  if (answers["fundingPlatform"] !== void 0) {
@@ -3450,8 +4039,209 @@ function migrateFundingAnswers(answers) {
3450
4039
  function sha256(content) {
3451
4040
  return createHash("sha256").update(content).digest("hex");
3452
4041
  }
4042
+ function toObjectLiteral(options) {
4043
+ return options.length === 0 ? "{}" : `{
4044
+ ${options.map((option) => ` ${option.key}: ${option.value}`).join(",\n")}
4045
+ }`;
4046
+ }
4047
+ function toTsconfigExtendsJson(extraConfigs) {
4048
+ const base = JSON.stringify("@tsconfig/strictest/tsconfig.json");
4049
+ return extraConfigs.length === 0 ? base : `[
4050
+ ${[base, ...extraConfigs.map((config) => JSON.stringify(config))].map((config) => ` ${config}`).join(",\n")}
4051
+ ]`;
4052
+ }
4053
+
4054
+ // src/upstream-snapshot.ts
4055
+ import {
4056
+ existsSync as existsSync5,
4057
+ readdirSync as readdirSync3,
4058
+ readFileSync as readFileSync4
4059
+ } from "node:fs";
4060
+ import {
4061
+ join as join4,
4062
+ relative as relative2
4063
+ } from "node:path";
4064
+ var VENDORED_SUFFIX = ".vendored";
4065
+ var REGULAR_FILE_MODES = /* @__PURE__ */ new Set(["100644", "100755"]);
4066
+ async function fetchUpstreamSnapshot(repo, ref) {
4067
+ const headers = { Accept: "application/vnd.github+json" };
4068
+ const token = process.env["GITHUB_TOKEN"];
4069
+ if (token) {
4070
+ headers["Authorization"] = `Bearer ${token}`;
4071
+ }
4072
+ const commit = await fetchJson(`https://api.github.com/repos/${repo}/commits/${encodeURIComponent(ref)}`, headers);
4073
+ const tree = await fetchJson(`https://api.github.com/repos/${repo}/git/trees/${commit.sha}?recursive=1`, headers);
4074
+ if (tree.truncated) {
4075
+ throw new Error(`The tree of ${repo}@${commit.sha} is too large for one API response.`);
4076
+ }
4077
+ const paths = tree.tree.filter((entry) => entry.type === "blob" && REGULAR_FILE_MODES.has(entry.mode)).map((entry) => entry.path);
4078
+ const contents = await Promise.all(paths.map(async (path) => {
4079
+ const response = await fetch(`https://raw.githubusercontent.com/${repo}/${commit.sha}/${path.split("/").map(encodeURIComponent).join("/")}`);
4080
+ if (!response.ok) {
4081
+ throw new Error(`Could not download ${path} from ${repo}@${commit.sha}: HTTP ${String(response.status)}.`);
4082
+ }
4083
+ return Buffer.from(await response.arrayBuffer());
4084
+ }));
4085
+ return {
4086
+ commit: commit.sha,
4087
+ files: new Map(paths.map((path, index) => [path, contents[index] ?? Buffer.alloc(0)]))
4088
+ };
4089
+ }
4090
+ function readUpstream(upstreamsPath, name) {
4091
+ const parsed = JSON.parse(readFileSync4(upstreamsPath, "utf-8"));
4092
+ const upstream = parsed.upstreams.find((candidate) => candidate.name === name);
4093
+ if (!upstream) {
4094
+ throw new Error(`${upstreamsPath} has no upstream named "${name}".`);
4095
+ }
4096
+ return upstream;
4097
+ }
4098
+ function readVendoredFiles(dir) {
4099
+ const files = /* @__PURE__ */ new Map();
4100
+ if (!existsSync5(dir)) {
4101
+ return files;
4102
+ }
4103
+ const paths = readdirSync3(dir, { recursive: true, withFileTypes: true }).filter((entry) => entry.isFile() && entry.name.endsWith(VENDORED_SUFFIX)).map((entry) => join4(entry.parentPath, entry.name)).sort();
4104
+ for (const fullPath of paths) {
4105
+ const upstreamPath = relative2(dir, fullPath).replaceAll("\\", "/").slice(0, -VENDORED_SUFFIX.length);
4106
+ files.set(upstreamPath, readFileSync4(fullPath));
4107
+ }
4108
+ return files;
4109
+ }
4110
+ async function fetchJson(url, headers) {
4111
+ const response = await fetch(url, { headers });
4112
+ if (!response.ok) {
4113
+ throw new Error(`GET ${url} failed: HTTP ${String(response.status)}.`);
4114
+ }
4115
+ return await response.json();
4116
+ }
4117
+
4118
+ // src/official-sample.ts
4119
+ var OFFICIAL_SAMPLE_UPSTREAM_NAME = "obsidian-sample-plugin";
4120
+ var OFFICIAL_SAMPLE_FILES_DIR = join5("templates", "official-sample", "files");
4121
+ var OFFICIAL_SAMPLE_PINNED_ANSWERS = {
4122
+ formatter: "none",
4123
+ packageManager: "npm"
4124
+ };
4125
+ function applyOfficialSampleIdentity(files, answers) {
4126
+ const packageName = `obsidian-${answers.pluginId}`;
4127
+ const result = new Map(files);
4128
+ editJson(result, "manifest.json", (manifest) => {
4129
+ const fundingUrl = resolveFunding(answers)?.getUrl(answers);
4130
+ const edited = {};
4131
+ for (const [key, value] of Object.entries(manifest)) {
4132
+ switch (key) {
4133
+ case "author":
4134
+ edited[key] = answers.authorName;
4135
+ break;
4136
+ case "authorUrl":
4137
+ edited[key] = `https://github.com/${answers.authorGitHubName}`;
4138
+ break;
4139
+ case "description":
4140
+ edited[key] = answers.pluginDescription;
4141
+ break;
4142
+ case "fundingUrl":
4143
+ if (fundingUrl) {
4144
+ edited[key] = fundingUrl;
4145
+ }
4146
+ break;
4147
+ case "id":
4148
+ edited[key] = answers.pluginId;
4149
+ break;
4150
+ case "name":
4151
+ edited[key] = answers.pluginName;
4152
+ break;
4153
+ default:
4154
+ edited[key] = value;
4155
+ }
4156
+ }
4157
+ return edited;
4158
+ });
4159
+ const upstreamPackageName = readUpstreamPackageName(files);
4160
+ editJson(result, "package.json", (packageJson) => ({ ...packageJson, name: packageName }));
4161
+ editJson(result, "package-lock.json", (lock) => renamePackageInLock(lock, upstreamPackageName, packageName));
4162
+ const readme = result.get("README.md");
4163
+ if (readme) {
4164
+ result.set("README.md", Buffer.from(readme.toString("utf-8").replace(/^# .*$/m, `# ${answers.pluginName}`), "utf-8"));
4165
+ }
4166
+ return result;
4167
+ }
4168
+ function copyOfficialSample(answers, targetDir, currentVersion, existingConfig, snapshot) {
4169
+ const files = applyOfficialSampleIdentity(snapshot.files, answers);
4170
+ const config = writeGeneratedFiles(
4171
+ [...files].map(([destinationPath, content]) => ({ content, destinationPath })),
4172
+ targetDir,
4173
+ currentVersion,
4174
+ existingConfig
4175
+ );
4176
+ return { ...config, upstreamCommit: snapshot.commit };
4177
+ }
4178
+ function getPackageRoot() {
4179
+ return join5(getScriptDir(), "..");
4180
+ }
4181
+ function getUpstreamsPath() {
4182
+ return join5(getPackageRoot(), "upstreams.json");
4183
+ }
4184
+ function loadOfficialSampleSnapshot() {
4185
+ const upstream = readUpstream(getUpstreamsPath(), OFFICIAL_SAMPLE_UPSTREAM_NAME);
4186
+ const files = readVendoredFiles(join5(getPackageRoot(), OFFICIAL_SAMPLE_FILES_DIR));
4187
+ if (files.size === 0) {
4188
+ throw new Error(`The vendored snapshot of ${upstream.repo} is missing from ${OFFICIAL_SAMPLE_FILES_DIR}.`);
4189
+ }
4190
+ return { commit: upstream.commit, files };
4191
+ }
4192
+ function editJson(files, path, edit) {
4193
+ const content = files.get(path);
4194
+ if (!content) {
4195
+ return;
4196
+ }
4197
+ const text3 = content.toString("utf-8");
4198
+ const indent = /^\{\r?\n(?<Indent>[ \t]+)/.exec(text3)?.groups?.["Indent"] ?? " ";
4199
+ const finalNewline = /\r?\n$/.exec(text3)?.[0] ?? "";
4200
+ const edited = edit(JSON.parse(text3));
4201
+ files.set(path, Buffer.from(`${JSON.stringify(edited, null, indent)}${finalNewline}`, "utf-8"));
4202
+ }
4203
+ function readUpstreamPackageName(files) {
4204
+ const content = files.get("package.json");
4205
+ if (!content) {
4206
+ return void 0;
4207
+ }
4208
+ const name = JSON.parse(content.toString("utf-8"))["name"];
4209
+ return typeof name === "string" ? name : void 0;
4210
+ }
4211
+ function renamePackageInLock(lock, upstreamName, packageName) {
4212
+ const renamed = { ...lock };
4213
+ if (renamed["name"] === upstreamName) {
4214
+ renamed["name"] = packageName;
4215
+ }
4216
+ const packages = renamed["packages"];
4217
+ if (typeof packages === "object" && packages !== null) {
4218
+ const root = packages[""];
4219
+ if (typeof root === "object" && root !== null && root["name"] === upstreamName) {
4220
+ renamed["packages"] = { ...packages, "": { ...root, name: packageName } };
4221
+ }
4222
+ }
4223
+ return renamed;
4224
+ }
4225
+
4226
+ // src/overlay.ts
4227
+ import {
4228
+ existsSync as existsSync6,
4229
+ readFileSync as readFileSync6,
4230
+ statSync as statSync2
4231
+ } from "node:fs";
4232
+ import {
4233
+ isAbsolute,
4234
+ join as join7,
4235
+ relative as relative3,
4236
+ resolve
4237
+ } from "node:path";
3453
4238
 
3454
- // src/plan-checks.ts
4239
+ // src/verification/plan-checks.ts
4240
+ import { readFileSync as readFileSync5 } from "node:fs";
4241
+ import {
4242
+ extname as extname2,
4243
+ join as join6
4244
+ } from "node:path";
3455
4245
  var EJS_SUFFIX = ".ejs";
3456
4246
  var RENDER_SITE_PATTERN = /(?:<%[-=]?|\$\{)\s*render\(\s*(?:'(?<Section>[^']*)'|\{(?<Options>[^}]*)\})/g;
3457
4247
  var SECTION_OPTION_PATTERN = /section\s*:\s*'(?<Section>[^']*)'/;
@@ -3476,7 +4266,7 @@ function loadTemplateInventory(templatesDir = defaultTemplatesDir()) {
3476
4266
  const emptyTemplates = /* @__PURE__ */ new Set();
3477
4267
  const partials = [];
3478
4268
  const renderSites = [];
3479
- for (const relativePath of walkTemplates(templatesDir, "")) {
4269
+ for (const [relativePath, physicalPath] of indexTemplateDir(templatesDir)) {
3480
4270
  if (ASSET_EXTENSIONS.has(extname2(relativePath))) {
3481
4271
  assetTemplates.add(relativePath);
3482
4272
  continue;
@@ -3485,7 +4275,7 @@ function loadTemplateInventory(templatesDir = defaultTemplatesDir()) {
3485
4275
  continue;
3486
4276
  }
3487
4277
  const withoutSuffix = relativePath.slice(0, -EJS_SUFFIX.length);
3488
- const body = readFileSync3(join2(templatesDir, relativePath), "utf-8");
4278
+ const body = readFileSync5(join6(templatesDir, physicalPath), "utf-8");
3489
4279
  if (isPartialTemplatePath(relativePath)) {
3490
4280
  partials.push(parsePartialPath(relativePath));
3491
4281
  } else {
@@ -3538,7 +4328,7 @@ function parsePartialPath(relativePath) {
3538
4328
  };
3539
4329
  }
3540
4330
  function defaultTemplatesDir() {
3541
- return join2(getScriptDir(), "..", "templates", "default");
4331
+ return join6(getScriptDir(), "..", "templates", "default");
3542
4332
  }
3543
4333
  function getRenderBase(templatePath) {
3544
4334
  if (!isPartialTemplatePath(templatePath)) {
@@ -3547,22 +4337,6 @@ function getRenderBase(templatePath) {
3547
4337
  const { basePath } = parsePartialPath(`${templatePath}${EJS_SUFFIX}`);
3548
4338
  return isPartialTemplatePath(basePath) ? getRenderBase(basePath) : templatePath;
3549
4339
  }
3550
- function walkTemplates(templatesDir, relativeDir) {
3551
- const absoluteDir = join2(templatesDir, relativeDir);
3552
- if (!existsSync3(absoluteDir)) {
3553
- return [];
3554
- }
3555
- const found = [];
3556
- for (const entry of readdirSync(absoluteDir)) {
3557
- const relativePath = relativeDir === "" ? entry : `${relativeDir}/${entry}`;
3558
- if (statSync(join2(templatesDir, relativePath)).isDirectory()) {
3559
- found.push(...walkTemplates(templatesDir, relativePath));
3560
- } else {
3561
- found.push(relativePath);
3562
- }
3563
- }
3564
- return found;
3565
- }
3566
4340
 
3567
4341
  // src/overlay.ts
3568
4342
  var OVERLAY_MANIFEST_FILE_NAME = "overlay.json";
@@ -3572,11 +4346,11 @@ var MANIFEST_KEYS = ["badges", "files", "packages", "partials"];
3572
4346
  var PACKAGE_NAME_PATTERN = /^(?:@[a-z0-9-~][a-z0-9-._~]*\/)?[a-z0-9-~][a-z0-9-._~]*$/;
3573
4347
  function loadOverlay(dir, builtIn = loadTemplateInventory()) {
3574
4348
  const absoluteDir = resolve(dir);
3575
- if (!existsSync4(absoluteDir) || !statSync2(absoluteDir).isDirectory()) {
4349
+ if (!existsSync6(absoluteDir) || !statSync2(absoluteDir).isDirectory()) {
3576
4350
  throw new Error(`Custom template directory not found: ${absoluteDir}`);
3577
4351
  }
3578
- const manifestPath = join3(absoluteDir, OVERLAY_MANIFEST_FILE_NAME);
3579
- if (!existsSync4(manifestPath)) {
4352
+ const manifestPath = join7(absoluteDir, OVERLAY_MANIFEST_FILE_NAME);
4353
+ if (!existsSync6(manifestPath)) {
3580
4354
  throw new Error(`Custom template directory has no ${OVERLAY_MANIFEST_FILE_NAME}: ${absoluteDir}`);
3581
4355
  }
3582
4356
  const manifest = readManifest(manifestPath);
@@ -3589,7 +4363,7 @@ ${problems.map((problem) => ` - ${problem}`).join("\n")}`);
3589
4363
  return overlay;
3590
4364
  }
3591
4365
  function toRecordedOverlayPath(overlayDir, projectDir) {
3592
- const relativePath = relative(projectDir, overlayDir);
4366
+ const relativePath = relative3(projectDir, overlayDir);
3593
4367
  return isAbsolute(relativePath) ? relativePath : relativePath.replaceAll("\\", "/");
3594
4368
  }
3595
4369
  function findManifestProblems(overlay, own, builtIn) {
@@ -3683,12 +4457,12 @@ function listStrayFiles(dir, own) {
3683
4457
  OVERLAY_MANIFEST_FILE_NAME,
3684
4458
  OVERLAY_README_FILE_NAME
3685
4459
  ]);
3686
- return walkFiles(dir, "").filter((path) => !accounted.has(path));
4460
+ return [...indexTemplateDir(dir)].filter(([logicalPath]) => !accounted.has(logicalPath)).map(([, physicalPath]) => physicalPath);
3687
4461
  }
3688
4462
  function readManifest(manifestPath) {
3689
4463
  let parsed;
3690
4464
  try {
3691
- parsed = JSON.parse(readFileSync4(manifestPath, "utf-8"));
4465
+ parsed = JSON.parse(readFileSync6(manifestPath, "utf-8"));
3692
4466
  } catch {
3693
4467
  throw new Error(`${manifestPath} is not valid JSON.`);
3694
4468
  }
@@ -3715,26 +4489,14 @@ function readManifest(manifestPath) {
3715
4489
  partials: readList("partials")
3716
4490
  };
3717
4491
  }
3718
- function walkFiles(root, relativeDir) {
3719
- const found = [];
3720
- for (const entry of readdirSync2(join3(root, relativeDir))) {
3721
- const relativePath = relativeDir === "" ? entry : `${relativeDir}/${entry}`;
3722
- if (statSync2(join3(root, relativePath)).isDirectory()) {
3723
- found.push(...walkFiles(root, relativePath));
3724
- } else {
3725
- found.push(relativePath);
3726
- }
3727
- }
3728
- return found;
3729
- }
3730
4492
 
3731
4493
  // src/project-formatter.ts
3732
4494
  import { spawnSync } from "node:child_process";
3733
4495
  import {
3734
- existsSync as existsSync5,
3735
- readFileSync as readFileSync5
4496
+ existsSync as existsSync7,
4497
+ readFileSync as readFileSync7
3736
4498
  } from "node:fs";
3737
- import { join as join4 } from "node:path";
4499
+ import { join as join8 } from "node:path";
3738
4500
  import process2 from "node:process";
3739
4501
  var FORMATTER_COMMANDS = {
3740
4502
  biome: {
@@ -3769,14 +4531,14 @@ function createProjectFormatter(targetDir, formatter) {
3769
4531
  };
3770
4532
  }
3771
4533
  function resolveBin(targetDir, packageName) {
3772
- const packageDir = join4(targetDir, "node_modules", packageName);
3773
- const packageJsonPath = join4(packageDir, "package.json");
3774
- if (!existsSync5(packageJsonPath)) {
4534
+ const packageDir = join8(targetDir, "node_modules", packageName);
4535
+ const packageJsonPath = join8(packageDir, "package.json");
4536
+ if (!existsSync7(packageJsonPath)) {
3775
4537
  return null;
3776
4538
  }
3777
- const { bin } = JSON.parse(readFileSync5(packageJsonPath, "utf-8"));
4539
+ const { bin } = JSON.parse(readFileSync7(packageJsonPath, "utf-8"));
3778
4540
  const relativeBin = typeof bin === "string" ? bin : Object.values(bin ?? {})[0];
3779
- return relativeBin === void 0 ? null : join4(packageDir, relativeBin);
4541
+ return relativeBin === void 0 ? null : join8(packageDir, relativeBin);
3780
4542
  }
3781
4543
  function runCli(binPath, targetDir, args, input) {
3782
4544
  const result = spawnSync(process2.execPath, [binPath, ...args], { cwd: targetDir, encoding: "utf-8", input });
@@ -3786,7 +4548,22 @@ function runCli(binPath, targetDir, args, input) {
3786
4548
  // src/main.ts
3787
4549
  var ARGV_OFFSET = 2;
3788
4550
  var JSON_INDENT_SPACES4 = 2;
4551
+ var SHORT_SHA_LENGTH = 7;
3789
4552
  var SCRIPT_MODE = 493;
4553
+ function applyPresetFlags(answers, cliArgs, hasOverlay) {
4554
+ if (!isOfficialSamplePreset(answers.preset)) {
4555
+ if (cliArgs.latest) {
4556
+ exitWithUsageError(`--latest picks which upstream tree preset=official-sample copies, and the preset is ${answers.preset}.
4557
+ Drop --latest, or pass --preset=official-sample.`);
4558
+ }
4559
+ return answers;
4560
+ }
4561
+ if (hasOverlay) {
4562
+ exitWithUsageError(`--customTemplate layers over the built-in templates, and preset=official-sample renders none: it copies obsidianmd/obsidian-sample-plugin as it is.
4563
+ Drop --customTemplate, or choose another preset.`);
4564
+ }
4565
+ return { ...answers, ...OFFICIAL_SAMPLE_PINNED_ANSWERS };
4566
+ }
3790
4567
  function assertManifestAnswersAreListable(answers) {
3791
4568
  const problems = findUnlistableManifestAnswers(answers);
3792
4569
  if (problems.length === 0) {
@@ -3802,7 +4579,7 @@ function buildSavedConfig(newConfig, answers, overlay, targetDir) {
3802
4579
  async function checkForUpdates(currentVersion) {
3803
4580
  const latestVer = await fetchLatestVersion("@mnaoumov/create-obsidian-plugin");
3804
4581
  if (latestVer !== null && compare(currentVersion, latestVer) < 0) {
3805
- log4.warn(`Your version is outdated. Latest: ${latestVer}. Update with:
4582
+ log5.warn(`Your version is outdated. Latest: ${latestVer}. Update with:
3806
4583
  npm install -g @mnaoumov/create-obsidian-plugin`);
3807
4584
  }
3808
4585
  }
@@ -3810,8 +4587,8 @@ async function detectMode(cliArgs) {
3810
4587
  if (cliArgs.mode) {
3811
4588
  return cliArgs.mode;
3812
4589
  }
3813
- const configPath = join5(process.cwd(), CONFIG_FILE_NAME);
3814
- if (existsSync6(configPath)) {
4590
+ const configPath = join9(process.cwd(), CONFIG_FILE_NAME);
4591
+ if (existsSync8(configPath)) {
3815
4592
  if (cliArgs.useDefaults) {
3816
4593
  exitWithUsageError(`Existing project detected (${CONFIG_FILE_NAME}), and --yes cannot ask whether to update it.
3817
4594
  Pass --mode=update to update it, or --mode=create to scaffold a new plugin beside it.`);
@@ -3830,7 +4607,7 @@ async function ensurePluginIdIsUnlisted(answers, useDefaults) {
3830
4607
  const listedIds = await fetchCommunityPluginIds();
3831
4608
  if (listedIds === null) {
3832
4609
  s.stop("Could not check the plugin id against the Community directory.");
3833
- log4.warn(`Could not fetch community-plugins.json, so "${answers.pluginId}" was not checked for a collision with a published plugin. The directory rejects a duplicate id, and an id can never be changed once published: check it by hand before submitting.`);
4610
+ log5.warn(`Could not fetch community-plugins.json, so "${answers.pluginId}" was not checked for a collision with a published plugin. The directory rejects a duplicate id, and an id can never be changed once published: check it by hand before submitting.`);
3834
4611
  return answers;
3835
4612
  }
3836
4613
  const collision = validatePluginIdIsUnlisted(answers.pluginId, listedIds);
@@ -3843,7 +4620,7 @@ async function ensurePluginIdIsUnlisted(answers, useDefaults) {
3843
4620
  exitWithUsageError(`${collision}.
3844
4621
  Pass --pluginId=<value> to choose another.`);
3845
4622
  }
3846
- log4.warn(collision);
4623
+ log5.warn(collision);
3847
4624
  const choice = await select2({
3848
4625
  initialValue: "reenter",
3849
4626
  message: `What should happen to "${answers.pluginId}"?`,
@@ -3901,6 +4678,10 @@ function exitWithUsageError(message) {
3901
4678
  `);
3902
4679
  process.exit(1);
3903
4680
  }
4681
+ function hasPrepareScript(targetDir) {
4682
+ const packageJson = JSON.parse(readFileSync8(join9(targetDir, "package.json"), "utf-8"));
4683
+ return Object.hasOwn(packageJson.scripts ?? {}, "prepare");
4684
+ }
3904
4685
  function loadOverlayOrExit(dir, hint = "") {
3905
4686
  try {
3906
4687
  return loadOverlay(dir);
@@ -3909,8 +4690,8 @@ function loadOverlayOrExit(dir, hint = "") {
3909
4690
  }
3910
4691
  }
3911
4692
  async function main() {
3912
- const packageJsonPath = join5(getScriptDir(), "..", "package.json");
3913
- const packageJson = JSON.parse(readFileSync6(packageJsonPath, "utf-8"));
4693
+ const packageJsonPath = join9(getScriptDir(), "..", "package.json");
4694
+ const packageJson = JSON.parse(readFileSync8(packageJsonPath, "utf-8"));
3914
4695
  const currentVersion = packageJson.version ?? "0.0.0";
3915
4696
  const m = "\x1B[38;5;135m";
3916
4697
  const r = "\x1B[0m";
@@ -3965,16 +4746,16 @@ async function offerAnswersExport(answers, customTemplate) {
3965
4746
  let choice = await ask();
3966
4747
  while (choice !== "generate") {
3967
4748
  if (choice === "script") {
3968
- const scriptPath = join5(process.cwd(), scriptName);
4749
+ const scriptPath = join9(process.cwd(), scriptName);
3969
4750
  writeFileSync2(scriptPath, formatCreateScript(answers, shell, customTemplate));
3970
4751
  if (shell === "sh") {
3971
4752
  chmodSync(scriptPath, SCRIPT_MODE);
3972
4753
  }
3973
- log4.success(`Wrote ${scriptName}`);
4754
+ log5.success(`Wrote ${scriptName}`);
3974
4755
  note(formatCreateCommand(answers, shell, customTemplate), "Non-interactive command");
3975
4756
  } else {
3976
- writeFileSync2(join5(process.cwd(), answersFileName), formatAnswersJson(answers));
3977
- log4.success(`Wrote ${answersFileName}`);
4757
+ writeFileSync2(join9(process.cwd(), answersFileName), formatAnswersJson(answers));
4758
+ log5.success(`Wrote ${answersFileName}`);
3978
4759
  const overlayFlag = customTemplate ? ` --customTemplate=${customTemplate}` : "";
3979
4760
  note(`npm create @mnaoumov/obsidian-plugin -- --yes --mode=create --answersFile=${answersFileName}${overlayFlag}`, "Non-interactive command");
3980
4761
  }
@@ -3991,18 +4772,41 @@ async function resolveExternalVersions(answers, overlay) {
3991
4772
  s.stop("Versions resolved.");
3992
4773
  return { minAppVersion, resolvedVersions };
3993
4774
  }
4775
+ async function resolveOfficialSampleSnapshot(latest) {
4776
+ const vendored = loadOfficialSampleSnapshot();
4777
+ if (!latest) {
4778
+ return vendored;
4779
+ }
4780
+ const upstream = readUpstream(getUpstreamsPath(), OFFICIAL_SAMPLE_UPSTREAM_NAME);
4781
+ const s = spinner();
4782
+ s.start(`Fetching ${upstream.repo}@${upstream.ref}...`);
4783
+ try {
4784
+ const snapshot = await fetchUpstreamSnapshot(upstream.repo, upstream.ref);
4785
+ s.stop(`Fetched ${upstream.repo} at ${snapshot.commit.slice(0, SHORT_SHA_LENGTH)}.`);
4786
+ return snapshot;
4787
+ } catch (error) {
4788
+ s.stop(`Could not fetch ${upstream.repo}.`);
4789
+ log5.warn(`${error instanceof Error ? error.message : String(error)}
4790
+ Using the snapshot this release vendored, ${vendored.commit.slice(0, SHORT_SHA_LENGTH)}.`);
4791
+ return vendored;
4792
+ }
4793
+ }
3994
4794
  async function runCreate(currentVersion, cliArgs) {
3995
4795
  const { answers: suppliedAnswers, customTemplate, useDefaults } = cliArgs;
3996
4796
  const overlay = customTemplate ? loadOverlayOrExit(resolvePath(customTemplate)) : null;
3997
- const answers = await ensurePluginIdIsUnlisted(
3998
- assertManifestAnswersAreListable(useDefaults ? getDefaultAnswers(suppliedAnswers) : await promptAnswers(suppliedAnswers)),
3999
- useDefaults
4797
+ const answers = applyPresetFlags(
4798
+ await ensurePluginIdIsUnlisted(
4799
+ assertManifestAnswersAreListable(useDefaults ? getDefaultAnswers(suppliedAnswers) : await promptAnswers(suppliedAnswers)),
4800
+ useDefaults
4801
+ ),
4802
+ cliArgs,
4803
+ overlay !== null
4000
4804
  );
4001
4805
  if (!useDefaults) {
4002
4806
  await offerAnswersExport(answers, customTemplate);
4003
4807
  }
4004
- const targetDir = join5(process.cwd(), `obsidian-${answers.pluginId}`);
4005
- if (existsSync6(targetDir) && !cliArgs.force) {
4808
+ const targetDir = join9(process.cwd(), `obsidian-${answers.pluginId}`);
4809
+ if (existsSync8(targetDir) && !cliArgs.force) {
4006
4810
  if (useDefaults) {
4007
4811
  exitWithUsageError(`Directory obsidian-${answers.pluginId} already exists, and --yes cannot ask whether to scaffold into it.
4008
4812
  Pass --force to scaffold into it anyway.`);
@@ -4017,19 +4821,28 @@ Pass --force to scaffold into it anyway.`);
4017
4821
  process.exit(0);
4018
4822
  }
4019
4823
  }
4020
- const { minAppVersion, resolvedVersions } = await resolveExternalVersions(answers, overlay);
4021
- const s = spinner();
4022
- s.start("Scaffolding plugin...");
4023
- const newConfig = copyTemplates(answers, targetDir, currentVersion, null, resolvedVersions, minAppVersion, overlay);
4024
- const configPath = join5(targetDir, CONFIG_FILE_NAME);
4824
+ let newConfig;
4825
+ if (isOfficialSamplePreset(answers.preset)) {
4826
+ const snapshot = await resolveOfficialSampleSnapshot(cliArgs.latest);
4827
+ const s = spinner();
4828
+ s.start("Copying the official sample plugin...");
4829
+ newConfig = copyOfficialSample(answers, targetDir, currentVersion, null, snapshot);
4830
+ s.stop(`Copied obsidianmd/obsidian-sample-plugin at ${snapshot.commit.slice(0, SHORT_SHA_LENGTH)}.`);
4831
+ } else {
4832
+ const { minAppVersion, resolvedVersions } = await resolveExternalVersions(answers, overlay);
4833
+ const s = spinner();
4834
+ s.start("Scaffolding plugin...");
4835
+ newConfig = copyTemplates(answers, targetDir, currentVersion, null, resolvedVersions, minAppVersion, overlay);
4836
+ s.stop("Plugin scaffolded.");
4837
+ }
4838
+ const configPath = join9(targetDir, CONFIG_FILE_NAME);
4025
4839
  const configWithAnswers = buildSavedConfig(newConfig, answers, overlay, targetDir);
4026
4840
  writeFileSync2(configPath, `${JSON.stringify(configWithAnswers, null, JSON_INDENT_SPACES4)}
4027
4841
  `);
4028
- s.stop("Plugin scaffolded.");
4029
4842
  const isFormatted = useDefaults ? false : await runPostScaffold(targetDir, answers);
4030
4843
  const pm = answers.packageManager;
4031
4844
  const dirName = `obsidian-${answers.pluginId}`;
4032
- const needsInstall = !existsSync6(join5(targetDir, "node_modules"));
4845
+ const needsInstall = !existsSync8(join9(targetDir, "node_modules"));
4033
4846
  const needsFormat = needsInitialFormat(answers.formatter) && !isFormatted;
4034
4847
  const steps = [
4035
4848
  ...needsInstall ? [getInstallCommand(pm)] : [],
@@ -4047,8 +4860,8 @@ async function runInitialFormat(targetDir, answers, isInstalled) {
4047
4860
  s.start("Formatting...");
4048
4861
  try {
4049
4862
  await execAsync(getRunCommand(answers.packageManager, "format"), targetDir);
4050
- const configPath = join5(targetDir, CONFIG_FILE_NAME);
4051
- const config = JSON.parse(readFileSync6(configPath, "utf-8"));
4863
+ const configPath = join9(targetDir, CONFIG_FILE_NAME);
4864
+ const config = JSON.parse(readFileSync8(configPath, "utf-8"));
4052
4865
  writeFileSync2(configPath, `${JSON.stringify(recordHashesOnDisk(targetDir, config), null, JSON_INDENT_SPACES4)}
4053
4866
  `);
4054
4867
  s.stop("Formatted.");
@@ -4077,7 +4890,7 @@ async function runPostScaffold(targetDir, answers) {
4077
4890
  } catch (error) {
4078
4891
  s.stop(`Failed to install dependencies. Run \`${installCmd}\` manually.`);
4079
4892
  if (error instanceof Error && "stderr" in error) {
4080
- log4.error(String(error.stderr));
4893
+ log5.error(String(error.stderr));
4081
4894
  }
4082
4895
  }
4083
4896
  }
@@ -4092,11 +4905,17 @@ async function runPostScaffold(targetDir, answers) {
4092
4905
  s.start("Initializing git repository...");
4093
4906
  try {
4094
4907
  await execAsync(`git init -b ${answers.defaultBranch}`, targetDir);
4908
+ if (isInstalled && hasPrepareScript(targetDir)) {
4909
+ await execAsync(getRunCommand(pm, "prepare"), targetDir);
4910
+ }
4095
4911
  await execAsync("git add -A", targetDir);
4096
- await execAsync('git commit -m "Initial commit from create-obsidian-plugin"', targetDir);
4912
+ await execAsync(`git commit -m "${INITIAL_COMMIT_MESSAGE}"`, targetDir);
4097
4913
  s.stop("Git repository initialized with initial commit.");
4098
- } catch {
4914
+ } catch (error) {
4099
4915
  s.stop("Failed to initialize git. Run `git init` manually.");
4916
+ if (error instanceof Error && "stderr" in error) {
4917
+ log5.error(String(error.stderr));
4918
+ }
4100
4919
  }
4101
4920
  }
4102
4921
  const shouldCreateGitHubRepo = await confirm({
@@ -4121,10 +4940,10 @@ async function runUpdate(currentVersion, cliArgs) {
4121
4940
  const targetDir = process.cwd();
4122
4941
  const existingConfig = loadConfig(targetDir);
4123
4942
  if (!existingConfig) {
4124
- log4.error("No config file found. Cannot update.");
4943
+ log5.error("No config file found. Cannot update.");
4125
4944
  process.exit(1);
4126
4945
  }
4127
- log4.info(`Current project was generated with v${existingConfig.generatorVersion}`);
4946
+ log5.info(`Current project was generated with v${existingConfig.generatorVersion}`);
4128
4947
  let overlay = null;
4129
4948
  if (customTemplate !== void 0) {
4130
4949
  overlay = customTemplate ? loadOverlayOrExit(resolvePath(customTemplate)) : null;
@@ -4134,21 +4953,21 @@ async function runUpdate(currentVersion, cliArgs) {
4134
4953
  `
4135
4954
  This project records it in ${CONFIG_FILE_NAME}. Pass --customTemplate=<dir> to point at where it is now, or --customTemplate= to stop using it.`
4136
4955
  );
4137
- log4.info(`Applying the custom template recorded for this project: ${existingConfig.customTemplate}`);
4956
+ log5.info(`Applying the custom template recorded for this project: ${existingConfig.customTemplate}`);
4138
4957
  }
4139
- const configPath = join5(targetDir, CONFIG_FILE_NAME);
4140
- const savedConfig = JSON.parse(readFileSync6(configPath, "utf-8"));
4958
+ const configPath = join9(targetDir, CONFIG_FILE_NAME);
4959
+ const savedConfig = JSON.parse(readFileSync8(configPath, "utf-8"));
4141
4960
  let answers;
4142
4961
  if (savedConfig.answers) {
4143
4962
  const saved = { ...savedConfig.answers, ...suppliedAnswers };
4144
- log4.info("Using saved answers from previous generation.");
4963
+ log5.info("Using saved answers from previous generation.");
4145
4964
  const shouldRePrompt = useDefaults ? false : await confirm({
4146
4965
  initialValue: false,
4147
4966
  message: "Would you like to change any settings?"
4148
4967
  });
4149
4968
  assertNotCancelled(shouldRePrompt);
4150
4969
  if (shouldRePrompt) {
4151
- answers = await promptAnswers(saved);
4970
+ answers = await promptAnswers(saved, suppliedAnswers);
4152
4971
  } else {
4153
4972
  answers = saved;
4154
4973
  }
@@ -4157,17 +4976,29 @@ This project records it in ${CONFIG_FILE_NAME}. Pass --customTemplate=<dir> to p
4157
4976
  exitWithUsageError(`${CONFIG_FILE_NAME} records no answers, so --yes has none to reuse.
4158
4977
  Run without --yes to answer them again.`);
4159
4978
  }
4160
- log4.warn("No saved answers found. Please provide the settings again.");
4979
+ log5.warn("No saved answers found. Please provide the settings again.");
4161
4980
  answers = await promptAnswers(suppliedAnswers);
4162
4981
  }
4163
4982
  const savedPluginId = savedConfig.answers?.pluginId;
4164
4983
  if (savedPluginId !== void 0 && answers.pluginId !== savedPluginId) {
4165
4984
  answers = await ensurePluginIdIsUnlisted(answers, useDefaults);
4166
4985
  }
4986
+ answers = applyPresetFlags(answers, cliArgs, overlay !== null);
4987
+ if (isOfficialSamplePreset(answers.preset)) {
4988
+ const snapshot = await resolveOfficialSampleSnapshot(cliArgs.latest);
4989
+ const s2 = spinner();
4990
+ s2.start("Updating project files...");
4991
+ const newConfig2 = copyOfficialSample(answers, targetDir, currentVersion, existingConfig, snapshot);
4992
+ writeFileSync2(configPath, `${JSON.stringify({ ...newConfig2, answers }, null, JSON_INDENT_SPACES4)}
4993
+ `);
4994
+ s2.stop(`Update complete: obsidianmd/obsidian-sample-plugin at ${snapshot.commit.slice(0, SHORT_SHA_LENGTH)}.`);
4995
+ outro("Project updated successfully!");
4996
+ return;
4997
+ }
4167
4998
  const { minAppVersion, resolvedVersions } = await resolveExternalVersions(answers, overlay);
4168
4999
  const projectFormatter = createProjectFormatter(targetDir, answers.formatter);
4169
5000
  if (projectFormatter === null && needsInitialFormat(answers.formatter)) {
4170
- log4.warn(`${answers.formatter} is not installed, so the update cannot tell the files it formatted from hand edits and skips them. Install the dependencies and update again to have them updated.`);
5001
+ log5.warn(`${answers.formatter} is not installed, so the update cannot tell the files it formatted from hand edits and skips them. Install the dependencies and update again to have them updated.`);
4171
5002
  }
4172
5003
  const s = spinner();
4173
5004
  s.start("Updating project files...");