在測試 PDF 匯出前,先驗證重新排序是否為排列
Validate a PDF reorder as a permutation before you test the export
重新排序 PDF 頁面前,應驗證匯出計劃是否包含每個原始實體頁面索引,且每個索引恰好出現一次。JavaScript 驗證器會拒絕重複、越界、無效及缺失的索引,並複製有效計劃;它只檢查結構,不驗證頁面次序是否符合用戶意圖。匯出後仍須檢查已儲存的 PDF,確認實際頁面內容及次序符合預期。
AI and affiliation disclosure: Codex generated this article and its JavaScript example for Yan Wang / LensUp. Codex ran the local checks described below; this does not claim personal execution or independent validation by the human account owner. The example is a standalone plan validator, not a production patch or a PDF exporter.
A reorder UI can display the expected number of thumbnails while its export plan contains the same source page twice. Checking the plan's length catches a missing slot, but not a duplicate that replaced another page.
For a pure reorder of one document, the useful input contract is narrow: every original physical page index appears exactly once. Deletion, repetition and insertion are different operations. They need different validators.
Define the index space first
The example accepts zero-based physical page indexes. For a four-page document, the allowed set is 0 through 3. It does not interpret printed numbers or PDF page labels.
The array [3, 0, 1, 2] means “take original physical page four first.” It is a valid permutation. It may still be the wrong reading order for the user. Validation can confirm the structure of the request, not its intent.
Check every slot
export function validateReorder(order, pageCount) {
if (!Number.isSafeInteger(pageCount) || pageCount < 1) {
throw new RangeError("pageCount must be a positive safe integer");
}
if (!Array.isArray(order) || order.length !== pageCount) {
throw new TypeError("order must contain one slot per source page");
}
const seen = new Set();
for (let i = 0; i < order.length; i += 1) {
const page = order[i];
if (!Number.isInteger(page) ||
page < 0 || page >= pageCount || seen.has(page)) {
throw new RangeError("order must be a permutation of source indexes");
}
seen.add(page);
}
return order.slice();
}
The indexed loop is deliberate. An ordinary sparse array has a length, but a missing slot reads as undefined. The integer check rejects it. Array methods that skip holes can make an incomplete plan look more complete than it is.
The returned array is a copy, so later changes to the caller's array don't change the accepted plan. This is not a deep-copy utility or a guard against hostile proxies and accessors; it expects ordinary application arrays containing numbers.
Test failures with the same page count
import assert from "node:assert/strict";
assert.deepEqual(validateReorder([3, 0, 1, 2], 4), [3, 0, 1, 2]);
assert.throws(() => validateReorder([0, 1, 1, 3], 4));
assert.throws(() => validateReorder([0, 1, 2, 4], 4));
assert.throws(() => validateReorder([0, 1, 2, "3"], 4));
assert.throws(() => validateReorder([0, 1, , 3], 4));
const requested = [1, 0];
const accepted = validateReorder(requested, 2);
requested.reverse();
assert.deepEqual(accepted, [1, 0]);
These assertions can follow the function in one ES module. The harness used for this article also checks invalid counts, non-array inputs, negative and fractional indexes, NaN, Infinity and shorter plans. Results and the actual runtime are retained with the manuscript; they do not constitute a browser or PDF-format compatibility test.
Snapshot the request, then test the artifact
Use the accepted plan as the input to the export job. If the user can continue editing while a save runs, decide how that job's snapshot is isolated from later UI changes. Copying this one array does not snapshot the entire document or solve asynchronous state management.
After export, open the saved PDF and check identifiable page content against the expected physical sequence. The validator never reads that PDF. It cannot detect an exporter using a stale array, writing pages in a different order, dropping content, breaking a link or changing a form.
So there are two separate questions: is this a structurally valid reorder request, and did this particular saved artifact implement it?
A valid permutation with the wrong intended sequence should pass the first test and fail the user's acceptance check. Keeping that distinction explicit gives each failure somewhere useful to go.
The article's two JavaScript blocks were executed together as an ES module with Node.js v22.23.4 on macOS. To reproduce the displayed checks, save them together as reorder-check.mjs and run node reorder-check.mjs. The separate retained harness adds the wider counterexample set described above.
Keep the scope small
This example intentionally has no “skip invalid entries” mode. Silently repairing [0, 1, 1, 3] would require deciding what the user meant. Fail the plan and return control to the UI instead.
It also does not claim that source indexes survive a mutation to the source document. Bind the plan to the document version being exported. A plan that was valid for an earlier page set is not automatically valid for a later one.
References: Number.isInteger, Array holes and iteration.
來源:DEV Community · dev.to