@lagless/codegen 0.0.33
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 +403 -0
- package/dist/cli.js +92 -0
- package/dist/cli.js.map +1 -0
- package/dist/dirname.js +6 -0
- package/dist/dirname.js.map +1 -0
- package/dist/generator.js +156 -0
- package/dist/generator.js.map +1 -0
- package/dist/index.js +4 -0
- package/dist/index.js.map +1 -0
- package/dist/nx-generator.js +66 -0
- package/dist/nx-generator.js.map +1 -0
- package/dist/parser.js +160 -0
- package/dist/parser.js.map +1 -0
- package/dist/template-engine.js +149 -0
- package/dist/template-engine.js.map +1 -0
- package/dist/tsconfig.lib.tsbuildinfo +1 -0
- package/files/component/__name__.ts.template +65 -0
- package/files/core/__projectName__.core.ts.template +16 -0
- package/files/filter/__name__.ts.template +13 -0
- package/files/input/__name__.ts.template +33 -0
- package/files/input-registry/__projectName__InputRegistry.ts.template +9 -0
- package/files/playerResource/__name__.ts.template +63 -0
- package/files/runner/__projectName__.runner.ts.template +16 -0
- package/files/singleton/__name__.ts.template +63 -0
- package/generators.json +9 -0
- package/package.json +67 -0
- package/schema.json +12 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/generator.ts"],"sourcesContent":["import { ECSSchema, FieldDefinition } from '@lagless/core';\nimport { generateFromTemplate as processTemplate, FileOperations } from './template-engine.js';\nimport { FieldTypeReverse, getTypeSizeBytes, typedArrayConstructors, typeToArrayConstructor } from '@lagless/binary';\n\nexport interface GenerateCodeOptions {\n schema: ECSSchema;\n projectName: string;\n outputDir: string;\n templateDir: string;\n fileOperations: FileOperations;\n}\n\nexport function generateBarrelFileContent(schema: ECSSchema, projectName: string): string {\n let content = '// Generated by @lagless/codegen. Do not edit manually.\\n\\n';\n\n // Export components\n schema.components.forEach((component) => {\n content += `export * from './${component.name}.js';\\n`;\n });\n\n // Export singletons\n schema.singletons.forEach((singleton) => {\n content += `export * from './${singleton.name}.js';\\n`;\n });\n\n // Export player resources\n schema.playerResources.forEach((playerResource) => {\n content += `export * from './${playerResource.name}.js';\\n`;\n });\n\n // Export filters\n schema.filters.forEach((filter) => {\n content += `export * from './${filter.name}.js';\\n`;\n });\n\n // Export inputs\n schema.inputs.forEach((input) => {\n content += `export * from './${input.name}.js';\\n`;\n });\n\n // Export input registry\n content += `export * from './${projectName}InputRegistry.js';\\n`;\n\n // Export core\n content += `export * from './${projectName}.core.js';\\n`;\n\n // Export runner\n content += `export * from './${projectName}.runner.js';\\n`;\n\n return content;\n}\n\nexport async function generateCode(options: GenerateCodeOptions): Promise<void> {\n const { schema, projectName, outputDir, templateDir, fileOperations } = options;\n const { writeFile, joinPath, exists } = fileOperations;\n\n // Ensure output directory exists\n if (!exists(outputDir)) {\n writeFile(joinPath(outputDir, '.gitkeep'), '');\n }\n\n // Generate component classes\n for (const component of schema.components) {\n await processTemplate({\n templateDir: joinPath(templateDir, 'component'),\n outputDir,\n data: {\n ...component,\n component,\n projectName,\n typeToArrayConstructor,\n getFieldByteSize: (field: FieldDefinition) => {\n const baseSize = getTypeSizeBytes(field.type);\n return field.isArray ? baseSize * field.arrayLength! : baseSize;\n },\n },\n fileOperations,\n });\n }\n\n // Generate singleton classes\n for (const singleton of schema.singletons) {\n await processTemplate({\n templateDir: joinPath(templateDir, 'singleton'),\n outputDir,\n data: {\n ...singleton,\n singleton,\n projectName,\n typeToArrayConstructor,\n },\n fileOperations,\n });\n }\n\n // Generate playerResource classes\n for (const playerResource of schema.playerResources) {\n await processTemplate({\n templateDir: joinPath(templateDir, 'playerResource'),\n outputDir,\n data: {\n ...playerResource,\n playerResource,\n projectName,\n typeToArrayConstructor,\n },\n fileOperations,\n });\n }\n\n // Generate Filter classes\n for (const filter of schema.filters) {\n const componentsImports = [...filter.include, ...filter.exclude].map((c) => c.name);\n const includeMask = filter.include.reduce((acc, component) => acc | component.id, 0);\n const excludeMask = filter.exclude.reduce((acc, component) => acc | component.id, 0);\n\n await processTemplate({\n templateDir: joinPath(templateDir, 'filter'),\n outputDir,\n data: {\n filter,\n includeMask,\n excludeMask,\n componentsImports,\n name: filter.name,\n projectName,\n },\n fileOperations,\n });\n }\n\n // Generate Input classes\n for (const input of schema.inputs) {\n await processTemplate({\n templateDir: joinPath(templateDir, 'input'),\n outputDir,\n data: {\n ...input,\n input,\n projectName,\n FieldTypeReverse,\n typedArrayConstructors,\n },\n fileOperations,\n });\n }\n\n // Generate input registry\n await processTemplate({\n templateDir: joinPath(templateDir, 'input-registry'),\n outputDir,\n data: {\n projectName,\n inputs: schema.inputs,\n schema,\n },\n fileOperations,\n });\n\n // Generate ECSCore class\n await processTemplate({\n templateDir: joinPath(templateDir, 'core'),\n outputDir,\n data: {\n projectName,\n schema,\n },\n fileOperations,\n });\n\n // Generate Runner class\n await processTemplate({\n templateDir: joinPath(templateDir, 'runner'),\n outputDir,\n data: {\n projectName,\n schema,\n },\n fileOperations,\n });\n\n // Generate barrel file\n const barrelContent = generateBarrelFileContent(schema, projectName);\n writeFile(joinPath(outputDir, 'index.ts'), barrelContent);\n}\n"],"names":["generateFromTemplate","processTemplate","FieldTypeReverse","getTypeSizeBytes","typedArrayConstructors","typeToArrayConstructor","generateBarrelFileContent","schema","projectName","content","components","forEach","component","name","singletons","singleton","playerResources","playerResource","filters","filter","inputs","input","generateCode","options","outputDir","templateDir","fileOperations","writeFile","joinPath","exists","data","getFieldByteSize","field","baseSize","type","isArray","arrayLength","componentsImports","include","exclude","map","c","includeMask","reduce","acc","id","excludeMask","barrelContent"],"rangeMappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;","mappings":"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"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/index.ts"],"sourcesContent":["export * from './parser.js';\nexport * from './generator.js';\n"],"names":[],"rangeMappings":";","mappings":"AAAA,cAAc,cAAc;AAC5B,cAAc,iBAAiB"}
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
import { formatFiles, joinPathFragments } from '@nx/devkit';
|
|
2
|
+
import { parseYamlConfig } from './parser.js';
|
|
3
|
+
import { generateCode } from './generator.js';
|
|
4
|
+
import * as fs from 'fs';
|
|
5
|
+
import { DIRNAME } from './dirname.js';
|
|
6
|
+
export default async function(tree, options) {
|
|
7
|
+
// Read and parse YAML config
|
|
8
|
+
const configPath = options.configPath;
|
|
9
|
+
if (!tree.exists(configPath)) {
|
|
10
|
+
throw new Error(`Config file not found: ${configPath}`);
|
|
11
|
+
}
|
|
12
|
+
const configContent = tree.read(configPath, 'utf-8');
|
|
13
|
+
if (!configContent) throw new Error(`Config file is empty: ${configPath}`);
|
|
14
|
+
const { schema, projectName } = parseYamlConfig(configContent, configPath);
|
|
15
|
+
// Generate output directory from config path (../code-gen)
|
|
16
|
+
const outputDir = joinPathFragments(configPath, '../code-gen');
|
|
17
|
+
const templateDir = joinPathFragments(DIRNAME, '..', 'files');
|
|
18
|
+
// Create file operations adapter for NX Tree
|
|
19
|
+
const fileOperations = {
|
|
20
|
+
writeFile: (path, content)=>tree.write(path, content),
|
|
21
|
+
// Only writeFile uses tree, other methods use fs
|
|
22
|
+
readFile: (path)=>fs.readFileSync(path, 'utf-8'),
|
|
23
|
+
joinPath: (...segments)=>joinPathFragments(...segments),
|
|
24
|
+
exists: (path)=>{
|
|
25
|
+
try {
|
|
26
|
+
fs.accessSync(path, fs.constants.F_OK);
|
|
27
|
+
return true;
|
|
28
|
+
} catch (e) {
|
|
29
|
+
return false;
|
|
30
|
+
}
|
|
31
|
+
},
|
|
32
|
+
readDir: (path)=>{
|
|
33
|
+
try {
|
|
34
|
+
return fs.readdirSync(path);
|
|
35
|
+
} catch (e) {
|
|
36
|
+
return [];
|
|
37
|
+
}
|
|
38
|
+
},
|
|
39
|
+
isDirectory: (path)=>{
|
|
40
|
+
try {
|
|
41
|
+
return fs.statSync(path).isDirectory();
|
|
42
|
+
} catch (e) {
|
|
43
|
+
return false;
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
};
|
|
47
|
+
if (!tree.exists(outputDir)) {
|
|
48
|
+
tree.write(joinPathFragments(outputDir, '.gitkeep'), '');
|
|
49
|
+
}
|
|
50
|
+
// Generate code using the unified template engine
|
|
51
|
+
await generateCode({
|
|
52
|
+
schema,
|
|
53
|
+
projectName,
|
|
54
|
+
outputDir,
|
|
55
|
+
templateDir,
|
|
56
|
+
fileOperations
|
|
57
|
+
});
|
|
58
|
+
await formatFiles(tree);
|
|
59
|
+
return ()=>{
|
|
60
|
+
console.log('ECS code generation complete!');
|
|
61
|
+
console.log(`Generated ${schema.components.length} components and ${schema.singletons.length} singletons.`);
|
|
62
|
+
console.log(`Project name: ${projectName}`);
|
|
63
|
+
};
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
//# sourceMappingURL=nx-generator.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/nx-generator.ts"],"sourcesContent":["import { Tree, formatFiles, joinPathFragments } from '@nx/devkit';\nimport { parseYamlConfig } from './parser.js';\nimport { generateCode } from './generator.js';\nimport { FileOperations } from './template-engine.js';\nimport * as fs from 'fs';\nimport { DIRNAME } from './dirname.js';\n\ninterface GeneratorOptions {\n configPath: string;\n}\n\nexport default async function (tree: Tree, options: GeneratorOptions) {\n // Read and parse YAML config\n const configPath = options.configPath;\n if (!tree.exists(configPath)) {\n throw new Error(`Config file not found: ${configPath}`);\n }\n\n const configContent = tree.read(configPath, 'utf-8');\n if (!configContent) throw new Error(`Config file is empty: ${configPath}`);\n\n const { schema, projectName } = parseYamlConfig(configContent, configPath);\n\n // Generate output directory from config path (../code-gen)\n const outputDir = joinPathFragments(configPath, '../code-gen');\n const templateDir = joinPathFragments(DIRNAME, '..', 'files');\n\n // Create file operations adapter for NX Tree\n const fileOperations: FileOperations = {\n writeFile: (path: string, content: string) => tree.write(path, content),\n // Only writeFile uses tree, other methods use fs\n readFile: (path: string) => fs.readFileSync(path, 'utf-8'),\n joinPath: (...segments: string[]) => joinPathFragments(...segments),\n exists: (path: string) => {\n try {\n fs.accessSync(path, fs.constants.F_OK);\n return true;\n } catch {\n return false;\n }\n },\n readDir: (path: string) => {\n try {\n return fs.readdirSync(path);\n } catch {\n return [];\n }\n },\n isDirectory: (path: string) => {\n try {\n return fs.statSync(path).isDirectory();\n } catch {\n return false;\n }\n },\n };\n\n if (!tree.exists(outputDir)) {\n tree.write(joinPathFragments(outputDir, '.gitkeep'), '');\n }\n\n // Generate code using the unified template engine\n await generateCode({\n schema,\n projectName,\n outputDir,\n templateDir,\n fileOperations,\n });\n\n await formatFiles(tree);\n\n return () => {\n console.log('ECS code generation complete!');\n console.log(`Generated ${schema.components.length} components and ${schema.singletons.length} singletons.`);\n console.log(`Project name: ${projectName}`);\n };\n}\n"],"names":["formatFiles","joinPathFragments","parseYamlConfig","generateCode","fs","DIRNAME","tree","options","configPath","exists","Error","configContent","read","schema","projectName","outputDir","templateDir","fileOperations","writeFile","path","content","write","readFile","readFileSync","joinPath","segments","accessSync","constants","F_OK","readDir","readdirSync","isDirectory","statSync","console","log","components","length","singletons"],"rangeMappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;","mappings":"AAAA,SAAeA,WAAW,EAAEC,iBAAiB,QAAQ,aAAa;AAClE,SAASC,eAAe,QAAQ,cAAc;AAC9C,SAASC,YAAY,QAAQ,iBAAiB;AAE9C,YAAYC,QAAQ,KAAK;AACzB,SAASC,OAAO,QAAQ,eAAe;AAMvC,eAAe,eAAgBC,IAAU,EAAEC,OAAyB;IAClE,6BAA6B;IAC7B,MAAMC,aAAaD,QAAQC,UAAU;IACrC,IAAI,CAACF,KAAKG,MAAM,CAACD,aAAa;QAC5B,MAAM,IAAIE,MAAM,CAAC,uBAAuB,EAAEF,WAAW,CAAC;IACxD;IAEA,MAAMG,gBAAgBL,KAAKM,IAAI,CAACJ,YAAY;IAC5C,IAAI,CAACG,eAAe,MAAM,IAAID,MAAM,CAAC,sBAAsB,EAAEF,WAAW,CAAC;IAEzE,MAAM,EAAEK,MAAM,EAAEC,WAAW,EAAE,GAAGZ,gBAAgBS,eAAeH;IAE/D,2DAA2D;IAC3D,MAAMO,YAAYd,kBAAkBO,YAAY;IAChD,MAAMQ,cAAcf,kBAAkBI,SAAS,MAAM;IAErD,6CAA6C;IAC7C,MAAMY,iBAAiC;QACrCC,WAAW,CAACC,MAAcC,UAAoBd,KAAKe,KAAK,CAACF,MAAMC;QAC/D,iDAAiD;QACjDE,UAAU,CAACH,OAAiBf,GAAGmB,YAAY,CAACJ,MAAM;QAClDK,UAAU,CAAC,GAAGC,WAAuBxB,qBAAqBwB;QAC1DhB,QAAQ,CAACU;YACP,IAAI;gBACFf,GAAGsB,UAAU,CAACP,MAAMf,GAAGuB,SAAS,CAACC,IAAI;gBACrC,OAAO;YACT,EAAE,UAAM;gBACN,OAAO;YACT;QACF;QACAC,SAAS,CAACV;YACR,IAAI;gBACF,OAAOf,GAAG0B,WAAW,CAACX;YACxB,EAAE,UAAM;gBACN,OAAO,EAAE;YACX;QACF;QACAY,aAAa,CAACZ;YACZ,IAAI;gBACF,OAAOf,GAAG4B,QAAQ,CAACb,MAAMY,WAAW;YACtC,EAAE,UAAM;gBACN,OAAO;YACT;QACF;IACF;IAEA,IAAI,CAACzB,KAAKG,MAAM,CAACM,YAAY;QAC3BT,KAAKe,KAAK,CAACpB,kBAAkBc,WAAW,aAAa;IACvD;IAEA,kDAAkD;IAClD,MAAMZ,aAAa;QACjBU;QACAC;QACAC;QACAC;QACAC;IACF;IAEA,MAAMjB,YAAYM;IAElB,OAAO;QACL2B,QAAQC,GAAG,CAAC;QACZD,QAAQC,GAAG,CAAC,CAAC,UAAU,EAAErB,OAAOsB,UAAU,CAACC,MAAM,CAAC,gBAAgB,EAAEvB,OAAOwB,UAAU,CAACD,MAAM,CAAC,YAAY,CAAC;QAC1GH,QAAQC,GAAG,CAAC,CAAC,cAAc,EAAEpB,YAAY,CAAC;IAC5C;AACF"}
|
package/dist/parser.js
ADDED
|
@@ -0,0 +1,160 @@
|
|
|
1
|
+
import { _ as _extends } from "@swc/helpers/_/_extends";
|
|
2
|
+
import { getTypeSizeBytes, typeStringToFieldType, typeToArrayConstructor } from '@lagless/binary';
|
|
3
|
+
import { parse } from 'yaml';
|
|
4
|
+
export function parseInputFieldType(fieldName, fieldType) {
|
|
5
|
+
const res = parseFieldType(fieldType);
|
|
6
|
+
return _extends({
|
|
7
|
+
name: fieldName
|
|
8
|
+
}, res, {
|
|
9
|
+
type: typeStringToFieldType[res.type],
|
|
10
|
+
byteLength: res.isArray && res.arrayLength ? getTypeSizeBytes(res.type) * res.arrayLength : getTypeSizeBytes(res.type)
|
|
11
|
+
});
|
|
12
|
+
}
|
|
13
|
+
export function parseFieldType(typeStr) {
|
|
14
|
+
const arrayMatch = typeStr.match(/^(\w+)\[(\d+)]$/);
|
|
15
|
+
if (arrayMatch) {
|
|
16
|
+
const baseType = arrayMatch[1];
|
|
17
|
+
const arrayLength = parseInt(arrayMatch[2], 10);
|
|
18
|
+
if (!Object.keys(typeToArrayConstructor).includes(baseType)) {
|
|
19
|
+
throw new Error(`Unsupported array base type: ${baseType}`);
|
|
20
|
+
}
|
|
21
|
+
if (arrayLength <= 0) {
|
|
22
|
+
throw new Error(`Array length must be positive: ${arrayLength}`);
|
|
23
|
+
}
|
|
24
|
+
return {
|
|
25
|
+
type: baseType,
|
|
26
|
+
isArray: true,
|
|
27
|
+
arrayLength
|
|
28
|
+
};
|
|
29
|
+
} else {
|
|
30
|
+
if (!Object.keys(typeToArrayConstructor).includes(typeStr)) {
|
|
31
|
+
throw new Error(`Unsupported type: ${typeStr}`);
|
|
32
|
+
}
|
|
33
|
+
return {
|
|
34
|
+
type: typeStr,
|
|
35
|
+
isArray: false
|
|
36
|
+
};
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
export function getProjectNameFromConfigPath(configPath) {
|
|
40
|
+
let projectName = configPath.split('/').slice(-5)[0];
|
|
41
|
+
projectName = projectName.slice(0, 1).toUpperCase() + projectName.slice(1);
|
|
42
|
+
// kebab to PascalCase
|
|
43
|
+
projectName = projectName.replace(/-([a-z])/g, (match, letter)=>letter.toUpperCase());
|
|
44
|
+
return projectName;
|
|
45
|
+
}
|
|
46
|
+
export function parseYamlConfig(configContent, configPath) {
|
|
47
|
+
const rawConfig = parse(configContent);
|
|
48
|
+
if (!rawConfig.components && !rawConfig.singletons) {
|
|
49
|
+
throw new Error('Config must contain at least one of: components, singletons');
|
|
50
|
+
}
|
|
51
|
+
// Determine project name: from config or from path
|
|
52
|
+
let projectName;
|
|
53
|
+
if (rawConfig.projectName) {
|
|
54
|
+
projectName = rawConfig.projectName;
|
|
55
|
+
} else if (configPath) {
|
|
56
|
+
projectName = getProjectNameFromConfigPath(configPath);
|
|
57
|
+
} else {
|
|
58
|
+
throw new Error('projectName must be specified in config or configPath must be provided');
|
|
59
|
+
}
|
|
60
|
+
const components = [];
|
|
61
|
+
const singletons = [];
|
|
62
|
+
// Parse components
|
|
63
|
+
let componentIdx = 0;
|
|
64
|
+
if (rawConfig.components) {
|
|
65
|
+
for (const [componentName, componentFields] of Object.entries(rawConfig.components)){
|
|
66
|
+
const fields = {};
|
|
67
|
+
for (const [fieldName, fieldType] of Object.entries(componentFields)){
|
|
68
|
+
fields[fieldName] = parseFieldType(fieldType);
|
|
69
|
+
}
|
|
70
|
+
components.push({
|
|
71
|
+
name: componentName,
|
|
72
|
+
id: Math.pow(2, componentIdx++),
|
|
73
|
+
fields
|
|
74
|
+
});
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
// Parse singletons
|
|
78
|
+
if (rawConfig.singletons) {
|
|
79
|
+
for (const [singletonName, singletonFields] of Object.entries(rawConfig.singletons)){
|
|
80
|
+
const fields = {};
|
|
81
|
+
for (const [fieldName, fieldType] of Object.entries(singletonFields)){
|
|
82
|
+
fields[fieldName] = parseFieldType(fieldType);
|
|
83
|
+
}
|
|
84
|
+
singletons.push({
|
|
85
|
+
name: singletonName,
|
|
86
|
+
fields
|
|
87
|
+
});
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
const playerResources = new Array();
|
|
91
|
+
// Parse player resources
|
|
92
|
+
if (rawConfig.playerResources) {
|
|
93
|
+
for (const [resourceName, resourceFields] of Object.entries(rawConfig.playerResources)){
|
|
94
|
+
const fields = {};
|
|
95
|
+
for (const [fieldName, fieldType] of Object.entries(resourceFields)){
|
|
96
|
+
fields[fieldName] = parseFieldType(fieldType);
|
|
97
|
+
}
|
|
98
|
+
playerResources.push({
|
|
99
|
+
name: resourceName,
|
|
100
|
+
fields
|
|
101
|
+
});
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
const filters = new Array();
|
|
105
|
+
// Parse filters
|
|
106
|
+
if (rawConfig.filters) {
|
|
107
|
+
for (const [filterName, filterComponents] of Object.entries(rawConfig.filters)){
|
|
108
|
+
const include = [];
|
|
109
|
+
const exclude = [];
|
|
110
|
+
for (const componentName of filterComponents.include || []){
|
|
111
|
+
const component = components.find((c)=>c.name === componentName);
|
|
112
|
+
if (!component) {
|
|
113
|
+
throw new Error(`Component not found in schema: ${componentName}`);
|
|
114
|
+
}
|
|
115
|
+
include.push(component);
|
|
116
|
+
}
|
|
117
|
+
for (const componentName of filterComponents.exclude || []){
|
|
118
|
+
const component = components.find((c)=>c.name === componentName);
|
|
119
|
+
if (!component) {
|
|
120
|
+
throw new Error(`Component not found in schema: ${componentName}`);
|
|
121
|
+
}
|
|
122
|
+
exclude.push(component);
|
|
123
|
+
}
|
|
124
|
+
filters.push({
|
|
125
|
+
name: filterName,
|
|
126
|
+
include,
|
|
127
|
+
exclude
|
|
128
|
+
});
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
const inputs = new Array();
|
|
132
|
+
// Parse inputs
|
|
133
|
+
if (rawConfig.inputs) {
|
|
134
|
+
let inputIdx = 1;
|
|
135
|
+
for (const [inputName, inputFields] of Object.entries(rawConfig.inputs)){
|
|
136
|
+
const fields = new Array();
|
|
137
|
+
for (const [fieldName, fieldType] of Object.entries(inputFields)){
|
|
138
|
+
fields.push(parseInputFieldType(fieldName, fieldType));
|
|
139
|
+
}
|
|
140
|
+
inputs.push({
|
|
141
|
+
name: inputName,
|
|
142
|
+
id: inputIdx++,
|
|
143
|
+
fields
|
|
144
|
+
});
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
const schema = {
|
|
148
|
+
components,
|
|
149
|
+
singletons,
|
|
150
|
+
filters,
|
|
151
|
+
playerResources,
|
|
152
|
+
inputs
|
|
153
|
+
};
|
|
154
|
+
return {
|
|
155
|
+
schema,
|
|
156
|
+
projectName
|
|
157
|
+
};
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
//# sourceMappingURL=parser.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/parser.ts"],"sourcesContent":["import {\n getTypeSizeBytes,\n InputFieldDefinition,\n typeStringToFieldType,\n typeToArrayConstructor,\n} from '@lagless/binary';\nimport {\n ComponentDefinition,\n ECSSchema,\n FieldDefinition,\n FilterDefinition,\n IInputDefinition,\n PlayerResourceDefinition,\n SingletonDefinition,\n} from '@lagless/core';\nimport { parse } from 'yaml';\n\nexport interface ECSConfig {\n projectName?: string;\n components?: Record<string, Record<string, string>>;\n singletons?: Record<string, Record<string, string>>;\n playerResources?: Record<string, Record<string, string>>;\n filters?: Record<string, { include?: string[]; exclude?: string[] }>;\n inputs?: Record<string, Record<string, string>>;\n}\n\nexport function parseInputFieldType(fieldName: string, fieldType: string): InputFieldDefinition {\n const res = parseFieldType(fieldType);\n\n return {\n name: fieldName,\n ...res,\n type: typeStringToFieldType[res.type],\n byteLength: res.isArray && res.arrayLength ? getTypeSizeBytes(res.type) * res.arrayLength : getTypeSizeBytes(res.type),\n };\n}\n\nexport function parseFieldType(typeStr: string): FieldDefinition {\n const arrayMatch = typeStr.match(/^(\\w+)\\[(\\d+)]$/);\n if (arrayMatch) {\n const baseType = arrayMatch[1];\n const arrayLength = parseInt(arrayMatch[2], 10);\n\n if (!Object.keys(typeToArrayConstructor).includes(baseType)) {\n throw new Error(`Unsupported array base type: ${baseType}`);\n }\n\n if (arrayLength <= 0) {\n throw new Error(`Array length must be positive: ${arrayLength}`);\n }\n\n return {\n type: baseType,\n isArray: true,\n arrayLength,\n };\n } else {\n if (!Object.keys(typeToArrayConstructor).includes(typeStr)) {\n throw new Error(`Unsupported type: ${typeStr}`);\n }\n\n return {\n type: typeStr,\n isArray: false,\n };\n }\n}\n\nexport function getProjectNameFromConfigPath(configPath: string): string {\n let projectName = configPath.split('/').slice(-5)[0];\n projectName = projectName.slice(0, 1).toUpperCase() + projectName.slice(1);\n // kebab to PascalCase\n projectName = projectName.replace(/-([a-z])/g, (match, letter) => letter.toUpperCase());\n return projectName;\n}\n\nexport function parseYamlConfig(configContent: string, configPath?: string): { schema: ECSSchema; projectName: string } {\n const rawConfig = parse(configContent) as ECSConfig;\n\n if (!rawConfig.components && !rawConfig.singletons) {\n throw new Error('Config must contain at least one of: components, singletons');\n }\n\n // Determine project name: from config or from path\n let projectName: string;\n if (rawConfig.projectName) {\n projectName = rawConfig.projectName;\n } else if (configPath) {\n projectName = getProjectNameFromConfigPath(configPath);\n } else {\n throw new Error('projectName must be specified in config or configPath must be provided');\n }\n\n const components: ComponentDefinition[] = [];\n const singletons: SingletonDefinition[] = [];\n\n // Parse components\n let componentIdx = 0;\n if (rawConfig.components) {\n for (const [componentName, componentFields] of Object.entries<Record<string, string>>(rawConfig.components)) {\n const fields: Record<string, FieldDefinition> = {};\n\n for (const [fieldName, fieldType] of Object.entries<string>(componentFields)) {\n fields[fieldName] = parseFieldType(fieldType);\n }\n\n components.push({\n name: componentName,\n id: Math.pow(2, componentIdx++),\n fields,\n });\n }\n }\n\n // Parse singletons\n if (rawConfig.singletons) {\n for (const [singletonName, singletonFields] of Object.entries<Record<string, string>>(rawConfig.singletons)) {\n const fields: Record<string, FieldDefinition> = {};\n\n for (const [fieldName, fieldType] of Object.entries<string>(singletonFields)) {\n fields[fieldName] = parseFieldType(fieldType);\n }\n\n singletons.push({\n name: singletonName,\n fields,\n });\n }\n }\n\n const playerResources = new Array<PlayerResourceDefinition>();\n // Parse player resources\n if (rawConfig.playerResources) {\n for (const [resourceName, resourceFields] of Object.entries<Record<string, string>>(rawConfig.playerResources)) {\n const fields: Record<string, FieldDefinition> = {};\n\n for (const [fieldName, fieldType] of Object.entries<string>(resourceFields)) {\n fields[fieldName] = parseFieldType(fieldType);\n }\n\n playerResources.push({\n name: resourceName,\n fields,\n });\n }\n }\n\n const filters = new Array<FilterDefinition>();\n // Parse filters\n if (rawConfig.filters) {\n for (const [filterName, filterComponents] of Object.entries(rawConfig.filters)) {\n const include: ComponentDefinition[] = [];\n const exclude: ComponentDefinition[] = [];\n\n for (const componentName of filterComponents.include || []) {\n const component = components.find(c => c.name === componentName);\n if (!component) {\n throw new Error(`Component not found in schema: ${componentName}`);\n }\n include.push(component);\n }\n\n for (const componentName of filterComponents.exclude || []) {\n const component = components.find(c => c.name === componentName);\n if (!component) {\n throw new Error(`Component not found in schema: ${componentName}`);\n }\n exclude.push(component);\n }\n\n filters.push({\n name: filterName,\n include,\n exclude,\n });\n }\n }\n\n const inputs = new Array<IInputDefinition>();\n // Parse inputs\n if (rawConfig.inputs) {\n let inputIdx = 1;\n for (const [inputName, inputFields] of Object.entries<Record<string, string>>(rawConfig.inputs)) {\n const fields = new Array<InputFieldDefinition>();\n\n for (const [fieldName, fieldType] of Object.entries<string>(inputFields)) {\n fields.push(parseInputFieldType(fieldName, fieldType));\n }\n\n inputs.push({\n name: inputName,\n id: inputIdx++,\n fields,\n });\n }\n }\n\n const schema = { components, singletons, filters, playerResources, inputs };\n return { schema, projectName };\n}\n"],"names":["getTypeSizeBytes","typeStringToFieldType","typeToArrayConstructor","parse","parseInputFieldType","fieldName","fieldType","res","parseFieldType","name","type","byteLength","isArray","arrayLength","typeStr","arrayMatch","match","baseType","parseInt","Object","keys","includes","Error","getProjectNameFromConfigPath","configPath","projectName","split","slice","toUpperCase","replace","letter","parseYamlConfig","configContent","rawConfig","components","singletons","componentIdx","componentName","componentFields","entries","fields","push","id","Math","pow","singletonName","singletonFields","playerResources","Array","resourceName","resourceFields","filters","filterName","filterComponents","include","exclude","component","find","c","inputs","inputIdx","inputName","inputFields","schema"],"rangeMappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;","mappings":"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"}
|
|
@@ -0,0 +1,149 @@
|
|
|
1
|
+
import * as ejs from 'ejs';
|
|
2
|
+
export class TemplateEngine {
|
|
3
|
+
async generateFromTemplate(options) {
|
|
4
|
+
const { templateDir, outputDir, data } = options;
|
|
5
|
+
if (!this.fileOps.exists(templateDir)) {
|
|
6
|
+
throw new Error(`Template directory not found: ${templateDir}`);
|
|
7
|
+
}
|
|
8
|
+
// Find all template files
|
|
9
|
+
const templateFiles = this.findTemplateFiles(templateDir, '');
|
|
10
|
+
if (templateFiles.length === 0) {
|
|
11
|
+
throw new Error(`No template files found in: ${templateDir}`);
|
|
12
|
+
}
|
|
13
|
+
// Process each template file
|
|
14
|
+
for (const templateFile of templateFiles){
|
|
15
|
+
await this.processTemplateFile(templateFile, outputDir, data);
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
findTemplateFiles(baseDir, relativePath) {
|
|
19
|
+
const files = [];
|
|
20
|
+
const currentDir = this.fileOps.joinPath(baseDir, relativePath);
|
|
21
|
+
if (!this.fileOps.exists(currentDir)) {
|
|
22
|
+
return files;
|
|
23
|
+
}
|
|
24
|
+
// If we have readDir and isDirectory, use them for proper directory traversal
|
|
25
|
+
if (this.fileOps.readDir && this.fileOps.isDirectory) {
|
|
26
|
+
try {
|
|
27
|
+
const entries = this.fileOps.readDir(currentDir);
|
|
28
|
+
for (const entry of entries){
|
|
29
|
+
const entryPath = this.fileOps.joinPath(currentDir, entry);
|
|
30
|
+
const entryRelativePath = relativePath ? this.fileOps.joinPath(relativePath, entry) : entry;
|
|
31
|
+
if (this.fileOps.isDirectory(entryPath)) {
|
|
32
|
+
// Recursively process subdirectories
|
|
33
|
+
files.push(...this.findTemplateFiles(baseDir, entryRelativePath));
|
|
34
|
+
} else if (this.isTemplateFile(entry)) {
|
|
35
|
+
files.push({
|
|
36
|
+
fullPath: entryPath,
|
|
37
|
+
relativePath: entryRelativePath,
|
|
38
|
+
outputPath: this.getOutputPath(entryRelativePath)
|
|
39
|
+
});
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
} catch (error) {
|
|
43
|
+
console.warn(`Could not read directory ${currentDir}:`, error);
|
|
44
|
+
}
|
|
45
|
+
} else {
|
|
46
|
+
// Fallback: check for common template file patterns
|
|
47
|
+
const commonFiles = [
|
|
48
|
+
'index.ts.ejs',
|
|
49
|
+
'index.ts',
|
|
50
|
+
'__name__.ts.ejs',
|
|
51
|
+
'__name__.ts',
|
|
52
|
+
'__projectName__.ts.ejs',
|
|
53
|
+
'__projectName__.ts',
|
|
54
|
+
'template.ts.ejs',
|
|
55
|
+
'template.ts'
|
|
56
|
+
];
|
|
57
|
+
for (const fileName of commonFiles){
|
|
58
|
+
const fullPath = this.fileOps.joinPath(currentDir, fileName);
|
|
59
|
+
if (this.fileOps.exists(fullPath)) {
|
|
60
|
+
const fileRelativePath = relativePath ? this.fileOps.joinPath(relativePath, fileName) : fileName;
|
|
61
|
+
files.push({
|
|
62
|
+
fullPath,
|
|
63
|
+
relativePath: fileRelativePath,
|
|
64
|
+
outputPath: this.getOutputPath(fileRelativePath)
|
|
65
|
+
});
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
return files;
|
|
70
|
+
}
|
|
71
|
+
isTemplateFile(fileName) {
|
|
72
|
+
// Consider files as templates if they:
|
|
73
|
+
// 1. Have .ejs extension
|
|
74
|
+
// 2. Are common code file extensions (.ts, .js, .json, etc.)
|
|
75
|
+
// 3. Contain template variables in filename
|
|
76
|
+
const templateExtensions = [
|
|
77
|
+
'.ejs',
|
|
78
|
+
'.ts',
|
|
79
|
+
'.js',
|
|
80
|
+
'.json',
|
|
81
|
+
'.md',
|
|
82
|
+
'.txt',
|
|
83
|
+
'.html'
|
|
84
|
+
];
|
|
85
|
+
const hasTemplateExtension = templateExtensions.some((ext)=>fileName.endsWith(ext));
|
|
86
|
+
const hasTemplateVariables = fileName.includes('__') || fileName.includes('<%');
|
|
87
|
+
return hasTemplateExtension || hasTemplateVariables;
|
|
88
|
+
}
|
|
89
|
+
getOutputPath(relativePath) {
|
|
90
|
+
let outputPath = relativePath;
|
|
91
|
+
// extension should be always .ts
|
|
92
|
+
// if ends with .template, just remove it
|
|
93
|
+
if (outputPath.endsWith('.template')) {
|
|
94
|
+
outputPath = outputPath.slice(0, -'.template'.length);
|
|
95
|
+
}
|
|
96
|
+
return outputPath;
|
|
97
|
+
}
|
|
98
|
+
async processTemplateFile(templateFile, outputDir, data) {
|
|
99
|
+
try {
|
|
100
|
+
// Read template content
|
|
101
|
+
const templateContent = this.fileOps.readFile(templateFile.fullPath);
|
|
102
|
+
// Process filename with template variables
|
|
103
|
+
let outputFileName = templateFile.outputPath;
|
|
104
|
+
if (outputFileName.includes('__') || outputFileName.includes('<%')) {
|
|
105
|
+
outputFileName = this.processFileName(outputFileName, data);
|
|
106
|
+
}
|
|
107
|
+
// Render template content
|
|
108
|
+
const renderedContent = ejs.render(templateContent, data, {
|
|
109
|
+
filename: templateFile.fullPath,
|
|
110
|
+
rmWhitespace: false,
|
|
111
|
+
delimiter: '%'
|
|
112
|
+
});
|
|
113
|
+
// Write output file
|
|
114
|
+
const outputPath = this.fileOps.joinPath(outputDir, outputFileName);
|
|
115
|
+
this.fileOps.writeFile(outputPath, renderedContent);
|
|
116
|
+
console.log(`Generated: ${outputFileName}`);
|
|
117
|
+
} catch (error) {
|
|
118
|
+
throw new Error(`Failed to process template ${templateFile.relativePath}: ${error instanceof Error ? error.message : error}`);
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
processFileName(fileName, data) {
|
|
122
|
+
let result = fileName;
|
|
123
|
+
// Handle __variable__ pattern
|
|
124
|
+
result = result.replace(/__(\w+)__/g, (match, varName)=>{
|
|
125
|
+
return data[varName] || match;
|
|
126
|
+
});
|
|
127
|
+
// Handle EJS pattern <%= variable %>
|
|
128
|
+
if (result.includes('<%')) {
|
|
129
|
+
try {
|
|
130
|
+
result = ejs.render(result, data, {
|
|
131
|
+
delimiter: '%'
|
|
132
|
+
});
|
|
133
|
+
} catch (error) {
|
|
134
|
+
console.warn(`Could not process filename template: ${fileName}`, error);
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
return result;
|
|
138
|
+
}
|
|
139
|
+
constructor(fileOperations){
|
|
140
|
+
this.fileOps = fileOperations;
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
// Helper function for easier usage
|
|
144
|
+
export function generateFromTemplate(options) {
|
|
145
|
+
const engine = new TemplateEngine(options.fileOperations);
|
|
146
|
+
return engine.generateFromTemplate(options);
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
//# sourceMappingURL=template-engine.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/template-engine.ts"],"sourcesContent":["import * as ejs from 'ejs';\n\nexport interface FileOperations {\n readFile: (path: string) => string;\n writeFile: (path: string, content: string) => void;\n joinPath: (...segments: string[]) => string;\n exists: (path: string) => boolean;\n readDir?: (path: string) => string[];\n isDirectory?: (path: string) => boolean;\n}\n\nexport interface TemplateOptions {\n templateDir: string;\n outputDir: string;\n data: any;\n fileOperations: FileOperations;\n}\n\nexport interface TemplateFile {\n fullPath: string;\n relativePath: string;\n outputPath: string;\n}\n\nexport class TemplateEngine {\n private fileOps: FileOperations;\n\n constructor(fileOperations: FileOperations) {\n this.fileOps = fileOperations;\n }\n\n async generateFromTemplate(options: TemplateOptions): Promise<void> {\n const { templateDir, outputDir, data } = options;\n\n if (!this.fileOps.exists(templateDir)) {\n throw new Error(`Template directory not found: ${templateDir}`);\n }\n\n // Find all template files\n const templateFiles = this.findTemplateFiles(templateDir, '');\n\n if (templateFiles.length === 0) {\n throw new Error(`No template files found in: ${templateDir}`);\n }\n\n // Process each template file\n for (const templateFile of templateFiles) {\n await this.processTemplateFile(templateFile, outputDir, data);\n }\n }\n\n private findTemplateFiles(baseDir: string, relativePath: string): TemplateFile[] {\n const files: TemplateFile[] = [];\n const currentDir = this.fileOps.joinPath(baseDir, relativePath);\n\n if (!this.fileOps.exists(currentDir)) {\n return files;\n }\n\n // If we have readDir and isDirectory, use them for proper directory traversal\n if (this.fileOps.readDir && this.fileOps.isDirectory) {\n try {\n const entries = this.fileOps.readDir(currentDir);\n\n for (const entry of entries) {\n const entryPath = this.fileOps.joinPath(currentDir, entry);\n const entryRelativePath = relativePath ? this.fileOps.joinPath(relativePath, entry) : entry;\n\n if (this.fileOps.isDirectory(entryPath)) {\n // Recursively process subdirectories\n files.push(...this.findTemplateFiles(baseDir, entryRelativePath));\n } else if (this.isTemplateFile(entry)) {\n files.push({\n fullPath: entryPath,\n relativePath: entryRelativePath,\n outputPath: this.getOutputPath(entryRelativePath),\n });\n }\n }\n } catch (error) {\n console.warn(`Could not read directory ${currentDir}:`, error);\n }\n } else {\n // Fallback: check for common template file patterns\n const commonFiles = [\n 'index.ts.ejs',\n 'index.ts',\n '__name__.ts.ejs',\n '__name__.ts',\n '__projectName__.ts.ejs',\n '__projectName__.ts',\n 'template.ts.ejs',\n 'template.ts',\n ];\n\n for (const fileName of commonFiles) {\n const fullPath = this.fileOps.joinPath(currentDir, fileName);\n if (this.fileOps.exists(fullPath)) {\n const fileRelativePath = relativePath ? this.fileOps.joinPath(relativePath, fileName) : fileName;\n files.push({\n fullPath,\n relativePath: fileRelativePath,\n outputPath: this.getOutputPath(fileRelativePath),\n });\n }\n }\n }\n\n return files;\n }\n\n private isTemplateFile(fileName: string): boolean {\n // Consider files as templates if they:\n // 1. Have .ejs extension\n // 2. Are common code file extensions (.ts, .js, .json, etc.)\n // 3. Contain template variables in filename\n const templateExtensions = ['.ejs', '.ts', '.js', '.json', '.md', '.txt', '.html'];\n const hasTemplateExtension = templateExtensions.some(ext => fileName.endsWith(ext));\n const hasTemplateVariables = fileName.includes('__') || fileName.includes('<%');\n\n return hasTemplateExtension || hasTemplateVariables;\n }\n\n private getOutputPath(relativePath: string): string {\n let outputPath = relativePath;\n\n // extension should be always .ts\n // if ends with .template, just remove it\n\n if (outputPath.endsWith('.template')) {\n outputPath = outputPath.slice(0, -'.template'.length);\n }\n\n return outputPath;\n }\n\n private async processTemplateFile(templateFile: TemplateFile, outputDir: string, data: any): Promise<void> {\n try {\n // Read template content\n const templateContent = this.fileOps.readFile(templateFile.fullPath);\n\n // Process filename with template variables\n let outputFileName = templateFile.outputPath;\n if (outputFileName.includes('__') || outputFileName.includes('<%')) {\n outputFileName = this.processFileName(outputFileName, data);\n }\n\n // Render template content\n const renderedContent = ejs.render(templateContent, data, {\n filename: templateFile.fullPath,\n rmWhitespace: false,\n delimiter: '%',\n });\n\n // Write output file\n const outputPath = this.fileOps.joinPath(outputDir, outputFileName);\n this.fileOps.writeFile(outputPath, renderedContent);\n\n console.log(`Generated: ${outputFileName}`);\n\n } catch (error) {\n throw new Error(`Failed to process template ${templateFile.relativePath}: ${error instanceof Error ? error.message : error}`);\n }\n }\n\n private processFileName(fileName: string, data: any): string {\n let result = fileName;\n\n // Handle __variable__ pattern\n result = result.replace(/__(\\w+)__/g, (match, varName) => {\n return data[varName] || match;\n });\n\n // Handle EJS pattern <%= variable %>\n if (result.includes('<%')) {\n try {\n result = ejs.render(result, data, { delimiter: '%' });\n } catch (error) {\n console.warn(`Could not process filename template: ${fileName}`, error);\n }\n }\n\n return result;\n }\n}\n\n// Helper function for easier usage\nexport function generateFromTemplate(options: TemplateOptions): Promise<void> {\n const engine = new TemplateEngine(options.fileOperations);\n return engine.generateFromTemplate(options);\n}\n"],"names":["ejs","TemplateEngine","generateFromTemplate","options","templateDir","outputDir","data","fileOps","exists","Error","templateFiles","findTemplateFiles","length","templateFile","processTemplateFile","baseDir","relativePath","files","currentDir","joinPath","readDir","isDirectory","entries","entry","entryPath","entryRelativePath","push","isTemplateFile","fullPath","outputPath","getOutputPath","error","console","warn","commonFiles","fileName","fileRelativePath","templateExtensions","hasTemplateExtension","some","ext","endsWith","hasTemplateVariables","includes","slice","templateContent","readFile","outputFileName","processFileName","renderedContent","render","filename","rmWhitespace","delimiter","writeFile","log","message","result","replace","match","varName","constructor","fileOperations","engine"],"rangeMappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;","mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":"5.9.3"}
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
// Generated by @lagless/codegen. Do not edit manually.
|
|
2
|
+
import { MemoryTracker } from '@lagless/binary';
|
|
3
|
+
|
|
4
|
+
export class <%= component.name %> {
|
|
5
|
+
public static readonly ID = <%= component.id %>;
|
|
6
|
+
public static readonly schema = {
|
|
7
|
+
<% for (const [fieldName, field] of Object.entries(fields)) { %>
|
|
8
|
+
<%= fieldName %>: <%= typeToArrayConstructor[field.type].name %>,
|
|
9
|
+
<% } %>
|
|
10
|
+
};
|
|
11
|
+
|
|
12
|
+
public readonly unsafe = {} as {
|
|
13
|
+
<% for (const [fieldName, field] of Object.entries(fields)) { %>
|
|
14
|
+
<%= fieldName %>: <%= typeToArrayConstructor[field.type].name %>;
|
|
15
|
+
<% } %>
|
|
16
|
+
};
|
|
17
|
+
|
|
18
|
+
private _cursorIndex = 0;
|
|
19
|
+
private readonly _cursor: {
|
|
20
|
+
readonly entity: number;
|
|
21
|
+
<% for (const [fieldName, field] of Object.entries(fields)) { %>
|
|
22
|
+
<%= fieldName %>: number;
|
|
23
|
+
<% } %>
|
|
24
|
+
};
|
|
25
|
+
|
|
26
|
+
public getCursor(index: number) {
|
|
27
|
+
this._cursorIndex = index;
|
|
28
|
+
return this._cursor;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
constructor(maxEntities: number, buffer: ArrayBuffer, memTracker: MemoryTracker) {
|
|
32
|
+
for (const [fieldName, TypedArrayConstructor] of Object.entries(<%= component.name %>.schema)) {
|
|
33
|
+
const typedArray = new TypedArrayConstructor(buffer, memTracker.ptr, maxEntities);
|
|
34
|
+
this.unsafe[fieldName as keyof typeof <%= component.name %>.schema] = typedArray as <%= component.name %>['unsafe'][keyof <%= component.name %>['unsafe']];
|
|
35
|
+
memTracker.add(typedArray.byteLength);
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
// eslint-disable-next-line @typescript-eslint/no-this-alias
|
|
39
|
+
const self = this;
|
|
40
|
+
|
|
41
|
+
this._cursor = {
|
|
42
|
+
get entity(): number {
|
|
43
|
+
return self._cursorIndex;
|
|
44
|
+
},
|
|
45
|
+
|
|
46
|
+
<% for (const [fieldName, field] of Object.entries(fields)) { %>
|
|
47
|
+
get <%= fieldName %>(): number {
|
|
48
|
+
return self.unsafe.<%= fieldName %>[self._cursorIndex];
|
|
49
|
+
},
|
|
50
|
+
|
|
51
|
+
set <%= fieldName %>(value: number) {
|
|
52
|
+
self.unsafe.<%= fieldName %>[self._cursorIndex] = value;
|
|
53
|
+
},
|
|
54
|
+
<% } %>
|
|
55
|
+
};
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
public static calculateSize(maxEntities: number, memTracker: MemoryTracker): void {
|
|
59
|
+
for (const [, TypedArrayConstructor] of Object.entries(this.schema)) {
|
|
60
|
+
memTracker.add(maxEntities * TypedArrayConstructor.BYTES_PER_ELEMENT);
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
Object.defineProperty(<%= component.name %>, 'name', { value: '<%= component.name %>' });
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
// Generated by @lagless/codegen. Do not edit manually.
|
|
2
|
+
import { ECSDeps } from '@lagless/core';
|
|
3
|
+
|
|
4
|
+
<% for (const component of schema.components) { %>import { <%= component.name %> } from './<%= component.name %>.js';<% } %>
|
|
5
|
+
<% for (const singleton of schema.singletons) { %>import { <%= singleton.name %> } from './<%= singleton.name %>.js';<% } %>
|
|
6
|
+
<% for (const playerResource of schema.playerResources) { %>import { <%= playerResource.name %> } from './<%= playerResource.name %>.js';<% } %>
|
|
7
|
+
<% for (const filter of schema.filters) { %>import { <%= filter.name %> } from './<%= filter.name %>.js';<% } %>
|
|
8
|
+
<% for (const input of schema.inputs) { %>import { <%= input.name %> } from './<%= input.name %>.js';<% } %>
|
|
9
|
+
|
|
10
|
+
export const <%= projectName %>Core: ECSDeps = {
|
|
11
|
+
components: [ <%= schema.components.map(({ name }) => name).join(', ') %> ],
|
|
12
|
+
singletons: [ <%= schema.singletons.map(({ name }) => name).join(', ') %> ],
|
|
13
|
+
playerResources: [ <%= schema.playerResources.map(({ name }) => name).join(', ') %> ],
|
|
14
|
+
filters: [ <%= schema.filters.map(({ name }) => name).join(', ') %> ],
|
|
15
|
+
inputs: [ <%= schema.inputs.map(({ name }) => name).join(', ') %> ],
|
|
16
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
// Generated by @lagless/codegen. Do not edit manually.
|
|
2
|
+
import { AbstractFilter, IComponentConstructor } from '@lagless/core';
|
|
3
|
+
<% for (const importComponent of componentsImports ) { %>import { <%= importComponent %> } from './<%= importComponent %>.js';<% } %>
|
|
4
|
+
|
|
5
|
+
export class <%= filter.name %> extends AbstractFilter {
|
|
6
|
+
public static readonly include: Array<IComponentConstructor> = [<%= filter.include.map(({ name }) => name).join(',') %>];
|
|
7
|
+
public static readonly exclude: Array<IComponentConstructor> = [<%= filter.exclude.map(({ name }) => name).join(',') %>];
|
|
8
|
+
|
|
9
|
+
public readonly includeMask: number = <%= includeMask %>;
|
|
10
|
+
public readonly excludeMask: number = <%= excludeMask %>;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
Object.defineProperty(<%= filter.name %>, 'name', { value: '<%= filter.name %>' });
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
// Generated by @lagless/codegen. Do not edit manually.
|
|
2
|
+
import { FieldType } from '@lagless/binary';
|
|
3
|
+
|
|
4
|
+
export class <%= input.name %> {
|
|
5
|
+
public static readonly id = <%= input.id %>;
|
|
6
|
+
public readonly id = <%= input.id %>;
|
|
7
|
+
|
|
8
|
+
<% let totalByteLength = input.fields.reduce((acc, field) => acc + field.byteLength, 0); %>
|
|
9
|
+
|
|
10
|
+
// <%= input.fields.map((field) => field.byteLength).join(' + ') %> = <%= totalByteLength %>;
|
|
11
|
+
public readonly byteLength = <%= totalByteLength %>;
|
|
12
|
+
|
|
13
|
+
public readonly fields = [
|
|
14
|
+
<% for (const field of input.fields) { %>
|
|
15
|
+
<% if (field.isArray) { %>
|
|
16
|
+
{ name: '<%= field.name %>', type: FieldType.<%= FieldTypeReverse[field.type] %>, isArray: true, arrayLength: <%= field.arrayLength %>, byteLength: <%= field.byteLength %> },
|
|
17
|
+
<% } else { %>
|
|
18
|
+
{ name: '<%= field.name %>', type: FieldType.<%= FieldTypeReverse[field.type] %>, isArray: false, byteLength: <%= field.byteLength %> },
|
|
19
|
+
<% } %>
|
|
20
|
+
<% } %>
|
|
21
|
+
] as const;
|
|
22
|
+
|
|
23
|
+
public readonly schema!: {
|
|
24
|
+
<% for (const field of input.fields) { %>
|
|
25
|
+
<% if (field.isArray) { %>
|
|
26
|
+
<%= field.name %>: <%= typedArrayConstructors[field.type].name %>,
|
|
27
|
+
<% } else { %>
|
|
28
|
+
<%= field.name %>: number,
|
|
29
|
+
<% } %>
|
|
30
|
+
<% } %>
|
|
31
|
+
};
|
|
32
|
+
|
|
33
|
+
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
// Generated by @lagless/codegen. Do not edit manually.
|
|
2
|
+
import { InputRegistry } from '@lagless/core';
|
|
3
|
+
|
|
4
|
+
<% for (const input of inputs) { %>import { <%= input.name %> } from './<%= input.name %>.js';<% } %>
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
export const <%= projectName %>InputRegistry = new InputRegistry([
|
|
8
|
+
<% for (const input of inputs) { %><%= input.name %>,<% } %>
|
|
9
|
+
]);
|