pict-docuserve 1.4.1 → 1.4.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.
- package/package.json +4 -6
- 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 +2 -2
- package/source/views/PictView-Docuserve-Section-Playground.js +239 -19
- package/source/views/PictView-Docuserve-Splash.js +54 -0
- package/dist/indoctrinate_content_staging/Indoctrinate-Catalog-AppData.json +0 -6333
- package/dist/pict-docuserve.js +0 -14253
- package/dist/pict-docuserve.js.map +0 -1
- package/dist/pict-docuserve.min.js +0 -101
- package/dist/pict-docuserve.min.js.map +0 -1
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "pict-docuserve",
|
|
3
|
-
"version": "1.4.
|
|
3
|
+
"version": "1.4.3",
|
|
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,7 +32,7 @@
|
|
|
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.6",
|
|
38
36
|
"pict-section-histogram": "^1.0.1",
|
|
39
37
|
"pict-section-modal": "^1.1.4",
|
|
40
38
|
"pict-section-theme": "^1.0.6",
|
|
@@ -42,8 +40,8 @@
|
|
|
42
40
|
"pict-view": "^1.0.68"
|
|
43
41
|
},
|
|
44
42
|
"devDependencies": {
|
|
45
|
-
"pict-docuserve": "^1.4.
|
|
46
|
-
"quackage": "^1.2.
|
|
43
|
+
"pict-docuserve": "^1.4.2",
|
|
44
|
+
"quackage": "^1.2.5"
|
|
47
45
|
},
|
|
48
46
|
"copyFilesSettings": {
|
|
49
47
|
"whenFileExists": "overwrite"
|
|
@@ -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;
|
|
@@ -1488,7 +1488,7 @@ class DocuserveDocumentationProvider extends libPictProvider
|
|
|
1488
1488
|
* corresponding #/doc/ route so the link navigates within docuserve
|
|
1489
1489
|
* instead of leaving to GitHub.
|
|
1490
1490
|
*
|
|
1491
|
-
* @param {string} pURL - A GitHub URL (e.g. "https://github.com/
|
|
1491
|
+
* @param {string} pURL - A GitHub URL (e.g. "https://github.com/fable-retold/fable")
|
|
1492
1492
|
* @returns {string|null} The hash route (e.g. "#/doc/fable/fable") or null if not a catalog module
|
|
1493
1493
|
*/
|
|
1494
1494
|
resolveGitHubURLToRoute(pURL)
|
|
@@ -1535,7 +1535,7 @@ class DocuserveDocumentationProvider extends libPictProvider
|
|
|
1535
1535
|
/**
|
|
1536
1536
|
* Resolve the GitHub Pages documentation URL for a module.
|
|
1537
1537
|
*
|
|
1538
|
-
* Returns a URL like https://
|
|
1538
|
+
* Returns a URL like https://fable-retold.github.io/pict-view/ if the
|
|
1539
1539
|
* module exists in the catalog.
|
|
1540
1540
|
*
|
|
1541
1541
|
* @param {string} pGroup - The group key
|