complete-cli 1.0.8 → 1.0.10

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.
@@ -1,8 +1,9 @@
1
1
  import chalk from "chalk";
2
2
  import { Command, Option } from "clipanion";
3
3
  import { ReadonlySet } from "complete-common";
4
- import { $, deleteFileOrDirectory, fatalError, isDirectory, isFile, readFile, writeFile, } from "complete-node";
4
+ import { $, deleteFileOrDirectoryAsync, fatalError, isDirectory, isFileAsync, readFileAsync, writeFileAsync, } from "complete-node";
5
5
  import klawSync from "klaw-sync";
6
+ import os from "node:os";
6
7
  import path from "node:path";
7
8
  import { ACTION_YML, ACTION_YML_TEMPLATE_PATH, CWD, TEMPLATES_DYNAMIC_DIR, TEMPLATES_STATIC_DIR, } from "../constants.js";
8
9
  import { getTruncatedText } from "./check/getTruncatedText.js";
@@ -18,18 +19,19 @@ export class CheckCommand extends Command {
18
19
  static usage = Command.Usage({
19
20
  description: "Check the template files of the current TypeScript project to see if they are up to date.",
20
21
  });
21
- // eslint-disable-next-line @typescript-eslint/require-await
22
22
  async execute() {
23
23
  let oneOrMoreErrors = false;
24
24
  const ignore = this.ignore ?? "";
25
25
  const ignoreFileNames = ignore.split(",");
26
26
  const ignoreFileNamesSet = new ReadonlySet(ignoreFileNames);
27
27
  // First, check the static files.
28
- if (checkTemplateDirectory(TEMPLATES_STATIC_DIR, ignoreFileNamesSet, this.verbose)) {
28
+ const staticTemplatesValid = await checkTemplateDirectory(TEMPLATES_STATIC_DIR, ignoreFileNamesSet, this.verbose);
29
+ if (!staticTemplatesValid) {
29
30
  oneOrMoreErrors = true;
30
31
  }
31
32
  // Second, check dynamic files that require specific logic.
32
- if (checkIndividualFiles(ignoreFileNamesSet, this.verbose)) {
33
+ const dynamicFilesValid = await checkDynamicFiles(ignoreFileNamesSet, this.verbose);
34
+ if (!dynamicFilesValid) {
33
35
  oneOrMoreErrors = true;
34
36
  }
35
37
  if (oneOrMoreErrors) {
@@ -37,7 +39,8 @@ export class CheckCommand extends Command {
37
39
  }
38
40
  }
39
41
  }
40
- function checkTemplateDirectory(templateDirectory, ignoreFileNamesSet, verbose) {
42
+ /** @returns Whether the directory was valid. */
43
+ async function checkTemplateDirectory(templateDirectory, ignoreFileNamesSet, verbose) {
41
44
  let oneOrMoreErrors = false;
42
45
  for (const klawItem of klawSync(templateDirectory)) {
43
46
  const templateFilePath = klawItem.path;
@@ -68,41 +71,46 @@ function checkTemplateDirectory(templateDirectory, ignoreFileNamesSet, verbose)
68
71
  if (ignoreFileNamesSet.has(projectFileName)) {
69
72
  continue;
70
73
  }
71
- if (!compareTextFiles(projectFilePath, templateFilePath, verbose)) {
74
+ // eslint-disable-next-line no-await-in-loop
75
+ const fileValid = await compareTextFiles(projectFilePath, templateFilePath, verbose);
76
+ if (!fileValid) {
72
77
  oneOrMoreErrors = true;
73
78
  }
74
79
  }
75
- return oneOrMoreErrors;
80
+ return !oneOrMoreErrors;
76
81
  }
77
- function checkIndividualFiles(ignoreFileNamesSet, verbose) {
82
+ /** @returns Whether the dynamic files were valid. */
83
+ async function checkDynamicFiles(ignoreFileNamesSet, verbose) {
78
84
  let oneOrMoreErrors = false;
79
85
  if (!ignoreFileNamesSet.has(ACTION_YML)) {
80
86
  const templateFilePath = ACTION_YML_TEMPLATE_PATH;
81
87
  const relativeTemplateFilePath = path.relative(TEMPLATES_DYNAMIC_DIR, templateFilePath);
82
88
  const projectFilePath = path.join(CWD, relativeTemplateFilePath);
83
- if (!compareTextFiles(projectFilePath, templateFilePath, verbose)) {
89
+ const fileValid = await compareTextFiles(projectFilePath, templateFilePath, verbose);
90
+ if (!fileValid) {
84
91
  oneOrMoreErrors = true;
85
92
  }
86
93
  }
87
- return oneOrMoreErrors;
94
+ return !oneOrMoreErrors;
88
95
  }
89
96
  /** @returns Whether the project file is valid in reference to the template file. */
90
- function compareTextFiles(projectFilePath, templateFilePath, verbose) {
91
- if (!isFile(projectFilePath)) {
97
+ async function compareTextFiles(projectFilePath, templateFilePath, verbose) {
98
+ const fileExists = await isFileAsync(projectFilePath);
99
+ if (!fileExists) {
92
100
  console.log(`Failed to find the following file: ${projectFilePath}`);
93
101
  printTemplateLocation(templateFilePath);
94
102
  return false;
95
103
  }
96
- const projectFileObject = getTruncatedFileText(projectFilePath, new Set(), new Set());
97
- const templateFileObject = getTruncatedFileText(templateFilePath, projectFileObject.ignoreLines, projectFileObject.linesBeforeIgnore);
104
+ const projectFileObject = await getTruncatedFileText(projectFilePath, new Set(), new Set());
105
+ const templateFileObject = await getTruncatedFileText(templateFilePath, projectFileObject.ignoreLines, projectFileObject.linesBeforeIgnore);
98
106
  if (projectFileObject.text === templateFileObject.text) {
99
107
  return true;
100
108
  }
101
109
  console.log(`The contents of the following file do not match: ${chalk.red(projectFilePath)}`);
102
110
  printTemplateLocation(templateFilePath);
103
111
  if (verbose) {
104
- const originalTemplateFile = readFile(templateFilePath);
105
- const originalProjectFile = readFile(projectFilePath);
112
+ const originalTemplateFile = await readFileAsync(templateFilePath);
113
+ const originalProjectFile = await readFileAsync(projectFilePath);
106
114
  console.log("--- Original template file: ---\n");
107
115
  console.log(originalTemplateFile);
108
116
  console.log();
@@ -116,18 +124,19 @@ function compareTextFiles(projectFilePath, templateFilePath, verbose) {
116
124
  console.log(projectFileObject.text);
117
125
  console.log();
118
126
  }
119
- const tempProjectFilePath = path.join(CWD, "tempProjectFile.txt");
120
- const tempTemplateFilePath = path.join(CWD, "tempTemplateFile.txt");
121
- writeFile(tempProjectFilePath, projectFileObject.text);
122
- writeFile(tempTemplateFilePath, templateFileObject.text);
123
- $.sync `diff ${tempProjectFilePath} ${tempTemplateFilePath} --ignore-blank-lines`;
124
- deleteFileOrDirectory(tempProjectFilePath);
125
- deleteFileOrDirectory(tempTemplateFilePath);
127
+ const tempDir = os.tmpdir();
128
+ const tempProjectFilePath = path.join(tempDir, "tempProjectFile.txt");
129
+ const tempTemplateFilePath = path.join(tempDir, "tempTemplateFile.txt");
130
+ await writeFileAsync(tempProjectFilePath, projectFileObject.text);
131
+ await writeFileAsync(tempTemplateFilePath, templateFileObject.text);
132
+ await $ `diff ${tempProjectFilePath} ${tempTemplateFilePath} --ignore-blank-lines`;
133
+ await deleteFileOrDirectoryAsync(tempProjectFilePath);
134
+ await deleteFileOrDirectoryAsync(tempTemplateFilePath);
126
135
  return false;
127
136
  }
128
- function getTruncatedFileText(filePath, ignoreLines, linesBeforeIgnore) {
137
+ async function getTruncatedFileText(filePath, ignoreLines, linesBeforeIgnore) {
129
138
  const fileName = path.basename(filePath);
130
- const fileContents = readFile(filePath);
139
+ const fileContents = await readFileAsync(filePath);
131
140
  return getTruncatedText(fileName, fileContents, ignoreLines, linesBeforeIgnore);
132
141
  }
133
142
  function printTemplateLocation(templateFilePath) {
@@ -21,5 +21,5 @@
21
21
  "pnpm-lock.yaml",
22
22
  "yarn.lock",
23
23
  ],
24
- "words": ["dbaeumer", "esbenp", "lockb", "sarisia", "tseslint", "Zamiell"],
24
+ "words": ["dbaeumer", "esbenp", "sarisia", "tseslint", "Zamiell"],
25
25
  }
@@ -34,4 +34,4 @@ tsconfig*.json linguist-language=JSON-with-Comments
34
34
  package-lock.json linguist-generated=true
35
35
  yarn.lock linguist-generated=true
36
36
  pnpm-lock.yaml linguist-generated=true
37
- bun.lockb linguist-generated=true
37
+ bun.lock linguist-generated=true
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "complete-cli",
3
- "version": "1.0.8",
3
+ "version": "1.0.10",
4
4
  "description": "A command line tool for bootstrapping TypeScript projects.",
5
5
  "keywords": [
6
6
  "typescript"
@@ -38,7 +38,7 @@
38
38
  "chalk": "5.4.1",
39
39
  "clipanion": "4.0.0-rc.4",
40
40
  "complete-common": "^1.1.1",
41
- "complete-node": "^3.0.1",
41
+ "complete-node": "^3.1.0",
42
42
  "klaw-sync": "6.0.0",
43
43
  "yaml": "2.7.0"
44
44
  },
@@ -3,14 +3,15 @@ import { Command, Option } from "clipanion";
3
3
  import { ReadonlySet } from "complete-common";
4
4
  import {
5
5
  $,
6
- deleteFileOrDirectory,
6
+ deleteFileOrDirectoryAsync,
7
7
  fatalError,
8
8
  isDirectory,
9
- isFile,
10
- readFile,
11
- writeFile,
9
+ isFileAsync,
10
+ readFileAsync,
11
+ writeFileAsync,
12
12
  } from "complete-node";
13
13
  import klawSync from "klaw-sync";
14
+ import os from "node:os";
14
15
  import path from "node:path";
15
16
  import {
16
17
  ACTION_YML,
@@ -40,7 +41,6 @@ export class CheckCommand extends Command {
40
41
  "Check the template files of the current TypeScript project to see if they are up to date.",
41
42
  });
42
43
 
43
- // eslint-disable-next-line @typescript-eslint/require-await
44
44
  async execute(): Promise<void> {
45
45
  let oneOrMoreErrors = false;
46
46
  const ignore = this.ignore ?? "";
@@ -48,18 +48,21 @@ export class CheckCommand extends Command {
48
48
  const ignoreFileNamesSet = new ReadonlySet(ignoreFileNames);
49
49
 
50
50
  // First, check the static files.
51
- if (
52
- checkTemplateDirectory(
53
- TEMPLATES_STATIC_DIR,
54
- ignoreFileNamesSet,
55
- this.verbose,
56
- )
57
- ) {
51
+ const staticTemplatesValid = await checkTemplateDirectory(
52
+ TEMPLATES_STATIC_DIR,
53
+ ignoreFileNamesSet,
54
+ this.verbose,
55
+ );
56
+ if (!staticTemplatesValid) {
58
57
  oneOrMoreErrors = true;
59
58
  }
60
59
 
61
60
  // Second, check dynamic files that require specific logic.
62
- if (checkIndividualFiles(ignoreFileNamesSet, this.verbose)) {
61
+ const dynamicFilesValid = await checkDynamicFiles(
62
+ ignoreFileNamesSet,
63
+ this.verbose,
64
+ );
65
+ if (!dynamicFilesValid) {
63
66
  oneOrMoreErrors = true;
64
67
  }
65
68
 
@@ -69,11 +72,12 @@ export class CheckCommand extends Command {
69
72
  }
70
73
  }
71
74
 
72
- function checkTemplateDirectory(
75
+ /** @returns Whether the directory was valid. */
76
+ async function checkTemplateDirectory(
73
77
  templateDirectory: string,
74
78
  ignoreFileNamesSet: ReadonlySet<string>,
75
79
  verbose: boolean,
76
- ): boolean {
80
+ ): Promise<boolean> {
77
81
  let oneOrMoreErrors = false;
78
82
 
79
83
  for (const klawItem of klawSync(templateDirectory)) {
@@ -120,15 +124,22 @@ function checkTemplateDirectory(
120
124
  continue;
121
125
  }
122
126
 
123
- if (!compareTextFiles(projectFilePath, templateFilePath, verbose)) {
127
+ // eslint-disable-next-line no-await-in-loop
128
+ const fileValid = await compareTextFiles(
129
+ projectFilePath,
130
+ templateFilePath,
131
+ verbose,
132
+ );
133
+ if (!fileValid) {
124
134
  oneOrMoreErrors = true;
125
135
  }
126
136
  }
127
137
 
128
- return oneOrMoreErrors;
138
+ return !oneOrMoreErrors;
129
139
  }
130
140
 
131
- function checkIndividualFiles(
141
+ /** @returns Whether the dynamic files were valid. */
142
+ async function checkDynamicFiles(
132
143
  ignoreFileNamesSet: ReadonlySet<string>,
133
144
  verbose: boolean,
134
145
  ) {
@@ -141,34 +152,40 @@ function checkIndividualFiles(
141
152
  templateFilePath,
142
153
  );
143
154
  const projectFilePath = path.join(CWD, relativeTemplateFilePath);
144
- if (!compareTextFiles(projectFilePath, templateFilePath, verbose)) {
155
+ const fileValid = await compareTextFiles(
156
+ projectFilePath,
157
+ templateFilePath,
158
+ verbose,
159
+ );
160
+ if (!fileValid) {
145
161
  oneOrMoreErrors = true;
146
162
  }
147
163
  }
148
164
 
149
- return oneOrMoreErrors;
165
+ return !oneOrMoreErrors;
150
166
  }
151
167
 
152
168
  /** @returns Whether the project file is valid in reference to the template file. */
153
- function compareTextFiles(
169
+ async function compareTextFiles(
154
170
  projectFilePath: string,
155
171
  templateFilePath: string,
156
172
  verbose: boolean,
157
- ): boolean {
158
- if (!isFile(projectFilePath)) {
173
+ ): Promise<boolean> {
174
+ const fileExists = await isFileAsync(projectFilePath);
175
+ if (!fileExists) {
159
176
  console.log(`Failed to find the following file: ${projectFilePath}`);
160
177
  printTemplateLocation(templateFilePath);
161
178
 
162
179
  return false;
163
180
  }
164
181
 
165
- const projectFileObject = getTruncatedFileText(
182
+ const projectFileObject = await getTruncatedFileText(
166
183
  projectFilePath,
167
184
  new Set(),
168
185
  new Set(),
169
186
  );
170
187
 
171
- const templateFileObject = getTruncatedFileText(
188
+ const templateFileObject = await getTruncatedFileText(
172
189
  templateFilePath,
173
190
  projectFileObject.ignoreLines,
174
191
  projectFileObject.linesBeforeIgnore,
@@ -186,8 +203,8 @@ function compareTextFiles(
186
203
  printTemplateLocation(templateFilePath);
187
204
 
188
205
  if (verbose) {
189
- const originalTemplateFile = readFile(templateFilePath);
190
- const originalProjectFile = readFile(projectFilePath);
206
+ const originalTemplateFile = await readFileAsync(templateFilePath);
207
+ const originalProjectFile = await readFileAsync(projectFilePath);
191
208
 
192
209
  console.log("--- Original template file: ---\n");
193
210
  console.log(originalTemplateFile);
@@ -203,27 +220,28 @@ function compareTextFiles(
203
220
  console.log();
204
221
  }
205
222
 
206
- const tempProjectFilePath = path.join(CWD, "tempProjectFile.txt");
207
- const tempTemplateFilePath = path.join(CWD, "tempTemplateFile.txt");
223
+ const tempDir = os.tmpdir();
224
+ const tempProjectFilePath = path.join(tempDir, "tempProjectFile.txt");
225
+ const tempTemplateFilePath = path.join(tempDir, "tempTemplateFile.txt");
208
226
 
209
- writeFile(tempProjectFilePath, projectFileObject.text);
210
- writeFile(tempTemplateFilePath, templateFileObject.text);
227
+ await writeFileAsync(tempProjectFilePath, projectFileObject.text);
228
+ await writeFileAsync(tempTemplateFilePath, templateFileObject.text);
211
229
 
212
- $.sync`diff ${tempProjectFilePath} ${tempTemplateFilePath} --ignore-blank-lines`;
230
+ await $`diff ${tempProjectFilePath} ${tempTemplateFilePath} --ignore-blank-lines`;
213
231
 
214
- deleteFileOrDirectory(tempProjectFilePath);
215
- deleteFileOrDirectory(tempTemplateFilePath);
232
+ await deleteFileOrDirectoryAsync(tempProjectFilePath);
233
+ await deleteFileOrDirectoryAsync(tempTemplateFilePath);
216
234
 
217
235
  return false;
218
236
  }
219
237
 
220
- function getTruncatedFileText(
238
+ async function getTruncatedFileText(
221
239
  filePath: string,
222
240
  ignoreLines: ReadonlySet<string>,
223
241
  linesBeforeIgnore: ReadonlySet<string>,
224
242
  ) {
225
243
  const fileName = path.basename(filePath);
226
- const fileContents = readFile(filePath);
244
+ const fileContents = await readFileAsync(filePath);
227
245
 
228
246
  return getTruncatedText(
229
247
  fileName,