@common-stack/generate-plugin 5.0.2-alpha.4

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.
Files changed (49) hide show
  1. package/.eslintrc.json +32 -0
  2. package/CHANGELOG.md +16 -0
  3. package/LICENSE +21 -0
  4. package/README.md +11 -0
  5. package/generators.json +9 -0
  6. package/jest.config.ts +10 -0
  7. package/lib/generators/add-entries/entries/antui/entry.client.tsx.template +100 -0
  8. package/lib/generators/add-entries/entries/antui/entry.server.tsx.template +254 -0
  9. package/lib/generators/add-entries/entries/antui/root.tsx.template +107 -0
  10. package/lib/generators/add-entries/entries/chakraui/context.tsx.template +20 -0
  11. package/lib/generators/add-entries/entries/chakraui/entry.client.tsx.template +105 -0
  12. package/lib/generators/add-entries/entries/chakraui/entry.server.tsx.template +256 -0
  13. package/lib/generators/add-entries/entries/chakraui/root.tsx.template +97 -0
  14. package/lib/generators/add-entries/files/common/AntStyles.tsx.template +8 -0
  15. package/lib/generators/add-entries/files/common/createEmotionCache.ts.template +7 -0
  16. package/lib/generators/add-entries/files/common/index.ts.template +3 -0
  17. package/lib/generators/add-entries/files/common/utils.ts.template +16 -0
  18. package/lib/generators/add-entries/generator.cjs +55 -0
  19. package/lib/generators/add-entries/generator.cjs.map +1 -0
  20. package/lib/generators/add-entries/generator.d.ts +4 -0
  21. package/lib/generators/add-entries/generator.mjs +55 -0
  22. package/lib/generators/add-entries/generator.mjs.map +1 -0
  23. package/lib/generators/add-entries/generator.spec.d.ts +1 -0
  24. package/lib/generators/add-entries/schema.json +13 -0
  25. package/lib/index.cjs +1 -0
  26. package/lib/index.cjs.map +1 -0
  27. package/lib/index.d.ts +1 -0
  28. package/lib/index.mjs +1 -0
  29. package/lib/index.mjs.map +1 -0
  30. package/package.json +28 -0
  31. package/project.json +7 -0
  32. package/rollup.config.mjs +65 -0
  33. package/src/generators/add-entries/entries/antui/entry.client.tsx.template +100 -0
  34. package/src/generators/add-entries/entries/antui/entry.server.tsx.template +254 -0
  35. package/src/generators/add-entries/entries/antui/root.tsx.template +107 -0
  36. package/src/generators/add-entries/entries/chakraui/context.tsx.template +20 -0
  37. package/src/generators/add-entries/entries/chakraui/entry.client.tsx.template +105 -0
  38. package/src/generators/add-entries/entries/chakraui/entry.server.tsx.template +256 -0
  39. package/src/generators/add-entries/entries/chakraui/root.tsx.template +97 -0
  40. package/src/generators/add-entries/files/common/AntStyles.tsx.template +8 -0
  41. package/src/generators/add-entries/files/common/createEmotionCache.ts.template +7 -0
  42. package/src/generators/add-entries/files/common/index.ts.template +3 -0
  43. package/src/generators/add-entries/files/common/utils.ts.template +16 -0
  44. package/src/generators/add-entries/generator.spec.ts +20 -0
  45. package/src/generators/add-entries/generator.ts +66 -0
  46. package/src/generators/add-entries/schema.d.ts +3 -0
  47. package/src/generators/add-entries/schema.json +13 -0
  48. package/src/index.ts +2 -0
  49. package/tsconfig.json +26 -0
@@ -0,0 +1,105 @@
1
+ import React, { useState, startTransition, StrictMode } from 'react';
2
+ import 'reflect-metadata';
3
+ import { RemixBrowser } from '@remix-run/react';
4
+ import { hydrateRoot } from 'react-dom/client';
5
+ import { ApolloProvider } from '@apollo/client/index.js';
6
+ import { SlotFillProvider, removeUniversalPortals } from '@common-stack/components-pro';
7
+ import { InversifyProvider, PluginArea } from '@common-stack/client-react';
8
+ import { Provider as ReduxProvider } from 'react-redux';
9
+ import { PersistGate } from 'redux-persist/integration/react';
10
+ import { persistStore } from 'redux-persist';
11
+ import { CacheProvider } from '@emotion/react';
12
+
13
+ // @ts-ignore
14
+ import createEmotionCache, { defaultCache } from '@app/frontend-stack-react/entries/common/createEmotionCache';
15
+ // @ts-ignore
16
+ import { createReduxStore } from '@app/frontend-stack-react/config/redux-config.js';
17
+ // @ts-ignore
18
+ import { createClientContainer } from '@app/frontend-stack-react/config/client.service';
19
+ // @ts-ignore
20
+ import clientModules from '@app/frontend-stack-react/modules.js';
21
+
22
+ import i18next from 'i18next';
23
+ import { I18nextProvider, initReactI18next } from 'react-i18next';
24
+ import LanguageDetector from 'i18next-browser-languagedetector';
25
+ import Backend from 'i18next-http-backend';
26
+ // @ts-ignore
27
+ import { getInitialNamespaces } from 'remix-i18next/client';
28
+ import config from '@app/cde-webconfig.json';
29
+ // @ts-ignore
30
+ import { ClientStyleContext } from '@app/frontend-stack-react/entries/chakraui/context.js';
31
+
32
+ const { apolloClient: client, container, serviceFunc } = createClientContainer();
33
+ const { store } = createReduxStore(client, serviceFunc(), container);
34
+ const persistor = persistStore(store);
35
+
36
+ (window as any).__remixStore = store;
37
+ removeUniversalPortals((window as any).__SLOT_FILLS__ || []);
38
+
39
+ interface ClientCacheProviderProps {
40
+ children: React.ReactNode;
41
+ }
42
+
43
+ function ClientCacheProvider({ children }: ClientCacheProviderProps) {
44
+ const [cache, setCache] = useState(defaultCache);
45
+
46
+ function reset() {
47
+ setCache(createEmotionCache());
48
+ }
49
+
50
+ return (
51
+ <ClientStyleContext.Provider value={{ reset }}>
52
+ <CacheProvider value={cache}>{children}</CacheProvider>
53
+ </ClientStyleContext.Provider>
54
+ );
55
+ }
56
+
57
+ async function hydrate() {
58
+ if (!i18next.isInitialized && config.i18n.enabled) {
59
+ await i18next
60
+ .use(initReactI18next)
61
+ .use(LanguageDetector)
62
+ .use(Backend)
63
+ .init({
64
+ fallbackLng: config.i18n.fallbackLng,
65
+ defaultNS: config.i18n.defaultNS,
66
+ react: config.i18n.react,
67
+ supportedLngs: config.i18n.supportedLngs,
68
+ backend: config.i18n.backend,
69
+ ns: getInitialNamespaces(),
70
+ detection: {
71
+ order: ['htmlTag'],
72
+ caches: [],
73
+ },
74
+ });
75
+ }
76
+ hydrateRoot(
77
+ document.getElementById('root')!,
78
+ <StrictMode>
79
+ <I18nextProvider i18n={i18next}>
80
+ <ClientCacheProvider>
81
+ <ApolloProvider client={client}>
82
+ <ReduxProvider store={store}>
83
+ <SlotFillProvider>
84
+ <InversifyProvider container={container} modules={clientModules}>
85
+ <PersistGate loading={null} persistor={persistor}>
86
+ {() => <RemixBrowser />}
87
+ </PersistGate>
88
+ </InversifyProvider>
89
+ </SlotFillProvider>
90
+ </ReduxProvider>
91
+ </ApolloProvider>
92
+ </ClientCacheProvider>
93
+ </I18nextProvider>
94
+ </StrictMode>,
95
+ );
96
+ // });
97
+ }
98
+
99
+ if (typeof requestIdleCallback === 'function') {
100
+ requestIdleCallback(hydrate);
101
+ } else {
102
+ // Safari doesn't support requestIdleCallback
103
+ // https://caniuse.com/requestidlecallback
104
+ setTimeout(hydrate, 1);
105
+ }
@@ -0,0 +1,256 @@
1
+ /**
2
+ * By default, Remix will handle generating the HTTP Response for you.
3
+ * You are free to delete this file if you'd like to, but if you ever want it revealed again, you can run `npx remix reveal` ✨
4
+ * For more information, see https://remix.run/file-conventions/entry.server
5
+ */
6
+ // @ts-nocheck
7
+ global.__CLIENT__ = false;
8
+ global.__SERVER__ = true;
9
+ import React from 'react';
10
+ import { PassThrough, Transform } from 'node:stream';
11
+ import type { AppLoadContext, EntryContext } from '@remix-run/node';
12
+ import { createReadableStreamFromReadable } from '@remix-run/node';
13
+ import { RemixServer } from '@remix-run/react';
14
+ import { isbot } from 'isbot';
15
+ import { ApolloProvider } from '@apollo/client/index.js';
16
+ import { SlotFillProvider } from '@common-stack/components-pro';
17
+ import { InversifyProvider, PluginArea } from '@common-stack/client-react';
18
+ import { renderToPipeableStream, renderToString } from 'react-dom/server';
19
+ import { Provider as ReduxProvider } from 'react-redux';
20
+ import { LOCATION_CHANGE } from '@common-stack/remix-router-redux';
21
+ import serialize from 'serialize-javascript';
22
+ import { CacheProvider } from '@emotion/react';
23
+ import createEmotionServer from '@emotion/server/create-instance';
24
+ import Backend from 'i18next-fs-backend';
25
+ import { renderToString } from 'react-dom/server';
26
+ import { renderHeadToString } from 'remix-island';
27
+ import publicEnv from '@src/config/public-config';
28
+ import { I18nextProvider, initReactI18next } from 'react-i18next';
29
+ import { createInstance } from 'i18next';
30
+ import { resolve } from 'node:path';
31
+ // import { renderStylesToNodeStream } from '@emotion/server';
32
+ // @ts-ignore
33
+ import { defaultCache } from '@app/frontend-stack-react/entries/common/createEmotionCache.js';
34
+ // @ts-ignore
35
+ import config from '@app/cde-webconfig.json';
36
+
37
+ import { Head } from './root';
38
+ import type { IAppLoadContext } from '@common-stack/client-core';
39
+ import { ServerStyleContext } from '@app/frontend-stack-react/entries/chakraui/context.js';
40
+ import { i18nextInstance as i18next } from '@app/frontend-stack-react/i18n-localization/i18next.server.js';
41
+ const { extractCriticalToChunks } = createEmotionServer(defaultCache);
42
+
43
+ const ABORT_DELAY = 5000;
44
+ const COMMON_HEAD = `
45
+ <meta charset="utf-8" />
46
+ <meta name="viewport" content="width=device-width,initial-scale=1" />
47
+ `;
48
+
49
+ export default function handleRequest(
50
+ request: Request,
51
+ responseStatusCode: number,
52
+ responseHeaders: Headers,
53
+ remixContext: EntryContext,
54
+ // This is ignored so we can keep it in the template for visibility. Feel
55
+ // free to delete this parameter in your app if you're not using it!
56
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
57
+ loadContext: AppLoadContext,
58
+ ) {
59
+ return isbot(request.headers.get('user-agent') || '')
60
+ ? handleBotRequest(request, responseStatusCode, responseHeaders, remixContext, loadContext)
61
+ : handleBrowserRequest(request, responseStatusCode, responseHeaders, remixContext, loadContext);
62
+ }
63
+
64
+ function handleBotRequest(
65
+ request: Request,
66
+ responseStatusCode: number,
67
+ responseHeaders: Headers,
68
+ remixContext: EntryContext,
69
+ loadContext: IAppLoadContext,
70
+ ) {
71
+ return new Promise((resolve, reject) => {
72
+ let shellRendered = false;
73
+ const { pipe, abort } = renderToPipeableStream(
74
+ <RemixServer context={remixContext} url={request.url} abortDelay={ABORT_DELAY} />,
75
+ {
76
+ onAllReady() {
77
+ shellRendered = true;
78
+
79
+ const head = renderHeadToString({ request, remixContext, Head });
80
+ const body = new PassThrough();
81
+
82
+ responseHeaders.set('Content-Type', 'text/html');
83
+ const stream = createReadableStreamFromReadable(body);
84
+ resolve(
85
+ new Response(stream, {
86
+ headers: responseHeaders,
87
+ status: responseStatusCode,
88
+ }),
89
+ );
90
+ body.write(`<!DOCTYPE html><html><head>${COMMON_HEAD}${head}</head><body><div id="root">`);
91
+ pipe(body);
92
+ body.write(`</div></body></html>`);
93
+ },
94
+ onShellError(error: unknown) {
95
+ reject(error);
96
+ },
97
+ onError(error: unknown) {
98
+ responseStatusCode = 500;
99
+ // Log streaming rendering errors from inside the shell. Don't log
100
+ // errors encountered during initial shell rendering since they'll
101
+ // reject and get logged in handleDocumentRequest.
102
+ if (shellRendered) {
103
+ console.error(error);
104
+ }
105
+ },
106
+ },
107
+ );
108
+
109
+ setTimeout(abort, ABORT_DELAY);
110
+ });
111
+ }
112
+
113
+ async function handleBrowserRequest(
114
+ request: Request,
115
+ responseStatusCode: number,
116
+ responseHeaders: Headers,
117
+ remixContext: EntryContext,
118
+ loadContext: IAppLoadContext,
119
+ ) {
120
+ const instance = createInstance();
121
+
122
+ // Then we could detect locale from the request
123
+ const lng = await i18next.getLocale(request);
124
+ // And here we detect what namespaces the routes about to render want to use
125
+ const ns = i18next.getRouteNamespaces(remixContext);
126
+ const slotFillContext = { fills: {} };
127
+ const {
128
+ modules: clientModules,
129
+ container,
130
+ apolloClient: client,
131
+ store,
132
+ }: IAppLoadContext = loadContext;
133
+
134
+ // First, we create a new instance of i18next so every request will have a
135
+ // completely unique instance and not share any state.
136
+ if (config.i18n.enabled) {
137
+ await instance
138
+ .use(initReactI18next) // Tell our instance to use react-i18next
139
+ .use(Backend) // Setup our backend.init({
140
+ .init({
141
+ fallbackLng: config.i18n.fallbackLng,
142
+ defaultNS: config.i18n.defaultNS,
143
+ react: config.i18n.react,
144
+ supportedLngs: config.i18n.supportedLngs,
145
+ lng, // The locale we detected above
146
+ ns, // The namespaces the routes about to render want to use
147
+ backend: {
148
+ loadPath: resolve(config.i18n.backend.loadServerPath),
149
+ },
150
+ });
151
+ }
152
+
153
+ const html = renderToString(
154
+ <I18nextProvider i18n={instance}>
155
+ <CacheProvider value={defaultCache}>
156
+ <ApolloProvider client={client}>
157
+ <ReduxProvider store={store}>
158
+ <SlotFillProvider context={slotFillContext}>
159
+ <InversifyProvider container={container} modules={clientModules}>
160
+ <RemixServer context={remixContext} url={request.url} />
161
+ </InversifyProvider>
162
+ </SlotFillProvider>
163
+ </ReduxProvider>
164
+ </ApolloProvider>
165
+ </CacheProvider>
166
+ </I18nextProvider>,
167
+ );
168
+
169
+ const chunks = extractCriticalToChunks(html);
170
+
171
+ return new Promise((resolve, reject) => {
172
+ let shellRendered = false;
173
+
174
+ const { pathname, search, hash } = new URL(request.url);
175
+ store.dispatch({
176
+ type: LOCATION_CHANGE,
177
+ payload: { location: { pathname, search, hash }, action: 'POP' },
178
+ });
179
+
180
+ const { pipe, abort } = renderToPipeableStream(
181
+ (
182
+ <I18nextProvider i18n={instance}>
183
+ <ServerStyleContext.Provider value={chunks.styles}>
184
+ <CacheProvider value={defaultCache}>
185
+ <ApolloProvider client={client}>
186
+ <ReduxProvider store={store}>
187
+ <SlotFillProvider context={slotFillContext}>
188
+ <InversifyProvider container={container} modules={clientModules}>
189
+ <RemixServer
190
+ context={remixContext}
191
+ url={request.url}
192
+ abortDelay={ABORT_DELAY}
193
+ />
194
+ </InversifyProvider>
195
+ </SlotFillProvider>
196
+ </ReduxProvider>
197
+ </ApolloProvider>
198
+ </CacheProvider>
199
+ </ServerStyleContext.Provider>
200
+ </I18nextProvider>
201
+ ) as any,
202
+ {
203
+ onShellReady() {
204
+ shellRendered = true;
205
+ const head = renderHeadToString({ request, remixContext, Head });
206
+ const body = new PassThrough();
207
+ const stream = createReadableStreamFromReadable(body);
208
+ const apolloState = { ...client.extract() };
209
+ const reduxState = { ...store.getState() };
210
+ const fills = Object.keys(slotFillContext.fills);
211
+ // const transform = new ConstantsTransform(fills, apolloState, reduxState);
212
+
213
+ let customHead = `<script>window.__ENV__=${JSON.stringify(publicEnv)}</script>`;
214
+ customHead += `<script>window.__APOLLO_STATE__=${serialize(apolloState, {
215
+ isJSON: true,
216
+ })}</script>`;
217
+ customHead += `<script>window.__PRELOADED_STATE__=${serialize(reduxState, {
218
+ isJSON: true,
219
+ })}</script>`;
220
+ customHead += `<script>window.__SLOT_FILLS__=${serialize(fills, { isJSON: true })}</script>`;
221
+ customHead += `<script>if (global === undefined) { var global = window; }</script>`;
222
+
223
+ responseHeaders.set('Content-Type', 'text/html');
224
+
225
+ resolve(
226
+ new Response(stream, {
227
+ headers: responseHeaders,
228
+ status: responseStatusCode,
229
+ }),
230
+ );
231
+ body.write(
232
+ `<!DOCTYPE html><html lng=${lng}><head>${COMMON_HEAD}${customHead}${head}</head><body><div id="root">`,
233
+ );
234
+ pipe(body);
235
+ body.write(`</div></body></html>`);
236
+ // pipe(transform).pipe(renderStylesToNodeStream()).pipe(body);
237
+ },
238
+ onShellError(error: unknown) {
239
+ reject(error);
240
+ },
241
+ onError(error: unknown) {
242
+ responseStatusCode = 500;
243
+ // Log streaming rendering errors from inside the shell. Don't log
244
+ // errors encountered during initial shell rendering since they'll
245
+ // reject and get logged in handleDocumentRequest.
246
+ if (shellRendered) {
247
+ console.error(error);
248
+ }
249
+ reject(error);
250
+ },
251
+ },
252
+ );
253
+
254
+ setTimeout(abort, ABORT_DELAY);
255
+ });
256
+ }
@@ -0,0 +1,97 @@
1
+ // @ts-nocheck
2
+ import * as React from 'react';
3
+
4
+ import { Links, Meta, Outlet, Scripts, ScrollRestoration, useLoaderData } from '@remix-run/react';
5
+ import { json } from '@remix-run/node';
6
+ import { PluginArea } from '@common-stack/client-react';
7
+ import { subscribeReduxRouter } from '@common-stack/remix-router-redux';
8
+
9
+ import { ApplicationErrorHandler } from '@admin-layout/chakra-ui';
10
+ // @ts-ignore
11
+ import clientModules, { plugins } from '@app/frontend-stack-react/modules.js';
12
+ import { createHead } from 'remix-island';
13
+ import { useContext } from 'react';
14
+ import { ServerStyleContext, ClientStyleContext } from './context';
15
+ import { withEmotionCache } from '@emotion/react';
16
+ import { useChangeLanguage } from 'remix-i18next/react';
17
+ import { i18nextInstance as i18next } from '@app/frontend-stack-react/i18n-localization/i18next.server.js';
18
+ import { ErrorBoundary } from '@app/frontend-stack-react/entries/chakraui/components/ErrorBoundary.js';
19
+
20
+ interface DocumentProps {
21
+ children: React.ReactNode;
22
+ }
23
+
24
+ export const Head = createHead(() => (
25
+ <>
26
+ <Meta />
27
+ <Links />
28
+ </>
29
+ ));
30
+
31
+ export const Document = withEmotionCache(({ children }: DocumentProps, emotionCache) => {
32
+ const serverStyleData = useContext(ServerStyleContext);
33
+ const clientStyleData = useContext(ClientStyleContext);
34
+
35
+ React.useEffect(() => {
36
+ // re-link sheet container
37
+ emotionCache.sheet.container = document.head;
38
+ // re-inject tags
39
+ const tags = emotionCache.sheet.tags;
40
+ emotionCache.sheet.flush();
41
+ tags.forEach((tag) => {
42
+ (emotionCache.sheet as any)._insertTag(tag);
43
+ });
44
+ // reset cache to reapply global styles
45
+ clientStyleData?.reset();
46
+ }, []);
47
+
48
+ return (
49
+ <>
50
+ <Head />
51
+ {serverStyleData?.map(({ key, ids, css }) => (
52
+ <style key={key} data-emotion={`${key} ${ids.join(' ')}`} dangerouslySetInnerHTML={{ __html: css }} />
53
+ ))}
54
+ <script
55
+ src="https://cdnjs.cloudflare.com/ajax/libs/reflect-metadata/0.1.13/Reflect.min.js"
56
+ integrity="sha512-jvbPH2TH5BSZumEfOJZn9IV+5bSwwN+qG4dvthYe3KCGC3/9HmxZ4phADbt9Pfcp+XSyyfc2vGZ/RMsSUZ9tbQ=="
57
+ crossOrigin="anonymous"
58
+ referrerPolicy="no-referrer"
59
+ ></script>
60
+ <PluginArea />
61
+ {children}
62
+ <ScrollRestoration />
63
+ <Scripts />
64
+ </>
65
+ );
66
+ });
67
+
68
+ export let loader = async ({ request }) => {
69
+ let locale = await i18next.getLocale(request);
70
+ return json({ locale });
71
+ };
72
+
73
+ export let handle = {
74
+ i18n: 'common',
75
+ };
76
+
77
+ export function shouldRevalidate(params: any) {
78
+ return params.defaultShouldRevalidate && params.currentUrl.pathname !== params.nextUrl.pathname;
79
+ }
80
+
81
+ export default function App() {
82
+ let { locale } = useLoaderData();
83
+
84
+ useChangeLanguage(locale);
85
+
86
+ React.useEffect(() => {
87
+ subscribeReduxRouter({ store: window.__remixStore, router: window.__remixRouter } as any);
88
+ }, []);
89
+
90
+ return (
91
+ <ApplicationErrorHandler plugins={plugins}>
92
+ <Document>{clientModules.getWrappedRoot(<Outlet />)}</Document>
93
+ </ApplicationErrorHandler>
94
+ );
95
+ }
96
+
97
+ export { ErrorBoundary };
@@ -0,0 +1,8 @@
1
+ import * as React from 'react';
2
+ import { createCache as createAntdCache, extractStyle, StyleProvider } from '@ant-design/cssinjs';
3
+
4
+ const antdCache = createAntdCache();
5
+ export const styleSheet = extractStyle(antdCache);
6
+ export const AntSytles = ({ children }: { children: React.ReactNode }) => (
7
+ <StyleProvider cache={antdCache}>{children}</StyleProvider>
8
+ );
@@ -0,0 +1,7 @@
1
+ import createCache from '@emotion/cache';
2
+
3
+ export const defaultCache = createEmotionCache();
4
+
5
+ export default function createEmotionCache() {
6
+ return createCache({ key: 'css', prepend: true });
7
+ }
@@ -0,0 +1,3 @@
1
+ export * from './AntStyles';
2
+ export * from './createEmotionCache';
3
+ export * from './utils';
@@ -0,0 +1,16 @@
1
+ import { isEmpty } from 'lodash-es';
2
+
3
+ export function jsonToString(json) {
4
+ if (isEmpty(json)) {
5
+ return '';
6
+ }
7
+
8
+ if (Array.isArray(json)) {
9
+ let arr = json.map((a) => jsonToString(a));
10
+ return arr.join(' ');
11
+ }
12
+
13
+ const str = JSON.stringify(json);
14
+ const arr = str.split(',');
15
+ return Array.isArray(arr) ? arr.join(' ') : str;
16
+ }
@@ -0,0 +1,20 @@
1
+ import { createTreeWithEmptyWorkspace } from '@nx/devkit/testing';
2
+ import { Tree, readProjectConfiguration } from '@nx/devkit';
3
+
4
+ import { addEntriesGenerator } from './generator';
5
+ import { AddEntriesGeneratorSchema } from './schema';
6
+
7
+ describe('add-entries generator', () => {
8
+ let tree: Tree;
9
+ const options: AddEntriesGeneratorSchema = { projectPath: '/' };
10
+
11
+ beforeEach(() => {
12
+ tree = createTreeWithEmptyWorkspace();
13
+ });
14
+
15
+ it('should run successfully', async () => {
16
+ await addEntriesGenerator(tree, options);
17
+ const config = readProjectConfiguration(tree, 'test');
18
+ expect(config).toBeDefined();
19
+ });
20
+ });
@@ -0,0 +1,66 @@
1
+ import { addProjectConfiguration, formatFiles, generateFiles, Tree } from '@nx/devkit';
2
+ import * as path from 'path';
3
+ import { AddEntriesGeneratorSchema } from './schema';
4
+ import * as fs from 'node:fs';
5
+
6
+ const loadJSON = (path) => {
7
+ const content = fs.readFileSync(path);
8
+ return JSON.parse(content as any);
9
+ }
10
+
11
+ const getFramework = async (projectRoot) => {
12
+ // const mergeConfigPath = path.join(projectRoot, 'tools', 'mergeConfig.js');
13
+ // const webConfigPath = path.join(projectRoot, 'app', 'cde-webconfig.json');
14
+ const configPath = `${projectRoot}/config.json`;
15
+
16
+ try {
17
+ const json = loadJSON(configPath);
18
+ return json?.uiFramework;
19
+ } catch(err) {
20
+ console.warn('Error while getting UI framework', err.message);
21
+ return null;
22
+ }
23
+ }
24
+
25
+ const resetProject = (rootDir: string) => {
26
+ if (fs.existsSync(`${rootDir}/project.json`)) {
27
+ fs.unlinkSync(`${rootDir}/project.json`);
28
+ }
29
+ if (fs.existsSync(`${rootDir}/src`)) {
30
+ fs.rmSync(`${rootDir}/src`, { recursive: true, force: true });
31
+ }
32
+ }
33
+
34
+ export async function addEntriesGenerator(tree: Tree, options: AddEntriesGeneratorSchema) {
35
+ const basePath = process.cwd();
36
+ const projectRoot = `${basePath}/${options.projectPath}`;
37
+ const projectSrc = `${options.projectPath}/src`;
38
+ // const sourcePath = path.join(__dirname, 'entries');
39
+ try {
40
+ let framework = await getFramework(projectRoot);
41
+ if (!framework) {
42
+ framework = 'antui';
43
+ }
44
+ console.log('UI framework specified: ', framework);
45
+
46
+ resetProject(projectRoot);
47
+
48
+ // addProjectConfiguration(tree, framework, {
49
+ // root: projectRoot,
50
+ // projectType: 'library',
51
+ // sourceRoot: projectSrc,
52
+ // targets: {},
53
+ // });
54
+
55
+ generateFiles(tree, path.join(__dirname, 'files'), projectSrc, {});
56
+ generateFiles(tree, path.join(__dirname, 'entries', framework), projectSrc, options);
57
+ // await fs.cpSync(path.join(__dirname, 'files'), projectSrc, {recursive: true});
58
+ // await fs.cpSync(path.join(__dirname, 'entries', framework), projectSrc, {recursive: true});
59
+ await formatFiles(tree);
60
+
61
+ } catch (err) {
62
+ console.error('Error while generating entries: ', err);
63
+ }
64
+ }
65
+
66
+ export default addEntriesGenerator;
@@ -0,0 +1,3 @@
1
+ export interface AddEntriesGeneratorSchema {
2
+ projectPath: string;
3
+ }
@@ -0,0 +1,13 @@
1
+ {
2
+ "$schema": "https://json-schema.org/schema",
3
+ "$id": "AddEntries",
4
+ "title": "",
5
+ "type": "object",
6
+ "properties": {
7
+ "projectPath": {
8
+ "type": "string",
9
+ "description": "The project relative path (ex: servers/frontend-server)"
10
+ }
11
+ },
12
+ "required": ["projectPath"]
13
+ }
package/src/index.ts ADDED
@@ -0,0 +1,2 @@
1
+ export * from './generators/add-entries/generator';
2
+ // export const schema = import('./generators/add-entries/schema.json');
package/tsconfig.json ADDED
@@ -0,0 +1,26 @@
1
+ {
2
+ "extends": "../../tsconfig.json",
3
+ "compilerOptions": {
4
+ "jsx": "react",
5
+ "module": "ESNext",
6
+ "resolveJsonModule": true,
7
+ "target": "ES6",
8
+ "lib": ["es5","es6"],
9
+ "esModuleInterop": true,
10
+ "allowSyntheticDefaultImports": true,
11
+ "experimentalDecorators": true,
12
+ "rootDir": "src",
13
+ "outDir": "lib",
14
+ "declaration": true,
15
+ "preserveConstEnums": true,
16
+ "declarationDir": "lib",
17
+ "skipLibCheck": true
18
+ },
19
+ "include": ["src"],
20
+ "exclude": [
21
+ "node_modules",
22
+ "lib",
23
+ "dist",
24
+ "rollup.config.mjs"
25
+ ]
26
+ }