@udx/mq 0.1.1

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.
@@ -0,0 +1,191 @@
1
+ #!/usr/bin/env node
2
+
3
+ /**
4
+ * Example: Analyze Document Structure
5
+ *
6
+ * This example demonstrates how to use mq to analyze the structure
7
+ * and content of a markdown document.
8
+ */
9
+
10
+ import { fromMarkdown } from 'mdast-util-from-markdown';
11
+ import { toString } from 'mdast-util-to-string';
12
+ import { visit } from 'unist-util-visit';
13
+
14
+ // Example markdown content
15
+ const markdown = `# Architecture Overview
16
+
17
+ ## Introduction
18
+
19
+ This document provides an overview of our system architecture.
20
+
21
+ ## Components
22
+
23
+ ### API Gateway
24
+
25
+ The API Gateway handles all incoming requests.
26
+
27
+ ### Service Layer
28
+
29
+ The Service Layer contains business logic.
30
+
31
+ ### Data Layer
32
+
33
+ The Data Layer manages data persistence.
34
+
35
+ ## Deployment
36
+
37
+ We use a CI/CD pipeline for deployment.
38
+
39
+ ## References
40
+
41
+ - [AWS Documentation](https://aws.amazon.com/documentation/)
42
+ - [Kubernetes](https://kubernetes.io/)
43
+ - [Docker](https://www.docker.com/)
44
+ `;
45
+
46
+ // Parse markdown to AST
47
+ const ast = fromMarkdown(markdown);
48
+
49
+ // Analyze document structure
50
+ function analyzeDocument(ast) {
51
+ let analysis = '# Document Analysis\n\n';
52
+
53
+ // Count elements
54
+ const counts = {
55
+ headings: 0,
56
+ paragraphs: 0,
57
+ links: 0,
58
+ images: 0,
59
+ codeBlocks: 0,
60
+ lists: 0,
61
+ listItems: 0
62
+ };
63
+
64
+ visit(ast, (node) => {
65
+ switch (node.type) {
66
+ case 'heading':
67
+ counts.headings++;
68
+ break;
69
+ case 'paragraph':
70
+ counts.paragraphs++;
71
+ break;
72
+ case 'link':
73
+ counts.links++;
74
+ break;
75
+ case 'image':
76
+ counts.images++;
77
+ break;
78
+ case 'code':
79
+ counts.codeBlocks++;
80
+ break;
81
+ case 'list':
82
+ counts.lists++;
83
+ break;
84
+ case 'listItem':
85
+ counts.listItems++;
86
+ break;
87
+ }
88
+ });
89
+
90
+ // Add counts to analysis
91
+ analysis += '## Document Statistics\n\n';
92
+ Object.entries(counts).forEach(([key, value]) => {
93
+ analysis += `- **${key.charAt(0).toUpperCase() + key.slice(1)}**: ${value}\n`;
94
+ });
95
+
96
+ // Analyze heading structure
97
+ analysis += '\n## Heading Structure\n\n';
98
+
99
+ const headings = [];
100
+ visit(ast, 'heading', (node) => {
101
+ headings.push({
102
+ level: node.depth,
103
+ text: toString(node)
104
+ });
105
+ });
106
+
107
+ headings.forEach(heading => {
108
+ const indent = ' '.repeat(heading.level - 1);
109
+ analysis += `${indent}- ${heading.text}\n`;
110
+ });
111
+
112
+ // Analyze content distribution
113
+ analysis += '\n## Content Distribution\n\n';
114
+
115
+ // Count words in each section
116
+ const sections = [];
117
+ let currentHeading = null;
118
+ let currentContent = '';
119
+
120
+ visit(ast, (node) => {
121
+ if (node.type === 'heading') {
122
+ if (currentHeading) {
123
+ sections.push({
124
+ heading: currentHeading,
125
+ content: currentContent,
126
+ wordCount: currentContent.split(/\s+/).filter(Boolean).length
127
+ });
128
+ }
129
+ currentHeading = toString(node);
130
+ currentContent = '';
131
+ } else if (node.type === 'paragraph' || node.type === 'code') {
132
+ currentContent += toString(node) + ' ';
133
+ }
134
+ });
135
+
136
+ // Add the last section
137
+ if (currentHeading) {
138
+ sections.push({
139
+ heading: currentHeading,
140
+ content: currentContent,
141
+ wordCount: currentContent.split(/\s+/).filter(Boolean).length
142
+ });
143
+ }
144
+
145
+ // Sort sections by word count
146
+ sections.sort((a, b) => b.wordCount - a.wordCount);
147
+
148
+ // Display section word counts
149
+ analysis += '| Section | Word Count |\n';
150
+ analysis += '| --- | --- |\n';
151
+ sections.forEach(section => {
152
+ analysis += `| ${section.heading} | ${section.wordCount} |\n`;
153
+ });
154
+
155
+ // Analyze links
156
+ analysis += '\n## Links\n\n';
157
+
158
+ const links = [];
159
+ visit(ast, 'link', (node) => {
160
+ links.push({
161
+ text: toString(node),
162
+ href: node.url
163
+ });
164
+ });
165
+
166
+ if (links.length > 0) {
167
+ analysis += '| Text | URL |\n';
168
+ analysis += '| --- | --- |\n';
169
+ links.forEach(link => {
170
+ analysis += `| ${link.text} | ${link.href} |\n`;
171
+ });
172
+ } else {
173
+ analysis += 'No links found in the document.\n';
174
+ }
175
+
176
+ return analysis;
177
+ }
178
+
179
+ const analysis = analyzeDocument(ast);
180
+
181
+ console.log('Original Markdown:');
182
+ console.log('=================');
183
+ console.log(markdown);
184
+ console.log('\n');
185
+
186
+ console.log('Document Analysis:');
187
+ console.log('=================');
188
+ console.log(analysis);
189
+
190
+ // How to run this example:
191
+ // node examples/analyze-document.js
@@ -0,0 +1,47 @@
1
+ /**
2
+ * Example: Cross-Linker
3
+ *
4
+ * This example demonstrates how to use the mdoc cross-linking
5
+ * functionality to add related document references.
6
+ */
7
+
8
+ import { addCrossLinks } from '../index.js';
9
+
10
+ // Example markdown content
11
+ const markdown = `# Worker Architecture Documentation
12
+
13
+ ## Table of Contents
14
+ 1. [Introduction](#introduction)
15
+ 2. [Core Components](#core-components)
16
+ 3. [Implementation Guide](#implementation-guide)
17
+
18
+ ## Introduction
19
+
20
+ This document describes the Worker architecture.
21
+
22
+ ## Core Components
23
+
24
+ This section details the core components of the Worker architecture.
25
+
26
+ ## Implementation Guide
27
+
28
+ This section provides a guide for implementing the Worker architecture.
29
+ `;
30
+
31
+ // Add cross-links to related documents
32
+ const enhancedMarkdown = addCrossLinks(markdown, {
33
+ docs: [
34
+ { path: 'pipeline-as-code.md', description: 'Explore the deployment automation that integrates with Worker' },
35
+ { path: 'stateless.md', description: 'Learn how Worker enables stateless media management' },
36
+ { path: 'rabbit-ci.md', description: 'Understand the CI/CD platform that works with Worker' }
37
+ ]
38
+ });
39
+
40
+ console.log('Original Markdown:');
41
+ console.log('=================');
42
+ console.log(markdown);
43
+ console.log('\n');
44
+
45
+ console.log('Enhanced Markdown with Cross-Links:');
46
+ console.log('================================');
47
+ console.log(enhancedMarkdown);
@@ -0,0 +1,93 @@
1
+ #!/usr/bin/env node
2
+
3
+ /**
4
+ * mq - Architecture Files Demo
5
+ *
6
+ * This script demonstrates using mq with architecture files from the content/architecture directory.
7
+ *
8
+ * @todo move files being tested with into test/fixtures
9
+ */
10
+
11
+ import fs from 'fs/promises';
12
+ import path from 'path';
13
+ import { fileURLToPath } from 'url';
14
+ import { exec } from 'child_process';
15
+ import { promisify } from 'util';
16
+
17
+ const execAsync = promisify(exec);
18
+
19
+ // Get the directory name
20
+ const __dirname = path.dirname(fileURLToPath(import.meta.url));
21
+ const architectureDir = path.join(__dirname, '..', '..', 'content', 'architecture');
22
+ const mqPath = path.join(__dirname, 'index.js');
23
+
24
+ // Test cases for architecture files
25
+ const TEST_CASES = [
26
+ {
27
+ name: 'Extract headings from pipeline-as-code.md',
28
+ command: `node ${mqPath} '.headings[]' -i ${path.join(architectureDir, 'pipeline-as-code.md')} | head -20`,
29
+ description: 'Extracts the first 20 headings from the pipeline-as-code.md file'
30
+ },
31
+ {
32
+ name: 'Generate TOC for data-discovery.md',
33
+ command: `node ${mqPath} '.toc' -i ${path.join(architectureDir, 'data-discovery.md')} | head -20`,
34
+ description: 'Generates a table of contents for the data-discovery.md file'
35
+ },
36
+ {
37
+ name: 'Count elements in content-website.md',
38
+ command: `node ${mqPath} --count -i ${path.join(architectureDir, 'content-website.md')}`,
39
+ description: 'Counts document elements in the content-website.md file'
40
+ },
41
+ {
42
+ name: 'Analyze document structure of wordpress-implementation.md',
43
+ command: `node ${mqPath} --structure -i ${path.join(architectureDir, 'wordpress-implementation.md')} | head -20`,
44
+ description: 'Shows the document structure of the wordpress-implementation.md file'
45
+ },
46
+ {
47
+ name: 'Extract code blocks from hoxler.md',
48
+ command: `node ${mqPath} '.codeBlocks[]' -i ${path.join(architectureDir, 'hoxler.md')} | head -20`,
49
+ description: 'Extracts code blocks from the hoxler.md file'
50
+ },
51
+ {
52
+ name: 'Extract links from transact-campus.md',
53
+ command: `node ${mqPath} '.links[]' -i ${path.join(architectureDir, 'transact-campus.md')} | head -20`,
54
+ description: 'Extracts links from the transact-campus.md file'
55
+ },
56
+ {
57
+ name: 'Full document analysis of worker.md',
58
+ command: `node ${mqPath} --analyze -i ${path.join(architectureDir, 'worker.md')} | head -40`,
59
+ description: 'Performs a full document analysis of the worker.md file'
60
+ }
61
+ ];
62
+
63
+ // Run the demo
64
+ async function runDemo() {
65
+ console.log('Running mq demo with architecture files...\n');
66
+
67
+ for (const testCase of TEST_CASES) {
68
+ console.log(`\n=== ${testCase.name} ===`);
69
+ console.log(`Description: ${testCase.description}`);
70
+ console.log(`Command: ${testCase.command}`);
71
+ console.log('\nOutput:');
72
+
73
+ try {
74
+ const { stdout, stderr } = await execAsync(testCase.command);
75
+
76
+ if (stderr) {
77
+ console.error(`Error: ${stderr}`);
78
+ continue;
79
+ }
80
+
81
+ console.log(stdout);
82
+ } catch (error) {
83
+ console.error(`Error running test "${testCase.name}":`, error.message);
84
+ }
85
+
86
+ console.log('\n' + '-'.repeat(80));
87
+ }
88
+
89
+ console.log('\nDemo completed successfully!');
90
+ }
91
+
92
+ // Run the demo
93
+ runDemo();
@@ -0,0 +1,200 @@
1
+ #!/usr/bin/env node
2
+
3
+ /**
4
+ * mq - Markdown Query
5
+ * Demo script for testing with architecture files
6
+ */
7
+
8
+ import fs from 'fs/promises';
9
+ import path from 'path';
10
+ import { execSync } from 'child_process';
11
+
12
+ // Main function
13
+ async function main() {
14
+ console.log('=== MQ DEMO WITH ARCHITECTURE FILES ===\n');
15
+
16
+ // Find markdown files in architecture directory
17
+ const architectureDir = path.join(process.cwd(), '../../content/architecture');
18
+ const files = await fs.readdir(architectureDir);
19
+ const markdownFiles = files.filter(file => file.endsWith('.md'));
20
+
21
+ console.log(`Found ${markdownFiles.length} markdown files in content/architecture/\n`);
22
+
23
+ // Select a file for demonstration
24
+ const demoFile = markdownFiles[0];
25
+ const demoFilePath = path.join(architectureDir, demoFile);
26
+
27
+ console.log(`Demonstrating mq with ${demoFile}:\n`);
28
+
29
+ // Demo 1: Extract headings
30
+ console.log('=== DEMO 1: EXTRACT HEADINGS ===');
31
+ console.log(`Command: cat ${demoFilePath} | mq '.headings[]'`);
32
+ console.log();
33
+
34
+ try {
35
+ const headingsOutput = execSync(`cat ${demoFilePath} | node ${path.join(process.cwd(), 'index.js')} '.headings[]'`).toString();
36
+ const headings = headingsOutput.split('\n').filter(Boolean);
37
+
38
+ // Show first few headings
39
+ const headingsToShow = Math.min(5, headings.length);
40
+ for (let i = 0; i < headingsToShow; i++) {
41
+ console.log(headings[i]);
42
+ }
43
+
44
+ if (headings.length > headingsToShow) {
45
+ console.log(`... and ${headings.length - headingsToShow} more headings\n`);
46
+ }
47
+ } catch (error) {
48
+ console.error(`Error extracting headings: ${error.message}`);
49
+ }
50
+
51
+ // Demo 2: Generate TOC
52
+ console.log('=== DEMO 2: GENERATE TABLE OF CONTENTS ===');
53
+ console.log(`Command: cat ${demoFilePath} | mq '.toc'`);
54
+ console.log();
55
+
56
+ try {
57
+ const tocOutput = execSync(`cat ${demoFilePath} | node ${path.join(process.cwd(), 'index.js')} '.toc'`).toString();
58
+ const tocLines = tocOutput.split('\n').filter(Boolean);
59
+
60
+ // Show first few TOC lines
61
+ const linesToShow = Math.min(10, tocLines.length);
62
+ for (let i = 0; i < linesToShow; i++) {
63
+ console.log(tocLines[i]);
64
+ }
65
+
66
+ if (tocLines.length > linesToShow) {
67
+ console.log('...\n');
68
+ }
69
+ } catch (error) {
70
+ console.error(`Error generating TOC: ${error.message}`);
71
+ }
72
+
73
+ // Demo 3: Count document elements
74
+ console.log('=== DEMO 3: COUNT DOCUMENT ELEMENTS ===');
75
+ console.log(`Command: cat ${demoFilePath} | mq --count`);
76
+ console.log();
77
+
78
+ try {
79
+ const countOutput = execSync(`cat ${demoFilePath} | node ${path.join(process.cwd(), 'index.js')} --count`).toString();
80
+ console.log(countOutput);
81
+ } catch (error) {
82
+ console.error(`Error counting elements: ${error.message}`);
83
+ }
84
+
85
+ // Demo 4: Extract code blocks
86
+ console.log('=== DEMO 4: EXTRACT CODE BLOCKS ===');
87
+ console.log(`Command: cat ${demoFilePath} | mq '.codeBlocks[]'`);
88
+ console.log();
89
+
90
+ try {
91
+ const codeBlocksOutput = execSync(`cat ${demoFilePath} | node ${path.join(process.cwd(), 'index.js')} '.codeBlocks[]'`).toString();
92
+ const codeBlocks = codeBlocksOutput.split('\n\n').filter(block => block.trim().startsWith('{'));
93
+
94
+ // Show first code block
95
+ if (codeBlocks.length > 0) {
96
+ console.log(codeBlocks[0]);
97
+
98
+ if (codeBlocks.length > 1) {
99
+ console.log(`... and ${codeBlocks.length - 1} more code blocks\n`);
100
+ }
101
+ } else {
102
+ console.log('No code blocks found in the document.\n');
103
+ }
104
+ } catch (error) {
105
+ console.error(`Error extracting code blocks: ${error.message}`);
106
+ }
107
+
108
+ // Demo 5: Transform code blocks to collapsible
109
+ console.log('=== DEMO 5: TRANSFORM CODE BLOCKS TO COLLAPSIBLE ===');
110
+ console.log(`Command: cat ${demoFilePath} | mq --transform '.codeBlocks[] |= makeCollapsible'`);
111
+ console.log();
112
+
113
+ try {
114
+ const transformOutput = execSync(`cat ${demoFilePath} | node ${path.join(process.cwd(), 'index.js')} --transform '.codeBlocks[] |= makeCollapsible'`).toString();
115
+ const transformLines = transformOutput.split('\n');
116
+
117
+ // Find the first transformed code block
118
+ let detailsStartIndex = -1;
119
+ for (let i = 0; i < transformLines.length; i++) {
120
+ if (transformLines[i].includes('<details>')) {
121
+ detailsStartIndex = i;
122
+ break;
123
+ }
124
+ }
125
+
126
+ if (detailsStartIndex >= 0) {
127
+ // Show the transformed code block
128
+ for (let i = detailsStartIndex; i < Math.min(detailsStartIndex + 10, transformLines.length); i++) {
129
+ console.log(transformLines[i]);
130
+ }
131
+ console.log('...\n');
132
+ } else {
133
+ console.log('No code blocks found to transform.\n');
134
+ }
135
+ } catch (error) {
136
+ console.error(`Error transforming code blocks: ${error.message}`);
137
+ }
138
+
139
+ // Demo 6: Analyze document structure
140
+ console.log('=== DEMO 6: ANALYZE DOCUMENT STRUCTURE ===');
141
+ console.log(`Command: cat ${demoFilePath} | mq --analyze`);
142
+ console.log();
143
+
144
+ try {
145
+ const analyzeOutput = execSync(`cat ${demoFilePath} | node ${path.join(process.cwd(), 'index.js')} --analyze`).toString();
146
+ const analyzeLines = analyzeOutput.split('\n');
147
+
148
+ // Show the first part of the analysis
149
+ for (let i = 0; i < Math.min(20, analyzeLines.length); i++) {
150
+ console.log(analyzeLines[i]);
151
+ }
152
+
153
+ if (analyzeLines.length > 20) {
154
+ console.log('...\n');
155
+ }
156
+ } catch (error) {
157
+ console.error(`Error analyzing document: ${error.message}`);
158
+ }
159
+
160
+ // Demo 7: Filter headings by level
161
+ console.log('=== DEMO 7: FILTER HEADINGS BY LEVEL ===');
162
+ console.log(`Command: cat ${demoFilePath} | mq '.headings[] | select(.level == 2)'`);
163
+ console.log();
164
+
165
+ try {
166
+ const filterOutput = execSync(`cat ${demoFilePath} | node ${path.join(process.cwd(), 'index.js')} '.headings[] | select(.level == 2)'`).toString();
167
+ const filterHeadings = filterOutput.split('\n\n').filter(Boolean);
168
+
169
+ // Show first few filtered headings
170
+ const headingsToShow = Math.min(5, filterHeadings.length);
171
+ for (let i = 0; i < headingsToShow; i++) {
172
+ console.log(filterHeadings[i]);
173
+ }
174
+
175
+ if (filterHeadings.length > headingsToShow) {
176
+ console.log(`... and ${filterHeadings.length - headingsToShow} more level 2 headings\n`);
177
+ }
178
+ } catch (error) {
179
+ console.error(`Error filtering headings: ${error.message}`);
180
+ }
181
+
182
+ // Summary
183
+ console.log('\n=== MQ USAGE SUMMARY ===');
184
+ console.log('After installing the mq package, you can use these commands:');
185
+ console.log('- Extract headings: mq \'.headings[]\'');
186
+ console.log('- Generate TOC: mq \'.toc\'');
187
+ console.log('- Count elements: mq --count');
188
+ console.log('- Show structure: mq --structure');
189
+ console.log('- Analyze document: mq --analyze');
190
+ console.log('- Transform code blocks: mq --transform \'.codeBlocks[] |= makeCollapsible\'');
191
+ console.log('- Filter headings: mq \'.headings[] | select(.level == 2)\'');
192
+ console.log('- Extract links: mq \'.links[]\'');
193
+ console.log('- Find external links: mq \'.links[] | select(.href | startswith("http"))\'');
194
+ }
195
+
196
+ // Run the main function
197
+ main().catch(error => {
198
+ console.error('Error:', error.message);
199
+ process.exit(1);
200
+ });
@@ -0,0 +1,64 @@
1
+ /**
2
+ * Example: Filter Code Blocks
3
+ *
4
+ * This example demonstrates how to use mdoc to filter code blocks
5
+ * by language.
6
+ */
7
+
8
+ import { fromMarkdown } from 'mdast-util-from-markdown';
9
+ import { visit } from 'unist-util-visit';
10
+
11
+ // Example markdown content
12
+ const markdown = `# Code Examples
13
+
14
+ ## JavaScript
15
+
16
+ \`\`\`javascript
17
+ function hello() {
18
+ console.log('Hello, world!');
19
+ }
20
+ \`\`\`
21
+
22
+ ## PHP
23
+
24
+ \`\`\`php
25
+ function hello() {
26
+ echo 'Hello, world!';
27
+ }
28
+ \`\`\`
29
+
30
+ ## Python
31
+
32
+ \`\`\`python
33
+ def hello():
34
+ print('Hello, world!')
35
+ \`\`\`
36
+
37
+ ## Shell
38
+
39
+ \`\`\`bash
40
+ echo 'Hello, world!'
41
+ \`\`\`
42
+ `;
43
+
44
+ // Parse markdown to AST
45
+ const ast = fromMarkdown(markdown);
46
+
47
+ // Extract all code blocks
48
+ console.log('All code blocks:');
49
+ console.log('==============');
50
+ visit(ast, 'code', (node) => {
51
+ console.log(`Language: ${node.lang || 'none'}`);
52
+ console.log(node.value);
53
+ console.log('---');
54
+ });
55
+ console.log('\n');
56
+
57
+ // Filter code blocks by language
58
+ console.log('Only JavaScript code blocks:');
59
+ console.log('=========================');
60
+ visit(ast, 'code', (node) => {
61
+ if (node.lang === 'javascript') {
62
+ console.log(node.value);
63
+ }
64
+ });
@@ -0,0 +1,71 @@
1
+ #!/usr/bin/env node
2
+
3
+ /**
4
+ * Example: Generate Table of Contents
5
+ *
6
+ * This example demonstrates how to use mq to generate a table of contents
7
+ * from a markdown document.
8
+ */
9
+
10
+ import { fromMarkdown } from 'mdast-util-from-markdown';
11
+ import { toString } from 'mdast-util-to-string';
12
+ import { visit } from 'unist-util-visit';
13
+
14
+ // Example markdown content
15
+ const markdown = `# Architecture Documentation
16
+
17
+ ## Overview
18
+
19
+ This document provides an overview of the architecture.
20
+
21
+ ## Components
22
+
23
+ ### Frontend
24
+
25
+ The frontend is built with React.
26
+
27
+ ### Backend
28
+
29
+ The backend is built with Node.js.
30
+
31
+ ### Database
32
+
33
+ We use PostgreSQL for data storage.
34
+
35
+ ## Deployment
36
+
37
+ Deployment is handled through CI/CD pipelines.
38
+ `;
39
+
40
+ // Parse markdown to AST
41
+ const ast = fromMarkdown(markdown);
42
+
43
+ // Extract headings
44
+ const headings = [];
45
+ visit(ast, 'heading', (node) => {
46
+ if (node.depth <= 3) { // Only include h1, h2, h3
47
+ headings.push({
48
+ level: node.depth,
49
+ text: toString(node),
50
+ anchor: toString(node).toLowerCase().replace(/[^\w]+/g, '-')
51
+ });
52
+ }
53
+ });
54
+
55
+ // Generate TOC
56
+ const toc = headings.map((heading, index) => {
57
+ const indent = ' '.repeat(heading.level - 1);
58
+ return `${indent}${index + 1}. [${heading.text}](#${heading.anchor})`;
59
+ }).join('\n');
60
+
61
+ console.log('Original Markdown:');
62
+ console.log('=================');
63
+ console.log(markdown);
64
+ console.log('\n');
65
+
66
+ console.log('Generated Table of Contents:');
67
+ console.log('==========================');
68
+ console.log(toc);
69
+
70
+ // How to run this example:
71
+ // node examples/generate-toc.js