pmcf 1.2.2 → 1.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pmcf",
3
- "version": "1.2.2",
3
+ "version": "1.4.0",
4
4
  "publishConfig": {
5
5
  "access": "public"
6
6
  },
@@ -23,21 +23,21 @@
23
23
  "license": "0BSD",
24
24
  "bin": {
25
25
  "pmcf-host-defs": "./bin/pmcf-host-defs",
26
+ "pmcf-info": "./bin/pmcf-info",
26
27
  "pmcf-location-defs": "./bin/pmcf-location-defs",
27
28
  "pmcf-named-defs": "./bin/pmcf-named-defs",
28
- "pmcf-info": "./bin/pmcf-info",
29
29
  "pmcf-network": "./bin/pmcf-network"
30
30
  },
31
31
  "scripts": {
32
32
  "prepare": "node --run prepare:typescript",
33
- "prepare:typescript": "tsc --allowJs --declaration --emitDeclarationOnly --declarationDir types --resolveJsonModule --target es2024 --lib es2024 -m esnext --module nodenext --moduleResolution nodenext --rootDir src ./src**/*.mjs",
33
+ "prepare:typescript": "tsc --allowJs --declaration --emitDeclarationOnly --declarationDir types --resolveJsonModule --target es2024 --lib esnext -m esnext --module nodenext --moduleResolution nodenext --rootDir src ./src**/*.mjs",
34
34
  "test": "node --run test:ava",
35
35
  "test:ava": "ava --timeout 4m tests/*-ava.mjs tests/*-ava-node.mjs",
36
36
  "cover": "c8 -x 'tests/**/*' --temp-directory build/tmp ava --timeout 4m tests/*-ava.mjs tests/*-ava-node.mjs && c8 report -r lcov -o build/coverage --temp-directory build/tmp",
37
37
  "docs": "documentation readme --section=API ./src**/*.mjs",
38
38
  "lint": "node --run lint:docs && node --run lint:typescript",
39
39
  "lint:docs": "documentation lint ./src**/*.mjs",
40
- "lint:typescript": "tsc --allowJs --checkJs --noEmit --resolveJsonModule --target es2024 --lib es2024 -m esnext --module nodenext --moduleResolution nodenext ./src**/*.mjs"
40
+ "lint:typescript": "tsc --allowJs --checkJs --noEmit --resolveJsonModule --target es2024 --lib esnext -m esnext --module nodenext --moduleResolution nodenext ./src**/*.mjs"
41
41
  },
42
42
  "devDependencies": {
43
43
  "@types/node": "^22.10.7",
package/src/model.mjs CHANGED
@@ -18,7 +18,7 @@ export class Base {
18
18
  return "**/" + this.typeFileName;
19
19
  }
20
20
 
21
- static refinedType(data) {
21
+ static async prepareData(world, data) {
22
22
  return this;
23
23
  }
24
24
 
@@ -96,13 +96,12 @@ export class Base {
96
96
  return this.typeName + ":" + this.owner.name + "/" + this.name;
97
97
  }
98
98
 
99
+ get propertyNames() {
100
+ return ["name", "description", "directory", "owner"];
101
+ }
102
+
99
103
  toJSON() {
100
- return {
101
- name: this.name,
102
- directory: this.directory,
103
- owner: this.owner.name,
104
- description: this.description
105
- };
104
+ return extractFrom(this, this.propertyNames);
106
105
  }
107
106
  }
108
107
 
@@ -122,23 +121,35 @@ export class World {
122
121
  return "";
123
122
  }
124
123
 
124
+ async _loadType(name, type) {
125
+ const baseName = type.baseName(name);
126
+
127
+ let object = this.#byName.get(baseName);
128
+
129
+ if (!object) {
130
+ const data = JSON.parse(
131
+ await readFile(
132
+ join(this.directory, baseName, type.typeFileName),
133
+ "utf8"
134
+ )
135
+ );
136
+
137
+ data.name = baseName;
138
+
139
+ type = await type.prepareData(this, data);
140
+ object = new type(this, data);
141
+ this.#byName.set(data.name, object);
142
+ }
143
+
144
+ return object;
145
+ }
146
+
125
147
  async load() {
126
148
  for (let type of Object.values(World.types)) {
127
149
  for await (const name of glob(type.fileNameGlob, {
128
150
  cwd: this.directory
129
151
  })) {
130
- const baseName = type.baseName(name);
131
- if (!this.#byName.get(baseName)) {
132
- const data = JSON.parse(
133
- await readFile(join(this.directory, name), "utf8")
134
- );
135
-
136
- data.name = baseName;
137
-
138
- type = type.refinedType(data);
139
- const object = new type(this, data);
140
- this.#byName.set(data.name, object);
141
- }
152
+ await this._loadType(name, type);
142
153
  }
143
154
  }
144
155
  }
@@ -175,34 +186,11 @@ export class World {
175
186
  }
176
187
 
177
188
  async location(name) {
178
- await this.load();
179
- return this.#byName.get(Location.baseName(name));
189
+ return this._loadType(name, Location);
180
190
  }
181
191
 
182
192
  async host(name) {
183
- await this.load();
184
- return this.#byName.get(Host.baseName(name));
185
- /*
186
- if (!data.name) {
187
- data.name = name;
188
- } else {
189
- name = data.name;
190
- }
191
-
192
- if (!data.location) {
193
- const parts = name.split(/\//);
194
-
195
- if (parts.length > 1 && parts[0] !== "services" && parts[0] !== "model") {
196
- data.location = parts[0];
197
- }
198
- }
199
-
200
- data.location = await this.location(data.location);
201
-
202
- if (data.extends) {
203
- data.extends = await Promise.all(data.extends.map(e => this.host(e)));
204
- }
205
- */
193
+ return this._loadType(name, Host);
206
194
  }
207
195
 
208
196
  async *subnets() {
@@ -238,7 +226,15 @@ export class Host extends Base {
238
226
  return "host";
239
227
  }
240
228
 
241
- static refinedType(data) {
229
+ static async prepareData(world, data) {
230
+ if (data.location) {
231
+ data.location = await world.location(data.location);
232
+ }
233
+
234
+ if (data.extends) {
235
+ data.extends = await Promise.all(data.extends.map(e => world.host(e)));
236
+ }
237
+
242
238
  if (data.name?.indexOf("model/") >= 0) {
243
239
  return Model;
244
240
  }
@@ -388,24 +384,24 @@ export class Host extends Base {
388
384
  return readFile(join(this.directory, `ssh_host_${type}_key.pub`), "utf8");
389
385
  }
390
386
 
387
+ get propertyNames() {
388
+ return [
389
+ ...super.propertyNames,
390
+ "os",
391
+ "distribution",
392
+ "deployment",
393
+ "master",
394
+ "location",
395
+ "model",
396
+ "replaces",
397
+ "depends",
398
+ "networkInterfaces"
399
+ ];
400
+ }
401
+
391
402
  toJSON() {
392
403
  return {
393
404
  ...super.toJSON(),
394
- ...Object.fromEntries(
395
- [
396
- "location",
397
- "model",
398
- "os",
399
- "distribution",
400
- "deployment",
401
- "replaces",
402
- "depends",
403
- "master",
404
- "networkInterfaces"
405
- ]
406
- .filter(p => this[p])
407
- .map(p => [p, this[p]])
408
- ),
409
405
  extends: this.extends.map(host => host.name),
410
406
  services: Object.fromEntries(
411
407
  Object.values(this.services).map(s => [s.name, s.toJSON()])
@@ -574,10 +570,13 @@ export class Location extends Base {
574
570
  return this.#administratorEmail || "admin@" + this.domain;
575
571
  }
576
572
 
573
+ get propertyNames() {
574
+ return [...super.propertyNames, "domain"];
575
+ }
576
+
577
577
  toJSON() {
578
578
  return {
579
579
  ...super.toJSON(),
580
- domain: this.domain,
581
580
  hosts: [...this.#hosts.keys()].sort()
582
581
  };
583
582
  }
@@ -627,14 +626,8 @@ export class Network extends Base {
627
626
  this.#hosts.set(host.name, host);
628
627
  }
629
628
 
630
- toJSON() {
631
- return {
632
- ...super.toJSON(),
633
- kind: this.kind,
634
- ipv4: this.ipv4,
635
- scope: this.scope,
636
- metric: this.metric
637
- };
629
+ get propertyNames() {
630
+ return [...super.propertyNames, "kind", "ipv4", "scope", "metric"];
638
631
  }
639
632
  }
640
633
 
@@ -734,16 +727,16 @@ export class Service extends Base {
734
727
  return this.#type || this.name;
735
728
  }
736
729
 
737
- toJSON() {
738
- return {
739
- ...super.toJSON(),
740
- ipAddress: this.ipAddress,
741
- alias: this.alias,
742
- type: this.type,
743
- master: this.master,
744
- priority: this.priority,
745
- weight: this.weight
746
- };
730
+ get propertyNames() {
731
+ return [
732
+ ...super.propertyNames,
733
+ "ipAddress",
734
+ "alias",
735
+ "type",
736
+ "master",
737
+ "priority",
738
+ "weight"
739
+ ];
747
740
  }
748
741
  }
749
742
 
@@ -776,3 +769,14 @@ export function sectionLines(sectionName, values) {
776
769
 
777
770
  return lines;
778
771
  }
772
+
773
+ function extractFrom(object, propertyNames) {
774
+ const json = {};
775
+ for (const p of propertyNames) {
776
+ const value = object[p];
777
+ if (value !== undefined) {
778
+ json[p] = value;
779
+ }
780
+ }
781
+ return json;
782
+ }
package/types/model.d.mts CHANGED
@@ -4,7 +4,7 @@ export class Base {
4
4
  static get typeName(): string;
5
5
  static get typeFileName(): string;
6
6
  static get fileNameGlob(): string;
7
- static refinedType(data: any): typeof Base;
7
+ static prepareData(world: any, data: any): Promise<typeof Base>;
8
8
  static baseName(name: any): any;
9
9
  constructor(owner: any, data: any);
10
10
  owner: any;
@@ -17,12 +17,8 @@ export class Base {
17
17
  get directory(): any;
18
18
  expand(object: any): any;
19
19
  toString(): string;
20
- toJSON(): {
21
- name: any;
22
- directory: any;
23
- owner: any;
24
- description: any;
25
- };
20
+ get propertyNames(): string[];
21
+ toJSON(): {};
26
22
  #private;
27
23
  }
28
24
  export class World {
@@ -32,6 +28,7 @@ export class World {
32
28
  constructor(directory: any);
33
29
  directory: any;
34
30
  get name(): string;
31
+ _loadType(name: any, type: any): Promise<any>;
35
32
  load(): Promise<void>;
36
33
  named(name: any): Promise<any>;
37
34
  locations(): AsyncGenerator<Location, void, unknown>;
@@ -47,7 +44,7 @@ export class World {
47
44
  #private;
48
45
  }
49
46
  export class Host extends Base {
50
- static refinedType(data: any): typeof Host;
47
+ static prepareData(world: any, data: any): Promise<typeof Host>;
51
48
  networkInterfaces: {};
52
49
  services: {};
53
50
  postinstall: any[];
@@ -75,10 +72,6 @@ export class Host extends Base {
75
72
  toJSON(): {
76
73
  extends: any[];
77
74
  services: any;
78
- name: any;
79
- directory: any;
80
- owner: any;
81
- description: any;
82
75
  };
83
76
  #private;
84
77
  }
@@ -101,12 +94,7 @@ export class Location extends Base {
101
94
  get dnsRecordTTL(): any;
102
95
  get administratorEmail(): any;
103
96
  toJSON(): {
104
- domain: any;
105
97
  hosts: any[];
106
- name: any;
107
- directory: any;
108
- owner: any;
109
- description: any;
110
98
  };
111
99
  #private;
112
100
  }
@@ -120,16 +108,6 @@ export class Network extends Base {
120
108
  get subnetAddress(): any;
121
109
  hosts(): AsyncGenerator<any, void, unknown>;
122
110
  addHost(host: any): void;
123
- toJSON(): {
124
- kind: any;
125
- ipv4: any;
126
- scope: any;
127
- metric: any;
128
- name: any;
129
- directory: any;
130
- owner: any;
131
- description: any;
132
- };
133
111
  #private;
134
112
  }
135
113
  export class Subnet extends Base {
@@ -145,17 +123,5 @@ export class Service extends Base {
145
123
  get weight(): any;
146
124
  get master(): any;
147
125
  get type(): any;
148
- toJSON(): {
149
- ipAddress: any;
150
- alias: any;
151
- type: any;
152
- master: any;
153
- priority: any;
154
- weight: any;
155
- name: any;
156
- directory: any;
157
- owner: any;
158
- description: any;
159
- };
160
126
  #private;
161
127
  }