pict-docuserve 1.4.0 → 1.4.2
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/dist/pict-docuserve.js +400 -36
- package/dist/pict-docuserve.js.map +1 -1
- package/dist/pict-docuserve.min.js +2 -2
- package/dist/pict-docuserve.min.js.map +1 -1
- package/package.json +5 -7
- package/source/Pict-Application-Docuserve.js +86 -20
- package/source/cli/Docuserve-CLI-Program.js +1 -0
- package/source/cli/commands/Docuserve-Command-StagePlayground.js +279 -0
- package/source/providers/Pict-Provider-Docuserve-Documentation.js +32 -12
- package/source/views/PictView-Docuserve-Section-Playground.js +1472 -0
- package/source/views/PictView-Docuserve-Splash.js +54 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "pict-docuserve",
|
|
3
|
-
"version": "1.4.
|
|
3
|
+
"version": "1.4.2",
|
|
4
4
|
"description": "Pict Documentation Server - A single-page documentation viewer built on Pict",
|
|
5
5
|
"main": "source/Pict-Application-Docuserve.js",
|
|
6
6
|
"bin": {
|
|
@@ -14,9 +14,7 @@
|
|
|
14
14
|
"scripts": {
|
|
15
15
|
"start": "node source/cli/Docuserve-CLI-Run.js serve",
|
|
16
16
|
"brand": "node node_modules/pict-section-theme/bin/pict-section-theme-brand.js --manifest ../../../Retold-Modules-Manifest.json --module pict-docuserve",
|
|
17
|
-
"prebuild": "npm run brand",
|
|
18
17
|
"build": "npx quack build && npx quack copy",
|
|
19
|
-
"prebuild-docs": "npm run brand",
|
|
20
18
|
"build-docs": "npx quack build && npx quack copy && node source/cli/Docuserve-CLI-Run.js inject ./docs && node example_applications/build-examples.js stage-docs",
|
|
21
19
|
"serve-docs": "node source/cli/Docuserve-CLI-Run.js serve ./docs",
|
|
22
20
|
"serve-examples": "node example_applications/build-examples.js",
|
|
@@ -34,16 +32,16 @@
|
|
|
34
32
|
"pict-application": "^1.0.34",
|
|
35
33
|
"pict-provider": "^1.0.13",
|
|
36
34
|
"pict-section-code": "^1.0.11",
|
|
37
|
-
"pict-section-content": "^1.0.
|
|
35
|
+
"pict-section-content": "^1.0.5",
|
|
38
36
|
"pict-section-histogram": "^1.0.1",
|
|
39
|
-
"pict-section-modal": "^1.1.
|
|
37
|
+
"pict-section-modal": "^1.1.4",
|
|
40
38
|
"pict-section-theme": "^1.0.6",
|
|
41
39
|
"pict-service-commandlineutility": "^1.0.19",
|
|
42
40
|
"pict-view": "^1.0.68"
|
|
43
41
|
},
|
|
44
42
|
"devDependencies": {
|
|
45
|
-
"pict-docuserve": "^1.
|
|
46
|
-
"quackage": "^1.2.
|
|
43
|
+
"pict-docuserve": "^1.4.1",
|
|
44
|
+
"quackage": "^1.2.5"
|
|
47
45
|
},
|
|
48
46
|
"copyFilesSettings": {
|
|
49
47
|
"whenFileExists": "overwrite"
|
|
@@ -23,6 +23,7 @@ const libViewContent = require('./views/PictView-Docuserve-Content.js');
|
|
|
23
23
|
const libViewSearch = require('./views/PictView-Docuserve-Search.js');
|
|
24
24
|
const libViewDemo = require('./views/PictView-Docuserve-Demo.js');
|
|
25
25
|
const libViewFablePlayground = require('./views/PictView-Docuserve-Fable-Playground.js');
|
|
26
|
+
const libViewSectionPlayground = require('./views/PictView-Docuserve-Section-Playground.js');
|
|
26
27
|
|
|
27
28
|
class DocuserveApplication extends libPictApplication
|
|
28
29
|
{
|
|
@@ -55,6 +56,7 @@ class DocuserveApplication extends libPictApplication
|
|
|
55
56
|
this.pict.addView('Docuserve-Search', libViewSearch.default_configuration, libViewSearch);
|
|
56
57
|
this.pict.addView('Docuserve-Demo', libViewDemo.default_configuration, libViewDemo);
|
|
57
58
|
this.pict.addView('Docuserve-Fable-Playground', libViewFablePlayground.default_configuration, libViewFablePlayground);
|
|
59
|
+
this.pict.addView('Docuserve-Section-Playground', libViewSectionPlayground.default_configuration, libViewSectionPlayground);
|
|
58
60
|
|
|
59
61
|
// Theme-Section is added later from onAfterInitializeAsync, after
|
|
60
62
|
// the brand has been resolved. Docuserve is a viewer — the docs
|
|
@@ -288,10 +290,23 @@ class DocuserveApplication extends libPictApplication
|
|
|
288
290
|
return;
|
|
289
291
|
}
|
|
290
292
|
|
|
291
|
-
// #/playground/<kind> — live editor + sandbox
|
|
292
|
-
// (
|
|
293
|
+
// #/playground/<kind> — live editor + sandbox. Three shapes:
|
|
294
|
+
// #/playground/fable — Fable JS REPL (bottom drawer)
|
|
295
|
+
// #/playground/section — section playground for the
|
|
296
|
+
// current module (standalone-mode
|
|
297
|
+
// docs site)
|
|
298
|
+
// #/playground/section/<group>/<module> — section playground for a
|
|
299
|
+
// specific module (catalog-mode
|
|
300
|
+
// docs site serving multiple)
|
|
293
301
|
if (tmpParts[0] === 'playground' && tmpParts.length >= 2)
|
|
294
302
|
{
|
|
303
|
+
if (tmpParts[1] === 'section')
|
|
304
|
+
{
|
|
305
|
+
let tmpGroup = (tmpParts.length >= 4) ? tmpParts[2] : (this.pict.AppData.Docuserve.CurrentGroup || '');
|
|
306
|
+
let tmpModule = (tmpParts.length >= 4) ? tmpParts[3] : (this.pict.AppData.Docuserve.CurrentModule || '');
|
|
307
|
+
this.navigateToSectionPlayground(tmpGroup, tmpModule);
|
|
308
|
+
return;
|
|
309
|
+
}
|
|
295
310
|
this.navigateToPlayground(tmpParts[1]);
|
|
296
311
|
return;
|
|
297
312
|
}
|
|
@@ -374,6 +389,55 @@ class DocuserveApplication extends libPictApplication
|
|
|
374
389
|
}
|
|
375
390
|
}
|
|
376
391
|
|
|
392
|
+
/**
|
|
393
|
+
* Open the section playground for `<group>/<module>`. Unlike the
|
|
394
|
+
* Fable playground (which lives in the bottom drawer), the section
|
|
395
|
+
* playground takes over the main content area — it needs full
|
|
396
|
+
* vertical space for its four editor tabs + iframe pane.
|
|
397
|
+
*
|
|
398
|
+
* @param {string} pGroup
|
|
399
|
+
* @param {string} pModule
|
|
400
|
+
*/
|
|
401
|
+
navigateToSectionPlayground(pGroup, pModule)
|
|
402
|
+
{
|
|
403
|
+
this.pict.AppData.Docuserve.CurrentGroup = pGroup;
|
|
404
|
+
this.pict.AppData.Docuserve.CurrentModule = pModule;
|
|
405
|
+
this.pict.AppData.Docuserve.CurrentDemo = '';
|
|
406
|
+
this.pict.AppData.Docuserve.CurrentPath = 'section-playground';
|
|
407
|
+
|
|
408
|
+
// Hide the bottom playground drawer — the section playground
|
|
409
|
+
// is the whole show on this route.
|
|
410
|
+
let tmpLayout = this.pict.views['Docuserve-Layout'];
|
|
411
|
+
if (tmpLayout && typeof tmpLayout.setPlaygroundEnabled === 'function')
|
|
412
|
+
{
|
|
413
|
+
tmpLayout.setPlaygroundEnabled(false);
|
|
414
|
+
}
|
|
415
|
+
|
|
416
|
+
let tmpPlayground = this.pict.views['Docuserve-Section-Playground'];
|
|
417
|
+
if (!tmpPlayground || typeof tmpPlayground.openPlayground !== 'function')
|
|
418
|
+
{
|
|
419
|
+
let tmpContentView = this.pict.views['Docuserve-Content'];
|
|
420
|
+
if (tmpContentView && typeof tmpContentView.displayContent === 'function')
|
|
421
|
+
{
|
|
422
|
+
tmpContentView.render();
|
|
423
|
+
tmpContentView.displayContent('<h1>Section playground unavailable</h1><p>The Section Playground view is not registered.</p>');
|
|
424
|
+
}
|
|
425
|
+
return;
|
|
426
|
+
}
|
|
427
|
+
tmpPlayground.openPlayground(pGroup, pModule);
|
|
428
|
+
|
|
429
|
+
// Keep the sidebar in sync — show the module's nav + active item.
|
|
430
|
+
let tmpSidebarView = this.pict.views['Docuserve-Sidebar'];
|
|
431
|
+
if (tmpSidebarView)
|
|
432
|
+
{
|
|
433
|
+
tmpSidebarView.renderSidebarGroups();
|
|
434
|
+
if (typeof tmpSidebarView.renderModuleNav === 'function')
|
|
435
|
+
{
|
|
436
|
+
tmpSidebarView.renderModuleNav(pGroup, pModule);
|
|
437
|
+
}
|
|
438
|
+
}
|
|
439
|
+
}
|
|
440
|
+
|
|
377
441
|
/**
|
|
378
442
|
* Navigate to a hash route.
|
|
379
443
|
*
|
|
@@ -433,12 +497,16 @@ class DocuserveApplication extends libPictApplication
|
|
|
433
497
|
? ('JS Playground: ' + tmpModule)
|
|
434
498
|
: 'JS Playground');
|
|
435
499
|
}
|
|
436
|
-
// Load the module's _playground.json
|
|
437
|
-
//
|
|
438
|
-
//
|
|
439
|
-
//
|
|
440
|
-
//
|
|
441
|
-
|
|
500
|
+
// Load the module's _playground.json. Two reasons to always do
|
|
501
|
+
// this (regardless of tmpEnabled):
|
|
502
|
+
// 1. The async `Kind` check inside isPlaygroundEnabled needs
|
|
503
|
+
// the cache populated. If the config declares Kind:
|
|
504
|
+
// "section", we have to re-call setPlaygroundEnabled(false)
|
|
505
|
+
// to hide the Fable drawer that the sync sidebar-based
|
|
506
|
+
// check just turned on.
|
|
507
|
+
// 2. Apps still consult AppData.Docuserve.Playground.Config
|
|
508
|
+
// (DOM-sandbox pane visibility etc.).
|
|
509
|
+
if (tmpDoc && typeof tmpDoc.loadPlaygroundConfig === 'function')
|
|
442
510
|
{
|
|
443
511
|
tmpDoc.loadPlaygroundConfig(tmpGroup, tmpModule).then((pConfig) =>
|
|
444
512
|
{
|
|
@@ -447,6 +515,16 @@ class DocuserveApplication extends libPictApplication
|
|
|
447
515
|
this.pict.AppData.Docuserve.Playground = {};
|
|
448
516
|
}
|
|
449
517
|
this.pict.AppData.Docuserve.Playground.Config = pConfig || null;
|
|
518
|
+
|
|
519
|
+
// Re-evaluate the drawer's enabled state now that the
|
|
520
|
+
// cache is populated — a Kind: "section" config flips
|
|
521
|
+
// it from true back to false.
|
|
522
|
+
if (typeof tmpDoc.isPlaygroundEnabled === 'function')
|
|
523
|
+
{
|
|
524
|
+
let tmpReEnabled = tmpDoc.isPlaygroundEnabled(tmpGroup, tmpModule);
|
|
525
|
+
tmpLayout.setPlaygroundEnabled(tmpReEnabled);
|
|
526
|
+
}
|
|
527
|
+
|
|
450
528
|
// Config controls DOM-sandbox pane visibility; let the
|
|
451
529
|
// playground view re-evaluate the moment it lands. No-op
|
|
452
530
|
// if the view hasn't been mounted yet.
|
|
@@ -457,18 +535,6 @@ class DocuserveApplication extends libPictApplication
|
|
|
457
535
|
}
|
|
458
536
|
});
|
|
459
537
|
}
|
|
460
|
-
else
|
|
461
|
-
{
|
|
462
|
-
if (this.pict.AppData.Docuserve.Playground)
|
|
463
|
-
{
|
|
464
|
-
this.pict.AppData.Docuserve.Playground.Config = null;
|
|
465
|
-
}
|
|
466
|
-
let tmpPlaygroundView = this.pict.views['Docuserve-Fable-Playground'];
|
|
467
|
-
if (tmpPlaygroundView && typeof tmpPlaygroundView._applySandboxMode === 'function')
|
|
468
|
-
{
|
|
469
|
-
tmpPlaygroundView._applySandboxMode();
|
|
470
|
-
}
|
|
471
|
-
}
|
|
472
538
|
}
|
|
473
539
|
|
|
474
540
|
/**
|
|
@@ -13,6 +13,7 @@ let _PictCLIProgram = new libCLIProgram(
|
|
|
13
13
|
require('./commands/Docuserve-Command-Inject.js'),
|
|
14
14
|
require('./commands/Docuserve-Command-PrepareLocal.js'),
|
|
15
15
|
require('./commands/Docuserve-Command-StageExamples.js'),
|
|
16
|
+
require('./commands/Docuserve-Command-StagePlayground.js'),
|
|
16
17
|
require('./commands/Docuserve-Command-CheckLinks.js')
|
|
17
18
|
]);
|
|
18
19
|
|
|
@@ -0,0 +1,279 @@
|
|
|
1
|
+
const libCommandLineCommand = require('pict-service-commandlineutility').ServiceCommandLineCommand;
|
|
2
|
+
|
|
3
|
+
const libFS = require('fs');
|
|
4
|
+
const libPath = require('path');
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Recursively create a directory if it does not exist.
|
|
8
|
+
*/
|
|
9
|
+
function ensureDir(pPath)
|
|
10
|
+
{
|
|
11
|
+
if (!libFS.existsSync(pPath))
|
|
12
|
+
{
|
|
13
|
+
libFS.mkdirSync(pPath, { recursive: true });
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* `pict-docuserve stage-playground <docs>` — read `<docs>/_playground.json`
|
|
19
|
+
* and copy every `Imports[]` entry with `Source: "local"` from its resolved
|
|
20
|
+
* source bundle into `<docs>/<Path>`.
|
|
21
|
+
*
|
|
22
|
+
* This is the per-module half of the section-playground story: each module's
|
|
23
|
+
* `_playground.json` declares which UMD bundles its iframe needs, this
|
|
24
|
+
* command stages them into the docs tree so the iframe can `<script src=...>`
|
|
25
|
+
* them relative to the docs root. Without it, the bundles either have to be
|
|
26
|
+
* hand-copied (the original section-form workflow) or loaded from the CDN —
|
|
27
|
+
* which doesn't work for un-published in-development versions.
|
|
28
|
+
*
|
|
29
|
+
* Resolution order for each Import's source bundle:
|
|
30
|
+
* 1. `<moduleRoot>/node_modules/<Name>/dist/<Name>.min.js` — the normal
|
|
31
|
+
* case for peer dependencies.
|
|
32
|
+
* 2. `<moduleRoot>/dist/<Name>.min.js` — when the Import IS the module
|
|
33
|
+
* being staged (e.g. pict-section-form staging itself).
|
|
34
|
+
* 3. Sibling monorepo checkout — walks up looking for a `modules/`
|
|
35
|
+
* directory and searches `modules/<group>/<Name>/dist/<Name>.min.js`.
|
|
36
|
+
* Lets in-monorepo dev workflows pick up a freshly-built bundle even
|
|
37
|
+
* when the umbrella `node_modules/` is stale.
|
|
38
|
+
*
|
|
39
|
+
* Clean no-op when `_playground.json` is absent — safe to wire into
|
|
40
|
+
* `quack prepare-docs` for every module.
|
|
41
|
+
*/
|
|
42
|
+
class DocuserveCommandStagePlayground extends libCommandLineCommand
|
|
43
|
+
{
|
|
44
|
+
constructor(pFable, pManifest, pServiceHash)
|
|
45
|
+
{
|
|
46
|
+
super(pFable, pManifest, pServiceHash);
|
|
47
|
+
|
|
48
|
+
this.options.CommandKeyword = 'stage-playground';
|
|
49
|
+
this.options.Description = 'Stage local Imports referenced by docs/_playground.json into the docs playground runtime folder.';
|
|
50
|
+
|
|
51
|
+
this.options.CommandArguments.push({ Name: '[docs_folder]', Description: 'The documentation folder to stage into. Defaults to ./docs.' });
|
|
52
|
+
this.options.CommandOptions.push({ Name: '-m, --module_root [module_root]', Description: 'Root of the module being staged (where node_modules lives). Defaults to the docs folder\'s parent.', Default: '' });
|
|
53
|
+
|
|
54
|
+
this.options.Aliases.push('stage-playground-runtime');
|
|
55
|
+
|
|
56
|
+
this.addCommand();
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
onRun()
|
|
60
|
+
{
|
|
61
|
+
let tmpDocsFolder = libPath.resolve(this.ArgumentString || './docs');
|
|
62
|
+
let tmpModuleRoot = libPath.resolve(this.CommandOptions.module_root || libPath.dirname(tmpDocsFolder));
|
|
63
|
+
|
|
64
|
+
let tmpPlaygroundConfigPath = libPath.join(tmpDocsFolder, '_playground.json');
|
|
65
|
+
if (!libFS.existsSync(tmpPlaygroundConfigPath))
|
|
66
|
+
{
|
|
67
|
+
this.log.info(`No _playground.json at [${tmpPlaygroundConfigPath}]; nothing to stage.`);
|
|
68
|
+
return;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
let tmpConfig;
|
|
72
|
+
try
|
|
73
|
+
{
|
|
74
|
+
tmpConfig = JSON.parse(libFS.readFileSync(tmpPlaygroundConfigPath, 'utf8'));
|
|
75
|
+
}
|
|
76
|
+
catch (pError)
|
|
77
|
+
{
|
|
78
|
+
this.log.error(`Failed to parse _playground.json [${tmpPlaygroundConfigPath}]: ${pError.message}`);
|
|
79
|
+
process.exit(1);
|
|
80
|
+
return;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
let tmpImports = (tmpConfig && Array.isArray(tmpConfig.Imports)) ? tmpConfig.Imports : [];
|
|
84
|
+
let tmpStylesheets = (tmpConfig && Array.isArray(tmpConfig.Stylesheets)) ? tmpConfig.Stylesheets : [];
|
|
85
|
+
|
|
86
|
+
// Staging targets — every Import / Stylesheet with Source: "local".
|
|
87
|
+
// Each entry produces { kind, name, source, dest } once resolved.
|
|
88
|
+
let tmpJobs = [];
|
|
89
|
+
for (let i = 0; i < tmpImports.length; i++)
|
|
90
|
+
{
|
|
91
|
+
let tmpImp = tmpImports[i];
|
|
92
|
+
if (!tmpImp || tmpImp.Source !== 'local') { continue; }
|
|
93
|
+
tmpJobs.push({ kind: 'script', spec: tmpImp });
|
|
94
|
+
}
|
|
95
|
+
for (let i = 0; i < tmpStylesheets.length; i++)
|
|
96
|
+
{
|
|
97
|
+
let tmpSheet = tmpStylesheets[i];
|
|
98
|
+
if (!tmpSheet || tmpSheet.Source !== 'local') { continue; }
|
|
99
|
+
tmpJobs.push({ kind: 'stylesheet', spec: tmpSheet });
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
if (tmpJobs.length === 0)
|
|
103
|
+
{
|
|
104
|
+
this.log.info(`No local Imports or Stylesheets declared in _playground.json; nothing to stage.`);
|
|
105
|
+
return;
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
this.log.info(`Staging ${tmpJobs.length} playground runtime asset(s) from module root [${tmpModuleRoot}]...`);
|
|
109
|
+
|
|
110
|
+
let tmpCopied = 0;
|
|
111
|
+
let tmpFailed = 0;
|
|
112
|
+
for (let i = 0; i < tmpJobs.length; i++)
|
|
113
|
+
{
|
|
114
|
+
let tmpJob = tmpJobs[i];
|
|
115
|
+
let tmpKind = tmpJob.kind;
|
|
116
|
+
let tmpSpec = tmpJob.spec;
|
|
117
|
+
let tmpName = tmpSpec.Name;
|
|
118
|
+
let tmpExt = (tmpKind === 'stylesheet') ? 'css' : 'js';
|
|
119
|
+
|
|
120
|
+
if (!tmpName && !tmpSpec.Path)
|
|
121
|
+
{
|
|
122
|
+
this.log.warn(`${tmpKind} #${i} has neither Name nor Path; skipping.`);
|
|
123
|
+
tmpFailed++;
|
|
124
|
+
continue;
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
let tmpRelativePath = tmpSpec.Path || `playground/runtime/${tmpName}.min.${tmpExt}`;
|
|
128
|
+
let tmpDest = libPath.join(tmpDocsFolder, tmpRelativePath);
|
|
129
|
+
|
|
130
|
+
let tmpSource = this._resolveAssetSource(tmpKind, tmpName, tmpSpec.Path, tmpModuleRoot);
|
|
131
|
+
if (!tmpSource)
|
|
132
|
+
{
|
|
133
|
+
this.log.warn(`[${tmpName || tmpRelativePath}] No ${tmpKind} source found; skipping. Build it (npx quack build) and re-run prepare-docs.`);
|
|
134
|
+
tmpFailed++;
|
|
135
|
+
continue;
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
try
|
|
139
|
+
{
|
|
140
|
+
ensureDir(libPath.dirname(tmpDest));
|
|
141
|
+
libFS.copyFileSync(tmpSource, tmpDest);
|
|
142
|
+
this.log.info(`Staged ${tmpKind} ${tmpName || tmpRelativePath}: ${tmpSource} -> ${tmpDest}`);
|
|
143
|
+
tmpCopied++;
|
|
144
|
+
}
|
|
145
|
+
catch (pError)
|
|
146
|
+
{
|
|
147
|
+
this.log.error(`[${tmpName || tmpRelativePath}] Copy failed: ${pError.message}`);
|
|
148
|
+
tmpFailed++;
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
this.log.info(`Playground staging complete: ${tmpCopied} copied, ${tmpFailed} failed.`);
|
|
153
|
+
if (tmpFailed > 0 && tmpCopied === 0)
|
|
154
|
+
{
|
|
155
|
+
// Hard failure only when nothing landed — a partial copy is a
|
|
156
|
+
// warning so prepare-docs can keep going.
|
|
157
|
+
process.exit(1);
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
/**
|
|
162
|
+
* Resolve the source asset (script bundle or stylesheet) for an Import
|
|
163
|
+
* or Stylesheet entry. Scripts look at `<pkg>/dist/<pkg>.min.js`;
|
|
164
|
+
* stylesheets look at `<pkg>/dist/<file>` for whatever Path was declared
|
|
165
|
+
* (since CSS filenames don't follow a single naming convention).
|
|
166
|
+
*
|
|
167
|
+
* @param {string} pKind - "script" or "stylesheet".
|
|
168
|
+
* @param {string} pName - Package name (may be empty for ad-hoc paths).
|
|
169
|
+
* @param {string} pSpecPath - Optional Path from the spec; for stylesheets
|
|
170
|
+
* we use its basename to find the source CSS.
|
|
171
|
+
* @param {string} pModuleRoot - Root of the module being staged.
|
|
172
|
+
* @returns {string|null} Absolute source path, or null if not found.
|
|
173
|
+
*/
|
|
174
|
+
_resolveAssetSource(pKind, pName, pSpecPath, pModuleRoot)
|
|
175
|
+
{
|
|
176
|
+
if (pKind === 'script')
|
|
177
|
+
{
|
|
178
|
+
return this._resolveBundleSource(pName, pModuleRoot);
|
|
179
|
+
}
|
|
180
|
+
// Stylesheet — look under the package's dist (or root) for a matching
|
|
181
|
+
// CSS file. The spec's Path basename hints at what file to find.
|
|
182
|
+
let tmpBasename = pSpecPath ? libPath.basename(pSpecPath) : (pName ? pName + '.min.css' : null);
|
|
183
|
+
if (!tmpBasename) { return null; }
|
|
184
|
+
|
|
185
|
+
let tmpCandidates = [];
|
|
186
|
+
if (pName)
|
|
187
|
+
{
|
|
188
|
+
tmpCandidates.push(libPath.join(pModuleRoot, 'node_modules', pName, 'dist', tmpBasename));
|
|
189
|
+
tmpCandidates.push(libPath.join(pModuleRoot, 'node_modules', pName, tmpBasename));
|
|
190
|
+
}
|
|
191
|
+
// Also check the module root in case the CSS lives alongside source/
|
|
192
|
+
tmpCandidates.push(libPath.join(pModuleRoot, 'dist', tmpBasename));
|
|
193
|
+
tmpCandidates.push(libPath.join(pModuleRoot, tmpBasename));
|
|
194
|
+
|
|
195
|
+
for (let i = 0; i < tmpCandidates.length; i++)
|
|
196
|
+
{
|
|
197
|
+
if (libFS.existsSync(tmpCandidates[i]))
|
|
198
|
+
{
|
|
199
|
+
return tmpCandidates[i];
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
return null;
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
/**
|
|
206
|
+
* Resolve the source UMD bundle for an Import by Name.
|
|
207
|
+
*
|
|
208
|
+
* @param {string} pName - Package name (e.g. "pict", "pict-section-form").
|
|
209
|
+
* @param {string} pModuleRoot - Root of the module being staged.
|
|
210
|
+
* @returns {string|null} Absolute path to the bundle, or null if not found.
|
|
211
|
+
*/
|
|
212
|
+
_resolveBundleSource(pName, pModuleRoot)
|
|
213
|
+
{
|
|
214
|
+
let tmpCandidates = [];
|
|
215
|
+
|
|
216
|
+
// 1. Peer dependency: <moduleRoot>/node_modules/<Name>/dist/<Name>.min.js
|
|
217
|
+
tmpCandidates.push(libPath.join(pModuleRoot, 'node_modules', pName, 'dist', `${pName}.min.js`));
|
|
218
|
+
|
|
219
|
+
// 2. Module IS the package being staged: <moduleRoot>/dist/<Name>.min.js
|
|
220
|
+
try
|
|
221
|
+
{
|
|
222
|
+
let tmpPkgPath = libPath.join(pModuleRoot, 'package.json');
|
|
223
|
+
if (libFS.existsSync(tmpPkgPath))
|
|
224
|
+
{
|
|
225
|
+
let tmpPkg = JSON.parse(libFS.readFileSync(tmpPkgPath, 'utf8'));
|
|
226
|
+
if (tmpPkg && tmpPkg.name === pName)
|
|
227
|
+
{
|
|
228
|
+
tmpCandidates.push(libPath.join(pModuleRoot, 'dist', `${pName}.min.js`));
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
}
|
|
232
|
+
catch (pError)
|
|
233
|
+
{
|
|
234
|
+
// Non-fatal — fall through to other candidates.
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
// 3. Sibling monorepo checkout — walk up until we find a `modules/`
|
|
238
|
+
// directory, then search modules/<group>/<Name>/dist/<Name>.min.js.
|
|
239
|
+
let tmpUp = pModuleRoot;
|
|
240
|
+
for (let i = 0; i < 5; i++)
|
|
241
|
+
{
|
|
242
|
+
let tmpModulesDir = libPath.join(tmpUp, 'modules');
|
|
243
|
+
if (libFS.existsSync(tmpModulesDir) && libFS.statSync(tmpModulesDir).isDirectory())
|
|
244
|
+
{
|
|
245
|
+
try
|
|
246
|
+
{
|
|
247
|
+
let tmpGroups = libFS.readdirSync(tmpModulesDir);
|
|
248
|
+
for (let g = 0; g < tmpGroups.length; g++)
|
|
249
|
+
{
|
|
250
|
+
let tmpCandidate = libPath.join(tmpModulesDir, tmpGroups[g], pName, 'dist', `${pName}.min.js`);
|
|
251
|
+
tmpCandidates.push(tmpCandidate);
|
|
252
|
+
}
|
|
253
|
+
}
|
|
254
|
+
catch (pError)
|
|
255
|
+
{
|
|
256
|
+
// readdirSync can fail on permission errors; skip silently.
|
|
257
|
+
}
|
|
258
|
+
break;
|
|
259
|
+
}
|
|
260
|
+
let tmpNext = libPath.dirname(tmpUp);
|
|
261
|
+
if (tmpNext === tmpUp)
|
|
262
|
+
{
|
|
263
|
+
break;
|
|
264
|
+
}
|
|
265
|
+
tmpUp = tmpNext;
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
for (let i = 0; i < tmpCandidates.length; i++)
|
|
269
|
+
{
|
|
270
|
+
if (libFS.existsSync(tmpCandidates[i]))
|
|
271
|
+
{
|
|
272
|
+
return tmpCandidates[i];
|
|
273
|
+
}
|
|
274
|
+
}
|
|
275
|
+
return null;
|
|
276
|
+
}
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
module.exports = DocuserveCommandStagePlayground;
|
|
@@ -1617,18 +1617,24 @@ class DocuserveDocumentationProvider extends libPictProvider
|
|
|
1617
1617
|
}
|
|
1618
1618
|
|
|
1619
1619
|
/**
|
|
1620
|
-
* Decide whether the playground panel should
|
|
1621
|
-
* given group/module.
|
|
1622
|
-
*
|
|
1623
|
-
*
|
|
1624
|
-
* `
|
|
1625
|
-
*
|
|
1626
|
-
*
|
|
1627
|
-
*
|
|
1628
|
-
*
|
|
1629
|
-
*
|
|
1630
|
-
*
|
|
1631
|
-
*
|
|
1620
|
+
* Decide whether the **Fable bottom-drawer** playground panel should
|
|
1621
|
+
* be enabled for the given group/module.
|
|
1622
|
+
*
|
|
1623
|
+
* Resolution order:
|
|
1624
|
+
* 1. If `_playground.json` is cached AND its `Kind` is `"section"`,
|
|
1625
|
+
* return false. Section-playground modules use the full-page
|
|
1626
|
+
* `#/playground/section` route and explicitly do NOT want the
|
|
1627
|
+
* Fable JS REPL drawer popping up on every doc page.
|
|
1628
|
+
* 2. Otherwise the opt-in signal is a `playground.md` entry in the
|
|
1629
|
+
* module's sidebar (catalog mode) or the root SidebarGroups
|
|
1630
|
+
* (standalone mode). Presence of that entry → drawer + tab
|
|
1631
|
+
* strip + "Try in Playground" buttons on code blocks.
|
|
1632
|
+
*
|
|
1633
|
+
* The cache is populated by `loadPlaygroundConfig()` (called on each
|
|
1634
|
+
* navigation by `_syncPlaygroundVisibility`). On the first visit to
|
|
1635
|
+
* a module, the cache may not yet be populated — this method
|
|
1636
|
+
* conservatively falls through to the sidebar check, and the caller
|
|
1637
|
+
* re-invokes once the async config load resolves.
|
|
1632
1638
|
*
|
|
1633
1639
|
* @param {string} [pGroup] - Current group key (may be empty)
|
|
1634
1640
|
* @param {string} [pModule] - Current module name (may be empty)
|
|
@@ -1636,6 +1642,20 @@ class DocuserveDocumentationProvider extends libPictProvider
|
|
|
1636
1642
|
*/
|
|
1637
1643
|
isPlaygroundEnabled(pGroup, pModule)
|
|
1638
1644
|
{
|
|
1645
|
+
// Check the _playground.json cache for an explicit Kind: 'section'
|
|
1646
|
+
// declaration — that module uses the full-page playground and
|
|
1647
|
+
// the Fable drawer must stay out of its way on every doc page,
|
|
1648
|
+
// not just on the playground route itself.
|
|
1649
|
+
let tmpCacheKey = (pGroup || '') + '/' + (pModule || '');
|
|
1650
|
+
if (Object.prototype.hasOwnProperty.call(this._PlaygroundConfigCache, tmpCacheKey))
|
|
1651
|
+
{
|
|
1652
|
+
let tmpConfig = this._PlaygroundConfigCache[tmpCacheKey];
|
|
1653
|
+
if (tmpConfig && tmpConfig.Kind === 'section')
|
|
1654
|
+
{
|
|
1655
|
+
return false;
|
|
1656
|
+
}
|
|
1657
|
+
}
|
|
1658
|
+
|
|
1639
1659
|
// Per-module sidebar (catalog mode).
|
|
1640
1660
|
if (pGroup && pModule)
|
|
1641
1661
|
{
|