Skip to content

Commit

Permalink
IM list autogenerated using scripts/generateImEnums.ts
Browse files Browse the repository at this point in the history
  • Loading branch information
cancerberoSgx committed Nov 15, 2018
1 parent 63d88b4 commit a852350
Show file tree
Hide file tree
Showing 74 changed files with 2,234 additions and 129 deletions.
326 changes: 326 additions & 0 deletions package-lock.json

Large diffs are not rendered by default.

7 changes: 6 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,8 @@
"test-browser-build": "rm -rf dist && npm run build-ts && cp -r spec/assets dist && npm run bundle",
"bundle": "browserify -d dist/spec/index.js -o dist/bundle.js",
"lint": "tslint \"src/**/*.ts\" \"spec/**/*.ts\"",
"lint-and-fix": "tslint \"src/**/*.ts\" \"spec/**/*.ts\" --fix"
"lint-and-fix": "tslint \"src/**/*.ts\" \"spec/**/*.ts\" --fix",
"generateImEnums": "npx ts-node scripts/generateImEnums.ts"
},
"repository": {
"type": "git",
Expand All @@ -42,11 +43,15 @@
"devDependencies": {
"@types/jasmine": "^2.8.11",
"@types/node": "^10.12.3",
"@types/shelljs": "^0.8.0",
"browserify": "^16.2.3",
"gulp": "^3.9.1",
"gulp-jasmine-browser": "^4.0.2",
"jasmine": "^3.3.0",
"puppeteer": "^1.3.0",
"shelljs": "^0.8.3",
"ts-node": "^7.0.1",
"ts-simple-ast": "^19.0.0",
"tslint": "^5.11.0",
"typescript": "^3.1.6"
},
Expand Down
251 changes: 128 additions & 123 deletions samples/interactive-execute-context/src/app.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { sampleCommandTemplates } from 'imagemagick-browser'
import pmap from 'p-map'
import pMap from 'p-map'
import * as React from 'react'
import { style } from 'typestyle'
import {
Expand Down Expand Up @@ -66,13 +66,14 @@ export class App extends React.Component<AppProps, AppState> {
backgroundColor: '#88ff88',
}),
h5: style({
margin: 0
margin: 0,
}),
}

render(): React.ReactNode {
return (
<div>

<div>
<h4>Images available (#{this.state.files.length}) :</h4>
<div>Show images and info: <input type='checkbox' checked={this.state.showImagesAndInfo} onChange={this.showImagesAndInfoChange.bind(this)}></input></div>
Expand All @@ -83,157 +84,161 @@ export class App extends React.Component<AppProps, AppState> {

<div><button onClick={this.removeAllImages.bind(this)} disabled={this.state.files.length === 0}>Remove all images</button></div>

<table className={(this.state.showImagesAndInfo || '') && this.styles.imagesList}>
{
(this.state.showImagesAndInfo || '') && <thead><tr>
<th>Name</th>
<th>Image</th>
<th>Info</th>
</tr></thead>
}
<tbody>
{this.state.files.map((f, i) =>
// <li>
// <table>

<tr>
<td>
<button data-image={f.name} onClick={this.removeImage.bind(this)}>remove</button>
{f.name}
</td>
<td>{(this.state.showImagesAndInfo || '') &&
<img alt={f.name} src={this.state.imgSrcs[i]}></img>}</td>
<td>{(this.state.showImagesAndInfo || '') &&
<textarea className={this.styles.infoTextarea} value={JSON.stringify(this.state.filesInfo[i][0].image, null, 2)}></textarea>}</td>
</tr>
)}
</tbody>
</table>
<div className={(this.state.showImagesAndInfo || '') && this.styles.imagesList}>
<table >
{(this.state.showImagesAndInfo || '') &&
<thead><tr>
<th>Name</th>
<th>Actions</th>
<th>Image</th>
<th>Info</th>
</tr></thead>
}
<tbody>
{this.state.files.map((f, i) =>
<tr>
<td>{f.name}</td>
<td>
<button data-image={f.name} onClick={this.removeImage.bind(this)}>remove</button>
</td>
<td>{(this.state.showImagesAndInfo || '') &&
<img alt={f.name} src={this.state.imgSrcs[i]}></img>}
</td>
<td>{(this.state.showImagesAndInfo || '') &&
<textarea className={this.styles.infoTextarea} value={JSON.stringify(this.state.filesInfo[i][0].image, null, 2)}></textarea>}
</td>
</tr>,
)}
</tbody>
</table>
</div>
</div>
<div>
<h4>Command</h4>
<p>Write a command using one supported syntax type:</p>
<div>Command (String syntax):

<div>
<h4>Command</h4>
<p>Write a command using one supported syntax type:</p>
<div>Command (String syntax):
<textarea className={this.styles.textarea} onChange={this.commandStringChange.bind(this)} value={this.state.commandString}></textarea>
</div>
<div>Command (Array syntax):
</div>
<div>Command (Array syntax):
<textarea className={this.styles.textarea} onChange={this.commandArrayChange.bind(this)} value={this.state.commandArray}></textarea>
{(this.state.jsonError || '') && <div>Execution error: {this.state.jsonError} <br />See browser console for more information.</div>}
</div>
<div>
Or select one example
<select onChange={this.selectExampleChange.bind(this)}>
{sampleCommandTemplates.map(t =>
<option>{t.name}</option>)}
</select>
</div>
{(this.state.jsonError || '') && <div>Execution error: {this.state.jsonError} <br />See browser console for more information.</div>}
</div>
<div>
<button onClick={this.execute.bind(this)}>Execute</button>
Or select one example
<select disabled={this.state.files.length === 0} onChange={this.selectExampleChange.bind(this)}>
{sampleCommandTemplates.map(t =>
<option>{t.name}</option>)}
</select>
</div>
</div>

<div>
<p>Output Files (#{this.state.outputFiles.length}) </p>
{(this.state.outputFiles.length || '') && <ul>{this.state.outputFiles.map((f, i) =>
<li><div>{f.name}</div>
<img src={this.state.outputFileSrcs[i]}></img>
</li>,
)}
</ul>}
</div>
<h5 className={this.styles.h5}><span className={this.state.exitCode ? this.styles.executionBad : this.styles.executionGood}>Exit code: {this.state.exitCode + ''}</span></h5>
<h5 className={this.styles.h5}>stdout:</h5>
<textarea className={this.styles.textarea} value={this.state.stdout}></textarea>
<h5 className={this.styles.h5}>stderr:</h5>
<textarea className={this.styles.textarea} value={this.state.stderr}></textarea>
</div>)
}

private defaultImage = 'fn.png'
<div>
<button onClick={this.execute.bind(this)}>Execute</button>
</div>

<div>
<p>Output Files (#{this.state.outputFiles.length}) </p>
{(this.state.outputFiles.length || '') && <ul>{this.state.outputFiles.map((f, i) =>
<li><div>{f.name}</div>
<img src={this.state.outputFileSrcs[i]}></img>
</li>,
)}
</ul>}
</div>
<h5 className={this.styles.h5}><span className={this.state.exitCode ? this.styles.executionBad : this.styles.executionGood}>Exit code: {this.state.exitCode + ''}</span></h5>
<h5 className={this.styles.h5}>stdout:</h5>
<textarea className={this.styles.textarea} value={this.state.stdout}></textarea>
<h5 className={this.styles.h5}>stderr:</h5>
<textarea className={this.styles.textarea} value={this.state.stderr}></textarea>
</div>)
}

private defaultImage = 'fn.png'
async componentDidMount() {
if (!this.state.files.find(f => f.name === this.defaultImage)) {
await this.addInputFiles([await buildInputFile(this.defaultImage)])
}
}
await this.addInputFiles([await buildInputFile(this.defaultImage)])
}
}

removeImage(e: React.MouseEvent<HTMLButtonElement>) {
const name = e.currentTarget.getAttribute('data-image')
this.props.context.removeFiles([name])
this.state.files = this.state.files.filter(f => f.name !== name)
this.setState({...this.state, files: this.state.files.filter(f => f.name !== name) })
}
this.props.context.removeFiles([name])
this.state.files = this.state.files.filter(f => f.name !== name)
this.setState({ ...this.state, files: this.state.files.filter(f => f.name !== name) })
}

async removeAllImages(e: React.MouseEvent<HTMLButtonElement>) {
const all = await this.props.context.getAllFiles()
this.props.context.removeFiles(all.map(f => f.name))
this.state.builtInImagesAdded = false
this.setState({...this.state, files: [] })
}
this.props.context.removeFiles(all.map(f => f.name))
this.state.builtInImagesAdded = false
this.setState({ ...this.state, files: [] })
}

protected commandStringChange(e: React.ChangeEvent<HTMLTextAreaElement>) {
const commandArray = JSON.stringify(cliToArray(e.target.value)) // TODO: validate
this.setState({...this.state, commandString: e.target.value, commandArray })
}
this.setState({ ...this.state, commandString: e.target.value, commandArray })
}

protected async addBuiltInImages() {
if (!this.state.builtInImagesAdded) {
const builtIn = await getBuiltInImages()
await this.addInputFiles(builtIn)
this.setState({...this.state, builtInImagesAdded: true })
}
}
await this.addInputFiles(builtIn)
this.setState({ ...this.state, builtInImagesAdded: true })
}
}

protected async execute() {
const result = await this.props.context.execute(this.state.commandString)
this.state.outputFiles = result.outputFiles
this.state.stderr = result.stderr.join('\n')
this.state.stdout = result.stdout.join('\n')
this.state.exitCode = result.exitCode
await this.updateImages()
}
this.state.outputFiles = result.outputFiles
this.state.stderr = result.stderr.join('\n')
this.state.stdout = result.stdout.join('\n')
this.state.exitCode = result.exitCode
await this.updateImages()
}

protected commandArrayChange(e: React.ChangeEvent<HTMLTextAreaElement>) {
const commandArray = e.target.value
let jsonError = ''
let commandString = this.state.commandString
let jsonError = ''
let commandString = this.state.commandString
try {
commandString = arrayToCli(JSON.parse(e.target.value))
} catch (error) {
jsonError = error + ''
}
this.setState({...this.state, commandString, commandArray, jsonError })
}
commandString = arrayToCli(JSON.parse(e.target.value))
} catch (error) {
jsonError = error + ''
}
this.setState({ ...this.state, commandString, commandArray, jsonError })
}

protected async addImagesInputChanged(e: React.ChangeEvent<HTMLInputElement>) {
const inputFiles = await getInputFilesFromHtmlInputElement(e.target)
this.addInputFiles(inputFiles)
}
this.addInputFiles(inputFiles)
}

protected async addInputFiles(files: MagickInputFile[]) {
this.props.context.addFiles(files)
this.props.context.addFiles(files)
await this.updateImages()
}
}

protected async updateImages() {
const files = await this.props.context.getAllFiles()
const imgSrcs = this.state.showImagesAndInfo ? await pmap(files, f => buildImageSrc(f, true)) : this.state.imgSrcs
const filesInfo = this.state.showImagesAndInfo ? await pmap(files, f => extractInfo(f)) : this.state.filesInfo
const outputFileSrcs = await pmap(this.state.outputFiles, f => buildImageSrc(f, true))
this.setState({...this.state, files, imgSrcs, outputFileSrcs, filesInfo })
}
const imgSrcs = this.state.showImagesAndInfo ? await pMap(files, f => buildImageSrc(f, true)) : this.state.imgSrcs
const filesInfo = this.state.showImagesAndInfo ? await pMap(files, f => extractInfo(f)) : this.state.filesInfo
const outputFileSrcs = await pMap(this.state.outputFiles, f => buildImageSrc(f, true))
this.setState({ ...this.state, files, imgSrcs, outputFileSrcs, filesInfo })
}

protected async showImagesAndInfoChange(e: React.ChangeEvent<HTMLInputElement>) {
this.state.showImagesAndInfo = e.target.checked
this.state.showImagesAndInfo = e.target.checked
await this.updateImages()
}
private selectExampleCounter = 0
}

private selectExampleCounter = 0
protected async selectExampleChange(e: React.ChangeEvent<HTMLSelectElement>) {
const template = sampleCommandTemplates[e.target.selectedIndex]
const img = this.state.files.find(i => i.name === this.defaultImage)
const info = await extractInfo(img)
const context = {...template.defaultTemplateContext, imageWidth: info[0].image.geometry.width, imageHeight: info[0].image.geometry.height }
const command = template.template(context)[0].map(s => s === '$INPUT' ? this.defaultImage : s === '$OUTPUT' ? `output${this.selectExampleCounter++}.gif` : s)
this.setState({...this.state, commandArray: JSON.stringify(command), commandString: arrayToCli(command) })
}
}
const img = this.state.files[0]
const info = await extractInfo(img)
const context = { ...template.defaultTemplateContext, imageWidth: info[0].image.geometry.width, imageHeight: info[0].image.geometry.height }
const command = template.template(context)[0].map(s => s === '$INPUT' ? img.name : s === '$OUTPUT' ? `output${this.selectExampleCounter++}.png` : s)
this.setState({ ...this.state, commandArray: JSON.stringify(command), commandString: arrayToCli(command) })
}
}
66 changes: 66 additions & 0 deletions scripts/generateImEnums.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
import { writeFileSync } from 'fs'
import { sep } from 'path'
import { config, exec, mkdir, rm } from 'shelljs'
import Project, { EnumDeclarationStructure, IndentationText, QuoteKind } from 'ts-simple-ast'

config.silent = true

// automatically generates TS enums from all convert -list list with few exceptions that are not usable/parsable
// Output folder - warning, it will be cleared
const FOLDER = `src${sep}list`
const EXCLUDE_FROM_LIST = ['Configure', 'Delegate', 'Magic', 'Mime', 'Threshold', 'Format', 'Coder', 'Color', 'Policy', 'Resource', 'Font', 'Locale', 'CLI', 'IMLog']

let project: Project
function getProject(): Project {
if (!project) {
project = new Project({
useVirtualFileSystem: true,
manipulationSettings: {
indentationText: IndentationText.TwoSpaces,
quoteKind: QuoteKind.Single,
},
})
}
return project
}
export function generateListEnum(listed: string) {
const enumName = 'IM' + listed
const enumDeclaration: EnumDeclarationStructure = {
name: enumName,
members: list(listed)
.filter((v, i, a) => a.indexOf(v) === i) // deduplicate
.map(n => ({
name: `'${isNaN(parseInt(n, 10)) ? n : (n + '_')}'`,
initializer: `'${n}'`,
})),
isExported: true,
}
const sourceFile = getProject().createSourceFile(`${enumName}.ts`)
sourceFile.addEnum(enumDeclaration)
return sourceFile
}

export function list(listed: string): string[] {
const result = exec(`convert -list ${listed}`)
// ok(result.code === 0, 'result.code: ' + result.code) // commented because of https://github.com/ImageMagick/ImageMagick/issues/1333
const names = result.stdout.split('\n').filter(s => s.trim())
return names
}

export function generateEnumsForAllLists() {
rm('-rf', FOLDER)
mkdir('-p', FOLDER)
let indexContent = ''
list('list')
.filter(name => EXCLUDE_FROM_LIST.indexOf(name) === -1)
.forEach(name => {
const sourceFile = generateListEnum(name)
const fileName = `IM${name}`
indexContent += `export * from './${fileName}'\n`
writeFileSync(`${FOLDER}${sep}${fileName}.ts`, `/* auto-generated file using command \`npx ts-node scripts/generateImEnums.ts\` */\n${sourceFile.getText()}`)
})
writeFileSync(`${FOLDER}${sep}index.ts`, indexContent)

}

generateEnumsForAllLists()
Loading

0 comments on commit a852350

Please sign in to comment.