obsidian-enhancing-export icon indicating copy to clipboard operation
obsidian-enhancing-export copied to clipboard

[Suggestion] Add "Export view" fields in page frontmatter

Open josephgarnier opened this issue 1 year ago • 1 comments

Hello dear dev!

Using the view can become quite time-consuming when you have to manage several export commands depending on the type of page.

It would be amazing if we could list the export commands to be executed in the frontmatter, with their arguments, and then call them with a single command Execute all commands on page.

A such page frontmatter declaration could be:

export:
  <name-of-export-command-1>:
    destination: <file-path>
    <param-1>: '<value-1>'
    <param-2>: ['<value-1>', '<value-2>']
  <name-of-export-command-2>:
    destination: <file-path>

The good news is that the Obsidian API can already handle frontmatter inner properties. Here is an example of code in JS to parse export and get its values:

/**
 * Get inside the frontmatter the value of the property `propertyName`.
 * @param {App} app A reference to the Obsidian `app`.
 * @param {Obsidian} obsidian A reference to the Obsidian API.
 * @param {TFile} file Vault file to parse.
 * @param {string} propertyName Property name of the value to get.
 * @returns {any|null} Value inside the frontmatter of `file`.
 * @throws {Error} If the property doesn't exists.
 */
static getFrontMatterEntry(app, obsidian, file, propertyName) {
  const fileFrontMatter = app.metadataCache.getFileCache(file)?.frontmatter;
  if (
    !fileFrontMatter ||
    !Object.keys(fileFrontMatter).includes(propertyName)
  )
    throw new Error(
      `The property '${propertyName}' doesn't exists in the file '${file.path}'.`
    );

  const propertyValue = obsidian.parseFrontMatterEntry(
    fileFrontMatter,
    propertyName
  );
  return propertyValue;
}

/**
 * Check if the frontmatter has a the property `propertyName`
 * @alias UtilityObsidian:getFrontMatterAliases
 * @param {App} app A reference to the Obsidian `app`.
 * @param {TFile} file Vault file to parse.
 * @param {string} propertyName Property name to check.
 * @returns {boolean} `true` if frontmatter has the property; otherwise `false`.
 */
static hasFrontMatterEntry(app, file, propertyName) {
  const fileFrontMatter = app.metadataCache.getFileCache(file)?.frontmatter;
  if (
    !fileFrontMatter ||
    !Object.keys(fileFrontMatter).includes(propertyName)
  )
    return false;

  return true;
}

/**
 * Extract the command arguments defined in the frontmatter property 'export' of the invoker page `invokerPage`.
 * @param {TFile} invokerPage Page that call the script.
 * @returns {Map<string,object>} Args of each command defined in the page. Map is in the form `{ key: <command-name>, value: <command-args-object> }`.
 * @throws {Error} If `invokerPage` has not property 'script' in its frontmatter, or if a script declaration is malformed.
 */
function extractAllCommandArgs(invokerPage) {
  if (!MyClass.hasFrontMatterEntry(Context.app, invokerPage, "export")) {
    throw new Error(
      `The frontmatter property 'export' is missing in '${invokerPage.basename}'!`
    );
  }

  /** @type {object} */
  const allScripts = MyClass.getFrontMatterEntry(
    Context.app,
    Context.obsidian,
    invokerPage,
    "export"
  );
  if (allScripts == null)
    throw new Error(
      `The frontmatter property 'export' is not defined in '${invokerPage.basename}'!`
    );

  /** @type {Map<string,Object|null>} */
  const scriptMap = new Map(Object.entries(allScripts));
  if (Array.from(scriptMap.values()).includes(null))
    throw new Error(
      `The frontmatter property 'export' is malformed! An argument list cannot be null, use '{}'.`
    );

  return scriptMap;
}

ps: Thank you very much for this very useful plugin.

josephgarnier avatar Oct 28 '24 07:10 josephgarnier

Thanks for your suggestion, but my energy is limited and I don't need this feature. If you think it is useful, PR is welcome.

mokeyish avatar Oct 28 '24 11:10 mokeyish