Skip to content

Commit

Permalink
feat(object specs): simplify extension API (#3)
Browse files Browse the repository at this point in the history
  • Loading branch information
strogonoff committed Jan 10, 2021
1 parent c6ddf02 commit f2f16c6
Show file tree
Hide file tree
Showing 2 changed files with 2 additions and 112 deletions.
95 changes: 1 addition & 94 deletions src/index.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,10 @@
import path from 'path';
import semver from 'semver';
import 'electron';
import log from 'electron-log';
import { Extension } from './types/extension';
import { ExtensionMaker } from './types/extension-maker';
import { withDatasetContext } from './context';
import { SerializableObjectSpec, DEFAULT_SPECS, matchesPath } from './object-specs';
import { stripLeadingSlash } from './util';
import { DEFAULT_SPECS, matchesPath } from './object-specs';


/* The default export of Paneron extension’s extension.ts entry file
Expand All @@ -28,97 +26,6 @@ export const makeExtension: ExtensionMaker = async (options) => {
return objectSpecs;
},

objectsToBuffers: (objects) => {
const buffers: Record<string, Uint8Array> = {};
for (const [objectPath, obj] of Object.entries(objects)) {
const spec = Object.values(objectSpecs).
find(c => matchesPath(objectPath, c.matches));

if (spec) {
const objectBuffersRelative = (spec as SerializableObjectSpec).serialize(obj);

const objectBuffers: Record<string, Uint8Array> =
Object.entries(objectBuffersRelative).
map(([objectRelativePath, data]) => ({
[path.join(objectPath, objectRelativePath)]: data,
})).
reduce((p, c) => ({ ...p, ...c }), {});

Object.assign(buffers, objectBuffers);
} else {
log.error("Unable to find object spec for object path", objectPath);
throw new Error("Unable to find object spec for path");
}
}
return buffers;
},

indexObjects: (rawData) => {
// 1. Go through paths and organize them by matching object spec.
// If a path matches some spec, that path is considered new object root,
// and subsequent paths are considered to belong to this object
// if they are descendants of object root path.
const toProcess: {
objectPath: string
data: Record<string, Uint8Array>
spec: SerializableObjectSpec
}[] = [];

// Sorted paths will appear in fashion [/, /foo/, /foo/bar.yaml, /baz/, /baz/qux.yaml, ...]
const paths = Object.keys(rawData).sort();

let currentSpec: SerializableObjectSpec | undefined;
let currentObject: {
path: string
buffers: Record<string, Uint8Array>
} | null = null;

for (const p of paths) {

if (currentObject && p.startsWith(currentObject.path)) {
// We are in the middle of processing an object
// and current path is a descendant of object’s path.

// Accumulate current path into current object for deserialization later.
const objectRelativePath = stripLeadingSlash(p.replace(currentObject.path, ''));
currentObject.buffers[`/${objectRelativePath}`] = rawData[p];

log.debug("Matched path to object", p, currentObject.path, objectRelativePath);

} else {
// Were we in the middle of processing a spec and an object?
if (currentSpec && currentObject) {
// If yes, add that spec and accumulated object to list for further processing...
toProcess.push({
objectPath: currentObject.path,
data: { ...currentObject.buffers },
spec: currentSpec,
});
// ...and reset/flush accumulated object.
currentObject = null;
}

// Find a matching spec for current path.
currentSpec = Object.values(objectSpecs).find(c => matchesPath(p, c.matches));

if (currentSpec) {
// If a matching spec was found, start a new object.
currentObject = { path: p, buffers: {} };
// Current path will be the root path for the object.
currentObject.buffers['/'] = rawData[p];
}
}
}

// 2. Deserialize accumulated buffers into objects.
const index: Record<string, Record<string, any>> = {};
for (const { objectPath, data, spec } of toProcess) {
index[objectPath] = spec.deserialize(data);
}

return index;
},

getMigration: (datasetVersion) => (
Object.entries(options.datasetMigrations).
filter(([migrationVersionSpec, _]) =>
Expand Down
19 changes: 1 addition & 18 deletions src/types/extension.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@ import { DatasetContext } from './renderer';

/* The interface that extension instance exposes to Paneron in main thread. */
export interface MainPlugin {

// False means another version of the host app must be used (probably a newer one).
isCompatible: (withHostAppVersion: string) => boolean

Expand All @@ -19,25 +18,9 @@ export interface MainPlugin {
getInitialMigration: () => MigrationModule

getObjectSpecs: () => SerializableObjectSpec[]
}

// TODO: Obsolete

// Converts buffers with raw file data per path
// to structured records (as JS objects) per path.
// Specs for conversion can be provided to makeExtension to customize
// how object is represented.
// NOTE: Slow, when processing full repository data
// it is supposed to be called from a worker thread only.
indexObjects: (rawData: Record<string, Uint8Array>) =>
Record<string, Record<string, any>>

// Converts a record that maps paths to object data
// to a record that maps paths to buffers / byte arrays
// ready for storage.
objectsToBuffers: (objects: Record<string, Record<string, any>>) =>
Record<string, Uint8Array>

}


/* The interface that extension instance exposes to Paneron in renderer thread. */
Expand Down

0 comments on commit f2f16c6

Please sign in to comment.