Skip to content

Commit

Permalink
Merge pull request #14 from AdobeXD/console-update
Browse files Browse the repository at this point in the history
Console update
  • Loading branch information
ashryanbeats authored Mar 5, 2019
2 parents 0269854 + 25f5fca commit 3ac44ac
Show file tree
Hide file tree
Showing 3 changed files with 272 additions and 88 deletions.
338 changes: 261 additions & 77 deletions lib/validate.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,108 +16,292 @@

const PLUGIN_NAME_MIN_LEN = 3;
const PLUGIN_NAME_MAX_LEN = 45;
const PLUGIN_DESC_MIN_LEN = 3;
const PLUGIN_DESC_MAX_LEN = 1000;
const PLUGIN_SUMMARY_MIN_LEN = 3;
const PLUGIN_SUMMARY_MAX_LEN = 30;
const RELEASE_NOTES_MIN_LEN = 3;
const RELEASE_NOTES_MAX_LEN = 1000;
const AUTHOR_MIN_LEN = 3;
const AUTHOR_MAX_LEN = 40;
const KEYWORD_MIN_LEN = 2;
const KEYWORD_CONCAT_MAX_LEN = 100;
const ICONS_LEN = 4;
const ICONS_SIZES = [48, 96, 144, 192];
const SUPPORTED_HOSTS = ["XD"];
const VERSION_REGEX = /^\d{1,2}\.\d{1,2}.\d{1,2}$/;
const MIN_VERSION = "0.0.1";
const MAX_VERSION = "99.99.99";
const SUPPORTED_LANGUAGES = ["en", "de", "fr", "ja", "ko", "zh", "es", "pt"];
const PLUGIN_VERSION_REGEX = /^\d{1,2}\.\d{1,2}.\d{1,2}$/;
const HOST_VERSION_REGEX = /^\d{1,2}\.\d{1,2}$/;
const PLUGIN_MIN_VERSION = "0.0.1";
const PLUGIN_MAX_VERSION = "99.99.99";
const HOST_MIN_VERSION = "13.0";
const HOST_MAX_VERSION = "99.99";

const fs = require("fs");
const path = require("path");

function validate(manifest, { root, id } = {}) {
const errors = [];
const errors = [];

// check the ID
if (!manifest.id) {
errors.push("F1000: Manifest is missing a 'id' field. Add a plugin id.");
// check the ID
if (!manifest.id) {
errors.push("F1000: Manifest is missing a 'id' field. Add a plugin id.");
} else {
if (id) {
if (manifest.id !== id) {
errors.push(
`F1001: Manifest 'id' does not match expected id. Saw '${
manifest.id
}', expected '${id}'.`
);
}
}
if (manifest.id.length !== 8) {
errors.push(
`F1002: Manifest 'id' character count is incorrect. Count is ${
manifest.id.length
}, expected 8.`
);
}
}

// check the name
if (!manifest.name) {
errors.push("F1010: Manifest is missing a plugin name.");
} else {
if (
manifest.name.length < PLUGIN_NAME_MIN_LEN ||
manifest.name.length > PLUGIN_NAME_MAX_LEN
) {
errors.push(
`F1011: Manifest name is not an appropriate length (expected ${PLUGIN_NAME_MIN_LEN} - ${PLUGIN_NAME_MAX_LEN} chars, saw ${
manifest.name.length
} chars).`
);
}
}

// check for a version
if (!manifest.version) {
errors.push("F1030: Manifest must specify a version number.");
} else {
if (!PLUGIN_VERSION_REGEX.test(manifest.version)) {
errors.push(
`F1031: Version format is incorrect. Saw ${
manifest.version
}, expected ${PLUGIN_MIN_VERSION} - ${PLUGIN_MAX_VERSION}.`
);
}
}

// check for a host property
if (!manifest.host) {
errors.push(
"F1020: Manifest is missing host requirements. Add a 'host' key."
);
} else {
// host.app
if (!manifest.host.app) {
errors.push(
"F1021: Manifest is missing host app id. Add a host.app key."
);
} else {
if (id) {
if (manifest.id !== id) {
errors.push (`F1001: Manifest 'id' does not match expected id. Saw '${manifest.id}', expected '${id}'`);
}
}
// is the host app one we expect?
if (!SUPPORTED_HOSTS.includes(manifest.host.app)) {
errors.push(
`F1022: Manifest host is not a recognized host. Saw ${
manifest.host.app
}, expected one of ${SUPPORTED_HOSTS.join()}`
);
}
}

// check the name
if (!manifest.name) {
errors.push("F1010: Manifest is missing a plugin name.");
// host.minVersion
if (!manifest.host.minVersion) {
errors.push(
"F1023: Manifest must specify the minimum supported host version."
);
} else {
if (manifest.name.length < PLUGIN_NAME_MIN_LEN || manifest.name.length > PLUGIN_NAME_MAX_LEN) {
errors.push(`F1011: Manifest name is not an appropriate length (expected ${PLUGIN_NAME_MIN_LEN} - ${PLUGIN_NAME_MAX_LEN} chars, saw ${manifest.name.length} chars).`);
}
if (!HOST_VERSION_REGEX.test(manifest.host.minVersion)) {
errors.push(
`F1024: Host minimum version format is incorrect. Saw ${
manifest.host.minVersion
}, expected ${HOST_MIN_VERSION} - ${HOST_MAX_VERSION}.`
);
}
}

// host.maxVersion
if (manifest.host.maxVersion) {
if (!HOST_VERSION_REGEX.test(manifest.host.minVersion)) {
errors.push(
`F1025: Host maximum version format is incorrect. Saw ${
manifest.host.maxVersion
}, expected ${HOST_MIN_VERSION} - ${HOST_MAX_VERSION}.`
);
}
}
}

// check for a version
if (!manifest.version) {
errors.push("F1030: Manifest must specify a version number.");
// validate entry points (this is a bit lax ATM, but easy verifiable with XD)
if (!manifest.uiEntryPoints) {
errors.push("F1040: Manifest must contain UI entry points.");
}

// validate icons
if (!manifest.icons) {
errors.push("W2010: Manifest must contain icons.");
} else {
if (!Array.isArray(manifest.icons) || manifest.icons.length !== ICONS_LEN) {
errors.push(
`W2000: Icons should be an array with ${ICONS_LEN} elements.`
);
} else {
if (!VERSION_REGEX.test(manifest.version)) {
errors.push(`F1031: Version format is incorrect. Saw ${manifest.version}, expected ${MIN_VERSION} - ${MAX_VERSION}.`)
manifest.icons.forEach((icon, idx) => {
if (!icon.width) {
errors.push(`W2001: Icon ${idx} should specify a width.`);
}
if (!icon.height) {
errors.push(`W2002: Icon ${idx} should specify a height.`);
}
if (icon.width && icon.height && icon.width !== icon.height) {
errors.push(`W2003: Icon ${idx} should be square.`);
}
if (
!ICONS_SIZES.includes(icon.width) ||
!ICONS_SIZES.includes(icon.height)
) {
errors.push(
`W2005: Icon ${idx} has at least one inaccurate dimension. Expected one of the following: ${ICONS_SIZES.join(
", "
)}.`
);
}
if (!icon.path) {
errors.push(`W2004: Icon ${idx} should specify a path.`);
}
if (!fs.existsSync(path.join(root || ".", icon.path))) {
errors.push(
`W2004: Icon ${idx} has path ${
icon.path
}, but no icon was found there.`
);
}
});
}
}

// validate description
if (!manifest.description) {
errors.push("F1050: Manifest must contain a plugin description.");
} else {
if (
manifest.description.length < PLUGIN_DESC_MIN_LEN ||
manifest.description.length > PLUGIN_DESC_MAX_LEN
) {
errors.push(
`F1051: Manifest description is not an appropriate length (expected ${PLUGIN_DESC_MIN_LEN} - ${PLUGIN_DESC_MAX_LEN} chars, saw ${
manifest.description.length
} chars).`
);
}
}

// validate summary
if (!manifest.summary) {
errors.push("F1060: Manifest must contain a plugin summary.");
} else {
if (
manifest.summary.length < PLUGIN_SUMMARY_MIN_LEN ||
manifest.summary.length > PLUGIN_SUMMARY_MAX_LEN
) {
errors.push(
`F1051: Manifest summary is not an appropriate length (expected ${PLUGIN_SUMMARY_MIN_LEN} - ${PLUGIN_SUMMARY_MAX_LEN} chars, saw ${
manifest.summary.length
} chars).`
);
}
}

// check for a host property
if (!manifest.host) {
errors.push("F1020: Manifest is missing host requirements. Add a 'host' key.");
// validate keywords
if (manifest.keywords) {
if (!Array.isArray(manifest.keywords)) {
errors.push("W2010: Keywords should be an array.");
} else {
// host.app
if (!manifest.host.app) {
errors.push("F1021: Manifest is missing host app id. Add a host.app key.");
} else {
// is the host app one we expect?
if (!SUPPORTED_HOSTS.includes(manifest.host.app)) {
errors.push(`F1022: Manifest host is not a recognized host. Saw ${manifest.host.app}, expected one of ${SUPPORTED_HOSTS.join()}`)
}
}
// check if each keyword meets length requirements
const concatKeywords = manifest.keywords.reduce((initVal, keyword) =>
keyword.length >= KEYWORD_MIN_LEN
? initVal + keyword
: errors.push(
`W2011: Keywords should be at least ${KEYWORD_MIN_LEN} chars. Found keyword ${keyword} with ${
keyword.length
} chars.`
)
);

// host.minVersion
if (!manifest.host.minVersion) {
errors.push("F1023: Manifest must specify the minimum supported host version.");
} else {
if (!VERSION_REGEX.test(manifest.host.minVersion)) {
errors.push(`F1024: Host minimum version format is incorrect. Saw ${manifest.host.minVersion}, expected ${MIN_VERSION} - ${MAX_VERSION}.`)
}
}
// check if concatenated keywords meets length requirements
if (concatKeywords.length > KEYWORD_CONCAT_MAX_LEN) {
errors.push(
`W2012: Concatenated length of all keywords should be no more than ${KEYWORD_CONCAT_MAX_LEN} chars. Found ${
concatKeywords.length
} chars.`
);
}
}
}

// host.maxVersion
if (manifest.host.maxVersion) {
if (!VERSION_REGEX.test(manifest.host.minVersion)) {
errors.push(`F1025: Host maximum version format is incorrect. Saw ${manifest.host.maxVersion}, expected ${MIN_VERSION} - ${MAX_VERSION}.`)
}
}
// validate release notes
if (manifest.releaseNotes) {
if (
manifest.releaseNotes.length < RELEASE_NOTES_MIN_LEN ||
manifest.releaseNotes.length > RELEASE_NOTES_MAX_LEN
) {
errors.push(
`W2020: Release notes are not an appropriate length (expected ${RELEASE_NOTES_MIN_LEN} - ${RELEASE_NOTES_MAX_LEN} chars, saw ${
manifest.releaseNotes.length
} chars).`
);
}
}

// validate entry points (this is a bit lax ATM, but easy verifiable with XD)
if (!manifest.uiEntryPoints) {
errors.push("F1040: Manifest must contain UI entry points.");
// validate keywords
if (!manifest.languages) {
errors.push("F1070: Manifest must contain supported languages.");
} else {
if (!Array.isArray(manifest.languages) || manifest.languages.length === 0) {
errors.push(
"F1071: Languages should be an array with at least one element."
);
} else {
// check if each keyword meets length requirements
manifest.languages.map(lang =>
SUPPORTED_LANGUAGES.includes(lang)
? lang
: errors.push(
`Unsupported language code "${lang}" found. \nOnly these language codes are supported: ${SUPPORTED_LANGUAGES.join(
", "
)}.`
)
);
}
}

// validate icons
if (manifest.icons) {
if (!Array.isArray(manifest.icons)) {
errors.push("W2000: Icons should be an array.");
} else {
manifest.icons.forEach((icon, idx) => {
if (!icon.width) {
errors.push(`W2001: Icon ${idx} should specify a width.`);
}
if (!icon.height) {
errors.push(`W2002: Icon ${idx} should specify a height.`);
}
if (icon.width && icon.height && icon.width !== icon.height) {
errors.push(`W2003: Icon ${idx} should be square.`);
}
if (!icon.path) {
errors.push(`W2004: Icon ${idx} should specify a path.`);
}
if (!fs.existsSync(path.join(root || '.', icon.path))) {
errors.push(`W2004: Icon ${idx} has path ${icon.path}, but no icon was found there.`);
}
});
}
if (!manifest.author) {
errors.push("F1080: Manifest must contain author.");
} else {
if (
manifest.author.length < AUTHOR_MIN_LEN ||
manifest.author.length > AUTHOR_MAX_LEN
) {
errors.push(
`F1081: Author is not an appropriate length (expected ${AUTHOR_MIN_LEN} - ${AUTHOR_MAX_LEN} chars, saw ${
manifest.author.length
} chars).`
);
}
}

return errors;
return errors;
}

module.exports = validate;
module.exports = validate;
Loading

0 comments on commit 3ac44ac

Please sign in to comment.