@taprootio/site-authoring 0.14.0 → 0.15.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +62 -10
- package/examples/riverbend-wellness/.taproot-site-media.json +23 -0
- package/examples/riverbend-wellness/pages/index.md +1 -17
- package/package.json +2 -2
- package/src/api.js +59 -1
- package/src/cli.js +147 -22
- package/src/constants.js +6 -0
- package/src/content/components.js +64 -6
- package/src/content/free-form-sections.js +21 -4
- package/src/content/markdown.js +161 -26
- package/src/content/tiptap-prosemirror.ts +66 -8
- package/src/content/validate-document.js +30 -6
- package/src/content/vocabulary.js +26 -0
- package/src/errors.js +22 -0
- package/src/espalier-shared.js +11 -0
- package/src/font-catalog.js +87 -0
- package/src/footer-contract.js +1 -1
- package/src/output.js +19 -1
- package/src/presentation-reference.js +21 -7
- package/src/problems.js +116 -0
- package/src/reference-help.js +100 -34
- package/src/session.js +13 -0
- package/src/theme-proposals.js +393 -0
- package/src/theme-validation.js +31 -10
- package/src/typed-page-reference.js +11 -3
- package/src/typed-pages.js +31 -9
- package/src/verbs/deploy.js +1 -0
- package/src/verbs/index.js +13 -0
- package/src/verbs/media-upload.js +127 -30
- package/src/verbs/nav-push.js +7 -0
- package/src/verbs/pages-push.js +406 -199
- package/src/verbs/places.js +61 -0
- package/src/verbs/plan.js +585 -0
- package/src/verbs/theme-push.js +68 -36
- package/src/verbs/validate.js +264 -217
- package/src/video-prepare.js +48 -12
- package/src/workspace-check.js +199 -0
- package/src/workspace-ledger.js +173 -0
- package/src/workspace.js +47 -4
package/src/verbs/theme-push.js
CHANGED
|
@@ -286,6 +286,69 @@ function describeDifferences(validated, presentation) {
|
|
|
286
286
|
});
|
|
287
287
|
}
|
|
288
288
|
|
|
289
|
+
/** The refusal for a workspace pulled before the presentation baseline existed. */
|
|
290
|
+
export function presentationPullRequired() {
|
|
291
|
+
return new SiteAuthoringError(
|
|
292
|
+
"theme.pull_required",
|
|
293
|
+
"The pull manifest records no presentation baseline, so this push has no revision to be fenced by. Run "
|
|
294
|
+
+ "'taproot-site pull' against a Taproot that serves the atomic presentation save, then retry 'theme push'.",
|
|
295
|
+
{ field: "presentation.revision" },
|
|
296
|
+
);
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
/** The refusal for a presentation that moved since the pull, naming where the two differ. */
|
|
300
|
+
export function presentationMovedRefusal({ baseline, current, differences }) {
|
|
301
|
+
return new SiteAuthoringError(
|
|
302
|
+
"theme.concurrent_modification",
|
|
303
|
+
`The site's presentation changed after this workspace was pulled (revision ${baseline.revision} → `
|
|
304
|
+
+ `${current.revision}), so nothing was written. Keep copies of the edited settings files, run `
|
|
305
|
+
+ "'taproot-site pull' to refresh the baseline, re-apply the edits, and push again; the paths below name "
|
|
306
|
+
+ "where the workspace and the site now differ.",
|
|
307
|
+
{ field: "revision", alternatives: differences.filter((entry) => entry.paths.length > 0).map((entry) => entry.file) },
|
|
308
|
+
).withDifferences(differences.flatMap((entry) => entry.paths.map((path) => `${entry.file}:${path}`)));
|
|
309
|
+
}
|
|
310
|
+
|
|
311
|
+
/**
|
|
312
|
+
* What pushing this validated presentation would do, from one fresh read of
|
|
313
|
+
* the site: the JSON paths that differ, whether the pull's baseline is still
|
|
314
|
+
* current, and whether a save whose response was lost would be replayed.
|
|
315
|
+
* `theme push` and `plan` both decide from this (TR00823).
|
|
316
|
+
*/
|
|
317
|
+
export async function comparePresentation(client, siteId, validated, manifest) {
|
|
318
|
+
const baseline = readPresentationBaseline(manifest);
|
|
319
|
+
let current;
|
|
320
|
+
try {
|
|
321
|
+
current = await getSitePresentation(client, siteId);
|
|
322
|
+
} catch (error) {
|
|
323
|
+
throw translateServerSupport(error, "read");
|
|
324
|
+
}
|
|
325
|
+
const stale = baseline !== undefined && baseline.revision !== current.revision;
|
|
326
|
+
// A save this workspace sent and never heard back from (TR00807). When the
|
|
327
|
+
// change set about to go is the same one, a moved revision is not evidence
|
|
328
|
+
// of a concurrent edit: it is what that save leaves behind when it
|
|
329
|
+
// committed. Replaying it under the baseline it was sent with lets the site
|
|
330
|
+
// answer already-current, or apply it if it never committed; anything else
|
|
331
|
+
// it refuses itself. A pending record for a different change set proves
|
|
332
|
+
// nothing about the site and takes the ordinary path.
|
|
333
|
+
const changeSet = buildChangeSet(validated);
|
|
334
|
+
const changeSetHash = computePresentationChangeSetHash(changeSet);
|
|
335
|
+
const pending = readPendingPresentationSave(manifest);
|
|
336
|
+
const replayable = pending !== undefined && pending.changeSetHash === changeSetHash;
|
|
337
|
+
const differences = describeDifferences(validated, current);
|
|
338
|
+
return {
|
|
339
|
+
baseline,
|
|
340
|
+
current,
|
|
341
|
+
stale,
|
|
342
|
+
changeSet,
|
|
343
|
+
changeSetHash,
|
|
344
|
+
pending,
|
|
345
|
+
replayable,
|
|
346
|
+
replaying: stale && replayable,
|
|
347
|
+
differences,
|
|
348
|
+
changed: differences.some((entry) => entry.paths.length > 0 || entry.truncated === true),
|
|
349
|
+
};
|
|
350
|
+
}
|
|
351
|
+
|
|
289
352
|
export async function themePush(invocation) {
|
|
290
353
|
const session = await openSession(invocation);
|
|
291
354
|
const { client, config, siteId, onProgress } = session;
|
|
@@ -307,12 +370,7 @@ export async function themePush(invocation) {
|
|
|
307
370
|
requireFooterContentPushed(appearanceContext.footer, publishing.footerSettings);
|
|
308
371
|
const baseline = readPresentationBaseline(appearanceContext.manifest);
|
|
309
372
|
if (!dryRun && baseline === undefined) {
|
|
310
|
-
throw
|
|
311
|
-
"theme.pull_required",
|
|
312
|
-
"The pull manifest records no presentation baseline, so this push has no revision to be fenced by. Run "
|
|
313
|
-
+ "'taproot-site pull' against a Taproot that serves the atomic presentation save, then retry 'theme push'.",
|
|
314
|
-
{ field: "presentation.revision" },
|
|
315
|
-
);
|
|
373
|
+
throw presentationPullRequired();
|
|
316
374
|
}
|
|
317
375
|
onProgress(`Validated the complete light/dark theme pair and ${scalarOperations.length} appearance settings.`);
|
|
318
376
|
for (const warning of themes.warnings) onProgress(`Espalier warning: ${warning}`);
|
|
@@ -329,29 +387,11 @@ export async function themePush(invocation) {
|
|
|
329
387
|
// The fresh read serves both modes: the dry run compares against it, and
|
|
330
388
|
// the push takes the footer document's draft token from it. Nothing before
|
|
331
389
|
// this point, and nothing in a dry run after it, writes to the site.
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
} catch (error) {
|
|
336
|
-
throw translateServerSupport(error, "read");
|
|
337
|
-
}
|
|
338
|
-
const stale = baseline !== undefined && baseline.revision !== current.revision;
|
|
339
|
-
// A save this workspace sent and never heard back from (TR00807). When the
|
|
340
|
-
// change set about to go is the same one, a moved revision is not evidence
|
|
341
|
-
// of a concurrent edit: it is what that save leaves behind when it
|
|
342
|
-
// committed. Replaying it under the baseline it was sent with lets the site
|
|
343
|
-
// answer already-current, or apply it if it never committed; anything else
|
|
344
|
-
// it refuses itself. A pending record for a different change set proves
|
|
345
|
-
// nothing about the site and takes the ordinary path.
|
|
346
|
-
const changeSet = buildChangeSet(validated);
|
|
347
|
-
const changeSetHash = computePresentationChangeSetHash(changeSet);
|
|
348
|
-
const pending = readPendingPresentationSave(appearanceContext.manifest);
|
|
349
|
-
const replayable = pending !== undefined && pending.changeSetHash === changeSetHash;
|
|
350
|
-
const replaying = stale && replayable;
|
|
390
|
+
const comparison = await withRefusalGuidance(onProgress, "theme push", async () =>
|
|
391
|
+
await comparePresentation(client, siteId, validated, appearanceContext.manifest));
|
|
392
|
+
const { current, stale, changeSet, changeSetHash, pending, replayable, replaying, differences, changed } = comparison;
|
|
351
393
|
|
|
352
394
|
if (dryRun) {
|
|
353
|
-
const differences = describeDifferences(validated, current);
|
|
354
|
-
const changed = differences.some((entry) => entry.paths.length > 0 || entry.truncated === true);
|
|
355
395
|
for (const entry of differences) {
|
|
356
396
|
if (entry.paths.length === 0 && entry.truncated !== true) continue;
|
|
357
397
|
onProgress(`${entry.file} differs at: ${entry.paths.join(", ")}${entry.truncated ? ", and more" : ""}.`);
|
|
@@ -401,15 +441,7 @@ export async function themePush(invocation) {
|
|
|
401
441
|
+ "it. The pull that refreshes the baseline shows what the site holds now.",
|
|
402
442
|
);
|
|
403
443
|
}
|
|
404
|
-
|
|
405
|
-
throw new SiteAuthoringError(
|
|
406
|
-
"theme.concurrent_modification",
|
|
407
|
-
`The site's presentation changed after this workspace was pulled (revision ${baseline.revision} → `
|
|
408
|
-
+ `${current.revision}), so nothing was written. Keep copies of the edited settings files, run `
|
|
409
|
-
+ "'taproot-site pull' to refresh the baseline, re-apply the edits, and push again; the paths below name "
|
|
410
|
-
+ "where the workspace and the site now differ.",
|
|
411
|
-
{ field: "revision", alternatives: differences.filter((entry) => entry.paths.length > 0).map((entry) => entry.file) },
|
|
412
|
-
).withDifferences(differences.flatMap((entry) => entry.paths.map((path) => `${entry.file}:${path}`)));
|
|
444
|
+
throw presentationMovedRefusal(comparison);
|
|
413
445
|
}
|
|
414
446
|
|
|
415
447
|
const expectedRevision = replaying ? pending.expectedRevision : baseline.revision;
|