wip: compat layer

This commit is contained in:
Jordan Pittman 2024-10-12 18:52:52 -04:00
parent ff0a5e3f7b
commit eeb38e7399
13 changed files with 565 additions and 0 deletions

View 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=="
}
}
}

View 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"
}
}

View 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')

View 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,
})
},
}
}

View 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',
},
},
)
}

View 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')