Compare commits
25 Commits
v1.3.0
...
338ac358db
| Author | SHA1 | Date | |
|---|---|---|---|
| 338ac358db | |||
| a83c7139c9 | |||
| 42c7d11c09 | |||
| 5ca5aa64c7 | |||
| eda7ef771e | |||
| 593c4d7783 | |||
| d24a522b32 | |||
| 41afb834ae | |||
| b745329e26 | |||
| 1fb4f64cb3 | |||
| 1f8e8981ce | |||
| a257d30dba | |||
| 97ee3b0667 | |||
| 8e2bafba5f | |||
| 6149bc133d | |||
| 5f22ee3b1f | |||
| fa72ff8061 | |||
| 65f24860e6 | |||
|
|
4881233211 | ||
| bc01fdf362 | |||
| 709998ff9c | |||
| 6adeadeed4 | |||
| 7b70a39b23 | |||
| 873a3c0e60 | |||
| 5b88efcfbe |
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**
|
[中文](README_ZH.md) | **English**
|
||||||
|
|
||||||
> *An elegant text snippet recording tool designed for developers.*
|
> *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
|
## Core Features
|
||||||
|
|
||||||
@@ -87,7 +87,7 @@ After building, the executable will be generated in the `bin` directory.
|
|||||||
## Project Structure
|
## Project Structure
|
||||||
|
|
||||||
```
|
```
|
||||||
Voidraft/
|
voidraft/
|
||||||
├── frontend/ # Vue 3 frontend application
|
├── frontend/ # Vue 3 frontend application
|
||||||
│ ├── src/
|
│ ├── src/
|
||||||
│ │ ├── views/editor/ # Editor core views
|
│ │ ├── views/editor/ # Editor core views
|
||||||
@@ -129,11 +129,11 @@ Voidraft/
|
|||||||
|
|
||||||
> Standing on the shoulders of giants, paying tribute to the open source spirit
|
> 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
|
### 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
|
- Inherits Heynote's elegant block editing philosophy
|
||||||
- Adds more practical features on the original foundation
|
- Adds more practical features on the original foundation
|
||||||
- Rebuilt with modern technology stack
|
- 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.
|
Welcome to Fork, Star, and contribute code.
|
||||||
|
|
||||||
[](https://opensource.org/licenses/MIT)
|
[](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*
|
*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)
|
**中文** | [English](README.md)
|
||||||
|
|
||||||
> *一个专为开发者打造的优雅文本片段记录工具。*
|
> *一个专为开发者打造的优雅文本片段记录工具。*
|
||||||
|
|
||||||
Voidraft 是一个现代化的开发者专用文本编辑器,让你能够随时随地记录、整理和管理各种文本片段。无论是临时的代码片段、API 响应、会议笔记,还是日常的待办事项,Voidraft 都能为你提供流畅而优雅的编辑体验。
|
voidraft 是一个现代化的开发者专用文本编辑器,让你能够随时随地记录、整理和管理各种文本片段。无论是临时的代码片段、API 响应、会议笔记,还是日常的待办事项,voidraft 都能为你提供流畅而优雅的编辑体验。
|
||||||
|
|
||||||
## 核心特性
|
## 核心特性
|
||||||
|
|
||||||
@@ -88,7 +88,7 @@ wails3 package
|
|||||||
## 项目结构
|
## 项目结构
|
||||||
|
|
||||||
```
|
```
|
||||||
Voidraft/
|
voidraft/
|
||||||
├── frontend/ # Vue 3 前端应用
|
├── frontend/ # Vue 3 前端应用
|
||||||
│ ├── src/
|
│ ├── src/
|
||||||
│ │ ├── views/editor/ # 编辑器核心视图
|
│ │ ├── 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 优雅的块状编辑理念
|
- 继承了 Heynote 优雅的块状编辑理念
|
||||||
- 在原有基础上增加了更多实用功能
|
- 在原有基础上增加了更多实用功能
|
||||||
- 采用现代化技术栈重新构建
|
- 采用现代化技术栈重新构建
|
||||||
@@ -159,7 +159,7 @@ Voidraft 的诞生离不开以下优秀的开源项目:
|
|||||||
欢迎 Fork、Star 和贡献代码。
|
欢迎 Fork、Star 和贡献代码。
|
||||||
|
|
||||||
[](https://opensource.org/licenses/MIT)
|
[](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*
|
*Made with ❤️ by landaiqing*
|
||||||
|
|||||||
12
Taskfile.yml
12
Taskfile.yml
@@ -12,13 +12,25 @@ vars:
|
|||||||
VITE_PORT: '{{.WAILS_VITE_PORT | default 9245}}'
|
VITE_PORT: '{{.WAILS_VITE_PORT | default 9245}}'
|
||||||
|
|
||||||
tasks:
|
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:
|
build:
|
||||||
summary: Builds the application
|
summary: Builds the application
|
||||||
|
deps: [version]
|
||||||
cmds:
|
cmds:
|
||||||
- task: "{{OS}}:build"
|
- task: "{{OS}}:build"
|
||||||
|
|
||||||
package:
|
package:
|
||||||
summary: Packages a production build of the application
|
summary: Packages a production build of the application
|
||||||
|
deps: [version]
|
||||||
cmds:
|
cmds:
|
||||||
- task: "{{OS}}:package"
|
- task: "{{OS}}:package"
|
||||||
|
|
||||||
|
|||||||
@@ -5,12 +5,12 @@ version: '3'
|
|||||||
|
|
||||||
# This information is used to generate the build assets.
|
# This information is used to generate the build assets.
|
||||||
info:
|
info:
|
||||||
companyName: "Voidraft" # The name of the company
|
companyName: "voidraft" # The name of the company
|
||||||
productName: "Voidraft" # The name of the application
|
productName: "voidraft" # The name of the application
|
||||||
productIdentifier: "landaiqing" # The unique product identifier
|
productIdentifier: "landaiqing" # The unique product identifier
|
||||||
description: "Voidraft" # The application description
|
description: "voidraft" # The application description
|
||||||
copyright: "© 2025 Voidraft. All rights reserved." # Copyright text
|
copyright: "© 2025 voidraft. All rights reserved." # Copyright text
|
||||||
comments: "Voidraft" # Comments
|
comments: "voidraft" # Comments
|
||||||
version: "0.0.1.0" # The application version
|
version: "0.0.1.0" # The application version
|
||||||
|
|
||||||
# Dev mode configuration
|
# Dev mode configuration
|
||||||
|
|||||||
@@ -4,15 +4,15 @@
|
|||||||
<key>CFBundlePackageType</key>
|
<key>CFBundlePackageType</key>
|
||||||
<string>APPL</string>
|
<string>APPL</string>
|
||||||
<key>CFBundleName</key>
|
<key>CFBundleName</key>
|
||||||
<string>Voidraft</string>
|
<string>voidraft</string>
|
||||||
<key>CFBundleExecutable</key>
|
<key>CFBundleExecutable</key>
|
||||||
<string>Voidraft</string>
|
<string>voidraft</string>
|
||||||
<key>CFBundleIdentifier</key>
|
<key>CFBundleIdentifier</key>
|
||||||
<string>landaiqing</string>
|
<string>landaiqing</string>
|
||||||
<key>CFBundleVersion</key>
|
<key>CFBundleVersion</key>
|
||||||
<string>0.0.1.0</string>
|
<string>0.0.1.0</string>
|
||||||
<key>CFBundleGetInfoString</key>
|
<key>CFBundleGetInfoString</key>
|
||||||
<string>Voidraft</string>
|
<string>voidraft</string>
|
||||||
<key>CFBundleShortVersionString</key>
|
<key>CFBundleShortVersionString</key>
|
||||||
<string>0.0.1.0</string>
|
<string>0.0.1.0</string>
|
||||||
<key>CFBundleIconFile</key>
|
<key>CFBundleIconFile</key>
|
||||||
@@ -22,7 +22,7 @@
|
|||||||
<key>NSHighResolutionCapable</key>
|
<key>NSHighResolutionCapable</key>
|
||||||
<string>true</string>
|
<string>true</string>
|
||||||
<key>NSHumanReadableCopyright</key>
|
<key>NSHumanReadableCopyright</key>
|
||||||
<string>© 2025 Voidraft. All rights reserved.</string>
|
<string>© 2025 voidraft. All rights reserved.</string>
|
||||||
<key>NSAppTransportSecurity</key>
|
<key>NSAppTransportSecurity</key>
|
||||||
<dict>
|
<dict>
|
||||||
<key>NSAllowsLocalNetworking</key>
|
<key>NSAllowsLocalNetworking</key>
|
||||||
|
|||||||
@@ -4,15 +4,15 @@
|
|||||||
<key>CFBundlePackageType</key>
|
<key>CFBundlePackageType</key>
|
||||||
<string>APPL</string>
|
<string>APPL</string>
|
||||||
<key>CFBundleName</key>
|
<key>CFBundleName</key>
|
||||||
<string>Voidraft</string>
|
<string>voidraft</string>
|
||||||
<key>CFBundleExecutable</key>
|
<key>CFBundleExecutable</key>
|
||||||
<string>Voidraft</string>
|
<string>voidraft</string>
|
||||||
<key>CFBundleIdentifier</key>
|
<key>CFBundleIdentifier</key>
|
||||||
<string>landaiqing</string>
|
<string>landaiqing</string>
|
||||||
<key>CFBundleVersion</key>
|
<key>CFBundleVersion</key>
|
||||||
<string>0.0.1.0</string>
|
<string>0.0.1.0</string>
|
||||||
<key>CFBundleGetInfoString</key>
|
<key>CFBundleGetInfoString</key>
|
||||||
<string>Voidraft</string>
|
<string>voidraft</string>
|
||||||
<key>CFBundleShortVersionString</key>
|
<key>CFBundleShortVersionString</key>
|
||||||
<string>0.0.1.0</string>
|
<string>0.0.1.0</string>
|
||||||
<key>CFBundleIconFile</key>
|
<key>CFBundleIconFile</key>
|
||||||
@@ -22,6 +22,6 @@
|
|||||||
<key>NSHighResolutionCapable</key>
|
<key>NSHighResolutionCapable</key>
|
||||||
<string>true</string>
|
<string>true</string>
|
||||||
<key>NSHumanReadableCopyright</key>
|
<key>NSHumanReadableCopyright</key>
|
||||||
<string>© 2025 Voidraft. All rights reserved.</string>
|
<string>© 2025 voidraft. All rights reserved.</string>
|
||||||
</dict>
|
</dict>
|
||||||
</plist>
|
</plist>
|
||||||
@@ -11,9 +11,12 @@ tasks:
|
|||||||
- task: common:build:frontend
|
- task: common:build:frontend
|
||||||
- task: common:generate:icons
|
- task: common:generate:icons
|
||||||
cmds:
|
cmds:
|
||||||
- go build {{.BUILD_FLAGS}} -o {{.OUTPUT}}
|
- go build {{.BUILD_FLAGS}} -ldflags="{{.LDFLAGS}} {{.VERSION_FLAGS}}" -o {{.OUTPUT}}
|
||||||
vars:
|
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}}'
|
DEFAULT_OUTPUT: '{{.BIN_DIR}}/{{.APP_NAME}}'
|
||||||
OUTPUT: '{{ .OUTPUT | default .DEFAULT_OUTPUT }}'
|
OUTPUT: '{{ .OUTPUT | default .DEFAULT_OUTPUT }}'
|
||||||
env:
|
env:
|
||||||
|
|||||||
@@ -11,9 +11,12 @@ tasks:
|
|||||||
- task: common:build:frontend
|
- task: common:build:frontend
|
||||||
- task: common:generate:icons
|
- task: common:generate:icons
|
||||||
cmds:
|
cmds:
|
||||||
- go build {{.BUILD_FLAGS}} -o {{.BIN_DIR}}/{{.APP_NAME}}
|
- go build {{.BUILD_FLAGS}} -ldflags="{{.LDFLAGS}} {{.VERSION_FLAGS}}" -o {{.BIN_DIR}}/{{.APP_NAME}}
|
||||||
vars:
|
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:
|
env:
|
||||||
GOOS: linux
|
GOOS: linux
|
||||||
CGO_ENABLED: 1
|
CGO_ENABLED: 1
|
||||||
|
|||||||
@@ -3,26 +3,26 @@
|
|||||||
#
|
#
|
||||||
# The lines below are called `modelines`. See `:help modeline`
|
# The lines below are called `modelines`. See `:help modeline`
|
||||||
|
|
||||||
name: "Voidraft"
|
name: "voidraft"
|
||||||
arch: ${GOARCH}
|
arch: ${GOARCH}
|
||||||
platform: "linux"
|
platform: "linux"
|
||||||
version: "0.0.1.0"
|
version: "0.0.1.0"
|
||||||
section: "default"
|
section: "default"
|
||||||
priority: "extra"
|
priority: "extra"
|
||||||
maintainer: ${GIT_COMMITTER_NAME} <${GIT_COMMITTER_EMAIL}>
|
maintainer: ${GIT_COMMITTER_NAME} <${GIT_COMMITTER_EMAIL}>
|
||||||
description: "Voidraft"
|
description: "voidraft"
|
||||||
vendor: "Voidraft"
|
vendor: "voidraft"
|
||||||
homepage: "https://wails.io"
|
homepage: "https://voidraft.landaiqing.cn"
|
||||||
license: "MIT"
|
license: "MIT"
|
||||||
release: "1"
|
release: "1"
|
||||||
|
|
||||||
contents:
|
contents:
|
||||||
- src: "./bin/Voidraft"
|
- src: "./bin/voidraft"
|
||||||
dst: "/usr/local/bin/Voidraft"
|
dst: "/usr/local/bin/voidraft"
|
||||||
- src: "./build/appicon.png"
|
- src: "./build/appicon.png"
|
||||||
dst: "/usr/share/icons/hicolor/128x128/apps/Voidraft.png"
|
dst: "/usr/share/icons/hicolor/128x128/apps/voidraft.png"
|
||||||
- src: "./build/linux/Voidraft.desktop"
|
- src: "./build/linux/voidraft.desktop"
|
||||||
dst: "/usr/share/applications/Voidraft.desktop"
|
dst: "/usr/share/applications/voidraft.desktop"
|
||||||
|
|
||||||
depends:
|
depends:
|
||||||
- gtk3
|
- gtk3
|
||||||
|
|||||||
@@ -14,13 +14,16 @@ tasks:
|
|||||||
- task: common:generate:icons
|
- task: common:generate:icons
|
||||||
cmds:
|
cmds:
|
||||||
- task: generate:syso
|
- 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
|
- cmd: powershell Remove-item *.syso
|
||||||
platforms: [windows]
|
platforms: [windows]
|
||||||
- cmd: rm -f *.syso
|
- cmd: rm -f *.syso
|
||||||
platforms: [linux, darwin]
|
platforms: [linux, darwin]
|
||||||
vars:
|
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:
|
env:
|
||||||
GOOS: windows
|
GOOS: windows
|
||||||
CGO_ENABLED: 1
|
CGO_ENABLED: 1
|
||||||
|
|||||||
@@ -5,11 +5,11 @@
|
|||||||
"info": {
|
"info": {
|
||||||
"0000": {
|
"0000": {
|
||||||
"ProductVersion": "0.0.1.0",
|
"ProductVersion": "0.0.1.0",
|
||||||
"CompanyName": "Voidraft",
|
"CompanyName": "voidraft",
|
||||||
"FileDescription": "Voidraft",
|
"FileDescription": "voidraft",
|
||||||
"LegalCopyright": "© 2025 Voidraft. All rights reserved.",
|
"LegalCopyright": "© 2025 voidraft. All rights reserved.",
|
||||||
"ProductName": "Voidraft",
|
"ProductName": "voidraft",
|
||||||
"Comments": "Voidraft"
|
"Comments": "voidraft"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -5,19 +5,19 @@
|
|||||||
!include "FileFunc.nsh"
|
!include "FileFunc.nsh"
|
||||||
|
|
||||||
!ifndef INFO_PROJECTNAME
|
!ifndef INFO_PROJECTNAME
|
||||||
!define INFO_PROJECTNAME "Voidraft"
|
!define INFO_PROJECTNAME "voidraft"
|
||||||
!endif
|
!endif
|
||||||
!ifndef INFO_COMPANYNAME
|
!ifndef INFO_COMPANYNAME
|
||||||
!define INFO_COMPANYNAME "Voidraft"
|
!define INFO_COMPANYNAME "voidraft"
|
||||||
!endif
|
!endif
|
||||||
!ifndef INFO_PRODUCTNAME
|
!ifndef INFO_PRODUCTNAME
|
||||||
!define INFO_PRODUCTNAME "Voidraft"
|
!define INFO_PRODUCTNAME "voidraft"
|
||||||
!endif
|
!endif
|
||||||
!ifndef INFO_PRODUCTVERSION
|
!ifndef INFO_PRODUCTVERSION
|
||||||
!define INFO_PRODUCTVERSION "0.0.1.0"
|
!define INFO_PRODUCTVERSION "0.0.1.0"
|
||||||
!endif
|
!endif
|
||||||
!ifndef INFO_COPYRIGHT
|
!ifndef INFO_COPYRIGHT
|
||||||
!define INFO_COPYRIGHT "© 2025 Voidraft. All rights reserved."
|
!define INFO_COPYRIGHT "© 2025 voidraft. All rights reserved."
|
||||||
!endif
|
!endif
|
||||||
!ifndef PRODUCT_EXECUTABLE
|
!ifndef PRODUCT_EXECUTABLE
|
||||||
!define PRODUCT_EXECUTABLE "${INFO_PROJECTNAME}.exe"
|
!define PRODUCT_EXECUTABLE "${INFO_PROJECTNAME}.exe"
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
<head>
|
<head>
|
||||||
<meta charset="UTF-8">
|
<meta charset="UTF-8">
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
<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/styles.css">
|
||||||
<link rel="stylesheet" href="css/changelog.css">
|
<link rel="stylesheet" href="css/changelog.css">
|
||||||
<link rel="icon" href="img/favicon.ico">
|
<link rel="icon" href="img/favicon.ico">
|
||||||
@@ -16,7 +16,7 @@
|
|||||||
<!-- 主卡片 -->
|
<!-- 主卡片 -->
|
||||||
<div class="card">
|
<div class="card">
|
||||||
<div class="card-header">
|
<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">
|
<div class="card-controls">
|
||||||
<button id="theme-toggle" class="btn btn-secondary" title="切换主题">
|
<button id="theme-toggle" class="btn btn-secondary" title="切换主题">
|
||||||
<i class="fas fa-sun"></i> <span data-en="Theme" data-zh="主题">Theme</span>
|
<i class="fas fa-sun"></i> <span data-en="Theme" data-zh="主题">Theme</span>
|
||||||
@@ -59,7 +59,7 @@
|
|||||||
|
|
||||||
<!-- 页脚 -->
|
<!-- 页脚 -->
|
||||||
<footer class="footer">
|
<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">
|
<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" 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>
|
<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>
|
<head>
|
||||||
<meta charset="UTF-8">
|
<meta charset="UTF-8">
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
<title>VoidRaft - An elegant text snippet recording tool designed for developers.</title>
|
<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="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="keywords" content="text editor, code snippets, developer tools, syntax highlighting, code formatting, multi-language, voidraft">
|
||||||
<meta name="author" content="VoidRaft Team">
|
<meta name="author" content="voidraft Team">
|
||||||
<meta name="robots" content="index, follow">
|
<meta name="robots" content="index, follow">
|
||||||
<link rel="canonical" href="https://landaiqing.github.io/voidraft/">
|
<link rel="canonical" href="https://landaiqing.github.io/voidraft/">
|
||||||
|
|
||||||
@@ -18,16 +18,16 @@
|
|||||||
<!-- Open Graph / Facebook -->
|
<!-- Open Graph / Facebook -->
|
||||||
<meta property="og:type" content="website">
|
<meta property="og:type" content="website">
|
||||||
<meta property="og:url" content="https://landaiqing.github.io/voidraft/">
|
<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: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: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: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 -->
|
<!-- Twitter -->
|
||||||
<meta property="twitter:card" content="summary_large_image">
|
<meta property="twitter:card" content="summary_large_image">
|
||||||
<meta property="twitter:url" content="https://landaiqing.github.io/voidraft/">
|
<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: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: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">
|
<meta property="twitter:image" content="https://landaiqing.github.io/voidraft/img/screenshot-dark.png">
|
||||||
|
|
||||||
<link rel="stylesheet" href="./css/styles.css">
|
<link rel="stylesheet" href="./css/styles.css">
|
||||||
@@ -39,13 +39,13 @@
|
|||||||
{
|
{
|
||||||
"@context": "https://schema.org",
|
"@context": "https://schema.org",
|
||||||
"@type": "SoftwareApplication",
|
"@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.",
|
"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/",
|
"url": "https://landaiqing.github.io/voidraft/",
|
||||||
"downloadUrl": "https://github.com/landaiqing/voidraft/releases",
|
"downloadUrl": "https://github.com/landaiqing/voidraft/releases",
|
||||||
"author": {
|
"author": {
|
||||||
"@type": "Organization",
|
"@type": "Organization",
|
||||||
"name": "VoidRaft"
|
"name": "voidraft"
|
||||||
},
|
},
|
||||||
"operatingSystem": ["Windows", "macOS", "Linux"],
|
"operatingSystem": ["Windows", "macOS", "Linux"],
|
||||||
"applicationCategory": "DeveloperApplication",
|
"applicationCategory": "DeveloperApplication",
|
||||||
@@ -66,7 +66,7 @@
|
|||||||
<!-- 主卡片 -->
|
<!-- 主卡片 -->
|
||||||
<div class="card">
|
<div class="card">
|
||||||
<div class="card-header">
|
<div class="card-header">
|
||||||
<h1 class="card-title">VoidRaft</h1>
|
<h1 class="card-title">voidraft</h1>
|
||||||
<div class="card-controls">
|
<div class="card-controls">
|
||||||
<button id="theme-toggle" class="btn btn-secondary" title="切换主题">
|
<button id="theme-toggle" class="btn btn-secondary" title="切换主题">
|
||||||
<i class="fas fa-sun"></i> <span data-en="Theme" data-zh="主题">Theme</span>
|
<i class="fas fa-sun"></i> <span data-en="Theme" data-zh="主题">Theme</span>
|
||||||
@@ -81,9 +81,9 @@
|
|||||||
<!-- Logo和介绍 -->
|
<!-- Logo和介绍 -->
|
||||||
<div class="logo-container">
|
<div class="logo-container">
|
||||||
<div class="logo-frame">
|
<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>
|
</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>
|
<p class="tagline" data-en="An elegant text snippet recording tool" data-zh="优雅的文本片段记录工具">An elegant text snippet recording tool</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@@ -195,15 +195,15 @@
|
|||||||
<div class="block-language">text</div>
|
<div class="block-language">text</div>
|
||||||
</div>
|
</div>
|
||||||
<pre class="code-block">
|
<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">// Multi-language support | Code formatting | Custom themes</span>
|
||||||
<span class="comment">// A modern text editor designed for developers</span></pre>
|
<span class="comment">// A modern text editor designed for developers</span></pre>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="preview-window">
|
<div class="preview-window">
|
||||||
<img src="img/screenshot-dark.png" alt="VoidRaft 界面预览" class="preview-image dark-theme-img">
|
<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-light.png" alt="voidraft 界面预览" class="preview-image light-theme-img" style="display: none;">
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@@ -241,7 +241,7 @@
|
|||||||
|
|
||||||
<!-- 页脚 -->
|
<!-- 页脚 -->
|
||||||
<footer class="footer">
|
<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">
|
<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" 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>
|
<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备用源
|
* 从GitHub API获取发布信息,支持Gitea备用源
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/**
|
/**
|
||||||
* VoidRaft - Website Script
|
* voidraft - Website Script
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -233,14 +233,14 @@ class SEOManager {
|
|||||||
this.languageManager = languageManager;
|
this.languageManager = languageManager;
|
||||||
this.metaTexts = {
|
this.metaTexts = {
|
||||||
en: {
|
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.',
|
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.',
|
title: 'voidraft - An elegant text snippet recording tool designed for developers.',
|
||||||
ogTitle: 'VoidRaft - An elegant text snippet recording tool designed for developers'
|
ogTitle: 'voidraft - An elegant text snippet recording tool designed for developers'
|
||||||
},
|
},
|
||||||
zh: {
|
zh: {
|
||||||
description: 'VoidRaft 是专为开发者打造的优雅文本片段记录工具。支持多语言代码块、语法高亮、代码格式化、自定义主题等功能。',
|
description: 'voidraft 是专为开发者打造的优雅文本片段记录工具。支持多语言代码块、语法高亮、代码格式化、自定义主题等功能。',
|
||||||
title: 'VoidRaft - 专为开发者打造的优雅文本片段记录工具',
|
title: 'voidraft - 专为开发者打造的优雅文本片段记录工具',
|
||||||
ogTitle: 'VoidRaft - 专为开发者打造的优雅文本片段记录工具'
|
ogTitle: 'voidraft - 专为开发者打造的优雅文本片段记录工具'
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
this.init();
|
this.init();
|
||||||
@@ -371,9 +371,9 @@ class UIEffects {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* VoidRaft主应用类
|
* voidraft主应用类
|
||||||
*/
|
*/
|
||||||
class VoidRaftApp {
|
class voidraftApp {
|
||||||
constructor() {
|
constructor() {
|
||||||
this.themeManager = null;
|
this.themeManager = null;
|
||||||
this.languageManager = null;
|
this.languageManager = null;
|
||||||
@@ -404,7 +404,7 @@ class VoidRaftApp {
|
|||||||
* 显示控制台品牌信息
|
* 显示控制台品牌信息
|
||||||
*/
|
*/
|
||||||
showConsoleBranding() {
|
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;');
|
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加载完成时初始化应用
|
// 当DOM加载完成时初始化应用
|
||||||
document.addEventListener('DOMContentLoaded', () => {
|
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>);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -114,11 +114,6 @@ export class AppearanceConfig {
|
|||||||
*/
|
*/
|
||||||
"systemTheme": SystemThemeType;
|
"systemTheme": SystemThemeType;
|
||||||
|
|
||||||
/**
|
|
||||||
* 自定义主题配置
|
|
||||||
*/
|
|
||||||
"customTheme": CustomThemeConfig;
|
|
||||||
|
|
||||||
/** Creates a new AppearanceConfig instance. */
|
/** Creates a new AppearanceConfig instance. */
|
||||||
constructor($$source: Partial<AppearanceConfig> = {}) {
|
constructor($$source: Partial<AppearanceConfig> = {}) {
|
||||||
if (!("language" in $$source)) {
|
if (!("language" in $$source)) {
|
||||||
@@ -127,9 +122,6 @@ export class AppearanceConfig {
|
|||||||
if (!("systemTheme" in $$source)) {
|
if (!("systemTheme" in $$source)) {
|
||||||
this["systemTheme"] = ("" as SystemThemeType);
|
this["systemTheme"] = ("" as SystemThemeType);
|
||||||
}
|
}
|
||||||
if (!("customTheme" in $$source)) {
|
|
||||||
this["customTheme"] = (new CustomThemeConfig());
|
|
||||||
}
|
|
||||||
|
|
||||||
Object.assign(this, $$source);
|
Object.assign(this, $$source);
|
||||||
}
|
}
|
||||||
@@ -138,11 +130,7 @@ export class AppearanceConfig {
|
|||||||
* Creates a new AppearanceConfig instance from a string or object.
|
* Creates a new AppearanceConfig instance from a string or object.
|
||||||
*/
|
*/
|
||||||
static createFrom($$source: any = {}): AppearanceConfig {
|
static createFrom($$source: any = {}): AppearanceConfig {
|
||||||
const $$createField2_0 = $$createType6;
|
|
||||||
let $$parsedSource = typeof $$source === 'string' ? JSON.parse($$source) : $$source;
|
let $$parsedSource = typeof $$source === 'string' ? JSON.parse($$source) : $$source;
|
||||||
if ("customTheme" in $$parsedSource) {
|
|
||||||
$$parsedSource["customTheme"] = $$createField2_0($$parsedSource["customTheme"]);
|
|
||||||
}
|
|
||||||
return new AppearanceConfig($$parsedSource as Partial<AppearanceConfig>);
|
return new AppearanceConfig($$parsedSource as Partial<AppearanceConfig>);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -201,49 +189,6 @@ export class ConfigMetadata {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* CustomThemeConfig 自定义主题配置
|
|
||||||
*/
|
|
||||||
export class CustomThemeConfig {
|
|
||||||
/**
|
|
||||||
* 深色主题配置
|
|
||||||
*/
|
|
||||||
"darkTheme": ThemeColorConfig;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 浅色主题配置
|
|
||||||
*/
|
|
||||||
"lightTheme": ThemeColorConfig;
|
|
||||||
|
|
||||||
/** Creates a new CustomThemeConfig instance. */
|
|
||||||
constructor($$source: Partial<CustomThemeConfig> = {}) {
|
|
||||||
if (!("darkTheme" in $$source)) {
|
|
||||||
this["darkTheme"] = (new ThemeColorConfig());
|
|
||||||
}
|
|
||||||
if (!("lightTheme" in $$source)) {
|
|
||||||
this["lightTheme"] = (new ThemeColorConfig());
|
|
||||||
}
|
|
||||||
|
|
||||||
Object.assign(this, $$source);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Creates a new CustomThemeConfig instance from a string or object.
|
|
||||||
*/
|
|
||||||
static createFrom($$source: any = {}): CustomThemeConfig {
|
|
||||||
const $$createField0_0 = $$createType7;
|
|
||||||
const $$createField1_0 = $$createType7;
|
|
||||||
let $$parsedSource = typeof $$source === 'string' ? JSON.parse($$source) : $$source;
|
|
||||||
if ("darkTheme" in $$parsedSource) {
|
|
||||||
$$parsedSource["darkTheme"] = $$createField0_0($$parsedSource["darkTheme"]);
|
|
||||||
}
|
|
||||||
if ("lightTheme" in $$parsedSource) {
|
|
||||||
$$parsedSource["lightTheme"] = $$createField1_0($$parsedSource["lightTheme"]);
|
|
||||||
}
|
|
||||||
return new CustomThemeConfig($$parsedSource as Partial<CustomThemeConfig>);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Document represents a document in the system
|
* Document represents a document in the system
|
||||||
*/
|
*/
|
||||||
@@ -428,7 +373,7 @@ export class Extension {
|
|||||||
* Creates a new Extension instance from a string or object.
|
* Creates a new Extension instance from a string or object.
|
||||||
*/
|
*/
|
||||||
static createFrom($$source: any = {}): Extension {
|
static createFrom($$source: any = {}): Extension {
|
||||||
const $$createField3_0 = $$createType8;
|
const $$createField3_0 = $$createType6;
|
||||||
let $$parsedSource = typeof $$source === 'string' ? JSON.parse($$source) : $$source;
|
let $$parsedSource = typeof $$source === 'string' ? JSON.parse($$source) : $$source;
|
||||||
if ("config" in $$parsedSource) {
|
if ("config" in $$parsedSource) {
|
||||||
$$parsedSource["config"] = $$createField3_0($$parsedSource["config"]);
|
$$parsedSource["config"] = $$createField3_0($$parsedSource["config"]);
|
||||||
@@ -522,6 +467,12 @@ export class GeneralConfig {
|
|||||||
*/
|
*/
|
||||||
"startAtLogin": boolean;
|
"startAtLogin": boolean;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 窗口吸附设置
|
||||||
|
* 是否启用窗口吸附功能(阈值现在是自适应的)
|
||||||
|
*/
|
||||||
|
"enableWindowSnap": boolean;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 全局热键设置
|
* 全局热键设置
|
||||||
* 是否启用全局热键
|
* 是否启用全局热键
|
||||||
@@ -547,6 +498,9 @@ export class GeneralConfig {
|
|||||||
if (!("startAtLogin" in $$source)) {
|
if (!("startAtLogin" in $$source)) {
|
||||||
this["startAtLogin"] = false;
|
this["startAtLogin"] = false;
|
||||||
}
|
}
|
||||||
|
if (!("enableWindowSnap" in $$source)) {
|
||||||
|
this["enableWindowSnap"] = false;
|
||||||
|
}
|
||||||
if (!("enableGlobalHotkey" in $$source)) {
|
if (!("enableGlobalHotkey" in $$source)) {
|
||||||
this["enableGlobalHotkey"] = false;
|
this["enableGlobalHotkey"] = false;
|
||||||
}
|
}
|
||||||
@@ -561,10 +515,10 @@ export class GeneralConfig {
|
|||||||
* Creates a new GeneralConfig instance from a string or object.
|
* Creates a new GeneralConfig instance from a string or object.
|
||||||
*/
|
*/
|
||||||
static createFrom($$source: any = {}): GeneralConfig {
|
static createFrom($$source: any = {}): GeneralConfig {
|
||||||
const $$createField5_0 = $$createType10;
|
const $$createField6_0 = $$createType8;
|
||||||
let $$parsedSource = typeof $$source === 'string' ? JSON.parse($$source) : $$source;
|
let $$parsedSource = typeof $$source === 'string' ? JSON.parse($$source) : $$source;
|
||||||
if ("globalHotkey" in $$parsedSource) {
|
if ("globalHotkey" in $$parsedSource) {
|
||||||
$$parsedSource["globalHotkey"] = $$createField5_0($$parsedSource["globalHotkey"]);
|
$$parsedSource["globalHotkey"] = $$createField6_0($$parsedSource["globalHotkey"]);
|
||||||
}
|
}
|
||||||
return new GeneralConfig($$parsedSource as Partial<GeneralConfig>);
|
return new GeneralConfig($$parsedSource as Partial<GeneralConfig>);
|
||||||
}
|
}
|
||||||
@@ -1171,6 +1125,58 @@ export enum TabType {
|
|||||||
TabTypeTab = "tab",
|
TabTypeTab = "tab",
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Theme 主题数据库模型
|
||||||
|
*/
|
||||||
|
export class Theme {
|
||||||
|
"id": number;
|
||||||
|
"name": string;
|
||||||
|
"type": ThemeType;
|
||||||
|
"colors": ThemeColorConfig;
|
||||||
|
"isDefault": boolean;
|
||||||
|
"createdAt": time$0.Time;
|
||||||
|
"updatedAt": time$0.Time;
|
||||||
|
|
||||||
|
/** Creates a new Theme instance. */
|
||||||
|
constructor($$source: Partial<Theme> = {}) {
|
||||||
|
if (!("id" in $$source)) {
|
||||||
|
this["id"] = 0;
|
||||||
|
}
|
||||||
|
if (!("name" in $$source)) {
|
||||||
|
this["name"] = "";
|
||||||
|
}
|
||||||
|
if (!("type" in $$source)) {
|
||||||
|
this["type"] = ("" as ThemeType);
|
||||||
|
}
|
||||||
|
if (!("colors" in $$source)) {
|
||||||
|
this["colors"] = (new ThemeColorConfig());
|
||||||
|
}
|
||||||
|
if (!("isDefault" in $$source)) {
|
||||||
|
this["isDefault"] = false;
|
||||||
|
}
|
||||||
|
if (!("createdAt" in $$source)) {
|
||||||
|
this["createdAt"] = null;
|
||||||
|
}
|
||||||
|
if (!("updatedAt" in $$source)) {
|
||||||
|
this["updatedAt"] = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
Object.assign(this, $$source);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a new Theme instance from a string or object.
|
||||||
|
*/
|
||||||
|
static createFrom($$source: any = {}): Theme {
|
||||||
|
const $$createField3_0 = $$createType9;
|
||||||
|
let $$parsedSource = typeof $$source === 'string' ? JSON.parse($$source) : $$source;
|
||||||
|
if ("colors" in $$parsedSource) {
|
||||||
|
$$parsedSource["colors"] = $$createField3_0($$parsedSource["colors"]);
|
||||||
|
}
|
||||||
|
return new Theme($$parsedSource as Partial<Theme>);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* ThemeColorConfig 主题颜色配置
|
* ThemeColorConfig 主题颜色配置
|
||||||
*/
|
*/
|
||||||
@@ -1379,6 +1385,19 @@ export class ThemeColorConfig {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ThemeType 主题类型枚举
|
||||||
|
*/
|
||||||
|
export enum ThemeType {
|
||||||
|
/**
|
||||||
|
* The Go zero value for the underlying type of the enum.
|
||||||
|
*/
|
||||||
|
$zero = "",
|
||||||
|
|
||||||
|
ThemeTypeDark = "dark",
|
||||||
|
ThemeTypeLight = "light",
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* UpdateSourceType 更新源类型
|
* UpdateSourceType 更新源类型
|
||||||
*/
|
*/
|
||||||
@@ -1477,8 +1496,8 @@ export class UpdatesConfig {
|
|||||||
* Creates a new UpdatesConfig instance from a string or object.
|
* Creates a new UpdatesConfig instance from a string or object.
|
||||||
*/
|
*/
|
||||||
static createFrom($$source: any = {}): UpdatesConfig {
|
static createFrom($$source: any = {}): UpdatesConfig {
|
||||||
const $$createField6_0 = $$createType11;
|
const $$createField6_0 = $$createType10;
|
||||||
const $$createField7_0 = $$createType12;
|
const $$createField7_0 = $$createType11;
|
||||||
let $$parsedSource = typeof $$source === 'string' ? JSON.parse($$source) : $$source;
|
let $$parsedSource = typeof $$source === 'string' ? JSON.parse($$source) : $$source;
|
||||||
if ("github" in $$parsedSource) {
|
if ("github" in $$parsedSource) {
|
||||||
$$parsedSource["github"] = $$createField6_0($$parsedSource["github"]);
|
$$parsedSource["github"] = $$createField6_0($$parsedSource["github"]);
|
||||||
@@ -1497,15 +1516,14 @@ const $$createType2 = AppearanceConfig.createFrom;
|
|||||||
const $$createType3 = UpdatesConfig.createFrom;
|
const $$createType3 = UpdatesConfig.createFrom;
|
||||||
const $$createType4 = GitBackupConfig.createFrom;
|
const $$createType4 = GitBackupConfig.createFrom;
|
||||||
const $$createType5 = ConfigMetadata.createFrom;
|
const $$createType5 = ConfigMetadata.createFrom;
|
||||||
const $$createType6 = CustomThemeConfig.createFrom;
|
var $$createType6 = (function $$initCreateType6(...args): any {
|
||||||
const $$createType7 = ThemeColorConfig.createFrom;
|
if ($$createType6 === $$initCreateType6) {
|
||||||
var $$createType8 = (function $$initCreateType8(...args): any {
|
$$createType6 = $$createType7;
|
||||||
if ($$createType8 === $$initCreateType8) {
|
|
||||||
$$createType8 = $$createType9;
|
|
||||||
}
|
}
|
||||||
return $$createType8(...args);
|
return $$createType6(...args);
|
||||||
});
|
});
|
||||||
const $$createType9 = $Create.Map($Create.Any, $Create.Any);
|
const $$createType7 = $Create.Map($Create.Any, $Create.Any);
|
||||||
const $$createType10 = HotkeyCombo.createFrom;
|
const $$createType8 = HotkeyCombo.createFrom;
|
||||||
const $$createType11 = GithubConfig.createFrom;
|
const $$createType9 = ThemeColorConfig.createFrom;
|
||||||
const $$createType12 = GiteaConfig.createFrom;
|
const $$createType10 = GithubConfig.createFrom;
|
||||||
|
const $$createType11 = GiteaConfig.createFrom;
|
||||||
|
|||||||
@@ -34,6 +34,30 @@ export function GetConfig(): Promise<models$0.AppConfig | null> & { cancel(): vo
|
|||||||
return $typingPromise;
|
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 强制重置所有配置为默认值
|
* ResetConfig 强制重置所有配置为默认值
|
||||||
*/
|
*/
|
||||||
@@ -82,6 +106,14 @@ export function SetHotkeyChangeCallback(callback: any): Promise<void> & { cancel
|
|||||||
return $resultPromise;
|
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
|
// Private type creation functions
|
||||||
const $$createType0 = models$0.AppConfig.createFrom;
|
const $$createType0 = models$0.AppConfig.createFrom;
|
||||||
const $$createType1 = $Create.Nullable($$createType0);
|
const $$createType1 = $Create.Nullable($$createType0);
|
||||||
|
|||||||
@@ -32,8 +32,8 @@ export function GetCurrentHotkey(): Promise<models$0.HotkeyCombo | null> & { can
|
|||||||
/**
|
/**
|
||||||
* Initialize 初始化热键服务
|
* Initialize 初始化热键服务
|
||||||
*/
|
*/
|
||||||
export function Initialize(app: application$0.App | null): Promise<void> & { cancel(): void } {
|
export function Initialize(app: application$0.App | null, mainWindow: application$0.WebviewWindow | null): Promise<void> & { cancel(): void } {
|
||||||
let $resultPromise = $Call.ByID(3671360458, app) as any;
|
let $resultPromise = $Call.ByID(3671360458, app, mainWindow) as any;
|
||||||
return $resultPromise;
|
return $resultPromise;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -13,6 +13,8 @@ import * as MigrationService from "./migrationservice.js";
|
|||||||
import * as SelfUpdateService from "./selfupdateservice.js";
|
import * as SelfUpdateService from "./selfupdateservice.js";
|
||||||
import * as StartupService from "./startupservice.js";
|
import * as StartupService from "./startupservice.js";
|
||||||
import * as SystemService from "./systemservice.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 TranslationService from "./translationservice.js";
|
||||||
import * as TrayService from "./trayservice.js";
|
import * as TrayService from "./trayservice.js";
|
||||||
import * as WindowService from "./windowservice.js";
|
import * as WindowService from "./windowservice.js";
|
||||||
@@ -29,6 +31,8 @@ export {
|
|||||||
SelfUpdateService,
|
SelfUpdateService,
|
||||||
StartupService,
|
StartupService,
|
||||||
SystemService,
|
SystemService,
|
||||||
|
TestService,
|
||||||
|
ThemeService,
|
||||||
TranslationService,
|
TranslationService,
|
||||||
TrayService,
|
TrayService,
|
||||||
WindowService
|
WindowService
|
||||||
|
|||||||
@@ -203,7 +203,7 @@ export class SelfUpdateResult {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* WindowInfo 窗口信息
|
* WindowInfo 窗口信息(简化版)
|
||||||
*/
|
*/
|
||||||
export class WindowInfo {
|
export class WindowInfo {
|
||||||
"Window": application$0.WebviewWindow | null;
|
"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
|
// Private type creation functions
|
||||||
const $$createType0 = application$0.WebviewWindow.createFrom;
|
const $$createType0 = application$0.WebviewWindow.createFrom;
|
||||||
const $$createType1 = $Create.Nullable($$createType0);
|
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;
|
||||||
|
}
|
||||||
104
frontend/bindings/voidraft/internal/services/themeservice.ts
Normal file
104
frontend/bindings/voidraft/internal/services/themeservice.ts
Normal file
@@ -0,0 +1,104 @@
|
|||||||
|
// Cynhyrchwyd y ffeil hon yn awtomatig. PEIDIWCH Â MODIWL
|
||||||
|
// This file is automatically generated. DO NOT EDIT
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ThemeService 主题服务
|
||||||
|
* @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";
|
||||||
|
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
||||||
|
// @ts-ignore: Unused imports
|
||||||
|
import * as models$0 from "../models/models.js";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* CreateTheme 创建新主题
|
||||||
|
*/
|
||||||
|
export function CreateTheme(theme: models$0.Theme | null): Promise<models$0.Theme | null> & { cancel(): void } {
|
||||||
|
let $resultPromise = $Call.ByID(3274757686, theme) as any;
|
||||||
|
let $typingPromise = $resultPromise.then(($result: any) => {
|
||||||
|
return $$createType1($result);
|
||||||
|
}) as any;
|
||||||
|
$typingPromise.cancel = $resultPromise.cancel.bind($resultPromise);
|
||||||
|
return $typingPromise;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* GetAllThemes 获取所有主题
|
||||||
|
*/
|
||||||
|
export function GetAllThemes(): Promise<(models$0.Theme | null)[]> & { cancel(): void } {
|
||||||
|
let $resultPromise = $Call.ByID(2425053076) as any;
|
||||||
|
let $typingPromise = $resultPromise.then(($result: any) => {
|
||||||
|
return $$createType2($result);
|
||||||
|
}) as any;
|
||||||
|
$typingPromise.cancel = $resultPromise.cancel.bind($resultPromise);
|
||||||
|
return $typingPromise;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* GetDefaultThemes 获取默认主题
|
||||||
|
*/
|
||||||
|
export function GetDefaultThemes(): Promise<{ [_: string]: models$0.Theme | null }> & { cancel(): void } {
|
||||||
|
let $resultPromise = $Call.ByID(3801788118) as any;
|
||||||
|
let $typingPromise = $resultPromise.then(($result: any) => {
|
||||||
|
return $$createType3($result);
|
||||||
|
}) as any;
|
||||||
|
$typingPromise.cancel = $resultPromise.cancel.bind($resultPromise);
|
||||||
|
return $typingPromise;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* GetThemeByType 根据类型获取默认主题
|
||||||
|
*/
|
||||||
|
export function GetThemeByType(themeType: models$0.ThemeType): Promise<models$0.Theme | null> & { cancel(): void } {
|
||||||
|
let $resultPromise = $Call.ByID(1680465265, themeType) as any;
|
||||||
|
let $typingPromise = $resultPromise.then(($result: any) => {
|
||||||
|
return $$createType1($result);
|
||||||
|
}) as any;
|
||||||
|
$typingPromise.cancel = $resultPromise.cancel.bind($resultPromise);
|
||||||
|
return $typingPromise;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ResetThemeColors 重置主题颜色为默认值
|
||||||
|
*/
|
||||||
|
export function ResetThemeColors(themeType: models$0.ThemeType): Promise<void> & { cancel(): void } {
|
||||||
|
let $resultPromise = $Call.ByID(342461245, themeType) as any;
|
||||||
|
return $resultPromise;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ServiceShutdown 服务关闭
|
||||||
|
*/
|
||||||
|
export function ServiceShutdown(): Promise<void> & { cancel(): void } {
|
||||||
|
let $resultPromise = $Call.ByID(1676749034) as any;
|
||||||
|
return $resultPromise;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ServiceStartup 服务启动时初始化
|
||||||
|
*/
|
||||||
|
export function ServiceStartup(options: application$0.ServiceOptions): Promise<void> & { cancel(): void } {
|
||||||
|
let $resultPromise = $Call.ByID(2915959937, options) as any;
|
||||||
|
return $resultPromise;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* UpdateThemeColors 更新主题颜色
|
||||||
|
*/
|
||||||
|
export function UpdateThemeColors(themeType: models$0.ThemeType, colors: models$0.ThemeColorConfig): Promise<void> & { cancel(): void } {
|
||||||
|
let $resultPromise = $Call.ByID(2750902529, themeType, colors) as any;
|
||||||
|
return $resultPromise;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Private type creation functions
|
||||||
|
const $$createType0 = models$0.Theme.createFrom;
|
||||||
|
const $$createType1 = $Create.Nullable($$createType0);
|
||||||
|
const $$createType2 = $Create.Array($$createType1);
|
||||||
|
const $$createType3 = $Create.Map($Create.Any, $$createType1);
|
||||||
@@ -2,7 +2,7 @@
|
|||||||
// This file is automatically generated. DO NOT EDIT
|
// This file is automatically generated. DO NOT EDIT
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* WindowService 窗口管理服务
|
* WindowService 窗口管理服务(专注于窗口生命周期管理)
|
||||||
* @module
|
* @module
|
||||||
*/
|
*/
|
||||||
|
|
||||||
@@ -46,6 +46,14 @@ export function OpenDocumentWindow(documentID: number): Promise<void> & { cancel
|
|||||||
return $resultPromise;
|
return $resultPromise;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ServiceShutdown 实现服务关闭接口
|
||||||
|
*/
|
||||||
|
export function ServiceShutdown(): Promise<void> & { cancel(): void } {
|
||||||
|
let $resultPromise = $Call.ByID(202192783) as any;
|
||||||
|
return $resultPromise;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* SetAppReferences 设置应用和主窗口引用
|
* SetAppReferences 设置应用和主窗口引用
|
||||||
*/
|
*/
|
||||||
@@ -54,6 +62,14 @@ export function SetAppReferences(app: application$0.App | null, mainWindow: appl
|
|||||||
return $resultPromise;
|
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
|
// Private type creation functions
|
||||||
const $$createType0 = $models.WindowInfo.createFrom;
|
const $$createType0 = $models.WindowInfo.createFrom;
|
||||||
const $$createType1 = $Create.Array($$createType0);
|
const $$createType1 = $Create.Array($$createType0);
|
||||||
|
|||||||
3286
frontend/package-lock.json
generated
3286
frontend/package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@@ -5,77 +5,92 @@
|
|||||||
"type": "module",
|
"type": "module",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"dev": "vite --host --mode development",
|
"dev": "vite --host --mode development",
|
||||||
"build:dev": "vue-tsc && vite build --minify false --mode development",
|
"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": "vue-tsc && vite build --mode production",
|
"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",
|
"preview": "vite preview",
|
||||||
"lint": "eslint",
|
"lint": "eslint",
|
||||||
"lint:fix": "eslint --fix"
|
"lint:fix": "eslint --fix"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@codemirror/autocomplete": "^6.18.6",
|
"@codemirror/autocomplete": "^6.18.7",
|
||||||
"@codemirror/commands": "^6.8.1",
|
"@codemirror/commands": "^6.8.1",
|
||||||
"@codemirror/lang-angular": "^0.1.4",
|
"@codemirror/lang-angular": "^0.1.4",
|
||||||
"@codemirror/lang-cpp": "^6.0.3",
|
"@codemirror/lang-cpp": "^6.0.3",
|
||||||
"@codemirror/lang-css": "^6.3.1",
|
"@codemirror/lang-css": "^6.3.1",
|
||||||
"@codemirror/lang-go": "^6.0.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-java": "^6.0.2",
|
||||||
"@codemirror/lang-javascript": "^6.2.4",
|
"@codemirror/lang-javascript": "^6.2.4",
|
||||||
"@codemirror/lang-json": "^6.0.2",
|
"@codemirror/lang-json": "^6.0.2",
|
||||||
"@codemirror/lang-less": "^6.0.2",
|
"@codemirror/lang-less": "^6.0.2",
|
||||||
"@codemirror/lang-lezer": "^6.0.2",
|
"@codemirror/lang-lezer": "^6.0.2",
|
||||||
"@codemirror/lang-liquid": "^6.2.3",
|
"@codemirror/lang-liquid": "^6.3.0",
|
||||||
"@codemirror/lang-markdown": "^6.3.3",
|
"@codemirror/lang-markdown": "^6.3.4",
|
||||||
"@codemirror/lang-php": "^6.0.2",
|
"@codemirror/lang-php": "^6.0.2",
|
||||||
"@codemirror/lang-python": "^6.2.1",
|
"@codemirror/lang-python": "^6.2.1",
|
||||||
"@codemirror/lang-rust": "^6.0.2",
|
"@codemirror/lang-rust": "^6.0.2",
|
||||||
"@codemirror/lang-sass": "^6.0.2",
|
"@codemirror/lang-sass": "^6.0.2",
|
||||||
"@codemirror/lang-sql": "^6.9.0",
|
"@codemirror/lang-sql": "^6.9.1",
|
||||||
"@codemirror/lang-vue": "^0.1.3",
|
"@codemirror/lang-vue": "^0.1.3",
|
||||||
"@codemirror/lang-wast": "^6.0.2",
|
"@codemirror/lang-wast": "^6.0.2",
|
||||||
"@codemirror/lang-xml": "^6.1.0",
|
|
||||||
"@codemirror/lang-yaml": "^6.1.2",
|
"@codemirror/lang-yaml": "^6.1.2",
|
||||||
"@codemirror/language": "^6.11.2",
|
"@codemirror/language": "^6.11.3",
|
||||||
"@codemirror/language-data": "^6.5.1",
|
"@codemirror/language-data": "^6.5.1",
|
||||||
"@codemirror/legacy-modes": "^6.5.1",
|
"@codemirror/legacy-modes": "^6.5.1",
|
||||||
"@codemirror/lint": "^6.8.5",
|
"@codemirror/lint": "^6.8.5",
|
||||||
"@codemirror/search": "^6.5.11",
|
"@codemirror/search": "^6.5.11",
|
||||||
"@codemirror/state": "^6.5.2",
|
"@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/highlight": "^1.2.1",
|
||||||
"@lezer/lr": "^1.4.2",
|
"@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": "^6.0.2",
|
||||||
"codemirror-lang-elixir": "^4.0.0",
|
"codemirror-lang-elixir": "^4.0.0",
|
||||||
"colors-named": "^1.0.2",
|
"colors-named": "^1.0.2",
|
||||||
"colors-named-hex": "^1.0.2",
|
"colors-named-hex": "^1.0.2",
|
||||||
"franc-min": "^6.2.0",
|
"franc-min": "^6.2.0",
|
||||||
|
"groovy-beautify": "^0.0.17",
|
||||||
"hsl-matcher": "^1.2.4",
|
"hsl-matcher": "^1.2.4",
|
||||||
"lezer": "^0.13.5",
|
"java-parser": "^3.0.1",
|
||||||
|
"jinx-rust": "^0.1.6",
|
||||||
|
"jsox": "^1.2.123",
|
||||||
|
"linguist-languages": "^9.0.0",
|
||||||
|
"node-sql-parser": "^5.3.12",
|
||||||
|
"php-parser": "^3.2.5",
|
||||||
"pinia": "^3.0.3",
|
"pinia": "^3.0.3",
|
||||||
"pinia-plugin-persistedstate": "^4.4.1",
|
"pinia-plugin-persistedstate": "^4.5.0",
|
||||||
"prettier": "^3.6.2",
|
"prettier": "^3.6.2",
|
||||||
"remarkable": "^2.0.1",
|
"remarkable": "^2.0.1",
|
||||||
"sass": "^1.89.2",
|
"sass": "^1.92.1",
|
||||||
"vue": "^3.5.17",
|
"sh-syntax": "^0.5.8",
|
||||||
"vue-i18n": "^11.1.10",
|
"sql-formatter": "^15.6.9",
|
||||||
|
"vue": "^3.5.21",
|
||||||
|
"vue-i18n": "^11.1.12",
|
||||||
"vue-pick-colors": "^1.8.0",
|
"vue-pick-colors": "^1.8.0",
|
||||||
"vue-router": "^4.5.1"
|
"vue-router": "^4.5.1"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@eslint/js": "^9.31.0",
|
"@eslint/js": "^9.35.0",
|
||||||
"@lezer/generator": "^1.8.0",
|
"@lezer/generator": "^1.8.0",
|
||||||
"@types/node": "^24.0.14",
|
"@types/node": "^24.3.1",
|
||||||
"@types/remarkable": "^2.0.8",
|
"@types/remarkable": "^2.0.8",
|
||||||
"@vitejs/plugin-vue": "^6.0.0",
|
"@vitejs/plugin-vue": "^6.0.1",
|
||||||
"@wailsio/runtime": "latest",
|
"@wailsio/runtime": "latest",
|
||||||
"eslint": "^9.31.0",
|
"cross-env": "^7.0.3",
|
||||||
"eslint-plugin-vue": "^10.3.0",
|
"eslint": "^9.35.0",
|
||||||
"globals": "^16.3.0",
|
"eslint-plugin-vue": "^10.4.0",
|
||||||
"typescript": "^5.8.3",
|
"globals": "^16.4.0",
|
||||||
"typescript-eslint": "^8.37.0",
|
"rollup-plugin-visualizer": "^6.0.3",
|
||||||
"unplugin-vue-components": "^28.8.0",
|
"typescript": "^5.9.2",
|
||||||
"vite": "^7.0.4",
|
"typescript-eslint": "^8.43.0",
|
||||||
|
"unplugin-vue-components": "^29.0.0",
|
||||||
|
"vite": "^7.1.5",
|
||||||
|
"vite-plugin-node-polyfills": "^0.24.0",
|
||||||
"vue-eslint-parser": "^10.2.0",
|
"vue-eslint-parser": "^10.2.0",
|
||||||
"vue-tsc": "^3.0.1"
|
"vue-tsc": "^3.0.6"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
BIN
frontend/public/go.wasm
Normal file
BIN
frontend/public/go.wasm
Normal file
Binary file not shown.
561
frontend/public/wasm_exec.js
Normal file
561
frontend/public/wasm_exec.js
Normal file
@@ -0,0 +1,561 @@
|
|||||||
|
// 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.
|
||||||
|
|
||||||
|
"use strict";
|
||||||
|
|
||||||
|
(() => {
|
||||||
|
const enosys = () => {
|
||||||
|
const err = new Error("not implemented");
|
||||||
|
err.code = "ENOSYS";
|
||||||
|
return err;
|
||||||
|
};
|
||||||
|
|
||||||
|
if (!globalThis.fs) {
|
||||||
|
let outputBuf = "";
|
||||||
|
globalThis.fs = {
|
||||||
|
constants: { O_WRONLY: -1, O_RDWR: -1, O_CREAT: -1, O_TRUNC: -1, O_APPEND: -1, O_EXCL: -1 }, // unused
|
||||||
|
writeSync(fd, buf) {
|
||||||
|
outputBuf += decoder.decode(buf);
|
||||||
|
const nl = outputBuf.lastIndexOf("\n");
|
||||||
|
if (nl != -1) {
|
||||||
|
console.log(outputBuf.substring(0, nl));
|
||||||
|
outputBuf = outputBuf.substring(nl + 1);
|
||||||
|
}
|
||||||
|
return buf.length;
|
||||||
|
},
|
||||||
|
write(fd, buf, offset, length, position, callback) {
|
||||||
|
if (offset !== 0 || length !== buf.length || position !== null) {
|
||||||
|
callback(enosys());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const n = this.writeSync(fd, buf);
|
||||||
|
callback(null, n);
|
||||||
|
},
|
||||||
|
chmod(path, mode, callback) { callback(enosys()); },
|
||||||
|
chown(path, uid, gid, callback) { callback(enosys()); },
|
||||||
|
close(fd, callback) { callback(enosys()); },
|
||||||
|
fchmod(fd, mode, callback) { callback(enosys()); },
|
||||||
|
fchown(fd, uid, gid, callback) { callback(enosys()); },
|
||||||
|
fstat(fd, callback) { callback(enosys()); },
|
||||||
|
fsync(fd, callback) { callback(null); },
|
||||||
|
ftruncate(fd, length, callback) { callback(enosys()); },
|
||||||
|
lchown(path, uid, gid, callback) { callback(enosys()); },
|
||||||
|
link(path, link, callback) { callback(enosys()); },
|
||||||
|
lstat(path, callback) { callback(enosys()); },
|
||||||
|
mkdir(path, perm, callback) { callback(enosys()); },
|
||||||
|
open(path, flags, mode, callback) { callback(enosys()); },
|
||||||
|
read(fd, buffer, offset, length, position, callback) { callback(enosys()); },
|
||||||
|
readdir(path, callback) { callback(enosys()); },
|
||||||
|
readlink(path, callback) { callback(enosys()); },
|
||||||
|
rename(from, to, callback) { callback(enosys()); },
|
||||||
|
rmdir(path, callback) { callback(enosys()); },
|
||||||
|
stat(path, callback) { callback(enosys()); },
|
||||||
|
symlink(path, link, callback) { callback(enosys()); },
|
||||||
|
truncate(path, length, callback) { callback(enosys()); },
|
||||||
|
unlink(path, callback) { callback(enosys()); },
|
||||||
|
utimes(path, atime, mtime, callback) { callback(enosys()); },
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!globalThis.process) {
|
||||||
|
globalThis.process = {
|
||||||
|
getuid() { return -1; },
|
||||||
|
getgid() { return -1; },
|
||||||
|
geteuid() { return -1; },
|
||||||
|
getegid() { return -1; },
|
||||||
|
getgroups() { throw enosys(); },
|
||||||
|
pid: -1,
|
||||||
|
ppid: -1,
|
||||||
|
umask() { throw enosys(); },
|
||||||
|
cwd() { throw enosys(); },
|
||||||
|
chdir() { throw enosys(); },
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!globalThis.crypto) {
|
||||||
|
throw new Error("globalThis.crypto is not available, polyfill required (crypto.getRandomValues only)");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!globalThis.performance) {
|
||||||
|
throw new Error("globalThis.performance is not available, polyfill required (performance.now only)");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!globalThis.TextEncoder) {
|
||||||
|
throw new Error("globalThis.TextEncoder is not available, polyfill required");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!globalThis.TextDecoder) {
|
||||||
|
throw new Error("globalThis.TextDecoder is not available, polyfill required");
|
||||||
|
}
|
||||||
|
|
||||||
|
const encoder = new TextEncoder("utf-8");
|
||||||
|
const decoder = new TextDecoder("utf-8");
|
||||||
|
|
||||||
|
globalThis.Go = class {
|
||||||
|
constructor() {
|
||||||
|
this.argv = ["js"];
|
||||||
|
this.env = {};
|
||||||
|
this.exit = (code) => {
|
||||||
|
if (code !== 0) {
|
||||||
|
console.warn("exit code:", code);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
this._exitPromise = new Promise((resolve) => {
|
||||||
|
this._resolveExitPromise = resolve;
|
||||||
|
});
|
||||||
|
this._pendingEvent = null;
|
||||||
|
this._scheduledTimeouts = new Map();
|
||||||
|
this._nextCallbackTimeoutID = 1;
|
||||||
|
|
||||||
|
const setInt64 = (addr, v) => {
|
||||||
|
this.mem.setUint32(addr + 0, v, true);
|
||||||
|
this.mem.setUint32(addr + 4, Math.floor(v / 4294967296), true);
|
||||||
|
}
|
||||||
|
|
||||||
|
const setInt32 = (addr, v) => {
|
||||||
|
this.mem.setUint32(addr + 0, v, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
const getInt64 = (addr) => {
|
||||||
|
const low = this.mem.getUint32(addr + 0, true);
|
||||||
|
const high = this.mem.getInt32(addr + 4, true);
|
||||||
|
return low + high * 4294967296;
|
||||||
|
}
|
||||||
|
|
||||||
|
const loadValue = (addr) => {
|
||||||
|
const f = this.mem.getFloat64(addr, true);
|
||||||
|
if (f === 0) {
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
if (!isNaN(f)) {
|
||||||
|
return f;
|
||||||
|
}
|
||||||
|
|
||||||
|
const id = this.mem.getUint32(addr, true);
|
||||||
|
return this._values[id];
|
||||||
|
}
|
||||||
|
|
||||||
|
const storeValue = (addr, v) => {
|
||||||
|
const nanHead = 0x7FF80000;
|
||||||
|
|
||||||
|
if (typeof v === "number" && v !== 0) {
|
||||||
|
if (isNaN(v)) {
|
||||||
|
this.mem.setUint32(addr + 4, nanHead, true);
|
||||||
|
this.mem.setUint32(addr, 0, true);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
this.mem.setFloat64(addr, v, true);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (v === undefined) {
|
||||||
|
this.mem.setFloat64(addr, 0, true);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
let id = this._ids.get(v);
|
||||||
|
if (id === undefined) {
|
||||||
|
id = this._idPool.pop();
|
||||||
|
if (id === undefined) {
|
||||||
|
id = this._values.length;
|
||||||
|
}
|
||||||
|
this._values[id] = v;
|
||||||
|
this._goRefCounts[id] = 0;
|
||||||
|
this._ids.set(v, id);
|
||||||
|
}
|
||||||
|
this._goRefCounts[id]++;
|
||||||
|
let typeFlag = 0;
|
||||||
|
switch (typeof v) {
|
||||||
|
case "object":
|
||||||
|
if (v !== null) {
|
||||||
|
typeFlag = 1;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case "string":
|
||||||
|
typeFlag = 2;
|
||||||
|
break;
|
||||||
|
case "symbol":
|
||||||
|
typeFlag = 3;
|
||||||
|
break;
|
||||||
|
case "function":
|
||||||
|
typeFlag = 4;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
this.mem.setUint32(addr + 4, nanHead | typeFlag, true);
|
||||||
|
this.mem.setUint32(addr, id, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
const loadSlice = (addr) => {
|
||||||
|
const array = getInt64(addr + 0);
|
||||||
|
const len = getInt64(addr + 8);
|
||||||
|
return new Uint8Array(this._inst.exports.mem.buffer, array, len);
|
||||||
|
}
|
||||||
|
|
||||||
|
const loadSliceOfValues = (addr) => {
|
||||||
|
const array = getInt64(addr + 0);
|
||||||
|
const len = getInt64(addr + 8);
|
||||||
|
const a = new Array(len);
|
||||||
|
for (let i = 0; i < len; i++) {
|
||||||
|
a[i] = loadValue(array + i * 8);
|
||||||
|
}
|
||||||
|
return a;
|
||||||
|
}
|
||||||
|
|
||||||
|
const loadString = (addr) => {
|
||||||
|
const saddr = getInt64(addr + 0);
|
||||||
|
const len = getInt64(addr + 8);
|
||||||
|
return decoder.decode(new DataView(this._inst.exports.mem.buffer, saddr, len));
|
||||||
|
}
|
||||||
|
|
||||||
|
const timeOrigin = Date.now() - performance.now();
|
||||||
|
this.importObject = {
|
||||||
|
_gotest: {
|
||||||
|
add: (a, b) => a + b,
|
||||||
|
},
|
||||||
|
gojs: {
|
||||||
|
// Go's SP does not change as long as no Go code is running. Some operations (e.g. calls, getters and setters)
|
||||||
|
// may synchronously trigger a Go event handler. This makes Go code get executed in the middle of the imported
|
||||||
|
// function. A goroutine can switch to a new stack if the current stack is too small (see morestack function).
|
||||||
|
// This changes the SP, thus we have to update the SP used by the imported function.
|
||||||
|
|
||||||
|
// func wasmExit(code int32)
|
||||||
|
"runtime.wasmExit": (sp) => {
|
||||||
|
sp >>>= 0;
|
||||||
|
const code = this.mem.getInt32(sp + 8, true);
|
||||||
|
this.exited = true;
|
||||||
|
delete this._inst;
|
||||||
|
delete this._values;
|
||||||
|
delete this._goRefCounts;
|
||||||
|
delete this._ids;
|
||||||
|
delete this._idPool;
|
||||||
|
this.exit(code);
|
||||||
|
},
|
||||||
|
|
||||||
|
// func wasmWrite(fd uintptr, p unsafe.Pointer, n int32)
|
||||||
|
"runtime.wasmWrite": (sp) => {
|
||||||
|
sp >>>= 0;
|
||||||
|
const fd = getInt64(sp + 8);
|
||||||
|
const p = getInt64(sp + 16);
|
||||||
|
const n = this.mem.getInt32(sp + 24, true);
|
||||||
|
fs.writeSync(fd, new Uint8Array(this._inst.exports.mem.buffer, p, n));
|
||||||
|
},
|
||||||
|
|
||||||
|
// func resetMemoryDataView()
|
||||||
|
"runtime.resetMemoryDataView": (sp) => {
|
||||||
|
sp >>>= 0;
|
||||||
|
this.mem = new DataView(this._inst.exports.mem.buffer);
|
||||||
|
},
|
||||||
|
|
||||||
|
// func nanotime1() int64
|
||||||
|
"runtime.nanotime1": (sp) => {
|
||||||
|
sp >>>= 0;
|
||||||
|
setInt64(sp + 8, (timeOrigin + performance.now()) * 1000000);
|
||||||
|
},
|
||||||
|
|
||||||
|
// func walltime() (sec int64, nsec int32)
|
||||||
|
"runtime.walltime": (sp) => {
|
||||||
|
sp >>>= 0;
|
||||||
|
const msec = (new Date).getTime();
|
||||||
|
setInt64(sp + 8, msec / 1000);
|
||||||
|
this.mem.setInt32(sp + 16, (msec % 1000) * 1000000, true);
|
||||||
|
},
|
||||||
|
|
||||||
|
// func scheduleTimeoutEvent(delay int64) int32
|
||||||
|
"runtime.scheduleTimeoutEvent": (sp) => {
|
||||||
|
sp >>>= 0;
|
||||||
|
const id = this._nextCallbackTimeoutID;
|
||||||
|
this._nextCallbackTimeoutID++;
|
||||||
|
this._scheduledTimeouts.set(id, setTimeout(
|
||||||
|
() => {
|
||||||
|
this._resume();
|
||||||
|
while (this._scheduledTimeouts.has(id)) {
|
||||||
|
// for some reason Go failed to register the timeout event, log and try again
|
||||||
|
// (temporary workaround for https://github.com/golang/go/issues/28975)
|
||||||
|
console.warn("scheduleTimeoutEvent: missed timeout event");
|
||||||
|
this._resume();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
getInt64(sp + 8),
|
||||||
|
));
|
||||||
|
this.mem.setInt32(sp + 16, id, true);
|
||||||
|
},
|
||||||
|
|
||||||
|
// func clearTimeoutEvent(id int32)
|
||||||
|
"runtime.clearTimeoutEvent": (sp) => {
|
||||||
|
sp >>>= 0;
|
||||||
|
const id = this.mem.getInt32(sp + 8, true);
|
||||||
|
clearTimeout(this._scheduledTimeouts.get(id));
|
||||||
|
this._scheduledTimeouts.delete(id);
|
||||||
|
},
|
||||||
|
|
||||||
|
// func getRandomData(r []byte)
|
||||||
|
"runtime.getRandomData": (sp) => {
|
||||||
|
sp >>>= 0;
|
||||||
|
crypto.getRandomValues(loadSlice(sp + 8));
|
||||||
|
},
|
||||||
|
|
||||||
|
// func finalizeRef(v ref)
|
||||||
|
"syscall/js.finalizeRef": (sp) => {
|
||||||
|
sp >>>= 0;
|
||||||
|
const id = this.mem.getUint32(sp + 8, true);
|
||||||
|
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": (sp) => {
|
||||||
|
sp >>>= 0;
|
||||||
|
storeValue(sp + 24, loadString(sp + 8));
|
||||||
|
},
|
||||||
|
|
||||||
|
// func valueGet(v ref, p string) ref
|
||||||
|
"syscall/js.valueGet": (sp) => {
|
||||||
|
sp >>>= 0;
|
||||||
|
const result = Reflect.get(loadValue(sp + 8), loadString(sp + 16));
|
||||||
|
sp = this._inst.exports.getsp() >>> 0; // see comment above
|
||||||
|
storeValue(sp + 32, result);
|
||||||
|
},
|
||||||
|
|
||||||
|
// func valueSet(v ref, p string, x ref)
|
||||||
|
"syscall/js.valueSet": (sp) => {
|
||||||
|
sp >>>= 0;
|
||||||
|
Reflect.set(loadValue(sp + 8), loadString(sp + 16), loadValue(sp + 32));
|
||||||
|
},
|
||||||
|
|
||||||
|
// func valueDelete(v ref, p string)
|
||||||
|
"syscall/js.valueDelete": (sp) => {
|
||||||
|
sp >>>= 0;
|
||||||
|
Reflect.deleteProperty(loadValue(sp + 8), loadString(sp + 16));
|
||||||
|
},
|
||||||
|
|
||||||
|
// func valueIndex(v ref, i int) ref
|
||||||
|
"syscall/js.valueIndex": (sp) => {
|
||||||
|
sp >>>= 0;
|
||||||
|
storeValue(sp + 24, Reflect.get(loadValue(sp + 8), getInt64(sp + 16)));
|
||||||
|
},
|
||||||
|
|
||||||
|
// valueSetIndex(v ref, i int, x ref)
|
||||||
|
"syscall/js.valueSetIndex": (sp) => {
|
||||||
|
sp >>>= 0;
|
||||||
|
Reflect.set(loadValue(sp + 8), getInt64(sp + 16), loadValue(sp + 24));
|
||||||
|
},
|
||||||
|
|
||||||
|
// func valueCall(v ref, m string, args []ref) (ref, bool)
|
||||||
|
"syscall/js.valueCall": (sp) => {
|
||||||
|
sp >>>= 0;
|
||||||
|
try {
|
||||||
|
const v = loadValue(sp + 8);
|
||||||
|
const m = Reflect.get(v, loadString(sp + 16));
|
||||||
|
const args = loadSliceOfValues(sp + 32);
|
||||||
|
const result = Reflect.apply(m, v, args);
|
||||||
|
sp = this._inst.exports.getsp() >>> 0; // see comment above
|
||||||
|
storeValue(sp + 56, result);
|
||||||
|
this.mem.setUint8(sp + 64, 1);
|
||||||
|
} catch (err) {
|
||||||
|
sp = this._inst.exports.getsp() >>> 0; // see comment above
|
||||||
|
storeValue(sp + 56, err);
|
||||||
|
this.mem.setUint8(sp + 64, 0);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
// func valueInvoke(v ref, args []ref) (ref, bool)
|
||||||
|
"syscall/js.valueInvoke": (sp) => {
|
||||||
|
sp >>>= 0;
|
||||||
|
try {
|
||||||
|
const v = loadValue(sp + 8);
|
||||||
|
const args = loadSliceOfValues(sp + 16);
|
||||||
|
const result = Reflect.apply(v, undefined, args);
|
||||||
|
sp = this._inst.exports.getsp() >>> 0; // see comment above
|
||||||
|
storeValue(sp + 40, result);
|
||||||
|
this.mem.setUint8(sp + 48, 1);
|
||||||
|
} catch (err) {
|
||||||
|
sp = this._inst.exports.getsp() >>> 0; // see comment above
|
||||||
|
storeValue(sp + 40, err);
|
||||||
|
this.mem.setUint8(sp + 48, 0);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
// func valueNew(v ref, args []ref) (ref, bool)
|
||||||
|
"syscall/js.valueNew": (sp) => {
|
||||||
|
sp >>>= 0;
|
||||||
|
try {
|
||||||
|
const v = loadValue(sp + 8);
|
||||||
|
const args = loadSliceOfValues(sp + 16);
|
||||||
|
const result = Reflect.construct(v, args);
|
||||||
|
sp = this._inst.exports.getsp() >>> 0; // see comment above
|
||||||
|
storeValue(sp + 40, result);
|
||||||
|
this.mem.setUint8(sp + 48, 1);
|
||||||
|
} catch (err) {
|
||||||
|
sp = this._inst.exports.getsp() >>> 0; // see comment above
|
||||||
|
storeValue(sp + 40, err);
|
||||||
|
this.mem.setUint8(sp + 48, 0);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
// func valueLength(v ref) int
|
||||||
|
"syscall/js.valueLength": (sp) => {
|
||||||
|
sp >>>= 0;
|
||||||
|
setInt64(sp + 16, parseInt(loadValue(sp + 8).length));
|
||||||
|
},
|
||||||
|
|
||||||
|
// valuePrepareString(v ref) (ref, int)
|
||||||
|
"syscall/js.valuePrepareString": (sp) => {
|
||||||
|
sp >>>= 0;
|
||||||
|
const str = encoder.encode(String(loadValue(sp + 8)));
|
||||||
|
storeValue(sp + 16, str);
|
||||||
|
setInt64(sp + 24, str.length);
|
||||||
|
},
|
||||||
|
|
||||||
|
// valueLoadString(v ref, b []byte)
|
||||||
|
"syscall/js.valueLoadString": (sp) => {
|
||||||
|
sp >>>= 0;
|
||||||
|
const str = loadValue(sp + 8);
|
||||||
|
loadSlice(sp + 16).set(str);
|
||||||
|
},
|
||||||
|
|
||||||
|
// func valueInstanceOf(v ref, t ref) bool
|
||||||
|
"syscall/js.valueInstanceOf": (sp) => {
|
||||||
|
sp >>>= 0;
|
||||||
|
this.mem.setUint8(sp + 24, (loadValue(sp + 8) instanceof loadValue(sp + 16)) ? 1 : 0);
|
||||||
|
},
|
||||||
|
|
||||||
|
// func copyBytesToGo(dst []byte, src ref) (int, bool)
|
||||||
|
"syscall/js.copyBytesToGo": (sp) => {
|
||||||
|
sp >>>= 0;
|
||||||
|
const dst = loadSlice(sp + 8);
|
||||||
|
const src = loadValue(sp + 32);
|
||||||
|
if (!(src instanceof Uint8Array || src instanceof Uint8ClampedArray)) {
|
||||||
|
this.mem.setUint8(sp + 48, 0);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const toCopy = src.subarray(0, dst.length);
|
||||||
|
dst.set(toCopy);
|
||||||
|
setInt64(sp + 40, toCopy.length);
|
||||||
|
this.mem.setUint8(sp + 48, 1);
|
||||||
|
},
|
||||||
|
|
||||||
|
// func copyBytesToJS(dst ref, src []byte) (int, bool)
|
||||||
|
"syscall/js.copyBytesToJS": (sp) => {
|
||||||
|
sp >>>= 0;
|
||||||
|
const dst = loadValue(sp + 8);
|
||||||
|
const src = loadSlice(sp + 16);
|
||||||
|
if (!(dst instanceof Uint8Array || dst instanceof Uint8ClampedArray)) {
|
||||||
|
this.mem.setUint8(sp + 48, 0);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const toCopy = src.subarray(0, dst.length);
|
||||||
|
dst.set(toCopy);
|
||||||
|
setInt64(sp + 40, toCopy.length);
|
||||||
|
this.mem.setUint8(sp + 48, 1);
|
||||||
|
},
|
||||||
|
|
||||||
|
"debug": (value) => {
|
||||||
|
console.log(value);
|
||||||
|
},
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
async run(instance) {
|
||||||
|
if (!(instance instanceof WebAssembly.Instance)) {
|
||||||
|
throw new Error("Go.run: WebAssembly.Instance expected");
|
||||||
|
}
|
||||||
|
this._inst = instance;
|
||||||
|
this.mem = new DataView(this._inst.exports.mem.buffer);
|
||||||
|
this._values = [ // JS values that Go currently has references to, indexed by reference id
|
||||||
|
NaN,
|
||||||
|
0,
|
||||||
|
null,
|
||||||
|
true,
|
||||||
|
false,
|
||||||
|
globalThis,
|
||||||
|
this,
|
||||||
|
];
|
||||||
|
this._goRefCounts = new Array(this._values.length).fill(Infinity); // 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
|
||||||
|
[0, 1],
|
||||||
|
[null, 2],
|
||||||
|
[true, 3],
|
||||||
|
[false, 4],
|
||||||
|
[globalThis, 5],
|
||||||
|
[this, 6],
|
||||||
|
]);
|
||||||
|
this._idPool = []; // unused ids that have been garbage collected
|
||||||
|
this.exited = false; // whether the Go program has exited
|
||||||
|
|
||||||
|
// Pass command line arguments and environment variables to WebAssembly by writing them to the linear memory.
|
||||||
|
let offset = 4096;
|
||||||
|
|
||||||
|
const strPtr = (str) => {
|
||||||
|
const ptr = offset;
|
||||||
|
const bytes = encoder.encode(str + "\0");
|
||||||
|
new Uint8Array(this.mem.buffer, offset, bytes.length).set(bytes);
|
||||||
|
offset += bytes.length;
|
||||||
|
if (offset % 8 !== 0) {
|
||||||
|
offset += 8 - (offset % 8);
|
||||||
|
}
|
||||||
|
return ptr;
|
||||||
|
};
|
||||||
|
|
||||||
|
const argc = this.argv.length;
|
||||||
|
|
||||||
|
const argvPtrs = [];
|
||||||
|
this.argv.forEach((arg) => {
|
||||||
|
argvPtrs.push(strPtr(arg));
|
||||||
|
});
|
||||||
|
argvPtrs.push(0);
|
||||||
|
|
||||||
|
const keys = Object.keys(this.env).sort();
|
||||||
|
keys.forEach((key) => {
|
||||||
|
argvPtrs.push(strPtr(`${key}=${this.env[key]}`));
|
||||||
|
});
|
||||||
|
argvPtrs.push(0);
|
||||||
|
|
||||||
|
const argv = offset;
|
||||||
|
argvPtrs.forEach((ptr) => {
|
||||||
|
this.mem.setUint32(offset, ptr, true);
|
||||||
|
this.mem.setUint32(offset + 4, 0, true);
|
||||||
|
offset += 8;
|
||||||
|
});
|
||||||
|
|
||||||
|
// The linker guarantees global data starts from at least wasmMinDataAddr.
|
||||||
|
// Keep in sync with cmd/link/internal/ld/data.go:wasmMinDataAddr.
|
||||||
|
const wasmMinDataAddr = 4096 + 8192;
|
||||||
|
if (offset >= wasmMinDataAddr) {
|
||||||
|
throw new Error("total length of command line and environment variables exceeds limit");
|
||||||
|
}
|
||||||
|
|
||||||
|
this._inst.exports.run(argc, argv);
|
||||||
|
if (this.exited) {
|
||||||
|
this._resolveExitPromise();
|
||||||
|
}
|
||||||
|
await this._exitPromise;
|
||||||
|
}
|
||||||
|
|
||||||
|
_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;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})();
|
||||||
32
frontend/src/common/prettier/plugins/go/build.bat
Normal file
32
frontend/src/common/prettier/plugins/go/build.bat
Normal file
@@ -0,0 +1,32 @@
|
|||||||
|
@echo off
|
||||||
|
rem Build script for Go Prettier Plugin WASM
|
||||||
|
rem This script compiles the Go code to WebAssembly
|
||||||
|
|
||||||
|
echo 🔨 Building Go Prettier Plugin WASM...
|
||||||
|
|
||||||
|
rem Set WASM build environment
|
||||||
|
set GOOS=js
|
||||||
|
set GOARCH=wasm
|
||||||
|
|
||||||
|
rem Build the WASM file
|
||||||
|
echo Compiling main.go to go.wasm...
|
||||||
|
go build -o go.wasm main.go
|
||||||
|
|
||||||
|
if %ERRORLEVEL% EQU 0 (
|
||||||
|
echo ✅ Build successful!
|
||||||
|
|
||||||
|
rem Show file size (Windows version)
|
||||||
|
for %%A in (go.wasm) do echo 📊 WASM file size: %%~zA bytes
|
||||||
|
|
||||||
|
rem Copy to public directory for browser access
|
||||||
|
if exist "..\..\..\..\..\public" (
|
||||||
|
copy go.wasm ..\..\..\..\..\public\go.wasm > nul
|
||||||
|
echo 📋 Copied to public directory
|
||||||
|
)
|
||||||
|
|
||||||
|
echo 🎉 Go Prettier Plugin WASM is ready!
|
||||||
|
) else (
|
||||||
|
echo ❌ Build failed!
|
||||||
|
pause
|
||||||
|
exit /b 1
|
||||||
|
)
|
||||||
30
frontend/src/common/prettier/plugins/go/build.sh
Normal file
30
frontend/src/common/prettier/plugins/go/build.sh
Normal file
@@ -0,0 +1,30 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
# Build script for Go Prettier Plugin WASM
|
||||||
|
# This script compiles the Go code to WebAssembly
|
||||||
|
|
||||||
|
echo "🔨 Building Go Prettier Plugin WASM..."
|
||||||
|
|
||||||
|
# Set WASM build environment
|
||||||
|
export GOOS=js
|
||||||
|
export GOARCH=wasm
|
||||||
|
|
||||||
|
# Build the WASM file
|
||||||
|
echo "Compiling main.go to go.wasm..."
|
||||||
|
go build -o go.wasm main.go
|
||||||
|
|
||||||
|
if [ $? -eq 0 ]; then
|
||||||
|
echo "✅ Build successful!"
|
||||||
|
echo "📊 WASM file size: $(du -h go.wasm | cut -f1)"
|
||||||
|
|
||||||
|
# Copy to public directory for browser access
|
||||||
|
if [ -d "../../../../../public" ]; then
|
||||||
|
cp go.wasm ../../../../../public/go.wasm
|
||||||
|
echo "📋 Copied to public directory"
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "🎉 Go Prettier Plugin WASM is ready!"
|
||||||
|
else
|
||||||
|
echo "❌ Build failed!"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
10
frontend/src/common/prettier/plugins/go/go.d.ts
vendored
Normal file
10
frontend/src/common/prettier/plugins/go/go.d.ts
vendored
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
import { Parser, Plugin } from "prettier";
|
||||||
|
|
||||||
|
export declare const languages: Plugin["languages"];
|
||||||
|
export declare const parsers: {
|
||||||
|
go: Parser;
|
||||||
|
};
|
||||||
|
export declare const printers: Plugin["printers"];
|
||||||
|
|
||||||
|
declare const plugin: Plugin;
|
||||||
|
export default plugin;
|
||||||
244
frontend/src/common/prettier/plugins/go/go.mjs
Normal file
244
frontend/src/common/prettier/plugins/go/go.mjs
Normal file
@@ -0,0 +1,244 @@
|
|||||||
|
/**
|
||||||
|
* Go Prettier Plugin - Universal Implementation
|
||||||
|
* WebAssembly-based Go code formatter for Prettier
|
||||||
|
* Supports both Node.js and Browser environments
|
||||||
|
*/
|
||||||
|
|
||||||
|
let initializePromise = null;
|
||||||
|
|
||||||
|
// Environment detection
|
||||||
|
const isNode = () => {
|
||||||
|
return typeof process !== 'undefined' &&
|
||||||
|
process.versions != null &&
|
||||||
|
process.versions.node != null;
|
||||||
|
};
|
||||||
|
|
||||||
|
const isBrowser = () => {
|
||||||
|
return typeof window !== 'undefined' &&
|
||||||
|
typeof document !== 'undefined';
|
||||||
|
};
|
||||||
|
|
||||||
|
// Node.js WASM loading
|
||||||
|
const loadWasmNode = async () => {
|
||||||
|
try {
|
||||||
|
const fs = await import('fs');
|
||||||
|
const path = await import('path');
|
||||||
|
const { fileURLToPath } = await import('url');
|
||||||
|
|
||||||
|
const __filename = fileURLToPath(import.meta.url);
|
||||||
|
const __dirname = path.dirname(__filename);
|
||||||
|
const wasmPath = path.join(__dirname, 'go.wasm');
|
||||||
|
|
||||||
|
return fs.readFileSync(wasmPath);
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Node.js WASM loading failed:', error);
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Browser WASM loading
|
||||||
|
const loadWasmBrowser = async () => {
|
||||||
|
try {
|
||||||
|
const response = await fetch('/go.wasm');
|
||||||
|
if (!response.ok) {
|
||||||
|
throw new Error(`Failed to load WASM file: ${response.status} ${response.statusText}`);
|
||||||
|
}
|
||||||
|
return await response.arrayBuffer();
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Browser WASM loading failed:', error);
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Node.js Go runtime initialization
|
||||||
|
const initGoRuntimeNode = async () => {
|
||||||
|
if (globalThis.Go) return;
|
||||||
|
|
||||||
|
try {
|
||||||
|
// Dynamic import of wasm_exec.js for Node.js
|
||||||
|
const { createRequire } = await import('module');
|
||||||
|
const require = createRequire(import.meta.url);
|
||||||
|
const path = await import('path');
|
||||||
|
const { fileURLToPath } = await import('url');
|
||||||
|
|
||||||
|
const __filename = fileURLToPath(import.meta.url);
|
||||||
|
const __dirname = path.dirname(__filename);
|
||||||
|
|
||||||
|
// Load wasm_exec.js
|
||||||
|
const wasmExecPath = path.join(__dirname, 'wasm_exec.js');
|
||||||
|
require(wasmExecPath);
|
||||||
|
|
||||||
|
if (!globalThis.Go) {
|
||||||
|
throw new Error('Go WASM runtime not available after loading wasm_exec.js');
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Node.js Go runtime initialization failed:', error);
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Browser Go runtime initialization
|
||||||
|
const initGoRuntimeBrowser = async () => {
|
||||||
|
// 总是重新初始化,因为可能存在版本不兼容问题
|
||||||
|
try {
|
||||||
|
// 移除旧的 Go 运行时
|
||||||
|
delete globalThis.Go;
|
||||||
|
|
||||||
|
// 动态导入本地的 wasm_exec.js 内容
|
||||||
|
const wasmExecResponse = await fetch('/wasm_exec.js');
|
||||||
|
if (!wasmExecResponse.ok) {
|
||||||
|
throw new Error(`Failed to fetch wasm_exec.js: ${wasmExecResponse.status}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
const wasmExecCode = await wasmExecResponse.text();
|
||||||
|
|
||||||
|
// 在全局作用域中执行 wasm_exec.js 代码
|
||||||
|
const script = document.createElement('script');
|
||||||
|
script.textContent = wasmExecCode;
|
||||||
|
document.head.appendChild(script);
|
||||||
|
|
||||||
|
// 等待一小段时间确保脚本执行完成
|
||||||
|
await new Promise(resolve => setTimeout(resolve, 100));
|
||||||
|
|
||||||
|
if (!globalThis.Go) {
|
||||||
|
throw new Error('Go WASM runtime not available after executing wasm_exec.js');
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log('Go runtime initialized successfully');
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Browser Go runtime initialization failed:', error);
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Universal initialization
|
||||||
|
const initialize = async () => {
|
||||||
|
if (initializePromise) return initializePromise;
|
||||||
|
|
||||||
|
initializePromise = (async () => {
|
||||||
|
let wasmBuffer;
|
||||||
|
|
||||||
|
console.log('Starting Go WASM initialization...');
|
||||||
|
|
||||||
|
// Environment-specific initialization
|
||||||
|
if (isNode()) {
|
||||||
|
console.log('Initializing for Node.js environment');
|
||||||
|
await initGoRuntimeNode();
|
||||||
|
wasmBuffer = await loadWasmNode();
|
||||||
|
} else if (isBrowser()) {
|
||||||
|
console.log('Initializing for Browser environment');
|
||||||
|
await initGoRuntimeBrowser();
|
||||||
|
wasmBuffer = await loadWasmBrowser();
|
||||||
|
} else {
|
||||||
|
throw new Error('Unsupported environment: neither Node.js nor Browser detected');
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log('Creating Go instance...');
|
||||||
|
const go = new globalThis.Go();
|
||||||
|
|
||||||
|
// 详细检查 importObject
|
||||||
|
console.log('Go import object keys:', Object.keys(go.importObject));
|
||||||
|
if (go.importObject.gojs) {
|
||||||
|
console.log('gojs import keys:', Object.keys(go.importObject.gojs));
|
||||||
|
console.log('scheduleTimeoutEvent type:', typeof go.importObject.gojs['runtime.scheduleTimeoutEvent']);
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log('Instantiating WebAssembly module...');
|
||||||
|
|
||||||
|
try {
|
||||||
|
const { instance } = await WebAssembly.instantiate(wasmBuffer, go.importObject);
|
||||||
|
console.log('WebAssembly instantiation successful');
|
||||||
|
|
||||||
|
console.log('Running Go program...');
|
||||||
|
// Run Go program (don't await as it's a long-running service)
|
||||||
|
go.run(instance).catch(err => {
|
||||||
|
console.error('Go WASM program exit error:', err);
|
||||||
|
});
|
||||||
|
} catch (instantiateError) {
|
||||||
|
console.error('WebAssembly instantiation failed:', instantiateError);
|
||||||
|
console.error('Error details:', {
|
||||||
|
message: instantiateError.message,
|
||||||
|
name: instantiateError.name,
|
||||||
|
stack: instantiateError.stack
|
||||||
|
});
|
||||||
|
throw instantiateError;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Wait for Go program to initialize and expose formatGo function
|
||||||
|
console.log('Waiting for formatGo function to be available...');
|
||||||
|
let retries = 0;
|
||||||
|
const maxRetries = 20; // 增加重试次数
|
||||||
|
|
||||||
|
while (typeof globalThis.formatGo !== 'function' && retries < maxRetries) {
|
||||||
|
await new Promise(resolve => setTimeout(resolve, 200)); // 增加等待时间
|
||||||
|
retries++;
|
||||||
|
if (retries % 5 === 0) {
|
||||||
|
console.log(`Waiting for formatGo function... (${retries}/${maxRetries})`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (typeof globalThis.formatGo !== 'function') {
|
||||||
|
throw new Error('Go WASM module not properly initialized - formatGo function not available after 20 retries');
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log('Go WASM initialization completed successfully');
|
||||||
|
})();
|
||||||
|
|
||||||
|
return initializePromise;
|
||||||
|
};
|
||||||
|
|
||||||
|
export const languages = [
|
||||||
|
{
|
||||||
|
name: "Go",
|
||||||
|
parsers: ["go-format"],
|
||||||
|
extensions: [".go"],
|
||||||
|
vscodeLanguageIds: ["go"],
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
export const parsers = {
|
||||||
|
"go-format": {
|
||||||
|
parse: (text) => text,
|
||||||
|
astFormat: "go-format",
|
||||||
|
locStart: (node) => 0,
|
||||||
|
locEnd: (node) => node.length,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
export const printers = {
|
||||||
|
"go-format": {
|
||||||
|
print: (path) => {
|
||||||
|
const text = path.getValue();
|
||||||
|
|
||||||
|
if (typeof globalThis.formatGo !== 'function') {
|
||||||
|
// 如果 formatGo 函数不可用,尝试初始化
|
||||||
|
initialize().then(() => {
|
||||||
|
// 初始化完成后,formatGo 应该可用
|
||||||
|
}).catch(err => {
|
||||||
|
console.error('Go WASM initialization failed:', err);
|
||||||
|
});
|
||||||
|
|
||||||
|
// 如果还是不可用,返回原始文本
|
||||||
|
return text;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
return globalThis.formatGo(text);
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Go formatting failed:', error);
|
||||||
|
// 返回原始文本而不是抛出错误
|
||||||
|
return text;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
// Export initialize function for manual initialization
|
||||||
|
export { initialize };
|
||||||
|
|
||||||
|
// Default export for Prettier plugin compatibility
|
||||||
|
export default {
|
||||||
|
languages,
|
||||||
|
parsers,
|
||||||
|
printers
|
||||||
|
};
|
||||||
BIN
frontend/src/common/prettier/plugins/go/go.wasm
Normal file
BIN
frontend/src/common/prettier/plugins/go/go.wasm
Normal file
Binary file not shown.
66
frontend/src/common/prettier/plugins/go/main.go
Normal file
66
frontend/src/common/prettier/plugins/go/main.go
Normal file
@@ -0,0 +1,66 @@
|
|||||||
|
//go:build js && wasm
|
||||||
|
|
||||||
|
// Package main implements a WebAssembly module that provides Go code formatting
|
||||||
|
// functionality for the Prettier plugin. This package exposes the formatGo function
|
||||||
|
// to JavaScript, enabling web-based Go code formatting using Go's built-in format package.
|
||||||
|
//
|
||||||
|
// The module is designed to be compiled to WebAssembly and loaded in Node.js
|
||||||
|
// environments as part of the go-prettier-format plugin.
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"go/format"
|
||||||
|
"syscall/js"
|
||||||
|
)
|
||||||
|
|
||||||
|
// formatGo is a JavaScript-callable function that formats Go source code.
|
||||||
|
// It wraps the standard library's go/format.Source function to be accessible
|
||||||
|
// from JavaScript environments through WebAssembly.
|
||||||
|
//
|
||||||
|
// Parameters:
|
||||||
|
// - this: The JavaScript 'this' context (unused)
|
||||||
|
// - i: JavaScript arguments array where i[0] should contain the Go source code as a string
|
||||||
|
//
|
||||||
|
// Returns:
|
||||||
|
// - js.Value: The formatted Go source code as a JavaScript string value
|
||||||
|
// - If formatting fails due to syntax errors, returns the original code unchanged
|
||||||
|
// - If no arguments are provided, returns js.Null() and logs an error
|
||||||
|
//
|
||||||
|
// The function handles syntax errors gracefully by returning the original code
|
||||||
|
// and logging error details to the JavaScript console for debugging purposes.
|
||||||
|
func formatGo(this js.Value, i []js.Value) interface{} {
|
||||||
|
if len(i) == 0 {
|
||||||
|
js.Global().Get("console").Call("error", "formatGo: missing code argument")
|
||||||
|
return js.Null()
|
||||||
|
}
|
||||||
|
code := i[0].String()
|
||||||
|
formatted, err := format.Source([]byte(code))
|
||||||
|
if err != nil {
|
||||||
|
// In case of a syntax error in the Go code, go/format returns an error.
|
||||||
|
// Prettier expects the original text to be returned in case of an error.
|
||||||
|
// We also log the error to the console for debugging purposes.
|
||||||
|
js.Global().Get("console").Call("error", "Error formatting Go code:", err.Error())
|
||||||
|
return js.ValueOf(code)
|
||||||
|
}
|
||||||
|
return js.ValueOf(string(formatted))
|
||||||
|
}
|
||||||
|
|
||||||
|
// main initializes the WebAssembly module and exposes the formatGo function
|
||||||
|
// to the JavaScript global scope. The function sets up a blocking channel
|
||||||
|
// to prevent the WASM module from exiting, allowing it to serve as a
|
||||||
|
// long-running service for formatting operations.
|
||||||
|
//
|
||||||
|
// The exposed formatGo function can be called from JavaScript as:
|
||||||
|
//
|
||||||
|
// global.formatGo(sourceCode)
|
||||||
|
func main() {
|
||||||
|
// Create a channel to keep the Go program running.
|
||||||
|
// This is necessary because the WASM module would exit otherwise.
|
||||||
|
c := make(chan struct{}, 0)
|
||||||
|
|
||||||
|
// Expose the formatGo function to the JavaScript global scope.
|
||||||
|
js.Global().Set("formatGo", js.FuncOf(formatGo))
|
||||||
|
|
||||||
|
// Block forever
|
||||||
|
<-c
|
||||||
|
}
|
||||||
561
frontend/src/common/prettier/plugins/go/wasm_exec.js
Normal file
561
frontend/src/common/prettier/plugins/go/wasm_exec.js
Normal file
@@ -0,0 +1,561 @@
|
|||||||
|
// 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.
|
||||||
|
|
||||||
|
"use strict";
|
||||||
|
|
||||||
|
(() => {
|
||||||
|
const enosys = () => {
|
||||||
|
const err = new Error("not implemented");
|
||||||
|
err.code = "ENOSYS";
|
||||||
|
return err;
|
||||||
|
};
|
||||||
|
|
||||||
|
if (!globalThis.fs) {
|
||||||
|
let outputBuf = "";
|
||||||
|
globalThis.fs = {
|
||||||
|
constants: { O_WRONLY: -1, O_RDWR: -1, O_CREAT: -1, O_TRUNC: -1, O_APPEND: -1, O_EXCL: -1 }, // unused
|
||||||
|
writeSync(fd, buf) {
|
||||||
|
outputBuf += decoder.decode(buf);
|
||||||
|
const nl = outputBuf.lastIndexOf("\n");
|
||||||
|
if (nl != -1) {
|
||||||
|
console.log(outputBuf.substring(0, nl));
|
||||||
|
outputBuf = outputBuf.substring(nl + 1);
|
||||||
|
}
|
||||||
|
return buf.length;
|
||||||
|
},
|
||||||
|
write(fd, buf, offset, length, position, callback) {
|
||||||
|
if (offset !== 0 || length !== buf.length || position !== null) {
|
||||||
|
callback(enosys());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const n = this.writeSync(fd, buf);
|
||||||
|
callback(null, n);
|
||||||
|
},
|
||||||
|
chmod(path, mode, callback) { callback(enosys()); },
|
||||||
|
chown(path, uid, gid, callback) { callback(enosys()); },
|
||||||
|
close(fd, callback) { callback(enosys()); },
|
||||||
|
fchmod(fd, mode, callback) { callback(enosys()); },
|
||||||
|
fchown(fd, uid, gid, callback) { callback(enosys()); },
|
||||||
|
fstat(fd, callback) { callback(enosys()); },
|
||||||
|
fsync(fd, callback) { callback(null); },
|
||||||
|
ftruncate(fd, length, callback) { callback(enosys()); },
|
||||||
|
lchown(path, uid, gid, callback) { callback(enosys()); },
|
||||||
|
link(path, link, callback) { callback(enosys()); },
|
||||||
|
lstat(path, callback) { callback(enosys()); },
|
||||||
|
mkdir(path, perm, callback) { callback(enosys()); },
|
||||||
|
open(path, flags, mode, callback) { callback(enosys()); },
|
||||||
|
read(fd, buffer, offset, length, position, callback) { callback(enosys()); },
|
||||||
|
readdir(path, callback) { callback(enosys()); },
|
||||||
|
readlink(path, callback) { callback(enosys()); },
|
||||||
|
rename(from, to, callback) { callback(enosys()); },
|
||||||
|
rmdir(path, callback) { callback(enosys()); },
|
||||||
|
stat(path, callback) { callback(enosys()); },
|
||||||
|
symlink(path, link, callback) { callback(enosys()); },
|
||||||
|
truncate(path, length, callback) { callback(enosys()); },
|
||||||
|
unlink(path, callback) { callback(enosys()); },
|
||||||
|
utimes(path, atime, mtime, callback) { callback(enosys()); },
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!globalThis.process) {
|
||||||
|
globalThis.process = {
|
||||||
|
getuid() { return -1; },
|
||||||
|
getgid() { return -1; },
|
||||||
|
geteuid() { return -1; },
|
||||||
|
getegid() { return -1; },
|
||||||
|
getgroups() { throw enosys(); },
|
||||||
|
pid: -1,
|
||||||
|
ppid: -1,
|
||||||
|
umask() { throw enosys(); },
|
||||||
|
cwd() { throw enosys(); },
|
||||||
|
chdir() { throw enosys(); },
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!globalThis.crypto) {
|
||||||
|
throw new Error("globalThis.crypto is not available, polyfill required (crypto.getRandomValues only)");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!globalThis.performance) {
|
||||||
|
throw new Error("globalThis.performance is not available, polyfill required (performance.now only)");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!globalThis.TextEncoder) {
|
||||||
|
throw new Error("globalThis.TextEncoder is not available, polyfill required");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!globalThis.TextDecoder) {
|
||||||
|
throw new Error("globalThis.TextDecoder is not available, polyfill required");
|
||||||
|
}
|
||||||
|
|
||||||
|
const encoder = new TextEncoder("utf-8");
|
||||||
|
const decoder = new TextDecoder("utf-8");
|
||||||
|
|
||||||
|
globalThis.Go = class {
|
||||||
|
constructor() {
|
||||||
|
this.argv = ["js"];
|
||||||
|
this.env = {};
|
||||||
|
this.exit = (code) => {
|
||||||
|
if (code !== 0) {
|
||||||
|
console.warn("exit code:", code);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
this._exitPromise = new Promise((resolve) => {
|
||||||
|
this._resolveExitPromise = resolve;
|
||||||
|
});
|
||||||
|
this._pendingEvent = null;
|
||||||
|
this._scheduledTimeouts = new Map();
|
||||||
|
this._nextCallbackTimeoutID = 1;
|
||||||
|
|
||||||
|
const setInt64 = (addr, v) => {
|
||||||
|
this.mem.setUint32(addr + 0, v, true);
|
||||||
|
this.mem.setUint32(addr + 4, Math.floor(v / 4294967296), true);
|
||||||
|
}
|
||||||
|
|
||||||
|
const setInt32 = (addr, v) => {
|
||||||
|
this.mem.setUint32(addr + 0, v, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
const getInt64 = (addr) => {
|
||||||
|
const low = this.mem.getUint32(addr + 0, true);
|
||||||
|
const high = this.mem.getInt32(addr + 4, true);
|
||||||
|
return low + high * 4294967296;
|
||||||
|
}
|
||||||
|
|
||||||
|
const loadValue = (addr) => {
|
||||||
|
const f = this.mem.getFloat64(addr, true);
|
||||||
|
if (f === 0) {
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
if (!isNaN(f)) {
|
||||||
|
return f;
|
||||||
|
}
|
||||||
|
|
||||||
|
const id = this.mem.getUint32(addr, true);
|
||||||
|
return this._values[id];
|
||||||
|
}
|
||||||
|
|
||||||
|
const storeValue = (addr, v) => {
|
||||||
|
const nanHead = 0x7FF80000;
|
||||||
|
|
||||||
|
if (typeof v === "number" && v !== 0) {
|
||||||
|
if (isNaN(v)) {
|
||||||
|
this.mem.setUint32(addr + 4, nanHead, true);
|
||||||
|
this.mem.setUint32(addr, 0, true);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
this.mem.setFloat64(addr, v, true);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (v === undefined) {
|
||||||
|
this.mem.setFloat64(addr, 0, true);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
let id = this._ids.get(v);
|
||||||
|
if (id === undefined) {
|
||||||
|
id = this._idPool.pop();
|
||||||
|
if (id === undefined) {
|
||||||
|
id = this._values.length;
|
||||||
|
}
|
||||||
|
this._values[id] = v;
|
||||||
|
this._goRefCounts[id] = 0;
|
||||||
|
this._ids.set(v, id);
|
||||||
|
}
|
||||||
|
this._goRefCounts[id]++;
|
||||||
|
let typeFlag = 0;
|
||||||
|
switch (typeof v) {
|
||||||
|
case "object":
|
||||||
|
if (v !== null) {
|
||||||
|
typeFlag = 1;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case "string":
|
||||||
|
typeFlag = 2;
|
||||||
|
break;
|
||||||
|
case "symbol":
|
||||||
|
typeFlag = 3;
|
||||||
|
break;
|
||||||
|
case "function":
|
||||||
|
typeFlag = 4;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
this.mem.setUint32(addr + 4, nanHead | typeFlag, true);
|
||||||
|
this.mem.setUint32(addr, id, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
const loadSlice = (addr) => {
|
||||||
|
const array = getInt64(addr + 0);
|
||||||
|
const len = getInt64(addr + 8);
|
||||||
|
return new Uint8Array(this._inst.exports.mem.buffer, array, len);
|
||||||
|
}
|
||||||
|
|
||||||
|
const loadSliceOfValues = (addr) => {
|
||||||
|
const array = getInt64(addr + 0);
|
||||||
|
const len = getInt64(addr + 8);
|
||||||
|
const a = new Array(len);
|
||||||
|
for (let i = 0; i < len; i++) {
|
||||||
|
a[i] = loadValue(array + i * 8);
|
||||||
|
}
|
||||||
|
return a;
|
||||||
|
}
|
||||||
|
|
||||||
|
const loadString = (addr) => {
|
||||||
|
const saddr = getInt64(addr + 0);
|
||||||
|
const len = getInt64(addr + 8);
|
||||||
|
return decoder.decode(new DataView(this._inst.exports.mem.buffer, saddr, len));
|
||||||
|
}
|
||||||
|
|
||||||
|
const timeOrigin = Date.now() - performance.now();
|
||||||
|
this.importObject = {
|
||||||
|
_gotest: {
|
||||||
|
add: (a, b) => a + b,
|
||||||
|
},
|
||||||
|
gojs: {
|
||||||
|
// Go's SP does not change as long as no Go code is running. Some operations (e.g. calls, getters and setters)
|
||||||
|
// may synchronously trigger a Go event handler. This makes Go code get executed in the middle of the imported
|
||||||
|
// function. A goroutine can switch to a new stack if the current stack is too small (see morestack function).
|
||||||
|
// This changes the SP, thus we have to update the SP used by the imported function.
|
||||||
|
|
||||||
|
// func wasmExit(code int32)
|
||||||
|
"runtime.wasmExit": (sp) => {
|
||||||
|
sp >>>= 0;
|
||||||
|
const code = this.mem.getInt32(sp + 8, true);
|
||||||
|
this.exited = true;
|
||||||
|
delete this._inst;
|
||||||
|
delete this._values;
|
||||||
|
delete this._goRefCounts;
|
||||||
|
delete this._ids;
|
||||||
|
delete this._idPool;
|
||||||
|
this.exit(code);
|
||||||
|
},
|
||||||
|
|
||||||
|
// func wasmWrite(fd uintptr, p unsafe.Pointer, n int32)
|
||||||
|
"runtime.wasmWrite": (sp) => {
|
||||||
|
sp >>>= 0;
|
||||||
|
const fd = getInt64(sp + 8);
|
||||||
|
const p = getInt64(sp + 16);
|
||||||
|
const n = this.mem.getInt32(sp + 24, true);
|
||||||
|
fs.writeSync(fd, new Uint8Array(this._inst.exports.mem.buffer, p, n));
|
||||||
|
},
|
||||||
|
|
||||||
|
// func resetMemoryDataView()
|
||||||
|
"runtime.resetMemoryDataView": (sp) => {
|
||||||
|
sp >>>= 0;
|
||||||
|
this.mem = new DataView(this._inst.exports.mem.buffer);
|
||||||
|
},
|
||||||
|
|
||||||
|
// func nanotime1() int64
|
||||||
|
"runtime.nanotime1": (sp) => {
|
||||||
|
sp >>>= 0;
|
||||||
|
setInt64(sp + 8, (timeOrigin + performance.now()) * 1000000);
|
||||||
|
},
|
||||||
|
|
||||||
|
// func walltime() (sec int64, nsec int32)
|
||||||
|
"runtime.walltime": (sp) => {
|
||||||
|
sp >>>= 0;
|
||||||
|
const msec = (new Date).getTime();
|
||||||
|
setInt64(sp + 8, msec / 1000);
|
||||||
|
this.mem.setInt32(sp + 16, (msec % 1000) * 1000000, true);
|
||||||
|
},
|
||||||
|
|
||||||
|
// func scheduleTimeoutEvent(delay int64) int32
|
||||||
|
"runtime.scheduleTimeoutEvent": (sp) => {
|
||||||
|
sp >>>= 0;
|
||||||
|
const id = this._nextCallbackTimeoutID;
|
||||||
|
this._nextCallbackTimeoutID++;
|
||||||
|
this._scheduledTimeouts.set(id, setTimeout(
|
||||||
|
() => {
|
||||||
|
this._resume();
|
||||||
|
while (this._scheduledTimeouts.has(id)) {
|
||||||
|
// for some reason Go failed to register the timeout event, log and try again
|
||||||
|
// (temporary workaround for https://github.com/golang/go/issues/28975)
|
||||||
|
console.warn("scheduleTimeoutEvent: missed timeout event");
|
||||||
|
this._resume();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
getInt64(sp + 8),
|
||||||
|
));
|
||||||
|
this.mem.setInt32(sp + 16, id, true);
|
||||||
|
},
|
||||||
|
|
||||||
|
// func clearTimeoutEvent(id int32)
|
||||||
|
"runtime.clearTimeoutEvent": (sp) => {
|
||||||
|
sp >>>= 0;
|
||||||
|
const id = this.mem.getInt32(sp + 8, true);
|
||||||
|
clearTimeout(this._scheduledTimeouts.get(id));
|
||||||
|
this._scheduledTimeouts.delete(id);
|
||||||
|
},
|
||||||
|
|
||||||
|
// func getRandomData(r []byte)
|
||||||
|
"runtime.getRandomData": (sp) => {
|
||||||
|
sp >>>= 0;
|
||||||
|
crypto.getRandomValues(loadSlice(sp + 8));
|
||||||
|
},
|
||||||
|
|
||||||
|
// func finalizeRef(v ref)
|
||||||
|
"syscall/js.finalizeRef": (sp) => {
|
||||||
|
sp >>>= 0;
|
||||||
|
const id = this.mem.getUint32(sp + 8, true);
|
||||||
|
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": (sp) => {
|
||||||
|
sp >>>= 0;
|
||||||
|
storeValue(sp + 24, loadString(sp + 8));
|
||||||
|
},
|
||||||
|
|
||||||
|
// func valueGet(v ref, p string) ref
|
||||||
|
"syscall/js.valueGet": (sp) => {
|
||||||
|
sp >>>= 0;
|
||||||
|
const result = Reflect.get(loadValue(sp + 8), loadString(sp + 16));
|
||||||
|
sp = this._inst.exports.getsp() >>> 0; // see comment above
|
||||||
|
storeValue(sp + 32, result);
|
||||||
|
},
|
||||||
|
|
||||||
|
// func valueSet(v ref, p string, x ref)
|
||||||
|
"syscall/js.valueSet": (sp) => {
|
||||||
|
sp >>>= 0;
|
||||||
|
Reflect.set(loadValue(sp + 8), loadString(sp + 16), loadValue(sp + 32));
|
||||||
|
},
|
||||||
|
|
||||||
|
// func valueDelete(v ref, p string)
|
||||||
|
"syscall/js.valueDelete": (sp) => {
|
||||||
|
sp >>>= 0;
|
||||||
|
Reflect.deleteProperty(loadValue(sp + 8), loadString(sp + 16));
|
||||||
|
},
|
||||||
|
|
||||||
|
// func valueIndex(v ref, i int) ref
|
||||||
|
"syscall/js.valueIndex": (sp) => {
|
||||||
|
sp >>>= 0;
|
||||||
|
storeValue(sp + 24, Reflect.get(loadValue(sp + 8), getInt64(sp + 16)));
|
||||||
|
},
|
||||||
|
|
||||||
|
// valueSetIndex(v ref, i int, x ref)
|
||||||
|
"syscall/js.valueSetIndex": (sp) => {
|
||||||
|
sp >>>= 0;
|
||||||
|
Reflect.set(loadValue(sp + 8), getInt64(sp + 16), loadValue(sp + 24));
|
||||||
|
},
|
||||||
|
|
||||||
|
// func valueCall(v ref, m string, args []ref) (ref, bool)
|
||||||
|
"syscall/js.valueCall": (sp) => {
|
||||||
|
sp >>>= 0;
|
||||||
|
try {
|
||||||
|
const v = loadValue(sp + 8);
|
||||||
|
const m = Reflect.get(v, loadString(sp + 16));
|
||||||
|
const args = loadSliceOfValues(sp + 32);
|
||||||
|
const result = Reflect.apply(m, v, args);
|
||||||
|
sp = this._inst.exports.getsp() >>> 0; // see comment above
|
||||||
|
storeValue(sp + 56, result);
|
||||||
|
this.mem.setUint8(sp + 64, 1);
|
||||||
|
} catch (err) {
|
||||||
|
sp = this._inst.exports.getsp() >>> 0; // see comment above
|
||||||
|
storeValue(sp + 56, err);
|
||||||
|
this.mem.setUint8(sp + 64, 0);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
// func valueInvoke(v ref, args []ref) (ref, bool)
|
||||||
|
"syscall/js.valueInvoke": (sp) => {
|
||||||
|
sp >>>= 0;
|
||||||
|
try {
|
||||||
|
const v = loadValue(sp + 8);
|
||||||
|
const args = loadSliceOfValues(sp + 16);
|
||||||
|
const result = Reflect.apply(v, undefined, args);
|
||||||
|
sp = this._inst.exports.getsp() >>> 0; // see comment above
|
||||||
|
storeValue(sp + 40, result);
|
||||||
|
this.mem.setUint8(sp + 48, 1);
|
||||||
|
} catch (err) {
|
||||||
|
sp = this._inst.exports.getsp() >>> 0; // see comment above
|
||||||
|
storeValue(sp + 40, err);
|
||||||
|
this.mem.setUint8(sp + 48, 0);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
// func valueNew(v ref, args []ref) (ref, bool)
|
||||||
|
"syscall/js.valueNew": (sp) => {
|
||||||
|
sp >>>= 0;
|
||||||
|
try {
|
||||||
|
const v = loadValue(sp + 8);
|
||||||
|
const args = loadSliceOfValues(sp + 16);
|
||||||
|
const result = Reflect.construct(v, args);
|
||||||
|
sp = this._inst.exports.getsp() >>> 0; // see comment above
|
||||||
|
storeValue(sp + 40, result);
|
||||||
|
this.mem.setUint8(sp + 48, 1);
|
||||||
|
} catch (err) {
|
||||||
|
sp = this._inst.exports.getsp() >>> 0; // see comment above
|
||||||
|
storeValue(sp + 40, err);
|
||||||
|
this.mem.setUint8(sp + 48, 0);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
// func valueLength(v ref) int
|
||||||
|
"syscall/js.valueLength": (sp) => {
|
||||||
|
sp >>>= 0;
|
||||||
|
setInt64(sp + 16, parseInt(loadValue(sp + 8).length));
|
||||||
|
},
|
||||||
|
|
||||||
|
// valuePrepareString(v ref) (ref, int)
|
||||||
|
"syscall/js.valuePrepareString": (sp) => {
|
||||||
|
sp >>>= 0;
|
||||||
|
const str = encoder.encode(String(loadValue(sp + 8)));
|
||||||
|
storeValue(sp + 16, str);
|
||||||
|
setInt64(sp + 24, str.length);
|
||||||
|
},
|
||||||
|
|
||||||
|
// valueLoadString(v ref, b []byte)
|
||||||
|
"syscall/js.valueLoadString": (sp) => {
|
||||||
|
sp >>>= 0;
|
||||||
|
const str = loadValue(sp + 8);
|
||||||
|
loadSlice(sp + 16).set(str);
|
||||||
|
},
|
||||||
|
|
||||||
|
// func valueInstanceOf(v ref, t ref) bool
|
||||||
|
"syscall/js.valueInstanceOf": (sp) => {
|
||||||
|
sp >>>= 0;
|
||||||
|
this.mem.setUint8(sp + 24, (loadValue(sp + 8) instanceof loadValue(sp + 16)) ? 1 : 0);
|
||||||
|
},
|
||||||
|
|
||||||
|
// func copyBytesToGo(dst []byte, src ref) (int, bool)
|
||||||
|
"syscall/js.copyBytesToGo": (sp) => {
|
||||||
|
sp >>>= 0;
|
||||||
|
const dst = loadSlice(sp + 8);
|
||||||
|
const src = loadValue(sp + 32);
|
||||||
|
if (!(src instanceof Uint8Array || src instanceof Uint8ClampedArray)) {
|
||||||
|
this.mem.setUint8(sp + 48, 0);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const toCopy = src.subarray(0, dst.length);
|
||||||
|
dst.set(toCopy);
|
||||||
|
setInt64(sp + 40, toCopy.length);
|
||||||
|
this.mem.setUint8(sp + 48, 1);
|
||||||
|
},
|
||||||
|
|
||||||
|
// func copyBytesToJS(dst ref, src []byte) (int, bool)
|
||||||
|
"syscall/js.copyBytesToJS": (sp) => {
|
||||||
|
sp >>>= 0;
|
||||||
|
const dst = loadValue(sp + 8);
|
||||||
|
const src = loadSlice(sp + 16);
|
||||||
|
if (!(dst instanceof Uint8Array || dst instanceof Uint8ClampedArray)) {
|
||||||
|
this.mem.setUint8(sp + 48, 0);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const toCopy = src.subarray(0, dst.length);
|
||||||
|
dst.set(toCopy);
|
||||||
|
setInt64(sp + 40, toCopy.length);
|
||||||
|
this.mem.setUint8(sp + 48, 1);
|
||||||
|
},
|
||||||
|
|
||||||
|
"debug": (value) => {
|
||||||
|
console.log(value);
|
||||||
|
},
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
async run(instance) {
|
||||||
|
if (!(instance instanceof WebAssembly.Instance)) {
|
||||||
|
throw new Error("Go.run: WebAssembly.Instance expected");
|
||||||
|
}
|
||||||
|
this._inst = instance;
|
||||||
|
this.mem = new DataView(this._inst.exports.mem.buffer);
|
||||||
|
this._values = [ // JS values that Go currently has references to, indexed by reference id
|
||||||
|
NaN,
|
||||||
|
0,
|
||||||
|
null,
|
||||||
|
true,
|
||||||
|
false,
|
||||||
|
globalThis,
|
||||||
|
this,
|
||||||
|
];
|
||||||
|
this._goRefCounts = new Array(this._values.length).fill(Infinity); // 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
|
||||||
|
[0, 1],
|
||||||
|
[null, 2],
|
||||||
|
[true, 3],
|
||||||
|
[false, 4],
|
||||||
|
[globalThis, 5],
|
||||||
|
[this, 6],
|
||||||
|
]);
|
||||||
|
this._idPool = []; // unused ids that have been garbage collected
|
||||||
|
this.exited = false; // whether the Go program has exited
|
||||||
|
|
||||||
|
// Pass command line arguments and environment variables to WebAssembly by writing them to the linear memory.
|
||||||
|
let offset = 4096;
|
||||||
|
|
||||||
|
const strPtr = (str) => {
|
||||||
|
const ptr = offset;
|
||||||
|
const bytes = encoder.encode(str + "\0");
|
||||||
|
new Uint8Array(this.mem.buffer, offset, bytes.length).set(bytes);
|
||||||
|
offset += bytes.length;
|
||||||
|
if (offset % 8 !== 0) {
|
||||||
|
offset += 8 - (offset % 8);
|
||||||
|
}
|
||||||
|
return ptr;
|
||||||
|
};
|
||||||
|
|
||||||
|
const argc = this.argv.length;
|
||||||
|
|
||||||
|
const argvPtrs = [];
|
||||||
|
this.argv.forEach((arg) => {
|
||||||
|
argvPtrs.push(strPtr(arg));
|
||||||
|
});
|
||||||
|
argvPtrs.push(0);
|
||||||
|
|
||||||
|
const keys = Object.keys(this.env).sort();
|
||||||
|
keys.forEach((key) => {
|
||||||
|
argvPtrs.push(strPtr(`${key}=${this.env[key]}`));
|
||||||
|
});
|
||||||
|
argvPtrs.push(0);
|
||||||
|
|
||||||
|
const argv = offset;
|
||||||
|
argvPtrs.forEach((ptr) => {
|
||||||
|
this.mem.setUint32(offset, ptr, true);
|
||||||
|
this.mem.setUint32(offset + 4, 0, true);
|
||||||
|
offset += 8;
|
||||||
|
});
|
||||||
|
|
||||||
|
// The linker guarantees global data starts from at least wasmMinDataAddr.
|
||||||
|
// Keep in sync with cmd/link/internal/ld/data.go:wasmMinDataAddr.
|
||||||
|
const wasmMinDataAddr = 4096 + 8192;
|
||||||
|
if (offset >= wasmMinDataAddr) {
|
||||||
|
throw new Error("total length of command line and environment variables exceeds limit");
|
||||||
|
}
|
||||||
|
|
||||||
|
this._inst.exports.run(argc, argv);
|
||||||
|
if (this.exited) {
|
||||||
|
this._resolveExitPromise();
|
||||||
|
}
|
||||||
|
await this._exitPromise;
|
||||||
|
}
|
||||||
|
|
||||||
|
_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;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})();
|
||||||
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;
|
||||||
|
}
|
||||||
2
frontend/src/common/prettier/plugins/java/printers/index.d.ts
vendored
Normal file
2
frontend/src/common/prettier/plugins/java/printers/index.d.ts
vendored
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
import type { JavaNodePrinter, JavaNodePrinters } from "./helpers.js";
|
||||||
|
export declare function printerForNodeType<T extends keyof JavaNodePrinters>(type: T): JavaNodePrinter<T>;
|
||||||
13
frontend/src/common/prettier/plugins/java/printers/index.js
Normal file
13
frontend/src/common/prettier/plugins/java/printers/index.js
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
import arrays from "./arrays.js";
|
||||||
|
import blocksAndStatements from "./blocks-and-statements.js";
|
||||||
|
import classes from "./classes.js";
|
||||||
|
import expressions from "./expressions.js";
|
||||||
|
import interfaces from "./interfaces.js";
|
||||||
|
import lexicalStructure from "./lexical-structure.js";
|
||||||
|
import names from "./names.js";
|
||||||
|
import packagesAndModules from "./packages-and-modules.js";
|
||||||
|
import typesValuesAndVariables from "./types-values-and-variables.js";
|
||||||
|
const printersByNodeType = Object.assign(Object.assign(Object.assign(Object.assign(Object.assign(Object.assign(Object.assign(Object.assign(Object.assign({}, arrays), blocksAndStatements), classes), expressions), interfaces), lexicalStructure), names), packagesAndModules), typesValuesAndVariables);
|
||||||
|
export function printerForNodeType(type) {
|
||||||
|
return printersByNodeType[type];
|
||||||
|
}
|
||||||
62
frontend/src/common/prettier/plugins/java/printers/interfaces.d.ts
vendored
Normal file
62
frontend/src/common/prettier/plugins/java/printers/interfaces.d.ts
vendored
Normal file
@@ -0,0 +1,62 @@
|
|||||||
|
import { builders } from "prettier/doc";
|
||||||
|
import { printClassPermits, printSingle } from "./helpers.js";
|
||||||
|
declare const _default: {
|
||||||
|
interfaceDeclaration(path: import("prettier").AstPath<import("java-parser").InterfaceDeclarationCstNode & {
|
||||||
|
comments?: import("../comments.js").JavaComment[];
|
||||||
|
}>, print: import("./helpers.js").JavaPrintFn): builders.Doc[];
|
||||||
|
normalInterfaceDeclaration(path: import("prettier").AstPath<import("java-parser").NormalInterfaceDeclarationCstNode & {
|
||||||
|
comments?: import("../comments.js").JavaComment[];
|
||||||
|
}>, print: import("./helpers.js").JavaPrintFn): builders.Doc[];
|
||||||
|
interfaceModifier: typeof printSingle;
|
||||||
|
interfaceExtends(path: import("prettier").AstPath<import("java-parser").InterfaceExtendsCstNode & {
|
||||||
|
comments?: import("../comments.js").JavaComment[];
|
||||||
|
}>, print: import("./helpers.js").JavaPrintFn): builders.Group;
|
||||||
|
interfacePermits: typeof printClassPermits;
|
||||||
|
interfaceBody(path: import("prettier").AstPath<import("java-parser").InterfaceBodyCstNode & {
|
||||||
|
comments?: import("../comments.js").JavaComment[];
|
||||||
|
}>, print: import("./helpers.js").JavaPrintFn): builders.Group | "{}" | (string | builders.Indent | builders.Hardline)[];
|
||||||
|
interfaceMemberDeclaration(path: import("prettier").AstPath<import("java-parser").InterfaceMemberDeclarationCstNode & {
|
||||||
|
comments?: import("../comments.js").JavaComment[];
|
||||||
|
}>, print: import("./helpers.js").JavaPrintFn): builders.Doc;
|
||||||
|
constantDeclaration(path: import("prettier").AstPath<import("java-parser").ConstantDeclarationCstNode & {
|
||||||
|
comments?: import("../comments.js").JavaComment[];
|
||||||
|
}>, print: import("./helpers.js").JavaPrintFn): builders.Doc[];
|
||||||
|
constantModifier: typeof printSingle;
|
||||||
|
interfaceMethodDeclaration(path: import("prettier").AstPath<import("java-parser").InterfaceMethodDeclarationCstNode & {
|
||||||
|
comments?: import("../comments.js").JavaComment[];
|
||||||
|
}>, print: import("./helpers.js").JavaPrintFn): builders.Doc[];
|
||||||
|
interfaceMethodModifier: typeof printSingle;
|
||||||
|
annotationInterfaceDeclaration(path: import("prettier").AstPath<import("java-parser").AnnotationInterfaceDeclarationCstNode & {
|
||||||
|
comments?: import("../comments.js").JavaComment[];
|
||||||
|
}>, print: import("./helpers.js").JavaPrintFn): builders.Doc[];
|
||||||
|
annotationInterfaceBody(path: import("prettier").AstPath<import("java-parser").AnnotationInterfaceBodyCstNode & {
|
||||||
|
comments?: import("../comments.js").JavaComment[];
|
||||||
|
}>, print: import("./helpers.js").JavaPrintFn): builders.Group | "{}" | (string | builders.Indent | builders.Hardline)[];
|
||||||
|
annotationInterfaceMemberDeclaration(path: import("prettier").AstPath<import("java-parser").AnnotationInterfaceMemberDeclarationCstNode & {
|
||||||
|
comments?: import("../comments.js").JavaComment[];
|
||||||
|
}>, print: import("./helpers.js").JavaPrintFn): builders.Doc;
|
||||||
|
annotationInterfaceElementDeclaration(path: import("prettier").AstPath<import("java-parser").AnnotationInterfaceElementDeclarationCstNode & {
|
||||||
|
comments?: import("../comments.js").JavaComment[];
|
||||||
|
}>, print: import("./helpers.js").JavaPrintFn): builders.Doc[];
|
||||||
|
annotationInterfaceElementModifier: typeof printSingle;
|
||||||
|
defaultValue(path: import("prettier").AstPath<import("java-parser").DefaultValueCstNode & {
|
||||||
|
comments?: import("../comments.js").JavaComment[];
|
||||||
|
}>, print: import("./helpers.js").JavaPrintFn): builders.Doc[];
|
||||||
|
annotation(path: import("prettier").AstPath<import("java-parser").AnnotationCstNode & {
|
||||||
|
comments?: import("../comments.js").JavaComment[];
|
||||||
|
}>, print: import("./helpers.js").JavaPrintFn): builders.Doc[];
|
||||||
|
elementValuePairList(path: import("prettier").AstPath<import("java-parser").ElementValuePairListCstNode & {
|
||||||
|
comments?: import("../comments.js").JavaComment[];
|
||||||
|
}>, print: import("./helpers.js").JavaPrintFn): builders.Doc[];
|
||||||
|
elementValuePair(path: import("prettier").AstPath<import("java-parser").ElementValuePairCstNode & {
|
||||||
|
comments?: import("../comments.js").JavaComment[];
|
||||||
|
}>, print: import("./helpers.js").JavaPrintFn): builders.Doc[];
|
||||||
|
elementValue: typeof printSingle;
|
||||||
|
elementValueArrayInitializer(path: import("prettier").AstPath<import("java-parser").ElementValueArrayInitializerCstNode & {
|
||||||
|
comments?: import("../comments.js").JavaComment[];
|
||||||
|
}>, print: import("./helpers.js").JavaPrintFn, options: import("./helpers.js").JavaParserOptions): builders.Group | "{}";
|
||||||
|
elementValueList(path: import("prettier").AstPath<import("java-parser").ElementValueListCstNode & {
|
||||||
|
comments?: import("../comments.js").JavaComment[];
|
||||||
|
}>, print: import("./helpers.js").JavaPrintFn): builders.Group;
|
||||||
|
};
|
||||||
|
export default _default;
|
||||||
157
frontend/src/common/prettier/plugins/java/printers/interfaces.js
Normal file
157
frontend/src/common/prettier/plugins/java/printers/interfaces.js
Normal file
@@ -0,0 +1,157 @@
|
|||||||
|
import { builders } from "prettier/doc";
|
||||||
|
import { call, each, hasDeclarationAnnotations, indentInParentheses, lineEndWithComments, lineStartWithComments, onlyDefinedKey, printArrayInitializer, printBlock, printClassPermits, printList, printSingle, printWithModifiers } from "./helpers.js";
|
||||||
|
const { group, hardline, indent, join, line } = builders;
|
||||||
|
export default {
|
||||||
|
interfaceDeclaration(path, print) {
|
||||||
|
const declarationKey = onlyDefinedKey(path.node.children, [
|
||||||
|
"annotationInterfaceDeclaration",
|
||||||
|
"normalInterfaceDeclaration"
|
||||||
|
]);
|
||||||
|
return printWithModifiers(path, print, "interfaceModifier", call(path, print, declarationKey), true);
|
||||||
|
},
|
||||||
|
normalInterfaceDeclaration(path, print) {
|
||||||
|
const { interfaceExtends, interfacePermits, typeParameters } = path.node.children;
|
||||||
|
const header = ["interface ", call(path, print, "typeIdentifier")];
|
||||||
|
if (typeParameters) {
|
||||||
|
header.push(call(path, print, "typeParameters"));
|
||||||
|
}
|
||||||
|
if (interfaceExtends) {
|
||||||
|
header.push(indent([line, call(path, print, "interfaceExtends")]));
|
||||||
|
}
|
||||||
|
if (interfacePermits) {
|
||||||
|
header.push(indent([line, call(path, print, "interfacePermits")]));
|
||||||
|
}
|
||||||
|
return [group(header), " ", call(path, print, "interfaceBody")];
|
||||||
|
},
|
||||||
|
interfaceModifier: printSingle,
|
||||||
|
interfaceExtends(path, print) {
|
||||||
|
return group([
|
||||||
|
"extends",
|
||||||
|
indent([line, call(path, print, "interfaceTypeList")])
|
||||||
|
]);
|
||||||
|
},
|
||||||
|
interfacePermits: printClassPermits,
|
||||||
|
interfaceBody(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 constantDeclaration = (_a = node.children.constantDeclaration) === null || _a === void 0 ? void 0 : _a[0].children;
|
||||||
|
const methodDeclaration = (_b = node.children.interfaceMethodDeclaration) === null || _b === void 0 ? void 0 : _b[0].children;
|
||||||
|
const currentRequiresPadding = (!constantDeclaration && !methodDeclaration) ||
|
||||||
|
(methodDeclaration === null || methodDeclaration === void 0 ? void 0 : methodDeclaration.methodBody[0].children.block) !== undefined ||
|
||||||
|
hasDeclarationAnnotations((_d = (_c = constantDeclaration === null || constantDeclaration === void 0 ? void 0 : constantDeclaration.constantModifier) !== null && _c !== void 0 ? _c : methodDeclaration === null || methodDeclaration === void 0 ? void 0 : methodDeclaration.interfaceMethodModifier) !== 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;
|
||||||
|
}, "interfaceMemberDeclaration");
|
||||||
|
return printBlock(path, declarations);
|
||||||
|
},
|
||||||
|
interfaceMemberDeclaration(path, print) {
|
||||||
|
const { children } = path.node;
|
||||||
|
return children.Semicolon
|
||||||
|
? ""
|
||||||
|
: call(path, print, onlyDefinedKey(children));
|
||||||
|
},
|
||||||
|
constantDeclaration(path, print) {
|
||||||
|
const declaration = [
|
||||||
|
call(path, print, "unannType"),
|
||||||
|
" ",
|
||||||
|
call(path, print, "variableDeclaratorList"),
|
||||||
|
";"
|
||||||
|
];
|
||||||
|
return printWithModifiers(path, print, "constantModifier", declaration);
|
||||||
|
},
|
||||||
|
constantModifier: printSingle,
|
||||||
|
interfaceMethodDeclaration(path, print) {
|
||||||
|
const declaration = [
|
||||||
|
call(path, print, "methodHeader"),
|
||||||
|
path.node.children.methodBody[0].children.Semicolon ? "" : " ",
|
||||||
|
call(path, print, "methodBody")
|
||||||
|
];
|
||||||
|
return printWithModifiers(path, print, "interfaceMethodModifier", declaration);
|
||||||
|
},
|
||||||
|
interfaceMethodModifier: printSingle,
|
||||||
|
annotationInterfaceDeclaration(path, print) {
|
||||||
|
return join(" ", [
|
||||||
|
"@interface",
|
||||||
|
call(path, print, "typeIdentifier"),
|
||||||
|
call(path, print, "annotationInterfaceBody")
|
||||||
|
]);
|
||||||
|
},
|
||||||
|
annotationInterfaceBody(path, print) {
|
||||||
|
const declarations = [];
|
||||||
|
each(path, declarationPath => {
|
||||||
|
const declaration = print(declarationPath);
|
||||||
|
if (declaration === "") {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
declarations.push(declarationPath.isFirst ? declaration : [hardline, declaration]);
|
||||||
|
}, "annotationInterfaceMemberDeclaration");
|
||||||
|
return printBlock(path, declarations);
|
||||||
|
},
|
||||||
|
annotationInterfaceMemberDeclaration(path, print) {
|
||||||
|
const { children } = path.node;
|
||||||
|
return children.Semicolon
|
||||||
|
? ""
|
||||||
|
: call(path, print, onlyDefinedKey(children));
|
||||||
|
},
|
||||||
|
annotationInterfaceElementDeclaration(path, print) {
|
||||||
|
const { dims, defaultValue } = path.node.children;
|
||||||
|
const declaration = [
|
||||||
|
call(path, print, "unannType"),
|
||||||
|
" ",
|
||||||
|
call(path, print, "Identifier"),
|
||||||
|
"()"
|
||||||
|
];
|
||||||
|
if (dims) {
|
||||||
|
declaration.push(call(path, print, "dims"));
|
||||||
|
}
|
||||||
|
if (defaultValue) {
|
||||||
|
declaration.push(" ", call(path, print, "defaultValue"));
|
||||||
|
}
|
||||||
|
declaration.push(";");
|
||||||
|
return printWithModifiers(path, print, "annotationInterfaceElementModifier", declaration);
|
||||||
|
},
|
||||||
|
annotationInterfaceElementModifier: printSingle,
|
||||||
|
defaultValue(path, print) {
|
||||||
|
return ["default ", call(path, print, "elementValue")];
|
||||||
|
},
|
||||||
|
annotation(path, print) {
|
||||||
|
const { children } = path.node;
|
||||||
|
const annotation = ["@", call(path, print, "typeName")];
|
||||||
|
if (children.elementValue || children.elementValuePairList) {
|
||||||
|
const valuesKey = onlyDefinedKey(children, [
|
||||||
|
"elementValue",
|
||||||
|
"elementValuePairList"
|
||||||
|
]);
|
||||||
|
annotation.push(indentInParentheses(call(path, print, valuesKey)));
|
||||||
|
}
|
||||||
|
return annotation;
|
||||||
|
},
|
||||||
|
elementValuePairList(path, print) {
|
||||||
|
return printList(path, print, "elementValuePair");
|
||||||
|
},
|
||||||
|
elementValuePair(path, print) {
|
||||||
|
return join(" ", [
|
||||||
|
call(path, print, "Identifier"),
|
||||||
|
call(path, print, "Equals"),
|
||||||
|
call(path, print, "elementValue")
|
||||||
|
]);
|
||||||
|
},
|
||||||
|
elementValue: printSingle,
|
||||||
|
elementValueArrayInitializer(path, print, options) {
|
||||||
|
return printArrayInitializer(path, print, options, "elementValueList");
|
||||||
|
},
|
||||||
|
elementValueList(path, print) {
|
||||||
|
return group(printList(path, print, "elementValue"));
|
||||||
|
}
|
||||||
|
};
|
||||||
14
frontend/src/common/prettier/plugins/java/printers/lexical-structure.d.ts
vendored
Normal file
14
frontend/src/common/prettier/plugins/java/printers/lexical-structure.d.ts
vendored
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
import { builders } from "prettier/doc";
|
||||||
|
import { printSingle } from "./helpers.js";
|
||||||
|
declare const _default: {
|
||||||
|
literal(path: import("prettier").AstPath<import("java-parser").LiteralCstNode & {
|
||||||
|
comments?: import("../comments.js").JavaComment[];
|
||||||
|
}>, print: import("./helpers.js").JavaPrintFn): builders.Doc;
|
||||||
|
integerLiteral: typeof printSingle;
|
||||||
|
floatingPointLiteral: typeof printSingle;
|
||||||
|
booleanLiteral: typeof printSingle;
|
||||||
|
shiftOperator(path: import("prettier").AstPath<import("java-parser").ShiftOperatorCstNode & {
|
||||||
|
comments?: import("../comments.js").JavaComment[];
|
||||||
|
}>, print: import("./helpers.js").JavaPrintFn): builders.Doc[];
|
||||||
|
};
|
||||||
|
export default _default;
|
||||||
@@ -0,0 +1,29 @@
|
|||||||
|
import { builders } from "prettier/doc";
|
||||||
|
import { findBaseIndent, map, onlyDefinedKey, printSingle } from "./helpers.js";
|
||||||
|
const { hardline, indent, join } = builders;
|
||||||
|
export default {
|
||||||
|
literal(path, print) {
|
||||||
|
const { TextBlock } = path.node.children;
|
||||||
|
if (!TextBlock) {
|
||||||
|
return printSingle(path, print);
|
||||||
|
}
|
||||||
|
const [open, ...lines] = TextBlock[0].image.split("\n");
|
||||||
|
const baseIndent = findBaseIndent(lines);
|
||||||
|
const textBlock = join(hardline, [
|
||||||
|
open,
|
||||||
|
...lines.map(line => line.slice(baseIndent))
|
||||||
|
]);
|
||||||
|
const ancestor = path.getNode(14);
|
||||||
|
return (ancestor === null || ancestor === void 0 ? void 0 : ancestor.name) === "variableInitializer" ||
|
||||||
|
((ancestor === null || ancestor === void 0 ? void 0 : ancestor.name) === "binaryExpression" &&
|
||||||
|
ancestor.children.AssignmentOperator)
|
||||||
|
? indent(textBlock)
|
||||||
|
: textBlock;
|
||||||
|
},
|
||||||
|
integerLiteral: printSingle,
|
||||||
|
floatingPointLiteral: printSingle,
|
||||||
|
booleanLiteral: printSingle,
|
||||||
|
shiftOperator(path, print) {
|
||||||
|
return map(path, print, onlyDefinedKey(path.node.children));
|
||||||
|
}
|
||||||
|
};
|
||||||
12
frontend/src/common/prettier/plugins/java/printers/names.d.ts
vendored
Normal file
12
frontend/src/common/prettier/plugins/java/printers/names.d.ts
vendored
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
import { printName, printSingle } from "./helpers.js";
|
||||||
|
declare const _default: {
|
||||||
|
typeIdentifier: typeof printSingle;
|
||||||
|
moduleName: typeof printName;
|
||||||
|
packageName: typeof printName;
|
||||||
|
typeName: typeof printName;
|
||||||
|
expressionName: typeof printName;
|
||||||
|
methodName: typeof printSingle;
|
||||||
|
packageOrTypeName: typeof printName;
|
||||||
|
ambiguousName: typeof printName;
|
||||||
|
};
|
||||||
|
export default _default;
|
||||||
11
frontend/src/common/prettier/plugins/java/printers/names.js
Normal file
11
frontend/src/common/prettier/plugins/java/printers/names.js
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
import { printName, printSingle } from "./helpers.js";
|
||||||
|
export default {
|
||||||
|
typeIdentifier: printSingle,
|
||||||
|
moduleName: printName,
|
||||||
|
packageName: printName,
|
||||||
|
typeName: printName,
|
||||||
|
expressionName: printName,
|
||||||
|
methodName: printSingle,
|
||||||
|
packageOrTypeName: printName,
|
||||||
|
ambiguousName: printName
|
||||||
|
};
|
||||||
46
frontend/src/common/prettier/plugins/java/printers/packages-and-modules.d.ts
vendored
Normal file
46
frontend/src/common/prettier/plugins/java/printers/packages-and-modules.d.ts
vendored
Normal file
@@ -0,0 +1,46 @@
|
|||||||
|
import type { ExportsModuleDirectiveCstNode, ImportDeclarationCstNode, OpensModuleDirectiveCstNode } from "java-parser";
|
||||||
|
import type { AstPath } from "prettier";
|
||||||
|
import { builders } from "prettier/doc";
|
||||||
|
import { printSingle, type JavaPrintFn } from "./helpers.js";
|
||||||
|
declare const _default: {
|
||||||
|
compilationUnit(path: AstPath<import("java-parser").CompilationUnitCstNode & {
|
||||||
|
comments?: import("../comments.js").JavaComment[];
|
||||||
|
}>, print: JavaPrintFn): builders.Doc[];
|
||||||
|
ordinaryCompilationUnit(path: AstPath<import("java-parser").OrdinaryCompilationUnitCstNode & {
|
||||||
|
comments?: import("../comments.js").JavaComment[];
|
||||||
|
}>, print: JavaPrintFn): builders.Doc[];
|
||||||
|
modularCompilationUnit(path: AstPath<import("java-parser").ModularCompilationUnitCstNode & {
|
||||||
|
comments?: import("../comments.js").JavaComment[];
|
||||||
|
}>, print: JavaPrintFn): builders.Doc[];
|
||||||
|
packageDeclaration(path: AstPath<import("java-parser").PackageDeclarationCstNode & {
|
||||||
|
comments?: import("../comments.js").JavaComment[];
|
||||||
|
}>, print: JavaPrintFn): builders.Doc[];
|
||||||
|
packageModifier: typeof printSingle;
|
||||||
|
importDeclaration(path: AstPath<ImportDeclarationCstNode & {
|
||||||
|
comments?: import("../comments.js").JavaComment[];
|
||||||
|
}>, print: JavaPrintFn): builders.Doc;
|
||||||
|
typeDeclaration(path: AstPath<import("java-parser").TypeDeclarationCstNode & {
|
||||||
|
comments?: import("../comments.js").JavaComment[];
|
||||||
|
}>, print: JavaPrintFn): builders.Doc;
|
||||||
|
moduleDeclaration(path: AstPath<import("java-parser").ModuleDeclarationCstNode & {
|
||||||
|
comments?: import("../comments.js").JavaComment[];
|
||||||
|
}>, print: JavaPrintFn): builders.Doc[];
|
||||||
|
moduleDirective: typeof printSingle;
|
||||||
|
requiresModuleDirective(path: AstPath<import("java-parser").RequiresModuleDirectiveCstNode & {
|
||||||
|
comments?: import("../comments.js").JavaComment[];
|
||||||
|
}>, print: JavaPrintFn): builders.Doc[];
|
||||||
|
exportsModuleDirective(path: AstPath<ExportsModuleDirectiveCstNode & {
|
||||||
|
comments?: import("../comments.js").JavaComment[];
|
||||||
|
}>, print: JavaPrintFn): builders.Doc[];
|
||||||
|
opensModuleDirective(path: AstPath<OpensModuleDirectiveCstNode & {
|
||||||
|
comments?: import("../comments.js").JavaComment[];
|
||||||
|
}>, print: JavaPrintFn): builders.Doc[];
|
||||||
|
usesModuleDirective(path: AstPath<import("java-parser").UsesModuleDirectiveCstNode & {
|
||||||
|
comments?: import("../comments.js").JavaComment[];
|
||||||
|
}>, print: JavaPrintFn): builders.Doc[];
|
||||||
|
providesModuleDirective(path: AstPath<import("java-parser").ProvidesModuleDirectiveCstNode & {
|
||||||
|
comments?: import("../comments.js").JavaComment[];
|
||||||
|
}>, print: JavaPrintFn): builders.Doc[];
|
||||||
|
requiresModifier: typeof printSingle;
|
||||||
|
};
|
||||||
|
export default _default;
|
||||||
@@ -0,0 +1,169 @@
|
|||||||
|
import { builders } from "prettier/doc";
|
||||||
|
import { call, lineEndWithComments, lineStartWithComments, map, printBlock, printDanglingComments, printName, printSingle } from "./helpers.js";
|
||||||
|
const { group, hardline, indent, join, line } = builders;
|
||||||
|
export default {
|
||||||
|
compilationUnit(path, print) {
|
||||||
|
return [...printDanglingComments(path), printSingle(path, print), hardline];
|
||||||
|
},
|
||||||
|
ordinaryCompilationUnit(path, print) {
|
||||||
|
const { children } = path.node;
|
||||||
|
const declarations = [];
|
||||||
|
if (children.packageDeclaration) {
|
||||||
|
declarations.push(call(path, print, "packageDeclaration"));
|
||||||
|
}
|
||||||
|
if (children.importDeclaration) {
|
||||||
|
const staticCount = sortImports(children.importDeclaration);
|
||||||
|
const importDeclarations = map(path, print, "importDeclaration").filter(doc => doc !== "");
|
||||||
|
const staticDeclarations = importDeclarations.slice(0, staticCount);
|
||||||
|
const nonStaticDeclarations = importDeclarations.slice(staticCount);
|
||||||
|
declarations.push(...[staticDeclarations, nonStaticDeclarations]
|
||||||
|
.filter(({ length }) => length)
|
||||||
|
.map(declarations => join(hardline, declarations)));
|
||||||
|
}
|
||||||
|
if (children.typeDeclaration) {
|
||||||
|
declarations.push(...map(path, print, "typeDeclaration").filter(declaration => declaration !== ""));
|
||||||
|
}
|
||||||
|
return join([hardline, hardline], declarations);
|
||||||
|
},
|
||||||
|
modularCompilationUnit(path, print) {
|
||||||
|
const { children } = path.node;
|
||||||
|
const declarations = [];
|
||||||
|
if (children.importDeclaration) {
|
||||||
|
const staticCount = sortImports(children.importDeclaration);
|
||||||
|
const importDeclarations = map(path, print, "importDeclaration").filter(doc => doc !== "");
|
||||||
|
const staticDeclarations = importDeclarations.slice(0, staticCount);
|
||||||
|
const nonStaticDeclarations = importDeclarations.slice(staticCount);
|
||||||
|
declarations.push(...[staticDeclarations, nonStaticDeclarations]
|
||||||
|
.filter(({ length }) => length)
|
||||||
|
.map(declarations => join(hardline, declarations)));
|
||||||
|
}
|
||||||
|
declarations.push(call(path, print, "moduleDeclaration"));
|
||||||
|
return join([hardline, hardline], declarations);
|
||||||
|
},
|
||||||
|
packageDeclaration(path, print) {
|
||||||
|
return join(hardline, [
|
||||||
|
...map(path, print, "packageModifier"),
|
||||||
|
["package ", printName(path, print), ";"]
|
||||||
|
]);
|
||||||
|
},
|
||||||
|
packageModifier: printSingle,
|
||||||
|
importDeclaration(path, print) {
|
||||||
|
const { children } = path.node;
|
||||||
|
if (children.emptyStatement) {
|
||||||
|
return call(path, print, "emptyStatement");
|
||||||
|
}
|
||||||
|
const declaration = ["import "];
|
||||||
|
if (children.Static) {
|
||||||
|
declaration.push("static ");
|
||||||
|
}
|
||||||
|
declaration.push(call(path, print, "packageOrTypeName"));
|
||||||
|
if (children.Star) {
|
||||||
|
declaration.push(".*");
|
||||||
|
}
|
||||||
|
declaration.push(";");
|
||||||
|
return declaration;
|
||||||
|
},
|
||||||
|
typeDeclaration(path, print) {
|
||||||
|
return path.node.children.Semicolon ? "" : printSingle(path, print);
|
||||||
|
},
|
||||||
|
moduleDeclaration(path, print) {
|
||||||
|
const { annotation, Open } = path.node.children;
|
||||||
|
const prefix = [];
|
||||||
|
if (annotation) {
|
||||||
|
prefix.push(...map(path, print, "annotation"));
|
||||||
|
}
|
||||||
|
if (Open) {
|
||||||
|
prefix.push("open");
|
||||||
|
}
|
||||||
|
const declarations = map(path, declarationPath => {
|
||||||
|
const declaration = print(declarationPath);
|
||||||
|
const { node, previous } = declarationPath;
|
||||||
|
return !previous ||
|
||||||
|
lineStartWithComments(node) <= lineEndWithComments(previous) + 1
|
||||||
|
? declaration
|
||||||
|
: [hardline, declaration];
|
||||||
|
}, "moduleDirective");
|
||||||
|
return join(" ", [
|
||||||
|
...prefix,
|
||||||
|
"module",
|
||||||
|
printName(path, print),
|
||||||
|
printBlock(path, declarations)
|
||||||
|
]);
|
||||||
|
},
|
||||||
|
moduleDirective: printSingle,
|
||||||
|
requiresModuleDirective(path, print) {
|
||||||
|
return join(" ", [
|
||||||
|
"requires",
|
||||||
|
...map(path, print, "requiresModifier"),
|
||||||
|
[call(path, print, "moduleName"), ";"]
|
||||||
|
]);
|
||||||
|
},
|
||||||
|
exportsModuleDirective(path, print) {
|
||||||
|
return printToModuleNamesDirective(path, print, "exports");
|
||||||
|
},
|
||||||
|
opensModuleDirective(path, print) {
|
||||||
|
return printToModuleNamesDirective(path, print, "opens");
|
||||||
|
},
|
||||||
|
usesModuleDirective(path, print) {
|
||||||
|
return ["uses ", call(path, print, "typeName"), ";"];
|
||||||
|
},
|
||||||
|
providesModuleDirective(path, print) {
|
||||||
|
const [firstTypeName, ...restTypeNames] = map(path, print, "typeName");
|
||||||
|
return [
|
||||||
|
"provides ",
|
||||||
|
firstTypeName,
|
||||||
|
group(indent([
|
||||||
|
line,
|
||||||
|
group(indent(["with", line, ...join([",", line], restTypeNames)]))
|
||||||
|
])),
|
||||||
|
";"
|
||||||
|
];
|
||||||
|
},
|
||||||
|
requiresModifier: printSingle
|
||||||
|
};
|
||||||
|
function sortImports(importDeclarations) {
|
||||||
|
importDeclarations.sort(({ children: a }, { children: b }) => {
|
||||||
|
if (a.Static && !b.Static) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
else if (b.Static && !a.Static) {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
if (!b.packageOrTypeName) {
|
||||||
|
if (a.packageOrTypeName) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
else if (!a.packageOrTypeName) {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
return compareFqn(a.packageOrTypeName[0], b.packageOrTypeName[0]);
|
||||||
|
});
|
||||||
|
return importDeclarations.reduce((staticCount, importDeclaration) => importDeclaration.children.Static ? staticCount + 1 : staticCount, 0);
|
||||||
|
}
|
||||||
|
function compareFqn(a, b) {
|
||||||
|
const identifiersA = a.children.Identifier;
|
||||||
|
const identifiersB = b.children.Identifier;
|
||||||
|
const minParts = Math.min(identifiersA.length, identifiersB.length);
|
||||||
|
for (let i = 0; i < minParts; i++) {
|
||||||
|
const imageA = identifiersA[i].image;
|
||||||
|
const imageB = identifiersB[i].image;
|
||||||
|
if (imageA < imageB) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
else if (imageA > imageB) {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return identifiersA.length - identifiersB.length;
|
||||||
|
}
|
||||||
|
function printToModuleNamesDirective(path, print, prefix) {
|
||||||
|
const directive = [prefix, " ", call(path, print, "packageName")];
|
||||||
|
if (path.node.children.moduleName) {
|
||||||
|
const moduleNames = join([",", line], map(path, print, "moduleName"));
|
||||||
|
directive.push(group(indent([line, group(indent(["to", line, ...moduleNames]))])));
|
||||||
|
}
|
||||||
|
directive.push(";");
|
||||||
|
return directive;
|
||||||
|
}
|
||||||
46
frontend/src/common/prettier/plugins/java/printers/types-values-and-variables.d.ts
vendored
Normal file
46
frontend/src/common/prettier/plugins/java/printers/types-values-and-variables.d.ts
vendored
Normal file
@@ -0,0 +1,46 @@
|
|||||||
|
import { builders } from "prettier/doc";
|
||||||
|
import { printClassType, printSingle } from "./helpers.js";
|
||||||
|
declare const _default: {
|
||||||
|
primitiveType(path: import("prettier").AstPath<import("java-parser").PrimitiveTypeCstNode & {
|
||||||
|
comments?: import("../comments.js").JavaComment[];
|
||||||
|
}>, print: import("./helpers.js").JavaPrintFn): builders.Doc[];
|
||||||
|
numericType: typeof printSingle;
|
||||||
|
integralType: typeof printSingle;
|
||||||
|
floatingPointType: typeof printSingle;
|
||||||
|
referenceType(path: import("prettier").AstPath<import("java-parser").ReferenceTypeCstNode & {
|
||||||
|
comments?: import("../comments.js").JavaComment[];
|
||||||
|
}>, print: import("./helpers.js").JavaPrintFn): builders.Doc[];
|
||||||
|
classOrInterfaceType: typeof printSingle;
|
||||||
|
classType: typeof printClassType;
|
||||||
|
interfaceType: typeof printSingle;
|
||||||
|
typeVariable(path: import("prettier").AstPath<import("java-parser").TypeVariableCstNode & {
|
||||||
|
comments?: import("../comments.js").JavaComment[];
|
||||||
|
}>, print: import("./helpers.js").JavaPrintFn): builders.Doc[];
|
||||||
|
dims(path: import("prettier").AstPath<import("java-parser").DimsCstNode & {
|
||||||
|
comments?: import("../comments.js").JavaComment[];
|
||||||
|
}>, print: import("./helpers.js").JavaPrintFn): builders.Doc[];
|
||||||
|
typeParameter(path: import("prettier").AstPath<import("java-parser").TypeParameterCstNode & {
|
||||||
|
comments?: import("../comments.js").JavaComment[];
|
||||||
|
}>, print: import("./helpers.js").JavaPrintFn): builders.Doc[];
|
||||||
|
typeParameterModifier: typeof printSingle;
|
||||||
|
typeBound(path: import("prettier").AstPath<import("java-parser").TypeBoundCstNode & {
|
||||||
|
comments?: import("../comments.js").JavaComment[];
|
||||||
|
}>, print: import("./helpers.js").JavaPrintFn): builders.Doc[];
|
||||||
|
additionalBound(path: import("prettier").AstPath<import("java-parser").AdditionalBoundCstNode & {
|
||||||
|
comments?: import("../comments.js").JavaComment[];
|
||||||
|
}>, print: import("./helpers.js").JavaPrintFn): builders.Doc[];
|
||||||
|
typeArguments(path: import("prettier").AstPath<import("java-parser").TypeArgumentsCstNode & {
|
||||||
|
comments?: import("../comments.js").JavaComment[];
|
||||||
|
}>, print: import("./helpers.js").JavaPrintFn): builders.Group;
|
||||||
|
typeArgumentList(path: import("prettier").AstPath<import("java-parser").TypeArgumentListCstNode & {
|
||||||
|
comments?: import("../comments.js").JavaComment[];
|
||||||
|
}>, print: import("./helpers.js").JavaPrintFn): builders.Doc[];
|
||||||
|
typeArgument: typeof printSingle;
|
||||||
|
wildcard(path: import("prettier").AstPath<import("java-parser").WildcardCstNode & {
|
||||||
|
comments?: import("../comments.js").JavaComment[];
|
||||||
|
}>, print: import("./helpers.js").JavaPrintFn): builders.Doc[];
|
||||||
|
wildcardBounds(path: import("prettier").AstPath<import("java-parser").WildcardBoundsCstNode & {
|
||||||
|
comments?: import("../comments.js").JavaComment[];
|
||||||
|
}>, print: import("./helpers.js").JavaPrintFn): builders.Doc[];
|
||||||
|
};
|
||||||
|
export default _default;
|
||||||
@@ -0,0 +1,90 @@
|
|||||||
|
import { builders } from "prettier/doc";
|
||||||
|
import { call, definedKeys, flatMap, isNonTerminal, map, onlyDefinedKey, printClassType, printList, printSingle } from "./helpers.js";
|
||||||
|
const { group, indent, join, line, softline } = builders;
|
||||||
|
export default {
|
||||||
|
primitiveType(path, print) {
|
||||||
|
const { children } = path.node;
|
||||||
|
const typeKey = onlyDefinedKey(children, ["Boolean", "numericType"]);
|
||||||
|
return join(" ", [
|
||||||
|
...map(path, print, "annotation"),
|
||||||
|
call(path, print, typeKey)
|
||||||
|
]);
|
||||||
|
},
|
||||||
|
numericType: printSingle,
|
||||||
|
integralType: printSingle,
|
||||||
|
floatingPointType: printSingle,
|
||||||
|
referenceType(path, print) {
|
||||||
|
const { children } = path.node;
|
||||||
|
const typeKey = onlyDefinedKey(children, [
|
||||||
|
"primitiveType",
|
||||||
|
"classOrInterfaceType"
|
||||||
|
]);
|
||||||
|
const type = call(path, print, typeKey);
|
||||||
|
return join(" ", [
|
||||||
|
...map(path, print, "annotation"),
|
||||||
|
children.dims ? [type, call(path, print, "dims")] : type
|
||||||
|
]);
|
||||||
|
},
|
||||||
|
classOrInterfaceType: printSingle,
|
||||||
|
classType: printClassType,
|
||||||
|
interfaceType: printSingle,
|
||||||
|
typeVariable(path, print) {
|
||||||
|
return join(" ", [
|
||||||
|
...map(path, print, "annotation"),
|
||||||
|
call(path, print, "Identifier")
|
||||||
|
]);
|
||||||
|
},
|
||||||
|
dims(path, print) {
|
||||||
|
return flatMap(path, childPath => {
|
||||||
|
const child = print(childPath);
|
||||||
|
return isNonTerminal(childPath.node) ? [child, " "] : child;
|
||||||
|
}, definedKeys(path.node.children, ["annotation", "LSquare", "RSquare"]));
|
||||||
|
},
|
||||||
|
typeParameter(path, print) {
|
||||||
|
const parameter = [
|
||||||
|
...map(path, print, "typeParameterModifier"),
|
||||||
|
call(path, print, "typeIdentifier")
|
||||||
|
];
|
||||||
|
if (path.node.children.typeBound) {
|
||||||
|
parameter.push(call(path, print, "typeBound"));
|
||||||
|
}
|
||||||
|
return join(" ", parameter);
|
||||||
|
},
|
||||||
|
typeParameterModifier: printSingle,
|
||||||
|
typeBound(path, print) {
|
||||||
|
const bound = ["extends ", call(path, print, "classOrInterfaceType")];
|
||||||
|
if (path.node.children.additionalBound) {
|
||||||
|
bound.push(group(indent([line, ...join(line, map(path, print, "additionalBound"))])));
|
||||||
|
}
|
||||||
|
return bound;
|
||||||
|
},
|
||||||
|
additionalBound(path, print) {
|
||||||
|
return ["& ", call(path, print, "interfaceType")];
|
||||||
|
},
|
||||||
|
typeArguments(path, print) {
|
||||||
|
return group([
|
||||||
|
"<",
|
||||||
|
indent([softline, call(path, print, "typeArgumentList")]),
|
||||||
|
softline,
|
||||||
|
">"
|
||||||
|
]);
|
||||||
|
},
|
||||||
|
typeArgumentList(path, print) {
|
||||||
|
return printList(path, print, "typeArgument");
|
||||||
|
},
|
||||||
|
typeArgument: printSingle,
|
||||||
|
wildcard(path, print) {
|
||||||
|
const wildcard = [...map(path, print, "annotation"), "?"];
|
||||||
|
if (path.node.children.wildcardBounds) {
|
||||||
|
wildcard.push(call(path, print, "wildcardBounds"));
|
||||||
|
}
|
||||||
|
return join(" ", wildcard);
|
||||||
|
},
|
||||||
|
wildcardBounds(path, print) {
|
||||||
|
return [
|
||||||
|
path.node.children.Extends ? "extends" : "super",
|
||||||
|
" ",
|
||||||
|
call(path, print, "referenceType")
|
||||||
|
];
|
||||||
|
}
|
||||||
|
};
|
||||||
4
frontend/src/common/prettier/plugins/php/index.d.ts
vendored
Normal file
4
frontend/src/common/prettier/plugins/php/index.d.ts
vendored
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
import type { Plugin } from "prettier";
|
||||||
|
|
||||||
|
declare const plugin: Plugin;
|
||||||
|
export default plugin;
|
||||||
19
frontend/src/common/prettier/plugins/php/index.mjs
Normal file
19
frontend/src/common/prettier/plugins/php/index.mjs
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
export {
|
||||||
|
languages,
|
||||||
|
printers,
|
||||||
|
parsers,
|
||||||
|
options,
|
||||||
|
defaultOptions
|
||||||
|
} from './src/index.mjs';
|
||||||
|
|
||||||
|
import { languages, printers, parsers, options, defaultOptions } from './src/index.mjs';
|
||||||
|
|
||||||
|
const phpPlugin = {
|
||||||
|
languages,
|
||||||
|
printers,
|
||||||
|
parsers,
|
||||||
|
options,
|
||||||
|
defaultOptions
|
||||||
|
};
|
||||||
|
|
||||||
|
export default phpPlugin;
|
||||||
111
frontend/src/common/prettier/plugins/php/src/clean.mjs
Normal file
111
frontend/src/common/prettier/plugins/php/src/clean.mjs
Normal file
@@ -0,0 +1,111 @@
|
|||||||
|
import { printNumber, normalizeMagicMethodName } from "./util.mjs";
|
||||||
|
|
||||||
|
const ignoredProperties = new Set([
|
||||||
|
"loc",
|
||||||
|
"range",
|
||||||
|
"raw",
|
||||||
|
"comments",
|
||||||
|
"leadingComments",
|
||||||
|
"trailingComments",
|
||||||
|
"parenthesizedExpression",
|
||||||
|
"parent",
|
||||||
|
"prev",
|
||||||
|
"start",
|
||||||
|
"end",
|
||||||
|
"tokens",
|
||||||
|
"errors",
|
||||||
|
"extra",
|
||||||
|
]);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This function takes the existing ast node and a copy, by reference
|
||||||
|
* We use it for testing, so that we can compare pre-post versions of the AST,
|
||||||
|
* excluding things we don't care about (like node location, case that will be
|
||||||
|
* changed by the printer, etc.)
|
||||||
|
*/
|
||||||
|
function clean(node, newObj) {
|
||||||
|
if (node.kind === "string") {
|
||||||
|
// TODO if options are available in this method, replace with
|
||||||
|
// newObj.isDoubleQuote = !useSingleQuote(node, options);
|
||||||
|
delete newObj.isDoubleQuote;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (["array", "list"].includes(node.kind)) {
|
||||||
|
// TODO if options are available in this method, assign instead of delete
|
||||||
|
delete newObj.shortForm;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (node.kind === "inline") {
|
||||||
|
if (node.value.includes("___PSEUDO_INLINE_PLACEHOLDER___")) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
newObj.value = newObj.value.replace(/\n/g, "");
|
||||||
|
}
|
||||||
|
|
||||||
|
// continue ((2)); -> continue 2;
|
||||||
|
// continue 1; -> continue;
|
||||||
|
if ((node.kind === "continue" || node.kind === "break") && node.level) {
|
||||||
|
const { level } = newObj;
|
||||||
|
|
||||||
|
if (level.kind === "number") {
|
||||||
|
newObj.level = level.value === "1" ? null : level;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// if () {{ }} -> if () {}
|
||||||
|
if (node.kind === "block") {
|
||||||
|
if (node.children.length === 1 && node.children[0].kind === "block") {
|
||||||
|
while (newObj.children[0].kind === "block") {
|
||||||
|
newObj.children = newObj.children[0].children;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Normalize numbers
|
||||||
|
if (node.kind === "number") {
|
||||||
|
newObj.value = printNumber(node.value);
|
||||||
|
}
|
||||||
|
|
||||||
|
const statements = ["foreach", "for", "if", "while", "do"];
|
||||||
|
|
||||||
|
if (statements.includes(node.kind)) {
|
||||||
|
if (node.body && node.body.kind !== "block") {
|
||||||
|
newObj.body = {
|
||||||
|
kind: "block",
|
||||||
|
children: [newObj.body],
|
||||||
|
};
|
||||||
|
} else {
|
||||||
|
newObj.body = newObj.body ? newObj.body : null;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (node.alternate && node.alternate.kind !== "block") {
|
||||||
|
newObj.alternate = {
|
||||||
|
kind: "block",
|
||||||
|
children: [newObj.alternate],
|
||||||
|
};
|
||||||
|
} else {
|
||||||
|
newObj.alternate = newObj.alternate ? newObj.alternate : null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (node.kind === "usegroup" && typeof node.name === "string") {
|
||||||
|
newObj.name = newObj.name.replace(/^\\/, "");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (node.kind === "useitem") {
|
||||||
|
newObj.name = newObj.name.replace(/^\\/, "");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (node.kind === "method" && node.name.kind === "identifier") {
|
||||||
|
newObj.name.name = normalizeMagicMethodName(newObj.name.name);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (node.kind === "noop") {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
clean.ignoredProperties = ignoredProperties;
|
||||||
|
|
||||||
|
export default clean;
|
||||||
1044
frontend/src/common/prettier/plugins/php/src/comments.mjs
Normal file
1044
frontend/src/common/prettier/plugins/php/src/comments.mjs
Normal file
File diff suppressed because it is too large
Load Diff
173
frontend/src/common/prettier/plugins/php/src/index.mjs
Normal file
173
frontend/src/common/prettier/plugins/php/src/index.mjs
Normal file
@@ -0,0 +1,173 @@
|
|||||||
|
import { doc } from "prettier";
|
||||||
|
import LINGUIST_LANGUAGES_PHP from "linguist-languages/data/PHP";
|
||||||
|
import LINGUIST_LANGUAGES_HTML_PHP from "linguist-languages/data/HTML_2b_PHP";
|
||||||
|
import parse from "./parser.mjs";
|
||||||
|
import print from "./printer.mjs";
|
||||||
|
import clean from "./clean.mjs";
|
||||||
|
import options from "./options.mjs";
|
||||||
|
import {
|
||||||
|
handleOwnLineComment,
|
||||||
|
handleEndOfLineComment,
|
||||||
|
handleRemainingComment,
|
||||||
|
getCommentChildNodes,
|
||||||
|
canAttachComment,
|
||||||
|
isBlockComment,
|
||||||
|
} from "./comments.mjs";
|
||||||
|
import { hasPragma, insertPragma } from "./pragma.mjs";
|
||||||
|
import { locStart, locEnd } from "./loc.mjs";
|
||||||
|
|
||||||
|
const { join, hardline } = doc.builders;
|
||||||
|
|
||||||
|
function createLanguage(linguistData, { extend, override }) {
|
||||||
|
const language = {};
|
||||||
|
|
||||||
|
for (const key in linguistData) {
|
||||||
|
const newKey = key === "languageId" ? "linguistLanguageId" : key;
|
||||||
|
language[newKey] = linguistData[key];
|
||||||
|
}
|
||||||
|
|
||||||
|
if (extend) {
|
||||||
|
for (const key in extend) {
|
||||||
|
language[key] = (language[key] || []).concat(extend[key]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const key in override) {
|
||||||
|
language[key] = override[key];
|
||||||
|
}
|
||||||
|
|
||||||
|
return language;
|
||||||
|
}
|
||||||
|
|
||||||
|
const languages = [
|
||||||
|
createLanguage(LINGUIST_LANGUAGES_PHP, {
|
||||||
|
override: {
|
||||||
|
parsers: ["php"],
|
||||||
|
vscodeLanguageIds: ["php"],
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
createLanguage(LINGUIST_LANGUAGES_HTML_PHP, {
|
||||||
|
override: {
|
||||||
|
parsers: ["php"],
|
||||||
|
vscodeLanguageIds: ["php"],
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
];
|
||||||
|
|
||||||
|
const parsers = {
|
||||||
|
php: {
|
||||||
|
parse,
|
||||||
|
astFormat: "php",
|
||||||
|
locStart,
|
||||||
|
locEnd,
|
||||||
|
hasPragma,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
const ignoredKeys = new Set([
|
||||||
|
"kind",
|
||||||
|
"loc",
|
||||||
|
"errors",
|
||||||
|
"extra",
|
||||||
|
"comments",
|
||||||
|
"leadingComments",
|
||||||
|
"enclosingNode",
|
||||||
|
"precedingNode",
|
||||||
|
"followingNode",
|
||||||
|
]);
|
||||||
|
function getVisitorKeys(node, nonTraversableKeys) {
|
||||||
|
return Object.keys(node).filter(
|
||||||
|
(key) => !nonTraversableKeys.has(key) && !ignoredKeys.has(key)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
const printers = {
|
||||||
|
php: {
|
||||||
|
print,
|
||||||
|
getVisitorKeys,
|
||||||
|
insertPragma,
|
||||||
|
massageAstNode: clean,
|
||||||
|
getCommentChildNodes,
|
||||||
|
canAttachComment,
|
||||||
|
isBlockComment,
|
||||||
|
handleComments: {
|
||||||
|
ownLine: handleOwnLineComment,
|
||||||
|
endOfLine: handleEndOfLineComment,
|
||||||
|
remaining: handleRemainingComment,
|
||||||
|
},
|
||||||
|
willPrintOwnComments(path) {
|
||||||
|
const { node } = path;
|
||||||
|
|
||||||
|
return node && node.kind === "noop";
|
||||||
|
},
|
||||||
|
printComment(path) {
|
||||||
|
const comment = path.node;
|
||||||
|
|
||||||
|
switch (comment.kind) {
|
||||||
|
case "commentblock": {
|
||||||
|
// for now, don't touch single line block comments
|
||||||
|
if (!comment.value.includes("\n")) {
|
||||||
|
return comment.value;
|
||||||
|
}
|
||||||
|
|
||||||
|
const lines = comment.value.split("\n");
|
||||||
|
// if this is a block comment, handle indentation
|
||||||
|
if (
|
||||||
|
lines
|
||||||
|
.slice(1, lines.length - 1)
|
||||||
|
.every((line) => line.trim()[0] === "*")
|
||||||
|
) {
|
||||||
|
return join(
|
||||||
|
hardline,
|
||||||
|
lines.map(
|
||||||
|
(line, index) =>
|
||||||
|
(index > 0 ? " " : "") +
|
||||||
|
(index < lines.length - 1 ? line.trim() : line.trimLeft())
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// otherwise we can't be sure about indentation, so just print as is
|
||||||
|
return comment.value;
|
||||||
|
}
|
||||||
|
case "commentline": {
|
||||||
|
return comment.value.trimRight();
|
||||||
|
}
|
||||||
|
/* c8 ignore next 2 */
|
||||||
|
default:
|
||||||
|
throw new Error(`Not a comment: ${JSON.stringify(comment)}`);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
hasPrettierIgnore(path) {
|
||||||
|
const isSimpleIgnore = (comment) =>
|
||||||
|
comment.value.includes("prettier-ignore") &&
|
||||||
|
!comment.value.includes("prettier-ignore-start") &&
|
||||||
|
!comment.value.includes("prettier-ignore-end");
|
||||||
|
|
||||||
|
const { node, parent: parentNode } = path;
|
||||||
|
|
||||||
|
return (
|
||||||
|
(node &&
|
||||||
|
node.kind !== "classconstant" &&
|
||||||
|
node.comments &&
|
||||||
|
node.comments.length > 0 &&
|
||||||
|
node.comments.some(isSimpleIgnore)) ||
|
||||||
|
// For proper formatting, the classconstant ignore formatting should
|
||||||
|
// run on the "constant" child
|
||||||
|
(node &&
|
||||||
|
node.kind === "constant" &&
|
||||||
|
parentNode &&
|
||||||
|
parentNode.kind === "classconstant" &&
|
||||||
|
parentNode.comments &&
|
||||||
|
parentNode.comments.length > 0 &&
|
||||||
|
parentNode.comments.some(isSimpleIgnore))
|
||||||
|
);
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
const defaultOptions = {
|
||||||
|
tabWidth: 4,
|
||||||
|
};
|
||||||
|
|
||||||
|
export { languages, printers, parsers, options, defaultOptions };
|
||||||
4
frontend/src/common/prettier/plugins/php/src/loc.mjs
Normal file
4
frontend/src/common/prettier/plugins/php/src/loc.mjs
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
const loc = (prop) => (node) => node.loc?.[prop]?.offset;
|
||||||
|
|
||||||
|
export const locStart = loc("start");
|
||||||
|
export const locEnd = loc("end");
|
||||||
250
frontend/src/common/prettier/plugins/php/src/needs-parens.mjs
Normal file
250
frontend/src/common/prettier/plugins/php/src/needs-parens.mjs
Normal file
@@ -0,0 +1,250 @@
|
|||||||
|
import { getPrecedence, shouldFlatten, isBitwiseOperator } from "./util.mjs";
|
||||||
|
|
||||||
|
function needsParens(path, options) {
|
||||||
|
const { parent } = path;
|
||||||
|
|
||||||
|
if (!parent) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
const { key, node } = path;
|
||||||
|
|
||||||
|
if (
|
||||||
|
[
|
||||||
|
// No need parens for top level children of this nodes
|
||||||
|
"program",
|
||||||
|
"expressionstatement",
|
||||||
|
"namespace",
|
||||||
|
"declare",
|
||||||
|
"block",
|
||||||
|
|
||||||
|
// No need parens
|
||||||
|
"include",
|
||||||
|
"print",
|
||||||
|
"return",
|
||||||
|
"echo",
|
||||||
|
].includes(parent.kind)
|
||||||
|
) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (node.kind) {
|
||||||
|
case "pre":
|
||||||
|
case "post":
|
||||||
|
if (parent.kind === "unary") {
|
||||||
|
return (
|
||||||
|
node.kind === "pre" &&
|
||||||
|
((node.type === "+" && parent.type === "+") ||
|
||||||
|
(node.type === "-" && parent.type === "-"))
|
||||||
|
);
|
||||||
|
}
|
||||||
|
// else fallthrough
|
||||||
|
case "unary":
|
||||||
|
switch (parent.kind) {
|
||||||
|
case "unary":
|
||||||
|
return (
|
||||||
|
node.type === parent.type &&
|
||||||
|
(node.type === "+" || node.type === "-")
|
||||||
|
);
|
||||||
|
case "propertylookup":
|
||||||
|
case "nullsafepropertylookup":
|
||||||
|
case "staticlookup":
|
||||||
|
case "offsetlookup":
|
||||||
|
case "call":
|
||||||
|
return key === "what";
|
||||||
|
case "bin":
|
||||||
|
return parent.type === "**" && key === "left";
|
||||||
|
default:
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
case "bin": {
|
||||||
|
switch (parent.kind) {
|
||||||
|
case "assign":
|
||||||
|
case "retif":
|
||||||
|
return ["and", "xor", "or"].includes(node.type);
|
||||||
|
case "silent":
|
||||||
|
case "cast":
|
||||||
|
// TODO: bug https://github.com/glayzzle/php-parser/issues/172
|
||||||
|
return node.parenthesizedExpression;
|
||||||
|
case "pre":
|
||||||
|
case "post":
|
||||||
|
case "unary":
|
||||||
|
return true;
|
||||||
|
case "call":
|
||||||
|
case "propertylookup":
|
||||||
|
case "nullsafepropertylookup":
|
||||||
|
case "staticlookup":
|
||||||
|
case "offsetlookup":
|
||||||
|
return key === "what";
|
||||||
|
case "bin": {
|
||||||
|
const po = parent.type;
|
||||||
|
const pp = getPrecedence(po);
|
||||||
|
const no = node.type;
|
||||||
|
const np = getPrecedence(no);
|
||||||
|
|
||||||
|
if (pp > np) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (po === "||" && no === "&&") {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pp === np && key === "right") {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pp === np && !shouldFlatten(po, no)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pp < np && no === "%") {
|
||||||
|
return po === "+" || po === "-";
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add parenthesis when working with bitwise operators
|
||||||
|
// It's not stricly needed but helps with code understanding
|
||||||
|
if (isBitwiseOperator(po)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
default:
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
case "propertylookup":
|
||||||
|
case "nullsafepropertylookup":
|
||||||
|
case "staticlookup": {
|
||||||
|
switch (parent.kind) {
|
||||||
|
case "call":
|
||||||
|
return key === "what" && node.parenthesizedExpression;
|
||||||
|
|
||||||
|
default:
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
case "clone":
|
||||||
|
case "new": {
|
||||||
|
const requiresParens =
|
||||||
|
node.kind === "clone" ||
|
||||||
|
(node.kind === "new" && options.phpVersion < 8.4);
|
||||||
|
switch (parent.kind) {
|
||||||
|
case "propertylookup":
|
||||||
|
case "nullsafepropertylookup":
|
||||||
|
case "staticlookup":
|
||||||
|
case "offsetlookup":
|
||||||
|
case "call":
|
||||||
|
return key === "what" && requiresParens;
|
||||||
|
default:
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
case "yield": {
|
||||||
|
switch (parent.kind) {
|
||||||
|
case "propertylookup":
|
||||||
|
case "nullsafepropertylookup":
|
||||||
|
case "staticlookup":
|
||||||
|
case "offsetlookup":
|
||||||
|
case "call":
|
||||||
|
return key === "what";
|
||||||
|
|
||||||
|
case "retif":
|
||||||
|
return key === "test";
|
||||||
|
|
||||||
|
default:
|
||||||
|
return !!(node.key || node.value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
case "assign": {
|
||||||
|
if (
|
||||||
|
parent.kind === "for" &&
|
||||||
|
(parent.init.includes(node) || parent.increment.includes(node))
|
||||||
|
) {
|
||||||
|
return false;
|
||||||
|
} else if (parent.kind === "assign") {
|
||||||
|
return false;
|
||||||
|
} else if (parent.kind === "static") {
|
||||||
|
return false;
|
||||||
|
} else if (
|
||||||
|
["if", "do", "while", "foreach", "switch"].includes(parent.kind)
|
||||||
|
) {
|
||||||
|
return false;
|
||||||
|
} else if (parent.kind === "silent") {
|
||||||
|
return false;
|
||||||
|
} else if (parent.kind === "call") {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
case "retif":
|
||||||
|
switch (parent.kind) {
|
||||||
|
case "cast":
|
||||||
|
return true;
|
||||||
|
case "unary":
|
||||||
|
case "bin":
|
||||||
|
case "retif":
|
||||||
|
if (key === "test" && !parent.trueExpr) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
case "propertylookup":
|
||||||
|
case "nullsafepropertylookup":
|
||||||
|
case "staticlookup":
|
||||||
|
case "offsetlookup":
|
||||||
|
case "call":
|
||||||
|
return key === "what";
|
||||||
|
|
||||||
|
default:
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
case "closure":
|
||||||
|
switch (parent.kind) {
|
||||||
|
case "call":
|
||||||
|
return key === "what";
|
||||||
|
|
||||||
|
// https://github.com/prettier/plugin-php/issues/1675
|
||||||
|
case "propertylookup":
|
||||||
|
case "nullsafepropertylookup":
|
||||||
|
return true;
|
||||||
|
|
||||||
|
default:
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
case "silence":
|
||||||
|
case "cast":
|
||||||
|
// TODO: bug https://github.com/glayzzle/php-parser/issues/172
|
||||||
|
return node.parenthesizedExpression;
|
||||||
|
// else fallthrough
|
||||||
|
case "string":
|
||||||
|
case "array":
|
||||||
|
switch (parent.kind) {
|
||||||
|
case "propertylookup":
|
||||||
|
case "nullsafepropertylookup":
|
||||||
|
case "staticlookup":
|
||||||
|
case "offsetlookup":
|
||||||
|
case "call":
|
||||||
|
if (
|
||||||
|
["string", "array"].includes(node.kind) &&
|
||||||
|
parent.kind === "offsetlookup"
|
||||||
|
) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return key === "what";
|
||||||
|
default:
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
case "print":
|
||||||
|
case "include":
|
||||||
|
return parent.kind === "bin";
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
export default needsParens;
|
||||||
69
frontend/src/common/prettier/plugins/php/src/options.mjs
Normal file
69
frontend/src/common/prettier/plugins/php/src/options.mjs
Normal file
@@ -0,0 +1,69 @@
|
|||||||
|
const CATEGORY_PHP = "PHP";
|
||||||
|
|
||||||
|
// prettier-ignore
|
||||||
|
const SUPPORTED_PHP_VERSIONS = [
|
||||||
|
5.0, 5.1, 5.2, 5.3, 5.4, 5.5, 5.6,
|
||||||
|
7.0, 7.1, 7.2, 7.3, 7.4,
|
||||||
|
8.0, 8.1, 8.2, 8.3, 8.4,
|
||||||
|
];
|
||||||
|
|
||||||
|
export const LATEST_SUPPORTED_PHP_VERSION = Math.max(...SUPPORTED_PHP_VERSIONS);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Resolve the PHP version to a number based on the provided options.
|
||||||
|
*/
|
||||||
|
export function resolvePhpVersion(options) {
|
||||||
|
if (!options) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (options.phpVersion === "auto" || options.phpVersion === "composer") {
|
||||||
|
options.phpVersion = LATEST_SUPPORTED_PHP_VERSION;
|
||||||
|
} else {
|
||||||
|
options.phpVersion = parseFloat(options.phpVersion);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default {
|
||||||
|
phpVersion: {
|
||||||
|
since: "0.13.0",
|
||||||
|
category: CATEGORY_PHP,
|
||||||
|
type: "choice",
|
||||||
|
default: "auto",
|
||||||
|
description: "Minimum target PHP version.",
|
||||||
|
choices: [
|
||||||
|
...SUPPORTED_PHP_VERSIONS.map((v) => ({ value: v.toFixed(1) })),
|
||||||
|
{
|
||||||
|
value: "auto",
|
||||||
|
description: `Use latest PHP Version (${LATEST_SUPPORTED_PHP_VERSION})`,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
trailingCommaPHP: {
|
||||||
|
since: "0.0.0",
|
||||||
|
category: CATEGORY_PHP,
|
||||||
|
type: "boolean",
|
||||||
|
default: true,
|
||||||
|
description: "Print trailing commas wherever possible when multi-line.",
|
||||||
|
},
|
||||||
|
braceStyle: {
|
||||||
|
since: "0.10.0",
|
||||||
|
category: CATEGORY_PHP,
|
||||||
|
type: "choice",
|
||||||
|
default: "per-cs",
|
||||||
|
description:
|
||||||
|
"Print one space or newline for code blocks (classes and functions).",
|
||||||
|
choices: [
|
||||||
|
{ value: "psr-2", description: "(deprecated) Use per-cs" },
|
||||||
|
{ value: "per-cs", description: "Use the PER Coding Style brace style." },
|
||||||
|
{ value: "1tbs", description: "Use 1tbs brace style." },
|
||||||
|
],
|
||||||
|
},
|
||||||
|
singleQuote: {
|
||||||
|
since: "0.0.0",
|
||||||
|
category: CATEGORY_PHP,
|
||||||
|
type: "boolean",
|
||||||
|
default: false,
|
||||||
|
description: "Use single quotes instead of double quotes.",
|
||||||
|
},
|
||||||
|
};
|
||||||
67
frontend/src/common/prettier/plugins/php/src/parser.mjs
Normal file
67
frontend/src/common/prettier/plugins/php/src/parser.mjs
Normal file
@@ -0,0 +1,67 @@
|
|||||||
|
import engine from "php-parser";
|
||||||
|
import { LATEST_SUPPORTED_PHP_VERSION } from "./options.mjs";
|
||||||
|
import { resolvePhpVersion } from "./options.mjs";
|
||||||
|
|
||||||
|
function parse(text, opts) {
|
||||||
|
const inMarkdown = opts && opts.parentParser === "markdown";
|
||||||
|
|
||||||
|
if (!text && inMarkdown) {
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
resolvePhpVersion(opts);
|
||||||
|
|
||||||
|
// Todo https://github.com/glayzzle/php-parser/issues/170
|
||||||
|
text = text.replace(/\?>\n<\?/g, "?>\n___PSEUDO_INLINE_PLACEHOLDER___<?");
|
||||||
|
|
||||||
|
// initialize a new parser instance
|
||||||
|
const parser = new engine({
|
||||||
|
parser: {
|
||||||
|
extractDoc: true,
|
||||||
|
version: `${LATEST_SUPPORTED_PHP_VERSION}`,
|
||||||
|
},
|
||||||
|
ast: {
|
||||||
|
withPositions: true,
|
||||||
|
withSource: true,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
const hasOpenPHPTag = text.indexOf("<?php") !== -1;
|
||||||
|
const parseAsEval = inMarkdown && !hasOpenPHPTag;
|
||||||
|
|
||||||
|
let ast;
|
||||||
|
try {
|
||||||
|
ast = parseAsEval ? parser.parseEval(text) : parser.parseCode(text);
|
||||||
|
} catch (err) {
|
||||||
|
if (err instanceof SyntaxError && "lineNumber" in err) {
|
||||||
|
err.loc = {
|
||||||
|
start: {
|
||||||
|
line: err.lineNumber,
|
||||||
|
column: err.columnNumber,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
delete err.lineNumber;
|
||||||
|
delete err.columnNumber;
|
||||||
|
}
|
||||||
|
|
||||||
|
throw err;
|
||||||
|
}
|
||||||
|
|
||||||
|
ast.extra = {
|
||||||
|
parseAsEval,
|
||||||
|
};
|
||||||
|
|
||||||
|
// https://github.com/glayzzle/php-parser/issues/155
|
||||||
|
// currently inline comments include the line break at the end, we need to
|
||||||
|
// strip those out and update the end location for each comment manually
|
||||||
|
ast.comments.forEach((comment) => {
|
||||||
|
if (comment.value[comment.value.length - 1] === "\n") {
|
||||||
|
comment.value = comment.value.slice(0, -1);
|
||||||
|
comment.loc.end.offset = comment.loc.end.offset - 1;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return ast;
|
||||||
|
}
|
||||||
|
|
||||||
|
export default parse;
|
||||||
92
frontend/src/common/prettier/plugins/php/src/pragma.mjs
Normal file
92
frontend/src/common/prettier/plugins/php/src/pragma.mjs
Normal file
@@ -0,0 +1,92 @@
|
|||||||
|
import { memoize } from "./util.mjs";
|
||||||
|
import parse from "./parser.mjs";
|
||||||
|
|
||||||
|
const reHasPragma = /@prettier|@format/;
|
||||||
|
|
||||||
|
const getPageLevelDocBlock = memoize((text) => {
|
||||||
|
const parsed = parse(text);
|
||||||
|
|
||||||
|
const [firstChild] = parsed.children;
|
||||||
|
const [firstDocBlock] = parsed.comments.filter(
|
||||||
|
(el) => el.kind === "commentblock"
|
||||||
|
);
|
||||||
|
|
||||||
|
if (
|
||||||
|
firstChild &&
|
||||||
|
firstDocBlock &&
|
||||||
|
firstDocBlock.loc.start.line < firstChild.loc.start.line
|
||||||
|
) {
|
||||||
|
return firstDocBlock;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
function hasPragma(text) {
|
||||||
|
// fast path optimization - check if the pragma shows up in the file at all
|
||||||
|
if (!reHasPragma.test(text)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
const pageLevelDocBlock = getPageLevelDocBlock(text);
|
||||||
|
|
||||||
|
if (pageLevelDocBlock) {
|
||||||
|
const { value } = pageLevelDocBlock;
|
||||||
|
|
||||||
|
return reHasPragma.test(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
function injectPragma(docblock) {
|
||||||
|
let lines = docblock.split("\n");
|
||||||
|
|
||||||
|
if (lines.length === 1) {
|
||||||
|
// normalize to multiline for simplicity
|
||||||
|
const [, line] = /\/*\*\*(.*)\*\//.exec(lines[0]);
|
||||||
|
|
||||||
|
lines = ["/**", ` * ${line.trim()}`, " */"];
|
||||||
|
}
|
||||||
|
|
||||||
|
// find the first @pragma
|
||||||
|
// if there happens to be one on the opening line, just put it on the next line.
|
||||||
|
const pragmaIndex = lines.findIndex((line) => /@\S/.test(line)) || 1;
|
||||||
|
|
||||||
|
// not found => index == -1, which conveniently will splice 1 from the end.
|
||||||
|
lines.splice(pragmaIndex, 0, " * @format");
|
||||||
|
|
||||||
|
return lines.join("\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
function insertPragma(text) {
|
||||||
|
const pageLevelDocBlock = getPageLevelDocBlock(text);
|
||||||
|
|
||||||
|
if (pageLevelDocBlock) {
|
||||||
|
const {
|
||||||
|
start: { offset: startOffset },
|
||||||
|
end: { offset: endOffset },
|
||||||
|
} = pageLevelDocBlock.loc;
|
||||||
|
const before = text.substring(0, startOffset);
|
||||||
|
const after = text.substring(endOffset);
|
||||||
|
|
||||||
|
return `${before}${injectPragma(pageLevelDocBlock.value, text)}${after}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
const openTag = "<?php";
|
||||||
|
|
||||||
|
if (!text.startsWith(openTag)) {
|
||||||
|
// bail out
|
||||||
|
return text;
|
||||||
|
}
|
||||||
|
|
||||||
|
const splitAt = openTag.length;
|
||||||
|
const phpTag = text.substring(0, splitAt);
|
||||||
|
const after = text.substring(splitAt);
|
||||||
|
|
||||||
|
return `${phpTag}
|
||||||
|
/**
|
||||||
|
* @format
|
||||||
|
*/
|
||||||
|
${after}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
export { hasPragma, insertPragma };
|
||||||
2899
frontend/src/common/prettier/plugins/php/src/printer.mjs
Normal file
2899
frontend/src/common/prettier/plugins/php/src/printer.mjs
Normal file
File diff suppressed because it is too large
Load Diff
743
frontend/src/common/prettier/plugins/php/src/util.mjs
Normal file
743
frontend/src/common/prettier/plugins/php/src/util.mjs
Normal file
@@ -0,0 +1,743 @@
|
|||||||
|
import { util as prettierUtil } from "prettier";
|
||||||
|
import { locStart } from "./loc.mjs";
|
||||||
|
|
||||||
|
const { hasNewline, skipEverythingButNewLine, skipNewline } = prettierUtil;
|
||||||
|
|
||||||
|
function printNumber(rawNumber) {
|
||||||
|
return (
|
||||||
|
rawNumber
|
||||||
|
.toLowerCase()
|
||||||
|
// Remove unnecessary plus and zeroes from scientific notation.
|
||||||
|
.replace(/^([+-]?[\d.]+e)(?:\+|(-))?0*(\d)/, "$1$2$3")
|
||||||
|
// Remove unnecessary scientific notation (1e0).
|
||||||
|
.replace(/^([+-]?[\d.]+)e[+-]?0+$/, "$1")
|
||||||
|
// Make sure numbers always start with a digit.
|
||||||
|
.replace(/^([+-])?\./, "$10.")
|
||||||
|
// Remove extraneous trailing decimal zeroes.
|
||||||
|
.replace(/(\.\d+?)0+(?=e|$)/, "$1")
|
||||||
|
// Remove unnecessary .e notation
|
||||||
|
.replace(/\.(?=e)/, "")
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// http://php.net/manual/en/language.operators.precedence.php
|
||||||
|
const PRECEDENCE = new Map(
|
||||||
|
[
|
||||||
|
["or"],
|
||||||
|
["xor"],
|
||||||
|
["and"],
|
||||||
|
[
|
||||||
|
"=",
|
||||||
|
"+=",
|
||||||
|
"-=",
|
||||||
|
"*=",
|
||||||
|
"**=",
|
||||||
|
"/=",
|
||||||
|
".=",
|
||||||
|
"%=",
|
||||||
|
"&=",
|
||||||
|
"|=",
|
||||||
|
"^=",
|
||||||
|
"<<=",
|
||||||
|
">>=",
|
||||||
|
],
|
||||||
|
["??"],
|
||||||
|
["||"],
|
||||||
|
["&&"],
|
||||||
|
["|"],
|
||||||
|
["^"],
|
||||||
|
["&"],
|
||||||
|
["==", "===", "!=", "!==", "<>", "<=>"],
|
||||||
|
["<", ">", "<=", ">="],
|
||||||
|
[">>", "<<"],
|
||||||
|
["+", "-", "."],
|
||||||
|
["*", "/", "%"],
|
||||||
|
["!"],
|
||||||
|
["instanceof"],
|
||||||
|
["++", "--", "~"],
|
||||||
|
["**"],
|
||||||
|
].flatMap((operators, index) =>
|
||||||
|
operators.map((operator) => [operator, index])
|
||||||
|
)
|
||||||
|
);
|
||||||
|
function getPrecedence(operator) {
|
||||||
|
return PRECEDENCE.get(operator);
|
||||||
|
}
|
||||||
|
|
||||||
|
const equalityOperators = ["==", "!=", "===", "!==", "<>", "<=>"];
|
||||||
|
const multiplicativeOperators = ["*", "/", "%"];
|
||||||
|
const bitshiftOperators = [">>", "<<"];
|
||||||
|
|
||||||
|
function isBitwiseOperator(operator) {
|
||||||
|
return (
|
||||||
|
!!bitshiftOperators[operator] ||
|
||||||
|
operator === "|" ||
|
||||||
|
operator === "^" ||
|
||||||
|
operator === "&"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function shouldFlatten(parentOp, nodeOp) {
|
||||||
|
if (getPrecedence(nodeOp) !== getPrecedence(parentOp)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ** is right-associative
|
||||||
|
// x ** y ** z --> x ** (y ** z)
|
||||||
|
if (parentOp === "**") {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// x == y == z --> (x == y) == z
|
||||||
|
if (
|
||||||
|
equalityOperators.includes(parentOp) &&
|
||||||
|
equalityOperators.includes(nodeOp)
|
||||||
|
) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// x * y % z --> (x * y) % z
|
||||||
|
if (
|
||||||
|
(nodeOp === "%" && multiplicativeOperators.includes(parentOp)) ||
|
||||||
|
(parentOp === "%" && multiplicativeOperators.includes(nodeOp))
|
||||||
|
) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// x * y / z --> (x * y) / z
|
||||||
|
// x / y * z --> (x / y) * z
|
||||||
|
if (
|
||||||
|
nodeOp !== parentOp &&
|
||||||
|
multiplicativeOperators.includes(nodeOp) &&
|
||||||
|
multiplicativeOperators.includes(parentOp)
|
||||||
|
) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// x << y << z --> (x << y) << z
|
||||||
|
if (
|
||||||
|
bitshiftOperators.includes(parentOp) &&
|
||||||
|
bitshiftOperators.includes(nodeOp)
|
||||||
|
) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
function nodeHasStatement(node) {
|
||||||
|
return [
|
||||||
|
"block",
|
||||||
|
"program",
|
||||||
|
"namespace",
|
||||||
|
"class",
|
||||||
|
"enum",
|
||||||
|
"interface",
|
||||||
|
"trait",
|
||||||
|
"traituse",
|
||||||
|
"declare",
|
||||||
|
].includes(node.kind);
|
||||||
|
}
|
||||||
|
|
||||||
|
function getBodyFirstChild({ body }) {
|
||||||
|
if (!body) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
if (body.kind === "block") {
|
||||||
|
body = body.children;
|
||||||
|
}
|
||||||
|
return body[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
function getNodeListProperty(node) {
|
||||||
|
const body = node.children || node.body || node.adaptations;
|
||||||
|
return Array.isArray(body) ? body : null;
|
||||||
|
}
|
||||||
|
|
||||||
|
function getLast(arr) {
|
||||||
|
if (arr.length > 0) {
|
||||||
|
return arr[arr.length - 1];
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
function getPenultimate(arr) {
|
||||||
|
if (arr.length > 1) {
|
||||||
|
return arr[arr.length - 2];
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
function isFirstChildrenInlineNode(path) {
|
||||||
|
const { node } = path;
|
||||||
|
|
||||||
|
if (node.kind === "program") {
|
||||||
|
const children = getNodeListProperty(node);
|
||||||
|
|
||||||
|
if (!children || children.length === 0) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return children[0].kind === "inline";
|
||||||
|
}
|
||||||
|
|
||||||
|
if (node.kind === "switch") {
|
||||||
|
if (!node.body) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
const children = getNodeListProperty(node.body);
|
||||||
|
|
||||||
|
if (children.length === 0) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
const [firstCase] = children;
|
||||||
|
|
||||||
|
if (!firstCase.body) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
const firstCaseChildren = getNodeListProperty(firstCase.body);
|
||||||
|
|
||||||
|
if (firstCaseChildren.length === 0) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return firstCaseChildren[0].kind === "inline";
|
||||||
|
}
|
||||||
|
|
||||||
|
const firstChild = getBodyFirstChild(node);
|
||||||
|
|
||||||
|
if (!firstChild) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return firstChild.kind === "inline";
|
||||||
|
}
|
||||||
|
|
||||||
|
function isDocNode(node) {
|
||||||
|
return (
|
||||||
|
node.kind === "nowdoc" ||
|
||||||
|
(node.kind === "encapsed" && node.type === "heredoc")
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Heredoc/Nowdoc nodes need a trailing linebreak if they
|
||||||
|
* appear as function arguments or array elements
|
||||||
|
*/
|
||||||
|
function docShouldHaveTrailingNewline(path, recurse = 0) {
|
||||||
|
const node = path.getNode(recurse);
|
||||||
|
const parent = path.getNode(recurse + 1);
|
||||||
|
const parentParent = path.getNode(recurse + 2);
|
||||||
|
|
||||||
|
if (!parent) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (
|
||||||
|
(parentParent &&
|
||||||
|
["call", "new", "echo"].includes(parentParent.kind) &&
|
||||||
|
!["call", "array"].includes(parent.kind)) ||
|
||||||
|
parent.kind === "parameter"
|
||||||
|
) {
|
||||||
|
const lastIndex = parentParent.arguments.length - 1;
|
||||||
|
const index = parentParent.arguments.indexOf(parent);
|
||||||
|
|
||||||
|
return index !== lastIndex;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (parentParent && parentParent.kind === "for") {
|
||||||
|
const initIndex = parentParent.init.indexOf(parent);
|
||||||
|
|
||||||
|
if (initIndex !== -1) {
|
||||||
|
return initIndex !== parentParent.init.length - 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
const testIndex = parentParent.test.indexOf(parent);
|
||||||
|
|
||||||
|
if (testIndex !== -1) {
|
||||||
|
return testIndex !== parentParent.test.length - 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
const incrementIndex = parentParent.increment.indexOf(parent);
|
||||||
|
|
||||||
|
if (incrementIndex !== -1) {
|
||||||
|
return incrementIndex !== parentParent.increment.length - 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (parent.kind === "bin") {
|
||||||
|
return (
|
||||||
|
parent.left === node || docShouldHaveTrailingNewline(path, recurse + 1)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (parent.kind === "case" && parent.test === node) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (parent.kind === "staticvariable") {
|
||||||
|
const lastIndex = parentParent.variables.length - 1;
|
||||||
|
const index = parentParent.variables.indexOf(parent);
|
||||||
|
|
||||||
|
return index !== lastIndex;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (parent.kind === "entry") {
|
||||||
|
if (parent.key === node) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
const lastIndex = parentParent.items.length - 1;
|
||||||
|
const index = parentParent.items.indexOf(parent);
|
||||||
|
|
||||||
|
return index !== lastIndex;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (["call", "new"].includes(parent.kind)) {
|
||||||
|
const lastIndex = parent.arguments.length - 1;
|
||||||
|
const index = parent.arguments.indexOf(node);
|
||||||
|
|
||||||
|
return index !== lastIndex;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (parent.kind === "echo") {
|
||||||
|
const lastIndex = parent.expressions.length - 1;
|
||||||
|
const index = parent.expressions.indexOf(node);
|
||||||
|
|
||||||
|
return index !== lastIndex;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (parent.kind === "array") {
|
||||||
|
const lastIndex = parent.items.length - 1;
|
||||||
|
const index = parent.items.indexOf(node);
|
||||||
|
|
||||||
|
return index !== lastIndex;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (parent.kind === "retif") {
|
||||||
|
return docShouldHaveTrailingNewline(path, recurse + 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
function lineShouldEndWithSemicolon(path) {
|
||||||
|
const { node, parent: parentNode } = path;
|
||||||
|
if (!parentNode) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
// for single line control structures written in a shortform (ie without a block),
|
||||||
|
// we need to make sure the single body node gets a semicolon
|
||||||
|
if (
|
||||||
|
["for", "foreach", "while", "do", "if", "switch"].includes(
|
||||||
|
parentNode.kind
|
||||||
|
) &&
|
||||||
|
node.kind !== "block" &&
|
||||||
|
node.kind !== "if" &&
|
||||||
|
(parentNode.body === node || parentNode.alternate === node)
|
||||||
|
) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (!nodeHasStatement(parentNode)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (node.kind === "echo" && node.shortForm) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (node.kind === "traituse") {
|
||||||
|
return !node.adaptations;
|
||||||
|
}
|
||||||
|
if (node.kind === "method" && node.isAbstract) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (node.kind === "method") {
|
||||||
|
const { parent } = path;
|
||||||
|
if (parent && parent.kind === "interface") {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return [
|
||||||
|
"expressionstatement",
|
||||||
|
"do",
|
||||||
|
"usegroup",
|
||||||
|
"classconstant",
|
||||||
|
"propertystatement",
|
||||||
|
"traitprecedence",
|
||||||
|
"traitalias",
|
||||||
|
"goto",
|
||||||
|
"constantstatement",
|
||||||
|
"enumcase",
|
||||||
|
"global",
|
||||||
|
"static",
|
||||||
|
"echo",
|
||||||
|
"unset",
|
||||||
|
"return",
|
||||||
|
"break",
|
||||||
|
"continue",
|
||||||
|
"throw",
|
||||||
|
].includes(node.kind);
|
||||||
|
}
|
||||||
|
|
||||||
|
function fileShouldEndWithHardline(path) {
|
||||||
|
const { node } = path;
|
||||||
|
const isProgramNode = node.kind === "program";
|
||||||
|
const lastNode = node.children && getLast(node.children);
|
||||||
|
|
||||||
|
if (!isProgramNode) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (lastNode && ["halt", "inline"].includes(lastNode.kind)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (
|
||||||
|
lastNode &&
|
||||||
|
(lastNode.kind === "declare" || lastNode.kind === "namespace")
|
||||||
|
) {
|
||||||
|
const lastNestedNode =
|
||||||
|
lastNode.children.length > 0 && getLast(lastNode.children);
|
||||||
|
|
||||||
|
if (lastNestedNode && ["halt", "inline"].includes(lastNestedNode.kind)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
function maybeStripLeadingSlashFromUse(name) {
|
||||||
|
const nameWithoutLeadingSlash = name.replace(/^\\/, "");
|
||||||
|
if (nameWithoutLeadingSlash.indexOf("\\") !== -1) {
|
||||||
|
return nameWithoutLeadingSlash;
|
||||||
|
}
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
|
||||||
|
function hasDanglingComments(node) {
|
||||||
|
return (
|
||||||
|
node.comments &&
|
||||||
|
node.comments.some((comment) => !comment.leading && !comment.trailing)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function isLookupNode(node) {
|
||||||
|
return (
|
||||||
|
node.kind === "propertylookup" ||
|
||||||
|
node.kind === "nullsafepropertylookup" ||
|
||||||
|
node.kind === "staticlookup" ||
|
||||||
|
node.kind === "offsetlookup"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function shouldPrintHardLineAfterStartInControlStructure(path) {
|
||||||
|
const { node } = path;
|
||||||
|
|
||||||
|
if (["try", "catch"].includes(node.kind)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return isFirstChildrenInlineNode(path);
|
||||||
|
}
|
||||||
|
|
||||||
|
function shouldPrintHardLineBeforeEndInControlStructure(path) {
|
||||||
|
const { node } = path;
|
||||||
|
|
||||||
|
if (["try", "catch"].includes(node.kind)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (node.kind === "switch") {
|
||||||
|
const children = getNodeListProperty(node.body);
|
||||||
|
|
||||||
|
if (children.length === 0) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
const lastCase = getLast(children);
|
||||||
|
|
||||||
|
if (!lastCase.body) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
const childrenInCase = getNodeListProperty(lastCase.body);
|
||||||
|
|
||||||
|
if (childrenInCase.length === 0) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return childrenInCase[0].kind !== "inline";
|
||||||
|
}
|
||||||
|
|
||||||
|
return !isFirstChildrenInlineNode(path);
|
||||||
|
}
|
||||||
|
|
||||||
|
function getAlignment(text) {
|
||||||
|
const lines = text.split("\n");
|
||||||
|
const lastLine = lines.pop();
|
||||||
|
|
||||||
|
return lastLine.length - lastLine.trimLeft().length + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
function isProgramLikeNode(node) {
|
||||||
|
return ["program", "declare", "namespace"].includes(node.kind);
|
||||||
|
}
|
||||||
|
|
||||||
|
function isReferenceLikeNode(node) {
|
||||||
|
return [
|
||||||
|
"name",
|
||||||
|
"parentreference",
|
||||||
|
"selfreference",
|
||||||
|
"staticreference",
|
||||||
|
].includes(node.kind);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Return `logical` value for `bin` node containing `||` or `&&` type otherwise return kind of node.
|
||||||
|
// Require for grouping logical and binary nodes in right way.
|
||||||
|
function getNodeKindIncludingLogical(node) {
|
||||||
|
if (node.kind === "bin" && ["||", "&&"].includes(node.type)) {
|
||||||
|
return "logical";
|
||||||
|
}
|
||||||
|
|
||||||
|
return node.kind;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check if string can safely be converted from double to single quotes and vice-versa, i.e.
|
||||||
|
*
|
||||||
|
* - no embedded variables ("foo $bar")
|
||||||
|
* - no linebreaks
|
||||||
|
* - no special characters like \n, \t, ...
|
||||||
|
* - no octal/hex/unicode characters
|
||||||
|
*
|
||||||
|
* See https://php.net/manual/en/language.types.string.php#language.types.string.syntax.double
|
||||||
|
*/
|
||||||
|
function useDoubleQuote(node, options) {
|
||||||
|
if (node.isDoubleQuote === options.singleQuote) {
|
||||||
|
// We have a double quote and the user passed singleQuote:true, or the other way around.
|
||||||
|
const rawValue = node.raw.slice(node.raw[0] === "b" ? 2 : 1, -1);
|
||||||
|
const isComplex = rawValue.match(
|
||||||
|
/\\([$nrtfve]|[xX][0-9a-fA-F]{1,2}|[0-7]{1,3}|u{([0-9a-fA-F]+)})|\r?\n|'|"|\$/
|
||||||
|
);
|
||||||
|
return node.isDoubleQuote ? isComplex : !isComplex;
|
||||||
|
}
|
||||||
|
return node.isDoubleQuote;
|
||||||
|
}
|
||||||
|
|
||||||
|
function hasEmptyBody(path, name = "body") {
|
||||||
|
const { node } = path;
|
||||||
|
|
||||||
|
return (
|
||||||
|
node[name] &&
|
||||||
|
node[name].children &&
|
||||||
|
node[name].children.length === 0 &&
|
||||||
|
(!node[name].comments || node[name].comments.length === 0)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function isNextLineEmptyAfterNamespace(text, node) {
|
||||||
|
let idx = locStart(node);
|
||||||
|
idx = skipEverythingButNewLine(text, idx);
|
||||||
|
idx = skipNewline(text, idx);
|
||||||
|
return hasNewline(text, idx);
|
||||||
|
}
|
||||||
|
|
||||||
|
function shouldPrintHardlineBeforeTrailingComma(lastElem) {
|
||||||
|
if (
|
||||||
|
lastElem.kind === "nowdoc" ||
|
||||||
|
(lastElem.kind === "encapsed" && lastElem.type === "heredoc")
|
||||||
|
) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (
|
||||||
|
lastElem.kind === "entry" &&
|
||||||
|
(lastElem.value.kind === "nowdoc" ||
|
||||||
|
(lastElem.value.kind === "encapsed" && lastElem.value.type === "heredoc"))
|
||||||
|
) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
function getAncestorCounter(path, typeOrTypes) {
|
||||||
|
const types = [].concat(typeOrTypes);
|
||||||
|
let counter = -1;
|
||||||
|
let ancestorNode;
|
||||||
|
while ((ancestorNode = path.getParentNode(++counter))) {
|
||||||
|
if (types.indexOf(ancestorNode.kind) !== -1) {
|
||||||
|
return counter;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
function getAncestorNode(path, typeOrTypes) {
|
||||||
|
const counter = getAncestorCounter(path, typeOrTypes);
|
||||||
|
return counter === -1 ? null : path.getParentNode(counter);
|
||||||
|
}
|
||||||
|
|
||||||
|
const magicMethods = [
|
||||||
|
"__construct",
|
||||||
|
"__destruct",
|
||||||
|
"__call",
|
||||||
|
"__callStatic",
|
||||||
|
"__get",
|
||||||
|
"__set",
|
||||||
|
"__isset",
|
||||||
|
"__unset",
|
||||||
|
"__sleep",
|
||||||
|
"__wakeup",
|
||||||
|
"__toString",
|
||||||
|
"__invoke",
|
||||||
|
"__set_state",
|
||||||
|
"__clone",
|
||||||
|
"__debugInfo",
|
||||||
|
];
|
||||||
|
const magicMethodsMap = new Map(
|
||||||
|
magicMethods.map((name) => [name.toLowerCase(), name])
|
||||||
|
);
|
||||||
|
|
||||||
|
function normalizeMagicMethodName(name) {
|
||||||
|
const loweredName = name.toLowerCase();
|
||||||
|
|
||||||
|
if (magicMethodsMap.has(loweredName)) {
|
||||||
|
return magicMethodsMap.get(loweredName);
|
||||||
|
}
|
||||||
|
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {string[]} kindsArray
|
||||||
|
* @returns {(node: Node | Comment) => Boolean}
|
||||||
|
*/
|
||||||
|
function createTypeCheckFunction(kindsArray) {
|
||||||
|
const kinds = new Set(kindsArray);
|
||||||
|
return (node) => kinds.has(node?.kind);
|
||||||
|
}
|
||||||
|
|
||||||
|
const isSingleWordType = createTypeCheckFunction([
|
||||||
|
"variadicplaceholder",
|
||||||
|
"namedargument",
|
||||||
|
"nullkeyword",
|
||||||
|
"identifier",
|
||||||
|
"parameter",
|
||||||
|
"variable",
|
||||||
|
"variadic",
|
||||||
|
"boolean",
|
||||||
|
"literal",
|
||||||
|
"number",
|
||||||
|
"string",
|
||||||
|
"clone",
|
||||||
|
"cast",
|
||||||
|
]);
|
||||||
|
|
||||||
|
const isArrayExpression = createTypeCheckFunction(["array"]);
|
||||||
|
const isCallLikeExpression = createTypeCheckFunction([
|
||||||
|
"nullsafepropertylookup",
|
||||||
|
"propertylookup",
|
||||||
|
"staticlookup",
|
||||||
|
"offsetlookup",
|
||||||
|
"call",
|
||||||
|
"new",
|
||||||
|
]);
|
||||||
|
const isArrowFuncExpression = createTypeCheckFunction(["arrowfunc"]);
|
||||||
|
|
||||||
|
function getChainParts(node, prev = []) {
|
||||||
|
const parts = prev;
|
||||||
|
if (isCallLikeExpression(node)) {
|
||||||
|
parts.push(node);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!node.what) {
|
||||||
|
return parts;
|
||||||
|
}
|
||||||
|
|
||||||
|
return getChainParts(node.what, parts);
|
||||||
|
}
|
||||||
|
|
||||||
|
function isSimpleCallArgument(node, depth = 2) {
|
||||||
|
if (depth <= 0) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
const isChildSimple = (child) => isSimpleCallArgument(child, depth - 1);
|
||||||
|
|
||||||
|
if (isSingleWordType(node)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isArrayExpression(node)) {
|
||||||
|
return node.items.every((x) => x === null || isChildSimple(x));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isCallLikeExpression(node)) {
|
||||||
|
const parts = getChainParts(node);
|
||||||
|
parts.unshift();
|
||||||
|
|
||||||
|
return (
|
||||||
|
parts.length <= depth &&
|
||||||
|
parts.every((node) =>
|
||||||
|
isLookupNode(node)
|
||||||
|
? isChildSimple(node.offset)
|
||||||
|
: node.arguments.every(isChildSimple)
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isArrowFuncExpression(node)) {
|
||||||
|
return (
|
||||||
|
node.arguments.length <= depth && node.arguments.every(isChildSimple)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
function memoize(fn) {
|
||||||
|
const cache = new Map();
|
||||||
|
return (key) => {
|
||||||
|
if (!cache.has(key)) {
|
||||||
|
cache.set(key, fn(key));
|
||||||
|
}
|
||||||
|
return cache.get(key);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export {
|
||||||
|
printNumber,
|
||||||
|
getPrecedence,
|
||||||
|
isBitwiseOperator,
|
||||||
|
shouldFlatten,
|
||||||
|
nodeHasStatement,
|
||||||
|
getLast,
|
||||||
|
getPenultimate,
|
||||||
|
getBodyFirstChild,
|
||||||
|
lineShouldEndWithSemicolon,
|
||||||
|
fileShouldEndWithHardline,
|
||||||
|
maybeStripLeadingSlashFromUse,
|
||||||
|
hasDanglingComments,
|
||||||
|
docShouldHaveTrailingNewline,
|
||||||
|
isLookupNode,
|
||||||
|
isFirstChildrenInlineNode,
|
||||||
|
shouldPrintHardLineAfterStartInControlStructure,
|
||||||
|
shouldPrintHardLineBeforeEndInControlStructure,
|
||||||
|
getAlignment,
|
||||||
|
isProgramLikeNode,
|
||||||
|
isReferenceLikeNode,
|
||||||
|
getNodeKindIncludingLogical,
|
||||||
|
useDoubleQuote,
|
||||||
|
hasEmptyBody,
|
||||||
|
isNextLineEmptyAfterNamespace,
|
||||||
|
shouldPrintHardlineBeforeTrailingComma,
|
||||||
|
isDocNode,
|
||||||
|
getAncestorNode,
|
||||||
|
normalizeMagicMethodName,
|
||||||
|
isSimpleCallArgument,
|
||||||
|
memoize,
|
||||||
|
};
|
||||||
391
frontend/src/common/prettier/plugins/powershell/ast.ts
Normal file
391
frontend/src/common/prettier/plugins/powershell/ast.ts
Normal file
@@ -0,0 +1,391 @@
|
|||||||
|
/**
|
||||||
|
* PowerShell AST 节点定义
|
||||||
|
* 定义抽象语法树的各种节点类型
|
||||||
|
*/
|
||||||
|
|
||||||
|
import { Token } from './lexer';
|
||||||
|
|
||||||
|
export interface ASTNode {
|
||||||
|
type: string;
|
||||||
|
start: number;
|
||||||
|
end: number;
|
||||||
|
line: number;
|
||||||
|
column: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface ScriptBlockAst extends ASTNode {
|
||||||
|
type: 'ScriptBlock';
|
||||||
|
statements: StatementAst[];
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface StatementAst extends ASTNode {
|
||||||
|
type: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface ExpressionAst extends ASTNode {
|
||||||
|
type: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 管道表达式
|
||||||
|
export interface PipelineAst extends StatementAst {
|
||||||
|
type: 'Pipeline';
|
||||||
|
elements: PipelineElementAst[];
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface PipelineElementAst extends ASTNode {
|
||||||
|
type: 'PipelineElement';
|
||||||
|
expression: ExpressionAst;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 命令表达式
|
||||||
|
export interface CommandAst extends ExpressionAst {
|
||||||
|
type: 'Command';
|
||||||
|
commandName: string;
|
||||||
|
parameters: ParameterAst[];
|
||||||
|
arguments: ExpressionAst[];
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface ParameterAst extends ASTNode {
|
||||||
|
type: 'Parameter';
|
||||||
|
name: string;
|
||||||
|
value?: ExpressionAst;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 赋值表达式
|
||||||
|
export interface AssignmentAst extends StatementAst {
|
||||||
|
type: 'Assignment';
|
||||||
|
left: ExpressionAst;
|
||||||
|
operator: string;
|
||||||
|
right: ExpressionAst;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 变量表达式
|
||||||
|
export interface VariableAst extends ExpressionAst {
|
||||||
|
type: 'Variable';
|
||||||
|
name: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 字面量表达式
|
||||||
|
export interface LiteralAst extends ExpressionAst {
|
||||||
|
type: 'Literal';
|
||||||
|
value: any;
|
||||||
|
literalType: 'String' | 'Number' | 'Boolean' | 'Null';
|
||||||
|
}
|
||||||
|
|
||||||
|
// 数组表达式
|
||||||
|
export interface ArrayAst extends ExpressionAst {
|
||||||
|
type: 'Array';
|
||||||
|
elements: ExpressionAst[];
|
||||||
|
}
|
||||||
|
|
||||||
|
// 哈希表表达式
|
||||||
|
export interface HashtableAst extends ExpressionAst {
|
||||||
|
type: 'Hashtable';
|
||||||
|
entries: HashtableEntryAst[];
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface HashtableEntryAst extends ASTNode {
|
||||||
|
type: 'HashtableEntry';
|
||||||
|
key: ExpressionAst;
|
||||||
|
value: ExpressionAst;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 函数定义
|
||||||
|
export interface FunctionDefinitionAst extends StatementAst {
|
||||||
|
type: 'FunctionDefinition';
|
||||||
|
name: string;
|
||||||
|
parameters: ParameterAst[];
|
||||||
|
body: ScriptBlockAst;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 控制流结构
|
||||||
|
export interface IfStatementAst extends StatementAst {
|
||||||
|
type: 'IfStatement';
|
||||||
|
condition: ExpressionAst;
|
||||||
|
ifBody: ScriptBlockAst;
|
||||||
|
elseIfClauses: ElseIfClauseAst[];
|
||||||
|
elseBody?: ScriptBlockAst;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface ElseIfClauseAst extends ASTNode {
|
||||||
|
type: 'ElseIfClause';
|
||||||
|
condition: ExpressionAst;
|
||||||
|
body: ScriptBlockAst;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface WhileStatementAst extends StatementAst {
|
||||||
|
type: 'WhileStatement';
|
||||||
|
condition: ExpressionAst;
|
||||||
|
body: ScriptBlockAst;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface ForStatementAst extends StatementAst {
|
||||||
|
type: 'ForStatement';
|
||||||
|
initializer?: ExpressionAst;
|
||||||
|
condition?: ExpressionAst;
|
||||||
|
iterator?: ExpressionAst;
|
||||||
|
body: ScriptBlockAst;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface ForEachStatementAst extends StatementAst {
|
||||||
|
type: 'ForEachStatement';
|
||||||
|
variable: VariableAst;
|
||||||
|
iterable: ExpressionAst;
|
||||||
|
body: ScriptBlockAst;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface SwitchStatementAst extends StatementAst {
|
||||||
|
type: 'SwitchStatement';
|
||||||
|
value: ExpressionAst;
|
||||||
|
clauses: SwitchClauseAst[];
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface SwitchClauseAst extends ASTNode {
|
||||||
|
type: 'SwitchClause';
|
||||||
|
pattern: ExpressionAst;
|
||||||
|
body: ScriptBlockAst;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface TryStatementAst extends StatementAst {
|
||||||
|
type: 'TryStatement';
|
||||||
|
body: ScriptBlockAst;
|
||||||
|
catchClauses: CatchClauseAst[];
|
||||||
|
finallyClause?: FinallyClauseAst;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface CatchClauseAst extends ASTNode {
|
||||||
|
type: 'CatchClause';
|
||||||
|
exceptionType?: string;
|
||||||
|
body: ScriptBlockAst;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface FinallyClauseAst extends ASTNode {
|
||||||
|
type: 'FinallyClause';
|
||||||
|
body: ScriptBlockAst;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 二元操作表达式
|
||||||
|
export interface BinaryExpressionAst extends ExpressionAst {
|
||||||
|
type: 'BinaryExpression';
|
||||||
|
left: ExpressionAst;
|
||||||
|
operator: string;
|
||||||
|
right: ExpressionAst;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 一元操作表达式
|
||||||
|
export interface UnaryExpressionAst extends ExpressionAst {
|
||||||
|
type: 'UnaryExpression';
|
||||||
|
operator: string;
|
||||||
|
operand: ExpressionAst;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 括号表达式
|
||||||
|
export interface ParenthesizedExpressionAst extends ExpressionAst {
|
||||||
|
type: 'ParenthesizedExpression';
|
||||||
|
expression: ExpressionAst;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 方法调用表达式
|
||||||
|
export interface MethodCallAst extends ExpressionAst {
|
||||||
|
type: 'MethodCall';
|
||||||
|
object: ExpressionAst;
|
||||||
|
methodName: string;
|
||||||
|
arguments: ExpressionAst[];
|
||||||
|
}
|
||||||
|
|
||||||
|
// 属性访问表达式
|
||||||
|
export interface PropertyAccessAst extends ExpressionAst {
|
||||||
|
type: 'PropertyAccess';
|
||||||
|
object: ExpressionAst;
|
||||||
|
propertyName: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 索引访问表达式
|
||||||
|
export interface IndexAccessAst extends ExpressionAst {
|
||||||
|
type: 'IndexAccess';
|
||||||
|
object: ExpressionAst;
|
||||||
|
index: ExpressionAst;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 注释节点
|
||||||
|
export interface CommentAst extends ASTNode {
|
||||||
|
type: 'Comment';
|
||||||
|
text: string;
|
||||||
|
isMultiline: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 空白节点
|
||||||
|
export interface WhitespaceAst extends ASTNode {
|
||||||
|
type: 'Whitespace';
|
||||||
|
text: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 工厂函数,用于创建AST节点
|
||||||
|
export class ASTNodeFactory {
|
||||||
|
static createScriptBlock(statements: StatementAst[], start: number, end: number, line: number, column: number): ScriptBlockAst {
|
||||||
|
return {
|
||||||
|
type: 'ScriptBlock',
|
||||||
|
statements,
|
||||||
|
start,
|
||||||
|
end,
|
||||||
|
line,
|
||||||
|
column
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
static createPipeline(elements: PipelineElementAst[], start: number, end: number, line: number, column: number): PipelineAst {
|
||||||
|
return {
|
||||||
|
type: 'Pipeline',
|
||||||
|
elements,
|
||||||
|
start,
|
||||||
|
end,
|
||||||
|
line,
|
||||||
|
column
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
static createCommand(commandName: string, parameters: ParameterAst[], args: ExpressionAst[], start: number, end: number, line: number, column: number): CommandAst {
|
||||||
|
return {
|
||||||
|
type: 'Command',
|
||||||
|
commandName,
|
||||||
|
parameters,
|
||||||
|
arguments: args,
|
||||||
|
start,
|
||||||
|
end,
|
||||||
|
line,
|
||||||
|
column
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
static createAssignment(left: ExpressionAst, operator: string, right: ExpressionAst, start: number, end: number, line: number, column: number): AssignmentAst {
|
||||||
|
return {
|
||||||
|
type: 'Assignment',
|
||||||
|
left,
|
||||||
|
operator,
|
||||||
|
right,
|
||||||
|
start,
|
||||||
|
end,
|
||||||
|
line,
|
||||||
|
column
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
static createVariable(name: string, start: number, end: number, line: number, column: number): VariableAst {
|
||||||
|
return {
|
||||||
|
type: 'Variable',
|
||||||
|
name,
|
||||||
|
start,
|
||||||
|
end,
|
||||||
|
line,
|
||||||
|
column
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
static createLiteral(value: any, literalType: 'String' | 'Number' | 'Boolean' | 'Null', start: number, end: number, line: number, column: number): LiteralAst {
|
||||||
|
return {
|
||||||
|
type: 'Literal',
|
||||||
|
value,
|
||||||
|
literalType,
|
||||||
|
start,
|
||||||
|
end,
|
||||||
|
line,
|
||||||
|
column
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
static createBinaryExpression(left: ExpressionAst, operator: string, right: ExpressionAst, start: number, end: number, line: number, column: number): BinaryExpressionAst {
|
||||||
|
return {
|
||||||
|
type: 'BinaryExpression',
|
||||||
|
left,
|
||||||
|
operator,
|
||||||
|
right,
|
||||||
|
start,
|
||||||
|
end,
|
||||||
|
line,
|
||||||
|
column
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
static createIfStatement(condition: ExpressionAst, ifBody: ScriptBlockAst, elseIfClauses: ElseIfClauseAst[], elseBody: ScriptBlockAst | undefined, start: number, end: number, line: number, column: number): IfStatementAst {
|
||||||
|
return {
|
||||||
|
type: 'IfStatement',
|
||||||
|
condition,
|
||||||
|
ifBody,
|
||||||
|
elseIfClauses,
|
||||||
|
elseBody,
|
||||||
|
start,
|
||||||
|
end,
|
||||||
|
line,
|
||||||
|
column
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
static createFunctionDefinition(name: string, parameters: ParameterAst[], body: ScriptBlockAst, start: number, end: number, line: number, column: number): FunctionDefinitionAst {
|
||||||
|
return {
|
||||||
|
type: 'FunctionDefinition',
|
||||||
|
name,
|
||||||
|
parameters,
|
||||||
|
body,
|
||||||
|
start,
|
||||||
|
end,
|
||||||
|
line,
|
||||||
|
column
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
static createComment(text: string, isMultiline: boolean, start: number, end: number, line: number, column: number): CommentAst {
|
||||||
|
return {
|
||||||
|
type: 'Comment',
|
||||||
|
text,
|
||||||
|
isMultiline,
|
||||||
|
start,
|
||||||
|
end,
|
||||||
|
line,
|
||||||
|
column
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// AST访问者模式接口
|
||||||
|
export interface ASTVisitor<T> {
|
||||||
|
visitScriptBlock(node: ScriptBlockAst): T;
|
||||||
|
visitPipeline(node: PipelineAst): T;
|
||||||
|
visitCommand(node: CommandAst): T;
|
||||||
|
visitAssignment(node: AssignmentAst): T;
|
||||||
|
visitVariable(node: VariableAst): T;
|
||||||
|
visitLiteral(node: LiteralAst): T;
|
||||||
|
visitBinaryExpression(node: BinaryExpressionAst): T;
|
||||||
|
visitIfStatement(node: IfStatementAst): T;
|
||||||
|
visitFunctionDefinition(node: FunctionDefinitionAst): T;
|
||||||
|
visitComment(node: CommentAst): T;
|
||||||
|
}
|
||||||
|
|
||||||
|
// AST遍历工具类
|
||||||
|
export class ASTTraverser {
|
||||||
|
static traverse<T>(node: ASTNode, visitor: Partial<ASTVisitor<T>>): T | undefined {
|
||||||
|
switch (node.type) {
|
||||||
|
case 'ScriptBlock':
|
||||||
|
return visitor.visitScriptBlock?.(node as ScriptBlockAst);
|
||||||
|
case 'Pipeline':
|
||||||
|
return visitor.visitPipeline?.(node as PipelineAst);
|
||||||
|
case 'Command':
|
||||||
|
return visitor.visitCommand?.(node as CommandAst);
|
||||||
|
case 'Assignment':
|
||||||
|
return visitor.visitAssignment?.(node as AssignmentAst);
|
||||||
|
case 'Variable':
|
||||||
|
return visitor.visitVariable?.(node as VariableAst);
|
||||||
|
case 'Literal':
|
||||||
|
return visitor.visitLiteral?.(node as LiteralAst);
|
||||||
|
case 'BinaryExpression':
|
||||||
|
return visitor.visitBinaryExpression?.(node as BinaryExpressionAst);
|
||||||
|
case 'IfStatement':
|
||||||
|
return visitor.visitIfStatement?.(node as IfStatementAst);
|
||||||
|
case 'FunctionDefinition':
|
||||||
|
return visitor.visitFunctionDefinition?.(node as FunctionDefinitionAst);
|
||||||
|
case 'Comment':
|
||||||
|
return visitor.visitComment?.(node as CommentAst);
|
||||||
|
default:
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,566 @@
|
|||||||
|
/**
|
||||||
|
* PowerShell 代码生成器
|
||||||
|
* 遍历AST并根据格式化规则生成格式化的PowerShell代码
|
||||||
|
*/
|
||||||
|
|
||||||
|
import {
|
||||||
|
ASTNode,
|
||||||
|
ScriptBlockAst,
|
||||||
|
StatementAst,
|
||||||
|
ExpressionAst,
|
||||||
|
PipelineAst,
|
||||||
|
CommandAst,
|
||||||
|
AssignmentAst,
|
||||||
|
VariableAst,
|
||||||
|
LiteralAst,
|
||||||
|
BinaryExpressionAst,
|
||||||
|
IfStatementAst,
|
||||||
|
FunctionDefinitionAst,
|
||||||
|
ParameterAst,
|
||||||
|
CommentAst,
|
||||||
|
PipelineElementAst,
|
||||||
|
ElseIfClauseAst,
|
||||||
|
ASTTraverser
|
||||||
|
} from './ast';
|
||||||
|
import { FormatterRules, FormatterOptions } from './formatter-rules';
|
||||||
|
|
||||||
|
export class PowerShellCodeGenerator {
|
||||||
|
private rules: FormatterRules;
|
||||||
|
private indentLevel: number = 0;
|
||||||
|
private output: string[] = [];
|
||||||
|
private currentLineLength: number = 0;
|
||||||
|
private needsNewline: boolean = false;
|
||||||
|
private lastWasComment: boolean = false;
|
||||||
|
|
||||||
|
constructor(options: Partial<FormatterOptions> = {}) {
|
||||||
|
this.rules = new FormatterRules(options);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 生成格式化的PowerShell代码
|
||||||
|
*/
|
||||||
|
public generate(ast: ScriptBlockAst, comments: CommentAst[] = []): string {
|
||||||
|
this.output = [];
|
||||||
|
this.indentLevel = 0;
|
||||||
|
this.currentLineLength = 0;
|
||||||
|
this.needsNewline = false;
|
||||||
|
this.lastWasComment = false;
|
||||||
|
|
||||||
|
// 首先处理文档开头的注释
|
||||||
|
this.generateLeadingComments(comments);
|
||||||
|
|
||||||
|
// 生成主体代码
|
||||||
|
this.generateScriptBlock(ast);
|
||||||
|
|
||||||
|
// 处理文档末尾
|
||||||
|
this.handleFinalNewline();
|
||||||
|
|
||||||
|
const result = this.output.join('');
|
||||||
|
return this.postProcess(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
private generateScriptBlock(node: ScriptBlockAst): void {
|
||||||
|
for (let i = 0; i < node.statements.length; i++) {
|
||||||
|
const statement = node.statements[i];
|
||||||
|
const nextStatement = i < node.statements.length - 1 ? node.statements[i + 1] : null;
|
||||||
|
|
||||||
|
this.generateStatement(statement);
|
||||||
|
|
||||||
|
// 在语句之间添加适当的空行
|
||||||
|
if (nextStatement) {
|
||||||
|
this.addStatementSeparation(statement, nextStatement);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private generateStatement(statement: StatementAst): void {
|
||||||
|
switch (statement.type) {
|
||||||
|
case 'Pipeline':
|
||||||
|
this.generatePipeline(statement as PipelineAst);
|
||||||
|
break;
|
||||||
|
case 'Assignment':
|
||||||
|
this.generateAssignment(statement as AssignmentAst);
|
||||||
|
break;
|
||||||
|
case 'IfStatement':
|
||||||
|
this.generateIfStatement(statement as IfStatementAst);
|
||||||
|
break;
|
||||||
|
case 'FunctionDefinition':
|
||||||
|
this.generateFunctionDefinition(statement as FunctionDefinitionAst);
|
||||||
|
break;
|
||||||
|
case 'RawText':
|
||||||
|
// 处理解析失败时的原始文本
|
||||||
|
this.append((statement as any).value);
|
||||||
|
return; // 不需要添加额外的换行
|
||||||
|
default:
|
||||||
|
this.append(`/* Unsupported statement type: ${statement.type} */`);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.ensureNewline();
|
||||||
|
}
|
||||||
|
|
||||||
|
private generatePipeline(pipeline: PipelineAst): void {
|
||||||
|
if (!this.rules.formatPipelines) {
|
||||||
|
// 简单连接所有元素
|
||||||
|
for (let i = 0; i < pipeline.elements.length; i++) {
|
||||||
|
if (i > 0) {
|
||||||
|
this.append(' | ');
|
||||||
|
}
|
||||||
|
this.generatePipelineElement(pipeline.elements[i]);
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const style = this.rules.getPipelineStyle(pipeline.elements.length);
|
||||||
|
|
||||||
|
if (style === 'multiline') {
|
||||||
|
this.generateMultilinePipeline(pipeline);
|
||||||
|
} else {
|
||||||
|
this.generateOnelinePipeline(pipeline);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private generateOnelinePipeline(pipeline: PipelineAst): void {
|
||||||
|
for (let i = 0; i < pipeline.elements.length; i++) {
|
||||||
|
if (i > 0) {
|
||||||
|
this.append(' | ');
|
||||||
|
}
|
||||||
|
this.generatePipelineElement(pipeline.elements[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private generateMultilinePipeline(pipeline: PipelineAst): void {
|
||||||
|
for (let i = 0; i < pipeline.elements.length; i++) {
|
||||||
|
if (i > 0) {
|
||||||
|
this.appendLine(' |');
|
||||||
|
this.appendIndent();
|
||||||
|
}
|
||||||
|
this.generatePipelineElement(pipeline.elements[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private generatePipelineElement(element: PipelineElementAst): void {
|
||||||
|
this.generateExpression(element.expression);
|
||||||
|
}
|
||||||
|
|
||||||
|
private generateExpression(expression: ExpressionAst): void {
|
||||||
|
switch (expression.type) {
|
||||||
|
case 'Command':
|
||||||
|
this.generateCommand(expression as CommandAst);
|
||||||
|
break;
|
||||||
|
case 'Variable':
|
||||||
|
this.generateVariable(expression as VariableAst);
|
||||||
|
break;
|
||||||
|
case 'Literal':
|
||||||
|
this.generateLiteral(expression as LiteralAst);
|
||||||
|
break;
|
||||||
|
case 'BinaryExpression':
|
||||||
|
this.generateBinaryExpression(expression as BinaryExpressionAst);
|
||||||
|
break;
|
||||||
|
case 'ParenthesizedExpression':
|
||||||
|
this.append('(');
|
||||||
|
this.generateExpression((expression as any).expression);
|
||||||
|
this.append(')');
|
||||||
|
break;
|
||||||
|
case 'Array':
|
||||||
|
this.generateArray(expression as any);
|
||||||
|
break;
|
||||||
|
case 'Hashtable':
|
||||||
|
this.generateHashtable(expression as any);
|
||||||
|
break;
|
||||||
|
case 'ScriptBlockExpression':
|
||||||
|
this.generateScriptBlockExpression(expression as any);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
this.append(`/* Unsupported expression type: ${expression.type} */`);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private generateCommand(command: CommandAst): void {
|
||||||
|
// 保持cmdlet名称的连字符,不进行破坏性的格式化
|
||||||
|
let commandName = command.commandName;
|
||||||
|
|
||||||
|
// 只有在明确指定要改变大小写时才进行格式化
|
||||||
|
// 但绝对不能删除连字符
|
||||||
|
if (this.rules.shouldFormatCommandCase()) {
|
||||||
|
commandName = this.rules.formatCommandCase(commandName);
|
||||||
|
}
|
||||||
|
|
||||||
|
this.append(commandName);
|
||||||
|
|
||||||
|
// 生成参数
|
||||||
|
for (const param of command.parameters) {
|
||||||
|
this.append(' ');
|
||||||
|
this.generateParameter(param);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 生成位置参数
|
||||||
|
for (const arg of command.arguments) {
|
||||||
|
this.append(' ');
|
||||||
|
this.generateExpression(arg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private generateParameter(parameter: ParameterAst): void {
|
||||||
|
const paramName = this.rules.formatParameterCase(parameter.name);
|
||||||
|
this.append(paramName);
|
||||||
|
|
||||||
|
if (parameter.value) {
|
||||||
|
this.append(' ');
|
||||||
|
this.generateExpression(parameter.value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private generateVariable(variable: VariableAst): void {
|
||||||
|
const formattedName = this.rules.formatVariableCase(variable.name);
|
||||||
|
this.append(formattedName);
|
||||||
|
}
|
||||||
|
|
||||||
|
private generateLiteral(literal: LiteralAst): void {
|
||||||
|
if (literal.literalType === 'String') {
|
||||||
|
const formattedString = this.rules.formatQuotes(literal.value as string);
|
||||||
|
this.append(formattedString);
|
||||||
|
} else {
|
||||||
|
this.append(String(literal.value));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private generateBinaryExpression(expression: BinaryExpressionAst): void {
|
||||||
|
this.generateExpression(expression.left);
|
||||||
|
|
||||||
|
// 根据PowerShell官方规范,属性访问操作符绝对不能加空格
|
||||||
|
if (expression.operator === '.' ||
|
||||||
|
expression.operator === '::' ||
|
||||||
|
expression.operator === '[' ||
|
||||||
|
expression.operator === ']' ||
|
||||||
|
expression.operator === '@{') {
|
||||||
|
// 属性访问是PowerShell面向对象的核心,必须保持紧凑
|
||||||
|
this.append(expression.operator);
|
||||||
|
} else {
|
||||||
|
// 使用格式化规则处理其他操作符
|
||||||
|
const formattedOperator = this.rules.formatOperatorSpacing(expression.operator);
|
||||||
|
this.append(formattedOperator);
|
||||||
|
}
|
||||||
|
|
||||||
|
this.generateExpression(expression.right);
|
||||||
|
}
|
||||||
|
|
||||||
|
private generateAssignment(assignment: AssignmentAst): void {
|
||||||
|
this.generateExpression(assignment.left);
|
||||||
|
|
||||||
|
const formattedOperator = this.rules.formatOperatorSpacing(assignment.operator);
|
||||||
|
this.append(formattedOperator);
|
||||||
|
|
||||||
|
this.generateExpression(assignment.right);
|
||||||
|
}
|
||||||
|
|
||||||
|
private generateIfStatement(ifStmt: IfStatementAst): void {
|
||||||
|
// if 条件
|
||||||
|
this.append('if ');
|
||||||
|
this.append(this.rules.formatParentheses(''));
|
||||||
|
this.append('(');
|
||||||
|
this.generateExpression(ifStmt.condition);
|
||||||
|
this.append(')');
|
||||||
|
|
||||||
|
// if 主体
|
||||||
|
this.append(this.rules.getBraceStart());
|
||||||
|
this.appendLine('');
|
||||||
|
this.indent();
|
||||||
|
this.generateScriptBlock(ifStmt.ifBody);
|
||||||
|
this.outdent();
|
||||||
|
this.appendIndent();
|
||||||
|
this.append('}');
|
||||||
|
|
||||||
|
// elseif 子句
|
||||||
|
for (const elseIfClause of ifStmt.elseIfClauses) {
|
||||||
|
this.generateElseIfClause(elseIfClause);
|
||||||
|
}
|
||||||
|
|
||||||
|
// else 子句
|
||||||
|
if (ifStmt.elseBody) {
|
||||||
|
this.append(' else');
|
||||||
|
this.append(this.rules.getBraceStart());
|
||||||
|
this.appendLine('');
|
||||||
|
this.indent();
|
||||||
|
this.generateScriptBlock(ifStmt.elseBody);
|
||||||
|
this.outdent();
|
||||||
|
this.appendIndent();
|
||||||
|
this.append('}');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private generateElseIfClause(elseIf: ElseIfClauseAst): void {
|
||||||
|
this.append(' elseif (');
|
||||||
|
this.generateExpression(elseIf.condition);
|
||||||
|
this.append(')');
|
||||||
|
this.append(this.rules.getBraceStart());
|
||||||
|
this.appendLine('');
|
||||||
|
this.indent();
|
||||||
|
this.generateScriptBlock(elseIf.body);
|
||||||
|
this.outdent();
|
||||||
|
this.appendIndent();
|
||||||
|
this.append('}');
|
||||||
|
}
|
||||||
|
|
||||||
|
private generateFunctionDefinition(func: FunctionDefinitionAst): void {
|
||||||
|
// 函数前的空行
|
||||||
|
if (this.rules.blankLinesAroundFunctions > 0) {
|
||||||
|
for (let i = 0; i < this.rules.blankLinesAroundFunctions; i++) {
|
||||||
|
this.appendLine('');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
this.append('function ');
|
||||||
|
this.append(func.name);
|
||||||
|
|
||||||
|
// 参数列表
|
||||||
|
if (func.parameters.length > 0) {
|
||||||
|
this.append('(');
|
||||||
|
for (let i = 0; i < func.parameters.length; i++) {
|
||||||
|
if (i > 0) {
|
||||||
|
this.append(this.rules.formatComma());
|
||||||
|
}
|
||||||
|
this.generateParameter(func.parameters[i]);
|
||||||
|
}
|
||||||
|
this.append(')');
|
||||||
|
}
|
||||||
|
|
||||||
|
// 函数体
|
||||||
|
this.append(this.rules.getBraceStart());
|
||||||
|
this.appendLine('');
|
||||||
|
this.indent();
|
||||||
|
this.generateScriptBlock(func.body);
|
||||||
|
this.outdent();
|
||||||
|
this.appendIndent();
|
||||||
|
this.append('}');
|
||||||
|
|
||||||
|
// 函数后的空行
|
||||||
|
if (this.rules.blankLinesAroundFunctions > 0) {
|
||||||
|
for (let i = 0; i < this.rules.blankLinesAroundFunctions; i++) {
|
||||||
|
this.appendLine('');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private generateLeadingComments(comments: CommentAst[]): void {
|
||||||
|
const leadingComments = comments.filter(c => this.isLeadingComment(c));
|
||||||
|
for (const comment of leadingComments) {
|
||||||
|
this.generateComment(comment);
|
||||||
|
this.appendLine('');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private generateComment(comment: CommentAst): void {
|
||||||
|
if (!this.rules.formatComments) {
|
||||||
|
this.append(comment.text);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (comment.isMultiline) {
|
||||||
|
this.generateMultilineComment(comment.text);
|
||||||
|
} else {
|
||||||
|
this.generateSingleLineComment(comment.text);
|
||||||
|
}
|
||||||
|
|
||||||
|
this.lastWasComment = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private generateArray(arrayExpr: any): void {
|
||||||
|
this.append('@(');
|
||||||
|
if (arrayExpr.elements && arrayExpr.elements.length > 0) {
|
||||||
|
for (let i = 0; i < arrayExpr.elements.length; i++) {
|
||||||
|
if (i > 0) {
|
||||||
|
this.append(this.rules.formatComma());
|
||||||
|
}
|
||||||
|
this.generateExpression(arrayExpr.elements[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
this.append(')');
|
||||||
|
}
|
||||||
|
|
||||||
|
private generateHashtable(hashtableExpr: any): void {
|
||||||
|
this.append('@{');
|
||||||
|
|
||||||
|
if (hashtableExpr.entries && hashtableExpr.entries.length > 0) {
|
||||||
|
// 强制使用紧凑格式,避免换行问题
|
||||||
|
for (let i = 0; i < hashtableExpr.entries.length; i++) {
|
||||||
|
const entry = hashtableExpr.entries[i];
|
||||||
|
|
||||||
|
this.generateExpression(entry.key);
|
||||||
|
this.append('=');
|
||||||
|
this.generateExpression(entry.value);
|
||||||
|
|
||||||
|
// 如果不是最后一个条目,添加分号和空格
|
||||||
|
if (i < hashtableExpr.entries.length - 1) {
|
||||||
|
this.append('; ');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
this.append('}');
|
||||||
|
}
|
||||||
|
|
||||||
|
private generateScriptBlockExpression(scriptBlockExpr: any): void {
|
||||||
|
this.append('{');
|
||||||
|
|
||||||
|
// 对原始内容应用基本的格式化规则
|
||||||
|
if (scriptBlockExpr.rawContent) {
|
||||||
|
const formattedContent = this.formatScriptBlockContent(scriptBlockExpr.rawContent);
|
||||||
|
this.append(formattedContent);
|
||||||
|
} else if (scriptBlockExpr.expression) {
|
||||||
|
// 兼容旧格式
|
||||||
|
this.generateExpression(scriptBlockExpr.expression);
|
||||||
|
}
|
||||||
|
|
||||||
|
this.append('}');
|
||||||
|
}
|
||||||
|
|
||||||
|
private formatScriptBlockContent(content: string): string {
|
||||||
|
if (!content || !content.trim()) {
|
||||||
|
return content;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 应用PowerShell官方规范的格式化规则
|
||||||
|
let formatted = content.trim();
|
||||||
|
|
||||||
|
// 1. 保护所有属性访问操作符 - 这是最关键的
|
||||||
|
// 匹配所有形式的属性访问:$var.Property, $_.Property, $obj.Method.Property等
|
||||||
|
formatted = formatted.replace(/(\$[a-zA-Z_][a-zA-Z0-9_]*|\$_)\s*\.\s*([a-zA-Z_][a-zA-Z0-9_]*)/g, '$1.$2');
|
||||||
|
|
||||||
|
// 2. 保护方法调用中的点号
|
||||||
|
formatted = formatted.replace(/(\w)\s*\.\s*([a-zA-Z_][a-zA-Z0-9_]*)\s*\(/g, '$1.$2(');
|
||||||
|
|
||||||
|
// 3. 确保数字单位不被分离
|
||||||
|
formatted = formatted.replace(/(\d+)\s*(KB|MB|GB|TB|PB)/gi, '$1$2');
|
||||||
|
|
||||||
|
// 4. PowerShell比较和逻辑操作符需要前后空格
|
||||||
|
const powershellOps = [
|
||||||
|
'-eq', '-ne', '-lt', '-le', '-gt', '-ge',
|
||||||
|
'-like', '-notlike', '-match', '-notmatch',
|
||||||
|
'-contains', '-notcontains', '-in', '-notin',
|
||||||
|
'-is', '-isnot', '-as', '-and', '-or', '-not', '-xor'
|
||||||
|
];
|
||||||
|
|
||||||
|
for (const op of powershellOps) {
|
||||||
|
const regex = new RegExp(`\\s*${op.replace('-', '\\-')}\\s*`, 'gi');
|
||||||
|
formatted = formatted.replace(regex, ` ${op} `);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 5. 清理多余空格,但保护属性访问
|
||||||
|
formatted = formatted.replace(/\s{2,}/g, ' ').trim();
|
||||||
|
|
||||||
|
// 6. 最终检查:确保没有属性访问被破坏
|
||||||
|
formatted = formatted.replace(/(\$\w+|\$_)\s+\.\s*/g, '$1.');
|
||||||
|
|
||||||
|
return formatted;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private generateSingleLineComment(text: string): void {
|
||||||
|
// 确保单行注释以 # 开头
|
||||||
|
const cleanText = text.startsWith('#') ? text : `# ${text}`;
|
||||||
|
this.append(cleanText);
|
||||||
|
}
|
||||||
|
|
||||||
|
private generateMultilineComment(text: string): void {
|
||||||
|
// 多行注释保持原格式
|
||||||
|
this.append(text);
|
||||||
|
}
|
||||||
|
|
||||||
|
private isLeadingComment(comment: CommentAst): boolean {
|
||||||
|
// 简单判断:如果注释在文档开头,就认为是前导注释
|
||||||
|
return comment.line <= 3;
|
||||||
|
}
|
||||||
|
|
||||||
|
private addStatementSeparation(current: StatementAst, next: StatementAst): void {
|
||||||
|
// 函数之间添加空行
|
||||||
|
if (current.type === 'FunctionDefinition' || next.type === 'FunctionDefinition') {
|
||||||
|
this.appendLine('');
|
||||||
|
}
|
||||||
|
|
||||||
|
// 控制结构前添加空行
|
||||||
|
if (next.type === 'IfStatement' && !this.lastWasComment) {
|
||||||
|
this.appendLine('');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private handleFinalNewline(): void {
|
||||||
|
if (this.rules.insertFinalNewline && this.output.length > 0) {
|
||||||
|
const lastLine = this.output[this.output.length - 1];
|
||||||
|
if (!lastLine.endsWith(this.rules.getNewline())) {
|
||||||
|
this.appendLine('');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private postProcess(code: string): string {
|
||||||
|
let result = code;
|
||||||
|
|
||||||
|
// 清理多余的空行
|
||||||
|
if (this.rules.maxConsecutiveEmptyLines >= 0) {
|
||||||
|
const maxEmpty = this.rules.maxConsecutiveEmptyLines;
|
||||||
|
const emptyLinePattern = new RegExp(`(${this.rules.getNewline()}){${maxEmpty + 2},}`, 'g');
|
||||||
|
const replacement = this.rules.getNewline().repeat(maxEmpty + 1);
|
||||||
|
result = result.replace(emptyLinePattern, replacement);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 清理行尾空白
|
||||||
|
if (this.rules.trimTrailingWhitespace) {
|
||||||
|
result = result.replace(/ +$/gm, '');
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 辅助方法
|
||||||
|
private append(text: string): void {
|
||||||
|
this.output.push(text);
|
||||||
|
this.currentLineLength += text.length;
|
||||||
|
this.needsNewline = false;
|
||||||
|
this.lastWasComment = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
private appendLine(text: string): void {
|
||||||
|
this.output.push(text + this.rules.getNewline());
|
||||||
|
this.currentLineLength = 0;
|
||||||
|
this.needsNewline = false;
|
||||||
|
this.lastWasComment = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
private appendIndent(): void {
|
||||||
|
const indent = this.rules.getIndent(this.indentLevel);
|
||||||
|
this.append(indent);
|
||||||
|
}
|
||||||
|
|
||||||
|
private ensureNewline(): void {
|
||||||
|
if (!this.needsNewline) {
|
||||||
|
this.appendLine('');
|
||||||
|
this.needsNewline = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private indent(): void {
|
||||||
|
this.indentLevel++;
|
||||||
|
}
|
||||||
|
|
||||||
|
private outdent(): void {
|
||||||
|
this.indentLevel = Math.max(0, this.indentLevel - 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
private shouldWrapLine(): boolean {
|
||||||
|
return this.currentLineLength > this.rules.printWidth;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 便捷函数:格式化PowerShell AST
|
||||||
|
*/
|
||||||
|
export function formatPowerShellAST(
|
||||||
|
ast: ScriptBlockAst,
|
||||||
|
comments: CommentAst[] = [],
|
||||||
|
options: Partial<FormatterOptions> = {}
|
||||||
|
): string {
|
||||||
|
const generator = new PowerShellCodeGenerator(options);
|
||||||
|
return generator.generate(ast, comments);
|
||||||
|
}
|
||||||
@@ -0,0 +1,440 @@
|
|||||||
|
/**
|
||||||
|
* PowerShell 格式化规则引擎
|
||||||
|
* 定义各种可配置的代码格式化规则和策略
|
||||||
|
*/
|
||||||
|
|
||||||
|
export interface FormatterOptions {
|
||||||
|
// 基本格式化选项
|
||||||
|
indentSize: number; // 缩进大小
|
||||||
|
useTabsForIndentation: boolean; // 使用制表符还是空格
|
||||||
|
printWidth: number; // 行最大长度
|
||||||
|
endOfLine: 'lf' | 'crlf' | 'cr' | 'auto'; // 行尾符类型
|
||||||
|
|
||||||
|
// 空格和间距
|
||||||
|
spaceAroundOperators: boolean; // 操作符周围的空格
|
||||||
|
spaceAfterCommas: boolean; // 逗号后的空格
|
||||||
|
spaceAfterSemicolons: boolean; // 分号后的空格
|
||||||
|
spaceInsideParentheses: boolean; // 括号内的空格
|
||||||
|
spaceInsideBrackets: boolean; // 方括号内的空格
|
||||||
|
spaceInsideBraces: boolean; // 大括号内的空格
|
||||||
|
|
||||||
|
// 换行和空行
|
||||||
|
maxConsecutiveEmptyLines: number; // 最大连续空行数
|
||||||
|
insertFinalNewline: boolean; // 文件末尾插入换行符
|
||||||
|
trimTrailingWhitespace: boolean; // 删除行尾空白
|
||||||
|
blankLinesAroundFunctions: number; // 函数前后的空行数
|
||||||
|
blankLinesAroundClasses: number; // 类前后的空行数
|
||||||
|
blankLinesAroundIfStatements: boolean; // if语句前后的空行
|
||||||
|
|
||||||
|
// 括号和大括号
|
||||||
|
braceStyle: 'allman' | 'otbs' | 'stroustrup'; // 大括号风格
|
||||||
|
alwaysParenthesizeArrowFunctions: boolean; // 箭头函数总是用括号
|
||||||
|
|
||||||
|
// PowerShell特定选项
|
||||||
|
formatPipelines: boolean; // 格式化管道
|
||||||
|
pipelineStyle: 'oneline' | 'multiline' | 'auto'; // 管道风格
|
||||||
|
formatParameters: boolean; // 格式化参数
|
||||||
|
parameterAlignment: 'left' | 'right' | 'auto'; // 参数对齐方式
|
||||||
|
formatHashtables: boolean; // 格式化哈希表
|
||||||
|
hashtableStyle: 'compact' | 'expanded'; // 哈希表风格
|
||||||
|
formatArrays: boolean; // 格式化数组
|
||||||
|
arrayStyle: 'compact' | 'expanded'; // 数组风格
|
||||||
|
formatComments: boolean; // 格式化注释
|
||||||
|
commentAlignment: 'left' | 'preserve'; // 注释对齐方式
|
||||||
|
|
||||||
|
// 命名和大小写
|
||||||
|
preferredCommandCase: 'lowercase' | 'uppercase' | 'pascalcase' | 'preserve'; // 命令大小写
|
||||||
|
preferredParameterCase: 'lowercase' | 'uppercase' | 'pascalcase' | 'preserve'; // 参数大小写
|
||||||
|
preferredVariableCase: 'camelcase' | 'pascalcase' | 'preserve'; // 变量大小写
|
||||||
|
|
||||||
|
// 引号和字符串
|
||||||
|
quotestyle: 'single' | 'double' | 'preserve'; // 引号风格
|
||||||
|
escapeNonAscii: boolean; // 转义非ASCII字符
|
||||||
|
|
||||||
|
// 长度和换行
|
||||||
|
wrapLongLines: boolean; // 自动换行长行
|
||||||
|
wrapParameters: boolean; // 换行长参数列表
|
||||||
|
wrapArrays: boolean; // 换行长数组
|
||||||
|
wrapHashtables: boolean; // 换行长哈希表
|
||||||
|
}
|
||||||
|
|
||||||
|
export const DEFAULT_OPTIONS: FormatterOptions = {
|
||||||
|
// 基本选项
|
||||||
|
indentSize: 4,
|
||||||
|
useTabsForIndentation: false,
|
||||||
|
printWidth: 120,
|
||||||
|
endOfLine: 'auto',
|
||||||
|
|
||||||
|
// 空格设置
|
||||||
|
spaceAroundOperators: true,
|
||||||
|
spaceAfterCommas: true,
|
||||||
|
spaceAfterSemicolons: true,
|
||||||
|
spaceInsideParentheses: false,
|
||||||
|
spaceInsideBrackets: false,
|
||||||
|
spaceInsideBraces: true,
|
||||||
|
|
||||||
|
// 空行设置
|
||||||
|
maxConsecutiveEmptyLines: 2,
|
||||||
|
insertFinalNewline: true,
|
||||||
|
trimTrailingWhitespace: true,
|
||||||
|
blankLinesAroundFunctions: 1,
|
||||||
|
blankLinesAroundClasses: 1,
|
||||||
|
blankLinesAroundIfStatements: false,
|
||||||
|
|
||||||
|
// 括号风格
|
||||||
|
braceStyle: 'otbs', // One True Brace Style
|
||||||
|
alwaysParenthesizeArrowFunctions: false,
|
||||||
|
|
||||||
|
// PowerShell特定
|
||||||
|
formatPipelines: true,
|
||||||
|
pipelineStyle: 'auto',
|
||||||
|
formatParameters: true,
|
||||||
|
parameterAlignment: 'left',
|
||||||
|
formatHashtables: true,
|
||||||
|
hashtableStyle: 'compact',
|
||||||
|
formatArrays: true,
|
||||||
|
arrayStyle: 'compact',
|
||||||
|
formatComments: true,
|
||||||
|
commentAlignment: 'preserve',
|
||||||
|
|
||||||
|
// 命名约定
|
||||||
|
preferredCommandCase: 'pascalcase',
|
||||||
|
preferredParameterCase: 'preserve',
|
||||||
|
preferredVariableCase: 'preserve',
|
||||||
|
|
||||||
|
// 字符串设置
|
||||||
|
quotestyle: 'preserve',
|
||||||
|
escapeNonAscii: false,
|
||||||
|
|
||||||
|
// 长度处理
|
||||||
|
wrapLongLines: true,
|
||||||
|
wrapParameters: true,
|
||||||
|
wrapArrays: true,
|
||||||
|
wrapHashtables: true
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 格式化规则类,包含各种格式化策略的实现
|
||||||
|
*/
|
||||||
|
export class FormatterRules {
|
||||||
|
private options: FormatterOptions;
|
||||||
|
|
||||||
|
constructor(options: Partial<FormatterOptions> = {}) {
|
||||||
|
this.options = { ...DEFAULT_OPTIONS, ...options };
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取缩进字符串
|
||||||
|
*/
|
||||||
|
getIndent(level: number): string {
|
||||||
|
if (level <= 0) return '';
|
||||||
|
|
||||||
|
const indentChar = this.options.useTabsForIndentation ? '\t' : ' ';
|
||||||
|
const indentSize = this.options.useTabsForIndentation ? 1 : this.options.indentSize;
|
||||||
|
|
||||||
|
return indentChar.repeat(level * indentSize);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取换行符
|
||||||
|
*/
|
||||||
|
getNewline(): string {
|
||||||
|
switch (this.options.endOfLine) {
|
||||||
|
case 'lf': return '\n';
|
||||||
|
case 'crlf': return '\r\n';
|
||||||
|
case 'cr': return '\r';
|
||||||
|
case 'auto':
|
||||||
|
default:
|
||||||
|
// 在浏览器环境中默认使用 LF
|
||||||
|
return '\n';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 格式化操作符周围的空格
|
||||||
|
*/
|
||||||
|
formatOperatorSpacing(operator: string): string {
|
||||||
|
if (!this.options.spaceAroundOperators) {
|
||||||
|
return operator;
|
||||||
|
}
|
||||||
|
|
||||||
|
// PowerShell语法中绝对不能加空格的操作符(官方规范)
|
||||||
|
const noSpaceOperators = [
|
||||||
|
'.', '::', // 属性访问和静态成员访问 - 这是PowerShell面向对象的核心
|
||||||
|
'[', ']', // 数组索引和类型转换
|
||||||
|
'(', ')', '{', '}', // 括号
|
||||||
|
'@{', // 哈希表字面量开始
|
||||||
|
';', // 哈希表和语句分隔符
|
||||||
|
'-', // cmdlet连字符(Get-ChildItem中的-)
|
||||||
|
'::' // 静态成员访问
|
||||||
|
];
|
||||||
|
|
||||||
|
if (noSpaceOperators.includes(operator)) {
|
||||||
|
return operator;
|
||||||
|
}
|
||||||
|
|
||||||
|
// PowerShell比较操作符需要空格
|
||||||
|
const powershellOperators = ['-eq', '-ne', '-lt', '-le', '-gt', '-ge',
|
||||||
|
'-like', '-notlike', '-match', '-notmatch',
|
||||||
|
'-contains', '-notcontains', '-in', '-notin',
|
||||||
|
'-is', '-isnot', '-as', '-and', '-or', '-not', '-xor'];
|
||||||
|
|
||||||
|
if (powershellOperators.some(op => operator.toLowerCase() === op)) {
|
||||||
|
return ` ${operator} `;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 算术和赋值操作符需要空格
|
||||||
|
const spaceOperators = ['=', '+=', '-=', '*=', '/=', '%=', '+', '*', '/', '%'];
|
||||||
|
if (spaceOperators.includes(operator)) {
|
||||||
|
return ` ${operator} `;
|
||||||
|
}
|
||||||
|
|
||||||
|
return operator;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 格式化逗号后的空格
|
||||||
|
*/
|
||||||
|
formatComma(): string {
|
||||||
|
return this.options.spaceAfterCommas ? ', ' : ',';
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 格式化分号后的空格
|
||||||
|
*/
|
||||||
|
formatSemicolon(): string {
|
||||||
|
return this.options.spaceAfterSemicolons ? '; ' : ';';
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 格式化括号内的空格
|
||||||
|
*/
|
||||||
|
formatParentheses(content: string): string {
|
||||||
|
if (this.options.spaceInsideParentheses) {
|
||||||
|
return `( ${content} )`;
|
||||||
|
}
|
||||||
|
return `(${content})`;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 格式化方括号内的空格
|
||||||
|
*/
|
||||||
|
formatBrackets(content: string): string {
|
||||||
|
if (this.options.spaceInsideBrackets) {
|
||||||
|
return `[ ${content} ]`;
|
||||||
|
}
|
||||||
|
return `[${content}]`;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 格式化大括号内的空格
|
||||||
|
*/
|
||||||
|
formatBraces(content: string): string {
|
||||||
|
if (this.options.spaceInsideBraces) {
|
||||||
|
return `{ ${content} }`;
|
||||||
|
}
|
||||||
|
return `{${content}}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取大括号的开始位置
|
||||||
|
*/
|
||||||
|
getBraceStart(): string {
|
||||||
|
switch (this.options.braceStyle) {
|
||||||
|
case 'allman':
|
||||||
|
return this.getNewline() + '{';
|
||||||
|
case 'stroustrup':
|
||||||
|
return this.getNewline() + '{';
|
||||||
|
case 'otbs':
|
||||||
|
default:
|
||||||
|
return ' {';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 格式化命令名的大小写
|
||||||
|
*/
|
||||||
|
formatCommandCase(command: string): string {
|
||||||
|
switch (this.options.preferredCommandCase) {
|
||||||
|
case 'lowercase':
|
||||||
|
return command.toLowerCase();
|
||||||
|
case 'uppercase':
|
||||||
|
return command.toUpperCase();
|
||||||
|
case 'pascalcase':
|
||||||
|
return this.toPascalCasePreservingHyphens(command);
|
||||||
|
case 'preserve':
|
||||||
|
default:
|
||||||
|
return command;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 检查是否应该格式化命令大小写
|
||||||
|
*/
|
||||||
|
shouldFormatCommandCase(): boolean {
|
||||||
|
return this.options.preferredCommandCase !== 'preserve';
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 格式化参数名的大小写
|
||||||
|
*/
|
||||||
|
formatParameterCase(parameter: string): string {
|
||||||
|
switch (this.options.preferredParameterCase) {
|
||||||
|
case 'lowercase':
|
||||||
|
return parameter.toLowerCase();
|
||||||
|
case 'uppercase':
|
||||||
|
return parameter.toUpperCase();
|
||||||
|
case 'pascalcase':
|
||||||
|
return this.toPascalCase(parameter);
|
||||||
|
case 'preserve':
|
||||||
|
default:
|
||||||
|
return parameter;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 格式化变量名的大小写
|
||||||
|
*/
|
||||||
|
formatVariableCase(variable: string): string {
|
||||||
|
if (!variable.startsWith('$')) {
|
||||||
|
return variable;
|
||||||
|
}
|
||||||
|
|
||||||
|
const variableName = variable.substring(1);
|
||||||
|
let formattedName: string;
|
||||||
|
|
||||||
|
switch (this.options.preferredVariableCase) {
|
||||||
|
case 'camelcase':
|
||||||
|
formattedName = this.toCamelCase(variableName);
|
||||||
|
break;
|
||||||
|
case 'pascalcase':
|
||||||
|
formattedName = this.toPascalCase(variableName);
|
||||||
|
break;
|
||||||
|
case 'preserve':
|
||||||
|
default:
|
||||||
|
formattedName = variableName;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return '$' + formattedName;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 格式化字符串引号
|
||||||
|
*/
|
||||||
|
formatQuotes(value: string): string {
|
||||||
|
if (this.options.quotestyle === 'preserve') {
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
const content = this.extractStringContent(value);
|
||||||
|
|
||||||
|
switch (this.options.quotestyle) {
|
||||||
|
case 'single':
|
||||||
|
return `'${content.replace(/'/g, "''")}'`;
|
||||||
|
case 'double':
|
||||||
|
return `"${content.replace(/"/g, '""')}"`;
|
||||||
|
default:
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 检查是否需要换行
|
||||||
|
*/
|
||||||
|
shouldWrapLine(line: string): boolean {
|
||||||
|
return this.options.wrapLongLines && line.length > this.options.printWidth;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取管道样式
|
||||||
|
*/
|
||||||
|
getPipelineStyle(elementCount: number): 'oneline' | 'multiline' {
|
||||||
|
switch (this.options.pipelineStyle) {
|
||||||
|
case 'oneline':
|
||||||
|
return 'oneline';
|
||||||
|
case 'multiline':
|
||||||
|
return 'multiline';
|
||||||
|
case 'auto':
|
||||||
|
default:
|
||||||
|
return elementCount > 2 ? 'multiline' : 'oneline';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取哈希表样式
|
||||||
|
*/
|
||||||
|
getHashtableStyle(entryCount: number): 'compact' | 'expanded' {
|
||||||
|
if (this.options.hashtableStyle === 'compact') {
|
||||||
|
return 'compact';
|
||||||
|
}
|
||||||
|
if (this.options.hashtableStyle === 'expanded') {
|
||||||
|
return 'expanded';
|
||||||
|
}
|
||||||
|
// auto logic: 对于小型哈希表默认使用compact,避免不必要的换行
|
||||||
|
return entryCount > 5 ? 'expanded' : 'compact';
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取数组样式
|
||||||
|
*/
|
||||||
|
getArrayStyle(elementCount: number): 'compact' | 'expanded' {
|
||||||
|
if (this.options.arrayStyle === 'compact') {
|
||||||
|
return 'compact';
|
||||||
|
}
|
||||||
|
if (this.options.arrayStyle === 'expanded') {
|
||||||
|
return 'expanded';
|
||||||
|
}
|
||||||
|
// auto logic could be added here
|
||||||
|
return elementCount > 5 ? 'expanded' : 'compact';
|
||||||
|
}
|
||||||
|
|
||||||
|
// 辅助方法
|
||||||
|
private toPascalCase(str: string): string {
|
||||||
|
return str.split(/[-_\s]/)
|
||||||
|
.map(word => word.charAt(0).toUpperCase() + word.slice(1).toLowerCase())
|
||||||
|
.join('');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 转换为PascalCase但保留连字符(专门用于PowerShell cmdlet)
|
||||||
|
*/
|
||||||
|
private toPascalCasePreservingHyphens(str: string): string {
|
||||||
|
return str.split('-')
|
||||||
|
.map(part => part.charAt(0).toUpperCase() + part.slice(1).toLowerCase())
|
||||||
|
.join('-');
|
||||||
|
}
|
||||||
|
|
||||||
|
private toCamelCase(str: string): string {
|
||||||
|
const pascalCase = this.toPascalCase(str);
|
||||||
|
return pascalCase.charAt(0).toLowerCase() + pascalCase.slice(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
private extractStringContent(str: string): string {
|
||||||
|
if ((str.startsWith('"') && str.endsWith('"')) ||
|
||||||
|
(str.startsWith("'") && str.endsWith("'"))) {
|
||||||
|
return str.slice(1, -1);
|
||||||
|
}
|
||||||
|
return str;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Getter methods for options
|
||||||
|
get indentSize(): number { return this.options.indentSize; }
|
||||||
|
get printWidth(): number { return this.options.printWidth; }
|
||||||
|
get maxConsecutiveEmptyLines(): number { return this.options.maxConsecutiveEmptyLines; }
|
||||||
|
get insertFinalNewline(): boolean { return this.options.insertFinalNewline; }
|
||||||
|
get trimTrailingWhitespace(): boolean { return this.options.trimTrailingWhitespace; }
|
||||||
|
get blankLinesAroundFunctions(): number { return this.options.blankLinesAroundFunctions; }
|
||||||
|
get formatPipelines(): boolean { return this.options.formatPipelines; }
|
||||||
|
get formatParameters(): boolean { return this.options.formatParameters; }
|
||||||
|
get formatHashtables(): boolean { return this.options.formatHashtables; }
|
||||||
|
get formatArrays(): boolean { return this.options.formatArrays; }
|
||||||
|
get formatComments(): boolean { return this.options.formatComments; }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 创建规则的副本,可以重写部分选项
|
||||||
|
*/
|
||||||
|
withOptions(overrides: Partial<FormatterOptions>): FormatterRules {
|
||||||
|
return new FormatterRules({ ...this.options, ...overrides });
|
||||||
|
}
|
||||||
|
}
|
||||||
208
frontend/src/common/prettier/plugins/powershell/index.ts
Normal file
208
frontend/src/common/prettier/plugins/powershell/index.ts
Normal file
@@ -0,0 +1,208 @@
|
|||||||
|
/**
|
||||||
|
* Prettier Plugin for PowerShell file formatting - Modular Version
|
||||||
|
*
|
||||||
|
* This plugin provides support for formatting PowerShell files (.ps1, .psm1, .psd1)
|
||||||
|
* using a modular architecture with lexer, parser, AST, and code generator.
|
||||||
|
*/
|
||||||
|
import type { Plugin, Parser, Printer, AstPath, Doc } from 'prettier';
|
||||||
|
import { PowerShellLexer } from './lexer';
|
||||||
|
import { PowerShellParser } from './parser';
|
||||||
|
import { ScriptBlockAst, CommentAst } from './ast';
|
||||||
|
import { formatPowerShellAST } from './code-generator';
|
||||||
|
import { FormatterOptions, DEFAULT_OPTIONS } from './formatter-rules';
|
||||||
|
|
||||||
|
// PowerShell格式化结果接口
|
||||||
|
interface PowerShellParseResult {
|
||||||
|
ast: ScriptBlockAst;
|
||||||
|
comments: CommentAst[];
|
||||||
|
originalText: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
const parserName = 'powershell';
|
||||||
|
|
||||||
|
// 语言配置
|
||||||
|
const languages = [
|
||||||
|
{
|
||||||
|
name: 'PowerShell',
|
||||||
|
aliases: ['powershell', 'pwsh', 'posh'],
|
||||||
|
parsers: [parserName],
|
||||||
|
extensions: ['.ps1', '.psm1', '.psd1'],
|
||||||
|
filenames: ['profile.ps1'],
|
||||||
|
tmScope: 'source.powershell',
|
||||||
|
aceMode: 'powershell',
|
||||||
|
linguistLanguageId: 295,
|
||||||
|
vscodeLanguageIds: ['powershell']
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
// 解析器配置
|
||||||
|
const powershellParser: Parser<PowerShellParseResult> = {
|
||||||
|
parse: parseCode,
|
||||||
|
astFormat: 'powershell',
|
||||||
|
locStart: (node: PowerShellParseResult) => 0,
|
||||||
|
locEnd: (node: PowerShellParseResult) => node.originalText.length,
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 解析PowerShell代码
|
||||||
|
*/
|
||||||
|
async function parseCode(text: string, parsers?: any, options?: any): Promise<PowerShellParseResult> {
|
||||||
|
try {
|
||||||
|
// 词法分析
|
||||||
|
const lexer = new PowerShellLexer(text);
|
||||||
|
const tokens = lexer.tokenize();
|
||||||
|
|
||||||
|
// 语法分析
|
||||||
|
const parser = new PowerShellParser(tokens, text);
|
||||||
|
const ast = parser.parse();
|
||||||
|
const comments = parser.getComments();
|
||||||
|
|
||||||
|
return {
|
||||||
|
ast,
|
||||||
|
comments,
|
||||||
|
originalText: text
|
||||||
|
};
|
||||||
|
} catch (error) {
|
||||||
|
console.warn('PowerShell parsing failed, using fallback:', error);
|
||||||
|
|
||||||
|
// 解析失败时,创建一个包含原始文本的简单AST
|
||||||
|
// 这样可以确保格式化失败时返回原始代码而不是空内容
|
||||||
|
return {
|
||||||
|
ast: {
|
||||||
|
type: 'ScriptBlock',
|
||||||
|
statements: [{
|
||||||
|
type: 'RawText',
|
||||||
|
value: text,
|
||||||
|
start: 0,
|
||||||
|
end: text.length,
|
||||||
|
line: 1,
|
||||||
|
column: 1
|
||||||
|
} as any],
|
||||||
|
start: 0,
|
||||||
|
end: text.length,
|
||||||
|
line: 1,
|
||||||
|
column: 1
|
||||||
|
},
|
||||||
|
comments: [],
|
||||||
|
originalText: text
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* PowerShell代码打印器
|
||||||
|
*/
|
||||||
|
const printPowerShell = (path: AstPath<PowerShellParseResult>, options: any): Doc => {
|
||||||
|
const parseResult = path.node;
|
||||||
|
|
||||||
|
try {
|
||||||
|
// 构建格式化选项 - 优先保持原有格式,避免破坏PowerShell语法
|
||||||
|
const formatterOptions: Partial<FormatterOptions> = {
|
||||||
|
indentSize: options.tabWidth || DEFAULT_OPTIONS.indentSize,
|
||||||
|
useTabsForIndentation: options.useTabs || DEFAULT_OPTIONS.useTabsForIndentation,
|
||||||
|
printWidth: options.printWidth || DEFAULT_OPTIONS.printWidth,
|
||||||
|
spaceAroundOperators: true,
|
||||||
|
formatPipelines: true,
|
||||||
|
formatParameters: true,
|
||||||
|
formatHashtables: true,
|
||||||
|
hashtableStyle: 'compact', // 强制使用紧凑格式,避免不必要的换行
|
||||||
|
formatArrays: true,
|
||||||
|
arrayStyle: 'compact',
|
||||||
|
formatComments: true,
|
||||||
|
maxConsecutiveEmptyLines: 1,
|
||||||
|
insertFinalNewline: true,
|
||||||
|
trimTrailingWhitespace: true,
|
||||||
|
blankLinesAroundFunctions: 1,
|
||||||
|
braceStyle: 'otbs',
|
||||||
|
preferredCommandCase: 'preserve', // 保持原有命令大小写,不破坏语法
|
||||||
|
preferredParameterCase: 'preserve',
|
||||||
|
preferredVariableCase: 'preserve',
|
||||||
|
quotestyle: 'preserve',
|
||||||
|
wrapLongLines: true
|
||||||
|
};
|
||||||
|
|
||||||
|
// 使用新的模块化格式化器
|
||||||
|
const formattedCode = formatPowerShellAST(
|
||||||
|
parseResult.ast,
|
||||||
|
parseResult.comments,
|
||||||
|
formatterOptions
|
||||||
|
);
|
||||||
|
|
||||||
|
return formattedCode;
|
||||||
|
} catch (error) {
|
||||||
|
console.warn('PowerShell formatting failed, returning original code:', error);
|
||||||
|
return parseResult.originalText;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// 打印器配置
|
||||||
|
const powershellPrinter: Printer<PowerShellParseResult> = {
|
||||||
|
print: printPowerShell,
|
||||||
|
};
|
||||||
|
|
||||||
|
// 插件选项配置
|
||||||
|
const options = {
|
||||||
|
// PowerShell特定格式化选项
|
||||||
|
powershellBraceStyle: {
|
||||||
|
type: 'choice' as const,
|
||||||
|
category: 'PowerShell',
|
||||||
|
default: DEFAULT_OPTIONS.braceStyle,
|
||||||
|
description: 'PowerShell大括号样式',
|
||||||
|
choices: [
|
||||||
|
{ value: 'allman', description: 'Allman风格(大括号另起一行)' },
|
||||||
|
{ value: 'otbs', description: '1TBS风格(大括号同行)' },
|
||||||
|
{ value: 'stroustrup', description: 'Stroustrup风格' }
|
||||||
|
]
|
||||||
|
},
|
||||||
|
powershellCommandCase: {
|
||||||
|
type: 'choice' as const,
|
||||||
|
category: 'PowerShell',
|
||||||
|
default: DEFAULT_OPTIONS.preferredCommandCase,
|
||||||
|
description: 'PowerShell命令大小写风格',
|
||||||
|
choices: [
|
||||||
|
{ value: 'lowercase', description: '小写' },
|
||||||
|
{ value: 'uppercase', description: '大写' },
|
||||||
|
{ value: 'pascalcase', description: 'Pascal大小写' },
|
||||||
|
{ value: 'preserve', description: '保持原样' }
|
||||||
|
]
|
||||||
|
},
|
||||||
|
powershellPipelineStyle: {
|
||||||
|
type: 'choice' as const,
|
||||||
|
category: 'PowerShell',
|
||||||
|
default: DEFAULT_OPTIONS.pipelineStyle,
|
||||||
|
description: 'PowerShell管道样式',
|
||||||
|
choices: [
|
||||||
|
{ value: 'oneline', description: '单行' },
|
||||||
|
{ value: 'multiline', description: '多行' },
|
||||||
|
{ value: 'auto', description: '自动' }
|
||||||
|
]
|
||||||
|
},
|
||||||
|
powershellSpaceAroundOperators: {
|
||||||
|
type: 'boolean' as const,
|
||||||
|
category: 'PowerShell',
|
||||||
|
default: DEFAULT_OPTIONS.spaceAroundOperators,
|
||||||
|
description: '在操作符周围添加空格'
|
||||||
|
},
|
||||||
|
powershellMaxEmptyLines: {
|
||||||
|
type: 'int' as const,
|
||||||
|
category: 'PowerShell',
|
||||||
|
default: DEFAULT_OPTIONS.maxConsecutiveEmptyLines,
|
||||||
|
description: '最大连续空行数'
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const powershellPlugin: Plugin = {
|
||||||
|
languages,
|
||||||
|
parsers: {
|
||||||
|
[parserName]: powershellParser,
|
||||||
|
},
|
||||||
|
printers: {
|
||||||
|
[parserName]: powershellPrinter,
|
||||||
|
},
|
||||||
|
options,
|
||||||
|
};
|
||||||
|
|
||||||
|
export default powershellPlugin;
|
||||||
|
export { languages };
|
||||||
|
export const parsers = powershellPlugin.parsers;
|
||||||
|
export const printers = powershellPlugin.printers;
|
||||||
722
frontend/src/common/prettier/plugins/powershell/lexer.ts
Normal file
722
frontend/src/common/prettier/plugins/powershell/lexer.ts
Normal file
@@ -0,0 +1,722 @@
|
|||||||
|
/**
|
||||||
|
* PowerShell 词法分析器 (Lexer)
|
||||||
|
* 将PowerShell代码分解为tokens,用于后续的语法分析和格式化
|
||||||
|
*/
|
||||||
|
|
||||||
|
export enum TokenType {
|
||||||
|
// 字面量
|
||||||
|
STRING = 'STRING',
|
||||||
|
NUMBER = 'NUMBER',
|
||||||
|
VARIABLE = 'VARIABLE',
|
||||||
|
|
||||||
|
// 关键字
|
||||||
|
KEYWORD = 'KEYWORD',
|
||||||
|
FUNCTION = 'FUNCTION',
|
||||||
|
|
||||||
|
// 操作符
|
||||||
|
OPERATOR = 'OPERATOR',
|
||||||
|
ASSIGNMENT = 'ASSIGNMENT',
|
||||||
|
COMPARISON = 'COMPARISON',
|
||||||
|
LOGICAL = 'LOGICAL',
|
||||||
|
ARITHMETIC = 'ARITHMETIC',
|
||||||
|
|
||||||
|
// 分隔符
|
||||||
|
LEFT_PAREN = 'LEFT_PAREN',
|
||||||
|
RIGHT_PAREN = 'RIGHT_PAREN',
|
||||||
|
LEFT_BRACE = 'LEFT_BRACE',
|
||||||
|
RIGHT_BRACE = 'RIGHT_BRACE',
|
||||||
|
LEFT_BRACKET = 'LEFT_BRACKET',
|
||||||
|
RIGHT_BRACKET = 'RIGHT_BRACKET',
|
||||||
|
SEMICOLON = 'SEMICOLON',
|
||||||
|
COMMA = 'COMMA',
|
||||||
|
DOT = 'DOT',
|
||||||
|
PIPE = 'PIPE',
|
||||||
|
|
||||||
|
// 特殊
|
||||||
|
WHITESPACE = 'WHITESPACE',
|
||||||
|
NEWLINE = 'NEWLINE',
|
||||||
|
COMMENT = 'COMMENT',
|
||||||
|
MULTILINE_COMMENT = 'MULTILINE_COMMENT',
|
||||||
|
HERE_STRING = 'HERE_STRING',
|
||||||
|
|
||||||
|
// 控制结构
|
||||||
|
IF = 'IF',
|
||||||
|
ELSE = 'ELSE',
|
||||||
|
ELSEIF = 'ELSEIF',
|
||||||
|
WHILE = 'WHILE',
|
||||||
|
FOR = 'FOR',
|
||||||
|
FOREACH = 'FOREACH',
|
||||||
|
SWITCH = 'SWITCH',
|
||||||
|
TRY = 'TRY',
|
||||||
|
CATCH = 'CATCH',
|
||||||
|
FINALLY = 'FINALLY',
|
||||||
|
|
||||||
|
// 其他
|
||||||
|
IDENTIFIER = 'IDENTIFIER',
|
||||||
|
CMDLET = 'CMDLET',
|
||||||
|
PARAMETER = 'PARAMETER',
|
||||||
|
EOF = 'EOF',
|
||||||
|
UNKNOWN = 'UNKNOWN'
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface Token {
|
||||||
|
type: TokenType;
|
||||||
|
value: string;
|
||||||
|
line: number;
|
||||||
|
column: number;
|
||||||
|
startIndex: number;
|
||||||
|
endIndex: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
export class PowerShellLexer {
|
||||||
|
private code: string;
|
||||||
|
private position: number = 0;
|
||||||
|
private line: number = 1;
|
||||||
|
private column: number = 1;
|
||||||
|
private tokens: Token[] = [];
|
||||||
|
|
||||||
|
// PowerShell关键字
|
||||||
|
private readonly keywords = new Set([
|
||||||
|
'if', 'else', 'elseif', 'switch', 'while', 'for', 'foreach', 'do',
|
||||||
|
'try', 'catch', 'finally', 'throw', 'return', 'break', 'continue',
|
||||||
|
'function', 'filter', 'param', 'begin', 'process', 'end',
|
||||||
|
'class', 'enum', 'using', 'namespace', 'workflow', 'configuration',
|
||||||
|
'dynamicparam', 'exit'
|
||||||
|
]);
|
||||||
|
|
||||||
|
// PowerShell比较操作符
|
||||||
|
private readonly comparisonOperators = new Set([
|
||||||
|
'-eq', '-ne', '-lt', '-le', '-gt', '-ge',
|
||||||
|
'-like', '-notlike', '-match', '-notmatch',
|
||||||
|
'-contains', '-notcontains', '-in', '-notin',
|
||||||
|
'-is', '-isnot', '-as'
|
||||||
|
]);
|
||||||
|
|
||||||
|
// PowerShell逻辑操作符
|
||||||
|
private readonly logicalOperators = new Set([
|
||||||
|
'-and', '-or', '-not', '-xor', '-band', '-bor', '-bxor', '-bnot'
|
||||||
|
]);
|
||||||
|
|
||||||
|
constructor(code: string) {
|
||||||
|
this.code = code;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 对代码进行词法分析,返回token数组
|
||||||
|
*/
|
||||||
|
public tokenize(): Token[] {
|
||||||
|
this.position = 0;
|
||||||
|
this.line = 1;
|
||||||
|
this.column = 1;
|
||||||
|
this.tokens = [];
|
||||||
|
|
||||||
|
while (this.position < this.code.length) {
|
||||||
|
this.skipWhitespace();
|
||||||
|
|
||||||
|
if (this.position >= this.code.length) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
const token = this.nextToken();
|
||||||
|
if (token) {
|
||||||
|
this.tokens.push(token);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
this.tokens.push({
|
||||||
|
type: TokenType.EOF,
|
||||||
|
value: '',
|
||||||
|
line: this.line,
|
||||||
|
column: this.column,
|
||||||
|
startIndex: this.position,
|
||||||
|
endIndex: this.position
|
||||||
|
});
|
||||||
|
|
||||||
|
return this.tokens;
|
||||||
|
}
|
||||||
|
|
||||||
|
private nextToken(): Token | null {
|
||||||
|
const startPos = this.position;
|
||||||
|
const startLine = this.line;
|
||||||
|
const startColumn = this.column;
|
||||||
|
|
||||||
|
const char = this.code[this.position];
|
||||||
|
|
||||||
|
// 处理换行
|
||||||
|
if (char === '\n') {
|
||||||
|
this.advance();
|
||||||
|
return this.createToken(TokenType.NEWLINE, '\n', startPos, startLine, startColumn);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 处理注释
|
||||||
|
if (char === '#') {
|
||||||
|
return this.tokenizeComment(startPos, startLine, startColumn);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 处理多行注释
|
||||||
|
if (char === '<' && this.peek() === '#') {
|
||||||
|
return this.tokenizeMultilineComment(startPos, startLine, startColumn);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 处理字符串
|
||||||
|
if (char === '"' || char === "'") {
|
||||||
|
return this.tokenizeString(startPos, startLine, startColumn);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 处理Here-String
|
||||||
|
if (char === '@' && (this.peek() === '"' || this.peek() === "'")) {
|
||||||
|
return this.tokenizeHereString(startPos, startLine, startColumn);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 处理哈希表字面量 @{
|
||||||
|
if (char === '@' && this.peek() === '{') {
|
||||||
|
this.advance(); // skip '@'
|
||||||
|
this.advance(); // skip '{'
|
||||||
|
return this.createToken(TokenType.LEFT_BRACE, '@{', startPos, startLine, startColumn);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 处理变量
|
||||||
|
if (char === '$') {
|
||||||
|
return this.tokenizeVariable(startPos, startLine, startColumn);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 处理数字
|
||||||
|
if (this.isDigit(char) || (char === '.' && this.isDigit(this.peek()))) {
|
||||||
|
return this.tokenizeNumber(startPos, startLine, startColumn);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 处理操作符和分隔符
|
||||||
|
const operatorToken = this.tokenizeOperator(startPos, startLine, startColumn);
|
||||||
|
if (operatorToken) {
|
||||||
|
return operatorToken;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 优先处理PowerShell比较操作符(以-开头)
|
||||||
|
if (char === '-' && this.isIdentifierStart(this.peek())) {
|
||||||
|
const potentialOperator = this.peekPowerShellOperator();
|
||||||
|
if (potentialOperator) {
|
||||||
|
return this.tokenizePowerShellOperator(startPos, startLine, startColumn);
|
||||||
|
}
|
||||||
|
// 如果不是操作符,可能是参数
|
||||||
|
return this.tokenizeParameter(startPos, startLine, startColumn);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 处理标识符(包括cmdlet和关键字)
|
||||||
|
if (this.isIdentifierStart(char)) {
|
||||||
|
return this.tokenizeIdentifier(startPos, startLine, startColumn);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 处理PowerShell特殊字符
|
||||||
|
if (char === '?') {
|
||||||
|
this.advance();
|
||||||
|
return this.createToken(TokenType.OPERATOR, char, startPos, startLine, startColumn);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 处理独立的减号(可能是负数或减法)
|
||||||
|
if (char === '-') {
|
||||||
|
this.advance();
|
||||||
|
return this.createToken(TokenType.ARITHMETIC, char, startPos, startLine, startColumn);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 处理其他可能的特殊字符,作为标识符处理而不是未知字符
|
||||||
|
if (this.isPrintableChar(char)) {
|
||||||
|
this.advance();
|
||||||
|
return this.createToken(TokenType.IDENTIFIER, char, startPos, startLine, startColumn);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 真正的未知字符(非打印字符等)
|
||||||
|
this.advance();
|
||||||
|
return this.createToken(TokenType.UNKNOWN, char, startPos, startLine, startColumn);
|
||||||
|
}
|
||||||
|
|
||||||
|
private tokenizeComment(startPos: number, startLine: number, startColumn: number): Token {
|
||||||
|
let value = '';
|
||||||
|
while (this.position < this.code.length && this.code[this.position] !== '\n') {
|
||||||
|
value += this.code[this.position];
|
||||||
|
this.advance();
|
||||||
|
}
|
||||||
|
return this.createToken(TokenType.COMMENT, value, startPos, startLine, startColumn);
|
||||||
|
}
|
||||||
|
|
||||||
|
private tokenizeMultilineComment(startPos: number, startLine: number, startColumn: number): Token {
|
||||||
|
let value = '';
|
||||||
|
this.advance(); // skip '<'
|
||||||
|
this.advance(); // skip '#'
|
||||||
|
value += '<#';
|
||||||
|
|
||||||
|
while (this.position < this.code.length - 1) {
|
||||||
|
if (this.code[this.position] === '#' && this.code[this.position + 1] === '>') {
|
||||||
|
value += '#>';
|
||||||
|
this.advance();
|
||||||
|
this.advance();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
value += this.code[this.position];
|
||||||
|
this.advance();
|
||||||
|
}
|
||||||
|
|
||||||
|
return this.createToken(TokenType.MULTILINE_COMMENT, value, startPos, startLine, startColumn);
|
||||||
|
}
|
||||||
|
|
||||||
|
private tokenizeString(startPos: number, startLine: number, startColumn: number): Token {
|
||||||
|
const quote = this.code[this.position];
|
||||||
|
let value = quote;
|
||||||
|
this.advance();
|
||||||
|
|
||||||
|
while (this.position < this.code.length) {
|
||||||
|
const char = this.code[this.position];
|
||||||
|
value += char;
|
||||||
|
|
||||||
|
if (char === quote) {
|
||||||
|
this.advance();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 处理转义字符
|
||||||
|
if (char === '`' && quote === '"') {
|
||||||
|
this.advance();
|
||||||
|
if (this.position < this.code.length) {
|
||||||
|
value += this.code[this.position];
|
||||||
|
this.advance();
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
this.advance();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return this.createToken(TokenType.STRING, value, startPos, startLine, startColumn);
|
||||||
|
}
|
||||||
|
|
||||||
|
private tokenizeHereString(startPos: number, startLine: number, startColumn: number): Token {
|
||||||
|
const quote = this.code[this.position + 1]; // " or '
|
||||||
|
let value = `@${quote}`;
|
||||||
|
this.advance(); // skip '@'
|
||||||
|
this.advance(); // skip quote
|
||||||
|
|
||||||
|
while (this.position < this.code.length - 1) {
|
||||||
|
if (this.code[this.position] === quote && this.code[this.position + 1] === '@') {
|
||||||
|
value += `${quote}@`;
|
||||||
|
this.advance();
|
||||||
|
this.advance();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
value += this.code[this.position];
|
||||||
|
this.advance();
|
||||||
|
}
|
||||||
|
|
||||||
|
return this.createToken(TokenType.HERE_STRING, value, startPos, startLine, startColumn);
|
||||||
|
}
|
||||||
|
|
||||||
|
private tokenizeVariable(startPos: number, startLine: number, startColumn: number): Token {
|
||||||
|
let value = '$';
|
||||||
|
this.advance(); // skip '$'
|
||||||
|
|
||||||
|
// 处理特殊变量如 $_, $$, $^
|
||||||
|
const specialVars = ['_', '$', '^', '?'];
|
||||||
|
if (specialVars.includes(this.code[this.position])) {
|
||||||
|
value += this.code[this.position];
|
||||||
|
this.advance();
|
||||||
|
return this.createToken(TokenType.VARIABLE, value, startPos, startLine, startColumn);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 处理大括号变量 ${variable name}
|
||||||
|
if (this.code[this.position] === '{') {
|
||||||
|
this.advance(); // skip '{'
|
||||||
|
value += '{';
|
||||||
|
while (this.position < this.code.length && this.code[this.position] !== '}') {
|
||||||
|
value += this.code[this.position];
|
||||||
|
this.advance();
|
||||||
|
}
|
||||||
|
if (this.position < this.code.length) {
|
||||||
|
value += '}';
|
||||||
|
this.advance(); // skip '}'
|
||||||
|
}
|
||||||
|
return this.createToken(TokenType.VARIABLE, value, startPos, startLine, startColumn);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 普通变量名
|
||||||
|
while (this.position < this.code.length && this.isIdentifierChar(this.code[this.position])) {
|
||||||
|
value += this.code[this.position];
|
||||||
|
this.advance();
|
||||||
|
}
|
||||||
|
|
||||||
|
return this.createToken(TokenType.VARIABLE, value, startPos, startLine, startColumn);
|
||||||
|
}
|
||||||
|
|
||||||
|
private tokenizeNumber(startPos: number, startLine: number, startColumn: number): Token {
|
||||||
|
let value = '';
|
||||||
|
let hasDecimal = false;
|
||||||
|
|
||||||
|
while (this.position < this.code.length) {
|
||||||
|
const char = this.code[this.position];
|
||||||
|
|
||||||
|
if (this.isDigit(char)) {
|
||||||
|
value += char;
|
||||||
|
this.advance();
|
||||||
|
} else if (char === '.' && !hasDecimal && this.isDigit(this.peek())) {
|
||||||
|
hasDecimal = true;
|
||||||
|
value += char;
|
||||||
|
this.advance();
|
||||||
|
} else {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 检查是否有PowerShell数字单位后缀(KB, MB, GB, TB, PB)
|
||||||
|
const unitPattern = /^(KB|MB|GB|TB|PB)/i;
|
||||||
|
const remainingCode = this.code.substring(this.position);
|
||||||
|
const unitMatch = remainingCode.match(unitPattern);
|
||||||
|
|
||||||
|
if (unitMatch) {
|
||||||
|
value += unitMatch[0]; // 使用 [0] 获取完整匹配
|
||||||
|
// 移动position到单位后面
|
||||||
|
for (let i = 0; i < unitMatch[0].length; i++) {
|
||||||
|
this.advance();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return this.createToken(TokenType.NUMBER, value, startPos, startLine, startColumn);
|
||||||
|
}
|
||||||
|
|
||||||
|
private tokenizeOperator(startPos: number, startLine: number, startColumn: number): Token | null {
|
||||||
|
const char = this.code[this.position];
|
||||||
|
|
||||||
|
// 双字符操作符
|
||||||
|
const twoChar = this.code.substring(this.position, this.position + 2);
|
||||||
|
const doubleOperators = ['==', '!=', '<=', '>=', '++', '--', '+=', '-=', '*=', '/=', '%='];
|
||||||
|
|
||||||
|
if (doubleOperators.includes(twoChar)) {
|
||||||
|
this.advance();
|
||||||
|
this.advance();
|
||||||
|
return this.createToken(TokenType.OPERATOR, twoChar, startPos, startLine, startColumn);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 单字符操作符
|
||||||
|
switch (char) {
|
||||||
|
case '=':
|
||||||
|
this.advance();
|
||||||
|
return this.createToken(TokenType.ASSIGNMENT, char, startPos, startLine, startColumn);
|
||||||
|
case '+':
|
||||||
|
case '*':
|
||||||
|
case '/':
|
||||||
|
case '%':
|
||||||
|
this.advance();
|
||||||
|
return this.createToken(TokenType.ARITHMETIC, char, startPos, startLine, startColumn);
|
||||||
|
case '-':
|
||||||
|
// 不在这里处理'-',让PowerShell操作符检查优先处理
|
||||||
|
return null;
|
||||||
|
case '(':
|
||||||
|
this.advance();
|
||||||
|
return this.createToken(TokenType.LEFT_PAREN, char, startPos, startLine, startColumn);
|
||||||
|
case ')':
|
||||||
|
this.advance();
|
||||||
|
return this.createToken(TokenType.RIGHT_PAREN, char, startPos, startLine, startColumn);
|
||||||
|
case '{':
|
||||||
|
this.advance();
|
||||||
|
return this.createToken(TokenType.LEFT_BRACE, char, startPos, startLine, startColumn);
|
||||||
|
case '}':
|
||||||
|
this.advance();
|
||||||
|
return this.createToken(TokenType.RIGHT_BRACE, char, startPos, startLine, startColumn);
|
||||||
|
case '[':
|
||||||
|
// 检查是否是PowerShell类型转换 [type]
|
||||||
|
const typePattern = this.peekTypeConversion();
|
||||||
|
if (typePattern) {
|
||||||
|
return this.tokenizeTypeConversion(startPos, startLine, startColumn);
|
||||||
|
}
|
||||||
|
this.advance();
|
||||||
|
return this.createToken(TokenType.LEFT_BRACKET, char, startPos, startLine, startColumn);
|
||||||
|
case ']':
|
||||||
|
this.advance();
|
||||||
|
return this.createToken(TokenType.RIGHT_BRACKET, char, startPos, startLine, startColumn);
|
||||||
|
case ';':
|
||||||
|
this.advance();
|
||||||
|
return this.createToken(TokenType.SEMICOLON, char, startPos, startLine, startColumn);
|
||||||
|
case ',':
|
||||||
|
this.advance();
|
||||||
|
return this.createToken(TokenType.COMMA, char, startPos, startLine, startColumn);
|
||||||
|
case '.':
|
||||||
|
this.advance();
|
||||||
|
return this.createToken(TokenType.DOT, char, startPos, startLine, startColumn);
|
||||||
|
case '|':
|
||||||
|
this.advance();
|
||||||
|
return this.createToken(TokenType.PIPE, char, startPos, startLine, startColumn);
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private tokenizeIdentifier(startPos: number, startLine: number, startColumn: number): Token {
|
||||||
|
let value = '';
|
||||||
|
|
||||||
|
// 改进的标识符识别,支持PowerShell cmdlet格式(动词-名词)
|
||||||
|
while (this.position < this.code.length) {
|
||||||
|
const char = this.code[this.position];
|
||||||
|
|
||||||
|
if (this.isIdentifierChar(char)) {
|
||||||
|
value += char;
|
||||||
|
this.advance();
|
||||||
|
} else if (char === '-' && value.length > 0 && this.isIdentifierStart(this.peek())) {
|
||||||
|
// 检查是否是cmdlet格式(动词-名词)
|
||||||
|
const nextPart = this.peekIdentifierPart();
|
||||||
|
if (nextPart && !this.isPowerShellOperator('-' + nextPart)) {
|
||||||
|
// 这是cmdlet名字的一部分,继续
|
||||||
|
value += char;
|
||||||
|
this.advance();
|
||||||
|
} else {
|
||||||
|
// 这可能是操作符,停止
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const lowerValue = value.toLowerCase();
|
||||||
|
|
||||||
|
// 检查是否是关键字
|
||||||
|
if (this.keywords.has(lowerValue)) {
|
||||||
|
return this.createToken(this.getKeywordTokenType(lowerValue), value, startPos, startLine, startColumn);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 检查是否是函数(以动词-名词格式)
|
||||||
|
if (this.isCmdletName(value)) {
|
||||||
|
return this.createToken(TokenType.CMDLET, value, startPos, startLine, startColumn);
|
||||||
|
}
|
||||||
|
|
||||||
|
return this.createToken(TokenType.IDENTIFIER, value, startPos, startLine, startColumn);
|
||||||
|
}
|
||||||
|
|
||||||
|
private tokenizeParameter(startPos: number, startLine: number, startColumn: number): Token {
|
||||||
|
let value = '';
|
||||||
|
|
||||||
|
while (this.position < this.code.length && (this.isIdentifierChar(this.code[this.position]) || this.code[this.position] === '-')) {
|
||||||
|
value += this.code[this.position];
|
||||||
|
this.advance();
|
||||||
|
}
|
||||||
|
|
||||||
|
const lowerValue = value.toLowerCase();
|
||||||
|
|
||||||
|
// 检查是否是比较操作符
|
||||||
|
if (this.comparisonOperators.has(lowerValue)) {
|
||||||
|
return this.createToken(TokenType.COMPARISON, value, startPos, startLine, startColumn);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 检查是否是逻辑操作符
|
||||||
|
if (this.logicalOperators.has(lowerValue)) {
|
||||||
|
return this.createToken(TokenType.LOGICAL, value, startPos, startLine, startColumn);
|
||||||
|
}
|
||||||
|
|
||||||
|
return this.createToken(TokenType.PARAMETER, value, startPos, startLine, startColumn);
|
||||||
|
}
|
||||||
|
|
||||||
|
private getKeywordTokenType(keyword: string): TokenType {
|
||||||
|
switch (keyword) {
|
||||||
|
case 'if': return TokenType.IF;
|
||||||
|
case 'else': return TokenType.ELSE;
|
||||||
|
case 'elseif': return TokenType.ELSEIF;
|
||||||
|
case 'while': return TokenType.WHILE;
|
||||||
|
case 'for': return TokenType.FOR;
|
||||||
|
case 'foreach': return TokenType.FOREACH;
|
||||||
|
case 'switch': return TokenType.SWITCH;
|
||||||
|
case 'try': return TokenType.TRY;
|
||||||
|
case 'catch': return TokenType.CATCH;
|
||||||
|
case 'finally': return TokenType.FINALLY;
|
||||||
|
case 'function': return TokenType.FUNCTION;
|
||||||
|
default: return TokenType.KEYWORD;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private isCmdletName(name: string): boolean {
|
||||||
|
// PowerShell cmdlet通常遵循 Verb-Noun 格式,可能包含多个连字符
|
||||||
|
const verbNounPattern = /^[A-Za-z]+(-[A-Za-z]+)+$/;
|
||||||
|
return verbNounPattern.test(name);
|
||||||
|
}
|
||||||
|
|
||||||
|
private peekPowerShellOperator(): string | null {
|
||||||
|
// 检查是否是PowerShell比较或逻辑操作符
|
||||||
|
const operatorPatterns = [
|
||||||
|
'-eq', '-ne', '-lt', '-le', '-gt', '-ge',
|
||||||
|
'-like', '-notlike', '-match', '-notmatch',
|
||||||
|
'-contains', '-notcontains', '-in', '-notin',
|
||||||
|
'-is', '-isnot', '-as',
|
||||||
|
'-and', '-or', '-not', '-xor',
|
||||||
|
'-band', '-bor', '-bxor', '-bnot'
|
||||||
|
];
|
||||||
|
|
||||||
|
for (const op of operatorPatterns) {
|
||||||
|
if (this.matchesOperator(op)) {
|
||||||
|
return op;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private matchesOperator(operator: string): boolean {
|
||||||
|
if (this.position + operator.length > this.code.length) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
const substr = this.code.substring(this.position, this.position + operator.length);
|
||||||
|
if (substr.toLowerCase() !== operator.toLowerCase()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 确保操作符后面不是字母数字字符(避免匹配部分单词)
|
||||||
|
const nextChar = this.position + operator.length < this.code.length
|
||||||
|
? this.code[this.position + operator.length]
|
||||||
|
: ' ';
|
||||||
|
return !this.isIdentifierChar(nextChar);
|
||||||
|
}
|
||||||
|
|
||||||
|
private tokenizePowerShellOperator(startPos: number, startLine: number, startColumn: number): Token {
|
||||||
|
const operator = this.peekPowerShellOperator();
|
||||||
|
if (!operator) {
|
||||||
|
// 如果不是操作符,作为参数处理
|
||||||
|
return this.tokenizeParameter(startPos, startLine, startColumn);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 消费操作符字符
|
||||||
|
for (let i = 0; i < operator.length; i++) {
|
||||||
|
this.advance();
|
||||||
|
}
|
||||||
|
|
||||||
|
const lowerOp = operator.toLowerCase();
|
||||||
|
|
||||||
|
// 确定操作符类型
|
||||||
|
if (this.comparisonOperators.has(lowerOp)) {
|
||||||
|
return this.createToken(TokenType.COMPARISON, operator, startPos, startLine, startColumn);
|
||||||
|
} else if (this.logicalOperators.has(lowerOp)) {
|
||||||
|
return this.createToken(TokenType.LOGICAL, operator, startPos, startLine, startColumn);
|
||||||
|
} else {
|
||||||
|
return this.createToken(TokenType.OPERATOR, operator, startPos, startLine, startColumn);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private peekIdentifierPart(): string | null {
|
||||||
|
if (this.position + 1 >= this.code.length) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
let result = '';
|
||||||
|
let pos = this.position + 1; // 跳过连字符
|
||||||
|
|
||||||
|
while (pos < this.code.length && this.isIdentifierChar(this.code[pos])) {
|
||||||
|
result += this.code[pos];
|
||||||
|
pos++;
|
||||||
|
}
|
||||||
|
|
||||||
|
return result.length > 0 ? result : null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private isPowerShellOperator(text: string): boolean {
|
||||||
|
const lowerText = text.toLowerCase();
|
||||||
|
return this.comparisonOperators.has(lowerText) || this.logicalOperators.has(lowerText);
|
||||||
|
}
|
||||||
|
|
||||||
|
private peekTypeConversion(): string | null {
|
||||||
|
// 检查是否是PowerShell类型转换,如 [int], [string], [datetime] 等
|
||||||
|
if (this.code[this.position] !== '[') {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
let pos = this.position + 1; // 跳过 '['
|
||||||
|
let typeContent = '';
|
||||||
|
|
||||||
|
// 查找类型名称
|
||||||
|
while (pos < this.code.length && this.code[pos] !== ']') {
|
||||||
|
typeContent += this.code[pos];
|
||||||
|
pos++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pos >= this.code.length || this.code[pos] !== ']') {
|
||||||
|
return null; // 没有找到匹配的 ']'
|
||||||
|
}
|
||||||
|
|
||||||
|
// 检查是否是有效的PowerShell类型
|
||||||
|
const validTypes = [
|
||||||
|
'int', 'int32', 'int64', 'string', 'bool', 'boolean', 'char', 'byte',
|
||||||
|
'double', 'float', 'decimal', 'long', 'short', 'datetime', 'timespan',
|
||||||
|
'array', 'hashtable', 'object', 'psobject', 'xml', 'scriptblock',
|
||||||
|
'guid', 'uri', 'version', 'regex', 'mailaddress', 'ipaddress'
|
||||||
|
];
|
||||||
|
|
||||||
|
const lowerType = typeContent.toLowerCase().trim();
|
||||||
|
if (validTypes.includes(lowerType) || lowerType.includes('.')) {
|
||||||
|
return `[${typeContent}]`;
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private tokenizeTypeConversion(startPos: number, startLine: number, startColumn: number): Token {
|
||||||
|
const typeConversion = this.peekTypeConversion();
|
||||||
|
if (!typeConversion) {
|
||||||
|
// 这不应该发生,但作为安全措施
|
||||||
|
this.advance();
|
||||||
|
return this.createToken(TokenType.LEFT_BRACKET, '[', startPos, startLine, startColumn);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 消费整个类型转换
|
||||||
|
for (let i = 0; i < typeConversion.length; i++) {
|
||||||
|
this.advance();
|
||||||
|
}
|
||||||
|
|
||||||
|
return this.createToken(TokenType.IDENTIFIER, typeConversion, startPos, startLine, startColumn);
|
||||||
|
}
|
||||||
|
|
||||||
|
private isIdentifierStart(char: string): boolean {
|
||||||
|
return /[a-zA-Z_]/.test(char);
|
||||||
|
}
|
||||||
|
|
||||||
|
private isIdentifierChar(char: string): boolean {
|
||||||
|
return /[a-zA-Z0-9_]/.test(char);
|
||||||
|
}
|
||||||
|
|
||||||
|
private isDigit(char: string): boolean {
|
||||||
|
return char >= '0' && char <= '9';
|
||||||
|
}
|
||||||
|
|
||||||
|
private isPrintableChar(char: string): boolean {
|
||||||
|
// 检查是否为可打印字符(非控制字符)
|
||||||
|
const charCode = char.charCodeAt(0);
|
||||||
|
return charCode >= 32 && charCode <= 126;
|
||||||
|
}
|
||||||
|
|
||||||
|
private advance(): void {
|
||||||
|
if (this.position < this.code.length) {
|
||||||
|
if (this.code[this.position] === '\n') {
|
||||||
|
this.line++;
|
||||||
|
this.column = 1;
|
||||||
|
} else {
|
||||||
|
this.column++;
|
||||||
|
}
|
||||||
|
this.position++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private peek(): string {
|
||||||
|
return this.position + 1 < this.code.length ? this.code[this.position + 1] : '';
|
||||||
|
}
|
||||||
|
|
||||||
|
private skipWhitespace(): void {
|
||||||
|
while (this.position < this.code.length) {
|
||||||
|
const char = this.code[this.position];
|
||||||
|
if (char === ' ' || char === '\t' || char === '\r') {
|
||||||
|
this.advance();
|
||||||
|
} else {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private createToken(type: TokenType, value: string, startPos: number, line: number, column: number): Token {
|
||||||
|
return {
|
||||||
|
type,
|
||||||
|
value,
|
||||||
|
line,
|
||||||
|
column,
|
||||||
|
startIndex: startPos,
|
||||||
|
endIndex: this.position
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
821
frontend/src/common/prettier/plugins/powershell/parser.ts
Normal file
821
frontend/src/common/prettier/plugins/powershell/parser.ts
Normal file
@@ -0,0 +1,821 @@
|
|||||||
|
/**
|
||||||
|
* PowerShell 语法分析器 (Parser)
|
||||||
|
* 将词法分析器产生的tokens转换为抽象语法树(AST)
|
||||||
|
*/
|
||||||
|
|
||||||
|
import { Token, TokenType } from './lexer';
|
||||||
|
import {
|
||||||
|
ASTNode,
|
||||||
|
ScriptBlockAst,
|
||||||
|
StatementAst,
|
||||||
|
ExpressionAst,
|
||||||
|
PipelineAst,
|
||||||
|
CommandAst,
|
||||||
|
AssignmentAst,
|
||||||
|
VariableAst,
|
||||||
|
LiteralAst,
|
||||||
|
BinaryExpressionAst,
|
||||||
|
IfStatementAst,
|
||||||
|
FunctionDefinitionAst,
|
||||||
|
ParameterAst,
|
||||||
|
ASTNodeFactory,
|
||||||
|
CommentAst,
|
||||||
|
PipelineElementAst,
|
||||||
|
ElseIfClauseAst,
|
||||||
|
UnaryExpressionAst,
|
||||||
|
ParenthesizedExpressionAst
|
||||||
|
} from './ast';
|
||||||
|
|
||||||
|
export class PowerShellParser {
|
||||||
|
private tokens: Token[];
|
||||||
|
private currentIndex: number = 0;
|
||||||
|
private comments: CommentAst[] = [];
|
||||||
|
|
||||||
|
private originalCode: string;
|
||||||
|
|
||||||
|
constructor(tokens: Token[], originalCode: string = '') {
|
||||||
|
this.tokens = tokens;
|
||||||
|
this.currentIndex = 0;
|
||||||
|
this.originalCode = originalCode;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 解析tokens生成AST
|
||||||
|
*/
|
||||||
|
public parse(): ScriptBlockAst {
|
||||||
|
const statements: StatementAst[] = [];
|
||||||
|
|
||||||
|
while (!this.isAtEnd()) {
|
||||||
|
// 跳过空白和换行
|
||||||
|
this.skipWhitespaceAndNewlines();
|
||||||
|
|
||||||
|
if (this.isAtEnd()) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 处理注释
|
||||||
|
if (this.match(TokenType.COMMENT, TokenType.MULTILINE_COMMENT)) {
|
||||||
|
const comment = this.parseComment();
|
||||||
|
this.comments.push(comment);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
const statement = this.parseStatement();
|
||||||
|
if (statement) {
|
||||||
|
statements.push(statement);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const start = this.tokens.length > 0 ? this.tokens[0].startIndex : 0;
|
||||||
|
const end = this.tokens.length > 0 ? this.tokens[this.tokens.length - 1].endIndex : 0;
|
||||||
|
const line = this.tokens.length > 0 ? this.tokens[0].line : 1;
|
||||||
|
const column = this.tokens.length > 0 ? this.tokens[0].column : 1;
|
||||||
|
|
||||||
|
return ASTNodeFactory.createScriptBlock(statements, start, end, line, column);
|
||||||
|
}
|
||||||
|
|
||||||
|
public getComments(): CommentAst[] {
|
||||||
|
return this.comments;
|
||||||
|
}
|
||||||
|
|
||||||
|
private parseStatement(): StatementAst | null {
|
||||||
|
// 函数定义
|
||||||
|
if (this.check(TokenType.FUNCTION)) {
|
||||||
|
return this.parseFunctionDefinition();
|
||||||
|
}
|
||||||
|
|
||||||
|
// 控制流语句
|
||||||
|
if (this.check(TokenType.IF)) {
|
||||||
|
return this.parseIfStatement();
|
||||||
|
}
|
||||||
|
|
||||||
|
// 赋值或管道
|
||||||
|
return this.parsePipeline();
|
||||||
|
}
|
||||||
|
|
||||||
|
private parseFunctionDefinition(): FunctionDefinitionAst {
|
||||||
|
const start = this.current().startIndex;
|
||||||
|
const line = this.current().line;
|
||||||
|
const column = this.current().column;
|
||||||
|
|
||||||
|
this.consume(TokenType.FUNCTION, "Expected 'function'");
|
||||||
|
|
||||||
|
// 函数名可能是CMDLET类型(如Get-Something)或IDENTIFIER
|
||||||
|
let nameToken: Token;
|
||||||
|
if (this.check(TokenType.CMDLET)) {
|
||||||
|
nameToken = this.consume(TokenType.CMDLET, "Expected function name");
|
||||||
|
} else {
|
||||||
|
nameToken = this.consume(TokenType.IDENTIFIER, "Expected function name");
|
||||||
|
}
|
||||||
|
const name = nameToken.value;
|
||||||
|
|
||||||
|
// 解析参数
|
||||||
|
const parameters: ParameterAst[] = [];
|
||||||
|
if (this.match(TokenType.LEFT_PAREN)) {
|
||||||
|
if (!this.check(TokenType.RIGHT_PAREN)) {
|
||||||
|
do {
|
||||||
|
const param = this.parseParameter();
|
||||||
|
if (param) {
|
||||||
|
parameters.push(param);
|
||||||
|
}
|
||||||
|
} while (this.match(TokenType.COMMA));
|
||||||
|
}
|
||||||
|
this.consume(TokenType.RIGHT_PAREN, "Expected ')' after parameters");
|
||||||
|
}
|
||||||
|
|
||||||
|
// 解析函数体
|
||||||
|
const body = this.parseScriptBlock();
|
||||||
|
|
||||||
|
const end = this.previous().endIndex;
|
||||||
|
|
||||||
|
return ASTNodeFactory.createFunctionDefinition(name, parameters, body, start, end, line, column);
|
||||||
|
}
|
||||||
|
|
||||||
|
private parseIfStatement(): IfStatementAst {
|
||||||
|
const start = this.current().startIndex;
|
||||||
|
const line = this.current().line;
|
||||||
|
const column = this.current().column;
|
||||||
|
|
||||||
|
this.consume(TokenType.IF, "Expected 'if'");
|
||||||
|
|
||||||
|
// PowerShell的if语句可能有括号,也可能没有
|
||||||
|
const hasParens = this.check(TokenType.LEFT_PAREN);
|
||||||
|
if (hasParens) {
|
||||||
|
this.consume(TokenType.LEFT_PAREN, "Expected '(' after 'if'");
|
||||||
|
}
|
||||||
|
|
||||||
|
const condition = this.parseExpression();
|
||||||
|
|
||||||
|
if (hasParens) {
|
||||||
|
this.consume(TokenType.RIGHT_PAREN, "Expected ')' after if condition");
|
||||||
|
}
|
||||||
|
|
||||||
|
const ifBody = this.parseScriptBlock();
|
||||||
|
|
||||||
|
const elseIfClauses: ElseIfClauseAst[] = [];
|
||||||
|
let elseBody: ScriptBlockAst | undefined;
|
||||||
|
|
||||||
|
// 处理 elseif 子句
|
||||||
|
while (this.match(TokenType.ELSEIF)) {
|
||||||
|
const elseIfStart = this.previous().startIndex;
|
||||||
|
const elseIfLine = this.previous().line;
|
||||||
|
const elseIfColumn = this.previous().column;
|
||||||
|
|
||||||
|
this.consume(TokenType.LEFT_PAREN, "Expected '(' after 'elseif'");
|
||||||
|
const elseIfCondition = this.parseExpression();
|
||||||
|
this.consume(TokenType.RIGHT_PAREN, "Expected ')' after elseif condition");
|
||||||
|
const elseIfBody = this.parseScriptBlock();
|
||||||
|
|
||||||
|
const elseIfEnd = this.previous().endIndex;
|
||||||
|
|
||||||
|
elseIfClauses.push({
|
||||||
|
type: 'ElseIfClause',
|
||||||
|
condition: elseIfCondition,
|
||||||
|
body: elseIfBody,
|
||||||
|
start: elseIfStart,
|
||||||
|
end: elseIfEnd,
|
||||||
|
line: elseIfLine,
|
||||||
|
column: elseIfColumn
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// 处理 else 子句
|
||||||
|
if (this.match(TokenType.ELSE)) {
|
||||||
|
elseBody = this.parseScriptBlock();
|
||||||
|
}
|
||||||
|
|
||||||
|
const end = this.previous().endIndex;
|
||||||
|
|
||||||
|
return ASTNodeFactory.createIfStatement(condition, ifBody, elseIfClauses, elseBody, start, end, line, column);
|
||||||
|
}
|
||||||
|
|
||||||
|
private parsePipeline(): PipelineAst {
|
||||||
|
const start = this.current().startIndex;
|
||||||
|
const line = this.current().line;
|
||||||
|
const column = this.current().column;
|
||||||
|
|
||||||
|
const elements: PipelineElementAst[] = [];
|
||||||
|
|
||||||
|
// 解析第一个元素
|
||||||
|
const firstElement = this.parsePipelineElement();
|
||||||
|
elements.push(firstElement);
|
||||||
|
|
||||||
|
// 解析管道链
|
||||||
|
while (this.match(TokenType.PIPE)) {
|
||||||
|
const element = this.parsePipelineElement();
|
||||||
|
elements.push(element);
|
||||||
|
}
|
||||||
|
|
||||||
|
const end = this.previous().endIndex;
|
||||||
|
|
||||||
|
return ASTNodeFactory.createPipeline(elements, start, end, line, column);
|
||||||
|
}
|
||||||
|
|
||||||
|
private parsePipelineElement(): PipelineElementAst {
|
||||||
|
const start = this.current().startIndex;
|
||||||
|
const line = this.current().line;
|
||||||
|
const column = this.current().column;
|
||||||
|
|
||||||
|
const expression = this.parseAssignment();
|
||||||
|
const end = this.previous().endIndex;
|
||||||
|
|
||||||
|
return {
|
||||||
|
type: 'PipelineElement',
|
||||||
|
expression,
|
||||||
|
start,
|
||||||
|
end,
|
||||||
|
line,
|
||||||
|
column
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
private parseAssignment(): ExpressionAst {
|
||||||
|
const expr = this.parseLogicalOr();
|
||||||
|
|
||||||
|
if (this.match(TokenType.ASSIGNMENT)) {
|
||||||
|
const operator = this.previous().value;
|
||||||
|
const right = this.parseAssignment();
|
||||||
|
|
||||||
|
return ASTNodeFactory.createAssignment(
|
||||||
|
expr,
|
||||||
|
operator,
|
||||||
|
right,
|
||||||
|
expr.start,
|
||||||
|
right.end,
|
||||||
|
expr.line,
|
||||||
|
expr.column
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return expr;
|
||||||
|
}
|
||||||
|
|
||||||
|
private parseLogicalOr(): ExpressionAst {
|
||||||
|
let expr = this.parseLogicalAnd();
|
||||||
|
|
||||||
|
while (this.match(TokenType.LOGICAL)) {
|
||||||
|
const operator = this.previous().value.toLowerCase();
|
||||||
|
if (operator === '-or' || operator === '-xor') {
|
||||||
|
const right = this.parseLogicalAnd();
|
||||||
|
expr = ASTNodeFactory.createBinaryExpression(
|
||||||
|
expr,
|
||||||
|
this.previous().value, // 使用原始大小写
|
||||||
|
right,
|
||||||
|
expr.start,
|
||||||
|
right.end,
|
||||||
|
expr.line,
|
||||||
|
expr.column
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
// 如果不是预期的操作符,回退
|
||||||
|
this.currentIndex--;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return expr;
|
||||||
|
}
|
||||||
|
|
||||||
|
private parseLogicalAnd(): ExpressionAst {
|
||||||
|
let expr = this.parseComparison();
|
||||||
|
|
||||||
|
while (this.match(TokenType.LOGICAL)) {
|
||||||
|
const operator = this.previous().value.toLowerCase();
|
||||||
|
if (operator === '-and') {
|
||||||
|
const right = this.parseComparison();
|
||||||
|
expr = ASTNodeFactory.createBinaryExpression(
|
||||||
|
expr,
|
||||||
|
this.previous().value, // 使用原始大小写
|
||||||
|
right,
|
||||||
|
expr.start,
|
||||||
|
right.end,
|
||||||
|
expr.line,
|
||||||
|
expr.column
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
// 如果不是预期的操作符,回退
|
||||||
|
this.currentIndex--;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return expr;
|
||||||
|
}
|
||||||
|
|
||||||
|
private parseComparison(): ExpressionAst {
|
||||||
|
let expr = this.parseArithmetic();
|
||||||
|
|
||||||
|
while (this.match(TokenType.COMPARISON)) {
|
||||||
|
const operator = this.previous().value;
|
||||||
|
const right = this.parseArithmetic();
|
||||||
|
expr = ASTNodeFactory.createBinaryExpression(
|
||||||
|
expr,
|
||||||
|
operator,
|
||||||
|
right,
|
||||||
|
expr.start,
|
||||||
|
right.end,
|
||||||
|
expr.line,
|
||||||
|
expr.column
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return expr;
|
||||||
|
}
|
||||||
|
|
||||||
|
private parseArithmetic(): ExpressionAst {
|
||||||
|
let expr = this.parseMultiplicative();
|
||||||
|
|
||||||
|
while (this.match(TokenType.ARITHMETIC)) {
|
||||||
|
const token = this.previous();
|
||||||
|
if (token.value === '+' || token.value === '-') {
|
||||||
|
const operator = token.value;
|
||||||
|
const right = this.parseMultiplicative();
|
||||||
|
expr = ASTNodeFactory.createBinaryExpression(
|
||||||
|
expr,
|
||||||
|
operator,
|
||||||
|
right,
|
||||||
|
expr.start,
|
||||||
|
right.end,
|
||||||
|
expr.line,
|
||||||
|
expr.column
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return expr;
|
||||||
|
}
|
||||||
|
|
||||||
|
private parseMultiplicative(): ExpressionAst {
|
||||||
|
let expr = this.parseUnary();
|
||||||
|
|
||||||
|
while (this.match(TokenType.ARITHMETIC)) {
|
||||||
|
const token = this.previous();
|
||||||
|
if (token.value === '*' || token.value === '/' || token.value === '%') {
|
||||||
|
const operator = token.value;
|
||||||
|
const right = this.parseUnary();
|
||||||
|
expr = ASTNodeFactory.createBinaryExpression(
|
||||||
|
expr,
|
||||||
|
operator,
|
||||||
|
right,
|
||||||
|
expr.start,
|
||||||
|
right.end,
|
||||||
|
expr.line,
|
||||||
|
expr.column
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return expr;
|
||||||
|
}
|
||||||
|
|
||||||
|
private parseUnary(): ExpressionAst {
|
||||||
|
if (this.match(TokenType.LOGICAL)) {
|
||||||
|
const token = this.previous();
|
||||||
|
const operator = token.value.toLowerCase();
|
||||||
|
if (operator === '-not') {
|
||||||
|
const operand = this.parseUnary();
|
||||||
|
return {
|
||||||
|
type: 'UnaryExpression',
|
||||||
|
operator: token.value, // 使用原始大小写
|
||||||
|
operand,
|
||||||
|
start: token.startIndex,
|
||||||
|
end: operand.end,
|
||||||
|
line: token.line,
|
||||||
|
column: token.column
|
||||||
|
} as UnaryExpressionAst;
|
||||||
|
} else {
|
||||||
|
// 如果不是-not,回退token
|
||||||
|
this.currentIndex--;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 处理算术一元操作符(+, -)
|
||||||
|
if (this.match(TokenType.ARITHMETIC)) {
|
||||||
|
const token = this.previous();
|
||||||
|
if (token.value === '+' || token.value === '-') {
|
||||||
|
const operand = this.parseUnary();
|
||||||
|
return {
|
||||||
|
type: 'UnaryExpression',
|
||||||
|
operator: token.value,
|
||||||
|
operand,
|
||||||
|
start: token.startIndex,
|
||||||
|
end: operand.end,
|
||||||
|
line: token.line,
|
||||||
|
column: token.column
|
||||||
|
} as UnaryExpressionAst;
|
||||||
|
} else {
|
||||||
|
// 如果不是一元操作符,回退
|
||||||
|
this.currentIndex--;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return this.parsePrimary();
|
||||||
|
}
|
||||||
|
|
||||||
|
private parsePrimary(): ExpressionAst {
|
||||||
|
// 变量
|
||||||
|
if (this.match(TokenType.VARIABLE)) {
|
||||||
|
const token = this.previous();
|
||||||
|
return ASTNodeFactory.createVariable(
|
||||||
|
token.value,
|
||||||
|
token.startIndex,
|
||||||
|
token.endIndex,
|
||||||
|
token.line,
|
||||||
|
token.column
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 字符串字面量
|
||||||
|
if (this.match(TokenType.STRING, TokenType.HERE_STRING)) {
|
||||||
|
const token = this.previous();
|
||||||
|
return ASTNodeFactory.createLiteral(
|
||||||
|
token.value,
|
||||||
|
'String',
|
||||||
|
token.startIndex,
|
||||||
|
token.endIndex,
|
||||||
|
token.line,
|
||||||
|
token.column
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 数字字面量
|
||||||
|
if (this.match(TokenType.NUMBER)) {
|
||||||
|
const token = this.previous();
|
||||||
|
const value = parseFloat(token.value);
|
||||||
|
return ASTNodeFactory.createLiteral(
|
||||||
|
value,
|
||||||
|
'Number',
|
||||||
|
token.startIndex,
|
||||||
|
token.endIndex,
|
||||||
|
token.line,
|
||||||
|
token.column
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 命令调用 - 扩展支持更多token类型
|
||||||
|
if (this.match(TokenType.CMDLET, TokenType.IDENTIFIER)) {
|
||||||
|
return this.parseCommand();
|
||||||
|
}
|
||||||
|
|
||||||
|
// 处理看起来像cmdlet但被错误标记的标识符
|
||||||
|
if (this.check(TokenType.IDENTIFIER) && this.current().value.includes('-')) {
|
||||||
|
this.advance();
|
||||||
|
return this.parseCommand();
|
||||||
|
}
|
||||||
|
|
||||||
|
// 哈希表 @{...}
|
||||||
|
if (this.check(TokenType.LEFT_BRACE) && this.current().value === '@{') {
|
||||||
|
return this.parseHashtable();
|
||||||
|
}
|
||||||
|
|
||||||
|
// 脚本块表达式 {...} - 已在parseHashtableValue中处理
|
||||||
|
// 这里不需要处理,因为独立的脚本块很少见
|
||||||
|
|
||||||
|
// 括号表达式
|
||||||
|
if (this.match(TokenType.LEFT_PAREN)) {
|
||||||
|
const expr = this.parseExpression();
|
||||||
|
this.consume(TokenType.RIGHT_PAREN, "Expected ')' after expression");
|
||||||
|
return {
|
||||||
|
type: 'ParenthesizedExpression',
|
||||||
|
expression: expr,
|
||||||
|
start: this.previous().startIndex,
|
||||||
|
end: this.previous().endIndex,
|
||||||
|
line: this.previous().line,
|
||||||
|
column: this.previous().column
|
||||||
|
} as ParenthesizedExpressionAst;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 对于不认识的token,作为普通标识符处理而不是抛出异常
|
||||||
|
const token = this.advance();
|
||||||
|
return ASTNodeFactory.createLiteral(
|
||||||
|
token.value,
|
||||||
|
'String', // 将未识别的token作为字符串处理
|
||||||
|
token.startIndex,
|
||||||
|
token.endIndex,
|
||||||
|
token.line,
|
||||||
|
token.column
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
private parseCommand(): CommandAst {
|
||||||
|
const start = this.previous().startIndex;
|
||||||
|
const line = this.previous().line;
|
||||||
|
const column = this.previous().column;
|
||||||
|
const commandName = this.previous().value;
|
||||||
|
|
||||||
|
const parameters: ParameterAst[] = [];
|
||||||
|
const args: ExpressionAst[] = [];
|
||||||
|
|
||||||
|
// 解析参数和参数值
|
||||||
|
while (!this.isAtEnd() &&
|
||||||
|
!this.check(TokenType.PIPE) &&
|
||||||
|
!this.check(TokenType.NEWLINE) &&
|
||||||
|
!this.check(TokenType.SEMICOLON) &&
|
||||||
|
!this.check(TokenType.RIGHT_PAREN) &&
|
||||||
|
!this.check(TokenType.RIGHT_BRACE)) {
|
||||||
|
|
||||||
|
if (this.match(TokenType.PARAMETER)) {
|
||||||
|
const paramToken = this.previous();
|
||||||
|
const param: ParameterAst = {
|
||||||
|
type: 'Parameter',
|
||||||
|
name: paramToken.value,
|
||||||
|
start: paramToken.startIndex,
|
||||||
|
end: paramToken.endIndex,
|
||||||
|
line: paramToken.line,
|
||||||
|
column: paramToken.column
|
||||||
|
};
|
||||||
|
|
||||||
|
// 检查参数是否有值
|
||||||
|
if (!this.check(TokenType.PARAMETER) &&
|
||||||
|
!this.check(TokenType.PIPE) &&
|
||||||
|
!this.check(TokenType.NEWLINE) &&
|
||||||
|
!this.check(TokenType.SEMICOLON)) {
|
||||||
|
param.value = this.parsePrimary();
|
||||||
|
}
|
||||||
|
|
||||||
|
parameters.push(param);
|
||||||
|
} else {
|
||||||
|
// 位置参数
|
||||||
|
const arg = this.parsePrimary();
|
||||||
|
args.push(arg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const end = this.previous().endIndex;
|
||||||
|
|
||||||
|
return ASTNodeFactory.createCommand(commandName, parameters, args, start, end, line, column);
|
||||||
|
}
|
||||||
|
|
||||||
|
private parseParameter(): ParameterAst | null {
|
||||||
|
if (this.match(TokenType.PARAMETER)) {
|
||||||
|
const token = this.previous();
|
||||||
|
const param: ParameterAst = {
|
||||||
|
type: 'Parameter',
|
||||||
|
name: token.value,
|
||||||
|
start: token.startIndex,
|
||||||
|
end: token.endIndex,
|
||||||
|
line: token.line,
|
||||||
|
column: token.column
|
||||||
|
};
|
||||||
|
|
||||||
|
// 检查是否有参数值
|
||||||
|
if (this.match(TokenType.ASSIGNMENT)) {
|
||||||
|
param.value = this.parseExpression();
|
||||||
|
}
|
||||||
|
|
||||||
|
return param;
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private parseScriptBlock(): ScriptBlockAst {
|
||||||
|
const start = this.current().startIndex;
|
||||||
|
const line = this.current().line;
|
||||||
|
const column = this.current().column;
|
||||||
|
|
||||||
|
this.consume(TokenType.LEFT_BRACE, "Expected '{'");
|
||||||
|
|
||||||
|
const statements: StatementAst[] = [];
|
||||||
|
|
||||||
|
while (!this.check(TokenType.RIGHT_BRACE) && !this.isAtEnd()) {
|
||||||
|
this.skipWhitespaceAndNewlines();
|
||||||
|
|
||||||
|
if (this.check(TokenType.RIGHT_BRACE)) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
const statement = this.parseStatement();
|
||||||
|
if (statement) {
|
||||||
|
statements.push(statement);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
this.consume(TokenType.RIGHT_BRACE, "Expected '}'");
|
||||||
|
|
||||||
|
const end = this.previous().endIndex;
|
||||||
|
|
||||||
|
return ASTNodeFactory.createScriptBlock(statements, start, end, line, column);
|
||||||
|
}
|
||||||
|
|
||||||
|
private parseExpression(): ExpressionAst {
|
||||||
|
return this.parseAssignment();
|
||||||
|
}
|
||||||
|
|
||||||
|
private parseComment(): CommentAst {
|
||||||
|
const token = this.previous();
|
||||||
|
const isMultiline = token.type === TokenType.MULTILINE_COMMENT;
|
||||||
|
|
||||||
|
return ASTNodeFactory.createComment(
|
||||||
|
token.value,
|
||||||
|
isMultiline,
|
||||||
|
token.startIndex,
|
||||||
|
token.endIndex,
|
||||||
|
token.line,
|
||||||
|
token.column
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 辅助方法
|
||||||
|
private match(...types: TokenType[]): boolean {
|
||||||
|
for (const type of types) {
|
||||||
|
if (this.check(type)) {
|
||||||
|
this.advance();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
private check(type: TokenType): boolean {
|
||||||
|
if (this.isAtEnd()) return false;
|
||||||
|
return this.current().type === type;
|
||||||
|
}
|
||||||
|
|
||||||
|
private advance(): Token {
|
||||||
|
if (!this.isAtEnd()) this.currentIndex++;
|
||||||
|
return this.previous();
|
||||||
|
}
|
||||||
|
|
||||||
|
private isAtEnd(): boolean {
|
||||||
|
return this.currentIndex >= this.tokens.length || this.current().type === TokenType.EOF;
|
||||||
|
}
|
||||||
|
|
||||||
|
private current(): Token {
|
||||||
|
if (this.currentIndex >= this.tokens.length) {
|
||||||
|
return this.tokens[this.tokens.length - 1];
|
||||||
|
}
|
||||||
|
return this.tokens[this.currentIndex];
|
||||||
|
}
|
||||||
|
|
||||||
|
private previous(): Token {
|
||||||
|
return this.tokens[this.currentIndex - 1];
|
||||||
|
}
|
||||||
|
|
||||||
|
private consume(type: TokenType, message: string): Token {
|
||||||
|
if (this.check(type)) return this.advance();
|
||||||
|
|
||||||
|
const current = this.current();
|
||||||
|
throw new Error(`${message}. Got ${current.type}(${current.value}) at line ${current.line}, column ${current.column}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private parseHashtable(): ExpressionAst {
|
||||||
|
const start = this.current().startIndex;
|
||||||
|
const line = this.current().line;
|
||||||
|
const column = this.current().column;
|
||||||
|
|
||||||
|
// 消费 @{
|
||||||
|
this.advance();
|
||||||
|
|
||||||
|
const entries: any[] = [];
|
||||||
|
|
||||||
|
// 解析哈希表内容
|
||||||
|
if (!this.check(TokenType.RIGHT_BRACE)) {
|
||||||
|
do {
|
||||||
|
// 解析键 - 只接受简单的标识符或字符串
|
||||||
|
const key = this.parseHashtableKey();
|
||||||
|
|
||||||
|
// 消费 =
|
||||||
|
this.consume(TokenType.ASSIGNMENT, "Expected '=' after hashtable key");
|
||||||
|
|
||||||
|
// 解析值
|
||||||
|
const value = this.parseHashtableValue();
|
||||||
|
|
||||||
|
entries.push({
|
||||||
|
type: 'HashtableEntry',
|
||||||
|
key,
|
||||||
|
value,
|
||||||
|
start: key.start,
|
||||||
|
end: value.end,
|
||||||
|
line: key.line,
|
||||||
|
column: key.column
|
||||||
|
});
|
||||||
|
|
||||||
|
} while (this.match(TokenType.SEMICOLON));
|
||||||
|
}
|
||||||
|
|
||||||
|
this.consume(TokenType.RIGHT_BRACE, "Expected '}' after hashtable entries");
|
||||||
|
const end = this.previous().endIndex;
|
||||||
|
|
||||||
|
return {
|
||||||
|
type: 'Hashtable',
|
||||||
|
entries,
|
||||||
|
start,
|
||||||
|
end,
|
||||||
|
line,
|
||||||
|
column
|
||||||
|
} as any;
|
||||||
|
}
|
||||||
|
|
||||||
|
private parseHashtableKey(): ExpressionAst {
|
||||||
|
// 哈希表键只能是简单的标识符或字符串
|
||||||
|
if (this.match(TokenType.STRING, TokenType.HERE_STRING)) {
|
||||||
|
const token = this.previous();
|
||||||
|
return ASTNodeFactory.createLiteral(
|
||||||
|
token.value,
|
||||||
|
'String',
|
||||||
|
token.startIndex,
|
||||||
|
token.endIndex,
|
||||||
|
token.line,
|
||||||
|
token.column
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 接受各种可能的标识符类型作为哈希表键
|
||||||
|
if (this.match(TokenType.IDENTIFIER, TokenType.CMDLET, TokenType.KEYWORD)) {
|
||||||
|
const token = this.previous();
|
||||||
|
return ASTNodeFactory.createLiteral(
|
||||||
|
token.value,
|
||||||
|
'String',
|
||||||
|
token.startIndex,
|
||||||
|
token.endIndex,
|
||||||
|
token.line,
|
||||||
|
token.column
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 对于任何其他类型的token,尝试作为字面量处理
|
||||||
|
const currentToken = this.current();
|
||||||
|
this.advance();
|
||||||
|
return ASTNodeFactory.createLiteral(
|
||||||
|
currentToken.value,
|
||||||
|
'String',
|
||||||
|
currentToken.startIndex,
|
||||||
|
currentToken.endIndex,
|
||||||
|
currentToken.line,
|
||||||
|
currentToken.column
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
private parseHashtableValue(): ExpressionAst {
|
||||||
|
// 哈希表值可以是任何表达式
|
||||||
|
if (this.check(TokenType.LEFT_BRACE)) {
|
||||||
|
// 这是一个脚本块 {expression} - 完全绕过复杂解析
|
||||||
|
const start = this.current().startIndex;
|
||||||
|
const line = this.current().line;
|
||||||
|
const column = this.current().column;
|
||||||
|
|
||||||
|
// 直接从原始代码中提取脚本块内容
|
||||||
|
const startPos = this.current().startIndex;
|
||||||
|
this.advance(); // 消费 {
|
||||||
|
|
||||||
|
let braceLevel = 1;
|
||||||
|
let endPos = this.current().startIndex;
|
||||||
|
|
||||||
|
// 找到匹配的右大括号位置
|
||||||
|
while (!this.isAtEnd() && braceLevel > 0) {
|
||||||
|
const token = this.current();
|
||||||
|
if (token.type === TokenType.LEFT_BRACE) {
|
||||||
|
braceLevel++;
|
||||||
|
} else if (token.type === TokenType.RIGHT_BRACE) {
|
||||||
|
braceLevel--;
|
||||||
|
if (braceLevel === 0) {
|
||||||
|
endPos = token.startIndex;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
this.advance();
|
||||||
|
}
|
||||||
|
|
||||||
|
this.consume(TokenType.RIGHT_BRACE, "Expected '}' after script block");
|
||||||
|
const end = this.previous().endIndex;
|
||||||
|
|
||||||
|
// 从原始代码中提取内容(从 { 后到 } 前)
|
||||||
|
const rawContent = this.getOriginalCodeSlice(startPos + 1, endPos);
|
||||||
|
|
||||||
|
return {
|
||||||
|
type: 'ScriptBlockExpression',
|
||||||
|
rawContent: rawContent.trim(), // 去掉首尾空白
|
||||||
|
start,
|
||||||
|
end,
|
||||||
|
line,
|
||||||
|
column
|
||||||
|
} as any;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 对于其他值,使用简单的解析
|
||||||
|
return this.parsePrimary();
|
||||||
|
}
|
||||||
|
|
||||||
|
private getOriginalCodeSlice(start: number, end: number): string {
|
||||||
|
// 直接从原始代码中提取片段
|
||||||
|
if (this.originalCode) {
|
||||||
|
return this.originalCode.substring(start, end);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 回退到基于token重建(如果没有原始代码)
|
||||||
|
let result = '';
|
||||||
|
for (const token of this.tokens) {
|
||||||
|
if (token.startIndex >= start && token.endIndex <= end) {
|
||||||
|
result += token.value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
private skipWhitespaceAndNewlines(): void {
|
||||||
|
while (this.match(TokenType.WHITESPACE, TokenType.NEWLINE)) {
|
||||||
|
// 继续跳过
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
824
frontend/src/common/prettier/plugins/rust/format/comments.ts
Normal file
824
frontend/src/common/prettier/plugins/rust/format/comments.ts
Normal file
@@ -0,0 +1,824 @@
|
|||||||
|
import { CommentOrDocComment, LocArray, Node, NodeType, NodeWithBodyOrCases } from "jinx-rust";
|
||||||
|
import {
|
||||||
|
end,
|
||||||
|
getBodyOrCases,
|
||||||
|
getLastParameter,
|
||||||
|
hasOuterAttributes,
|
||||||
|
isInner,
|
||||||
|
is_Attribute,
|
||||||
|
is_AttributeOrDocComment,
|
||||||
|
is_BlockCommentKind,
|
||||||
|
is_BlockCommentNode,
|
||||||
|
is_Comment,
|
||||||
|
is_CommentOrDocComment,
|
||||||
|
is_ExpressionWithBodyOrCases,
|
||||||
|
is_ExternSpecifier,
|
||||||
|
is_FlowControlExpression,
|
||||||
|
is_FunctionDeclaration,
|
||||||
|
is_FunctionNode,
|
||||||
|
is_IfBlockExpression,
|
||||||
|
is_LineCommentKind,
|
||||||
|
is_LineCommentNode,
|
||||||
|
is_LocArray,
|
||||||
|
is_MacroRule,
|
||||||
|
is_NodeWithBodyOrCases,
|
||||||
|
is_ReassignmentNode,
|
||||||
|
is_StatementNode,
|
||||||
|
is_StructLiteralProperty,
|
||||||
|
is_StructLiteralPropertySpread,
|
||||||
|
nisAnyOf,
|
||||||
|
ownStart,
|
||||||
|
start,
|
||||||
|
} from "jinx-rust/utils";
|
||||||
|
import { is_CallExpression_or_CallLikeMacroInvocation } from "../transform";
|
||||||
|
import { Narrow, assert, exit, iLast, last_of, maybe_last_of } from "../utils/common";
|
||||||
|
import { is_MemberAccessLike, is_xVariableEqualishLike } from "./core";
|
||||||
|
import {
|
||||||
|
AnyComment,
|
||||||
|
CustomOptions,
|
||||||
|
DCM,
|
||||||
|
Doc,
|
||||||
|
MutatedAttribute,
|
||||||
|
NodeWithComments,
|
||||||
|
PrettierCommentInfo,
|
||||||
|
breakParent,
|
||||||
|
cursor,
|
||||||
|
hardline,
|
||||||
|
indent,
|
||||||
|
join,
|
||||||
|
line,
|
||||||
|
lineSuffix,
|
||||||
|
literalline,
|
||||||
|
} from "./external";
|
||||||
|
import { assertPathAtNode, canAttachComment, getAllComments, getContext, getNode, getOptions, pathCallEach } from "./plugin";
|
||||||
|
import { shouldPrintOuterAttributesAbove } from "./styling";
|
||||||
|
|
||||||
|
function addCommentHelper(node: Node, comment: AnyComment, leading = false, trailing = false) {
|
||||||
|
__DEV__: assert(!handled(comment));
|
||||||
|
((node as NodeWithComments<Node>).comments ??= []).push(comment);
|
||||||
|
(comment.leading = leading), (comment.trailing = trailing), (comment.printed = false);
|
||||||
|
}
|
||||||
|
|
||||||
|
function addLeadingComment(node: Node, comment: AnyComment) {
|
||||||
|
addCommentHelper(node, comment, true);
|
||||||
|
}
|
||||||
|
function addDanglingComment(node: Node, comment: AnyComment, marker: DCM) {
|
||||||
|
addCommentHelper(node, comment);
|
||||||
|
comment.marker = marker;
|
||||||
|
}
|
||||||
|
function addTrailingComment(node: Node, comment: AnyComment) {
|
||||||
|
addCommentHelper(node, comment, false, true);
|
||||||
|
}
|
||||||
|
export function setPrettierIgnoreTarget(node: Node, comment: AnyComment) {
|
||||||
|
__DEV__: Narrow<Node & { prettierIgnore?: true }>(node), assert(isPrettierIgnoreComment(comment) || isPrettierIgnoreAttribute(comment));
|
||||||
|
comment.unignore = true;
|
||||||
|
node.prettierIgnore = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
function hasComments<T extends Node>(node: T): node is NodeWithComments<T> {
|
||||||
|
return "comments" in node && node.comments.length > 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function printDanglingComments(enclosingNode: Node, sameIndent: boolean, marker?: DCM) {
|
||||||
|
if (hasComments(enclosingNode)) {
|
||||||
|
const printed: Doc[] = [];
|
||||||
|
pathCallEach(enclosingNode, "comments", (comment) => {
|
||||||
|
if (isDangling(comment) && (!marker || comment.marker === marker)) {
|
||||||
|
printed.push(printComment(comment));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
if (printed.length > 0) {
|
||||||
|
return sameIndent //
|
||||||
|
? join(hardline, printed)
|
||||||
|
: indent([hardline, join(hardline, printed)]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
export function needsHardlineAfterDanglingComment(node: Node) {
|
||||||
|
if (!hasComment(node)) return false;
|
||||||
|
const lastDanglingComment = maybe_last_of(getComments(node, CF.Dangling));
|
||||||
|
return lastDanglingComment && is_LineCommentNode(lastDanglingComment);
|
||||||
|
}
|
||||||
|
export function setDidPrintComment(comment: AnyComment) {
|
||||||
|
comment.printed = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
function printComment(comment: AnyComment) {
|
||||||
|
__DEV__: assertPathAtNode("printComment", comment);
|
||||||
|
__DEV__: assert(handled(comment), `Assertion failed: Comment was not printed at ${comment.loc.url()}`, comment);
|
||||||
|
setDidPrintComment(comment);
|
||||||
|
return getContext().options.printer.printComment!(getContext().path as any, getOptions());
|
||||||
|
}
|
||||||
|
|
||||||
|
export function isPreviousLineEmpty(node: Node) {
|
||||||
|
let index = start(node) - 1;
|
||||||
|
index = skipSpaces(index, true) as number;
|
||||||
|
index = skipNewline(index, true) as number;
|
||||||
|
index = skipSpaces(index, true) as number;
|
||||||
|
return index !== skipNewline(index, true);
|
||||||
|
}
|
||||||
|
export function hasBreaklineBefore(node: Node) {
|
||||||
|
return hasNewline(start(node) - 1, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function hasBreaklineAfter(node: Node) {
|
||||||
|
return hasNewline(end(node));
|
||||||
|
}
|
||||||
|
|
||||||
|
export function printCommentsSeparately(ignored?: Set<AnyComment>) {
|
||||||
|
const node = getNode();
|
||||||
|
__DEV__: Narrow<Node & { comments?: AnyComment[] }>(node);
|
||||||
|
|
||||||
|
const leading: Doc[] = [];
|
||||||
|
const trailing: Doc[] = [];
|
||||||
|
let hasTrailingLineComment = false;
|
||||||
|
let hadLeadingBlockComment = false;
|
||||||
|
|
||||||
|
if ("comments" in node) {
|
||||||
|
pathCallEach(node, "comments", (comment) => {
|
||||||
|
if (ignored?.has(comment)) {
|
||||||
|
return;
|
||||||
|
} else if (isLeading(comment)) {
|
||||||
|
leading.push(printLeadingComment(comment));
|
||||||
|
} else if (isTrailing(comment)) {
|
||||||
|
trailing.push(printTrailingComment(comment));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
if (node === getOptions().cursorNode) {
|
||||||
|
leading.unshift(cursor);
|
||||||
|
trailing.push(cursor);
|
||||||
|
}
|
||||||
|
|
||||||
|
return (leading.length | trailing.length) > 0 ? { leading, trailing } : ({ leading: "", trailing: "" } as const);
|
||||||
|
|
||||||
|
function printLeadingComment(comment: AnyComment) {
|
||||||
|
if (is_Attribute(comment) && !comment.inner) {
|
||||||
|
const printed = printComment(comment);
|
||||||
|
return [printed, " "];
|
||||||
|
}
|
||||||
|
hadLeadingBlockComment ||= is_BlockCommentKind(comment) && hasBreaklineBefore(comment);
|
||||||
|
return [
|
||||||
|
printComment(comment),
|
||||||
|
is_BlockCommentKind(comment)
|
||||||
|
? hasBreaklineAfter(comment) //
|
||||||
|
? hadLeadingBlockComment
|
||||||
|
? hardline
|
||||||
|
: line
|
||||||
|
: " "
|
||||||
|
: hardline,
|
||||||
|
hasNewline(skipNewline(skipSpaces(end(comment)))) ? hardline : "",
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
function printTrailingComment(comment: AnyComment) {
|
||||||
|
const printed = printComment(comment);
|
||||||
|
return hasBreaklineBefore(comment)
|
||||||
|
? lineSuffix([hardline, isPreviousLineEmpty(comment) ? hardline : "", printed])
|
||||||
|
: is_BlockCommentNode(comment)
|
||||||
|
? [" ", printed]
|
||||||
|
: lineSuffix([" ", printed, hasTrailingLineComment === (hasTrailingLineComment = true) ? hardline : breakParent]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export function getPostLeadingComment(comment: AnyComment) {
|
||||||
|
// console.log(comment.loc.url());
|
||||||
|
// is_BlockCommentKind(comment)
|
||||||
|
// ? hasBreaklineAfter(comment) //
|
||||||
|
// ? hasBreaklineBefore(comment)
|
||||||
|
// ? hardline
|
||||||
|
// : line
|
||||||
|
// : " "
|
||||||
|
// : hardline,
|
||||||
|
return hasNewline(skipNewline(skipSpaces(end(comment)))) ? hardline : "";
|
||||||
|
}
|
||||||
|
|
||||||
|
export function withComments<D extends Doc>(node: Node, printed: D, ignored?: Set<AnyComment>): D | Doc[] {
|
||||||
|
__DEV__: assertPathAtNode("withComments", node);
|
||||||
|
const { leading, trailing } = printCommentsSeparately(ignored);
|
||||||
|
return leading || trailing ? [...leading!, printed, ...trailing!] : printed;
|
||||||
|
// return needsOuterParens(node) ? group(["(", indent([softline, parts]), softline, ")"]) : parts;
|
||||||
|
// return parts;
|
||||||
|
}
|
||||||
|
export function getComments(node: Node, ...args: Parameters<typeof getCommentTestFunction>): AnyComment[] {
|
||||||
|
__DEV__: Narrow<Node & { comments?: AnyComment[] }>(node);
|
||||||
|
// if (!node || !node.comments) return [];
|
||||||
|
// if (args.length === 0) return node.comments;
|
||||||
|
// return args.length > 0 ? node.comments.filter(getCommentTestFunction(...args)) : node.comments;
|
||||||
|
return node && node.comments //
|
||||||
|
? args.length > 0
|
||||||
|
? node.comments.filter(getCommentTestFunction(...args))
|
||||||
|
: node.comments
|
||||||
|
: [];
|
||||||
|
}
|
||||||
|
|
||||||
|
export function getFirstComment(node: Node, flags: CF, fn?: (comment: AnyComment) => boolean): AnyComment | undefined {
|
||||||
|
const r = getComments(node, flags | CF.First, fn);
|
||||||
|
return r.length === 0 ? undefined : r[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
export function escapeComments(flags: number, fn?: (comment: AnyComment) => boolean) {
|
||||||
|
const comments = getAllComments().filter(getCommentTestFunction(flags, fn)) as AnyComment[];
|
||||||
|
comments.forEach(setDidPrintComment);
|
||||||
|
return new Set(comments);
|
||||||
|
}
|
||||||
|
|
||||||
|
export const enum CF {
|
||||||
|
Leading = 1 << 1,
|
||||||
|
Trailing = 1 << 2,
|
||||||
|
Dangling = 1 << 3,
|
||||||
|
Block = 1 << 4,
|
||||||
|
Line = 1 << 5,
|
||||||
|
PrettierIgnore = 1 << 6,
|
||||||
|
First = 1 << 7,
|
||||||
|
Last = 1 << 8,
|
||||||
|
}
|
||||||
|
export function isPrettierIgnoreComment(comment: AnyComment) {
|
||||||
|
return is_Comment(comment) && /^\s*prettier-ignore\s*/.test(comment.value) && !comment.unignore;
|
||||||
|
}
|
||||||
|
export function isPrettierIgnoreAttribute(node: Node): node is MutatedAttribute {
|
||||||
|
return is_Attribute(node) && /^\s*rustfmt::skip\s*$/.test(node.value);
|
||||||
|
}
|
||||||
|
function getCommentTestFunction(flags: CF, fn?: (comment: AnyComment) => boolean) {
|
||||||
|
return function (comment: AnyComment, index: number, comments: AnyComment[]) {
|
||||||
|
__DEV__: Narrow<number>(flags), assert(handled(comment));
|
||||||
|
return !(
|
||||||
|
(flags & CF.Leading && !isLeading(comment)) ||
|
||||||
|
(flags & CF.Trailing && !isTrailing(comment)) ||
|
||||||
|
(flags & CF.Dangling && !isDangling(comment)) ||
|
||||||
|
(flags & CF.Block && !is_BlockCommentKind(comment)) ||
|
||||||
|
(flags & CF.Line && !is_LineCommentKind(comment)) ||
|
||||||
|
(flags & CF.First && index !== 0) ||
|
||||||
|
(flags & CF.Last && !iLast(index, comments)) ||
|
||||||
|
(flags & CF.PrettierIgnore && !(isPrettierIgnoreComment(comment) || isPrettierIgnoreAttribute(comment))) ||
|
||||||
|
(fn && !fn(comment))
|
||||||
|
);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export function hasComment(node: Node, flags: number = 0, fn?: (comment: AnyComment) => boolean) {
|
||||||
|
if ("comments" in node && node.comments!.length > 0) {
|
||||||
|
return flags || fn ? (node.comments as AnyComment[]).some(getCommentTestFunction(flags, fn)) : true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
export function hasNewlineInRange(leftIndex: number, rightIndex: number) {
|
||||||
|
__DEV__: assert(leftIndex <= rightIndex);
|
||||||
|
const text = getContext().options.originalText;
|
||||||
|
for (var i = leftIndex; i < rightIndex; ++i) if (text.charCodeAt(i) === 10) return true;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
export function isNextLineEmpty(node: Node) {
|
||||||
|
return isNextLineEmptyAfterIndex(end(node));
|
||||||
|
}
|
||||||
|
export function isNextLineEmptyAfterIndex(index: number | false) {
|
||||||
|
let oldIdx: number | false = -1;
|
||||||
|
let idx: number | false = index;
|
||||||
|
while (idx !== oldIdx) {
|
||||||
|
oldIdx = idx;
|
||||||
|
idx = skipToLineEnd(idx);
|
||||||
|
idx = skipBlockComment(idx);
|
||||||
|
idx = skipSpaces(idx);
|
||||||
|
idx = skipParens(idx);
|
||||||
|
}
|
||||||
|
idx = skipLineComment(idx);
|
||||||
|
idx = skipParens(idx);
|
||||||
|
idx = skipNewline(idx);
|
||||||
|
idx = skipParens(idx);
|
||||||
|
return idx !== false && hasNewline(idx);
|
||||||
|
}
|
||||||
|
export function hasNewline(index: number | false, backwards = false) {
|
||||||
|
if (index === false) return false;
|
||||||
|
const i = skipSpaces(index, backwards);
|
||||||
|
return i !== false && i !== skipNewline(i, backwards);
|
||||||
|
}
|
||||||
|
function skipLineComment(index: number | false) {
|
||||||
|
if (index === false) return false;
|
||||||
|
const { commentSpans, originalText } = getContext().options;
|
||||||
|
if (commentSpans.has(index) && originalText.charCodeAt(index + 1) === 47 /** "/" */)
|
||||||
|
return skipEverythingButNewLine(commentSpans.get(index)!);
|
||||||
|
return index;
|
||||||
|
}
|
||||||
|
function skipBlockComment(index: number | false) {
|
||||||
|
if (index === false) return false;
|
||||||
|
const { commentSpans, originalText } = getContext().options;
|
||||||
|
if (commentSpans.has(index) && originalText.charCodeAt(index + 1) === 42 /** "*" */) return commentSpans.get(index)!;
|
||||||
|
return index;
|
||||||
|
}
|
||||||
|
const [skipSpaces, skipToLineEnd, skipEverythingButNewLine] = [/[ \t]/, /[,; \t]/, /[^\r\n]/].map(function (re) {
|
||||||
|
return function (index: number | false, backwards = false) {
|
||||||
|
if (index === false) return false;
|
||||||
|
const { originalText: text } = getContext().options;
|
||||||
|
let cursor = index;
|
||||||
|
while (cursor >= 0 && cursor < text.length) {
|
||||||
|
if (re.test(text.charAt(cursor))) backwards ? cursor-- : cursor++;
|
||||||
|
else return cursor;
|
||||||
|
}
|
||||||
|
return cursor === -1 || cursor === text.length ? cursor : false;
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
function skipNewline(index: number | false, backwards = false) {
|
||||||
|
if (index === false) return false;
|
||||||
|
const { originalText } = getContext().options;
|
||||||
|
const atIndex = originalText.charCodeAt(index);
|
||||||
|
if (backwards) {
|
||||||
|
if (originalText.charCodeAt(index - 1) === 13 && atIndex === 10) return index - 2;
|
||||||
|
if (atIndex === 10) return index - 1;
|
||||||
|
} else {
|
||||||
|
if (atIndex === 13 && originalText.charCodeAt(index + 1) === 10) return index + 2;
|
||||||
|
if (atIndex === 10) return index + 1;
|
||||||
|
}
|
||||||
|
return index;
|
||||||
|
}
|
||||||
|
|
||||||
|
function skipParens(index: number | false, backwards = false) {
|
||||||
|
return index;
|
||||||
|
// if (index === false) return false;
|
||||||
|
// const { parensPositions } = getContext().options;
|
||||||
|
// while (parensPositions.has(index)) backwards ? index-- : index++;
|
||||||
|
// return index;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function getNextNonSpaceNonCommentCharacterIndex(node: Node) {
|
||||||
|
return getNextNonSpaceNonCommentCharacterIndexWithStartIndex(end(node));
|
||||||
|
}
|
||||||
|
function getNextNonSpaceNonCommentCharacterIndexWithStartIndex(i: number) {
|
||||||
|
let oldIdx = -1;
|
||||||
|
let nextIdx = i;
|
||||||
|
while (nextIdx !== oldIdx) {
|
||||||
|
oldIdx = nextIdx;
|
||||||
|
nextIdx = skipSpaces(nextIdx) as number;
|
||||||
|
nextIdx = skipBlockComment(nextIdx) as number;
|
||||||
|
nextIdx = skipLineComment(nextIdx) as number;
|
||||||
|
nextIdx = skipNewline(nextIdx) as number;
|
||||||
|
nextIdx = skipParens(nextIdx) as number;
|
||||||
|
}
|
||||||
|
return nextIdx;
|
||||||
|
}
|
||||||
|
export function getNextNonSpaceNonCommentCharacter(node: Node) {
|
||||||
|
return getContext().options.originalText.charAt(getNextNonSpaceNonCommentCharacterIndex(node));
|
||||||
|
}
|
||||||
|
|
||||||
|
interface CommentContext {
|
||||||
|
comment: AnyComment;
|
||||||
|
precedingNode: Node | undefined;
|
||||||
|
enclosingNode: Node | undefined;
|
||||||
|
followingNode: Node | undefined;
|
||||||
|
text: string;
|
||||||
|
options: CustomOptions;
|
||||||
|
ast: Node;
|
||||||
|
isLastComment: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
function handled(comment: AnyComment) {
|
||||||
|
return "printed" in comment;
|
||||||
|
}
|
||||||
|
function handleCommon(ctx: CommentContext): boolean {
|
||||||
|
{
|
||||||
|
const { comment, precedingNode, enclosingNode, followingNode } = ctx;
|
||||||
|
if (!enclosingNode) {
|
||||||
|
ctx.enclosingNode = ctx.comment.loc.src.program;
|
||||||
|
} else if (enclosingNode && is_NodeWithBodyOrCases(enclosingNode)) {
|
||||||
|
const body = getBodyOrCases(enclosingNode);
|
||||||
|
if (body) {
|
||||||
|
if (is_ExpressionWithBodyOrCases(enclosingNode) && enclosingNode.label) {
|
||||||
|
if (ctx.precedingNode === enclosingNode.label) {
|
||||||
|
ctx.precedingNode = undefined;
|
||||||
|
}
|
||||||
|
if (followingNode === enclosingNode.label) {
|
||||||
|
ctx.followingNode = undefined;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (comment.loc.isBefore(body)) {
|
||||||
|
if (followingNode && body.loc.contains(followingNode)) {
|
||||||
|
ctx.followingNode = undefined;
|
||||||
|
}
|
||||||
|
if (!ctx.precedingNode && !ctx.followingNode) {
|
||||||
|
addLeadingComment(enclosingNode, comment);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
} else if (comment.loc.isAfter(body)) {
|
||||||
|
if (precedingNode && body.loc.contains(precedingNode)) {
|
||||||
|
ctx.precedingNode = undefined;
|
||||||
|
}
|
||||||
|
if (!ctx.precedingNode && !ctx.followingNode) {
|
||||||
|
addTrailingComment(enclosingNode, comment);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
} else if (body.loc.contains(comment)) {
|
||||||
|
if (precedingNode && !body.loc.contains(precedingNode)) {
|
||||||
|
ctx.precedingNode = undefined;
|
||||||
|
}
|
||||||
|
if (followingNode && !body.loc.contains(followingNode)) {
|
||||||
|
ctx.followingNode = undefined;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (const fn of [
|
||||||
|
handleMixedInOuterAttributeComments,
|
||||||
|
handleAttributeComments,
|
||||||
|
handleDanglingComments,
|
||||||
|
handleFunctionComments,
|
||||||
|
handleMacroRuleComments,
|
||||||
|
handleStructLiteralComments,
|
||||||
|
handleVariableDeclaratorComments,
|
||||||
|
handleIfBlockExpressionComments,
|
||||||
|
handleMemberExpressionComments,
|
||||||
|
handleStatementComments,
|
||||||
|
handleFlowControlComments,
|
||||||
|
handleBadComments,
|
||||||
|
]) {
|
||||||
|
fn(ctx);
|
||||||
|
if (handled(ctx.comment)) {
|
||||||
|
// console.log(ctx.comment.loc.url(), fn.name);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const { precedingNode, followingNode, comment } = ctx;
|
||||||
|
|
||||||
|
if (isStartOfLine(comment)) {
|
||||||
|
if (followingNode) {
|
||||||
|
addLeadingComment(followingNode, comment);
|
||||||
|
} else if (precedingNode) {
|
||||||
|
addTrailingComment(precedingNode, comment);
|
||||||
|
} else {
|
||||||
|
exit.never(ctx);
|
||||||
|
}
|
||||||
|
} else if (isEndOfLine(comment)) {
|
||||||
|
if (precedingNode) {
|
||||||
|
addTrailingComment(precedingNode, comment);
|
||||||
|
} else if (followingNode) {
|
||||||
|
addLeadingComment(followingNode, comment);
|
||||||
|
} else {
|
||||||
|
exit.never(ctx);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (precedingNode && followingNode) {
|
||||||
|
return false;
|
||||||
|
} else if (precedingNode) {
|
||||||
|
addTrailingComment(precedingNode, comment);
|
||||||
|
} else if (followingNode) {
|
||||||
|
addLeadingComment(followingNode, comment);
|
||||||
|
} else {
|
||||||
|
exit.never(ctx);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return handled(ctx.comment);
|
||||||
|
}
|
||||||
|
export function handleOwnLineComment(ctx: CommentContext) {
|
||||||
|
return handleCommon(ctx);
|
||||||
|
}
|
||||||
|
export function handleEndOfLineComment(ctx: CommentContext) {
|
||||||
|
const { precedingNode, enclosingNode, comment } = ctx;
|
||||||
|
if (
|
||||||
|
// handleCallExpressionComments
|
||||||
|
precedingNode &&
|
||||||
|
enclosingNode &&
|
||||||
|
is_CallExpression_or_CallLikeMacroInvocation(enclosingNode) &&
|
||||||
|
enclosingNode.arguments.length > 0 &&
|
||||||
|
precedingNode === (enclosingNode.typeArguments ? last_of(enclosingNode.typeArguments) : enclosingNode.callee)
|
||||||
|
) {
|
||||||
|
addLeadingComment(enclosingNode.arguments[0], comment);
|
||||||
|
return true;
|
||||||
|
} else if (
|
||||||
|
// handlePropertyComments
|
||||||
|
enclosingNode &&
|
||||||
|
is_StructLiteralProperty(enclosingNode)
|
||||||
|
) {
|
||||||
|
addLeadingComment(enclosingNode, comment);
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
return handleCommon(ctx);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export function handleRemainingComment(ctx: CommentContext) {
|
||||||
|
return handleCommon(ctx);
|
||||||
|
}
|
||||||
|
|
||||||
|
function handleStructLiteralComments({ enclosingNode, followingNode, comment }: CommentContext) {
|
||||||
|
if (enclosingNode && is_StructLiteralPropertySpread(enclosingNode) && followingNode === enclosingNode.expression) {
|
||||||
|
addLeadingComment(enclosingNode, comment);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function handleVariableDeclaratorComments({ enclosingNode, followingNode, comment }: CommentContext) {
|
||||||
|
if (
|
||||||
|
enclosingNode &&
|
||||||
|
(is_xVariableEqualishLike(enclosingNode) || is_ReassignmentNode(enclosingNode)) &&
|
||||||
|
followingNode &&
|
||||||
|
(is_BlockCommentKind(comment) ||
|
||||||
|
nisAnyOf(followingNode, [
|
||||||
|
NodeType.StructLiteral,
|
||||||
|
NodeType.StructPattern,
|
||||||
|
NodeType.TupleLiteral,
|
||||||
|
NodeType.TypeTuple,
|
||||||
|
NodeType.TuplePattern,
|
||||||
|
NodeType.ArrayLiteral,
|
||||||
|
NodeType.ArrayPattern,
|
||||||
|
NodeType.SizedArrayLiteral,
|
||||||
|
NodeType.TypeSizedArray,
|
||||||
|
]))
|
||||||
|
) {
|
||||||
|
addLeadingComment(followingNode, comment);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function handleMixedInOuterAttributeComments({ precedingNode, enclosingNode, followingNode, comment }: CommentContext) {
|
||||||
|
if (enclosingNode && hasOuterAttributes(enclosingNode) && end(comment) <= ownStart(enclosingNode)) {
|
||||||
|
if (isPrettierIgnoreComment(comment) || isPrettierIgnoreAttribute(comment)) {
|
||||||
|
setPrettierIgnoreTarget(enclosingNode, comment);
|
||||||
|
}
|
||||||
|
if (isEndOfLine(comment)) {
|
||||||
|
__DEV__: assert(!!precedingNode && is_Attribute(precedingNode), "", precedingNode);
|
||||||
|
if (shouldPrintOuterAttributesAbove(enclosingNode)) {
|
||||||
|
// #[attr] // comment
|
||||||
|
// node
|
||||||
|
addTrailingComment(precedingNode, comment);
|
||||||
|
} else {
|
||||||
|
// #[attr] /* comment */ node
|
||||||
|
addLeadingComment(followingNode || enclosingNode, comment);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// __DEV__: assert(isStartOfLine(comment));
|
||||||
|
if (followingNode && end(followingNode) <= ownStart(enclosingNode)) {
|
||||||
|
addLeadingComment(followingNode, comment);
|
||||||
|
} else if (precedingNode && enclosingNode.loc.contains(precedingNode)) {
|
||||||
|
addTrailingComment(precedingNode, comment);
|
||||||
|
} else {
|
||||||
|
addLeadingComment(enclosingNode, comment);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
function handleAttributeComments({ precedingNode, enclosingNode, followingNode, comment, ast }: CommentContext) {
|
||||||
|
if (is_AttributeOrDocComment(comment)) {
|
||||||
|
if (
|
||||||
|
comment.inner &&
|
||||||
|
enclosingNode &&
|
||||||
|
is_FunctionDeclaration(enclosingNode) &&
|
||||||
|
(!followingNode || !is_StatementNode(followingNode)) &&
|
||||||
|
(!precedingNode || !is_StatementNode(precedingNode))
|
||||||
|
) {
|
||||||
|
if (enclosingNode.body) {
|
||||||
|
if (canAttachCommentInLocArray(enclosingNode.body)) {
|
||||||
|
addDanglingComment(enclosingNode, comment, DCM["body"]);
|
||||||
|
} else {
|
||||||
|
addLeadingComment(enclosingNode.body[0], comment);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
addLeadingComment(enclosingNode, comment);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// if (comment.loc.url().startsWith("tests/samples/macro/attr.rs") && getContext().options.danglingAttributes.includes(comment)) {
|
||||||
|
// // debugger;
|
||||||
|
// console.log({
|
||||||
|
// comment: comment.loc.url(),
|
||||||
|
// precedingNode: precedingNode?.loc.url(),
|
||||||
|
// enclosingNode: enclosingNode?.loc.url(),
|
||||||
|
// followingNode: followingNode?.loc.url(),
|
||||||
|
// });
|
||||||
|
// }
|
||||||
|
if (followingNode) {
|
||||||
|
addLeadingComment(followingNode, comment);
|
||||||
|
} else if (enclosingNode) {
|
||||||
|
for (var key in DCM)
|
||||||
|
if (key in enclosingNode) {
|
||||||
|
addDanglingComment(enclosingNode, comment, key as DCM);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
addDanglingComment(ast, comment, DCM["body"]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function handleBadComments({ precedingNode, enclosingNode, followingNode, ast, comment }: CommentContext) {
|
||||||
|
if (!enclosingNode) {
|
||||||
|
// console.log(comment.loc.url());
|
||||||
|
if (followingNode) {
|
||||||
|
addLeadingComment(followingNode, comment);
|
||||||
|
} else if (precedingNode) {
|
||||||
|
addTrailingComment(precedingNode, comment);
|
||||||
|
} else {
|
||||||
|
addDanglingComment(enclosingNode || ast, comment, DCM["body"]);
|
||||||
|
}
|
||||||
|
} else if (!precedingNode && !followingNode) {
|
||||||
|
if (enclosingNode && enclosingNode !== ast) {
|
||||||
|
addLeadingComment(enclosingNode, comment);
|
||||||
|
} else {
|
||||||
|
addDanglingComment(ast, comment, DCM["body"]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
function is_ABI_Comment({ precedingNode, enclosingNode, comment }: CommentContext) {
|
||||||
|
return (
|
||||||
|
is_CommentOrDocComment(comment) &&
|
||||||
|
((precedingNode && is_ExternSpecifier(precedingNode)) || (enclosingNode && is_ExternSpecifier(enclosingNode)))
|
||||||
|
);
|
||||||
|
}
|
||||||
|
function handleFlowControlComments({ precedingNode, enclosingNode, followingNode, comment }: CommentContext) {
|
||||||
|
if (enclosingNode && is_FlowControlExpression(enclosingNode)) {
|
||||||
|
if (!precedingNode && (isOwnLine(comment) || isEndOfLine(comment)) && !followingNode) {
|
||||||
|
addLeadingComment(enclosingNode, comment);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
function handleFunctionComments(ctx: CommentContext) {
|
||||||
|
const { precedingNode, enclosingNode, followingNode, comment } = ctx;
|
||||||
|
if (enclosingNode && is_FunctionNode(enclosingNode)) {
|
||||||
|
if (
|
||||||
|
is_FunctionDeclaration(enclosingNode) &&
|
||||||
|
((!is_ABI_Comment(ctx) && comment.loc.isBefore(enclosingNode.generics || enclosingNode.id)) ||
|
||||||
|
(enclosingNode.generics && comment.loc.isBetween(enclosingNode.generics, enclosingNode.parameters)))
|
||||||
|
) {
|
||||||
|
addLeadingComment(enclosingNode, comment);
|
||||||
|
} else if (
|
||||||
|
!enclosingNode.returnType &&
|
||||||
|
comment.loc.isBetween(
|
||||||
|
enclosingNode.parameters,
|
||||||
|
is_FunctionDeclaration(enclosingNode) ? enclosingNode.body! : enclosingNode.expression
|
||||||
|
)
|
||||||
|
) {
|
||||||
|
if (is_FunctionDeclaration(enclosingNode)) {
|
||||||
|
addCommentToBlock(enclosingNode, comment);
|
||||||
|
} else {
|
||||||
|
addLeadingComment(enclosingNode.expression, comment);
|
||||||
|
}
|
||||||
|
} else if (
|
||||||
|
precedingNode && //
|
||||||
|
enclosingNode.parameters.loc.contains(comment)
|
||||||
|
) {
|
||||||
|
if (precedingNode === getLastParameter(enclosingNode)) {
|
||||||
|
addTrailingComment(precedingNode, comment);
|
||||||
|
}
|
||||||
|
} else if (
|
||||||
|
followingNode &&
|
||||||
|
isStartOfLine(comment) &&
|
||||||
|
comment.loc.isAfter(enclosingNode.parameters) &&
|
||||||
|
(!is_FunctionDeclaration(enclosingNode) || !enclosingNode.whereBounds || comment.loc.isAfter(enclosingNode.whereBounds!)) &&
|
||||||
|
(!enclosingNode.returnType || comment.loc.isAfter(enclosingNode.returnType)) &&
|
||||||
|
followingNode === (is_FunctionDeclaration(enclosingNode) ? enclosingNode.body?.[0] : enclosingNode.expression)
|
||||||
|
) {
|
||||||
|
addLeadingComment(followingNode, comment);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
function handleMacroRuleComments(ctx: CommentContext) {
|
||||||
|
const { precedingNode, enclosingNode, followingNode, comment } = ctx;
|
||||||
|
if (enclosingNode && is_MacroRule(enclosingNode)) {
|
||||||
|
if (enclosingNode.transform.loc.contains(comment)) {
|
||||||
|
__DEV__: assert(enclosingNode.transform.length > 0);
|
||||||
|
if (!precedingNode || !enclosingNode.transform.loc.contains(precedingNode)) {
|
||||||
|
__DEV__: assert(!!followingNode && enclosingNode.transform.loc.contains(followingNode));
|
||||||
|
addLeadingComment(followingNode, comment);
|
||||||
|
}
|
||||||
|
} else if (enclosingNode.match.loc.contains(comment)) {
|
||||||
|
__DEV__: assert(enclosingNode.match.length > 0);
|
||||||
|
if (!followingNode || !enclosingNode.match.loc.contains(followingNode)) {
|
||||||
|
__DEV__: assert(!!precedingNode && enclosingNode.match.loc.contains(precedingNode));
|
||||||
|
addTrailingComment(precedingNode!, comment);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function handleStatementComments(ctx: CommentContext) {
|
||||||
|
const { precedingNode, comment } = ctx;
|
||||||
|
if (isEndOfLine(comment) && precedingNode && (is_StatementNode(precedingNode) || precedingNode.loc.sliceText().endsWith(";"))) {
|
||||||
|
addTrailingComment(precedingNode, comment);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function addCommentToBlock(block: NodeWithBodyOrCases, comment: AnyComment) {
|
||||||
|
const body = getBodyOrCases(block);
|
||||||
|
__DEV__: assert(!!body);
|
||||||
|
if (body.length > 0) {
|
||||||
|
addLeadingComment(body![0], comment);
|
||||||
|
} else {
|
||||||
|
addDanglingComment(block, comment, DCM["body"]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function handleIfBlockExpressionComments(ctx: CommentContext) {
|
||||||
|
const { comment, enclosingNode } = ctx;
|
||||||
|
if (enclosingNode && is_IfBlockExpression(enclosingNode)) {
|
||||||
|
const { condition, body, else: else_ } = enclosingNode;
|
||||||
|
if (comment.loc.isBefore(condition)) {
|
||||||
|
addLeadingComment(condition, comment);
|
||||||
|
} else if (comment.loc.isBetween(condition, body)) {
|
||||||
|
addTrailingComment(condition, comment);
|
||||||
|
} else if (else_ && comment.loc.isBetween(body, else_)) {
|
||||||
|
if (is_IfBlockExpression(else_)) {
|
||||||
|
addLeadingComment(else_.condition, comment);
|
||||||
|
} else {
|
||||||
|
addCommentToBlock(else_, comment);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function handleMemberExpressionComments({ comment, precedingNode, enclosingNode }: CommentContext) {
|
||||||
|
if (enclosingNode && is_MemberAccessLike(enclosingNode)) {
|
||||||
|
if (isStartOfLine(comment) || !precedingNode) addLeadingComment(enclosingNode, comment);
|
||||||
|
else addTrailingComment(precedingNode, comment);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
function handleDanglingComments({ comment, enclosingNode }: CommentContext) {
|
||||||
|
if (enclosingNode) {
|
||||||
|
for (var key in DCM) {
|
||||||
|
if (key in enclosingNode) {
|
||||||
|
var arr: LocArray = enclosingNode[key];
|
||||||
|
if (is_LocArray(arr) && canAttachCommentInLocArray(arr) && arr.loc.contains(comment)) {
|
||||||
|
addDanglingComment(enclosingNode, comment, key as DCM);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function canAttachCommentInLocArray(arr: LocArray) {
|
||||||
|
return arr.length === 0 || arr.every((node) => !canAttachComment(node));
|
||||||
|
}
|
||||||
|
|
||||||
|
function isOwnLine(comment: AnyComment) {
|
||||||
|
return isStartOfLine(comment) && hasBreaklineAfter(comment);
|
||||||
|
}
|
||||||
|
function isStartOfLine(comment: AnyComment) {
|
||||||
|
return comment.placement === "ownLine";
|
||||||
|
}
|
||||||
|
function isEndOfLine(comment: AnyComment) {
|
||||||
|
return comment.placement === "endOfLine";
|
||||||
|
}
|
||||||
|
export function isDangling(comment: AnyComment) {
|
||||||
|
__DEV__: assert(handled(comment));
|
||||||
|
return !comment.leading && !comment.trailing;
|
||||||
|
}
|
||||||
|
export function isLeading(comment: AnyComment) {
|
||||||
|
__DEV__: assert(handled(comment));
|
||||||
|
return comment.leading && !comment.trailing;
|
||||||
|
}
|
||||||
|
export function isTrailing(comment: AnyComment) {
|
||||||
|
__DEV__: assert(handled(comment));
|
||||||
|
return !comment.leading && comment.trailing;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function print_comment(comment: CommentOrDocComment) {
|
||||||
|
__DEV__: Narrow<PrettierCommentInfo>(comment);
|
||||||
|
|
||||||
|
const doc = is_BlockCommentNode(comment)
|
||||||
|
? isIndentableBlockComment(comment.value)
|
||||||
|
? [
|
||||||
|
(!handled(comment) || isTrailing(comment)) && !hasBreaklineBefore(comment) ? hardline : "",
|
||||||
|
getCommentStart(comment),
|
||||||
|
...comment.value.split(/\n/g).map((line, i, a) =>
|
||||||
|
i === 0 //
|
||||||
|
? [line.trimEnd(), hardline]
|
||||||
|
: !iLast(i, a)
|
||||||
|
? [" " + line.trim(), hardline]
|
||||||
|
: " " + line.trimStart()
|
||||||
|
),
|
||||||
|
"*/",
|
||||||
|
]
|
||||||
|
: [
|
||||||
|
getCommentStart(comment), //
|
||||||
|
join(literalline, comment.value.split(/\n/g)),
|
||||||
|
"*/",
|
||||||
|
]
|
||||||
|
: [getCommentStart(comment), comment.value.trimEnd()];
|
||||||
|
|
||||||
|
return handled(comment) && isDangling(comment) //
|
||||||
|
? [doc, getPostLeadingComment(comment)]
|
||||||
|
: doc;
|
||||||
|
|
||||||
|
function getCommentStart(comment: CommentOrDocComment) {
|
||||||
|
return is_Comment(comment)
|
||||||
|
? is_BlockCommentKind(comment)
|
||||||
|
? "/*"
|
||||||
|
: "//"
|
||||||
|
: is_BlockCommentKind(comment)
|
||||||
|
? isInner(comment)
|
||||||
|
? "/*!"
|
||||||
|
: "/**"
|
||||||
|
: isInner(comment)
|
||||||
|
? "//!"
|
||||||
|
: "///";
|
||||||
|
}
|
||||||
|
function isIndentableBlockComment(value: string) {
|
||||||
|
const lines = `*${value}*`.split(/\n/g);
|
||||||
|
return lines.length > 1 && lines.every((line) => /^\s*\*/.test(line));
|
||||||
|
}
|
||||||
|
}
|
||||||
282
frontend/src/common/prettier/plugins/rust/format/complexity.ts
Normal file
282
frontend/src/common/prettier/plugins/rust/format/complexity.ts
Normal file
@@ -0,0 +1,282 @@
|
|||||||
|
import {
|
||||||
|
ForLtParametersBody,
|
||||||
|
FunctionSpread,
|
||||||
|
GenericParameterDeclaration,
|
||||||
|
MaybeGenericArgsTarget,
|
||||||
|
MissingNode,
|
||||||
|
Node,
|
||||||
|
NodeType,
|
||||||
|
TypeBound,
|
||||||
|
TypeBoundsConstaint,
|
||||||
|
TypeCallArgument,
|
||||||
|
TypeNamespaceTargetNoSelector,
|
||||||
|
TypeNode,
|
||||||
|
} from "jinx-rust";
|
||||||
|
import {
|
||||||
|
getAstPath,
|
||||||
|
getOwnChildAstPath,
|
||||||
|
is_BareTypeTraitBound,
|
||||||
|
is_FunctionSpread,
|
||||||
|
is_LetScrutinee,
|
||||||
|
is_Literal,
|
||||||
|
is_MissingNode,
|
||||||
|
is_TypeBoundsStandaloneNode,
|
||||||
|
is_TypeFunctionNode,
|
||||||
|
is_TypeNode,
|
||||||
|
is_VariableDeclarationNode,
|
||||||
|
} from "jinx-rust/utils";
|
||||||
|
import { exit, has_key_defined, last_of, spliceAll } from "../utils/common";
|
||||||
|
import { canBreak } from "./external";
|
||||||
|
import { getContext, getNode, getOptions, getPrintFn } from "./plugin";
|
||||||
|
|
||||||
|
let DEPTH = 0;
|
||||||
|
const ANCESTRY: Node[] = [];
|
||||||
|
const LONE_SHORT_ARGUMENT_THRESHOLD_RATE = 0.25;
|
||||||
|
|
||||||
|
export function withCheckContext<R>(fn: () => R): R {
|
||||||
|
if (0 === DEPTH) {
|
||||||
|
return fn();
|
||||||
|
} else {
|
||||||
|
DEPTH = 0;
|
||||||
|
const prev = spliceAll(ANCESTRY);
|
||||||
|
try {
|
||||||
|
return fn();
|
||||||
|
} finally {
|
||||||
|
DEPTH = ANCESTRY.push(...prev);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export function is_short(str: string) {
|
||||||
|
return str.length <= LONE_SHORT_ARGUMENT_THRESHOLD_RATE * getOptions().printWidth;
|
||||||
|
}
|
||||||
|
function print(target: Node) {
|
||||||
|
const current = getNode();
|
||||||
|
const keys: (string | number)[] = [...getAstPath(ANCESTRY[0], getNode())];
|
||||||
|
for (let i = 1; i < ANCESTRY.length; i++) keys.push(...getOwnChildAstPath(ANCESTRY[i - 1], ANCESTRY[i]));
|
||||||
|
keys.push(...getOwnChildAstPath(last_of(ANCESTRY), target));
|
||||||
|
try {
|
||||||
|
return getContext().path.call(() => getPrintFn(target)(), ...keys);
|
||||||
|
} catch (e) {
|
||||||
|
console.log({ current, target, keys, ANCESTRY });
|
||||||
|
throw e;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function IsSimpleFunction<T extends Node>(fn: (node: T) => boolean): (node: T) => boolean {
|
||||||
|
return function (node: T) {
|
||||||
|
if (0 !== DEPTH && node === ANCESTRY[DEPTH - 1]) {
|
||||||
|
return fn(node);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (DEPTH >= 2) {
|
||||||
|
return isShortBasic(node);
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
return fn((ANCESTRY[DEPTH++] = node) as any);
|
||||||
|
} finally {
|
||||||
|
ANCESTRY.length = --DEPTH;
|
||||||
|
}
|
||||||
|
} as any;
|
||||||
|
}
|
||||||
|
|
||||||
|
function HasComplexFunction<T extends Node>(fn: (node: T) => boolean): (node: T) => boolean {
|
||||||
|
return function (node: T) {
|
||||||
|
if (0 !== DEPTH && node === ANCESTRY[DEPTH - 1]) {
|
||||||
|
return fn(node);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (DEPTH >= 2) {
|
||||||
|
return !isShortBasic(node);
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
return fn((ANCESTRY[DEPTH++] = node) as any);
|
||||||
|
} finally {
|
||||||
|
ANCESTRY.length = --DEPTH;
|
||||||
|
}
|
||||||
|
} as any;
|
||||||
|
}
|
||||||
|
|
||||||
|
const isShortBasic = (node: Node) => {
|
||||||
|
switch (node.nodeType) {
|
||||||
|
case NodeType.MissingNode:
|
||||||
|
return true;
|
||||||
|
case NodeType.Identifier:
|
||||||
|
case NodeType.Index:
|
||||||
|
case NodeType.LtIdentifier:
|
||||||
|
case NodeType.LbIdentifier:
|
||||||
|
case NodeType.McIdentifier:
|
||||||
|
return is_short(node.name);
|
||||||
|
case NodeType.Literal:
|
||||||
|
return is_short(node.value) && !/\n/.test(node.value);
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
};
|
||||||
|
|
||||||
|
export const isSimpleType = IsSimpleFunction<FunctionSpread | TypeNode | MissingNode>((node): boolean => {
|
||||||
|
switch (node.nodeType) {
|
||||||
|
case NodeType.MissingNode:
|
||||||
|
case NodeType.FunctionSpread:
|
||||||
|
return true;
|
||||||
|
case NodeType.MacroInvocation:
|
||||||
|
return false;
|
||||||
|
case NodeType.Identifier:
|
||||||
|
case NodeType.TypeNever:
|
||||||
|
case NodeType.TypeInferred:
|
||||||
|
return true;
|
||||||
|
case NodeType.TypePath:
|
||||||
|
return isShortBasic(node.segment) && (!node.namespace || isSimpleType(node.namespace));
|
||||||
|
case NodeType.TypeCall:
|
||||||
|
return isSimpleType(node.typeCallee) && !hasComplexTypeArguments(node);
|
||||||
|
case NodeType.ExpressionTypeSelector:
|
||||||
|
return isSimpleType(node.typeTarget) && (!node.typeExpression || isSimpleType(node.typeExpression));
|
||||||
|
case NodeType.TypeDynBounds:
|
||||||
|
return !hasComplexTypeBounds(node);
|
||||||
|
case NodeType.TypeImplBounds:
|
||||||
|
return !hasComplexTypeBounds(node);
|
||||||
|
case NodeType.TypeFnPointer: {
|
||||||
|
const param = node.parameters[0];
|
||||||
|
return (
|
||||||
|
(!node.extern || !node.extern.abi || isShortBasic(node.extern.abi)) &&
|
||||||
|
!hasComplexLtParameters(node) &&
|
||||||
|
(node.parameters.length === 0 ||
|
||||||
|
(node.parameters.length === 1 &&
|
||||||
|
(is_FunctionSpread(param) ||
|
||||||
|
(!is_TypeFunctionNode(param.typeAnnotation) && isSimpleType(param.typeAnnotation))))) &&
|
||||||
|
(!node.returnType || isSimpleType(node.returnType))
|
||||||
|
);
|
||||||
|
}
|
||||||
|
case NodeType.TypeFunction:
|
||||||
|
return isSimpleType(node.callee) && node.parameters.every(isSimpleType) && (!node.returnType || isSimpleType(node.returnType));
|
||||||
|
case NodeType.TypeSizedArray:
|
||||||
|
return isSimpleType(node.typeExpression) && isShortBasic(node.sizeExpression);
|
||||||
|
case NodeType.TypeSlice:
|
||||||
|
return isSimpleType(node.typeExpression);
|
||||||
|
case NodeType.TypeTuple:
|
||||||
|
return node.items.length === 0 || (node.items.length === 1 && isSimpleType(node.items[0]));
|
||||||
|
case NodeType.TypeReference:
|
||||||
|
case NodeType.TypeDereferenceMut:
|
||||||
|
case NodeType.TypeDereferenceConst:
|
||||||
|
case NodeType.TypeParenthesized:
|
||||||
|
return isSimpleType(node.typeExpression);
|
||||||
|
default:
|
||||||
|
__DEV__: exit.never(node);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
export const hasComplexTypeBounds = HasComplexFunction<Extract<Node, TypeBoundsConstaint>>((node) => {
|
||||||
|
return !!node.typeBounds && node.typeBounds.length > 1 && !node.typeBounds.every(isSimpleTypeBound);
|
||||||
|
});
|
||||||
|
|
||||||
|
export const isSimpleTypeBound = (node: TypeBound): boolean => {
|
||||||
|
switch (node.nodeType) {
|
||||||
|
case NodeType.TypeParenthesized:
|
||||||
|
return isSimpleTypeBound(node.typeExpression);
|
||||||
|
// #Lifetime
|
||||||
|
case NodeType.LtIdentifier:
|
||||||
|
case NodeType.LtElided:
|
||||||
|
case NodeType.LtStatic:
|
||||||
|
return true;
|
||||||
|
case NodeType.TypeTraitBound:
|
||||||
|
return is_BareTypeTraitBound(node) && isSimpleTypeNamespaceTargetNoSelector(node.typeExpression);
|
||||||
|
default:
|
||||||
|
__DEV__: exit.never(node);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
function isSimpleTypeNamespaceTargetNoSelector(node: TypeNamespaceTargetNoSelector): boolean {
|
||||||
|
switch (node.nodeType) {
|
||||||
|
case NodeType.Identifier:
|
||||||
|
return true;
|
||||||
|
case NodeType.TypePath:
|
||||||
|
return undefined === node.namespace || isSimpleTypeNamespaceTargetNoSelector(node.namespace);
|
||||||
|
case NodeType.TypeCall:
|
||||||
|
return false;
|
||||||
|
case NodeType.TypeFunction:
|
||||||
|
return isSimpleTypeNamespaceTargetNoSelector(node.callee) && node.parameters.length === 0 && !node.returnType;
|
||||||
|
default:
|
||||||
|
__DEV__: exit.never(node);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const isSimpleTypeArgument = IsSimpleFunction<TypeCallArgument>((node) => {
|
||||||
|
if (is_TypeNode(node)) {
|
||||||
|
return isSimpleType(node);
|
||||||
|
}
|
||||||
|
switch (node.nodeType) {
|
||||||
|
// #Lifetime
|
||||||
|
case NodeType.LtIdentifier:
|
||||||
|
case NodeType.LtElided:
|
||||||
|
case NodeType.LtStatic:
|
||||||
|
case NodeType.Literal:
|
||||||
|
return true;
|
||||||
|
case NodeType.MinusExpression:
|
||||||
|
return is_Literal(node.expression);
|
||||||
|
case NodeType.BlockExpression:
|
||||||
|
return false; //willBreak(getPrintFn(node)("body"));
|
||||||
|
case NodeType.TypeCallNamedArgument:
|
||||||
|
return isSimpleType(node.typeExpression);
|
||||||
|
case NodeType.TypeCallNamedBound:
|
||||||
|
return isSimpleType(node.typeTarget) && !hasComplexTypeBounds(node);
|
||||||
|
default:
|
||||||
|
__DEV__: exit.never(node);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
export const hasComplexTypeArguments = HasComplexFunction<Extract<Node, MaybeGenericArgsTarget>>((node) =>
|
||||||
|
!node.typeArguments || node.typeArguments.length === 0
|
||||||
|
? false
|
||||||
|
: node.typeArguments.length === 1
|
||||||
|
? (() => {
|
||||||
|
const arg = node.typeArguments[0];
|
||||||
|
return is_TypeBoundsStandaloneNode(arg) || canBreak(print(arg));
|
||||||
|
})()
|
||||||
|
: true
|
||||||
|
);
|
||||||
|
|
||||||
|
export const hasComplexLtParameters = HasComplexFunction<Extract<Node, ForLtParametersBody>>((node) => {
|
||||||
|
const ltParameters = node.ltParameters;
|
||||||
|
if (!ltParameters || ltParameters.length === 0) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (ltParameters.length === 1) {
|
||||||
|
const arg = ltParameters[0];
|
||||||
|
if (arg.ltBounds && arg.ltBounds.length > 1) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
});
|
||||||
|
|
||||||
|
export const isShortGenericParameterDeclaration = IsSimpleFunction<GenericParameterDeclaration>((node) => {
|
||||||
|
switch (node.nodeType) {
|
||||||
|
case NodeType.GenericTypeParameterDeclaration:
|
||||||
|
return !node.typeBounds && !node.typeDefault;
|
||||||
|
case NodeType.ConstTypeParameterDeclaration:
|
||||||
|
return (!node.typeAnnotation || is_MissingNode(node)) && !node.typeDefault;
|
||||||
|
case NodeType.GenericLtParameterDeclaration:
|
||||||
|
return !node.ltBounds;
|
||||||
|
default:
|
||||||
|
exit.never();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
export const hasComplexGenerics = HasComplexFunction<Node>((node) => {
|
||||||
|
return has_key_defined(node, "generics") && node.generics.length > 0 && !node.generics.every(isShortGenericParameterDeclaration);
|
||||||
|
});
|
||||||
|
|
||||||
|
export const hasComplexTypeAnnotation = HasComplexFunction<Node>((node) => {
|
||||||
|
if (is_VariableDeclarationNode(node) && !is_LetScrutinee(node)) {
|
||||||
|
const { typeAnnotation } = node;
|
||||||
|
return !!typeAnnotation && !is_MissingNode(typeAnnotation) && !isSimpleType(typeAnnotation);
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
});
|
||||||
2349
frontend/src/common/prettier/plugins/rust/format/core.ts
Normal file
2349
frontend/src/common/prettier/plugins/rust/format/core.ts
Normal file
File diff suppressed because it is too large
Load Diff
126
frontend/src/common/prettier/plugins/rust/format/external.ts
Normal file
126
frontend/src/common/prettier/plugins/rust/format/external.ts
Normal file
@@ -0,0 +1,126 @@
|
|||||||
|
import { Attribute, AttributeOrDocComment, Comment, DocCommentAttribute, LocArray, MemberExpression, Node, SourceFile } from "jinx-rust";
|
||||||
|
import { PickProps } from "jinx-rust/utils";
|
||||||
|
import type { Doc, ParserOptions, Printer } from "prettier";
|
||||||
|
import { doc } from "prettier";
|
||||||
|
import { AssertTypesEq } from "../utils/common";
|
||||||
|
|
||||||
|
export type { Doc, ParserOptions, Plugin, Printer } from "prettier";
|
||||||
|
|
||||||
|
|
||||||
|
export const {
|
||||||
|
join,
|
||||||
|
line,
|
||||||
|
softline,
|
||||||
|
hardline,
|
||||||
|
literalline,
|
||||||
|
group,
|
||||||
|
conditionalGroup,
|
||||||
|
fill,
|
||||||
|
lineSuffix,
|
||||||
|
lineSuffixBoundary,
|
||||||
|
cursor,
|
||||||
|
breakParent,
|
||||||
|
ifBreak,
|
||||||
|
trim,
|
||||||
|
indent,
|
||||||
|
indentIfBreak,
|
||||||
|
align,
|
||||||
|
addAlignmentToDoc,
|
||||||
|
markAsRoot,
|
||||||
|
dedentToRoot,
|
||||||
|
dedent,
|
||||||
|
hardlineWithoutBreakParent,
|
||||||
|
literallineWithoutBreakParent,
|
||||||
|
label,
|
||||||
|
} = doc.builders;
|
||||||
|
|
||||||
|
export const {
|
||||||
|
willBreak,
|
||||||
|
traverseDoc,
|
||||||
|
findInDoc,
|
||||||
|
mapDoc,
|
||||||
|
removeLines,
|
||||||
|
stripTrailingHardline,
|
||||||
|
} = doc.utils;
|
||||||
|
|
||||||
|
// Fallback implementations for removed common in prettier 3
|
||||||
|
export const isConcat = (doc: any): boolean => Array.isArray(doc);
|
||||||
|
export const getDocParts = (doc: any): any[] => Array.isArray(doc) ? doc : [doc];
|
||||||
|
export const propagateBreaks = (doc: any): any => doc;
|
||||||
|
export const normalizeParts = (parts: any[]): any[] => parts.flat();
|
||||||
|
export const normalizeDoc = (doc: any): any => doc;
|
||||||
|
export const cleanDoc = (doc: any): any => doc;
|
||||||
|
export const canBreak = (doc: any): boolean => {
|
||||||
|
if (!doc) return false;
|
||||||
|
if (typeof doc === 'string') return false;
|
||||||
|
if (Array.isArray(doc)) return doc.some(canBreak);
|
||||||
|
if (doc.type === 'group' || doc.type === 'fill') return true;
|
||||||
|
return willBreak(doc);
|
||||||
|
};
|
||||||
|
|
||||||
|
export const Symbol_comments = Symbol.for("comments");
|
||||||
|
|
||||||
|
export interface CustomOptions extends ParserOptions<Node> {
|
||||||
|
[Symbol_comments]: AnyComment[];
|
||||||
|
rsParsedFile: SourceFile;
|
||||||
|
commentSpans: Map<number, number>;
|
||||||
|
printer: Printer<Node>;
|
||||||
|
cursorNode: any;
|
||||||
|
|
||||||
|
comments: Comment[];
|
||||||
|
danglingAttributes: AttributeOrDocComment[];
|
||||||
|
actuallyMethodNodes: WeakSet<MemberExpression>;
|
||||||
|
}
|
||||||
|
|
||||||
|
export type NodeWithComments<T extends Node> = T & { comments: AnyComment[] };
|
||||||
|
export interface MutatedComment extends Comment, PrettierCommentInfo {}
|
||||||
|
export interface MutatedAttribute extends Attribute, PrettierCommentInfo {}
|
||||||
|
export interface MutatedDocComment extends DocCommentAttribute, PrettierCommentInfo {}
|
||||||
|
export type AnyComment = MutatedComment | MutatedAttribute | MutatedDocComment;
|
||||||
|
|
||||||
|
type keyofDelimitedArrayProps<T> = T extends never ? never : keyof PickProps<T, LocArray<any, "()" | "[]" | "{}" | "<>">>;
|
||||||
|
|
||||||
|
__DEV__: AssertTypesEq<keyof typeof DCM, keyofDelimitedArrayProps<Node>>();
|
||||||
|
|
||||||
|
export enum DCM {
|
||||||
|
"arguments" = "arguments",
|
||||||
|
"parameters" = "parameters",
|
||||||
|
"items" = "items",
|
||||||
|
"properties" = "properties",
|
||||||
|
"members" = "members",
|
||||||
|
"body" = "body",
|
||||||
|
"cases" = "cases",
|
||||||
|
"typeArguments" = "typeArguments",
|
||||||
|
"ltParameters" = "ltParameters",
|
||||||
|
"generics" = "generics",
|
||||||
|
"specifiers" = "specifiers",
|
||||||
|
"rules" = "rules",
|
||||||
|
"match" = "match",
|
||||||
|
"transform" = "transform",
|
||||||
|
"segments" = "segments",
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface PrettierCommentInfo {
|
||||||
|
trailing: boolean;
|
||||||
|
leading: boolean;
|
||||||
|
unignore: boolean;
|
||||||
|
printed: boolean;
|
||||||
|
placement: "ownLine" | "endOfLine" | "remaining";
|
||||||
|
// nodeDescription?: any;
|
||||||
|
marker?: DCM;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface AstPath<T = Node> {
|
||||||
|
stack: (Node | string | number)[];
|
||||||
|
callParent<R>(callback: (path: this) => R, count?: number): R;
|
||||||
|
getName(): PropertyKey | null;
|
||||||
|
getValue(): T;
|
||||||
|
getNode(count?: number): T | null;
|
||||||
|
getParentNode(count?: number): T | null;
|
||||||
|
|
||||||
|
match(...predicates: ((node: Node, name: string | null, number: number | null) => boolean)[]): boolean;
|
||||||
|
|
||||||
|
call<R>(callback: (path: AstPath, index: number, value: any) => R, ...props: (string | number)[]): R;
|
||||||
|
each(callback: (path: AstPath, index: number, value: any) => void, ...props: (string | number)[]): void;
|
||||||
|
map<R>(callback: (path: AstPath, index: number, value: any) => R, ...props: (string | number)[]): R[];
|
||||||
|
}
|
||||||
367
frontend/src/common/prettier/plugins/rust/format/plugin.ts
Normal file
367
frontend/src/common/prettier/plugins/rust/format/plugin.ts
Normal file
@@ -0,0 +1,367 @@
|
|||||||
|
import { AttributeOrComment, IfBlockExpression, Node, Program, rs } from "jinx-rust";
|
||||||
|
import {
|
||||||
|
ArrayProps,
|
||||||
|
BoolProps,
|
||||||
|
NodeProps,
|
||||||
|
end,
|
||||||
|
hasAttributes,
|
||||||
|
insertNodes,
|
||||||
|
is_Attribute,
|
||||||
|
is_AttributeOrComment,
|
||||||
|
is_BlockCommentKind,
|
||||||
|
is_BlockCommentNode,
|
||||||
|
is_Comment,
|
||||||
|
is_DocCommentAttribute,
|
||||||
|
is_ElseBlock,
|
||||||
|
is_LineCommentNode,
|
||||||
|
is_MacroInvocation,
|
||||||
|
is_MacroRule,
|
||||||
|
is_MissingNode,
|
||||||
|
is_Node,
|
||||||
|
is_PunctuationToken,
|
||||||
|
is_UnionPattern,
|
||||||
|
start,
|
||||||
|
} from "jinx-rust/utils";
|
||||||
|
import { getCommentChildNodes, isTransformed, transform_ast } from "../transform";
|
||||||
|
import { Narrow, assert, color, each, exit, iLast, is_array, map_tagged_template, print_string } from "../utils/common";
|
||||||
|
import {
|
||||||
|
CF,
|
||||||
|
escapeComments,
|
||||||
|
getComments,
|
||||||
|
handleEndOfLineComment,
|
||||||
|
handleOwnLineComment,
|
||||||
|
handleRemainingComment,
|
||||||
|
hasBreaklineAfter,
|
||||||
|
hasComment,
|
||||||
|
isDangling,
|
||||||
|
isPrettierIgnoreAttribute,
|
||||||
|
setDidPrintComment,
|
||||||
|
withComments,
|
||||||
|
} from "./comments";
|
||||||
|
import { withCheckContext } from "./complexity";
|
||||||
|
import { isNoopExpressionStatement, maybeEmptyLine } from "./core";
|
||||||
|
import { AstPath, CustomOptions, Doc, Plugin, Symbol_comments, group, hardline, indent, line, softline, ParserOptions } from "./external";
|
||||||
|
import { printer } from "./printer";
|
||||||
|
import { needsInnerParens, needsOuterSoftbreakParens, shouldPrintOuterAttributesAbove } from "./styling";
|
||||||
|
|
||||||
|
export function is_printing_macro() {
|
||||||
|
return getContext().path.stack.some((node) => is_Node(node) && (is_MacroInvocation(node) || is_Attribute(node)));
|
||||||
|
}
|
||||||
|
|
||||||
|
export function assertPathAtNode(name: string, node: Node, ...ctx: any[]) {
|
||||||
|
__DEV__: if (getNode() !== node)
|
||||||
|
exit(`Attempted to call ${name}() in wrong prettier path context`, { asserted: node, actual: getNode() }, ...ctx);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function f(...args: [strings: TemplateStringsArray, ...values: Doc[]]) {
|
||||||
|
let cancel = false;
|
||||||
|
const res = map_tagged_template(args, (doc) => {
|
||||||
|
cancel ||= !doc || (is_array(doc) && doc.length === 0);
|
||||||
|
return doc;
|
||||||
|
});
|
||||||
|
return cancel ? "" : res;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function sg_single(s: TemplateStringsArray, v_0: Doc) {
|
||||||
|
return group([s[0], indent([softline, v_0]), softline, s[1]]);
|
||||||
|
}
|
||||||
|
export function sg_duo(s: TemplateStringsArray, v_0: Doc, v_1: Doc) {
|
||||||
|
return group([s[0], indent([softline, v_0, s[1], line, v_1]), softline, s[2]]);
|
||||||
|
}
|
||||||
|
|
||||||
|
let ctx: {
|
||||||
|
path: AstPath;
|
||||||
|
options: CustomOptions;
|
||||||
|
print: (path?: AstPath | string | [] | undefined, args?: any) => Doc;
|
||||||
|
args: any;
|
||||||
|
};
|
||||||
|
|
||||||
|
export const getNode = () => ctx.path.stack[ctx.path.stack.length - 1] as Node;
|
||||||
|
export const stackIncludes = (x: Node | string | number) => ctx.path.stack.includes(x);
|
||||||
|
export const getContext = () => ctx;
|
||||||
|
export const getOptions = () => ctx.options;
|
||||||
|
export const getProgram = () => ctx.options.rsParsedFile.program;
|
||||||
|
export const getAllComments = () => ctx.options[Symbol_comments];
|
||||||
|
export const getParentNode = (child?: Node) => {
|
||||||
|
__DEV__: if (child) assertPathAtNode("getParentNode", child);
|
||||||
|
return ctx.path.getParentNode();
|
||||||
|
};
|
||||||
|
export const getGrandParentNode = () => ctx.path.getParentNode(1) as Node;
|
||||||
|
export const getPrintFn = <T extends Node>(forNode?: T | undefined): print<T> => {
|
||||||
|
__DEV__: if (forNode) assertPathAtNode("getPrintFn", forNode);
|
||||||
|
return print as print<T>;
|
||||||
|
};
|
||||||
|
|
||||||
|
const get = (property: keyof any) => getNode()[property];
|
||||||
|
const has = (property: keyof any) => !!get(property);
|
||||||
|
|
||||||
|
export function pathCall<T extends Node, K extends keyof NodeProps<T> & keyof T, R>(node: T, key: K, fn: (child: T[K]) => R): R {
|
||||||
|
return ctx.path.call(() => fn(getNode() as any), key as any);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function pathCallEach<T extends Node, K extends AK<T>>(
|
||||||
|
node: T,
|
||||||
|
key: K, // @ts-expect-error
|
||||||
|
fn: (child: NonNullable<T[K]>[number], index: number) => void
|
||||||
|
) {
|
||||||
|
__DEV__: assertPathAtNode("", node); // @ts-expect-error
|
||||||
|
ctx.path.each((_, i) => fn(getNode() as any, i), key);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function pathCallAtParent<T extends Node, R>(parent: T, fn: (parent: T) => R): R {
|
||||||
|
return ctx.path.callParent(() => {
|
||||||
|
__DEV__: assertPathAtNode("pathCallParent", parent);
|
||||||
|
return fn(parent);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
export function pathCallParentOf<T extends Node, R>(child: Node, fn: (parent: T) => R): R {
|
||||||
|
__DEV__: assertPathAtNode("pathCallParentOf", child);
|
||||||
|
return ctx.path.callParent((p) => fn(getNode() as any));
|
||||||
|
}
|
||||||
|
|
||||||
|
export function pathCallTopMostIfBlockExpression<R>(node: IfBlockExpression, fn: (node: IfBlockExpression) => R): R {
|
||||||
|
const parent = getParentNode(node)!;
|
||||||
|
return is_ElseBlock(node, parent) ? pathCallAtParent(parent, (parent) => pathCallTopMostIfBlockExpression(parent, fn)) : fn(node);
|
||||||
|
}
|
||||||
|
|
||||||
|
function print(property?: any, args?: any): Doc | Doc[] {
|
||||||
|
if (!property) return ctx.print(undefined!, args);
|
||||||
|
if (Array.isArray(property)) return ctx.print(property as any, args);
|
||||||
|
const value = get(property);
|
||||||
|
return !!value ? (Array.isArray(value) ? ctx.path.map(ctx.print, property) : ctx.print(property, args)) : "";
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace print {
|
||||||
|
export function b(property: string, res = `${property} `): Doc {
|
||||||
|
return has(property) ? res : "";
|
||||||
|
}
|
||||||
|
export function map(property: string, mapItem?: MapFn<any, any>): Doc[] {
|
||||||
|
return !has(property) ? [] : ctx.path.map(mapItem ? (p, i, a) => mapItem(a[i], i, a) : () => ctx.print(), property);
|
||||||
|
}
|
||||||
|
export function join(property: string, sep: SepFn<any, any> | Doc, trailingSep: TrailingSepFn<any, any> | Doc = ""): Doc[] {
|
||||||
|
return map_join(property, () => ctx.print(), sep, trailingSep);
|
||||||
|
}
|
||||||
|
export function map_join(
|
||||||
|
property: string,
|
||||||
|
mapFn: MapFn<any, any>,
|
||||||
|
sep: SepFn<any, any> | Doc,
|
||||||
|
sepTrailing: TrailingSepFn<any, any> | Doc = ""
|
||||||
|
) {
|
||||||
|
const sepFn = typeof sep === "function" ? sep : () => sep;
|
||||||
|
return map(property, (v, i, a) => [
|
||||||
|
mapFn(v, i, a),
|
||||||
|
iLast(i, a as any)
|
||||||
|
? typeof sepTrailing === "function"
|
||||||
|
? sepTrailing(v)
|
||||||
|
: sepTrailing
|
||||||
|
: sepFn(v, a[i + 1], i === 0 ? undefined : a[i - 1]),
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// prettier-ignore
|
||||||
|
type SepFn<T extends Node = Node, K extends AK<T> = AK<T>> = <A extends AV<T, K>>(item: A[number], next_item: A[number], prev_item: A[number] | undefined) => Doc;
|
||||||
|
type MapFn<T extends Node = Node, K extends AK<T> = AK<T>> = <A extends AV<T, K>>(item: A[number], index: number, arr: A) => Doc;
|
||||||
|
type TrailingSepFn<T extends Node = Node, K extends AK<T> = AK<T>> = <A extends AV<T, K>>(item: A[number]) => Doc;
|
||||||
|
type AV<T extends Node, K extends keyof T> = Extract<NonNullable<T[K]>, ReadonlyArray<unknown>>;
|
||||||
|
type AK<T extends Node> = keyof ArrayProps<T> & keyof T;
|
||||||
|
// type AK<T extends Node> = keyof PickProps<T, {nodeType:number}|{nodeType:number}[]> & keyof T;
|
||||||
|
|
||||||
|
export interface print<T extends Node> {
|
||||||
|
(property?: [], args?: any): Doc;
|
||||||
|
(property?: [AK<T>, number], args?: any): Doc;
|
||||||
|
(property?: AK<T>, args?: any): Doc[];
|
||||||
|
// (property?: T extends {rules:{nodeType:number}|{nodeType:number}[]} ? "rules" : never, args?: any): Doc[];
|
||||||
|
(property?: keyof NodeProps<T> & keyof T, args?: any): Doc;
|
||||||
|
b(property: keyof BoolProps<T>, res?: string): Doc;
|
||||||
|
map<K extends AK<T>>(property: K & keyof ArrayProps<T>, mapFn?: MapFn<T, K>): Doc[];
|
||||||
|
join<K extends AK<T>>(property: K, sep: SepFn<T, K> | Doc, trailingSep?: TrailingSepFn<T, K> | Doc): Doc[];
|
||||||
|
map_join<K extends AK<T>>(property: K, mapFn: MapFn<T, K>, sep: SepFn<T, K> | Doc, trailingSep?: TrailingSepFn<T, K> | Doc): Doc[];
|
||||||
|
}
|
||||||
|
|
||||||
|
function genericPrint() {
|
||||||
|
return withCheckContext(() => {
|
||||||
|
const node = getNode();
|
||||||
|
__DEV__: assert(node.nodeType in printer);
|
||||||
|
|
||||||
|
let printed: Doc = hasPrettierIgnore(node) //
|
||||||
|
? node.loc.getOwnText()
|
||||||
|
: printer[node.nodeType]!(print as any, node as never);
|
||||||
|
|
||||||
|
const inner_parens = needsInnerParens(node);
|
||||||
|
|
||||||
|
if (inner_parens) {
|
||||||
|
printed = group(["(", printed, ")"]);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (hasAttributes(node)) {
|
||||||
|
const print_above = shouldPrintOuterAttributesAbove(node); /* || node.attributes.length > 1 */
|
||||||
|
printed = [
|
||||||
|
...print.join(
|
||||||
|
"attributes",
|
||||||
|
(attr) =>
|
||||||
|
print_above
|
||||||
|
? maybeEmptyLine(attr)
|
||||||
|
: is_LineCommentNode(attr) || (is_BlockCommentNode(attr) && hasBreaklineAfter(attr))
|
||||||
|
? hardline
|
||||||
|
: " ",
|
||||||
|
(attr) =>
|
||||||
|
print_above && is_DocCommentAttribute(attr)
|
||||||
|
? maybeEmptyLine(attr)
|
||||||
|
: print_above || is_LineCommentNode(attr) || (is_BlockCommentNode(attr) && hasBreaklineAfter(attr))
|
||||||
|
? hardline
|
||||||
|
: " "
|
||||||
|
),
|
||||||
|
printed,
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
printed = withComments(
|
||||||
|
node,
|
||||||
|
printed,
|
||||||
|
hasPrettierIgnore(node) || ((is_Attribute(node) || is_MacroInvocation(node)) && !isTransformed(node))
|
||||||
|
? escapeComments(0, (comment) => node.loc.ownContains(comment))
|
||||||
|
: is_MacroRule(node)
|
||||||
|
? escapeComments(0, (comment) => node.transform.loc.contains(comment))
|
||||||
|
: is_UnionPattern(getParentNode() ?? ({ nodeType: 0 } as any))
|
||||||
|
? new Set(getComments(node, CF.Leading | CF.Trailing, (comment) => !isDangling(comment)))
|
||||||
|
: undefined
|
||||||
|
);
|
||||||
|
|
||||||
|
if (!inner_parens && needsOuterSoftbreakParens(node)) {
|
||||||
|
printed = [group(["(", indent([softline, printed]), softline, ")"])];
|
||||||
|
}
|
||||||
|
|
||||||
|
return printed;
|
||||||
|
});
|
||||||
|
|
||||||
|
function hasPrettierIgnore(node: Node) {
|
||||||
|
return (
|
||||||
|
(node as any).prettierIgnore ||
|
||||||
|
hasComment(node, CF.PrettierIgnore) ||
|
||||||
|
(hasAttributes(node) && node.attributes.some(isPrettierIgnoreAttribute))
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export function canAttachComment(n: Node) {
|
||||||
|
return !is_Comment(n) && !isNoopExpressionStatement(n) && !is_MissingNode(n) && !is_PunctuationToken(n);
|
||||||
|
}
|
||||||
|
|
||||||
|
export const plugin: Plugin<Node> = {
|
||||||
|
languages: [
|
||||||
|
{
|
||||||
|
name: "Rust",
|
||||||
|
aliases: ["rs"],
|
||||||
|
parsers: ["jinx-rust"],
|
||||||
|
extensions: [".rs", ".rs.in"],
|
||||||
|
linguistLanguageId: 327,
|
||||||
|
vscodeLanguageIds: ["rust"],
|
||||||
|
tmScope: "source.rust",
|
||||||
|
aceMode: "rust",
|
||||||
|
codemirrorMode: "rust",
|
||||||
|
codemirrorMimeType: "text/x-rustsrc",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
parsers: {
|
||||||
|
"jinx-rust": {
|
||||||
|
astFormat: "jinx-rust",
|
||||||
|
locStart: start,
|
||||||
|
locEnd: end,
|
||||||
|
parse(code: string, options: ParserOptions<Node> & Partial<CustomOptions>) {
|
||||||
|
const customOptions = options as CustomOptions;
|
||||||
|
ctx = { options: customOptions } as any;
|
||||||
|
|
||||||
|
customOptions.rsParsedFile = rs.parseFile((customOptions.originalText = code), { filepath: customOptions.filepath });
|
||||||
|
|
||||||
|
customOptions.actuallyMethodNodes = new WeakSet();
|
||||||
|
customOptions.danglingAttributes = [];
|
||||||
|
customOptions.comments = [];
|
||||||
|
|
||||||
|
transform_ast(customOptions);
|
||||||
|
|
||||||
|
const comments: AttributeOrComment[] = [];
|
||||||
|
insertNodes(comments, customOptions.comments);
|
||||||
|
insertNodes(comments, customOptions.danglingAttributes);
|
||||||
|
|
||||||
|
// @ts-expect-error
|
||||||
|
customOptions.rsParsedFile.program.comments = comments;
|
||||||
|
|
||||||
|
customOptions.commentSpans = new Map(comments.map((n) => [start(n), end(n)]));
|
||||||
|
|
||||||
|
return customOptions.rsParsedFile.program;
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
printers: {
|
||||||
|
"jinx-rust": {
|
||||||
|
preprocess: (node: Node) => (node as Program).loc?.src || node,
|
||||||
|
print(path, options, print, args) {
|
||||||
|
if (path.stack.length === 1) {
|
||||||
|
__DEV__: Narrow<CustomOptions>(options);
|
||||||
|
ctx = { path, options, print: print as any, args };
|
||||||
|
try {
|
||||||
|
const printed = genericPrint();
|
||||||
|
__DEV__: devEndCheck(printed);
|
||||||
|
return printed;
|
||||||
|
} finally {
|
||||||
|
ctx = undefined!;
|
||||||
|
}
|
||||||
|
} else if (args || ctx.args) {
|
||||||
|
const prev_args = ctx.args;
|
||||||
|
try {
|
||||||
|
ctx.args = args;
|
||||||
|
return genericPrint();
|
||||||
|
} finally {
|
||||||
|
ctx.args = prev_args;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return genericPrint();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
hasPrettierIgnore: () => false,
|
||||||
|
willPrintOwnComments: () => true,
|
||||||
|
isBlockComment: (node: Node): boolean => {
|
||||||
|
return is_AttributeOrComment(node) && is_BlockCommentKind(node as any);
|
||||||
|
},
|
||||||
|
canAttachComment: canAttachComment,
|
||||||
|
getCommentChildNodes: getCommentChildNodes,
|
||||||
|
printComment: genericPrint,
|
||||||
|
handleComments: {
|
||||||
|
// @ts-expect-error
|
||||||
|
avoidAstMutation: true,
|
||||||
|
ownLine: handleOwnLineComment,
|
||||||
|
endOfLine: handleEndOfLineComment,
|
||||||
|
remaining: handleRemainingComment,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
options: {},
|
||||||
|
defaultOptions: {
|
||||||
|
// default prettier (2) -> rustfmt (4)
|
||||||
|
tabWidth: 4,
|
||||||
|
// default prettier (80) -> rustfmt (100)
|
||||||
|
printWidth: 100,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
function devEndCheck(printed: Doc) {
|
||||||
|
let first = false;
|
||||||
|
const comments = getAllComments();
|
||||||
|
each(comments, (comment, index) => {
|
||||||
|
if (!comment.printed) {
|
||||||
|
if (!first) (first = true), console.log(color.red(`Unprinted comments:`));
|
||||||
|
const len = 40;
|
||||||
|
const msg =
|
||||||
|
color.magenta(
|
||||||
|
(comment.marker ? `Dangling "${comment.marker}" ` : "") +
|
||||||
|
(is_Attribute(comment) ? "Attribute " : is_DocCommentAttribute(comment) ? "DocCommentAttribute" : "Comment") +
|
||||||
|
` ${index}/${comments.length}` +
|
||||||
|
color.yellow(` ${print_string(comment.loc.sliceText(0, len))}${comment.loc.len() > len ? " ..." : ""}`)
|
||||||
|
) + color.grey(`\n at ${comment.loc.url()}`);
|
||||||
|
if (globalThis.TESTS_FORMAT_DEV) exit(msg);
|
||||||
|
else console.log(msg);
|
||||||
|
setDidPrintComment(comment);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
719
frontend/src/common/prettier/plugins/rust/format/printer.ts
Normal file
719
frontend/src/common/prettier/plugins/rust/format/printer.ts
Normal file
@@ -0,0 +1,719 @@
|
|||||||
|
import { DelimKind, Node, NodeType, NTMap } from "jinx-rust";
|
||||||
|
import {
|
||||||
|
getDelimChars,
|
||||||
|
hasSuffix,
|
||||||
|
is_ArrayOrTupleLiteral,
|
||||||
|
is_BlockExpression,
|
||||||
|
is_ClosureFunctionExpression,
|
||||||
|
is_Identifier,
|
||||||
|
is_IfBlockExpression,
|
||||||
|
is_LiteralNumberLike,
|
||||||
|
is_StructLiteral,
|
||||||
|
start,
|
||||||
|
} from "jinx-rust/utils";
|
||||||
|
import {
|
||||||
|
BlockLikeMacroInvocation,
|
||||||
|
CallLikeMacroInvocation,
|
||||||
|
is_BlockLikeMacroInvocation,
|
||||||
|
is_CallLikeMacroInvocation,
|
||||||
|
isTransformed,
|
||||||
|
} from "../transform";
|
||||||
|
import { exit } from "../utils/common";
|
||||||
|
import { hasComment, print_comment } from "./comments";
|
||||||
|
import { isSimpleType } from "./complexity";
|
||||||
|
import {
|
||||||
|
adjustClause,
|
||||||
|
parenthesize_if_break,
|
||||||
|
printAnnotatedPattern,
|
||||||
|
printArrayLike,
|
||||||
|
printArrowFunction,
|
||||||
|
printAssignment,
|
||||||
|
printBinaryishExpression,
|
||||||
|
printBlockBody,
|
||||||
|
printBodyOrCases,
|
||||||
|
printCallArguments,
|
||||||
|
printCallExpression,
|
||||||
|
printCondition,
|
||||||
|
printDanglingCommentsForInline,
|
||||||
|
printDeclarationTypeBounds,
|
||||||
|
printEnumBody,
|
||||||
|
printFlowControlExpression,
|
||||||
|
printGenerics_x_whereBounds,
|
||||||
|
printIfBlock,
|
||||||
|
printIfBlockCondition,
|
||||||
|
printImplTraitForType,
|
||||||
|
printLtBounds,
|
||||||
|
printLtParameters,
|
||||||
|
printMacroRules,
|
||||||
|
printMaybeBlockBody,
|
||||||
|
printMemberExpression,
|
||||||
|
printNumber,
|
||||||
|
printObject,
|
||||||
|
printParametersAndReturnType,
|
||||||
|
printRuleMatch,
|
||||||
|
printRuleTransform,
|
||||||
|
printTypeAnnotation,
|
||||||
|
printTypeArguments,
|
||||||
|
printTypeBounds,
|
||||||
|
printUnaryExpression,
|
||||||
|
printUnionPattern,
|
||||||
|
} from "./core";
|
||||||
|
import { DCM, Doc, group, hardline, ifBreak, indent, join, line, softline, willBreak } from "./external";
|
||||||
|
import { f, getOptions, getParentNode, pathCall, sg_duo, sg_single, type print } from "./plugin";
|
||||||
|
import { needsParens, stmtNeedsSemi } from "./styling";
|
||||||
|
|
||||||
|
type nPrint<T extends Node> = (print: print<T>, node: T) => Doc | never;
|
||||||
|
|
||||||
|
export const printer: { [K in NodeType]: nPrint<Extract<NTMap[K], Node>> } = {
|
||||||
|
[NodeType.MissingNode](print, node) {
|
||||||
|
return "";
|
||||||
|
},
|
||||||
|
[NodeType.SourceFile](print, node) {
|
||||||
|
return [
|
||||||
|
print.b("UTF8BOM", "\uFEFF"), //
|
||||||
|
print("shebang"),
|
||||||
|
print("program"),
|
||||||
|
];
|
||||||
|
},
|
||||||
|
[NodeType.Shebang](print, node) {
|
||||||
|
return [`#!${node.value}`, hardline];
|
||||||
|
},
|
||||||
|
[NodeType.Program](print, node) {
|
||||||
|
return printBodyOrCases(print, node);
|
||||||
|
},
|
||||||
|
[NodeType.Snippet](print, node) {
|
||||||
|
exit.never();
|
||||||
|
},
|
||||||
|
[NodeType.Identifier](print, node) {
|
||||||
|
return node.name;
|
||||||
|
},
|
||||||
|
[NodeType.Index](print, node) {
|
||||||
|
return node.name;
|
||||||
|
},
|
||||||
|
[NodeType.LbIdentifier](print, node) {
|
||||||
|
return node.name;
|
||||||
|
},
|
||||||
|
[NodeType.McIdentifier](print, node) {
|
||||||
|
return node.name;
|
||||||
|
},
|
||||||
|
[NodeType.LtIdentifier](print, node) {
|
||||||
|
return node.name;
|
||||||
|
},
|
||||||
|
[NodeType.PunctuationToken](print, node) {
|
||||||
|
return node.token;
|
||||||
|
},
|
||||||
|
[NodeType.DelimGroup](print, node) {
|
||||||
|
return node.loc.getOwnText();
|
||||||
|
},
|
||||||
|
[NodeType.Literal](print, node) {
|
||||||
|
let { value } = node;
|
||||||
|
if (is_LiteralNumberLike(node)) value = printNumber(value);
|
||||||
|
return hasSuffix(node) ? [value, print("suffix")] : value;
|
||||||
|
},
|
||||||
|
[NodeType.ItemPath](print, node) {
|
||||||
|
return [print("namespace"), "::", print("segment")];
|
||||||
|
},
|
||||||
|
[NodeType.ExpressionPath](print, node) {
|
||||||
|
return [print("namespace"), "::", print("segment")];
|
||||||
|
},
|
||||||
|
[NodeType.TypePath](print, node) {
|
||||||
|
return [print("namespace"), "::", print("segment")];
|
||||||
|
},
|
||||||
|
[NodeType.Comment](print, node) {
|
||||||
|
return print_comment(node);
|
||||||
|
},
|
||||||
|
[NodeType.DocCommentAttribute](print, node) {
|
||||||
|
return print_comment(node);
|
||||||
|
},
|
||||||
|
[NodeType.Attribute](print, node) {
|
||||||
|
return [
|
||||||
|
node.inner ? "#![" : "#[",
|
||||||
|
isTransformed(node)
|
||||||
|
? [print("segments"), printDanglingCommentsForInline(node)] //
|
||||||
|
: node.segments.loc.sliceText(1, -1).trim(),
|
||||||
|
"]",
|
||||||
|
];
|
||||||
|
},
|
||||||
|
[NodeType.MacroInvocation](print, node) {
|
||||||
|
const hasCurlyBrackets = node.segments.dk === DelimKind["{}"];
|
||||||
|
const delim = getDelimChars(node.segments);
|
||||||
|
if (node.segments.length === 0) {
|
||||||
|
return [print("callee"), "!", hasCurlyBrackets ? " " : "", delim.left, printDanglingCommentsForInline(node), delim.right];
|
||||||
|
}
|
||||||
|
if (isTransformed(node)) {
|
||||||
|
if (is_CallLikeMacroInvocation(node)) {
|
||||||
|
return [print("callee"), "!", printCallArguments(print as print<CallLikeMacroInvocation>, node)];
|
||||||
|
}
|
||||||
|
if (is_BlockLikeMacroInvocation(node)) {
|
||||||
|
return [print("callee"), "!", " ", printBlockBody(print as print<BlockLikeMacroInvocation>, node)];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
let content = node.segments.loc.sliceText(1, -1);
|
||||||
|
if (content.trim().length === 0) {
|
||||||
|
content = "";
|
||||||
|
} else if (!content.includes("\n")) {
|
||||||
|
content = content.trim();
|
||||||
|
if (hasCurlyBrackets) content = " " + content + " ";
|
||||||
|
}
|
||||||
|
return [print("callee"), "!", hasCurlyBrackets ? " " : "", delim.left, content, delim.right];
|
||||||
|
},
|
||||||
|
[NodeType.MacroRulesDeclaration](print, node) {
|
||||||
|
return ["macro_rules! ", print("id"), printMacroRules(print, node)];
|
||||||
|
},
|
||||||
|
[NodeType.MacroRuleDeclaration](print, node) {
|
||||||
|
return [printRuleMatch(print, node), " => ", printRuleTransform(print, node), ";"];
|
||||||
|
},
|
||||||
|
[NodeType.MacroDeclaration](print, node) {
|
||||||
|
return [print("pub"), "macro ", print("id"), printMacroRules(print, node)];
|
||||||
|
},
|
||||||
|
[NodeType.MacroInlineRuleDeclaration](print, node) {
|
||||||
|
return [printRuleMatch(print, node), " ", printRuleTransform(print, node)];
|
||||||
|
},
|
||||||
|
[NodeType.MacroGroup](print, node) {
|
||||||
|
return node.loc.getOwnText();
|
||||||
|
},
|
||||||
|
[NodeType.MacroParameterDeclaration](print, node) {
|
||||||
|
return [print("id"), ":", print("ty")];
|
||||||
|
},
|
||||||
|
[NodeType.PubSpecifier](print, node) {
|
||||||
|
if (!node.location) return "pub ";
|
||||||
|
if (is_Identifier(node.location)) {
|
||||||
|
switch (node.location.name) {
|
||||||
|
case "crate":
|
||||||
|
if (start(node) === start(node.location)) {
|
||||||
|
return "crate ";
|
||||||
|
} else {
|
||||||
|
return ["pub(", print("location"), ") "];
|
||||||
|
}
|
||||||
|
case "self":
|
||||||
|
case "super":
|
||||||
|
return ["pub(", print("location"), ") "];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return ["pub(in ", print("location"), ") "];
|
||||||
|
},
|
||||||
|
[NodeType.ExternSpecifier](print, node) {
|
||||||
|
return ["extern ", f`${print("abi")} `];
|
||||||
|
},
|
||||||
|
[NodeType.ExpressionStatement](print, node) {
|
||||||
|
return [print("expression"), stmtNeedsSemi(node) ? ";" : ""];
|
||||||
|
},
|
||||||
|
[NodeType.UseStatement](print, node) {
|
||||||
|
return [print("pub"), "use ", print("import"), ";"];
|
||||||
|
},
|
||||||
|
[NodeType.DestructuredImport](print, node) {
|
||||||
|
if (node.specifiers.length === 0) return [print("source"), "::{", printDanglingCommentsForInline(node, DCM["specifiers"]), "}"];
|
||||||
|
let space = true;
|
||||||
|
__DEV__: if (globalThis.TESTS_FORMAT_DEV) space = false;
|
||||||
|
return [
|
||||||
|
print("source"),
|
||||||
|
group([
|
||||||
|
"::{",
|
||||||
|
indent([space ? line : softline, join([",", line], print("specifiers")), ifBreak(",")]),
|
||||||
|
space ? line : softline,
|
||||||
|
"}",
|
||||||
|
]),
|
||||||
|
];
|
||||||
|
},
|
||||||
|
[NodeType.AmbientImport](print, node) {
|
||||||
|
return f`${print("source")}::*` || "*";
|
||||||
|
},
|
||||||
|
[NodeType.AnonymousImport](print, node) {
|
||||||
|
return [print("source"), " as ", "_"];
|
||||||
|
},
|
||||||
|
[NodeType.NamedImport](print, node) {
|
||||||
|
return [print("source"), f` as ${print("local")}`];
|
||||||
|
},
|
||||||
|
[NodeType.ExternCrateStatement](print, node) {
|
||||||
|
return [print("pub"), "extern crate ", print("import"), ";"];
|
||||||
|
},
|
||||||
|
[NodeType.TypeAliasDeclaration](print, node) {
|
||||||
|
return [
|
||||||
|
print("pub"),
|
||||||
|
"type",
|
||||||
|
printAssignment(
|
||||||
|
printGenerics_x_whereBounds(print, node, printDeclarationTypeBounds(print, node, ":")), //
|
||||||
|
" =",
|
||||||
|
"typeExpression"
|
||||||
|
),
|
||||||
|
";",
|
||||||
|
];
|
||||||
|
},
|
||||||
|
[NodeType.LetVariableDeclaration](print, node) {
|
||||||
|
return [
|
||||||
|
"let ",
|
||||||
|
printAssignment(
|
||||||
|
printAnnotatedPattern(print, node), //
|
||||||
|
" =",
|
||||||
|
"expression"
|
||||||
|
),
|
||||||
|
f` else ${print("else")}`,
|
||||||
|
";",
|
||||||
|
];
|
||||||
|
},
|
||||||
|
[NodeType.ConstVariableDeclaration](print, node) {
|
||||||
|
return [
|
||||||
|
print("pub"),
|
||||||
|
"const ",
|
||||||
|
printAssignment(
|
||||||
|
printAnnotatedPattern(print, node), //
|
||||||
|
" =",
|
||||||
|
"expression"
|
||||||
|
),
|
||||||
|
";",
|
||||||
|
];
|
||||||
|
},
|
||||||
|
[NodeType.StaticVariableDeclaration](print, node) {
|
||||||
|
return [
|
||||||
|
print("pub"),
|
||||||
|
"static ",
|
||||||
|
printAssignment(
|
||||||
|
printAnnotatedPattern(print, node), //
|
||||||
|
" =",
|
||||||
|
"expression"
|
||||||
|
),
|
||||||
|
";",
|
||||||
|
];
|
||||||
|
},
|
||||||
|
[NodeType.ModuleDeclaration](print, node) {
|
||||||
|
return [
|
||||||
|
print("pub"), //
|
||||||
|
print.b("unsafe"),
|
||||||
|
"mod ",
|
||||||
|
print("id"),
|
||||||
|
printMaybeBlockBody(print, node),
|
||||||
|
];
|
||||||
|
},
|
||||||
|
[NodeType.ExternBlockDeclaration](print, node) {
|
||||||
|
return [
|
||||||
|
print("pub"), //
|
||||||
|
print.b("unsafe"),
|
||||||
|
"extern ",
|
||||||
|
f`${print("abi")} `,
|
||||||
|
printBlockBody(print, node),
|
||||||
|
];
|
||||||
|
},
|
||||||
|
[NodeType.FunctionDeclaration](print, node) {
|
||||||
|
return [
|
||||||
|
print("pub"),
|
||||||
|
print.b("const"),
|
||||||
|
print.b("async"),
|
||||||
|
print.b("unsafe"),
|
||||||
|
print("extern"),
|
||||||
|
"fn",
|
||||||
|
printGenerics_x_whereBounds(print, node, printParametersAndReturnType(node)),
|
||||||
|
printMaybeBlockBody(print, node),
|
||||||
|
];
|
||||||
|
},
|
||||||
|
[NodeType.FunctionSelfParameterDeclaration](print, node) {
|
||||||
|
return group([print.b("ref", "&"), f`${print("lt")} `, print.b("mut"), "self", printTypeAnnotation(print, node)]);
|
||||||
|
},
|
||||||
|
[NodeType.FunctionParameterDeclaration](print, node) {
|
||||||
|
return group(printAnnotatedPattern(print, node));
|
||||||
|
},
|
||||||
|
[NodeType.FunctionSpread](print, node) {
|
||||||
|
return "...";
|
||||||
|
},
|
||||||
|
[NodeType.StructDeclaration](print, node) {
|
||||||
|
return [print("pub"), "struct", printGenerics_x_whereBounds(print, node, ""), printObject(print, node)];
|
||||||
|
},
|
||||||
|
[NodeType.StructPropertyDeclaration](print, node) {
|
||||||
|
return [print("pub"), print("id"), printTypeAnnotation(print, node)];
|
||||||
|
},
|
||||||
|
[NodeType.TupleStructDeclaration](print, node) {
|
||||||
|
return [print("pub"), "struct", printGenerics_x_whereBounds(print, node, printArrayLike(print, node)), ";"];
|
||||||
|
},
|
||||||
|
[NodeType.TupleStructItemDeclaration](print, node) {
|
||||||
|
return [print("pub"), print("typeAnnotation")];
|
||||||
|
},
|
||||||
|
[NodeType.UnionDeclaration](print, node) {
|
||||||
|
return [print("pub"), "union", printGenerics_x_whereBounds(print, node, ""), printObject(print, node)];
|
||||||
|
},
|
||||||
|
[NodeType.EnumDeclaration](print, node) {
|
||||||
|
return [print("pub"), "enum", printGenerics_x_whereBounds(print, node, ""), printEnumBody(print, node)];
|
||||||
|
},
|
||||||
|
[NodeType.EnumMemberDeclaration](print, node) {
|
||||||
|
return [
|
||||||
|
print("pub"),
|
||||||
|
printAssignment(
|
||||||
|
print("id"), //
|
||||||
|
" =",
|
||||||
|
"value"
|
||||||
|
),
|
||||||
|
];
|
||||||
|
},
|
||||||
|
[NodeType.EnumMemberTupleDeclaration](print, node) {
|
||||||
|
return [
|
||||||
|
print("pub"),
|
||||||
|
printAssignment(
|
||||||
|
[print("id"), printArrayLike(print, node)], //
|
||||||
|
" =",
|
||||||
|
"value"
|
||||||
|
),
|
||||||
|
];
|
||||||
|
},
|
||||||
|
[NodeType.EnumMemberStructDeclaration](print, node) {
|
||||||
|
return [
|
||||||
|
print("pub"),
|
||||||
|
printAssignment(
|
||||||
|
[print("id"), printObject(print, node)], //
|
||||||
|
" =",
|
||||||
|
"value"
|
||||||
|
),
|
||||||
|
];
|
||||||
|
},
|
||||||
|
[NodeType.TraitDeclaration](print, node) {
|
||||||
|
return [
|
||||||
|
print("pub"),
|
||||||
|
print.b("unsafe"),
|
||||||
|
"trait",
|
||||||
|
printGenerics_x_whereBounds(print, node, printDeclarationTypeBounds(print, node, ":")),
|
||||||
|
adjustClause(node, printBlockBody(print, node)),
|
||||||
|
];
|
||||||
|
},
|
||||||
|
[NodeType.AutoTraitDeclaration](print, node) {
|
||||||
|
return [
|
||||||
|
print("pub"),
|
||||||
|
print.b("unsafe"),
|
||||||
|
"auto trait ",
|
||||||
|
print("id"),
|
||||||
|
" ",
|
||||||
|
printBlockBody(print, node as any), // see "transform.ts"
|
||||||
|
];
|
||||||
|
},
|
||||||
|
[NodeType.TraitAliasDeclaration](print, node) {
|
||||||
|
return [
|
||||||
|
print("pub"),
|
||||||
|
print.b("unsafe"),
|
||||||
|
"trait",
|
||||||
|
printGenerics_x_whereBounds(print, node, printDeclarationTypeBounds(print, node, " =")),
|
||||||
|
";",
|
||||||
|
];
|
||||||
|
},
|
||||||
|
[NodeType.ImplDeclaration](print, node) {
|
||||||
|
return [
|
||||||
|
print("pub"),
|
||||||
|
print.b("unsafe"),
|
||||||
|
"impl",
|
||||||
|
printGenerics_x_whereBounds(print, node, [print.b("const"), printImplTraitForType(print, node)]),
|
||||||
|
adjustClause(node, printBlockBody(print, node)),
|
||||||
|
];
|
||||||
|
},
|
||||||
|
[NodeType.NegativeImplDeclaration](print, node) {
|
||||||
|
return [
|
||||||
|
print("pub"),
|
||||||
|
"impl",
|
||||||
|
printGenerics_x_whereBounds(print, node, ["!", printImplTraitForType(print, node)]),
|
||||||
|
" ",
|
||||||
|
printBlockBody(print, node as any), // see "transform.ts"
|
||||||
|
];
|
||||||
|
},
|
||||||
|
[NodeType.ExpressionTypeSelector](print, node) {
|
||||||
|
return group(["<", print("typeTarget"), f` as ${print("typeExpression")}`, ">"]);
|
||||||
|
},
|
||||||
|
[NodeType.ExpressionTypeCast](print, node) {
|
||||||
|
return [print("typeCallee"), f`::${printTypeArguments(print, node)}`];
|
||||||
|
},
|
||||||
|
[NodeType.ExpressionAsTypeCast](print, node) {
|
||||||
|
return [print("expression"), " as ", print("typeExpression")];
|
||||||
|
},
|
||||||
|
[NodeType.ReturnExpression](print, node) {
|
||||||
|
return ["return", printFlowControlExpression(print, node)];
|
||||||
|
},
|
||||||
|
[NodeType.BreakExpression](print, node) {
|
||||||
|
return ["break", f` ${print("label")}`, printFlowControlExpression(print, node)];
|
||||||
|
},
|
||||||
|
[NodeType.ContinueExpression](print, node) {
|
||||||
|
return ["continue", f` ${print("label")}`];
|
||||||
|
},
|
||||||
|
[NodeType.YieldExpression](print, node) {
|
||||||
|
return ["yield", printFlowControlExpression(print, node)];
|
||||||
|
},
|
||||||
|
[NodeType.RangeLiteral](print, node) {
|
||||||
|
return [print("lower"), "..", print.b("last", "="), print("upper")];
|
||||||
|
},
|
||||||
|
[NodeType.CallExpression](print, node) {
|
||||||
|
return printCallExpression(print, node);
|
||||||
|
},
|
||||||
|
[NodeType.MemberExpression](print, node) {
|
||||||
|
return printMemberExpression(print, node);
|
||||||
|
},
|
||||||
|
[NodeType.AwaitExpression](print, node) {
|
||||||
|
return [print("expression"), ".await"];
|
||||||
|
},
|
||||||
|
[NodeType.UnwrapExpression](print, node) {
|
||||||
|
return [print("expression"), "?"];
|
||||||
|
},
|
||||||
|
[NodeType.ParenthesizedExpression](print, node) {
|
||||||
|
exit.never();
|
||||||
|
const shouldHug = !hasComment(node.expression) && (is_ArrayOrTupleLiteral(node.expression) || is_StructLiteral(node.expression));
|
||||||
|
if (shouldHug) return ["(", print("expression"), ")"];
|
||||||
|
return group(["(", indent([softline, print("expression")]), softline, ")"]);
|
||||||
|
},
|
||||||
|
[NodeType.MinusExpression](print, node) {
|
||||||
|
return printUnaryExpression("-", node);
|
||||||
|
},
|
||||||
|
[NodeType.NotExpression](print, node) {
|
||||||
|
return printUnaryExpression("!", node);
|
||||||
|
},
|
||||||
|
[NodeType.OrExpression](print, node) {
|
||||||
|
return printBinaryishExpression(print, node);
|
||||||
|
},
|
||||||
|
[NodeType.AndExpression](print, node) {
|
||||||
|
return printBinaryishExpression(print, node);
|
||||||
|
},
|
||||||
|
[NodeType.ReassignmentExpression](print, node) {
|
||||||
|
return printAssignment(print("left"), " =", "right");
|
||||||
|
},
|
||||||
|
[NodeType.UnassignedExpression](print, node) {
|
||||||
|
return "_";
|
||||||
|
},
|
||||||
|
[NodeType.OperationExpression](print, node) {
|
||||||
|
return printBinaryishExpression(print, node);
|
||||||
|
},
|
||||||
|
[NodeType.ReassignmentOperationExpression](print, node) {
|
||||||
|
return printAssignment(print("left"), " " + node.kind, "right");
|
||||||
|
},
|
||||||
|
[NodeType.ComparisonExpression](print, node) {
|
||||||
|
return printBinaryishExpression(print, node);
|
||||||
|
},
|
||||||
|
[NodeType.LetScrutinee](print, node) {
|
||||||
|
return ["let ", printAssignment(print("pattern"), " =", "expression")];
|
||||||
|
},
|
||||||
|
[NodeType.ClosureFunctionExpression](print, node) {
|
||||||
|
return printArrowFunction(print, node);
|
||||||
|
},
|
||||||
|
[NodeType.ClosureFunctionParameterDeclaration](print, node) {
|
||||||
|
return group(printAnnotatedPattern(print, node));
|
||||||
|
},
|
||||||
|
[NodeType.BlockExpression](print, node) {
|
||||||
|
return [
|
||||||
|
f`${print("label")}: `,
|
||||||
|
print.b("const"),
|
||||||
|
print.b("async"),
|
||||||
|
print.b("move"),
|
||||||
|
print.b("unsafe"),
|
||||||
|
printBlockBody(print, node),
|
||||||
|
];
|
||||||
|
},
|
||||||
|
[NodeType.LoopBlockExpression](print, node) {
|
||||||
|
return [f`${print("label")}: `, "loop ", printBlockBody(print, node)];
|
||||||
|
},
|
||||||
|
[NodeType.WhileBlockExpression](print, node) {
|
||||||
|
return [f`${print("label")}: `, "while ", printCondition(print, node), printBlockBody(print, node)];
|
||||||
|
},
|
||||||
|
[NodeType.ForInBlockExpression](print, node) {
|
||||||
|
return [f`${print("label")}: `, "for ", print("pattern"), " in ", print("expression"), " ", printBlockBody(print, node)];
|
||||||
|
},
|
||||||
|
[NodeType.IfBlockExpression](print, node) {
|
||||||
|
return [f`${print("label")}: `, printIfBlock(print, node)];
|
||||||
|
},
|
||||||
|
[NodeType.TryBlockExpression](print, node) {
|
||||||
|
return [f`${print("label")}: `, "try ", printBlockBody(print, node)];
|
||||||
|
},
|
||||||
|
[NodeType.MatchExpression](print, node) {
|
||||||
|
const id = Symbol("match");
|
||||||
|
const expr = print("expression");
|
||||||
|
const needs_parens = pathCall(node, "expression", needsParens);
|
||||||
|
|
||||||
|
let printed: Doc = [
|
||||||
|
f`${print("label")}: `,
|
||||||
|
"match ",
|
||||||
|
needs_parens ? expr : group([indent([softline, expr]), softline], { id }),
|
||||||
|
needs_parens ? " " : !willBreak(expr) ? ifBreak("", " ", { groupId: id }) : "" /* ifBreak("", " ", { groupId: id }) */,
|
||||||
|
printBlockBody(print, node),
|
||||||
|
];
|
||||||
|
|
||||||
|
const parent = getParentNode()!;
|
||||||
|
if (is_ClosureFunctionExpression(parent) && parent.expression === node) {
|
||||||
|
printed = parenthesize_if_break([indent([softline, printed]), softline]);
|
||||||
|
}
|
||||||
|
return printed;
|
||||||
|
},
|
||||||
|
[NodeType.MatchExpressionCase](print, node) {
|
||||||
|
return group([
|
||||||
|
group(print("pattern")),
|
||||||
|
" ",
|
||||||
|
printIfBlockCondition(print, node),
|
||||||
|
"=>", //
|
||||||
|
(is_BlockExpression(node.expression) || is_IfBlockExpression(node.expression)) &&
|
||||||
|
!hasComment(node.expression, 0, (comment) => getOptions().danglingAttributes.includes(comment as any))
|
||||||
|
? [" ", print("expression")]
|
||||||
|
: group(indent([line, print("expression")])),
|
||||||
|
]);
|
||||||
|
return printAssignment(
|
||||||
|
[print("pattern"), " ", printIfBlockCondition(print, node)], //
|
||||||
|
"=>",
|
||||||
|
"expression"
|
||||||
|
);
|
||||||
|
return [print("pattern"), " ", printIfBlockCondition(print, node)];
|
||||||
|
},
|
||||||
|
[NodeType.StructLiteral](print, node) {
|
||||||
|
return [print("struct"), printObject(print, node)];
|
||||||
|
},
|
||||||
|
[NodeType.StructLiteralPropertyShorthand](print, node) {
|
||||||
|
return print("value");
|
||||||
|
},
|
||||||
|
[NodeType.StructLiteralProperty](print, node) {
|
||||||
|
return [print("key"), ": ", print("value")];
|
||||||
|
},
|
||||||
|
[NodeType.StructLiteralPropertySpread](print, node) {
|
||||||
|
return ["..", print("expression")];
|
||||||
|
},
|
||||||
|
[NodeType.StructLiteralRestUnassigned](print, node) {
|
||||||
|
return "..";
|
||||||
|
},
|
||||||
|
[NodeType.ArrayLiteral](print, node) {
|
||||||
|
return printArrayLike(print, node);
|
||||||
|
},
|
||||||
|
[NodeType.SizedArrayLiteral](print, node) {
|
||||||
|
return sg_duo`[${print("initExpression")};${print("sizeExpression")}]`;
|
||||||
|
},
|
||||||
|
[NodeType.TupleLiteral](print, node) {
|
||||||
|
return printArrayLike(print, node);
|
||||||
|
},
|
||||||
|
[NodeType.ReferenceExpression](print, node) {
|
||||||
|
return printUnaryExpression(["&", print.b("mut")], node);
|
||||||
|
},
|
||||||
|
[NodeType.RawReferenceExpression](print, node) {
|
||||||
|
return printUnaryExpression(`&raw ${node.kind} `, node);
|
||||||
|
},
|
||||||
|
[NodeType.DereferenceExpression](print, node) {
|
||||||
|
return printUnaryExpression("*", node);
|
||||||
|
},
|
||||||
|
[NodeType.BoxExpression](print, node) {
|
||||||
|
return printUnaryExpression("box ", node);
|
||||||
|
},
|
||||||
|
[NodeType.UnionPattern](print, node) {
|
||||||
|
return printUnionPattern(print, node);
|
||||||
|
},
|
||||||
|
[NodeType.ParenthesizedPattern](print, node) {
|
||||||
|
exit.never();
|
||||||
|
return sg_single`(${print("pattern")})`;
|
||||||
|
},
|
||||||
|
[NodeType.RestPattern](print, node) {
|
||||||
|
return "..";
|
||||||
|
},
|
||||||
|
[NodeType.WildcardPattern](print, node) {
|
||||||
|
return "_";
|
||||||
|
},
|
||||||
|
[NodeType.PatternVariableDeclaration](print, node) {
|
||||||
|
return [print.b("ref"), print.b("mut"), printAssignment(print("id"), " @", "pattern")];
|
||||||
|
},
|
||||||
|
[NodeType.StructPattern](print, node) {
|
||||||
|
return [print("struct"), printObject(print, node)];
|
||||||
|
},
|
||||||
|
[NodeType.StructPatternPropertyDestructured](print, node) {
|
||||||
|
return [print("key"), ": ", print("pattern")];
|
||||||
|
},
|
||||||
|
[NodeType.StructPatternPropertyShorthand](print, node) {
|
||||||
|
return [print.b("box"), print.b("ref"), print.b("mut"), print("id")];
|
||||||
|
},
|
||||||
|
[NodeType.TuplePattern](print, node) {
|
||||||
|
return [print("struct"), printArrayLike(print, node)];
|
||||||
|
},
|
||||||
|
[NodeType.ArrayPattern](print, node) {
|
||||||
|
return printArrayLike(print, node);
|
||||||
|
},
|
||||||
|
[NodeType.ReferencePattern](print, node) {
|
||||||
|
return ["&", print.b("mut"), print("pattern")];
|
||||||
|
},
|
||||||
|
[NodeType.BoxPattern](print, node) {
|
||||||
|
return ["box ", print("pattern")];
|
||||||
|
},
|
||||||
|
[NodeType.MinusPattern](print, node) {
|
||||||
|
return ["-", print("pattern")];
|
||||||
|
},
|
||||||
|
[NodeType.RangePattern](print, node) {
|
||||||
|
return [print("lower"), "..", print.b("last", "="), print("upper")];
|
||||||
|
},
|
||||||
|
[NodeType.TypeCall](print, node) {
|
||||||
|
return [print("typeCallee"), printTypeArguments(print, node)];
|
||||||
|
},
|
||||||
|
[NodeType.TypeCallNamedArgument](print, node) {
|
||||||
|
return printAssignment(print("target"), " =", "typeExpression");
|
||||||
|
},
|
||||||
|
[NodeType.TypeCallNamedBound](print, node) {
|
||||||
|
return [print("typeTarget"), printTypeBounds(":", print, node)];
|
||||||
|
},
|
||||||
|
[NodeType.LtElided](print, node) {
|
||||||
|
return "'_";
|
||||||
|
},
|
||||||
|
[NodeType.LtStatic](print, node) {
|
||||||
|
return "'static";
|
||||||
|
},
|
||||||
|
[NodeType.TypeNever](print, node) {
|
||||||
|
return "!";
|
||||||
|
},
|
||||||
|
[NodeType.TypeInferred](print, node) {
|
||||||
|
return "_";
|
||||||
|
},
|
||||||
|
[NodeType.GenericTypeParameterDeclaration](print, node) {
|
||||||
|
return printAssignment(
|
||||||
|
[print("id"), printTypeBounds(":", print, node)], //
|
||||||
|
" =",
|
||||||
|
"typeDefault"
|
||||||
|
);
|
||||||
|
},
|
||||||
|
[NodeType.ConstTypeParameterDeclaration](print, node) {
|
||||||
|
return [
|
||||||
|
"const ",
|
||||||
|
printAssignment(
|
||||||
|
[print("id"), printTypeAnnotation(print, node)], //
|
||||||
|
" =",
|
||||||
|
"typeDefault"
|
||||||
|
),
|
||||||
|
];
|
||||||
|
},
|
||||||
|
[NodeType.GenericLtParameterDeclaration](print, node) {
|
||||||
|
return [print("id"), printLtBounds(":", print, node)];
|
||||||
|
},
|
||||||
|
[NodeType.WhereTypeBoundDeclaration](print, node) {
|
||||||
|
return [printLtParameters(print, node), print("typeTarget"), printTypeBounds(":", print, node)];
|
||||||
|
},
|
||||||
|
[NodeType.WhereLtBoundDeclaration](print, node) {
|
||||||
|
return [print("ltTarget"), printLtBounds(":", print, node)];
|
||||||
|
},
|
||||||
|
[NodeType.TypeTraitBound](print, node) {
|
||||||
|
return [print.b("maybeConst", "~const "), print.b("optional", "?"), printLtParameters(print, node), print("typeExpression")];
|
||||||
|
},
|
||||||
|
[NodeType.TypeDynBounds](print, node) {
|
||||||
|
return printTypeBounds("dyn", print, node);
|
||||||
|
},
|
||||||
|
[NodeType.TypeImplBounds](print, node) {
|
||||||
|
return printTypeBounds("impl", print, node);
|
||||||
|
},
|
||||||
|
[NodeType.TypeFnPointer](print, node) {
|
||||||
|
return [printLtParameters(print, node), print.b("unsafe"), print("extern"), "fn", printParametersAndReturnType(node)];
|
||||||
|
},
|
||||||
|
[NodeType.TypeFnPointerParameter](print, node) {
|
||||||
|
return [f`${print("id")}: `, print("typeAnnotation")];
|
||||||
|
},
|
||||||
|
[NodeType.TypeFunction](print, node) {
|
||||||
|
return [print("callee"), printParametersAndReturnType(node)];
|
||||||
|
},
|
||||||
|
[NodeType.TypeTuple](print, node) {
|
||||||
|
return printArrayLike(print, node);
|
||||||
|
},
|
||||||
|
[NodeType.TypeSizedArray](print, node) {
|
||||||
|
return sg_duo`[${print("typeExpression")};${print("sizeExpression")}]`;
|
||||||
|
if (isSimpleType(node)) return ["[", print("typeExpression"), "; ", print("sizeExpression"), "]"];
|
||||||
|
},
|
||||||
|
[NodeType.TypeSlice](print, node) {
|
||||||
|
if (isSimpleType(node)) return ["[", print("typeExpression"), "]"];
|
||||||
|
return sg_single`[${print("typeExpression")}]`;
|
||||||
|
},
|
||||||
|
[NodeType.TypeReference](print, node) {
|
||||||
|
return ["&", f`${print("lt")} `, print.b("mut"), print("typeExpression")];
|
||||||
|
},
|
||||||
|
[NodeType.TypeDereferenceConst](print, node) {
|
||||||
|
return ["*const ", print("typeExpression")];
|
||||||
|
},
|
||||||
|
[NodeType.TypeDereferenceMut](print, node) {
|
||||||
|
return ["*mut ", print("typeExpression")];
|
||||||
|
},
|
||||||
|
[NodeType.TypeParenthesized](print, node) {
|
||||||
|
exit.never();
|
||||||
|
return sg_single`(${print("typeExpression")})`;
|
||||||
|
},
|
||||||
|
};
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user