virtual-code-owners 8.0.3 → 8.0.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -43,21 +43,20 @@ For example a CODEOWNERS file can look like this:
43
43
 
44
44
  # admin & ci stuff => transversal
45
45
 
46
- .github/ @ch/transversal
46
+ .github/ @ch/transversal
47
47
 
48
48
  # generic stuff
49
49
 
50
- apps/framework/ @ch/transversal
51
- apps/ux-portal/ @ch/ux @ch/transversal
52
- libs/components/ @ch/ux
50
+ apps/framework/ @ch/transversal
51
+ apps/ux-portal/ @ch/ux @ch/transversal
52
+ libs/components/ @ch/ux
53
53
 
54
54
  # specific functionality
55
55
 
56
- libs/ubc-sales/ @ch/sales
57
- libs/ubc-after-sales/ @ch/after-sales
58
- libs/ubc-pre-sales/ @ch/pre-sales
59
- libs/ubc-refund/ @ch/sales @ch/after-sales
60
- libs/ubc-baarden/ @ch/mannen-met-baarden
56
+ libs/sales/ @ch/sales
57
+ libs/after-sales/ @ch/after-sales
58
+ libs/refund/ @ch/sales @ch/after-sales
59
+ libs/baarden/ @ch/mannen-met-baarden
61
60
  ```
62
61
 
63
62
  ... where only the @cloud-heroes-all is a 'real' team on GitHub level. The other
@@ -74,7 +73,7 @@ to keep CODEOWNERS current.
74
73
  ch/after-sales:
75
74
  - john-doe-ch
76
75
  - pete-peterson-ch
77
- - william-the-fourth-ch
76
+ - john-galt-ch
78
77
  - daisy-duck
79
78
  - donald-duck
80
79
  ch/sales:
@@ -83,11 +82,6 @@ ch/sales:
83
82
  - abraham-ableton-ch
84
83
  - dagny-taggert-ch
85
84
  - karl-marx-ch
86
- ch/pre-sales:
87
- - jean-claude-ch
88
- - valerie-valerton-ch
89
- - averel-dalton-ch
90
- - john-galt-ch
91
85
  ch/ux:
92
86
  - davy-davidson-ch
93
87
  - john-johnson-ch
@@ -129,21 +123,20 @@ Running `npx virtual-code-owners` will combine these into a CODEOWNERS file like
129
123
 
130
124
  # admin & ci stuff => transversal
131
125
 
132
- .github/ @abraham-lincoln @benjamin-franklin @koos-koets @luke-the-lucky-ch @mary-the-merry-ch
126
+ .github/ @abraham-lincoln @benjamin-franklin @koos-koets @luke-the-lucky-ch @mary-the-merry-ch
133
127
 
134
128
  # generic stuff
135
129
 
136
- apps/framework/ @abraham-lincoln @benjamin-franklin @koos-koets @luke-the-lucky-ch @mary-the-merry-ch
137
- apps/ux-portal/ @abraham-lincoln @benjamin-franklin @davy-davidson-ch @joe-dalton-ch @john-johnson-ch @koos-koets @luke-the-lucky-ch @mary-the-merry-ch
138
- libs/components/ @davy-davidson-ch @joe-dalton-ch @john-johnson-ch @koos-koets
130
+ apps/framework/ @abraham-lincoln @benjamin-franklin @koos-koets @luke-the-lucky-ch @mary-the-merry-ch
131
+ apps/ux-portal/ @abraham-lincoln @benjamin-franklin @davy-davidson-ch @joe-dalton-ch @john-johnson-ch @koos-koets @luke-the-lucky-ch @mary-the-merry-ch
132
+ libs/components/ @davy-davidson-ch @joe-dalton-ch @john-johnson-ch @koos-koets
139
133
 
140
134
  # specific functionality
141
135
 
142
- libs/ubc-sales/ @abraham-ableton-ch @dagny-taggert-ch @gregory-gregson-ch @jane-doe-ch @karl-marx-ch
143
- libs/ubc-after-sales/ @daisy-duck @donald-duck @john-doe-ch @pete-peterson-ch @william-the-fourth-ch
144
- libs/ubc-pre-sales/ @averel-dalton-ch @jean-claude-ch @john-galt-ch @valerie-valerton-ch
145
- libs/ubc-refund/ @abraham-ableton-ch @dagny-taggert-ch @daisy-duck @donald-duck @gregory-gregson-ch @jane-doe-ch @john-doe-ch @karl-marx-ch @pete-peterson-ch @william-the-fourth-ch
146
- libs/ubc-baarden/ jan@example.com korneel@example.com pier@example.com tjorus@example.com
136
+ libs/sales/ @abraham-ableton-ch @dagny-taggert-ch @gregory-gregson-ch @jane-doe-ch @karl-marx-ch
137
+ libs/after-sales/ @daisy-duck @donald-duck @john-doe-ch @john-galt @pete-peterson-ch
138
+ libs/refund/ @abraham-ableton-ch @dagny-taggert-ch @daisy-duck @donald-duck @gregory-gregson-ch @jane-doe-ch @john-doe-ch @john-galt @karl-marx-ch @pete-peterson-ch
139
+ libs/baarden/ jan@example.com korneel@example.com pier@example.com tjorus@example.com
147
140
  ```
148
141
 
149
142
  ## FAQ
@@ -252,16 +245,16 @@ the formatting of _those_.
252
245
 
253
246
  You should _totally_ use GitHub teams! If you can.
254
247
 
255
- Organizations sometimes have large mono repositories with loads of code owners.
256
- They or their bureaucracy haven't landed on actually using GitHub teams to clearly
248
+ Organizations sometimes have large mono repositories with many code owners.
249
+ They or their bureaucracy haven't landed on actually using GitHub teams to
257
250
  demarcate that. Or you're working on a cross-functional team that doesn't follow
258
251
  the organization chart (and hence the GitHub teams). Teams in those organizations
259
- who want to have clear code ownership have the following choices:
252
+ who want to have clear code ownership can either:
260
253
 
261
254
  - Wrestle the bureaucracy.
262
- This is the recommended approach. It might take a while, though - and even
263
- though there are good people on many levels in bureaucracies, it might
264
- eventually not pan out because #reasons.
255
+ Recommended! It might take a while, though - and even though there are good
256
+ people on many levels in bureaucracies, it might eventually not pan out
257
+ because #reasons.
265
258
  - Maintain a CODEOWNERS file with code assigned to large lists of individuals.
266
259
  An option, but laborious to maintain, even for smaller projects
267
260
 
package/dist/cli.js CHANGED
@@ -25,64 +25,64 @@ Options:
25
25
  outputs (default: false)
26
26
  -h, --help display help for command`;
27
27
  export function cli(
28
- pArguments = process.argv.slice(2),
29
- pOutStream = process.stdout,
30
- pErrorStream = process.stderr,
31
- pErrorExitCode = 1,
28
+ pArguments = process.argv.slice(2),
29
+ pOutStream = process.stdout,
30
+ pErrorStream = process.stderr,
31
+ pErrorExitCode = 1,
32
32
  ) {
33
- try {
34
- const lOptions = getOptions(pArguments);
35
- if (lOptions.help) {
36
- pOutStream.write(`${HELP_MESSAGE}${EOL}`);
37
- return;
38
- }
39
- if (lOptions.version) {
40
- pOutStream.write(`${VERSION}${EOL}`);
41
- return;
42
- }
43
- main(lOptions, pErrorStream);
44
- } catch (pError) {
45
- pErrorStream.write(`${EOL}ERROR: ${pError.message}${EOL}${EOL}`);
46
- process.exitCode = pErrorExitCode;
47
- }
33
+ try {
34
+ const lOptions = getOptions(pArguments);
35
+ if (lOptions.help) {
36
+ pOutStream.write(`${HELP_MESSAGE}${EOL}`);
37
+ return;
38
+ }
39
+ if (lOptions.version) {
40
+ pOutStream.write(`${VERSION}${EOL}`);
41
+ return;
42
+ }
43
+ main(lOptions, pErrorStream);
44
+ } catch (pError) {
45
+ pErrorStream.write(`${EOL}ERROR: ${pError.message}${EOL}${EOL}`);
46
+ process.exitCode = pErrorExitCode;
47
+ }
48
48
  }
49
49
  function getOptions(pArguments) {
50
- return parseArgs({
51
- args: pArguments,
52
- options: {
53
- virtualCodeOwners: {
54
- type: "string",
55
- short: "v",
56
- default: ".github/VIRTUAL-CODEOWNERS.txt",
57
- },
58
- virtualTeams: {
59
- type: "string",
60
- short: "t",
61
- default: ".github/virtual-teams.yml",
62
- },
63
- codeOwners: {
64
- type: "string",
65
- short: "c",
66
- default: ".github/CODEOWNERS",
67
- },
68
- emitLabeler: {
69
- type: "boolean",
70
- short: "l",
71
- default: false,
72
- },
73
- labelerLocation: {
74
- type: "string",
75
- default: ".github/labeler.yml",
76
- },
77
- dryRun: {
78
- type: "boolean",
79
- default: false,
80
- },
81
- help: { type: "boolean", short: "h", default: false },
82
- version: { type: "boolean", short: "V", default: false },
83
- },
84
- strict: true,
85
- allowPositionals: true,
86
- tokens: false,
87
- }).values;
50
+ return parseArgs({
51
+ args: pArguments,
52
+ options: {
53
+ virtualCodeOwners: {
54
+ type: "string",
55
+ short: "v",
56
+ default: ".github/VIRTUAL-CODEOWNERS.txt",
57
+ },
58
+ virtualTeams: {
59
+ type: "string",
60
+ short: "t",
61
+ default: ".github/virtual-teams.yml",
62
+ },
63
+ codeOwners: {
64
+ type: "string",
65
+ short: "c",
66
+ default: ".github/CODEOWNERS",
67
+ },
68
+ emitLabeler: {
69
+ type: "boolean",
70
+ short: "l",
71
+ default: false,
72
+ },
73
+ labelerLocation: {
74
+ type: "string",
75
+ default: ".github/labeler.yml",
76
+ },
77
+ dryRun: {
78
+ type: "boolean",
79
+ default: false,
80
+ },
81
+ help: { type: "boolean", short: "h", default: false },
82
+ version: { type: "boolean", short: "V", default: false },
83
+ },
84
+ strict: true,
85
+ allowPositionals: true,
86
+ tokens: false,
87
+ }).values;
88
88
  }
@@ -1,63 +1,63 @@
1
1
  import { EOL } from "node:os";
2
2
  import { isEmailIshUsername } from "../utensils.js";
3
3
  const DEFAULT_WARNING =
4
- `#${EOL}` +
5
- `# DO NOT EDIT - this file is generated and your edits will be overwritten${EOL}` +
6
- `#${EOL}` +
7
- `# To make changes:${EOL}` +
8
- `#${EOL}` +
9
- `# - edit .github/VIRTUAL-CODEOWNERS.txt${EOL}` +
10
- `# - and/ or add team members to .github/virtual-teams.yml${EOL}` +
11
- `# - run 'npx virtual-code-owners' (or 'npx virtual-code-owners --emitLabeler' if you also${EOL}` +
12
- `# want to generate a .github/labeler.yml)${EOL}` +
13
- `#${EOL}${EOL}`;
4
+ `#${EOL}` +
5
+ `# DO NOT EDIT - this file is generated and your edits will be overwritten${EOL}` +
6
+ `#${EOL}` +
7
+ `# To make changes:${EOL}` +
8
+ `#${EOL}` +
9
+ `# - edit .github/VIRTUAL-CODEOWNERS.txt${EOL}` +
10
+ `# - and/ or add team members to .github/virtual-teams.yml${EOL}` +
11
+ `# - run 'npx virtual-code-owners' (or 'npx virtual-code-owners --emitLabeler' if you also${EOL}` +
12
+ `# want to generate a .github/labeler.yml)${EOL}` +
13
+ `#${EOL}${EOL}`;
14
14
  export default function generateCodeOwners(
15
- pVirtualCodeOwners,
16
- pTeamMap,
17
- pGeneratedWarning = DEFAULT_WARNING,
15
+ pVirtualCodeOwners,
16
+ pTeamMap,
17
+ pGeneratedWarning = DEFAULT_WARNING,
18
18
  ) {
19
- return (
20
- pGeneratedWarning +
21
- pVirtualCodeOwners
22
- .filter((pLine) => pLine.type !== "ignorable-comment")
23
- .map((pLine) => generateLine(pLine, pTeamMap))
24
- .join(EOL)
25
- );
19
+ return (
20
+ pGeneratedWarning +
21
+ pVirtualCodeOwners
22
+ .filter((pLine) => pLine.type !== "ignorable-comment")
23
+ .map((pLine) => generateLine(pLine, pTeamMap))
24
+ .join(EOL)
25
+ );
26
26
  }
27
27
  function generateLine(pCSTLine, pTeamMap) {
28
- if (pCSTLine.type === "rule") {
29
- const lUserNames = uniq(
30
- pCSTLine.users.flatMap((pUser) => expandTeamToUserNames(pUser, pTeamMap)),
31
- )
32
- .sort(compareUserNames)
33
- .join(" ");
34
- return (
35
- pCSTLine.filesPattern +
36
- pCSTLine.spaces +
37
- lUserNames +
38
- (pCSTLine.inlineComment ? ` #${pCSTLine.inlineComment}` : "")
39
- );
40
- }
41
- return pCSTLine.raw;
28
+ if (pCSTLine.type === "rule") {
29
+ const lUserNames = uniq(
30
+ pCSTLine.users.flatMap((pUser) => expandTeamToUserNames(pUser, pTeamMap)),
31
+ )
32
+ .sort(compareUserNames)
33
+ .join(" ");
34
+ return (
35
+ pCSTLine.filesPattern +
36
+ pCSTLine.spaces +
37
+ lUserNames +
38
+ (pCSTLine.inlineComment ? ` #${pCSTLine.inlineComment}` : "")
39
+ );
40
+ }
41
+ return pCSTLine.raw;
42
42
  }
43
43
  function expandTeamToUserNames(pUser, pTeamMap) {
44
- if (pUser.type === "virtual-team-name") {
45
- return stringifyTeamMembers(pTeamMap, pUser.bareName);
46
- }
47
- return [pUser.raw];
44
+ if (pUser.type === "virtual-team-name") {
45
+ return stringifyTeamMembers(pTeamMap, pUser.bareName);
46
+ }
47
+ return [pUser.raw];
48
48
  }
49
49
  function stringifyTeamMembers(pTeamMap, pTeamName) {
50
- return (pTeamMap[pTeamName] ?? []).map(userNameToCodeOwner);
50
+ return (pTeamMap[pTeamName] ?? []).map(userNameToCodeOwner);
51
51
  }
52
52
  function userNameToCodeOwner(pUserName) {
53
- if (isEmailIshUsername(pUserName)) {
54
- return pUserName;
55
- }
56
- return `@${pUserName}`;
53
+ if (isEmailIshUsername(pUserName)) {
54
+ return pUserName;
55
+ }
56
+ return `@${pUserName}`;
57
57
  }
58
58
  function compareUserNames(pLeftName, pRightName) {
59
- return pLeftName.toLowerCase() > pRightName.toLowerCase() ? 1 : -1;
59
+ return pLeftName.toLowerCase() > pRightName.toLowerCase() ? 1 : -1;
60
60
  }
61
61
  function uniq(pUserNames) {
62
- return Array.from(new Set(pUserNames));
62
+ return Array.from(new Set(pUserNames));
63
63
  }
@@ -1,56 +1,56 @@
1
1
  import { EOL } from "node:os";
2
2
  const DEFAULT_WARNING =
3
- `#${EOL}` +
4
- `# DO NOT EDIT - this file is generated and your edits will be overwritten${EOL}` +
5
- `#${EOL}` +
6
- `# To make changes:${EOL}` +
7
- `#${EOL}` +
8
- `# - edit .github/VIRTUAL-CODEOWNERS.txt${EOL}` +
9
- `# - and/ or add teams (& members) to .github/virtual-teams.yml${EOL}` +
10
- `# - run 'npx virtual-code-owners --emitLabeler'${EOL}` +
11
- `#${EOL}${EOL}`;
3
+ `#${EOL}` +
4
+ `# DO NOT EDIT - this file is generated and your edits will be overwritten${EOL}` +
5
+ `#${EOL}` +
6
+ `# To make changes:${EOL}` +
7
+ `#${EOL}` +
8
+ `# - edit .github/VIRTUAL-CODEOWNERS.txt${EOL}` +
9
+ `# - and/ or add teams (& members) to .github/virtual-teams.yml${EOL}` +
10
+ `# - run 'npx virtual-code-owners --emitLabeler'${EOL}` +
11
+ `#${EOL}${EOL}`;
12
12
  export default function generateLabelerYml(
13
- pCodeOwners,
14
- pTeamMap,
15
- pGeneratedWarning = DEFAULT_WARNING,
13
+ pCodeOwners,
14
+ pTeamMap,
15
+ pGeneratedWarning = DEFAULT_WARNING,
16
16
  ) {
17
- let lReturnValue = pGeneratedWarning;
18
- for (const lTeamName in pTeamMap) {
19
- const lPatternsForTeam = getPatternsForTeam(pCodeOwners, lTeamName)
20
- .map(
21
- (pPattern) =>
22
- ` - any-glob-to-any-file: ${transformForYamlAndMinimatch(pPattern)}${EOL}`,
23
- )
24
- .join("");
25
- if (lPatternsForTeam) {
26
- lReturnValue += `${lTeamName}:${EOL} - changed-files:${EOL}${lPatternsForTeam}${EOL}`;
27
- }
28
- }
29
- return lReturnValue;
17
+ let lReturnValue = pGeneratedWarning;
18
+ for (const lTeamName in pTeamMap) {
19
+ const lPatternsForTeam = getPatternsForTeam(pCodeOwners, lTeamName)
20
+ .map(
21
+ (pPattern) =>
22
+ ` - any-glob-to-any-file: ${transformForYamlAndMinimatch(pPattern)}${EOL}`,
23
+ )
24
+ .join("");
25
+ if (lPatternsForTeam) {
26
+ lReturnValue += `${lTeamName}:${EOL} - changed-files:${EOL}${lPatternsForTeam}${EOL}`;
27
+ }
28
+ }
29
+ return lReturnValue;
30
30
  }
31
31
  function getPatternsForTeam(pCodeOwners, pTeamName) {
32
- return pCodeOwners
33
- .filter((pLine) => {
34
- return pLine.type === "rule" && lineContainsTeamName(pLine, pTeamName);
35
- })
36
- .map((pLine) => pLine.filesPattern);
32
+ return pCodeOwners
33
+ .filter((pLine) => {
34
+ return pLine.type === "rule" && lineContainsTeamName(pLine, pTeamName);
35
+ })
36
+ .map((pLine) => pLine.filesPattern);
37
37
  }
38
38
  function transformForYamlAndMinimatch(pOriginalString) {
39
- let lReturnValue = pOriginalString;
40
- if (pOriginalString === "*") {
41
- lReturnValue = "**";
42
- }
43
- if (lReturnValue.startsWith("*")) {
44
- lReturnValue = `"${lReturnValue}"`;
45
- }
46
- if (pOriginalString.endsWith("/")) {
47
- lReturnValue = `${lReturnValue}**`;
48
- }
49
- return lReturnValue;
39
+ let lReturnValue = pOriginalString;
40
+ if (pOriginalString === "*") {
41
+ lReturnValue = "**";
42
+ }
43
+ if (lReturnValue.startsWith("*")) {
44
+ lReturnValue = `"${lReturnValue}"`;
45
+ }
46
+ if (pOriginalString.endsWith("/")) {
47
+ lReturnValue = `${lReturnValue}**`;
48
+ }
49
+ return lReturnValue;
50
50
  }
51
51
  function lineContainsTeamName(pLine, pTeamName) {
52
- return pLine.users.some(
53
- (pUser) =>
54
- pUser.type === "virtual-team-name" && pUser.bareName === pTeamName,
55
- );
52
+ return pLine.users.some(
53
+ (pUser) =>
54
+ pUser.type === "virtual-team-name" && pUser.bareName === pTeamName,
55
+ );
56
56
  }
package/dist/main.js CHANGED
@@ -5,30 +5,30 @@ import generateLabelerYml from "./labeler-yml/generate.js";
5
5
  import readTeamMap from "./team-map/read.js";
6
6
  import readVirtualCodeOwners from "./virtual-code-owners/read.js";
7
7
  export function main(pOptions, pErrorStream) {
8
- const lTeamMap = readTeamMap(pOptions.virtualTeams);
9
- const lVirtualCodeOwners = readVirtualCodeOwners(
10
- pOptions.virtualCodeOwners,
11
- lTeamMap,
12
- );
13
- const lCodeOwnersContent = generateCodeOwners(lVirtualCodeOwners, lTeamMap);
14
- if (!pOptions.dryRun) {
15
- writeFileSync(pOptions.codeOwners, lCodeOwnersContent, {
16
- encoding: "utf-8",
17
- flag: "w",
18
- });
19
- }
20
- if (pOptions.emitLabeler) {
21
- const lLabelerContent = generateLabelerYml(lVirtualCodeOwners, lTeamMap);
22
- if (!pOptions.dryRun) {
23
- writeFileSync(pOptions.labelerLocation, lLabelerContent, {
24
- encoding: "utf-8",
25
- flag: "w",
26
- });
27
- }
28
- pErrorStream.write(
29
- `${EOL}Wrote '${pOptions.codeOwners}' AND '${pOptions.labelerLocation}'${EOL}${EOL}`,
30
- );
31
- } else {
32
- pErrorStream.write(`${EOL}Wrote '${pOptions.codeOwners}'${EOL}${EOL}`);
33
- }
8
+ const lTeamMap = readTeamMap(pOptions.virtualTeams);
9
+ const lVirtualCodeOwners = readVirtualCodeOwners(
10
+ pOptions.virtualCodeOwners,
11
+ lTeamMap,
12
+ );
13
+ const lCodeOwnersContent = generateCodeOwners(lVirtualCodeOwners, lTeamMap);
14
+ if (!pOptions.dryRun) {
15
+ writeFileSync(pOptions.codeOwners, lCodeOwnersContent, {
16
+ encoding: "utf-8",
17
+ flag: "w",
18
+ });
19
+ }
20
+ if (pOptions.emitLabeler) {
21
+ const lLabelerContent = generateLabelerYml(lVirtualCodeOwners, lTeamMap);
22
+ if (!pOptions.dryRun) {
23
+ writeFileSync(pOptions.labelerLocation, lLabelerContent, {
24
+ encoding: "utf-8",
25
+ flag: "w",
26
+ });
27
+ }
28
+ pErrorStream.write(
29
+ `${EOL}Wrote '${pOptions.codeOwners}' AND '${pOptions.labelerLocation}'${EOL}${EOL}`,
30
+ );
31
+ } else {
32
+ pErrorStream.write(`${EOL}Wrote '${pOptions.codeOwners}'${EOL}${EOL}`);
33
+ }
34
34
  }
@@ -4,29 +4,29 @@ import { EOL } from "node:os";
4
4
  import { parse as parseYaml } from "yaml";
5
5
  import virtualTeamsSchema from "./virtual-teams.schema.js";
6
6
  export default function readTeamMap(pVirtualTeamsFileName) {
7
- const lVirtualTeamsAsAString = readFileSync(pVirtualTeamsFileName, {
8
- encoding: "utf-8",
9
- });
10
- const lTeamMap = parseYaml(lVirtualTeamsAsAString);
11
- assertTeamMapValid(lTeamMap, pVirtualTeamsFileName);
12
- return lTeamMap;
7
+ const lVirtualTeamsAsAString = readFileSync(pVirtualTeamsFileName, {
8
+ encoding: "utf-8",
9
+ });
10
+ const lTeamMap = parseYaml(lVirtualTeamsAsAString);
11
+ assertTeamMapValid(lTeamMap, pVirtualTeamsFileName);
12
+ return lTeamMap;
13
13
  }
14
14
  function assertTeamMapValid(pTeamMap, pVirtualTeamsFileName) {
15
- const ajv = new Ajv({
16
- allErrors: true,
17
- verbose: true,
18
- });
19
- if (!ajv.validate(virtualTeamsSchema, pTeamMap)) {
20
- throw new Error(
21
- `This is not a valid virtual-teams.yml:${EOL}${formatAjvErrors(ajv.errors, pVirtualTeamsFileName)}.\n`,
22
- );
23
- }
15
+ const ajv = new Ajv({
16
+ allErrors: true,
17
+ verbose: true,
18
+ });
19
+ if (!ajv.validate(virtualTeamsSchema, pTeamMap)) {
20
+ throw new Error(
21
+ `This is not a valid virtual-teams.yml:${EOL}${formatAjvErrors(ajv.errors, pVirtualTeamsFileName)}.\n`,
22
+ );
23
+ }
24
24
  }
25
25
  function formatAjvErrors(pAjvErrors, pVirtualTeamsFileName) {
26
- return pAjvErrors
27
- .map((pAjvError) => formatAjvError(pAjvError, pVirtualTeamsFileName))
28
- .join(EOL);
26
+ return pAjvErrors
27
+ .map((pAjvError) => formatAjvError(pAjvError, pVirtualTeamsFileName))
28
+ .join(EOL);
29
29
  }
30
30
  function formatAjvError(pAjvError, pVirtualTeamsFileName) {
31
- return `${pVirtualTeamsFileName}: ${pAjvError.instancePath} - ${JSON.stringify(pAjvError.data)} ${pAjvError.message}`;
31
+ return `${pVirtualTeamsFileName}: ${pAjvError.instancePath} - ${JSON.stringify(pAjvError.data)} ${pAjvError.message}`;
32
32
  }
@@ -1,16 +1,16 @@
1
1
  export default {
2
- $schema: "http://json-schema.org/draft-07/schema#",
3
- title: "virtual teams schema for virtual-code-owners",
4
- description: "a list of teams and their team members",
5
- $id: "org.js.virtual-code-owners/7.0.0",
6
- type: "object",
7
- additionalProperties: {
8
- type: "array",
9
- items: {
10
- type: "string",
11
- description:
12
- "Username or e-mail address of a team member. (Don't prefix usernames with '@')",
13
- pattern: "^[^@][^\\s]+$",
14
- },
15
- },
2
+ $schema: "http://json-schema.org/draft-07/schema#",
3
+ title: "virtual teams schema for virtual-code-owners",
4
+ description: "a list of teams and their team members",
5
+ $id: "org.js.virtual-code-owners/7.0.0",
6
+ type: "object",
7
+ additionalProperties: {
8
+ type: "array",
9
+ items: {
10
+ type: "string",
11
+ description:
12
+ "Username or e-mail address of a team member. (Don't prefix usernames with '@')",
13
+ pattern: "^[^@][^\\s]+$",
14
+ },
15
+ },
16
16
  };
package/dist/utensils.js CHANGED
@@ -1,4 +1,4 @@
1
1
  export function isEmailIshUsername(pUsername) {
2
- const lEmailIshUsernameRE = /^.+@.+$/;
3
- return Boolean(pUsername.match(lEmailIshUsernameRE));
2
+ const lEmailIshUsernameRE = /^.+@.+$/;
3
+ return Boolean(pUsername.match(lEmailIshUsernameRE));
4
4
  }
package/dist/version.js CHANGED
@@ -1 +1 @@
1
- export const VERSION = "8.0.3";
1
+ export const VERSION = "8.0.4";
@@ -1,32 +1,32 @@
1
1
  export function getAnomalies(pVirtualCodeOwners) {
2
- const weirdLines = pVirtualCodeOwners
3
- .filter((pLine) => pLine.type === "unknown")
4
- .map((pLine) => ({
5
- ...pLine,
6
- type: "invalid-line",
7
- }));
8
- const weirdUsers = pVirtualCodeOwners.flatMap((pLine) => {
9
- if (pLine.type === "rule") {
10
- return pLine.users
11
- .filter((pUser) => pUser.type === "invalid")
12
- .map((pUser) => ({
13
- ...pUser,
14
- line: pLine.line,
15
- type: "invalid-user",
16
- }));
17
- }
18
- return [];
19
- });
20
- return weirdLines.concat(weirdUsers).sort(orderAnomaly);
2
+ const weirdLines = pVirtualCodeOwners
3
+ .filter((pLine) => pLine.type === "unknown")
4
+ .map((pLine) => ({
5
+ ...pLine,
6
+ type: "invalid-line",
7
+ }));
8
+ const weirdUsers = pVirtualCodeOwners.flatMap((pLine) => {
9
+ if (pLine.type === "rule") {
10
+ return pLine.users
11
+ .filter((pUser) => pUser.type === "invalid")
12
+ .map((pUser) => ({
13
+ ...pUser,
14
+ line: pLine.line,
15
+ type: "invalid-user",
16
+ }));
17
+ }
18
+ return [];
19
+ });
20
+ return weirdLines.concat(weirdUsers).sort(orderAnomaly);
21
21
  }
22
22
  function orderAnomaly(pLeft, pRight) {
23
- if (
24
- pLeft.line === pRight.line &&
25
- pLeft.type === "invalid-user" &&
26
- pRight.type === "invalid-user"
27
- ) {
28
- return pLeft.userNumberWithinLine > pRight.userNumberWithinLine ? 1 : -1;
29
- } else {
30
- return pLeft.line > pRight.line ? 1 : -1;
31
- }
23
+ if (
24
+ pLeft.line === pRight.line &&
25
+ pLeft.type === "invalid-user" &&
26
+ pRight.type === "invalid-user"
27
+ ) {
28
+ return pLeft.userNumberWithinLine > pRight.userNumberWithinLine ? 1 : -1;
29
+ } else {
30
+ return pLeft.line > pRight.line ? 1 : -1;
31
+ }
32
32
  }
@@ -1,67 +1,67 @@
1
1
  import { EOL } from "node:os";
2
2
  import { isEmailIshUsername } from "../utensils.js";
3
3
  export function parse(pVirtualCodeOwnersAsString, pTeamMap = {}) {
4
- return pVirtualCodeOwnersAsString
5
- .split(EOL)
6
- .map((pUntreatedLine, pLineNo) =>
7
- parseLine(pUntreatedLine, pTeamMap, pLineNo + 1),
8
- );
4
+ return pVirtualCodeOwnersAsString
5
+ .split(EOL)
6
+ .map((pUntreatedLine, pLineNo) =>
7
+ parseLine(pUntreatedLine, pTeamMap, pLineNo + 1),
8
+ );
9
9
  }
10
10
  function parseLine(pUntreatedLine, pTeamMap, pLineNo) {
11
- const lTrimmedLine = pUntreatedLine.trim();
12
- const lCommentSplitLine = lTrimmedLine.split(/\s*#/);
13
- const lRule = lCommentSplitLine[0]?.match(
14
- /^(?<filesPattern>[^\s]+)(?<spaces>\s+)(?<userNames>.*)$/,
15
- );
16
- if (lTrimmedLine.startsWith("#!")) {
17
- return { type: "ignorable-comment", line: pLineNo, raw: pUntreatedLine };
18
- }
19
- if (lTrimmedLine.startsWith("#")) {
20
- return { type: "comment", line: pLineNo, raw: pUntreatedLine };
21
- }
22
- if (!lRule?.groups) {
23
- if (lTrimmedLine === "") {
24
- return { type: "empty", line: pLineNo, raw: pUntreatedLine };
25
- }
26
- return { type: "unknown", line: pLineNo, raw: pUntreatedLine };
27
- }
28
- return {
29
- type: "rule",
30
- line: pLineNo,
31
- filesPattern: lRule.groups.filesPattern,
32
- spaces: lRule.groups.spaces,
33
- users: parseUsers(lRule.groups.userNames, pTeamMap),
34
- inlineComment: lCommentSplitLine[1] ?? "",
35
- raw: pUntreatedLine,
36
- };
11
+ const lTrimmedLine = pUntreatedLine.trim();
12
+ const lCommentSplitLine = lTrimmedLine.split(/\s*#/);
13
+ const lRule = lCommentSplitLine[0]?.match(
14
+ /^(?<filesPattern>[^\s]+)(?<spaces>\s+)(?<userNames>.*)$/,
15
+ );
16
+ if (lTrimmedLine.startsWith("#!")) {
17
+ return { type: "ignorable-comment", line: pLineNo, raw: pUntreatedLine };
18
+ }
19
+ if (lTrimmedLine.startsWith("#")) {
20
+ return { type: "comment", line: pLineNo, raw: pUntreatedLine };
21
+ }
22
+ if (!lRule?.groups) {
23
+ if (lTrimmedLine === "") {
24
+ return { type: "empty", line: pLineNo, raw: pUntreatedLine };
25
+ }
26
+ return { type: "unknown", line: pLineNo, raw: pUntreatedLine };
27
+ }
28
+ return {
29
+ type: "rule",
30
+ line: pLineNo,
31
+ filesPattern: lRule.groups.filesPattern,
32
+ spaces: lRule.groups.spaces,
33
+ users: parseUsers(lRule.groups.userNames, pTeamMap),
34
+ inlineComment: lCommentSplitLine[1] ?? "",
35
+ raw: pUntreatedLine,
36
+ };
37
37
  }
38
38
  function parseUsers(pUserNamesString, pTeamMap) {
39
- const lUserNames = pUserNamesString.split(/\s+/);
40
- return lUserNames.map((pUserName, pIndex) => {
41
- const lBareName = getBareUserName(pUserName);
42
- return {
43
- type: getUserNameType(pUserName, lBareName, pTeamMap),
44
- userNumberWithinLine: pIndex + 1,
45
- bareName: lBareName,
46
- raw: pUserName,
47
- };
48
- });
39
+ const lUserNames = pUserNamesString.split(/\s+/);
40
+ return lUserNames.map((pUserName, pIndex) => {
41
+ const lBareName = getBareUserName(pUserName);
42
+ return {
43
+ type: getUserNameType(pUserName, lBareName, pTeamMap),
44
+ userNumberWithinLine: pIndex + 1,
45
+ bareName: lBareName,
46
+ raw: pUserName,
47
+ };
48
+ });
49
49
  }
50
50
  function getUserNameType(pUserName, pBareName, pTeamMap) {
51
- if (isEmailIshUsername(pUserName)) {
52
- return "e-mail-address";
53
- }
54
- if (pUserName.startsWith("@")) {
55
- if (pTeamMap.hasOwnProperty(pBareName)) {
56
- return "virtual-team-name";
57
- }
58
- return "other-user-or-team";
59
- }
60
- return "invalid";
51
+ if (isEmailIshUsername(pUserName)) {
52
+ return "e-mail-address";
53
+ }
54
+ if (pUserName.startsWith("@")) {
55
+ if (pTeamMap.hasOwnProperty(pBareName)) {
56
+ return "virtual-team-name";
57
+ }
58
+ return "other-user-or-team";
59
+ }
60
+ return "invalid";
61
61
  }
62
62
  function getBareUserName(pUserName) {
63
- if (pUserName.startsWith("@")) {
64
- return pUserName.slice(1);
65
- }
66
- return pUserName;
63
+ if (pUserName.startsWith("@")) {
64
+ return pUserName.slice(1);
65
+ }
66
+ return pUserName;
67
67
  }
@@ -3,35 +3,35 @@ import { EOL } from "node:os";
3
3
  import { getAnomalies } from "./anomalies.js";
4
4
  import { parse as parseVirtualCodeOwners } from "./parse.js";
5
5
  export default function readVirtualCodeOwners(
6
- pVirtualCodeOwnersFileName,
7
- pTeamMap,
6
+ pVirtualCodeOwnersFileName,
7
+ pTeamMap,
8
8
  ) {
9
- const lVirtualCodeOwnersAsAString = readFileSync(pVirtualCodeOwnersFileName, {
10
- encoding: "utf-8",
11
- });
12
- const lVirtualCodeOwners = parseVirtualCodeOwners(
13
- lVirtualCodeOwnersAsAString,
14
- pTeamMap,
15
- );
16
- const lAnomalies = getAnomalies(lVirtualCodeOwners);
17
- if (lAnomalies.length > 0) {
18
- throw new Error(
19
- `This is not a valid virtual code-owners file:${EOL}${reportAnomalies(pVirtualCodeOwnersFileName, lAnomalies)}`,
20
- );
21
- }
22
- return lVirtualCodeOwners;
9
+ const lVirtualCodeOwnersAsAString = readFileSync(pVirtualCodeOwnersFileName, {
10
+ encoding: "utf-8",
11
+ });
12
+ const lVirtualCodeOwners = parseVirtualCodeOwners(
13
+ lVirtualCodeOwnersAsAString,
14
+ pTeamMap,
15
+ );
16
+ const lAnomalies = getAnomalies(lVirtualCodeOwners);
17
+ if (lAnomalies.length > 0) {
18
+ throw new Error(
19
+ `This is not a valid virtual code-owners file:${EOL}${reportAnomalies(pVirtualCodeOwnersFileName, lAnomalies)}`,
20
+ );
21
+ }
22
+ return lVirtualCodeOwners;
23
23
  }
24
24
  function reportAnomalies(pFileName, pAnomalies) {
25
- return pAnomalies
26
- .map((pAnomaly) => {
27
- if (pAnomaly.type === "invalid-line") {
28
- return `${pFileName}:${pAnomaly.line}:1 invalid line - neither a rule, comment nor empty: "${pAnomaly.raw}"`;
29
- } else {
30
- return (
31
- `${pFileName}:${pAnomaly.line}:1 invalid user or team name "${pAnomaly.raw}" (#${pAnomaly.userNumberWithinLine} on this line). ` +
32
- `It should either start with "@" or be an e-mail address.`
33
- );
34
- }
35
- })
36
- .join(EOL);
25
+ return pAnomalies
26
+ .map((pAnomaly) => {
27
+ if (pAnomaly.type === "invalid-line") {
28
+ return `${pFileName}:${pAnomaly.line}:1 invalid line - neither a rule, comment nor empty: "${pAnomaly.raw}"`;
29
+ } else {
30
+ return (
31
+ `${pFileName}:${pAnomaly.line}:1 invalid user or team name "${pAnomaly.raw}" (#${pAnomaly.userNumberWithinLine} on this line). ` +
32
+ `It should either start with "@" or be an e-mail address.`
33
+ );
34
+ }
35
+ })
36
+ .join(EOL);
37
37
  }
package/package.json CHANGED
@@ -1,38 +1,38 @@
1
1
  {
2
- "name": "virtual-code-owners",
3
- "version": "8.0.3",
4
- "description": "CODEOWNERS with teams for teams that can't use GitHub teams",
5
- "type": "module",
6
- "bin": {
7
- "virtual-code-owners": "dist/run-cli.js"
8
- },
9
- "files": [
10
- "dist/",
11
- "package.json",
12
- "README.md",
13
- "LICENSE"
14
- ],
15
- "keywords": [
16
- "CODEOWNERS"
17
- ],
18
- "author": "Sander Verweij (https://sverweij.github.io/)",
19
- "license": "MIT",
20
- "homepage": "https://github.com/sverweij/virtual-code-owners",
21
- "repository": {
22
- "type": "git",
23
- "url": "git+https://github.com/sverweij/virtual-code-owners.git"
24
- },
25
- "bugs": {
26
- "url": "https://github.com/sverweij/virtual-code-owners/issues"
27
- },
28
- "dependencies": {
29
- "ajv": "8.12.0",
30
- "yaml": "2.4.1"
31
- },
32
- "engines": {
33
- "node": "^18.11.0||>=20.0.0"
34
- },
35
- "scripts": {
36
- "test": "echo for test, build and static analysis scripts: see the github repository"
37
- }
2
+ "name": "virtual-code-owners",
3
+ "version": "8.0.4",
4
+ "description": "CODEOWNERS with teams for teams that can't use GitHub teams",
5
+ "type": "module",
6
+ "bin": {
7
+ "virtual-code-owners": "dist/run-cli.js"
8
+ },
9
+ "files": [
10
+ "dist/",
11
+ "package.json",
12
+ "README.md",
13
+ "LICENSE"
14
+ ],
15
+ "keywords": [
16
+ "CODEOWNERS"
17
+ ],
18
+ "author": "Sander Verweij (https://sverweij.github.io/)",
19
+ "license": "MIT",
20
+ "homepage": "https://github.com/sverweij/virtual-code-owners",
21
+ "repository": {
22
+ "type": "git",
23
+ "url": "git+https://github.com/sverweij/virtual-code-owners.git"
24
+ },
25
+ "bugs": {
26
+ "url": "https://github.com/sverweij/virtual-code-owners/issues"
27
+ },
28
+ "dependencies": {
29
+ "ajv": "8.12.0",
30
+ "yaml": "2.4.1"
31
+ },
32
+ "engines": {
33
+ "node": "^18.11.0||>=20.0.0"
34
+ },
35
+ "scripts": {
36
+ "test": "echo for test, build and static analysis scripts: see the github repository"
37
+ }
38
38
  }