Skip to content

Commit

Permalink
chore: add script to check older removed apis to consider dropping
Browse files Browse the repository at this point in the history
  • Loading branch information
sgtcoolguy committed Nov 25, 2019
1 parent 69fe30c commit b31bfed
Show file tree
Hide file tree
Showing 3 changed files with 125 additions and 0 deletions.
123 changes: 123 additions & 0 deletions build/scons-removals.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,123 @@
#!/usr/bin/env node
'use strict';

const path = require('path');
const glob = require('glob');
const yaml = require('js-yaml');
const fs = require('fs-extra');
const promisify = require('util').promisify;
const semver = require('semver');
const chalk = require('chalk');

/**
* @param {object} thing type, property or method from docs
* @param {string} thingPath full API path of the object we're checking
*/
async function checkDeprecatedAndRemoved(thing, thingPath) {
if (Object.prototype.hasOwnProperty.call(thing, 'deprecated')
&& Object.prototype.hasOwnProperty.call(thing.deprecated, 'removed')) {
return { path: thingPath, deprecated: thing.deprecated };
}
return null;
}

async function checkMethod(m, methodOwner) {
return checkDeprecatedAndRemoved(m, `${methodOwner}#${m.name}()`);
}

async function checkProperty(p, propertyOwner) {
return checkDeprecatedAndRemoved(p, `${propertyOwner}.${p.name}`);
}

/**
* @param {Object} t type definition from YAML
* @return {Promise<object[]>} unremoved apis that are deprecated
*/
async function checkType(t) {
const unremovedDeprecations = [];
const typePossible = await checkDeprecatedAndRemoved(t, t.name);
if (typePossible) {
unremovedDeprecations.push(typePossible);
}
const methods = await Promise.all((t.methods || []).map(m => checkMethod(m, t.name)));
unremovedDeprecations.push(...methods.filter(m => m));
const properties = await Promise.all((t.properties || []).map(p => checkProperty(p, t.name)));
unremovedDeprecations.push(...properties.filter(p => p));
// console.info(unremovedDeprecations);
return unremovedDeprecations;
}

/**
* @param {string} file filepath of a yml doc file to check
* @returns {Promise<object[]>}
*/
async function checkFile(file) {
const contents = await fs.readFile(file, 'utf8');
// remove comments
contents.replace(/\w*#.*/, '');
const doc = await yaml.safeLoadAll(contents);
const types = Array.isArray(doc) ? doc : [ doc ];
// go through the types in the document, for each one, check top-level for deprecated
// then check each property, event, method
const arr = await Promise.all(types.map(t => checkType(t)));
const flattened = [].concat(...arr);
return flattened;
}

/**
* @param {string|object} deprecatedSince string or object holding deprecated since value from yml docs
* @return {string}
*/
function pickFirstVersion(deprecatedSince) {
if (typeof deprecatedSince !== 'string') {
// deprecated.since may be an object with platform keys, version values!
// Hack to just pick first value we can
return Object.values(deprecatedSince)[0];
}
return deprecatedSince;
}

/**
* @param {string} a first version strign to comparse
* @param {string} b second version string to compare
* @returns {1|0|-1}
*/
function compareVersions(a, b) {
return semver.compare(a, b);
}

/**
* @param {object} a first type/method/property doc definition to compare
* @param {object} b second type/method/property doc definition to compare
* @returns {1|0|-1}
*/
function compareRemoved(a, b) {
return compareVersions(pickFirstVersion(a.deprecated.removed), pickFirstVersion(b.deprecated.removed));
}

/**
* @param {string} version maximum version to include
* @returns {object[]}
*/
async function main(version) {
const apidocs = path.join(__dirname, '../apidoc');
const files = await promisify(glob)(`${apidocs}/**/*.yml`);
const arr = await Promise.all(files.map(f => checkFile(f)));
const flattened = [].concat(...arr).filter(f => compareVersions(pickFirstVersion(f.deprecated.removed), version) < 0);
// Sort by deprecated.since oldest to newest
flattened.sort(compareRemoved);
return flattened;
}

main(process.argv[2]).then(results => {
if (results && results.length !== 0) {
results.forEach(f => {
console.error(`${chalk.cyan(f.path)} has been removed since ${chalk.red(pickFirstVersion(f.deprecated.removed))}. Consider dropping from apidocs.`);
});
return process.exit(1);
}
return process.exit(0);
}).catch(err => {
console.error(err);
process.exit(1);
});
1 change: 1 addition & 0 deletions build/scons.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,4 +19,5 @@ commander
.command('check-ios-toplevel', 'Ensures we don\'t check in prefilled values for version/hash/timestamp')
.command('xcode-project-build <projectDir> <targetBuildDir> <productName>', 'Runs the portion of the xcode project setup')
.command('deprecations', 'Checks the apidocs for deprecated but unremoved types/properties/methods')
.command('removals <minVersion>', 'Checks the apidocs for deprecated and removed types/properties/methods older than a given version')
.parse(process.argv);
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
"clean:ios": "npm run clean -- ios",
"commit": "git-cz",
"deprecations": "./build/scons deprecations",
"docs:removed": "./build/scons removals 7.0.0",
"format": "npm-run-all --parallel format:**",
"format:android": "npm run lint:android -- --fix",
"format:ios": "npm run lint:ios -- --fix",
Expand Down

0 comments on commit b31bfed

Please sign in to comment.