Skip to content

Commit 029a88d

Browse files
committed
Added ability add project aliases
1 parent 6ef57c3 commit 029a88d

File tree

3 files changed

+134
-14
lines changed

3 files changed

+134
-14
lines changed

README.md

Lines changed: 24 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
[![Static Badge](https://img.shields.io/badge/license-Free_(Restricted)-blue)](https://github.com/nasriyasoftware/PostBuild?tab=License-1-ov-file) ![Repository Size](https://img.shields.io/github/repo-size/nasriyasoftware/PostBuild.svg) ![Last Commit](https://img.shields.io/github/last-commit/nasriyasoftware/PostBuild.svg) [![Status](https://img.shields.io/badge/Status-Stable-green.svg)](link-to-your-status-page)
44
##### Visit us at [www.nasriya.net](https://nasriya.net).
55

6-
PostBuild is a utility pacakge for **TypeScript** run useful tasks after transpiling TypeScript into **ESM** and **CJS** JavaScript file.
6+
PostBuild is a utility pacakge for **TypeScript** that runs useful tasks after transpiling TypeScript into **ESM** and **CJS** JavaScript file.
77

88
Made with ❤️ in **Palestine** 🇵🇸
99
___
@@ -25,15 +25,16 @@ npm run postbuild-init
2525
##### Config File Content
2626
The above comand will generate a file with all the features set to their recommended values. This table below explains them in details.
2727

28-
| Property | Description | Posible values | Default value |
29-
| ------------------- | ------------------------------------------------------------------------ | ----------------------- | ------------- |
30-
| `esmDir` | The directory of the generated `ESM` folder. | `auto` or the directory | `auto` |
31-
| `cjsDir` | The directory of the generated `CJS` folder. | `auto` or the directory | `auto` |
32-
| `verbose` | An option to enable logging extra details . | `true` or `false` | `true` |
33-
| `addExtensions` | Appending `.js` to all import statements. | `true` or `false` | `true` |
34-
| `copyFiles` | An options object to copy assets to the `dist` folder after transpiling. | `object` or `undefined` | Notice below |
35-
| `copyFiles.from` | The directory where you want to copy the assets to. | directory | `src` |
36-
| `copyFiles.exclude` | An array of file extensions to exclude. | `string[]` | `['.ts']` |
28+
| Property | Description | Posible values | Default value |
29+
| ------------------- | ------------------------------------------------------------------------ | ------------------------ | ------------- |
30+
| `esmDir` | The directory of the generated `ESM` folder. | `auto` or the directory | `auto` |
31+
| `cjsDir` | The directory of the generated `CJS` folder. | `auto` or the directory | `auto` |
32+
| `verbose` | An option to enable logging extra details . | `true` or `false` | `true` |
33+
| `addExtensions` | Appending `.js` to all import statements. | `true` or `false` | `true` |
34+
| `copyFiles` | An options object to copy assets to the `dist` folder after transpiling. | `object` or `undefined` | Notice below |
35+
| `copyFiles.from` | The directory where you want to copy the assets to. | directory | `src` |
36+
| `copyFiles.exclude` | An array of file extensions to exclude. | `string[]` | `['.ts']` |
37+
| `aliases` | Define aliases to your imports | `Record<string, string>` | Nothing |
3738

3839
The default configurations works well if your project is structured like this:
3940
```
@@ -65,7 +66,19 @@ The best way to use this package is to integrate it with your build process by a
6566
}
6667
```
6768

68-
**Note:**
69+
#### Defining aliases
70+
In `postbuild.config.json`, you can add your aliases as such:
71+
72+
```json
73+
{
74+
"aliases": {
75+
"my-module": "/modules/my-module",
76+
"@elements/*": "/elements/"
77+
}
78+
}
79+
```
80+
81+
#### Using `__dirname`
6982
All `__dirname` matches in `ESM` will be replaced with `import.meta.dirname`, for example:
7083

7184
```ts

main.js

Lines changed: 109 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -87,9 +87,23 @@ class Main {
8787
} else {
8888
this.#_config.addExtensions = false;
8989
}
90+
91+
if ('aliases' in this.#_configFile) {
92+
const aliases = this.#_configFile.aliases;
93+
if (!utils.is.realObject(aliases)) { throw new Error(`The "aliases" option is expecting a real object, isntead got ${typeof aliases}`) }
94+
95+
this.#_config.aliases = {}
96+
for (const prop in aliases) {
97+
if (typeof aliases[prop] === 'string') {
98+
this.#_config.aliases[prop] = aliases[prop];
99+
} else {
100+
throw new TypeError(`One of the defined aliases (${aliases[prop]}) is not a string`)
101+
}
102+
}
103+
}
90104
} catch (error) {
91105
if (error instanceof Error) {
92-
error.message = `Unable to read postbuild.this.#_configFile.json: ${error.message}`;
106+
error.message = `Unable to read postbuild configFile: ${error.message}`;
93107
}
94108

95109
throw error;
@@ -263,6 +277,98 @@ class Main {
263277
fs.writeFileSync(fullPath, content, 'utf8');
264278
}
265279
});
280+
},
281+
aliases: {
282+
regex: {
283+
/**
284+
* Create a regular expression for catching imports
285+
* @param {string} pattern
286+
* @returns {RegExp}
287+
*/
288+
createCatch: (pattern) => {
289+
const escapedPattern = pattern.replace(/[-\/\\^$+?.()|[\]{}]/g, '\\$&').replace(/\*/g, '.*');
290+
return new RegExp(`^${escapedPattern}$`)
291+
},
292+
/**
293+
* Create a regular expression for catching imports
294+
* @param {string} pattern
295+
* @returns {RegExp}
296+
*/
297+
createExact: (pattern) => {
298+
const escapedPattern = pattern.replace(/[-\/\\^$+?.()|[\]{}]/g, '\\$&');
299+
return new RegExp(`^${escapedPattern}`)
300+
}
301+
},
302+
getPatterns: () => {
303+
const aliases = this.#_config.aliases;
304+
return Object.keys(aliases).map(alias => {
305+
const catchPattern = this.#_helpers.aliases.regex.createCatch(alias);
306+
const exactPattern = this.#_helpers.aliases.regex.createExact(alias);
307+
308+
return {
309+
alias,
310+
catchPattern,
311+
exactPattern,
312+
resolvedPath: aliases[alias]
313+
};
314+
});
315+
},
316+
matchImportPath: (importPath, aliasPatterns) => {
317+
for (const { catchPattern, exactPattern, resolvedPath } of aliasPatterns) {
318+
// Check if the import path starts with the alias pattern
319+
const match = importPath.match(catchPattern);
320+
if (match) {
321+
const newMatch = match[0].replace(exactPattern, resolvedPath)
322+
const newImportPath = importPath.replace(match[0], newMatch);
323+
324+
// Construct the new path by combining the resolved path with the remaining path
325+
return importPath.replace(match, newImportPath)
326+
}
327+
}
328+
329+
return importPath; // No match found
330+
},
331+
replaceImports: (filePath, aliasPatterns) => {
332+
let fileContent = fs.readFileSync(filePath, 'utf8');
333+
334+
// Replace import paths based on alias patterns
335+
fileContent = fileContent.replace(/from ['"]([^'"]+)['"]/g, (match, importPath) => {
336+
// Match the import path against alias patterns
337+
const resolvedPath = this.#_helpers.aliases.matchImportPath(importPath, aliasPatterns);
338+
339+
// Only replace if the alias was matched, else return the original import path
340+
if (resolvedPath !== importPath) {
341+
// Preserve the specific path segments after the alias
342+
const remainingPath = importPath.replace(/^.*\/[^\/]+/, ''); // Strip alias part
343+
return `from '${resolvedPath}${remainingPath}${remainingPath.endsWith('.js') ? '' : '.js'}'`;
344+
}
345+
346+
return match; // No change if alias was not matched
347+
});
348+
349+
fs.writeFileSync(filePath, fileContent, 'utf8');
350+
},
351+
processFiles: (directory, aliasPatterns) => {
352+
fs.readdirSync(directory).forEach(file => {
353+
const fullPath = path.join(directory, file);
354+
355+
if (fs.lstatSync(fullPath).isDirectory()) {
356+
this.#_helpers.aliases.processFiles(fullPath, aliasPatterns);
357+
} else if (file.endsWith('.js')) {
358+
this.#_helpers.aliases.replaceImports(fullPath, aliasPatterns);
359+
}
360+
});
361+
},
362+
check: () => {
363+
const aliasPatterns = this.#_helpers.aliases.getPatterns();
364+
if (this.#_config.esmDir) {
365+
this.#_helpers.aliases.processFiles(this.#_config.esmDir, aliasPatterns);
366+
}
367+
368+
if (this.#_config.cjsDir) {
369+
this.#_helpers.aliases.processFiles(this.#_config.cjsDir, aliasPatterns);
370+
}
371+
}
266372
}
267373
}
268374

@@ -274,10 +380,11 @@ class Main {
274380
this.#_helpers.create.packages();
275381
this.#_helpers.copy.run();
276382
this.#_helpers.extensions.run();
383+
this.#_helpers.aliases.check();
277384

278385
const et = Date.now();
279386
const duration = et - st;
280-
this.#_helpers.print(`PostBuild finishes in ${duration} milliseconds`);
387+
this.#_helpers.print(`PostBuild finished in ${duration} milliseconds`);
281388
}
282389
}
283390

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@nasriya/postbuild",
3-
"version": "1.0.6",
3+
"version": "1.1.0",
44
"description": "A package that does some tasks after compilation",
55
"main": "main.js",
66
"type": "module",

0 commit comments

Comments
 (0)