@genexus/mercury 0.19.2 → 0.21.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.
Files changed (132) hide show
  1. package/dist/assets/MERCURY_ASSETS.d.ts +28 -0
  2. package/dist/assets/MERCURY_ASSETS.js +1 -1
  3. package/dist/assets/MERCURY_ASSETS.ts +23130 -23102
  4. package/dist/assets/icons/patterns-default-associated/dark/default-associated-modified.svg +16 -0
  5. package/dist/assets/icons/patterns-default-associated/dark/default-associated-synchronized.svg +16 -0
  6. package/dist/assets/icons/patterns-default-associated/light/default-associated-modified.svg +16 -0
  7. package/dist/assets/icons/patterns-default-associated/light/default-associated-synchronized.svg +16 -0
  8. package/dist/bundles/css/all.css +1 -1
  9. package/dist/bundles/css/base/base-globant.css +1 -1
  10. package/dist/bundles/css/base/base.css +1 -1
  11. package/dist/bundles/css/base/icons.css +1 -1
  12. package/dist/bundles/css/components/accordion.css +1 -1
  13. package/dist/bundles/css/components/button.css +1 -1
  14. package/dist/bundles/css/components/chat.css +1 -1
  15. package/dist/bundles/css/components/code.css +1 -1
  16. package/dist/bundles/css/components/combo-box.css +1 -1
  17. package/dist/bundles/css/components/dialog.css +1 -1
  18. package/dist/bundles/css/components/dropdown.css +1 -1
  19. package/dist/bundles/css/components/edit.css +1 -1
  20. package/dist/bundles/css/components/flexible-layout.css +1 -1
  21. package/dist/bundles/css/components/icon.css +1 -1
  22. package/dist/bundles/css/components/list-box.css +1 -1
  23. package/dist/bundles/css/components/markdown-viewer.css +1 -1
  24. package/dist/bundles/css/components/navigation-list.css +1 -1
  25. package/dist/bundles/css/components/pills.css +1 -1
  26. package/dist/bundles/css/components/segmented-control.css +1 -1
  27. package/dist/bundles/css/components/slider.css +1 -1
  28. package/dist/bundles/css/components/switch.css +1 -1
  29. package/dist/bundles/css/components/tab.css +1 -1
  30. package/dist/bundles/css/components/tabular-grid.css +1 -1
  31. package/dist/bundles/css/components/tooltip.css +1 -1
  32. package/dist/bundles/css/utils/form--full.css +1 -1
  33. package/dist/bundles/css/utils/form.css +1 -1
  34. package/dist/bundles/css/utils/spacing.css +1 -1
  35. package/dist/cli/bundle.js +185 -17
  36. package/dist/cli/internal/constants.d.ts +3 -12
  37. package/dist/cli/internal/constants.js +4 -13
  38. package/dist/cli/internal/create-bundles-with-custom-paths.d.ts +10 -2
  39. package/dist/cli/internal/create-bundles-with-custom-paths.js +102 -55
  40. package/dist/cli/internal/file-management.d.ts +3 -2
  41. package/dist/cli/internal/file-management.js +45 -12
  42. package/dist/cli/internal/print-utils.d.ts +6 -6
  43. package/dist/cli/internal/print-utils.js +14 -12
  44. package/dist/cli/internal/transpile-bundle-and-create-mappings.d.ts +2 -3
  45. package/dist/cli/internal/transpile-bundle-and-create-mappings.js +37 -66
  46. package/dist/cli/internal/types.d.ts +0 -1
  47. package/dist/cli/internal/utils.d.ts +11 -8
  48. package/dist/cli/internal/utils.js +27 -22
  49. package/dist/cli/internal/validate-args.js +7 -1
  50. package/dist/cli/internal/watch-fs.d.ts +3 -0
  51. package/dist/cli/internal/watch-fs.js +92 -0
  52. package/dist/cli/mercury.js +2 -2
  53. package/package.json +17 -12
  54. package/dist/bundles/js/all.js +0 -1
  55. package/dist/bundles/js/base/base-globant.js +0 -1
  56. package/dist/bundles/js/base/base.js +0 -1
  57. package/dist/bundles/js/base/icons.js +0 -1
  58. package/dist/bundles/js/bundle-mappings.js +0 -237
  59. package/dist/bundles/js/chameleon/scrollbar.js +0 -1
  60. package/dist/bundles/js/components/accordion.js +0 -1
  61. package/dist/bundles/js/components/button.js +0 -1
  62. package/dist/bundles/js/components/chat.js +0 -1
  63. package/dist/bundles/js/components/checkbox.js +0 -1
  64. package/dist/bundles/js/components/code.js +0 -1
  65. package/dist/bundles/js/components/combo-box.js +0 -1
  66. package/dist/bundles/js/components/dialog.js +0 -1
  67. package/dist/bundles/js/components/dropdown.js +0 -1
  68. package/dist/bundles/js/components/edit.js +0 -1
  69. package/dist/bundles/js/components/flexible-layout.js +0 -1
  70. package/dist/bundles/js/components/icon.js +0 -1
  71. package/dist/bundles/js/components/layout-splitter.js +0 -1
  72. package/dist/bundles/js/components/list-box.js +0 -1
  73. package/dist/bundles/js/components/markdown-viewer.js +0 -1
  74. package/dist/bundles/js/components/navigation-list.js +0 -1
  75. package/dist/bundles/js/components/pills.js +0 -1
  76. package/dist/bundles/js/components/radio-group.js +0 -1
  77. package/dist/bundles/js/components/segmented-control.js +0 -1
  78. package/dist/bundles/js/components/sidebar.js +0 -1
  79. package/dist/bundles/js/components/slider.js +0 -1
  80. package/dist/bundles/js/components/switch.js +0 -1
  81. package/dist/bundles/js/components/tab.js +0 -1
  82. package/dist/bundles/js/components/tabular-grid.js +0 -1
  83. package/dist/bundles/js/components/ticket-list.js +0 -1
  84. package/dist/bundles/js/components/tooltip.js +0 -1
  85. package/dist/bundles/js/components/tree-view.js +0 -1
  86. package/dist/bundles/js/components/widget.js +0 -1
  87. package/dist/bundles/js/resets/box-sizing.js +0 -1
  88. package/dist/bundles/js/utils/elevation.js +0 -1
  89. package/dist/bundles/js/utils/form--full.js +0 -1
  90. package/dist/bundles/js/utils/form.js +0 -1
  91. package/dist/bundles/js/utils/layout.js +0 -1
  92. package/dist/bundles/js/utils/spacing.js +0 -1
  93. package/dist/bundles/js/utils/typography.js +0 -1
  94. package/dist/bundles/scss/all.scss +0 -8
  95. package/dist/bundles/scss/base/base.scss +0 -24
  96. package/dist/bundles/scss/base/icons.scss +0 -4
  97. package/dist/bundles/scss/chameleon/scrollbar.scss +0 -3
  98. package/dist/bundles/scss/components/accordion.scss +0 -3
  99. package/dist/bundles/scss/components/button.scss +0 -8
  100. package/dist/bundles/scss/components/chat.scss +0 -3
  101. package/dist/bundles/scss/components/checkbox.scss +0 -3
  102. package/dist/bundles/scss/components/code.scss +0 -3
  103. package/dist/bundles/scss/components/combo-box.scss +0 -3
  104. package/dist/bundles/scss/components/dialog.scss +0 -3
  105. package/dist/bundles/scss/components/dropdown.scss +0 -3
  106. package/dist/bundles/scss/components/edit.scss +0 -3
  107. package/dist/bundles/scss/components/flexible-layout.scss +0 -3
  108. package/dist/bundles/scss/components/icon.scss +0 -8
  109. package/dist/bundles/scss/components/layout-splitter.scss +0 -3
  110. package/dist/bundles/scss/components/list-box.scss +0 -3
  111. package/dist/bundles/scss/components/markdown-viewer.scss +0 -3
  112. package/dist/bundles/scss/components/navigation-list.scss +0 -3
  113. package/dist/bundles/scss/components/pills.scss +0 -3
  114. package/dist/bundles/scss/components/radio-group.scss +0 -3
  115. package/dist/bundles/scss/components/segmented-control.scss +0 -3
  116. package/dist/bundles/scss/components/sidebar.scss +0 -3
  117. package/dist/bundles/scss/components/slider.scss +0 -3
  118. package/dist/bundles/scss/components/switch.scss +0 -3
  119. package/dist/bundles/scss/components/tab.scss +0 -3
  120. package/dist/bundles/scss/components/tabular-grid.scss +0 -10
  121. package/dist/bundles/scss/components/ticket-list.scss +0 -3
  122. package/dist/bundles/scss/components/tooltip.scss +0 -3
  123. package/dist/bundles/scss/components/tree-view.scss +0 -3
  124. package/dist/bundles/scss/components/widget.scss +0 -3
  125. package/dist/bundles/scss/resets/box-sizing.scss +0 -3
  126. package/dist/bundles/scss/utils/elevation.scss +0 -4
  127. package/dist/bundles/scss/utils/form--full.scss +0 -20
  128. package/dist/bundles/scss/utils/form.scss +0 -4
  129. package/dist/bundles/scss/utils/layout.scss +0 -4
  130. package/dist/bundles/scss/utils/spacing.scss +0 -4
  131. package/dist/bundles/scss/utils/typography.scss +0 -9
  132. package/dist/mercury.scss +0 -24789
@@ -1,20 +1,188 @@
1
1
  #!/usr/bin/env node
2
- import { ensureDirectoryExistsAndItsClear, walkSync, copyDirectories } from "./internal/file-management.js";
3
- import { BASE_BUNDLES_OUT_DIR, SCSS_BUNDLES_INPUT_DIR, SCSS_BUNDLES_OUT_DIR } from "./internal/constants.js";
4
- import { createBundleMappingsFile, transpileCssBundleWithPlaceholder } from "./internal/transpile-bundle-and-create-mappings.js";
2
+ import fs from "node:fs/promises";
3
+ import path from "node:path";
4
+ import os from "node:os";
5
+ import { fileURLToPath } from "node:url";
6
+ import { Worker, isMainThread, parentPort } from "worker_threads";
7
+ import { ensureDirectoryExistsAndItsClear, getFilesInDir, refreshAngularBrowser
8
+ // copyDirectories
9
+ } from "./internal/file-management.js";
10
+ import { BASE_BUNDLES_OUT_DIR, CSS_BUNDLES_OUT_DIR, SCSS_BUNDLES_INPUT_DIR
11
+ // SCSS_BUNDLES_OUT_DIR
12
+ } from "./internal/constants.js";
13
+ import { transpileCssBundleWithPlaceholder } from "./internal/transpile-bundle-and-create-mappings.js";
5
14
  import { measureTime } from "./internal/utils.js";
6
- measureTime(() => {
7
- // Improve process visualization
8
- console.log("");
9
- // Clear bundle directories
10
- ensureDirectoryExistsAndItsClear(BASE_BUNDLES_OUT_DIR);
11
- // Copy the src/bundles/scss content to the dist/bundles/scss and create the
12
- // bundles
13
- copyDirectories(SCSS_BUNDLES_INPUT_DIR, SCSS_BUNDLES_OUT_DIR);
14
- // Transpile scss bundles into .css and .js files
15
- for (const fileMetadata of walkSync(SCSS_BUNDLES_OUT_DIR)) {
16
- transpileCssBundleWithPlaceholder(fileMetadata);
15
+ import { printBundleWasTranspiled } from "./internal/print-utils.js";
16
+ import { printRebuilding, stopRebuildingStdout, watchFileSystemChanges } from "./internal/watch-fs.js";
17
+ import { getArguments } from "./internal/validate-args.js";
18
+ import { createBundlesWithCustomPaths } from "./internal/create-bundles-with-custom-paths.js";
19
+ const MESSAGE_TYPE = {
20
+ SUCCESS: "Success",
21
+ ERROR: "Error"
22
+ };
23
+ if (isMainThread) {
24
+ const [, , ...args] = process.argv;
25
+ const watchMode = args.find(arg => arg === "--watch");
26
+ let cliArgs;
27
+ // Check if the bundles processing is running in watch mode
28
+ if (watchMode) {
29
+ cliArgs = getArguments();
30
+ if (!cliArgs) {
31
+ process.exit();
32
+ }
17
33
  }
18
- // Import all .js files into a single file (defined in `BUNDLE_MAPPING_FILE` var)
19
- createBundleMappingsFile();
20
- });
34
+ // This is a WA to have __filename and __dirname in ES modules
35
+ const __filename = fileURLToPath(import.meta.url);
36
+ const THREADS = Math.min(8, os.cpus().length / 2);
37
+ const workers = [];
38
+ /**
39
+ * Files to transpile
40
+ */
41
+ let allFilesToProcess = [];
42
+ let firstBuild = true;
43
+ // - - - - - - - - - - - - Sets to implement cache - - - - - - - - - - - -
44
+ const BUNDLES_TO_AVOID_REBUILD = [
45
+ "all",
46
+ "base/icons",
47
+ "resets/box-sizing",
48
+ "utils/form--full"
49
+ ];
50
+ const CSS_FILES_TO_AVOID_REMOVE = new Set(BUNDLES_TO_AVOID_REBUILD.map(bundleName => path.join(CSS_BUNDLES_OUT_DIR, bundleName + ".css")));
51
+ const SCSS_FILES_TO_AVOID_TRANSPILE = new Set(BUNDLES_TO_AVOID_REBUILD.map(bundleName => path.join(SCSS_BUNDLES_INPUT_DIR, bundleName + ".scss")));
52
+ // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
53
+ const createWorkers = () => {
54
+ for (let index = 0; index < THREADS; index++) {
55
+ const worker = new Worker(__filename);
56
+ workers.push(worker);
57
+ }
58
+ };
59
+ const ensureAllDirectoryExists = (filesToProcess) => {
60
+ const CSS_CREATED_DIRS = new Set();
61
+ return filesToProcess.map(async (fileMetadata) => {
62
+ const cssOutDir = fileMetadata.dir.replace(SCSS_BUNDLES_INPUT_DIR, CSS_BUNDLES_OUT_DIR);
63
+ // Create the file directory if it does not exists
64
+ if (CSS_CREATED_DIRS.has(cssOutDir)) {
65
+ return Promise.resolve();
66
+ }
67
+ else {
68
+ CSS_CREATED_DIRS.add(cssOutDir);
69
+ return fs.mkdir(cssOutDir, { recursive: true });
70
+ }
71
+ });
72
+ };
73
+ const compileBundles = async (options) => {
74
+ let completedProcessingIndex = 0;
75
+ // First build where the directory has to be discovered
76
+ if (firstBuild) {
77
+ allFilesToProcess = await getFilesInDir(SCSS_BUNDLES_INPUT_DIR);
78
+ createWorkers();
79
+ }
80
+ const ACTUAL_FILES_TO_PROCESS = structuredClone(allFilesToProcess).filter(fileMetadata => !options ||
81
+ !options.scssFilesToAvoidTranspile.has(fileMetadata.filePath));
82
+ const TOTAL_FILES = ACTUAL_FILES_TO_PROCESS.length;
83
+ // Clear bundle directories
84
+ await ensureDirectoryExistsAndItsClear(BASE_BUNDLES_OUT_DIR, options?.cssFilesToAvoidRemove);
85
+ // Ensure all directories exists before transpiling any bundle
86
+ await Promise.all(ensureAllDirectoryExists(ACTUAL_FILES_TO_PROCESS));
87
+ let workersProcessingMetadata = 0;
88
+ let thereWasAnError = false;
89
+ const sendFileMetadataToWorker = (worker, fileMetadata) => {
90
+ worker.postMessage({ fileMetadata, cliArgs }); // Send the data to process the file
91
+ workersProcessingMetadata++;
92
+ };
93
+ const updateFileProcessingStatus = () => {
94
+ completedProcessingIndex++;
95
+ workersProcessingMetadata--;
96
+ };
97
+ return new Promise((resolve, reject) => workers.forEach(worker => {
98
+ let fileMetadata = ACTUAL_FILES_TO_PROCESS.pop();
99
+ sendFileMetadataToWorker(worker, fileMetadata);
100
+ // When the worker completes the processing, increase the index and
101
+ // check if there is work remaining to process in the thread
102
+ worker.on("message", message => {
103
+ updateFileProcessingStatus();
104
+ if (message === MESSAGE_TYPE.ERROR) {
105
+ thereWasAnError = true;
106
+ }
107
+ // Stop all workers when there is an error
108
+ if (thereWasAnError) {
109
+ worker.removeAllListeners("message");
110
+ if (workersProcessingMetadata === 0) {
111
+ reject();
112
+ }
113
+ return;
114
+ }
115
+ if (!watchMode) {
116
+ printBundleWasTranspiled(fileMetadata.filePath);
117
+ }
118
+ // All metadatas were processed. Resolve the Promise
119
+ if (completedProcessingIndex === TOTAL_FILES) {
120
+ worker.removeAllListeners("message");
121
+ resolve(ACTUAL_FILES_TO_PROCESS);
122
+ }
123
+ // There is more metadata to be processed, add a new processing in
124
+ // the thread
125
+ else if (ACTUAL_FILES_TO_PROCESS.length > 0) {
126
+ fileMetadata = ACTUAL_FILES_TO_PROCESS.pop();
127
+ sendFileMetadataToWorker(worker, fileMetadata);
128
+ }
129
+ // Waiting for the last compilation to end. There is nothing to do,
130
+ // so we need to remove the listeners to ensure the following
131
+ // processing uses the workers in a "fresh" state
132
+ else {
133
+ worker.removeAllListeners("message");
134
+ }
135
+ });
136
+ }));
137
+ };
138
+ const compileAndCreateBundles = async () => {
139
+ printRebuilding(firstBuild);
140
+ try {
141
+ // Compile all CSSs into the standard output (dist/bundles/css)
142
+ await compileBundles(firstBuild
143
+ ? undefined
144
+ : {
145
+ cssFilesToAvoidRemove: CSS_FILES_TO_AVOID_REMOVE,
146
+ scssFilesToAvoidTranspile: SCSS_FILES_TO_AVOID_TRANSPILE
147
+ });
148
+ // Clear the CLI dir output target
149
+ await ensureDirectoryExistsAndItsClear(cliArgs.outDirPath);
150
+ // Remove "Rebuilding..." message, since the next function will print
151
+ // some output in the console
152
+ stopRebuildingStdout();
153
+ // Copy the files from the standard output (dist/bundles/css) to the CLI
154
+ // output by applying the transformations for the icons and custom fonts
155
+ // paths.
156
+ //
157
+ // Last true value meaning: Don't hash the bundles in watch mode to avoid
158
+ // issues with Angular that caches the bundle mapping file, causing to
159
+ // not update the hashes for the fetches
160
+ await createBundlesWithCustomPaths(cliArgs, true);
161
+ refreshAngularBrowser();
162
+ firstBuild = false;
163
+ }
164
+ catch (err) {
165
+ stopRebuildingStdout();
166
+ if (err) {
167
+ console.log(err);
168
+ }
169
+ }
170
+ };
171
+ if (watchMode) {
172
+ measureTime(compileAndCreateBundles).finally(() => watchFileSystemChanges(compileAndCreateBundles));
173
+ }
174
+ // There is no need to wait for any changes, since the watch mode is not enabled
175
+ else {
176
+ await measureTime(compileBundles);
177
+ process.exit();
178
+ }
179
+ }
180
+ // Worker thread code
181
+ else {
182
+ parentPort.on("message", (data) => transpileCssBundleWithPlaceholder(data.fileMetadata, data.cliArgs)
183
+ .then(() => parentPort.postMessage(MESSAGE_TYPE.SUCCESS))
184
+ .catch(err => {
185
+ console.error(err);
186
+ parentPort.postMessage(MESSAGE_TYPE.ERROR);
187
+ }));
188
+ }
@@ -3,17 +3,11 @@ export declare const SCSS_BUNDLES_INPUT_DIR: string;
3
3
  export declare const BASE_BUNDLES_OUT_DIR: string;
4
4
  export declare const SCSS_BUNDLES_OUT_DIR: string;
5
5
  export declare const CSS_BUNDLES_OUT_DIR: string;
6
- export declare const JS_BUNDLES_OUT_DIR: string;
7
6
  export declare const BASE_BUNDLE = "base/base";
8
- export declare const BASE_BUNDLE_WITH_BACK_SLASH = "\\base\\base";
9
7
  export declare const BASE_GLOBANT_BUNDLE = "base/base-globant";
10
- export declare const BUNDLE_MAPPING_FILE = "bundle-mappings.js";
11
8
  export declare const BUNDLE_MAPPING_TO_HASH_FILE = "bundle-to-hash-mappings.ts";
12
- export declare const BASE_SCSS_FILE = "base.scss";
13
- export declare const BASE_GLOBANT_FILE = "base-globant";
9
+ export declare const BASE_CSS_FILE = "base.css";
14
10
  export declare const BASE_GLOBANT_CSS_FILE = "base-globant.css";
15
- export declare const BASE_GLOBANT_JS_FILE = "base-globant.js";
16
- export declare const BASE_GLOBANT_SCSS_FILE = "base-globant.scss";
17
11
  export declare const ICONS_PATH_PLACEHOLDER = "{{ICONS_PATH}}";
18
12
  export declare const FONT_FACE_PATH_PLACEHOLDER = "{{FONT_FACE_PATH}}";
19
13
  export declare const DEFAULT_FONT_FACE_PATH = "./assets/fonts/";
@@ -21,8 +15,5 @@ export declare const DEFAULT_ICONS_PATH = "./assets/icons/";
21
15
  export declare const DEFAULT_OUT_DIR_PATH = "./.mercury";
22
16
  export declare const SEPARATE_BY_COMMA_REGEX: RegExp;
23
17
  export declare const SPECIAL_CHARS_IN_BUNDLE_NAME_REGEX: RegExp;
24
- export declare const BUNDLE_MAPPING_ENTRIES: {
25
- readonly BUNDLE_NAME: "bundleName";
26
- readonly FILE_DIR: "fileDir";
27
- readonly TRANSPILED_BUNDLE: "transpiledBundle";
28
- };
18
+ export declare const HASH_LENGTH = 16;
19
+ export declare const HASH_AND_LETTER_LENGTH: number;
@@ -1,21 +1,16 @@
1
1
  import path from "node:path";
2
+ // import type { BundleAssociationMetadata } from "./types";
2
3
  export const KB = 1000;
3
4
  export const SCSS_BUNDLES_INPUT_DIR = path.join("src", "bundles", "scss");
4
5
  export const BASE_BUNDLES_OUT_DIR = path.join("dist", "bundles");
5
6
  export const SCSS_BUNDLES_OUT_DIR = path.join(BASE_BUNDLES_OUT_DIR, "scss");
6
7
  export const CSS_BUNDLES_OUT_DIR = path.join(BASE_BUNDLES_OUT_DIR, "css");
7
- export const JS_BUNDLES_OUT_DIR = path.join(BASE_BUNDLES_OUT_DIR, "js");
8
8
  export const BASE_BUNDLE = "base/base";
9
- export const BASE_BUNDLE_WITH_BACK_SLASH = "\\base\\base";
10
9
  export const BASE_GLOBANT_BUNDLE = "base/base-globant";
11
10
  // Files
12
- export const BUNDLE_MAPPING_FILE = "bundle-mappings.js";
13
11
  export const BUNDLE_MAPPING_TO_HASH_FILE = "bundle-to-hash-mappings.ts";
14
- export const BASE_SCSS_FILE = "base.scss";
15
- export const BASE_GLOBANT_FILE = "base-globant";
12
+ export const BASE_CSS_FILE = "base.css";
16
13
  export const BASE_GLOBANT_CSS_FILE = "base-globant.css";
17
- export const BASE_GLOBANT_JS_FILE = "base-globant.js";
18
- export const BASE_GLOBANT_SCSS_FILE = "base-globant.scss";
19
14
  // Placeholders
20
15
  export const ICONS_PATH_PLACEHOLDER = "{{ICONS_PATH}}";
21
16
  export const FONT_FACE_PATH_PLACEHOLDER = "{{FONT_FACE_PATH}}";
@@ -25,9 +20,5 @@ export const DEFAULT_ICONS_PATH = "./assets/icons/";
25
20
  export const DEFAULT_OUT_DIR_PATH = "./.mercury";
26
21
  export const SEPARATE_BY_COMMA_REGEX = /\s*,\s*/g;
27
22
  export const SPECIAL_CHARS_IN_BUNDLE_NAME_REGEX = /[\/-]/g;
28
- // Bundle mapping entries
29
- export const BUNDLE_MAPPING_ENTRIES = {
30
- BUNDLE_NAME: "bundleName",
31
- FILE_DIR: "fileDir",
32
- TRANSPILED_BUNDLE: "transpiledBundle"
33
- };
23
+ export const HASH_LENGTH = 16;
24
+ export const HASH_AND_LETTER_LENGTH = HASH_LENGTH + 1;
@@ -1,2 +1,10 @@
1
- import type { CLIArguments } from "./types";
2
- export declare const createBundlesWithCustomPaths: (args: CLIArguments) => void;
1
+ import type { CLIArguments, FileMetadata } from "./types";
2
+ export declare const createBundleWithCustomPath: (args: CLIArguments, options: {
3
+ bundleFolder: string;
4
+ fileBaseDirToWrite: string;
5
+ }, fileMetadata: FileMetadata, avoidAllHashes: boolean, actualFilePath: string) => {
6
+ bundleName: string;
7
+ bundleNameWithHash: string;
8
+ fileSize: string;
9
+ };
10
+ export declare const createBundlesWithCustomPaths: (args: CLIArguments, avoidAllHashes?: boolean) => Promise<void>;
@@ -1,67 +1,114 @@
1
1
  import fs from "node:fs";
2
2
  import path from "node:path";
3
- // @ts-expect-error: This file does exists after the bundle transpilation process
4
- import { bundleMappings } from "../../bundles/js/bundle-mappings.js";
5
- import { BASE_BUNDLE, BASE_GLOBANT_BUNDLE, BUNDLE_MAPPING_TO_HASH_FILE } from "./constants.js";
6
- import { getBundleNameWithHash, getHash, replacePlaceholdersInBundle } from "./utils.js";
7
- import { printBundleToHashMappingsWasCreated, printBundleWasCreated } from "./print-utils.js";
8
- const findLargestPath = () => {
9
- let largestBundleLength = 0;
10
- bundleMappings.forEach(entry => {
11
- largestBundleLength = Math.max(largestBundleLength, entry.bundleName.length);
3
+ import { fileURLToPath } from "node:url";
4
+ import { BASE_BUNDLE, BASE_CSS_FILE, BASE_GLOBANT_BUNDLE, BASE_GLOBANT_CSS_FILE, BUNDLE_MAPPING_TO_HASH_FILE, DEFAULT_FONT_FACE_PATH, DEFAULT_ICONS_PATH, HASH_AND_LETTER_LENGTH } from "./constants.js";
5
+ import { getFilesInDir } from "./file-management.js";
6
+ import { getBundleFolderAndFileBaseDir, getBundleName, getFileNameWithHash, getFileNameWithoutExt, getFileSize, getHash, sanitizeBundleName } from "./utils.js";
7
+ import { printBundleWasCreated, printBundleWasCreatedTableHeader } from "./print-utils.js";
8
+ export const createBundleWithCustomPath = (args, options, fileMetadata, avoidAllHashes, actualFilePath) => {
9
+ const { avoidHash, fontFacePath, iconsPath } = args;
10
+ const { bundleFolder, fileBaseDirToWrite } = options;
11
+ const fileNameWithoutExt = getFileNameWithoutExt(fileMetadata);
12
+ const bundleName = getBundleName(fileMetadata);
13
+ // Copy CSS bundle
14
+ let css = fs.readFileSync(actualFilePath ?? fileMetadata.filePath, {
15
+ encoding: "utf8"
12
16
  });
13
- return largestBundleLength;
17
+ if (fontFacePath !== DEFAULT_FONT_FACE_PATH) {
18
+ css = css.replaceAll(DEFAULT_FONT_FACE_PATH, fontFacePath);
19
+ }
20
+ if (iconsPath !== DEFAULT_ICONS_PATH) {
21
+ css = css.replaceAll(DEFAULT_ICONS_PATH, iconsPath);
22
+ }
23
+ const fileNameWithHash = avoidAllHashes || avoidHash.has(bundleName)
24
+ ? fileNameWithoutExt
25
+ : getFileNameWithHash(fileNameWithoutExt, getHash(css));
26
+ const fileNameToWriteCss = `${fileNameWithHash}.css`;
27
+ const filePathWithHash = path.join(fileBaseDirToWrite, fileNameToWriteCss);
28
+ // Create the CSS bundle with hash
29
+ fs.writeFileSync(filePathWithHash, css);
30
+ return {
31
+ bundleName,
32
+ bundleNameWithHash: sanitizeBundleName(`${bundleFolder}/${fileNameWithHash}`),
33
+ fileSize: getFileSize(css)
34
+ };
14
35
  };
15
- const getActualBundleName = (bundleName) => bundleName === BASE_BUNDLE || bundleName === BASE_GLOBANT_BUNDLE
16
- ? BASE_BUNDLE
17
- : bundleName;
18
- const shouldSkipBundleCreation = (bundleName, globant) => (bundleName === BASE_BUNDLE && globant) ||
19
- (bundleName === BASE_GLOBANT_BUNDLE && !globant);
20
- export const createBundlesWithCustomPaths = (args) => {
21
- const { avoidHash, fontFacePath, iconsPath, globant } = args;
36
+ export const createBundlesWithCustomPaths = async (args, avoidAllHashes = false) => {
37
+ const hasGlobantVariant = args.globant;
22
38
  const outDir = path.join(args.outDirPath);
23
39
  const CREATED_DIRS = new Set();
24
- const largestBundleLength = findLargestPath();
25
- let bundleMappingToHashObjectEntries = "";
26
- bundleMappings.forEach(entry => {
27
- const { bundleName, fileDir, transpiledBundle } = entry;
28
- if (shouldSkipBundleCreation(bundleName, globant)) {
29
- return;
40
+ // This is a WA to have __filename and __dirname in ES modules
41
+ const __filename = fileURLToPath(import.meta.url);
42
+ // Directory name where the script is located (<path from root to node_modules/@genexus/mercury>/dist/cli/)
43
+ const __dirname = path.dirname(__filename);
44
+ const cssOutput = path.join(__dirname, "../../bundles/css");
45
+ /**
46
+ * Files to transpile
47
+ */
48
+ const allFilesToCopy = await getFilesInDir(cssOutput);
49
+ let largestBundleLength = BUNDLE_MAPPING_TO_HASH_FILE.length;
50
+ let largestFileSizeLength = 0;
51
+ allFilesToCopy.forEach(fileMetadata => {
52
+ const options = getBundleFolderAndFileBaseDir(fileMetadata, outDir);
53
+ largestBundleLength = Math.max(largestBundleLength, options.bundleFolder.length + fileMetadata.fileName.length);
54
+ });
55
+ if (!avoidAllHashes) {
56
+ largestBundleLength += HASH_AND_LETTER_LENGTH;
57
+ }
58
+ const copiedFiles = [];
59
+ allFilesToCopy.forEach(fileMetadata => {
60
+ const bundleName = getBundleName(fileMetadata);
61
+ const options = getBundleFolderAndFileBaseDir(fileMetadata, outDir);
62
+ const { fileBaseDirToWrite } = options;
63
+ let actualFilePath = fileMetadata.filePath;
64
+ if (!CREATED_DIRS.has(fileBaseDirToWrite)) {
65
+ CREATED_DIRS.add(fileBaseDirToWrite);
66
+ fs.mkdirSync(path.join(fileBaseDirToWrite), { recursive: true });
30
67
  }
31
- const actualBundleName = getActualBundleName(bundleName);
32
- const compiledBundleWithoutPlaceholders = replacePlaceholdersInBundle(transpiledBundle, fontFacePath, iconsPath);
33
- const hash = getHash(compiledBundleWithoutPlaceholders);
34
- if (fileDir && !CREATED_DIRS.has(fileDir)) {
35
- fs.mkdirSync(path.join(outDir, fileDir), { recursive: true });
36
- CREATED_DIRS.add(fileDir);
68
+ // There is no need to copy the base-globant.css file, since the base.css
69
+ // file already contains this file
70
+ if (hasGlobantVariant) {
71
+ if (bundleName === BASE_GLOBANT_BUNDLE) {
72
+ return;
73
+ }
74
+ // Replace the content of the base bundle with the Globant variant
75
+ if (bundleName === BASE_BUNDLE) {
76
+ actualFilePath = actualFilePath.replace(BASE_CSS_FILE, BASE_GLOBANT_CSS_FILE);
77
+ }
37
78
  }
38
- const bundleNameWithHash = avoidHash.has(actualBundleName)
39
- ? actualBundleName
40
- : getBundleNameWithHash(actualBundleName, hash);
41
- const filePathToCreateBundle = path.join(outDir, `${bundleNameWithHash}.css`);
42
- fs.writeFileSync(filePathToCreateBundle, compiledBundleWithoutPlaceholders);
43
- printBundleWasCreated({
44
- outDir,
45
- bundleName: actualBundleName,
46
- compiledBundleWithoutPlaceholders,
47
- filePathToCreateBundle,
48
- // WA to improve style
49
- largestBundleLength: largestBundleLength + (avoidHash.has(actualBundleName) ? 17 : 0)
50
- });
51
- // Store the bundle mapping.
52
- // For example: "components/button" --> "components/button-9f82641938b85445"
53
- const bundleToHashEntry = ` "${actualBundleName}": "${bundleNameWithHash}"`;
54
- // Concat entries in the object
55
- bundleMappingToHashObjectEntries +=
56
- bundleMappingToHashObjectEntries === ""
57
- ? bundleToHashEntry
58
- : ",\n" + bundleToHashEntry;
79
+ copiedFiles.push(createBundleWithCustomPath(args, options, fileMetadata, avoidAllHashes, actualFilePath));
59
80
  });
60
- bundleMappingToHashObjectEntries = `export const bundleToHashMappings = {\n${bundleMappingToHashObjectEntries}\n} as const;\n`;
81
+ copiedFiles.sort((a, b) => (a.bundleName <= b.bundleName ? -1 : 0));
82
+ const bundleMappingFileContent = `export const bundleToHashMappings = {\n${copiedFiles.map(entry => ` "${entry.bundleName}": "${entry.bundleNameWithHash}"`).join(",\n")}\n} as const;\n`;
83
+ const bundleMappingFileSize = getFileSize(bundleMappingFileContent);
61
84
  const bundleMappingFilePath = path.join(outDir, BUNDLE_MAPPING_TO_HASH_FILE);
62
- fs.writeFileSync(bundleMappingFilePath, bundleMappingToHashObjectEntries);
63
- printBundleToHashMappingsWasCreated({
64
- outDir,
65
- filePath: bundleMappingFilePath
85
+ // Compute the largest fileName length
86
+ largestFileSizeLength = copiedFiles.reduce((acc, copiedFile) => Math.max(acc, copiedFile.fileSize.length), bundleMappingFileSize.length);
87
+ printBundleWasCreatedTableHeader({
88
+ largestBundleLength: avoidAllHashes
89
+ ? largestBundleLength
90
+ : largestBundleLength + 1,
91
+ outDir
92
+ });
93
+ // Print bundle created message
94
+ for (let index = 0; index < copiedFiles.length; index++) {
95
+ const entry = copiedFiles[index];
96
+ printBundleWasCreated({
97
+ bundleNameWithHash: `${entry.bundleNameWithHash}.css`,
98
+ fileSize: entry.fileSize,
99
+ largestBundleLength,
100
+ largestFileSizeLength,
101
+ outDir
102
+ });
103
+ }
104
+ fs.writeFileSync(bundleMappingFilePath, bundleMappingFileContent);
105
+ // Separate the TS file
106
+ console.log("");
107
+ printBundleWasCreated({
108
+ bundleNameWithHash: BUNDLE_MAPPING_TO_HASH_FILE,
109
+ fileSize: getFileSize(bundleMappingFileContent),
110
+ largestBundleLength,
111
+ largestFileSizeLength,
112
+ outDir
66
113
  });
67
114
  };
@@ -1,4 +1,5 @@
1
1
  import type { FileMetadata } from "./types";
2
- export declare const ensureDirectoryExistsAndItsClear: (dirPath: string) => void;
3
- export declare function walkSync(dir: string): Generator<FileMetadata>;
2
+ export declare const ensureDirectoryExistsAndItsClear: (dirPath: string, filesToNotRemove?: Set<string>) => Promise<void>;
3
+ export declare const getFilesInDir: (dir: string) => Promise<FileMetadata[]>;
4
4
  export declare const copyDirectories: (srcDir: string, outDir: string) => void;
5
+ export declare const refreshAngularBrowser: () => void;
@@ -1,20 +1,53 @@
1
1
  import fs from "node:fs";
2
2
  import path from "node:path";
3
- export const ensureDirectoryExistsAndItsClear = (dirPath) => {
4
- if (fs.existsSync(dirPath)) {
3
+ import { readdir, rm } from "node:fs/promises";
4
+ export const ensureDirectoryExistsAndItsClear = async (dirPath, filesToNotRemove) => {
5
+ // First build
6
+ if (!fs.existsSync(dirPath)) {
7
+ fs.mkdirSync(dirPath, { recursive: true });
8
+ return;
9
+ }
10
+ // Incremental rebuild keeps some file without any changes, so we must skip
11
+ // the file deletion
12
+ if (filesToNotRemove) {
13
+ const filesInDir = await getFilesInDir(dirPath);
14
+ await Promise.all(filesInDir.map(file => filesToNotRemove.has(file.filePath)
15
+ ? Promise.resolve()
16
+ : rm(file.filePath)));
17
+ }
18
+ // Incremental rebuild did not include any file to exclude its removal
19
+ else {
5
20
  fs.rmSync(dirPath, { recursive: true });
21
+ fs.mkdirSync(dirPath, { recursive: true });
6
22
  }
7
- fs.mkdirSync(dirPath, { recursive: true });
8
23
  };
9
- export function* walkSync(dir) {
10
- const files = fs.readdirSync(dir, { withFileTypes: true });
11
- for (const file of files) {
12
- if (file.isDirectory()) {
13
- yield* walkSync(path.join(dir, file.name));
14
- }
15
- else {
16
- yield { dir, fileName: file.name, filePath: path.join(dir, file.name) };
24
+ export const getFilesInDir = async (dir) => {
25
+ const filesAndDirs = await readdir(dir, {
26
+ withFileTypes: true,
27
+ recursive: true
28
+ });
29
+ const files = [];
30
+ for (let index = 0; index < filesAndDirs.length; index++) {
31
+ const file = filesAndDirs[index];
32
+ if (file.isFile()) {
33
+ files.push({
34
+ dir: file.parentPath,
35
+ fileName: file.name,
36
+ filePath: path.join(file.parentPath, file.name)
37
+ });
17
38
  }
18
39
  }
19
- }
40
+ return files;
41
+ };
20
42
  export const copyDirectories = (srcDir, outDir) => fs.cpSync(srcDir, outDir, { recursive: true });
43
+ export const refreshAngularBrowser = () => {
44
+ const ANGULAR_FILE_TO_TRIGGER_RELOAD = path.join(process.cwd(), "../showcase/src/index.html");
45
+ const FILE_CONTENT = fs.readFileSync(ANGULAR_FILE_TO_TRIGGER_RELOAD, {
46
+ encoding: "utf8"
47
+ });
48
+ // Trigger a dummy write in the index.html
49
+ fs.writeFileSync(ANGULAR_FILE_TO_TRIGGER_RELOAD, FILE_CONTENT + "\n");
50
+ // Rollback that write to not provoke any changes, but do it after the
51
+ // debounce of the Angular CLI has completed the queued HMR
52
+ setTimeout(() => fs.writeFileSync(ANGULAR_FILE_TO_TRIGGER_RELOAD, FILE_CONTENT), 300);
53
+ };
@@ -1,13 +1,13 @@
1
- export declare const printBundleWasCreated: (args: {
1
+ export declare const printBundleWasCreatedTableHeader: (args: {
2
2
  outDir: string;
3
- bundleName: string;
4
3
  largestBundleLength: number;
5
- filePathToCreateBundle: string;
6
- compiledBundleWithoutPlaceholders: string;
7
4
  }) => void;
8
- export declare const printBundleToHashMappingsWasCreated: (args: {
5
+ export declare const printBundleWasCreated: (args: {
9
6
  outDir: string;
10
- filePath: string;
7
+ bundleNameWithHash: string;
8
+ largestBundleLength: number;
9
+ largestFileSizeLength: number;
10
+ fileSize: string;
11
11
  }) => void;
12
12
  export declare const printBundleWasTranspiled: (filePath: string) => void;
13
13
  export declare const printArgumentDoesNotExistsError: (arg: string) => void;
@@ -1,18 +1,20 @@
1
1
  import { styleText } from "node:util";
2
- import { getFileSize } from "./utils.js";
3
- import { DEFAULT_FONT_FACE_PATH, DEFAULT_ICONS_PATH, DEFAULT_OUT_DIR_PATH, SCSS_BUNDLES_OUT_DIR } from "./constants.js";
4
- export const printBundleWasCreated = (args) => console.log(styleText("greenBright", " Created: ") +
5
- styleText("white", args.outDir) +
6
- styleText("whiteBright", args.filePathToCreateBundle.replace(args.outDir, "")) +
7
- styleText("cyan", " ".repeat(1 + args.largestBundleLength - args.bundleName.length) +
8
- getFileSize(args.compiledBundleWithoutPlaceholders)));
9
- export const printBundleToHashMappingsWasCreated = (args) => console.log("\n" +
10
- styleText("greenBright", " Created: ") +
11
- styleText("white", args.outDir) +
12
- styleText("whiteBright", args.filePath.replace(args.outDir, "")));
2
+ import { DEFAULT_FONT_FACE_PATH, DEFAULT_ICONS_PATH, DEFAULT_OUT_DIR_PATH, SCSS_BUNDLES_INPUT_DIR, SCSS_BUNDLES_OUT_DIR } from "./constants.js";
3
+ import path from "node:path";
4
+ const separator = () => styleText(["gray"], " | ");
5
+ export const printBundleWasCreatedTableHeader = (args) => console.log(styleText(["white", "bold"], "Files") +
6
+ " ".repeat(args.largestBundleLength + args.outDir.length - "Files".length) +
7
+ separator() +
8
+ styleText(["white", "bold"], "Raw size"));
9
+ export const printBundleWasCreated = (args) => console.log(styleText("white", args.outDir) +
10
+ styleText("greenBright", path.join(args.outDir, args.bundleNameWithHash).replace(args.outDir, "")) +
11
+ " ".repeat(Math.max(args.largestBundleLength - args.bundleNameWithHash.length, 0)) +
12
+ separator() +
13
+ " ".repeat(Math.max(args.largestFileSizeLength - args.fileSize.length, 0)) +
14
+ styleText("cyanBright", args.fileSize));
13
15
  export const printBundleWasTranspiled = (filePath) => console.log(styleText("greenBright", " Transpiled: ") +
14
16
  styleText("white", SCSS_BUNDLES_OUT_DIR) +
15
- styleText("whiteBright", filePath.replace(SCSS_BUNDLES_OUT_DIR, "")));
17
+ styleText("whiteBright", filePath.replace(SCSS_BUNDLES_INPUT_DIR, "")));
16
18
  export const printArgumentDoesNotExistsError = (arg) => console.log(styleText("red", " error ") +
17
19
  styleText("gray", "Argument does not exists: ") +
18
20
  `'${arg}'`);
@@ -1,3 +1,2 @@
1
- import { FileMetadata } from "./types.js";
2
- export declare const transpileCssBundleWithPlaceholder: (fileMetadata: FileMetadata) => void;
3
- export declare const createBundleMappingsFile: () => void;
1
+ import type { CLIArguments, FileMetadata } from "./types";
2
+ export declare const transpileCssBundleWithPlaceholder: (fileMetadata: FileMetadata, args?: CLIArguments) => Promise<void>;