Move getSequentialName to shared-core
This commit is contained in:
parent
586591aa6a
commit
3be9655bcf
|
@ -1,113 +1,5 @@
|
|||
/**
|
||||
* Duplicates a name with respect to a collection of existing names
|
||||
* e.g.
|
||||
* name all names result
|
||||
* ------ ----------- --------
|
||||
* ("foo") ["foo"] "foo 1"
|
||||
* ("foo") ["foo", "foo 1"] "foo 2"
|
||||
* ("foo 1") ["foo", "foo 1"] "foo 2"
|
||||
* ("foo") ["foo", "foo 2"] "foo 1"
|
||||
*
|
||||
* Repl
|
||||
*/
|
||||
export const duplicateName = (name: string, allNames: string[]) => {
|
||||
const duplicatePattern = new RegExp(`\\s(\\d+)$`)
|
||||
const baseName = name.split(duplicatePattern)[0]
|
||||
const isDuplicate = new RegExp(`${baseName}\\s(\\d+)$`)
|
||||
// export * from
|
||||
import { helpers } from "@budibase/shared-core"
|
||||
|
||||
// get the sequence from matched names
|
||||
const sequence: number[] = []
|
||||
allNames.filter(n => {
|
||||
if (n === baseName) {
|
||||
return true
|
||||
}
|
||||
const match = n.match(isDuplicate)
|
||||
if (match) {
|
||||
sequence.push(parseInt(match[1]))
|
||||
return true
|
||||
}
|
||||
return false
|
||||
})
|
||||
sequence.sort((a, b) => a - b)
|
||||
// get the next number in the sequence
|
||||
let number
|
||||
if (sequence.length === 0) {
|
||||
number = 1
|
||||
} else {
|
||||
// get the next number in the sequence
|
||||
for (let i = 0; i < sequence.length; i++) {
|
||||
if (sequence[i] !== i + 1) {
|
||||
number = i + 1
|
||||
break
|
||||
}
|
||||
}
|
||||
if (!number) {
|
||||
number = sequence.length + 1
|
||||
}
|
||||
}
|
||||
|
||||
return `${baseName} ${number}`
|
||||
}
|
||||
|
||||
/**
|
||||
* More flexible alternative to the above function, which handles getting the
|
||||
* next sequential name from an array of existing items while accounting for
|
||||
* any type of prefix, and being able to deeply retrieve that name from the
|
||||
* existing item array.
|
||||
*
|
||||
* Examples with a prefix of "foo":
|
||||
* [] => "foo"
|
||||
* ["foo"] => "foo2"
|
||||
* ["foo", "foo6"] => "foo7"
|
||||
*
|
||||
* Examples with a prefix of "foo " (space at the end):
|
||||
* [] => "foo"
|
||||
* ["foo"] => "foo 2"
|
||||
* ["foo", "foo 6"] => "foo 7"
|
||||
*
|
||||
* @param items the array of existing items
|
||||
* @param prefix the string prefix of each name, including any spaces desired
|
||||
* @param getName optional function to extract the name for an item, if not a
|
||||
* flat array of strings
|
||||
*/
|
||||
export const getSequentialName = <T extends any>(
|
||||
items: T[] | null,
|
||||
prefix: string | null,
|
||||
{
|
||||
getName,
|
||||
numberFirstItem,
|
||||
separator = "",
|
||||
}: {
|
||||
getName?: (item: T) => string
|
||||
numberFirstItem?: boolean
|
||||
separator?: string
|
||||
} = {}
|
||||
) => {
|
||||
if (!prefix?.length) {
|
||||
return ""
|
||||
}
|
||||
const trimmedPrefix = prefix.trim()
|
||||
const firstName = numberFirstItem ? `${prefix}1` : trimmedPrefix
|
||||
if (!items?.length) {
|
||||
return firstName
|
||||
}
|
||||
let max = 0
|
||||
items.forEach(item => {
|
||||
const name = getName?.(item) ?? item
|
||||
if (typeof name !== "string" || !name.startsWith(trimmedPrefix)) {
|
||||
return
|
||||
}
|
||||
const split = name.split(trimmedPrefix)
|
||||
if (split.length !== 2) {
|
||||
return
|
||||
}
|
||||
if (split[1].trim() === "") {
|
||||
split[1] = "1"
|
||||
}
|
||||
const num = parseInt(split[1])
|
||||
if (num > max) {
|
||||
max = num
|
||||
}
|
||||
})
|
||||
return max === 0 ? firstName : `${prefix}${separator}${max + 1}`
|
||||
}
|
||||
export const duplicateName = helpers.duplicateName
|
||||
export const getSequentialName = helpers.getSequentialName
|
||||
|
|
|
@ -0,0 +1,113 @@
|
|||
/**
|
||||
* Duplicates a name with respect to a collection of existing names
|
||||
* e.g.
|
||||
* name all names result
|
||||
* ------ ----------- --------
|
||||
* ("foo") ["foo"] "foo 1"
|
||||
* ("foo") ["foo", "foo 1"] "foo 2"
|
||||
* ("foo 1") ["foo", "foo 1"] "foo 2"
|
||||
* ("foo") ["foo", "foo 2"] "foo 1"
|
||||
*
|
||||
* Repl
|
||||
*/
|
||||
export const duplicateName = (name: string, allNames: string[]) => {
|
||||
const duplicatePattern = new RegExp(`\\s(\\d+)$`)
|
||||
const baseName = name.split(duplicatePattern)[0]
|
||||
const isDuplicate = new RegExp(`${baseName}\\s(\\d+)$`)
|
||||
|
||||
// get the sequence from matched names
|
||||
const sequence: number[] = []
|
||||
allNames.filter(n => {
|
||||
if (n === baseName) {
|
||||
return true
|
||||
}
|
||||
const match = n.match(isDuplicate)
|
||||
if (match) {
|
||||
sequence.push(parseInt(match[1]))
|
||||
return true
|
||||
}
|
||||
return false
|
||||
})
|
||||
sequence.sort((a, b) => a - b)
|
||||
// get the next number in the sequence
|
||||
let number
|
||||
if (sequence.length === 0) {
|
||||
number = 1
|
||||
} else {
|
||||
// get the next number in the sequence
|
||||
for (let i = 0; i < sequence.length; i++) {
|
||||
if (sequence[i] !== i + 1) {
|
||||
number = i + 1
|
||||
break
|
||||
}
|
||||
}
|
||||
if (!number) {
|
||||
number = sequence.length + 1
|
||||
}
|
||||
}
|
||||
|
||||
return `${baseName} ${number}`
|
||||
}
|
||||
|
||||
/**
|
||||
* More flexible alternative to the above function, which handles getting the
|
||||
* next sequential name from an array of existing items while accounting for
|
||||
* any type of prefix, and being able to deeply retrieve that name from the
|
||||
* existing item array.
|
||||
*
|
||||
* Examples with a prefix of "foo":
|
||||
* [] => "foo"
|
||||
* ["foo"] => "foo2"
|
||||
* ["foo", "foo6"] => "foo7"
|
||||
*
|
||||
* Examples with a prefix of "foo " (space at the end):
|
||||
* [] => "foo"
|
||||
* ["foo"] => "foo 2"
|
||||
* ["foo", "foo 6"] => "foo 7"
|
||||
*
|
||||
* @param items the array of existing items
|
||||
* @param prefix the string prefix of each name, including any spaces desired
|
||||
* @param getName optional function to extract the name for an item, if not a
|
||||
* flat array of strings
|
||||
*/
|
||||
export const getSequentialName = <T extends any>(
|
||||
items: T[] | null,
|
||||
prefix: string | null,
|
||||
{
|
||||
getName,
|
||||
numberFirstItem,
|
||||
separator = "",
|
||||
}: {
|
||||
getName?: (item: T) => string
|
||||
numberFirstItem?: boolean
|
||||
separator?: string
|
||||
} = {}
|
||||
) => {
|
||||
if (!prefix?.length) {
|
||||
return ""
|
||||
}
|
||||
const trimmedPrefix = prefix.trim()
|
||||
const firstName = numberFirstItem ? `${prefix}1` : trimmedPrefix
|
||||
if (!items?.length) {
|
||||
return firstName
|
||||
}
|
||||
let max = 0
|
||||
items.forEach(item => {
|
||||
const name = getName?.(item) ?? item
|
||||
if (typeof name !== "string" || !name.startsWith(trimmedPrefix)) {
|
||||
return
|
||||
}
|
||||
const split = name.split(trimmedPrefix)
|
||||
if (split.length !== 2) {
|
||||
return
|
||||
}
|
||||
if (split[1].trim() === "") {
|
||||
split[1] = "1"
|
||||
}
|
||||
const num = parseInt(split[1])
|
||||
if (num > max) {
|
||||
max = num
|
||||
}
|
||||
})
|
||||
return max === 0 ? firstName : `${prefix}${separator}${max + 1}`
|
||||
}
|
|
@ -7,3 +7,4 @@ export * as schema from "./schema"
|
|||
export * as views from "./views"
|
||||
export * as roles from "./roles"
|
||||
export * as lists from "./lists"
|
||||
export * from "./duplicate"
|
||||
|
|
Loading…
Reference in New Issue