diff --git a/arkoala-arkts/shopping/user/ui2abc.json b/arkoala-arkts/shopping/user/ui2abc.json new file mode 100644 index 0000000000000000000000000000000000000000..544f2de45636d578e2f8231a09367f52138038e6 --- /dev/null +++ b/arkoala-arkts/shopping/user/ui2abc.json @@ -0,0 +1,13 @@ +{ + "compilerOptions": { + "package": "@koalaui/user", + "outDir": "build/abc", + "baseUrl": "." + }, + "ets": [ + "./src/ets/**/*.ets" + ], + "memoOnly": [ + "./src/**/*.ts" + ] +} diff --git a/arkoala-arkts/trivial/user/package.json b/arkoala-arkts/trivial/user/package.json index d92b95543d13be0b6daac43ef27b04b0ef9dfe57..79775d524cc463425b6ba038cb615e9f7cad500f 100644 --- a/arkoala-arkts/trivial/user/package.json +++ b/arkoala-arkts/trivial/user/package.json @@ -4,8 +4,8 @@ "description": "", "scripts": { "clean": "rimraf build generated unmemoized js_output abc lib app/user/build", - "compile:plugin": "cd ../../../arkoala/ets-plugin && npm run compile", - "compile:ets": "npm run compile:plugin && cd src/ets && ets-tsc -p ./etsconfig.json", + "compile:plugin": "cd ../../../arkoala/ets-plugin && npm run compile && npm run compile --prefix ../../incremental/tools/ui2abc", + "compile:ets": "npm run compile:plugin && ../../../incremental/tools/ui2abc/lib/ui2abc.js --config ui2abc.json", "unmemoize": "npm run compile:ets && ets-tsc -p tsconfig-unmemoize.json", "unmemoize:runtime": "npm run unmemoize --prefix ../../../incremental/runtime", "unmemoize:arkui-no-common": "npm run unmemoize --prefix ../../arkui", diff --git a/arkoala-arkts/trivial/user/ui2abc.json b/arkoala-arkts/trivial/user/ui2abc.json new file mode 100644 index 0000000000000000000000000000000000000000..ea371aa7e892319ebf2af9f4d8645809b52e684a --- /dev/null +++ b/arkoala-arkts/trivial/user/ui2abc.json @@ -0,0 +1,10 @@ +{ + "compilerOptions": { + "package": "@koalaui/user", + "outDir": "build/abc", + "baseUrl": "." + }, + "ets": [ + "./src/ets/**/*.ets" + ] +} diff --git a/arkoala/ets-plugin/src/ArkExpander.ts b/arkoala/ets-plugin/src/ArkExpander.ts index 88df0994e6233ede85eae3023e6eefc911d99443..d672ebd4c2eade4a9bb27cfd4b52c450b422a561 100644 --- a/arkoala/ets-plugin/src/ArkExpander.ts +++ b/arkoala/ets-plugin/src/ArkExpander.ts @@ -177,15 +177,18 @@ export default function arkExpander(program: ts.Program, userPluginOptions: ArkT moduleInfo: userPluginOptions.moduleInfo } const typeChecker = program.getTypeChecker() - prepareDestination(pluginOptions.destination) const entryTracker = new EntryTracker(pluginOptions.source) return (ctx: ts.TransformationContext) => { + const configFile = ctx.getCompilerOptions().configFilePath as string + const destination = path.join(path.dirname(configFile), pluginOptions.destination) + prepareDestination(destination) + return (sourceFile: ts.SourceFile) => { if (!fileIsEligible(sourceFile.fileName)) { console.log("Verbatim TS: ", sourceFile.fileName) - printSourceFile(sourceFile, pluginOptions.source, pluginOptions.destination, ".ts") + printSourceFile(sourceFile, pluginOptions.source, destination, ".ts") return sourceFile } else { console.log("ETS->TS: " + path.normalize(sourceFile.fileName)) @@ -193,9 +196,9 @@ export default function arkExpander(program: ts.Program, userPluginOptions: ArkT let final = arkExpandFile(sourceFile, pluginOptions.arkui, typeChecker, ctx, extras, entryTracker, pluginOptions.moduleInfo) - printSourceFile(final, pluginOptions.source, pluginOptions.destination) + printSourceFile(final, pluginOptions.source, destination) if (pluginOptions.arkui != "@koalaui/arkts-arkui") { - updateRouterDestinationsFile(pluginOptions.destination, entryTracker) + updateRouterDestinationsFile(destination, entryTracker) } // if (structTranslator.entryFile) { diff --git a/incremental/tools/ui2abc/package.json b/incremental/tools/ui2abc/package.json new file mode 100644 index 0000000000000000000000000000000000000000..cab955f219a3f7a19abdaa51f7a40f6361ef5872 --- /dev/null +++ b/incremental/tools/ui2abc/package.json @@ -0,0 +1,24 @@ +{ + "name": "@koalaui/ui2abc", + "version": "1.5.0+devel", + "description": "", + "main": "lib/ui2abc.js", + "bin": "lib/ui2abc.js", + "scripts": { + "clean": "rimraf out lib", + "compile": "npx tsc ui2abc.ts --target esnext --module commonjs --outDir lib && chmod a+x lib/ui2abc.js" + }, + "keywords": [], + "dependencies": { + "commander": "^10.0.0", + "minimatch": "10.0.1" + }, + "devDependencies": { + "@types/node": "^18.0.0", + "typescript": "^4.9.5", + "webpack": "5.95.0", + "copy-webpack-plugin": "12.0.2", + "webpack-cli": "5.1.4", + "rimraf": "^6.0.1" + } +} diff --git a/incremental/tools/ui2abc/ui2abc.ts b/incremental/tools/ui2abc/ui2abc.ts new file mode 100644 index 0000000000000000000000000000000000000000..2b0a6e73cc5d9c7a529c5806531831767383df9e --- /dev/null +++ b/incremental/tools/ui2abc/ui2abc.ts @@ -0,0 +1,226 @@ +#!/usr/bin/env node + +/* + * 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 { program } from "commander" +import * as fs from "fs" +import * as path from "path" +import { spawnSync } from "child_process" +import { minimatch } from 'minimatch' + + +const readdirSyncRecursive: (dir: string) => string[] = (dir: string) => + fs.readdirSync(dir).reduce((files: string[], file: string) => { + const name = path.join(dir, file) + return fs.lstatSync(name).isDirectory() ? [...files, ...readdirSyncRecursive(name)] : [...files, name] + }, []) + + +function findMatching(base: string, include: string[], exclude: string[]): string[] { + return readdirSyncRecursive(base) + .map(it => path.resolve(it)) + .filter(it => include.some(value => minimatch(it, path.join(base, value), { matchBase: true }))) + .filter(it => !exclude.some(value => minimatch(it, path.join(base, value), { matchBase: true }))) +} + +function findFiles(uiConfigFile: string, section: string): string[] { + const config = JSON.parse(fs.readFileSync(uiConfigFile, 'utf8')) + const baseDir = path.resolve(path.dirname(uiConfigFile)) + const include = config[section] ? (config[section]).map(it => it.replace('\\.', '.')) : [] + console.log(section, include) + const exclude = config.exclude ? (config.exclude as string[]).map(it => it.replace('\\.', '.')) : [] + const files = findMatching(baseDir, include, exclude) + return files +} + +function buildDir(configFile: string): string { + const configDir = path.dirname(configFile) + const build = path.resolve(path.join(configDir, "build")) + fs.mkdirSync(build, { recursive: true }) + return build +} + +function generateEtsConfig(inputFile: string, userConfigFile: string, outputFile: string): string { + const etsConfigDir = buildDir(userConfigFile) + const build = "." + const includeFile = path.relative(etsConfigDir, inputFile) + const baseUrl = "." + const destination = `${build}/generated/` + + const etsConfig = { + extends: "@koalaui/arkts-arkui/config/etsconfig-base.json", + include: [ + includeFile + ], + compilerOptions: { + types: [], + baseUrl: baseUrl, + rootDirs: [ + baseUrl + ], + outDir: `${build}/ets-junk`, + plugins: [ + { + transform: "@koalaui/ets-plugin/build/lib/src/ArkExpander.js", + destination: destination, + arkui: "@koalaui/arkts-arkui" + } + ] + } + } + + return JSON.stringify(etsConfig, undefined, 4) +} + +function generateMemoConfig(inputFile: string, userConfigFile: string, outputFile: string): string { + const memoConfigDir = buildDir(userConfigFile) + const build = "." + const includeFile = path.relative(memoConfigDir, inputFile) + const baseUrl = "." + const destination = `${build}/unmemoized/` + + const memoConfig = { + extends: "@koalaui/build-common/tsconfig.json", + compilerOptions: { + types: [], + plugins: [ + { + transform: "@koalaui/compiler-plugin/build/lib/src/koala-transformer.js", + trace: false, + only_unmemoize: true, + unmemoizeDir: destination + } + ], + outDir: `${build}/junk`, + baseUrl: baseUrl, + paths: { + "@koalaui/arkui-common": [ + "../../../../arkoala/arkui-common/src/arkts" + ], + "@koalaui/runtime": [ + "../../../../incremental/runtime" + ], + "#arkcompat": [ + "../../../../arkoala/arkui-common/src/arkts" + ], + "@koalaui/arkts-arkui": [ + "../../../arkui/src" + ], + "@koalaui/arkts-arkui/ohos.router": [ + "../../../arkui/src/ohos.router.ts" + ], + "app/*": [ + `${build}/generated/src/ets/*` + ] + } + }, + files: [ + "../../../../incremental/tools/panda/arkts/std-lib/global.d.ts" + ], + include: [ + includeFile + ], + // TODO: remove these from the generation already! + exclude: [ + "../../arkui/src/generated/arkts", + "../../arkui/src/generated/common.ts", + "../../arkui/src/generated/test_utils.ts", + "../../arkui/src/generated/main.ts" + ], + // This seems very ad hoc. + references: [ + { "path": "../../../../arkoala/arkui-common" }, + { "path": "../../../../arkoala/arkui-common/tsconfig-unmemoize.json" }, + { "path": "../../../../incremental/runtime" }, + { "path": "../../../arkui/tsconfig-unmemoize.json" } + ] + } + + return JSON.stringify(memoConfig, undefined, 4) +} + +function createEtsConfig(file: string, config: string, output: string): string { + const etsConfigFile = path.join(buildDir(config), "etsconfig.json") + console.log(`Producing ${etsConfigFile}`) + fs.writeFileSync(etsConfigFile, generateEtsConfig(file, config, output)) + return etsConfigFile +} + +function createMemoConfig(file: string, config: string, output: string): string { + const memoConfigFile = path.join(buildDir(config), "tsconfig-unmemoize.json") + console.log(`Producing ${memoConfigFile}`) + fs.writeFileSync(memoConfigFile, generateMemoConfig(file, config, output)) + return memoConfigFile +} + +function runCmd(command: string, args: string[]) { + + console.log(`${command} ${args.join(" ")}`) + const result = spawnSync(command, args) + console.log(result.stdout.toString()) + console.log(result.stderr.toString()) + if (result.signal) { + console.log(`${command}: signal ${result.signal}`) + return false + } + if (result.status != 0) { + console.log(`${command} returned ${result.status}`) + return false + } + if (result.error) { + console.log("${command} error:", result.error) + return false + } + return true +} +function etsTsc(file: string, etsConfig: string) { + let npx = process.platform === "win32" ? "npx.cmd" : "npx" + return runCmd(npx, ["ets-tsc", "-p", etsConfig]) +} + +function ui2abc(file: string, config: string, output: string) { + const etsFiles = findFiles(config, "ets") + etsFiles.forEach(file => { + const etsConfig = createEtsConfig(file, config, output) + etsTsc(file, etsConfig) + }) + + const pureMemoFiles = findFiles(config, "memoOnly") + const build = buildDir(config) + const memoIntermediates = etsFiles.map(it => path.join(build, it)) + const allMemoFiles = [...pureMemoFiles, ...memoIntermediates] + allMemoFiles.forEach(file => { + const memoConfig = createMemoConfig(file, config, output) + etsTsc(file, memoConfig) + }) + /* + const arktsConfig = generateArktsConfig(file, config, output) + es2panda(file, arktsConfig, output) + */ +} + +export function main() { + const options = program + .option('--file ', 'Path to input .ets file') + .option('--config ', 'Path to arktsconfig.json file') + .option('--output ', 'Path to output .abc file') + .parse() + .opts() + + ui2abc(options.file, options.config, options.output) +} + +main() \ No newline at end of file