Anki/ts/lib/tslib/runtime-require.ts
Damien Elmes 9f55cf26fc
Switch to SvelteKit (#3077)
* Update to latest Node LTS

* Add sveltekit

* Split tslib into separate @generated and @tslib components

SvelteKit's path aliases don't support multiple locations, so our old
approach of using @tslib to refer to both ts/lib and out/ts/lib will no
longer work. Instead, all generated sources and their includes are
placed in a separate out/ts/generated folder, and imported via @generated
instead. This also allows us to generate .ts files, instead of needing
to output separate .d.ts and .js files.

* Switch package.json to module type

* Avoid usage of baseUrl

Incompatible with SvelteKit

* Move sass into ts; use relative links

SvelteKit's default sass support doesn't allow overriding loadPaths

* jest->vitest, graphs example working with yarn dev

* most pages working in dev mode

* Some fixes after rebasing

* Fix/silence some svelte-check errors

* Get image-occlusion working with Fabric types

* Post-rebase lock changes

* Editor is now checked

* SvelteKit build integrated into ninja

* Use the new SvelteKit entrypoint for pages like congrats/deck options/etc

* Run eslint once for ts/**; fix some tests

* Fix a bunch of issues introduced when rebasing over latest main

* Run eslint fix

* Fix remaining eslint+pylint issues; tests now all pass

* Fix some issues with a clean build

* Latest bufbuild no longer requires @__PURE__ hack

* Add a few missed dependencies

* Add yarn.bat to fix Windows build

* Fix pages failing to show when ANKI_API_PORT not defined

* Fix svelte-check and vitest on Windows

* Set node path in ./yarn

* Move svelte-kit output to ts/.svelte-kit

Sadly, I couldn't figure out a way to store it in out/ if out/ is
a symlink, as it breaks module resolution when SvelteKit is run.

* Allow HMR inside Anki

* Skip SvelteKit build when HMR is defined

* Fix some post-rebase issues

I should have done a normal merge instead.
2024-03-31 09:16:31 +01:00

102 lines
2.7 KiB
TypeScript

// Copyright: Ankitects Pty Ltd and contributors
// License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
/**
* Names of anki packages
*
* @privateRemarks
* Originally this was more strictly typed as a record:
* ```ts
* type AnkiPackages = {
* "anki/NoteEditor": NoteEditorPackage,
* }
* ```
* This would be very useful for `require`: the result could be strictly typed.
* However cross-module type imports currently don't work.
*/
type AnkiPackages =
| "anki/NoteEditor"
| "anki/EditorField"
| "anki/PlainTextInput"
| "anki/RichTextInput"
| "anki/TemplateButtons"
| "anki/packages"
| "anki/bridgecommand"
| "anki/shortcuts"
| "anki/theme"
| "anki/location"
| "anki/surround"
| "anki/ui"
| "anki/reviewer";
type PackageDeprecation<T extends Record<string, unknown>> = {
[key in keyof T]?: string;
};
/** This can be extended to allow require() calls at runtime, for packages
that are not included at bundling time. */
const runtimePackages: Partial<Record<AnkiPackages, Record<string, unknown>>> = {};
const prohibit = () => false;
/**
* Packages registered with this function escape the typing provided by `AnkiPackages`
*/
export function registerPackageRaw(
name: string,
entries: Record<string, unknown>,
): void {
runtimePackages[name] = entries;
}
export function registerPackage<
T extends AnkiPackages,
U extends Record<string, unknown>,
>(name: T, entries: U, deprecation?: PackageDeprecation<U>): void {
const pack = deprecation
? new Proxy(entries, {
set: prohibit,
defineProperty: prohibit,
deleteProperty: prohibit,
get: (target, name: string) => {
if (name in deprecation) {
console.log(`anki: ${name} is deprecated: ${deprecation[name]}`);
}
return target[name];
},
})
: entries;
registerPackageRaw(name, pack);
}
function require<T extends AnkiPackages>(name: T): Record<string, unknown> | undefined {
if (!(name in runtimePackages)) {
throw new Error(`Cannot require "${name}" at runtime.`);
} else {
return runtimePackages[name];
}
}
function listPackages(): string[] {
return Object.keys(runtimePackages);
}
function hasPackages(...names: string[]): boolean {
for (const name of names) {
if (!(name in runtimePackages)) {
return false;
}
}
return true;
}
// Export require() as a global.
Object.assign(globalThis, { require });
registerPackage("anki/packages", {
// We also register require here, so add-ons can have a type-save variant of require (TODO, see AnkiPackages above)
require,
listPackages,
hasPackages,
});