feat: add demo vault

Ship a curated demo-vault/ for Smart Rename, bootstrapped by the release-injected
obsidian-dev-utils demo-vault-helper. Notes walk through renaming a note while
preserving backlink display text, handling invalid characters, and every setting.
Add a static registerDemoVaultCoverageSuite no-app test that keeps the demo vault
in sync with the PluginSettings surface, the project dprint.json (excludes
demo-vault), and the README demo vault access section.
This commit is contained in:
Michael Naumov 2026-07-20 02:08:56 -06:00
parent 1edec0bc7d
commit fdb5c2c07b
19 changed files with 245 additions and 0 deletions

View file

@ -10,6 +10,14 @@ This is a plugin for [Obsidian](https://obsidian.md/) that adds the command `Sma
1. Adds the previous title as an alias to the renamed note 1. Adds the previous title as an alias to the renamed note
2. Preserves the backlinks to the renamed note that were using previous title as a display text. 2. Preserves the backlinks to the renamed note that were using previous title as a display text.
## Demo vault
A demo vault with usage examples ships with every release. You can access it via any of the following:
1. Running the **Smart Rename: Open demo vault** command.
2. Downloading `smart-rename.demo-vault.zip` from the [Releases](https://github.com/mnaoumov/obsidian-smart-rename/releases).
3. Browsing its source in [`demo-vault/`](./demo-vault/README.md) in this repository.
## Detailed explanation ## Detailed explanation
### Step 1 ### Step 1

13
demo-vault/.gitignore vendored Normal file
View file

@ -0,0 +1,13 @@
# Churny / runtime-generated Obsidian state.
.obsidian/workspace.json
.obsidian/hotkeys.json
# Built plugins are release-injected by archivePluginDemoVault at release time —
# both the plugin under test AND the obsidian-dev-utils-owned Demo Vault Helper
# bootstrap plugin (which installs, configures, and enables CodeScript Toolkit at
# runtime). Nothing helper-related is committed; commit only the baked settings
# file for the plugin under test.
.obsidian/plugins/*
!.obsidian/plugins/smart-rename/
.obsidian/plugins/smart-rename/*
!.obsidian/plugins/smart-rename/data.json

View file

@ -0,0 +1,12 @@
{
// Scoped markdownlint config for the demo vault. The notes are an Obsidian
// vault, so two default rules are inherently incompatible and disabled here;
// every other rule still applies so the notes stay clean.
"config": {
// Notes intentionally open with a `[Docs](...)` link, not a heading.
"MD041": false,
// `[[wikilinks]]` are Obsidian's native link syntax; markdownlint parses
// them as undefined shortcut reference links.
"MD052": false
}
}

8
demo-vault/.obsidian/app.json vendored Normal file
View file

@ -0,0 +1,8 @@
{
"attachmentFolderPath": "_assets/attachments",
"newLinkFormat": "shortest",
"useMarkdownLinks": false,
"showUnsupportedFiles": true,
"defaultViewMode": "source",
"livePreview": true
}

View file

@ -0,0 +1,4 @@
[
"demo-vault-helper",
"smart-rename"
]

18
demo-vault/00 Start.md Normal file
View file

@ -0,0 +1,18 @@
Welcome to the [Smart Rename](https://github.com/mnaoumov/obsidian-smart-rename/) demo vault. When you rename a note, Obsidian normally rewrites every link to point at the new name - and the visible text changes with it. **Smart Rename** instead preserves the old title as the link's display text, so your notes keep reading the way you wrote them. It also handles invalid characters, the first header, and a frontmatter title key.
**How to try it:** open [[Rename me]], run **Smart Rename: Invoke** from the Command Palette (or right-click the note and choose the smart rename option), and type a new title. Then look at [[References/Note A]] and [[References/Note B]] - the links still show the old title.
> [!TIP] Interactive buttons
>
> The two setup notes have **Run** buttons, powered by [`CodeScript Toolkit`](https://github.com/mnaoumov/obsidian-codescript-toolkit/), which this vault installs for you automatically on first open (see [[CodeScript Toolkit prerequisite]]). Renaming itself is a manual command, so the feature notes have no buttons.
## Feature
- [[Smart rename]]
- [[Invalid characters]]
- [[Settings]]
## Setup
- [[Code buttons check]]
- [[CodeScript Toolkit prerequisite]]

View file

@ -0,0 +1,13 @@
[Docs](https://github.com/mnaoumov/obsidian-codescript-toolkit/)
# Code buttons check
If [`CodeScript Toolkit`](https://github.com/mnaoumov/obsidian-codescript-toolkit/) is installed and enabled, the block below renders as a **Run** button. Click it - a notice should appear. If you only see a code block, install the prerequisite first: [[CodeScript Toolkit prerequisite]].
```code-button
---
caption: Click me
---
import { Notice } from 'obsidian';
new Notice('Code buttons work - you are ready to explore the demo vault.');
```

View file

@ -0,0 +1,22 @@
[Docs](https://github.com/mnaoumov/obsidian-codescript-toolkit/)
# CodeScript Toolkit prerequisite
The **Run** buttons in this vault are powered by [`CodeScript Toolkit`](https://github.com/mnaoumov/obsidian-codescript-toolkit/). This vault installs and enables it for you automatically the first time you open the vault (and trust it). Nothing here is required to explore Smart Rename - renaming is a plain command with no button.
## If the buttons do not work
If a code block does not turn into a button, install CodeScript Toolkit manually:
1. Open **Settings -> Community plugins -> Browse**.
2. Search for **CodeScript Toolkit**, install it, and enable it.
3. Reopen a note that has a **Run** button.
Or click the button below to install and enable it (needs an internet connection):
```code-button
---
caption: Install CodeScript Toolkit
---
await require('/demoSetup.ts').installAndEnable(app, 'fix-require-modules');
```

View file

@ -0,0 +1,19 @@
[Docs](https://github.com/mnaoumov/obsidian-smart-rename/)
# Invalid characters
Some characters (like `:` `/` `\` `*` `?`) cannot appear in a file name. Smart Rename lets you decide what happens when your new title contains one.
## Try it
1. Open [[Rename me]] and run **Smart Rename: Invoke**.
2. Type a title that contains an invalid character, such as `Chapter 1: Beginnings`.
3. Depending on the **Invalid characters action** setting, Smart Rename will either show an error, remove the invalid character, or replace it.
## The three actions
- **Error** - refuse the rename and show a notice (the default).
- **Remove** - strip the invalid characters from the file name.
- **Replace** - swap each invalid character for the configured replacement character (default `_`).
When the invalid title is stored as the note's display text (so the reader still sees `Chapter 1: Beginnings` even though the file name is sanitized) is controlled by the store-invalid-title setting. See [[Settings]] for all of these keys.

9
demo-vault/README.md Normal file
View file

@ -0,0 +1,9 @@
# Smart Rename demo vault
A small Obsidian vault that demonstrates the [Smart Rename](https://github.com/mnaoumov/obsidian-smart-rename) plugin - it renames the active note and rewrites its backlinks so their display text keeps showing the old title, with control over invalid characters, the first header, and a frontmatter title key.
Open [00 Start](<./00 Start.md>) and work through the notes. Open [Rename me](<./Rename me.md>), run **Smart Rename: Invoke**, and watch the backlinks in `References/`.
## First open
The first time you open this vault, Obsidian treats it as **untrusted**, so the bundled plugins are listed but not loaded until you **Trust author and enable plugins** and reload. After that, the Demo Vault Helper installs [CodeScript Toolkit](https://github.com/mnaoumov/obsidian-codescript-toolkit) (which powers the optional **Run** buttons in the setup notes) and opens the start note for you.

View file

@ -0,0 +1,5 @@
[Docs](https://github.com/mnaoumov/obsidian-smart-rename/)
# Note A
A note that links to [[Rename me]] with a plain link (no alias). After a smart rename, this becomes `[[New title|Rename me]]` so it still reads "Rename me".

View file

@ -0,0 +1,5 @@
[Docs](https://github.com/mnaoumov/obsidian-smart-rename/)
# Note B
Another note linking to [[Rename me|our starting note]]. It already has a custom alias, so the link keeps showing "our starting note" - smart rename only swaps the target, never your chosen display text.

7
demo-vault/Rename me.md Normal file
View file

@ -0,0 +1,7 @@
[Docs](https://github.com/mnaoumov/obsidian-smart-rename/)
# Rename me
This is the note the [[Smart rename]] demo renames. With this note active, run **Smart Rename: Invoke** and give it a new title.
Two notes link here - [[References/Note A]] and [[References/Note B]]. After the rename, their links will keep showing "Rename me" as their display text instead of switching to the new name.

25
demo-vault/Settings.md Normal file
View file

@ -0,0 +1,25 @@
[Docs](https://github.com/mnaoumov/obsidian-smart-rename/)
# Settings
Open **Settings -> Community plugins -> Smart Rename** to configure the plugin. Each option below lists the setting key stored in the plugin's `data.json`.
## Invalid characters
- `invalidCharacterAction` - how to process invalid characters in the new title: show an error, remove them, or replace them.
- `replacementCharacter` - the character used to replace invalid characters (only when the action is *Replace*).
- `shouldStoreInvalidTitle` - keep the original, invalid title as the note's display text; if disabled, the sanitized version is stored.
## Title
- `shouldUpdateFirstHeader` - also update the first header of the note when it matches the old title.
- `shouldUpdateTitleKey` - update the `title` key in the note's frontmatter.
## Previous display text
- `shouldPreservePreviousDisplayTextInNoteLinks` - keep the old title as display text in ordinary note links.
- `shouldPreservePreviousDisplayTextInFrontmatterLinks` - keep the old title as display text in links inside frontmatter.
## Other
- `shouldSupportNonMarkdownFiles` - make the command and context menu available for non-markdown files too.

View file

@ -0,0 +1,20 @@
[Docs](https://github.com/mnaoumov/obsidian-smart-rename/)
# Smart rename
Smart Rename renames the **active note** and rewrites its backlinks so their **display text keeps showing the old title**. A plain rename would change the visible link text to the new name; Smart Rename turns `[[Old title]]` into `[[New title|Old title]]` so the reader still sees what you originally wrote.
## Try it
1. Open [[Rename me]] (the note this demo renames).
2. Run **Smart Rename: Invoke** from the Command Palette, or right-click the note in the file explorer and choose the smart rename option.
3. Type a new title - for example `Renamed note` - and confirm.
4. Open [[References/Note A]] and [[References/Note B]]. Their links now point at the new note, but still **display** the old title.
## What it preserves
- **Note links** - a bare `[[Rename me]]` becomes `[[Renamed note|Rename me]]`, keeping the old text visible (controlled by the note-links setting in [[Settings]]).
- **Frontmatter links** - links inside YAML frontmatter get the same treatment (controlled by the frontmatter-links setting).
- **The first header and a title key** - optionally kept in sync with the new name (see [[Settings]]).
Renaming to a title that contains characters Obsidian cannot use in a filename is handled separately - see [[Invalid characters]].

View file

@ -0,0 +1,16 @@
import type { App } from 'obsidian';
import { Notice } from 'obsidian';
import {
enableCommunityPlugin,
installCommunityPlugin
} from 'obsidian-dev-utils/obsidian/community-plugins';
// Smart Rename works on the active file via a command + a prompt for the new title, so there is
// Nothing for a code-button to drive - the demo notes walk through it manually. The only helper the
// Vault needs is the shared CodeScript Toolkit installer used by the prerequisite note's button.
export async function installAndEnable(app: App, pluginId: string): Promise<void> {
await installCommunityPlugin({ app, pluginId });
await enableCommunityPlugin({ app, pluginId });
new Notice(`Installed and enabled: ${pluginId}`);
}

View file

@ -0,0 +1,10 @@
// Per-vault startup script, run by the universal Demo Vault Helper plugin (via CodeScript
// Toolkit's require) once CodeScript Toolkit is installed and enabled. This is where each
// plugin's demo vault does its own startup setup. Here it just opens the landing note.
const START_NOTE_PATH = '00 Start.md';
const startNote = app.vault.getFileByPath(START_NOTE_PATH);
if (startNote) {
void app.workspace.getLeaf(false).openFile(startNote);
}

10
dprint.json Normal file
View file

@ -0,0 +1,10 @@
{
"extends": "./node_modules/obsidian-dev-utils/dist/templates/dprint.json",
"excludes": [
"dist",
"**/node_modules",
"**/*-lock.json",
"**/*.md",
"demo-vault"
]
}

View file

@ -0,0 +1,21 @@
import process from 'node:process';
import { registerDemoVaultCoverageSuite } from 'obsidian-dev-utils/script-utils/demo-vault-coverage';
import { getRootFolder } from 'obsidian-dev-utils/script-utils/root';
// Keeps the in-repo `demo-vault/` in sync with the plugin's public surface WITHOUT
// Launching Obsidian: it reflects the real config from source and asserts every
// Setting is documented in a note, and that the guard note/member still exist
// (rename drift). Smart Rename's feature surface is an editor/file command with
// No public API interface, so only the PluginSettings config class is reflected;
// The plugin's runtime behavior is covered by the other integration tests.
registerDemoVaultCoverageSuite({
configInterfaces: [{ interfaceName: 'PluginSettings', sourcePath: 'src/plugin-settings.ts' }],
interfaces: [],
nonTrivialGuard: {
expectDemoNote: 'Settings.md',
expectMember: 'invalidCharacterAction',
interfaceName: 'PluginSettings',
sourcePath: 'src/plugin-settings.ts'
},
rootFolder: getRootFolder() ?? process.cwd()
});