@cocreate/cli 1.51.2 → 1.53.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/CHANGELOG.md +22 -0
- package/CoCreate.config.js +562 -500
- package/package.json +1 -9
- package/src/coc.js +80 -92
- package/src/commands/other/translate.js +147 -0
- package/src/commands/upload.js +93 -100
- package/src/execute.js +5 -3
- package/src/getConfig.js +32 -0
package/package.json
CHANGED
|
@@ -1,18 +1,10 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@cocreate/cli",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.53.0",
|
|
4
4
|
"description": "Polyrepo management bash CLI tool. Run all git commands and yarn commands on multiple repositories. Also includes a few custom macros for cloning, installing, etc.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"cli",
|
|
7
|
-
"cocreate",
|
|
8
|
-
"low-code-framework",
|
|
9
|
-
"no-code-framework",
|
|
10
|
-
"cocreatejs",
|
|
11
|
-
"cocreatejs-component",
|
|
12
|
-
"cocreate-framework",
|
|
13
|
-
"no-code",
|
|
14
7
|
"low-code",
|
|
15
|
-
"collaborative-framework",
|
|
16
8
|
"realtime",
|
|
17
9
|
"realtime-framework",
|
|
18
10
|
"collaboration",
|
package/src/coc.js
CHANGED
|
@@ -2,11 +2,11 @@
|
|
|
2
2
|
|
|
3
3
|
// Import necessary modules for path operations, file system operations, and more
|
|
4
4
|
const path = require("path");
|
|
5
|
-
const fs = require("fs");
|
|
6
5
|
const readline = require("readline");
|
|
7
6
|
const execute = require("./execute");
|
|
8
7
|
const addMeta = require("./addMeta");
|
|
9
8
|
const { color } = require("./fonts");
|
|
9
|
+
const { getConfig } = require("./getConfig");
|
|
10
10
|
|
|
11
11
|
// Configuration object for storing options
|
|
12
12
|
let config = {};
|
|
@@ -15,41 +15,36 @@ let config = {};
|
|
|
15
15
|
const argv = process.argv.slice(2);
|
|
16
16
|
|
|
17
17
|
// Define available command-line options
|
|
18
|
-
const
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
18
|
+
const availableOptions = {
|
|
19
|
+
"--self": { key: "self", type: "boolean" },
|
|
20
|
+
"-s": { key: "self", type: "boolean" },
|
|
21
|
+
"--directory": { key: "directory", type: "string" },
|
|
22
|
+
"-d": { key: "directory", type: "string" },
|
|
23
|
+
"--config": { key: "config", type: "string" },
|
|
24
|
+
"-c": { key: "config", type: "string" }
|
|
25
|
+
};
|
|
26
|
+
|
|
27
|
+
const options = {};
|
|
28
|
+
const commandParts = [];
|
|
29
|
+
for (let i = 0; i < argv.length; i++) {
|
|
30
|
+
let option = availableOptions[argv[i]];
|
|
31
|
+
if (option) {
|
|
32
|
+
if (option.type === "boolean") {
|
|
33
|
+
options[option.key] = true;
|
|
34
|
+
} else if (option.type === "string") {
|
|
35
|
+
options[option.key] = argv[i + 1];
|
|
36
|
+
argv.splice(i + 1, 1);
|
|
37
|
+
}
|
|
38
|
+
} else {
|
|
39
|
+
if (argv[i].match(/[\s'"]/)) {
|
|
40
|
+
commandParts.push(`'${argv[i].replace(/'/g, "\\'")}'`);
|
|
41
|
+
} else {
|
|
42
|
+
commandParts.push(argv[i]);
|
|
43
|
+
}
|
|
26
44
|
}
|
|
27
45
|
}
|
|
28
46
|
|
|
29
|
-
|
|
30
|
-
command = argv
|
|
31
|
-
.map((part) => (part.match(/ |'|"/) ? `'${part.replace(/'/, "'")}'` : part))
|
|
32
|
-
.join(" ");
|
|
33
|
-
|
|
34
|
-
/**
|
|
35
|
-
* Load repository configuration from the given path.
|
|
36
|
-
* @param {string} path - The file path to load repository config from.
|
|
37
|
-
* @returns {Array} - List of repositories.
|
|
38
|
-
*/
|
|
39
|
-
function getRepositories(path) {
|
|
40
|
-
try {
|
|
41
|
-
const config = require(path);
|
|
42
|
-
return config.repositories;
|
|
43
|
-
} catch (err) {
|
|
44
|
-
console.error(
|
|
45
|
-
color.red + "cannot read repository file in" + color.reset,
|
|
46
|
-
path,
|
|
47
|
-
color.red + "error:" + color.reset,
|
|
48
|
-
err.message
|
|
49
|
-
);
|
|
50
|
-
process.exit(1);
|
|
51
|
-
}
|
|
52
|
-
}
|
|
47
|
+
command = commandParts.join(" ");
|
|
53
48
|
|
|
54
49
|
/**
|
|
55
50
|
* Main function to execute commands across repositories.
|
|
@@ -57,68 +52,60 @@ function getRepositories(path) {
|
|
|
57
52
|
* @param {Array} [repos=null] - List of repositories to process.
|
|
58
53
|
* @param {string} [directory=null] - The directory path of the configuration.
|
|
59
54
|
*/
|
|
60
|
-
async function main(config = {},
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
);
|
|
76
|
-
}
|
|
77
|
-
// Load repositories from default CoCreate.config.js if exists
|
|
78
|
-
else if (!config["self"] && fs.existsSync(currentRepoPath)) {
|
|
79
|
-
repos = getRepositories(currentRepoPath);
|
|
80
|
-
directory = path.dirname(currentRepoPath);
|
|
81
|
-
console.warn(
|
|
82
|
-
`${color.yellow}using ${currentRepoPath} configuration${color.reset}`
|
|
83
|
-
);
|
|
84
|
-
}
|
|
85
|
-
// If package.json exists, load repository details from it
|
|
86
|
-
else if (fs.existsSync(packageJsonPath)) {
|
|
87
|
-
const repoPath = path.resolve(process.cwd());
|
|
88
|
-
const packageObj = require(packageJsonPath);
|
|
89
|
-
const repoUrl =
|
|
90
|
-
packageObj.repository &&
|
|
91
|
-
packageObj.repository.url.substring(12);
|
|
92
|
-
const repoEntry = packageObj.main;
|
|
93
|
-
repos = [
|
|
94
|
-
{
|
|
95
|
-
path: repoPath,
|
|
96
|
-
repo: repoUrl,
|
|
97
|
-
entry: repoEntry
|
|
98
|
-
}
|
|
99
|
-
];
|
|
100
|
-
directory = path.dirname(packageJsonPath);
|
|
101
|
-
console.warn(
|
|
102
|
-
`${color.yellow}using ${packageJsonPath} configuration${color.reset}`
|
|
103
|
-
);
|
|
55
|
+
async function main(config = {}, options) {
|
|
56
|
+
let directory = options["directory"] || process.cwd();
|
|
57
|
+
if (!config.repositories) {
|
|
58
|
+
let configString = options["config"];
|
|
59
|
+
if (configString) {
|
|
60
|
+
try {
|
|
61
|
+
config = JSON.parse(configString);
|
|
62
|
+
console.warn(
|
|
63
|
+
`${color.yellow}using supplied JSON configuration${color.reset}`
|
|
64
|
+
);
|
|
65
|
+
} catch (error) {
|
|
66
|
+
directory = configString;
|
|
67
|
+
config = await getConfig(directory);
|
|
68
|
+
}
|
|
69
|
+
} else {
|
|
70
|
+
config = await getConfig(directory);
|
|
104
71
|
}
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
72
|
+
|
|
73
|
+
if (!config.configPath) {
|
|
74
|
+
const package = await getConfig(directory, "package.json");
|
|
75
|
+
if (package.configPath) {
|
|
76
|
+
config.configPath = package.configPath;
|
|
77
|
+
const repoUrl =
|
|
78
|
+
package.repository && package.repository.url.substring(12);
|
|
79
|
+
config.repositories = [
|
|
80
|
+
{
|
|
81
|
+
path: package.configPath,
|
|
82
|
+
repo: repoUrl,
|
|
83
|
+
entry: package.main
|
|
84
|
+
}
|
|
85
|
+
];
|
|
86
|
+
} else {
|
|
87
|
+
console.error(
|
|
88
|
+
`${color.red}config file cannot be found${color.reset}`
|
|
89
|
+
);
|
|
90
|
+
process.exit(1);
|
|
91
|
+
}
|
|
111
92
|
}
|
|
93
|
+
|
|
94
|
+
directory = path.dirname(config.configPath);
|
|
95
|
+
console.warn(
|
|
96
|
+
`${color.yellow}using config ${config.configPath} ${color.reset}`
|
|
97
|
+
);
|
|
112
98
|
}
|
|
113
99
|
|
|
114
|
-
|
|
115
|
-
config = { hideMessage: false, ...config };
|
|
100
|
+
config.hideMessage = false;
|
|
116
101
|
|
|
117
|
-
// Add metadata to
|
|
118
|
-
if (
|
|
102
|
+
// Add metadata to repositories if any are present
|
|
103
|
+
if (config.repositories && config.repositories.length) {
|
|
104
|
+
config.repositories = await addMeta(config.repositories, [], directory);
|
|
105
|
+
}
|
|
119
106
|
|
|
120
107
|
// Execute the command across repositories
|
|
121
|
-
const failed = await execute(command,
|
|
108
|
+
const failed = await execute(command, config);
|
|
122
109
|
|
|
123
110
|
// Handle any failed command executions
|
|
124
111
|
if (failed && failed.length > 0) {
|
|
@@ -134,7 +121,7 @@ async function main(config = {}, repos = null, directory = null) {
|
|
|
134
121
|
}
|
|
135
122
|
|
|
136
123
|
// Prompt user to retry failed commands
|
|
137
|
-
await promptRetry(failed, config,
|
|
124
|
+
await promptRetry(failed, config, options);
|
|
138
125
|
}
|
|
139
126
|
}
|
|
140
127
|
|
|
@@ -144,7 +131,7 @@ async function main(config = {}, repos = null, directory = null) {
|
|
|
144
131
|
* @param {Object} config - Configuration object.
|
|
145
132
|
* @param {string} directory - Path of the configuration directory.
|
|
146
133
|
*/
|
|
147
|
-
async function promptRetry(failed, config,
|
|
134
|
+
async function promptRetry(failed, config, options) {
|
|
148
135
|
const rl = readline.createInterface({
|
|
149
136
|
input: process.stdin,
|
|
150
137
|
output: process.stdout
|
|
@@ -155,7 +142,8 @@ async function promptRetry(failed, config, directory) {
|
|
|
155
142
|
async (answer) => {
|
|
156
143
|
rl.close();
|
|
157
144
|
if (answer.toLowerCase() === "yes") {
|
|
158
|
-
|
|
145
|
+
config.repositories = failed;
|
|
146
|
+
await main(config, options);
|
|
159
147
|
} else {
|
|
160
148
|
process.exit(0);
|
|
161
149
|
}
|
|
@@ -164,4 +152,4 @@ async function promptRetry(failed, config, directory) {
|
|
|
164
152
|
}
|
|
165
153
|
|
|
166
154
|
// Call the main function with initial configuration
|
|
167
|
-
main(config);
|
|
155
|
+
main(config, options);
|
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview
|
|
3
|
+
* This script is designed to generate SEO-friendly content for a given HTML source.
|
|
4
|
+
* It uses the Gemini API to translate and generate content based on the provided HTML and languages.
|
|
5
|
+
*
|
|
6
|
+
* Prerequisites:
|
|
7
|
+
* - Node.js installed on your system.
|
|
8
|
+
* - The Google Generative AI library installed:
|
|
9
|
+
* `npm install @google/generative-ai`
|
|
10
|
+
* - A valid Gemini API key.
|
|
11
|
+
*
|
|
12
|
+
* Usage:
|
|
13
|
+
* Import and call the `translateHtml` function with the HTML source, languages array, and options.
|
|
14
|
+
*/
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* Example for structured data translation:
|
|
18
|
+
*
|
|
19
|
+
* {
|
|
20
|
+
* "selector": "script[type='application/ld+json']",
|
|
21
|
+
* "innerHTML": {
|
|
22
|
+
* "en": {
|
|
23
|
+
* "@context": "http://schema.org",
|
|
24
|
+
* "@type": "WebPage",
|
|
25
|
+
* "name": "Basketball Betting Sportsbook | NBA, EuroLeague, NCAA & Global Leagues",
|
|
26
|
+
* "description": "Unlock premier basketball betting at Amapola Sportsbook. Get competitive odds for NBA, EuroLeague, NCAA, and global basketball. Enjoy live betting, swift payouts, and insightful picks for an unmatched wagering experience.",
|
|
27
|
+
* "url": "https://amapolacasino.com/sportsbook/basketball/",
|
|
28
|
+
* "image": "https://amapolacasino.com/assets/basketball-og.jpg",
|
|
29
|
+
* "author": {
|
|
30
|
+
* "@type": "Organization",
|
|
31
|
+
* "name": "AmapolaCasino"
|
|
32
|
+
* }
|
|
33
|
+
* },
|
|
34
|
+
* "es": { ... },
|
|
35
|
+
* "fr": { ... },
|
|
36
|
+
* "pt": { ... },
|
|
37
|
+
* "ht": { ... },
|
|
38
|
+
* "nl": { ... },
|
|
39
|
+
* "gn": { ... }
|
|
40
|
+
* }
|
|
41
|
+
* }
|
|
42
|
+
*/
|
|
43
|
+
|
|
44
|
+
const { GoogleGenerativeAI } = require("@google/generative-ai");
|
|
45
|
+
const Config = require("@cocreate/config");
|
|
46
|
+
const MODEL_NAME = "gemini-2.5-flash-lite";
|
|
47
|
+
|
|
48
|
+
// Send HTML to Gemini AI and get translation JSON
|
|
49
|
+
// Exported function to generate translation object for HTML source and languages
|
|
50
|
+
async function getApiKey(options) {
|
|
51
|
+
if (options.apiKey) return options.apiKey;
|
|
52
|
+
const config = await Config({
|
|
53
|
+
GoogleGenerativeAIApiKey: {
|
|
54
|
+
prompt: "Enter your Google Generative AI API key: "
|
|
55
|
+
}
|
|
56
|
+
});
|
|
57
|
+
return config.GoogleGenerativeAIApiKey;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
module.exports = async function translateHtml(html, languages, options = {}) {
|
|
61
|
+
const apiKey = await getApiKey(options);
|
|
62
|
+
if (!apiKey)
|
|
63
|
+
throw new Error(
|
|
64
|
+
"Google Generative AI API key is required in options.apiKey, process.env, or via prompt."
|
|
65
|
+
);
|
|
66
|
+
const genAI = new GoogleGenerativeAI(apiKey);
|
|
67
|
+
const model =
|
|
68
|
+
options.model || genAI.getGenerativeModel({ model: MODEL_NAME });
|
|
69
|
+
const translationObj = await generateTranslationObject(
|
|
70
|
+
html,
|
|
71
|
+
model,
|
|
72
|
+
languages
|
|
73
|
+
);
|
|
74
|
+
return translationObj;
|
|
75
|
+
};
|
|
76
|
+
|
|
77
|
+
// Update generateTranslationObject to accept only html, model, languages
|
|
78
|
+
async function generateTranslationObject(html, model, languages) {
|
|
79
|
+
const langList = languages.map((l) => `"${l}"`).join(", ");
|
|
80
|
+
const prompt = `
|
|
81
|
+
You are an expert web localization AI. Given the following HTML file, extract all translatable content (titles, meta tags, headers, buttons, video/image alt/title, labels, aria-label, all aria-* attributes, and placeholders) and generate a JSON object in the following format:
|
|
82
|
+
|
|
83
|
+
{
|
|
84
|
+
"translations": [
|
|
85
|
+
{
|
|
86
|
+
"selector": "<css selector>",
|
|
87
|
+
"innerHTML": {
|
|
88
|
+
${languages
|
|
89
|
+
.map((l) => `\"${l}\"`)
|
|
90
|
+
.join(
|
|
91
|
+
", \
|
|
92
|
+
"
|
|
93
|
+
)}
|
|
94
|
+
}
|
|
95
|
+
},
|
|
96
|
+
{
|
|
97
|
+
"selector": "<css selector>",
|
|
98
|
+
"attributes": {
|
|
99
|
+
"alt": { ${langList} },
|
|
100
|
+
"label": { ${langList} },
|
|
101
|
+
"aria-label": { ${langList} },
|
|
102
|
+
"aria-*": { ${langList} },
|
|
103
|
+
"title": { ${langList} },
|
|
104
|
+
"placeholder": { ${langList} }
|
|
105
|
+
}
|
|
106
|
+
},
|
|
107
|
+
// Example for structured data translation:
|
|
108
|
+
{
|
|
109
|
+
"selector": "script[type='application/ld+json']",
|
|
110
|
+
"innerHTML": {
|
|
111
|
+
"en": { "@context": "http://schema.org", "@type": "WebPage", "name": "English name", "description": "English description" },
|
|
112
|
+
"es": { "@context": "http://schema.org", "@type": "WebPage", "name": "Spanish name", "description": "Spanish description" },
|
|
113
|
+
"fr": { "@context": "http://schema.org", "@type": "WebPage", "name": "French name", "description": "French description" }
|
|
114
|
+
// ...other languages
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
// ...more selectors as needed
|
|
118
|
+
]
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
Do not add any extra keys or key names not shown in this structure. Only use the keys: name, directory, path, content-type, translations, selector, innerHTML, attributes, alt, label, aria-label, aria-*, title, placeholder, and the language codes (${languages.join(
|
|
122
|
+
", "
|
|
123
|
+
)}).
|
|
124
|
+
|
|
125
|
+
For every translatable item (innerHTML and attributes), provide a translation for each language: ${languages.join(
|
|
126
|
+
", "
|
|
127
|
+
)}. Do not leave any language blank. For Guarani (\"gn\"), always translate to Guarani and never leave it in English.
|
|
128
|
+
|
|
129
|
+
Only output the JSON object, do not include any explanation or extra text.
|
|
130
|
+
|
|
131
|
+
HTML:
|
|
132
|
+
${html}
|
|
133
|
+
`;
|
|
134
|
+
|
|
135
|
+
try {
|
|
136
|
+
const result = await model.generateContent(prompt);
|
|
137
|
+
let jsonText = result.response.candidates[0].content.parts[0].text;
|
|
138
|
+
// Extract the first JSON object from the response
|
|
139
|
+
const match = jsonText.match(/\{[\s\S]*\}/);
|
|
140
|
+
if (!match) throw new Error("No JSON object found in AI response");
|
|
141
|
+
jsonText = match[0];
|
|
142
|
+
return JSON.parse(jsonText).translations;
|
|
143
|
+
} catch (err) {
|
|
144
|
+
console.log(`AI error:`, err);
|
|
145
|
+
return null;
|
|
146
|
+
}
|
|
147
|
+
}
|
package/src/commands/upload.js
CHANGED
|
@@ -1,102 +1,95 @@
|
|
|
1
|
-
const file = require(
|
|
2
|
-
const path = require(
|
|
3
|
-
const fs = require(
|
|
1
|
+
const file = require("@cocreate/file");
|
|
2
|
+
const path = require("path");
|
|
3
|
+
const fs = require("fs");
|
|
4
|
+
const { getConfig } = require("../getConfig");
|
|
5
|
+
const translate = require("./other/translate");
|
|
4
6
|
|
|
5
7
|
module.exports = async function upload(directory, args) {
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
}
|
|
95
|
-
|
|
96
|
-
currentDir = path.dirname(currentDir);
|
|
97
|
-
}
|
|
98
|
-
|
|
99
|
-
return null;
|
|
100
|
-
}
|
|
101
|
-
|
|
102
|
-
}
|
|
8
|
+
if (args && !Array.isArray(args)) args = [args];
|
|
9
|
+
|
|
10
|
+
let isWatch = false;
|
|
11
|
+
let translateFn = null;
|
|
12
|
+
|
|
13
|
+
if (args && (args.includes("-t") || args.includes("--translate"))) {
|
|
14
|
+
translateFn = translate;
|
|
15
|
+
args = args.filter((arg) => arg !== "-t" && arg !== "--translate");
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
if (directory && typeof directory === "string") {
|
|
19
|
+
if (["-w", "--watch"].includes(directory)) {
|
|
20
|
+
isWatch = true;
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
directory = process.cwd();
|
|
25
|
+
|
|
26
|
+
if (
|
|
27
|
+
isWatch ||
|
|
28
|
+
(args && (args.includes("-w") || args.includes("--watch")))
|
|
29
|
+
) {
|
|
30
|
+
for (let i = 0; i < args.length; i++) {
|
|
31
|
+
if (args[i].startsWith("-")) continue;
|
|
32
|
+
else if (path.isAbsolute(args[i])) directory = args[i];
|
|
33
|
+
else directory = path.resolve(directory, args[i]);
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
console.log("Watching: ", directory);
|
|
37
|
+
fs.watch(
|
|
38
|
+
directory,
|
|
39
|
+
{ recursive: true },
|
|
40
|
+
async (eventType, filename) => {
|
|
41
|
+
if (!filename.includes("CoCreate.config.js")) {
|
|
42
|
+
const config = await getConfig(directory, filename);
|
|
43
|
+
if (config.configPath) {
|
|
44
|
+
await file(config, config.configPath, config.filePath, {
|
|
45
|
+
translate: translateFn
|
|
46
|
+
});
|
|
47
|
+
} else {
|
|
48
|
+
console.log(
|
|
49
|
+
"Failed to read or parse CoCreate.config.js."
|
|
50
|
+
);
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
);
|
|
55
|
+
} else {
|
|
56
|
+
if (!args || !args.length) {
|
|
57
|
+
const CoCreateConfig = await getConfig(directory);
|
|
58
|
+
if (CoCreateConfig.configPath) {
|
|
59
|
+
await file(
|
|
60
|
+
CoCreateConfig,
|
|
61
|
+
CoCreateConfig.configPath,
|
|
62
|
+
CoCreateConfig.filePath,
|
|
63
|
+
{ translate: translateFn }
|
|
64
|
+
);
|
|
65
|
+
} else {
|
|
66
|
+
console.log("Failed to read or parse CoCreate.config.js.");
|
|
67
|
+
}
|
|
68
|
+
} else {
|
|
69
|
+
for (let arg of args) {
|
|
70
|
+
arg = path.resolve(directory, arg);
|
|
71
|
+
let CoCreateConfig;
|
|
72
|
+
|
|
73
|
+
try {
|
|
74
|
+
CoCreateConfig = JSON.parse(arg);
|
|
75
|
+
} catch (error) {}
|
|
76
|
+
|
|
77
|
+
if (!CoCreateConfig) {
|
|
78
|
+
CoCreateConfig = await getConfig(arg);
|
|
79
|
+
if (CoCreateConfig.configPath) {
|
|
80
|
+
await file(
|
|
81
|
+
CoCreateConfig,
|
|
82
|
+
CoCreateConfig.configPath,
|
|
83
|
+
CoCreateConfig.filePath,
|
|
84
|
+
{ translate: translateFn }
|
|
85
|
+
);
|
|
86
|
+
} else {
|
|
87
|
+
console.log(
|
|
88
|
+
"Failed to read or parse CoCreate.config.js."
|
|
89
|
+
);
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
};
|
package/src/execute.js
CHANGED
|
@@ -3,9 +3,11 @@ const fs = require("fs");
|
|
|
3
3
|
const spawn = require("./spawn");
|
|
4
4
|
const util = require("node:util");
|
|
5
5
|
const exec = util.promisify(require("node:child_process").exec);
|
|
6
|
+
const { getConfig } = require("./getConfig");
|
|
7
|
+
|
|
6
8
|
const { color } = require("./fonts");
|
|
7
9
|
|
|
8
|
-
module.exports = async function execute(command,
|
|
10
|
+
module.exports = async function execute(command, config) {
|
|
9
11
|
let failed = [];
|
|
10
12
|
let [filename, ...args] = command.replaceAll("'", '"').trim().split(" ");
|
|
11
13
|
|
|
@@ -22,7 +24,7 @@ module.exports = async function execute(command, repos = [], config) {
|
|
|
22
24
|
let isPredefined = fs.existsSync(predefined);
|
|
23
25
|
let repositories = [];
|
|
24
26
|
|
|
25
|
-
for (let repo of
|
|
27
|
+
for (let repo of config.repositories || []) {
|
|
26
28
|
try {
|
|
27
29
|
if (
|
|
28
30
|
repo.exclude &&
|
|
@@ -71,7 +73,7 @@ module.exports = async function execute(command, repos = [], config) {
|
|
|
71
73
|
}
|
|
72
74
|
|
|
73
75
|
if (isPredefined) {
|
|
74
|
-
failed = require(predefined)(repositories, args);
|
|
76
|
+
failed = await require(predefined)(repositories, args);
|
|
75
77
|
}
|
|
76
78
|
|
|
77
79
|
return failed;
|
package/src/getConfig.js
ADDED
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
const fs = require("fs");
|
|
2
|
+
const path = require("path");
|
|
3
|
+
|
|
4
|
+
async function getConfig(directory, filename = "") {
|
|
5
|
+
let configPath = findClosestConfig(directory, "CoCreate.config.js");
|
|
6
|
+
if (configPath) {
|
|
7
|
+
let config = require(configPath);
|
|
8
|
+
config.configPath = configPath;
|
|
9
|
+
config.filePath = path.resolve(directory, filename);
|
|
10
|
+
return config;
|
|
11
|
+
} else {
|
|
12
|
+
console.log("No CoCreate.config file found in parent directories.");
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
function findClosestConfig(directory, filename) {
|
|
17
|
+
let currentDir = directory;
|
|
18
|
+
|
|
19
|
+
while (currentDir !== "/" && currentDir !== ".") {
|
|
20
|
+
let configFile = path.join(currentDir, filename);
|
|
21
|
+
|
|
22
|
+
if (fs.existsSync(configFile)) {
|
|
23
|
+
return configFile;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
currentDir = path.dirname(currentDir);
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
return null;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
module.exports = { getConfig, findClosestConfig };
|