* Copyright (c) 2024-2025 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 { copyFileSync, existsSync, mkdirSync, readdirSync, rmSync } from 'node:fs'
import { basename, join, parse, resolve } from 'node:path'
import {
Package,
IDLIZE_HOME,
external_packages,
idlize_packages,
} from '../utils.mjs'
const all_packages = [
...external_packages,
...idlize_packages,
]
const koalaui_dependencies = [
"@koalaui/compat",
"@koalaui/common",
"@koalaui/interop",
"@koalaui/libarkts"
]
const idlizer_dependencies = [
"@idlizer/core",
"@idlizer/interfaces",
"@idlizer/libohos",
"@idlizer/etsgen",
"@idlizer/arkgen",
"@idlizer/runner"
]
function findPackage(name, packages) {
const pkg = packages.find(it => it.name() === name)
if (!pkg) {
throw new Error(`Package ${name} is not available for bundling`)
}
return pkg
}
function mangleVersion(version, manglePanda) {
if (manglePanda) {
const pandaSdk = new Package(process.env.PANDA_SDK_PATH ?? join(IDLIZE_HOME, './external/incremental/tools/panda/node_modules/@panda/sdk'))
const pandaVersion = pandaSdk.version()
return `${version}-panda-${pandaVersion}`
}
return version
}
function applyVersions(dependencies, versions, packages) {
for (const dependency of dependencies) {
const pkg = findPackage(dependency, packages)
pkg.write('version', versions[pkg.name()])
for (const field of ['dependencies', 'devDependencies', 'optionalDependencies', 'peerDependencies']) {
const subDependencies = pkg.read(field)
if (subDependencies) {
for (const subDependency in subDependencies) {
if (!(subDependency in versions))
continue
subDependencies[subDependency] = versions[subDependency]
}
pkg.write(field, subDependencies)
}
}
}
}
export function bundle(bundleVersion, bundleOut, options) {
bundleOut = resolve(process.env.IDLIZE_BUNDLE_OUT ?? bundleOut ?? join(IDLIZE_HOME, "bundle"))
if (bundleOut === parse(bundleOut).root || bundleOut === IDLIZE_HOME ||
existsSync(join(bundleOut, 'package.json'))) {
throw new Error(`Refusing to clean unsafe bundle output directory: ${bundleOut}`)
}
if (options.idlizerOnly && !options.koalauiVersion) {
throw new Error('koalaui packages were not selected and their version is not specified')
}
const newVersion = mangleVersion(bundleVersion, options.pandaVersion)
const allDependencies = [
...koalaui_dependencies,
...idlizer_dependencies,
]
const bundlableDependencies = options.idlizerOnly ? idlizer_dependencies : allDependencies
const availablePackages = options.idlizerOnly ? idlize_packages : all_packages
const packageSnapshots = allDependencies.flatMap(dep => {
if (options.idlizerOnly && koalaui_dependencies.includes(dep)) {
return []
}
const pkg = findPackage(dep, availablePackages)
return [{
snapshot: pkg.snapshot(),
package: pkg
}]
})
const newVersions = allDependencies.reduce((versions, dep) => {
versions[dep] = (options.idlizerOnly && koalaui_dependencies.indexOf(dep) >= 0) ?
options.koalauiVersion :
newVersion
return versions
}, {})
try {
applyVersions(bundlableDependencies, newVersions, availablePackages)
console.log("Compiling dependencies..")
bundlableDependencies.forEach(dep => {
const pkg = findPackage(dep, availablePackages)
console.log(`compiling ${pkg.name()}..`)
pkg.compile()
})
console.log("Packing..")
rmSync(bundleOut, { recursive: true, force: true })
mkdirSync(bundleOut, { recursive: true })
bundlableDependencies.forEach(dep => {
const pkg = findPackage(dep, availablePackages)
console.log(`packing ${pkg.name()}..`)
const packPath = pkg.pack()
copyFileSync(packPath, join(bundleOut, basename(packPath)))
rmSync(packPath)
})
const outputFiles = readdirSync(bundleOut).sort()
if (outputFiles.length !== bundlableDependencies.length ||
outputFiles.some(file => !file.endsWith('.tgz'))) {
throw new Error(`Unexpected bundle contents: ${outputFiles.join(', ')}`)
}
console.log(`All done! Bundle saved to ${bundleOut}`)
} finally {
packageSnapshots.forEach(record => {
record.package.restore(record.snapshot)
})
}
}