mirror of
https://github.com/anthonyfitzpatrick/manuscript-compiler.git
synced 2026-07-22 08:31:19 +00:00
Bundle logo and attest release artifacts
This commit is contained in:
parent
a50b64adbc
commit
1da688ee91
16 changed files with 84 additions and 31 deletions
44
.github/workflows/release.yml
vendored
Normal file
44
.github/workflows/release.yml
vendored
Normal file
|
|
@ -0,0 +1,44 @@
|
|||
name: Release
|
||||
|
||||
on:
|
||||
release:
|
||||
types: [published]
|
||||
|
||||
permissions:
|
||||
id-token: write
|
||||
attestations: write
|
||||
contents: write
|
||||
|
||||
jobs:
|
||||
release:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Check out release tag
|
||||
uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6
|
||||
with:
|
||||
ref: ${{ github.event.release.tag_name }}
|
||||
- name: Set up Node.js
|
||||
uses: actions/setup-node@249970729cb0ef3589644e2896645e5dc5ba9c38 # v6
|
||||
with:
|
||||
node-version: 24
|
||||
cache: npm
|
||||
- name: Install dependencies
|
||||
run: npm ci
|
||||
- name: Verify release tag
|
||||
env:
|
||||
RELEASE_TAG: ${{ github.event.release.tag_name }}
|
||||
run: test "$(node -p "require('./manifest.json').version")" = "$RELEASE_TAG"
|
||||
- name: Build release assets
|
||||
run: npm run build
|
||||
- name: Attest runtime assets
|
||||
uses: actions/attest@f7c74d28b9d84cb8768d0b8ca14a4bac6ef463e6 # v4.2.0
|
||||
with:
|
||||
subject-path: |
|
||||
main.js
|
||||
manifest.json
|
||||
styles.css
|
||||
- name: Upload release assets
|
||||
env:
|
||||
GH_TOKEN: ${{ github.token }}
|
||||
RELEASE_TAG: ${{ github.event.release.tag_name }}
|
||||
run: gh release upload "$RELEASE_TAG" main.js manifest.json styles.css --clobber
|
||||
|
|
@ -89,4 +89,4 @@ Keep the PR focused. Address review comments with new commits unless the maintai
|
|||
|
||||
## Releases
|
||||
|
||||
A release tag must exactly equal the version in `manifest.json`, without a `v` prefix. Attach `main.js`, `manifest.json`, `styles.css`, and `logo.svg` individually. The optional ZIP must contain exactly those four files. Follow [RELEASE_READINESS.md](RELEASE_READINESS.md) and preserve every unchecked manual gate in [MANUAL_TESTING.md](MANUAL_TESTING.md) until it is actually completed.
|
||||
A release tag must exactly equal the version in `manifest.json`, without a `v` prefix. Attach `main.js`, `manifest.json`, and `styles.css` individually. The optional ZIP must contain exactly those three files; `logo.svg` remains repository branding and is bundled into `main.js` for runtime display. Follow [RELEASE_READINESS.md](RELEASE_READINESS.md) and preserve every unchecked manual gate in [MANUAL_TESTING.md](MANUAL_TESTING.md) until it is actually completed.
|
||||
|
|
|
|||
|
|
@ -229,7 +229,7 @@ If a change introduces caching, document ownership and invalidation. Never cache
|
|||
- Scope CSS to plugin roots and retain theme variables, focus-visible, reduced-motion, and high-contrast behavior.
|
||||
- Keep UI sentence case and accessible.
|
||||
- Keep `manifest.json` identity and minimum version stable unless the product release explicitly changes them.
|
||||
- Release exactly `main.js`, `manifest.json`, `styles.css`, and `logo.svg`.
|
||||
- Release exactly `main.js`, `manifest.json`, and `styles.css`; keep `logo.svg` only as the repository's editable branding source.
|
||||
|
||||
## CI and release process
|
||||
|
||||
|
|
@ -242,7 +242,7 @@ npm run package
|
|||
npm run package:validate
|
||||
```
|
||||
|
||||
The ZIP is optional; attach `main.js`, `manifest.json`, `styles.css`, and `logo.svg` individually to the GitHub release. The tag must exactly match `manifest.json` without a `v` prefix. Obsidian's Community Plugins installer downloads only its recognised runtime files; the logo remains a companion GitHub/manual-install asset. Do not package tests, fixtures, source, diagnostics, data files, or inspection artifacts.
|
||||
The ZIP is optional; attach `main.js`, `manifest.json`, and `styles.css` individually to the GitHub release. The tag must exactly match `manifest.json` without a `v` prefix. The logo artwork is bundled into `main.js`; `logo.svg` remains in the repository for branding and must not be packaged. Do not package tests, fixtures, source, diagnostics, data files, or inspection artifacts.
|
||||
|
||||
## Common mistakes
|
||||
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@ All items are intentionally unchecked. Record date, tester, Obsidian version, op
|
|||
|
||||
## Installation and workflow
|
||||
|
||||
- [ ] Install only `main.js`, `manifest.json`, `styles.css`, and `logo.svg` in a clean Obsidian vault.
|
||||
- [ ] Install only `main.js`, `manifest.json`, and `styles.css` in a clean Obsidian vault; confirm the settings page still displays the logo.
|
||||
- [ ] Upgrade an existing vault from the prior plugin version; confirm profiles, history, and formatting choices survive.
|
||||
- [ ] Load malformed persisted settings and confirm bounded, actionable recovery.
|
||||
- [ ] Right-click a folder and confirm the exact root opens in **Manuscript → Contents → Create file**.
|
||||
|
|
|
|||
|
|
@ -195,7 +195,7 @@ Manuscript Compiler is not yet listed in Obsidian's Community Plugins catalogue.
|
|||
|
||||
### Manual Installation
|
||||
|
||||
Download `main.js`, `manifest.json`, `styles.css`, and `logo.svg` from the same [GitHub release](https://github.com/anthonyfitzpatrick/manuscript-compiler/releases). Place them directly in `<vault>/.obsidian/plugins/manuscript-compiler/`, reload Obsidian, and enable **Manuscript Compiler** under Community Plugins.
|
||||
Download `main.js`, `manifest.json`, and `styles.css` from the same [GitHub release](https://github.com/anthonyfitzpatrick/manuscript-compiler/releases). Place them directly in `<vault>/.obsidian/plugins/manuscript-compiler/`, reload Obsidian, and enable **Manuscript Compiler** under Community Plugins.
|
||||
|
||||
## Known Limitations
|
||||
|
||||
|
|
@ -229,7 +229,7 @@ npm audit
|
|||
git diff --check
|
||||
```
|
||||
|
||||
The release archive is `release/manuscript-compiler-0.10.0.zip` and contains exactly `main.js`, `manifest.json`, `styles.css`, and `logo.svg`. Obsidian's Community Plugins installer fetches its three recognised runtime files; `logo.svg` is also published for manual installs and release branding.
|
||||
The release archive is `release/manuscript-compiler-0.10.0.zip` and contains exactly `main.js`, `manifest.json`, and `styles.css`. The editable `logo.svg` remains in the repository for README, GitHub, documentation, website, and social branding; its artwork is compiled into `main.js` and it is not a runtime or release-package file.
|
||||
|
||||
Automated structural validation is not a substitute for opening outputs in Word, Vellum, LibreOffice, multiple EPUB readers, text editors, and browsers. See the [Manual Release Checklist](MANUAL_TESTING.md).
|
||||
|
||||
|
|
|
|||
|
|
@ -101,12 +101,11 @@ The User Guide covers installation, manuscript organisation, the complete three-
|
|||
|
||||
Until Manuscript Compiler is accepted into the Obsidian Community Plugins directory, install it manually from this GitHub Release.
|
||||
|
||||
Download all four release assets:
|
||||
Download all three runtime release assets:
|
||||
|
||||
- `main.js`
|
||||
- `manifest.json`
|
||||
- `styles.css`
|
||||
- `logo.svg`
|
||||
|
||||
Create the following folder inside the vault if it does not already exist:
|
||||
|
||||
|
|
@ -114,7 +113,7 @@ Create the following folder inside the vault if it does not already exist:
|
|||
<vault>/.obsidian/plugins/manuscript-compiler/
|
||||
```
|
||||
|
||||
Place the four files directly inside that folder. Do not mix files from different releases.
|
||||
Place the three files directly inside that folder. Do not mix files from different releases. The settings logo is already bundled into `main.js`; the repository's `logo.svg` is branding source artwork and is not required for installation.
|
||||
|
||||
Restart Obsidian or reload Community Plugins, then open **Settings → Community plugins** and enable **Manuscript Compiler**.
|
||||
|
||||
|
|
|
|||
|
|
@ -38,9 +38,11 @@ Run and record current output before publishing:
|
|||
- `npm audit`
|
||||
- `git diff --check`
|
||||
|
||||
The release archive must be `release/manuscript-compiler-0.10.0.zip` and contain exactly `main.js`, `manifest.json`, `styles.css`, and `logo.svg`.
|
||||
The release archive must be `release/manuscript-compiler-0.10.0.zip` and contain exactly `main.js`, `manifest.json`, and `styles.css`.
|
||||
|
||||
Attach those four files individually to the GitHub release. The release tag must be exactly `0.10.0`, without a `v` prefix; the ZIP is optional and is not an installation dependency. Obsidian's Community Plugins installer uses the three recognised runtime assets, while GitHub and manual-install users also receive the standalone logo.
|
||||
The three runtime assets are `main.js`, `manifest.json`, and `styles.css`. GitHub Artifact Attestations cover those files. The release tag must be exactly `0.10.0`, without a `v` prefix; the ZIP is optional and is not an installation dependency.
|
||||
|
||||
`logo.svg` remains the master editable artwork in the repository for branding and documentation. The build bundles its SVG text into `main.js`, so neither the release package nor an installed plugin needs a separate logo file.
|
||||
|
||||
## Runtime dependencies
|
||||
|
||||
|
|
|
|||
|
|
@ -45,9 +45,8 @@ Official release assets are exactly:
|
|||
- `main.js`
|
||||
- `manifest.json`
|
||||
- `styles.css`
|
||||
- `logo.svg`
|
||||
|
||||
The optional release ZIP contains only those four files. The package validator rejects active content and external references in the standalone SVG. Use assets from one release tag and verify that the tag exactly matches the version in `manifest.json`. Dependency changes require lockfile review, licence review, audit, updated third-party notices, and explicit approval. Runtime dependencies must not be introduced as convenience wrappers around platform, export, or network behavior.
|
||||
The optional release ZIP contains only those three files. The repository's `logo.svg` is validated as branding source and compiled into `main.js`; it is not read from disk at runtime or included in the release package. Use assets from one release tag and verify that the tag exactly matches the version in `manifest.json`. Dependency changes require lockfile review, licence review, audit, updated third-party notices, and explicit approval. Runtime dependencies must not be introduced as convenience wrappers around platform, export, or network behavior.
|
||||
|
||||
## Supported versions
|
||||
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@ Manuscript Compiler is independently maintained. The documentation is the fastes
|
|||
## Before requesting help
|
||||
|
||||
1. Read the [User Guide](USER_GUIDE.md), especially its troubleshooting and known-limitations sections.
|
||||
2. Confirm the installed `main.js`, `manifest.json`, `styles.css`, and `logo.svg` came from the same release.
|
||||
2. Confirm the installed `main.js`, `manifest.json`, and `styles.css` came from the same release.
|
||||
3. Reproduce the problem with a small synthetic manuscript where possible.
|
||||
4. Remove manuscript prose, private metadata, absolute vault paths, account details, and access tokens from anything you share.
|
||||
5. Search existing [issues](https://github.com/anthonyfitzpatrick/manuscript-compiler/issues) and [Discussions](https://github.com/anthonyfitzpatrick/manuscript-compiler/discussions).
|
||||
|
|
|
|||
|
|
@ -30,21 +30,21 @@ For a first export, work through all three stages without skipping the Contents
|
|||
|
||||
Until Manuscript Compiler is available through Obsidian's Community Plugins catalogue:
|
||||
|
||||
1. Download `main.js`, `manifest.json`, `styles.css`, and `logo.svg` from a release whose tag exactly matches the manifest version.
|
||||
1. Download `main.js`, `manifest.json`, and `styles.css` from a release whose tag exactly matches the manifest version.
|
||||
2. Create `<vault>/.obsidian/plugins/manuscript-compiler/` if it does not exist.
|
||||
3. Put only those four files in that folder.
|
||||
3. Put only those three files in that folder. The settings logo is already bundled into `main.js`.
|
||||
4. Restart Obsidian or reload community plugins.
|
||||
5. Open **Settings → Community plugins** and enable **Manuscript Compiler**.
|
||||
|
||||
The plugin is mobile-safe, but the exact save/share experience depends on the mobile operating system and Obsidian host.
|
||||
|
||||
After enabling the plugin, confirm the installation before working with a real manuscript. Open the command palette and search for Manuscript Compiler, or right-click a test folder in File Explorer and confirm that **Compile manuscript from this folder** appears. If the command is missing, verify that the four release files are directly inside the plugin folder rather than inside an additional nested directory.
|
||||
After enabling the plugin, confirm the installation before working with a real manuscript. Open the command palette and search for Manuscript Compiler, or right-click a test folder in File Explorer and confirm that **Compile manuscript from this folder** appears. If the command is missing, verify that the three release files are directly inside the plugin folder rather than inside an additional nested directory.
|
||||
|
||||
## Updating
|
||||
|
||||
1. Close any open Manuscript Compiler window.
|
||||
2. Back up the vault using the same process used for other important Obsidian data.
|
||||
3. Replace `main.js`, `manifest.json`, `styles.css`, and `logo.svg` with all four files from the same release.
|
||||
3. Replace `main.js`, `manifest.json`, and `styles.css` with all three files from the same release.
|
||||
4. Restart Obsidian.
|
||||
5. Open the plugin once and confirm existing profiles and formatting choices remain available.
|
||||
|
||||
|
|
|
|||
|
|
@ -16,7 +16,7 @@ const context = await esbuild.context({
|
|||
bundle: true,
|
||||
external: ["obsidian", "electron", "@codemirror/autocomplete", "@codemirror/collab", "@codemirror/commands", "@codemirror/language", "@codemirror/lint", "@codemirror/search", "@codemirror/state", "@codemirror/view", "@lezer/common", "@lezer/highlight", "@lezer/lr", ...builtinModules, ...builtinModules.map((module) => `node:${module}`)],
|
||||
format: "cjs",
|
||||
loader: { ".svg": "dataurl" },
|
||||
loader: { ".svg": "text" },
|
||||
target: "es2018",
|
||||
logLevel: "info",
|
||||
sourcemap: production ? false : "inline",
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
import esbuild from "esbuild";
|
||||
|
||||
await esbuild.build({ entryPoints: ["tests/run.ts"], bundle: true, platform: "node", format: "esm", target: "node18", outfile: ".test-build/run.mjs", alias: { obsidian: "./tests/obsidian-stub.ts" }, loader: { ".svg": "dataurl" }, logLevel: "warning" });
|
||||
await esbuild.build({ entryPoints: ["tests/run.ts"], bundle: true, platform: "node", format: "esm", target: "node18", outfile: ".test-build/run.mjs", alias: { obsidian: "./tests/obsidian-stub.ts" }, loader: { ".svg": "text" }, logLevel: "warning" });
|
||||
await import("./.test-build/run.mjs");
|
||||
|
|
|
|||
|
|
@ -2,7 +2,8 @@ import { mkdir, readFile, rm, stat, writeFile } from "node:fs/promises";
|
|||
import path from "node:path";
|
||||
import { unzipSync, zipSync } from "fflate";
|
||||
|
||||
const required = ["main.js", "manifest.json", "styles.css", "logo.svg"];
|
||||
const required = ["main.js", "manifest.json", "styles.css"];
|
||||
const repositoryLogo = "logo.svg";
|
||||
const allowedManifestKeys = new Set(["id", "name", "version", "minAppVersion", "description", "author", "authorUrl", "fundingUrl", "isDesktopOnly"]);
|
||||
const semverPattern = /^\d+\.\d+\.\d+$/;
|
||||
const packageJson = await jsonFile("package.json");
|
||||
|
|
@ -35,13 +36,17 @@ async function validateAssets() {
|
|||
const info = await stat(name);
|
||||
assert(info.isFile() && info.size > 0, `Required release asset is missing or empty: ${name}`);
|
||||
}
|
||||
const logoInfo = await stat(repositoryLogo);
|
||||
assert(logoInfo.isFile() && logoInfo.size > 0, `Repository branding asset is missing or empty: ${repositoryLogo}`);
|
||||
const bundle = await readFile("main.js", "utf8");
|
||||
const logo = await readFile("logo.svg", "utf8");
|
||||
const releaseText = `${bundle}\n${await readFile("manifest.json", "utf8")}\n${await readFile("styles.css", "utf8")}\n${logo}`;
|
||||
const logo = await readFile(repositoryLogo, "utf8");
|
||||
const releaseText = `${bundle}\n${await readFile("manifest.json", "utf8")}\n${await readFile("styles.css", "utf8")}`;
|
||||
assert(!/sourceMappingURL|\.map(?:\s|$)/i.test(bundle), "Production bundle contains a source map reference.");
|
||||
assert(!/require\(["'](?:electron|(?:node:)?(?:fs|path|os|child_process))["']\)/.test(bundle), "Production bundle contains a prohibited desktop or Node import.");
|
||||
assert(!/\b(?:fetch|requestUrl|XMLHttpRequest|WebSocket|sendBeacon)\s*\(/.test(bundle), "Production bundle contains a prohibited network API.");
|
||||
assert(!/\b(?:eval|Function)\s*\(/.test(bundle), "Production bundle contains dynamic code execution.");
|
||||
assert(!bundle.includes(repositoryLogo), "Production bundle contains a runtime logo file path.");
|
||||
assert(bundle.includes("Semantic Tree") && bundle.includes("A hierarchy of parts, chapters and scenes inside a document."), "Production bundle is missing the bundled plugin logo.");
|
||||
assert(/<svg\b/i.test(logo), "logo.svg is not an SVG document.");
|
||||
assert(!/<(?:script|foreignObject|iframe|object|embed)\b/i.test(logo), "logo.svg contains active or embedded content.");
|
||||
assert(!/\b(?:href|src)\s*=\s*["'](?:https?:|data:|javascript:)/i.test(logo), "logo.svg contains an external or active reference.");
|
||||
|
|
|
|||
6
src/assets.d.ts
vendored
6
src/assets.d.ts
vendored
|
|
@ -1,12 +1,12 @@
|
|||
/**
|
||||
* Manuscript Compiler — compile-time declarations for bundled visual assets.
|
||||
*
|
||||
* SVG imports are converted to data URLs by the production bundler so settings
|
||||
* SVG imports are converted to raw text by the production bundler so settings
|
||||
* artwork remains offline, mobile-safe, and contained in main.js. This file
|
||||
* describes that build boundary only; it does not load files at runtime or add
|
||||
* release-package assets. Keep the declaration aligned with esbuild.config.mjs.
|
||||
*/
|
||||
declare module "*.svg" {
|
||||
const dataUrl: string;
|
||||
export default dataUrl;
|
||||
const rawSvg: string;
|
||||
export default rawSvg;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -20,6 +20,10 @@ import { EXPORT_FORMAT_DETAILS, EXPORT_FORMATS, type ExportFormat } from "./expo
|
|||
import buyMeACoffeeArtwork from "./assets/bmc-button.svg";
|
||||
import pluginLogo from "../logo.svg";
|
||||
|
||||
const svgDataUrl = (svg: string): string => `data:image/svg+xml;charset=utf-8,${encodeURIComponent(svg)}`;
|
||||
const buyMeACoffeeArtworkUrl = svgDataUrl(buyMeACoffeeArtwork);
|
||||
const pluginLogoUrl = svgDataUrl(pluginLogo);
|
||||
|
||||
/** Reusable vault-folder picker for compatibility commands/settings. */
|
||||
export class FolderSuggestModal extends FuzzySuggestModal<TFolder> {
|
||||
constructor(app: App, private readonly onChoose: (folder: TFolder) => void) { super(app); }
|
||||
|
|
@ -151,7 +155,7 @@ export class ManuscriptCompilerSettingTab extends PluginSettingTab {
|
|||
}
|
||||
private renderSupportContent(panel: HTMLElement): void {
|
||||
const identity = panel.createDiv({ cls: "manuscript-support-identity" });
|
||||
identity.createEl("img", { cls: "manuscript-support-logo", attr: { src: pluginLogo, alt: "", "aria-hidden": "true" } });
|
||||
identity.createEl("img", { cls: "manuscript-support-logo", attr: { src: pluginLogoUrl, alt: "", "aria-hidden": "true" } });
|
||||
const identityText = identity.createDiv({ cls: "manuscript-support-identity-text" });
|
||||
identityText.createEl("strong", { cls: "manuscript-support-name", text: "Manuscript Compiler" });
|
||||
identityText.createEl("p", { text: `Version ${this.plugin.manifest.version}` });
|
||||
|
|
@ -162,7 +166,7 @@ export class ManuscriptCompilerSettingTab extends PluginSettingTab {
|
|||
const button = new ButtonComponent(actions).setTooltip(action.label).setClass("manuscript-support-button");
|
||||
if (action.label === "Buy me a coffee") {
|
||||
const icon = button.buttonEl.createSpan({ cls: "manuscript-support-bmc-icon", attr: { "aria-hidden": "true" } });
|
||||
icon.createEl("img", { attr: { src: buyMeACoffeeArtwork, alt: "" } });
|
||||
icon.createEl("img", { attr: { src: buyMeACoffeeArtworkUrl, alt: "" } });
|
||||
} else {
|
||||
button.setIcon(action.icon);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -385,10 +385,10 @@ test("advanced controls remain available and settings lead with Defaults", async
|
|||
});
|
||||
|
||||
test("settings end with an accessible responsive Support & Links panel", async () => {
|
||||
const ui = await readFile(path.join("src", "ui.ts"), "utf8"); const css = await readFile("styles.css", "utf8");
|
||||
const ui = await readFile(path.join("src", "ui.ts"), "utf8"); const css = await readFile("styles.css", "utf8"); const build = await readFile("esbuild.config.mjs", "utf8");
|
||||
const records = ui.indexOf('setName("Export records")'); const support = ui.indexOf("this.renderSupportPanel(container);"); assert.ok(records >= 0 && support > records, "support must render after every setting");
|
||||
assert.match(ui, /container\.addClass\("manuscript-compiler-settings"\)/); assert.match(css, /\.manuscript-compiler-settings > \.setting-item:not\(\.setting-item-heading\)[\s\S]*padding-block: var\(--size-4-2\)/); assert.match(css, /\.manuscript-compiler-settings > details > \.setting-item/);
|
||||
assert.match(ui, /const SUPPORT_SECTION_TITLE = "Support & Links"/); assert.match(ui, /import pluginLogo from "\.\.\/logo\.svg"/); assert.match(ui, /manuscript-support-logo/); assert.match(ui, /text: `Version \$\{this\.plugin\.manifest\.version\}`/); assert.equal((ui.match(/\{ label: /g) ?? []).length, 5);
|
||||
assert.match(ui, /const SUPPORT_SECTION_TITLE = "Support & Links"/); assert.match(ui, /import pluginLogo from "\.\.\/logo\.svg"/); assert.match(build, /loader: \{ "\.svg": "text" \}/); assert.match(ui, /const pluginLogoUrl = svgDataUrl\(pluginLogo\)/); assert.match(ui, /src: pluginLogoUrl/); assert.doesNotMatch(ui, /readFile.*logo|getResourcePath.*logo|adapter.*logo/i); assert.match(ui, /manuscript-support-logo/); assert.match(ui, /text: `Version \$\{this\.plugin\.manifest\.version\}`/); assert.equal((ui.match(/\{ label: /g) ?? []).length, 5);
|
||||
for (const action of [
|
||||
'{ label: "Report a bug", icon: "bug", url: "https://github.com/anthonyfitzpatrick/manuscript-compiler/issues/new?template=bug_report.yml" }',
|
||||
'{ label: "Feature request", icon: "lightbulb", url: "https://github.com/anthonyfitzpatrick/manuscript-compiler/issues/new?template=feature_request.yml" }',
|
||||
|
|
@ -544,7 +544,7 @@ test("plugin CSS selectors are owned, theme-safe, and retain accessibility modes
|
|||
assert.doesNotMatch(css, /#[0-9a-f]{3,8}\b|!important/i); assert.match(css, /@media \(forced-colors: active\)/); assert.match(css, /@media \(prefers-reduced-motion: reduce\)/); assert.match(css, /:focus-visible/);
|
||||
});
|
||||
|
||||
test("0.10.0 version metadata and release package allowlist are consistent", async () => { const manifest = JSON.parse(await readFile("manifest.json", "utf8")); const packageJson = JSON.parse(await readFile("package.json", "utf8")); const lock = JSON.parse(await readFile("package-lock.json", "utf8")); const versions = JSON.parse(await readFile("versions.json", "utf8")); const packaging = await readFile(path.join("scripts", "package.mjs"), "utf8"); assert.equal(manifest.version, "0.10.0"); assert.equal(packageJson.version, manifest.version); assert.equal(lock.version, manifest.version); assert.equal(lock.packages[""].version, manifest.version); assert.equal(versions[manifest.version], manifest.minAppVersion); assert.equal(manifest.authorUrl, "https://wolf359.app"); assert.equal(manifest.fundingUrl, "https://buymeacoffee.com/wolf359pressab"); assert.match(packaging, /const required = \["main\.js", "manifest\.json", "styles\.css", "logo\.svg"\]/); });
|
||||
test("0.10.0 version metadata, bundled branding, and release package allowlist are consistent", async () => { const manifest = JSON.parse(await readFile("manifest.json", "utf8")); const packageJson = JSON.parse(await readFile("package.json", "utf8")); const lock = JSON.parse(await readFile("package-lock.json", "utf8")); const versions = JSON.parse(await readFile("versions.json", "utf8")); const packaging = await readFile(path.join("scripts", "package.mjs"), "utf8"); const readme = await readFile("README.md", "utf8"); assert.equal(manifest.version, "0.10.0"); assert.equal(packageJson.version, manifest.version); assert.equal(lock.version, manifest.version); assert.equal(lock.packages[""].version, manifest.version); assert.equal(versions[manifest.version], manifest.minAppVersion); assert.equal(manifest.authorUrl, "https://wolf359.app"); assert.equal(manifest.fundingUrl, "https://buymeacoffee.com/wolf359pressab"); assert.match(packaging, /const required = \["main\.js", "manifest\.json", "styles\.css"\]/); assert.doesNotMatch(packaging, /const required = \[[^\]]*logo\.svg/); assert.match(packaging, /const repositoryLogo = "logo\.svg"/); assert.match(readme, /<img src="logo\.svg"/); });
|
||||
test("repository hygiene ignores runtime state and rejects tracked plugin data", async () => {
|
||||
for (const candidate of ["data.json", ".obsidian/plugins/manuscript-compiler/data.json", "nested/manuscript-compiler/data.json"]) {
|
||||
await execFileAsync("git", ["check-ignore", "--no-index", "--quiet", candidate]);
|
||||
|
|
|
|||
Loading…
Reference in a new issue