@metaverse-systems/the-seed 1.0.4 → 1.2.1

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 (56) hide show
  1. package/.eslintrc.json +1 -0
  2. package/.vscode/settings.json +14 -0
  3. package/README.md +530 -0
  4. package/dist/Build.d.ts +10 -0
  5. package/dist/Build.js +59 -16
  6. package/dist/Build.js.map +1 -1
  7. package/dist/Config.d.ts +1 -1
  8. package/dist/Config.js +2 -4
  9. package/dist/Config.js.map +1 -1
  10. package/dist/Dependencies.d.ts +14 -0
  11. package/dist/Dependencies.js +104 -0
  12. package/dist/Dependencies.js.map +1 -0
  13. package/dist/Package.d.ts +45 -0
  14. package/dist/Package.js +249 -0
  15. package/dist/Package.js.map +1 -0
  16. package/dist/ResourcePak.d.ts +2 -2
  17. package/dist/ResourcePak.js +19 -18
  18. package/dist/ResourcePak.js.map +1 -1
  19. package/dist/Scopes.d.ts +9 -6
  20. package/dist/Scopes.js.map +1 -1
  21. package/dist/Template.d.ts +2 -1
  22. package/dist/Template.js +18 -16
  23. package/dist/Template.js.map +1 -1
  24. package/dist/index.d.ts +4 -2
  25. package/dist/index.js +5 -1
  26. package/dist/index.js.map +1 -1
  27. package/dist/scripts/DependenciesCLI.d.ts +3 -0
  28. package/dist/scripts/DependenciesCLI.js +58 -0
  29. package/dist/scripts/DependenciesCLI.js.map +1 -0
  30. package/dist/scripts/PackageCLI.d.ts +3 -0
  31. package/dist/scripts/PackageCLI.js +38 -0
  32. package/dist/scripts/PackageCLI.js.map +1 -0
  33. package/dist/scripts/the-seed.js +13 -0
  34. package/dist/scripts/the-seed.js.map +1 -1
  35. package/dist/types.d.ts +27 -3
  36. package/native/binding.gyp +20 -0
  37. package/native/src/addon.cpp +60 -0
  38. package/package.json +4 -1
  39. package/src/Build.ts +71 -17
  40. package/src/Config.ts +3 -5
  41. package/src/Dependencies.ts +107 -0
  42. package/src/Package.ts +287 -0
  43. package/src/ResourcePak.ts +12 -11
  44. package/src/Scopes.ts +4 -4
  45. package/src/Template.ts +10 -9
  46. package/src/index.ts +13 -2
  47. package/src/scripts/DependenciesCLI.ts +57 -0
  48. package/src/scripts/PackageCLI.ts +42 -0
  49. package/src/scripts/the-seed.ts +13 -0
  50. package/src/types.ts +29 -3
  51. package/test/Build.test.ts +223 -0
  52. package/test/Config.test.ts +1 -1
  53. package/test/Dependencies.test.ts +153 -0
  54. package/test/Package.test.ts +631 -0
  55. package/test/ResourcePak.test.ts +106 -24
  56. package/test/Template.test.ts +187 -0
@@ -17,12 +17,16 @@ describe("ResourcePak", () => {
17
17
  beforeEach(() => {
18
18
  tempDir = createTempDir();
19
19
  const defaultConfig = {
20
- prefix: tempDir, // or any other default values your Config expects
21
- scopes: {}
20
+ prefix: tempDir,
21
+ scopes: {
22
+ "@test": {
23
+ author: { name: "Test Author", email: "test@test.com", url: "" }
24
+ }
25
+ }
22
26
  };
23
27
  fs.writeFileSync(path.join(tempDir, 'config.json'), JSON.stringify(defaultConfig));
24
28
  config = new Config(tempDir);
25
- rp = new ResourcePak(config, tempDir);
29
+ rp = new ResourcePak(config);
26
30
  });
27
31
 
28
32
  afterEach(() => {
@@ -30,40 +34,118 @@ describe("ResourcePak", () => {
30
34
  });
31
35
 
32
36
  it("should create a new package", () => {
33
- const packageName = "@test/package";
34
- rp.create(packageName);
37
+ rp.createPackage("@test", "my-pak");
35
38
  expect(rp.package).toBeDefined();
36
- expect(rp.package?.name).toBe(packageName);
37
- // Add more assertions as necessary
39
+ expect(rp.package?.name).toBe("@test/my-pak");
40
+ expect(rp.package?.resources).toEqual([]);
41
+ expect(rp.packageDir).toBe(path.join(tempDir, "projects", "@test", "my-pak"));
42
+ expect(fs.existsSync(rp.packageDir)).toBe(true);
43
+ expect(fs.existsSync(path.join(rp.packageDir, "package.json"))).toBe(true);
38
44
  });
39
45
 
40
- it("should add a resource", () => {
41
- const packageName = "@test/package";
42
- rp.create(packageName);
46
+ it("should add a resource using process.cwd() by default", () => {
47
+ rp.createPackage("@test", "my-pak");
48
+ const pakDir = rp.packageDir;
43
49
 
44
- const resourceName = "testResource";
50
+ // Create a dummy resource file in the pak directory
45
51
  const fileName = "testFile.txt";
46
- // Creating a dummy file to add
47
- const filePath = path.join(tempDir, fileName);
52
+ const filePath = path.join(pakDir, fileName);
48
53
  fs.writeFileSync(filePath, "Dummy content");
49
- rp.addResource(resourceName, filePath);
54
+
55
+ // Use the packageDir parameter (since process.cwd() won't match pakDir in tests)
56
+ rp.addResource("testResource", fileName, pakDir);
50
57
 
51
58
  expect(rp.package?.resources).toContainEqual(expect.objectContaining({
52
- name: resourceName,
53
- filename: tempDir + "/" + fileName,
54
- // size: depends on the content written
59
+ name: "testResource",
60
+ filename: fileName,
55
61
  }));
56
- // Add more assertions as necessary
62
+ expect(rp.package!.resources!.length).toBe(1);
63
+ });
64
+
65
+ it("should add a resource with explicit packageDir parameter", () => {
66
+ rp.createPackage("@test", "my-pak");
67
+ const pakDir = rp.packageDir;
68
+
69
+ const fileName = "asset.png";
70
+ const filePath = path.join(pakDir, fileName);
71
+ fs.writeFileSync(filePath, "PNG data");
72
+
73
+ rp.addResource("myAsset", fileName, pakDir);
74
+
75
+ const savedPkg = JSON.parse(fs.readFileSync(path.join(pakDir, "package.json")).toString());
76
+ expect(savedPkg.resources).toHaveLength(1);
77
+ expect(savedPkg.resources[0].name).toBe("myAsset");
78
+ expect(savedPkg.resources[0].filename).toBe(fileName);
79
+ expect(savedPkg.resources[0].size).toBeGreaterThan(0);
80
+ });
81
+
82
+ it("should not add a duplicate resource name", () => {
83
+ rp.createPackage("@test", "my-pak");
84
+ const pakDir = rp.packageDir;
85
+
86
+ const file1 = path.join(pakDir, "file1.txt");
87
+ const file2 = path.join(pakDir, "file2.txt");
88
+ fs.writeFileSync(file1, "content1");
89
+ fs.writeFileSync(file2, "content2");
90
+
91
+ rp.addResource("dup", "file1.txt", pakDir);
92
+ rp.addResource("dup", "file2.txt", pakDir);
93
+
94
+ const savedPkg = JSON.parse(fs.readFileSync(path.join(pakDir, "package.json")).toString());
95
+ expect(savedPkg.resources).toHaveLength(1);
96
+ expect(savedPkg.resources[0].filename).toBe("file1.txt");
57
97
  });
58
98
 
59
99
  it("should save package configuration", () => {
60
- const packageName = "@test/package";
61
- rp.create(packageName);
62
- rp.savePackage();
63
- const packageJsonPath = path.join(tempDir, "package.json");
100
+ rp.createPackage("@test", "my-pak");
101
+ rp.save();
102
+ const packageJsonPath = path.join(rp.packageDir, "package.json");
64
103
  expect(fs.existsSync(packageJsonPath)).toBe(true);
65
- // Further assertions on the contents of package.json can be added
104
+ const saved = JSON.parse(fs.readFileSync(packageJsonPath).toString());
105
+ expect(saved.name).toBe("@test/my-pak");
66
106
  });
67
107
 
68
- // Add more tests for other methods, e.g., build(), as needed.
108
+ it("should build a .pak file with explicit packageDir", () => {
109
+ rp.createPackage("@test", "my-pak");
110
+ const pakDir = rp.packageDir;
111
+
112
+ // Add two resources
113
+ const file1 = path.join(pakDir, "res1.txt");
114
+ const file2 = path.join(pakDir, "res2.dat");
115
+ fs.writeFileSync(file1, "Hello resource 1");
116
+ fs.writeFileSync(file2, "Resource 2 data");
117
+
118
+ rp.addResource("resource1", "res1.txt", pakDir);
119
+ rp.addResource("resource2", "res2.dat", pakDir);
120
+
121
+ // Build with explicit packageDir
122
+ rp.build(pakDir);
123
+
124
+ const pakFile = path.join(pakDir, "my-pak.pak");
125
+ expect(fs.existsSync(pakFile)).toBe(true);
126
+
127
+ // Verify the .pak starts with a 10-digit header size
128
+ const content = fs.readFileSync(pakFile).toString();
129
+ const headerSizeStr = content.substring(0, 10);
130
+ expect(headerSizeStr).toMatch(/^\d{10}$/);
131
+ });
132
+
133
+ it("should build using packageDir parameter instead of cwd", () => {
134
+ rp.createPackage("@test", "build-test");
135
+ const pakDir = rp.packageDir;
136
+
137
+ const file = path.join(pakDir, "data.bin");
138
+ fs.writeFileSync(file, "binary data");
139
+ rp.addResource("data", "data.bin", pakDir);
140
+
141
+ // Build with explicit pakDir (not relying on process.cwd())
142
+ rp.build(pakDir);
143
+
144
+ const pakFile = path.join(pakDir, "build-test.pak");
145
+ expect(fs.existsSync(pakFile)).toBe(true);
146
+
147
+ // Read the pak and verify it contains header JSON + resource data
148
+ const pakContent = fs.readFileSync(pakFile);
149
+ expect(pakContent.length).toBeGreaterThan(11); // header size + newline + content
150
+ });
69
151
  });
@@ -0,0 +1,187 @@
1
+ import fs from "fs";
2
+ import path from "path";
3
+ import os from "os";
4
+ import Config from "../src/Config";
5
+ import Template from "../src/Template";
6
+
7
+ jest.mock("child_process", () => ({
8
+ execSync: jest.fn()
9
+ }));
10
+
11
+ function createTempDir(): string {
12
+ return fs.mkdtempSync(path.join(os.tmpdir(), "template-test-"));
13
+ }
14
+
15
+ describe("test Template", () => {
16
+ let configDir: string;
17
+ let config: Config;
18
+ let template: Template;
19
+
20
+ beforeAll(() => {
21
+ configDir = createTempDir();
22
+ config = new Config(configDir);
23
+
24
+ // Create a scope for testing
25
+ const scopes = config.config.scopes;
26
+ scopes["@test-scope"] = {
27
+ author: {
28
+ name: "Test Author",
29
+ email: "test@example.com",
30
+ url: "https://example.com"
31
+ }
32
+ };
33
+ config.saveConfig();
34
+ });
35
+
36
+ beforeEach(() => {
37
+ template = new Template(config);
38
+ });
39
+
40
+ afterAll(() => {
41
+ fs.rmSync(configDir, { recursive: true });
42
+ });
43
+
44
+ describe("askName", () => {
45
+ it("returns questions with scope list and name input", () => {
46
+ template.type = "component";
47
+ const questions = template.askName();
48
+
49
+ expect(questions).toHaveLength(2);
50
+ expect(questions[0].type).toBe("list");
51
+ expect(questions[0].name).toBe("scopeName");
52
+ expect(questions[0].choices).toContain("@test-scope");
53
+ expect(questions[1].name).toBe("templateName");
54
+ });
55
+ });
56
+
57
+ describe("copyTemplate", () => {
58
+ let targetDir: string;
59
+
60
+ beforeEach(() => {
61
+ targetDir = createTempDir();
62
+ // Set prefix so scopeDir can be created
63
+ config.config.prefix = targetDir;
64
+ config.saveConfig();
65
+ });
66
+
67
+ afterEach(() => {
68
+ fs.rmSync(targetDir, { recursive: true });
69
+ });
70
+
71
+ it("copies component template and substitutes SKELETON variables", () => {
72
+ template.type = "component";
73
+ template.packageDir = path.join(targetDir, "my-component");
74
+ fs.mkdirSync(template.packageDir, { recursive: true });
75
+
76
+ // The actual template directory relative to the source
77
+ const templateDir = path.join(__dirname, "..", "templates", "component");
78
+
79
+ // Copy template manually (since require.main won't work in tests)
80
+ const fsExtra = jest.requireActual("fs-extra");
81
+ fsExtra.copySync(templateDir, template.packageDir);
82
+
83
+ // Now run the variable substitution part by calling copyTemplate
84
+ // We need to mock the copySync and path resolution inside copyTemplate
85
+ // Instead, let's test the file content after manual copy + variable substitution
86
+ const projectName = "my-component";
87
+ const underscoreName = "my_component";
88
+
89
+ const variables: { [key: string]: string } = {
90
+ "AUTHOR_EMAIL": "test@example.com",
91
+ "AUTHOR_URL": "https://example.com",
92
+ "SKELETON_": underscoreName,
93
+ "SKELETON": projectName
94
+ };
95
+
96
+ const files = [
97
+ "AUTHORS",
98
+ "COPYING",
99
+ "configure.ac",
100
+ "Makefile.am",
101
+ "src/Makefile.am",
102
+ "src/SKELETON.hpp",
103
+ "src/SKELETON.cpp",
104
+ "SKELETON.pc.in"
105
+ ];
106
+
107
+ files.forEach((file) => {
108
+ let temp = fs.readFileSync(template.packageDir + "/" + file).toString();
109
+ Object.keys(variables).forEach((variable) => {
110
+ const regex = new RegExp(variable, "g");
111
+ temp = temp.replace(regex, variables[variable]);
112
+ });
113
+ fs.writeFileSync(template.packageDir + "/" + file, temp);
114
+ });
115
+
116
+ fs.renameSync(template.packageDir + "/src/SKELETON.hpp", template.packageDir + "/src/" + projectName + ".hpp");
117
+ fs.renameSync(template.packageDir + "/src/SKELETON.cpp", template.packageDir + "/src/" + projectName + ".cpp");
118
+ fs.renameSync(template.packageDir + "/SKELETON.pc.in", template.packageDir + "/" + projectName + ".pc.in");
119
+
120
+ // Verify SKELETON replaced
121
+ const configureAc = fs.readFileSync(path.join(template.packageDir, "configure.ac")).toString();
122
+ expect(configureAc).toContain(projectName);
123
+ expect(configureAc).not.toContain("SKELETON");
124
+
125
+ // Verify files renamed
126
+ expect(fs.existsSync(path.join(template.packageDir, "src", projectName + ".hpp"))).toBe(true);
127
+ expect(fs.existsSync(path.join(template.packageDir, "src", projectName + ".cpp"))).toBe(true);
128
+ expect(fs.existsSync(path.join(template.packageDir, projectName + ".pc.in"))).toBe(true);
129
+
130
+ // Verify SKELETON files no longer exist
131
+ expect(fs.existsSync(path.join(template.packageDir, "src", "SKELETON.hpp"))).toBe(false);
132
+ expect(fs.existsSync(path.join(template.packageDir, "src", "SKELETON.cpp"))).toBe(false);
133
+ });
134
+
135
+ it("copies system template with .pc.in file", () => {
136
+ template.type = "system";
137
+ template.packageDir = path.join(targetDir, "my-system");
138
+
139
+ const templateDir = path.join(__dirname, "..", "templates", "system");
140
+ const fsExtra = jest.requireActual("fs-extra");
141
+ fsExtra.copySync(templateDir, template.packageDir);
142
+
143
+ // Verify .pc.in template file exists (system has one)
144
+ expect(fs.existsSync(path.join(template.packageDir, "SKELETON.pc.in"))).toBe(true);
145
+ });
146
+
147
+ it("copies program template without .pc.in file", () => {
148
+ template.type = "program";
149
+ template.packageDir = path.join(targetDir, "my-program");
150
+
151
+ const templateDir = path.join(__dirname, "..", "templates", "program");
152
+ const fsExtra = jest.requireActual("fs-extra");
153
+ fsExtra.copySync(templateDir, template.packageDir);
154
+
155
+ // Program template does not have a .pc.in file
156
+ expect(fs.existsSync(path.join(template.packageDir, "SKELETON.pc.in"))).toBe(false);
157
+ });
158
+ });
159
+
160
+ describe("variable substitution", () => {
161
+ it("replaces both SKELETON_ (underscore) and SKELETON variants", () => {
162
+ const tmpDir = createTempDir();
163
+ const testFile = path.join(tmpDir, "test.txt");
164
+ fs.writeFileSync(testFile, "SKELETON_ and SKELETON are placeholders");
165
+
166
+ const projectName = "my-project";
167
+ const underscoreName = "my_project";
168
+
169
+ const variables: { [key: string]: string } = {
170
+ "SKELETON_": underscoreName,
171
+ "SKELETON": projectName
172
+ };
173
+
174
+ let content = fs.readFileSync(testFile).toString();
175
+ Object.keys(variables).forEach((variable) => {
176
+ const regex = new RegExp(variable, "g");
177
+ content = content.replace(regex, variables[variable]);
178
+ });
179
+
180
+ expect(content).toContain(underscoreName);
181
+ expect(content).toContain(projectName);
182
+ expect(content).not.toContain("SKELETON");
183
+
184
+ fs.rmSync(tmpDir, { recursive: true });
185
+ });
186
+ });
187
+ });