export function getWorkspaceFoldersByPrefixes()

in packages/core/src/shared/utilities/workspaceUtils.ts [502:596]


export function getWorkspaceFoldersByPrefixes(
    folders: CurrentWsFolders
): { [prefix: string]: vscode.WorkspaceFolder } | undefined {
    if (folders.length <= 1) {
        return undefined
    }
    let remainingWorkspaceFoldersToMap = folders.map((f) => ({
        folder: f,
        preferredPrefixQueue: f.uri.fsPath
            .split(path.sep)
            .reverse()
            .slice(0, workspaceFolderPrefixGuards.maximumFolderDepthConsidered)
            .reduce(
                (candidates, subDir) => {
                    candidates.push(sanitizeFilename(path.join(subDir, candidates[candidates.length - 1])))
                    return candidates
                },
                [f.name]
            )
            .reverse(),
    }))
    const results: ReturnType<typeof getWorkspaceFoldersByPrefixes> = {}

    for (
        let addParentFolderCount = 0;
        remainingWorkspaceFoldersToMap.length > 0 &&
        addParentFolderCount < workspaceFolderPrefixGuards.maximumFolderDepthConsidered;
        addParentFolderCount++
    ) {
        const workspacesByPrefixes = remainingWorkspaceFoldersToMap.reduce(
            (acc, wsFolder) => {
                const prefix = wsFolder.preferredPrefixQueue.pop()
                // this should never happen, as last candidates should be handled below, and the array starts non empty
                if (prefix === undefined) {
                    throw new ToolkitError(
                        `Encountered a folder with invalid prefix candidates (workspace folder ${wsFolder.folder.name})`
                    )
                }
                acc[prefix] = acc[prefix] ?? []
                acc[prefix].push(wsFolder)
                return acc
            },
            {} as { [key: string]: (typeof remainingWorkspaceFoldersToMap)[0][] }
        )
        remainingWorkspaceFoldersToMap = []
        for (const [prefix, folders] of Object.entries(workspacesByPrefixes)) {
            // if a folder has a unique prefix
            if (folders.length === 1 && results[prefix] === undefined) {
                results[prefix] = folders[0].folder
                continue
            }

            // find the folders that do not have more parents
            const foldersToSuffix: typeof folders = []
            for (const folder of folders) {
                if (folder.preferredPrefixQueue.length > 0) {
                    remainingWorkspaceFoldersToMap.push(folder)
                } else {
                    foldersToSuffix.push(folder)
                }
            }
            // for these last resort folders, suffix them with an increasing number until unique
            if (foldersToSuffix.length === 1 && results[prefix] === undefined) {
                results[prefix] = foldersToSuffix[0].folder
            } else {
                let suffix = 1
                for (const folder of foldersToSuffix) {
                    let newPrefix: string
                    let safetyCounter = 0
                    do {
                        newPrefix = `${prefix}_${suffix}`
                        suffix++
                        safetyCounter++
                    } while (
                        results[newPrefix] !== undefined &&
                        safetyCounter < workspaceFolderPrefixGuards.maximumFoldersWithMatchingSubfolders
                    )
                    if (safetyCounter >= workspaceFolderPrefixGuards.maximumFoldersWithMatchingSubfolders) {
                        throw new ToolkitError(
                            `Could not find a unique prefix for workspace folder ${folder.folder.name} in zip file.`
                        )
                    }
                    results[newPrefix] = folder.folder
                }
            }
        }
    }
    if (remainingWorkspaceFoldersToMap.length > 0) {
        throw new ToolkitError(
            `Could not find a unique prefix for workspace folder ${remainingWorkspaceFoldersToMap[0].folder.name} in zip file.`
        )
    }

    return results
}