diff --git a/index.js b/index.js index a2d6890..2378b0f 100755 --- a/index.js +++ b/index.js @@ -14,7 +14,7 @@ switch (argv.cmd) { log('targets:', targets) const folders = JSON.parse(argv.folders) log('folders:', folders) - packager.createVendorPackage(argv.profile, folders, targets) + packager.createVendorPackage(argv.profile, argv.context, folders, targets) break } diff --git a/lib/filter.js b/lib/filter.js index f0398fa..dead580 100644 --- a/lib/filter.js +++ b/lib/filter.js @@ -1,4 +1,5 @@ const excludedFilesList = ['.gitignore', '.DS_Store', '*.txt', 'manifest.js'] +const excludedFoldersList = ['instantAssets'] function excludedFiles(filename) { for (let str of excludedFilesList) { @@ -15,6 +16,13 @@ function excludedFiles(filename) { return false } +function excludedFolders() { + return { + filters: excludedFoldersList + } +} + module.exports = { - excludedFiles + excludedFiles, + excludedFolders } diff --git a/lib/manifest.js b/lib/manifest.js new file mode 100644 index 0000000..caa73b5 --- /dev/null +++ b/lib/manifest.js @@ -0,0 +1,128 @@ +const fs = require('fs-extra') +const RegEx = require('./regex') +const debug = require('@ff0000-ad-tech/debug') +let log = debug('cs-plugin-vendor-ft:manifest') + +let storedFtData = null +let storedImageMap = null + +function parseFtData(context, build) { + log('parseFtData()', context, build) + storedFtData = [] + storedImageMap = null + return new Promise((resolve, reject) => { + const pathFtData = context + '/' + build + '/common/js/data/FtData.js' + log('pathFtData:', pathFtData) + fs.readFile(pathFtData, 'utf8', (err, data) => { + const labelMatches = data.match(RegEx.ftDataTypes) + // log('labelMatches:', labelMatches.length) + // log(labelMatches) + + const dataMatches = data.split(RegEx.ftDataTypes) + dataMatches.shift() + // log('dataMatches:', dataMatches.length) + // log(dataMatches) + + for (let i = 0; i < labelMatches.length; i++) { + const labelType = labelMatches[i].slice(labelMatches[i].indexOf('-') + 1) + // log(' -> labelType:', labelType) + + if (labelType == 'end-keys') { + // skip + } else if (labelType == 'image-map') { + // strip comments + const singleData = dataMatches[i].replace(RegEx.lineComments, '') + const stripVar = singleData.substr(singleData.indexOf('{')) + // store for later use on a per size basis + storedImageMap = JSON.parse(stripVar) + } else { + let value = RegEx.ftDataValue.exec(dataMatches[i])[3] + value = value.slice(0, value.length - 1) // removes a trailing ' or " + storedFtData.push({ + type: labelType, + name: RegEx.ftDataNames.exec(dataMatches[i])[1], + default: value + }) + } + } + log(storedFtData) + + resolve() + }) + }) +} + +function parseFtDataImageMap(json, size) { + for (let key in storedImageMap) { + let val = '' + if (size in storedImageMap[key]) { + val = storedImageMap[key][size] + } else if ('default' in storedImageMap[key]) { + val = storedImageMap['default'] + } + json['instantAds'].push({ + type: 'image', + name: key, + default: val + }) + } +} + +function transform(dataRaw, buildData) { + // remove comments, TF.manifest( + + // UPDATE to use dotAll [\s\S] + let toStringJSON = dataRaw.replace(/\/\/.+/g, '').replace(/FT\.manifest\(/g, '') + + let index = toStringJSON.lastIndexOf('})') + log('index:', index) + toStringJSON = toStringJSON.substring(0, index + 1) + log('toStringJSON:', toStringJSON) + + let manifestJSON = JSON.parse(toStringJSON) + log(manifestJSON) + + // ---------------------------------------- + // update base properties + // if (adlabelType == TYPE_STANDARD || (adlabelType == TYPE_EXPANDABLE && self.is_collapsed(size['build_size'])): + // manifest_json['width'] = self.build_data['dimensions']['width'] + // manifest_json['height'] = self.build_data['dimensions']['height'] + // manifest_json['clickTagCount'] = len(self.settings.clicktags[size['deploy_size']]) + + // add rich-loads + manifestJSON['richLoads'].push({ + name: 'richloadBase', + src: buildData.directories.name['rich'] + }) + + // set instandAds-reference to richLoads + manifestJSON['instantAds'].push({ + name: 'richloadBase', + type: 'richLoad' + }) + + // if expandable, create a manifest node for the expanded params + // if (adlabelType == TYPE_EXPANDABLE && self.is_expanded(size['build_size'])) { + manifestJSON['expand'] = { + width: buildData['dimensions'][0], + height: buildData['dimensions'][1], + indentAcross: 0, + indentDown: 0 + } + // } + + // apply the FtData + storedFtData.forEach(target => { + manifestJSON['instantAds'].push(target) + }) + + // apply the imageMap + parseFtDataImageMap(manifestJSON, buildData['dimensions'].join('x')) + + return manifestJSON +} + +module.exports = { + parseFtData, + transform +} diff --git a/lib/packager.js b/lib/packager.js index aa379e8..41a6030 100755 --- a/lib/packager.js +++ b/lib/packager.js @@ -3,16 +3,16 @@ const path = require('path') const walk = require('walk') const JSZIP = require('jszip') const Utils = require('./utils') -const Filter = require('./filter') +const Manifest = require('./manifest') +const RegEx = require('./regex') const debug = require('@ff0000-ad-tech/debug') let log = debug('cs-plugin-vendor-ft:packager') -let buildData const TYPE_STANDARD = 'standard' const TYPE_EXPANDABLE = 'expandable' let skipPartners = [] -function createVendorPackage(profile, folders, targets) { +function createVendorPackage(profile, context, folders, targets) { log('createVendorPackage()') return new Promise((resolve, reject) => { // make the top level directory @@ -31,175 +31,126 @@ function createVendorPackage(profile, folders, targets) { const dirUploadBase = dirUpload + 'baseLoad/' fs.emptyDirSync(dirUploadBase) - // top level for each [size] folder - let masterPromises = [] - - Object.keys(targets).forEach(target => { - const buildData = {} - - // extract the [size] folder name - const filePath = '.' + targets[target] - const filePathSplit = filePath.split(path.sep) - filePathSplit.pop() - const folderName = filePathSplit.pop() - buildData['dimensions'] = folderName.match(/^([0-9]+)x([0-9]+)/g)[0].split('x') - - log(' folderName:', folderName) - log(' target:', target) - log(' filePath:', filePath) - - // get the ad type; then is expandable, set flag to skip the partner - - // project_name__deploy_profile__size - const dirOutputName = getUnderscored(folders.project) + '__' + getUnderscored(profile) + '__' + folderName - - buildData.directories = { - name: { - base: dirOutputName + '_FT_BASE', - rich: dirOutputName + '_FT_RICH' - }, - upload: { - base: dirUploadBase, - rich: dirUploadRich - }, - review: {} - } - - // REVIEW - buildData.directories.review['size'] = dirReview + folderName + '/' - fs.emptyDirSync(buildData.directories.review['size']) - - // RICH - buildData.directories.review['rich'] = buildData.directories.review['size'] + 'richLoads/' - fs.emptyDirSync(buildData.directories.review['rich']) - - buildData.directories.review['richStd'] = buildData.directories.review['rich'] + buildData.directories.name.rich + '/' - fs.emptyDirSync(buildData.directories.review['richStd']) - - let zipRich = new JSZIP() - masterPromises.push( - // copy the entire directory - Utils.copyDirectory(filePath, Filter.excludedFiles, buildData.directories.review['richStd'], './', zipRich).then(() => { - // return the promise of the zip save - return Utils.save(zipRich, buildData.directories.upload['rich'], buildData.directories.name['rich']) - }) - ) - - // BASE - buildData.directories.review['base'] = buildData.directories.review['size'] + 'baseLoad/' + buildData.directories.name.base + '/' - fs.emptyDirSync(buildData.directories.review['base']) - - let zipBase = new JSZIP() - let basePromises = [ - // index - new Promise((resolve, reject) => { - fs.readFile(path.join(__dirname, '../src') + '/ft_base_standard.html', 'utf8', (err, data) => { - // modify the index now: - data = data.replace(get_richload_base_css_regex, val => { - return val - .replace(get_width_css_regex, () => 'width: ' + buildData['dimensions'][0]) - .replace(get_height_css_regex, () => 'height: ' + buildData['dimensions'][1]) + // get FtData for later usage: + Manifest.parseFtData(context, folders.build).then(() => { + // top level for each [size] folder + let masterPromises = [] + + Object.keys(targets).forEach(target => { + const buildData = {} + + // extract the [size] folder name + const filePath = '.' + targets[target] + const filePathSplit = filePath.split(path.sep) + filePathSplit.pop() + const folderName = filePathSplit.pop() + buildData['dimensions'] = folderName.match(RegEx.dimension)[0].split('x') + + log(' folderName:', folderName) + log(' target:', target) + log(' filePath:', filePath) + + // get the ad type; then is expandable, set flag to skip the partner + + // project_name__deploy_profile__size + const dirOutputName = Utils.getUnderscored(folders.project) + '__' + Utils.getUnderscored(profile) + '__' + folderName + + buildData.directories = { + name: { + base: dirOutputName + '_FT_BASE', + rich: dirOutputName + '_FT_RICH' + }, + upload: { + base: dirUploadBase, + rich: dirUploadRich + }, + review: {} + } + + // REVIEW + buildData.directories.review['size'] = dirReview + folderName + '/' + fs.emptyDirSync(buildData.directories.review['size']) + + // RICH + buildData.directories.review['rich'] = buildData.directories.review['size'] + 'richLoads/' + fs.emptyDirSync(buildData.directories.review['rich']) + + buildData.directories.review['richStd'] = buildData.directories.review['rich'] + buildData.directories.name.rich + '/' + fs.emptyDirSync(buildData.directories.review['richStd']) + + let zipRich = new JSZIP() + masterPromises.push( + // copy the entire directory + Utils.copyDirectory(filePath, buildData.directories.review['richStd'], './', zipRich).then(() => { + // return the promise of the zip save + return Utils.save(zipRich, buildData.directories.upload['rich'], buildData.directories.name['rich']) + }) + ) + + // BASE + buildData.directories.review['base'] = buildData.directories.review['size'] + 'baseLoad/' + buildData.directories.name.base + '/' + fs.emptyDirSync(buildData.directories.review['base']) + + let zipBase = new JSZIP() + let basePromises = [ + // index + new Promise((resolve, reject) => { + fs.readFile(path.join(__dirname, '../src') + '/ft_base_standard.html', 'utf8', (err, data) => { + // modify the index now: + data = data.replace(RegEx.cssRichLoadBase, val => { + return val + .replace(RegEx.cssWidth, () => 'width: ' + buildData['dimensions'][0]) + .replace(RegEx.cssHeight, () => 'height: ' + buildData['dimensions'][1]) + }) + + // write into the zip + zipBase.file('index.html', data) + + // write into review + fs.writeFile(buildData.directories.review['base'] + 'index.html', data, err => { + if (err) reject() + }) + + resolve() }) - - // write into the zip - zipBase.file('index.html', data) - - // write into review - fs.writeFile(buildData.directories.review['base'] + 'index.html', data, err => { - if (err) reject() + }), + // manifest.js + new Promise((resolve, reject) => { + fs.readFile(filePath + 'manifest.js', 'utf8', (err, dataRaw) => { + const manifestJSON = Manifest.transform(dataRaw, buildData) + // get the image map data + const backToString = 'FT.manifest(' + JSON.stringify(manifestJSON) + ')' + + // write into the zip + zipBase.file('manifest.js', backToString) + + // write into review + fs.writeFile(buildData.directories.review['base'] + 'manifest.js', backToString, err => { + if (err) reject() + }) + + resolve() }) - - resolve() }) - }), - // manifest.js - new Promise((resolve, reject) => { - fs.readFile(filePath + 'manifest.js', 'utf8', (err, dataRaw) => { - const manifestJSON = transformManifest(dataRaw, buildData) - const backToString = 'FT.manifest(' + JSON.stringify(manifestJSON) + ')' - - // write into the zip - zipBase.file('manifest.js', backToString) - - // write into review - fs.writeFile(buildData.directories.review['base'] + 'manifest.js', backToString, err => { - if (err) reject() - }) - - resolve() + ] + masterPromises.push( + Promise.all(basePromises).then(() => { + return Utils.save(zipBase, buildData.directories.upload['base'], buildData.directories.name['base']) }) - }) - ] - masterPromises.push( - Promise.all(basePromises).then(() => { - return Utils.save(zipBase, buildData.directories.upload['base'], buildData.directories.name['base']) - }) - ) - - log(buildData) - }) + ) - Promise.all(masterPromises).then(() => { - log('ALL SIZE ZIPS CREATED') - skipPartners = [] - resolve() - }) - }) -} - -function transformManifest(dataRaw, buildData) { - // remove comments, TF.manifest( - let toStringJSON = dataRaw.replace(/\/\/.+/g, '').replace(/FT\.manifest\(/g, '') - - let index = toStringJSON.lastIndexOf('})') - log('index:', index) - toStringJSON = toStringJSON.substring(0, index + 1) - log('toStringJSON:', toStringJSON) - - let manifestJSON = JSON.parse(toStringJSON) - log(manifestJSON) - - // ---------------------------------------- - // update base properties - // if (ad_type == TYPE_STANDARD || (ad_type == TYPE_EXPANDABLE && self.is_collapsed(size['build_size'])): - // manifest_json['width'] = self.build_data['dimensions']['width'] - // manifest_json['height'] = self.build_data['dimensions']['height'] - // manifest_json['clickTagCount'] = len(self.settings.clicktags[size['deploy_size']]) - - // add rich-loads - manifestJSON['richLoads'].push({ - name: 'richloadBase', - src: buildData.directories.name['rich'] - }) + log(buildData) + }) - // set instandAds-reference to richLoads - manifestJSON['instantAds'].push({ - name: 'richloadBase', - type: 'richLoad' + Promise.all(masterPromises).then(() => { + log('ALL SIZE ZIPS CREATED') + skipPartners = [] + resolve() + }) + }) }) - - // if expandable, create a manifest node for the expanded params - // if (ad_type == TYPE_EXPANDABLE && self.is_expanded(size['build_size'])) { - manifestJSON['expand'] = { - width: buildData['dimensions'][0], - height: buildData['dimensions'][1], - indentAcross: 0, - indentDown: 0 - } - // } - - return manifestJSON -} - -function getUnderscored(str) { - return str.replace(/(\s|\-)/g, '_') } -const get_richload_base_css_regex = /#richload-base\s*\{[^\}]+\}/g -const get_richload_expand_css_regex = /#richload-expand\s*\{[^\}]+\}/g -const get_width_css_regex = /(width\:\s*)[0-9]+/ -const get_height_css_regex = /(height\:\s*)[0-9]+/ - module.exports = { createVendorPackage } diff --git a/lib/regex.js b/lib/regex.js new file mode 100644 index 0000000..88bc7fc --- /dev/null +++ b/lib/regex.js @@ -0,0 +1,25 @@ +const cssHeight = /(height\:\s*)[0-9]+/ +const cssWidth = /(width\:\s*)[0-9]+/ +const cssRichLoadBase = /#richload-base\s*\{[^\}]+\}/g +const cssRichLoadExpand = /#richload-expand\s*\{[^\}]+\}/g +const dimension = /^([0-9]+)x([0-9]+)/g + +const blockComments = /\/\*(.|[\s\s])*?(\*\/)/g +const lineComments = /[^\n\S]*\/\/[^\/\n][^\n]*/gm + +const ftDataTypes = /\/\/\s*@ft\-[\s\S].+/g +const ftDataNames = /instantAds[\.\[\"\'\s]+([^\.\[\"\'\s]+)/g +const ftDataValue = /\|\|([^\"\']*)([\"\'])((?:[^\2\\]|\\.)*?\2)/g + +module.exports = { + blockComments, + cssHeight, + cssWidth, + cssRichLoadBase, + cssRichLoadExpand, + dimension, + ftDataTypes, + ftDataNames, + ftDataValue, + lineComments +} diff --git a/lib/utils.js b/lib/utils.js index fdb6ae5..8fabd5e 100644 --- a/lib/utils.js +++ b/lib/utils.js @@ -2,24 +2,27 @@ const fs = require('fs-extra') const path = require('path') const walk = require('walk') const JSZIP = require('jszip') +const Filter = require('./filter') const debug = require('@ff0000-ad-tech/debug') -let log = debug('cs-plugin-vendor-ft:packager') +let log = debug('cs-plugin-vendor-ft:utils') -function copyDirectory(from, filters, toReview, toUpload, zip) { +function getUnderscored(str) { + return str.replace(/(\s|\-)/g, '_') +} + +function copyDirectory(from, toReview, toUpload, zip) { return new Promise((resolve, reject) => { walk - .walk(from, { - filters: ['instantAssets'] - }) + .walk(from, Filter.excludedFolders()) .on('file', (root, stat, next) => { - if (filters.call(this, stat.name)) { + if (Filter.excludedFiles(stat.name)) { // skip the excluded files next() } else { fs.readFile(root + '/' + stat.name, (err, data) => { // remove the base file path to get just the directores to copy over let baseFolder = '.' + String(root).substr(from.length) + '/' - log('file:', stat.name, '| root:', root, '| baseFolder:', baseFolder) + // log('file:', stat.name, '| root:', root, '| baseFolder:', baseFolder) fs.writeFile((toReview || from) + baseFolder + stat.name, data) @@ -58,6 +61,7 @@ function save(zip, path, name) { } module.exports = { + getUnderscored, copyDirectory, save }