create-arui-scripts-app 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (50) hide show
  1. package/README.md +58 -0
  2. package/assets/.yarn/releases/yarn-4.9.1.cjs +948 -0
  3. package/bin/create-arui-scripts-app.js +3 -0
  4. package/build/build-context.d.ts +2 -0
  5. package/build/build-context.js +83 -0
  6. package/build/build-file-map.d.ts +3 -0
  7. package/build/build-file-map.js +49 -0
  8. package/build/cli.d.ts +1 -0
  9. package/build/cli.js +15 -0
  10. package/build/create-program.d.ts +5 -0
  11. package/build/create-program.js +103 -0
  12. package/build/defaults.d.ts +21 -0
  13. package/build/defaults.js +48 -0
  14. package/build/install-dependencies.d.ts +3 -0
  15. package/build/install-dependencies.js +39 -0
  16. package/build/questions.d.ts +3 -0
  17. package/build/questions.js +126 -0
  18. package/build/run.d.ts +9 -0
  19. package/build/run.js +191 -0
  20. package/build/templates/app-component.template.d.ts +2 -0
  21. package/build/templates/app-component.template.js +73 -0
  22. package/build/templates/app-styles.template.d.ts +3 -0
  23. package/build/templates/app-styles.template.js +31 -0
  24. package/build/templates/app-test.template.d.ts +2 -0
  25. package/build/templates/app-test.template.js +14 -0
  26. package/build/templates/arui-scripts-config.template.d.ts +2 -0
  27. package/build/templates/arui-scripts-config.template.js +46 -0
  28. package/build/templates/client-entry.template.d.ts +2 -0
  29. package/build/templates/client-entry.template.js +105 -0
  30. package/build/templates/misc.template.d.ts +6 -0
  31. package/build/templates/misc.template.js +74 -0
  32. package/build/templates/package-json.template.d.ts +2 -0
  33. package/build/templates/package-json.template.js +36 -0
  34. package/build/templates/server-entry.template.d.ts +2 -0
  35. package/build/templates/server-entry.template.js +115 -0
  36. package/build/templates/store.template.d.ts +3 -0
  37. package/build/templates/store.template.js +63 -0
  38. package/build/templates/tsconfig.template.d.ts +2 -0
  39. package/build/templates/tsconfig.template.js +14 -0
  40. package/build/templates/vitest-config.template.d.ts +1 -0
  41. package/build/templates/vitest-config.template.js +18 -0
  42. package/build/types.d.ts +34 -0
  43. package/build/types.js +2 -0
  44. package/build/validate-project-name.d.ts +1 -0
  45. package/build/validate-project-name.js +20 -0
  46. package/build/versions.d.ts +4 -0
  47. package/build/versions.js +7 -0
  48. package/build/write-files.d.ts +4 -0
  49. package/build/write-files.js +59 -0
  50. package/package.json +56 -0
@@ -0,0 +1,115 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.serverEntryTemplate = serverEntryTemplate;
4
+ function serverEntryTemplate(ctx) {
5
+ const reduxImport = ctx.useRtk ? "\nimport { Provider } from 'react-redux';" : '';
6
+ const storeImport = ctx.useRtk ? "\nimport { makeStore } from '../client/store';" : '';
7
+ const renderPageFn = ctx.useRtk
8
+ ? `function renderPage(appHtml: string, assets: Assets, preloadedState: string): string {
9
+ const css = assets.css
10
+ .map((href) => '<link rel="stylesheet" href="/' + href + '" />')
11
+ .join('');
12
+ const js = assets.js.map((src) => '<script src="/' + src + '"></script>').join('');
13
+ const state = '<script>window.__PRELOADED_STATE__ = ' + preloadedState + ';</script>';
14
+
15
+ return (
16
+ '<!DOCTYPE html><html lang="ru"><head><meta charset="utf-8" /><base href="/" />' +
17
+ css +
18
+ '</head><body><div id="react-app">' +
19
+ appHtml +
20
+ '</div>' +
21
+ state +
22
+ js +
23
+ '</body></html>'
24
+ );
25
+ }`
26
+ : `function renderPage(appHtml: string, assets: Assets): string {
27
+ const css = assets.css
28
+ .map((href) => '<link rel="stylesheet" href="/' + href + '" />')
29
+ .join('');
30
+ const js = assets.js.map((src) => '<script src="/' + src + '"></script>').join('');
31
+
32
+ return (
33
+ '<!DOCTYPE html><html lang="ru"><head><meta charset="utf-8" /><base href="/" />' +
34
+ css +
35
+ '</head><body><div id="react-app">' +
36
+ appHtml +
37
+ '</div>' +
38
+ js +
39
+ '</body></html>'
40
+ );
41
+ }`;
42
+ const handlerBody = ctx.useRtk
43
+ ? ` const assets = await readAssetsManifest();
44
+ const store = makeStore();
45
+ const appHtml = renderToString(
46
+ <Provider store={store}>
47
+ <App />
48
+ </Provider>,
49
+ );
50
+ // Экранируем символ "<", чтобы через состояние нельзя было внедрить теги в HTML
51
+ const preloadedState = JSON.stringify(store.getState()).replace(/</g, '\\\\u003c');
52
+
53
+ return renderPage(appHtml, assets, preloadedState);`
54
+ : ` const assets = await readAssetsManifest();
55
+ const appHtml = renderToString(<App />);
56
+
57
+ return renderPage(appHtml, assets);`;
58
+ return `import path from 'path';
59
+
60
+ import Hapi from '@hapi/hapi';
61
+ import Inert from '@hapi/inert';
62
+ import React from 'react';
63
+ import { renderToString } from 'react-dom/server';${reduxImport}
64
+
65
+ import { readAssetsManifest } from '@alfalab/scripts-server';
66
+
67
+ import { App } from '../client/components/app';${storeImport}
68
+
69
+ const PORT = ${ctx.serverPort};
70
+
71
+ type Assets = {
72
+ css: string[];
73
+ js: string[];
74
+ };
75
+
76
+ ${renderPageFn}
77
+
78
+ async function start() {
79
+ const server = Hapi.server({
80
+ port: PORT,
81
+ routes: {
82
+ files: {
83
+ relativeTo: path.join(process.cwd(), '.build'),
84
+ },
85
+ },
86
+ });
87
+
88
+ await server.register(Inert);
89
+
90
+ server.route({
91
+ method: 'GET',
92
+ path: '/assets/{param*}',
93
+ handler: {
94
+ directory: {
95
+ path: 'assets',
96
+ },
97
+ },
98
+ });
99
+
100
+ server.route({
101
+ method: 'GET',
102
+ path: '/',
103
+ handler: async () => {
104
+ ${handlerBody}
105
+ },
106
+ });
107
+
108
+ await server.start();
109
+ // eslint-disable-next-line no-console
110
+ console.log('Server is listening on ' + server.info.uri);
111
+ }
112
+
113
+ start();
114
+ `;
115
+ }
@@ -0,0 +1,3 @@
1
+ export declare function storeIndexTemplate(): string;
2
+ export declare function storeHooksTemplate(): string;
3
+ export declare function counterSliceTemplate(): string;
@@ -0,0 +1,63 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.storeIndexTemplate = storeIndexTemplate;
4
+ exports.storeHooksTemplate = storeHooksTemplate;
5
+ exports.counterSliceTemplate = counterSliceTemplate;
6
+ function storeIndexTemplate() {
7
+ return `import { combineReducers, configureStore } from '@reduxjs/toolkit';
8
+
9
+ import { counterReducer } from './counter-slice';
10
+
11
+ const rootReducer = combineReducers({
12
+ counter: counterReducer,
13
+ });
14
+
15
+ export function makeStore(preloadedState?: Partial<RootState>) {
16
+ return configureStore({
17
+ reducer: rootReducer,
18
+ preloadedState,
19
+ });
20
+ }
21
+
22
+ export type RootState = ReturnType<typeof rootReducer>;
23
+ export type AppStore = ReturnType<typeof makeStore>;
24
+ export type AppDispatch = AppStore['dispatch'];
25
+ `;
26
+ }
27
+ function storeHooksTemplate() {
28
+ return `import { useDispatch, useSelector } from 'react-redux';
29
+
30
+ import type { AppDispatch, RootState } from './index';
31
+
32
+ export const useAppDispatch = useDispatch.withTypes<AppDispatch>();
33
+ export const useAppSelector = useSelector.withTypes<RootState>();
34
+ `;
35
+ }
36
+ function counterSliceTemplate() {
37
+ return `import { createSlice } from '@reduxjs/toolkit';
38
+
39
+ type CounterState = {
40
+ value: number;
41
+ };
42
+
43
+ const initialState: CounterState = {
44
+ value: 0,
45
+ };
46
+
47
+ const counterSlice = createSlice({
48
+ name: 'counter',
49
+ initialState,
50
+ reducers: {
51
+ increment: (state) => {
52
+ state.value += 1;
53
+ },
54
+ decrement: (state) => {
55
+ state.value -= 1;
56
+ },
57
+ },
58
+ });
59
+
60
+ export const { increment, decrement } = counterSlice.actions;
61
+ export const counterReducer = counterSlice.reducer;
62
+ `;
63
+ }
@@ -0,0 +1,2 @@
1
+ import { type TemplateContext } from '../types';
2
+ export declare function tsconfigTemplate(ctx: TemplateContext): string;
@@ -0,0 +1,14 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.tsconfigTemplate = tsconfigTemplate;
4
+ function tsconfigTemplate(ctx) {
5
+ const types = ctx.testRunner === 'jest' ? ['jest', 'node', 'webpack-env'] : ['node', 'webpack-env'];
6
+ const tsconfig = {
7
+ extends: 'arui-scripts/tsconfig.json',
8
+ include: ['global-definitions.d.ts', 'src/**/*.ts', 'src/**/*.tsx'],
9
+ compilerOptions: {
10
+ types,
11
+ },
12
+ };
13
+ return `${JSON.stringify(tsconfig, null, 4)}\n`;
14
+ }
@@ -0,0 +1 @@
1
+ export declare function vitestConfigTemplate(): string;
@@ -0,0 +1,18 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.vitestConfigTemplate = vitestConfigTemplate;
4
+ function vitestConfigTemplate() {
5
+ return `import { defineConfig, mergeConfig } from 'vitest/config';
6
+
7
+ import aruiConfig from 'arui-scripts/vitest';
8
+
9
+ export default mergeConfig(
10
+ aruiConfig,
11
+ defineConfig({
12
+ test: {
13
+ // тут можно переопределить настройки Vitest
14
+ },
15
+ }),
16
+ );
17
+ `;
18
+ }
@@ -0,0 +1,34 @@
1
+ export type CodeLoader = 'swc' | 'babel' | 'tsc';
2
+ export type TestRunner = 'jest' | 'vitest';
3
+ export type InitAnswers = {
4
+ name: string;
5
+ useRtk: boolean;
6
+ clientOnly: boolean;
7
+ codeLoader: CodeLoader;
8
+ testRunner: TestRunner;
9
+ cssModules: boolean;
10
+ clientServerPort: number;
11
+ serverPort: number;
12
+ dockerRegistry: string;
13
+ presets: string;
14
+ polyfills: boolean;
15
+ reactCompiler: boolean;
16
+ install: boolean;
17
+ };
18
+ export type TemplateContext = {
19
+ name: string;
20
+ useRtk: boolean;
21
+ clientOnly: boolean;
22
+ codeLoader: CodeLoader;
23
+ testRunner: TestRunner;
24
+ cssModules: boolean;
25
+ clientServerPort: number;
26
+ serverPort: number;
27
+ dockerRegistry: string;
28
+ presets: string;
29
+ polyfills: boolean;
30
+ reactCompiler: boolean;
31
+ aruiScriptsVersion: string;
32
+ dependencies: Record<string, string>;
33
+ devDependencies: Record<string, string>;
34
+ };
package/build/types.js ADDED
@@ -0,0 +1,2 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
@@ -0,0 +1 @@
1
+ export declare function validateProjectName(name: string): true | string;
@@ -0,0 +1,20 @@
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.validateProjectName = validateProjectName;
7
+ const validate_npm_package_name_1 = __importDefault(require("validate-npm-package-name"));
8
+ function validateProjectName(name) {
9
+ var _a, _b;
10
+ const trimmed = name.trim();
11
+ if (!trimmed) {
12
+ return 'Имя проекта не может быть пустым';
13
+ }
14
+ const result = (0, validate_npm_package_name_1.default)(trimmed);
15
+ if (result.validForNewPackages) {
16
+ return true;
17
+ }
18
+ const messages = [...((_a = result.errors) !== null && _a !== void 0 ? _a : []), ...((_b = result.warnings) !== null && _b !== void 0 ? _b : [])];
19
+ return messages.join('; ') || 'Некорректное имя пакета';
20
+ }
@@ -0,0 +1,4 @@
1
+ /** Версия arui-scripts, которую scaffold кладёт в package.json нового проекта.
2
+ * Генерируется скриптом scripts/sync-arui-scripts-version.js при сборке.
3
+ */
4
+ export declare const DEFAULT_ARUI_SCRIPTS_VERSION = "23.2.0";
@@ -0,0 +1,7 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.DEFAULT_ARUI_SCRIPTS_VERSION = void 0;
4
+ /** Версия arui-scripts, которую scaffold кладёт в package.json нового проекта.
5
+ * Генерируется скриптом scripts/sync-arui-scripts-version.js при сборке.
6
+ */
7
+ exports.DEFAULT_ARUI_SCRIPTS_VERSION = '23.2.0';
@@ -0,0 +1,4 @@
1
+ export declare function findConflictingFiles(targetDir: string, files: Record<string, string>, extraPaths?: string[]): Promise<string[]>;
2
+ export declare function writeFiles(targetDir: string, files: Record<string, string>): Promise<void>;
3
+ export declare const STATIC_ASSET_PATHS: string[];
4
+ export declare function copyStaticAssets(targetDir: string): Promise<number>;
@@ -0,0 +1,59 @@
1
+ "use strict";
2
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
3
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
4
+ return new (P || (P = Promise))(function (resolve, reject) {
5
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
6
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
7
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
8
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
9
+ });
10
+ };
11
+ var __importDefault = (this && this.__importDefault) || function (mod) {
12
+ return (mod && mod.__esModule) ? mod : { "default": mod };
13
+ };
14
+ Object.defineProperty(exports, "__esModule", { value: true });
15
+ exports.STATIC_ASSET_PATHS = void 0;
16
+ exports.findConflictingFiles = findConflictingFiles;
17
+ exports.writeFiles = writeFiles;
18
+ exports.copyStaticAssets = copyStaticAssets;
19
+ const path_1 = __importDefault(require("path"));
20
+ const fs_extra_1 = __importDefault(require("fs-extra"));
21
+ function findConflictingFiles(targetDir_1, files_1) {
22
+ return __awaiter(this, arguments, void 0, function* (targetDir, files, extraPaths = []) {
23
+ const conflicts = [];
24
+ yield Promise.all([...Object.keys(files), ...extraPaths].map((relPath) => __awaiter(this, void 0, void 0, function* () {
25
+ if (yield fs_extra_1.default.pathExists(path_1.default.join(targetDir, relPath))) {
26
+ conflicts.push(relPath);
27
+ }
28
+ })));
29
+ return conflicts.sort();
30
+ });
31
+ }
32
+ function writeFiles(targetDir, files) {
33
+ return __awaiter(this, void 0, void 0, function* () {
34
+ yield fs_extra_1.default.ensureDir(targetDir);
35
+ yield Promise.all(Object.keys(files).map((relPath) => fs_extra_1.default.outputFile(path_1.default.join(targetDir, relPath), files[relPath])));
36
+ });
37
+ }
38
+ // статические ассеты, которые копируются в проект как есть (к примеру, .yarn/releases)
39
+ const STATIC_ASSETS_DIR = path_1.default.join(__dirname, '../assets');
40
+ // пути, которые создает copyStaticAssets в целевой директории (для проверки конфликтов)
41
+ exports.STATIC_ASSET_PATHS = ['.yarn'];
42
+ function countFiles(dir) {
43
+ return __awaiter(this, void 0, void 0, function* () {
44
+ const entries = yield fs_extra_1.default.readdir(dir);
45
+ const counts = yield Promise.all(entries.map((entry) => __awaiter(this, void 0, void 0, function* () {
46
+ const entryPath = path_1.default.join(dir, entry);
47
+ const stat = yield fs_extra_1.default.stat(entryPath);
48
+ return stat.isDirectory() ? countFiles(entryPath) : 1;
49
+ })));
50
+ return counts.reduce((sum, count) => sum + count, 0);
51
+ });
52
+ }
53
+ // копирует статические ассеты и возвращает количество скопированных файлов
54
+ function copyStaticAssets(targetDir) {
55
+ return __awaiter(this, void 0, void 0, function* () {
56
+ yield fs_extra_1.default.copy(STATIC_ASSETS_DIR, targetDir);
57
+ return countFiles(STATIC_ASSETS_DIR);
58
+ });
59
+ }
package/package.json ADDED
@@ -0,0 +1,56 @@
1
+ {
2
+ "name": "create-arui-scripts-app",
3
+ "version": "1.0.0",
4
+ "description": "CLI для генерации нового react приложения на arui-scripts",
5
+ "license": "MPL-2.0",
6
+ "repository": {
7
+ "type": "git",
8
+ "url": "git+https://github.com/core-ds/arui-scripts.git"
9
+ },
10
+ "bugs": {
11
+ "url": "https://github.com/core-ds/arui-scripts/issues"
12
+ },
13
+ "homepage": "https://github.com/core-ds/arui-scripts/tree/master/packages/create-arui-scripts-app#readme",
14
+ "bin": "./bin/create-arui-scripts-app.js",
15
+ "main": "./build/run.js",
16
+ "typings": "./build/run.d.ts",
17
+ "files": [
18
+ "assets",
19
+ "bin",
20
+ "build"
21
+ ],
22
+ "scripts": {
23
+ "sync:version": "node ./scripts/sync-arui-scripts-version.js",
24
+ "build": "yarn sync:version && tsc --project tsconfig.json",
25
+ "test": "jest",
26
+ "lint:scripts": "arui-presets-lint scripts",
27
+ "format": "arui-presets-lint format",
28
+ "format:check": "arui-presets-lint format:check",
29
+ "lint": "yarn lint:scripts && yarn format:check",
30
+ "lint:fix": "yarn lint:scripts --fix && yarn format",
31
+ "audit": "yarn npm audit --severity high --environment production"
32
+ },
33
+ "dependencies": {
34
+ "chalk": "^2.4.2",
35
+ "commander": "^12",
36
+ "fs-extra": "6.0.1",
37
+ "ora": "^5",
38
+ "prompts": "^2.4.2",
39
+ "shelljs": "0.8.5",
40
+ "validate-npm-package-name": "^5.0.1"
41
+ },
42
+ "devDependencies": {
43
+ "@types/fs-extra": "^9.0.13",
44
+ "@types/jest": "^29.5.14",
45
+ "@types/node": "^20.19.0",
46
+ "@types/prompts": "^2.4.9",
47
+ "@types/shelljs": "^0.8.12",
48
+ "@types/validate-npm-package-name": "^3.0.3",
49
+ "jest": "28.1.3",
50
+ "ts-jest": "28.0.8",
51
+ "typescript": "6.0.2"
52
+ },
53
+ "engines": {
54
+ "node": "^20.19.0 || >=22.12.0"
55
+ }
56
+ }