blob: 308df2dd01fb0f48c7ff1f81f1d875a877531fd3 [file] [log] [blame]
Copybara854996b2021-09-07 19:36:02 +00001// 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
5const PROJECT_NAME_PATTERN = '[a-z0-9][-a-z0-9]*[a-z0-9]';
6const USER_ID_PATTERN = '\\d+';
7
8const PROJECT_MEMBER_NAME_REGEX = new RegExp(
9 `projects/(${PROJECT_NAME_PATTERN})/members/(${USER_ID_PATTERN})`);
10
11const USER_NAME_REGEX = new RegExp(`users/(${USER_ID_PATTERN})`);
12
13const PROJECT_NAME_REGEX = new RegExp(`projects/(${PROJECT_NAME_PATTERN})`);
14
15
16/**
17 * Custom error class for handling invalidly formatted resource names.
18 */
19export 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 */
34export 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 */
44export 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 */
58export 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 */
72export 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 */
87export 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 */
99export function projectMemberToProjectName(projectMember) {
100 const project = extractProjectFromProjectMember(projectMember);
101 return `projects/${project}`;
102}