Harmony-Free Hengong Generator Automatically Generates Modes

bangjin yubangjin yu
3 min read

Hello everyone, welcome! Today, we will be discussing the scenario of automatically generating models using JSON in Harmony. Many students often make mistakes when writing model data, either by omitting or miswriting certain parameters, or by incorrectly specifying the data type of the parameters. This can lead to unexpected errors during development, which require multiple debugging attempts to identify the problem. In this session, I will guide you all through using the hvigor script to implement the generator to automatically generate models, ensuring the correctness of the models.

一、First, create a TypeScript project and import the necessary dependencies. You can refer to hvigor plugin development for details. Additionally, take a look at hvigor - it is a lightweight build tool provided by Huawei, which enables the automatic generation of models by writing JavaScript code.

二、The data in the JSON file is read from the specified path of the JSON data file using the hvigor and fs-extra plugins.

1、Traverse and read the JSON file

traverseDirectory(path:string,complete: (dirent: fs.Dirent<string>) => void){
    fs.readdir(path, { withFileTypes: true },(err,dirents)=>{
        if (err) {
            log(`Error reading directory ${path}:${err}`);
            return;
        }
        dirents.forEach((dirent)=>{
            const fullPath = `${path}/${dirent.name}`;
            if (dirent.isDirectory()){
                // If it is a folder, make a recursive call
                fs.mkdir(`${this.config.out}/${dirent.name}`)
                this.traverseDirectory(fullPath,complete);
            }else{
                complete(dirent)
            }
        })
    })
}

2、Read the file data

this.traverseDirectory(this.config.input,(dirent)=>{
    let buf =  fs.readFileSync(dirent.parentPath + "/" + dirent.name,{encoding:'utf-8'})
})

三、Create the model file using the fs-extra plugin and output it to the "out" folder. Create the model file based on the JSON file. Convert the JSON data into model data using jsonToModel, and then write it into the model file.

1、Convert JSON data to model data

jsonToModel(json:object,name:string):string{
    let data = Object.entries(json);
    let body = "";
    let init = `\tconstructor(face:${name}Face) {\n\t\tif(face==null)`;
    let otherMap:Map<string,any> = new Map()
    data.forEach((k)=>{
        if(k[1] instanceof Array){
            body += `\t${k[0]}:Array<${this.arrayToModel(k[0],k[1],otherMap,name)}> | undefined \n`
        }else if(k[1] != null && typeof k[1] == "object"){
            let objName = name + k[0].substring(0, 1).toUpperCase() + k[0].substring(1);
            otherMap.set(objName,k[1])
            body += `\t${k[0]}:${objName}Model | undefined \n`
        }else{
            body += `\t${k[0]}:${typeof k[1]} | undefined \n`
        }
        init += `\t\tthis.${k[0]} = face.${k[0]} \n`
    })
    let model = `export interface ${name}Face{ \n ${body}}\n\n`
    model += `export class ${name}Model implements ${name}Face{\n${body}\n}\n\n`
    otherMap.forEach((v,k)=>{
        model += this.jsonToModel(v,k)
    })
    return model
}
// Handling array nesting issues
arrayToModel(k:string,v:Array<any>,otherMap:Map<string,any>,name:string):string{
    if(v.length > 0){
        if(typeof v[0] == "object"){
            if(v[0] instanceof Array){
                return `Array<${this.arrayToModel(k,v[0],otherMap,name)}>`;
            }else{
                let objName = name + k.substring(0, 1).toUpperCase() + k.substring(1);
                otherMap.set(objName,v[0])
                return objName + "Model"
            }
        }else{
            return typeof v[0]
        }
    }else{
        return "object"
    }
}

2、Based on creating the model file and writing the model data into the model file

this.traverseDirectory(this.config.input,(dirent)=>{
    let buf =  fs.readFileSync(dirent.parentPath + "/" + dirent.name,{encoding:'utf-8'})
    let fileName = dirent.name.split('.')[0];
    fileName = fileName.substring(0, 1).toUpperCase() + fileName.substring(1);
    const filePath = `${this.config.out}/${fileName}.g.ets`;
    let model = this.jsonToModel(JSON.parse(buf),fileName)
    fs.writeFileSync(filePath,model)
})

Note: The complete code has been submitted to Code Repository,Go to Download.tgz package

1、Manual Import: Place the downloaded.tgz package into the project. In the /hvigor/hvigor-config.json5 file, introduce XXX to replace the storage path.

/hvigor/hvigor-config.json5

{
  "dependencies": {
    "@free/generator": "file:../XXX.tgz"
  },
}
  1. Introduce the hvigorfile.json5 file under the "entry" directory.
/entry/hvigorfile.json5

import { jsonToModelPlugin } from '@free/generator';

// Input: The location for JSON input. Default: /entry/json/
// Output: The location for the model. Default: /entry/model/

export default {
    system: hapTasks, 
    plugins:[
        jsonToModelPlugin(input?:string,out?:string)
    ]        
}

3、Execute the command hvigorw --sync

If you like this content, please give a little heart!

0
Subscribe to my newsletter

Read articles from bangjin yu directly inside your inbox. Subscribe to the newsletter, and don't miss out.

Written by

bangjin yu
bangjin yu