watskeburt 2.0.5 → 4.0.0

Sign up to get free protection for your applications and to get access to all the features.
package/README.md CHANGED
@@ -2,21 +2,6 @@
2
2
 
3
3
  Get changed files & their statuses since any git _revision_
4
4
 
5
- ## what's this do?
6
-
7
- A micro-lib to retrieve an array of file names that were changed since a
8
- revision. Also sports a cli for use outside of JavaScript c.s.
9
-
10
- ## why?
11
-
12
- I needed something simple and robust to support some upcoming features in
13
- [dependency-cruiser](https://github.com/sverweij/dependency-cruiser) and to
14
- run standalone to use _in combination_ with dependency-cruiser.
15
-
16
- There are a few specialized packages like this on npm, but it seems they've
17
- fallen out of maintenance. More generic packages are still maintained,
18
- but for just this simple usage they're a bit overkill.
19
-
20
5
  ## :construction_worker: usage
21
6
 
22
7
  ### :scroll: API
@@ -30,20 +15,23 @@ console.log(await getSHA());
30
15
  // list all files that differ between 'main' and the current revision (including
31
16
  // files not staged for commit and files not under revision control)
32
17
  /** @type {import('watskeburt').IChange[]} */
33
- const lChangedFiles = await list("main");
18
+ const lChangedFiles = await list({ oldRevision: "main" });
34
19
 
35
20
  // list all files that differ between 'v0.6.1' and 'v0.7.1' (by definition
36
21
  // won't include files staged for commit and/ or not under revision control)
37
22
  /** @type {import('watskeburt').IChange[]} */
38
- const lChangedFiles = await list("v0.6.1", "v0.7.1");
23
+ const lChangedFiles = await list({
24
+ oldRevision: "v0.6.1",
25
+ newRevision: "v0.7.1",
26
+ });
39
27
 
40
- // As a third parameter you can pass some options
41
- // (pass null as the second parameter if you only want to compare between
42
- // a revision and the working tree):
28
+ // list all files that differ between 'main' and the current revision
29
+ // (excluding files not staged for commit)
43
30
  /** @type {import('watskeburt').IChange[]|string} */
44
- const lChangedFiles = await list("main", null, {
31
+ const lChangedFiles = await list({
32
+ oldRevision: "main",
45
33
  trackedOnly: false, // when set to true leaves out files not under revision control
46
- outputType: "object", // other options: "json" and "regex" (as used in the CLI)
34
+ outputType: "json", // options: "object", "json" and "regex"
47
35
  });
48
36
  ```
49
37
 
@@ -53,24 +41,23 @@ The array of changes this returns looks like this:
53
41
  [
54
42
  {
55
43
  name: "doc/cli.md",
56
- changeType: "modified",
44
+ type: "modified",
57
45
  },
58
46
  {
59
47
  name: "test/thing.spec.mjs",
60
- changeType: "renamed",
48
+ type: "renamed",
61
49
  oldName: "test/old-thing.spec.mjs",
62
50
  },
63
51
  {
64
52
  name: "src/not-tracked-yet.mjs",
65
- changeType: "untracked",
53
+ type: "untracked",
66
54
  },
67
55
  ];
68
56
  ```
69
57
 
70
58
  ### :shell: cli
71
59
 
72
- For now there's also a simple command line interface (which works from node ^16.19 and
73
- node >=18.11).
60
+ Works with node >=18.11
74
61
 
75
62
  ```shell
76
63
  # list all JavaScript-ish files changed since main in a regular expression
@@ -78,19 +65,18 @@ $ npx watskeburt main
78
65
  ^(src/cli[.]mjs|src/formatters/regex[.]mjs|src/version[.]mjs)$
79
66
  ```
80
67
 
81
- By default this returns a regex that contains all changed files that could be
82
- source files in the JavaScript ecosystem (.js, .mjs, .ts, .tsx ...) that can
83
- be used in e.g. the `--focus` and `--reaches` filters of dependency-cruiser.
68
+ This emits a regex that contains all changed files that could be
69
+ source files in the JavaScript ecosystem (.js, .mjs, .ts, .tsx ...). It can
70
+ be used in e.g. dependency-cruiser's `--focus` and `--reaches` filters.
84
71
 
85
- The JSON output (which looks a lot like the array above) is unfiltered and
86
- also contains other extensions.
72
+ The JSON output (= the array above, serialized) also contains other extensions.
87
73
 
88
74
  ```
89
75
  Usage: watskeburt [options] [old-revision] [new-revision]
90
76
 
91
77
  lists files & their statuses since [old-revision] or between [old-revision] and [new-revision].
92
78
 
93
- -> When you don't pass a revision at all old-revision defaults to the current one.
79
+ -> When you don't pass a revision old-revision defaults to the current one.
94
80
 
95
81
  Options:
96
82
  -T, --outputType <type> what format to emit (choices: "json", "regex", default: "regex")
@@ -99,11 +85,19 @@ Options:
99
85
  -h, --help display help for command
100
86
  ```
101
87
 
88
+ ## why?
89
+
90
+ I needed something robust to support caching in
91
+ [dependency-cruiser](https://github.com/sverweij/dependency-cruiser) and to
92
+ run standalone to use _in combination_ with dependency-cruiser.
93
+
94
+ A few specialized packages like this existed, but they had fallen out of
95
+ maintenance. More generic packages still were maintained, but for my use
96
+ case they were overkill.
97
+
102
98
  ## 🇳🇱 what does 'watskeburt' mean?
103
99
 
104
100
  Wazzup.
105
101
 
106
102
  _watskeburt_ is a fast pronunciation of the Dutch "wat is er gebeurd?"
107
- (_what has happened?_) or "wat er is gebeurd" (_what has happened_). It's
108
- also the title of a song by the Dutch band "De Jeugd van Tegenwoordig"
109
- (_Youth these days_).
103
+ (_what has happened?_) or "wat er is gebeurd" (_what has happened_).
package/dist/cli.js CHANGED
@@ -6,7 +6,7 @@ const HELP_MESSAGE = `Usage: watskeburt [options] [old-revision] [new-revision]
6
6
 
7
7
  lists files & their statuses since [old-revision] or between [old-revision] and [new-revision].
8
8
 
9
- -> When you don't pass a revision at all old-revision defaults to the current one.
9
+ -> When you don't pass a revision old-revision defaults to the current one.
10
10
 
11
11
  Options:
12
12
  -T, --outputType <type> what format to emit (choices: "json", "regex", default: "regex")
@@ -36,11 +36,11 @@ export async function cli(
36
36
  process.exitCode = pErrorExitCode;
37
37
  return;
38
38
  }
39
- const lResult = await list(
40
- lArguments.positionals[0],
41
- lArguments.positionals[1],
42
- lArguments.values,
43
- );
39
+ const lResult = await list({
40
+ ...lArguments.values,
41
+ oldRevision: lArguments.positionals[0],
42
+ newRevision: lArguments.positionals[1],
43
+ });
44
44
  pOutStream.write(`${lResult}${EOL}`);
45
45
  } catch (pError) {
46
46
  pErrorStream.write(`${EOL}ERROR: ${pError.message}${EOL}${EOL}`);
@@ -0,0 +1,9 @@
1
+ import formatAsRegex from "./regex.js";
2
+ import formatAsJSON from "./json.js";
3
+ const OUTPUT_TYPE_TO_FUNCTION = new Map([
4
+ ["regex", formatAsRegex],
5
+ ["json", formatAsJSON],
6
+ ]);
7
+ export function format(pChanges, pOutputType) {
8
+ return OUTPUT_TYPE_TO_FUNCTION.get(pOutputType)(pChanges);
9
+ }
@@ -1,4 +1,4 @@
1
1
  const INDENT = 2;
2
- export default function formatToJSON(pChanges) {
2
+ export default function formatAsJSON(pChanges) {
3
3
  return JSON.stringify(pChanges, null, INDENT);
4
4
  }
@@ -25,7 +25,7 @@ const DEFAULT_CHANGE_TYPES = new Set([
25
25
  "copied",
26
26
  "untracked",
27
27
  ]);
28
- export default function formatToRegex(
28
+ export default function formatAsRegex(
29
29
  pChanges,
30
30
  pExtensions = DEFAULT_EXTENSIONS,
31
31
  pChangeTypes = DEFAULT_CHANGE_TYPES,
@@ -33,7 +33,7 @@ export default function formatToRegex(
33
33
  const lChanges = pChanges
34
34
  .filter(
35
35
  (pChange) =>
36
- pChangeTypes.has(pChange.changeType) &&
36
+ pChangeTypes.has(pChange.type) &&
37
37
  pExtensions.has(extname(pChange.name)),
38
38
  )
39
39
  .map(({ name }) => name.replace(/\\/g, "\\\\").replace(/\./g, "[.]"))
package/dist/main.js CHANGED
@@ -1,22 +1,25 @@
1
1
  import { parseDiffLines } from "./parse-diff-lines.js";
2
2
  import { parseStatusLines } from "./parse-status-lines.js";
3
3
  import * as primitives from "./git-primitives.js";
4
- import format from "./formatters/format.js";
5
- export async function list(pOldRevision, pNewRevision, pOptions) {
6
- const lOldRevision = pOldRevision || (await primitives.getSHA());
4
+ export async function list(pOptions) {
5
+ const lOldRevision = pOptions?.oldRevision || (await primitives.getSHA());
7
6
  const lOptions = pOptions || {};
8
7
  const [lDiffLines, lStatusLines] = await Promise.all([
9
- primitives.getDiffLines(lOldRevision, pNewRevision),
8
+ primitives.getDiffLines(lOldRevision, pOptions?.newRevision),
10
9
  !lOptions.trackedOnly ? primitives.getStatusShort() : "",
11
10
  ]);
12
11
  let lChanges = parseDiffLines(lDiffLines);
13
12
  if (!lOptions.trackedOnly) {
14
13
  lChanges = lChanges.concat(
15
14
  parseStatusLines(lStatusLines).filter(
16
- ({ changeType }) => changeType === "untracked",
15
+ ({ type: changeType }) => changeType === "untracked",
17
16
  ),
18
17
  );
19
18
  }
19
+ if (!lOptions.outputType) {
20
+ return lChanges;
21
+ }
22
+ const { format } = await import("./format/format.js");
20
23
  return format(lChanges, lOptions.outputType);
21
24
  }
22
25
  export function getSHA() {
@@ -7,15 +7,15 @@ export function parseDiffLines(pString) {
7
7
  .split(EOL)
8
8
  .filter(Boolean)
9
9
  .map(parseDiffLine)
10
- .filter(({ name, changeType }) => Boolean(name) && Boolean(changeType));
10
+ .filter(
11
+ ({ name, type: changeType }) => Boolean(name) && Boolean(changeType),
12
+ );
11
13
  }
12
14
  export function parseDiffLine(pString) {
13
15
  const lMatchResult = pString.match(DIFF_NAME_STATUS_LINE_PATTERN);
14
16
  const lReturnValue = {};
15
17
  if (lMatchResult?.groups) {
16
- lReturnValue.changeType = changeChar2ChangeType(
17
- lMatchResult.groups.changeType,
18
- );
18
+ lReturnValue.type = changeChar2ChangeType(lMatchResult.groups.changeType);
19
19
  if (lMatchResult.groups.newName) {
20
20
  lReturnValue.name = lMatchResult.groups.newName;
21
21
  lReturnValue.oldName = lMatchResult.groups.name;
@@ -7,7 +7,9 @@ export function parseStatusLines(pString) {
7
7
  .split(EOL)
8
8
  .filter(Boolean)
9
9
  .map(parseStatusLine)
10
- .filter(({ name, changeType }) => Boolean(name) && Boolean(changeType));
10
+ .filter(
11
+ ({ name, type: changeType }) => Boolean(name) && Boolean(changeType),
12
+ );
11
13
  }
12
14
  export function parseStatusLine(pString) {
13
15
  const lMatchResult = pString.match(DIFF_SHORT_STATUS_LINE_PATTERN);
@@ -19,7 +21,7 @@ export function parseStatusLine(pString) {
19
21
  const lUnStagedChangeType = changeChar2ChangeType(
20
22
  lMatchResult.groups.unStagedChangeType,
21
23
  );
22
- lReturnValue.changeType =
24
+ lReturnValue.type =
23
25
  lStagedChangeType === "unmodified"
24
26
  ? lUnStagedChangeType
25
27
  : lStagedChangeType;
package/dist/version.js CHANGED
@@ -1 +1 @@
1
- export const VERSION = "2.0.5";
1
+ export const VERSION = "4.0.0";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "watskeburt",
3
- "version": "2.0.5",
3
+ "version": "4.0.0",
4
4
  "description": "List files changed since a git revision",
5
5
  "keywords": [
6
6
  "git",
@@ -1,4 +1,4 @@
1
- export type changeTypeType =
1
+ export type changeType =
2
2
  | "added"
3
3
  | "copied"
4
4
  | "deleted"
@@ -20,86 +20,67 @@ export interface IChange {
20
20
  /**
21
21
  * how the file was changed
22
22
  */
23
- changeType: changeTypeType;
23
+ type: changeType;
24
24
  /**
25
25
  * if the file was renamed: what the old file's name was
26
26
  */
27
27
  oldName?: string;
28
28
  }
29
29
 
30
- export type outputTypeType = "regex" | "json" | "object";
30
+ export type outputTypeType = "regex" | "json";
31
31
 
32
- export interface IFormatOptions {
32
+ export interface IBaseOptions {
33
33
  /**
34
- * The type of output to deliver. Defaults to "object" - in which case
35
- * the listSync function returns an IChange[] object
34
+ * The revision against which to compare. When not passed defaults to the
35
+ * _current_ commit hash (if there's any)
36
36
  */
37
- outputType: "regex" | "json";
37
+ oldRevision?: string;
38
+ /**
39
+ * Newer revision against which to compare. Leave out when you want to
40
+ * compare against the working tree
41
+ */
42
+ newRevision?: string;
38
43
  /**
39
- * When true _only_ takes already tracked files into account.
40
- * When false also takes untracked files into account.
41
- *
42
- * Defaults to false.
44
+ * When true only takes already tracked files into account.
45
+ * When false also takes untracked files into account (default)
43
46
  */
44
47
  trackedOnly?: boolean;
45
48
  }
46
49
 
47
- export interface IInternalOptions {
50
+ export interface IFormatOptions extends IBaseOptions {
48
51
  /**
49
- * The type of output to deliver. Defaults to "object" - in which case
50
- * the listSync function returns an IChange[] object
52
+ * The type of output to deliver.
51
53
  */
52
- outputType?: "object";
54
+ outputType: "regex" | "json";
55
+ }
56
+
57
+ export interface IInternalOptions extends IBaseOptions {
53
58
  /**
54
- * When true _only_ takes already tracked files into account.
55
- * When false also takes untracked files into account.
56
- *
57
- * Defaults to false.
59
+ * The type of output to deliver. undefined/ left out
60
+ * the outputType defaults to a list of `IChange`s
58
61
  */
59
- trackedOnly?: boolean;
62
+ outputType?: undefined;
60
63
  }
61
64
 
62
65
  export type IOptions = IFormatOptions | IInternalOptions;
63
66
 
64
67
  /**
65
- * returns promise of a list of files changed since pOldRevision.
68
+ * promises a list of files changed since pOldRevision.
66
69
  *
67
- * @param pOldRevision The revision against which to compare. E.g. a commit-hash,
68
- * a branch or a tag. When not passed defaults to the _current_
69
- * commit hash (if there's any)
70
- * @param pNewRevision Newer revision against which to compare. Leave out or pass
71
- * null when you want to compare against the working tree
72
- * @param pOptions Options that influence how the changes are returned and that
73
- * filter what is returned and
74
70
  * @throws {Error}
75
71
  */
76
- export function list(
77
- pOldRevision?: string,
78
- pNewRevision?: string,
79
- pOptions?: IInternalOptions,
80
- ): Promise<IChange[]>;
72
+ export function list(pOptions?: IInternalOptions): Promise<IChange[]>;
81
73
 
82
74
  /**
83
- * returns promise a list of files changed since pOldRevision, formatted into a
84
- * string as a pOptions.outputType
75
+ * promises a list of files changed since pOldRevision, formatted
76
+ * into a string as a pOptions.outputType
85
77
  *
86
- * @param pOldRevision The revision against which to compare. E.g. a commit-hash,
87
- * a branch or a tag. When not passed defaults to the _current_
88
- * commit hash (if there's any)
89
- * @param pNewRevision Newer revision against which to compare. Leave out or pass
90
- * null when you want to compare against the working tree
91
- * @param pOptions Options that influence how the changes are returned and that
92
- * filter what is returned and
93
78
  * @throws {Error}
94
79
  */
95
- export function list(
96
- pOldRevision?: string,
97
- pNewRevision?: string,
98
- pOptions?: IFormatOptions,
99
- ): Promise<string>;
80
+ export function list(pOptions?: IFormatOptions): Promise<string>;
100
81
 
101
82
  /**
102
- * Returns the SHA1 of the current HEAD
83
+ * Promises the SHA1 of the current HEAD
103
84
  *
104
85
  * @throws {Error}
105
86
  */
@@ -1,12 +0,0 @@
1
- import formatToRegex from "./regex.js";
2
- import formatToJSON from "./json.js";
3
- const identity = (pX) => pX;
4
- const OUTPUT_TYPE_TO_FUNCTION = new Map([
5
- ["regex", formatToRegex],
6
- ["json", formatToJSON],
7
- ]);
8
- export default function format(pChanges, pOutputType) {
9
- return (OUTPUT_TYPE_TO_FUNCTION.get(pOutputType ?? "unknown") || identity)(
10
- pChanges,
11
- );
12
- }