@skalfa/skalfa-app 1.0.1 → 1.0.3
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 +1 -1
- package/bun.lock +34 -24
- package/package.json +4 -5
- package/utils/commands/skalfa.ts +3 -0
- package/blueprints/starter.blueprint.json +0 -103
- package/langs/index.ts +0 -1
- package/langs/validation.langs.ts +0 -17
- package/utils/commands/barrels.ts +0 -28
- package/utils/commands/blueprint.ts +0 -421
- package/utils/commands/light.ts +0 -21
- package/utils/commands/logger.ts +0 -42
- package/utils/commands/stubs/table-blueprint.stub +0 -13
- package/utils/commands/use-pdf.ts +0 -29
package/README.md
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
<p align="center">
|
|
2
|
-
<img src="https://
|
|
2
|
+
<img src="https://skalfa.sejedigital.com/images/logo-skalfa.png" alt="Skalfa Logo" width="300" />
|
|
3
3
|
</p>
|
|
4
4
|
|
|
5
5
|
# @skalfa/skalfa-app
|
package/bun.lock
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
"configVersion": 0,
|
|
4
4
|
"workspaces": {
|
|
5
5
|
"": {
|
|
6
|
-
"name": "
|
|
6
|
+
"name": "@skalfa/skalfa-app",
|
|
7
7
|
"dependencies": {
|
|
8
8
|
"@fortawesome/fontawesome-svg-core": "^6.7.2",
|
|
9
9
|
"@fortawesome/free-brands-svg-icons": "^6.7.2",
|
|
@@ -11,7 +11,7 @@
|
|
|
11
11
|
"@fortawesome/free-solid-svg-icons": "^6.7.2",
|
|
12
12
|
"@fortawesome/react-fontawesome": "^0.2.2",
|
|
13
13
|
"@react-google-maps/api": "^2.20.7",
|
|
14
|
-
"@skalfa/skalfa-app-core": "^1.0.
|
|
14
|
+
"@skalfa/skalfa-app-core": "^1.0.3",
|
|
15
15
|
"@tailwindcss/postcss": "^4.0.0",
|
|
16
16
|
"axios": "^1.12.0",
|
|
17
17
|
"moment": "^2.30.1",
|
|
@@ -41,9 +41,9 @@
|
|
|
41
41
|
|
|
42
42
|
"@emnapi/runtime": ["@emnapi/runtime@1.7.1", "", { "dependencies": { "tslib": "^2.4.0" } }, "sha512-PVtJr5CmLwYAU9PZDMITZoR5iAOShYREoR45EyyLrbntV50mdePTgUn4AmOw90Ifcj+x2kRjdzr1HP3RrNiHGA=="],
|
|
43
43
|
|
|
44
|
-
"@eslint-community/eslint-utils": ["@eslint-community/eslint-utils@4.
|
|
44
|
+
"@eslint-community/eslint-utils": ["@eslint-community/eslint-utils@4.9.1", "", { "dependencies": { "eslint-visitor-keys": "^3.4.3" }, "peerDependencies": { "eslint": "^6.0.0 || ^7.0.0 || >=8.0.0" } }, "sha512-phrYmNiYppR7znFEdqgfWHXR6NCkZEK7hwWDHZUjit/2/U0r6XvkDl0SYnoM51Hq7FhCGdLDT6zxCCOY1hexsQ=="],
|
|
45
45
|
|
|
46
|
-
"@eslint-community/regexpp": ["@eslint-community/regexpp@4.12.
|
|
46
|
+
"@eslint-community/regexpp": ["@eslint-community/regexpp@4.12.2", "", {}, "sha512-EriSTlt5OC9/7SXkRSCAhfSxxoSUgBm33OH+IkwbdpgoqsSsUg7y3uh+IICI/Qg4BBWr3U2i39RpmycbxMq4ew=="],
|
|
47
47
|
|
|
48
48
|
"@eslint/config-array": ["@eslint/config-array@0.19.1", "", { "dependencies": { "@eslint/object-schema": "^2.1.5", "debug": "^4.3.1", "minimatch": "^3.1.2" } }, "sha512-fo6Mtm5mWyKjA/Chy1BYTdn5mGJoDNjC7C64ug20ADsRDGrA85bN3uK3MaKbeRkRuuIEAR5N33Jr1pbm411/PA=="],
|
|
49
49
|
|
|
@@ -169,7 +169,7 @@
|
|
|
169
169
|
|
|
170
170
|
"@rushstack/eslint-patch": ["@rushstack/eslint-patch@1.10.5", "", {}, "sha512-kkKUDVlII2DQiKy7UstOR1ErJP8kUKAQ4oa+SQtM0K+lPdmmjj0YnnxBgtTVYH7mUKtbsxeFC9y0AmK7Yb78/A=="],
|
|
171
171
|
|
|
172
|
-
"@skalfa/skalfa-app-core": ["@skalfa/skalfa-app-core@1.0.
|
|
172
|
+
"@skalfa/skalfa-app-core": ["@skalfa/skalfa-app-core@1.0.3", "", { "dependencies": { "axios": "^1.12.0", "clsx": "^2.1.1", "crypto-js": "^4.2.0", "js-cookie": "^3.0.5", "lz-string": "^1.5.0", "moment": "^2.30.1", "tailwind-merge": "^3.0.2", "validator": "^13.15.22" }, "peerDependencies": { "next": "^15.0.0 || ^16.0.0", "react": "^19.0.0", "react-dom": "^19.0.0" } }, "sha512-nEGXFnXxyvwzQvcGY3gBOjFHYyvhIYoLLGetQ3p7sC2I31Ase/BkoseEYkC5vEAefep9OVxiLD6IsJKSDQ3VeQ=="],
|
|
173
173
|
|
|
174
174
|
"@swc/helpers": ["@swc/helpers@0.5.15", "", { "dependencies": { "tslib": "^2.8.0" } }, "sha512-JQ5TuMi45Owi4/BIMAJBoSQoOJu12oOk/gADqlcUL9JEdHB8vyjUSsxqeNXnmXHjYKMi2WcYtezGEEhqUI/E2g=="],
|
|
175
175
|
|
|
@@ -219,21 +219,25 @@
|
|
|
219
219
|
|
|
220
220
|
"@types/yargs-parser": ["@types/yargs-parser@21.0.3", "", {}, "sha512-I4q9QU9MQv4oEOz4tAHJtNz1cwuLxn2F3xcc2iV5WdqLPpUnj30aUuxt1mAxYTG+oe8CZMV/+6rU4S4gRDzqtQ=="],
|
|
221
221
|
|
|
222
|
-
"@typescript-eslint/eslint-plugin": ["@typescript-eslint/eslint-plugin@8.
|
|
222
|
+
"@typescript-eslint/eslint-plugin": ["@typescript-eslint/eslint-plugin@8.62.1", "", { "dependencies": { "@eslint-community/regexpp": "^4.12.2", "@typescript-eslint/scope-manager": "8.62.1", "@typescript-eslint/type-utils": "8.62.1", "@typescript-eslint/utils": "8.62.1", "@typescript-eslint/visitor-keys": "8.62.1", "ignore": "^7.0.5", "natural-compare": "^1.4.0", "ts-api-utils": "^2.5.0" }, "peerDependencies": { "@typescript-eslint/parser": "^8.62.1", "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", "typescript": ">=4.8.4 <6.1.0" } }, "sha512-4EQM77WgVNxj7OkL/5b/D/xZsw00G577+UriYTC7JF5opcF3T2AuoeY7ueLaZgSVjSgCS6yOAJB5bRGLPSJUzA=="],
|
|
223
223
|
|
|
224
|
-
"@typescript-eslint/parser": ["@typescript-eslint/parser@8.
|
|
224
|
+
"@typescript-eslint/parser": ["@typescript-eslint/parser@8.62.1", "", { "dependencies": { "@typescript-eslint/scope-manager": "8.62.1", "@typescript-eslint/types": "8.62.1", "@typescript-eslint/typescript-estree": "8.62.1", "@typescript-eslint/visitor-keys": "8.62.1", "debug": "^4.4.3" }, "peerDependencies": { "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", "typescript": ">=4.8.4 <6.1.0" } }, "sha512-sPhE4iHuJDSvoAiec+Ro8JyXw8f0ql13HFR82P99nCm9GwTEKG0KYLvDe6REk8BCXuit6vJAv/Yxg5ABaNS2rA=="],
|
|
225
225
|
|
|
226
|
-
"@typescript-eslint/
|
|
226
|
+
"@typescript-eslint/project-service": ["@typescript-eslint/project-service@8.62.1", "", { "dependencies": { "@typescript-eslint/tsconfig-utils": "^8.62.1", "@typescript-eslint/types": "^8.62.1", "debug": "^4.4.3" }, "peerDependencies": { "typescript": ">=4.8.4 <6.1.0" } }, "sha512-yQ3RgY5RkSBpsNS1Bx/JQEcA24FOSdfGktoyprAr5u18390UQdtVcfnEv4nIrIshNnavlVyZBKxQwT1fIAE6cg=="],
|
|
227
227
|
|
|
228
|
-
"@typescript-eslint/
|
|
228
|
+
"@typescript-eslint/scope-manager": ["@typescript-eslint/scope-manager@8.62.1", "", { "dependencies": { "@typescript-eslint/types": "8.62.1", "@typescript-eslint/visitor-keys": "8.62.1" } }, "sha512-r4d249KbQ1SFdpeStvob8Ih6aPPIzfqllPVOtvhve6ZcpuVcYo5/7zUWckKpHE7StASX4kTKZTLf0WQm/wPkcg=="],
|
|
229
229
|
|
|
230
|
-
"@typescript-eslint/
|
|
230
|
+
"@typescript-eslint/tsconfig-utils": ["@typescript-eslint/tsconfig-utils@8.62.1", "", { "peerDependencies": { "typescript": ">=4.8.4 <6.1.0" } }, "sha512-xadytJqX9vJVQ2fdQjkcIVigwaOJNWkpjdLt6cEQ+xPnrI1fkp+/jZE/I97k9KUjqtpd25i0HeyZf3T6dutv2g=="],
|
|
231
231
|
|
|
232
|
-
"@typescript-eslint/
|
|
232
|
+
"@typescript-eslint/type-utils": ["@typescript-eslint/type-utils@8.62.1", "", { "dependencies": { "@typescript-eslint/types": "8.62.1", "@typescript-eslint/typescript-estree": "8.62.1", "@typescript-eslint/utils": "8.62.1", "debug": "^4.4.3", "ts-api-utils": "^2.5.0" }, "peerDependencies": { "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", "typescript": ">=4.8.4 <6.1.0" } }, "sha512-aXM5xlqXiTxPibXB93cLAURfT3rlizf7uMXISCXy66Isr/9hISJx3yDsKl0L7lKa51b8JpFuNKby0/O0pEm9jg=="],
|
|
233
233
|
|
|
234
|
-
"@typescript-eslint/
|
|
234
|
+
"@typescript-eslint/types": ["@typescript-eslint/types@8.62.1", "", {}, "sha512-ooCzJFaf+Hg+uG6fA3NRFGuFjlfNlDhBthbv4ZPU/0elCAFUfnyXUvf/WOpHz/jYwSmvU2GkR2LtyUfy1AxZ1Q=="],
|
|
235
235
|
|
|
236
|
-
"@typescript-eslint/
|
|
236
|
+
"@typescript-eslint/typescript-estree": ["@typescript-eslint/typescript-estree@8.62.1", "", { "dependencies": { "@typescript-eslint/project-service": "8.62.1", "@typescript-eslint/tsconfig-utils": "8.62.1", "@typescript-eslint/types": "8.62.1", "@typescript-eslint/visitor-keys": "8.62.1", "debug": "^4.4.3", "minimatch": "^10.2.2", "semver": "^7.7.3", "tinyglobby": "^0.2.15", "ts-api-utils": "^2.5.0" }, "peerDependencies": { "typescript": ">=4.8.4 <6.1.0" } }, "sha512-xMcW9oP9u7fAMXYs9A65CVmtLQe2r//oXINHfi8HV+oiqhih17sbLdhXr4540YWlgpDKQdY854OL5ZrdCiQsAA=="],
|
|
237
|
+
|
|
238
|
+
"@typescript-eslint/utils": ["@typescript-eslint/utils@8.62.1", "", { "dependencies": { "@eslint-community/eslint-utils": "^4.9.1", "@typescript-eslint/scope-manager": "8.62.1", "@typescript-eslint/types": "8.62.1", "@typescript-eslint/typescript-estree": "8.62.1" }, "peerDependencies": { "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", "typescript": ">=4.8.4 <6.1.0" } }, "sha512-sHtbPfuKNZCG+ih8SyjjucqRntSVmp8XgL5u6o9mAhiSn8ds5o/M/XdM0abweme2Tln3szOstOrZ9OXitvPh0g=="],
|
|
239
|
+
|
|
240
|
+
"@typescript-eslint/visitor-keys": ["@typescript-eslint/visitor-keys@8.62.1", "", { "dependencies": { "@typescript-eslint/types": "8.62.1", "eslint-visitor-keys": "^5.0.0" } }, "sha512-4g3BLxfdTMy8iZG0MaBkadnlRrCJ74cQiFbyEVMrkwIoqdyaXXQM22cotDvrl4x28wgIZ9rEJRoM+mmhSJpJ1g=="],
|
|
237
241
|
|
|
238
242
|
"acorn": ["acorn@8.14.0", "", { "bin": "bin/acorn" }, "sha512-cl669nCJTZBsL97OF4kUQm5g5hC2uihk0NxY3WENAC0TYdILVkAyHymAntgxGkl7K+t0cXIrH5siy5S4XkFycA=="],
|
|
239
243
|
|
|
@@ -419,6 +423,8 @@
|
|
|
419
423
|
|
|
420
424
|
"fastq": ["fastq@1.18.0", "", { "dependencies": { "reusify": "^1.0.4" } }, "sha512-QKHXPW0hD8g4UET03SdOdunzSouc9N4AuHdsX8XNcTsuz+yYFILVNIX4l9yHABMhiEI9Db0JTTIpu0wB+Y1QQw=="],
|
|
421
425
|
|
|
426
|
+
"fdir": ["fdir@6.5.0", "", { "peerDependencies": { "picomatch": "^3 || ^4" } }, "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg=="],
|
|
427
|
+
|
|
422
428
|
"figures": ["figures@2.0.0", "", { "dependencies": { "escape-string-regexp": "^1.0.5" } }, "sha512-Oa2M9atig69ZkfwiApY8F2Yy+tzMbazyvqv21R0NsSC8floSOC09BbT1ITWAdoMGQvJ/aZnR1KMwdx9tvHnTNA=="],
|
|
423
429
|
|
|
424
430
|
"file-entry-cache": ["file-entry-cache@8.0.0", "", { "dependencies": { "flat-cache": "^4.0.0" } }, "sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ=="],
|
|
@@ -431,7 +437,7 @@
|
|
|
431
437
|
|
|
432
438
|
"flatted": ["flatted@3.3.2", "", {}, "sha512-AiwGJM8YcNOaobumgtng+6NHuOqC3A7MixFeDafM3X9cIUM+xUXoS5Vfgf+OihAYe20fxqNM9yPBXJzRtZ/4eA=="],
|
|
433
439
|
|
|
434
|
-
"follow-redirects": ["follow-redirects@1.16.0", "", {
|
|
440
|
+
"follow-redirects": ["follow-redirects@1.16.0", "", {}, "sha512-y5rN/uOsadFT/JfYwhxRS5R7Qce+g3zG97+JrtFZlC9klX/W5hD7iiLzScI4nZqUS7DNUdhPgw4xI8W2LuXlUw=="],
|
|
435
441
|
|
|
436
442
|
"for-each": ["for-each@0.3.3", "", { "dependencies": { "is-callable": "^1.1.3" } }, "sha512-jqYfLp7mo9vIyQf8ykW2v7A+2N4QjeCeI5+Dz9XraiO1ign81wjiH7Fb9vSOWvQfNtmSa4H2RoQTrrXivdUZmw=="],
|
|
437
443
|
|
|
@@ -463,8 +469,6 @@
|
|
|
463
469
|
|
|
464
470
|
"graceful-fs": ["graceful-fs@4.2.11", "", {}, "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ=="],
|
|
465
471
|
|
|
466
|
-
"graphemer": ["graphemer@1.4.0", "", {}, "sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag=="],
|
|
467
|
-
|
|
468
472
|
"has-bigints": ["has-bigints@1.1.0", "", {}, "sha512-R3pbpkcIqv2Pm3dUwgjclDRVmWpTJW2DcMzcIhEXEx1oh/CEMObMm3KLmRJOdvhM7o4uQBnwr8pzRK2sJWIqfg=="],
|
|
469
473
|
|
|
470
474
|
"has-flag": ["has-flag@4.0.0", "", {}, "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ=="],
|
|
@@ -477,7 +481,7 @@
|
|
|
477
481
|
|
|
478
482
|
"has-tostringtag": ["has-tostringtag@1.0.2", "", { "dependencies": { "has-symbols": "^1.0.3" } }, "sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw=="],
|
|
479
483
|
|
|
480
|
-
"hasown": ["hasown@2.0.
|
|
484
|
+
"hasown": ["hasown@2.0.4", "", { "dependencies": { "function-bind": "^1.1.2" } }, "sha512-T2UbfbBEF32wiepXIsMlTW9+dDYC6wMh/t/vYA4tuOMKqWz/n3vr1NFSxQiyP+zk2mXsoMA/i/7qV6LKut1t1A=="],
|
|
481
485
|
|
|
482
486
|
"https-proxy-agent": ["https-proxy-agent@5.0.1", "", { "dependencies": { "agent-base": "6", "debug": "4" } }, "sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA=="],
|
|
483
487
|
|
|
@@ -791,11 +795,13 @@
|
|
|
791
795
|
|
|
792
796
|
"tapable": ["tapable@2.2.1", "", {}, "sha512-GNzQvQTOIP6RyTfE2Qxb8ZVlNmw0n88vp1szwWRimP02mnTsx3Wtn5qRdqY9w2XduFNUgvOwhNnQsjwCp+kqaQ=="],
|
|
793
797
|
|
|
798
|
+
"tinyglobby": ["tinyglobby@0.2.17", "", { "dependencies": { "fdir": "^6.5.0", "picomatch": "^4.0.4" } }, "sha512-wXR/dYpcqKmfWpEdZjiKJOwCNFndD0DMnrW/cYjVGttEkBfVgcLFHoNrlj47mjOVic9yyNu65alsgF4NQyTa2g=="],
|
|
799
|
+
|
|
794
800
|
"to-regex-range": ["to-regex-range@5.0.1", "", { "dependencies": { "is-number": "^7.0.0" } }, "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ=="],
|
|
795
801
|
|
|
796
802
|
"tree-kill": ["tree-kill@1.2.2", "", { "bin": "cli.js" }, "sha512-L0Orpi8qGpRG//Nd+H90vFB+3iHnue1zSSGmNOOCh1GLJ7rUKVwV2HvijphGQS2UmhUZewS9VgvxYIdgr+fG1A=="],
|
|
797
803
|
|
|
798
|
-
"ts-api-utils": ["ts-api-utils@2.
|
|
804
|
+
"ts-api-utils": ["ts-api-utils@2.5.0", "", { "peerDependencies": { "typescript": ">=4.8.4" } }, "sha512-OJ/ibxhPlqrMM0UiNHJ/0CKQkoKF243/AEmplt3qpRgkW8VG7IfOS41h7V8TjITqdByHzrjcS/2si+y4lIh8NA=="],
|
|
799
805
|
|
|
800
806
|
"tsconfig-paths": ["tsconfig-paths@3.15.0", "", { "dependencies": { "@types/json5": "^0.0.29", "json5": "^1.0.2", "minimist": "^1.2.6", "strip-bom": "^3.0.0" } }, "sha512-2Ac2RgzDe/cn48GvOe3M+o82pEFewD3UPbyoUHHdKasHwJKjds4fLXWf/Ux5kATBKN20oaFGu+jbElp1pos0mg=="],
|
|
801
807
|
|
|
@@ -847,12 +853,14 @@
|
|
|
847
853
|
|
|
848
854
|
"@humanfs/node/@humanwhocodes/retry": ["@humanwhocodes/retry@0.3.1", "", {}, "sha512-JBxkERygn7Bv/GbN5Rv8Ul6LVknS+5Bp6RgDC/O8gEBU/yeH5Ui5C/OlWrTb6qct7LjjfT6Re2NxB0ln0yYybA=="],
|
|
849
855
|
|
|
850
|
-
"@typescript-eslint/
|
|
856
|
+
"@typescript-eslint/eslint-plugin/ignore": ["ignore@7.0.5", "", {}, "sha512-Hs59xBNfUIunMFgWAbGX5cq6893IbWg4KnrjbYwX3tx0ztorVgTDA6B2sxf8ejHJ4wz8BqGUMYlnzNBer5NvGg=="],
|
|
851
857
|
|
|
852
|
-
"@typescript-eslint/typescript-estree/minimatch": ["minimatch@
|
|
858
|
+
"@typescript-eslint/typescript-estree/minimatch": ["minimatch@10.2.5", "", { "dependencies": { "brace-expansion": "^5.0.5" } }, "sha512-MULkVLfKGYDFYejP07QOurDLLQpcjk7Fw+7jXS2R2czRQzR56yHRveU5NDJEOviH+hETZKSkIk5c+T23GjFUMg=="],
|
|
853
859
|
|
|
854
860
|
"@typescript-eslint/typescript-estree/semver": ["semver@7.7.3", "", { "bin": "bin/semver.js" }, "sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q=="],
|
|
855
861
|
|
|
862
|
+
"@typescript-eslint/visitor-keys/eslint-visitor-keys": ["eslint-visitor-keys@5.0.1", "", {}, "sha512-tD40eHxA35h0PEIZNeIjkHoDR4YjjJp34biM0mDvplBe//mB+IHCqHDGV7pxF+7MklTvighcCPPZC7ynWyjdTA=="],
|
|
863
|
+
|
|
856
864
|
"chalk/supports-color": ["supports-color@7.2.0", "", { "dependencies": { "has-flag": "^4.0.0" } }, "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw=="],
|
|
857
865
|
|
|
858
866
|
"eslint-import-resolver-node/debug": ["debug@3.2.7", "", { "dependencies": { "ms": "^2.1.1" } }, "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ=="],
|
|
@@ -869,9 +877,9 @@
|
|
|
869
877
|
|
|
870
878
|
"fast-glob/glob-parent": ["glob-parent@5.1.2", "", { "dependencies": { "is-glob": "^4.0.1" } }, "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow=="],
|
|
871
879
|
|
|
872
|
-
"
|
|
880
|
+
"fdir/picomatch": ["picomatch@4.0.4", "", {}, "sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A=="],
|
|
873
881
|
|
|
874
|
-
"
|
|
882
|
+
"figures/escape-string-regexp": ["escape-string-regexp@1.0.5", "", {}, "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg=="],
|
|
875
883
|
|
|
876
884
|
"is-bun-module/semver": ["semver@7.7.3", "", { "bin": "bin/semver.js" }, "sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q=="],
|
|
877
885
|
|
|
@@ -887,9 +895,9 @@
|
|
|
887
895
|
|
|
888
896
|
"string-width/emoji-regex": ["emoji-regex@8.0.0", "", {}, "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A=="],
|
|
889
897
|
|
|
890
|
-
"
|
|
898
|
+
"tinyglobby/picomatch": ["picomatch@4.0.4", "", {}, "sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A=="],
|
|
891
899
|
|
|
892
|
-
"@typescript-eslint/typescript-estree/minimatch/brace-expansion": ["brace-expansion@
|
|
900
|
+
"@typescript-eslint/typescript-estree/minimatch/brace-expansion": ["brace-expansion@5.0.7", "", { "dependencies": { "balanced-match": "^4.0.2" } }, "sha512-7oFy703dxfY3/NLxC1fh2SUCQ0H9rmAY+5EpDVfXjUTTs+HEwR2nYaqLv+GWcTsumwxPfiz6CzCNkwXwBUwqCA=="],
|
|
893
901
|
|
|
894
902
|
"eslint-import-resolver-typescript/fast-glob/glob-parent": ["glob-parent@5.1.2", "", { "dependencies": { "is-glob": "^4.0.1" } }, "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow=="],
|
|
895
903
|
|
|
@@ -901,6 +909,8 @@
|
|
|
901
909
|
|
|
902
910
|
"signale/chalk/supports-color": ["supports-color@5.5.0", "", { "dependencies": { "has-flag": "^3.0.0" } }, "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow=="],
|
|
903
911
|
|
|
912
|
+
"@typescript-eslint/typescript-estree/minimatch/brace-expansion/balanced-match": ["balanced-match@4.0.4", "", {}, "sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA=="],
|
|
913
|
+
|
|
904
914
|
"pkg-conf/find-up/locate-path/p-locate": ["p-locate@2.0.0", "", { "dependencies": { "p-limit": "^1.1.0" } }, "sha512-nQja7m7gSKuewoVRen45CtVfODR3crN3goVQ0DDZ9N3yHxgpkuBhZqsaiotSQRrADUrne346peY7kT3TSACykg=="],
|
|
905
915
|
|
|
906
916
|
"pkg-conf/find-up/locate-path/path-exists": ["path-exists@3.0.0", "", {}, "sha512-bpC7GYwiDYQ4wYLe+FA8lhRjhQCMcQGuSgGGqDkg/QerRWw9CmGRT0iSOVRSZJ29NMLZgIzqaljJ63oaL4NIJQ=="],
|
package/package.json
CHANGED
|
@@ -1,14 +1,13 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@skalfa/skalfa-app",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.3",
|
|
4
4
|
"scripts": {
|
|
5
|
-
"dev": "concurrently --raw \"bun run barrels\" \"next dev\"",
|
|
5
|
+
"dev": "concurrently --raw \"bun run skalfa watch:barrels\" \"next dev\"",
|
|
6
6
|
"build": "next build",
|
|
7
7
|
"start": "next start",
|
|
8
8
|
"test": "bun tsc --noEmit",
|
|
9
9
|
"lint": "npx eslint app/* components/* utils/* contexts/* schema/*",
|
|
10
|
-
"
|
|
11
|
-
"barrels": "bun run utils/commands/barrels.ts"
|
|
10
|
+
"skalfa": "bun run utils/commands/skalfa.ts"
|
|
12
11
|
},
|
|
13
12
|
"dependencies": {
|
|
14
13
|
"@fortawesome/fontawesome-svg-core": "^6.7.2",
|
|
@@ -17,7 +16,7 @@
|
|
|
17
16
|
"@fortawesome/free-solid-svg-icons": "^6.7.2",
|
|
18
17
|
"@fortawesome/react-fontawesome": "^0.2.2",
|
|
19
18
|
"@react-google-maps/api": "^2.20.7",
|
|
20
|
-
"@skalfa/skalfa-app-core": "^1.0.
|
|
19
|
+
"@skalfa/skalfa-app-core": "^1.0.3",
|
|
21
20
|
"@tailwindcss/postcss": "^4.0.0",
|
|
22
21
|
"axios": "^1.12.0",
|
|
23
22
|
"moment": "^2.30.1",
|
|
@@ -1,103 +0,0 @@
|
|
|
1
|
-
[
|
|
2
|
-
{
|
|
3
|
-
"model" : "iam/user",
|
|
4
|
-
"schema" : {
|
|
5
|
-
"name" : "type:string,200 required min:1 max:200 fillable searchable selectable",
|
|
6
|
-
"email" : "type:string,100 unique index required min:5 max:100 fillable searchable selectable",
|
|
7
|
-
"password" : "type:string,200 required min:8 max:50 fillable hidden",
|
|
8
|
-
"image" : "type:string,100 required fillable selectable file",
|
|
9
|
-
"email_verification_at" : "type:timestamp"
|
|
10
|
-
},
|
|
11
|
-
"relations": {
|
|
12
|
-
"roles": "[]:Role expandable fillable",
|
|
13
|
-
"permission": "[1]Permission"
|
|
14
|
-
},
|
|
15
|
-
"seeders" : [
|
|
16
|
-
["Admin", "admin@mail.com", "$2b$10$tPX5QhnM.vUEDmDpht6O4OarVyTh43NTxhkzFrNxfRijJ3uhSHcli", null, "0001-01-01 01:01:01.000+00"],
|
|
17
|
-
["User", "user@mail.com", "$2b$10$tPX5QhnM.vUEDmDpht6O4OarVyTh43NTxhkzFrNxfRijJ3uhSHcli", null, "0001-01-01 01:01:01.000+00"]
|
|
18
|
-
],
|
|
19
|
-
"migrations" : false,
|
|
20
|
-
|
|
21
|
-
"pages": {
|
|
22
|
-
"iam/user": {
|
|
23
|
-
"features": "create import export print",
|
|
24
|
-
"schema": {
|
|
25
|
-
"Nama" : "name column:sortable form:text|required|min:1|max:200|6",
|
|
26
|
-
"Email" : "email column:sortable form:text|required|email|min:5|max:100|6",
|
|
27
|
-
"Password" : "password form:input-password|required,create|min:8|max:50",
|
|
28
|
-
"Foto" : "image form:image|6"
|
|
29
|
-
}
|
|
30
|
-
}
|
|
31
|
-
}
|
|
32
|
-
},
|
|
33
|
-
{
|
|
34
|
-
"model" : "iam/role",
|
|
35
|
-
"schema" : {
|
|
36
|
-
"name" : "type:string,25 index required min:1 max:25 fillable searchable selectable"
|
|
37
|
-
},
|
|
38
|
-
"controllers" : ["iam/role"],
|
|
39
|
-
"seeders" : [["Admin"], ["User"]],
|
|
40
|
-
"migrations" : false,
|
|
41
|
-
|
|
42
|
-
"pages": {
|
|
43
|
-
"iam/user": {
|
|
44
|
-
"features": "create",
|
|
45
|
-
"schema": {
|
|
46
|
-
"Nama" : "name column:sortable form:text|required|min:1|max:25"
|
|
47
|
-
}
|
|
48
|
-
}
|
|
49
|
-
}
|
|
50
|
-
},
|
|
51
|
-
{
|
|
52
|
-
"model" : "iam/user-role",
|
|
53
|
-
"schema" : {
|
|
54
|
-
"user_id" : "type:bigInteger unsigned index required fillable selectable",
|
|
55
|
-
"role_id" : "type:bigInteger unsigned index required fillable selectable"
|
|
56
|
-
},
|
|
57
|
-
"relations": {
|
|
58
|
-
"role" : "Role",
|
|
59
|
-
"user" : "User"
|
|
60
|
-
},
|
|
61
|
-
"controllers" : false,
|
|
62
|
-
"seeders" : [[1, 1], [2, 2]],
|
|
63
|
-
"migrations" : false,
|
|
64
|
-
"pages": false
|
|
65
|
-
},
|
|
66
|
-
{
|
|
67
|
-
"model" : "iam/role-permission",
|
|
68
|
-
"schema" : {
|
|
69
|
-
"user_id" : "type:bigInteger unsigned index fillable selectable",
|
|
70
|
-
"role_id" : "type:bigInteger unsigned index fillable selectable",
|
|
71
|
-
"permissions" : "type:json nullable fillable selectable"
|
|
72
|
-
},
|
|
73
|
-
"migrations" : false
|
|
74
|
-
},
|
|
75
|
-
{
|
|
76
|
-
"model" : "iam/user-access-token",
|
|
77
|
-
"controllers" : false,
|
|
78
|
-
"schema" : {
|
|
79
|
-
"user_id" : "type:bigInteger unsigned index fillable selectable",
|
|
80
|
-
"agent" : "type:string,100 nullable index fillable selectable",
|
|
81
|
-
"token" : "type:string,200 fillable selectable hidden",
|
|
82
|
-
"permissions" : "type:json nullable fillable selectable",
|
|
83
|
-
"last_used_ip" : "type:string,100 nullable fillable selectable",
|
|
84
|
-
"last_used_at" : "type:timestamp nullable fillable selectable",
|
|
85
|
-
"expired_at" : "type:timestamp nullable fillable selectable"
|
|
86
|
-
},
|
|
87
|
-
"migrations" : false,
|
|
88
|
-
"pages": false
|
|
89
|
-
},
|
|
90
|
-
{
|
|
91
|
-
"model" : "iam/user-mail-token",
|
|
92
|
-
"controllers" : false,
|
|
93
|
-
"schema" : {
|
|
94
|
-
"user_id" : "type:bigInteger unsigned index fillable selectable",
|
|
95
|
-
"type" : "type:string,10 fillable selectable hidden",
|
|
96
|
-
"token" : "type:string,200 fillable selectable hidden",
|
|
97
|
-
"used_at" : "type:timestamp fillable selectable",
|
|
98
|
-
"expired_at" : "type:timestamp fillable selectable"
|
|
99
|
-
},
|
|
100
|
-
"migrations" : false,
|
|
101
|
-
"pages": false
|
|
102
|
-
}
|
|
103
|
-
]
|
package/langs/index.ts
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export * from "./validation.langs";
|
|
@@ -1,17 +0,0 @@
|
|
|
1
|
-
export const validationLangs = {
|
|
2
|
-
required: "Please fill in this field!",
|
|
3
|
-
min: "Field must contain more than @min Character!",
|
|
4
|
-
max: "Field must be less than @max Character!",
|
|
5
|
-
min_max: "Field must be @min - @max Character!",
|
|
6
|
-
phone: "Please enter valid mobile number!",
|
|
7
|
-
url: "Please enter valid url!",
|
|
8
|
-
uppercase: "Field must be at least 1 uppercase!",
|
|
9
|
-
lowercase: "Field must be at least 1 lowercase!",
|
|
10
|
-
numeric: "Field must be at least 1 numeric!",
|
|
11
|
-
email: "Please enter valid email!",
|
|
12
|
-
in: "Field must be one of @keywords",
|
|
13
|
-
not_in: "Field can't one of @keywords",
|
|
14
|
-
regex: "Please enter valid format",
|
|
15
|
-
invalid_file_type: "Only allow extensions @extension",
|
|
16
|
-
max_file_size: "Max file size @maxFileSize Mb",
|
|
17
|
-
};
|
|
@@ -1,28 +0,0 @@
|
|
|
1
|
-
import path from "path";
|
|
2
|
-
import fs from "fs";
|
|
3
|
-
import { exec } from "child_process";
|
|
4
|
-
import { logger } from "./logger";
|
|
5
|
-
|
|
6
|
-
const rootDir = path.resolve();
|
|
7
|
-
const configText = fs.readFileSync("barrels.json", "utf8");
|
|
8
|
-
const config = JSON.parse(configText);
|
|
9
|
-
const directories: string[] = Array.isArray(config.directory) ? config.directory : [config.directory];
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
directories.forEach((dir) => {
|
|
13
|
-
const absoluteDir = path.join(rootDir, dir);
|
|
14
|
-
|
|
15
|
-
if (!fs.existsSync(absoluteDir)) {
|
|
16
|
-
logger.error(`Barrels error: ${absoluteDir} directory not found`)
|
|
17
|
-
return;
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
fs.watch(absoluteDir, { recursive: true }, (_, filename) => {
|
|
21
|
-
if (filename && (filename.endsWith(".ts") || filename.endsWith(".tsx")) && filename !== "index.ts") {
|
|
22
|
-
exec("npx barrelsby -c barrels.json", { cwd: rootDir })
|
|
23
|
-
logger.info("Barrels updated " + absoluteDir + "/index.ts")
|
|
24
|
-
}
|
|
25
|
-
});
|
|
26
|
-
});
|
|
27
|
-
|
|
28
|
-
logger.start("Barrels watched " + directories.join(", "))
|
|
@@ -1,421 +0,0 @@
|
|
|
1
|
-
import fs from "fs";
|
|
2
|
-
import path from "path";
|
|
3
|
-
import { ValidationRules, conversion } from "@skalfa/skalfa-app-core";
|
|
4
|
-
import { logger } from "./logger";
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
type SchemaMap = Record<string, string>
|
|
9
|
-
|
|
10
|
-
type ColumnItem = {
|
|
11
|
-
selector ?: string
|
|
12
|
-
label : string
|
|
13
|
-
sortable ?: boolean
|
|
14
|
-
item ?: string
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
type FormItem = {
|
|
18
|
-
type ?: string
|
|
19
|
-
col ?: number
|
|
20
|
-
construction : {
|
|
21
|
-
name : string
|
|
22
|
-
label : string
|
|
23
|
-
placeholder : string
|
|
24
|
-
validations : ValidationRules[]
|
|
25
|
-
serverOptionControl ?: {
|
|
26
|
-
path : string
|
|
27
|
-
}
|
|
28
|
-
fields ?: FormItem[]
|
|
29
|
-
wrap ?: boolean
|
|
30
|
-
}
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
type DetailItem = {
|
|
34
|
-
label : string
|
|
35
|
-
item : string
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
type ParsedSchema = {
|
|
39
|
-
columns : ColumnItem[]
|
|
40
|
-
forms : FormItem[]
|
|
41
|
-
details : DetailItem[]
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
type BlueprintPage = {
|
|
45
|
-
features ?: string
|
|
46
|
-
path ?: string
|
|
47
|
-
schema ?: Record<string, string>
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
type BlueprintStruct = {
|
|
51
|
-
model : string
|
|
52
|
-
controllers ?: string[]
|
|
53
|
-
schema ?: SchemaMap
|
|
54
|
-
pages ?: false | Record<string, BlueprintPage>
|
|
55
|
-
[key: string]: any
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
type LoadedBlueprintFile = {
|
|
59
|
-
file : string
|
|
60
|
-
blueprints : BlueprintStruct[]
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
const renderJS = (value: unknown, indent = 0): string => {
|
|
66
|
-
const pad = " ".repeat(indent)
|
|
67
|
-
|
|
68
|
-
if (Array.isArray(value)) {
|
|
69
|
-
if (!value.length) return "[]"
|
|
70
|
-
|
|
71
|
-
if (value.every(v => typeof v === "string")) {
|
|
72
|
-
return `[${value.map(v => JSON.stringify(v)).join(", ")}]`
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
return `[\n${value
|
|
76
|
-
.map(v => pad + " " + renderJS(v, indent + 2))
|
|
77
|
-
.join(",\n")}\n${pad}]`
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
if (value && typeof value === "object") {
|
|
81
|
-
const entries = Object.entries(value as Record<string, unknown>)
|
|
82
|
-
if (!entries.length) return "{}"
|
|
83
|
-
|
|
84
|
-
return `{\n${entries
|
|
85
|
-
.map(([k, v]) => `${pad} ${k}: ${renderJS(v, indent + 2)}`)
|
|
86
|
-
.join(",\n")}\n${pad}}`
|
|
87
|
-
}
|
|
88
|
-
|
|
89
|
-
if (typeof value === "string") return JSON.stringify(value)
|
|
90
|
-
|
|
91
|
-
return String(value)
|
|
92
|
-
}
|
|
93
|
-
|
|
94
|
-
function extractValidationArray(def: string = ""): ValidationRules[] {
|
|
95
|
-
const rules: ValidationRules[] = []
|
|
96
|
-
|
|
97
|
-
if (def.includes("required")) rules.push("required")
|
|
98
|
-
|
|
99
|
-
if (def.includes("email")) rules.push("email")
|
|
100
|
-
|
|
101
|
-
if (def.includes("url")) rules.push("url")
|
|
102
|
-
|
|
103
|
-
const min = def.match(/min,(\d+)/)
|
|
104
|
-
if (min) rules.push(`min:${min[1]}`)
|
|
105
|
-
|
|
106
|
-
const max = def.match(/max,(\d+)/)
|
|
107
|
-
if (max) rules.push(`max:${max[1]}`)
|
|
108
|
-
|
|
109
|
-
return rules
|
|
110
|
-
}
|
|
111
|
-
|
|
112
|
-
function extractFormType(rules: string[]): string | undefined {
|
|
113
|
-
const rule = rules.find(r => r.startsWith("form:"))
|
|
114
|
-
return rule ? rule.replace("form:", "") : undefined
|
|
115
|
-
}
|
|
116
|
-
|
|
117
|
-
function inferFormType(pageDef = "", modelDef = ""): string {
|
|
118
|
-
const explicit = pageDef.split("|")
|
|
119
|
-
if (explicit && explicit[0] && explicit[0] != "text") return explicit[0]
|
|
120
|
-
|
|
121
|
-
if (modelDef.includes("type:integer") || modelDef.includes("type:float")) {
|
|
122
|
-
return "number"
|
|
123
|
-
}
|
|
124
|
-
|
|
125
|
-
if (modelDef.includes("type:date")) return "date"
|
|
126
|
-
if (modelDef.includes("type:datetime")) return "datetime"
|
|
127
|
-
if (modelDef.includes("type:image")) return "image"
|
|
128
|
-
|
|
129
|
-
return "default"
|
|
130
|
-
}
|
|
131
|
-
|
|
132
|
-
function parseFeatures(features?: string): { controlBar: string[]; action: string[] } {
|
|
133
|
-
const controlBar: string[] = []
|
|
134
|
-
const action: string[] = []
|
|
135
|
-
|
|
136
|
-
if (!features) {
|
|
137
|
-
return { controlBar: ["CREATE"], action: ["EDIT", "DELETE"] }
|
|
138
|
-
}
|
|
139
|
-
|
|
140
|
-
const list = features.split(" ")
|
|
141
|
-
|
|
142
|
-
if (list.includes("create")) controlBar.push("CREATE")
|
|
143
|
-
|
|
144
|
-
controlBar.push("SEARCH", "SORT", "SELECTABLE")
|
|
145
|
-
|
|
146
|
-
if (list.includes("import")) controlBar.push("IMPORT")
|
|
147
|
-
if (list.includes("export")) controlBar.push("EXPORT")
|
|
148
|
-
if (list.includes("print")) controlBar.push("PRINT")
|
|
149
|
-
|
|
150
|
-
if (list.includes("update") || list.includes("edit")) action.push("EDIT")
|
|
151
|
-
if (list.includes("delete")) action.push("DELETE")
|
|
152
|
-
if (list.includes("detail")) action.push("DETAIL")
|
|
153
|
-
|
|
154
|
-
return { controlBar, action }
|
|
155
|
-
}
|
|
156
|
-
|
|
157
|
-
function parseModelSchema(schema: SchemaMap = {}): ParsedSchema {
|
|
158
|
-
const columns: ColumnItem[] = []
|
|
159
|
-
const forms: FormItem[] = []
|
|
160
|
-
const details: DetailItem[] = []
|
|
161
|
-
|
|
162
|
-
for (const [field, def] of Object.entries(schema)) {
|
|
163
|
-
const label = conversion.strPascal(field, " ")
|
|
164
|
-
|
|
165
|
-
if (def.includes("selectable")) {
|
|
166
|
-
columns.push({ selector: field, label })
|
|
167
|
-
details.push({ label, item: field })
|
|
168
|
-
}
|
|
169
|
-
|
|
170
|
-
if (def.includes("fillable")) {
|
|
171
|
-
const fieldType = inferFormType("", def);
|
|
172
|
-
forms.push({
|
|
173
|
-
...(fieldType != "default" ? { type: fieldType } : {}),
|
|
174
|
-
construction: {
|
|
175
|
-
name: field,
|
|
176
|
-
label,
|
|
177
|
-
placeholder: "Masukkan " + label.toLowerCase(),
|
|
178
|
-
validations: extractValidationArray(def)
|
|
179
|
-
}
|
|
180
|
-
})
|
|
181
|
-
}
|
|
182
|
-
}
|
|
183
|
-
|
|
184
|
-
return { columns, forms, details }
|
|
185
|
-
}
|
|
186
|
-
|
|
187
|
-
function resolvePath(page: BlueprintPage, controllers: string[] | boolean | undefined, model: string): string {
|
|
188
|
-
if (page.path) return page.path
|
|
189
|
-
|
|
190
|
-
if (Array.isArray(controllers)) {
|
|
191
|
-
const match = controllers
|
|
192
|
-
if (match) return "/" + match[1]
|
|
193
|
-
}
|
|
194
|
-
|
|
195
|
-
return "/" + model.split("/").pop()
|
|
196
|
-
}
|
|
197
|
-
|
|
198
|
-
function parsePageSchema(pageSchema: Record<string, string>, modelSchema: SchemaMap = {}): ParsedSchema {
|
|
199
|
-
const columns: ColumnItem[] = []
|
|
200
|
-
const forms: FormItem[] = []
|
|
201
|
-
const details: DetailItem[] = []
|
|
202
|
-
|
|
203
|
-
for (const [field, def] of Object.entries(pageSchema)) {
|
|
204
|
-
const rules = def.replace(/\|/g, " ").split(" ").filter(Boolean)
|
|
205
|
-
|
|
206
|
-
const defaultLabel = conversion.strPascal(field, " ")
|
|
207
|
-
|
|
208
|
-
const colLabelRule = rules.find(r => r.includes("column:label,"))
|
|
209
|
-
const colLabel = conversion.strPascal(colLabelRule ? colLabelRule.split(",")[1] : defaultLabel, " ")
|
|
210
|
-
|
|
211
|
-
const formLabelRule = rules.find(r => r.includes("form:label,"))
|
|
212
|
-
const formLabel = conversion.strPascal(formLabelRule ? formLabelRule.split(",")[1] : (colLabelRule ? colLabel : defaultLabel), " ")
|
|
213
|
-
|
|
214
|
-
const detailLabel = colLabelRule ? colLabel : (formLabelRule ? formLabel : defaultLabel)
|
|
215
|
-
|
|
216
|
-
const hasColumn = rules.some(r => r.includes("column:"))
|
|
217
|
-
const hasForm = rules.some(r => r.includes("form:")) || rules.every(r => !r.includes("column:"))
|
|
218
|
-
|
|
219
|
-
const hasDetail = rules.includes("detail")
|
|
220
|
-
|
|
221
|
-
if (hasColumn) {
|
|
222
|
-
columns.push({
|
|
223
|
-
selector: field,
|
|
224
|
-
label: colLabel,
|
|
225
|
-
...(rules.includes("column:sortable") || rules.includes("sortable") ? { sortable: true } : {})
|
|
226
|
-
})
|
|
227
|
-
if (!hasDetail) details.push({ label: detailLabel, item: field })
|
|
228
|
-
}
|
|
229
|
-
|
|
230
|
-
if (hasForm) {
|
|
231
|
-
const typeRules = rules.filter(r => !r.startsWith("form:label,"))
|
|
232
|
-
const typeRule = extractFormType(typeRules)
|
|
233
|
-
let fieldType = inferFormType(typeRule, modelSchema[field] || "");
|
|
234
|
-
|
|
235
|
-
let selectPath = ""
|
|
236
|
-
const selectRule = rules.find(r => r.startsWith("select,") || r.startsWith("form:select,"))
|
|
237
|
-
if (selectRule) {
|
|
238
|
-
fieldType = "select"
|
|
239
|
-
selectPath = selectRule.split(",")[1]
|
|
240
|
-
}
|
|
241
|
-
|
|
242
|
-
if (typeRule === "check") fieldType = "boolean"
|
|
243
|
-
if (typeRule === "currency") fieldType = "currency"
|
|
244
|
-
if (typeRule === "image") fieldType = "image"
|
|
245
|
-
if (typeRule === "date") fieldType = "date"
|
|
246
|
-
if (typeRule === "time") fieldType = "time"
|
|
247
|
-
|
|
248
|
-
let col: number | undefined
|
|
249
|
-
const colRule = rules.find(r => /col,(\d+)/.test(r))
|
|
250
|
-
|
|
251
|
-
if (colRule) {
|
|
252
|
-
const n = Number(colRule.split(',').pop())
|
|
253
|
-
if (n >= 1 && n <= 12) col = n
|
|
254
|
-
}
|
|
255
|
-
|
|
256
|
-
forms.push({
|
|
257
|
-
...(fieldType != "default" && fieldType != "text" ? { type: fieldType } : {}),
|
|
258
|
-
...(col ? { col } : {}),
|
|
259
|
-
construction: {
|
|
260
|
-
name: field,
|
|
261
|
-
label: formLabel,
|
|
262
|
-
placeholder: "Masukkan " + formLabel.toLowerCase(),
|
|
263
|
-
validations: extractValidationArray(modelSchema[field] || ""),
|
|
264
|
-
...(selectPath ? { serverOptionControl: { path: selectPath } } : {}),
|
|
265
|
-
...(rules.includes("wrap") ? { wrap: true } : {})
|
|
266
|
-
}
|
|
267
|
-
})
|
|
268
|
-
}
|
|
269
|
-
|
|
270
|
-
if (hasDetail) details.push({ label: detailLabel, item: field })
|
|
271
|
-
}
|
|
272
|
-
|
|
273
|
-
const formMap = new Map<string, FormItem>()
|
|
274
|
-
forms.forEach(f => formMap.set(f.construction.name, f))
|
|
275
|
-
|
|
276
|
-
const nestedForms: FormItem[] = []
|
|
277
|
-
|
|
278
|
-
forms.forEach(f => {
|
|
279
|
-
const name = f.construction.name
|
|
280
|
-
if (name.includes(".")) {
|
|
281
|
-
const parts = name.split(".")
|
|
282
|
-
const selfName = parts.pop() as string
|
|
283
|
-
const parentName = parts.join(".")
|
|
284
|
-
const parent = formMap.get(parentName)
|
|
285
|
-
|
|
286
|
-
if (parent) {
|
|
287
|
-
if (!parent.type) parent.type = "cluster"
|
|
288
|
-
if (!parent.construction.fields) parent.construction.fields = []
|
|
289
|
-
|
|
290
|
-
f.construction.name = selfName
|
|
291
|
-
|
|
292
|
-
parent.construction.fields.push(f)
|
|
293
|
-
} else {
|
|
294
|
-
nestedForms.push(f)
|
|
295
|
-
}
|
|
296
|
-
} else {
|
|
297
|
-
nestedForms.push(f)
|
|
298
|
-
}
|
|
299
|
-
})
|
|
300
|
-
|
|
301
|
-
return { columns, forms: nestedForms, details }
|
|
302
|
-
}
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
function loadBlueprintFiles(dir: string = "blueprints"): LoadedBlueprintFile[] {
|
|
307
|
-
const basePath = path.join(process.cwd(), dir)
|
|
308
|
-
|
|
309
|
-
if (!fs.existsSync(basePath)) {
|
|
310
|
-
throw new Error("Blueprint folder not found")
|
|
311
|
-
}
|
|
312
|
-
|
|
313
|
-
return fs.readdirSync(basePath)
|
|
314
|
-
.filter(f => f.endsWith(".blueprint.json"))
|
|
315
|
-
.map(file => {
|
|
316
|
-
const fullPath = path.join(basePath, file)
|
|
317
|
-
const content = JSON.parse(fs.readFileSync(fullPath, "utf-8"))
|
|
318
|
-
|
|
319
|
-
if (!Array.isArray(content)) {
|
|
320
|
-
throw new Error(`${file} must export array of blueprints`)
|
|
321
|
-
}
|
|
322
|
-
|
|
323
|
-
return {
|
|
324
|
-
file: file.replace(".blueprint.json", ""),
|
|
325
|
-
blueprints: content as BlueprintStruct[],
|
|
326
|
-
}
|
|
327
|
-
})
|
|
328
|
-
}
|
|
329
|
-
|
|
330
|
-
const blueprintMarker = `// ============================================
|
|
331
|
-
// ## file THIS FILE IS AUTO-GENERATED BY BLUEPRINT
|
|
332
|
-
// ?? Blueprint : {{ blueprint }}
|
|
333
|
-
// !! If this comment is removed, blueprint engine WILL NOT override this file.
|
|
334
|
-
// ============================================
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
`
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
// ===============================
|
|
341
|
-
// ## Main generator
|
|
342
|
-
// ===============================
|
|
343
|
-
|
|
344
|
-
export async function blueprint(options?: { only?: string[] }): Promise<void> {
|
|
345
|
-
const stub = fs.readFileSync(path.join(process.cwd(), "/utils/commands/stubs/table-blueprint.stub"), "utf-8")
|
|
346
|
-
|
|
347
|
-
const loaded = loadBlueprintFiles()
|
|
348
|
-
|
|
349
|
-
for (const file of loaded) {
|
|
350
|
-
for (const bp of file.blueprints) {
|
|
351
|
-
|
|
352
|
-
const pagesToGenerate: Record<string, BlueprintPage> = { ...(bp.pages || {}) }
|
|
353
|
-
|
|
354
|
-
for (const [key, val] of Object.entries(bp)) {
|
|
355
|
-
if (typeof val === "object" && val["schema"]) {
|
|
356
|
-
pagesToGenerate[key] = val as BlueprintPage
|
|
357
|
-
}
|
|
358
|
-
}
|
|
359
|
-
|
|
360
|
-
for (const [key, page] of Object.entries(pagesToGenerate)) {
|
|
361
|
-
|
|
362
|
-
const route = key;
|
|
363
|
-
const name = conversion.strPascal(route.split("/").pop() as string)
|
|
364
|
-
|
|
365
|
-
if (options?.only && !options.only.includes(name)) continue
|
|
366
|
-
|
|
367
|
-
const outDir = path.join(process.cwd(), "app", route)
|
|
368
|
-
fs.mkdirSync(outDir, { recursive: true })
|
|
369
|
-
|
|
370
|
-
const filePath = path.join(outDir, "page.tsx");
|
|
371
|
-
|
|
372
|
-
if (fs.existsSync(filePath)) {
|
|
373
|
-
const content = fs.readFileSync(filePath, "utf-8")
|
|
374
|
-
|
|
375
|
-
if (!content.includes("AUTO-GENERATED BY BLUEPRINT")) {
|
|
376
|
-
logger.info(`Skip overridden file: ${filePath}`)
|
|
377
|
-
continue
|
|
378
|
-
}
|
|
379
|
-
}
|
|
380
|
-
|
|
381
|
-
const schema = bp.schema ?? {}
|
|
382
|
-
|
|
383
|
-
const parsed: ParsedSchema = page?.schema ? parsePageSchema(page.schema, schema) : parseModelSchema(schema)
|
|
384
|
-
|
|
385
|
-
const { controlBar, action } = parseFeatures(page?.features)
|
|
386
|
-
|
|
387
|
-
const fetchPath = resolvePath(page, bp.controllers, bp.model)
|
|
388
|
-
|
|
389
|
-
let properties = `
|
|
390
|
-
fetchControl={{
|
|
391
|
-
path: "${fetchPath}"
|
|
392
|
-
}}
|
|
393
|
-
columnControl={${renderJS(parsed.columns, 8)}}
|
|
394
|
-
formControl={{
|
|
395
|
-
fields: ${renderJS(parsed.forms, 10)}
|
|
396
|
-
}}
|
|
397
|
-
`
|
|
398
|
-
if (parsed.details) {
|
|
399
|
-
properties += ` detailControl={${renderJS(parsed.details, 8)}}\n`
|
|
400
|
-
}
|
|
401
|
-
|
|
402
|
-
if (controlBar.length) {
|
|
403
|
-
properties += ` controlBar={${JSON.stringify(controlBar)}}\n`
|
|
404
|
-
}
|
|
405
|
-
|
|
406
|
-
if (action.length) {
|
|
407
|
-
properties += ` actionControl={${JSON.stringify(action)}}\n`
|
|
408
|
-
}
|
|
409
|
-
|
|
410
|
-
const content = stub
|
|
411
|
-
.replace(/{{ marker }}/g, blueprintMarker.replace(/{{ blueprint }}/g, file.file + ".blueprint.json"))
|
|
412
|
-
.replace(/{{ name }}/g, name)
|
|
413
|
-
.replace(/{{ title }}/g, name)
|
|
414
|
-
.replace(/{{ properties }}/g, properties)
|
|
415
|
-
|
|
416
|
-
fs.writeFileSync(path.join(outDir, "page.tsx"), content)
|
|
417
|
-
logger.info(`Generated: ${filePath}`)
|
|
418
|
-
}
|
|
419
|
-
}
|
|
420
|
-
}
|
|
421
|
-
}
|
package/utils/commands/light.ts
DELETED
|
@@ -1,21 +0,0 @@
|
|
|
1
|
-
import { Command } from "commander";
|
|
2
|
-
import { usePdf } from "./use-pdf";
|
|
3
|
-
import { blueprint } from "./blueprint";
|
|
4
|
-
import { logger } from "./logger";
|
|
5
|
-
|
|
6
|
-
const program = new Command();
|
|
7
|
-
|
|
8
|
-
program.name("light").description("Next Light CLI").version("1.0.0");
|
|
9
|
-
|
|
10
|
-
program.command("use-pdf").description("Copy pdf.worker.min.mjs ke folder public/").action(usePdf );
|
|
11
|
-
program.command("blueprint")
|
|
12
|
-
.option("-o, --only <names...>", "Run only specific blueprints")
|
|
13
|
-
.description("Generate blueprint")
|
|
14
|
-
.action(async (opts) => {
|
|
15
|
-
await blueprint({ only: opts.only })
|
|
16
|
-
|
|
17
|
-
logger.info("Success run all blueprints!")
|
|
18
|
-
process.exit(0);
|
|
19
|
-
});
|
|
20
|
-
|
|
21
|
-
program.parse();
|
package/utils/commands/logger.ts
DELETED
|
@@ -1,42 +0,0 @@
|
|
|
1
|
-
/* eslint-disable no-console */
|
|
2
|
-
type LogType = "start" | "info" | "error" | "warning" | "cavity" | "socket" | "cavityError" | "socketError";
|
|
3
|
-
|
|
4
|
-
const colors: Record<LogType | "default", string> = {
|
|
5
|
-
default : "\x1b[0m", // default
|
|
6
|
-
start : "\x1b[32m", // green
|
|
7
|
-
info : "\x1b[36m", // cyan
|
|
8
|
-
error : "\x1b[31m", // red
|
|
9
|
-
warning : "\x1b[33m", // yellow
|
|
10
|
-
cavity : "\x1b[34m", // blue
|
|
11
|
-
cavityError : "\x1b[31m", // red
|
|
12
|
-
socket : "\x1b[35m", // magenta
|
|
13
|
-
socketError : "\x1b[31m", // red
|
|
14
|
-
};
|
|
15
|
-
|
|
16
|
-
const prefixes: Record<LogType, string> = {
|
|
17
|
-
start : "START",
|
|
18
|
-
info : "INFO",
|
|
19
|
-
error : "ERROR",
|
|
20
|
-
warning : "WARNING",
|
|
21
|
-
cavity : "CAVITY",
|
|
22
|
-
socket : "SOCKET",
|
|
23
|
-
cavityError : "CAVITY ERROR",
|
|
24
|
-
socketError : "SOCKET ERROR",
|
|
25
|
-
};
|
|
26
|
-
|
|
27
|
-
function log(type: LogType, ...msg: unknown[]) {
|
|
28
|
-
const color = colors[type];
|
|
29
|
-
const prefix = prefixes[type];
|
|
30
|
-
console.log(`${color}[${prefix}]${colors.default}`, ...msg);
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
export const logger = {
|
|
34
|
-
start : (...msg: unknown[]) => log("start", ...msg),
|
|
35
|
-
info : (...msg: unknown[]) => log("info", ...msg),
|
|
36
|
-
error : (...msg: unknown[]) => log("error", ...msg),
|
|
37
|
-
warning : (...msg: unknown[]) => log("warning", ...msg),
|
|
38
|
-
cavity : (...msg: unknown[]) => log("cavity", ...msg),
|
|
39
|
-
cavityError : (...msg: unknown[]) => log("cavityError", ...msg),
|
|
40
|
-
socket : (...msg: unknown[]) => log("socket", ...msg),
|
|
41
|
-
socketError : (...msg: unknown[]) => log("socketError", ...msg),
|
|
42
|
-
};
|
|
@@ -1,29 +0,0 @@
|
|
|
1
|
-
import fs from "fs";
|
|
2
|
-
import path from "path";
|
|
3
|
-
import { fileURLToPath } from "url";
|
|
4
|
-
import { logger } from "./logger";
|
|
5
|
-
|
|
6
|
-
export function usePdf() {
|
|
7
|
-
const __filename = fileURLToPath(import.meta.url);
|
|
8
|
-
const __dirname = path.dirname(__filename);
|
|
9
|
-
const projectRoot = path.join(__dirname, "..", "..");
|
|
10
|
-
|
|
11
|
-
const source = path.join(
|
|
12
|
-
projectRoot,
|
|
13
|
-
"node_modules",
|
|
14
|
-
"pdfjs-dist",
|
|
15
|
-
"legacy",
|
|
16
|
-
"build",
|
|
17
|
-
"pdf.worker.min.mjs"
|
|
18
|
-
);
|
|
19
|
-
|
|
20
|
-
const target = path.join(projectRoot, "public", "pdf.worker.min.mjs");
|
|
21
|
-
|
|
22
|
-
if (!fs.existsSync(source)) {
|
|
23
|
-
logger.error(`Gagal: pdf.worker.min.mjs tidak ditemukan.`)
|
|
24
|
-
process.exit(1);
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
fs.copyFileSync(source, target);
|
|
28
|
-
logger.info("Berhasil memindahkan worker ke public/pdf.worker.min.mjs")
|
|
29
|
-
}
|