Class: Woods::Obsidian::NameMapper
- Inherits:
-
Object
- Object
- Woods::Obsidian::NameMapper
- Defined in:
- lib/woods/obsidian/name_mapper.rb
Overview
Centralizes the identifier -> note-filename mapping for an Obsidian vault.
This is the single source of truth for three things that must always
agree: the filename a note is written to, the wikilink target that points
at it, and the inverse path -> id map shipped in the machine sidecar.
Building them in one place means a link can never point at a filename the
writer didn't produce.
Rules:
- Sanitize
::to__and every other non[A-Za-z0-9_-]char to_, so the basename is always safe both as a filename and as a wikilink target (Obsidian's# | ^ : %%link-breaking chars are all removed). - Collisions are resolved per folder, case-insensitively (macOS/Windows fold case): the colliding note gets a short content hash appended. Two identical basenames in different type folders are distinct paths and need no hash.
- The MOC basename
_indexis reserved in every folder so a (pathological) unit named_indexcan never overwrite a folder's index note. - Filenames are capped to 255 bytes, truncated on a UTF-8 char boundary.
- The alias (the human-readable display half of a wikilink) keeps the
original identifier, with only the link-structural chars
[ ] |replaced.
Determinism: ids are processed in sorted order, so the same input always produces the same collision-hash assignments.
Constant Summary collapse
- MAX_FILENAME_BYTES =
255- EXTENSION =
'.md'- HASH_SUFFIX_BYTES =
"-" + 8 hex chars
9- RESERVED_BASENAMES =
%w[_index].freeze
Instance Method Summary collapse
-
#ids ⇒ Array<String>
Exported identifiers, sorted.
-
#initialize(id_to_dir) ⇒ NameMapper
constructor
A new instance of NameMapper.
-
#known?(id) ⇒ Boolean
Whether this id has an emitted note.
-
#path_for(id) ⇒ String?
Vault-relative note path ("models/User.md").
-
#paths_to_ids ⇒ Hash{String=>String}
Inverse path -> id map (sorted).
-
#target_for(id) ⇒ String?
Wikilink target with no extension ("models/User").
-
#wikilink(id) ⇒ String?
Full wikilink ("[[models/User|User]]") or nil if unknown.
Constructor Details
#initialize(id_to_dir) ⇒ NameMapper
Returns a new instance of NameMapper.
40 41 42 43 44 |
# File 'lib/woods/obsidian/name_mapper.rb', line 40 def initialize(id_to_dir) @map = {} @paths = {} build(id_to_dir) end |
Instance Method Details
#ids ⇒ Array<String>
Returns exported identifiers, sorted.
47 48 49 |
# File 'lib/woods/obsidian/name_mapper.rb', line 47 def ids @map.keys end |
#known?(id) ⇒ Boolean
Returns whether this id has an emitted note.
53 54 55 |
# File 'lib/woods/obsidian/name_mapper.rb', line 53 def known?(id) @map.key?(id) end |
#path_for(id) ⇒ String?
Returns vault-relative note path ("models/User.md").
59 60 61 |
# File 'lib/woods/obsidian/name_mapper.rb', line 59 def path_for(id) @map[id]&.fetch(:path) end |
#paths_to_ids ⇒ Hash{String=>String}
Returns inverse path -> id map (sorted).
79 80 81 |
# File 'lib/woods/obsidian/name_mapper.rb', line 79 def paths_to_ids @paths end |
#target_for(id) ⇒ String?
Returns wikilink target with no extension ("models/User").
65 66 67 |
# File 'lib/woods/obsidian/name_mapper.rb', line 65 def target_for(id) @map[id]&.fetch(:target) end |
#wikilink(id) ⇒ String?
Returns full wikilink ("[[models/User|User]]") or nil if unknown.
71 72 73 74 75 76 |
# File 'lib/woods/obsidian/name_mapper.rb', line 71 def wikilink(id) entry = @map[id] return nil unless entry "[[#{entry[:target]}|#{entry[:alias]}]]" end |