├── CMakeLists.txt ├── .github └── workflows │ ├── ios.yml │ ├── android.yml │ ├── ubuntu.yml │ ├── macos.yml │ └── windows.yml ├── Worker.h ├── main.cpp ├── README.md ├── .gitattributes ├── .gitignore ├── .clang-format └── Worker.cpp /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.5) 2 | 3 | project(QObject2Ts LANGUAGES CXX) 4 | 5 | set(CMAKE_INCLUDE_CURRENT_DIR ON) 6 | 7 | set(CMAKE_AUTOUIC ON) 8 | set(CMAKE_AUTOMOC ON) 9 | set(CMAKE_AUTORCC ON) 10 | 11 | set(CMAKE_CXX_STANDARD 11) 12 | set(CMAKE_CXX_STANDARD_REQUIRED ON) 13 | 14 | find_package(Qt5Core) 15 | SET(EXECUTABLE_OUTPUT_PATH ${PROJECT_SOURCE_DIR}/bin) 16 | add_executable(QObject2Ts 17 | main.cpp 18 | Worker.cpp 19 | ) 20 | target_link_libraries(QObject2Ts Qt5::Core) 21 | 22 | -------------------------------------------------------------------------------- /.github/workflows/ios.yml: -------------------------------------------------------------------------------- 1 | name: IOS 2 | on: 3 | push: 4 | paths-ignore: 5 | - 'README.md' 6 | pull_request: 7 | paths-ignore: 8 | - 'README.md' 9 | jobs: 10 | build: 11 | name: Build 12 | runs-on: ${{ matrix.os }} 13 | strategy: 14 | matrix: 15 | os: [macos-latest] 16 | qt_ver: [5.12.6] 17 | qt_target: [ios] 18 | steps: 19 | - name: Install Qt 20 | # if: steps.cacheqt.outputs.cache-hit != 'true' 21 | uses: jurplel/install-qt-action@v2.0.0 22 | with: 23 | # Version of Qt to install 24 | version: ${{ matrix.qt_ver }} 25 | # Target platform for build 26 | target: ${{ matrix.qt_target }} 27 | - uses: actions/checkout@v1 28 | with: 29 | fetch-depth: 1 30 | - name: build ios 31 | run: | 32 | cmake . -DCONFIG+=release -DCONFIG+=iphoneos 33 | make 34 | -------------------------------------------------------------------------------- /Worker.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | 4 | #include 5 | namespace Meta { 6 | struct Arg { 7 | QString type; 8 | QString name; 9 | }; 10 | struct Property : Arg { 11 | QString notify; 12 | QString get; 13 | QString set; 14 | bool readonly = false; 15 | }; 16 | 17 | struct Method { 18 | bool isNotifyMethod = false; 19 | QString name; 20 | QString returnType; 21 | QList args; 22 | }; 23 | struct MetaObj { 24 | QString name; 25 | QList properties; 26 | QList methods; 27 | }; 28 | } // namespace Meta 29 | 30 | class Worker { 31 | public: 32 | void work(const QString &inputFile, const QString &outputFile); 33 | 34 | private: 35 | void parseLine(const QString &line); 36 | void parseProperty(const QString &line); 37 | void parseFunction(bool isInvok, const QString &type, const QString &name, const QString &args); 38 | 39 | void parseArgs(QList &args, const QString &argsStr); 40 | void writeTs(const QString &outputFile); 41 | 42 | private: 43 | Meta::MetaObj m_obj; 44 | }; 45 | -------------------------------------------------------------------------------- /main.cpp: -------------------------------------------------------------------------------- 1 | #include "Worker.h" 2 | #include 3 | #include 4 | #include 5 | #include 6 | int main(int argc, char *argv[]) 7 | { 8 | QCoreApplication::setApplicationName("QObject2TS"); 9 | QCoreApplication::setOrganizationName("jaredtao"); 10 | QCoreApplication::setOrganizationDomain("https://jaredtao.github.io"); 11 | QCoreApplication::setApplicationVersion("1.0.0"); 12 | 13 | QCoreApplication a(argc, argv); 14 | 15 | QCommandLineParser parser; 16 | parser.setApplicationDescription("convert QObject to typescript"); 17 | parser.addPositionalArgument("input", "input file path"); 18 | parser.addPositionalArgument("output", "output file path"); 19 | parser.addHelpOption(); 20 | parser.addVersionOption(); 21 | 22 | parser.process(a); 23 | 24 | QString inputFile; 25 | QString outputFile; 26 | 27 | if (parser.positionalArguments().size() < 1) { 28 | parser.showHelp(); 29 | } 30 | inputFile = parser.positionalArguments().at(0); 31 | if (parser.positionalArguments().size() > 1) { 32 | parser.positionalArguments().at(1); 33 | } else { 34 | QFileInfo info(inputFile); 35 | outputFile = info.absolutePath() + "/" + info.baseName() + ".ts"; 36 | } 37 | 38 | Worker worker; 39 | worker.work(inputFile, outputFile); 40 | 41 | return 0; 42 | } 43 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # QObject2Ts 2 | 3 | 简易Qt反射器。 4 | 5 | 解析QObject声明文件,生成对应的typescript文件。 6 | 7 | 提取属性、public Q_INVOK函数、public slots函数。 8 | 9 | Qt版本: 5.12.x 10 | 11 | ## status 12 | | [Windows][win-link]| [Ubuntu][ubuntu-link]|[MacOS][macos-link]|[Android][android-link]|[IOS][ios-link]| 13 | |---------------|---------------|-----------------|-----------------|----------------| 14 | | ![win-badge] | ![ubuntu-badge] | ![macos-badge] |![android-badge] |![ios-badge] | 15 | 16 | 17 | [win-link]: https://github.com/JaredTao/QObject2Ts/actions?query=workflow%3AWindows "WindowsAction" 18 | [win-badge]: https://github.com/JaredTao/QObject2Ts/workflows/Windows/badge.svg "Windows" 19 | 20 | [ubuntu-link]: https://github.com/JaredTao/QObject2Ts/actions?query=workflow%3AUbuntu "UbuntuAction" 21 | [ubuntu-badge]: https://github.com/JaredTao/QObject2Ts/workflows/Ubuntu/badge.svg "Ubuntu" 22 | 23 | [macos-link]: https://github.com/JaredTao/QObject2Ts/actions?query=workflow%3AMacOS "MacOSAction" 24 | [macos-badge]: https://github.com/JaredTao/QObject2Ts/workflows/MacOS/badge.svg "MacOS" 25 | 26 | [android-link]: https://github.com/JaredTao/QObject2Ts/actions?query=workflow%3AAndroid "AndroidAction" 27 | [android-badge]: https://github.com/JaredTao/QObject2Ts/workflows/Android/badge.svg "Android" 28 | 29 | [ios-link]: https://github.com/JaredTao/QObject2Ts/actions?query=workflow%3AIOS "IOSAction" 30 | [ios-badge]: https://github.com/JaredTao/QObject2Ts/workflows/IOS/badge.svg "IOS" -------------------------------------------------------------------------------- /.github/workflows/android.yml: -------------------------------------------------------------------------------- 1 | name: Android 2 | on: 3 | push: 4 | paths-ignore: 5 | - 'README.md' 6 | - 'LICENSE' 7 | pull_request: 8 | paths-ignore: 9 | - 'README.md' 10 | - 'LICENSE' 11 | jobs: 12 | build: 13 | name: Build 14 | runs-on: ${{ matrix.os }} 15 | strategy: 16 | matrix: 17 | os: [ubuntu-latest] 18 | # 5.9.8 版本低,需要额外设置工具链。这里暂不支持。 19 | qt_ver: [5.12.6] 20 | qt_target: [android] 21 | # android_arm64_v8a 暂时不支持. install-qt-action 依赖的aqtinstall版本为0.5*,需要升级 22 | # qt_arch: [android_x86,android_armv7,android_arm64_v8a] 23 | qt_arch: [android_x86,android_armv7] 24 | # exclude: 25 | # - qt_ver: 5.9.8 26 | # qt_arch: android_arm64_v8a 27 | steps: 28 | - name: Install Qt 29 | # if: steps.cacheqt.outputs.cache-hit != 'true' 30 | uses: jurplel/install-qt-action@v2.0.0 31 | with: 32 | # Version of Qt to install 33 | version: ${{ matrix.qt_ver }} 34 | # Target platform for build 35 | target: ${{ matrix.qt_target }} 36 | # Architecture for Windows/Android 37 | arch: ${{ matrix.qt_arch }} 38 | - uses: actions/checkout@v1 39 | with: 40 | fetch-depth: 1 41 | - name: build android 42 | run: | 43 | export ANDROID_SDK_ROOT=$ANDROID_HOME 44 | export ANDROID_NDK_ROOT=$ANDROID_HOME/ndk-bundle 45 | cmake . 46 | make -------------------------------------------------------------------------------- /.github/workflows/ubuntu.yml: -------------------------------------------------------------------------------- 1 | name: Ubuntu 2 | # Qt官方没有linux平台的x86包 3 | on: 4 | push: 5 | paths-ignore: 6 | - 'README.md' 7 | - 'LICENSE' 8 | pull_request: 9 | paths-ignore: 10 | - 'README.md' 11 | - 'LICENSE' 12 | jobs: 13 | build: 14 | name: Build 15 | runs-on: ${{ matrix.os }} 16 | strategy: 17 | matrix: 18 | os: [ubuntu-16.04,ubuntu-18.04] 19 | qt_ver: [5.12.6] 20 | qt_arch: [gcc_64] 21 | steps: 22 | - name: cacheQt 23 | id: UbuntuCacheQt 24 | uses: actions/cache@v1 25 | with: 26 | path: ../Qt/${{matrix.qt_ver}}/${{matrix.qt_arch}} 27 | key: ${{ runner.os }}-Qt/${{matrix.qt_ver}}/${{matrix.qt_arch}} 28 | - name: setupQt 29 | if: steps.UbuntuCacheQt.outputs.cache-hit == 'true' 30 | shell: pwsh 31 | env: 32 | QtPath: ../Qt/${{matrix.qt_ver}}/${{matrix.qt_arch}} 33 | run: | 34 | $qt_Path=${env:QtPath} 35 | echo "::set-env name=Qt5_Dir::$qt_Path" 36 | echo "::add-path::$qt_Path/bin" 37 | - name: Install Qt 38 | if: steps.UbuntuCacheQt.outputs.cache-hit != 'true' 39 | uses: jurplel/install-qt-action@v2.0.0 40 | with: 41 | version: ${{ matrix.qt_ver }} 42 | - name: ubuntu install GL library 43 | run: sudo apt-get install -y libglew-dev libglfw3-dev 44 | - uses: actions/checkout@v1 45 | with: 46 | fetch-depth: 1 47 | - name: build ubuntu 48 | run: | 49 | qmake 50 | make -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | ############################################################################### 2 | # Set default behavior to automatically normalize line endings. 3 | ############################################################################### 4 | * text=auto 5 | ############################################################################### 6 | # Set default behavior for command prompt diff. 7 | # 8 | # This is need for earlier builds of msysgit that does not have it on by 9 | # default for csharp files. 10 | # Note: This is only used by command line 11 | ############################################################################### 12 | #*.cs diff=csharp 13 | ############################################################################### 14 | # Set the merge driver for project and solution files 15 | # 16 | # Merging from the command prompt will add diff markers to the files if there 17 | # are conflicts (Merging from VS is not affected by the settings below, in VS 18 | # the diff markers are never inserted). Diff markers may cause the following 19 | # file extensions to fail to load in VS. An alternative would be to treat 20 | # these files as binary and thus will always conflict and require user 21 | # intervention with every merge. To do so, just uncomment the entries below 22 | ############################################################################### 23 | #*.sln merge=binary 24 | #*.csproj merge=binary 25 | #*.vbproj merge=binary 26 | #*.vcxproj merge=binary 27 | #*.vcproj merge=binary 28 | #*.dbproj merge=binary 29 | #*.fsproj merge=binary 30 | #*.lsproj merge=binary 31 | #*.wixproj merge=binary 32 | #*.modelproj merge=binary 33 | #*.sqlproj merge=binary 34 | #*.wwaproj merge=binary 35 | ############################################################################### 36 | # behavior for image files 37 | # 38 | # image files are treated as binary by default. 39 | ############################################################################### 40 | #*.jpg binary 41 | #*.png binary 42 | #*.gif binary 43 | ############################################################################### 44 | # diff behavior for common document formats 45 | # 46 | # Convert binary document formats to text before diffing them. This feature 47 | # is only available from the command line. Turn it on by uncommenting the 48 | # entries below. 49 | ############################################################################### 50 | #*.doc diff=astextplain 51 | #*.DOC diff=astextplain 52 | #*.docx diff=astextplain 53 | #*.DOCX diff=astextplain 54 | #*.dot diff=astextplain 55 | #*.DOT diff=astextplain 56 | #*.pdf diff=astextplain 57 | #*.PDF diff=astextplain 58 | #*.rtf diff=astextplain 59 | #*.RTF diff=astextplain 60 | #*.png filter=lfs diff=lfs merge=lfs -text 61 | #*.jpg filter=lfs diff=lfs merge=lfs -text 62 | #*.gif filter=lfs diff=lfs merge=lfs -text 63 | -------------------------------------------------------------------------------- /.github/workflows/macos.yml: -------------------------------------------------------------------------------- 1 | name: MacOS 2 | on: 3 | push: 4 | paths-ignore: 5 | - 'README.md' 6 | - 'LICENSE' 7 | pull_request: 8 | paths-ignore: 9 | - 'README.md' 10 | - 'LICENSE' 11 | jobs: 12 | build: 13 | name: Build 14 | runs-on: ${{ matrix.os }} 15 | strategy: 16 | matrix: 17 | os: [macos-latest] 18 | qt_ver: [5.12.6] 19 | qt_arch: [clang_64] 20 | env: 21 | targetName: HelloActions-Qt 22 | steps: 23 | - name: cacheQt 24 | id: MacosCacheQt 25 | uses: actions/cache@v1 26 | with: 27 | path: ../Qt/${{matrix.qt_ver}}/${{matrix.qt_arch}} 28 | key: ${{ runner.os }}-Qt/${{matrix.qt_ver}}/${{matrix.qt_arch}} 29 | - name: setupQt 30 | if: steps.MacosCacheQt.outputs.cache-hit == 'true' 31 | shell: pwsh 32 | env: 33 | QtPath: ../Qt/${{matrix.qt_ver}}/${{matrix.qt_arch}} 34 | run: | 35 | $qt_Path=${env:QtPath} 36 | echo "::set-env name=Qt5_Dir::$qt_Path" 37 | echo "::add-path::$qt_Path/bin" 38 | - name: Install Qt 39 | if: steps.MacosCacheQt.outputs.cache-hit != 'true' 40 | uses: jurplel/install-qt-action@v2.0.0 41 | with: 42 | version: ${{ matrix.qt_ver }} 43 | 44 | - uses: actions/checkout@v1 45 | with: 46 | fetch-depth: 1 47 | - name: build macos 48 | run: | 49 | cmake . 50 | make 51 | # tag 打包 52 | - name: package 53 | if: startsWith(github.event.ref, 'refs/tags/') 54 | run: | 55 | # 拷贝依赖 56 | macdeployqt bin/${targetName}.app -qmldir=. -verbose=1 -dmg 57 | # tag 查询github-Release 58 | - name: queryRelease 59 | id: queryReleaseMacos 60 | if: startsWith(github.event.ref, 'refs/tags/') 61 | shell: pwsh 62 | env: 63 | githubFullName: ${{ github.event.repository.full_name }} 64 | ref: ${{ github.event.ref }} 65 | run: | 66 | [string]$tag = ${env:ref}.Substring(${env:ref}.LastIndexOf('/') + 1) 67 | [string]$url = 'https://api.github.com/repos/' + ${env:githubFullName} + '/releases/tags/' + ${tag} 68 | $response={} 69 | try { 70 | $response = Invoke-RestMethod -Uri $url -Method Get 71 | } catch { 72 | Write-Host "StatusCode:" $_.Exception.Response.StatusCode.value__ 73 | Write-Host "StatusDescription:" $_.Exception.Response.StatusDescription 74 | # 没查到,输出 75 | echo "::set-output name=needCreateRelease::true" 76 | return 77 | } 78 | [string]$latestUpUrl = $response.upload_url 79 | Write-Host 'latestUpUrl:'$latestUpUrl 80 | if ($latestUpUrl.Length -eq 0) { 81 | # 没查到,输出 82 | echo "::set-output name=needCreateRelease::true" 83 | } 84 | # tag 创建github-Release 85 | - name: createReleaseWin 86 | id: createReleaseWin 87 | if: startsWith(github.event.ref, 'refs/tags/') && steps.queryReleaseMacos.outputs.needCreateRelease == 'true' 88 | env: 89 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 90 | uses: actions/create-release@v1.0.0 91 | with: 92 | tag_name: ${{ github.ref }} 93 | release_name: Release ${{ github.ref }} 94 | body: ${{ github.event.head_commit.message }} 95 | draft: false 96 | prerelease: false 97 | # 重定向upload_url到环境变量uploadUrl。 98 | - name: getLatestTagRelease 99 | # tag 上一步无论成功还是失败都执行 100 | if: startsWith(github.event.ref, 'refs/tags/') 101 | shell: pwsh 102 | env: 103 | githubFullName: ${{ github.event.repository.full_name }} 104 | upUrl: ${{ steps.queryReleaseMacos.outputs.upload_url }} 105 | ref: ${{ github.event.ref }} 106 | run: | 107 | # upUrl不为空,导出就完事 108 | if (${env:upUrl}.Length -gt 0) { 109 | $v=${env:upUrl} 110 | echo "::set-env name=uploadUrl::$v" 111 | return 112 | } 113 | [string]$tag = ${env:ref}.Substring(${env:ref}.LastIndexOf('/') + 1) 114 | [string]$url = 'https://api.github.com/repos/' + ${env:githubFullName} + '/releases/tags/' + ${tag} 115 | $response = Invoke-RestMethod -Uri $url -Method Get 116 | [string]$latestUpUrl = $response.upload_url 117 | Write-Host 'latestUpUrl:'$latestUpUrl 118 | echo "::set-env name=uploadUrl::$latestUpUrl" 119 | Write-Host 'env uploadUrl:'${env:uploadUrl} 120 | # tag 上传Release 121 | - name: uploadRelease 122 | id: uploadRelease 123 | if: startsWith(github.event.ref, 'refs/tags/') 124 | env: 125 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 126 | uses: actions/upload-release-asset@v1.0.1 127 | with: 128 | upload_url: ${{ env.uploadUrl }} 129 | asset_path: ./bin/${{ env.targetName }}.dmg 130 | asset_name: ${{ env.targetName }}.dmg 131 | asset_content_type: application/applefile -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | ## Ignore Visual Studio temporary files, build results, and 2 | ## files generated by popular Visual Studio add-ons. 3 | 4 | build/ 5 | run/ 6 | # User-specific files 7 | *.suo 8 | *.user 9 | *.userosscache 10 | *.sln.docstates 11 | 12 | # User-specific files (MonoDevelop/Xamarin Studio) 13 | *.userprefs 14 | 15 | # Build results 16 | [Dd]ebug/ 17 | [Dd]ebugPublic/ 18 | [Rr]elease/ 19 | [Rr]eleases/ 20 | x64/ 21 | x86/ 22 | bld/ 23 | [Bb]in/ 24 | [Oo]bj/ 25 | [Ll]og/ 26 | 27 | # Visual Studio 2015 cache/options directory 28 | .vs/ 29 | # Uncomment if you have tasks that create the project's static files in wwwroot 30 | #wwwroot/ 31 | 32 | # MSTest test Results 33 | [Tt]est[Rr]esult*/ 34 | [Bb]uild[Ll]og.* 35 | 36 | # NUNIT 37 | *.VisualState.xml 38 | TestResult.xml 39 | 40 | # Build Results of an ATL Project 41 | [Dd]ebugPS/ 42 | [Rr]eleasePS/ 43 | dlldata.c 44 | 45 | # DNX 46 | project.lock.json 47 | project.fragment.lock.json 48 | artifacts/ 49 | 50 | *_i.c 51 | *_p.c 52 | *_i.h 53 | *.ilk 54 | *.meta 55 | *.obj 56 | *.pch 57 | *.pdb 58 | *.pgc 59 | *.pgd 60 | *.rsp 61 | *.sbr 62 | *.tlb 63 | *.tli 64 | *.tlh 65 | *.tmp 66 | *.tmp_proj 67 | *.log 68 | *.vspscc 69 | *.vssscc 70 | .builds 71 | *.pidb 72 | *.svclog 73 | *.scc 74 | 75 | # Chutzpah Test files 76 | _Chutzpah* 77 | 78 | # Visual C++ cache files 79 | ipch/ 80 | *.aps 81 | *.ncb 82 | *.opendb 83 | *.opensdf 84 | *.sdf 85 | *.cachefile 86 | *.VC.db 87 | *.VC.VC.opendb 88 | 89 | # Visual Studio profiler 90 | *.psess 91 | *.vsp 92 | *.vspx 93 | *.sap 94 | 95 | # TFS 2012 Local Workspace 96 | $tf/ 97 | 98 | # Guidance Automation Toolkit 99 | *.gpState 100 | 101 | # ReSharper is a .NET coding add-in 102 | _ReSharper*/ 103 | *.[Rr]e[Ss]harper 104 | *.DotSettings.user 105 | 106 | # JustCode is a .NET coding add-in 107 | .JustCode 108 | 109 | # TeamCity is a build add-in 110 | _TeamCity* 111 | 112 | # DotCover is a Code Coverage Tool 113 | *.dotCover 114 | 115 | # NCrunch 116 | _NCrunch_* 117 | .*crunch*.local.xml 118 | nCrunchTemp_* 119 | 120 | # MightyMoose 121 | *.mm.* 122 | AutoTest.Net/ 123 | 124 | # Web workbench (sass) 125 | .sass-cache/ 126 | 127 | # Installshield output folder 128 | [Ee]xpress/ 129 | 130 | # DocProject is a documentation generator add-in 131 | DocProject/buildhelp/ 132 | DocProject/Help/*.HxT 133 | DocProject/Help/*.HxC 134 | DocProject/Help/*.hhc 135 | DocProject/Help/*.hhk 136 | DocProject/Help/*.hhp 137 | DocProject/Help/Html2 138 | DocProject/Help/html 139 | 140 | # Click-Once directory 141 | publish/ 142 | 143 | # Publish Web Output 144 | *.[Pp]ublish.xml 145 | *.azurePubxml 146 | # TODO: Comment the next line if you want to checkin your web deploy settings 147 | # but database connection strings (with potential passwords) will be unencrypted 148 | #*.pubxml 149 | *.publishproj 150 | 151 | # Microsoft Azure Web App publish settings. Comment the next line if you want to 152 | # checkin your Azure Web App publish settings, but sensitive information contained 153 | # in these scripts will be unencrypted 154 | PublishScripts/ 155 | 156 | # NuGet Packages 157 | *.nupkg 158 | # The packages folder can be ignored because of Package Restore 159 | **/packages/* 160 | # except build/, which is used as an MSBuild target. 161 | !**/packages/build/ 162 | # Uncomment if necessary however generally it will be regenerated when needed 163 | #!**/packages/repositories.config 164 | # NuGet v3's project.json files produces more ignoreable files 165 | *.nuget.props 166 | *.nuget.targets 167 | 168 | # Microsoft Azure Build Output 169 | csx/ 170 | *.build.csdef 171 | 172 | # Microsoft Azure Emulator 173 | ecf/ 174 | rcf/ 175 | 176 | # Windows Store app package directories and files 177 | AppPackages/ 178 | BundleArtifacts/ 179 | Package.StoreAssociation.xml 180 | _pkginfo.txt 181 | 182 | # Visual Studio cache files 183 | # files ending in .cache can be ignored 184 | *.[Cc]ache 185 | # but keep track of directories ending in .cache 186 | !*.[Cc]ache/ 187 | 188 | # Others 189 | ClientBin/ 190 | ~$* 191 | *~ 192 | *.dbmdl 193 | *.dbproj.schemaview 194 | *.jfm 195 | *.pfx 196 | *.publishsettings 197 | node_modules/ 198 | orleans.codegen.cs 199 | 200 | # Since there are multiple workflows, uncomment next line to ignore bower_components 201 | # (https://github.com/github/gitignore/pull/1529#issuecomment-104372622) 202 | #bower_components/ 203 | 204 | # RIA/Silverlight projects 205 | Generated_Code/ 206 | 207 | # Backup & report files from converting an old project file 208 | # to a newer Visual Studio version. Backup files are not needed, 209 | # because we have git ;-) 210 | _UpgradeReport_Files/ 211 | Backup*/ 212 | UpgradeLog*.XML 213 | UpgradeLog*.htm 214 | 215 | # SQL Server files 216 | *.mdf 217 | *.ldf 218 | 219 | # Business Intelligence projects 220 | *.rdl.data 221 | *.bim.layout 222 | *.bim_*.settings 223 | 224 | # Microsoft Fakes 225 | FakesAssemblies/ 226 | 227 | # GhostDoc plugin setting file 228 | *.GhostDoc.xml 229 | 230 | # Node.js Tools for Visual Studio 231 | .ntvs_analysis.dat 232 | 233 | # Visual Studio 6 build log 234 | *.plg 235 | 236 | # Visual Studio 6 workspace options file 237 | *.opt 238 | 239 | # Visual Studio LightSwitch build output 240 | **/*.HTMLClient/GeneratedArtifacts 241 | **/*.DesktopClient/GeneratedArtifacts 242 | **/*.DesktopClient/ModelManifest.xml 243 | **/*.Server/GeneratedArtifacts 244 | **/*.Server/ModelManifest.xml 245 | _Pvt_Extensions 246 | 247 | # Paket dependency manager 248 | .paket/paket.exe 249 | paket-files/ 250 | 251 | # FAKE - F# Make 252 | .fake/ 253 | 254 | # JetBrains Rider 255 | .idea/ 256 | *.sln.iml 257 | 258 | # CodeRush 259 | .cr/ 260 | 261 | # Python Tools for Visual Studio (PTVS) 262 | __pycache__/ 263 | *.pyc 264 | /.vscode/settings.json 265 | *.user 266 | -------------------------------------------------------------------------------- /.clang-format: -------------------------------------------------------------------------------- 1 | --- 2 | # 语言: None, Cpp, Java, JavaScript, ObjC, Proto, TableGen, TextProto 3 | Language: Cpp 4 | # BasedOnStyle: WebKit 5 | # 访问说明符(public、private等)的偏移 6 | AccessModifierOffset: -4 7 | # 开括号(开圆括号、开尖括号、开方括号)后的对齐: Align, DontAlign, AlwaysBreak(总是在开括号后换行) 8 | AlignAfterOpenBracket: AlwaysBreak 9 | # 连续赋值时,对齐所有等号 10 | AlignConsecutiveAssignments: false 11 | # 连续声明时,对齐所有声明的变量名 12 | AlignConsecutiveDeclarations: false 13 | # 左对齐逃脱换行(使用反斜杠换行)的反斜杠 14 | AlignEscapedNewlines: Right 15 | # 水平对齐二元和三元表达式的操作数 16 | AlignOperands: true 17 | # 对齐连续的尾随的注释 18 | AlignTrailingComments: true 19 | # 允许函数声明的所有参数在放在下一行 20 | AllowAllParametersOfDeclarationOnNextLine: false 21 | # 允许短的块放在同一行 22 | AllowShortBlocksOnASingleLine: false 23 | # 允许短的case标签放在同一行 24 | AllowShortCaseLabelsOnASingleLine: false 25 | # 允许短的函数放在同一行: None, InlineOnly(定义在类中), Empty(空函数), Inline(定义在类中,空函数), All 26 | AllowShortFunctionsOnASingleLine: Empty 27 | # 允许短的if语句保持在同一行 28 | AllowShortIfStatementsOnASingleLine: false 29 | # 允许短的循环保持在同一行 30 | AllowShortLoopsOnASingleLine: false 31 | # 总是在定义返回类型后换行(deprecated) 32 | AlwaysBreakAfterDefinitionReturnType: None 33 | # 总是在返回类型后换行: None, All, TopLevel(顶级函数,不包括在类中的函数), 34 | # AllDefinitions(所有的定义,不包括声明), TopLevelDefinitions(所有的顶级函数的定义) 35 | AlwaysBreakAfterReturnType: None 36 | # 总是在多行string字面量前换行 37 | AlwaysBreakBeforeMultilineStrings: false 38 | # 总是在template声明后换行 39 | AlwaysBreakTemplateDeclarations: true 40 | # false表示函数实参要么都在同一行,要么都各自一行 41 | BinPackArguments: false 42 | # false表示所有形参要么都在同一行,要么都各自一行 43 | BinPackParameters: false 44 | # 在大括号前换行: Attach(始终将大括号附加到周围的上下文), Linux(除函数、命名空间和类定义,与Attach类似), 45 | # Mozilla(除枚举、函数、记录定义,与Attach类似), Stroustrup(除函数定义、catch、else,与Attach类似), 46 | # Allman(总是在大括号前换行), GNU(总是在大括号前换行,并对于控制语句的大括号增加额外的缩进), WebKit(在函数前换行), Custom 47 | # 注:这里认为语句块也属于函数 48 | BreakBeforeBraces: WebKit 49 | # 大括号换行,只有当BreakBeforeBraces设置为Custom时才有效 50 | BraceWrapping: 51 | # class定义后面 52 | AfterClass: true 53 | # 控制语句后面 54 | AfterControlStatement: false 55 | # enum定义后面 56 | AfterEnum: true 57 | # 函数定义后面 58 | AfterFunction: true 59 | # 命名空间定义后面 60 | AfterNamespace: true 61 | # ObjC定义后面 62 | AfterObjCDeclaration: false 63 | # struct定义后面 64 | AfterStruct: true 65 | # union定义后面 66 | AfterUnion: true 67 | # extern 定义后面 68 | AfterExternBlock: true 69 | # catch之前 70 | BeforeCatch: false 71 | # else 之前 72 | BeforeElse: false 73 | # 缩进大括号 74 | IndentBraces: false 75 | 76 | SplitEmptyFunction: true 77 | 78 | SplitEmptyRecord: true 79 | 80 | SplitEmptyNamespace: true 81 | # 在二元运算符前换行: None(在操作符后换行), NonAssignment(在非赋值的操作符前换行), All(在操作符前换行) 82 | BreakBeforeBinaryOperators: All 83 | 84 | # 继承列表的逗号前换行 85 | BreakBeforeInheritanceComma: true 86 | # 在三元运算符前换行 87 | BreakBeforeTernaryOperators: true 88 | # 在构造函数的初始化列表的逗号前换行 89 | BreakConstructorInitializersBeforeComma: true 90 | # 初始化列表前换行 91 | BreakConstructorInitializers: BeforeComma 92 | # Java注解后换行 93 | BreakAfterJavaFieldAnnotations: false 94 | 95 | BreakStringLiterals: true 96 | # 每行字符的限制,0表示没有限制 97 | ColumnLimit: 160 98 | # 描述具有特殊意义的注释的正则表达式,它不应该被分割为多行或以其它方式改变 99 | CommentPragmas: '^ IWYU pragma:' 100 | # 紧凑 命名空间 101 | CompactNamespaces: false 102 | # 构造函数的初始化列表要么都在同一行,要么都各自一行 103 | ConstructorInitializerAllOnOneLineOrOnePerLine: true 104 | # 构造函数的初始化列表的缩进宽度 105 | ConstructorInitializerIndentWidth: 4 106 | # 延续的行的缩进宽度 107 | ContinuationIndentWidth: 4 108 | # 去除C++11的列表初始化的大括号{后和}前的空格 109 | Cpp11BracedListStyle: false 110 | # 继承最常用的指针和引用的对齐方式 111 | DerivePointerAlignment: false 112 | # 关闭格式化 113 | DisableFormat: false 114 | # 自动检测函数的调用和定义是否被格式为每行一个参数(Experimental) 115 | ExperimentalAutoDetectBinPacking: false 116 | # 固定命名空间注释 117 | FixNamespaceComments: true 118 | # 需要被解读为foreach循环而不是函数调用的宏 119 | ForEachMacros: 120 | - foreach 121 | - Q_FOREACH 122 | - BOOST_FOREACH 123 | 124 | IncludeBlocks: Preserve 125 | # 对#include进行排序,匹配了某正则表达式的#include拥有对应的优先级,匹配不到的则默认优先级为INT_MAX(优先级越小排序越靠前), 126 | # 可以定义负数优先级从而保证某些#include永远在最前面 127 | IncludeCategories: 128 | - Regex: '^"(llvm|llvm-c|clang|clang-c)/' 129 | Priority: 2 130 | - Regex: '^(<|"(gtest|gmock|isl|json)/)' 131 | Priority: 3 132 | - Regex: 'stdafx\.' 133 | Priority: 1 134 | - Regex: '.*' 135 | Priority: 1 136 | 137 | IncludeIsMainRegex: '(Test)?$' 138 | # 缩进case标签 139 | IndentCaseLabels: true 140 | 141 | IndentPPDirectives: None 142 | # 缩进宽度 143 | IndentWidth: 4 144 | # 函数返回类型换行时,缩进函数声明或函数定义的函数名 145 | IndentWrappedFunctionNames: true 146 | 147 | JavaScriptQuotes: Leave 148 | 149 | JavaScriptWrapImports: true 150 | # 保留在块开始处的空行 151 | KeepEmptyLinesAtTheStartOfBlocks: true 152 | # 开始一个块的宏的正则表达式 153 | MacroBlockBegin: '' 154 | # 结束一个块的宏的正则表达式 155 | MacroBlockEnd: '' 156 | # 连续空行的最大数量 157 | MaxEmptyLinesToKeep: 1 158 | 159 | # 命名空间的缩进: None, Inner(缩进嵌套的命名空间中的内容), All 160 | NamespaceIndentation: All 161 | # 使用ObjC块时缩进宽度 162 | ObjCBlockIndentWidth: 4 163 | # 在ObjC的@property后添加一个空格 164 | ObjCSpaceAfterProperty: true 165 | # 在ObjC的protocol列表前添加一个空格 166 | ObjCSpaceBeforeProtocolList: true 167 | 168 | PenaltyBreakAssignment: 2 169 | 170 | PenaltyBreakBeforeFirstCallParameter: 19 171 | # 在一个注释中引入换行的penalty 172 | PenaltyBreakComment: 300 173 | # 第一次在<<前换行的penalty 174 | PenaltyBreakFirstLessLess: 120 175 | # 在一个字符串字面量中引入换行的penalty 176 | PenaltyBreakString: 1000 177 | # 对于每个在行字符数限制之外的字符的penalty 178 | PenaltyExcessCharacter: 1000000 179 | # 将函数的返回类型放到它自己的行的penalty 180 | PenaltyReturnTypeOnItsOwnLine: 60 181 | # 指针和引用的对齐: Left, Right, Middle 182 | PointerAlignment: Right 183 | 184 | #RawStringFormats: 185 | # - Delimiter: pb 186 | # Language: TextProto 187 | # BasedOnStyle: google 188 | # 允许重新排版注释 189 | ReflowComments: false 190 | # 允许排序#include 191 | SortIncludes: true 192 | 193 | SortUsingDeclarations: true 194 | # 在C风格类型转换后添加空格 195 | SpaceAfterCStyleCast: false 196 | # 模板关键字后面添加空格 197 | SpaceAfterTemplateKeyword: true 198 | # 在赋值运算符之前添加空格 199 | SpaceBeforeAssignmentOperators: true 200 | # 开圆括号之前添加一个空格: Never, ControlStatements, Always 201 | SpaceBeforeParens: ControlStatements 202 | # 在空的圆括号中添加空格 203 | SpaceInEmptyParentheses: false 204 | # 在尾随的评论前添加的空格数(只适用于//) 205 | SpacesBeforeTrailingComments: 1 206 | # 在尖括号的<后和>前添加空格 207 | SpacesInAngles: false 208 | # 在容器(ObjC和JavaScript的数组和字典等)字面量中添加空格 209 | SpacesInContainerLiterals: true 210 | # 在C风格类型转换的括号中添加空格 211 | SpacesInCStyleCastParentheses: false 212 | # 在圆括号的(后和)前添加空格 213 | SpacesInParentheses: false 214 | # 在方括号的[后和]前添加空格,lamda表达式和未指明大小的数组的声明不受影响 215 | SpacesInSquareBrackets: false 216 | # 标准: Cpp03, Cpp11, Auto 217 | Standard: Cpp11 218 | # tab宽度 219 | TabWidth: 4 220 | # 使用tab字符: Never, ForIndentation, ForContinuationAndIndentation, Always 221 | UseTab: Never 222 | ... 223 | 224 | -------------------------------------------------------------------------------- /.github/workflows/windows.yml: -------------------------------------------------------------------------------- 1 | name: Windows 2 | on: 3 | # push代码时触发workflow 4 | push: 5 | # 忽略README.md 6 | paths-ignore: 7 | - 'README.md' 8 | - 'LICENSE' 9 | # pull_request时触发workflow 10 | pull_request: 11 | # 忽略README.md 12 | paths-ignore: 13 | - 'README.md' 14 | - 'LICENSE' 15 | jobs: 16 | build: 17 | name: Build 18 | # 运行平台, windows-latest目前是windows server 2019 19 | runs-on: windows-latest 20 | strategy: 21 | # 矩阵配置 22 | matrix: 23 | qt_ver: [5.12.6] 24 | qt_target: [desktop] 25 | # mingw用不了 26 | # qt_arch: [win64_msvc2017_64, win32_msvc2017, win32_mingw53,win32_mingw73] 27 | qt_arch: [win64_msvc2017_64, win32_msvc2017] 28 | # 额外设置msvc_arch 29 | include: 30 | - qt_arch: win64_msvc2017_64 31 | msvc_arch: x64 32 | qt_arch_install: msvc2017_64 33 | - qt_arch: win32_msvc2017 34 | msvc_arch: x86 35 | qt_arch_install: msvc2017 36 | env: 37 | targetName: HelloActions-Qt.exe 38 | # 步骤 39 | steps: 40 | - name: cacheQt 41 | id: WindowsCacheQt 42 | uses: actions/cache@v1 43 | with: 44 | path: ../Qt/${{matrix.qt_ver}}/${{matrix.qt_arch_install}} 45 | key: ${{ runner.os }}-Qt/${{matrix.qt_ver}}/${{matrix.qt_arch}} 46 | - name: setupQt 47 | if: steps.WindowsCacheQt.outputs.cache-hit == 'true' 48 | shell: pwsh 49 | env: 50 | QtPath: ../Qt/${{matrix.qt_ver}}/${{matrix.qt_arch_install}} 51 | run: | 52 | $qt_Path=${env:QtPath} 53 | echo "::set-env name=Qt5_Dir::$qt_Path" 54 | echo "::add-path::$qt_Path/bin" 55 | # 安装Qt 56 | - name: Install Qt 57 | if: steps.WindowsCacheQt.outputs.cache-hit != 'true' 58 | # 使用外部action。这个action专门用来安装Qt 59 | uses: jurplel/install-qt-action@v2.0.0 60 | with: 61 | # Version of Qt to install 62 | version: ${{ matrix.qt_ver }} 63 | # Target platform for build 64 | target: ${{ matrix.qt_target }} 65 | # Architecture for Windows/Android 66 | arch: ${{ matrix.qt_arch }} 67 | # 拉取代码 68 | - uses: actions/checkout@v1 69 | with: 70 | fetch-depth: 1 71 | # 编译msvc 72 | - name: build-msvc 73 | shell: cmd 74 | env: 75 | vc_arch: ${{ matrix.msvc_arch }} 76 | run: | 77 | call "C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" %vc_arch% 78 | cmake . 79 | ninja 80 | # tag 打包 81 | - name: package 82 | if: startsWith(github.event.ref, 'refs/tags/') 83 | env: 84 | VCINSTALLDIR: 'C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\VC' 85 | archiveName: ${{ matrix.qt_ver }}-${{ matrix.qt_target }}-${{ matrix.qt_arch }} 86 | shell: pwsh 87 | run: | 88 | # 创建文件夹 89 | New-Item -ItemType Directory ${env:archiveName} 90 | # 拷贝exe 91 | Copy-Item bin\${env:targetName} ${env:archiveName}\ 92 | # 拷贝依赖 93 | windeployqt --qmldir . ${env:archiveName}\${env:targetName} 94 | # 打包zip 95 | Compress-Archive -Path ${env:archiveName} ${env:archiveName}'.zip' 96 | # 记录环境变量packageName给后续step 97 | $name = ${env:archiveName} 98 | echo "::set-env name=packageName::$name" 99 | # 打印环境变量packageName 100 | Write-Host 'packageName:'${env:packageName} 101 | # tag 查询github-Release 102 | - name: queryReleaseWin 103 | id: queryReleaseWin 104 | if: startsWith(github.event.ref, 'refs/tags/') 105 | shell: pwsh 106 | env: 107 | githubFullName: ${{ github.event.repository.full_name }} 108 | ref: ${{ github.event.ref }} 109 | run: | 110 | [string]$tag = ${env:ref}.Substring(${env:ref}.LastIndexOf('/') + 1) 111 | [string]$url = 'https://api.github.com/repos/' + ${env:githubFullName} + '/releases/tags/' + ${tag} 112 | $response={} 113 | try { 114 | $response = Invoke-RestMethod -Uri $url -Method Get 115 | } catch { 116 | Write-Host "StatusCode:" $_.Exception.Response.StatusCode.value__ 117 | Write-Host "StatusDescription:" $_.Exception.Response.StatusDescription 118 | # 没查到,输出 119 | echo "::set-output name=needCreateRelease::true" 120 | return 121 | } 122 | [string]$latestUpUrl = $response.upload_url 123 | Write-Host 'latestUpUrl:'$latestUpUrl 124 | if ($latestUpUrl.Length -eq 0) { 125 | # 没查到,输出 126 | echo "::set-output name=needCreateRelease::true" 127 | } 128 | # tag 创建github-Release 129 | - name: createReleaseWin 130 | id: createReleaseWin 131 | if: startsWith(github.event.ref, 'refs/tags/') && steps.queryReleaseWin.outputs.needCreateRelease == 'true' 132 | env: 133 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 134 | uses: actions/create-release@v1.0.0 135 | with: 136 | tag_name: ${{ github.ref }} 137 | release_name: Release ${{ github.ref }} 138 | body: ${{ github.event.head_commit.message }} 139 | draft: false 140 | prerelease: false 141 | # 重定向upload_url到环境变量uploadUrl。 142 | - name: getLatestTagRelease 143 | # tag 上一步无论成功还是失败都执行 144 | if: startsWith(github.event.ref, 'refs/tags/') 145 | shell: pwsh 146 | env: 147 | githubFullName: ${{ github.event.repository.full_name }} 148 | upUrl: ${{ steps.createReleaseWin.outputs.upload_url }} 149 | ref: ${{ github.event.ref }} 150 | run: | 151 | # upUrl不为空,导出就完事 152 | if (${env:upUrl}.Length -gt 0) { 153 | $v=${env:upUrl} 154 | echo "::set-env name=uploadUrl::$v" 155 | return 156 | } 157 | [string]$tag = ${env:ref}.Substring(${env:ref}.LastIndexOf('/') + 1) 158 | [string]$url = 'https://api.github.com/repos/' + ${env:githubFullName} + '/releases/tags/' + ${tag} 159 | $response = Invoke-RestMethod -Uri $url -Method Get 160 | [string]$latestUpUrl = $response.upload_url 161 | Write-Host 'latestUpUrl:'$latestUpUrl 162 | echo "::set-env name=uploadUrl::$latestUpUrl" 163 | Write-Host 'env uploadUrl:'${env:uploadUrl} 164 | # tag 上传Release 165 | - name: uploadRelease 166 | id: uploadRelease 167 | if: startsWith(github.event.ref, 'refs/tags/') 168 | env: 169 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 170 | uses: actions/upload-release-asset@v1.0.1 171 | with: 172 | upload_url: ${{ env.uploadUrl }} 173 | asset_path: ./${{ env.packageName }}.zip 174 | asset_name: ${{ env.packageName }}.zip 175 | asset_content_type: application/zip -------------------------------------------------------------------------------- /Worker.cpp: -------------------------------------------------------------------------------- 1 | #include "Worker.h" 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | //枚举转数字 8 | template 9 | static inline constexpr NumberType e2n(EnumType e) 10 | { 11 | return static_cast(e); 12 | } 13 | //数字转枚举 14 | template 15 | static inline constexpr EnumType n2e(NumberType n) 16 | { 17 | return static_cast(n); 18 | } 19 | //枚举转int 20 | template 21 | static inline constexpr int e2i(EnumType e) 22 | { 23 | return e2n(e); 24 | } 25 | //int转枚举 26 | template 27 | static inline constexpr EnumType i2e(int i) 28 | { 29 | return n2e(i); 30 | } 31 | static const QString inttegerType = "char|short|int|long|uchar|ushort|uint|ulong|int8_t|int16_t|int32_t|uint8_t|uin16_t|uint32_t"; 32 | static const QString supportTypes = QString("void|bool|%1|float|double|qreal|QString").arg(inttegerType); 33 | static const QString nameFeature = QString("[a-zA-Z_]+[0-9a-zA-Z_]*"); 34 | static QString type2js(const QString &type){ 35 | if (type == "bool") { 36 | return "boolean"; 37 | } else if (type == "QString") { 38 | return "string"; 39 | } else if (inttegerType.contains(type)) { 40 | return "number"; 41 | } else if (type == "float" || type == "double" || type == "qreal ") { 42 | return "number"; 43 | } 44 | return "string"; 45 | } 46 | namespace Reg { 47 | enum class RegIndex : uint32_t { 48 | classNameIndex = 0, 49 | propertyIndex, 50 | privateSectionIndex, 51 | publicSectionIndex, 52 | protectedSectionIndex, 53 | signalsSectionIndex, 54 | slotsSectionIndex, 55 | functionIndex, 56 | 57 | IndexCount, 58 | }; 59 | 60 | static const QRegularExpression regs[] = { 61 | QRegularExpression(QString(R"(\bclass\b \b(%1)\b)").arg(nameFeature)), 62 | QRegularExpression(R"(\bQ_PROPERTY\()"), 63 | QRegularExpression(R"(\bprivate\b:)"), 64 | QRegularExpression(R"(\bpublic\b:)"), 65 | QRegularExpression(R"(\bprotected\b:)"), 66 | QRegularExpression(R"(\b(signals|Q_SIGNALS)\b:)"), 67 | QRegularExpression(R"(\b(public slots|Q_SLOTS)\b:)"), 68 | QRegularExpression(QString(R"(\b(Q_INVOKABLE)?\b\b(const)?\s?&?&?\s?(%1)\s?&?&?\b(%2)\s?(const)?(\([^\)]*\)))").arg(supportTypes).arg(nameFeature)), 69 | }; 70 | static const QRegularExpression typeNameReg(QString(R"(\b(%1) (%2)\b)").arg(supportTypes).arg(nameFeature)); 71 | static const QRegularExpression typeNameRefReg(QString(R"(\b(const)?\s?&?&?\s?(%1)\s?&?&?(%2)\b)").arg(supportTypes).arg(nameFeature)); 72 | static const QRegularExpression readPropertyReg(QString(R"(\bREAD (%1)\b)").arg(nameFeature)); 73 | static const QRegularExpression writePropertyReg(QString(R"(\bWRITE (%1)\b)").arg(nameFeature)); 74 | static const QRegularExpression signalPropertyReg(QString(R"(\bNOTIFY (%1)\b)").arg(nameFeature)); 75 | static const QRegularExpression readonlyPropertyReg(QString(R"(\bCONSTANT\b)")); 76 | } // namespace Reg 77 | namespace Parser { 78 | enum class SectionType : uint8_t { 79 | s_private = 0, 80 | s_public, 81 | s_protected, 82 | s_signals, 83 | s_publicSlots, 84 | }; 85 | struct Context { 86 | SectionType sec = SectionType::s_private; 87 | }; 88 | static Context ctx; 89 | } // namespace Parser 90 | 91 | void Worker::work(const QString &inputFile, const QString &outputFile) 92 | { 93 | QFile file(inputFile); 94 | if (!file.open(QFile::ReadOnly)) { 95 | qWarning() << inputFile << file.errorString(); 96 | return; 97 | } 98 | QTextStream ts(&file); 99 | while (!ts.atEnd()) { 100 | parseLine(ts.readLine()); 101 | } 102 | file.close(); 103 | writeTs(outputFile); 104 | } 105 | 106 | void Worker::parseLine(const QString &line) 107 | { 108 | for (uint32_t i = 0; i < e2n(Reg::RegIndex::IndexCount); i++) { 109 | auto match = Reg::regs[i].match(line); 110 | if (match.hasMatch()) { 111 | switch (n2e(i)) { 112 | case Reg::RegIndex::classNameIndex: 113 | m_obj.name = match.captured(1); 114 | qWarning() << "class " << m_obj.name; 115 | break; 116 | case Reg::RegIndex::propertyIndex: 117 | parseProperty(line); 118 | break; 119 | case Reg::RegIndex::privateSectionIndex: 120 | Parser::ctx.sec = Parser::SectionType::s_private; 121 | break; 122 | case Reg::RegIndex::publicSectionIndex: 123 | Parser::ctx.sec = Parser::SectionType::s_public; 124 | break; 125 | case Reg::RegIndex::protectedSectionIndex: 126 | Parser::ctx.sec = Parser::SectionType::s_protected; 127 | break; 128 | case Reg::RegIndex::signalsSectionIndex: 129 | Parser::ctx.sec = Parser::SectionType::s_signals; 130 | break; 131 | case Reg::RegIndex::slotsSectionIndex: 132 | Parser::ctx.sec = Parser::SectionType::s_publicSlots; 133 | break; 134 | case Reg::RegIndex::functionIndex: 135 | parseFunction(!match.captured(1).isEmpty(), match.captured(3), match.captured(4), match.captured(6)); 136 | break; 137 | default: 138 | break; 139 | } 140 | } 141 | } 142 | } 143 | 144 | void Worker::parseProperty(const QString &line) 145 | { 146 | static const QString propFeature = "Q_PROPERTY("; 147 | auto sline = line.simplified(); 148 | auto start = sline.indexOf(propFeature) + propFeature.length(); 149 | sline = sline.mid(start, sline.length() - 2); 150 | auto propMatch = Reg::typeNameReg.match(sline); 151 | if (!propMatch.hasMatch()) { 152 | return; 153 | } 154 | Meta::Property prop; 155 | prop.type = propMatch.captured(1); 156 | prop.name = propMatch.captured(2); 157 | auto readmatch = Reg::readPropertyReg.match(sline); 158 | if (readmatch.hasMatch()) { 159 | prop.get = readmatch.captured(1); 160 | } 161 | auto writeMatch = Reg::writePropertyReg.match(sline); 162 | if (writeMatch.hasMatch()) { 163 | prop.set = writeMatch.captured(1); 164 | } 165 | if (Reg::readonlyPropertyReg.match(sline).hasMatch()) { 166 | prop.readonly = true; 167 | if (!prop.set.isEmpty()) { 168 | prop.set.clear(); 169 | } 170 | } 171 | auto notifyMatch = Reg::signalPropertyReg.match(sline); 172 | if (notifyMatch.hasMatch()) { 173 | prop.notify = notifyMatch.captured(1); 174 | } 175 | qWarning() << "prop:" << prop.type << prop.name << prop.get << prop.set << prop.notify << prop.readonly; 176 | m_obj.properties.append(prop); 177 | } 178 | 179 | void Worker::parseFunction(bool isInvok, const QString &type, const QString &name, const QString &args) 180 | { 181 | qWarning() << "function:" << isInvok << type << name << args; 182 | for (auto prop : m_obj.properties) { 183 | if (prop.get == name || prop.set == name ||prop.notify == name) { 184 | return; 185 | } 186 | } 187 | if (Parser::ctx.sec == Parser::SectionType::s_publicSlots || (Parser::ctx.sec == Parser::SectionType::s_public && isInvok)) { 188 | Meta::Method method; 189 | method.returnType = type; 190 | method.name = name; 191 | parseArgs(method.args, args.mid(1, args.length() - 2)); 192 | m_obj.methods.push_back(method); 193 | } else if (Parser::ctx.sec == Parser::SectionType::s_signals) { 194 | Meta::Method method; 195 | method.returnType = type; 196 | method.name = name; 197 | method.isNotifyMethod = true; 198 | parseArgs(method.args, args.mid(1, args.length() - 2)); 199 | m_obj.methods.push_back(method); 200 | } 201 | } 202 | 203 | void Worker::parseArgs(QList &args, const QString &argsStr) 204 | { 205 | qWarning() << argsStr; 206 | auto list = argsStr.split(','); 207 | for (auto i : list) { 208 | auto match = Reg::typeNameRefReg.match(i); 209 | if (match.hasMatch()) { 210 | Meta::Arg arg; 211 | arg.type = match.captured(2); 212 | arg.name = match.captured(3); 213 | qWarning() << " arg" << arg.type << arg.name; 214 | args.push_back(arg); 215 | } 216 | } 217 | } 218 | 219 | void Worker::writeTs(const QString &outputFile) { 220 | const static QString newLine = "\n"; 221 | QFile file(outputFile); 222 | if (!file.open(QFile::WriteOnly)) { 223 | qWarning() << file.errorString(); 224 | return; 225 | } 226 | QTextStream os(&file); 227 | os << "class " << m_obj.name << "{"<< newLine; 228 | for (auto p : m_obj.properties) { 229 | os << QString(" %1private _%2: %3;").arg(p.readonly ? " readonly " : " ").arg(p.name).arg(type2js(p.type)) << newLine; 230 | } 231 | for (auto p : m_obj.properties) { 232 | if (!p.get.isEmpty()) { 233 | os << QString(" get %1() { return this._%1;}").arg(p.name) << newLine; 234 | } 235 | if (!p.set.isEmpty()) { 236 | os << QString (" set %1(value: %2) { this._%1 = value;}").arg(p.name).arg(type2js(p.type)) << newLine; 237 | } 238 | } 239 | for (auto m: m_obj.methods) { 240 | QString args; 241 | for (auto arg : m.args) { 242 | if (!args.isEmpty()) { 243 | args.append(", "); 244 | } 245 | args.append(QString("%1: %2").arg(arg.name).arg(type2js(arg.type))); 246 | } 247 | os << QString(" public %1 (%2):%3 {}").arg(m.name).arg(args).arg(m.returnType) << newLine; 248 | } 249 | 250 | os << "}" << newLine; 251 | file.close(); 252 | } 253 | --------------------------------------------------------------------------------