From 993c083c22a8aa11091fa6c749531389a58ac7d3 Mon Sep 17 00:00:00 2001 From: mantou132 <709922234@qq.com> Date: Sun, 10 Dec 2023 20:51:12 +0800 Subject: [PATCH] [duoyun-ui] Export svelte component --- .eslintignore | 1 + packages/duoyun-ui/.gitignore | 1 + packages/duoyun-ui/package.json | 2 ++ packages/gem-port/src/common.ts | 26 +++++++++++++++++ packages/gem-port/src/index.ts | 6 ++-- packages/gem-port/src/react.ts | 36 +++-------------------- packages/gem-port/src/svelte.ts | 51 +++++++++++++++++++++++++++++++++ packages/gem-port/src/vue.ts | 2 +- 8 files changed, 90 insertions(+), 35 deletions(-) create mode 100644 packages/gem-port/src/svelte.ts diff --git a/.eslintignore b/.eslintignore index 48cee302..f5c7eb02 100644 --- a/.eslintignore +++ b/.eslintignore @@ -1,5 +1,6 @@ packages/*/dist packages/*/react +packages/*/svelte packages/*/bin packages/*/coverage packages/*/extension diff --git a/packages/duoyun-ui/.gitignore b/packages/duoyun-ui/.gitignore index c8edc823..1d99705e 100644 --- a/packages/duoyun-ui/.gitignore +++ b/packages/duoyun-ui/.gitignore @@ -5,6 +5,7 @@ /elements/ /react/ /vue/ +/svelte/ /locales/ /coverage/ diff --git a/packages/duoyun-ui/package.json b/packages/duoyun-ui/package.json index b26cdf2a..401b42a7 100644 --- a/packages/duoyun-ui/package.json +++ b/packages/duoyun-ui/package.json @@ -6,6 +6,7 @@ "./elements/*": "./elements/*.js", "./react/*": "./react/*.js", "./vue/*": "./vue/*", + "./svelte/*": "./svelte/*.js", "./lib/*": "./lib/*.js", "./locales/*": "./locales/*.js" }, @@ -13,6 +14,7 @@ "/elements/", "/react/", "/vue/", + "/svelte/", "/lib/", "/locales/" ], diff --git a/packages/gem-port/src/common.ts b/packages/gem-port/src/common.ts index 991c3f92..cbd601a4 100644 --- a/packages/gem-port/src/common.ts +++ b/packages/gem-port/src/common.ts @@ -3,6 +3,7 @@ import { readdirSync, readFileSync, statSync } from 'fs'; import { ElementDetail, getElements } from 'gem-analyzer'; import { Project } from 'ts-morph'; +import * as ts from 'typescript'; const dev = process.env.MODE === 'dev'; const elements = process.env.ELEMENTS?.split(','); @@ -46,3 +47,28 @@ export function getRelativePath(elementFilePath: string, outDir: string) { const relativePath = path.relative(path.resolve(outDir), path.dirname(elementFilePath)).replace('src/', ''); return `${relativePath}/${basename}`; } + +export function compile(outDir: string, fileSystem: Record): void { + const options: ts.CompilerOptions = { + jsx: ts.JsxEmit.React, + target: ts.ScriptTarget.ES2020, + declaration: true, + outDir, + }; + const host = ts.createCompilerHost(options); + const originReadFile = host.readFile; + host.readFile = (filename: string) => { + if (filename in fileSystem) return fileSystem[filename]; + return originReadFile(filename); + }; + const program = ts.createProgram(Object.keys(fileSystem), options, host); + program.emit().diagnostics.forEach((diagnostic) => { + if (diagnostic.file) { + const { line, character } = ts.getLineAndCharacterOfPosition(diagnostic.file, diagnostic.start!); + const message = ts.flattenDiagnosticMessageText(diagnostic.messageText, '\n'); + console.warn(`${diagnostic.file.fileName} (${line + 1},${character + 1}): ${message}`); + } else { + console.warn(ts.flattenDiagnosticMessageText(diagnostic.messageText, '\n')); + } + }); +} diff --git a/packages/gem-port/src/index.ts b/packages/gem-port/src/index.ts index b62f5e39..efe921a3 100644 --- a/packages/gem-port/src/index.ts +++ b/packages/gem-port/src/index.ts @@ -7,7 +7,8 @@ import program from 'commander'; import { name, description, version } from '../package.json'; import { compileReact } from './react'; -import { compileVue } from './vue'; +import { generateVue } from './vue'; +import { compileSvelte } from './svelte'; const cliOptions = { outDir: './', @@ -21,7 +22,8 @@ program .arguments('') .action((dir: string) => { compileReact(dir, path.resolve(cliOptions.outDir, 'react')); - compileVue(dir, path.resolve(cliOptions.outDir, 'vue')); + generateVue(dir, path.resolve(cliOptions.outDir, 'vue')); + compileSvelte(dir, path.resolve(cliOptions.outDir, 'svelte')); process.exit(0); }); diff --git a/packages/gem-port/src/react.ts b/packages/gem-port/src/react.ts index f06bd1b9..341ebb97 100644 --- a/packages/gem-port/src/react.ts +++ b/packages/gem-port/src/react.ts @@ -1,6 +1,4 @@ -import * as ts from 'typescript'; - -import { getElementPathList, getFileElements, getComponentName, getRelativePath } from './common'; +import { getElementPathList, getFileElements, getComponentName, getRelativePath, compile } from './common'; function createReactSourceFile(elementFilePath: string, outDir: string) { const elementDetailList = getFileElements(elementFilePath); @@ -22,7 +20,7 @@ function createReactSourceFile(elementFilePath: string, outDir: string) { ${properties .map(({ name, reactive, event }) => event - ? [`'on${event}'`, `(arg: CustomEvent[0]>) => void`].join( + ? [`'on${event}'`, `(event: CustomEvent[0]>) => void`].join( '?:', ) : reactive @@ -83,36 +81,10 @@ function createReactSourceFile(elementFilePath: string, outDir: string) { ); } -function createReactSourceFiles(elementsDir: string, outDir: string) { +export function compileReact(elementsDir: string, outDir: string): void { const fileSystem: Record = {}; getElementPathList(elementsDir).forEach((elementFilePath) => { Object.assign(fileSystem, createReactSourceFile(elementFilePath, outDir)); }); - return fileSystem; -} - -export function compileReact(elementsDir: string, outDir: string): void { - const options: ts.CompilerOptions = { - jsx: ts.JsxEmit.React, - target: ts.ScriptTarget.ES2020, - declaration: true, - outDir, - }; - const fileSystem = createReactSourceFiles(elementsDir, outDir); - const host = ts.createCompilerHost(options); - const originReadFile = host.readFile; - host.readFile = (filename: string) => { - if (filename in fileSystem) return fileSystem[filename]; - return originReadFile(filename); - }; - const program = ts.createProgram(Object.keys(fileSystem), options, host); - program.emit().diagnostics.forEach((diagnostic) => { - if (diagnostic.file) { - const { line, character } = ts.getLineAndCharacterOfPosition(diagnostic.file, diagnostic.start!); - const message = ts.flattenDiagnosticMessageText(diagnostic.messageText, '\n'); - console.warn(`${diagnostic.file.fileName} (${line + 1},${character + 1}): ${message}`); - } else { - console.warn(ts.flattenDiagnosticMessageText(diagnostic.messageText, '\n')); - } - }); + compile(outDir, fileSystem); } diff --git a/packages/gem-port/src/svelte.ts b/packages/gem-port/src/svelte.ts new file mode 100644 index 00000000..504bbc9d --- /dev/null +++ b/packages/gem-port/src/svelte.ts @@ -0,0 +1,51 @@ +import path from 'path'; + +import { compile, getComponentName, getElementPathList, getFileElements, getRelativePath } from './common'; + +export function compileSvelte(elementsDir: string, outDir: string): void { + const fileSystem: Record = {}; + getElementPathList(elementsDir).forEach((elementFilePath) => { + const elementDetailList = getFileElements(elementFilePath); + Object.assign( + fileSystem, + Object.fromEntries( + elementDetailList.map(({ name: tag, constructorName, properties }) => { + const componentName = getComponentName(tag); + const componentPropsName = `${componentName}Props`; + const relativePath = getRelativePath(elementFilePath, outDir); + const basename = path.basename(relativePath); + return [ + basename + '.ts', + ` + import type { HTMLAttributes } from "svelte/elements"; + import { ${constructorName} } from '${relativePath}'; + export * from '${relativePath}'; + + interface ${componentPropsName} extends HTMLAttributes { + ${properties + .map(({ name, reactive, event }) => + event + ? [ + `'on:${event}'`, + `(event: CustomEvent[0]>) => void`, + ].join('?:') + : reactive + ? [name, `${constructorName}['${name}']`].join('?:') + : '', + ) + .join(';')} + }; + + declare module "svelte/elements" { + interface SvelteHTMLElements { + '${tag}': ${componentPropsName}; + } + } + `, + ]; + }), + ), + ); + }); + compile(outDir, fileSystem); +} diff --git a/packages/gem-port/src/vue.ts b/packages/gem-port/src/vue.ts index 27c2caaf..3480a491 100644 --- a/packages/gem-port/src/vue.ts +++ b/packages/gem-port/src/vue.ts @@ -27,7 +27,7 @@ declare module '@vue/runtime-dom' { } */ -export function compileVue(elementsDir: string, outDir: string): void { +export function generateVue(elementsDir: string, outDir: string): void { mkdirSync(outDir, { recursive: true }); getElementPathList(elementsDir).forEach((elementFilePath) => { getFileElements(elementFilePath).forEach(({ name: tag, properties, constructorName, methods, events }) => {