@harpy-js/core 0.4.7
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 +326 -0
- package/dist/cli.d.ts +12 -0
- package/dist/cli.js +53 -0
- package/dist/client/Link.d.ts +5 -0
- package/dist/client/Link.js +62 -0
- package/dist/client/__tests__/getActiveItemId.test.d.ts +1 -0
- package/dist/client/__tests__/getActiveItemId.test.js +38 -0
- package/dist/client/getActiveItemId.d.ts +7 -0
- package/dist/client/getActiveItemId.js +55 -0
- package/dist/client/use-i18n.d.ts +7 -0
- package/dist/client/use-i18n.js +64 -0
- package/dist/core/__tests__/component-analyzer.test.d.ts +1 -0
- package/dist/core/__tests__/component-analyzer.test.js +151 -0
- package/dist/core/__tests__/hydration-manifest.test.d.ts +1 -0
- package/dist/core/__tests__/hydration-manifest.test.js +211 -0
- package/dist/core/__tests__/jsx.engine.test.d.ts +1 -0
- package/dist/core/__tests__/jsx.engine.test.js +118 -0
- package/dist/core/app-setup.d.ts +7 -0
- package/dist/core/app-setup.js +79 -0
- package/dist/core/auto-register.module.d.ts +9 -0
- package/dist/core/auto-register.module.js +18 -0
- package/dist/core/auto-wrap-middleware.d.ts +4 -0
- package/dist/core/auto-wrap-middleware.js +130 -0
- package/dist/core/client-component-wrapper.d.ts +5 -0
- package/dist/core/client-component-wrapper.js +37 -0
- package/dist/core/client-hydration.d.ts +2 -0
- package/dist/core/client-hydration.js +93 -0
- package/dist/core/client-wrapper-browser.d.ts +2 -0
- package/dist/core/client-wrapper-browser.js +22 -0
- package/dist/core/component-analyzer.d.ts +4 -0
- package/dist/core/component-analyzer.js +98 -0
- package/dist/core/component-auto-wrapper.d.ts +2 -0
- package/dist/core/component-auto-wrapper.js +63 -0
- package/dist/core/component-client-wrapper.d.ts +4 -0
- package/dist/core/component-client-wrapper.js +80 -0
- package/dist/core/hydration-generator.d.ts +2 -0
- package/dist/core/hydration-generator.js +98 -0
- package/dist/core/hydration-manifest.d.ts +7 -0
- package/dist/core/hydration-manifest.js +83 -0
- package/dist/core/hydration.d.ts +16 -0
- package/dist/core/hydration.js +72 -0
- package/dist/core/jsx.engine.d.ts +9 -0
- package/dist/core/jsx.engine.js +161 -0
- package/dist/core/live-reload-client.js +32 -0
- package/dist/core/live-reload.controller.d.ts +10 -0
- package/dist/core/live-reload.controller.js +38 -0
- package/dist/core/navigation.service.d.ts +18 -0
- package/dist/core/navigation.service.js +206 -0
- package/dist/core/router.module.d.ts +2 -0
- package/dist/core/router.module.js +21 -0
- package/dist/core/static-assets.controller.d.ts +4 -0
- package/dist/core/static-assets.controller.js +51 -0
- package/dist/core/types/nav.types.d.ts +22 -0
- package/dist/core/types/nav.types.js +2 -0
- package/dist/core/views/layout.d.ts +8 -0
- package/dist/core/views/layout.js +35 -0
- package/dist/decorators/jsx.decorator.d.ts +26 -0
- package/dist/decorators/jsx.decorator.js +10 -0
- package/dist/decorators/layout.decorator.d.ts +4 -0
- package/dist/decorators/layout.decorator.js +29 -0
- package/dist/i18n/__tests__/i18n.helper.test.d.ts +1 -0
- package/dist/i18n/__tests__/i18n.helper.test.js +105 -0
- package/dist/i18n/__tests__/i18n.interceptor.test.d.ts +1 -0
- package/dist/i18n/__tests__/i18n.interceptor.test.js +195 -0
- package/dist/i18n/__tests__/i18n.module.test.d.ts +1 -0
- package/dist/i18n/__tests__/i18n.module.test.js +83 -0
- package/dist/i18n/__tests__/i18n.service.test.d.ts +1 -0
- package/dist/i18n/__tests__/i18n.service.test.js +109 -0
- package/dist/i18n/__tests__/t.test.d.ts +1 -0
- package/dist/i18n/__tests__/t.test.js +66 -0
- package/dist/i18n/i18n-module.options.d.ts +10 -0
- package/dist/i18n/i18n-module.options.js +4 -0
- package/dist/i18n/i18n-switcher.controller.d.ts +12 -0
- package/dist/i18n/i18n-switcher.controller.js +80 -0
- package/dist/i18n/i18n-types.d.ts +8 -0
- package/dist/i18n/i18n-types.js +2 -0
- package/dist/i18n/i18n.helper.d.ts +14 -0
- package/dist/i18n/i18n.helper.js +70 -0
- package/dist/i18n/i18n.interceptor.d.ts +9 -0
- package/dist/i18n/i18n.interceptor.js +99 -0
- package/dist/i18n/i18n.module.d.ts +5 -0
- package/dist/i18n/i18n.module.js +51 -0
- package/dist/i18n/i18n.service.d.ts +12 -0
- package/dist/i18n/i18n.service.js +61 -0
- package/dist/i18n/index.d.ts +10 -0
- package/dist/i18n/index.js +20 -0
- package/dist/i18n/locale.decorator.d.ts +1 -0
- package/dist/i18n/locale.decorator.js +8 -0
- package/dist/i18n/t.d.ts +3 -0
- package/dist/i18n/t.js +16 -0
- package/dist/index.d.ts +19 -0
- package/dist/index.js +40 -0
- package/package.json +79 -0
- package/scripts/analyze-styles.ts +124 -0
- package/scripts/auto-wrap-exports.ts +239 -0
- package/scripts/build-css.ts +38 -0
- package/scripts/build-hydration.ts +313 -0
- package/scripts/build-page-styles.ts +43 -0
- package/scripts/copy-assets.ts +34 -0
- package/scripts/dev.sh +3 -0
- package/scripts/dev.ts +257 -0
- package/src/cli.ts +71 -0
- package/src/client/Link.tsx +62 -0
- package/src/client/__tests__/getActiveItemId.test.ts +49 -0
- package/src/client/getActiveItemId.ts +54 -0
- package/src/client/use-i18n.ts +111 -0
- package/src/core/__tests__/component-analyzer.test.ts +141 -0
- package/src/core/__tests__/hydration-manifest.test.ts +223 -0
- package/src/core/__tests__/jsx.engine.test.ts +137 -0
- package/src/core/app-setup.ts +114 -0
- package/src/core/auto-register.module.ts +30 -0
- package/src/core/auto-wrap-middleware.ts +165 -0
- package/src/core/client-component-wrapper.ts +72 -0
- package/src/core/client-hydration.tsx +99 -0
- package/src/core/client-wrapper-browser.ts +40 -0
- package/src/core/component-analyzer.ts +89 -0
- package/src/core/component-auto-wrapper.ts +68 -0
- package/src/core/component-client-wrapper.ts +112 -0
- package/src/core/hydration-generator.ts +94 -0
- package/src/core/hydration-manifest.ts +79 -0
- package/src/core/hydration.ts +70 -0
- package/src/core/jsx.engine.ts +205 -0
- package/src/core/live-reload-client.js +32 -0
- package/src/core/live-reload.controller.ts +55 -0
- package/src/core/navigation.service.ts +257 -0
- package/src/core/router.module.ts +9 -0
- package/src/core/static-assets.controller.ts +19 -0
- package/src/core/types/nav.types.ts +53 -0
- package/src/core/views/layout.tsx +61 -0
- package/src/decorators/jsx.decorator.ts +49 -0
- package/src/decorators/layout.decorator.ts +66 -0
- package/src/i18n/__tests__/i18n.helper.test.ts +126 -0
- package/src/i18n/__tests__/i18n.interceptor.test.ts +229 -0
- package/src/i18n/__tests__/i18n.module.test.ts +98 -0
- package/src/i18n/__tests__/i18n.service.test.ts +129 -0
- package/src/i18n/__tests__/t.test.ts +88 -0
- package/src/i18n/i18n-module.options.ts +53 -0
- package/src/i18n/i18n-switcher.controller.ts +99 -0
- package/src/i18n/i18n-types.ts +56 -0
- package/src/i18n/i18n.helper.ts +75 -0
- package/src/i18n/i18n.interceptor.ts +114 -0
- package/src/i18n/i18n.module.ts +45 -0
- package/src/i18n/i18n.service.ts +95 -0
- package/src/i18n/index.ts +37 -0
- package/src/i18n/locale.decorator.ts +10 -0
- package/src/i18n/t.ts +62 -0
- package/src/index.ts +31 -0
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.I18N_MODULE_OPTIONS = exports.tUnsafe = exports.t = exports.CurrentLocale = exports.I18nSwitcherController = exports.I18nHelper = exports.I18nInterceptor = exports.I18nService = exports.I18nModule = void 0;
|
|
4
|
+
var i18n_module_1 = require("./i18n.module");
|
|
5
|
+
Object.defineProperty(exports, "I18nModule", { enumerable: true, get: function () { return i18n_module_1.I18nModule; } });
|
|
6
|
+
var i18n_service_1 = require("./i18n.service");
|
|
7
|
+
Object.defineProperty(exports, "I18nService", { enumerable: true, get: function () { return i18n_service_1.I18nService; } });
|
|
8
|
+
var i18n_interceptor_1 = require("./i18n.interceptor");
|
|
9
|
+
Object.defineProperty(exports, "I18nInterceptor", { enumerable: true, get: function () { return i18n_interceptor_1.I18nInterceptor; } });
|
|
10
|
+
var i18n_helper_1 = require("./i18n.helper");
|
|
11
|
+
Object.defineProperty(exports, "I18nHelper", { enumerable: true, get: function () { return i18n_helper_1.I18nHelper; } });
|
|
12
|
+
var i18n_switcher_controller_1 = require("./i18n-switcher.controller");
|
|
13
|
+
Object.defineProperty(exports, "I18nSwitcherController", { enumerable: true, get: function () { return i18n_switcher_controller_1.I18nSwitcherController; } });
|
|
14
|
+
var locale_decorator_1 = require("./locale.decorator");
|
|
15
|
+
Object.defineProperty(exports, "CurrentLocale", { enumerable: true, get: function () { return locale_decorator_1.CurrentLocale; } });
|
|
16
|
+
var t_1 = require("./t");
|
|
17
|
+
Object.defineProperty(exports, "t", { enumerable: true, get: function () { return t_1.t; } });
|
|
18
|
+
Object.defineProperty(exports, "tUnsafe", { enumerable: true, get: function () { return t_1.tUnsafe; } });
|
|
19
|
+
var i18n_module_options_1 = require("./i18n-module.options");
|
|
20
|
+
Object.defineProperty(exports, "I18N_MODULE_OPTIONS", { enumerable: true, get: function () { return i18n_module_options_1.I18N_MODULE_OPTIONS; } });
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare const CurrentLocale: (...dataOrPipes: unknown[]) => ParameterDecorator;
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.CurrentLocale = void 0;
|
|
4
|
+
const common_1 = require("@nestjs/common");
|
|
5
|
+
exports.CurrentLocale = (0, common_1.createParamDecorator)((data, ctx) => {
|
|
6
|
+
const request = ctx.switchToHttp().getRequest();
|
|
7
|
+
return request.locale;
|
|
8
|
+
});
|
package/dist/i18n/t.d.ts
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
import type { NestedKeyOf, DeepValue, ExtractVariables } from "./i18n-types";
|
|
2
|
+
export declare function t<TDict extends Record<string, any>, TKey extends NestedKeyOf<TDict>>(dict: TDict, key: TKey, vars?: DeepValue<TDict, TKey> extends string ? ExtractVariables<DeepValue<TDict, TKey>> : Record<string, string | number>): string;
|
|
3
|
+
export declare function tUnsafe(dict: Record<string, any>, key: string, vars?: Record<string, string | number>): string;
|
package/dist/i18n/t.js
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.t = t;
|
|
4
|
+
exports.tUnsafe = tUnsafe;
|
|
5
|
+
function t(dict, key, vars) {
|
|
6
|
+
const value = key.split(".").reduce((acc, k) => acc?.[k], dict);
|
|
7
|
+
if (typeof value !== "string")
|
|
8
|
+
return "";
|
|
9
|
+
return value.replace(/\{\{(.*?)\}\}/g, (_match, k) => String(vars?.[k.trim()] ?? ""));
|
|
10
|
+
}
|
|
11
|
+
function tUnsafe(dict, key, vars) {
|
|
12
|
+
const value = key.split(".").reduce((acc, k) => acc?.[k], dict);
|
|
13
|
+
if (typeof value !== "string")
|
|
14
|
+
return "";
|
|
15
|
+
return value.replace(/\{\{(.*?)\}\}/g, (_match, k) => String(vars?.[k.trim()] ?? ""));
|
|
16
|
+
}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
export { autoWrapClientComponent } from "./core/client-component-wrapper";
|
|
2
|
+
export { hydrationContext, initializeHydrationContext } from "./core/hydration";
|
|
3
|
+
export { getChunkPath, getHydrationManifest } from "./core/hydration-manifest";
|
|
4
|
+
export { withJsxEngine } from "./core/jsx.engine";
|
|
5
|
+
export { LiveReloadController } from "./core/live-reload.controller";
|
|
6
|
+
export { StaticAssetsController } from "./core/static-assets.controller";
|
|
7
|
+
export { JsxRender } from "./decorators/jsx.decorator";
|
|
8
|
+
export { WithLayout } from "./decorators/layout.decorator";
|
|
9
|
+
export type { MetaOptions, RenderOptions } from "./decorators/jsx.decorator";
|
|
10
|
+
export type { JsxLayout, JsxLayoutProps } from "./core/jsx.engine";
|
|
11
|
+
export { RouterModule } from "./core/router.module";
|
|
12
|
+
export { NavigationService } from "./core/navigation.service";
|
|
13
|
+
export { AutoRegisterModule } from "./core/auto-register.module";
|
|
14
|
+
export type { NavItem, NavSection } from "./core/types/nav.types";
|
|
15
|
+
export type { NavigationRegistry } from "./core/types/nav.types";
|
|
16
|
+
export { configureHarpyApp, HarpyAppOptions } from "./core/app-setup";
|
|
17
|
+
export { setupHarpyApp } from "./core/app-setup";
|
|
18
|
+
export { default as Link } from "./client/Link";
|
|
19
|
+
export { buildHrefIndex, getActiveItemIdFromIndex, getActiveItemIdFromManifest, } from "./client/getActiveItemId";
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.getActiveItemIdFromManifest = exports.getActiveItemIdFromIndex = exports.buildHrefIndex = exports.Link = exports.setupHarpyApp = exports.configureHarpyApp = exports.AutoRegisterModule = exports.NavigationService = exports.RouterModule = exports.WithLayout = exports.JsxRender = exports.StaticAssetsController = exports.LiveReloadController = exports.withJsxEngine = exports.getHydrationManifest = exports.getChunkPath = exports.initializeHydrationContext = exports.hydrationContext = exports.autoWrapClientComponent = void 0;
|
|
7
|
+
var client_component_wrapper_1 = require("./core/client-component-wrapper");
|
|
8
|
+
Object.defineProperty(exports, "autoWrapClientComponent", { enumerable: true, get: function () { return client_component_wrapper_1.autoWrapClientComponent; } });
|
|
9
|
+
var hydration_1 = require("./core/hydration");
|
|
10
|
+
Object.defineProperty(exports, "hydrationContext", { enumerable: true, get: function () { return hydration_1.hydrationContext; } });
|
|
11
|
+
Object.defineProperty(exports, "initializeHydrationContext", { enumerable: true, get: function () { return hydration_1.initializeHydrationContext; } });
|
|
12
|
+
var hydration_manifest_1 = require("./core/hydration-manifest");
|
|
13
|
+
Object.defineProperty(exports, "getChunkPath", { enumerable: true, get: function () { return hydration_manifest_1.getChunkPath; } });
|
|
14
|
+
Object.defineProperty(exports, "getHydrationManifest", { enumerable: true, get: function () { return hydration_manifest_1.getHydrationManifest; } });
|
|
15
|
+
var jsx_engine_1 = require("./core/jsx.engine");
|
|
16
|
+
Object.defineProperty(exports, "withJsxEngine", { enumerable: true, get: function () { return jsx_engine_1.withJsxEngine; } });
|
|
17
|
+
var live_reload_controller_1 = require("./core/live-reload.controller");
|
|
18
|
+
Object.defineProperty(exports, "LiveReloadController", { enumerable: true, get: function () { return live_reload_controller_1.LiveReloadController; } });
|
|
19
|
+
var static_assets_controller_1 = require("./core/static-assets.controller");
|
|
20
|
+
Object.defineProperty(exports, "StaticAssetsController", { enumerable: true, get: function () { return static_assets_controller_1.StaticAssetsController; } });
|
|
21
|
+
var jsx_decorator_1 = require("./decorators/jsx.decorator");
|
|
22
|
+
Object.defineProperty(exports, "JsxRender", { enumerable: true, get: function () { return jsx_decorator_1.JsxRender; } });
|
|
23
|
+
var layout_decorator_1 = require("./decorators/layout.decorator");
|
|
24
|
+
Object.defineProperty(exports, "WithLayout", { enumerable: true, get: function () { return layout_decorator_1.WithLayout; } });
|
|
25
|
+
var router_module_1 = require("./core/router.module");
|
|
26
|
+
Object.defineProperty(exports, "RouterModule", { enumerable: true, get: function () { return router_module_1.RouterModule; } });
|
|
27
|
+
var navigation_service_1 = require("./core/navigation.service");
|
|
28
|
+
Object.defineProperty(exports, "NavigationService", { enumerable: true, get: function () { return navigation_service_1.NavigationService; } });
|
|
29
|
+
var auto_register_module_1 = require("./core/auto-register.module");
|
|
30
|
+
Object.defineProperty(exports, "AutoRegisterModule", { enumerable: true, get: function () { return auto_register_module_1.AutoRegisterModule; } });
|
|
31
|
+
var app_setup_1 = require("./core/app-setup");
|
|
32
|
+
Object.defineProperty(exports, "configureHarpyApp", { enumerable: true, get: function () { return app_setup_1.configureHarpyApp; } });
|
|
33
|
+
var app_setup_2 = require("./core/app-setup");
|
|
34
|
+
Object.defineProperty(exports, "setupHarpyApp", { enumerable: true, get: function () { return app_setup_2.setupHarpyApp; } });
|
|
35
|
+
var Link_1 = require("./client/Link");
|
|
36
|
+
Object.defineProperty(exports, "Link", { enumerable: true, get: function () { return __importDefault(Link_1).default; } });
|
|
37
|
+
var getActiveItemId_1 = require("./client/getActiveItemId");
|
|
38
|
+
Object.defineProperty(exports, "buildHrefIndex", { enumerable: true, get: function () { return getActiveItemId_1.buildHrefIndex; } });
|
|
39
|
+
Object.defineProperty(exports, "getActiveItemIdFromIndex", { enumerable: true, get: function () { return getActiveItemId_1.getActiveItemIdFromIndex; } });
|
|
40
|
+
Object.defineProperty(exports, "getActiveItemIdFromManifest", { enumerable: true, get: function () { return getActiveItemId_1.getActiveItemIdFromManifest; } });
|
package/package.json
ADDED
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@harpy-js/core",
|
|
3
|
+
"version": "0.4.7",
|
|
4
|
+
"description": "Harpy - A powerful NestJS + React/JSX SSR framework with automatic hydration and i18n support",
|
|
5
|
+
"main": "dist/index.js",
|
|
6
|
+
"types": "dist/index.d.ts",
|
|
7
|
+
"exports": {
|
|
8
|
+
".": {
|
|
9
|
+
"types": "./dist/index.d.ts",
|
|
10
|
+
"default": "./dist/index.js"
|
|
11
|
+
},
|
|
12
|
+
"./client": {
|
|
13
|
+
"types": "./dist/client/use-i18n.d.ts",
|
|
14
|
+
"default": "./dist/client/use-i18n.js"
|
|
15
|
+
},
|
|
16
|
+
"./client/getActiveItemId": {
|
|
17
|
+
"types": "./dist/client/getActiveItemId.d.ts",
|
|
18
|
+
"default": "./dist/client/getActiveItemId.js"
|
|
19
|
+
},
|
|
20
|
+
"./client/Link": {
|
|
21
|
+
"types": "./dist/client/Link.d.ts",
|
|
22
|
+
"default": "./dist/client/Link.js"
|
|
23
|
+
}
|
|
24
|
+
},
|
|
25
|
+
"bin": {
|
|
26
|
+
"harpy": "./dist/cli.js"
|
|
27
|
+
},
|
|
28
|
+
"files": [
|
|
29
|
+
"dist",
|
|
30
|
+
"scripts",
|
|
31
|
+
"src"
|
|
32
|
+
],
|
|
33
|
+
"scripts": {
|
|
34
|
+
"build": "tsc && cp src/core/live-reload-client.js dist/core/",
|
|
35
|
+
"dev": "tsc --watch",
|
|
36
|
+
"test": "jest",
|
|
37
|
+
"test:watch": "jest --watch",
|
|
38
|
+
"test:coverage": "jest --coverage",
|
|
39
|
+
"prepublishOnly": "npm run build"
|
|
40
|
+
},
|
|
41
|
+
"keywords": [
|
|
42
|
+
"nestjs",
|
|
43
|
+
"react",
|
|
44
|
+
"jsx",
|
|
45
|
+
"ssr",
|
|
46
|
+
"hydration"
|
|
47
|
+
],
|
|
48
|
+
"author": "",
|
|
49
|
+
"license": "MIT",
|
|
50
|
+
"peerDependencies": {
|
|
51
|
+
"@nestjs/common": "^11.0.0",
|
|
52
|
+
"@nestjs/core": "^11.0.0",
|
|
53
|
+
"@nestjs/platform-fastify": "^11.0.0",
|
|
54
|
+
"react": "^19.0.0",
|
|
55
|
+
"react-dom": "^19.0.0"
|
|
56
|
+
},
|
|
57
|
+
"dependencies": {
|
|
58
|
+
"@fastify/cookie": "^11.0.1",
|
|
59
|
+
"chokidar": "^3.6.0",
|
|
60
|
+
"esbuild": "^0.24.2",
|
|
61
|
+
"rxjs": "^7.8.1",
|
|
62
|
+
"tsx": "^4.20.6"
|
|
63
|
+
},
|
|
64
|
+
"devDependencies": {
|
|
65
|
+
"@nestjs/testing": "^11.0.0",
|
|
66
|
+
"@types/jest": "^29.5.0",
|
|
67
|
+
"@types/node": "^22.19.1",
|
|
68
|
+
"@types/react": "^19.2.2",
|
|
69
|
+
"@types/react-dom": "^19.2.2",
|
|
70
|
+
"fastify": "^5.6.2",
|
|
71
|
+
"jest": "^29.7.0",
|
|
72
|
+
"ts-jest": "^29.1.0",
|
|
73
|
+
"typescript": "^5.7.2"
|
|
74
|
+
},
|
|
75
|
+
"publishConfig": {
|
|
76
|
+
"access": "public"
|
|
77
|
+
},
|
|
78
|
+
"gitHead": "d7a4f2ad108c68f2b441ad0c24385b45b1e046a3"
|
|
79
|
+
}
|
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* Analyze page components to determine which styles are used
|
|
4
|
+
* This helps identify page-specific vs common styles
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import * as fs from "fs";
|
|
8
|
+
import * as path from "path";
|
|
9
|
+
|
|
10
|
+
const SRC_DIR = path.join(__dirname, "../src");
|
|
11
|
+
const FEATURES_DIR = path.join(SRC_DIR, "features");
|
|
12
|
+
|
|
13
|
+
interface PageInfo {
|
|
14
|
+
name: string;
|
|
15
|
+
viewFiles: string[];
|
|
16
|
+
classes: Set<string>;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
// Extract Tailwind classes from file content
|
|
20
|
+
function extractClasses(content: string): Set<string> {
|
|
21
|
+
const classes = new Set<string>();
|
|
22
|
+
// Match className="..." and class="..."
|
|
23
|
+
const classMatches = content.match(/(?:className|class)="([^"]*)"/g) || [];
|
|
24
|
+
|
|
25
|
+
classMatches.forEach((match) => {
|
|
26
|
+
const classContent = match
|
|
27
|
+
.replace(/(?:className|class)="/, "")
|
|
28
|
+
.replace(/"$/, "");
|
|
29
|
+
const tokens = classContent.split(/\s+/);
|
|
30
|
+
tokens.forEach((token) => {
|
|
31
|
+
if (token.trim()) classes.add(token);
|
|
32
|
+
});
|
|
33
|
+
});
|
|
34
|
+
|
|
35
|
+
return classes;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
// Find all pages and their view files
|
|
39
|
+
function analyzePages(): PageInfo[] {
|
|
40
|
+
const pages: PageInfo[] = [];
|
|
41
|
+
|
|
42
|
+
if (!fs.existsSync(FEATURES_DIR)) return pages;
|
|
43
|
+
|
|
44
|
+
const featureDirs = fs
|
|
45
|
+
.readdirSync(FEATURES_DIR)
|
|
46
|
+
.filter((f) => fs.statSync(path.join(FEATURES_DIR, f)).isDirectory());
|
|
47
|
+
|
|
48
|
+
featureDirs.forEach((featureName) => {
|
|
49
|
+
const viewsDir = path.join(FEATURES_DIR, featureName, "views");
|
|
50
|
+
if (fs.existsSync(viewsDir)) {
|
|
51
|
+
const viewFiles = fs
|
|
52
|
+
.readdirSync(viewsDir)
|
|
53
|
+
.filter((f) => f.endsWith(".tsx") || f.endsWith(".ts"))
|
|
54
|
+
.map((f) => path.join(viewsDir, f));
|
|
55
|
+
|
|
56
|
+
const classes = new Set<string>();
|
|
57
|
+
viewFiles.forEach((file) => {
|
|
58
|
+
const content = fs.readFileSync(file, "utf-8");
|
|
59
|
+
const fileClasses = extractClasses(content);
|
|
60
|
+
fileClasses.forEach((c) => classes.add(c));
|
|
61
|
+
});
|
|
62
|
+
|
|
63
|
+
pages.push({
|
|
64
|
+
name: featureName,
|
|
65
|
+
viewFiles,
|
|
66
|
+
classes,
|
|
67
|
+
});
|
|
68
|
+
}
|
|
69
|
+
});
|
|
70
|
+
|
|
71
|
+
return pages;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
// Also extract classes from layout
|
|
75
|
+
function getLayoutClasses(): Set<string> {
|
|
76
|
+
const layoutFile = path.join(SRC_DIR, "core/views/layout.tsx");
|
|
77
|
+
if (fs.existsSync(layoutFile)) {
|
|
78
|
+
const content = fs.readFileSync(layoutFile, "utf-8");
|
|
79
|
+
return extractClasses(content);
|
|
80
|
+
}
|
|
81
|
+
return new Set();
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
function main() {
|
|
85
|
+
const pages = analyzePages();
|
|
86
|
+
const layoutClasses = getLayoutClasses();
|
|
87
|
+
|
|
88
|
+
console.log("📊 Page Style Analysis:\n");
|
|
89
|
+
|
|
90
|
+
pages.forEach((page) => {
|
|
91
|
+
console.log(`${page.name}: ${page.classes.size} classes`);
|
|
92
|
+
console.log(
|
|
93
|
+
` Files: ${page.viewFiles.map((f) => path.basename(f)).join(", ")}`,
|
|
94
|
+
);
|
|
95
|
+
});
|
|
96
|
+
|
|
97
|
+
console.log(`\nlayout: ${layoutClasses.size} classes`);
|
|
98
|
+
console.log("\nCommon classes (used across multiple pages):");
|
|
99
|
+
|
|
100
|
+
const commonClasses = new Set<string>();
|
|
101
|
+
const classUsage = new Map<string, number>();
|
|
102
|
+
|
|
103
|
+
// Count usage across all pages and layout
|
|
104
|
+
layoutClasses.forEach((c) => classUsage.set(c, (classUsage.get(c) || 0) + 1));
|
|
105
|
+
pages.forEach((page) => {
|
|
106
|
+
page.classes.forEach((c) => {
|
|
107
|
+
classUsage.set(c, (classUsage.get(c) || 0) + 1);
|
|
108
|
+
});
|
|
109
|
+
});
|
|
110
|
+
|
|
111
|
+
classUsage.forEach((count, className) => {
|
|
112
|
+
if (count > 1) {
|
|
113
|
+
commonClasses.add(className);
|
|
114
|
+
}
|
|
115
|
+
});
|
|
116
|
+
|
|
117
|
+
console.log(`Total common: ${commonClasses.size}`);
|
|
118
|
+
console.log(
|
|
119
|
+
"Sample common classes:",
|
|
120
|
+
Array.from(commonClasses).slice(0, 10).join(", "),
|
|
121
|
+
);
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
main();
|
|
@@ -0,0 +1,239 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Post-build script to automatically wrap client component exports
|
|
5
|
+
*
|
|
6
|
+
* This script:
|
|
7
|
+
* 1. Identifies components with 'use client' directive in source
|
|
8
|
+
* 2. Automatically wraps their compiled exports with autoWrapClientComponent
|
|
9
|
+
* 3. Allows developers to write components without manual wrapping
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
import * as fs from "fs";
|
|
13
|
+
import * as path from "path";
|
|
14
|
+
|
|
15
|
+
const PROJECT_ROOT = process.cwd();
|
|
16
|
+
const SRC_DIR = path.join(PROJECT_ROOT, "src");
|
|
17
|
+
const DIST_DIR = path.join(PROJECT_ROOT, "dist");
|
|
18
|
+
|
|
19
|
+
interface ClientComponentInfo {
|
|
20
|
+
sourceFile: string;
|
|
21
|
+
compiledFile: string;
|
|
22
|
+
componentName: string;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* Find all TypeScript/TSX files with 'use client' directive
|
|
27
|
+
*/
|
|
28
|
+
function findClientComponentsInSource(): Map<string, string> {
|
|
29
|
+
const clientComponents = new Map<string, string>(); // compiledFile -> componentName
|
|
30
|
+
const extensions = [".ts", ".tsx"];
|
|
31
|
+
|
|
32
|
+
function walkDir(dir: string) {
|
|
33
|
+
if (!fs.existsSync(dir)) return;
|
|
34
|
+
|
|
35
|
+
const entries = fs.readdirSync(dir, { withFileTypes: true });
|
|
36
|
+
|
|
37
|
+
for (const entry of entries) {
|
|
38
|
+
const fullPath = path.join(dir, entry.name);
|
|
39
|
+
|
|
40
|
+
if (entry.isDirectory()) {
|
|
41
|
+
if (!entry.name.startsWith(".") && entry.name !== "node_modules") {
|
|
42
|
+
walkDir(fullPath);
|
|
43
|
+
}
|
|
44
|
+
} else if (extensions.includes(path.extname(entry.name))) {
|
|
45
|
+
try {
|
|
46
|
+
const content = fs.readFileSync(fullPath, "utf-8");
|
|
47
|
+
|
|
48
|
+
// Check for 'use client' directive at the start of the file
|
|
49
|
+
if (/^['"]use client['"]/.test(content.trim())) {
|
|
50
|
+
const fileName = path.basename(fullPath, path.extname(fullPath));
|
|
51
|
+
// Convert kebab-case to PascalCase
|
|
52
|
+
const componentName = fileName
|
|
53
|
+
.split("-")
|
|
54
|
+
.map((part) => part.charAt(0).toUpperCase() + part.slice(1))
|
|
55
|
+
.join("");
|
|
56
|
+
|
|
57
|
+
// Calculate the corresponding compiled file path
|
|
58
|
+
const relativePath = path.relative(SRC_DIR, fullPath);
|
|
59
|
+
const compiledPath = path.join(
|
|
60
|
+
DIST_DIR,
|
|
61
|
+
relativePath.replace(/\.tsx?$/, ".js"),
|
|
62
|
+
);
|
|
63
|
+
|
|
64
|
+
clientComponents.set(compiledPath, componentName);
|
|
65
|
+
}
|
|
66
|
+
} catch (error) {
|
|
67
|
+
console.error(`Error reading file ${fullPath}:`, error);
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
walkDir(SRC_DIR);
|
|
74
|
+
return clientComponents;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
/**
|
|
78
|
+
* Transform a compiled JavaScript file to wrap the default export
|
|
79
|
+
* Handles SWC's Object.defineProperty pattern
|
|
80
|
+
*/
|
|
81
|
+
function transformCompiledFile(
|
|
82
|
+
filePath: string,
|
|
83
|
+
componentName: string,
|
|
84
|
+
): boolean {
|
|
85
|
+
try {
|
|
86
|
+
if (!fs.existsSync(filePath)) {
|
|
87
|
+
console.warn(`⚠️ File not found: ${filePath}`);
|
|
88
|
+
return false;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
let content = fs.readFileSync(filePath, "utf-8");
|
|
92
|
+
|
|
93
|
+
// Skip if already wrapped (contains autoWrapClientComponent)
|
|
94
|
+
if (content.includes("autoWrapClientComponent")) {
|
|
95
|
+
console.log(` ✓ Already wrapped: ${path.basename(filePath)}`);
|
|
96
|
+
return true;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
// Import the wrapper from @harpy-js/core package instead of relative path
|
|
100
|
+
const normalizedRelativePath = "@harpy-js/core";
|
|
101
|
+
|
|
102
|
+
// Add the require at the top of the file (after the 'use strict' and initial Object.defineProperty)
|
|
103
|
+
const requireStatement = `var { autoWrapClientComponent: _autoWrapClientComponent } = require("${normalizedRelativePath}");`;
|
|
104
|
+
|
|
105
|
+
// Ensure the require statement is added before any wrapping
|
|
106
|
+
if (
|
|
107
|
+
!content.includes(requireStatement) &&
|
|
108
|
+
!content.includes("_autoWrapClientComponent")
|
|
109
|
+
) {
|
|
110
|
+
// Check if we have the 'use client' and Object.defineProperty pattern
|
|
111
|
+
if (
|
|
112
|
+
content.includes('"use strict"') &&
|
|
113
|
+
content.includes("Object.defineProperty")
|
|
114
|
+
) {
|
|
115
|
+
// Find the last Object.defineProperty line before any exports
|
|
116
|
+
const lines = content.split("\n");
|
|
117
|
+
let insertIndex = -1;
|
|
118
|
+
|
|
119
|
+
for (let i = 0; i < lines.length; i++) {
|
|
120
|
+
if (lines[i].includes("Object.defineProperty(exports")) {
|
|
121
|
+
insertIndex = i + 1;
|
|
122
|
+
break;
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
if (insertIndex !== -1) {
|
|
127
|
+
lines.splice(insertIndex, 0, requireStatement);
|
|
128
|
+
content = lines.join("\n");
|
|
129
|
+
}
|
|
130
|
+
} else {
|
|
131
|
+
// Fallback: insert at the beginning after any initial comments
|
|
132
|
+
const lines = content.split("\n");
|
|
133
|
+
let insertIndex = 0;
|
|
134
|
+
for (let i = 0; i < lines.length; i++) {
|
|
135
|
+
if (lines[i].includes('"use strict"')) {
|
|
136
|
+
insertIndex = i + 1;
|
|
137
|
+
break;
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
lines.splice(insertIndex, 0, requireStatement);
|
|
141
|
+
content = lines.join("\n");
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
// SWC pattern: const _default = ComponentName;
|
|
146
|
+
const swcPattern = new RegExp(
|
|
147
|
+
`const\\s+_default\\s*=\\s*${componentName}\\s*;`,
|
|
148
|
+
);
|
|
149
|
+
|
|
150
|
+
if (swcPattern.test(content)) {
|
|
151
|
+
// Replace the _default assignment with a wrapped version
|
|
152
|
+
content = content.replace(
|
|
153
|
+
`const _default = ${componentName};`,
|
|
154
|
+
`const _default = _autoWrapClientComponent(${componentName}, '${componentName}');`,
|
|
155
|
+
);
|
|
156
|
+
|
|
157
|
+
fs.writeFileSync(filePath, content, "utf-8");
|
|
158
|
+
console.log(` ✓ Wrapped: ${path.basename(filePath)}`);
|
|
159
|
+
return true;
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
// CommonJS pattern: exports.default = ComponentName;
|
|
163
|
+
const pattern1 = new RegExp(
|
|
164
|
+
`exports\\.default\\s*=\\s*${componentName}\\s*;`,
|
|
165
|
+
);
|
|
166
|
+
if (pattern1.test(content)) {
|
|
167
|
+
content = content.replace(
|
|
168
|
+
pattern1,
|
|
169
|
+
`var { autoWrapClientComponent } = require("${normalizedRelativePath}");\nexports.default = autoWrapClientComponent(${componentName}, '${componentName}');`,
|
|
170
|
+
);
|
|
171
|
+
fs.writeFileSync(filePath, content, "utf-8");
|
|
172
|
+
console.log(` ✓ Wrapped: ${path.basename(filePath)}`);
|
|
173
|
+
return true;
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
// ES6 pattern: export default ComponentName;
|
|
177
|
+
const pattern2 = new RegExp(`export\\s+default\\s+${componentName}\\s*;`);
|
|
178
|
+
if (pattern2.test(content)) {
|
|
179
|
+
content = content.replace(
|
|
180
|
+
`export default ${componentName};`,
|
|
181
|
+
`import { autoWrapClientComponent as _autoWrapClientComponent } from "${normalizedRelativePath}";\nexport default _autoWrapClientComponent(${componentName}, '${componentName}');`,
|
|
182
|
+
);
|
|
183
|
+
fs.writeFileSync(filePath, content, "utf-8");
|
|
184
|
+
console.log(` ✓ Wrapped: ${path.basename(filePath)}`);
|
|
185
|
+
return true;
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
// Named export pattern: exports.ComponentName = ComponentName;
|
|
189
|
+
const namedExportPattern = new RegExp(
|
|
190
|
+
`exports\\.${componentName}\\s*=\\s*${componentName}\\s*;`,
|
|
191
|
+
);
|
|
192
|
+
if (namedExportPattern.test(content)) {
|
|
193
|
+
content = content.replace(
|
|
194
|
+
namedExportPattern,
|
|
195
|
+
`exports.${componentName} = _autoWrapClientComponent(${componentName}, '${componentName}');`,
|
|
196
|
+
);
|
|
197
|
+
fs.writeFileSync(filePath, content, "utf-8");
|
|
198
|
+
console.log(` ✓ Wrapped: ${path.basename(filePath)}`);
|
|
199
|
+
return true;
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
console.warn(
|
|
203
|
+
` ⚠️ Could not find export pattern for ${componentName} in ${path.basename(filePath)}`,
|
|
204
|
+
);
|
|
205
|
+
return false;
|
|
206
|
+
} catch (error) {
|
|
207
|
+
console.error(` ✗ Error transforming ${path.basename(filePath)}:`, error);
|
|
208
|
+
return false;
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
/**
|
|
213
|
+
* Main function
|
|
214
|
+
*/
|
|
215
|
+
function main(): void {
|
|
216
|
+
console.log("🔄 Auto-wrapping client component exports...\n");
|
|
217
|
+
|
|
218
|
+
const clientComponents = findClientComponentsInSource();
|
|
219
|
+
|
|
220
|
+
if (clientComponents.size === 0) {
|
|
221
|
+
console.log("⚠️ No client components found\n");
|
|
222
|
+
return;
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
console.log(`Found ${clientComponents.size} client component(s):\n`);
|
|
226
|
+
|
|
227
|
+
let wrapped = 0;
|
|
228
|
+
for (const [compiledPath, componentName] of clientComponents) {
|
|
229
|
+
if (transformCompiledFile(compiledPath, componentName)) {
|
|
230
|
+
wrapped++;
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
console.log(
|
|
235
|
+
`\n✨ Auto-wrap complete: ${wrapped}/${clientComponents.size} components wrapped\n`,
|
|
236
|
+
);
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
main();
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* Build script for Tailwind CSS v4
|
|
4
|
+
* Compiles src/assets/styles.css to public/styles.css
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import * as fs from "fs";
|
|
8
|
+
import * as path from "path";
|
|
9
|
+
|
|
10
|
+
const inputFile = path.join(__dirname, "../src/assets/styles.css");
|
|
11
|
+
const outputFile = path.join(__dirname, "../public/styles.css");
|
|
12
|
+
|
|
13
|
+
// Create public directory if it doesn't exist
|
|
14
|
+
const publicDir = path.dirname(outputFile);
|
|
15
|
+
if (!fs.existsSync(publicDir)) {
|
|
16
|
+
fs.mkdirSync(publicDir, { recursive: true });
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
// Read the input CSS file
|
|
20
|
+
const inputCSS = fs.readFileSync(inputFile, "utf8");
|
|
21
|
+
|
|
22
|
+
// Import and compile with Tailwind v4
|
|
23
|
+
(async () => {
|
|
24
|
+
const tailwindModule = await import("@tailwindcss/postcss");
|
|
25
|
+
const compile =
|
|
26
|
+
(tailwindModule as any).default || (tailwindModule as any).compile;
|
|
27
|
+
|
|
28
|
+
try {
|
|
29
|
+
const output = await compile(inputCSS, {
|
|
30
|
+
file: inputFile,
|
|
31
|
+
});
|
|
32
|
+
fs.writeFileSync(outputFile, output.toString());
|
|
33
|
+
console.log("✅ CSS compiled successfully");
|
|
34
|
+
} catch (err) {
|
|
35
|
+
console.error("❌ CSS compilation failed:", err);
|
|
36
|
+
process.exit(1);
|
|
37
|
+
}
|
|
38
|
+
})();
|