@yt778/code-cst
v0.1.15
Published
TypeScript CLI that converts an entire Android project (Kotlin/Java/Gradle/XML) into Concrete Syntax Trees via tree-sitter wasm grammars.
Maintainers
Readme
@yt778/code-cst
A TypeScript CLI that converts an Android (Kotlin / Jetpack Compose) project into a standalone HarmonyOS (ArkTS / ArkUI) project skeleton — powered by tree-sitter wasm grammars, no native compilation.
npm install -g @yt778/code-cst
cst convert ./my-kotlin-app ./hm-outcst convert <target> <outDir> copies a runnable HarmonyOS scaffold into <outDir>, parses
the Kotlin source, extracts data / logic / UI constructs, renders ArkTS .ets stubs into the
scaffold's entry module, migrates image & string resources, and (by default) runs a real
DevEco compile check. The result is a complete, type-checkable HarmonyOS project you can
open in DevEco Studio.
What this is — and isn't. It is a porting accelerator: it scaffolds the project and stubs out the structure (classes, fields,
@ComponentV2UI, navigation shell) so you start from a compiling skeleton instead of a blank project. Generated method bodies are// GENERATED — REVIEW REQUIREDplaceholders — not working logic. Don't measure success by "does the output run as an app"; measure it by "how much boilerplate did it save me."
Requirements
- Node.js ≥ 18 (tested on Node 22)
- For the optional compile check: DevEco Studio installed (
DEVECO_HOME, or auto-detected). Without it the check self-skips — generation still runs.
Install
# 1) Global install — gives you the `cst` (and `ycst`) command system-wide
npm install -g @yt778/code-cst
cst --version
# 2) Or run once without installing
npx @yt778/code-cst convert ./my-kotlin-app ./hm-outNo registry config needed on the user side — install from your default registry. (The project's
.npmrconly routes the@yt778scope to the official registry for publishing.)
Usage
cst convert <kotlin-project> <outDir> [options]Convert a project into a HarmonyOS project at ./hm-out:
cst convert /path/to/FunnyTranslation ./hm-out
# → Scaffolding HarmonyOS project at ./hm-out…
# → Discovered 317 Kotlin file(s). Generating…
# → Generated 510 construct(s) [data:248 ui:244 logic:18] · skipped 220
# → ArkTS: 7 error node(s) across 511 file(s)Inspect only a subset with --filter, skip the slow DevEco check with --no-check, or skip
resource migration with --no-resources.
Options
| Flag | Default | Description |
|---|---|---|
| -t, --template <t> | auto | Force a template: data · logic · ui · auto (auto-classify each construct) |
| --filter <globs> | — | Comma-separated include globs (project-relative) |
| -q, --quiet | off | Suppress progress output |
| --wasm-dir <dir> | bundled | Directory holding grammar wasm files |
| --trace | off | Emit a full conversion report to stderr |
| --force | off | Overwrite a non-empty <outDir> (refuses non-empty otherwise) |
| --no-check | off | Skip the post-conversion DevEco compile check |
| --no-resources | off | Skip migrating image resources (drawable/mipmap → media/) |
| --all-resources | off | Migrate every image under the source's resource roots, not just referenced ones |
| --no-app-shell | off | Skip emitting the Navigation + Tabs app shell (entry Index.ets + routing) |
| --emit-dsl | off | Dump each UI construct's DSL intermediate (<Name>.dsl.json) next to the .ets |
-h, --help and -V, --version work as usual. Exit code is non-zero when the DevEco compile
check finds errors (CI-ready).
What you get
hm-out/
├── AppScope/ # app-level config + icons (scaffold)
├── entry/
│ ├── src/main/
│ │ ├── ets/
│ │ │ ├── entryability/EntryAbility.ets # scaffold
│ │ │ ├── pages/Index.ets # Navigation + Tabs shell
│ │ │ └── com/<pkg>/… # generated .ets (mirrors the Kotlin package)
│ │ ├── main/resources/… # migrated strings + images
│ │ └── module.json5
│ └── build-profile.json5
├── hvigor/ … build-profile.json5 … oh-package.json5
└── … a complete HarmonyOS project, openable in DevEcoEach generated file is one of three kinds, auto-classified from the Kotlin construct:
data (data/model classes → @ObservedV2 / interfaces), logic (ViewModels), and
ui (@Composable → @ComponentV2 struct build()). Nested Kotlin types are hoisted to
top-level (ArkTS can't nest class declarations).
Build from source
git clone <repo> && cd cst_demo
npm install
npm run build # scripts/build.mjs: tsc --noEmit (type gate) → esbuild bundles src/cli.ts
# into a single dist/cli.js → copies runtime assets into dist/. No sourcemaps.
node dist/cli.js convert <kotlin-project> <outDir>
# live during development: npm run dev -- convert <kotlin-project> <outDir>The published package ships only dist/ (files: ["dist"]): one bundled cli.js + the
runtime data it reads (grammar wasm/, templates/, mappings/, the per-converter
*.json5 tables, the spawned DevEco checker arkts-check.cjs, and web-tree-sitter.wasm).
Internals: the CST engine
convert is built on a lossless tree-sitter Concrete Syntax Tree engine. Every node
carries startIndex/endIndex byte ranges, so any construct's source is sliceable from the
file text — lossless by default. This CST (not a lossy AST) is what lets the converter read
exact source while emitting ArkTS. The engine (walker → pool → parser → serialize) is
an internal library convert calls; it is not exposed as a CLI command.
The converter is data- and registry-driven — you extend it without touching the main loop:
mapping rules in mappings/mappings.json5, per-component
Compose→ArkUI tables co-located with each converter (src/gen/ui/<c>/<c>.json5), and
self-registering converters/checkers. See docs/DESIGN.md,
docs/CLASSIFICATION.md, docs/RENDERING.md,
and docs/COMPONENT_CONVERTER.md for the full architecture.
Grammar wasms ship under wasm/: tree-sitter-kotlin, -java, -xml, -arkts. Point at a
different folder with --wasm-dir; a missing grammar warns and skips those files rather than
failing.
