UNPKG

@haxtheweb/create

Version:

CLI for all things HAX the web

696 lines (680 loc) • 31.8 kB
#!/usr/bin/env node "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.webcomponentActions = webcomponentActions; exports.webcomponentCommandDetected = webcomponentCommandDetected; exports.webcomponentGenerateHAXSchema = webcomponentGenerateHAXSchema; exports.webcomponentProcess = webcomponentProcess; var fs = _interopRequireWildcard(require("node:fs")); var path = _interopRequireWildcard(require("node:path")); var _promises = require("node:timers/promises"); var ejs = _interopRequireWildcard(require("ejs")); var p = _interopRequireWildcard(require("@clack/prompts")); var _picocolors = _interopRequireDefault(require("picocolors")); var _statements = require("../statements.js"); var _logging = require("../logging.js"); var _utils = require("../utils.js"); var hax = _interopRequireWildcard(require("@haxtheweb/haxcms-nodejs")); function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; } function _getRequireWildcardCache(e) { if ("function" != typeof WeakMap) return null; var r = new WeakMap(), t = new WeakMap(); return (_getRequireWildcardCache = function (e) { return e ? t : r; })(e); } function _interopRequireWildcard(e, r) { if (!r && e && e.__esModule) return e; if (null === e || "object" != typeof e && "function" != typeof e) return { default: e }; var t = _getRequireWildcardCache(r); if (t && t.has(e)) return t.get(e); var n = { __proto__: null }, a = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var u in e) if ("default" !== u && {}.hasOwnProperty.call(e, u)) { var i = a ? Object.getOwnPropertyDescriptor(e, u) : null; i && (i.get || i.set) ? Object.defineProperty(n, u, i) : n[u] = e[u]; } return n.default = e, t && t.set(e, n), n; } const HAXCMS = hax.HAXCMS; let sysGit = true; (0, _utils.exec)('which git', error => { if (error) { sysGit = false; } }); class HAXWiring { /** * Return a haxProperties prototype / example structure */ prototypeHaxProperties = () => { // example properties valid for HAX context menu. let props = { api: "1", type: "element", editingElement: "core", hideDefaultSettings: false, canScale: true, canEditSource: true, contentEditable: false, gizmo: { title: "Tag name", description: "", icon: "icons:android", color: "purple", tags: ["Other"], handles: [{ type: "data", type_exclusive: false, url: "src" }], meta: { author: "auto" }, requiresChildren: false, requiresParent: false }, settings: { configure: [{ slot: "", title: "Inner content", description: "The slotted content that lives inside the tag", inputMethod: "textfield", icon: "android", required: true, validationType: "text" }, { slot: "button", title: "Button content", description: "The content that can override the button", inputMethod: "textfield", icon: "android", required: true, validationType: "text" }, { property: "title", title: "Title", description: "", inputMethod: "textfield", icon: "android", required: true, validationType: "text" }, { property: "primaryColor", title: "Title", description: "", inputMethod: "textfield", icon: "android", required: false, validation: ".*", validationType: "text" }], advanced: [{ property: "secondaryColor", title: "Secondary color", description: "An optional secondary color used in certain edge cases.", inputMethod: "colorpicker", icon: "color" }, { property: "endPoint", title: "API endpoint", description: "An optional endpoint to hit and load in more data dymaically.", inputMethod: "textfield", icon: "android", validation: "[a-z0-9]", validationType: "url" }], developer: [] }, saveOptions: { wipeSlot: false, unsetAttributes: ["end-point", "secondary-color"] }, documentation: { howTo: "https://haxtheweb.org/welcome", purpose: "https://haxtheweb.org/welcome" }, demoSchema: [{ tag: "my-tag", content: "<p>inner html</p>", properties: { endPoint: "https://cdn2.thecatapi.com/images/9j5.jpg", primaryColor: "yellow", title: "A cat" } }] }; return props; }; } // processing an element async function webcomponentProcess(commandRun, project, port = "8000") { // auto select operations to perform if requested if (!project.extras) { console.log(commandRun.options.extras); if (commandRun.options.extras === false) { project.extras = []; } else { let extras = ['launch', 'install', 'git']; if (!sysGit || project.isMonorepo) { extras.pop(); } project.extras = extras; } } // values not set by user but used in templating project.className = (0, _utils.dashToCamel)(project.name); // option to build github repo link for the user if (project.extras && project.extras.includes('git')) { // @todo need to support git@ and https methods if (commandRun.options.auto) { project.gitRepo = `https://github.com/${project.author}/${project.name}.git`; } else { project.gitRepo = await p.text({ message: 'Git Repo location:', placeholder: `https://github.com/${project.author}/${project.name}.git`, initialValue: `https://github.com/${project.author}/${project.name}.git` }); } // if they supplied one and it has github in it, build a link automatically for ejs index if (project.gitRepo && project.gitRepo.includes('github.com')) { project.githubLink = project.gitRepo.replace('git@github.com:', 'https://github.com/').replace('.git', ''); } else { project.githubLink = null; } } else { project.githubLink = null; } // if we have an org, add a / at the end so file name is written correctly if (project.org) { project.org += '/'; } else { project.org = ''; } let s = p.spinner(); s.start((0, _statements.merlinSays)('Copying project files')); // leverage this little helper from HAXcms await HAXCMS.recurseCopy(`${process.mainModule.path}/templates/${project.type}/hax/`, `${project.path}/${project.name}`); // rename gitignore to improve copy cross platform compat await fs.renameSync(`${project.path}/${project.name}/_github`, `${project.path}/${project.name}/.github`); await fs.renameSync(`${project.path}/${project.name}/_vscode`, `${project.path}/${project.name}/.vscode`); await fs.renameSync(`${project.path}/${project.name}/_dddignore`, `${project.path}/${project.name}/.dddignore`); await fs.renameSync(`${project.path}/${project.name}/_editorconfig`, `${project.path}/${project.name}/.editorconfig`); await fs.renameSync(`${project.path}/${project.name}/_gitignore`, `${project.path}/${project.name}/.gitignore`); await fs.renameSync(`${project.path}/${project.name}/_nojekyll`, `${project.path}/${project.name}/.nojekyll`); await fs.renameSync(`${project.path}/${project.name}/_npmignore`, `${project.path}/${project.name}/.npmignore`); await fs.renameSync(`${project.path}/${project.name}/_surgeignore`, `${project.path}/${project.name}/.surgeignore`); await fs.renameSync(`${project.path}/${project.name}/_travis.yml`, `${project.path}/${project.name}/.travis.yml`); // rename paths that are of the element name in question await fs.renameSync(`${project.path}/${project.name}/lib/webcomponent.haxProperties.json`, `${project.path}/${project.name}/lib/${project.name}.haxProperties.json`); // loop through and rename all the localization files fs.readdir(`${project.path}/${project.name}/locales/`, function (err, files) { if (err) { console.error("Could not list the directory.", err); process.exit(1); } files.forEach(async function (file, index) { await fs.renameSync(`${project.path}/${project.name}/locales/${file}`, `${project.path}/${project.name}/locales/${file.replace('webcomponent', project.name)}`); }); }); await fs.renameSync(`${project.path}/${project.name}/webcomponent.js`, `${project.path}/${project.name}/${project.name}.js`); await fs.renameSync(`${project.path}/${project.name}/test/webcomponent.test.js`, `${project.path}/${project.name}/test/${project.name}.test.js`); s.stop((0, _statements.merlinSays)('Files copied')); await (0, _promises.setTimeout)(500); s.start((0, _statements.merlinSays)('Making files awesome')); for (const filePath of (0, _utils.readAllFiles)(`${project.path}/${project.name}`)) { try { // ensure we don't try to pattern rewrite image files if (!filePath.endsWith('.jpg') && !filePath.endsWith('.png')) { const ejsString = ejs.fileLoader(filePath, 'utf8'); let content = ejs.render(ejsString, project); // file written successfully fs.writeFileSync(filePath, content); } } catch (err) { console.error(filePath); console.error(err); } } s.stop('Files are now awesome!'); if (project.gitRepo && !commandRun.options.isMonorepo) { try { await (0, _utils.exec)(`cd ${project.path}/${project.name} && git init && git add -A && git commit -m "first commit" && git branch -M main${project.gitRepo ? ` && git remote add origin ${project.gitRepo}` : ''}`); } catch (e) {} } // options for install, git and other extras // can't launch if we didn't install first so launch implies installation if (project.extras && (project.extras.includes('launch') || project.extras.includes('install'))) { s.start((0, _statements.merlinSays)(`Installation magic (${commandRun.options.npmClient} install)`)); try { // monorepos install from top but then still need to launch from local location if (!commandRun.options.isMonorepo) { await (0, _utils.exec)(`cd ${project.path}/${project.name} && ${commandRun.options.npmClient} install`); } } catch (e) { console.warn(e); } s.stop((0, _statements.merlinSays)(`Everything is installed. It's go time`)); } // autolaunch if default was selected if (project.extras && project.extras.includes('launch')) { let optionPath = `${project.path}/${project.name}`; let command = `${commandRun.options.npmClient} start`; p.note(`${(0, _statements.merlinSays)(`I have summoned a sub-process daemon šŸ‘¹`)} šŸš€ Running your ${_picocolors.default.bold(project.type)} ${_picocolors.default.bold(project.name)}: ${_picocolors.default.underline(_picocolors.default.cyan(`http://localhost:${port}`))} šŸ  Launched: ${_picocolors.default.underline(_picocolors.default.bold(_picocolors.default.yellow(_picocolors.default.bgBlack(`${optionPath}`))))} šŸ’» Folder: ${_picocolors.default.bold(_picocolors.default.yellow(_picocolors.default.bgBlack(`cd ${optionPath}`)))} šŸ“‚ Open folder: ${_picocolors.default.bold(_picocolors.default.yellow(_picocolors.default.bgBlack(`open ${optionPath}`)))} šŸ“˜ VS Code Project: ${_picocolors.default.bold(_picocolors.default.yellow(_picocolors.default.bgBlack(`code ${optionPath}`)))} 🚧 Launch later: ${_picocolors.default.bold(_picocolors.default.yellow(_picocolors.default.bgBlack(`${command}`)))} āŒØļø To resume šŸ§™ Merlin press: ${_picocolors.default.bold(_picocolors.default.black(_picocolors.default.bgRed(` CTRL + C or CTRL + BREAK `)))} `); // at least a second to see the message print at all await (0, _promises.setTimeout)(1000); try { await (0, _utils.exec)(`cd ${optionPath} && ${command} && ${commandRun.options.npmClient} run analyze`); } catch (e) { // don't log bc output is weird } } else if (!commandRun.options.quiet) { let nextSteps = `cd ${project.path}/${project.name} && ${project.extras.includes('install') ? '' : `${commandRun.options.npmClient} install && `}${commandRun.options.npmClient} start`; p.note(`${project.name} is ready to go. Run the following to start development:`); p.outro(nextSteps); } } function webcomponentActions() { return [{ value: 'start', label: "Launch project" }, { value: 'wc:stats', label: "Check status of web component" }, { value: 'wc:element', label: "Add new Lit component to existing project" }, { value: 'wc:haxproperties', label: "Write haxProperties schema" }]; } // autodetect webcomponent async function webcomponentCommandDetected(commandRun, packageData = {}, port = "8000") { if (!commandRun.options.quiet) { p.intro(`${_picocolors.default.bgBlack(_picocolors.default.white(` HAXTheWeb : Webcomponent detected `))}`); p.intro(`${_picocolors.default.bgBlue(_picocolors.default.white(` Web component name: ${packageData.name} `))}`); } let actions = webcomponentActions(); let actionAssigned = false; // default to status unless already set so we don't issue a create in a create if (!commandRun.arguments.action) { actionAssigned = true; commandRun.arguments.action = 'wc:status'; } commandRun.command = "webcomponent"; let operation = { ...commandRun.arguments, ...commandRun.options }; actions.push({ value: 'quit', label: "🚪 Quit" }); while (operation.action !== 'quit') { if (!operation.action) { commandRun = { command: null, arguments: {}, options: { npmClient: `${operation.npmClient}` } }; operation = await p.group({ action: ({ results }) => p.select({ message: `Actions you can take:`, defaultValue: actions[0], initialValue: actions[0], options: actions }) }, { onCancel: () => { if (!commandRun.options.quiet) { p.cancel('šŸ§™ Merlin: Canceling CLI.. HAX ya later šŸŖ„'); } process.exit(0); } }); } if (operation.action) { p.intro(`hax wc ${_picocolors.default.bold(operation.action)}`); } switch (operation.action) { case "start": if (!commandRun.options.quiet) { // Multi-line clack spacing p.note(`${(0, _statements.merlinSays)(`I have summoned a sub-process daemon šŸ‘¹`)} šŸš€ Running your ${_picocolors.default.bold('webcomponent')} ${_picocolors.default.bold(packageData.name)}: ${_picocolors.default.underline(_picocolors.default.cyan(`http://localhost:${port}`))} šŸ  Launched: ${_picocolors.default.underline(_picocolors.default.bold(_picocolors.default.yellow(_picocolors.default.bgBlack(`${process.cwd()}`))))} šŸ’» Folder: ${_picocolors.default.bold(_picocolors.default.yellow(_picocolors.default.bgBlack(`cd ${process.cwd()}`)))} šŸ“‚ Open folder: ${_picocolors.default.bold(_picocolors.default.yellow(_picocolors.default.bgBlack(`open ${process.cwd()}`)))} šŸ“˜ VS Code Project: ${_picocolors.default.bold(_picocolors.default.yellow(_picocolors.default.bgBlack(`code ${process.cwd()}`)))} 🚧 Launch later: ${_picocolors.default.bold(_picocolors.default.yellow(_picocolors.default.bgBlack(`${commandRun.options.npmClient} start`)))} āŒØļø To exit šŸ§™ Merlin press: ${_picocolors.default.bold(_picocolors.default.black(_picocolors.default.bgRed(` CTRL + C or CTRL + BREAK `)))} `); } try { // ensure it's installed first, unless it's a monorepo. basic check for node_modules // folder as far as if already installed so we don't double install needlessly if (!commandRun.options.isMonorepo && !fs.existsSync("./node_modules")) { if (!commandRun.options.quiet) { let s = p.spinner(); s.start((0, _statements.merlinSays)(`Installation magic (${commandRun.options.npmClient} install)`)); await (0, _utils.exec)(`${commandRun.options.npmClient} install`); s.stop((0, _statements.merlinSays)(`Everything is installed. It's go time`)); } else { await (0, _utils.exec)(`${commandRun.options.npmClient} install`); } } await (0, _utils.exec)(`${commandRun.options.npmClient} start`); } catch (e) { // don't log bc output is odd } break; case "serve": try { if (!commandRun.options.quiet) { p.intro(`Launching development server.. `); } if (packageData.scripts.serve) { if (!commandRun.options.quiet) { p.note(`${(0, _statements.merlinSays)(`Project launched in development mode`)} šŸš€ Running your ${_picocolors.default.bold('webcomponent')} ${_picocolors.default.bold(packageData.name)}: ${_picocolors.default.underline(_picocolors.default.cyan(`http://localhost:${port}`))} šŸ  Launched: ${_picocolors.default.underline(_picocolors.default.bold(_picocolors.default.yellow(_picocolors.default.bgBlack(`${process.cwd()}`))))} šŸ’» Folder: ${_picocolors.default.bold(_picocolors.default.yellow(_picocolors.default.bgBlack(`cd ${process.cwd()}`)))} šŸ“‚ Open folder: ${_picocolors.default.bold(_picocolors.default.yellow(_picocolors.default.bgBlack(`open ${process.cwd()}`)))} šŸ“˜ VS Code Project: ${_picocolors.default.bold(_picocolors.default.yellow(_picocolors.default.bgBlack(`code ${process.cwd()}`)))} 🚧 Launch later: ${_picocolors.default.bold(_picocolors.default.yellow(_picocolors.default.bgBlack(`${commandRun.options.npmClient} serve`)))} āŒØļø To exit šŸ§™ Merlin press: ${_picocolors.default.bold(_picocolors.default.black(_picocolors.default.bgRed(` CTRL + C or CTRL + BREAK `)))} `); } await (0, _utils.exec)(`${commandRun.options.npmClient} run serve`); } else { // if no serve script, run start instead if (!commandRun.options.quiet) { p.note(`${(0, _statements.merlinSays)(`No ${_picocolors.default.bold('serve')} script found, running ${_picocolors.default.bold(`${commandRun.options.npmClient} start`)} instead`)} šŸš€ Running your ${_picocolors.default.bold('webcomponent')} ${_picocolors.default.bold(packageData.name)}: ${_picocolors.default.underline(_picocolors.default.cyan(`http://localhost:${port}`))} šŸ  Launched: ${_picocolors.default.underline(_picocolors.default.bold(_picocolors.default.yellow(_picocolors.default.bgBlack(`${process.cwd()}`))))} šŸ’» Folder: ${_picocolors.default.bold(_picocolors.default.yellow(_picocolors.default.bgBlack(`cd ${process.cwd()}`)))} šŸ“‚ Open folder: ${_picocolors.default.bold(_picocolors.default.yellow(_picocolors.default.bgBlack(`open ${process.cwd()}`)))} šŸ“˜ VS Code Project: ${_picocolors.default.bold(_picocolors.default.yellow(_picocolors.default.bgBlack(`code ${process.cwd()}`)))} 🚧 Launch later: ${_picocolors.default.bold(_picocolors.default.yellow(_picocolors.default.bgBlack(`${commandRun.options.npmClient} start`)))} āŒØļø To exit šŸ§™ Merlin press: ${_picocolors.default.bold(_picocolors.default.black(_picocolors.default.bgRed(` CTRL + C or CTRL + BREAK `)))} `); } await (0, _utils.exec)(`${commandRun.options.npmClient} start`); } } catch (e) { // don't log bc output is odd console.log("error", e); } break; case "wc:status": case "wc:stats": case "webcomponent:status": case "webcomponent:stats": try { let webcomponentStats = {}; if (packageData) { webcomponentStats.title = packageData.name; webcomponentStats.description = packageData.description; webcomponentStats.git = packageData.repository.url; } webcomponentStats.modules = []; webcomponentStats.superclasses = []; if (fs.existsSync(`${process.cwd()}/custom-elements.json`)) { let components = JSON.parse(fs.readFileSync(`${process.cwd()}/custom-elements.json`, 'utf8')).modules; for (var i in components) { webcomponentStats.modules.push(`${components[i].path}`); if (components[i].declarations[0].superclass && !webcomponentStats.superclasses.includes(components[i].declarations[0].superclass.name)) { webcomponentStats.superclasses.push(`${components[i].declarations[0].superclass.name}`); } } } if (!commandRun.options.format && !commandRun.options.quiet) { p.intro(`${_picocolors.default.bgBlue(_picocolors.default.white(` Title: ${webcomponentStats.title} `))}`); p.intro(`${_picocolors.default.bgBlue(_picocolors.default.white(` Description: ${webcomponentStats.description} `))}`); if (webcomponentStats.git) { p.intro(`${_picocolors.default.bgBlue(_picocolors.default.white(` Git: ${webcomponentStats.git} `))}`); } if (webcomponentStats.modules.length !== 0) { p.intro(`${_picocolors.default.bgBlue(_picocolors.default.white(` Modules: ${webcomponentStats.modules} `))}`); p.intro(`${_picocolors.default.bgBlue(_picocolors.default.white(` Number of modules: ${webcomponentStats.modules.length} `))}`); } if (webcomponentStats.superclasses.length !== 0) { p.intro(`${_picocolors.default.bgBlue(_picocolors.default.white(` Inherited superclasses: ${webcomponentStats.superclasses} `))}`); } } } catch (e) { (0, _logging.log)(e.stderr); } break; case "wc:element": case "webcomponent:element": try { const reservedNames = ["annotation-xml", "color-profile", "font-face", "font-face-src", "font-face-uri", "font-face-format", "font-face-name", "missing-glyph"]; if (!commandRun.options.name) { commandRun.options.name = await p.text({ message: 'Component name:', placeholder: 'my-component', required: true, validate: value => { if (!value) { return "Name is required (tab writes default)"; } if (reservedNames.includes(value)) { return `Reserved name ${_picocolors.default.bold(value)} cannot be used`; } if (value.toLocaleLowerCase() !== value) { return "Name must be lowercase"; } if (/^\d/.test(value)) { return "Name cannot start with a number"; } if (/[`~!@#$%^&*()_=+\[\]{}|;:\'",<.>\/?\\]/.test(value)) { return "No special characters allowed in name"; } if (value.indexOf(' ') !== -1) { return "No spaces allowed in name"; } if (value.indexOf('-') === -1 || value.replace('--', '') !== value || value[0] === '-' || value[value.length - 1] === '-') { return "Name must include at least one `-` and must not start or end name."; } // Check for any other syntax errors if (!/^[a-z][a-z0-9.\-]*\-[a-z0-9.\-]*$/.test(value)) { return `Name must follow the syntax ${_picocolors.default.bold("my-component")}`; } // assumes auto was selected in CLI let joint = process.cwd(); if (commandRun.options.path) { joint = commandRun.options.path; } if (fs.existsSync(path.join(joint, value))) { return `${path.join(joint, value)} exists, rename this project`; } } }); } else { let value = commandRun.options.name; if (!value) { console.error(_picocolors.default.red("Name is required (tab writes default)")); process.exit(1); } if (reservedNames.includes(value)) { console.error(_picocolors.default.red(`Reserved name ${_picocolors.default.bold(value)} cannot be used`)); process.exit(1); } if (value.toLocaleLowerCase() !== value) { console.error(_picocolors.default.red("Name must be lowercase")); process.exit(1); } if (/^\d/.test(value)) { console.error(_picocolors.default.red("Name cannot start with a number")); process.exit(1); } if (/[`~!@#$%^&*()_=+\[\]{}|;:\'",<.>\/?\\]/.test(value)) { console.error(_picocolors.default.red("No special characters allowed in name")); process.exit(1); } if (value.indexOf(' ') !== -1) { console.error(_picocolors.default.red("No spaces allowed in name")); process.exit(1); } if (value.indexOf('-') === -1 || value.replace('--', '') !== value || value[0] === '-' || value[value.length - 1] === '-') { console.error(_picocolors.default.red("Name must include at least one `-` and must not start or end name.")); process.exit(1); } // Check for any other syntax errors if (!/^[a-z][a-z0-9.\-]*\-[a-z0-9.\-]*$/.test(value)) { console.error(_picocolors.default.red(`Name must follow the syntax ${_picocolors.default.bold("my-component")}`)); process.exit(1); } // assumes auto was selected in CLI let joint = process.cwd(); if (commandRun.options.path) { joint = commandRun.options.path; } if (fs.existsSync(path.join(joint, value))) { console.error(_picocolors.default.red(`${path.join(joint, value)} exists, rename this project`)); process.exit(1); } } const project = { name: commandRun.options.name, mainModule: packageData.name, path: process.cwd(), className: (0, _utils.dashToCamel)(commandRun.options.name), year: new Date().getFullYear() }; if (packageData.author) { project.author = packageData.author.name; } const filePath = `${project.path}/${project.name}.js`; await fs.copyFileSync(`${process.mainModule.path}/templates/generic/webcomponent.js`, filePath); const ejsString = ejs.fileLoader(filePath, 'utf8'); let content = ejs.render(ejsString, project); // file written successfully fs.writeFileSync(filePath, content); p.note(`šŸ§™ Add to another web component (.js): ${_picocolors.default.underline(_picocolors.default.bold(_picocolors.default.yellow(_picocolors.default.bgBlack(`import ./${project.name}.js`))))} šŸ’» Add to an HTML file: ${_picocolors.default.bold(_picocolors.default.yellow(_picocolors.default.bgBlack(`<script type="module" src="${project.name}"></script>`)))}`); // at least a second to see the message print at all await (0, _promises.setTimeout)(1000); } catch (e) { (0, _logging.log)(e.stderr); // Original ejs.render error checking console.error(_picocolors.default.red(process.cwd())); console.error(_picocolors.default.red(e)); } break; case "wc:haxproperties": case "webcomponent:haxproperties": try { if (packageData.customElements) { await webcomponentGenerateHAXSchema(commandRun, packageData); } } catch (e) { (0, _logging.log)(e.stderr); } break; case "quit": // quit process.exit(0); break; } // y or noi need to act like it ran and finish instead of looping options if (commandRun.options.y || !commandRun.options.i || !actionAssigned) { process.exit(0); } operation.action = null; } } // merge the web component factory libraries the user has installed async function webcomponentGenerateHAXSchema(commandRun, packageData) { // run analyzer automatically if we have it so that it's up to date if (packageData.scripts.analyze) { await (0, _utils.exec)(`${commandRun.options.npmClient} run analyze`); } if (fs.existsSync(`${process.cwd()}/${packageData.customElements}`)) { const ceFileData = fs.readFileSync(`${process.cwd()}/${packageData.customElements}`, 'utf8', (error, data) => { if (error) { console.warn(error); return; } return data; }); let wiring = new HAXWiring(); if (commandRun.options.debug) { (0, _logging.log)(ceFileData, 'debug'); } if (ceFileData) { let ce = JSON.parse(ceFileData); await ce.modules.forEach(async modules => { await modules.declarations.forEach(async declarations => { let props = wiring.prototypeHaxProperties(); props.gizmo.title = declarations.tagName.replace('-', ' '); props.gizmo.tags = ["Other"]; props.gizmo.handles = []; props.gizmo.meta.author = "HAXTheWeb core team"; delete props.gizmo.shortcutKey; delete props.gizmo.requiresChildren; delete props.gizmo.requiresParent; props.settings.configure = []; props.settings.advanced = []; props.documentation = { howTo: null, purpose: null }; props.saveOptions = { unsetAttributes: [] }; props.demoSchema = [{ tag: declarations.tagName, content: "", properties: {} }]; let propData = []; if (declarations.attributes) { propData = declarations.attributes; } // loop through and if props are things we can map then do it await propData.forEach(async prop => { if (["t", "colors", '_haxState', "elementVisible"].includes(prop.fieldName)) { props.saveOptions.unsetAttributes.push(prop.fieldName); } else { let type = "textfield"; if (prop.type && prop.type.text) { type = getInputMethodFromType(prop.type.text); } if (type) { let propSchema = { property: prop.fieldName, title: prop.name, description: "", inputMethod: type }; if (prop.default !== undefined) { props.demoSchema[0].properties[prop.fieldName] = prop.default; } props.settings.configure.push(propSchema); } } }); if (commandRun.options.v) { (0, _logging.log)(JSON.stringify(props, null, 2), 'silly'); } fs.writeFileSync(`./lib/${declarations.tagName}.haxProperties.json`, JSON.stringify(props, null, 2)); (0, _logging.log)(`schema written to: ./lib/${declarations.tagName}.haxProperties.json`); }); }); } } } function getInputMethodFromType(type) { switch (type) { case "string": return "textfield"; case "number": return "number"; case "boolean": return "boolean"; } return false; }