diff --git a/package-lock.json b/package-lock.json index 8dbe6796..44b5715d 100644 --- a/package-lock.json +++ b/package-lock.json @@ -2939,6 +2939,15 @@ "integrity": "sha512-Q5Vn3yjTDyCMV50TB6VRIbQNxSE4OmZR86VSbGaNpfUolm0iePBB4KdEEHmxoY5sT2+2DIvXW0rvMDP2nHZ4Mg==", "dev": true }, + "@types/fs-extra": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/@types/fs-extra/-/fs-extra-5.1.0.tgz", + "integrity": "sha512-AInn5+UBFIK9FK5xc9yP5e3TQSPNNgjHByqYcj9g5elVBnDQcQL7PlO1CIRy2gWlbwK7UPYqi7vRvFA44dCmYQ==", + "dev": true, + "requires": { + "@types/node": "*" + } + }, "@types/geojson": { "version": "7946.0.7", "resolved": "https://registry.npmjs.org/@types/geojson/-/geojson-7946.0.7.tgz", @@ -3669,6 +3678,21 @@ } } }, + "@types/handlebars": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/@types/handlebars/-/handlebars-4.1.0.tgz", + "integrity": "sha512-gq9YweFKNNB1uFK71eRqsd4niVkXrxHugqWFQkeLRJvGjnxsLr16bYtcsG4tOFwmYi0Bax+wCkbf1reUfdl4kA==", + "dev": true, + "requires": { + "handlebars": "*" + } + }, + "@types/highlight.js": { + "version": "9.12.3", + "resolved": "https://registry.npmjs.org/@types/highlight.js/-/highlight.js-9.12.3.tgz", + "integrity": "sha512-pGF/zvYOACZ/gLGWdQH8zSwteQS1epp68yRcVLJMgUck/MjEn/FBYmPub9pXT8C1e4a8YZfHo1CKyV8q1vKUnQ==", + "dev": true + }, "@types/jasmine": { "version": "2.5.54", "resolved": "https://registry.npmjs.org/@types/jasmine/-/jasmine-2.5.54.tgz", @@ -3693,6 +3717,18 @@ "@types/geojson": "*" } }, + "@types/lodash": { + "version": "4.14.150", + "resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.14.150.tgz", + "integrity": "sha512-kMNLM5JBcasgYscD9x/Gvr6lTAv2NVgsKtet/hm93qMyf/D1pt+7jeEZklKJKxMVmXjxbRVQQGfqDSfipYCO6w==", + "dev": true + }, + "@types/marked": { + "version": "0.4.2", + "resolved": "https://registry.npmjs.org/@types/marked/-/marked-0.4.2.tgz", + "integrity": "sha512-cDB930/7MbzaGF6U3IwSQp6XBru8xWajF5PV2YZZeV8DyiliTuld11afVztGI9+yJZ29il5E+NpGA6ooV/Cjkg==", + "dev": true + }, "@types/minimatch": { "version": "3.0.3", "resolved": "https://registry.npmjs.org/@types/minimatch/-/minimatch-3.0.3.tgz", @@ -3717,6 +3753,16 @@ "integrity": "sha512-/DJGXtMuklLQef49qDsmjQofzaGU6D5To2xJZRLBNZO4GLAi30IjxLy6hHRQdycXP+IZKKXqJhYyNJ53SglJ8w==", "dev": true }, + "@types/shelljs": { + "version": "0.8.7", + "resolved": "https://registry.npmjs.org/@types/shelljs/-/shelljs-0.8.7.tgz", + "integrity": "sha512-Mg2qGjLIJIieeJ1/NjswAOY9qXDShLeh6JwpD1NZsvUvI0hxdUCNDpnBXv9YQeugKi2EHU+BqkbUE4jpY4GKmQ==", + "dev": true, + "requires": { + "@types/glob": "*", + "@types/node": "*" + } + }, "@types/source-list-map": { "version": "0.1.2", "resolved": "https://registry.npmjs.org/@types/source-list-map/-/source-list-map-0.1.2.tgz", @@ -6061,6 +6107,11 @@ "integrity": "sha512-a+UqTh4kgZg/SlGvfbzDHpgRu7AAQOmmqRHJnxhRZICKFUT91brVhNNt58CMWU9PsBbv3PDCZUHbVxuDiH2mtA==", "dev": true }, + "colors.js": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/colors.js/-/colors.js-1.2.4.tgz", + "integrity": "sha1-U4DdOUERZ4b7wFX06kAgL8/goPA=" + }, "combine-lists": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/combine-lists/-/combine-lists-1.0.1.tgz", @@ -8021,6 +8072,25 @@ "buffer-indexof": "^1.0.0" } }, + "doc-prsr": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/doc-prsr/-/doc-prsr-2.2.0.tgz", + "integrity": "sha512-dki+ovIixP94KE6uCkatbMYa05tlnOW4MkgNL7rJ1R4cNWZm2yfn3ydod42p3xpZkh4vzKYVq9lJf9Nescuryg==", + "dev": true, + "requires": { + "commander": "^2.9.0", + "path": "^0.12.7", + "typescript": "^2.7.0" + }, + "dependencies": { + "typescript": { + "version": "2.9.2", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-2.9.2.tgz", + "integrity": "sha512-Gr4p6nFNaoufRIY4NMdpQRNmgxVIGMs4Fcu/ujdYk3nAZqk7supzBE9idmvfZIlH/Cuj//dvi+019qEue9lV0w==", + "dev": true + } + } + }, "doiuse": { "version": "2.6.0", "resolved": "https://registry.npmjs.org/doiuse/-/doiuse-2.6.0.tgz", @@ -16947,6 +17017,33 @@ "integrity": "sha1-s2PlXoAGym/iF4TS2yK9FdeRfxQ=", "dev": true }, + "path": { + "version": "0.12.7", + "resolved": "https://registry.npmjs.org/path/-/path-0.12.7.tgz", + "integrity": "sha1-1NwqUGxM4hl+tIHr/NWzbAFAsQ8=", + "dev": true, + "requires": { + "process": "^0.11.1", + "util": "^0.10.3" + }, + "dependencies": { + "inherits": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", + "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=", + "dev": true + }, + "util": { + "version": "0.10.4", + "resolved": "https://registry.npmjs.org/util/-/util-0.10.4.tgz", + "integrity": "sha512-0Pm9hTQ3se5ll1XihRic3FDIku70C+iHUdT/W926rSgHV5QgXsYbKZN8MSC3tJtSkhuROzvsQjAaFENRXr+19A==", + "dev": true, + "requires": { + "inherits": "2.0.3" + } + } + } + }, "path-browserify": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/path-browserify/-/path-browserify-0.0.1.tgz", @@ -18093,6 +18190,12 @@ "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==" }, + "progress": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/progress/-/progress-2.0.3.tgz", + "integrity": "sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==", + "dev": true + }, "promise": { "version": "7.3.1", "resolved": "https://registry.npmjs.org/promise/-/promise-7.3.1.tgz", @@ -21894,6 +21997,73 @@ "integrity": "sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c=", "dev": true }, + "typedoc": { + "version": "0.12.0", + "resolved": "https://registry.npmjs.org/typedoc/-/typedoc-0.12.0.tgz", + "integrity": "sha512-dsdlaYZ7Je8JC+jQ3j2Iroe4uyD0GhqzADNUVyBRgLuytQDP/g0dPkAw5PdM/4drnmmJjRzSWW97FkKo+ITqQg==", + "dev": true, + "requires": { + "@types/fs-extra": "^5.0.3", + "@types/handlebars": "^4.0.38", + "@types/highlight.js": "^9.12.3", + "@types/lodash": "^4.14.110", + "@types/marked": "^0.4.0", + "@types/minimatch": "3.0.3", + "@types/shelljs": "^0.8.0", + "fs-extra": "^7.0.0", + "handlebars": "^4.0.6", + "highlight.js": "^9.0.0", + "lodash": "^4.17.10", + "marked": "^0.4.0", + "minimatch": "^3.0.0", + "progress": "^2.0.0", + "shelljs": "^0.8.2", + "typedoc-default-themes": "^0.5.0", + "typescript": "3.0.x" + }, + "dependencies": { + "fs-extra": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-7.0.1.tgz", + "integrity": "sha512-YJDaCJZEnBmcbw13fvdAM9AwNOJwOzrE4pqMqBq5nFiEqXUqHwlK4B+3pUw6JNvfSPtX05xFHtYy/1ni01eGCw==", + "dev": true, + "requires": { + "graceful-fs": "^4.1.2", + "jsonfile": "^4.0.0", + "universalify": "^0.1.0" + } + }, + "marked": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/marked/-/marked-0.4.0.tgz", + "integrity": "sha512-tMsdNBgOsrUophCAFQl0XPe6Zqk/uy9gnue+jIIKhykO51hxyu6uNx7zBPy0+y/WKYVZZMspV9YeXLNdKk+iYw==", + "dev": true + }, + "shelljs": { + "version": "0.8.3", + "resolved": "https://registry.npmjs.org/shelljs/-/shelljs-0.8.3.tgz", + "integrity": "sha512-fc0BKlAWiLpwZljmOvAOTE/gXawtCoNrP5oaY7KIaQbbyHeQVg01pSEuEGvGh3HEdBU4baCD7wQBwADmM/7f7A==", + "dev": true, + "requires": { + "glob": "^7.0.0", + "interpret": "^1.0.0", + "rechoir": "^0.6.2" + } + }, + "typescript": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-3.0.3.tgz", + "integrity": "sha512-kk80vLW9iGtjMnIv11qyxLqZm20UklzuR2tL0QAnDIygIUIemcZMxlMWudl9OOt76H3ntVzcTiddQ1/pAAJMYg==", + "dev": true + } + } + }, + "typedoc-default-themes": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/typedoc-default-themes/-/typedoc-default-themes-0.5.0.tgz", + "integrity": "sha1-bcJDPnjti+qOiHo6zeLzF4W9Yic=", + "dev": true + }, "typeface-exo": { "version": "0.0.22", "resolved": "https://registry.npmjs.org/typeface-exo/-/typeface-exo-0.0.22.tgz", diff --git a/package.json b/package.json index 4379e8c7..204ae98a 100644 --- a/package.json +++ b/package.json @@ -28,9 +28,10 @@ "e2e": "ng e2e", "docs": "compodoc -p src/tsconfig.app.json -d docs", "docs:dirs": "gulp create-docs-dirs", - "docs:build": "npm-run-all docs:prepare docs:dirs", "docs:parse": "gulp docs", - "docs:prepare": "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:serve": "npm start -- docs --port 4100", "docs:gh-pages": "ts-node -P ./scripts/docs/tsconfig.json ./scripts/docs/build-docs.ts", "prepush": "npm run lint:ci", @@ -63,6 +64,7 @@ "ckeditor": "4.7.3", "classlist.js": "1.1.20150312", "core-js": "2.5.1", + "colors.js": "1.2.4", "echarts": "^4.0.2", "eva-icons": "^1.1.3", "gulp-bump": "2.7.0", @@ -107,6 +109,7 @@ "angular-cli-ghpages": "^0.6.2", "codelyzer": "^5.1.2", "conventional-changelog-cli": "1.3.4", + "doc-prsr": "2.2.0", "gulp": "4.0.2", "gulp-rename": "1.4.0", "gulp-replace": "1.0.0", @@ -128,6 +131,7 @@ "rimraf": "2.6.1", "style-loader": "^1.1.3", "stylelint": "7.13.0", + "typedoc": "^0.12.0", "ts-node": "3.2.2", "tslint": "^5.7.0", "tslint-language-service": "^0.9.9", diff --git a/scripts/docs/build-docs.ts b/scripts/docs/build-docs.ts index d198679c..3a4ee3c2 100644 --- a/scripts/docs/build-docs.ts +++ b/scripts/docs/build-docs.ts @@ -110,7 +110,9 @@ async function buildDocsApp(projectDir: string, baseHref: string) { if (!baseHref.endsWith('/')) { baseHref = baseHref + '/'; } - await runCommand('npm run build -- docs --prod --aot --base-href /ngx-admin/', { cwd: projectDir }); + // await runCommand('npm run build -- docs --prod --aot --base-href /ngx-admin/', { cwd: projectDir }); + // await runCommand('npm run docs:prepare', { cwd: projectDir }); + await runCommand('npm run docs:build', { cwd: projectDir }); // await runCommand(`npm run build -- docs --prod --base-href '${baseHref}'`, { cwd: projectDir }); // await runCommand('npm run docs:dirs', { cwd: projectDir }); } diff --git a/scripts/gulp/tasks/config.ts b/scripts/gulp/tasks/config.ts index 2fb538c6..4bf55b38 100644 --- a/scripts/gulp/tasks/config.ts +++ b/scripts/gulp/tasks/config.ts @@ -1 +1,3 @@ export const DOCS_DIST = './docs/dist'; +export const DOCS_OUTPUT = './docs/output.json'; +export const EXTENSIONS = ['ts', 'html', 'scss']; diff --git a/scripts/gulp/tasks/docs/docs.ts b/scripts/gulp/tasks/docs/docs.ts index 3021f193..73e8c429 100644 --- a/scripts/gulp/tasks/docs/docs.ts +++ b/scripts/gulp/tasks/docs/docs.ts @@ -10,7 +10,6 @@ task( 'docs', series( 'generate-doc-json-and-parse-themes', - 'find-full-examples', ), ); task('create-docs-dirs', (done) => { @@ -60,6 +59,7 @@ function flatten(root, arr) { function createDirsStructure(dirs) { const index = readFileSync(join(DOCS_DIST, 'index.html'), 'utf8'); dirs.forEach((dir: any) => { + const fullPath = join(DOCS_DIST, dir); if (!existsSync(fullPath)) { mkDirByPathSync(fullPath); diff --git a/scripts/gulp/tasks/docs/example.ts b/scripts/gulp/tasks/docs/example.ts new file mode 100644 index 00000000..8a0319d8 --- /dev/null +++ b/scripts/gulp/tasks/docs/example.ts @@ -0,0 +1,186 @@ +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)/, ''); +} diff --git a/scripts/gulp/tasks/docs/export-themes.ts b/scripts/gulp/tasks/docs/export-themes.ts new file mode 100644 index 00000000..d60de2ad --- /dev/null +++ b/scripts/gulp/tasks/docs/export-themes.ts @@ -0,0 +1,158 @@ +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; +}