node-plantuml-2 1.1.3 → 1.1.5

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.
@@ -24,18 +24,59 @@ function resolveBundledGraphviz () {
24
24
  // Try to resolve the package
25
25
  var pkgPath
26
26
  try {
27
- // Try to require.resolve the package
27
+ // Method 1: Try require.resolve (works in most cases, including external projects)
28
28
  var pkgJsonPath = require.resolve(pkgName + '/package.json')
29
29
  pkgPath = path.dirname(pkgJsonPath)
30
30
  } catch (e) {
31
- // Package might not be installed (optional dependency)
32
- // Try to find it in node_modules relative to this package
33
- var thisPkgPath = path.join(__dirname, '..')
34
- var possiblePath = path.join(thisPkgPath, 'node_modules', pkgName)
35
- if (fs.existsSync(path.join(possiblePath, 'package.json'))) {
36
- pkgPath = possiblePath
37
- } else {
38
- return null
31
+ // Method 2: Package might not be installed (optional dependency)
32
+ // Try to find it by locating node-plantuml-2 package first, then look in its parent node_modules
33
+ try {
34
+ // Find where node-plantuml-2 is installed
35
+ var nodePlantumlPath = require.resolve('node-plantuml-2')
36
+ // Get the node_modules directory that contains node-plantuml-2
37
+ // node-plantuml-2 is at: .../node_modules/node-plantuml-2/lib/...
38
+ // So node_modules is at: .../node_modules/
39
+ var nodeModulesDir = path.dirname(path.dirname(nodePlantumlPath))
40
+
41
+ // For scoped packages like @node-plantuml-2/graphviz-win32-x64,
42
+ // the path structure is: node_modules/@node-plantuml-2/graphviz-win32-x64/
43
+ // So we need to handle the @scope/package format
44
+ var possiblePath = path.join(nodeModulesDir, pkgName)
45
+ if (fs.existsSync(path.join(possiblePath, 'package.json'))) {
46
+ pkgPath = possiblePath
47
+ } else {
48
+ // Method 3: Try in current package's node_modules (for development)
49
+ var thisPkgPath = path.join(__dirname, '..')
50
+ var devPath = path.join(thisPkgPath, 'node_modules', pkgName)
51
+ if (fs.existsSync(path.join(devPath, 'package.json'))) {
52
+ pkgPath = devPath
53
+ } else {
54
+ // Method 4: Recursive search up the directory tree
55
+ var currentDir = thisPkgPath
56
+ var found = false
57
+ while (currentDir !== path.dirname(currentDir)) {
58
+ var searchPath = path.join(currentDir, 'node_modules', pkgName)
59
+ if (fs.existsSync(path.join(searchPath, 'package.json'))) {
60
+ pkgPath = searchPath
61
+ found = true
62
+ break
63
+ }
64
+ currentDir = path.dirname(currentDir)
65
+ }
66
+ if (!found) {
67
+ return null
68
+ }
69
+ }
70
+ }
71
+ } catch (resolveErr) {
72
+ // If we can't even resolve node-plantuml-2, try local fallback
73
+ var thisPkgPath = path.join(__dirname, '..')
74
+ var possiblePath = path.join(thisPkgPath, 'node_modules', pkgName)
75
+ if (fs.existsSync(path.join(possiblePath, 'package.json'))) {
76
+ pkgPath = possiblePath
77
+ } else {
78
+ return null
79
+ }
39
80
  }
40
81
  }
41
82
 
@@ -82,14 +123,18 @@ function getBundledGraphvizLibPath (dotPath) {
82
123
  }
83
124
 
84
125
  try {
126
+ // Normalize path separators for checking
127
+ var normalizedPath = dotPath.replace(/\\/g, '/')
128
+
85
129
  // Check if this is a bundled Graphviz path
86
130
  // Bundled path format: .../node_modules/@node-plantuml-2/graphviz-*/graphviz/bin/dot
87
131
  // Handle both / and \ path separators (Windows uses \)
88
- var isBundled = dotPath.includes('@node-plantuml-2/graphviz-') &&
89
- (dotPath.includes('/graphviz/bin/') || dotPath.includes('\\graphviz\\bin\\'))
132
+ var isBundled = normalizedPath.includes('@node-plantuml-2/graphviz-') &&
133
+ normalizedPath.includes('/graphviz/bin/')
90
134
  if (isBundled) {
91
135
  // Extract the graphviz directory
92
- var graphvizDir = path.dirname(path.dirname(dotPath)) // Go up from bin/ to graphviz/
136
+ // Go up from bin/ to graphviz/
137
+ var graphvizDir = path.dirname(path.dirname(dotPath))
93
138
  var libDir = path.join(graphvizDir, 'lib')
94
139
 
95
140
  if (fs.existsSync(libDir)) {
@@ -126,20 +171,24 @@ function getGraphvizPackageName (platform, arch) {
126
171
  }
127
172
 
128
173
  /**
129
- * Resolve Graphviz dot executable path with fallback strategy
174
+ * Resolve Graphviz dot executable path
130
175
  *
131
176
  * Priority order:
132
177
  * 1. options.dotPath (user-specified)
133
- * 2. Bundled Graphviz (from optional dependencies)
134
- * 3. Common installation paths (platform-specific)
135
- * 4. System 'dot' in PATH (which dot)
178
+ * 2. Bundled Graphviz (from optional dependencies) - REQUIRED
179
+ *
180
+ * NOTE: We ONLY use bundled Graphviz packages. System Graphviz is NOT used.
181
+ * This ensures consistent behavior across all environments.
136
182
  *
137
183
  * @param {Object} options - Options object
138
184
  * @param {string} options.dotPath - User-specified dot path (highest priority)
185
+ * @param {boolean} options.allowSystemFallback - If true, allow system Graphviz as fallback (for install scripts only)
139
186
  * @returns {string|null} - Path to dot executable, or null if not found
187
+ * @throws {Error} - If bundled Graphviz is not found and allowSystemFallback is false
140
188
  */
141
189
  function resolveDotExecutable (options) {
142
190
  options = options || {}
191
+ var allowSystemFallback = options.allowSystemFallback === true
143
192
 
144
193
  // Priority 1: User-specified dot path
145
194
  if (options.dotPath) {
@@ -149,12 +198,42 @@ function resolveDotExecutable (options) {
149
198
  }
150
199
  }
151
200
 
152
- // Priority 2: Bundled Graphviz from optional dependencies
201
+ // Priority 2: Bundled Graphviz from optional dependencies (REQUIRED)
153
202
  var bundledGraphviz = resolveBundledGraphviz()
154
203
  if (bundledGraphviz) {
155
204
  return bundledGraphviz
156
205
  }
157
206
 
207
+ // If bundled Graphviz is not found, we should NOT fallback to system
208
+ // This ensures all users use the same Graphviz version
209
+ if (!allowSystemFallback) {
210
+ var platform = os.platform()
211
+ var arch = os.arch()
212
+ var pkgName = getGraphvizPackageName(platform, arch)
213
+
214
+ if (pkgName) {
215
+ throw new Error(
216
+ 'Bundled Graphviz not found. Please install the Graphviz runtime package:\n' +
217
+ ' npm install ' + pkgName + '\n\n' +
218
+ 'This package should be automatically installed via optionalDependencies.\n' +
219
+ 'If it failed to install, please check:\n' +
220
+ ' 1. Your platform is supported: ' + platform + ' ' + arch + '\n' +
221
+ ' 2. Network connection during npm install\n' +
222
+ ' 3. npm install logs for errors\n\n' +
223
+ 'Alternatively, you can specify a custom Graphviz path:\n' +
224
+ ' plantuml.generate(code, { dotPath: "/path/to/dot" })'
225
+ )
226
+ } else {
227
+ throw new Error(
228
+ 'Graphviz is required but not available.\n' +
229
+ 'Your platform (' + platform + ' ' + arch + ') is not supported.\n' +
230
+ 'Please install Graphviz manually and specify the path:\n' +
231
+ ' plantuml.generate(code, { dotPath: "/path/to/dot" })'
232
+ )
233
+ }
234
+ }
235
+
236
+ // System fallback (ONLY for install scripts, NOT for runtime)
158
237
  // Priority 3: Common installation paths (platform-specific)
159
238
  var commonPaths = getCommonDotPaths()
160
239
  for (var i = 0; i < commonPaths.length; i++) {
@@ -215,11 +215,20 @@ function joinOptions (argv, options) {
215
215
  argv.push(file)
216
216
  }
217
217
 
218
- // Auto-detect dot path if not specified
218
+ // Auto-detect dot path if not specified (ONLY from bundled Graphviz)
219
219
  if (!options.dot) {
220
- var detectedDot = dotResolver.resolveDotExecutable({ dotPath: null })
221
- if (detectedDot) {
222
- options.dot = detectedDot
220
+ try {
221
+ var detectedDot = dotResolver.resolveDotExecutable({ dotPath: null })
222
+ if (detectedDot) {
223
+ options.dot = detectedDot
224
+ }
225
+ } catch (err) {
226
+ // Graphviz is optional for most diagram types
227
+ // Only required for certain diagram types (e.g., some activity diagrams)
228
+ // If not found, PlantUML will handle it gracefully
229
+ if (process.env.DEBUG_PLANTUML) {
230
+ console.warn('[DEBUG] Graphviz not found, some diagram types may not work:', err.message)
231
+ }
223
232
  }
224
233
  }
225
234
 
@@ -384,15 +393,34 @@ module.exports.decode = function (encoded, callback) {
384
393
  }
385
394
 
386
395
  module.exports.testdot = function (callback) {
387
- // Auto-detect dot path and pass it to PlantUML
388
- var detectedDot = dotResolver.resolveDotExecutable({ dotPath: null })
396
+ // Auto-detect dot path and pass it to PlantUML (ONLY from bundled Graphviz)
397
+ var detectedDot = null
398
+ try {
399
+ detectedDot = dotResolver.resolveDotExecutable({ dotPath: null })
400
+ } catch (err) {
401
+ // If bundled Graphviz is not found, return error
402
+ if (typeof callback === 'function') {
403
+ return callback(new Error('Graphviz not found: ' + err.message))
404
+ }
405
+ throw err
406
+ }
407
+
389
408
  var argv = [TESTDOT]
390
409
  if (detectedDot) {
410
+ // Ensure dot path is absolute - PlantUML Java process needs absolute path
411
+ var absoluteDotPath = path.resolve(detectedDot)
412
+ // Normalize path separators for the platform
413
+ if (process.platform === 'win32') {
414
+ absoluteDotPath = absoluteDotPath.replace(/\//g, '\\')
415
+ } else {
416
+ absoluteDotPath = absoluteDotPath.replace(/\\/g, '/')
417
+ }
391
418
  argv.push(DOT)
392
- argv.push(detectedDot)
419
+ argv.push(absoluteDotPath)
393
420
  }
394
421
 
395
422
  // Don't pass callback to exec - we need to handle output ourselves
423
+ // Pass empty options object to ensure environment variables are set correctly
396
424
  var child = plantumlExecutor.exec(argv, undefined, {}, undefined)
397
425
 
398
426
  var stdoutChunks = []
@@ -102,9 +102,18 @@ function execWithSpawn (argv, cwd, options, cb) {
102
102
  }
103
103
  }
104
104
 
105
- // If no dot path in argv, try to detect it
105
+ // If no dot path in argv, try to detect it (ONLY from bundled Graphviz)
106
106
  if (!dotPath) {
107
- dotPath = dotResolver.resolveDotExecutable({ dotPath: null })
107
+ try {
108
+ dotPath = dotResolver.resolveDotExecutable({ dotPath: null })
109
+ } catch (err) {
110
+ // If bundled Graphviz is not found, log error but continue
111
+ // PlantUML will work without Graphviz for most diagram types
112
+ if (process.env.DEBUG_PLANTUML) {
113
+ console.warn('[DEBUG] Graphviz not found:', err.message)
114
+ }
115
+ // dotPath remains null, PlantUML will handle it
116
+ }
108
117
  }
109
118
 
110
119
  // CRITICAL FIX: Ensure dot path is absolute and properly formatted
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "node-plantuml-2",
3
- "version": "1.1.3",
3
+ "version": "1.1.5",
4
4
  "plantumlVersion": "1.2026.1",
5
5
  "description": "Node.js PlantUML renderer with Java backend. Multiple output formats (PNG, SVG, EPS, ASCII, Unicode) with full UTF-8 support",
6
6
  "main": "index.js",
@@ -26,13 +26,13 @@
26
26
  "plantuml-encoder": "^1.2.5"
27
27
  },
28
28
  "optionalDependencies": {
29
- "@node-plantuml-2/jre-win32-x64": "^1.1.3",
30
- "@node-plantuml-2/jre-darwin-arm64": "^1.1.3",
31
- "@node-plantuml-2/jre-linux-x64": "^1.1.3",
32
- "@node-plantuml-2/graphviz-win32-x64": "^1.1.3",
33
- "@node-plantuml-2/graphviz-darwin-arm64": "^1.1.3",
34
- "@node-plantuml-2/graphviz-darwin-x64": "^1.1.3",
35
- "@node-plantuml-2/graphviz-linux-x64": "^1.1.3"
29
+ "@node-plantuml-2/jre-win32-x64": "^1.1.5",
30
+ "@node-plantuml-2/jre-darwin-arm64": "^1.1.5",
31
+ "@node-plantuml-2/jre-linux-x64": "^1.1.5",
32
+ "@node-plantuml-2/graphviz-win32-x64": "^1.1.5",
33
+ "@node-plantuml-2/graphviz-darwin-arm64": "^1.1.5",
34
+ "@node-plantuml-2/graphviz-darwin-x64": "^1.1.5",
35
+ "@node-plantuml-2/graphviz-linux-x64": "^1.1.5"
36
36
  },
37
37
  "devDependencies": {
38
38
  "chai": "^4.x",
@@ -62,9 +62,7 @@
62
62
  "test:integration": "node test/test-integration-full.js",
63
63
  "build": "node nail/build.js",
64
64
  "build:all": "node scripts/build-all.js",
65
- "build:all:jar-only": "node scripts/get-plantuml-jar.js --latest",
66
- "test:graphviz": "node scripts/test-graphviz-build.js",
67
- "test:graphviz:build": "node scripts/test-graphviz-build.js"
65
+ "build:all:jar-only": "node scripts/get-plantuml-jar.js --latest"
68
66
  },
69
67
  "bin": {
70
68
  "puml": "index.js"
@@ -254,8 +254,8 @@ async function installGraphviz () {
254
254
  console.log('🔍 Checking if Graphviz is already installed...')
255
255
  console.log('')
256
256
 
257
- // First check if Graphviz is already installed
258
- var detected = dotResolver.resolveDotExecutable({ dotPath: null })
257
+ // First check if Graphviz is already installed (allow system fallback for install script)
258
+ var detected = dotResolver.resolveDotExecutable({ dotPath: null, allowSystemFallback: true })
259
259
  if (detected) {
260
260
  console.log('✅ Graphviz is already installed at: ' + detected)
261
261
  console.log('')
@@ -290,10 +290,10 @@ async function installGraphviz () {
290
290
  }
291
291
 
292
292
  if (installed) {
293
- // Verify installation
293
+ // Verify installation (allow system fallback for install script)
294
294
  console.log('')
295
295
  console.log('🔍 Verifying installation...')
296
- var newDetected = dotResolver.resolveDotExecutable({ dotPath: null })
296
+ var newDetected = dotResolver.resolveDotExecutable({ dotPath: null, allowSystemFallback: true })
297
297
  if (newDetected) {
298
298
  console.log('✅ Graphviz is now available at: ' + newDetected)
299
299
  return true