jizy-packer 2.0.6 → 2.1.1

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/README.md CHANGED
@@ -1,2 +1,120 @@
1
+
1
2
  # jizy-packer
2
- Build a CLI app to generate optimized builds.
3
+
4
+ A CLI tool and Node.js library to generate optimized builds for your projects. It provides utilities for configuration management, build orchestration, and file operations.
5
+
6
+ ## Features
7
+
8
+ - Command-line interface for building projects
9
+ - Configurable via JSON and programmatic API
10
+ - Utilities for cleaning build folders and managing configs
11
+ - Rollup-based build process with plugin support
12
+
13
+ ## Quick Usage
14
+
15
+ ### CLI
16
+
17
+ ```sh
18
+ node lib/Cli.js
19
+ node lib/Cli.js --action build --name perso --config { "key": "value" }
20
+ node lib/Cli.js --action build --name perso --config ABSOLUTE_PATH_TO_JSON_FILE
21
+ ```
22
+
23
+ Options:
24
+ - `--action, -a` Build action (dist|build)
25
+ - `--name, -n` Name of the build
26
+ - `--config, -c` Path to the custom config file or JSON string
27
+ - `--debug, -d` Enable debug mode
28
+
29
+ ### Programmatic
30
+
31
+ ```js
32
+ import jPackBuild from './lib/Build.js';
33
+
34
+ await jPackBuild({
35
+ action: 'build',
36
+ name: 'perso',
37
+ config: 'PATH_TO_JSON_FILE',
38
+ debug: true
39
+ });
40
+ ```
41
+
42
+ ### Create a jPacker
43
+
44
+ Example from the "jizy-browser" extension.
45
+
46
+ ***First for the default dist build***
47
+
48
+ #### ./config/config.json
49
+ ```json
50
+ {
51
+ "desktopBreakpoint": "900px"
52
+ }
53
+ ```
54
+
55
+ #### ./config/jpack.js
56
+ ```js
57
+ import fs from 'fs';
58
+ import path from 'path';
59
+ import { LogMe, jPackConfig } from 'jizy-packer';
60
+
61
+ const jPackData = {
62
+ name: 'BrowserCompat',
63
+ alias: 'jizy-browser',
64
+
65
+ onCheckConfig: () => {
66
+ // add some config validation
67
+ const desktopBreakpoint = jPackConfig.get('desktopBreakpoint');
68
+ if (!desktopBreakpoint) {
69
+ LogMe.error('Missing desktopBreakpoint in config');
70
+ process.exit(1);
71
+ }
72
+ },
73
+
74
+ // generate config.less
75
+ onGenerateBuildJs: (code) => {
76
+ LogMe.log('Generate config.less');
77
+ const desktopBreakpoint = jPackConfig.get('desktopBreakpoint') ?? '768px';
78
+ let lessContent = `@desktop-breakpoint: ${desktopBreakpoint};\n`;
79
+ lessContent += `@mobile-breakpoint: @desktop-breakpoint - 1px;`;
80
+ fs.writeFileSync(path.join(jPackConfig.get('targetPath'), 'config.less'), lessContent);
81
+ return code;
82
+ },
83
+
84
+ // parse wrapped js
85
+ onGenerateWrappedJs: (wrapped) => wrapped,
86
+
87
+ // after packing
88
+ onPacked: () => { }
89
+ };
90
+
91
+ export default jPackData;
92
+ ```
93
+
94
+ #### ./config/jpack.template
95
+ ```js
96
+ import BrowserCompat from '{{PREFIX}}lib/js/browsercompat.js';
97
+ import '{{PREFIX}}lib/browsercompat.less';
98
+ export default BrowserCompat;
99
+ ```
100
+
101
+ #### ./config/jpack.wrapper.js
102
+ ```js
103
+ /*! BrowserCompat v@VERSION | @DATE | [@BUNDLE] */
104
+ (function (global) {
105
+ "use strict";
106
+
107
+ if (typeof global !== "object" || !global || !global.document) {
108
+ throw new Error("BrowserCompat requires a window and a document");
109
+ }
110
+
111
+ if (typeof global.BrowserCompat !== "undefined") {
112
+ throw new Error("BrowserCompat is already defined");
113
+ }
114
+
115
+ // @CODE
116
+
117
+ global.BrowserCompat = BrowserCompat;
118
+
119
+ })(typeof window !== "undefined" ? window : this);
120
+ ```
package/lib/Build.js CHANGED
@@ -1,193 +1,141 @@
1
1
  import fs from 'fs';
2
2
  import path from 'path';
3
3
  import { rollup } from 'rollup';
4
+ import { pathToFileURL } from 'url';
4
5
 
5
6
  import LogMe from "./LogMe.js";
6
7
  import jPackConfig from "./Config.js";
7
8
  import jPackRollup from "./Rollup.js";
8
- import { cleanBuildFolder } from './utils.js';
9
+ import { emptyTargetPath, loadJson } from "./utils.js";
10
+
11
+ /**
12
+ * @param {string} action the build action (dist|build) defaults to dist
13
+ * @param {string} name the name of the build ([a-z0-9\-\_])
14
+ * @param {string } config the path to the custom config.json file
15
+ * @param {boolean} debug for verbose logging
16
+ *
17
+ * 1. build dist default export
18
+ * no params
19
+ * default package config
20
+ * use ./config/jpack.js
21
+ * use ./config/config.json
22
+ * 2. build custom config
23
+ * name (default to custom)
24
+ * default package config
25
+ * use ./config/jpack.js
26
+ * use ./config/config.json
27
+ * custom package config
28
+ * use [ABS_PATH_TO_CONFIG].json or json string
29
+ */
9
30
 
10
31
  export default async function jPackBuild({
11
- target = null,
32
+ action = null,
12
33
  name = null,
13
- zip = false,
34
+ config = null,
14
35
  debug = false
15
36
  } = {}) {
16
37
 
17
- LogMe.log('---');
18
-
19
38
  if (debug) {
20
39
  process.env.DEBUG = true;
21
40
  }
22
41
 
23
- LogMe.log('Build project...');
24
-
25
- if (!target || target === 'dist') {
26
- target = '';
27
- name = '';
28
- zip = false;
42
+ if (!action || action !== 'build') {
43
+ action = 'dist';
29
44
  }
30
45
 
31
- if (zip && !name) {
32
- name = 'zip';
46
+ if (config) {
47
+ action = 'build';
33
48
  }
34
49
 
35
- if (target && !name) {
36
- name = 'export';
37
- }
38
-
39
- if (!name) {
50
+ if (action === 'dist') {
40
51
  name = 'default';
52
+ config = null;
53
+ } else {
54
+ // Sanitize the build folder name
55
+ if (name) {
56
+ name = name.replace(/[^a-zA-Z0-9\-\_]/g, '');
57
+ name = name.toLowerCase();
58
+ }
59
+
60
+ if (!name) {
61
+ name = 'custom';
62
+ }
41
63
  }
42
64
 
43
- LogMe.log(' Target: ' + target);
44
- LogMe.log(' Name: ' + name);
45
- LogMe.log(' Zip: ' + (zip ? 'enabled' : 'disabled'));
46
- LogMe.log(' Debug: ' + (debug ? 'enabled' : 'disabled'));
65
+ LogMe.log('---');
66
+ LogMe.log('action: ' + action);
67
+ LogMe.log('name: ' + name);
68
+ LogMe.log('config: ' + (config ? 'yes' : 'no'));
69
+ LogMe.log('debug: ' + (debug ? 'enabled' : 'disabled'));
47
70
  LogMe.log('---');
48
71
 
49
- jPackConfig.set('buildZip', zip);
50
72
  jPackConfig.set('buildName', name);
51
-
52
- let targetPath;
53
- if (target) {
54
- targetPath = path.join(jPackConfig.get('basePath'), 'build', target);
55
- jPackConfig.set('buildTarget', targetPath);
56
- if (!fs.existsSync(targetPath)) {
57
- fs.mkdirSync(targetPath, { recursive: true });
58
- }
59
- } else {
60
- LogMe.log('Empty or create dist directory');
61
- targetPath = path.join(jPackConfig.get('basePath'), 'dist');
62
- jPackConfig.set('buildTarget', targetPath);
63
- cleanBuildFolder(targetPath);
64
-
65
- const targetCfgPath = path.join(targetPath, 'config.json');
66
- if (!fs.existsSync(targetCfgPath)) {
67
- const defaultCfgPath = path.join(jPackConfig.get('basePath'), 'config', 'config.json');
68
- if (fs.existsSync(defaultCfgPath)) {
69
- LogMe.log('Copy default config.json file');
70
- fs.copyFileSync(defaultCfgPath, targetCfgPath);
73
+ jPackConfig.set('action', action);
74
+ jPackConfig.set('debug', debug);
75
+
76
+ if (config) {
77
+ LogMe.log('Build config');
78
+ try {
79
+ if (config.substr(0, 1) === '{') {
80
+ LogMe.log(' JSON string');
81
+ jPackConfig.sets(JSON.parse(config));
82
+ } else {
83
+ LogMe.log(' JSON file');
84
+ jPackConfig.sets(loadJson(config));
71
85
  }
86
+ } catch (error) {
87
+ LogMe.error(' ' + error.message);
88
+ process.exit(1);
72
89
  }
73
90
  }
74
91
 
75
- const defaultCfgPath = path.join(jPackConfig.get('basePath'), 'config', 'config.json');
76
- const targetCfgPath = path.join(jPackConfig.get('buildTarget'), 'config.json');
77
- if (!fs.existsSync(targetCfgPath)) {
78
- if (fs.existsSync(defaultCfgPath)) {
79
- LogMe.log('Copy default config.json file');
80
- fs.copyFileSync(defaultCfgPath, targetCfgPath);
81
- }
82
- }
83
-
84
- if (fs.existsSync(defaultCfgPath)) {
85
- LogMe.log('Load default config file');
86
- LogMe.log(defaultCfgPath);
87
- jPackConfig.loadFromJson(defaultCfgPath);
88
- }
89
-
90
- const cfgPath = checkTargetDirectory(jPackConfig.get('buildTarget'));
91
- if (fs.existsSync(cfgPath)) {
92
- LogMe.log(`Load client config file`);
93
- LogMe.log(cfgPath);
94
- jPackConfig.loadFromJson(cfgPath);
95
- }
92
+ jPackConfig.validate();
96
93
 
97
94
  try {
98
- jPackConfig.setPackageVersion();
99
- checkConfig();
100
- await doBuild();
95
+ LogMe.log('Empty the target directory');
96
+ LogMe.log(' TargetPath: ' + jPackConfig.get('targetPath'));
97
+ emptyTargetPath(jPackConfig.get('targetPath'));
101
98
  } catch (error) {
102
- LogMe.error(`Failed to load configuration file: ${cfgPath}`);
103
- LogMe.error(error.message);
99
+ LogMe.error(' ' + error.message);
104
100
  process.exit(1);
105
101
  }
106
- };
107
102
 
108
- async function doBuild() {
109
- LogMe.log('---');
110
- LogMe.dir(jPackConfig.all());
111
103
  LogMe.log('---');
112
-
113
- const inputOptions = {
114
- input: jPackConfig.get('buildJsFilePath'),
115
- plugins: jPackRollup(),
116
- };
117
-
118
- const outputOptions = {
119
- file: jPackConfig.get('assetsPath') + '/js/' + jPackConfig.get('alias') + '.min.js',
120
- format: "iife",
121
- name: jPackConfig.get('name'),
122
- sourcemap: false,
123
- };
104
+ LogMe.log('Launch build ...');
124
105
 
125
106
  try {
126
- LogMe.log('Starting Rollup build...');
127
- const bundle = await rollup(inputOptions);
128
- await bundle.write(outputOptions);
129
- LogMe.log('Rollup build completed successfully.');
130
- } catch (error) {
131
- console.error('Error during Rollup build:', error);
132
- process.exit(1);
133
- }
134
- }
135
-
136
- function checkTargetDirectory(targetPath) {
137
- LogMe.log('checkTargetDirectory()');
138
-
139
- if (!fs.existsSync(targetPath)) {
140
- LogMe.error(`Does not exist: ${targetPath}`);
141
- process.exit(1);
142
- }
107
+ LogMe.log('---');
108
+ LogMe.dir(jPackConfig.all());
109
+ LogMe.log('---');
110
+
111
+ const inputOptions = {
112
+ input: jPackConfig.get('buildJsFilePath'),
113
+ plugins: jPackRollup(),
114
+ };
115
+
116
+ const outputOptions = {
117
+ file: jPackConfig.get('targetRelativePath') + '/js/' + jPackConfig.get('alias') + '.min.js',
118
+ format: "iife",
119
+ name: jPackConfig.get('name'),
120
+ sourcemap: false,
121
+ };
122
+
123
+ try {
124
+ LogMe.log('Starting Rollup build...');
125
+ const bundle = await rollup(inputOptions);
126
+ await bundle.write(outputOptions);
127
+ LogMe.log('Rollup build completed successfully.');
128
+ } catch (error) {
129
+ console.error('Error during Rollup build:', error);
130
+ process.exit(1);
131
+ }
143
132
 
144
- if (!fs.lstatSync(targetPath).isDirectory()) {
145
- LogMe.error(`Is not a directory: ${targetPath}`);
133
+ LogMe.log('---');
134
+ LogMe.log('Build completed successfully');
135
+ LogMe.log('---');
146
136
  process.exit(1);
147
- }
148
-
149
- const cfgPath = path.join(targetPath, 'config.json');
150
-
151
- if (!fs.existsSync(cfgPath)) {
152
- LogMe.warn(' config.json not found in target path');
153
- return null;
154
- }
155
-
156
- const files = fs.readdirSync(targetPath)
157
- .filter(file => file !== 'config.json');
158
-
159
- if (files.length > 0) {
160
- LogMe.error('Build target can only contain config.json');
137
+ } catch (error) {
138
+ LogMe.error(error.message);
161
139
  process.exit(1);
162
140
  }
163
-
164
- return cfgPath;
165
- }
166
-
167
- function checkConfig() {
168
- const basePath = jPackConfig.get('basePath');
169
-
170
- const buildName = jPackConfig.get('buildName')
171
- .replace(/[^a-zA-Z0-9]/g, ''); // Sanitize the build folder name
172
-
173
- jPackConfig.set('buildName', buildName);
174
-
175
- if (buildName === 'default') {
176
- jPackConfig.set('assetsPath', 'dist');
177
- jPackConfig.set('importPrefix', '../');
178
- }
179
- else {
180
- jPackConfig.set('assetsPath', 'build/' + buildName);
181
- jPackConfig.set('importPrefix', '../../');
182
- }
183
-
184
- jPackConfig.set('assetsFullpath', path.join(basePath, jPackConfig.get('assetsPath')));
185
- jPackConfig.set('buildJsFilePath', path.join(basePath, jPackConfig.get('assetsPath'), 'build.js'));
186
- jPackConfig.set('buildTemplatePath', path.join(basePath, 'config', 'jpack.template'));
187
- jPackConfig.set('wrapperPath', path.join(basePath, 'config', 'jpack.wrapper.js'));
188
-
189
- const onCheckConfig = jPackConfig.get('onCheckConfig');
190
- if (typeof onCheckConfig === 'function') {
191
- onCheckConfig();
192
- }
193
- }
141
+ };
package/lib/Cli.js CHANGED
@@ -3,17 +3,17 @@ import { hideBin } from 'yargs/helpers';
3
3
  import jPackBuild from "./Build.js";
4
4
  import jPackConfig from "./Config.js";
5
5
 
6
- const jPackCli = function (cfg) {
6
+ const jPackCli = function (jPackData) {
7
7
  jPackConfig.set('basePath', process.cwd());
8
- jPackConfig.sets(cfg);
8
+ jPackData();
9
9
 
10
10
  const command = yargs(hideBin(process.argv))
11
11
  .usage('Usage: $0 <command> [options]')
12
- .option('target', {
13
- alias: 't',
12
+ .option('action', {
13
+ alias: 'a',
14
14
  type: 'string',
15
- description: 'Target path',
16
- default: '',
15
+ description: 'Set the build action (dist or build)',
16
+ default: 'dist',
17
17
  })
18
18
  .option('name', {
19
19
  alias: 'n',
@@ -21,11 +21,11 @@ const jPackCli = function (cfg) {
21
21
  description: 'Set the build name',
22
22
  default: '',
23
23
  })
24
- .option('zip', {
25
- alias: 'z',
26
- type: 'boolean',
27
- description: 'Create a zip file',
28
- default: false,
24
+ .option('config', {
25
+ alias: 'c',
26
+ type: 'string',
27
+ description: 'Custom config absolute path or json string',
28
+ default: '',
29
29
  })
30
30
  .option('debug', {
31
31
  alias: 'd',
package/lib/Config.js CHANGED
@@ -4,6 +4,10 @@ import path from 'path';
4
4
  const config = {};
5
5
 
6
6
  const jPackConfig = {
7
+ /**
8
+ * Returns a shallow copy of the current config object
9
+ * replacing functions with 'fn'.
10
+ */
7
11
  all: function () {
8
12
  const result = {};
9
13
  for (const key in config) {
@@ -17,54 +21,91 @@ const jPackConfig = {
17
21
  return result;
18
22
  },
19
23
 
20
- loadFromJson: function (cfgPath) {
21
- if (!fs.existsSync(cfgPath)) {
22
- throw new Error(`Configuration file not found: ${cfgPath}`);
23
- }
24
-
25
- const data = fs.readFileSync(cfgPath, 'utf8');
26
- const json = JSON.parse(data);
27
- this.sets(json);
28
- },
29
-
24
+ /**
25
+ * Loads the version from package.json and sets it in the config under 'version'.
26
+ */
30
27
  setPackageVersion: function () {
31
28
  const pkgPath = path.join(jPackConfig.get('basePath'), 'package.json');
29
+
32
30
  if (fs.existsSync(pkgPath)) {
33
31
  const data = fs.readFileSync(pkgPath, 'utf8');
34
32
  const json = JSON.parse(data);
33
+
35
34
  if (json.version) {
36
35
  this.set('version', json.version);
36
+ return;
37
37
  }
38
38
  }
39
+
40
+ this.set('version', '0.0.1');
39
41
  },
40
42
 
41
- check: function () {
43
+ /**
44
+ * Validates and prepares the config object, setting paths and defaults as needed.
45
+ * Throws if required fields are missing.
46
+ */
47
+ validate: function () {
42
48
  if (!config.basePath) {
43
49
  throw new Error('Invalid configuration: basePath is required.');
44
50
  }
45
51
 
46
- if (!config.name) {
47
- throw new Error('Invalid configuration: name is required.');
52
+ if (!config.buildName) {
53
+ throw new Error('Invalid configuration: buildName is required.');
54
+ }
55
+
56
+ if (config.action === 'dist') {
57
+ config.importPrefix = '../';
58
+ config.targetRelativePath = 'dist';
59
+ config.targetPath = path.join(config.basePath, 'dist');
60
+ }
61
+ else {
62
+ config.importPrefix = '../../';
63
+ config.targetPath = path.join(config.basePath, 'build', config.buildName);
64
+ config.targetRelativePath = 'build/' + config.buildName;
65
+ }
66
+
67
+ config.buildJsFilePath = path.join(config.targetPath, 'build.js');
68
+ config.buildTemplatePath = path.join(config.basePath, 'config', 'jpack.template');
69
+ config.wrapperPath = path.join(config.basePath, 'config', 'jpack.wrapper.js');
70
+
71
+ if (typeof config.onCheckConfig === 'function') {
72
+ config.onCheckConfig();
48
73
  }
49
74
 
50
75
  if (!config.alias) {
51
76
  config.alias = config.name.toLowerCase();
52
77
  config.alias = config.alias.replace(/\s+/g, '-');
53
78
  }
54
-
55
- if (!config.cfg) {
56
- config.cfg = config.alias;
57
- }
58
79
  },
59
80
 
81
+ /**
82
+ * Merges a new config object into the current config.
83
+ * @param {Object} newConfig - The config object to merge.
84
+ */
60
85
  sets: (newConfig) => {
61
- Object.assign(config, newConfig);
86
+ if (typeof newConfig !== 'object' || newConfig === null) {
87
+ throw new Error('Invalid configuration: newConfig must be an object.');
88
+ }
89
+
90
+ Object.keys(newConfig).forEach(element => {
91
+ config[element] = newConfig[element];
92
+ });
62
93
  },
63
94
 
95
+ /**
96
+ * Gets a config value by key, or returns the default if not set.
97
+ * @param {string} key - The config key.
98
+ * @param {*} def - The default value if key is not set.
99
+ */
64
100
  get(key, def) {
65
101
  return config[key] || def;
66
102
  },
67
103
 
104
+ /**
105
+ * Sets a config value by key.
106
+ * @param {string} key - The config key.
107
+ * @param {*} value - The value to set.
108
+ */
68
109
  set(key, value) {
69
110
  config[key] = value;
70
111
  }
package/lib/Rollup.js CHANGED
@@ -6,22 +6,18 @@ import json from "@rollup/plugin-json";
6
6
  import resolve from "@rollup/plugin-node-resolve";
7
7
  import commonjs from "@rollup/plugin-commonjs";
8
8
  import terser from '@rollup/plugin-terser';
9
- import { execSync } from 'child_process';
10
9
 
11
10
  import jPackConfig from "./Config.js";
12
11
  import LogMe from "./LogMe.js";
13
- import { cleanBuildFolder } from "./utils.js";
12
+ import { emptyTargetPath } from './utils.js';
14
13
 
15
14
  export default async function jPackRollup(config) {
16
- const assetsPath = jPackConfig.get('assetsPath');
17
-
18
15
  return [
19
16
  {
20
17
  name: 'beforeBuild',
21
18
  buildStart() {
22
- // target folder exists so empty
23
- // should not happen since it's required to have an empty target folder
24
- cleanBuildFolder(assetsPath);
19
+ LogMe.log('Prepare build folder');
20
+ emptyTargetPath(jPackConfig.get('targetPath'));
25
21
  },
26
22
  },
27
23
 
@@ -44,7 +40,7 @@ export default async function jPackRollup(config) {
44
40
  limit: 0,
45
41
  emitFiles: true,
46
42
  fileName: '[name][extname]',
47
- destDir: assetsPath + '/fonts/',
43
+ destDir: jPackConfig.get('targetRelativePath') + '/fonts/',
48
44
  }),
49
45
 
50
46
  url({
@@ -52,7 +48,7 @@ export default async function jPackRollup(config) {
52
48
  limit: 0,
53
49
  emitFiles: true,
54
50
  fileName: '[name][extname]',
55
- destDir: assetsPath + '/images/',
51
+ destDir: jPackConfig.get('targetRelativePath') + '/images/',
56
52
  }),
57
53
 
58
54
  json(), // Handle JSON imports
@@ -77,6 +73,9 @@ export default async function jPackRollup(config) {
77
73
  ];
78
74
  };
79
75
 
76
+ function cleanBuildFolder() {
77
+ }
78
+
80
79
  function generateBuildJs() {
81
80
  LogMe.log('Generate the build.js file ...');
82
81
 
@@ -154,13 +153,13 @@ function onPacked() {
154
153
 
155
154
  function moveCssFiles() {
156
155
  LogMe.log('Moving CSS files from js/ to css/ ...');
157
- const assetsPath = jPackConfig.get('assetsPath');
156
+ const targetPath = jPackConfig.get('targetPath');
158
157
 
159
- fs.readdirSync(assetsPath + '/js')
158
+ fs.readdirSync(jPackConfig.get('targetRelativePath') + '/js')
160
159
  .filter(file => file.endsWith('.css'))
161
160
  .forEach(file => {
162
- const oldPath = path.join(assetsPath + '/js', file);
163
- const newPath = path.join(assetsPath + '/css', file);
161
+ const oldPath = path.join(jPackConfig.get('targetRelativePath') + '/js', file);
162
+ const newPath = path.join(jPackConfig.get('targetRelativePath') + '/css', file);
164
163
  fs.mkdirSync(path.dirname(newPath), { recursive: true });
165
164
  fs.renameSync(oldPath, newPath);
166
165
  LogMe.log('- ' + file);
@@ -176,83 +175,13 @@ function cleanupBuild() {
176
175
  fs.unlinkSync(jPackConfig.get('buildJsFilePath'));
177
176
  }
178
177
 
179
- let emptyBuildFolder = false;
180
- const ignoreRemove = [];
181
-
182
- if (jPackConfig.get('buildZip')) {
183
- LogMe.log('Creating zip file ...');
184
- const zipFilePath = path.join(jPackConfig.get('assetsFullpath'), jPackConfig.get('buildName') + '.zip');
185
-
186
- execSync(`cd ${jPackConfig.get('assetsFullpath')} && zip -r ${zipFilePath} .`, { stdio: 'inherit' });
187
- LogMe.log('-> ' + zipFilePath);
188
-
189
- if (jPackConfig.get('buildTarget')) {
190
- LogMe.log('Transfer zip file ...');
191
- const zipTargetPath = path.join(jPackConfig.get('buildTarget'), jPackConfig.get('buildName') + '.zip');
192
- fs.copyFileSync(zipFilePath, zipTargetPath);
193
- LogMe.log('-> ' + zipTargetPath);
194
- }
195
-
196
- emptyBuildFolder = true;
197
- ignoreRemove.push(zipFilePath);
198
- }
199
- else if (jPackConfig.get('buildTarget') && jPackConfig.get('assetsPath') !== 'dist') {
200
- LogMe.log('Copy generated build folder ...');
201
-
202
- fs.mkdirSync(jPackConfig.get('buildTarget'), { recursive: true });
203
-
204
- // Iterate over the files and directories in jPackConfig.get('assetsPath')
205
- fs.readdirSync(jPackConfig.get('assetsPath')).forEach(file => {
206
- const sourcePath = path.join(jPackConfig.get('assetsPath'), file);
207
- const destinationPath = path.join(jPackConfig.get('buildTarget'), file);
208
-
209
- if (fs.lstatSync(sourcePath).isDirectory()) {
210
- // Recursively copy directories
211
- fs.mkdirSync(destinationPath, { recursive: true });
212
- fs.readdirSync(sourcePath).forEach(subFile => {
213
- const subSourcePath = path.join(sourcePath, subFile);
214
- const subDestinationPath = path.join(destinationPath, subFile);
215
- fs.copyFileSync(subSourcePath, subDestinationPath);
216
- LogMe.log('- Copied file: ' + subDestinationPath);
217
- });
218
- } else {
219
- // Copy files
220
- fs.copyFileSync(sourcePath, destinationPath);
221
- LogMe.log('- Copied file: ' + destinationPath);
178
+ fs.readdirSync(jPackConfig.get('targetPath')).forEach(file => {
179
+ const filePath = path.join(jPackConfig.get('targetPath'), file);
180
+ if (fs.lstatSync(filePath).isDirectory()) {
181
+ if (fs.readdirSync(filePath).length === 0) {
182
+ fs.rmdirSync(filePath);
183
+ LogMe.log('Removed empty folder: ' + filePath);
222
184
  }
223
- });
224
-
225
- emptyBuildFolder = true;
226
- }
227
-
228
- if (emptyBuildFolder) {
229
- LogMe.log('Cleaning up build folder ...');
230
-
231
- fs.readdirSync(jPackConfig.get('assetsPath')).forEach(file => {
232
- const filePath = path.join(jPackConfig.get('assetsPath'), file);
233
- if (fs.lstatSync(filePath).isDirectory()) {
234
- fs.rmSync(filePath, { recursive: true, force: true });
235
- LogMe.log('Removed folder: ' + filePath);
236
- }
237
- else {
238
- if (filePath.endsWith('.zip')) {
239
- return;
240
- }
241
-
242
- fs.unlinkSync(filePath);
243
- LogMe.log('Removed file: ' + filePath);
244
- }
245
- });
246
- }
247
- else {
248
- fs.readdirSync(jPackConfig.get('assetsPath')).forEach(file => {
249
- const filePath = path.join(jPackConfig.get('assetsPath'), file);
250
- if (fs.lstatSync(filePath).isDirectory()) {
251
- if (fs.readdirSync(filePath).length === 0) {
252
- fs.rmdirSync(filePath);
253
- LogMe.log('Removed empty folder: ' + filePath);
254
- }
255
- }
256
- });
257
- }
185
+ }
186
+ });
258
187
  }
package/lib/index.js CHANGED
@@ -3,14 +3,11 @@ import jPackCli from './Cli.js';
3
3
  import jPackConfig from './Config.js';
4
4
  import LogMe from './LogMe.js';
5
5
  import jPackRollup from './Rollup.js';
6
- import { removeEmptyDirs, cleanBuildFolder } from './utils.js';
7
6
 
8
7
  export {
9
8
  jPackBuild,
10
9
  jPackCli,
11
10
  jPackConfig,
12
11
  LogMe,
13
- jPackRollup,
14
- removeEmptyDirs,
15
- cleanBuildFolder
12
+ jPackRollup
16
13
  }
package/lib/utils.js CHANGED
@@ -1,43 +1,92 @@
1
1
  import fs from 'fs';
2
2
  import path from 'path';
3
- import LogMe from './LogMe.js';
4
3
 
5
- export function removeEmptyDirs(dir) {
6
- if (!fs.existsSync(dir)) return;
4
+ import LogMe from './LogMe.js';
7
5
 
8
- const files = fs.readdirSync(dir);
9
- for (const file of files) {
10
- const fullPath = path.join(dir, file);
11
- if (fs.lstatSync(fullPath).isDirectory()) {
12
- removeEmptyDirs(fullPath);
6
+ export function emptyTargetPath(targetPath, removeEmpty = false) {
7
+ if (!fs.existsSync(targetPath)) {
8
+ if (removeEmpty) {
9
+ return;
13
10
  }
11
+ fs.mkdirSync(targetPath, { recursive: true });
14
12
  }
15
13
 
16
- // After removing subdirs, check if current dir is empty
17
- if (fs.readdirSync(dir).length === 0) {
18
- fs.rmdirSync(dir);
14
+ if (!fs.lstatSync(targetPath).isDirectory()) {
15
+ throw new Error(`Target path is not a directory`);
19
16
  }
20
- };
21
17
 
22
- export function cleanBuildFolder(buildPath) {
23
- LogMe.log('cleanBuildFolder()');
24
-
25
- if (fs.existsSync(buildPath)) {
26
- LogMe.log(' Cleanup');
27
- fs.readdirSync(buildPath).forEach(file => {
28
- if (file !== 'config.json') {
29
- const filePath = path.join(buildPath, file);
30
- if (fs.lstatSync(filePath).isDirectory()) {
31
- fs.rmSync(filePath, { recursive: true, force: true });
32
- LogMe.log(' - [RM] ' + filePath);
33
- } else {
34
- fs.unlinkSync(filePath);
35
- LogMe.log(' - [RM] ' + filePath);
18
+ let files = fs.readdirSync(targetPath);
19
+
20
+ if (files.length > 0) {
21
+ for (const file of files) {
22
+ const fullPath = path.join(targetPath, file);
23
+ if (fs.lstatSync(fullPath).isDirectory()) {
24
+ try {
25
+ emptyTargetPath(fullPath, true);
26
+ } catch (error) {
27
+ LogMe.error('Failed to empty directory: ' + fullPath);
28
+ LogMe.error(error.message);
36
29
  }
37
30
  }
38
- });
39
- } else {
40
- fs.mkdirSync(buildPath, { recursive: true });
41
- LogMe.log(' Created target directory');
31
+ else {
32
+ fs.unlinkSync(fullPath);
33
+ LogMe.log(' [RM] ' + fullPath);
34
+ }
35
+ }
36
+
37
+ files = fs.readdirSync(targetPath);
38
+ }
39
+
40
+ if (files.length === 0) {
41
+ if (removeEmpty) {
42
+ LogMe.log(' [RM] ' + targetPath);
43
+ fs.rmdirSync(targetPath);
44
+ }
45
+ }
46
+ };
47
+
48
+ export function loadJson(filePath) {
49
+ try {
50
+ if (!fs.existsSync(filePath)) {
51
+ throw new Error('File not found');
52
+ }
53
+
54
+ const data = fs.readFileSync(filePath, 'utf8');
55
+ const json = JSON.parse(data);
56
+ return json;
57
+
58
+ } catch (error) {
59
+ throw new Error(`Failed to load JSON file: ${filePath}\n${error.message}`);
60
+ }
61
+ };
62
+
63
+ export function loadJsonConfigs(...configs) {
64
+ const loadedConfigs = [];
65
+ for (const configPath of configs) {
66
+ if (!fs.existsSync(configPath)) {
67
+ continue;
68
+ }
69
+ loadedConfigs.push(loadJson(configPath));
70
+ }
71
+ let mergedConfig = {};
72
+ for (const conf of loadedConfigs) {
73
+ mergedConfig = deepMerge(mergedConfig, conf);
74
+ }
75
+ return mergedConfig;
76
+ };
77
+
78
+ function isObject(item) {
79
+ return (item && typeof item === 'object' && !Array.isArray(item));
80
+ }
81
+
82
+ function deepMerge(target, source) {
83
+ for (const key in source) {
84
+ if (isObject(source[key])) {
85
+ if (!target[key]) Object.assign(target, { [key]: {} });
86
+ deepMerge(target[key], source[key]);
87
+ } else {
88
+ target[key] = source[key];
89
+ }
42
90
  }
43
- };
91
+ return target;
92
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "jizy-packer",
3
- "version": "2.0.6",
3
+ "version": "2.1.1",
4
4
  "type": "module",
5
5
  "files": [
6
6
  "lib/*.js"