Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 11 additions & 0 deletions editor/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
# example

```html
<uc-editor id="editor" uuid="84313a71-6c6d-4064-83f5-abcba112b67b" public-key="demopublickey"></uc-editor>
<script>
let editor = document.querySelector('#editor');
editor.addEventListener('apply', e => {
let {originalUrl, transformationsUrl, transformations} = e.detail;
console.log('APPLY', {originalUrl, transformationsUrl, transformations})
})
```
83 changes: 83 additions & 0 deletions editor/deploy-to-s3.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
import { S3Client, PutObjectCommand } from '@aws-sdk/client-s3';
import path from 'path';
import fs from 'fs';
import { fileURLToPath } from 'url';
import fg from 'fast-glob';

const PRE_RELEASE_REGEXP = /(^\d+\.\d+\.\d+-)((alpha|beta|rc)\.\d+)\.?\d*?$/;
const MINOR_RELEASE_REGEXP = /^(\d+\.\d+)\.\d+/;
const MAJOR_RELEASE_REGEXP = /^(\d+)\.\d+\.\d+/;

const getVersionTypes = (version) => {
let preReleaseMatch = version.match(PRE_RELEASE_REGEXP);
return [
version,
...(preReleaseMatch
? [
preReleaseMatch[1] + version.replace(PRE_RELEASE_REGEXP, '$2.x'),
preReleaseMatch[1] + version.replace(PRE_RELEASE_REGEXP, '$3.x'),
]
: [version.replace(MINOR_RELEASE_REGEXP, '$1.x'), version.replace(MAJOR_RELEASE_REGEXP, '$1.x')]),
];
};

const S3_PATH = 'libs/editor/';
const UPLOAD_FROM = './dist/';
const BUCKET = 'uploadcare-static';
const REGION = 'us-east-1';

const __filename = fileURLToPath(import.meta.url);
const __dirname = path.dirname(__filename);

const pkg = JSON.parse(fs.readFileSync('./package.json').toString());
const versionTypes = getVersionTypes(pkg.version);
const files = fg.sync('**/**', { cwd: UPLOAD_FROM });
const s3Client = new S3Client({ region: REGION });

const getContentType = (filePath) => {
let extension = path.extname(filePath);
return {
'.js': 'application/javascript',
'.json': 'application/json',
'.css': 'text/css',
}[extension];
};

const uploadToS3 = async (data, filePath, { dry }) => {
let contentType = getContentType(filePath);
console.log(`uploading ${data.length}B to ${filePath}, ${contentType}`);

if (dry) {
console.log('DRY RUN.');
return undefined;
}

const result = await s3Client.send(
new PutObjectCommand({
Bucket: BUCKET,
Key: filePath,
Body: data,
ContentType: `${contentType}; charset=utf-8`,
ACL: 'public-read',
})
);

return result;
};

const uploadFile = (data, fileName, options) => {
return Promise.all(versionTypes.map((version) => uploadToS3(data, `${S3_PATH}${version}/${fileName}`, options)));
};

Promise.all(
files.map((uploadPath) => {
const absolutePath = path.join(__dirname, UPLOAD_FROM, uploadPath);
const file = fs.promises.readFile(absolutePath, { encoding: 'utf-8' });
return Promise.all([file, uploadPath]);
})
)
.then((filesData) => Promise.all(filesData.map(([file, uploadPath]) => uploadFile(file, uploadPath, { dry: false }))))
.catch((error) => {
console.error('Error: \n', error.message);
process.exit(1);
});
70 changes: 70 additions & 0 deletions editor/esbuild.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
import esbuild from 'esbuild'
import fs from 'fs'
import path from 'path'

let version = JSON.parse(fs.readFileSync('./package.json').toString()).version
let locales = fs
.readdirSync('./src/l10n/locales/')
.map((file) => path.basename(file, '.json'))

let buildSequence = [
{
in: './src/index.js',
out: 'dist/uploadcare-editor.js',
minifyHtml: true,
},
]

function build(buildItem) {
return esbuild
.build({
entryPoints: [buildItem.in],
bundle: true,
minify: true,
sourcemap: false,
outfile: buildItem.out,
define: {
__DEPLOY_ENV__: JSON.stringify('production'),
__DEBUG__: JSON.stringify(Boolean(false)),
__VERSION__: JSON.stringify(version),
__LOCALES__: JSON.stringify(locales),
},
})
.then(async () => {
if (!buildItem.minifyHtml) {
return
}
let js = fs.readFileSync(buildItem.out).toString()
let checkIfHtml = (str) => {
return str.includes('<') && (str.includes('</') || str.includes('/>'))
}
let processChunk = (ch) => {
if (checkIfHtml(ch)) {
let htmlMin = ch.split('\n').join(' ')
while (htmlMin.includes(' ')) {
htmlMin = htmlMin.split(' ').join(' ')
}
htmlMin = htmlMin.split('> <').join('><')
// return htmlMin.split('" ').join('"').split('; ').join(';').split(': ').join(':').trim();
return htmlMin.trim()
}
return ch
}
let result = js
.split('`')
.map((chunk) => processChunk(chunk))
.join('`')
.split(`'`)
.map((chunk) => processChunk(chunk))
.join(`'`)
fs.writeFileSync(buildItem.out, result)
})
}

Promise.allSettled(buildSequence.map((buildItem) => build(buildItem))).then(
(results) => {
if (results.filter(({ status }) => status === 'rejected').length > 0) {
process.exit(1)
}
},
)
140 changes: 140 additions & 0 deletions editor/extract-styles.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,140 @@
import fg from 'fast-glob'
import parser from '@babel/parser'
import fs from 'fs'
import traverse from '@babel/traverse'
import osPath from 'path'
import jsBeautify from 'js-beautify'

let cssBeautify = jsBeautify.css

function camelCaseToDash(str) {
return str.replace(/([a-z])([A-Z])/g, '$1-$2').toLowerCase()
}

function extractFromExpressionNode(node) {
let styleObj = {}

for (let prop of node.properties) {
if (prop.type !== 'ObjectProperty') {
console.log(prop)
console.log('2UNKNOWN NODE TYPE', prop.type)
continue
}
let token = prop.key.name || prop.key.value
let objValue = prop.value
styleObj[token] = {}
for (let prop of objValue.properties) {
let key = prop.key.name || prop.key.value
let value = prop.value.value
styleObj[token][key] = value
}
}

return styleObj
}

function extractFromImportPath(filepath, ast, path) {
let styleObj = {}
let name = path.node.right.name
let node = path.scope.bindings[name].path.node
traverse.default(ast, {
ImportSpecifier: (path) => {
if (path.node.imported.name === node.imported.name) {
path.findParent((path) => {
if (path.node.type === 'ImportDeclaration') {
let importFromPath = path.node.source.value
let relativePath = osPath.join(
osPath.dirname(filepath),
importFromPath,
)
let code = fs.readFileSync(relativePath).toString()
let ast = parser.parse(code, { sourceType: 'module' })
traverse.default(ast, {
VariableDeclarator: (path) => {
if (path.node.id.name === name) {
styleObj = extractFromExpressionNode(path.node.init)
}
},
})
}
})
}
},
})
return styleObj
}

function processIdentifierPath(filepath, ast, path) {
let styleObj = {}
let name = path.node.right.name
let node = path.scope.bindings[name].path.node
if (node.type === 'VariableDeclarator') {
styleObj = extractFromExpressionNode(node.init)
} else if (node.type === 'ImportSpecifier') {
styleObj = extractFromImportPath(filepath, ast, path)
} else {
console.log('3UNKNOWN NODE TYPE', node.type)
}
return styleObj
}

function processInlineExpressionPath(path) {
let node = path.node.right
return extractFromExpressionNode(node)
}

function processFile(filepath) {
let styles = []
let code = fs.readFileSync(filepath).toString()
let ast = parser.parse(code, { sourceType: 'module' })
traverse.default(ast, {
AssignmentExpression: (path) => {
if (path.node.left.property?.name === 'styles') {
let componentName = path.node.left.object.name
let styleObj
if (path.node.right.type === 'Identifier') {
styleObj = processIdentifierPath(filepath, ast, path)
} else if (path.node.right.type === 'ObjectExpression') {
styleObj = processInlineExpressionPath(path)
} else {
console.log('1UNKNOWN NODE TYPE', path.node.right.type)
}
styles.push({
componentName,
styles: styleObj,
})
}
},
})
return styles
}

function convertToCss(stylesObj) {
let css = ''
for (let { componentName, styles } of stylesObj) {
Object.keys(styles).forEach((token) => {
if(token === ':host') {
css += `${camelCaseToDash(componentName)} {`
} else {
css += `${camelCaseToDash(componentName)} .${token} {`
}
let style = styles[token]
Object.keys(style).forEach((key) => {
let value = style[key]
css += `${camelCaseToDash(key)}: ${value};`
})
css += `}`
})
}
return cssBeautify(css)
}

;(async function () {
let sourceFiles = fg.sync('./src/**/*.js')
let styles = []
for (let filepath of sourceFiles) {
styles = [...styles, ...processFile(filepath)]
}
let css = convertToCss(styles)
fs.writeFileSync('./src/css/editor.css', css);
})()
Loading