msfs-layout-generator 0.1.1 → 0.1.3

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/dist/cli.js CHANGED
@@ -40,7 +40,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
40
40
  const commander_1 = require("commander");
41
41
  const chalk_1 = __importDefault(require("chalk"));
42
42
  const path = __importStar(require("path"));
43
- const doProcessLayoutFileCli_1 = require("./utils/doProcessLayoutFileCli");
43
+ const processLayout_1 = require("./utils/processLayout");
44
44
  // Define the program
45
45
  const program = new commander_1.Command();
46
46
  // Helper function for consistent logging
@@ -135,7 +135,7 @@ async function handleAction(directories, options) {
135
135
  throw new Error(`Directory does not exist`);
136
136
  }
137
137
  // Run the main processing function
138
- const result = await (0, doProcessLayoutFileCli_1.doProcessLayoutFileCli)(fullPath, {
138
+ const result = await (0, processLayout_1.doProcessLayoutFileCli)(fullPath, {
139
139
  force,
140
140
  quiet,
141
141
  debug,
package/dist/index.js CHANGED
@@ -1,7 +1,7 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.generateLayout = void 0;
4
- const doProcessLayoutFile_1 = require("./utils/doProcessLayoutFile");
4
+ const processLayout_1 = require("./utils/processLayout");
5
5
  /**
6
6
  * Process an MSFS package directory to generate/update layout.json
7
7
  *
@@ -27,4 +27,4 @@ const doProcessLayoutFile_1 = require("./utils/doProcessLayoutFile");
27
27
  * console.error("Failed:", error.message);
28
28
  * }
29
29
  */
30
- exports.generateLayout = doProcessLayoutFile_1.doProcessLayoutFile;
30
+ exports.generateLayout = processLayout_1.doProcessLayoutFile;
@@ -24,3 +24,4 @@
24
24
  * }
25
25
  */
26
26
  export declare const generateLayout: (layoutPath: string) => Promise<void>;
27
+ export type { ProcessOptions, ProcessResult } from "@/index.d";
@@ -0,0 +1,12 @@
1
+ import { ProcessOptions, ProcessResult } from "@/index.d";
2
+ /**
3
+ * Unified function to process layout files for MSFS packages
4
+ * Can be used both programmatically and via CLI
5
+ *
6
+ * @param packageDir - Path to MSFS package directory
7
+ * @param options - Processing options
8
+ * @returns Promise<void> if returnResult=false, Promise<ProcessResult> if returnResult=true
9
+ */
10
+ export declare const processLayout: (packageDir: string, options?: ProcessOptions) => Promise<void | ProcessResult>;
11
+ export declare const doProcessLayoutFile: (layoutPath: string) => Promise<void>;
12
+ export declare const doProcessLayoutFileCli: (packageDir: string, options?: Omit<ProcessOptions, "returnResult">) => Promise<ProcessResult>;
@@ -33,38 +33,46 @@ var __importStar = (this && this.__importStar) || (function () {
33
33
  };
34
34
  })();
35
35
  Object.defineProperty(exports, "__esModule", { value: true });
36
- exports.doProcessLayoutFileCli = void 0;
36
+ exports.doProcessLayoutFileCli = exports.doProcessLayoutFile = exports.processLayout = void 0;
37
37
  const path = __importStar(require("node:path"));
38
38
  const getAllFiles_1 = require("./getAllFiles");
39
39
  const doExcludeFile_1 = require("./doExcludeFile");
40
40
  const promises_1 = require("fs/promises");
41
41
  const getWindowsFileTime_1 = require("./getWindowsFileTime");
42
42
  const doUpdateManifest_1 = require("./doUpdateManifest");
43
- const doProcessLayoutFileCli = async (packageDir, options = {}) => {
44
- const { force = false, quiet = false, debug = false, checkManifest = true, skipManifestUpdate = false } = options;
43
+ /**
44
+ * Unified function to process layout files for MSFS packages
45
+ * Can be used both programmatically and via CLI
46
+ *
47
+ * @param packageDir - Path to MSFS package directory
48
+ * @param options - Processing options
49
+ * @returns Promise<void> if returnResult=false, Promise<ProcessResult> if returnResult=true
50
+ */
51
+ const processLayout = async (packageDir, options = {}) => {
52
+ const { force = false, quiet = false, debug = false, checkManifest = true, skipManifestUpdate = false, returnResult = false // Default: behave like old doProcessLayoutFile
53
+ } = options;
45
54
  const layoutPathFile = path.join(packageDir, 'layout.json');
46
55
  const manifestPath = path.join(packageDir, 'manifest.json');
56
+ // Helper logging function
57
+ const log = (message, type = 'info') => {
58
+ if (quiet)
59
+ return;
60
+ const prefixes = {
61
+ info: 'ℹ',
62
+ warn: '⚠',
63
+ error: '✗',
64
+ success: '✓'
65
+ };
66
+ console.log(`${prefixes[type]} ${message}`);
67
+ };
47
68
  // Validate input directory exists
48
69
  try {
49
70
  await (0, promises_1.access)(packageDir, promises_1.constants.F_OK);
50
71
  }
51
72
  catch {
52
- return {
53
- fileCount: 0,
54
- totalSize: 0,
55
- layoutPath: layoutPathFile,
56
- manifestPath,
57
- skippedFiles: 0,
58
- success: false,
59
- message: `Directory does not exist: ${packageDir}`
60
- };
61
- }
62
- // Check for manifest.json if required
63
- if (checkManifest) {
64
- try {
65
- await (0, promises_1.access)(manifestPath, promises_1.constants.F_OK);
66
- }
67
- catch {
73
+ const error = `Directory does not exist: ${packageDir}`;
74
+ log(error, 'error');
75
+ if (returnResult) {
68
76
  return {
69
77
  fileCount: 0,
70
78
  totalSize: 0,
@@ -72,14 +80,54 @@ const doProcessLayoutFileCli = async (packageDir, options = {}) => {
72
80
  manifestPath,
73
81
  skippedFiles: 0,
74
82
  success: false,
75
- message: `manifest.json not found in ${packageDir}`
83
+ message: error
76
84
  };
77
85
  }
86
+ throw new Error(error);
87
+ }
88
+ // Check for manifest.json if required
89
+ if (checkManifest) {
90
+ try {
91
+ await (0, promises_1.access)(manifestPath, promises_1.constants.F_OK);
92
+ }
93
+ catch {
94
+ const error = `manifest.json not found in ${packageDir}`;
95
+ log(error, 'error');
96
+ if (returnResult) {
97
+ return {
98
+ fileCount: 0,
99
+ totalSize: 0,
100
+ layoutPath: layoutPathFile,
101
+ manifestPath,
102
+ skippedFiles: 0,
103
+ success: false,
104
+ message: error
105
+ };
106
+ }
107
+ throw new Error(error);
108
+ }
78
109
  }
79
110
  // Check if layout.json already exists
111
+ let shouldProceed = true;
112
+ let skipReason = '';
80
113
  try {
81
114
  await (0, promises_1.access)(layoutPathFile, promises_1.constants.F_OK);
82
115
  if (!force) {
116
+ skipReason = 'layout.json already exists. Use --force to overwrite.';
117
+ shouldProceed = false;
118
+ }
119
+ else if (debug) {
120
+ log('layout.json exists, will overwrite due to --force flag', 'info');
121
+ }
122
+ }
123
+ catch {
124
+ // layout.json doesn't exist, that's fine
125
+ if (debug) {
126
+ log('No existing layout.json found, creating new one', 'info');
127
+ }
128
+ }
129
+ if (!shouldProceed) {
130
+ if (returnResult) {
83
131
  return {
84
132
  fileCount: 0,
85
133
  totalSize: 0,
@@ -87,45 +135,44 @@ const doProcessLayoutFileCli = async (packageDir, options = {}) => {
87
135
  manifestPath,
88
136
  skippedFiles: 0,
89
137
  success: false,
90
- message: `layout.json already exists. Use --force to overwrite.`
138
+ message: skipReason
91
139
  };
92
140
  }
93
- if (debug && !quiet) {
94
- console.log(`Debug: layout.json exists, will overwrite due to --force flag`);
95
- }
96
- }
97
- catch {
98
- // layout.json doesn't exist, that's fine
99
- if (debug && !quiet) {
100
- console.log(`Debug: No existing layout.json found, creating new one`);
101
- }
141
+ log(skipReason, 'warn');
142
+ return;
102
143
  }
144
+ // Main processing logic
103
145
  let totalPackageSize = 0;
104
146
  const layout = { content: [] };
105
147
  let hasLongPath = false;
106
148
  let excludedCount = 0;
107
149
  try {
108
150
  const allFiles = await (0, getAllFiles_1.getAllFiles)(packageDir);
109
- if (debug && !quiet) {
110
- console.log(`Debug: Found ${allFiles.length} total files in ${packageDir}`);
151
+ if (debug) {
152
+ log(`Found ${allFiles.length} total files in ${packageDir}`, 'info');
111
153
  }
112
154
  if (allFiles.length === 0) {
113
- return {
114
- fileCount: 0,
115
- totalSize: 0,
116
- layoutPath: layoutPathFile,
117
- manifestPath,
118
- skippedFiles: 0,
119
- success: false,
120
- message: 'No files found in package directory'
121
- };
155
+ const error = 'No files found in package directory';
156
+ log(error, 'error');
157
+ if (returnResult) {
158
+ return {
159
+ fileCount: 0,
160
+ totalSize: 0,
161
+ layoutPath: layoutPathFile,
162
+ manifestPath,
163
+ skippedFiles: 0,
164
+ success: false,
165
+ message: error
166
+ };
167
+ }
168
+ throw new Error(error);
122
169
  }
123
170
  for (const file of allFiles) {
124
171
  // Check for long file paths (Windows limitation)
125
172
  if (file.length > 259) {
126
173
  hasLongPath = true;
127
- if (debug && !quiet) {
128
- console.log(`Debug: Skipping long path: ${file}`);
174
+ if (debug) {
175
+ log(`Skipping long path: ${file}`, 'info');
129
176
  }
130
177
  continue;
131
178
  }
@@ -136,8 +183,8 @@ const doProcessLayoutFileCli = async (packageDir, options = {}) => {
136
183
  totalPackageSize += stats.size;
137
184
  if (isExcluded) {
138
185
  excludedCount++;
139
- if (debug && !quiet) {
140
- console.log(`Debug: Excluding file: ${relativePath}`);
186
+ if (debug) {
187
+ log(`Excluding file: ${relativePath}`, 'info');
141
188
  }
142
189
  continue;
143
190
  }
@@ -149,25 +196,30 @@ const doProcessLayoutFileCli = async (packageDir, options = {}) => {
149
196
  layout.content.push(content);
150
197
  }
151
198
  catch (error) {
152
- if (debug && !quiet) {
153
- console.log(`Debug: Error processing file ${file}: ${error.message}`);
199
+ if (debug) {
200
+ log(`Error processing file ${file}: ${error.message}`, 'info');
154
201
  }
155
202
  excludedCount++;
156
203
  }
157
204
  }
158
- if (hasLongPath && !quiet) {
159
- console.log(`Warning: One or more file paths exceed 259 characters and were skipped.`);
205
+ if (hasLongPath) {
206
+ log('One or more file paths exceed 259 characters and were skipped.', 'warn');
160
207
  }
161
208
  if (layout.content.length === 0) {
162
- return {
163
- fileCount: 0,
164
- totalSize: 0,
165
- layoutPath: layoutPathFile,
166
- manifestPath,
167
- skippedFiles: excludedCount,
168
- success: false,
169
- message: 'No valid files to include in layout.json'
170
- };
209
+ const error = 'No valid files to include in layout.json';
210
+ log(error, 'error');
211
+ if (returnResult) {
212
+ return {
213
+ fileCount: 0,
214
+ totalSize: 0,
215
+ layoutPath: layoutPathFile,
216
+ manifestPath,
217
+ skippedFiles: excludedCount,
218
+ success: false,
219
+ message: error
220
+ };
221
+ }
222
+ throw new Error(error);
171
223
  }
172
224
  // Sort content by path for consistent output
173
225
  layout.content.sort((a, b) => a.path.localeCompare(b.path));
@@ -182,39 +234,48 @@ const doProcessLayoutFileCli = async (packageDir, options = {}) => {
182
234
  try {
183
235
  await (0, promises_1.access)(manifestPath, promises_1.constants.F_OK);
184
236
  await (0, doUpdateManifest_1.doUpdateManifest)(manifestPath, totalPackageSize);
185
- if (debug && !quiet) {
186
- console.log(`Debug: Updated manifest.json with total_package_size`);
237
+ if (debug) {
238
+ log('Updated manifest.json with total_package_size', 'info');
187
239
  }
188
240
  }
189
241
  catch {
190
242
  // manifest doesn't exist, skip
191
- if (debug && !quiet) {
192
- console.log(`Debug: manifest.json not found, skipping update`);
243
+ if (debug) {
244
+ log('manifest.json not found, skipping update', 'info');
193
245
  }
194
246
  }
195
247
  }
196
- if (!quiet) {
197
- console.log(`Successfully updated layout.json with ${layout.content.length} files`);
248
+ log(`Successfully updated layout.json with ${layout.content.length} files`, 'success');
249
+ if (returnResult) {
250
+ return {
251
+ fileCount: layout.content.length,
252
+ totalSize: totalPackageSize,
253
+ layoutPath: layoutPathFile,
254
+ manifestPath,
255
+ skippedFiles: excludedCount,
256
+ success: true
257
+ };
198
258
  }
199
- return {
200
- fileCount: layout.content.length,
201
- totalSize: totalPackageSize,
202
- layoutPath: layoutPathFile,
203
- manifestPath,
204
- skippedFiles: excludedCount,
205
- success: true
206
- };
207
259
  }
208
260
  catch (error) {
209
- return {
210
- fileCount: 0,
211
- totalSize: 0,
212
- layoutPath: layoutPathFile,
213
- manifestPath,
214
- skippedFiles: excludedCount,
215
- success: false,
216
- message: `Error processing ${packageDir}: ${error.message}`
217
- };
261
+ const errorMsg = `Error processing ${packageDir}: ${error.message}`;
262
+ log(errorMsg, 'error');
263
+ if (returnResult) {
264
+ return {
265
+ fileCount: 0,
266
+ totalSize: 0,
267
+ layoutPath: layoutPathFile,
268
+ manifestPath,
269
+ skippedFiles: excludedCount,
270
+ success: false,
271
+ message: errorMsg
272
+ };
273
+ }
274
+ throw error;
218
275
  }
219
276
  };
277
+ exports.processLayout = processLayout;
278
+ const doProcessLayoutFile = (layoutPath) => (0, exports.processLayout)(layoutPath, { returnResult: false });
279
+ exports.doProcessLayoutFile = doProcessLayoutFile;
280
+ const doProcessLayoutFileCli = (packageDir, options = {}) => (0, exports.processLayout)(packageDir, { ...options, returnResult: true });
220
281
  exports.doProcessLayoutFileCli = doProcessLayoutFileCli;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "msfs-layout-generator",
3
- "version": "0.1.1",
3
+ "version": "0.1.3",
4
4
  "description": "Generate layout.json for MSFS community packages",
5
5
  "repository": {
6
6
  "type": "git",
@@ -31,17 +31,17 @@
31
31
  },
32
32
  "devDependencies": {
33
33
  "@types/bun": "latest",
34
- "tsc-alias": "^1.8.16"
34
+ "tsc-alias": "^1.8.16",
35
+ "@types/node": "^25.0.3",
36
+ "ts-node": "^10.9.2",
37
+ "tsconfig-paths": "^4.2.0"
35
38
  },
36
39
  "peerDependencies": {
37
40
  "typescript": "^5.9.3"
38
41
  },
39
42
  "dependencies": {
40
- "@types/node": "^25.0.3",
41
43
  "chalk": "^5.6.2",
42
44
  "commander": "^14.0.2",
43
- "glob": "^13.0.0",
44
- "ts-node": "^10.9.2",
45
- "tsconfig-paths": "^4.2.0"
45
+ "glob": "^13.0.0"
46
46
  }
47
47
  }
@@ -1 +0,0 @@
1
- export declare const doProcessLayoutFile: (layoutPath: string) => Promise<void>;
@@ -1,17 +0,0 @@
1
- export interface ProcessOptions {
2
- force?: boolean;
3
- quiet?: boolean;
4
- debug?: boolean;
5
- checkManifest?: boolean;
6
- skipManifestUpdate?: boolean;
7
- }
8
- export interface ProcessResult {
9
- fileCount: number;
10
- totalSize: number;
11
- layoutPath: string;
12
- manifestPath: string;
13
- skippedFiles: number;
14
- success: boolean;
15
- message?: string;
16
- }
17
- export declare const doProcessLayoutFileCli: (packageDir: string, options?: ProcessOptions) => Promise<ProcessResult>;
@@ -1,109 +0,0 @@
1
- "use strict";
2
- var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
- if (k2 === undefined) k2 = k;
4
- var desc = Object.getOwnPropertyDescriptor(m, k);
5
- if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
- desc = { enumerable: true, get: function() { return m[k]; } };
7
- }
8
- Object.defineProperty(o, k2, desc);
9
- }) : (function(o, m, k, k2) {
10
- if (k2 === undefined) k2 = k;
11
- o[k2] = m[k];
12
- }));
13
- var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
- Object.defineProperty(o, "default", { enumerable: true, value: v });
15
- }) : function(o, v) {
16
- o["default"] = v;
17
- });
18
- var __importStar = (this && this.__importStar) || (function () {
19
- var ownKeys = function(o) {
20
- ownKeys = Object.getOwnPropertyNames || function (o) {
21
- var ar = [];
22
- for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
- return ar;
24
- };
25
- return ownKeys(o);
26
- };
27
- return function (mod) {
28
- if (mod && mod.__esModule) return mod;
29
- var result = {};
30
- if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
- __setModuleDefault(result, mod);
32
- return result;
33
- };
34
- })();
35
- Object.defineProperty(exports, "__esModule", { value: true });
36
- exports.doProcessLayoutFile = void 0;
37
- const path = __importStar(require("node:path"));
38
- const getAllFiles_1 = require("./getAllFiles");
39
- const doExcludeFile_1 = require("./doExcludeFile");
40
- const promises_1 = require("fs/promises");
41
- const getWindowsFileTime_1 = require("./getWindowsFileTime");
42
- const doUpdateManifest_1 = require("./doUpdateManifest");
43
- const doProcessLayoutFile = async (layoutPath) => {
44
- const layoutPathFile = path.join(layoutPath, 'layout.json');
45
- const directory = await (0, promises_1.readdir)(layoutPath);
46
- if (!directory.includes('layout.json')) {
47
- console.log(`No layout.json is found in "${layoutPath}". A new layout will be created.`);
48
- await (0, promises_1.writeFile)(layoutPathFile, "", 'utf8');
49
- }
50
- let totalPackageSize = 0;
51
- const layout = { content: [] };
52
- try {
53
- const allFiles = await (0, getAllFiles_1.getAllFiles)(layoutPath);
54
- let hasLongPath = false;
55
- for (const file of allFiles) {
56
- if (file.length > 259) {
57
- hasLongPath = true;
58
- continue;
59
- }
60
- const relativePath = path.relative(layoutPath, file).split(path.sep).join('/');
61
- const isExcluded = (0, doExcludeFile_1.doExcludeFile)(relativePath);
62
- try {
63
- const stats = await (0, promises_1.stat)(file);
64
- totalPackageSize += stats.size;
65
- if (isExcluded) {
66
- continue;
67
- }
68
- const content = {
69
- path: relativePath,
70
- size: stats.size,
71
- date: (0, getWindowsFileTime_1.getWindowsFileTime)(stats.mtime)
72
- };
73
- layout.content.push(content);
74
- }
75
- catch (error) {
76
- console.log(`Error processing file ${file}: ${error.message}`);
77
- }
78
- }
79
- if (hasLongPath) {
80
- console.log(`Warning: One or more file paths in the folder containing "${layoutPath}" are 260 characters or greater in length. Some files may have been skipped.`);
81
- }
82
- if (layout.content.length === 0) {
83
- console.log(`No files were found in the folder containing "${layoutPath}". The layout.json will not be updated.`);
84
- return;
85
- }
86
- // Sort content by path for consistent output
87
- layout.content.sort((a, b) => a.path.localeCompare(b.path));
88
- // Write layout.json with LF line endings
89
- const json = JSON.stringify(layout, null, 2).replace(/\r\n/g, '\n');
90
- await (0, promises_1.writeFile)(layoutPathFile, json, 'utf8');
91
- // Add layout.json size to total
92
- const layoutStats = await (0, promises_1.stat)(layoutPath);
93
- totalPackageSize += layoutStats.size;
94
- // Update manifest.json if it exists
95
- const manifestPath = path.join(layoutPath, 'manifest.json');
96
- try {
97
- await (0, promises_1.access)(manifestPath, promises_1.constants.F_OK);
98
- await (0, doUpdateManifest_1.doUpdateManifest)(manifestPath, totalPackageSize);
99
- }
100
- catch {
101
- // manifest doesn't exist, skip
102
- }
103
- console.log(`Successfully updated ${layoutPath} with ${layout.content.length} files`);
104
- }
105
- catch (error) {
106
- console.log(`Error processing ${layoutPathFile}: ${error.message}`);
107
- }
108
- };
109
- exports.doProcessLayoutFile = doProcessLayoutFile;