sigpro 1.0.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.
- package/LICENSE +21 -0
- package/Readme.md +1544 -0
- package/SigProRouterPlugin/Readme.md +139 -0
- package/SigProRouterPlugin/vite-plugin-sigpro.js +141 -0
- package/index.js +8 -0
- package/package.json +11 -0
- package/sigpro-1.0.0.tgz +0 -0
- package/sigpro.js +474 -0
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
# SigPro Router Plugin for Vite
|
|
2
|
+
|
|
3
|
+
A Vite plugin that automatically generates routes from your file structure in `src/pages/`, similar to Next.js file-based routing but for any JavaScript project.
|
|
4
|
+
|
|
5
|
+
## Features
|
|
6
|
+
|
|
7
|
+
- š **File-based routing**: Automatically creates routes from your `src/pages` directory
|
|
8
|
+
- š **Dynamic routes**: Supports parameterized routes using `[param]` syntax
|
|
9
|
+
- š§ **Path-to-regexp conversion**: Dynamic routes are converted to RegExp with named capture groups
|
|
10
|
+
- š **Route map generation**: Console output shows all detected routes at build time
|
|
11
|
+
- šÆ **Virtual module**: Access your routes via `virtual:sigpro-routes`
|
|
12
|
+
|
|
13
|
+
## Installation
|
|
14
|
+
|
|
15
|
+
1. Save the plugin code in your project, for example as `plugins/sigpro-router.js`
|
|
16
|
+
|
|
17
|
+
2. Add it to your Vite configuration:
|
|
18
|
+
|
|
19
|
+
```javascript
|
|
20
|
+
// vite.config.js
|
|
21
|
+
import { defineConfig } from 'vite';
|
|
22
|
+
import sigproRouter from './plugins/sigpro-router';
|
|
23
|
+
|
|
24
|
+
export default defineConfig({
|
|
25
|
+
plugins: [sigproRouter()]
|
|
26
|
+
});
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
## Usage
|
|
30
|
+
|
|
31
|
+
### 1. Create Pages
|
|
32
|
+
|
|
33
|
+
Create `.js` files in your `src/pages` directory. Each file becomes a route:
|
|
34
|
+
|
|
35
|
+
```
|
|
36
|
+
src/pages/
|
|
37
|
+
āāā index.js -> /
|
|
38
|
+
āāā about.js -> /about
|
|
39
|
+
āāā blog/
|
|
40
|
+
ā āāā index.js -> /blog
|
|
41
|
+
ā āāā [id].js -> /blog/:id (dynamic)
|
|
42
|
+
āāā users/
|
|
43
|
+
āāā [userId].js -> /users/:userId (dynamic)
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
### 2. Access Routes in Your Application
|
|
47
|
+
|
|
48
|
+
The plugin exposes a virtual module `virtual:sigpro-routes` that exports a `routes` array:
|
|
49
|
+
|
|
50
|
+
```javascript
|
|
51
|
+
// In your router or main application file
|
|
52
|
+
import { routes } from 'virtual:sigpro-routes';
|
|
53
|
+
|
|
54
|
+
// The routes array structure:
|
|
55
|
+
// [
|
|
56
|
+
// { path: '/', component: PageComponent, isDynamic: false, paramName: null },
|
|
57
|
+
// { path: /^\/blog\/(?<id>[^/]+)$/, component: PageComponent, isDynamic: true, paramName: 'id' },
|
|
58
|
+
// { path: /^\/users\/(?<userId>[^/]+)$/, component: PageComponent, isDynamic: true, paramName: 'userId' },
|
|
59
|
+
// ]
|
|
60
|
+
|
|
61
|
+
// Example usage with a simple router
|
|
62
|
+
function renderRoute(path) {
|
|
63
|
+
for (const route of routes) {
|
|
64
|
+
if (!route.isDynamic && route.path === path) {
|
|
65
|
+
return route.component();
|
|
66
|
+
} else if (route.isDynamic) {
|
|
67
|
+
const match = path.match(route.path);
|
|
68
|
+
if (match) {
|
|
69
|
+
// Access params via match.groups
|
|
70
|
+
const params = match.groups;
|
|
71
|
+
return route.component(params);
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
return '<h1>404 Not Found</h1>';
|
|
76
|
+
}
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
### 3. Build Time Output
|
|
80
|
+
|
|
81
|
+
When you run your Vite dev server or build, you'll see a route map in the console:
|
|
82
|
+
|
|
83
|
+
```
|
|
84
|
+
š [SigPro Router] Mapa de rutas generado:
|
|
85
|
+
š / -> index.js
|
|
86
|
+
š /about -> about.js
|
|
87
|
+
š /blog -> blog/index.js
|
|
88
|
+
š /blog/[id] -> blog/[id].js
|
|
89
|
+
š /users/[userId] -> users/[userId].js
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
## Route Priority
|
|
93
|
+
|
|
94
|
+
Routes are automatically prioritized:
|
|
95
|
+
|
|
96
|
+
1. Static routes (non-dynamic) are matched before dynamic routes
|
|
97
|
+
2. Routes are sorted by path length (shorter paths first)
|
|
98
|
+
|
|
99
|
+
## Route Object Properties
|
|
100
|
+
|
|
101
|
+
Each route in the `routes` array contains:
|
|
102
|
+
|
|
103
|
+
| Property | Type | Description |
|
|
104
|
+
|----------|------|-------------|
|
|
105
|
+
| `path` | `string \| RegExp` | Static path string or RegExp for dynamic routes |
|
|
106
|
+
| `component` | `Function` | The imported page component/module |
|
|
107
|
+
| `isDynamic` | `boolean` | Whether the route has parameters |
|
|
108
|
+
| `paramName` | `string \| null` | The parameter name for dynamic routes |
|
|
109
|
+
|
|
110
|
+
## Dynamic Route Parameters
|
|
111
|
+
|
|
112
|
+
For dynamic routes like `blog/[id].js`:
|
|
113
|
+
|
|
114
|
+
- The route path becomes: `new RegExp("^\\/blog\\/(?<id>[^/]+)$")`
|
|
115
|
+
- Parameters can be accessed via `match.groups` when matching the route
|
|
116
|
+
|
|
117
|
+
Example:
|
|
118
|
+
```javascript
|
|
119
|
+
const match = '/blog/123'.match(/^\/blog\/(?<id>[^/]+)$/);
|
|
120
|
+
console.log(match.groups.id); // '123'
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
## Limitations
|
|
124
|
+
|
|
125
|
+
- Only scans `.js` files (no JSX/TS support by default - modify the plugin if needed)
|
|
126
|
+
- Requires a `src/pages` directory in your project root
|
|
127
|
+
- Dynamic parameters are matched as single path segments (no catch-all routes)
|
|
128
|
+
|
|
129
|
+
## Customization
|
|
130
|
+
|
|
131
|
+
You can modify the plugin to:
|
|
132
|
+
- Support other file extensions (.jsx, .ts, .tsx)
|
|
133
|
+
- Change the pages directory location
|
|
134
|
+
- Add custom route sorting logic
|
|
135
|
+
- Implement nested dynamic routes
|
|
136
|
+
|
|
137
|
+
---
|
|
138
|
+
|
|
139
|
+
Built for SigPro applications with Vite.
|
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
import fs from 'fs';
|
|
2
|
+
import path from 'path';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* SigPro Router Plugin for Vite
|
|
6
|
+
*
|
|
7
|
+
* This plugin generates routes automatically based on the file structure in src/pages/
|
|
8
|
+
* It creates a virtual module 'virtual:sigpro-routes' that exports a routes array
|
|
9
|
+
* with all the detected pages and their corresponding components.
|
|
10
|
+
*
|
|
11
|
+
* @returns {import('vite').Plugin} Vite plugin object
|
|
12
|
+
*/
|
|
13
|
+
export default function sigproRouter() {
|
|
14
|
+
// Virtual module identifiers
|
|
15
|
+
const VIRTUAL_MODULE_ID = 'virtual:sigpro-routes';
|
|
16
|
+
const RESOLVED_VIRTUAL_MODULE_ID = '\0' + VIRTUAL_MODULE_ID;
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* Recursively retrieves all JavaScript files from a directory
|
|
20
|
+
*
|
|
21
|
+
* @param {string} directoryPath - The path to scan for files
|
|
22
|
+
* @returns {string[]} Array of absolute paths to all .js files found
|
|
23
|
+
*/
|
|
24
|
+
function getAllJavaScriptFiles(directoryPath) {
|
|
25
|
+
let filesFound = [];
|
|
26
|
+
|
|
27
|
+
// Return empty array if directory doesn't exist
|
|
28
|
+
if (!fs.existsSync(directoryPath)) return filesFound;
|
|
29
|
+
|
|
30
|
+
const directoryContents = fs.readdirSync(directoryPath);
|
|
31
|
+
|
|
32
|
+
directoryContents.forEach(item => {
|
|
33
|
+
const fullItemPath = path.resolve(directoryPath, item);
|
|
34
|
+
const itemStats = fs.statSync(fullItemPath);
|
|
35
|
+
|
|
36
|
+
if (itemStats && itemStats.isDirectory()) {
|
|
37
|
+
// Recursively scan subdirectories
|
|
38
|
+
filesFound = filesFound.concat(getAllJavaScriptFiles(fullItemPath));
|
|
39
|
+
} else if (item.endsWith('.js')) {
|
|
40
|
+
// Add JavaScript files to results
|
|
41
|
+
filesFound.push(fullItemPath);
|
|
42
|
+
}
|
|
43
|
+
});
|
|
44
|
+
|
|
45
|
+
return filesFound;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
return {
|
|
49
|
+
name: 'sigpro-router',
|
|
50
|
+
|
|
51
|
+
/**
|
|
52
|
+
* Resolves the virtual module ID to our internal ID
|
|
53
|
+
*
|
|
54
|
+
* @param {string} importeeId - The module ID being imported
|
|
55
|
+
* @returns {string|null} The resolved virtual module ID or null
|
|
56
|
+
*/
|
|
57
|
+
resolveId(importeeId) {
|
|
58
|
+
if (importeeId === VIRTUAL_MODULE_ID) return RESOLVED_VIRTUAL_MODULE_ID;
|
|
59
|
+
},
|
|
60
|
+
|
|
61
|
+
/**
|
|
62
|
+
* Generates the virtual module content with route definitions
|
|
63
|
+
*
|
|
64
|
+
* @param {string} moduleId - The resolved module ID being loaded
|
|
65
|
+
* @returns {string|null} Generated module code or null
|
|
66
|
+
*/
|
|
67
|
+
load(moduleId) {
|
|
68
|
+
if (moduleId === RESOLVED_VIRTUAL_MODULE_ID) {
|
|
69
|
+
const PAGES_DIRECTORY = path.resolve(process.cwd(), 'src/pages');
|
|
70
|
+
let pageFiles = getAllJavaScriptFiles(PAGES_DIRECTORY);
|
|
71
|
+
|
|
72
|
+
/**
|
|
73
|
+
* Sort files to prioritize routes:
|
|
74
|
+
* 1. Static routes come before dynamic routes
|
|
75
|
+
* 2. Shorter paths come first (more specific routes)
|
|
76
|
+
*/
|
|
77
|
+
pageFiles = pageFiles.sort((fileA, fileB) => {
|
|
78
|
+
const fileAHasDynamicParam = fileA.includes('[');
|
|
79
|
+
const fileBHasDynamicParam = fileB.includes('[');
|
|
80
|
+
|
|
81
|
+
if (fileAHasDynamicParam !== fileBHasDynamicParam) {
|
|
82
|
+
return fileAHasDynamicParam ? 1 : -1;
|
|
83
|
+
}
|
|
84
|
+
return fileA.length - fileB.length;
|
|
85
|
+
});
|
|
86
|
+
|
|
87
|
+
let importStatements = '';
|
|
88
|
+
let routeDefinitions = 'export const routes = [\n';
|
|
89
|
+
|
|
90
|
+
console.log('\nš [SigPro Router] Generated route map:');
|
|
91
|
+
|
|
92
|
+
pageFiles.forEach((fullFilePath, index) => {
|
|
93
|
+
// Calculate relative path from pages directory
|
|
94
|
+
const relativeFilePath = path.relative(PAGES_DIRECTORY, fullFilePath).replace(/\\/g, '/');
|
|
95
|
+
const fileNameWithoutExtension = relativeFilePath.replace('.js', '');
|
|
96
|
+
const componentVariableName = `Page_${index}`;
|
|
97
|
+
|
|
98
|
+
// Convert file path to URL path
|
|
99
|
+
let urlPath = '/' + fileNameWithoutExtension.toLowerCase();
|
|
100
|
+
if (urlPath.endsWith('/index')) urlPath = urlPath.replace('/index', '') || '/';
|
|
101
|
+
|
|
102
|
+
// Detect if this is a dynamic route (contains [param])
|
|
103
|
+
const isDynamicRoute = urlPath.includes('[') && urlPath.includes(']');
|
|
104
|
+
let finalPathValue = `'${urlPath}'`;
|
|
105
|
+
let parameterName = null;
|
|
106
|
+
|
|
107
|
+
if (isDynamicRoute) {
|
|
108
|
+
// Extract parameter name from brackets (e.g., from [id] extract 'id')
|
|
109
|
+
const parameterMatch = urlPath.match(/\[([^\]]+)\]/);
|
|
110
|
+
parameterName = parameterMatch ? parameterMatch[1] : 'id';
|
|
111
|
+
|
|
112
|
+
/**
|
|
113
|
+
* Convert dynamic route to RegExp with named capture groups
|
|
114
|
+
* Example: /blog/[id] becomes new RegExp("^\\/blog\\/(?<id>[^/]+)$")
|
|
115
|
+
* This allows accessing parameters via match.groups.parameterName
|
|
116
|
+
*/
|
|
117
|
+
const regexPattern = urlPath
|
|
118
|
+
.replace(/\//g, '\\/')
|
|
119
|
+
.replace(/\[([^\]]+)\]/, '(?<$1>[^/]+)'); // Replace [id] with (?<id>[^/]+)
|
|
120
|
+
|
|
121
|
+
finalPathValue = `new RegExp("^${regexPattern}$")`;
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
// Log route information to console
|
|
125
|
+
console.log(` ${isDynamicRoute ? 'š' : 'š'} ${urlPath.padEnd(20)} -> ${relativeFilePath}`);
|
|
126
|
+
|
|
127
|
+
// Generate import statement for this page component
|
|
128
|
+
importStatements += `import ${componentVariableName} from './src/pages/${relativeFilePath}';\n`;
|
|
129
|
+
|
|
130
|
+
// Generate route definition object
|
|
131
|
+
routeDefinitions += ` { path: ${finalPathValue}, component: ${componentVariableName}, isDynamic: ${isDynamicRoute}, paramName: ${parameterName ? `'${parameterName}'` : 'null'} },\n`;
|
|
132
|
+
});
|
|
133
|
+
|
|
134
|
+
routeDefinitions += '];';
|
|
135
|
+
|
|
136
|
+
// Return complete module code
|
|
137
|
+
return `${importStatements}\n${routeDefinitions}`;
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
};
|
|
141
|
+
}
|
package/index.js
ADDED
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
// This is the main entry point of the package
|
|
2
|
+
// Directly exports your plugin from sigpro.js
|
|
3
|
+
|
|
4
|
+
// If your sigpro.js already exports the plugin as default, you can do:
|
|
5
|
+
export { default } from './sigpro.js';
|
|
6
|
+
|
|
7
|
+
// Or if you prefer CommonJS:
|
|
8
|
+
// module.exports = require('./sigpro.js');
|
package/package.json
ADDED
package/sigpro-1.0.0.tgz
ADDED
|
Binary file
|