@dittowords/cli 3.2.2-alpha → 3.4.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/bin/ditto.js +37 -5
- package/bin/ditto.js.map +1 -1
- package/bin/generate-suggestions.js +19 -10
- package/bin/generate-suggestions.js.map +1 -1
- package/bin/http/fetchComponents.js.map +1 -1
- package/bin/replace.js +9 -3
- package/bin/replace.js.map +1 -1
- package/lib/ditto.ts +52 -13
- package/lib/generate-suggestions.test.ts +25 -24
- package/lib/generate-suggestions.ts +41 -24
- package/lib/http/fetchComponents.ts +12 -1
- package/lib/replace.test.ts +22 -3
- package/lib/replace.ts +15 -3
- package/package.json +1 -1
- package/testfiles/test1.jsx +18 -0
- package/testfiles/test2.jsx +9 -0
- package/bin/lib/add-project.js +0 -36
- package/bin/lib/add-project.js.map +0 -1
- package/bin/lib/api.js +0 -20
- package/bin/lib/api.js.map +0 -1
- package/bin/lib/config.js +0 -202
- package/bin/lib/config.js.map +0 -1
- package/bin/lib/consts.js +0 -21
- package/bin/lib/consts.js.map +0 -1
- package/bin/lib/ditto.js +0 -121
- package/bin/lib/ditto.js.map +0 -1
- package/bin/lib/generate-suggestions.js +0 -71
- package/bin/lib/generate-suggestions.js.map +0 -1
- package/bin/lib/http/fetchComponents.js +0 -13
- package/bin/lib/http/fetchComponents.js.map +0 -1
- package/bin/lib/http/fetchVariants.js +0 -26
- package/bin/lib/http/fetchVariants.js.map +0 -1
- package/bin/lib/init/init.js +0 -50
- package/bin/lib/init/init.js.map +0 -1
- package/bin/lib/init/project.js +0 -108
- package/bin/lib/init/project.js.map +0 -1
- package/bin/lib/init/token.js +0 -91
- package/bin/lib/init/token.js.map +0 -1
- package/bin/lib/output.js +0 -34
- package/bin/lib/output.js.map +0 -1
- package/bin/lib/pull.js +0 -264
- package/bin/lib/pull.js.map +0 -1
- package/bin/lib/remove-project.js +0 -35
- package/bin/lib/remove-project.js.map +0 -1
- package/bin/lib/replace.js +0 -107
- package/bin/lib/replace.js.map +0 -1
- package/bin/lib/types.js +0 -3
- package/bin/lib/types.js.map +0 -1
- package/bin/lib/utils/cleanFileName.js +0 -11
- package/bin/lib/utils/cleanFileName.js.map +0 -1
- package/bin/lib/utils/generateJsDriver.js +0 -56
- package/bin/lib/utils/generateJsDriver.js.map +0 -1
- package/bin/lib/utils/getSelectedProjects.js +0 -61
- package/bin/lib/utils/getSelectedProjects.js.map +0 -1
- package/bin/lib/utils/processMetaOption.js +0 -15
- package/bin/lib/utils/processMetaOption.js.map +0 -1
- package/bin/lib/utils/projectsToText.js +0 -25
- package/bin/lib/utils/projectsToText.js.map +0 -1
- package/bin/lib/utils/promptForProject.js +0 -43
- package/bin/lib/utils/promptForProject.js.map +0 -1
- package/bin/lib/utils/quit.js +0 -10
- package/bin/lib/utils/quit.js.map +0 -1
- package/bin/lib/utils/sourcesToText.js +0 -25
- package/bin/lib/utils/sourcesToText.js.map +0 -1
- package/bin/package.json +0 -76
package/bin/ditto.js
CHANGED
|
@@ -48,10 +48,21 @@ const COMMANDS = [
|
|
|
48
48
|
{
|
|
49
49
|
name: "generate-suggestions",
|
|
50
50
|
description: "Find text that can be potentially replaced with Ditto text",
|
|
51
|
+
flags: {
|
|
52
|
+
"-d, --directory [value]": {
|
|
53
|
+
description: "Directory to search for text",
|
|
54
|
+
},
|
|
55
|
+
},
|
|
51
56
|
},
|
|
52
57
|
{
|
|
53
58
|
name: "replace",
|
|
54
59
|
description: "Find and replace Ditto text with code",
|
|
60
|
+
flags: {
|
|
61
|
+
"-ln, --line-numbers [value]": {
|
|
62
|
+
description: "Only replace text on a specific line number",
|
|
63
|
+
processor: (value) => value.split(",").map(Number),
|
|
64
|
+
},
|
|
65
|
+
},
|
|
55
66
|
},
|
|
56
67
|
];
|
|
57
68
|
const setupCommands = () => {
|
|
@@ -60,13 +71,30 @@ const setupCommands = () => {
|
|
|
60
71
|
const cmd = commander_1.program
|
|
61
72
|
.command(commandConfig.name)
|
|
62
73
|
.description(commandConfig.description)
|
|
63
|
-
.action((
|
|
64
|
-
|
|
74
|
+
.action((options) => {
|
|
75
|
+
return executeCommand(commandConfig.name, options);
|
|
76
|
+
});
|
|
77
|
+
if (commandConfig.flags) {
|
|
78
|
+
Object.entries(commandConfig.flags).forEach(([flags, { description, processor }]) => {
|
|
79
|
+
if (processor) {
|
|
80
|
+
cmd.option(flags, description, processor);
|
|
81
|
+
}
|
|
82
|
+
else {
|
|
83
|
+
cmd.option(flags, description);
|
|
84
|
+
}
|
|
85
|
+
});
|
|
86
|
+
}
|
|
87
|
+
if ("commands" in commandConfig && commandConfig.commands) {
|
|
65
88
|
commandConfig.commands.forEach((nestedCommand) => {
|
|
66
89
|
cmd
|
|
67
90
|
.command(nestedCommand.name)
|
|
68
91
|
.description(nestedCommand.description)
|
|
69
|
-
.action((str, options) =>
|
|
92
|
+
.action((str, options) => {
|
|
93
|
+
if (commandConfig.name === "project") {
|
|
94
|
+
const command = `${commandConfig.name} ${nestedCommand.name}`;
|
|
95
|
+
return executeCommand(command, options);
|
|
96
|
+
}
|
|
97
|
+
});
|
|
70
98
|
});
|
|
71
99
|
}
|
|
72
100
|
});
|
|
@@ -105,10 +133,14 @@ const executeCommand = async (command, options) => {
|
|
|
105
133
|
return (0, remove_project_1.default)();
|
|
106
134
|
}
|
|
107
135
|
case "generate-suggestions": {
|
|
108
|
-
return (0, generate_suggestions_1.generateSuggestions)(
|
|
136
|
+
return (0, generate_suggestions_1.generateSuggestions)({
|
|
137
|
+
...(options.directory ? { directory: options.directory } : {}),
|
|
138
|
+
});
|
|
109
139
|
}
|
|
110
140
|
case "replace": {
|
|
111
|
-
return (0, replace_1.replace)(options
|
|
141
|
+
return (0, replace_1.replace)(options.args, {
|
|
142
|
+
...(options?.lineNumbers ? { lineNumbers: options.lineNumbers } : {}),
|
|
143
|
+
});
|
|
112
144
|
}
|
|
113
145
|
default: {
|
|
114
146
|
(0, quit_1.quit)("Exiting Ditto CLI...");
|
package/bin/ditto.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ditto.js","sourceRoot":"","sources":["../lib/ditto.ts"],"names":[],"mappings":";;;;;;AACA,0DAA0D;AAC1D,yCAAoC;AACpC,wDAAwD;AACxD,4BAA0B;AAC1B,4CAAoB;AACpB,gDAAwB;AAExB,sCAAuD;AACvD,iCAA8B;AAC9B,uCAAoC;AACpC,gEAAuC;AACvC,sEAA6C;AAC7C,uCAAoC;AACpC,iEAA6D;AAE7D,kFAA0D;AAE1D,SAAS,UAAU;IACjB,MAAM,eAAe,GAAG,cAAI,CAAC,IAAI,CAAC,SAAS,EAAE,IAAI,EAAE,cAAc,CAAC,CAAC;IACnE,MAAM,kBAAkB,GAAG,YAAE,CAAC,YAAY,CAAC,eAAe,EAAE,MAAM,CAAC,CAAC;IACpE,MAAM,WAAW,GAAG,IAAI,CAAC,KAAK,CAAC,kBAAkB,CAAwB,CAAC;IAC1E,MAAM,OAAO,GAAG,WAAW,CAAC,OAAO,CAAC;IAEpC,OAAO,OAAO,CAAC;AACjB,CAAC;AAED,MAAM,OAAO,GAAG,UAAU,EAAE,CAAC;
|
|
1
|
+
{"version":3,"file":"ditto.js","sourceRoot":"","sources":["../lib/ditto.ts"],"names":[],"mappings":";;;;;;AACA,0DAA0D;AAC1D,yCAAoC;AACpC,wDAAwD;AACxD,4BAA0B;AAC1B,4CAAoB;AACpB,gDAAwB;AAExB,sCAAuD;AACvD,iCAA8B;AAC9B,uCAAoC;AACpC,gEAAuC;AACvC,sEAA6C;AAC7C,uCAAoC;AACpC,iEAA6D;AAE7D,kFAA0D;AAE1D,SAAS,UAAU;IACjB,MAAM,eAAe,GAAG,cAAI,CAAC,IAAI,CAAC,SAAS,EAAE,IAAI,EAAE,cAAc,CAAC,CAAC;IACnE,MAAM,kBAAkB,GAAG,YAAE,CAAC,YAAY,CAAC,eAAe,EAAE,MAAM,CAAC,CAAC;IACpE,MAAM,WAAW,GAAG,IAAI,CAAC,KAAK,CAAC,kBAAkB,CAAwB,CAAC;IAC1E,MAAM,OAAO,GAAG,WAAW,CAAC,OAAO,CAAC;IAEpC,OAAO,OAAO,CAAC;AACjB,CAAC;AAED,MAAM,OAAO,GAAG,UAAU,EAAE,CAAC;AAmB7B,MAAM,QAAQ,GAA6B;IACzC;QACE,IAAI,EAAE,MAAM;QACZ,WAAW,EAAE,yDAAyD;KACvE;IACD;QACE,IAAI,EAAE,SAAS;QACf,WAAW,EAAE,uCAAuC;QACpD,QAAQ,EAAE;YACR;gBACE,IAAI,EAAE,KAAK;gBACX,WAAW,EAAE,uCAAuC;aACrD;YACD;gBACE,IAAI,EAAE,QAAQ;gBACd,WAAW,EAAE,wCAAwC;aACtD;SACF;KACF;IACD;QACE,IAAI,EAAE,sBAAsB;QAC5B,WAAW,EAAE,4DAA4D;QACzE,KAAK,EAAE;YACL,yBAAyB,EAAE;gBACzB,WAAW,EAAE,8BAA8B;aAC5C;SACF;KACF;IACD;QACE,IAAI,EAAE,SAAS;QACf,WAAW,EAAE,uCAAuC;QACpD,KAAK,EAAE;YACL,6BAA6B,EAAE;gBAC7B,WAAW,EAAE,6CAA6C;gBAC1D,SAAS,EAAE,CAAC,KAAa,EAAE,EAAE,CAAC,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,MAAM,CAAC;aAC3D;SACF;KACF;CACF,CAAC;AAEF,MAAM,aAAa,GAAG,GAAG,EAAE;IACzB,mBAAO,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC;IAE1B,QAAQ,CAAC,OAAO,CAAC,CAAC,aAAa,EAAE,EAAE;QACjC,MAAM,GAAG,GAAG,mBAAO;aAChB,OAAO,CAAC,aAAa,CAAC,IAAI,CAAC;aAC3B,WAAW,CAAC,aAAa,CAAC,WAAW,CAAC;aACtC,MAAM,CAAC,CAAC,OAAO,EAAE,EAAE;YAClB,OAAO,cAAc,CAAC,aAAa,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC;QACrD,CAAC,CAAC,CAAC;QAEL,IAAI,aAAa,CAAC,KAAK,EAAE;YACvB,MAAM,CAAC,OAAO,CAAC,aAAa,CAAC,KAAK,CAAC,CAAC,OAAO,CACzC,CAAC,CAAC,KAAK,EAAE,EAAE,WAAW,EAAE,SAAS,EAAE,CAAC,EAAE,EAAE;gBACtC,IAAI,SAAS,EAAE;oBACb,GAAG,CAAC,MAAM,CAAC,KAAK,EAAE,WAAW,EAAE,SAAS,CAAC,CAAC;iBAC3C;qBAAM;oBACL,GAAG,CAAC,MAAM,CAAC,KAAK,EAAE,WAAW,CAAC,CAAC;iBAChC;YACH,CAAC,CACF,CAAC;SACH;QAED,IAAI,UAAU,IAAI,aAAa,IAAI,aAAa,CAAC,QAAQ,EAAE;YACzD,aAAa,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC,aAAa,EAAE,EAAE;gBAC/C,GAAG;qBACA,OAAO,CAAC,aAAa,CAAC,IAAI,CAAC;qBAC3B,WAAW,CAAC,aAAa,CAAC,WAAW,CAAC;qBACtC,MAAM,CAAC,CAAC,GAAG,EAAE,OAAO,EAAE,EAAE;oBACvB,IAAI,aAAa,CAAC,IAAI,KAAK,SAAS,EAAE;wBACpC,MAAM,OAAO,GACX,GAAG,aAAa,CAAC,IAAI,IAAI,aAAa,CAAC,IAAI,EAAa,CAAC;wBAC3D,OAAO,cAAc,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC;qBACzC;gBACH,CAAC,CAAC,CAAC;YACP,CAAC,CAAC,CAAC;SACJ;IACH,CAAC,CAAC,CAAC;AACL,CAAC,CAAC;AAEF,MAAM,YAAY,GAAG,GAAG,EAAE;IACxB,mBAAO,CAAC,MAAM,CACZ,sBAAsB,EACtB,qGAAqG,CACtG,CAAC;IACF,mBAAO,CAAC,OAAO,CAAC,OAAO,EAAE,eAAe,EAAE,4BAA4B,CAAC,CAAC;AAC1E,CAAC,CAAC;AAEF,MAAM,cAAc,GAAG,KAAK,EAC1B,OAAyB,EACzB,OAAY,EACG,EAAE;IACjB,MAAM,mBAAmB,GAAG,IAAA,yBAAkB,GAAE,CAAC;IACjD,IAAI,mBAAmB,EAAE;QACvB,IAAI;YACF,MAAM,IAAA,WAAI,GAAE,CAAC;SACd;QAAC,OAAO,KAAK,EAAE;YACd,IAAA,WAAI,EAAC,sBAAsB,CAAC,CAAC;YAC7B,OAAO;SACR;KACF;IAED,MAAM,EAAE,IAAI,EAAE,GAAG,mBAAO,CAAC,IAAI,EAAE,CAAC;IAChC,QAAQ,OAAO,EAAE;QACf,KAAK,MAAM,CAAC;QACZ,KAAK,MAAM,CAAC,CAAC;YACX,OAAO,IAAA,WAAI,EAAC,EAAE,IAAI,EAAE,IAAA,2BAAiB,EAAC,IAAI,CAAC,EAAE,CAAC,CAAC;SAChD;QACD,KAAK,SAAS,CAAC;QACf,KAAK,aAAa,CAAC,CAAC;YAClB,6DAA6D;YAC7D,6DAA6D;YAC7D,2CAA2C;YAC3C,IAAI,mBAAmB;gBAAE,OAAO;YAEhC,OAAO,IAAA,qBAAU,GAAE,CAAC;SACrB;QACD,KAAK,gBAAgB,CAAC,CAAC;YACrB,OAAO,IAAA,wBAAa,GAAE,CAAC;SACxB;QACD,KAAK,sBAAsB,CAAC,CAAC;YAC3B,OAAO,IAAA,0CAAmB,EAAC;gBACzB,GAAG,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC,CAAC,EAAE,SAAS,EAAE,OAAO,CAAC,SAAS,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;aAC/D,CAAC,CAAC;SACJ;QACD,KAAK,SAAS,CAAC,CAAC;YACd,OAAO,IAAA,iBAAO,EAAC,OAAO,CAAC,IAAI,EAAE;gBAC3B,GAAG,CAAC,OAAO,EAAE,WAAW,CAAC,CAAC,CAAC,EAAE,WAAW,EAAE,OAAO,CAAC,WAAW,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;aACtE,CAAC,CAAC;SACJ;QACD,OAAO,CAAC,CAAC;YACP,IAAA,WAAI,EAAC,sBAAsB,CAAC,CAAC;YAC7B,OAAO;SACR;KACF;AACH,CAAC,CAAC;AAEF,MAAM,IAAI,GAAG,KAAK,IAAI,EAAE;IACtB,aAAa,EAAE,CAAC;IAChB,YAAY,EAAE,CAAC;IAEf,IAAI,OAAO,CAAC,IAAI,CAAC,MAAM,IAAI,CAAC,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,WAAW,CAAC,EAAE;QACrE,MAAM,cAAc,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC;QACjC,OAAO;KACR;IAED,mBAAO,CAAC,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;AAC9B,CAAC,CAAC;AAEF,IAAI,EAAE,CAAC"}
|
|
@@ -9,27 +9,33 @@ const glob_1 = __importDefault(require("glob"));
|
|
|
9
9
|
const parser_1 = require("@babel/parser");
|
|
10
10
|
const traverse_1 = __importDefault(require("@babel/traverse"));
|
|
11
11
|
const fetchComponents_1 = require("./http/fetchComponents");
|
|
12
|
-
async function generateSuggestions() {
|
|
12
|
+
async function generateSuggestions(flags) {
|
|
13
13
|
const components = await (0, fetchComponents_1.fetchComponents)();
|
|
14
14
|
const results = {};
|
|
15
15
|
for (const [compApiId, component] of Object.entries(components)) {
|
|
16
16
|
if (!results[compApiId]) {
|
|
17
|
-
results[compApiId] =
|
|
17
|
+
results[compApiId] = { apiId: compApiId, ...component, occurrences: {} };
|
|
18
|
+
}
|
|
19
|
+
const directory = flags.directory || ".";
|
|
20
|
+
const result = await findTextInJSXFiles(directory, component);
|
|
21
|
+
results[compApiId].occurrences = result;
|
|
22
|
+
// Remove if there the length is zero
|
|
23
|
+
if (Object.keys(results[compApiId].occurrences).length === 0) {
|
|
24
|
+
delete results[compApiId];
|
|
18
25
|
}
|
|
19
|
-
const result = await findTextInJSXFiles(".", component.text);
|
|
20
|
-
results[compApiId] = [...results[compApiId], ...result];
|
|
21
26
|
}
|
|
22
27
|
// Display results to user
|
|
23
28
|
console.log(JSON.stringify(results, null, 2));
|
|
24
29
|
}
|
|
25
30
|
exports.generateSuggestions = generateSuggestions;
|
|
26
|
-
async function findTextInJSXFiles(path,
|
|
27
|
-
const result =
|
|
31
|
+
async function findTextInJSXFiles(path, component) {
|
|
32
|
+
const result = {};
|
|
28
33
|
const files = glob_1.default.sync(`${path}/**/*.+(jsx|tsx)`, {
|
|
29
34
|
ignore: "**/node_modules/**",
|
|
30
35
|
});
|
|
31
36
|
const promises = [];
|
|
32
37
|
for (const file of files) {
|
|
38
|
+
result[file] = [];
|
|
33
39
|
promises.push(fs_extra_1.default.readFile(file, "utf-8").then((code) => {
|
|
34
40
|
const ast = (0, parser_1.parse)(code, {
|
|
35
41
|
sourceType: "module",
|
|
@@ -38,8 +44,8 @@ async function findTextInJSXFiles(path, searchString) {
|
|
|
38
44
|
const occurrences = [];
|
|
39
45
|
(0, traverse_1.default)(ast, {
|
|
40
46
|
JSXText(path) {
|
|
41
|
-
if (path.node.value.includes(
|
|
42
|
-
const regex = new RegExp(
|
|
47
|
+
if (path.node.value.includes(component.text)) {
|
|
48
|
+
const regex = new RegExp(component.text, "g");
|
|
43
49
|
let match;
|
|
44
50
|
while ((match = regex.exec(path.node.value)) !== null) {
|
|
45
51
|
const lines = path.node.value.slice(0, match.index).split("\n");
|
|
@@ -49,14 +55,17 @@ async function findTextInJSXFiles(path, searchString) {
|
|
|
49
55
|
const lineNumber = path.node.loc.start.line + lines.length - 1;
|
|
50
56
|
const codeLines = code.split("\n");
|
|
51
57
|
const line = codeLines[lineNumber - 1];
|
|
52
|
-
const preview = replaceAt(line, match.index,
|
|
58
|
+
const preview = replaceAt(line, match.index, component.text, `${component.text}`);
|
|
53
59
|
occurrences.push({ lineNumber, preview });
|
|
54
60
|
}
|
|
55
61
|
}
|
|
56
62
|
},
|
|
57
63
|
});
|
|
58
64
|
if (occurrences.length > 0) {
|
|
59
|
-
result
|
|
65
|
+
result[file] = occurrences;
|
|
66
|
+
}
|
|
67
|
+
else {
|
|
68
|
+
delete result[file];
|
|
60
69
|
}
|
|
61
70
|
}));
|
|
62
71
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"generate-suggestions.js","sourceRoot":"","sources":["../lib/generate-suggestions.ts"],"names":[],"mappings":";;;;;;AAAA,wDAA0B;AAC1B,gDAAwB;AACxB,0CAAsC;AACtC,+DAAuC;AAEvC,
|
|
1
|
+
{"version":3,"file":"generate-suggestions.js","sourceRoot":"","sources":["../lib/generate-suggestions.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"fetchComponents.js","sourceRoot":"","sources":["../../lib/http/fetchComponents.ts"],"names":[],"mappings":";;;;;;AAAA,iDAAyB;
|
|
1
|
+
{"version":3,"file":"fetchComponents.js","sourceRoot":"","sources":["../../lib/http/fetchComponents.ts"],"names":[],"mappings":";;;;;;AAAA,iDAAyB;AAalB,KAAK,UAAU,eAAe;IACnC,MAAM,EAAE,IAAI,EAAE,GAAG,MAAM,aAAG,CAAC,GAAG,CAO3B,aAAa,EAAE,EAAE,CAAC,CAAC;IAEtB,OAAO,IAAI,CAAC;AACd,CAAC;AAXD,0CAWC"}
|
package/bin/replace.js
CHANGED
|
@@ -32,7 +32,7 @@ const parser_1 = require("@babel/parser");
|
|
|
32
32
|
const traverse_1 = __importDefault(require("@babel/traverse"));
|
|
33
33
|
const t = __importStar(require("@babel/types"));
|
|
34
34
|
const core_1 = require("@babel/core");
|
|
35
|
-
async function replaceJSXTextInFile(filePath, replacement) {
|
|
35
|
+
async function replaceJSXTextInFile(filePath, replacement, flags) {
|
|
36
36
|
const code = await fs_extra_1.default.readFile(filePath, "utf-8");
|
|
37
37
|
const ast = (0, parser_1.parse)(code, {
|
|
38
38
|
sourceType: "module",
|
|
@@ -43,6 +43,12 @@ async function replaceJSXTextInFile(filePath, replacement) {
|
|
|
43
43
|
const { searchString, replaceWith } = replacement;
|
|
44
44
|
const regex = new RegExp(searchString, "gi");
|
|
45
45
|
if (regex.test(path.node.value)) {
|
|
46
|
+
// Ignore if not on a line number that we want to replace.
|
|
47
|
+
if (flags.lineNumbers &&
|
|
48
|
+
path.node.loc &&
|
|
49
|
+
!flags.lineNumbers.includes(path.node.loc.start.line)) {
|
|
50
|
+
return;
|
|
51
|
+
}
|
|
46
52
|
const splitValues = splitByCaseInsensitive(path.node.value, searchString);
|
|
47
53
|
const nodes = [];
|
|
48
54
|
splitValues.forEach((splitValue) => {
|
|
@@ -73,7 +79,7 @@ exports.replaceJSXTextInFile = replaceJSXTextInFile;
|
|
|
73
79
|
function splitByCaseInsensitive(str, delimiter) {
|
|
74
80
|
return str.split(new RegExp(`(${delimiter})`, "gi")).filter((s) => s !== "");
|
|
75
81
|
}
|
|
76
|
-
function replace(options) {
|
|
82
|
+
function replace(options, flags) {
|
|
77
83
|
let filePath;
|
|
78
84
|
let searchString;
|
|
79
85
|
let replaceWith;
|
|
@@ -88,7 +94,7 @@ function replace(options) {
|
|
|
88
94
|
console.error("Usage for replace: ditto-cli replace <file path> <search string> <replace with>");
|
|
89
95
|
return;
|
|
90
96
|
}
|
|
91
|
-
replaceJSXTextInFile(filePath, { searchString, replaceWith });
|
|
97
|
+
replaceJSXTextInFile(filePath, { searchString, replaceWith }, flags);
|
|
92
98
|
}
|
|
93
99
|
exports.replace = replace;
|
|
94
100
|
function parseOptions(options) {
|
package/bin/replace.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"replace.js","sourceRoot":"","sources":["../lib/replace.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA,wDAA0B;AAC1B,0CAAsC;AACtC,+DAAuC;AACvC,gDAAkC;AAClC,sCAA+C;AAE/C,KAAK,UAAU,oBAAoB,CACjC,QAAgB,EAChB,WAA0D;
|
|
1
|
+
{"version":3,"file":"replace.js","sourceRoot":"","sources":["../lib/replace.ts"],"names":[],"mappings":"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"}
|
package/lib/ditto.ts
CHANGED
|
@@ -35,7 +35,16 @@ type Command =
|
|
|
35
35
|
| "generate-suggestions"
|
|
36
36
|
| "replace";
|
|
37
37
|
|
|
38
|
-
|
|
38
|
+
interface CommandConfig<T extends Command | "add" | "remove"> {
|
|
39
|
+
name: T;
|
|
40
|
+
description: string;
|
|
41
|
+
commands?: CommandConfig<"add" | "remove">[];
|
|
42
|
+
flags?: {
|
|
43
|
+
[flag: string]: { description: string; processor?: (value: string) => any };
|
|
44
|
+
};
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
const COMMANDS: CommandConfig<Command>[] = [
|
|
39
48
|
{
|
|
40
49
|
name: "pull",
|
|
41
50
|
description: "Sync copy from Ditto into the current working directory",
|
|
@@ -57,12 +66,23 @@ const COMMANDS = [
|
|
|
57
66
|
{
|
|
58
67
|
name: "generate-suggestions",
|
|
59
68
|
description: "Find text that can be potentially replaced with Ditto text",
|
|
69
|
+
flags: {
|
|
70
|
+
"-d, --directory [value]": {
|
|
71
|
+
description: "Directory to search for text",
|
|
72
|
+
},
|
|
73
|
+
},
|
|
60
74
|
},
|
|
61
75
|
{
|
|
62
76
|
name: "replace",
|
|
63
77
|
description: "Find and replace Ditto text with code",
|
|
78
|
+
flags: {
|
|
79
|
+
"-ln, --line-numbers [value]": {
|
|
80
|
+
description: "Only replace text on a specific line number",
|
|
81
|
+
processor: (value: string) => value.split(",").map(Number),
|
|
82
|
+
},
|
|
83
|
+
},
|
|
64
84
|
},
|
|
65
|
-
]
|
|
85
|
+
];
|
|
66
86
|
|
|
67
87
|
const setupCommands = () => {
|
|
68
88
|
program.name("ditto-cli");
|
|
@@ -71,19 +91,34 @@ const setupCommands = () => {
|
|
|
71
91
|
const cmd = program
|
|
72
92
|
.command(commandConfig.name)
|
|
73
93
|
.description(commandConfig.description)
|
|
74
|
-
.action((
|
|
94
|
+
.action((options) => {
|
|
95
|
+
return executeCommand(commandConfig.name, options);
|
|
96
|
+
});
|
|
75
97
|
|
|
76
|
-
if (
|
|
98
|
+
if (commandConfig.flags) {
|
|
99
|
+
Object.entries(commandConfig.flags).forEach(
|
|
100
|
+
([flags, { description, processor }]) => {
|
|
101
|
+
if (processor) {
|
|
102
|
+
cmd.option(flags, description, processor);
|
|
103
|
+
} else {
|
|
104
|
+
cmd.option(flags, description);
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
);
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
if ("commands" in commandConfig && commandConfig.commands) {
|
|
77
111
|
commandConfig.commands.forEach((nestedCommand) => {
|
|
78
112
|
cmd
|
|
79
113
|
.command(nestedCommand.name)
|
|
80
114
|
.description(nestedCommand.description)
|
|
81
|
-
.action((str, options) =>
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
115
|
+
.action((str, options) => {
|
|
116
|
+
if (commandConfig.name === "project") {
|
|
117
|
+
const command =
|
|
118
|
+
`${commandConfig.name} ${nestedCommand.name}` as Command;
|
|
119
|
+
return executeCommand(command, options);
|
|
120
|
+
}
|
|
121
|
+
});
|
|
87
122
|
});
|
|
88
123
|
}
|
|
89
124
|
});
|
|
@@ -99,7 +134,7 @@ const setupOptions = () => {
|
|
|
99
134
|
|
|
100
135
|
const executeCommand = async (
|
|
101
136
|
command: Command | "none",
|
|
102
|
-
options:
|
|
137
|
+
options: any
|
|
103
138
|
): Promise<void> => {
|
|
104
139
|
const needsInitialization = needsTokenOrSource();
|
|
105
140
|
if (needsInitialization) {
|
|
@@ -130,10 +165,14 @@ const executeCommand = async (
|
|
|
130
165
|
return removeProject();
|
|
131
166
|
}
|
|
132
167
|
case "generate-suggestions": {
|
|
133
|
-
return generateSuggestions(
|
|
168
|
+
return generateSuggestions({
|
|
169
|
+
...(options.directory ? { directory: options.directory } : {}),
|
|
170
|
+
});
|
|
134
171
|
}
|
|
135
172
|
case "replace": {
|
|
136
|
-
return replace(options
|
|
173
|
+
return replace(options.args, {
|
|
174
|
+
...(options?.lineNumbers ? { lineNumbers: options.lineNumbers } : {}),
|
|
175
|
+
});
|
|
137
176
|
}
|
|
138
177
|
default: {
|
|
139
178
|
quit("Exiting Ditto CLI...");
|
|
@@ -14,19 +14,23 @@ describe("findTextInJSXFiles", () => {
|
|
|
14
14
|
await fs.unlink(filePath);
|
|
15
15
|
}
|
|
16
16
|
|
|
17
|
-
it("should return an empty
|
|
18
|
-
const result = await findTextInJSXFiles(".",
|
|
17
|
+
it("should return an empty obj when no files are found", async () => {
|
|
18
|
+
const result = await findTextInJSXFiles(".", {
|
|
19
|
+
text: "searchString",
|
|
20
|
+
} as any);
|
|
19
21
|
|
|
20
|
-
expect(result).toEqual(
|
|
22
|
+
expect(result).toEqual({});
|
|
21
23
|
});
|
|
22
24
|
|
|
23
|
-
it("should return an empty
|
|
25
|
+
it("should return an empty obj when searchString is not found in any file", async () => {
|
|
24
26
|
const file1 = await createTempFile("file1.jsx", "<div>No match</div>");
|
|
25
27
|
const file2 = await createTempFile("file2.tsx", "<div>No match</div>");
|
|
26
28
|
|
|
27
|
-
const result = await findTextInJSXFiles(".",
|
|
29
|
+
const result = await findTextInJSXFiles(".", {
|
|
30
|
+
text: "searchString",
|
|
31
|
+
} as any);
|
|
28
32
|
|
|
29
|
-
expect(result).toEqual(
|
|
33
|
+
expect(result).toEqual({});
|
|
30
34
|
|
|
31
35
|
await deleteTempFile(file1);
|
|
32
36
|
await deleteTempFile(file2);
|
|
@@ -38,25 +42,22 @@ describe("findTextInJSXFiles", () => {
|
|
|
38
42
|
`<div>Test searchString and another searchString</div>`
|
|
39
43
|
);
|
|
40
44
|
|
|
41
|
-
const expectedResult =
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
"<div>Test searchString and another {{searchString}}</div>",
|
|
54
|
-
},
|
|
55
|
-
],
|
|
56
|
-
},
|
|
57
|
-
];
|
|
45
|
+
const expectedResult = {
|
|
46
|
+
[file1]: [
|
|
47
|
+
{
|
|
48
|
+
lineNumber: 1,
|
|
49
|
+
preview: "<div>Test searchString and another searchString</div>",
|
|
50
|
+
},
|
|
51
|
+
{
|
|
52
|
+
lineNumber: 1,
|
|
53
|
+
preview: "<div>Test searchString and another searchString</div>",
|
|
54
|
+
},
|
|
55
|
+
],
|
|
56
|
+
};
|
|
58
57
|
|
|
59
|
-
const result = await findTextInJSXFiles(".",
|
|
58
|
+
const result = await findTextInJSXFiles(".", {
|
|
59
|
+
text: "searchString",
|
|
60
|
+
} as any);
|
|
60
61
|
|
|
61
62
|
expect(result).toEqual(expectedResult);
|
|
62
63
|
|
|
@@ -3,38 +3,51 @@ import glob from "glob";
|
|
|
3
3
|
import { parse } from "@babel/parser";
|
|
4
4
|
import traverse from "@babel/traverse";
|
|
5
5
|
|
|
6
|
-
import {
|
|
6
|
+
import {
|
|
7
|
+
FetchComponentResponseComponent,
|
|
8
|
+
fetchComponents,
|
|
9
|
+
} from "./http/fetchComponents";
|
|
10
|
+
|
|
11
|
+
interface Result extends FetchComponentResponseComponent {
|
|
12
|
+
apiId: string;
|
|
13
|
+
occurrences: {
|
|
14
|
+
[file: string]: Occurrence[];
|
|
15
|
+
};
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
interface Occurrence {
|
|
19
|
+
lineNumber: number;
|
|
20
|
+
preview: string;
|
|
21
|
+
}
|
|
7
22
|
|
|
8
|
-
async function generateSuggestions() {
|
|
23
|
+
async function generateSuggestions(flags: { directory?: string }) {
|
|
9
24
|
const components = await fetchComponents();
|
|
10
|
-
const results: {
|
|
11
|
-
[compApiId: string]: FindResults;
|
|
12
|
-
} = {};
|
|
25
|
+
const results: { [apiId: string]: Result } = {};
|
|
13
26
|
|
|
14
27
|
for (const [compApiId, component] of Object.entries(components)) {
|
|
15
28
|
if (!results[compApiId]) {
|
|
16
|
-
results[compApiId] =
|
|
29
|
+
results[compApiId] = { apiId: compApiId, ...component, occurrences: {} };
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
const directory = flags.directory || ".";
|
|
33
|
+
const result = await findTextInJSXFiles(directory, component);
|
|
34
|
+
results[compApiId].occurrences = result;
|
|
35
|
+
|
|
36
|
+
// Remove if there the length is zero
|
|
37
|
+
if (Object.keys(results[compApiId].occurrences).length === 0) {
|
|
38
|
+
delete results[compApiId];
|
|
17
39
|
}
|
|
18
|
-
const result = await findTextInJSXFiles(".", component.text);
|
|
19
|
-
results[compApiId] = [...results[compApiId], ...result];
|
|
20
40
|
}
|
|
21
41
|
|
|
22
42
|
// Display results to user
|
|
23
43
|
console.log(JSON.stringify(results, null, 2));
|
|
24
44
|
}
|
|
25
45
|
|
|
26
|
-
interface Occurence {
|
|
27
|
-
lineNumber: number;
|
|
28
|
-
preview: string;
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
type FindResults = { file: string; occurrences: Occurence[] }[];
|
|
32
|
-
|
|
33
46
|
async function findTextInJSXFiles(
|
|
34
47
|
path: string,
|
|
35
|
-
|
|
36
|
-
)
|
|
37
|
-
const result:
|
|
48
|
+
component: FetchComponentResponseComponent
|
|
49
|
+
) {
|
|
50
|
+
const result: Result["occurrences"] = {};
|
|
38
51
|
const files = glob.sync(`${path}/**/*.+(jsx|tsx)`, {
|
|
39
52
|
ignore: "**/node_modules/**",
|
|
40
53
|
});
|
|
@@ -42,6 +55,8 @@ async function findTextInJSXFiles(
|
|
|
42
55
|
const promises: Promise<any>[] = [];
|
|
43
56
|
|
|
44
57
|
for (const file of files) {
|
|
58
|
+
result[file] = [];
|
|
59
|
+
|
|
45
60
|
promises.push(
|
|
46
61
|
fs.readFile(file, "utf-8").then((code) => {
|
|
47
62
|
const ast = parse(code, {
|
|
@@ -49,12 +64,12 @@ async function findTextInJSXFiles(
|
|
|
49
64
|
plugins: ["jsx", "typescript"],
|
|
50
65
|
});
|
|
51
66
|
|
|
52
|
-
const occurrences:
|
|
67
|
+
const occurrences: Occurrence[] = [];
|
|
53
68
|
|
|
54
69
|
traverse(ast, {
|
|
55
70
|
JSXText(path) {
|
|
56
|
-
if (path.node.value.includes(
|
|
57
|
-
const regex = new RegExp(
|
|
71
|
+
if (path.node.value.includes(component.text)) {
|
|
72
|
+
const regex = new RegExp(component.text, "g");
|
|
58
73
|
let match;
|
|
59
74
|
while ((match = regex.exec(path.node.value)) !== null) {
|
|
60
75
|
const lines = path.node.value.slice(0, match.index).split("\n");
|
|
@@ -70,8 +85,8 @@ async function findTextInJSXFiles(
|
|
|
70
85
|
const preview = replaceAt(
|
|
71
86
|
line,
|
|
72
87
|
match.index,
|
|
73
|
-
|
|
74
|
-
|
|
88
|
+
component.text,
|
|
89
|
+
`${component.text}`
|
|
75
90
|
);
|
|
76
91
|
|
|
77
92
|
occurrences.push({ lineNumber, preview });
|
|
@@ -81,7 +96,9 @@ async function findTextInJSXFiles(
|
|
|
81
96
|
});
|
|
82
97
|
|
|
83
98
|
if (occurrences.length > 0) {
|
|
84
|
-
result
|
|
99
|
+
result[file] = occurrences;
|
|
100
|
+
} else {
|
|
101
|
+
delete result[file];
|
|
85
102
|
}
|
|
86
103
|
})
|
|
87
104
|
);
|
|
@@ -1,6 +1,17 @@
|
|
|
1
1
|
import api from "../api";
|
|
2
2
|
|
|
3
|
-
export
|
|
3
|
+
export interface FetchComponentResponseComponent {
|
|
4
|
+
name: string;
|
|
5
|
+
text: string;
|
|
6
|
+
status: "NONE" | "WIP" | "REVIEW" | "FINAL";
|
|
7
|
+
folder: "string" | null;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
export interface FetchComponentResponse {
|
|
11
|
+
[compApiId: string]: FetchComponentResponseComponent;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export async function fetchComponents(): Promise<FetchComponentResponse> {
|
|
4
15
|
const { data } = await api.get<{
|
|
5
16
|
[compApiId: string]: {
|
|
6
17
|
name: string;
|
package/lib/replace.test.ts
CHANGED
|
@@ -67,7 +67,7 @@ describe("replaceJSXTextInFile", () => {
|
|
|
67
67
|
const searchString = "world";
|
|
68
68
|
const replaceWith = "some-id";
|
|
69
69
|
|
|
70
|
-
await replaceJSXTextInFile(tempFile, { searchString, replaceWith });
|
|
70
|
+
await replaceJSXTextInFile(tempFile, { searchString, replaceWith }, {});
|
|
71
71
|
|
|
72
72
|
const transformedCode = await fs.readFile(tempFile, "utf-8");
|
|
73
73
|
expect(transformedCode).toContain(
|
|
@@ -75,12 +75,31 @@ describe("replaceJSXTextInFile", () => {
|
|
|
75
75
|
);
|
|
76
76
|
});
|
|
77
77
|
|
|
78
|
+
test("should replace JSX text with a DittoComponent with a flag", async () => {
|
|
79
|
+
const tempFile = await createTempJSXFile(
|
|
80
|
+
`<>\n<div>Hello, world</div>\n<div>Hello, world</div>\n</>`
|
|
81
|
+
);
|
|
82
|
+
const searchString = "world";
|
|
83
|
+
const replaceWith = "some-id";
|
|
84
|
+
|
|
85
|
+
await replaceJSXTextInFile(
|
|
86
|
+
tempFile,
|
|
87
|
+
{ searchString, replaceWith },
|
|
88
|
+
{ lineNumbers: [3] }
|
|
89
|
+
);
|
|
90
|
+
|
|
91
|
+
const transformedCode = await fs.readFile(tempFile, "utf-8");
|
|
92
|
+
expect(transformedCode).toContain(
|
|
93
|
+
`<>\n <div>Hello, world</div>\n <div>Hello, <DittoComponent componentId=\"some-id\" /></div>\n</>;`
|
|
94
|
+
);
|
|
95
|
+
});
|
|
96
|
+
|
|
78
97
|
test("should handle case-insensitive search", async () => {
|
|
79
98
|
const tempFile = await createTempJSXFile("<div>HeLLo, WoRlD</div>");
|
|
80
99
|
const searchString = "world";
|
|
81
100
|
const replaceWith = "some-id";
|
|
82
101
|
|
|
83
|
-
await replaceJSXTextInFile(tempFile, { searchString, replaceWith });
|
|
102
|
+
await replaceJSXTextInFile(tempFile, { searchString, replaceWith }, {});
|
|
84
103
|
|
|
85
104
|
const transformedCode = await fs.readFile(tempFile, "utf-8");
|
|
86
105
|
expect(transformedCode).toContain(
|
|
@@ -93,7 +112,7 @@ describe("replaceJSXTextInFile", () => {
|
|
|
93
112
|
const searchString = "foobar";
|
|
94
113
|
const replaceWith = "some-id";
|
|
95
114
|
|
|
96
|
-
await replaceJSXTextInFile(tempFile, { searchString, replaceWith });
|
|
115
|
+
await replaceJSXTextInFile(tempFile, { searchString, replaceWith }, {});
|
|
97
116
|
|
|
98
117
|
const transformedCode = await fs.readFile(tempFile, "utf-8");
|
|
99
118
|
expect(transformedCode).toContain("<div>Hello, world!</div>");
|
package/lib/replace.ts
CHANGED
|
@@ -6,7 +6,10 @@ import { transformFromAst } from "@babel/core";
|
|
|
6
6
|
|
|
7
7
|
async function replaceJSXTextInFile(
|
|
8
8
|
filePath: string,
|
|
9
|
-
replacement: { searchString: string; replaceWith: string }
|
|
9
|
+
replacement: { searchString: string; replaceWith: string },
|
|
10
|
+
flags: {
|
|
11
|
+
lineNumbers?: number[];
|
|
12
|
+
}
|
|
10
13
|
) {
|
|
11
14
|
const code = await fs.readFile(filePath, "utf-8");
|
|
12
15
|
const ast = parse(code, {
|
|
@@ -20,6 +23,15 @@ async function replaceJSXTextInFile(
|
|
|
20
23
|
|
|
21
24
|
const regex = new RegExp(searchString, "gi");
|
|
22
25
|
if (regex.test(path.node.value)) {
|
|
26
|
+
// Ignore if not on a line number that we want to replace.
|
|
27
|
+
if (
|
|
28
|
+
flags.lineNumbers &&
|
|
29
|
+
path.node.loc &&
|
|
30
|
+
!flags.lineNumbers.includes(path.node.loc.start.line)
|
|
31
|
+
) {
|
|
32
|
+
return;
|
|
33
|
+
}
|
|
34
|
+
|
|
23
35
|
const splitValues = splitByCaseInsensitive(
|
|
24
36
|
path.node.value,
|
|
25
37
|
searchString
|
|
@@ -59,7 +71,7 @@ function splitByCaseInsensitive(str: string, delimiter: string) {
|
|
|
59
71
|
return str.split(new RegExp(`(${delimiter})`, "gi")).filter((s) => s !== "");
|
|
60
72
|
}
|
|
61
73
|
|
|
62
|
-
function replace(options: string[]) {
|
|
74
|
+
function replace(options: string[], flags: { lineNumbers?: number[] }) {
|
|
63
75
|
let filePath: string;
|
|
64
76
|
let searchString: string;
|
|
65
77
|
let replaceWith: string;
|
|
@@ -77,7 +89,7 @@ function replace(options: string[]) {
|
|
|
77
89
|
return;
|
|
78
90
|
}
|
|
79
91
|
|
|
80
|
-
replaceJSXTextInFile(filePath, { searchString, replaceWith });
|
|
92
|
+
replaceJSXTextInFile(filePath, { searchString, replaceWith }, flags);
|
|
81
93
|
}
|
|
82
94
|
|
|
83
95
|
function parseOptions(options: string[]): {
|