JavaScript API
A fluent API that reads like English. Every edit is tracked by default. Author is set once and applied to everything.
const docex = require('./src/docex');
const doc = docex("paper.docx");
doc.author("Alex Chen");
Opening and saving
Open a .docx file. Returns a document object.
const doc = docex("paper.docx");
Set the author name for all subsequent operations. Applied to tracked changes and comments.
doc.author("Alex Chen");
Save the document. Overwrites the original by default. All queued operations are applied in a single zip cycle. Auto-verifies after save.
await doc.save(); // overwrite original
await doc.save("revised.docx"); // save to new file
await doc.save({ dryRun: true }); // preview without saving
Create an empty .docx file from scratch.
await docex.create("new-paper.docx");
Disable tracked changes for subsequent operations. Edits will be applied directly.
doc.untracked();
doc.replace("old", "new"); // no tracked change record
Position selectors
Target any location in the document. Like CSS selectors for documents.
Select the position at a phrase. Used for comments, formatting, and inline operations.
doc.at("digital wellbeing").comment("Needs citation");
doc.at("measurement validity").bold();
doc.at("12,847").highlight("yellow");
Select the position after a heading or text. Used for inserting new content.
doc.after("Methods").insert("We used a mixed-methods approach.");
doc.after("Results").figure("fig03.png", "Figure 3. Rates.");
doc.after("Results").table([["A","B"],["1","2"]]);
Select the position before a heading or text.
doc.before("Conclusion").insert("Final remarks before conclusion.");
Select a paragraph by its stable ID. IDs survive other edits, making them reliable anchors.
doc.id("3A7F2B1C").replace("old text", "new text");
Text operations
Replace text. Shows as a tracked change (strikethrough + insertion) in Word.
doc.replace("measurement validity", "regulatory gap");
Replace all occurrences of a string throughout the document.
doc.replaceAll("GDPR", "GDPR/DPA");
Delete text (tracked). Shows as strikethrough in Word.
doc.delete("redundant sentence here");
Insert a new paragraph after a heading or text.
doc.after("Methods").insert("We used a mixed-methods approach.");
Find all occurrences of text in the document.
const results = await doc.find("sleep");
// [{paragraph: 3, text: "...the research dataset..."}]
Formatting
Apply basic formatting to selected text.
doc.at("significant findings").bold();
doc.at("p < 0.05").italic();
doc.at("critical note").underline();
Highlight text with a Word highlight color.
doc.at("needs review").highlight("yellow");
Set text color.
doc.at("warning").color("red");
Additional formatting options.
doc.at("removed text").strikethrough();
doc.at("2").superscript(); // x2 becomes x^2
doc.at("i").subscript(); // xi becomes x_i
doc.at("Author Name").smallCaps();
doc.at("var x = 1").code();
Add a footnote anchored to text.
doc.at("finding").footnote("See appendix B for full results.");
Comments
Add a comment anchored to a phrase.
doc.at("digital wellbeing").comment("Needs citation", { by: "Reviewer 2" });
Reply to an existing comment (threaded reply in Word).
doc.at("digital wellbeing").reply("Added Johnson 2022", { by: "Alex Chen" });
List all comments in the document.
const comments = await doc.comments();
// [{id: 1, author: "Reviewer 2", text: "Needs citation", anchor: "digital wellbeing"}]
Export all comments to CSV or JSON.
const csv = await doc.exportComments("csv");
Figures and tables
Insert a figure after a heading or paragraph. Auto-detects image dimensions.
doc.after("Results").figure("fig03.png", "Figure 3. Effect sizes by study.");
Insert a table. Supports booktabs styling and captions.
doc.after("Results").table(
[["Study", "N", "Effect Size"],
["Smith 2023", "342", "d = 0.45"],
["Lee 2022", "289", "d = 0.38"]],
{ style: "booktabs", caption: "Table 1. Effect sizes by study." }
);
Insert a bullet or numbered list.
doc.after("Key findings").bulletList([
"Screen time >4h/day associated with 23% reduction in sleep quality",
"Only 14.2% of studies used objective sleep measures",
"Average effect size: d = 0.42"
]);
List all figures in the document.
const figs = await doc.figures();
// [{rId: "rId5", src: "word/media/image1.png", width: "5486400emu"}]
Tracked changes
List all tracked changes.
const revs = await doc.revisions();
// [{id: 17, type: "del", author: "Research Assistant", text: "12,847 records"}]
Accept or reject tracked changes. Pass an ID for a specific change, or omit to apply to all.
await doc.accept(); // accept all
await doc.accept(5); // accept only change #5
await doc.reject(); // reject all
Create a clean copy with all tracked changes accepted and markup removed.
await doc.cleanCopy();
Compare two documents and produce a .docx with tracked changes showing the differences.
await doc.diff("paper-v1.docx");
.dex format
Convert a .docx workspace into .dex plain text format.
const { DexDecompiler } = require('./src/dex-decompiler');
const dex = DexDecompiler.decompile("paper.docx");
// Returns the full .dex string
Convert a .dex string back into a .docx file.
const { DexCompiler } = require('./src/dex-compiler');
await DexCompiler.compile(dexString, "output.docx");
Journal styles
Apply a journal formatting preset. Sets fonts, margins, spacing, headers, and page layout.
await doc.style("polcomm"); // Political Communication
await doc.style("apa7"); // APA 7th Edition
await doc.style("jcmc"); // Journal of Computer-Mediated Communication
await doc.style("joc"); // Journal of Communication
await doc.style("academic"); // Generic academic
Validate the document against journal requirements.
const result = await doc.verify("polcomm");
// { pass: false, issues: ["Word count 8200 exceeds limit 8000"] }
Document health
Run the document doctor. Checks for corrupt zip structure, orphaned images, broken relationships, duplicate paragraph IDs, and heading hierarchy problems.
const health = await doc.validate();
// { issues: [], healthy: true }
Get word counts broken down by section.
const counts = await doc.wordCount();
// { body: 6800, headings: 45, abstract: 250, captions: 120, footnotes: 85, total: 7300 }
Get document metadata (title, author, creation date, etc.).
const meta = await doc.metadata();
// { title: "The Effects of Social Media on Sleep Quality", creator: "Alex Chen", created: "2026-02-15" }
List all headings or paragraphs with their IDs.
const headings = await doc.headings();
// [{level: 1, text: "Introduction", index: 5}]
const paras = await doc.paragraphs();
// [{id: "3A7F2B1C", text: "We analyzed 12,847...", index: 12}]
Anonymize for blind peer review. Removes author names, affiliations, and identifying information.
await doc.anonymize();
Preview all pending operations without applying them.
doc.replace("old", "new");
doc.at("text").comment("note");
const ops = doc.preview();
// [{type: "replace", old: "old", new: "new"}, {type: "comment", anchor: "text"}]
Batch operations
Apply operations to multiple documents at once.
docex.batch(["paper1.docx", "paper2.docx"]).forEach(doc => {
doc.style("apa7");
doc.save();
});
Create a new document from a journal template.
await docex.fromTemplate({
title: "My Paper",
journal: "polcomm",
sections: ["Introduction", "Methods", "Results", "Discussion"]
});
Generate a response-to-reviewers letter from a JSON spec.
await docex.responseLetter({
manuscript: "paper.docx",
responses: "responses.json",
output: "response-letter.docx"
});
Export
Export the document to other formats.
const latex = await doc.toLatex();
const html = await doc.toHtml();
const md = await doc.toMarkdown();