@mnaoumov/create-obsidian-plugin 1.3.0 → 1.4.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.
package/CHANGELOG.md ADDED
@@ -0,0 +1,137 @@
1
+ # Changelog
2
+
3
+ All notable changes to this project will be documented in this file.
4
+
5
+ ## 1.4.0 (2026-11-01)
6
+
7
+ ### Features
8
+
9
+ - The `official-sample` preset writes the `LICENSE` copyright line as `Copyright (C) <year> by <author>`, keeping upstream's 0BSD text.
10
+ - A See also section compares similar scaffolders, in the README and on the docs site.
11
+ - `CHANGELOG.md`, back-filled from the tags, linked from the README and the docs site.
12
+ - Tool names are marked as code in all Markdown prose, with a test that catches a bare one.
13
+
14
+ ### Removed
15
+
16
+ - The `enhanced` preset alias: `--preset=enhanced` now fails validation like any unknown value.
17
+ - Every migration of an older `.create-obsidian-plugin.json` answer shape (`framework`, `cssMode`, `buildSystem`, `gitHubFunding`, a missing `defaultBranch` or `coverageBadge`, a stored `pluginShortName`).
18
+
19
+ [Full diff](https://github.com/mnaoumov/create-obsidian-plugin/compare/1.3.0...1.4.0)
20
+ ## 1.3.0 (2026-11-01)
21
+
22
+ ### Features
23
+
24
+ - **cli:** quote the -- separator in --help and the answers-file hint
25
+
26
+ [Full diff](https://github.com/mnaoumov/create-obsidian-plugin/compare/1.2.0...1.3.0)
27
+
28
+ ## 1.2.0 (2026-11-01)
29
+
30
+ ### Features
31
+
32
+ - **template:** add a Similar plugins section to the generated README
33
+ - **template:** let a parenthesized folder group templates without entering their path
34
+ - **issue-templates:** give the bug form field ids that bug-report links prefill
35
+ - tell AI agents how to file an issue when they skip the forms
36
+ - scaffold the Report a bug command whenever issue forms are chosen
37
+
38
+ ### Fixes
39
+
40
+ - **deps:** float brace-expansion to 5.0.12 and fast-uri to 3.1.9 past their advisories
41
+ - **versions:** drop the smol-toml advisory override now that typescript-dev-toolkit 3.7.3 pins 1.9.1
42
+ - **templates:** select .obsidian-lib in the framework stylesheets
43
+ - **templates:** show the plugin name as code in the demo sample view
44
+ - **gate:** report a missing package manager as could not run, not a failed install
45
+ - **bundler:** leave esbuild to obsidian-dev-toolkit on the framework presets
46
+ - **lint:** discover root ESLint config for scripts
47
+ - **lint:** reconcile unused binding checks with ESLint 10
48
+ - **templates:** format Solid readonly configuration comment
49
+ - override vulnerable development KaTeX dependency
50
+ - **demo:** avoid keyword identifier in number setting callback
51
+ - **demo:** stop scaffolding the gitignored scratch note
52
+ - **versions:** override re2js to ^2.9.1 in scaffolded projects for GHSA-gg6h-894w-4m9c
53
+ - **spell-checker:** know "toolkits" in the emitted cspell.json
54
+ - **versions:** hold toolkit-declared packages in the toolkit's range
55
+
56
+ [Full diff](https://github.com/mnaoumov/create-obsidian-plugin/compare/1.1.0...1.2.0)
57
+
58
+ ## 1.1.0 (2026-10-21)
59
+
60
+ ### Features
61
+
62
+ - scaffold onto @mnaoumov/obsidian-lib and the @mnaoumov toolkits
63
+ - **templates:** take commitlint and nano-staged configs from typescript-dev-toolkit
64
+ - **preset:** keep preset "enhanced" working as a deprecated alias of all-in-one
65
+ - **preset:** label the preset All-in-one Framework and lead its hint with the helper library
66
+ - **preset:** add the Official sample plugin preset
67
+ - **docs-showcase:** extract, wrap and type-check the developer docs' code blocks
68
+ - **preset:** add the Developer docs showcase preset
69
+ - **upstream-sync:** watch every upstream and open one update PR per change
70
+ - **docs-showcase:** link each snippet's docs page from what its command shows
71
+ - **templates:** link Discussions from the issue chooser
72
+ - **formatter:** run prettier and biome through the toolkit runners
73
+ - **test-runner:** run jest through the toolkits on the framework presets
74
+ - **e2e:** run wdio-obsidian and obsidian-test through obsidian-dev-toolkit
75
+ - **github-actions:** call obsidian-dev-toolkit's reusable workflows
76
+ - **bundler:** build every bundler through obsidian-dev-toolkit's adapters
77
+ - **scaffold:** emit .nvmrc so CI runs the project's Node, not the latest LTS
78
+ - **docs-showcase:** recognize a code-examples-only LICENSE and refuse unknown ones
79
+
80
+ ### Fixes
81
+
82
+ - **demo-vault:** import configureCommunityPlugin from @mnaoumov/obsidian-lib
83
+ - **dprint:** keep JSX attributes double-quoted
84
+ - **versions:** override smol-toml to clear GHSA-r4xh-jqrq-34v2
85
+ - **verify-tarball:** read npm 12's keyed npm pack --json output as well as the array
86
+ - **templates:** emit nano-staged config patterns in sorted order
87
+ - **templates:** require CodeScript Toolkit 13.8.0 for the demo-vault injection
88
+ - **templates:** drop the preact view's import-x/no-deprecated directives for preact 11
89
+ - **templates:** remove the three directives the previous commit left staged out
90
+ - **cli:** let render:case and gate:case read a deprecated answer value as the CLI does
91
+ - **update:** ask every question again when the user chooses to change settings
92
+ - **templates:** pass the framework scaffolds' own lint, format and audit gate
93
+ - **verify:** read the pins step's checks from under the pins key
94
+ - **versions:** pin @codemirror/state and view to obsidian 1.14.4's peers
95
+ - **prompts:** offer "Keep current tooling" on update and make "Use recommended defaults" apply them
96
+ - **cli-args:** look the mode up instead of asserting a string to the Mode enum
97
+ - **templates:** clear what the toolkit runners and verify:projects found
98
+ - **templates:** keep biome and dprint agreeing on the framework configs
99
+ - **standalone:** clear the gate failures the wdio install used to hide
100
+ - **templates:** reach the CSS module through its class names so vite keeps it
101
+ - **test:** declare sweepCases' void return so tsc accepts the generator
102
+ - **templates:** ignore coverage/ in git and cspell, spell-check staged dotfiles
103
+ - **scaffold:** install the git hooks after git init and make the first commit conventional
104
+ - **demo-vault:** stop linking to the gitignored scratch note
105
+ - **cspell:** know the word the template's word list adds for the demo vault .gitignore
106
+ - **plugin-drift:** leave generator-scaffolded plugins out of the real-plugin set
107
+ - **versions:** read the smol-toml pin off typescript-dev-toolkit's markdownlint-cli2
108
+ - **templates:** mark the plugin name as code in the README and demo-vault prose
109
+
110
+ [Full diff](https://github.com/mnaoumov/create-obsidian-plugin/compare/1.0.2...1.1.0)
111
+
112
+ ## 1.0.2 (2026-10-10)
113
+
114
+ ### Features
115
+
116
+ - verify obsidian-dev-utils source links against its checkout
117
+
118
+ ### Fixes
119
+
120
+ - **verify-tarball:** pack with --ignore-scripts so HUSKY=0 output cannot break the JSON
121
+ - **templates:** point dead upstream links at their current homes
122
+
123
+ [Full diff](https://github.com/mnaoumov/create-obsidian-plugin/compare/1.0.1...1.0.2)
124
+
125
+ ## 1.0.1 (2026-10-07)
126
+
127
+ ### Other
128
+
129
+ - publish to npm from GitHub Actions with trusted publishing
130
+
131
+ [Full diff](https://github.com/mnaoumov/create-obsidian-plugin/compare/1.0.0...1.0.1)
132
+
133
+ ## 1.0.0 (2026-10-07)
134
+
135
+ Initial release.
136
+
137
+ [Commits](https://github.com/mnaoumov/create-obsidian-plugin/commits/1.0.0)
package/README.md CHANGED
@@ -12,7 +12,7 @@ A scaffolding CLI that generates [Obsidian](https://obsidian.md/) plugin project
12
12
  npm create @mnaoumov/obsidian-plugin
13
13
  ```
14
14
 
15
- This walks you through an interactive wizard, then scaffolds the project into a new `obsidian-<plugin id>` folder. pnpm, yarn and bun work too: see [Getting started](https://mnaoumov.dev/create-obsidian-plugin/guides/getting-started/).
15
+ This walks you through an interactive wizard, then scaffolds the project into a new `obsidian-<plugin id>` folder. `pnpm`, `yarn` and `bun` work too: see [Getting started](https://mnaoumov.dev/create-obsidian-plugin/guides/getting-started/).
16
16
 
17
17
  Run the same command inside a project it created to [update it](https://mnaoumov.dev/create-obsidian-plugin/guides/updating/) to the latest templates, keeping the files you changed.
18
18
 
@@ -24,10 +24,31 @@ Answer every question up front and skip the prompts:
24
24
  npm create @mnaoumov/obsidian-plugin "--" --yes --pluginId=my-tool --packageManager=npm
25
25
  ```
26
26
 
27
- Keep the quotes around `"--"`: in PowerShell a bare `--` is swallowed before npm sees it. See [The -- separator in PowerShell](https://mnaoumov.dev/create-obsidian-plugin/guides/powershell-separator/). Every option is listed in [Command-line options](https://mnaoumov.dev/create-obsidian-plugin/guides/command-line/).
27
+ Keep the quotes around `"--"`: in PowerShell a bare `--` is swallowed before `npm` sees it. See [The -- separator in PowerShell](https://mnaoumov.dev/create-obsidian-plugin/guides/powershell-separator/). Every option is listed in [Command-line options](https://mnaoumov.dev/create-obsidian-plugin/guides/command-line/).
28
28
 
29
29
  [Sample Plugin Extended](https://github.com/mnaoumov/obsidian-sample-plugin-extended) is a plugin generated with this tool.
30
30
 
31
+ ## See also
32
+
33
+ [My other Obsidian resources](https://github.com/mnaoumov/obsidian-resources)
34
+
35
+ | Tool | Features | How `create-obsidian-plugin` differs |
36
+ | --- | --- | --- |
37
+ | [`@aoout/create-obsidian-plugin`](https://www.npmjs.com/package/@aoout/create-obsidian-plugin) | `npm create` wizard, forked from zephraph's `create-obsidian-plugin`; `i18next`; a tag-triggered release workflow; a desktop-only option; `git init` and an optional GitHub repository | Same goal; adds: presets; a choice of bundler, UI framework, linter, formatter and test runner; an update in place that keeps the files you edited; `--yes` and answers export |
38
+ | [`cookiecutter-obsidian-plugin`](https://github.com/serafinovsky/cookiecutter-obsidian-plugin) | A Python `cookiecutter` template; TypeScript, `esbuild`, `eslint`, `prettier`; optional `vitest` and i18n; a release workflow | Same goal; runs on Node.js through `npm create`, with no Python; adds: presets; five bundlers; UI frameworks; an update in place |
39
+ | [`create-obsidian-plugin`](https://www.npmjs.com/package/create-obsidian-plugin) | The `npm init obsidian-plugin` wizard by zephraph; asks for the id and name; a TypeScript plugin whose `dev` and `build` scripts run `obsidian-plugin-cli` | Same goal; adds: presets; a tooling choice in each category; an update in place; `--yes` and answers export |
40
+ | [`create-obsidian-plugin-pnpm`](https://www.npmjs.com/package/create-obsidian-plugin-pnpm) | An `npm create` scaffolder that copies one fixed template; `pnpm`, strict TypeScript, `esbuild`, `eslint`; CI and draft-release workflows; a declarative settings example | Same goal; adds: `npm`, `yarn` and `bun`; presets; a choice of bundler, UI framework, linter, formatter and test runner; an update in place |
41
+ | [`dsebastien/obsidian-plugin-template`](https://github.com/dsebastien/obsidian-plugin-template) | A GitHub template repository; `bun`, strict TypeScript, `tailwindcss` 4, `eslint`, `prettier`, `husky` with `lint-staged`, `commitizen`; CI and release workflows | A generator rather than a template you copy and rename by hand; fills in your plugin's identity from prompts or flags; a choice in each tooling category; an update in place |
42
+ | [`generator-obsidian-plugin`](https://github.com/mnaoumov/generator-obsidian-plugin) (my tool) | A Yeoman generator (`yo obsidian-plugin`); `obsidian-typings`, `eslint`, `cspell`, `dprint`, `obsidian-dev-utils` scripts; `svelte` and `react` examples; `sass` | Supersedes it; needs no global `yo`; adds: presets; a choice in each tooling category; an update in place that keeps the files you edited; `--yes` |
43
+ | [`nolebase/obsidian-plugin-template`](https://github.com/nolebase/obsidian-plugin-template) | A GitHub template repository; TypeScript, `unbuild`, `eslint`, `cspell`, `pnpm`; publishing on release | A generator rather than a template you copy and rename; five bundlers, `unbuild` not among them; UI frameworks; an update in place |
44
+ | [`obsidianmd/obsidian-sample-plugin`](https://github.com/obsidianmd/obsidian-sample-plugin) | Obsidian's official template repository; TypeScript, `esbuild`, `eslint` with `eslint-plugin-obsidianmd`, `npm`; sample code | Extends it: the `official-sample` preset copies it with your id, name, author, description and license holder filled in, and can update it later; the other presets add a choice of tooling |
45
+
46
+ Last searched for similar tools on 2026-11-01.
47
+
48
+ ## Changelog
49
+
50
+ All notable changes to this project will be documented in the [CHANGELOG](./CHANGELOG.md).
51
+
31
52
  ## Contributing
32
53
 
33
54
  Contributions are welcome — see [CONTRIBUTING](./CONTRIBUTING.md) to get set up.
@@ -46,10 +67,6 @@ Open issues through the [issue forms](https://github.com/mnaoumov/create-obsidia
46
67
 
47
68
  Filing from the CLI or the API (`gh issue create --body`, or an AI agent filing for you) skips the form, and `gh issue create --template` cannot load an issue form. In that case, open the matching form in [`.github/ISSUE_TEMPLATE/`](https://github.com/mnaoumov/create-obsidian-plugin/tree/HEAD/.github/ISSUE_TEMPLATE), copy every field as a `### <label>` heading in the form's order, and fill in each one. Always state the version you used and your operating system.
48
69
 
49
- ## My other Obsidian resources
50
-
51
- [My other Obsidian resources](https://github.com/mnaoumov/obsidian-resources)
52
-
53
70
  ## License
54
71
 
55
72
  © [Michael Naumov](https://github.com/mnaoumov/)
package/dist/main.js CHANGED
@@ -5,7 +5,7 @@ import {
5
5
  cancel as cancel3,
6
6
  confirm,
7
7
  intro,
8
- log as log5,
8
+ log as log4,
9
9
  note,
10
10
  outro,
11
11
  select as select2,
@@ -179,7 +179,7 @@ var OFFICIAL_SAMPLE_ANSWER_KEYS = [
179
179
  var OfficialSample = class extends FeatureOption {
180
180
  constructor() {
181
181
  super({
182
- promptHint: "Exactly obsidianmd/obsidian-sample-plugin, with your plugin's id, name, author and description filled in",
182
+ promptHint: "Exactly obsidianmd/obsidian-sample-plugin, with your plugin's id, name, author, description and license holder filled in",
183
183
  promptLabel: "Official sample plugin",
184
184
  settingValue: OFFICIAL_SAMPLE_PRESET
185
185
  });
@@ -2555,26 +2555,8 @@ function getPluginShortName(pluginId) {
2555
2555
  return pluginId.split("-").map((word) => (word[0] ?? "").toUpperCase() + word.slice(1)).join("");
2556
2556
  }
2557
2557
 
2558
- // src/answers/deprecated-answers.ts
2559
- import { log as log2 } from "@clack/prompts";
2560
- var DEPRECATED_ANSWER_VALUES = {
2561
- preset: {
2562
- enhanced: "all-in-one"
2563
- }
2564
- };
2565
- function resolveDeprecatedAnswer(key, value, source) {
2566
- const replacement = DEPRECATED_ANSWER_VALUES[key]?.[value];
2567
- if (replacement === void 0) {
2568
- return value;
2569
- }
2570
- log2.warn(`${key} "${value}" in ${source} is deprecated and was read as "${replacement}". Use "${replacement}" instead.`);
2571
- return replacement;
2572
- }
2573
-
2574
2558
  // src/answers/cli-args.ts
2575
2559
  var COMPUTED_ANSWER_KEYS = ["currentYear"];
2576
- var DERIVED_TEMPLATE_KEYS = ["pluginShortName"];
2577
- var REFUSED_KEYS = [...COMPUTED_ANSWER_KEYS, ...DERIVED_TEMPLATE_KEYS];
2578
2560
  var ANSWERS_FILE_PREFIX = "--answersFile=";
2579
2561
  var CUSTOM_TEMPLATE_PREFIX = "--customTemplate=";
2580
2562
  var MODE_PREFIX = "--mode=";
@@ -2681,7 +2663,7 @@ function parseCliArgs(argv) {
2681
2663
  }
2682
2664
  const [rawKey, rawValue] = splitFlag(argument);
2683
2665
  const key = toAnswerKey(rawKey);
2684
- flagAnswers[key] = resolveAnswer(key, rawValue, `--${key}`);
2666
+ flagAnswers[key] = resolveAnswer(key, rawValue);
2685
2667
  }
2686
2668
  const fileAnswers = answersFilePath === null ? {} : readAnswersFile(answersFilePath);
2687
2669
  const isOfficialSample = isOfficialSamplePreset(flagAnswers.preset ?? fileAnswers.preset);
@@ -2700,13 +2682,12 @@ function parseCliArgs(argv) {
2700
2682
  useDefaults
2701
2683
  };
2702
2684
  }
2703
- function resolveAnswer(key, value, source) {
2704
- const resolved = resolveDeprecatedAnswer(key, value, source);
2705
- assertValidAnswer(key, resolved);
2706
- return resolved;
2685
+ function resolveAnswer(key, value) {
2686
+ assertValidAnswer(key, value);
2687
+ return value;
2707
2688
  }
2708
2689
  function toAnswerKey(key) {
2709
- if (REFUSED_KEYS.includes(key)) {
2690
+ if (COMPUTED_ANSWER_KEYS.includes(key)) {
2710
2691
  throw new Error(`${key} is computed by the generator, not answered, so it cannot be set.`);
2711
2692
  }
2712
2693
  const answerable = getAnswerableKeys();
@@ -2761,14 +2742,14 @@ function readAnswersFile(path) {
2761
2742
  const source = typeof wrapped === "object" && wrapped !== null ? wrapped : record;
2762
2743
  const answers = {};
2763
2744
  for (const [rawKey, value] of Object.entries(source)) {
2764
- if (REFUSED_KEYS.includes(rawKey)) {
2745
+ if (COMPUTED_ANSWER_KEYS.includes(rawKey)) {
2765
2746
  continue;
2766
2747
  }
2767
2748
  if (typeof value !== "string") {
2768
2749
  throw new Error(`${rawKey} in ${path} should be a string, got ${typeof value}.`);
2769
2750
  }
2770
2751
  const key = toAnswerKey(rawKey);
2771
- answers[key] = resolveAnswer(key, value, path);
2752
+ answers[key] = resolveAnswer(key, value);
2772
2753
  }
2773
2754
  return answers;
2774
2755
  }
@@ -2887,7 +2868,7 @@ function validatePluginIdIsUnlisted(pluginId, listedIds) {
2887
2868
  import { join as join5 } from "node:path";
2888
2869
 
2889
2870
  // src/templates.ts
2890
- import { log as log4 } from "@clack/prompts";
2871
+ import { log as log3 } from "@clack/prompts";
2891
2872
  import ejs from "ejs";
2892
2873
  import { createHash } from "node:crypto";
2893
2874
  import {
@@ -3169,7 +3150,7 @@ function walkFiles(root, relativeDir) {
3169
3150
  }
3170
3151
 
3171
3152
  // src/versions.ts
3172
- import { log as log3 } from "@clack/prompts";
3153
+ import { log as log2 } from "@clack/prompts";
3173
3154
  import {
3174
3155
  maxSatisfying,
3175
3156
  minVersion,
@@ -3472,7 +3453,7 @@ async function resolveVersions(dependencies) {
3472
3453
  }
3473
3454
  resolved.set(packageName, resolution.spec);
3474
3455
  if (resolution.heldBelow !== null) {
3475
- log3.info(`Holding ${packageName} on ${resolution.spec}, the range ${resolution.heldBy ?? ""} declares, rather than the latest ${resolution.heldBelow}.`);
3456
+ log2.info(`Holding ${packageName} on ${resolution.spec}, the range ${resolution.heldBy ?? ""} declares, rather than the latest ${resolution.heldBelow}.`);
3476
3457
  }
3477
3458
  }
3478
3459
  for (const constrainer of CONSTRAINING_PACKAGES) {
@@ -3497,7 +3478,7 @@ async function resolveVersions(dependencies) {
3497
3478
  record(rest[index] ?? "", resolution);
3498
3479
  }
3499
3480
  if (failed.length > 0) {
3500
- log3.warn(`Could not look up the latest version of ${failed.join(", ")}. Falling back to "${FALLBACK_VERSION}".`);
3481
+ log2.warn(`Could not look up the latest version of ${failed.join(", ")}. Falling back to "${FALLBACK_VERSION}".`);
3501
3482
  }
3502
3483
  return resolved;
3503
3484
  }
@@ -3806,10 +3787,7 @@ function loadConfig(dir) {
3806
3787
  if (!existsSync4(configPath)) {
3807
3788
  return null;
3808
3789
  }
3809
- const parsed = JSON.parse(readFileSync3(configPath, "utf-8"));
3810
- const raw = parsed;
3811
- migrateAnswers(raw);
3812
- return parsed;
3790
+ return JSON.parse(readFileSync3(configPath, "utf-8"));
3813
3791
  }
3814
3792
  function pinPresetAnswers(answers) {
3815
3793
  return answers.preset === "demo" ? { ...answers, ...DEMO_PINNED_ANSWERS } : answers;
@@ -3951,25 +3929,25 @@ function importedModule(block) {
3951
3929
  }
3952
3930
  function logUpdateSummary(updated, created, skipped) {
3953
3931
  if (updated.length > 0) {
3954
- log4.success(`Updated ${String(updated.length)} file(s):`);
3932
+ log3.success(`Updated ${String(updated.length)} file(s):`);
3955
3933
  for (const f of updated) {
3956
- log4.info(` ${f}`);
3934
+ log3.info(` ${f}`);
3957
3935
  }
3958
3936
  }
3959
3937
  if (created.length > 0) {
3960
- log4.success(`Created ${String(created.length)} new file(s):`);
3938
+ log3.success(`Created ${String(created.length)} new file(s):`);
3961
3939
  for (const f of created) {
3962
- log4.info(` ${f}`);
3940
+ log3.info(` ${f}`);
3963
3941
  }
3964
3942
  }
3965
3943
  if (skipped.length > 0) {
3966
- log4.warn(`Skipped ${String(skipped.length)} file(s) with local modifications:`);
3944
+ log3.warn(`Skipped ${String(skipped.length)} file(s) with local modifications:`);
3967
3945
  for (const f of skipped) {
3968
- log4.info(` ${f}`);
3946
+ log3.info(` ${f}`);
3969
3947
  }
3970
3948
  }
3971
3949
  if (updated.length === 0 && created.length === 0) {
3972
- log4.info("Everything is already up to date.");
3950
+ log3.info("Everything is already up to date.");
3973
3951
  }
3974
3952
  }
3975
3953
  function matchesRender(currentHash, newHash, projectFormatter, destinationPath, rendered) {
@@ -3982,64 +3960,6 @@ function matchesRender(currentHash, newHash, projectFormatter, destinationPath,
3982
3960
  const formatted = projectFormatter.formatContent(destinationPath, rendered);
3983
3961
  return formatted !== null && sha256(formatted) === currentHash;
3984
3962
  }
3985
- function migrateAnswers(raw) {
3986
- const answers = raw["answers"];
3987
- if (!answers) {
3988
- return;
3989
- }
3990
- if (answers["framework"] && !answers["uiFramework"]) {
3991
- answers["uiFramework"] = answers["framework"];
3992
- delete answers["framework"];
3993
- }
3994
- if (answers["cssMode"] && !answers["styling"]) {
3995
- answers["styling"] = answers["cssMode"];
3996
- delete answers["cssMode"];
3997
- }
3998
- if (answers["buildSystem"] && !answers["bundler"]) {
3999
- answers["bundler"] = answers["buildSystem"];
4000
- delete answers["buildSystem"];
4001
- }
4002
- answers["defaultBranch"] ??= "master";
4003
- migrateFundingAnswers(answers);
4004
- answers["fundingUsername"] ??= answers["authorGitHubName"];
4005
- answers["coverageBadge"] ??= "none";
4006
- delete answers["pluginShortName"];
4007
- for (const [key, value] of Object.entries(answers)) {
4008
- if (typeof value === "string") {
4009
- answers[key] = resolveDeprecatedAnswer(key, value, CONFIG_FILE_NAME);
4010
- }
4011
- }
4012
- }
4013
- function migrateFundingAnswers(answers) {
4014
- if (answers["fundingPlatform"] !== void 0) {
4015
- return;
4016
- }
4017
- delete answers["gitHubFunding"];
4018
- const url = typeof answers["fundingUrl"] === "string" ? answers["fundingUrl"] : "";
4019
- if (!url) {
4020
- answers["fundingPlatform"] = "none";
4021
- answers["fundingUrl"] = "";
4022
- return;
4023
- }
4024
- function stripWww(value) {
4025
- return value.replace("://www.", "://");
4026
- }
4027
- for (const option of FUNDING_PLATFORM_OPTIONS) {
4028
- const prefix = stripWww(option.getUrl({ fundingUrl: "", fundingUsername: "" }));
4029
- const normalizedUrl = stripWww(url);
4030
- if (!prefix || !normalizedUrl.startsWith(prefix)) {
4031
- continue;
4032
- }
4033
- const handle = normalizedUrl.slice(prefix.length).replace(/\/$/, "");
4034
- if (!validateFundingUsername(handle)) {
4035
- answers["fundingPlatform"] = option.settingValue;
4036
- answers["fundingUsername"] = handle;
4037
- answers["fundingUrl"] = "";
4038
- return;
4039
- }
4040
- }
4041
- answers["fundingPlatform"] = "custom";
4042
- }
4043
3963
  function sha256(content) {
4044
3964
  return createHash("sha256").update(content).digest("hex");
4045
3965
  }
@@ -4167,6 +4087,10 @@ function applyOfficialSampleIdentity(files, answers) {
4167
4087
  if (readme) {
4168
4088
  result.set("README.md", Buffer.from(readme.toString("utf-8").replace(/^# .*$/m, `# ${answers.pluginName}`), "utf-8"));
4169
4089
  }
4090
+ const license = result.get("LICENSE");
4091
+ if (license) {
4092
+ result.set("LICENSE", Buffer.from(license.toString("utf-8").replace(/^Copyright \(C\) [^\r\n]*/m, getOfficialSampleCopyrightLine(answers)), "utf-8"));
4093
+ }
4170
4094
  return result;
4171
4095
  }
4172
4096
  function copyOfficialSample(answers, targetDir, currentVersion, existingConfig, snapshot) {
@@ -4179,6 +4103,9 @@ function copyOfficialSample(answers, targetDir, currentVersion, existingConfig,
4179
4103
  );
4180
4104
  return { ...config, upstreamCommit: snapshot.commit };
4181
4105
  }
4106
+ function getOfficialSampleCopyrightLine(answers) {
4107
+ return `Copyright (C) ${String(answers.currentYear)} by ${answers.authorName}`;
4108
+ }
4182
4109
  function getPackageRoot() {
4183
4110
  return join5(getScriptDir(), "..");
4184
4111
  }
@@ -4583,7 +4510,7 @@ function buildSavedConfig(newConfig, answers, overlay, targetDir) {
4583
4510
  async function checkForUpdates(currentVersion) {
4584
4511
  const latestVer = await fetchLatestVersion("@mnaoumov/create-obsidian-plugin");
4585
4512
  if (latestVer !== null && compare(currentVersion, latestVer) < 0) {
4586
- log5.warn(`Your version is outdated. Latest: ${latestVer}. Update with:
4513
+ log4.warn(`Your version is outdated. Latest: ${latestVer}. Update with:
4587
4514
  npm install -g @mnaoumov/create-obsidian-plugin`);
4588
4515
  }
4589
4516
  }
@@ -4611,7 +4538,7 @@ async function ensurePluginIdIsUnlisted(answers, useDefaults) {
4611
4538
  const listedIds = await fetchCommunityPluginIds();
4612
4539
  if (listedIds === null) {
4613
4540
  s.stop("Could not check the plugin id against the Community directory.");
4614
- 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.`);
4541
+ 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.`);
4615
4542
  return answers;
4616
4543
  }
4617
4544
  const collision = validatePluginIdIsUnlisted(answers.pluginId, listedIds);
@@ -4624,7 +4551,7 @@ async function ensurePluginIdIsUnlisted(answers, useDefaults) {
4624
4551
  exitWithUsageError(`${collision}.
4625
4552
  Pass --pluginId=<value> to choose another.`);
4626
4553
  }
4627
- log5.warn(collision);
4554
+ log4.warn(collision);
4628
4555
  const choice = await select2({
4629
4556
  initialValue: "reenter",
4630
4557
  message: `What should happen to "${answers.pluginId}"?`,
@@ -4755,11 +4682,11 @@ async function offerAnswersExport(answers, customTemplate) {
4755
4682
  if (shell === "sh") {
4756
4683
  chmodSync(scriptPath, SCRIPT_MODE);
4757
4684
  }
4758
- log5.success(`Wrote ${scriptName}`);
4685
+ log4.success(`Wrote ${scriptName}`);
4759
4686
  note(formatCreateCommand(answers, shell, customTemplate), "Non-interactive command");
4760
4687
  } else {
4761
4688
  writeFileSync2(join9(process.cwd(), answersFileName), formatAnswersJson(answers));
4762
- log5.success(`Wrote ${answersFileName}`);
4689
+ log4.success(`Wrote ${answersFileName}`);
4763
4690
  const overlayFlag = customTemplate ? ` --customTemplate=${customTemplate}` : "";
4764
4691
  note(`npm create @mnaoumov/obsidian-plugin "--" --yes --mode=create --answersFile=${answersFileName}${overlayFlag}`, "Non-interactive command");
4765
4692
  }
@@ -4790,7 +4717,7 @@ async function resolveOfficialSampleSnapshot(latest) {
4790
4717
  return snapshot;
4791
4718
  } catch (error) {
4792
4719
  s.stop(`Could not fetch ${upstream.repo}.`);
4793
- log5.warn(`${error instanceof Error ? error.message : String(error)}
4720
+ log4.warn(`${error instanceof Error ? error.message : String(error)}
4794
4721
  Using the snapshot this release vendored, ${vendored.commit.slice(0, SHORT_SHA_LENGTH)}.`);
4795
4722
  return vendored;
4796
4723
  }
@@ -4894,7 +4821,7 @@ async function runPostScaffold(targetDir, answers) {
4894
4821
  } catch (error) {
4895
4822
  s.stop(`Failed to install dependencies. Run \`${installCmd}\` manually.`);
4896
4823
  if (error instanceof Error && "stderr" in error) {
4897
- log5.error(String(error.stderr));
4824
+ log4.error(String(error.stderr));
4898
4825
  }
4899
4826
  }
4900
4827
  }
@@ -4918,7 +4845,7 @@ async function runPostScaffold(targetDir, answers) {
4918
4845
  } catch (error) {
4919
4846
  s.stop("Failed to initialize git. Run `git init` manually.");
4920
4847
  if (error instanceof Error && "stderr" in error) {
4921
- log5.error(String(error.stderr));
4848
+ log4.error(String(error.stderr));
4922
4849
  }
4923
4850
  }
4924
4851
  }
@@ -4944,10 +4871,10 @@ async function runUpdate(currentVersion, cliArgs) {
4944
4871
  const targetDir = process.cwd();
4945
4872
  const existingConfig = loadConfig(targetDir);
4946
4873
  if (!existingConfig) {
4947
- log5.error("No config file found. Cannot update.");
4874
+ log4.error("No config file found. Cannot update.");
4948
4875
  process.exit(1);
4949
4876
  }
4950
- log5.info(`Current project was generated with v${existingConfig.generatorVersion}`);
4877
+ log4.info(`Current project was generated with v${existingConfig.generatorVersion}`);
4951
4878
  let overlay = null;
4952
4879
  if (customTemplate !== void 0) {
4953
4880
  overlay = customTemplate ? loadOverlayOrExit(resolvePath(customTemplate)) : null;
@@ -4957,14 +4884,14 @@ async function runUpdate(currentVersion, cliArgs) {
4957
4884
  `
4958
4885
  This project records it in ${CONFIG_FILE_NAME}. Pass --customTemplate=<dir> to point at where it is now, or --customTemplate= to stop using it.`
4959
4886
  );
4960
- log5.info(`Applying the custom template recorded for this project: ${existingConfig.customTemplate}`);
4887
+ log4.info(`Applying the custom template recorded for this project: ${existingConfig.customTemplate}`);
4961
4888
  }
4962
4889
  const configPath = join9(targetDir, CONFIG_FILE_NAME);
4963
4890
  const savedConfig = JSON.parse(readFileSync8(configPath, "utf-8"));
4964
4891
  let answers;
4965
4892
  if (savedConfig.answers) {
4966
4893
  const saved = { ...savedConfig.answers, ...suppliedAnswers };
4967
- log5.info("Using saved answers from previous generation.");
4894
+ log4.info("Using saved answers from previous generation.");
4968
4895
  const shouldRePrompt = useDefaults ? false : await confirm({
4969
4896
  initialValue: false,
4970
4897
  message: "Would you like to change any settings?"
@@ -4980,7 +4907,7 @@ This project records it in ${CONFIG_FILE_NAME}. Pass --customTemplate=<dir> to p
4980
4907
  exitWithUsageError(`${CONFIG_FILE_NAME} records no answers, so --yes has none to reuse.
4981
4908
  Run without --yes to answer them again.`);
4982
4909
  }
4983
- log5.warn("No saved answers found. Please provide the settings again.");
4910
+ log4.warn("No saved answers found. Please provide the settings again.");
4984
4911
  answers = await promptAnswers(suppliedAnswers);
4985
4912
  }
4986
4913
  const savedPluginId = savedConfig.answers?.pluginId;
@@ -5002,7 +4929,7 @@ Run without --yes to answer them again.`);
5002
4929
  const { minAppVersion, resolvedVersions } = await resolveExternalVersions(answers, overlay);
5003
4930
  const projectFormatter = createProjectFormatter(targetDir, answers.formatter);
5004
4931
  if (projectFormatter === null && needsInitialFormat(answers.formatter)) {
5005
- 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.`);
4932
+ 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.`);
5006
4933
  }
5007
4934
  const s = spinner();
5008
4935
  s.start("Updating project files...");
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mnaoumov/create-obsidian-plugin",
3
- "version": "1.3.0",
3
+ "version": "1.4.0",
4
4
  "description": "Create Obsidian plugin from modern templates.",
5
5
  "homepage": "https://mnaoumov.dev/create-obsidian-plugin/",
6
6
  "bugs": "https://github.com/mnaoumov/create-obsidian-plugin/issues",