@haxtheweb/create
Version:
CLI for all things HAX the web
696 lines (680 loc) ⢠31.8 kB
JavaScript
;
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;
}