Skip to content

Commit 0e848f6

Browse files
committed
🐛 Fix mathjax; cleanup distribution; resolves #224
1 parent 0bd7b4d commit 0e848f6

File tree

7 files changed

+165
-36
lines changed

7 files changed

+165
-36
lines changed

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ coverage/
2222
dist
2323
old
2424
examples/
25+
*.out
2526

2627
slides-extended/
2728
slides-extended.zip

esbuild.config.mjs

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -188,9 +188,8 @@ const parameters = {
188188
}),
189189
copy({
190190
assets: {
191-
from: ['node_modules/mathjax/es5/**/*'],
192-
to: ['./plugin/math/mathjax'],
193-
keepStructure: true
191+
from: ['node_modules/mathjax/**/*'],
192+
to: ['./plugin/math/mathjax/'],
194193
}
195194
}),
196195
copy({

src/plugin/load-mathjax.js

Lines changed: 31 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,7 @@
1+
// Queue for typeset calls that happen before MathJax is ready
2+
const typesetQueue = [];
3+
let mathJaxReady = false;
4+
15
window.MathJax = {
26
tex: {
37
inlineMath: [
@@ -21,24 +25,38 @@ window.MathJax = {
2125
},
2226
options: {
2327
enableMenu: false,
24-
enableExplorer: false,
25-
enableAssistiveMml: false,
2628
enableEnrichment: false,
27-
menuOptions: {
28-
settings: {
29-
assistiveMml: false,
30-
collapsible: false,
31-
explorer: false,
32-
},
33-
},
34-
renderActions: {
35-
assistiveMml: [],
36-
},
3729
},
3830
startup: {
3931
ready: () => {
4032
MathJax.startup.defaultReady();
41-
console.log("MathJax initialized with all extensions");
33+
MathJax.startup.promise.then(() => {
34+
console.debug("MathJax initialized and ready");
35+
mathJaxReady = true;
36+
37+
// Process any queued typeset calls
38+
if (typesetQueue.length > 0) {
39+
console.debug(
40+
`Processing ${typesetQueue.length} queued MathJax typeset calls`,
41+
);
42+
typesetQueue.forEach((args) => {
43+
MathJax.typesetPromise(...args).catch((err) =>
44+
console.error("Queued typeset error:", err),
45+
);
46+
});
47+
typesetQueue.length = 0;
48+
}
49+
});
4250
},
4351
},
52+
// Provide a safe typeset function that queues calls if MathJax isn't ready yet
53+
typeset: (...args) => {
54+
if (mathJaxReady && MathJax.typesetPromise) {
55+
return MathJax.typesetPromise(...args);
56+
}
57+
// Queue the call for later
58+
typesetQueue.push(args);
59+
console.debug("MathJax not ready yet, queuing typeset call");
60+
return Promise.resolve();
61+
},
4462
};

src/slidesExtended-Distribution.ts

Lines changed: 69 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,11 @@
1-
import { existsSync, mkdirSync, readFileSync, writeFileSync } from "node:fs";
1+
import {
2+
existsSync,
3+
mkdirSync,
4+
readFileSync,
5+
renameSync,
6+
rmSync,
7+
writeFileSync,
8+
} from "node:fs";
29
import path from "node:path";
310
import JSZip from "jszip";
411
import { requestUrl } from "obsidian";
@@ -32,27 +39,71 @@ export class SlidesExtendedDistribution {
3239
async update() {
3340
const version = this.plugin.manifest.version;
3441
const downloadUrl = `https://github.com/ebullient/obsidian-slides-extended/releases/download/${version}/slides-extended.zip`;
35-
const response = await requestUrl(downloadUrl);
36-
if (response.status !== 200) {
37-
console.error(`Failed to download ${downloadUrl}`);
38-
return;
42+
43+
// Backup existing dist directory before attempting update
44+
// Use dist-backup instead of dist/.backup to avoid issues with trailing slashes
45+
const backupDir = path.join(this.pluginDirectory, "dist-backup");
46+
let didBackup = false;
47+
48+
if (existsSync(this.distDirectory)) {
49+
console.debug(
50+
"Backing up existing distribution files before update",
51+
);
52+
// Remove any existing backup first
53+
if (existsSync(backupDir)) {
54+
rmSync(backupDir, { recursive: true, force: true });
55+
}
56+
renameSync(this.distDirectory, backupDir);
57+
didBackup = true;
3958
}
4059

41-
const zip = new JSZip();
42-
const contents = await zip.loadAsync(response.arrayBuffer);
43-
const pluginDirectory = this.pluginDirectory;
44-
45-
for (const filename of Object.keys(contents.files)) {
46-
if (!contents.files[filename].dir) {
47-
zip.file(filename)
48-
.async("nodebuffer")
49-
.then((content) => {
50-
const dest = path.join(pluginDirectory, filename);
51-
const dir = path.dirname(dest);
52-
mkdirSync(dir, { recursive: true });
53-
writeFileSync(dest, content);
60+
try {
61+
const response = await requestUrl(downloadUrl);
62+
if (response.status !== 200) {
63+
throw new Error(
64+
`Failed to download ${downloadUrl}: HTTP ${response.status}`,
65+
);
66+
}
67+
68+
const zip = new JSZip();
69+
const contents = await zip.loadAsync(response.arrayBuffer);
70+
const pluginDirectory = this.pluginDirectory;
71+
72+
for (const filename of Object.keys(contents.files)) {
73+
if (!contents.files[filename].dir) {
74+
zip.file(filename)
75+
.async("nodebuffer")
76+
.then((content) => {
77+
const dest = path.join(pluginDirectory, filename);
78+
const dir = path.dirname(dest);
79+
mkdirSync(dir, { recursive: true });
80+
writeFileSync(dest, content);
81+
});
82+
}
83+
}
84+
85+
// Update successful, remove backup
86+
if (didBackup && existsSync(backupDir)) {
87+
console.debug("Update successful, removing backup");
88+
rmSync(backupDir, { recursive: true, force: true });
89+
}
90+
} catch (error) {
91+
console.error("Failed to update distribution files:", error);
92+
93+
// Restore backup on failure
94+
if (didBackup && existsSync(backupDir)) {
95+
console.debug("Restoring backup due to update failure");
96+
// Remove partial update if it exists
97+
if (existsSync(this.distDirectory)) {
98+
rmSync(this.distDirectory, {
99+
recursive: true,
100+
force: true,
54101
});
102+
}
103+
renameSync(backupDir, this.distDirectory);
55104
}
105+
106+
throw error;
56107
}
57108
}
58109
}

src/template/embed.html

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -135,7 +135,7 @@
135135
gfm: true,
136136
},
137137
mathjax3: {
138-
mathjax: '{{{base}}}plugin/math/mathjax/tex-chtml-full.js',
138+
mathjax: '{{{base}}}plugin/math/mathjax/tex-chtml.js',
139139
},
140140
};
141141

src/template/reveal.html

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -208,7 +208,7 @@
208208
allottedTime: {{{.}}} * 1000,
209209
{{/timeForPresentation}}
210210
mathjax3: {
211-
mathjax: '{{{base}}}plugin/math/mathjax/tex-chtml-full.js',
211+
mathjax: '{{{base}}}plugin/math/mathjax/tex-chtml.js',
212212
},
213213
markdown: {
214214
gfm: true,

test/buildValidation.unit.test.ts

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
import { existsSync, readFileSync, readdirSync } from "node:fs";
2+
import { join } from "node:path";
3+
4+
const BUILD_DIR = process.env.OUTDIR || "./build";
5+
const TEMPLATE_DIR = "./src/template";
6+
7+
describe("Build Validation", () => {
8+
describe("Template References", () => {
9+
const templates = readdirSync(TEMPLATE_DIR).filter((f) =>
10+
f.endsWith(".html"),
11+
);
12+
13+
for (const templateFile of templates) {
14+
describe(templateFile, () => {
15+
const templatePath = join(TEMPLATE_DIR, templateFile);
16+
const content = readFileSync(templatePath, "utf-8");
17+
18+
// Extract all {{{base}}}path references (from any attribute or config)
19+
// Matches: {{{base}}}dist/..., {{{base}}}css/..., {{{base}}}plugin/...
20+
const basePathPattern =
21+
/\{\{\{base\}\}\}((?:dist|css|plugin)\/[^"'}\s]+)/g;
22+
const matches = [...content.matchAll(basePathPattern)];
23+
24+
if (matches.length === 0) {
25+
it(`should have at least one {{{base}}} reference`, () => {
26+
expect(matches.length).toBeGreaterThan(0);
27+
});
28+
}
29+
30+
for (const match of matches) {
31+
const path = match[1];
32+
33+
it(`should have ${path} in build output`, () => {
34+
const fullPath = join(BUILD_DIR, path);
35+
expect(existsSync(fullPath)).toBe(true);
36+
});
37+
}
38+
});
39+
}
40+
});
41+
42+
describe("Critical Build Files", () => {
43+
const criticalFiles = [
44+
"dist/reveal.js",
45+
"plugin/math/math.js",
46+
"plugin/math/mathjax/tex-chtml.js",
47+
"plugin/load-mathjax.js",
48+
"plugin/obsidian-markdown.js",
49+
"template/reveal.html",
50+
"template/embed.html",
51+
];
52+
53+
for (const file of criticalFiles) {
54+
it(`should have ${file}`, () => {
55+
const fullPath = join(BUILD_DIR, file);
56+
expect(existsSync(fullPath)).toBe(true);
57+
});
58+
}
59+
});
60+
});

0 commit comments

Comments
 (0)