Skip to content

Commit

Permalink
Make the public invalidate invalidate more things
Browse files Browse the repository at this point in the history
Signed-off-by: William So <polyipseity@gmail.com>
  • Loading branch information
polyipseity committed Aug 18, 2023
1 parent fdbca01 commit 58abf99
Show file tree
Hide file tree
Showing 5 changed files with 252 additions and 130 deletions.
5 changes: 5 additions & 0 deletions .changeset/wet-coins-change.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"obsidian-modules": minor
---

Make the public `invalidate` invalidate more things.
36 changes: 30 additions & 6 deletions sources/@types/obsidian-modules.ts
Original file line number Diff line number Diff line change
Expand Up @@ -43,8 +43,16 @@ declare module "obsidian-modules" {
* Invalidate the cache of a module or an alias.
*
* @param id module specifier
* @returns void
*/
readonly invalidate: (id: string) => void
readonly invalidate: (id: string) => AsyncOrSync<void>

/**
* Invalidate all caches.
*
* @returns void
*/
readonly invalidateAll: () => AsyncOrSync<void>

/**
* Object for resolving module specifiers.
Expand Down Expand Up @@ -140,6 +148,11 @@ declare module "obsidian-modules" {
*/
interface Resolve {

/**
* Module resolution invalidation event.
*/
readonly onInvalidate: EventEmitterLite<readonly [id: string]>

/**
* Resolves a module specifier.
*
Expand All @@ -158,6 +171,21 @@ declare module "obsidian-modules" {
readonly aresolve: (
...args: Parameters<Resolve["resolve"]>
) => AsyncOrSync<ReturnType<Resolve["resolve"]>>

/**
* Invalidate the cache of a module resolution.
*
* @param id module specifier
* @returns void
*/
readonly invalidate: (id: string) => AsyncOrSync<void>

/**
* Invalidate all caches.
*
* @returns void
*/
readonly invalidateAll: () => AsyncOrSync<void>
}

/**
Expand Down Expand Up @@ -214,12 +242,8 @@ declare module "obsidian-modules" {
* Identity of the parent module being loaded.
*/
parent?: string | undefined

/**
* Current {@link Require}.
*/
readonly require: Require
}
}
import type { } from "obsidian-modules"
import type { AsyncOrSync } from "ts-essentials"
import type { EventEmitterLite } from "@polyipseity/obsidian-plugin-library"
65 changes: 38 additions & 27 deletions sources/require/require.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import {
Functions,
aroundIdentityFactory,
attachFunctionSourceMap,
clearProperties,
launderUnchecked,
patchWindows,
promisePromise,
Expand Down Expand Up @@ -71,20 +72,40 @@ function createRequire(
resolve: Resolve,
sourceRoot = "",
): Require {
function invalidate(self2: Require, id: string): void {
const { aliased, aliases, cache, dependants, dependencies } = self2,
id2 = aliased[id] ?? id,
seen = new Set(),
ing = [...aliases[id2] ?? [id2]]
for (let cur = ing.shift(); cur !== void 0; cur = ing.shift()) {
if (seen.has(cur)) { continue }
seen.add(cur)
// eslint-disable-next-line @typescript-eslint/no-dynamic-delete
delete cache[cur]
const dependencies2 = dependencies[cur]
for (const dep of dependencies2 ?? []) {
dependants[dep]?.delete(cur)
}
dependencies2?.clear()
for (const dep of dependants[cur] ?? []) {
ing.push(...aliases[dep] ?? [dep])
}
}
}
function resolve0(
self1: Require,
self2: Require,
id: string,
resolved: Resolved | null,
): readonly [Resolved, ModuleCache] {
if (!resolved) { throw new Error(id) }
const { id: id2 } = resolved,
{ aliased, aliased: { [id]: oldID }, aliases, cache } = self1
{ aliased, aliased: { [id]: oldID }, aliases, cache } = self2
aliased[id] = id2;
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
(aliases[id2] ??= new Set([id2])).add(id)
if (oldID !== void 0 && id2 !== oldID) {
aliases[oldID]?.delete(id)
self1.invalidate(id)
invalidate(self2, id)
}
if (resolved.cache === false) {
// eslint-disable-next-line @typescript-eslint/no-dynamic-delete
Expand Down Expand Up @@ -206,11 +227,7 @@ function createRequire(
aliased: {},
aliases: {},
cache: {},
context: {
cwds: [],
dependencies: new WeakMap(),
get require() { return ret },
},
context: { cwds: [] } satisfies Context,
dependants: {},
dependencies: {},
async import(id0: string, opts?: ImportOptions) {
Expand Down Expand Up @@ -422,28 +439,22 @@ function createRequire(
cleanup.call()
}
},
invalidate(id: string) {
const { aliased, aliases, cache, dependants, dependencies } = ret,
id2 = aliased[id] ?? id,
seen = new Set(),
ing = [...aliases[id2] ?? [id2]]
for (let cur = ing.shift(); cur !== void 0; cur = ing.shift()) {
if (seen.has(cur)) { continue }
seen.add(cur)
// eslint-disable-next-line @typescript-eslint/no-dynamic-delete
delete cache[cur]
const dependencies2 = dependencies[cur]
for (const dep of dependencies2 ?? []) {
dependants[dep]?.delete(cur)
}
dependencies2?.clear()
for (const dep of dependants[cur] ?? []) {
ing.push(...aliases[dep] ?? [dep])
}
}
async invalidate(id: string) {
invalidate(ret, id)
await resolve.invalidate(id)
},
async invalidateAll() {
const { aliased, aliases, cache, dependants, dependencies } = ret
clearProperties(cache)
clearProperties(dependants)
clearProperties(dependencies)
clearProperties(aliased)
clearProperties(aliases)
await resolve.invalidateAll()
},
resolve,
})
resolve.onInvalidate.listen(id => { invalidate(ret, id) })
return ret
}

Expand Down
Loading

0 comments on commit 58abf99

Please sign in to comment.