create nu_plugin_node_example.js (#15482)

example like
[nu_plugin_python_example.py](https://github.com/nushell/nushell/blob/main/crates/nu_plugin_python/nu_plugin_python_example.py)
This commit is contained in:
whi 2025-04-12 03:18:46 +08:00 committed by GitHub
parent c8c018452f
commit 017daeed18
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194

View File

@ -0,0 +1,248 @@
#!/usr/bin/env node
/**
* Node.js Nushell Plugin Example
* Communicates with Nushell via JSON-encoded messages over stdin/stdout
*
* Register command: `plugin add -s 'C:\Program Files\nodejs\node.exe' ./nu_plugin_node_example.js`
* `plugin use ./nu_plugin_node_example.js`
* Usage: node_example 2 "3"
*/
// Configuration constants
const NUSHELL_VERSION = '0.103.1';
const PLUGIN_VERSION = '0.1.1';
// Core protocol functions
/**
* Writes a structured response to stdout
* @param {number} id - Call identifier
* @param {object} response - Response payload
*/
function writeResponse (id, response) {
const message = JSON.stringify({ CallResponse: [id, response] });
process.stdout.write(`${message}\n`);
}
/**
* Writes an error response
* @param {number} id - Call identifier
* @param {string} text - Error description
* @param {object|null} span - Error location metadata
*/
function writeError (id, text, span = null) {
const error = span ? {
Error: {
msg: 'Plugin execution error',
labels: [{ text, span }]
}
} : {
Error: {
msg: 'Plugin configuration error',
help: text
}
};
writeResponse(id, error);
}
// Plugin capability definitions
/**
* Generates plugin signature metadata
* @returns {object} Structured plugin capabilities
*/
function getPluginSignature () {
return {
Signature: [{
sig: {
name: 'node_example',
description: 'Demonstration plugin for Node.js',
extra_description: '',
required_positional: [
{
name: 'a',
desc: 'Required integer parameter',
shape: 'Int'
},
{
name: 'b',
desc: 'Required string parameter',
shape: 'String'
}
],
optional_positional: [{
name: 'opt',
desc: 'Optional numeric parameter',
shape: 'Int'
}],
rest_positional: {
name: 'rest',
desc: 'Variable-length string parameters',
shape: 'String'
},
named: [
{
long: 'help',
short: 'h',
arg: null,
required: false,
desc: 'Display help information'
},
{
long: 'flag',
short: 'f',
arg: null,
required: false,
desc: 'Example boolean flag'
},
{
long: 'named',
short: 'n',
arg: 'String',
required: false,
desc: 'Example named parameter'
}
],
input_output_types: [['Any', 'Any']],
allow_variants_without_examples: true,
search_terms: ['nodejs', 'example'],
is_filter: false,
creates_scope: false,
allows_unknown_args: false,
category: 'Experimental'
},
examples: []
}]
};
}
/**
* Processes execution calls from Nushell
* @param {number} id - Call identifier
* @param {object} callData - Execution context metadata
*/
function processExecutionCall (id, callData) {
const span = callData.call.head;
// Generate sample tabular data
const tableData = Array.from({ length: 10 }, (_, index) => ({
Record: {
val: {
one: { Int: { val: index * 1, span } },
two: { Int: { val: index * 2, span } },
three: { Int: { val: index * 3, span } }
},
span
}
}));
writeResponse(id, {
PipelineData: {
Value: [{
List: {
vals: tableData,
span
}
}, null]
}
});
}
// Protocol handling
/**
* Handles different types of input messages
* @param {object} input - Parsed JSON message from Nushell
*/
function handleInputMessage (input) {
if (input.Hello) {
handleHelloMessage(input.Hello);
} else if (input === 'Goodbye') {
process.exit(0);
} else if (input.Call) {
handleCallMessage(...input.Call);
} else if (input.Signal) {
handleSignal(input.Signal);
}
}
function handleHelloMessage ({ version }) {
if (version !== NUSHELL_VERSION) {
process.stderr.write(`Version mismatch: Expected ${NUSHELL_VERSION}, got ${version}\n`);
process.exit(1);
}
}
function handleCallMessage (id, call) {
try {
if (call === 'Metadata') {
writeResponse(id, { Metadata: { version: PLUGIN_VERSION } });
} else if (call === 'Signature') {
writeResponse(id, getPluginSignature());
} else if (call.Run) {
processExecutionCall(id, call.Run);
} else {
writeError(id, `Unsupported operation: ${JSON.stringify(call)}`);
}
} catch (error) {
writeError(id, `Processing error: ${error.message}`);
}
}
function handleSignal (signal) {
if (signal !== 'Reset') {
process.stderr.write(`Unhandled signal: ${signal}\n`);
}
}
// Stream processing setup
/**
* Initializes plugin communication protocol
*/
function initializePlugin () {
// Set up JSON encoding
process.stdout.write('\x04json\n');
// Send handshake message
process.stdout.write(JSON.stringify({
Hello: {
protocol: 'nu-plugin',
version: NUSHELL_VERSION,
features: []
}
}) + '\n');
// Configure input processing
let buffer = '';
process.stdin.setEncoding('utf8')
.on('data', chunk => {
buffer += chunk;
const messages = buffer.split('\n');
buffer = messages.pop() || ''; // Preserve incomplete line
for (const message of messages) {
if (message.trim()) {
try {
handleInputMessage(JSON.parse(message));
} catch (error) {
process.stderr.write(`Parse error: ${error.message}\n`);
process.stderr.write(`Received: ${message}\n`);
}
}
}
})
.on('error', error => {
process.stderr.write(`Input error: ${error.message}\n`);
process.exit(1);
});
}
// Main execution
if (process.argv.includes('--stdio')) {
initializePlugin();
} else {
console.log('This plugin is intended to be run from within Nushell');
process.exit(2);
}