mirror of
https://github.com/akveo/ngx-admin.git
synced 2025-12-17 16:00:14 +01:00
fix(app): build docs script
This commit is contained in:
parent
f33b2502de
commit
4ac024d73d
5 changed files with 3 additions and 356 deletions
|
|
@ -28,9 +28,7 @@
|
||||||
"e2e": "ng e2e",
|
"e2e": "ng e2e",
|
||||||
"docs": "compodoc -p src/tsconfig.app.json -d docs",
|
"docs": "compodoc -p src/tsconfig.app.json -d docs",
|
||||||
"docs:dirs": "gulp create-docs-dirs",
|
"docs:dirs": "gulp create-docs-dirs",
|
||||||
"docs:parse": "gulp docs",
|
"docs:prod": "npm run build -- docs --prod --aot --base-href /ngx-admin/",
|
||||||
"docs:prepare": "npm-run-all docs:parse",
|
|
||||||
"docs:prod": "npm run build -- docs --prod --aot --base-href '/ngx-admin/'",
|
|
||||||
"docs:build": "npm-run-all docs:prod docs:dirs",
|
"docs:build": "npm-run-all docs:prod docs:dirs",
|
||||||
"docs:serve": "npm start -- docs --port 4100",
|
"docs:serve": "npm start -- docs --port 4100",
|
||||||
"docs:gh-pages": "ts-node -P ./scripts/docs/tsconfig.json ./scripts/docs/build-docs.ts",
|
"docs:gh-pages": "ts-node -P ./scripts/docs/tsconfig.json ./scripts/docs/build-docs.ts",
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
export const REPO_URL = 'https://github.com/akveo/ngx-admin.git';
|
export const REPO_URL = 'https://github.com/alexeykurbako/ngx-admin.git';
|
||||||
export const REPO_OWNER = 'akveo';
|
export const REPO_OWNER = 'alexeykurbako';
|
||||||
export const REPO_NAME = 'ngx-admin';
|
export const REPO_NAME = 'ngx-admin';
|
||||||
export const OUT_DIR = 'docs/dist'; // Relative to the directory you run command
|
export const OUT_DIR = 'docs/dist'; // Relative to the directory you run command
|
||||||
|
|
|
||||||
|
|
@ -2,16 +2,9 @@ import { task, series } from 'gulp';
|
||||||
import { existsSync, mkdirSync, readFileSync, writeFileSync } from 'fs';
|
import { existsSync, mkdirSync, readFileSync, writeFileSync } from 'fs';
|
||||||
import { isAbsolute, join, resolve, sep } from 'path';
|
import { isAbsolute, join, resolve, sep } from 'path';
|
||||||
|
|
||||||
import './example';
|
|
||||||
import { structure as DOCS } from '../../../../docs/structure';
|
import { structure as DOCS } from '../../../../docs/structure';
|
||||||
import { DOCS_DIST } from '../config';
|
import { DOCS_DIST } from '../config';
|
||||||
|
|
||||||
task(
|
|
||||||
'docs',
|
|
||||||
series(
|
|
||||||
'generate-doc-json-and-parse-themes',
|
|
||||||
),
|
|
||||||
);
|
|
||||||
task('create-docs-dirs', (done) => {
|
task('create-docs-dirs', (done) => {
|
||||||
const docsStructure = flatten('docs', routesTree(DOCS));
|
const docsStructure = flatten('docs', routesTree(DOCS));
|
||||||
createDirsStructure(docsStructure);
|
createDirsStructure(docsStructure);
|
||||||
|
|
|
||||||
|
|
@ -1,186 +0,0 @@
|
||||||
import { dest, src, task, series } from 'gulp';
|
|
||||||
import { accessSync, readFileSync, writeFileSync } from 'fs';
|
|
||||||
import { DOCS_OUTPUT, EXTENSIONS } from '../config';
|
|
||||||
import { join } from 'path';
|
|
||||||
import { exportThemes } from './export-themes';
|
|
||||||
|
|
||||||
const del = require('del');
|
|
||||||
const replace = require('gulp-replace');
|
|
||||||
const typedoc = require('gulp-typedoc');
|
|
||||||
const sass = require('gulp-sass');
|
|
||||||
const exec = require('child_process').execSync;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Copy everything from with-layout and without-layout dirs
|
|
||||||
* directly into examples dir. This way we can reference examples
|
|
||||||
* without specifying this dirs.
|
|
||||||
* For example, @stacked-example(..., button/button-showcase.component)
|
|
||||||
* instead of @stacked-example(..., layout/button/button-showcase.component)
|
|
||||||
*/
|
|
||||||
const EXAMPLES_SRC = [
|
|
||||||
'./src/playground/*.*',
|
|
||||||
'./src/playground/with-layout/**/*.*',
|
|
||||||
'./src/playground/without-layout/**/*.*',
|
|
||||||
];
|
|
||||||
const EXAMPLES_DEST = './docs/assets/examples';
|
|
||||||
|
|
||||||
task('copy-examples', () => {
|
|
||||||
del.sync(EXAMPLES_DEST);
|
|
||||||
return src(EXAMPLES_SRC)
|
|
||||||
.pipe(replace(/\/\*\*.*\*\/\n\s*\n/s, ''))
|
|
||||||
.pipe(dest(EXAMPLES_DEST));
|
|
||||||
});
|
|
||||||
|
|
||||||
task('generate-doc-json', generateDocJson);
|
|
||||||
function generateDocJson() {
|
|
||||||
return src(['src/framework/**/*.ts', '!src/**/*.spec.ts', '!src/framework/theme/**/node_modules{,/**}'])
|
|
||||||
.pipe(typedoc({
|
|
||||||
module: 'commonjs',
|
|
||||||
target: 'ES6',
|
|
||||||
// TODO: ignoreCompilerErrors, huh?
|
|
||||||
ignoreCompilerErrors: true,
|
|
||||||
includeDeclarations: true,
|
|
||||||
emitDecoratorMetadata: true,
|
|
||||||
experimentalDecorators: true,
|
|
||||||
excludeExternals: true,
|
|
||||||
exclude: 'node_modules/**/*',
|
|
||||||
json: 'docs/docs.json',
|
|
||||||
version: true,
|
|
||||||
noLib: true,
|
|
||||||
}));
|
|
||||||
}
|
|
||||||
|
|
||||||
task(
|
|
||||||
'parse-themes',
|
|
||||||
parseThemes,
|
|
||||||
);
|
|
||||||
function parseThemes() {
|
|
||||||
exec('prsr -g typedoc -f angular -i docs/docs.json -o docs/output.json');
|
|
||||||
|
|
||||||
return src('docs/themes.scss')
|
|
||||||
.pipe(sass({
|
|
||||||
functions: exportThemes('docs/', ''),
|
|
||||||
}));
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
task(
|
|
||||||
'generate-doc-json-and-parse-themes',
|
|
||||||
series(
|
|
||||||
'generate-doc-json',
|
|
||||||
'parse-themes',
|
|
||||||
),
|
|
||||||
);
|
|
||||||
|
|
||||||
task(
|
|
||||||
'validate-examples',
|
|
||||||
series(
|
|
||||||
'copy-examples',
|
|
||||||
(done) => {
|
|
||||||
const docs = JSON.parse(readFileSync(DOCS_OUTPUT, 'utf8'));
|
|
||||||
|
|
||||||
docs.classes.forEach(cls => validate(cls));
|
|
||||||
|
|
||||||
done();
|
|
||||||
},
|
|
||||||
),
|
|
||||||
);
|
|
||||||
|
|
||||||
task(
|
|
||||||
'find-full-examples',
|
|
||||||
series(
|
|
||||||
'validate-examples',
|
|
||||||
(done) => {
|
|
||||||
const docs = JSON.parse(readFileSync(DOCS_OUTPUT, 'utf8'));
|
|
||||||
docs.classes.forEach(cls => {
|
|
||||||
cls.overview = cls.overview.map(unfold);
|
|
||||||
cls.liveExamples = cls.liveExamples.map(unfold);
|
|
||||||
});
|
|
||||||
writeFileSync(DOCS_OUTPUT, JSON.stringify(docs));
|
|
||||||
|
|
||||||
done();
|
|
||||||
},
|
|
||||||
),
|
|
||||||
);
|
|
||||||
|
|
||||||
function unfold(tag) {
|
|
||||||
if (tag.type === 'text') {
|
|
||||||
return tag;
|
|
||||||
}
|
|
||||||
|
|
||||||
return unfoldWithFiles(tag);
|
|
||||||
}
|
|
||||||
|
|
||||||
function unfoldWithFiles(tag) {
|
|
||||||
if (isFile(tag.content.id)) {
|
|
||||||
return unfoldFile(tag);
|
|
||||||
}
|
|
||||||
|
|
||||||
return unfoldComponent(tag);
|
|
||||||
}
|
|
||||||
|
|
||||||
function unfoldFile(tag) {
|
|
||||||
const id = withoutExtension(tag.content.id);
|
|
||||||
const files = [tag.content.id];
|
|
||||||
return createNode(tag, files, id);
|
|
||||||
}
|
|
||||||
|
|
||||||
function unfoldComponent(tag) {
|
|
||||||
const files = EXTENSIONS
|
|
||||||
.map(extension => `${tag.content.id}.${extension}`)
|
|
||||||
.filter(isFileExists);
|
|
||||||
|
|
||||||
return createNode(tag, files);
|
|
||||||
}
|
|
||||||
|
|
||||||
function createNode(tag, files, id = tag.content.id) {
|
|
||||||
return {
|
|
||||||
...tag,
|
|
||||||
content: {
|
|
||||||
...tag.content,
|
|
||||||
files,
|
|
||||||
id,
|
|
||||||
},
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
function validate(cls) {
|
|
||||||
const examples = cls.overview
|
|
||||||
.filter(({ type }) => type !== 'text')
|
|
||||||
.map(({ content }) => content);
|
|
||||||
|
|
||||||
const missing = examples.filter(({ id }) => !isFileExists(id) && !isComponentExists(id));
|
|
||||||
|
|
||||||
if (missing.length) {
|
|
||||||
throw new Error(createMissingMsg(missing));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function createMissingMsg(examples): string {
|
|
||||||
const missing = examples.map(({ id, name }) => `${name}, ${id}`);
|
|
||||||
return `Can't resolve:\n${missing.join('\n')}`;
|
|
||||||
}
|
|
||||||
|
|
||||||
function isComponentExists(path): boolean {
|
|
||||||
return EXTENSIONS
|
|
||||||
.map(extension => `${path}.${extension}`)
|
|
||||||
.some(isFileExists);
|
|
||||||
}
|
|
||||||
|
|
||||||
function isFileExists(file): boolean {
|
|
||||||
try {
|
|
||||||
const path = join(EXAMPLES_DEST, file);
|
|
||||||
accessSync(path);
|
|
||||||
return true;
|
|
||||||
} catch (e) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function isFile(id) {
|
|
||||||
return EXTENSIONS.some(extension => id.endsWith(extension));
|
|
||||||
}
|
|
||||||
|
|
||||||
function withoutExtension(file) {
|
|
||||||
return file.replace(/\.(ts|html|scss)/, '');
|
|
||||||
}
|
|
||||||
|
|
@ -1,158 +0,0 @@
|
||||||
const _ = require('lodash');
|
|
||||||
const fs = require('fs');
|
|
||||||
const Colors = require('colors.js');
|
|
||||||
|
|
||||||
class Prop {
|
|
||||||
public name: string;
|
|
||||||
public value: any = null;
|
|
||||||
public parents: any[] = [];
|
|
||||||
public childs: any[] = [];
|
|
||||||
|
|
||||||
constructor(name) {
|
|
||||||
this.name = name;
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
class PropLink {
|
|
||||||
public theme: any;
|
|
||||||
public prop: any;
|
|
||||||
|
|
||||||
constructor(theme, prop) {
|
|
||||||
this.theme = theme;
|
|
||||||
this.prop = prop;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const exporter = {
|
|
||||||
get_value(a) {
|
|
||||||
let value, i;
|
|
||||||
switch (a.constructor.name) {
|
|
||||||
case 'SassList':
|
|
||||||
value = [];
|
|
||||||
for (i = 0; i < a.getLength(); i++) {
|
|
||||||
value.push(exporter.get_value(a.getValue(i)));
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case 'SassMap':
|
|
||||||
value = {};
|
|
||||||
for (i = 0; i < a.getLength(); i++) {
|
|
||||||
value[a.getKey(i).getValue()] = exporter.get_value(a.getValue(i));
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case 'SassColor':
|
|
||||||
if (1 === a.getA()) {
|
|
||||||
value = Colors.rgb2hex(a.getR(), a.getG(), a.getB());
|
|
||||||
} else {
|
|
||||||
value = 'rgba(' + a.getR() + ', ' + a.getG() + ', ' + a.getB() + ', ' + a.getA() + ')';
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case 'SassNumber':
|
|
||||||
value = a.getValue();
|
|
||||||
if (a.getUnit()) {
|
|
||||||
value += a.getUnit();
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case 'SassNull':
|
|
||||||
value = null;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
value = a.getValue();
|
|
||||||
}
|
|
||||||
return value;
|
|
||||||
},
|
|
||||||
|
|
||||||
parseThemes(THEMES) {
|
|
||||||
let result = {};
|
|
||||||
|
|
||||||
Object.keys(THEMES).forEach((themeName) => {
|
|
||||||
result[themeName] = result[themeName] ? result[themeName] : {};
|
|
||||||
result[themeName].data = result[themeName].data ? result[themeName].data : {};
|
|
||||||
result[themeName].name = themeName;
|
|
||||||
result[themeName].parent = THEMES[themeName].parent;
|
|
||||||
const theme = THEMES[themeName].data;
|
|
||||||
|
|
||||||
Object.keys(theme).forEach((prop) => {
|
|
||||||
result[themeName].data[prop] = result[themeName].data[prop] ? result[themeName].data[prop] : new Prop(prop);
|
|
||||||
result = exporter.getParent(prop, themeName, themeName, prop, result, THEMES);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
return result;
|
|
||||||
},
|
|
||||||
|
|
||||||
getParent(prop, scopedThemeName, resultThemeName, resultProp, resultObj, THEMES) {
|
|
||||||
const scopedTheme = THEMES[scopedThemeName].data;
|
|
||||||
const scopedParent = THEMES[scopedThemeName].parent;
|
|
||||||
const value = scopedTheme[prop];
|
|
||||||
if (typeof value === 'string' && scopedTheme[value]) {
|
|
||||||
if (resultObj[resultThemeName].data[resultProp].parents.length === 0) {
|
|
||||||
exporter.linkProps(resultObj, scopedThemeName, value, resultThemeName, prop);
|
|
||||||
} else {
|
|
||||||
resultObj[resultThemeName].data[resultProp].parents.push(new PropLink(scopedThemeName, value));
|
|
||||||
}
|
|
||||||
exporter.getParent(value, scopedThemeName, resultThemeName, resultProp, resultObj, THEMES);
|
|
||||||
} else {
|
|
||||||
resultObj[resultThemeName].data[resultProp].value = value;
|
|
||||||
if (scopedParent && THEMES[scopedParent].data[prop] === value) {
|
|
||||||
if (resultObj[resultThemeName].data[resultProp].parents.length === 0) {
|
|
||||||
exporter.linkProps(resultObj, scopedParent, prop, resultThemeName, prop)
|
|
||||||
} else {
|
|
||||||
resultObj[resultThemeName].data[resultProp].parents.push(new PropLink(scopedParent, prop));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return resultObj;
|
|
||||||
},
|
|
||||||
|
|
||||||
|
|
||||||
linkProps(resultObj, parentThemeName, parentPropName, childThemeName, childPropName) {
|
|
||||||
if (!resultObj.hasOwnProperty(parentThemeName)) {
|
|
||||||
resultObj[parentThemeName].data = {};
|
|
||||||
resultObj[parentThemeName].data[parentPropName] = new Prop(parentPropName);
|
|
||||||
} else if (!resultObj[parentThemeName].data.hasOwnProperty(parentPropName)) {
|
|
||||||
resultObj[parentThemeName].data[parentPropName] = new Prop(parentPropName);
|
|
||||||
}
|
|
||||||
resultObj[childThemeName].data[childPropName].parents.push(new PropLink(parentThemeName, parentPropName));
|
|
||||||
resultObj[parentThemeName].data[parentPropName].childs.push(new PropLink(childThemeName, childPropName));
|
|
||||||
return resultObj;
|
|
||||||
},
|
|
||||||
|
|
||||||
|
|
||||||
function(path) {
|
|
||||||
return function (file, themes, mapping) {
|
|
||||||
const themesValue = exporter.get_value(themes);
|
|
||||||
const mappingValue = exporter.get_value(mapping);
|
|
||||||
|
|
||||||
const completeThemes = {};
|
|
||||||
Object.keys(themesValue).forEach((themeName) => {
|
|
||||||
const theme = themesValue[themeName];
|
|
||||||
completeThemes[themeName] = {
|
|
||||||
...theme,
|
|
||||||
data: _.defaults(mappingValue, theme.data),
|
|
||||||
};
|
|
||||||
});
|
|
||||||
|
|
||||||
|
|
||||||
let output = {
|
|
||||||
themes: exporter.parseThemes(themesValue),
|
|
||||||
// TODO: we need to change internal function interface as it very hard to re-use them
|
|
||||||
completeThemes: exporter.parseThemes(completeThemes),
|
|
||||||
};
|
|
||||||
|
|
||||||
output = _.defaults(JSON.parse(fs.readFileSync(path + '/' + file.getValue())), output);
|
|
||||||
fs.writeFileSync(path + '/' + file.getValue(), JSON.stringify(output, null, ' '));
|
|
||||||
return themes;
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
interface(name) {
|
|
||||||
name = name || 'export';
|
|
||||||
return name + '($file, $themes, $mapping)';
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
export function exportThemes(path, name) {
|
|
||||||
const out = {};
|
|
||||||
out[exporter.interface(name)] = exporter.function(path);
|
|
||||||
return out;
|
|
||||||
}
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue