Part of the Scripting Language reference.
Only whitelisted methods can be called on values. Calling a non-whitelisted method throws a security error.
String methods (29)
| Method |
Description |
s.charAt(i) |
Character at index |
s.charCodeAt(i) |
Character code at index |
s.codePointAt(i) |
Unicode code point at index |
s.concat(...strs) |
Concatenate strings |
s.endsWith(str) |
Check if ends with substring |
s.includes(str) |
Check if contains substring |
s.indexOf(str) |
First index of substring (-1 if absent) |
s.lastIndexOf(str) |
Last index of substring |
s.localeCompare(str) |
Locale-aware comparison (-1, 0, or 1) |
s.match(regex) |
Match against regex |
s.matchAll(regex) |
All matches as array of arrays |
s.normalize(form) |
Unicode normalization (NFC, NFD, etc.) |
s.padEnd(len, fill) |
Pad end to target length |
s.padStart(len, fill) |
Pad start to target length |
s.repeat(n) |
Repeat string n times |
s.replace(find, rep) |
Replace first occurrence |
s.replaceAll(find, rep) |
Replace all occurrences |
s.search(regex) |
Search for regex match position |
s.slice(start, end) |
Extract substring by indices |
s.split(sep) |
Split into array |
s.startsWith(str) |
Check if starts with substring |
s.substring(start, end) |
Extract substring |
s.toLowerCase() |
Convert to lowercase |
s.toUpperCase() |
Convert to uppercase |
s.trim() |
Remove whitespace from both ends |
s.trimStart() |
Remove whitespace from start |
s.trimEnd() |
Remove whitespace from end |
s.at(i) |
Character at index (negative supported) |
s.toString() |
Convert to string |
let s = "Hello, World!"
log(s.charAt(0)) // => H
log(s.includes("World")) // => true
log(s.indexOf("World")) // => 7
log(s.slice(0, 5)) // => Hello
log(s.split(", ")) // => [Hello, World!]
log(s.toLowerCase()) // => hello, world!
log(s.toUpperCase()) // => HELLO, WORLD!
log(s.trim()) // => Hello, World!
log(s.replace("World", "there")) // => Hello, there!
log(s.at(-1)) // => !
log("42".padStart(5, "0")) // => 00042
log("ha".repeat(3)) // => hahaha
matchAll - returns all regex matches:
let text = "cat bat hat"
let re = RegExp.create("[a-z]at", "g")
let matches = text.matchAll(re)
log(matches.length) // => 3
String smart value methods (28)
Automation-compatible methods callable on any string. All methods returning strings are chainable.
Text manipulation
| Method |
Description |
s.capitalize() |
First letter uppercase, rest unchanged |
s.abbreviate(maxLen) |
Shorten with “…” suffix (maxLen >= 4) |
s.left(n) |
First n characters |
s.right(n) |
Last n characters |
s.remove(sub) |
Remove all occurrences of sub |
s.reverse() |
Reverse string (unicode-safe) |
log("hello world".capitalize()) // => Hello world
log("hello world".abbreviate(8)) // => hello...
log("hello".left(3)) // => hel
log("hello".right(3)) // => llo
log("a.b.c".remove(".")) // => abc
log("hello".reverse()) // => olleh
| Method |
Description |
s.substringBefore(sep) |
Text before first occurrence of sep |
s.substringAfter(sep) |
Text after first occurrence of sep |
s.substringBetween(open, close?) |
Text between delimiters (null if not found) |
log("user@example.com".substringBefore("@")) // => user
log("user@example.com".substringAfter("@")) // => example.com
log("(hello)".substringBetween("(", ")")) // => hello
log("*bold*".substringBetween("*")) // => bold
Checks
| Method |
Description |
s.isEmpty() |
True if length is 0 |
s.isNotEmpty() |
True if length > 0 |
s.isBlank() |
True if empty or whitespace only |
s.isNotBlank() |
True if contains non-whitespace |
s.equalsIgnoreCase(other) |
Case-insensitive comparison |
s.isAlpha() |
Only letters (a-zA-Z), non-empty |
s.isAlphanumeric() |
Only letters and digits, non-empty |
s.isNumeric() |
Only digits (0-9), non-empty |
log("".isEmpty()) // => true
log(" ".isBlank()) // => true
log("Hello".equalsIgnoreCase("HELLO")) // => true
log("abc".isAlpha()) // => true
log("abc123".isAlphanumeric()) // => true
log("12345".isNumeric()) // => true
Conversion
| Method |
Description |
s.asNumber() |
Convert to number, null if invalid |
log("42".asNumber()) // => 42
log("3.14".asNumber()) // => 3.14
log("abc".asNumber()) // => null
Encoding
| Method |
Description |
s.htmlEncode() |
Escape & < > " ' as HTML entities |
s.jsonEncode() |
Escape \ " \n \r \t for JSON embedding |
s.xmlEncode() |
Escape & < > " ' as XML entities |
s.urlEncode() |
URL-encode (encodeURIComponent) |
s.quote() |
Escape regex special characters |
log("<b>A & B</b>".htmlEncode()) // => <b>A & B</b>
log('say "hello"'.jsonEncode()) // => say \"hello\"
log("<tag>".xmlEncode()) // => <tag>
log("hello world".urlEncode()) // => hello%20world
log("a.b*c".quote()) // => a\.b\*c
Case conversion and word splitting
| Method |
Description |
s.camelCase() |
“hello world” -> “helloWorld” |
s.kebabCase() |
“helloWorld” -> “hello-world” |
s.snakeCase() |
“helloWorld” -> “hello_world” |
s.words() |
Split into array of words (camelCase-aware) |
s.lines() |
Split by newline into array |
log("hello world".camelCase()) // => helloWorld
log("helloWorld".kebabCase()) // => hello-world
log("helloWorld".snakeCase()) // => hello_world
log("helloWorld".words()) // => [hello, World]
log("a\nb\nc".lines()) // => [a, b, c]
Chaining
All methods returning strings can be chained with each other and with native string methods:
log(" hello world ".trim().capitalize().abbreviate(8)) // => Hello...
log("user@example.com".substringBefore("@").capitalize()) // => User
log("HELLO WORLD".toLowerCase().capitalize()) // => Hello world
Array methods
Non-callback methods (23)
| Method |
Description |
a.push(...vals) |
Add to end, return new length |
a.pop() |
Remove and return last element |
a.shift() |
Remove and return first element |
a.unshift(...vals) |
Add to start, return new length |
a.concat(...arrs) |
Merge arrays |
a.slice(start, end) |
Extract sub-array |
a.splice(i, del, ...add) |
Remove/insert elements |
a.indexOf(val) |
First index of value |
a.lastIndexOf(val) |
Last index of value |
a.includes(val) |
Check if contains value |
a.join(sep) |
Join elements into string |
a.reverse() |
Reverse in place |
a.at(i) |
Element at index (negative supported) |
a.flat(depth) |
Flatten nested arrays |
a.fill(val, start, end) |
Fill with value |
a.copyWithin(t, s, e) |
Copy elements within array |
a.with(index, value) |
Return copy with one element replaced |
a.toReversed() |
Return reversed copy (original unchanged) |
a.toSpliced(i, del, ...add) |
Return spliced copy (original unchanged) |
a.keys() |
Array of indices |
a.values() |
Array of values |
a.entries() |
Array of [index, value] pairs |
a.toString() |
String representation |
let arr = [3, 1, 4, 1, 5]
log(arr.indexOf(4)) // => 2
log(arr.includes(5)) // => true
log(arr.slice(1, 3)) // => [1, 4]
log(arr.join("-")) // => 3-1-4-1-5
log(arr.at(-1)) // => 5
let nested = [[1, 2], [3, [4, 5]]]
log(nested.flat()) // => [1, 2, 3, [4, 5]]
log(nested.flat(2)) // => [1, 2, 3, 4, 5]
Immutable methods:
let arr = [3, 1, 4]
log(arr.toReversed()) // => [4, 1, 3]
log(arr) // => [3, 1, 4] (unchanged)
log(arr.with(1, 99)) // => [3, 99, 4]
log(arr) // => [3, 1, 4] (unchanged)
Callback methods (15)
| Method |
Description |
a.map(fn) |
Transform each element |
a.filter(fn) |
Keep elements where fn returns true |
a.find(fn) |
First element where fn returns true |
a.findIndex(fn) |
Index of first match |
a.findLast(fn) |
Last element where fn returns true |
a.findLastIndex(fn) |
Index of last match |
a.every(fn) |
True if fn returns true for all |
a.some(fn) |
True if fn returns true for any |
a.forEach(fn) |
Execute fn for each element |
a.reduce(fn, init) |
Reduce to single value (left to right) |
a.reduceRight(fn, init) |
Reduce to single value (right to left) |
a.flatMap(fn) |
Map then flatten one level |
a.sort(fn) |
Sort in place with comparator |
a.toSorted(fn) |
Return sorted copy (original unchanged) |
a.group(fn) |
Group elements into object by key function |
let nums = [1, 2, 3, 4, 5]
log(nums.map(x => x * 2)) // => [2, 4, 6, 8, 10]
log(nums.filter(x => x > 3)) // => [4, 5]
log(nums.find(x => x > 3)) // => 4
log(nums.every(x => x > 0)) // => true
log(nums.some(x => x > 4)) // => true
log(nums.reduce((sum, x) => sum + x, 0)) // => 15
group - group elements by key:
let nums = [1, 2, 3, 4, 5]
let grouped = nums.group(n => n % 2 === 0 ? "even" : "odd")
log(grouped.odd) // => [1, 3, 5]
log(grouped.even) // => [2, 4]
toSorted - sorted copy without mutating:
let arr = [3, 1, 4]
let sorted = arr.toSorted((a, b) => a - b)
log(sorted) // => [1, 3, 4]
log(arr) // => [3, 1, 4] (unchanged)
Array smart value methods (9)
Automation-compatible aggregation and access methods on arrays.
| Method |
Returns |
Description |
a.first() |
any/null |
First element, null if empty |
a.last() |
any/null |
Last element, null if empty |
a.size() |
number |
Number of elements |
a.isEmpty() |
boolean |
True if empty |
a.distinct() |
array |
Unique elements (preserves order) |
a.sum() |
number |
Sum of numeric elements (skips non-numeric) |
a.average() |
number |
Average of numeric elements |
a.min() |
number/null |
Minimum numeric value, null if none |
a.max() |
number/null |
Maximum numeric value, null if none |
log([10, 20, 30].first()) // => 10
log([10, 20, 30].last()) // => 30
log([].first()) // => null
log([1, 2, 3].size()) // => 3
log([].isEmpty()) // => true
log([1, 2, 2, 3, 1].distinct()) // => [1, 2, 3]
log([10, 20, 30].sum()) // => 60
log([10, 20, 30].average()) // => 20
log([5, 2, 8, 1].min()) // => 1
log([5, 2, 8, 1].max()) // => 8
// Non-numeric values are skipped in sum/average/min/max
log([1, "two", 3].sum()) // => 4
// Chaining with native methods
log([3, 1, 2, 1].distinct().toSorted((a,b) => a-b).first()) // => 1
Date navigation and presets
Comparison
| Method |
Returns |
Description |
d.compareTo(other) |
number |
-1, 0, or 1 |
Start/end navigation
| Method |
Returns |
Description |
d.startOfDay() |
Date |
Midnight UTC |
d.endOfDay() |
Date |
23:59:59.999 UTC |
d.startOfMonth() |
Date |
First day of month |
d.endOfMonth() |
Date |
Last day of month |
d.startOfYear() |
Date |
January 1st |
d.endOfYear() |
Date |
December 31st |
Day-of-week navigation
| Method |
Returns |
Description |
d.withNextDayOfWeek(day) |
Date |
Next given weekday (min +1 day) |
d.firstOfTheMonth(day) |
Date |
First given weekday in month |
d.lastOfTheMonth(day) |
Date |
Last given weekday in month |
Day names: monday, tuesday, wednesday, thursday, friday, saturday, sunday (or short: mon, tue, wed, thu, fri, sat, sun).
| Method |
Example Output |
Description |
d.jiraDate() |
2024-06-15 |
YYYY-MM-DD |
d.jiraDateTime() |
2024-06-15T14:30:45.123Z |
ISO 8601 |
d.shortDate() |
6/15/24 |
M/D/YY |
d.shortTime() |
2:30 PM |
h:mm AM/PM |
d.shortDateTime() |
6/15/24 2:30 PM |
Short date + time |
d.mediumDate() |
Jun 15, 2024 |
MMM D, YYYY |
d.mediumTime() |
2:30:45 PM |
h:mm:ss AM/PM |
d.mediumDateTime() |
Jun 15, 2024 2:30:45 PM |
Medium date + time |
d.longDate() |
June 15, 2024 |
Full month name |
d.longDateTime() |
June 15, 2024 2:30:45 PM UTC |
Long date + time + UTC |
d.fullDate() |
Saturday, June 15, 2024 |
Day + full date |
d.fullDateTime() |
Saturday, June 15, 2024 2:30:45 PM UTC |
Full day + date + time |
Additional tokens for format():
| Token |
Description |
Example |
MMMM |
Full month name |
June |
MMM |
Short month name |
Jun |
M |
Month without padding |
6 |
d |
Day without padding |
5 |
H |
24h hour without padding |
9 |
h |
12h hour without padding |
2 |
m |
Minute without padding |
5 |
s |
Second without padding |
3 |
Business days
| Method |
Returns |
Description |
d.isBusinessDay() |
boolean |
Mon-Fri |
d.toBusinessDay() |
Date |
Move weekend to next Monday |
d.toBusinessDayBackwards() |
Date |
Move weekend to previous Friday |
d.plusBusinessDays(n) |
Date |
Add n business days (max 10000) |
d.minusBusinessDays(n) |
Date |
Subtract n business days (max 10000) |
d.firstBusinessDayOfMonth() |
Date |
First weekday of month |
d.lastBusinessDayOfMonth() |
Date |
Last weekday of month |
let d = Date.create("2024-06-15T14:30:00Z") // Saturday
// Navigation
log(d.startOfDay().toISOString()) // => 2024-06-15T00:00:00.000Z
log(d.endOfMonth().jiraDate()) // => 2024-06-30
log(d.withNextDayOfWeek("monday").jiraDate()) // => 2024-06-17
// Format presets
log(d.jiraDate()) // => 2024-06-15
log(d.mediumDate()) // => Jun 15, 2024
log(d.fullDate()) // => Saturday, June 15, 2024
// Business days
log(d.isBusinessDay()) // => false (Saturday)
log(d.toBusinessDay().jiraDate()) // => 2024-06-17 (Monday)
log(d.startOfMonth().plusBusinessDays(3).jiraDate()) // => 2024-06-05
Date timezone
Two methods for working with timezones. Both accept IANA timezone names (e.g. "America/New_York", "Asia/Tokyo", "Europe/London").
setTimeZone - display only
Changes how the date is displayed without changing the underlying timestamp. Affects format(), all format presets, and toString(). Does not affect getTime(), getUTC*(), arithmetic, or navigation.
let d = Date.create("2024-06-15T14:30:00Z")
// UTC 14:30 -> New York (UTC-4) = 10:30
log(d.setTimeZone("America/New_York").format("HH:mm")) // => 10:30
// Timestamp is unchanged
log(d.setTimeZone("Asia/Tokyo").getTime() === d.getTime()) // => true
// longDateTime/fullDateTime show timezone name
log(d.setTimeZone("America/New_York").longDateTime())
// => June 15, 2024 10:30:00 AM America/New_York
convertToTimeZone - real conversion
Converts to another timezone by shifting the timestamp. The UTC components of the new Date equal the wall clock in the target timezone. Useful for navigation operations like getting midnight in a specific timezone.
let d = Date.create("2024-06-15T14:30:00Z")
// UTC 14:30 -> New York (UTC-4): getUTCHours() = 10
let ny = d.convertToTimeZone("America/New_York")
log(ny.getUTCHours()) // => 10
// Get midnight in Tokyo
log(d.convertToTimeZone("Asia/Tokyo").startOfDay().jiraDate())
// => 2024-06-15
Difference between setTimeZone and convertToTimeZone
setTimeZone: Same moment in time, different display. Use for formatting output.
convertToTimeZone: Different moment in time, UTC components = wall clock. Use before navigation (startOfDay, endOfMonth) when you need timezone-aware boundaries.
Number methods (6)
| Method |
Description |
n.toFixed(d) |
Format with d decimal places |
n.toPrecision(p) |
Format with p significant digits |
n.toExponential(d) |
Format in exponential notation |
n.toString(radix) |
Convert to string (optional radix) |
n.toLocaleString() |
Format with locale-specific formatting |
n.valueOf() |
Primitive numeric value |
let pi = 3.14159
log(pi.toFixed(2)) // => 3.14
log(pi.toPrecision(4)) // => 3.142
log((255).toString(16)) // => ff
log((1234567).toLocaleString()) // => 1,234,567
Object methods (3)
| Method |
Description |
o.hasOwnProperty(key) |
Check if object has own property |
o.toString() |
String representation |
o.valueOf() |
Primitive value |
let obj = { a: 1, b: 2 }
log(obj.hasOwnProperty("a")) // => true
log(obj.hasOwnProperty("c")) // => false
User wrapper
Users.current() and Users.get(accountId) return frozen User objects with typed properties.
| Property |
Description |
displayName |
User display name |
accountId |
Atlassian account ID |
emailAddress |
User email address |
avatarUrl |
Avatar URL (48x48) |
active |
Is account active (default: false) |
timeZone |
User timezone |
locale |
User locale |
accountType |
Account type |
self |
REST API URL |
| Method |
Return |
Description |
toString() |
string |
displayName or accountId or “Unknown User” |
toJSON() |
object |
Plain object without internal fields |
equals(other) |
boolean |
Compare by accountId |
RichIssue also exposes:
issue.assigneeUser - Assignee as User wrapper (null if unassigned)
issue.reporterUser - Reporter as User wrapper
issue.projectObj - Project as Project wrapper
const user = Users.current()
log(user.displayName) // => John Doe
log(user.timeZone) // => America/New_York
const issue = Issues.get("TEST-1")
log(issue.assigneeUser?.displayName)
log(issue.reporterUser?.equals(user))
Project wrapper
Projects.get(key) returns a frozen Project object with typed properties and async methods.
| Property |
Description |
key |
Project key |
name |
Project name |
id |
Project ID |
projectTypeKey |
Project type (software, etc.) |
simplified |
Is simplified project (default: false) |
description |
Project description |
lead |
Project lead (User wrapper or null) |
avatarUrl |
Avatar URL (48x48) |
self |
REST API URL |
url |
Project URL |
| Method |
Return |
Description |
toString() |
string |
Project key |
toJSON() |
object |
Plain object without internal fields |
equals(other) |
boolean |
Compare by key |
getComponents() |
array |
Project components |
getVersions() |
array |
Project versions |
getStatuses() |
array |
Project statuses |
getRoles() |
object |
Project roles |
const proj = Projects.get("PROJ")
log(proj.name) // => My Project
log(proj.lead?.displayName) // => Jane Lead
const comps = proj.getComponents()
Next steps