Skip to content

Commit

Permalink
Added ability add project aliases
Browse files Browse the repository at this point in the history
  • Loading branch information
ahmadnasriya committed Jul 23, 2024
1 parent 6ef57c3 commit 029a88d
Show file tree
Hide file tree
Showing 3 changed files with 134 additions and 14 deletions.
35 changes: 24 additions & 11 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
[![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)
##### Visit us at [www.nasriya.net](https://nasriya.net).

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

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

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

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

**Note:**
#### Defining aliases
In `postbuild.config.json`, you can add your aliases as such:

```json
{
"aliases": {
"my-module": "/modules/my-module",
"@elements/*": "/elements/"
}
}
```

#### Using `__dirname`
All `__dirname` matches in `ESM` will be replaced with `import.meta.dirname`, for example:

```ts
Expand Down
111 changes: 109 additions & 2 deletions main.js
Original file line number Diff line number Diff line change
Expand Up @@ -87,9 +87,23 @@ class Main {
} else {
this.#_config.addExtensions = false;
}

if ('aliases' in this.#_configFile) {
const aliases = this.#_configFile.aliases;
if (!utils.is.realObject(aliases)) { throw new Error(`The "aliases" option is expecting a real object, isntead got ${typeof aliases}`) }

this.#_config.aliases = {}
for (const prop in aliases) {
if (typeof aliases[prop] === 'string') {
this.#_config.aliases[prop] = aliases[prop];
} else {
throw new TypeError(`One of the defined aliases (${aliases[prop]}) is not a string`)
}
}
}
} catch (error) {
if (error instanceof Error) {
error.message = `Unable to read postbuild.this.#_configFile.json: ${error.message}`;
error.message = `Unable to read postbuild configFile: ${error.message}`;
}

throw error;
Expand Down Expand Up @@ -263,6 +277,98 @@ class Main {
fs.writeFileSync(fullPath, content, 'utf8');
}
});
},
aliases: {
regex: {
/**
* Create a regular expression for catching imports
* @param {string} pattern
* @returns {RegExp}
*/
createCatch: (pattern) => {
const escapedPattern = pattern.replace(/[-\/\\^$+?.()|[\]{}]/g, '\\$&').replace(/\*/g, '.*');
return new RegExp(`^${escapedPattern}$`)
},
/**
* Create a regular expression for catching imports
* @param {string} pattern
* @returns {RegExp}
*/
createExact: (pattern) => {
const escapedPattern = pattern.replace(/[-\/\\^$+?.()|[\]{}]/g, '\\$&');
return new RegExp(`^${escapedPattern}`)
}
},
getPatterns: () => {
const aliases = this.#_config.aliases;
return Object.keys(aliases).map(alias => {
const catchPattern = this.#_helpers.aliases.regex.createCatch(alias);
const exactPattern = this.#_helpers.aliases.regex.createExact(alias);

return {
alias,
catchPattern,
exactPattern,
resolvedPath: aliases[alias]
};
});
},
matchImportPath: (importPath, aliasPatterns) => {
for (const { catchPattern, exactPattern, resolvedPath } of aliasPatterns) {
// Check if the import path starts with the alias pattern
const match = importPath.match(catchPattern);
if (match) {
const newMatch = match[0].replace(exactPattern, resolvedPath)
const newImportPath = importPath.replace(match[0], newMatch);

// Construct the new path by combining the resolved path with the remaining path
return importPath.replace(match, newImportPath)
}
}

return importPath; // No match found
},
replaceImports: (filePath, aliasPatterns) => {
let fileContent = fs.readFileSync(filePath, 'utf8');

// Replace import paths based on alias patterns
fileContent = fileContent.replace(/from ['"]([^'"]+)['"]/g, (match, importPath) => {
// Match the import path against alias patterns
const resolvedPath = this.#_helpers.aliases.matchImportPath(importPath, aliasPatterns);

// Only replace if the alias was matched, else return the original import path
if (resolvedPath !== importPath) {
// Preserve the specific path segments after the alias
const remainingPath = importPath.replace(/^.*\/[^\/]+/, ''); // Strip alias part
return `from '${resolvedPath}${remainingPath}${remainingPath.endsWith('.js') ? '' : '.js'}'`;
}

return match; // No change if alias was not matched
});

fs.writeFileSync(filePath, fileContent, 'utf8');
},
processFiles: (directory, aliasPatterns) => {
fs.readdirSync(directory).forEach(file => {
const fullPath = path.join(directory, file);

if (fs.lstatSync(fullPath).isDirectory()) {
this.#_helpers.aliases.processFiles(fullPath, aliasPatterns);
} else if (file.endsWith('.js')) {
this.#_helpers.aliases.replaceImports(fullPath, aliasPatterns);
}
});
},
check: () => {
const aliasPatterns = this.#_helpers.aliases.getPatterns();
if (this.#_config.esmDir) {
this.#_helpers.aliases.processFiles(this.#_config.esmDir, aliasPatterns);
}

if (this.#_config.cjsDir) {
this.#_helpers.aliases.processFiles(this.#_config.cjsDir, aliasPatterns);
}
}
}
}

Expand All @@ -274,10 +380,11 @@ class Main {
this.#_helpers.create.packages();
this.#_helpers.copy.run();
this.#_helpers.extensions.run();
this.#_helpers.aliases.check();

const et = Date.now();
const duration = et - st;
this.#_helpers.print(`PostBuild finishes in ${duration} milliseconds`);
this.#_helpers.print(`PostBuild finished in ${duration} milliseconds`);
}
}

Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@nasriya/postbuild",
"version": "1.0.6",
"version": "1.1.0",
"description": "A package that does some tasks after compilation",
"main": "main.js",
"type": "module",
Expand Down

0 comments on commit 029a88d

Please sign in to comment.