Merge pull request #134 from Flow-Works/feat/add-conditional-types-for-loadlibrary

Feat/add-conditional-types-for-loadlibrary
This commit is contained in:
ThinLiquid 2024-01-17 17:07:51 +00:00 committed by GitHub
commit 092a25d33a
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
10 changed files with 84 additions and 26 deletions

View file

@ -1,6 +1,6 @@
import semver from 'semver' import semver from 'semver'
import Kernel from '../kernel' import Kernel from '../kernel'
import { Process, Executable, LibraryData, Package, Library, Permission } from '../types' import { Process, Executable, Package, Library, Permission, LoadedLibrary, LibraryPath } from '../types'
import FlowWindow from './FlowWindow' import FlowWindow from './FlowWindow'
import LibraryLib from './LibraryLib' import LibraryLib from './LibraryLib'
import ProcLib from './ProcLib' import ProcLib from './ProcLib'
@ -57,7 +57,7 @@ export default class ProcessLib {
}) })
} }
async loadLibrary (url: string): Promise<LibraryData> { async loadLibrary <T extends LibraryPath>(url: T): Promise<LoadedLibrary<T>> {
let executable: Executable let executable: Executable
try { try {
const comps = import.meta.glob('../system/**/*.ts') const comps = import.meta.glob('../system/**/*.ts')

View file

@ -83,7 +83,7 @@ const BootLoader: Process = {
const files = await fs.readdir('/home/Applications/') const files = await fs.readdir('/home/Applications/')
files files
.filter((x: string) => x.endsWith('.app') && ((input.elm as HTMLInputElement) !== null ? x.toLowerCase().includes((input.elm as HTMLInputElement).value.toLowerCase()) : true)) .filter((x: string) => x.endsWith('.app') && ((input.elm as HTMLInputElement) !== null ? x.toLowerCase().includes((input.elm as HTMLInputElement).value.toLowerCase()) : true))
.forEach(async (file: string) => { .forEach((file: string) => {
fs.readFile(`/home/Applications/${file}`).then(async (data: Uint8Array) => { fs.readFile(`/home/Applications/${file}`).then(async (data: Uint8Array) => {
const path = Buffer.from(data).toString() const path = Buffer.from(data).toString()
const executable = await process.kernel.getExecutable(path) as Process const executable = await process.kernel.getExecutable(path) as Process
@ -97,7 +97,7 @@ const BootLoader: Process = {
alt: `${executable.config.name} icon` alt: `${executable.config.name} icon`
}).appendTo(appElement) }).appendTo(appElement)
new HTML('div').text(executable.config.name).appendTo(appElement) new HTML('div').text(executable.config.name).appendTo(appElement)
}) }).catch((e: any) => console.error(e))
}) })
} }
@ -129,11 +129,11 @@ const BootLoader: Process = {
setInterval((): any => { setInterval((): any => {
getTime().then((time) => { getTime().then((time) => {
statusBar.element.qs('div[data-toolbar-id="calendar"]').text(time) statusBar.element.qs('div[data-toolbar-id="calendar"]')?.text(time)
}).catch(e => console.error) }).catch(e => console.error)
}, 1000) }, 1000)
statusBar.element.qs('div[data-toolbar-id="start"]').on('click', () => { statusBar.element.qs('div[data-toolbar-id="start"]')?.on('click', () => {
launcher.toggle() launcher.toggle()
}) })
@ -180,11 +180,11 @@ const BootLoader: Process = {
e.detail.win.focus() e.detail.win.focus()
e.detail.win.toggleMin() e.detail.win.toggleMin()
}) })
).appendTo(statusBar.element.qs('div[data-toolbar-id="apps"]')) ).appendTo(statusBar.element.qs('div[data-toolbar-id="apps"]')?.elm as HTMLElement)
}) })
document.addEventListener('app_closed', (e: AppClosedEvent): void => { document.addEventListener('app_closed', (e: AppClosedEvent): void => {
statusBar.element.qs('div[data-toolbar-id="apps"]').qs(`img[data-id="${e.detail.token}"]`).elm.parentElement.remove() statusBar.element.qs('div[data-toolbar-id="apps"]')?.qs(`img[data-id="${e.detail.token}"]`)?.elm.parentElement?.remove()
}) })
document.body.style.flexDirection = 'column-reverse' document.body.style.flexDirection = 'column-reverse'

View file

@ -16,7 +16,7 @@ const UserAccessControl: Process = {
const target = process.data.executable const target = process.data.executable
return await new Promise((resolve) => { return await new Promise((resolve) => {
process.loadLibrary('lib/WindowManager').then(async wm => { process.loadLibrary('lib/WindowManager').then(async wm => {
let message let message = 'Unknown action'
switch (process.data.type) { switch (process.data.type) {
case 'launch': { case 'launch': {
message = `${initiator.config.name as string} wants to launch ${target.config.name as string}` message = `${initiator.config.name as string} wants to launch ${target.config.name as string}`
@ -42,7 +42,7 @@ const UserAccessControl: Process = {
} else { } else {
resolve(false) resolve(false)
} }
}) }).catch((e) => console.error(e))
}).catch((e) => console.error(e)) }).catch((e) => console.error(e))
}) })
} }

View file

@ -9,7 +9,7 @@ const BrowserApp: Process = {
targetVer: '1.0.0-indev.0' targetVer: '1.0.0-indev.0'
}, },
run: async (process) => { run: async (process) => {
const win = await process.loadLibrary('lib/WindowManager').then((wm: any) => { const win = await process.loadLibrary('lib/WindowManager').then(wm => {
return wm.createWindow({ return wm.createWindow({
title: 'Browser', title: 'Browser',
icon, icon,
@ -75,7 +75,7 @@ const BrowserApp: Process = {
iframe: HTMLIFrameElement = document.createElement('iframe') iframe: HTMLIFrameElement = document.createElement('iframe')
constructor (url: string) { constructor (url: string) {
this.iframe.src = `/service/${xor.encode(url) as string}` this.iframe.src = `/service/${xor.encode(url)}`
this.iframe.style.display = 'none' this.iframe.style.display = 'none'
this.header.innerHTML = ` this.header.innerHTML = `
@ -97,7 +97,7 @@ const BrowserApp: Process = {
if (this === tabManager.activeTab) { if (this === tabManager.activeTab) {
(win.content.querySelector('.toggle') as HTMLElement).innerHTML = 'toggle_on' (win.content.querySelector('.toggle') as HTMLElement).innerHTML = 'toggle_on'
} }
this.iframe.src = `/service/${xor.encode(win.content.querySelector('input').value) as string}` this.iframe.src = `/service/${xor.encode(win.content.querySelector('input')?.value ?? '')}`
} }
} }
@ -167,7 +167,7 @@ const BrowserApp: Process = {
win.content.querySelector('.inp')?.addEventListener('keydown', (event: KeyboardEvent) => { win.content.querySelector('.inp')?.addEventListener('keydown', (event: KeyboardEvent) => {
if (event.key === 'Enter') { if (event.key === 'Enter') {
tabManager.activeTab.iframe.src = tabManager.activeTab.proxy ? `/service/${xor.encode((win.content.querySelector('.inp') as HTMLInputElement).value) as string}` : (win.content.querySelector('.inp') as HTMLInputElement).value tabManager.activeTab.iframe.src = tabManager.activeTab.proxy ? `/service/${xor.encode((win.content.querySelector('.inp') as HTMLInputElement).value)}` : (win.content.querySelector('.inp') as HTMLInputElement).value
} }
}); });

View file

@ -56,7 +56,7 @@ const Files: Process = {
(win.content.querySelector('.folder') as HTMLElement).onclick = async () => { (win.content.querySelector('.folder') as HTMLElement).onclick = async () => {
const title = prompt('Enter folder name') const title = prompt('Enter folder name')
if (title != null) { if (title != null) {
await fs.mkdir(`${dir}/${title}`, '') await fs.mkdir(`${dir}/${title}`)
} }
} }
@ -69,7 +69,7 @@ const Files: Process = {
const genIcon = (): string => { const genIcon = (): string => {
return `<span class="material-symbols-rounded">${(MIMETypes[file.split('.')[1]] === undefined ? 'draft' : MIMETypes[file.split('.')[1]].icon) as string}</span>` return `<span class="material-symbols-rounded">${(MIMETypes[file.split('.')[1]] === undefined ? 'draft' : MIMETypes[file.split('.')[1]].icon) as string}</span>`
} }
const icon = fileStat.isDirectory() as boolean ? '<span class="material-symbols-rounded">folder</span>' : genIcon() const icon = fileStat.isDirectory() ? '<span class="material-symbols-rounded">folder</span>' : genIcon()
element.innerHTML += `${icon} <span style="flex:1;">${file}</span><span class="material-symbols-rounded delete">delete_forever</span><span class="material-symbols-rounded rename">edit</span>`; element.innerHTML += `${icon} <span style="flex:1;">${file}</span><span class="material-symbols-rounded delete">delete_forever</span><span class="material-symbols-rounded rename">edit</span>`;
(element.querySelector('.rename') as HTMLElement).onclick = async () => { (element.querySelector('.rename') as HTMLElement).onclick = async () => {
@ -79,7 +79,7 @@ const Files: Process = {
} }
} }
(element.querySelector('.delete') as HTMLElement).onclick = async () => { (element.querySelector('.delete') as HTMLElement).onclick = async () => {
if (fileStat.isDirectory() as boolean) { if (fileStat.isDirectory()) {
await fs.rmdir(dir + seperator + file) await fs.rmdir(dir + seperator + file)
} else { } else {
await fs.unlink(dir + seperator + file) await fs.unlink(dir + seperator + file)
@ -101,7 +101,7 @@ const Files: Process = {
} }
element.ondblclick = async () => { element.ondblclick = async () => {
if (fileStat.isDirectory() as boolean) { if (fileStat.isDirectory()) {
await setDir(dir + seperator + file) await setDir(dir + seperator + file)
} else { } else {
await run(dir + seperator + file) await run(dir + seperator + file)

View file

@ -81,7 +81,7 @@ const Store: Process = {
install(app.url) install(app.url)
} }
} }
}) }).catch((e: any) => console.error(e))
}).catch((e: any) => console.error(e)) }).catch((e: any) => console.error(e))
}) })
}) })

View file

@ -1,6 +1,6 @@
import { Library } from '../../types' import { Library } from '../../types'
const MIME: Library = { const MIMETypes: Library = {
config: { config: {
name: 'MIMETypes', name: 'MIMETypes',
type: 'library', type: 'library',
@ -83,4 +83,4 @@ const MIME: Library = {
} }
} }
export default MIME export default MIMETypes

View file

@ -1,6 +1,6 @@
import Kernel from '../../kernel' import Kernel from '../../kernel'
import ProcessLib from '../../structures/ProcessLib' import ProcessLib from '../../structures/ProcessLib'
import { Directory, Errors, File, Library, Permission } from '../../types' import { Directory, Errors, File, Library, Permission, Stats } from '../../types'
console.debug = (...args: any[]) => { console.debug = (...args: any[]) => {
console.log('[VirtualFS]', ...args) console.log('[VirtualFS]', ...args)
@ -421,7 +421,7 @@ const VirtualFS: Library = {
console.debug(`readdir ${path}`) console.debug(`readdir ${path}`)
return result return result
}, },
stat: async (path: string): Promise<{ isDirectory: () => boolean, isFile: () => boolean }> => { stat: async (path: string): Promise<Stats> => {
const { current } = await navigatePath(path) const { current } = await navigatePath(path)
console.debug(`stat ${path}`) console.debug(`stat ${path}`)

View file

@ -8,9 +8,6 @@ const XOR: Library = {
}, },
init: (l, k, p) => {}, init: (l, k, p) => {},
data: { data: {
randomMax: 100,
randomMin: -100,
encode: (str: string): string => { encode: (str: string): string => {
return encodeURIComponent( return encodeURIComponent(
str str

View file

@ -1,7 +1,10 @@
import HTML from './HTML'
import Kernel from './kernel' import Kernel from './kernel'
import FlowWindow from './structures/FlowWindow' import FlowWindow from './structures/FlowWindow'
import LibraryLib from './structures/LibraryLib' import LibraryLib from './structures/LibraryLib'
import ProcessLib from './structures/ProcessLib' import ProcessLib from './structures/ProcessLib'
import Components from './system/lib/Components'
import MIMETypes from './system/lib/MIMETypes'
export interface AppClosedEvent extends CustomEvent { export interface AppClosedEvent extends CustomEvent {
detail: { detail: {
@ -124,3 +127,61 @@ export interface KernelConfig {
SERVER: string SERVER: string
[key: string]: any [key: string]: any
} }
export interface Stats {
isDirectory: () => boolean
isFile: () => boolean
}
export interface FileSystem {
unlink: (path: string) => Promise<void>
readFile: (path: string) => Promise<Buffer>
writeFile: (path: string, content: string | Buffer) => Promise<void>
mkdir: (path: string) => Promise<void>
rmdir: (path: string) => Promise<void>
readdir: (path: string) => Promise<string[]>
stat: (path: string) => Promise<Stats>
rename: (oldPath: string, newPath: string) => Promise<void>
exists: (path: string) => Promise<boolean>
}
export interface ModalData {
value: boolean
win: FlowWindow
}
export interface WindowManager {
windowArea: HTML
windows: FlowWindow[]
getHighestZIndex: () => number
createWindow: (config: FlowWindowConfig, process: ProcessLib) => FlowWindow
createModal: (title: string, text: string, process: ProcessLib) => Promise<ModalData>
}
export interface Launcher {
element: HTML
toggle: () => void
}
export interface XOR {
encode: (str: string) => string
decode: (str: string) => string
}
export interface StatusBar {
element: HTML
updateBatteryIcon: (battery: any) => void
updateIcon: (ms: number) => void
}
export type LoadedLibrary<T> =
T extends 'lib/VirtualFS' ? FileSystem :
T extends 'lib/WindowManager' ? WindowManager :
T extends 'lib/HTML' ? typeof HTML :
T extends 'lib/Launcher' ? Launcher :
T extends 'lib/XOR' ? XOR :
T extends 'lib/StatusBar' ? StatusBar :
T extends 'lib/MIMETypes' ? typeof MIMETypes.data :
T extends 'lib/Components' ? typeof Components.data :
any
export type LibraryPath = 'lib/VirtualFS' | 'lib/WindowManager' | string