apidocly 1.0.3

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,57 @@
1
+ const COMMENT_PATTERNS = {
2
+ js: {
3
+ block: /\/\*\*[\s\S]*?\*\//g,
4
+ linePrefix: /^\s*\*\s?/gm,
5
+ start: '/**',
6
+ end: '*/'
7
+ },
8
+ php: {
9
+ block: /\/\*\*[\s\S]*?\*\//g,
10
+ linePrefix: /^\s*\*\s?/gm,
11
+ start: '/**',
12
+ end: '*/'
13
+ },
14
+ python: {
15
+ block: /"""[\s\S]*?"""|\'\'\'[\s\S]*?\'\'\'/g,
16
+ linePrefix: /^\s*/gm,
17
+ start: '"""',
18
+ end: '"""'
19
+ }
20
+ };
21
+
22
+ function extractCommentBlocks(content, language) {
23
+ const pattern = COMMENT_PATTERNS[language];
24
+ if (!pattern) return [];
25
+
26
+ const blocks = [];
27
+ const matches = content.match(pattern.block);
28
+
29
+ if (!matches) return [];
30
+
31
+ for (const match of matches) {
32
+ if (!match.includes('@api')) continue;
33
+
34
+ let cleaned = match;
35
+
36
+ if (language === 'js' || language === 'php') {
37
+ cleaned = match
38
+ .replace(/^\/\*\*\s*/, '')
39
+ .replace(/\s*\*\/$/, '')
40
+ .replace(pattern.linePrefix, '')
41
+ .trim();
42
+ } else if (language === 'python') {
43
+ cleaned = match
44
+ .replace(/^"""\s*/, '')
45
+ .replace(/\s*"""$/, '')
46
+ .replace(/^'''\s*/, '')
47
+ .replace(/\s*'''$/, '')
48
+ .trim();
49
+ }
50
+
51
+ blocks.push(cleaned);
52
+ }
53
+
54
+ return blocks;
55
+ }
56
+
57
+ module.exports = { extractCommentBlocks, COMMENT_PATTERNS };
@@ -0,0 +1,67 @@
1
+ const fs = require('fs');
2
+ const path = require('path');
3
+
4
+ const DEFAULT_CONFIG = {
5
+ name: 'API Documentation',
6
+ version: '1.0.0',
7
+ description: '',
8
+ title: 'API Documentation',
9
+ url: '',
10
+ sampleUrl: '',
11
+ environments: [],
12
+ template: {
13
+ withCompare: true,
14
+ withGenerator: true
15
+ },
16
+ password: null,
17
+ passwordMessage: 'Enter password to view API documentation',
18
+ header: null,
19
+ footer: null
20
+ };
21
+
22
+ const CONFIG_FILES = [
23
+ 'apidocly.json',
24
+ ];
25
+
26
+ function loadConfig(configPath, inputPath) {
27
+ let config = { ...DEFAULT_CONFIG };
28
+ let configDir = inputPath;
29
+
30
+ if (configPath) {
31
+ if (fs.existsSync(configPath)) {
32
+ const userConfig = JSON.parse(fs.readFileSync(configPath, 'utf8'));
33
+ config = { ...config, ...userConfig };
34
+ configDir = path.dirname(configPath);
35
+ } else {
36
+ throw new Error(`Config file not found: ${configPath}`);
37
+ }
38
+ } else {
39
+ for (const filename of CONFIG_FILES) {
40
+ const filePath = path.join(inputPath, filename);
41
+ if (fs.existsSync(filePath)) {
42
+ const userConfig = JSON.parse(fs.readFileSync(filePath, 'utf8'));
43
+ config = { ...config, ...userConfig };
44
+ configDir = inputPath;
45
+ break;
46
+ }
47
+ }
48
+ }
49
+
50
+ if (config.header && config.header.filename) {
51
+ const headerPath = path.join(configDir, config.header.filename);
52
+ if (fs.existsSync(headerPath)) {
53
+ config.header.content = fs.readFileSync(headerPath, 'utf8');
54
+ }
55
+ }
56
+
57
+ if (config.footer && config.footer.filename) {
58
+ const footerPath = path.join(configDir, config.footer.filename);
59
+ if (fs.existsSync(footerPath)) {
60
+ config.footer.content = fs.readFileSync(footerPath, 'utf8');
61
+ }
62
+ }
63
+
64
+ return config;
65
+ }
66
+
67
+ module.exports = { loadConfig, DEFAULT_CONFIG };
@@ -0,0 +1,64 @@
1
+ const fs = require('fs');
2
+ const path = require('path');
3
+ const { glob } = require('glob');
4
+
5
+ const SUPPORTED_EXTENSIONS = {
6
+ js: ['.js', '.jsx', '.ts', '.tsx', '.mjs', '.cjs'],
7
+ php: ['.php'],
8
+ python: ['.py']
9
+ };
10
+
11
+ const ALL_EXTENSIONS = Object.values(SUPPORTED_EXTENSIONS).flat();
12
+
13
+ async function scanFiles(inputPath, options = {}) {
14
+ const { verbose } = options;
15
+ const files = [];
16
+
17
+ const stat = fs.statSync(inputPath);
18
+
19
+ if (stat.isFile()) {
20
+ const ext = path.extname(inputPath).toLowerCase();
21
+ if (ALL_EXTENSIONS.includes(ext)) {
22
+ files.push(inputPath);
23
+ }
24
+ } else if (stat.isDirectory()) {
25
+ const patterns = ALL_EXTENSIONS.map(ext => `**/*${ext}`);
26
+
27
+ for (const pattern of patterns) {
28
+ const matches = await glob(pattern, {
29
+ cwd: inputPath,
30
+ absolute: true,
31
+ ignore: [
32
+ '**/node_modules/**',
33
+ '**/vendor/**',
34
+ '**/.git/**',
35
+ '**/dist/**',
36
+ '**/build/**',
37
+ '**/__pycache__/**',
38
+ '**/venv/**'
39
+ ]
40
+ });
41
+ files.push(...matches);
42
+ }
43
+ }
44
+
45
+ const uniqueFiles = [...new Set(files)];
46
+
47
+ if (verbose) {
48
+ console.log(` Found ${uniqueFiles.length} source files`);
49
+ }
50
+
51
+ return uniqueFiles;
52
+ }
53
+
54
+ function getLanguage(filePath) {
55
+ const ext = path.extname(filePath).toLowerCase();
56
+
57
+ if (SUPPORTED_EXTENSIONS.js.includes(ext)) return 'js';
58
+ if (SUPPORTED_EXTENSIONS.php.includes(ext)) return 'php';
59
+ if (SUPPORTED_EXTENSIONS.python.includes(ext)) return 'python';
60
+
61
+ return null;
62
+ }
63
+
64
+ module.exports = { scanFiles, getLanguage, SUPPORTED_EXTENSIONS };
@@ -0,0 +1,106 @@
1
+ /**
2
+ * CSS/JS Minifier using Terser
3
+ * Terser provides reliable minification and obfuscation with proper scope analysis
4
+ */
5
+
6
+ const { minify } = require('terser');
7
+
8
+ /**
9
+ * Minify CSS
10
+ */
11
+ function minifyCSS(css) {
12
+ return css
13
+ .replace(/\/\*[\s\S]*?\*\//g, '')
14
+ .replace(/[\n\r\t]/g, '')
15
+ .replace(/\s*([{}:;,>~+])\s*/g, '$1')
16
+ .replace(/\s{2,}/g, ' ')
17
+ .replace(/;}/g, '}')
18
+ .trim();
19
+ }
20
+
21
+ /**
22
+ * Minify JavaScript using Terser (synchronous wrapper)
23
+ */
24
+ function minifyJS(js) {
25
+ // Terser is async, but we need sync for compatibility
26
+ // Use basic minification for sync context
27
+ return js
28
+ .replace(/\/\/[^\n]*/g, '') // Remove single-line comments
29
+ .replace(/\/\*[\s\S]*?\*\//g, '') // Remove multi-line comments
30
+ .replace(/\s+/g, ' ') // Collapse whitespace
31
+ .replace(/\s*([{}:;,=()[\]<>!&|?+\-*\/])\s*/g, '$1') // Remove space around operators
32
+ .replace(/;\s*}/g, '}') // Remove trailing semicolons
33
+ .trim();
34
+ }
35
+
36
+ /**
37
+ * Minify JSON (for api_data.js)
38
+ */
39
+ function minifyJSON(obj) {
40
+ return JSON.stringify(obj);
41
+ }
42
+
43
+ /**
44
+ * Minify and obfuscate JavaScript using Terser (async)
45
+ * Returns a Promise
46
+ */
47
+ async function minifyAndObfuscateJSAsync(js) {
48
+ try {
49
+ const result = await minify(js, {
50
+ compress: {
51
+ dead_code: true,
52
+ drop_debugger: true,
53
+ conditionals: true,
54
+ evaluate: true,
55
+ booleans: true,
56
+ loops: true,
57
+ unused: true,
58
+ hoist_funs: true,
59
+ keep_fargs: false,
60
+ hoist_vars: false,
61
+ if_return: true,
62
+ join_vars: true,
63
+ side_effects: true,
64
+ warnings: false
65
+ },
66
+ mangle: {
67
+ toplevel: false, // Don't mangle top-level names (preserves window.* functions)
68
+ reserved: [
69
+ // Preserve API data variables
70
+ 'apiData', 'apiDataEncrypted', 'apiDataAuth', 'apiVersions',
71
+ // Preserve global functions exposed via window.*
72
+ 'downloadOpenAPI', 'downloadPostmanCollection', 'downloadInsomniaCollection',
73
+ 'switchCodeSample', 'copyCodeSample', 'toggleEndpoint', 'toggleGroup',
74
+ 'showEndpoint', 'goBack', 'hashChange'
75
+ ]
76
+ },
77
+ format: {
78
+ comments: false
79
+ },
80
+ sourceMap: false
81
+ });
82
+
83
+ return result.code || js;
84
+ } catch (error) {
85
+ console.warn('Terser minification failed, using basic minification:', error.message);
86
+ return minifyJS(js);
87
+ }
88
+ }
89
+
90
+ /**
91
+ * Synchronous wrapper for minifyAndObfuscateJS
92
+ * Uses basic minification (Terser is async-only)
93
+ */
94
+ function minifyAndObfuscateJS(js) {
95
+ // For sync usage, just do basic minification
96
+ // The async version should be preferred
97
+ return minifyJS(js);
98
+ }
99
+
100
+ module.exports = {
101
+ minifyCSS,
102
+ minifyJS,
103
+ minifyJSON,
104
+ minifyAndObfuscateJS,
105
+ minifyAndObfuscateJSAsync
106
+ };
package/package.json ADDED
@@ -0,0 +1,46 @@
1
+ {
2
+ "name": "apidocly",
3
+ "version": "1.0.3",
4
+ "description": "API documentation generator with beautiful dark UI, password protection, and OpenAPI/Rest client export.",
5
+ "main": "lib/index.js",
6
+ "bin": {
7
+ "apidocly": "bin/apidocly.js"
8
+ },
9
+ "scripts": {
10
+ "test": "echo \"No tests yet\" && exit 0"
11
+ },
12
+ "keywords": [
13
+ "api",
14
+ "documentation",
15
+ "generator",
16
+ "apidoc",
17
+ "openapi",
18
+ "swagger",
19
+ "dark-mode",
20
+ "rest-api",
21
+ "api-docs",
22
+ "jsdoc",
23
+ "cli"
24
+ ],
25
+ "author": "",
26
+ "license": "MIT",
27
+ "homepage": "https://apidocly.com",
28
+ "bugs": {
29
+ "url": "https://apidocly.com"
30
+ },
31
+ "dependencies": {
32
+ "commander": "^11.1.0",
33
+ "glob": "11.1.0",
34
+ "terser": "^5.37.0"
35
+ },
36
+ "engines": {
37
+ "node": ">=14.0.0"
38
+ },
39
+ "files": [
40
+ "bin",
41
+ "lib",
42
+ "template",
43
+ "README.md",
44
+ "LICENSE"
45
+ ]
46
+ }