Skip to content

Instantly share code, notes, and snippets.

@cdaringe
Forked from dylancwood/split.js
Last active August 29, 2015 14:01
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save cdaringe/f556943b685aff43c292 to your computer and use it in GitHub Desktop.
Save cdaringe/f556943b685aff43c292 to your computer and use it in GitHub Desktop.
/*
TODO:
Address methods that reference other methods as '$this->doSomething()'
+ $this->select() Could be addressed by each class extending BaseAppData
+ Grep for methods defined in File 'A' that are referenced in File 'B' using $this->
+ Alternatively, change all calls to '$this' to be $AppData.
*/
var fs = require('fs');
var Promise = require('es6-promise').Promise;
var _ = require('underscore');
var now = (new Date()).getTime(),
buildPath = './build-' + now,
buildPathClasses = buildPath + '/AppDataClasses';
// src data
var splitFilesDirPath = '../micis/AppDataClasses/';
var appDataPath = '../micis/AppData.inc_orig';
// function parsing regex
var funcRx = /function *[^\s(]* *\([^)]*\)\s*\{/g;
var funcNameRx = /function *([^\s(]*) *\([^)]*\)\s*\{/;
// Promise array indicating all files read
var subClassFilesParsed = [];
//format {'filename':[func1, func2]...}
var subFunctionNames = {},
appFunctionNames = [];
// parse all sub-class files
fs.readdir(splitFilesDirPath, function readFiles(err, files) {
if (err) throw err;
subClassFilesParsed = files.map(function readFile(filename) {
return new Promise(function readFileP(resolve, reject){
var fileFullPath = splitFilesDirPath + filename;
subFunctionNames[filename] = [];
fs.readFile(fileFullPath, 'utf-8', function parseFunctionNames(err, contents) {
if (contents === undefined || err) {
reject();
return;
}
// match function blocks, then function names
subFunctionNames[filename] = contents.match(funcRx).map(function extractFunctionName(str) {
var groups = str.match(funcNameRx);
return groups[1];
});
subFunctionNames[filename] = _.uniq(subFunctionNames[filename]).sort();
resolve();
});
});
});
});
Promise.all(subClassFilesParsed).then(readAppData);
function readAppData(){
var appDataReadP = new Promise(function readAppDataP(resolve, reject){
fs.readFile(appDataPath, 'utf-8', function readAppData(err, contents){
if (contents === undefined || err) {
console.log('AppData not found!');
reject();
return;
}
appFunctionNames = contents.match(funcRx).map(function extractFunctionName(str) {
var groups = str.match(funcNameRx);
//console.log('>>>' + groups[1]);
return groups[1];
});
appFunctionNames = _.uniq(appFunctionNames).sort(); // eliminate duplicates (funcs in comment blocks)
resolve();
});
});
appDataReadP
.then(validateFileNames)
.then(buildAppData);
}
function validateFileNames(){
try{
var currentFuncCount = 0,
totalSubFunctions = 0,
totalAppFunctions = appFunctionNames.length,
missingFunctions = [],
duplicateFunctions = [];
// function report per file
console.log('Num class files: ' + Object.keys(subFunctionNames).length);
Object.keys(subFunctionNames).forEach(function printClassFunctionInfo(key){
currentFuncCount = subFunctionNames[key].length;
totalSubFunctions += currentFuncCount;
console.log('..' + key + ':\t\t\t' + currentFuncCount);
});
// totals
console.log('Total subClass function count: ' + totalSubFunctions);
console.log('Total AppData function count: ' + totalAppFunctions);
if (totalSubFunctions !== totalAppFunctions) {
console.log('Error: File count mismatch between AppData and SubClasses');
}
// ensure all functions in AppData present in sub-classes, no duplicates
appFunctionNames.forEach(function validateAllFunctionsPresent(funcName) {
var foundCount = 0;
Object.keys(subFunctionNames).forEach(function testForPresence(key){
if (subFunctionNames[key].indexOf(funcName) >= 0) ++foundCount;
});
if (foundCount === 0) missingFunctions.push(funcName);
else if (foundCount > 1) duplicateFunctions.push(funcName);
else if (foundCount !== 1) {
console.log('Error: ' + funcName + ' // ' + foundCount);
throw new Error('Bogus number of functions detected');
}
});
// error
if (missingFunctions.length || duplicateFunctions.length) {
console.log("Missing functions: ");
console.dir(missingFunctions);
console.log("Duplicate functions: ");
console.dir(duplicateFunctions);
throw new Error("Expected to find 1:1 mapping between AppData " +
"and SubClass functions");
}
}
catch(e){
console.dir(e);
}
}
function buildAppData(){
fs.mkdirSync(buildPath);
fs.mkdirSync(buildPathClasses);
writeAppData()
.then(writeAppDataClasses)
.then(tidyUp);
}
function writeAppData(){
return new Promise(function writeAppDataP(resolve, reject){
var fileContents,
file;
try{
// base
fileContents = '<?php\n' +
'require_once("BaseAppData.inc");\n' +
'define ("PHI_LINKED", 1);\n' +
'define ("PHI_UNLINKED", 2);\n' +
'define ("PHI_NOPRIVILEGE", 3);\n\n';
// requires
Object.keys(subFunctionNames).sort().forEach(function appendSubClassRequire(file){
fileContents += 'require_once("./AppDataClasses/' + file + '");\n';
})
// class
fileContents += '\nclass AppData extends BaseAppData {\n\n' +
'\t\tfunction __construct() {\n';
// constructor
Object.keys(subFunctionNames).sort().forEach(function addMemberObjects(file){
fileContents += '\t\t\t\t$this->' + file.substr(0, file.indexOf('.')) + ' = new ' + file.substr(0, file.indexOf('.')) + '($this);\n';
});
fileContents += '\t\t}\n\n';
// member functions
for (file in subFunctionNames) {
fileContents += '\t\t// ' + file + '\n';
subFunctionNames[file].forEach(function addMemberFunctions(funcName){
fileContents += '\t\tpublic function ' + funcName + '(){ return $this->' + file.substr(0, file.indexOf('.')) + '->' + funcName + '(); }\n';
});
fileContents += '\n';
}
fileContents += '}\n';
fs.writeFile(buildPath + '/AppData.inc',
fileContents,
function(err) {
if (err) {
console.log(err);
reject();
return;
}
}
);
resolve();
} catch(e) {
console.dir(e);
throw e;
}
});
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment