@cocreate/cli 1.59.0 → 1.62.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.
@@ -1,147 +1,145 @@
1
+ const { GoogleGenAI, Type } = require("@google/genai");
2
+ const Config = require("@cocreate/config");
3
+
1
4
  /**
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.
5
+ * Default Gemini model identifier used for language translation tasks.
6
+ * @type {string}
14
7
  */
8
+ const DEFAULT_MODEL = "gemini-2.5-flash-lite";
15
9
 
16
10
  /**
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
- * }
11
+ * Translation mapping for a single element's attributes and inner content.
12
+ * @typedef {Object} ElementTranslations
13
+ * @property {string|null} [text] - Inner text content or script payload.
14
+ * @property {string|null} [placeholder] - Input placeholder text.
15
+ * @property {string|null} [title] - Element title attribute.
16
+ * @property {string|null} [alt] - Image alternate text.
17
+ * @property {string|null} ["aria-label"] - ARIA accessibility label.
18
+ * @property {Record<string, string>} [additionalProperties] - Dynamic attributes (e.g., `aria-description`).
42
19
  */
43
20
 
44
- const { GoogleGenerativeAI } = require("@google/generative-ai");
45
- const Config = require("@cocreate/config");
46
- const MODEL_NAME = "gemini-2.5-flash-lite";
21
+ /**
22
+ * Key-value mapping of `i18n` keys to element translations for a specific language.
23
+ * @typedef {Record<string, ElementTranslations>} LanguageTranslations
24
+ */
47
25
 
48
- // Send HTML to Gemini AI and get translation JSON
49
- // Exported function to generate translation object for HTML source and languages
26
+ /**
27
+ * Language-First dictionary structure mapping language codes (e.g., "en", "es") to their translations.
28
+ * @typedef {Record<string, LanguageTranslations>} LanguageFirstTranslationMap
29
+ */
30
+
31
+ /**
32
+ * Configuration options for the HTML translation process.
33
+ * @typedef {Object} TranslateOptions
34
+ * @property {string} [apiKey] - Google GenAI API key. If omitted, attempts lookup via configuration service.
35
+ * @property {string} [model] - Gemini model name override (defaults to "gemini-2.5-flash-lite").
36
+ * @property {number} [temperature] - Model sampling temperature (defaults to 0.2).
37
+ */
38
+
39
+ /**
40
+ * Resolves the Google GenAI API key from explicit options or global configuration.
41
+ *
42
+ * @async
43
+ * @param {TranslateOptions} options - Configuration options passed to the translator.
44
+ * @returns {Promise<string|undefined>} Resolved API key string or undefined if not found.
45
+ */
50
46
  async function getApiKey(options) {
51
- if (options.apiKey) return options.apiKey;
52
- const config = await Config.prompt({
53
- GoogleGenerativeAIApiKey: {
54
- prompt: "Enter your Google Generative AI API key: "
55
- }
56
- });
57
- return config.GoogleGenerativeAIApiKey;
47
+ if (options?.apiKey) return options.apiKey;
48
+ if (typeof Config?.get === "function") {
49
+ return await Config.get("GEMINI_API_KEY") || process.env.GEMINI_API_KEY;
50
+ }
51
+ return process.env.GEMINI_API_KEY;
58
52
  }
59
53
 
54
+ /**
55
+ * Analyzes HTML source code, extracts `i18n` elements and `<script type="application/ld+json">` data,
56
+ * and uses Google GenAI to synthesize a Language-First JSON translation dictionary.
57
+ *
58
+ * @async
59
+ * @param {string} html - Raw HTML source code string containing elements with `i18n` attributes.
60
+ * @param {string[]} languages - Array of target language codes (e.g., `["en", "es", "fr"]`).
61
+ * @param {TranslateOptions} [options={}] - Optional configuration parameters for model and authentication.
62
+ * @returns {Promise<LanguageFirstTranslationMap|null>} Language-First translation map, or `null` if generation fails.
63
+ * @throws {Error} Throws an error if no API key is provided or resolved.
64
+ *
65
+ * @example
66
+ * const translations = await translateHtml(
67
+ * '<h1 i18n="heading">Hello</h1><input i18n="search" placeholder="Search...">',
68
+ * ["es", "fr"]
69
+ * );
70
+ */
60
71
  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:
72
+ const apiKey = await getApiKey(options);
73
+ if (!apiKey) {
74
+ throw new Error("Google GenAI API key is required for translateHtml.");
75
+ }
82
76
 
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
- }
77
+ const ai = new GoogleGenAI({ apiKey });
78
+ const modelName = options.model || DEFAULT_MODEL;
79
+ const langList = Array.isArray(languages) ? languages.join(", ") : String(languages);
120
80
 
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
- )}).
81
+ const prompt = `
82
+ You are an expert web localization AI.
83
+ Analyze the provided HTML and find all elements containing an "i18n" attribute, as well as any <script type="application/ld+json"> tags.
124
84
 
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.
85
+ Target Languages: ${langList}
128
86
 
129
- Only output the JSON object, do not include any explanation or extra text.
87
+ Instructions:
88
+ 1. Extract translatable content for each "i18n" key (inner text, alt, title, placeholder, label, aria-label, and aria-* attributes).
89
+ 2. For script[type='application/ld+json'], use the key "ld+json" or the element's "i18n" attribute, and translate string fields (like name, description) while keeping schema keywords (@context, @type, url) intact.
90
+ 3. Organize the translations into a LANGUAGE-FIRST structure where top-level keys are the target language codes (${langList}).
91
+ 4. Inside each language code object, map each "i18n" key to its translated properties (e.g., "text", "placeholder", "alt", "title", "aria-label").
92
+ 5. Provide a full translation for EVERY target language requested. Never leave a requested language empty.
130
93
 
131
- HTML:
94
+ HTML Source:
132
95
  ${html}
133
96
  `;
134
97
 
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
- }
98
+ /**
99
+ * JSON Schema enforcing structured Language-First output from Gemini.
100
+ * @type {import("@google/genai").Schema}
101
+ */
102
+ const responseSchema = {
103
+ type: Type.OBJECT,
104
+ properties: {
105
+ translations: {
106
+ type: Type.OBJECT,
107
+ description: "Map of language codes (e.g., 'en', 'es') to key-value translation objects",
108
+ additionalProperties: {
109
+ type: Type.OBJECT,
110
+ description: "Map of i18n keys to element translation properties",
111
+ additionalProperties: {
112
+ type: Type.OBJECT,
113
+ properties: {
114
+ text: { type: Type.STRING, nullable: true },
115
+ placeholder: { type: Type.STRING, nullable: true },
116
+ title: { type: Type.STRING, nullable: true },
117
+ alt: { type: Type.STRING, nullable: true },
118
+ "aria-label": { type: Type.STRING, nullable: true }
119
+ },
120
+ additionalProperties: true
121
+ }
122
+ }
123
+ }
124
+ },
125
+ required: ["translations"]
126
+ };
127
+
128
+ try {
129
+ const response = await ai.models.generateContent({
130
+ model: modelName,
131
+ contents: prompt,
132
+ config: {
133
+ responseMimeType: "application/json",
134
+ responseSchema: responseSchema,
135
+ temperature: options.temperature ?? 0.2
136
+ }
137
+ });
138
+
139
+ const parsed = JSON.parse(response.text);
140
+ return parsed.translations;
141
+ } catch (err) {
142
+ console.error("Gemini Translation Error:", err);
143
+ return null;
144
+ }
145
+ };
@@ -1,159 +0,0 @@
1
- const fs = require("fs");
2
- const path = require("path");
3
-
4
- function findDirectories(startPath, callback, fileName) {
5
- // Resolve relative paths to absolute paths if needed
6
- const resolvedPath =
7
- startPath.startsWith("./") || startPath.startsWith("../")
8
- ? path.resolve(startPath)
9
- : startPath;
10
-
11
- const segments = resolvedPath.split("/"); // Split path by '/'
12
- let currentPath = "/"; // Start from root
13
-
14
- for (let i = 0; i < segments.length; i++) {
15
- const segment = segments[i];
16
- const isWildcard = segment === "*";
17
-
18
- if (isWildcard) {
19
- // Get all directories at this level
20
- const directories = fs
21
- .readdirSync(currentPath)
22
- .filter((file) =>
23
- fs.statSync(path.join(currentPath, file)).isDirectory()
24
- );
25
-
26
- // Process each directory and continue along the path
27
- directories.forEach((dir) => {
28
- findDirectories(
29
- path.join(currentPath, dir, ...segments.slice(i + 1)),
30
- callback,
31
- fileName
32
- );
33
- });
34
- return; // Stop further processing in the loop for wildcard case
35
- } else {
36
- // Continue to the next part of the path
37
- currentPath = path.join(currentPath, segment);
38
-
39
- // If a segment doesn’t exist or isn’t a directory, log an error and stop
40
- if (
41
- !fs.existsSync(currentPath) ||
42
- !fs.statSync(currentPath).isDirectory()
43
- ) {
44
- console.log(`Directory not found: ${currentPath}`);
45
- return;
46
- }
47
- }
48
- }
49
-
50
- // If we reach the end of the path without wildcards, we have a valid directory
51
- callback(currentPath, fileName);
52
- }
53
-
54
- function createOrUpdateFile(directoryPath, fileName) {
55
- let buildStep = `- name: Build\n run: yarn build`;
56
-
57
- // Check if webpack config exists to include build step
58
- const webpackPath = filePath.replace(fileName, "webpack.config.js");
59
- if (!fs.existsSync(webpackPath)) buildStep = "";
60
-
61
- // Define file content (e.g., for YAML or other configuration)
62
- const fileContent = `name: Automated Workflow
63
- on:
64
- push:
65
- branches:
66
- - main
67
- jobs:
68
- about:
69
- runs-on: ubuntu-latest
70
- steps:
71
- - name: Checkout
72
- uses: actions/checkout@v3
73
- - name: Setup Node.js
74
- uses: actions/setup-node@v3
75
- with:
76
- node-version: 16
77
- - name: Jaid/action-sync-node-meta
78
- uses: jaid/action-sync-node-meta@v1.4.0
79
- with:
80
- direction: overwrite-github
81
- githubToken: "\${{ secrets.GITHUB }}"
82
- release:
83
- runs-on: ubuntu-latest
84
- steps:
85
- - name: Checkout
86
- uses: actions/checkout@v3
87
- - name: Setup Node.js
88
- uses: actions/setup-node@v3
89
- with:
90
- node-version: 14
91
- - name: Semantic Release
92
- uses: cycjimmy/semantic-release-action@v3
93
- id: semantic
94
- with:
95
- extra_plugins: |
96
- @semantic-release/changelog
97
- @semantic-release/git
98
- @semantic-release/github
99
- env:
100
- GITHUB_TOKEN: "\${{ secrets.GITHUB }}"
101
- NPM_TOKEN: "\${{ secrets.NPM_TOKEN }}"
102
- outputs:
103
- new_release_published: "\${{ steps.semantic.outputs.new_release_published }}"
104
- new_release_version: "\${{ steps.semantic.outputs.new_release_version }}"
105
- upload:
106
- runs-on: ubuntu-latest
107
- needs: release
108
- if: needs.release.outputs.new_release_published == 'true'
109
- env:
110
- VERSION: "\${{ needs.release.outputs.new_release_version }}"
111
- steps:
112
- - name: Checkout
113
- uses: actions/checkout@v3
114
- - name: Setup Node.js
115
- uses: actions/setup-node@v3
116
- with:
117
- node-version: 16
118
- - name: Set npm registry auth
119
- run: echo "//registry.npmjs.org/:_authToken=\${{ secrets.NPM_TOKEN }}" > ~/.npmrc
120
- - name: Install dependencies
121
- run: yarn install
122
- ${buildStep}
123
- - name: Set Environment Variables
124
- run: |
125
- echo "organization_id=\${{ secrets.COCREATE_ORGANIZATION_ID }}" >> $GITHUB_ENV
126
- echo "key=\${{ secrets.COCREATE_KEY }}" >> $GITHUB_ENV
127
- echo "host=\${{ secrets.COCREATE_HOST }}" >> $GITHUB_ENV
128
- - name: CoCreate Upload
129
- run: coc upload
130
- `;
131
-
132
- const filePath = path.join(directoryPath, fileName);
133
- // Create or update the file
134
- if (fs.existsSync(filePath)) fs.unlinkSync(filePath);
135
- fs.writeFileSync(filePath, fileContent);
136
- }
137
-
138
- // Define the directories with wildcards
139
- const directories = [
140
- "../../../../../CoCreate-modules/*/",
141
- "../../../../../CoCreate-apps/*/",
142
- "../../../../../CoCreate-plugins/*/",
143
- "../../../../../CoCreateCSS/",
144
- "../../../../../CoCreateJS/",
145
- "../../../../../CoCreateWS/",
146
- "../../../../../YellowOracle/",
147
- "../../../../../CoCreate-website/",
148
- "../../../../../CoCreate-admin/",
149
- "../../../../../CoCreate-website-old/",
150
- "../../../../../CoCreate-superadmin/",
151
- ];
152
- const fileName = "automated.yml";
153
-
154
- // Execute directory search and create/update file if the directory exists
155
- directories.forEach((directory) => {
156
- findDirectories(directory, createOrUpdateFile, fileName);
157
- });
158
-
159
- console.log("Finished");
@@ -1,133 +0,0 @@
1
- const fs = require("fs");
2
- const path = require("path");
3
-
4
- function findDirectories(startPath, callback, fileName) {
5
- // Resolve relative paths to absolute paths if needed
6
- const resolvedPath =
7
- startPath.startsWith("./") || startPath.startsWith("../")
8
- ? path.resolve(startPath)
9
- : startPath;
10
-
11
- const segments = resolvedPath.split("/"); // Split path by '/'
12
- let currentPath = "/"; // Start from root
13
-
14
- for (let i = 0; i < segments.length; i++) {
15
- const segment = segments[i];
16
- const isWildcard = segment === "*";
17
-
18
- if (isWildcard) {
19
- // Get all directories at this level
20
- const directories = fs
21
- .readdirSync(currentPath)
22
- .filter((file) =>
23
- fs.statSync(path.join(currentPath, file)).isDirectory()
24
- );
25
-
26
- // Process each directory and continue along the path
27
- directories.forEach((dir) => {
28
- findDirectories(
29
- path.join(currentPath, dir, ...segments.slice(i + 1)),
30
- callback,
31
- fileName
32
- );
33
- });
34
- return; // Stop further processing in the loop for wildcard case
35
- } else {
36
- // Continue to the next part of the path
37
- currentPath = path.join(currentPath, segment);
38
-
39
- // If a segment doesn’t exist or isn’t a directory, log an error and stop
40
- if (
41
- !fs.existsSync(currentPath) ||
42
- !fs.statSync(currentPath).isDirectory()
43
- ) {
44
- console.log(`Directory not found: ${currentPath}`);
45
- return;
46
- }
47
- }
48
- }
49
-
50
- // If we reach the end of the path without wildcards, we have a valid directory
51
- callback(currentPath, fileName);
52
- }
53
-
54
- function createOrUpdateFile(directoryPath, fileName) {
55
- let name = path
56
- .basename(path.resolve(path.dirname(directoryPath), "./"))
57
- .substring(9);
58
- let object = "";
59
- let replaceContent = fs.readFileSync(directoryPath).toString();
60
-
61
- // Parse content to extract `object`
62
- let content_source = replaceContent.substring(
63
- replaceContent.indexOf("sources")
64
- );
65
- let content1 = content_source.substring(content_source.indexOf("object"));
66
- let content2 = content1.substring(content1.indexOf(":"));
67
- object = content2.substring(3, content2.indexOf(",") - 4);
68
-
69
- let fileContent = `module.exports = {
70
- "config": {
71
- "organization_id": "5ff747727005da1c272740ab",
72
- "key": "2061acef-0451-4545-f754-60cf8160",
73
- "host": "general.cocreate.app"
74
- },
75
-
76
- "sources": [
77
- {
78
- "array": "files",
79
- "object": {
80
- "_id": "${object}",
81
- "name": "index.html",
82
- "path": "/docs/${name}",
83
- "pathname": "/docs/${name}/index.html",
84
- "src": "{{./docs/index.html}}",
85
- "host": [
86
- "general.cocreate.app"
87
- ],
88
- "directory": "${name}",
89
- "content-type": "{{content-type}}",
90
- "public": "true"
91
- }
92
- }
93
- ]
94
- }
95
- `;
96
-
97
- if (!object.length) {
98
- console.log("object Undefined: ", directoryPath);
99
- } else if (object.length !== 24) {
100
- console.log("object not valid! Please check your config: ", directoryPath);
101
- } else {
102
- const filePath = path.join(directoryPath, fileName);
103
- if (fs.existsSync(filePath)) fs.unlinkSync(filePath);
104
- fs.writeFileSync(filePath, fileContent);
105
- }
106
- const filePath = path.join(directoryPath, fileName);
107
- // Create or update the file
108
- if (fs.existsSync(filePath)) fs.unlinkSync(filePath);
109
- fs.writeFileSync(filePath, fileContent);
110
- }
111
-
112
- // Define the directories with wildcards
113
- const directories = [
114
- "../../../../../CoCreate-modules/*/",
115
- "../../../../../CoCreate-apps/*/",
116
- "../../../../../CoCreate-plugins/*/",
117
- "../../../../../CoCreateCSS/",
118
- "../../../../../CoCreateJS/",
119
- "../../../../../CoCreateWS/",
120
- "../../../../../YellowOracle/",
121
- "../../../../../CoCreate-website/",
122
- "../../../../../CoCreate-admin/",
123
- "../../../../../CoCreate-website-old/",
124
- "../../../../../CoCreate-superadmin/",
125
- ];
126
- const fileName = "CoCreate.config.js";
127
-
128
- // Execute directory search and create/update file if the directory exists
129
- directories.forEach((directory) => {
130
- findDirectories(directory, createOrUpdateFile, fileName);
131
- });
132
-
133
- console.log("Finished");
@@ -1,81 +0,0 @@
1
- let glob = require("glob");
2
- let fs = require("fs");
3
- const path = require("path");
4
-
5
- function globUpdater(er, files) {
6
- if (er) console.log(files, "glob resolving issue");
7
- else
8
- files.forEach((filename) => {
9
- console.log(filename + "/manual.yml", "glob resolving issue");
10
- update(filename + "/manual.yml");
11
- });
12
- }
13
-
14
- function update(Path) {
15
- // component name
16
- let name = path
17
- .basename(path.resolve(path.dirname(Path), "../.."))
18
- .substring(9);
19
- let fileContent = `name: Manual Workflow
20
- on:
21
- workflow_dispatch:
22
- inputs:
23
- invalidations:
24
- description: |
25
- If set to 'true', invalidates previous upload.
26
- default: 'true'
27
- required: true
28
-
29
- jobs:
30
- cdn:
31
- runs-on: ubuntu-latest
32
- env:
33
- DRY_RUN: \${{ github.event.inputs.dry_run }}
34
- GITHUB_TOKEN: '\${{ secrets.GITHUB_TOKEN }}'
35
- NPM_TOKEN: '\${{ secrets.NPM_TOKEN }}'
36
-
37
- steps:
38
- - name: Checkout
39
- uses: actions/checkout@v3
40
- - name: setup nodejs
41
- uses: actions/setup-node@v3
42
- with:
43
- node-version: 16
44
- - name: yarn install
45
- run: >
46
- echo "//registry.npmjs.org/:_authToken=\${{ secrets.NPM_TOKEN }}" >
47
- .npmrc
48
-
49
- yarn install
50
- - name: yarn build
51
- run: yarn build
52
- - name: upload latest bundle
53
- uses: CoCreate-app/CoCreate-s3@master
54
- with:
55
- aws-key-id: '\${{ secrets.AWSACCESSKEYID }}'
56
- aws-access-key: '\${{ secrets.AWSSECERTACCESSKEY }}'
57
- distributionId: '\${{ secrets.DISTRIBUTION_ID }}'
58
- bucket: testcrudbucket
59
- source: ./dist
60
- destination: /${name}/latest
61
- acl: public-read
62
- invalidations: \${{ github.event.inputs.invalidations }}
63
-
64
- `;
65
-
66
- if (fs.existsSync(Path)) fs.unlinkSync(Path);
67
- fs.writeFileSync(Path, fileContent);
68
- }
69
-
70
- // glob("../CoCreate-modules/CoCreate-action/.github/workflows", globUpdater)
71
- glob("../CoCreate-modules/*/.github/workflows/", globUpdater);
72
- glob("../CoCreate-apps/*/.github/workflows/", globUpdater);
73
- glob("../CoCreate-plugins/*/.github/workflows/", globUpdater);
74
-
75
- // substrin (9) removes CoCreateC leving namme as SS
76
- // glob("../CoCreateCSS/.github/workflows/", globUpdater)
77
-
78
- // does not need to add name... will require for name to be removed from destination
79
- // glob("../CoCreateJS/.github/workflows/", globUpdater)
80
-
81
- console.log("finished");