@stripchatdev/create-stripchat-extension 0.1.45 → 0.1.47
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/dist/bin/cli/actions/updateAction.d.ts +6 -0
- package/dist/bin/cli/actions/updateAction.js +33 -0
- package/dist/bin/cli/helpers/printCliError.d.ts +1 -0
- package/dist/bin/cli/helpers/printCliError.js +21 -0
- package/dist/bin/cli/index.js +70 -0
- package/dist/bin/create.d.ts +2 -0
- package/dist/bin/create.js +238 -0
- package/dist/package.json +5 -2
- package/dist/src/constants.d.ts +14 -9
- package/dist/src/constants.js +53 -8
- package/dist/src/dependencies/constants.d.ts +2 -0
- package/dist/src/dependencies/constants.js +11 -0
- package/dist/src/dependencies/resolveDependencies.d.ts +6 -0
- package/dist/src/dependencies/resolveDependencies.js +43 -0
- package/dist/src/dependencies/resolveDependencies.test.js +74 -0
- package/dist/src/helpers/error.d.ts +3 -0
- package/dist/src/helpers/error.js +9 -0
- package/dist/src/helpers/error.test.js +15 -0
- package/dist/src/helpers/getIsDirectoryExists.d.ts +7 -0
- package/dist/src/helpers/getIsDirectoryExists.js +23 -0
- package/dist/src/helpers/getIsDirectoryExists.test.js +34 -0
- package/dist/src/helpers/getIsJsxFramework.d.ts +2 -0
- package/dist/src/helpers/getIsJsxFramework.js +2 -0
- package/dist/src/helpers/getIsJsxFramework.test.js +10 -0
- package/dist/src/helpers/getIsTypescript.d.ts +2 -0
- package/dist/src/helpers/getIsTypescript.js +1 -0
- package/dist/src/helpers/getIsTypescript.test.js +10 -0
- package/dist/src/helpers/isSubPath.d.ts +1 -0
- package/dist/src/helpers/isSubPath.js +5 -0
- package/dist/src/helpers/normalizePath.d.ts +2 -0
- package/dist/src/helpers/normalizePath.js +4 -0
- package/dist/src/helpers/normalizePath.test.js +19 -0
- package/dist/src/migrator/executor.d.ts +9 -0
- package/dist/src/migrator/executor.js +112 -0
- package/dist/src/migrator/migration.d.ts +3 -0
- package/dist/src/migrator/migration.js +18 -0
- package/dist/src/migrator/migration.test.js +74 -0
- package/dist/src/migrator/migrations/migrations.test.js +97 -0
- package/dist/src/migrator/migrations/v2/AGENTS_md/001_recreate-with-generated-part.d.ts +2 -0
- package/dist/src/migrator/migrations/v2/AGENTS_md/001_recreate-with-generated-part.js +14 -0
- package/dist/src/migrator/migrations/v2/_project-config_json/001_create.d.ts +2 -0
- package/dist/src/migrator/migrations/v2/_project-config_json/001_create.js +14 -0
- package/dist/src/migrator/migrations/v2/vite_config_ts/001_turn_off_minify_and_assets_inline.d.ts +2 -0
- package/dist/src/migrator/migrations/v2/vite_config_ts/001_turn_off_minify_and_assets_inline.js +118 -0
- package/dist/src/migrator/planner.d.ts +5 -0
- package/dist/src/migrator/planner.js +65 -0
- package/dist/src/migrator/planner.test.js +40 -0
- package/dist/src/migrator/types.d.ts +29 -0
- package/dist/src/migrator/updates/updates.test.js +102 -0
- package/dist/src/migrator/updates/v2/AGENTS_md/001_update-generated-part.d.ts +2 -0
- package/dist/src/migrator/updates/v2/AGENTS_md/001_update-generated-part.js +38 -0
- package/dist/src/migrator/updates/v2/package_json/001_update-versions.d.ts +2 -0
- package/dist/src/migrator/updates/v2/package_json/001_update-versions.js +77 -0
- package/dist/src/migrator/updates/v2/package_json/002_add-cli-commands.d.ts +2 -0
- package/dist/src/migrator/updates/v2/package_json/002_add-cli-commands.js +61 -0
- package/dist/src/migrator/validators/getIsValidMigration.d.ts +2 -0
- package/dist/src/migrator/validators/getIsValidMigration.js +3 -0
- package/dist/src/migrator/validators/getIsValidMigration.test.js +13 -0
- package/dist/src/projectConfig/buildProjectConfig.d.ts +15 -0
- package/dist/src/projectConfig/buildProjectConfig.js +27 -0
- package/dist/src/projectConfig/detectPackageManagerRuntime.d.ts +2 -0
- package/dist/src/{helpers/detectPackageManager.js → projectConfig/detectPackageManagerRuntime.js} +1 -1
- package/dist/src/{helpers/detectPackageManager.test.js → projectConfig/detectPackageManagerRuntime.test.js} +10 -10
- package/dist/src/projectConfig/recoverProjectConfig.d.ts +1 -0
- package/dist/src/projectConfig/recoverProjectConfig.js +34 -0
- package/dist/src/projectConfig/recovery/detectPackageManagerFromFiles.d.ts +2 -0
- package/dist/src/projectConfig/recovery/detectPackageManagerFromFiles.js +16 -0
- package/dist/src/projectConfig/recovery/detectPackageManagerFromFiles.test.d.ts +1 -0
- package/dist/src/projectConfig/recovery/detectPackageManagerFromFiles.test.js +37 -0
- package/dist/src/projectConfig/recovery/parseAgentsMd.d.ts +10 -0
- package/dist/src/projectConfig/recovery/parseAgentsMd.js +52 -0
- package/dist/src/projectConfig/recovery/parseAgentsMd.test.d.ts +1 -0
- package/dist/src/projectConfig/recovery/parseAgentsMd.test.js +67 -0
- package/dist/src/projectConfig/recovery/resolveProjectNameFromDir.d.ts +1 -0
- package/dist/src/projectConfig/recovery/resolveProjectNameFromDir.js +11 -0
- package/dist/src/projectConfig/recovery/resolveProjectNameFromDir.test.d.ts +1 -0
- package/dist/src/projectConfig/recovery/resolveProjectNameFromDir.test.js +21 -0
- package/dist/src/projectConfig/resolveExistsProjectConfig.d.ts +2 -0
- package/dist/src/projectConfig/resolveExistsProjectConfig.js +34 -0
- package/dist/src/projectConfig/updateProjectConfig.d.ts +2 -0
- package/dist/src/projectConfig/updateProjectConfig.js +20 -0
- package/dist/src/projectConfig/validators/getIsValidProjectConfig.d.ts +2 -0
- package/dist/src/projectConfig/validators/getIsValidProjectConfig.js +6 -0
- package/dist/src/projectConfig/validators/getIsValidProjectConfig.test.d.ts +1 -0
- package/dist/src/projectConfig/validators/getIsValidProjectConfig.test.js +33 -0
- package/dist/src/projectConfig/validators/validateProjectConfig.d.ts +2 -0
- package/dist/src/projectConfig/validators/validateProjectConfig.js +30 -0
- package/dist/src/projectConfig/validators/validateProjectConfig.test.d.ts +1 -0
- package/dist/src/projectConfig/validators/validateProjectConfig.test.js +215 -0
- package/dist/src/templater/executor.d.ts +2 -0
- package/dist/src/templater/executor.js +22 -0
- package/dist/src/templater/executor.test.d.ts +1 -0
- package/dist/src/{executor.test.js → templater/executor.test.js} +25 -11
- package/dist/src/templater/helpers/getIsTypescriptOnlyFile.d.ts +1 -0
- package/dist/src/templater/helpers/getIsTypescriptOnlyFile.js +10 -0
- package/dist/src/templater/helpers/getIsTypescriptOnlyFile.test.d.ts +1 -0
- package/dist/src/templater/helpers/getIsTypescriptOnlyFile.test.js +25 -0
- package/dist/src/templater/helpers/resolveTemplateExtension.d.ts +1 -0
- package/dist/src/templater/helpers/resolveTemplateExtension.js +16 -0
- package/dist/src/templater/helpers/resolveTemplateExtension.test.d.ts +1 -0
- package/dist/src/{mappers → templater/mappers}/mapProjectConfigToTemplateModel.d.ts +1 -1
- package/dist/src/{mappers → templater/mappers}/mapProjectConfigToTemplateModel.js +6 -8
- package/dist/src/templater/mappers/mapProjectConfigToTemplateModel.test.d.ts +1 -0
- package/dist/src/{mappers → templater/mappers}/mapProjectConfigToTemplateModel.test.js +29 -23
- package/dist/src/templater/planner.d.ts +2 -0
- package/dist/src/templater/planner.js +104 -0
- package/dist/src/templater/planner.test.d.ts +1 -0
- package/dist/src/templater/planner.test.js +64 -0
- package/dist/src/templates/constants.d.ts +6 -0
- package/dist/src/templates/constants.js +11 -0
- package/dist/src/templates/helpers/resolveTemplatesDir.d.ts +1 -0
- package/dist/src/templates/helpers/resolveTemplatesDir.js +16 -0
- package/dist/src/templates/templates.d.ts +10 -0
- package/dist/src/templates/templates.js +133 -0
- package/dist/src/templates/templates.test.d.ts +1 -0
- package/dist/src/templates/templates.test.js +263 -0
- package/dist/src/templates/types.d.ts +21 -0
- package/dist/src/templates/types.js +1 -0
- package/dist/src/types.d.ts +28 -9
- package/dist/src/validators/getIsValidCategory.d.ts +2 -0
- package/dist/src/validators/getIsValidCategory.js +2 -0
- package/dist/src/validators/getIsValidCategory.test.d.ts +1 -0
- package/dist/src/validators/{isValidCategory.test.js → getIsValidCategory.test.js} +3 -3
- package/dist/src/validators/getIsValidFramework.d.ts +2 -0
- package/dist/src/validators/getIsValidFramework.js +2 -0
- package/dist/src/validators/getIsValidFramework.test.d.ts +1 -0
- package/dist/src/validators/{isValidFramework.test.js → getIsValidFramework.test.js} +3 -3
- package/dist/src/validators/getIsValidLanguage.d.ts +2 -0
- package/dist/src/validators/getIsValidLanguage.js +2 -0
- package/dist/src/validators/getIsValidLanguage.test.d.ts +1 -0
- package/dist/src/validators/{isValidLanguage.test.js → getIsValidLanguage.test.js} +3 -3
- package/dist/src/validators/getIsValidPackageManager.d.ts +2 -0
- package/dist/src/validators/getIsValidPackageManager.js +4 -0
- package/dist/src/validators/getIsValidPackageManager.test.d.ts +1 -0
- package/dist/src/validators/getIsValidPackageManager.test.js +11 -0
- package/dist/src/validators/getIsValidSlot.d.ts +2 -0
- package/dist/src/validators/getIsValidSlot.js +4 -0
- package/dist/src/validators/getIsValidSlot.test.d.ts +1 -0
- package/dist/src/validators/getIsValidSlot.test.js +26 -0
- package/dist/src/validators/validateSlots.js +40 -8
- package/dist/src/validators/validateSlots.test.js +125 -34
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/package.json +5 -2
- package/templates/v1/vite.config.ts.ejs +27 -0
- package/templates/v2/.project-config.json.ejs +1 -0
- package/templates/v2/AGENTS.md.ejs +712 -0
- package/templates/v2/README.md.ejs +31 -0
- package/templates/v2/package.json.ejs +26 -0
- package/dist/bin/cli.js +0 -221
- package/dist/src/executor.d.ts +0 -2
- package/dist/src/executor.js +0 -22
- package/dist/src/helpers/detectPackageManager.d.ts +0 -2
- package/dist/src/helpers/isDirectory.d.ts +0 -1
- package/dist/src/helpers/isDirectory.js +0 -9
- package/dist/src/helpers/isDirectory.test.js +0 -22
- package/dist/src/helpers/isTypescriptOnlyFile.d.ts +0 -1
- package/dist/src/helpers/isTypescriptOnlyFile.js +0 -5
- package/dist/src/helpers/isTypescriptOnlyFile.test.js +0 -22
- package/dist/src/helpers/normalizeRelPath.d.ts +0 -1
- package/dist/src/helpers/normalizeRelPath.js +0 -1
- package/dist/src/helpers/normalizeRelPath.test.js +0 -19
- package/dist/src/helpers/resolveTemplateExtension.d.ts +0 -1
- package/dist/src/helpers/resolveTemplateExtension.js +0 -17
- package/dist/src/helpers/resolveTemplatesDir.d.ts +0 -1
- package/dist/src/helpers/resolveTemplatesDir.js +0 -11
- package/dist/src/helpers/resolveTemplatesDir.test.js +0 -21
- package/dist/src/planner.d.ts +0 -2
- package/dist/src/planner.js +0 -126
- package/dist/src/planner.test.js +0 -58
- package/dist/src/validators/index.d.ts +0 -6
- package/dist/src/validators/index.js +0 -6
- package/dist/src/validators/isValidCategory.d.ts +0 -2
- package/dist/src/validators/isValidCategory.js +0 -2
- package/dist/src/validators/isValidFramework.d.ts +0 -2
- package/dist/src/validators/isValidFramework.js +0 -2
- package/dist/src/validators/isValidLanguage.d.ts +0 -2
- package/dist/src/validators/isValidLanguage.js +0 -2
- package/dist/src/validators/validateProjectDir.d.ts +0 -1
- package/dist/src/validators/validateProjectDir.js +0 -6
- package/dist/src/validators/validateProjectDir.test.js +0 -19
- package/dist/bin/{cli.d.ts → cli/index.d.ts} +0 -0
- package/dist/src/{executor.test.d.ts → dependencies/resolveDependencies.test.d.ts} +0 -0
- package/dist/src/helpers/{detectPackageManager.test.d.ts → error.test.d.ts} +0 -0
- package/dist/src/helpers/{isDirectory.test.d.ts → getIsDirectoryExists.test.d.ts} +0 -0
- package/dist/src/helpers/{isTypescriptOnlyFile.test.d.ts → getIsJsxFramework.test.d.ts} +0 -0
- package/dist/src/helpers/{normalizeRelPath.test.d.ts → getIsTypescript.test.d.ts} +0 -0
- package/dist/src/helpers/{resolveTemplateExtension.test.d.ts → normalizePath.test.d.ts} +0 -0
- package/dist/src/{helpers/resolveTemplatesDir.test.d.ts → migrator/migration.test.d.ts} +0 -0
- package/dist/src/{mappers/mapProjectConfigToTemplateModel.test.d.ts → migrator/migrations/migrations.test.d.ts} +0 -0
- package/dist/src/{planner.test.d.ts → migrator/planner.test.d.ts} +0 -0
- package/dist/src/{validators/isValidCategory.test.d.ts → migrator/types.js} +0 -0
- package/dist/src/{validators/isValidFramework.test.d.ts → migrator/updates/updates.test.d.ts} +0 -0
- package/dist/src/{validators/isValidLanguage.test.d.ts → migrator/validators/getIsValidMigration.test.d.ts} +0 -0
- package/dist/src/{validators/validateProjectDir.test.d.ts → projectConfig/detectPackageManagerRuntime.test.d.ts} +0 -0
- package/dist/src/{helpers → templater/helpers}/resolveTemplateExtension.test.js +0 -0
- package/templates/{.gitignore.ejs → v1/.gitignore.ejs} +0 -0
- package/templates/{AGENTS.md.ejs → v1/AGENTS.md.ejs} +0 -0
- package/templates/{CLAUDE.md → v1/CLAUDE.md} +0 -0
- package/templates/{README.md.ejs → v1/README.md.ejs} +0 -0
- package/templates/{package.json.ejs → v1/package.json.ejs} +0 -0
- package/templates/{public → v1/public}/icon.svg +0 -0
- package/templates/{public → v1/public}/manifest.json.ejs +0 -0
- package/templates/{public → v1/public}/resolveSlotPage.js.ejs +0 -0
- package/templates/{src → v1/src}/slots/background/app.ts.ejs +0 -0
- package/templates/{src → v1/src}/slots/background/background.html.ejs +0 -0
- package/templates/{src → v1/src}/slots/background/main.ts.ejs +0 -0
- package/templates/{src/slots/slot/slot.html.ejs → v1/src/slots/slot/__SLOT_KEY__.html.ejs} +0 -0
- package/templates/{src → v1/src}/slots/slot/app.ts.ejs +0 -0
- package/templates/{src → v1/src}/slots/slot/app.tsx.ejs +0 -0
- package/templates/{src → v1/src}/slots/slot/main.css.ejs +0 -0
- package/templates/{src → v1/src}/slots/slot/main.ts.ejs +0 -0
- package/templates/{src → v1/src}/slots/slot/main.tsx.ejs +0 -0
- package/templates/{tsconfig.json.ejs → v1/tsconfig.json.ejs} +0 -0
- package/templates/{vite.config.ts.ejs → v2/vite.config.ts.ejs} +1 -1
|
@@ -2,6 +2,10 @@ import { readFile, rm, mkdtemp } from 'node:fs/promises';
|
|
|
2
2
|
import { tmpdir } from 'node:os';
|
|
3
3
|
import { join } from 'node:path';
|
|
4
4
|
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest';
|
|
5
|
+
import { CLI_COMMANDS_MAP, EXT_HELPER_VERSION } from '../constants.js';
|
|
6
|
+
import { buildProjectConfig } from '../projectConfig/buildProjectConfig.js';
|
|
7
|
+
import { MANAGED_TEMPLATES } from '../templates/constants.js';
|
|
8
|
+
import { LAST_TEMPLATE_VERSION, TEMPLATES_DIR } from '../templates/templates.js';
|
|
5
9
|
import { executeCommands } from './executor.js';
|
|
6
10
|
import { mapProjectConfigToTemplateData } from './mappers/mapProjectConfigToTemplateModel.js';
|
|
7
11
|
import { planProject } from './planner.js';
|
|
@@ -13,9 +17,9 @@ const rewriteDestPaths = (commands, destDir) => commands.map((cmd) => {
|
|
|
13
17
|
}
|
|
14
18
|
return { ...cmd, destPath };
|
|
15
19
|
});
|
|
16
|
-
const buildCommands =
|
|
20
|
+
const buildCommands = (config, destDir) => {
|
|
17
21
|
const data = mapProjectConfigToTemplateData(config);
|
|
18
|
-
const commands =
|
|
22
|
+
const commands = planProject('/output/my-ext', config.lastTemplateVersion, data);
|
|
19
23
|
return rewriteDestPaths(commands, destDir);
|
|
20
24
|
};
|
|
21
25
|
describe('executeCommands', () => {
|
|
@@ -27,17 +31,22 @@ describe('executeCommands', () => {
|
|
|
27
31
|
await rm(tmpDir, { recursive: true });
|
|
28
32
|
});
|
|
29
33
|
it('renders EJS templates into destination files', async () => {
|
|
30
|
-
const
|
|
34
|
+
const projectConfig = buildProjectConfig({
|
|
31
35
|
category: 'games-and-fun',
|
|
32
36
|
framework: 'vanilla',
|
|
33
37
|
language: 'ts',
|
|
34
38
|
name: 'my-ext',
|
|
35
39
|
packageManager: 'npm',
|
|
36
40
|
slots: ['EXTENSION_SLOT_MAIN_GAME_FUN', 'EXTENSION_SLOT_BACKGROUND'],
|
|
37
|
-
|
|
38
|
-
|
|
41
|
+
extHelperVersion: EXT_HELPER_VERSION,
|
|
42
|
+
lastTemplateVersion: LAST_TEMPLATE_VERSION,
|
|
43
|
+
cliCommands: CLI_COMMANDS_MAP,
|
|
44
|
+
managedTemplates: MANAGED_TEMPLATES,
|
|
45
|
+
templatesDir: TEMPLATES_DIR,
|
|
46
|
+
});
|
|
47
|
+
const commands = buildCommands(projectConfig, tmpDir);
|
|
39
48
|
const cb = vi.fn();
|
|
40
|
-
|
|
49
|
+
executeCommands(commands, cb);
|
|
41
50
|
for (const command of commands) {
|
|
42
51
|
if (command.type === 'render') {
|
|
43
52
|
const content = await readFile(command.destPath, 'utf-8');
|
|
@@ -56,22 +65,27 @@ describe('executeCommands', () => {
|
|
|
56
65
|
}
|
|
57
66
|
expect(cb).toHaveBeenCalledTimes(commands.length);
|
|
58
67
|
});
|
|
59
|
-
it('rejects with ENOENT when a source template is missing',
|
|
60
|
-
const
|
|
68
|
+
it('rejects with ENOENT when a source template is missing', () => {
|
|
69
|
+
const projectConfig = buildProjectConfig({
|
|
61
70
|
category: 'sex-toys',
|
|
62
71
|
framework: 'vanilla',
|
|
63
72
|
language: 'js',
|
|
64
73
|
name: 'my-ext',
|
|
65
74
|
packageManager: 'npm',
|
|
66
75
|
slots: ['EXTENSION_SLOT_MAIN_SEX_TOY', 'EXTENSION_SLOT_BACKGROUND'],
|
|
67
|
-
|
|
68
|
-
|
|
76
|
+
extHelperVersion: EXT_HELPER_VERSION,
|
|
77
|
+
lastTemplateVersion: LAST_TEMPLATE_VERSION,
|
|
78
|
+
cliCommands: CLI_COMMANDS_MAP,
|
|
79
|
+
managedTemplates: MANAGED_TEMPLATES,
|
|
80
|
+
templatesDir: TEMPLATES_DIR,
|
|
81
|
+
});
|
|
82
|
+
const commands = buildCommands(projectConfig, tmpDir);
|
|
69
83
|
const corruptedIndex = commands.findIndex((c) => c.type === 'render');
|
|
70
84
|
const corrupted = [...commands];
|
|
71
85
|
corrupted[corruptedIndex] = {
|
|
72
86
|
...corrupted[corruptedIndex],
|
|
73
87
|
srcPath: join(tmpDir, 'nonexistent.ejs'),
|
|
74
88
|
};
|
|
75
|
-
|
|
89
|
+
expect(() => executeCommands(corrupted)).toThrow(/ENOENT/);
|
|
76
90
|
});
|
|
77
91
|
});
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare const getIsTypescriptOnlyFile: (templateFilePath: string) => boolean;
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { relative } from 'node:path';
|
|
2
|
+
import { TS_ONLY_FILES } from '../../constants.js';
|
|
3
|
+
import { toNormalizedRelPath } from '../../helpers/normalizePath.js';
|
|
4
|
+
import { TEMPLATES_DIR } from '../../templates/templates.js';
|
|
5
|
+
export const getIsTypescriptOnlyFile = (templateFilePath) => {
|
|
6
|
+
const withoutEjs = relative(TEMPLATES_DIR, templateFilePath).replace(/\.ejs$/, '');
|
|
7
|
+
const normalizedFile = toNormalizedRelPath(withoutEjs);
|
|
8
|
+
const withoutVersion = normalizedFile.split('/').slice(1).join('/');
|
|
9
|
+
return TS_ONLY_FILES.includes(withoutVersion);
|
|
10
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { join } from 'node:path';
|
|
2
|
+
import { describe, expect, it } from 'vitest';
|
|
3
|
+
import { TEMPLATES_DIR } from '../../templates/templates.js';
|
|
4
|
+
import { getIsTypescriptOnlyFile } from './getIsTypescriptOnlyFile.js';
|
|
5
|
+
const templatePath = (fileName) => join(TEMPLATES_DIR, 'v1', fileName);
|
|
6
|
+
describe('isTypescriptOnlyFile', () => {
|
|
7
|
+
it('returns true for tsconfig.json', () => {
|
|
8
|
+
expect(getIsTypescriptOnlyFile(templatePath('tsconfig.json'))).toBe(true);
|
|
9
|
+
});
|
|
10
|
+
it('returns true for tsconfig.json.ejs (strips .ejs suffix)', () => {
|
|
11
|
+
expect(getIsTypescriptOnlyFile(templatePath('tsconfig.json.ejs'))).toBe(true);
|
|
12
|
+
});
|
|
13
|
+
it('returns false for package.json', () => {
|
|
14
|
+
expect(getIsTypescriptOnlyFile(templatePath('package.json'))).toBe(false);
|
|
15
|
+
});
|
|
16
|
+
it('returns false for package.json.ejs', () => {
|
|
17
|
+
expect(getIsTypescriptOnlyFile(templatePath('package.json.ejs'))).toBe(false);
|
|
18
|
+
});
|
|
19
|
+
it('returns false for vite.config.ts.ejs', () => {
|
|
20
|
+
expect(getIsTypescriptOnlyFile(templatePath('vite.config.ts.ejs'))).toBe(false);
|
|
21
|
+
});
|
|
22
|
+
it('returns false for an empty string', () => {
|
|
23
|
+
expect(getIsTypescriptOnlyFile('')).toBe(false);
|
|
24
|
+
});
|
|
25
|
+
});
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare const resolveTemplateExtension: (templatePath: string, isTypescript: boolean) => string;
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { dirname, join, parse } from 'node:path';
|
|
2
|
+
import { TEMPLATE_EXT } from '../../templates/constants.js';
|
|
3
|
+
const resolveOutputExtension = (templateExt, isTypescript) => {
|
|
4
|
+
const map = {
|
|
5
|
+
'.ts': isTypescript ? '.ts' : '.js',
|
|
6
|
+
'.tsx': isTypescript ? '.tsx' : '.jsx',
|
|
7
|
+
};
|
|
8
|
+
return map[templateExt] ?? templateExt;
|
|
9
|
+
};
|
|
10
|
+
export const resolveTemplateExtension = (templatePath, isTypescript) => {
|
|
11
|
+
const withoutEjs = templatePath.endsWith(TEMPLATE_EXT)
|
|
12
|
+
? templatePath.slice(0, -TEMPLATE_EXT.length)
|
|
13
|
+
: templatePath;
|
|
14
|
+
const withoutEjsParsed = parse(withoutEjs);
|
|
15
|
+
return join(dirname(templatePath), `${withoutEjsParsed.name}${resolveOutputExtension(withoutEjsParsed.ext, isTypescript)}`);
|
|
16
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import type { TProjectConfig, TTemplateData } from '
|
|
1
|
+
import type { TProjectConfig, TTemplateData } from '../../types.js';
|
|
2
2
|
export declare const mapProjectConfigToTemplateData: (config: TProjectConfig) => TTemplateData;
|
|
@@ -1,24 +1,22 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { PACKAGE_MANAGER_COMMANDS_MAP, SLOT_LABELS } from '../../constants.js';
|
|
2
|
+
import { getIsJsxFramework } from '../../helpers/getIsJsxFramework.js';
|
|
3
|
+
import { getIsTypescript } from '../../helpers/getIsTypescript.js';
|
|
2
4
|
const buildSlotResolverEntries = (config) => config.slots.map((slot) => ({
|
|
3
5
|
slotCamelCased: SLOT_LABELS[slot],
|
|
4
6
|
slot,
|
|
5
7
|
}));
|
|
6
8
|
export const mapProjectConfigToTemplateData = (config) => {
|
|
7
|
-
const isTypescript = config.language
|
|
8
|
-
const isJsxFramework =
|
|
9
|
+
const isTypescript = getIsTypescript(config.language);
|
|
10
|
+
const isJsxFramework = getIsJsxFramework(config.framework);
|
|
9
11
|
const ext = isTypescript ? 'ts' : 'js';
|
|
10
12
|
const jsxExt = isTypescript ? 'tsx' : 'jsx';
|
|
11
13
|
return {
|
|
12
14
|
config,
|
|
15
|
+
...config,
|
|
13
16
|
ext,
|
|
14
|
-
extHelperVersion: EXT_HELPER_VERSION,
|
|
15
|
-
framework: config.framework,
|
|
16
17
|
isJsxFramework,
|
|
17
18
|
isTypescript,
|
|
18
19
|
jsxExt,
|
|
19
|
-
language: config.language,
|
|
20
|
-
name: config.name,
|
|
21
|
-
packageManager: config.packageManager,
|
|
22
20
|
packageManagerCommands: PACKAGE_MANAGER_COMMANDS_MAP[config.packageManager],
|
|
23
21
|
slotsEntries: buildSlotResolverEntries(config),
|
|
24
22
|
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -1,15 +1,31 @@
|
|
|
1
1
|
import { describe, expect, it } from 'vitest';
|
|
2
|
-
import { EXT_HELPER_VERSION } from '
|
|
3
|
-
import {
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
2
|
+
import { CLI_COMMANDS_MAP, EXT_HELPER_VERSION } from '../../constants.js';
|
|
3
|
+
import { DEPENDENCIES } from '../../dependencies/constants.js';
|
|
4
|
+
import { buildProjectConfig } from '../../projectConfig/buildProjectConfig.js';
|
|
5
|
+
import { MANAGED_TEMPLATES } from '../../templates/constants.js';
|
|
6
|
+
import { LAST_TEMPLATE_VERSION, TEMPLATES_DIR } from '../../templates/templates.js';
|
|
7
|
+
import { mapProjectConfigToTemplateData } from './mapProjectConfigToTemplateModel.js';
|
|
8
|
+
const makeConfig = (overrides = {}) => {
|
|
9
|
+
const language = overrides.language ?? 'ts';
|
|
10
|
+
const framework = overrides.framework ?? 'vanilla';
|
|
11
|
+
const projectConfig = buildProjectConfig({
|
|
12
|
+
name: 'test-ext',
|
|
13
|
+
category: 'games-and-fun',
|
|
14
|
+
framework,
|
|
15
|
+
language,
|
|
16
|
+
packageManager: 'npm',
|
|
17
|
+
slots: ['EXTENSION_SLOT_MAIN_GAME_FUN', 'EXTENSION_SLOT_BACKGROUND'],
|
|
18
|
+
extHelperVersion: EXT_HELPER_VERSION,
|
|
19
|
+
lastTemplateVersion: LAST_TEMPLATE_VERSION,
|
|
20
|
+
cliCommands: CLI_COMMANDS_MAP,
|
|
21
|
+
managedTemplates: MANAGED_TEMPLATES,
|
|
22
|
+
templatesDir: TEMPLATES_DIR,
|
|
23
|
+
});
|
|
24
|
+
return {
|
|
25
|
+
...projectConfig,
|
|
26
|
+
...overrides,
|
|
27
|
+
};
|
|
28
|
+
};
|
|
13
29
|
describe('mapProjectConfigToTemplateData', () => {
|
|
14
30
|
it('sets typescript flags when language is ts', () => {
|
|
15
31
|
const result = mapProjectConfigToTemplateData(makeConfig({ language: 'ts' }));
|
|
@@ -75,11 +91,6 @@ describe('mapProjectConfigToTemplateData', () => {
|
|
|
75
91
|
const result = mapProjectConfigToTemplateData(makeConfig({ slots: [] }));
|
|
76
92
|
expect(result.slotsEntries).toEqual([]);
|
|
77
93
|
});
|
|
78
|
-
it('passes config reference unchanged', () => {
|
|
79
|
-
const config = makeConfig();
|
|
80
|
-
const result = mapProjectConfigToTemplateData(config);
|
|
81
|
-
expect(result.config).toBe(config);
|
|
82
|
-
});
|
|
83
94
|
it('passes name, framework, language, and slots from config', () => {
|
|
84
95
|
const config = makeConfig({
|
|
85
96
|
framework: 'preact',
|
|
@@ -95,13 +106,8 @@ describe('mapProjectConfigToTemplateData', () => {
|
|
|
95
106
|
{ slot: 'EXTENSION_SLOT_MAIN_GAME_FUN', slotCamelCased: 'mainGameFun' },
|
|
96
107
|
]);
|
|
97
108
|
});
|
|
98
|
-
it('
|
|
99
|
-
const result = mapProjectConfigToTemplateData(makeConfig());
|
|
100
|
-
expect(result.entryModulePath).toBeUndefined();
|
|
101
|
-
expect(result.slot).toBeUndefined();
|
|
102
|
-
});
|
|
103
|
-
it('sets extHelperVersion from package version', () => {
|
|
109
|
+
it('sets ext-helper dependency from resolved dependencies', () => {
|
|
104
110
|
const result = mapProjectConfigToTemplateData(makeConfig());
|
|
105
|
-
expect(result.
|
|
111
|
+
expect(result.config.dependencies['@stripchatdev/ext-helper']).toBe(DEPENDENCIES['@stripchatdev/ext-helper']);
|
|
106
112
|
});
|
|
107
113
|
});
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
import { existsSync } from 'node:fs';
|
|
2
|
+
import { join } from 'node:path';
|
|
3
|
+
import { isSubPath } from '../helpers/isSubPath.js';
|
|
4
|
+
import { GENERAL_SLOT_NAME_PLACEHOLDER, TEMPLATE_EXT, } from '../templates/constants.js';
|
|
5
|
+
import { collectTemplateFiles, GENERAL_SLOT_TEMPLATE_DIR_REL, SLOTS_TEMPLATE_DIR_REL, TEMPLATES_DIR, } from '../templates/templates.js';
|
|
6
|
+
import { getIsTypescriptOnlyFile } from './helpers/getIsTypescriptOnlyFile.js';
|
|
7
|
+
import { resolveTemplateExtension } from './helpers/resolveTemplateExtension.js';
|
|
8
|
+
const shouldSkipGlobalTemplate = (templatePath, data) => getIsTypescriptOnlyFile(templatePath) && !data.isTypescript;
|
|
9
|
+
const shouldSkipSlotTemplate = (relPath, allRelPaths, isJsxFramework) => {
|
|
10
|
+
if (relPath.endsWith('.tsx.ejs')) {
|
|
11
|
+
const tsCounterpart = relPath.replace(/\.tsx\.ejs$/, '.ts.ejs');
|
|
12
|
+
if (allRelPaths.has(tsCounterpart) && !isJsxFramework) {
|
|
13
|
+
return true;
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
if (relPath.endsWith('.ts.ejs')) {
|
|
17
|
+
const tsxCounterpart = relPath.replace(/\.ts\.ejs$/, '.tsx.ejs');
|
|
18
|
+
if (allRelPaths.has(tsxCounterpart) && isJsxFramework) {
|
|
19
|
+
return true;
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
return false;
|
|
23
|
+
};
|
|
24
|
+
const planGlobalTemplates = (projectDir, targetVersion, data) => {
|
|
25
|
+
const files = collectTemplateFiles(TEMPLATES_DIR, targetVersion);
|
|
26
|
+
const commands = [];
|
|
27
|
+
for (const file of files) {
|
|
28
|
+
if (file.deleted) {
|
|
29
|
+
continue;
|
|
30
|
+
}
|
|
31
|
+
if (isSubPath('src/slots', file.relPath)) {
|
|
32
|
+
continue;
|
|
33
|
+
}
|
|
34
|
+
if (shouldSkipGlobalTemplate(file.srcPath, data)) {
|
|
35
|
+
continue;
|
|
36
|
+
}
|
|
37
|
+
const isEjs = file.srcPath.endsWith(TEMPLATE_EXT);
|
|
38
|
+
if (!isEjs) {
|
|
39
|
+
commands.push({
|
|
40
|
+
destPath: join(projectDir, file.relPath),
|
|
41
|
+
srcPath: file.srcPath,
|
|
42
|
+
type: 'copy',
|
|
43
|
+
});
|
|
44
|
+
continue;
|
|
45
|
+
}
|
|
46
|
+
commands.push({
|
|
47
|
+
data,
|
|
48
|
+
destPath: join(projectDir, resolveTemplateExtension(file.relPath, data.isTypescript)),
|
|
49
|
+
srcPath: file.srcPath,
|
|
50
|
+
type: 'render',
|
|
51
|
+
});
|
|
52
|
+
}
|
|
53
|
+
return commands;
|
|
54
|
+
};
|
|
55
|
+
const buildSlotTemplateData = (data, slotKey) => {
|
|
56
|
+
const isBackground = slotKey === 'background';
|
|
57
|
+
const entryExt = isBackground || !data.isJsxFramework ? data.ext : data.jsxExt;
|
|
58
|
+
return {
|
|
59
|
+
...data,
|
|
60
|
+
entryModulePath: `/src/slots/${slotKey}/main.${entryExt}`,
|
|
61
|
+
slot: slotKey,
|
|
62
|
+
stylePath: `/src/slots/${slotKey}/main.css`,
|
|
63
|
+
};
|
|
64
|
+
};
|
|
65
|
+
const planSlotTemplates = (projectDir, targetVersion, data, slotKey) => {
|
|
66
|
+
const specificDir = join(SLOTS_TEMPLATE_DIR_REL, slotKey);
|
|
67
|
+
const hasSpecificDir = existsSync(specificDir);
|
|
68
|
+
const slotTemplatedDirRel = hasSpecificDir ? specificDir : GENERAL_SLOT_TEMPLATE_DIR_REL;
|
|
69
|
+
const slotData = buildSlotTemplateData(data, slotKey);
|
|
70
|
+
const files = collectTemplateFiles(TEMPLATES_DIR, targetVersion, slotTemplatedDirRel);
|
|
71
|
+
const allRelPaths = new Set(files.map((f) => f.relPath));
|
|
72
|
+
const commands = [];
|
|
73
|
+
for (const file of files) {
|
|
74
|
+
if (shouldSkipSlotTemplate(file.relPath, allRelPaths, data.isJsxFramework)) {
|
|
75
|
+
continue;
|
|
76
|
+
}
|
|
77
|
+
const outputRelPath = file.relPath.replace(GENERAL_SLOT_NAME_PLACEHOLDER, slotKey);
|
|
78
|
+
const resolvedPath = resolveTemplateExtension(outputRelPath, data.isTypescript);
|
|
79
|
+
const isHtml = resolvedPath.endsWith('.html');
|
|
80
|
+
const destPath = isHtml
|
|
81
|
+
? join(projectDir, resolvedPath)
|
|
82
|
+
: join(projectDir, 'src', 'slots', slotKey, resolvedPath);
|
|
83
|
+
if (file.relPath.endsWith(TEMPLATE_EXT)) {
|
|
84
|
+
commands.push({
|
|
85
|
+
data: slotData,
|
|
86
|
+
destPath,
|
|
87
|
+
srcPath: file.srcPath,
|
|
88
|
+
type: 'render',
|
|
89
|
+
});
|
|
90
|
+
continue;
|
|
91
|
+
}
|
|
92
|
+
commands.push({
|
|
93
|
+
destPath,
|
|
94
|
+
srcPath: file.srcPath,
|
|
95
|
+
type: 'copy',
|
|
96
|
+
});
|
|
97
|
+
}
|
|
98
|
+
return commands;
|
|
99
|
+
};
|
|
100
|
+
export const planProject = (projectDir, targetVersion, data) => {
|
|
101
|
+
const globalCommands = planGlobalTemplates(projectDir, targetVersion, data);
|
|
102
|
+
const slotCommands = data.slotsEntries.flatMap(({ slotCamelCased }) => planSlotTemplates(projectDir, targetVersion, data, slotCamelCased));
|
|
103
|
+
return [...globalCommands, ...slotCommands];
|
|
104
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import { relative, basename, join } from 'node:path';
|
|
2
|
+
import { describe, expect, it } from 'vitest';
|
|
3
|
+
import { CATEGORIES, CLI_COMMANDS_MAP, EXT_HELPER_VERSION, FRAMEWORKS, LANGUAGES, SLOT_RULES_BY_CATEGORY, } from '../constants.js';
|
|
4
|
+
import { toNormalizedRelPath } from '../helpers/normalizePath.js';
|
|
5
|
+
import { buildProjectConfig } from '../projectConfig/buildProjectConfig.js';
|
|
6
|
+
import { MANAGED_TEMPLATES } from '../templates/constants.js';
|
|
7
|
+
import { LAST_TEMPLATE_VERSION, TEMPLATES_DIR } from '../templates/templates.js';
|
|
8
|
+
import { mapProjectConfigToTemplateData } from './mappers/mapProjectConfigToTemplateModel.js';
|
|
9
|
+
import { planProject } from './planner.js';
|
|
10
|
+
const PROJECT_DIR = '/output/my-ext';
|
|
11
|
+
const buildSlotCombos = (category) => {
|
|
12
|
+
const rules = SLOT_RULES_BY_CATEGORY[category];
|
|
13
|
+
const base = [...rules.requiredBase];
|
|
14
|
+
const combos = [base];
|
|
15
|
+
if (category === 'games-and-fun') {
|
|
16
|
+
combos.length = 0;
|
|
17
|
+
combos.push([...base, 'EXTENSION_SLOT_RIGHT_OVERLAY'], [...base, 'EXTENSION_SLOT_VIDEO_DECORATIVE_OVERLAY']);
|
|
18
|
+
return combos;
|
|
19
|
+
}
|
|
20
|
+
if (category === 'sex-toys') {
|
|
21
|
+
combos.push([...base, 'EXTENSION_SLOT_MOVEABLE_OVERLAY'], [...base, 'EXTENSION_SLOT_RIGHT_OVERLAY'], [...base, 'EXTENSION_SLOT_VIDEO_DECORATIVE_OVERLAY'], [...base, 'EXTENSION_SLOT_MOVEABLE_OVERLAY', 'EXTENSION_SLOT_RIGHT_OVERLAY'], [...base, 'EXTENSION_SLOT_MOVEABLE_OVERLAY', 'EXTENSION_SLOT_VIDEO_DECORATIVE_OVERLAY']);
|
|
22
|
+
}
|
|
23
|
+
return combos;
|
|
24
|
+
};
|
|
25
|
+
const SLOT_COMBOS_BY_CATEGORY = Object.fromEntries(CATEGORIES.map((category) => {
|
|
26
|
+
return [category, buildSlotCombos(category)];
|
|
27
|
+
}));
|
|
28
|
+
const TEST_CASES = CATEGORIES.flatMap((category) => SLOT_COMBOS_BY_CATEGORY[category].flatMap((slots) => FRAMEWORKS.flatMap((framework) => LANGUAGES.flatMap((language) => new Array(LAST_TEMPLATE_VERSION).fill(0).map((_, index) => ({
|
|
29
|
+
category,
|
|
30
|
+
framework,
|
|
31
|
+
language,
|
|
32
|
+
slots,
|
|
33
|
+
slotsStr: slots.join(', '),
|
|
34
|
+
templateVersion: index + 1,
|
|
35
|
+
}))))));
|
|
36
|
+
const normalizeCommands = (commands) => commands.map((cmd) => {
|
|
37
|
+
const srcRel = join(basename(TEMPLATES_DIR), relative(TEMPLATES_DIR, cmd.srcPath));
|
|
38
|
+
const srcNormalized = toNormalizedRelPath(srcRel);
|
|
39
|
+
const destNormalized = toNormalizedRelPath(cmd.destPath).replace('/output/', '');
|
|
40
|
+
if (cmd.type === 'copy') {
|
|
41
|
+
return { type: 'copy', src: srcNormalized, dest: destNormalized };
|
|
42
|
+
}
|
|
43
|
+
return { type: 'render', src: srcNormalized, dest: destNormalized };
|
|
44
|
+
});
|
|
45
|
+
describe('planProject', { tags: ['snapshot'] }, () => {
|
|
46
|
+
it.each(TEST_CASES)('template version $templateVersion + $language + $framework, $category ($slotsStr)', ({ category, framework, language, slots, templateVersion, }) => {
|
|
47
|
+
const projectConfig = buildProjectConfig({
|
|
48
|
+
category,
|
|
49
|
+
framework,
|
|
50
|
+
language,
|
|
51
|
+
name: basename(PROJECT_DIR),
|
|
52
|
+
packageManager: 'npm',
|
|
53
|
+
slots,
|
|
54
|
+
extHelperVersion: EXT_HELPER_VERSION,
|
|
55
|
+
lastTemplateVersion: templateVersion,
|
|
56
|
+
cliCommands: CLI_COMMANDS_MAP,
|
|
57
|
+
managedTemplates: MANAGED_TEMPLATES,
|
|
58
|
+
templatesDir: TEMPLATES_DIR,
|
|
59
|
+
});
|
|
60
|
+
const data = mapProjectConfigToTemplateData(projectConfig);
|
|
61
|
+
const commands = planProject(PROJECT_DIR, templateVersion, data);
|
|
62
|
+
expect(normalizeCommands(commands)).toMatchSnapshot();
|
|
63
|
+
});
|
|
64
|
+
});
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import type { TRelPath } from '../types.js';
|
|
2
|
+
export declare const INIT_TEMPLATE_VERSION = 1;
|
|
3
|
+
export declare const TEMPLATE_EXT = ".ejs";
|
|
4
|
+
export declare const MANAGED_TEMPLATES: TRelPath[];
|
|
5
|
+
export declare const DELETED_TEMPLATE_EXT = ".deleted";
|
|
6
|
+
export declare const GENERAL_SLOT_NAME_PLACEHOLDER = "__SLOT_KEY__";
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
export const INIT_TEMPLATE_VERSION = 1;
|
|
2
|
+
export const TEMPLATE_EXT = '.ejs';
|
|
3
|
+
// only extends
|
|
4
|
+
export const MANAGED_TEMPLATES = [
|
|
5
|
+
'AGENTS.md.ejs',
|
|
6
|
+
'package.json.ejs',
|
|
7
|
+
'vite.config.ts.ejs',
|
|
8
|
+
'.project-config.json.ejs',
|
|
9
|
+
];
|
|
10
|
+
export const DELETED_TEMPLATE_EXT = '.deleted';
|
|
11
|
+
export const GENERAL_SLOT_NAME_PLACEHOLDER = '__SLOT_KEY__';
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare const resolveTemplatesDir: () => string;
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { dirname, join } from 'node:path';
|
|
2
|
+
import { AppError } from '../../helpers/error.js';
|
|
3
|
+
import { getIsDirectoryExists } from '../../helpers/getIsDirectoryExists.js';
|
|
4
|
+
const __dirname = dirname(import.meta.filename);
|
|
5
|
+
export const resolveTemplatesDir = () => {
|
|
6
|
+
// first value - for dist folder, second value for tests
|
|
7
|
+
const candidatePaths = ['../../../templates', '../../templates'];
|
|
8
|
+
for (const candidatePath of candidatePaths) {
|
|
9
|
+
const dir = join(__dirname, candidatePath);
|
|
10
|
+
const { isExists } = getIsDirectoryExists(dir);
|
|
11
|
+
if (isExists) {
|
|
12
|
+
return dir;
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
throw new AppError('Templates dir not found');
|
|
16
|
+
};
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type { TRelPath } from '../types.js';
|
|
2
|
+
import type { TTemplateFile, TTemplateVersionDir, TManagedFile } from './types';
|
|
3
|
+
export declare const discoverVersionDirs: (templatesDir: string, targetVersion: number, order?: "asc" | "desc") => TTemplateVersionDir[];
|
|
4
|
+
export declare const getLastTemplateVersion: (templatesDir: string) => number;
|
|
5
|
+
export declare const collectManagedFiles: (templateDir: string, managedTemplates: TRelPath[], targetVersion: number) => TManagedFile[];
|
|
6
|
+
export declare const collectTemplateFiles: (templatesDir: string, targetVersion: number, subDir?: string) => TTemplateFile[];
|
|
7
|
+
export declare const TEMPLATES_DIR: string;
|
|
8
|
+
export declare const LAST_TEMPLATE_VERSION: number;
|
|
9
|
+
export declare const SLOTS_TEMPLATE_DIR_REL: string;
|
|
10
|
+
export declare const GENERAL_SLOT_TEMPLATE_DIR_REL: string;
|
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
import { existsSync, readdirSync } from 'node:fs';
|
|
2
|
+
import { join, relative } from 'node:path';
|
|
3
|
+
import { DELETED_TEMPLATE_EXT, INIT_TEMPLATE_VERSION, TEMPLATE_EXT } from './constants.js';
|
|
4
|
+
import { resolveTemplatesDir } from './helpers/resolveTemplatesDir.js';
|
|
5
|
+
const FOLDER_VERSION_PATTERN = /v(\d+)/;
|
|
6
|
+
export const discoverVersionDirs = (templatesDir, targetVersion, order = 'asc') => {
|
|
7
|
+
const entries = readdirSync(templatesDir, {
|
|
8
|
+
withFileTypes: true,
|
|
9
|
+
});
|
|
10
|
+
return entries
|
|
11
|
+
.map((entry) => {
|
|
12
|
+
if (!entry.isDirectory()) {
|
|
13
|
+
return null;
|
|
14
|
+
}
|
|
15
|
+
const match = entry.name.match(FOLDER_VERSION_PATTERN);
|
|
16
|
+
if (!match) {
|
|
17
|
+
return null;
|
|
18
|
+
}
|
|
19
|
+
const [, versionStr] = match;
|
|
20
|
+
const version = Number(versionStr);
|
|
21
|
+
if (!Number.isFinite(version)) {
|
|
22
|
+
return null;
|
|
23
|
+
}
|
|
24
|
+
if (version > targetVersion) {
|
|
25
|
+
return null;
|
|
26
|
+
}
|
|
27
|
+
return {
|
|
28
|
+
dirPath: join(entry.parentPath, entry.name),
|
|
29
|
+
version,
|
|
30
|
+
};
|
|
31
|
+
})
|
|
32
|
+
.filter((entry) => entry !== null)
|
|
33
|
+
.sort((a, b) => {
|
|
34
|
+
if (order === 'asc') {
|
|
35
|
+
return a.version - b.version;
|
|
36
|
+
}
|
|
37
|
+
return b.version - a.version;
|
|
38
|
+
});
|
|
39
|
+
};
|
|
40
|
+
export const getLastTemplateVersion = (templatesDir) => {
|
|
41
|
+
const versionDirs = discoverVersionDirs(templatesDir, Number.MAX_SAFE_INTEGER, 'desc');
|
|
42
|
+
return versionDirs[0]?.version || INIT_TEMPLATE_VERSION;
|
|
43
|
+
};
|
|
44
|
+
export const collectManagedFiles = (templateDir, managedTemplates, targetVersion) => {
|
|
45
|
+
const versionDirs = discoverVersionDirs(templateDir, targetVersion, 'asc');
|
|
46
|
+
const managedTemplatesMap = {};
|
|
47
|
+
for (const relPath of managedTemplates) {
|
|
48
|
+
for (const versionDir of versionDirs) {
|
|
49
|
+
const { dirPath, version } = versionDir;
|
|
50
|
+
const targetManagedFilePath = join(dirPath, relPath);
|
|
51
|
+
const targetManagedFilePathDeleted = join(dirPath, `${relPath}.deleted`);
|
|
52
|
+
if (existsSync(targetManagedFilePath)) {
|
|
53
|
+
managedTemplatesMap[relPath] = {
|
|
54
|
+
relPath,
|
|
55
|
+
srcPath: join(dirPath, relPath),
|
|
56
|
+
version,
|
|
57
|
+
};
|
|
58
|
+
}
|
|
59
|
+
else if (existsSync(targetManagedFilePathDeleted)) {
|
|
60
|
+
managedTemplatesMap[relPath] = {
|
|
61
|
+
relPath,
|
|
62
|
+
srcPath: join(dirPath, relPath),
|
|
63
|
+
version,
|
|
64
|
+
deleted: true,
|
|
65
|
+
};
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
return Object.values(managedTemplatesMap).map(({ deleted, relPath, version }) => {
|
|
70
|
+
return {
|
|
71
|
+
relPath: relPath.endsWith(TEMPLATE_EXT)
|
|
72
|
+
? relPath.slice(0, -TEMPLATE_EXT.length)
|
|
73
|
+
: relPath,
|
|
74
|
+
version,
|
|
75
|
+
deleted,
|
|
76
|
+
};
|
|
77
|
+
});
|
|
78
|
+
};
|
|
79
|
+
const listTemplateFiles = (dir, version) => {
|
|
80
|
+
if (!existsSync(dir)) {
|
|
81
|
+
return [];
|
|
82
|
+
}
|
|
83
|
+
const entries = readdirSync(dir, { recursive: true, withFileTypes: true });
|
|
84
|
+
return entries
|
|
85
|
+
.filter((entry) => entry.isFile())
|
|
86
|
+
.map((entry) => {
|
|
87
|
+
const relPath = relative(dir, join(entry.parentPath, entry.name));
|
|
88
|
+
const srcPath = join(entry.parentPath, entry.name);
|
|
89
|
+
const isDeleted = relPath.endsWith(DELETED_TEMPLATE_EXT);
|
|
90
|
+
const resolvedRelPath = isDeleted
|
|
91
|
+
? relPath.slice(0, -DELETED_TEMPLATE_EXT.length)
|
|
92
|
+
: relPath;
|
|
93
|
+
const resolvedSrcPath = isDeleted
|
|
94
|
+
? srcPath.slice(0, -DELETED_TEMPLATE_EXT.length)
|
|
95
|
+
: srcPath;
|
|
96
|
+
return {
|
|
97
|
+
relPath: resolvedRelPath,
|
|
98
|
+
srcPath: resolvedSrcPath,
|
|
99
|
+
version,
|
|
100
|
+
deleted: isDeleted,
|
|
101
|
+
};
|
|
102
|
+
})
|
|
103
|
+
.sort((a, b) => a.relPath.localeCompare(b.relPath));
|
|
104
|
+
};
|
|
105
|
+
export const collectTemplateFiles = (templatesDir, targetVersion, subDir) => {
|
|
106
|
+
const versionDirs = discoverVersionDirs(templatesDir, targetVersion);
|
|
107
|
+
let subVersionDirs = versionDirs;
|
|
108
|
+
if (subDir) {
|
|
109
|
+
subVersionDirs = versionDirs.map(({ dirPath, version }) => {
|
|
110
|
+
return {
|
|
111
|
+
dirPath: join(dirPath, subDir),
|
|
112
|
+
version,
|
|
113
|
+
};
|
|
114
|
+
});
|
|
115
|
+
}
|
|
116
|
+
const templateFilesMap = {};
|
|
117
|
+
for (const { dirPath, version } of subVersionDirs) {
|
|
118
|
+
const templateFiles = listTemplateFiles(dirPath, version);
|
|
119
|
+
for (const templateFile of templateFiles) {
|
|
120
|
+
if (templateFile.deleted) {
|
|
121
|
+
delete templateFilesMap[templateFile.relPath];
|
|
122
|
+
}
|
|
123
|
+
else {
|
|
124
|
+
templateFilesMap[templateFile.relPath] = templateFile;
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
return Object.values(templateFilesMap);
|
|
129
|
+
};
|
|
130
|
+
export const TEMPLATES_DIR = resolveTemplatesDir();
|
|
131
|
+
export const LAST_TEMPLATE_VERSION = getLastTemplateVersion(TEMPLATES_DIR);
|
|
132
|
+
export const SLOTS_TEMPLATE_DIR_REL = join('src', 'slots');
|
|
133
|
+
export const GENERAL_SLOT_TEMPLATE_DIR_REL = join(SLOTS_TEMPLATE_DIR_REL, 'slot');
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|