@mnaoumov/create-obsidian-plugin 1.0.1 → 1.1.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 (490) hide show
  1. package/README.md +38 -7
  2. package/dist/main.js +1068 -333
  3. package/package.json +15 -6
  4. package/src/main.ts +118 -11
  5. package/templates/default/.github/ISSUE_TEMPLATE/config.yml.ejs +4 -0
  6. package/templates/default/.github/workflows/attest-release-assets.yml.ejs +1 -11
  7. package/templates/default/.github/workflows/ci.yml_framework.ejs +19 -0
  8. package/templates/default/.github/workflows/ci.yml_framework@job-permissions_measured-coverage-badge.ejs +3 -0
  9. package/templates/default/.github/workflows/ci.yml_framework@with_measured-coverage-badge.ejs +1 -0
  10. package/templates/default/.github/workflows/{ci.yml.ejs → ci.yml_standalone.ejs} +1 -1
  11. package/templates/default/.github/workflows/release.yml_framework.ejs +19 -0
  12. package/templates/default/.github/workflows/{release.yml.ejs → release.yml_standalone.ejs} +1 -1
  13. package/templates/default/.gitignore_common.ejs +1 -0
  14. package/templates/default/.gitignore_wdio-obsidian.ejs +2 -0
  15. package/templates/default/.nvmrc.ejs +1 -0
  16. package/templates/default/.prettierignore.ejs +1 -0
  17. package/templates/default/.prettierignore@ignores_docs-showcase.ejs +3 -0
  18. package/templates/default/{CONTRIBUTING.md@demo-vault_dev-utils.ejs → CONTRIBUTING.md@demo-vault_framework.ejs} +1 -1
  19. package/templates/default/{README.md@demo-vault_dev-utils.ejs → README.md@demo-vault_framework.ejs} +1 -1
  20. package/templates/default/README.md@preset_docs-showcase.ejs +4 -0
  21. package/templates/default/{README.md@preset_dev-utils.ejs → README.md@preset_framework.ejs} +1 -1
  22. package/templates/default/biome.jsonc_framework.ejs +16 -0
  23. package/templates/default/biome.jsonc_framework@excludes_docs-showcase.ejs +1 -0
  24. package/templates/default/{biome.jsonc.ejs → biome.jsonc_standalone.ejs} +1 -1
  25. package/templates/default/cspell.json.ejs +10 -2
  26. package/templates/default/cspell.json@ignore-paths_docs-showcase.ejs +1 -0
  27. package/templates/default/demo-vault/.gitignore.ejs +4 -4
  28. package/templates/default/demo-vault/00 Start.md.ejs +1 -1
  29. package/templates/default/demo-vault/01 Sample commands.md.ejs +4 -4
  30. package/templates/default/demo-vault/02 Settings.md.ejs +2 -2
  31. package/templates/default/demo-vault/03 WebAssembly.md.ejs +2 -2
  32. package/templates/default/demo-vault/README.md.ejs +1 -1
  33. package/templates/default/demo-vault/_assets/CodeScriptToolkit/demoSetup.ts.ejs +1 -1
  34. package/templates/default/demo-vault/_assets/CodeScriptToolkit/startup.ts.ejs +4 -4
  35. package/templates/default/dprint.json_framework.ejs +10 -0
  36. package/templates/default/dprint.json_framework@excludes_docs-showcase.ejs +2 -0
  37. package/templates/default/dprint.json_standalone.ejs +1 -0
  38. package/templates/default/eslint.config.mts_standalone.ejs +9 -0
  39. package/templates/default/jest.config.ts_framework.ejs +31 -0
  40. package/templates/default/{scripts/rollup.config.ts@lint-out-dir_dev-utils.ejs → jest.config.ts_framework@lint-root-dir_framework.ejs} +1 -1
  41. package/templates/default/jest.config.ts_framework@ts-jest-tsconfig_solid.ejs +8 -0
  42. package/templates/default/{jest.config.ts.ejs → jest.config.ts_standalone.ejs} +0 -1
  43. package/templates/default/package.json@targets_parcel-targets.ejs +31 -0
  44. package/templates/default/package.json@targets_parcel.ejs +2 -33
  45. package/templates/default/parcel-transformer-inline-imports.cjs.ejs +1 -1
  46. package/templates/default/prettier.config.mjs_framework.ejs +3 -0
  47. package/templates/default/scripts/build-clean.ts.ejs +2 -2
  48. package/templates/default/scripts/build-compile-typescript.ts.ejs +14 -0
  49. package/templates/default/scripts/build-compile.ts.ejs +2 -2
  50. package/templates/default/scripts/build-options.ts.ejs +9 -0
  51. package/templates/default/scripts/build-styles.ts.ejs +4 -7
  52. package/templates/default/scripts/build.ts.ejs +2 -2
  53. package/templates/default/scripts/build.ts@bundler_adapter-cli.ejs +11 -0
  54. package/templates/default/scripts/build.ts@bundler_adapter-cli@run_rollup.ejs +1 -0
  55. package/templates/default/scripts/build.ts@bundler_adapter-cli@run_vite.ejs +1 -0
  56. package/templates/default/scripts/build.ts@bundler_adapter-cli@run_webpack.ejs +1 -0
  57. package/templates/default/scripts/build.ts@bundler_cli-bundler.ejs +1 -1
  58. package/templates/default/scripts/build.ts@bundler_cli-bundler@import_tailwind.ejs +0 -1
  59. package/templates/default/scripts/build.ts@bundler_esbuild.ejs +2 -2
  60. package/templates/default/scripts/build.ts@bundler_esbuild@preset_framework.ejs +5 -0
  61. package/templates/default/scripts/build.ts@bundler_parcel-adapter.ejs +5 -0
  62. package/templates/default/scripts/commit.ts_framework.ejs +3 -0
  63. package/templates/default/scripts/commitlint-config.ts_framework.ejs +1 -0
  64. package/templates/default/scripts/demo-vault-global-setup.ts.ejs +7 -4
  65. package/templates/default/scripts/dev.ts.ejs +1 -1
  66. package/templates/default/scripts/dev.ts@bundler_adapter-cli.ejs +6 -0
  67. package/templates/default/scripts/dev.ts@bundler_adapter-cli@run_rollup.ejs +3 -0
  68. package/templates/default/scripts/dev.ts@bundler_adapter-cli@run_vite.ejs +3 -0
  69. package/templates/default/scripts/dev.ts@bundler_adapter-cli@run_webpack.ejs +3 -0
  70. package/templates/default/scripts/dev.ts@bundler_esbuild.ejs +2 -2
  71. package/templates/default/scripts/dev.ts@bundler_esbuild@preset_framework.ejs +5 -0
  72. package/templates/default/scripts/dev.ts@bundler_parcel-adapter.ejs +5 -0
  73. package/templates/default/scripts/eslint-config.ts.ejs +3 -14
  74. package/templates/default/scripts/eslint-config.ts@ignores_docs-showcase.ejs +4 -0
  75. package/templates/default/scripts/find-overexposed-fix.ts.ejs +4 -4
  76. package/templates/default/scripts/find-overexposed.ts.ejs +3 -3
  77. package/templates/default/scripts/format-check.ts@tool_biome-formatter.ejs +3 -8
  78. package/templates/default/scripts/format-check.ts@tool_biome-formatter@preset_framework.ejs +7 -0
  79. package/templates/default/scripts/format-check.ts@tool_biome-formatter@preset_standalone.ejs +8 -0
  80. package/templates/default/scripts/format-check.ts@tool_dprint.ejs +2 -2
  81. package/templates/default/scripts/format-check.ts@tool_dprint@preset_framework.ejs +7 -0
  82. package/templates/default/scripts/format-check.ts@tool_prettier.ejs +3 -8
  83. package/templates/default/scripts/format-check.ts@tool_prettier@preset_framework.ejs +7 -0
  84. package/templates/default/scripts/format-check.ts@tool_prettier@preset_standalone.ejs +8 -0
  85. package/templates/default/scripts/format.ts@tool_biome-formatter.ejs +3 -8
  86. package/templates/default/scripts/format.ts@tool_biome-formatter@preset_framework.ejs +7 -0
  87. package/templates/default/scripts/format.ts@tool_biome-formatter@preset_standalone.ejs +8 -0
  88. package/templates/default/scripts/format.ts@tool_dprint.ejs +2 -2
  89. package/templates/default/scripts/format.ts@tool_dprint@preset_framework.ejs +7 -0
  90. package/templates/default/scripts/format.ts@tool_prettier.ejs +3 -8
  91. package/templates/default/scripts/format.ts@tool_prettier@preset_framework.ejs +7 -0
  92. package/templates/default/scripts/format.ts@tool_prettier@preset_standalone.ejs +8 -0
  93. package/templates/default/scripts/gate.ts.ejs +3 -3
  94. package/templates/default/scripts/lint-fix.ts.ejs +2 -2
  95. package/templates/default/scripts/lint-fix.ts@tool_biome-linter.ejs +3 -8
  96. package/templates/default/scripts/lint-fix.ts@tool_biome-linter@preset_framework.ejs +7 -0
  97. package/templates/default/scripts/lint-fix.ts@tool_biome-linter@preset_standalone.ejs +8 -0
  98. package/templates/default/scripts/lint-fix.ts@tool_eslint.ejs +2 -2
  99. package/templates/default/scripts/lint-fix.ts@tool_eslint@preset_framework.ejs +7 -0
  100. package/templates/default/scripts/lint-md-fix.ts_framework.ejs +7 -0
  101. package/templates/default/scripts/lint-md.ts_framework.ejs +7 -0
  102. package/templates/default/scripts/lint.ts.ejs +2 -2
  103. package/templates/default/scripts/lint.ts@tool_biome-linter.ejs +3 -8
  104. package/templates/default/scripts/lint.ts@tool_biome-linter@preset_framework.ejs +7 -0
  105. package/templates/default/scripts/lint.ts@tool_biome-linter@preset_standalone.ejs +8 -0
  106. package/templates/default/scripts/lint.ts@tool_eslint.ejs +2 -2
  107. package/templates/default/scripts/lint.ts@tool_eslint@preset_framework.ejs +7 -0
  108. package/templates/default/scripts/{markdownlint-cli2-config.ts_dev-utils.ejs → markdownlint-cli2-config.ts_framework.ejs} +4 -4
  109. package/templates/default/scripts/markdownlint-cli2-config.ts_standalone.ejs +0 -3
  110. package/templates/default/scripts/nano-staged-config.ts_toolkit-nano-staged.ejs +3 -0
  111. package/templates/default/scripts/prepare.ts_framework.ejs +3 -0
  112. package/templates/default/scripts/rollup.config.ts_framework.ejs +49 -0
  113. package/templates/default/scripts/rollup.config.ts_framework@plugin_rollup-json.ejs +2 -0
  114. package/templates/default/scripts/rollup.config.ts_framework@plugin_scss.ejs +3 -0
  115. package/templates/default/scripts/{rollup.config.ts.ejs → rollup.config.ts_standalone.ejs} +4 -4
  116. package/templates/default/scripts/rollup.config.ts_standalone@import_rollup-json.ejs +1 -0
  117. package/templates/default/scripts/rollup.config.ts_standalone@import_scss.ejs +1 -0
  118. package/templates/default/scripts/rollup.config.ts_standalone@unwrap_rollup-json.ejs +1 -0
  119. package/templates/default/scripts/rollup.config.ts_standalone@unwrap_scss.ejs +1 -0
  120. package/templates/default/scripts/spellcheck.ts_framework.ejs +7 -0
  121. package/templates/default/scripts/stylesheet-stub.ts.ejs +1 -1
  122. package/templates/default/scripts/test-coverage.ts.ejs +2 -8
  123. package/templates/default/scripts/test-coverage.ts@tool_jest.ejs +5 -0
  124. package/templates/default/scripts/test-coverage.ts@tool_vitest.ejs +8 -0
  125. package/templates/default/scripts/test-e2e.ts@tool_obsidian-test.ejs +2 -8
  126. package/templates/default/scripts/test-e2e.ts@tool_obsidian-test@preset_framework.ejs +4 -0
  127. package/templates/default/scripts/test-e2e.ts@tool_obsidian-test@preset_standalone.ejs +8 -0
  128. package/templates/default/scripts/test-e2e.ts@tool_wdio-obsidian.ejs +2 -8
  129. package/templates/default/scripts/test-e2e.ts@tool_wdio-obsidian@preset_framework.ejs +5 -0
  130. package/templates/default/scripts/test-e2e.ts@tool_wdio-obsidian@preset_standalone.ejs +8 -0
  131. package/templates/default/scripts/test-integration-android.ts.ejs +2 -2
  132. package/templates/default/scripts/test-integration-demo-vault.ts.ejs +2 -2
  133. package/templates/default/scripts/test-integration-desktop-performance.ts.ejs +2 -2
  134. package/templates/default/scripts/test-integration-desktop.ts.ejs +2 -2
  135. package/templates/default/scripts/test-integration-no-app.ts.ejs +2 -2
  136. package/templates/default/scripts/test-integration.ts.ejs +2 -2
  137. package/templates/default/scripts/test-watch.ts_framework@tool_jest.ejs +5 -0
  138. package/templates/default/scripts/test-watch.ts_framework@tool_vitest.ejs +8 -0
  139. package/templates/default/scripts/test.ts_framework@tool_jest.ejs +5 -0
  140. package/templates/default/scripts/test.ts_framework@tool_vitest.ejs +8 -0
  141. package/templates/default/scripts/{version.ts_dev-utils.ejs → version.ts_framework.ejs} +3 -3
  142. package/templates/default/scripts/vite.config.ts_framework.ejs +10 -0
  143. package/templates/default/scripts/{vite.config.ts.ejs → vite.config.ts_standalone.ejs} +5 -8
  144. package/templates/default/scripts/vitest-config.ts.ejs +3 -2
  145. package/templates/default/scripts/vitest-config.ts@edit-context_docs-showcase.ejs +3 -0
  146. package/templates/default/scripts/webpack.config.ts_framework.ejs +19 -0
  147. package/templates/default/scripts/webpack.config.ts_framework@import_scss.ejs +1 -0
  148. package/templates/default/scripts/webpack.config.ts_framework@plugin_scss.ejs +1 -0
  149. package/templates/default/scripts/webpack.config.ts_framework@rule_scss.ejs +4 -0
  150. package/templates/default/scripts/{webpack.config.ts.ejs → webpack.config.ts_standalone.ejs} +4 -4
  151. package/templates/default/src/demo-vault-buttons.demo-vault.integration.test.ts.ejs +2 -2
  152. package/templates/default/src/demo-vault.no-app.integration.test.ts.ejs +3 -3
  153. package/templates/default/src/docs-showcase.desktop.integration.test.ts.ejs +77 -0
  154. package/templates/default/src/editor-extensions/{sample-state-field.ts_dev-utils.ejs → sample-state-field.ts_framework.ejs} +1 -1
  155. package/templates/default/src/main.ts@import_tailwind.ejs +1 -1
  156. package/templates/default/src/main.ts@import_tailwind@preset_framework.ejs +1 -0
  157. package/templates/default/src/main.ts@import_tailwind@preset_standalone.ejs +1 -0
  158. package/templates/default/src/{plugin-settings-component.test.ts_enhanced.ejs → plugin-settings-component.test.ts_all-in-one.ejs} +4 -4
  159. package/templates/default/src/plugin-settings-component.test.ts_demo.ejs +5 -5
  160. package/templates/default/src/{plugin-settings-component.ts_enhanced.ejs → plugin-settings-component.ts_all-in-one.ejs} +3 -3
  161. package/templates/default/src/plugin-settings-component.ts_demo.ejs +7 -7
  162. package/templates/default/src/{plugin-settings-tab.ts_enhanced.ejs → plugin-settings-tab.ts_all-in-one.ejs} +1 -1
  163. package/templates/default/src/plugin-settings-tab.ts_demo.ejs +3 -3
  164. package/templates/default/src/plugin-settings.ts_demo.ejs +2 -2
  165. package/templates/default/src/{plugin.ts_enhanced.ejs → plugin.ts_all-in-one.ejs} +5 -5
  166. package/templates/default/src/plugin.ts_all-in-one@import2_css-modules.ejs +1 -0
  167. package/templates/default/src/plugin.ts_all-in-one@import2_docs-showcase.ejs +1 -0
  168. package/templates/default/src/plugin.ts_all-in-one@onload_css-modules.ejs +1 -0
  169. package/templates/default/src/plugin.ts_all-in-one@onload_docs-showcase.ejs +3 -0
  170. package/templates/default/src/plugin.ts_demo.ejs +16 -16
  171. package/templates/default/src/plugin.ts_demo@import_css-modules.ejs +1 -0
  172. package/templates/default/src/plugin.ts_demo@onload_css-modules.ejs +1 -0
  173. package/templates/default/src/plugin.ts_standalone.ejs +5 -3
  174. package/templates/default/src/plugin.ts_standalone@import_css-modules.ejs +1 -0
  175. package/templates/default/src/plugin.ts_standalone@onload_css-modules.ejs +1 -0
  176. package/templates/default/src/react-components/{sample-react-component.tsx_dev-utils.ejs → sample-react-component.tsx_framework.ejs} +1 -1
  177. package/templates/default/src/styles/css-modules.d.ts.ejs +9 -3
  178. package/templates/default/src/styles/{main.css_dev-utils.ejs → main.css_framework.ejs} +2 -2
  179. package/templates/default/src/styles/main.module.css.ejs +4 -2
  180. package/templates/default/src/styles/{main.scss_dev-utils.ejs → main.scss_framework.ejs} +2 -2
  181. package/templates/default/src/styles/sample-css-module-command.ts.ejs +30 -0
  182. package/templates/default/src/views/{sample-react-view.tsx_dev-utils.ejs → sample-react-view.tsx_framework.ejs} +1 -1
  183. package/templates/default/src/wasm/README.md.ejs +1 -1
  184. package/templates/default/src/wasm/answer.ts_wasm-adapter.ejs +18 -0
  185. package/templates/default/{tsconfig.json_dev-utils.ejs → tsconfig.json_framework.ejs} +2 -2
  186. package/templates/default/tsconfig.json_framework@exclude_docs-showcase.ejs +4 -0
  187. package/templates/default/tsconfig.json_framework@include_wdio-obsidian.ejs +1 -0
  188. package/templates/default/tsconfig.json_framework@types_toolkit-styles.ejs +2 -0
  189. package/templates/default/tsconfig.json_framework@types_wasm.ejs +2 -0
  190. package/templates/default/tsconfig.json_standalone.ejs +1 -1
  191. package/templates/default/vitest.config.ts_standalone.ejs +11 -2
  192. package/templates/default/wdio.conf.mts.ejs +5 -0
  193. package/templates/default/wdio.conf.ts.ejs +4 -4
  194. package/templates/docs-showcase/files/src/docs/README.md +511 -0
  195. package/templates/docs-showcase/files/src/docs/entry.d.ts +8 -0
  196. package/templates/docs-showcase/files/src/docs/entry.js +4 -0
  197. package/templates/docs-showcase/files/src/docs/host.ts +449 -0
  198. package/templates/docs-showcase/files/src/docs/index.ts +699 -0
  199. package/templates/docs-showcase/files/src/docs/plugins/editor/communicating-with-editor-extensions/01-intro.ts +21 -0
  200. package/templates/docs-showcase/files/src/docs/plugins/editor/communicating-with-editor-extensions/03-state-field.ts +32 -0
  201. package/templates/docs-showcase/files/src/docs/plugins/editor/decorations/01-widgets.ts +23 -0
  202. package/templates/docs-showcase/files/src/docs/plugins/editor/decorations/02-widgets.ts +20 -0
  203. package/templates/docs-showcase/files/src/docs/plugins/editor/decorations/04-state-fields.ts +57 -0
  204. package/templates/docs-showcase/files/src/docs/plugins/editor/decorations/05-view-plugins.ts +79 -0
  205. package/templates/docs-showcase/files/src/docs/plugins/editor/editor/01-intro.ts +26 -0
  206. package/templates/docs-showcase/files/src/docs/plugins/editor/editor/03-replace-current-selection.ts +26 -0
  207. package/templates/docs-showcase/files/src/docs/plugins/editor/markdown-post-processing/01-intro.ts +39 -0
  208. package/templates/docs-showcase/files/src/docs/plugins/editor/state-fields/01-defining-state-effects.ts +19 -0
  209. package/templates/docs-showcase/files/src/docs/plugins/editor/state-fields/02-defining-a-state-field.ts +35 -0
  210. package/templates/docs-showcase/files/src/docs/plugins/editor/state-fields/04-dispatching-state-effects.ts +34 -0
  211. package/templates/docs-showcase/files/src/docs/plugins/editor/state-management/01-state-changes.ts +21 -0
  212. package/templates/docs-showcase/files/src/docs/plugins/editor/state-management/02-state-changes.ts +23 -0
  213. package/templates/docs-showcase/files/src/docs/plugins/editor/view-plugins/01-creating-a-view-plugin.ts +36 -0
  214. package/templates/docs-showcase/files/src/docs/plugins/events/01-intro.ts +21 -0
  215. package/templates/docs-showcase/files/src/docs/plugins/getting-started/anatomy-of-a-plugin/01-intro.ts +22 -0
  216. package/templates/docs-showcase/files/src/docs/plugins/getting-started/anatomy-of-a-plugin/02-plugin-lifecycle.ts +22 -0
  217. package/templates/docs-showcase/files/src/docs/plugins/getting-started/build-a-plugin/06-step-5-update-the-source-code.ts +19 -0
  218. package/templates/docs-showcase/files/src/docs/plugins/getting-started/build-a-plugin/07-step-5-update-the-source-code.ts +21 -0
  219. package/templates/docs-showcase/files/src/docs/plugins/getting-started/mobile-development/03-platform-specific-features.ts +25 -0
  220. package/templates/docs-showcase/files/src/docs/plugins/getting-started/use-react-in-your-plugin/03-configure-your-plugin.ts +23 -0
  221. package/templates/docs-showcase/files/src/docs/plugins/guides/build-a-bases-view/01-step-1-sample-plugin-setup.ts +18 -0
  222. 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
  223. package/templates/docs-showcase/files/src/docs/plugins/guides/build-a-bases-view/03-step-3-add-configuration.ts +40 -0
  224. package/templates/docs-showcase/files/src/docs/plugins/guides/defer-views/04-accessing-your-customview-without-reveal.ts +26 -0
  225. package/templates/docs-showcase/files/src/docs/plugins/guides/manage-plugin-lifecycle/01-overview.ts +26 -0
  226. package/templates/docs-showcase/files/src/docs/plugins/guides/manage-plugin-lifecycle/02-overview.ts +30 -0
  227. package/templates/docs-showcase/files/src/docs/plugins/guides/manage-plugin-lifecycle/03-automatic-resource-management-with-compo.ts +26 -0
  228. package/templates/docs-showcase/files/src/docs/plugins/guides/manage-plugin-lifecycle/04-registerevent-eventref.ts +22 -0
  229. package/templates/docs-showcase/files/src/docs/plugins/guides/manage-plugin-lifecycle/05-registerinterval-id.ts +21 -0
  230. package/templates/docs-showcase/files/src/docs/plugins/guides/manage-plugin-lifecycle/06-registerdomevent-el-event-handler.ts +20 -0
  231. package/templates/docs-showcase/files/src/docs/plugins/guides/manage-plugin-lifecycle/08-understanding-the-lifecycle-of-objects.ts +29 -0
  232. package/templates/docs-showcase/files/src/docs/plugins/guides/manage-plugin-lifecycle/14-componentized-modal-example.ts +37 -0
  233. 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
  234. 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
  235. package/templates/docs-showcase/files/src/docs/plugins/guides/store-secrets/03-step-3-retrieve-the-secret-value.ts +22 -0
  236. package/templates/docs-showcase/files/src/docs/plugins/releasing/plugin-guidelines/01-use-setheading-instead-of-a-h1-h2.ts +20 -0
  237. package/templates/docs-showcase/files/src/docs/plugins/releasing/plugin-guidelines/03-clean-up-resources-when-plugin-unloads.ts +23 -0
  238. package/templates/docs-showcase/files/src/docs/plugins/releasing/plugin-guidelines/04-avoid-accessing-workspace-activeleaf-dir.ts +24 -0
  239. package/templates/docs-showcase/files/src/docs/plugins/releasing/plugin-guidelines/05-avoid-accessing-workspace-activeleaf-dir.ts +22 -0
  240. package/templates/docs-showcase/files/src/docs/plugins/releasing/plugin-guidelines/10-avoid-iterating-all-files-to-find-a-file.ts +20 -0
  241. package/templates/docs-showcase/files/src/docs/plugins/releasing/plugin-guidelines/11-avoid-iterating-all-files-to-find-a-file.ts +20 -0
  242. package/templates/docs-showcase/files/src/docs/plugins/releasing/plugin-guidelines/13-use-normalizepath-to-clean-up-user-defin.ts +18 -0
  243. package/templates/docs-showcase/files/src/docs/plugins/releasing/plugin-guidelines/15-no-hardcoded-styling.ts +21 -0
  244. package/templates/docs-showcase/files/src/docs/plugins/releasing/plugin-guidelines/16-no-hardcoded-styling.ts +19 -0
  245. package/templates/docs-showcase/files/src/docs/plugins/releasing/plugin-guidelines/17-no-hardcoded-styling.ts +14 -0
  246. package/templates/docs-showcase/files/src/docs/plugins/releasing/plugin-guidelines/18-prefer-async-await-over-promise.ts +24 -0
  247. package/templates/docs-showcase/files/src/docs/plugins/releasing/plugin-guidelines/19-prefer-async-await-over-promise.ts +27 -0
  248. package/templates/docs-showcase/files/src/docs/plugins/user-interface/commands/01-intro.ts +25 -0
  249. package/templates/docs-showcase/files/src/docs/plugins/user-interface/commands/03-editor-commands.ts +27 -0
  250. package/templates/docs-showcase/files/src/docs/plugins/user-interface/commands/05-hot-keys.ts +25 -0
  251. package/templates/docs-showcase/files/src/docs/plugins/user-interface/context-menus/01-intro.ts +41 -0
  252. package/templates/docs-showcase/files/src/docs/plugins/user-interface/html-elements/02-create-html-elements-using-createel.ts +19 -0
  253. package/templates/docs-showcase/files/src/docs/plugins/user-interface/html-elements/03-create-html-elements-using-createel.ts +21 -0
  254. package/templates/docs-showcase/files/src/docs/plugins/user-interface/html-elements/04-style-your-elements.ts +14 -0
  255. package/templates/docs-showcase/files/src/docs/plugins/user-interface/html-elements/05-style-your-elements.ts +21 -0
  256. package/templates/docs-showcase/files/src/docs/plugins/user-interface/html-elements/06-conditional-styles.ts +19 -0
  257. package/templates/docs-showcase/files/src/docs/plugins/user-interface/icons/01-use-icons.ts +20 -0
  258. package/templates/docs-showcase/files/src/docs/plugins/user-interface/icons/02-use-icons.ts +14 -0
  259. package/templates/docs-showcase/files/src/docs/plugins/user-interface/icons/03-add-your-own-icon.ts +23 -0
  260. package/templates/docs-showcase/files/src/docs/plugins/user-interface/modals/01-intro.ts +20 -0
  261. package/templates/docs-showcase/files/src/docs/plugins/user-interface/modals/02-intro.ts +26 -0
  262. package/templates/docs-showcase/files/src/docs/plugins/user-interface/modals/03-accept-user-input.ts +38 -0
  263. package/templates/docs-showcase/files/src/docs/plugins/user-interface/modals/04-accept-user-input.ts +22 -0
  264. package/templates/docs-showcase/files/src/docs/plugins/user-interface/modals/05-select-from-list-of-suggestions.ts +56 -0
  265. package/templates/docs-showcase/files/src/docs/plugins/user-interface/modals/06-approximate-string-matching-results.ts +28 -0
  266. package/templates/docs-showcase/files/src/docs/plugins/user-interface/modals/07-custom-rendering-of-fuzzy-search-results.ts +41 -0
  267. package/templates/docs-showcase/files/src/docs/plugins/user-interface/ribbon-actions/01-intro.ts +21 -0
  268. package/templates/docs-showcase/files/src/docs/plugins/user-interface/right-to-left/01-use-fallback-values-when-necessary.ts +14 -0
  269. package/templates/docs-showcase/files/src/docs/plugins/user-interface/right-to-left/02-global-selectors.ts +14 -0
  270. package/templates/docs-showcase/files/src/docs/plugins/user-interface/right-to-left/03-icons-are-mirrored-automatically.ts +14 -0
  271. package/templates/docs-showcase/files/src/docs/plugins/user-interface/settings/09-toggle.ts +20 -0
  272. package/templates/docs-showcase/files/src/docs/plugins/user-interface/settings/10-text.ts +23 -0
  273. package/templates/docs-showcase/files/src/docs/plugins/user-interface/settings/11-textarea.ts +23 -0
  274. package/templates/docs-showcase/files/src/docs/plugins/user-interface/settings/12-number.ts +23 -0
  275. package/templates/docs-showcase/files/src/docs/plugins/user-interface/settings/13-slider.ts +23 -0
  276. package/templates/docs-showcase/files/src/docs/plugins/user-interface/settings/14-dropdown.ts +28 -0
  277. package/templates/docs-showcase/files/src/docs/plugins/user-interface/settings/15-file.ts +27 -0
  278. package/templates/docs-showcase/files/src/docs/plugins/user-interface/settings/16-folder.ts +23 -0
  279. package/templates/docs-showcase/files/src/docs/plugins/user-interface/settings/17-color-picker.ts +20 -0
  280. package/templates/docs-showcase/files/src/docs/plugins/user-interface/settings/18-validating-input.ts +28 -0
  281. package/templates/docs-showcase/files/src/docs/plugins/user-interface/settings/23-groups.ts +27 -0
  282. package/templates/docs-showcase/files/src/docs/plugins/user-interface/settings/32-cleanup.ts +30 -0
  283. package/templates/docs-showcase/files/src/docs/plugins/user-interface/settings/33-no-top-level-heading.ts +27 -0
  284. package/templates/docs-showcase/files/src/docs/plugins/user-interface/settings/34-headings-only-when-there-are-multiple-se.ts +26 -0
  285. package/templates/docs-showcase/files/src/docs/plugins/user-interface/settings/36-headings.ts +20 -0
  286. package/templates/docs-showcase/files/src/docs/plugins/user-interface/settings/38-moment-format.ts +42 -0
  287. package/templates/docs-showcase/files/src/docs/plugins/user-interface/settings/39-buttons.ts +26 -0
  288. package/templates/docs-showcase/files/src/docs/plugins/user-interface/settings/40-extra-button.ts +28 -0
  289. package/templates/docs-showcase/files/src/docs/plugins/user-interface/settings/41-progress-bar.ts +23 -0
  290. package/templates/docs-showcase/files/src/docs/plugins/user-interface/status-bar/01-intro.ts +20 -0
  291. package/templates/docs-showcase/files/src/docs/plugins/user-interface/status-bar/02-intro.ts +25 -0
  292. package/templates/docs-showcase/files/src/docs/plugins/user-interface/views/01-intro.ts +39 -0
  293. package/templates/docs-showcase/files/src/docs/plugins/user-interface/workspace/05-inspect-the-workspace.ts +23 -0
  294. package/templates/docs-showcase/files/src/docs/plugins/user-interface/workspace/06-leaf-groups.ts +19 -0
  295. package/templates/docs-showcase/files/src/docs/plugins/vault/02-read-files.ts +37 -0
  296. package/templates/docs-showcase/files/src/docs/plugins/vault/03-modify-files.ts +19 -0
  297. package/templates/docs-showcase/files/src/docs/plugins/vault/04-modify-files.ts +22 -0
  298. package/templates/docs-showcase/files/src/docs/plugins/vault/05-is-it-a-file-or-folder.ts +25 -0
  299. package/templates/docs-showcase/files/src/docs/reference/css-variables/about-styling/01-for-plugins.ts +14 -0
  300. package/templates/docs-showcase/files/src/docs/reference/css-variables/about-styling/02-for-themes-and-snippets.ts +14 -0
  301. package/templates/docs-showcase/files/src/docs/reference/css-variables/publish/site-fonts/01-intro.ts +14 -0
  302. package/templates/docs-showcase/files/src/docs/reference/typescript-api/command/callback/01-example.ts +24 -0
  303. package/templates/docs-showcase/files/src/docs/reference/typescript-api/debounce/01-example.ts +24 -0
  304. package/templates/docs-showcase/files/src/docs/reference/typescript-api/vault/process/01-example.ts +22 -0
  305. package/templates/docs-showcase/files/src/docs/themes/app-themes/build-a-theme/05-step-4-change-the-font.ts +14 -0
  306. package/templates/docs-showcase/files/src/docs/themes/app-themes/build-a-theme/06-step-5-change-the-background-color.ts +14 -0
  307. 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
  308. package/templates/docs-showcase/files/src/docs/themes/app-themes/build-a-theme/08-step-7-discover-css-variables-in-use.ts +14 -0
  309. package/templates/docs-showcase/files/src/docs/themes/app-themes/embed-fonts-and-images-in-your-theme/02-use-data-urls.ts +14 -0
  310. package/templates/docs-showcase/files/src/docs/themes/app-themes/theme-guidelines/01-use-css-variables.ts +14 -0
  311. 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
  312. package/templates/docs-showcase/files/src/docs/themes/obsidian-publish-themes/build-a-publish-theme/01-intro.ts +14 -0
  313. package/templates/docs-showcase/files/src/docs/tsconfig.json +25 -0
  314. package/templates/docs-showcase/host/entry.d.ts +8 -0
  315. package/templates/docs-showcase/host/entry.js +4 -0
  316. package/templates/docs-showcase/host/host.ts +449 -0
  317. package/templates/docs-showcase/host/tsconfig.json +25 -0
  318. package/templates/docs-showcase/snippets.json +3566 -0
  319. package/templates/official-sample/README.md +9 -0
  320. package/templates/official-sample/files/.editorconfig.vendored +11 -0
  321. package/templates/official-sample/files/.github/workflows/lint.yml.vendored +27 -0
  322. package/templates/official-sample/files/.github/workflows/release.yml.vendored +50 -0
  323. package/templates/official-sample/files/.gitignore.vendored +22 -0
  324. package/templates/official-sample/files/.npmrc.vendored +1 -0
  325. package/templates/official-sample/files/AGENTS.md.vendored +269 -0
  326. package/templates/official-sample/files/LICENSE.vendored +5 -0
  327. package/templates/official-sample/files/README.md.vendored +92 -0
  328. package/templates/official-sample/files/esbuild.config.mjs.vendored +49 -0
  329. package/templates/official-sample/files/eslint.config.mts.vendored +32 -0
  330. package/templates/official-sample/files/manifest.json.vendored +11 -0
  331. package/templates/official-sample/files/package-lock.json.vendored +5053 -0
  332. package/templates/official-sample/files/package.json.vendored +27 -0
  333. package/templates/official-sample/files/src/main.ts.vendored +114 -0
  334. package/templates/official-sample/files/src/settings.ts.vendored +38 -0
  335. package/templates/official-sample/files/styles.css.vendored +8 -0
  336. package/templates/official-sample/files/tsconfig.json.vendored +19 -0
  337. package/templates/official-sample/files/version-bump.mjs.vendored +17 -0
  338. package/templates/official-sample/files/versions.json.vendored +3 -0
  339. package/upstreams.json +35 -0
  340. package/templates/default/dprint.json_dev-utils.ejs +0 -10
  341. package/templates/default/jest.config.ts@lint-root-dir_dev-utils.ejs +0 -1
  342. package/templates/default/scripts/build.ts@bundler_cli-bundler@lint-build-styles_dev-utils.ejs +0 -1
  343. package/templates/default/scripts/build.ts@bundler_esbuild@dev-utils-pre-build_tailwind.ejs +0 -2
  344. package/templates/default/scripts/build.ts@bundler_esbuild@lint-build-styles_dev-utils.ejs +0 -1
  345. package/templates/default/scripts/build.ts@bundler_esbuild@preset_dev-utils.ejs +0 -7
  346. package/templates/default/scripts/commit.ts_dev-utils.ejs +0 -3
  347. package/templates/default/scripts/dev.ts@bundler_esbuild@dev-utils-pre-build_tailwind.ejs +0 -2
  348. package/templates/default/scripts/dev.ts@bundler_esbuild@lint-build-styles_dev-utils.ejs +0 -1
  349. package/templates/default/scripts/dev.ts@bundler_esbuild@preset_dev-utils.ejs +0 -7
  350. package/templates/default/scripts/esbuild-plugins.ts.ejs +0 -20
  351. package/templates/default/scripts/esbuild-plugins.ts@dev-utils-import_vue.ejs +0 -2
  352. package/templates/default/scripts/esbuild-plugins.ts@dev-utils-plugin_vue.ejs +0 -1
  353. package/templates/default/scripts/esbuild-plugins.ts@dev-utils-plugin_wasm.ejs +0 -13
  354. package/templates/default/scripts/format-check.ts@tool_dprint@preset_dev-utils.ejs +0 -7
  355. package/templates/default/scripts/format.ts@tool_dprint@preset_dev-utils.ejs +0 -7
  356. package/templates/default/scripts/lint-fix.ts@tool_eslint@preset_dev-utils.ejs +0 -7
  357. package/templates/default/scripts/lint-md-fix.ts_dev-utils.ejs +0 -7
  358. package/templates/default/scripts/lint-md.ts_dev-utils.ejs +0 -7
  359. package/templates/default/scripts/lint.ts@tool_eslint@preset_dev-utils.ejs +0 -7
  360. package/templates/default/scripts/prepare.ts_dev-utils.ejs +0 -3
  361. package/templates/default/scripts/spellcheck.ts_dev-utils.ejs +0 -7
  362. package/templates/default/scripts/test-watch.ts_dev-utils@tool_jest.ejs +0 -13
  363. package/templates/default/scripts/test-watch.ts_dev-utils@tool_vitest.ejs +0 -8
  364. package/templates/default/scripts/test.ts_dev-utils@tool_jest.ejs +0 -13
  365. package/templates/default/scripts/test.ts_dev-utils@tool_vitest.ejs +0 -8
  366. package/templates/default/scripts/vite.config.ts@lint-empty-out-dir_dev-utils.ejs +0 -1
  367. package/templates/default/scripts/vite.config.ts@lint-out-dir_dev-utils.ejs +0 -1
  368. package/templates/default/scripts/webpack.config.ts@lint-webpack-default_dev-utils.ejs +0 -1
  369. package/templates/default/src/main.ts@import_css-modules.ejs +0 -1
  370. package/templates/default/src/views/sample-preact-view.tsx_dev-utils.ejs +0 -45
  371. package/templates/default/tsconfig.json_dev-utils@compiler-options_preact.ejs +0 -2
  372. package/templates/default/tsconfig.json_dev-utils@compiler-options_react.ejs +0 -1
  373. package/templates/default/tsconfig.json_dev-utils@compiler-options_solid.ejs +0 -2
  374. /package/templates/default/.github/workflows/{ci.yml@steps_biome-linter.ejs → ci.yml_standalone@steps_biome-linter.ejs} +0 -0
  375. /package/templates/default/.github/workflows/{ci.yml@steps_cspell.ejs → ci.yml_standalone@steps_cspell.ejs} +0 -0
  376. /package/templates/default/.github/workflows/{ci.yml@steps_dprint.ejs → ci.yml_standalone@steps_dprint.ejs} +0 -0
  377. /package/templates/default/.github/workflows/{ci.yml@steps_eslint.ejs → ci.yml_standalone@steps_eslint.ejs} +0 -0
  378. /package/templates/default/.github/workflows/{ci.yml@steps_jest.ejs → ci.yml_standalone@steps_jest.ejs} +0 -0
  379. /package/templates/default/.github/workflows/{ci.yml@steps_markdownlint.ejs → ci.yml_standalone@steps_markdownlint.ejs} +0 -0
  380. /package/templates/default/.github/workflows/{ci.yml@steps_prettier.ejs → ci.yml_standalone@steps_prettier.ejs} +0 -0
  381. /package/templates/default/.github/workflows/{ci.yml@steps_vitest.ejs → ci.yml_standalone@steps_vitest.ejs} +0 -0
  382. /package/templates/default/{.gitignore_tailwind.ejs → .gitignore_tailwind-cli.ejs} +0 -0
  383. /package/templates/default/{CONTRIBUTING.md@scripts_dev-utils.ejs → CONTRIBUTING.md@scripts_framework.ejs} +0 -0
  384. /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
  385. /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
  386. /package/templates/default/{eslint.config.mts_dev-utils.ejs → eslint.config.mts_framework.ejs} +0 -0
  387. /package/templates/default/{jest.config.ts@ts-jest-tsconfig_solid.ejs → jest.config.ts_standalone@ts-jest-tsconfig_solid.ejs} +0 -0
  388. /package/templates/default/{prettier.config.mjs.ejs → prettier.config.mjs_standalone.ejs} +0 -0
  389. /package/templates/default/scripts/{commitlint-config.ts.ejs → commitlint-config.ts_standalone.ejs} +0 -0
  390. /package/templates/default/scripts/{nano-staged-config.ts.ejs → nano-staged-config.ts_inline-nano-staged.ejs} +0 -0
  391. /package/templates/default/scripts/{rollup.config.ts@import_rollup-json.ejs → rollup.config.ts_framework@import_rollup-json.ejs} +0 -0
  392. /package/templates/default/scripts/{rollup.config.ts@import_scss.ejs → rollup.config.ts_framework@import_scss.ejs} +0 -0
  393. /package/templates/default/scripts/{rollup.config.ts@unwrap_rollup-json.ejs → rollup.config.ts_framework@unwrap_rollup-json.ejs} +0 -0
  394. /package/templates/default/scripts/{rollup.config.ts@unwrap_scss.ejs → rollup.config.ts_framework@unwrap_scss.ejs} +0 -0
  395. /package/templates/default/scripts/{rollup.config.ts@import_rollup-babel.ejs → rollup.config.ts_standalone@import_rollup-babel.ejs} +0 -0
  396. /package/templates/default/scripts/{rollup.config.ts@import_rollup-postcss.ejs → rollup.config.ts_standalone@import_rollup-postcss.ejs} +0 -0
  397. /package/templates/default/scripts/{rollup.config.ts@import_svelte.ejs → rollup.config.ts_standalone@import_svelte.ejs} +0 -0
  398. /package/templates/default/scripts/{rollup.config.ts@import_vue.ejs → rollup.config.ts_standalone@import_vue.ejs} +0 -0
  399. /package/templates/default/scripts/{rollup.config.ts@import_wasm.ejs → rollup.config.ts_standalone@import_wasm.ejs} +0 -0
  400. /package/templates/default/scripts/{rollup.config.ts@post-plugin_preact.ejs → rollup.config.ts_standalone@post-plugin_preact.ejs} +0 -0
  401. /package/templates/default/scripts/{rollup.config.ts@post-plugin_react.ejs → rollup.config.ts_standalone@post-plugin_react.ejs} +0 -0
  402. /package/templates/default/scripts/{rollup.config.ts@post-plugin_rollup-json.ejs → rollup.config.ts_standalone@post-plugin_rollup-json.ejs} +0 -0
  403. /package/templates/default/scripts/{rollup.config.ts@post-plugin_rollup-postcss.ejs → rollup.config.ts_standalone@post-plugin_rollup-postcss.ejs} +0 -0
  404. /package/templates/default/scripts/{rollup.config.ts@post-plugin_scss.ejs → rollup.config.ts_standalone@post-plugin_scss.ejs} +0 -0
  405. /package/templates/default/scripts/{rollup.config.ts@post-plugin_solid.ejs → rollup.config.ts_standalone@post-plugin_solid.ejs} +0 -0
  406. /package/templates/default/scripts/{rollup.config.ts@post-plugin_wasm.ejs → rollup.config.ts_standalone@post-plugin_wasm.ejs} +0 -0
  407. /package/templates/default/scripts/{rollup.config.ts@pre-plugin_svelte.ejs → rollup.config.ts_standalone@pre-plugin_svelte.ejs} +0 -0
  408. /package/templates/default/scripts/{rollup.config.ts@pre-plugin_vue.ejs → rollup.config.ts_standalone@pre-plugin_vue.ejs} +0 -0
  409. /package/templates/default/scripts/{rollup.config.ts@unwrap_rollup-babel.ejs → rollup.config.ts_standalone@unwrap_rollup-babel.ejs} +0 -0
  410. /package/templates/default/scripts/{rollup.config.ts@unwrap_rollup-postcss.ejs → rollup.config.ts_standalone@unwrap_rollup-postcss.ejs} +0 -0
  411. /package/templates/default/scripts/{rollup.config.ts@unwrap_svelte.ejs → rollup.config.ts_standalone@unwrap_svelte.ejs} +0 -0
  412. /package/templates/default/scripts/{rollup.config.ts@unwrap_vue.ejs → rollup.config.ts_standalone@unwrap_vue.ejs} +0 -0
  413. /package/templates/default/scripts/{rollup.config.ts@unwrap_wasm.ejs → rollup.config.ts_standalone@unwrap_wasm.ejs} +0 -0
  414. /package/templates/default/scripts/{test-watch.ts_dev-utils.ejs → test-watch.ts_framework.ejs} +0 -0
  415. /package/templates/default/scripts/{test.ts_dev-utils.ejs → test.ts_framework.ejs} +0 -0
  416. /package/templates/default/scripts/{vite.config.ts@import_preact.ejs → vite.config.ts_standalone@import_preact.ejs} +0 -0
  417. /package/templates/default/scripts/{vite.config.ts@import_react.ejs → vite.config.ts_standalone@import_react.ejs} +0 -0
  418. /package/templates/default/scripts/{vite.config.ts@import_solid.ejs → vite.config.ts_standalone@import_solid.ejs} +0 -0
  419. /package/templates/default/scripts/{vite.config.ts@import_svelte.ejs → vite.config.ts_standalone@import_svelte.ejs} +0 -0
  420. /package/templates/default/scripts/{vite.config.ts@import_vue.ejs → vite.config.ts_standalone@import_vue.ejs} +0 -0
  421. /package/templates/default/scripts/{vite.config.ts@plugin_preact.ejs → vite.config.ts_standalone@plugin_preact.ejs} +0 -0
  422. /package/templates/default/scripts/{vite.config.ts@plugin_react.ejs → vite.config.ts_standalone@plugin_react.ejs} +0 -0
  423. /package/templates/default/scripts/{vite.config.ts@plugin_solid.ejs → vite.config.ts_standalone@plugin_solid.ejs} +0 -0
  424. /package/templates/default/scripts/{vite.config.ts@plugin_svelte.ejs → vite.config.ts_standalone@plugin_svelte.ejs} +0 -0
  425. /package/templates/default/scripts/{vite.config.ts@plugin_vue.ejs → vite.config.ts_standalone@plugin_vue.ejs} +0 -0
  426. /package/templates/default/scripts/{webpack.config.ts@import_svelte.ejs → webpack.config.ts_standalone@import_svelte.ejs} +0 -0
  427. /package/templates/default/scripts/{webpack.config.ts@import_vue.ejs → webpack.config.ts_standalone@import_vue.ejs} +0 -0
  428. /package/templates/default/scripts/{webpack.config.ts@import_webpack-css-extract.ejs → webpack.config.ts_standalone@import_webpack-css-extract.ejs} +0 -0
  429. /package/templates/default/scripts/{webpack.config.ts@plugin_vue.ejs → webpack.config.ts_standalone@plugin_vue.ejs} +0 -0
  430. /package/templates/default/scripts/{webpack.config.ts@plugin_webpack-css-extract.ejs → webpack.config.ts_standalone@plugin_webpack-css-extract.ejs} +0 -0
  431. /package/templates/default/scripts/{webpack.config.ts@rule_css-modules.ejs → webpack.config.ts_standalone@rule_css-modules.ejs} +0 -0
  432. /package/templates/default/scripts/{webpack.config.ts@rule_css.ejs → webpack.config.ts_standalone@rule_css.ejs} +0 -0
  433. /package/templates/default/scripts/{webpack.config.ts@rule_postcss.ejs → webpack.config.ts_standalone@rule_postcss.ejs} +0 -0
  434. /package/templates/default/scripts/{webpack.config.ts@rule_scss.ejs → webpack.config.ts_standalone@rule_scss.ejs} +0 -0
  435. /package/templates/default/scripts/{webpack.config.ts@rule_solid.ejs → webpack.config.ts_standalone@rule_solid.ejs} +0 -0
  436. /package/templates/default/scripts/{webpack.config.ts@rule_svelte.ejs → webpack.config.ts_standalone@rule_svelte.ejs} +0 -0
  437. /package/templates/default/scripts/{webpack.config.ts@rule_tailwind.ejs → webpack.config.ts_standalone@rule_tailwind.ejs} +0 -0
  438. /package/templates/default/scripts/{webpack.config.ts@rule_vue.ejs → webpack.config.ts_standalone@rule_vue.ejs} +0 -0
  439. /package/templates/default/scripts/{webpack.config.ts@rule_wasm.ejs → webpack.config.ts_standalone@rule_wasm.ejs} +0 -0
  440. /package/templates/default/scripts/{webpack.config.ts@ts-loader-compiler-options_vue.ejs → webpack.config.ts_standalone@ts-loader-compiler-options_vue.ejs} +0 -0
  441. /package/templates/default/scripts/{webpack.config.ts@ts-loader-options_vue.ejs → webpack.config.ts_standalone@ts-loader-options_vue.ejs} +0 -0
  442. /package/templates/default/src/{plugin-settings-component.test.ts_enhanced@test-imports_vitest.ejs → plugin-settings-component.test.ts_all-in-one@test-imports_vitest.ejs} +0 -0
  443. /package/templates/default/src/{plugin-settings.ts_enhanced.ejs → plugin-settings.ts_all-in-one.ejs} +0 -0
  444. /package/templates/default/src/{plugin.ts_enhanced@import2_codemirror.ejs → plugin.ts_all-in-one@import2_codemirror.ejs} +0 -0
  445. /package/templates/default/src/{plugin.ts_enhanced@import2_i18next.ejs → plugin.ts_all-in-one@import2_i18next.ejs} +0 -0
  446. /package/templates/default/src/{plugin.ts_enhanced@import2_lit.ejs → plugin.ts_all-in-one@import2_lit.ejs} +0 -0
  447. /package/templates/default/src/{plugin.ts_enhanced@import2_preact.ejs → plugin.ts_all-in-one@import2_preact.ejs} +0 -0
  448. /package/templates/default/src/{plugin.ts_enhanced@import2_react.ejs → plugin.ts_all-in-one@import2_react.ejs} +0 -0
  449. /package/templates/default/src/{plugin.ts_enhanced@import2_solid.ejs → plugin.ts_all-in-one@import2_solid.ejs} +0 -0
  450. /package/templates/default/src/{plugin.ts_enhanced@import2_svelte.ejs → plugin.ts_all-in-one@import2_svelte.ejs} +0 -0
  451. /package/templates/default/src/{plugin.ts_enhanced@import2_typesafe-i18n.ejs → plugin.ts_all-in-one@import2_typesafe-i18n.ejs} +0 -0
  452. /package/templates/default/src/{plugin.ts_enhanced@import2_vue.ejs → plugin.ts_all-in-one@import2_vue.ejs} +0 -0
  453. /package/templates/default/src/{plugin.ts_enhanced@import2_wasm.ejs → plugin.ts_all-in-one@import2_wasm.ejs} +0 -0
  454. /package/templates/default/src/{plugin.ts_enhanced@method_ui-view.ejs → plugin.ts_all-in-one@method_ui-view.ejs} +0 -0
  455. /package/templates/default/src/{plugin.ts_enhanced@onload_codemirror.ejs → plugin.ts_all-in-one@onload_codemirror.ejs} +0 -0
  456. /package/templates/default/src/{plugin.ts_enhanced@onload_i18next.ejs → plugin.ts_all-in-one@onload_i18next.ejs} +0 -0
  457. /package/templates/default/src/{plugin.ts_enhanced@onload_lit.ejs → plugin.ts_all-in-one@onload_lit.ejs} +0 -0
  458. /package/templates/default/src/{plugin.ts_enhanced@onload_preact.ejs → plugin.ts_all-in-one@onload_preact.ejs} +0 -0
  459. /package/templates/default/src/{plugin.ts_enhanced@onload_react.ejs → plugin.ts_all-in-one@onload_react.ejs} +0 -0
  460. /package/templates/default/src/{plugin.ts_enhanced@onload_solid.ejs → plugin.ts_all-in-one@onload_solid.ejs} +0 -0
  461. /package/templates/default/src/{plugin.ts_enhanced@onload_svelte.ejs → plugin.ts_all-in-one@onload_svelte.ejs} +0 -0
  462. /package/templates/default/src/{plugin.ts_enhanced@onload_typesafe-i18n.ejs → plugin.ts_all-in-one@onload_typesafe-i18n.ejs} +0 -0
  463. /package/templates/default/src/{plugin.ts_enhanced@onload_vue.ejs → plugin.ts_all-in-one@onload_vue.ejs} +0 -0
  464. /package/templates/default/src/{plugin.ts_enhanced@onload_wasm.ejs → plugin.ts_all-in-one@onload_wasm.ejs} +0 -0
  465. /package/templates/default/src/preact-components/{sample-preact-component.tsx_dev-utils.ejs → sample-preact-component.tsx_framework.ejs} +0 -0
  466. /package/templates/default/src/solid-components/{sample-solid-component.tsx_dev-utils.ejs → sample-solid-component.tsx_framework.ejs} +0 -0
  467. /package/templates/default/src/styles/{main.css_dev-utils@content_tailwind.ejs → main.css_framework@content_tailwind.ejs} +0 -0
  468. /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
  469. /package/templates/default/src/views/{sample-preact-view.tsx_standalone.ejs → sample-preact-view.tsx.ejs} +0 -0
  470. /package/templates/default/src/views/{sample-solid-view.tsx_dev-utils.ejs → sample-solid-view.tsx_framework.ejs} +0 -0
  471. /package/templates/default/src/wasm/{answer.ts_esbuild.ejs → answer.ts_wasm-esbuild.ejs} +0 -0
  472. /package/templates/default/src/wasm/{answer.ts_parcel.ejs → answer.ts_wasm-parcel.ejs} +0 -0
  473. /package/templates/default/src/wasm/{answer.ts_rollup.ejs → answer.ts_wasm-rollup.ejs} +0 -0
  474. /package/templates/default/src/wasm/{answer.ts_vite.ejs → answer.ts_wasm-vite.ejs} +0 -0
  475. /package/templates/default/src/wasm/{answer.ts_webpack.ejs → answer.ts_wasm-webpack.ejs} +0 -0
  476. /package/templates/default/src/{wasm.d.ts_esbuild.ejs → wasm.d.ts_wasm-esbuild.ejs} +0 -0
  477. /package/templates/default/src/{wasm.d.ts_parcel.ejs → wasm.d.ts_wasm-parcel.ejs} +0 -0
  478. /package/templates/default/src/{wasm.d.ts_rollup.ejs → wasm.d.ts_wasm-rollup.ejs} +0 -0
  479. /package/templates/default/src/{wasm.d.ts_vite.ejs → wasm.d.ts_wasm-vite.ejs} +0 -0
  480. /package/templates/default/src/{wasm.d.ts_webpack.ejs → wasm.d.ts_wasm-webpack.ejs} +0 -0
  481. /package/templates/default/{tsconfig.json_dev-utils@compiler-options_i18next.ejs → tsconfig.json_framework@compiler-options_i18next.ejs} +0 -0
  482. /package/templates/default/{tsconfig.json_dev-utils@compiler-options_lit.ejs → tsconfig.json_framework@compiler-options_lit.ejs} +0 -0
  483. /package/templates/default/{tsconfig.json_dev-utils@include_has-e2e.ejs → tsconfig.json_framework@include_has-e2e.ejs} +0 -0
  484. /package/templates/default/{tsconfig.json_dev-utils@include_svelte.ejs → tsconfig.json_framework@include_svelte.ejs} +0 -0
  485. /package/templates/default/{tsconfig.json_dev-utils@include_vue.ejs → tsconfig.json_framework@include_vue.ejs} +0 -0
  486. /package/templates/default/{tsconfig.json_dev-utils@types_jest.ejs → tsconfig.json_framework@types_jest.ejs} +0 -0
  487. /package/templates/default/{tsconfig.json_dev-utils@types_svelte.ejs → tsconfig.json_framework@types_svelte.ejs} +0 -0
  488. /package/templates/default/{tsconfig.json_dev-utils@types_wdio-obsidian.ejs → tsconfig.json_framework@types_wdio-obsidian.ejs} +0 -0
  489. /package/templates/default/{tsconfig.json_dev-utils@types_with-unofficial.ejs → tsconfig.json_framework@types_with-unofficial.ejs} +0 -0
  490. /package/templates/default/{vitest.config.ts_dev-utils.ejs → vitest.config.ts_framework.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,12 +15,12 @@ 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 join8,
24
24
  resolve as resolvePath
25
25
  } from "node:path";
26
26
  import { compare } from "semver";
@@ -191,38 +191,38 @@ async function promptApiSubset(savedValue) {
191
191
  return promptFeature({ defaultOption: new Official(), message: "Obsidian API subset", options: API_SUBSET_OPTIONS, savedValue });
192
192
  }
193
193
 
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
- }
199
-
200
194
  // src/features/bundler/esbuild.ts
201
195
  var Esbuild = class extends FeatureOption {
202
196
  constructor() {
203
197
  super({ promptHint: "Fast and simple (recommended)", promptLabel: "esbuild", settingValue: "esbuild" });
204
198
  }
205
- configure(builder, answers) {
199
+ configure(builder) {
206
200
  builder.addPackage("esbuild");
207
- if (isDevUtilsPreset(answers.preset)) {
208
- builder.addFiles(["scripts/esbuild-plugins.ts"]);
209
- }
210
201
  }
211
202
  };
212
203
 
204
+ // src/features/preset/is-framework-preset.ts
205
+ var FRAMEWORK_PRESETS = /* @__PURE__ */ new Set(["all-in-one", "demo", "docs-showcase"]);
206
+ function isFrameworkPreset(preset) {
207
+ return FRAMEWORK_PRESETS.has(preset);
208
+ }
209
+
213
210
  // src/features/bundler/parcel.ts
214
211
  var Parcel = class extends FeatureOption {
215
212
  constructor() {
216
213
  super({ promptHint: "Zero-config bundler", promptLabel: "Parcel", settingValue: "parcel" });
217
214
  }
218
- configure(builder) {
215
+ configure(builder, answers) {
216
+ if (isFrameworkPreset(answers.preset)) {
217
+ 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");
218
+ return;
219
+ }
219
220
  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
221
  ".parcelrc",
221
222
  "parcel-namer-obsidian.cjs",
222
223
  "parcel-resolver-obsidian.cjs",
223
224
  "parcel-transformer-inline-imports.cjs"
224
- ]);
225
- builder.addPartial("cli-bundler");
225
+ ]).addPartial("parcel-targets").addPartial("cli-bundler");
226
226
  }
227
227
  };
228
228
 
@@ -231,12 +231,16 @@ var Rollup = class extends FeatureOption {
231
231
  constructor() {
232
232
  super({ promptHint: "Flexible with plugin ecosystem", promptLabel: "Rollup", settingValue: "rollup" });
233
233
  }
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([
234
+ configure(builder, answers) {
235
+ builder.addPackage("@rollup/plugin-commonjs").addPackage("@rollup/plugin-node-resolve").addPackage("rollup").addFiles([
236
236
  "rollup.config.mjs",
237
237
  "scripts/rollup.config.ts"
238
238
  ]);
239
- builder.addPartial("cli-bundler");
239
+ if (isFrameworkPreset(answers.preset)) {
240
+ builder.addPackage("esbuild").addDepcheckIgnore("esbuild", "the peer dependency `rollup-plugin-esbuild` runs; nothing imports it.").addPackage("rollup-plugin-esbuild").addPartial("adapter-cli");
241
+ return;
242
+ }
243
+ builder.addPackage("@rollup/plugin-typescript").addPackage("@rollup/plugin-terser").addPartial("cli-bundler");
240
244
  }
241
245
  };
242
246
 
@@ -245,12 +249,12 @@ var Vite = class extends FeatureOption {
245
249
  constructor() {
246
250
  super({ promptHint: "Modern dev server with HMR", promptLabel: "Vite", settingValue: "vite" });
247
251
  }
248
- configure(builder) {
252
+ configure(builder, answers) {
249
253
  builder.addPackage("vite").addFiles([
250
254
  "vite.config.ts",
251
255
  "scripts/vite.config.ts"
252
256
  ]);
253
- builder.addPartial("cli-bundler");
257
+ builder.addPartial(isFrameworkPreset(answers.preset) ? "adapter-cli" : "cli-bundler");
254
258
  }
255
259
  };
256
260
 
@@ -259,12 +263,16 @@ var Webpack = class extends FeatureOption {
259
263
  constructor() {
260
264
  super({ promptHint: "Mature bundler with broad plugin support", promptLabel: "Webpack", settingValue: "webpack" });
261
265
  }
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([
266
+ configure(builder, answers) {
267
+ builder.addPackage("webpack").addPackage("webpack-cli").addDepcheckIgnore("webpack-cli", "what the build script runs as the `webpack` command.").addFiles([
264
268
  "webpack.config.ts",
265
269
  "scripts/webpack.config.ts"
266
270
  ]);
267
- builder.addPartial("cli-bundler");
271
+ if (isFrameworkPreset(answers.preset)) {
272
+ builder.addPackage("esbuild-loader").addDepcheckIgnore("esbuild-loader", "named as a loader string in `scripts/webpack.config.ts`.").addPartial("adapter-cli");
273
+ return;
274
+ }
275
+ builder.addPackage("terser-webpack-plugin").addPackage("ts-loader").addDepcheckIgnore("ts-loader", "named as a loader string in `scripts/webpack.config.ts`.").addPartial("cli-bundler");
268
276
  }
269
277
  };
270
278
 
@@ -275,31 +283,40 @@ async function promptBundler(savedValue) {
275
283
  }
276
284
 
277
285
  // src/features/git-hooks.ts
286
+ var INITIAL_COMMIT_MESSAGE = "chore: initial commit from create-obsidian-plugin";
278
287
  function addHusky(builder) {
279
288
  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
289
  }
281
- function addStagedFilesHook(builder) {
290
+ function addStagedFilesHook(builder, preset) {
282
291
  addHusky(builder);
292
+ builder.addPartial(usesToolkitNanoStagedConfig(preset) ? "toolkit-nano-staged" : "inline-nano-staged");
283
293
  builder.addPackage("nano-staged").addDepcheckIgnore("nano-staged", "`.husky/pre-commit` runs it; configured by `scripts/nano-staged-config.ts`.").addFiles([
284
294
  ".husky/pre-commit",
285
295
  ".nano-staged.mjs",
286
296
  "scripts/nano-staged-config.ts"
287
297
  ]);
288
298
  }
299
+ function usesToolkitNanoStagedConfig(preset) {
300
+ return isFrameworkPreset(preset);
301
+ }
289
302
 
290
303
  // src/features/commit-linting/conventional-commits.ts
291
304
  var ConventionalCommits = class extends FeatureOption {
292
305
  constructor() {
293
306
  super({ promptHint: "commitlint + a husky commit-msg hook", promptLabel: "Conventional Commits", settingValue: "conventional-commits" });
294
307
  }
295
- configure(builder) {
308
+ configure(builder, answers) {
296
309
  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([
310
+ 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([
298
311
  "commitlint.config.ts",
299
312
  "scripts/commit.ts",
300
313
  "scripts/commitlint-config.ts",
301
314
  ".husky/commit-msg"
302
315
  ]);
316
+ if (isFrameworkPreset(answers.preset)) {
317
+ return;
318
+ }
319
+ 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");
303
320
  }
304
321
  };
305
322
 
@@ -319,14 +336,24 @@ async function promptCommitLinting(savedValue) {
319
336
  // src/features/coverage-badge/coverage-badge.ts
320
337
  var CoverageBadge = class extends FeatureOption {
321
338
  constructor() {
322
- super({ promptHint: 'A "coverage: 100%" README badge', promptLabel: "Coverage badge", settingValue: "coverage-badge" });
339
+ super({ promptHint: "A coverage README badge, measured by CI where the project has one", promptLabel: "Coverage badge", settingValue: "coverage-badge" });
323
340
  }
324
341
  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})`
342
+ const repoUrl = `https://github.com/${answers.authorGitHubName}/obsidian-${answers.pluginId}`;
343
+ if (!isMeasured(answers)) {
344
+ builder.addBadge(`[![Coverage: 100%](https://img.shields.io/badge/coverage-100%25-brightgreen)](${repoUrl})`);
345
+ return;
346
+ }
347
+ builder.addPartial("measured-coverage-badge").addBadge(
348
+ `[![Coverage](https://raw.githubusercontent.com/${answers.authorGitHubName}/obsidian-${answers.pluginId}/badges/coverage.svg)](${repoUrl}/actions/workflows/ci.yml)`
327
349
  );
328
350
  }
329
351
  };
352
+ var CI_ANSWERS = /* @__PURE__ */ new Set(["ci", "ci-and-release"]);
353
+ var MEASURING_TEST_RUNNERS = /* @__PURE__ */ new Set(["jest", "vitest"]);
354
+ function isMeasured(answers) {
355
+ return isFrameworkPreset(answers.preset) && CI_ANSWERS.has(answers.gitHubActions) && MEASURING_TEST_RUNNERS.has(answers.testRunner);
356
+ }
330
357
 
331
358
  // src/features/coverage-badge/none.ts
332
359
  var None2 = class extends FeatureOption {
@@ -366,12 +393,16 @@ var WdioObsidian = class extends FeatureOption {
366
393
  constructor() {
367
394
  super({ promptHint: "WebdriverIO service for Obsidian, multi-version & CI/CD", promptLabel: "wdio-obsidian", settingValue: "wdio-obsidian" });
368
395
  }
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",
396
+ configure(builder, answers) {
397
+ 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([
372
398
  "e2e/sample.spec.ts",
373
399
  "scripts/test-e2e.ts"
374
400
  ]).addPartial("has-e2e");
401
+ if (isFrameworkPreset(answers.preset)) {
402
+ builder.addPackage("wdio-obsidian-reporter").addDepcheckIgnore("wdio-obsidian-reporter", "loaded by name by wdio for the `obsidian` reporter `defineWdioObsidianConfig` names.").addFiles(["wdio.conf.mts"]);
403
+ return;
404
+ }
405
+ builder.addFiles(["wdio.conf.ts"]);
375
406
  }
376
407
  };
377
408
 
@@ -452,14 +483,16 @@ var Prettier = class extends FeatureOption {
452
483
  constructor() {
453
484
  super({ promptHint: "Opinionated, widely adopted", promptLabel: "Prettier", settingValue: "prettier" });
454
485
  }
455
- configure(builder) {
486
+ configure(builder, answers) {
456
487
  builder.addLintStagedCommand("*.{ts,tsx,mts}", "prettier --write").addPackage("prettier").addScript("format").addScript("format:check").addFiles([
457
488
  ".prettierignore",
458
489
  "prettier.config.mjs",
459
- "scripts/prettier.config.ts",
460
490
  "scripts/format.ts",
461
491
  "scripts/format-check.ts"
462
492
  ]);
493
+ if (!isFrameworkPreset(answers.preset)) {
494
+ builder.addFiles(["scripts/prettier.config.ts"]);
495
+ }
463
496
  }
464
497
  };
465
498
 
@@ -806,6 +839,11 @@ var None9 = class extends FeatureOption {
806
839
  constructor() {
807
840
  super({ promptHint: "No hot reload support", promptLabel: "(none)", settingValue: "none" });
808
841
  }
842
+ configure(builder, answers) {
843
+ if (isFrameworkPreset(answers.preset)) {
844
+ builder.addBuildOption("reload", "false");
845
+ }
846
+ }
809
847
  };
810
848
 
811
849
  // src/features/hot-reload/obsidian-cli.ts
@@ -813,6 +851,11 @@ var ObsidianCli = class extends FeatureOption {
813
851
  constructor() {
814
852
  super({ promptHint: "Reloads via obsidian plugin:reload CLI command", promptLabel: "Obsidian CLI", settingValue: "obsidian-cli" });
815
853
  }
854
+ configure(builder, answers) {
855
+ if (isFrameworkPreset(answers.preset)) {
856
+ builder.addBuildOption("reload", "'obsidian-cli'");
857
+ }
858
+ }
816
859
  };
817
860
 
818
861
  // src/features/hot-reload/index.ts
@@ -889,7 +932,7 @@ var Eslint = class extends FeatureOption {
889
932
  "scripts/lint.ts",
890
933
  "scripts/lint-fix.ts"
891
934
  ]);
892
- if (isDevUtilsPreset(answers.preset)) {
935
+ if (isFrameworkPreset(answers.preset)) {
893
936
  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
937
  return;
895
938
  }
@@ -918,7 +961,7 @@ var Markdownlint = class extends FeatureOption {
918
961
  configure(builder, answers) {
919
962
  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
963
  // `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
964
+ // So does the toolkit's runner -- which copies its own `.mjs` in when it finds none, pointing
922
965
  // At a `scripts/markdownlint-cli2-config.ts` that then has to exist. Hence this shape rather than a
923
966
  // Single `.mts` that nothing reads.
924
967
  ".markdownlint-cli2.mjs",
@@ -929,7 +972,7 @@ var Markdownlint = class extends FeatureOption {
929
972
  // Repository, which 404 until the user pushes it.
930
973
  "linkinator.config.json"
931
974
  ]);
932
- if (isDevUtilsPreset(answers.preset)) {
975
+ if (isFrameworkPreset(answers.preset)) {
933
976
  return;
934
977
  }
935
978
  builder.addPackage("markdownlint").addPackage("markdownlint-rule-relative-links");
@@ -1032,17 +1075,17 @@ var DEMO_VAULT_TEMPLATE_FILES = [
1032
1075
  "demo-vault/_assets/CodeScriptToolkit/startup.ts"
1033
1076
  ];
1034
1077
 
1035
- // src/features/preset/demo.ts
1036
- var Demo = class extends FeatureOption {
1078
+ // src/features/preset/all-in-one.ts
1079
+ var AllInOne = class extends FeatureOption {
1037
1080
  constructor() {
1038
- super({ promptHint: "All features enabled for demonstration", promptLabel: "Demo", settingValue: "demo" });
1081
+ super({
1082
+ 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",
1083
+ promptLabel: "All-in-one Framework",
1084
+ settingValue: "all-in-one"
1085
+ });
1039
1086
  }
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",
1087
+ configure(builder, answers) {
1088
+ 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
1089
  // Not gated on the answers either: the shared ESLint config's `obsidianmd/validate-license` compares
1047
1090
  // The LICENSE year with the current one, so without this bump every project turns red on 1 January.
1048
1091
  ".github/workflows/update-license-year.yml",
@@ -1054,28 +1097,24 @@ var Demo = class extends FeatureOption {
1054
1097
  "scripts/dev.ts",
1055
1098
  "scripts/gate.ts",
1056
1099
  "scripts/version.ts",
1057
- "src/modals/sample-form-modal.ts",
1058
- "src/modals/sample-suggest-modal.ts",
1059
1100
  "src/plugin-settings.ts",
1060
1101
  "src/plugin-settings-component.ts",
1061
1102
  "src/plugin-settings-tab.ts",
1062
- "src/views/sample-view.ts",
1063
1103
  ...DEMO_VAULT_TEMPLATE_FILES
1064
- ]).addPartial("dev-utils");
1104
+ ]).addPartial("framework");
1105
+ if (answers.gitHubActions !== "ci-and-release") {
1106
+ builder.addFiles([".github/workflows/attest-release-assets.yml"]);
1107
+ }
1065
1108
  }
1066
1109
  };
1067
1110
 
1068
- // src/features/preset/enhanced.ts
1069
- var Enhanced = class extends FeatureOption {
1111
+ // src/features/preset/demo.ts
1112
+ var Demo = class extends FeatureOption {
1070
1113
  constructor() {
1071
- super({ promptHint: "Recommended. Uses obsidian-dev-utils for settings, linting, and more", promptLabel: "Enhanced", settingValue: "enhanced" });
1114
+ super({ promptHint: "All features enabled for demonstration", promptLabel: "Demo", settingValue: "demo" });
1072
1115
  }
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",
1116
+ configure(builder, answers) {
1117
+ 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
1118
  // Not gated on the answers either: the shared ESLint config's `obsidianmd/validate-license` compares
1080
1119
  // The LICENSE year with the current one, so without this bump every project turns red on 1 January.
1081
1120
  ".github/workflows/update-license-year.yml",
@@ -1087,18 +1126,70 @@ var Enhanced = class extends FeatureOption {
1087
1126
  "scripts/dev.ts",
1088
1127
  "scripts/gate.ts",
1089
1128
  "scripts/version.ts",
1129
+ "src/modals/sample-form-modal.ts",
1130
+ "src/modals/sample-suggest-modal.ts",
1090
1131
  "src/plugin-settings.ts",
1091
1132
  "src/plugin-settings-component.ts",
1092
1133
  "src/plugin-settings-tab.ts",
1134
+ "src/views/sample-view.ts",
1093
1135
  ...DEMO_VAULT_TEMPLATE_FILES
1094
- ]).addPartial("dev-utils");
1136
+ ]).addPartial("framework");
1137
+ if (answers.gitHubActions !== "ci-and-release") {
1138
+ builder.addFiles([".github/workflows/attest-release-assets.yml"]);
1139
+ }
1140
+ }
1141
+ };
1142
+
1143
+ // src/features/preset/docs-showcase.ts
1144
+ var DOCS_SHOWCASE_PRESET = "docs-showcase";
1145
+ var DocsShowcase = class extends FeatureOption {
1146
+ constructor() {
1147
+ super({
1148
+ promptHint: "The All-in-one Framework project, plus every code block of the Obsidian developer docs as a command you can run",
1149
+ promptLabel: "Developer docs showcase",
1150
+ settingValue: DOCS_SHOWCASE_PRESET
1151
+ });
1152
+ }
1153
+ configure(builder, answers) {
1154
+ new AllInOne().configure(builder, answers);
1155
+ builder.addPartial("all-in-one").addPackage("@codemirror/language").addPackage("@codemirror/state").addPackage("@codemirror/view").addScript("build:compile:typescript").addFiles(["scripts/build-compile-typescript.ts"]);
1156
+ if (answers.testRunner === "vitest") {
1157
+ builder.addFiles(["src/docs-showcase.desktop.integration.test.ts"]);
1158
+ }
1159
+ }
1160
+ };
1161
+
1162
+ // src/features/preset/official-sample.ts
1163
+ var OFFICIAL_SAMPLE_PRESET = "official-sample";
1164
+ var OFFICIAL_SAMPLE_ANSWER_KEYS = [
1165
+ "authorGitHubName",
1166
+ "authorName",
1167
+ "defaultBranch",
1168
+ "fundingPlatform",
1169
+ "fundingUrl",
1170
+ "fundingUsername",
1171
+ "pluginDescription",
1172
+ "pluginId",
1173
+ "pluginName",
1174
+ "preset"
1175
+ ];
1176
+ var OfficialSample = class extends FeatureOption {
1177
+ constructor() {
1178
+ super({
1179
+ promptHint: "Exactly obsidianmd/obsidian-sample-plugin, with your plugin's id, name, author and description filled in",
1180
+ promptLabel: "Official sample plugin",
1181
+ settingValue: OFFICIAL_SAMPLE_PRESET
1182
+ });
1095
1183
  }
1096
1184
  };
1185
+ function isOfficialSamplePreset(preset) {
1186
+ return preset === OFFICIAL_SAMPLE_PRESET;
1187
+ }
1097
1188
 
1098
1189
  // src/features/preset/standalone.ts
1099
1190
  var Standalone = class extends FeatureOption {
1100
1191
  constructor() {
1101
- super({ promptHint: "Standalone plugin without obsidian-dev-utils dependency", promptLabel: "Standalone", settingValue: "standalone" });
1192
+ super({ promptHint: "Standalone plugin without the @mnaoumov library dependencies", promptLabel: "Standalone", settingValue: "standalone" });
1102
1193
  }
1103
1194
  configure(builder) {
1104
1195
  builder.addScript("dev").addScript("build").addScript("version").addFiles([
@@ -1111,9 +1202,10 @@ var Standalone = class extends FeatureOption {
1111
1202
  };
1112
1203
 
1113
1204
  // src/features/preset/index.ts
1114
- var PRESET_OPTIONS = [new Demo(), new Enhanced(), new Standalone()];
1205
+ var PRESET_OPTIONS = [new AllInOne(), new Demo(), new DocsShowcase(), new Standalone()];
1206
+ var PRESET_PROMPT_OPTIONS = [...PRESET_OPTIONS, new OfficialSample()];
1115
1207
  async function promptPreset(savedValue) {
1116
- return promptFeature({ defaultOption: new Enhanced(), message: "Choose a preset", options: PRESET_OPTIONS, savedValue });
1208
+ return promptFeature({ defaultOption: new AllInOne(), message: "Choose a preset", options: PRESET_PROMPT_OPTIONS, savedValue });
1117
1209
  }
1118
1210
 
1119
1211
  // src/features/spell-checker/cspell.ts
@@ -1142,16 +1234,25 @@ async function promptSpellChecker(savedValue) {
1142
1234
  return promptFeature({ defaultOption: new Cspell(), message: "Spell checker", options: SPELL_CHECKER_OPTIONS, savedValue });
1143
1235
  }
1144
1236
 
1237
+ // src/features/styling/toolkit-styles.ts
1238
+ function addToolkitStyles(builder, bundler, flag) {
1239
+ builder.addBuildStyles(flag).addPartial("toolkit-styles");
1240
+ if (bundler === "webpack") {
1241
+ 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`.");
1242
+ }
1243
+ }
1244
+
1145
1245
  // src/features/styling/css-modules.ts
1146
1246
  var CssModules = class extends FeatureOption {
1147
1247
  constructor() {
1148
1248
  super({ promptHint: "Scoped CSS with .module.css files", promptLabel: "CSS Modules", settingValue: "css-modules" });
1149
1249
  }
1150
1250
  configure(builder, answers) {
1151
- builder.addFiles([
1152
- "src/styles/main.module.css",
1153
- "src/styles/css-modules.d.ts"
1154
- ]);
1251
+ builder.addFiles(["src/styles/css-modules.d.ts", "src/styles/main.module.css", "src/styles/sample-css-module-command.ts"]);
1252
+ if (isFrameworkPreset(answers.preset)) {
1253
+ addToolkitStyles(builder, answers.bundler, "cssModules");
1254
+ return;
1255
+ }
1155
1256
  if (answers.bundler === "rollup") {
1156
1257
  builder.addPackage("rollup-plugin-postcss").addPartial("rollup-postcss");
1157
1258
  }
@@ -1167,7 +1268,12 @@ var Css = class extends FeatureOption {
1167
1268
  super({ promptHint: "Plain CSS styles", promptLabel: "CSS", settingValue: "css" });
1168
1269
  }
1169
1270
  configure(builder, answers) {
1170
- builder.addFiles(["src/styles/main.css", "src/styles/styles.d.ts"]);
1271
+ builder.addFiles(["src/styles/main.css"]);
1272
+ if (isFrameworkPreset(answers.preset)) {
1273
+ addToolkitStyles(builder, answers.bundler);
1274
+ return;
1275
+ }
1276
+ builder.addFiles(["src/styles/styles.d.ts"]);
1171
1277
  if (answers.bundler === "rollup") {
1172
1278
  builder.addPackage("rollup-plugin-postcss").addPartial("rollup-postcss");
1173
1279
  }
@@ -1193,9 +1299,13 @@ var PostCss = class extends FeatureOption {
1193
1299
  builder.addPackage("autoprefixer").addPackage("postcss").addFiles([
1194
1300
  "postcss.config.cjs",
1195
1301
  "scripts/postcss.config.ts",
1196
- "src/styles/main.css",
1197
- "src/styles/styles.d.ts"
1302
+ "src/styles/main.css"
1198
1303
  ]);
1304
+ if (isFrameworkPreset(answers.preset)) {
1305
+ addToolkitStyles(builder, answers.bundler, "postcss");
1306
+ return;
1307
+ }
1308
+ builder.addFiles(["src/styles/styles.d.ts"]);
1199
1309
  if (answers.bundler === "esbuild") {
1200
1310
  builder.addPackage("esbuild-postcss");
1201
1311
  }
@@ -1226,8 +1336,13 @@ var Scss = class extends FeatureOption {
1226
1336
  super({ promptHint: "Sass/SCSS preprocessor", promptLabel: "SCSS", settingValue: "scss" });
1227
1337
  }
1228
1338
  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];
1339
+ builder.addFiles(["src/styles/main.scss"]);
1340
+ if (isFrameworkPreset(answers.preset)) {
1341
+ builder.addPartial("toolkit-styles");
1342
+ } else {
1343
+ builder.addFiles(["src/styles/styles.d.ts"]);
1344
+ }
1345
+ const plugin = isFrameworkPreset(answers.preset) && answers.bundler === "esbuild" ? void 0 : SCSS_PLUGINS[answers.bundler];
1231
1346
  if (plugin) {
1232
1347
  builder.addPackage(plugin);
1233
1348
  const depcheckReason = SCSS_PLUGIN_DEPCHECK_REASONS[answers.bundler];
@@ -1239,7 +1354,10 @@ var Scss = class extends FeatureOption {
1239
1354
  builder.addPackage("sass-embedded").addDepcheckIgnore("sass-embedded", "the Sass compiler `esbuild-sass-plugin` peers on; nothing imports it directly.");
1240
1355
  }
1241
1356
  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");
1357
+ 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.");
1358
+ if (!isFrameworkPreset(answers.preset)) {
1359
+ builder.addPartial("webpack-css-extract");
1360
+ }
1243
1361
  }
1244
1362
  }
1245
1363
  };
@@ -1250,11 +1368,16 @@ var Tailwind = class extends FeatureOption {
1250
1368
  super({ promptHint: "Utility-first CSS framework", promptLabel: "Tailwind CSS", settingValue: "tailwind" });
1251
1369
  }
1252
1370
  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([
1371
+ builder.addPackage("tailwindcss").addDepcheckIgnore("tailwindcss", 'imported by `src/styles/main.css` (`@import "tailwindcss"`), which depcheck does not read.').addFiles(["src/styles/main.css"]);
1372
+ if (isFrameworkPreset(answers.preset)) {
1373
+ builder.addPackage("@tailwindcss/postcss").addDepcheckIgnore("@tailwindcss/postcss", "loaded by obsidian-dev-toolkit for its `styles.tailwind` build option.");
1374
+ addToolkitStyles(builder, answers.bundler, "tailwind");
1375
+ return;
1376
+ }
1377
+ builder.addPackage("@tailwindcss/cli").addDepcheckIgnore("@tailwindcss/cli", "run as a CLI by `scripts/build-styles.ts`.").addScript("build:styles").addFiles([
1254
1378
  "scripts/build-styles.ts",
1255
- "src/styles/main.css",
1256
1379
  "src/styles/styles.d.ts"
1257
- ]);
1380
+ ]).addPartial("tailwind-cli");
1258
1381
  if (answers.bundler === "rollup") {
1259
1382
  builder.addPackage("rollup-plugin-postcss").addPartial("rollup-postcss");
1260
1383
  }
@@ -1273,12 +1396,12 @@ async function promptStyling(savedValue) {
1273
1396
  // src/features/test-runner/sample-unit-tests.ts
1274
1397
  function addSampleUnitTests(builder, answers) {
1275
1398
  builder.addFiles(["src/main.test.ts"]);
1276
- if (!isDevUtilsPreset(answers.preset)) {
1399
+ if (!isFrameworkPreset(answers.preset)) {
1277
1400
  return;
1278
1401
  }
1279
- builder.addFiles(["src/plugin-settings-component.test.ts"]);
1402
+ builder.addFiles(["src/plugin-settings-component.test.ts"]).addPackage("@mnaoumov/typescript-lib");
1280
1403
  if (answers.preset === "demo") {
1281
- builder.addFiles(["src/plugin-settings.test.ts"]);
1404
+ builder.addFiles(["src/plugin-settings.test.ts"]).addPackage("@mnaoumov/typescript-test-toolkit");
1282
1405
  }
1283
1406
  }
1284
1407
 
@@ -1288,7 +1411,9 @@ var Jest = class extends FeatureOption {
1288
1411
  super({ promptHint: "Feature-rich, widely adopted", promptLabel: "Jest", settingValue: "jest" });
1289
1412
  }
1290
1413
  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([
1414
+ const isFramework = isFrameworkPreset(answers.preset);
1415
+ const configNames = isFramework ? "`defineObsidianPluginJestConfig` from @mnaoumov/obsidian-dev-toolkit" : "`jest.config.ts`";
1416
+ 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
1417
  "jest.config.ts",
1293
1418
  "scripts/framework-component-stub.ts",
1294
1419
  "scripts/stylesheet-stub.ts",
@@ -1297,6 +1422,9 @@ var Jest = class extends FeatureOption {
1297
1422
  "scripts/test.ts",
1298
1423
  "scripts/test-watch.ts"
1299
1424
  ]);
1425
+ if (isFramework) {
1426
+ 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"]);
1427
+ }
1300
1428
  addSampleUnitTests(builder, answers);
1301
1429
  }
1302
1430
  };
@@ -1316,23 +1444,23 @@ var Vitest = class extends FeatureOption {
1316
1444
  configure(builder, answers) {
1317
1445
  builder.addPackage("jsdom").addPackage("obsidian-test-mocks").addDepcheckIgnore(
1318
1446
  "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`."
1447
+ 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
1448
  ).addPackage("vitest").addScript("test").addScript("test:watch").addFiles([
1321
1449
  "vitest.config.ts",
1322
1450
  "src/plugin.test.ts",
1323
1451
  "scripts/test.ts",
1324
1452
  "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.
1453
+ // Both presets, not just the framework ones: the emitted `src/plugin.ts` reaches `src/wasm/answer.ts`
1454
+ // On every preset when the `wasm` answer is chosen, and registers the answered view, which may be a
1455
+ // Single-file component. So every vitest config aliases `.wasm` and `.svelte` / `.vue` to these stubs.
1329
1456
  "scripts/wasm-module-stub.ts",
1457
+ "scripts/framework-component-stub.ts",
1330
1458
  // `src/main.test.ts` imports `src/main.ts`, which imports the stylesheet -- and on `tailwind` that
1331
1459
  // File does not exist until the first build. See the stub's own comment.
1332
1460
  "scripts/stylesheet-stub.ts"
1333
1461
  ]);
1334
1462
  addSampleUnitTests(builder, answers);
1335
- if (!isDevUtilsPreset(answers.preset)) {
1463
+ if (!isFrameworkPreset(answers.preset)) {
1336
1464
  return;
1337
1465
  }
1338
1466
  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 +1468,6 @@ var Vitest = class extends FeatureOption {
1340
1468
  "scripts/test-integration-desktop.ts",
1341
1469
  "scripts/test-integration-desktop-performance.ts",
1342
1470
  "scripts/demo-vault-global-setup.ts",
1343
- "scripts/framework-component-stub.ts",
1344
1471
  "scripts/test-coverage.ts",
1345
1472
  "scripts/test-integration.ts",
1346
1473
  "scripts/test-integration-demo-vault.ts",
@@ -1392,6 +1519,10 @@ var Preact = class extends FeatureOption {
1392
1519
  "src/preact-components/sample-preact-component.tsx",
1393
1520
  "src/views/sample-preact-view.tsx"
1394
1521
  ]);
1522
+ if (isFrameworkPreset(answers.preset)) {
1523
+ builder.addBuildFramework("preact").addTsconfigExtends("@mnaoumov/obsidian-dev-toolkit/tsconfig/preact.json");
1524
+ return;
1525
+ }
1395
1526
  const plugin = BUILD_PLUGINS[answers.bundler];
1396
1527
  if (plugin) {
1397
1528
  builder.addPackage(plugin);
@@ -1419,6 +1550,10 @@ var React = class extends FeatureOption {
1419
1550
  "src/react-components/sample-react-component.tsx",
1420
1551
  "src/views/sample-react-view.tsx"
1421
1552
  ]);
1553
+ if (isFrameworkPreset(answers.preset)) {
1554
+ builder.addBuildFramework("react").addTsconfigExtends("@mnaoumov/obsidian-dev-toolkit/tsconfig/react.json");
1555
+ return;
1556
+ }
1422
1557
  const plugin = BUILD_PLUGINS2[answers.bundler];
1423
1558
  if (plugin) {
1424
1559
  builder.addPackage(plugin);
@@ -1446,6 +1581,10 @@ var Solid = class extends FeatureOption {
1446
1581
  "src/solid-components/sample-solid-component.tsx",
1447
1582
  "src/views/sample-solid-view.tsx"
1448
1583
  ]);
1584
+ if (isFrameworkPreset(answers.preset)) {
1585
+ 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.");
1586
+ return;
1587
+ }
1449
1588
  const plugin = BUILD_PLUGINS3[answers.bundler];
1450
1589
  if (plugin) {
1451
1590
  builder.addPackage(plugin);
@@ -1487,16 +1626,17 @@ var Svelte = class extends FeatureOption {
1487
1626
  "src/svelte-components/sample-svelte-component.svelte",
1488
1627
  "src/views/sample-svelte-view.ts"
1489
1628
  ]);
1490
- const isDevUtilsEsbuild = isDevUtilsPreset(answers.preset) && answers.bundler === "esbuild";
1629
+ builder.addPackage("svelte-check");
1630
+ if (isFrameworkPreset(answers.preset)) {
1631
+ 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.");
1632
+ return;
1633
+ }
1491
1634
  const plugin = getBuildPlugin(answers.bundler);
1492
- if (plugin !== null && !isDevUtilsEsbuild) {
1635
+ if (plugin !== null) {
1493
1636
  builder.addPackage(plugin);
1494
1637
  }
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)) {
1638
+ builder.addDepcheckIgnore("svelte-check", "run as a CLI by `scripts/build.ts`.");
1639
+ if (SVELTE_PREPROCESS_BUNDLERS.has(answers.bundler)) {
1500
1640
  builder.addPackage("svelte-preprocess");
1501
1641
  }
1502
1642
  if (answers.bundler === "webpack") {
@@ -1527,11 +1667,19 @@ var Vue = class extends FeatureOption {
1527
1667
  super({ promptHint: "Progressive framework with SFC", promptLabel: "Vue", settingValue: "vue" });
1528
1668
  }
1529
1669
  configure(builder, answers) {
1530
- builder.addPackage("vue").addPackage(getBuildPlugin2(answers.bundler)).addPartial("ui-view").addSentenceCaseBrand("Vue").addFiles([
1670
+ builder.addPackage("vue").addPartial("ui-view").addSentenceCaseBrand("Vue").addFiles([
1531
1671
  "src/vue-components/sample-vue-component.d.ts",
1532
1672
  "src/vue-components/sample-vue-component.vue",
1533
1673
  "src/views/sample-vue-view.ts"
1534
1674
  ]);
1675
+ if (isFrameworkPreset(answers.preset)) {
1676
+ builder.addBuildFramework("vue").addPackage("unplugin-vue").addDepcheckIgnore("unplugin-vue", "loaded by obsidian-dev-toolkit to compile `.vue` components.");
1677
+ if (answers.bundler === "parcel") {
1678
+ builder.addPackage("@parcel/transformer-vue").addDepcheckIgnore("@parcel/transformer-vue", "resolved by name by `@parcel/config-default` for `.vue`; nothing imports it.");
1679
+ }
1680
+ return;
1681
+ }
1682
+ builder.addPackage(getBuildPlugin2(answers.bundler));
1535
1683
  if (answers.bundler === "rollup") {
1536
1684
  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
1685
  }
@@ -1574,24 +1722,29 @@ var Wasm = class extends FeatureOption {
1574
1722
  super({ promptHint: "Import and use .wasm modules", promptLabel: "WASM", settingValue: "wasm" });
1575
1723
  }
1576
1724
  configure(builder, answers) {
1577
- const plugin = getWasmPlugin(answers.bundler);
1578
- if (plugin !== null) {
1579
- builder.addPackage(plugin);
1725
+ const isFramework = isFrameworkPreset(answers.preset);
1726
+ if (isFramework) {
1727
+ builder.addBuildOption("wasm", "true").addPartial("wasm-adapter");
1728
+ } else {
1729
+ const plugin = getWasmPlugin(answers.bundler);
1730
+ if (plugin !== null) {
1731
+ builder.addPackage(plugin);
1732
+ }
1733
+ builder.addFiles(["src/wasm.d.ts"]).addPartial(`wasm-${answers.bundler}`);
1580
1734
  }
1581
1735
  builder.addSentenceCaseBrand("WASM");
1582
1736
  builder.addFiles([
1583
1737
  // 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.
1738
+ // Export, `answer()`, returning 42 -- the sample module from `CodeScript Toolkit`'s demo vault.
1585
1739
  "src/wasm/module.wasm",
1586
1740
  // Its source in WebAssembly text format. Documentation only: nothing in the build reads it, and it
1587
1741
  // Is here so the binary beside it is not opaque.
1588
1742
  "src/wasm/module.wat",
1589
- "src/wasm.d.ts",
1590
1743
  "src/wasm/answer.ts",
1591
1744
  "src/wasm/sample-command.ts",
1592
1745
  "src/wasm/README.md"
1593
1746
  ]);
1594
- if (isDevUtilsPreset(answers.preset)) {
1747
+ if (isFramework) {
1595
1748
  builder.addFiles(["demo-vault/03 WebAssembly.md"]);
1596
1749
  }
1597
1750
  }
@@ -1656,6 +1809,22 @@ function getPluginShortName(pluginId) {
1656
1809
  return pluginId.split("-").map((word) => (word[0] ?? "").toUpperCase() + word.slice(1)).join("");
1657
1810
  }
1658
1811
 
1812
+ // src/deprecated-answers.ts
1813
+ import { log } from "@clack/prompts";
1814
+ var DEPRECATED_ANSWER_VALUES = {
1815
+ preset: {
1816
+ enhanced: "all-in-one"
1817
+ }
1818
+ };
1819
+ function resolveDeprecatedAnswer(key, value, source) {
1820
+ const replacement = DEPRECATED_ANSWER_VALUES[key]?.[value];
1821
+ if (replacement === void 0) {
1822
+ return value;
1823
+ }
1824
+ log.warn(`${key} "${value}" in ${source} is deprecated and was read as "${replacement}". Use "${replacement}" instead.`);
1825
+ return replacement;
1826
+ }
1827
+
1659
1828
  // src/directory-constraints.ts
1660
1829
  var CORE_FEATURE_NAMES = [
1661
1830
  "Audio recorder",
@@ -1795,7 +1964,7 @@ function findCoreFeatureName(name) {
1795
1964
  // src/prompts.ts
1796
1965
  import {
1797
1966
  cancel as cancel2,
1798
- log
1967
+ log as log2
1799
1968
  } from "@clack/prompts";
1800
1969
  import { styleText as styleText3 } from "node:util";
1801
1970
 
@@ -1891,6 +2060,30 @@ ${barEnd}
1891
2060
  }
1892
2061
 
1893
2062
  // src/prompts.ts
2063
+ var MAX_HINTED_CHANGES = 3;
2064
+ var TOOLING_QUESTIONS = {
2065
+ bundler: { message: "Bundler", options: BUNDLER_OPTIONS },
2066
+ uiFramework: { message: "UI framework", options: UI_FRAMEWORK_OPTIONS },
2067
+ linter: { message: "Linter", options: LINTER_OPTIONS },
2068
+ formatter: { message: "Formatter", options: FORMATTER_OPTIONS },
2069
+ spellChecker: { message: "Spell checker", options: SPELL_CHECKER_OPTIONS },
2070
+ markdownLinter: { message: "Markdown linter", options: MARKDOWN_LINTER_OPTIONS },
2071
+ testRunner: { message: "Unit testing", options: TEST_RUNNER_OPTIONS },
2072
+ e2eTestRunner: { message: "E2E testing", options: E2E_TEST_RUNNER_OPTIONS },
2073
+ editorExtensions: { message: "Editor extensions", options: EDITOR_EXTENSIONS_OPTIONS },
2074
+ styling: { message: "Styling", options: STYLING_OPTIONS },
2075
+ wasmSupport: { message: "WebAssembly support", options: WASM_SUPPORT_OPTIONS },
2076
+ commitLinting: { message: "Commit linting", options: COMMIT_LINTING_OPTIONS },
2077
+ hotReload: { message: "Hot reload", options: HOT_RELOAD_OPTIONS },
2078
+ internationalization: { message: "Internationalization", options: INTERNATIONALIZATION_OPTIONS },
2079
+ gitHubActions: { message: "GitHub Actions", options: GITHUB_ACTIONS_OPTIONS },
2080
+ gitHubIssueTemplates: { message: "GitHub issue templates", options: GITHUB_ISSUE_TEMPLATES_OPTIONS },
2081
+ coverageBadge: { message: "Coverage badge", options: COVERAGE_BADGE_OPTIONS },
2082
+ apiSubset: { message: "Obsidian API subset", options: API_SUBSET_OPTIONS },
2083
+ packageManager: { message: "Package manager", options: PACKAGE_MANAGER_OPTIONS },
2084
+ platformSupport: { message: "Platform support", options: PLATFORM_SUPPORT_OPTIONS }
2085
+ };
2086
+ var API_SUBSET_PRESETS = ["all-in-one", "docs-showcase"];
1894
2087
  var DEFAULT_PLUGIN_ID = "my-awesome-helper";
1895
2088
  function getDefaultAnswers(defaults) {
1896
2089
  const pluginId = defaults?.pluginId ?? DEFAULT_PLUGIN_ID;
@@ -1909,10 +2102,10 @@ function getDefaultAnswers(defaults) {
1909
2102
  function makePluginName(pluginId) {
1910
2103
  return extractWords(pluginId).join(" ");
1911
2104
  }
1912
- async function promptAnswers(defaults) {
2105
+ async function promptAnswers(defaults, supplied = defaults ?? {}) {
1913
2106
  showHotkeyHints();
1914
2107
  const defaultTooling = getDefaultTooling();
1915
- const steps = skipSuppliedAnswers(buildPromptSteps(defaults ?? {}, defaultTooling), defaults ?? {});
2108
+ const steps = skipSuppliedAnswers(buildPromptSteps(defaults ?? {}, supplied, defaultTooling), supplied);
1916
2109
  const answers = await runPromptSteps(steps);
1917
2110
  return buildAnswers(answers, defaultTooling);
1918
2111
  }
@@ -1922,6 +2115,9 @@ function validateNotEmpty(value) {
1922
2115
  }
1923
2116
  return void 0;
1924
2117
  }
2118
+ function asksApiSubset(preset) {
2119
+ return API_SUBSET_PRESETS.includes(preset ?? "");
2120
+ }
1925
2121
  function buildAnswers(answers, defaultTooling) {
1926
2122
  function get(key, fallback) {
1927
2123
  return answers.get(key) ?? fallback;
@@ -1931,7 +2127,7 @@ function buildAnswers(answers, defaultTooling) {
1931
2127
  apiSubset: get("apiSubset", defaultTooling.apiSubset),
1932
2128
  authorGitHubName: get("authorGitHubName", "johndoe"),
1933
2129
  authorName: get("authorName", "John Doe"),
1934
- bundler: get("bundler", "esbuild"),
2130
+ bundler: get("bundler", defaultTooling.bundler),
1935
2131
  commitLinting: get("commitLinting", defaultTooling.commitLinting),
1936
2132
  coverageBadge: get("coverageBadge", defaultTooling.coverageBadge),
1937
2133
  currentYear: (/* @__PURE__ */ new Date()).getFullYear(),
@@ -1949,154 +2145,165 @@ function buildAnswers(answers, defaultTooling) {
1949
2145
  linter: get("linter", defaultTooling.linter),
1950
2146
  markdownLinter: get("markdownLinter", defaultTooling.markdownLinter),
1951
2147
  obsidianConfigFolder: get("obsidianConfigFolder", ""),
1952
- packageManager: get("packageManager", "npm"),
1953
- platformSupport: get("platformSupport", "desktop-only"),
2148
+ packageManager: get("packageManager", defaultTooling.packageManager),
2149
+ platformSupport: get("platformSupport", defaultTooling.platformSupport),
1954
2150
  pluginDescription: get("pluginDescription", "Does something awesome."),
1955
2151
  pluginId,
1956
2152
  pluginName: get("pluginName", makePluginName(pluginId)),
1957
- preset: get("preset", "enhanced"),
2153
+ preset: get("preset", "all-in-one"),
1958
2154
  spellChecker: get("spellChecker", defaultTooling.spellChecker),
1959
2155
  styling: get("styling", defaultTooling.styling),
1960
2156
  testRunner: get("testRunner", defaultTooling.testRunner),
1961
- uiFramework: get("uiFramework", "none"),
2157
+ uiFramework: get("uiFramework", defaultTooling.uiFramework),
1962
2158
  wasmSupport: get("wasmSupport", defaultTooling.wasmSupport)
1963
2159
  };
1964
2160
  }
1965
- function buildPromptSteps(d, defaultTooling) {
2161
+ function buildPromptSteps(d, supplied, defaultTooling) {
1966
2162
  function isCustomize(answers) {
1967
2163
  return answers.get("toolingMode") === "customize";
1968
2164
  }
1969
2165
  function skipUnlessCustomize(answers) {
1970
2166
  return !isCustomize(answers);
1971
2167
  }
2168
+ function tooling(key, answers) {
2169
+ if (answers.get("toolingMode") === "defaults" && supplied[key] === void 0) {
2170
+ return defaultTooling[key];
2171
+ }
2172
+ return d[key] ?? defaultTooling[key];
2173
+ }
2174
+ function changes(answers) {
2175
+ return findToolingChanges(d, supplied, defaultTooling, answers.get("preset"));
2176
+ }
1972
2177
  return [
1973
2178
  {
1974
- defaultValue: () => d.preset ?? "enhanced",
2179
+ defaultValue: () => d.preset ?? "all-in-one",
1975
2180
  key: "preset",
1976
2181
  prompt: (saved) => promptPreset(saved)
1977
2182
  },
1978
2183
  {
1979
- defaultValue: () => "defaults",
2184
+ // A skipped `Tooling` keeps what was saved, which is what the question offers first when there is any.
2185
+ defaultValue: (answers) => changes(answers).length > 0 ? "keep" : "defaults",
1980
2186
  key: "toolingMode",
1981
- prompt: () => promptToolingMode(),
1982
- skip: (answers) => answers.get("preset") === "demo"
2187
+ prompt: (saved, answers) => promptToolingMode(saved, changes(answers)),
2188
+ // The official sample is upstream's tooling as it is, so there is nothing to customize.
2189
+ skip: (answers) => answers.get("preset") === "demo" || isOfficialSamplePreset(answers.get("preset"))
1983
2190
  },
1984
2191
  {
1985
- defaultValue: (answers) => answers.get("preset") === "demo" ? "esbuild" : d.bundler ?? "esbuild",
2192
+ defaultValue: (answers) => answers.get("preset") === "demo" ? "esbuild" : tooling("bundler", answers),
1986
2193
  key: "bundler",
1987
2194
  prompt: (saved) => promptBundler(saved),
1988
2195
  skip: skipUnlessCustomize
1989
2196
  },
1990
2197
  {
1991
- defaultValue: (answers) => answers.get("preset") === "demo" ? "none" : d.uiFramework ?? "none",
2198
+ defaultValue: (answers) => answers.get("preset") === "demo" ? "none" : tooling("uiFramework", answers),
1992
2199
  key: "uiFramework",
1993
2200
  prompt: (saved) => promptUiFramework(saved),
1994
2201
  skip: skipUnlessCustomize
1995
2202
  },
1996
2203
  {
1997
- defaultValue: () => d.linter ?? defaultTooling.linter,
2204
+ defaultValue: (answers) => tooling("linter", answers),
1998
2205
  key: "linter",
1999
2206
  prompt: (saved) => promptLinter(saved),
2000
2207
  skip: skipUnlessCustomize
2001
2208
  },
2002
2209
  {
2003
- defaultValue: () => d.formatter ?? defaultTooling.formatter,
2210
+ defaultValue: (answers) => tooling("formatter", answers),
2004
2211
  key: "formatter",
2005
2212
  prompt: (saved) => promptFormatter(saved),
2006
2213
  skip: skipUnlessCustomize
2007
2214
  },
2008
2215
  {
2009
- defaultValue: () => d.spellChecker ?? defaultTooling.spellChecker,
2216
+ defaultValue: (answers) => tooling("spellChecker", answers),
2010
2217
  key: "spellChecker",
2011
2218
  prompt: (saved) => promptSpellChecker(saved),
2012
2219
  skip: skipUnlessCustomize
2013
2220
  },
2014
2221
  {
2015
- defaultValue: () => d.markdownLinter ?? defaultTooling.markdownLinter,
2222
+ defaultValue: (answers) => tooling("markdownLinter", answers),
2016
2223
  key: "markdownLinter",
2017
2224
  prompt: (saved) => promptMarkdownLinter(saved),
2018
2225
  skip: skipUnlessCustomize
2019
2226
  },
2020
2227
  {
2021
- defaultValue: () => d.testRunner ?? defaultTooling.testRunner,
2228
+ defaultValue: (answers) => tooling("testRunner", answers),
2022
2229
  key: "testRunner",
2023
2230
  prompt: (saved) => promptTestRunner(saved),
2024
2231
  skip: skipUnlessCustomize
2025
2232
  },
2026
2233
  {
2027
- defaultValue: () => d.e2eTestRunner ?? defaultTooling.e2eTestRunner,
2234
+ defaultValue: (answers) => tooling("e2eTestRunner", answers),
2028
2235
  key: "e2eTestRunner",
2029
2236
  prompt: (saved) => promptE2eTestRunner(saved),
2030
2237
  skip: skipUnlessCustomize
2031
2238
  },
2032
2239
  {
2033
- defaultValue: () => d.editorExtensions ?? defaultTooling.editorExtensions,
2240
+ defaultValue: (answers) => tooling("editorExtensions", answers),
2034
2241
  key: "editorExtensions",
2035
2242
  prompt: (saved) => promptEditorExtensions(saved),
2036
2243
  skip: skipUnlessCustomize
2037
2244
  },
2038
2245
  {
2039
- defaultValue: () => d.styling ?? defaultTooling.styling,
2246
+ defaultValue: (answers) => tooling("styling", answers),
2040
2247
  key: "styling",
2041
2248
  prompt: (saved) => promptStyling(saved),
2042
2249
  skip: skipUnlessCustomize
2043
2250
  },
2044
2251
  {
2045
- defaultValue: () => d.wasmSupport ?? defaultTooling.wasmSupport,
2252
+ defaultValue: (answers) => tooling("wasmSupport", answers),
2046
2253
  key: "wasmSupport",
2047
2254
  prompt: (saved) => promptWasmSupport(saved),
2048
2255
  skip: skipUnlessCustomize
2049
2256
  },
2050
2257
  {
2051
- defaultValue: () => d.commitLinting ?? defaultTooling.commitLinting,
2258
+ defaultValue: (answers) => tooling("commitLinting", answers),
2052
2259
  key: "commitLinting",
2053
2260
  prompt: (saved) => promptCommitLinting(saved),
2054
2261
  skip: skipUnlessCustomize
2055
2262
  },
2056
2263
  {
2057
- defaultValue: () => d.hotReload ?? defaultTooling.hotReload,
2264
+ defaultValue: (answers) => tooling("hotReload", answers),
2058
2265
  key: "hotReload",
2059
2266
  prompt: (saved) => promptHotReload(saved),
2060
2267
  skip: skipUnlessCustomize
2061
2268
  },
2062
2269
  {
2063
- defaultValue: () => d.internationalization ?? defaultTooling.internationalization,
2270
+ defaultValue: (answers) => tooling("internationalization", answers),
2064
2271
  key: "internationalization",
2065
2272
  prompt: (saved) => promptInternationalization(saved),
2066
2273
  skip: skipUnlessCustomize
2067
2274
  },
2068
2275
  {
2069
- defaultValue: () => d.gitHubActions ?? defaultTooling.gitHubActions,
2276
+ defaultValue: (answers) => tooling("gitHubActions", answers),
2070
2277
  key: "gitHubActions",
2071
2278
  prompt: (saved) => promptGitHubActions(saved),
2072
2279
  skip: skipUnlessCustomize
2073
2280
  },
2074
2281
  {
2075
- defaultValue: () => d.gitHubIssueTemplates ?? defaultTooling.gitHubIssueTemplates,
2282
+ defaultValue: (answers) => tooling("gitHubIssueTemplates", answers),
2076
2283
  key: "gitHubIssueTemplates",
2077
2284
  prompt: (saved) => promptGitHubIssueTemplates(saved),
2078
2285
  skip: skipUnlessCustomize
2079
2286
  },
2080
2287
  {
2081
- defaultValue: () => d.coverageBadge ?? defaultTooling.coverageBadge,
2288
+ defaultValue: (answers) => tooling("coverageBadge", answers),
2082
2289
  key: "coverageBadge",
2083
2290
  prompt: (saved) => promptCoverageBadge(saved),
2084
2291
  skip: skipUnlessCustomize
2085
2292
  },
2086
2293
  {
2087
- defaultValue: () => d.apiSubset ?? defaultTooling.apiSubset,
2294
+ defaultValue: (answers) => tooling("apiSubset", answers),
2088
2295
  key: "apiSubset",
2089
2296
  prompt: (saved) => promptApiSubset(saved),
2090
- skip: (answers) => !(isCustomize(answers) && answers.get("preset") === "enhanced")
2297
+ skip: (answers) => !(isCustomize(answers) && asksApiSubset(answers.get("preset")))
2091
2298
  },
2092
2299
  {
2093
- defaultValue: () => d.packageManager ?? "npm",
2300
+ defaultValue: (answers) => tooling("packageManager", answers),
2094
2301
  key: "packageManager",
2095
2302
  prompt: (saved) => promptPackageManager(saved),
2096
2303
  skip: skipUnlessCustomize
2097
2304
  },
2098
2305
  {
2099
- defaultValue: () => d.platformSupport ?? "desktop-only",
2306
+ defaultValue: (answers) => tooling("platformSupport", answers),
2100
2307
  key: "platformSupport",
2101
2308
  prompt: (saved) => promptPlatformSupport(saved),
2102
2309
  skip: skipUnlessCustomize
@@ -2187,37 +2394,59 @@ function buildPromptSteps(d, defaultTooling) {
2187
2394
  defaultValue: saved || void 0,
2188
2395
  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
2396
  placeholder: saved || "path/to/test-vault/.obsidian"
2190
- })
2397
+ }),
2398
+ // Upstream builds into the project folder and copies nothing into a vault.
2399
+ skip: (answers) => isOfficialSamplePreset(answers.get("preset"))
2191
2400
  }
2192
2401
  ];
2193
2402
  }
2403
+ function describeChanges(changes, describe) {
2404
+ const named = changes.slice(0, MAX_HINTED_CHANGES).map(describe).join(", ");
2405
+ const rest = changes.length - MAX_HINTED_CHANGES;
2406
+ return rest > 0 ? `${named}, and ${String(rest)} more` : named;
2407
+ }
2194
2408
  function extractWords(pluginId) {
2195
2409
  return pluginId.split("-").map((w) => (w[0] ?? "").toUpperCase() + w.slice(1));
2196
2410
  }
2411
+ function findToolingChanges(d, supplied, defaultTooling, preset) {
2412
+ const changes = [];
2413
+ for (const [key, question] of Object.entries(TOOLING_QUESTIONS)) {
2414
+ const saved = d[key];
2415
+ if (saved === void 0 || supplied[key] !== void 0 || saved === defaultTooling[key]) {
2416
+ continue;
2417
+ }
2418
+ if (key === "apiSubset" && !asksApiSubset(preset)) {
2419
+ continue;
2420
+ }
2421
+ changes.push({
2422
+ question: question.message,
2423
+ recommended: getOptionLabel(question, defaultTooling[key]),
2424
+ saved: getOptionLabel(question, saved)
2425
+ });
2426
+ }
2427
+ return changes;
2428
+ }
2197
2429
  function getDefaultAnswersBase(pluginId) {
2198
2430
  return {
2199
2431
  ...getDefaultTooling(),
2200
2432
  authorGitHubName: "johndoe",
2201
2433
  authorName: "John Doe",
2202
- bundler: "esbuild",
2203
2434
  currentYear: (/* @__PURE__ */ new Date()).getFullYear(),
2204
2435
  defaultBranch: "main",
2205
2436
  fundingPlatform: "buy-me-a-coffee",
2206
2437
  fundingUrl: "",
2207
2438
  fundingUsername: "johndoe",
2208
2439
  obsidianConfigFolder: "",
2209
- packageManager: "npm",
2210
- platformSupport: "desktop-only",
2211
2440
  pluginDescription: "Does something awesome.",
2212
2441
  pluginId,
2213
2442
  pluginName: makePluginName(pluginId),
2214
- preset: "enhanced",
2215
- uiFramework: "none"
2443
+ preset: "all-in-one"
2216
2444
  };
2217
2445
  }
2218
2446
  function getDefaultTooling() {
2219
2447
  return {
2220
2448
  apiSubset: "official",
2449
+ bundler: "esbuild",
2221
2450
  commitLinting: "conventional-commits",
2222
2451
  coverageBadge: "none",
2223
2452
  e2eTestRunner: "none",
@@ -2229,12 +2458,18 @@ function getDefaultTooling() {
2229
2458
  internationalization: "none",
2230
2459
  linter: "eslint",
2231
2460
  markdownLinter: "markdownlint",
2461
+ packageManager: "npm",
2462
+ platformSupport: "desktop-only",
2232
2463
  spellChecker: "cspell",
2233
2464
  styling: "scss",
2234
2465
  testRunner: "vitest",
2466
+ uiFramework: "none",
2235
2467
  wasmSupport: "none"
2236
2468
  };
2237
2469
  }
2470
+ function getOptionLabel(question, value) {
2471
+ return question.options.find((option) => option.settingValue === value)?.promptLabel ?? value;
2472
+ }
2238
2473
  function promptPluginDescription(saved) {
2239
2474
  const value = saved || void 0;
2240
2475
  return text({
@@ -2253,13 +2488,29 @@ function promptPluginName(saved) {
2253
2488
  validate: validatePluginName
2254
2489
  });
2255
2490
  }
2256
- async function promptToolingMode() {
2491
+ async function promptToolingMode(savedValue, changes) {
2492
+ const customize = { hint: "Choose each tool individually", label: "Customize", value: "customize" };
2493
+ if (changes.length === 0) {
2494
+ return select({
2495
+ initialValue: savedValue,
2496
+ message: "Tooling",
2497
+ options: [
2498
+ customize,
2499
+ { hint: "ESLint, dprint, SCSS, Vitest, and more", label: "Use recommended defaults", value: "defaults" }
2500
+ ]
2501
+ });
2502
+ }
2257
2503
  return select({
2258
- initialValue: "defaults",
2504
+ initialValue: savedValue,
2259
2505
  message: "Tooling",
2260
2506
  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" }
2507
+ { hint: describeChanges(changes, (change) => `${change.question}: ${change.saved}`), label: "Keep current tooling", value: "keep" },
2508
+ customize,
2509
+ {
2510
+ hint: describeChanges(changes, (change) => `${change.question}: ${change.saved} -> ${change.recommended}`),
2511
+ label: "Use recommended defaults",
2512
+ value: "defaults"
2513
+ }
2263
2514
  ]
2264
2515
  });
2265
2516
  }
@@ -2275,7 +2526,7 @@ async function runPromptSteps(steps) {
2275
2526
  }
2276
2527
  try {
2277
2528
  const savedValue = answers.get(step.key) ?? step.defaultValue(answers);
2278
- answers.set(step.key, await step.prompt(savedValue));
2529
+ answers.set(step.key, await step.prompt(savedValue, answers));
2279
2530
  i++;
2280
2531
  } catch (error) {
2281
2532
  if (!(error instanceof GoBackError)) {
@@ -2303,7 +2554,7 @@ function showHotkeyHints() {
2303
2554
  function key(s) {
2304
2555
  return styleText3("cyan", s);
2305
2556
  }
2306
- log.info([
2557
+ log2.info([
2307
2558
  `${key("\u2191\u2193")} Navigate ${key("Enter")} Confirm ${key("Esc")} Go back`,
2308
2559
  `${dim("Text inputs:")} ${key("Tab")}/${key("\u2192")}/${key("End")} Accept suggestion`
2309
2560
  ].join("\n"));
@@ -2323,6 +2574,7 @@ var ANSWERS_FILE_PREFIX = "--answersFile=";
2323
2574
  var CUSTOM_TEMPLATE_PREFIX = "--customTemplate=";
2324
2575
  var MODE_PREFIX = "--mode=";
2325
2576
  var MODES = ["create" /* Create */, "update" /* Update */];
2577
+ var MODE_BY_VALUE = new Map(MODES.map((mode) => [mode, mode]));
2326
2578
  var FLAG_PREFIX_LENGTH = 2;
2327
2579
  var FREE_TEXT_VALIDATORS = {
2328
2580
  authorGitHubName: validateNotEmpty,
@@ -2334,6 +2586,9 @@ var FREE_TEXT_VALIDATORS = {
2334
2586
  pluginName: validatePluginName
2335
2587
  };
2336
2588
  var DEMO_PINNED_ANSWER_KEYS = ["bundler", "uiFramework"];
2589
+ var VALUES_OUTSIDE_ANSWER_SPACE = {
2590
+ preset: [OFFICIAL_SAMPLE_PRESET]
2591
+ };
2337
2592
  function assertValidAnswer(key, value) {
2338
2593
  const dimension = findChoiceDimension(key);
2339
2594
  if (dimension) {
@@ -2366,6 +2621,8 @@ function getHelpText() {
2366
2621
  " --customTemplate=<dir> Layer your own templates over the built-in ones: a directory",
2367
2622
  " mirroring templates/default, plus an overlay.json. Recorded in the",
2368
2623
  " project and re-applied on update; pass it empty to drop it.",
2624
+ " --latest With --preset=official-sample: copy obsidianmd/obsidian-sample-plugin",
2625
+ " as it is upstream today, not the snapshot this release vendored.",
2369
2626
  "",
2370
2627
  "Answers (any of these may be given as --<key>=<value>):"
2371
2628
  ];
@@ -2380,6 +2637,7 @@ function parseCliArgs(argv) {
2380
2637
  let answersFilePath = null;
2381
2638
  let customTemplate;
2382
2639
  let force = false;
2640
+ let latest = false;
2383
2641
  let mode;
2384
2642
  let showHelp = false;
2385
2643
  let useDefaults = false;
@@ -2404,27 +2662,40 @@ function parseCliArgs(argv) {
2404
2662
  force = true;
2405
2663
  continue;
2406
2664
  }
2665
+ if (argument === "--latest") {
2666
+ latest = true;
2667
+ continue;
2668
+ }
2407
2669
  if (argument.startsWith(MODE_PREFIX)) {
2408
2670
  mode = toMode(argument.slice(MODE_PREFIX.length));
2409
2671
  continue;
2410
2672
  }
2411
- const [rawKey, value] = splitFlag(argument);
2673
+ const [rawKey, rawValue] = splitFlag(argument);
2412
2674
  const key = toAnswerKey(rawKey);
2413
- assertValidAnswer(key, value);
2414
- flagAnswers[key] = value;
2675
+ flagAnswers[key] = resolveAnswer(key, rawValue, `--${key}`);
2415
2676
  }
2416
2677
  const fileAnswers = answersFilePath === null ? {} : readAnswersFile(answersFilePath);
2417
- const answers = { ...fileAnswers, ...flagAnswers };
2678
+ const isOfficialSample = isOfficialSamplePreset(flagAnswers.preset ?? fileAnswers.preset);
2679
+ if (isOfficialSample) {
2680
+ assertNoOfficialSampleConflict(flagAnswers);
2681
+ }
2682
+ const answers = { ...isOfficialSample ? pickOfficialSampleAnswers(fileAnswers) : fileAnswers, ...flagAnswers };
2418
2683
  assertNoDemoConflict(answers);
2419
2684
  return {
2420
2685
  answers,
2421
2686
  customTemplate,
2422
2687
  force,
2688
+ latest,
2423
2689
  mode,
2424
2690
  showHelp,
2425
2691
  useDefaults
2426
2692
  };
2427
2693
  }
2694
+ function resolveAnswer(key, value, source) {
2695
+ const resolved = resolveDeprecatedAnswer(key, value, source);
2696
+ assertValidAnswer(key, resolved);
2697
+ return resolved;
2698
+ }
2428
2699
  function toAnswerKey(key) {
2429
2700
  if (REFUSED_KEYS.includes(key)) {
2430
2701
  throw new Error(`${key} is computed by the generator, not answered, so it cannot be set.`);
@@ -2445,12 +2716,23 @@ function assertNoDemoConflict(answers) {
2445
2716
  }
2446
2717
  }
2447
2718
  }
2719
+ function assertNoOfficialSampleConflict(answers) {
2720
+ const conflicting = Object.keys(answers).filter((key) => answers[key] !== void 0 && !OFFICIAL_SAMPLE_ANSWER_KEYS.includes(key));
2721
+ if (conflicting.length > 0) {
2722
+ const flags = conflicting.map((key) => `--${key}`).join(", ");
2723
+ 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.`);
2724
+ }
2725
+ }
2448
2726
  function findChoiceDimension(key) {
2449
2727
  const dimension = ANSWER_SPACE.find((candidate) => candidate.answerKey === key);
2450
2728
  if (!dimension || dimension.values.includes("")) {
2451
2729
  return null;
2452
2730
  }
2453
- return dimension;
2731
+ const extraValues = VALUES_OUTSIDE_ANSWER_SPACE[key];
2732
+ return extraValues ? { ...dimension, values: [...dimension.values, ...extraValues] } : dimension;
2733
+ }
2734
+ function pickOfficialSampleAnswers(answers) {
2735
+ return Object.fromEntries(Object.entries(answers).filter(([key]) => OFFICIAL_SAMPLE_ANSWER_KEYS.includes(key)));
2454
2736
  }
2455
2737
  function readAnswersFile(path) {
2456
2738
  if (!existsSync(path)) {
@@ -2477,8 +2759,7 @@ function readAnswersFile(path) {
2477
2759
  throw new Error(`${rawKey} in ${path} should be a string, got ${typeof value}.`);
2478
2760
  }
2479
2761
  const key = toAnswerKey(rawKey);
2480
- assertValidAnswer(key, value);
2481
- answers[key] = value;
2762
+ answers[key] = resolveAnswer(key, value, path);
2482
2763
  }
2483
2764
  return answers;
2484
2765
  }
@@ -2493,10 +2774,11 @@ function splitFlag(argument) {
2493
2774
  return [argument.slice(FLAG_PREFIX_LENGTH, separatorIndex), argument.slice(separatorIndex + 1)];
2494
2775
  }
2495
2776
  function toMode(value) {
2496
- if (!MODES.includes(value)) {
2777
+ const mode = MODE_BY_VALUE.get(value);
2778
+ if (mode === void 0) {
2497
2779
  throw new Error(`"${value}" is not a mode. It accepts: ${MODES.join(", ")}.`);
2498
2780
  }
2499
- return value;
2781
+ return mode;
2500
2782
  }
2501
2783
 
2502
2784
  // src/answers-export.ts
@@ -2536,6 +2818,9 @@ function formatCreateScript(answers, shell, customTemplate) {
2536
2818
  }
2537
2819
  function getExportableKeys(answers) {
2538
2820
  const keys = getAnswerableKeys();
2821
+ if (isOfficialSamplePreset(answers.preset)) {
2822
+ return keys.filter((key) => OFFICIAL_SAMPLE_ANSWER_KEYS.includes(key));
2823
+ }
2539
2824
  if (answers.preset !== "demo") {
2540
2825
  return keys;
2541
2826
  }
@@ -2589,48 +2874,50 @@ function validatePluginIdIsUnlisted(pluginId, listedIds) {
2589
2874
  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
2875
  }
2591
2876
 
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";
2877
+ // src/official-sample.ts
2878
+ import { join as join4 } from "node:path";
2605
2879
 
2606
- // src/plan-checks.ts
2880
+ // src/templates.ts
2881
+ import { log as log4 } from "@clack/prompts";
2882
+ import ejs from "ejs";
2883
+ import { createHash } from "node:crypto";
2607
2884
  import {
2608
2885
  existsSync as existsSync3,
2609
- readdirSync,
2886
+ mkdirSync,
2610
2887
  readFileSync as readFileSync3,
2611
- statSync
2888
+ writeFileSync
2612
2889
  } from "node:fs";
2613
2890
  import {
2614
- extname as extname2,
2891
+ dirname,
2892
+ extname,
2615
2893
  join as join2
2616
2894
  } from "node:path";
2895
+ import { fileURLToPath } from "node:url";
2617
2896
 
2618
- // src/templates.ts
2619
- import { log as log3 } from "@clack/prompts";
2620
- import ejs from "ejs";
2621
- import { createHash } from "node:crypto";
2897
+ // src/docs-showcase/docs-showcase-files.ts
2622
2898
  import {
2623
2899
  existsSync as existsSync2,
2624
- mkdirSync,
2625
- readFileSync as readFileSync2,
2626
- writeFileSync
2900
+ readdirSync,
2901
+ readFileSync as readFileSync2
2627
2902
  } from "node:fs";
2628
2903
  import {
2629
- dirname,
2630
- extname,
2631
- join
2904
+ join,
2905
+ relative
2632
2906
  } from "node:path";
2633
- import { fileURLToPath } from "node:url";
2907
+ var DOCS_SHOWCASE_TREE_DIR = join("src", "docs");
2908
+ var DOCS_SHOWCASE_FILES_DIR = join("templates", "docs-showcase", "files");
2909
+ var DOCS_SHOWCASE_HOST_DIR = join("templates", "docs-showcase", "host");
2910
+ var DOCS_SHOWCASE_REPORT_PATH = join("templates", "docs-showcase", "snippets.json");
2911
+ function readDocsShowcaseFiles(packageRoot) {
2912
+ const filesDir = join(packageRoot, DOCS_SHOWCASE_FILES_DIR);
2913
+ if (!existsSync2(filesDir)) {
2914
+ return [];
2915
+ }
2916
+ 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) => ({
2917
+ content: readFileSync2(fullPath, "utf-8"),
2918
+ destinationPath: relative(filesDir, fullPath).replaceAll("\\", "/")
2919
+ }));
2920
+ }
2634
2921
 
2635
2922
  // src/template-builder.ts
2636
2923
  var PARTIAL_NAME_PATTERN = /^[a-z0-9]+(?:-[a-z0-9]+)*$/;
@@ -2647,10 +2934,31 @@ var Dependency = class {
2647
2934
  this.version = version;
2648
2935
  }
2649
2936
  };
2937
+ var FRAMEWORKS_ESBUILD_COMPILES_UNASKED = /* @__PURE__ */ new Set(["preact", "react", "svelte"]);
2650
2938
  var TemplateBuilder = class {
2651
2939
  get badges() {
2652
2940
  return [...this._badges];
2653
2941
  }
2942
+ /**
2943
+ * The options every obsidian-dev-toolkit bundler adapter takes, as `key: <TypeScript literal>` source, sorted by key.
2944
+ *
2945
+ * `framework` is a single value, and only `preset: demo` registers more than one, a set it builds only with esbuild.
2946
+ * There the toolkit compiles Svelte, React and Preact unasked, so the framework that needs the option is the one
2947
+ * passed.
2948
+ */
2949
+ get buildOptions() {
2950
+ const options = new Map(this._buildOptions);
2951
+ const frameworks = [...this._buildFrameworks];
2952
+ const framework = frameworks.length > 1 ? frameworks.find((name) => !FRAMEWORKS_ESBUILD_COMPILES_UNASKED.has(name)) : frameworks[0];
2953
+ if (framework !== void 0) {
2954
+ options.set("framework", `'${framework}'`);
2955
+ }
2956
+ if (this._buildStyles !== null) {
2957
+ const flags = [...this._buildStyles].sort((a, b) => a.localeCompare(b));
2958
+ options.set("styles", flags.length === 0 ? "{}" : `{ ${flags.map((flag) => `${flag}: true`).join(", ")} }`);
2959
+ }
2960
+ return [...options.entries()].map(([key, value]) => ({ key, value })).sort((a, b) => a.key.localeCompare(b.key));
2961
+ }
2654
2962
  get depcheckIgnores() {
2655
2963
  return [...this._depcheckIgnores.entries()].map(([packageName, reason]) => ({ packageName, reason })).sort((a, b) => a.packageName.localeCompare(b.packageName));
2656
2964
  }
@@ -2658,7 +2966,7 @@ var TemplateBuilder = class {
2658
2966
  return [...this._dependencies.values()].sort((a, b) => a.packageName.localeCompare(b.packageName));
2659
2967
  }
2660
2968
  get lintStagedPatterns() {
2661
- return [...this._lintStagedPatterns.entries()].map(([pattern, commands]) => ({ commands: [...commands], pattern }));
2969
+ return [...this._lintStagedPatterns.entries()].map(([pattern, commands]) => ({ commands: [...commands], pattern })).sort((a, b) => a.pattern.localeCompare(b.pattern));
2662
2970
  }
2663
2971
  get partials() {
2664
2972
  return new Set(this._partials);
@@ -2672,7 +2980,16 @@ var TemplateBuilder = class {
2672
2980
  get templateFiles() {
2673
2981
  return new Set(this._templateFiles);
2674
2982
  }
2983
+ /**
2984
+ * The configs the emitted `tsconfig.json` extends after its base, in registration order.
2985
+ */
2986
+ get tsconfigExtends() {
2987
+ return [...this._tsconfigExtends];
2988
+ }
2675
2989
  _badges = [];
2990
+ _buildFrameworks = /* @__PURE__ */ new Set();
2991
+ _buildOptions = /* @__PURE__ */ new Map();
2992
+ _buildStyles = null;
2676
2993
  _depcheckIgnores = /* @__PURE__ */ new Map();
2677
2994
  _dependencies = /* @__PURE__ */ new Map();
2678
2995
  _lintStagedPatterns = /* @__PURE__ */ new Map();
@@ -2680,6 +2997,7 @@ var TemplateBuilder = class {
2680
2997
  _scripts = {};
2681
2998
  _sentenceCaseBrands = /* @__PURE__ */ new Set();
2682
2999
  _templateFiles = /* @__PURE__ */ new Set();
3000
+ _tsconfigExtends = /* @__PURE__ */ new Set();
2683
3001
  /**
2684
3002
  * Registers a README badge, rendered in registration order on the line under the title.
2685
3003
  *
@@ -2691,6 +3009,35 @@ var TemplateBuilder = class {
2691
3009
  this._badges.push(markdown);
2692
3010
  return this;
2693
3011
  }
3012
+ /**
3013
+ * Registers a UI framework the obsidian-dev-toolkit bundler adapters compile, through their `framework` option.
3014
+ */
3015
+ addBuildFramework(framework) {
3016
+ this._buildFrameworks.add(framework);
3017
+ return this;
3018
+ }
3019
+ /**
3020
+ * Registers an obsidian-dev-toolkit bundler adapter option other than `framework` and `styles`.
3021
+ *
3022
+ * @param key - The option name.
3023
+ * @param value - The option's value, as TypeScript source.
3024
+ */
3025
+ addBuildOption(key, value) {
3026
+ this._buildOptions.set(key, value);
3027
+ return this;
3028
+ }
3029
+ /**
3030
+ * Turns on the adapters' `styles` option, which compiles the project's plain stylesheets, with a flag of it if given.
3031
+ *
3032
+ * @param flag - `postcss`, `tailwind` or `cssModules`; omitted, the stylesheets are compiled as plain CSS.
3033
+ */
3034
+ addBuildStyles(flag) {
3035
+ this._buildStyles ??= /* @__PURE__ */ new Set();
3036
+ if (flag !== void 0) {
3037
+ this._buildStyles.add(flag);
3038
+ }
3039
+ return this;
3040
+ }
2694
3041
  /**
2695
3042
  * Registers a declared package that depcheck reports as unused although it is not -- one only ever
2696
3043
  * invoked as a CLI, named as a string in a config, or reached by a compiler option.
@@ -2718,6 +3065,11 @@ var TemplateBuilder = class {
2718
3065
  * The commands are collected here rather than concatenated from template partials because a partial can
2719
3066
  * only ever emit `'<command>',` -- and the trailing comma the last one leaves behind is exactly what the
2720
3067
  * generated formatter config strips, so the file failed its own `format:check`.
3068
+ *
3069
+ * The patterns are rendered sorted, not in registration order: they become the keys of the emitted
3070
+ * `nano-staged-config.ts` object, which the shared ESLint config's `perfectionist/sort-objects` checks,
3071
+ * and answers register them in question order (markdownlint's `*.md` before the `*.{ts,tsx,mts}` that
3072
+ * `preset: demo` forces in). Commands under one pattern keep their order, since nano-staged runs them so.
2721
3073
  */
2722
3074
  addLintStagedCommand(pattern, command) {
2723
3075
  const commands = this._lintStagedPatterns.get(pattern) ?? [];
@@ -2755,13 +3107,23 @@ var TemplateBuilder = class {
2755
3107
  this._sentenceCaseBrands.add(brand);
2756
3108
  return this;
2757
3109
  }
3110
+ /**
3111
+ * Registers a config the emitted `tsconfig.json` extends after its base, such as a framework's JSX preset.
3112
+ *
3113
+ * Collected here rather than composed from partials for the same reason as {@link addLintStagedCommand}: the
3114
+ * `extends` value is a list whose last entry must not carry a comma, and a single entry is written as a plain string.
3115
+ */
3116
+ addTsconfigExtends(config) {
3117
+ this._tsconfigExtends.add(config);
3118
+ return this;
3119
+ }
2758
3120
  };
2759
3121
 
2760
3122
  // src/versions.ts
2761
- import { log as log2 } from "@clack/prompts";
3123
+ import { log as log3 } from "@clack/prompts";
2762
3124
  var PINNED_VERSIONS = {
2763
3125
  "@babel/core": {
2764
- check: `node -e "process.stdout.write(require('@rollup/plugin-babel/package.json').peerDependencies['@babel/core'])"`,
3126
+ 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
3127
  checkRequires: "@rollup/plugin-babel",
2766
3128
  expect: "^7.0.0",
2767
3129
  manualCheck: null,
@@ -2771,7 +3133,7 @@ var PINNED_VERSIONS = {
2771
3133
  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
3134
  },
2773
3135
  "@babel/plugin-transform-react-jsx": {
2774
- check: `node -e "process.stdout.write(require('@rollup/plugin-babel/package.json').peerDependencies['@babel/core'])"`,
3136
+ 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
3137
  checkRequires: "@rollup/plugin-babel",
2776
3138
  expect: "^7.0.0",
2777
3139
  manualCheck: null,
@@ -2781,7 +3143,7 @@ var PINNED_VERSIONS = {
2781
3143
  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
3144
  },
2783
3145
  "@babel/preset-react": {
2784
- check: `node -e "process.stdout.write(require('@rollup/plugin-babel/package.json').peerDependencies['@babel/core'])"`,
3146
+ 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
3147
  checkRequires: "@rollup/plugin-babel",
2786
3148
  expect: "^7.0.0",
2787
3149
  manualCheck: null,
@@ -2791,7 +3153,7 @@ var PINNED_VERSIONS = {
2791
3153
  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
3154
  },
2793
3155
  "@babel/preset-typescript": {
2794
- check: `node -e "process.stdout.write(require('@rollup/plugin-babel/package.json').peerDependencies['@babel/core'])"`,
3156
+ 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
3157
  checkRequires: "@rollup/plugin-babel",
2796
3158
  expect: "^7.0.0",
2797
3159
  manualCheck: null,
@@ -2813,23 +3175,73 @@ var PINNED_VERSIONS = {
2813
3175
  "@codemirror/state": {
2814
3176
  check: `node -e "process.stdout.write(require('obsidian/package.json').peerDependencies['@codemirror/state'])"`,
2815
3177
  checkRequires: "obsidian",
2816
- expect: "6.5.0",
3178
+ expect: "6.7.6",
2817
3179
  manualCheck: null,
2818
3180
  needsOverride: true,
2819
3181
  section: "devDependencies",
2820
- version: "6.5.0",
3182
+ version: "6.7.6",
2821
3183
  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
3184
  },
2823
3185
  "@codemirror/view": {
2824
3186
  check: `node -e "process.stdout.write(require('obsidian/package.json').peerDependencies['@codemirror/view'])"`,
2825
3187
  checkRequires: "obsidian",
2826
- expect: "6.38.6",
3188
+ expect: "6.43.13",
2827
3189
  manualCheck: null,
2828
3190
  needsOverride: true,
2829
3191
  section: "devDependencies",
2830
- version: "6.38.6",
3192
+ version: "6.43.13",
2831
3193
  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
3194
  },
3195
+ "@wdio/cli": {
3196
+ 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)"`,
3197
+ checkRequires: "wdio-obsidian-service",
3198
+ expect: "^9.18.1",
3199
+ manualCheck: null,
3200
+ needsOverride: false,
3201
+ section: "devDependencies",
3202
+ version: "^9.32.0",
3203
+ 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."
3204
+ },
3205
+ "@wdio/globals": {
3206
+ 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)"`,
3207
+ checkRequires: "wdio-obsidian-service",
3208
+ expect: "^9.18.1",
3209
+ manualCheck: null,
3210
+ needsOverride: false,
3211
+ section: "devDependencies",
3212
+ version: "^9.31.3",
3213
+ 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."
3214
+ },
3215
+ "@wdio/local-runner": {
3216
+ 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)"`,
3217
+ checkRequires: "wdio-obsidian-service",
3218
+ expect: "^9.18.1",
3219
+ manualCheck: null,
3220
+ needsOverride: false,
3221
+ section: "devDependencies",
3222
+ version: "^9.32.0",
3223
+ 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."
3224
+ },
3225
+ "@wdio/mocha-framework": {
3226
+ 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)"`,
3227
+ checkRequires: "wdio-obsidian-service",
3228
+ expect: "^9.18.1",
3229
+ manualCheck: null,
3230
+ needsOverride: false,
3231
+ section: "devDependencies",
3232
+ version: "^9.32.0",
3233
+ 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."
3234
+ },
3235
+ "expect-webdriverio": {
3236
+ 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)"`,
3237
+ checkRequires: "wdio-obsidian-service",
3238
+ expect: "^9.18.1",
3239
+ manualCheck: null,
3240
+ needsOverride: false,
3241
+ section: "devDependencies",
3242
+ version: "^6.1.0",
3243
+ 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."
3244
+ },
2833
3245
  "moment": {
2834
3246
  check: null,
2835
3247
  checkRequires: null,
@@ -2856,17 +3268,17 @@ var ADVISORY_OVERRIDES = {
2856
3268
  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
3269
  expect: "^2.2.0",
2858
3270
  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"],
3271
+ requires: ["obsidian-integration-testing", "wdio-obsidian-service"],
2860
3272
  spec: "^3.2.1",
2861
3273
  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
3274
  },
2863
3275
  "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'])"`,
3276
+ 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
3277
  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"],
3278
+ 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.",
3279
+ requires: ["obsidian-integration-testing"],
2868
3280
  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`."
3281
+ 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`."
2870
3282
  },
2871
3283
  "serialize-javascript": {
2872
3284
  check: `node -e "const fs=require('node:fs');process.stdout.write(JSON.parse(fs.readFileSync('node_modules/mocha/package.json','utf8')).dependencies['serialize-javascript'])"`,
@@ -2875,6 +3287,14 @@ var ADVISORY_OVERRIDES = {
2875
3287
  requires: ["@wdio/mocha-framework"],
2876
3288
  spec: "^7.1.1",
2877
3289
  why: "Clears GHSA-5c6j-r48x-rmvq (RCE via RegExp.flags and Date.prototype.toISOString) and GHSA-qj8w-gfj5-8c6v (CPU-exhaustion denial of service via crafted array-likes), both fixed in 7.0.5. No direct bump reaches it: mocha declares `serialize-javascript@^6.0.2` at every published version including 11.8.0, and the only consumer here is @wdio/mocha-framework -> mocha. `npm audit fix --force` offers a DOWNGRADE to @wdio/mocha-framework@7.7.3 instead. The forced major is safe for the one call site that exists: mocha's `buffered-worker-pool.js` calls `serializeJavascript(opts, { unsafe: true, ignoreFunction: true })`, and 6.0.2 and 7.1.1 were measured to return byte-identical output for that exact option pair across RegExp, Date, Map, Set, undefined, BigInt, functions and a script-tag string. Note the call is on mocha's parallel-run path, which wdio does not take."
3290
+ },
3291
+ "smol-toml": {
3292
+ check: `node -e "const fs=require('node:fs');const path=['node_modules/@mnaoumov/typescript-dev-toolkit/node_modules/markdownlint-cli2/package.json','node_modules/markdownlint-cli2/package.json'].find((candidate)=>fs.existsSync(candidate));process.stdout.write(JSON.parse(fs.readFileSync(path,'utf8')).dependencies['smol-toml'])"`,
3293
+ expect: "1.8.0",
3294
+ manualCheck: "The check reads the exact version pinned by the markdownlint-cli2 that @mnaoumov/typescript-dev-toolkit reaches, nested under it when the project also declares a newer markdownlint-cli2, which is what makes the override necessary. When the toolkit moves to markdownlint-cli2 ^0.24.0 or later, that copy pins 1.9.1 and the override and this entry can go.",
3295
+ requires: ["@mnaoumov/obsidian-dev-toolkit", "@mnaoumov/typescript-dev-toolkit"],
3296
+ spec: "^1.9.1",
3297
+ why: "Clears GHSA-r4xh-jqrq-34v2 (quadratic-time parse() from parseKey rescanning to the end of the document), patched in 1.9.0. markdownlint-cli2 pinned `smol-toml` to exactly 1.8.0 up to 0.23.3, and @mnaoumov/typescript-dev-toolkit declares markdownlint-cli2 `^0.23.2`, which on a 0.x package stops below 0.24.0, the first release pinning 1.9.1. So the toolkit presets still reach 1.8.0 through the toolkit, and `npm audit fix --force` offers only a DOWNGRADE of markdownlint-cli2 to 0.21.0. The markdownlint answer's own markdownlint-cli2 resolves to 0.24.0 or later, so `standalone` needs no override. The spec stays inside the 1.x major, and markdownlint-cli2 imports only `parse`, to read a `.markdownlint-cli2.toml` config."
2878
3298
  }
2879
3299
  };
2880
3300
  var DESKTOP_RELEASES_JSON_URL = "https://raw.githubusercontent.com/obsidianmd/obsidian-releases/master/desktop-releases.json";
@@ -2997,7 +3417,7 @@ async function resolveVersions(dependencies) {
2997
3417
  resolved.set(packageName, `^${version}`);
2998
3418
  }
2999
3419
  if (failed.length > 0) {
3000
- log2.warn(`Could not look up the latest version of ${failed.join(", ")}. Falling back to "${FALLBACK_VERSION}".`);
3420
+ log3.warn(`Could not look up the latest version of ${failed.join(", ")}. Falling back to "${FALLBACK_VERSION}".`);
3001
3421
  }
3002
3422
  return resolved;
3003
3423
  }
@@ -3015,6 +3435,7 @@ function hasPackage(dependencies, packageName) {
3015
3435
  var ASSET_EXTENSIONS = /* @__PURE__ */ new Set([".wasm"]);
3016
3436
  var JSON_INDENT_SPACES3 = 2;
3017
3437
  var UNRESOLVED_VERSION = "latest";
3438
+ var TOOLKIT_WORKFLOW_REF = "3.0.0";
3018
3439
  var BASE_TEMPLATE_FILES = [
3019
3440
  // Never empty: `tslib` and `typescript` below are false positives on every answer set.
3020
3441
  ".depcheckrc.json",
@@ -3023,6 +3444,9 @@ var BASE_TEMPLATE_FILES = [
3023
3444
  ".gitattributes",
3024
3445
  ".gitignore",
3025
3446
  ".npmrc",
3447
+ // The same Node major as this repo's own `.nvmrc`. Every CI workflow reads it, the toolkit's reusable ones by
3448
+ // Default, and without it they fall back to the latest LTS, which is not the version the project is developed on.
3449
+ ".nvmrc",
3026
3450
  "CONTRIBUTING.md",
3027
3451
  "LICENSE",
3028
3452
  "README.md",
@@ -3080,7 +3504,9 @@ var DEMO_OVERRIDES = [
3080
3504
  { answerKey: "spellChecker", demoValue: "cspell", options: SPELL_CHECKER_OPTIONS },
3081
3505
  { answerKey: "styling", demoValue: "scss", options: STYLING_OPTIONS }
3082
3506
  ];
3083
- function buildTemplate(answers, overlay = null) {
3507
+ var DEMO_PINNED_ANSWERS = { bundler: "esbuild", uiFramework: "none" };
3508
+ function buildTemplate(givenAnswers, overlay = null) {
3509
+ const answers = pinPresetAnswers(givenAnswers);
3084
3510
  const builder = new TemplateBuilder();
3085
3511
  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
3512
  const funding = resolveFunding(answers);
@@ -3114,40 +3540,45 @@ function buildTemplate(answers, overlay = null) {
3114
3540
  builder.addPartial(option.partialName);
3115
3541
  }
3116
3542
  }
3543
+ if (builder.lintStagedPatterns.length > 0) {
3544
+ addStagedFilesHook(builder, answers.preset);
3545
+ }
3546
+ if (isFrameworkPreset(answers.preset) && builder.buildOptions.length > 0) {
3547
+ builder.addFiles(["scripts/build-options.ts"]);
3548
+ }
3117
3549
  if (overlay) {
3118
3550
  applyOverlay(builder, overlay);
3119
3551
  }
3120
- if (builder.lintStagedPatterns.length > 0) {
3121
- addStagedFilesHook(builder);
3122
- }
3123
3552
  return builder;
3124
3553
  }
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");
3554
+ function copyTemplates(givenAnswers, targetDir, currentVersion, existingConfig, resolvedVersions = /* @__PURE__ */ new Map(), minAppVersion = FALLBACK_MIN_APP_VERSION, overlay = null, projectFormatter) {
3555
+ const answers = pinPresetAnswers(givenAnswers);
3556
+ const templatesDir = join2(getScriptDir(), "..", "templates", "default");
3127
3557
  function findTemplate(relativePath) {
3128
3558
  if (overlay) {
3129
- const overlayPath = join(overlay.dir, relativePath);
3130
- if (existsSync2(overlayPath)) {
3559
+ const overlayPath = join2(overlay.dir, relativePath);
3560
+ if (existsSync3(overlayPath)) {
3131
3561
  return overlayPath;
3132
3562
  }
3133
3563
  }
3134
- const builtInPath = join(templatesDir, relativePath);
3135
- return existsSync2(builtInPath) ? builtInPath : null;
3564
+ const builtInPath = join2(templatesDir, relativePath);
3565
+ return existsSync3(builtInPath) ? builtInPath : null;
3136
3566
  }
3137
- const newConfig = {
3138
- fileHashes: {},
3139
- generatorVersion: currentVersion
3140
- };
3141
3567
  const builder = buildTemplate(answers, overlay);
3142
3568
  const templateFiles = builder.templateFiles;
3143
3569
  const partials = builder.partials;
3144
3570
  const dependencies = builder.dependencies;
3571
+ const hasBuildOptions = templateFiles.has("scripts/build-options.ts");
3145
3572
  let currentTemplatePath = "";
3146
3573
  let renderRoot = "";
3147
3574
  const templateContext = {
3148
3575
  ...answers,
3149
3576
  ...getFundingTemplateContext(answers),
3150
3577
  _badges: builder.badges,
3578
+ _buildOptionsArgument: hasBuildOptions ? "buildOptions" : "",
3579
+ _buildOptionsImport: hasBuildOptions ? "\nimport { buildOptions } from './build-options.ts';\n" : "",
3580
+ _buildOptionsLiteral: toObjectLiteral(builder.buildOptions),
3581
+ _cspellIdentityWords: getCspellIdentityWords(answers),
3151
3582
  _depcheckIgnores: builder.depcheckIgnores,
3152
3583
  _dependencies: dependencies.map((dependency) => ({
3153
3584
  packageName: dependency.packageName,
@@ -3161,6 +3592,8 @@ function copyTemplates(answers, targetDir, currentVersion, existingConfig, resol
3161
3592
  _resolutions: Object.entries(buildResolutions(dependencies)).map(([packageName, spec]) => ({ packageName, spec })),
3162
3593
  _scripts: builder.scripts,
3163
3594
  _sentenceCaseBrands: builder.sentenceCaseBrands,
3595
+ _toolkitWorkflowRef: TOOLKIT_WORKFLOW_REF,
3596
+ _tsconfigExtendsJson: toTsconfigExtendsJson(builder.tsconfigExtends),
3164
3597
  pluginShortName: getPluginShortName(answers.pluginId),
3165
3598
  render(options) {
3166
3599
  const { indentLevel, section } = typeof options === "string" ? { indentLevel: 0, section: options } : { indentLevel: 0, section: void 0, ...options };
@@ -3176,7 +3609,7 @@ function copyTemplates(answers, targetDir, currentVersion, existingConfig, resol
3176
3609
  }
3177
3610
  currentTemplatePath = partialPath;
3178
3611
  renderRoot = previousRenderRoot || partialPath;
3179
- let rendered = ejs.render(readFileSync2(fullPath, "utf-8"), templateContext);
3612
+ let rendered = ejs.render(readFileSync3(fullPath, "utf-8"), templateContext);
3180
3613
  if (indentLevel > 0) {
3181
3614
  const indent = " ".repeat(indentLevel);
3182
3615
  rendered = rendered.replaceAll(/^(?<Content>.+)$/gm, `${indent}$<Content>`);
@@ -3192,7 +3625,7 @@ function copyTemplates(answers, targetDir, currentVersion, existingConfig, resol
3192
3625
  *
3193
3626
  * A section that contributes imports emits them in PARTIAL order, which is the order the answers were
3194
3627
  * 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
3628
+ * import-sorting lint rule wants. The toolkit presets now adopt obsidian-dev-toolkit's shared
3196
3629
  * ESLint config, which sorts imports as an ERROR, so `uiFramework=lit editorExtensions=codemirror`
3197
3630
  * emitted a `src/plugin.ts` that was red the moment it was generated. The sorting cannot be pushed
3198
3631
  * into the partials: each one knows only itself, and which others are beside it is the answer set.
@@ -3201,71 +3634,35 @@ function copyTemplates(answers, targetDir, currentVersion, existingConfig, resol
3201
3634
  return sortImportStatements(text3);
3202
3635
  }
3203
3636
  };
3204
- const skipped = [];
3205
- const updated = [];
3206
- const created = [];
3207
- const written = [];
3637
+ const renderedFiles = [];
3208
3638
  for (const registeredPath of templateFiles) {
3209
3639
  const destinationPath = getDestinationPath(registeredPath, answers);
3210
- const fullDestinationPath = join(targetDir, destinationPath);
3211
3640
  const isAsset = ASSET_EXTENSIONS.has(extname(registeredPath));
3212
3641
  const ejsPath = findTemplate(`${registeredPath}.ejs`);
3213
3642
  let rendered;
3214
3643
  if (isAsset) {
3215
3644
  currentTemplatePath = registeredPath;
3216
- rendered = readFileSync2(findTemplate(registeredPath) ?? join(templatesDir, registeredPath));
3645
+ rendered = readFileSync3(findTemplate(registeredPath) ?? join2(templatesDir, registeredPath));
3217
3646
  } else if (ejsPath === null) {
3218
3647
  currentTemplatePath = `${registeredPath}.ejs`;
3219
3648
  rendered = templateContext["render"]();
3220
3649
  } else {
3221
3650
  currentTemplatePath = `${registeredPath}.ejs`;
3222
3651
  try {
3223
- rendered = ejs.render(readFileSync2(ejsPath, "utf-8"), templateContext);
3652
+ rendered = ejs.render(readFileSync3(ejsPath, "utf-8"), templateContext);
3224
3653
  } catch (error) {
3225
3654
  if (overlay && ejsPath.startsWith(overlay.dir)) {
3226
3655
  throw new Error(`${ejsPath} failed to render: ${error instanceof Error ? error.message : String(error)}`, { cause: error });
3227
3656
  }
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;
3657
+ rendered = readFileSync3(ejsPath, "utf-8");
3239
3658
  }
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;
3248
- }
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
3659
  }
3258
- writeFileSync(fullDestinationPath, rendered);
3259
- written.push(destinationPath);
3660
+ renderedFiles.push({ content: rendered, destinationPath });
3260
3661
  }
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);
3662
+ if (answers.preset === DOCS_SHOWCASE_PRESET) {
3663
+ renderedFiles.push(...readDocsShowcaseFiles(join2(getScriptDir(), "..")));
3267
3664
  }
3268
- return newConfig;
3665
+ return writeGeneratedFiles(renderedFiles, targetDir, currentVersion, existingConfig, projectFormatter);
3269
3666
  }
3270
3667
  function getDestinationPath(templatePath, answers) {
3271
3668
  return templatePath.replace(/%= (?<AnswerKey>.+?) %/g, (_match, ...args) => String(answers[String(args[0])]));
@@ -3279,20 +3676,23 @@ function isPartialTemplatePath(templatePath) {
3279
3676
  return markerIndex > 0 && PARTIAL_NAME_PATTERN.test(fileName.slice(markerIndex + 1));
3280
3677
  }
3281
3678
  function loadConfig(dir) {
3282
- const configPath = join(dir, CONFIG_FILE_NAME);
3283
- if (!existsSync2(configPath)) {
3679
+ const configPath = join2(dir, CONFIG_FILE_NAME);
3680
+ if (!existsSync3(configPath)) {
3284
3681
  return null;
3285
3682
  }
3286
- const parsed = JSON.parse(readFileSync2(configPath, "utf-8"));
3683
+ const parsed = JSON.parse(readFileSync3(configPath, "utf-8"));
3287
3684
  const raw = parsed;
3288
3685
  migrateAnswers(raw);
3289
3686
  return parsed;
3290
3687
  }
3688
+ function pinPresetAnswers(answers) {
3689
+ return answers.preset === "demo" ? { ...answers, ...DEMO_PINNED_ANSWERS } : answers;
3690
+ }
3291
3691
  function recordHashesOnDisk(targetDir, config) {
3292
3692
  const fileHashes = {};
3293
3693
  for (const [destinationPath, hash] of Object.entries(config.fileHashes)) {
3294
- const fullPath = join(targetDir, destinationPath);
3295
- fileHashes[destinationPath] = existsSync2(fullPath) ? sha256(readFileSync2(fullPath)) : hash;
3694
+ const fullPath = join2(targetDir, destinationPath);
3695
+ fileHashes[destinationPath] = existsSync3(fullPath) ? sha256(readFileSync3(fullPath)) : hash;
3296
3696
  }
3297
3697
  return { ...config, fileHashes };
3298
3698
  }
@@ -3321,6 +3721,56 @@ function sortImportStatements(text3) {
3321
3721
  return `${statements.join("\n")}
3322
3722
  `;
3323
3723
  }
3724
+ function writeGeneratedFiles(files, targetDir, currentVersion, existingConfig, projectFormatter) {
3725
+ const newConfig = {
3726
+ fileHashes: {},
3727
+ generatorVersion: currentVersion
3728
+ };
3729
+ const skipped = [];
3730
+ const updated = [];
3731
+ const created = [];
3732
+ const written = [];
3733
+ for (const { content: rendered, destinationPath } of files) {
3734
+ const fullDestinationPath = join2(targetDir, destinationPath);
3735
+ const newHash = sha256(rendered);
3736
+ if (existingConfig && existsSync3(fullDestinationPath)) {
3737
+ const currentContent = Buffer.isBuffer(rendered) ? readFileSync3(fullDestinationPath) : readFileSync3(fullDestinationPath, "utf-8");
3738
+ const currentHash = sha256(currentContent);
3739
+ const originalHash = existingConfig.fileHashes[destinationPath];
3740
+ if (matchesRender(currentHash, newHash, projectFormatter, destinationPath, rendered)) {
3741
+ newConfig.fileHashes[destinationPath] = currentHash;
3742
+ continue;
3743
+ }
3744
+ if (originalHash === void 0) {
3745
+ skipped.push(destinationPath);
3746
+ continue;
3747
+ }
3748
+ if (currentHash !== originalHash) {
3749
+ skipped.push(destinationPath);
3750
+ newConfig.fileHashes[destinationPath] = originalHash;
3751
+ continue;
3752
+ }
3753
+ updated.push(destinationPath);
3754
+ } else {
3755
+ created.push(destinationPath);
3756
+ }
3757
+ newConfig.fileHashes[destinationPath] = newHash;
3758
+ const destDir = dirname(fullDestinationPath);
3759
+ if (!existsSync3(destDir)) {
3760
+ mkdirSync(destDir, { recursive: true });
3761
+ }
3762
+ writeFileSync(fullDestinationPath, rendered);
3763
+ written.push(destinationPath);
3764
+ }
3765
+ formatWrittenFiles(projectFormatter, targetDir, written, newConfig);
3766
+ const configPath = join2(targetDir, CONFIG_FILE_NAME);
3767
+ writeFileSync(configPath, `${JSON.stringify(newConfig, null, JSON_INDENT_SPACES3)}
3768
+ `);
3769
+ if (existingConfig) {
3770
+ logUpdateSummary(updated, created, skipped);
3771
+ }
3772
+ return newConfig;
3773
+ }
3324
3774
  function applyOverlay(builder, overlay) {
3325
3775
  builder.addFiles([...overlay.files]);
3326
3776
  for (const packageName of overlay.packages) {
@@ -3343,9 +3793,13 @@ function formatWrittenFiles(projectFormatter, targetDir, written, config) {
3343
3793
  }
3344
3794
  projectFormatter.formatFiles(textFiles);
3345
3795
  for (const destinationPath of textFiles) {
3346
- config.fileHashes[destinationPath] = sha256(readFileSync2(join(targetDir, destinationPath)));
3796
+ config.fileHashes[destinationPath] = sha256(readFileSync3(join2(targetDir, destinationPath)));
3347
3797
  }
3348
3798
  }
3799
+ function getCspellIdentityWords(answers) {
3800
+ const words = [answers.authorGitHubName, "mnaoumov"];
3801
+ return words.filter((word, index) => words.findIndex((other) => other.toLowerCase() === word.toLowerCase()) === index);
3802
+ }
3349
3803
  function getFundingTemplateContext(answers) {
3350
3804
  const funding = resolveFunding(answers);
3351
3805
  return {
@@ -3363,25 +3817,25 @@ function importedModule(block) {
3363
3817
  }
3364
3818
  function logUpdateSummary(updated, created, skipped) {
3365
3819
  if (updated.length > 0) {
3366
- log3.success(`Updated ${String(updated.length)} file(s):`);
3820
+ log4.success(`Updated ${String(updated.length)} file(s):`);
3367
3821
  for (const f of updated) {
3368
- log3.info(` ${f}`);
3822
+ log4.info(` ${f}`);
3369
3823
  }
3370
3824
  }
3371
3825
  if (created.length > 0) {
3372
- log3.success(`Created ${String(created.length)} new file(s):`);
3826
+ log4.success(`Created ${String(created.length)} new file(s):`);
3373
3827
  for (const f of created) {
3374
- log3.info(` ${f}`);
3828
+ log4.info(` ${f}`);
3375
3829
  }
3376
3830
  }
3377
3831
  if (skipped.length > 0) {
3378
- log3.warn(`Skipped ${String(skipped.length)} file(s) with local modifications:`);
3832
+ log4.warn(`Skipped ${String(skipped.length)} file(s) with local modifications:`);
3379
3833
  for (const f of skipped) {
3380
- log3.info(` ${f}`);
3834
+ log4.info(` ${f}`);
3381
3835
  }
3382
3836
  }
3383
3837
  if (updated.length === 0 && created.length === 0) {
3384
- log3.info("Everything is already up to date.");
3838
+ log4.info("Everything is already up to date.");
3385
3839
  }
3386
3840
  }
3387
3841
  function matchesRender(currentHash, newHash, projectFormatter, destinationPath, rendered) {
@@ -3416,6 +3870,11 @@ function migrateAnswers(raw) {
3416
3870
  answers["fundingUsername"] ??= answers["authorGitHubName"];
3417
3871
  answers["coverageBadge"] ??= "none";
3418
3872
  delete answers["pluginShortName"];
3873
+ for (const [key, value] of Object.entries(answers)) {
3874
+ if (typeof value === "string") {
3875
+ answers[key] = resolveDeprecatedAnswer(key, value, CONFIG_FILE_NAME);
3876
+ }
3877
+ }
3419
3878
  }
3420
3879
  function migrateFundingAnswers(answers) {
3421
3880
  if (answers["fundingPlatform"] !== void 0) {
@@ -3450,8 +3909,215 @@ function migrateFundingAnswers(answers) {
3450
3909
  function sha256(content) {
3451
3910
  return createHash("sha256").update(content).digest("hex");
3452
3911
  }
3912
+ function toObjectLiteral(options) {
3913
+ return options.length === 0 ? "{}" : `{
3914
+ ${options.map((option) => ` ${option.key}: ${option.value}`).join(",\n")}
3915
+ }`;
3916
+ }
3917
+ function toTsconfigExtendsJson(extraConfigs) {
3918
+ const base = JSON.stringify("@tsconfig/strictest/tsconfig.json");
3919
+ return extraConfigs.length === 0 ? base : `[
3920
+ ${[base, ...extraConfigs.map((config) => JSON.stringify(config))].map((config) => ` ${config}`).join(",\n")}
3921
+ ]`;
3922
+ }
3923
+
3924
+ // src/upstream-snapshot.ts
3925
+ import {
3926
+ existsSync as existsSync4,
3927
+ readdirSync as readdirSync2,
3928
+ readFileSync as readFileSync4
3929
+ } from "node:fs";
3930
+ import {
3931
+ join as join3,
3932
+ relative as relative2
3933
+ } from "node:path";
3934
+ var VENDORED_SUFFIX = ".vendored";
3935
+ var REGULAR_FILE_MODES = /* @__PURE__ */ new Set(["100644", "100755"]);
3936
+ async function fetchUpstreamSnapshot(repo, ref) {
3937
+ const headers = { Accept: "application/vnd.github+json" };
3938
+ const token = process.env["GITHUB_TOKEN"];
3939
+ if (token) {
3940
+ headers["Authorization"] = `Bearer ${token}`;
3941
+ }
3942
+ const commit = await fetchJson(`https://api.github.com/repos/${repo}/commits/${encodeURIComponent(ref)}`, headers);
3943
+ const tree = await fetchJson(`https://api.github.com/repos/${repo}/git/trees/${commit.sha}?recursive=1`, headers);
3944
+ if (tree.truncated) {
3945
+ throw new Error(`The tree of ${repo}@${commit.sha} is too large for one API response.`);
3946
+ }
3947
+ const paths = tree.tree.filter((entry) => entry.type === "blob" && REGULAR_FILE_MODES.has(entry.mode)).map((entry) => entry.path);
3948
+ const contents = await Promise.all(paths.map(async (path) => {
3949
+ const response = await fetch(`https://raw.githubusercontent.com/${repo}/${commit.sha}/${path.split("/").map(encodeURIComponent).join("/")}`);
3950
+ if (!response.ok) {
3951
+ throw new Error(`Could not download ${path} from ${repo}@${commit.sha}: HTTP ${String(response.status)}.`);
3952
+ }
3953
+ return Buffer.from(await response.arrayBuffer());
3954
+ }));
3955
+ return {
3956
+ commit: commit.sha,
3957
+ files: new Map(paths.map((path, index) => [path, contents[index] ?? Buffer.alloc(0)]))
3958
+ };
3959
+ }
3960
+ function readUpstream(upstreamsPath, name) {
3961
+ const parsed = JSON.parse(readFileSync4(upstreamsPath, "utf-8"));
3962
+ const upstream = parsed.upstreams.find((candidate) => candidate.name === name);
3963
+ if (!upstream) {
3964
+ throw new Error(`${upstreamsPath} has no upstream named "${name}".`);
3965
+ }
3966
+ return upstream;
3967
+ }
3968
+ function readVendoredFiles(dir) {
3969
+ const files = /* @__PURE__ */ new Map();
3970
+ if (!existsSync4(dir)) {
3971
+ return files;
3972
+ }
3973
+ const paths = readdirSync2(dir, { recursive: true, withFileTypes: true }).filter((entry) => entry.isFile() && entry.name.endsWith(VENDORED_SUFFIX)).map((entry) => join3(entry.parentPath, entry.name)).sort();
3974
+ for (const fullPath of paths) {
3975
+ const upstreamPath = relative2(dir, fullPath).replaceAll("\\", "/").slice(0, -VENDORED_SUFFIX.length);
3976
+ files.set(upstreamPath, readFileSync4(fullPath));
3977
+ }
3978
+ return files;
3979
+ }
3980
+ async function fetchJson(url, headers) {
3981
+ const response = await fetch(url, { headers });
3982
+ if (!response.ok) {
3983
+ throw new Error(`GET ${url} failed: HTTP ${String(response.status)}.`);
3984
+ }
3985
+ return await response.json();
3986
+ }
3987
+
3988
+ // src/official-sample.ts
3989
+ var OFFICIAL_SAMPLE_UPSTREAM_NAME = "obsidian-sample-plugin";
3990
+ var OFFICIAL_SAMPLE_FILES_DIR = join4("templates", "official-sample", "files");
3991
+ var OFFICIAL_SAMPLE_PINNED_ANSWERS = {
3992
+ formatter: "none",
3993
+ packageManager: "npm"
3994
+ };
3995
+ function applyOfficialSampleIdentity(files, answers) {
3996
+ const packageName = `obsidian-${answers.pluginId}`;
3997
+ const result = new Map(files);
3998
+ editJson(result, "manifest.json", (manifest) => {
3999
+ const fundingUrl = resolveFunding(answers)?.getUrl(answers);
4000
+ const edited = {};
4001
+ for (const [key, value] of Object.entries(manifest)) {
4002
+ switch (key) {
4003
+ case "author":
4004
+ edited[key] = answers.authorName;
4005
+ break;
4006
+ case "authorUrl":
4007
+ edited[key] = `https://github.com/${answers.authorGitHubName}`;
4008
+ break;
4009
+ case "description":
4010
+ edited[key] = answers.pluginDescription;
4011
+ break;
4012
+ case "fundingUrl":
4013
+ if (fundingUrl) {
4014
+ edited[key] = fundingUrl;
4015
+ }
4016
+ break;
4017
+ case "id":
4018
+ edited[key] = answers.pluginId;
4019
+ break;
4020
+ case "name":
4021
+ edited[key] = answers.pluginName;
4022
+ break;
4023
+ default:
4024
+ edited[key] = value;
4025
+ }
4026
+ }
4027
+ return edited;
4028
+ });
4029
+ const upstreamPackageName = readUpstreamPackageName(files);
4030
+ editJson(result, "package.json", (packageJson) => ({ ...packageJson, name: packageName }));
4031
+ editJson(result, "package-lock.json", (lock) => renamePackageInLock(lock, upstreamPackageName, packageName));
4032
+ const readme = result.get("README.md");
4033
+ if (readme) {
4034
+ result.set("README.md", Buffer.from(readme.toString("utf-8").replace(/^# .*$/m, `# ${answers.pluginName}`), "utf-8"));
4035
+ }
4036
+ return result;
4037
+ }
4038
+ function copyOfficialSample(answers, targetDir, currentVersion, existingConfig, snapshot) {
4039
+ const files = applyOfficialSampleIdentity(snapshot.files, answers);
4040
+ const config = writeGeneratedFiles(
4041
+ [...files].map(([destinationPath, content]) => ({ content, destinationPath })),
4042
+ targetDir,
4043
+ currentVersion,
4044
+ existingConfig
4045
+ );
4046
+ return { ...config, upstreamCommit: snapshot.commit };
4047
+ }
4048
+ function getPackageRoot() {
4049
+ return join4(getScriptDir(), "..");
4050
+ }
4051
+ function getUpstreamsPath() {
4052
+ return join4(getPackageRoot(), "upstreams.json");
4053
+ }
4054
+ function loadOfficialSampleSnapshot() {
4055
+ const upstream = readUpstream(getUpstreamsPath(), OFFICIAL_SAMPLE_UPSTREAM_NAME);
4056
+ const files = readVendoredFiles(join4(getPackageRoot(), OFFICIAL_SAMPLE_FILES_DIR));
4057
+ if (files.size === 0) {
4058
+ throw new Error(`The vendored snapshot of ${upstream.repo} is missing from ${OFFICIAL_SAMPLE_FILES_DIR}.`);
4059
+ }
4060
+ return { commit: upstream.commit, files };
4061
+ }
4062
+ function editJson(files, path, edit) {
4063
+ const content = files.get(path);
4064
+ if (!content) {
4065
+ return;
4066
+ }
4067
+ const text3 = content.toString("utf-8");
4068
+ const indent = /^\{\r?\n(?<Indent>[ \t]+)/.exec(text3)?.groups?.["Indent"] ?? " ";
4069
+ const finalNewline = /\r?\n$/.exec(text3)?.[0] ?? "";
4070
+ const edited = edit(JSON.parse(text3));
4071
+ files.set(path, Buffer.from(`${JSON.stringify(edited, null, indent)}${finalNewline}`, "utf-8"));
4072
+ }
4073
+ function readUpstreamPackageName(files) {
4074
+ const content = files.get("package.json");
4075
+ if (!content) {
4076
+ return void 0;
4077
+ }
4078
+ const name = JSON.parse(content.toString("utf-8"))["name"];
4079
+ return typeof name === "string" ? name : void 0;
4080
+ }
4081
+ function renamePackageInLock(lock, upstreamName, packageName) {
4082
+ const renamed = { ...lock };
4083
+ if (renamed["name"] === upstreamName) {
4084
+ renamed["name"] = packageName;
4085
+ }
4086
+ const packages = renamed["packages"];
4087
+ if (typeof packages === "object" && packages !== null) {
4088
+ const root = packages[""];
4089
+ if (typeof root === "object" && root !== null && root["name"] === upstreamName) {
4090
+ renamed["packages"] = { ...packages, "": { ...root, name: packageName } };
4091
+ }
4092
+ }
4093
+ return renamed;
4094
+ }
4095
+
4096
+ // src/overlay.ts
4097
+ import {
4098
+ existsSync as existsSync6,
4099
+ readdirSync as readdirSync4,
4100
+ readFileSync as readFileSync6,
4101
+ statSync as statSync2
4102
+ } from "node:fs";
4103
+ import {
4104
+ isAbsolute,
4105
+ join as join6,
4106
+ relative as relative3,
4107
+ resolve
4108
+ } from "node:path";
3453
4109
 
3454
4110
  // src/plan-checks.ts
4111
+ import {
4112
+ existsSync as existsSync5,
4113
+ readdirSync as readdirSync3,
4114
+ readFileSync as readFileSync5,
4115
+ statSync
4116
+ } from "node:fs";
4117
+ import {
4118
+ extname as extname2,
4119
+ join as join5
4120
+ } from "node:path";
3455
4121
  var EJS_SUFFIX = ".ejs";
3456
4122
  var RENDER_SITE_PATTERN = /(?:<%[-=]?|\$\{)\s*render\(\s*(?:'(?<Section>[^']*)'|\{(?<Options>[^}]*)\})/g;
3457
4123
  var SECTION_OPTION_PATTERN = /section\s*:\s*'(?<Section>[^']*)'/;
@@ -3485,7 +4151,7 @@ function loadTemplateInventory(templatesDir = defaultTemplatesDir()) {
3485
4151
  continue;
3486
4152
  }
3487
4153
  const withoutSuffix = relativePath.slice(0, -EJS_SUFFIX.length);
3488
- const body = readFileSync3(join2(templatesDir, relativePath), "utf-8");
4154
+ const body = readFileSync5(join5(templatesDir, relativePath), "utf-8");
3489
4155
  if (isPartialTemplatePath(relativePath)) {
3490
4156
  partials.push(parsePartialPath(relativePath));
3491
4157
  } else {
@@ -3538,7 +4204,7 @@ function parsePartialPath(relativePath) {
3538
4204
  };
3539
4205
  }
3540
4206
  function defaultTemplatesDir() {
3541
- return join2(getScriptDir(), "..", "templates", "default");
4207
+ return join5(getScriptDir(), "..", "templates", "default");
3542
4208
  }
3543
4209
  function getRenderBase(templatePath) {
3544
4210
  if (!isPartialTemplatePath(templatePath)) {
@@ -3548,14 +4214,14 @@ function getRenderBase(templatePath) {
3548
4214
  return isPartialTemplatePath(basePath) ? getRenderBase(basePath) : templatePath;
3549
4215
  }
3550
4216
  function walkTemplates(templatesDir, relativeDir) {
3551
- const absoluteDir = join2(templatesDir, relativeDir);
3552
- if (!existsSync3(absoluteDir)) {
4217
+ const absoluteDir = join5(templatesDir, relativeDir);
4218
+ if (!existsSync5(absoluteDir)) {
3553
4219
  return [];
3554
4220
  }
3555
4221
  const found = [];
3556
- for (const entry of readdirSync(absoluteDir)) {
4222
+ for (const entry of readdirSync3(absoluteDir)) {
3557
4223
  const relativePath = relativeDir === "" ? entry : `${relativeDir}/${entry}`;
3558
- if (statSync(join2(templatesDir, relativePath)).isDirectory()) {
4224
+ if (statSync(join5(templatesDir, relativePath)).isDirectory()) {
3559
4225
  found.push(...walkTemplates(templatesDir, relativePath));
3560
4226
  } else {
3561
4227
  found.push(relativePath);
@@ -3572,11 +4238,11 @@ var MANIFEST_KEYS = ["badges", "files", "packages", "partials"];
3572
4238
  var PACKAGE_NAME_PATTERN = /^(?:@[a-z0-9-~][a-z0-9-._~]*\/)?[a-z0-9-~][a-z0-9-._~]*$/;
3573
4239
  function loadOverlay(dir, builtIn = loadTemplateInventory()) {
3574
4240
  const absoluteDir = resolve(dir);
3575
- if (!existsSync4(absoluteDir) || !statSync2(absoluteDir).isDirectory()) {
4241
+ if (!existsSync6(absoluteDir) || !statSync2(absoluteDir).isDirectory()) {
3576
4242
  throw new Error(`Custom template directory not found: ${absoluteDir}`);
3577
4243
  }
3578
- const manifestPath = join3(absoluteDir, OVERLAY_MANIFEST_FILE_NAME);
3579
- if (!existsSync4(manifestPath)) {
4244
+ const manifestPath = join6(absoluteDir, OVERLAY_MANIFEST_FILE_NAME);
4245
+ if (!existsSync6(manifestPath)) {
3580
4246
  throw new Error(`Custom template directory has no ${OVERLAY_MANIFEST_FILE_NAME}: ${absoluteDir}`);
3581
4247
  }
3582
4248
  const manifest = readManifest(manifestPath);
@@ -3589,7 +4255,7 @@ ${problems.map((problem) => ` - ${problem}`).join("\n")}`);
3589
4255
  return overlay;
3590
4256
  }
3591
4257
  function toRecordedOverlayPath(overlayDir, projectDir) {
3592
- const relativePath = relative(projectDir, overlayDir);
4258
+ const relativePath = relative3(projectDir, overlayDir);
3593
4259
  return isAbsolute(relativePath) ? relativePath : relativePath.replaceAll("\\", "/");
3594
4260
  }
3595
4261
  function findManifestProblems(overlay, own, builtIn) {
@@ -3688,7 +4354,7 @@ function listStrayFiles(dir, own) {
3688
4354
  function readManifest(manifestPath) {
3689
4355
  let parsed;
3690
4356
  try {
3691
- parsed = JSON.parse(readFileSync4(manifestPath, "utf-8"));
4357
+ parsed = JSON.parse(readFileSync6(manifestPath, "utf-8"));
3692
4358
  } catch {
3693
4359
  throw new Error(`${manifestPath} is not valid JSON.`);
3694
4360
  }
@@ -3717,9 +4383,9 @@ function readManifest(manifestPath) {
3717
4383
  }
3718
4384
  function walkFiles(root, relativeDir) {
3719
4385
  const found = [];
3720
- for (const entry of readdirSync2(join3(root, relativeDir))) {
4386
+ for (const entry of readdirSync4(join6(root, relativeDir))) {
3721
4387
  const relativePath = relativeDir === "" ? entry : `${relativeDir}/${entry}`;
3722
- if (statSync2(join3(root, relativePath)).isDirectory()) {
4388
+ if (statSync2(join6(root, relativePath)).isDirectory()) {
3723
4389
  found.push(...walkFiles(root, relativePath));
3724
4390
  } else {
3725
4391
  found.push(relativePath);
@@ -3731,10 +4397,10 @@ function walkFiles(root, relativeDir) {
3731
4397
  // src/project-formatter.ts
3732
4398
  import { spawnSync } from "node:child_process";
3733
4399
  import {
3734
- existsSync as existsSync5,
3735
- readFileSync as readFileSync5
4400
+ existsSync as existsSync7,
4401
+ readFileSync as readFileSync7
3736
4402
  } from "node:fs";
3737
- import { join as join4 } from "node:path";
4403
+ import { join as join7 } from "node:path";
3738
4404
  import process2 from "node:process";
3739
4405
  var FORMATTER_COMMANDS = {
3740
4406
  biome: {
@@ -3769,14 +4435,14 @@ function createProjectFormatter(targetDir, formatter) {
3769
4435
  };
3770
4436
  }
3771
4437
  function resolveBin(targetDir, packageName) {
3772
- const packageDir = join4(targetDir, "node_modules", packageName);
3773
- const packageJsonPath = join4(packageDir, "package.json");
3774
- if (!existsSync5(packageJsonPath)) {
4438
+ const packageDir = join7(targetDir, "node_modules", packageName);
4439
+ const packageJsonPath = join7(packageDir, "package.json");
4440
+ if (!existsSync7(packageJsonPath)) {
3775
4441
  return null;
3776
4442
  }
3777
- const { bin } = JSON.parse(readFileSync5(packageJsonPath, "utf-8"));
4443
+ const { bin } = JSON.parse(readFileSync7(packageJsonPath, "utf-8"));
3778
4444
  const relativeBin = typeof bin === "string" ? bin : Object.values(bin ?? {})[0];
3779
- return relativeBin === void 0 ? null : join4(packageDir, relativeBin);
4445
+ return relativeBin === void 0 ? null : join7(packageDir, relativeBin);
3780
4446
  }
3781
4447
  function runCli(binPath, targetDir, args, input) {
3782
4448
  const result = spawnSync(process2.execPath, [binPath, ...args], { cwd: targetDir, encoding: "utf-8", input });
@@ -3786,7 +4452,22 @@ function runCli(binPath, targetDir, args, input) {
3786
4452
  // src/main.ts
3787
4453
  var ARGV_OFFSET = 2;
3788
4454
  var JSON_INDENT_SPACES4 = 2;
4455
+ var SHORT_SHA_LENGTH = 7;
3789
4456
  var SCRIPT_MODE = 493;
4457
+ function applyPresetFlags(answers, cliArgs, hasOverlay) {
4458
+ if (!isOfficialSamplePreset(answers.preset)) {
4459
+ if (cliArgs.latest) {
4460
+ exitWithUsageError(`--latest picks which upstream tree preset=official-sample copies, and the preset is ${answers.preset}.
4461
+ Drop --latest, or pass --preset=official-sample.`);
4462
+ }
4463
+ return answers;
4464
+ }
4465
+ if (hasOverlay) {
4466
+ exitWithUsageError(`--customTemplate layers over the built-in templates, and preset=official-sample renders none: it copies obsidianmd/obsidian-sample-plugin as it is.
4467
+ Drop --customTemplate, or choose another preset.`);
4468
+ }
4469
+ return { ...answers, ...OFFICIAL_SAMPLE_PINNED_ANSWERS };
4470
+ }
3790
4471
  function assertManifestAnswersAreListable(answers) {
3791
4472
  const problems = findUnlistableManifestAnswers(answers);
3792
4473
  if (problems.length === 0) {
@@ -3802,7 +4483,7 @@ function buildSavedConfig(newConfig, answers, overlay, targetDir) {
3802
4483
  async function checkForUpdates(currentVersion) {
3803
4484
  const latestVer = await fetchLatestVersion("@mnaoumov/create-obsidian-plugin");
3804
4485
  if (latestVer !== null && compare(currentVersion, latestVer) < 0) {
3805
- log4.warn(`Your version is outdated. Latest: ${latestVer}. Update with:
4486
+ log5.warn(`Your version is outdated. Latest: ${latestVer}. Update with:
3806
4487
  npm install -g @mnaoumov/create-obsidian-plugin`);
3807
4488
  }
3808
4489
  }
@@ -3810,8 +4491,8 @@ async function detectMode(cliArgs) {
3810
4491
  if (cliArgs.mode) {
3811
4492
  return cliArgs.mode;
3812
4493
  }
3813
- const configPath = join5(process.cwd(), CONFIG_FILE_NAME);
3814
- if (existsSync6(configPath)) {
4494
+ const configPath = join8(process.cwd(), CONFIG_FILE_NAME);
4495
+ if (existsSync8(configPath)) {
3815
4496
  if (cliArgs.useDefaults) {
3816
4497
  exitWithUsageError(`Existing project detected (${CONFIG_FILE_NAME}), and --yes cannot ask whether to update it.
3817
4498
  Pass --mode=update to update it, or --mode=create to scaffold a new plugin beside it.`);
@@ -3830,7 +4511,7 @@ async function ensurePluginIdIsUnlisted(answers, useDefaults) {
3830
4511
  const listedIds = await fetchCommunityPluginIds();
3831
4512
  if (listedIds === null) {
3832
4513
  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.`);
4514
+ 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
4515
  return answers;
3835
4516
  }
3836
4517
  const collision = validatePluginIdIsUnlisted(answers.pluginId, listedIds);
@@ -3843,7 +4524,7 @@ async function ensurePluginIdIsUnlisted(answers, useDefaults) {
3843
4524
  exitWithUsageError(`${collision}.
3844
4525
  Pass --pluginId=<value> to choose another.`);
3845
4526
  }
3846
- log4.warn(collision);
4527
+ log5.warn(collision);
3847
4528
  const choice = await select2({
3848
4529
  initialValue: "reenter",
3849
4530
  message: `What should happen to "${answers.pluginId}"?`,
@@ -3901,6 +4582,10 @@ function exitWithUsageError(message) {
3901
4582
  `);
3902
4583
  process.exit(1);
3903
4584
  }
4585
+ function hasPrepareScript(targetDir) {
4586
+ const packageJson = JSON.parse(readFileSync8(join8(targetDir, "package.json"), "utf-8"));
4587
+ return Object.hasOwn(packageJson.scripts ?? {}, "prepare");
4588
+ }
3904
4589
  function loadOverlayOrExit(dir, hint = "") {
3905
4590
  try {
3906
4591
  return loadOverlay(dir);
@@ -3909,8 +4594,8 @@ function loadOverlayOrExit(dir, hint = "") {
3909
4594
  }
3910
4595
  }
3911
4596
  async function main() {
3912
- const packageJsonPath = join5(getScriptDir(), "..", "package.json");
3913
- const packageJson = JSON.parse(readFileSync6(packageJsonPath, "utf-8"));
4597
+ const packageJsonPath = join8(getScriptDir(), "..", "package.json");
4598
+ const packageJson = JSON.parse(readFileSync8(packageJsonPath, "utf-8"));
3914
4599
  const currentVersion = packageJson.version ?? "0.0.0";
3915
4600
  const m = "\x1B[38;5;135m";
3916
4601
  const r = "\x1B[0m";
@@ -3965,16 +4650,16 @@ async function offerAnswersExport(answers, customTemplate) {
3965
4650
  let choice = await ask();
3966
4651
  while (choice !== "generate") {
3967
4652
  if (choice === "script") {
3968
- const scriptPath = join5(process.cwd(), scriptName);
4653
+ const scriptPath = join8(process.cwd(), scriptName);
3969
4654
  writeFileSync2(scriptPath, formatCreateScript(answers, shell, customTemplate));
3970
4655
  if (shell === "sh") {
3971
4656
  chmodSync(scriptPath, SCRIPT_MODE);
3972
4657
  }
3973
- log4.success(`Wrote ${scriptName}`);
4658
+ log5.success(`Wrote ${scriptName}`);
3974
4659
  note(formatCreateCommand(answers, shell, customTemplate), "Non-interactive command");
3975
4660
  } else {
3976
- writeFileSync2(join5(process.cwd(), answersFileName), formatAnswersJson(answers));
3977
- log4.success(`Wrote ${answersFileName}`);
4661
+ writeFileSync2(join8(process.cwd(), answersFileName), formatAnswersJson(answers));
4662
+ log5.success(`Wrote ${answersFileName}`);
3978
4663
  const overlayFlag = customTemplate ? ` --customTemplate=${customTemplate}` : "";
3979
4664
  note(`npm create @mnaoumov/obsidian-plugin -- --yes --mode=create --answersFile=${answersFileName}${overlayFlag}`, "Non-interactive command");
3980
4665
  }
@@ -3991,18 +4676,41 @@ async function resolveExternalVersions(answers, overlay) {
3991
4676
  s.stop("Versions resolved.");
3992
4677
  return { minAppVersion, resolvedVersions };
3993
4678
  }
4679
+ async function resolveOfficialSampleSnapshot(latest) {
4680
+ const vendored = loadOfficialSampleSnapshot();
4681
+ if (!latest) {
4682
+ return vendored;
4683
+ }
4684
+ const upstream = readUpstream(getUpstreamsPath(), OFFICIAL_SAMPLE_UPSTREAM_NAME);
4685
+ const s = spinner();
4686
+ s.start(`Fetching ${upstream.repo}@${upstream.ref}...`);
4687
+ try {
4688
+ const snapshot = await fetchUpstreamSnapshot(upstream.repo, upstream.ref);
4689
+ s.stop(`Fetched ${upstream.repo} at ${snapshot.commit.slice(0, SHORT_SHA_LENGTH)}.`);
4690
+ return snapshot;
4691
+ } catch (error) {
4692
+ s.stop(`Could not fetch ${upstream.repo}.`);
4693
+ log5.warn(`${error instanceof Error ? error.message : String(error)}
4694
+ Using the snapshot this release vendored, ${vendored.commit.slice(0, SHORT_SHA_LENGTH)}.`);
4695
+ return vendored;
4696
+ }
4697
+ }
3994
4698
  async function runCreate(currentVersion, cliArgs) {
3995
4699
  const { answers: suppliedAnswers, customTemplate, useDefaults } = cliArgs;
3996
4700
  const overlay = customTemplate ? loadOverlayOrExit(resolvePath(customTemplate)) : null;
3997
- const answers = await ensurePluginIdIsUnlisted(
3998
- assertManifestAnswersAreListable(useDefaults ? getDefaultAnswers(suppliedAnswers) : await promptAnswers(suppliedAnswers)),
3999
- useDefaults
4701
+ const answers = applyPresetFlags(
4702
+ await ensurePluginIdIsUnlisted(
4703
+ assertManifestAnswersAreListable(useDefaults ? getDefaultAnswers(suppliedAnswers) : await promptAnswers(suppliedAnswers)),
4704
+ useDefaults
4705
+ ),
4706
+ cliArgs,
4707
+ overlay !== null
4000
4708
  );
4001
4709
  if (!useDefaults) {
4002
4710
  await offerAnswersExport(answers, customTemplate);
4003
4711
  }
4004
- const targetDir = join5(process.cwd(), `obsidian-${answers.pluginId}`);
4005
- if (existsSync6(targetDir) && !cliArgs.force) {
4712
+ const targetDir = join8(process.cwd(), `obsidian-${answers.pluginId}`);
4713
+ if (existsSync8(targetDir) && !cliArgs.force) {
4006
4714
  if (useDefaults) {
4007
4715
  exitWithUsageError(`Directory obsidian-${answers.pluginId} already exists, and --yes cannot ask whether to scaffold into it.
4008
4716
  Pass --force to scaffold into it anyway.`);
@@ -4017,19 +4725,28 @@ Pass --force to scaffold into it anyway.`);
4017
4725
  process.exit(0);
4018
4726
  }
4019
4727
  }
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);
4728
+ let newConfig;
4729
+ if (isOfficialSamplePreset(answers.preset)) {
4730
+ const snapshot = await resolveOfficialSampleSnapshot(cliArgs.latest);
4731
+ const s = spinner();
4732
+ s.start("Copying the official sample plugin...");
4733
+ newConfig = copyOfficialSample(answers, targetDir, currentVersion, null, snapshot);
4734
+ s.stop(`Copied obsidianmd/obsidian-sample-plugin at ${snapshot.commit.slice(0, SHORT_SHA_LENGTH)}.`);
4735
+ } else {
4736
+ const { minAppVersion, resolvedVersions } = await resolveExternalVersions(answers, overlay);
4737
+ const s = spinner();
4738
+ s.start("Scaffolding plugin...");
4739
+ newConfig = copyTemplates(answers, targetDir, currentVersion, null, resolvedVersions, minAppVersion, overlay);
4740
+ s.stop("Plugin scaffolded.");
4741
+ }
4742
+ const configPath = join8(targetDir, CONFIG_FILE_NAME);
4025
4743
  const configWithAnswers = buildSavedConfig(newConfig, answers, overlay, targetDir);
4026
4744
  writeFileSync2(configPath, `${JSON.stringify(configWithAnswers, null, JSON_INDENT_SPACES4)}
4027
4745
  `);
4028
- s.stop("Plugin scaffolded.");
4029
4746
  const isFormatted = useDefaults ? false : await runPostScaffold(targetDir, answers);
4030
4747
  const pm = answers.packageManager;
4031
4748
  const dirName = `obsidian-${answers.pluginId}`;
4032
- const needsInstall = !existsSync6(join5(targetDir, "node_modules"));
4749
+ const needsInstall = !existsSync8(join8(targetDir, "node_modules"));
4033
4750
  const needsFormat = needsInitialFormat(answers.formatter) && !isFormatted;
4034
4751
  const steps = [
4035
4752
  ...needsInstall ? [getInstallCommand(pm)] : [],
@@ -4047,8 +4764,8 @@ async function runInitialFormat(targetDir, answers, isInstalled) {
4047
4764
  s.start("Formatting...");
4048
4765
  try {
4049
4766
  await execAsync(getRunCommand(answers.packageManager, "format"), targetDir);
4050
- const configPath = join5(targetDir, CONFIG_FILE_NAME);
4051
- const config = JSON.parse(readFileSync6(configPath, "utf-8"));
4767
+ const configPath = join8(targetDir, CONFIG_FILE_NAME);
4768
+ const config = JSON.parse(readFileSync8(configPath, "utf-8"));
4052
4769
  writeFileSync2(configPath, `${JSON.stringify(recordHashesOnDisk(targetDir, config), null, JSON_INDENT_SPACES4)}
4053
4770
  `);
4054
4771
  s.stop("Formatted.");
@@ -4077,7 +4794,7 @@ async function runPostScaffold(targetDir, answers) {
4077
4794
  } catch (error) {
4078
4795
  s.stop(`Failed to install dependencies. Run \`${installCmd}\` manually.`);
4079
4796
  if (error instanceof Error && "stderr" in error) {
4080
- log4.error(String(error.stderr));
4797
+ log5.error(String(error.stderr));
4081
4798
  }
4082
4799
  }
4083
4800
  }
@@ -4092,11 +4809,17 @@ async function runPostScaffold(targetDir, answers) {
4092
4809
  s.start("Initializing git repository...");
4093
4810
  try {
4094
4811
  await execAsync(`git init -b ${answers.defaultBranch}`, targetDir);
4812
+ if (isInstalled && hasPrepareScript(targetDir)) {
4813
+ await execAsync(getRunCommand(pm, "prepare"), targetDir);
4814
+ }
4095
4815
  await execAsync("git add -A", targetDir);
4096
- await execAsync('git commit -m "Initial commit from create-obsidian-plugin"', targetDir);
4816
+ await execAsync(`git commit -m "${INITIAL_COMMIT_MESSAGE}"`, targetDir);
4097
4817
  s.stop("Git repository initialized with initial commit.");
4098
- } catch {
4818
+ } catch (error) {
4099
4819
  s.stop("Failed to initialize git. Run `git init` manually.");
4820
+ if (error instanceof Error && "stderr" in error) {
4821
+ log5.error(String(error.stderr));
4822
+ }
4100
4823
  }
4101
4824
  }
4102
4825
  const shouldCreateGitHubRepo = await confirm({
@@ -4121,10 +4844,10 @@ async function runUpdate(currentVersion, cliArgs) {
4121
4844
  const targetDir = process.cwd();
4122
4845
  const existingConfig = loadConfig(targetDir);
4123
4846
  if (!existingConfig) {
4124
- log4.error("No config file found. Cannot update.");
4847
+ log5.error("No config file found. Cannot update.");
4125
4848
  process.exit(1);
4126
4849
  }
4127
- log4.info(`Current project was generated with v${existingConfig.generatorVersion}`);
4850
+ log5.info(`Current project was generated with v${existingConfig.generatorVersion}`);
4128
4851
  let overlay = null;
4129
4852
  if (customTemplate !== void 0) {
4130
4853
  overlay = customTemplate ? loadOverlayOrExit(resolvePath(customTemplate)) : null;
@@ -4134,21 +4857,21 @@ async function runUpdate(currentVersion, cliArgs) {
4134
4857
  `
4135
4858
  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
4859
  );
4137
- log4.info(`Applying the custom template recorded for this project: ${existingConfig.customTemplate}`);
4860
+ log5.info(`Applying the custom template recorded for this project: ${existingConfig.customTemplate}`);
4138
4861
  }
4139
- const configPath = join5(targetDir, CONFIG_FILE_NAME);
4140
- const savedConfig = JSON.parse(readFileSync6(configPath, "utf-8"));
4862
+ const configPath = join8(targetDir, CONFIG_FILE_NAME);
4863
+ const savedConfig = JSON.parse(readFileSync8(configPath, "utf-8"));
4141
4864
  let answers;
4142
4865
  if (savedConfig.answers) {
4143
4866
  const saved = { ...savedConfig.answers, ...suppliedAnswers };
4144
- log4.info("Using saved answers from previous generation.");
4867
+ log5.info("Using saved answers from previous generation.");
4145
4868
  const shouldRePrompt = useDefaults ? false : await confirm({
4146
4869
  initialValue: false,
4147
4870
  message: "Would you like to change any settings?"
4148
4871
  });
4149
4872
  assertNotCancelled(shouldRePrompt);
4150
4873
  if (shouldRePrompt) {
4151
- answers = await promptAnswers(saved);
4874
+ answers = await promptAnswers(saved, suppliedAnswers);
4152
4875
  } else {
4153
4876
  answers = saved;
4154
4877
  }
@@ -4157,17 +4880,29 @@ This project records it in ${CONFIG_FILE_NAME}. Pass --customTemplate=<dir> to p
4157
4880
  exitWithUsageError(`${CONFIG_FILE_NAME} records no answers, so --yes has none to reuse.
4158
4881
  Run without --yes to answer them again.`);
4159
4882
  }
4160
- log4.warn("No saved answers found. Please provide the settings again.");
4883
+ log5.warn("No saved answers found. Please provide the settings again.");
4161
4884
  answers = await promptAnswers(suppliedAnswers);
4162
4885
  }
4163
4886
  const savedPluginId = savedConfig.answers?.pluginId;
4164
4887
  if (savedPluginId !== void 0 && answers.pluginId !== savedPluginId) {
4165
4888
  answers = await ensurePluginIdIsUnlisted(answers, useDefaults);
4166
4889
  }
4890
+ answers = applyPresetFlags(answers, cliArgs, overlay !== null);
4891
+ if (isOfficialSamplePreset(answers.preset)) {
4892
+ const snapshot = await resolveOfficialSampleSnapshot(cliArgs.latest);
4893
+ const s2 = spinner();
4894
+ s2.start("Updating project files...");
4895
+ const newConfig2 = copyOfficialSample(answers, targetDir, currentVersion, existingConfig, snapshot);
4896
+ writeFileSync2(configPath, `${JSON.stringify({ ...newConfig2, answers }, null, JSON_INDENT_SPACES4)}
4897
+ `);
4898
+ s2.stop(`Update complete: obsidianmd/obsidian-sample-plugin at ${snapshot.commit.slice(0, SHORT_SHA_LENGTH)}.`);
4899
+ outro("Project updated successfully!");
4900
+ return;
4901
+ }
4167
4902
  const { minAppVersion, resolvedVersions } = await resolveExternalVersions(answers, overlay);
4168
4903
  const projectFormatter = createProjectFormatter(targetDir, answers.formatter);
4169
4904
  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.`);
4905
+ 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
4906
  }
4172
4907
  const s = spinner();
4173
4908
  s.start("Updating project files...");