Code Conventions

Mandatory coding standards for the WvdS FPC RAD Suite.

Naming Conventions

Types

Category Prefix Example
Class TWvdS* TWvdSBuildConfig, TWvdSProjectManager
Interface IWvdS* IWvdSLogger, IWvdSParser
Record TWvdS* TWvdSBuildResult, TWvdSToolPath
Enum TWvdS* TWvdSProjectType, TWvdSBuildStatus
Exception EWvdS* EWvdSFileNotFound, EWvdSParseError
Callback TWvdS* TWvdSBuildCallback, TWvdSProgressHandler
External API types (VSCode, Node.js) retain their original names.

Unit Names

Microsoft-style namespaces with WvdS prefix:

WvdS.{Domain}.{Layer}.pas

Examples:
WvdS.Build.Models.pas
WvdS.Build.Service.pas
WvdS.Projects.SettingsDialog.pas
WvdS.VSCode.Commands.pas

Layer Suffixes

Suffix Content Example
.Models Records, enums, types WvdS.Build.Models
.Service Business logic WvdS.Build.Service
.Dialog WebView dialogs WvdS.Projects.SettingsDialog
.Provider VSCode API wrapper WvdS.Designer.EditorProvider

Variables and Parameters

Category Prefix Example
Private fields F FProjectPath, FConfig
Parameters A APath, AOptions, ACallback
Local variables None Result, I, Config

Resourcestrings

Prefix by feature:

Prefix Feature
rsCore* Core Extension
rsBuild* Build Extension
rsProject* Projects Extension
rsDesigner* UI Designer
rsPreview* UI Preview
rsMeta* UI Meta
rsPackaging* Packaging
rsTool* Toolchain

Code Structure

Unit Layout

unit WvdS.{Feature}.{Layer};
 
{$mode objfpc}{$H+}
 
interface
 
uses
  // 1. System Units
  SysUtils, Classes,
  // 2. WvdS Common
  WvdS.System, WvdS.Collections,
  // 3. Feature-specific
  WvdS.{Feature}.Models;
 
type
  // Type definitions
 
function PublicFunction(const AParam: string): Boolean;
procedure PublicProcedure(AValue: Integer);
 
implementation
 
uses
  // Private uses (units needed only here)
  WvdS.VSCode.Strings;
 
// Private types and variables
type
  TInternalHelper = class
  end;
 
var
  InternalState: TObject;
 
// Implementations
 
function PublicFunction(const AParam: string): Boolean;
begin
  // ...
end;
 
procedure PublicProcedure(AValue: Integer);
begin
  // ...
end;
 
initialization
  // Initialization
 
finalization
  // Cleanup
 
end.

Class Layout

type
  TWvdSExampleClass = class(TObject)
  private
    FName: string;
    FValue: Integer;
    procedure SetName(const AValue: string);
  protected
    procedure DoInternalWork; virtual;
  public
    constructor Create(const AName: string);
    destructor Destroy; override;
    procedure Execute;
    property Name: string read FName write SetName;
    property Value: Integer read FValue write FValue;
  end;

Documentation

PasDoc Format

(*
  @abstract(Short description in one sentence.)
 
  Detailed description of purpose and usage.
  Can span multiple sentences.
 
  @param(APath Full path to the file)
  @param(AOptions Optional configuration, can be nil)
  @returns(True if successful, False on error)
 
  @raises(EWvdSFileNotFound when file does not exist)
  @raises(EWvdSAccessDenied when no read permissions)
 
  Security:
    - CWE-22: Path is validated against path traversal
 
  @seealso(RelatedFunction)
  @seealso(TWvdSRelatedClass)
*)
function ProcessFile(const APath: string; AOptions: TOptions): Boolean;

Inline Comments

// Short comment for single line
Result := CalculateValue;
 
// Multi-line comment for more complex logic
// Explains the why, not the what
if (Value > Threshold) and (Mode = mAdvanced) then
begin
  // We need to use the advanced algorithm here,
  // as the simple one becomes inaccurate for large values
  Result := AdvancedCalculation(Value);
end;

Constants Instead of Magic Numbers

// FORBIDDEN
if Length(Name) > 64 then
if Timeout > 30000 then
 
// CORRECT
const
  MAX_PROJECT_NAME_LENGTH = 64;
  DEFAULT_TIMEOUT_MS = 30000;
 
if Length(Name) > MAX_PROJECT_NAME_LENGTH then
if Timeout > DEFAULT_TIMEOUT_MS then

Terminology

Use consistent terms:

Use Avoid
Path Url, Location, Dir (inconsistent)
Config Settings, Options, Prefs (inconsistent)
Create Make, Build (for objects)
Generate Create (for output)
Validate Check, Verify (for inputs)
Initialize Setup, Init (inconsistent)
Execute Run, Process (inconsistent)

Formatting

Indentation

  • 2 Spaces for indentation (not tabs)
  • begin on its own line for blocks
  • end at the same indentation level as the corresponding begin
// CORRECT
procedure Example;
begin
  if Condition then
  begin
    DoSomething;
    DoMore;
  end
  else
  begin
    DoAlternative;
  end;
end;
 
// FORBIDDEN
procedure Example; begin
  if Condition then begin DoSomething; DoMore; end
  else DoAlternative;
end;

Line Length

  • Maximum 120 characters per line
  • Wrap long expressions
// For long parameter lists
function VeryLongFunctionName(
  const AFirstParameter: string;
  const ASecondParameter: Integer;
  AThirdParameter: TOptions
): Boolean;
 
// For long conditions
if (FirstCondition) and
   (SecondCondition) and
   (ThirdCondition) then
begin
  // ...
end;

Forbidden Patterns

Empty Exception Handlers

// FORBIDDEN
try
  DoSomething;
except
  // Do nothing - swallowing errors!
end;
 
// CORRECT
try
  DoSomething;
except
  on E: Exception do
    LogError(rsUnexpectedError, [E.ClassName, E.Message]);
end;

TODO/FIXME in Production Code

// FORBIDDEN in main branch
// TODO: Implement this later
// FIXME: This is broken
 
// ALLOWED only in feature branches, must be removed before merge

Hardcoded Strings

// FORBIDDEN
ShowMessage('File not found');
ShowMessage('Datei nicht gefunden');
 
// CORRECT
ShowMessage(rsFileNotFound);  // resourcestring

Global Variables in Services

// FORBIDDEN
var
  GlobalConfig: TConfig;  // Hard to test!
 
// CORRECT - Pass parameters
function ProcessWithConfig(const AConfig: TConfig): Boolean;

Testability

Services must be testable without VSCode/UI:

// FORBIDDEN - UI in Service
procedure ValidateAndShowError(const AName: string);
begin
  if not IsValid(AName) then
    ShowMessage('Invalid name');  // UI dependency!
end;
 
// CORRECT - Return value
function ValidateName(const AName: string; out AError: string): Boolean;
begin
  Result := IsValid(AName);
  if not Result then
    AError := rsInvalidName;
end;

pas2js Compatibility (IMPORTANT)

pas2js is NOT 100% compatible with FPC! These restrictions MUST be observed.

Unsupported Features

Feature FPC pas2js Workaround
class var Yes No Use unit-level variable
Inline var Yes No Declare in var block
Int64 Yes No Use Integer
Zuletzt geändert: on 2026/01/29 at 10:29 PM