wip: compat layer
This commit is contained in:
parent
ff0a5e3f7b
commit
eeb38e7399
13 changed files with 565 additions and 0 deletions
14
crates/plugin-example/node/src/client.ts
Normal file
14
crates/plugin-example/node/src/client.ts
Normal file
|
|
@ -0,0 +1,14 @@
|
|||
import * as net from 'node:net'
|
||||
import * as rpc from 'vscode-jsonrpc/node'
|
||||
|
||||
let client = net.connect(12345)
|
||||
|
||||
// Use stdin and stdout for communication:
|
||||
let connection = rpc.createMessageConnection(client, client)
|
||||
|
||||
connection.onNotification('loaded', () => console.log('server loaded'))
|
||||
connection.onNotification('ping', () => console.log('ping'))
|
||||
connection.onNotification('@/plugins/loaded', () => console.log('plugins loaded'))
|
||||
|
||||
connection.listen()
|
||||
connection.sendRequest('@/plugins/load', 'foo')
|
||||
127
crates/plugin-example/node/src/plugin-api.ts
Normal file
127
crates/plugin-example/node/src/plugin-api.ts
Normal file
|
|
@ -0,0 +1,127 @@
|
|||
export type PluginFn = (api: PluginAPI) => void
|
||||
export type PluginWithConfig = { handler: PluginFn }
|
||||
export type PluginWithOptions<T> = {
|
||||
(options?: T): PluginWithConfig
|
||||
__isOptionsFunction: true
|
||||
}
|
||||
|
||||
export type Plugin = PluginFn | PluginWithConfig | PluginWithOptions<any>
|
||||
export type CssInJs = { [key: string]: string | CssInJs | CssInJs[] }
|
||||
|
||||
export type NamedUtilityValue = {
|
||||
kind: 'named'
|
||||
|
||||
/**
|
||||
* bg-red-500
|
||||
* ^^^^^^^
|
||||
*
|
||||
* w-1/2
|
||||
* ^
|
||||
*/
|
||||
value: string
|
||||
|
||||
/**
|
||||
* w-1/2
|
||||
* ^^^
|
||||
*/
|
||||
fraction: string | null
|
||||
}
|
||||
|
||||
export type PluginAPI = {
|
||||
addBase(base: CssInJs): void
|
||||
addVariant(name: string, variant: string | string[] | CssInJs): void
|
||||
|
||||
addUtilities(
|
||||
utilities: Record<string, CssInJs | CssInJs[]> | Record<string, CssInJs | CssInJs[]>[],
|
||||
options?: {},
|
||||
): void
|
||||
|
||||
matchUtilities(
|
||||
utilities: Record<
|
||||
string,
|
||||
(value: string, extra: { modifier: string | null }) => CssInJs | CssInJs[]
|
||||
>,
|
||||
options?: Partial<{
|
||||
type: string | string[]
|
||||
supportsNegativeValues: boolean
|
||||
values: Record<string, string> & {
|
||||
__BARE_VALUE__?: (value: NamedUtilityValue) => string | undefined
|
||||
}
|
||||
modifiers: 'any' | Record<string, string>
|
||||
}>,
|
||||
): void
|
||||
|
||||
// addComponents(utilities: Record<string, CssInJs> | Record<string, CssInJs>[], options?: {}): void
|
||||
// matchComponents(
|
||||
// utilities: Record<string, (value: string, extra: { modifier: string | null }) => CssInJs>,
|
||||
// options?: Partial<{
|
||||
// type: string | string[]
|
||||
// supportsNegativeValues: boolean
|
||||
// values: Record<string, string> & {
|
||||
// __BARE_VALUE__?: (value: NamedUtilityValue) => string | undefined
|
||||
// }
|
||||
// modifiers: 'any' | Record<string, string>
|
||||
// }>,
|
||||
// ): void
|
||||
|
||||
// theme(path: string, defaultValue?: any): any
|
||||
// prefix(className: string): string
|
||||
}
|
||||
|
||||
import * as rpc from 'vscode-jsonrpc/node'
|
||||
|
||||
export function buildPluginController(server: rpc.MessageConnection) {
|
||||
let utilityMap = new Map<
|
||||
string,
|
||||
(value: string, extra: { modifier: string | null }) => CssInJs | CssInJs[]
|
||||
>()
|
||||
|
||||
let api = buildPluginApi(server, utilityMap)
|
||||
|
||||
return {
|
||||
api,
|
||||
|
||||
matchUtility(id: string, value: string, modifier: string | null) {
|
||||
let fn = utilityMap.get(id)
|
||||
if (!fn) return
|
||||
|
||||
return fn(value, { modifier })
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
function buildPluginApi(
|
||||
server: rpc.MessageConnection,
|
||||
utilityMap: Map<
|
||||
string,
|
||||
(value: string, extra: { modifier: string | null }) => CssInJs | CssInJs[]
|
||||
>,
|
||||
): PluginAPI {
|
||||
return {
|
||||
addBase(base) {
|
||||
server.sendNotification('@/plugin/add-base', { ast: base })
|
||||
},
|
||||
|
||||
addVariant(name, variant) {
|
||||
server.sendNotification('@/plugin/add-variant', { name, format: variant })
|
||||
},
|
||||
|
||||
addUtilities(utilities, options) {
|
||||
server.sendNotification('@/plugin/add-utilities', { ast: utilities, options })
|
||||
},
|
||||
|
||||
matchUtilities(utilities, options) {
|
||||
let namesToIds: Record<string, string> = {}
|
||||
|
||||
for (let [name, fn] of Object.entries(utilities)) {
|
||||
let id = Math.random().toString(36).slice(2)
|
||||
namesToIds[name] = id
|
||||
utilityMap.set(id, fn)
|
||||
}
|
||||
|
||||
server.sendNotification('@/plugin/match-utility', {
|
||||
utilities: namesToIds,
|
||||
})
|
||||
},
|
||||
}
|
||||
}
|
||||
27
crates/plugin-example/node/src/plugin.ts
Normal file
27
crates/plugin-example/node/src/plugin.ts
Normal file
|
|
@ -0,0 +1,27 @@
|
|||
import type { PluginAPI } from './plugin-api'
|
||||
|
||||
module.exports = function ({ addBase, addVariant, addUtilities, matchUtilities }: PluginAPI) {
|
||||
addBase({
|
||||
div: {
|
||||
transform: 'skewY(-10deg)',
|
||||
},
|
||||
})
|
||||
|
||||
addVariant('hover', ':hover')
|
||||
addVariant('marker', ['::marker', '* ::marker'])
|
||||
|
||||
addUtilities({
|
||||
'.skew-10deg': {
|
||||
transform: 'skewY(-10deg)',
|
||||
},
|
||||
})
|
||||
|
||||
matchUtilities(
|
||||
{ skew: (value) => ({ transform: `skewY(${value})` }) },
|
||||
{
|
||||
values: {
|
||||
f10: '10deg',
|
||||
},
|
||||
},
|
||||
)
|
||||
}
|
||||
33
crates/plugin-example/node/src/server.ts
Normal file
33
crates/plugin-example/node/src/server.ts
Normal file
|
|
@ -0,0 +1,33 @@
|
|||
import * as net from 'node:net'
|
||||
import * as rpc from 'vscode-jsonrpc/node'
|
||||
import { buildPluginController, PluginFn } from './plugin-api'
|
||||
|
||||
let socket = await new Promise<net.Socket>((resolve) => {
|
||||
net.createServer(resolve).listen(12345)
|
||||
})
|
||||
|
||||
let server = rpc.createMessageConnection(socket, socket)
|
||||
let controller = buildPluginController(server)
|
||||
|
||||
async function loadPlugin(path: string): Promise<PluginFn> {
|
||||
return import(path).then((m) => m.default ?? m)
|
||||
}
|
||||
|
||||
server.onRequest('@/plugins/load', async ({ plugins: paths }) => {
|
||||
console.log('Loading…')
|
||||
let plugins: PluginFn[] = await Promise.all(paths.map(loadPlugin))
|
||||
|
||||
for (let plugin of plugins) {
|
||||
plugin(controller.api)
|
||||
}
|
||||
console.log('Loaded…')
|
||||
})
|
||||
|
||||
server.onRequest('@/plugins/match-utility', async ({ id, value, modifier }) => {
|
||||
let ast = controller.matchUtility(id, value, modifier)
|
||||
|
||||
return { ast }
|
||||
})
|
||||
|
||||
server.listen()
|
||||
server.sendNotification('loaded')
|
||||
Loading…
Add table
Add a link
Reference in a new issue