wip: compat layer
This commit is contained in:
parent
ff0a5e3f7b
commit
eeb38e7399
13 changed files with 565 additions and 0 deletions
58
crates/plugin-example/node/package-lock.json
generated
Normal file
58
crates/plugin-example/node/package-lock.json
generated
Normal file
|
|
@ -0,0 +1,58 @@
|
|||
{
|
||||
"name": "node",
|
||||
"version": "1.0.0",
|
||||
"lockfileVersion": 3,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "node",
|
||||
"version": "1.0.0",
|
||||
"license": "ISC",
|
||||
"dependencies": {
|
||||
"vscode-jsonrpc": "^8.2.1",
|
||||
"vscode-languageserver": "^9.0.1"
|
||||
}
|
||||
},
|
||||
"node_modules/vscode-jsonrpc": {
|
||||
"version": "8.2.1",
|
||||
"resolved": "https://registry.npmjs.org/vscode-jsonrpc/-/vscode-jsonrpc-8.2.1.tgz",
|
||||
"integrity": "sha512-kdjOSJ2lLIn7r1rtrMbbNCHjyMPfRnowdKjBQ+mGq6NAW5QY2bEZC/khaC5OR8svbbjvLEaIXkOq45e2X9BIbQ==",
|
||||
"engines": {
|
||||
"node": ">=14.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/vscode-languageserver": {
|
||||
"version": "9.0.1",
|
||||
"resolved": "https://registry.npmjs.org/vscode-languageserver/-/vscode-languageserver-9.0.1.tgz",
|
||||
"integrity": "sha512-woByF3PDpkHFUreUa7Hos7+pUWdeWMXRd26+ZX2A8cFx6v/JPTtd4/uN0/jB6XQHYaOlHbio03NTHCqrgG5n7g==",
|
||||
"dependencies": {
|
||||
"vscode-languageserver-protocol": "3.17.5"
|
||||
},
|
||||
"bin": {
|
||||
"installServerIntoExtension": "bin/installServerIntoExtension"
|
||||
}
|
||||
},
|
||||
"node_modules/vscode-languageserver-protocol": {
|
||||
"version": "3.17.5",
|
||||
"resolved": "https://registry.npmjs.org/vscode-languageserver-protocol/-/vscode-languageserver-protocol-3.17.5.tgz",
|
||||
"integrity": "sha512-mb1bvRJN8SVznADSGWM9u/b07H7Ecg0I3OgXDuLdn307rl/J3A9YD6/eYOssqhecL27hK1IPZAsaqh00i/Jljg==",
|
||||
"dependencies": {
|
||||
"vscode-jsonrpc": "8.2.0",
|
||||
"vscode-languageserver-types": "3.17.5"
|
||||
}
|
||||
},
|
||||
"node_modules/vscode-languageserver-protocol/node_modules/vscode-jsonrpc": {
|
||||
"version": "8.2.0",
|
||||
"resolved": "https://registry.npmjs.org/vscode-jsonrpc/-/vscode-jsonrpc-8.2.0.tgz",
|
||||
"integrity": "sha512-C+r0eKJUIfiDIfwJhria30+TYWPtuHJXHtI7J0YlOmKAo7ogxP20T0zxB7HZQIFhIyvoBPwWskjxrvAtfjyZfA==",
|
||||
"engines": {
|
||||
"node": ">=14.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/vscode-languageserver-types": {
|
||||
"version": "3.17.5",
|
||||
"resolved": "https://registry.npmjs.org/vscode-languageserver-types/-/vscode-languageserver-types-3.17.5.tgz",
|
||||
"integrity": "sha512-Ld1VelNuX9pdF39h2Hgaeb5hEZM2Z3jUrrMgWQAu82jMtZp7p3vJT3BzToKtZI7NgQssZje5o0zryOrhQvzQAg=="
|
||||
}
|
||||
}
|
||||
}
|
||||
15
crates/plugin-example/node/package.json
Normal file
15
crates/plugin-example/node/package.json
Normal file
|
|
@ -0,0 +1,15 @@
|
|||
{
|
||||
"name": "node",
|
||||
"version": "1.0.0",
|
||||
"main": "index.js",
|
||||
"scripts": {
|
||||
"test": "echo \"Error: no test specified\" && exit 1"
|
||||
},
|
||||
"author": "",
|
||||
"license": "ISC",
|
||||
"description": "",
|
||||
"dependencies": {
|
||||
"vscode-jsonrpc": "^8.2.1",
|
||||
"vscode-languageserver": "^9.0.1"
|
||||
}
|
||||
}
|
||||
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