gpii-universal
Version:
Cross platform, core components of the GPII personalization infrastructure.
158 lines (132 loc) • 6.46 kB
JavaScript
/*
A script to generate a schema "codex" for all known solutions and generic preferences. The "codex" is a map,
keyed by URI. For application settings, the URI looks like:
http://registry.gpii.net/applications/com.microsoft.windows.onscreenKeyboard
For "generic preference terms", the URI looks like:
http://registry.gpii.net/common/fontSize
Each map entry is a schema that describes all possible settings for a given solution, as shown here:
{
"http://registry.gpii.net/applications/my.sample.app": {
properties: {
setting1: {
// setting1 sub-schema
},
setting2: {
// setting2 sub-schema
}
}
}
}
This structure allows for more efficient settings/preferences validation than previous strategies. Payloads to be
validated can be broken down into a series of small "per solution" validation passes, which typically take less than
5ms even for our largest sample settings payloads.
*/
/* eslint-env node */
;
var fluid = require("infusion");
var gpii = fluid.registerNamespace("gpii");
var mkdirp = require("mkdirp");
var fs = require("fs");
var path = require("path");
// Add the ability to require JSON5 files.
require("json5/lib/register");
// Require universal so that we can resolve paths to it and any sub-modules.
fluid.require("%gpii-universal");
fluid.registerNamespace("gpii.solutionsRegistry.schemaGenerator");
gpii.solutionsRegistry.schemaGenerator.generateSolutionsSchemaCodex = function (that) {
// TODO: Add all solutions/settings and schemas from that.options.solutionsRegistryPath
var solutionsSettings = gpii.solutionsRegistry.schemaGenerator.settingsFromSolutions(that);
var genericSettings = gpii.solutionsRegistry.schemaGenerator.genericSettings(that);
var allSettings = fluid.extend({}, solutionsSettings, genericSettings);
// Sort the keys so that the final generated file is more readable.
var orderedSettings = {};
var allSettingsKeys = fluid.keys(allSettings).sort();
fluid.each(allSettingsKeys, function (settingURI) {
orderedSettings[settingURI] = allSettings[settingURI];
});
var resolvedCodexOutputPath = fluid.module.resolvePath(that.options.codexOutputPath);
var settingsOutputDir = path.dirname(resolvedCodexOutputPath);
if (!fs.existsSync(settingsOutputDir)) {
mkdirp.sync(settingsOutputDir);
}
fs.writeFileSync(resolvedCodexOutputPath, JSON.stringify(orderedSettings, null, 2));
};
gpii.solutionsRegistry.schemaGenerator.settingsFromSolutions = function (that) {
var settingsBySolution = {};
var resolvedSrPath = fluid.module.resolvePath(that.options.solutionsRegistryPath);
var srFiles = fs.readdirSync(resolvedSrPath).filter(function (filename) { return filename.match(/\.json5?$/i); });
fluid.each(srFiles, function (filename) {
var pathToFile = path.resolve(resolvedSrPath, filename);
var srFileData = require(pathToFile);
fluid.each(srFileData, function (solutionDef, solutionKey) {
var solutionURI = "http://registry.gpii.net/applications/" + solutionKey;
var solutionSchema = {
"$schema": "gss-v7-full#",
// Add the name as a courtesy to make reading the generated file more palatable.
title: solutionDef.name,
type: "object",
properties: {},
additionalProperties: false
};
fluid.each(fluid.get(solutionDef, "settingsHandlers"), function (settingsHandlerDef) {
fluid.each(fluid.get(settingsHandlerDef, "supportedSettings"), function (settingsDef, settingsKey) {
if (settingsDef.schema) {
solutionSchema.properties[settingsKey] = settingsDef.schema;
}
});
});
// If there is not an explicit "enabled" setting for a solution, add it now.
if (fluid.get(solutionSchema, "properties.enabled") === undefined) {
var solutionName = fluid.get(solutionDef, "name");
var title = solutionName ? "Enable " + solutionName : "Enable";
fluid.set(solutionSchema, "properties.enabled", {
title: title,
description: title + ".",
type: "boolean",
default: false
});
};
if (!fluid.jQueryStandalone.isEmptyObject(solutionSchema.properties)) {
settingsBySolution[solutionURI] = solutionSchema;
}
});
});
return settingsBySolution;
};
gpii.solutionsRegistry.schemaGenerator.genericSettings = function (that) {
var allGenericSettings = {};
var resolvedPath = fluid.module.resolvePath(that.options.genericPreferenceTermsPath);
var rawGenericSettings = require(resolvedPath);
fluid.each(rawGenericSettings, function (settingDef, settingURI) {
var schema = fluid.get(settingDef, "schema");
if (schema) {
allGenericSettings[settingURI] = fluid.extend({ "$schema": "gss-v7-full#" }, schema);
}
});
return allGenericSettings;
};
fluid.defaults("gpii.solutionsRegistry.schemaGenerator", {
gradeNames: ["fluid.component"],
baseSettingsSchema: "%solutionsRegistry/src/schemas/settings-base-schema.json5",
codexOutputPath: "%gpii-universal/build/schemas/solution-schema-codex.json",
// TODO: Move this out of test data and break down into individual solutions.
solutionsRegistryPath: "%gpii-universal/testData/solutions",
// TODO: Move this out of test data to a suitable location.
genericPreferenceTermsPath: "%gpii-universal/testData/ontologies/flat.json5",
events: {
createAllSchemas: null
},
listeners: {
"onCreate.createAllSchemas": {
funcName: "fluid.promise.fireTransformEvent",
args: ["{that}.events.createAllSchemas"]
},
"createAllSchemas.generateSettingsSchema": {
priority: "first",
funcName: "gpii.solutionsRegistry.schemaGenerator.generateSolutionsSchemaCodex",
args: ["{that}"]
}
// TODO: Generate prefs safe schema from the settings schema.
}
});
gpii.solutionsRegistry.schemaGenerator();