提交 c3b7aa78 编写于 作者: fxy060608's avatar fxy060608

wip(uts): compiler

上级 4cfe9d7d
......@@ -8,7 +8,11 @@ export function genTemplate(
options: CompilerOptions
) {
if (!template) {
return { code: genRenderFunctionDecl(options) + ` { return null }` }
return {
code: genRenderFunctionDecl(options) + ` { return null }`,
importEasyComponents: [],
importUTSComponents: [],
}
}
return compile(template.content, options)
}
......@@ -44,12 +44,15 @@ import {
TO_HANDLERS,
} from './runtimeHelpers'
import { object2Map } from './utils'
import { matchEasycom, parseUTSComponent } from '@dcloudio/uni-cli-shared'
type CodegenNode = TemplateChildNode | JSChildNode | SSRCodegenNode
export interface CodegenContext extends Required<CodegenOptions> {
source: string
code: string
importEasyComponents: string[]
importUTSComponents: string[]
line: number
column: number
offset: number
......@@ -82,6 +85,8 @@ function createCodegenContext(
filename,
source: ast.loc.source,
code: ``,
importEasyComponents: [],
importUTSComponents: [],
column: 1,
line: 1,
offset: 0,
......@@ -191,6 +196,8 @@ export function generate(
}
return {
code: context.code,
importEasyComponents: context.importEasyComponents,
importUTSComponents: context.importUTSComponents,
// SourceMapGenerator does have toJSON() method but it's not in the types
map: context.map ? (context.map as any).toJSON() : undefined,
}
......@@ -199,7 +206,14 @@ export function generate(
function genAssets(
assets: string[],
type: 'component' | 'directive',
{ helper, push, newline }: CodegenContext
{
helper,
push,
newline,
targetLanguage,
importEasyComponents,
importUTSComponents,
}: CodegenContext
) {
const resolver = helper(
type === 'component' ? RESOLVE_COMPONENT : RESOLVE_DIRECTIVE
......@@ -211,11 +225,42 @@ function genAssets(
if (maybeSelfReference) {
id = id.slice(0, -6)
}
push(
`const ${toValidAssetId(id, type)} = ${resolver}(${JSON.stringify(id)}${
let assetCode = ''
if (type === 'component') {
// 原生UTS组件
const utsComponentOptions = parseUTSComponent(id, targetLanguage)
if (utsComponentOptions) {
assetCode = `const ${toValidAssetId(id, type)} = ${
utsComponentOptions.namespace
}.${utsComponentOptions.className}.name`
const importCode = `import '${utsComponentOptions.source}'`
if (!importUTSComponents.includes(importCode)) {
importUTSComponents.push(importCode)
}
}
if (!assetCode) {
const source = matchEasycom(id)
if (source) {
const componentId = toValidAssetId(id, type)
assetCode = `const ${componentId} = ${resolver}(${JSON.stringify(
id
)}${maybeSelfReference ? `, true` : ``})`
const importCode = `import ${componentId} from '${source}'`
if (!importEasyComponents.includes(importCode)) {
importEasyComponents.push(importCode)
}
}
}
}
if (!assetCode) {
assetCode = `const ${toValidAssetId(
id,
type
)} = ${resolver}(${JSON.stringify(id)}${
maybeSelfReference ? `, true` : ``
})`
)
}
push(assetCode)
if (i < assets.length - 1) {
newline()
}
......
......@@ -77,5 +77,7 @@ export type CompilerOptions = TransformOptions & CodegenOptions
export interface CodegenResult {
code: string
importEasyComponents: string[]
importUTSComponents: string[]
map?: RawSourceMap
}
......@@ -186,6 +186,8 @@ export async function transformVue(
const fileName = path.relative(options.root, filename)
const className = genClassName(fileName, options.classNamePrefix)
let templateCode = ''
let templateImportEasyComponentsCode = ''
let templateImportUTSComponentsCode = ''
if (!isApp) {
const templateResult = genTemplate(descriptor, {
targetLanguage: options.targetLanguage as any,
......@@ -195,6 +197,10 @@ export async function transformVue(
sourceMap: true,
})
templateCode = templateResult.code
templateImportEasyComponentsCode =
templateResult.importEasyComponents.join('\n')
templateImportUTSComponentsCode =
templateResult.importUTSComponents.join('\n')
}
// 生成 script 文件
let utsCode =
......@@ -203,7 +209,8 @@ export async function transformVue(
genStyle(descriptor, { filename: fileName, className }) +
'\n'
utsCode += templateCode
let jsCode = ''
let jsCode =
templateImportEasyComponentsCode + '\n' + templateImportUTSComponentsCode
const content = descriptor.script?.content
if (content) {
jsCode += await parseImports(content)
......
......@@ -10,24 +10,28 @@ describe('easycom', () => {
initEasycoms(rootDir, { platform: 'h5', dirs: [] }).easycoms
).toEqual([
{
name: 'test',
pattern: new RegExp('^test$'),
replacement: normalizePath(
path.resolve(rootDir, 'components/test/test.vue')
),
},
{
name: 'test1',
pattern: new RegExp('^test1$'),
replacement: normalizePath(
path.resolve(rootDir, 'components/test1/test1.vue')
),
},
{
name: 'test2',
pattern: new RegExp('^test2$'),
replacement: normalizePath(
path.resolve(rootDir, 'uni_modules/plugin/components/test2/test2.vue')
),
},
{
name: '^uni-(.*)',
pattern: new RegExp('^uni-(.*)'),
replacement: normalizePath(
path.resolve(rootDir, 'components/uni-$1.vue')
......
......@@ -19,6 +19,7 @@ interface EasycomOption {
custom?: EasycomCustom
}
export interface EasycomMatcher {
name: string
pattern: RegExp
replacement: string
}
......@@ -70,9 +71,7 @@ export function initEasycoms(
const options = initEasycomOptions(parsePagesJsonOnce(inputDir, platform))
const initUTSEasycom = () => {
initUTSComponents(inputDir, platform).forEach((item) => {
const index = easycoms.findIndex(
(easycom) => item.pattern.toString() === easycom.pattern.toString()
)
const index = easycoms.findIndex((easycom) => item.name === easycom.name)
if (index > -1) {
easycoms.splice(index, 1, item)
} else {
......@@ -148,6 +147,8 @@ function initEasycom({
}
Object.keys(easycomsObj).forEach((name) => {
easycoms.push({
name:
name.startsWith('^') && name.endsWith('$') ? name.slice(1, -1) : name,
pattern: new RegExp(name),
replacement: easycomsObj[name],
})
......
import fs from 'fs'
import path from 'path'
import glob from 'fast-glob'
import { camelize, capitalize } from '@vue/shared'
import * as UTSCompiler from '@dcloudio/uni-uts-v1'
import { isInHBuilderX } from './hbx'
......@@ -128,20 +128,54 @@ export function resolveUTSCompiler(): typeof UTSCompiler {
return require(compilerPath)
}
interface UTSComponentMeta {
source: string
kotlinPackage: string
swiftModule: string
}
const utsComponents = new Map<string, UTSComponentMeta>()
export function isUTSComponent(name: string) {
return utsComponents.has(name)
}
export function parseUTSComponent(name: string, type: 'kotlin' | 'swift') {
const meta = utsComponents.get(name)
if (meta) {
const namespace =
meta[type === 'swift' ? 'swiftModule' : 'kotlinPackage'] || ''
const className = capitalize(camelize(name)) + 'Component'
return {
className,
namespace,
source: meta.source,
}
}
}
export function initUTSComponents(
inputDir: string,
platform: UniApp.PLATFORM
): EasycomMatcher[] {
utsComponents.clear()
const components: EasycomMatcher[] = []
if (platform !== 'app' && platform !== 'app-plus') {
return components
}
const easycomsObj = Object.create(null)
const easycomsObj: Record<
string,
{ source: string; kotlinPackage: string; swiftModule: string }
> = {}
const dirs = resolveUTSComponentDirs(inputDir)
dirs.forEach((dir) => {
const is_uni_modules_utssdk = dir.endsWith('utssdk')
const is_ussdk =
!is_uni_modules_utssdk && path.dirname(dir).endsWith('utssdk')
const pluginId = is_uni_modules_utssdk
? path.basename(path.dirname(dir))
: path.basename(dir)
if (is_uni_modules_utssdk || is_ussdk) {
glob
.sync('**/*.vue', {
......@@ -161,15 +195,33 @@ export function initUTSComponents(
const importDir = normalizePath(
is_uni_modules_utssdk ? path.dirname(dir) : dir
)
easycomsObj[`^${name}$`] = `${importDir}?uts-proxy`
easycomsObj[`^${name}$`] = {
source: `${importDir}?uts-proxy`,
kotlinPackage: parseKotlinPackageWithPluginId(
pluginId,
is_uni_modules_utssdk
),
swiftModule: parseSwiftPackageWithPluginId(
pluginId,
is_uni_modules_utssdk
),
}
}
})
}
})
Object.keys(easycomsObj).forEach((name) => {
const obj = easycomsObj[name]
const componentName = name.slice(1, -1)
components.push({
name: componentName,
pattern: new RegExp(name),
replacement: easycomsObj[name],
replacement: obj.source,
})
utsComponents.set(componentName, {
source: obj.source,
kotlinPackage: obj.kotlinPackage,
swiftModule: obj.swiftModule,
})
})
return components
......@@ -201,3 +253,31 @@ function parseVueComponentName(file: string) {
return matches[1]
}
}
function prefix(id: string) {
if (
process.env.UNI_UTS_MODULE_PREFIX &&
!id.startsWith(process.env.UNI_UTS_MODULE_PREFIX)
) {
return process.env.UNI_UTS_MODULE_PREFIX + '-' + id
}
return id
}
export function parseKotlinPackageWithPluginId(
id: string,
is_uni_modules: boolean
) {
return 'uts.sdk.' + (is_uni_modules ? 'modules.' : '') + camelize(prefix(id))
}
export function parseSwiftPackageWithPluginId(
id: string,
is_uni_modules: boolean
) {
return (
'UTSSDK' +
(is_uni_modules ? 'Modules' : '') +
capitalize(camelize(prefix(id)))
)
}
package uts.sdk.modules.testUts;
import kotlinx.coroutines.async;
import kotlinx.coroutines.CoroutineScope;
import kotlinx.coroutines.Deferred;
import kotlinx.coroutines.Dispatchers;
import io.dcloud.uts.Map;
import io.dcloud.uts.UTSAndroid;
import io.dcloud.uts.*;
fun test() {}
fun testByJs() {
return test();
}
......@@ -189,7 +189,7 @@ export async function runKotlinDev(
kotlinFile,
jarFile,
getKotlincHome(),
getDefaultJar()
(isX ? getDefaultJar(2) : getDefaultJar())
.concat(resolveLibs(filename))
.concat(deps)
.concat(resDeps)
......@@ -349,7 +349,7 @@ export async function compile(
if (rClass) {
imports.push(rClass)
}
const componentsCode = genComponentsCode(filename, components)
const componentsCode = genComponentsCode(filename, components, isX)
const { package: pluginPackage, id: pluginId } = parseKotlinPackage(filename)
const input: Parameters<typeof bundle>[1]['input'] = {
root: inputDir,
......@@ -371,8 +371,7 @@ export async function compile(
return
}
}
const result = await bundle(UTSTarget.KOTLIN, {
const options = {
input,
output: {
isX,
......@@ -388,7 +387,8 @@ export async function compile(
uniExtApiPackage: 'io.dcloud.uts.extapi',
},
},
})
}
const result = await bundle(UTSTarget.KOTLIN, options)
sourceMap &&
moveRootIndexSourceMap(filename, {
inputDir,
......
......@@ -177,11 +177,11 @@ function isCliProject(projectPath: string) {
export async function compile(
filename: string,
{ inputDir, outputDir, sourceMap, components, isPlugin }: ToSwiftOptions
{ inputDir, outputDir, sourceMap, components, isX, isPlugin }: ToSwiftOptions
) {
const { bundle, UTSTarget } = getUTSCompiler()
// let time = Date.now()
const componentsCode = genComponentsCode(filename, components)
const componentsCode = genComponentsCode(filename, components, isX)
const { namespace, id: pluginId } = parseSwiftPackage(filename)
const input: Parameters<typeof bundle>[1]['input'] = {
root: inputDir,
......@@ -206,6 +206,7 @@ export async function compile(
const result = await bundle(UTSTarget.SWIFT, {
input,
output: {
isX,
isPlugin,
outDir: outputDir,
package: namespace,
......
......@@ -280,16 +280,18 @@ function parseVueComponentName(file: string) {
export function genComponentsCode(
filename: string,
components: Record<string, string>
components: Record<string, string>,
isX: boolean
) {
const codes: string[] = []
const dirname = path.dirname(filename)
Object.keys(components).forEach((name) => {
const source = normalizePath(path.relative(dirname, components[name]))
const className = capitalize(camelize(name))
codes.push(
`export { default as ${capitalize(camelize(name))}Component } from '${
source.startsWith('.') ? source : './' + source
}'`
`export { default as ${className}Component${
isX ? `, ${className}Node` : ''
} } from '${source.startsWith('.') ? source : './' + source}'`
)
})
return codes.join('\n')
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册