@open-audio-stack/core 0.1.7 → 0.1.9

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.
@@ -4,6 +4,8 @@ export declare class ConfigLocal extends Config {
4
4
  path: string;
5
5
  constructor(configPath: string, config?: ConfigInterface);
6
6
  delete(): boolean | void;
7
+ export(dir: string, ext?: string): boolean;
8
+ exportConfig(dirRoot: string, items: any, ext?: string): void;
7
9
  load(): ConfigInterface;
8
10
  save(): void;
9
11
  set(key: keyof ConfigInterface, val: any): void;
@@ -1,6 +1,6 @@
1
1
  import path from 'path';
2
2
  import { Config } from './Config.js';
3
- import { dirCreate, fileCreateJson, fileDelete, fileExists, fileReadJson } from '../helpers/file.js';
3
+ import { dirCreate, fileCreateJson, fileCreateYaml, fileDelete, fileExists, fileReadJson } from '../helpers/file.js';
4
4
  import { configDefaultsLocal } from '../helpers/configLocal.js';
5
5
  export class ConfigLocal extends Config {
6
6
  path;
@@ -18,6 +18,29 @@ export class ConfigLocal extends Config {
18
18
  delete() {
19
19
  return fileDelete(this.path);
20
20
  }
21
+ export(dir, ext = 'json') {
22
+ // TODO improve the way this is handled.
23
+ this.exportConfig(path.join(dir, 'architectures'), this.architectures(), ext);
24
+ this.exportConfig(path.join(dir, 'file-formats'), this.fileFormats(), ext);
25
+ this.exportConfig(path.join(dir, 'file-types'), this.fileTypes(), ext);
26
+ this.exportConfig(path.join(dir, 'licenses'), this.licenses(), ext);
27
+ this.exportConfig(path.join(dir, 'plugin-formats'), this.pluginFormats(), ext);
28
+ this.exportConfig(path.join(dir, 'plugin-types'), this.pluginTypes(), ext);
29
+ this.exportConfig(path.join(dir, 'preset-formats'), this.presetFormats(), ext);
30
+ this.exportConfig(path.join(dir, 'preset-types'), this.presetTypes(), ext);
31
+ this.exportConfig(path.join(dir, 'project-formats'), this.projectFormats(), ext);
32
+ this.exportConfig(path.join(dir, 'project-types'), this.projectTypes(), ext);
33
+ this.exportConfig(path.join(dir, 'systems'), this.systems(), ext);
34
+ return true;
35
+ }
36
+ exportConfig(dirRoot, items, ext = 'json') {
37
+ const saveFile = ext === 'yaml' ? fileCreateYaml : fileCreateJson;
38
+ items.forEach((item) => {
39
+ dirCreate(path.join(dirRoot, item.value));
40
+ saveFile(path.join(dirRoot, item.value, `index.${ext}`), item);
41
+ });
42
+ saveFile(path.join(dirRoot, `index.${ext}`), items);
43
+ }
21
44
  load() {
22
45
  return fileReadJson(this.path);
23
46
  }
@@ -11,6 +11,7 @@ export declare class Manager {
11
11
  addPackage(pkg: Package): void;
12
12
  filter(method: (pkgVersion: PackageVersion, pkg: Package) => boolean): Package[];
13
13
  getPackage(slug: string): Package | undefined;
14
+ getReport(): any;
14
15
  listPackages(): Package[];
15
16
  removePackage(slug: string): void;
16
17
  reset(): void;
@@ -11,14 +11,13 @@ export class Manager {
11
11
  this.type = type;
12
12
  }
13
13
  addPackage(pkg) {
14
- const pkgExisting = this.packages.get(pkg.slug);
15
- if (pkgExisting) {
16
- for (const [version, pkgVersion] of pkg.versions) {
17
- pkgExisting.addVersion(version, pkgVersion);
18
- }
14
+ let pkgExisting = this.packages.get(pkg.slug);
15
+ if (!pkgExisting) {
16
+ pkgExisting = new Package(pkg.slug);
17
+ this.packages.set(pkg.slug, pkgExisting);
19
18
  }
20
- else {
21
- this.packages.set(pkg.slug, pkg);
19
+ for (const [version, pkgVersion] of pkg.versions) {
20
+ pkgExisting.addVersion(version, pkgVersion);
22
21
  }
23
22
  }
24
23
  filter(method) {
@@ -34,6 +33,15 @@ export class Manager {
34
33
  getPackage(slug) {
35
34
  return this.packages.get(slug);
36
35
  }
36
+ getReport() {
37
+ const reports = {};
38
+ for (const [slug, pkg] of this.packages) {
39
+ const report = pkg.getReport();
40
+ if (Object.keys(report).length)
41
+ reports[slug] = report;
42
+ }
43
+ return reports;
44
+ }
37
45
  listPackages() {
38
46
  return Array.from(this.packages.values());
39
47
  }
@@ -6,6 +6,7 @@ export declare class ManagerLocal extends Manager {
6
6
  protected typeDir: string;
7
7
  constructor(type: RegistryType, config: ConfigInterface);
8
8
  scan(ext?: string): void;
9
+ export(dir: string, ext?: string): boolean;
9
10
  install(slug: string, version?: string): Promise<void | PackageVersion>;
10
11
  uninstall(slug: string, version?: string): Promise<void | PackageVersion>;
11
12
  }
@@ -1,7 +1,7 @@
1
1
  import path from 'path';
2
2
  import { Package } from './Package.js';
3
3
  import { Manager } from './Manager.js';
4
- import { archiveExtract, dirCreate, dirDelete, dirEmpty, dirRead, fileCreate, fileCreateJson, fileExists, fileHash, fileOpen, fileReadJson, filesMove, isAdmin, runCliAsAdmin, } from '../helpers/file.js';
4
+ import { archiveExtract, dirCreate, dirDelete, dirEmpty, dirRead, fileCreate, fileCreateJson, fileCreateYaml, fileExists, fileHash, fileOpen, fileReadJson, fileReadYaml, filesMove, isAdmin, runCliAsAdmin, } from '../helpers/file.js';
5
5
  import { pathGetSlug, pathGetVersion } from '../helpers/utils.js';
6
6
  import { commandExists, getArchitecture, getSystem, isTests } from '../helpers/utilsLocal.js';
7
7
  import { apiBuffer } from '../helpers/api.js';
@@ -25,13 +25,39 @@ export class ManagerLocal extends Manager {
25
25
  const filePaths = dirRead(`${this.typeDir}/**/index.${ext}`);
26
26
  filePaths.forEach((filePath) => {
27
27
  const subPath = filePath.replace(`${this.typeDir}/`, '');
28
- const pkgJson = fileReadJson(filePath);
28
+ const pkgJson = ext === 'yaml' ? fileReadYaml(filePath) : fileReadJson(filePath);
29
29
  pkgJson.installed = true;
30
30
  const pkg = new Package(pathGetSlug(subPath));
31
- pkg.addVersion(pathGetVersion(subPath), pkgJson);
31
+ const version = pathGetVersion(subPath);
32
+ pkg.addVersion(version, pkgJson);
32
33
  this.addPackage(pkg);
33
34
  });
34
35
  }
36
+ export(dir, ext = 'json') {
37
+ const packagesByOrg = {};
38
+ const filename = `index.${ext}`;
39
+ const saveFile = ext === 'yaml' ? fileCreateYaml : fileCreateJson;
40
+ for (const [pkgSlug, pkg] of this.packages) {
41
+ for (const [version, pkgVersion] of pkg.versions) {
42
+ dirCreate(path.join(dir, pkgSlug, version));
43
+ saveFile(path.join(dir, pkgSlug, version, filename), pkgVersion);
44
+ }
45
+ saveFile(path.join(dir, pkgSlug, filename), pkg.toJSON());
46
+ // TODO find a more elegant way to handle org exports.
47
+ const pkgOrg = pkgSlug.split('/')[0];
48
+ if (!packagesByOrg[pkgOrg])
49
+ packagesByOrg[pkgOrg] = {};
50
+ packagesByOrg[pkgOrg][pkgSlug] = pkg.toJSON();
51
+ }
52
+ for (const orgId in packagesByOrg) {
53
+ dirCreate(path.join(dir, orgId));
54
+ saveFile(path.join(dir, orgId, filename), packagesByOrg[orgId]);
55
+ }
56
+ dirCreate(dir);
57
+ saveFile(path.join(dir, filename), this.toJSON());
58
+ saveFile(path.join(dir, `report.${ext}`), this.getReport());
59
+ return true;
60
+ }
35
61
  async install(slug, version) {
36
62
  // Get package information from registry.
37
63
  const pkg = this.getPackage(slug);
@@ -1,13 +1,23 @@
1
- import { PackageInterface, PackageVersion, PackageVersions } from '../types/Package.js';
1
+ import { PackageReport, PackageVersion, PackageVersions } from '../types/Package.js';
2
2
  export declare class Package {
3
+ reports: Map<string, PackageReport>;
3
4
  slug: string;
4
5
  version: string;
5
6
  versions: Map<string, PackageVersion>;
6
7
  constructor(slug: string, versions?: PackageVersions);
7
8
  addVersion(version: string, details: PackageVersion): void;
8
9
  removeVersion(version: string): void;
10
+ getReport(): {
11
+ [k: string]: PackageReport;
12
+ };
9
13
  getVersion(version: string): PackageVersion | undefined;
10
14
  getVersionLatest(): PackageVersion | undefined;
11
15
  latestVersion(): string;
12
- toJSON(): PackageInterface;
16
+ toJSON(): {
17
+ slug: string;
18
+ version: string;
19
+ versions: {
20
+ [k: string]: PackageVersion;
21
+ };
22
+ };
13
23
  }
@@ -1,13 +1,15 @@
1
1
  import * as semver from 'semver';
2
- import { PackageVersionValidator } from '../helpers/package.js';
2
+ import { packageErrors, packageRecommendations } from '../helpers/package.js';
3
3
  import { isValidSlug } from '../helpers/utils.js';
4
4
  export class Package {
5
+ reports;
5
6
  slug;
6
7
  version;
7
8
  versions;
8
9
  constructor(slug, versions) {
9
10
  if (!isValidSlug(slug))
10
11
  console.error('Invalid package slug', slug);
12
+ this.reports = new Map();
11
13
  this.slug = slug;
12
14
  this.versions = versions ? new Map(Object.entries(versions)) : new Map();
13
15
  this.version = this.latestVersion();
@@ -15,9 +17,16 @@ export class Package {
15
17
  addVersion(version, details) {
16
18
  if (this.versions.has(version))
17
19
  return;
18
- const validationError = PackageVersionValidator.safeParse(details).error;
19
- if (validationError)
20
- return console.error('Invalid package version', validationError.issues);
20
+ const errors = packageErrors(details);
21
+ const recs = packageRecommendations(details);
22
+ const report = {
23
+ ...(errors.length > 0 && { errors }),
24
+ ...(recs.length > 0 && { recs }),
25
+ };
26
+ if (Object.keys(report).length > 0)
27
+ this.reports.set(version, report);
28
+ if (errors.length > 0)
29
+ return;
21
30
  this.versions.set(version, details);
22
31
  this.version = this.latestVersion();
23
32
  }
@@ -27,6 +36,9 @@ export class Package {
27
36
  this.versions.delete(version);
28
37
  this.version = this.latestVersion();
29
38
  }
39
+ getReport() {
40
+ return Object.fromEntries(this.reports);
41
+ }
30
42
  getVersion(version) {
31
43
  return this.versions.get(version);
32
44
  }
@@ -37,14 +49,10 @@ export class Package {
37
49
  return Array.from(this.versions.keys()).sort(semver.rcompare)[0] || '0.0.0';
38
50
  }
39
51
  toJSON() {
40
- const data = {
52
+ return {
41
53
  slug: this.slug,
42
54
  version: this.version,
43
- versions: {},
55
+ versions: Object.fromEntries(this.versions),
44
56
  };
45
- this.versions.forEach((details, version) => {
46
- data.versions[version] = details;
47
- });
48
- return data;
49
57
  }
50
58
  }
@@ -3,5 +3,6 @@ import { Registry } from './Registry.js';
3
3
  export declare class RegistryLocal extends Registry {
4
4
  protected managers: Record<string, ManagerLocal>;
5
5
  constructor(name: string, url: string, version: string);
6
+ export(dir: string, ext?: string): boolean;
6
7
  scan(ext?: string): void;
7
8
  }
@@ -1,10 +1,21 @@
1
+ import path from 'path';
1
2
  import { Registry } from './Registry.js';
3
+ import { dirCreate, fileCreateJson, fileCreateYaml } from '../helpers/file.js';
2
4
  export class RegistryLocal extends Registry {
3
5
  managers;
4
6
  constructor(name, url, version) {
5
7
  super(name, url, version);
6
8
  this.managers = {};
7
9
  }
10
+ export(dir, ext = 'json') {
11
+ const saveFile = ext === 'yaml' ? fileCreateYaml : fileCreateJson;
12
+ for (const [, manager] of Object.entries(this.managers)) {
13
+ manager.export(path.join(dir, manager.type), ext);
14
+ }
15
+ dirCreate(dir);
16
+ saveFile(path.join(dir, `index.${ext}`), this.toJSON());
17
+ return true;
18
+ }
8
19
  scan(ext = 'json') {
9
20
  for (const [, manager] of Object.entries(this.managers)) {
10
21
  manager.scan(ext);
@@ -14,7 +14,7 @@ export function adminArguments() {
14
14
  export async function adminInit() {
15
15
  const argv = adminArguments();
16
16
  const manager = new ManagerLocal(argv.type, { appDir: dirApp() });
17
- manager.sync();
17
+ await manager.sync();
18
18
  if (argv.operation === 'install') {
19
19
  await manager.install(argv.id, argv.ver);
20
20
  }
@@ -22,6 +22,7 @@ export declare function dirRead(dir: string, options?: any): string[];
22
22
  export declare function dirRename(dir: string, dirNew: string): void | boolean;
23
23
  export declare function fileCreate(filePath: string, data: string | Buffer): void;
24
24
  export declare function fileCreateJson(filePath: string, data: object): void;
25
+ export declare function fileCreateYaml(filePath: string, data: object): void;
25
26
  export declare function fileDate(filePath: string): Date;
26
27
  export declare function fileDelete(filePath: string): boolean | void;
27
28
  export declare function fileExec(filePath: string): void;
@@ -142,6 +142,9 @@ export function fileCreate(filePath, data) {
142
142
  export function fileCreateJson(filePath, data) {
143
143
  return fileCreate(filePath, JSON.stringify(data, null, 2));
144
144
  }
145
+ export function fileCreateYaml(filePath, data) {
146
+ return fileCreate(filePath, yaml.dump(data));
147
+ }
145
148
  export function fileDate(filePath) {
146
149
  return statSync(filePath).mtime;
147
150
  }
@@ -12,6 +12,7 @@ import { ProjectType } from '../types/ProjectType.js';
12
12
  import { SystemType } from '../types/SystemType.js';
13
13
  import { PackageFileMap, PackageInterface, PackageValidationRec, PackageVersion } from '../types/Package.js';
14
14
  export declare function packageCompatibleFiles(pkg: PackageVersion, arch: Architecture[], sys: SystemType[], excludedFormats?: FileFormat[]): (PluginFile | PresetFile | ProjectFile)[];
15
+ export declare function packageErrors(pkgVersion: PackageVersion): z.ZodIssue[];
15
16
  export declare function packageFileMap(pkgVersion: PackageVersion): PackageFileMap;
16
17
  export declare function packageVersionLatest(pkg: PackageInterface): string;
17
18
  export declare const PackageSystemValidator: z.ZodObject<{
@@ -171,12 +172,10 @@ export declare const PackageVersionValidator: z.ZodObject<{
171
172
  }>;
172
173
  url: z.ZodString;
173
174
  }, "strip", z.ZodTypeAny, {
174
- type: PluginType | PresetType | ProjectType;
175
- date: string;
176
- url: string;
177
175
  audio: string;
178
176
  author: string;
179
177
  changes: string;
178
+ date: string;
180
179
  description: string;
181
180
  files: {
182
181
  type: FileType;
@@ -191,17 +190,17 @@ export declare const PackageVersionValidator: z.ZodObject<{
191
190
  }[];
192
191
  url: string;
193
192
  }[];
193
+ type: PluginType | PresetType | ProjectType;
194
+ url: string;
194
195
  image: string;
195
196
  license: License;
196
197
  name: string;
197
198
  tags: string[];
198
199
  }, {
199
- type: PluginType | PresetType | ProjectType;
200
- date: string;
201
- url: string;
202
200
  audio: string;
203
201
  author: string;
204
202
  changes: string;
203
+ date: string;
205
204
  description: string;
206
205
  files: {
207
206
  type: FileType;
@@ -216,6 +215,8 @@ export declare const PackageVersionValidator: z.ZodObject<{
216
215
  }[];
217
216
  url: string;
218
217
  }[];
218
+ type: PluginType | PresetType | ProjectType;
219
+ url: string;
219
220
  image: string;
220
221
  license: License;
221
222
  name: string;
@@ -20,6 +20,9 @@ export function packageCompatibleFiles(pkg, arch, sys, excludedFormats) {
20
20
  return archMatches.length && sysMatches.length && formatAllowed;
21
21
  });
22
22
  }
23
+ export function packageErrors(pkgVersion) {
24
+ return PackageVersionValidator.safeParse(pkgVersion).error?.issues || [];
25
+ }
23
26
  export function packageFileMap(pkgVersion) {
24
27
  return pkgVersion.files.reduce((result, file) => {
25
28
  file.systems.forEach(system => {
@@ -2,6 +2,7 @@ import { PluginFile, PluginFileMap, PluginInterface } from './Plugin.js';
2
2
  import { PresetFile, PresetFileMap, PresetInterface } from './Preset.js';
3
3
  import { ProjectFile, ProjectFileMap, ProjectInterface } from './Project.js';
4
4
  import { License } from './License.js';
5
+ import { ZodIssue } from 'zod';
5
6
  export interface PackageInterface {
6
7
  slug: string;
7
8
  version: string;
@@ -23,6 +24,10 @@ export interface PackageBase {
23
24
  tags: string[];
24
25
  url: string;
25
26
  }
27
+ export interface PackageReport {
28
+ errors?: ZodIssue[];
29
+ recs?: PackageValidationRec[];
30
+ }
26
31
  export type PackageVersion = PluginInterface | PresetInterface | ProjectInterface;
27
32
  export type PackageFile = PluginFile | PresetFile | ProjectFile;
28
33
  export type PackageFileMap = PluginFileMap | PresetFileMap | ProjectFileMap;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@open-audio-stack/core",
3
- "version": "0.1.7",
3
+ "version": "0.1.9",
4
4
  "description": "Open-source audio plugin management software",
5
5
  "type": "module",
6
6
  "main": "./build/index.js",