create-nativecore 0.1.1 → 0.2.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/README.md +6 -14
- package/bin/index.mjs +402 -431
- package/package.json +3 -2
- package/template/.env.example +28 -0
- package/template/.htmlhintrc +14 -0
- package/template/api/data/dashboard.json +11 -0
- package/template/api/data/users.json +18 -0
- package/template/api/mockApi.js +161 -0
- package/template/assets/icon.svg +13 -0
- package/template/assets/logo.svg +25 -0
- package/template/eslint.config.js +94 -0
- package/template/index.html +137 -0
- package/template/manifest.json +19 -0
- package/template/public/.well-known/security.txt +9 -0
- package/template/public/_headers +24 -0
- package/template/public/_redirects +14 -0
- package/template/public/assets/icon.svg +13 -0
- package/template/public/assets/logo.svg +25 -0
- package/template/public/manifest.json +19 -0
- package/template/public/robots.txt +13 -0
- package/template/public/sitemap.xml +27 -0
- package/template/scripts/build-for-bots.mjs +121 -0
- package/template/scripts/convert-to-ts.mjs +106 -0
- package/template/scripts/fix-encoding.mjs +38 -0
- package/template/scripts/fix-svg-paths.mjs +32 -0
- package/template/scripts/generate-cf-router.mjs +52 -0
- package/template/scripts/inject-dev-tools.mjs +41 -0
- package/template/scripts/inject-version.mjs +65 -0
- package/template/scripts/make-component.mjs +445 -0
- package/template/scripts/make-component.mjs.backup +432 -0
- package/template/scripts/make-controller.mjs +119 -0
- package/template/scripts/make-core-component.mjs +303 -0
- package/template/scripts/make-view.mjs +346 -0
- package/template/scripts/minify.mjs +71 -0
- package/template/scripts/prepare-static-assets.mjs +141 -0
- package/template/scripts/prompt-bot-build.mjs +223 -0
- package/template/scripts/remove-component.mjs +170 -0
- package/template/scripts/remove-core-component.mjs +156 -0
- package/template/scripts/remove-dev.mjs +13 -0
- package/template/scripts/remove-view.mjs +200 -0
- package/template/scripts/strip-dev-blocks.mjs +30 -0
- package/template/scripts/watch-compile.mjs +69 -0
- package/template/server.js +1066 -0
- package/template/src/app.ts +115 -0
- package/template/src/components/appRegistry.ts +8 -0
- package/template/src/components/core/app-footer.ts +27 -0
- package/template/src/components/core/app-header.ts +175 -0
- package/template/src/components/core/app-sidebar.ts +238 -0
- package/template/src/components/core/loading-spinner.ts +25 -0
- package/template/src/components/core/nc-a.ts +313 -0
- package/template/src/components/core/nc-accordion.ts +186 -0
- package/template/src/components/core/nc-alert.ts +153 -0
- package/template/src/components/core/nc-animation.ts +1150 -0
- package/template/src/components/core/nc-autocomplete.ts +271 -0
- package/template/src/components/core/nc-avatar-group.ts +113 -0
- package/template/src/components/core/nc-avatar.ts +148 -0
- package/template/src/components/core/nc-badge.ts +86 -0
- package/template/src/components/core/nc-bottom-nav.ts +214 -0
- package/template/src/components/core/nc-breadcrumb.ts +96 -0
- package/template/src/components/core/nc-button.ts +307 -0
- package/template/src/components/core/nc-card.ts +160 -0
- package/template/src/components/core/nc-checkbox.ts +282 -0
- package/template/src/components/core/nc-chip.ts +115 -0
- package/template/src/components/core/nc-code.ts +314 -0
- package/template/src/components/core/nc-collapsible.ts +154 -0
- package/template/src/components/core/nc-color-picker.ts +268 -0
- package/template/src/components/core/nc-copy-button.ts +119 -0
- package/template/src/components/core/nc-date-picker.ts +443 -0
- package/template/src/components/core/nc-div.ts +280 -0
- package/template/src/components/core/nc-divider.ts +81 -0
- package/template/src/components/core/nc-drawer.ts +230 -0
- package/template/src/components/core/nc-dropdown.ts +178 -0
- package/template/src/components/core/nc-empty-state.ts +134 -0
- package/template/src/components/core/nc-file-upload.ts +354 -0
- package/template/src/components/core/nc-form.ts +312 -0
- package/template/src/components/core/nc-image.ts +184 -0
- package/template/src/components/core/nc-input.ts +383 -0
- package/template/src/components/core/nc-kbd.ts +48 -0
- package/template/src/components/core/nc-menu-item.ts +193 -0
- package/template/src/components/core/nc-menu.ts +376 -0
- package/template/src/components/core/nc-modal.ts +238 -0
- package/template/src/components/core/nc-nav-item.ts +151 -0
- package/template/src/components/core/nc-number-input.ts +350 -0
- package/template/src/components/core/nc-otp-input.ts +235 -0
- package/template/src/components/core/nc-pagination.ts +178 -0
- package/template/src/components/core/nc-popover.ts +260 -0
- package/template/src/components/core/nc-progress-circular.ts +119 -0
- package/template/src/components/core/nc-progress.ts +134 -0
- package/template/src/components/core/nc-radio.ts +235 -0
- package/template/src/components/core/nc-rating.ts +266 -0
- package/template/src/components/core/nc-rich-text.ts +283 -0
- package/template/src/components/core/nc-scroll-top.ts +116 -0
- package/template/src/components/core/nc-select.ts +452 -0
- package/template/src/components/core/nc-skeleton.ts +107 -0
- package/template/src/components/core/nc-slider.ts +285 -0
- package/template/src/components/core/nc-snackbar.ts +230 -0
- package/template/src/components/core/nc-splash.ts +343 -0
- package/template/src/components/core/nc-stepper.ts +247 -0
- package/template/src/components/core/nc-switch.ts +281 -0
- package/template/src/components/core/nc-tab-item.ts +138 -0
- package/template/src/components/core/nc-table.ts +279 -0
- package/template/src/components/core/nc-tabs.ts +554 -0
- package/template/src/components/core/nc-tag-input.ts +279 -0
- package/template/src/components/core/nc-textarea.ts +216 -0
- package/template/src/components/core/nc-time-picker.ts +438 -0
- package/template/src/components/core/nc-timeline.ts +186 -0
- package/template/src/components/core/nc-tooltip.ts +143 -0
- package/template/src/components/frameworkRegistry.ts +68 -0
- package/template/src/components/preloadRegistry.ts +28 -0
- package/template/src/components/registry.ts +8 -0
- package/template/src/components/ui/dashboard-signal-lab.ts +284 -0
- package/template/src/constants/apiEndpoints.ts +27 -0
- package/template/src/constants/errorMessages.ts +23 -0
- package/template/src/constants/index.ts +8 -0
- package/template/src/constants/routePaths.ts +15 -0
- package/template/src/constants/storageKeys.ts +18 -0
- package/template/src/controllers/dashboard.controller.ts +200 -0
- package/template/src/controllers/home.controller.ts +21 -0
- package/template/src/controllers/index.ts +11 -0
- package/template/src/controllers/login.controller.ts +131 -0
- package/template/src/core/component.ts +354 -0
- package/template/src/core/errorHandler.ts +85 -0
- package/template/src/core/gpu-animation.ts +604 -0
- package/template/src/core/http.ts +173 -0
- package/template/src/core/lazyComponents.ts +90 -0
- package/template/src/core/router.ts +642 -0
- package/template/src/core/signals.ts +146 -0
- package/template/src/core/state.ts +248 -0
- package/template/src/dev/component-editor.ts +1363 -0
- package/template/src/dev/component-overlay.ts +278 -0
- package/template/src/dev/context-menu.ts +223 -0
- package/template/src/dev/denc-tools.ts +250 -0
- package/template/src/dev/hmr.ts +189 -0
- package/template/src/dev/nfbs.code-workspace +27 -0
- package/template/src/dev/outline-panel.ts +1247 -0
- package/template/src/middleware/auth.middleware.ts +23 -0
- package/template/src/routes/routes.ts +38 -0
- package/template/src/services/api.service.ts +394 -0
- package/template/src/services/auth.service.ts +176 -0
- package/template/src/services/index.ts +8 -0
- package/template/src/services/logger.service.ts +74 -0
- package/template/src/services/storage.service.ts +88 -0
- package/template/src/stores/appStore.ts +57 -0
- package/template/src/stores/uiStore.ts +36 -0
- package/template/src/styles/core-variables.css +219 -0
- package/template/src/styles/core.css +710 -0
- package/template/src/styles/main.css +3164 -0
- package/template/src/styles/variables.css +152 -0
- package/template/src/types/global.d.ts +47 -0
- package/template/src/utils/cacheBuster.ts +20 -0
- package/template/src/utils/dom.ts +149 -0
- package/template/src/utils/events.ts +203 -0
- package/template/src/utils/form.ts +176 -0
- package/template/src/utils/formatters.ts +169 -0
- package/template/src/utils/helpers.ts +195 -0
- package/template/src/utils/markdown.ts +307 -0
- package/template/src/utils/sidebar.ts +96 -0
- package/template/src/utils/smoothScroll.ts +85 -0
- package/template/src/utils/templates.ts +23 -0
- package/template/src/utils/validation.ts +73 -0
- package/template/src/views/protected/dashboard.html +293 -0
- package/template/src/views/public/home.html +150 -0
- package/template/src/views/public/login.html +102 -0
- package/template/tests/unit/component.test.ts +87 -0
- package/template/tests/unit/computed.test.ts +79 -0
- package/template/tests/unit/form.test.ts +68 -0
- package/template/tests/unit/formatters.test.ts +49 -0
- package/template/tests/unit/lazy-components.test.ts +59 -0
- package/template/tests/unit/markdown.test.ts +62 -0
- package/template/tests/unit/router.test.ts +112 -0
- package/template/tests/unit/signals.test.ts +54 -0
- package/template/tests/unit/validation.test.ts +50 -0
- package/template/tsconfig.build.json +21 -0
- package/template/tsconfig.json +51 -0
- package/template/vitest.config.ts +36 -0
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
# robots.txt for nativeCore Framework
|
|
2
|
+
|
|
3
|
+
User-agent: *
|
|
4
|
+
Allow: /
|
|
5
|
+
|
|
6
|
+
# Disallow admin/private areas if any
|
|
7
|
+
# Disallow: /admin/
|
|
8
|
+
|
|
9
|
+
# Sitemap location
|
|
10
|
+
Sitemap: https://yourdomain.com/sitemap.xml
|
|
11
|
+
|
|
12
|
+
# Crawl-delay (optional, adjust as needed)
|
|
13
|
+
Crawl-delay: 1
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
<?xml version="1.0" encoding="UTF-8"?>
|
|
2
|
+
<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
|
|
3
|
+
<url>
|
|
4
|
+
<loc>https://yourdomain.com/</loc>
|
|
5
|
+
<lastmod>2026-01-22</lastmod>
|
|
6
|
+
<changefreq>weekly</changefreq>
|
|
7
|
+
<priority>1.0</priority>
|
|
8
|
+
</url>
|
|
9
|
+
<url>
|
|
10
|
+
<loc>https://yourdomain.com/about</loc>
|
|
11
|
+
<lastmod>2026-01-22</lastmod>
|
|
12
|
+
<changefreq>monthly</changefreq>
|
|
13
|
+
<priority>0.8</priority>
|
|
14
|
+
</url>
|
|
15
|
+
<url>
|
|
16
|
+
<loc>https://yourdomain.com/components</loc>
|
|
17
|
+
<lastmod>2026-01-22</lastmod>
|
|
18
|
+
<changefreq>weekly</changefreq>
|
|
19
|
+
<priority>0.8</priority>
|
|
20
|
+
</url>
|
|
21
|
+
<url>
|
|
22
|
+
<loc>https://yourdomain.com/login</loc>
|
|
23
|
+
<lastmod>2026-01-22</lastmod>
|
|
24
|
+
<changefreq>monthly</changefreq>
|
|
25
|
+
<priority>0.5</priority>
|
|
26
|
+
</url>
|
|
27
|
+
</urlset>
|
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
import puppeteer from 'puppeteer';
|
|
2
|
+
import fs from 'fs';
|
|
3
|
+
import path from 'path';
|
|
4
|
+
import { fileURLToPath } from 'url';
|
|
5
|
+
|
|
6
|
+
const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
|
7
|
+
const distPath = path.join(__dirname, '../dist');
|
|
8
|
+
const botDistPath = path.join(distPath, 'bot');
|
|
9
|
+
|
|
10
|
+
// Routes to pre-render for bots. Keep this to publicly reachable marketing/docs pages.
|
|
11
|
+
const routes = [
|
|
12
|
+
'/',
|
|
13
|
+
'/docs',
|
|
14
|
+
'/components',
|
|
15
|
+
'/login'
|
|
16
|
+
];
|
|
17
|
+
|
|
18
|
+
function sanitizeBotHtml(html) {
|
|
19
|
+
return html
|
|
20
|
+
.replace(/<style>\s*html\[data-public-route="pending"\] body \{[\s\S]*?<\/style>/, '<style>html[data-public-route] body { visibility: visible; opacity: 1; }</style>')
|
|
21
|
+
.replace(/data-public-route="pending"/g, 'data-public-route="ready"')
|
|
22
|
+
.replace(/<script>\s*\(function\(\) \{[\s\S]*?document\.documentElement\.setAttribute\('data-public-route', 'ready'\);\s*\}\)\(\);\s*<\/script>/, '')
|
|
23
|
+
.replace(/<script>\s*\(function\(\) \{[\s\S]*?document\.write\(`<link rel="stylesheet" href="\/src\/styles\/main\.css\?v=\$\{version\}">`\);\s*\}\)\(\);\s*<\/script>/, '')
|
|
24
|
+
.replace(/<script type="module">\s*\(function\(\) \{[\s\S]*?import\(`\/dist\/app\.js\?v=\$\{version\}`\);\s*\}\)\(\);\s*<\/script>/, '')
|
|
25
|
+
.replace(/<script defer="" src="https:\/\/static\.cloudflareinsights\.com\/beacon[^>]*><\/script>/g, '');
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
async function buildForBots() {
|
|
29
|
+
console.log('🤖 Building bot-optimized HTML...\n');
|
|
30
|
+
|
|
31
|
+
fs.rmSync(botDistPath, { recursive: true, force: true });
|
|
32
|
+
fs.mkdirSync(botDistPath, { recursive: true });
|
|
33
|
+
|
|
34
|
+
let browser;
|
|
35
|
+
|
|
36
|
+
try {
|
|
37
|
+
// Launch headless browser
|
|
38
|
+
console.log('🚀 Starting headless browser...');
|
|
39
|
+
browser = await puppeteer.launch({
|
|
40
|
+
headless: 'new',
|
|
41
|
+
args: ['--no-sandbox', '--disable-setuid-sandbox']
|
|
42
|
+
});
|
|
43
|
+
|
|
44
|
+
const page = await browser.newPage();
|
|
45
|
+
|
|
46
|
+
// Process each route
|
|
47
|
+
for (const route of routes) {
|
|
48
|
+
console.log(`📄 Rendering ${route}...`);
|
|
49
|
+
|
|
50
|
+
try {
|
|
51
|
+
// Navigate to the page
|
|
52
|
+
await page.goto(`http://localhost:8000${route}`, {
|
|
53
|
+
waitUntil: 'networkidle0',
|
|
54
|
+
timeout: 30000
|
|
55
|
+
});
|
|
56
|
+
|
|
57
|
+
// Wait a bit for any animations/dynamic content
|
|
58
|
+
await new Promise(resolve => setTimeout(resolve, 1000));
|
|
59
|
+
|
|
60
|
+
// Get the rendered HTML
|
|
61
|
+
const html = sanitizeBotHtml(await page.content());
|
|
62
|
+
|
|
63
|
+
// Determine output path
|
|
64
|
+
let outputPath;
|
|
65
|
+
if (route === '/') {
|
|
66
|
+
outputPath = path.join(botDistPath, 'index.html');
|
|
67
|
+
} else {
|
|
68
|
+
// Create directory for route
|
|
69
|
+
const routeDir = path.join(botDistPath, route);
|
|
70
|
+
if (!fs.existsSync(routeDir)) {
|
|
71
|
+
fs.mkdirSync(routeDir, { recursive: true });
|
|
72
|
+
}
|
|
73
|
+
outputPath = path.join(routeDir, 'index.html');
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
// Write HTML file
|
|
77
|
+
fs.writeFileSync(outputPath, html);
|
|
78
|
+
|
|
79
|
+
console.log(` ✅ Saved to ${outputPath.replace(distPath, 'dist')}`);
|
|
80
|
+
} catch (error) {
|
|
81
|
+
console.error(` ❌ Failed to render ${route}:`, error.message);
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
console.log('\n✨ Bot build complete!');
|
|
86
|
+
console.log(`📦 Bot-optimized files in: dist/bot/`);
|
|
87
|
+
console.log(`📦 Publishable bot files will be copied into: _deploy/bot/ during prepare-static-assets`);
|
|
88
|
+
console.log(`🔍 Search engines will now see pre-rendered HTML\n`);
|
|
89
|
+
|
|
90
|
+
} catch (error) {
|
|
91
|
+
console.error('❌ Bot build failed:', error);
|
|
92
|
+
process.exit(1);
|
|
93
|
+
} finally {
|
|
94
|
+
if (browser) {
|
|
95
|
+
await browser.close();
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
// Check if dev server is running
|
|
101
|
+
async function checkDevServer() {
|
|
102
|
+
try {
|
|
103
|
+
const response = await fetch('http://localhost:8000');
|
|
104
|
+
return response.ok;
|
|
105
|
+
} catch {
|
|
106
|
+
return false;
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
// Main execution
|
|
111
|
+
(async () => {
|
|
112
|
+
const serverRunning = await checkDevServer();
|
|
113
|
+
|
|
114
|
+
if (!serverRunning) {
|
|
115
|
+
console.error('❌ Dev server is not running on http://localhost:8000');
|
|
116
|
+
console.error('💡 Please run `npm start` in another terminal first\n');
|
|
117
|
+
process.exit(1);
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
await buildForBots();
|
|
121
|
+
})();
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* TypeScript Conversion Helper
|
|
4
|
+
* Converts all remaining .js files to .ts with basic type annotations
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import fs from 'fs';
|
|
8
|
+
import path from 'path';
|
|
9
|
+
import { fileURLToPath } from 'url';
|
|
10
|
+
|
|
11
|
+
const __filename = fileURLToPath(import.meta.url);
|
|
12
|
+
const __dirname = path.dirname(__filename);
|
|
13
|
+
|
|
14
|
+
const srcDir = path.join(__dirname, '..', 'src');
|
|
15
|
+
|
|
16
|
+
// Files to skip (already converted or special cases)
|
|
17
|
+
const skipFiles = new Set([
|
|
18
|
+
'state.ts', 'component.ts', 'router.ts', 'http.ts',
|
|
19
|
+
'auth.service.ts', 'api.service.ts', 'storage.service.ts'
|
|
20
|
+
]);
|
|
21
|
+
|
|
22
|
+
// Basic type inference rules
|
|
23
|
+
const typeInference = {
|
|
24
|
+
'const.*=.*\\[\\]': 'any[]',
|
|
25
|
+
'const.*=.*\\{\\}': 'Record<string, any>',
|
|
26
|
+
'const.*=.*useState\\(': 'State',
|
|
27
|
+
'const.*=.*computed\\(': 'ComputedState',
|
|
28
|
+
};
|
|
29
|
+
|
|
30
|
+
function convertJsToTs(content) {
|
|
31
|
+
let tsContent = content;
|
|
32
|
+
|
|
33
|
+
// Remove .js extensions from imports
|
|
34
|
+
tsContent = tsContent.replace(/from ['"](.*)\.js['"]/g, "from '$1'");
|
|
35
|
+
|
|
36
|
+
// Add basic type annotations to function parameters
|
|
37
|
+
tsContent = tsContent.replace(
|
|
38
|
+
/function\s+(\w+)\s*\(([^)]*)\)/g,
|
|
39
|
+
(match, funcName, params) => {
|
|
40
|
+
const typedParams = params
|
|
41
|
+
.split(',')
|
|
42
|
+
.map(p => p.trim())
|
|
43
|
+
.filter(p => p)
|
|
44
|
+
.map(p => {
|
|
45
|
+
if (p.includes('=')) {
|
|
46
|
+
const [name, defaultValue] = p.split('=').map(s => s.trim());
|
|
47
|
+
return `${name}: any = ${defaultValue}`;
|
|
48
|
+
}
|
|
49
|
+
return `${p}: any`;
|
|
50
|
+
})
|
|
51
|
+
.join(', ');
|
|
52
|
+
return `function ${funcName}(${typedParams})`;
|
|
53
|
+
}
|
|
54
|
+
);
|
|
55
|
+
|
|
56
|
+
// Add void return types to functions without returns
|
|
57
|
+
tsContent = tsContent.replace(
|
|
58
|
+
/(function\s+\w+\([^)]*\))\s*\{/g,
|
|
59
|
+
'$1: void {'
|
|
60
|
+
);
|
|
61
|
+
|
|
62
|
+
return tsContent;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
function processFile(filePath) {
|
|
66
|
+
const ext = path.extname(filePath);
|
|
67
|
+
const basename = path.basename(filePath);
|
|
68
|
+
|
|
69
|
+
if (ext !== '.js' || skipFiles.has(basename)) {
|
|
70
|
+
return;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
const content = fs.readFileSync(filePath, 'utf-8');
|
|
74
|
+
const tsContent = convertJsToTs(content);
|
|
75
|
+
const tsPath = filePath.replace(/\.js$/, '.ts');
|
|
76
|
+
|
|
77
|
+
fs.writeFileSync(tsPath, tsContent, 'utf-8');
|
|
78
|
+
console.log(`✅ Converted: ${path.relative(srcDir, filePath)} → ${path.basename(tsPath)}`);
|
|
79
|
+
|
|
80
|
+
// Delete old .js file
|
|
81
|
+
fs.unlinkSync(filePath);
|
|
82
|
+
console.log(`🗑️ Deleted: ${path.relative(srcDir, filePath)}`);
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
function walkDir(dir) {
|
|
86
|
+
const files = fs.readdirSync(dir);
|
|
87
|
+
|
|
88
|
+
for (const file of files) {
|
|
89
|
+
const filePath = path.join(dir, file);
|
|
90
|
+
const stat = fs.statSync(filePath);
|
|
91
|
+
|
|
92
|
+
if (stat.isDirectory()) {
|
|
93
|
+
walkDir(filePath);
|
|
94
|
+
} else if (stat.isFile()) {
|
|
95
|
+
processFile(filePath);
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
console.log('🚀 Starting TypeScript conversion...\n');
|
|
101
|
+
walkDir(srcDir);
|
|
102
|
+
console.log('\n✨ Conversion complete!');
|
|
103
|
+
console.log('\n📝 Next steps:');
|
|
104
|
+
console.log(' 1. Run: npm run typecheck');
|
|
105
|
+
console.log(' 2. Fix any type errors');
|
|
106
|
+
console.log(' 3. Add proper type annotations to converted files');
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import { readFileSync, writeFileSync } from 'fs';
|
|
2
|
+
|
|
3
|
+
// Map: corrupted string → correct character/entity
|
|
4
|
+
// These are Windows-1252 bytes re-interpreted as UTF-8 mojibake
|
|
5
|
+
const fixes = [
|
|
6
|
+
// Special HTML chars — use entities so files stay ASCII-safe
|
|
7
|
+
['src/components/ui/nc-alert.ts', '\u00c3\u00b7', '×'],
|
|
8
|
+
['src/components/ui/nc-modal.ts', '\u00c3\u00b7', '×'],
|
|
9
|
+
['src/components/ui/nc-pagination.ts', '\u00c2\u00ab', '«'],
|
|
10
|
+
['src/components/ui/nc-pagination.ts', '\u00e2\u20ac\u00b9','‹'],
|
|
11
|
+
['src/components/ui/nc-pagination.ts', '\u00e2\u20ac\u00a6','…'],
|
|
12
|
+
['src/components/ui/nc-pagination.ts', '\u00e2\u20ac\u00ba','›'],
|
|
13
|
+
['src/components/ui/nc-pagination.ts', '\u00c2\u00bb', '»'],
|
|
14
|
+
// em dash in comment
|
|
15
|
+
['src/components/core/app-sidebar.ts', '\u00e2\u20ac\u201c', '\u2014'],
|
|
16
|
+
// Dashboard emojis — restore real UTF-8 emoji codepoints
|
|
17
|
+
['src/views/protected/dashboard.html', '\u00f0\u0178\u201c\u201c', '\uD83D\uDD04'], // 🔄
|
|
18
|
+
['src/views/protected/dashboard.html', '\u00e2\u017e\u2022', '\u2795'], // ➕
|
|
19
|
+
['src/views/protected/dashboard.html', '\u00f0\u0178\u201c\u0160', '\uD83D\uDCCA'], // 📊
|
|
20
|
+
['src/views/protected/dashboard.html', '\u00e2\u0161\u2122\u00ef\u00b8\u008f', '\u2699\uFE0F'], // ⚙️
|
|
21
|
+
['src/views/protected/dashboard.html', '\u00f0\u0178\u2019\u00a5', '\uD83D\uDC65'], // 👥
|
|
22
|
+
['src/views/protected/dashboard.html', '\u00f0\u0178\u201c\u02c6', '\uD83D\uDCC8'], // 📈
|
|
23
|
+
['src/views/protected/dashboard.html', '\u00e2\u0153\u2026', '\u2705'], // ✅
|
|
24
|
+
// Components page emojis
|
|
25
|
+
['src/views/public/components.html', '\u00f0\u0178\u201c\u00a7', '\uD83D\uDD27'], // 🔧
|
|
26
|
+
['src/views/public/components.html', '\u00e2\u00ad\u00ad', '\u2B50'], // ⭐
|
|
27
|
+
['src/views/public/components.html', '\u00f0\u0178\u201c\u00a4', '\uD83D\uDCE4'], // 📤
|
|
28
|
+
['src/views/public/components.html', '\u00f0\u0178\u2014\u2018\u00ef\u00b8\u008f', '\uD83D\uDDD1\uFE0F'], // 🗑️
|
|
29
|
+
];
|
|
30
|
+
|
|
31
|
+
for (const [file, bad, good] of fixes) {
|
|
32
|
+
const content = readFileSync(file, 'utf8');
|
|
33
|
+
if (content.includes(bad)) {
|
|
34
|
+
writeFileSync(file, content.split(bad).join(good), 'utf8');
|
|
35
|
+
console.log(`Fixed ${file} ${JSON.stringify(bad)} -> ${JSON.stringify(good)}`);
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
console.log('Encoding fix complete.');
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { readFileSync, writeFileSync } from 'fs';
|
|
2
|
+
|
|
3
|
+
const files = [
|
|
4
|
+
'src/components/ui/nc-fab.ts',
|
|
5
|
+
'src/components/ui/nc-file-upload.ts',
|
|
6
|
+
'src/components/ui/nc-icon-button.ts',
|
|
7
|
+
'src/components/ui/nc-icon.ts',
|
|
8
|
+
'src/components/ui/nc-menu-item.ts',
|
|
9
|
+
'src/dev/outline-panel.ts',
|
|
10
|
+
];
|
|
11
|
+
|
|
12
|
+
const svgCtxMarkers = [' d=', '<path', '<polyline', '<polygon', '<svg', '"M', "'M"];
|
|
13
|
+
|
|
14
|
+
for (const file of files) {
|
|
15
|
+
const orig = readFileSync(file, 'utf8');
|
|
16
|
+
let c = orig;
|
|
17
|
+
|
|
18
|
+
// Replace digit/space + nc- + digit back to v- only in SVG path contexts
|
|
19
|
+
c = c.replace(/([0-9 ])nc-([0-9])/g, (match, before, after, offset) => {
|
|
20
|
+
const ctx = orig.substring(Math.max(0, offset - 80), offset + 80);
|
|
21
|
+
const inSvg = svgCtxMarkers.some(m => ctx.includes(m));
|
|
22
|
+
return inSvg ? before + 'v-' + after : match;
|
|
23
|
+
});
|
|
24
|
+
|
|
25
|
+
if (c !== orig) {
|
|
26
|
+
writeFileSync(file, c, 'utf8');
|
|
27
|
+
console.log('Fixed:', file);
|
|
28
|
+
} else {
|
|
29
|
+
console.log('No change:', file);
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
console.log('Done');
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
import fs from 'fs';
|
|
4
|
+
import path from 'path';
|
|
5
|
+
import { fileURLToPath } from 'url';
|
|
6
|
+
|
|
7
|
+
const __filename = fileURLToPath(import.meta.url);
|
|
8
|
+
const __dirname = path.dirname(__filename);
|
|
9
|
+
|
|
10
|
+
const routesPath = path.resolve(__dirname, '..', 'src', 'routes', 'routes.ts');
|
|
11
|
+
const redirectsPath = path.resolve(__dirname, '..', 'public', '_redirects');
|
|
12
|
+
|
|
13
|
+
export function extractProtectedRoutes(routesSource) {
|
|
14
|
+
const match = routesSource.match(/export const protectedRoutes = \[(.*?)\];/s);
|
|
15
|
+
|
|
16
|
+
if (!match) {
|
|
17
|
+
throw new Error('Could not find protectedRoutes export in src/routes/routes.ts');
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
return Array.from(match[1].matchAll(/['"]([^'"]+)['"]/g), routeMatch => routeMatch[1]);
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
export function extractRegisteredRoutes(routesSource) {
|
|
24
|
+
return Array.from(routesSource.matchAll(/\.register\(\s*['"]([^'"]+)['"]/g), match => match[1]);
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
export function renderCfRouter(protectedRoutes, registeredRoutes) {
|
|
28
|
+
const routeRules = registeredRoutes
|
|
29
|
+
.filter(route => route !== '/')
|
|
30
|
+
.flatMap(route => {
|
|
31
|
+
const variants = route.endsWith('/') ? [route] : [route, `${route}/`];
|
|
32
|
+
return variants.map(routeVariant => `${routeVariant} / 200`);
|
|
33
|
+
});
|
|
34
|
+
|
|
35
|
+
return [
|
|
36
|
+
...routeRules
|
|
37
|
+
].join('\n') + '\n';
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
export function generateCfRouter() {
|
|
41
|
+
const routesSource = fs.readFileSync(routesPath, 'utf8');
|
|
42
|
+
const protectedRoutes = extractProtectedRoutes(routesSource);
|
|
43
|
+
const registeredRoutes = extractRegisteredRoutes(routesSource);
|
|
44
|
+
const output = renderCfRouter(protectedRoutes, registeredRoutes);
|
|
45
|
+
|
|
46
|
+
fs.writeFileSync(redirectsPath, output);
|
|
47
|
+
console.log(`Updated: ${path.relative(path.resolve(__dirname, '..'), redirectsPath).replace(/\\/g, '/')}`);
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
if (process.argv[1] && path.resolve(process.argv[1]) === __filename) {
|
|
51
|
+
generateCfRouter();
|
|
52
|
+
}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
// scripts/inject-denc-tools.mjs
|
|
2
|
+
// Inject denc-tools script into HTML files for development
|
|
3
|
+
import { readFile, writeFile } from 'fs/promises';
|
|
4
|
+
import { resolve } from 'path';
|
|
5
|
+
|
|
6
|
+
const files = ['index.html'];
|
|
7
|
+
const devScripts = ` <!-- DEnc-ONLY-START -->
|
|
8
|
+
<!-- Hot Module Replacement (HMR) - Development Only -->
|
|
9
|
+
<script type="module" src="/src/dev/hmr.js"></script>
|
|
10
|
+
<script type="module" src="/dist/dev/denc-tools.js"></script>
|
|
11
|
+
<!-- DEnc-ONLY-END -->`;
|
|
12
|
+
|
|
13
|
+
async function injectDevTools(file) {
|
|
14
|
+
try {
|
|
15
|
+
const path = resolve(process.cwd(), file);
|
|
16
|
+
let html = await readFile(path, 'utf8');
|
|
17
|
+
|
|
18
|
+
// Check if denc-tools already injected
|
|
19
|
+
if (html.includes('dist/dev/denc-tools.js')) {
|
|
20
|
+
console.log(`✓ Dev scripts already injected in ${file}`);
|
|
21
|
+
return;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
// Find the injection marker
|
|
25
|
+
const marker = '<!--- inject here --->';
|
|
26
|
+
if (html.includes(marker)) {
|
|
27
|
+
html = html.replace(marker, devScripts);
|
|
28
|
+
await writeFile(path, html, 'utf8');
|
|
29
|
+
console.log(`✓ Injected dev scripts (HMR + denc-tools) into ${file}`);
|
|
30
|
+
} else {
|
|
31
|
+
console.warn(`⚠️ No injection marker found in ${file}`);
|
|
32
|
+
}
|
|
33
|
+
} catch (error) {
|
|
34
|
+
console.error(`✗ Failed to inject denc-tools into ${file}:`, error.message);
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
(async () => {
|
|
39
|
+
console.log('🔧 Injecting dev scripts (HMR + denc-tools) for development...\n');
|
|
40
|
+
await Promise.all(files.map(injectDevTools));
|
|
41
|
+
})();
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Version Injection Script
|
|
3
|
+
* Automatically injects package.json version into cache buster
|
|
4
|
+
*/
|
|
5
|
+
import fs from 'fs';
|
|
6
|
+
import path from 'path';
|
|
7
|
+
import { fileURLToPath } from 'url';
|
|
8
|
+
|
|
9
|
+
const __filename = fileURLToPath(import.meta.url);
|
|
10
|
+
const __dirname = path.dirname(__filename);
|
|
11
|
+
|
|
12
|
+
// Read package.json
|
|
13
|
+
const packageJson = JSON.parse(
|
|
14
|
+
fs.readFileSync(path.join(__dirname, '../package.json'), 'utf-8')
|
|
15
|
+
);
|
|
16
|
+
|
|
17
|
+
const packageVersion = packageJson.version;
|
|
18
|
+
const githubRunId = process.env.GITHUB_RUN_ID;
|
|
19
|
+
const githubRunAttempt = process.env.GITHUB_RUN_ATTEMPT;
|
|
20
|
+
const gitSha = process.env.GITHUB_SHA?.slice(0, 8);
|
|
21
|
+
const timestamp = new Date().toISOString().replace(/[-:TZ.]/g, '').slice(0, 14);
|
|
22
|
+
const deployVersion = githubRunId
|
|
23
|
+
? `${packageVersion}-${githubRunId}-${githubRunAttempt || '1'}`
|
|
24
|
+
: gitSha
|
|
25
|
+
? `${packageVersion}-${gitSha}`
|
|
26
|
+
: `${packageVersion}-${timestamp}`;
|
|
27
|
+
|
|
28
|
+
function replaceOrThrow(content, pattern, replacement, fileLabel) {
|
|
29
|
+
const matched = content.match(pattern);
|
|
30
|
+
|
|
31
|
+
if (!matched) {
|
|
32
|
+
throw new Error(`Failed to inject deploy version into ${fileLabel}`);
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
return content.replace(pattern, replacement);
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
// Update cacheBuster.ts
|
|
39
|
+
const cacheBusterPath = path.join(__dirname, '../src/utils/cacheBuster.ts');
|
|
40
|
+
let cacheBusterContent = fs.readFileSync(cacheBusterPath, 'utf-8');
|
|
41
|
+
|
|
42
|
+
cacheBusterContent = replaceOrThrow(
|
|
43
|
+
cacheBusterContent,
|
|
44
|
+
/export const cacheVersion = isDevelopment[\s\S]*?;/,
|
|
45
|
+
`export const cacheVersion = isDevelopment\n ? Date.now()\n : '${deployVersion}';`,
|
|
46
|
+
'src/utils/cacheBuster.ts'
|
|
47
|
+
);
|
|
48
|
+
|
|
49
|
+
fs.writeFileSync(cacheBusterPath, cacheBusterContent);
|
|
50
|
+
|
|
51
|
+
for (const htmlFileName of ['index.html']) {
|
|
52
|
+
const htmlPath = path.join(__dirname, `../${htmlFileName}`);
|
|
53
|
+
let htmlContent = fs.readFileSync(htmlPath, 'utf-8');
|
|
54
|
+
|
|
55
|
+
htmlContent = replaceOrThrow(
|
|
56
|
+
htmlContent,
|
|
57
|
+
/const version = isDev \? Date\.now\(\) : '[^']+';/g,
|
|
58
|
+
`const version = isDev ? Date.now() : '${deployVersion}';`,
|
|
59
|
+
htmlFileName
|
|
60
|
+
);
|
|
61
|
+
|
|
62
|
+
fs.writeFileSync(htmlPath, htmlContent);
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
console.log(`Deploy version ${deployVersion} injected successfully!`);
|