* Copyright (c) 2024 Huawei Device Co., Ltd.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import * as idl from "@idlizer/core/idl"
import { Language, LayoutNodeRole, isStaticMaterialized, maybeRestoreGenerics, isInExternalModule, isInStdlibModule, isTopLevelConflicted, getInitializerFeature, lib } from "@idlizer/core"
import { ImportFeature, ImportsCollector } from "./ImportsCollector"
import { createDependenciesCollector, DependenciesCollector } from "./idl/IdlDependenciesCollector"
import { getInternalClassName, isMaterialized, PeerLibrary, maybeTransformManagedCallback } from "@idlizer/core"
export function convertDeclToFeature(library: PeerLibrary, node: idl.IDLEntry | idl.IDLReferenceType): ImportFeature {
const featureNameConvertor = library.createTypeNameConvertor(library.language)
if (idl.isReferenceType(node)) {
const decl = library.resolveTypeReference(node)
if (!decl) {
throw new Error(`Expected to have an entry: ${node.name}`)
}
return convertDeclToFeature(library, decl)
}
if (isInStdlibModule(node)) {
return { module: '', feature: '' }
}
let feature = featureNameConvertor.convert(node).split(".")[0]
let alias: string | undefined
if ([Language.TS, Language.ARKTS].includes(library.language)) {
if (isTopLevelConflicted(library, library.language, node)) {
const featureNs = idl.getNamespaceName(node)
alias = feature
feature = featureNs.at(0) ?? node.name
}
}
const moduleName = library.layout.resolve({
node,
role: LayoutNodeRole.INTERFACE
})
return {
feature,
alias,
module: `${moduleName}`,
isDefault: isDefaultDeclaration(node, library.language)
}
}
export function collectDeclItself(
library: PeerLibrary,
node: idl.IDLEntry | idl.IDLReferenceType,
emitter: ImportsCollector | ((entry: idl.IDLEntry | idl.IDLReferenceType) => void),
options?: {
includeMaterializedInternals?: boolean,
includeTransformedCallbacks?: boolean,
},
): void {
if (idl.isReferenceType(node)) {
node = library.resolveTypeReference(node) ?? node
}
if (idl.isSyntheticEntry(node)) {
if (library.language === Language.TS)
return
if (library.language === Language.ARKTS && !(idl.isInterface(node) && node.subkind === idl.IDLInterfaceSubkind.AnonymousInterface))
return
if (library.language === Language.KOTLIN && idl.isCallback(node))
return
}
if ([Language.TS, Language.ARKTS].includes(library.language)) {
node = maybeRestoreGenerics(node, library) ?? node
if (idl.isReferenceType(node)) {
const decl = library.resolveTypeReference(node)
if (decl && idl.isInterface(decl) && decl.subkind === idl.IDLInterfaceSubkind.Tuple) {
return
}
}
}
if (emitter instanceof ImportsCollector) {
if (idl.isSyntheticEntry(node) && library.language === Language.ARKTS && library.name !== 'arkoala'
) {
return
}
if (idl.isInterface(node) && isMaterialized(node, library) && isInExternalModule(node)) {
emitter.addFeature("extractors", library.layout.handwrittenPackage())
}
const feature = convertDeclToFeature(library, node)
if (!feature.module) {
return
}
emitter.addFeature(feature.feature, feature.module, feature.alias, feature.isDefault)
if (options?.includeMaterializedInternals) {
if (idl.isInterface(node) && isMaterialized(node, library) && !isStaticMaterialized(node, library) && !isInExternalModule(node)) {
const ns = idl.getNamespaceName(node)
if (ns !== '') {
emitter.addFeature(ns.split('.')[0], feature.module)
} else {
emitter.addFeature(getInternalClassName(node.name), feature.module)
}
}
}
if (options?.includeTransformedCallbacks) {
if (idl.isCallback(node)) {
const maybeTransformed = maybeTransformManagedCallback(node, library)
if (maybeTransformed)
collectDeclItself(library, maybeTransformed, emitter, options)
}
}
} else {
emitter(node)
}
}
export function collectDeclDependencies(
library: PeerLibrary,
node: idl.IDLNode,
emitter: ImportsCollector | ((entry: idl.IDLEntry | idl.IDLReferenceType) => void),
options?: {
expandTypedefs?: boolean,
includeMaterializedInternals?: boolean,
includeTransformedCallbacks?: boolean,
},
collector?: DependenciesCollector,
): void {
collector = collector ?? createDependenciesCollector(library)
const deps = collector.convert(node)
if (options?.expandTypedefs) {
for (let i = 0; i < deps.length; i++) {
const dep = deps[i]
if (!idl.isTypedef(dep) && !(idl.isInterface(dep) && dep.subkind === idl.IDLInterfaceSubkind.Tuple))
continue
for (const subDependency of collector.convert(dep)) {
if (!deps.includes(subDependency))
deps.push(subDependency)
}
}
}
for (const dep of deps) {
collectDeclItself(library, dep, emitter, {
includeMaterializedInternals: options?.includeMaterializedInternals,
includeTransformedCallbacks: options?.includeTransformedCallbacks,
})
}
if (emitter instanceof ImportsCollector) {
const needsConstInitializer = idl.isConstant(node) && !node.value
const needsPropInitializer = idl.isInterface(node)
&& idl.isClassSubkind(node)
&& !isMaterialized(node, library)
&& node.properties.length > 0
if (needsConstInitializer || needsPropInitializer) {
emitter.addFeature(getInitializerFeature(library.language), library.layout.handwrittenPackage())
}
}
}
function isDefaultDeclaration(node: idl.IDLNode, lang: Language): boolean {
if (lang !== Language.ARKTS) return false
if (idl.hasExtAttribute(node, idl.IDLExtendedAttributes.DefaultExport)) return true
const ns = node.parent
if (ns && idl.isNamespace(ns) && idl.hasExtAttribute(ns, idl.IDLExtendedAttributes.DefaultExport)) return true
return false
}