Skip to content

Commit 974fa1b

Browse files
authored
refactor: unwrap PluginMeta namespace + self-reexport (#22945)
1 parent fb02744 commit 974fa1b

1 file changed

Lines changed: 147 additions & 147 deletions

File tree

  • packages/opencode/src/plugin

packages/opencode/src/plugin/meta.ts

Lines changed: 147 additions & 147 deletions
Original file line numberDiff line numberDiff line change
@@ -8,181 +8,181 @@ import { Flock } from "@opencode-ai/shared/util/flock"
88

99
import { parsePluginSpecifier, pluginSource } from "./shared"
1010

11-
export namespace PluginMeta {
12-
type Source = "file" | "npm"
13-
14-
export type Theme = {
15-
src: string
16-
dest: string
17-
mtime?: number
18-
size?: number
19-
}
11+
type Source = "file" | "npm"
2012

21-
export type Entry = {
22-
id: string
23-
source: Source
24-
spec: string
25-
target: string
26-
requested?: string
27-
version?: string
28-
modified?: number
29-
first_time: number
30-
last_time: number
31-
time_changed: number
32-
load_count: number
33-
fingerprint: string
34-
themes?: Record<string, Theme>
35-
}
13+
export type Theme = {
14+
src: string
15+
dest: string
16+
mtime?: number
17+
size?: number
18+
}
3619

37-
export type State = "first" | "updated" | "same"
20+
export type Entry = {
21+
id: string
22+
source: Source
23+
spec: string
24+
target: string
25+
requested?: string
26+
version?: string
27+
modified?: number
28+
first_time: number
29+
last_time: number
30+
time_changed: number
31+
load_count: number
32+
fingerprint: string
33+
themes?: Record<string, Theme>
34+
}
3835

39-
export type Touch = {
40-
spec: string
41-
target: string
42-
id: string
43-
}
36+
export type State = "first" | "updated" | "same"
4437

45-
type Store = Record<string, Entry>
46-
type Core = Omit<Entry, "first_time" | "last_time" | "time_changed" | "load_count" | "fingerprint" | "themes">
47-
type Row = Touch & { core: Core }
38+
export type Touch = {
39+
spec: string
40+
target: string
41+
id: string
42+
}
4843

49-
function storePath() {
50-
return Flag.OPENCODE_PLUGIN_META_FILE ?? path.join(Global.Path.state, "plugin-meta.json")
51-
}
44+
type Store = Record<string, Entry>
45+
type Core = Omit<Entry, "first_time" | "last_time" | "time_changed" | "load_count" | "fingerprint" | "themes">
46+
type Row = Touch & { core: Core }
5247

53-
function lock(file: string) {
54-
return `plugin-meta:${file}`
55-
}
48+
function storePath() {
49+
return Flag.OPENCODE_PLUGIN_META_FILE ?? path.join(Global.Path.state, "plugin-meta.json")
50+
}
5651

57-
function fileTarget(spec: string, target: string) {
58-
if (spec.startsWith("file://")) return fileURLToPath(spec)
59-
if (target.startsWith("file://")) return fileURLToPath(target)
60-
return
61-
}
52+
function lock(file: string) {
53+
return `plugin-meta:${file}`
54+
}
6255

63-
async function modifiedAt(file: string) {
64-
const stat = await Filesystem.statAsync(file)
65-
if (!stat) return
66-
const mtime = stat.mtimeMs
67-
return Math.floor(typeof mtime === "bigint" ? Number(mtime) : mtime)
68-
}
56+
function fileTarget(spec: string, target: string) {
57+
if (spec.startsWith("file://")) return fileURLToPath(spec)
58+
if (target.startsWith("file://")) return fileURLToPath(target)
59+
return
60+
}
6961

70-
function resolvedTarget(target: string) {
71-
if (target.startsWith("file://")) return fileURLToPath(target)
72-
return target
73-
}
62+
async function modifiedAt(file: string) {
63+
const stat = await Filesystem.statAsync(file)
64+
if (!stat) return
65+
const mtime = stat.mtimeMs
66+
return Math.floor(typeof mtime === "bigint" ? Number(mtime) : mtime)
67+
}
7468

75-
async function npmVersion(target: string) {
76-
const resolved = resolvedTarget(target)
77-
const stat = await Filesystem.statAsync(resolved)
78-
const dir = stat?.isDirectory() ? resolved : path.dirname(resolved)
79-
return Filesystem.readJson<{ version?: string }>(path.join(dir, "package.json"))
80-
.then((item) => item.version)
81-
.catch(() => undefined)
82-
}
69+
function resolvedTarget(target: string) {
70+
if (target.startsWith("file://")) return fileURLToPath(target)
71+
return target
72+
}
8373

84-
async function entryCore(item: Touch): Promise<Core> {
85-
const spec = item.spec
86-
const target = item.target
87-
const source = pluginSource(spec)
88-
if (source === "file") {
89-
const file = fileTarget(spec, target)
90-
return {
91-
id: item.id,
92-
source,
93-
spec,
94-
target,
95-
modified: file ? await modifiedAt(file) : undefined,
96-
}
97-
}
74+
async function npmVersion(target: string) {
75+
const resolved = resolvedTarget(target)
76+
const stat = await Filesystem.statAsync(resolved)
77+
const dir = stat?.isDirectory() ? resolved : path.dirname(resolved)
78+
return Filesystem.readJson<{ version?: string }>(path.join(dir, "package.json"))
79+
.then((item) => item.version)
80+
.catch(() => undefined)
81+
}
9882

83+
async function entryCore(item: Touch): Promise<Core> {
84+
const spec = item.spec
85+
const target = item.target
86+
const source = pluginSource(spec)
87+
if (source === "file") {
88+
const file = fileTarget(spec, target)
9989
return {
10090
id: item.id,
10191
source,
10292
spec,
10393
target,
104-
requested: parsePluginSpecifier(spec).version,
105-
version: await npmVersion(target),
94+
modified: file ? await modifiedAt(file) : undefined,
10695
}
10796
}
10897

109-
function fingerprint(value: Core) {
110-
if (value.source === "file") return [value.target, value.modified ?? ""].join("|")
111-
return [value.target, value.requested ?? "", value.version ?? ""].join("|")
98+
return {
99+
id: item.id,
100+
source,
101+
spec,
102+
target,
103+
requested: parsePluginSpecifier(spec).version,
104+
version: await npmVersion(target),
112105
}
106+
}
113107

114-
async function read(file: string): Promise<Store> {
115-
return Filesystem.readJson<Store>(file).catch(() => ({}) as Store)
116-
}
108+
function fingerprint(value: Core) {
109+
if (value.source === "file") return [value.target, value.modified ?? ""].join("|")
110+
return [value.target, value.requested ?? "", value.version ?? ""].join("|")
111+
}
117112

118-
async function row(item: Touch): Promise<Row> {
119-
return {
120-
...item,
121-
core: await entryCore(item),
122-
}
123-
}
113+
async function read(file: string): Promise<Store> {
114+
return Filesystem.readJson<Store>(file).catch(() => ({}) as Store)
115+
}
124116

125-
function next(prev: Entry | undefined, core: Core, now: number): { state: State; entry: Entry } {
126-
const entry: Entry = {
127-
...core,
128-
first_time: prev?.first_time ?? now,
129-
last_time: now,
130-
time_changed: prev?.time_changed ?? now,
131-
load_count: (prev?.load_count ?? 0) + 1,
132-
fingerprint: fingerprint(core),
133-
themes: prev?.themes,
134-
}
135-
const state: State = !prev ? "first" : prev.fingerprint === entry.fingerprint ? "same" : "updated"
136-
if (state === "updated") entry.time_changed = now
137-
return {
138-
state,
139-
entry,
140-
}
117+
async function row(item: Touch): Promise<Row> {
118+
return {
119+
...item,
120+
core: await entryCore(item),
141121
}
122+
}
142123

143-
export async function touchMany(items: Touch[]): Promise<Array<{ state: State; entry: Entry }>> {
144-
if (!items.length) return []
145-
const file = storePath()
146-
const rows = await Promise.all(items.map((item) => row(item)))
147-
148-
return Flock.withLock(lock(file), async () => {
149-
const store = await read(file)
150-
const now = Date.now()
151-
const out: Array<{ state: State; entry: Entry }> = []
152-
for (const item of rows) {
153-
const hit = next(store[item.id], item.core, now)
154-
store[item.id] = hit.entry
155-
out.push(hit)
156-
}
157-
await Filesystem.writeJson(file, store)
158-
return out
159-
})
124+
function next(prev: Entry | undefined, core: Core, now: number): { state: State; entry: Entry } {
125+
const entry: Entry = {
126+
...core,
127+
first_time: prev?.first_time ?? now,
128+
last_time: now,
129+
time_changed: prev?.time_changed ?? now,
130+
load_count: (prev?.load_count ?? 0) + 1,
131+
fingerprint: fingerprint(core),
132+
themes: prev?.themes,
133+
}
134+
const state: State = !prev ? "first" : prev.fingerprint === entry.fingerprint ? "same" : "updated"
135+
if (state === "updated") entry.time_changed = now
136+
return {
137+
state,
138+
entry,
160139
}
140+
}
161141

162-
export async function touch(spec: string, target: string, id: string): Promise<{ state: State; entry: Entry }> {
163-
return touchMany([{ spec, target, id }]).then((item) => {
164-
const hit = item[0]
165-
if (hit) return hit
166-
throw new Error("Failed to touch plugin metadata.")
167-
})
168-
}
142+
export async function touchMany(items: Touch[]): Promise<Array<{ state: State; entry: Entry }>> {
143+
if (!items.length) return []
144+
const file = storePath()
145+
const rows = await Promise.all(items.map((item) => row(item)))
146+
147+
return Flock.withLock(lock(file), async () => {
148+
const store = await read(file)
149+
const now = Date.now()
150+
const out: Array<{ state: State; entry: Entry }> = []
151+
for (const item of rows) {
152+
const hit = next(store[item.id], item.core, now)
153+
store[item.id] = hit.entry
154+
out.push(hit)
155+
}
156+
await Filesystem.writeJson(file, store)
157+
return out
158+
})
159+
}
169160

170-
export async function setTheme(id: string, name: string, theme: Theme): Promise<void> {
171-
const file = storePath()
172-
await Flock.withLock(lock(file), async () => {
173-
const store = await read(file)
174-
const entry = store[id]
175-
if (!entry) return
176-
entry.themes = {
177-
...entry.themes,
178-
[name]: theme,
179-
}
180-
await Filesystem.writeJson(file, store)
181-
})
182-
}
161+
export async function touch(spec: string, target: string, id: string): Promise<{ state: State; entry: Entry }> {
162+
return touchMany([{ spec, target, id }]).then((item) => {
163+
const hit = item[0]
164+
if (hit) return hit
165+
throw new Error("Failed to touch plugin metadata.")
166+
})
167+
}
183168

184-
export async function list(): Promise<Store> {
185-
const file = storePath()
186-
return Flock.withLock(lock(file), async () => read(file))
187-
}
169+
export async function setTheme(id: string, name: string, theme: Theme): Promise<void> {
170+
const file = storePath()
171+
await Flock.withLock(lock(file), async () => {
172+
const store = await read(file)
173+
const entry = store[id]
174+
if (!entry) return
175+
entry.themes = {
176+
...entry.themes,
177+
[name]: theme,
178+
}
179+
await Filesystem.writeJson(file, store)
180+
})
188181
}
182+
183+
export async function list(): Promise<Store> {
184+
const file = storePath()
185+
return Flock.withLock(lock(file), async () => read(file))
186+
}
187+
188+
export * as PluginMeta from "./meta"

0 commit comments

Comments
 (0)