purgetss
Version:
A package that simplifies mobile app creation for Titanium developers.
720 lines (618 loc) • 30.2 kB
JavaScript
'use_strick'
let saveGlossary = false
const fs = require('fs')
const cwd = process.cwd()
const _ = require('lodash')
const path = require('path')
const chalk = require('chalk')
const colores = require('../lib/colores').colores
module.exports.colores = colores
const purgeLabel = colores.purgeLabel
const projectsConfigJS = cwd + '/purgetss/config.js'
const logger = {
info: (...args) => console.log(purgeLabel, args.join(' ')),
warn: (...args) => console.log(purgeLabel, chalk.yellow(args.join(' '))),
error: (...args) => console.log(purgeLabel, chalk.red(args.join(' '))),
file: (...args) => console.log(purgeLabel, chalk.yellow(args.join(' ')), 'file created!')
}
const helpers = require('../lib/helpers')
const tiCompletionsFile = require('../lib/completions/titanium/completions-v3.json')
const srcConfigFile = path.resolve(__dirname, '../lib/templates/purgetss.config.js')
const configFile = (fs.existsSync(projectsConfigJS)) ? require(projectsConfigJS) : require(srcConfigFile)
configFile.purge = configFile.purge ?? { mode: 'all' }
configFile.theme.extend = configFile.theme.extend ?? {}
const configOptions = (configFile.purge && configFile.purge.options) ? configFile.purge.options : {}
if (configOptions) {
configOptions.plugins = configOptions.plugins ?? []
configOptions.safelist = configOptions.safelist ?? []
configOptions.missing = configOptions.missing ?? true
configOptions.widgets = configOptions.widgets ?? false
}
function autoBuildTailwindTSS(options = {}) {
saveGlossary = options.glossary ?? false
let tailwindStyles = fs.readFileSync(path.resolve(__dirname, '../lib/templates/tailwind/template.tss'), 'utf8')
tailwindStyles += fs.readFileSync(path.resolve(__dirname, '../lib/templates/tailwind/custom-template.tss'), 'utf8')
tailwindStyles += (fs.existsSync(projectsConfigJS)) ? `// config.js file updated on: ${getFileUpdatedDate(projectsConfigJS)}\n` : '// default config.js file\n'
const baseValues = combineDefaultThemeWithConfigFile()
const completionsPropertiesWithBaseValues = setBaseValuesToProperties(getPropertiesFromTiCompletionsFile(), baseValues)
const tiUIComponents = getTiUIComponents(baseValues)
tailwindStyles += processTitaniumRules(tiUIComponents)
tailwindStyles += processCustomClasses()
tailwindStyles += processCompoundClasses(baseValues)
tailwindStyles += processCompletionsClasses(completionsPropertiesWithBaseValues)
tailwindStyles = helpers.compileApplyDirectives(tailwindStyles)
if (fs.existsSync(projectsConfigJS)) {
makeSureFolderExists(cwd + '/purgetss/styles/')
saveFile(cwd + '/purgetss/styles/tailwind.tss', tailwindStyles)
logger.file('./purgetss/styles/tailwind.tss')
} else {
saveFile(path.resolve(__dirname, '../dist/tailwind.tss'), tailwindStyles)
logger.file('./dist/tailwind.tss')
}
}
exports.autoBuildTailwindTSS = autoBuildTailwindTSS
function processCustomClasses() {
let tailwindStyles = ''
if (Object.keys(configFile.theme).length) {
_.each(configFile.theme, (value, key) => {
if (key !== 'extend') {
const theClasses = helpers.customRules(value, key)
tailwindStyles += theClasses
}
})
}
if (tailwindStyles !== '') return `\n// Custom Classes\n${tailwindStyles}// End of Custom Classes\n`
return ''
}
function processTitaniumRules(_propertiesOnly) {
const currentLegacyOption = helpers.globalOptions.legacy
helpers.globalOptions.legacy = true
let customRules = '\n// Ti Elements'
_.each(_propertiesOnly, (value, key) => {
const property = `\n// Property: ${key}\n`
const description = `// Description: ${value.description.replace(/\n/g, ' ')}\n`
customRules += property + description + helpers.customRules(value.base, key)
})
helpers.globalOptions.legacy = currentLegacyOption
if (customRules !== '\n// Ti Elements\n') return customRules
return ''
}
function processCompletionsClasses(_completionsWithBaseValues) {
let processedClasses = ''
_.each(_completionsWithBaseValues, (data, key) => {
const theClasses = generateCombinedClasses(key, data)
if (theClasses) {
generateGlossary(key, theClasses, data)
processedClasses += theClasses
}
})
return processedClasses
}
function generateGlossary(_key, _theClasses, _keyName = null) {
let baseDestinationFolder = ''
if (!fs.existsSync(projectsConfigJS)) baseDestinationFolder = path.resolve(__dirname, '../dist/glossary/')
else if (saveGlossary) baseDestinationFolder = cwd + '/purgetss/glossary/'
if (baseDestinationFolder !== '') {
makeSureFolderExists(baseDestinationFolder)
let destinationFolder = ''
if (_keyName) {
if (_key.includes('color') || _key.includes('Color') || _key.includes('colors') || _key === 'tint') {
destinationFolder = baseDestinationFolder + '/colorProperties'
} else if (Object.entries(_keyName.base).length) {
destinationFolder = baseDestinationFolder + '/configurableProperties'
} else if (_keyName.type === 'Boolean') {
destinationFolder = baseDestinationFolder + '/booleanProperties'
} else {
destinationFolder = baseDestinationFolder + '/constantProperties'
}
} else {
if (_key.includes('color') || _key.includes('Color') || _key.includes('colors')) {
destinationFolder = baseDestinationFolder + '/colorProperties'
} else {
destinationFolder = baseDestinationFolder + '/compoundClasses'
}
}
makeSureFolderExists(destinationFolder)
saveFile(`${destinationFolder}/${_key}.md`, '```css' + _theClasses + '```')
}
return _theClasses
}
function setBaseValuesToProperties(_allProperties, _base) {
let allKeys = ''
_.each(_allProperties, (data, key) => {
const activeKey = findBaseKey(key, data)
allKeys += `${key}\n`
_allProperties[key].base = combineKeys(configFile.theme, _base[key] ?? _base[activeKey], key)
})
return _allProperties
}
function getTiUIComponents(_base) {
const propertiesOnly = {}
_.each(tiCompletionsFile.types, (value, key) => {
if (key.includes('Ti.UI.') || key.includes('Ti.Android.')) {
const _key = key.replace('Ti.UI.', '').replace('Ti.Android.', '')
const combinedKeys = combineKeys(configFile.theme, _base[_key], _key)
if (combinedKeys) {
delete configFile.theme[_key]
if (!propertiesOnly[_key] && Object.keys(combinedKeys).length) {
propertiesOnly[_key] = {
base: combinedKeys,
description: value.description
}
}
}
}
})
return propertiesOnly
}
function processCompoundClasses({ ..._base }) {
let compoundClasses = ''
const compoundTemplate = require('../lib/templates/tailwind/compoundTemplate.json')
_.each(compoundTemplate, (value, key) => {
compoundClasses += generateGlossary(key, helpers.processProperties(value.description, value.template, value.base ?? { default: _base[key] }))
})
// Fixed values
compoundClasses += generateGlossary('anchorPoint', helpers.anchorPoint())
compoundClasses += generateGlossary('autocapitalization-alternative', helpers.autocapitalization())
compoundClasses += generateGlossary('backgroundGradient-linear', helpers.backgroundLinearGradient())
compoundClasses += generateGlossary('backgroundGradient-radial', helpers.backgroundRadialGradient())
compoundClasses += generateGlossary('clipMode', helpers.clipMode())
compoundClasses += generateGlossary('constraint', helpers.constraint())
compoundClasses += generateGlossary('content-height-and-width', helpers.contentHeightAndWidth())
compoundClasses += generateGlossary('curve-alternative', helpers.curve())
compoundClasses += generateGlossary('defaultItemTemplate', helpers.defaultItemTemplate())
compoundClasses += generateGlossary('displayCaps', helpers.displayCaps())
compoundClasses += generateGlossary('draggingType', helpers.draggingType())
compoundClasses += generateGlossary('dropShadow', helpers.dropShadow())
compoundClasses += generateGlossary('ellipsize-alternative', helpers.ellipsize())
compoundClasses += generateGlossary('filterAttribute', helpers.filterAttribute())
compoundClasses += generateGlossary('flip', helpers.flip())
compoundClasses += generateGlossary('fontStyle', helpers.fontStyle())
compoundClasses += generateGlossary('grid-cols-rows-span', helpers.gridColumnsRowsStartEnd())
compoundClasses += generateGlossary('gridFlow', helpers.gridFlow())
compoundClasses += generateGlossary('gridSystem', helpers.gridSystem())
compoundClasses += generateGlossary('items', helpers.items())
compoundClasses += generateGlossary('navigationMode', helpers.navigationMode())
compoundClasses += generateGlossary('orientationModes', helpers.orientationModes())
compoundClasses += generateGlossary('placement', helpers.placement())
compoundClasses += generateGlossary('progressBarStyle', helpers.progressBarStyle())
compoundClasses += generateGlossary('scrollType', helpers.scrollType())
compoundClasses += generateGlossary('showScrollIndicators', helpers.scrollIndicators())
compoundClasses += generateGlossary('statusBarStyle-alternative', helpers.statusBarStyle())
compoundClasses += generateGlossary('theme', helpers.theme())
compoundClasses += generateGlossary('tiMedia', helpers.tiMedia(false))
compoundClasses += generateGlossary('titleAttributesShadow-alternative', helpers.titleAttributesShadow())
compoundClasses += generateGlossary('toggle', helpers.toggle())
compoundClasses += generateGlossary('touchEnabled-alternative', helpers.touchEnabled())
compoundClasses += generateGlossary('viewShadowOffset', helpers.viewShadowV6())
compoundClasses += generateGlossary('visible-alternative', helpers.visible())
// ! Configurables
compoundClasses += generateGlossary('borderRadius-alternative', helpers.borderRadius(_base.borderRadius))
compoundClasses += generateGlossary('borderRadius-full', helpers.borderRadiusFull(_base.borderRadius))
compoundClasses += generateGlossary('fontFamily', helpers.fontFamily(_base.fontFamily))
compoundClasses += generateGlossary('fontSize', helpers.fontSize(_base.fontSize))
compoundClasses += generateGlossary('fontWeight', helpers.fontWeight(_base.fontWeight))
compoundClasses += generateGlossary('margin-alternative', helpers.gap(_base.margin))
compoundClasses += generateGlossary('minimumFontSize', helpers.minimumFontSize(_base.fontSize))
compoundClasses += generateGlossary('padding-alternative', helpers.padding(_base.padding))
compoundClasses += generateGlossary('rotate-negative-values', helpers.negativeRotate(_base.rotate))
compoundClasses += generateGlossary('zoom-in-out', helpers.zoomIn(_base.scale))
compoundClasses += generateGlossary('widthHeight', helpers.widthHeight(_base.widthHeight))
compoundClasses += generateGlossary('size', helpers.size(_base.size))
// ! colors
compoundClasses += generateGlossary('backgroundGradient', helpers.backgroundGradient(combineKeys(configFile.theme, _base.colors, 'backgroundGradient')))
compoundClasses += generateGlossary('backgroundSelectedGradient', helpers.backgroundSelectedGradient(combineKeys(configFile.theme, _base.colors, 'backgroundSelectedGradient')))
compoundClasses += generateGlossary('color-alternative', helpers.textColor(_base.textColor))
compoundClasses += generateGlossary('hintTextColor', helpers.placeholder(combineKeys(configFile.theme, _base.colors, 'hintTextColor')))
// compoundClasses += generateGlossary('tint', helpers.tint(combineKeys(configFile.theme, _base.colors, 'tint')))
compoundClasses += generateGlossary('tintColor', helpers.tintColor(combineKeys(configFile.theme, _base.colors, 'tintColor')))
compoundClasses += generateGlossary('titleAttributes-color', helpers.titleAttributesColor(combineKeys(configFile.theme, _base.colors, 'titleAttributesColor')))
compoundClasses += generateGlossary('titleAttributes-shadow-color', helpers.titleAttributesShadowColor(combineKeys(configFile.theme, _base.colors, 'titleAttributesShadowColor')))
return compoundClasses
}
function findBaseKey(_key, _data) {
if (_key.includes('color') || _key.includes('Color') || _key === 'tint') {
return 'colors'
} else if (_key.includes('spacing') || _key.includes('Spacing')) {
return 'spacing'
} else if (_key === 'duration' || _key === 'timeout' || _key.includes('Timeout')) {
return 'delay'
} else if (_key === 'pagingControlAlpha') {
return 'opacity'
} else if (_key === 'lines' || _key === 'columnCount' || _key === 'rowCount' || _key === 'repeatCount' || _key === 'maxLines') {
return 'count' // 1-12
} else if (_key === 'activeTab' || _key === 'cacheSize') {
return 'repeat' // 0-12
} else if (((_key.includes('scale') || _key.includes('Scale')) && _data.type !== 'Boolean')) {
return 'scale'
} else if (_key === 'shadowRadius' || _key === 'separatorHeight' || _key.includes('RowHeight') || _key === 'rowHeight' || _key === 'elevation' || _key === 'maxElevation' || _key === 'indentionLevel' || _key === 'keyboardToolbarHeight' || _key === 'maximumLineHeight' || _key === 'yOffset' || _key === 'xOffset' || _key === 'pagingControlHeight' || _key === 'pageWidth' || _key === 'pageHeight' || _key === 'uprightWidth' || _key === 'uprightHeight' || _key === 'backgroundLeftCap' || _key === 'backgroundTopCap' || _key === 'contentWidth' || _key === 'contentHeight' || ((_key.includes('Padding') || _key.includes('padding') || _key === 'leftTrackLeftCap' || _key === 'leftTrackTopCap' || _key === 'rightTrackLeftCap' || _key === 'rightTrackTopCap') && _data.type !== 'Boolean')) {
return 'noFractions'
} else if (_key === 'top' || _key === 'bottom' || _key === 'left' || _key === 'right') {
return 'margin'
} else if ((_key.includes('height') || _key.includes('Height')) && _key !== 'platformHeight') {
return 'height'
} else if ((_key.includes('width') || _key.includes('Width')) && _key !== 'platformWidth') {
return 'width'
} else if (_key === 'shiftMode') {
return 'shiftMode'
}
return _key
}
function combineDefaultThemeWithConfigFile() {
const defaultColors = require('tailwindcss/colors')
const defaultTheme = require('tailwindcss/defaultTheme')
const defaultThemeWidth = defaultTheme.width({ theme: () => (defaultTheme.spacing) })
const defaultThemeHeight = defaultTheme.height({ theme: () => (defaultTheme.spacing) })
const defaultThemeSize = defaultTheme.size({ theme: () => (defaultTheme.spacing) })
removeDeprecatedColors(defaultColors)
const tiResets = { full: '100%' }
const allWidthsCombined = (configFile.theme.spacing) ? { ...configFile.theme.spacing, ...tiResets } : { ...defaultThemeWidth }
const allHeightsCombined = (configFile.theme.spacing) ? { ...configFile.theme.spacing, ...tiResets } : { ...defaultThemeHeight }
const allSpacingCombined = (configFile.theme.spacing) ? { ...configFile.theme.spacing, ...tiResets } : { ...defaultThemeWidth, ...defaultThemeHeight }
const allSizesCombined = (configFile.theme.spacing) ? { ...configFile.theme.spacing, ...tiResets } : { ...defaultThemeSize }
const themeOrDefaultValues = {
width: configFile.theme.width ?? allWidthsCombined,
height: configFile.theme.height ?? allHeightsCombined,
spacing: configFile.theme.spacing ?? allSpacingCombined,
size: configFile.theme.spacing ?? allSizesCombined,
fontSize: configFile.theme.spacing ?? defaultTheme.fontSize,
minimumFontSize: configFile.theme.spacing ?? defaultTheme.minimumFontSize,
colors: configFile.theme.colors ?? { transparent: 'transparent', ...defaultColors }
}
removeUnnecesaryValues(themeOrDefaultValues)
fixDefaultScale(defaultTheme.scale)
const base = {
colors: {},
spacing: {},
size: {},
width: {},
height: {},
widthHeight: {},
boolean: { default: true, false: false },
shiftMode: { none: 0, title: 1, icon: 2 },
rotate: combineKeys(configFile.theme, { ...defaultTheme.rotate, ...{ 135: '135deg', 225: '225deg', 270: '270deg', 315: '315deg', 360: '360deg' } }, 'rotate'),
zIndex: defaultTheme.zIndex,
opacity: defaultTheme.opacity,
fontWeight: defaultTheme.fontWeight,
borderWidth: combineKeys(configFile.theme, { ...removePxFromDefaultTheme(defaultTheme.borderWidth), ...{ 0: 0, 1: 1, 2: 2, 3: 3, 4: 4, 5: 5, 6: 6, 7: 7, 8: 8, 9: 9, 10: 10, 11: 11, 12: 12 } }, 'borderWidth'),
fontSize: { ...themeOrDefaultValues.fontSize, ...configFile.theme.extend.spacing, ...configFile.theme.extend.fontSize },
minimumFontSize: { ...themeOrDefaultValues.minimumFontSize, ...configFile.theme.extend.spacing, ...configFile.theme.extend.minimumFontSize },
verticalMargin: { top: '-0.5', bottom: '0.5', middle: '0' },
horizontalMargin: { left: '-0.5', right: '0.5', center: '0' },
scale: { ...{ 1: '0.01', 5: '0.05', 10: '0.10', 25: '0.25', 200: 2 }, ...defaultTheme.scale },
moveByProperties: { default: true, false: false },
moveByAnimate: { default: true, false: false },
moveByAnimation: { default: true, false: false },
repeat: { 0: 0, 1: 1, 2: 2, 3: 3, 4: 4, 5: 5, 6: 6, 7: 7, 8: 8, 9: 9, 10: 10, 11: 11, 12: 12 },
count: { 1: 1, 2: 2, 3: 3, 4: 4, 5: 5, 6: 6, 7: 7, 8: 8, 9: 9, 10: 10, 11: 11, 12: 12 },
delay: { ...{ 0: '0ms', 25: '25ms', 50: '50ms', 250: '250ms', 350: '350ms', 400: '400ms', 450: '450ms', 600: '600ms', 800: '800ms', 900: '900ms', 2000: '2000ms', 3000: '3000ms', 4000: '4000ms', 5000: '5000ms' }, ...defaultTheme.transitionDelay }
}
_.merge(base.colors, themeOrDefaultValues.colors, configFile.theme.extend.colors)
_.merge(base.size, themeOrDefaultValues.spacing, configFile.theme.extend.spacing)
_.merge(base.spacing, themeOrDefaultValues.spacing, configFile.theme.extend.spacing)
_.merge(base.width, themeOrDefaultValues.spacing, configFile.theme.extend.spacing, themeOrDefaultValues.width, configFile.theme.extend.width)
_.merge(base.height, themeOrDefaultValues.spacing, configFile.theme.extend.spacing, themeOrDefaultValues.height, configFile.theme.extend.height)
_.merge(base.widthHeight, base.width, base.height)
fixPercentages(base.size)
fixPercentages(base.width)
fixPercentages(base.height)
fixPercentages(base.spacing)
// fixfontSize(base.fontSize);
// ! Extras...
base.transitionDuration = { ...base.delay, ...defaultTheme.transitionDuration }
base.fontFamily = combineKeys(configFile.theme, {}, 'fontFamily')
base.fontSize = combineKeys(configFile.theme, base.fontSize, 'fontSize')
base.fontWeight = combineKeys(configFile.theme, defaultTheme.fontWeight, 'fontWeight')
base.textColor = combineKeys(configFile.theme, base.colors, 'textColor')
base.margin = combineKeys(configFile.theme, base.spacing, 'margin')
base.padding = combineKeys(configFile.theme, helpers.removeFractions(base.spacing, ['full', 'auto', 'screen']), 'padding')
base.countDownDuration = { ...base.delay, ...defaultTheme.transitionDuration }
base.noFractions = helpers.removeFractions(base.spacing, ['full', 'auto', 'screen'])
base.minimumFontSize = combineKeys(configFile.theme, base.fontSize, 'minimumFontSize')
// combineKeys(configFile.theme, (configFile.theme.spacing || configFile.theme.borderRadius) ? {} : { ...defaultTheme.borderRadius, ...base.spacing }, 'borderRadius');
base.borderRadius = helpers.processBorderRadius(helpers.removeFractions((configFile.theme.spacing || configFile.theme.borderRadius) ? {} : { ...defaultTheme.borderRadius, ...base.spacing }, ['full', 'auto', 'screen']))
_.each(base, (_value, key) => {
delete configFile.theme[key]
})
base.margin.auto = 'null'
delete base.margin.screen
delete base.zIndex.auto
// ! Process custom Window, View and ImageView
base.Window = (configFile.theme.Window && configFile.theme.Window.apply)
? _.merge({ apply: configFile.theme.Window.apply }, configFile.theme.Window)
: _.merge({ default: { backgroundColor: '#FFFFFF' } }, configFile.theme.Window)
base.ImageView = (configFile.theme.ImageView && configFile.theme.ImageView.apply)
? _.merge({ apply: configFile.theme.ImageView.apply }, { ios: { hires: true } }, configFile.theme.ImageView)
: _.merge({ ios: { hires: true } }, configFile.theme.ImageView)
base.View = (configFile.theme.View && configFile.theme.View.apply)
? _.merge({ apply: configFile.theme.View.apply }, configFile.theme.View)
: _.merge({ default: { width: 'Ti.UI.SIZE', height: 'Ti.UI.SIZE' } }, configFile.theme.View)
// !Delete plugins specified in the config file
const deletePlugins = checkDeletePlugins()
_.each(deletePlugins, value => {
delete base[value]
delete configFile.theme[value]
delete configFile.theme.extend[value]
})
return base
}
function checkDeletePlugins() {
const deletePlugins = configFile.plugins ?? configOptions.plugins
return Array.isArray(deletePlugins) ? deletePlugins : Object.keys(deletePlugins).map(key => key)
}
// ! Helper Functions
function removeDeprecatedColors(theObject) {
delete theObject.blueGray
delete theObject.coolGray
delete theObject.current
delete theObject.inherit
delete theObject.lightBlue
delete theObject.trueGray
delete theObject.warmGray
}
function removeUnnecesaryValues(theObject) {
delete theObject.width.fit
delete theObject.width.max
delete theObject.width.min
delete theObject.width.svw
delete theObject.width.lvw
delete theObject.width.dvw
delete theObject.height.fit
delete theObject.height.max
delete theObject.height.min
delete theObject.height.svh
delete theObject.height.lvh
delete theObject.height.dvh
delete theObject.spacing.fit
delete theObject.spacing.max
delete theObject.spacing.min
delete theObject.spacing.svw
delete theObject.spacing.lvw
delete theObject.spacing.dvw
delete theObject.spacing.svh
delete theObject.spacing.lvh
delete theObject.spacing.dvh
}
function fixPercentages(theObject) {
_.each(theObject, (value, key) => {
if (value.toString().includes('.333333%')) theObject[key] = value.replace('.333333%', '.333334%')
})
}
function removePxFromDefaultTheme(theObject) {
_.each(theObject, (value, key) => {
if (value.toString().includes('px')) theObject[key] = value.replace('px', '')
})
return theObject
}
function fixfontSize(theObject) {
_.each(theObject, value => {
if (value.length > 1) value.pop()
})
}
function combineKeys(values, base, key) {
return (values[key]) ? { ...values[key], ...values.extend[key] } : { ...base, ...values.extend[key] }
}
function getPropertiesFromTiCompletionsFile() {
const propertiesOnly = {}
const properties = [
// ! Deprecated or Custom Process
'handlePlatformUrl',
'hidden',
// 'selectionIndicator',
'semanticColorType',
'splitActionBar',
'supported',
'tabsTintColor',
'tintColor',
'unselectedItemTintColor',
'wordWrap',
// ! Readonly
'activationState',
'animating',
'batteryState',
'DIST_ADHOC',
'DIST_STORE',
'ENV_DEV',
'ENV_DEVELOPMENT',
'ENV_PROD',
'ENV_PRODUCTION',
'ENV_TEST',
'externalPlaybackActive',
'focused',
'hasContentPending',
'isActivated',
'isAdvertisingTrackingEnabled',
'isComplicationEnabled',
'isPaired',
'isReachable',
'isSupported',
'isWatchAppInstalled',
'landscape',
'muted',
'orientation',
'OS_ANDROID',
'OS_IOS',
'paused',
'playing',
'portrait',
'safeAreaPadding',
'specified',
'waiting',
// ! fs. properties
'bigint',
'executable',
'force',
'readonly',
'recursive',
'remoteBackup',
'symbolicLink',
'withFileTypes',
'writable',
'UIApplicationOpenURLOptionsOpenInPlaceKey',
'UIApplicationOpenURLOptionUniversalLinksOnly',
// ! Handled by Purge TSS
'fontFamily',
'fontSize',
'fontWeight',
'minimumFontSize',
'orientationModes',
'size',
'textColor'
]
_.each(tiCompletionsFile.types, (value, key) => {
_.each(value.properties, property => {
if (validTypesOnly(property, key) && !properties.includes(property)) {
if (!propertiesOnly[property]) {
propertiesOnly[property] = tiCompletionsFile.properties[property]
propertiesOnly[property].modules = []
}
propertiesOnly[property].modules.push(key)
}
})
})
return propertiesOnly
}
function getFileUpdatedDate(_path) {
return fs.statSync(_path).mtime
}
function saveFile(file, data) {
fs.writeFileSync(file, data, err => {
throw err
})
}
function validTypesOnly(property, key) {
return key.includes('Ti.UI.') ||
tiCompletionsFile.properties[property].type === 'Boolean' ||
tiCompletionsFile.properties[property].type === 'Point' ||
tiCompletionsFile.properties[property].type === 'Number' ||
tiCompletionsFile.properties[property].type === 'Array' ||
tiCompletionsFile.properties[property].type === 'String'
}
function fixDefaultScale(values) {
_.each(values, (value, key) => {
if (value.startsWith('.')) values[key] = '0' + value
})
return values
}
function processComments(key, data) {
let myComments = ''
myComments += `\n// Property: ${key}`
if (data.description) myComments += `\n// Description: ${data.description.replace(/\n/g, ' ').replace(/<code>|<\/code>/g, '').replace(/<strong>|<\/strong>/g, '').replace(/<em>|<\/em>/g, '').replace(/<a[^>]*>|<\/a>/g, '')}`
if (data.modules) myComments += `\n// Component(s): ${data.modules.join(', ')}\n`
return myComments
}
function generateCombinedClasses(key, data) {
let myClasses = ''
const comments = processComments(key, data)
if (Object.entries(data.base).length) {
_.each(data.base, (value, _key) => {
if (typeof value === 'object') {
_.each(value, (_value, __key) => {
myClasses += `'.${setModifier(removeUneededVariablesFromPropertyName(camelCaseToDash(key + '-' + _key + '-' + __key)))}': { ${key}: ${helpers.parseValue(_value)} }\n`
})
} else {
myClasses += `'.${setModifier(removeUneededVariablesFromPropertyName(camelCaseToDash(key + '-' + _key)))}': { ${key}: ${helpers.parseValue(value)} }\n`
}
})
} else {
_.each(data.values, (_value, _key) => {
if (!_value.includes('deprecated')) myClasses += formatClass(key, _value)
})
}
if (myClasses !== '') return comments + myClasses
return false
}
function saveAutoTSS(key, classes) {
if (fs.existsSync(projectsConfigJS) && saveGlossary) {
makeSureFolderExists(cwd + '/purgetss/experimental/tailwind-classes/')
saveFile(cwd + `/purgetss/experimental/tailwind-classes/${key}.tss`, classes)
}
}
function formatClass(key, value) {
return `'.${formatClassName(key, value)}': { ${key}: ${value} }\n`
}
function formatClassName(property, value) {
return setModifier(removeUneededVariablesFromPropertyName(camelCaseToDash(`${property}-${removeModuleName(value, property)}`)))
}
function removeUneededVariablesFromPropertyName(property) {
return Array.from(new Set(property.split('-')))
.join('-')
// .replace('-ti-platform-android', '')
// .replace('-android', '')
.replace('-default', '')
.replace('-input-buttonmode', '')
.replace('-option-', '-')
.replace('-ti-confidential-', '-')
.replace('-ti-platform', '')
.replace('-ti-', '-')
.replace('-true', '')
.replace('-user-notification', '')
.replace('-user-setting', '')
.replace('align-alignment-', '')
.replace('autolink', '')
.replace('background-', 'bg-')
.replace('bg-repeat', 'background-repeat')
.replace('border-width', 'border')
.replace('color-', '')
.replace('column-', 'col-')
.replace('edges-edge', 'edges')
.replace('flag-', '')
.replace('height-', 'h-')
.replace('input-borderstyle-', '')
.replace('layout-', '')
.replace('prevent-image', 'prevent-default-image')
.replace('recurrencefrequency', 'recurrence')
.replace('returnkey-', '')
.replace('text-alignment-', 'text-')
.replace('width-', 'w-')
.replace('-bg-false', '-background-false') // special case for allowBackground: false
.replace(/--/g, '-')
}
function setModifier(_modifier) {
if (_modifier.includes('-i-os')) {
// some classes ended up with '-i-os' in their names after processing, this is to clear it.
_modifier = _modifier.replace('-i-os', '') + '[platform=ios]'
} else if (_modifier.includes('-android')) {
_modifier = _modifier.replace('-android', '') + '[platform=android]'
} else if (_modifier.includes('-handheld-')) {
_modifier = _modifier.replace('-handheld-', '-') + '[formFactor=handheld]'
} else if (_modifier.includes('-tablet-')) {
_modifier = _modifier.replace('-tablet-', '-') + '[formFactor=tablet]'
} else if (_modifier.includes('[if=')) {
let ifStatement = _modifier.match(/\[if=(.*?)\]/)
if (ifStatement) {
ifStatement = ifStatement[0]
_modifier = _modifier.replace(/\[if=(.*?)\]-/, '')
_modifier = _modifier + `${ifStatement}`
}
}
return _modifier
}
function defaultModifier(modifier) {
return modifier === '' || modifier === null || modifier === 'global' || modifier === 'default' || modifier === 'DEFAULT'
}
function notDefaultRules(rule) {
return rule !== '' && rule !== null && rule !== 'global' && rule !== 'default' && rule !== 'DEFAULT' && rule !== 'ios' && rule !== 'android' && rule !== 'android' && rule !== 'handheld' && rule !== 'tablet' && !rule.startsWith('[if=')
}
function camelCaseToDash(str) {
return (str.includes('[')) ? str : str.replace(/([a-z])([A-Z])/g, '$1-$2').toLowerCase()
}
function removeModuleName(value, property) {
return camelCaseToDash(value
// .replace(/^Ti.UI.iOS./, '')
.replace(/^Ti.UI.iPad./, '')
.replace(/^Ti.App./, '')
// .replace(/^Ti.Geolocation.Android./, '')g
.replace(/^Ti.Geolocation./, '')
// .replace(/^Ti.UI.Android./, '')
.replace(/^Ti.UI./, '')
.replace(/^Ti.Media.Sound./, '')
.replace(/^Ti.Media./, '')
.replace(/_/g, '-')
.replace(/'/g, '')
.replace(`${property}-`, '')
.replace(/\./g, '-'))
}
function makeSureFolderExists(folder) {
if (!fs.existsSync(folder)) fs.mkdirSync(folder)
}