Copybara | 854996b | 2021-09-07 19:36:02 +0000 | [diff] [blame] | 1 | // Copyright 2020 The Chromium Authors. All rights reserved. |
| 2 | // Use of this source code is governed by a BSD-style license that can be |
| 3 | // found in the LICENSE file. |
| 4 | // Based on: https://source.chromium.org/chromium/infra/infra/+/main:appengine/monorail/project/project_constants.py;l=13 |
| 5 | const PROJECT_NAME_PATTERN = '[a-z0-9][-a-z0-9]*[a-z0-9]'; |
| 6 | const USER_ID_PATTERN = '\\d+'; |
| 7 | |
| 8 | const PROJECT_MEMBER_NAME_REGEX = new RegExp( |
| 9 | `projects/(${PROJECT_NAME_PATTERN})/members/(${USER_ID_PATTERN})`); |
| 10 | |
| 11 | const USER_NAME_REGEX = new RegExp(`users/(${USER_ID_PATTERN})`); |
| 12 | |
| 13 | const PROJECT_NAME_REGEX = new RegExp(`projects/(${PROJECT_NAME_PATTERN})`); |
| 14 | |
| 15 | |
| 16 | /** |
| 17 | * Custom error class for handling invalidly formatted resource names. |
| 18 | */ |
| 19 | export class ResourceNameError extends Error { |
| 20 | /** @override */ |
| 21 | constructor(message) { |
| 22 | super(message || 'Invalid resource name format'); |
| 23 | } |
| 24 | } |
| 25 | |
| 26 | /** |
| 27 | * Returns a FieldMask given an array of string paths. |
| 28 | * https://developers.google.com/protocol-buffers/docs/reference/csharp/class/google/protobuf/well-known-types/field-mask#paths |
| 29 | * https://source.chromium.org/chromium/chromium/src/+/main:third_party/protobuf/python/google/protobuf/internal/well_known_types.py;l=425;drc=e10d98917fee771b0947a57468d1cadac446bc42 |
| 30 | * @param {Array<string>} paths The given paths to turn into a field mask. |
| 31 | * These should be a comma separated list of camel case strings. |
| 32 | * @return {string} |
| 33 | */ |
| 34 | export function pathsToFieldMask(paths) { |
| 35 | return paths.join(','); |
| 36 | } |
| 37 | |
| 38 | /** |
| 39 | * Extract a User ID from a User resource name. |
| 40 | * @param {UserName} user User resource name. |
| 41 | * @return {string} User ID. |
| 42 | * @throws {Error} if the User resource name is invalid. |
| 43 | */ |
| 44 | export function extractUserId(user) { |
| 45 | const matches = user.match(USER_NAME_REGEX); |
| 46 | if (!matches) { |
| 47 | throw new ResourceNameError(); |
| 48 | } |
| 49 | return matches[1]; |
| 50 | } |
| 51 | |
| 52 | /** |
| 53 | * Extract a project's displayName from a Project resource name. |
| 54 | * @param {ProjectName} project Project resource name. |
| 55 | * @return {string} The project's displayName. |
| 56 | * @throws {Error} if the Project resource name is invalid. |
| 57 | */ |
| 58 | export function extractProjectDisplayName(project) { |
| 59 | const matches = project.match(PROJECT_NAME_REGEX); |
| 60 | if (!matches) { |
| 61 | throw new ResourceNameError(); |
| 62 | } |
| 63 | return matches[1]; |
| 64 | } |
| 65 | |
| 66 | /** |
| 67 | * Gets the displayName of the Project referenced in a ProjectMember |
| 68 | * resource name. |
| 69 | * @param {ProjectMemberName} projectMember ProjectMember resource name. |
| 70 | * @return {string} A display name for a project. |
| 71 | */ |
| 72 | export function extractProjectFromProjectMember(projectMember) { |
| 73 | const matches = projectMember.match(PROJECT_MEMBER_NAME_REGEX); |
| 74 | if (!matches) { |
| 75 | throw new ResourceNameError(); |
| 76 | } |
| 77 | return matches[1]; |
| 78 | } |
| 79 | |
| 80 | /** |
| 81 | * Creates a ProjectStar resource name based on a UserName nad a ProjectName. |
| 82 | * @param {ProjectName} project Resource name of the referenced project. |
| 83 | * @param {UserName} user Resource name of the referenced user. |
| 84 | * @return {ProjectStarName} |
| 85 | * @throws {Error} If the project or user resource name is invalid. |
| 86 | */ |
| 87 | export function projectAndUserToStarName(project, user) { |
| 88 | if (!project || !user) return undefined; |
| 89 | const userId = extractUserId(user); |
| 90 | const projectName = extractProjectDisplayName(project); |
| 91 | return `users/${userId}/projectStars/${projectName}`; |
| 92 | } |
| 93 | |
| 94 | /** |
| 95 | * Converts a given ProjectMemberName to just the ProjectName segment present. |
| 96 | * @param {ProjectMemberName} projectMember Resource name of a ProjectMember. |
| 97 | * @return {ProjectName} Resource name of the referenced project. |
| 98 | */ |
| 99 | export function projectMemberToProjectName(projectMember) { |
| 100 | const project = extractProjectFromProjectMember(projectMember); |
| 101 | return `projects/${project}`; |
| 102 | } |