@gxp-dev/tools 2.0.11 → 2.0.12

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/lib/cli.js CHANGED
@@ -22,6 +22,7 @@ const {
22
22
  extensionChromeCommand,
23
23
  extensionBuildCommand,
24
24
  extensionInstallCommand,
25
+ extractConfigCommand,
25
26
  } = require("./commands");
26
27
 
27
28
  // Load global configuration
@@ -39,6 +40,22 @@ yargs
39
40
  describe: "Project name (for new projects)",
40
41
  type: "string",
41
42
  },
43
+ description: {
44
+ describe: "Project description",
45
+ type: "string",
46
+ alias: "d",
47
+ },
48
+ build: {
49
+ describe: "AI build prompt - describe what to build for auto-scaffolding",
50
+ type: "string",
51
+ alias: "b",
52
+ },
53
+ provider: {
54
+ describe: "AI provider for scaffolding (claude, codex, gemini)",
55
+ type: "string",
56
+ alias: "p",
57
+ choices: ["claude", "codex", "gemini"],
58
+ },
42
59
  },
43
60
  initCommand
44
61
  )
@@ -245,6 +262,31 @@ yargs
245
262
  },
246
263
  assetsCommand
247
264
  )
265
+ .command(
266
+ "extract-config",
267
+ "Extract GxP configuration from source files to app-manifest.json",
268
+ {
269
+ "dry-run": {
270
+ describe: "Show what would be extracted without making changes",
271
+ type: "boolean",
272
+ default: false,
273
+ alias: "d",
274
+ },
275
+ overwrite: {
276
+ describe: "Overwrite existing values in manifest",
277
+ type: "boolean",
278
+ default: false,
279
+ alias: "o",
280
+ },
281
+ verbose: {
282
+ describe: "Show detailed output",
283
+ type: "boolean",
284
+ default: false,
285
+ alias: "v",
286
+ },
287
+ },
288
+ extractConfigCommand
289
+ )
248
290
  .demandCommand(1, "Please provide a valid command")
249
291
  .help("h")
250
292
  .alias("h", "help")
@@ -0,0 +1,186 @@
1
+ /**
2
+ * Extract Config Command
3
+ *
4
+ * Scans source files for GxP store usage and directives,
5
+ * then generates/updates app-manifest.json with extracted configuration.
6
+ */
7
+
8
+ const path = require("path");
9
+ const fs = require("fs");
10
+ const {
11
+ findProjectRoot,
12
+ extractConfigFromSource,
13
+ mergeConfig,
14
+ generateSummary,
15
+ } = require("../utils");
16
+
17
+ /**
18
+ * Main extract-config command handler
19
+ * @param {Object} argv - Yargs arguments
20
+ */
21
+ async function extractConfigCommand(argv) {
22
+ const projectPath = findProjectRoot();
23
+ const srcDir = path.join(projectPath, "src");
24
+ const manifestPath = path.join(projectPath, "app-manifest.json");
25
+
26
+ const dryRun = argv.dryRun || argv["dry-run"] || false;
27
+ const overwrite = argv.overwrite || false;
28
+ const verbose = argv.verbose || false;
29
+
30
+ console.log("🔍 Scanning source files for GxP configuration...");
31
+ console.log(` Project: ${projectPath}`);
32
+ console.log(` Source: ${srcDir}`);
33
+ console.log("");
34
+
35
+ // Check if src directory exists
36
+ if (!fs.existsSync(srcDir)) {
37
+ console.error("❌ Source directory not found: src/");
38
+ console.log(" Make sure you are in a GxP project directory.");
39
+ return;
40
+ }
41
+
42
+ // Extract configuration from source files
43
+ const extractedConfig = extractConfigFromSource(srcDir);
44
+
45
+ // Show summary of what was found
46
+ const summary = generateSummary(extractedConfig);
47
+ console.log(summary);
48
+
49
+ // Check if anything was extracted
50
+ const totalItems =
51
+ Object.keys(extractedConfig.strings).length +
52
+ Object.keys(extractedConfig.settings).length +
53
+ Object.keys(extractedConfig.assets).length +
54
+ Object.keys(extractedConfig.triggerState).length +
55
+ extractedConfig.dependencies.length;
56
+
57
+ if (totalItems === 0) {
58
+ console.log("â„šī¸ No GxP configuration found in source files.");
59
+ console.log("");
60
+ console.log("💡 Tips:");
61
+ console.log(" - Use store.getString('key', 'default') in your components");
62
+ console.log(" - Use gxp-string directive: <span gxp-string=\"key\">default</span>");
63
+ console.log(" - Use gxp-src directive: <img gxp-src=\"key\" src=\"/default.jpg\" />");
64
+ return;
65
+ }
66
+
67
+ if (dryRun) {
68
+ console.log("🔸 Dry run mode - no changes will be made.");
69
+ console.log("");
70
+ console.log("To apply changes, run without --dry-run flag:");
71
+ console.log(" gxdev extract-config");
72
+ return;
73
+ }
74
+
75
+ // Load existing manifest or create new one
76
+ let existingManifest = {};
77
+ if (fs.existsSync(manifestPath)) {
78
+ try {
79
+ existingManifest = JSON.parse(fs.readFileSync(manifestPath, "utf-8"));
80
+ if (verbose) {
81
+ console.log("📄 Found existing app-manifest.json");
82
+ }
83
+ } catch (error) {
84
+ console.warn("⚠ Could not parse existing app-manifest.json, creating new one");
85
+ existingManifest = getDefaultManifest();
86
+ }
87
+ } else {
88
+ console.log("📄 Creating new app-manifest.json");
89
+ existingManifest = getDefaultManifest();
90
+ }
91
+
92
+ // Merge extracted config into manifest
93
+ const mergedManifest = mergeConfig(existingManifest, extractedConfig, {
94
+ overwrite,
95
+ });
96
+
97
+ // Write updated manifest
98
+ try {
99
+ fs.writeFileSync(manifestPath, JSON.stringify(mergedManifest, null, "\t"));
100
+ console.log("✅ Updated app-manifest.json");
101
+
102
+ if (verbose) {
103
+ console.log("");
104
+ console.log("📋 Changes applied:");
105
+ logChanges(existingManifest, mergedManifest, extractedConfig);
106
+ }
107
+ } catch (error) {
108
+ console.error("❌ Error writing app-manifest.json:", error.message);
109
+ }
110
+ }
111
+
112
+ /**
113
+ * Get default manifest structure
114
+ * @returns {Object} Default manifest
115
+ */
116
+ function getDefaultManifest() {
117
+ return {
118
+ name: "GxToolkit",
119
+ version: "1.0.0",
120
+ description: "GxToolkit Plugin",
121
+ manifest_version: 3,
122
+ asset_dir: "/src/assets/",
123
+ configurationFile: "configuration.json",
124
+ appInstructionsFile: "app-instructions.md",
125
+ defaultStylingFile: "default-styling.css",
126
+ settings: {},
127
+ strings: {
128
+ default: {},
129
+ },
130
+ assets: {},
131
+ triggerState: {},
132
+ dependencies: [],
133
+ permissions: [],
134
+ };
135
+ }
136
+
137
+ /**
138
+ * Log what changes were made
139
+ * @param {Object} oldManifest - Original manifest
140
+ * @param {Object} newManifest - Updated manifest
141
+ * @param {Object} extracted - Extracted configuration
142
+ */
143
+ function logChanges(oldManifest, newManifest, extracted) {
144
+ const oldStrings = oldManifest.strings?.default || {};
145
+ const newStrings = newManifest.strings?.default || {};
146
+
147
+ // Count new additions
148
+ let addedStrings = 0;
149
+ let addedSettings = 0;
150
+ let addedAssets = 0;
151
+ let addedState = 0;
152
+ let addedDeps = 0;
153
+
154
+ for (const key of Object.keys(extracted.strings)) {
155
+ if (!oldStrings[key]) addedStrings++;
156
+ }
157
+
158
+ for (const key of Object.keys(extracted.settings)) {
159
+ if (oldManifest.settings?.[key] === undefined) addedSettings++;
160
+ }
161
+
162
+ for (const key of Object.keys(extracted.assets)) {
163
+ if (!oldManifest.assets?.[key]) addedAssets++;
164
+ }
165
+
166
+ for (const key of Object.keys(extracted.triggerState)) {
167
+ if (oldManifest.triggerState?.[key] === undefined) addedState++;
168
+ }
169
+
170
+ for (const dep of extracted.dependencies) {
171
+ const exists = (oldManifest.dependencies || []).some(
172
+ (d) => d.identifier === dep.identifier
173
+ );
174
+ if (!exists) addedDeps++;
175
+ }
176
+
177
+ if (addedStrings > 0) console.log(` + ${addedStrings} new string(s)`);
178
+ if (addedSettings > 0) console.log(` + ${addedSettings} new setting(s)`);
179
+ if (addedAssets > 0) console.log(` + ${addedAssets} new asset(s)`);
180
+ if (addedState > 0) console.log(` + ${addedState} new state value(s)`);
181
+ if (addedDeps > 0) console.log(` + ${addedDeps} new dependency(ies)`);
182
+ }
183
+
184
+ module.exports = {
185
+ extractConfigCommand,
186
+ };
@@ -18,6 +18,7 @@ const {
18
18
  extensionBuildCommand,
19
19
  extensionInstallCommand,
20
20
  } = require("./extensions");
21
+ const { extractConfigCommand } = require("./extract-config");
21
22
 
22
23
  module.exports = {
23
24
  initCommand,
@@ -32,4 +33,5 @@ module.exports = {
32
33
  extensionChromeCommand,
33
34
  extensionBuildCommand,
34
35
  extensionInstallCommand,
36
+ extractConfigCommand,
35
37
  };