diff --git a/CHANGELOG.md b/CHANGELOG.md
index 6887b5c79..d9cf4e7d0 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,4 +1,5 @@
## v5.2.1
+
Bugfix: fix publish command on windows [#695](https://github.com/idyll-lang/idyll/pull/695)
## v5.2.0
@@ -8,30 +9,34 @@ Add experimental [project create API](https://github.com/idyll-lang/idyll/pull/6
## v5.1.0
Features:
+
- Adds `insertFullWidth` option to markup serializer ([#686](https://github.com/idyll-lang/idyll/pull/686))
- Adds `inlineAuthorView` option to `idyll-document` ([#681](https://github.com/idyll-lang/idyll/pull/681))
Bugfixes:
-- General improvements to markup serialization ([#685](https://github.com/idyll-lang/idyll/pull/685), [#684](https://github.com/idyll-lang/idyll/pull/684), [#676](https://github.com/idyll-lang/idyll/pull/676))
+
+- General improvements to markup serialization ([#685](https://github.com/idyll-lang/idyll/pull/685), [#684](https://github.com/idyll-lang/idyll/pull/684), [#676](https://github.com/idyll-lang/idyll/pull/676))
### v5.0.1
Bugfixes:
-- Improves output of `AST.toMarkup(ast)` function so that extra whitespace is not inserted on repeated calls.
+- Improves output of `AST.toMarkup(ast)` function so that extra whitespace is not inserted on repeated calls.
# v5.0
Features:
+
- Adds `fullWidthSteps` option to the scroller, to make it easier for scroller components steps to take on wider designs
Bugfixes:
-- Component resolver is initialized at the start of compile process and when a compiler postprocessor plugin creates a new component in components directory, it won't be available till the next build and the current build fails with component not found error. (See: https://github.com/idyll-lang/idyll/pull/610)
+
+- Component resolver is initialized at the start of compile process and when a compiler postprocessor plugin creates a new component in components directory, it won't be available till the next build and the current build fails with component not found error. (See: https://github.com/idyll-lang/idyll/pull/610)
Breaking changes:
- Update header component default behavior to use styles (background color and text color) provided by themes
-- Fix the `package.json` options logic so any idyll option can be provided via package.json and
+- Fix the `package.json` options logic so any idyll option can be provided via package.json and
## v4.10
diff --git a/package.json b/package.json
index ef6820085..abed77302 100644
--- a/package.json
+++ b/package.json
@@ -7,7 +7,7 @@
},
"devDependencies": {
"husky": "^1.1.3",
- "lerna": "^2.0.0",
+ "lerna": "^2.11.0",
"prettier": "1.15.1",
"pretty-quick": "^1.8.0"
},
diff --git a/packages/idyll-cli/package.json b/packages/idyll-cli/package.json
index 345bca899..4e8e9892c 100644
--- a/packages/idyll-cli/package.json
+++ b/packages/idyll-cli/package.json
@@ -40,6 +40,7 @@
"bs-pretty-message": "^1.0.8",
"chalk": "^2.4.1",
"change-case": "^3.0.1",
+ "command-line-args": "^5.1.1",
"cross-spawn": "^6.0.5",
"csv-parse": "^4.8.2",
"debug": "^3.1.0",
diff --git a/packages/idyll-cli/src/index.js b/packages/idyll-cli/src/index.js
index a637fc8fc..40718631f 100755
--- a/packages/idyll-cli/src/index.js
+++ b/packages/idyll-cli/src/index.js
@@ -1,331 +1,396 @@
-const fs = require('fs');
-const { dirname, basename, extname, join } = require('path');
-const EventEmitter = require('events');
-const mkdirp = require('mkdirp');
-
-const pathBuilder = require('./path-builder');
-const configureNode = require('./node-config');
-const pipeline = require('./pipeline');
-const { ComponentResolver, DataResolver, CSSResolver } = require('./resolvers');
-
-const debug = require('debug')('idyll:cli');
-
-function createDirectories(paths) {
- mkdirp.sync(paths.OUTPUT_DIR);
- mkdirp.sync(paths.STATIC_OUTPUT_DIR);
- mkdirp.sync(paths.TMP_DIR);
-}
-
-const searchParentDirectories = packageDir => {
- while (true) {
- if (packageDir === join(packageDir, '..')) {
- break;
- }
-
- packageDir = join(packageDir, '..');
- const parentPackageFilePath = join(packageDir, 'package.json');
-
- const parentPackageFile = fs.existsSync(parentPackageFilePath)
- ? require(parentPackageFilePath)
- : {};
-
- if (parentPackageFile.idyll) {
- return parentPackageFile.idyll;
- }
- }
- return {};
-};
-
-const idyll = (options = {}, cb) => {
- const opts = Object.assign(
- {},
- {
- alias: {},
- watch: false,
- open: true,
- datasets: 'data',
- minify: true,
- ssr: true,
- components: 'components',
- static: 'static',
- staticOutputDir: 'static',
- defaultComponents: dirname(require.resolve('idyll-components')),
- layout: 'centered',
- theme: 'github',
- output: 'build',
- outputCSS: 'idyll_styles.css',
- outputJS: 'idyll_index.js',
- port: process.env.PORT || 3000,
- temp: '.idyll',
- template: join(__dirname, 'client', '_index.html'),
- transform: [],
- compiler: {},
- compileLibs: false
- },
- options
- );
-
- const paths = pathBuilder(opts);
- debug('Reading from paths:', paths);
-
- createDirectories(paths);
- configureNode(paths);
-
- const inputPackage = fs.existsSync(paths.PACKAGE_FILE)
- ? require(paths.PACKAGE_FILE)
- : {};
- const inputConfig = inputPackage.idyll || {};
-
- const parentInputConfig = searchParentDirectories(paths.INPUT_DIR);
- Object.assign(opts, parentInputConfig, inputConfig, options);
-
- // Resolve compiler plugins:
- if (opts.compiler.postProcessors) {
- opts.compiler.postProcessors = opts.compiler.postProcessors.map(
- processor => {
- try {
- return require(require.resolve(processor, {
- paths: [paths.INPUT_DIR]
- }));
- } catch (e) {
- console.log(e);
- console.warn('\n\nCould not find post-processor plugin: ', processor);
- }
- }
- );
- }
-
- // Resolve context:
- if (opts.context) {
- if (opts.context.indexOf('./') > -1) {
- opts.context = join(paths.INPUT_DIR, opts.context);
- }
- }
-
- let bs;
- let watchers;
-
- const createResolvers = () => {
- return new Map([
- ['components', new ComponentResolver(opts, paths)],
- ['css', new CSSResolver(opts, paths)],
- ['data', new DataResolver(opts, paths)]
- ]);
- };
-
- class IdyllInstance extends EventEmitter {
- getPaths() {
- return paths;
- }
-
- getOptions() {
- return opts;
- }
-
- build(src) {
- // Resolvers are recreated on each build, since new data dependencies might have been added.
- const resolvers = createResolvers();
-
- if (src) opts.inputString = src;
-
- debug('Starting the build');
- // Leaving the following timing statement in for backwards-compatibility.
- if (opts.debug) console.time('Build Time');
-
- pipeline
- .build(opts, paths, resolvers)
- .then(output => {
- debug('Build completed');
- // Leaving the following timing statement in for backwards-compatibility.
- if (opts.debug) console.timeEnd('Build Time');
- this.emit('update', output);
- })
- .then(() => {
- if (!bs && opts.watch && opts.inputFile) {
- bs = require('browser-sync').create();
- // any time an input files changes we will recompile .idl source
- // and write ast.json, components.js, and data.js to disk
- watchers = [
- bs.watch(paths.IDYLL_INPUT_FILE, { ignoreInitial: true }, () =>
- inst.build()
- ),
- // that will cause watchify to rebuild so we just watch the output bundle file
- // and reload when it is updated. Watch options are to prevent multiple change
- // events since the bundle file can be somewhat large
- bs.watch(
- paths.JS_OUTPUT_FILE,
- { awaitWriteFinish: { stabilityThreshold: 499 } },
- bs.reload
- ),
- // when CSS changes we reassemble and inject it
- bs.watch(paths.CSS_INPUT_FILE, { ignoreInitial: true }, () => {
- pipeline.updateCSS(paths, resolvers.get('css')).then(() => {
- bs.reload('styles.css');
- });
- }),
- // when any static files change we do a full rebuild.
- bs.watch(paths.STATIC_DIR, { ignoreInitial: true }, () =>
- inst.build()
- )
- ];
-
- // Each resolver is responsible for generating a list of directories to watch for
- // their corresponding data types.
- if (!opts.compiler.postProcessors) {
- resolvers.forEach((resolver, name) => {
- let watcher = bs.watch(
- resolver.getDirectories(),
- { ignoreInitial: true },
- () => {
- inst.build();
- }
- );
- watchers.push(watcher);
- });
- }
-
- bs.init({
- cors: true,
- logLevel: 'warn',
- logPrefix: 'Idyll',
- notify: false,
- server: [paths.OUTPUT_DIR],
- ui: false,
- port: opts.port,
- open: opts.open,
- plugins: [require('bs-pretty-message')]
- });
- }
- })
- .then(() => {
- this.emit('complete');
- })
- .catch(error => {
- // pass along errors if anyone is listening
- if (this.listenerCount('error')) {
- this.emit('error', error);
- } else {
- // otherwise dump to the console
- console.error(error);
- }
- bs &&
- bs.sockets &&
- bs.sockets.emit('fullscreen:message', {
- title: 'Error compiling Idyll project',
- body: error.toString()
- });
- });
- return this;
- }
-
- // Returns an array of the default components
- // Each element of the array is an object with keys 'name' and 'path'
- // 'name' is the file name of the component
- // 'path' is the absolute path to the component
- getComponents() {
- var components = [];
- var defaultCompsDir = this.getPaths().DEFAULT_COMPONENT_DIRS;
- var compsDir = this.getComponentsDirectory(); // grabs the `components` folder of their current directory
- var componentDirs = [defaultCompsDir, compsDir];
-
- componentDirs.forEach(dirs => {
- dirs.forEach(dir => {
- try {
- fs.statSync(dir);
- } catch (error) {
- // for when directory doesn't exist
- return;
- }
- fs.readdirSync(dir + '').forEach(file => {
- var compName = file.replace(/\.jsx?/g, '');
- if (compName !== 'index') {
- // avoid conflicts with index.js file
- components.push({
- name: compName,
- path: dir + '/' + file
- });
- }
- });
- });
- });
- return components;
- }
-
- // Returns the directory of the `components` folder
- // of this IdyllInstance
- // Note: this isn't guaranteed to exist
- // It just adds "component" to the directory of this idyll instance
- getComponentsDirectory() {
- return this.getPaths().COMPONENT_DIRS;
- }
-
- // Adds the given component (directory) to the components used
- // in this IdyllInstance
- // If there is already a component for the given componentPath,
- // it will be overwritten with the one from componentPath
- // If there is no components/ directory, then it will be created
- addComponent(componentPath) {
- const componentsDirectory = this.getComponentsDirectory();
- // We grab the name of the component, and put that in the components directory
- const componentFileName = basename(componentPath);
- // ensure components directory exists
- try {
- fs.statSync(componentsDirectory[0]);
- } catch (err) {
- fs.mkdirSync(componentsDirectory[0]);
- }
- fs.copyFileSync(
- componentPath,
- componentsDirectory[0] + '/' + componentFileName
- );
- }
-
- // Returns an array of the current datasets used in this IdyllInstance's data directory
- getDatasets() {
- var dataFolder = this.getPaths().DATA_DIR;
- var defaultData = [];
- fs.readdirSync(dataFolder).forEach(file => {
- var fileName = file;
- var datasetPath = dataFolder + '/' + file;
- var extension = extname(file);
- defaultData.push({
- name: fileName,
- path: datasetPath,
- extension: extension
- });
- });
- return defaultData;
- }
-
- // Adds a dataset to the current datasets used in this IdyllInstance
- // It will be added to the `data` directory of this IdyllInstance
- addDataset(datasetPath) {
- const datasetDirectory = this.getPaths().DATA_DIR;
- const datasetName = basename(datasetPath);
- try {
- fs.statSync(datasetDirectory);
- } catch (err) {
- fs.mkdirSync(datasetDirectory);
- }
- fs.copyFileSync(datasetPath, datasetDirectory + '/' + datasetName);
- }
-
- stopWatching() {
- if (watchers.length) {
- watchers.forEach(w => w.close());
- watchers = null;
- }
- if (bs) bs.exit();
- }
- }
-
- const inst = new IdyllInstance();
-
- return inst;
-};
-
-idyll.getVersion = () => {
- return require('../package.json').version;
-};
-
-module.exports = idyll;
+const fs = require('fs');
+const { dirname, basename, extname, join } = require('path');
+const EventEmitter = require('events');
+const mkdirp = require('mkdirp');
+const commandLineArgs = require('command-line-args');
+
+const pathBuilder = require('./path-builder');
+const configureNode = require('./node-config');
+const pipeline = require('./pipeline');
+const { ComponentResolver, DataResolver, CSSResolver } = require('./resolvers');
+
+const debug = require('debug')('idyll:cli');
+
+const optionDefinitions = [{ name: 'env', alias: 'e', type: String }];
+const commandLineOptions = commandLineArgs(optionDefinitions);
+
+function createDirectories(paths) {
+ mkdirp.sync(paths.OUTPUT_DIR);
+ mkdirp.sync(paths.STATIC_OUTPUT_DIR);
+ mkdirp.sync(paths.TMP_DIR);
+}
+
+const searchParentDirectories = packageDir => {
+ while (true) {
+ if (packageDir === join(packageDir, '..')) {
+ break;
+ }
+ packageDir = join(packageDir, '..');
+ const parentPackageFilePath = join(packageDir, 'package.json');
+
+ const parentPackageFile = fs.existsSync(parentPackageFilePath)
+ ? require(parentPackageFilePath)
+ : {};
+
+ if (parentPackageFile.idyll) {
+ return parentPackageFile;
+ }
+ }
+ return {};
+};
+
+function selectIdyllConfig(inputPackage, env) {
+ var hasMultipleConfigs = false; // for error handling later
+ if (inputPackage.idyll) {
+ // Check for an idyll env key if array found
+ if (Array.isArray(inputPackage.idyll)) {
+ if (env == null) {
+ return {
+ idyll: inputPackage.idyll[0][1],
+ hasMultipleConfigs: hasMultipleConfigs
+ };
+ } else {
+ for (var i in inputPackage.idyll) {
+ hasMultipleConfigs = true;
+ if (inputPackage.idyll[i][0] === env) {
+ return {
+ idyll: inputPackage.idyll[i][1],
+ hasMultipleConfigs: hasMultipleConfigs
+ };
+ }
+ }
+ throw Error(
+ 'No matching env found out of available options. Please verify your package.json file(s) have ' +
+ env
+ );
+ }
+ } else {
+ // env passed but package.json is in wrong format
+ if (env != null) {
+ throw Error('No env found matching ' + env);
+ }
+ return {
+ idyll: inputPackage.idyll,
+ hasMultipleConfigs: hasMultipleConfigs
+ };
+ }
+ }
+ return {
+ idyll: {},
+ hasMultipleConfigs: hasMultipleConfigs
+ };
+}
+
+const idyll = (options = {}, cb) => {
+ const opts = Object.assign(
+ {},
+ {
+ alias: {},
+ watch: false,
+ open: true,
+ datasets: 'data',
+ minify: true,
+ ssr: true,
+ components: 'components',
+ static: 'static',
+ staticOutputDir: 'static',
+ defaultComponents: dirname(require.resolve('idyll-components')),
+ layout: 'centered',
+ theme: 'github',
+ output: 'build',
+ outputCSS: 'idyll_styles.css',
+ outputJS: 'idyll_index.js',
+ port: process.env.PORT || 3000,
+ temp: '.idyll',
+ template: join(__dirname, 'client', '_index.html'),
+ transform: [],
+ compiler: {},
+ compileLibs: false,
+ env: commandLineOptions.env
+ },
+ options
+ );
+
+ const paths = pathBuilder(opts);
+ debug('Reading from paths:', paths);
+
+ createDirectories(paths);
+ configureNode(paths);
+
+ const inputPackage = fs.existsSync(paths.PACKAGE_FILE)
+ ? require(paths.PACKAGE_FILE)
+ : {};
+
+ if (
+ commandLineOptions.env !== options.env &&
+ (commandLineOptions.env !== undefined && options.env !== undefined)
+ ) {
+ //Should one supercede the other?
+ throw Error(
+ "Mismatch between Idyll env provided and command line arg. Please remove the Idyll({env='...',...} or the command line argument."
+ );
+ }
+
+ const env = commandLineOptions.env || options.env;
+ const inputConfig = selectIdyllConfig(inputPackage, env);
+ const parentInputConfig = selectIdyllConfig(
+ searchParentDirectories(paths.INPUT_DIR),
+ env
+ );
+ if (parentInputConfig.hasMultipleConfigs && !inputConfig.hasMultipleConfigs) {
+ throw Error(
+ 'Project root has multiple config options given but the local project does not. Please add envs to the local project and use the --env parameter or remove them from the top level package.'
+ );
+ }
+ Object.assign(opts, parentInputConfig.idyll, inputConfig.idyll, options);
+
+ // Resolve compiler plugins:
+ if (opts.compiler.postProcessors) {
+ opts.compiler.postProcessors = opts.compiler.postProcessors.map(
+ processor => {
+ try {
+ return require(require.resolve(processor, {
+ paths: [paths.INPUT_DIR]
+ }));
+ } catch (e) {
+ console.log(e);
+ console.warn('\n\nCould not find post-processor plugin: ', processor);
+ }
+ }
+ );
+ }
+
+ // Resolve context:
+ if (opts.context) {
+ if (opts.context.indexOf('./') > -1) {
+ opts.context = join(paths.INPUT_DIR, opts.context);
+ }
+ }
+
+ let bs;
+ let watchers;
+
+ const createResolvers = () => {
+ return new Map([
+ ['components', new ComponentResolver(opts, paths)],
+ ['css', new CSSResolver(opts, paths)],
+ ['data', new DataResolver(opts, paths)]
+ ]);
+ };
+
+ class IdyllInstance extends EventEmitter {
+ getPaths() {
+ return paths;
+ }
+
+ getOptions() {
+ return opts;
+ }
+
+ build(src) {
+ // Resolvers are recreated on each build, since new data dependencies might have been added.
+ const resolvers = createResolvers();
+
+ if (src) opts.inputString = src;
+
+ debug('Starting the build');
+ // Leaving the following timing statement in for backwards-compatibility.
+ if (opts.debug) console.time('Build Time');
+
+ pipeline
+ .build(opts, paths, resolvers)
+ .then(output => {
+ debug('Build completed');
+ // Leaving the following timing statement in for backwards-compatibility.
+ if (opts.debug) console.timeEnd('Build Time');
+ this.emit('update', output);
+ })
+ .then(() => {
+ if (!bs && opts.watch && opts.inputFile) {
+ bs = require('browser-sync').create();
+ // any time an input files changes we will recompile .idl source
+ // and write ast.json, components.js, and data.js to disk
+ watchers = [
+ bs.watch(paths.IDYLL_INPUT_FILE, { ignoreInitial: true }, () =>
+ inst.build()
+ ),
+ // that will cause watchify to rebuild so we just watch the output bundle file
+ // and reload when it is updated. Watch options are to prevent multiple change
+ // events since the bundle file can be somewhat large
+ bs.watch(
+ paths.JS_OUTPUT_FILE,
+ { awaitWriteFinish: { stabilityThreshold: 499 } },
+ bs.reload
+ ),
+ // when CSS changes we reassemble and inject it
+ bs.watch(paths.CSS_INPUT_FILE, { ignoreInitial: true }, () => {
+ pipeline.updateCSS(paths, resolvers.get('css')).then(() => {
+ bs.reload('styles.css');
+ });
+ }),
+ // when any static files change we do a full rebuild.
+ bs.watch(paths.STATIC_DIR, { ignoreInitial: true }, () =>
+ inst.build()
+ )
+ ];
+
+ // Each resolver is responsible for generating a list of directories to watch for
+ // their corresponding data types.
+ if (!opts.compiler.postProcessors) {
+ resolvers.forEach((resolver, name) => {
+ let watcher = bs.watch(
+ resolver.getDirectories(),
+ { ignoreInitial: true },
+ () => {
+ inst.build();
+ }
+ );
+ watchers.push(watcher);
+ });
+ }
+
+ bs.init({
+ cors: true,
+ logLevel: 'warn',
+ logPrefix: 'Idyll',
+ notify: false,
+ server: [paths.OUTPUT_DIR],
+ ui: false,
+ port: opts.port,
+ open: opts.open,
+ plugins: [require('bs-pretty-message')]
+ });
+ }
+ })
+ .then(() => {
+ this.emit('complete');
+ })
+ .catch(error => {
+ // pass along errors if anyone is listening
+ if (this.listenerCount('error')) {
+ this.emit('error', error);
+ } else {
+ // otherwise dump to the console
+ console.error(error);
+ }
+ bs &&
+ bs.sockets &&
+ bs.sockets.emit('fullscreen:message', {
+ title: 'Error compiling Idyll project',
+ body: error.toString()
+ });
+ });
+ return this;
+ }
+
+ // Returns an array of the default components
+ // Each element of the array is an object with keys 'name' and 'path'
+ // 'name' is the file name of the component
+ // 'path' is the absolute path to the component
+ getComponents() {
+ var components = [];
+ var defaultCompsDir = this.getPaths().DEFAULT_COMPONENT_DIRS;
+ var compsDir = this.getComponentsDirectory(); // grabs the `components` folder of their current directory
+ var componentDirs = [defaultCompsDir, compsDir];
+
+ componentDirs.forEach(dirs => {
+ dirs.forEach(dir => {
+ try {
+ fs.statSync(dir);
+ } catch (error) {
+ // for when directory doesn't exist
+ return;
+ }
+ fs.readdirSync(dir + '').forEach(file => {
+ var compName = file.replace(/\.jsx?/g, '');
+ if (compName !== 'index') {
+ // avoid conflicts with index.js file
+ components.push({
+ name: compName,
+ path: dir + '/' + file
+ });
+ }
+ });
+ });
+ });
+ return components;
+ }
+
+ // Returns the directory of the `components` folder
+ // of this IdyllInstance
+ // Note: this isn't guaranteed to exist
+ // It just adds "component" to the directory of this idyll instance
+ getComponentsDirectory() {
+ return this.getPaths().COMPONENT_DIRS;
+ }
+
+ // Adds the given component (directory) to the components used
+ // in this IdyllInstance
+ // If there is already a component for the given componentPath,
+ // it will be overwritten with the one from componentPath
+ // If there is no components/ directory, then it will be created
+ addComponent(componentPath) {
+ const componentsDirectory = this.getComponentsDirectory();
+ // We grab the name of the component, and put that in the components directory
+ const componentFileName = basename(componentPath);
+ // ensure components directory exists
+ try {
+ fs.statSync(componentsDirectory[0]);
+ } catch (err) {
+ fs.mkdirSync(componentsDirectory[0]);
+ }
+ fs.copyFileSync(
+ componentPath,
+ componentsDirectory[0] + '/' + componentFileName
+ );
+ }
+
+ // Returns an array of the current datasets used in this IdyllInstance's data directory
+ getDatasets() {
+ var dataFolder = this.getPaths().DATA_DIR;
+ var defaultData = [];
+ fs.readdirSync(dataFolder).forEach(file => {
+ var fileName = file;
+ var datasetPath = dataFolder + '/' + file;
+ var extension = extname(file);
+ defaultData.push({
+ name: fileName,
+ path: datasetPath,
+ extension: extension
+ });
+ });
+ return defaultData;
+ }
+
+ // Adds a dataset to the current datasets used in this IdyllInstance
+ // It will be added to the `data` directory of this IdyllInstance
+ addDataset(datasetPath) {
+ const datasetDirectory = this.getPaths().DATA_DIR;
+ const datasetName = basename(datasetPath);
+ try {
+ fs.statSync(datasetDirectory);
+ } catch (err) {
+ fs.mkdirSync(datasetDirectory);
+ }
+ fs.copyFileSync(datasetPath, datasetDirectory + '/' + datasetName);
+ }
+
+ stopWatching() {
+ if (watchers.length) {
+ watchers.forEach(w => w.close());
+ watchers = null;
+ }
+ if (bs) bs.exit();
+ }
+ }
+
+ const inst = new IdyllInstance();
+
+ return inst;
+};
+
+idyll.getVersion = () => {
+ return require('../package.json').version;
+};
+
+module.exports = idyll;
diff --git a/packages/idyll-cli/test/env-options/outer-project/components/CapitalPascal.js b/packages/idyll-cli/test/env-options/outer-project/components/CapitalPascal.js
new file mode 100644
index 000000000..d5861b1c7
--- /dev/null
+++ b/packages/idyll-cli/test/env-options/outer-project/components/CapitalPascal.js
@@ -0,0 +1,11 @@
+const React = require('react');
+
+class PascalComponent extends React.PureComponent {
+ render() {
+ const { hasError, updateProps, idyll, ...props } = this.props;
+
+ return
This is a custom component
;
+ }
+}
+
+module.exports = PascalComponent;
diff --git a/packages/idyll-cli/test/env-options/outer-project/components/custom-component.js b/packages/idyll-cli/test/env-options/outer-project/components/custom-component.js
new file mode 100644
index 000000000..39d111ab6
--- /dev/null
+++ b/packages/idyll-cli/test/env-options/outer-project/components/custom-component.js
@@ -0,0 +1,17 @@
+const React = require('react');
+
+class CustomComponent extends React.PureComponent {
+ render() {
+ const { hasError, updateProps, idyll, ...props } = this.props;
+ return This is a custom component
;
+ }
+}
+
+module.exports = CustomComponent;
+
+module.exports.IndexedComponent = class extends React.PureComponent {
+ render() {
+ const { hasError, updateProps, idyll, ...props } = this.props;
+ return This is another custom component
;
+ }
+};
diff --git a/packages/idyll-cli/test/env-options/outer-project/components/functional-component.js b/packages/idyll-cli/test/env-options/outer-project/components/functional-component.js
new file mode 100644
index 000000000..01991bcf4
--- /dev/null
+++ b/packages/idyll-cli/test/env-options/outer-project/components/functional-component.js
@@ -0,0 +1,5 @@
+const React = require('react');
+
+module.exports = () => {
+ return Let's put the fun back in functional!
;
+};
diff --git a/packages/idyll-cli/test/env-options/outer-project/components/functional-default-component.js b/packages/idyll-cli/test/env-options/outer-project/components/functional-default-component.js
new file mode 100644
index 000000000..47bdf47fe
--- /dev/null
+++ b/packages/idyll-cli/test/env-options/outer-project/components/functional-default-component.js
@@ -0,0 +1,9 @@
+const React = require('react');
+
+export default () => (
+
+ This is some text
+ And a button
+ Then some more text
+
+);
diff --git a/packages/idyll-cli/test/env-options/outer-project/custom-theme.css b/packages/idyll-cli/test/env-options/outer-project/custom-theme.css
new file mode 100644
index 000000000..ae41890f6
--- /dev/null
+++ b/packages/idyll-cli/test/env-options/outer-project/custom-theme.css
@@ -0,0 +1,721 @@
+@font-face {
+ font-family: octicons-link;
+ src: url(data:font/woff;charset=utf-8;base64,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)
+ format('woff');
+}
+
+.idyll-root {
+ -ms-text-size-adjust: 100%;
+ -webkit-text-size-adjust: 100%;
+ line-height: 1.5;
+ color: #24292e;
+ font-family: -apple-system, system-ui, BlinkMacSystemFont, 'Segoe UI',
+ Helvetica, Arial, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji',
+ 'Segoe UI Symbol';
+ font-size: 16px;
+ line-height: 1.5;
+ word-wrap: break-word;
+}
+
+.idyll-root .pl-c {
+ color: #969896;
+}
+
+.idyll-root .pl-c1,
+.idyll-root .pl-s .pl-v {
+ color: #0086b3;
+}
+
+.idyll-root .pl-e,
+.idyll-root .pl-en {
+ color: #795da3;
+}
+
+.idyll-root .pl-smi,
+.idyll-root .pl-s .pl-s1 {
+ color: #333;
+}
+
+.idyll-root .pl-ent {
+ color: #63a35c;
+}
+
+.idyll-root .pl-k {
+ color: #a71d5d;
+}
+
+.idyll-root .pl-s,
+.idyll-root .pl-pds,
+.idyll-root .pl-s .pl-pse .pl-s1,
+.idyll-root .pl-sr,
+.idyll-root .pl-sr .pl-cce,
+.idyll-root .pl-sr .pl-sre,
+.idyll-root .pl-sr .pl-sra {
+ color: #183691;
+}
+
+.idyll-root .pl-v,
+.idyll-root .pl-smw {
+ color: #ed6a43;
+}
+
+.idyll-root .pl-bu {
+ color: #b52a1d;
+}
+
+.idyll-root .pl-ii {
+ color: #f8f8f8;
+ background-color: #b52a1d;
+}
+
+.idyll-root .pl-c2 {
+ color: #f8f8f8;
+ background-color: #b52a1d;
+}
+
+.idyll-root .pl-c2::before {
+ content: '^M';
+}
+
+.idyll-root .pl-sr .pl-cce {
+ font-weight: bold;
+ color: #63a35c;
+}
+
+.idyll-root .pl-ml {
+ color: #693a17;
+}
+
+.idyll-root .pl-mh,
+.idyll-root .pl-mh .pl-en,
+.idyll-root .pl-ms {
+ font-weight: bold;
+ color: #1d3e81;
+}
+
+.idyll-root .pl-mq {
+ color: #008080;
+}
+
+.idyll-root .pl-mi {
+ font-style: italic;
+ color: #333;
+}
+
+.idyll-root .pl-mb {
+ font-weight: bold;
+ color: #333;
+}
+
+.idyll-root .pl-md {
+ color: #bd2c00;
+ background-color: #ffecec;
+}
+
+.idyll-root .pl-mi1 {
+ color: #55a532;
+ background-color: #eaffea;
+}
+
+.idyll-root .pl-mc {
+ color: #ef9700;
+ background-color: #ffe3b4;
+}
+
+.idyll-root .pl-mi2 {
+ color: #d8d8d8;
+ background-color: #808080;
+}
+
+.idyll-root .pl-mdr {
+ font-weight: bold;
+ color: #795da3;
+}
+
+.idyll-root .pl-mo {
+ color: #1d3e81;
+}
+
+.idyll-root .pl-ba {
+ color: #595e62;
+}
+
+.idyll-root .pl-sg {
+ color: #c0c0c0;
+}
+
+.idyll-root .pl-corl {
+ text-decoration: underline;
+ color: #183691;
+}
+
+.idyll-root .octicon {
+ display: inline-block;
+ vertical-align: text-top;
+ fill: currentColor;
+}
+
+.idyll-root a {
+ background-color: transparent;
+ -webkit-text-decoration-skip: objects;
+}
+
+.idyll-root a:active,
+.idyll-root a:hover {
+ outline-width: 0;
+}
+
+.idyll-root strong {
+ font-weight: inherit;
+}
+
+.idyll-root strong {
+ font-weight: bolder;
+}
+
+.idyll-root h1 {
+ font-size: 2em;
+ margin: 0.67em 0;
+}
+
+.idyll-root img {
+ border-style: none;
+}
+
+.idyll-root svg:not(:root) {
+ overflow: hidden;
+}
+
+.idyll-root code,
+.idyll-root kbd,
+.idyll-root pre {
+ font-family: monospace, monospace;
+ font-size: 1em;
+}
+
+.idyll-root hr {
+ box-sizing: content-box;
+ height: 0;
+ overflow: visible;
+}
+
+.idyll-root input {
+ font: inherit;
+ margin: 10px 10px 20px 0;
+}
+
+.idyll-root input {
+ overflow: visible;
+}
+
+.idyll-root [type='checkbox'] {
+ box-sizing: border-box;
+ padding: 0;
+}
+
+.idyll-root * {
+ box-sizing: border-box;
+}
+
+.idyll-root input {
+ font-family: inherit;
+ font-size: inherit;
+ line-height: inherit;
+}
+
+.idyll-root a {
+ color: #0366d6;
+ text-decoration: none;
+}
+
+.idyll-root a:hover {
+ text-decoration: underline;
+}
+
+.idyll-root strong {
+ font-weight: 600;
+}
+
+.idyll-root hr {
+ height: 0;
+ margin: 15px 0;
+ overflow: hidden;
+ background: transparent;
+ border: 0;
+ border-bottom: 1px solid #dfe2e5;
+}
+
+.idyll-root hr::before {
+ display: table;
+ content: '';
+}
+
+.idyll-root hr::after {
+ display: table;
+ clear: both;
+ content: '';
+}
+
+.idyll-root table {
+ border-spacing: 0;
+ border-collapse: collapse;
+}
+
+.idyll-root td,
+.idyll-root th {
+ padding: 0;
+}
+
+.idyll-root h1,
+.idyll-root h2,
+.idyll-root h3,
+.idyll-root h4,
+.idyll-root h5,
+.idyll-root h6 {
+ margin-top: 0;
+ margin-bottom: 0;
+}
+
+.idyll-root h1 {
+ font-size: 32px;
+ font-weight: 600;
+}
+
+.idyll-root h2 {
+ font-size: 24px;
+ font-weight: 600;
+}
+
+.idyll-root h3 {
+ font-size: 20px;
+ font-weight: 600;
+}
+
+.idyll-root h4 {
+ font-size: 16px;
+ font-weight: 600;
+}
+
+.idyll-root h5 {
+ font-size: 14px;
+ font-weight: 600;
+}
+
+.idyll-root h6 {
+ font-size: 12px;
+ font-weight: 600;
+}
+
+.idyll-root p {
+ margin-top: 0;
+ margin-bottom: 10px;
+}
+
+.idyll-root blockquote {
+ margin: 0;
+}
+
+.idyll-root ul,
+.idyll-root ol {
+ padding-left: 0;
+ margin-top: 0;
+ margin-bottom: 0;
+}
+
+.idyll-root ol ol,
+.idyll-root ul ol {
+ list-style-type: lower-roman;
+}
+
+.idyll-root ul ul ol,
+.idyll-root ul ol ol,
+.idyll-root ol ul ol,
+.idyll-root ol ol ol {
+ list-style-type: lower-alpha;
+}
+
+.idyll-root dd {
+ margin-left: 0;
+}
+
+.idyll-root code {
+ font-family: 'SFMono-Regular', Consolas, 'Liberation Mono', Menlo, Courier,
+ monospace;
+ font-size: 12px;
+}
+
+.idyll-root pre {
+ margin-top: 0;
+ margin-bottom: 0;
+ font: 12px 'SFMono-Regular', Consolas, 'Liberation Mono', Menlo, Courier,
+ monospace;
+}
+
+.idyll-root .octicon {
+ vertical-align: text-bottom;
+}
+
+.idyll-root .pl-0 {
+ padding-left: 0 !important;
+}
+
+.idyll-root .pl-1 {
+ padding-left: 4px !important;
+}
+
+.idyll-root .pl-2 {
+ padding-left: 8px !important;
+}
+
+.idyll-root .pl-3 {
+ padding-left: 16px !important;
+}
+
+.idyll-root .pl-4 {
+ padding-left: 24px !important;
+}
+
+.idyll-root .pl-5 {
+ padding-left: 32px !important;
+}
+
+.idyll-root .pl-6 {
+ padding-left: 40px !important;
+}
+
+.idyll-root::before {
+ display: table;
+ content: '';
+}
+
+.idyll-root::after {
+ display: table;
+ clear: both;
+ content: '';
+}
+
+.idyll-root > *:first-child {
+ margin-top: 0 !important;
+}
+
+.idyll-root > *:last-child {
+ margin-bottom: 0 !important;
+}
+
+.idyll-root a:not([href]) {
+ color: inherit;
+ text-decoration: none;
+}
+
+.idyll-root .anchor {
+ float: left;
+ padding-right: 4px;
+ margin-left: -20px;
+ line-height: 1;
+}
+
+.idyll-root .anchor:focus {
+ outline: none;
+}
+
+.idyll-root p,
+.idyll-root blockquote,
+.idyll-root ul,
+.idyll-root ol,
+.idyll-root dl,
+.idyll-root table,
+.idyll-root pre {
+ margin-top: 0;
+ margin-bottom: 16px;
+}
+
+.idyll-root hr {
+ height: 0.25em;
+ padding: 0;
+ margin: 24px 0;
+ background-color: #e1e4e8;
+ border: 0;
+}
+
+.idyll-root blockquote {
+ padding: 0 1em;
+ color: #6a737d;
+ border-left: 0.25em solid #dfe2e5;
+}
+
+.idyll-root blockquote > :first-child {
+ margin-top: 0;
+}
+
+.idyll-root blockquote > :last-child {
+ margin-bottom: 0;
+}
+
+.idyll-root kbd {
+ display: inline-block;
+ padding: 3px 5px;
+ font-size: 11px;
+ line-height: 10px;
+ color: #444d56;
+ vertical-align: middle;
+ background-color: #fafbfc;
+ border: solid 1px #c6cbd1;
+ border-bottom-color: #959da5;
+ border-radius: 3px;
+ box-shadow: inset 0 -1px 0 #959da5;
+}
+
+.idyll-root h1,
+.idyll-root h2,
+.idyll-root h3,
+.idyll-root h4,
+.idyll-root h5,
+.idyll-root h6 {
+ margin-top: 24px;
+ margin-bottom: 16px;
+ font-weight: 600;
+ line-height: 1.25;
+}
+
+.idyll-root h1 .octicon-link,
+.idyll-root h2 .octicon-link,
+.idyll-root h3 .octicon-link,
+.idyll-root h4 .octicon-link,
+.idyll-root h5 .octicon-link,
+.idyll-root h6 .octicon-link {
+ color: #1b1f23;
+ vertical-align: middle;
+ visibility: hidden;
+}
+
+.idyll-root h1:hover .anchor,
+.idyll-root h2:hover .anchor,
+.idyll-root h3:hover .anchor,
+.idyll-root h4:hover .anchor,
+.idyll-root h5:hover .anchor,
+.idyll-root h6:hover .anchor {
+ text-decoration: none;
+}
+
+.idyll-root h1:hover .anchor .octicon-link,
+.idyll-root h2:hover .anchor .octicon-link,
+.idyll-root h3:hover .anchor .octicon-link,
+.idyll-root h4:hover .anchor .octicon-link,
+.idyll-root h5:hover .anchor .octicon-link,
+.idyll-root h6:hover .anchor .octicon-link {
+ visibility: visible;
+}
+
+.idyll-root h1 {
+ padding-bottom: 0.3em;
+ font-size: 2em;
+ border-bottom: 1px solid #eaecef;
+}
+
+.idyll-root h2 {
+ padding-bottom: 0.3em;
+ font-size: 1.5em;
+ border-bottom: 1px solid #eaecef;
+}
+
+.idyll-root h3 {
+ font-size: 1.25em;
+}
+
+.idyll-root h4 {
+ font-size: 1em;
+}
+
+.idyll-root h5 {
+ font-size: 0.875em;
+}
+
+.idyll-root h6 {
+ font-size: 0.85em;
+ color: #6a737d;
+}
+
+.idyll-root h1.hed,
+.idyll-root h2.dek {
+ border-bottom: none;
+ padding-bottom: 0;
+ margin-top: 12px;
+}
+
+.idyll-root ul,
+.idyll-root ol {
+ padding-left: 2em;
+}
+
+.idyll-root ul ul,
+.idyll-root ul ol,
+.idyll-root ol ol,
+.idyll-root ol ul {
+ margin-top: 0;
+ margin-bottom: 0;
+}
+
+.idyll-root li > p {
+ margin-top: 16px;
+}
+
+.idyll-root li + li {
+ margin-top: 0.25em;
+}
+
+.idyll-root dl {
+ padding: 0;
+}
+
+.idyll-root dl dt {
+ padding: 0;
+ margin-top: 16px;
+ font-size: 1em;
+ font-style: italic;
+ font-weight: 600;
+}
+
+.idyll-root dl dd {
+ padding: 0 16px;
+ margin-bottom: 16px;
+}
+
+.idyll-root table {
+ display: block;
+ width: 100%;
+ overflow: auto;
+}
+
+.idyll-root table th {
+ font-weight: 600;
+}
+
+.idyll-root table th,
+.idyll-root table td {
+ padding: 6px 13px;
+ border: 1px solid #dfe2e5;
+}
+
+.idyll-root table tr {
+ background-color: #fff;
+ border-top: 1px solid #c6cbd1;
+}
+
+.idyll-root table tr:nth-child(2n) {
+ background-color: #f6f8fa;
+}
+
+.idyll-root img {
+ max-width: 100%;
+ box-sizing: content-box;
+ background-color: #fff;
+}
+
+.idyll-root code {
+ padding: 0;
+ padding-top: 0.2em;
+ padding-bottom: 0.2em;
+ margin: 0;
+ font-size: 85%;
+ background-color: rgba(27, 31, 35, 0.05);
+ border-radius: 3px;
+}
+
+.idyll-root code::before,
+.idyll-root code::after {
+ letter-spacing: -0.2em;
+ content: '\00a0';
+}
+
+.idyll-root pre {
+ word-wrap: normal;
+}
+
+.idyll-root pre > code {
+ padding: 0;
+ margin: 0;
+ font-size: 100%;
+ word-break: normal;
+ white-space: pre;
+ background: transparent;
+ border: 0;
+}
+
+.idyll-root .highlight {
+ margin-bottom: 16px;
+}
+
+.idyll-root .highlight pre {
+ margin-bottom: 0;
+ word-break: normal;
+}
+
+.idyll-root .highlight pre,
+.idyll-root pre {
+ padding: 16px;
+ overflow: auto;
+ font-size: 85%;
+ line-height: 1.45;
+ background-color: #f6f8fa;
+ border-radius: 3px;
+}
+
+.idyll-root pre code {
+ display: inline;
+ max-width: auto;
+ padding: 0;
+ margin: 0;
+ overflow: visible;
+ line-height: inherit;
+ word-wrap: normal;
+ background-color: transparent;
+ border: 0;
+}
+
+.idyll-root pre code::before,
+.idyll-root pre code::after {
+ content: normal;
+}
+
+.idyll-root .full-commit .btn-outline:not(:disabled):hover {
+ color: #005cc5;
+ border-color: #005cc5;
+}
+
+.idyll-root kbd {
+ display: inline-block;
+ padding: 3px 5px;
+ font: 11px 'SFMono-Regular', Consolas, 'Liberation Mono', Menlo, Courier,
+ monospace;
+ line-height: 10px;
+ color: #444d56;
+ vertical-align: middle;
+ background-color: #fcfcfc;
+ border: solid 1px #c6cbd1;
+ border-bottom-color: #959da5;
+ border-radius: 3px;
+ box-shadow: inset 0 -1px 0 #959da5;
+}
+
+.idyll-root :checked + .radio-label {
+ position: relative;
+ z-index: 1;
+ border-color: #0366d6;
+}
+
+.idyll-root .task-list-item {
+ list-style-type: none;
+}
+
+.idyll-root .task-list-item + .task-list-item {
+ margin-top: 3px;
+}
+
+.idyll-root .task-list-item input {
+ margin: 0 0.2em 0.25em -1.6em;
+ vertical-align: middle;
+}
+
+.idyll-root hr {
+ border-bottom-color: #eee;
+}
diff --git a/packages/idyll-cli/test/env-options/outer-project/data/example-data.json b/packages/idyll-cli/test/env-options/outer-project/data/example-data.json
new file mode 100644
index 000000000..070f8e68e
--- /dev/null
+++ b/packages/idyll-cli/test/env-options/outer-project/data/example-data.json
@@ -0,0 +1,10 @@
+[
+ {
+ "x": 0,
+ "y": 0
+ },
+ {
+ "x": 1,
+ "y": 1
+ }
+]
diff --git a/packages/idyll-cli/test/env-options/outer-project/data/example-file.csv b/packages/idyll-cli/test/env-options/outer-project/data/example-file.csv
new file mode 100644
index 000000000..e5726765b
--- /dev/null
+++ b/packages/idyll-cli/test/env-options/outer-project/data/example-file.csv
@@ -0,0 +1,3 @@
+"x","y"
+0,0
+1,1
\ No newline at end of file
diff --git a/packages/idyll-cli/test/env-options/outer-project/index.idl b/packages/idyll-cli/test/env-options/outer-project/index.idl
new file mode 100644
index 000000000..b0992ba94
--- /dev/null
+++ b/packages/idyll-cli/test/env-options/outer-project/index.idl
@@ -0,0 +1,58 @@
+[meta title:"Page Title" description:"Short description of your project" /]
+
+[Header
+ title:"Welcome to Idyll"
+ subtitle:"Open index.idl to start writing"
+ author:"Your Name Here"
+ authorLink:"https://idyll-lang.github.io" /]
+
+
+This is an Idyll file. Write text
+as you please in here. To add interactivity,
+you can add different components to the text.
+
+[data name:"myData" source:"example-data.json" /]
+[data name:"myCSVData" source:"example-file.csv" /]
+
+[Table data:myData /]
+
+[Table data:myCSVData /]
+
+Here is how you can use a variable:
+
+[var name:"exampleVar" value:5 /]
+
+[Range min:0 max:10 value:exampleVar /]
+[Display value:exampleVar /]
+
+```js
+var code = true;
+```
+
+And here is a custom component:
+
+[CustomComponent /]
+
+You can use standard html tags if a
+component with the same name
+doesn't exist.
+
+[ReactSimplePieChart
+ slices:`[{
+ color: '#7b3af5',
+ value: 0.1,
+ }, {
+ color: '#EAE7D6',
+ value: 0.9, },
+ ]` /]
+
+[PackageJsonComponentTest /]
+
+This adds support for indexed components: [CustomComponent.IndexedComponent /]
+
+[FunctionalComponent /]
+
+[FunctionalDefaultComponent /]
+
+
+[CapitalPascal /]
diff --git a/packages/idyll-cli/test/env-options/outer-project/inner-project/package.json b/packages/idyll-cli/test/env-options/outer-project/inner-project/package.json
new file mode 100644
index 000000000..ebc6062fd
--- /dev/null
+++ b/packages/idyll-cli/test/env-options/outer-project/inner-project/package.json
@@ -0,0 +1,38 @@
+{
+ "name": "test-project-inner",
+ "version": "1.0.0",
+ "scripts": {
+ "start": "idyll index.idl --watch --css styles.css --layout centered --theme github --spellcheck"
+ },
+ "idyll": [
+ [
+ "default-env",
+ {
+ "layout": "none"
+ }
+ ],
+ [
+ "my-env",
+ {
+ "alias": {
+ "PackageJsonComponentTest": "CustomComponent"
+ },
+ "layout": "none"
+ }
+ ],
+ [
+ "inner-env",
+ {
+ "alias": {
+ "PackageJsonComponentTest": "CustomComponent"
+ },
+ "layout": "blog"
+ }
+ ]
+ ],
+ "dependencies": {
+ "idyll-component": "^1.1.0",
+ "react-simple-pie-chart": "^0.4.1"
+ },
+ "devDependencies": {}
+}
diff --git a/packages/idyll-cli/test/env-options/outer-project/package.json b/packages/idyll-cli/test/env-options/outer-project/package.json
new file mode 100644
index 000000000..6129aa198
--- /dev/null
+++ b/packages/idyll-cli/test/env-options/outer-project/package.json
@@ -0,0 +1,32 @@
+{
+ "name": "test-project",
+ "version": "1.0.0",
+ "scripts": {
+ "start": "idyll index.idl --watch --css styles.css --layout centered --theme github --spellcheck"
+ },
+ "idyll": [
+ ["default-env",
+ {
+ "layout": "blog"
+ }],
+ ["my-env",
+ {
+ "alias": {
+ "PackageJsonComponentTest": "CustomComponent"
+ },
+ "layout": "none"
+ }],
+ ["outer-env",
+ {
+ "alias": {
+ "PackageJsonComponentTest": "CustomComponent"
+ },
+ "layout": "centered"
+ }]
+ ],
+ "dependencies": {
+ "idyll-component": "^1.1.0",
+ "react-simple-pie-chart": "^0.4.1"
+ },
+ "devDependencies": {}
+}
diff --git a/packages/idyll-cli/test/env-options/outer-project/static/favicon.ico b/packages/idyll-cli/test/env-options/outer-project/static/favicon.ico
new file mode 100755
index 000000000..7031685a9
Binary files /dev/null and b/packages/idyll-cli/test/env-options/outer-project/static/favicon.ico differ
diff --git a/packages/idyll-cli/test/env-options/outer-project/styles.css b/packages/idyll-cli/test/env-options/outer-project/styles.css
new file mode 100644
index 000000000..710c588e5
--- /dev/null
+++ b/packages/idyll-cli/test/env-options/outer-project/styles.css
@@ -0,0 +1,13 @@
+@import url('https://fonts.googleapis.com/css?family=Archivo+Black|Fira+Mono:400,500,700|Source+Sans+Pro:300,300i,400,400i,600,600i,700,700i');
+
+body {
+ font-family: 'Source Sans Pro', sans-serif;
+}
+
+.hed {
+ font-family: 'Archivo Black', sans-serif;
+}
+
+.byline {
+ font-family: 'Fira Mono', monospace;
+}
diff --git a/packages/idyll-cli/test/env-options/test.js b/packages/idyll-cli/test/env-options/test.js
new file mode 100644
index 000000000..30f99fbff
--- /dev/null
+++ b/packages/idyll-cli/test/env-options/test.js
@@ -0,0 +1,125 @@
+jasmine.DEFAULT_TIMEOUT_INTERVAL = 30000; // 30 second timeout
+
+const Idyll = require('../../src');
+const fs = require('fs');
+const { join, resolve, dirname } = require('path');
+
+const getFilenames = dir => {
+ return fs.readdirSync(dir).filter(f => f !== '.DS_Store');
+};
+
+const dirToHash = dir => {
+ return getFilenames(dir).reduce((acc, val) => {
+ let fullPath = join(dir, val);
+
+ if (fs.statSync(fullPath).isFile()) {
+ acc[val] = fs.readFileSync(fullPath, 'utf8');
+ } else {
+ acc[val] = dirToHash(fullPath);
+ }
+
+ return acc;
+ }, {});
+};
+
+const PROJECT_DIR = join(__dirname, 'outer-project', 'inner-project');
+
+const PROJECT_BUILD_DIR = join(PROJECT_DIR, 'build');
+
+test('no env provided', () => {
+ const idyll = Idyll({
+ inputFile: join(PROJECT_DIR, 'index.idl'),
+ output: PROJECT_BUILD_DIR,
+ htmlTemplate: join(PROJECT_DIR, '_index.html'),
+ components: join(PROJECT_DIR, 'components'),
+ datasets: join(PROJECT_DIR, 'data'),
+ theme: join(PROJECT_DIR, 'custom-theme.css'),
+ css: join(PROJECT_DIR, 'styles.css'),
+ googleFonts: ['Hanalei Fill'],
+ favicon: 'static/favicon.ico',
+ compiler: {
+ spellcheck: false
+ },
+ minify: false
+ });
+
+ expect(idyll.getOptions()).toEqual({
+ alias: {},
+ compileLibs: false,
+ compiler: { spellcheck: false },
+ components: join(PROJECT_DIR, 'components'),
+ css: join(PROJECT_DIR, 'styles.css'),
+ datasets: join(PROJECT_DIR, 'data'),
+ env: undefined,
+ defaultComponents: dirname(require.resolve('idyll-components')),
+ favicon: 'static/favicon.ico',
+ googleFonts: ['Hanalei Fill'],
+ htmlTemplate: join(PROJECT_DIR, '_index.html'),
+ inputFile: join(PROJECT_DIR, 'index.idl'),
+ layout: 'none',
+ minify: false,
+ open: true,
+ output: join(PROJECT_DIR, 'build'),
+ outputCSS: 'idyll_styles.css',
+ outputJS: 'idyll_index.js',
+ port: 3000,
+ ssr: true,
+ static: 'static',
+ staticOutputDir: "static",
+ temp: '.idyll',
+ template: resolve(join(__dirname, '/../../src/client/_index.html')),
+ theme: join(PROJECT_DIR, 'custom-theme.css'),
+ transform: [],
+ watch: false
+ });
+});
+
+test('my-env provided', () => {
+ const idyll = Idyll({
+ inputFile: join(PROJECT_DIR, 'index.idl'),
+ output: PROJECT_BUILD_DIR,
+ htmlTemplate: join(PROJECT_DIR, '_index.html'),
+ components: join(PROJECT_DIR, 'components'),
+ datasets: join(PROJECT_DIR, 'data'),
+ theme: join(PROJECT_DIR, 'custom-theme.css'),
+ css: join(PROJECT_DIR, 'styles.css'),
+ googleFonts: ['Hanalei Fill'],
+ favicon: 'static/favicon.ico',
+ compiler: {
+ spellcheck: false
+ },
+ minify: false,
+ env: 'my-env'
+ });
+
+ expect(idyll.getOptions()).toEqual({
+ env: 'my-env',
+ alias: { PackageJsonComponentTest: 'CustomComponent' },
+ compileLibs: false,
+ compiler: { spellcheck: false },
+ components: join(PROJECT_DIR, 'components'),
+ css: join(PROJECT_DIR, 'styles.css'),
+ datasets: join(PROJECT_DIR, 'data'),
+ env: 'my-env',
+ defaultComponents: dirname(require.resolve('idyll-components')),
+ favicon: 'static/favicon.ico',
+ googleFonts: ['Hanalei Fill'],
+ htmlTemplate: join(PROJECT_DIR, '_index.html'),
+ inputFile: join(PROJECT_DIR, 'index.idl'),
+ layout: 'none',
+ minify: false,
+ open: true,
+ output: join(PROJECT_DIR, 'build'),
+ outputCSS: 'idyll_styles.css',
+ outputJS: 'idyll_index.js',
+ port: 3000,
+ ssr: true,
+ static: 'static',
+ staticOutputDir: "static",
+ temp: '.idyll',
+ template: resolve(join(__dirname, '/../../src/client/_index.html')),
+ theme: join(PROJECT_DIR, 'custom-theme.css'),
+ transform: [],
+ watch: false
+ });
+});
diff --git a/packages/idyll-docs/pages/docs/configuration-and-styles.js b/packages/idyll-docs/pages/docs/configuration-and-styles.js
index 41382ed52..0f8fbc6c7 100644
--- a/packages/idyll-docs/pages/docs/configuration-and-styles.js
+++ b/packages/idyll-docs/pages/docs/configuration-and-styles.js
@@ -199,6 +199,40 @@ export default ({ url }) => (
You can also compile an input string directly instead of a file:
{ExampleCodeB}
+
+ Selecting Idyll options using the env parameter
+
+ Oftentimes it can be helpful to change your options based on where You
+ are running Idyll. Idyll supports an env paramter you can use either by
+ API or with the command-line with \`--env my-env\`
+
+
+ To use the env parameter you need to change the format of package.json
+ to support multiple options.
+
+ package.json example
+
+ {`"idyll": [
+ "my-env", {
+ "layout": "blog",
+ "theme": "my-custom-theme.css",
+ "components": ["./components/", "../some-other-components/"],
+ "googleFonts": ["Hanalei Fill"],
+ "favicon": "static/favicon.ico",
+ "alias": {
+ "VL": "IdyllVegaLite"
+ }],
+ [
+ "prod-env", {
+ "theme": "my-custom-prod-theme.css",
+ }]
+ ]}`}
+
+
+ If no env is supplied and package.json is in list format, the first env
+ will be used by default.
+
+
Continue to the next section to learn about{' '}
diff --git a/yarn.lock b/yarn.lock
index 8cd5c7bce..717a7a6ef 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -3570,7 +3570,7 @@ command-join@^2.0.0:
dependencies:
"@improved/node" "^1.0.0"
-command-line-args@^5.0.0:
+command-line-args@^5.0.0, command-line-args@^5.1.1:
version "5.1.1"
resolved "https://registry.yarnpkg.com/command-line-args/-/command-line-args-5.1.1.tgz#88e793e5bb3ceb30754a86863f0401ac92fd369a"
integrity sha512-hL/eG8lrll1Qy1ezvkant+trihbGnaKaeEjj6Scyr3DN+RC7iQ5Rz84IeLERfAWDGo0HBSNAakczwgCilDXnWg==
@@ -7647,7 +7647,7 @@ left-pad@^1.3.0:
resolved "https://registry.yarnpkg.com/left-pad/-/left-pad-1.3.0.tgz#5b8a3a7765dfe001261dde915589e782f8c94d1e"
integrity sha512-XI5MPzVNApjAyhQzphX8BkmKsKUxD4LdyK24iZeQGinBN9yTQT3bFlCBy/aVx2HrNcqQGsdot8ghrjyrvMCoEA==
-lerna@^2.0.0:
+lerna@^2.11.0:
version "2.11.0"
resolved "https://registry.yarnpkg.com/lerna/-/lerna-2.11.0.tgz#89b5681e286d388dda5bbbdbbf6b84c8094eff65"
integrity sha512-kgM6zwe2P2tR30MYvgiLLW+9buFCm6E7o8HnRlhTgm70WVBvXVhydqv+q/MF2HrVZkCawfVtCfetyQmtd4oHhQ==