@mathiscode/pucc 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +314 -0
- package/dist/commands/about.d.ts +6 -0
- package/dist/commands/about.d.ts.map +1 -0
- package/dist/commands/echo.d.ts +3 -0
- package/dist/commands/echo.d.ts.map +1 -0
- package/dist/commands/help.d.ts +6 -0
- package/dist/commands/help.d.ts.map +1 -0
- package/dist/components/ShellTerminal.d.ts +73 -0
- package/dist/components/ShellTerminal.d.ts.map +1 -0
- package/dist/components/TerminalLogger.d.ts +12 -0
- package/dist/components/TerminalLogger.d.ts.map +1 -0
- package/dist/core/CommandParser.d.ts +17 -0
- package/dist/core/CommandParser.d.ts.map +1 -0
- package/dist/core/DevToolsShell.d.ts +38 -0
- package/dist/core/DevToolsShell.d.ts.map +1 -0
- package/dist/core/Pucc.d.ts +74 -0
- package/dist/core/Pucc.d.ts.map +1 -0
- package/dist/demo.css +349 -0
- package/dist/devtools-shell.esm.js +243 -0
- package/dist/devtools-shell.esm.js.map +7 -0
- package/dist/devtools-shell.js +242 -0
- package/dist/devtools-shell.js.map +7 -0
- package/dist/index.d.ts +8 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.html +285 -0
- package/dist/pucc.css +253 -0
- package/dist/pucc.css.map +7 -0
- package/dist/pucc.esm.css +253 -0
- package/dist/pucc.esm.css.map +7 -0
- package/dist/pucc.esm.js +10619 -0
- package/dist/pucc.esm.js.map +7 -0
- package/dist/pucc.js +10616 -0
- package/dist/pucc.js.map +7 -0
- package/dist/types.d.ts +38 -0
- package/dist/types.d.ts.map +1 -0
- package/package.json +64 -0
|
@@ -0,0 +1,242 @@
|
|
|
1
|
+
/*! devtools-shell v1.0.0 */
|
|
2
|
+
"use strict";
|
|
3
|
+
(() => {
|
|
4
|
+
// src/core/CommandParser.ts
|
|
5
|
+
var CommandParser = class {
|
|
6
|
+
/**
|
|
7
|
+
* Parse a command string into structured arguments
|
|
8
|
+
*/
|
|
9
|
+
static parse(input) {
|
|
10
|
+
const args = { _: [] };
|
|
11
|
+
const trimmed = input.trim();
|
|
12
|
+
if (!trimmed) {
|
|
13
|
+
return args;
|
|
14
|
+
}
|
|
15
|
+
let i = 0;
|
|
16
|
+
const length = trimmed.length;
|
|
17
|
+
while (i < length) {
|
|
18
|
+
while (i < length && /\s/.test(trimmed[i])) {
|
|
19
|
+
i++;
|
|
20
|
+
}
|
|
21
|
+
if (i >= length)
|
|
22
|
+
break;
|
|
23
|
+
const keyMatch = trimmed.slice(i).match(/^([a-zA-Z_][a-zA-Z0-9_]*)\s*=/);
|
|
24
|
+
if (keyMatch) {
|
|
25
|
+
const key = keyMatch[1];
|
|
26
|
+
i += keyMatch[0].length;
|
|
27
|
+
while (i < length && /\s/.test(trimmed[i])) {
|
|
28
|
+
i++;
|
|
29
|
+
}
|
|
30
|
+
let value = "";
|
|
31
|
+
let inQuotes = false;
|
|
32
|
+
let quoteChar = "";
|
|
33
|
+
if (i < length && (trimmed[i] === '"' || trimmed[i] === "'")) {
|
|
34
|
+
inQuotes = true;
|
|
35
|
+
quoteChar = trimmed[i];
|
|
36
|
+
i++;
|
|
37
|
+
}
|
|
38
|
+
while (i < length) {
|
|
39
|
+
const char = trimmed[i];
|
|
40
|
+
if (inQuotes) {
|
|
41
|
+
if (char === quoteChar) {
|
|
42
|
+
i++;
|
|
43
|
+
break;
|
|
44
|
+
}
|
|
45
|
+
value += char;
|
|
46
|
+
} else {
|
|
47
|
+
if (/\s/.test(char)) {
|
|
48
|
+
break;
|
|
49
|
+
}
|
|
50
|
+
value += char;
|
|
51
|
+
}
|
|
52
|
+
i++;
|
|
53
|
+
}
|
|
54
|
+
if (value === "true") {
|
|
55
|
+
args[key] = true;
|
|
56
|
+
} else if (value === "false") {
|
|
57
|
+
args[key] = false;
|
|
58
|
+
} else if (/^-?\d+$/.test(value)) {
|
|
59
|
+
args[key] = parseInt(value, 10);
|
|
60
|
+
} else if (/^-?\d*\.\d+$/.test(value)) {
|
|
61
|
+
args[key] = parseFloat(value);
|
|
62
|
+
} else {
|
|
63
|
+
args[key] = value;
|
|
64
|
+
}
|
|
65
|
+
} else {
|
|
66
|
+
let arg = "";
|
|
67
|
+
let inQuotes = false;
|
|
68
|
+
let quoteChar = "";
|
|
69
|
+
while (i < length) {
|
|
70
|
+
const char = trimmed[i];
|
|
71
|
+
if (!inQuotes && (char === '"' || char === "'")) {
|
|
72
|
+
inQuotes = true;
|
|
73
|
+
quoteChar = char;
|
|
74
|
+
i++;
|
|
75
|
+
continue;
|
|
76
|
+
}
|
|
77
|
+
if (inQuotes && char === quoteChar) {
|
|
78
|
+
inQuotes = false;
|
|
79
|
+
i++;
|
|
80
|
+
break;
|
|
81
|
+
}
|
|
82
|
+
if (!inQuotes && /\s/.test(char)) {
|
|
83
|
+
break;
|
|
84
|
+
}
|
|
85
|
+
arg += char;
|
|
86
|
+
i++;
|
|
87
|
+
}
|
|
88
|
+
if (arg) {
|
|
89
|
+
args._.push(arg);
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
return args;
|
|
94
|
+
}
|
|
95
|
+
};
|
|
96
|
+
|
|
97
|
+
// src/commands/help.ts
|
|
98
|
+
var helpCommand = (_args, shell2) => {
|
|
99
|
+
if (!shell2) {
|
|
100
|
+
console.error("DevToolsShell instance not available");
|
|
101
|
+
return;
|
|
102
|
+
}
|
|
103
|
+
const commands = shell2.getCommands();
|
|
104
|
+
if (commands.length === 0) {
|
|
105
|
+
console.log("No commands registered.");
|
|
106
|
+
return;
|
|
107
|
+
}
|
|
108
|
+
console.log("\n%cAvailable Commands:", "font-weight: bold; font-size: 14px;");
|
|
109
|
+
console.log("\u2500".repeat(50));
|
|
110
|
+
commands.forEach((cmd) => {
|
|
111
|
+
console.log(
|
|
112
|
+
`%c$${cmd.name}%c - ${cmd.description}`,
|
|
113
|
+
"color: #4CAF50; font-weight: bold;",
|
|
114
|
+
"color: inherit;"
|
|
115
|
+
);
|
|
116
|
+
});
|
|
117
|
+
console.log("\u2500".repeat(50));
|
|
118
|
+
console.log(`Total: ${commands.length} command(s)`);
|
|
119
|
+
};
|
|
120
|
+
|
|
121
|
+
// src/commands/about.ts
|
|
122
|
+
var aboutCommand = () => {
|
|
123
|
+
console.log("%cDevTools Shell", "font-size: 20px; font-weight: bold; color: #2196F3;");
|
|
124
|
+
console.log("\u2500".repeat(50));
|
|
125
|
+
console.log("Version: 1.0.0");
|
|
126
|
+
console.log("A browser console command system library");
|
|
127
|
+
console.log("Built with TypeScript and esbuild");
|
|
128
|
+
console.log("\u2500".repeat(50));
|
|
129
|
+
console.log(
|
|
130
|
+
"Use %c$help%c to see available commands",
|
|
131
|
+
"color: #4CAF50; font-weight: bold;",
|
|
132
|
+
"color: inherit;"
|
|
133
|
+
);
|
|
134
|
+
};
|
|
135
|
+
|
|
136
|
+
// src/core/DevToolsShell.ts
|
|
137
|
+
var DevToolsShell = class {
|
|
138
|
+
constructor() {
|
|
139
|
+
this.commands = /* @__PURE__ */ new Map();
|
|
140
|
+
this.initialized = false;
|
|
141
|
+
this.registerBuiltInCommands();
|
|
142
|
+
}
|
|
143
|
+
/**
|
|
144
|
+
* Register a custom command
|
|
145
|
+
*/
|
|
146
|
+
addCommand(name, handler, description) {
|
|
147
|
+
if (!name || typeof name !== "string") {
|
|
148
|
+
throw new Error("Command name must be a non-empty string");
|
|
149
|
+
}
|
|
150
|
+
if (name.startsWith("$")) {
|
|
151
|
+
throw new Error("Command name should not include the $ prefix");
|
|
152
|
+
}
|
|
153
|
+
if (typeof handler !== "function") {
|
|
154
|
+
throw new Error("Command handler must be a function");
|
|
155
|
+
}
|
|
156
|
+
if (this.commands.has(name)) {
|
|
157
|
+
console.warn(`Command "${name}" already exists. Overwriting...`);
|
|
158
|
+
}
|
|
159
|
+
this.commands.set(name, {
|
|
160
|
+
name,
|
|
161
|
+
description: description || "No description provided",
|
|
162
|
+
handler
|
|
163
|
+
});
|
|
164
|
+
this.attachCommandToWindow(name);
|
|
165
|
+
}
|
|
166
|
+
/**
|
|
167
|
+
* Execute a command by name with arguments
|
|
168
|
+
*/
|
|
169
|
+
execute(commandName, input = "") {
|
|
170
|
+
const command = this.commands.get(commandName);
|
|
171
|
+
if (!command) {
|
|
172
|
+
console.error(`Command "${commandName}" not found. Use $help to see available commands.`);
|
|
173
|
+
return;
|
|
174
|
+
}
|
|
175
|
+
try {
|
|
176
|
+
const args = CommandParser.parse(input);
|
|
177
|
+
const result = command.handler(args, this);
|
|
178
|
+
if (result instanceof Promise) {
|
|
179
|
+
result.catch((error) => {
|
|
180
|
+
console.error(`Error executing command "${commandName}":`, error);
|
|
181
|
+
});
|
|
182
|
+
}
|
|
183
|
+
} catch (error) {
|
|
184
|
+
console.error(`Error executing command "${commandName}":`, error);
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
/**
|
|
188
|
+
* Get all registered commands
|
|
189
|
+
*/
|
|
190
|
+
getCommands() {
|
|
191
|
+
return Array.from(this.commands.values());
|
|
192
|
+
}
|
|
193
|
+
/**
|
|
194
|
+
* Get a specific command by name
|
|
195
|
+
*/
|
|
196
|
+
getCommand(name) {
|
|
197
|
+
return this.commands.get(name);
|
|
198
|
+
}
|
|
199
|
+
/**
|
|
200
|
+
* Initialize the shell and attach to window
|
|
201
|
+
*/
|
|
202
|
+
initialize() {
|
|
203
|
+
if (this.initialized) {
|
|
204
|
+
return;
|
|
205
|
+
}
|
|
206
|
+
this.commands.forEach((_, name) => {
|
|
207
|
+
this.attachCommandToWindow(name);
|
|
208
|
+
});
|
|
209
|
+
this.initialized = true;
|
|
210
|
+
}
|
|
211
|
+
/**
|
|
212
|
+
* Register built-in commands
|
|
213
|
+
*/
|
|
214
|
+
registerBuiltInCommands() {
|
|
215
|
+
this.addCommand("help", helpCommand, "Display all available commands");
|
|
216
|
+
this.addCommand("about", aboutCommand, "Show library information");
|
|
217
|
+
}
|
|
218
|
+
/**
|
|
219
|
+
* Attach a command to window as $commandName
|
|
220
|
+
*/
|
|
221
|
+
attachCommandToWindow(name) {
|
|
222
|
+
const windowName = `$${name}`;
|
|
223
|
+
window[windowName] = (...args) => {
|
|
224
|
+
const input = args.length > 0 ? args.join(" ") : "";
|
|
225
|
+
this.execute(name, input);
|
|
226
|
+
};
|
|
227
|
+
}
|
|
228
|
+
};
|
|
229
|
+
|
|
230
|
+
// src/index.ts
|
|
231
|
+
var shell = new DevToolsShell();
|
|
232
|
+
if (typeof window !== "undefined") {
|
|
233
|
+
shell.initialize();
|
|
234
|
+
window.DevToolsShell = shell;
|
|
235
|
+
Promise.resolve().then(() => {
|
|
236
|
+
if (window.DevToolsShell !== shell) {
|
|
237
|
+
window.DevToolsShell = shell;
|
|
238
|
+
}
|
|
239
|
+
});
|
|
240
|
+
}
|
|
241
|
+
})();
|
|
242
|
+
//# sourceMappingURL=devtools-shell.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../src/core/CommandParser.ts", "../src/commands/help.ts", "../src/commands/about.ts", "../src/core/DevToolsShell.ts", "../src/index.ts"],
|
|
4
|
+
"sourcesContent": ["import type { ParsedArgs } from '../types';\n\n/**\n * Parses command strings into structured arguments\n * Supports both positional arguments and key=value pairs\n *\n * Examples:\n * - `$new customer` \u2192 `{ _: ['customer'] }`\n * - `name=\"John Smith\" balance=5400` \u2192 `{ name: \"John Smith\", balance: 5400 }`\n * - `$new customer name=\"John\"` \u2192 `{ _: ['customer'], name: \"John\" }`\n */\nexport class CommandParser {\n /**\n * Parse a command string into structured arguments\n */\n static parse(input: string): ParsedArgs {\n const args: ParsedArgs = { _: [] };\n const trimmed = input.trim();\n\n if (!trimmed) {\n return args;\n }\n\n let i = 0;\n const length = trimmed.length;\n\n while (i < length) {\n // Skip whitespace\n while (i < length && /\\s/.test(trimmed[i])) {\n i++;\n }\n\n if (i >= length) break;\n\n // Check if this looks like a key=value pair (starts with identifier followed by =)\n const keyMatch = trimmed.slice(i).match(/^([a-zA-Z_][a-zA-Z0-9_]*)\\s*=/);\n \n if (keyMatch) {\n const key = keyMatch[1];\n i += keyMatch[0].length; // Move past \"key=\"\n \n // Skip whitespace after =\n while (i < length && /\\s/.test(trimmed[i])) {\n i++;\n }\n\n // Parse the value (may be quoted or unquoted)\n let value = '';\n let inQuotes = false;\n let quoteChar = '';\n \n if (i < length && (trimmed[i] === '\"' || trimmed[i] === \"'\")) {\n inQuotes = true;\n quoteChar = trimmed[i];\n i++; // Skip opening quote\n }\n\n while (i < length) {\n const char = trimmed[i];\n \n if (inQuotes) {\n if (char === quoteChar) {\n i++; // Skip closing quote\n break;\n }\n value += char;\n } else {\n // Unquoted value - stop at whitespace or end\n if (/\\s/.test(char)) {\n break;\n }\n value += char;\n }\n i++;\n }\n\n // Try to parse as number or boolean\n if (value === 'true') {\n args[key] = true;\n } else if (value === 'false') {\n args[key] = false;\n } else if (/^-?\\d+$/.test(value)) {\n args[key] = parseInt(value, 10);\n } else if (/^-?\\d*\\.\\d+$/.test(value)) {\n args[key] = parseFloat(value);\n } else {\n args[key] = value;\n }\n } else {\n // Positional argument\n let arg = '';\n let inQuotes = false;\n let quoteChar = '';\n \n while (i < length) {\n const char = trimmed[i];\n \n if (!inQuotes && (char === '\"' || char === \"'\")) {\n inQuotes = true;\n quoteChar = char;\n i++;\n continue;\n }\n \n if (inQuotes && char === quoteChar) {\n inQuotes = false;\n i++;\n break;\n }\n \n if (!inQuotes && /\\s/.test(char)) {\n break;\n }\n \n arg += char;\n i++;\n }\n \n if (arg) {\n args._.push(arg);\n }\n }\n }\n\n return args;\n }\n}\n", "import type { CommandHandler, Command } from '../types';\n\n/**\n * Built-in help command handler\n */\nexport const helpCommand: CommandHandler = (_args, shell) => {\n if (!shell) {\n console.error('DevToolsShell instance not available');\n return;\n }\n\n const commands = shell.getCommands();\n \n if (commands.length === 0) {\n console.log('No commands registered.');\n return;\n }\n\n console.log('\\n%cAvailable Commands:', 'font-weight: bold; font-size: 14px;');\n console.log('\u2500'.repeat(50));\n \n commands.forEach((cmd: Command) => {\n console.log(`%c$${cmd.name}%c - ${cmd.description}`, \n 'color: #4CAF50; font-weight: bold;', \n 'color: inherit;');\n });\n \n console.log('\u2500'.repeat(50));\n console.log(`Total: ${commands.length} command(s)`);\n};\n", "import type { CommandHandler } from '../types';\n\n/**\n * Built-in about command handler\n */\nexport const aboutCommand: CommandHandler = () => {\n console.log('%cDevTools Shell', 'font-size: 20px; font-weight: bold; color: #2196F3;');\n console.log('\u2500'.repeat(50));\n console.log('Version: 1.0.0');\n console.log('A browser console command system library');\n console.log('Built with TypeScript and esbuild');\n console.log('\u2500'.repeat(50));\n console.log('Use %c$help%c to see available commands', \n 'color: #4CAF50; font-weight: bold;', \n 'color: inherit;');\n};\n", "import type { Command, CommandHandler, ParsedArgs } from '../types';\nimport { CommandParser } from './CommandParser';\nimport { helpCommand } from '../commands/help';\nimport { aboutCommand } from '../commands/about';\n\n/**\n * Core DevToolsShell class managing command registry and execution\n */\nexport class DevToolsShell {\n private commands: Map<string, Command> = new Map();\n private initialized = false;\n\n constructor() {\n this.registerBuiltInCommands();\n }\n\n /**\n * Register a custom command\n */\n addCommand(name: string, handler: CommandHandler, description: string): void {\n if (!name || typeof name !== 'string') {\n throw new Error('Command name must be a non-empty string');\n }\n\n if (name.startsWith('$')) {\n throw new Error('Command name should not include the $ prefix');\n }\n\n if (typeof handler !== 'function') {\n throw new Error('Command handler must be a function');\n }\n\n if (this.commands.has(name)) {\n console.warn(`Command \"${name}\" already exists. Overwriting...`);\n }\n\n this.commands.set(name, {\n name,\n description: description || 'No description provided',\n handler,\n });\n\n // Attach to window for console access\n this.attachCommandToWindow(name);\n }\n\n /**\n * Execute a command by name with arguments\n */\n execute(commandName: string, input: string = ''): void {\n const command = this.commands.get(commandName);\n \n if (!command) {\n console.error(`Command \"${commandName}\" not found. Use $help to see available commands.`);\n return;\n }\n\n try {\n const args = CommandParser.parse(input);\n // Pass the shell instance to the handler so it can access shell methods\n const result = command.handler(args, this);\n \n // Handle async handlers\n if (result instanceof Promise) {\n result.catch((error) => {\n console.error(`Error executing command \"${commandName}\":`, error);\n });\n }\n } catch (error) {\n console.error(`Error executing command \"${commandName}\":`, error);\n }\n }\n\n /**\n * Get all registered commands\n */\n getCommands(): Command[] {\n return Array.from(this.commands.values());\n }\n\n /**\n * Get a specific command by name\n */\n getCommand(name: string): Command | undefined {\n return this.commands.get(name);\n }\n\n /**\n * Initialize the shell and attach to window\n */\n initialize(): void {\n if (this.initialized) {\n return;\n }\n\n // Attach all existing commands to window\n this.commands.forEach((_, name) => {\n this.attachCommandToWindow(name);\n });\n\n this.initialized = true;\n }\n\n /**\n * Register built-in commands\n */\n private registerBuiltInCommands(): void {\n this.addCommand('help', helpCommand, 'Display all available commands');\n this.addCommand('about', aboutCommand, 'Show library information');\n }\n\n /**\n * Attach a command to window as $commandName\n */\n private attachCommandToWindow(name: string): void {\n const windowName = `$${name}` as `$${string}`;\n \n // Create a function that can be called from console\n window[windowName] = (...args: any[]) => {\n // If called as a function with arguments, join them as a string\n const input = args.length > 0 ? args.join(' ') : '';\n this.execute(name, input);\n };\n }\n}\n", "import { DevToolsShell } from './core/DevToolsShell';\n\n// Export the main class\nexport { DevToolsShell };\nexport type { Command, CommandHandler, ParsedArgs } from './types';\n\n// Create and initialize the shell instance\n// For IIFE builds, this will be executed immediately when the script loads\nconst shell = new DevToolsShell();\n\n// Auto-initialize when loaded in browser (for IIFE builds)\nif (typeof window !== 'undefined') {\n shell.initialize();\n \n // Set the instance on window for user access\n // We assign it directly - if esbuild's globalName overwrites it,\n // we'll fix it in the next microtask\n window.DevToolsShell = shell;\n \n // Ensure our instance assignment takes precedence over esbuild's globalName\n // by setting it again after the current execution context\n Promise.resolve().then(() => {\n if (window.DevToolsShell !== shell) {\n window.DevToolsShell = shell;\n }\n });\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
|
+
"names": ["shell"]
|
|
7
|
+
}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { Pucc } from './core/Pucc';
|
|
2
|
+
import { ShellTerminal } from './components/ShellTerminal';
|
|
3
|
+
import { TerminalLogger } from './components/TerminalLogger';
|
|
4
|
+
export { Pucc };
|
|
5
|
+
export { ShellTerminal };
|
|
6
|
+
export { TerminalLogger };
|
|
7
|
+
export type { Command, CommandHandler, ParsedArgs } from './types';
|
|
8
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,MAAM,aAAa,CAAC;AACnC,OAAO,EAAE,aAAa,EAAE,MAAM,4BAA4B,CAAC;AAC3D,OAAO,EAAE,cAAc,EAAE,MAAM,6BAA6B,CAAC;AAM7D,OAAO,EAAE,IAAI,EAAE,CAAC;AAChB,OAAO,EAAE,aAAa,EAAE,CAAC;AACzB,OAAO,EAAE,cAAc,EAAE,CAAC;AAC1B,YAAY,EAAE,OAAO,EAAE,cAAc,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC"}
|
package/dist/index.html
ADDED
|
@@ -0,0 +1,285 @@
|
|
|
1
|
+
<!DOCTYPE html>
|
|
2
|
+
<html lang="en">
|
|
3
|
+
<head>
|
|
4
|
+
<meta charset="UTF-8">
|
|
5
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
6
|
+
<title>Pucc : Power User Console Component</title>
|
|
7
|
+
<link rel="stylesheet" href="demo.css">
|
|
8
|
+
</head>
|
|
9
|
+
<body>
|
|
10
|
+
<div class="container">
|
|
11
|
+
<div class="hero">
|
|
12
|
+
<h1>Pucc</h1>
|
|
13
|
+
<h2>Power User Console Component</h2>
|
|
14
|
+
<h3>Made with ❤️ by <a href="https://github.com/mathiscode">Jay Mathis</a></h3>
|
|
15
|
+
<div class="github-link">
|
|
16
|
+
<a href="https://github.com/mathiscode/pucc" target="_blank" rel="noopener noreferrer" class="github-button">
|
|
17
|
+
<svg width="20" height="20" viewBox="0 0 24 24" fill="currentColor" aria-hidden="true">
|
|
18
|
+
<path d="M12 0c-6.626 0-12 5.373-12 12 0 5.302 3.438 9.8 8.207 11.387.599.111.793-.261.793-.577v-2.234c-3.338.726-4.033-1.416-4.033-1.416-.546-1.387-1.333-1.756-1.333-1.756-1.089-.745.083-.729.083-.729 1.205.084 1.839 1.237 1.839 1.237 1.07 1.834 2.807 1.304 3.492.997.107-.775.418-1.305.762-1.604-2.665-.305-5.467-1.334-5.467-5.931 0-1.311.469-2.381 1.236-3.221-.124-.303-.535-1.524.117-3.176 0 0 1.008-.322 3.301 1.23.957-.266 1.983-.399 3.003-.404 1.02.005 2.047.138 3.006.404 2.291-1.552 3.297-1.23 3.297-1.23.653 1.653.242 2.874.118 3.176.77.84 1.235 1.911 1.235 3.221 0 4.609-2.807 5.624-5.479 5.921.43.372.823 1.102.823 2.222v3.293c0 .319.192.694.801.576 4.765-1.589 8.199-6.086 8.199-11.386 0-6.627-5.373-12-12-12z"/>
|
|
19
|
+
</svg>
|
|
20
|
+
<span>View on GitHub</span>
|
|
21
|
+
</a>
|
|
22
|
+
</div>
|
|
23
|
+
<p>A browser library that provides a console command system. Register custom commands and execute them via the browser console with a <code>$</code> (configurable) prefix or via the dropdown or embedded terminal Custom Element.</p>
|
|
24
|
+
<br />
|
|
25
|
+
<p>This can be very useful for web apps that need to provide a console for users to interact with the app, bypassing the UI for power users.</p>
|
|
26
|
+
</div>
|
|
27
|
+
|
|
28
|
+
<div class="terminal-container">
|
|
29
|
+
<h2>Dropdown Terminal <span class="badge">Alt+S</span></h2>
|
|
30
|
+
<p style="color: var(--text-muted); margin-bottom: 1rem;">
|
|
31
|
+
Press <kbd>Alt</kbd> + <kbd>S</kbd> (hotkey configurable) to open a dropdown terminal that slides down from the top of the page. Press <kbd>Escape</kbd> to close it.
|
|
32
|
+
</p>
|
|
33
|
+
<div id="dropdown-terminal">
|
|
34
|
+
<p style="color: var(--text-muted); margin: 0; text-align: center;">
|
|
35
|
+
The dropdown terminal will appear at the top of the page when you press <kbd>Alt</kbd> + <kbd>S</kbd>
|
|
36
|
+
</p>
|
|
37
|
+
</div>
|
|
38
|
+
</div>
|
|
39
|
+
|
|
40
|
+
<div class="terminal-container" style="margin-bottom: 3rem;">
|
|
41
|
+
<h2>Embedded Terminal <span class="badge">Live Demo</span></h2>
|
|
42
|
+
<p style="color: var(--text-muted); margin-bottom: 1rem;">A terminal embedded directly in the page. Try commands like <code>help</code> or <code>about</code>:</p>
|
|
43
|
+
<div id="embedded-terminal"></div>
|
|
44
|
+
</div>
|
|
45
|
+
|
|
46
|
+
<div class="content-grid">
|
|
47
|
+
<div class="card">
|
|
48
|
+
<h2>Installation</h2>
|
|
49
|
+
<p>Get started with Pucc in seconds. Choose your preferred package manager:</p>
|
|
50
|
+
<p><strong>Via pnpm/yarn/npm</strong></p>
|
|
51
|
+
<pre><code>pnpm add @mathiscode/pucc # or yarn add / npm install</code></pre>
|
|
52
|
+
<p><strong>Via Script Tag</strong></p>
|
|
53
|
+
<pre><code><script src="https://unpkg.com/@mathiscode/pucc/dist/pucc.js"></script></code></pre>
|
|
54
|
+
</div>
|
|
55
|
+
|
|
56
|
+
<div class="card">
|
|
57
|
+
<h2>Usage</h2>
|
|
58
|
+
<p>After including the library, commands are automatically available in the browser console:</p>
|
|
59
|
+
<pre><code>$help() // Lists all available commands
|
|
60
|
+
$about() // Shows library information</code></pre>
|
|
61
|
+
</div>
|
|
62
|
+
|
|
63
|
+
<div class="card">
|
|
64
|
+
<h2>Adding Custom Commands</h2>
|
|
65
|
+
<p>Register a new command with ease:</p>
|
|
66
|
+
<pre><code>Pucc.addCommand('new', (args) => {
|
|
67
|
+
console.log('Creating:', args._[0]);
|
|
68
|
+
console.log('Arguments:', args);
|
|
69
|
+
}, 'Create a new entity');</code></pre>
|
|
70
|
+
<p>Now you can use it in the console or dropdown terminal:</p>
|
|
71
|
+
<pre><code>$new('customer', 'name="John Smith"', 'balance=5400')
|
|
72
|
+
new customer name="John Smith" balance=5400</code></pre>
|
|
73
|
+
</div>
|
|
74
|
+
|
|
75
|
+
<div class="card">
|
|
76
|
+
<h2>Terminal Types</h2>
|
|
77
|
+
<p><strong>Embedded Terminal</strong></p>
|
|
78
|
+
<p>Embedded terminals are always visible on the page. Use the <code>embedded</code> attribute:</p>
|
|
79
|
+
<pre><code><pucc-terminal embedded="true"></pucc-terminal></code></pre>
|
|
80
|
+
<p><strong>Dropdown Terminal</strong></p>
|
|
81
|
+
<p>Dropdown terminals slide down from the top when activated via hotkey (default: <kbd>Alt</kbd> + <kbd>S</kbd>). Press <kbd>Escape</kbd> to close.</p>
|
|
82
|
+
<pre><code><pucc-terminal></pucc-terminal></code></pre>
|
|
83
|
+
</div>
|
|
84
|
+
|
|
85
|
+
<div class="card">
|
|
86
|
+
<h2>Configuration</h2>
|
|
87
|
+
<p>Customize the terminal with attributes:</p>
|
|
88
|
+
<pre><code><pucc-terminal
|
|
89
|
+
embedded="true"
|
|
90
|
+
height="300px"
|
|
91
|
+
theme="dark"
|
|
92
|
+
prompt="# "
|
|
93
|
+
hotkey="alt+s"
|
|
94
|
+
pucc-options='{"enableGlobalRegistrations": false}'>
|
|
95
|
+
</pucc-terminal></code></pre>
|
|
96
|
+
<p><strong>Attributes:</strong></p>
|
|
97
|
+
<ul style="color: var(--text-muted); margin: 0.5rem 0; padding-left: 1.5rem;">
|
|
98
|
+
<li><code>embedded</code> - Set to "true" for embedded mode</li>
|
|
99
|
+
<li><code>height</code> - Terminal height (e.g., "300px", "50vh")</li>
|
|
100
|
+
<li><code>theme</code> - Color theme ("dark" or "light")</li>
|
|
101
|
+
<li><code>prompt</code> - Custom prompt text (default: "$ ")</li>
|
|
102
|
+
<li><code>hotkey</code> - Keyboard shortcut for dropdown (e.g., "alt+s")</li>
|
|
103
|
+
<li><code>pucc-options</code> - JSON string with Pucc constructor options (see "Passing Pucc Options to Terminal" card)</li>
|
|
104
|
+
</ul>
|
|
105
|
+
</div>
|
|
106
|
+
|
|
107
|
+
<div class="card">
|
|
108
|
+
<h2>Command Execution</h2>
|
|
109
|
+
<p><strong>Browser Console</strong></p>
|
|
110
|
+
<p>In the browser console, use the <code>$</code> prefix and call it as a function:</p>
|
|
111
|
+
<pre><code>$help()
|
|
112
|
+
$about()</code></pre>
|
|
113
|
+
<p><strong>Terminal Component</strong></p>
|
|
114
|
+
<p>In embedded or dropdown terminals, type commands directly without the prefix:</p>
|
|
115
|
+
<pre><code>help
|
|
116
|
+
about</code></pre>
|
|
117
|
+
</div>
|
|
118
|
+
|
|
119
|
+
<div class="card">
|
|
120
|
+
<h2>Command Arguments</h2>
|
|
121
|
+
<p>The command parser supports flexible argument formats:</p>
|
|
122
|
+
<p><strong>Positional arguments:</strong></p>
|
|
123
|
+
<pre><code>$new customer
|
|
124
|
+
// args = { _: ['customer'] }</code></pre>
|
|
125
|
+
<p><strong>Key-value pairs:</strong></p>
|
|
126
|
+
<pre><code>$new name="John Smith" balance=5400
|
|
127
|
+
// args = { name: "John Smith", balance: 5400 }</code></pre>
|
|
128
|
+
<p><strong>Mixed (positional + key-value):</strong></p>
|
|
129
|
+
<pre><code>$new customer name="John Smith" balance=5400
|
|
130
|
+
// args = { _: ['customer'], name: "John Smith", balance: 5400 }</code></pre>
|
|
131
|
+
<p><strong>Type conversion:</strong></p>
|
|
132
|
+
<ul style="color: var(--text-muted); margin: 0.5rem 0; padding-left: 1.5rem;">
|
|
133
|
+
<li>Numbers: <code>balance=5400</code> → <code>5400</code> (number)</li>
|
|
134
|
+
<li>Booleans: <code>active=true</code> → <code>true</code> (boolean)</li>
|
|
135
|
+
<li>Strings: <code>name="John"</code> → <code>"John"</code> (string)</li>
|
|
136
|
+
</ul>
|
|
137
|
+
</div>
|
|
138
|
+
|
|
139
|
+
<div class="card">
|
|
140
|
+
<h2>Module Import (ESM)</h2>
|
|
141
|
+
<p>When using ESM, no global instance is created automatically. You have full control:</p>
|
|
142
|
+
<pre><code>import { Pucc } from 'pucc';
|
|
143
|
+
|
|
144
|
+
// Option 1: Create a global instance (like IIFE build)
|
|
145
|
+
const shell = new Pucc();
|
|
146
|
+
shell.initialize();
|
|
147
|
+
// Now commands are available: $help(), $about()
|
|
148
|
+
|
|
149
|
+
// Option 2: Create a terminal-only instance
|
|
150
|
+
const shell = new Pucc({ enableGlobalRegistrations: false });
|
|
151
|
+
// Commands only available in terminal elements, not globally</code></pre>
|
|
152
|
+
</div>
|
|
153
|
+
|
|
154
|
+
<div class="card">
|
|
155
|
+
<h2>Disabling Global Registrations</h2>
|
|
156
|
+
<p>Limit commands to the terminal only (avoiding global namespace pollution):</p>
|
|
157
|
+
<pre><code>import { Pucc } from 'pucc';
|
|
158
|
+
|
|
159
|
+
const shell = new Pucc({ enableGlobalRegistrations: false });
|
|
160
|
+
|
|
161
|
+
// Commands will only be available through the terminal
|
|
162
|
+
// They will NOT be accessible via window.$commandName
|
|
163
|
+
shell.addCommand('mycommand', (args) => {
|
|
164
|
+
console.log('This command is only available in the terminal');
|
|
165
|
+
}, 'A terminal-only command');</code></pre>
|
|
166
|
+
</div>
|
|
167
|
+
|
|
168
|
+
<div class="card">
|
|
169
|
+
<h2>Custom Command Prefix</h2>
|
|
170
|
+
<p>Customize the command prefix (must be a valid JavaScript identifier):</p>
|
|
171
|
+
<pre><code>import { Pucc } from 'pucc';
|
|
172
|
+
|
|
173
|
+
const shell = new Pucc({ commandPrefix: 'cmd' });
|
|
174
|
+
|
|
175
|
+
// Now commands can be called with the custom prefix
|
|
176
|
+
// cmdhelp() or cmdabout() in the console
|
|
177
|
+
// Or without prefix: help() or about()
|
|
178
|
+
|
|
179
|
+
shell.addCommand('greet', (args) => {
|
|
180
|
+
console.log(`Hello, ${args._[0] || 'World'}!`);
|
|
181
|
+
}, 'Greet someone');
|
|
182
|
+
|
|
183
|
+
// Can be called as: cmdgreet('Alice') or greet('Alice')</code></pre>
|
|
184
|
+
<p><strong>Valid prefixes:</strong> <code>$</code>, <code>_</code>, <code>cmd</code>, <code>myPrefix</code>, <code>prefix123</code>, <code>_prefix</code></p>
|
|
185
|
+
<p style="color: var(--text-muted); font-size: 0.9em; margin-top: 0.5rem;">The prefix must be a valid JavaScript identifier (starts with a letter, underscore, or dollar sign; can only contain letters, digits, underscores, and dollar signs).</p>
|
|
186
|
+
</div>
|
|
187
|
+
|
|
188
|
+
<div class="card">
|
|
189
|
+
<h2>Passing Pucc Options to Terminal</h2>
|
|
190
|
+
<p>Configure Pucc options when using the <code>pucc-terminal</code> custom element:</p>
|
|
191
|
+
<p><strong>Via attribute (simple options):</strong></p>
|
|
192
|
+
<pre><code><pucc-terminal
|
|
193
|
+
embedded="true"
|
|
194
|
+
pucc-options='{"enableGlobalRegistrations": false, "commandPrefix": "_"}'>
|
|
195
|
+
</pucc-terminal></code></pre>
|
|
196
|
+
<p><strong>Via property (full functionality):</strong></p>
|
|
197
|
+
<pre><code>const terminal = document.querySelector('pucc-terminal');
|
|
198
|
+
|
|
199
|
+
terminal.puccOptions = {
|
|
200
|
+
enableGlobalRegistrations: false,
|
|
201
|
+
commandPrefix: 'cmd',
|
|
202
|
+
customHelpHandler: (args, shell) => {
|
|
203
|
+
console.log('Custom help!');
|
|
204
|
+
},
|
|
205
|
+
initialCommands: [
|
|
206
|
+
{
|
|
207
|
+
name: 'greet',
|
|
208
|
+
description: 'Greet someone',
|
|
209
|
+
handler: (args) => {
|
|
210
|
+
console.log(`Hello, ${args._[0] || 'World'}!`);
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
]
|
|
214
|
+
};</code></pre>
|
|
215
|
+
<p style="color: var(--text-muted); font-size: 0.9em; margin-top: 0.5rem;"><strong>Note:</strong> The <code>pucc-options</code> attribute only supports JSON-serializable options. For options that include functions, use the <code>puccOptions</code> property instead.</p>
|
|
216
|
+
</div>
|
|
217
|
+
|
|
218
|
+
<div class="card">
|
|
219
|
+
<h2>About the Author</h2>
|
|
220
|
+
<p>Pucc is created and maintained by <strong><a href="https://jaymath.is">Jay Mathis</a></strong>, a developer passionate about building useful tools for the web.</p>
|
|
221
|
+
<p><strong>Connect & Explore:</strong></p>
|
|
222
|
+
<ul style="color: var(--text-muted); margin: 0.5rem 0; padding-left: 1.5rem;">
|
|
223
|
+
<li><a href="https://github.com/mathiscode" target="_blank" rel="noopener noreferrer">GitHub Profile</a> - Check out other projects and contributions</li>
|
|
224
|
+
<li><a href="https://github.com/mathiscode/pucc" target="_blank" rel="noopener noreferrer">Pucc Repository</a> - Star, fork, or contribute to this project</li>
|
|
225
|
+
<li><a href="https://jaymath.is" target="_blank" rel="noopener noreferrer">Website</a> - Learn more about Jay and his work</li>
|
|
226
|
+
</ul>
|
|
227
|
+
<p style="color: var(--text-muted); font-size: 0.9em; margin-top: 0.5rem;">Found Pucc useful? Consider giving it <a href="https://github.com/mathiscode/pucc/stargazers" target="_blank" rel="noopener noreferrer">a star on GitHub</a>! ⭐</p>
|
|
228
|
+
</div>
|
|
229
|
+
</div>
|
|
230
|
+
</div>
|
|
231
|
+
|
|
232
|
+
<script src="pucc.js"></script>
|
|
233
|
+
|
|
234
|
+
<script>
|
|
235
|
+
function createTerminals() {
|
|
236
|
+
const embeddedContainer = document.getElementById('embedded-terminal');
|
|
237
|
+
const dropdownContainer = document.getElementById('dropdown-terminal');
|
|
238
|
+
|
|
239
|
+
if (embeddedContainer) {
|
|
240
|
+
const embeddedTerminal = document.createElement('pucc-terminal');
|
|
241
|
+
embeddedTerminal.setAttribute('embedded', 'true');
|
|
242
|
+
embeddedTerminal.setAttribute('height', '250px');
|
|
243
|
+
embeddedTerminal.setAttribute('theme', 'dark');
|
|
244
|
+
embeddedTerminal.setAttribute('prompt', '# ');
|
|
245
|
+
embeddedContainer.appendChild(embeddedTerminal);
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
if (dropdownContainer) {
|
|
249
|
+
const dropdownTerminal = document.createElement('pucc-terminal');
|
|
250
|
+
dropdownTerminal.setAttribute('height', '400px');
|
|
251
|
+
dropdownTerminal.setAttribute('theme', 'dark');
|
|
252
|
+
dropdownTerminal.setAttribute('prompt', '# ');
|
|
253
|
+
dropdownContainer.appendChild(dropdownTerminal);
|
|
254
|
+
}
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
if (customElements.get('pucc-terminal')) {
|
|
258
|
+
createTerminals();
|
|
259
|
+
} else {
|
|
260
|
+
customElements.whenDefined('pucc-terminal').then(() => {
|
|
261
|
+
createTerminals();
|
|
262
|
+
});
|
|
263
|
+
}
|
|
264
|
+
</script>
|
|
265
|
+
|
|
266
|
+
<script>
|
|
267
|
+
let lastModified = 0;
|
|
268
|
+
setInterval(async () => {
|
|
269
|
+
try {
|
|
270
|
+
const response = await fetch('pucc.js?t=' + Date.now(), { method: 'HEAD' });
|
|
271
|
+
const modified = response.headers.get('last-modified');
|
|
272
|
+
if (modified) {
|
|
273
|
+
const modifiedTime = new Date(modified).getTime();
|
|
274
|
+
if (lastModified > 0 && modifiedTime > lastModified) {
|
|
275
|
+
window.location.reload();
|
|
276
|
+
}
|
|
277
|
+
lastModified = modifiedTime;
|
|
278
|
+
}
|
|
279
|
+
} catch (e) {
|
|
280
|
+
// Ignore errors
|
|
281
|
+
}
|
|
282
|
+
}, 1000);
|
|
283
|
+
</script>
|
|
284
|
+
</body>
|
|
285
|
+
</html>
|