Zum Inhalt

Transform Files

Transform files are used to customize how files are presented on the web interface. Technically, their purpose is to set attribute values to files and directories. For example, you can change the display name of a file by setting the name attribute.

Transform files are the tool PFS provides to allow customization of the web interface for various use cases.

A Transform file always refers to a file or directory. The purpose of this Transform file is to set attributes for that file or directory. All Transform files are located in the data volumes and should be placed next to the files they refer to. If a directory contains a file named transform.txt, it will be executed as the Transform file for that directory. If a file named <file>.transform.txt exists in the same directory as a file named <file>, it will be run as the Transform file for that file.

Basic Syntax

The purpose of a Transform file is to set attributes. The basic syntax to set attributes of the file or directory that this Transform file refers to is <attribute> = <value>. Each instruction in a Transform file must be on a separate line.

A Transform file can look like this:

name = "The display name"
thumb = 'thumb.jpg'
hidden = true
number = 42

Some attributes have a special meaning and change how files are displayed or behave. These attributes are described in the File Customizations documentation.

Setting Attributes for Files

It is also possible to set attributes for other files in the same directory. Files are referenced by writing their file name in single quotes. For example, the following Transform file sets the display names of multiple files and hides file2.txt.

name = "My name"
'file1.txt'.name = "File 1"
'file2.txt'.name = "File 2"
'file2.txt'.hidden = true

If file1.txt or file2.txt does not exist, the respective line will be ignored.

It is also possible to read attributes and use these values to set other attributes.

'file1.txt'.name = "A file name"
name = 'file1.txt'.name

Comments

Lines in a Transform file that contain // outside of a string are treated as comments, and everything after that // is ignored.

Expressions

It is possible to use expressions to combine values. Complex expressions can be constructed by combining values using operators. The operator priority can be controlled by enclosing expressions in parentheses ().

number = (5+7)*3 - 2

Each operator can have a different effect depending on the data types.

Data Types

There are various data types for values.

Values can be combined using operators. The effect of an operator depends on the data types of the values.

String

Strings are text values enclosed in double quotes. For example, "Hello" is a string value. If special characters like " or newlines (\n) need to be included in the string, they can be escaped using backslashes (\).

name = "Hello \"World\""

String values are immutable. That means a string cannot be modified. New strings have to be created instead.

Operators

If the + operator has at least one string value, the string representations of the values are concatenated.

value = "Hello" + "World" // "HelloWorld"
value = "Hello " + 2 // "Hello 2"
value = 2 + " Hello" // "2 Hello"

String Operations

Here are some operations that can be performed on strings:

string.length

The length of the string.

Example: "Test".length is 4.

string.uppercase

The string in uppercase.

Example: "Test".uppercase is "TEST".

string.lowercase

The string in lowercase.

Example: "Test".lowercase is "test".

string.trim

Removes whitespace from the beginning and end of the string.

Example: " Test ".trim is "Test".

string.startsWith(string, index?)

Checks whether the string begins with the given string. Optionally, you can specify the index where to start searching.

Examples:

  • "Test".startsWith("Te") is true
  • "Test".startsWith("e") is false
  • "Test".startsWith("e", 1) is true
string.endsWith(string)

Checks whether the string ends with the given string.

Examples:

  • "Test".endsWith("Te") is false
  • "Test".endsWith("st") is true
string.slice(startIndex, endIndex?)

Creates a substring from the start index (inclusive) to the end index (exclusive). If no end index is specified, the substring goes until the end of the original string.

Examples:

  • "Test".slice(1, 3) is "es"
  • "Test".slice(1) is "est"
string.indexOf(string, index?)

Returns the start index of the first substring that begins with the given string. Optionally, you can specify the index where to start searching.

Examples:

  • "Hello".indexOf("l") is 2
  • "Hello".indexOf("l", 3) is 3
string.lastIndexOf(string, index?)

Returns the start index of the last substring that begins with the given string. Optionally, you can specify the index where to start searching.

Examples:

  • "Hello".lastIndexOf("l") is 3
  • "Hello".lastIndexOf("l", 2) is 2
string.split(regex)

Splits the string at each occurrence of the specified regex string. Returns an array containing the resulting substrings. The split operation behaves like Java's String.split(regex) method.

Example: "Test".split("e") is ["T", "st"]

Integer

Integers are numbers without a decimal point. For example, 123 is an integer value. Integer values can be positive or negative. Integer values are represented as 64-bit signed integers.

number1 = 123
number2 = -42

Operators

Operator Description Example
value + value Add 4 + 5 is 9
value - value Subtract 10 - 4 is 6
value * value Multiply 5 * 4 is 20
value / value Divide 10 / 5 is 2, 17 / 5 is 3 (integer division)
value % value Modulo 10 % 4 is 2
value ** value Pow 2 ** 5 is 32
- value Negation -(5) is -5
value < value Less than 5 < 8 is true
value <= value Less than or equal 5 <= 8 is true
value > value Greater than 5 > 8 is false
value >= value Greater than or equal 5 >= 8 is false
number++
Increments the variable number by 1 and returns the previous value.
++number
Increments the variable number by 1 and returns the new value.
number--
Decrements the variable number by 1 and returns the previous value.
--number
Decrements the variable number by 1 and returns the new value.

Float

Floats are numbers with a decimal point. For example, 3.14 is a float value. Float values can be positive or negative. Float values are represented as 64-bit floating-point numbers. Syntactically, a float is different from an integer in that it has a decimal point.

number1 = 3.14
number2 = -0.5

Floats support the same numerical operators as integers. If floats and integers are used together in a numerical operator, the result is a float.

Boolean

Boolean values can be either true or false.

hidden = true

Array

Arrays are lists of values enclosed in square brackets. For example, [1, 2, 3] is an array containing 3 integer values. Arrays can contain any data type.

array1 = [1, "Hello", true]

If values are separated by a line break, no additional comma is needed.

array2 = [
    1
    "Hello"
    true
]

With the new [number] syntax, an array with the specified length can be created. This array contains null values at each position.

array3 = new [10]

Array Operations

Here are some operations that can be performed on arrays:

array.length

The length of the array.

Example: [1, 3, 5].length is 3.

array.add(value)

Adds an element to the end of the array. If the value itself is an array, all elements from the array are added.

Example:

array = [1]
array.add(2) // array is [1, 2]
array.add([3, 4]) // array is [1, 2, 3, 4]

array.slice(startIndex, endIndex?)

Creates a copy of a subarray. The elements in the array are not copied, i.e., a shallow copy is created. The startIndex is inclusive and the endIndex is exclusive. If no endIndex is specified, the subarray ends at the end of the array. If the startIndex is greater than the endIndex, an empty array is returned.

Example:

array = [1, 2, 3, 4, 5]
array2 = array.slice(1, 3) // [2, 3]
array3 = array.slice(2) // [3, 4, 5]

array.map(function)

Applies the specified function to all elements in the array and returns a new array that contains the return values.

Example:

array = [1, 2, 3, 4, 5]
array2 = array.map(function(x) => x*2) // [2, 4, 6, 8, 10]

array.filter(function)

Applies the specified function to all elements in the array and returns a new array that contains all elements for which the boolean representation of the return value is true.

Example:

array = [1, 2, 3, 4, 5]
array2 = array.filter(function(x) => x <= 3) // [1, 2, 3]

array.sort(comparatorFunction?)

Returns an ascendingly sorted copy of the array. If a comparatorFunction is specified, it must meet the following requirements.

  • The function must accept two parameters.
  • If the first parameter is smaller than the second, the function should return a negative integer.
  • If the first parameter is larger than the second, the function should return a positive integer.
  • If both parameters are equal, the function should return 0.

If no comparatorFunction is specified, the elements are compared to each other on a best-effort basis.

Example:

array = [4, 3, 6, 9, 2]
array2 = array.sort() // [2, 3, 4, 6, 9]

array.reverse()

Returns a reverse copy of the array, where the order of the elements is reversed.

Example:

array = [1, 2, 3, 4, 5]
array2 = array.reverse() // [5, 4, 3, 2, 1]

array.join(separator?)

Concatenates the string representations of the elements of the array and returns the result. Optionally, a separator can be specified, which separates the elements.

Example:

array = ["A", "B", "C"]
str1 = array.join() // "ABC"
str2 = array.join(":") // "A:B:C"

Object

Objects are collections of key-value pairs enclosed in double curly braces. Object values can contain any data type.

Entries are separated by commas. If entries are separated by a line break, the comma is optional.

object1 = {{name: "value", number: 456, hidden: true}}
object2 = {{
    name: "value"
    number: 456
    hidden: true
}}

With the . operator, you can access a key-value pair. Both read and write access is possible.

object.key = "value"
name = object.key

The + operator merges the attributes of two objects. If both objects contain the same attribute, the value is taken from the second object. Note that the + operator creates a new object. The input objects are not modified.

object = {{ x: 5, y: 0 }} + {{ y: 3, z: 8 }} // = {{ x: 5, y: 3, z: 8 }}

The += operator works similarly to the + operator, but no new object is created. Instead, the attributes from the second object are written into the first object.

object = {{ x: 5, y: 0 }}
object += {{ y: 3, z: 8 }}
// object = {{ x: 5, y: 3, z: 8 }}

File

The Transform file of a directory can access the files in the directory by writing their name in single quotes. If the file does not exist, the value will be null.

Files behave like Objects. Files have attributes that can be read and written. There are special attributes that have certain effects on the appearance or behavior of the files (see File Customizations).

thumb = 'thumb.jpg'
'thumb.jpg'.hidden = true

this

The constant this always contains the file or directory to which the currently executed Transform file belongs.

Example: Both lines are equivalent as long as hidden is not defined as a variable.

hidden = true
this.hidden = true

filelist

The constant filelist contains an array with all files in the directory whose Transform file is currently being executed. If the Transform file of a file is being executed, filelist is an empty array.

Null

Null represents the absence of a value. It is represented as null.

attribute1 = null

If one operand of the + operator is null, the result is always the other operand, e.g., value + null = value.

When reading attributes of null, the result is always null. When writing attributes of null, nothing happens.

value = null.x // value is null
null.x = 1 // nothing happens

TextScript

TextScript is a scripting language that can be used to generate text. It is possible to use a TextScript as a value by enclosing it in grave accents (`). The TextScript is able to access attributes of the file it was assigned to. An external variable is defined for each attribute of the file.

name = `@custom; @number;`
custom = "Name"
number = 123456

'file1.txt'.name = `@custom;`
'file1.txt'.custom = "File 1"

In this example, the name of this directory will be Name 123456 and the name of file1.txt will be File 1.

TextScript values are resolved to strings after the Transform files have been run.

TextScript values are also resolved when they are converted to a string. This happens, for example, when a TextScript value is concatenated with a string using the + operator. The external variables then have the value of the corresponding attribute at the time of resolution.

Multiline TextScript

It is possible to specify a multi-line TextScript. This must be enclosed with three grave accents.

value = ```
Name: @name;
Age: @age;
```

Standard TextScript Functions

In addition to the functions that are available by default in the standard library of TextScript, there are some additional functions that can be used in TextScript values. These functions can only be used within a TextScript. These functions are not valid in other places in Transform Files. However, for some functions there are equivalents in the standard library for Transform Files.

escapeHTML(string)
Escapes all special characters to the &#00; syntax. Newlines are replaced by <br/>. Tabs and spaces may be replaced by &emsp; or &nbsp;.
toTimeString(int)

Returns a string representation of the specified amount of seconds. The format of the resulting string is h:mm:ss, mm:ss, or m:ss depending on the amount of seconds.

value = `@toTimeString(100);` // value will be "1:40"

Range

Ranges represent a range of numbers. There are integer ranges and float ranges. A range has a minimum and a maximum value. The range may contain parts of the values in between.

Ranges can be specified by using a tilde (~) between two numbers. These ranges contain all numbers between those two numbers. For example, 10 ~ 20 represents the range of numbers from 10 to 20.

Multiple ranges can be combined by using the + operator. For example, 10~20 + 30~40 represents the range of numbers from 10 to 20 and from 30 to 40, but does not include 21 to 29.

Ranges can be converted to a string using the str() function.

years = 2005~2010 + 2020~2023
name = str(years)

The name will be 2005-2010, 2020-2023.

Function

Functions are values that contain instructions. A function can be called, which executes the instructions of the function.

Functions can have parameters. Parameters are named variables that can be used in a function. When calling the function, concrete values are specified for the parameters.

Functions are created with the keyword function, followed by the list of parameter names in parentheses. The instructions are written in curly braces.

var func = function(file, name) {
    file.name = name
    file.hidden = false
}

A function can be called with the () operator. Values for the parameters must be specified in the parentheses.

func('file1.txt', "File One")
func('file2.txt', "File Two")

Return

With the return statement, a function can return a value. The return value is delivered to the caller of the function. If a return statement is executed, the function call ends immediately. Instructions after the return are not executed anymore.

var func = function(a, b) {
    return a + b
}
value = func(5, 4) // value is 9

If a return is executed without a value, or the function ends without return, the function call returns the value null.

If a function consists of a single return statement, it can also be defined with the => syntax.

var func = function(a, b) => a + b
value = func(5, 4) // value is 9

Combining Functions

Functions can be combined with all operators and all types of values. If a function is specified as an operand of an operator, the operator returns a function that executes this function and applies the operator to the return value and the other value. If both operands are functions, both functions are executed and the operator is applied to their return values. The resulting function requires the same parameters as the original function. If both values are functions, the parameters must match.

var add = function(a, b) => a + b
var multiply = function(a, b) => a * b
// equivalent to function(a, b) => (a + b) + 3
var addPlus3 = add + 3
// equivalent to function(a, b) => (a * b) - (a + b)
var func = multiply - add

Additional Operators

In addition to the datatype-dependent operators, there are also operators that can be applied to any values.

Equality Operators

The == operator compares two values and returns a boolean indicating whether they are equal. != checks whether the values are not equal.

5 == 3 // false
5 == 5 // true
3 == "3" // false
"example" == "example" // true
"a" == "b" // false
"a" != "b" // true

NOT Operator

!value applies a NOT operation to the boolean representation of value.

!true // false
!false // true
!null // true
!!null // false
!0 // false
!"example" // false

Boolean representation

The boolean representation of a value is false if and only if the value is null or the boolean value false. The boolean representation is true for all non-null values, except false.

AND and OR Operators

The AND operator value1 && value2 returns value2 if the boolean representation of value1 is true. Otherwise, value2 is not evaluated and value1 is returned. If value1 and value2 are both boolean values, this behavior results in a logical AND operation.

true && false // false
false && true // false
null && "example" // null
"example" && null // null
0 && "example" // "example"
false && "example" // false

The OR operator value1 || value2 returns value1 if the boolean representation of value1 is true. In this case, value2 is not evaluated. Otherwise, value2 is evaluated and returned. If value1 and value2 are boolean values, this behavior results in a logical OR operation.

true || true // true
false || true // true
false || "example" // "example"
"a" || "b" // "a"
null || "b" // "b"

Strict AND and OR Operators

The operators & and | behave identically to && and ||, but instead of the regular boolean representation, the strict boolean representation is used. In the strict boolean representation, in addition to null and the boolean false, the following values evaluate to false:

  • The integer 0 resolves to false
  • The float 0.0 resolves to false
  • Empty strings resolve to false
  • Empty arrays resolve to false
  • Empty ranges resolve to false
true & "example" // "example"
false & "example" // false
"" & "example" // ""
0 & true // 0
null | "a" // "a"
0 | "a" // "a"
1 | "a" // 1

Combining Comparators

The | operator can be very useful when combining separate comparator functions for sorting. A comparator function returns a positive integer if the first parameter is greater than the second parameter, a negative integer if the first parameter is less than the second parameter and 0 if both parameters are equal. Separate comparator functions, for example byName and byDate, can be combined as byName | -byDate, which returns a new comparator function that primarily sorts elements ascending by their name, and secondary by their date descending.

Type Checking Operator

With value is type, you can check whether a value has a certain type. Valid types are null, int, float, boolean, string, textscript, object, array, int_range, float_range, and function.

"example" is string // true
"example" is int // false

Ternary Operator

cond ? value1 : value2 returns value1 if the boolean representation of cond is true. Otherwise, value2 is returned.

true ? 1 : 2 // 1
false ? 1 : 2 // 2
"example" ? "a" : "b" // "a"
null ? "a" : "b" // "b"

Compound Assignment Operator

The += operator is a shorthand to combine the current value of a variable with a value using the + operator and write the result back into the variable.

variable += value
is equivalent to
variable = variable + value

Variables

With the var keyword, temporary variables can be declared. These variables can store values.

var x = 5 * 4
var y = 10 + 1
value = x + y

Variables vs. File attributes

If a value is set that was not previously declared as a variable, an attribute with the corresponding name is set for the current file. Attributes of files are stored in the main volume and can change the behavior of the files, while variables are deleted after the rebuild process ends.

value = "example" // Sets the "value" attribute of the file
var value = "example" // Sets the variable "value"

Public Variables

By default, a variable is accessible in the Transform files of a file or directory. If a variable is declared with the keyword public, it is also accessible from all Transform files of the files within the directory. If a public variable is defined in the Transform file of a directory, it can be read by the Transform files of all files in that directory, but not written.

In particular, public variables can be used to define functions that can be called in the Transform files of files in a directory.

Example:

transform.txt in the root directory
public var setName = function(file, name) {
    file.name = name
}

transform.txt in dir/
setName('file.txt', "File") // Sets the name of dir/file.txt

Control Statements

With control statements, the program flow can be changed.

if Statement

With an if statement, part of the program is only executed if a condition is true. The condition must be written in parentheses. The condition is evaluated based on the boolean representation. After an if block, an optional else block can be specified, which is only executed if the condition is false. It is also possible to combine if and else to else if.

if (value == "example") {
    attr = 1
} else if (value == "test") {
    value = 2
} else {
    value = 0
}

while Loop

A while loop is executed as long as a condition has the boolean representation true.

var value = 0
while (value < 10) {
    array[value] = "example"
    value++
}

The break statement can be used to exit the loop before the condition is false. The continue statement can be used to jump directly to the next iteration.

for Loop

The for loop works similarly to the while loop but offers a more compact syntax for declaration, condition, and increment.

for (var value = 0; value < 10; value++) {
    array[value] = "example"
}

With the for each loop, you can iterate over all values of an array.

var array = [3, 5, 2]
var sum = 0
for (value : array) {
    sum += value
}
// sum is 10

As with the while loop, you can use break to exit the loop prematurely and continue to jump to the next iteration.

Command Syntax

The command syntax is an alternative for calling functions. A command consists of a command name and multiple parameters, separated by spaces. The command name is the function to call. The basic syntax of a command is command_name parameter1 parameter2 .... Each command has to be on a separate line. Commands that don't exist are ignored.

rename 'file.txt' "File Name"
hide 'file2.txt'
nonexistent 'file.txt' // Nothing happens

History

In PFS 1.x, the command syntax was used for almost all operations that a Transform file can perform. Functions exist since PFS 2.x. Before that, commands were hard-coded operations.

Execution Order of Transform Files

Top-Down Transform Files

Top-Down Transform Files can be named transform.txt. These are executed before the Transform Files of the files within this directory.

Usually, data is set within Top-Down Transform Files. Also, Top-Down Transform Files are particularly well suited for defining public variables so that they are already defined when the inner Transform Files are executed.

Bottom-Up Transform Files

In contrast, Bottom-Up Transform Files are executed after the Transform Files of the files within this directory have been executed. Bottom-Up Transform Files must be named transform.bottomup.txt.

With Bottom-Up Transform Files, data from the inner files can be processed programmatically.

Example:

dir/file.txt.transform.txt
title = "File"
year = 2026

dir/transform.txt
for (f : filelist) {
    f.name = f.title + " (" + f.year + ")"
}

Hooks

Hooks are functions executed for all files and directories located in a directory. Hooks are also executed for deeply nested files.

The hook is executed in the context of the respective file, i.e., this and filelist refer to the respective file or directory for which the hook is currently being executed.

In general, hooks should be defined in Top-Down Transform Files so that they are defined before the Transform Files of the inner files are executed. Defining hooks in Bottom-Up Transform Files or other hooks can lead to undesirable behavior.

Top-Down Hooks

Top-Down Hooks are executed before the Top-Down Transform Files of a folder or file are executed. Accordingly, a top-down hook is not run for the folder that defines the hook.

A top-down hook is registered using the function topdownHook(function).

Example:

transform.txt of dir/
topdownHook(function() {
    this.name = "File: " + this.name
})

transform.txt of dir/special.txt
name = "Special Name"

This example results in the following names.

File Name Reason
dir/ dir Top-down hook is not run for the defining folder
o/ o o is not inside dir
dir/file.txt File: file.txt Hook is run for files
dir/x/ File: x Hook is run for folders
dir/x/y.txt File: y.txt Hook is run for nested files
dir/special.txt Special Name Top-Down Transform File overwrites the name

Bottom-Up Hooks

Bottom-Up Hooks are executed after the Bottom-Up Transform Files of a file or directory have been executed. Specifically, bottom-up hooks are run for directories after all Transform Files of all files in this folder have been executed. Bottom-up hooks are also executed for the directory itself that defines the hook.

A bottom-up hook is registered using the function bottomupHook(function).

Example:

transform.txt of dir/
bottomupHook(function() {
    this.name = "File: " + this.name
})

transform.txt of dir/special.txt
name = "Special Name"

This example results in the following names.

File Name Reason
dir/ "File: dir" Bottom-up hook is run for the defining folder
o/ o o is not inside dir
dir/file.txt File: file.txt Hook is run for files
dir/x/ File: x Hook is run for folders
dir/x/y.txt File: y.txt Hook is run for nested files
dir/special.txt File: Special Name Bottom-up hook is run after the Transform File

Standard Library

There are some functions and constants that are available by default.

str(value)
Converts the value into its string representation and returns it. If the value is null, null is returned.
toInt(value)
Converts the value into an integer and returns it. If the value is a string, the string is parsed to an integer. If the value is null, null is returned.
toFloat(value)
Converts the value into a float and returns it. If the value is a string, the string is parsed to a float. If the value is null, null is returned.
file(string|file)

If a string is specified, the file with the specified name is returned. file("name") is equivalent to the single-quote syntax to get the file: 'name'. If no file with the specified name exists, null is returned. It is not possible to access deeply nested files using this function. If a file value is specified, this file value is returned. If null is specified, null is returned.

This function is useful for dynamically retrieving file objects with non-constant names. For example, file("file_" + num + ".txt").

filename(file|string)
Returns the filename of the specified file. The filename is the part of the name before the last ., or the full name if the name does not contain a .. For example, the filename of example.txt is example, the filename of test.file.txt is test.file, and the filename of test is test. If a string is specified, the string is interpreted as the full name. It doesn't matter whether the file exists or not. If null is specified, null is returned.
fileext(file|string)
Returns the extension of the specified file. The extension is the part of the name after the last ., or the full name if the name does not contain a .. For example, the extension of example.txt is txt, and the extension of test is test. If a string is specified, the string is interpreted as the full name. It doesn't matter whether the file exists or not. If null is specified, null is returned.
readfile(file|string)

Reads the specified text file and returns the file's content as a string. The charset of the file is assumed to be UTF-8. The file may be specified by its name. If the file does not exist or is a directory, null is returned.

This function is useful for outsourcing larger amounts of data from the Transform File to other files. For example, this.info = readfile('info.txt') outsources the description to an info.txt file.

escapeHTML(string)
Escapes all special characters to the &#00; syntax. Newlines are replaced by <br/>. Tabs and spaces may be replaced by &emsp; or &nbsp;. If null is specified, null is returned.
toTimeString(int)
Returns a string representation of the specified number of seconds. The format of the resulting string is h:mm:ss, mm:ss, or m:ss, depending on the number of seconds. For example, toTimeString(100) returns "1:40". If null is specified, null is returned.
parseTimeString(string)
The reverse function of toTimeString. Accepts a duration as a string in the format h:mm:ss, mm:ss, or m:ss, and returns the number of seconds. For example, parseTimeString("1:40") returns 100. If null is specified, null is returned.

Logging

For debugging, the function debug(value) should be used. It outputs the specified value together with the type of the value as a debug message in the console during the rebuild process. This requires the TomatenHTTP server to be configured to log debug messages.

To log data, use the log(logFileName, string) function. This saves the log entries in a log file located in the main volume instead of outputting them in the console. For this purpose, a line with the specified string is appended to the file with the specified name in the logs folder of the main volume.

Note that each call to the log function adds a line to the log file. When collecting statistics, it is often desirable to generate only one line per rebuild process. In this case, it is recommended to call the log function in a transform.bottomup.txt in the root folder.

As with all functions, debug and log can also be called with the command syntax.

debug "Hello World"
log "example.log" "Hello World"

Sorting

By default, the file list of a directory is sorted on a best-effort basis. Among other things, the name of the file is considered, as well as whether it is a folder or a file.

If a custom sorting is desired, the current filelist can be sorted using the sort(comparator) function. The sorting happens in-place and has a direct effect on the filelist variable, as well as the order in which files are displayed in the UI. The sort function expects a comparator function that takes two files to compare. The return value of the comparator function is an integer that indicates which of the two files should be before the other.

  • A negative integer means the first file should be before the second file.
  • A positive integer means the first file should be after the second file.
  • 0 means the order of the two files does not matter.

This comparator function can be implemented arbitrarily. There are some helper functions to easily describe custom criteria for sorting.

compare(value1, value2)
A helper function that compares two arbitrary values based on their natural order. For example, compare(5, 7) returns a negative integer, and compare("B", "A") returns a positive integer. The compare function cannot be used to compare objects, arrays, functions, or files, as they do not have a defined natural order.
byDefault
A comparator function for files that implements the default sorting of files. If a comparator is implemented that does not specify a unique sort order, it is recommended to call byDefault(file1, file2) as the last comparison criteria.
byAsc(attributeName|function)
A function that generates and returns a comparator function for files or objects. If an attribute name is specified as a string, byAsc returns a comparator function that compares the given attribute for both objects or files based on their natural order, resulting in an ascending sort order. If a function is specified, this function is applied to the objects or files to be compared to obtain the respective values, which are then compared based on their natural order. Therefore, byAsc("attribute") is equivalent to byAsc(function (obj) => obj.attribute).
byDsc(attributeName|function)
As a counterpart to byAsc, this function compares the values in such a way that a descending sort order is created.

byAsc and byDsc can be used in combination with Combining Functions and the | operator (strict OR) to define custom comparator functions. For example, byDsc("size") | byAsc("example") | byDefault results in a comparator function for files that sorts first by file size in descending order, then by the attr attribute in ascending order, and if both were identical, by the default sort order.

Mathematical Functions

Usage Description
PI The constant PI, approximately 3.14
sin(float) Sine of a radian angle
cos(float) Cosine of a radian angle
tan(float) Tangent of a radian angle
asin(float) Arcsine
acos(float) Arccosine
atan(float) Arctangent
exp(float) e^x
floor(float) Largest float that is less than or equal to the specified value and equal to an integer
ceil(float) Smallest float that is greater than or equal to the specified value and equal to an integer
sqrt(float) Square root
log10(float) Base 10 logarithm
ln(float) Natural logarithm (base e)