watskeburt 2.0.5 → 4.0.0

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
@@ -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
- }