Compare commits
33 Commits
v1.3.3
...
0012a5dc19
| Author | SHA1 | Date | |
|---|---|---|---|
| 0012a5dc19 | |||
| 3cda88371e | |||
| 0338351680 | |||
| e372a0dd7c | |||
| d597f379ff | |||
| 9222a52d91 | |||
| c3670bb8cd | |||
| 2ea3456ff7 | |||
| c9379f0edb | |||
| f72010bd69 | |||
| cd027097f8 | |||
| 9cbbf729c0 | |||
|
|
c26c11e253 | ||
| 338ac358db | |||
| a83c7139c9 | |||
| 42c7d11c09 | |||
| 5ca5aa64c7 | |||
| eda7ef771e | |||
| 593c4d7783 | |||
| d24a522b32 | |||
| 41afb834ae | |||
| b745329e26 | |||
| 1fb4f64cb3 | |||
| 1f8e8981ce | |||
| a257d30dba | |||
| 97ee3b0667 | |||
| 8e2bafba5f | |||
| 6149bc133d | |||
| 5f22ee3b1f | |||
| fa72ff8061 | |||
| 65f24860e6 | |||
|
|
4881233211 | ||
| bc01fdf362 |
14
README.md
14
README.md
@@ -1,10 +1,10 @@
|
||||
# <img src="./frontend/public/appicon.png" alt="VoidRaft Logo" width="32" height="32" style="vertical-align: middle;"> VoidRaft
|
||||
# <img src="./frontend/public/appicon.png" alt="voidraft Logo" width="32" height="32" style="vertical-align: middle;"> voidraft
|
||||
|
||||
[中文](README_ZH.md) | **English**
|
||||
|
||||
> *An elegant text snippet recording tool designed for developers.*
|
||||
|
||||
VoidRaft is a modern developer-focused text editor that allows you to record, organize, and manage various text snippets anytime, anywhere. Whether it's temporary code snippets, API responses, meeting notes, or daily to-do lists, VoidRaft provides a smooth and elegant editing experience.
|
||||
voidraft is a modern developer-focused text editor that allows you to record, organize, and manage various text snippets anytime, anywhere. Whether it's temporary code snippets, API responses, meeting notes, or daily to-do lists, voidraft provides a smooth and elegant editing experience.
|
||||
|
||||
## Core Features
|
||||
|
||||
@@ -87,7 +87,7 @@ After building, the executable will be generated in the `bin` directory.
|
||||
## Project Structure
|
||||
|
||||
```
|
||||
Voidraft/
|
||||
voidraft/
|
||||
├── frontend/ # Vue 3 frontend application
|
||||
│ ├── src/
|
||||
│ │ ├── views/editor/ # Editor core views
|
||||
@@ -129,11 +129,11 @@ Voidraft/
|
||||
|
||||
> Standing on the shoulders of giants, paying tribute to the open source spirit
|
||||
|
||||
The birth of VoidRaft is inseparable from the following excellent open source projects:
|
||||
The birth of voidraft is inseparable from the following excellent open source projects:
|
||||
|
||||
### Special Thanks
|
||||
|
||||
- **[Heynote](https://github.com/heyman/heynote/)** - VoidRaft is a feature-enhanced version based on Heynote's concept
|
||||
- **[Heynote](https://github.com/heyman/heynote/)** - voidraft is a feature-enhanced version based on Heynote's concept
|
||||
- Inherits Heynote's elegant block editing philosophy
|
||||
- Adds more practical features on the original foundation
|
||||
- Rebuilt with modern technology stack
|
||||
@@ -157,7 +157,7 @@ This project is open source under the [MIT License](LICENSE).
|
||||
Welcome to Fork, Star, and contribute code.
|
||||
|
||||
[](https://opensource.org/licenses/MIT)
|
||||
[](https://github.com/yourusername/Voidraft)
|
||||
[](https://github.com/yourusername/Voidraft)
|
||||
[](https://github.com/yourusername/voidraft)
|
||||
[](https://github.com/yourusername/voidraft)
|
||||
|
||||
*Made with ❤️ by landaiqing*
|
||||
14
README_ZH.md
14
README_ZH.md
@@ -1,10 +1,10 @@
|
||||
# <img src="./frontend/public/appicon.png" alt="Voidraft Logo" width="32" height="32" style="vertical-align: middle;"> Voidraft
|
||||
# <img src="./frontend/public/appicon.png" alt="voidraft Logo" width="32" height="32" style="vertical-align: middle;"> voidraft
|
||||
|
||||
**中文** | [English](README.md)
|
||||
|
||||
> *一个专为开发者打造的优雅文本片段记录工具。*
|
||||
|
||||
Voidraft 是一个现代化的开发者专用文本编辑器,让你能够随时随地记录、整理和管理各种文本片段。无论是临时的代码片段、API 响应、会议笔记,还是日常的待办事项,Voidraft 都能为你提供流畅而优雅的编辑体验。
|
||||
voidraft 是一个现代化的开发者专用文本编辑器,让你能够随时随地记录、整理和管理各种文本片段。无论是临时的代码片段、API 响应、会议笔记,还是日常的待办事项,voidraft 都能为你提供流畅而优雅的编辑体验。
|
||||
|
||||
## 核心特性
|
||||
|
||||
@@ -88,7 +88,7 @@ wails3 package
|
||||
## 项目结构
|
||||
|
||||
```
|
||||
Voidraft/
|
||||
voidraft/
|
||||
├── frontend/ # Vue 3 前端应用
|
||||
│ ├── src/
|
||||
│ │ ├── views/editor/ # 编辑器核心视图
|
||||
@@ -131,11 +131,11 @@ Voidraft/
|
||||
|
||||
> 站在巨人的肩膀上,致敬开源精神
|
||||
|
||||
Voidraft 的诞生离不开以下优秀的开源项目:
|
||||
voidraft 的诞生离不开以下优秀的开源项目:
|
||||
|
||||
### 特别感谢
|
||||
|
||||
- **[Heynote](https://github.com/heyman/heynote/)** - Voidraft 是基于 Heynote 概念的功能增强版本
|
||||
- **[Heynote](https://github.com/heyman/heynote/)** - voidraft 是基于 Heynote 概念的功能增强版本
|
||||
- 继承了 Heynote 优雅的块状编辑理念
|
||||
- 在原有基础上增加了更多实用功能
|
||||
- 采用现代化技术栈重新构建
|
||||
@@ -159,7 +159,7 @@ Voidraft 的诞生离不开以下优秀的开源项目:
|
||||
欢迎 Fork、Star 和贡献代码。
|
||||
|
||||
[](https://opensource.org/licenses/MIT)
|
||||
[](https://github.com/yourusername/Voidraft)
|
||||
[](https://github.com/yourusername/Voidraft)
|
||||
[](https://github.com/yourusername/voidraft)
|
||||
[](https://github.com/yourusername/voidraft)
|
||||
|
||||
*Made with ❤️ by landaiqing*
|
||||
|
||||
12
Taskfile.yml
12
Taskfile.yml
@@ -12,13 +12,25 @@ vars:
|
||||
VITE_PORT: '{{.WAILS_VITE_PORT | default 9245}}'
|
||||
|
||||
tasks:
|
||||
version:
|
||||
summary: Generate version information
|
||||
cmds:
|
||||
- '{{if eq OS "windows"}}cmd /c ".\scripts\version.bat"{{else}}bash ./scripts/version.sh{{end}}'
|
||||
sources:
|
||||
- scripts/version.bat
|
||||
- scripts/version.sh
|
||||
generates:
|
||||
- version.txt
|
||||
|
||||
build:
|
||||
summary: Builds the application
|
||||
deps: [version]
|
||||
cmds:
|
||||
- task: "{{OS}}:build"
|
||||
|
||||
package:
|
||||
summary: Packages a production build of the application
|
||||
deps: [version]
|
||||
cmds:
|
||||
- task: "{{OS}}:package"
|
||||
|
||||
|
||||
@@ -5,12 +5,12 @@ version: '3'
|
||||
|
||||
# This information is used to generate the build assets.
|
||||
info:
|
||||
companyName: "Voidraft" # The name of the company
|
||||
productName: "Voidraft" # The name of the application
|
||||
companyName: "voidraft" # The name of the company
|
||||
productName: "voidraft" # The name of the application
|
||||
productIdentifier: "landaiqing" # The unique product identifier
|
||||
description: "Voidraft" # The application description
|
||||
copyright: "© 2025 Voidraft. All rights reserved." # Copyright text
|
||||
comments: "Voidraft" # Comments
|
||||
description: "voidraft" # The application description
|
||||
copyright: "© 2025 voidraft. All rights reserved." # Copyright text
|
||||
comments: "voidraft" # Comments
|
||||
version: "0.0.1.0" # The application version
|
||||
|
||||
# Dev mode configuration
|
||||
|
||||
@@ -4,15 +4,15 @@
|
||||
<key>CFBundlePackageType</key>
|
||||
<string>APPL</string>
|
||||
<key>CFBundleName</key>
|
||||
<string>Voidraft</string>
|
||||
<string>voidraft</string>
|
||||
<key>CFBundleExecutable</key>
|
||||
<string>Voidraft</string>
|
||||
<string>voidraft</string>
|
||||
<key>CFBundleIdentifier</key>
|
||||
<string>landaiqing</string>
|
||||
<key>CFBundleVersion</key>
|
||||
<string>0.0.1.0</string>
|
||||
<key>CFBundleGetInfoString</key>
|
||||
<string>Voidraft</string>
|
||||
<string>voidraft</string>
|
||||
<key>CFBundleShortVersionString</key>
|
||||
<string>0.0.1.0</string>
|
||||
<key>CFBundleIconFile</key>
|
||||
@@ -22,7 +22,7 @@
|
||||
<key>NSHighResolutionCapable</key>
|
||||
<string>true</string>
|
||||
<key>NSHumanReadableCopyright</key>
|
||||
<string>© 2025 Voidraft. All rights reserved.</string>
|
||||
<string>© 2025 voidraft. All rights reserved.</string>
|
||||
<key>NSAppTransportSecurity</key>
|
||||
<dict>
|
||||
<key>NSAllowsLocalNetworking</key>
|
||||
|
||||
@@ -4,15 +4,15 @@
|
||||
<key>CFBundlePackageType</key>
|
||||
<string>APPL</string>
|
||||
<key>CFBundleName</key>
|
||||
<string>Voidraft</string>
|
||||
<string>voidraft</string>
|
||||
<key>CFBundleExecutable</key>
|
||||
<string>Voidraft</string>
|
||||
<string>voidraft</string>
|
||||
<key>CFBundleIdentifier</key>
|
||||
<string>landaiqing</string>
|
||||
<key>CFBundleVersion</key>
|
||||
<string>0.0.1.0</string>
|
||||
<key>CFBundleGetInfoString</key>
|
||||
<string>Voidraft</string>
|
||||
<string>voidraft</string>
|
||||
<key>CFBundleShortVersionString</key>
|
||||
<string>0.0.1.0</string>
|
||||
<key>CFBundleIconFile</key>
|
||||
@@ -22,6 +22,6 @@
|
||||
<key>NSHighResolutionCapable</key>
|
||||
<string>true</string>
|
||||
<key>NSHumanReadableCopyright</key>
|
||||
<string>© 2025 Voidraft. All rights reserved.</string>
|
||||
<string>© 2025 voidraft. All rights reserved.</string>
|
||||
</dict>
|
||||
</plist>
|
||||
@@ -11,9 +11,12 @@ tasks:
|
||||
- task: common:build:frontend
|
||||
- task: common:generate:icons
|
||||
cmds:
|
||||
- go build {{.BUILD_FLAGS}} -o {{.OUTPUT}}
|
||||
- go build {{.BUILD_FLAGS}} -ldflags="{{.LDFLAGS}} {{.VERSION_FLAGS}}" -o {{.OUTPUT}}
|
||||
vars:
|
||||
BUILD_FLAGS: '{{if eq .PRODUCTION "true"}}-tags production -trimpath -buildvcs=false -ldflags="-w -s"{{else}}-buildvcs=false -gcflags=all="-l"{{end}}'
|
||||
BUILD_FLAGS: '{{if eq .PRODUCTION "true"}}-tags production -trimpath -buildvcs=false{{else}}-buildvcs=false -gcflags=all="-l"{{end}}'
|
||||
LDFLAGS: '{{if eq .PRODUCTION "true"}}-w -s{{else}}{{end}}'
|
||||
VERSION_FLAGS:
|
||||
sh: 'grep "VERSION=" version.txt | cut -d"=" -f2 | xargs -I {} echo "-X voidraft/internal/version.Version={}"'
|
||||
DEFAULT_OUTPUT: '{{.BIN_DIR}}/{{.APP_NAME}}'
|
||||
OUTPUT: '{{ .OUTPUT | default .DEFAULT_OUTPUT }}'
|
||||
env:
|
||||
|
||||
@@ -11,9 +11,12 @@ tasks:
|
||||
- task: common:build:frontend
|
||||
- task: common:generate:icons
|
||||
cmds:
|
||||
- go build {{.BUILD_FLAGS}} -o {{.BIN_DIR}}/{{.APP_NAME}}
|
||||
- go build {{.BUILD_FLAGS}} -ldflags="{{.LDFLAGS}} {{.VERSION_FLAGS}}" -o {{.BIN_DIR}}/{{.APP_NAME}}
|
||||
vars:
|
||||
BUILD_FLAGS: '{{if eq .PRODUCTION "true"}}-tags production -trimpath -buildvcs=false -ldflags="-w -s"{{else}}-buildvcs=false -gcflags=all="-l"{{end}}'
|
||||
BUILD_FLAGS: '{{if eq .PRODUCTION "true"}}-tags production -trimpath -buildvcs=false{{else}}-buildvcs=false -gcflags=all="-l"{{end}}'
|
||||
LDFLAGS: '{{if eq .PRODUCTION "true"}}-w -s{{else}}{{end}}'
|
||||
VERSION_FLAGS:
|
||||
sh: 'grep "VERSION=" version.txt | cut -d"=" -f2 | xargs -I {} echo "-X voidraft/internal/version.Version={}"'
|
||||
env:
|
||||
GOOS: linux
|
||||
CGO_ENABLED: 1
|
||||
|
||||
@@ -3,26 +3,26 @@
|
||||
#
|
||||
# The lines below are called `modelines`. See `:help modeline`
|
||||
|
||||
name: "Voidraft"
|
||||
name: "voidraft"
|
||||
arch: ${GOARCH}
|
||||
platform: "linux"
|
||||
version: "0.0.1.0"
|
||||
section: "default"
|
||||
priority: "extra"
|
||||
maintainer: ${GIT_COMMITTER_NAME} <${GIT_COMMITTER_EMAIL}>
|
||||
description: "Voidraft"
|
||||
vendor: "Voidraft"
|
||||
homepage: "https://wails.io"
|
||||
description: "voidraft"
|
||||
vendor: "voidraft"
|
||||
homepage: "https://voidraft.landaiqing.cn"
|
||||
license: "MIT"
|
||||
release: "1"
|
||||
|
||||
contents:
|
||||
- src: "./bin/Voidraft"
|
||||
dst: "/usr/local/bin/Voidraft"
|
||||
- src: "./bin/voidraft"
|
||||
dst: "/usr/local/bin/voidraft"
|
||||
- src: "./build/appicon.png"
|
||||
dst: "/usr/share/icons/hicolor/128x128/apps/Voidraft.png"
|
||||
- src: "./build/linux/Voidraft.desktop"
|
||||
dst: "/usr/share/applications/Voidraft.desktop"
|
||||
dst: "/usr/share/icons/hicolor/128x128/apps/voidraft.png"
|
||||
- src: "./build/linux/voidraft.desktop"
|
||||
dst: "/usr/share/applications/voidraft.desktop"
|
||||
|
||||
depends:
|
||||
- gtk3
|
||||
|
||||
@@ -14,13 +14,16 @@ tasks:
|
||||
- task: common:generate:icons
|
||||
cmds:
|
||||
- task: generate:syso
|
||||
- go build {{.BUILD_FLAGS}} -o {{.BIN_DIR}}/{{.APP_NAME}}.exe
|
||||
- go build {{.BUILD_FLAGS}} -ldflags="{{.LDFLAGS}} {{.VERSION_FLAGS}}" -o {{.BIN_DIR}}/{{.APP_NAME}}.exe
|
||||
- cmd: powershell Remove-item *.syso
|
||||
platforms: [windows]
|
||||
- cmd: rm -f *.syso
|
||||
platforms: [linux, darwin]
|
||||
vars:
|
||||
BUILD_FLAGS: '{{if eq .PRODUCTION "true"}}-tags production -trimpath -buildvcs=false -ldflags="-w -s -H windowsgui"{{else}}-buildvcs=false -gcflags=all="-l"{{end}}'
|
||||
BUILD_FLAGS: '{{if eq .PRODUCTION "true"}}-tags production -trimpath -buildvcs=false{{else}}-buildvcs=false -gcflags=all="-l"{{end}}'
|
||||
LDFLAGS: '{{if eq .PRODUCTION "true"}}-w -s -H windowsgui{{else}}{{end}}'
|
||||
VERSION_FLAGS:
|
||||
sh: 'powershell -Command "(Get-Content version.txt) -replace ''VERSION='', ''-X voidraft/internal/version.Version=''"'
|
||||
env:
|
||||
GOOS: windows
|
||||
CGO_ENABLED: 1
|
||||
|
||||
@@ -5,11 +5,11 @@
|
||||
"info": {
|
||||
"0000": {
|
||||
"ProductVersion": "0.0.1.0",
|
||||
"CompanyName": "Voidraft",
|
||||
"FileDescription": "Voidraft",
|
||||
"LegalCopyright": "© 2025 Voidraft. All rights reserved.",
|
||||
"ProductName": "Voidraft",
|
||||
"Comments": "Voidraft"
|
||||
"CompanyName": "voidraft",
|
||||
"FileDescription": "voidraft",
|
||||
"LegalCopyright": "© 2025 voidraft. All rights reserved.",
|
||||
"ProductName": "voidraft",
|
||||
"Comments": "voidraft"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -5,19 +5,19 @@
|
||||
!include "FileFunc.nsh"
|
||||
|
||||
!ifndef INFO_PROJECTNAME
|
||||
!define INFO_PROJECTNAME "Voidraft"
|
||||
!define INFO_PROJECTNAME "voidraft"
|
||||
!endif
|
||||
!ifndef INFO_COMPANYNAME
|
||||
!define INFO_COMPANYNAME "Voidraft"
|
||||
!define INFO_COMPANYNAME "voidraft"
|
||||
!endif
|
||||
!ifndef INFO_PRODUCTNAME
|
||||
!define INFO_PRODUCTNAME "Voidraft"
|
||||
!define INFO_PRODUCTNAME "voidraft"
|
||||
!endif
|
||||
!ifndef INFO_PRODUCTVERSION
|
||||
!define INFO_PRODUCTVERSION "0.0.1.0"
|
||||
!endif
|
||||
!ifndef INFO_COPYRIGHT
|
||||
!define INFO_COPYRIGHT "© 2025 Voidraft. All rights reserved."
|
||||
!define INFO_COPYRIGHT "© 2025 voidraft. All rights reserved."
|
||||
!endif
|
||||
!ifndef PRODUCT_EXECUTABLE
|
||||
!define PRODUCT_EXECUTABLE "${INFO_PROJECTNAME}.exe"
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>VoidRaft - Changelog</title>
|
||||
<title>voidraft - Changelog</title>
|
||||
<link rel="stylesheet" href="css/styles.css">
|
||||
<link rel="stylesheet" href="css/changelog.css">
|
||||
<link rel="icon" href="img/favicon.ico">
|
||||
@@ -16,7 +16,7 @@
|
||||
<!-- 主卡片 -->
|
||||
<div class="card">
|
||||
<div class="card-header">
|
||||
<h1 class="card-title" data-en="VoidRaft Changelog" data-zh="VoidRaft 更新日志">VoidRaft Changelog</h1>
|
||||
<h1 class="card-title" data-en="voidraft Changelog" data-zh="voidraft 更新日志">voidraft Changelog</h1>
|
||||
<div class="card-controls">
|
||||
<button id="theme-toggle" class="btn btn-secondary" title="切换主题">
|
||||
<i class="fas fa-sun"></i> <span data-en="Theme" data-zh="主题">Theme</span>
|
||||
@@ -59,7 +59,7 @@
|
||||
|
||||
<!-- 页脚 -->
|
||||
<footer class="footer">
|
||||
<p class="footer-text" data-en="© 2025 VoidRaft - An elegant text snippet recording tool designed for developers" data-zh="© 2025 VoidRaft - 专为开发者打造的优雅文本片段记录工具">© 2023-2024 VoidRaft - An elegant text snippet recording tool designed for developers</p>
|
||||
<p class="footer-text" data-en="© 2025 voidraft - An elegant text snippet recording tool designed for developers" data-zh="© 2025 voidraft - 专为开发者打造的优雅文本片段记录工具">© 2023-2024 voidraft - An elegant text snippet recording tool designed for developers</p>
|
||||
<div class="footer-links">
|
||||
<a href="https://github.com/landaiqing/voidraft" target="_blank" class="footer-link">GitHub</a>
|
||||
<a href="https://github.com/landaiqing/voidraft/issues" target="_blank" class="footer-link" data-en="Issues" data-zh="问题反馈">Issues</a>
|
||||
|
||||
@@ -3,10 +3,10 @@
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>VoidRaft - An elegant text snippet recording tool designed for developers.</title>
|
||||
<meta name="description" content="VoidRaft is an elegant text snippet recording tool designed for developers. Features multi-language code blocks, syntax highlighting, code formatting, custom themes, and more.">
|
||||
<meta name="keywords" content="text editor, code snippets, developer tools, syntax highlighting, code formatting, multi-language, VoidRaft">
|
||||
<meta name="author" content="VoidRaft Team">
|
||||
<title>voidraft - An elegant text snippet recording tool designed for developers.</title>
|
||||
<meta name="description" content="voidraft is an elegant text snippet recording tool designed for developers. Features multi-language code blocks, syntax highlighting, code formatting, custom themes, and more.">
|
||||
<meta name="keywords" content="text editor, code snippets, developer tools, syntax highlighting, code formatting, multi-language, voidraft">
|
||||
<meta name="author" content="voidraft Team">
|
||||
<meta name="robots" content="index, follow">
|
||||
<link rel="canonical" href="https://landaiqing.github.io/voidraft/">
|
||||
|
||||
@@ -18,16 +18,16 @@
|
||||
<!-- Open Graph / Facebook -->
|
||||
<meta property="og:type" content="website">
|
||||
<meta property="og:url" content="https://landaiqing.github.io/voidraft/">
|
||||
<meta property="og:title" content="VoidRaft - An elegant text snippet recording tool designed for developers">
|
||||
<meta property="og:description" content="VoidRaft is an elegant text snippet recording tool designed for developers. Features multi-language code blocks, syntax highlighting, code formatting, custom themes, and more.">
|
||||
<meta property="og:title" content="voidraft - An elegant text snippet recording tool designed for developers">
|
||||
<meta property="og:description" content="voidraft is an elegant text snippet recording tool designed for developers. Features multi-language code blocks, syntax highlighting, code formatting, custom themes, and more.">
|
||||
<meta property="og:image" content="https://landaiqing.github.io/voidraft/img/screenshot-dark.png">
|
||||
<meta property="og:site_name" content="VoidRaft">
|
||||
<meta property="og:site_name" content="voidraft">
|
||||
|
||||
<!-- Twitter -->
|
||||
<meta property="twitter:card" content="summary_large_image">
|
||||
<meta property="twitter:url" content="https://landaiqing.github.io/voidraft/">
|
||||
<meta property="twitter:title" content="VoidRaft - An elegant text snippet recording tool designed for developers">
|
||||
<meta property="twitter:description" content="VoidRaft is an elegant text snippet recording tool designed for developers. Features multi-language code blocks, syntax highlighting, code formatting, custom themes, and more.">
|
||||
<meta property="twitter:title" content="voidraft - An elegant text snippet recording tool designed for developers">
|
||||
<meta property="twitter:description" content="voidraft is an elegant text snippet recording tool designed for developers. Features multi-language code blocks, syntax highlighting, code formatting, custom themes, and more.">
|
||||
<meta property="twitter:image" content="https://landaiqing.github.io/voidraft/img/screenshot-dark.png">
|
||||
|
||||
<link rel="stylesheet" href="./css/styles.css">
|
||||
@@ -39,13 +39,13 @@
|
||||
{
|
||||
"@context": "https://schema.org",
|
||||
"@type": "SoftwareApplication",
|
||||
"name": "VoidRaft",
|
||||
"name": "voidraft",
|
||||
"description": "An elegant text snippet recording tool designed for developers. Features multi-language code blocks, syntax highlighting, code formatting, custom themes, and more.",
|
||||
"url": "https://landaiqing.github.io/voidraft/",
|
||||
"downloadUrl": "https://github.com/landaiqing/voidraft/releases",
|
||||
"author": {
|
||||
"@type": "Organization",
|
||||
"name": "VoidRaft"
|
||||
"name": "voidraft"
|
||||
},
|
||||
"operatingSystem": ["Windows", "macOS", "Linux"],
|
||||
"applicationCategory": "DeveloperApplication",
|
||||
@@ -66,7 +66,7 @@
|
||||
<!-- 主卡片 -->
|
||||
<div class="card">
|
||||
<div class="card-header">
|
||||
<h1 class="card-title">VoidRaft</h1>
|
||||
<h1 class="card-title">voidraft</h1>
|
||||
<div class="card-controls">
|
||||
<button id="theme-toggle" class="btn btn-secondary" title="切换主题">
|
||||
<i class="fas fa-sun"></i> <span data-en="Theme" data-zh="主题">Theme</span>
|
||||
@@ -81,9 +81,9 @@
|
||||
<!-- Logo和介绍 -->
|
||||
<div class="logo-container">
|
||||
<div class="logo-frame">
|
||||
<img src="img/logo.png" alt="VoidRaft Logo" class="logo-image">
|
||||
<img src="img/logo.png" alt="voidraft Logo" class="logo-image">
|
||||
</div>
|
||||
<h2 class="logo-text" data-en="VoidRaft" data-zh="VoidRaft">VoidRaft</h2>
|
||||
<h2 class="logo-text" data-en="voidraft" data-zh="voidraft">voidraft</h2>
|
||||
<p class="tagline" data-en="An elegant text snippet recording tool" data-zh="优雅的文本片段记录工具">An elegant text snippet recording tool</p>
|
||||
</div>
|
||||
|
||||
@@ -195,15 +195,15 @@
|
||||
<div class="block-language">text</div>
|
||||
</div>
|
||||
<pre class="code-block">
|
||||
<span class="comment">// VoidRaft - An elegant text snippet recording tool</span>
|
||||
<span class="comment">// voidraft - An elegant text snippet recording tool</span>
|
||||
<span class="comment">// Multi-language support | Code formatting | Custom themes</span>
|
||||
<span class="comment">// A modern text editor designed for developers</span></pre>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="preview-window">
|
||||
<img src="img/screenshot-dark.png" alt="VoidRaft 界面预览" class="preview-image dark-theme-img">
|
||||
<img src="img/screenshot-light.png" alt="VoidRaft 界面预览" class="preview-image light-theme-img" style="display: none;">
|
||||
<img src="img/screenshot-dark.png" alt="voidraft 界面预览" class="preview-image dark-theme-img">
|
||||
<img src="img/screenshot-light.png" alt="voidraft 界面预览" class="preview-image light-theme-img" style="display: none;">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -241,7 +241,7 @@
|
||||
|
||||
<!-- 页脚 -->
|
||||
<footer class="footer">
|
||||
<p class="footer-text" data-en="© 2025 VoidRaft - An elegant text snippet recording tool designed for developers" data-zh="© 2025 VoidRaft - 专为开发者打造的优雅文本片段记录工具">© 2025 VoidRaft - An elegant text snippet recording tool designed for developers</p>
|
||||
<p class="footer-text" data-en="© 2025 voidraft - An elegant text snippet recording tool designed for developers" data-zh="© 2025 voidraft - 专为开发者打造的优雅文本片段记录工具">© 2025 voidraft - An elegant text snippet recording tool designed for developers</p>
|
||||
<div class="footer-links">
|
||||
<a href="https://github.com/landaiqing/voidraft" target="_blank" class="footer-link">GitHub</a>
|
||||
<a href="https://github.com/landaiqing/voidraft/issues" target="_blank" class="footer-link" data-en="Issues" data-zh="问题反馈">Issues</a>
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/**
|
||||
* VoidRaft - Changelog Script
|
||||
* voidraft - Changelog Script
|
||||
* 从GitHub API获取发布信息,支持Gitea备用源
|
||||
*/
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/**
|
||||
* VoidRaft - Website Script
|
||||
* voidraft - Website Script
|
||||
*/
|
||||
|
||||
/**
|
||||
@@ -233,14 +233,14 @@ class SEOManager {
|
||||
this.languageManager = languageManager;
|
||||
this.metaTexts = {
|
||||
en: {
|
||||
description: 'VoidRaft is an elegant text snippet recording tool designed for developers. Features multi-language code blocks, syntax highlighting, code formatting, custom themes, and more.',
|
||||
title: 'VoidRaft - An elegant text snippet recording tool designed for developers.',
|
||||
ogTitle: 'VoidRaft - An elegant text snippet recording tool designed for developers'
|
||||
description: 'voidraft is an elegant text snippet recording tool designed for developers. Features multi-language code blocks, syntax highlighting, code formatting, custom themes, and more.',
|
||||
title: 'voidraft - An elegant text snippet recording tool designed for developers.',
|
||||
ogTitle: 'voidraft - An elegant text snippet recording tool designed for developers'
|
||||
},
|
||||
zh: {
|
||||
description: 'VoidRaft 是专为开发者打造的优雅文本片段记录工具。支持多语言代码块、语法高亮、代码格式化、自定义主题等功能。',
|
||||
title: 'VoidRaft - 专为开发者打造的优雅文本片段记录工具',
|
||||
ogTitle: 'VoidRaft - 专为开发者打造的优雅文本片段记录工具'
|
||||
description: 'voidraft 是专为开发者打造的优雅文本片段记录工具。支持多语言代码块、语法高亮、代码格式化、自定义主题等功能。',
|
||||
title: 'voidraft - 专为开发者打造的优雅文本片段记录工具',
|
||||
ogTitle: 'voidraft - 专为开发者打造的优雅文本片段记录工具'
|
||||
}
|
||||
};
|
||||
this.init();
|
||||
@@ -371,9 +371,9 @@ class UIEffects {
|
||||
}
|
||||
|
||||
/**
|
||||
* VoidRaft主应用类
|
||||
* voidraft主应用类
|
||||
*/
|
||||
class VoidRaftApp {
|
||||
class voidraftApp {
|
||||
constructor() {
|
||||
this.themeManager = null;
|
||||
this.languageManager = null;
|
||||
@@ -404,7 +404,7 @@ class VoidRaftApp {
|
||||
* 显示控制台品牌信息
|
||||
*/
|
||||
showConsoleBranding() {
|
||||
console.log('%c VoidRaft', 'color: #ff006e; font-size: 20px; font-family: "Space Mono", monospace;');
|
||||
console.log('%c voidraft', 'color: #ff006e; font-size: 20px; font-family: "Space Mono", monospace;');
|
||||
console.log('%c An elegant text snippet recording tool designed for developers.', 'color: #073B4C; font-family: "Space Mono", monospace;');
|
||||
}
|
||||
|
||||
@@ -439,5 +439,5 @@ class VoidRaftApp {
|
||||
|
||||
// 当DOM加载完成时初始化应用
|
||||
document.addEventListener('DOMContentLoaded', () => {
|
||||
window.voidRaftApp = new VoidRaftApp();
|
||||
window.voidRaftApp = new voidraftApp();
|
||||
});
|
||||
@@ -0,0 +1,64 @@
|
||||
// Cynhyrchwyd y ffeil hon yn awtomatig. PEIDIWCH Â MODIWL
|
||||
// This file is automatically generated. DO NOT EDIT
|
||||
|
||||
/**
|
||||
* Service represents the notifications service
|
||||
* @module
|
||||
*/
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
||||
// @ts-ignore: Unused imports
|
||||
import {Call as $Call, Create as $Create} from "@wailsio/runtime";
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
||||
// @ts-ignore: Unused imports
|
||||
import * as application$0 from "../../application/models.js";
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
||||
// @ts-ignore: Unused imports
|
||||
import * as $models from "./models.js";
|
||||
|
||||
/**
|
||||
* RemoveBadge removes the badge label from the application icon.
|
||||
*/
|
||||
export function RemoveBadge(): Promise<void> & { cancel(): void } {
|
||||
let $resultPromise = $Call.ByID(2374916939) as any;
|
||||
return $resultPromise;
|
||||
}
|
||||
|
||||
/**
|
||||
* ServiceName returns the name of the service.
|
||||
*/
|
||||
export function ServiceName(): Promise<string> & { cancel(): void } {
|
||||
let $resultPromise = $Call.ByID(2428202016) as any;
|
||||
return $resultPromise;
|
||||
}
|
||||
|
||||
/**
|
||||
* ServiceShutdown is called when the service is unloaded.
|
||||
*/
|
||||
export function ServiceShutdown(): Promise<void> & { cancel(): void } {
|
||||
let $resultPromise = $Call.ByID(3893755233) as any;
|
||||
return $resultPromise;
|
||||
}
|
||||
|
||||
/**
|
||||
* ServiceStartup is called when the service is loaded.
|
||||
*/
|
||||
export function ServiceStartup(options: application$0.ServiceOptions): Promise<void> & { cancel(): void } {
|
||||
let $resultPromise = $Call.ByID(4078800764, options) as any;
|
||||
return $resultPromise;
|
||||
}
|
||||
|
||||
/**
|
||||
* SetBadge sets the badge label on the application icon.
|
||||
*/
|
||||
export function SetBadge(label: string): Promise<void> & { cancel(): void } {
|
||||
let $resultPromise = $Call.ByID(784276339, label) as any;
|
||||
return $resultPromise;
|
||||
}
|
||||
|
||||
export function SetCustomBadge(label: string, options: $models.Options): Promise<void> & { cancel(): void } {
|
||||
let $resultPromise = $Call.ByID(3058653106, label, options) as any;
|
||||
return $resultPromise;
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
// Cynhyrchwyd y ffeil hon yn awtomatig. PEIDIWCH Â MODIWL
|
||||
// This file is automatically generated. DO NOT EDIT
|
||||
|
||||
import * as BadgeService from "./badgeservice.js";
|
||||
export {
|
||||
BadgeService
|
||||
};
|
||||
|
||||
export * from "./models.js";
|
||||
@@ -0,0 +1,58 @@
|
||||
// Cynhyrchwyd y ffeil hon yn awtomatig. PEIDIWCH Â MODIWL
|
||||
// This file is automatically generated. DO NOT EDIT
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
||||
// @ts-ignore: Unused imports
|
||||
import {Create as $Create} from "@wailsio/runtime";
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
||||
// @ts-ignore: Unused imports
|
||||
import * as color$0 from "../../../../../../../image/color/models.js";
|
||||
|
||||
export class Options {
|
||||
"TextColour": color$0.RGBA;
|
||||
"BackgroundColour": color$0.RGBA;
|
||||
"FontName": string;
|
||||
"FontSize": number;
|
||||
"SmallFontSize": number;
|
||||
|
||||
/** Creates a new Options instance. */
|
||||
constructor($$source: Partial<Options> = {}) {
|
||||
if (!("TextColour" in $$source)) {
|
||||
this["TextColour"] = (new color$0.RGBA());
|
||||
}
|
||||
if (!("BackgroundColour" in $$source)) {
|
||||
this["BackgroundColour"] = (new color$0.RGBA());
|
||||
}
|
||||
if (!("FontName" in $$source)) {
|
||||
this["FontName"] = "";
|
||||
}
|
||||
if (!("FontSize" in $$source)) {
|
||||
this["FontSize"] = 0;
|
||||
}
|
||||
if (!("SmallFontSize" in $$source)) {
|
||||
this["SmallFontSize"] = 0;
|
||||
}
|
||||
|
||||
Object.assign(this, $$source);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new Options instance from a string or object.
|
||||
*/
|
||||
static createFrom($$source: any = {}): Options {
|
||||
const $$createField0_0 = $$createType0;
|
||||
const $$createField1_0 = $$createType0;
|
||||
let $$parsedSource = typeof $$source === 'string' ? JSON.parse($$source) : $$source;
|
||||
if ("TextColour" in $$parsedSource) {
|
||||
$$parsedSource["TextColour"] = $$createField0_0($$parsedSource["TextColour"]);
|
||||
}
|
||||
if ("BackgroundColour" in $$parsedSource) {
|
||||
$$parsedSource["BackgroundColour"] = $$createField1_0($$parsedSource["BackgroundColour"]);
|
||||
}
|
||||
return new Options($$parsedSource as Partial<Options>);
|
||||
}
|
||||
}
|
||||
|
||||
// Private type creation functions
|
||||
const $$createType0 = color$0.RGBA.createFrom;
|
||||
@@ -0,0 +1,9 @@
|
||||
// Cynhyrchwyd y ffeil hon yn awtomatig. PEIDIWCH Â MODIWL
|
||||
// This file is automatically generated. DO NOT EDIT
|
||||
|
||||
import * as NotificationService from "./notificationservice.js";
|
||||
export {
|
||||
NotificationService
|
||||
};
|
||||
|
||||
export * from "./models.js";
|
||||
@@ -0,0 +1,107 @@
|
||||
// Cynhyrchwyd y ffeil hon yn awtomatig. PEIDIWCH Â MODIWL
|
||||
// This file is automatically generated. DO NOT EDIT
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
||||
// @ts-ignore: Unused imports
|
||||
import {Create as $Create} from "@wailsio/runtime";
|
||||
|
||||
/**
|
||||
* NotificationAction represents an action button for a notification.
|
||||
*/
|
||||
export class NotificationAction {
|
||||
"id"?: string;
|
||||
"title"?: string;
|
||||
|
||||
/**
|
||||
* (macOS-specific)
|
||||
*/
|
||||
"destructive"?: boolean;
|
||||
|
||||
/** Creates a new NotificationAction instance. */
|
||||
constructor($$source: Partial<NotificationAction> = {}) {
|
||||
|
||||
Object.assign(this, $$source);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new NotificationAction instance from a string or object.
|
||||
*/
|
||||
static createFrom($$source: any = {}): NotificationAction {
|
||||
let $$parsedSource = typeof $$source === 'string' ? JSON.parse($$source) : $$source;
|
||||
return new NotificationAction($$parsedSource as Partial<NotificationAction>);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* NotificationCategory groups actions for notifications.
|
||||
*/
|
||||
export class NotificationCategory {
|
||||
"id"?: string;
|
||||
"actions"?: NotificationAction[];
|
||||
"hasReplyField"?: boolean;
|
||||
"replyPlaceholder"?: string;
|
||||
"replyButtonTitle"?: string;
|
||||
|
||||
/** Creates a new NotificationCategory instance. */
|
||||
constructor($$source: Partial<NotificationCategory> = {}) {
|
||||
|
||||
Object.assign(this, $$source);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new NotificationCategory instance from a string or object.
|
||||
*/
|
||||
static createFrom($$source: any = {}): NotificationCategory {
|
||||
const $$createField1_0 = $$createType1;
|
||||
let $$parsedSource = typeof $$source === 'string' ? JSON.parse($$source) : $$source;
|
||||
if ("actions" in $$parsedSource) {
|
||||
$$parsedSource["actions"] = $$createField1_0($$parsedSource["actions"]);
|
||||
}
|
||||
return new NotificationCategory($$parsedSource as Partial<NotificationCategory>);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* NotificationOptions contains configuration for a notification
|
||||
*/
|
||||
export class NotificationOptions {
|
||||
"id": string;
|
||||
"title": string;
|
||||
|
||||
/**
|
||||
* (macOS and Linux only)
|
||||
*/
|
||||
"subtitle"?: string;
|
||||
"body"?: string;
|
||||
"categoryId"?: string;
|
||||
"data"?: { [_: string]: any };
|
||||
|
||||
/** Creates a new NotificationOptions instance. */
|
||||
constructor($$source: Partial<NotificationOptions> = {}) {
|
||||
if (!("id" in $$source)) {
|
||||
this["id"] = "";
|
||||
}
|
||||
if (!("title" in $$source)) {
|
||||
this["title"] = "";
|
||||
}
|
||||
|
||||
Object.assign(this, $$source);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new NotificationOptions instance from a string or object.
|
||||
*/
|
||||
static createFrom($$source: any = {}): NotificationOptions {
|
||||
const $$createField5_0 = $$createType2;
|
||||
let $$parsedSource = typeof $$source === 'string' ? JSON.parse($$source) : $$source;
|
||||
if ("data" in $$parsedSource) {
|
||||
$$parsedSource["data"] = $$createField5_0($$parsedSource["data"]);
|
||||
}
|
||||
return new NotificationOptions($$parsedSource as Partial<NotificationOptions>);
|
||||
}
|
||||
}
|
||||
|
||||
// Private type creation functions
|
||||
const $$createType0 = NotificationAction.createFrom;
|
||||
const $$createType1 = $Create.Array($$createType0);
|
||||
const $$createType2 = $Create.Map($Create.Any, $Create.Any);
|
||||
@@ -0,0 +1,110 @@
|
||||
// Cynhyrchwyd y ffeil hon yn awtomatig. PEIDIWCH Â MODIWL
|
||||
// This file is automatically generated. DO NOT EDIT
|
||||
|
||||
/**
|
||||
* Service represents the notifications service
|
||||
* @module
|
||||
*/
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
||||
// @ts-ignore: Unused imports
|
||||
import {Call as $Call, Create as $Create} from "@wailsio/runtime";
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
||||
// @ts-ignore: Unused imports
|
||||
import * as application$0 from "../../application/models.js";
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
||||
// @ts-ignore: Unused imports
|
||||
import * as $models from "./models.js";
|
||||
|
||||
export function CheckNotificationAuthorization(): Promise<boolean> & { cancel(): void } {
|
||||
let $resultPromise = $Call.ByID(2216952893) as any;
|
||||
return $resultPromise;
|
||||
}
|
||||
|
||||
/**
|
||||
* OnNotificationResponse registers a callback function that will be called when
|
||||
* a notification response is received from the user.
|
||||
*/
|
||||
export function OnNotificationResponse(callback: any): Promise<void> & { cancel(): void } {
|
||||
let $resultPromise = $Call.ByID(1642697808, callback) as any;
|
||||
return $resultPromise;
|
||||
}
|
||||
|
||||
export function RegisterNotificationCategory(category: $models.NotificationCategory): Promise<void> & { cancel(): void } {
|
||||
let $resultPromise = $Call.ByID(2917562919, category) as any;
|
||||
return $resultPromise;
|
||||
}
|
||||
|
||||
export function RemoveAllDeliveredNotifications(): Promise<void> & { cancel(): void } {
|
||||
let $resultPromise = $Call.ByID(3956282340) as any;
|
||||
return $resultPromise;
|
||||
}
|
||||
|
||||
export function RemoveAllPendingNotifications(): Promise<void> & { cancel(): void } {
|
||||
let $resultPromise = $Call.ByID(108821341) as any;
|
||||
return $resultPromise;
|
||||
}
|
||||
|
||||
export function RemoveDeliveredNotification(identifier: string): Promise<void> & { cancel(): void } {
|
||||
let $resultPromise = $Call.ByID(975691940, identifier) as any;
|
||||
return $resultPromise;
|
||||
}
|
||||
|
||||
export function RemoveNotification(identifier: string): Promise<void> & { cancel(): void } {
|
||||
let $resultPromise = $Call.ByID(3966653866, identifier) as any;
|
||||
return $resultPromise;
|
||||
}
|
||||
|
||||
export function RemoveNotificationCategory(categoryID: string): Promise<void> & { cancel(): void } {
|
||||
let $resultPromise = $Call.ByID(2032615554, categoryID) as any;
|
||||
return $resultPromise;
|
||||
}
|
||||
|
||||
export function RemovePendingNotification(identifier: string): Promise<void> & { cancel(): void } {
|
||||
let $resultPromise = $Call.ByID(3729049703, identifier) as any;
|
||||
return $resultPromise;
|
||||
}
|
||||
|
||||
/**
|
||||
* Public methods that delegate to the implementation.
|
||||
*/
|
||||
export function RequestNotificationAuthorization(): Promise<boolean> & { cancel(): void } {
|
||||
let $resultPromise = $Call.ByID(3933442950) as any;
|
||||
return $resultPromise;
|
||||
}
|
||||
|
||||
export function SendNotification(options: $models.NotificationOptions): Promise<void> & { cancel(): void } {
|
||||
let $resultPromise = $Call.ByID(3968228732, options) as any;
|
||||
return $resultPromise;
|
||||
}
|
||||
|
||||
export function SendNotificationWithActions(options: $models.NotificationOptions): Promise<void> & { cancel(): void } {
|
||||
let $resultPromise = $Call.ByID(1886542847, options) as any;
|
||||
return $resultPromise;
|
||||
}
|
||||
|
||||
/**
|
||||
* ServiceName returns the name of the service.
|
||||
*/
|
||||
export function ServiceName(): Promise<string> & { cancel(): void } {
|
||||
let $resultPromise = $Call.ByID(2704532675) as any;
|
||||
return $resultPromise;
|
||||
}
|
||||
|
||||
/**
|
||||
* ServiceShutdown is called when the service is unloaded.
|
||||
*/
|
||||
export function ServiceShutdown(): Promise<void> & { cancel(): void } {
|
||||
let $resultPromise = $Call.ByID(2550195434) as any;
|
||||
return $resultPromise;
|
||||
}
|
||||
|
||||
/**
|
||||
* ServiceStartup is called when the service is loaded.
|
||||
*/
|
||||
export function ServiceStartup(options: application$0.ServiceOptions): Promise<void> & { cancel(): void } {
|
||||
let $resultPromise = $Call.ByID(4047820929, options) as any;
|
||||
return $resultPromise;
|
||||
}
|
||||
4
frontend/bindings/image/color/index.ts
Normal file
4
frontend/bindings/image/color/index.ts
Normal file
@@ -0,0 +1,4 @@
|
||||
// Cynhyrchwyd y ffeil hon yn awtomatig. PEIDIWCH Â MODIWL
|
||||
// This file is automatically generated. DO NOT EDIT
|
||||
|
||||
export * from "./models.js";
|
||||
46
frontend/bindings/image/color/models.ts
Normal file
46
frontend/bindings/image/color/models.ts
Normal file
@@ -0,0 +1,46 @@
|
||||
// Cynhyrchwyd y ffeil hon yn awtomatig. PEIDIWCH Â MODIWL
|
||||
// This file is automatically generated. DO NOT EDIT
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
||||
// @ts-ignore: Unused imports
|
||||
import {Create as $Create} from "@wailsio/runtime";
|
||||
|
||||
/**
|
||||
* RGBA represents a traditional 32-bit alpha-premultiplied color, having 8
|
||||
* bits for each of red, green, blue and alpha.
|
||||
*
|
||||
* An alpha-premultiplied color component C has been scaled by alpha (A), so
|
||||
* has valid values 0 <= C <= A.
|
||||
*/
|
||||
export class RGBA {
|
||||
"R": number;
|
||||
"G": number;
|
||||
"B": number;
|
||||
"A": number;
|
||||
|
||||
/** Creates a new RGBA instance. */
|
||||
constructor($$source: Partial<RGBA> = {}) {
|
||||
if (!("R" in $$source)) {
|
||||
this["R"] = 0;
|
||||
}
|
||||
if (!("G" in $$source)) {
|
||||
this["G"] = 0;
|
||||
}
|
||||
if (!("B" in $$source)) {
|
||||
this["B"] = 0;
|
||||
}
|
||||
if (!("A" in $$source)) {
|
||||
this["A"] = 0;
|
||||
}
|
||||
|
||||
Object.assign(this, $$source);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new RGBA instance from a string or object.
|
||||
*/
|
||||
static createFrom($$source: any = {}): RGBA {
|
||||
let $$parsedSource = typeof $$source === 'string' ? JSON.parse($$source) : $$source;
|
||||
return new RGBA($$parsedSource as Partial<RGBA>);
|
||||
}
|
||||
}
|
||||
@@ -467,6 +467,12 @@ export class GeneralConfig {
|
||||
*/
|
||||
"startAtLogin": boolean;
|
||||
|
||||
/**
|
||||
* 窗口吸附设置
|
||||
* 是否启用窗口吸附功能(阈值现在是自适应的)
|
||||
*/
|
||||
"enableWindowSnap": boolean;
|
||||
|
||||
/**
|
||||
* 全局热键设置
|
||||
* 是否启用全局热键
|
||||
@@ -478,6 +484,12 @@ export class GeneralConfig {
|
||||
*/
|
||||
"globalHotkey": HotkeyCombo;
|
||||
|
||||
/**
|
||||
* 界面设置
|
||||
* 是否启用加载动画
|
||||
*/
|
||||
"enableLoadingAnimation": boolean;
|
||||
|
||||
/** Creates a new GeneralConfig instance. */
|
||||
constructor($$source: Partial<GeneralConfig> = {}) {
|
||||
if (!("alwaysOnTop" in $$source)) {
|
||||
@@ -492,12 +504,18 @@ export class GeneralConfig {
|
||||
if (!("startAtLogin" in $$source)) {
|
||||
this["startAtLogin"] = false;
|
||||
}
|
||||
if (!("enableWindowSnap" in $$source)) {
|
||||
this["enableWindowSnap"] = false;
|
||||
}
|
||||
if (!("enableGlobalHotkey" in $$source)) {
|
||||
this["enableGlobalHotkey"] = false;
|
||||
}
|
||||
if (!("globalHotkey" in $$source)) {
|
||||
this["globalHotkey"] = (new HotkeyCombo());
|
||||
}
|
||||
if (!("enableLoadingAnimation" in $$source)) {
|
||||
this["enableLoadingAnimation"] = false;
|
||||
}
|
||||
|
||||
Object.assign(this, $$source);
|
||||
}
|
||||
@@ -506,10 +524,10 @@ export class GeneralConfig {
|
||||
* Creates a new GeneralConfig instance from a string or object.
|
||||
*/
|
||||
static createFrom($$source: any = {}): GeneralConfig {
|
||||
const $$createField5_0 = $$createType8;
|
||||
const $$createField6_0 = $$createType8;
|
||||
let $$parsedSource = typeof $$source === 'string' ? JSON.parse($$source) : $$source;
|
||||
if ("globalHotkey" in $$parsedSource) {
|
||||
$$parsedSource["globalHotkey"] = $$createField5_0($$parsedSource["globalHotkey"]);
|
||||
$$parsedSource["globalHotkey"] = $$createField6_0($$parsedSource["globalHotkey"]);
|
||||
}
|
||||
return new GeneralConfig($$parsedSource as Partial<GeneralConfig>);
|
||||
}
|
||||
|
||||
@@ -34,6 +34,30 @@ export function GetConfig(): Promise<models$0.AppConfig | null> & { cancel(): vo
|
||||
return $typingPromise;
|
||||
}
|
||||
|
||||
/**
|
||||
* GetConfigDir 获取配置目录
|
||||
*/
|
||||
export function GetConfigDir(): Promise<string> & { cancel(): void } {
|
||||
let $resultPromise = $Call.ByID(2275626561) as any;
|
||||
return $resultPromise;
|
||||
}
|
||||
|
||||
/**
|
||||
* GetSettingsPath 获取设置文件路径
|
||||
*/
|
||||
export function GetSettingsPath(): Promise<string> & { cancel(): void } {
|
||||
let $resultPromise = $Call.ByID(2175583370) as any;
|
||||
return $resultPromise;
|
||||
}
|
||||
|
||||
/**
|
||||
* MigrateConfig 执行配置迁移
|
||||
*/
|
||||
export function MigrateConfig(): Promise<void> & { cancel(): void } {
|
||||
let $resultPromise = $Call.ByID(434292783) as any;
|
||||
return $resultPromise;
|
||||
}
|
||||
|
||||
/**
|
||||
* ResetConfig 强制重置所有配置为默认值
|
||||
*/
|
||||
@@ -82,6 +106,14 @@ export function SetHotkeyChangeCallback(callback: any): Promise<void> & { cancel
|
||||
return $resultPromise;
|
||||
}
|
||||
|
||||
/**
|
||||
* SetWindowSnapConfigChangeCallback 设置窗口吸附配置变更回调
|
||||
*/
|
||||
export function SetWindowSnapConfigChangeCallback(callback: any): Promise<void> & { cancel(): void } {
|
||||
let $resultPromise = $Call.ByID(2324961653, callback) as any;
|
||||
return $resultPromise;
|
||||
}
|
||||
|
||||
// Private type creation functions
|
||||
const $$createType0 = models$0.AppConfig.createFrom;
|
||||
const $$createType1 = $Create.Nullable($$createType0);
|
||||
|
||||
@@ -13,6 +13,7 @@ import * as MigrationService from "./migrationservice.js";
|
||||
import * as SelfUpdateService from "./selfupdateservice.js";
|
||||
import * as StartupService from "./startupservice.js";
|
||||
import * as SystemService from "./systemservice.js";
|
||||
import * as TestService from "./testservice.js";
|
||||
import * as ThemeService from "./themeservice.js";
|
||||
import * as TranslationService from "./translationservice.js";
|
||||
import * as TrayService from "./trayservice.js";
|
||||
@@ -30,6 +31,7 @@ export {
|
||||
SelfUpdateService,
|
||||
StartupService,
|
||||
SystemService,
|
||||
TestService,
|
||||
ThemeService,
|
||||
TranslationService,
|
||||
TrayService,
|
||||
|
||||
@@ -203,7 +203,7 @@ export class SelfUpdateResult {
|
||||
}
|
||||
|
||||
/**
|
||||
* WindowInfo 窗口信息
|
||||
* WindowInfo 窗口信息(简化版)
|
||||
*/
|
||||
export class WindowInfo {
|
||||
"Window": application$0.WebviewWindow | null;
|
||||
@@ -238,6 +238,26 @@ export class WindowInfo {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* WindowSnapService 窗口吸附服务
|
||||
*/
|
||||
export class WindowSnapService {
|
||||
|
||||
/** Creates a new WindowSnapService instance. */
|
||||
constructor($$source: Partial<WindowSnapService> = {}) {
|
||||
|
||||
Object.assign(this, $$source);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new WindowSnapService instance from a string or object.
|
||||
*/
|
||||
static createFrom($$source: any = {}): WindowSnapService {
|
||||
let $$parsedSource = typeof $$source === 'string' ? JSON.parse($$source) : $$source;
|
||||
return new WindowSnapService($$parsedSource as Partial<WindowSnapService>);
|
||||
}
|
||||
}
|
||||
|
||||
// Private type creation functions
|
||||
const $$createType0 = application$0.WebviewWindow.createFrom;
|
||||
const $$createType1 = $Create.Nullable($$createType0);
|
||||
|
||||
55
frontend/bindings/voidraft/internal/services/testservice.ts
Normal file
55
frontend/bindings/voidraft/internal/services/testservice.ts
Normal file
@@ -0,0 +1,55 @@
|
||||
// Cynhyrchwyd y ffeil hon yn awtomatig. PEIDIWCH Â MODIWL
|
||||
// This file is automatically generated. DO NOT EDIT
|
||||
|
||||
/**
|
||||
* TestService 测试服务 - 仅在开发环境使用
|
||||
* @module
|
||||
*/
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
||||
// @ts-ignore: Unused imports
|
||||
import {Call as $Call, Create as $Create} from "@wailsio/runtime";
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
||||
// @ts-ignore: Unused imports
|
||||
import * as application$0 from "../../../github.com/wailsapp/wails/v3/pkg/application/models.js";
|
||||
|
||||
/**
|
||||
* ClearAll 清除所有测试状态
|
||||
*/
|
||||
export function ClearAll(): Promise<void> & { cancel(): void } {
|
||||
let $resultPromise = $Call.ByID(2179720854) as any;
|
||||
return $resultPromise;
|
||||
}
|
||||
|
||||
/**
|
||||
* ServiceStartup 服务启动时调用
|
||||
*/
|
||||
export function ServiceStartup(options: application$0.ServiceOptions): Promise<void> & { cancel(): void } {
|
||||
let $resultPromise = $Call.ByID(617408198, options) as any;
|
||||
return $resultPromise;
|
||||
}
|
||||
|
||||
/**
|
||||
* TestBadge 测试Badge功能
|
||||
*/
|
||||
export function TestBadge(text: string): Promise<void> & { cancel(): void } {
|
||||
let $resultPromise = $Call.ByID(4242952145, text) as any;
|
||||
return $resultPromise;
|
||||
}
|
||||
|
||||
/**
|
||||
* TestNotification 测试通知功能
|
||||
*/
|
||||
export function TestNotification(title: string, subtitle: string, body: string): Promise<void> & { cancel(): void } {
|
||||
let $resultPromise = $Call.ByID(1697553289, title, subtitle, body) as any;
|
||||
return $resultPromise;
|
||||
}
|
||||
|
||||
/**
|
||||
* TestUpdateNotification 测试更新通知
|
||||
*/
|
||||
export function TestUpdateNotification(): Promise<void> & { cancel(): void } {
|
||||
let $resultPromise = $Call.ByID(3091730060) as any;
|
||||
return $resultPromise;
|
||||
}
|
||||
@@ -2,7 +2,7 @@
|
||||
// This file is automatically generated. DO NOT EDIT
|
||||
|
||||
/**
|
||||
* WindowService 窗口管理服务
|
||||
* WindowService 窗口管理服务(专注于窗口生命周期管理)
|
||||
* @module
|
||||
*/
|
||||
|
||||
@@ -46,6 +46,14 @@ export function OpenDocumentWindow(documentID: number): Promise<void> & { cancel
|
||||
return $resultPromise;
|
||||
}
|
||||
|
||||
/**
|
||||
* ServiceShutdown 实现服务关闭接口
|
||||
*/
|
||||
export function ServiceShutdown(): Promise<void> & { cancel(): void } {
|
||||
let $resultPromise = $Call.ByID(202192783) as any;
|
||||
return $resultPromise;
|
||||
}
|
||||
|
||||
/**
|
||||
* SetAppReferences 设置应用和主窗口引用
|
||||
*/
|
||||
@@ -54,6 +62,14 @@ export function SetAppReferences(app: application$0.App | null, mainWindow: appl
|
||||
return $resultPromise;
|
||||
}
|
||||
|
||||
/**
|
||||
* SetWindowSnapService 设置窗口吸附服务引用
|
||||
*/
|
||||
export function SetWindowSnapService(snapService: $models.WindowSnapService | null): Promise<void> & { cancel(): void } {
|
||||
let $resultPromise = $Call.ByID(1105193745, snapService) as any;
|
||||
return $resultPromise;
|
||||
}
|
||||
|
||||
// Private type creation functions
|
||||
const $$createType0 = $models.WindowInfo.createFrom;
|
||||
const $$createType1 = $Create.Array($$createType0);
|
||||
|
||||
@@ -9,5 +9,6 @@
|
||||
<body>
|
||||
<div id="app"></div>
|
||||
<script type="module" src="/src/main.ts"></script>
|
||||
<script src="/math.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
2509
frontend/package-lock.json
generated
2509
frontend/package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@@ -5,20 +5,20 @@
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
"dev": "vite --host --mode development",
|
||||
"build:dev": "vue-tsc && vite build --minify false --mode development",
|
||||
"build": "vue-tsc && vite build --mode production",
|
||||
"build:dev": "cross-env NODE_OPTIONS=\"--max-old-space-size=8192\" vue-tsc && cross-env NODE_OPTIONS=\"--max-old-space-size=8192\" vite build --minify false --mode development",
|
||||
"build": "cross-env NODE_OPTIONS=\"--max-old-space-size=8192\" vue-tsc && cross-env NODE_OPTIONS=\"--max-old-space-size=8192\" vite build --mode production",
|
||||
"preview": "vite preview",
|
||||
"lint": "eslint",
|
||||
"lint:fix": "eslint --fix"
|
||||
},
|
||||
"dependencies": {
|
||||
"@codemirror/autocomplete": "^6.18.6",
|
||||
"@codemirror/autocomplete": "^6.18.7",
|
||||
"@codemirror/commands": "^6.8.1",
|
||||
"@codemirror/lang-angular": "^0.1.4",
|
||||
"@codemirror/lang-cpp": "^6.0.3",
|
||||
"@codemirror/lang-css": "^6.3.1",
|
||||
"@codemirror/lang-go": "^6.0.1",
|
||||
"@codemirror/lang-html": "^6.4.9",
|
||||
"@codemirror/lang-html": "^6.4.10",
|
||||
"@codemirror/lang-java": "^6.0.2",
|
||||
"@codemirror/lang-javascript": "^6.2.4",
|
||||
"@codemirror/lang-json": "^6.0.2",
|
||||
@@ -33,7 +33,6 @@
|
||||
"@codemirror/lang-sql": "^6.9.1",
|
||||
"@codemirror/lang-vue": "^0.1.3",
|
||||
"@codemirror/lang-wast": "^6.0.2",
|
||||
"@codemirror/lang-xml": "^6.1.0",
|
||||
"@codemirror/lang-yaml": "^6.1.2",
|
||||
"@codemirror/language": "^6.11.3",
|
||||
"@codemirror/language-data": "^6.5.1",
|
||||
@@ -41,41 +40,53 @@
|
||||
"@codemirror/lint": "^6.8.5",
|
||||
"@codemirror/search": "^6.5.11",
|
||||
"@codemirror/state": "^6.5.2",
|
||||
"@codemirror/view": "^6.38.1",
|
||||
"@codemirror/view": "^6.38.2",
|
||||
"@cospaia/prettier-plugin-clojure": "^0.0.2",
|
||||
"@lezer/highlight": "^1.2.1",
|
||||
"@lezer/lr": "^1.4.2",
|
||||
"@prettier/plugin-xml": "^3.4.2",
|
||||
"@reteps/dockerfmt": "^0.3.6",
|
||||
"@toml-tools/lexer": "^1.0.0",
|
||||
"@toml-tools/parser": "^1.0.0",
|
||||
"codemirror": "^6.0.2",
|
||||
"codemirror-lang-elixir": "^4.0.0",
|
||||
"colors-named": "^1.0.2",
|
||||
"colors-named-hex": "^1.0.2",
|
||||
"franc-min": "^6.2.0",
|
||||
"groovy-beautify": "^0.0.17",
|
||||
"hsl-matcher": "^1.2.4",
|
||||
"lezer": "^0.13.5",
|
||||
"java-parser": "^3.0.1",
|
||||
"jsox": "^1.2.123",
|
||||
"linguist-languages": "^9.0.0",
|
||||
"php-parser": "^3.2.5",
|
||||
"pinia": "^3.0.3",
|
||||
"pinia-plugin-persistedstate": "^4.5.0",
|
||||
"prettier": "^3.6.2",
|
||||
"remarkable": "^2.0.1",
|
||||
"sass": "^1.90.0",
|
||||
"vue": "^3.5.18",
|
||||
"vue-i18n": "^11.1.11",
|
||||
"sass": "^1.92.1",
|
||||
"sh-syntax": "^0.5.8",
|
||||
"vue": "^3.5.21",
|
||||
"vue-i18n": "^11.1.12",
|
||||
"vue-pick-colors": "^1.8.0",
|
||||
"vue-router": "^4.5.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@eslint/js": "^9.33.0",
|
||||
"@eslint/js": "^9.35.0",
|
||||
"@lezer/generator": "^1.8.0",
|
||||
"@types/node": "^24.3.0",
|
||||
"@types/node": "^24.3.1",
|
||||
"@types/remarkable": "^2.0.8",
|
||||
"@vitejs/plugin-vue": "^6.0.1",
|
||||
"@wailsio/runtime": "latest",
|
||||
"eslint": "^9.33.0",
|
||||
"cross-env": "^7.0.3",
|
||||
"eslint": "^9.35.0",
|
||||
"eslint-plugin-vue": "^10.4.0",
|
||||
"globals": "^16.3.0",
|
||||
"globals": "^16.4.0",
|
||||
"typescript": "^5.9.2",
|
||||
"typescript-eslint": "^8.39.1",
|
||||
"typescript-eslint": "^8.43.0",
|
||||
"unplugin-vue-components": "^29.0.0",
|
||||
"vite": "^7.1.2",
|
||||
"vite": "^7.1.5",
|
||||
"vite-plugin-node-polyfills": "^0.24.0",
|
||||
"vue-eslint-parser": "^10.2.0",
|
||||
"vue-tsc": "^3.0.5"
|
||||
"vue-tsc": "^3.0.6"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,7 +1,5 @@
|
||||
importScripts("guesslang.min.js")
|
||||
|
||||
const LANGUAGES = ["json", "py", "html", "sql", "md", "java", "php", "css", "xml", "cpp", "rs", "cs", "rb", "sh", "yaml", "toml", "go", "clj", "ex", "erl", "js", "ts", "swift", "kt", "groovy", "ps1", "dart", "scala"]
|
||||
|
||||
const guessLang = new self.GuessLang()
|
||||
|
||||
function sendResult(language, confidence, idx) {
|
||||
@@ -27,20 +25,13 @@ onmessage = (event) => {
|
||||
|
||||
guessLang.runModel(content).then((result) => {
|
||||
if (result.length > 0) {
|
||||
const lang = result[0]
|
||||
if (LANGUAGES.includes(lang.languageId) && lang.confidence > 0.15) {
|
||||
sendResult(lang.languageId, lang.confidence, idx)
|
||||
// 返回置信度最高的结果
|
||||
const bestResult = result[0]
|
||||
if (bestResult.confidence > 0.15) {
|
||||
sendResult(bestResult.languageId, bestResult.confidence, idx)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
for (let lang of result) {
|
||||
if (LANGUAGES.includes(lang.languageId) && lang.confidence > 0.5) {
|
||||
sendResult(lang.languageId, lang.confidence, idx)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
sendResult("text", 0.0, idx)
|
||||
}).catch(() => {
|
||||
sendResult("text", 0.0, idx)
|
||||
|
||||
3
frontend/public/math.js
Normal file
3
frontend/public/math.js
Normal file
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
BIN
frontend/src/common/prettier/plugins/clang/clang-format-cli.wasm
Normal file
BIN
frontend/src/common/prettier/plugins/clang/clang-format-cli.wasm
Normal file
Binary file not shown.
@@ -0,0 +1,10 @@
|
||||
import fs from "node:fs/promises";
|
||||
import initAsync from "./clang-format.js";
|
||||
|
||||
const wasm = new URL("./clang-format.wasm", import.meta.url);
|
||||
|
||||
export default function (init = fs.readFile(wasm)) {
|
||||
return initAsync(init);
|
||||
}
|
||||
|
||||
export * from "./clang-format.js";
|
||||
@@ -0,0 +1,8 @@
|
||||
import initAsync from "./clang-format.js";
|
||||
import wasm from "./clang-format.wasm?url";
|
||||
|
||||
export default function (input = wasm) {
|
||||
return initAsync(input);
|
||||
}
|
||||
|
||||
export * from "./clang-format.js";
|
||||
155
frontend/src/common/prettier/plugins/clang/clang-format.js
Normal file
155
frontend/src/common/prettier/plugins/clang/clang-format.js
Normal file
File diff suppressed because one or more lines are too long
BIN
frontend/src/common/prettier/plugins/clang/clang-format.wasm
Normal file
BIN
frontend/src/common/prettier/plugins/clang/clang-format.wasm
Normal file
Binary file not shown.
3
frontend/src/common/prettier/plugins/clang/cli-pre.js
Normal file
3
frontend/src/common/prettier/plugins/clang/cli-pre.js
Normal file
@@ -0,0 +1,3 @@
|
||||
Module.preRun = function customPreRun() {
|
||||
ENV.PWD = process.cwd();
|
||||
}
|
||||
858
frontend/src/common/prettier/plugins/clang/git-clang-format
Normal file
858
frontend/src/common/prettier/plugins/clang/git-clang-format
Normal file
@@ -0,0 +1,858 @@
|
||||
#!/usr/bin/env python3
|
||||
#
|
||||
# ===- git-clang-format - ClangFormat Git Integration -------*- python -*--=== #
|
||||
#
|
||||
# Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
# See https://llvm.org/LICENSE.txt for license information.
|
||||
# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
#
|
||||
# ===----------------------------------------------------------------------=== #
|
||||
|
||||
r"""
|
||||
clang-format git integration
|
||||
============================
|
||||
|
||||
This file provides a clang-format integration for git. Put it somewhere in your
|
||||
path and ensure that it is executable. Then, "git clang-format" will invoke
|
||||
clang-format on the changes in current files or a specific commit.
|
||||
|
||||
For further details, run:
|
||||
git clang-format -h
|
||||
|
||||
Requires Python version >=3.8
|
||||
"""
|
||||
|
||||
from __future__ import absolute_import, division, print_function
|
||||
import argparse
|
||||
import collections
|
||||
import contextlib
|
||||
import errno
|
||||
import os
|
||||
import re
|
||||
import subprocess
|
||||
import sys
|
||||
|
||||
usage = "git clang-format [OPTIONS] [<commit>] [<commit>|--staged] [--] [<file>...]"
|
||||
|
||||
desc = """
|
||||
If zero or one commits are given, run clang-format on all lines that differ
|
||||
between the working directory and <commit>, which defaults to HEAD. Changes are
|
||||
only applied to the working directory, or in the stage/index.
|
||||
|
||||
Examples:
|
||||
To format staged changes, i.e everything that's been `git add`ed:
|
||||
git clang-format
|
||||
|
||||
To also format everything touched in the most recent commit:
|
||||
git clang-format HEAD~1
|
||||
|
||||
If you're on a branch off main, to format everything touched on your branch:
|
||||
git clang-format main
|
||||
|
||||
If two commits are given (requires --diff), run clang-format on all lines in the
|
||||
second <commit> that differ from the first <commit>.
|
||||
|
||||
The following git-config settings set the default of the corresponding option:
|
||||
clangFormat.binary
|
||||
clangFormat.commit
|
||||
clangFormat.extensions
|
||||
clangFormat.style
|
||||
"""
|
||||
|
||||
# Name of the temporary index file in which save the output of clang-format.
|
||||
# This file is created within the .git directory.
|
||||
temp_index_basename = "clang-format-index"
|
||||
|
||||
|
||||
Range = collections.namedtuple("Range", "start, count")
|
||||
|
||||
|
||||
def main():
|
||||
config = load_git_config()
|
||||
|
||||
# In order to keep '--' yet allow options after positionals, we need to
|
||||
# check for '--' ourselves. (Setting nargs='*' throws away the '--', while
|
||||
# nargs=argparse.REMAINDER disallows options after positionals.)
|
||||
argv = sys.argv[1:]
|
||||
try:
|
||||
idx = argv.index("--")
|
||||
except ValueError:
|
||||
dash_dash = []
|
||||
else:
|
||||
dash_dash = argv[idx:]
|
||||
argv = argv[:idx]
|
||||
|
||||
default_extensions = ",".join(
|
||||
[
|
||||
# From clang/lib/Frontend/FrontendOptions.cpp, all lower case
|
||||
"c",
|
||||
"h", # C
|
||||
"m", # ObjC
|
||||
"mm", # ObjC++
|
||||
"cc",
|
||||
"cp",
|
||||
"cpp",
|
||||
"c++",
|
||||
"cxx",
|
||||
"hh",
|
||||
"hpp",
|
||||
"hxx",
|
||||
"inc", # C++
|
||||
"ccm",
|
||||
"cppm",
|
||||
"cxxm",
|
||||
"c++m", # C++ Modules
|
||||
"cu",
|
||||
"cuh", # CUDA
|
||||
"cl", # OpenCL
|
||||
# Other languages that clang-format supports
|
||||
"proto",
|
||||
"protodevel", # Protocol Buffers
|
||||
"java", # Java
|
||||
"js",
|
||||
"mjs",
|
||||
"cjs", # JavaScript
|
||||
"ts", # TypeScript
|
||||
"cs", # C Sharp
|
||||
"json",
|
||||
"ipynb", # Json
|
||||
"sv",
|
||||
"svh",
|
||||
"v",
|
||||
"vh", # Verilog
|
||||
"td", # TableGen
|
||||
"txtpb",
|
||||
"textpb",
|
||||
"pb.txt",
|
||||
"textproto",
|
||||
"asciipb", # TextProto
|
||||
]
|
||||
)
|
||||
|
||||
p = argparse.ArgumentParser(
|
||||
usage=usage,
|
||||
formatter_class=argparse.RawDescriptionHelpFormatter,
|
||||
description=desc,
|
||||
)
|
||||
p.add_argument(
|
||||
"--binary",
|
||||
default=config.get("clangformat.binary", "clang-format"),
|
||||
help="path to clang-format",
|
||||
),
|
||||
p.add_argument(
|
||||
"--commit",
|
||||
default=config.get("clangformat.commit", "HEAD"),
|
||||
help="default commit to use if none is specified",
|
||||
),
|
||||
p.add_argument(
|
||||
"--diff",
|
||||
action="store_true",
|
||||
help="print a diff instead of applying the changes",
|
||||
)
|
||||
p.add_argument(
|
||||
"--diffstat",
|
||||
action="store_true",
|
||||
help="print a diffstat instead of applying the changes",
|
||||
)
|
||||
p.add_argument(
|
||||
"--extensions",
|
||||
default=config.get("clangformat.extensions", default_extensions),
|
||||
help=(
|
||||
"comma-separated list of file extensions to format, "
|
||||
"excluding the period and case-insensitive"
|
||||
),
|
||||
),
|
||||
p.add_argument(
|
||||
"-f",
|
||||
"--force",
|
||||
action="store_true",
|
||||
help="allow changes to unstaged files",
|
||||
)
|
||||
p.add_argument(
|
||||
"-p", "--patch", action="store_true", help="select hunks interactively"
|
||||
)
|
||||
p.add_argument(
|
||||
"-q",
|
||||
"--quiet",
|
||||
action="count",
|
||||
default=0,
|
||||
help="print less information",
|
||||
)
|
||||
p.add_argument(
|
||||
"--staged",
|
||||
"--cached",
|
||||
action="store_true",
|
||||
help="format lines in the stage instead of the working dir",
|
||||
)
|
||||
p.add_argument(
|
||||
"--style",
|
||||
default=config.get("clangformat.style", None),
|
||||
help="passed to clang-format",
|
||||
),
|
||||
p.add_argument(
|
||||
"-v",
|
||||
"--verbose",
|
||||
action="count",
|
||||
default=0,
|
||||
help="print extra information",
|
||||
)
|
||||
p.add_argument(
|
||||
"--diff_from_common_commit",
|
||||
action="store_true",
|
||||
help=(
|
||||
"diff from the last common commit for commits in "
|
||||
"separate branches rather than the exact point of the "
|
||||
"commits"
|
||||
),
|
||||
)
|
||||
# We gather all the remaining positional arguments into 'args' since we need
|
||||
# to use some heuristics to determine whether or not <commit> was present.
|
||||
# However, to print pretty messages, we make use of metavar and help.
|
||||
p.add_argument(
|
||||
"args",
|
||||
nargs="*",
|
||||
metavar="<commit>",
|
||||
help="revision from which to compute the diff",
|
||||
)
|
||||
p.add_argument(
|
||||
"ignored",
|
||||
nargs="*",
|
||||
metavar="<file>...",
|
||||
help="if specified, only consider differences in these files",
|
||||
)
|
||||
opts = p.parse_args(argv)
|
||||
|
||||
opts.verbose -= opts.quiet
|
||||
del opts.quiet
|
||||
|
||||
commits, files = interpret_args(opts.args, dash_dash, opts.commit)
|
||||
if len(commits) > 2:
|
||||
die("at most two commits allowed; %d given" % len(commits))
|
||||
if len(commits) == 2:
|
||||
if opts.staged:
|
||||
die("--staged is not allowed when two commits are given")
|
||||
if not opts.diff:
|
||||
die("--diff is required when two commits are given")
|
||||
elif opts.diff_from_common_commit:
|
||||
die("--diff_from_common_commit is only allowed when two commits are given")
|
||||
|
||||
if os.path.dirname(opts.binary):
|
||||
opts.binary = os.path.abspath(opts.binary)
|
||||
|
||||
changed_lines = compute_diff_and_extract_lines(
|
||||
commits, files, opts.staged, opts.diff_from_common_commit
|
||||
)
|
||||
if opts.verbose >= 1:
|
||||
ignored_files = set(changed_lines)
|
||||
filter_by_extension(changed_lines, opts.extensions.lower().split(","))
|
||||
# The computed diff outputs absolute paths, so we must cd before accessing
|
||||
# those files.
|
||||
cd_to_toplevel()
|
||||
filter_symlinks(changed_lines)
|
||||
filter_ignored_files(changed_lines, binary=opts.binary)
|
||||
if opts.verbose >= 1:
|
||||
ignored_files.difference_update(changed_lines)
|
||||
if ignored_files:
|
||||
print(
|
||||
"Ignoring the following files (wrong extension, symlink, or "
|
||||
"ignored by clang-format):"
|
||||
)
|
||||
for filename in ignored_files:
|
||||
print(" %s" % filename)
|
||||
if changed_lines:
|
||||
print("Running clang-format on the following files:")
|
||||
for filename in changed_lines:
|
||||
print(" %s" % filename)
|
||||
|
||||
if not changed_lines:
|
||||
if opts.verbose >= 0:
|
||||
print("no modified files to format")
|
||||
return 0
|
||||
|
||||
if len(commits) > 1:
|
||||
old_tree = commits[1]
|
||||
revision = old_tree
|
||||
elif opts.staged:
|
||||
old_tree = create_tree_from_index(changed_lines)
|
||||
revision = ""
|
||||
else:
|
||||
old_tree = create_tree_from_workdir(changed_lines)
|
||||
revision = None
|
||||
new_tree = run_clang_format_and_save_to_tree(
|
||||
changed_lines, revision, binary=opts.binary, style=opts.style
|
||||
)
|
||||
if opts.verbose >= 1:
|
||||
print("old tree: %s" % old_tree)
|
||||
print("new tree: %s" % new_tree)
|
||||
|
||||
if old_tree == new_tree:
|
||||
if opts.verbose >= 0:
|
||||
print("clang-format did not modify any files")
|
||||
return 0
|
||||
|
||||
if opts.diff:
|
||||
return print_diff(old_tree, new_tree)
|
||||
if opts.diffstat:
|
||||
return print_diffstat(old_tree, new_tree)
|
||||
|
||||
changed_files = apply_changes(
|
||||
old_tree, new_tree, force=opts.force, patch_mode=opts.patch
|
||||
)
|
||||
if (opts.verbose >= 0 and not opts.patch) or opts.verbose >= 1:
|
||||
print("changed files:")
|
||||
for filename in changed_files:
|
||||
print(" %s" % filename)
|
||||
|
||||
return 1
|
||||
|
||||
|
||||
def load_git_config(non_string_options=None):
|
||||
"""Return the git configuration as a dictionary.
|
||||
|
||||
All options are assumed to be strings unless in `non_string_options`, in
|
||||
which is a dictionary mapping option name (in lower case) to either "--bool"
|
||||
or "--int"."""
|
||||
if non_string_options is None:
|
||||
non_string_options = {}
|
||||
out = {}
|
||||
for entry in run("git", "config", "--list", "--null").split("\0"):
|
||||
if entry:
|
||||
if "\n" in entry:
|
||||
name, value = entry.split("\n", 1)
|
||||
else:
|
||||
# A setting with no '=' ('\n' with --null) is implicitly 'true'
|
||||
name = entry
|
||||
value = "true"
|
||||
if name in non_string_options:
|
||||
value = run("git", "config", non_string_options[name], name)
|
||||
out[name] = value
|
||||
return out
|
||||
|
||||
|
||||
def interpret_args(args, dash_dash, default_commit):
|
||||
"""Interpret `args` as "[commits] [--] [files]" and return (commits, files).
|
||||
|
||||
It is assumed that "--" and everything that follows has been removed from
|
||||
args and placed in `dash_dash`.
|
||||
|
||||
If "--" is present (i.e., `dash_dash` is non-empty), the arguments to its
|
||||
left (if present) are taken as commits. Otherwise, the arguments are
|
||||
checked from left to right if they are commits or files. If commits are not
|
||||
given, a list with `default_commit` is used."""
|
||||
if dash_dash:
|
||||
if len(args) == 0:
|
||||
commits = [default_commit]
|
||||
else:
|
||||
commits = args
|
||||
for commit in commits:
|
||||
object_type = get_object_type(commit)
|
||||
if object_type not in ("commit", "tag"):
|
||||
if object_type is None:
|
||||
die("'%s' is not a commit" % commit)
|
||||
else:
|
||||
die(
|
||||
"'%s' is a %s, but a commit was expected"
|
||||
% (commit, object_type)
|
||||
)
|
||||
files = dash_dash[1:]
|
||||
elif args:
|
||||
commits = []
|
||||
while args:
|
||||
if not disambiguate_revision(args[0]):
|
||||
break
|
||||
commits.append(args.pop(0))
|
||||
if not commits:
|
||||
commits = [default_commit]
|
||||
files = args
|
||||
else:
|
||||
commits = [default_commit]
|
||||
files = []
|
||||
return commits, files
|
||||
|
||||
|
||||
def disambiguate_revision(value):
|
||||
"""Returns True if `value` is a revision, False if it is a file, or dies."""
|
||||
# If `value` is ambiguous (neither a commit nor a file), the following
|
||||
# command will die with an appropriate error message.
|
||||
run("git", "rev-parse", value, verbose=False)
|
||||
object_type = get_object_type(value)
|
||||
if object_type is None:
|
||||
return False
|
||||
if object_type in ("commit", "tag"):
|
||||
return True
|
||||
die("`%s` is a %s, but a commit or filename was expected" % (value, object_type))
|
||||
|
||||
|
||||
def get_object_type(value):
|
||||
"""Returns a string description of an object's type, or None if it is not
|
||||
a valid git object."""
|
||||
cmd = ["git", "cat-file", "-t", value]
|
||||
p = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
|
||||
stdout, stderr = p.communicate()
|
||||
if p.returncode != 0:
|
||||
return None
|
||||
return convert_string(stdout.strip())
|
||||
|
||||
|
||||
def compute_diff_and_extract_lines(commits, files, staged, diff_common_commit):
|
||||
"""Calls compute_diff() followed by extract_lines()."""
|
||||
diff_process = compute_diff(commits, files, staged, diff_common_commit)
|
||||
changed_lines = extract_lines(diff_process.stdout)
|
||||
diff_process.stdout.close()
|
||||
diff_process.wait()
|
||||
if diff_process.returncode != 0:
|
||||
# Assume error was already printed to stderr.
|
||||
sys.exit(2)
|
||||
return changed_lines
|
||||
|
||||
|
||||
def compute_diff(commits, files, staged, diff_common_commit):
|
||||
"""Return a subprocess object producing the diff from `commits`.
|
||||
|
||||
The return value's `stdin` file object will produce a patch with the
|
||||
differences between the working directory (or stage if --staged is used) and
|
||||
the first commit if a single one was specified, or the difference between
|
||||
both specified commits, filtered on `files` (if non-empty).
|
||||
Zero context lines are used in the patch."""
|
||||
git_tool = "diff-index"
|
||||
extra_args = []
|
||||
if len(commits) == 2:
|
||||
git_tool = "diff-tree"
|
||||
if diff_common_commit:
|
||||
commits = [f"{commits[0]}...{commits[1]}"]
|
||||
elif staged:
|
||||
extra_args += ["--cached"]
|
||||
|
||||
cmd = ["git", git_tool, "-p", "-U0"] + extra_args + commits + ["--"]
|
||||
cmd.extend(files)
|
||||
p = subprocess.Popen(cmd, stdin=subprocess.PIPE, stdout=subprocess.PIPE)
|
||||
p.stdin.close()
|
||||
return p
|
||||
|
||||
|
||||
def extract_lines(patch_file):
|
||||
"""Extract the changed lines in `patch_file`.
|
||||
|
||||
The return value is a dictionary mapping filename to a list of (start_line,
|
||||
line_count) pairs.
|
||||
|
||||
The input must have been produced with ``-U0``, meaning unidiff format with
|
||||
zero lines of context. The return value is a dict mapping filename to a
|
||||
list of line `Range`s."""
|
||||
matches = {}
|
||||
for line in patch_file:
|
||||
line = convert_string(line)
|
||||
match = re.search(r"^\+\+\+\ [^/]+/(.*)", line)
|
||||
if match:
|
||||
filename = match.group(1).rstrip("\r\n\t")
|
||||
match = re.search(r"^@@ -[0-9,]+ \+(\d+)(,(\d+))?", line)
|
||||
if match:
|
||||
start_line = int(match.group(1))
|
||||
line_count = 1
|
||||
if match.group(3):
|
||||
line_count = int(match.group(3))
|
||||
if line_count == 0:
|
||||
line_count = 1
|
||||
if start_line == 0:
|
||||
continue
|
||||
matches.setdefault(filename, []).append(Range(start_line, line_count))
|
||||
return matches
|
||||
|
||||
|
||||
def filter_by_extension(dictionary, allowed_extensions):
|
||||
"""Delete every key in `dictionary` that doesn't have an allowed extension.
|
||||
|
||||
`allowed_extensions` must be a collection of lowercase file extensions,
|
||||
excluding the period."""
|
||||
allowed_extensions = frozenset(allowed_extensions)
|
||||
for filename in list(dictionary.keys()):
|
||||
base_ext = filename.rsplit(".", 1)
|
||||
if len(base_ext) == 1 and "" in allowed_extensions:
|
||||
continue
|
||||
if len(base_ext) == 1 or base_ext[1].lower() not in allowed_extensions:
|
||||
del dictionary[filename]
|
||||
|
||||
|
||||
def filter_symlinks(dictionary):
|
||||
"""Delete every key in `dictionary` that is a symlink."""
|
||||
for filename in list(dictionary.keys()):
|
||||
if os.path.islink(filename):
|
||||
del dictionary[filename]
|
||||
|
||||
|
||||
def filter_ignored_files(dictionary, binary):
|
||||
"""Delete every key in `dictionary` that is ignored by clang-format."""
|
||||
ignored_files = run(binary, "-list-ignored", *dictionary.keys())
|
||||
if not ignored_files:
|
||||
return
|
||||
ignored_files = ignored_files.split("\n")
|
||||
for filename in ignored_files:
|
||||
del dictionary[filename]
|
||||
|
||||
|
||||
def cd_to_toplevel():
|
||||
"""Change to the top level of the git repository."""
|
||||
toplevel = run("git", "rev-parse", "--show-toplevel")
|
||||
os.chdir(toplevel)
|
||||
|
||||
|
||||
def create_tree_from_workdir(filenames):
|
||||
"""Create a new git tree with the given files from the working directory.
|
||||
|
||||
Returns the object ID (SHA-1) of the created tree."""
|
||||
return create_tree(filenames, "--stdin")
|
||||
|
||||
|
||||
def create_tree_from_index(filenames):
|
||||
# Copy the environment, because the files have to be read from the original
|
||||
# index.
|
||||
env = os.environ.copy()
|
||||
|
||||
def index_contents_generator():
|
||||
for filename in filenames:
|
||||
git_ls_files_cmd = [
|
||||
"git",
|
||||
"ls-files",
|
||||
"--stage",
|
||||
"-z",
|
||||
"--",
|
||||
filename,
|
||||
]
|
||||
git_ls_files = subprocess.Popen(
|
||||
git_ls_files_cmd,
|
||||
env=env,
|
||||
stdin=subprocess.PIPE,
|
||||
stdout=subprocess.PIPE,
|
||||
)
|
||||
stdout = git_ls_files.communicate()[0]
|
||||
yield convert_string(stdout.split(b"\0")[0])
|
||||
|
||||
return create_tree(index_contents_generator(), "--index-info")
|
||||
|
||||
|
||||
def run_clang_format_and_save_to_tree(
|
||||
changed_lines, revision=None, binary="clang-format", style=None
|
||||
):
|
||||
"""Run clang-format on each file and save the result to a git tree.
|
||||
|
||||
Returns the object ID (SHA-1) of the created tree."""
|
||||
# Copy the environment when formatting the files in the index, because the
|
||||
# files have to be read from the original index.
|
||||
env = os.environ.copy() if revision == "" else None
|
||||
|
||||
def iteritems(container):
|
||||
try:
|
||||
return container.iteritems() # Python 2
|
||||
except AttributeError:
|
||||
return container.items() # Python 3
|
||||
|
||||
def index_info_generator():
|
||||
for filename, line_ranges in iteritems(changed_lines):
|
||||
if revision is not None:
|
||||
if len(revision) > 0:
|
||||
git_metadata_cmd = [
|
||||
"git",
|
||||
"ls-tree",
|
||||
"%s:%s" % (revision, os.path.dirname(filename)),
|
||||
os.path.basename(filename),
|
||||
]
|
||||
else:
|
||||
git_metadata_cmd = [
|
||||
"git",
|
||||
"ls-files",
|
||||
"--stage",
|
||||
"--",
|
||||
filename,
|
||||
]
|
||||
git_metadata = subprocess.Popen(
|
||||
git_metadata_cmd,
|
||||
env=env,
|
||||
stdin=subprocess.PIPE,
|
||||
stdout=subprocess.PIPE,
|
||||
)
|
||||
stdout = git_metadata.communicate()[0]
|
||||
mode = oct(int(stdout.split()[0], 8))
|
||||
else:
|
||||
mode = oct(os.stat(filename).st_mode)
|
||||
# Adjust python3 octal format so that it matches what git expects
|
||||
if mode.startswith("0o"):
|
||||
mode = "0" + mode[2:]
|
||||
blob_id = clang_format_to_blob(
|
||||
filename,
|
||||
line_ranges,
|
||||
revision=revision,
|
||||
binary=binary,
|
||||
style=style,
|
||||
env=env,
|
||||
)
|
||||
yield "%s %s\t%s" % (mode, blob_id, filename)
|
||||
|
||||
return create_tree(index_info_generator(), "--index-info")
|
||||
|
||||
|
||||
def create_tree(input_lines, mode):
|
||||
"""Create a tree object from the given input.
|
||||
|
||||
If mode is '--stdin', it must be a list of filenames. If mode is
|
||||
'--index-info' is must be a list of values suitable for "git update-index
|
||||
--index-info", such as "<mode> <SP> <sha1> <TAB> <filename>". Any other
|
||||
mode is invalid."""
|
||||
assert mode in ("--stdin", "--index-info")
|
||||
cmd = ["git", "update-index", "--add", "-z", mode]
|
||||
with temporary_index_file():
|
||||
p = subprocess.Popen(cmd, stdin=subprocess.PIPE)
|
||||
for line in input_lines:
|
||||
p.stdin.write(to_bytes("%s\0" % line))
|
||||
p.stdin.close()
|
||||
if p.wait() != 0:
|
||||
die("`%s` failed" % " ".join(cmd))
|
||||
tree_id = run("git", "write-tree")
|
||||
return tree_id
|
||||
|
||||
|
||||
def clang_format_to_blob(
|
||||
filename,
|
||||
line_ranges,
|
||||
revision=None,
|
||||
binary="clang-format",
|
||||
style=None,
|
||||
env=None,
|
||||
):
|
||||
"""Run clang-format on the given file and save the result to a git blob.
|
||||
|
||||
Runs on the file in `revision` if not None, or on the file in the working
|
||||
directory if `revision` is None. Revision can be set to an empty string to
|
||||
run clang-format on the file in the index.
|
||||
|
||||
Returns the object ID (SHA-1) of the created blob."""
|
||||
clang_format_cmd = [binary]
|
||||
if style:
|
||||
clang_format_cmd.extend(["--style=" + style])
|
||||
clang_format_cmd.extend(
|
||||
[
|
||||
"--lines=%s:%s" % (start_line, start_line + line_count - 1)
|
||||
for start_line, line_count in line_ranges
|
||||
]
|
||||
)
|
||||
if revision is not None:
|
||||
clang_format_cmd.extend(["--assume-filename=" + filename])
|
||||
git_show_cmd = [
|
||||
"git",
|
||||
"cat-file",
|
||||
"blob",
|
||||
"%s:%s" % (revision, filename),
|
||||
]
|
||||
git_show = subprocess.Popen(
|
||||
git_show_cmd, env=env, stdin=subprocess.PIPE, stdout=subprocess.PIPE
|
||||
)
|
||||
git_show.stdin.close()
|
||||
clang_format_stdin = git_show.stdout
|
||||
else:
|
||||
clang_format_cmd.extend([filename])
|
||||
git_show = None
|
||||
clang_format_stdin = subprocess.PIPE
|
||||
try:
|
||||
clang_format = subprocess.Popen(
|
||||
clang_format_cmd, stdin=clang_format_stdin, stdout=subprocess.PIPE
|
||||
)
|
||||
if clang_format_stdin == subprocess.PIPE:
|
||||
clang_format_stdin = clang_format.stdin
|
||||
except OSError as e:
|
||||
if e.errno == errno.ENOENT:
|
||||
die('cannot find executable "%s"' % binary)
|
||||
else:
|
||||
raise
|
||||
clang_format_stdin.close()
|
||||
hash_object_cmd = [
|
||||
"git",
|
||||
"hash-object",
|
||||
"-w",
|
||||
"--path=" + filename,
|
||||
"--stdin",
|
||||
]
|
||||
hash_object = subprocess.Popen(
|
||||
hash_object_cmd, stdin=clang_format.stdout, stdout=subprocess.PIPE
|
||||
)
|
||||
clang_format.stdout.close()
|
||||
stdout = hash_object.communicate()[0]
|
||||
if hash_object.returncode != 0:
|
||||
die("`%s` failed" % " ".join(hash_object_cmd))
|
||||
if clang_format.wait() != 0:
|
||||
die("`%s` failed" % " ".join(clang_format_cmd))
|
||||
if git_show and git_show.wait() != 0:
|
||||
die("`%s` failed" % " ".join(git_show_cmd))
|
||||
return convert_string(stdout).rstrip("\r\n")
|
||||
|
||||
|
||||
@contextlib.contextmanager
|
||||
def temporary_index_file(tree=None):
|
||||
"""Context manager for setting GIT_INDEX_FILE to a temporary file and
|
||||
deleting the file afterward."""
|
||||
index_path = create_temporary_index(tree)
|
||||
old_index_path = os.environ.get("GIT_INDEX_FILE")
|
||||
os.environ["GIT_INDEX_FILE"] = index_path
|
||||
try:
|
||||
yield
|
||||
finally:
|
||||
if old_index_path is None:
|
||||
del os.environ["GIT_INDEX_FILE"]
|
||||
else:
|
||||
os.environ["GIT_INDEX_FILE"] = old_index_path
|
||||
os.remove(index_path)
|
||||
|
||||
|
||||
def create_temporary_index(tree=None):
|
||||
"""Create a temporary index file and return the created file's path.
|
||||
|
||||
If `tree` is not None, use that as the tree to read in. Otherwise, an
|
||||
empty index is created."""
|
||||
gitdir = run("git", "rev-parse", "--git-dir")
|
||||
path = os.path.join(gitdir, temp_index_basename)
|
||||
if tree is None:
|
||||
tree = "--empty"
|
||||
run("git", "read-tree", "--index-output=" + path, tree)
|
||||
return path
|
||||
|
||||
|
||||
def print_diff(old_tree, new_tree):
|
||||
"""Print the diff between the two trees to stdout."""
|
||||
# We use the porcelain 'diff' and not plumbing 'diff-tree' because the
|
||||
# output is expected to be viewed by the user, and only the former does nice
|
||||
# things like color and pagination.
|
||||
#
|
||||
# We also only print modified files since `new_tree` only contains the files
|
||||
# that were modified, so unmodified files would show as deleted without the
|
||||
# filter.
|
||||
return subprocess.run(
|
||||
["git", "diff", "--diff-filter=M", "--exit-code", old_tree, new_tree]
|
||||
).returncode
|
||||
|
||||
|
||||
def print_diffstat(old_tree, new_tree):
|
||||
"""Print the diffstat between the two trees to stdout."""
|
||||
# We use the porcelain 'diff' and not plumbing 'diff-tree' because the
|
||||
# output is expected to be viewed by the user, and only the former does nice
|
||||
# things like color and pagination.
|
||||
#
|
||||
# We also only print modified files since `new_tree` only contains the files
|
||||
# that were modified, so unmodified files would show as deleted without the
|
||||
# filter.
|
||||
return subprocess.run(
|
||||
[
|
||||
"git",
|
||||
"diff",
|
||||
"--diff-filter=M",
|
||||
"--exit-code",
|
||||
"--stat",
|
||||
old_tree,
|
||||
new_tree,
|
||||
]
|
||||
).returncode
|
||||
|
||||
|
||||
def apply_changes(old_tree, new_tree, force=False, patch_mode=False):
|
||||
"""Apply the changes in `new_tree` to the working directory.
|
||||
|
||||
Bails if there are local changes in those files and not `force`. If
|
||||
`patch_mode`, runs `git checkout --patch` to select hunks interactively."""
|
||||
changed_files = (
|
||||
run(
|
||||
"git",
|
||||
"diff-tree",
|
||||
"--diff-filter=M",
|
||||
"-r",
|
||||
"-z",
|
||||
"--name-only",
|
||||
old_tree,
|
||||
new_tree,
|
||||
)
|
||||
.rstrip("\0")
|
||||
.split("\0")
|
||||
)
|
||||
if not force:
|
||||
unstaged_files = run("git", "diff-files", "--name-status", *changed_files)
|
||||
if unstaged_files:
|
||||
print(
|
||||
"The following files would be modified but have unstaged changes:",
|
||||
file=sys.stderr,
|
||||
)
|
||||
print(unstaged_files, file=sys.stderr)
|
||||
print("Please commit, stage, or stash them first.", file=sys.stderr)
|
||||
sys.exit(2)
|
||||
if patch_mode:
|
||||
# In patch mode, we could just as well create an index from the new tree
|
||||
# and checkout from that, but then the user will be presented with a
|
||||
# message saying "Discard ... from worktree". Instead, we use the old
|
||||
# tree as the index and checkout from new_tree, which gives the slightly
|
||||
# better message, "Apply ... to index and worktree". This is not quite
|
||||
# right, since it won't be applied to the user's index, but oh well.
|
||||
with temporary_index_file(old_tree):
|
||||
subprocess.run(["git", "checkout", "--patch", new_tree], check=True)
|
||||
index_tree = old_tree
|
||||
else:
|
||||
with temporary_index_file(new_tree):
|
||||
run("git", "checkout-index", "-f", "--", *changed_files)
|
||||
return changed_files
|
||||
|
||||
|
||||
def run(*args, **kwargs):
|
||||
stdin = kwargs.pop("stdin", "")
|
||||
verbose = kwargs.pop("verbose", True)
|
||||
strip = kwargs.pop("strip", True)
|
||||
for name in kwargs:
|
||||
raise TypeError("run() got an unexpected keyword argument '%s'" % name)
|
||||
p = subprocess.Popen(
|
||||
args,
|
||||
stdout=subprocess.PIPE,
|
||||
stderr=subprocess.PIPE,
|
||||
stdin=subprocess.PIPE,
|
||||
)
|
||||
stdout, stderr = p.communicate(input=stdin)
|
||||
|
||||
stdout = convert_string(stdout)
|
||||
stderr = convert_string(stderr)
|
||||
|
||||
if p.returncode == 0:
|
||||
if stderr:
|
||||
if verbose:
|
||||
print("`%s` printed to stderr:" % " ".join(args), file=sys.stderr)
|
||||
print(stderr.rstrip(), file=sys.stderr)
|
||||
if strip:
|
||||
stdout = stdout.rstrip("\r\n")
|
||||
return stdout
|
||||
if verbose:
|
||||
print("`%s` returned %s" % (" ".join(args), p.returncode), file=sys.stderr)
|
||||
if stderr:
|
||||
print(stderr.rstrip(), file=sys.stderr)
|
||||
sys.exit(2)
|
||||
|
||||
|
||||
def die(message):
|
||||
print("error:", message, file=sys.stderr)
|
||||
sys.exit(2)
|
||||
|
||||
|
||||
def to_bytes(str_input):
|
||||
# Encode to UTF-8 to get binary data.
|
||||
if isinstance(str_input, bytes):
|
||||
return str_input
|
||||
return str_input.encode("utf-8")
|
||||
|
||||
|
||||
def to_string(bytes_input):
|
||||
if isinstance(bytes_input, str):
|
||||
return bytes_input
|
||||
return bytes_input.encode("utf-8")
|
||||
|
||||
|
||||
def convert_string(bytes_input):
|
||||
try:
|
||||
return to_string(bytes_input.decode("utf-8"))
|
||||
except AttributeError: # 'str' object has no attribute 'decode'.
|
||||
return str(bytes_input)
|
||||
except UnicodeError:
|
||||
return str(bytes_input)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
sys.exit(main())
|
||||
216
frontend/src/common/prettier/plugins/clang/index.ts
Normal file
216
frontend/src/common/prettier/plugins/clang/index.ts
Normal file
@@ -0,0 +1,216 @@
|
||||
/**
|
||||
* Prettier Plugin for C/C++/C#/Java/Protobuf formatting using clang-format WebAssembly
|
||||
*
|
||||
* This plugin provides support for formatting multiple languages using the clang-format WASM implementation.
|
||||
* Supported languages:
|
||||
* - C / C++
|
||||
* - Objective-C / Objective-C++
|
||||
* - C#
|
||||
* - Java
|
||||
* - Protocol Buffer (Protobuf)
|
||||
*
|
||||
* It supports various file extensions and common clang-format styles.
|
||||
*/
|
||||
import type { Plugin, Parser, Printer } from 'prettier';
|
||||
|
||||
// Import the clang-format WASM module
|
||||
import clangFormatInit, { format } from './clang-format-vite.js';
|
||||
|
||||
const parserName = 'clang-format';
|
||||
|
||||
// Language configuration
|
||||
const languages = [
|
||||
{
|
||||
name: 'C',
|
||||
aliases: ['c'],
|
||||
parsers: ['c'],
|
||||
extensions: ['.c', '.h'],
|
||||
filenames: ['*.c', '*.h'],
|
||||
aceMode: 'c_cpp',
|
||||
tmScope: 'source.c',
|
||||
linguistLanguageId: 50,
|
||||
vscodeLanguageIds: ['c']
|
||||
},
|
||||
{
|
||||
name: 'C++',
|
||||
aliases: ['cpp', 'cxx', 'cc'],
|
||||
parsers: ['cpp'],
|
||||
extensions: ['.cpp', '.cxx', '.cc', '.hpp', '.hxx', '.hh', '.C', '.H'],
|
||||
filenames: ['*.cpp', '*.cxx', '*.cc', '*.hpp', '*.hxx', '*.hh', '*.C', '*.H'],
|
||||
aceMode: 'c_cpp',
|
||||
tmScope: 'source.cpp',
|
||||
linguistLanguageId: 43,
|
||||
vscodeLanguageIds: ['cpp']
|
||||
},
|
||||
{
|
||||
name: 'Objective-C',
|
||||
aliases: ['objc', 'objectivec'],
|
||||
parsers: ['objective-c'],
|
||||
extensions: ['.m'],
|
||||
filenames: ['*.m'],
|
||||
aceMode: 'objectivec',
|
||||
tmScope: 'source.objc',
|
||||
linguistLanguageId: 259,
|
||||
vscodeLanguageIds: ['objective-c']
|
||||
},
|
||||
{
|
||||
name: 'Objective-C++',
|
||||
aliases: ['objcpp', 'objectivecpp'],
|
||||
parsers: ['objective-cpp'],
|
||||
extensions: ['.mm'],
|
||||
filenames: ['*.mm'],
|
||||
aceMode: 'objectivec',
|
||||
tmScope: 'source.objcpp',
|
||||
linguistLanguageId: 260,
|
||||
vscodeLanguageIds: ['objective-cpp']
|
||||
},
|
||||
{
|
||||
name: 'C#',
|
||||
aliases: ['csharp', 'cs'],
|
||||
parsers: ['cs'],
|
||||
extensions: ['.cs'],
|
||||
filenames: ['*.cs'],
|
||||
aceMode: 'csharp',
|
||||
tmScope: 'source.cs',
|
||||
linguistLanguageId: 42,
|
||||
vscodeLanguageIds: ['csharp']
|
||||
},
|
||||
{
|
||||
name: 'Java',
|
||||
aliases: ['java'],
|
||||
parsers: ['java'],
|
||||
extensions: ['.java'],
|
||||
filenames: ['*.java'],
|
||||
aceMode: 'java',
|
||||
tmScope: 'source.java',
|
||||
linguistLanguageId: 181,
|
||||
vscodeLanguageIds: ['java']
|
||||
},
|
||||
{
|
||||
name: 'Protocol Buffer',
|
||||
aliases: ['protobuf', 'proto'],
|
||||
parsers: ['proto'],
|
||||
extensions: ['.proto'],
|
||||
filenames: ['*.proto'],
|
||||
aceMode: 'protobuf',
|
||||
tmScope: 'source.proto',
|
||||
linguistLanguageId: 297,
|
||||
vscodeLanguageIds: ['proto']
|
||||
}
|
||||
];
|
||||
|
||||
// Parser configuration
|
||||
const clangParser: Parser<string> = {
|
||||
astFormat: parserName,
|
||||
parse: (text: string) => text,
|
||||
locStart: () => 0,
|
||||
locEnd: (node: string) => node.length,
|
||||
};
|
||||
|
||||
// Lazy initialize clang-format WASM module
|
||||
let initPromise: Promise<void> | null = null;
|
||||
let isInitialized = false;
|
||||
|
||||
function initClangFormat(): Promise<void> {
|
||||
if (isInitialized) {
|
||||
return Promise.resolve();
|
||||
}
|
||||
|
||||
if (!initPromise) {
|
||||
initPromise = (async () => {
|
||||
try {
|
||||
await clangFormatInit();
|
||||
isInitialized = true;
|
||||
} catch (error) {
|
||||
console.warn('Failed to initialize clang-format WASM module:', error);
|
||||
initPromise = null;
|
||||
throw error;
|
||||
}
|
||||
})();
|
||||
}
|
||||
|
||||
return initPromise;
|
||||
}
|
||||
|
||||
// Printer configuration
|
||||
const clangPrinter: Printer<string> = {
|
||||
// @ts-expect-error -- Support async printer like shell plugin
|
||||
async print(path, options) {
|
||||
try {
|
||||
// Wait for initialization to complete
|
||||
await initClangFormat();
|
||||
|
||||
const text = (path as any).getValue ? (path as any).getValue() : path.node;
|
||||
const style = getClangStyle(options);
|
||||
|
||||
// Format using clang-format (synchronous call)
|
||||
const formatted = format(text, options.filename, style);
|
||||
|
||||
return formatted.trim();
|
||||
} catch (error) {
|
||||
console.warn('clang-format failed:', error);
|
||||
// Return original text if formatting fails
|
||||
return (path as any).getValue ? (path as any).getValue() : path.node;
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
|
||||
// Helper function to determine clang-format style
|
||||
function getClangStyle(options: any): string {
|
||||
// You can extend this to support more options
|
||||
const style = options.clangStyle || 'LLVM';
|
||||
|
||||
// Support common styles
|
||||
const validStyles = ['LLVM', 'Google', 'Chromium', 'Mozilla', 'WebKit', 'Microsoft', 'GNU'];
|
||||
if (validStyles.includes(style)) {
|
||||
return style;
|
||||
}
|
||||
|
||||
// Default to LLVM style
|
||||
return 'LLVM';
|
||||
}
|
||||
|
||||
// Plugin options
|
||||
const options = {
|
||||
clangStyle: {
|
||||
since: '0.0.1',
|
||||
category: 'Format' as const,
|
||||
type: 'choice' as const,
|
||||
default: 'LLVM',
|
||||
description: 'The clang-format style to use',
|
||||
choices: [
|
||||
{ value: 'LLVM', description: 'LLVM coding standards' },
|
||||
{ value: 'Google', description: "Google's C++ style guide" },
|
||||
{ value: 'Chromium', description: "Chromium's style guide" },
|
||||
{ value: 'Mozilla', description: "Mozilla's style guide" },
|
||||
{ value: 'WebKit', description: "WebKit's style guide" },
|
||||
{ value: 'Microsoft', description: "Microsoft's style guide" },
|
||||
{ value: 'GNU', description: 'GNU coding standards' }
|
||||
]
|
||||
},
|
||||
filename: {
|
||||
// since: '0.1.0',
|
||||
category: 'Config',
|
||||
type: 'string',
|
||||
default: undefined,
|
||||
description: 'Custom filename to use for web_fmt processing (affects language detection)',
|
||||
}
|
||||
};
|
||||
|
||||
// Plugin object
|
||||
const clangPlugin: Plugin = {
|
||||
languages,
|
||||
parsers: {
|
||||
[parserName]: clangParser,
|
||||
},
|
||||
printers: {
|
||||
[parserName]: clangPrinter,
|
||||
},
|
||||
...options,
|
||||
};
|
||||
|
||||
export default clangPlugin;
|
||||
export { languages };
|
||||
export const parsers = clangPlugin.parsers;
|
||||
export const printers = clangPlugin.printers;
|
||||
105
frontend/src/common/prettier/plugins/clang/src/CMakeLists.txt
Normal file
105
frontend/src/common/prettier/plugins/clang/src/CMakeLists.txt
Normal file
@@ -0,0 +1,105 @@
|
||||
cmake_minimum_required(VERSION 3.20)
|
||||
|
||||
project(clang-format-wasm)
|
||||
|
||||
set(CMAKE_CXX_STANDARD 17)
|
||||
set(CMAKE_CXX_STANDARD_REQUIRED ON)
|
||||
|
||||
# Set Emscripten flags for WASM
|
||||
if(EMSCRIPTEN)
|
||||
set(CMAKE_EXECUTABLE_SUFFIX ".js")
|
||||
|
||||
# Common Emscripten flags
|
||||
set(EMSCRIPTEN_FLAGS
|
||||
-O3
|
||||
-sWASM=1
|
||||
-sEXPORTED_RUNTIME_METHODS=['ccall','cwrap']
|
||||
-sALLOW_MEMORY_GROWTH=1
|
||||
-sMODULARIZE=1
|
||||
-sEXPORT_NAME='Module'
|
||||
-sENVIRONMENT=web,webview,worker
|
||||
-sUSE_ES6_IMPORT_META=0
|
||||
--no-entry
|
||||
)
|
||||
|
||||
# Library-specific flags
|
||||
set(LIB_EMSCRIPTEN_FLAGS
|
||||
${EMSCRIPTEN_FLAGS}
|
||||
-sEXPORTED_FUNCTIONS=['_malloc','_free']
|
||||
--bind
|
||||
)
|
||||
|
||||
# CLI-specific flags
|
||||
set(CLI_EMSCRIPTEN_FLAGS
|
||||
${EMSCRIPTEN_FLAGS}
|
||||
-sEXPORTED_FUNCTIONS=['_main']
|
||||
-sINVOKE_RUN=0
|
||||
-sNODERAWFS=1
|
||||
)
|
||||
endif()
|
||||
|
||||
# Find LLVM
|
||||
find_package(LLVM REQUIRED CONFIG)
|
||||
message(STATUS "Found LLVM ${LLVM_PACKAGE_VERSION}")
|
||||
message(STATUS "Using LLVMConfig.cmake in: ${LLVM_DIR}")
|
||||
|
||||
# Include LLVM headers
|
||||
include_directories(${LLVM_INCLUDE_DIRS})
|
||||
add_definitions(${LLVM_DEFINITIONS})
|
||||
|
||||
# Find Clang
|
||||
find_package(Clang REQUIRED CONFIG)
|
||||
|
||||
# Get LLVM components
|
||||
llvm_map_components_to_libnames(llvm_libs support core)
|
||||
|
||||
# Define source files
|
||||
set(LIB_SOURCES
|
||||
lib.cc
|
||||
lib.h
|
||||
binding.cc
|
||||
)
|
||||
|
||||
set(CLI_SOURCES
|
||||
cli.cc
|
||||
)
|
||||
|
||||
# Create library target
|
||||
add_executable(clang-format-wasm ${LIB_SOURCES})
|
||||
|
||||
# Link against Clang and LLVM libraries
|
||||
target_link_libraries(clang-format-wasm
|
||||
clangFormat
|
||||
clangToolingCore
|
||||
clangBasic
|
||||
clangRewrite
|
||||
${llvm_libs}
|
||||
)
|
||||
|
||||
# Create CLI target
|
||||
add_executable(clang-format-cli ${CLI_SOURCES})
|
||||
|
||||
target_link_libraries(clang-format-cli
|
||||
clangFormat
|
||||
clangToolingCore
|
||||
clangBasic
|
||||
clangRewrite
|
||||
${llvm_libs}
|
||||
)
|
||||
|
||||
# Set Emscripten flags
|
||||
if(EMSCRIPTEN)
|
||||
# Configure library target
|
||||
set_target_properties(clang-format-wasm PROPERTIES
|
||||
COMPILE_FLAGS "${LIB_EMSCRIPTEN_FLAGS}"
|
||||
LINK_FLAGS "${LIB_EMSCRIPTEN_FLAGS}"
|
||||
OUTPUT_NAME "clang-format-esm"
|
||||
)
|
||||
|
||||
# Configure CLI target
|
||||
set_target_properties(clang-format-cli PROPERTIES
|
||||
COMPILE_FLAGS "${CLI_EMSCRIPTEN_FLAGS}"
|
||||
LINK_FLAGS "${CLI_EMSCRIPTEN_FLAGS}"
|
||||
OUTPUT_NAME "clang-format-cli"
|
||||
)
|
||||
endif()
|
||||
@@ -0,0 +1,117 @@
|
||||
#include "CustomFileSystem.h"
|
||||
#include "llvm/ADT/StringExtras.h"
|
||||
#include "llvm/Support/Path.h"
|
||||
#include <emscripten.h>
|
||||
#include <iostream>
|
||||
#include <string>
|
||||
#include <system_error>
|
||||
|
||||
using namespace llvm;
|
||||
using namespace llvm::vfs;
|
||||
|
||||
namespace {
|
||||
|
||||
bool isRunningOnWindows() {
|
||||
return EM_ASM_INT({return process.platform == 'win32' ? 1 : 0}) == 1;
|
||||
}
|
||||
|
||||
std::error_code current_path(SmallVectorImpl<char> &result) {
|
||||
result.clear();
|
||||
|
||||
const char *pwd = ::getenv("PWD");
|
||||
result.append(pwd, pwd + strlen(pwd));
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
namespace llvm {
|
||||
namespace vfs {
|
||||
|
||||
sys::path::Style getPathStyle() {
|
||||
static sys::path::Style cachedStyle = sys::path::Style::native;
|
||||
|
||||
if (cachedStyle == sys::path::Style::native) {
|
||||
cachedStyle = isRunningOnWindows() ? sys::path::Style::windows
|
||||
: sys::path::Style::posix;
|
||||
}
|
||||
|
||||
return cachedStyle;
|
||||
}
|
||||
|
||||
void make_absolute(const Twine ¤t_directory,
|
||||
SmallVectorImpl<char> &path) {
|
||||
StringRef p(path.data(), path.size());
|
||||
|
||||
auto pathStyle = getPathStyle();
|
||||
|
||||
bool rootDirectory = sys::path::has_root_directory(p, pathStyle);
|
||||
bool rootName = sys::path::has_root_name(p, pathStyle);
|
||||
|
||||
// Already absolute.
|
||||
if ((rootName || is_style_posix(pathStyle)) && rootDirectory)
|
||||
return;
|
||||
|
||||
// All of the following conditions will need the current directory.
|
||||
SmallString<128> current_dir;
|
||||
current_directory.toVector(current_dir);
|
||||
|
||||
// Relative path. Prepend the current directory.
|
||||
if (!rootName && !rootDirectory) {
|
||||
// Append path to the current directory.
|
||||
sys::path::append(current_dir, pathStyle, p);
|
||||
// Set path to the result.
|
||||
path.swap(current_dir);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!rootName && rootDirectory) {
|
||||
StringRef cdrn = sys::path::root_name(current_dir, pathStyle);
|
||||
SmallString<128> curDirRootName(cdrn.begin(), cdrn.end());
|
||||
sys::path::append(curDirRootName, pathStyle, p);
|
||||
// Set path to the result.
|
||||
path.swap(curDirRootName);
|
||||
return;
|
||||
}
|
||||
|
||||
if (rootName && !rootDirectory) {
|
||||
StringRef pRootName = sys::path::root_name(p, pathStyle);
|
||||
StringRef bRootDirectory =
|
||||
sys::path::root_directory(current_dir, pathStyle);
|
||||
StringRef bRelativePath = sys::path::relative_path(current_dir, pathStyle);
|
||||
StringRef pRelativePath = sys::path::relative_path(p, pathStyle);
|
||||
|
||||
SmallString<128> res;
|
||||
sys::path::append(res, pathStyle, pRootName, bRootDirectory, bRelativePath,
|
||||
pRelativePath);
|
||||
path.swap(res);
|
||||
return;
|
||||
}
|
||||
|
||||
llvm_unreachable("All rootName and rootDirectory combinations should have "
|
||||
"occurred above!");
|
||||
}
|
||||
|
||||
std::error_code make_absolute(SmallVectorImpl<char> &path) {
|
||||
if (sys::path::is_absolute(path, getPathStyle()))
|
||||
return {};
|
||||
|
||||
SmallString<128> current_dir;
|
||||
if (std::error_code ec = current_path(current_dir))
|
||||
return ec;
|
||||
|
||||
make_absolute(current_dir, path);
|
||||
return {};
|
||||
}
|
||||
|
||||
CustomFileSystem::CustomFileSystem(IntrusiveRefCntPtr<FileSystem> FS)
|
||||
: ProxyFileSystem(std::move(FS)) {}
|
||||
|
||||
std::error_code
|
||||
CustomFileSystem::makeAbsolute(SmallVectorImpl<char> &Path) const {
|
||||
return make_absolute(Path);
|
||||
}
|
||||
|
||||
} // namespace vfs
|
||||
} // namespace llvm
|
||||
@@ -0,0 +1,27 @@
|
||||
#ifndef CUSTOM_FILE_SYSTEM_H
|
||||
#define CUSTOM_FILE_SYSTEM_H
|
||||
|
||||
#include "llvm/ADT/IntrusiveRefCntPtr.h"
|
||||
#include "llvm/ADT/SmallString.h"
|
||||
#include "llvm/ADT/SmallVector.h"
|
||||
#include "llvm/Support/ErrorOr.h"
|
||||
#include "llvm/Support/Path.h"
|
||||
#include "llvm/Support/VirtualFileSystem.h"
|
||||
|
||||
namespace llvm {
|
||||
namespace vfs {
|
||||
|
||||
sys::path::Style getPathStyle();
|
||||
std::error_code make_absolute(SmallVectorImpl<char> &path);
|
||||
|
||||
class CustomFileSystem : public ProxyFileSystem {
|
||||
public:
|
||||
CustomFileSystem(IntrusiveRefCntPtr<FileSystem> FS);
|
||||
|
||||
std::error_code makeAbsolute(SmallVectorImpl<char> &Path) const override;
|
||||
};
|
||||
|
||||
} // namespace vfs
|
||||
} // namespace llvm
|
||||
|
||||
#endif // CUSTOM_FILE_SYSTEM_H
|
||||
100
frontend/src/common/prettier/plugins/clang/src/README.md
Normal file
100
frontend/src/common/prettier/plugins/clang/src/README.md
Normal file
@@ -0,0 +1,100 @@
|
||||
# Clang Format WASM Plugin
|
||||
|
||||
这是一个基于 clang-format WebAssembly 的 Prettier 插件,支持格式化 C/C++/C#/Java/Protobuf 代码。
|
||||
|
||||
## 目录结构
|
||||
|
||||
```
|
||||
clang/
|
||||
├── src/ # 源码目录
|
||||
│ ├── scripts/ # 构建和工具脚本
|
||||
│ │ ├── build.sh # 主构建脚本
|
||||
│ │ ├── gen_patch.sh # 补丁生成脚本
|
||||
│ │ └── cli.patch # CLI 修改补丁
|
||||
│ ├── *.cc # C++ 源文件
|
||||
│ ├── *.h # C++ 头文件
|
||||
│ ├── CMakeLists.txt # CMake 构建配置
|
||||
│ ├── package.json # NPM 包配置
|
||||
│ ├── clang-format.d.ts # TypeScript 类型定义
|
||||
│ ├── template.js # JavaScript 模板
|
||||
│ └── clang-format-diff.py # Python 差异工具
|
||||
├── *.js # 编译后的 JavaScript 文件
|
||||
├── *.wasm # 编译后的 WebAssembly 文件
|
||||
├── *.cjs # CommonJS 格式的 CLI 工具
|
||||
├── git-clang-format # Git 集成工具
|
||||
└── index.ts # 插件入口文件
|
||||
```
|
||||
|
||||
## 构建说明
|
||||
|
||||
### 前提条件
|
||||
|
||||
- Install LLVM and Clang (version 18 or later)
|
||||
- Install CMake (version 3.27 or later)
|
||||
- Install Ninja (version 1.11 or later)
|
||||
|
||||
### 构建步骤
|
||||
|
||||
1. Clone this repository
|
||||
|
||||
2. 进入源码目录:
|
||||
```bash
|
||||
cd src
|
||||
```
|
||||
|
||||
3. 运行构建脚本:
|
||||
```bash
|
||||
./scripts/build.sh
|
||||
```
|
||||
|
||||
构建脚本会:
|
||||
- 创建 `build` 目录并编译源码
|
||||
- 将编译结果复制到上级目录(插件目录)
|
||||
- 生成 WebAssembly 文件和 JavaScript 绑定
|
||||
- 复制必要的工具和类型定义文件
|
||||
|
||||
### 输出文件
|
||||
|
||||
构建完成后,插件目录下会包含:
|
||||
- `clang-format.wasm` - WebAssembly 库文件
|
||||
- `clang-format.js` - JavaScript 绑定文件
|
||||
- `clang-format-cli.cjs` - CLI 工具
|
||||
- `clang-format-cli.wasm` - CLI WebAssembly 文件
|
||||
- `git-clang-format` - Git 集成工具
|
||||
- `clang-format-diff.py` - 差异工具
|
||||
|
||||
## 开发说明
|
||||
|
||||
### 修改源码
|
||||
|
||||
- C++ 源文件位于 `src/` 目录下
|
||||
- 修改后运行 `./scripts/build.sh` 重新构建
|
||||
- 类型定义文件 `src/clang-format.d.ts` 需要与实际 API 保持同步
|
||||
|
||||
### 生成补丁
|
||||
|
||||
如果修改了 CLI 相关代码,可以使用:
|
||||
```bash
|
||||
./scripts/gen_patch.sh
|
||||
```
|
||||
|
||||
生成补丁文件 `scripts/cli.patch`。
|
||||
|
||||
## 使用说明
|
||||
|
||||
插件会自动加载编译后的 WebAssembly 文件,支持以下语言:
|
||||
- C/C++
|
||||
- Objective-C/C++
|
||||
- C#
|
||||
- Java
|
||||
- Protocol Buffer
|
||||
|
||||
支持的 clang-format 样式:
|
||||
- LLVM
|
||||
- Google
|
||||
- Chromium
|
||||
- Mozilla
|
||||
- WebKit
|
||||
- Microsoft
|
||||
- GNU
|
||||
- 自定义样式
|
||||
26
frontend/src/common/prettier/plugins/clang/src/binding.cc
Normal file
26
frontend/src/common/prettier/plugins/clang/src/binding.cc
Normal file
@@ -0,0 +1,26 @@
|
||||
#include "lib.h"
|
||||
#include <emscripten/bind.h>
|
||||
|
||||
using namespace emscripten;
|
||||
|
||||
EMSCRIPTEN_BINDINGS(my_module) {
|
||||
register_vector<unsigned>("RangeList");
|
||||
|
||||
value_object<Result>("Result")
|
||||
.field("error", &Result::error)
|
||||
.field("content", &Result::content);
|
||||
|
||||
function<std::string>("version", &version);
|
||||
function<Result, const std::string, const std::string, const std::string>(
|
||||
"format", &format);
|
||||
function<Result, const std::string, const std::string, const std::string,
|
||||
const std::vector<unsigned>>("format_byte", &format_byte);
|
||||
function<Result, const std::string, const std::string, const std::string,
|
||||
const std::vector<unsigned>>("format_line", &format_line);
|
||||
function<void, const std::string>("set_fallback_style", &set_fallback_style);
|
||||
function<void, bool>("set_sort_includes", &set_sort_includes);
|
||||
function<Result, const std::string, const std::string, const std::string>(
|
||||
"dump_config", &dump_config);
|
||||
}
|
||||
|
||||
int main(void) {}
|
||||
@@ -0,0 +1,197 @@
|
||||
#!/usr/bin/env python3
|
||||
#
|
||||
# ===- clang-format-diff.py - ClangFormat Diff Reformatter ----*- python -*--===#
|
||||
#
|
||||
# Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
# See https://llvm.org/LICENSE.txt for license information.
|
||||
# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
#
|
||||
# ===------------------------------------------------------------------------===#
|
||||
|
||||
"""
|
||||
This script reads input from a unified diff and reformats all the changed
|
||||
lines. This is useful to reformat all the lines touched by a specific patch.
|
||||
Example usage for git/svn users:
|
||||
|
||||
git diff -U0 --no-color --relative HEAD^ | {clang_format_diff} -p1 -i
|
||||
svn diff --diff-cmd=diff -x-U0 | {clang_format_diff} -i
|
||||
|
||||
It should be noted that the filename contained in the diff is used unmodified
|
||||
to determine the source file to update. Users calling this script directly
|
||||
should be careful to ensure that the path in the diff is correct relative to the
|
||||
current working directory.
|
||||
"""
|
||||
from __future__ import absolute_import, division, print_function
|
||||
|
||||
import argparse
|
||||
import difflib
|
||||
import re
|
||||
import subprocess
|
||||
import sys
|
||||
|
||||
if sys.version_info.major >= 3:
|
||||
from io import StringIO
|
||||
else:
|
||||
from io import BytesIO as StringIO
|
||||
|
||||
|
||||
def main():
|
||||
parser = argparse.ArgumentParser(
|
||||
description=__doc__.format(clang_format_diff="%(prog)s"),
|
||||
formatter_class=argparse.RawDescriptionHelpFormatter,
|
||||
)
|
||||
parser.add_argument(
|
||||
"-i",
|
||||
action="store_true",
|
||||
default=False,
|
||||
help="apply edits to files instead of displaying a diff",
|
||||
)
|
||||
parser.add_argument(
|
||||
"-p",
|
||||
metavar="NUM",
|
||||
default=0,
|
||||
help="strip the smallest prefix containing P slashes",
|
||||
)
|
||||
parser.add_argument(
|
||||
"-regex",
|
||||
metavar="PATTERN",
|
||||
default=None,
|
||||
help="custom pattern selecting file paths to reformat "
|
||||
"(case sensitive, overrides -iregex)",
|
||||
)
|
||||
parser.add_argument(
|
||||
"-iregex",
|
||||
metavar="PATTERN",
|
||||
default=r".*\.(?:cpp|cc|c\+\+|cxx|cppm|ccm|cxxm|c\+\+m|c|cl|h|hh|hpp"
|
||||
r"|hxx|m|mm|inc|js|ts|proto|protodevel|java|cs|json|ipynb|s?vh?)",
|
||||
help="custom pattern selecting file paths to reformat "
|
||||
"(case insensitive, overridden by -regex)",
|
||||
)
|
||||
parser.add_argument(
|
||||
"-sort-includes",
|
||||
action="store_true",
|
||||
default=False,
|
||||
help="let clang-format sort include blocks",
|
||||
)
|
||||
parser.add_argument(
|
||||
"-v",
|
||||
"--verbose",
|
||||
action="store_true",
|
||||
help="be more verbose, ineffective without -i",
|
||||
)
|
||||
parser.add_argument(
|
||||
"-style",
|
||||
help="formatting style to apply (LLVM, GNU, Google, Chromium, "
|
||||
"Microsoft, Mozilla, WebKit)",
|
||||
)
|
||||
parser.add_argument(
|
||||
"-fallback-style",
|
||||
help="The name of the predefined style used as a"
|
||||
"fallback in case clang-format is invoked with"
|
||||
"-style=file, but can not find the .clang-format"
|
||||
"file to use.",
|
||||
)
|
||||
parser.add_argument(
|
||||
"-binary",
|
||||
default="clang-format",
|
||||
help="location of binary to use for clang-format",
|
||||
)
|
||||
args = parser.parse_args()
|
||||
|
||||
# Extract changed lines for each file.
|
||||
filename = None
|
||||
lines_by_file = {}
|
||||
for line in sys.stdin:
|
||||
match = re.search(r"^\+\+\+\ (.*?/){%s}(.+)" % args.p, line.rstrip())
|
||||
if match:
|
||||
filename = match.group(2)
|
||||
if filename is None:
|
||||
continue
|
||||
|
||||
if args.regex is not None:
|
||||
if not re.match("^%s$" % args.regex, filename):
|
||||
continue
|
||||
else:
|
||||
if not re.match("^%s$" % args.iregex, filename, re.IGNORECASE):
|
||||
continue
|
||||
|
||||
match = re.search(r"^@@.*\+(\d+)(?:,(\d+))?", line)
|
||||
if match:
|
||||
start_line = int(match.group(1))
|
||||
line_count = 1
|
||||
if match.group(2):
|
||||
line_count = int(match.group(2))
|
||||
# The input is something like
|
||||
#
|
||||
# @@ -1, +0,0 @@
|
||||
#
|
||||
# which means no lines were added.
|
||||
if line_count == 0:
|
||||
continue
|
||||
# Also format lines range if line_count is 0 in case of deleting
|
||||
# surrounding statements.
|
||||
end_line = start_line
|
||||
if line_count != 0:
|
||||
end_line += line_count - 1
|
||||
lines_by_file.setdefault(filename, []).extend(
|
||||
["--lines", str(start_line) + ":" + str(end_line)]
|
||||
)
|
||||
|
||||
# Reformat files containing changes in place.
|
||||
has_diff = False
|
||||
for filename, lines in lines_by_file.items():
|
||||
if args.i and args.verbose:
|
||||
print("Formatting {}".format(filename))
|
||||
command = [args.binary, filename]
|
||||
if args.i:
|
||||
command.append("-i")
|
||||
if args.sort_includes:
|
||||
command.append("--sort-includes")
|
||||
command.extend(lines)
|
||||
if args.style:
|
||||
command.extend(["--style", args.style])
|
||||
if args.fallback_style:
|
||||
command.extend(["--fallback-style", args.fallback_style])
|
||||
|
||||
try:
|
||||
p = subprocess.Popen(
|
||||
command,
|
||||
stdout=subprocess.PIPE,
|
||||
stderr=None,
|
||||
stdin=subprocess.PIPE,
|
||||
universal_newlines=True,
|
||||
)
|
||||
except OSError as e:
|
||||
# Give the user more context when clang-format isn't
|
||||
# found/isn't executable, etc.
|
||||
raise RuntimeError(
|
||||
'Failed to run "%s" - %s"' % (" ".join(command), e.strerror)
|
||||
)
|
||||
|
||||
stdout, _stderr = p.communicate()
|
||||
if p.returncode != 0:
|
||||
return p.returncode
|
||||
|
||||
if not args.i:
|
||||
with open(filename) as f:
|
||||
code = f.readlines()
|
||||
formatted_code = StringIO(stdout).readlines()
|
||||
diff = difflib.unified_diff(
|
||||
code,
|
||||
formatted_code,
|
||||
filename,
|
||||
filename,
|
||||
"(before formatting)",
|
||||
"(after formatting)",
|
||||
)
|
||||
diff_string = "".join(diff)
|
||||
if len(diff_string) > 0:
|
||||
has_diff = True
|
||||
sys.stdout.write(diff_string)
|
||||
|
||||
if has_diff:
|
||||
return 1
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
sys.exit(main())
|
||||
175
frontend/src/common/prettier/plugins/clang/src/clang-format.d.ts
vendored
Normal file
175
frontend/src/common/prettier/plugins/clang/src/clang-format.d.ts
vendored
Normal file
@@ -0,0 +1,175 @@
|
||||
export type InitInput =
|
||||
| RequestInfo
|
||||
| URL
|
||||
| Response
|
||||
| BufferSource
|
||||
| WebAssembly.Module;
|
||||
|
||||
export default function init(input?: InitInput): Promise<void>;
|
||||
|
||||
/**
|
||||
* The style to use for formatting.
|
||||
* Supported style values are:
|
||||
* - `LLVM` - A style complying with the LLVM coding standards.
|
||||
* - `Google` - A style complying with Google’s C++ style guide.
|
||||
* - `Chromium` - A style complying with Chromium’s style guide.
|
||||
* - `Mozilla` - A style complying with Mozilla’s style guide.
|
||||
* - `WebKit` - A style complying with WebKit’s style guide.
|
||||
* - `Microsoft` - A style complying with Microsoft’s style guide.
|
||||
* - `GNU` - A style complying with the GNU coding standards.
|
||||
* - A string starting with `{`, for example: `{BasedOnStyle: Chromium, IndentWidth: 4, ...}`.
|
||||
* - A string which represents `.clang-format` content.
|
||||
*
|
||||
*/
|
||||
export type Style =
|
||||
| "LLVM"
|
||||
| "Google"
|
||||
| "Chromium"
|
||||
| "Mozilla"
|
||||
| "WebKit"
|
||||
| "Microsoft"
|
||||
| "GNU"
|
||||
| (string & {});
|
||||
|
||||
/**
|
||||
* The filename to use for determining the language.
|
||||
*/
|
||||
export type Filename =
|
||||
| "main.c"
|
||||
| "main.cc"
|
||||
| "main.cxx"
|
||||
| "main.cpp"
|
||||
| "main.java"
|
||||
| "main.js"
|
||||
| "main.mjs"
|
||||
| "main.ts"
|
||||
| "main.json"
|
||||
| "main.m"
|
||||
| "main.mm"
|
||||
| "main.proto"
|
||||
| "main.cs"
|
||||
| (string & {});
|
||||
|
||||
/**
|
||||
* Formats the given content using the specified style.
|
||||
*
|
||||
* @param {string} content - The content to format.
|
||||
* @param {Filename} filename - The filename to use for determining the language.
|
||||
* @param {Style} style - The style to use for formatting.
|
||||
* Supported style values are:
|
||||
* - `LLVM` - A style complying with the LLVM coding standards.
|
||||
* - `Google` - A style complying with Google’s C++ style guide.
|
||||
* - `Chromium` - A style complying with Chromium’s style guide.
|
||||
* - `Mozilla` - A style complying with Mozilla’s style guide.
|
||||
* - `WebKit` - A style complying with WebKit’s style guide.
|
||||
* - `Microsoft` - A style complying with Microsoft’s style guide.
|
||||
* - `GNU` - A style complying with the GNU coding standards.
|
||||
* - A string starting with `{`, for example: `{BasedOnStyle: Chromium, IndentWidth: 4, ...}`.
|
||||
* - A string which represents `.clang-format` content.
|
||||
*
|
||||
* @returns {string} The formatted content.
|
||||
* @throws {Error}
|
||||
*
|
||||
* @see {@link https://clang.llvm.org/docs/ClangFormatStyleOptions.html}
|
||||
*/
|
||||
export declare function format(
|
||||
content: string,
|
||||
filename?: Filename,
|
||||
style?: Style,
|
||||
): string;
|
||||
|
||||
/**
|
||||
* Both the startLine and endLine are 1-based.
|
||||
*/
|
||||
export type LineRange = [startLine: number, endLine: number];
|
||||
|
||||
/**
|
||||
* Both the offset and length are measured in bytes.
|
||||
*/
|
||||
export type ByteRange = [offset: number, length: number];
|
||||
|
||||
/**
|
||||
* Formats the specified range of lines in the given content using the specified style.
|
||||
*
|
||||
* @param {string} content - The content to format.
|
||||
* @param {LineRange[]} range - Array<[startLine, endLine]> - The range of lines to format.
|
||||
* Both startLine and endLine are 1-based.
|
||||
* Multiple ranges can be formatted by specifying several lines arguments.
|
||||
* @param {Filename} filename - The filename to use for determining the language.
|
||||
* @param {Style} style - The style to use for formatting.
|
||||
* Supported style values are:
|
||||
* - `LLVM` - A style complying with the LLVM coding standards.
|
||||
* - `Google` - A style complying with Google’s C++ style guide.
|
||||
* - `Chromium` - A style complying with Chromium’s style guide.
|
||||
* - `Mozilla` - A style complying with Mozilla’s style guide.
|
||||
* - `WebKit` - A style complying with WebKit’s style guide.
|
||||
* - `Microsoft` - A style complying with Microsoft’s style guide.
|
||||
* - `GNU` - A style complying with the GNU coding standards.
|
||||
* - A string starting with `{`, for example: `{BasedOnStyle: Chromium, IndentWidth: 4, ...}`.
|
||||
* - A string which represents `.clang-format` content.
|
||||
*
|
||||
* @returns {string} The formatted content.
|
||||
* @throws {Error}
|
||||
*
|
||||
* @see {@link https://clang.llvm.org/docs/ClangFormatStyleOptions.html}
|
||||
*/
|
||||
export declare function format_line_range(
|
||||
content: string,
|
||||
range: ByteRange[] | [[offset: number]],
|
||||
filename?: Filename,
|
||||
style?: Style,
|
||||
): string;
|
||||
|
||||
/**
|
||||
* @deprecated Use `format_line_range` instead.
|
||||
*/
|
||||
export declare function formatLineRange(
|
||||
content: string,
|
||||
range: ByteRange[] | [[offset: number]],
|
||||
filename?: Filename,
|
||||
style?: Style,
|
||||
): string;
|
||||
|
||||
/**
|
||||
* Formats the specified range of bytes in the given content using the specified style.
|
||||
*
|
||||
* @param {string} content - The content to format.
|
||||
* @param {ByteRange[]} range - Array<[offset, length]> - The range of bytes to format.
|
||||
* @param {Filename} filename - The filename to use for determining the language.
|
||||
* @param {Style} style - The style to use for formatting.
|
||||
* Supported style values are:
|
||||
* - `LLVM` - A style complying with the LLVM coding standards.
|
||||
* - `Google` - A style complying with Google’s C++ style guide.
|
||||
* - `Chromium` - A style complying with Chromium’s style guide.
|
||||
* - `Mozilla` - A style complying with Mozilla’s style guide.
|
||||
* - `WebKit` - A style complying with WebKit’s style guide.
|
||||
* - `Microsoft` - A style complying with Microsoft’s style guide.
|
||||
* - `GNU` - A style complying with the GNU coding standards.
|
||||
* - A string starting with `{`, for example: `{BasedOnStyle: Chromium, IndentWidth: 4, ...}`.
|
||||
* - A string which represents `.clang-format` content.
|
||||
*
|
||||
* @returns {string} The formatted content.
|
||||
* @throws {Error}
|
||||
*
|
||||
* @see {@link https://clang.llvm.org/docs/ClangFormatStyleOptions.html}
|
||||
*/
|
||||
export declare function format_byte_range(
|
||||
content: string,
|
||||
range: LineRange[],
|
||||
filename?: Filename,
|
||||
style?: Style,
|
||||
): string;
|
||||
|
||||
/**
|
||||
* @deprecated Use `format_byte_range` instead.
|
||||
*/
|
||||
export declare function formatByteRange(
|
||||
content: string,
|
||||
range: LineRange[],
|
||||
filename?: Filename,
|
||||
style?: Style,
|
||||
): string;
|
||||
|
||||
export declare function version(): string;
|
||||
|
||||
export declare function set_fallback_style(style: Style): void;
|
||||
748
frontend/src/common/prettier/plugins/clang/src/cli.cc
Normal file
748
frontend/src/common/prettier/plugins/clang/src/cli.cc
Normal file
@@ -0,0 +1,748 @@
|
||||
//===-- clang-format/ClangFormat.cpp - Clang format tool ------------------===//
|
||||
//
|
||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
// See https://llvm.org/LICENSE.txt for license information.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
///
|
||||
/// \file
|
||||
/// This file implements a clang-format tool that automatically formats
|
||||
/// (fragments of) C++ code.
|
||||
///
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "clang/../../lib/Format/MatchFilePath.h"
|
||||
#include "clang/Basic/Diagnostic.h"
|
||||
#include "clang/Basic/DiagnosticOptions.h"
|
||||
#include "clang/Basic/FileManager.h"
|
||||
#include "clang/Basic/SourceManager.h"
|
||||
#include "clang/Basic/Version.h"
|
||||
#include "clang/Format/Format.h"
|
||||
#include "clang/Rewrite/Core/Rewriter.h"
|
||||
#include "llvm/ADT/StringSwitch.h"
|
||||
#include "llvm/Support/CommandLine.h"
|
||||
#include "llvm/Support/FileSystem.h"
|
||||
#include "llvm/Support/InitLLVM.h"
|
||||
#include "llvm/Support/Process.h"
|
||||
#include <fstream>
|
||||
|
||||
#include "CustomFileSystem.h"
|
||||
|
||||
using namespace llvm;
|
||||
using clang::tooling::Replacements;
|
||||
|
||||
static cl::opt<bool> Help("h", cl::desc("Alias for -help"), cl::Hidden);
|
||||
|
||||
// Mark all our options with this category, everything else (except for -version
|
||||
// and -help) will be hidden.
|
||||
static cl::OptionCategory ClangFormatCategory("Clang-format options");
|
||||
|
||||
static cl::list<unsigned>
|
||||
Offsets("offset",
|
||||
cl::desc("Format a range starting at this byte offset.\n"
|
||||
"Multiple ranges can be formatted by specifying\n"
|
||||
"several -offset and -length pairs.\n"
|
||||
"Can only be used with one input file."),
|
||||
cl::cat(ClangFormatCategory));
|
||||
static cl::list<unsigned>
|
||||
Lengths("length",
|
||||
cl::desc("Format a range of this length (in bytes).\n"
|
||||
"Multiple ranges can be formatted by specifying\n"
|
||||
"several -offset and -length pairs.\n"
|
||||
"When only a single -offset is specified without\n"
|
||||
"-length, clang-format will format up to the end\n"
|
||||
"of the file.\n"
|
||||
"Can only be used with one input file."),
|
||||
cl::cat(ClangFormatCategory));
|
||||
static cl::list<std::string>
|
||||
LineRanges("lines",
|
||||
cl::desc("<start line>:<end line> - format a range of\n"
|
||||
"lines (both 1-based).\n"
|
||||
"Multiple ranges can be formatted by specifying\n"
|
||||
"several -lines arguments.\n"
|
||||
"Can't be used with -offset and -length.\n"
|
||||
"Can only be used with one input file."),
|
||||
cl::cat(ClangFormatCategory));
|
||||
static cl::opt<std::string>
|
||||
Style("style", cl::desc(clang::format::StyleOptionHelpDescription),
|
||||
cl::init(clang::format::DefaultFormatStyle),
|
||||
cl::cat(ClangFormatCategory));
|
||||
static cl::opt<std::string>
|
||||
FallbackStyle("fallback-style",
|
||||
cl::desc("The name of the predefined style used as a\n"
|
||||
"fallback in case clang-format is invoked with\n"
|
||||
"-style=file, but can not find the .clang-format\n"
|
||||
"file to use. Defaults to 'LLVM'.\n"
|
||||
"Use -fallback-style=none to skip formatting."),
|
||||
cl::init(clang::format::DefaultFallbackStyle),
|
||||
cl::cat(ClangFormatCategory));
|
||||
|
||||
static cl::opt<std::string> AssumeFileName(
|
||||
"assume-filename",
|
||||
cl::desc("Set filename used to determine the language and to find\n"
|
||||
".clang-format file.\n"
|
||||
"Only used when reading from stdin.\n"
|
||||
"If this is not passed, the .clang-format file is searched\n"
|
||||
"relative to the current working directory when reading stdin.\n"
|
||||
"Unrecognized filenames are treated as C++.\n"
|
||||
"supported:\n"
|
||||
" CSharp: .cs\n"
|
||||
" Java: .java\n"
|
||||
" JavaScript: .js .mjs .cjs .ts\n"
|
||||
" Json: .json .ipynb\n"
|
||||
" Objective-C: .m .mm\n"
|
||||
" Proto: .proto .protodevel\n"
|
||||
" TableGen: .td\n"
|
||||
" TextProto: .txtpb .textpb .pb.txt .textproto .asciipb\n"
|
||||
" Verilog: .sv .svh .v .vh"),
|
||||
cl::init("<stdin>"), cl::cat(ClangFormatCategory));
|
||||
|
||||
static cl::opt<bool> Inplace("i",
|
||||
cl::desc("Inplace edit <file>s, if specified."),
|
||||
cl::cat(ClangFormatCategory));
|
||||
|
||||
static cl::opt<bool> OutputXML("output-replacements-xml",
|
||||
cl::desc("Output replacements as XML."),
|
||||
cl::cat(ClangFormatCategory));
|
||||
static cl::opt<bool>
|
||||
DumpConfig("dump-config",
|
||||
cl::desc("Dump configuration options to stdout and exit.\n"
|
||||
"Can be used with -style option."),
|
||||
cl::cat(ClangFormatCategory));
|
||||
static cl::opt<unsigned>
|
||||
Cursor("cursor",
|
||||
cl::desc("The position of the cursor when invoking\n"
|
||||
"clang-format from an editor integration"),
|
||||
cl::init(0), cl::cat(ClangFormatCategory));
|
||||
|
||||
static cl::opt<bool>
|
||||
SortIncludes("sort-includes",
|
||||
cl::desc("If set, overrides the include sorting behavior\n"
|
||||
"determined by the SortIncludes style flag"),
|
||||
cl::cat(ClangFormatCategory));
|
||||
|
||||
static cl::opt<std::string> QualifierAlignment(
|
||||
"qualifier-alignment",
|
||||
cl::desc("If set, overrides the qualifier alignment style\n"
|
||||
"determined by the QualifierAlignment style flag"),
|
||||
cl::init(""), cl::cat(ClangFormatCategory));
|
||||
|
||||
static cl::opt<std::string> Files(
|
||||
"files",
|
||||
cl::desc("A file containing a list of files to process, one per line."),
|
||||
cl::value_desc("filename"), cl::init(""), cl::cat(ClangFormatCategory));
|
||||
|
||||
static cl::opt<bool>
|
||||
Verbose("verbose", cl::desc("If set, shows the list of processed files"),
|
||||
cl::cat(ClangFormatCategory));
|
||||
|
||||
// Use --dry-run to match other LLVM tools when you mean do it but don't
|
||||
// actually do it
|
||||
static cl::opt<bool>
|
||||
DryRun("dry-run",
|
||||
cl::desc("If set, do not actually make the formatting changes"),
|
||||
cl::cat(ClangFormatCategory));
|
||||
|
||||
// Use -n as a common command as an alias for --dry-run. (git and make use -n)
|
||||
static cl::alias DryRunShort("n", cl::desc("Alias for --dry-run"),
|
||||
cl::cat(ClangFormatCategory), cl::aliasopt(DryRun),
|
||||
cl::NotHidden);
|
||||
|
||||
// Emulate being able to turn on/off the warning.
|
||||
static cl::opt<bool>
|
||||
WarnFormat("Wclang-format-violations",
|
||||
cl::desc("Warnings about individual formatting changes needed. "
|
||||
"Used only with --dry-run or -n"),
|
||||
cl::init(true), cl::cat(ClangFormatCategory), cl::Hidden);
|
||||
|
||||
static cl::opt<bool>
|
||||
NoWarnFormat("Wno-clang-format-violations",
|
||||
cl::desc("Do not warn about individual formatting changes "
|
||||
"needed. Used only with --dry-run or -n"),
|
||||
cl::init(false), cl::cat(ClangFormatCategory), cl::Hidden);
|
||||
|
||||
static cl::opt<unsigned> ErrorLimit(
|
||||
"ferror-limit",
|
||||
cl::desc("Set the maximum number of clang-format errors to emit\n"
|
||||
"before stopping (0 = no limit).\n"
|
||||
"Used only with --dry-run or -n"),
|
||||
cl::init(0), cl::cat(ClangFormatCategory));
|
||||
|
||||
static cl::opt<bool>
|
||||
WarningsAsErrors("Werror",
|
||||
cl::desc("If set, changes formatting warnings to errors"),
|
||||
cl::cat(ClangFormatCategory));
|
||||
|
||||
namespace {
|
||||
enum class WNoError { Unknown };
|
||||
}
|
||||
|
||||
static cl::bits<WNoError> WNoErrorList(
|
||||
"Wno-error",
|
||||
cl::desc("If set, don't error out on the specified warning type."),
|
||||
cl::values(
|
||||
clEnumValN(WNoError::Unknown, "unknown",
|
||||
"If set, unknown format options are only warned about.\n"
|
||||
"This can be used to enable formatting, even if the\n"
|
||||
"configuration contains unknown (newer) options.\n"
|
||||
"Use with caution, as this might lead to dramatically\n"
|
||||
"differing format depending on an option being\n"
|
||||
"supported or not.")),
|
||||
cl::cat(ClangFormatCategory));
|
||||
|
||||
static cl::opt<bool>
|
||||
ShowColors("fcolor-diagnostics",
|
||||
cl::desc("If set, and on a color-capable terminal controls "
|
||||
"whether or not to print diagnostics in color"),
|
||||
cl::init(true), cl::cat(ClangFormatCategory), cl::Hidden);
|
||||
|
||||
static cl::opt<bool>
|
||||
NoShowColors("fno-color-diagnostics",
|
||||
cl::desc("If set, and on a color-capable terminal controls "
|
||||
"whether or not to print diagnostics in color"),
|
||||
cl::init(false), cl::cat(ClangFormatCategory), cl::Hidden);
|
||||
|
||||
static cl::list<std::string> FileNames(cl::Positional,
|
||||
cl::desc("[@<file>] [<file> ...]"),
|
||||
cl::cat(ClangFormatCategory));
|
||||
|
||||
static cl::opt<bool> FailOnIncompleteFormat(
|
||||
"fail-on-incomplete-format",
|
||||
cl::desc("If set, fail with exit code 1 on incomplete format."),
|
||||
cl::init(false), cl::cat(ClangFormatCategory));
|
||||
|
||||
static cl::opt<bool> ListIgnored("list-ignored",
|
||||
cl::desc("List ignored files."),
|
||||
cl::cat(ClangFormatCategory), cl::Hidden);
|
||||
|
||||
namespace clang {
|
||||
namespace format {
|
||||
|
||||
static FileID createInMemoryFile(StringRef FileName, MemoryBufferRef Source,
|
||||
SourceManager &Sources, FileManager &Files,
|
||||
llvm::vfs::InMemoryFileSystem *MemFS) {
|
||||
MemFS->addFileNoOwn(FileName, 0, Source);
|
||||
auto File = Files.getOptionalFileRef(FileName);
|
||||
assert(File && "File not added to MemFS?");
|
||||
return Sources.createFileID(*File, SourceLocation(), SrcMgr::C_User);
|
||||
}
|
||||
|
||||
// Parses <start line>:<end line> input to a pair of line numbers.
|
||||
// Returns true on error.
|
||||
static bool parseLineRange(StringRef Input, unsigned &FromLine,
|
||||
unsigned &ToLine) {
|
||||
std::pair<StringRef, StringRef> LineRange = Input.split(':');
|
||||
return LineRange.first.getAsInteger(0, FromLine) ||
|
||||
LineRange.second.getAsInteger(0, ToLine);
|
||||
}
|
||||
|
||||
static bool fillRanges(MemoryBuffer *Code,
|
||||
std::vector<tooling::Range> &Ranges) {
|
||||
IntrusiveRefCntPtr<llvm::vfs::InMemoryFileSystem> InMemoryFileSystem(
|
||||
new llvm::vfs::InMemoryFileSystem);
|
||||
FileManager Files(FileSystemOptions(), InMemoryFileSystem);
|
||||
DiagnosticOptions DiagOpts;
|
||||
DiagnosticsEngine Diagnostics(
|
||||
IntrusiveRefCntPtr<DiagnosticIDs>(new DiagnosticIDs), DiagOpts);
|
||||
SourceManager Sources(Diagnostics, Files);
|
||||
const auto ID = createInMemoryFile("<irrelevant>", *Code, Sources, Files,
|
||||
InMemoryFileSystem.get());
|
||||
if (!LineRanges.empty()) {
|
||||
if (!Offsets.empty() || !Lengths.empty()) {
|
||||
errs() << "error: cannot use -lines with -offset/-length\n";
|
||||
return true;
|
||||
}
|
||||
|
||||
for (const auto &LineRange : LineRanges) {
|
||||
unsigned FromLine, ToLine;
|
||||
if (parseLineRange(LineRange, FromLine, ToLine)) {
|
||||
errs() << "error: invalid <start line>:<end line> pair\n";
|
||||
return true;
|
||||
}
|
||||
if (FromLine < 1) {
|
||||
errs() << "error: start line should be at least 1\n";
|
||||
return true;
|
||||
}
|
||||
if (FromLine > ToLine) {
|
||||
errs() << "error: start line should not exceed end line\n";
|
||||
return true;
|
||||
}
|
||||
const auto Start = Sources.translateLineCol(ID, FromLine, 1);
|
||||
const auto End = Sources.translateLineCol(ID, ToLine, UINT_MAX);
|
||||
if (Start.isInvalid() || End.isInvalid())
|
||||
return true;
|
||||
const auto Offset = Sources.getFileOffset(Start);
|
||||
const auto Length = Sources.getFileOffset(End) - Offset;
|
||||
Ranges.push_back(tooling::Range(Offset, Length));
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
if (Offsets.empty())
|
||||
Offsets.push_back(0);
|
||||
const bool EmptyLengths = Lengths.empty();
|
||||
unsigned Length = 0;
|
||||
if (Offsets.size() == 1 && EmptyLengths) {
|
||||
Length = Sources.getFileOffset(Sources.getLocForEndOfFile(ID)) - Offsets[0];
|
||||
} else if (Offsets.size() != Lengths.size()) {
|
||||
errs() << "error: number of -offset and -length arguments must match.\n";
|
||||
return true;
|
||||
}
|
||||
for (unsigned I = 0, E = Offsets.size(), CodeSize = Code->getBufferSize();
|
||||
I < E; ++I) {
|
||||
const auto Offset = Offsets[I];
|
||||
if (Offset >= CodeSize) {
|
||||
errs() << "error: offset " << Offset << " is outside the file\n";
|
||||
return true;
|
||||
}
|
||||
if (!EmptyLengths)
|
||||
Length = Lengths[I];
|
||||
if (Offset + Length > CodeSize) {
|
||||
errs() << "error: invalid length " << Length << ", offset + length ("
|
||||
<< Offset + Length << ") is outside the file.\n";
|
||||
return true;
|
||||
}
|
||||
Ranges.push_back(tooling::Range(Offset, Length));
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static void outputReplacementXML(StringRef Text) {
|
||||
// FIXME: When we sort includes, we need to make sure the stream is correct
|
||||
// utf-8.
|
||||
size_t From = 0;
|
||||
size_t Index;
|
||||
while ((Index = Text.find_first_of("\n\r<&", From)) != StringRef::npos) {
|
||||
outs() << Text.substr(From, Index - From);
|
||||
switch (Text[Index]) {
|
||||
case '\n':
|
||||
outs() << " ";
|
||||
break;
|
||||
case '\r':
|
||||
outs() << " ";
|
||||
break;
|
||||
case '<':
|
||||
outs() << "<";
|
||||
break;
|
||||
case '&':
|
||||
outs() << "&";
|
||||
break;
|
||||
default:
|
||||
llvm_unreachable("Unexpected character encountered!");
|
||||
}
|
||||
From = Index + 1;
|
||||
}
|
||||
outs() << Text.substr(From);
|
||||
}
|
||||
|
||||
static void outputReplacementsXML(const Replacements &Replaces) {
|
||||
for (const auto &R : Replaces) {
|
||||
outs() << "<replacement "
|
||||
<< "offset='" << R.getOffset() << "' "
|
||||
<< "length='" << R.getLength() << "'>";
|
||||
outputReplacementXML(R.getReplacementText());
|
||||
outs() << "</replacement>\n";
|
||||
}
|
||||
}
|
||||
|
||||
static bool
|
||||
emitReplacementWarnings(const Replacements &Replaces, StringRef AssumedFileName,
|
||||
const std::unique_ptr<llvm::MemoryBuffer> &Code) {
|
||||
unsigned Errors = 0;
|
||||
if (WarnFormat && !NoWarnFormat) {
|
||||
SourceMgr Mgr;
|
||||
const char *StartBuf = Code->getBufferStart();
|
||||
|
||||
Mgr.AddNewSourceBuffer(
|
||||
MemoryBuffer::getMemBuffer(StartBuf, AssumedFileName), SMLoc());
|
||||
for (const auto &R : Replaces) {
|
||||
SMDiagnostic Diag = Mgr.GetMessage(
|
||||
SMLoc::getFromPointer(StartBuf + R.getOffset()),
|
||||
WarningsAsErrors ? SourceMgr::DiagKind::DK_Error
|
||||
: SourceMgr::DiagKind::DK_Warning,
|
||||
"code should be clang-formatted [-Wclang-format-violations]");
|
||||
|
||||
Diag.print(nullptr, llvm::errs(), ShowColors && !NoShowColors);
|
||||
if (ErrorLimit && ++Errors >= ErrorLimit)
|
||||
break;
|
||||
}
|
||||
}
|
||||
return WarningsAsErrors;
|
||||
}
|
||||
|
||||
static void outputXML(const Replacements &Replaces,
|
||||
const Replacements &FormatChanges,
|
||||
const FormattingAttemptStatus &Status,
|
||||
const cl::opt<unsigned> &Cursor,
|
||||
unsigned CursorPosition) {
|
||||
outs() << "<?xml version='1.0'?>\n<replacements "
|
||||
"xml:space='preserve' incomplete_format='"
|
||||
<< (Status.FormatComplete ? "false" : "true") << "'";
|
||||
if (!Status.FormatComplete)
|
||||
outs() << " line='" << Status.Line << "'";
|
||||
outs() << ">\n";
|
||||
if (Cursor.getNumOccurrences() != 0) {
|
||||
outs() << "<cursor>" << FormatChanges.getShiftedCodePosition(CursorPosition)
|
||||
<< "</cursor>\n";
|
||||
}
|
||||
|
||||
outputReplacementsXML(Replaces);
|
||||
outs() << "</replacements>\n";
|
||||
}
|
||||
|
||||
class ClangFormatDiagConsumer : public DiagnosticConsumer {
|
||||
virtual void anchor() {}
|
||||
|
||||
void HandleDiagnostic(DiagnosticsEngine::Level DiagLevel,
|
||||
const Diagnostic &Info) override {
|
||||
|
||||
SmallVector<char, 16> vec;
|
||||
Info.FormatDiagnostic(vec);
|
||||
errs() << "clang-format error:" << vec << "\n";
|
||||
}
|
||||
};
|
||||
|
||||
// Returns true on error.
|
||||
static bool format(StringRef FileName, bool ErrorOnIncompleteFormat = false) {
|
||||
const bool IsSTDIN = FileName == "-";
|
||||
if (!OutputXML && Inplace && IsSTDIN) {
|
||||
errs() << "error: cannot use -i when reading from stdin.\n";
|
||||
return true;
|
||||
}
|
||||
// On Windows, overwriting a file with an open file mapping doesn't work,
|
||||
// so read the whole file into memory when formatting in-place.
|
||||
ErrorOr<std::unique_ptr<MemoryBuffer>> CodeOrErr =
|
||||
!OutputXML && Inplace
|
||||
? MemoryBuffer::getFileAsStream(FileName)
|
||||
: MemoryBuffer::getFileOrSTDIN(FileName, /*IsText=*/true);
|
||||
if (std::error_code EC = CodeOrErr.getError()) {
|
||||
errs() << FileName << ": " << EC.message() << "\n";
|
||||
return true;
|
||||
}
|
||||
std::unique_ptr<llvm::MemoryBuffer> Code = std::move(CodeOrErr.get());
|
||||
if (Code->getBufferSize() == 0)
|
||||
return false; // Empty files are formatted correctly.
|
||||
|
||||
StringRef BufStr = Code->getBuffer();
|
||||
|
||||
const char *InvalidBOM = SrcMgr::ContentCache::getInvalidBOM(BufStr);
|
||||
|
||||
if (InvalidBOM) {
|
||||
errs() << "error: encoding with unsupported byte order mark \""
|
||||
<< InvalidBOM << "\" detected";
|
||||
if (!IsSTDIN)
|
||||
errs() << " in file '" << FileName << "'";
|
||||
errs() << ".\n";
|
||||
return true;
|
||||
}
|
||||
|
||||
std::vector<tooling::Range> Ranges;
|
||||
if (fillRanges(Code.get(), Ranges))
|
||||
return true;
|
||||
StringRef AssumedFileName = IsSTDIN ? AssumeFileName : FileName;
|
||||
if (AssumedFileName.empty()) {
|
||||
llvm::errs() << "error: empty filenames are not allowed\n";
|
||||
return true;
|
||||
}
|
||||
|
||||
auto RealFS = vfs::getRealFileSystem();
|
||||
auto CustomFS = new vfs::CustomFileSystem(RealFS);
|
||||
IntrusiveRefCntPtr<vfs::FileSystem> CustomFSPtr(CustomFS);
|
||||
Expected<FormatStyle> FormatStyle =
|
||||
getStyle(Style, AssumedFileName, FallbackStyle, Code->getBuffer(),
|
||||
CustomFSPtr.get(), WNoErrorList.isSet(WNoError::Unknown));
|
||||
if (!FormatStyle) {
|
||||
llvm::errs() << toString(FormatStyle.takeError()) << "\n";
|
||||
return true;
|
||||
}
|
||||
|
||||
StringRef QualifierAlignmentOrder = QualifierAlignment;
|
||||
|
||||
FormatStyle->QualifierAlignment =
|
||||
StringSwitch<FormatStyle::QualifierAlignmentStyle>(
|
||||
QualifierAlignmentOrder.lower())
|
||||
.Case("right", FormatStyle::QAS_Right)
|
||||
.Case("left", FormatStyle::QAS_Left)
|
||||
.Default(FormatStyle->QualifierAlignment);
|
||||
|
||||
if (FormatStyle->QualifierAlignment == FormatStyle::QAS_Left) {
|
||||
FormatStyle->QualifierOrder = {"const", "volatile", "type"};
|
||||
} else if (FormatStyle->QualifierAlignment == FormatStyle::QAS_Right) {
|
||||
FormatStyle->QualifierOrder = {"type", "const", "volatile"};
|
||||
} else if (QualifierAlignmentOrder.contains("type")) {
|
||||
FormatStyle->QualifierAlignment = FormatStyle::QAS_Custom;
|
||||
SmallVector<StringRef> Qualifiers;
|
||||
QualifierAlignmentOrder.split(Qualifiers, " ", /*MaxSplit=*/-1,
|
||||
/*KeepEmpty=*/false);
|
||||
FormatStyle->QualifierOrder = {Qualifiers.begin(), Qualifiers.end()};
|
||||
}
|
||||
|
||||
if (SortIncludes.getNumOccurrences() != 0) {
|
||||
FormatStyle->SortIncludes = {};
|
||||
if (SortIncludes)
|
||||
FormatStyle->SortIncludes.Enabled = true;
|
||||
}
|
||||
unsigned CursorPosition = Cursor;
|
||||
Replacements Replaces = sortIncludes(*FormatStyle, Code->getBuffer(), Ranges,
|
||||
AssumedFileName, &CursorPosition);
|
||||
|
||||
const bool IsJson = FormatStyle->isJson();
|
||||
|
||||
// To format JSON insert a variable to trick the code into thinking its
|
||||
// JavaScript.
|
||||
if (IsJson && !FormatStyle->DisableFormat) {
|
||||
auto Err =
|
||||
Replaces.add(tooling::Replacement(AssumedFileName, 0, 0, "x = "));
|
||||
if (Err)
|
||||
llvm::errs() << "Bad Json variable insertion\n";
|
||||
}
|
||||
|
||||
auto ChangedCode = tooling::applyAllReplacements(Code->getBuffer(), Replaces);
|
||||
if (!ChangedCode) {
|
||||
llvm::errs() << toString(ChangedCode.takeError()) << "\n";
|
||||
return true;
|
||||
}
|
||||
// Get new affected ranges after sorting `#includes`.
|
||||
Ranges = tooling::calculateRangesAfterReplacements(Replaces, Ranges);
|
||||
FormattingAttemptStatus Status;
|
||||
Replacements FormatChanges =
|
||||
reformat(*FormatStyle, *ChangedCode, Ranges, AssumedFileName, &Status);
|
||||
Replaces = Replaces.merge(FormatChanges);
|
||||
if (DryRun) {
|
||||
return Replaces.size() > (IsJson ? 1u : 0u) &&
|
||||
emitReplacementWarnings(Replaces, AssumedFileName, Code);
|
||||
}
|
||||
if (OutputXML) {
|
||||
outputXML(Replaces, FormatChanges, Status, Cursor, CursorPosition);
|
||||
} else {
|
||||
IntrusiveRefCntPtr<llvm::vfs::InMemoryFileSystem> InMemoryFileSystem(
|
||||
new llvm::vfs::InMemoryFileSystem);
|
||||
FileManager Files(FileSystemOptions(), InMemoryFileSystem);
|
||||
|
||||
DiagnosticOptions DiagOpts;
|
||||
ClangFormatDiagConsumer IgnoreDiagnostics;
|
||||
DiagnosticsEngine Diagnostics(
|
||||
IntrusiveRefCntPtr<DiagnosticIDs>(new DiagnosticIDs), DiagOpts,
|
||||
&IgnoreDiagnostics, false);
|
||||
SourceManager Sources(Diagnostics, Files);
|
||||
FileID ID = createInMemoryFile(AssumedFileName, *Code, Sources, Files,
|
||||
InMemoryFileSystem.get());
|
||||
Rewriter Rewrite(Sources, LangOptions());
|
||||
tooling::applyAllReplacements(Replaces, Rewrite);
|
||||
if (Inplace) {
|
||||
if (Rewrite.overwriteChangedFiles())
|
||||
return true;
|
||||
} else {
|
||||
if (Cursor.getNumOccurrences() != 0) {
|
||||
outs() << "{ \"Cursor\": "
|
||||
<< FormatChanges.getShiftedCodePosition(CursorPosition)
|
||||
<< ", \"IncompleteFormat\": "
|
||||
<< (Status.FormatComplete ? "false" : "true");
|
||||
if (!Status.FormatComplete)
|
||||
outs() << ", \"Line\": " << Status.Line;
|
||||
outs() << " }\n";
|
||||
}
|
||||
Rewrite.getEditBuffer(ID).write(outs());
|
||||
}
|
||||
}
|
||||
return ErrorOnIncompleteFormat && !Status.FormatComplete;
|
||||
}
|
||||
|
||||
} // namespace format
|
||||
} // namespace clang
|
||||
|
||||
static void PrintVersion(raw_ostream &OS) {
|
||||
OS << clang::getClangToolFullVersion("clang-format") << '\n';
|
||||
}
|
||||
|
||||
// Dump the configuration.
|
||||
static int dumpConfig() {
|
||||
std::unique_ptr<llvm::MemoryBuffer> Code;
|
||||
// We can't read the code to detect the language if there's no file name.
|
||||
if (!FileNames.empty()) {
|
||||
// Read in the code in case the filename alone isn't enough to detect the
|
||||
// language.
|
||||
ErrorOr<std::unique_ptr<MemoryBuffer>> CodeOrErr =
|
||||
MemoryBuffer::getFileOrSTDIN(FileNames[0], /*IsText=*/true);
|
||||
if (std::error_code EC = CodeOrErr.getError()) {
|
||||
llvm::errs() << EC.message() << "\n";
|
||||
return 1;
|
||||
}
|
||||
Code = std::move(CodeOrErr.get());
|
||||
}
|
||||
|
||||
auto RealFS = vfs::getRealFileSystem();
|
||||
auto CustomFS = new vfs::CustomFileSystem(RealFS);
|
||||
IntrusiveRefCntPtr<vfs::FileSystem> CustomFSPtr(CustomFS);
|
||||
|
||||
Expected<clang::format::FormatStyle> FormatStyle = clang::format::getStyle(
|
||||
Style,
|
||||
FileNames.empty() || FileNames[0] == "-" ? AssumeFileName : FileNames[0],
|
||||
FallbackStyle, Code ? Code->getBuffer() : "", CustomFSPtr.get());
|
||||
if (!FormatStyle) {
|
||||
llvm::errs() << toString(FormatStyle.takeError()) << "\n";
|
||||
return 1;
|
||||
}
|
||||
std::string Config = clang::format::configurationAsText(*FormatStyle);
|
||||
outs() << Config << "\n";
|
||||
return 0;
|
||||
}
|
||||
|
||||
using String = SmallString<128>;
|
||||
static String IgnoreDir; // Directory of .clang-format-ignore file.
|
||||
static String PrevDir; // Directory of previous `FilePath`.
|
||||
static SmallVector<String> Patterns; // Patterns in .clang-format-ignore file.
|
||||
|
||||
// Check whether `FilePath` is ignored according to the nearest
|
||||
// .clang-format-ignore file based on the rules below:
|
||||
// - A blank line is skipped.
|
||||
// - Leading and trailing spaces of a line are trimmed.
|
||||
// - A line starting with a hash (`#`) is a comment.
|
||||
// - A non-comment line is a single pattern.
|
||||
// - The slash (`/`) is used as the directory separator.
|
||||
// - A pattern is relative to the directory of the .clang-format-ignore file (or
|
||||
// the root directory if the pattern starts with a slash).
|
||||
// - A pattern is negated if it starts with a bang (`!`).
|
||||
static bool isIgnored(StringRef FilePath) {
|
||||
using namespace llvm::sys::fs;
|
||||
if (!is_regular_file(FilePath))
|
||||
return false;
|
||||
|
||||
String Path;
|
||||
String AbsPath{FilePath};
|
||||
|
||||
auto PathStyle = vfs::getPathStyle();
|
||||
|
||||
using namespace llvm::sys::path;
|
||||
vfs::make_absolute(AbsPath);
|
||||
remove_dots(AbsPath, /*remove_dot_dot=*/true, PathStyle);
|
||||
|
||||
if (StringRef Dir{parent_path(AbsPath, PathStyle)}; PrevDir != Dir) {
|
||||
PrevDir = Dir;
|
||||
|
||||
for (;;) {
|
||||
Path = Dir;
|
||||
append(Path, PathStyle, ".clang-format-ignore");
|
||||
if (is_regular_file(Path))
|
||||
break;
|
||||
Dir = parent_path(Dir, PathStyle);
|
||||
if (Dir.empty())
|
||||
return false;
|
||||
}
|
||||
|
||||
IgnoreDir = convert_to_slash(Dir, PathStyle);
|
||||
|
||||
std::ifstream IgnoreFile{Path.c_str()};
|
||||
if (!IgnoreFile.good())
|
||||
return false;
|
||||
|
||||
Patterns.clear();
|
||||
|
||||
for (std::string Line; std::getline(IgnoreFile, Line);) {
|
||||
if (const auto Pattern{StringRef{Line}.trim()};
|
||||
// Skip empty and comment lines.
|
||||
!Pattern.empty() && Pattern[0] != '#') {
|
||||
Patterns.push_back(Pattern);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (IgnoreDir.empty())
|
||||
return false;
|
||||
|
||||
const auto Pathname{convert_to_slash(AbsPath, PathStyle)};
|
||||
for (const auto &Pat : Patterns) {
|
||||
const bool IsNegated = Pat[0] == '!';
|
||||
StringRef Pattern{Pat};
|
||||
if (IsNegated)
|
||||
Pattern = Pattern.drop_front();
|
||||
|
||||
if (Pattern.empty())
|
||||
continue;
|
||||
|
||||
Pattern = Pattern.ltrim();
|
||||
|
||||
// `Pattern` is relative to `IgnoreDir` unless it starts with a slash.
|
||||
// This doesn't support patterns containing drive names (e.g. `C:`).
|
||||
if (Pattern[0] != '/') {
|
||||
Path = IgnoreDir;
|
||||
append(Path, Style::posix, Pattern);
|
||||
remove_dots(Path, /*remove_dot_dot=*/true, Style::posix);
|
||||
Pattern = Path;
|
||||
}
|
||||
|
||||
if (clang::format::matchFilePath(Pattern, Pathname) == !IsNegated)
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
int main(int argc, const char **argv) {
|
||||
InitLLVM X(argc, argv);
|
||||
|
||||
cl::HideUnrelatedOptions(ClangFormatCategory);
|
||||
|
||||
cl::SetVersionPrinter(PrintVersion);
|
||||
cl::ParseCommandLineOptions(
|
||||
argc, argv,
|
||||
"A tool to format C/C++/Java/JavaScript/JSON/Objective-C/Protobuf/C# "
|
||||
"code.\n\n"
|
||||
"If no arguments are specified, it formats the code from standard input\n"
|
||||
"and writes the result to the standard output.\n"
|
||||
"If <file>s are given, it reformats the files. If -i is specified\n"
|
||||
"together with <file>s, the files are edited in-place. Otherwise, the\n"
|
||||
"result is written to the standard output.\n");
|
||||
|
||||
if (Help) {
|
||||
cl::PrintHelpMessage();
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (DumpConfig)
|
||||
return dumpConfig();
|
||||
|
||||
if (!Files.empty()) {
|
||||
std::ifstream ExternalFileOfFiles{std::string(Files)};
|
||||
std::string Line;
|
||||
unsigned LineNo = 1;
|
||||
while (std::getline(ExternalFileOfFiles, Line)) {
|
||||
FileNames.push_back(Line);
|
||||
LineNo++;
|
||||
}
|
||||
errs() << "Clang-formatting " << LineNo << " files\n";
|
||||
}
|
||||
|
||||
if (FileNames.empty()) {
|
||||
if (isIgnored(AssumeFileName))
|
||||
return 0;
|
||||
return clang::format::format("-", FailOnIncompleteFormat);
|
||||
}
|
||||
|
||||
if (FileNames.size() > 1 &&
|
||||
(!Offsets.empty() || !Lengths.empty() || !LineRanges.empty())) {
|
||||
errs() << "error: -offset, -length and -lines can only be used for "
|
||||
"single file.\n";
|
||||
return 1;
|
||||
}
|
||||
|
||||
unsigned FileNo = 1;
|
||||
bool Error = false;
|
||||
for (const auto &FileName : FileNames) {
|
||||
const bool Ignored = isIgnored(FileName);
|
||||
if (ListIgnored) {
|
||||
if (Ignored)
|
||||
outs() << FileName << '\n';
|
||||
continue;
|
||||
}
|
||||
if (Ignored)
|
||||
continue;
|
||||
if (Verbose) {
|
||||
errs() << "Formatting [" << FileNo++ << "/" << FileNames.size() << "] "
|
||||
<< FileName << "\n";
|
||||
}
|
||||
Error |= clang::format::format(FileName, FailOnIncompleteFormat);
|
||||
}
|
||||
return Error ? 1 : 0;
|
||||
}
|
||||
323
frontend/src/common/prettier/plugins/clang/src/lib.cc
Normal file
323
frontend/src/common/prettier/plugins/clang/src/lib.cc
Normal file
@@ -0,0 +1,323 @@
|
||||
//===-- clang-format/ClangFormat.cpp - Clang format tool ------------------===//
|
||||
//
|
||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
// See https://llvm.org/LICENSE.txt for license information.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
///
|
||||
/// \file
|
||||
/// This file implements a clang-format tool that automatically formats
|
||||
/// (fragments of) C++ code.
|
||||
///
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "lib.h"
|
||||
#include "clang/Basic/FileManager.h"
|
||||
#include "clang/Basic/SourceManager.h"
|
||||
#include "clang/Basic/Version.h"
|
||||
#include "clang/Format/Format.h"
|
||||
#include "clang/Rewrite/Core/Rewriter.h"
|
||||
|
||||
using namespace llvm;
|
||||
using clang::tooling::Replacements;
|
||||
|
||||
static std::string FallbackStyle{clang::format::DefaultFallbackStyle};
|
||||
|
||||
static unsigned Cursor{0};
|
||||
|
||||
static bool SortIncludes{false};
|
||||
|
||||
static std::string QualifierAlignment{""};
|
||||
|
||||
static auto Ok(const std::string content) -> Result {
|
||||
return {false, std::move(content)};
|
||||
}
|
||||
|
||||
static auto Err(const std::string content) -> Result {
|
||||
return {true, std::move(content)};
|
||||
}
|
||||
|
||||
namespace clang {
|
||||
namespace format {
|
||||
|
||||
static FileID createInMemoryFile(StringRef FileName, MemoryBufferRef Source,
|
||||
SourceManager &Sources, FileManager &Files,
|
||||
llvm::vfs::InMemoryFileSystem *MemFS) {
|
||||
MemFS->addFileNoOwn(FileName, 0, Source);
|
||||
auto File = Files.getOptionalFileRef(FileName);
|
||||
assert(File && "File not added to MemFS?");
|
||||
return Sources.createFileID(*File, SourceLocation(), SrcMgr::C_User);
|
||||
}
|
||||
|
||||
static auto fillRanges(MemoryBuffer *Code, std::vector<tooling::Range> &Ranges)
|
||||
-> void {
|
||||
Ranges.push_back(tooling::Range(0, Code->getBuffer().size()));
|
||||
}
|
||||
|
||||
static auto isPredefinedStyle(StringRef style) -> bool {
|
||||
return StringSwitch<bool>(style.lower())
|
||||
.Cases("llvm", "chromium", "mozilla", "google", "webkit", "gnu",
|
||||
"microsoft", "none", "file", true)
|
||||
.Default(false);
|
||||
}
|
||||
|
||||
static auto format_range(const std::unique_ptr<llvm::MemoryBuffer> code,
|
||||
const std::string assumedFileName,
|
||||
const std::string style,
|
||||
std::vector<tooling::Range> ranges) -> Result {
|
||||
StringRef BufStr = code->getBuffer();
|
||||
|
||||
const char *InvalidBOM = SrcMgr::ContentCache::getInvalidBOM(BufStr);
|
||||
|
||||
if (InvalidBOM) {
|
||||
std::stringstream err;
|
||||
err << "encoding with unsupported byte order mark \"" << InvalidBOM
|
||||
<< "\" detected.";
|
||||
|
||||
return Err(err.str());
|
||||
}
|
||||
|
||||
StringRef AssumedFileName = assumedFileName;
|
||||
if (AssumedFileName.empty())
|
||||
AssumedFileName = "<stdin>";
|
||||
|
||||
IntrusiveRefCntPtr<llvm::vfs::InMemoryFileSystem> InMemoryFileSystem(
|
||||
new llvm::vfs::InMemoryFileSystem);
|
||||
FileManager Files(FileSystemOptions(), InMemoryFileSystem);
|
||||
|
||||
DiagnosticOptions DiagOpts;
|
||||
DiagnosticsEngine Diagnostics(
|
||||
IntrusiveRefCntPtr<DiagnosticIDs>(new DiagnosticIDs), DiagOpts);
|
||||
SourceManager Sources(Diagnostics, Files);
|
||||
|
||||
StringRef _style = style;
|
||||
|
||||
if (!_style.starts_with("{") && !isPredefinedStyle(_style)) {
|
||||
std::unique_ptr<llvm::MemoryBuffer> DotClangFormat =
|
||||
MemoryBuffer::getMemBuffer(style);
|
||||
|
||||
createInMemoryFile(".clang-format", *DotClangFormat.get(), Sources, Files,
|
||||
InMemoryFileSystem.get());
|
||||
_style = "file:.clang-format";
|
||||
}
|
||||
|
||||
llvm::Expected<FormatStyle> FormatStyle =
|
||||
getStyle(_style, AssumedFileName, FallbackStyle, code->getBuffer(),
|
||||
InMemoryFileSystem.get(), false);
|
||||
|
||||
InMemoryFileSystem.reset();
|
||||
|
||||
if (!FormatStyle) {
|
||||
std::string err = llvm::toString(FormatStyle.takeError());
|
||||
return Err(err);
|
||||
}
|
||||
|
||||
StringRef QualifierAlignmentOrder = QualifierAlignment;
|
||||
|
||||
FormatStyle->QualifierAlignment =
|
||||
StringSwitch<FormatStyle::QualifierAlignmentStyle>(
|
||||
QualifierAlignmentOrder.lower())
|
||||
.Case("right", FormatStyle::QAS_Right)
|
||||
.Case("left", FormatStyle::QAS_Left)
|
||||
.Default(FormatStyle->QualifierAlignment);
|
||||
|
||||
if (FormatStyle->QualifierAlignment == FormatStyle::QAS_Left) {
|
||||
FormatStyle->QualifierOrder = {"const", "volatile", "type"};
|
||||
} else if (FormatStyle->QualifierAlignment == FormatStyle::QAS_Right) {
|
||||
FormatStyle->QualifierOrder = {"type", "const", "volatile"};
|
||||
} else if (QualifierAlignmentOrder.contains("type")) {
|
||||
FormatStyle->QualifierAlignment = FormatStyle::QAS_Custom;
|
||||
SmallVector<StringRef> Qualifiers;
|
||||
QualifierAlignmentOrder.split(Qualifiers, " ", /*MaxSplit=*/-1,
|
||||
/*KeepEmpty=*/false);
|
||||
FormatStyle->QualifierOrder = {Qualifiers.begin(), Qualifiers.end()};
|
||||
}
|
||||
|
||||
if (SortIncludes) {
|
||||
FormatStyle->SortIncludes = {};
|
||||
FormatStyle->SortIncludes.Enabled = true;
|
||||
}
|
||||
|
||||
unsigned CursorPosition = Cursor;
|
||||
Replacements Replaces = sortIncludes(*FormatStyle, code->getBuffer(), ranges,
|
||||
AssumedFileName, &CursorPosition);
|
||||
|
||||
// To format JSON insert a variable to trick the code into thinking its
|
||||
// JavaScript.
|
||||
if (FormatStyle->isJson() && !FormatStyle->DisableFormat) {
|
||||
auto err =
|
||||
Replaces.add(tooling::Replacement(AssumedFileName, 0, 0, "x = "));
|
||||
if (err)
|
||||
return Err("Bad Json variable insertion");
|
||||
}
|
||||
|
||||
auto ChangedCode =
|
||||
cantFail(tooling::applyAllReplacements(code->getBuffer(), Replaces));
|
||||
|
||||
// Get new affected ranges after sorting `#includes`.
|
||||
ranges = tooling::calculateRangesAfterReplacements(Replaces, ranges);
|
||||
FormattingAttemptStatus Status;
|
||||
Replacements FormatChanges =
|
||||
reformat(*FormatStyle, ChangedCode, ranges, AssumedFileName, &Status);
|
||||
Replaces = Replaces.merge(FormatChanges);
|
||||
|
||||
return Ok(
|
||||
cantFail(tooling::applyAllReplacements(code->getBuffer(), Replaces)));
|
||||
}
|
||||
|
||||
static auto format_range(const std::string str,
|
||||
const std::string assumedFileName,
|
||||
const std::string style, const bool is_line_range,
|
||||
const std::vector<unsigned> ranges) -> Result {
|
||||
ErrorOr<std::unique_ptr<MemoryBuffer>> CodeOrErr =
|
||||
MemoryBuffer::getMemBuffer(str);
|
||||
|
||||
if (std::error_code EC = CodeOrErr.getError())
|
||||
return Err(EC.message());
|
||||
std::unique_ptr<llvm::MemoryBuffer> Code = std::move(CodeOrErr.get());
|
||||
if (Code->getBufferSize() == 0)
|
||||
return Ok(""); // Empty files are formatted correctly.
|
||||
|
||||
std::vector<tooling::Range> Ranges;
|
||||
|
||||
if (ranges.empty()) {
|
||||
fillRanges(Code.get(), Ranges);
|
||||
return format_range(std::move(Code), assumedFileName, style,
|
||||
std::move(Ranges));
|
||||
}
|
||||
|
||||
IntrusiveRefCntPtr<llvm::vfs::InMemoryFileSystem> InMemoryFileSystem(
|
||||
new llvm::vfs::InMemoryFileSystem);
|
||||
FileManager Files(FileSystemOptions(), InMemoryFileSystem);
|
||||
DiagnosticOptions DiagOpts;
|
||||
DiagnosticsEngine Diagnostics(
|
||||
IntrusiveRefCntPtr<DiagnosticIDs>(new DiagnosticIDs), DiagOpts);
|
||||
SourceManager Sources(Diagnostics, Files);
|
||||
FileID ID = createInMemoryFile("<irrelevant>", *Code, Sources, Files,
|
||||
InMemoryFileSystem.get());
|
||||
|
||||
if (is_line_range) {
|
||||
for (auto FromLine = begin(ranges); FromLine < end(ranges); FromLine += 2) {
|
||||
auto ToLine = FromLine + 1;
|
||||
|
||||
SourceLocation Start = Sources.translateLineCol(ID, *FromLine, 1);
|
||||
SourceLocation End = Sources.translateLineCol(ID, *ToLine, UINT_MAX);
|
||||
if (Start.isInvalid() || End.isInvalid())
|
||||
return Err("invalid line number");
|
||||
unsigned Offset = Sources.getFileOffset(Start);
|
||||
unsigned Length = Sources.getFileOffset(End) - Offset;
|
||||
Ranges.push_back(tooling::Range(Offset, Length));
|
||||
}
|
||||
} else {
|
||||
if (ranges.size() > 2 && ranges.size() % 2 != 0)
|
||||
return Err("number of -offset and -length arguments must match");
|
||||
|
||||
if (ranges.size() == 1) {
|
||||
auto offset = begin(ranges);
|
||||
if (*offset >= Code->getBufferSize()) {
|
||||
std::stringstream err;
|
||||
err << "offset " << *offset << " is outside the file";
|
||||
return Err(err.str());
|
||||
}
|
||||
SourceLocation Start =
|
||||
Sources.getLocForStartOfFile(ID).getLocWithOffset(*offset);
|
||||
SourceLocation End = Sources.getLocForEndOfFile(ID);
|
||||
|
||||
unsigned Offset = Sources.getFileOffset(Start);
|
||||
unsigned Length = Sources.getFileOffset(End) - Offset;
|
||||
|
||||
Ranges.push_back(tooling::Range(Offset, Length));
|
||||
} else {
|
||||
for (auto offset = begin(ranges); offset < end(ranges); offset += 2) {
|
||||
auto length = offset + 1;
|
||||
|
||||
if (*offset >= Code->getBufferSize()) {
|
||||
std::stringstream err;
|
||||
err << "offset " << *offset << " is outside the file";
|
||||
return Err(err.str());
|
||||
}
|
||||
|
||||
unsigned end = *offset + *length;
|
||||
if (end > Code->getBufferSize()) {
|
||||
std::stringstream err;
|
||||
err << "invalid length " << *length << ", offset + length (" << end
|
||||
<< ") is outside the file.";
|
||||
return Err(err.str());
|
||||
}
|
||||
|
||||
SourceLocation Start =
|
||||
Sources.getLocForStartOfFile(ID).getLocWithOffset(*offset);
|
||||
SourceLocation End = Start.getLocWithOffset(*length);
|
||||
|
||||
unsigned Offset = Sources.getFileOffset(Start);
|
||||
unsigned Length = Sources.getFileOffset(End) - Offset;
|
||||
|
||||
Ranges.push_back(tooling::Range(Offset, Length));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return format_range(std::move(Code), assumedFileName, style,
|
||||
std::move(Ranges));
|
||||
}
|
||||
|
||||
static auto format(const std::string str, const std::string assumedFileName,
|
||||
const std::string style) -> Result {
|
||||
ErrorOr<std::unique_ptr<MemoryBuffer>> CodeOrErr =
|
||||
MemoryBuffer::getMemBuffer(str);
|
||||
|
||||
if (std::error_code EC = CodeOrErr.getError())
|
||||
return Err(EC.message());
|
||||
std::unique_ptr<llvm::MemoryBuffer> Code = std::move(CodeOrErr.get());
|
||||
if (Code->getBufferSize() == 0)
|
||||
return Ok(""); // Empty files are formatted correctly.
|
||||
|
||||
std::vector<tooling::Range> Ranges;
|
||||
fillRanges(Code.get(), Ranges);
|
||||
|
||||
return format_range(std::move(Code), assumedFileName, style,
|
||||
std::move(Ranges));
|
||||
}
|
||||
|
||||
} // namespace format
|
||||
} // namespace clang
|
||||
|
||||
auto version() -> std::string {
|
||||
return clang::getClangToolFullVersion("clang-format");
|
||||
}
|
||||
|
||||
auto format(const std::string str, const std::string assumedFileName,
|
||||
const std::string style) -> Result {
|
||||
return clang::format::format(str, assumedFileName, style);
|
||||
}
|
||||
|
||||
auto format_byte(const std::string str, const std::string assumedFileName,
|
||||
const std::string style, const std::vector<unsigned> ranges)
|
||||
-> Result {
|
||||
return clang::format::format_range(str, assumedFileName, style, false,
|
||||
std::move(ranges));
|
||||
}
|
||||
|
||||
auto format_line(const std::string str, const std::string assumedFileName,
|
||||
const std::string style, const std::vector<unsigned> ranges)
|
||||
-> Result {
|
||||
return clang::format::format_range(str, assumedFileName, style, true,
|
||||
std::move(ranges));
|
||||
}
|
||||
|
||||
auto set_fallback_style(const std::string style) -> void {
|
||||
FallbackStyle = style;
|
||||
}
|
||||
|
||||
auto set_sort_includes(const bool sort) -> void { SortIncludes = sort; }
|
||||
|
||||
auto dump_config(const std::string style, const std::string FileName,
|
||||
const std::string code) -> Result {
|
||||
llvm::Expected<clang::format::FormatStyle> FormatStyle =
|
||||
clang::format::getStyle(style, FileName, FallbackStyle, code);
|
||||
if (!FormatStyle)
|
||||
return Err(llvm::toString(FormatStyle.takeError()));
|
||||
std::string Config = clang::format::configurationAsText(*FormatStyle);
|
||||
return Ok(Config);
|
||||
}
|
||||
24
frontend/src/common/prettier/plugins/clang/src/lib.h
Normal file
24
frontend/src/common/prettier/plugins/clang/src/lib.h
Normal file
@@ -0,0 +1,24 @@
|
||||
#ifndef CLANG_FORMAT_WASM_LIB_H_
|
||||
#define CLANG_FORMAT_WASM_LIB_H_
|
||||
#include <sstream>
|
||||
|
||||
struct Result {
|
||||
bool error;
|
||||
std::string content;
|
||||
};
|
||||
|
||||
auto version() -> std::string;
|
||||
auto format(const std::string str, const std::string assumedFileName, const std::string style) -> Result;
|
||||
auto format_byte(const std::string str,
|
||||
const std::string assumedFileName,
|
||||
const std::string style,
|
||||
const std::vector<unsigned> ranges) -> Result;
|
||||
auto format_line(const std::string str,
|
||||
const std::string assumedFileName,
|
||||
const std::string style,
|
||||
const std::vector<unsigned> ranges) -> Result;
|
||||
auto set_fallback_style(const std::string style) -> void;
|
||||
auto set_sort_includes(const bool sort) -> void;
|
||||
auto dump_config(const std::string style, const std::string FileName, const std::string code) -> Result;
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,42 @@
|
||||
set -Eeo pipefail
|
||||
|
||||
cd $(dirname $0)/..
|
||||
project_root=$(pwd)
|
||||
|
||||
rm -rf pkg
|
||||
mkdir -p pkg build
|
||||
cd build
|
||||
|
||||
export CC=$(which clang)
|
||||
export CXX=$(which clang++)
|
||||
|
||||
emcmake cmake -G Ninja ..
|
||||
ninja clang-format-wasm
|
||||
|
||||
cd $project_root
|
||||
|
||||
if [[ ! -z "${WASM_OPT}" ]]; then
|
||||
wasm-opt -Os build/clang-format-esm.wasm -o build/clang-format-esm-Os.wasm
|
||||
wasm-opt -Oz build/clang-format-esm.wasm -o build/clang-format-esm-Oz.wasm
|
||||
fi
|
||||
|
||||
SMALLEST_WASM=$(ls -Sr build/clang-format-e*.wasm | head -1)
|
||||
|
||||
cp $SMALLEST_WASM pkg/clang-format.wasm
|
||||
cat src/template.js build/clang-format-esm.js >pkg/clang-format.js
|
||||
|
||||
# add shebang
|
||||
echo '#!/usr/bin/env node' | cat - ./build/clang-format-cli.js >./pkg/clang-format-cli.cjs
|
||||
cp ./build/clang-format-cli.wasm ./pkg/
|
||||
|
||||
cp ./src/clang-format.d.ts src/clang-format-*.js ./pkg/
|
||||
cp ./package.json LICENSE README.md .npmignore ./pkg/
|
||||
|
||||
# copy git-clang-format and clang-format-diff.py
|
||||
cp ./build/_deps/llvm_project-src/clang/tools/clang-format/git-clang-format ./pkg/
|
||||
cp ./build/_deps/llvm_project-src/clang/tools/clang-format/clang-format-diff.py ./pkg/
|
||||
|
||||
ls -lh ./pkg
|
||||
|
||||
# make sure repo is clean
|
||||
# git diff --exit-code
|
||||
@@ -0,0 +1,95 @@
|
||||
diff --git a/src/cli.cc b/src/cli.cc
|
||||
index 2861005..69ec009 100644
|
||||
--- a/src/cli.cc
|
||||
+++ b/src/cli.cc
|
||||
@@ -12,7 +12,7 @@
|
||||
///
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
-#include "../../lib/Format/MatchFilePath.h"
|
||||
+#include "clang/../../lib/Format/MatchFilePath.h"
|
||||
#include "clang/Basic/Diagnostic.h"
|
||||
#include "clang/Basic/DiagnosticOptions.h"
|
||||
#include "clang/Basic/FileManager.h"
|
||||
@@ -27,6 +27,8 @@
|
||||
#include "llvm/Support/Process.h"
|
||||
#include <fstream>
|
||||
|
||||
+#include "CustomFileSystem.h"
|
||||
+
|
||||
using namespace llvm;
|
||||
using clang::tooling::Replacements;
|
||||
|
||||
@@ -448,9 +450,12 @@ static bool format(StringRef FileName, bool ErrorOnIncompleteFormat = false) {
|
||||
return true;
|
||||
}
|
||||
|
||||
+ auto RealFS = vfs::getRealFileSystem();
|
||||
+ auto CustomFS = new vfs::CustomFileSystem(RealFS);
|
||||
+ IntrusiveRefCntPtr<vfs::FileSystem> CustomFSPtr(CustomFS);
|
||||
Expected<FormatStyle> FormatStyle =
|
||||
getStyle(Style, AssumedFileName, FallbackStyle, Code->getBuffer(),
|
||||
- nullptr, WNoErrorList.isSet(WNoError::Unknown));
|
||||
+ CustomFSPtr.get(), WNoErrorList.isSet(WNoError::Unknown));
|
||||
if (!FormatStyle) {
|
||||
llvm::errs() << toString(FormatStyle.takeError()) << "\n";
|
||||
return true;
|
||||
@@ -571,10 +576,15 @@ static int dumpConfig() {
|
||||
}
|
||||
Code = std::move(CodeOrErr.get());
|
||||
}
|
||||
+
|
||||
+ auto RealFS = vfs::getRealFileSystem();
|
||||
+ auto CustomFS = new vfs::CustomFileSystem(RealFS);
|
||||
+ IntrusiveRefCntPtr<vfs::FileSystem> CustomFSPtr(CustomFS);
|
||||
+
|
||||
Expected<clang::format::FormatStyle> FormatStyle = clang::format::getStyle(
|
||||
Style,
|
||||
FileNames.empty() || FileNames[0] == "-" ? AssumeFileName : FileNames[0],
|
||||
- FallbackStyle, Code ? Code->getBuffer() : "");
|
||||
+ FallbackStyle, Code ? Code->getBuffer() : "", CustomFSPtr.get());
|
||||
if (!FormatStyle) {
|
||||
llvm::errs() << toString(FormatStyle.takeError()) << "\n";
|
||||
return 1;
|
||||
@@ -607,24 +617,26 @@ static bool isIgnored(StringRef FilePath) {
|
||||
String Path;
|
||||
String AbsPath{FilePath};
|
||||
|
||||
+ auto PathStyle = vfs::getPathStyle();
|
||||
+
|
||||
using namespace llvm::sys::path;
|
||||
- make_absolute(AbsPath);
|
||||
- remove_dots(AbsPath, /*remove_dot_dot=*/true);
|
||||
+ vfs::make_absolute(AbsPath);
|
||||
+ remove_dots(AbsPath, /*remove_dot_dot=*/true, PathStyle);
|
||||
|
||||
- if (StringRef Dir{parent_path(AbsPath)}; PrevDir != Dir) {
|
||||
+ if (StringRef Dir{parent_path(AbsPath, PathStyle)}; PrevDir != Dir) {
|
||||
PrevDir = Dir;
|
||||
|
||||
for (;;) {
|
||||
Path = Dir;
|
||||
- append(Path, ".clang-format-ignore");
|
||||
+ append(Path, PathStyle, ".clang-format-ignore");
|
||||
if (is_regular_file(Path))
|
||||
break;
|
||||
- Dir = parent_path(Dir);
|
||||
+ Dir = parent_path(Dir, PathStyle);
|
||||
if (Dir.empty())
|
||||
return false;
|
||||
}
|
||||
|
||||
- IgnoreDir = convert_to_slash(Dir);
|
||||
+ IgnoreDir = convert_to_slash(Dir, PathStyle);
|
||||
|
||||
std::ifstream IgnoreFile{Path.c_str()};
|
||||
if (!IgnoreFile.good())
|
||||
@@ -644,7 +656,7 @@ static bool isIgnored(StringRef FilePath) {
|
||||
if (IgnoreDir.empty())
|
||||
return false;
|
||||
|
||||
- const auto Pathname{convert_to_slash(AbsPath)};
|
||||
+ const auto Pathname{convert_to_slash(AbsPath, PathStyle)};
|
||||
for (const auto &Pat : Patterns) {
|
||||
const bool IsNegated = Pat[0] == '!';
|
||||
StringRef Pattern{Pat};
|
||||
@@ -0,0 +1,26 @@
|
||||
current_dir=$(pwd)
|
||||
tmp_dir=$(mktemp -d)
|
||||
|
||||
cd $tmp_dir
|
||||
|
||||
git init
|
||||
|
||||
cp $current_dir/build/_deps/llvm_project-src/clang/tools/clang-format/ClangFormat.cpp ./cli.cc
|
||||
|
||||
git add -f .
|
||||
git commit -m "init"
|
||||
|
||||
cp $current_dir/src/cli.cc ./cli.cc
|
||||
|
||||
git add -f .
|
||||
git diff \
|
||||
--cached \
|
||||
--no-color \
|
||||
--ignore-space-at-eol \
|
||||
--no-ext-diff \
|
||||
--src-prefix=a/src/ \
|
||||
--dst-prefix=b/src/ \
|
||||
>$current_dir/scripts/cli.patch || true
|
||||
|
||||
rm -rf $tmp_dir
|
||||
|
||||
146
frontend/src/common/prettier/plugins/clang/src/template.js
Normal file
146
frontend/src/common/prettier/plugins/clang/src/template.js
Normal file
@@ -0,0 +1,146 @@
|
||||
/* @ts-self-types="./clang-format.d.ts" */
|
||||
async function load(module) {
|
||||
if (typeof Response === "function" && module instanceof Response) {
|
||||
if ("compileStreaming" in WebAssembly) {
|
||||
try {
|
||||
return await WebAssembly.compileStreaming(module);
|
||||
} catch (e) {
|
||||
if (module.headers.get("Content-Type") !== "application/wasm") {
|
||||
console.warn(
|
||||
"`WebAssembly.compileStreaming` failed because your server does not serve wasm with `application/wasm` MIME type. Falling back to `WebAssembly.instantiate` which is slower. Original error:\n",
|
||||
e,
|
||||
);
|
||||
} else {
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return module.arrayBuffer();
|
||||
}
|
||||
|
||||
return module;
|
||||
}
|
||||
|
||||
let wasm;
|
||||
export default async function initAsync(input) {
|
||||
if (wasm !== undefined) {
|
||||
return wasm;
|
||||
}
|
||||
|
||||
if (typeof input === "undefined") {
|
||||
input = new URL("clang-format.wasm", import.meta.url);
|
||||
}
|
||||
|
||||
if (
|
||||
typeof input === "string" ||
|
||||
(typeof Request === "function" && input instanceof Request) ||
|
||||
(typeof URL === "function" && input instanceof URL)
|
||||
) {
|
||||
input = fetch(input);
|
||||
}
|
||||
|
||||
wasm = await load(await input).then((wasm) => Module({ wasm }));
|
||||
assert_init = () => {};
|
||||
}
|
||||
|
||||
function assert_init() {
|
||||
throw new Error("uninit");
|
||||
}
|
||||
|
||||
export function version() {
|
||||
assert_init();
|
||||
return wasm.version();
|
||||
}
|
||||
|
||||
export function set_fallback_style(style) {
|
||||
assert_init();
|
||||
wasm.set_fallback_style(style);
|
||||
}
|
||||
|
||||
export function set_sort_includes(sort) {
|
||||
assert_init();
|
||||
wasm.set_sort_includes(sort);
|
||||
}
|
||||
|
||||
function unwrap(result) {
|
||||
const { error, content } = result;
|
||||
if (error) {
|
||||
throw Error(content);
|
||||
}
|
||||
return content;
|
||||
}
|
||||
|
||||
export function format(content, filename = "<stdin>", style = "LLVM") {
|
||||
assert_init();
|
||||
const result = wasm.format(content, filename, style);
|
||||
return unwrap(result);
|
||||
}
|
||||
|
||||
export function format_line_range(
|
||||
content,
|
||||
range,
|
||||
filename = "<stdin>",
|
||||
style = "LLVM",
|
||||
) {
|
||||
assert_init();
|
||||
const rangeList = new wasm.RangeList();
|
||||
for (const [fromLine, toLine] of range) {
|
||||
if (fromLine < 1) {
|
||||
throw Error("start line should be at least 1");
|
||||
}
|
||||
if (fromLine > toLine) {
|
||||
throw Error("start line should not exceed end line");
|
||||
}
|
||||
rangeList.push_back(fromLine);
|
||||
rangeList.push_back(toLine);
|
||||
}
|
||||
|
||||
const result = wasm.format_line(content, filename, style, rangeList);
|
||||
rangeList.delete();
|
||||
return unwrap(result);
|
||||
}
|
||||
|
||||
export function format_byte_range(
|
||||
content,
|
||||
range,
|
||||
filename = "<stdin>",
|
||||
style = "LLVM",
|
||||
) {
|
||||
assert_init();
|
||||
const rangeList = new wasm.RangeList();
|
||||
|
||||
if (range.length === 1 && range[0].length === 1) {
|
||||
rangeList.push_back(range[0][0]);
|
||||
} else {
|
||||
for (const [offset, length] of range) {
|
||||
if (offset < 0) {
|
||||
throw Error("start offset should be at least 0");
|
||||
}
|
||||
if (length < 0) {
|
||||
throw Error("length should be at least 0");
|
||||
}
|
||||
rangeList.push_back(offset);
|
||||
rangeList.push_back(length);
|
||||
}
|
||||
}
|
||||
|
||||
const result = wasm.format_byte(content, filename, style, rangeList);
|
||||
rangeList.delete();
|
||||
return unwrap(result);
|
||||
}
|
||||
|
||||
export function dump_config({
|
||||
style = "file",
|
||||
filename = "<stdin>",
|
||||
code = "",
|
||||
} = {}) {
|
||||
assert_init();
|
||||
const result = wasm.dump_config(style, filename, code);
|
||||
return unwrap(result);
|
||||
}
|
||||
|
||||
export {
|
||||
format_byte_range as formatByteRange,
|
||||
format_line_range as formatLineRange,
|
||||
};
|
||||
32
frontend/src/common/prettier/plugins/dart/dart_fmt.d.ts
vendored
Normal file
32
frontend/src/common/prettier/plugins/dart/dart_fmt.d.ts
vendored
Normal file
@@ -0,0 +1,32 @@
|
||||
export function format(input: string, filename: string, config?: LayoutConfig): string;
|
||||
|
||||
interface LayoutConfig {
|
||||
line_width?: number;
|
||||
line_ending?: "lf" | "crlf";
|
||||
language_version?: string;
|
||||
}
|
||||
|
||||
export type InitInput = RequestInfo | URL | Response | BufferSource | WebAssembly.Module;
|
||||
|
||||
export type InitOutput = unknown;
|
||||
|
||||
// export type SyncInitInput = BufferSource | WebAssembly.Module;
|
||||
// /**
|
||||
// * Instantiates the given `module`, which can either be bytes or
|
||||
// * a precompiled `WebAssembly.Module`.
|
||||
// *
|
||||
// * @param {SyncInitInput} module
|
||||
// *
|
||||
// * @returns {InitOutput}
|
||||
// */
|
||||
// export function initSync(module: SyncInitInput): InitOutput;
|
||||
|
||||
/**
|
||||
* If `module_or_path` is {RequestInfo} or {URL}, makes a request and
|
||||
* for everything else, calls `WebAssembly.instantiate` directly.
|
||||
*
|
||||
* @param {InitInput | Promise<InitInput>} module_or_path
|
||||
*
|
||||
* @returns {Promise<InitOutput>}
|
||||
*/
|
||||
export default function init(module_or_path?: InitInput | Promise<InitInput>): Promise<InitOutput>;
|
||||
84
frontend/src/common/prettier/plugins/dart/dart_fmt.js
Normal file
84
frontend/src/common/prettier/plugins/dart/dart_fmt.js
Normal file
@@ -0,0 +1,84 @@
|
||||
import { format as dart_fmt, instantiate, invoke } from "./dart_fmt.mjs";
|
||||
|
||||
let wasm;
|
||||
|
||||
function get_imports() {}
|
||||
function init_memory() {}
|
||||
|
||||
function normalize(module) {
|
||||
if (!(module instanceof WebAssembly.Module)) {
|
||||
return new WebAssembly.Module(module);
|
||||
}
|
||||
return module;
|
||||
}
|
||||
|
||||
export default async function (input) {
|
||||
if (wasm !== undefined) return wasm;
|
||||
|
||||
if (typeof input === "undefined") {
|
||||
input = new URL("dart_fmt.wasm", import.meta.url);
|
||||
}
|
||||
const imports = get_imports();
|
||||
|
||||
if (
|
||||
typeof input === "string" ||
|
||||
(typeof Request === "function" && input instanceof Request) ||
|
||||
(typeof URL === "function" && input instanceof URL)
|
||||
) {
|
||||
input = fetch(input);
|
||||
}
|
||||
|
||||
init_memory(imports);
|
||||
|
||||
wasm = await load(await input)
|
||||
.then(normalize)
|
||||
.then(instantiate);
|
||||
|
||||
invoke(wasm);
|
||||
|
||||
return wasm;
|
||||
}
|
||||
|
||||
async function load(module) {
|
||||
if (typeof Response === "function" && module instanceof Response) {
|
||||
if ("compileStreaming" in WebAssembly) {
|
||||
try {
|
||||
return await WebAssembly.compileStreaming(module);
|
||||
} catch (e) {
|
||||
if (module.headers.get("Content-Type") != "application/wasm") {
|
||||
console.warn(
|
||||
"`WebAssembly.compileStreaming` failed because your server does not serve wasm with `application/wasm` MIME type. Falling back to `WebAssembly.instantiate` which is slower. Original error:\n",
|
||||
e,
|
||||
);
|
||||
} else {
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return module.arrayBuffer();
|
||||
}
|
||||
|
||||
return module;
|
||||
}
|
||||
|
||||
export function format(source, filename = "stdin.dart", config = {}) {
|
||||
const options = { lineEnding: "\n" };
|
||||
if (config.line_width) {
|
||||
options.pageWidth = config.line_width;
|
||||
}
|
||||
if (options.line_ending === "crlf") {
|
||||
options.lineEnding = "\r\n";
|
||||
}
|
||||
if(options.language_version) {
|
||||
options.languageVersion = options.language_version;
|
||||
}
|
||||
|
||||
const result = dart_fmt(source, filename, JSON.stringify(options));
|
||||
const err = result[0] === "x";
|
||||
const output = result.slice(1);
|
||||
if (err) {
|
||||
throw new Error(output);
|
||||
}
|
||||
return output;
|
||||
}
|
||||
350
frontend/src/common/prettier/plugins/dart/dart_fmt.mjs
Normal file
350
frontend/src/common/prettier/plugins/dart/dart_fmt.mjs
Normal file
@@ -0,0 +1,350 @@
|
||||
|
||||
// `modulePromise` is a promise to the `WebAssembly.module` object to be
|
||||
// instantiated.
|
||||
// `importObjectPromise` is a promise to an object that contains any additional
|
||||
// imports needed by the module that aren't provided by the standard runtime.
|
||||
// The fields on this object will be merged into the importObject with which
|
||||
// the module will be instantiated.
|
||||
// This function returns a promise to the instantiated module.
|
||||
export const instantiate = async (modulePromise, importObjectPromise) => {
|
||||
let dartInstance;
|
||||
|
||||
// Prints to the console
|
||||
function printToConsole(value) {
|
||||
if (typeof dartPrint == "function") {
|
||||
dartPrint(value);
|
||||
return;
|
||||
}
|
||||
if (typeof console == "object" && typeof console.log != "undefined") {
|
||||
console.log(value);
|
||||
return;
|
||||
}
|
||||
if (typeof print == "function") {
|
||||
print(value);
|
||||
return;
|
||||
}
|
||||
|
||||
throw "Unable to print message: " + js;
|
||||
}
|
||||
|
||||
// Converts a Dart List to a JS array. Any Dart objects will be converted, but
|
||||
// this will be cheap for JSValues.
|
||||
function arrayFromDartList(constructor, list) {
|
||||
const exports = dartInstance.exports;
|
||||
const read = exports.$listRead;
|
||||
const length = exports.$listLength(list);
|
||||
const array = new constructor(length);
|
||||
for (let i = 0; i < length; i++) {
|
||||
array[i] = read(list, i);
|
||||
}
|
||||
return array;
|
||||
}
|
||||
|
||||
// A special symbol attached to functions that wrap Dart functions.
|
||||
const jsWrappedDartFunctionSymbol = Symbol("JSWrappedDartFunction");
|
||||
|
||||
function finalizeWrapper(dartFunction, wrapped) {
|
||||
wrapped.dartFunction = dartFunction;
|
||||
wrapped[jsWrappedDartFunctionSymbol] = true;
|
||||
return wrapped;
|
||||
}
|
||||
|
||||
// Imports
|
||||
const dart2wasm = {
|
||||
|
||||
_49: v => v.toString(),
|
||||
_64: s => {
|
||||
if (!/^\s*[+-]?(?:Infinity|NaN|(?:\.\d+|\d+(?:\.\d*)?)(?:[eE][+-]?\d+)?)\s*$/.test(s)) {
|
||||
return NaN;
|
||||
}
|
||||
return parseFloat(s);
|
||||
},
|
||||
_65: () => {
|
||||
let stackString = new Error().stack.toString();
|
||||
let frames = stackString.split('\n');
|
||||
let drop = 2;
|
||||
if (frames[0] === 'Error') {
|
||||
drop += 1;
|
||||
}
|
||||
return frames.slice(drop).join('\n');
|
||||
},
|
||||
_69: () => {
|
||||
// On browsers return `globalThis.location.href`
|
||||
if (globalThis.location != null) {
|
||||
return globalThis.location.href;
|
||||
}
|
||||
return null;
|
||||
},
|
||||
_70: () => {
|
||||
return typeof process != "undefined" &&
|
||||
Object.prototype.toString.call(process) == "[object process]" &&
|
||||
process.platform == "win32"
|
||||
},
|
||||
_85: s => JSON.stringify(s),
|
||||
_86: s => printToConsole(s),
|
||||
_87: a => a.join(''),
|
||||
_90: (s, t) => s.split(t),
|
||||
_91: s => s.toLowerCase(),
|
||||
_92: s => s.toUpperCase(),
|
||||
_93: s => s.trim(),
|
||||
_97: (s, p, i) => s.indexOf(p, i),
|
||||
_98: (s, p, i) => s.lastIndexOf(p, i),
|
||||
_100: Object.is,
|
||||
_101: s => s.toUpperCase(),
|
||||
_102: s => s.toLowerCase(),
|
||||
_103: (a, i) => a.push(i),
|
||||
_113: (a, b) => a == b ? 0 : (a > b ? 1 : -1),
|
||||
_114: a => a.length,
|
||||
_116: (a, i) => a[i],
|
||||
_117: (a, i, v) => a[i] = v,
|
||||
_120: (o, start, length) => new Uint8Array(o.buffer, o.byteOffset + start, length),
|
||||
_121: (o, start, length) => new Int8Array(o.buffer, o.byteOffset + start, length),
|
||||
_122: (o, start, length) => new Uint8ClampedArray(o.buffer, o.byteOffset + start, length),
|
||||
_123: (o, start, length) => new Uint16Array(o.buffer, o.byteOffset + start, length),
|
||||
_124: (o, start, length) => new Int16Array(o.buffer, o.byteOffset + start, length),
|
||||
_125: (o, start, length) => new Uint32Array(o.buffer, o.byteOffset + start, length),
|
||||
_126: (o, start, length) => new Int32Array(o.buffer, o.byteOffset + start, length),
|
||||
_129: (o, start, length) => new Float32Array(o.buffer, o.byteOffset + start, length),
|
||||
_130: (o, start, length) => new Float64Array(o.buffer, o.byteOffset + start, length),
|
||||
_133: (o) => new DataView(o.buffer, o.byteOffset, o.byteLength),
|
||||
_137: Function.prototype.call.bind(Object.getOwnPropertyDescriptor(DataView.prototype, 'byteLength').get),
|
||||
_138: (b, o) => new DataView(b, o),
|
||||
_140: Function.prototype.call.bind(DataView.prototype.getUint8),
|
||||
_141: Function.prototype.call.bind(DataView.prototype.setUint8),
|
||||
_142: Function.prototype.call.bind(DataView.prototype.getInt8),
|
||||
_143: Function.prototype.call.bind(DataView.prototype.setInt8),
|
||||
_144: Function.prototype.call.bind(DataView.prototype.getUint16),
|
||||
_145: Function.prototype.call.bind(DataView.prototype.setUint16),
|
||||
_146: Function.prototype.call.bind(DataView.prototype.getInt16),
|
||||
_147: Function.prototype.call.bind(DataView.prototype.setInt16),
|
||||
_148: Function.prototype.call.bind(DataView.prototype.getUint32),
|
||||
_149: Function.prototype.call.bind(DataView.prototype.setUint32),
|
||||
_150: Function.prototype.call.bind(DataView.prototype.getInt32),
|
||||
_151: Function.prototype.call.bind(DataView.prototype.setInt32),
|
||||
_156: Function.prototype.call.bind(DataView.prototype.getFloat32),
|
||||
_157: Function.prototype.call.bind(DataView.prototype.setFloat32),
|
||||
_158: Function.prototype.call.bind(DataView.prototype.getFloat64),
|
||||
_159: Function.prototype.call.bind(DataView.prototype.setFloat64),
|
||||
_165: x0 => format = x0,
|
||||
_166: f => finalizeWrapper(f, function(x0,x1,x2) { return dartInstance.exports._166(f,arguments.length,x0,x1,x2) }),
|
||||
_184: (c) =>
|
||||
queueMicrotask(() => dartInstance.exports.$invokeCallback(c)),
|
||||
_187: (s, m) => {
|
||||
try {
|
||||
return new RegExp(s, m);
|
||||
} catch (e) {
|
||||
return String(e);
|
||||
}
|
||||
},
|
||||
_188: (x0,x1) => x0.exec(x1),
|
||||
_189: (x0,x1) => x0.test(x1),
|
||||
_190: (x0,x1) => x0.exec(x1),
|
||||
_191: (x0,x1) => x0.exec(x1),
|
||||
_192: x0 => x0.pop(),
|
||||
_198: o => o === undefined,
|
||||
_199: o => typeof o === 'boolean',
|
||||
_200: o => typeof o === 'number',
|
||||
_202: o => typeof o === 'string',
|
||||
_205: o => o instanceof Int8Array,
|
||||
_206: o => o instanceof Uint8Array,
|
||||
_207: o => o instanceof Uint8ClampedArray,
|
||||
_208: o => o instanceof Int16Array,
|
||||
_209: o => o instanceof Uint16Array,
|
||||
_210: o => o instanceof Int32Array,
|
||||
_211: o => o instanceof Uint32Array,
|
||||
_212: o => o instanceof Float32Array,
|
||||
_213: o => o instanceof Float64Array,
|
||||
_214: o => o instanceof ArrayBuffer,
|
||||
_215: o => o instanceof DataView,
|
||||
_216: o => o instanceof Array,
|
||||
_217: o => typeof o === 'function' && o[jsWrappedDartFunctionSymbol] === true,
|
||||
_220: o => o instanceof RegExp,
|
||||
_221: (l, r) => l === r,
|
||||
_222: o => o,
|
||||
_223: o => o,
|
||||
_224: o => o,
|
||||
_225: b => !!b,
|
||||
_226: o => o.length,
|
||||
_229: (o, i) => o[i],
|
||||
_230: f => f.dartFunction,
|
||||
_231: l => arrayFromDartList(Int8Array, l),
|
||||
_232: (data, length) => {
|
||||
const jsBytes = new Uint8Array(length);
|
||||
const getByte = dartInstance.exports.$uint8ListGet;
|
||||
for (let i = 0; i < length; i++) {
|
||||
jsBytes[i] = getByte(data, i);
|
||||
}
|
||||
return jsBytes;
|
||||
},
|
||||
_233: l => arrayFromDartList(Uint8ClampedArray, l),
|
||||
_234: l => arrayFromDartList(Int16Array, l),
|
||||
_235: l => arrayFromDartList(Uint16Array, l),
|
||||
_236: l => arrayFromDartList(Int32Array, l),
|
||||
_237: l => arrayFromDartList(Uint32Array, l),
|
||||
_238: l => arrayFromDartList(Float32Array, l),
|
||||
_239: l => arrayFromDartList(Float64Array, l),
|
||||
_240: (data, length) => {
|
||||
const read = dartInstance.exports.$byteDataGetUint8;
|
||||
const view = new DataView(new ArrayBuffer(length));
|
||||
for (let i = 0; i < length; i++) {
|
||||
view.setUint8(i, read(data, i));
|
||||
}
|
||||
return view;
|
||||
},
|
||||
_241: l => arrayFromDartList(Array, l),
|
||||
_242: (s, length) => {
|
||||
if (length == 0) return '';
|
||||
|
||||
const read = dartInstance.exports.$stringRead1;
|
||||
let result = '';
|
||||
let index = 0;
|
||||
const chunkLength = Math.min(length - index, 500);
|
||||
let array = new Array(chunkLength);
|
||||
while (index < length) {
|
||||
const newChunkLength = Math.min(length - index, 500);
|
||||
for (let i = 0; i < newChunkLength; i++) {
|
||||
array[i] = read(s, index++);
|
||||
}
|
||||
if (newChunkLength < chunkLength) {
|
||||
array = array.slice(0, newChunkLength);
|
||||
}
|
||||
result += String.fromCharCode(...array);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
,
|
||||
_243: (s, length) => {
|
||||
if (length == 0) return '';
|
||||
|
||||
const read = dartInstance.exports.$stringRead2;
|
||||
let result = '';
|
||||
let index = 0;
|
||||
const chunkLength = Math.min(length - index, 500);
|
||||
let array = new Array(chunkLength);
|
||||
while (index < length) {
|
||||
const newChunkLength = Math.min(length - index, 500);
|
||||
for (let i = 0; i < newChunkLength; i++) {
|
||||
array[i] = read(s, index++);
|
||||
}
|
||||
if (newChunkLength < chunkLength) {
|
||||
array = array.slice(0, newChunkLength);
|
||||
}
|
||||
result += String.fromCharCode(...array);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
,
|
||||
_244: (s) => {
|
||||
let length = s.length;
|
||||
let range = 0;
|
||||
for (let i = 0; i < length; i++) {
|
||||
range |= s.codePointAt(i);
|
||||
}
|
||||
const exports = dartInstance.exports;
|
||||
if (range < 256) {
|
||||
if (length <= 10) {
|
||||
if (length == 1) {
|
||||
return exports.$stringAllocate1_1(s.codePointAt(0));
|
||||
}
|
||||
if (length == 2) {
|
||||
return exports.$stringAllocate1_2(s.codePointAt(0), s.codePointAt(1));
|
||||
}
|
||||
if (length == 3) {
|
||||
return exports.$stringAllocate1_3(s.codePointAt(0), s.codePointAt(1), s.codePointAt(2));
|
||||
}
|
||||
if (length == 4) {
|
||||
return exports.$stringAllocate1_4(s.codePointAt(0), s.codePointAt(1), s.codePointAt(2), s.codePointAt(3));
|
||||
}
|
||||
if (length == 5) {
|
||||
return exports.$stringAllocate1_5(s.codePointAt(0), s.codePointAt(1), s.codePointAt(2), s.codePointAt(3), s.codePointAt(4));
|
||||
}
|
||||
if (length == 6) {
|
||||
return exports.$stringAllocate1_6(s.codePointAt(0), s.codePointAt(1), s.codePointAt(2), s.codePointAt(3), s.codePointAt(4), s.codePointAt(5));
|
||||
}
|
||||
if (length == 7) {
|
||||
return exports.$stringAllocate1_7(s.codePointAt(0), s.codePointAt(1), s.codePointAt(2), s.codePointAt(3), s.codePointAt(4), s.codePointAt(5), s.codePointAt(6));
|
||||
}
|
||||
if (length == 8) {
|
||||
return exports.$stringAllocate1_8(s.codePointAt(0), s.codePointAt(1), s.codePointAt(2), s.codePointAt(3), s.codePointAt(4), s.codePointAt(5), s.codePointAt(6), s.codePointAt(7));
|
||||
}
|
||||
if (length == 9) {
|
||||
return exports.$stringAllocate1_9(s.codePointAt(0), s.codePointAt(1), s.codePointAt(2), s.codePointAt(3), s.codePointAt(4), s.codePointAt(5), s.codePointAt(6), s.codePointAt(7), s.codePointAt(8));
|
||||
}
|
||||
if (length == 10) {
|
||||
return exports.$stringAllocate1_10(s.codePointAt(0), s.codePointAt(1), s.codePointAt(2), s.codePointAt(3), s.codePointAt(4), s.codePointAt(5), s.codePointAt(6), s.codePointAt(7), s.codePointAt(8), s.codePointAt(9));
|
||||
}
|
||||
}
|
||||
const dartString = exports.$stringAllocate1(length);
|
||||
const write = exports.$stringWrite1;
|
||||
for (let i = 0; i < length; i++) {
|
||||
write(dartString, i, s.codePointAt(i));
|
||||
}
|
||||
return dartString;
|
||||
} else {
|
||||
const dartString = exports.$stringAllocate2(length);
|
||||
const write = exports.$stringWrite2;
|
||||
for (let i = 0; i < length; i++) {
|
||||
write(dartString, i, s.charCodeAt(i));
|
||||
}
|
||||
return dartString;
|
||||
}
|
||||
}
|
||||
,
|
||||
_247: l => new Array(l),
|
||||
_251: (o, p) => o[p],
|
||||
_255: o => String(o),
|
||||
_260: x0 => x0.index,
|
||||
_262: x0 => x0.length,
|
||||
_264: (x0,x1) => x0[x1],
|
||||
_265: (x0,x1) => x0.exec(x1),
|
||||
_267: x0 => x0.flags,
|
||||
_268: x0 => x0.multiline,
|
||||
_269: x0 => x0.ignoreCase,
|
||||
_270: x0 => x0.unicode,
|
||||
_271: x0 => x0.dotAll,
|
||||
_272: (x0,x1) => x0.lastIndex = x1
|
||||
};
|
||||
|
||||
const baseImports = {
|
||||
dart2wasm: dart2wasm,
|
||||
|
||||
|
||||
Math: Math,
|
||||
Date: Date,
|
||||
Object: Object,
|
||||
Array: Array,
|
||||
Reflect: Reflect,
|
||||
};
|
||||
|
||||
const jsStringPolyfill = {
|
||||
"charCodeAt": (s, i) => s.charCodeAt(i),
|
||||
"compare": (s1, s2) => {
|
||||
if (s1 < s2) return -1;
|
||||
if (s1 > s2) return 1;
|
||||
return 0;
|
||||
},
|
||||
"concat": (s1, s2) => s1 + s2,
|
||||
"equals": (s1, s2) => s1 === s2,
|
||||
"fromCharCode": (i) => String.fromCharCode(i),
|
||||
"length": (s) => s?.length||0,
|
||||
"substring": (s, a, b) => s.substring(a, b),
|
||||
};
|
||||
|
||||
dartInstance = await WebAssembly.instantiate(await modulePromise, {
|
||||
...baseImports,
|
||||
...(await importObjectPromise),
|
||||
"wasm:js-string": jsStringPolyfill,
|
||||
});
|
||||
|
||||
return dartInstance;
|
||||
}
|
||||
|
||||
// Call the main function for the instantiated module
|
||||
// `moduleInstance` is the instantiated dart2wasm module
|
||||
// `args` are any arguments that should be passed into the main function.
|
||||
export const invoke = (moduleInstance, ...args) => {
|
||||
moduleInstance.exports.$invokeMain(args);
|
||||
}
|
||||
|
||||
|
||||
export let format;
|
||||
BIN
frontend/src/common/prettier/plugins/dart/dart_fmt.unopt.wasm
Normal file
BIN
frontend/src/common/prettier/plugins/dart/dart_fmt.unopt.wasm
Normal file
Binary file not shown.
File diff suppressed because one or more lines are too long
BIN
frontend/src/common/prettier/plugins/dart/dart_fmt.wasm
Normal file
BIN
frontend/src/common/prettier/plugins/dart/dart_fmt.wasm
Normal file
Binary file not shown.
File diff suppressed because one or more lines are too long
10
frontend/src/common/prettier/plugins/dart/dart_fmt_node.js
Normal file
10
frontend/src/common/prettier/plugins/dart/dart_fmt_node.js
Normal file
@@ -0,0 +1,10 @@
|
||||
import fs from "node:fs/promises";
|
||||
import initAsync from "./dart_fmt.js";
|
||||
|
||||
const wasm = new URL("./dart_fmt.wasm", import.meta.url);
|
||||
|
||||
export default function __wbg_init(init = fs.readFile(wasm)) {
|
||||
return initAsync(init);
|
||||
}
|
||||
|
||||
export * from "./dart_fmt.js";
|
||||
@@ -0,0 +1,8 @@
|
||||
import initAsync from "./dart_fmt.js";
|
||||
import wasm from "./dart_fmt.wasm?url";
|
||||
|
||||
export default function __wbg_init(input = wasm) {
|
||||
return initAsync(input);
|
||||
}
|
||||
|
||||
export * from "./dart_fmt.js";
|
||||
132
frontend/src/common/prettier/plugins/dart/index.ts
Normal file
132
frontend/src/common/prettier/plugins/dart/index.ts
Normal file
@@ -0,0 +1,132 @@
|
||||
/**
|
||||
* Prettier Plugin for Dart formatting using dart_fmt WebAssembly
|
||||
*
|
||||
* This plugin provides support for formatting Dart files using the dart_fmt WASM implementation.
|
||||
* dart_fmt is the official Dart code formatter integrated into the Dart SDK.
|
||||
*/
|
||||
import type { Plugin, Parser, Printer } from 'prettier';
|
||||
|
||||
// Import the Dart formatter WASM module
|
||||
import dartInit, { format } from './dart_fmt_vite.js';
|
||||
|
||||
const parserName = 'dart';
|
||||
|
||||
// Language configuration
|
||||
const languages = [
|
||||
{
|
||||
name: 'Dart',
|
||||
aliases: ['dart'],
|
||||
parsers: [parserName],
|
||||
extensions: ['.dart'],
|
||||
aceMode: 'dart',
|
||||
tmScope: 'source.dart',
|
||||
linguistLanguageId: 103,
|
||||
vscodeLanguageIds: ['dart']
|
||||
}
|
||||
];
|
||||
|
||||
// Parser configuration
|
||||
const dartParser: Parser<string> = {
|
||||
astFormat: parserName,
|
||||
parse: (text: string) => text,
|
||||
locStart: () => 0,
|
||||
locEnd: (node: string) => node.length,
|
||||
};
|
||||
|
||||
// Lazy initialize Dart WASM module
|
||||
let initPromise: Promise<void> | null = null;
|
||||
let isInitialized = false;
|
||||
|
||||
function initDart(): Promise<void> {
|
||||
if (isInitialized) {
|
||||
return Promise.resolve();
|
||||
}
|
||||
|
||||
if (!initPromise) {
|
||||
initPromise = (async () => {
|
||||
try {
|
||||
await dartInit();
|
||||
isInitialized = true;
|
||||
} catch (error) {
|
||||
console.warn('Failed to initialize Dart WASM module:', error);
|
||||
initPromise = null;
|
||||
throw error;
|
||||
}
|
||||
})();
|
||||
}
|
||||
|
||||
return initPromise;
|
||||
}
|
||||
|
||||
// Printer configuration
|
||||
const dartPrinter: Printer<string> = {
|
||||
// @ts-expect-error -- Support async printer like shell plugin
|
||||
async print(path, options) {
|
||||
try {
|
||||
// Wait for initialization to complete
|
||||
await initDart();
|
||||
|
||||
const text = (path as any).getValue ? (path as any).getValue() : path.node;
|
||||
const config = getDartConfig(options);
|
||||
|
||||
// Format using dart_fmt (synchronous call)
|
||||
const formatted = format(text, undefined, config);
|
||||
|
||||
return formatted.trim();
|
||||
} catch (error) {
|
||||
console.warn('Dart formatting failed:', error);
|
||||
// Return original text if formatting fails
|
||||
return (path as any).getValue ? (path as any).getValue() : path.node;
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
|
||||
// Helper function to create Dart config from Prettier options
|
||||
function getDartConfig(options: any): any {
|
||||
const config: any = {};
|
||||
|
||||
// Map Prettier options to Dart formatter config
|
||||
if (options.printWidth !== undefined) {
|
||||
config.line_width = options.printWidth;
|
||||
}
|
||||
|
||||
if (options.endOfLine !== undefined) {
|
||||
config.line_ending = options.endOfLine === 'crlf' ? 'crlf' : 'lf';
|
||||
}
|
||||
|
||||
// Dart language version (if specified)
|
||||
if (options.dartLanguageVersion !== undefined) {
|
||||
config.language_version = options.dartLanguageVersion;
|
||||
}
|
||||
|
||||
return config;
|
||||
}
|
||||
|
||||
// Plugin options
|
||||
const options = {
|
||||
dartLanguageVersion: {
|
||||
since: '0.0.1',
|
||||
category: 'Format' as const,
|
||||
type: 'string' as const,
|
||||
default: undefined,
|
||||
description: 'Dart language version (e.g., "3.0", "2.17")'
|
||||
}
|
||||
};
|
||||
|
||||
// Plugin object
|
||||
const dartPlugin: Plugin = {
|
||||
languages,
|
||||
parsers: {
|
||||
[parserName]: dartParser,
|
||||
},
|
||||
printers: {
|
||||
[parserName]: dartPrinter,
|
||||
},
|
||||
options,
|
||||
};
|
||||
|
||||
export default dartPlugin;
|
||||
export { languages };
|
||||
export const parsers = dartPlugin.parsers;
|
||||
export const printers = dartPlugin.printers;
|
||||
31
frontend/src/common/prettier/plugins/dart/lib/binding.dart
Normal file
31
frontend/src/common/prettier/plugins/dart/lib/binding.dart
Normal file
@@ -0,0 +1,31 @@
|
||||
import 'dart:convert';
|
||||
import 'dart:js_interop';
|
||||
import 'package:dart_fmt/dart_fmt.dart';
|
||||
|
||||
class Options {
|
||||
final int? pageWidth;
|
||||
final String? lineEnding;
|
||||
final String? languageVersion;
|
||||
|
||||
Options.fromJson(Map<String, dynamic> json)
|
||||
: pageWidth = json['pageWidth'] as int?,
|
||||
lineEnding = json['lineEnding'] as String?,
|
||||
languageVersion = json['languageVersion'] as String?;
|
||||
}
|
||||
|
||||
String formatWrapper(String source, String filename, String options) {
|
||||
final config = Options.fromJson(jsonDecode(options));
|
||||
|
||||
try {
|
||||
return "o${format(source, filename, pageWidth: config.pageWidth, lineEnding: config.lineEnding, version: config.languageVersion)}";
|
||||
} catch (e) {
|
||||
return "x$e";
|
||||
}
|
||||
}
|
||||
|
||||
@JS('format')
|
||||
external set formatExport(JSFunction handler);
|
||||
|
||||
void main(List<String> arguments) {
|
||||
formatExport = formatWrapper.toJS;
|
||||
}
|
||||
5
frontend/src/common/prettier/plugins/dart/lib/build.sh
Normal file
5
frontend/src/common/prettier/plugins/dart/lib/build.sh
Normal file
@@ -0,0 +1,5 @@
|
||||
cd $(dirname $0)/..
|
||||
|
||||
dart compile wasm ./lib/binding.dart -o ./build/dart_fmt.wasm
|
||||
|
||||
|
||||
14
frontend/src/common/prettier/plugins/dart/lib/dart_fmt.dart
Normal file
14
frontend/src/common/prettier/plugins/dart/lib/dart_fmt.dart
Normal file
@@ -0,0 +1,14 @@
|
||||
import 'package:dart_style/dart_style.dart';
|
||||
import 'package:pub_semver/pub_semver.dart';
|
||||
|
||||
String format(String source, String filename,
|
||||
{int? pageWidth, String? lineEnding, String? version}) {
|
||||
final languageVersion = version != null
|
||||
? Version.parse(version)
|
||||
: DartFormatter.latestLanguageVersion;
|
||||
final formatter = DartFormatter(
|
||||
pageWidth: pageWidth,
|
||||
lineEnding: lineEnding,
|
||||
languageVersion: languageVersion);
|
||||
return formatter.format(source, uri: filename);
|
||||
}
|
||||
10
frontend/src/common/prettier/plugins/go/gofmt.d.ts
vendored
Normal file
10
frontend/src/common/prettier/plugins/go/gofmt.d.ts
vendored
Normal file
@@ -0,0 +1,10 @@
|
||||
export type InitInput =
|
||||
| RequestInfo
|
||||
| URL
|
||||
| Response
|
||||
| BufferSource
|
||||
| WebAssembly.Module;
|
||||
|
||||
export default function initAsync(wasm_url?: InitInput): Promise<void>;
|
||||
export declare function initSync(module: BufferSource | WebAssembly.Module): void;
|
||||
export declare function format(input: string): string;
|
||||
355
frontend/src/common/prettier/plugins/go/gofmt.js
Normal file
355
frontend/src/common/prettier/plugins/go/gofmt.js
Normal file
@@ -0,0 +1,355 @@
|
||||
// Copyright 2018 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
//
|
||||
// This file has been modified for use by the TinyGo compiler.
|
||||
|
||||
const encoder = new TextEncoder("utf-8");
|
||||
const decoder = new TextDecoder("utf-8");
|
||||
let reinterpretBuf = new DataView(new ArrayBuffer(8));
|
||||
var logLine = [];
|
||||
|
||||
class TinyGo {
|
||||
constructor() {
|
||||
this._callbackTimeouts = new Map();
|
||||
this._nextCallbackTimeoutID = 1;
|
||||
|
||||
const mem = () => {
|
||||
// The buffer may change when requesting more memory.
|
||||
return new DataView(this._inst.exports.memory.buffer);
|
||||
}
|
||||
|
||||
const unboxValue = (v_ref) => {
|
||||
reinterpretBuf.setBigInt64(0, v_ref, true);
|
||||
const f = reinterpretBuf.getFloat64(0, true);
|
||||
if (f === 0) {
|
||||
return undefined;
|
||||
}
|
||||
if (!isNaN(f)) {
|
||||
return f;
|
||||
}
|
||||
|
||||
const id = v_ref & 0xffffffffn;
|
||||
return this._values[id];
|
||||
}
|
||||
|
||||
|
||||
const loadValue = (addr) => {
|
||||
let v_ref = mem().getBigUint64(addr, true);
|
||||
return unboxValue(v_ref);
|
||||
}
|
||||
|
||||
const boxValue = (v) => {
|
||||
const nanHead = 0x7FF80000n;
|
||||
|
||||
if (typeof v === "number") {
|
||||
if (isNaN(v)) {
|
||||
return nanHead << 32n;
|
||||
}
|
||||
if (v === 0) {
|
||||
return (nanHead << 32n) | 1n;
|
||||
}
|
||||
reinterpretBuf.setFloat64(0, v, true);
|
||||
return reinterpretBuf.getBigInt64(0, true);
|
||||
}
|
||||
|
||||
switch (v) {
|
||||
case undefined:
|
||||
return 0n;
|
||||
case null:
|
||||
return (nanHead << 32n) | 2n;
|
||||
case true:
|
||||
return (nanHead << 32n) | 3n;
|
||||
case false:
|
||||
return (nanHead << 32n) | 4n;
|
||||
}
|
||||
|
||||
let id = this._ids.get(v);
|
||||
if (id === undefined) {
|
||||
id = this._idPool.pop();
|
||||
if (id === undefined) {
|
||||
id = BigInt(this._values.length);
|
||||
}
|
||||
this._values[id] = v;
|
||||
this._goRefCounts[id] = 0;
|
||||
this._ids.set(v, id);
|
||||
}
|
||||
this._goRefCounts[id]++;
|
||||
let typeFlag = 1n;
|
||||
switch (typeof v) {
|
||||
case "string":
|
||||
typeFlag = 2n;
|
||||
break;
|
||||
case "symbol":
|
||||
typeFlag = 3n;
|
||||
break;
|
||||
case "function":
|
||||
typeFlag = 4n;
|
||||
break;
|
||||
}
|
||||
return id | ((nanHead | typeFlag) << 32n);
|
||||
}
|
||||
|
||||
const storeValue = (addr, v) => {
|
||||
let v_ref = boxValue(v);
|
||||
mem().setBigUint64(addr, v_ref, true);
|
||||
}
|
||||
|
||||
const loadSlice = (array, len, cap) => {
|
||||
return new Uint8Array(this._inst.exports.memory.buffer, array, len);
|
||||
}
|
||||
|
||||
const loadSliceOfValues = (array, len, cap) => {
|
||||
const a = new Array(len);
|
||||
for (let i = 0; i < len; i++) {
|
||||
a[i] = loadValue(array + i * 8);
|
||||
}
|
||||
return a;
|
||||
}
|
||||
|
||||
const loadString = (ptr, len) => {
|
||||
return decoder.decode(new DataView(this._inst.exports.memory.buffer, ptr, len));
|
||||
}
|
||||
|
||||
const timeOrigin = Date.now() - performance.now();
|
||||
this.importObject = {
|
||||
wasi_snapshot_preview1: {
|
||||
// https://github.com/WebAssembly/WASI/blob/main/phases/snapshot/docs.md#fd_write
|
||||
fd_write: () => 0, // dummy
|
||||
},
|
||||
gojs: {
|
||||
// func ticks() float64
|
||||
"runtime.ticks": () => {
|
||||
return timeOrigin + performance.now();
|
||||
},
|
||||
|
||||
// func finalizeRef(v ref)
|
||||
"syscall/js.finalizeRef": (v_ref) => {
|
||||
reinterpretBuf.setBigInt64(0, v_ref, true);
|
||||
const f = reinterpretBuf.getFloat64(0, true);
|
||||
if (f === 0 || !isNaN(f)) {
|
||||
return;
|
||||
}
|
||||
const id = v_ref & 0xffffffffn;
|
||||
this._goRefCounts[id]--;
|
||||
if (this._goRefCounts[id] === 0) {
|
||||
const v = this._values[id];
|
||||
this._values[id] = null;
|
||||
this._ids.delete(v);
|
||||
this._idPool.push(id);
|
||||
}
|
||||
},
|
||||
|
||||
// func stringVal(value string) ref
|
||||
"syscall/js.stringVal": (value_ptr, value_len) => {
|
||||
const s = loadString(value_ptr, value_len);
|
||||
return boxValue(s);
|
||||
},
|
||||
|
||||
// func valueGet(v ref, p string) ref
|
||||
"syscall/js.valueGet": (v_ref, p_ptr, p_len) => {
|
||||
let prop = loadString(p_ptr, p_len);
|
||||
let v = unboxValue(v_ref);
|
||||
let result = Reflect.get(v, prop);
|
||||
return boxValue(result);
|
||||
},
|
||||
|
||||
// func valueSet(v ref, p string, x ref)
|
||||
"syscall/js.valueSet": (v_ref, p_ptr, p_len, x_ref) => {
|
||||
const v = unboxValue(v_ref);
|
||||
const p = loadString(p_ptr, p_len);
|
||||
const x = unboxValue(x_ref);
|
||||
Reflect.set(v, p, x);
|
||||
},
|
||||
|
||||
// func valueIndex(v ref, i int) ref
|
||||
"syscall/js.valueIndex": (v_ref, i) => {
|
||||
return boxValue(Reflect.get(unboxValue(v_ref), i));
|
||||
},
|
||||
|
||||
// valueSetIndex(v ref, i int, x ref)
|
||||
"syscall/js.valueSetIndex": (v_ref, i, x_ref) => {
|
||||
Reflect.set(unboxValue(v_ref), i, unboxValue(x_ref));
|
||||
},
|
||||
|
||||
// func valueCall(v ref, m string, args []ref) (ref, bool)
|
||||
"syscall/js.valueCall": (ret_addr, v_ref, m_ptr, m_len, args_ptr, args_len, args_cap) => {
|
||||
const v = unboxValue(v_ref);
|
||||
const name = loadString(m_ptr, m_len);
|
||||
const args = loadSliceOfValues(args_ptr, args_len, args_cap);
|
||||
try {
|
||||
const m = Reflect.get(v, name);
|
||||
storeValue(ret_addr, Reflect.apply(m, v, args));
|
||||
mem().setUint8(ret_addr + 8, 1);
|
||||
} catch (err) {
|
||||
storeValue(ret_addr, err);
|
||||
mem().setUint8(ret_addr + 8, 0);
|
||||
}
|
||||
},
|
||||
|
||||
// func valueNew(v ref, args []ref) (ref, bool)
|
||||
"syscall/js.valueNew": (ret_addr, v_ref, args_ptr, args_len, args_cap) => {
|
||||
const v = unboxValue(v_ref);
|
||||
const args = loadSliceOfValues(args_ptr, args_len, args_cap);
|
||||
try {
|
||||
storeValue(ret_addr, Reflect.construct(v, args));
|
||||
mem().setUint8(ret_addr + 8, 1);
|
||||
} catch (err) {
|
||||
storeValue(ret_addr, err);
|
||||
mem().setUint8(ret_addr+ 8, 0);
|
||||
}
|
||||
},
|
||||
|
||||
// func valueLength(v ref) int
|
||||
"syscall/js.valueLength": (v_ref) => {
|
||||
return unboxValue(v_ref).length;
|
||||
},
|
||||
|
||||
// valuePrepareString(v ref) (ref, int)
|
||||
"syscall/js.valuePrepareString": (ret_addr, v_ref) => {
|
||||
const s = String(unboxValue(v_ref));
|
||||
const str = encoder.encode(s);
|
||||
storeValue(ret_addr, str);
|
||||
mem().setInt32(ret_addr + 8, str.length, true);
|
||||
},
|
||||
|
||||
// valueLoadString(v ref, b []byte)
|
||||
"syscall/js.valueLoadString": (v_ref, slice_ptr, slice_len, slice_cap) => {
|
||||
const str = unboxValue(v_ref);
|
||||
loadSlice(slice_ptr, slice_len, slice_cap).set(str);
|
||||
},
|
||||
}
|
||||
};
|
||||
|
||||
// Go 1.20 uses 'env'. Go 1.21 uses 'gojs'.
|
||||
// For compatibility, we use both as long as Go 1.20 is supported.
|
||||
this.importObject.env = this.importObject.gojs;
|
||||
}
|
||||
|
||||
async run(instance) {
|
||||
this._inst = instance;
|
||||
this._values = [ // JS values that Go currently has references to, indexed by reference id
|
||||
NaN,
|
||||
0,
|
||||
null,
|
||||
true,
|
||||
false,
|
||||
// fake global
|
||||
{
|
||||
set format(fn){ instance.format = fn; },
|
||||
Array,
|
||||
Object,
|
||||
},
|
||||
this,
|
||||
];
|
||||
this._goRefCounts = []; // number of references that Go has to a JS value, indexed by reference id
|
||||
this._ids = new Map(); // mapping from JS values to reference ids
|
||||
this._idPool = []; // unused ids that have been garbage collected
|
||||
this.exited = false; // whether the Go program has exited
|
||||
|
||||
while (true) {
|
||||
const callbackPromise = new Promise((resolve) => {
|
||||
this._resolveCallbackPromise = () => {
|
||||
if (this.exited) {
|
||||
throw new Error("bad callback: Go program has already exited");
|
||||
}
|
||||
setTimeout(resolve, 0); // make sure it is asynchronous
|
||||
};
|
||||
});
|
||||
this._inst.exports._start();
|
||||
if (this.exited) {
|
||||
break;
|
||||
}
|
||||
await callbackPromise;
|
||||
}
|
||||
}
|
||||
|
||||
_resume() {
|
||||
if (this.exited) {
|
||||
throw new Error("Go program has already exited");
|
||||
}
|
||||
this._inst.exports.resume();
|
||||
if (this.exited) {
|
||||
this._resolveExitPromise();
|
||||
}
|
||||
}
|
||||
|
||||
_makeFuncWrapper(id) {
|
||||
const go = this;
|
||||
return function () {
|
||||
const event = { id: id, this: this, args: arguments };
|
||||
go._pendingEvent = event;
|
||||
go._resume();
|
||||
return event.result;
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* ================== End of wasm_exec.js ==================
|
||||
*/
|
||||
/**/let wasm;
|
||||
/**/async function __load(module, imports) {
|
||||
/**/ if (typeof Response === 'function' && module instanceof Response) {
|
||||
/**/ if (typeof WebAssembly.instantiateStreaming === 'function') {
|
||||
/**/ try { return await WebAssembly.instantiateStreaming(module, imports); }
|
||||
/**/ catch (e) {
|
||||
/**/ if (module.headers.get('Content-Type') != 'application/wasm') {
|
||||
/**/ console.warn("`WebAssembly.instantiateStreaming` failed because your server does not serve wasm with `application/wasm` MIME type. Falling back to `WebAssembly.instantiate` which is slower. Original error:\n", e);
|
||||
/**/ } else { throw e; }
|
||||
/**/ }
|
||||
/**/ }
|
||||
/**/ const bytes = await module.arrayBuffer();
|
||||
/**/ return await WebAssembly.instantiate(bytes, imports);
|
||||
/**/ } else {
|
||||
/**/ const instance = await WebAssembly.instantiate(module, imports);
|
||||
/**/ if (instance instanceof WebAssembly.Instance) return { instance, module };
|
||||
/**/ else return instance;
|
||||
/**/ }
|
||||
/**/}
|
||||
/**/function __finalize_init(instance) {
|
||||
/**/ return wasm = instance;
|
||||
/**/}
|
||||
/**/function __init_memory(imports, maybe_memory) { }
|
||||
/**/export function initSync(module) {
|
||||
/**/ if (wasm !== undefined) return wasm;
|
||||
/**/
|
||||
/**/ const go = new TinyGo();
|
||||
/**/ const imports = go.importObject;
|
||||
/**/
|
||||
/**/ __init_memory(imports);
|
||||
/**/
|
||||
/**/ if (!(module instanceof WebAssembly.Module)) module = new WebAssembly.Module(module);
|
||||
/**/
|
||||
/**/ const instance = new WebAssembly.Instance(module, imports);
|
||||
/**/
|
||||
/**/ go.run(instance);
|
||||
/**/ return __finalize_init(instance, module);
|
||||
/**/}
|
||||
/**/export default async function initAsync(input) {
|
||||
/**/ if (wasm !== undefined) return wasm;
|
||||
/**/
|
||||
/**/ if (typeof input === 'undefined') input = new URL('gofmt.wasm', import.meta.url);
|
||||
/**/
|
||||
/**/ const go = new TinyGo();
|
||||
/**/ const imports = go.importObject;
|
||||
/**/
|
||||
/**/ if (typeof input === 'string' || (typeof Request === 'function' && input instanceof Request) || (typeof URL === 'function' && input instanceof URL)) {
|
||||
/**/ input = fetch(input);
|
||||
/**/ }
|
||||
/**/
|
||||
/**/ __init_memory(imports);
|
||||
/**/
|
||||
/**/ const { instance, module } = await __load(await input, imports);
|
||||
/**/
|
||||
/**/ go.run(instance);
|
||||
/**/ return __finalize_init(instance, module);
|
||||
/**/}
|
||||
/**/export function format(input) {
|
||||
/**/ const [err, result] = wasm.format(input);
|
||||
/**/ if (err) {
|
||||
/**/ throw new Error(result);
|
||||
/**/ }
|
||||
/**/ return result;
|
||||
/**/}
|
||||
/**/
|
||||
BIN
frontend/src/common/prettier/plugins/go/gofmt.wasm
Normal file
BIN
frontend/src/common/prettier/plugins/go/gofmt.wasm
Normal file
Binary file not shown.
10
frontend/src/common/prettier/plugins/go/gofmt_node.js
Normal file
10
frontend/src/common/prettier/plugins/go/gofmt_node.js
Normal file
@@ -0,0 +1,10 @@
|
||||
import fs from "node:fs/promises";
|
||||
import initAsync from "./gofmt.js";
|
||||
|
||||
const wasm = new URL("./gofmt.wasm", import.meta.url);
|
||||
|
||||
export default function (init = fs.readFile(wasm)) {
|
||||
return initAsync(init);
|
||||
}
|
||||
|
||||
export * from "./gofmt.js";
|
||||
8
frontend/src/common/prettier/plugins/go/gofmt_vite.js
Normal file
8
frontend/src/common/prettier/plugins/go/gofmt_vite.js
Normal file
@@ -0,0 +1,8 @@
|
||||
import initAsync from "./gofmt.js";
|
||||
import wasm_url from "./gofmt.wasm?url";
|
||||
|
||||
export default function (input = wasm_url) {
|
||||
return initAsync(input);
|
||||
}
|
||||
|
||||
export * from "./gofmt.js";
|
||||
101
frontend/src/common/prettier/plugins/go/index.ts
Normal file
101
frontend/src/common/prettier/plugins/go/index.ts
Normal file
@@ -0,0 +1,101 @@
|
||||
/**
|
||||
* Prettier Plugin for Go formatting using gofmt WebAssembly
|
||||
*
|
||||
* This plugin provides support for formatting Go files using the gofmt WASM implementation.
|
||||
*/
|
||||
import type { Plugin, Parser, Printer } from 'prettier';
|
||||
|
||||
// Import the gofmt WASM module
|
||||
import gofmtInit, { format } from './gofmt_vite.js';
|
||||
|
||||
const parserName = 'go';
|
||||
|
||||
// Language configuration
|
||||
const languages = [
|
||||
{
|
||||
name: 'Go',
|
||||
aliases: ['go', 'golang'],
|
||||
parsers: [parserName],
|
||||
extensions: ['.go'],
|
||||
aceMode: 'golang',
|
||||
tmScope: 'source.go',
|
||||
linguistLanguageId: 132,
|
||||
vscodeLanguageIds: ['go']
|
||||
}
|
||||
];
|
||||
|
||||
// Parser configuration
|
||||
const goParser: Parser<string> = {
|
||||
astFormat: parserName,
|
||||
parse: (text: string) => text,
|
||||
locStart: () => 0,
|
||||
locEnd: (node: string) => node.length,
|
||||
};
|
||||
|
||||
// Lazy initialize gofmt WASM module
|
||||
let initPromise: Promise<void> | null = null;
|
||||
let isInitialized = false;
|
||||
|
||||
function initGofmt(): Promise<void> {
|
||||
if (isInitialized) {
|
||||
return Promise.resolve();
|
||||
}
|
||||
|
||||
if (!initPromise) {
|
||||
initPromise = (async () => {
|
||||
try {
|
||||
await gofmtInit();
|
||||
isInitialized = true;
|
||||
} catch (error) {
|
||||
console.warn('Failed to initialize gofmt WASM module:', error);
|
||||
initPromise = null;
|
||||
throw error;
|
||||
}
|
||||
})();
|
||||
}
|
||||
|
||||
return initPromise;
|
||||
}
|
||||
|
||||
// Printer configuration
|
||||
const goPrinter: Printer<string> = {
|
||||
// @ts-expect-error -- Support async printer like shell plugin
|
||||
async print(path, options) {
|
||||
try {
|
||||
// Wait for initialization to complete
|
||||
await initGofmt();
|
||||
|
||||
const text = (path as any).getValue ? (path as any).getValue() : path.node;
|
||||
|
||||
// Format using gofmt (synchronous call)
|
||||
const formatted = format(text);
|
||||
|
||||
return formatted.trim();
|
||||
} catch (error) {
|
||||
console.warn('Go formatting failed:', error);
|
||||
// Return original text if formatting fails
|
||||
return (path as any).getValue ? (path as any).getValue() : path.node;
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
// Plugin options (Go doesn't need additional config options)
|
||||
const options = {};
|
||||
|
||||
// Plugin definition
|
||||
const goPlugin: Plugin = {
|
||||
languages,
|
||||
parsers: {
|
||||
[parserName]: goParser,
|
||||
},
|
||||
printers: {
|
||||
[parserName]: goPrinter,
|
||||
},
|
||||
options,
|
||||
};
|
||||
|
||||
// Export plugin without auto-initialization
|
||||
export default goPlugin;
|
||||
export { languages, initGofmt as initialize };
|
||||
export const parsers = goPlugin.parsers;
|
||||
export const printers = goPlugin.printers;
|
||||
9
frontend/src/common/prettier/plugins/go/src/build.sh
Normal file
9
frontend/src/common/prettier/plugins/go/src/build.sh
Normal file
@@ -0,0 +1,9 @@
|
||||
set -Eeo pipefail
|
||||
|
||||
cd $(dirname $0)
|
||||
|
||||
echo "Building..."
|
||||
tinygo build -o=../gofmt.wasm -target=wasm -no-debug ./lib.go
|
||||
|
||||
echo "Generating JS..."
|
||||
cp $(tinygo env TINYGOROOT)/targets/wasm_exec.js ../gofmt.js
|
||||
23
frontend/src/common/prettier/plugins/go/src/lib.go
Normal file
23
frontend/src/common/prettier/plugins/go/src/lib.go
Normal file
@@ -0,0 +1,23 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"go/format"
|
||||
"syscall/js"
|
||||
)
|
||||
|
||||
func Format(this js.Value, args []js.Value) any {
|
||||
input := ([]byte)(args[0].String())
|
||||
|
||||
output, err := format.Source(input)
|
||||
if err != nil {
|
||||
return []any{true, err.Error()}
|
||||
}
|
||||
|
||||
return []any{false, string(output)}
|
||||
}
|
||||
|
||||
func main() {
|
||||
done := make(chan bool)
|
||||
js.Global().Set("format", js.FuncOf(Format))
|
||||
<-done
|
||||
}
|
||||
67
frontend/src/common/prettier/plugins/groovy/index.ts
Normal file
67
frontend/src/common/prettier/plugins/groovy/index.ts
Normal file
@@ -0,0 +1,67 @@
|
||||
/**
|
||||
* Prettier Plugin for Groovy/Jenkins file formatting
|
||||
*
|
||||
* This plugin provides support for formatting Groovy and Jenkins files using the groovy-beautify library.
|
||||
* It supports .groovy files and Jenkins-related files like Jenkinsfile.
|
||||
*/
|
||||
import type { Plugin, Parser, Printer } from 'prettier';
|
||||
import groovyBeautify from 'groovy-beautify';
|
||||
|
||||
const parserName = 'groovy';
|
||||
|
||||
// 语言配置
|
||||
const languages = [
|
||||
{
|
||||
name: 'Groovy',
|
||||
aliases: ['groovy'],
|
||||
parsers: [parserName],
|
||||
filenames: ['jenkinsfile', 'Jenkinsfile'],
|
||||
extensions: ['.jenkinsfile', '.Jenkinsfile', '.groovy'],
|
||||
aceMode: 'groovy',
|
||||
tmScope: 'source.groovy',
|
||||
linguistLanguageId: 142,
|
||||
vscodeLanguageIds: ['groovy']
|
||||
},
|
||||
];
|
||||
|
||||
// 解析器配置
|
||||
const groovyParser: Parser<string> = {
|
||||
astFormat: parserName,
|
||||
parse: (text: string) => text,
|
||||
locStart: () => 0,
|
||||
locEnd: (node: string) => node.length,
|
||||
};
|
||||
|
||||
// 打印器配置
|
||||
const groovyPrinter: Printer<string> = {
|
||||
print: (path, options) => {
|
||||
try {
|
||||
return groovyBeautify(path.node, {
|
||||
width: options.printWidth || 80,
|
||||
}).trim();
|
||||
} catch (error) {
|
||||
return path.node;
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
const options = {
|
||||
|
||||
};
|
||||
|
||||
// 插件对象
|
||||
const groovyPlugin: Plugin = {
|
||||
languages,
|
||||
parsers: {
|
||||
[parserName]: groovyParser,
|
||||
},
|
||||
printers: {
|
||||
[parserName]: groovyPrinter,
|
||||
},
|
||||
options,
|
||||
};
|
||||
|
||||
export default groovyPlugin;
|
||||
export { languages };
|
||||
export const parsers = groovyPlugin.parsers;
|
||||
export const printers = groovyPlugin.printers;
|
||||
17
frontend/src/common/prettier/plugins/java/comments.d.ts
vendored
Normal file
17
frontend/src/common/prettier/plugins/java/comments.d.ts
vendored
Normal file
@@ -0,0 +1,17 @@
|
||||
import type { IToken } from "java-parser";
|
||||
import { type AstPath } from "prettier";
|
||||
import { type JavaNode, type JavaNonTerminal, type JavaParserOptions } from "./printers/helpers.js";
|
||||
export declare function determineFormatterOffOnRanges(cst: JavaNonTerminal): void;
|
||||
export declare function isFullyBetweenFormatterOffOn(path: AstPath<JavaNode>): boolean;
|
||||
export declare function canAttachComment(node: JavaNode): boolean;
|
||||
export declare function handleLineComment(commentNode: JavaComment, _: string, options: JavaParserOptions): boolean;
|
||||
export declare function handleRemainingComment(commentNode: JavaComment): boolean;
|
||||
export type JavaComment = IToken & {
|
||||
value: string;
|
||||
leading: boolean;
|
||||
trailing: boolean;
|
||||
printed: boolean;
|
||||
enclosingNode?: JavaNonTerminal;
|
||||
precedingNode?: JavaNonTerminal;
|
||||
followingNode?: JavaNonTerminal;
|
||||
};
|
||||
199
frontend/src/common/prettier/plugins/java/comments.js
Normal file
199
frontend/src/common/prettier/plugins/java/comments.js
Normal file
@@ -0,0 +1,199 @@
|
||||
import { util } from "prettier";
|
||||
import parser from "./parser.js";
|
||||
import { isEmptyStatement, isNonTerminal, isTerminal } from "./printers/helpers.js";
|
||||
const formatterOffOnRangesByCst = new WeakMap();
|
||||
export function determineFormatterOffOnRanges(cst) {
|
||||
const { comments } = cst;
|
||||
if (!comments) {
|
||||
return;
|
||||
}
|
||||
const ranges = comments
|
||||
.filter(({ image }) => /^(\/\/\s*@formatter:(off|on)\s*|\/\*\s*@formatter:(off|on)\s*\*\/)$/.test(image))
|
||||
.reduce((ranges, { image, startOffset }) => {
|
||||
const previous = ranges.at(-1);
|
||||
if (image.endsWith("off")) {
|
||||
if ((previous === null || previous === void 0 ? void 0 : previous.on) !== Infinity) {
|
||||
ranges.push({ off: startOffset, on: Infinity });
|
||||
}
|
||||
}
|
||||
else if ((previous === null || previous === void 0 ? void 0 : previous.on) === Infinity) {
|
||||
previous.on = startOffset;
|
||||
}
|
||||
return ranges;
|
||||
}, new Array());
|
||||
formatterOffOnRangesByCst.set(cst, ranges);
|
||||
}
|
||||
export function isFullyBetweenFormatterOffOn(path) {
|
||||
var _a;
|
||||
const { node, root } = path;
|
||||
const start = parser.locStart(node);
|
||||
const end = parser.locEnd(node);
|
||||
return (((_a = formatterOffOnRangesByCst
|
||||
.get(root)) === null || _a === void 0 ? void 0 : _a.some(range => range.off < start && end < range.on)) === true);
|
||||
}
|
||||
export function canAttachComment(node) {
|
||||
var _a, _b, _c;
|
||||
if (isTerminal(node)) {
|
||||
const { name, CATEGORIES } = node.tokenType;
|
||||
return (name === "Identifier" ||
|
||||
(CATEGORIES === null || CATEGORIES === void 0 ? void 0 : CATEGORIES.find(({ name }) => name === "BinaryOperator")) !== undefined);
|
||||
}
|
||||
const { children, name } = node;
|
||||
switch (name) {
|
||||
case "argumentList":
|
||||
case "blockStatements":
|
||||
case "emptyStatement":
|
||||
case "enumBodyDeclarations":
|
||||
return false;
|
||||
case "annotationInterfaceMemberDeclaration":
|
||||
case "classMemberDeclaration":
|
||||
case "interfaceMemberDeclaration":
|
||||
case "methodBody":
|
||||
return !children.Semicolon;
|
||||
case "blockStatement":
|
||||
return !children.statement || !isEmptyStatement(children.statement[0]);
|
||||
case "classBodyDeclaration":
|
||||
return !((_a = children.classMemberDeclaration) === null || _a === void 0 ? void 0 : _a[0].children.Semicolon);
|
||||
case "recordBodyDeclaration":
|
||||
return !((_c = (_b = children.classBodyDeclaration) === null || _b === void 0 ? void 0 : _b[0].children.classMemberDeclaration) === null || _c === void 0 ? void 0 : _c[0].children.Semicolon);
|
||||
case "statement":
|
||||
return !isEmptyStatement(node);
|
||||
case "statementWithoutTrailingSubstatement":
|
||||
return !children.emptyStatement;
|
||||
default:
|
||||
return true;
|
||||
}
|
||||
}
|
||||
export function handleLineComment(commentNode, _, options) {
|
||||
return [
|
||||
handleBinaryExpressionComments,
|
||||
handleFqnOrRefTypeComments,
|
||||
handleIfStatementComments,
|
||||
handleJumpStatementComments,
|
||||
handleLabeledStatementComments,
|
||||
handleNameComments
|
||||
].some(fn => fn(commentNode, options));
|
||||
}
|
||||
export function handleRemainingComment(commentNode) {
|
||||
return [
|
||||
handleFqnOrRefTypeComments,
|
||||
handleMethodDeclaratorComments,
|
||||
handleNameComments,
|
||||
handleJumpStatementComments
|
||||
].some(fn => fn(commentNode));
|
||||
}
|
||||
function handleBinaryExpressionComments(commentNode, options) {
|
||||
const { enclosingNode, precedingNode, followingNode } = commentNode;
|
||||
if (enclosingNode &&
|
||||
isNonTerminal(enclosingNode) &&
|
||||
enclosingNode.name === "binaryExpression") {
|
||||
if (isBinaryOperator(followingNode)) {
|
||||
if (options.experimentalOperatorPosition === "start") {
|
||||
util.addLeadingComment(followingNode, commentNode);
|
||||
}
|
||||
else {
|
||||
util.addTrailingComment(followingNode, commentNode);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
else if (options.experimentalOperatorPosition === "start" &&
|
||||
isBinaryOperator(precedingNode)) {
|
||||
util.addLeadingComment(precedingNode, commentNode);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
function handleFqnOrRefTypeComments(commentNode) {
|
||||
const { enclosingNode, followingNode } = commentNode;
|
||||
if (enclosingNode &&
|
||||
isNonTerminal(enclosingNode) &&
|
||||
enclosingNode.name === "fqnOrRefType" &&
|
||||
followingNode) {
|
||||
util.addLeadingComment(followingNode, commentNode);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
function handleIfStatementComments(commentNode) {
|
||||
const { enclosingNode, precedingNode } = commentNode;
|
||||
if (enclosingNode &&
|
||||
isNonTerminal(enclosingNode) &&
|
||||
enclosingNode.name === "ifStatement" &&
|
||||
precedingNode &&
|
||||
isNonTerminal(precedingNode) &&
|
||||
precedingNode.name === "statement") {
|
||||
util.addDanglingComment(enclosingNode, commentNode, undefined);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
function handleJumpStatementComments(commentNode) {
|
||||
const { enclosingNode, precedingNode, followingNode } = commentNode;
|
||||
if (enclosingNode &&
|
||||
!precedingNode &&
|
||||
!followingNode &&
|
||||
isNonTerminal(enclosingNode) &&
|
||||
["breakStatement", "continueStatement", "returnStatement"].includes(enclosingNode.name)) {
|
||||
util.addTrailingComment(enclosingNode, commentNode);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
function handleLabeledStatementComments(commentNode) {
|
||||
const { enclosingNode, precedingNode } = commentNode;
|
||||
if (enclosingNode &&
|
||||
precedingNode &&
|
||||
isNonTerminal(enclosingNode) &&
|
||||
enclosingNode.name === "labeledStatement" &&
|
||||
isTerminal(precedingNode) &&
|
||||
precedingNode.tokenType.name === "Identifier") {
|
||||
util.addLeadingComment(precedingNode, commentNode);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
function handleMethodDeclaratorComments(commentNode) {
|
||||
const { enclosingNode } = commentNode;
|
||||
if (enclosingNode &&
|
||||
isNonTerminal(enclosingNode) &&
|
||||
enclosingNode.name === "methodDeclarator" &&
|
||||
!enclosingNode.children.receiverParameter &&
|
||||
!enclosingNode.children.formalParameterList &&
|
||||
enclosingNode.children.LBrace[0].startOffset < commentNode.startOffset &&
|
||||
commentNode.startOffset < enclosingNode.children.RBrace[0].startOffset) {
|
||||
util.addDanglingComment(enclosingNode, commentNode, undefined);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
function handleNameComments(commentNode) {
|
||||
const { enclosingNode, precedingNode } = commentNode;
|
||||
if (enclosingNode &&
|
||||
precedingNode &&
|
||||
isNonTerminal(enclosingNode) &&
|
||||
isTerminal(precedingNode) &&
|
||||
precedingNode.tokenType.name === "Identifier" &&
|
||||
[
|
||||
"ambiguousName",
|
||||
"classOrInterfaceTypeToInstantiate",
|
||||
"expressionName",
|
||||
"moduleDeclaration",
|
||||
"moduleName",
|
||||
"packageDeclaration",
|
||||
"packageName",
|
||||
"packageOrTypeName",
|
||||
"typeName"
|
||||
].includes(enclosingNode.name)) {
|
||||
util.addTrailingComment(precedingNode, commentNode);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
function isBinaryOperator(node) {
|
||||
var _a;
|
||||
return (node !== undefined &&
|
||||
(isNonTerminal(node)
|
||||
? node.name === "shiftOperator"
|
||||
: (_a = node.tokenType.CATEGORIES) === null || _a === void 0 ? void 0 : _a.some(({ name }) => name === "BinaryOperator")));
|
||||
}
|
||||
563
frontend/src/common/prettier/plugins/java/index.d.ts
vendored
Normal file
563
frontend/src/common/prettier/plugins/java/index.d.ts
vendored
Normal file
@@ -0,0 +1,563 @@
|
||||
import type { JavaNode } from "./printers/helpers.js";
|
||||
declare const _default: {
|
||||
languages: {
|
||||
name: string;
|
||||
parsers: "java"[];
|
||||
group: string;
|
||||
tmScope: string;
|
||||
aceMode: string;
|
||||
codemirrorMode: string;
|
||||
codemirrorMimeType: string;
|
||||
extensions: string[];
|
||||
linguistLanguageId: number;
|
||||
vscodeLanguageIds: string[];
|
||||
}[];
|
||||
parsers: {
|
||||
java: {
|
||||
parse(text: string, options: import("./printers/helpers.js").JavaParserOptions): import("./printers/helpers.js").JavaNonTerminal;
|
||||
astFormat: string;
|
||||
hasPragma(text: string): boolean;
|
||||
locStart(node: JavaNode): number;
|
||||
locEnd(node: JavaNode): number;
|
||||
};
|
||||
};
|
||||
printers: {
|
||||
java: {
|
||||
print(path: import("prettier").AstPath<import("java-parser").ArrayInitializerCstNode & {
|
||||
comments?: import("./comments.js").JavaComment[];
|
||||
}> | import("prettier").AstPath<import("java-parser").VariableInitializerListCstNode & {
|
||||
comments?: import("./comments.js").JavaComment[];
|
||||
}> | import("prettier").AstPath<import("java-parser").BlockCstNode & {
|
||||
comments?: import("./comments.js").JavaComment[];
|
||||
}> | import("prettier").AstPath<import("java-parser").BlockStatementsCstNode & {
|
||||
comments?: import("./comments.js").JavaComment[];
|
||||
}> | import("prettier").AstPath<import("java-parser").LocalVariableDeclarationStatementCstNode & {
|
||||
comments?: import("./comments.js").JavaComment[];
|
||||
}> | import("prettier").AstPath<import("java-parser").LocalVariableDeclarationCstNode & {
|
||||
comments?: import("./comments.js").JavaComment[];
|
||||
}> | import("prettier").AstPath<import("java-parser").LabeledStatementCstNode & {
|
||||
comments?: import("./comments.js").JavaComment[];
|
||||
}> | import("prettier").AstPath<import("java-parser").ExpressionStatementCstNode & {
|
||||
comments?: import("./comments.js").JavaComment[];
|
||||
}> | import("prettier").AstPath<import("java-parser").IfStatementCstNode & {
|
||||
comments?: import("./comments.js").JavaComment[];
|
||||
}> | import("prettier").AstPath<import("java-parser").AssertStatementCstNode & {
|
||||
comments?: import("./comments.js").JavaComment[];
|
||||
}> | import("prettier").AstPath<import("java-parser").SwitchStatementCstNode & {
|
||||
comments?: import("./comments.js").JavaComment[];
|
||||
}> | import("prettier").AstPath<import("java-parser").SwitchBlockCstNode & {
|
||||
comments?: import("./comments.js").JavaComment[];
|
||||
}> | import("prettier").AstPath<import("java-parser").SwitchBlockStatementGroupCstNode & {
|
||||
comments?: import("./comments.js").JavaComment[];
|
||||
}> | import("prettier").AstPath<import("java-parser").SwitchLabelCstNode & {
|
||||
comments?: import("./comments.js").JavaComment[];
|
||||
}> | import("prettier").AstPath<import("java-parser").SwitchRuleCstNode & {
|
||||
comments?: import("./comments.js").JavaComment[];
|
||||
}> | import("prettier").AstPath<import("java-parser").WhileStatementCstNode & {
|
||||
comments?: import("./comments.js").JavaComment[];
|
||||
}> | import("prettier").AstPath<import("java-parser").DoStatementCstNode & {
|
||||
comments?: import("./comments.js").JavaComment[];
|
||||
}> | import("prettier").AstPath<import("java-parser").BasicForStatementCstNode & {
|
||||
comments?: import("./comments.js").JavaComment[];
|
||||
}> | import("prettier").AstPath<import("java-parser").StatementExpressionListCstNode & {
|
||||
comments?: import("./comments.js").JavaComment[];
|
||||
}> | import("prettier").AstPath<import("java-parser").EnhancedForStatementCstNode & {
|
||||
comments?: import("./comments.js").JavaComment[];
|
||||
}> | import("prettier").AstPath<import("java-parser").BreakStatementCstNode & {
|
||||
comments?: import("./comments.js").JavaComment[];
|
||||
}> | import("prettier").AstPath<import("java-parser").ContinueStatementCstNode & {
|
||||
comments?: import("./comments.js").JavaComment[];
|
||||
}> | import("prettier").AstPath<import("java-parser").ReturnStatementCstNode & {
|
||||
comments?: import("./comments.js").JavaComment[];
|
||||
}> | import("prettier").AstPath<import("java-parser").ThrowStatementCstNode & {
|
||||
comments?: import("./comments.js").JavaComment[];
|
||||
}> | import("prettier").AstPath<import("java-parser").SynchronizedStatementCstNode & {
|
||||
comments?: import("./comments.js").JavaComment[];
|
||||
}> | import("prettier").AstPath<import("java-parser").TryStatementCstNode & {
|
||||
comments?: import("./comments.js").JavaComment[];
|
||||
}> | import("prettier").AstPath<import("java-parser").CatchesCstNode & {
|
||||
comments?: import("./comments.js").JavaComment[];
|
||||
}> | import("prettier").AstPath<import("java-parser").CatchClauseCstNode & {
|
||||
comments?: import("./comments.js").JavaComment[];
|
||||
}> | import("prettier").AstPath<import("java-parser").CatchFormalParameterCstNode & {
|
||||
comments?: import("./comments.js").JavaComment[];
|
||||
}> | import("prettier").AstPath<import("java-parser").CatchTypeCstNode & {
|
||||
comments?: import("./comments.js").JavaComment[];
|
||||
}> | import("prettier").AstPath<import("java-parser").FinallyCstNode & {
|
||||
comments?: import("./comments.js").JavaComment[];
|
||||
}> | import("prettier").AstPath<import("java-parser").TryWithResourcesStatementCstNode & {
|
||||
comments?: import("./comments.js").JavaComment[];
|
||||
}> | import("prettier").AstPath<import("java-parser").ResourceSpecificationCstNode & {
|
||||
comments?: import("./comments.js").JavaComment[];
|
||||
}> | import("prettier").AstPath<import("java-parser").ResourceListCstNode & {
|
||||
comments?: import("./comments.js").JavaComment[];
|
||||
}> | import("prettier").AstPath<import("java-parser").YieldStatementCstNode & {
|
||||
comments?: import("./comments.js").JavaComment[];
|
||||
}> | import("prettier").AstPath<import("java-parser").ForInitCstNode & {
|
||||
comments?: import("./comments.js").JavaComment[];
|
||||
}> | import("prettier").AstPath<import("java-parser").ForUpdateCstNode & {
|
||||
comments?: import("./comments.js").JavaComment[];
|
||||
}> | import("prettier").AstPath<import("java-parser").StatementCstNode & {
|
||||
comments?: import("./comments.js").JavaComment[];
|
||||
}> | import("prettier").AstPath<import("java-parser").StatementWithoutTrailingSubstatementCstNode & {
|
||||
comments?: import("./comments.js").JavaComment[];
|
||||
}> | import("prettier").AstPath<import("java-parser").ForStatementCstNode & {
|
||||
comments?: import("./comments.js").JavaComment[];
|
||||
}> | import("prettier").AstPath<import("java-parser").BlockStatementCstNode & {
|
||||
comments?: import("./comments.js").JavaComment[];
|
||||
}> | import("prettier").AstPath<import("java-parser").CaseConstantCstNode & {
|
||||
comments?: import("./comments.js").JavaComment[];
|
||||
}> | import("prettier").AstPath<import("java-parser").CasePatternCstNode & {
|
||||
comments?: import("./comments.js").JavaComment[];
|
||||
}> | import("prettier").AstPath<import("java-parser").EmptyStatementCstNode & {
|
||||
comments?: import("./comments.js").JavaComment[];
|
||||
}> | import("prettier").AstPath<import("java-parser").StatementExpressionCstNode & {
|
||||
comments?: import("./comments.js").JavaComment[];
|
||||
}> | import("prettier").AstPath<import("java-parser").LocalVariableTypeCstNode & {
|
||||
comments?: import("./comments.js").JavaComment[];
|
||||
}> | import("prettier").AstPath<import("java-parser").ResourceCstNode & {
|
||||
comments?: import("./comments.js").JavaComment[];
|
||||
}> | import("prettier").AstPath<import("java-parser").VariableAccessCstNode & {
|
||||
comments?: import("./comments.js").JavaComment[];
|
||||
}> | import("prettier").AstPath<import("java-parser").ClassDeclarationCstNode & {
|
||||
comments?: import("./comments.js").JavaComment[];
|
||||
}> | import("prettier").AstPath<import("java-parser").NormalClassDeclarationCstNode & {
|
||||
comments?: import("./comments.js").JavaComment[];
|
||||
}> | import("prettier").AstPath<import("java-parser").TypeParametersCstNode & {
|
||||
comments?: import("./comments.js").JavaComment[];
|
||||
}> | import("prettier").AstPath<import("java-parser").TypeParameterListCstNode & {
|
||||
comments?: import("./comments.js").JavaComment[];
|
||||
}> | import("prettier").AstPath<import("java-parser").ClassExtendsCstNode & {
|
||||
comments?: import("./comments.js").JavaComment[];
|
||||
}> | import("prettier").AstPath<import("java-parser").ClassImplementsCstNode & {
|
||||
comments?: import("./comments.js").JavaComment[];
|
||||
}> | import("prettier").AstPath<import("java-parser").InterfaceTypeListCstNode & {
|
||||
comments?: import("./comments.js").JavaComment[];
|
||||
}> | import("prettier").AstPath<import("java-parser").ClassBodyCstNode & {
|
||||
comments?: import("./comments.js").JavaComment[];
|
||||
}> | import("prettier").AstPath<import("java-parser").ClassMemberDeclarationCstNode & {
|
||||
comments?: import("./comments.js").JavaComment[];
|
||||
}> | import("prettier").AstPath<import("java-parser").FieldDeclarationCstNode & {
|
||||
comments?: import("./comments.js").JavaComment[];
|
||||
}> | import("prettier").AstPath<import("java-parser").VariableDeclaratorListCstNode & {
|
||||
comments?: import("./comments.js").JavaComment[];
|
||||
}> | import("prettier").AstPath<import("java-parser").VariableDeclaratorCstNode & {
|
||||
comments?: import("./comments.js").JavaComment[];
|
||||
}> | import("prettier").AstPath<import("java-parser").VariableDeclaratorIdCstNode & {
|
||||
comments?: import("./comments.js").JavaComment[];
|
||||
}> | import("prettier").AstPath<import("java-parser").UnannPrimitiveTypeWithOptionalDimsSuffixCstNode & {
|
||||
comments?: import("./comments.js").JavaComment[];
|
||||
}> | import("prettier").AstPath<import("java-parser").UnannReferenceTypeCstNode & {
|
||||
comments?: import("./comments.js").JavaComment[];
|
||||
}> | import("prettier").AstPath<import("java-parser").MethodDeclarationCstNode & {
|
||||
comments?: import("./comments.js").JavaComment[];
|
||||
}> | import("prettier").AstPath<import("java-parser").MethodHeaderCstNode & {
|
||||
comments?: import("./comments.js").JavaComment[];
|
||||
}> | import("prettier").AstPath<import("java-parser").MethodDeclaratorCstNode & {
|
||||
comments?: import("./comments.js").JavaComment[];
|
||||
}> | import("prettier").AstPath<import("java-parser").ReceiverParameterCstNode & {
|
||||
comments?: import("./comments.js").JavaComment[];
|
||||
}> | import("prettier").AstPath<import("java-parser").FormalParameterListCstNode & {
|
||||
comments?: import("./comments.js").JavaComment[];
|
||||
}> | import("prettier").AstPath<import("java-parser").VariableParaRegularParameterCstNode & {
|
||||
comments?: import("./comments.js").JavaComment[];
|
||||
}> | import("prettier").AstPath<import("java-parser").VariableArityParameterCstNode & {
|
||||
comments?: import("./comments.js").JavaComment[];
|
||||
}> | import("prettier").AstPath<import("java-parser").ThrowsCstNode & {
|
||||
comments?: import("./comments.js").JavaComment[];
|
||||
}> | import("prettier").AstPath<import("java-parser").ExceptionTypeListCstNode & {
|
||||
comments?: import("./comments.js").JavaComment[];
|
||||
}> | import("prettier").AstPath<import("java-parser").StaticInitializerCstNode & {
|
||||
comments?: import("./comments.js").JavaComment[];
|
||||
}> | import("prettier").AstPath<import("java-parser").ConstructorDeclarationCstNode & {
|
||||
comments?: import("./comments.js").JavaComment[];
|
||||
}> | import("prettier").AstPath<import("java-parser").ConstructorDeclaratorCstNode & {
|
||||
comments?: import("./comments.js").JavaComment[];
|
||||
}> | import("prettier").AstPath<import("java-parser").ConstructorBodyCstNode & {
|
||||
comments?: import("./comments.js").JavaComment[];
|
||||
}> | import("prettier").AstPath<import("java-parser").UnqualifiedExplicitConstructorInvocationCstNode & {
|
||||
comments?: import("./comments.js").JavaComment[];
|
||||
}> | import("prettier").AstPath<import("java-parser").QualifiedExplicitConstructorInvocationCstNode & {
|
||||
comments?: import("./comments.js").JavaComment[];
|
||||
}> | import("prettier").AstPath<import("java-parser").EnumDeclarationCstNode & {
|
||||
comments?: import("./comments.js").JavaComment[];
|
||||
}> | import("prettier").AstPath<import("java-parser").EnumBodyCstNode & {
|
||||
comments?: import("./comments.js").JavaComment[];
|
||||
}> | import("prettier").AstPath<import("java-parser").EnumConstantListCstNode & {
|
||||
comments?: import("./comments.js").JavaComment[];
|
||||
}> | import("prettier").AstPath<import("java-parser").EnumConstantCstNode & {
|
||||
comments?: import("./comments.js").JavaComment[];
|
||||
}> | import("prettier").AstPath<import("java-parser").EnumBodyDeclarationsCstNode & {
|
||||
comments?: import("./comments.js").JavaComment[];
|
||||
}> | import("prettier").AstPath<import("java-parser").RecordDeclarationCstNode & {
|
||||
comments?: import("./comments.js").JavaComment[];
|
||||
}> | import("prettier").AstPath<import("java-parser").RecordHeaderCstNode & {
|
||||
comments?: import("./comments.js").JavaComment[];
|
||||
}> | import("prettier").AstPath<import("java-parser").RecordComponentListCstNode & {
|
||||
comments?: import("./comments.js").JavaComment[];
|
||||
}> | import("prettier").AstPath<import("java-parser").RecordComponentCstNode & {
|
||||
comments?: import("./comments.js").JavaComment[];
|
||||
}> | import("prettier").AstPath<import("java-parser").VariableArityRecordComponentCstNode & {
|
||||
comments?: import("./comments.js").JavaComment[];
|
||||
}> | import("prettier").AstPath<import("java-parser").RecordBodyCstNode & {
|
||||
comments?: import("./comments.js").JavaComment[];
|
||||
}> | import("prettier").AstPath<import("java-parser").CompactConstructorDeclarationCstNode & {
|
||||
comments?: import("./comments.js").JavaComment[];
|
||||
}> | import("prettier").AstPath<import("java-parser").UnannTypeCstNode & {
|
||||
comments?: import("./comments.js").JavaComment[];
|
||||
}> | import("prettier").AstPath<import("java-parser").VariableInitializerCstNode & {
|
||||
comments?: import("./comments.js").JavaComment[];
|
||||
}> | import("prettier").AstPath<import("java-parser").VariableModifierCstNode & {
|
||||
comments?: import("./comments.js").JavaComment[];
|
||||
}> | import("prettier").AstPath<import("java-parser").UnannClassTypeCstNode & {
|
||||
comments?: import("./comments.js").JavaComment[];
|
||||
}> | import("prettier").AstPath<import("java-parser").ClassBodyDeclarationCstNode & {
|
||||
comments?: import("./comments.js").JavaComment[];
|
||||
}> | import("prettier").AstPath<import("java-parser").InstanceInitializerCstNode & {
|
||||
comments?: import("./comments.js").JavaComment[];
|
||||
}> | import("prettier").AstPath<import("java-parser").ClassModifierCstNode & {
|
||||
comments?: import("./comments.js").JavaComment[];
|
||||
}> | import("prettier").AstPath<import("java-parser").ClassPermitsCstNode & {
|
||||
comments?: import("./comments.js").JavaComment[];
|
||||
}> | import("prettier").AstPath<import("java-parser").FieldModifierCstNode & {
|
||||
comments?: import("./comments.js").JavaComment[];
|
||||
}> | import("prettier").AstPath<import("java-parser").MethodModifierCstNode & {
|
||||
comments?: import("./comments.js").JavaComment[];
|
||||
}> | import("prettier").AstPath<import("java-parser").MethodBodyCstNode & {
|
||||
comments?: import("./comments.js").JavaComment[];
|
||||
}> | import("prettier").AstPath<import("java-parser").ConstructorModifierCstNode & {
|
||||
comments?: import("./comments.js").JavaComment[];
|
||||
}> | import("prettier").AstPath<import("java-parser").SimpleTypeNameCstNode & {
|
||||
comments?: import("./comments.js").JavaComment[];
|
||||
}> | import("prettier").AstPath<import("java-parser").ExplicitConstructorInvocationCstNode & {
|
||||
comments?: import("./comments.js").JavaComment[];
|
||||
}> | import("prettier").AstPath<import("java-parser").EnumConstantModifierCstNode & {
|
||||
comments?: import("./comments.js").JavaComment[];
|
||||
}> | import("prettier").AstPath<import("java-parser").ExceptionTypeCstNode & {
|
||||
comments?: import("./comments.js").JavaComment[];
|
||||
}> | import("prettier").AstPath<import("java-parser").FormalParameterCstNode & {
|
||||
comments?: import("./comments.js").JavaComment[];
|
||||
}> | import("prettier").AstPath<import("java-parser").ResultCstNode & {
|
||||
comments?: import("./comments.js").JavaComment[];
|
||||
}> | import("prettier").AstPath<import("java-parser").RecordBodyDeclarationCstNode & {
|
||||
comments?: import("./comments.js").JavaComment[];
|
||||
}> | import("prettier").AstPath<import("java-parser").RecordComponentModifierCstNode & {
|
||||
comments?: import("./comments.js").JavaComment[];
|
||||
}> | import("prettier").AstPath<import("java-parser").UnannClassOrInterfaceTypeCstNode & {
|
||||
comments?: import("./comments.js").JavaComment[];
|
||||
}> | import("prettier").AstPath<import("java-parser").UnannInterfaceTypeCstNode & {
|
||||
comments?: import("./comments.js").JavaComment[];
|
||||
}> | import("prettier").AstPath<import("java-parser").UnannPrimitiveTypeCstNode & {
|
||||
comments?: import("./comments.js").JavaComment[];
|
||||
}> | import("prettier").AstPath<import("java-parser").UnannTypeVariableCstNode & {
|
||||
comments?: import("./comments.js").JavaComment[];
|
||||
}> | import("prettier").AstPath<import("java-parser").LambdaExpressionCstNode & {
|
||||
comments?: import("./comments.js").JavaComment[];
|
||||
}> | import("prettier").AstPath<import("java-parser").LambdaParametersCstNode & {
|
||||
comments?: import("./comments.js").JavaComment[];
|
||||
}> | import("prettier").AstPath<import("java-parser").LambdaParametersWithBracesCstNode & {
|
||||
comments?: import("./comments.js").JavaComment[];
|
||||
}> | import("prettier").AstPath<import("java-parser").ConciseLambdaParameterListCstNode & {
|
||||
comments?: import("./comments.js").JavaComment[];
|
||||
}> | import("prettier").AstPath<import("java-parser").NormalLambdaParameterListCstNode & {
|
||||
comments?: import("./comments.js").JavaComment[];
|
||||
}> | import("prettier").AstPath<import("java-parser").RegularLambdaParameterCstNode & {
|
||||
comments?: import("./comments.js").JavaComment[];
|
||||
}> | import("prettier").AstPath<import("java-parser").ConditionalExpressionCstNode & {
|
||||
comments?: import("./comments.js").JavaComment[];
|
||||
}> | import("prettier").AstPath<import("java-parser").BinaryExpressionCstNode & {
|
||||
comments?: import("./comments.js").JavaComment[];
|
||||
}> | import("prettier").AstPath<import("java-parser").UnaryExpressionCstNode & {
|
||||
comments?: import("./comments.js").JavaComment[];
|
||||
}> | import("prettier").AstPath<import("java-parser").UnaryExpressionNotPlusMinusCstNode & {
|
||||
comments?: import("./comments.js").JavaComment[];
|
||||
}> | import("prettier").AstPath<import("java-parser").PrimaryCstNode & {
|
||||
comments?: import("./comments.js").JavaComment[];
|
||||
}> | import("prettier").AstPath<import("java-parser").PrimarySuffixCstNode & {
|
||||
comments?: import("./comments.js").JavaComment[];
|
||||
}> | import("prettier").AstPath<import("java-parser").FqnOrRefTypeCstNode & {
|
||||
comments?: import("./comments.js").JavaComment[];
|
||||
}> | import("prettier").AstPath<import("java-parser").FqnOrRefTypePartFirstCstNode & {
|
||||
comments?: import("./comments.js").JavaComment[];
|
||||
}> | import("prettier").AstPath<import("java-parser").FqnOrRefTypePartRestCstNode & {
|
||||
comments?: import("./comments.js").JavaComment[];
|
||||
}> | import("prettier").AstPath<import("java-parser").FqnOrRefTypePartCommonCstNode & {
|
||||
comments?: import("./comments.js").JavaComment[];
|
||||
}> | import("prettier").AstPath<import("java-parser").ParenthesisExpressionCstNode & {
|
||||
comments?: import("./comments.js").JavaComment[];
|
||||
}> | import("prettier").AstPath<import("java-parser").PrimitiveCastExpressionCstNode & {
|
||||
comments?: import("./comments.js").JavaComment[];
|
||||
}> | import("prettier").AstPath<import("java-parser").ReferenceTypeCastExpressionCstNode & {
|
||||
comments?: import("./comments.js").JavaComment[];
|
||||
}> | import("prettier").AstPath<import("java-parser").UnqualifiedClassInstanceCreationExpressionCstNode & {
|
||||
comments?: import("./comments.js").JavaComment[];
|
||||
}> | import("prettier").AstPath<import("java-parser").ClassOrInterfaceTypeToInstantiateCstNode & {
|
||||
comments?: import("./comments.js").JavaComment[];
|
||||
}> | import("prettier").AstPath<import("java-parser").MethodInvocationSuffixCstNode & {
|
||||
comments?: import("./comments.js").JavaComment[];
|
||||
}> | import("prettier").AstPath<import("java-parser").ArgumentListCstNode & {
|
||||
comments?: import("./comments.js").JavaComment[];
|
||||
}> | import("prettier").AstPath<import("java-parser").ArrayCreationExpressionCstNode & {
|
||||
comments?: import("./comments.js").JavaComment[];
|
||||
}> | import("prettier").AstPath<import("java-parser").ArrayCreationExpressionWithoutInitializerSuffixCstNode & {
|
||||
comments?: import("./comments.js").JavaComment[];
|
||||
}> | import("prettier").AstPath<import("java-parser").ArrayCreationWithInitializerSuffixCstNode & {
|
||||
comments?: import("./comments.js").JavaComment[];
|
||||
}> | import("prettier").AstPath<import("java-parser").DimExprsCstNode & {
|
||||
comments?: import("./comments.js").JavaComment[];
|
||||
}> | import("prettier").AstPath<import("java-parser").DimExprCstNode & {
|
||||
comments?: import("./comments.js").JavaComment[];
|
||||
}> | import("prettier").AstPath<import("java-parser").ClassLiteralSuffixCstNode & {
|
||||
comments?: import("./comments.js").JavaComment[];
|
||||
}> | import("prettier").AstPath<import("java-parser").ArrayAccessSuffixCstNode & {
|
||||
comments?: import("./comments.js").JavaComment[];
|
||||
}> | import("prettier").AstPath<import("java-parser").MethodReferenceSuffixCstNode & {
|
||||
comments?: import("./comments.js").JavaComment[];
|
||||
}> | import("prettier").AstPath<import("java-parser").StringTemplateCstNode & {
|
||||
comments?: import("./comments.js").JavaComment[];
|
||||
}> | import("prettier").AstPath<import("java-parser").TextBlockTemplateCstNode & {
|
||||
comments?: import("./comments.js").JavaComment[];
|
||||
}> | import("prettier").AstPath<import("java-parser").RecordPatternCstNode & {
|
||||
comments?: import("./comments.js").JavaComment[];
|
||||
}> | import("prettier").AstPath<import("java-parser").ComponentPatternListCstNode & {
|
||||
comments?: import("./comments.js").JavaComment[];
|
||||
}> | import("prettier").AstPath<import("java-parser").GuardCstNode & {
|
||||
comments?: import("./comments.js").JavaComment[];
|
||||
}> | import("prettier").AstPath<import("java-parser").TemplateCstNode & {
|
||||
comments?: import("./comments.js").JavaComment[];
|
||||
}> | import("prettier").AstPath<import("java-parser").PatternCstNode & {
|
||||
comments?: import("./comments.js").JavaComment[];
|
||||
}> | import("prettier").AstPath<import("java-parser").ExpressionCstNode & {
|
||||
comments?: import("./comments.js").JavaComment[];
|
||||
}> | import("prettier").AstPath<import("java-parser").TypePatternCstNode & {
|
||||
comments?: import("./comments.js").JavaComment[];
|
||||
}> | import("prettier").AstPath<import("java-parser").CastExpressionCstNode & {
|
||||
comments?: import("./comments.js").JavaComment[];
|
||||
}> | import("prettier").AstPath<import("java-parser").TypeArgumentsOrDiamondCstNode & {
|
||||
comments?: import("./comments.js").JavaComment[];
|
||||
}> | import("prettier").AstPath<import("java-parser").DiamondCstNode & {
|
||||
comments?: import("./comments.js").JavaComment[];
|
||||
}> | import("prettier").AstPath<import("java-parser").ComponentPatternCstNode & {
|
||||
comments?: import("./comments.js").JavaComment[];
|
||||
}> | import("prettier").AstPath<import("java-parser").MatchAllPatternCstNode & {
|
||||
comments?: import("./comments.js").JavaComment[];
|
||||
}> | import("prettier").AstPath<import("java-parser").ConciseLambdaParameterCstNode & {
|
||||
comments?: import("./comments.js").JavaComment[];
|
||||
}> | import("prettier").AstPath<import("java-parser").EmbeddedExpressionCstNode & {
|
||||
comments?: import("./comments.js").JavaComment[];
|
||||
}> | import("prettier").AstPath<import("java-parser").LambdaBodyCstNode & {
|
||||
comments?: import("./comments.js").JavaComment[];
|
||||
}> | import("prettier").AstPath<import("java-parser").LambdaParameterListCstNode & {
|
||||
comments?: import("./comments.js").JavaComment[];
|
||||
}> | import("prettier").AstPath<import("java-parser").NormalLambdaParameterCstNode & {
|
||||
comments?: import("./comments.js").JavaComment[];
|
||||
}> | import("prettier").AstPath<import("java-parser").LambdaParameterTypeCstNode & {
|
||||
comments?: import("./comments.js").JavaComment[];
|
||||
}> | import("prettier").AstPath<import("java-parser").NewExpressionCstNode & {
|
||||
comments?: import("./comments.js").JavaComment[];
|
||||
}> | import("prettier").AstPath<import("java-parser").PrimaryPrefixCstNode & {
|
||||
comments?: import("./comments.js").JavaComment[];
|
||||
}> | import("prettier").AstPath<import("java-parser").TemplateArgumentCstNode & {
|
||||
comments?: import("./comments.js").JavaComment[];
|
||||
}> | import("prettier").AstPath<import("java-parser").InterfaceDeclarationCstNode & {
|
||||
comments?: import("./comments.js").JavaComment[];
|
||||
}> | import("prettier").AstPath<import("java-parser").NormalInterfaceDeclarationCstNode & {
|
||||
comments?: import("./comments.js").JavaComment[];
|
||||
}> | import("prettier").AstPath<import("java-parser").InterfaceExtendsCstNode & {
|
||||
comments?: import("./comments.js").JavaComment[];
|
||||
}> | import("prettier").AstPath<import("java-parser").InterfaceBodyCstNode & {
|
||||
comments?: import("./comments.js").JavaComment[];
|
||||
}> | import("prettier").AstPath<import("java-parser").InterfaceMemberDeclarationCstNode & {
|
||||
comments?: import("./comments.js").JavaComment[];
|
||||
}> | import("prettier").AstPath<import("java-parser").ConstantDeclarationCstNode & {
|
||||
comments?: import("./comments.js").JavaComment[];
|
||||
}> | import("prettier").AstPath<import("java-parser").InterfaceMethodDeclarationCstNode & {
|
||||
comments?: import("./comments.js").JavaComment[];
|
||||
}> | import("prettier").AstPath<import("java-parser").AnnotationInterfaceDeclarationCstNode & {
|
||||
comments?: import("./comments.js").JavaComment[];
|
||||
}> | import("prettier").AstPath<import("java-parser").AnnotationInterfaceBodyCstNode & {
|
||||
comments?: import("./comments.js").JavaComment[];
|
||||
}> | import("prettier").AstPath<import("java-parser").AnnotationInterfaceMemberDeclarationCstNode & {
|
||||
comments?: import("./comments.js").JavaComment[];
|
||||
}> | import("prettier").AstPath<import("java-parser").AnnotationInterfaceElementDeclarationCstNode & {
|
||||
comments?: import("./comments.js").JavaComment[];
|
||||
}> | import("prettier").AstPath<import("java-parser").DefaultValueCstNode & {
|
||||
comments?: import("./comments.js").JavaComment[];
|
||||
}> | import("prettier").AstPath<import("java-parser").AnnotationCstNode & {
|
||||
comments?: import("./comments.js").JavaComment[];
|
||||
}> | import("prettier").AstPath<import("java-parser").ElementValuePairListCstNode & {
|
||||
comments?: import("./comments.js").JavaComment[];
|
||||
}> | import("prettier").AstPath<import("java-parser").ElementValuePairCstNode & {
|
||||
comments?: import("./comments.js").JavaComment[];
|
||||
}> | import("prettier").AstPath<import("java-parser").ElementValueArrayInitializerCstNode & {
|
||||
comments?: import("./comments.js").JavaComment[];
|
||||
}> | import("prettier").AstPath<import("java-parser").ElementValueListCstNode & {
|
||||
comments?: import("./comments.js").JavaComment[];
|
||||
}> | import("prettier").AstPath<import("java-parser").ElementValueCstNode & {
|
||||
comments?: import("./comments.js").JavaComment[];
|
||||
}> | import("prettier").AstPath<import("java-parser").AnnotationInterfaceElementModifierCstNode & {
|
||||
comments?: import("./comments.js").JavaComment[];
|
||||
}> | import("prettier").AstPath<import("java-parser").ConstantModifierCstNode & {
|
||||
comments?: import("./comments.js").JavaComment[];
|
||||
}> | import("prettier").AstPath<import("java-parser").InterfaceModifierCstNode & {
|
||||
comments?: import("./comments.js").JavaComment[];
|
||||
}> | import("prettier").AstPath<import("java-parser").InterfacePermitsCstNode & {
|
||||
comments?: import("./comments.js").JavaComment[];
|
||||
}> | import("prettier").AstPath<import("java-parser").InterfaceMethodModifierCstNode & {
|
||||
comments?: import("./comments.js").JavaComment[];
|
||||
}> | import("prettier").AstPath<import("java-parser").LiteralCstNode & {
|
||||
comments?: import("./comments.js").JavaComment[];
|
||||
}> | import("prettier").AstPath<import("java-parser").ShiftOperatorCstNode & {
|
||||
comments?: import("./comments.js").JavaComment[];
|
||||
}> | import("prettier").AstPath<import("java-parser").BooleanLiteralCstNode & {
|
||||
comments?: import("./comments.js").JavaComment[];
|
||||
}> | import("prettier").AstPath<import("java-parser").FloatingPointLiteralCstNode & {
|
||||
comments?: import("./comments.js").JavaComment[];
|
||||
}> | import("prettier").AstPath<import("java-parser").IntegerLiteralCstNode & {
|
||||
comments?: import("./comments.js").JavaComment[];
|
||||
}> | import("prettier").AstPath<import("java-parser").MethodNameCstNode & {
|
||||
comments?: import("./comments.js").JavaComment[];
|
||||
}> | import("prettier").AstPath<import("java-parser").AmbiguousNameCstNode & {
|
||||
comments?: import("./comments.js").JavaComment[];
|
||||
}> | import("prettier").AstPath<import("java-parser").TypeNameCstNode & {
|
||||
comments?: import("./comments.js").JavaComment[];
|
||||
}> | import("prettier").AstPath<import("java-parser").TypeIdentifierCstNode & {
|
||||
comments?: import("./comments.js").JavaComment[];
|
||||
}> | import("prettier").AstPath<import("java-parser").ExpressionNameCstNode & {
|
||||
comments?: import("./comments.js").JavaComment[];
|
||||
}> | import("prettier").AstPath<import("java-parser").PackageNameCstNode & {
|
||||
comments?: import("./comments.js").JavaComment[];
|
||||
}> | import("prettier").AstPath<import("java-parser").ModuleNameCstNode & {
|
||||
comments?: import("./comments.js").JavaComment[];
|
||||
}> | import("prettier").AstPath<import("java-parser").PackageOrTypeNameCstNode & {
|
||||
comments?: import("./comments.js").JavaComment[];
|
||||
}> | import("prettier").AstPath<import("java-parser").CompilationUnitCstNode & {
|
||||
comments?: import("./comments.js").JavaComment[];
|
||||
}> | import("prettier").AstPath<import("java-parser").OrdinaryCompilationUnitCstNode & {
|
||||
comments?: import("./comments.js").JavaComment[];
|
||||
}> | import("prettier").AstPath<import("java-parser").ModularCompilationUnitCstNode & {
|
||||
comments?: import("./comments.js").JavaComment[];
|
||||
}> | import("prettier").AstPath<import("java-parser").PackageDeclarationCstNode & {
|
||||
comments?: import("./comments.js").JavaComment[];
|
||||
}> | import("prettier").AstPath<import("java-parser").ImportDeclarationCstNode & {
|
||||
comments?: import("./comments.js").JavaComment[];
|
||||
}> | import("prettier").AstPath<import("java-parser").TypeDeclarationCstNode & {
|
||||
comments?: import("./comments.js").JavaComment[];
|
||||
}> | import("prettier").AstPath<import("java-parser").ModuleDeclarationCstNode & {
|
||||
comments?: import("./comments.js").JavaComment[];
|
||||
}> | import("prettier").AstPath<import("java-parser").RequiresModuleDirectiveCstNode & {
|
||||
comments?: import("./comments.js").JavaComment[];
|
||||
}> | import("prettier").AstPath<import("java-parser").ExportsModuleDirectiveCstNode & {
|
||||
comments?: import("./comments.js").JavaComment[];
|
||||
}> | import("prettier").AstPath<import("java-parser").OpensModuleDirectiveCstNode & {
|
||||
comments?: import("./comments.js").JavaComment[];
|
||||
}> | import("prettier").AstPath<import("java-parser").UsesModuleDirectiveCstNode & {
|
||||
comments?: import("./comments.js").JavaComment[];
|
||||
}> | import("prettier").AstPath<import("java-parser").ProvidesModuleDirectiveCstNode & {
|
||||
comments?: import("./comments.js").JavaComment[];
|
||||
}> | import("prettier").AstPath<import("java-parser").ModuleDirectiveCstNode & {
|
||||
comments?: import("./comments.js").JavaComment[];
|
||||
}> | import("prettier").AstPath<import("java-parser").RequiresModifierCstNode & {
|
||||
comments?: import("./comments.js").JavaComment[];
|
||||
}> | import("prettier").AstPath<import("java-parser").PackageModifierCstNode & {
|
||||
comments?: import("./comments.js").JavaComment[];
|
||||
}> | import("prettier").AstPath<import("java-parser").PrimitiveTypeCstNode & {
|
||||
comments?: import("./comments.js").JavaComment[];
|
||||
}> | import("prettier").AstPath<import("java-parser").ReferenceTypeCstNode & {
|
||||
comments?: import("./comments.js").JavaComment[];
|
||||
}> | import("prettier").AstPath<import("java-parser").TypeVariableCstNode & {
|
||||
comments?: import("./comments.js").JavaComment[];
|
||||
}> | import("prettier").AstPath<import("java-parser").DimsCstNode & {
|
||||
comments?: import("./comments.js").JavaComment[];
|
||||
}> | import("prettier").AstPath<import("java-parser").TypeParameterCstNode & {
|
||||
comments?: import("./comments.js").JavaComment[];
|
||||
}> | import("prettier").AstPath<import("java-parser").TypeBoundCstNode & {
|
||||
comments?: import("./comments.js").JavaComment[];
|
||||
}> | import("prettier").AstPath<import("java-parser").AdditionalBoundCstNode & {
|
||||
comments?: import("./comments.js").JavaComment[];
|
||||
}> | import("prettier").AstPath<import("java-parser").TypeArgumentsCstNode & {
|
||||
comments?: import("./comments.js").JavaComment[];
|
||||
}> | import("prettier").AstPath<import("java-parser").TypeArgumentListCstNode & {
|
||||
comments?: import("./comments.js").JavaComment[];
|
||||
}> | import("prettier").AstPath<import("java-parser").WildcardCstNode & {
|
||||
comments?: import("./comments.js").JavaComment[];
|
||||
}> | import("prettier").AstPath<import("java-parser").WildcardBoundsCstNode & {
|
||||
comments?: import("./comments.js").JavaComment[];
|
||||
}> | import("prettier").AstPath<import("java-parser").InterfaceTypeCstNode & {
|
||||
comments?: import("./comments.js").JavaComment[];
|
||||
}> | import("prettier").AstPath<import("java-parser").ClassTypeCstNode & {
|
||||
comments?: import("./comments.js").JavaComment[];
|
||||
}> | import("prettier").AstPath<import("java-parser").NumericTypeCstNode & {
|
||||
comments?: import("./comments.js").JavaComment[];
|
||||
}> | import("prettier").AstPath<import("java-parser").ClassOrInterfaceTypeCstNode & {
|
||||
comments?: import("./comments.js").JavaComment[];
|
||||
}> | import("prettier").AstPath<import("java-parser").FloatingPointTypeCstNode & {
|
||||
comments?: import("./comments.js").JavaComment[];
|
||||
}> | import("prettier").AstPath<import("java-parser").IntegralTypeCstNode & {
|
||||
comments?: import("./comments.js").JavaComment[];
|
||||
}> | import("prettier").AstPath<import("java-parser").TypeArgumentCstNode & {
|
||||
comments?: import("./comments.js").JavaComment[];
|
||||
}> | import("prettier").AstPath<import("java-parser").TypeParameterModifierCstNode & {
|
||||
comments?: import("./comments.js").JavaComment[];
|
||||
}> | import("prettier").AstPath<import("java-parser").IToken & {
|
||||
comments?: import("./comments.js").JavaComment[];
|
||||
}>, options: import("prettier").ParserOptions<JavaNode>, print: (path: import("prettier").AstPath<JavaNode>) => import("prettier").Doc, args: unknown): import("prettier/doc.js").builders.Doc;
|
||||
hasPrettierIgnore(path: import("prettier").AstPath<JavaNode>): boolean;
|
||||
canAttachComment: typeof import("./comments.js").canAttachComment;
|
||||
isBlockComment(node: JavaNode): boolean;
|
||||
printComment(commentPath: import("prettier").AstPath<JavaNode>): string | import("prettier/doc.js").builders.Doc[];
|
||||
getCommentChildNodes(node: JavaNode): any[];
|
||||
handleComments: {
|
||||
ownLine: typeof import("./comments.js").handleLineComment;
|
||||
endOfLine: typeof import("./comments.js").handleLineComment;
|
||||
remaining: typeof import("./comments.js").handleRemainingComment;
|
||||
};
|
||||
};
|
||||
};
|
||||
options: {
|
||||
entrypoint: {
|
||||
type: "choice";
|
||||
category: string;
|
||||
default: string;
|
||||
choices: {
|
||||
value: string;
|
||||
description: string;
|
||||
}[];
|
||||
description: string;
|
||||
};
|
||||
arrowParens: {
|
||||
type: "choice";
|
||||
category: string;
|
||||
default: string;
|
||||
choices: {
|
||||
value: string;
|
||||
description: string;
|
||||
}[];
|
||||
description: string;
|
||||
};
|
||||
trailingComma: {
|
||||
type: "choice";
|
||||
category: string;
|
||||
default: string;
|
||||
choices: {
|
||||
value: string;
|
||||
description: string;
|
||||
}[];
|
||||
description: string;
|
||||
};
|
||||
experimentalOperatorPosition: {
|
||||
type: "choice";
|
||||
category: string;
|
||||
default: string;
|
||||
choices: {
|
||||
value: string;
|
||||
description: string;
|
||||
}[];
|
||||
description: string;
|
||||
};
|
||||
};
|
||||
defaultOptions: {
|
||||
arrowParens: "avoid";
|
||||
};
|
||||
};
|
||||
export default _default;
|
||||
29
frontend/src/common/prettier/plugins/java/index.js
Normal file
29
frontend/src/common/prettier/plugins/java/index.js
Normal file
@@ -0,0 +1,29 @@
|
||||
import options from "./options.js";
|
||||
import parser from "./parser.js";
|
||||
import printer from "./printer.js";
|
||||
export default {
|
||||
languages: [
|
||||
{
|
||||
name: "Java",
|
||||
parsers: ["java"],
|
||||
group: "Java",
|
||||
tmScope: "source.java",
|
||||
aceMode: "java",
|
||||
codemirrorMode: "clike",
|
||||
codemirrorMimeType: "text/x-java",
|
||||
extensions: [".java"],
|
||||
linguistLanguageId: 181,
|
||||
vscodeLanguageIds: ["java"]
|
||||
}
|
||||
],
|
||||
parsers: {
|
||||
java: parser
|
||||
},
|
||||
printers: {
|
||||
java: printer
|
||||
},
|
||||
options,
|
||||
defaultOptions: {
|
||||
arrowParens: "avoid"
|
||||
}
|
||||
};
|
||||
43
frontend/src/common/prettier/plugins/java/options.d.ts
vendored
Normal file
43
frontend/src/common/prettier/plugins/java/options.d.ts
vendored
Normal file
@@ -0,0 +1,43 @@
|
||||
declare const _default: {
|
||||
entrypoint: {
|
||||
type: "choice";
|
||||
category: string;
|
||||
default: string;
|
||||
choices: {
|
||||
value: string;
|
||||
description: string;
|
||||
}[];
|
||||
description: string;
|
||||
};
|
||||
arrowParens: {
|
||||
type: "choice";
|
||||
category: string;
|
||||
default: string;
|
||||
choices: {
|
||||
value: string;
|
||||
description: string;
|
||||
}[];
|
||||
description: string;
|
||||
};
|
||||
trailingComma: {
|
||||
type: "choice";
|
||||
category: string;
|
||||
default: string;
|
||||
choices: {
|
||||
value: string;
|
||||
description: string;
|
||||
}[];
|
||||
description: string;
|
||||
};
|
||||
experimentalOperatorPosition: {
|
||||
type: "choice";
|
||||
category: string;
|
||||
default: string;
|
||||
choices: {
|
||||
value: string;
|
||||
description: string;
|
||||
}[];
|
||||
description: string;
|
||||
};
|
||||
};
|
||||
export default _default;
|
||||
284
frontend/src/common/prettier/plugins/java/options.js
Normal file
284
frontend/src/common/prettier/plugins/java/options.js
Normal file
@@ -0,0 +1,284 @@
|
||||
export default {
|
||||
entrypoint: {
|
||||
type: "choice",
|
||||
category: "Global",
|
||||
default: "compilationUnit",
|
||||
// sed -nr 's/.*\.RULE\(([^,]+),.*/\1/p' $(ls path/to/java-parser/rules/folder/*)
|
||||
choices: [
|
||||
{ value: "arrayInitializer", description: "" },
|
||||
{ value: "variableInitializerList", description: "" },
|
||||
{ value: "block", description: "" },
|
||||
{ value: "blockStatements", description: "" },
|
||||
{ value: "blockStatement", description: "" },
|
||||
{ value: "localVariableDeclarationStatement", description: "" },
|
||||
{ value: "localVariableDeclaration", description: "" },
|
||||
{ value: "localVariableType", description: "" },
|
||||
{ value: "statement", description: "" },
|
||||
{ value: "statementWithoutTrailingSubstatement", description: "" },
|
||||
{ value: "emptyStatement", description: "" },
|
||||
{ value: "labeledStatement", description: "" },
|
||||
{ value: "expressionStatement", description: "" },
|
||||
{ value: "statementExpression", description: "" },
|
||||
{ value: "ifStatement", description: "" },
|
||||
{ value: "assertStatement", description: "" },
|
||||
{ value: "switchStatement", description: "" },
|
||||
{ value: "switchBlock", description: "" },
|
||||
{ value: "switchBlockStatementGroup", description: "" },
|
||||
{ value: "switchLabel", description: "" },
|
||||
{ value: "switchRule", description: "" },
|
||||
{ value: "caseConstant", description: "" },
|
||||
{ value: "casePattern", description: "" },
|
||||
{ value: "whileStatement", description: "" },
|
||||
{ value: "doStatement", description: "" },
|
||||
{ value: "forStatement", description: "" },
|
||||
{ value: "basicForStatement", description: "" },
|
||||
{ value: "forInit", description: "" },
|
||||
{ value: "forUpdate", description: "" },
|
||||
{ value: "statementExpressionList", description: "" },
|
||||
{ value: "enhancedForStatement", description: "" },
|
||||
{ value: "breakStatement", description: "" },
|
||||
{ value: "continueStatement", description: "" },
|
||||
{ value: "returnStatement", description: "" },
|
||||
{ value: "throwStatement", description: "" },
|
||||
{ value: "synchronizedStatement", description: "" },
|
||||
{ value: "tryStatement", description: "" },
|
||||
{ value: "catches", description: "" },
|
||||
{ value: "catchClause", description: "" },
|
||||
{ value: "catchFormalParameter", description: "" },
|
||||
{ value: "catchType", description: "" },
|
||||
{ value: "finally", description: "" },
|
||||
{ value: "tryWithResourcesStatement", description: "" },
|
||||
{ value: "resourceSpecification", description: "" },
|
||||
{ value: "resourceList", description: "" },
|
||||
{ value: "resource", description: "" },
|
||||
{ value: "yieldStatement", description: "" },
|
||||
{ value: "variableAccess", description: "" },
|
||||
{ value: "classDeclaration", description: "" },
|
||||
{ value: "normalClassDeclaration", description: "" },
|
||||
{ value: "classModifier", description: "" },
|
||||
{ value: "typeParameters", description: "" },
|
||||
{ value: "typeParameterList", description: "" },
|
||||
{ value: "classExtends", description: "" },
|
||||
{ value: "classImplements", description: "" },
|
||||
{ value: "interfaceTypeList", description: "" },
|
||||
{ value: "classPermits", description: "" },
|
||||
{ value: "classBody", description: "" },
|
||||
{ value: "classBodyDeclaration", description: "" },
|
||||
{ value: "classMemberDeclaration", description: "" },
|
||||
{ value: "fieldDeclaration", description: "" },
|
||||
{ value: "fieldModifier", description: "" },
|
||||
{ value: "variableDeclaratorList", description: "" },
|
||||
{ value: "variableDeclarator", description: "" },
|
||||
{ value: "variableDeclaratorId", description: "" },
|
||||
{ value: "variableInitializer", description: "" },
|
||||
{ value: "unannType", description: "" },
|
||||
{ value: "unannPrimitiveTypeWithOptionalDimsSuffix", description: "" },
|
||||
{ value: "unannPrimitiveType", description: "" },
|
||||
{ value: "unannReferenceType", description: "" },
|
||||
{ value: "unannClassOrInterfaceType", description: "" },
|
||||
{ value: "unannClassType", description: "" },
|
||||
{ value: "unannInterfaceType", description: "" },
|
||||
{ value: "unannTypeVariable", description: "" },
|
||||
{ value: "methodDeclaration", description: "" },
|
||||
{ value: "methodModifier", description: "" },
|
||||
{ value: "methodHeader", description: "" },
|
||||
{ value: "result", description: "" },
|
||||
{ value: "methodDeclarator", description: "" },
|
||||
{ value: "receiverParameter", description: "" },
|
||||
{ value: "formalParameterList", description: "" },
|
||||
{ value: "formalParameter", description: "" },
|
||||
{ value: "variableParaRegularParameter", description: "" },
|
||||
{ value: "variableArityParameter", description: "" },
|
||||
{ value: "variableModifier", description: "" },
|
||||
{ value: "throws", description: "" },
|
||||
{ value: "exceptionTypeList", description: "" },
|
||||
{ value: "exceptionType", description: "" },
|
||||
{ value: "methodBody", description: "" },
|
||||
{ value: "instanceInitializer", description: "" },
|
||||
{ value: "staticInitializer", description: "" },
|
||||
{ value: "constructorDeclaration", description: "" },
|
||||
{ value: "constructorModifier", description: "" },
|
||||
{ value: "constructorDeclarator", description: "" },
|
||||
{ value: "simpleTypeName", description: "" },
|
||||
{ value: "constructorBody", description: "" },
|
||||
{ value: "explicitConstructorInvocation", description: "" },
|
||||
{ value: "unqualifiedExplicitConstructorInvocation", description: "" },
|
||||
{ value: "qualifiedExplicitConstructorInvocation", description: "" },
|
||||
{ value: "enumDeclaration", description: "" },
|
||||
{ value: "enumBody", description: "" },
|
||||
{ value: "enumConstantList", description: "" },
|
||||
{ value: "enumConstant", description: "" },
|
||||
{ value: "enumConstantModifier", description: "" },
|
||||
{ value: "enumBodyDeclarations", description: "" },
|
||||
{ value: "recordDeclaration", description: "" },
|
||||
{ value: "recordHeader", description: "" },
|
||||
{ value: "recordComponentList", description: "" },
|
||||
{ value: "recordComponent", description: "" },
|
||||
{ value: "variableArityRecordComponent", description: "" },
|
||||
{ value: "recordComponentModifier", description: "" },
|
||||
{ value: "recordBody", description: "" },
|
||||
{ value: "recordBodyDeclaration", description: "" },
|
||||
{ value: "compactConstructorDeclaration", description: "" },
|
||||
{ value: "isDims", description: "" },
|
||||
{ value: "expression", description: "" },
|
||||
{ value: "lambdaExpression", description: "" },
|
||||
{ value: "lambdaParameters", description: "" },
|
||||
{ value: "lambdaParametersWithBraces", description: "" },
|
||||
{ value: "lambdaParameterList", description: "" },
|
||||
{ value: "conciseLambdaParameterList", description: "" },
|
||||
{ value: "normalLambdaParameterList", description: "" },
|
||||
{ value: "normalLambdaParameter", description: "" },
|
||||
{ value: "regularLambdaParameter", description: "" },
|
||||
{ value: "lambdaParameterType", description: "" },
|
||||
{ value: "conciseLambdaParameter", description: "" },
|
||||
{ value: "lambdaBody", description: "" },
|
||||
{ value: "conditionalExpression", description: "" },
|
||||
{ value: "binaryExpression", description: "" },
|
||||
{ value: "unaryExpression", description: "" },
|
||||
{ value: "unaryExpressionNotPlusMinus", description: "" },
|
||||
{ value: "primary", description: "" },
|
||||
{ value: "primaryPrefix", description: "" },
|
||||
{ value: "primarySuffix", description: "" },
|
||||
{ value: "fqnOrRefType", description: "" },
|
||||
{ value: "fqnOrRefTypePartRest", description: "" },
|
||||
{ value: "fqnOrRefTypePartCommon", description: "" },
|
||||
{ value: "fqnOrRefTypePartFirst", description: "" },
|
||||
{ value: "parenthesisExpression", description: "" },
|
||||
{ value: "castExpression", description: "" },
|
||||
{ value: "primitiveCastExpression", description: "" },
|
||||
{ value: "referenceTypeCastExpression", description: "" },
|
||||
{ value: "newExpression", description: "" },
|
||||
{ value: "unqualifiedClassInstanceCreationExpression", description: "" },
|
||||
{ value: "classOrInterfaceTypeToInstantiate", description: "" },
|
||||
{ value: "typeArgumentsOrDiamond", description: "" },
|
||||
{ value: "diamond", description: "" },
|
||||
{ value: "methodInvocationSuffix", description: "" },
|
||||
{ value: "argumentList", description: "" },
|
||||
{ value: "arrayCreationExpression", description: "" },
|
||||
{
|
||||
value: "arrayCreationExpressionWithoutInitializerSuffix",
|
||||
description: ""
|
||||
},
|
||||
{ value: "arrayCreationWithInitializerSuffix", description: "" },
|
||||
{ value: "dimExprs", description: "" },
|
||||
{ value: "dimExpr", description: "" },
|
||||
{ value: "classLiteralSuffix", description: "" },
|
||||
{ value: "arrayAccessSuffix", description: "" },
|
||||
{ value: "methodReferenceSuffix", description: "" },
|
||||
{ value: "templateArgument", description: "" },
|
||||
{ value: "template", description: "" },
|
||||
{ value: "stringTemplate", description: "" },
|
||||
{ value: "textBlockTemplate", description: "" },
|
||||
{ value: "embeddedExpression", description: "" },
|
||||
{ value: "pattern", description: "" },
|
||||
{ value: "typePattern", description: "" },
|
||||
{ value: "recordPattern", description: "" },
|
||||
{ value: "componentPatternList", description: "" },
|
||||
{ value: "componentPattern", description: "" },
|
||||
{ value: "matchAllPattern", description: "" },
|
||||
{ value: "guard", description: "" },
|
||||
{ value: "isRefTypeInMethodRef", description: "" },
|
||||
{ value: "interfaceDeclaration", description: "" },
|
||||
{ value: "normalInterfaceDeclaration", description: "" },
|
||||
{ value: "interfaceModifier", description: "" },
|
||||
{ value: "interfaceExtends", description: "" },
|
||||
{ value: "interfacePermits", description: "" },
|
||||
{ value: "interfaceBody", description: "" },
|
||||
{ value: "interfaceMemberDeclaration", description: "" },
|
||||
{ value: "constantDeclaration", description: "" },
|
||||
{ value: "constantModifier", description: "" },
|
||||
{ value: "interfaceMethodDeclaration", description: "" },
|
||||
{ value: "interfaceMethodModifier", description: "" },
|
||||
{ value: "annotationInterfaceDeclaration", description: "" },
|
||||
{ value: "annotationInterfaceBody", description: "" },
|
||||
{ value: "annotationInterfaceMemberDeclaration", description: "" },
|
||||
{ value: "annotationInterfaceElementDeclaration", description: "" },
|
||||
{ value: "annotationInterfaceElementModifier", description: "" },
|
||||
{ value: "defaultValue", description: "" },
|
||||
{ value: "annotation", description: "" },
|
||||
{ value: "elementValuePairList", description: "" },
|
||||
{ value: "elementValuePair", description: "" },
|
||||
{ value: "elementValue", description: "" },
|
||||
{ value: "elementValueArrayInitializer", description: "" },
|
||||
{ value: "elementValueList", description: "" },
|
||||
{ value: "literal", description: "" },
|
||||
{ value: "integerLiteral", description: "" },
|
||||
{ value: "floatingPointLiteral", description: "" },
|
||||
{ value: "booleanLiteral", description: "" },
|
||||
{ value: "shiftOperator", description: "" },
|
||||
{ value: "moduleName", description: "" },
|
||||
{ value: "packageName", description: "" },
|
||||
{ value: "typeName", description: "" },
|
||||
{ value: "expressionName", description: "" },
|
||||
{ value: "methodName", description: "" },
|
||||
{ value: "packageOrTypeName", description: "" },
|
||||
{ value: "ambiguousName", description: "" },
|
||||
{ value: "compilationUnit", description: "" },
|
||||
{ value: "ordinaryCompilationUnit", description: "" },
|
||||
{ value: "modularCompilationUnit", description: "" },
|
||||
{ value: "packageDeclaration", description: "" },
|
||||
{ value: "packageModifier", description: "" },
|
||||
{ value: "importDeclaration", description: "" },
|
||||
{ value: "typeDeclaration", description: "" },
|
||||
{ value: "moduleDeclaration", description: "" },
|
||||
{ value: "moduleDirective", description: "" },
|
||||
{ value: "requiresModuleDirective", description: "" },
|
||||
{ value: "exportsModuleDirective", description: "" },
|
||||
{ value: "opensModuleDirective", description: "" },
|
||||
{ value: "usesModuleDirective", description: "" },
|
||||
{ value: "providesModuleDirective", description: "" },
|
||||
{ value: "requiresModifier", description: "" },
|
||||
{ value: "primitiveType", description: "" },
|
||||
{ value: "numericType", description: "" },
|
||||
{ value: "integralType", description: "" },
|
||||
{ value: "floatingPointType", description: "" },
|
||||
{ value: "referenceType", description: "" },
|
||||
{ value: "classOrInterfaceType", description: "" },
|
||||
{ value: "classType", description: "" },
|
||||
{ value: "interfaceType", description: "" },
|
||||
{ value: "typeVariable", description: "" },
|
||||
{ value: "dims", description: "" },
|
||||
{ value: "typeParameter", description: "" },
|
||||
{ value: "typeParameterModifier", description: "" },
|
||||
{ value: "typeBound", description: "" },
|
||||
{ value: "additionalBound", description: "" },
|
||||
{ value: "typeArguments", description: "" },
|
||||
{ value: "typeArgumentList", description: "" },
|
||||
{ value: "typeArgument", description: "" },
|
||||
{ value: "wildcard", description: "" },
|
||||
{ value: "wildcardBounds", description: "" }
|
||||
],
|
||||
description: "Prettify from the entrypoint, allowing to use prettier on snippet."
|
||||
},
|
||||
arrowParens: {
|
||||
type: "choice",
|
||||
category: "Java",
|
||||
default: "always",
|
||||
choices: [
|
||||
{ value: "always", description: "" },
|
||||
{ value: "avoid", description: "" }
|
||||
],
|
||||
description: "Include parentheses around a sole arrow function parameter."
|
||||
},
|
||||
trailingComma: {
|
||||
type: "choice",
|
||||
category: "Java",
|
||||
default: "all",
|
||||
choices: [
|
||||
{ value: "all", description: "" },
|
||||
{ value: "es5", description: "" },
|
||||
{ value: "none", description: "" }
|
||||
],
|
||||
description: "Print trailing commas wherever possible when multi-line."
|
||||
},
|
||||
experimentalOperatorPosition: {
|
||||
type: "choice",
|
||||
category: "Java",
|
||||
default: "end",
|
||||
choices: [
|
||||
{ value: "start", description: "" },
|
||||
{ value: "end", description: "" }
|
||||
],
|
||||
description: "Where to print operators when binary expressions wrap lines."
|
||||
}
|
||||
};
|
||||
9
frontend/src/common/prettier/plugins/java/parser.d.ts
vendored
Normal file
9
frontend/src/common/prettier/plugins/java/parser.d.ts
vendored
Normal file
@@ -0,0 +1,9 @@
|
||||
import { type JavaNode, type JavaNonTerminal, type JavaParserOptions } from "./printers/helpers.js";
|
||||
declare const _default: {
|
||||
parse(text: string, options: JavaParserOptions): JavaNonTerminal;
|
||||
astFormat: string;
|
||||
hasPragma(text: string): boolean;
|
||||
locStart(node: JavaNode): number;
|
||||
locEnd(node: JavaNode): number;
|
||||
};
|
||||
export default _default;
|
||||
24
frontend/src/common/prettier/plugins/java/parser.js
Normal file
24
frontend/src/common/prettier/plugins/java/parser.js
Normal file
@@ -0,0 +1,24 @@
|
||||
import { parse } from "java-parser";
|
||||
import { determineFormatterOffOnRanges } from "./comments.js";
|
||||
import { isTerminal } from "./printers/helpers.js";
|
||||
export default {
|
||||
parse(text, options) {
|
||||
var _a;
|
||||
const cst = parse(text, options.entrypoint);
|
||||
(_a = cst.comments) === null || _a === void 0 ? void 0 : _a.forEach(comment => {
|
||||
comment.value = comment.image;
|
||||
});
|
||||
determineFormatterOffOnRanges(cst);
|
||||
return cst;
|
||||
},
|
||||
astFormat: "java",
|
||||
hasPragma(text) {
|
||||
return /^\/\*\*\n\s+\*\s@(format|prettier)\n\s+\*\//.test(text);
|
||||
},
|
||||
locStart(node) {
|
||||
return isTerminal(node) ? node.startOffset : node.location.startOffset;
|
||||
},
|
||||
locEnd(node) {
|
||||
return (isTerminal(node) ? node.endOffset : node.location.endOffset) + 1;
|
||||
}
|
||||
};
|
||||
18
frontend/src/common/prettier/plugins/java/printer.d.ts
vendored
Normal file
18
frontend/src/common/prettier/plugins/java/printer.d.ts
vendored
Normal file
@@ -0,0 +1,18 @@
|
||||
import type { AstPath } from "prettier";
|
||||
import { canAttachComment, handleLineComment, handleRemainingComment } from "./comments.js";
|
||||
import { type JavaNode } from "./printers/helpers.js";
|
||||
declare const _default: {
|
||||
print(path: DistributedAstPath<JavaNode>, options: import("prettier").ParserOptions<JavaNode>, print: (path: AstPath<JavaNode>) => import("prettier").Doc, args: unknown): import("prettier/doc.js").builders.Doc;
|
||||
hasPrettierIgnore(path: AstPath<JavaNode>): boolean;
|
||||
canAttachComment: typeof canAttachComment;
|
||||
isBlockComment(node: JavaNode): boolean;
|
||||
printComment(commentPath: AstPath<JavaNode>): string | import("prettier/doc.js").builders.Doc[];
|
||||
getCommentChildNodes(node: JavaNode): any[];
|
||||
handleComments: {
|
||||
ownLine: typeof handleLineComment;
|
||||
endOfLine: typeof handleLineComment;
|
||||
remaining: typeof handleRemainingComment;
|
||||
};
|
||||
};
|
||||
export default _default;
|
||||
type DistributedAstPath<T> = T extends any ? AstPath<T> : never;
|
||||
40
frontend/src/common/prettier/plugins/java/printer.js
Normal file
40
frontend/src/common/prettier/plugins/java/printer.js
Normal file
@@ -0,0 +1,40 @@
|
||||
import { canAttachComment, handleLineComment, handleRemainingComment, isFullyBetweenFormatterOffOn } from "./comments.js";
|
||||
import { isNonTerminal, isTerminal, printComment } from "./printers/helpers.js";
|
||||
import { printerForNodeType } from "./printers/index.js";
|
||||
export default {
|
||||
print(path, options, print, args) {
|
||||
return hasTerminal(path)
|
||||
? path.node.image
|
||||
: printerForNodeType(path.node.name)(path, print, options, args);
|
||||
},
|
||||
hasPrettierIgnore(path) {
|
||||
var _a;
|
||||
const { node } = path;
|
||||
return (((_a = node.comments) === null || _a === void 0 ? void 0 : _a.some(({ image }) => /^(\/\/\s*prettier-ignore|\/\*\s*prettier-ignore\s*\*\/)$/.test(image))) === true ||
|
||||
(canAttachComment(node) && isFullyBetweenFormatterOffOn(path)));
|
||||
},
|
||||
canAttachComment,
|
||||
isBlockComment(node) {
|
||||
return isTerminal(node) && node.tokenType.name === "TraditionalComment";
|
||||
},
|
||||
printComment(commentPath) {
|
||||
const { node } = commentPath;
|
||||
if (isNonTerminal(node) || node.tokenType.GROUP !== "comments") {
|
||||
throw new Error(`Not a comment: ${JSON.stringify(node)}`);
|
||||
}
|
||||
return printComment(node);
|
||||
},
|
||||
getCommentChildNodes(node) {
|
||||
return isNonTerminal(node)
|
||||
? Object.values(node.children).flatMap(child => child)
|
||||
: [];
|
||||
},
|
||||
handleComments: {
|
||||
ownLine: handleLineComment,
|
||||
endOfLine: handleLineComment,
|
||||
remaining: handleRemainingComment
|
||||
}
|
||||
};
|
||||
function hasTerminal(path) {
|
||||
return isTerminal(path.node);
|
||||
}
|
||||
9
frontend/src/common/prettier/plugins/java/printers/arrays.d.ts
vendored
Normal file
9
frontend/src/common/prettier/plugins/java/printers/arrays.d.ts
vendored
Normal file
@@ -0,0 +1,9 @@
|
||||
declare const _default: {
|
||||
arrayInitializer(path: import("prettier").AstPath<import("java-parser").ArrayInitializerCstNode & {
|
||||
comments?: import("../comments.js").JavaComment[];
|
||||
}>, print: import("./helpers.js").JavaPrintFn, options: import("./helpers.js").JavaParserOptions): import("prettier/doc.js").builders.Group | "{}";
|
||||
variableInitializerList(path: import("prettier").AstPath<import("java-parser").VariableInitializerListCstNode & {
|
||||
comments?: import("../comments.js").JavaComment[];
|
||||
}>, print: import("./helpers.js").JavaPrintFn): import("prettier/doc.js").builders.Doc[];
|
||||
};
|
||||
export default _default;
|
||||
@@ -0,0 +1,9 @@
|
||||
import { printArrayInitializer, printList } from "./helpers.js";
|
||||
export default {
|
||||
arrayInitializer(path, print, options) {
|
||||
return printArrayInitializer(path, print, options, "variableInitializerList");
|
||||
},
|
||||
variableInitializerList(path, print) {
|
||||
return printList(path, print, "variableInitializer");
|
||||
}
|
||||
};
|
||||
117
frontend/src/common/prettier/plugins/java/printers/blocks-and-statements.d.ts
vendored
Normal file
117
frontend/src/common/prettier/plugins/java/printers/blocks-and-statements.d.ts
vendored
Normal file
@@ -0,0 +1,117 @@
|
||||
import { builders } from "prettier/doc";
|
||||
import { printSingle } from "./helpers.js";
|
||||
declare const _default: {
|
||||
block(path: import("prettier").AstPath<import("java-parser").BlockCstNode & {
|
||||
comments?: import("../comments.js").JavaComment[];
|
||||
}>, print: import("./helpers.js").JavaPrintFn): builders.Group | "{}" | (string | builders.Indent | builders.Hardline)[];
|
||||
blockStatements(path: import("prettier").AstPath<import("java-parser").BlockStatementsCstNode & {
|
||||
comments?: import("../comments.js").JavaComment[];
|
||||
}>, print: import("./helpers.js").JavaPrintFn): builders.Doc[];
|
||||
blockStatement: typeof printSingle;
|
||||
localVariableDeclarationStatement(path: import("prettier").AstPath<import("java-parser").LocalVariableDeclarationStatementCstNode & {
|
||||
comments?: import("../comments.js").JavaComment[];
|
||||
}>, print: import("./helpers.js").JavaPrintFn): builders.Doc[];
|
||||
localVariableDeclaration(path: import("prettier").AstPath<import("java-parser").LocalVariableDeclarationCstNode & {
|
||||
comments?: import("../comments.js").JavaComment[];
|
||||
}>, print: import("./helpers.js").JavaPrintFn): builders.Doc[];
|
||||
localVariableType: typeof printSingle;
|
||||
statement: typeof printSingle;
|
||||
statementWithoutTrailingSubstatement: typeof printSingle;
|
||||
emptyStatement(): string;
|
||||
labeledStatement(path: import("prettier").AstPath<import("java-parser").LabeledStatementCstNode & {
|
||||
comments?: import("../comments.js").JavaComment[];
|
||||
}>, print: import("./helpers.js").JavaPrintFn): builders.Doc[];
|
||||
expressionStatement(path: import("prettier").AstPath<import("java-parser").ExpressionStatementCstNode & {
|
||||
comments?: import("../comments.js").JavaComment[];
|
||||
}>, print: import("./helpers.js").JavaPrintFn): builders.Doc[];
|
||||
statementExpression: typeof printSingle;
|
||||
ifStatement(path: import("prettier").AstPath<import("java-parser").IfStatementCstNode & {
|
||||
comments?: import("../comments.js").JavaComment[];
|
||||
}>, print: import("./helpers.js").JavaPrintFn): builders.Doc[];
|
||||
assertStatement(path: import("prettier").AstPath<import("java-parser").AssertStatementCstNode & {
|
||||
comments?: import("../comments.js").JavaComment[];
|
||||
}>, print: import("./helpers.js").JavaPrintFn): builders.Doc[];
|
||||
switchStatement(path: import("prettier").AstPath<import("java-parser").SwitchStatementCstNode & {
|
||||
comments?: import("../comments.js").JavaComment[];
|
||||
}>, print: import("./helpers.js").JavaPrintFn): builders.Doc[];
|
||||
switchBlock(path: import("prettier").AstPath<import("java-parser").SwitchBlockCstNode & {
|
||||
comments?: import("../comments.js").JavaComment[];
|
||||
}>, print: import("./helpers.js").JavaPrintFn): builders.Group | "{}" | (string | builders.Indent | builders.Hardline)[];
|
||||
switchBlockStatementGroup(path: import("prettier").AstPath<import("java-parser").SwitchBlockStatementGroupCstNode & {
|
||||
comments?: import("../comments.js").JavaComment[];
|
||||
}>, print: import("./helpers.js").JavaPrintFn): builders.Doc[];
|
||||
switchLabel(path: import("prettier").AstPath<import("java-parser").SwitchLabelCstNode & {
|
||||
comments?: import("../comments.js").JavaComment[];
|
||||
}>, print: import("./helpers.js").JavaPrintFn): "default" | builders.Group | builders.Doc[];
|
||||
switchRule(path: import("prettier").AstPath<import("java-parser").SwitchRuleCstNode & {
|
||||
comments?: import("../comments.js").JavaComment[];
|
||||
}>, print: import("./helpers.js").JavaPrintFn): builders.Doc[];
|
||||
caseConstant: typeof printSingle;
|
||||
casePattern: typeof printSingle;
|
||||
whileStatement(path: import("prettier").AstPath<import("java-parser").WhileStatementCstNode & {
|
||||
comments?: import("../comments.js").JavaComment[];
|
||||
}>, print: import("./helpers.js").JavaPrintFn): builders.Doc[];
|
||||
doStatement(path: import("prettier").AstPath<import("java-parser").DoStatementCstNode & {
|
||||
comments?: import("../comments.js").JavaComment[];
|
||||
}>, print: import("./helpers.js").JavaPrintFn): (string | builders.Group | builders.Doc[])[];
|
||||
forStatement: typeof printSingle;
|
||||
basicForStatement(path: import("prettier").AstPath<import("java-parser").BasicForStatementCstNode & {
|
||||
comments?: import("../comments.js").JavaComment[];
|
||||
}>, print: import("./helpers.js").JavaPrintFn): builders.Doc[];
|
||||
forInit: typeof printSingle;
|
||||
forUpdate: typeof printSingle;
|
||||
statementExpressionList(path: import("prettier").AstPath<import("java-parser").StatementExpressionListCstNode & {
|
||||
comments?: import("../comments.js").JavaComment[];
|
||||
}>, print: import("./helpers.js").JavaPrintFn): builders.Group;
|
||||
enhancedForStatement(path: import("prettier").AstPath<import("java-parser").EnhancedForStatementCstNode & {
|
||||
comments?: import("../comments.js").JavaComment[];
|
||||
}>, print: import("./helpers.js").JavaPrintFn): builders.Group;
|
||||
breakStatement(path: import("prettier").AstPath<import("java-parser").BreakStatementCstNode & {
|
||||
comments?: import("../comments.js").JavaComment[];
|
||||
}>, print: import("./helpers.js").JavaPrintFn): builders.Doc[] | "break;";
|
||||
continueStatement(path: import("prettier").AstPath<import("java-parser").ContinueStatementCstNode & {
|
||||
comments?: import("../comments.js").JavaComment[];
|
||||
}>, print: import("./helpers.js").JavaPrintFn): builders.Doc[] | "continue;";
|
||||
returnStatement(path: import("prettier").AstPath<import("java-parser").ReturnStatementCstNode & {
|
||||
comments?: import("../comments.js").JavaComment[];
|
||||
}>, print: import("./helpers.js").JavaPrintFn): builders.Doc[];
|
||||
throwStatement(path: import("prettier").AstPath<import("java-parser").ThrowStatementCstNode & {
|
||||
comments?: import("../comments.js").JavaComment[];
|
||||
}>, print: import("./helpers.js").JavaPrintFn): builders.Doc[];
|
||||
synchronizedStatement(path: import("prettier").AstPath<import("java-parser").SynchronizedStatementCstNode & {
|
||||
comments?: import("../comments.js").JavaComment[];
|
||||
}>, print: import("./helpers.js").JavaPrintFn): builders.Doc[];
|
||||
tryStatement(path: import("prettier").AstPath<import("java-parser").TryStatementCstNode & {
|
||||
comments?: import("../comments.js").JavaComment[];
|
||||
}>, print: import("./helpers.js").JavaPrintFn): builders.Doc;
|
||||
catches(path: import("prettier").AstPath<import("java-parser").CatchesCstNode & {
|
||||
comments?: import("../comments.js").JavaComment[];
|
||||
}>, print: import("./helpers.js").JavaPrintFn): builders.Doc[];
|
||||
catchClause(path: import("prettier").AstPath<import("java-parser").CatchClauseCstNode & {
|
||||
comments?: import("../comments.js").JavaComment[];
|
||||
}>, print: import("./helpers.js").JavaPrintFn): builders.Doc[];
|
||||
catchFormalParameter(path: import("prettier").AstPath<import("java-parser").CatchFormalParameterCstNode & {
|
||||
comments?: import("../comments.js").JavaComment[];
|
||||
}>, print: import("./helpers.js").JavaPrintFn): builders.Doc[];
|
||||
catchType(path: import("prettier").AstPath<import("java-parser").CatchTypeCstNode & {
|
||||
comments?: import("../comments.js").JavaComment[];
|
||||
}>, print: import("./helpers.js").JavaPrintFn): builders.Doc[];
|
||||
finally(path: import("prettier").AstPath<import("java-parser").FinallyCstNode & {
|
||||
comments?: import("../comments.js").JavaComment[];
|
||||
}>, print: import("./helpers.js").JavaPrintFn): builders.Doc[];
|
||||
tryWithResourcesStatement(path: import("prettier").AstPath<import("java-parser").TryWithResourcesStatementCstNode & {
|
||||
comments?: import("../comments.js").JavaComment[];
|
||||
}>, print: import("./helpers.js").JavaPrintFn): builders.Doc[];
|
||||
resourceSpecification(path: import("prettier").AstPath<import("java-parser").ResourceSpecificationCstNode & {
|
||||
comments?: import("../comments.js").JavaComment[];
|
||||
}>, print: import("./helpers.js").JavaPrintFn): builders.Group | "()";
|
||||
resourceList(path: import("prettier").AstPath<import("java-parser").ResourceListCstNode & {
|
||||
comments?: import("../comments.js").JavaComment[];
|
||||
}>, print: import("./helpers.js").JavaPrintFn): builders.Doc[];
|
||||
resource: typeof printSingle;
|
||||
yieldStatement(path: import("prettier").AstPath<import("java-parser").YieldStatementCstNode & {
|
||||
comments?: import("../comments.js").JavaComment[];
|
||||
}>, print: import("./helpers.js").JavaPrintFn): builders.Doc[];
|
||||
variableAccess: typeof printSingle;
|
||||
};
|
||||
export default _default;
|
||||
@@ -0,0 +1,337 @@
|
||||
import { builders } from "prettier/doc";
|
||||
import { call, definedKeys, indentInParentheses, isBinaryExpression, isEmptyStatement, lineEndWithComments, lineStartWithComments, map, onlyDefinedKey, printBlock, printDanglingComments, printSingle, printWithModifiers } from "./helpers.js";
|
||||
const { group, hardline, ifBreak, indent, join, line, softline } = builders;
|
||||
export default {
|
||||
block(path, print) {
|
||||
const statements = path.node.children.blockStatements
|
||||
? call(path, print, "blockStatements")
|
||||
: [];
|
||||
return printBlock(path, statements.length ? [statements] : []);
|
||||
},
|
||||
blockStatements(path, print) {
|
||||
return join(hardline, map(path, statementPath => {
|
||||
const { node, previous } = statementPath;
|
||||
const statement = print(statementPath);
|
||||
return previous &&
|
||||
lineStartWithComments(node) > lineEndWithComments(previous) + 1
|
||||
? [hardline, statement]
|
||||
: statement;
|
||||
}, "blockStatement").filter(doc => doc !== ""));
|
||||
},
|
||||
blockStatement: printSingle,
|
||||
localVariableDeclarationStatement(path, print) {
|
||||
return [call(path, print, "localVariableDeclaration"), ";"];
|
||||
},
|
||||
localVariableDeclaration(path, print) {
|
||||
const declaration = join(" ", [
|
||||
call(path, print, "localVariableType"),
|
||||
call(path, print, "variableDeclaratorList")
|
||||
]);
|
||||
return printWithModifiers(path, print, "variableModifier", declaration);
|
||||
},
|
||||
localVariableType: printSingle,
|
||||
statement: printSingle,
|
||||
statementWithoutTrailingSubstatement: printSingle,
|
||||
emptyStatement() {
|
||||
return "";
|
||||
},
|
||||
labeledStatement(path, print) {
|
||||
return [
|
||||
call(path, print, "Identifier"),
|
||||
": ",
|
||||
call(path, print, "statement")
|
||||
];
|
||||
},
|
||||
expressionStatement(path, print) {
|
||||
return [call(path, print, "statementExpression"), ";"];
|
||||
},
|
||||
statementExpression: printSingle,
|
||||
ifStatement(path, print) {
|
||||
var _a;
|
||||
const { children } = path.node;
|
||||
const hasEmptyStatement = isEmptyStatement(children.statement[0]);
|
||||
const statements = map(path, print, "statement");
|
||||
const statement = [
|
||||
"if ",
|
||||
indentInParentheses(call(path, print, "expression")),
|
||||
hasEmptyStatement ? ";" : [" ", statements[0]]
|
||||
];
|
||||
if (children.Else) {
|
||||
const danglingComments = printDanglingComments(path);
|
||||
if (danglingComments.length) {
|
||||
statement.push(hardline, ...danglingComments, hardline);
|
||||
}
|
||||
else {
|
||||
const elseHasBlock = ((_a = children.statement[0].children
|
||||
.statementWithoutTrailingSubstatement) === null || _a === void 0 ? void 0 : _a[0].children.block) !==
|
||||
undefined;
|
||||
statement.push(elseHasBlock ? " " : hardline);
|
||||
}
|
||||
const elseHasEmptyStatement = isEmptyStatement(children.statement[1]);
|
||||
statement.push("else", elseHasEmptyStatement ? ";" : [" ", statements[1]]);
|
||||
}
|
||||
return statement;
|
||||
},
|
||||
assertStatement(path, print) {
|
||||
return ["assert ", ...join([" : "], map(path, print, "expression")), ";"];
|
||||
},
|
||||
switchStatement(path, print) {
|
||||
return join(" ", [
|
||||
"switch",
|
||||
indentInParentheses(call(path, print, "expression")),
|
||||
call(path, print, "switchBlock")
|
||||
]);
|
||||
},
|
||||
switchBlock(path, print) {
|
||||
const { children } = path.node;
|
||||
const caseKeys = definedKeys(children, [
|
||||
"switchBlockStatementGroup",
|
||||
"switchRule"
|
||||
]);
|
||||
const cases = caseKeys.length === 1 ? map(path, print, caseKeys[0]) : [];
|
||||
return printBlock(path, cases);
|
||||
},
|
||||
switchBlockStatementGroup(path, print) {
|
||||
var _a, _b;
|
||||
const { children } = path.node;
|
||||
const switchLabel = call(path, print, "switchLabel");
|
||||
if (!children.blockStatements) {
|
||||
return [switchLabel, ":"];
|
||||
}
|
||||
const blockStatements = call(path, print, "blockStatements");
|
||||
const statements = children.blockStatements[0].children.blockStatement;
|
||||
const onlyStatementIsBlock = statements.length === 1 &&
|
||||
((_b = (_a = statements[0].children.statement) === null || _a === void 0 ? void 0 : _a[0].children.statementWithoutTrailingSubstatement) === null || _b === void 0 ? void 0 : _b[0].children.block) !== undefined;
|
||||
return [
|
||||
switchLabel,
|
||||
":",
|
||||
onlyStatementIsBlock
|
||||
? [" ", blockStatements]
|
||||
: indent([hardline, blockStatements])
|
||||
];
|
||||
},
|
||||
switchLabel(path, print) {
|
||||
var _a, _b;
|
||||
const { children } = path.node;
|
||||
if (!((_b = (_a = children.caseConstant) !== null && _a !== void 0 ? _a : children.casePattern) !== null && _b !== void 0 ? _b : children.Null)) {
|
||||
return "default";
|
||||
}
|
||||
const values = [];
|
||||
if (children.Null) {
|
||||
values.push("null");
|
||||
if (children.Default) {
|
||||
values.push("default");
|
||||
}
|
||||
}
|
||||
else {
|
||||
const valuesKey = onlyDefinedKey(children, [
|
||||
"caseConstant",
|
||||
"casePattern"
|
||||
]);
|
||||
values.push(...map(path, print, valuesKey));
|
||||
}
|
||||
const hasMultipleValues = values.length > 1;
|
||||
const label = hasMultipleValues
|
||||
? ["case", indent([line, ...join([",", line], values)])]
|
||||
: ["case ", values[0]];
|
||||
return children.guard
|
||||
? [
|
||||
group([...label, hasMultipleValues ? line : " "]),
|
||||
call(path, print, "guard")
|
||||
]
|
||||
: group(label);
|
||||
},
|
||||
switchRule(path, print) {
|
||||
const { children } = path.node;
|
||||
const bodyKey = onlyDefinedKey(children, [
|
||||
"block",
|
||||
"expression",
|
||||
"throwStatement"
|
||||
]);
|
||||
const parts = [
|
||||
call(path, print, "switchLabel"),
|
||||
" -> ",
|
||||
call(path, print, bodyKey)
|
||||
];
|
||||
if (children.Semicolon) {
|
||||
parts.push(";");
|
||||
}
|
||||
return parts;
|
||||
},
|
||||
caseConstant: printSingle,
|
||||
casePattern: printSingle,
|
||||
whileStatement(path, print) {
|
||||
const statement = call(path, print, "statement");
|
||||
const hasEmptyStatement = isEmptyStatement(path.node.children.statement[0]);
|
||||
return [
|
||||
"while ",
|
||||
indentInParentheses(call(path, print, "expression")),
|
||||
...[hasEmptyStatement ? ";" : " ", statement]
|
||||
];
|
||||
},
|
||||
doStatement(path, print) {
|
||||
const hasEmptyStatement = isEmptyStatement(path.node.children.statement[0]);
|
||||
return [
|
||||
"do",
|
||||
hasEmptyStatement ? ";" : [" ", call(path, print, "statement")],
|
||||
" while ",
|
||||
indentInParentheses(call(path, print, "expression")),
|
||||
";"
|
||||
];
|
||||
},
|
||||
forStatement: printSingle,
|
||||
basicForStatement(path, print) {
|
||||
const { children } = path.node;
|
||||
const danglingComments = printDanglingComments(path);
|
||||
if (danglingComments.length) {
|
||||
danglingComments.push(hardline);
|
||||
}
|
||||
const expressions = ["forInit", "expression", "forUpdate"].map(expressionKey => expressionKey in children ? call(path, print, expressionKey) : "");
|
||||
const hasEmptyStatement = isEmptyStatement(children.statement[0]);
|
||||
return [
|
||||
...danglingComments,
|
||||
"for ",
|
||||
expressions.some(expression => expression !== "")
|
||||
? indentInParentheses(join([";", line], expressions))
|
||||
: "(;;)",
|
||||
hasEmptyStatement ? ";" : [" ", call(path, print, "statement")]
|
||||
];
|
||||
},
|
||||
forInit: printSingle,
|
||||
forUpdate: printSingle,
|
||||
statementExpressionList(path, print) {
|
||||
return group(map(path, print, "statementExpression").map((expression, index) => index === 0 ? expression : [",", indent([line, expression])]));
|
||||
},
|
||||
enhancedForStatement(path, print) {
|
||||
var _a;
|
||||
const statementNode = path.node.children.statement[0];
|
||||
const forStatement = [
|
||||
printDanglingComments(path),
|
||||
"for ",
|
||||
"(",
|
||||
call(path, print, "localVariableDeclaration"),
|
||||
" : ",
|
||||
call(path, print, "expression"),
|
||||
")"
|
||||
];
|
||||
if (isEmptyStatement(statementNode)) {
|
||||
forStatement.push(";");
|
||||
}
|
||||
else {
|
||||
const hasStatementBlock = ((_a = statementNode.children.statementWithoutTrailingSubstatement) === null || _a === void 0 ? void 0 : _a[0].children.block) !== undefined;
|
||||
const statement = call(path, print, "statement");
|
||||
forStatement.push(hasStatementBlock ? [" ", statement] : indent([line, statement]));
|
||||
}
|
||||
return group(forStatement);
|
||||
},
|
||||
breakStatement(path, print) {
|
||||
return path.node.children.Identifier
|
||||
? ["break ", call(path, print, "Identifier"), ";"]
|
||||
: "break;";
|
||||
},
|
||||
continueStatement(path, print) {
|
||||
return path.node.children.Identifier
|
||||
? ["continue ", call(path, print, "Identifier"), ";"]
|
||||
: "continue;";
|
||||
},
|
||||
returnStatement(path, print) {
|
||||
const { children } = path.node;
|
||||
const statement = ["return"];
|
||||
if (children.expression) {
|
||||
statement.push(" ");
|
||||
const expression = call(path, print, "expression");
|
||||
if (isBinaryExpression(children.expression[0])) {
|
||||
statement.push(group([
|
||||
ifBreak("("),
|
||||
indent([softline, expression]),
|
||||
softline,
|
||||
ifBreak(")")
|
||||
]));
|
||||
}
|
||||
else {
|
||||
statement.push(expression);
|
||||
}
|
||||
}
|
||||
statement.push(";");
|
||||
return statement;
|
||||
},
|
||||
throwStatement(path, print) {
|
||||
return ["throw ", call(path, print, "expression"), ";"];
|
||||
},
|
||||
synchronizedStatement(path, print) {
|
||||
return [
|
||||
"synchronized ",
|
||||
indentInParentheses(call(path, print, "expression")),
|
||||
" ",
|
||||
call(path, print, "block")
|
||||
];
|
||||
},
|
||||
tryStatement(path, print) {
|
||||
const { children } = path.node;
|
||||
if (children.tryWithResourcesStatement) {
|
||||
return call(path, print, "tryWithResourcesStatement");
|
||||
}
|
||||
const blocks = ["try", call(path, print, "block")];
|
||||
if (children.catches) {
|
||||
blocks.push(call(path, print, "catches"));
|
||||
}
|
||||
if (children.finally) {
|
||||
blocks.push(call(path, print, "finally"));
|
||||
}
|
||||
return join(" ", blocks);
|
||||
},
|
||||
catches(path, print) {
|
||||
return join(" ", map(path, print, "catchClause"));
|
||||
},
|
||||
catchClause(path, print) {
|
||||
return [
|
||||
"catch ",
|
||||
indentInParentheses(call(path, print, "catchFormalParameter")),
|
||||
" ",
|
||||
call(path, print, "block")
|
||||
];
|
||||
},
|
||||
catchFormalParameter(path, print) {
|
||||
return join(" ", [
|
||||
...map(path, print, "variableModifier"),
|
||||
call(path, print, "catchType"),
|
||||
call(path, print, "variableDeclaratorId")
|
||||
]);
|
||||
},
|
||||
catchType(path, print) {
|
||||
return join([line, "| "], [call(path, print, "unannClassType"), ...map(path, print, "classType")]);
|
||||
},
|
||||
finally(path, print) {
|
||||
return ["finally ", call(path, print, "block")];
|
||||
},
|
||||
tryWithResourcesStatement(path, print) {
|
||||
const { children } = path.node;
|
||||
const blocks = [
|
||||
"try",
|
||||
call(path, print, "resourceSpecification"),
|
||||
call(path, print, "block")
|
||||
];
|
||||
if (children.catches) {
|
||||
blocks.push(call(path, print, "catches"));
|
||||
}
|
||||
if (children.finally) {
|
||||
blocks.push(call(path, print, "finally"));
|
||||
}
|
||||
return join(" ", blocks);
|
||||
},
|
||||
resourceSpecification(path, print) {
|
||||
const resources = [call(path, print, "resourceList")];
|
||||
if (path.node.children.Semicolon) {
|
||||
resources.push(ifBreak(";"));
|
||||
}
|
||||
return indentInParentheses(resources);
|
||||
},
|
||||
resourceList(path, print) {
|
||||
return join([";", line], map(path, print, "resource"));
|
||||
},
|
||||
resource: printSingle,
|
||||
yieldStatement(path, print) {
|
||||
return ["yield ", call(path, print, "expression"), ";"];
|
||||
},
|
||||
variableAccess: printSingle
|
||||
};
|
||||
157
frontend/src/common/prettier/plugins/java/printers/classes.d.ts
vendored
Normal file
157
frontend/src/common/prettier/plugins/java/printers/classes.d.ts
vendored
Normal file
@@ -0,0 +1,157 @@
|
||||
import type { ClassBodyCstNode, EnumBodyDeclarationsCstNode } from "java-parser";
|
||||
import type { AstPath } from "prettier";
|
||||
import { builders } from "prettier/doc";
|
||||
import { printClassPermits, printClassType, printSingle, type JavaPrintFn } from "./helpers.js";
|
||||
declare const _default: {
|
||||
classDeclaration(path: AstPath<import("java-parser").ClassDeclarationCstNode & {
|
||||
comments?: import("../comments.js").JavaComment[];
|
||||
}>, print: JavaPrintFn): builders.Doc[];
|
||||
normalClassDeclaration(path: AstPath<import("java-parser").NormalClassDeclarationCstNode & {
|
||||
comments?: import("../comments.js").JavaComment[];
|
||||
}>, print: JavaPrintFn): builders.Doc[];
|
||||
classModifier: typeof printSingle;
|
||||
typeParameters(path: AstPath<import("java-parser").TypeParametersCstNode & {
|
||||
comments?: import("../comments.js").JavaComment[];
|
||||
}>, print: JavaPrintFn): builders.Group;
|
||||
typeParameterList(path: AstPath<import("java-parser").TypeParameterListCstNode & {
|
||||
comments?: import("../comments.js").JavaComment[];
|
||||
}>, print: JavaPrintFn): builders.Doc[];
|
||||
classExtends(path: AstPath<import("java-parser").ClassExtendsCstNode & {
|
||||
comments?: import("../comments.js").JavaComment[];
|
||||
}>, print: JavaPrintFn): builders.Doc[];
|
||||
classImplements(path: AstPath<import("java-parser").ClassImplementsCstNode & {
|
||||
comments?: import("../comments.js").JavaComment[];
|
||||
}>, print: JavaPrintFn): builders.Group;
|
||||
classPermits: typeof printClassPermits;
|
||||
interfaceTypeList(path: AstPath<import("java-parser").InterfaceTypeListCstNode & {
|
||||
comments?: import("../comments.js").JavaComment[];
|
||||
}>, print: JavaPrintFn): builders.Group;
|
||||
classBody(path: AstPath<ClassBodyCstNode & {
|
||||
comments?: import("../comments.js").JavaComment[];
|
||||
}>, print: JavaPrintFn): builders.Group | "{}" | (string | builders.Indent | builders.Hardline)[];
|
||||
classBodyDeclaration: typeof printSingle;
|
||||
classMemberDeclaration(path: AstPath<import("java-parser").ClassMemberDeclarationCstNode & {
|
||||
comments?: import("../comments.js").JavaComment[];
|
||||
}>, print: JavaPrintFn): builders.Doc;
|
||||
fieldDeclaration(path: AstPath<import("java-parser").FieldDeclarationCstNode & {
|
||||
comments?: import("../comments.js").JavaComment[];
|
||||
}>, print: JavaPrintFn): builders.Doc[];
|
||||
fieldModifier: typeof printSingle;
|
||||
variableDeclaratorList(path: AstPath<import("java-parser").VariableDeclaratorListCstNode & {
|
||||
comments?: import("../comments.js").JavaComment[];
|
||||
}>, print: JavaPrintFn): builders.Group | builders.Doc[];
|
||||
variableDeclarator(path: AstPath<import("java-parser").VariableDeclaratorCstNode & {
|
||||
comments?: import("../comments.js").JavaComment[];
|
||||
}>, print: JavaPrintFn): builders.Doc;
|
||||
variableDeclaratorId(path: AstPath<import("java-parser").VariableDeclaratorIdCstNode & {
|
||||
comments?: import("../comments.js").JavaComment[];
|
||||
}>, print: JavaPrintFn): builders.Doc;
|
||||
variableInitializer: typeof printSingle;
|
||||
unannType: typeof printSingle;
|
||||
unannPrimitiveTypeWithOptionalDimsSuffix(path: AstPath<import("java-parser").UnannPrimitiveTypeWithOptionalDimsSuffixCstNode & {
|
||||
comments?: import("../comments.js").JavaComment[];
|
||||
}>, print: JavaPrintFn): builders.Doc;
|
||||
unannPrimitiveType: typeof printSingle;
|
||||
unannReferenceType(path: AstPath<import("java-parser").UnannReferenceTypeCstNode & {
|
||||
comments?: import("../comments.js").JavaComment[];
|
||||
}>, print: JavaPrintFn): builders.Doc;
|
||||
unannClassOrInterfaceType: typeof printSingle;
|
||||
unannClassType: typeof printClassType;
|
||||
unannInterfaceType: typeof printSingle;
|
||||
unannTypeVariable: typeof printSingle;
|
||||
methodDeclaration(path: AstPath<import("java-parser").MethodDeclarationCstNode & {
|
||||
comments?: import("../comments.js").JavaComment[];
|
||||
}>, print: JavaPrintFn): builders.Doc[];
|
||||
methodModifier: typeof printSingle;
|
||||
methodHeader(path: AstPath<import("java-parser").MethodHeaderCstNode & {
|
||||
comments?: import("../comments.js").JavaComment[];
|
||||
}>, print: JavaPrintFn): builders.Group;
|
||||
result: typeof printSingle;
|
||||
methodDeclarator(path: AstPath<import("java-parser").MethodDeclaratorCstNode & {
|
||||
comments?: import("../comments.js").JavaComment[];
|
||||
}>, print: JavaPrintFn): builders.Doc[];
|
||||
receiverParameter(path: AstPath<import("java-parser").ReceiverParameterCstNode & {
|
||||
comments?: import("../comments.js").JavaComment[];
|
||||
}>, print: JavaPrintFn): builders.Doc[];
|
||||
formalParameterList(path: AstPath<import("java-parser").FormalParameterListCstNode & {
|
||||
comments?: import("../comments.js").JavaComment[];
|
||||
}>, print: JavaPrintFn): builders.Doc[];
|
||||
formalParameter: typeof printSingle;
|
||||
variableParaRegularParameter(path: AstPath<import("java-parser").VariableParaRegularParameterCstNode & {
|
||||
comments?: import("../comments.js").JavaComment[];
|
||||
}>, print: JavaPrintFn): builders.Doc[];
|
||||
variableArityParameter(path: AstPath<import("java-parser").VariableArityParameterCstNode & {
|
||||
comments?: import("../comments.js").JavaComment[];
|
||||
}>, print: JavaPrintFn): builders.Doc[];
|
||||
variableModifier: typeof printSingle;
|
||||
throws(path: AstPath<import("java-parser").ThrowsCstNode & {
|
||||
comments?: import("../comments.js").JavaComment[];
|
||||
}>, print: JavaPrintFn): builders.Doc[];
|
||||
exceptionTypeList(path: AstPath<import("java-parser").ExceptionTypeListCstNode & {
|
||||
comments?: import("../comments.js").JavaComment[];
|
||||
}>, print: JavaPrintFn): builders.Doc[];
|
||||
exceptionType: typeof printSingle;
|
||||
methodBody: typeof printSingle;
|
||||
instanceInitializer: typeof printSingle;
|
||||
staticInitializer(path: AstPath<import("java-parser").StaticInitializerCstNode & {
|
||||
comments?: import("../comments.js").JavaComment[];
|
||||
}>, print: JavaPrintFn): builders.Doc[];
|
||||
constructorDeclaration(path: AstPath<import("java-parser").ConstructorDeclarationCstNode & {
|
||||
comments?: import("../comments.js").JavaComment[];
|
||||
}>, print: JavaPrintFn): builders.Doc[];
|
||||
constructorModifier: typeof printSingle;
|
||||
constructorDeclarator(path: AstPath<import("java-parser").ConstructorDeclaratorCstNode & {
|
||||
comments?: import("../comments.js").JavaComment[];
|
||||
}>, print: JavaPrintFn): builders.Doc[];
|
||||
simpleTypeName: typeof printSingle;
|
||||
constructorBody(path: AstPath<import("java-parser").ConstructorBodyCstNode & {
|
||||
comments?: import("../comments.js").JavaComment[];
|
||||
}>, print: JavaPrintFn): builders.Group | "{}" | (string | builders.Indent | builders.Hardline)[];
|
||||
explicitConstructorInvocation: typeof printSingle;
|
||||
unqualifiedExplicitConstructorInvocation(path: AstPath<import("java-parser").UnqualifiedExplicitConstructorInvocationCstNode & {
|
||||
comments?: import("../comments.js").JavaComment[];
|
||||
}>, print: JavaPrintFn): builders.Doc[];
|
||||
qualifiedExplicitConstructorInvocation(path: AstPath<import("java-parser").QualifiedExplicitConstructorInvocationCstNode & {
|
||||
comments?: import("../comments.js").JavaComment[];
|
||||
}>, print: JavaPrintFn): builders.Doc[];
|
||||
enumDeclaration(path: AstPath<import("java-parser").EnumDeclarationCstNode & {
|
||||
comments?: import("../comments.js").JavaComment[];
|
||||
}>, print: JavaPrintFn): builders.Doc[];
|
||||
enumBody(path: AstPath<import("java-parser").EnumBodyCstNode & {
|
||||
comments?: import("../comments.js").JavaComment[];
|
||||
}>, print: JavaPrintFn, options: import("./helpers.js").JavaParserOptions): builders.Group | "{}" | (string | builders.Indent | builders.Hardline)[];
|
||||
enumConstantList(path: AstPath<import("java-parser").EnumConstantListCstNode & {
|
||||
comments?: import("../comments.js").JavaComment[];
|
||||
}>, print: JavaPrintFn): builders.Doc[];
|
||||
enumConstant(path: AstPath<import("java-parser").EnumConstantCstNode & {
|
||||
comments?: import("../comments.js").JavaComment[];
|
||||
}>, print: JavaPrintFn): builders.Doc[];
|
||||
enumConstantModifier: typeof printSingle;
|
||||
enumBodyDeclarations(path: AstPath<EnumBodyDeclarationsCstNode & {
|
||||
comments?: import("../comments.js").JavaComment[];
|
||||
}>, print: JavaPrintFn): builders.Doc[];
|
||||
recordDeclaration(path: AstPath<import("java-parser").RecordDeclarationCstNode & {
|
||||
comments?: import("../comments.js").JavaComment[];
|
||||
}>, print: JavaPrintFn): builders.Doc[];
|
||||
recordHeader(path: AstPath<import("java-parser").RecordHeaderCstNode & {
|
||||
comments?: import("../comments.js").JavaComment[];
|
||||
}>, print: JavaPrintFn): builders.Group | "()";
|
||||
recordComponentList(path: AstPath<import("java-parser").RecordComponentListCstNode & {
|
||||
comments?: import("../comments.js").JavaComment[];
|
||||
}>, print: JavaPrintFn): builders.Doc[];
|
||||
recordComponent(path: AstPath<import("java-parser").RecordComponentCstNode & {
|
||||
comments?: import("../comments.js").JavaComment[];
|
||||
}>, print: JavaPrintFn): builders.Group;
|
||||
variableArityRecordComponent(path: AstPath<import("java-parser").VariableArityRecordComponentCstNode & {
|
||||
comments?: import("../comments.js").JavaComment[];
|
||||
}>, print: JavaPrintFn): builders.Doc[];
|
||||
recordComponentModifier: typeof printSingle;
|
||||
recordBody(path: AstPath<import("java-parser").RecordBodyCstNode & {
|
||||
comments?: import("../comments.js").JavaComment[];
|
||||
}>, print: JavaPrintFn): builders.Group | "{}" | (string | builders.Indent | builders.Hardline)[];
|
||||
recordBodyDeclaration: typeof printSingle;
|
||||
compactConstructorDeclaration(path: AstPath<import("java-parser").CompactConstructorDeclarationCstNode & {
|
||||
comments?: import("../comments.js").JavaComment[];
|
||||
}>, print: JavaPrintFn): builders.Doc[];
|
||||
};
|
||||
export default _default;
|
||||
446
frontend/src/common/prettier/plugins/java/printers/classes.js
Normal file
446
frontend/src/common/prettier/plugins/java/printers/classes.js
Normal file
@@ -0,0 +1,446 @@
|
||||
import { builders } from "prettier/doc";
|
||||
import { call, each, hasDeclarationAnnotations, hasLeadingComments, indentInParentheses, isBinaryExpression, lineEndWithComments, lineStartWithComments, map, onlyDefinedKey, printBlock, printClassPermits, printClassType, printDanglingComments, printList, printSingle, printWithModifiers } from "./helpers.js";
|
||||
const { group, hardline, indent, indentIfBreak, join, line, softline } = builders;
|
||||
export default {
|
||||
classDeclaration(path, print) {
|
||||
const declarationKey = onlyDefinedKey(path.node.children, [
|
||||
"enumDeclaration",
|
||||
"normalClassDeclaration",
|
||||
"recordDeclaration"
|
||||
]);
|
||||
const declaration = call(path, print, declarationKey);
|
||||
return printWithModifiers(path, print, "classModifier", declaration, true);
|
||||
},
|
||||
normalClassDeclaration(path, print) {
|
||||
const { classExtends, classImplements, classPermits, typeParameters } = path.node.children;
|
||||
const header = ["class ", call(path, print, "typeIdentifier")];
|
||||
if (typeParameters) {
|
||||
header.push(call(path, print, "typeParameters"));
|
||||
}
|
||||
if (classExtends) {
|
||||
header.push(indent([line, call(path, print, "classExtends")]));
|
||||
}
|
||||
if (classImplements) {
|
||||
header.push(indent([line, call(path, print, "classImplements")]));
|
||||
}
|
||||
if (classPermits) {
|
||||
header.push(indent([line, call(path, print, "classPermits")]));
|
||||
}
|
||||
return [group(header), " ", call(path, print, "classBody")];
|
||||
},
|
||||
classModifier: printSingle,
|
||||
typeParameters(path, print) {
|
||||
return group([
|
||||
"<",
|
||||
indent([softline, call(path, print, "typeParameterList")]),
|
||||
softline,
|
||||
">"
|
||||
]);
|
||||
},
|
||||
typeParameterList(path, print) {
|
||||
return printList(path, print, "typeParameter");
|
||||
},
|
||||
classExtends(path, print) {
|
||||
return ["extends ", call(path, print, "classType")];
|
||||
},
|
||||
classImplements(path, print) {
|
||||
return group([
|
||||
"implements",
|
||||
indent([line, call(path, print, "interfaceTypeList")])
|
||||
]);
|
||||
},
|
||||
classPermits: printClassPermits,
|
||||
interfaceTypeList(path, print) {
|
||||
return group(printList(path, print, "interfaceType"));
|
||||
},
|
||||
classBody(path, print) {
|
||||
return printBlock(path, printClassBodyDeclarations(path, print));
|
||||
},
|
||||
classBodyDeclaration: printSingle,
|
||||
classMemberDeclaration(path, print) {
|
||||
const { children } = path.node;
|
||||
return children.Semicolon
|
||||
? ""
|
||||
: call(path, print, onlyDefinedKey(children));
|
||||
},
|
||||
fieldDeclaration(path, print) {
|
||||
const declaration = [
|
||||
call(path, print, "unannType"),
|
||||
" ",
|
||||
call(path, print, "variableDeclaratorList"),
|
||||
";"
|
||||
];
|
||||
return printWithModifiers(path, print, "fieldModifier", declaration);
|
||||
},
|
||||
fieldModifier: printSingle,
|
||||
variableDeclaratorList(path, print) {
|
||||
var _a;
|
||||
const declarators = map(path, print, "variableDeclarator");
|
||||
return declarators.length > 1 &&
|
||||
path.node.children.variableDeclarator.some(({ children }) => children.Equals)
|
||||
? group(indent(join([",", line], declarators)), {
|
||||
shouldBreak: ((_a = path.getNode(4)) === null || _a === void 0 ? void 0 : _a.name) !== "forInit"
|
||||
})
|
||||
: join(", ", declarators);
|
||||
},
|
||||
variableDeclarator(path, print) {
|
||||
var _a, _b;
|
||||
const { children } = path.node;
|
||||
const variableInitializer = (_a = children.variableInitializer) === null || _a === void 0 ? void 0 : _a[0];
|
||||
const declaratorId = call(path, print, "variableDeclaratorId");
|
||||
if (!variableInitializer) {
|
||||
return declaratorId;
|
||||
}
|
||||
const expression = (_b = variableInitializer.children.expression) === null || _b === void 0 ? void 0 : _b[0];
|
||||
const declarator = [declaratorId, " ", call(path, print, "Equals")];
|
||||
const initializer = call(path, print, "variableInitializer");
|
||||
if (hasLeadingComments(variableInitializer) ||
|
||||
(expression && isBinaryExpression(expression))) {
|
||||
declarator.push(group(indent([line, initializer])));
|
||||
}
|
||||
else {
|
||||
const groupId = Symbol("assignment");
|
||||
declarator.push(group(indent(line), { id: groupId }), indentIfBreak(initializer, { groupId }));
|
||||
}
|
||||
return group(declarator);
|
||||
},
|
||||
variableDeclaratorId(path, print) {
|
||||
const { dims, Underscore } = path.node.children;
|
||||
if (Underscore) {
|
||||
return "_";
|
||||
}
|
||||
const identifier = call(path, print, "Identifier");
|
||||
return dims ? [identifier, call(path, print, "dims")] : identifier;
|
||||
},
|
||||
variableInitializer: printSingle,
|
||||
unannType: printSingle,
|
||||
unannPrimitiveTypeWithOptionalDimsSuffix(path, print) {
|
||||
const type = call(path, print, "unannPrimitiveType");
|
||||
return path.node.children.dims ? [type, call(path, print, "dims")] : type;
|
||||
},
|
||||
unannPrimitiveType: printSingle,
|
||||
unannReferenceType(path, print) {
|
||||
const type = call(path, print, "unannClassOrInterfaceType");
|
||||
return path.node.children.dims ? [type, call(path, print, "dims")] : type;
|
||||
},
|
||||
unannClassOrInterfaceType: printSingle,
|
||||
unannClassType: printClassType,
|
||||
unannInterfaceType: printSingle,
|
||||
unannTypeVariable: printSingle,
|
||||
methodDeclaration(path, print) {
|
||||
const declaration = [
|
||||
call(path, print, "methodHeader"),
|
||||
path.node.children.methodBody[0].children.Semicolon ? "" : " ",
|
||||
call(path, print, "methodBody")
|
||||
];
|
||||
return printWithModifiers(path, print, "methodModifier", declaration);
|
||||
},
|
||||
methodModifier: printSingle,
|
||||
methodHeader(path, print) {
|
||||
const { typeParameters, annotation, throws } = path.node.children;
|
||||
const header = [];
|
||||
if (typeParameters) {
|
||||
header.push(call(path, print, "typeParameters"));
|
||||
}
|
||||
if (annotation) {
|
||||
header.push(join(line, map(path, print, "annotation")));
|
||||
}
|
||||
header.push(call(path, print, "result"), call(path, print, "methodDeclarator"));
|
||||
return throws
|
||||
? group([
|
||||
...join(" ", header),
|
||||
group(indent([line, call(path, print, "throws")]))
|
||||
])
|
||||
: group(join(" ", header));
|
||||
},
|
||||
result: printSingle,
|
||||
methodDeclarator(path, print) {
|
||||
const { dims, formalParameterList, receiverParameter } = path.node.children;
|
||||
const declarator = [call(path, print, "Identifier")];
|
||||
const parameters = [];
|
||||
if (receiverParameter) {
|
||||
parameters.push(call(path, print, "receiverParameter"));
|
||||
}
|
||||
if (formalParameterList) {
|
||||
parameters.push(call(path, print, "formalParameterList"));
|
||||
}
|
||||
const items = parameters.length
|
||||
? join([",", line], parameters)
|
||||
: printDanglingComments(path);
|
||||
declarator.push(items.length ? indentInParentheses(items) : "()");
|
||||
if (dims) {
|
||||
declarator.push(call(path, print, "dims"));
|
||||
}
|
||||
return declarator;
|
||||
},
|
||||
receiverParameter(path, print) {
|
||||
return join(" ", [
|
||||
...map(path, print, "annotation"),
|
||||
call(path, print, "unannType"),
|
||||
path.node.children.Identifier
|
||||
? [call(path, print, "Identifier"), ".this"]
|
||||
: "this"
|
||||
]);
|
||||
},
|
||||
formalParameterList(path, print) {
|
||||
return printList(path, print, "formalParameter");
|
||||
},
|
||||
formalParameter: printSingle,
|
||||
variableParaRegularParameter(path, print) {
|
||||
return join(" ", [
|
||||
...map(path, print, "variableModifier"),
|
||||
call(path, print, "unannType"),
|
||||
call(path, print, "variableDeclaratorId")
|
||||
]);
|
||||
},
|
||||
variableArityParameter(path, print) {
|
||||
const type = join(" ", [
|
||||
...map(path, print, "variableModifier"),
|
||||
call(path, print, "unannType"),
|
||||
...map(path, print, "annotation")
|
||||
]);
|
||||
return [type, "... ", call(path, print, "Identifier")];
|
||||
},
|
||||
variableModifier: printSingle,
|
||||
throws(path, print) {
|
||||
return ["throws ", call(path, print, "exceptionTypeList")];
|
||||
},
|
||||
exceptionTypeList(path, print) {
|
||||
return join(", ", map(path, print, "exceptionType"));
|
||||
},
|
||||
exceptionType: printSingle,
|
||||
methodBody: printSingle,
|
||||
instanceInitializer: printSingle,
|
||||
staticInitializer(path, print) {
|
||||
return ["static ", call(path, print, "block")];
|
||||
},
|
||||
constructorDeclaration(path, print) {
|
||||
const declaration = [call(path, print, "constructorDeclarator")];
|
||||
if (path.node.children.throws) {
|
||||
declaration.push(group(indent([line, call(path, print, "throws")])));
|
||||
}
|
||||
declaration.push(" ", call(path, print, "constructorBody"));
|
||||
return printWithModifiers(path, print, "constructorModifier", declaration, true);
|
||||
},
|
||||
constructorModifier: printSingle,
|
||||
constructorDeclarator(path, print) {
|
||||
const { children } = path.node;
|
||||
const parameters = [];
|
||||
if (children.receiverParameter) {
|
||||
parameters.push(call(path, print, "receiverParameter"));
|
||||
}
|
||||
if (children.formalParameterList) {
|
||||
parameters.push(call(path, print, "formalParameterList"));
|
||||
}
|
||||
const header = [call(path, print, "simpleTypeName")];
|
||||
header.push(parameters.length
|
||||
? indentInParentheses(join([",", line], parameters))
|
||||
: "()");
|
||||
return children.typeParameters
|
||||
? [call(path, print, "typeParameters"), " ", ...header]
|
||||
: header;
|
||||
},
|
||||
simpleTypeName: printSingle,
|
||||
constructorBody(path, print) {
|
||||
const { children } = path.node;
|
||||
const statements = [];
|
||||
if (children.explicitConstructorInvocation) {
|
||||
statements.push(call(path, print, "explicitConstructorInvocation"));
|
||||
}
|
||||
if (children.blockStatements) {
|
||||
statements.push(call(path, print, "blockStatements"));
|
||||
}
|
||||
return printBlock(path, statements);
|
||||
},
|
||||
explicitConstructorInvocation: printSingle,
|
||||
unqualifiedExplicitConstructorInvocation(path, print) {
|
||||
const { children } = path.node;
|
||||
const invocation = [];
|
||||
if (children.typeArguments) {
|
||||
invocation.push(call(path, print, "typeArguments"));
|
||||
}
|
||||
invocation.push(children.Super ? "super" : "this");
|
||||
if (children.argumentList) {
|
||||
invocation.push(group(["(", call(path, print, "argumentList"), ")"]));
|
||||
}
|
||||
else {
|
||||
invocation.push(indentInParentheses(printDanglingComments(path), { shouldBreak: true }));
|
||||
}
|
||||
invocation.push(";");
|
||||
return invocation;
|
||||
},
|
||||
qualifiedExplicitConstructorInvocation(path, print) {
|
||||
const { children } = path.node;
|
||||
const invocation = [call(path, print, "expressionName"), "."];
|
||||
if (children.typeArguments) {
|
||||
invocation.push(call(path, print, "typeArguments"));
|
||||
}
|
||||
invocation.push("super");
|
||||
if (children.argumentList) {
|
||||
invocation.push(group(["(", call(path, print, "argumentList"), ")"]));
|
||||
}
|
||||
else {
|
||||
invocation.push(indentInParentheses(printDanglingComments(path), { shouldBreak: true }));
|
||||
}
|
||||
invocation.push(";");
|
||||
return invocation;
|
||||
},
|
||||
enumDeclaration(path, print) {
|
||||
const header = ["enum", call(path, print, "typeIdentifier")];
|
||||
if (path.node.children.classImplements) {
|
||||
header.push(call(path, print, "classImplements"));
|
||||
}
|
||||
return join(" ", [...header, call(path, print, "enumBody")]);
|
||||
},
|
||||
enumBody(path, print, options) {
|
||||
var _a;
|
||||
const { children } = path.node;
|
||||
const contents = [];
|
||||
const hasNonEmptyDeclaration = ((_a = children.enumBodyDeclarations) !== null && _a !== void 0 ? _a : [])
|
||||
.flatMap(({ children }) => { var _a; return (_a = children.classBodyDeclaration) !== null && _a !== void 0 ? _a : []; })
|
||||
.some(({ children }) => { var _a; return !((_a = children.classMemberDeclaration) === null || _a === void 0 ? void 0 : _a[0].children.Semicolon); });
|
||||
if (children.enumConstantList) {
|
||||
contents.push(call(path, print, "enumConstantList"));
|
||||
if (!hasNonEmptyDeclaration && options.trailingComma !== "none") {
|
||||
contents.push(",");
|
||||
}
|
||||
}
|
||||
if (hasNonEmptyDeclaration) {
|
||||
contents.push(";", hardline, call(path, print, "enumBodyDeclarations"));
|
||||
}
|
||||
return printBlock(path, contents.length ? [contents] : []);
|
||||
},
|
||||
enumConstantList(path, print) {
|
||||
return join([",", hardline], map(path, constantPath => {
|
||||
const constant = print(constantPath);
|
||||
const { node, previous } = constantPath;
|
||||
return !previous ||
|
||||
lineStartWithComments(node) <= lineEndWithComments(previous) + 1
|
||||
? constant
|
||||
: [hardline, constant];
|
||||
}, "enumConstant"));
|
||||
},
|
||||
enumConstant(path, print) {
|
||||
const { argumentList, classBody } = path.node.children;
|
||||
const initializer = [call(path, print, "Identifier")];
|
||||
if (argumentList) {
|
||||
initializer.push(group(["(", call(path, print, "argumentList"), ")"]));
|
||||
}
|
||||
if (classBody) {
|
||||
initializer.push(" ", call(path, print, "classBody"));
|
||||
}
|
||||
return printWithModifiers(path, print, "enumConstantModifier", initializer);
|
||||
},
|
||||
enumConstantModifier: printSingle,
|
||||
enumBodyDeclarations(path, print) {
|
||||
return join(hardline, printClassBodyDeclarations(path, print));
|
||||
},
|
||||
recordDeclaration(path, print) {
|
||||
const { children } = path.node;
|
||||
const header = ["record ", call(path, print, "typeIdentifier")];
|
||||
if (children.typeParameters) {
|
||||
header.push(call(path, print, "typeParameters"));
|
||||
}
|
||||
header.push(call(path, print, "recordHeader"));
|
||||
if (children.classImplements) {
|
||||
header.push(" ", call(path, print, "classImplements"));
|
||||
}
|
||||
return [group(header), " ", call(path, print, "recordBody")];
|
||||
},
|
||||
recordHeader(path, print) {
|
||||
return path.node.children.recordComponentList
|
||||
? indentInParentheses(call(path, print, "recordComponentList"))
|
||||
: indentInParentheses(printDanglingComments(path), { shouldBreak: true });
|
||||
},
|
||||
recordComponentList(path, print) {
|
||||
return join([",", line], map(path, componentPath => {
|
||||
const { node, previous } = componentPath;
|
||||
const blankLine = previous &&
|
||||
lineStartWithComments(node) > lineEndWithComments(previous) + 1;
|
||||
const component = print(componentPath);
|
||||
return blankLine ? [softline, component] : component;
|
||||
}, "recordComponent"));
|
||||
},
|
||||
recordComponent(path, print) {
|
||||
const { children } = path.node;
|
||||
const component = [call(path, print, "unannType")];
|
||||
if (children.Identifier ||
|
||||
children.variableArityRecordComponent[0].children.annotation) {
|
||||
component.push(" ");
|
||||
}
|
||||
const suffixKey = onlyDefinedKey(children, [
|
||||
"Identifier",
|
||||
"variableArityRecordComponent"
|
||||
]);
|
||||
component.push(call(path, print, suffixKey));
|
||||
return group(join(line, [...map(path, print, "recordComponentModifier"), component]));
|
||||
},
|
||||
variableArityRecordComponent(path, print) {
|
||||
return [
|
||||
...join(" ", map(path, print, "annotation")),
|
||||
"... ",
|
||||
call(path, print, "Identifier")
|
||||
];
|
||||
},
|
||||
recordComponentModifier: printSingle,
|
||||
recordBody(path, print) {
|
||||
const declarations = [];
|
||||
let previousRequiresPadding = false;
|
||||
each(path, declarationPath => {
|
||||
var _a, _b, _c, _d;
|
||||
const declaration = print(declarationPath);
|
||||
if (declaration === "") {
|
||||
return;
|
||||
}
|
||||
const { node, previous } = declarationPath;
|
||||
const fieldDeclaration = (_c = (_b = (_a = node.children.classBodyDeclaration) === null || _a === void 0 ? void 0 : _a[0].children.classMemberDeclaration) === null || _b === void 0 ? void 0 : _b[0].children.fieldDeclaration) === null || _c === void 0 ? void 0 : _c[0].children;
|
||||
const currentRequiresPadding = !fieldDeclaration ||
|
||||
hasDeclarationAnnotations((_d = fieldDeclaration.fieldModifier) !== null && _d !== void 0 ? _d : []);
|
||||
const blankLine = declarations.length > 0 &&
|
||||
(previousRequiresPadding ||
|
||||
currentRequiresPadding ||
|
||||
lineStartWithComments(node) > lineEndWithComments(previous) + 1);
|
||||
declarations.push(blankLine ? [hardline, declaration] : declaration);
|
||||
previousRequiresPadding = currentRequiresPadding;
|
||||
}, "recordBodyDeclaration");
|
||||
return printBlock(path, declarations);
|
||||
},
|
||||
recordBodyDeclaration: printSingle,
|
||||
compactConstructorDeclaration(path, print) {
|
||||
const declaration = [
|
||||
call(path, print, "simpleTypeName"),
|
||||
" ",
|
||||
call(path, print, "constructorBody")
|
||||
];
|
||||
return printWithModifiers(path, print, "constructorModifier", declaration, true);
|
||||
}
|
||||
};
|
||||
function printClassBodyDeclarations(path, print) {
|
||||
var _a;
|
||||
if (!path.node.children.classBodyDeclaration) {
|
||||
return [];
|
||||
}
|
||||
const declarations = [];
|
||||
let previousRequiresPadding = path.node.name === "enumBodyDeclarations" ||
|
||||
((_a = path.grandparent) === null || _a === void 0 ? void 0 : _a.name) ===
|
||||
"normalClassDeclaration";
|
||||
each(path, declarationPath => {
|
||||
var _a, _b, _c;
|
||||
const declaration = print(declarationPath);
|
||||
if (declaration === "") {
|
||||
return;
|
||||
}
|
||||
const { node, previous } = declarationPath;
|
||||
const fieldDeclaration = (_b = (_a = node.children.classMemberDeclaration) === null || _a === void 0 ? void 0 : _a[0].children.fieldDeclaration) === null || _b === void 0 ? void 0 : _b[0].children;
|
||||
const currentRequiresPadding = fieldDeclaration
|
||||
? hasDeclarationAnnotations((_c = fieldDeclaration.fieldModifier) !== null && _c !== void 0 ? _c : [])
|
||||
: true;
|
||||
const blankLine = previousRequiresPadding ||
|
||||
(declarations.length > 0 &&
|
||||
(currentRequiresPadding ||
|
||||
lineStartWithComments(node) > lineEndWithComments(previous) + 1));
|
||||
declarations.push(blankLine ? [hardline, declaration] : declaration);
|
||||
previousRequiresPadding = currentRequiresPadding;
|
||||
}, "classBodyDeclaration");
|
||||
return declarations;
|
||||
}
|
||||
134
frontend/src/common/prettier/plugins/java/printers/expressions.d.ts
vendored
Normal file
134
frontend/src/common/prettier/plugins/java/printers/expressions.d.ts
vendored
Normal file
@@ -0,0 +1,134 @@
|
||||
import type { StringTemplateCstNode, TextBlockTemplateCstNode } from "java-parser";
|
||||
import type { AstPath } from "prettier";
|
||||
import { builders } from "prettier/doc";
|
||||
import type { JavaComment } from "../comments.js";
|
||||
import { printSingle, type JavaPrintFn } from "./helpers.js";
|
||||
declare const _default: {
|
||||
expression: typeof printSingle;
|
||||
lambdaExpression(path: AstPath<import("java-parser").LambdaExpressionCstNode & {
|
||||
comments?: JavaComment[];
|
||||
}>, print: JavaPrintFn, _: import("./helpers.js").JavaParserOptions, args?: unknown): builders.Doc[];
|
||||
lambdaParameters(path: AstPath<import("java-parser").LambdaParametersCstNode & {
|
||||
comments?: JavaComment[];
|
||||
}>, print: JavaPrintFn, options: import("./helpers.js").JavaParserOptions): builders.Doc;
|
||||
lambdaParametersWithBraces(path: AstPath<import("java-parser").LambdaParametersWithBracesCstNode & {
|
||||
comments?: JavaComment[];
|
||||
}>, print: JavaPrintFn, options: import("./helpers.js").JavaParserOptions): builders.Doc;
|
||||
lambdaParameterList: typeof printSingle;
|
||||
conciseLambdaParameterList(path: AstPath<import("java-parser").ConciseLambdaParameterListCstNode & {
|
||||
comments?: JavaComment[];
|
||||
}>, print: JavaPrintFn): builders.Doc[];
|
||||
normalLambdaParameterList(path: AstPath<import("java-parser").NormalLambdaParameterListCstNode & {
|
||||
comments?: JavaComment[];
|
||||
}>, print: JavaPrintFn): builders.Doc[];
|
||||
normalLambdaParameter: typeof printSingle;
|
||||
regularLambdaParameter(path: AstPath<import("java-parser").RegularLambdaParameterCstNode & {
|
||||
comments?: JavaComment[];
|
||||
}>, print: JavaPrintFn): builders.Doc[];
|
||||
lambdaParameterType: typeof printSingle;
|
||||
conciseLambdaParameter: typeof printSingle;
|
||||
lambdaBody: typeof printSingle;
|
||||
conditionalExpression(path: AstPath<import("java-parser").ConditionalExpressionCstNode & {
|
||||
comments?: JavaComment[];
|
||||
}>, print: JavaPrintFn): builders.Doc;
|
||||
binaryExpression(path: AstPath<import("java-parser").BinaryExpressionCstNode & {
|
||||
comments?: JavaComment[];
|
||||
}>, print: JavaPrintFn, options: import("./helpers.js").JavaParserOptions): builders.Doc;
|
||||
unaryExpression(path: AstPath<import("java-parser").UnaryExpressionCstNode & {
|
||||
comments?: JavaComment[];
|
||||
}>, print: JavaPrintFn): builders.Doc[];
|
||||
unaryExpressionNotPlusMinus(path: AstPath<import("java-parser").UnaryExpressionNotPlusMinusCstNode & {
|
||||
comments?: JavaComment[];
|
||||
}>, print: JavaPrintFn): builders.Doc[];
|
||||
primary(path: AstPath<import("java-parser").PrimaryCstNode & {
|
||||
comments?: JavaComment[];
|
||||
}>, print: JavaPrintFn): builders.Doc;
|
||||
primaryPrefix: typeof printSingle;
|
||||
primarySuffix(path: AstPath<import("java-parser").PrimarySuffixCstNode & {
|
||||
comments?: JavaComment[];
|
||||
}>, print: JavaPrintFn): builders.Doc;
|
||||
fqnOrRefType(path: AstPath<import("java-parser").FqnOrRefTypeCstNode & {
|
||||
comments?: JavaComment[];
|
||||
}>, print: JavaPrintFn, _: import("./helpers.js").JavaParserOptions, args: unknown): builders.Doc[];
|
||||
fqnOrRefTypePartFirst(path: AstPath<import("java-parser").FqnOrRefTypePartFirstCstNode & {
|
||||
comments?: JavaComment[];
|
||||
}>, print: JavaPrintFn): builders.Doc[];
|
||||
fqnOrRefTypePartRest(path: AstPath<import("java-parser").FqnOrRefTypePartRestCstNode & {
|
||||
comments?: JavaComment[];
|
||||
}>, print: JavaPrintFn): builders.Doc[];
|
||||
fqnOrRefTypePartCommon(path: AstPath<import("java-parser").FqnOrRefTypePartCommonCstNode & {
|
||||
comments?: JavaComment[];
|
||||
}>, print: JavaPrintFn): builders.Doc;
|
||||
parenthesisExpression(path: AstPath<import("java-parser").ParenthesisExpressionCstNode & {
|
||||
comments?: JavaComment[];
|
||||
}>, print: JavaPrintFn): builders.Group | "()" | (string | builders.Indent)[];
|
||||
castExpression: typeof printSingle;
|
||||
primitiveCastExpression(path: AstPath<import("java-parser").PrimitiveCastExpressionCstNode & {
|
||||
comments?: JavaComment[];
|
||||
}>, print: JavaPrintFn): builders.Doc[];
|
||||
referenceTypeCastExpression(path: AstPath<import("java-parser").ReferenceTypeCastExpressionCstNode & {
|
||||
comments?: JavaComment[];
|
||||
}>, print: JavaPrintFn): builders.Doc[];
|
||||
newExpression: typeof printSingle;
|
||||
unqualifiedClassInstanceCreationExpression(path: AstPath<import("java-parser").UnqualifiedClassInstanceCreationExpressionCstNode & {
|
||||
comments?: JavaComment[];
|
||||
}>, print: JavaPrintFn): builders.Doc[];
|
||||
classOrInterfaceTypeToInstantiate(path: AstPath<import("java-parser").ClassOrInterfaceTypeToInstantiateCstNode & {
|
||||
comments?: JavaComment[];
|
||||
}>, print: JavaPrintFn): builders.Doc[];
|
||||
typeArgumentsOrDiamond: typeof printSingle;
|
||||
diamond(): string;
|
||||
methodInvocationSuffix(path: AstPath<import("java-parser").MethodInvocationSuffixCstNode & {
|
||||
comments?: JavaComment[];
|
||||
}>, print: JavaPrintFn): builders.Group | "()";
|
||||
argumentList(path: AstPath<import("java-parser").ArgumentListCstNode & {
|
||||
comments?: JavaComment[];
|
||||
}>, print: JavaPrintFn): builders.Group | (builders.Indent | builders.Softline)[] | (builders.BreakParent | builders.Group)[];
|
||||
arrayCreationExpression(path: AstPath<import("java-parser").ArrayCreationExpressionCstNode & {
|
||||
comments?: JavaComment[];
|
||||
}>, print: JavaPrintFn): builders.Doc[];
|
||||
arrayCreationExpressionWithoutInitializerSuffix(path: AstPath<import("java-parser").ArrayCreationExpressionWithoutInitializerSuffixCstNode & {
|
||||
comments?: JavaComment[];
|
||||
}>, print: JavaPrintFn): builders.Doc;
|
||||
arrayCreationWithInitializerSuffix(path: AstPath<import("java-parser").ArrayCreationWithInitializerSuffixCstNode & {
|
||||
comments?: JavaComment[];
|
||||
}>, print: JavaPrintFn): builders.Doc[];
|
||||
dimExprs(path: AstPath<import("java-parser").DimExprsCstNode & {
|
||||
comments?: JavaComment[];
|
||||
}>, print: JavaPrintFn): builders.Doc[];
|
||||
dimExpr(path: AstPath<import("java-parser").DimExprCstNode & {
|
||||
comments?: JavaComment[];
|
||||
}>, print: JavaPrintFn): builders.Doc[];
|
||||
classLiteralSuffix(path: AstPath<import("java-parser").ClassLiteralSuffixCstNode & {
|
||||
comments?: JavaComment[];
|
||||
}>, print: JavaPrintFn): builders.Doc[];
|
||||
arrayAccessSuffix(path: AstPath<import("java-parser").ArrayAccessSuffixCstNode & {
|
||||
comments?: JavaComment[];
|
||||
}>, print: JavaPrintFn): builders.Doc[];
|
||||
methodReferenceSuffix(path: AstPath<import("java-parser").MethodReferenceSuffixCstNode & {
|
||||
comments?: JavaComment[];
|
||||
}>, print: JavaPrintFn): builders.Doc[];
|
||||
templateArgument: typeof printSingle;
|
||||
template: typeof printSingle;
|
||||
stringTemplate(path: AstPath<StringTemplateCstNode & {
|
||||
comments?: JavaComment[];
|
||||
}>, print: JavaPrintFn): builders.Indent;
|
||||
textBlockTemplate(path: AstPath<TextBlockTemplateCstNode & {
|
||||
comments?: JavaComment[];
|
||||
}>, print: JavaPrintFn): builders.Indent;
|
||||
embeddedExpression: typeof printSingle;
|
||||
pattern: typeof printSingle;
|
||||
typePattern: typeof printSingle;
|
||||
recordPattern(path: AstPath<import("java-parser").RecordPatternCstNode & {
|
||||
comments?: JavaComment[];
|
||||
}>, print: JavaPrintFn): builders.Doc[];
|
||||
componentPatternList(path: AstPath<import("java-parser").ComponentPatternListCstNode & {
|
||||
comments?: JavaComment[];
|
||||
}>, print: JavaPrintFn): builders.Doc[];
|
||||
componentPattern: typeof printSingle;
|
||||
matchAllPattern: typeof printSingle;
|
||||
guard(path: AstPath<import("java-parser").GuardCstNode & {
|
||||
comments?: JavaComment[];
|
||||
}>, print: JavaPrintFn): builders.Doc[];
|
||||
};
|
||||
export default _default;
|
||||
@@ -0,0 +1,598 @@
|
||||
import { builders, utils } from "prettier/doc";
|
||||
import { call, definedKeys, each, findBaseIndent, flatMap, hasLeadingComments, indentInParentheses, isBinaryExpression, isNonTerminal, isTerminal, map, onlyDefinedKey, printDanglingComments, printList, printName, printSingle } from "./helpers.js";
|
||||
const { breakParent, conditionalGroup, group, hardline, ifBreak, indent, indentIfBreak, join, line, lineSuffixBoundary, softline } = builders;
|
||||
const { removeLines, willBreak } = utils;
|
||||
export default {
|
||||
expression: printSingle,
|
||||
lambdaExpression(path, print, _, args = {}) {
|
||||
var _a;
|
||||
const hug = (_a = args.hug) !== null && _a !== void 0 ? _a : false;
|
||||
const parameters = call(path, print, "lambdaParameters");
|
||||
const expression = [hug ? removeLines(parameters) : parameters, " ->"];
|
||||
const lambdaExpression = path.node.children.lambdaBody[0].children.expression;
|
||||
const body = call(path, print, "lambdaBody");
|
||||
if (lambdaExpression) {
|
||||
const suffix = indent([line, body]);
|
||||
expression.push(group(hug ? [suffix, softline] : suffix));
|
||||
}
|
||||
else {
|
||||
expression.push(" ", body);
|
||||
}
|
||||
return expression;
|
||||
},
|
||||
lambdaParameters(path, print, options) {
|
||||
const parameters = printSingle(path, print);
|
||||
return !path.node.children.lambdaParametersWithBraces &&
|
||||
options.arrowParens === "always"
|
||||
? ["(", parameters, ")"]
|
||||
: parameters;
|
||||
},
|
||||
lambdaParametersWithBraces(path, print, options) {
|
||||
var _a;
|
||||
const { lambdaParameterList } = path.node.children;
|
||||
if (!lambdaParameterList) {
|
||||
return "()";
|
||||
}
|
||||
const { conciseLambdaParameterList, normalLambdaParameterList } = lambdaParameterList[0].children;
|
||||
const parameterCount = ((_a = conciseLambdaParameterList === null || conciseLambdaParameterList === void 0 ? void 0 : conciseLambdaParameterList[0].children.conciseLambdaParameter) !== null && _a !== void 0 ? _a : normalLambdaParameterList === null || normalLambdaParameterList === void 0 ? void 0 : normalLambdaParameterList[0].children.normalLambdaParameter).length;
|
||||
const parameters = call(path, print, "lambdaParameterList");
|
||||
if (parameterCount > 1) {
|
||||
return indentInParentheses(parameters);
|
||||
}
|
||||
return conciseLambdaParameterList && options.arrowParens === "avoid"
|
||||
? parameters
|
||||
: ["(", parameters, ")"];
|
||||
},
|
||||
lambdaParameterList: printSingle,
|
||||
conciseLambdaParameterList(path, print) {
|
||||
return printList(path, print, "conciseLambdaParameter");
|
||||
},
|
||||
normalLambdaParameterList(path, print) {
|
||||
return printList(path, print, "normalLambdaParameter");
|
||||
},
|
||||
normalLambdaParameter: printSingle,
|
||||
regularLambdaParameter(path, print) {
|
||||
return join(" ", [
|
||||
...map(path, print, "variableModifier"),
|
||||
call(path, print, "lambdaParameterType"),
|
||||
call(path, print, "variableDeclaratorId")
|
||||
]);
|
||||
},
|
||||
lambdaParameterType: printSingle,
|
||||
conciseLambdaParameter: printSingle,
|
||||
lambdaBody: printSingle,
|
||||
conditionalExpression(path, print) {
|
||||
var _a;
|
||||
const binaryExpression = call(path, print, "binaryExpression");
|
||||
if (!path.node.children.QuestionMark) {
|
||||
return binaryExpression;
|
||||
}
|
||||
const expressions = map(path, print, "expression");
|
||||
const contents = indent(join(line, [
|
||||
binaryExpression,
|
||||
["? ", expressions[0]],
|
||||
[": ", expressions[1]]
|
||||
]));
|
||||
const isNestedTernary = ((_a = path.getNode(4)) === null || _a === void 0 ? void 0 : _a.name) ===
|
||||
"conditionalExpression";
|
||||
return isNestedTernary ? contents : group(contents);
|
||||
},
|
||||
binaryExpression(path, print, options) {
|
||||
var _a, _b;
|
||||
const { children } = path.node;
|
||||
const operands = flatMap(path, print, definedKeys(children, [
|
||||
"expression",
|
||||
"pattern",
|
||||
"referenceType",
|
||||
"unaryExpression"
|
||||
]));
|
||||
const operators = flatMap(path, operatorPath => {
|
||||
const { node } = operatorPath;
|
||||
let image;
|
||||
if (isTerminal(node)) {
|
||||
image = node.image;
|
||||
}
|
||||
else if (node.children.Less) {
|
||||
image = "<<";
|
||||
}
|
||||
else {
|
||||
image = node.children.Greater.length === 2 ? ">>" : ">>>";
|
||||
}
|
||||
return { image, doc: print(operatorPath) };
|
||||
}, definedKeys(children, [
|
||||
"AssignmentOperator",
|
||||
"BinaryOperator",
|
||||
"Instanceof",
|
||||
"shiftOperator"
|
||||
]));
|
||||
const hasNonAssignmentOperators = (operators.length > 0 && !children.AssignmentOperator) ||
|
||||
(children.expression !== undefined &&
|
||||
isBinaryExpression(children.expression[0]));
|
||||
const isInList = ((_a = path.getNode(4)) === null || _a === void 0 ? void 0 : _a.name) === "elementValue" ||
|
||||
((_b = path.getNode(6)) === null || _b === void 0 ? void 0 : _b.name) === "argumentList";
|
||||
return binary(operands, operators, {
|
||||
hasNonAssignmentOperators,
|
||||
isInList,
|
||||
isRoot: true,
|
||||
operatorPosition: options.experimentalOperatorPosition
|
||||
});
|
||||
},
|
||||
unaryExpression(path, print) {
|
||||
return [
|
||||
...map(path, print, "UnaryPrefixOperator"),
|
||||
call(path, print, "primary"),
|
||||
...map(path, print, "UnarySuffixOperator")
|
||||
];
|
||||
},
|
||||
unaryExpressionNotPlusMinus(path, print) {
|
||||
const { children } = path.node;
|
||||
const expression = [];
|
||||
if (children.UnaryPrefixOperatorNotPlusMinus) {
|
||||
expression.push(...map(path, print, "UnaryPrefixOperatorNotPlusMinus"));
|
||||
}
|
||||
expression.push(call(path, print, "primary"));
|
||||
if (children.UnarySuffixOperator) {
|
||||
expression.push(...map(path, print, "UnarySuffixOperator"));
|
||||
}
|
||||
return join(" ", expression);
|
||||
},
|
||||
primary(path, print) {
|
||||
var _a, _b;
|
||||
const { children } = path.node;
|
||||
if (!children.primarySuffix) {
|
||||
return call(path, print, "primaryPrefix");
|
||||
}
|
||||
const methodInvocations = children.primarySuffix
|
||||
.filter(({ children }) => children.methodInvocationSuffix)
|
||||
.map(({ children }) => children.methodInvocationSuffix[0].children);
|
||||
const hasLambdaMethodParameter = methodInvocations.some(({ argumentList }) => argumentList === null || argumentList === void 0 ? void 0 : argumentList[0].children.expression.some(({ children }) => children.lambdaExpression));
|
||||
const prefixIsCallExpression = children.primaryPrefix[0].children.newExpression;
|
||||
const callExpressionCount = methodInvocations.length +
|
||||
(prefixIsCallExpression ? 1 : 0) +
|
||||
children.primarySuffix.filter(({ children }) => children.unqualifiedClassInstanceCreationExpression).length;
|
||||
const fqnOrRefType = (_a = children.primaryPrefix[0].children.fqnOrRefType) === null || _a === void 0 ? void 0 : _a[0].children;
|
||||
const prefixIsMethodInvocation = (fqnOrRefType === null || fqnOrRefType === void 0 ? void 0 : fqnOrRefType.fqnOrRefTypePartRest) !== undefined &&
|
||||
((_b = children.primarySuffix) === null || _b === void 0 ? void 0 : _b[0].children.methodInvocationSuffix) !== undefined;
|
||||
const prefixIsStaticMethodInvocation = prefixIsMethodInvocation && isCapitalizedIdentifier(fqnOrRefType);
|
||||
const prefixIsInstanceMethodInvocation = prefixIsMethodInvocation && !prefixIsStaticMethodInvocation;
|
||||
const mustBreakForCallExpressions = methodInvocations.length > 2 && hasLambdaMethodParameter;
|
||||
const separator = mustBreakForCallExpressions ? hardline : softline;
|
||||
const prefix = [
|
||||
call(path, prefixPath => print(prefixPath, {
|
||||
lastSeparator: prefixIsStaticMethodInvocation ||
|
||||
(prefixIsInstanceMethodInvocation && callExpressionCount === 1)
|
||||
? ""
|
||||
: separator
|
||||
}), "primaryPrefix")
|
||||
];
|
||||
const canBreakForCallExpressions = callExpressionCount > 2 ||
|
||||
(callExpressionCount === 2 && prefixIsInstanceMethodInvocation) ||
|
||||
willBreak(prefix);
|
||||
const suffixes = [];
|
||||
each(path, suffixPath => {
|
||||
const { node, previous } = suffixPath;
|
||||
const suffix = print(suffixPath);
|
||||
if (node.children.Dot) {
|
||||
if ((canBreakForCallExpressions &&
|
||||
((!previous && prefixIsCallExpression) ||
|
||||
(previous === null || previous === void 0 ? void 0 : previous.children.methodInvocationSuffix) ||
|
||||
(previous === null || previous === void 0 ? void 0 : previous.children.unqualifiedClassInstanceCreationExpression))) ||
|
||||
(!node.children.templateArgument && willBreak(suffix))) {
|
||||
suffixes.push(separator);
|
||||
}
|
||||
suffixes.push(suffix);
|
||||
}
|
||||
else if (previous) {
|
||||
suffixes.push(suffix);
|
||||
}
|
||||
else {
|
||||
prefix.push(prefixIsInstanceMethodInvocation && callExpressionCount >= 2
|
||||
? indent(suffix)
|
||||
: suffix);
|
||||
}
|
||||
}, "primarySuffix");
|
||||
const hasSuffixComments = children.primarySuffix.some(suffix => hasLeadingComments(suffix));
|
||||
return group(canBreakForCallExpressions || hasSuffixComments
|
||||
? [prefix, indent(suffixes)]
|
||||
: [prefix, ...suffixes]);
|
||||
},
|
||||
primaryPrefix: printSingle,
|
||||
primarySuffix(path, print) {
|
||||
const { children } = path.node;
|
||||
if (!children.Dot) {
|
||||
return printSingle(path, print);
|
||||
}
|
||||
const suffix = ["."];
|
||||
if (children.This) {
|
||||
suffix.push("this");
|
||||
}
|
||||
else if (children.Identifier) {
|
||||
if (children.typeArguments) {
|
||||
suffix.push(call(path, print, "typeArguments"));
|
||||
}
|
||||
suffix.push(call(path, print, "Identifier"));
|
||||
}
|
||||
else {
|
||||
const suffixKey = onlyDefinedKey(children, [
|
||||
"templateArgument",
|
||||
"unqualifiedClassInstanceCreationExpression"
|
||||
]);
|
||||
suffix.push(call(path, print, suffixKey));
|
||||
}
|
||||
return suffix;
|
||||
},
|
||||
fqnOrRefType(path, print, _, args) {
|
||||
var _a;
|
||||
const lastSeparator = (_a = args.lastSeparator) !== null && _a !== void 0 ? _a : "";
|
||||
const fqnOrRefType = [
|
||||
call(path, print, "fqnOrRefTypePartFirst"),
|
||||
...map(path, partPath => {
|
||||
const part = print(partPath);
|
||||
return partPath.isLast
|
||||
? [willBreak(part) ? hardline : lastSeparator, part]
|
||||
: part;
|
||||
}, "fqnOrRefTypePartRest")
|
||||
];
|
||||
fqnOrRefType.push(indent(fqnOrRefType.pop()));
|
||||
return path.node.children.dims
|
||||
? [fqnOrRefType, call(path, print, "dims")]
|
||||
: fqnOrRefType;
|
||||
},
|
||||
fqnOrRefTypePartFirst(path, print) {
|
||||
return join(" ", [
|
||||
...map(path, print, "annotation"),
|
||||
call(path, print, "fqnOrRefTypePartCommon")
|
||||
]);
|
||||
},
|
||||
fqnOrRefTypePartRest(path, print) {
|
||||
const common = call(path, print, "fqnOrRefTypePartCommon");
|
||||
const type = path.node.children.typeArguments
|
||||
? [call(path, print, "typeArguments"), common]
|
||||
: common;
|
||||
return [".", ...join(" ", [...map(path, print, "annotation"), type])];
|
||||
},
|
||||
fqnOrRefTypePartCommon(path, print) {
|
||||
const { children } = path.node;
|
||||
const keywordKey = onlyDefinedKey(children, ["Identifier", "Super"]);
|
||||
const keyword = call(path, print, keywordKey);
|
||||
return children.typeArguments
|
||||
? [keyword, call(path, print, "typeArguments")]
|
||||
: keyword;
|
||||
},
|
||||
parenthesisExpression(path, print) {
|
||||
var _a;
|
||||
const expression = call(path, print, "expression");
|
||||
const ancestorName = (_a = path.getNode(14)) === null || _a === void 0 ? void 0 : _a.name;
|
||||
const binaryExpression = path.getNode(8);
|
||||
return ancestorName &&
|
||||
["guard", "returnStatement"].includes(ancestorName) &&
|
||||
binaryExpression &&
|
||||
binaryExpression.name === "binaryExpression" &&
|
||||
Object.keys(binaryExpression.children).length === 1
|
||||
? indentInParentheses(expression)
|
||||
: ["(", indent(expression), ")"];
|
||||
},
|
||||
castExpression: printSingle,
|
||||
primitiveCastExpression(path, print) {
|
||||
return [
|
||||
"(",
|
||||
call(path, print, "primitiveType"),
|
||||
") ",
|
||||
call(path, print, "unaryExpression")
|
||||
];
|
||||
},
|
||||
referenceTypeCastExpression(path, print) {
|
||||
const { children } = path.node;
|
||||
const type = call(path, print, "referenceType");
|
||||
const cast = children.additionalBound
|
||||
? indentInParentheses(join(line, [type, ...map(path, print, "additionalBound")]))
|
||||
: ["(", type, ")"];
|
||||
const expressionKey = onlyDefinedKey(children, [
|
||||
"lambdaExpression",
|
||||
"unaryExpressionNotPlusMinus"
|
||||
]);
|
||||
return [cast, " ", call(path, print, expressionKey)];
|
||||
},
|
||||
newExpression: printSingle,
|
||||
unqualifiedClassInstanceCreationExpression(path, print) {
|
||||
const { children } = path.node;
|
||||
const expression = ["new "];
|
||||
if (children.typeArguments) {
|
||||
expression.push(call(path, print, "typeArguments"));
|
||||
}
|
||||
expression.push(call(path, print, "classOrInterfaceTypeToInstantiate"), children.argumentList
|
||||
? group(["(", call(path, print, "argumentList"), ")"])
|
||||
: "()");
|
||||
if (children.classBody) {
|
||||
expression.push(" ", call(path, print, "classBody"));
|
||||
}
|
||||
return expression;
|
||||
},
|
||||
classOrInterfaceTypeToInstantiate(path, print) {
|
||||
const { children } = path.node;
|
||||
const type = children.annotation
|
||||
? flatMap(path, childPath => [
|
||||
print(childPath),
|
||||
isNonTerminal(childPath.node) ? " " : "."
|
||||
], ["annotation", "Identifier"])
|
||||
: printName(path, print);
|
||||
if (children.typeArgumentsOrDiamond) {
|
||||
type.push(call(path, print, "typeArgumentsOrDiamond"));
|
||||
}
|
||||
return type;
|
||||
},
|
||||
typeArgumentsOrDiamond: printSingle,
|
||||
diamond() {
|
||||
return "<>";
|
||||
},
|
||||
methodInvocationSuffix(path, print) {
|
||||
return path.node.children.argumentList
|
||||
? group(["(", call(path, print, "argumentList"), ")"])
|
||||
: indentInParentheses(printDanglingComments(path), { shouldBreak: true });
|
||||
},
|
||||
argumentList(path, print) {
|
||||
var _a, _b, _c, _d;
|
||||
const expressions = path.node.children.expression;
|
||||
const lastExpression = expressions.at(-1);
|
||||
const lastExpressionLambdaBodyExpression = (_b = (_a = lastExpression.children.lambdaExpression) === null || _a === void 0 ? void 0 : _a[0].children.lambdaBody[0].children.expression) === null || _b === void 0 ? void 0 : _b[0].children;
|
||||
const lastExpressionLambdaBodyTernaryExpression = (_c = lastExpressionLambdaBodyExpression === null || lastExpressionLambdaBodyExpression === void 0 ? void 0 : lastExpressionLambdaBodyExpression.conditionalExpression) === null || _c === void 0 ? void 0 : _c[0].children;
|
||||
const isHuggable = !lastExpression.comments &&
|
||||
(!lastExpressionLambdaBodyExpression ||
|
||||
(lastExpressionLambdaBodyTernaryExpression === null || lastExpressionLambdaBodyTernaryExpression === void 0 ? void 0 : lastExpressionLambdaBodyTernaryExpression.QuestionMark) !== undefined ||
|
||||
((_d = lastExpressionLambdaBodyTernaryExpression === null || lastExpressionLambdaBodyTernaryExpression === void 0 ? void 0 : lastExpressionLambdaBodyTernaryExpression.binaryExpression) === null || _d === void 0 ? void 0 : _d[0].children.unaryExpression.length) === 1) &&
|
||||
expressions.findIndex(({ children }) => children.lambdaExpression) ===
|
||||
expressions.length - 1;
|
||||
const args = map(path, print, "expression");
|
||||
const allArgsExpandable = [
|
||||
indent([softline, ...join([",", line], args)]),
|
||||
softline
|
||||
];
|
||||
if (!isHuggable || willBreak(args.at(-1)[0])) {
|
||||
return allArgsExpandable;
|
||||
}
|
||||
const headArgs = args.slice(0, -1);
|
||||
const huggedLastArg = path.call(argPath => print(argPath, { hug: true }), "children", "expression", args.length - 1);
|
||||
const lastArgExpanded = join(", ", [
|
||||
...headArgs,
|
||||
group(huggedLastArg, { shouldBreak: true })
|
||||
]);
|
||||
if (willBreak(huggedLastArg)) {
|
||||
return [
|
||||
breakParent,
|
||||
conditionalGroup([lastArgExpanded, allArgsExpandable])
|
||||
];
|
||||
}
|
||||
return conditionalGroup([
|
||||
join(", ", [...headArgs, huggedLastArg]),
|
||||
lastArgExpanded,
|
||||
allArgsExpandable
|
||||
]);
|
||||
},
|
||||
arrayCreationExpression(path, print) {
|
||||
const { children } = path.node;
|
||||
const typeKey = onlyDefinedKey(children, [
|
||||
"classOrInterfaceType",
|
||||
"primitiveType"
|
||||
]);
|
||||
const suffixKey = onlyDefinedKey(children, [
|
||||
"arrayCreationExpressionWithoutInitializerSuffix",
|
||||
"arrayCreationWithInitializerSuffix"
|
||||
]);
|
||||
return ["new ", call(path, print, typeKey), call(path, print, suffixKey)];
|
||||
},
|
||||
arrayCreationExpressionWithoutInitializerSuffix(path, print) {
|
||||
const expressions = call(path, print, "dimExprs");
|
||||
return path.node.children.dims
|
||||
? [expressions, call(path, print, "dims")]
|
||||
: expressions;
|
||||
},
|
||||
arrayCreationWithInitializerSuffix(path, print) {
|
||||
return [
|
||||
call(path, print, "dims"),
|
||||
" ",
|
||||
call(path, print, "arrayInitializer")
|
||||
];
|
||||
},
|
||||
dimExprs(path, print) {
|
||||
return map(path, print, "dimExpr");
|
||||
},
|
||||
dimExpr(path, print) {
|
||||
return join(" ", [
|
||||
...map(path, print, "annotation"),
|
||||
["[", call(path, print, "expression"), "]"]
|
||||
]);
|
||||
},
|
||||
classLiteralSuffix(path, print) {
|
||||
const lSquares = map(path, print, "LSquare");
|
||||
const rSquares = map(path, print, "RSquare");
|
||||
return [
|
||||
...lSquares.flatMap((lSquare, index) => [lSquare, rSquares[index]]),
|
||||
".class"
|
||||
];
|
||||
},
|
||||
arrayAccessSuffix(path, print) {
|
||||
return ["[", call(path, print, "expression"), "]"];
|
||||
},
|
||||
methodReferenceSuffix(path, print) {
|
||||
const { children } = path.node;
|
||||
const reference = ["::"];
|
||||
if (children.typeArguments) {
|
||||
reference.push(call(path, print, "typeArguments"));
|
||||
}
|
||||
reference.push(call(path, print, onlyDefinedKey(children, ["Identifier", "New"])));
|
||||
return reference;
|
||||
},
|
||||
templateArgument: printSingle,
|
||||
template: printSingle,
|
||||
stringTemplate(path, print) {
|
||||
return printTemplate(path, print, "StringTemplateBegin", "StringTemplateMid", "StringTemplateEnd");
|
||||
},
|
||||
textBlockTemplate(path, print) {
|
||||
return printTemplate(path, print, "TextBlockTemplateBegin", "TextBlockTemplateMid", "TextBlockTemplateEnd");
|
||||
},
|
||||
embeddedExpression: printSingle,
|
||||
pattern: printSingle,
|
||||
typePattern: printSingle,
|
||||
recordPattern(path, print) {
|
||||
const patterns = path.node.children.componentPatternList
|
||||
? indentInParentheses(call(path, print, "componentPatternList"))
|
||||
: "()";
|
||||
return [call(path, print, "referenceType"), patterns];
|
||||
},
|
||||
componentPatternList(path, print) {
|
||||
return printList(path, print, "componentPattern");
|
||||
},
|
||||
componentPattern: printSingle,
|
||||
matchAllPattern: printSingle,
|
||||
guard(path, print) {
|
||||
var _a;
|
||||
const expression = call(path, print, "expression");
|
||||
const hasParentheses = ((_a = path.node.children.expression[0].children.conditionalExpression) === null || _a === void 0 ? void 0 : _a[0].children.binaryExpression[0].children.unaryExpression[0].children.primary[0].children.primaryPrefix[0].children.parenthesisExpression) !==
|
||||
undefined;
|
||||
return [
|
||||
"when ",
|
||||
hasParentheses
|
||||
? expression
|
||||
: group([
|
||||
ifBreak("("),
|
||||
indent([softline, expression]),
|
||||
softline,
|
||||
ifBreak(")")
|
||||
])
|
||||
];
|
||||
}
|
||||
};
|
||||
function binary(operands, operators, { hasNonAssignmentOperators = false, isInList = false, isRoot = false, operatorPosition }) {
|
||||
let levelOperator;
|
||||
let levelPrecedence;
|
||||
let level = [];
|
||||
while (operators.length) {
|
||||
const nextOperator = operators[0].image;
|
||||
const nextPrecedence = getOperatorPrecedence(nextOperator);
|
||||
if (levelPrecedence === undefined || nextPrecedence === levelPrecedence) {
|
||||
const { image: operator, doc: operatorDoc } = operators.shift();
|
||||
level.push(operands.shift());
|
||||
if (levelOperator !== undefined &&
|
||||
needsParentheses(levelOperator, operator)) {
|
||||
level = [["(", group(indent(level)), ")"]];
|
||||
}
|
||||
const parts = [" ", operatorDoc, line];
|
||||
if (operatorPosition === "start" && !isAssignmentOperator(operator)) {
|
||||
parts.reverse();
|
||||
}
|
||||
level.push(parts);
|
||||
levelOperator = operator;
|
||||
levelPrecedence = nextPrecedence;
|
||||
}
|
||||
else if (nextPrecedence < levelPrecedence) {
|
||||
if (!isRoot) {
|
||||
break;
|
||||
}
|
||||
level.push(operands.shift());
|
||||
const content = group(indent(level));
|
||||
operands.unshift(levelOperator !== undefined &&
|
||||
needsParentheses(levelOperator, nextOperator)
|
||||
? ["(", content, ")"]
|
||||
: content);
|
||||
level = [];
|
||||
levelOperator = undefined;
|
||||
levelPrecedence = undefined;
|
||||
}
|
||||
else {
|
||||
const content = binary(operands, operators, { operatorPosition });
|
||||
operands.unshift(levelOperator !== undefined &&
|
||||
needsParentheses(nextOperator, levelOperator)
|
||||
? ["(", indent(content), ")"]
|
||||
: content);
|
||||
}
|
||||
}
|
||||
level.push(operands.shift());
|
||||
if (!levelOperator ||
|
||||
(!isInList &&
|
||||
!isAssignmentOperator(levelOperator) &&
|
||||
levelOperator !== "instanceof")) {
|
||||
return group(level);
|
||||
}
|
||||
if (!isRoot || hasNonAssignmentOperators) {
|
||||
return group(indent(level));
|
||||
}
|
||||
const groupId = Symbol("assignment");
|
||||
return group([
|
||||
level[0],
|
||||
group(indent(level[1]), { id: groupId }),
|
||||
indentIfBreak(level[2], { groupId })
|
||||
]);
|
||||
}
|
||||
const precedencesByOperator = new Map([
|
||||
["||"],
|
||||
["&&"],
|
||||
["|"],
|
||||
["^"],
|
||||
["&"],
|
||||
["==", "!="],
|
||||
["<", ">", "<=", ">=", "instanceof"],
|
||||
["<<", ">>", ">>>"],
|
||||
["+", "-"],
|
||||
["*", "/", "%"]
|
||||
].flatMap((operators, index) => operators.map(operator => [operator, index])));
|
||||
function getOperatorPrecedence(operator) {
|
||||
var _a;
|
||||
return (_a = precedencesByOperator.get(operator)) !== null && _a !== void 0 ? _a : -1;
|
||||
}
|
||||
function needsParentheses(operator, parentOperator) {
|
||||
return ((operator === "&&" && parentOperator === "||") ||
|
||||
(["|", "^", "&", "<<", ">>", ">>>"].includes(parentOperator) &&
|
||||
getOperatorPrecedence(operator) >
|
||||
getOperatorPrecedence(parentOperator)) ||
|
||||
[operator, parentOperator].every(o => ["==", "!="].includes(o)) ||
|
||||
[operator, parentOperator].every(o => ["<<", ">>", ">>>"].includes(o)) ||
|
||||
(operator === "*" && parentOperator === "/") ||
|
||||
(operator === "/" && parentOperator === "*") ||
|
||||
(operator === "%" && ["+", "-", "*", "/"].includes(parentOperator)) ||
|
||||
(["*", "/"].includes(operator) && parentOperator === "%"));
|
||||
}
|
||||
const assignmentOperators = new Set([
|
||||
"=",
|
||||
"*=",
|
||||
"/=",
|
||||
"%=",
|
||||
"+=",
|
||||
"-=",
|
||||
"<<=",
|
||||
">>=",
|
||||
">>>=",
|
||||
"&=",
|
||||
"^=",
|
||||
"|="
|
||||
]);
|
||||
function isAssignmentOperator(operator) {
|
||||
return assignmentOperators.has(operator);
|
||||
}
|
||||
function isCapitalizedIdentifier(fqnOrRefType) {
|
||||
var _a, _b, _c;
|
||||
const nextToLastIdentifier = (_c = (_b = [
|
||||
fqnOrRefType.fqnOrRefTypePartFirst[0],
|
||||
...((_a = fqnOrRefType.fqnOrRefTypePartRest) !== null && _a !== void 0 ? _a : [])
|
||||
].at(-2)) === null || _b === void 0 ? void 0 : _b.children.fqnOrRefTypePartCommon[0].children.Identifier) === null || _c === void 0 ? void 0 : _c[0].image;
|
||||
return /^\p{Uppercase_Letter}/u.test(nextToLastIdentifier !== null && nextToLastIdentifier !== void 0 ? nextToLastIdentifier : "");
|
||||
}
|
||||
function printTemplate(path, print, beginKey, midKey, endKey) {
|
||||
const begin = call(path, ({ node }) => node.image, beginKey);
|
||||
const mids = map(path, ({ node }) => node.image, midKey);
|
||||
const end = call(path, ({ node }) => node.image, endKey);
|
||||
const lines = [begin, ...mids, end].join("").split("\n").slice(1);
|
||||
const baseIndent = findBaseIndent(lines);
|
||||
const prefix = "\n" + " ".repeat(baseIndent);
|
||||
const parts = [begin, ...mids, end].map(image => join(hardline, image.split(prefix)));
|
||||
return indent([
|
||||
parts[0],
|
||||
...map(path, (expressionPath, index) => {
|
||||
const expression = group([
|
||||
indent([softline, print(expressionPath), lineSuffixBoundary]),
|
||||
softline
|
||||
]);
|
||||
return index === 0 ? expression : [parts[index], expression];
|
||||
}, "embeddedExpression"),
|
||||
parts.at(-1)
|
||||
]);
|
||||
}
|
||||
71
frontend/src/common/prettier/plugins/java/printers/helpers.d.ts
vendored
Normal file
71
frontend/src/common/prettier/plugins/java/printers/helpers.d.ts
vendored
Normal file
@@ -0,0 +1,71 @@
|
||||
import type { AnnotationCstNode, ClassPermitsCstNode, ClassTypeCtx, CstElement, CstNode, ExpressionCstNode, InterfacePermitsCstNode, IToken, StatementCstNode } from "java-parser";
|
||||
import type { AstPath, Doc, ParserOptions } from "prettier";
|
||||
import { builders } from "prettier/doc";
|
||||
import type { JavaComment } from "../comments.js";
|
||||
export declare function onlyDefinedKey<T extends Record<string, any>, K extends Key<T> & string>(obj: T, options?: K[]): K;
|
||||
export declare function definedKeys<T extends Record<string, any>, K extends Key<T> & string>(obj: T, options?: K[]): K[];
|
||||
export declare function printWithModifiers<T extends CstNode, P extends IterProperties<T["children"]>>(path: AstPath<T>, print: JavaPrintFn, modifierChild: P, contents: Doc, noTypeAnnotations?: boolean): builders.Doc[];
|
||||
export declare function hasDeclarationAnnotations(modifiers: ModifierNode[]): boolean;
|
||||
export declare function call<T extends CstNode, U, P extends IterProperties<T["children"]>>(path: AstPath<T>, callback: MapCallback<IndexValue<IndexValue<T, "children">, P>, U>, child: P): U;
|
||||
export declare function each<T extends CstNode, P extends IterProperties<T["children"]>>(path: AstPath<T>, callback: MapCallback<IndexValue<IndexValue<T, "children">, P>, void>, child: P): void;
|
||||
export declare function map<T extends CstNode, U, P extends IterProperties<T["children"]>>(path: AstPath<T>, callback: MapCallback<IndexValue<IndexValue<T, "children">, P>, U>, child: P): U[];
|
||||
export declare function flatMap<T extends CstNode, U, P extends IterProperties<T["children"]>>(path: AstPath<T>, callback: MapCallback<IndexValue<IndexValue<T, "children">, P>, U>, children: P[]): U[];
|
||||
export declare function printSingle(path: AstPath<JavaNonTerminal>, print: JavaPrintFn, _?: JavaParserOptions, args?: unknown): builders.Doc;
|
||||
export declare function lineStartWithComments(node: JavaNonTerminal): number;
|
||||
export declare function lineEndWithComments(node: JavaNonTerminal): number;
|
||||
export declare function printDanglingComments(path: AstPath<JavaNonTerminal>): builders.Doc[];
|
||||
export declare function printComment(node: JavaTerminal): string | builders.Doc[];
|
||||
export declare function hasLeadingComments(node: JavaNode): boolean | undefined;
|
||||
export declare function indentInParentheses(contents: Doc, opts?: {
|
||||
shouldBreak?: boolean;
|
||||
}): builders.Group | "()";
|
||||
export declare function printArrayInitializer<T extends JavaNonTerminal, P extends IterProperties<T["children"]>>(path: AstPath<T>, print: JavaPrintFn, options: JavaParserOptions, child: P): builders.Group | "{}";
|
||||
export declare function printBlock(path: AstPath<JavaNonTerminal>, contents: Doc[]): builders.Group | "{}" | (string | builders.Indent | builders.Hardline)[];
|
||||
export declare function printName(path: AstPath<JavaNonTerminal & {
|
||||
children: {
|
||||
Identifier: IToken[];
|
||||
};
|
||||
}>, print: JavaPrintFn): builders.Doc[];
|
||||
export declare function printList<T extends JavaNonTerminal, P extends IterProperties<T["children"]>>(path: AstPath<T>, print: JavaPrintFn, child: P): builders.Doc[];
|
||||
export declare function printClassPermits(path: AstPath<ClassPermitsCstNode | InterfacePermitsCstNode>, print: JavaPrintFn): builders.Group;
|
||||
export declare function printClassType(path: AstPath<JavaNonTerminal & {
|
||||
children: ClassTypeCtx;
|
||||
}>, print: JavaPrintFn): builders.Doc[];
|
||||
export declare function isBinaryExpression(expression: ExpressionCstNode): boolean;
|
||||
export declare function findBaseIndent(lines: string[]): number;
|
||||
export declare function isEmptyStatement(statement: StatementCstNode): boolean;
|
||||
export declare function isNonTerminal(node: CstElement): node is JavaNonTerminal;
|
||||
export declare function isTerminal(node: CstElement): node is IToken;
|
||||
export type JavaNode = CstElement & {
|
||||
comments?: JavaComment[];
|
||||
};
|
||||
export type JavaNonTerminal = Exclude<JavaNode, IToken>;
|
||||
export type JavaTerminal = Exclude<JavaNode, CstNode>;
|
||||
export type JavaNodePrinters = {
|
||||
[T in JavaNonTerminal["name"]]: JavaNodePrinter<T>;
|
||||
};
|
||||
export type JavaNodePrinter<T> = (path: AstPath<Extract<JavaNonTerminal, {
|
||||
name: T;
|
||||
}>>, print: JavaPrintFn, options: JavaParserOptions, args?: unknown) => Doc;
|
||||
export type JavaPrintFn = (path: AstPath<JavaNode>, args?: unknown) => Doc;
|
||||
export type JavaParserOptions = ParserOptions<JavaNode> & {
|
||||
entrypoint?: string;
|
||||
};
|
||||
export type IterProperties<T> = T extends any[] ? IndexProperties<T> : ArrayProperties<T>;
|
||||
type Key<T> = T extends T ? keyof T : never;
|
||||
type ModifierNode = JavaNonTerminal & {
|
||||
children: {
|
||||
annotation?: AnnotationCstNode[];
|
||||
};
|
||||
};
|
||||
type IsTuple<T> = T extends [] ? true : T extends [infer First, ...infer Remain] ? IsTuple<Remain> : false;
|
||||
type IndexProperties<T extends {
|
||||
length: number;
|
||||
}> = IsTuple<T> extends true ? Exclude<Partial<T>["length"], T["length"]> : number;
|
||||
type ArrayProperties<T> = {
|
||||
[K in keyof T]: NonNullable<T[K]> extends readonly any[] ? K : never;
|
||||
}[keyof T];
|
||||
type ArrayElement<T> = T extends Array<infer E> ? E : never;
|
||||
type MapCallback<T, U> = (path: AstPath<ArrayElement<T>>, index: number, value: any) => U;
|
||||
type IndexValue<T, P> = T extends any[] ? P extends number ? T[P] : never : P extends keyof T ? T[P] : never;
|
||||
export {};
|
||||
239
frontend/src/common/prettier/plugins/java/printers/helpers.js
Normal file
239
frontend/src/common/prettier/plugins/java/printers/helpers.js
Normal file
@@ -0,0 +1,239 @@
|
||||
import { builders } from "prettier/doc";
|
||||
import parser from "../parser.js";
|
||||
const { group, hardline, ifBreak, indent, join, line, softline } = builders;
|
||||
export function onlyDefinedKey(obj, options) {
|
||||
const keys = definedKeys(obj, options);
|
||||
if (keys.length === 1) {
|
||||
return keys[0];
|
||||
}
|
||||
throw new Error(keys.length > 1
|
||||
? `More than one defined key found: ${keys}`
|
||||
: "No defined keys found");
|
||||
}
|
||||
export function definedKeys(obj, options) {
|
||||
return (options !== null && options !== void 0 ? options : Object.keys(obj)).filter(key => obj[key] !== undefined);
|
||||
}
|
||||
const indexByModifier = [
|
||||
"public",
|
||||
"protected",
|
||||
"private",
|
||||
"abstract",
|
||||
"default",
|
||||
"static",
|
||||
"final",
|
||||
"transient",
|
||||
"volatile",
|
||||
"synchronized",
|
||||
"native",
|
||||
"sealed",
|
||||
"non-sealed",
|
||||
"strictfp"
|
||||
].reduce((map, name, index) => map.set(name, index), new Map());
|
||||
export function printWithModifiers(path, print, modifierChild, contents, noTypeAnnotations = false) {
|
||||
const declarationAnnotations = [];
|
||||
const otherModifiers = [];
|
||||
const typeAnnotations = [];
|
||||
each(path, modifierPath => {
|
||||
const { children } = modifierPath.node;
|
||||
const modifier = print(modifierPath);
|
||||
if (children.annotation) {
|
||||
(otherModifiers.length ? typeAnnotations : declarationAnnotations).push(modifier);
|
||||
}
|
||||
else {
|
||||
otherModifiers.push(modifier);
|
||||
declarationAnnotations.push(...typeAnnotations);
|
||||
typeAnnotations.length = 0;
|
||||
}
|
||||
}, modifierChild);
|
||||
if (noTypeAnnotations) {
|
||||
declarationAnnotations.push(...typeAnnotations);
|
||||
typeAnnotations.length = 0;
|
||||
}
|
||||
otherModifiers.sort((a, b) => indexByModifier.get(a) - indexByModifier.get(b));
|
||||
return join(hardline, [
|
||||
...declarationAnnotations,
|
||||
join(" ", [...otherModifiers, ...typeAnnotations, contents])
|
||||
]);
|
||||
}
|
||||
export function hasDeclarationAnnotations(modifiers) {
|
||||
let hasAnnotation = false;
|
||||
let hasNonAnnotation = false;
|
||||
for (const modifier of modifiers) {
|
||||
if (modifier.children.annotation) {
|
||||
hasAnnotation = true;
|
||||
}
|
||||
else if (hasAnnotation) {
|
||||
return true;
|
||||
}
|
||||
else {
|
||||
hasNonAnnotation = true;
|
||||
}
|
||||
}
|
||||
return hasAnnotation && !hasNonAnnotation;
|
||||
}
|
||||
export function call(path, callback, child) {
|
||||
return path.map(callback, "children", child)[0];
|
||||
}
|
||||
export function each(path, callback, child) {
|
||||
if (path.node.children[child]) {
|
||||
path.each(callback, "children", child);
|
||||
}
|
||||
}
|
||||
export function map(path, callback, child) {
|
||||
return path.node.children[child] ? path.map(callback, "children", child) : [];
|
||||
}
|
||||
export function flatMap(path, callback, children) {
|
||||
return children
|
||||
.flatMap(child => map(path, callback, child).map((doc, index) => {
|
||||
const node = path.node.children[child][index];
|
||||
return {
|
||||
doc,
|
||||
startOffset: parser.locStart(node)
|
||||
};
|
||||
}))
|
||||
.sort((a, b) => a.startOffset - b.startOffset)
|
||||
.map(({ doc }) => doc);
|
||||
}
|
||||
export function printSingle(path, print, _, args) {
|
||||
return call(path, childPath => print(childPath, args), onlyDefinedKey(path.node.children));
|
||||
}
|
||||
export function lineStartWithComments(node) {
|
||||
const { comments, location } = node;
|
||||
return comments
|
||||
? Math.min(location.startLine, comments[0].startLine)
|
||||
: location.startLine;
|
||||
}
|
||||
export function lineEndWithComments(node) {
|
||||
const { comments, location } = node;
|
||||
return comments
|
||||
? Math.max(location.endLine, comments.at(-1).endLine)
|
||||
: location.endLine;
|
||||
}
|
||||
export function printDanglingComments(path) {
|
||||
if (!path.node.comments) {
|
||||
return [];
|
||||
}
|
||||
const comments = [];
|
||||
path.each(commentPath => {
|
||||
const comment = commentPath.node;
|
||||
if (comment.leading || comment.trailing) {
|
||||
return;
|
||||
}
|
||||
comment.printed = true;
|
||||
comments.push(printComment(comment));
|
||||
}, "comments");
|
||||
return join(hardline, comments);
|
||||
}
|
||||
export function printComment(node) {
|
||||
const { image } = node;
|
||||
const lines = image.split("\n").map(line => line.trim());
|
||||
return lines.length > 1 &&
|
||||
lines[0].startsWith("/*") &&
|
||||
lines.slice(1).every(line => line.startsWith("*")) &&
|
||||
lines.at(-1).endsWith("*/")
|
||||
? join(hardline, lines.map((line, index) => (index === 0 ? line : ` ${line}`)))
|
||||
: image;
|
||||
}
|
||||
export function hasLeadingComments(node) {
|
||||
var _a;
|
||||
return (_a = node.comments) === null || _a === void 0 ? void 0 : _a.some(({ leading }) => leading);
|
||||
}
|
||||
export function indentInParentheses(contents, opts) {
|
||||
return !Array.isArray(contents) || contents.length
|
||||
? group(["(", indent([softline, contents]), softline, ")"], opts)
|
||||
: "()";
|
||||
}
|
||||
export function printArrayInitializer(path, print, options, child) {
|
||||
const list = [];
|
||||
if (child && child in path.node.children) {
|
||||
list.push(call(path, print, child));
|
||||
if (options.trailingComma !== "none") {
|
||||
list.push(ifBreak(","));
|
||||
}
|
||||
}
|
||||
list.push(...printDanglingComments(path));
|
||||
return list.length ? group(["{", indent([line, ...list]), line, "}"]) : "{}";
|
||||
}
|
||||
export function printBlock(path, contents) {
|
||||
if (!contents.length) {
|
||||
const danglingComments = printDanglingComments(path);
|
||||
return danglingComments.length
|
||||
? ["{", indent([hardline, ...danglingComments]), hardline, "}"]
|
||||
: "{}";
|
||||
}
|
||||
return group([
|
||||
"{",
|
||||
indent([hardline, ...join(hardline, contents)]),
|
||||
hardline,
|
||||
"}"
|
||||
]);
|
||||
}
|
||||
export function printName(path, print) {
|
||||
return join(".", map(path, print, "Identifier"));
|
||||
}
|
||||
export function printList(path, print, child) {
|
||||
return join([",", line], map(path, print, child));
|
||||
}
|
||||
export function printClassPermits(path, print) {
|
||||
return group([
|
||||
"permits",
|
||||
indent([line, group(printList(path, print, "typeName"))])
|
||||
]);
|
||||
}
|
||||
export function printClassType(path, print) {
|
||||
const { children } = path.node;
|
||||
return definedKeys(children, ["annotation", "Identifier", "typeArguments"])
|
||||
.flatMap(child => children[child].map((node, index) => ({
|
||||
child,
|
||||
index,
|
||||
startOffset: parser.locStart(node)
|
||||
})))
|
||||
.sort((a, b) => a.startOffset - b.startOffset)
|
||||
.flatMap(({ child, index: childIndex }, index, array) => {
|
||||
const node = children[child][childIndex];
|
||||
const next = array.at(index + 1);
|
||||
const nextNode = next && children[next.child][next.index];
|
||||
const docs = [path.call(print, "children", child, childIndex)];
|
||||
if (nextNode) {
|
||||
if (isNonTerminal(node)) {
|
||||
docs.push(node.name === "annotation" ? " " : ".");
|
||||
}
|
||||
else if (isTerminal(nextNode) || nextNode.name === "annotation") {
|
||||
docs.push(".");
|
||||
}
|
||||
}
|
||||
return docs;
|
||||
});
|
||||
}
|
||||
export function isBinaryExpression(expression) {
|
||||
var _a;
|
||||
const conditionalExpression = (_a = expression.children.conditionalExpression) === null || _a === void 0 ? void 0 : _a[0].children;
|
||||
if (!conditionalExpression) {
|
||||
return false;
|
||||
}
|
||||
const isTernary = conditionalExpression.QuestionMark !== undefined;
|
||||
if (isTernary) {
|
||||
return false;
|
||||
}
|
||||
const hasNonAssignmentOperators = Object.values(conditionalExpression.binaryExpression[0].children).some(child => {
|
||||
var _a;
|
||||
return isTerminal(child[0]) &&
|
||||
!((_a = child[0].tokenType.CATEGORIES) === null || _a === void 0 ? void 0 : _a.some(category => category.name === "AssignmentOperator"));
|
||||
});
|
||||
return hasNonAssignmentOperators;
|
||||
}
|
||||
export function findBaseIndent(lines) {
|
||||
return lines.length
|
||||
? Math.min(...lines.map(line => line.search(/\S/)).filter(indent => indent >= 0))
|
||||
: 0;
|
||||
}
|
||||
export function isEmptyStatement(statement) {
|
||||
var _a;
|
||||
return (((_a = statement.children.statementWithoutTrailingSubstatement) === null || _a === void 0 ? void 0 : _a[0].children.emptyStatement) !== undefined);
|
||||
}
|
||||
export function isNonTerminal(node) {
|
||||
return !isTerminal(node);
|
||||
}
|
||||
export function isTerminal(node) {
|
||||
return "tokenType" in node;
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user