Skip to content

feat(h5p-author): export the library loader and the text checks, on the player's library rules - #110

Merged
alekswebnet merged 2 commits into
mainfrom
feat/author-library-loader
Nov 2, 2026
Merged

alekswebnet merged 2 commits into
mainfrom
feat/author-library-loader

Conversation

@alekswebnet

@alekswebnet alekswebnet commented Nov 2, 2026 •

Copy link
Copy Markdown
Contributor

Closes #106.

What

h5p-author exports what a tool beside the build needs (embed-my/creator's outline and apply), and stops keeping its own versions of the player's library rules.

The player exports its library rules at a new subpath, ./plan, built to dist/h5p-plan.js (7.7 kB, not minified):

  • planPack, plus librariesNamedIn, addonPatterns, textMatches and dependenciesIn. The last four moved out of sw/package-reader.ts, which loads zip.js, into src/shared/content-libraries.ts. The Service Worker imports them from there, and the build fails if zip.js ever gets into h5p-plan.js.
  • build:plan builds that file on its own. prepare:dev and h5p-author's tests run it, since h5p-author imports it as it runs.
  • ./plan is not named in docs/compatibility.md, which now says so, so h5p-author depends on the player's exact version (workspace:*).

h5p-author exports:

  • openPack(libraries?), the pack buildPackage opens.

  • loadLibraries(pack, { type, language, params }), now in lib/libraries.mjs, which has no Node import of its own. It loads, as the build does:

    • the content type, every library the parameters name, and a library field's default;
    • each one's translations, then patchSemantics;
    • every other library of the pack, without its semantics.

    buildPackage calls it. It takes any object with libraries, newest, open and translation, so h5p-author: a check of saved content, which the build also runs on what it writes #107 can pass one built on a package's own folders.

  • markupText, plainText and allowedTags.

Pack.open now returns { folder, library, semantics, index, translations }, with translations as names. The part's file and zip.js's reader stay inside the pack, so no zip.js type is in the published declarations, and the build reaches them through an @internal archiveOf. SourceError moved to lib/source-error.mjs, and build.mjs re-exports it.

Reuse

  • buildPackage now plans the parts a package carries with the player's planPack, for a package that carries nothing yet, in place of its own closure. Addons go through the player's patterns, so a package carries what the player would take from the pack for it.

  • Two things stay in h5p-author:

    • a check that every library the content and the parts name was planned, because the plan leaves a gap without saying so;
    • the order the build has always listed libraries in: depth first, which h5p.json and the zip's folders follow.

    On the plan's own order, breadth first, all five sources I first tried listed their libraries differently. The runtime keeps the listed order between libraries that don't depend on each other, and that order decides whose stylesheet comes later.

  • The old closure also followed dynamicDependencies. No library in the pack has any (checked today).

  • Not reused: the runtime's library-name parser, content check and content upgrade. They are GPL-3.0-only, and h5p-author is MIT.

  • embed's SCORM writer still carries copies of these functions: embed: plan the SCORM zip's parts with the player's own functions, not copies #109.

Checks

  • Same output as main: all 32 type files' examples (28 content types and the four parts types), media included, built with this branch and with main. Each came out with the same libraries, in the same order, the same folders and the same notes.
  • Typecheck: pnpm typecheck passes, every package. That includes the player's consumer check, which now imports ./plan under nodenext, and h5p-author's package-types.ts, which imports the new exports and expects part.file and archiveOf to be errors.
  • Player: the unit suite passes (358). The browser suite's pack.test.ts and libraries.test.ts pass (39), and the full build passes.
  • h5p-author: 108 tests pass, including the new libraries.test.ts, which covers:
    • a library named in the parameters, with and without a version;
    • a library field's default (Interactive Video's summary task);
    • the German translation;
    • the Video poster made optional, while the pack's own semantics stay as they are;
    • the rest of the pack without semantics;
    • another source with the pack's members;
    • an unknown type as a SourceError.
  • apps/skills: 73 pass. Every example builds and plays trusted and untrusted with no warnings, and the quiz plays through in the preview.
  • The demo: the sweep's sweep-content.test.ts passes (5).

The full browser suite in all three engines is left to CI.

Release

Publish the player before h5p-author: the author pins the player's exact version, and needs a version that has ./plan.

Next

After review

A self-review of the branch found the following, fixed in the second commit:

  • prepublishOnly guards the player pin as it guards the pack's: check-pack-published.mjs refuses to publish until the pinned player version is on npm and exports ./plan. Today it refuses, correctly: 1.2.0 is on npm without ./plan.
  • build.test.ts holds a build's h5p.json to the depth-first order, derived from the zip's own library.json files, and checks that True/False's dependencies come before the text beside it. Run against the plan's breadth-first order, the test fails.
  • Pack.close() closes each part on its own again, so one that fails to close leaves no other open.
  • The addon note lists addons alone, not what an addon would need in turn (none needs anything today).
  • loadLibraries finds the main library by folder rather than identity, for a LibrarySource that builds its records on each call.
  • Docs: the README and the module header say what is exported, the libraries as the build loads them, the generator and the text rules, and that the layouts and the source check are not. LibraryRecord and TranslationReport are exported as types.

🤖 Generated with Claude Code

alekswebnet and others added 2 commits November 2, 2026 14:54
…he player's library rules (#106)

The player exports its library rules at ./plan: planPack, librariesNamedIn, addonPatterns,
textMatches and dependenciesIn, the last four moved out of package-reader.ts into a module without
zip.js, built to dist/h5p-plan.js. h5p-author plans the parts a package carries with planPack in
place of its own closure, keeping the order it has always listed them in, and exports openPack,
loadLibraries and the text checks for a tool beside the build. Every type file's example builds
with the libraries, order, folders and notes it had before.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
… player pin, the library order held by a test, three small fixes

- check-pack-published.mjs refuses to publish until the pinned player version is on npm and exports ./plan: 1.2.0 is there without it, and the author would install and fail on its first import
- build.test.ts holds a build's h5p.json to the depth-first order, derived from the zip's own library.json files; it fails on the plan's breadth-first order
- Pack.close() closes each part on its own, so one that fails to close leaves no other open
- the addon note lists addons alone, not what an addon would need in turn
- loadLibraries finds the main library by folder, not identity, for a LibrarySource that builds its records on each call
- the README and author.mjs say what is exported, and LibraryRecord and TranslationReport are exported as types

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
@alekswebnet
alekswebnet merged commit 0492ebd into main Nov 2, 2026
9 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

h5p-author: export the library loader and the text checks, on the player's library rules

1 participant