better code
Massimo Melina committed
Sep 20, 2023 at 21:53 UTC
d58887c5afc703b887e467798c988137e234610c
8 files changed
+49
-50
README.md
+1
-1
@@ -68,7 +68,7 @@ If you don't like this behavior, disable it in the Admin-panel or enter this con
68
69
If your system is not Windows/Linux/Mac or you just don't want to run the binaries, you can try this alternative version:
70
71
-1. [install node.js](https://nodejs.org)
71
+1. [install node.js](https://nodejs.org) version 18
72
2. execute at command line `npx hfs@latest`
73
74
The `@latest` part is optional, and ensures that you are always up to date.
mui-grid-form/index.ts
+3
-1
@@ -34,16 +34,18 @@ export interface FieldDescriptor<T=any> extends FieldApi<T> {
34
fromField?: (v: any) => T
35
before?: ReactNode
36
after?: ReactNode
37
+ getError?: GetError
38
[extraProp: string]: any
39
}
40
41
// it seems necessary to cast (Multi)SelectField sometimes
42
export type Field<T> = FC<FieldProps<T>>
43
44
+type GetError = (v: any, extra?: any) => Promisable<ValidationError>
45
export type Promisable<T> = T | Promise<T>
46
interface FieldApi<T> {
47
// provide getError if you want your error to be visible by the Form component
46
- getError?: (v: any, extra?: any) => Promisable<ValidationError>
48
+ getError?: GetError
49
isEqual?: (a: T, b: T) => boolean,
50
}
51
export interface FieldProps<T> {
plugins/download-counter/plugin.js
+14
-15
@@ -44,21 +44,20 @@ exports.init = async api => {
44
frontend_js: 'main.js',
45
frontend_css: 'style.css',
46
unload: () => save.flush(), // we may have pending savings
47
- middleware: (ctx) =>
48
- () => { // execute after other middlewares are done
49
- if (ctx.status >= 300 || ctx.state.download_counter_ignore || ctx.state.includesLastByte === false) return
50
- if (!(ctx.vfsNode || api.getConfig('archives') && ctx.state.archive)) return
51
- ctx.state.completed.then(() => {
52
- const key = uri2key(ctx.path)
53
- const entries = ctx.vfsNode ? [key]
54
- : ctx.state.originalStream?.getArchiveEntries?.().filter(x => x.at(-1) !== '/').map(x => key + uri2key(x))
55
- if (!entries) return
56
- for (const k of entries)
57
- counters[k] = counters[k] + 1 || 1
58
- save()
59
- })
60
- },
61
- onDirEntry: ({ entry, listUri }) => {
47
+ middleware: ctx => () => { // callback = execute after other middlewares are done
48
+ if (ctx.status >= 300 || ctx.state.download_counter_ignore || ctx.state.includesLastByte === false) return
49
+ if (!(ctx.vfsNode || api.getConfig('archives') && ctx.state.archive)) return
50
+ ctx.state.completed.then(() => {
51
+ const key = uri2key(ctx.path)
52
+ const entries = ctx.vfsNode ? [key]
53
+ : ctx.state.originalStream?.getArchiveEntries?.().filter(x => x.at(-1) !== '/').map(x => key + uri2key(x))
54
+ if (!entries) return
55
+ for (const k of entries)
56
+ counters[k] = counters[k] + 1 || 1
57
+ save()
58
+ })
59
+ },
60
+ onDirEntry({ entry, listUri }) {
61
const k = uri2key(listUri + entry.n)
62
const n = counters[k]
63
if (n)
src/api.plugins.ts
+1
-1
@@ -28,7 +28,7 @@ import { HTTP_FAILED_DEPENDENCY, HTTP_NOT_FOUND, HTTP_SERVER_ERROR } from './con
28
const apis: ApiHandlers = {
29
30
get_plugins({}, ctx) {
31
- const list = new SendListReadable({ addAtStart: [ ...mapPlugins(serialize), ...getAvailablePlugins().map(serialize) ] })
31
+ const list = new SendListReadable({ addAtStart: [ ...mapPlugins(serialize, false), ...getAvailablePlugins().map(serialize) ] })
32
return list.events(ctx, {
33
pluginInstalled: p => list.add(serialize(p)),
34
'pluginStarted pluginStopped pluginUpdated': p => {
src/config.ts
+2
-5
@@ -5,7 +5,7 @@ import { argv, ORIGINAL_CWD, VERSION } from './const'
5
import { watchLoad } from './watchLoad'
6
import yaml from 'yaml'
7
import _ from 'lodash'
8
-import { DAY, debounceAsync, newObj, onOff, tryJson, wait, with_ } from './misc'
8
+import { DAY, debounceAsync, newObj, onOff, throw_, tryJson, wait, with_ } from './misc'
9
import { statSync } from 'fs'
10
import { join, resolve } from 'path'
11
import events from './events'
@@ -86,10 +86,7 @@ export function defineConfig<T, CT=T>(k: string, defaultValue: T, compiler?: Sub
86
else
87
setConfig1(k, v)
88
},
89
- compiled: () => {
90
- if (!compiler) throw "missing compiler"
91
- return compiled as CT
92
- }
89
+ compiled: () => compiled ?? throw_("missing compiler"),
90
}
91
if (compiler)
92
ret.sub((...args) =>
src/cross.ts
+5
@@ -88,6 +88,11 @@ export function _log(...args: any[]) {
88
return args[args.length-1]
89
}
90
91
+export function _dbg(x: any) {
92
+ debugger
93
+ return x
94
+}
95
+
96
export type PendingPromise<T=unknown> = Promise<T> & { resolve: (value?: T) => void, reject: (reason?: any) => void }
97
export function pendingPromise<T>() {
98
let takeOut
src/debounceAsync.ts
+1
@@ -19,6 +19,7 @@ export default function debounceAsync<Cancelable extends boolean = false, A exte
19
let lastSince = 0
20
const interceptingWrapper = (...args: A) => runningDebouncer = debouncer(...args)
21
return Object.assign(interceptingWrapper, {
22
+ clearRetain: () => last = undefined,
23
flush: () => runningCallback ?? exec(),
24
...cancelable && {
25
cancel() {
src/plugins.ts
+22
-27
@@ -7,18 +7,8 @@ import { API_VERSION, APP_PATH, COMPATIBLE_API_VERSION, IS_WINDOWS, PLUGINS_PUB_
7
import * as Const from './const'
8
import Koa from 'koa'
9
import {
10
- adjustStaticPathForGlob,
11
- Callback,
12
- debounceAsync,
13
- Dict,
14
- getOrSet,
15
- onProcessExit,
16
- PendingPromise, pendingPromise,
17
- same,
18
- tryJson,
19
- wait,
20
- wantArray,
21
- watchDir
10
+ adjustStaticPathForGlob, Callback, debounceAsync, Dict, getOrSet, onProcessExit,
11
+ PendingPromise, pendingPromise, same, tryJson, wait, wantArray, watchDir
12
} from './misc'
13
import { defineConfig, getConfig } from './config'
14
import { DirEntry } from './api.file_list'
@@ -89,19 +79,12 @@ export function setPluginConfig(id: string, changes: Dict) {
79
}
80
81
export function getPluginInfo(id: string) {
82
+ if (id === SERVER_CODE_ID)
83
+ return serverCodeReturned
84
const running = plugins[id]?.getData()
85
return running && Object.assign(running, {id}) || availablePlugins[id]
86
}
87
96
-export function mapPlugins<T>(cb:(plugin:Readonly<Plugin>, pluginName:string)=> T) {
97
- return _.map(plugins, (pl,plName) => {
98
- try { return cb(pl,plName) }
99
- catch(e) {
100
- console.log('plugin error', plName, String(e))
101
- }
102
- }).filter(x => x !== undefined) as Exclude<T,undefined>[]
103
-}
104
-
88
export function findPluginByRepo<T>(repo: string) {
89
return _.find(plugins, pl => match(pl.getData()))
90
|| _.find(availablePlugins, match)
@@ -126,6 +109,21 @@ const serverCode = defineConfig('server_code', '', async (script, { k }) => {
109
}
110
})
111
112
+const SERVER_CODE_ID = '.'
113
+let serverCodeReturned: any
114
+serverCode.sub(() => serverCode.compiled().then(x => serverCodeReturned = x))
115
+export function mapPlugins<T>(cb:(plugin:Readonly<Plugin>, pluginName:string)=> T, includeServerCode=true) {
116
+ const entries = Object.entries(plugins)
117
+ if (includeServerCode && serverCodeReturned)
118
+ entries.push([SERVER_CODE_ID, serverCodeReturned])
119
+ return entries.map(([plName,pl]) => {
120
+ try { return cb(pl,plName) }
121
+ catch(e) {
122
+ console.log('plugin error', plName, String(e))
123
+ }
124
+ }).filter(x => x !== undefined) as Exclude<T,undefined>[]
125
+}
126
+
127
async function initPlugin<T>(pl: any, more?: T) {
128
return Object.assign(pl, await pl.init?.({
129
const: Const, // legacy, deprecated in 0.48
@@ -143,11 +141,7 @@ async function initPlugin<T>(pl: any, more?: T) {
141
export const pluginsMiddleware: Koa.Middleware = async (ctx, next) => {
142
const after: Dict<CallMeAfter> = {}
143
// run middleware plugins
146
- const entries = Object.entries(plugins)
147
- const sc = await serverCode.compiled()
148
- if (sc)
149
- entries.push(['.', await serverCode.compiled()])
150
- for (const [id,pl] of entries)
144
+ await Promise.all(mapPlugins(async (pl, id) => {
145
try {
146
const res = await pl.middleware?.(ctx)
147
if (res === true)
@@ -158,7 +152,8 @@ export const pluginsMiddleware: Koa.Middleware = async (ctx, next) => {
152
catch(e){
153
printError(id, e)
154
}
161
- // expose public plugins' files
155
+ }))
156
+ // expose public plugins' files`
157
if (!ctx.pluginBlockedRequest) {
158
const { path } = ctx
159
if (path.startsWith(PLUGINS_PUB_URI)) {