Compare commits
17 Commits
v1.3.5
...
f72010bd69
| Author | SHA1 | Date | |
|---|---|---|---|
| f72010bd69 | |||
| cd027097f8 | |||
| 9cbbf729c0 | |||
|
|
c26c11e253 | ||
| 338ac358db | |||
| a83c7139c9 | |||
| 42c7d11c09 | |||
| 5ca5aa64c7 | |||
| eda7ef771e | |||
| 593c4d7783 | |||
| d24a522b32 | |||
| 41afb834ae | |||
| b745329e26 | |||
| 1fb4f64cb3 | |||
| 1f8e8981ce | |||
| a257d30dba | |||
| 97ee3b0667 |
@@ -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>);
|
||||
}
|
||||
}
|
||||
@@ -50,6 +50,14 @@ export function GetSettingsPath(): Promise<string> & { cancel(): void } {
|
||||
return $resultPromise;
|
||||
}
|
||||
|
||||
/**
|
||||
* MigrateConfig 执行配置迁移
|
||||
*/
|
||||
export function MigrateConfig(): Promise<void> & { cancel(): void } {
|
||||
let $resultPromise = $Call.ByID(434292783) as any;
|
||||
return $resultPromise;
|
||||
}
|
||||
|
||||
/**
|
||||
* ResetConfig 强制重置所有配置为默认值
|
||||
*/
|
||||
|
||||
@@ -13,11 +13,11 @@ import * as MigrationService from "./migrationservice.js";
|
||||
import * as SelfUpdateService from "./selfupdateservice.js";
|
||||
import * as StartupService from "./startupservice.js";
|
||||
import * as SystemService from "./systemservice.js";
|
||||
import * as TestService from "./testservice.js";
|
||||
import * as ThemeService from "./themeservice.js";
|
||||
import * as TranslationService from "./translationservice.js";
|
||||
import * as TrayService from "./trayservice.js";
|
||||
import * as WindowService from "./windowservice.js";
|
||||
import * as WindowSnapService from "./windowsnapservice.js";
|
||||
export {
|
||||
BackupService,
|
||||
ConfigService,
|
||||
@@ -31,11 +31,11 @@ export {
|
||||
SelfUpdateService,
|
||||
StartupService,
|
||||
SystemService,
|
||||
TestService,
|
||||
ThemeService,
|
||||
TranslationService,
|
||||
TrayService,
|
||||
WindowService,
|
||||
WindowSnapService
|
||||
WindowService
|
||||
};
|
||||
|
||||
export * from "./models.js";
|
||||
|
||||
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;
|
||||
}
|
||||
@@ -1,79 +0,0 @@
|
||||
// Cynhyrchwyd y ffeil hon yn awtomatig. PEIDIWCH Â MODIWL
|
||||
// This file is automatically generated. DO NOT EDIT
|
||||
|
||||
/**
|
||||
* WindowSnapService 窗口吸附服务
|
||||
* @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";
|
||||
|
||||
/**
|
||||
* Cleanup 清理资源
|
||||
*/
|
||||
export function Cleanup(): Promise<void> & { cancel(): void } {
|
||||
let $resultPromise = $Call.ByID(2155505498) as any;
|
||||
return $resultPromise;
|
||||
}
|
||||
|
||||
/**
|
||||
* GetCurrentThreshold 获取当前自适应阈值(用于调试或显示)
|
||||
*/
|
||||
export function GetCurrentThreshold(): Promise<number> & { cancel(): void } {
|
||||
let $resultPromise = $Call.ByID(3176419026) as any;
|
||||
return $resultPromise;
|
||||
}
|
||||
|
||||
/**
|
||||
* OnWindowSnapConfigChanged 处理窗口吸附配置变更
|
||||
*/
|
||||
export function OnWindowSnapConfigChanged(enabled: boolean): Promise<void> & { cancel(): void } {
|
||||
let $resultPromise = $Call.ByID(3794787039, enabled) as any;
|
||||
return $resultPromise;
|
||||
}
|
||||
|
||||
/**
|
||||
* RegisterWindow 注册需要吸附管理的窗口
|
||||
*/
|
||||
export function RegisterWindow(documentID: number, window: application$0.WebviewWindow | null, title: string): Promise<void> & { cancel(): void } {
|
||||
let $resultPromise = $Call.ByID(1000222723, documentID, window, title) as any;
|
||||
return $resultPromise;
|
||||
}
|
||||
|
||||
/**
|
||||
* ServiceShutdown 实现服务关闭接口
|
||||
*/
|
||||
export function ServiceShutdown(): Promise<void> & { cancel(): void } {
|
||||
let $resultPromise = $Call.ByID(1172710495) as any;
|
||||
return $resultPromise;
|
||||
}
|
||||
|
||||
/**
|
||||
* SetAppReferences 设置应用和主窗口引用
|
||||
*/
|
||||
export function SetAppReferences(app: application$0.App | null, mainWindow: application$0.WebviewWindow | null): Promise<void> & { cancel(): void } {
|
||||
let $resultPromise = $Call.ByID(1782093351, app, mainWindow) as any;
|
||||
return $resultPromise;
|
||||
}
|
||||
|
||||
/**
|
||||
* SetSnapEnabled 设置是否启用窗口吸附
|
||||
*/
|
||||
export function SetSnapEnabled(enabled: boolean): Promise<void> & { cancel(): void } {
|
||||
let $resultPromise = $Call.ByID(2280126835, enabled) as any;
|
||||
return $resultPromise;
|
||||
}
|
||||
|
||||
/**
|
||||
* UnregisterWindow 取消注册窗口
|
||||
*/
|
||||
export function UnregisterWindow(documentID: number): Promise<void> & { cancel(): void } {
|
||||
let $resultPromise = $Call.ByID(2844230768, documentID) as any;
|
||||
return $resultPromise;
|
||||
}
|
||||
2832
frontend/package-lock.json
generated
2832
frontend/package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@@ -5,20 +5,20 @@
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
"dev": "vite --host --mode development",
|
||||
"build:dev": "vue-tsc && vite build --minify false --mode development",
|
||||
"build": "vue-tsc && vite build --mode production",
|
||||
"build:dev": "cross-env NODE_OPTIONS=\"--max-old-space-size=8192\" vue-tsc && cross-env NODE_OPTIONS=\"--max-old-space-size=8192\" vite build --minify false --mode development",
|
||||
"build": "cross-env NODE_OPTIONS=\"--max-old-space-size=8192\" vue-tsc && cross-env NODE_OPTIONS=\"--max-old-space-size=8192\" vite build --mode production",
|
||||
"preview": "vite preview",
|
||||
"lint": "eslint",
|
||||
"lint:fix": "eslint --fix"
|
||||
},
|
||||
"dependencies": {
|
||||
"@codemirror/autocomplete": "^6.18.6",
|
||||
"@codemirror/autocomplete": "^6.18.7",
|
||||
"@codemirror/commands": "^6.8.1",
|
||||
"@codemirror/lang-angular": "^0.1.4",
|
||||
"@codemirror/lang-cpp": "^6.0.3",
|
||||
"@codemirror/lang-css": "^6.3.1",
|
||||
"@codemirror/lang-go": "^6.0.1",
|
||||
"@codemirror/lang-html": "^6.4.9",
|
||||
"@codemirror/lang-html": "^6.4.10",
|
||||
"@codemirror/lang-java": "^6.0.2",
|
||||
"@codemirror/lang-javascript": "^6.2.4",
|
||||
"@codemirror/lang-json": "^6.0.2",
|
||||
@@ -33,7 +33,6 @@
|
||||
"@codemirror/lang-sql": "^6.9.1",
|
||||
"@codemirror/lang-vue": "^0.1.3",
|
||||
"@codemirror/lang-wast": "^6.0.2",
|
||||
"@codemirror/lang-xml": "^6.1.0",
|
||||
"@codemirror/lang-yaml": "^6.1.2",
|
||||
"@codemirror/language": "^6.11.3",
|
||||
"@codemirror/language-data": "^6.5.1",
|
||||
@@ -41,40 +40,56 @@
|
||||
"@codemirror/lint": "^6.8.5",
|
||||
"@codemirror/search": "^6.5.11",
|
||||
"@codemirror/state": "^6.5.2",
|
||||
"@codemirror/view": "^6.38.1",
|
||||
"@codemirror/view": "^6.38.2",
|
||||
"@cospaia/prettier-plugin-clojure": "^0.0.2",
|
||||
"@lezer/highlight": "^1.2.1",
|
||||
"@lezer/lr": "^1.4.2",
|
||||
"@prettier/plugin-xml": "^3.4.2",
|
||||
"@reteps/dockerfmt": "^0.3.6",
|
||||
"@toml-tools/lexer": "^1.0.0",
|
||||
"@toml-tools/parser": "^1.0.0",
|
||||
"codemirror": "^6.0.2",
|
||||
"codemirror-lang-elixir": "^4.0.0",
|
||||
"colors-named": "^1.0.2",
|
||||
"colors-named-hex": "^1.0.2",
|
||||
"franc-min": "^6.2.0",
|
||||
"groovy-beautify": "^0.0.17",
|
||||
"hsl-matcher": "^1.2.4",
|
||||
"lezer": "^0.13.5",
|
||||
"java-parser": "^3.0.1",
|
||||
"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-plugin-persistedstate": "^4.5.0",
|
||||
"prettier": "^3.6.2",
|
||||
"remarkable": "^2.0.1",
|
||||
"sass": "^1.90.0",
|
||||
"vue": "^3.5.19",
|
||||
"vue-i18n": "^11.1.11",
|
||||
"sass": "^1.92.1",
|
||||
"sh-syntax": "^0.5.8",
|
||||
"sql-formatter": "^15.6.9",
|
||||
"vue": "^3.5.21",
|
||||
"vue-i18n": "^11.1.12",
|
||||
"vue-pick-colors": "^1.8.0",
|
||||
"vue-router": "^4.5.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@eslint/js": "^9.34.0",
|
||||
"@eslint/js": "^9.35.0",
|
||||
"@lezer/generator": "^1.8.0",
|
||||
"@types/node": "^24.3.0",
|
||||
"@types/node": "^24.3.1",
|
||||
"@types/remarkable": "^2.0.8",
|
||||
"@vitejs/plugin-vue": "^6.0.1",
|
||||
"@wailsio/runtime": "latest",
|
||||
"eslint": "^9.34.0",
|
||||
"cross-env": "^7.0.3",
|
||||
"eslint": "^9.35.0",
|
||||
"eslint-plugin-vue": "^10.4.0",
|
||||
"globals": "^16.3.0",
|
||||
"globals": "^16.4.0",
|
||||
"rollup-plugin-visualizer": "^6.0.3",
|
||||
"typescript": "^5.9.2",
|
||||
"typescript-eslint": "^8.40.0",
|
||||
"typescript-eslint": "^8.43.0",
|
||||
"unplugin-vue-components": "^29.0.0",
|
||||
"vite": "^7.1.3",
|
||||
"vite": "^7.1.5",
|
||||
"vite-plugin-node-polyfills": "^0.24.0",
|
||||
"vue-eslint-parser": "^10.2.0",
|
||||
"vue-tsc": "^3.0.6"
|
||||
}
|
||||
|
||||
BIN
frontend/public/go-format.wasm
Normal file
BIN
frontend/public/go-format.wasm
Normal file
Binary file not shown.
117
frontend/src/common/prettier/plugins/clang/CustomFileSystem.cc
Normal file
117
frontend/src/common/prettier/plugins/clang/CustomFileSystem.cc
Normal file
@@ -0,0 +1,117 @@
|
||||
#include "CustomFileSystem.h"
|
||||
#include "llvm/ADT/StringExtras.h"
|
||||
#include "llvm/Support/Path.h"
|
||||
#include <emscripten.h>
|
||||
#include <iostream>
|
||||
#include <string>
|
||||
#include <system_error>
|
||||
|
||||
using namespace llvm;
|
||||
using namespace llvm::vfs;
|
||||
|
||||
namespace {
|
||||
|
||||
bool isRunningOnWindows() {
|
||||
return EM_ASM_INT({return process.platform == 'win32' ? 1 : 0}) == 1;
|
||||
}
|
||||
|
||||
std::error_code current_path(SmallVectorImpl<char> &result) {
|
||||
result.clear();
|
||||
|
||||
const char *pwd = ::getenv("PWD");
|
||||
result.append(pwd, pwd + strlen(pwd));
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
namespace llvm {
|
||||
namespace vfs {
|
||||
|
||||
sys::path::Style getPathStyle() {
|
||||
static sys::path::Style cachedStyle = sys::path::Style::native;
|
||||
|
||||
if (cachedStyle == sys::path::Style::native) {
|
||||
cachedStyle = isRunningOnWindows() ? sys::path::Style::windows
|
||||
: sys::path::Style::posix;
|
||||
}
|
||||
|
||||
return cachedStyle;
|
||||
}
|
||||
|
||||
void make_absolute(const Twine ¤t_directory,
|
||||
SmallVectorImpl<char> &path) {
|
||||
StringRef p(path.data(), path.size());
|
||||
|
||||
auto pathStyle = getPathStyle();
|
||||
|
||||
bool rootDirectory = sys::path::has_root_directory(p, pathStyle);
|
||||
bool rootName = sys::path::has_root_name(p, pathStyle);
|
||||
|
||||
// Already absolute.
|
||||
if ((rootName || is_style_posix(pathStyle)) && rootDirectory)
|
||||
return;
|
||||
|
||||
// All of the following conditions will need the current directory.
|
||||
SmallString<128> current_dir;
|
||||
current_directory.toVector(current_dir);
|
||||
|
||||
// Relative path. Prepend the current directory.
|
||||
if (!rootName && !rootDirectory) {
|
||||
// Append path to the current directory.
|
||||
sys::path::append(current_dir, pathStyle, p);
|
||||
// Set path to the result.
|
||||
path.swap(current_dir);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!rootName && rootDirectory) {
|
||||
StringRef cdrn = sys::path::root_name(current_dir, pathStyle);
|
||||
SmallString<128> curDirRootName(cdrn.begin(), cdrn.end());
|
||||
sys::path::append(curDirRootName, pathStyle, p);
|
||||
// Set path to the result.
|
||||
path.swap(curDirRootName);
|
||||
return;
|
||||
}
|
||||
|
||||
if (rootName && !rootDirectory) {
|
||||
StringRef pRootName = sys::path::root_name(p, pathStyle);
|
||||
StringRef bRootDirectory =
|
||||
sys::path::root_directory(current_dir, pathStyle);
|
||||
StringRef bRelativePath = sys::path::relative_path(current_dir, pathStyle);
|
||||
StringRef pRelativePath = sys::path::relative_path(p, pathStyle);
|
||||
|
||||
SmallString<128> res;
|
||||
sys::path::append(res, pathStyle, pRootName, bRootDirectory, bRelativePath,
|
||||
pRelativePath);
|
||||
path.swap(res);
|
||||
return;
|
||||
}
|
||||
|
||||
llvm_unreachable("All rootName and rootDirectory combinations should have "
|
||||
"occurred above!");
|
||||
}
|
||||
|
||||
std::error_code make_absolute(SmallVectorImpl<char> &path) {
|
||||
if (sys::path::is_absolute(path, getPathStyle()))
|
||||
return {};
|
||||
|
||||
SmallString<128> current_dir;
|
||||
if (std::error_code ec = current_path(current_dir))
|
||||
return ec;
|
||||
|
||||
make_absolute(current_dir, path);
|
||||
return {};
|
||||
}
|
||||
|
||||
CustomFileSystem::CustomFileSystem(IntrusiveRefCntPtr<FileSystem> FS)
|
||||
: ProxyFileSystem(std::move(FS)) {}
|
||||
|
||||
std::error_code
|
||||
CustomFileSystem::makeAbsolute(SmallVectorImpl<char> &Path) const {
|
||||
return make_absolute(Path);
|
||||
}
|
||||
|
||||
} // namespace vfs
|
||||
} // namespace llvm
|
||||
@@ -0,0 +1,27 @@
|
||||
#ifndef CUSTOM_FILE_SYSTEM_H
|
||||
#define CUSTOM_FILE_SYSTEM_H
|
||||
|
||||
#include "llvm/ADT/IntrusiveRefCntPtr.h"
|
||||
#include "llvm/ADT/SmallString.h"
|
||||
#include "llvm/ADT/SmallVector.h"
|
||||
#include "llvm/Support/ErrorOr.h"
|
||||
#include "llvm/Support/Path.h"
|
||||
#include "llvm/Support/VirtualFileSystem.h"
|
||||
|
||||
namespace llvm {
|
||||
namespace vfs {
|
||||
|
||||
sys::path::Style getPathStyle();
|
||||
std::error_code make_absolute(SmallVectorImpl<char> &path);
|
||||
|
||||
class CustomFileSystem : public ProxyFileSystem {
|
||||
public:
|
||||
CustomFileSystem(IntrusiveRefCntPtr<FileSystem> FS);
|
||||
|
||||
std::error_code makeAbsolute(SmallVectorImpl<char> &Path) const override;
|
||||
};
|
||||
|
||||
} // namespace vfs
|
||||
} // namespace llvm
|
||||
|
||||
#endif // CUSTOM_FILE_SYSTEM_H
|
||||
26
frontend/src/common/prettier/plugins/clang/binding.cc
Normal file
26
frontend/src/common/prettier/plugins/clang/binding.cc
Normal file
@@ -0,0 +1,26 @@
|
||||
#include "lib.h"
|
||||
#include <emscripten/bind.h>
|
||||
|
||||
using namespace emscripten;
|
||||
|
||||
EMSCRIPTEN_BINDINGS(my_module) {
|
||||
register_vector<unsigned>("RangeList");
|
||||
|
||||
value_object<Result>("Result")
|
||||
.field("error", &Result::error)
|
||||
.field("content", &Result::content);
|
||||
|
||||
function<std::string>("version", &version);
|
||||
function<Result, const std::string, const std::string, const std::string>(
|
||||
"format", &format);
|
||||
function<Result, const std::string, const std::string, const std::string,
|
||||
const std::vector<unsigned>>("format_byte", &format_byte);
|
||||
function<Result, const std::string, const std::string, const std::string,
|
||||
const std::vector<unsigned>>("format_line", &format_line);
|
||||
function<void, const std::string>("set_fallback_style", &set_fallback_style);
|
||||
function<void, bool>("set_sort_includes", &set_sort_includes);
|
||||
function<Result, const std::string, const std::string, const std::string>(
|
||||
"dump_config", &dump_config);
|
||||
}
|
||||
|
||||
int main(void) {}
|
||||
File diff suppressed because one or more lines are too long
BIN
frontend/src/common/prettier/plugins/clang/clang-format-cli.wasm
Normal file
BIN
frontend/src/common/prettier/plugins/clang/clang-format-cli.wasm
Normal file
Binary file not shown.
197
frontend/src/common/prettier/plugins/clang/clang-format-diff.py
Normal file
197
frontend/src/common/prettier/plugins/clang/clang-format-diff.py
Normal file
@@ -0,0 +1,197 @@
|
||||
#!/usr/bin/env python3
|
||||
#
|
||||
# ===- clang-format-diff.py - ClangFormat Diff Reformatter ----*- python -*--===#
|
||||
#
|
||||
# Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
# See https://llvm.org/LICENSE.txt for license information.
|
||||
# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
#
|
||||
# ===------------------------------------------------------------------------===#
|
||||
|
||||
"""
|
||||
This script reads input from a unified diff and reformats all the changed
|
||||
lines. This is useful to reformat all the lines touched by a specific patch.
|
||||
Example usage for git/svn users:
|
||||
|
||||
git diff -U0 --no-color --relative HEAD^ | {clang_format_diff} -p1 -i
|
||||
svn diff --diff-cmd=diff -x-U0 | {clang_format_diff} -i
|
||||
|
||||
It should be noted that the filename contained in the diff is used unmodified
|
||||
to determine the source file to update. Users calling this script directly
|
||||
should be careful to ensure that the path in the diff is correct relative to the
|
||||
current working directory.
|
||||
"""
|
||||
from __future__ import absolute_import, division, print_function
|
||||
|
||||
import argparse
|
||||
import difflib
|
||||
import re
|
||||
import subprocess
|
||||
import sys
|
||||
|
||||
if sys.version_info.major >= 3:
|
||||
from io import StringIO
|
||||
else:
|
||||
from io import BytesIO as StringIO
|
||||
|
||||
|
||||
def main():
|
||||
parser = argparse.ArgumentParser(
|
||||
description=__doc__.format(clang_format_diff="%(prog)s"),
|
||||
formatter_class=argparse.RawDescriptionHelpFormatter,
|
||||
)
|
||||
parser.add_argument(
|
||||
"-i",
|
||||
action="store_true",
|
||||
default=False,
|
||||
help="apply edits to files instead of displaying a diff",
|
||||
)
|
||||
parser.add_argument(
|
||||
"-p",
|
||||
metavar="NUM",
|
||||
default=0,
|
||||
help="strip the smallest prefix containing P slashes",
|
||||
)
|
||||
parser.add_argument(
|
||||
"-regex",
|
||||
metavar="PATTERN",
|
||||
default=None,
|
||||
help="custom pattern selecting file paths to reformat "
|
||||
"(case sensitive, overrides -iregex)",
|
||||
)
|
||||
parser.add_argument(
|
||||
"-iregex",
|
||||
metavar="PATTERN",
|
||||
default=r".*\.(?:cpp|cc|c\+\+|cxx|cppm|ccm|cxxm|c\+\+m|c|cl|h|hh|hpp"
|
||||
r"|hxx|m|mm|inc|js|ts|proto|protodevel|java|cs|json|ipynb|s?vh?)",
|
||||
help="custom pattern selecting file paths to reformat "
|
||||
"(case insensitive, overridden by -regex)",
|
||||
)
|
||||
parser.add_argument(
|
||||
"-sort-includes",
|
||||
action="store_true",
|
||||
default=False,
|
||||
help="let clang-format sort include blocks",
|
||||
)
|
||||
parser.add_argument(
|
||||
"-v",
|
||||
"--verbose",
|
||||
action="store_true",
|
||||
help="be more verbose, ineffective without -i",
|
||||
)
|
||||
parser.add_argument(
|
||||
"-style",
|
||||
help="formatting style to apply (LLVM, GNU, Google, Chromium, "
|
||||
"Microsoft, Mozilla, WebKit)",
|
||||
)
|
||||
parser.add_argument(
|
||||
"-fallback-style",
|
||||
help="The name of the predefined style used as a"
|
||||
"fallback in case clang-format is invoked with"
|
||||
"-style=file, but can not find the .clang-format"
|
||||
"file to use.",
|
||||
)
|
||||
parser.add_argument(
|
||||
"-binary",
|
||||
default="clang-format",
|
||||
help="location of binary to use for clang-format",
|
||||
)
|
||||
args = parser.parse_args()
|
||||
|
||||
# Extract changed lines for each file.
|
||||
filename = None
|
||||
lines_by_file = {}
|
||||
for line in sys.stdin:
|
||||
match = re.search(r"^\+\+\+\ (.*?/){%s}(.+)" % args.p, line.rstrip())
|
||||
if match:
|
||||
filename = match.group(2)
|
||||
if filename is None:
|
||||
continue
|
||||
|
||||
if args.regex is not None:
|
||||
if not re.match("^%s$" % args.regex, filename):
|
||||
continue
|
||||
else:
|
||||
if not re.match("^%s$" % args.iregex, filename, re.IGNORECASE):
|
||||
continue
|
||||
|
||||
match = re.search(r"^@@.*\+(\d+)(?:,(\d+))?", line)
|
||||
if match:
|
||||
start_line = int(match.group(1))
|
||||
line_count = 1
|
||||
if match.group(2):
|
||||
line_count = int(match.group(2))
|
||||
# The input is something like
|
||||
#
|
||||
# @@ -1, +0,0 @@
|
||||
#
|
||||
# which means no lines were added.
|
||||
if line_count == 0:
|
||||
continue
|
||||
# Also format lines range if line_count is 0 in case of deleting
|
||||
# surrounding statements.
|
||||
end_line = start_line
|
||||
if line_count != 0:
|
||||
end_line += line_count - 1
|
||||
lines_by_file.setdefault(filename, []).extend(
|
||||
["--lines", str(start_line) + ":" + str(end_line)]
|
||||
)
|
||||
|
||||
# Reformat files containing changes in place.
|
||||
has_diff = False
|
||||
for filename, lines in lines_by_file.items():
|
||||
if args.i and args.verbose:
|
||||
print("Formatting {}".format(filename))
|
||||
command = [args.binary, filename]
|
||||
if args.i:
|
||||
command.append("-i")
|
||||
if args.sort_includes:
|
||||
command.append("--sort-includes")
|
||||
command.extend(lines)
|
||||
if args.style:
|
||||
command.extend(["--style", args.style])
|
||||
if args.fallback_style:
|
||||
command.extend(["--fallback-style", args.fallback_style])
|
||||
|
||||
try:
|
||||
p = subprocess.Popen(
|
||||
command,
|
||||
stdout=subprocess.PIPE,
|
||||
stderr=None,
|
||||
stdin=subprocess.PIPE,
|
||||
universal_newlines=True,
|
||||
)
|
||||
except OSError as e:
|
||||
# Give the user more context when clang-format isn't
|
||||
# found/isn't executable, etc.
|
||||
raise RuntimeError(
|
||||
'Failed to run "%s" - %s"' % (" ".join(command), e.strerror)
|
||||
)
|
||||
|
||||
stdout, _stderr = p.communicate()
|
||||
if p.returncode != 0:
|
||||
return p.returncode
|
||||
|
||||
if not args.i:
|
||||
with open(filename) as f:
|
||||
code = f.readlines()
|
||||
formatted_code = StringIO(stdout).readlines()
|
||||
diff = difflib.unified_diff(
|
||||
code,
|
||||
formatted_code,
|
||||
filename,
|
||||
filename,
|
||||
"(before formatting)",
|
||||
"(after formatting)",
|
||||
)
|
||||
diff_string = "".join(diff)
|
||||
if len(diff_string) > 0:
|
||||
has_diff = True
|
||||
sys.stdout.write(diff_string)
|
||||
|
||||
if has_diff:
|
||||
return 1
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
sys.exit(main())
|
||||
@@ -0,0 +1,10 @@
|
||||
import fs from "node:fs/promises";
|
||||
import initAsync from "./clang-format.js";
|
||||
|
||||
const wasm = new URL("./clang-format.wasm", import.meta.url);
|
||||
|
||||
export default function (init = fs.readFile(wasm)) {
|
||||
return initAsync(init);
|
||||
}
|
||||
|
||||
export * from "./clang-format.js";
|
||||
@@ -0,0 +1,8 @@
|
||||
import initAsync from "./clang-format.js";
|
||||
import wasm from "./clang-format.wasm?url";
|
||||
|
||||
export default function (input = wasm) {
|
||||
return initAsync(input);
|
||||
}
|
||||
|
||||
export * from "./clang-format.js";
|
||||
175
frontend/src/common/prettier/plugins/clang/clang-format.d.ts
vendored
Normal file
175
frontend/src/common/prettier/plugins/clang/clang-format.d.ts
vendored
Normal file
@@ -0,0 +1,175 @@
|
||||
export type InitInput =
|
||||
| RequestInfo
|
||||
| URL
|
||||
| Response
|
||||
| BufferSource
|
||||
| WebAssembly.Module;
|
||||
|
||||
export default function init(input?: InitInput): Promise<void>;
|
||||
|
||||
/**
|
||||
* The style to use for formatting.
|
||||
* Supported style values are:
|
||||
* - `LLVM` - A style complying with the LLVM coding standards.
|
||||
* - `Google` - A style complying with Google’s C++ style guide.
|
||||
* - `Chromium` - A style complying with Chromium’s style guide.
|
||||
* - `Mozilla` - A style complying with Mozilla’s style guide.
|
||||
* - `WebKit` - A style complying with WebKit’s style guide.
|
||||
* - `Microsoft` - A style complying with Microsoft’s style guide.
|
||||
* - `GNU` - A style complying with the GNU coding standards.
|
||||
* - A string starting with `{`, for example: `{BasedOnStyle: Chromium, IndentWidth: 4, ...}`.
|
||||
* - A string which represents `.clang-format` content.
|
||||
*
|
||||
*/
|
||||
export type Style =
|
||||
| "LLVM"
|
||||
| "Google"
|
||||
| "Chromium"
|
||||
| "Mozilla"
|
||||
| "WebKit"
|
||||
| "Microsoft"
|
||||
| "GNU"
|
||||
| (string & {});
|
||||
|
||||
/**
|
||||
* The filename to use for determining the language.
|
||||
*/
|
||||
export type Filename =
|
||||
| "main.c"
|
||||
| "main.cc"
|
||||
| "main.cxx"
|
||||
| "main.cpp"
|
||||
| "main.java"
|
||||
| "main.js"
|
||||
| "main.mjs"
|
||||
| "main.ts"
|
||||
| "main.json"
|
||||
| "main.m"
|
||||
| "main.mm"
|
||||
| "main.proto"
|
||||
| "main.cs"
|
||||
| (string & {});
|
||||
|
||||
/**
|
||||
* Formats the given content using the specified style.
|
||||
*
|
||||
* @param {string} content - The content to format.
|
||||
* @param {Filename} filename - The filename to use for determining the language.
|
||||
* @param {Style} style - The style to use for formatting.
|
||||
* Supported style values are:
|
||||
* - `LLVM` - A style complying with the LLVM coding standards.
|
||||
* - `Google` - A style complying with Google’s C++ style guide.
|
||||
* - `Chromium` - A style complying with Chromium’s style guide.
|
||||
* - `Mozilla` - A style complying with Mozilla’s style guide.
|
||||
* - `WebKit` - A style complying with WebKit’s style guide.
|
||||
* - `Microsoft` - A style complying with Microsoft’s style guide.
|
||||
* - `GNU` - A style complying with the GNU coding standards.
|
||||
* - A string starting with `{`, for example: `{BasedOnStyle: Chromium, IndentWidth: 4, ...}`.
|
||||
* - A string which represents `.clang-format` content.
|
||||
*
|
||||
* @returns {string} The formatted content.
|
||||
* @throws {Error}
|
||||
*
|
||||
* @see {@link https://clang.llvm.org/docs/ClangFormatStyleOptions.html}
|
||||
*/
|
||||
export declare function format(
|
||||
content: string,
|
||||
filename?: Filename,
|
||||
style?: Style,
|
||||
): string;
|
||||
|
||||
/**
|
||||
* Both the startLine and endLine are 1-based.
|
||||
*/
|
||||
export type LineRange = [startLine: number, endLine: number];
|
||||
|
||||
/**
|
||||
* Both the offset and length are measured in bytes.
|
||||
*/
|
||||
export type ByteRange = [offset: number, length: number];
|
||||
|
||||
/**
|
||||
* Formats the specified range of lines in the given content using the specified style.
|
||||
*
|
||||
* @param {string} content - The content to format.
|
||||
* @param {LineRange[]} range - Array<[startLine, endLine]> - The range of lines to format.
|
||||
* Both startLine and endLine are 1-based.
|
||||
* Multiple ranges can be formatted by specifying several lines arguments.
|
||||
* @param {Filename} filename - The filename to use for determining the language.
|
||||
* @param {Style} style - The style to use for formatting.
|
||||
* Supported style values are:
|
||||
* - `LLVM` - A style complying with the LLVM coding standards.
|
||||
* - `Google` - A style complying with Google’s C++ style guide.
|
||||
* - `Chromium` - A style complying with Chromium’s style guide.
|
||||
* - `Mozilla` - A style complying with Mozilla’s style guide.
|
||||
* - `WebKit` - A style complying with WebKit’s style guide.
|
||||
* - `Microsoft` - A style complying with Microsoft’s style guide.
|
||||
* - `GNU` - A style complying with the GNU coding standards.
|
||||
* - A string starting with `{`, for example: `{BasedOnStyle: Chromium, IndentWidth: 4, ...}`.
|
||||
* - A string which represents `.clang-format` content.
|
||||
*
|
||||
* @returns {string} The formatted content.
|
||||
* @throws {Error}
|
||||
*
|
||||
* @see {@link https://clang.llvm.org/docs/ClangFormatStyleOptions.html}
|
||||
*/
|
||||
export declare function format_line_range(
|
||||
content: string,
|
||||
range: ByteRange[] | [[offset: number]],
|
||||
filename?: Filename,
|
||||
style?: Style,
|
||||
): string;
|
||||
|
||||
/**
|
||||
* @deprecated Use `format_line_range` instead.
|
||||
*/
|
||||
export declare function formatLineRange(
|
||||
content: string,
|
||||
range: ByteRange[] | [[offset: number]],
|
||||
filename?: Filename,
|
||||
style?: Style,
|
||||
): string;
|
||||
|
||||
/**
|
||||
* Formats the specified range of bytes in the given content using the specified style.
|
||||
*
|
||||
* @param {string} content - The content to format.
|
||||
* @param {ByteRange[]} range - Array<[offset, length]> - The range of bytes to format.
|
||||
* @param {Filename} filename - The filename to use for determining the language.
|
||||
* @param {Style} style - The style to use for formatting.
|
||||
* Supported style values are:
|
||||
* - `LLVM` - A style complying with the LLVM coding standards.
|
||||
* - `Google` - A style complying with Google’s C++ style guide.
|
||||
* - `Chromium` - A style complying with Chromium’s style guide.
|
||||
* - `Mozilla` - A style complying with Mozilla’s style guide.
|
||||
* - `WebKit` - A style complying with WebKit’s style guide.
|
||||
* - `Microsoft` - A style complying with Microsoft’s style guide.
|
||||
* - `GNU` - A style complying with the GNU coding standards.
|
||||
* - A string starting with `{`, for example: `{BasedOnStyle: Chromium, IndentWidth: 4, ...}`.
|
||||
* - A string which represents `.clang-format` content.
|
||||
*
|
||||
* @returns {string} The formatted content.
|
||||
* @throws {Error}
|
||||
*
|
||||
* @see {@link https://clang.llvm.org/docs/ClangFormatStyleOptions.html}
|
||||
*/
|
||||
export declare function format_byte_range(
|
||||
content: string,
|
||||
range: LineRange[],
|
||||
filename?: Filename,
|
||||
style?: Style,
|
||||
): string;
|
||||
|
||||
/**
|
||||
* @deprecated Use `format_byte_range` instead.
|
||||
*/
|
||||
export declare function formatByteRange(
|
||||
content: string,
|
||||
range: LineRange[],
|
||||
filename?: Filename,
|
||||
style?: Style,
|
||||
): string;
|
||||
|
||||
export declare function version(): string;
|
||||
|
||||
export declare function set_fallback_style(style: Style): void;
|
||||
155
frontend/src/common/prettier/plugins/clang/clang-format.js
Normal file
155
frontend/src/common/prettier/plugins/clang/clang-format.js
Normal file
File diff suppressed because one or more lines are too long
BIN
frontend/src/common/prettier/plugins/clang/clang-format.wasm
Normal file
BIN
frontend/src/common/prettier/plugins/clang/clang-format.wasm
Normal file
Binary file not shown.
3
frontend/src/common/prettier/plugins/clang/cli-pre.js
Normal file
3
frontend/src/common/prettier/plugins/clang/cli-pre.js
Normal file
@@ -0,0 +1,3 @@
|
||||
Module.preRun = function customPreRun() {
|
||||
ENV.PWD = process.cwd();
|
||||
}
|
||||
748
frontend/src/common/prettier/plugins/clang/cli.cc
Normal file
748
frontend/src/common/prettier/plugins/clang/cli.cc
Normal file
@@ -0,0 +1,748 @@
|
||||
//===-- clang-format/ClangFormat.cpp - Clang format tool ------------------===//
|
||||
//
|
||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
// See https://llvm.org/LICENSE.txt for license information.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
///
|
||||
/// \file
|
||||
/// This file implements a clang-format tool that automatically formats
|
||||
/// (fragments of) C++ code.
|
||||
///
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "clang/../../lib/Format/MatchFilePath.h"
|
||||
#include "clang/Basic/Diagnostic.h"
|
||||
#include "clang/Basic/DiagnosticOptions.h"
|
||||
#include "clang/Basic/FileManager.h"
|
||||
#include "clang/Basic/SourceManager.h"
|
||||
#include "clang/Basic/Version.h"
|
||||
#include "clang/Format/Format.h"
|
||||
#include "clang/Rewrite/Core/Rewriter.h"
|
||||
#include "llvm/ADT/StringSwitch.h"
|
||||
#include "llvm/Support/CommandLine.h"
|
||||
#include "llvm/Support/FileSystem.h"
|
||||
#include "llvm/Support/InitLLVM.h"
|
||||
#include "llvm/Support/Process.h"
|
||||
#include <fstream>
|
||||
|
||||
#include "CustomFileSystem.h"
|
||||
|
||||
using namespace llvm;
|
||||
using clang::tooling::Replacements;
|
||||
|
||||
static cl::opt<bool> Help("h", cl::desc("Alias for -help"), cl::Hidden);
|
||||
|
||||
// Mark all our options with this category, everything else (except for -version
|
||||
// and -help) will be hidden.
|
||||
static cl::OptionCategory ClangFormatCategory("Clang-format options");
|
||||
|
||||
static cl::list<unsigned>
|
||||
Offsets("offset",
|
||||
cl::desc("Format a range starting at this byte offset.\n"
|
||||
"Multiple ranges can be formatted by specifying\n"
|
||||
"several -offset and -length pairs.\n"
|
||||
"Can only be used with one input file."),
|
||||
cl::cat(ClangFormatCategory));
|
||||
static cl::list<unsigned>
|
||||
Lengths("length",
|
||||
cl::desc("Format a range of this length (in bytes).\n"
|
||||
"Multiple ranges can be formatted by specifying\n"
|
||||
"several -offset and -length pairs.\n"
|
||||
"When only a single -offset is specified without\n"
|
||||
"-length, clang-format will format up to the end\n"
|
||||
"of the file.\n"
|
||||
"Can only be used with one input file."),
|
||||
cl::cat(ClangFormatCategory));
|
||||
static cl::list<std::string>
|
||||
LineRanges("lines",
|
||||
cl::desc("<start line>:<end line> - format a range of\n"
|
||||
"lines (both 1-based).\n"
|
||||
"Multiple ranges can be formatted by specifying\n"
|
||||
"several -lines arguments.\n"
|
||||
"Can't be used with -offset and -length.\n"
|
||||
"Can only be used with one input file."),
|
||||
cl::cat(ClangFormatCategory));
|
||||
static cl::opt<std::string>
|
||||
Style("style", cl::desc(clang::format::StyleOptionHelpDescription),
|
||||
cl::init(clang::format::DefaultFormatStyle),
|
||||
cl::cat(ClangFormatCategory));
|
||||
static cl::opt<std::string>
|
||||
FallbackStyle("fallback-style",
|
||||
cl::desc("The name of the predefined style used as a\n"
|
||||
"fallback in case clang-format is invoked with\n"
|
||||
"-style=file, but can not find the .clang-format\n"
|
||||
"file to use. Defaults to 'LLVM'.\n"
|
||||
"Use -fallback-style=none to skip formatting."),
|
||||
cl::init(clang::format::DefaultFallbackStyle),
|
||||
cl::cat(ClangFormatCategory));
|
||||
|
||||
static cl::opt<std::string> AssumeFileName(
|
||||
"assume-filename",
|
||||
cl::desc("Set filename used to determine the language and to find\n"
|
||||
".clang-format file.\n"
|
||||
"Only used when reading from stdin.\n"
|
||||
"If this is not passed, the .clang-format file is searched\n"
|
||||
"relative to the current working directory when reading stdin.\n"
|
||||
"Unrecognized filenames are treated as C++.\n"
|
||||
"supported:\n"
|
||||
" CSharp: .cs\n"
|
||||
" Java: .java\n"
|
||||
" JavaScript: .js .mjs .cjs .ts\n"
|
||||
" Json: .json .ipynb\n"
|
||||
" Objective-C: .m .mm\n"
|
||||
" Proto: .proto .protodevel\n"
|
||||
" TableGen: .td\n"
|
||||
" TextProto: .txtpb .textpb .pb.txt .textproto .asciipb\n"
|
||||
" Verilog: .sv .svh .v .vh"),
|
||||
cl::init("<stdin>"), cl::cat(ClangFormatCategory));
|
||||
|
||||
static cl::opt<bool> Inplace("i",
|
||||
cl::desc("Inplace edit <file>s, if specified."),
|
||||
cl::cat(ClangFormatCategory));
|
||||
|
||||
static cl::opt<bool> OutputXML("output-replacements-xml",
|
||||
cl::desc("Output replacements as XML."),
|
||||
cl::cat(ClangFormatCategory));
|
||||
static cl::opt<bool>
|
||||
DumpConfig("dump-config",
|
||||
cl::desc("Dump configuration options to stdout and exit.\n"
|
||||
"Can be used with -style option."),
|
||||
cl::cat(ClangFormatCategory));
|
||||
static cl::opt<unsigned>
|
||||
Cursor("cursor",
|
||||
cl::desc("The position of the cursor when invoking\n"
|
||||
"clang-format from an editor integration"),
|
||||
cl::init(0), cl::cat(ClangFormatCategory));
|
||||
|
||||
static cl::opt<bool>
|
||||
SortIncludes("sort-includes",
|
||||
cl::desc("If set, overrides the include sorting behavior\n"
|
||||
"determined by the SortIncludes style flag"),
|
||||
cl::cat(ClangFormatCategory));
|
||||
|
||||
static cl::opt<std::string> QualifierAlignment(
|
||||
"qualifier-alignment",
|
||||
cl::desc("If set, overrides the qualifier alignment style\n"
|
||||
"determined by the QualifierAlignment style flag"),
|
||||
cl::init(""), cl::cat(ClangFormatCategory));
|
||||
|
||||
static cl::opt<std::string> Files(
|
||||
"files",
|
||||
cl::desc("A file containing a list of files to process, one per line."),
|
||||
cl::value_desc("filename"), cl::init(""), cl::cat(ClangFormatCategory));
|
||||
|
||||
static cl::opt<bool>
|
||||
Verbose("verbose", cl::desc("If set, shows the list of processed files"),
|
||||
cl::cat(ClangFormatCategory));
|
||||
|
||||
// Use --dry-run to match other LLVM tools when you mean do it but don't
|
||||
// actually do it
|
||||
static cl::opt<bool>
|
||||
DryRun("dry-run",
|
||||
cl::desc("If set, do not actually make the formatting changes"),
|
||||
cl::cat(ClangFormatCategory));
|
||||
|
||||
// Use -n as a common command as an alias for --dry-run. (git and make use -n)
|
||||
static cl::alias DryRunShort("n", cl::desc("Alias for --dry-run"),
|
||||
cl::cat(ClangFormatCategory), cl::aliasopt(DryRun),
|
||||
cl::NotHidden);
|
||||
|
||||
// Emulate being able to turn on/off the warning.
|
||||
static cl::opt<bool>
|
||||
WarnFormat("Wclang-format-violations",
|
||||
cl::desc("Warnings about individual formatting changes needed. "
|
||||
"Used only with --dry-run or -n"),
|
||||
cl::init(true), cl::cat(ClangFormatCategory), cl::Hidden);
|
||||
|
||||
static cl::opt<bool>
|
||||
NoWarnFormat("Wno-clang-format-violations",
|
||||
cl::desc("Do not warn about individual formatting changes "
|
||||
"needed. Used only with --dry-run or -n"),
|
||||
cl::init(false), cl::cat(ClangFormatCategory), cl::Hidden);
|
||||
|
||||
static cl::opt<unsigned> ErrorLimit(
|
||||
"ferror-limit",
|
||||
cl::desc("Set the maximum number of clang-format errors to emit\n"
|
||||
"before stopping (0 = no limit).\n"
|
||||
"Used only with --dry-run or -n"),
|
||||
cl::init(0), cl::cat(ClangFormatCategory));
|
||||
|
||||
static cl::opt<bool>
|
||||
WarningsAsErrors("Werror",
|
||||
cl::desc("If set, changes formatting warnings to errors"),
|
||||
cl::cat(ClangFormatCategory));
|
||||
|
||||
namespace {
|
||||
enum class WNoError { Unknown };
|
||||
}
|
||||
|
||||
static cl::bits<WNoError> WNoErrorList(
|
||||
"Wno-error",
|
||||
cl::desc("If set, don't error out on the specified warning type."),
|
||||
cl::values(
|
||||
clEnumValN(WNoError::Unknown, "unknown",
|
||||
"If set, unknown format options are only warned about.\n"
|
||||
"This can be used to enable formatting, even if the\n"
|
||||
"configuration contains unknown (newer) options.\n"
|
||||
"Use with caution, as this might lead to dramatically\n"
|
||||
"differing format depending on an option being\n"
|
||||
"supported or not.")),
|
||||
cl::cat(ClangFormatCategory));
|
||||
|
||||
static cl::opt<bool>
|
||||
ShowColors("fcolor-diagnostics",
|
||||
cl::desc("If set, and on a color-capable terminal controls "
|
||||
"whether or not to print diagnostics in color"),
|
||||
cl::init(true), cl::cat(ClangFormatCategory), cl::Hidden);
|
||||
|
||||
static cl::opt<bool>
|
||||
NoShowColors("fno-color-diagnostics",
|
||||
cl::desc("If set, and on a color-capable terminal controls "
|
||||
"whether or not to print diagnostics in color"),
|
||||
cl::init(false), cl::cat(ClangFormatCategory), cl::Hidden);
|
||||
|
||||
static cl::list<std::string> FileNames(cl::Positional,
|
||||
cl::desc("[@<file>] [<file> ...]"),
|
||||
cl::cat(ClangFormatCategory));
|
||||
|
||||
static cl::opt<bool> FailOnIncompleteFormat(
|
||||
"fail-on-incomplete-format",
|
||||
cl::desc("If set, fail with exit code 1 on incomplete format."),
|
||||
cl::init(false), cl::cat(ClangFormatCategory));
|
||||
|
||||
static cl::opt<bool> ListIgnored("list-ignored",
|
||||
cl::desc("List ignored files."),
|
||||
cl::cat(ClangFormatCategory), cl::Hidden);
|
||||
|
||||
namespace clang {
|
||||
namespace format {
|
||||
|
||||
static FileID createInMemoryFile(StringRef FileName, MemoryBufferRef Source,
|
||||
SourceManager &Sources, FileManager &Files,
|
||||
llvm::vfs::InMemoryFileSystem *MemFS) {
|
||||
MemFS->addFileNoOwn(FileName, 0, Source);
|
||||
auto File = Files.getOptionalFileRef(FileName);
|
||||
assert(File && "File not added to MemFS?");
|
||||
return Sources.createFileID(*File, SourceLocation(), SrcMgr::C_User);
|
||||
}
|
||||
|
||||
// Parses <start line>:<end line> input to a pair of line numbers.
|
||||
// Returns true on error.
|
||||
static bool parseLineRange(StringRef Input, unsigned &FromLine,
|
||||
unsigned &ToLine) {
|
||||
std::pair<StringRef, StringRef> LineRange = Input.split(':');
|
||||
return LineRange.first.getAsInteger(0, FromLine) ||
|
||||
LineRange.second.getAsInteger(0, ToLine);
|
||||
}
|
||||
|
||||
static bool fillRanges(MemoryBuffer *Code,
|
||||
std::vector<tooling::Range> &Ranges) {
|
||||
IntrusiveRefCntPtr<llvm::vfs::InMemoryFileSystem> InMemoryFileSystem(
|
||||
new llvm::vfs::InMemoryFileSystem);
|
||||
FileManager Files(FileSystemOptions(), InMemoryFileSystem);
|
||||
DiagnosticOptions DiagOpts;
|
||||
DiagnosticsEngine Diagnostics(
|
||||
IntrusiveRefCntPtr<DiagnosticIDs>(new DiagnosticIDs), DiagOpts);
|
||||
SourceManager Sources(Diagnostics, Files);
|
||||
const auto ID = createInMemoryFile("<irrelevant>", *Code, Sources, Files,
|
||||
InMemoryFileSystem.get());
|
||||
if (!LineRanges.empty()) {
|
||||
if (!Offsets.empty() || !Lengths.empty()) {
|
||||
errs() << "error: cannot use -lines with -offset/-length\n";
|
||||
return true;
|
||||
}
|
||||
|
||||
for (const auto &LineRange : LineRanges) {
|
||||
unsigned FromLine, ToLine;
|
||||
if (parseLineRange(LineRange, FromLine, ToLine)) {
|
||||
errs() << "error: invalid <start line>:<end line> pair\n";
|
||||
return true;
|
||||
}
|
||||
if (FromLine < 1) {
|
||||
errs() << "error: start line should be at least 1\n";
|
||||
return true;
|
||||
}
|
||||
if (FromLine > ToLine) {
|
||||
errs() << "error: start line should not exceed end line\n";
|
||||
return true;
|
||||
}
|
||||
const auto Start = Sources.translateLineCol(ID, FromLine, 1);
|
||||
const auto End = Sources.translateLineCol(ID, ToLine, UINT_MAX);
|
||||
if (Start.isInvalid() || End.isInvalid())
|
||||
return true;
|
||||
const auto Offset = Sources.getFileOffset(Start);
|
||||
const auto Length = Sources.getFileOffset(End) - Offset;
|
||||
Ranges.push_back(tooling::Range(Offset, Length));
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
if (Offsets.empty())
|
||||
Offsets.push_back(0);
|
||||
const bool EmptyLengths = Lengths.empty();
|
||||
unsigned Length = 0;
|
||||
if (Offsets.size() == 1 && EmptyLengths) {
|
||||
Length = Sources.getFileOffset(Sources.getLocForEndOfFile(ID)) - Offsets[0];
|
||||
} else if (Offsets.size() != Lengths.size()) {
|
||||
errs() << "error: number of -offset and -length arguments must match.\n";
|
||||
return true;
|
||||
}
|
||||
for (unsigned I = 0, E = Offsets.size(), CodeSize = Code->getBufferSize();
|
||||
I < E; ++I) {
|
||||
const auto Offset = Offsets[I];
|
||||
if (Offset >= CodeSize) {
|
||||
errs() << "error: offset " << Offset << " is outside the file\n";
|
||||
return true;
|
||||
}
|
||||
if (!EmptyLengths)
|
||||
Length = Lengths[I];
|
||||
if (Offset + Length > CodeSize) {
|
||||
errs() << "error: invalid length " << Length << ", offset + length ("
|
||||
<< Offset + Length << ") is outside the file.\n";
|
||||
return true;
|
||||
}
|
||||
Ranges.push_back(tooling::Range(Offset, Length));
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static void outputReplacementXML(StringRef Text) {
|
||||
// FIXME: When we sort includes, we need to make sure the stream is correct
|
||||
// utf-8.
|
||||
size_t From = 0;
|
||||
size_t Index;
|
||||
while ((Index = Text.find_first_of("\n\r<&", From)) != StringRef::npos) {
|
||||
outs() << Text.substr(From, Index - From);
|
||||
switch (Text[Index]) {
|
||||
case '\n':
|
||||
outs() << " ";
|
||||
break;
|
||||
case '\r':
|
||||
outs() << " ";
|
||||
break;
|
||||
case '<':
|
||||
outs() << "<";
|
||||
break;
|
||||
case '&':
|
||||
outs() << "&";
|
||||
break;
|
||||
default:
|
||||
llvm_unreachable("Unexpected character encountered!");
|
||||
}
|
||||
From = Index + 1;
|
||||
}
|
||||
outs() << Text.substr(From);
|
||||
}
|
||||
|
||||
static void outputReplacementsXML(const Replacements &Replaces) {
|
||||
for (const auto &R : Replaces) {
|
||||
outs() << "<replacement "
|
||||
<< "offset='" << R.getOffset() << "' "
|
||||
<< "length='" << R.getLength() << "'>";
|
||||
outputReplacementXML(R.getReplacementText());
|
||||
outs() << "</replacement>\n";
|
||||
}
|
||||
}
|
||||
|
||||
static bool
|
||||
emitReplacementWarnings(const Replacements &Replaces, StringRef AssumedFileName,
|
||||
const std::unique_ptr<llvm::MemoryBuffer> &Code) {
|
||||
unsigned Errors = 0;
|
||||
if (WarnFormat && !NoWarnFormat) {
|
||||
SourceMgr Mgr;
|
||||
const char *StartBuf = Code->getBufferStart();
|
||||
|
||||
Mgr.AddNewSourceBuffer(
|
||||
MemoryBuffer::getMemBuffer(StartBuf, AssumedFileName), SMLoc());
|
||||
for (const auto &R : Replaces) {
|
||||
SMDiagnostic Diag = Mgr.GetMessage(
|
||||
SMLoc::getFromPointer(StartBuf + R.getOffset()),
|
||||
WarningsAsErrors ? SourceMgr::DiagKind::DK_Error
|
||||
: SourceMgr::DiagKind::DK_Warning,
|
||||
"code should be clang-formatted [-Wclang-format-violations]");
|
||||
|
||||
Diag.print(nullptr, llvm::errs(), ShowColors && !NoShowColors);
|
||||
if (ErrorLimit && ++Errors >= ErrorLimit)
|
||||
break;
|
||||
}
|
||||
}
|
||||
return WarningsAsErrors;
|
||||
}
|
||||
|
||||
static void outputXML(const Replacements &Replaces,
|
||||
const Replacements &FormatChanges,
|
||||
const FormattingAttemptStatus &Status,
|
||||
const cl::opt<unsigned> &Cursor,
|
||||
unsigned CursorPosition) {
|
||||
outs() << "<?xml version='1.0'?>\n<replacements "
|
||||
"xml:space='preserve' incomplete_format='"
|
||||
<< (Status.FormatComplete ? "false" : "true") << "'";
|
||||
if (!Status.FormatComplete)
|
||||
outs() << " line='" << Status.Line << "'";
|
||||
outs() << ">\n";
|
||||
if (Cursor.getNumOccurrences() != 0) {
|
||||
outs() << "<cursor>" << FormatChanges.getShiftedCodePosition(CursorPosition)
|
||||
<< "</cursor>\n";
|
||||
}
|
||||
|
||||
outputReplacementsXML(Replaces);
|
||||
outs() << "</replacements>\n";
|
||||
}
|
||||
|
||||
class ClangFormatDiagConsumer : public DiagnosticConsumer {
|
||||
virtual void anchor() {}
|
||||
|
||||
void HandleDiagnostic(DiagnosticsEngine::Level DiagLevel,
|
||||
const Diagnostic &Info) override {
|
||||
|
||||
SmallVector<char, 16> vec;
|
||||
Info.FormatDiagnostic(vec);
|
||||
errs() << "clang-format error:" << vec << "\n";
|
||||
}
|
||||
};
|
||||
|
||||
// Returns true on error.
|
||||
static bool format(StringRef FileName, bool ErrorOnIncompleteFormat = false) {
|
||||
const bool IsSTDIN = FileName == "-";
|
||||
if (!OutputXML && Inplace && IsSTDIN) {
|
||||
errs() << "error: cannot use -i when reading from stdin.\n";
|
||||
return true;
|
||||
}
|
||||
// On Windows, overwriting a file with an open file mapping doesn't work,
|
||||
// so read the whole file into memory when formatting in-place.
|
||||
ErrorOr<std::unique_ptr<MemoryBuffer>> CodeOrErr =
|
||||
!OutputXML && Inplace
|
||||
? MemoryBuffer::getFileAsStream(FileName)
|
||||
: MemoryBuffer::getFileOrSTDIN(FileName, /*IsText=*/true);
|
||||
if (std::error_code EC = CodeOrErr.getError()) {
|
||||
errs() << FileName << ": " << EC.message() << "\n";
|
||||
return true;
|
||||
}
|
||||
std::unique_ptr<llvm::MemoryBuffer> Code = std::move(CodeOrErr.get());
|
||||
if (Code->getBufferSize() == 0)
|
||||
return false; // Empty files are formatted correctly.
|
||||
|
||||
StringRef BufStr = Code->getBuffer();
|
||||
|
||||
const char *InvalidBOM = SrcMgr::ContentCache::getInvalidBOM(BufStr);
|
||||
|
||||
if (InvalidBOM) {
|
||||
errs() << "error: encoding with unsupported byte order mark \""
|
||||
<< InvalidBOM << "\" detected";
|
||||
if (!IsSTDIN)
|
||||
errs() << " in file '" << FileName << "'";
|
||||
errs() << ".\n";
|
||||
return true;
|
||||
}
|
||||
|
||||
std::vector<tooling::Range> Ranges;
|
||||
if (fillRanges(Code.get(), Ranges))
|
||||
return true;
|
||||
StringRef AssumedFileName = IsSTDIN ? AssumeFileName : FileName;
|
||||
if (AssumedFileName.empty()) {
|
||||
llvm::errs() << "error: empty filenames are not allowed\n";
|
||||
return true;
|
||||
}
|
||||
|
||||
auto RealFS = vfs::getRealFileSystem();
|
||||
auto CustomFS = new vfs::CustomFileSystem(RealFS);
|
||||
IntrusiveRefCntPtr<vfs::FileSystem> CustomFSPtr(CustomFS);
|
||||
Expected<FormatStyle> FormatStyle =
|
||||
getStyle(Style, AssumedFileName, FallbackStyle, Code->getBuffer(),
|
||||
CustomFSPtr.get(), WNoErrorList.isSet(WNoError::Unknown));
|
||||
if (!FormatStyle) {
|
||||
llvm::errs() << toString(FormatStyle.takeError()) << "\n";
|
||||
return true;
|
||||
}
|
||||
|
||||
StringRef QualifierAlignmentOrder = QualifierAlignment;
|
||||
|
||||
FormatStyle->QualifierAlignment =
|
||||
StringSwitch<FormatStyle::QualifierAlignmentStyle>(
|
||||
QualifierAlignmentOrder.lower())
|
||||
.Case("right", FormatStyle::QAS_Right)
|
||||
.Case("left", FormatStyle::QAS_Left)
|
||||
.Default(FormatStyle->QualifierAlignment);
|
||||
|
||||
if (FormatStyle->QualifierAlignment == FormatStyle::QAS_Left) {
|
||||
FormatStyle->QualifierOrder = {"const", "volatile", "type"};
|
||||
} else if (FormatStyle->QualifierAlignment == FormatStyle::QAS_Right) {
|
||||
FormatStyle->QualifierOrder = {"type", "const", "volatile"};
|
||||
} else if (QualifierAlignmentOrder.contains("type")) {
|
||||
FormatStyle->QualifierAlignment = FormatStyle::QAS_Custom;
|
||||
SmallVector<StringRef> Qualifiers;
|
||||
QualifierAlignmentOrder.split(Qualifiers, " ", /*MaxSplit=*/-1,
|
||||
/*KeepEmpty=*/false);
|
||||
FormatStyle->QualifierOrder = {Qualifiers.begin(), Qualifiers.end()};
|
||||
}
|
||||
|
||||
if (SortIncludes.getNumOccurrences() != 0) {
|
||||
FormatStyle->SortIncludes = {};
|
||||
if (SortIncludes)
|
||||
FormatStyle->SortIncludes.Enabled = true;
|
||||
}
|
||||
unsigned CursorPosition = Cursor;
|
||||
Replacements Replaces = sortIncludes(*FormatStyle, Code->getBuffer(), Ranges,
|
||||
AssumedFileName, &CursorPosition);
|
||||
|
||||
const bool IsJson = FormatStyle->isJson();
|
||||
|
||||
// To format JSON insert a variable to trick the code into thinking its
|
||||
// JavaScript.
|
||||
if (IsJson && !FormatStyle->DisableFormat) {
|
||||
auto Err =
|
||||
Replaces.add(tooling::Replacement(AssumedFileName, 0, 0, "x = "));
|
||||
if (Err)
|
||||
llvm::errs() << "Bad Json variable insertion\n";
|
||||
}
|
||||
|
||||
auto ChangedCode = tooling::applyAllReplacements(Code->getBuffer(), Replaces);
|
||||
if (!ChangedCode) {
|
||||
llvm::errs() << toString(ChangedCode.takeError()) << "\n";
|
||||
return true;
|
||||
}
|
||||
// Get new affected ranges after sorting `#includes`.
|
||||
Ranges = tooling::calculateRangesAfterReplacements(Replaces, Ranges);
|
||||
FormattingAttemptStatus Status;
|
||||
Replacements FormatChanges =
|
||||
reformat(*FormatStyle, *ChangedCode, Ranges, AssumedFileName, &Status);
|
||||
Replaces = Replaces.merge(FormatChanges);
|
||||
if (DryRun) {
|
||||
return Replaces.size() > (IsJson ? 1u : 0u) &&
|
||||
emitReplacementWarnings(Replaces, AssumedFileName, Code);
|
||||
}
|
||||
if (OutputXML) {
|
||||
outputXML(Replaces, FormatChanges, Status, Cursor, CursorPosition);
|
||||
} else {
|
||||
IntrusiveRefCntPtr<llvm::vfs::InMemoryFileSystem> InMemoryFileSystem(
|
||||
new llvm::vfs::InMemoryFileSystem);
|
||||
FileManager Files(FileSystemOptions(), InMemoryFileSystem);
|
||||
|
||||
DiagnosticOptions DiagOpts;
|
||||
ClangFormatDiagConsumer IgnoreDiagnostics;
|
||||
DiagnosticsEngine Diagnostics(
|
||||
IntrusiveRefCntPtr<DiagnosticIDs>(new DiagnosticIDs), DiagOpts,
|
||||
&IgnoreDiagnostics, false);
|
||||
SourceManager Sources(Diagnostics, Files);
|
||||
FileID ID = createInMemoryFile(AssumedFileName, *Code, Sources, Files,
|
||||
InMemoryFileSystem.get());
|
||||
Rewriter Rewrite(Sources, LangOptions());
|
||||
tooling::applyAllReplacements(Replaces, Rewrite);
|
||||
if (Inplace) {
|
||||
if (Rewrite.overwriteChangedFiles())
|
||||
return true;
|
||||
} else {
|
||||
if (Cursor.getNumOccurrences() != 0) {
|
||||
outs() << "{ \"Cursor\": "
|
||||
<< FormatChanges.getShiftedCodePosition(CursorPosition)
|
||||
<< ", \"IncompleteFormat\": "
|
||||
<< (Status.FormatComplete ? "false" : "true");
|
||||
if (!Status.FormatComplete)
|
||||
outs() << ", \"Line\": " << Status.Line;
|
||||
outs() << " }\n";
|
||||
}
|
||||
Rewrite.getEditBuffer(ID).write(outs());
|
||||
}
|
||||
}
|
||||
return ErrorOnIncompleteFormat && !Status.FormatComplete;
|
||||
}
|
||||
|
||||
} // namespace format
|
||||
} // namespace clang
|
||||
|
||||
static void PrintVersion(raw_ostream &OS) {
|
||||
OS << clang::getClangToolFullVersion("clang-format") << '\n';
|
||||
}
|
||||
|
||||
// Dump the configuration.
|
||||
static int dumpConfig() {
|
||||
std::unique_ptr<llvm::MemoryBuffer> Code;
|
||||
// We can't read the code to detect the language if there's no file name.
|
||||
if (!FileNames.empty()) {
|
||||
// Read in the code in case the filename alone isn't enough to detect the
|
||||
// language.
|
||||
ErrorOr<std::unique_ptr<MemoryBuffer>> CodeOrErr =
|
||||
MemoryBuffer::getFileOrSTDIN(FileNames[0], /*IsText=*/true);
|
||||
if (std::error_code EC = CodeOrErr.getError()) {
|
||||
llvm::errs() << EC.message() << "\n";
|
||||
return 1;
|
||||
}
|
||||
Code = std::move(CodeOrErr.get());
|
||||
}
|
||||
|
||||
auto RealFS = vfs::getRealFileSystem();
|
||||
auto CustomFS = new vfs::CustomFileSystem(RealFS);
|
||||
IntrusiveRefCntPtr<vfs::FileSystem> CustomFSPtr(CustomFS);
|
||||
|
||||
Expected<clang::format::FormatStyle> FormatStyle = clang::format::getStyle(
|
||||
Style,
|
||||
FileNames.empty() || FileNames[0] == "-" ? AssumeFileName : FileNames[0],
|
||||
FallbackStyle, Code ? Code->getBuffer() : "", CustomFSPtr.get());
|
||||
if (!FormatStyle) {
|
||||
llvm::errs() << toString(FormatStyle.takeError()) << "\n";
|
||||
return 1;
|
||||
}
|
||||
std::string Config = clang::format::configurationAsText(*FormatStyle);
|
||||
outs() << Config << "\n";
|
||||
return 0;
|
||||
}
|
||||
|
||||
using String = SmallString<128>;
|
||||
static String IgnoreDir; // Directory of .clang-format-ignore file.
|
||||
static String PrevDir; // Directory of previous `FilePath`.
|
||||
static SmallVector<String> Patterns; // Patterns in .clang-format-ignore file.
|
||||
|
||||
// Check whether `FilePath` is ignored according to the nearest
|
||||
// .clang-format-ignore file based on the rules below:
|
||||
// - A blank line is skipped.
|
||||
// - Leading and trailing spaces of a line are trimmed.
|
||||
// - A line starting with a hash (`#`) is a comment.
|
||||
// - A non-comment line is a single pattern.
|
||||
// - The slash (`/`) is used as the directory separator.
|
||||
// - A pattern is relative to the directory of the .clang-format-ignore file (or
|
||||
// the root directory if the pattern starts with a slash).
|
||||
// - A pattern is negated if it starts with a bang (`!`).
|
||||
static bool isIgnored(StringRef FilePath) {
|
||||
using namespace llvm::sys::fs;
|
||||
if (!is_regular_file(FilePath))
|
||||
return false;
|
||||
|
||||
String Path;
|
||||
String AbsPath{FilePath};
|
||||
|
||||
auto PathStyle = vfs::getPathStyle();
|
||||
|
||||
using namespace llvm::sys::path;
|
||||
vfs::make_absolute(AbsPath);
|
||||
remove_dots(AbsPath, /*remove_dot_dot=*/true, PathStyle);
|
||||
|
||||
if (StringRef Dir{parent_path(AbsPath, PathStyle)}; PrevDir != Dir) {
|
||||
PrevDir = Dir;
|
||||
|
||||
for (;;) {
|
||||
Path = Dir;
|
||||
append(Path, PathStyle, ".clang-format-ignore");
|
||||
if (is_regular_file(Path))
|
||||
break;
|
||||
Dir = parent_path(Dir, PathStyle);
|
||||
if (Dir.empty())
|
||||
return false;
|
||||
}
|
||||
|
||||
IgnoreDir = convert_to_slash(Dir, PathStyle);
|
||||
|
||||
std::ifstream IgnoreFile{Path.c_str()};
|
||||
if (!IgnoreFile.good())
|
||||
return false;
|
||||
|
||||
Patterns.clear();
|
||||
|
||||
for (std::string Line; std::getline(IgnoreFile, Line);) {
|
||||
if (const auto Pattern{StringRef{Line}.trim()};
|
||||
// Skip empty and comment lines.
|
||||
!Pattern.empty() && Pattern[0] != '#') {
|
||||
Patterns.push_back(Pattern);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (IgnoreDir.empty())
|
||||
return false;
|
||||
|
||||
const auto Pathname{convert_to_slash(AbsPath, PathStyle)};
|
||||
for (const auto &Pat : Patterns) {
|
||||
const bool IsNegated = Pat[0] == '!';
|
||||
StringRef Pattern{Pat};
|
||||
if (IsNegated)
|
||||
Pattern = Pattern.drop_front();
|
||||
|
||||
if (Pattern.empty())
|
||||
continue;
|
||||
|
||||
Pattern = Pattern.ltrim();
|
||||
|
||||
// `Pattern` is relative to `IgnoreDir` unless it starts with a slash.
|
||||
// This doesn't support patterns containing drive names (e.g. `C:`).
|
||||
if (Pattern[0] != '/') {
|
||||
Path = IgnoreDir;
|
||||
append(Path, Style::posix, Pattern);
|
||||
remove_dots(Path, /*remove_dot_dot=*/true, Style::posix);
|
||||
Pattern = Path;
|
||||
}
|
||||
|
||||
if (clang::format::matchFilePath(Pattern, Pathname) == !IsNegated)
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
int main(int argc, const char **argv) {
|
||||
InitLLVM X(argc, argv);
|
||||
|
||||
cl::HideUnrelatedOptions(ClangFormatCategory);
|
||||
|
||||
cl::SetVersionPrinter(PrintVersion);
|
||||
cl::ParseCommandLineOptions(
|
||||
argc, argv,
|
||||
"A tool to format C/C++/Java/JavaScript/JSON/Objective-C/Protobuf/C# "
|
||||
"code.\n\n"
|
||||
"If no arguments are specified, it formats the code from standard input\n"
|
||||
"and writes the result to the standard output.\n"
|
||||
"If <file>s are given, it reformats the files. If -i is specified\n"
|
||||
"together with <file>s, the files are edited in-place. Otherwise, the\n"
|
||||
"result is written to the standard output.\n");
|
||||
|
||||
if (Help) {
|
||||
cl::PrintHelpMessage();
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (DumpConfig)
|
||||
return dumpConfig();
|
||||
|
||||
if (!Files.empty()) {
|
||||
std::ifstream ExternalFileOfFiles{std::string(Files)};
|
||||
std::string Line;
|
||||
unsigned LineNo = 1;
|
||||
while (std::getline(ExternalFileOfFiles, Line)) {
|
||||
FileNames.push_back(Line);
|
||||
LineNo++;
|
||||
}
|
||||
errs() << "Clang-formatting " << LineNo << " files\n";
|
||||
}
|
||||
|
||||
if (FileNames.empty()) {
|
||||
if (isIgnored(AssumeFileName))
|
||||
return 0;
|
||||
return clang::format::format("-", FailOnIncompleteFormat);
|
||||
}
|
||||
|
||||
if (FileNames.size() > 1 &&
|
||||
(!Offsets.empty() || !Lengths.empty() || !LineRanges.empty())) {
|
||||
errs() << "error: -offset, -length and -lines can only be used for "
|
||||
"single file.\n";
|
||||
return 1;
|
||||
}
|
||||
|
||||
unsigned FileNo = 1;
|
||||
bool Error = false;
|
||||
for (const auto &FileName : FileNames) {
|
||||
const bool Ignored = isIgnored(FileName);
|
||||
if (ListIgnored) {
|
||||
if (Ignored)
|
||||
outs() << FileName << '\n';
|
||||
continue;
|
||||
}
|
||||
if (Ignored)
|
||||
continue;
|
||||
if (Verbose) {
|
||||
errs() << "Formatting [" << FileNo++ << "/" << FileNames.size() << "] "
|
||||
<< FileName << "\n";
|
||||
}
|
||||
Error |= clang::format::format(FileName, FailOnIncompleteFormat);
|
||||
}
|
||||
return Error ? 1 : 0;
|
||||
}
|
||||
858
frontend/src/common/prettier/plugins/clang/git-clang-format
Normal file
858
frontend/src/common/prettier/plugins/clang/git-clang-format
Normal file
@@ -0,0 +1,858 @@
|
||||
#!/usr/bin/env python3
|
||||
#
|
||||
# ===- git-clang-format - ClangFormat Git Integration -------*- python -*--=== #
|
||||
#
|
||||
# Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
# See https://llvm.org/LICENSE.txt for license information.
|
||||
# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
#
|
||||
# ===----------------------------------------------------------------------=== #
|
||||
|
||||
r"""
|
||||
clang-format git integration
|
||||
============================
|
||||
|
||||
This file provides a clang-format integration for git. Put it somewhere in your
|
||||
path and ensure that it is executable. Then, "git clang-format" will invoke
|
||||
clang-format on the changes in current files or a specific commit.
|
||||
|
||||
For further details, run:
|
||||
git clang-format -h
|
||||
|
||||
Requires Python version >=3.8
|
||||
"""
|
||||
|
||||
from __future__ import absolute_import, division, print_function
|
||||
import argparse
|
||||
import collections
|
||||
import contextlib
|
||||
import errno
|
||||
import os
|
||||
import re
|
||||
import subprocess
|
||||
import sys
|
||||
|
||||
usage = "git clang-format [OPTIONS] [<commit>] [<commit>|--staged] [--] [<file>...]"
|
||||
|
||||
desc = """
|
||||
If zero or one commits are given, run clang-format on all lines that differ
|
||||
between the working directory and <commit>, which defaults to HEAD. Changes are
|
||||
only applied to the working directory, or in the stage/index.
|
||||
|
||||
Examples:
|
||||
To format staged changes, i.e everything that's been `git add`ed:
|
||||
git clang-format
|
||||
|
||||
To also format everything touched in the most recent commit:
|
||||
git clang-format HEAD~1
|
||||
|
||||
If you're on a branch off main, to format everything touched on your branch:
|
||||
git clang-format main
|
||||
|
||||
If two commits are given (requires --diff), run clang-format on all lines in the
|
||||
second <commit> that differ from the first <commit>.
|
||||
|
||||
The following git-config settings set the default of the corresponding option:
|
||||
clangFormat.binary
|
||||
clangFormat.commit
|
||||
clangFormat.extensions
|
||||
clangFormat.style
|
||||
"""
|
||||
|
||||
# Name of the temporary index file in which save the output of clang-format.
|
||||
# This file is created within the .git directory.
|
||||
temp_index_basename = "clang-format-index"
|
||||
|
||||
|
||||
Range = collections.namedtuple("Range", "start, count")
|
||||
|
||||
|
||||
def main():
|
||||
config = load_git_config()
|
||||
|
||||
# In order to keep '--' yet allow options after positionals, we need to
|
||||
# check for '--' ourselves. (Setting nargs='*' throws away the '--', while
|
||||
# nargs=argparse.REMAINDER disallows options after positionals.)
|
||||
argv = sys.argv[1:]
|
||||
try:
|
||||
idx = argv.index("--")
|
||||
except ValueError:
|
||||
dash_dash = []
|
||||
else:
|
||||
dash_dash = argv[idx:]
|
||||
argv = argv[:idx]
|
||||
|
||||
default_extensions = ",".join(
|
||||
[
|
||||
# From clang/lib/Frontend/FrontendOptions.cpp, all lower case
|
||||
"c",
|
||||
"h", # C
|
||||
"m", # ObjC
|
||||
"mm", # ObjC++
|
||||
"cc",
|
||||
"cp",
|
||||
"cpp",
|
||||
"c++",
|
||||
"cxx",
|
||||
"hh",
|
||||
"hpp",
|
||||
"hxx",
|
||||
"inc", # C++
|
||||
"ccm",
|
||||
"cppm",
|
||||
"cxxm",
|
||||
"c++m", # C++ Modules
|
||||
"cu",
|
||||
"cuh", # CUDA
|
||||
"cl", # OpenCL
|
||||
# Other languages that clang-format supports
|
||||
"proto",
|
||||
"protodevel", # Protocol Buffers
|
||||
"java", # Java
|
||||
"js",
|
||||
"mjs",
|
||||
"cjs", # JavaScript
|
||||
"ts", # TypeScript
|
||||
"cs", # C Sharp
|
||||
"json",
|
||||
"ipynb", # Json
|
||||
"sv",
|
||||
"svh",
|
||||
"v",
|
||||
"vh", # Verilog
|
||||
"td", # TableGen
|
||||
"txtpb",
|
||||
"textpb",
|
||||
"pb.txt",
|
||||
"textproto",
|
||||
"asciipb", # TextProto
|
||||
]
|
||||
)
|
||||
|
||||
p = argparse.ArgumentParser(
|
||||
usage=usage,
|
||||
formatter_class=argparse.RawDescriptionHelpFormatter,
|
||||
description=desc,
|
||||
)
|
||||
p.add_argument(
|
||||
"--binary",
|
||||
default=config.get("clangformat.binary", "clang-format"),
|
||||
help="path to clang-format",
|
||||
),
|
||||
p.add_argument(
|
||||
"--commit",
|
||||
default=config.get("clangformat.commit", "HEAD"),
|
||||
help="default commit to use if none is specified",
|
||||
),
|
||||
p.add_argument(
|
||||
"--diff",
|
||||
action="store_true",
|
||||
help="print a diff instead of applying the changes",
|
||||
)
|
||||
p.add_argument(
|
||||
"--diffstat",
|
||||
action="store_true",
|
||||
help="print a diffstat instead of applying the changes",
|
||||
)
|
||||
p.add_argument(
|
||||
"--extensions",
|
||||
default=config.get("clangformat.extensions", default_extensions),
|
||||
help=(
|
||||
"comma-separated list of file extensions to format, "
|
||||
"excluding the period and case-insensitive"
|
||||
),
|
||||
),
|
||||
p.add_argument(
|
||||
"-f",
|
||||
"--force",
|
||||
action="store_true",
|
||||
help="allow changes to unstaged files",
|
||||
)
|
||||
p.add_argument(
|
||||
"-p", "--patch", action="store_true", help="select hunks interactively"
|
||||
)
|
||||
p.add_argument(
|
||||
"-q",
|
||||
"--quiet",
|
||||
action="count",
|
||||
default=0,
|
||||
help="print less information",
|
||||
)
|
||||
p.add_argument(
|
||||
"--staged",
|
||||
"--cached",
|
||||
action="store_true",
|
||||
help="format lines in the stage instead of the working dir",
|
||||
)
|
||||
p.add_argument(
|
||||
"--style",
|
||||
default=config.get("clangformat.style", None),
|
||||
help="passed to clang-format",
|
||||
),
|
||||
p.add_argument(
|
||||
"-v",
|
||||
"--verbose",
|
||||
action="count",
|
||||
default=0,
|
||||
help="print extra information",
|
||||
)
|
||||
p.add_argument(
|
||||
"--diff_from_common_commit",
|
||||
action="store_true",
|
||||
help=(
|
||||
"diff from the last common commit for commits in "
|
||||
"separate branches rather than the exact point of the "
|
||||
"commits"
|
||||
),
|
||||
)
|
||||
# We gather all the remaining positional arguments into 'args' since we need
|
||||
# to use some heuristics to determine whether or not <commit> was present.
|
||||
# However, to print pretty messages, we make use of metavar and help.
|
||||
p.add_argument(
|
||||
"args",
|
||||
nargs="*",
|
||||
metavar="<commit>",
|
||||
help="revision from which to compute the diff",
|
||||
)
|
||||
p.add_argument(
|
||||
"ignored",
|
||||
nargs="*",
|
||||
metavar="<file>...",
|
||||
help="if specified, only consider differences in these files",
|
||||
)
|
||||
opts = p.parse_args(argv)
|
||||
|
||||
opts.verbose -= opts.quiet
|
||||
del opts.quiet
|
||||
|
||||
commits, files = interpret_args(opts.args, dash_dash, opts.commit)
|
||||
if len(commits) > 2:
|
||||
die("at most two commits allowed; %d given" % len(commits))
|
||||
if len(commits) == 2:
|
||||
if opts.staged:
|
||||
die("--staged is not allowed when two commits are given")
|
||||
if not opts.diff:
|
||||
die("--diff is required when two commits are given")
|
||||
elif opts.diff_from_common_commit:
|
||||
die("--diff_from_common_commit is only allowed when two commits are given")
|
||||
|
||||
if os.path.dirname(opts.binary):
|
||||
opts.binary = os.path.abspath(opts.binary)
|
||||
|
||||
changed_lines = compute_diff_and_extract_lines(
|
||||
commits, files, opts.staged, opts.diff_from_common_commit
|
||||
)
|
||||
if opts.verbose >= 1:
|
||||
ignored_files = set(changed_lines)
|
||||
filter_by_extension(changed_lines, opts.extensions.lower().split(","))
|
||||
# The computed diff outputs absolute paths, so we must cd before accessing
|
||||
# those files.
|
||||
cd_to_toplevel()
|
||||
filter_symlinks(changed_lines)
|
||||
filter_ignored_files(changed_lines, binary=opts.binary)
|
||||
if opts.verbose >= 1:
|
||||
ignored_files.difference_update(changed_lines)
|
||||
if ignored_files:
|
||||
print(
|
||||
"Ignoring the following files (wrong extension, symlink, or "
|
||||
"ignored by clang-format):"
|
||||
)
|
||||
for filename in ignored_files:
|
||||
print(" %s" % filename)
|
||||
if changed_lines:
|
||||
print("Running clang-format on the following files:")
|
||||
for filename in changed_lines:
|
||||
print(" %s" % filename)
|
||||
|
||||
if not changed_lines:
|
||||
if opts.verbose >= 0:
|
||||
print("no modified files to format")
|
||||
return 0
|
||||
|
||||
if len(commits) > 1:
|
||||
old_tree = commits[1]
|
||||
revision = old_tree
|
||||
elif opts.staged:
|
||||
old_tree = create_tree_from_index(changed_lines)
|
||||
revision = ""
|
||||
else:
|
||||
old_tree = create_tree_from_workdir(changed_lines)
|
||||
revision = None
|
||||
new_tree = run_clang_format_and_save_to_tree(
|
||||
changed_lines, revision, binary=opts.binary, style=opts.style
|
||||
)
|
||||
if opts.verbose >= 1:
|
||||
print("old tree: %s" % old_tree)
|
||||
print("new tree: %s" % new_tree)
|
||||
|
||||
if old_tree == new_tree:
|
||||
if opts.verbose >= 0:
|
||||
print("clang-format did not modify any files")
|
||||
return 0
|
||||
|
||||
if opts.diff:
|
||||
return print_diff(old_tree, new_tree)
|
||||
if opts.diffstat:
|
||||
return print_diffstat(old_tree, new_tree)
|
||||
|
||||
changed_files = apply_changes(
|
||||
old_tree, new_tree, force=opts.force, patch_mode=opts.patch
|
||||
)
|
||||
if (opts.verbose >= 0 and not opts.patch) or opts.verbose >= 1:
|
||||
print("changed files:")
|
||||
for filename in changed_files:
|
||||
print(" %s" % filename)
|
||||
|
||||
return 1
|
||||
|
||||
|
||||
def load_git_config(non_string_options=None):
|
||||
"""Return the git configuration as a dictionary.
|
||||
|
||||
All options are assumed to be strings unless in `non_string_options`, in
|
||||
which is a dictionary mapping option name (in lower case) to either "--bool"
|
||||
or "--int"."""
|
||||
if non_string_options is None:
|
||||
non_string_options = {}
|
||||
out = {}
|
||||
for entry in run("git", "config", "--list", "--null").split("\0"):
|
||||
if entry:
|
||||
if "\n" in entry:
|
||||
name, value = entry.split("\n", 1)
|
||||
else:
|
||||
# A setting with no '=' ('\n' with --null) is implicitly 'true'
|
||||
name = entry
|
||||
value = "true"
|
||||
if name in non_string_options:
|
||||
value = run("git", "config", non_string_options[name], name)
|
||||
out[name] = value
|
||||
return out
|
||||
|
||||
|
||||
def interpret_args(args, dash_dash, default_commit):
|
||||
"""Interpret `args` as "[commits] [--] [files]" and return (commits, files).
|
||||
|
||||
It is assumed that "--" and everything that follows has been removed from
|
||||
args and placed in `dash_dash`.
|
||||
|
||||
If "--" is present (i.e., `dash_dash` is non-empty), the arguments to its
|
||||
left (if present) are taken as commits. Otherwise, the arguments are
|
||||
checked from left to right if they are commits or files. If commits are not
|
||||
given, a list with `default_commit` is used."""
|
||||
if dash_dash:
|
||||
if len(args) == 0:
|
||||
commits = [default_commit]
|
||||
else:
|
||||
commits = args
|
||||
for commit in commits:
|
||||
object_type = get_object_type(commit)
|
||||
if object_type not in ("commit", "tag"):
|
||||
if object_type is None:
|
||||
die("'%s' is not a commit" % commit)
|
||||
else:
|
||||
die(
|
||||
"'%s' is a %s, but a commit was expected"
|
||||
% (commit, object_type)
|
||||
)
|
||||
files = dash_dash[1:]
|
||||
elif args:
|
||||
commits = []
|
||||
while args:
|
||||
if not disambiguate_revision(args[0]):
|
||||
break
|
||||
commits.append(args.pop(0))
|
||||
if not commits:
|
||||
commits = [default_commit]
|
||||
files = args
|
||||
else:
|
||||
commits = [default_commit]
|
||||
files = []
|
||||
return commits, files
|
||||
|
||||
|
||||
def disambiguate_revision(value):
|
||||
"""Returns True if `value` is a revision, False if it is a file, or dies."""
|
||||
# If `value` is ambiguous (neither a commit nor a file), the following
|
||||
# command will die with an appropriate error message.
|
||||
run("git", "rev-parse", value, verbose=False)
|
||||
object_type = get_object_type(value)
|
||||
if object_type is None:
|
||||
return False
|
||||
if object_type in ("commit", "tag"):
|
||||
return True
|
||||
die("`%s` is a %s, but a commit or filename was expected" % (value, object_type))
|
||||
|
||||
|
||||
def get_object_type(value):
|
||||
"""Returns a string description of an object's type, or None if it is not
|
||||
a valid git object."""
|
||||
cmd = ["git", "cat-file", "-t", value]
|
||||
p = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
|
||||
stdout, stderr = p.communicate()
|
||||
if p.returncode != 0:
|
||||
return None
|
||||
return convert_string(stdout.strip())
|
||||
|
||||
|
||||
def compute_diff_and_extract_lines(commits, files, staged, diff_common_commit):
|
||||
"""Calls compute_diff() followed by extract_lines()."""
|
||||
diff_process = compute_diff(commits, files, staged, diff_common_commit)
|
||||
changed_lines = extract_lines(diff_process.stdout)
|
||||
diff_process.stdout.close()
|
||||
diff_process.wait()
|
||||
if diff_process.returncode != 0:
|
||||
# Assume error was already printed to stderr.
|
||||
sys.exit(2)
|
||||
return changed_lines
|
||||
|
||||
|
||||
def compute_diff(commits, files, staged, diff_common_commit):
|
||||
"""Return a subprocess object producing the diff from `commits`.
|
||||
|
||||
The return value's `stdin` file object will produce a patch with the
|
||||
differences between the working directory (or stage if --staged is used) and
|
||||
the first commit if a single one was specified, or the difference between
|
||||
both specified commits, filtered on `files` (if non-empty).
|
||||
Zero context lines are used in the patch."""
|
||||
git_tool = "diff-index"
|
||||
extra_args = []
|
||||
if len(commits) == 2:
|
||||
git_tool = "diff-tree"
|
||||
if diff_common_commit:
|
||||
commits = [f"{commits[0]}...{commits[1]}"]
|
||||
elif staged:
|
||||
extra_args += ["--cached"]
|
||||
|
||||
cmd = ["git", git_tool, "-p", "-U0"] + extra_args + commits + ["--"]
|
||||
cmd.extend(files)
|
||||
p = subprocess.Popen(cmd, stdin=subprocess.PIPE, stdout=subprocess.PIPE)
|
||||
p.stdin.close()
|
||||
return p
|
||||
|
||||
|
||||
def extract_lines(patch_file):
|
||||
"""Extract the changed lines in `patch_file`.
|
||||
|
||||
The return value is a dictionary mapping filename to a list of (start_line,
|
||||
line_count) pairs.
|
||||
|
||||
The input must have been produced with ``-U0``, meaning unidiff format with
|
||||
zero lines of context. The return value is a dict mapping filename to a
|
||||
list of line `Range`s."""
|
||||
matches = {}
|
||||
for line in patch_file:
|
||||
line = convert_string(line)
|
||||
match = re.search(r"^\+\+\+\ [^/]+/(.*)", line)
|
||||
if match:
|
||||
filename = match.group(1).rstrip("\r\n\t")
|
||||
match = re.search(r"^@@ -[0-9,]+ \+(\d+)(,(\d+))?", line)
|
||||
if match:
|
||||
start_line = int(match.group(1))
|
||||
line_count = 1
|
||||
if match.group(3):
|
||||
line_count = int(match.group(3))
|
||||
if line_count == 0:
|
||||
line_count = 1
|
||||
if start_line == 0:
|
||||
continue
|
||||
matches.setdefault(filename, []).append(Range(start_line, line_count))
|
||||
return matches
|
||||
|
||||
|
||||
def filter_by_extension(dictionary, allowed_extensions):
|
||||
"""Delete every key in `dictionary` that doesn't have an allowed extension.
|
||||
|
||||
`allowed_extensions` must be a collection of lowercase file extensions,
|
||||
excluding the period."""
|
||||
allowed_extensions = frozenset(allowed_extensions)
|
||||
for filename in list(dictionary.keys()):
|
||||
base_ext = filename.rsplit(".", 1)
|
||||
if len(base_ext) == 1 and "" in allowed_extensions:
|
||||
continue
|
||||
if len(base_ext) == 1 or base_ext[1].lower() not in allowed_extensions:
|
||||
del dictionary[filename]
|
||||
|
||||
|
||||
def filter_symlinks(dictionary):
|
||||
"""Delete every key in `dictionary` that is a symlink."""
|
||||
for filename in list(dictionary.keys()):
|
||||
if os.path.islink(filename):
|
||||
del dictionary[filename]
|
||||
|
||||
|
||||
def filter_ignored_files(dictionary, binary):
|
||||
"""Delete every key in `dictionary` that is ignored by clang-format."""
|
||||
ignored_files = run(binary, "-list-ignored", *dictionary.keys())
|
||||
if not ignored_files:
|
||||
return
|
||||
ignored_files = ignored_files.split("\n")
|
||||
for filename in ignored_files:
|
||||
del dictionary[filename]
|
||||
|
||||
|
||||
def cd_to_toplevel():
|
||||
"""Change to the top level of the git repository."""
|
||||
toplevel = run("git", "rev-parse", "--show-toplevel")
|
||||
os.chdir(toplevel)
|
||||
|
||||
|
||||
def create_tree_from_workdir(filenames):
|
||||
"""Create a new git tree with the given files from the working directory.
|
||||
|
||||
Returns the object ID (SHA-1) of the created tree."""
|
||||
return create_tree(filenames, "--stdin")
|
||||
|
||||
|
||||
def create_tree_from_index(filenames):
|
||||
# Copy the environment, because the files have to be read from the original
|
||||
# index.
|
||||
env = os.environ.copy()
|
||||
|
||||
def index_contents_generator():
|
||||
for filename in filenames:
|
||||
git_ls_files_cmd = [
|
||||
"git",
|
||||
"ls-files",
|
||||
"--stage",
|
||||
"-z",
|
||||
"--",
|
||||
filename,
|
||||
]
|
||||
git_ls_files = subprocess.Popen(
|
||||
git_ls_files_cmd,
|
||||
env=env,
|
||||
stdin=subprocess.PIPE,
|
||||
stdout=subprocess.PIPE,
|
||||
)
|
||||
stdout = git_ls_files.communicate()[0]
|
||||
yield convert_string(stdout.split(b"\0")[0])
|
||||
|
||||
return create_tree(index_contents_generator(), "--index-info")
|
||||
|
||||
|
||||
def run_clang_format_and_save_to_tree(
|
||||
changed_lines, revision=None, binary="clang-format", style=None
|
||||
):
|
||||
"""Run clang-format on each file and save the result to a git tree.
|
||||
|
||||
Returns the object ID (SHA-1) of the created tree."""
|
||||
# Copy the environment when formatting the files in the index, because the
|
||||
# files have to be read from the original index.
|
||||
env = os.environ.copy() if revision == "" else None
|
||||
|
||||
def iteritems(container):
|
||||
try:
|
||||
return container.iteritems() # Python 2
|
||||
except AttributeError:
|
||||
return container.items() # Python 3
|
||||
|
||||
def index_info_generator():
|
||||
for filename, line_ranges in iteritems(changed_lines):
|
||||
if revision is not None:
|
||||
if len(revision) > 0:
|
||||
git_metadata_cmd = [
|
||||
"git",
|
||||
"ls-tree",
|
||||
"%s:%s" % (revision, os.path.dirname(filename)),
|
||||
os.path.basename(filename),
|
||||
]
|
||||
else:
|
||||
git_metadata_cmd = [
|
||||
"git",
|
||||
"ls-files",
|
||||
"--stage",
|
||||
"--",
|
||||
filename,
|
||||
]
|
||||
git_metadata = subprocess.Popen(
|
||||
git_metadata_cmd,
|
||||
env=env,
|
||||
stdin=subprocess.PIPE,
|
||||
stdout=subprocess.PIPE,
|
||||
)
|
||||
stdout = git_metadata.communicate()[0]
|
||||
mode = oct(int(stdout.split()[0], 8))
|
||||
else:
|
||||
mode = oct(os.stat(filename).st_mode)
|
||||
# Adjust python3 octal format so that it matches what git expects
|
||||
if mode.startswith("0o"):
|
||||
mode = "0" + mode[2:]
|
||||
blob_id = clang_format_to_blob(
|
||||
filename,
|
||||
line_ranges,
|
||||
revision=revision,
|
||||
binary=binary,
|
||||
style=style,
|
||||
env=env,
|
||||
)
|
||||
yield "%s %s\t%s" % (mode, blob_id, filename)
|
||||
|
||||
return create_tree(index_info_generator(), "--index-info")
|
||||
|
||||
|
||||
def create_tree(input_lines, mode):
|
||||
"""Create a tree object from the given input.
|
||||
|
||||
If mode is '--stdin', it must be a list of filenames. If mode is
|
||||
'--index-info' is must be a list of values suitable for "git update-index
|
||||
--index-info", such as "<mode> <SP> <sha1> <TAB> <filename>". Any other
|
||||
mode is invalid."""
|
||||
assert mode in ("--stdin", "--index-info")
|
||||
cmd = ["git", "update-index", "--add", "-z", mode]
|
||||
with temporary_index_file():
|
||||
p = subprocess.Popen(cmd, stdin=subprocess.PIPE)
|
||||
for line in input_lines:
|
||||
p.stdin.write(to_bytes("%s\0" % line))
|
||||
p.stdin.close()
|
||||
if p.wait() != 0:
|
||||
die("`%s` failed" % " ".join(cmd))
|
||||
tree_id = run("git", "write-tree")
|
||||
return tree_id
|
||||
|
||||
|
||||
def clang_format_to_blob(
|
||||
filename,
|
||||
line_ranges,
|
||||
revision=None,
|
||||
binary="clang-format",
|
||||
style=None,
|
||||
env=None,
|
||||
):
|
||||
"""Run clang-format on the given file and save the result to a git blob.
|
||||
|
||||
Runs on the file in `revision` if not None, or on the file in the working
|
||||
directory if `revision` is None. Revision can be set to an empty string to
|
||||
run clang-format on the file in the index.
|
||||
|
||||
Returns the object ID (SHA-1) of the created blob."""
|
||||
clang_format_cmd = [binary]
|
||||
if style:
|
||||
clang_format_cmd.extend(["--style=" + style])
|
||||
clang_format_cmd.extend(
|
||||
[
|
||||
"--lines=%s:%s" % (start_line, start_line + line_count - 1)
|
||||
for start_line, line_count in line_ranges
|
||||
]
|
||||
)
|
||||
if revision is not None:
|
||||
clang_format_cmd.extend(["--assume-filename=" + filename])
|
||||
git_show_cmd = [
|
||||
"git",
|
||||
"cat-file",
|
||||
"blob",
|
||||
"%s:%s" % (revision, filename),
|
||||
]
|
||||
git_show = subprocess.Popen(
|
||||
git_show_cmd, env=env, stdin=subprocess.PIPE, stdout=subprocess.PIPE
|
||||
)
|
||||
git_show.stdin.close()
|
||||
clang_format_stdin = git_show.stdout
|
||||
else:
|
||||
clang_format_cmd.extend([filename])
|
||||
git_show = None
|
||||
clang_format_stdin = subprocess.PIPE
|
||||
try:
|
||||
clang_format = subprocess.Popen(
|
||||
clang_format_cmd, stdin=clang_format_stdin, stdout=subprocess.PIPE
|
||||
)
|
||||
if clang_format_stdin == subprocess.PIPE:
|
||||
clang_format_stdin = clang_format.stdin
|
||||
except OSError as e:
|
||||
if e.errno == errno.ENOENT:
|
||||
die('cannot find executable "%s"' % binary)
|
||||
else:
|
||||
raise
|
||||
clang_format_stdin.close()
|
||||
hash_object_cmd = [
|
||||
"git",
|
||||
"hash-object",
|
||||
"-w",
|
||||
"--path=" + filename,
|
||||
"--stdin",
|
||||
]
|
||||
hash_object = subprocess.Popen(
|
||||
hash_object_cmd, stdin=clang_format.stdout, stdout=subprocess.PIPE
|
||||
)
|
||||
clang_format.stdout.close()
|
||||
stdout = hash_object.communicate()[0]
|
||||
if hash_object.returncode != 0:
|
||||
die("`%s` failed" % " ".join(hash_object_cmd))
|
||||
if clang_format.wait() != 0:
|
||||
die("`%s` failed" % " ".join(clang_format_cmd))
|
||||
if git_show and git_show.wait() != 0:
|
||||
die("`%s` failed" % " ".join(git_show_cmd))
|
||||
return convert_string(stdout).rstrip("\r\n")
|
||||
|
||||
|
||||
@contextlib.contextmanager
|
||||
def temporary_index_file(tree=None):
|
||||
"""Context manager for setting GIT_INDEX_FILE to a temporary file and
|
||||
deleting the file afterward."""
|
||||
index_path = create_temporary_index(tree)
|
||||
old_index_path = os.environ.get("GIT_INDEX_FILE")
|
||||
os.environ["GIT_INDEX_FILE"] = index_path
|
||||
try:
|
||||
yield
|
||||
finally:
|
||||
if old_index_path is None:
|
||||
del os.environ["GIT_INDEX_FILE"]
|
||||
else:
|
||||
os.environ["GIT_INDEX_FILE"] = old_index_path
|
||||
os.remove(index_path)
|
||||
|
||||
|
||||
def create_temporary_index(tree=None):
|
||||
"""Create a temporary index file and return the created file's path.
|
||||
|
||||
If `tree` is not None, use that as the tree to read in. Otherwise, an
|
||||
empty index is created."""
|
||||
gitdir = run("git", "rev-parse", "--git-dir")
|
||||
path = os.path.join(gitdir, temp_index_basename)
|
||||
if tree is None:
|
||||
tree = "--empty"
|
||||
run("git", "read-tree", "--index-output=" + path, tree)
|
||||
return path
|
||||
|
||||
|
||||
def print_diff(old_tree, new_tree):
|
||||
"""Print the diff between the two trees to stdout."""
|
||||
# We use the porcelain 'diff' and not plumbing 'diff-tree' because the
|
||||
# output is expected to be viewed by the user, and only the former does nice
|
||||
# things like color and pagination.
|
||||
#
|
||||
# We also only print modified files since `new_tree` only contains the files
|
||||
# that were modified, so unmodified files would show as deleted without the
|
||||
# filter.
|
||||
return subprocess.run(
|
||||
["git", "diff", "--diff-filter=M", "--exit-code", old_tree, new_tree]
|
||||
).returncode
|
||||
|
||||
|
||||
def print_diffstat(old_tree, new_tree):
|
||||
"""Print the diffstat between the two trees to stdout."""
|
||||
# We use the porcelain 'diff' and not plumbing 'diff-tree' because the
|
||||
# output is expected to be viewed by the user, and only the former does nice
|
||||
# things like color and pagination.
|
||||
#
|
||||
# We also only print modified files since `new_tree` only contains the files
|
||||
# that were modified, so unmodified files would show as deleted without the
|
||||
# filter.
|
||||
return subprocess.run(
|
||||
[
|
||||
"git",
|
||||
"diff",
|
||||
"--diff-filter=M",
|
||||
"--exit-code",
|
||||
"--stat",
|
||||
old_tree,
|
||||
new_tree,
|
||||
]
|
||||
).returncode
|
||||
|
||||
|
||||
def apply_changes(old_tree, new_tree, force=False, patch_mode=False):
|
||||
"""Apply the changes in `new_tree` to the working directory.
|
||||
|
||||
Bails if there are local changes in those files and not `force`. If
|
||||
`patch_mode`, runs `git checkout --patch` to select hunks interactively."""
|
||||
changed_files = (
|
||||
run(
|
||||
"git",
|
||||
"diff-tree",
|
||||
"--diff-filter=M",
|
||||
"-r",
|
||||
"-z",
|
||||
"--name-only",
|
||||
old_tree,
|
||||
new_tree,
|
||||
)
|
||||
.rstrip("\0")
|
||||
.split("\0")
|
||||
)
|
||||
if not force:
|
||||
unstaged_files = run("git", "diff-files", "--name-status", *changed_files)
|
||||
if unstaged_files:
|
||||
print(
|
||||
"The following files would be modified but have unstaged changes:",
|
||||
file=sys.stderr,
|
||||
)
|
||||
print(unstaged_files, file=sys.stderr)
|
||||
print("Please commit, stage, or stash them first.", file=sys.stderr)
|
||||
sys.exit(2)
|
||||
if patch_mode:
|
||||
# In patch mode, we could just as well create an index from the new tree
|
||||
# and checkout from that, but then the user will be presented with a
|
||||
# message saying "Discard ... from worktree". Instead, we use the old
|
||||
# tree as the index and checkout from new_tree, which gives the slightly
|
||||
# better message, "Apply ... to index and worktree". This is not quite
|
||||
# right, since it won't be applied to the user's index, but oh well.
|
||||
with temporary_index_file(old_tree):
|
||||
subprocess.run(["git", "checkout", "--patch", new_tree], check=True)
|
||||
index_tree = old_tree
|
||||
else:
|
||||
with temporary_index_file(new_tree):
|
||||
run("git", "checkout-index", "-f", "--", *changed_files)
|
||||
return changed_files
|
||||
|
||||
|
||||
def run(*args, **kwargs):
|
||||
stdin = kwargs.pop("stdin", "")
|
||||
verbose = kwargs.pop("verbose", True)
|
||||
strip = kwargs.pop("strip", True)
|
||||
for name in kwargs:
|
||||
raise TypeError("run() got an unexpected keyword argument '%s'" % name)
|
||||
p = subprocess.Popen(
|
||||
args,
|
||||
stdout=subprocess.PIPE,
|
||||
stderr=subprocess.PIPE,
|
||||
stdin=subprocess.PIPE,
|
||||
)
|
||||
stdout, stderr = p.communicate(input=stdin)
|
||||
|
||||
stdout = convert_string(stdout)
|
||||
stderr = convert_string(stderr)
|
||||
|
||||
if p.returncode == 0:
|
||||
if stderr:
|
||||
if verbose:
|
||||
print("`%s` printed to stderr:" % " ".join(args), file=sys.stderr)
|
||||
print(stderr.rstrip(), file=sys.stderr)
|
||||
if strip:
|
||||
stdout = stdout.rstrip("\r\n")
|
||||
return stdout
|
||||
if verbose:
|
||||
print("`%s` returned %s" % (" ".join(args), p.returncode), file=sys.stderr)
|
||||
if stderr:
|
||||
print(stderr.rstrip(), file=sys.stderr)
|
||||
sys.exit(2)
|
||||
|
||||
|
||||
def die(message):
|
||||
print("error:", message, file=sys.stderr)
|
||||
sys.exit(2)
|
||||
|
||||
|
||||
def to_bytes(str_input):
|
||||
# Encode to UTF-8 to get binary data.
|
||||
if isinstance(str_input, bytes):
|
||||
return str_input
|
||||
return str_input.encode("utf-8")
|
||||
|
||||
|
||||
def to_string(bytes_input):
|
||||
if isinstance(bytes_input, str):
|
||||
return bytes_input
|
||||
return bytes_input.encode("utf-8")
|
||||
|
||||
|
||||
def convert_string(bytes_input):
|
||||
try:
|
||||
return to_string(bytes_input.decode("utf-8"))
|
||||
except AttributeError: # 'str' object has no attribute 'decode'.
|
||||
return str(bytes_input)
|
||||
except UnicodeError:
|
||||
return str(bytes_input)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
sys.exit(main())
|
||||
155
frontend/src/common/prettier/plugins/clang/index.ts
Normal file
155
frontend/src/common/prettier/plugins/clang/index.ts
Normal file
@@ -0,0 +1,155 @@
|
||||
/**
|
||||
* Prettier Plugin for C/C++ formatting using clang-format WebAssembly
|
||||
*
|
||||
* This plugin provides support for formatting C/C++ files using the clang-format WASM implementation.
|
||||
* It supports various C/C++ file extensions and common clang-format styles.
|
||||
*/
|
||||
import type { Plugin, Parser, Printer } from 'prettier';
|
||||
|
||||
// Import the clang-format WASM module
|
||||
import clangFormatInit, { format } from './clang-format-vite.js';
|
||||
|
||||
const parserName = 'clang';
|
||||
|
||||
// Language configuration
|
||||
const languages = [
|
||||
{
|
||||
name: 'C',
|
||||
aliases: ['c'],
|
||||
parsers: [parserName],
|
||||
extensions: ['.c', '.h'],
|
||||
aceMode: 'c_cpp',
|
||||
tmScope: 'source.c',
|
||||
linguistLanguageId: 50,
|
||||
vscodeLanguageIds: ['c']
|
||||
},
|
||||
{
|
||||
name: 'C++',
|
||||
aliases: ['cpp', 'cxx', 'cc'],
|
||||
parsers: [parserName],
|
||||
extensions: ['.cpp', '.cxx', '.cc', '.hpp', '.hxx', '.hh', '.C', '.H'],
|
||||
aceMode: 'c_cpp',
|
||||
tmScope: 'source.cpp',
|
||||
linguistLanguageId: 43,
|
||||
vscodeLanguageIds: ['cpp']
|
||||
},
|
||||
{
|
||||
name: 'Objective-C',
|
||||
aliases: ['objc', 'objectivec'],
|
||||
parsers: [parserName],
|
||||
extensions: ['.m', '.mm'],
|
||||
aceMode: 'objectivec',
|
||||
tmScope: 'source.objc',
|
||||
linguistLanguageId: 259,
|
||||
vscodeLanguageIds: ['objective-c']
|
||||
}
|
||||
];
|
||||
|
||||
// Parser configuration
|
||||
const clangParser: Parser<string> = {
|
||||
astFormat: parserName,
|
||||
parse: (text: string) => text,
|
||||
locStart: () => 0,
|
||||
locEnd: (node: string) => node.length,
|
||||
};
|
||||
|
||||
// Initialize clang-format WASM module
|
||||
let initPromise: Promise<void> | null = null;
|
||||
let isInitialized = false;
|
||||
|
||||
function initClangFormat(): Promise<void> {
|
||||
if (initPromise) {
|
||||
return initPromise;
|
||||
}
|
||||
|
||||
initPromise = (async () => {
|
||||
if (!isInitialized) {
|
||||
await clangFormatInit();
|
||||
isInitialized = true;
|
||||
}
|
||||
})();
|
||||
|
||||
return initPromise;
|
||||
}
|
||||
|
||||
// Printer configuration
|
||||
const clangPrinter: Printer<string> = {
|
||||
print: (path, options) => {
|
||||
try {
|
||||
if (!isInitialized) {
|
||||
console.warn('clang-format WASM module not initialized, returning original text');
|
||||
return (path as any).getValue ? (path as any).getValue() : path.node;
|
||||
}
|
||||
|
||||
const text = (path as any).getValue ? (path as any).getValue() : path.node;
|
||||
const style = getClangStyle(options);
|
||||
|
||||
// Format using clang-format (synchronous call)
|
||||
const formatted = format(text, undefined, style);
|
||||
|
||||
return formatted.trim();
|
||||
} catch (error) {
|
||||
console.warn('clang-format failed:', error);
|
||||
// Return original text if formatting fails
|
||||
return (path as any).getValue ? (path as any).getValue() : path.node;
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
|
||||
// Helper function to determine clang-format style
|
||||
function getClangStyle(options: any): string {
|
||||
// You can extend this to support more options
|
||||
const style = options.clangStyle || 'LLVM';
|
||||
|
||||
// Support common styles
|
||||
const validStyles = ['LLVM', 'Google', 'Chromium', 'Mozilla', 'WebKit', 'Microsoft', 'GNU'];
|
||||
if (validStyles.includes(style)) {
|
||||
return style;
|
||||
}
|
||||
|
||||
// Default to LLVM style
|
||||
return 'LLVM';
|
||||
}
|
||||
|
||||
// Plugin options
|
||||
const options = {
|
||||
clangStyle: {
|
||||
since: '0.0.1',
|
||||
category: 'Format' as const,
|
||||
type: 'choice' as const,
|
||||
default: 'LLVM',
|
||||
description: 'The clang-format style to use',
|
||||
choices: [
|
||||
{ value: 'LLVM', description: 'LLVM coding standards' },
|
||||
{ value: 'Google', description: "Google's C++ style guide" },
|
||||
{ value: 'Chromium', description: "Chromium's style guide" },
|
||||
{ value: 'Mozilla', description: "Mozilla's style guide" },
|
||||
{ value: 'WebKit', description: "WebKit's style guide" },
|
||||
{ value: 'Microsoft', description: "Microsoft's style guide" },
|
||||
{ value: 'GNU', description: 'GNU coding standards' }
|
||||
]
|
||||
}
|
||||
};
|
||||
|
||||
// Plugin object
|
||||
const clangPlugin: Plugin = {
|
||||
languages,
|
||||
parsers: {
|
||||
[parserName]: clangParser,
|
||||
},
|
||||
printers: {
|
||||
[parserName]: clangPrinter,
|
||||
},
|
||||
options,
|
||||
};
|
||||
|
||||
// Initialize WASM module when plugin loads
|
||||
initClangFormat().catch(error => {
|
||||
console.warn('Failed to initialize clang-format WASM module:', error);
|
||||
});
|
||||
|
||||
export default clangPlugin;
|
||||
export { languages };
|
||||
export const parsers = clangPlugin.parsers;
|
||||
export const printers = clangPlugin.printers;
|
||||
323
frontend/src/common/prettier/plugins/clang/lib.cc
Normal file
323
frontend/src/common/prettier/plugins/clang/lib.cc
Normal file
@@ -0,0 +1,323 @@
|
||||
//===-- clang-format/ClangFormat.cpp - Clang format tool ------------------===//
|
||||
//
|
||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
// See https://llvm.org/LICENSE.txt for license information.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
///
|
||||
/// \file
|
||||
/// This file implements a clang-format tool that automatically formats
|
||||
/// (fragments of) C++ code.
|
||||
///
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "lib.h"
|
||||
#include "clang/Basic/FileManager.h"
|
||||
#include "clang/Basic/SourceManager.h"
|
||||
#include "clang/Basic/Version.h"
|
||||
#include "clang/Format/Format.h"
|
||||
#include "clang/Rewrite/Core/Rewriter.h"
|
||||
|
||||
using namespace llvm;
|
||||
using clang::tooling::Replacements;
|
||||
|
||||
static std::string FallbackStyle{clang::format::DefaultFallbackStyle};
|
||||
|
||||
static unsigned Cursor{0};
|
||||
|
||||
static bool SortIncludes{false};
|
||||
|
||||
static std::string QualifierAlignment{""};
|
||||
|
||||
static auto Ok(const std::string content) -> Result {
|
||||
return {false, std::move(content)};
|
||||
}
|
||||
|
||||
static auto Err(const std::string content) -> Result {
|
||||
return {true, std::move(content)};
|
||||
}
|
||||
|
||||
namespace clang {
|
||||
namespace format {
|
||||
|
||||
static FileID createInMemoryFile(StringRef FileName, MemoryBufferRef Source,
|
||||
SourceManager &Sources, FileManager &Files,
|
||||
llvm::vfs::InMemoryFileSystem *MemFS) {
|
||||
MemFS->addFileNoOwn(FileName, 0, Source);
|
||||
auto File = Files.getOptionalFileRef(FileName);
|
||||
assert(File && "File not added to MemFS?");
|
||||
return Sources.createFileID(*File, SourceLocation(), SrcMgr::C_User);
|
||||
}
|
||||
|
||||
static auto fillRanges(MemoryBuffer *Code, std::vector<tooling::Range> &Ranges)
|
||||
-> void {
|
||||
Ranges.push_back(tooling::Range(0, Code->getBuffer().size()));
|
||||
}
|
||||
|
||||
static auto isPredefinedStyle(StringRef style) -> bool {
|
||||
return StringSwitch<bool>(style.lower())
|
||||
.Cases("llvm", "chromium", "mozilla", "google", "webkit", "gnu",
|
||||
"microsoft", "none", "file", true)
|
||||
.Default(false);
|
||||
}
|
||||
|
||||
static auto format_range(const std::unique_ptr<llvm::MemoryBuffer> code,
|
||||
const std::string assumedFileName,
|
||||
const std::string style,
|
||||
std::vector<tooling::Range> ranges) -> Result {
|
||||
StringRef BufStr = code->getBuffer();
|
||||
|
||||
const char *InvalidBOM = SrcMgr::ContentCache::getInvalidBOM(BufStr);
|
||||
|
||||
if (InvalidBOM) {
|
||||
std::stringstream err;
|
||||
err << "encoding with unsupported byte order mark \"" << InvalidBOM
|
||||
<< "\" detected.";
|
||||
|
||||
return Err(err.str());
|
||||
}
|
||||
|
||||
StringRef AssumedFileName = assumedFileName;
|
||||
if (AssumedFileName.empty())
|
||||
AssumedFileName = "<stdin>";
|
||||
|
||||
IntrusiveRefCntPtr<llvm::vfs::InMemoryFileSystem> InMemoryFileSystem(
|
||||
new llvm::vfs::InMemoryFileSystem);
|
||||
FileManager Files(FileSystemOptions(), InMemoryFileSystem);
|
||||
|
||||
DiagnosticOptions DiagOpts;
|
||||
DiagnosticsEngine Diagnostics(
|
||||
IntrusiveRefCntPtr<DiagnosticIDs>(new DiagnosticIDs), DiagOpts);
|
||||
SourceManager Sources(Diagnostics, Files);
|
||||
|
||||
StringRef _style = style;
|
||||
|
||||
if (!_style.starts_with("{") && !isPredefinedStyle(_style)) {
|
||||
std::unique_ptr<llvm::MemoryBuffer> DotClangFormat =
|
||||
MemoryBuffer::getMemBuffer(style);
|
||||
|
||||
createInMemoryFile(".clang-format", *DotClangFormat.get(), Sources, Files,
|
||||
InMemoryFileSystem.get());
|
||||
_style = "file:.clang-format";
|
||||
}
|
||||
|
||||
llvm::Expected<FormatStyle> FormatStyle =
|
||||
getStyle(_style, AssumedFileName, FallbackStyle, code->getBuffer(),
|
||||
InMemoryFileSystem.get(), false);
|
||||
|
||||
InMemoryFileSystem.reset();
|
||||
|
||||
if (!FormatStyle) {
|
||||
std::string err = llvm::toString(FormatStyle.takeError());
|
||||
return Err(err);
|
||||
}
|
||||
|
||||
StringRef QualifierAlignmentOrder = QualifierAlignment;
|
||||
|
||||
FormatStyle->QualifierAlignment =
|
||||
StringSwitch<FormatStyle::QualifierAlignmentStyle>(
|
||||
QualifierAlignmentOrder.lower())
|
||||
.Case("right", FormatStyle::QAS_Right)
|
||||
.Case("left", FormatStyle::QAS_Left)
|
||||
.Default(FormatStyle->QualifierAlignment);
|
||||
|
||||
if (FormatStyle->QualifierAlignment == FormatStyle::QAS_Left) {
|
||||
FormatStyle->QualifierOrder = {"const", "volatile", "type"};
|
||||
} else if (FormatStyle->QualifierAlignment == FormatStyle::QAS_Right) {
|
||||
FormatStyle->QualifierOrder = {"type", "const", "volatile"};
|
||||
} else if (QualifierAlignmentOrder.contains("type")) {
|
||||
FormatStyle->QualifierAlignment = FormatStyle::QAS_Custom;
|
||||
SmallVector<StringRef> Qualifiers;
|
||||
QualifierAlignmentOrder.split(Qualifiers, " ", /*MaxSplit=*/-1,
|
||||
/*KeepEmpty=*/false);
|
||||
FormatStyle->QualifierOrder = {Qualifiers.begin(), Qualifiers.end()};
|
||||
}
|
||||
|
||||
if (SortIncludes) {
|
||||
FormatStyle->SortIncludes = {};
|
||||
FormatStyle->SortIncludes.Enabled = true;
|
||||
}
|
||||
|
||||
unsigned CursorPosition = Cursor;
|
||||
Replacements Replaces = sortIncludes(*FormatStyle, code->getBuffer(), ranges,
|
||||
AssumedFileName, &CursorPosition);
|
||||
|
||||
// To format JSON insert a variable to trick the code into thinking its
|
||||
// JavaScript.
|
||||
if (FormatStyle->isJson() && !FormatStyle->DisableFormat) {
|
||||
auto err =
|
||||
Replaces.add(tooling::Replacement(AssumedFileName, 0, 0, "x = "));
|
||||
if (err)
|
||||
return Err("Bad Json variable insertion");
|
||||
}
|
||||
|
||||
auto ChangedCode =
|
||||
cantFail(tooling::applyAllReplacements(code->getBuffer(), Replaces));
|
||||
|
||||
// Get new affected ranges after sorting `#includes`.
|
||||
ranges = tooling::calculateRangesAfterReplacements(Replaces, ranges);
|
||||
FormattingAttemptStatus Status;
|
||||
Replacements FormatChanges =
|
||||
reformat(*FormatStyle, ChangedCode, ranges, AssumedFileName, &Status);
|
||||
Replaces = Replaces.merge(FormatChanges);
|
||||
|
||||
return Ok(
|
||||
cantFail(tooling::applyAllReplacements(code->getBuffer(), Replaces)));
|
||||
}
|
||||
|
||||
static auto format_range(const std::string str,
|
||||
const std::string assumedFileName,
|
||||
const std::string style, const bool is_line_range,
|
||||
const std::vector<unsigned> ranges) -> Result {
|
||||
ErrorOr<std::unique_ptr<MemoryBuffer>> CodeOrErr =
|
||||
MemoryBuffer::getMemBuffer(str);
|
||||
|
||||
if (std::error_code EC = CodeOrErr.getError())
|
||||
return Err(EC.message());
|
||||
std::unique_ptr<llvm::MemoryBuffer> Code = std::move(CodeOrErr.get());
|
||||
if (Code->getBufferSize() == 0)
|
||||
return Ok(""); // Empty files are formatted correctly.
|
||||
|
||||
std::vector<tooling::Range> Ranges;
|
||||
|
||||
if (ranges.empty()) {
|
||||
fillRanges(Code.get(), Ranges);
|
||||
return format_range(std::move(Code), assumedFileName, style,
|
||||
std::move(Ranges));
|
||||
}
|
||||
|
||||
IntrusiveRefCntPtr<llvm::vfs::InMemoryFileSystem> InMemoryFileSystem(
|
||||
new llvm::vfs::InMemoryFileSystem);
|
||||
FileManager Files(FileSystemOptions(), InMemoryFileSystem);
|
||||
DiagnosticOptions DiagOpts;
|
||||
DiagnosticsEngine Diagnostics(
|
||||
IntrusiveRefCntPtr<DiagnosticIDs>(new DiagnosticIDs), DiagOpts);
|
||||
SourceManager Sources(Diagnostics, Files);
|
||||
FileID ID = createInMemoryFile("<irrelevant>", *Code, Sources, Files,
|
||||
InMemoryFileSystem.get());
|
||||
|
||||
if (is_line_range) {
|
||||
for (auto FromLine = begin(ranges); FromLine < end(ranges); FromLine += 2) {
|
||||
auto ToLine = FromLine + 1;
|
||||
|
||||
SourceLocation Start = Sources.translateLineCol(ID, *FromLine, 1);
|
||||
SourceLocation End = Sources.translateLineCol(ID, *ToLine, UINT_MAX);
|
||||
if (Start.isInvalid() || End.isInvalid())
|
||||
return Err("invalid line number");
|
||||
unsigned Offset = Sources.getFileOffset(Start);
|
||||
unsigned Length = Sources.getFileOffset(End) - Offset;
|
||||
Ranges.push_back(tooling::Range(Offset, Length));
|
||||
}
|
||||
} else {
|
||||
if (ranges.size() > 2 && ranges.size() % 2 != 0)
|
||||
return Err("number of -offset and -length arguments must match");
|
||||
|
||||
if (ranges.size() == 1) {
|
||||
auto offset = begin(ranges);
|
||||
if (*offset >= Code->getBufferSize()) {
|
||||
std::stringstream err;
|
||||
err << "offset " << *offset << " is outside the file";
|
||||
return Err(err.str());
|
||||
}
|
||||
SourceLocation Start =
|
||||
Sources.getLocForStartOfFile(ID).getLocWithOffset(*offset);
|
||||
SourceLocation End = Sources.getLocForEndOfFile(ID);
|
||||
|
||||
unsigned Offset = Sources.getFileOffset(Start);
|
||||
unsigned Length = Sources.getFileOffset(End) - Offset;
|
||||
|
||||
Ranges.push_back(tooling::Range(Offset, Length));
|
||||
} else {
|
||||
for (auto offset = begin(ranges); offset < end(ranges); offset += 2) {
|
||||
auto length = offset + 1;
|
||||
|
||||
if (*offset >= Code->getBufferSize()) {
|
||||
std::stringstream err;
|
||||
err << "offset " << *offset << " is outside the file";
|
||||
return Err(err.str());
|
||||
}
|
||||
|
||||
unsigned end = *offset + *length;
|
||||
if (end > Code->getBufferSize()) {
|
||||
std::stringstream err;
|
||||
err << "invalid length " << *length << ", offset + length (" << end
|
||||
<< ") is outside the file.";
|
||||
return Err(err.str());
|
||||
}
|
||||
|
||||
SourceLocation Start =
|
||||
Sources.getLocForStartOfFile(ID).getLocWithOffset(*offset);
|
||||
SourceLocation End = Start.getLocWithOffset(*length);
|
||||
|
||||
unsigned Offset = Sources.getFileOffset(Start);
|
||||
unsigned Length = Sources.getFileOffset(End) - Offset;
|
||||
|
||||
Ranges.push_back(tooling::Range(Offset, Length));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return format_range(std::move(Code), assumedFileName, style,
|
||||
std::move(Ranges));
|
||||
}
|
||||
|
||||
static auto format(const std::string str, const std::string assumedFileName,
|
||||
const std::string style) -> Result {
|
||||
ErrorOr<std::unique_ptr<MemoryBuffer>> CodeOrErr =
|
||||
MemoryBuffer::getMemBuffer(str);
|
||||
|
||||
if (std::error_code EC = CodeOrErr.getError())
|
||||
return Err(EC.message());
|
||||
std::unique_ptr<llvm::MemoryBuffer> Code = std::move(CodeOrErr.get());
|
||||
if (Code->getBufferSize() == 0)
|
||||
return Ok(""); // Empty files are formatted correctly.
|
||||
|
||||
std::vector<tooling::Range> Ranges;
|
||||
fillRanges(Code.get(), Ranges);
|
||||
|
||||
return format_range(std::move(Code), assumedFileName, style,
|
||||
std::move(Ranges));
|
||||
}
|
||||
|
||||
} // namespace format
|
||||
} // namespace clang
|
||||
|
||||
auto version() -> std::string {
|
||||
return clang::getClangToolFullVersion("clang-format");
|
||||
}
|
||||
|
||||
auto format(const std::string str, const std::string assumedFileName,
|
||||
const std::string style) -> Result {
|
||||
return clang::format::format(str, assumedFileName, style);
|
||||
}
|
||||
|
||||
auto format_byte(const std::string str, const std::string assumedFileName,
|
||||
const std::string style, const std::vector<unsigned> ranges)
|
||||
-> Result {
|
||||
return clang::format::format_range(str, assumedFileName, style, false,
|
||||
std::move(ranges));
|
||||
}
|
||||
|
||||
auto format_line(const std::string str, const std::string assumedFileName,
|
||||
const std::string style, const std::vector<unsigned> ranges)
|
||||
-> Result {
|
||||
return clang::format::format_range(str, assumedFileName, style, true,
|
||||
std::move(ranges));
|
||||
}
|
||||
|
||||
auto set_fallback_style(const std::string style) -> void {
|
||||
FallbackStyle = style;
|
||||
}
|
||||
|
||||
auto set_sort_includes(const bool sort) -> void { SortIncludes = sort; }
|
||||
|
||||
auto dump_config(const std::string style, const std::string FileName,
|
||||
const std::string code) -> Result {
|
||||
llvm::Expected<clang::format::FormatStyle> FormatStyle =
|
||||
clang::format::getStyle(style, FileName, FallbackStyle, code);
|
||||
if (!FormatStyle)
|
||||
return Err(llvm::toString(FormatStyle.takeError()));
|
||||
std::string Config = clang::format::configurationAsText(*FormatStyle);
|
||||
return Ok(Config);
|
||||
}
|
||||
24
frontend/src/common/prettier/plugins/clang/lib.h
Normal file
24
frontend/src/common/prettier/plugins/clang/lib.h
Normal file
@@ -0,0 +1,24 @@
|
||||
#ifndef CLANG_FORMAT_WASM_LIB_H_
|
||||
#define CLANG_FORMAT_WASM_LIB_H_
|
||||
#include <sstream>
|
||||
|
||||
struct Result {
|
||||
bool error;
|
||||
std::string content;
|
||||
};
|
||||
|
||||
auto version() -> std::string;
|
||||
auto format(const std::string str, const std::string assumedFileName, const std::string style) -> Result;
|
||||
auto format_byte(const std::string str,
|
||||
const std::string assumedFileName,
|
||||
const std::string style,
|
||||
const std::vector<unsigned> ranges) -> Result;
|
||||
auto format_line(const std::string str,
|
||||
const std::string assumedFileName,
|
||||
const std::string style,
|
||||
const std::vector<unsigned> ranges) -> Result;
|
||||
auto set_fallback_style(const std::string style) -> void;
|
||||
auto set_sort_includes(const bool sort) -> void;
|
||||
auto dump_config(const std::string style, const std::string FileName, const std::string code) -> Result;
|
||||
|
||||
#endif
|
||||
146
frontend/src/common/prettier/plugins/clang/template.js
Normal file
146
frontend/src/common/prettier/plugins/clang/template.js
Normal file
@@ -0,0 +1,146 @@
|
||||
/* @ts-self-types="./clang-format.d.ts" */
|
||||
async function load(module) {
|
||||
if (typeof Response === "function" && module instanceof Response) {
|
||||
if ("compileStreaming" in WebAssembly) {
|
||||
try {
|
||||
return await WebAssembly.compileStreaming(module);
|
||||
} catch (e) {
|
||||
if (module.headers.get("Content-Type") !== "application/wasm") {
|
||||
console.warn(
|
||||
"`WebAssembly.compileStreaming` failed because your server does not serve wasm with `application/wasm` MIME type. Falling back to `WebAssembly.instantiate` which is slower. Original error:\n",
|
||||
e,
|
||||
);
|
||||
} else {
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return module.arrayBuffer();
|
||||
}
|
||||
|
||||
return module;
|
||||
}
|
||||
|
||||
let wasm;
|
||||
export default async function initAsync(input) {
|
||||
if (wasm !== undefined) {
|
||||
return wasm;
|
||||
}
|
||||
|
||||
if (typeof input === "undefined") {
|
||||
input = new URL("clang-format.wasm", import.meta.url);
|
||||
}
|
||||
|
||||
if (
|
||||
typeof input === "string" ||
|
||||
(typeof Request === "function" && input instanceof Request) ||
|
||||
(typeof URL === "function" && input instanceof URL)
|
||||
) {
|
||||
input = fetch(input);
|
||||
}
|
||||
|
||||
wasm = await load(await input).then((wasm) => Module({ wasm }));
|
||||
assert_init = () => {};
|
||||
}
|
||||
|
||||
function assert_init() {
|
||||
throw new Error("uninit");
|
||||
}
|
||||
|
||||
export function version() {
|
||||
assert_init();
|
||||
return wasm.version();
|
||||
}
|
||||
|
||||
export function set_fallback_style(style) {
|
||||
assert_init();
|
||||
wasm.set_fallback_style(style);
|
||||
}
|
||||
|
||||
export function set_sort_includes(sort) {
|
||||
assert_init();
|
||||
wasm.set_sort_includes(sort);
|
||||
}
|
||||
|
||||
function unwrap(result) {
|
||||
const { error, content } = result;
|
||||
if (error) {
|
||||
throw Error(content);
|
||||
}
|
||||
return content;
|
||||
}
|
||||
|
||||
export function format(content, filename = "<stdin>", style = "LLVM") {
|
||||
assert_init();
|
||||
const result = wasm.format(content, filename, style);
|
||||
return unwrap(result);
|
||||
}
|
||||
|
||||
export function format_line_range(
|
||||
content,
|
||||
range,
|
||||
filename = "<stdin>",
|
||||
style = "LLVM",
|
||||
) {
|
||||
assert_init();
|
||||
const rangeList = new wasm.RangeList();
|
||||
for (const [fromLine, toLine] of range) {
|
||||
if (fromLine < 1) {
|
||||
throw Error("start line should be at least 1");
|
||||
}
|
||||
if (fromLine > toLine) {
|
||||
throw Error("start line should not exceed end line");
|
||||
}
|
||||
rangeList.push_back(fromLine);
|
||||
rangeList.push_back(toLine);
|
||||
}
|
||||
|
||||
const result = wasm.format_line(content, filename, style, rangeList);
|
||||
rangeList.delete();
|
||||
return unwrap(result);
|
||||
}
|
||||
|
||||
export function format_byte_range(
|
||||
content,
|
||||
range,
|
||||
filename = "<stdin>",
|
||||
style = "LLVM",
|
||||
) {
|
||||
assert_init();
|
||||
const rangeList = new wasm.RangeList();
|
||||
|
||||
if (range.length === 1 && range[0].length === 1) {
|
||||
rangeList.push_back(range[0][0]);
|
||||
} else {
|
||||
for (const [offset, length] of range) {
|
||||
if (offset < 0) {
|
||||
throw Error("start offset should be at least 0");
|
||||
}
|
||||
if (length < 0) {
|
||||
throw Error("length should be at least 0");
|
||||
}
|
||||
rangeList.push_back(offset);
|
||||
rangeList.push_back(length);
|
||||
}
|
||||
}
|
||||
|
||||
const result = wasm.format_byte(content, filename, style, rangeList);
|
||||
rangeList.delete();
|
||||
return unwrap(result);
|
||||
}
|
||||
|
||||
export function dump_config({
|
||||
style = "file",
|
||||
filename = "<stdin>",
|
||||
code = "",
|
||||
} = {}) {
|
||||
assert_init();
|
||||
const result = wasm.dump_config(style, filename, code);
|
||||
return unwrap(result);
|
||||
}
|
||||
|
||||
export {
|
||||
format_byte_range as formatByteRange,
|
||||
format_line_range as formatLineRange,
|
||||
};
|
||||
42
frontend/src/common/prettier/plugins/go/build-tinygo.bat
Normal file
42
frontend/src/common/prettier/plugins/go/build-tinygo.bat
Normal file
@@ -0,0 +1,42 @@
|
||||
@echo off
|
||||
rem Build script for Go Prettier Plugin WASM using TinyGo
|
||||
rem This script compiles the Go code to WebAssembly for browser environment
|
||||
|
||||
echo Building Go Prettier Plugin WASM with TinyGo...
|
||||
|
||||
rem Check if TinyGo is available
|
||||
tinygo version >nul 2>&1
|
||||
if errorlevel 1 (
|
||||
echo TinyGo not found! Please install TinyGo first.
|
||||
echo Visit: https://tinygo.org/getting-started/install/
|
||||
pause
|
||||
exit /b 1
|
||||
)
|
||||
|
||||
rem Display TinyGo version
|
||||
echo Using TinyGo version:
|
||||
tinygo version
|
||||
|
||||
rem Build the WASM file using TinyGo
|
||||
echo Compiling main.go to go.wasm with TinyGo...
|
||||
tinygo build -o go-format.wasm -target wasm main.go
|
||||
if errorlevel 1 (
|
||||
echo Build failed!
|
||||
pause
|
||||
exit /b 1
|
||||
)
|
||||
|
||||
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
|
||||
del go.wasm
|
||||
echo Cleaned up local WASM file
|
||||
)
|
||||
|
||||
echo Go Prettier Plugin WASM (TinyGo) is ready!
|
||||
38
frontend/src/common/prettier/plugins/go/build-tinygo.sh
Normal file
38
frontend/src/common/prettier/plugins/go/build-tinygo.sh
Normal file
@@ -0,0 +1,38 @@
|
||||
#!/bin/bash
|
||||
|
||||
# Build script for Go Prettier Plugin WASM using TinyGo
|
||||
# This script compiles the Go code to WebAssembly for browser environment
|
||||
|
||||
echo "Building Go Prettier Plugin WASM with TinyGo..."
|
||||
|
||||
# Check if TinyGo is available
|
||||
if ! command -v tinygo &> /dev/null; then
|
||||
echo "TinyGo not found! Please install TinyGo first."
|
||||
echo "Visit: https://tinygo.org/getting-started/install/"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Display TinyGo version
|
||||
echo "Using TinyGo version: $(tinygo version)"
|
||||
|
||||
# Build the WASM file using TinyGo
|
||||
echo "Compiling main.go to go.wasm with TinyGo..."
|
||||
tinygo build -o go-format.wasm -target wasm main.go
|
||||
|
||||
if [ $? -ne 0 ]; then
|
||||
echo "Build failed!"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "Build successful!"
|
||||
echo "WASM file size: $(du -h go-format.wasm | cut -f1)"
|
||||
|
||||
# Copy to public directory for browser access
|
||||
if [ -d "../../../../../public" ]; then
|
||||
cp go-format.wasm ../../../../../public/go-format.wasm
|
||||
echo "Copied to public directory"
|
||||
rm go-format.wasm
|
||||
echo "Cleaned up local WASM file"
|
||||
fi
|
||||
|
||||
echo "Go Prettier Plugin WASM (TinyGo) is ready!"
|
||||
43
frontend/src/common/prettier/plugins/go/build.bat
Normal file
43
frontend/src/common/prettier/plugins/go/build.bat
Normal file
@@ -0,0 +1,43 @@
|
||||
@echo off
|
||||
rem Build script for Go Prettier Plugin WASM using native Go
|
||||
rem This script compiles the Go code to WebAssembly for browser environment
|
||||
|
||||
echo Building Go Prettier Plugin WASM with native Go...
|
||||
|
||||
rem Check if Go is available
|
||||
go version >nul 2>&1
|
||||
if %ERRORLEVEL% NEQ 0 (
|
||||
echo Go not found! Please install Go 1.21+ first.
|
||||
echo Visit: https://golang.org/dl/
|
||||
pause
|
||||
exit /b 1
|
||||
)
|
||||
|
||||
rem Set WASM build environment for browser (js/wasm)
|
||||
set GOOS=js
|
||||
set GOARCH=wasm
|
||||
|
||||
rem Build the WASM file using native Go
|
||||
echo Compiling main.go to go.wasm with Go...
|
||||
go build -o go-format.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
|
||||
del go.wasm
|
||||
echo Cleaned up local WASM file
|
||||
)
|
||||
|
||||
echo Go Prettier Plugin WASM is ready!
|
||||
) else (
|
||||
echo Build failed!
|
||||
pause
|
||||
exit /b 1
|
||||
)
|
||||
42
frontend/src/common/prettier/plugins/go/build.sh
Normal file
42
frontend/src/common/prettier/plugins/go/build.sh
Normal file
@@ -0,0 +1,42 @@
|
||||
#!/bin/bash
|
||||
|
||||
# Build script for Go Prettier Plugin WASM using native Go
|
||||
# This script compiles the Go code to WebAssembly for browser environment
|
||||
|
||||
echo "Building Go Prettier Plugin WASM with native Go..."
|
||||
|
||||
# Check if Go is available
|
||||
if ! command -v go &> /dev/null; then
|
||||
echo "Go not found! Please install Go 1.21+ first."
|
||||
echo "Visit: https://golang.org/dl/"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Display Go version
|
||||
echo "Using Go version: $(go version)"
|
||||
|
||||
# Set WASM build environment for browser (js/wasm)
|
||||
export GOOS=js
|
||||
export GOARCH=wasm
|
||||
|
||||
# Build the WASM file using native Go
|
||||
echo "Compiling main.go to go.wasm with Go..."
|
||||
go build -o go-format.wasm main.go
|
||||
|
||||
if [ $? -eq 0 ]; then
|
||||
echo "Build successful!"
|
||||
echo "WASM file size: $(du -h go-format.wasm | cut -f1)"
|
||||
|
||||
# Copy to public directory for browser access
|
||||
if [ -d "../../../../../public" ]; then
|
||||
cp go-format.wasm ../../../../../public/go-format.wasm
|
||||
echo "Copied to public directory"
|
||||
rm go-format.wasm
|
||||
echo "Cleaned up local WASM file"
|
||||
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;
|
||||
142
frontend/src/common/prettier/plugins/go/go.mjs
Normal file
142
frontend/src/common/prettier/plugins/go/go.mjs
Normal file
@@ -0,0 +1,142 @@
|
||||
/**
|
||||
* @fileoverview Go Prettier Format Plugin
|
||||
* A Prettier plugin for formatting Go code using WebAssembly.
|
||||
* This plugin leverages Go's native formatting capabilities through WASM.
|
||||
*/
|
||||
import "./wasm_exec.js"
|
||||
/** @type {Promise<void>|null} */
|
||||
let initializePromise;
|
||||
|
||||
/**
|
||||
* Initializes the Go WebAssembly module for formatting Go code.
|
||||
* This function sets up the WASM runtime and makes the formatGo function
|
||||
* available on the global object.
|
||||
*
|
||||
* @async
|
||||
* @function initialize
|
||||
* @returns {Promise<void>} A promise that resolves when the WASM module is ready
|
||||
* @throws {Error} If the WASM file cannot be loaded or instantiated
|
||||
*/
|
||||
function initialize() {
|
||||
if (initializePromise) {
|
||||
return initializePromise;
|
||||
}
|
||||
|
||||
initializePromise = (async () => {
|
||||
|
||||
const go = new TinyGo();
|
||||
|
||||
// Load WASM file from browser
|
||||
const response = await fetch('/go-format.wasm');
|
||||
if (!response.ok) {
|
||||
throw new Error(`Failed to load WASM file: ${response.status} ${response.statusText}`);
|
||||
}
|
||||
const wasmBuffer = await response.arrayBuffer();
|
||||
|
||||
const { instance } = await WebAssembly.instantiate(
|
||||
wasmBuffer,
|
||||
go.importObject
|
||||
);
|
||||
|
||||
// go.run returns a promise that resolves when the go program exits.
|
||||
// Since our program is a long-running service (it exposes a function and waits),
|
||||
// we don't await it.
|
||||
go.run(instance);
|
||||
|
||||
// The `formatGo` function is now available on the global object.
|
||||
})();
|
||||
|
||||
return initializePromise;
|
||||
}
|
||||
|
||||
/**
|
||||
* Prettier language configuration for Go.
|
||||
* Defines the language settings, file extensions, and parser mappings.
|
||||
*
|
||||
* @type {Array<Object>}
|
||||
* @property {string} name - The display name of the language
|
||||
* @property {string[]} parsers - Array of parser names for this language
|
||||
* @property {string[]} extensions - File extensions associated with this language
|
||||
* @property {string[]} vscodeLanguageIds - VSCode language identifier mappings
|
||||
*/
|
||||
const languages = [
|
||||
{
|
||||
name: "Go",
|
||||
parsers: ["go-format"],
|
||||
extensions: [".go"],
|
||||
vscodeLanguageIds: ["go"],
|
||||
},
|
||||
];
|
||||
|
||||
/**
|
||||
* Prettier parser configuration for Go.
|
||||
* Defines how Go source code should be parsed and processed.
|
||||
*
|
||||
* @type {Object<string, Object>}
|
||||
* @property {Object} go-format - Go language parser configuration
|
||||
* @property {Function} go-format.parse - Parser function that returns the input text as-is
|
||||
* @property {string} go-format.astFormat - AST format identifier for the printer
|
||||
* @property {Function} go-format.locStart - Function to get the start location of a node
|
||||
* @property {Function} go-format.locEnd - Function to get the end location of a node
|
||||
*/
|
||||
const parsers = {
|
||||
"go-format": {
|
||||
/**
|
||||
* Parse Go source code. For this plugin, we pass through the text as-is
|
||||
* since the actual formatting is handled by the Go WASM module.
|
||||
*
|
||||
* @param {string} text - The Go source code to parse
|
||||
* @returns {string} The input text unchanged
|
||||
*/
|
||||
parse: (text) => text,
|
||||
astFormat: "go-format",
|
||||
// These are required for Prettier to work
|
||||
/**
|
||||
* Get the start location of a node in the source code.
|
||||
*
|
||||
* @param {string} node - The node (in this case, the source text)
|
||||
* @returns {number} Always returns 0 as we treat the entire text as one node
|
||||
*/
|
||||
locStart: (node) => 0,
|
||||
/**
|
||||
* Get the end location of a node in the source code.
|
||||
*
|
||||
* @param {string} node - The node (in this case, the source text)
|
||||
* @returns {number} The length of the text
|
||||
*/
|
||||
locEnd: (node) => node.length,
|
||||
},
|
||||
};
|
||||
|
||||
/**
|
||||
* Prettier printer configuration for Go.
|
||||
* Defines how the parsed Go AST should be formatted back to text.
|
||||
*
|
||||
* @type {Object<string, Object>}
|
||||
* @property {Object} go-format - Go formatting printer configuration
|
||||
* @property {Function} go-format.print - Async function that formats Go code
|
||||
*/
|
||||
const printers = {
|
||||
"go-format": {
|
||||
/**
|
||||
* Format Go source code using the WebAssembly Go formatter.
|
||||
* This function initializes the WASM module if needed and calls the
|
||||
* global formatGo function exposed by the Go program.
|
||||
*
|
||||
* @async
|
||||
* @param {Object} path - Prettier's path object containing the source code
|
||||
* @param {Function} path.getValue - Function to get the current node value
|
||||
* @returns {Promise<string>} The formatted Go source code
|
||||
* @throws {Error} If the WASM module fails to initialize or format the code
|
||||
*/
|
||||
print: async (path) => {
|
||||
// The WASM module must be initialized before we can format.
|
||||
await initialize();
|
||||
const text = path.getValue();
|
||||
// The `formatGo` function is exposed on the global object by our Go program.
|
||||
return globalThis.formatGo(text);
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
export default { languages, parsers, printers, initialize };
|
||||
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 using native Go (GOOS=js GOARCH=wasm)
|
||||
// and loaded in browser environments as part of the Go Prettier 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
|
||||
}
|
||||
553
frontend/src/common/prettier/plugins/go/wasm_exec.js
Normal file
553
frontend/src/common/prettier/plugins/go/wasm_exec.js
Normal file
@@ -0,0 +1,553 @@
|
||||
// Copyright 2018 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
//
|
||||
// This file has been modified for use by the TinyGo compiler.
|
||||
|
||||
(() => {
|
||||
// Map multiple JavaScript environments to a single common API,
|
||||
// preferring web standards over Node.js API.
|
||||
//
|
||||
// Environments considered:
|
||||
// - Browsers
|
||||
// - Node.js
|
||||
// - Electron
|
||||
// - Parcel
|
||||
|
||||
if (typeof global !== "undefined") {
|
||||
// global already exists
|
||||
} else if (typeof window !== "undefined") {
|
||||
window.global = window;
|
||||
} else if (typeof self !== "undefined") {
|
||||
self.global = self;
|
||||
} else {
|
||||
throw new Error("cannot export Go (neither global, window nor self is defined)");
|
||||
}
|
||||
|
||||
if (!global.require && typeof require !== "undefined") {
|
||||
global.require = require;
|
||||
}
|
||||
|
||||
if (!global.fs && global.require) {
|
||||
global.fs = require("node:fs");
|
||||
}
|
||||
|
||||
const enosys = () => {
|
||||
const err = new Error("not implemented");
|
||||
err.code = "ENOSYS";
|
||||
return err;
|
||||
};
|
||||
|
||||
if (!global.fs) {
|
||||
let outputBuf = "";
|
||||
global.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.substr(0, nl));
|
||||
outputBuf = outputBuf.substr(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 (!global.process) {
|
||||
global.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 (!global.crypto) {
|
||||
const nodeCrypto = require("node:crypto");
|
||||
global.crypto = {
|
||||
getRandomValues(b) {
|
||||
nodeCrypto.randomFillSync(b);
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
if (!global.performance) {
|
||||
global.performance = {
|
||||
now() {
|
||||
const [sec, nsec] = process.hrtime();
|
||||
return sec * 1000 + nsec / 1000000;
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
if (!global.TextEncoder) {
|
||||
global.TextEncoder = require("node:util").TextEncoder;
|
||||
}
|
||||
|
||||
if (!global.TextDecoder) {
|
||||
global.TextDecoder = require("node:util").TextDecoder;
|
||||
}
|
||||
|
||||
// End of polyfills for common API.
|
||||
|
||||
const encoder = new TextEncoder("utf-8");
|
||||
const decoder = new TextDecoder("utf-8");
|
||||
let reinterpretBuf = new DataView(new ArrayBuffer(8));
|
||||
var logLine = [];
|
||||
const wasmExit = {}; // thrown to exit via proc_exit (not an error)
|
||||
|
||||
global.TinyGo = class {
|
||||
constructor() {
|
||||
this._callbackTimeouts = new Map();
|
||||
this._nextCallbackTimeoutID = 1;
|
||||
|
||||
const mem = () => {
|
||||
// The buffer may change when requesting more memory.
|
||||
return new DataView(this._inst.exports.memory.buffer);
|
||||
}
|
||||
|
||||
const unboxValue = (v_ref) => {
|
||||
reinterpretBuf.setBigInt64(0, v_ref, true);
|
||||
const f = reinterpretBuf.getFloat64(0, true);
|
||||
if (f === 0) {
|
||||
return undefined;
|
||||
}
|
||||
if (!isNaN(f)) {
|
||||
return f;
|
||||
}
|
||||
|
||||
const id = v_ref & 0xffffffffn;
|
||||
return this._values[id];
|
||||
}
|
||||
|
||||
|
||||
const loadValue = (addr) => {
|
||||
let v_ref = mem().getBigUint64(addr, true);
|
||||
return unboxValue(v_ref);
|
||||
}
|
||||
|
||||
const boxValue = (v) => {
|
||||
const nanHead = 0x7FF80000n;
|
||||
|
||||
if (typeof v === "number") {
|
||||
if (isNaN(v)) {
|
||||
return nanHead << 32n;
|
||||
}
|
||||
if (v === 0) {
|
||||
return (nanHead << 32n) | 1n;
|
||||
}
|
||||
reinterpretBuf.setFloat64(0, v, true);
|
||||
return reinterpretBuf.getBigInt64(0, true);
|
||||
}
|
||||
|
||||
switch (v) {
|
||||
case undefined:
|
||||
return 0n;
|
||||
case null:
|
||||
return (nanHead << 32n) | 2n;
|
||||
case true:
|
||||
return (nanHead << 32n) | 3n;
|
||||
case false:
|
||||
return (nanHead << 32n) | 4n;
|
||||
}
|
||||
|
||||
let id = this._ids.get(v);
|
||||
if (id === undefined) {
|
||||
id = this._idPool.pop();
|
||||
if (id === undefined) {
|
||||
id = BigInt(this._values.length);
|
||||
}
|
||||
this._values[id] = v;
|
||||
this._goRefCounts[id] = 0;
|
||||
this._ids.set(v, id);
|
||||
}
|
||||
this._goRefCounts[id]++;
|
||||
let typeFlag = 1n;
|
||||
switch (typeof v) {
|
||||
case "string":
|
||||
typeFlag = 2n;
|
||||
break;
|
||||
case "symbol":
|
||||
typeFlag = 3n;
|
||||
break;
|
||||
case "function":
|
||||
typeFlag = 4n;
|
||||
break;
|
||||
}
|
||||
return id | ((nanHead | typeFlag) << 32n);
|
||||
}
|
||||
|
||||
const storeValue = (addr, v) => {
|
||||
let v_ref = boxValue(v);
|
||||
mem().setBigUint64(addr, v_ref, true);
|
||||
}
|
||||
|
||||
const loadSlice = (array, len, cap) => {
|
||||
return new Uint8Array(this._inst.exports.memory.buffer, array, len);
|
||||
}
|
||||
|
||||
const loadSliceOfValues = (array, len, cap) => {
|
||||
const a = new Array(len);
|
||||
for (let i = 0; i < len; i++) {
|
||||
a[i] = loadValue(array + i * 8);
|
||||
}
|
||||
return a;
|
||||
}
|
||||
|
||||
const loadString = (ptr, len) => {
|
||||
return decoder.decode(new DataView(this._inst.exports.memory.buffer, ptr, len));
|
||||
}
|
||||
|
||||
const timeOrigin = Date.now() - performance.now();
|
||||
this.importObject = {
|
||||
wasi_snapshot_preview1: {
|
||||
// https://github.com/WebAssembly/WASI/blob/main/phases/snapshot/docs.md#fd_write
|
||||
fd_write: function(fd, iovs_ptr, iovs_len, nwritten_ptr) {
|
||||
let nwritten = 0;
|
||||
if (fd == 1) {
|
||||
for (let iovs_i=0; iovs_i<iovs_len;iovs_i++) {
|
||||
let iov_ptr = iovs_ptr+iovs_i*8; // assuming wasm32
|
||||
let ptr = mem().getUint32(iov_ptr + 0, true);
|
||||
let len = mem().getUint32(iov_ptr + 4, true);
|
||||
nwritten += len;
|
||||
for (let i=0; i<len; i++) {
|
||||
let c = mem().getUint8(ptr+i);
|
||||
if (c == 13) { // CR
|
||||
// ignore
|
||||
} else if (c == 10) { // LF
|
||||
// write line
|
||||
let line = decoder.decode(new Uint8Array(logLine));
|
||||
logLine = [];
|
||||
console.log(line);
|
||||
} else {
|
||||
logLine.push(c);
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
console.error('invalid file descriptor:', fd);
|
||||
}
|
||||
mem().setUint32(nwritten_ptr, nwritten, true);
|
||||
return 0;
|
||||
},
|
||||
fd_close: () => 0, // dummy
|
||||
fd_fdstat_get: () => 0, // dummy
|
||||
fd_seek: () => 0, // dummy
|
||||
proc_exit: (code) => {
|
||||
this.exited = true;
|
||||
this.exitCode = code;
|
||||
this._resolveExitPromise();
|
||||
throw wasmExit;
|
||||
},
|
||||
random_get: (bufPtr, bufLen) => {
|
||||
crypto.getRandomValues(loadSlice(bufPtr, bufLen));
|
||||
return 0;
|
||||
},
|
||||
},
|
||||
gojs: {
|
||||
// func ticks() int64
|
||||
"runtime.ticks": () => {
|
||||
return BigInt((timeOrigin + performance.now()) * 1e6);
|
||||
},
|
||||
|
||||
// func sleepTicks(timeout int64)
|
||||
"runtime.sleepTicks": (timeout) => {
|
||||
// Do not sleep, only reactivate scheduler after the given timeout.
|
||||
setTimeout(() => {
|
||||
if (this.exited) return;
|
||||
try {
|
||||
this._inst.exports.go_scheduler();
|
||||
} catch (e) {
|
||||
if (e !== wasmExit) throw e;
|
||||
}
|
||||
}, Number(timeout)/1e6);
|
||||
},
|
||||
|
||||
// func finalizeRef(v ref)
|
||||
"syscall/js.finalizeRef": (v_ref) => {
|
||||
// Note: TinyGo does not support finalizers so this is only called
|
||||
// for one specific case, by js.go:jsString. and can/might leak memory.
|
||||
const id = v_ref & 0xffffffffn;
|
||||
if (this._goRefCounts?.[id] !== undefined) {
|
||||
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);
|
||||
}
|
||||
} else {
|
||||
console.error("syscall/js.finalizeRef: unknown id", id);
|
||||
}
|
||||
},
|
||||
|
||||
// func stringVal(value string) ref
|
||||
"syscall/js.stringVal": (value_ptr, value_len) => {
|
||||
value_ptr >>>= 0;
|
||||
const s = loadString(value_ptr, value_len);
|
||||
return boxValue(s);
|
||||
},
|
||||
|
||||
// func valueGet(v ref, p string) ref
|
||||
"syscall/js.valueGet": (v_ref, p_ptr, p_len) => {
|
||||
let prop = loadString(p_ptr, p_len);
|
||||
let v = unboxValue(v_ref);
|
||||
let result = Reflect.get(v, prop);
|
||||
return boxValue(result);
|
||||
},
|
||||
|
||||
// func valueSet(v ref, p string, x ref)
|
||||
"syscall/js.valueSet": (v_ref, p_ptr, p_len, x_ref) => {
|
||||
const v = unboxValue(v_ref);
|
||||
const p = loadString(p_ptr, p_len);
|
||||
const x = unboxValue(x_ref);
|
||||
Reflect.set(v, p, x);
|
||||
},
|
||||
|
||||
// func valueDelete(v ref, p string)
|
||||
"syscall/js.valueDelete": (v_ref, p_ptr, p_len) => {
|
||||
const v = unboxValue(v_ref);
|
||||
const p = loadString(p_ptr, p_len);
|
||||
Reflect.deleteProperty(v, p);
|
||||
},
|
||||
|
||||
// func valueIndex(v ref, i int) ref
|
||||
"syscall/js.valueIndex": (v_ref, i) => {
|
||||
return boxValue(Reflect.get(unboxValue(v_ref), i));
|
||||
},
|
||||
|
||||
// valueSetIndex(v ref, i int, x ref)
|
||||
"syscall/js.valueSetIndex": (v_ref, i, x_ref) => {
|
||||
Reflect.set(unboxValue(v_ref), i, unboxValue(x_ref));
|
||||
},
|
||||
|
||||
// func valueCall(v ref, m string, args []ref) (ref, bool)
|
||||
"syscall/js.valueCall": (ret_addr, v_ref, m_ptr, m_len, args_ptr, args_len, args_cap) => {
|
||||
const v = unboxValue(v_ref);
|
||||
const name = loadString(m_ptr, m_len);
|
||||
const args = loadSliceOfValues(args_ptr, args_len, args_cap);
|
||||
try {
|
||||
const m = Reflect.get(v, name);
|
||||
storeValue(ret_addr, Reflect.apply(m, v, args));
|
||||
mem().setUint8(ret_addr + 8, 1);
|
||||
} catch (err) {
|
||||
storeValue(ret_addr, err);
|
||||
mem().setUint8(ret_addr + 8, 0);
|
||||
}
|
||||
},
|
||||
|
||||
// func valueInvoke(v ref, args []ref) (ref, bool)
|
||||
"syscall/js.valueInvoke": (ret_addr, v_ref, args_ptr, args_len, args_cap) => {
|
||||
try {
|
||||
const v = unboxValue(v_ref);
|
||||
const args = loadSliceOfValues(args_ptr, args_len, args_cap);
|
||||
storeValue(ret_addr, Reflect.apply(v, undefined, args));
|
||||
mem().setUint8(ret_addr + 8, 1);
|
||||
} catch (err) {
|
||||
storeValue(ret_addr, err);
|
||||
mem().setUint8(ret_addr + 8, 0);
|
||||
}
|
||||
},
|
||||
|
||||
// func valueNew(v ref, args []ref) (ref, bool)
|
||||
"syscall/js.valueNew": (ret_addr, v_ref, args_ptr, args_len, args_cap) => {
|
||||
const v = unboxValue(v_ref);
|
||||
const args = loadSliceOfValues(args_ptr, args_len, args_cap);
|
||||
try {
|
||||
storeValue(ret_addr, Reflect.construct(v, args));
|
||||
mem().setUint8(ret_addr + 8, 1);
|
||||
} catch (err) {
|
||||
storeValue(ret_addr, err);
|
||||
mem().setUint8(ret_addr+ 8, 0);
|
||||
}
|
||||
},
|
||||
|
||||
// func valueLength(v ref) int
|
||||
"syscall/js.valueLength": (v_ref) => {
|
||||
return unboxValue(v_ref).length;
|
||||
},
|
||||
|
||||
// valuePrepareString(v ref) (ref, int)
|
||||
"syscall/js.valuePrepareString": (ret_addr, v_ref) => {
|
||||
const s = String(unboxValue(v_ref));
|
||||
const str = encoder.encode(s);
|
||||
storeValue(ret_addr, str);
|
||||
mem().setInt32(ret_addr + 8, str.length, true);
|
||||
},
|
||||
|
||||
// valueLoadString(v ref, b []byte)
|
||||
"syscall/js.valueLoadString": (v_ref, slice_ptr, slice_len, slice_cap) => {
|
||||
const str = unboxValue(v_ref);
|
||||
loadSlice(slice_ptr, slice_len, slice_cap).set(str);
|
||||
},
|
||||
|
||||
// func valueInstanceOf(v ref, t ref) bool
|
||||
"syscall/js.valueInstanceOf": (v_ref, t_ref) => {
|
||||
return unboxValue(v_ref) instanceof unboxValue(t_ref);
|
||||
},
|
||||
|
||||
// func copyBytesToGo(dst []byte, src ref) (int, bool)
|
||||
"syscall/js.copyBytesToGo": (ret_addr, dest_addr, dest_len, dest_cap, src_ref) => {
|
||||
let num_bytes_copied_addr = ret_addr;
|
||||
let returned_status_addr = ret_addr + 4; // Address of returned boolean status variable
|
||||
|
||||
const dst = loadSlice(dest_addr, dest_len);
|
||||
const src = unboxValue(src_ref);
|
||||
if (!(src instanceof Uint8Array || src instanceof Uint8ClampedArray)) {
|
||||
mem().setUint8(returned_status_addr, 0); // Return "not ok" status
|
||||
return;
|
||||
}
|
||||
const toCopy = src.subarray(0, dst.length);
|
||||
dst.set(toCopy);
|
||||
mem().setUint32(num_bytes_copied_addr, toCopy.length, true);
|
||||
mem().setUint8(returned_status_addr, 1); // Return "ok" status
|
||||
},
|
||||
|
||||
// copyBytesToJS(dst ref, src []byte) (int, bool)
|
||||
// Originally copied from upstream Go project, then modified:
|
||||
// https://github.com/golang/go/blob/3f995c3f3b43033013013e6c7ccc93a9b1411ca9/misc/wasm/wasm_exec.js#L404-L416
|
||||
"syscall/js.copyBytesToJS": (ret_addr, dst_ref, src_addr, src_len, src_cap) => {
|
||||
let num_bytes_copied_addr = ret_addr;
|
||||
let returned_status_addr = ret_addr + 4; // Address of returned boolean status variable
|
||||
|
||||
const dst = unboxValue(dst_ref);
|
||||
const src = loadSlice(src_addr, src_len);
|
||||
if (!(dst instanceof Uint8Array || dst instanceof Uint8ClampedArray)) {
|
||||
mem().setUint8(returned_status_addr, 0); // Return "not ok" status
|
||||
return;
|
||||
}
|
||||
const toCopy = src.subarray(0, dst.length);
|
||||
dst.set(toCopy);
|
||||
mem().setUint32(num_bytes_copied_addr, toCopy.length, true);
|
||||
mem().setUint8(returned_status_addr, 1); // Return "ok" status
|
||||
},
|
||||
}
|
||||
};
|
||||
|
||||
// Go 1.20 uses 'env'. Go 1.21 uses 'gojs'.
|
||||
// For compatibility, we use both as long as Go 1.20 is supported.
|
||||
this.importObject.env = this.importObject.gojs;
|
||||
}
|
||||
|
||||
async run(instance) {
|
||||
this._inst = instance;
|
||||
this._values = [ // JS values that Go currently has references to, indexed by reference id
|
||||
NaN,
|
||||
0,
|
||||
null,
|
||||
true,
|
||||
false,
|
||||
global,
|
||||
this,
|
||||
];
|
||||
this._goRefCounts = []; // number of references that Go has to a JS value, indexed by reference id
|
||||
this._ids = new Map(); // mapping from JS values to reference ids
|
||||
this._idPool = []; // unused ids that have been garbage collected
|
||||
this.exited = false; // whether the Go program has exited
|
||||
this.exitCode = 0;
|
||||
|
||||
if (this._inst.exports._start) {
|
||||
let exitPromise = new Promise((resolve, reject) => {
|
||||
this._resolveExitPromise = resolve;
|
||||
});
|
||||
|
||||
// Run program, but catch the wasmExit exception that's thrown
|
||||
// to return back here.
|
||||
try {
|
||||
this._inst.exports._start();
|
||||
} catch (e) {
|
||||
if (e !== wasmExit) throw e;
|
||||
}
|
||||
|
||||
await exitPromise;
|
||||
return this.exitCode;
|
||||
} else {
|
||||
this._inst.exports._initialize();
|
||||
}
|
||||
}
|
||||
|
||||
_resume() {
|
||||
if (this.exited) {
|
||||
throw new Error("Go program has already exited");
|
||||
}
|
||||
try {
|
||||
this._inst.exports.resume();
|
||||
} catch (e) {
|
||||
if (e !== wasmExit) throw e;
|
||||
}
|
||||
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;
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
if (
|
||||
global.require &&
|
||||
global.require.main === module &&
|
||||
global.process &&
|
||||
global.process.versions &&
|
||||
!global.process.versions.electron
|
||||
) {
|
||||
if (process.argv.length != 3) {
|
||||
console.error("usage: go_js_wasm_exec [wasm binary] [arguments]");
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
const go = new Go();
|
||||
WebAssembly.instantiate(fs.readFileSync(process.argv[2]), go.importObject).then(async (result) => {
|
||||
let exitCode = await go.run(result.instance);
|
||||
process.exit(exitCode);
|
||||
}).catch((err) => {
|
||||
console.error(err);
|
||||
process.exit(1);
|
||||
});
|
||||
}
|
||||
})();
|
||||
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,
|
||||
};
|
||||
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")})`;
|
||||
},
|
||||
};
|
||||
645
frontend/src/common/prettier/plugins/rust/format/styling.ts
Normal file
645
frontend/src/common/prettier/plugins/rust/format/styling.ts
Normal file
@@ -0,0 +1,645 @@
|
||||
import {
|
||||
ClosureFunctionExpression,
|
||||
ComparisonExpression,
|
||||
ConditionExpression,
|
||||
EnumDeclaration,
|
||||
EnumMemberStructDeclaration,
|
||||
ExpressionAsTypeCast,
|
||||
ExpressionNode,
|
||||
ExpressionStatement,
|
||||
ExpressionWithBody,
|
||||
LeftRightExpression,
|
||||
LogicalExpression,
|
||||
MacroDeclaration,
|
||||
MacroRulesDeclaration,
|
||||
MissingNode,
|
||||
Node,
|
||||
NodeType,
|
||||
NodeWithBody,
|
||||
NodeWithBodyOrCases,
|
||||
OperationExpression,
|
||||
PRCD,
|
||||
StructDeclaration,
|
||||
StructLiteral,
|
||||
StructPattern,
|
||||
TK,
|
||||
UnionDeclaration,
|
||||
} from "jinx-rust";
|
||||
import {
|
||||
can_have_OuterAttributes,
|
||||
getAstPath,
|
||||
getPrecedence,
|
||||
hasAttributes,
|
||||
hasBody,
|
||||
hasCondition,
|
||||
hasItems,
|
||||
hasLetScrutineeCondition,
|
||||
hasOuterAttributes,
|
||||
hasProperties,
|
||||
is_Attribute,
|
||||
is_AttributeOrDocComment,
|
||||
is_AwaitExpression,
|
||||
is_BitwiseOperator,
|
||||
is_CallExpression,
|
||||
is_ClosureFunctionExpression,
|
||||
is_ComparisonExpression,
|
||||
is_DocCommentAttribute,
|
||||
is_ElseBlock,
|
||||
is_EnumMemberDeclaration,
|
||||
is_EqualityOperator,
|
||||
is_ExpressionAsTypeCast,
|
||||
is_ExpressionStatement,
|
||||
is_ExpressionWithBody,
|
||||
is_ExpressionWithBodyOrCases,
|
||||
is_ExpressionWithBodyOrCases_or_BlockLikeMacroInvocation,
|
||||
is_FlowControlExpression,
|
||||
is_FlowControlMaybeValueExpression,
|
||||
is_ForInBlockExpression,
|
||||
is_Identifier,
|
||||
is_IfBlockExpression,
|
||||
is_ImplicitReturnAbleNode,
|
||||
is_LeftRightExpression,
|
||||
is_LetScrutinee,
|
||||
is_Literal,
|
||||
is_LiteralNumberLike,
|
||||
is_LogicalExpression,
|
||||
is_LoopBlockExpression,
|
||||
is_MatchExpression,
|
||||
is_MatchExpressionCase,
|
||||
is_MemberExpression,
|
||||
is_NodeWithBodyNoBody,
|
||||
is_NodeWithMaybePatternNoUnionBody,
|
||||
is_OperationExpression,
|
||||
is_ParenthesizedNode,
|
||||
is_PatternVariableDeclaration,
|
||||
is_PostfixExpression,
|
||||
is_RangeLiteral,
|
||||
is_ReassignmentNode,
|
||||
is_ReturnExpression,
|
||||
is_StatementNode,
|
||||
is_StructLiteral,
|
||||
is_StructLiteralProperty,
|
||||
is_StructPatternProperty,
|
||||
is_StructPropertyDeclaration,
|
||||
is_TypeBoundsStandaloneNode,
|
||||
is_TypeFunctionNode,
|
||||
is_TypeTraitBound,
|
||||
is_UnaryExpression,
|
||||
is_UnaryType,
|
||||
is_UnionPattern,
|
||||
is_WhileBlockExpression,
|
||||
is_YieldExpression,
|
||||
is_bitshiftOperator,
|
||||
is_multiplicativeOperator,
|
||||
} from "jinx-rust/utils";
|
||||
import { BlockLikeMacroInvocation, is_BlockLikeMacroInvocation, is_CallExpression_or_CallLikeMacroInvocation } from "../transform";
|
||||
import { exit, last_of } from "../utils/common";
|
||||
import { CF, hasBreaklineAfter, hasComment } from "./comments";
|
||||
import { flowControlExpressionNeedsOuterParens } from "./core";
|
||||
import { Doc, hardline, softline, willBreak } from "./external";
|
||||
import {
|
||||
assertPathAtNode,
|
||||
getContext,
|
||||
getGrandParentNode,
|
||||
getNode,
|
||||
getOptions,
|
||||
getParentNode,
|
||||
getPrintFn,
|
||||
is_printing_macro,
|
||||
pathCallAtParent,
|
||||
pathCallParentOf,
|
||||
stackIncludes,
|
||||
} from "./plugin";
|
||||
|
||||
export function needsOuterSoftbreakParens(node: Node) {
|
||||
const parent = getParentNode(node);
|
||||
|
||||
if (!parent) return false;
|
||||
|
||||
if (is_ExpressionAsTypeCast(node)) {
|
||||
return precedenceNeedsParens(node, parent);
|
||||
}
|
||||
|
||||
if (
|
||||
is_FlowControlMaybeValueExpression(parent) && //
|
||||
parent.expression === node &&
|
||||
flowControlExpressionNeedsOuterParens(parent)
|
||||
) {
|
||||
return true;
|
||||
}
|
||||
if (
|
||||
is_ExpressionWithBodyOrCases_or_BlockLikeMacroInvocation(node) &&
|
||||
(false ||
|
||||
(is_MemberExpression(parent) && parent.expression === node) ||
|
||||
(is_ExpressionWithBodyOrCases_or_BlockLikeMacroInvocation(parent) && !is_ElseBlock(node, parent)))
|
||||
) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (is_UnionPattern(node) && is_NodeWithMaybePatternNoUnionBody(parent)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (hasComment(node)) {
|
||||
if (is_UnaryExpression(parent)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (hasComment(node, CF.Line)) {
|
||||
if (is_ReturnExpression(parent) || (is_YieldExpression(parent) && parent.expression === node)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
if (
|
||||
hasComment(node, CF.Leading, (comment) => is_Attribute(comment) && !comment.inner) &&
|
||||
!can_have_OuterAttributes(node, parent, true)
|
||||
) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
export function needsInnerParens(node: Node) {
|
||||
if (needsOuterSoftbreakParens(node)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const parent = getParentNode(node);
|
||||
|
||||
if (!parent) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (is_Identifier(node)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (is_Literal(node)) {
|
||||
return is_LiteralNumberLike(node) && is_MemberExpression(parent) && node === parent.expression;
|
||||
}
|
||||
|
||||
if (is_CallExpression(parent) && parent.callee === node && is_MemberExpression(node)) {
|
||||
return !getOptions().actuallyMethodNodes.has(node);
|
||||
}
|
||||
|
||||
if (is_ReassignmentNode(node)) {
|
||||
if (is_printing_macro()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (is_ClosureFunctionExpression(parent) && node === parent.expression) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (is_ExpressionStatement(parent)) {
|
||||
return is_StructLiteral(node.left);
|
||||
}
|
||||
|
||||
if (is_ReassignmentNode(parent)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
if (is_ParenthesizedNode(parent)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (is_ExpressionStatement(parent)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (is_RangeLiteral(node)) {
|
||||
return (
|
||||
is_ExpressionAsTypeCast(parent) ||
|
||||
is_LogicalExpression(parent) ||
|
||||
is_UnaryExpression(parent) ||
|
||||
is_PostfixExpression(parent) ||
|
||||
(is_MemberExpression(parent) && node === parent.expression) ||
|
||||
(is_CallExpression(parent) && node === parent.callee) ||
|
||||
is_OperationExpression(parent) ||
|
||||
is_ComparisonExpression(parent)
|
||||
);
|
||||
}
|
||||
|
||||
if (is_LetScrutinee(parent) && is_LogicalExpression(node) && parent.expression === (node as any)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (is_UnaryExpression(node)) {
|
||||
switch (parent.nodeType) {
|
||||
case NodeType.MemberExpression:
|
||||
case NodeType.AwaitExpression:
|
||||
return node === parent.expression;
|
||||
case NodeType.CallExpression:
|
||||
return node === parent.callee;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (is_ExpressionWithBodyOrCases_or_BlockLikeMacroInvocation(node)) {
|
||||
if (is_ExpressionWithBodyOrCases(parent)) {
|
||||
return !is_ElseBlock(node, parent);
|
||||
}
|
||||
if (is_LetScrutinee(parent) && parent.expression === node && is_ExpressionWithBodyOrCases(getGrandParentNode())) {
|
||||
return true;
|
||||
}
|
||||
return (
|
||||
is_ExpressionAsTypeCast(parent) ||
|
||||
is_LogicalExpression(parent) ||
|
||||
is_UnaryExpression(parent) ||
|
||||
is_PostfixExpression(parent) ||
|
||||
(is_MemberExpression(parent) && node === parent.expression) ||
|
||||
(is_CallExpression(parent) && node === parent.callee) ||
|
||||
is_OperationExpression(parent) ||
|
||||
is_ComparisonExpression(parent) ||
|
||||
is_RangeLiteral(parent)
|
||||
);
|
||||
}
|
||||
|
||||
if (is_StructLiteral(node)) {
|
||||
if (is_ExpressionWithBodyOrCases(parent)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (is_LetScrutinee(parent) && parent.expression === node && is_ExpressionWithBodyOrCases(getGrandParentNode())) {
|
||||
return true;
|
||||
}
|
||||
if (is_UnaryExpression(parent) || is_PostfixExpression(parent) || is_MemberExpression(parent)) {
|
||||
return parent.expression === node;
|
||||
}
|
||||
if (is_CallExpression(parent)) {
|
||||
return parent.callee === node;
|
||||
}
|
||||
}
|
||||
|
||||
if (is_LogicalExpression(node) || is_OperationExpression(node) || is_ComparisonExpression(node) || is_ClosureFunctionExpression(node)) {
|
||||
return precedenceNeedsParens(node, parent);
|
||||
}
|
||||
|
||||
if (is_TypeFunctionNode(node)) {
|
||||
const gp = getGrandParentNode();
|
||||
if (node.returnType && is_TypeTraitBound(parent) && is_TypeBoundsStandaloneNode(gp) && last_of(gp.typeBounds) !== parent) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
if (is_TypeBoundsStandaloneNode(node)) {
|
||||
return (
|
||||
(is_UnaryType(parent) && node.typeBounds.length > 1) ||
|
||||
is_TypeBoundsStandaloneNode(parent) ||
|
||||
is_TypeTraitBound(parent) ||
|
||||
(is_TypeFunctionNode(parent) && parent.returnType === node)
|
||||
);
|
||||
}
|
||||
|
||||
if (is_PatternVariableDeclaration(parent)) {
|
||||
return is_UnionPattern(node);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
function precedenceNeedsParens(node: LeftRightExpression | ClosureFunctionExpression | ExpressionAsTypeCast, parent: Node) {
|
||||
if (is_UnaryExpression(parent) || is_PostfixExpression(parent)) return true;
|
||||
if (is_ReassignmentNode(parent)) return parent.left === node;
|
||||
if (is_MemberExpression(parent)) return parent.expression === node;
|
||||
if (is_CallExpression(parent)) return parent.callee === node;
|
||||
if (is_ExpressionAsTypeCast(parent)) return !is_ExpressionAsTypeCast(node);
|
||||
if (is_LogicalExpression(parent)) return is_LogicalExpression(node) ? parent.nodeType !== node.nodeType : evalPrecedence(node, parent);
|
||||
if (is_OperationExpression(parent) || is_ComparisonExpression(parent)) return evalPrecedence(node, parent);
|
||||
return false;
|
||||
function evalPrecedence(
|
||||
child: LeftRightExpression | ClosureFunctionExpression | ExpressionAsTypeCast,
|
||||
parent: ComparisonExpression | OperationExpression | LogicalExpression
|
||||
) {
|
||||
if (is_ExpressionAsTypeCast(child) || is_ClosureFunctionExpression(child)) {
|
||||
return true;
|
||||
}
|
||||
function getPrec(node, bool) {
|
||||
// if (is_EqualityOperator(node.tk)) {
|
||||
// return 11.3;
|
||||
// }
|
||||
// if (is_LargerLesserOperator(node.tk)) {
|
||||
// return 11.6;
|
||||
// }
|
||||
return getPrecedence(node, bool);
|
||||
}
|
||||
|
||||
const childPRCD = getPrec(child, is_insideScrutinee(child));
|
||||
const parentPRCD = getPrec(parent, is_insideScrutinee(parent));
|
||||
|
||||
if (parentPRCD > childPRCD) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (parentPRCD === childPRCD && parent.right === child) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (parentPRCD === childPRCD && !shouldFlatten(parent, child)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (parentPRCD < childPRCD && child.tk === TK["%"]) {
|
||||
return parentPRCD === PRCD["+-"];
|
||||
}
|
||||
|
||||
if (is_BitwiseOperator(parent.tk) || (is_BitwiseOperator(child.tk) && is_EqualityOperator(parent.tk))) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
export function shouldFlatten(parent: ExpressionNode | ConditionExpression, node: ExpressionNode | ConditionExpression) {
|
||||
if (getPrecedence(node, is_insideScrutinee(node)) !== getPrecedence(parent, is_insideScrutinee(parent))) return false;
|
||||
if (is_ComparisonExpression(parent) && is_ComparisonExpression(node)) return false;
|
||||
if (is_OperationExpression(parent) && is_OperationExpression(node)) {
|
||||
if (
|
||||
(node.tk === TK["%"] && is_multiplicativeOperator(parent.tk)) ||
|
||||
(parent.tk === TK["%"] && is_multiplicativeOperator(node.tk)) ||
|
||||
(node.tk !== parent.tk && is_multiplicativeOperator(node.tk) && is_multiplicativeOperator(parent.tk)) ||
|
||||
(is_bitshiftOperator(node.tk) && is_bitshiftOperator(parent.tk))
|
||||
)
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
export function needsParens(node: Node) {
|
||||
return needsOuterSoftbreakParens(node) || needsInnerParens(node);
|
||||
}
|
||||
|
||||
export function stmtNeedsSemi(stmt: ExpressionStatement, disregardExprType = false) {
|
||||
return pathCallParentOf(stmt, (parent) => needsSemi(parent as any, stmt, disregardExprType));
|
||||
}
|
||||
|
||||
const NoNode = { nodeType: 0 } as MissingNode;
|
||||
|
||||
export function needsSemi(parent: NodeWithBody, stmt: ExpressionStatement, disregardExprType = false) {
|
||||
const expr = disregardExprType ? NoNode : stmt.expression!;
|
||||
const hadSemi = !disregardExprType && stmt.semi;
|
||||
|
||||
return (
|
||||
!!expr &&
|
||||
(forcePreserveSemi()
|
||||
? true
|
||||
: shouldNeverSemi()
|
||||
? false
|
||||
: shouldPreserveSemi()
|
||||
? hadSemi || shouldAlwaysSemi() || canAutoCompleteSemi()
|
||||
: true)
|
||||
);
|
||||
|
||||
function forcePreserveSemi() {
|
||||
/** Rust Compiler bug (preserve optional semicolon) */
|
||||
// rust-lang/rust#70844 https://github.com/rust-lang/rust/issues/70844
|
||||
// issue#22 https://github.com/jinxdash/prettier-plugin-rust/issues/22
|
||||
return (
|
||||
hadSemi &&
|
||||
stmt === last_of(parent.body!) &&
|
||||
((is_IfBlockExpression(expr) &&
|
||||
hasLetScrutineeCondition(expr) &&
|
||||
!(is_LetScrutinee(expr.condition) && is_Identifier(expr.condition.expression))) ||
|
||||
(is_MatchExpression(expr) && !is_Identifier(expr.expression)))
|
||||
);
|
||||
}
|
||||
function shouldNeverSemi() {
|
||||
return is_ExpressionWithBodyOrCases_or_BlockLikeMacroInvocation(expr);
|
||||
}
|
||||
function shouldPreserveSemi() {
|
||||
return stmt === last_of(parent.body!) && (is_ImplicitReturnAbleNode(parent) || is_BlockLikeMacroInvocation(parent));
|
||||
}
|
||||
function shouldAlwaysSemi() {
|
||||
return is_FlowControlExpression(expr) || is_ReassignmentNode(expr);
|
||||
}
|
||||
function canAutoCompleteSemi() {
|
||||
return withPathAt(parent, function checkParent(child: NodeWithBodyOrCases): boolean {
|
||||
return pathCallParentOf(child, (parent) => {
|
||||
if (is_IfBlockExpression(parent) && parent.else === child) {
|
||||
// if ... { ... } else if { ... } ...
|
||||
// ^ ------------------------------- parent
|
||||
// ^ ----------- child
|
||||
return checkParent(parent);
|
||||
}
|
||||
if (is_ExpressionStatement(parent)) {
|
||||
// { .... { ... } ... }
|
||||
// ^ -----------------^ grandparent
|
||||
// ^ --- ^ ExpressionStatement<child>
|
||||
if (hasOuterAttributes(parent)) return false;
|
||||
return stmtNeedsSemi(parent, true);
|
||||
}
|
||||
if (is_MatchExpressionCase(parent) && parent.expression === child) {
|
||||
return pathCallParentOf(parent, checkParent);
|
||||
}
|
||||
return false;
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
export function canInlineBlockBody(node: NodeWithBodyOrCases | BlockLikeMacroInvocation): boolean {
|
||||
if (!is_ExpressionWithBody(node)) {
|
||||
return false;
|
||||
}
|
||||
const body = node.body;
|
||||
|
||||
if (body.length === 0) {
|
||||
return canInlineInlineable(node);
|
||||
}
|
||||
|
||||
if (body.length === 1) {
|
||||
const stmt = body[0];
|
||||
if (is_AttributeOrDocComment(stmt)) {
|
||||
return true;
|
||||
}
|
||||
if (is_ExpressionStatement(stmt) && !needsSemi(node, stmt)) {
|
||||
/**
|
||||
* parent ( ExpressionStatement | StructLiteralProperty | LetVariableDeclaration | ... )
|
||||
* ...
|
||||
* node {
|
||||
* expr
|
||||
* }
|
||||
* ...
|
||||
*
|
||||
*
|
||||
* Q: Can you inline "node { expr }" ?
|
||||
*/
|
||||
const expr = stmt.expression!;
|
||||
|
||||
if (
|
||||
is_FlowControlExpression(expr) || //
|
||||
is_ClosureFunctionExpression(expr) ||
|
||||
is_ExpressionWithBodyOrCases_or_BlockLikeMacroInvocation(expr)
|
||||
) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return canInlineInlineable(node);
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// function q(node: ExpressionWithBody) {
|
||||
// pathCallTopMostIfBlockExpression(node, (node) => {});
|
||||
// }
|
||||
|
||||
function canInlineInlineable(node: ExpressionWithBody) {
|
||||
if (is_ForInBlockExpression(node) || is_LoopBlockExpression(node)) {
|
||||
return false;
|
||||
}
|
||||
if (is_WhileBlockExpression(node)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
const parent = getParentNode(node)!;
|
||||
|
||||
if (
|
||||
is_ExpressionStatement(parent) &&
|
||||
(!is_ImplicitReturnAbleNode(node) || pathCallAtParent(parent, (parent) => stmtNeedsSemi(parent, true)))
|
||||
) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (is_ElseBlock(node, parent)) {
|
||||
return pathCallAtParent(parent, canInlineBlockBody);
|
||||
}
|
||||
// if (is_CaseBlock(node, parent)) {
|
||||
// return false;
|
||||
// }
|
||||
if (is_IfBlockExpression(node)) {
|
||||
if (
|
||||
!node.else ||
|
||||
// hasLetScrutineeCondition(node) ||
|
||||
is_ExpressionWithBodyOrCases_or_BlockLikeMacroInvocation(node.condition) ||
|
||||
willBreak(getPrintFn(node)("condition"))
|
||||
) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const grandparent = getGrandParentNode();
|
||||
if (is_ExpressionStatement(parent) && hasBody(grandparent) && grandparent.body.length > 1) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
return (
|
||||
is_CallExpression_or_CallLikeMacroInvocation(parent) ||
|
||||
hasItems(parent) ||
|
||||
hasProperties(parent) ||
|
||||
is_ClosureFunctionExpression(parent) ||
|
||||
is_MemberExpression(parent) ||
|
||||
is_AwaitExpression(parent) ||
|
||||
is_LeftRightExpression(parent)
|
||||
);
|
||||
}
|
||||
|
||||
type NodeWithBracketContent =
|
||||
| NodeWithBodyOrCases
|
||||
| BlockLikeMacroInvocation
|
||||
| EnumDeclaration
|
||||
| StructDeclaration
|
||||
| StructLiteral
|
||||
| StructPattern
|
||||
| EnumMemberStructDeclaration
|
||||
| UnionDeclaration
|
||||
| MacroRulesDeclaration
|
||||
| MacroDeclaration;
|
||||
|
||||
export function emptyContent(node: NodeWithBracketContent): Doc {
|
||||
switch (node.nodeType) {
|
||||
case NodeType.Program:
|
||||
case NodeType.MacroRulesDeclaration:
|
||||
case NodeType.MacroDeclaration:
|
||||
case NodeType.ExternBlockDeclaration:
|
||||
case NodeType.ModuleDeclaration:
|
||||
case NodeType.TraitDeclaration:
|
||||
case NodeType.StructDeclaration:
|
||||
case NodeType.MacroInvocation:
|
||||
case NodeType.FunctionDeclaration:
|
||||
case NodeType.ImplDeclaration:
|
||||
case NodeType.UnionDeclaration:
|
||||
case NodeType.EnumDeclaration:
|
||||
case NodeType.EnumMemberStructDeclaration:
|
||||
case NodeType.StructLiteral:
|
||||
case NodeType.StructPattern:
|
||||
// case NodeType.MatchExpression:
|
||||
return "";
|
||||
case NodeType.BlockExpression:
|
||||
case NodeType.WhileBlockExpression:
|
||||
case NodeType.ForInBlockExpression:
|
||||
case NodeType.TryBlockExpression:
|
||||
case NodeType.IfBlockExpression:
|
||||
return canInlineInlineable(node)
|
||||
? is_IfBlockExpression(node) || is_ElseBlock(node, getParentNode()!)
|
||||
? softline
|
||||
: ""
|
||||
: hardline;
|
||||
case NodeType.LoopBlockExpression:
|
||||
case NodeType.MatchExpression:
|
||||
return hardline;
|
||||
default:
|
||||
if (is_NodeWithBodyNoBody(node)) {
|
||||
return "";
|
||||
}
|
||||
__DEV__: exit.never(node);
|
||||
return "";
|
||||
}
|
||||
}
|
||||
|
||||
export function is_insideScrutinee(target: Node) {
|
||||
return withPathAt(target, (n) => stackIncludes("condition") && r(n));
|
||||
function r(CHILD: Node) {
|
||||
switch (CHILD.nodeType) {
|
||||
case NodeType.OrExpression:
|
||||
case NodeType.AndExpression:
|
||||
return pathCallParentOf(CHILD, (PARENT) =>
|
||||
hasCondition(PARENT) && PARENT.condition === CHILD //
|
||||
? hasLetScrutineeCondition(PARENT)
|
||||
: r(PARENT)
|
||||
);
|
||||
case NodeType.LetScrutinee:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function withPathAt<T extends Node, R>(target: T, callback: (target: T) => R): R {
|
||||
if (target === getNode()) return callback(target);
|
||||
if (target === getParentNode()) return pathCallAtParent(target, () => callback(target));
|
||||
if (stackIncludes(target)) return pathCallAtParent(getParentNode()!, () => withPathAt(target, callback));
|
||||
return getContext().path.call(() => {
|
||||
__DEV__: assertPathAtNode("withPathAt", target);
|
||||
return callback(target); // @ts-ignore
|
||||
}, ...getAstPath(getNode(), target));
|
||||
}
|
||||
export function shouldPrintOuterAttributesAbove(node: Node) {
|
||||
return (
|
||||
is_StatementNode(node) ||
|
||||
is_MatchExpressionCase(node) ||
|
||||
(hasAttributes(node) &&
|
||||
node.attributes.some(
|
||||
canInlineOuterAttribute(node)
|
||||
? (attr) => is_DocCommentAttribute(attr) || hasBreaklineAfter(attr) //
|
||||
: is_DocCommentAttribute
|
||||
))
|
||||
);
|
||||
function canInlineOuterAttribute(node: Node) {
|
||||
return (
|
||||
is_EnumMemberDeclaration(node) ||
|
||||
is_StructPropertyDeclaration(node) ||
|
||||
is_StructLiteralProperty(node) ||
|
||||
is_StructPatternProperty(node)
|
||||
);
|
||||
}
|
||||
}
|
||||
8
frontend/src/common/prettier/plugins/rust/index.ts
Normal file
8
frontend/src/common/prettier/plugins/rust/index.ts
Normal file
@@ -0,0 +1,8 @@
|
||||
import { plugin } from "./format/plugin";
|
||||
|
||||
export default plugin;
|
||||
export const languages = plugin.languages;
|
||||
export const parsers = plugin.parsers;
|
||||
export const printers = plugin.printers;
|
||||
export const options = plugin.options;
|
||||
export const defaultOptions = plugin.defaultOptions;
|
||||
@@ -0,0 +1,116 @@
|
||||
import {
|
||||
AttrSegment,
|
||||
CallExpression,
|
||||
DelimKind,
|
||||
ExpressionPath,
|
||||
Identifier,
|
||||
Literal,
|
||||
LocArray,
|
||||
MacroInvocation,
|
||||
NodeType,
|
||||
PunctuationToken,
|
||||
ReassignmentExpression,
|
||||
TK,
|
||||
rs,
|
||||
} from "jinx-rust";
|
||||
import { isTK, start } from "jinx-rust/utils";
|
||||
import { assert, exit } from "../../utils/common";
|
||||
import { isIdent } from "./utils";
|
||||
|
||||
type SimpleAttrItem =
|
||||
| Identifier //
|
||||
| Literal
|
||||
| ExpressionPath
|
||||
| CallExpression
|
||||
| ReassignmentExpression
|
||||
| MacroInvocation;
|
||||
|
||||
export function transform_simpleAttrSyntax(segments: MacroInvocation["segments"]) {
|
||||
assert(segments.length !== 0, segments.loc.url());
|
||||
return transform_segments(segments, false);
|
||||
|
||||
function transform_segments<N extends boolean>(
|
||||
seq: LocArray<AttrSegment>,
|
||||
nestedCall: N
|
||||
): N extends true ? LocArray<SimpleAttrItem, "()"> : SimpleAttrItem {
|
||||
let i = 0;
|
||||
|
||||
if (nestedCall) {
|
||||
const args = rs.createLocArray<SimpleAttrItem, any>(DelimKind["()"], seq.loc.clone());
|
||||
while (i !== seq.length) {
|
||||
args.push(read(true));
|
||||
if (i === seq.length) break;
|
||||
assert(isTK(seq[i++], TK[","]));
|
||||
}
|
||||
return args as any;
|
||||
} else {
|
||||
const res = read(true);
|
||||
assert(i === seq.length, res.loc.url());
|
||||
return res as any;
|
||||
}
|
||||
|
||||
function read(allowEq: boolean): SimpleAttrItem {
|
||||
let lhs: Identifier | ExpressionPath;
|
||||
|
||||
switch (seq[i].nodeType) {
|
||||
case NodeType.Literal:
|
||||
return seq[i++] as Literal;
|
||||
case NodeType.Identifier:
|
||||
lhs = seq[i++] as Identifier;
|
||||
break;
|
||||
case NodeType.PunctuationToken:
|
||||
assert((seq[i] as PunctuationToken).tk === TK["::"], seq[i].loc.url());
|
||||
lhs = eatPathSegment(undefined);
|
||||
break;
|
||||
default:
|
||||
exit.never();
|
||||
}
|
||||
|
||||
while (true) {
|
||||
if (i === seq.length) return lhs;
|
||||
const seg = seq[i];
|
||||
switch (seg.nodeType) {
|
||||
case NodeType.PunctuationToken:
|
||||
switch (seg.tk) {
|
||||
case TK[","]:
|
||||
assert(nestedCall);
|
||||
return lhs;
|
||||
case TK["="]: {
|
||||
assert(allowEq);
|
||||
const right = (i++, read(false));
|
||||
return rs.mockNode(NodeType.ReassignmentExpression, right.loc.cloneFrom(start(lhs)), {
|
||||
tk: TK["="],
|
||||
kind: DelimKind["="],
|
||||
left: lhs,
|
||||
right,
|
||||
});
|
||||
}
|
||||
case TK["::"]:
|
||||
lhs = eatPathSegment(lhs);
|
||||
continue;
|
||||
default:
|
||||
exit.never();
|
||||
}
|
||||
case NodeType.DelimGroup:
|
||||
assert(seg.segments.dk === DelimKind["()"]);
|
||||
return rs.mockNode(NodeType.CallExpression, seq[i++].loc.cloneFrom(start(lhs)), {
|
||||
callee: lhs,
|
||||
typeArguments: undefined,
|
||||
method: undefined,
|
||||
arguments: transform_segments(seg.segments, true),
|
||||
});
|
||||
default:
|
||||
exit.never();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function eatPathSegment(left: undefined | Identifier | ExpressionPath) {
|
||||
const segment = seq[i + 1];
|
||||
assert(isIdent(segment));
|
||||
const res = rs.mockNode(NodeType.ExpressionPath, segment.loc.cloneFrom(start(left ?? seq[i])), { namespace: left, segment });
|
||||
i += 2;
|
||||
return res;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,92 @@
|
||||
import {
|
||||
DelimGroup,
|
||||
DelimKind,
|
||||
IfBlockExpression,
|
||||
LocArray,
|
||||
MacroInvocation,
|
||||
NodeType,
|
||||
NodeWithBody,
|
||||
rs,
|
||||
Segment,
|
||||
Snippet,
|
||||
StatementNode,
|
||||
TK,
|
||||
} from "jinx-rust";
|
||||
import { insertNodes, start, transferAttributes } from "jinx-rust/utils";
|
||||
import { assert, iLast } from "../../utils/common";
|
||||
import { isGroup, isIdent, isToken } from "./utils";
|
||||
|
||||
export function transform_macro_cfg_if(segments: MacroInvocation["segments"]) {
|
||||
const danglingAttributes: Snippet["danglingAttributes"] = [];
|
||||
const comments: Snippet["comments"] = [];
|
||||
|
||||
const block = (function create_if_block(i: number): IfBlockExpression | undefined {
|
||||
if (i >= segments.length) return undefined;
|
||||
|
||||
const _if = segments[i];
|
||||
const pound = segments[i + 1];
|
||||
const grp = segments[i + 2];
|
||||
const block = segments[i + 3];
|
||||
const _else = segments[i + 4];
|
||||
|
||||
assert(
|
||||
isIdent(_if, "if") &&
|
||||
isToken(pound, TK["#"]) &&
|
||||
isGroup(grp, DelimKind["[]"]) &&
|
||||
isGroup(block, DelimKind["{}"]) &&
|
||||
(!_else || isIdent(_else, "else"))
|
||||
);
|
||||
|
||||
return create_block(block, (body) =>
|
||||
rs.mockNode(NodeType.IfBlockExpression, block.loc.cloneFrom(start(_if)), {
|
||||
label: undefined,
|
||||
condition: rs.mockNode(NodeType.Attribute, grp.loc.cloneFrom(start(pound)), {
|
||||
segments: grp.segments,
|
||||
value: grp.segments.loc.sliceText(),
|
||||
line: false,
|
||||
inner: false,
|
||||
}) as any,
|
||||
body: body,
|
||||
else: (_else && iLast(i + 5, segments)
|
||||
? function create_else_block(i: number) {
|
||||
const block = segments[i];
|
||||
assert(isGroup(block, DelimKind["{}"]));
|
||||
return create_block(block, (body) =>
|
||||
rs.mockNode(NodeType.BlockExpression, body.loc.clone(), {
|
||||
label: undefined,
|
||||
body,
|
||||
})
|
||||
);
|
||||
}
|
||||
: create_if_block)(i + 5),
|
||||
})
|
||||
);
|
||||
})(0);
|
||||
|
||||
const ast = rs.createLocArray(
|
||||
segments.dk,
|
||||
segments.loc,
|
||||
block && [
|
||||
rs.mockNode(NodeType.ExpressionStatement, block.loc.clone(), {
|
||||
expression: block,
|
||||
semi: false,
|
||||
}),
|
||||
]
|
||||
);
|
||||
|
||||
return rs.mockNode(NodeType.Snippet, segments.loc.clone(), { ast, danglingAttributes, comments });
|
||||
|
||||
function create_block<R extends NodeWithBody>(
|
||||
group: DelimGroup<Segment> & { segments: { dk: 3 } },
|
||||
fn: (statements: LocArray<StatementNode, "{}">) => R
|
||||
): R {
|
||||
const snippet = rs.toBlockBody(group.segments);
|
||||
|
||||
insertNodes(danglingAttributes, snippet.danglingAttributes);
|
||||
insertNodes(comments, snippet.comments);
|
||||
|
||||
const block = fn(snippet.ast);
|
||||
transferAttributes(snippet, block);
|
||||
return block;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
import { DelimGroup, DelimKind, Identifier, LocArray, PunctuationToken, Segment, TK } from "jinx-rust";
|
||||
import { isTK, is_DelimGroup, is_Identifier, is_PunctuationToken } from "jinx-rust/utils";
|
||||
|
||||
export function isIdent(node: Segment | undefined, name?: string): node is Identifier {
|
||||
return !!node && is_Identifier(node) && (null == name || node.name === name);
|
||||
}
|
||||
export function isToken(node: Segment | undefined, tk?: TK): node is PunctuationToken {
|
||||
return !!node && (null == tk ? is_PunctuationToken(node) : isTK(node, tk));
|
||||
}
|
||||
export function isGroup<D extends DelimKind>(node: Segment | undefined, dk?: D): node is DelimGroup & { segments: LocArray<any, D> } {
|
||||
return !!node && is_DelimGroup(node) && (null == dk || node.segments.dk === dk);
|
||||
}
|
||||
|
||||
export function isCallLike(tk_1: Segment | undefined, tk_2: Segment | undefined): boolean {
|
||||
return !!tk_1 && !!tk_2 && is_Identifier(tk_1) && is_DelimGroup(tk_2) && tk_2.segments.dk === DelimKind["()"];
|
||||
}
|
||||
568
frontend/src/common/prettier/plugins/rust/transform/index.ts
Normal file
568
frontend/src/common/prettier/plugins/rust/transform/index.ts
Normal file
@@ -0,0 +1,568 @@
|
||||
import {
|
||||
Attribute,
|
||||
AttributeOrDocComment,
|
||||
CallExpression,
|
||||
DelimKind,
|
||||
ExpressionNode,
|
||||
LocArray,
|
||||
MacroInvocation,
|
||||
MemberExpression,
|
||||
Node,
|
||||
NodeType,
|
||||
NodeWithBodyNoBody,
|
||||
NodeWithTypeBounds,
|
||||
NTMap,
|
||||
ProgramLike,
|
||||
rs,
|
||||
Snippet,
|
||||
StatementNode,
|
||||
StructLiteral,
|
||||
StructPattern,
|
||||
TK,
|
||||
TypeBound,
|
||||
TypeBoundsStandaloneNode,
|
||||
TypeDynBounds,
|
||||
TypeTraitBound,
|
||||
} from "jinx-rust";
|
||||
import {
|
||||
countActualNodeChildren,
|
||||
deleteAttributes,
|
||||
each_childNode,
|
||||
end,
|
||||
getActualNodeChildren,
|
||||
getBodyOrCases,
|
||||
getMacroName,
|
||||
getNodeChildren,
|
||||
hasAttributes,
|
||||
hasMethod,
|
||||
hasTypeBounds,
|
||||
includesTK,
|
||||
insertNode,
|
||||
insertNodes,
|
||||
is_AttributeOrDocComment,
|
||||
is_BareTypeTraitBound,
|
||||
is_BlockExpression,
|
||||
is_CallExpression,
|
||||
is_ClosureFunctionExpression,
|
||||
is_DocCommentAttribute,
|
||||
is_ExpressionStatement,
|
||||
is_ExpressionWithBodyOrCases,
|
||||
is_FlowControlExpression,
|
||||
is_IfBlockExpression,
|
||||
is_MacroInvocation,
|
||||
is_Node,
|
||||
is_NodeWithBodyNoBody,
|
||||
is_NodeWithBodyOrCases,
|
||||
is_Program,
|
||||
is_PunctuationToken,
|
||||
is_ReassignmentNode,
|
||||
is_Snippet,
|
||||
is_TypeBoundsStandaloneNode,
|
||||
is_TypeDynBounds,
|
||||
is_TypeImplBounds,
|
||||
is_TypeTraitBound,
|
||||
ownStart,
|
||||
reassignNodeProperty,
|
||||
start,
|
||||
transferAttributes,
|
||||
unsafe_set_nodeType,
|
||||
} from "jinx-rust/utils";
|
||||
import { isPrettierIgnoreAttribute, setPrettierIgnoreTarget } from "../format/comments";
|
||||
import { is_StructSpread } from "../format/core";
|
||||
import { CustomOptions } from "../format/external";
|
||||
import { getOptions } from "../format/plugin";
|
||||
import {
|
||||
Array_replace,
|
||||
Array_splice,
|
||||
assert,
|
||||
binarySearchIn,
|
||||
each,
|
||||
exit,
|
||||
iLast,
|
||||
last_of,
|
||||
Map_get,
|
||||
spliceAll,
|
||||
try_eval,
|
||||
} from "../utils/common";
|
||||
import { transform_simpleAttrSyntax } from "./custom/attribute";
|
||||
import { transform_macro_cfg_if } from "./custom/cfg_if";
|
||||
|
||||
export interface ExpressionLikeAttribute extends Attribute {
|
||||
segments: LocArray<any, "[]">;
|
||||
}
|
||||
|
||||
export interface CallLikeMacroInvocation extends MacroInvocation {
|
||||
segments: LocArray<any, any>;
|
||||
callee: MacroInvocation["callee"];
|
||||
method: undefined;
|
||||
typeArguments: undefined;
|
||||
arguments: LocArray<ExpressionNode, "()" | "[]" | "{}">;
|
||||
}
|
||||
|
||||
export interface BlockLikeMacroInvocation extends MacroInvocation {
|
||||
segments: LocArray<any, any>;
|
||||
body: LocArray<StatementNode, "()" | "[]" | "{}">;
|
||||
attributes?: AttributeOrDocComment[];
|
||||
}
|
||||
|
||||
export function is_CallLikeMacroInvocation(node: Node): node is CallLikeMacroInvocation {
|
||||
return is_MacroInvocation(node) && "arguments" in node;
|
||||
}
|
||||
|
||||
export function is_BlockLikeMacroInvocation(node: Node): node is BlockLikeMacroInvocation {
|
||||
return is_MacroInvocation(node) && "body" in node;
|
||||
}
|
||||
|
||||
export function is_CallExpression_or_CallLikeMacroInvocation(node: any): node is CallExpression | CallLikeMacroInvocation {
|
||||
return is_CallExpression(node) || is_CallLikeMacroInvocation(node);
|
||||
}
|
||||
|
||||
const IGNORED_MACROS = new Set([
|
||||
// std
|
||||
// crates
|
||||
"quote",
|
||||
]);
|
||||
|
||||
const HARDCODED_MACRO_DELIMS = new Map<string, MacroInvocation["segments"]["dk"]>();
|
||||
each(
|
||||
{
|
||||
[DelimKind["{}"]]: [
|
||||
// std
|
||||
"thread_local",
|
||||
// crates
|
||||
"cfg_if",
|
||||
],
|
||||
[DelimKind["()"]]: [
|
||||
// std
|
||||
"assert_eq",
|
||||
"assert_ne",
|
||||
"assert",
|
||||
"cfg",
|
||||
"concat_bytes",
|
||||
"concat_idents",
|
||||
"concat",
|
||||
"debug_assert_eq",
|
||||
"debug_assert_ne",
|
||||
"debug_assert",
|
||||
"eprint",
|
||||
"eprintln",
|
||||
"format_args_nl",
|
||||
"format_args",
|
||||
"format",
|
||||
"matches",
|
||||
"panic",
|
||||
"print",
|
||||
"println",
|
||||
"try",
|
||||
"unimplemented",
|
||||
"unreachable",
|
||||
"write",
|
||||
"writeln",
|
||||
// crates
|
||||
],
|
||||
[DelimKind["[]"]]: [
|
||||
// std
|
||||
"vec",
|
||||
// crates
|
||||
],
|
||||
},
|
||||
(names, tk) =>
|
||||
each(names, (name) => {
|
||||
HARDCODED_MACRO_DELIMS.set(name, +tk as MacroInvocation["segments"]["dk"]);
|
||||
})
|
||||
);
|
||||
|
||||
let _COMMENTS: CustomOptions["comments"] = undefined!;
|
||||
let _DANGLING_ATTRIBUTES: CustomOptions["danglingAttributes"] = undefined!;
|
||||
|
||||
export function transform_ast(options: CustomOptions) {
|
||||
try {
|
||||
_COMMENTS = options.comments;
|
||||
_DANGLING_ATTRIBUTES = options.danglingAttributes;
|
||||
transformNode(options.rsParsedFile);
|
||||
} finally {
|
||||
_depth = 0;
|
||||
_COMMENTS = undefined!;
|
||||
_DANGLING_ATTRIBUTES = undefined!;
|
||||
}
|
||||
}
|
||||
|
||||
let _depth = 0;
|
||||
const isReadingSnippet = () => 0 !== _depth;
|
||||
|
||||
function maybe_transform_node<T extends Node, S extends Snippet>(
|
||||
node: T,
|
||||
read_snippet: () => S,
|
||||
fn: (node: T, snippet: S) => void
|
||||
): T | undefined {
|
||||
const snippet = try_eval(read_snippet);
|
||||
if (snippet) {
|
||||
++_depth;
|
||||
transformNode(snippet);
|
||||
--_depth;
|
||||
fn(node, snippet);
|
||||
transformed.add(node);
|
||||
return node;
|
||||
}
|
||||
}
|
||||
const transformed = new WeakSet<Node>();
|
||||
export function isTransformed(node: Node) {
|
||||
return transformed.has(node);
|
||||
}
|
||||
|
||||
const transform: { [K in NodeType]?: (node: NTMap[K]) => void } = {
|
||||
[NodeType.Attribute](node) {
|
||||
try_eval(() => {
|
||||
node.segments = rs.createLocArray(node.segments.dk, node.segments.loc.clone(), [
|
||||
transform_simpleAttrSyntax(node.segments),
|
||||
]) as any;
|
||||
transformed.add(node);
|
||||
});
|
||||
},
|
||||
[NodeType.MacroInlineRuleDeclaration](node) {
|
||||
node.match.dk = DelimKind["()"];
|
||||
node.transform.dk = DelimKind["{}"];
|
||||
},
|
||||
[NodeType.MacroInvocation](node) {
|
||||
const name = getMacroName(node);
|
||||
|
||||
if (
|
||||
IGNORED_MACROS.has(name) ||
|
||||
node.segments.length === 0 ||
|
||||
(node.segments.length === 1 && is_PunctuationToken(node.segments[0]))
|
||||
) {
|
||||
return;
|
||||
}
|
||||
|
||||
const tk = transformMacroDelim(name, node);
|
||||
|
||||
if (name === "matches") {
|
||||
//
|
||||
}
|
||||
|
||||
if (name === "if_chain") {
|
||||
//
|
||||
}
|
||||
|
||||
if (name === "cfg_if") {
|
||||
transformBlockLike(() => transform_macro_cfg_if(node.segments) as any);
|
||||
} else if (tk === DelimKind["{}"]) {
|
||||
transformBlockLike(); /* || (includesTK(node, TK[","]) && transformCallLike()); */
|
||||
} else {
|
||||
transformCallLike(); /* || (includesTK(node, TK[";"]) && transformBlockLike()); */
|
||||
}
|
||||
|
||||
function transformBlockLike(transform = () => rs.toBlockBody(node.segments)) {
|
||||
return maybe_transform_node(node as BlockLikeMacroInvocation, transform, (node, snippet) => {
|
||||
const _body = snippet.ast;
|
||||
_body.dk = tk;
|
||||
|
||||
node.body = _body;
|
||||
node.segments = _body;
|
||||
transferAttributes(snippet, node);
|
||||
});
|
||||
}
|
||||
|
||||
function transformCallLike() {
|
||||
return maybe_transform_node(
|
||||
node as CallLikeMacroInvocation,
|
||||
() => rs.toCallExpressionArguments(node.segments),
|
||||
(node, snippet) => {
|
||||
const _arguments = snippet.ast;
|
||||
_arguments.dk = tk;
|
||||
|
||||
node.method = undefined;
|
||||
node.typeArguments = undefined;
|
||||
node.arguments = _arguments;
|
||||
node.segments = _arguments;
|
||||
}
|
||||
);
|
||||
}
|
||||
},
|
||||
[NodeType.CallExpression](node) {
|
||||
if (hasMethod(node)) {
|
||||
node.callee = rs.mockNode(NodeType.MemberExpression, node.method.loc.cloneFrom(start(node.callee)), {
|
||||
expression: node.callee,
|
||||
property: node.method,
|
||||
computed: false,
|
||||
});
|
||||
node.method = undefined!;
|
||||
getOptions().actuallyMethodNodes.add(node.callee as MemberExpression);
|
||||
}
|
||||
},
|
||||
|
||||
[NodeType.AutoTraitDeclaration](node) {
|
||||
mockBodyNoBody(node);
|
||||
},
|
||||
[NodeType.NegativeImplDeclaration](node) {
|
||||
mockBodyNoBody(node);
|
||||
},
|
||||
|
||||
[NodeType.StructLiteral](node) {
|
||||
moveSpreadsToEnd(node);
|
||||
},
|
||||
[NodeType.StructPattern](node) {
|
||||
moveSpreadsToEnd(node);
|
||||
},
|
||||
};
|
||||
|
||||
function moveSpreadsToEnd(node: StructLiteral | StructPattern) {
|
||||
const props = node.properties;
|
||||
if (props.some((p, i, a) => is_StructSpread(p) && !iLast(i, a))) {
|
||||
const spreads: any[] = [];
|
||||
for (let i = 0; i < props.length; i++) {
|
||||
const prop = props[i];
|
||||
if (is_StructSpread(prop)) {
|
||||
Array_splice(props, prop, i--);
|
||||
spreads.push(prop);
|
||||
}
|
||||
}
|
||||
props.push(...spreads);
|
||||
}
|
||||
}
|
||||
|
||||
function mockBodyNoBody(node: NodeWithBodyNoBody) {
|
||||
// @ts-expect-error
|
||||
node.body = rs.createLocArray(last_of(rs.toTokens(node).ast).loc.clone(), DelimKind["{}"]);
|
||||
}
|
||||
|
||||
function transformMacroDelim(name: string, node: MacroInvocation): 1 | 2 | 3 {
|
||||
if (HARDCODED_MACRO_DELIMS.has(name)) {
|
||||
return HARDCODED_MACRO_DELIMS.get(name)!;
|
||||
}
|
||||
if (node.segments.dk === DelimKind["{}"] && includesTK(node, TK[","])) {
|
||||
return DelimKind["()"];
|
||||
}
|
||||
if (node.segments.dk === DelimKind["()"] && includesTK(node, TK[";"])) {
|
||||
return DelimKind["{}"];
|
||||
}
|
||||
return node.segments.dk;
|
||||
}
|
||||
|
||||
// export function createTransformed<S extends Node>(create: () => S): S {
|
||||
// return transformNode(create());
|
||||
// }
|
||||
|
||||
const seen = new WeakSet<Node>();
|
||||
function transformNode<T extends Node>(node: T, parent?: Node, key?: string, index?: any): T {
|
||||
if (!seen.has(node)) {
|
||||
seen.add(node);
|
||||
if (is_Snippet(node) || is_Program(node)) {
|
||||
registerPogramLike(node);
|
||||
}
|
||||
|
||||
each_childNode(node, transformNode);
|
||||
|
||||
insert_blocks(node, parent, key, index);
|
||||
|
||||
transform[node.nodeType]?.(node as any);
|
||||
|
||||
flatten_typeBounds(node);
|
||||
|
||||
transform_nodeAttributes(node);
|
||||
}
|
||||
return node;
|
||||
}
|
||||
|
||||
function insert_blocks(node: Node, parent?: Node, key?: string, index?: any) {
|
||||
if (parent && key) {
|
||||
if (
|
||||
!is_ExpressionStatement(parent) &&
|
||||
(false ||
|
||||
// "1 + break" -> "1 + { break; }"
|
||||
is_FlowControlExpression(node) ||
|
||||
// "1 + a = b" -> "1 + { a = b; }"
|
||||
(!isReadingSnippet() && is_ReassignmentNode(node) && !(is_ReassignmentNode(parent) && parent.left === node)))
|
||||
) {
|
||||
reassignNodeProperty(blockify(node), parent, key, index);
|
||||
} else if (
|
||||
is_ClosureFunctionExpression(node) &&
|
||||
(false ||
|
||||
// "|| -> T x" -> "|| -> T { x }"
|
||||
(!!node.returnType && !is_BlockExpression(node.expression)) ||
|
||||
// "|| match x {}" -> "|| { match x {} }"
|
||||
(is_ExpressionWithBodyOrCases(node.expression) &&
|
||||
!is_BlockExpression(node.expression) &&
|
||||
!is_IfBlockExpression(node.expression)))
|
||||
) {
|
||||
node.expression = blockify(node.expression);
|
||||
}
|
||||
}
|
||||
function blockify(node: ExpressionNode) {
|
||||
const block = rs.mockNode(NodeType.BlockExpression, node.loc.clone(), {
|
||||
label: undefined,
|
||||
body: rs.createLocArray(DelimKind["{}"], node.loc.clone(), [
|
||||
rs.mockNode(NodeType.ExpressionStatement, node.loc.clone(), { semi: false, expression: node }),
|
||||
]),
|
||||
});
|
||||
transferAttributes(node, block);
|
||||
return block;
|
||||
}
|
||||
}
|
||||
|
||||
function flatten_typeBounds(topNode: Node) {
|
||||
if (hasTypeBounds(topNode)) {
|
||||
const nestedBounds: TypeTraitBound[] = topNode.typeBounds.filter(isBoundWithNestedBounds);
|
||||
const [first, ...subsequent] = nestedBounds;
|
||||
|
||||
const flatten = (bound: TypeTraitBound) =>
|
||||
Array_replace(topNode.typeBounds, bound, ...(bound.typeExpression as unknown as TypeDynBounds).typeBounds);
|
||||
|
||||
if (nestedBounds.every(isBareBoundWithNestedBoundsNoPrefix)) {
|
||||
// A + (B + C)
|
||||
// -> A + B + C
|
||||
each(nestedBounds, flatten);
|
||||
} else if (
|
||||
!hasDefinedPrefix(topNode) &&
|
||||
first === topNode.typeBounds[0] &&
|
||||
!isBareBoundWithNestedBoundsNoPrefix(first) &&
|
||||
subsequent.every(isBareBoundWithNestedBoundsNoPrefix)
|
||||
) {
|
||||
if (is_TypeDynBounds(topNode)) {
|
||||
if (is_TypeImplBounds(first.typeExpression)) {
|
||||
// (impl A) + B
|
||||
// -> impl A + B
|
||||
unsafe_set_nodeType(topNode, NodeType.TypeImplBounds);
|
||||
} else {
|
||||
// (dyn A) + B
|
||||
// -> dyn A + B
|
||||
topNode.dyn = true;
|
||||
}
|
||||
each(nestedBounds, flatten);
|
||||
} else {
|
||||
each(subsequent, flatten);
|
||||
(first.typeExpression as unknown as TypeDynBounds).typeBounds.push(...topNode.typeBounds.slice(1));
|
||||
topNode.typeBounds.length = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function isBoundWithNestedBounds(bound: TypeBound): bound is TypeTraitBound & { typeExpression: TypeBoundsStandaloneNode } {
|
||||
return is_TypeTraitBound(bound) && is_TypeBoundsStandaloneNode(bound.typeExpression);
|
||||
}
|
||||
function isBareBoundWithNestedBounds(bound: TypeBound): bound is TypeTraitBound & { typeExpression: TypeBoundsStandaloneNode } {
|
||||
return isBoundWithNestedBounds(bound) && is_BareTypeTraitBound(bound);
|
||||
}
|
||||
function isBareBoundWithNestedBoundsNoPrefix(bound: TypeBound): bound is TypeTraitBound & { typeExpression: TypeDynBounds } {
|
||||
return isBareBoundWithNestedBounds(bound) && !hasDefinedPrefix(bound.typeExpression);
|
||||
}
|
||||
function hasDefinedPrefix(node: NodeWithTypeBounds) {
|
||||
return (is_TypeDynBounds(node) && node.dyn) || is_TypeImplBounds(node);
|
||||
}
|
||||
}
|
||||
|
||||
function transform_nodeAttributes(node: Node) {
|
||||
/**
|
||||
* # Inside Token trees:
|
||||
*
|
||||
* 1. DocCommentAttribute --is parsed as--> Comment
|
||||
* 2. Attribute --is parsed as--> Token<'#'>, DelimGroup<'[]'>
|
||||
*
|
||||
* # Transforming tokens into a Snippet:
|
||||
*
|
||||
* 1. DocCommentAttribute <--replace from-- Comment
|
||||
* a) Remove node with same loc from comments
|
||||
* b) Merge Snippet.danglingAttributes with Program.danglingAttributes
|
||||
*
|
||||
* 2. Attribute (no action needed)
|
||||
*
|
||||
*/
|
||||
if (hasAttributes(node)) {
|
||||
const attrs = node.attributes;
|
||||
for (let i = 0; i < attrs.length; i++) {
|
||||
const attr = attrs[i];
|
||||
if (isReadingSnippet() && is_DocCommentAttribute(attr)) {
|
||||
const index = binarySearchIn(_COMMENTS, start(attr), start);
|
||||
__DEV__: assert(index !== -1), assert(end(_COMMENTS[index]) === end(attr));
|
||||
_COMMENTS.splice(index, 1);
|
||||
}
|
||||
if (attr.inner) {
|
||||
if (isPrettierIgnoreAttribute(attr)) {
|
||||
setPrettierIgnoreTarget(is_Program(node) ? node.loc.src : node, attr);
|
||||
}
|
||||
// @ts-expect-error Inserting Attribute into StatementNode[]
|
||||
insertNode(is_Snippet(node) ? node.ast : getBodyOrCases(node)!, attr);
|
||||
Array_splice(attrs, attr, i--);
|
||||
}
|
||||
}
|
||||
if (attrs.length === 0) {
|
||||
deleteAttributes(node);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function registerPogramLike(program: Extract<Node, ProgramLike>) {
|
||||
const comments = spliceAll(program.comments);
|
||||
const danglingAttributes = spliceAll(program.danglingAttributes);
|
||||
for (let i = 0; i < danglingAttributes.length; i++) {
|
||||
const attr = danglingAttributes[i];
|
||||
// if (isReadingSnippet() && is_DocCommentAttribute(attr)) {
|
||||
// }
|
||||
if (is_DocCommentAttribute(attr)) {
|
||||
if (isReadingSnippet()) {
|
||||
const index = binarySearchIn(_COMMENTS, start(attr), start);
|
||||
__DEV__: assert(index !== -1), assert(end(_COMMENTS[index]) === end(attr));
|
||||
_COMMENTS.splice(index, 1);
|
||||
}
|
||||
} else {
|
||||
transformNode(danglingAttributes[i], program, "danglingAttributes", i);
|
||||
}
|
||||
}
|
||||
if (!isReadingSnippet()) insertNodes(_COMMENTS, comments);
|
||||
insertNodes(_DANGLING_ATTRIBUTES, danglingAttributes);
|
||||
}
|
||||
|
||||
const CommentChildNodes = new WeakMap<Node, Node[]>();
|
||||
|
||||
export function getCommentChildNodes(n: any): Node[] {
|
||||
const children = Map_get(CommentChildNodes, n, getTransformedNodeChildren);
|
||||
/**
|
||||
* parent {
|
||||
* #[attr]
|
||||
* #![attr] <-------- list misplaced inner attrs as part of "#[attr] child {}"
|
||||
* child {}
|
||||
* }
|
||||
*/
|
||||
if (is_NodeWithBodyOrCases(n) || is_BlockLikeMacroInvocation(n)) {
|
||||
for (let i = 0; i < children.length; i++) {
|
||||
const attr = children[i];
|
||||
if (is_AttributeOrDocComment(attr)) {
|
||||
const target = children.find((n) => start(n) <= start(attr) && ownStart(n) >= end(attr));
|
||||
if (target) {
|
||||
children.splice(i--, 1);
|
||||
insertNode(Map_get(CommentChildNodes, target, getTransformedNodeChildren), attr);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return children;
|
||||
|
||||
function getTransformedNodeChildren(node: Node) {
|
||||
if (is_Program(node)) node.comments ??= []; // prettier core deletes this property
|
||||
const children = getNodeChildren(node);
|
||||
|
||||
if (is_NodeWithBodyNoBody(node)) {
|
||||
insertNodes(children, (node as any).body);
|
||||
}
|
||||
|
||||
__DEV__: {
|
||||
const actual_count = countActualNodeChildren(node);
|
||||
if (
|
||||
children.length !== actual_count &&
|
||||
!(is_MacroInvocation(node) && actual_count - node.segments.length === children.length)
|
||||
) {
|
||||
const actual = getActualNodeChildren(node);
|
||||
const missing = actual.filter((n) => !children.includes(n));
|
||||
const unknown = children.filter((n) => !actual.includes(n));
|
||||
const duplicates_in_object = actual.filter((n, i, a) => i !== 0 && n === a[i - 1]);
|
||||
const duplicates_in_childNodes = children.filter((n, i, a) => i !== 0 && n === a[i - 1]);
|
||||
const ctx = { missing, unknown, duplicates_in_object, duplicates_in_childNodes };
|
||||
for (let key in ctx) if (ctx[key].length === 0) delete ctx[key];
|
||||
exit(`${node.type} was transformed but did not patch its childNodes list`, ctx, node.loc.url(), node);
|
||||
}
|
||||
for (const child of children)
|
||||
if (!is_Node(child)) exit(`${node.type}'s childNodes includes unexpected entries`, { node, child });
|
||||
}
|
||||
return children;
|
||||
}
|
||||
}
|
||||
246
frontend/src/common/prettier/plugins/rust/utils/common.ts
Normal file
246
frontend/src/common/prettier/plugins/rust/utils/common.ts
Normal file
@@ -0,0 +1,246 @@
|
||||
import { createCustomError } from "./debug";
|
||||
|
||||
declare global {
|
||||
interface ImportMeta {
|
||||
url: string;
|
||||
}
|
||||
}
|
||||
|
||||
export function Narrow<T extends R, R = unknown>(value: R): asserts value is T {}
|
||||
export function AssertTypesEq<A extends B, B>(...args: [B] extends [A] ? [] : [RIGHT_TYPES_NOT_ASSIGNABLE_TO_LEFT: Exclude<B, A>]) {}
|
||||
|
||||
// prettier-ignore
|
||||
type indexof<A> = A extends readonly any[] ? A extends 0 ? any : keyof A & number : A extends Set<unknown> ? never : A extends Map<infer U, unknown> ? U
|
||||
: A extends Iterable<unknown> ? never : A extends object ? keyof A & (number | string) : never;
|
||||
// prettier-ignore
|
||||
type valueof<A> = A extends ReadonlyArray<infer U> ? A extends 0 ? any : U : A extends Set<infer U> ? U : A extends Map<unknown, infer U> ? U
|
||||
: A extends Iterable<infer U> ? U : A extends object ? A[keyof A & (number | string)] : never;
|
||||
// prettier-ignore
|
||||
type vObject<V extends unknown = unknown, K extends unknown = unknown> = | object | readonly V[] | { [key: string]: V } | anySet<V> | anyMap<K, V>;
|
||||
export type itfn<A, R> = (value: valueof<A>, key: indexof<A>) => R;
|
||||
type anySet<V extends unknown = unknown> = Set<V>;
|
||||
type anyMap<K extends unknown = unknown, V extends unknown = unknown> = Map<K, V>;
|
||||
type anyfunction<A extends any[] = unknown[], R = unknown> = (...args: A) => R;
|
||||
type objlike = object | anyfunction;
|
||||
type anymap<K extends unknown = unknown, V extends unknown = unknown> = K extends objlike ? Map<K, V> | WeakMap<K, V> : Map<K, V>;
|
||||
|
||||
export function exit(message: string, ...ctx: any[]): never {
|
||||
if (ctx.length > 0) console.log("Error context:", { ...ctx });
|
||||
throw createCustomError({ message });
|
||||
}
|
||||
exit.never = function never(...ctx: any[]): never {
|
||||
exit("Reached unreachable code", ...ctx);
|
||||
};
|
||||
export function assert(predicate: boolean, err?: string, ...ctx: any[]): asserts predicate {
|
||||
__DEV__: if (typeof predicate !== "boolean") exit("Expected boolean", predicate);
|
||||
if (false === predicate) exit(err ?? "Assertion failed", ...ctx);
|
||||
}
|
||||
export function Identity<T>(v: T): T {
|
||||
return v;
|
||||
}
|
||||
|
||||
export function last_of<T extends ArrayLike<any>>(arr: T): T extends readonly [...infer A, infer U] ? U : T[number] {
|
||||
__DEV__: isArrayLike(arr) || exit("Expected Array"), arr.length > 0 || exit("Attempted to retrieve last item of an empty array", arr);
|
||||
return arr[arr.length - 1];
|
||||
}
|
||||
export function maybe_last_of<T extends readonly any[] | undefined>(
|
||||
arr: T
|
||||
): T extends any[] ? (T extends readonly [...infer A, infer U] ? U : T[number]) : undefined {
|
||||
return (undefined === arr || 0 === arr.length ? undefined : last_of(arr as any[])) as any;
|
||||
}
|
||||
|
||||
export function normPath(filepath: string) {
|
||||
return filepath.replace(/^file:\/\/\//, "").replace(/\\\\?/g, "/");
|
||||
}
|
||||
|
||||
export function print_string(str: string) {
|
||||
return /[\u0000-\u0020]/.test(str)
|
||||
? str
|
||||
.replace(/ /g, "•")
|
||||
.replace(/\n/g, "↲")
|
||||
.replace(/\t/g, "╚")
|
||||
.replace(/[\u0000-\u0020]/g, "□")
|
||||
: str;
|
||||
}
|
||||
|
||||
function isArrayLike(value: any): value is ArrayLike<unknown> {
|
||||
return is_object(value) && oisArrayLike(value);
|
||||
}
|
||||
|
||||
function oisArrayLike(value: {}): value is ArrayLike<unknown> {
|
||||
return "length" in value && (0 === (value as any).length || "0" in value);
|
||||
}
|
||||
|
||||
export function binarySearchIn<T extends {}>(array: ArrayLike<T>, target: number, toValue: (item: T) => number) {
|
||||
if (isEmpty(array)) return -1;
|
||||
let i = 0;
|
||||
let low = 0;
|
||||
let high = array.length - 1;
|
||||
let value = toValue(array[high]);
|
||||
if (target >= value) return high;
|
||||
else high--;
|
||||
while (low <= high) {
|
||||
i = low + ((high - low) >> 1);
|
||||
value = toValue(array[i]);
|
||||
if (target === value) return i;
|
||||
if (target > value) low = i + 1;
|
||||
else high = i - 1;
|
||||
}
|
||||
return low - 1;
|
||||
}
|
||||
|
||||
export function getTerminalWidth(fallbackWidth = 200) {
|
||||
return globalThis?.process?.stdout?.columns ?? fallbackWidth;
|
||||
}
|
||||
|
||||
// @ts-ignore
|
||||
const isBrowser = typeof window !== "undefined" && typeof window.document !== "undefined";
|
||||
export const color = ((cfn, mfn) => ({
|
||||
black: cfn(30),
|
||||
red: cfn(31),
|
||||
green: cfn(32),
|
||||
yellow: cfn(33),
|
||||
blue: cfn(34),
|
||||
magenta: cfn(35),
|
||||
cyan: cfn(36),
|
||||
white: cfn(37),
|
||||
grey: cfn(90),
|
||||
bold: mfn(1, 22),
|
||||
italic: mfn(3, 23),
|
||||
underline: mfn(4, 24),
|
||||
hidden: mfn(8, 28),
|
||||
hiddenCursor: (str: string) => `\x1B[?25l${str}\x1B[?25h`,
|
||||
unstyle: (str: string) => str.replace(/\x1B\[[0-9][0-9]?m/g, ""),
|
||||
unstyledLength: (str: string) => str.replace(/\x1B\[[0-9][0-9]?m/g, "").length,
|
||||
link: (str: string) => color.underline(color.blue(str)),
|
||||
}))(
|
||||
(c1: number) => (isBrowser ? Identity : (str: string) => `\x1B[${c1}m${str.replace(/\x1B\[39m/g, `\x1B[${c1}m`)}\x1B[39m`),
|
||||
(c1: number, c2: number) => (isBrowser ? Identity : (str: string) => `\x1B[${c1}m${str}\x1B[${c2}m`)
|
||||
);
|
||||
export function Map_get<K extends object, V>(map: WeakMap<K, V>, key: K, init: (key: K) => V): V;
|
||||
export function Map_get<K, V>(map: Map<K, V>, key: K, init: (key: K) => V): V;
|
||||
export function Map_get<K, V>(map: anymap<K, V>, key: K, init: (key: K) => V): V {
|
||||
if (!map.has(key)) map.set(key, init(key));
|
||||
return map.get(key)!;
|
||||
}
|
||||
export function isEmpty(array: ArrayLike<any>): boolean {
|
||||
__DEV__: assert(isArrayLike(array));
|
||||
return 0 === array.length;
|
||||
}
|
||||
export function Array_splice<T extends any[]>(array: T, target: T[number], index: number = array.indexOf(target)) {
|
||||
__DEV__: {
|
||||
const i = arguments.length === 2 ? array.indexOf(target) : index;
|
||||
assert(i === index && i !== -1 && i === array.lastIndexOf(target), "", { array, target, index, i });
|
||||
}
|
||||
array.splice(index, 1);
|
||||
}
|
||||
export function Array_replace<T extends any[]>(array: T, target: T[number], ...replacements: T[number][]) {
|
||||
const i = array.indexOf(target);
|
||||
__DEV__: if (i === -1 || i !== array.lastIndexOf(target))
|
||||
exit("Array_replace", { index: i, lastIndex: array.lastIndexOf(target), array, target, replacements });
|
||||
array.splice(array.indexOf(target), 1, ...replacements);
|
||||
}
|
||||
export function has_key_defined<T extends object, K extends T extends never ? never : keyof T>(
|
||||
o: T,
|
||||
k: K
|
||||
): o is K extends never
|
||||
? never
|
||||
: T extends { [k in K]: any }
|
||||
? T & { [k in K]: {} }
|
||||
: T extends { [k in K]?: any }
|
||||
? T & { [k in K]: {} }
|
||||
: never {
|
||||
return k in o && undefined !== o[k];
|
||||
}
|
||||
|
||||
export function is_object(data: unknown): data is object | ({ [key: string]: unknown } | unknown[]) {
|
||||
return "object" === typeof data && null !== data;
|
||||
}
|
||||
|
||||
export function is_array(data: unknown): data is any[] {
|
||||
return Array.isArray(data);
|
||||
}
|
||||
|
||||
function ois_vobject(data: any) {
|
||||
__DEV__: assert(is_object(data));
|
||||
switch (data.constructor) {
|
||||
case Array:
|
||||
case Object:
|
||||
case Set:
|
||||
case Map:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
export function each<A extends vObject>(data: A, callback: itfn<A, void>): void;
|
||||
export function each(data: any, callback: (value: any, index: any) => void): void {
|
||||
__DEV__: assert(ois_vobject(data));
|
||||
// prettier-ignore
|
||||
switch (data.constructor) {
|
||||
case Array: { let i = 0; for (; i < data.length; i++) callback(data[i], i); return; }
|
||||
case Object: { let k; for (k in data) callback(data[k], k); return; }
|
||||
case Set: { let d; for (d of data) callback(d, undefined!); return; }
|
||||
case Map: { let e; for (e of data) callback(e[1], e[0]); return; }
|
||||
default: { let x; for (x of data) callback(x, undefined!); return; }
|
||||
}
|
||||
}
|
||||
|
||||
export function iLast(index: number, array: any[]) {
|
||||
return 1 + index === array.length;
|
||||
}
|
||||
|
||||
export function find_last<T>(arr: T[], test: itfn<T[], boolean>): T | undefined {
|
||||
for (var i = arr.length; --i !== -1; ) if (test(arr[i], i)) return arr[i];
|
||||
}
|
||||
|
||||
export function try_eval<T>(fn: () => T): T | undefined {
|
||||
try {
|
||||
return fn();
|
||||
} catch (e) {
|
||||
return undefined;
|
||||
}
|
||||
}
|
||||
|
||||
export function clamp(min: number, max: number, value: number) {
|
||||
return value > min ? (value < max ? value : max) : min;
|
||||
}
|
||||
|
||||
export type MaybeFlatten<T> = T extends ReadonlyArray<infer U> ? MaybeFlatten<Exclude<U, T>> : T;
|
||||
export type FlatArray<T> = MaybeFlatten<T>[];
|
||||
export function flat<T extends readonly any[]>(arr: T): FlatArray<T> {
|
||||
return (arr as any as [any]).flat(Infinity);
|
||||
}
|
||||
export function flatMap<T extends readonly any[], R>(arr: T, mapFn: (item: T[number], index: number, array: T) => R): FlatArray<R> {
|
||||
return flat(arr.map(mapFn as any));
|
||||
}
|
||||
|
||||
export function joinln(...arr: string[]): string {
|
||||
return arr.join("\n");
|
||||
}
|
||||
|
||||
export function join_lines(fn: () => Generator<string, void, void>): string {
|
||||
return [...fn()].join("\n");
|
||||
}
|
||||
|
||||
export function reduce_tagged_template<T>(args: [strings: TemplateStringsArray, ...values: T[]], map: (value: T) => string) {
|
||||
for (var str = "" + args[0][0], i = 1; i < args.length; i++) str += map(args[i] as T) + args[0][i];
|
||||
return str;
|
||||
}
|
||||
|
||||
export function map_tagged_template<T, R>(args: [strings: TemplateStringsArray, ...values: T[]], map: (value: T) => R) {
|
||||
const arr: (R | string)[] = [args[0][0]];
|
||||
for (var i = 1; i < args.length; i++) arr.push(map(args[i] as T), args[0][i]);
|
||||
return arr;
|
||||
}
|
||||
|
||||
export function spliceAll<T extends any[]>(array: T): [...T] {
|
||||
const r: [...T] = [...array];
|
||||
array.length = 0;
|
||||
return r;
|
||||
}
|
||||
|
||||
export function spread<R>(fn: () => Iterable<R>): R[] {
|
||||
return [...fn()];
|
||||
}
|
||||
141
frontend/src/common/prettier/plugins/rust/utils/debug.ts
Normal file
141
frontend/src/common/prettier/plugins/rust/utils/debug.ts
Normal file
@@ -0,0 +1,141 @@
|
||||
import { clamp, color, getTerminalWidth, normPath } from "./common";
|
||||
|
||||
const cwd =
|
||||
typeof process === "object" && typeof process?.cwd === "function" ? /* @__PURE__ */ normPath(/* @__PURE__ */ process.cwd() ?? "") : "";
|
||||
function normPath_strip_cwd(filepath: string) {
|
||||
let normFilePath = normPath(filepath);
|
||||
return normFilePath.startsWith(cwd) ? normFilePath.slice(cwd.length + 1) : normFilePath;
|
||||
}
|
||||
|
||||
type StackStyleFn = (callee: string, item: StackItem) => (str: string) => string;
|
||||
interface Stack extends Array<StackItem> {
|
||||
message: string;
|
||||
style?: { callee?: StackStyleFn; url?: StackStyleFn } | undefined;
|
||||
}
|
||||
|
||||
class StackLine {
|
||||
declare readonly raw: string;
|
||||
declare readonly callee: string;
|
||||
declare readonly filepath: string;
|
||||
declare readonly line: string;
|
||||
declare readonly col: string;
|
||||
declare readonly other: string;
|
||||
declare readonly url: string;
|
||||
constructor(raw: string) {
|
||||
({
|
||||
1: this.callee = "",
|
||||
2: this.filepath = "",
|
||||
3: this.line = "",
|
||||
4: this.col = "",
|
||||
5: this.other = "",
|
||||
} = (this.raw = raw).match(/at (?:(.+?)\s+\()?(?:(.+?):([0-9]+)(?::([0-9]+))?|([^)]+))\)?/) ?? ["", "", "", "", "", ""]);
|
||||
this.url = this.filepath //
|
||||
? normPath_strip_cwd(this.filepath) + (this.line && this.col && `:${this.line}:${this.col}`)
|
||||
: this.other === "native"
|
||||
? "<native>"
|
||||
: "";
|
||||
}
|
||||
}
|
||||
|
||||
function getPrintWidth() {
|
||||
return clamp(0, getTerminalWidth(128), 200) - 4;
|
||||
}
|
||||
|
||||
class StackItem extends StackLine {
|
||||
constructor(private readonly stack: Stack, readonly i: number, raw: string) {
|
||||
super(raw);
|
||||
}
|
||||
hidden = false;
|
||||
hide() {
|
||||
this.hidden = true;
|
||||
return this;
|
||||
}
|
||||
hideNext(n: number) {
|
||||
for (let i = 0; i < n; i++) this.at(i)?.hide();
|
||||
}
|
||||
hideWhileTrue(test: (line: StackItem) => boolean) {
|
||||
let line: StackItem | undefined = this;
|
||||
while (line && test(line)) line = line.hide().next();
|
||||
}
|
||||
at(relIndex: number) {
|
||||
return this.i + relIndex >= this.stack.length || this.i + relIndex < 0 ? undefined : this.stack[this.i + relIndex];
|
||||
}
|
||||
next() {
|
||||
return this.at(+1);
|
||||
}
|
||||
toString() {
|
||||
const url = this.url;
|
||||
const calleeColor = this.stack.style?.callee?.(this.callee, this) ?? color.cyan;
|
||||
const urlColor = this.stack.style?.url?.(url, this) ?? color.grey;
|
||||
return compose2Cols(" at " + calleeColor(this.callee), urlColor(url), getPrintWidth());
|
||||
}
|
||||
}
|
||||
|
||||
// prettier-ignore
|
||||
function createStack(message: string, Error_stack: string, style: Stack["style"]): Stack {
|
||||
for (var STACK: Stack = [] as any, i = 0, stack = Error_stack.split("\n").slice(2); i < stack.length; i++) STACK[i] = new StackItem(STACK, i, stack[i]);
|
||||
return (STACK.message = message), (STACK.style = style), STACK;
|
||||
}
|
||||
|
||||
function composeStack(stack: Stack) {
|
||||
var hidden = 0;
|
||||
var str = stack.message;
|
||||
for (var item of stack) item.hidden ? ++hidden : (str += "\n" + item.toString());
|
||||
return str + (hidden > 0 ? "\n" + color.grey(compose2Cols("", `...filtered ${hidden} lines`, getPrintWidth())) : "");
|
||||
}
|
||||
|
||||
export function get_caller_cmd(offset = 0) {
|
||||
const obj: { stack: string } = {} as any;
|
||||
Error.captureStackTrace(obj, get_caller_cmd);
|
||||
const lines = obj.stack.split("\n");
|
||||
return new StackLine(lines[1 + clamp(0, lines.length - 2, offset)]).url;
|
||||
}
|
||||
|
||||
var Error_prepareStackTrace;
|
||||
let replaced_default_prepareStackTrace = false;
|
||||
function custom_prepareStackTrace(err, calls) {
|
||||
return (Error_prepareStackTrace?.(err, calls) ?? calls.join("\n"))?.replace(/file:\/\/\//g, "").replace(/\\\\?/g, "/") ?? calls;
|
||||
}
|
||||
|
||||
export function overrideDefaultError(silent = false) {
|
||||
if (replaced_default_prepareStackTrace === (replaced_default_prepareStackTrace = true)) return;
|
||||
Error_prepareStackTrace = Error.prepareStackTrace ?? ((_, calls) => calls.join("\n"));
|
||||
Error.prepareStackTrace = custom_prepareStackTrace;
|
||||
if (!silent) console.log(color.grey(`[devtools] Replaced Error.prepareStackTrace at ${get_caller_cmd(1)}`));
|
||||
}
|
||||
|
||||
export function createCustomError({
|
||||
message = "Unknown Error",
|
||||
editStack = (stack: StackItem[]) => {},
|
||||
style = undefined as Stack["style"],
|
||||
stackTraceLimit = 20,
|
||||
}): Error {
|
||||
const _stackTraceLimit = Error.stackTraceLimit;
|
||||
const _prepareStackTrace = Error.prepareStackTrace;
|
||||
if (replaced_default_prepareStackTrace && _prepareStackTrace === custom_prepareStackTrace)
|
||||
Error.prepareStackTrace = Error_prepareStackTrace;
|
||||
|
||||
Error.stackTraceLimit = stackTraceLimit;
|
||||
|
||||
const _ctx: { stack: string } = {} as any;
|
||||
|
||||
Error.captureStackTrace(_ctx, createCustomError);
|
||||
|
||||
const stack = createStack(message, _ctx.stack, style);
|
||||
Error.prepareStackTrace = function (err, calls) {
|
||||
editStack(stack);
|
||||
return composeStack(stack);
|
||||
};
|
||||
|
||||
const err = new Error(message); // (get) to trigger prepareStackTrace, (set) to prevent treeshaking
|
||||
err.stack = err.stack;
|
||||
|
||||
Error.stackTraceLimit = _stackTraceLimit;
|
||||
Error.prepareStackTrace = _prepareStackTrace;
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
function compose2Cols(left: string, right: string, len = 64, min = 1) {
|
||||
return left + " ".repeat(clamp(min, len, len - (color.unstyledLength(left) + color.unstyledLength(right)))) + right;
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user