@genexus/mercury 0.20.0 → 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 (124) hide show
  1. package/dist/bundles/css/all.css +1 -1
  2. package/dist/bundles/css/base/base-globant.css +1 -1
  3. package/dist/bundles/css/base/base.css +1 -1
  4. package/dist/bundles/css/components/accordion.css +1 -1
  5. package/dist/bundles/css/components/button.css +1 -1
  6. package/dist/bundles/css/components/chat.css +1 -1
  7. package/dist/bundles/css/components/code.css +1 -1
  8. package/dist/bundles/css/components/combo-box.css +1 -1
  9. package/dist/bundles/css/components/dialog.css +1 -1
  10. package/dist/bundles/css/components/dropdown.css +1 -1
  11. package/dist/bundles/css/components/edit.css +1 -1
  12. package/dist/bundles/css/components/flexible-layout.css +1 -1
  13. package/dist/bundles/css/components/icon.css +1 -1
  14. package/dist/bundles/css/components/list-box.css +1 -1
  15. package/dist/bundles/css/components/markdown-viewer.css +1 -1
  16. package/dist/bundles/css/components/navigation-list.css +1 -1
  17. package/dist/bundles/css/components/pills.css +1 -1
  18. package/dist/bundles/css/components/segmented-control.css +1 -1
  19. package/dist/bundles/css/components/slider.css +1 -1
  20. package/dist/bundles/css/components/switch.css +1 -1
  21. package/dist/bundles/css/components/tab.css +1 -1
  22. package/dist/bundles/css/components/tabular-grid.css +1 -1
  23. package/dist/bundles/css/components/tooltip.css +1 -1
  24. package/dist/bundles/css/utils/form--full.css +1 -1
  25. package/dist/bundles/css/utils/form.css +1 -1
  26. package/dist/bundles/css/utils/spacing.css +1 -1
  27. package/dist/cli/bundle.js +185 -17
  28. package/dist/cli/internal/constants.d.ts +3 -12
  29. package/dist/cli/internal/constants.js +4 -13
  30. package/dist/cli/internal/create-bundles-with-custom-paths.d.ts +10 -2
  31. package/dist/cli/internal/create-bundles-with-custom-paths.js +102 -55
  32. package/dist/cli/internal/file-management.d.ts +3 -2
  33. package/dist/cli/internal/file-management.js +45 -12
  34. package/dist/cli/internal/print-utils.d.ts +6 -6
  35. package/dist/cli/internal/print-utils.js +14 -12
  36. package/dist/cli/internal/transpile-bundle-and-create-mappings.d.ts +2 -3
  37. package/dist/cli/internal/transpile-bundle-and-create-mappings.js +37 -66
  38. package/dist/cli/internal/types.d.ts +0 -1
  39. package/dist/cli/internal/utils.d.ts +11 -8
  40. package/dist/cli/internal/utils.js +27 -22
  41. package/dist/cli/internal/validate-args.js +7 -1
  42. package/dist/cli/internal/watch-fs.d.ts +3 -0
  43. package/dist/cli/internal/watch-fs.js +92 -0
  44. package/dist/cli/mercury.js +2 -2
  45. package/package.json +17 -12
  46. package/dist/bundles/js/all.js +0 -1
  47. package/dist/bundles/js/base/base-globant.js +0 -1
  48. package/dist/bundles/js/base/base.js +0 -1
  49. package/dist/bundles/js/base/icons.js +0 -1
  50. package/dist/bundles/js/bundle-mappings.js +0 -237
  51. package/dist/bundles/js/chameleon/scrollbar.js +0 -1
  52. package/dist/bundles/js/components/accordion.js +0 -1
  53. package/dist/bundles/js/components/button.js +0 -1
  54. package/dist/bundles/js/components/chat.js +0 -1
  55. package/dist/bundles/js/components/checkbox.js +0 -1
  56. package/dist/bundles/js/components/code.js +0 -1
  57. package/dist/bundles/js/components/combo-box.js +0 -1
  58. package/dist/bundles/js/components/dialog.js +0 -1
  59. package/dist/bundles/js/components/dropdown.js +0 -1
  60. package/dist/bundles/js/components/edit.js +0 -1
  61. package/dist/bundles/js/components/flexible-layout.js +0 -1
  62. package/dist/bundles/js/components/icon.js +0 -1
  63. package/dist/bundles/js/components/layout-splitter.js +0 -1
  64. package/dist/bundles/js/components/list-box.js +0 -1
  65. package/dist/bundles/js/components/markdown-viewer.js +0 -1
  66. package/dist/bundles/js/components/navigation-list.js +0 -1
  67. package/dist/bundles/js/components/pills.js +0 -1
  68. package/dist/bundles/js/components/radio-group.js +0 -1
  69. package/dist/bundles/js/components/segmented-control.js +0 -1
  70. package/dist/bundles/js/components/sidebar.js +0 -1
  71. package/dist/bundles/js/components/slider.js +0 -1
  72. package/dist/bundles/js/components/switch.js +0 -1
  73. package/dist/bundles/js/components/tab.js +0 -1
  74. package/dist/bundles/js/components/tabular-grid.js +0 -1
  75. package/dist/bundles/js/components/ticket-list.js +0 -1
  76. package/dist/bundles/js/components/tooltip.js +0 -1
  77. package/dist/bundles/js/components/tree-view.js +0 -1
  78. package/dist/bundles/js/components/widget.js +0 -1
  79. package/dist/bundles/js/resets/box-sizing.js +0 -1
  80. package/dist/bundles/js/utils/elevation.js +0 -1
  81. package/dist/bundles/js/utils/form--full.js +0 -1
  82. package/dist/bundles/js/utils/form.js +0 -1
  83. package/dist/bundles/js/utils/layout.js +0 -1
  84. package/dist/bundles/js/utils/spacing.js +0 -1
  85. package/dist/bundles/js/utils/typography.js +0 -1
  86. package/dist/bundles/scss/all.scss +0 -8
  87. package/dist/bundles/scss/base/base.scss +0 -24
  88. package/dist/bundles/scss/base/icons.scss +0 -4
  89. package/dist/bundles/scss/chameleon/scrollbar.scss +0 -3
  90. package/dist/bundles/scss/components/accordion.scss +0 -3
  91. package/dist/bundles/scss/components/button.scss +0 -8
  92. package/dist/bundles/scss/components/chat.scss +0 -3
  93. package/dist/bundles/scss/components/checkbox.scss +0 -3
  94. package/dist/bundles/scss/components/code.scss +0 -3
  95. package/dist/bundles/scss/components/combo-box.scss +0 -3
  96. package/dist/bundles/scss/components/dialog.scss +0 -3
  97. package/dist/bundles/scss/components/dropdown.scss +0 -3
  98. package/dist/bundles/scss/components/edit.scss +0 -3
  99. package/dist/bundles/scss/components/flexible-layout.scss +0 -3
  100. package/dist/bundles/scss/components/icon.scss +0 -8
  101. package/dist/bundles/scss/components/layout-splitter.scss +0 -3
  102. package/dist/bundles/scss/components/list-box.scss +0 -3
  103. package/dist/bundles/scss/components/markdown-viewer.scss +0 -3
  104. package/dist/bundles/scss/components/navigation-list.scss +0 -3
  105. package/dist/bundles/scss/components/pills.scss +0 -3
  106. package/dist/bundles/scss/components/radio-group.scss +0 -3
  107. package/dist/bundles/scss/components/segmented-control.scss +0 -3
  108. package/dist/bundles/scss/components/sidebar.scss +0 -3
  109. package/dist/bundles/scss/components/slider.scss +0 -3
  110. package/dist/bundles/scss/components/switch.scss +0 -3
  111. package/dist/bundles/scss/components/tab.scss +0 -3
  112. package/dist/bundles/scss/components/tabular-grid.scss +0 -10
  113. package/dist/bundles/scss/components/ticket-list.scss +0 -3
  114. package/dist/bundles/scss/components/tooltip.scss +0 -3
  115. package/dist/bundles/scss/components/tree-view.scss +0 -3
  116. package/dist/bundles/scss/components/widget.scss +0 -3
  117. package/dist/bundles/scss/resets/box-sizing.scss +0 -3
  118. package/dist/bundles/scss/utils/elevation.scss +0 -4
  119. package/dist/bundles/scss/utils/form--full.scss +0 -20
  120. package/dist/bundles/scss/utils/form.scss +0 -4
  121. package/dist/bundles/scss/utils/layout.scss +0 -4
  122. package/dist/bundles/scss/utils/spacing.scss +0 -4
  123. package/dist/bundles/scss/utils/typography.scss +0 -9
  124. package/dist/mercury.scss +0 -24802
@@ -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>;
@@ -1,86 +1,57 @@
1
- import fs from "node:fs";
1
+ import fs from "node:fs/promises";
2
2
  import path from "node:path";
3
3
  import * as sass from "sass";
4
- import { BASE_BUNDLE_WITH_BACK_SLASH, BASE_GLOBANT_CSS_FILE, BASE_GLOBANT_FILE, BASE_GLOBANT_JS_FILE, BASE_GLOBANT_SCSS_FILE, BASE_SCSS_FILE, BUNDLE_MAPPING_ENTRIES, BUNDLE_MAPPING_FILE, CSS_BUNDLES_OUT_DIR, DEFAULT_FONT_FACE_PATH, DEFAULT_ICONS_PATH, JS_BUNDLES_OUT_DIR, SCSS_BUNDLES_OUT_DIR } from "./constants.js";
5
- import { getBundleNameWithoutSpecialChars, replacePlaceholdersInBundle } from "./utils.js";
6
- import { printBundleWasTranspiled } from "./print-utils.js";
4
+ import { BASE_BUNDLE, BASE_GLOBANT_BUNDLE, BASE_GLOBANT_CSS_FILE, CSS_BUNDLES_OUT_DIR, DEFAULT_FONT_FACE_PATH, DEFAULT_ICONS_PATH, SCSS_BUNDLES_INPUT_DIR, SCSS_BUNDLES_OUT_DIR } from "./constants.js";
5
+ import { replacePlaceholdersInBundle, sanitizeBundleName } from "./utils.js";
7
6
  const transpileBundle = (filePath, globant) => sass.compile(filePath, {
8
7
  loadPaths: [globant ? "src/config/globant" : "src/config/default"],
9
8
  style: "compressed"
10
9
  }).css;
11
- const CSS_CREATED_DIRS = new Set();
12
- const JS_CREATED_DIRS = new Set();
13
- const BUNDLES = [];
14
- const addBaseGlobantFile = (fileMetadata, cssOutDir, jsOutDir) => {
10
+ let BUNDLES = [];
11
+ const transpileGlobantCssFile = async (fileMetadata, cssOutDir) => {
15
12
  const { filePath } = fileMetadata;
16
13
  BUNDLES.push({
17
14
  fileDir: fileMetadata.dir
18
15
  .replace(SCSS_BUNDLES_OUT_DIR, "")
19
- .replace("\\", "/"),
20
- bundleNameWithBackSlash: filePath
21
- .replace(SCSS_BUNDLES_OUT_DIR, "")
22
- .replace(BASE_SCSS_FILE, BASE_GLOBANT_FILE)
16
+ .replace("\\", "/")
23
17
  });
24
18
  const transpiledBundle = transpileBundle(filePath, true);
25
19
  // Store the CSS file with its default values
26
- fs.writeFileSync(path.join(cssOutDir, BASE_GLOBANT_CSS_FILE), replacePlaceholdersInBundle(transpiledBundle, DEFAULT_FONT_FACE_PATH, DEFAULT_ICONS_PATH));
27
- // Store the CSS file in a JS file with placeholders for the values
28
- fs.writeFileSync(path.join(jsOutDir, BASE_GLOBANT_JS_FILE), `export const bundle = \`${transpiledBundle}\`;`);
29
- printBundleWasTranspiled(filePath.replace(BASE_SCSS_FILE, BASE_GLOBANT_SCSS_FILE));
20
+ await fs.writeFile(path.join(cssOutDir, BASE_GLOBANT_CSS_FILE), replacePlaceholdersInBundle(transpiledBundle, DEFAULT_FONT_FACE_PATH, DEFAULT_ICONS_PATH));
30
21
  };
31
- export const transpileCssBundleWithPlaceholder = (fileMetadata) => {
32
- const { fileName, filePath } = fileMetadata;
33
- const cssOutDir = fileMetadata.dir.replace(SCSS_BUNDLES_OUT_DIR, CSS_BUNDLES_OUT_DIR);
34
- const jsOutDir = fileMetadata.dir.replace(SCSS_BUNDLES_OUT_DIR, JS_BUNDLES_OUT_DIR);
22
+ export const transpileCssBundleWithPlaceholder = async (fileMetadata, args) => {
23
+ const { fileName } = fileMetadata;
24
+ let actualFilePath = fileMetadata.filePath;
25
+ const hasGlobantVariant = args?.globant ?? false;
26
+ const cssOutDir = fileMetadata.dir.replace(SCSS_BUNDLES_INPUT_DIR, CSS_BUNDLES_OUT_DIR);
35
27
  const fileNameCssExt = fileName.replace(".scss", ".css");
36
- const fileNameJsExt = fileName.replace(".scss", ".js");
37
- const bundleNameWithBackSlash = filePath
38
- .replace(SCSS_BUNDLES_OUT_DIR, "")
39
- .replace(".scss", "");
28
+ const bundleName = sanitizeBundleName(actualFilePath.replace(SCSS_BUNDLES_INPUT_DIR, "").replace(".scss", ""));
29
+ // There is no need to generate the base-globant.css file, since the base.css
30
+ // file already contains this file
31
+ if (hasGlobantVariant) {
32
+ if (bundleName === BASE_GLOBANT_BUNDLE) {
33
+ return;
34
+ }
35
+ // Replace the content of the base bundle with the Globant variant
36
+ if (bundleName === BASE_BUNDLE) {
37
+ actualFilePath = actualFilePath.replace(BASE_BUNDLE, BASE_GLOBANT_BUNDLE);
38
+ }
39
+ }
40
+ // The Globant variant is not forced, so we are creating both bundles, the
41
+ // base/base and base/base-globant bundles
42
+ else if (bundleName === BASE_BUNDLE) {
43
+ transpileGlobantCssFile({
44
+ dir: fileMetadata.dir,
45
+ fileName: fileName.replace(BASE_BUNDLE, BASE_GLOBANT_BUNDLE),
46
+ filePath: actualFilePath
47
+ }, cssOutDir);
48
+ }
40
49
  BUNDLES.push({
41
50
  fileDir: fileMetadata.dir
42
- .replace(SCSS_BUNDLES_OUT_DIR, "")
43
- .replace("\\", "/"),
44
- bundleNameWithBackSlash
51
+ .replace(SCSS_BUNDLES_INPUT_DIR, "")
52
+ .replace("\\", "/")
45
53
  });
46
- // Create the file directory if it does not exists
47
- if (!CSS_CREATED_DIRS.has(cssOutDir)) {
48
- fs.mkdirSync(cssOutDir, { recursive: true });
49
- fs.mkdirSync(jsOutDir, { recursive: true });
50
- CSS_CREATED_DIRS.add(cssOutDir);
51
- JS_CREATED_DIRS.add(jsOutDir);
52
- }
53
- const transpiledBundle = transpileBundle(filePath, false);
54
+ const transpiledBundle = transpileBundle(actualFilePath, hasGlobantVariant);
54
55
  // Store the CSS file with its default values
55
- fs.writeFileSync(path.join(cssOutDir, fileNameCssExt), replacePlaceholdersInBundle(transpiledBundle, DEFAULT_FONT_FACE_PATH, DEFAULT_ICONS_PATH));
56
- // Store the CSS file in a JS file with placeholders for the values
57
- fs.writeFileSync(path.join(jsOutDir, fileNameJsExt), `export const bundle = \`${transpiledBundle}\`;`);
58
- printBundleWasTranspiled(filePath);
59
- if (bundleNameWithBackSlash.replaceAll("/", "\\") ===
60
- BASE_BUNDLE_WITH_BACK_SLASH) {
61
- addBaseGlobantFile(fileMetadata, cssOutDir, jsOutDir);
62
- }
63
- };
64
- const createBundleEntryInMappingFile = (bundleName, fileDir, transpiledBundleRef) => ` {
65
- ${BUNDLE_MAPPING_ENTRIES.BUNDLE_NAME}: "${bundleName}",
66
- ${BUNDLE_MAPPING_ENTRIES.FILE_DIR}: "${fileDir}",
67
- ${BUNDLE_MAPPING_ENTRIES.TRANSPILED_BUNDLE}: ${transpiledBundleRef}
68
- }`;
69
- export const createBundleMappingsFile = () => {
70
- let bundleAssociationImports = "";
71
- let bundleMappingObjectEntries = "";
72
- BUNDLES.forEach(bundleMetadata => {
73
- const bundleName = bundleMetadata.bundleNameWithBackSlash
74
- .replaceAll("\\", "/")
75
- .substring(1);
76
- const transpiledBundleRef = getBundleNameWithoutSpecialChars(bundleName);
77
- const bundleEntry = createBundleEntryInMappingFile(bundleName, bundleMetadata.fileDir, transpiledBundleRef);
78
- bundleAssociationImports += `import { bundle as ${transpiledBundleRef} } from "./${bundleName}.js";\n`;
79
- // Concat entries in the object
80
- bundleMappingObjectEntries +=
81
- bundleMappingObjectEntries === "" ? bundleEntry : ",\n" + bundleEntry;
82
- });
83
- bundleMappingObjectEntries = `\nexport const bundleMappings = [\n${bundleMappingObjectEntries}\n];`;
84
- // Create the JS file that contains all mappings for the bundle
85
- fs.writeFileSync(path.join(JS_BUNDLES_OUT_DIR, BUNDLE_MAPPING_FILE), bundleAssociationImports + bundleMappingObjectEntries);
56
+ await fs.writeFile(path.join(cssOutDir, fileNameCssExt), replacePlaceholdersInBundle(transpiledBundle, DEFAULT_FONT_FACE_PATH, DEFAULT_ICONS_PATH));
86
57
  };
@@ -1,6 +1,5 @@
1
1
  export type BundleMetadata = {
2
2
  fileDir: string;
3
- bundleNameWithBackSlash: string;
4
3
  };
5
4
  export type BundleAssociationMetadata = {
6
5
  bundleName: string;
@@ -1,11 +1,14 @@
1
+ import type { FileMetadata } from "./types";
1
2
  export declare const getFileSize: (fileContent: string) => string;
2
3
  export declare const getHash: (fileContent: string) => string;
3
- export declare const getBundleNameWithHash: <B extends string, H extends string>(bundleName: B, hash: H) => `${B}-${H}`;
4
+ export declare const getFileNameWithHash: <B extends string, H extends string>(bundleName: B, hash: H) => `${B}-${H}`;
4
5
  export declare const replacePlaceholdersInBundle: (transpiledBundle: string, fontFaceValue: string, iconsValue: string) => string;
5
- /**
6
- * @example
7
- * "base/icons" --> "baseIcons"
8
- * "utils/form--full" --> "utilsFormFull"
9
- */
10
- export declare const getBundleNameWithoutSpecialChars: (bundleName: string) => string;
11
- export declare const measureTime: (callback: () => void) => void;
6
+ export declare const measureTime: (callback: (() => void) | (() => Promise<void>)) => Promise<void>;
7
+ export declare const sanitizeBundleName: (bundleName: string) => string;
8
+ export declare const getBundleFolder: (fileMetadata: FileMetadata) => string;
9
+ export declare const getBundleFolderAndFileBaseDir: (fileMetadata: FileMetadata, outDir: string) => {
10
+ bundleFolder: string;
11
+ fileBaseDirToWrite: string;
12
+ };
13
+ export declare const getFileNameWithoutExt: (fileMetadata: FileMetadata) => string;
14
+ export declare const getBundleName: (fileMetadata: FileMetadata) => string;
@@ -1,42 +1,47 @@
1
1
  import crypto from "node:crypto";
2
2
  import { styleText } from "node:util";
3
- import { FONT_FACE_PATH_PLACEHOLDER, ICONS_PATH_PLACEHOLDER, KB, SPECIAL_CHARS_IN_BUNDLE_NAME_REGEX } from "./constants.js";
3
+ import { CSS_BUNDLES_OUT_DIR, FONT_FACE_PATH_PLACEHOLDER, HASH_LENGTH, ICONS_PATH_PLACEHOLDER, KB
4
+ // SPECIAL_CHARS_IN_BUNDLE_NAME_REGEX
5
+ } from "./constants.js";
6
+ import path from "node:path";
4
7
  export const getFileSize = (fileContent) => {
5
8
  const fileLength = fileContent.length;
6
9
  if (fileLength < KB) {
7
- return fileLength + "B";
10
+ return fileLength + " bytes";
8
11
  }
9
12
  const fileLengthInKB = fileLength / KB;
10
13
  if (fileLengthInKB < KB) {
11
- return fileLengthInKB + "KB";
14
+ return fileLengthInKB.toFixed(2) + " kB";
12
15
  }
13
16
  const fileLengthInMB = fileLengthInKB / KB;
14
17
  if (fileLengthInMB < KB) {
15
- return fileLengthInMB.toFixed(3) + "MB";
18
+ return fileLengthInMB.toFixed(2) + " MB";
16
19
  }
17
20
  const fileLengthInGB = fileLengthInMB / KB;
18
- return fileLengthInGB.toFixed(3) + "GB";
21
+ return fileLengthInGB.toFixed(2) + " GB";
19
22
  };
20
- export const getHash = (fileContent) => crypto.createHash("md5").update(fileContent).digest("hex").substring(16);
21
- export const getBundleNameWithHash = (bundleName, hash) => `${bundleName}-${hash}`;
23
+ export const getHash = (fileContent) => crypto
24
+ .createHash("md5")
25
+ .update(fileContent)
26
+ .digest("hex")
27
+ .substring(HASH_LENGTH);
28
+ export const getFileNameWithHash = (bundleName, hash) => `${bundleName}-${hash}`;
22
29
  export const replacePlaceholdersInBundle = (transpiledBundle, fontFaceValue, iconsValue) => transpiledBundle
23
30
  .replaceAll(ICONS_PATH_PLACEHOLDER, iconsValue)
24
31
  .replaceAll(FONT_FACE_PATH_PLACEHOLDER, fontFaceValue);
25
- /**
26
- * @example
27
- * "base/icons" --> "baseIcons"
28
- * "utils/form--full" --> "utilsFormFull"
29
- */
30
- export const getBundleNameWithoutSpecialChars = (bundleName) => {
31
- const bundleNameNoSpecialChars = bundleName
32
- .split(SPECIAL_CHARS_IN_BUNDLE_NAME_REGEX)
33
- .map(subPath => subPath.charAt(0).toUpperCase() + subPath.slice(1))
34
- .join("");
35
- return (bundleNameNoSpecialChars.charAt(0).toLowerCase() +
36
- bundleNameNoSpecialChars.slice(1));
37
- };
38
- export const measureTime = (callback) => {
32
+ export const measureTime = async (callback) => {
39
33
  console.time(styleText("green", "Done in"));
40
- callback();
34
+ await callback();
41
35
  console.timeEnd(styleText("green", "Done in"));
42
36
  };
37
+ export const sanitizeBundleName = (bundleName) => bundleName.replaceAll("\\", "/").replace(/^\//, "");
38
+ export const getBundleFolder = (fileMetadata) => fileMetadata.dir.split(CSS_BUNDLES_OUT_DIR)[1];
39
+ export const getBundleFolderAndFileBaseDir = (fileMetadata, outDir) => {
40
+ const bundleFolder = getBundleFolder(fileMetadata);
41
+ return {
42
+ bundleFolder,
43
+ fileBaseDirToWrite: path.join(outDir, bundleFolder)
44
+ };
45
+ };
46
+ export const getFileNameWithoutExt = (fileMetadata) => fileMetadata.fileName.replace(/.css$/, "");
47
+ export const getBundleName = (fileMetadata) => sanitizeBundleName(`${getBundleFolder(fileMetadata)}/${getFileNameWithoutExt(fileMetadata)}`);
@@ -1,5 +1,6 @@
1
1
  import { DEFAULT_FONT_FACE_PATH, DEFAULT_ICONS_PATH, DEFAULT_OUT_DIR_PATH, SEPARATE_BY_COMMA_REGEX } from "./constants.js";
2
2
  import { printArgumentDoesNotExistsError, printDuplicatedArgumentError, printInvalidArgumentError, printMissingFontPathArgumentWarning, printMissingIconsPathArgumentWarning, printMissingOutDirPathArgumentWarning } from "./print-utils.js";
3
+ import { sanitizeBundleName } from "./utils.js";
3
4
  const ARGUMENT_VALUE_AND_NAME_SEPARATOR_REGEX = /\s*=\s*/g;
4
5
  const ERROR_IN_CHECK = false;
5
6
  const SUCCESS_CHECK = true;
@@ -40,6 +41,9 @@ const checkArgument = (argument) => {
40
41
  }
41
42
  const argNameWithValue = argument.split(ARGUMENT_VALUE_AND_NAME_SEPARATOR_REGEX);
42
43
  if (argNameWithValue.length !== 2) {
44
+ if (argNameWithValue[0] === "--watch") {
45
+ return SUCCESS_CHECK;
46
+ }
43
47
  printInvalidArgumentError(argument);
44
48
  return ERROR_IN_CHECK;
45
49
  }
@@ -109,8 +113,10 @@ export const getArguments = () => {
109
113
  if (anyWarning) {
110
114
  console.log("");
111
115
  }
116
+ // Sanitize bundle names to avoid issues with "/" and "\" in paths
117
+ const sanitizedAvoidHash = new Set(avoidHash.map(bundleName => sanitizeBundleName(bundleName)));
112
118
  return {
113
- avoidHash: new Set(avoidHash),
119
+ avoidHash: new Set(sanitizedAvoidHash),
114
120
  globant: hasGlobant,
115
121
  fontFacePath,
116
122
  iconsPath,
@@ -0,0 +1,3 @@
1
+ export declare const printRebuilding: (firstBuild: boolean) => void;
2
+ export declare const stopRebuildingStdout: () => void;
3
+ export declare const watchFileSystemChanges: (callbackToCompile: () => Promise<void>) => void;