@dittowords/cli 2.5.1 → 2.6.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.
Files changed (73) hide show
  1. package/.idea/workspace.xml +124 -0
  2. package/README.md +23 -10
  3. package/babel.config.js +2 -8
  4. package/bin/add-project.js +38 -0
  5. package/bin/add-project.js.map +1 -0
  6. package/bin/api.js +20 -0
  7. package/bin/api.js.map +1 -0
  8. package/bin/config.js +174 -0
  9. package/bin/config.js.map +1 -0
  10. package/bin/consts.js +21 -0
  11. package/bin/consts.js.map +1 -0
  12. package/bin/ditto.js +71 -74
  13. package/bin/ditto.js.map +1 -0
  14. package/bin/init/init.js +39 -0
  15. package/bin/init/init.js.map +1 -0
  16. package/bin/init/project.js +115 -0
  17. package/bin/init/project.js.map +1 -0
  18. package/bin/init/token.js +89 -0
  19. package/bin/init/token.js.map +1 -0
  20. package/bin/output.js +34 -0
  21. package/bin/output.js.map +1 -0
  22. package/bin/pull.js +305 -0
  23. package/bin/pull.js.map +1 -0
  24. package/bin/remove-project.js +40 -0
  25. package/bin/remove-project.js.map +1 -0
  26. package/bin/types.js +3 -0
  27. package/bin/types.js.map +1 -0
  28. package/bin/utils/getSelectedProjects.js +76 -0
  29. package/bin/utils/getSelectedProjects.js.map +1 -0
  30. package/bin/utils/processMetaOption.js +15 -0
  31. package/bin/utils/processMetaOption.js.map +1 -0
  32. package/bin/utils/projectsToText.js +16 -0
  33. package/bin/utils/projectsToText.js.map +1 -0
  34. package/bin/utils/promptForProject.js +44 -0
  35. package/bin/utils/promptForProject.js.map +1 -0
  36. package/bin/utils/sourcesToText.js +25 -0
  37. package/bin/utils/sourcesToText.js.map +1 -0
  38. package/jest.config.js +1 -1
  39. package/lib/{add-project.js → add-project.ts} +8 -8
  40. package/lib/api.ts +15 -0
  41. package/lib/{config.test.js → config.test.ts} +14 -25
  42. package/lib/config.ts +214 -0
  43. package/lib/consts.ts +20 -0
  44. package/lib/ditto.ts +97 -0
  45. package/lib/init/{init.js → init.ts} +11 -12
  46. package/lib/init/project.test.ts +49 -0
  47. package/lib/init/{project.js → project.ts} +31 -29
  48. package/lib/init/{token.test.js → token.test.ts} +3 -3
  49. package/lib/init/{token.js → token.ts} +23 -19
  50. package/lib/output.ts +21 -0
  51. package/lib/pull.test.ts +172 -0
  52. package/lib/{pull.js → pull.ts} +145 -98
  53. package/lib/{remove-project.js → remove-project.ts} +11 -15
  54. package/lib/types.ts +23 -0
  55. package/lib/utils/getSelectedProjects.ts +55 -0
  56. package/lib/utils/processMetaOption.test.ts +18 -0
  57. package/lib/utils/processMetaOption.ts +16 -0
  58. package/lib/utils/{projectsToText.js → projectsToText.ts} +5 -4
  59. package/lib/utils/{promptForProject.js → promptForProject.ts} +18 -9
  60. package/lib/utils/{sourcesToText.js → sourcesToText.ts} +6 -5
  61. package/package.json +20 -15
  62. package/testing/fixtures/project-config-pull.yml +0 -0
  63. package/tsconfig.json +12 -0
  64. package/yarn-error.log +4466 -0
  65. package/lib/api.js +0 -18
  66. package/lib/config.js +0 -169
  67. package/lib/consts.js +0 -14
  68. package/lib/init/project.test.js +0 -99
  69. package/lib/output.js +0 -21
  70. package/lib/pull.test.js +0 -173
  71. package/lib/utils/getSelectedProjects.js +0 -44
  72. package/lib/utils/processMetaOption.js +0 -16
  73. package/lib/utils/processMetaOption.test.js +0 -16
@@ -1,11 +1,9 @@
1
1
  /* eslint-disable no-underscore-dangle */
2
- const fs = require("fs");
3
- const path = require("path");
4
-
5
- const tempy = require("tempy");
6
- const yaml = require("js-yaml");
7
-
8
- const config = require("./config");
2
+ import fs from "fs";
3
+ import path from "path";
4
+ import tempy from "tempy";
5
+ import yaml from "js-yaml";
6
+ import config from "./config";
9
7
 
10
8
  const fakeHomedir = fs.mkdtempSync(path.join(__dirname, "../testing/tmp"));
11
9
 
@@ -57,11 +55,15 @@ describe("Tokens in config files", () => {
57
55
  describe("saveToken", () => {
58
56
  it("creates a config file with config data", () => {
59
57
  const fileContents = fs.readFileSync(configFile, "utf8");
60
- const configData = yaml.safeLoad(fileContents);
61
- expect(configData["testing.dittowords.com"]).toBeDefined();
62
- expect(configData["testing.dittowords.com"][0].token).toEqual(
63
- "faketoken"
64
- );
58
+ const configData = yaml.load(fileContents);
59
+ if (configData && typeof configData === "object") {
60
+ expect(configData["testing.dittowords.com"]).toBeDefined();
61
+ expect(configData["testing.dittowords.com"][0].token).toEqual(
62
+ "faketoken"
63
+ );
64
+ } else {
65
+ fail("Config Data should have been an object!");
66
+ }
65
67
  });
66
68
  });
67
69
 
@@ -73,16 +75,3 @@ describe("Tokens in config files", () => {
73
75
  });
74
76
  });
75
77
  });
76
-
77
- describe("save", () => {
78
- let data;
79
- beforeEach(() => {
80
- const file = tempy.writeSync("");
81
- config.save(file, "test.setting", true);
82
- data = config.readData(file);
83
- });
84
-
85
- it("writes a setting correctly", () => {
86
- expect(data.test.setting).toEqual(true);
87
- });
88
- });
package/lib/config.ts ADDED
@@ -0,0 +1,214 @@
1
+ import fs from "fs";
2
+ import path from "path";
3
+ import url from "url";
4
+ import yaml from "js-yaml";
5
+
6
+ import consts from "./consts";
7
+ import { Project, ConfigYAML } from "./types";
8
+
9
+ function createFileIfMissing(filename: string) {
10
+ const dir = path.dirname(filename);
11
+
12
+ if (!fs.existsSync(dir)) fs.mkdirSync(dir);
13
+
14
+ if (!fs.existsSync(filename)) {
15
+ fs.closeSync(fs.openSync(filename, "w"));
16
+ }
17
+ }
18
+
19
+ function jsonIsConfigYAML(json: unknown): json is ConfigYAML {
20
+ return typeof json === "object";
21
+ }
22
+
23
+ function jsonIsGlobalYAML(
24
+ json: unknown
25
+ ): json is Record<string, { token: string }[]> {
26
+ return (
27
+ !!json &&
28
+ typeof json === "object" &&
29
+ Object.values(json).every((arr) =>
30
+ arr.every(
31
+ (val: any) =>
32
+ typeof val === "object" && Object.keys(val).includes("token")
33
+ )
34
+ )
35
+ );
36
+ }
37
+
38
+ /**
39
+ * Read data from a project config file
40
+ * @param {string} file defaults to `PROJECT_CONFIG_FILE` defined in `constants.js`
41
+ * @param {*} defaultData defaults to `{}`
42
+ * @returns { ConfigYAML }
43
+ */
44
+ function readProjectConfigData(
45
+ file = consts.PROJECT_CONFIG_FILE,
46
+ defaultData = {}
47
+ ): ConfigYAML {
48
+ createFileIfMissing(file);
49
+ const fileContents = fs.readFileSync(file, "utf8");
50
+ const yamlData = yaml.load(fileContents);
51
+ if (jsonIsConfigYAML(yamlData)) {
52
+ return yamlData;
53
+ }
54
+ return defaultData;
55
+ }
56
+
57
+ /**
58
+ * Read data from a global config file
59
+ * @param {string} file defaults to `CONFIG_FILE` defined in `constants.js`
60
+ * @param {*} defaultData defaults to `{}`
61
+ * @returns { Record<string, { token: string }[]> }
62
+ */
63
+ function readGlobalConfigData(
64
+ file = consts.CONFIG_FILE,
65
+ defaultData = {}
66
+ ): Record<string, { token: string }[]> {
67
+ createFileIfMissing(file);
68
+ const fileContents = fs.readFileSync(file, "utf8");
69
+ const yamlData = yaml.load(fileContents);
70
+ if (jsonIsGlobalYAML(yamlData)) {
71
+ return yamlData;
72
+ }
73
+ return defaultData;
74
+ }
75
+
76
+ function writeProjectConfigData(file: string, data: object) {
77
+ createFileIfMissing(file);
78
+ const existingData = readProjectConfigData(file);
79
+ const yamlStr = yaml.dump({ ...existingData, ...data });
80
+ fs.writeFileSync(file, yamlStr, "utf8");
81
+ }
82
+
83
+ function writeGlobalConfigData(file: string, data: object) {
84
+ createFileIfMissing(file);
85
+ const existingData = readGlobalConfigData(file);
86
+ const yamlStr = yaml.dump({ ...existingData, ...data });
87
+ fs.writeFileSync(file, yamlStr, "utf8");
88
+ }
89
+
90
+ function justTheHost(host: string) {
91
+ if (!host.includes("://")) return host;
92
+ return url.parse(host).hostname || "";
93
+ }
94
+
95
+ function deleteToken(file: string, host: string) {
96
+ const data = readGlobalConfigData(file);
97
+ const hostParsed = justTheHost(host);
98
+ data[hostParsed] = [];
99
+ data[hostParsed][0] = { token: "" };
100
+ writeGlobalConfigData(file, data);
101
+ }
102
+
103
+ function saveToken(file: string, host: string, token: string) {
104
+ const data = readGlobalConfigData(file);
105
+ const hostParsed = justTheHost(host);
106
+ data[hostParsed] = []; // only allow one token per host
107
+ data[hostParsed][0] = { token };
108
+ writeGlobalConfigData(file, data);
109
+ }
110
+
111
+ function getTokenFromEnv() {
112
+ return process.env.DITTO_API_KEY;
113
+ }
114
+
115
+ /**
116
+ *
117
+ * @param {string} file
118
+ * @param {string} host
119
+ * @returns {Token}
120
+ */
121
+ function getToken(file: string, host: string) {
122
+ const tokenFromEnv = getTokenFromEnv();
123
+ if (tokenFromEnv) {
124
+ return tokenFromEnv;
125
+ }
126
+
127
+ const data = readGlobalConfigData(file);
128
+ const hostEntry = data[justTheHost(host)];
129
+ if (!hostEntry) return undefined;
130
+ const { length } = hostEntry;
131
+ return hostEntry[length - 1].token;
132
+ }
133
+
134
+ const IS_DUPLICATE = /-(\d+$)/;
135
+
136
+ function dedupeProjectName(projectNames: Set<string>, projectName: string) {
137
+ let dedupedName = projectName;
138
+
139
+ if (projectNames.has(dedupedName)) {
140
+ while (projectNames.has(dedupedName)) {
141
+ const [_, numberStr] = dedupedName.match(IS_DUPLICATE) || [];
142
+ if (numberStr && !isNaN(parseInt(numberStr))) {
143
+ dedupedName = `${dedupedName.replace(IS_DUPLICATE, "")}-${
144
+ parseInt(numberStr) + 1
145
+ }`;
146
+ } else {
147
+ dedupedName = `${dedupedName}-1`;
148
+ }
149
+ }
150
+ }
151
+
152
+ return dedupedName;
153
+ }
154
+
155
+ /**
156
+ * Reads from the config file, filters out
157
+ * invalid projects, dedupes those remaining, and returns:
158
+ * - whether or not the data required to `pull` is present
159
+ * - whether or not the component library should be fetched
160
+ * - an array of valid, deduped projects
161
+ * - the `variants` and `format` config options
162
+ */
163
+ function parseSourceInformation() {
164
+ const { projects, components, variants, format } = readProjectConfigData();
165
+
166
+ const projectNames = new Set<string>();
167
+ const validProjects: Project[] = [];
168
+
169
+ let componentLibraryInProjects = false;
170
+
171
+ (projects || []).forEach((project) => {
172
+ const isValid = project.id && project.name;
173
+ if (!isValid) {
174
+ return;
175
+ }
176
+
177
+ if (project.id === "ditto_component_library") {
178
+ componentLibraryInProjects = true;
179
+ return;
180
+ }
181
+
182
+ project.fileName = dedupeProjectName(projectNames, project.name);
183
+ projectNames.add(project.fileName);
184
+
185
+ validProjects.push(project);
186
+ });
187
+
188
+ const shouldFetchComponentLibrary =
189
+ !!components || componentLibraryInProjects;
190
+
191
+ const hasSourceData = !!validProjects.length || shouldFetchComponentLibrary;
192
+
193
+ return {
194
+ hasSourceData,
195
+ validProjects,
196
+ shouldFetchComponentLibrary,
197
+ variants: variants || false,
198
+ format,
199
+ };
200
+ }
201
+
202
+ export default {
203
+ createFileIfMissing,
204
+ readProjectConfigData,
205
+ readGlobalConfigData,
206
+ writeGlobalConfigData,
207
+ writeProjectConfigData,
208
+ justTheHost,
209
+ saveToken,
210
+ deleteToken,
211
+ getToken,
212
+ getTokenFromEnv,
213
+ parseSourceInformation,
214
+ };
package/lib/consts.ts ADDED
@@ -0,0 +1,20 @@
1
+ import { homedir } from "os";
2
+ import path from "path";
3
+
4
+ export const API_HOST =
5
+ process.env.DITTO_API_HOST || "https://api.dittowords.com";
6
+ export const CONFIG_FILE =
7
+ process.env.DITTO_CONFIG_FILE || path.join(homedir(), ".config", "ditto");
8
+ export const PROJECT_CONFIG_FILE = path.normalize(
9
+ path.join("ditto", "config.yml")
10
+ );
11
+ export const TEXT_DIR = process.env.DITTO_TEXT_DIR || "ditto";
12
+ export const TEXT_FILE = path.normalize(path.join(TEXT_DIR, "text.json"));
13
+
14
+ export default {
15
+ API_HOST,
16
+ CONFIG_FILE,
17
+ PROJECT_CONFIG_FILE,
18
+ TEXT_DIR,
19
+ TEXT_FILE,
20
+ };
package/lib/ditto.ts ADDED
@@ -0,0 +1,97 @@
1
+ #!/usr/bin/env node
2
+ // This is the main entry point for the ditto-cli command.
3
+ import { program } from "commander";
4
+ // to use V8's code cache to speed up instantiation time
5
+ import "v8-compile-cache";
6
+
7
+ import { init, needsInit } from "./init/init";
8
+ import { pull } from "./pull";
9
+
10
+ import addProject from "./add-project";
11
+ import removeProject from "./remove-project";
12
+ import processMetaOption from "./utils/processMetaOption";
13
+
14
+ /**
15
+ * Catch and report unexpected error.
16
+ * @param {any} error The thrown error object.
17
+ * @returns {void}
18
+ */
19
+ function quit(exitCode = 2) {
20
+ console.log("\nExiting Ditto CLI...\n");
21
+ process.exitCode = exitCode;
22
+ process.exit();
23
+ }
24
+
25
+ const setupCommands = () => {
26
+ program.name("ditto-cli");
27
+ program
28
+ .command("pull")
29
+ .description("Sync copy from Ditto into working directory")
30
+ .action(() => checkInit("pull"));
31
+
32
+ const projectDescription = "Add a Ditto project to sync copy from";
33
+ const projectCommand = program
34
+ .command("project")
35
+ .description(projectDescription)
36
+ .action(() => checkInit("project"));
37
+
38
+ projectCommand
39
+ .command("add")
40
+ .description(projectDescription)
41
+ .action(() => checkInit("project"));
42
+
43
+ projectCommand
44
+ .command("remove")
45
+ .description("Stop syncing copy from a Ditto project")
46
+ .action(() => checkInit("project remove"));
47
+ };
48
+
49
+ const setupOptions = () => {
50
+ program.option(
51
+ "-m, --meta <data...>",
52
+ "Optional metadata for this command to send arbitrary data to the backend. Ex: -m githubActionRequest:true trigger:manual"
53
+ );
54
+ };
55
+
56
+ const checkInit = async (command: string) => {
57
+ if (needsInit() && command !== "project remove") {
58
+ try {
59
+ await init();
60
+ if (command === "pull") main(); // re-run to actually pull text now that init is finished
61
+ } catch (error) {
62
+ quit();
63
+ }
64
+ } else {
65
+ const { meta } = program.opts();
66
+ switch (command) {
67
+ case "pull":
68
+ pull({ meta: processMetaOption(meta) });
69
+ break;
70
+ case "project":
71
+ case "project add":
72
+ addProject();
73
+ break;
74
+ case "project remove":
75
+ removeProject();
76
+ break;
77
+ case "none":
78
+ setupCommands();
79
+ program.help();
80
+ break;
81
+ default:
82
+ quit();
83
+ }
84
+ }
85
+ };
86
+
87
+ const main = async () => {
88
+ if (process.argv.length <= 2 && process.argv[1].includes("ditto-cli")) {
89
+ await checkInit("none");
90
+ } else {
91
+ setupCommands();
92
+ setupOptions();
93
+ }
94
+ program.parse(process.argv);
95
+ };
96
+
97
+ main();
@@ -1,17 +1,16 @@
1
1
  // Related to initializing a user/environment to ditto.
2
2
  // expected to be run once per project.
3
- const boxen = require("boxen");
4
- const chalk = require("chalk");
5
- const projectsToText = require("../utils/projectsToText");
3
+ import boxen from "boxen";
4
+ import chalk from "chalk";
5
+ import projectsToText from "../utils/projectsToText";
6
6
 
7
- const { needsSource, collectAndSaveProject } = require("./project");
8
- const { needsToken, collectAndSaveToken } = require("./token");
7
+ import { needsSource, collectAndSaveProject } from "./project";
8
+ import { needsToken, collectAndSaveToken } from "./token";
9
9
 
10
- const config = require("../config");
11
- const output = require("../output");
12
- const sourcesToText = require("../utils/sourcesToText");
10
+ import config from "../config";
11
+ import sourcesToText from "../utils/sourcesToText";
13
12
 
14
- const needsInit = () => needsToken() || needsSource();
13
+ export const needsInit = () => needsToken() || needsSource();
15
14
 
16
15
  function welcome() {
17
16
  const msg = chalk.white(`${chalk.bold(
@@ -23,7 +22,7 @@ We're glad to have you here.`);
23
22
  console.log(boxen(msg, { padding: 1 }));
24
23
  }
25
24
 
26
- async function init() {
25
+ export const init = async () => {
27
26
  welcome();
28
27
 
29
28
  if (needsToken()) {
@@ -43,6 +42,6 @@ async function init() {
43
42
  sourcesToText(validProjects, shouldFetchComponentLibrary);
44
43
 
45
44
  console.log(message);
46
- }
45
+ };
47
46
 
48
- module.exports = { needsInit, init };
47
+ export default { needsInit, init };
@@ -0,0 +1,49 @@
1
+ const fs = require("fs");
2
+ const path = require("path");
3
+
4
+ const yaml = require("js-yaml");
5
+ const { createFileIfMissing } = require("../config");
6
+
7
+ import { _testing } from "./project";
8
+
9
+ const fakeProjectDir = path.join(__dirname, "../../testing/tmp");
10
+ const badYaml = path.join(__dirname, "../../testing/fixtures/bad-yaml.yml");
11
+ const configEmptyProjects = path.join(
12
+ __dirname,
13
+ "../../testing/fixtures/bad-yaml.yml"
14
+ );
15
+ const configMissingName = path.join(
16
+ __dirname,
17
+ "../../testing/fixtures/project-config-no-name.yml"
18
+ );
19
+ const configMissingId = path.join(
20
+ __dirname,
21
+ "../../testing/fixtures/project-config-no-id.yml"
22
+ );
23
+ const configLegit = path.join(
24
+ __dirname,
25
+ "../../testing/fixtures/project-config-working.yml"
26
+ );
27
+
28
+ describe("saveProject", () => {
29
+ const configFile = path.join(fakeProjectDir, "ditto/config.yml");
30
+ const projectName = "My Amazing Project";
31
+ const projectId = "5f284259ce1d451b2eb2e23c";
32
+
33
+ beforeEach(() => {
34
+ if (!fs.existsSync(fakeProjectDir)) fs.mkdirSync(fakeProjectDir);
35
+ _testing.saveProject(configFile, projectName, projectId);
36
+ });
37
+
38
+ afterEach(() => {
39
+ fs.rmdirSync(fakeProjectDir, { recursive: true });
40
+ });
41
+
42
+ it("creates a config file with config data", () => {
43
+ const fileContents = fs.readFileSync(configFile, "utf8");
44
+ const data = yaml.load(fileContents);
45
+ expect(data.projects).toBeDefined();
46
+ expect(data.projects[0].name).toEqual(projectName);
47
+ expect(data.projects[0].id).toEqual(projectId);
48
+ });
49
+ });
@@ -1,15 +1,17 @@
1
- const ora = require("ora");
2
-
3
- const api = require("../api").default;
4
- const config = require("../config");
5
- const consts = require("../consts");
6
- const output = require("../output");
7
- const { collectAndSaveToken } = require("../init/token");
8
- const {
1
+ import ora from "ora";
2
+
3
+ import api from "../api";
4
+ import config from "../config";
5
+ import consts from "../consts";
6
+ import output from "../output";
7
+ import { collectAndSaveToken } from "./token";
8
+ import {
9
9
  getSelectedProjects,
10
10
  getIsUsingComponents,
11
- } = require("../utils/getSelectedProjects");
12
- const promptForProject = require("../utils/promptForProject");
11
+ } from "../utils/getSelectedProjects";
12
+ import promptForProject from "../utils/promptForProject";
13
+ import { AxiosResponse } from "axios";
14
+ import { Project, Token } from "../types";
13
15
 
14
16
  function quit(exitCode = 2) {
15
17
  console.log("\nExiting Ditto CLI...\n");
@@ -17,23 +19,23 @@ function quit(exitCode = 2) {
17
19
  process.exit();
18
20
  }
19
21
 
20
- function saveProject(file, name, id) {
21
- // old functionality included "components" in the `projects`
22
+ function saveProject(file: string, name: string, id: string) {
23
+ // old functionality included "ditto_component_library" in the `projects`
22
24
  // array, but we want to always treat the component library as a separate
23
25
  // entity and use the new notation of a top-level `components` key
24
26
  if (id === "components") {
25
- config.writeData(file, { components: true });
27
+ config.writeProjectConfigData(file, { components: true });
26
28
  return;
27
29
  }
28
30
 
29
31
  const projects = [...getSelectedProjects(), { name, id }];
30
32
 
31
- config.writeData(file, { projects });
33
+ config.writeProjectConfigData(file, { projects });
32
34
  }
33
35
 
34
- function needsSource() {
36
+ export const needsSource = () => {
35
37
  return !config.parseSourceInformation().hasSourceData;
36
- }
38
+ };
37
39
 
38
40
  async function askForAnotherToken() {
39
41
  config.deleteToken(consts.CONFIG_FILE, consts.API_HOST);
@@ -43,17 +45,16 @@ async function askForAnotherToken() {
43
45
  }
44
46
 
45
47
  async function listProjects(
46
- token,
47
- projectsAlreadySelected,
48
- componentsSelected
48
+ token: Token,
49
+ projectsAlreadySelected: Project[],
50
+ componentsSelected: boolean
49
51
  ) {
50
52
  const spinner = ora("Fetching projects in your workspace...");
51
53
  spinner.start();
52
54
 
53
- let projects = [];
54
-
55
+ let response: AxiosResponse<{ id: string; name: string }[]>;
55
56
  try {
56
- projects = await api.get("/project-names", {
57
+ response = await api.get("/project-names", {
57
58
  headers: {
58
59
  Authorization: `token ${token}`,
59
60
  },
@@ -64,8 +65,7 @@ async function listProjects(
64
65
  }
65
66
 
66
67
  spinner.stop();
67
-
68
- return projects.data.filter(({ id }) => {
68
+ return response.data.filter(({ id }: Project) => {
69
69
  if (id === "ditto_component_library") {
70
70
  return !componentsSelected;
71
71
  } else {
@@ -74,7 +74,7 @@ async function listProjects(
74
74
  });
75
75
  }
76
76
 
77
- async function collectProject(token, initialize) {
77
+ async function collectProject(token: Token, initialize: boolean) {
78
78
  const path = process.cwd();
79
79
  if (initialize) {
80
80
  console.log(
@@ -114,7 +114,7 @@ async function collectProject(token, initialize) {
114
114
  });
115
115
  }
116
116
 
117
- async function collectAndSaveProject(initialize = false) {
117
+ export const collectAndSaveProject = async (initialize = false) => {
118
118
  try {
119
119
  const token = config.getToken(consts.CONFIG_FILE, consts.API_HOST);
120
120
  const project = await collectProject(token, initialize);
@@ -134,7 +134,7 @@ async function collectAndSaveProject(initialize = false) {
134
134
  );
135
135
 
136
136
  saveProject(consts.PROJECT_CONFIG_FILE, project.name, project.id);
137
- } catch (e) {
137
+ } catch (e: any) {
138
138
  console.log(e);
139
139
  if (e.response && e.response.status === 404) {
140
140
  await askForAnotherToken();
@@ -143,6 +143,8 @@ async function collectAndSaveProject(initialize = false) {
143
143
  quit();
144
144
  }
145
145
  }
146
- }
146
+ };
147
+
148
+ export const _testing = { saveProject, needsSource };
147
149
 
148
- module.exports = { needsSource, collectAndSaveProject };
150
+ export default { needsSource, collectAndSaveProject };
@@ -1,7 +1,7 @@
1
- const tempy = require("tempy");
1
+ import tempy from "tempy";
2
2
 
3
- const config = require("../config");
4
- const { needsToken } = require("./token");
3
+ import config from "../config";
4
+ import { needsToken } from "./token";
5
5
 
6
6
  describe("needsToken()", () => {
7
7
  it("is true if there is no config file", () => {