<commit_before>const fs = require('fs');
const path = require('path');
const glob = require('glob');
const svgo = require('svgo');
const mkdirp = require('mkdirp');
const loaderUtils = require('loader-utils');
const webpack = require('webpack');
const RawModule = require('webpack/lib/RawModule');
const { omit, concat, uniqBy } = require('lodash');
const { merge } = require('webpack-merge');
const { RawSource } = webpack.sources || require('webpack-sources');
const SingleEntryPlugin = webpack.EntryPlugin || webpack.SingleEntryPlugin;

// Helpers
const formatOptions = require('./options-formatter');
const generateSVG = require('./generate-svg');
const generateStyles = require('./generate-styles');
const { stripVariables, findVariables } = require('./variable-parser');

// Errors & Warnings
const { OptionsMismatchWarning, VariablesNotSupportedInLanguageWarning, VariablesNotSupportedWithFragmentsWarning, NoSourceFilesWarning } = require('./errors');

const plugin = {
    name: 'SVGSpritemapPlugin'
};

module.exports = class SVGSpritemapPlugin {
    constructor(pattern, options) {
        this.options = formatOptions(pattern, options);
        this.warnings = [];
        this.filenames = {
            spritemap: this.options.output.filename,
            styles: this.options.styles.filename
        };

        // Dependencies
        this.files = [];
        this.directories = [];
    }

    apply(compiler) {
        compiler.hooks.entryOption.tap(plugin, (context, entry) => {
            const { output: outputOptions } = this.options;

            if ( !outputOptions.svg4everybody ) {
                return;
            }

            // This is a little hacky but there's no other way since Webpack
            // doesn't support virtual files (https://github.com/rmarscher/virtual-module-webpack-plugin)
            const helper = {
                file: fs.readFileSync(path.join(__dirname, 'templates/svg4everybody.template.js'), 'utf8'),
                path: path.join(__dirname, '../svg4everybody-helper.js')
            };

            // Write the helper file to disk
            fs.writeFileSync(helper.path, helper.file.replace('/* PLACEHOLDER */', JSON.stringify(outputOptions.svg4everybody)), 'utf8');

            // Append helper to entry
            const applyEntryPlugin = (entries, name = 'main') => {
                entries.forEach((entry) => {
                    const plugin = new SingleEntryPlugin(context, entry, name);

                    plugin.apply(compiler);
                });
            };

            if ( typeof entry === 'string' ) {
                applyEntryPlugin([entry, helper.path]);
            } else if ( Array.isArray(entry) ) {
                if ( !entry.includes(helper.path) ) {
                    applyEntryPlugin([...entry, helper.path]);
                }
            } else if ( typeof entry === 'object' && entry !== null ) {
                Object.keys(entry).forEach((name) => {
                    if ( typeof entry[name] === 'string' ) {
                        applyEntryPlugin([entry[name], helper.path], name);
                    } else if ( entry[name].hasOwnProperty('import') ) {
                        applyEntryPlugin([...entry[name].import, helper.path], name);
                    } else if ( Array.isArray(entry[name]) ) {
                        if ( !entry[name].includes(helper.path) ) {
                            applyEntryPlugin([...entry[name], helper.path], name);
                        }
                    } else {
                        // Webpack currently doesn't allow this configuration (object with values other than string/array or descriptors)
                        // but let's make sure we throw if this ever gets added
                        throw new Error(`Unsupported sub-entry type for svg4everybody helper: '${typeof entry[name]}'`);
                    }
                });
            } else {
                throw new Error(`Unsupported entry type for svg4everybody helper: '${typeof entry}'`);
            }
        });

        // Update dependencies when needed
        compiler.hooks.environment.tap(plugin, this.updateDependencies.bind(this));
        compiler.hooks.watchRun.tap(plugin, this.updateDependencies.bind(this));

        // Generate spritemap
        compiler.hooks.run.tapAsync(plugin, this.generateSpritemap.bind(this));
        compiler.hooks.watchRun.tapAsync(plugin, this.generateSpritemap.bind(this));

        compiler.hooks.afterCompile.tap(plugin, (compilation) => {
            compilation.warnings = [...compilation.warnings, ...this.warnings];
        });

        compiler.hooks.make.tap(plugin, (compilation) => {
            const { output: outputOptions, styles: stylesOptions } = this.options;

            if (this.spritemap) {
                compilation.emitAsset(outputOptions.filename, new RawSource(this.spritemap), {
                    immutable: this.spritemapCache === this.spritemap,
                    development: false,
                    javascriptModule: false
                });

                // Store spritemap in cache to make sure we can check for immutability in the next compilation
                this.spritemapCache = this.spritemap;

                // Update filename now that the contenthash is known
                this.updateFilename('spritemap', compilation);
                this.generateStyles(compilation);
            }

            // Generate styles
            compilation.hooks.afterHash.tap(plugin, () => {
                this.updateFilename('spritemap', compilation);

                if ( typeof this.styles !== 'undefined' && this.stylesType === 'asset' ) {
                    compilation.emitAsset(stylesOptions.filename, new RawSource(this.styles.content))
                }
            });

            compilation.hooks.beforeChunks.tap(plugin, () => {
                // Set up a dummy module that we can add to our source chunk
                // To prevent it from getting cleaned up, this seems to be required
                // to correctly link the spritemap asset to the chunk
                const chunk = compilation.addChunk(outputOptions.chunk.name);
                chunk.reason = 'svg-spritemap-webpack-plugin dummy module';

                const module = new RawModule('', `${outputOptions.chunk.name}-dummy-module`);
                module.buildInfo = {};
                module.buildMeta = {};

                compilation.modules.add(module);
                compilation.chunkGraph.connectChunkAndModule(chunk, module);
            })

            // Optimize spritemap SVG/filename
            compilation.hooks.optimizeAssets.tap(plugin, (assets) => {
                const { output: outputOptions, sprite: spriteOptions } = this.options;
                const asset = compilation.getAsset(this.filenames.spritemap);

                if (!asset) {
                    return;
                }

                // Strip variables from spritemap SVG
                const stripped = stripVariables(asset.source);
                compilation.updateAsset(this.filenames.spritemap, new RawSource(stripped));

                if ( outputOptions.svgo === false ) {
                    return;
                }

                const config = merge({}, omit(outputOptions.svgo, ['plugins']), {
                    plugins: uniqBy(concat([{
                        name: 'removeTitle',
                        active: !spriteOptions.generate.title // Disable the removeTitle plugin when title elements should be generated
                    }], svgo.extendDefaultPlugins(outputOptions.svgo.plugins), [{
                        name: 'cleanupIDs',
                        active: false // Force disable cleanupIDs as the identifiers are to be used to target a specific sprite
                    }]).reverse(), 'name')
                });
                const output = svgo.optimize(assets[this.filenames.spritemap].source(), config);

                compilation.updateAsset(this.filenames.spritemap, new RawSource(output.data), {
                    minimized: true
                });
            });

            // Make sure we add the generated SVG as a file to the spritemap chunk
            compiler.hooks.thisCompilation.tap(plugin, (compilation) => {
                compilation.hooks.processAssets.tap({
                    name: this.constructor.name,
                    stage: webpack.Compilation.PROCESS_ASSETS_STAGE_OPTIMIZE
                }, () => {
                    compilation.chunks.forEach((chunk) => {
                        if ( chunk.name !== outputOptions.chunk.name ) {
                            return;
                        }

                        chunk.files.add(this.filenames.spritemap);
                    });
                });
            });
        });

        // Clean up the spritemap chunk
        compiler.hooks.thisCompilation.tap(plugin, (compilation) => {
            compilation.hooks.processAssets.tap({
                name: this.constructor.name,
                stage: webpack.Compilation.PROCESS_ASSETS_STAGE_OPTIMIZE
            }, () => {
                this.cleanUpChunk(compilation);
            });
        });

        // Add context dependencies to webpack compilation to make sure watching works correctly
        compiler.hooks.afterCompile.tap(plugin, (compilation) => {
            this.directories.forEach((directory) => {
                compilation.contextDependencies.add(directory);
            });
        });
    }

    generateSpritemap(compiler, callback) {
        const { sprite: spriteOptions, input: inputOptions, output: outputOptions } = this.options;

        Promise.all(this.files.map((file) => {
            return new Promise((resolve) => {
                return fs.readFile(file, {
                    encoding: 'utf-8'
                }, (error, content) => {
                    resolve({
                        path: file,
                        content: content
                    });
                });
            });
        })).then((sources) => {
            if ( !sources.length ) {
                this.warnings.push(new NoSourceFilesWarning(inputOptions.patterns));
            }

            if ( spriteOptions.generate.view && !spriteOptions.generate.use ) {
                this.warnings.push(new OptionsMismatchWarning(`Using sprite.generate.view requires sprite.generate.use to be enabled`));
            }

            if ( spriteOptions.generate.use && !spriteOptions.generate.symbol ) {
                this.warnings.push(new OptionsMismatchWarning(`Using sprite.generate.use requires sprite.generate.symbol to be enabled`));
            }

            if ( spriteOptions.generate.title && !spriteOptions.generate.symbol ) {
                this.warnings.push(new OptionsMismatchWarning(`Using sprite.generate.title requires sprite.generate.symbol to be enabled`));
            }

            if ( spriteOptions.generate.symbol === true && spriteOptions.generate.view === true ) {
                this.warnings.push(new OptionsMismatchWarning(`Both sprite.generate.symbol and sprite.generate.view are set to true which will cause identifier conflicts, use a string value (postfix) for either of these options`));
            }

            // Generate SVG
            this.sources = sources;
            this.spritemap = generateSVG(sources, {
                sprite: spriteOptions,
                output: outputOptions,
                input: inputOptions
            }, this.warnings);

            callback();
        });
    }

    generateStyles(compilation) {
        const { output: outputOptions, sprite: spriteOptions, styles: stylesOptions } = this.options;

        if ( !stylesOptions ) {
            return;
        }

        const extension = path.extname(stylesOptions.filename).substring(1).toLowerCase();

        this.styles = generateStyles(this.spritemap, {
            extension: extension,
            keepAttributes: stylesOptions.keepAttributes,
            prefix: spriteOptions.prefix,
            prefixStylesSelectors: spriteOptions.prefixStylesSelectors,
            postfix: {
                symbol: spriteOptions.generate.symbol,
                view: spriteOptions.generate.view
            },
            format: {
                type: stylesOptions.format,
                publicPath: (() => {
                    const publicPath = compilation.options.publicPath;

                    if ( typeof publicPath === 'undefined' || publicPath === 'auto' ) {
                        return `/${this.filenames.spritemap}`;
                    }

                    return `${publicPath.replace(/\/$/, '')}/${this.filenames.spritemap}`;
                })()
            },
            variables: stylesOptions.variables,
            callback: stylesOptions.callback
        }, this.sources);

        // Emit a warning when variables are detected while the language doesn't support it
        if ( !['scss', 'sass'].includes(extension) && findVariables(this.spritemap).length ) {
            this.warnings.push(new VariablesNotSupportedInLanguageWarning(extension));
        }

        // Emit a warning when variables are detected while the stylesOptions.format is set to 'fragment'
        if ( stylesOptions.format === 'fragment' && findVariables(this.spritemap).length ) {
            this.warnings.push(new VariablesNotSupportedWithFragmentsWarning());
        }

        // Emit a warning when using 'fragment' for styles.format without enabling sprite.generate.view
        if ( stylesOptions.format === 'fragment' && !spriteOptions.generate.view ) {
            this.warnings.push(new OptionsMismatchWarning(`Using styles.format with value 'fragment' in combination with sprite.generate.view with value false will result in CSS fragments not working correctly`));
        }

        // Emit a warning when using [hash] in filename while using 'fragment' for styles.format
        if ( stylesOptions.format === 'fragment' && outputOptions.filename.includes('[hash]') ) {
            this.warnings.push(new OptionsMismatchWarning(`Using styles.format with value 'fragment' in combination with [hash] in output.filename will results in incorrect fragment URLs`));
        }

        // Include warnings received from the style formatters
        if ( this.styles.warnings ) {
            this.warnings = [...this.warnings, ...this.styles.warnings];
        }

        // Write the styles file before compilation starts to make sure the files
        // are written to disk before other plugins/loaders (e.g. mini-css-extract-plugin) can use them
        this.stylesType = this.getStylesType(this.styles.content, stylesOptions.filename);
        this.writeStylesToDisk(this.styles.content, this.stylesType);
    }

    cleanUpChunk(compilation) {
        const { output: outputOptions } = this.options;
        if ( outputOptions.chunk.keep ) {
            return;
        }

        // Fetch existing filenames from all instances of this plugin
        const filenames = compilation.options.plugins.filter((plugin) => {
            return plugin instanceof SVGSpritemapPlugin;
        }).map((plugin) => {
            return Object.values(plugin.filenames);
        }).reduce((filenames, values) => {
            return filenames.concat(values);
        }, []);

        Array.from(compilation.chunks).filter((chunk) => {
            if ( !chunk.name ) {
                return false;
            }

            if ( chunk.name === outputOptions.chunk.name ) {
                return true;
            }

            if ( chunk.name.startsWith(`${outputOptions.chunk.name}${compilation.options.optimization.splitChunks.automaticNameDelimiter}`) ) {
                return true;
            }
        }).forEach((chunk) => {
            Array.from(chunk.files).filter((file) => {
                return !filenames.includes(file);
            }).forEach((file) => {
                delete compilation.assets[file];
            });
        });
    }

    updateDependencies() {
        const { input: inputOptions } = this.options;

        this.files = [];
        this.directories = [];

        inputOptions.patterns.forEach((pattern) => {
            this.directories.push(path.resolve(pattern.replace(/\*.*/, '')));

            glob.sync(pattern, inputOptions.options).map((match) => {
                const pathname = path.resolve(match);
                const stats = fs.lstatSync(pathname);

                if (stats.isFile()) {
                    this.files = [...new Set([...this.files, pathname])];

                    // Add parent directories of files to directory watch list
                    // to ensure new files in these directories are watched as well
                    this.directories = [...new Set([...this.directories, pathname.substring(0, pathname.lastIndexOf(path.sep))])];
                } else if (stats.isDirectory()) {
                    this.directories = [...new Set([...this.directories, pathname])];
                }
            });
        });
    }

    getStylesType(styles, filename = '') {
        if ( !styles || !filename ) {
            return;
        }

        if ( path.parse(filename).dir ) {
            return 'dir';
        }

        if ( filename.startsWith('~') ) {
            return 'module';
        }

        return 'asset';
    }

    writeStylesToDisk(styles, type) {
        const { styles: stylesOptions } = this.options;

        const location = {
            'dir': stylesOptions.filename,
            'module': path.resolve(__dirname, '../', stylesOptions.filename.replace('~', ''))
        }[type];

        if ( typeof location === 'undefined' ) {
            return;
        }

        // check is location exist
        const locationExists = fs.existsSync(location);

        // Make sure we don't rewrite the file when it's correct already
        const contents = locationExists && fs.readFileSync(location, 'utf8');
        if ( contents === styles ) {
            return;
        }

        if ( type === 'dir' && !locationExists ) {
            const dirname = path.dirname(location);

            if ( !fs.existsSync(dirname) ) {
                mkdirp.sync(dirname);
            }
        }

        fs.writeFileSync(location, styles, 'utf8');
    }

    updateFilename(identifier, compilation) {
        const oldFilename = this.filenames[identifier];
        const asset = compilation.getAsset(oldFilename);

        if (!asset) {
            return oldFilename;
        }

        const source = typeof asset.source === 'string' ? asset.source : asset.source._value;
        const hash = compilation.hash;
        const contenthash = asset && loaderUtils.getHashDigest(source, 'sha1', 'hex', compilation.options.output.hashDigestLength || 16);

        const newFilename = [{
            pattern: /\[hash]/,
            value: hash || '[hash]'
        }, {
            pattern: /\[contenthash]/,
            value: contenthash || '[contenthash]'
        }].reduce((filename, item) => {
            const pattern = new RegExp(item.pattern, 'ig');

            return filename.replace(pattern, item.value);
        }, this.filenames[identifier]);

        compilation.renameAsset(oldFilename, newFilename);

        compilation.updateAsset(newFilename, source, {
            contenthash: contenthash
        });
        this.filenames[identifier] = newFilename;
    }
};
<commit_msg>Fix public path for styles content not extracting value from the correct place<commit_after>const fs = require('fs');
const path = require('path');
const glob = require('glob');
const svgo = require('svgo');
const mkdirp = require('mkdirp');
const loaderUtils = require('loader-utils');
const webpack = require('webpack');
const RawModule = require('webpack/lib/RawModule');
const { omit, concat, uniqBy } = require('lodash');
const { merge } = require('webpack-merge');
const { RawSource } = webpack.sources || require('webpack-sources');
const SingleEntryPlugin = webpack.EntryPlugin || webpack.SingleEntryPlugin;

// Helpers
const formatOptions = require('./options-formatter');
const generateSVG = require('./generate-svg');
const generateStyles = require('./generate-styles');
const { stripVariables, findVariables } = require('./variable-parser');

// Errors & Warnings
const { OptionsMismatchWarning, VariablesNotSupportedInLanguageWarning, VariablesNotSupportedWithFragmentsWarning, NoSourceFilesWarning } = require('./errors');

const plugin = {
    name: 'SVGSpritemapPlugin'
};

module.exports = class SVGSpritemapPlugin {
    constructor(pattern, options) {
        this.options = formatOptions(pattern, options);
        this.warnings = [];
        this.filenames = {
            spritemap: this.options.output.filename,
            styles: this.options.styles.filename
        };

        // Dependencies
        this.files = [];
        this.directories = [];
    }

    apply(compiler) {
        compiler.hooks.entryOption.tap(plugin, (context, entry) => {
            const { output: outputOptions } = this.options;

            if ( !outputOptions.svg4everybody ) {
                return;
            }

            // This is a little hacky but there's no other way since Webpack
            // doesn't support virtual files (https://github.com/rmarscher/virtual-module-webpack-plugin)
            const helper = {
                file: fs.readFileSync(path.join(__dirname, 'templates/svg4everybody.template.js'), 'utf8'),
                path: path.join(__dirname, '../svg4everybody-helper.js')
            };

            // Write the helper file to disk
            fs.writeFileSync(helper.path, helper.file.replace('/* PLACEHOLDER */', JSON.stringify(outputOptions.svg4everybody)), 'utf8');

            // Append helper to entry
            const applyEntryPlugin = (entries, name = 'main') => {
                entries.forEach((entry) => {
                    const plugin = new SingleEntryPlugin(context, entry, name);

                    plugin.apply(compiler);
                });
            };

            if ( typeof entry === 'string' ) {
                applyEntryPlugin([entry, helper.path]);
            } else if ( Array.isArray(entry) ) {
                if ( !entry.includes(helper.path) ) {
                    applyEntryPlugin([...entry, helper.path]);
                }
            } else if ( typeof entry === 'object' && entry !== null ) {
                Object.keys(entry).forEach((name) => {
                    if ( typeof entry[name] === 'string' ) {
                        applyEntryPlugin([entry[name], helper.path], name);
                    } else if ( entry[name].hasOwnProperty('import') ) {
                        applyEntryPlugin([...entry[name].import, helper.path], name);
                    } else if ( Array.isArray(entry[name]) ) {
                        if ( !entry[name].includes(helper.path) ) {
                            applyEntryPlugin([...entry[name], helper.path], name);
                        }
                    } else {
                        // Webpack currently doesn't allow this configuration (object with values other than string/array or descriptors)
                        // but let's make sure we throw if this ever gets added
                        throw new Error(`Unsupported sub-entry type for svg4everybody helper: '${typeof entry[name]}'`);
                    }
                });
            } else {
                throw new Error(`Unsupported entry type for svg4everybody helper: '${typeof entry}'`);
            }
        });

        // Update dependencies when needed
        compiler.hooks.environment.tap(plugin, this.updateDependencies.bind(this));
        compiler.hooks.watchRun.tap(plugin, this.updateDependencies.bind(this));

        // Generate spritemap
        compiler.hooks.run.tapAsync(plugin, this.generateSpritemap.bind(this));
        compiler.hooks.watchRun.tapAsync(plugin, this.generateSpritemap.bind(this));

        compiler.hooks.afterCompile.tap(plugin, (compilation) => {
            compilation.warnings = [...compilation.warnings, ...this.warnings];
        });

        compiler.hooks.make.tap(plugin, (compilation) => {
            const { output: outputOptions, styles: stylesOptions } = this.options;

            if (this.spritemap) {
                compilation.emitAsset(outputOptions.filename, new RawSource(this.spritemap), {
                    immutable: this.spritemapCache === this.spritemap,
                    development: false,
                    javascriptModule: false
                });

                // Store spritemap in cache to make sure we can check for immutability in the next compilation
                this.spritemapCache = this.spritemap;

                // Update filename now that the contenthash is known
                this.updateFilename('spritemap', compilation);
                this.generateStyles(compilation);
            }

            // Generate styles
            compilation.hooks.afterHash.tap(plugin, () => {
                this.updateFilename('spritemap', compilation);

                if ( typeof this.styles !== 'undefined' && this.stylesType === 'asset' ) {
                    compilation.emitAsset(stylesOptions.filename, new RawSource(this.styles.content))
                }
            });

            compilation.hooks.beforeChunks.tap(plugin, () => {
                // Set up a dummy module that we can add to our source chunk
                // To prevent it from getting cleaned up, this seems to be required
                // to correctly link the spritemap asset to the chunk
                const chunk = compilation.addChunk(outputOptions.chunk.name);
                chunk.reason = 'svg-spritemap-webpack-plugin dummy module';

                const module = new RawModule('', `${outputOptions.chunk.name}-dummy-module`);
                module.buildInfo = {};
                module.buildMeta = {};

                compilation.modules.add(module);
                compilation.chunkGraph.connectChunkAndModule(chunk, module);
            })

            // Optimize spritemap SVG/filename
            compilation.hooks.optimizeAssets.tap(plugin, (assets) => {
                const { output: outputOptions, sprite: spriteOptions } = this.options;
                const asset = compilation.getAsset(this.filenames.spritemap);

                if (!asset) {
                    return;
                }

                // Strip variables from spritemap SVG
                const stripped = stripVariables(asset.source);
                compilation.updateAsset(this.filenames.spritemap, new RawSource(stripped));

                if ( outputOptions.svgo === false ) {
                    return;
                }

                const config = merge({}, omit(outputOptions.svgo, ['plugins']), {
                    plugins: uniqBy(concat([{
                        name: 'removeTitle',
                        active: !spriteOptions.generate.title // Disable the removeTitle plugin when title elements should be generated
                    }], svgo.extendDefaultPlugins(outputOptions.svgo.plugins), [{
                        name: 'cleanupIDs',
                        active: false // Force disable cleanupIDs as the identifiers are to be used to target a specific sprite
                    }]).reverse(), 'name')
                });
                const output = svgo.optimize(assets[this.filenames.spritemap].source(), config);

                compilation.updateAsset(this.filenames.spritemap, new RawSource(output.data), {
                    minimized: true
                });
            });

            // Make sure we add the generated SVG as a file to the spritemap chunk
            compiler.hooks.thisCompilation.tap(plugin, (compilation) => {
                compilation.hooks.processAssets.tap({
                    name: this.constructor.name,
                    stage: webpack.Compilation.PROCESS_ASSETS_STAGE_OPTIMIZE
                }, () => {
                    compilation.chunks.forEach((chunk) => {
                        if ( chunk.name !== outputOptions.chunk.name ) {
                            return;
                        }

                        chunk.files.add(this.filenames.spritemap);
                    });
                });
            });
        });

        // Clean up the spritemap chunk
        compiler.hooks.thisCompilation.tap(plugin, (compilation) => {
            compilation.hooks.processAssets.tap({
                name: this.constructor.name,
                stage: webpack.Compilation.PROCESS_ASSETS_STAGE_OPTIMIZE
            }, () => {
                this.cleanUpChunk(compilation);
            });
        });

        // Add context dependencies to webpack compilation to make sure watching works correctly
        compiler.hooks.afterCompile.tap(plugin, (compilation) => {
            this.directories.forEach((directory) => {
                compilation.contextDependencies.add(directory);
            });
        });
    }

    generateSpritemap(compiler, callback) {
        const { sprite: spriteOptions, input: inputOptions, output: outputOptions } = this.options;

        Promise.all(this.files.map((file) => {
            return new Promise((resolve) => {
                return fs.readFile(file, {
                    encoding: 'utf-8'
                }, (error, content) => {
                    resolve({
                        path: file,
                        content: content
                    });
                });
            });
        })).then((sources) => {
            if ( !sources.length ) {
                this.warnings.push(new NoSourceFilesWarning(inputOptions.patterns));
            }

            if ( spriteOptions.generate.view && !spriteOptions.generate.use ) {
                this.warnings.push(new OptionsMismatchWarning(`Using sprite.generate.view requires sprite.generate.use to be enabled`));
            }

            if ( spriteOptions.generate.use && !spriteOptions.generate.symbol ) {
                this.warnings.push(new OptionsMismatchWarning(`Using sprite.generate.use requires sprite.generate.symbol to be enabled`));
            }

            if ( spriteOptions.generate.title && !spriteOptions.generate.symbol ) {
                this.warnings.push(new OptionsMismatchWarning(`Using sprite.generate.title requires sprite.generate.symbol to be enabled`));
            }

            if ( spriteOptions.generate.symbol === true && spriteOptions.generate.view === true ) {
                this.warnings.push(new OptionsMismatchWarning(`Both sprite.generate.symbol and sprite.generate.view are set to true which will cause identifier conflicts, use a string value (postfix) for either of these options`));
            }

            // Generate SVG
            this.sources = sources;
            this.spritemap = generateSVG(sources, {
                sprite: spriteOptions,
                output: outputOptions,
                input: inputOptions
            }, this.warnings);

            callback();
        });
    }

    generateStyles(compilation) {
        const { output: outputOptions, sprite: spriteOptions, styles: stylesOptions } = this.options;

        if ( !stylesOptions ) {
            return;
        }

        const extension = path.extname(stylesOptions.filename).substring(1).toLowerCase();

        this.styles = generateStyles(this.spritemap, {
            extension: extension,
            keepAttributes: stylesOptions.keepAttributes,
            prefix: spriteOptions.prefix,
            prefixStylesSelectors: spriteOptions.prefixStylesSelectors,
            postfix: {
                symbol: spriteOptions.generate.symbol,
                view: spriteOptions.generate.view
            },
            format: {
                type: stylesOptions.format,
                publicPath: (() => {
                    const publicPath = compilation.options.output.publicPath;

                    if ( typeof publicPath === 'undefined' || publicPath === 'auto' ) {
                        return `/${this.filenames.spritemap}`;
                    }

                    return `${publicPath.replace(/\/$/, '')}/${this.filenames.spritemap}`;
                })()
            },
            variables: stylesOptions.variables,
            callback: stylesOptions.callback
        }, this.sources);

        // Emit a warning when variables are detected while the language doesn't support it
        if ( !['scss', 'sass'].includes(extension) && findVariables(this.spritemap).length ) {
            this.warnings.push(new VariablesNotSupportedInLanguageWarning(extension));
        }

        // Emit a warning when variables are detected while the stylesOptions.format is set to 'fragment'
        if ( stylesOptions.format === 'fragment' && findVariables(this.spritemap).length ) {
            this.warnings.push(new VariablesNotSupportedWithFragmentsWarning());
        }

        // Emit a warning when using 'fragment' for styles.format without enabling sprite.generate.view
        if ( stylesOptions.format === 'fragment' && !spriteOptions.generate.view ) {
            this.warnings.push(new OptionsMismatchWarning(`Using styles.format with value 'fragment' in combination with sprite.generate.view with value false will result in CSS fragments not working correctly`));
        }

        // Emit a warning when using [hash] in filename while using 'fragment' for styles.format
        if ( stylesOptions.format === 'fragment' && outputOptions.filename.includes('[hash]') ) {
            this.warnings.push(new OptionsMismatchWarning(`Using styles.format with value 'fragment' in combination with [hash] in output.filename will results in incorrect fragment URLs`));
        }

        // Include warnings received from the style formatters
        if ( this.styles.warnings ) {
            this.warnings = [...this.warnings, ...this.styles.warnings];
        }

        // Write the styles file before compilation starts to make sure the files
        // are written to disk before other plugins/loaders (e.g. mini-css-extract-plugin) can use them
        this.stylesType = this.getStylesType(this.styles.content, stylesOptions.filename);
        this.writeStylesToDisk(this.styles.content, this.stylesType);
    }

    cleanUpChunk(compilation) {
        const { output: outputOptions } = this.options;
        if ( outputOptions.chunk.keep ) {
            return;
        }

        // Fetch existing filenames from all instances of this plugin
        const filenames = compilation.options.plugins.filter((plugin) => {
            return plugin instanceof SVGSpritemapPlugin;
        }).map((plugin) => {
            return Object.values(plugin.filenames);
        }).reduce((filenames, values) => {
            return filenames.concat(values);
        }, []);

        Array.from(compilation.chunks).filter((chunk) => {
            if ( !chunk.name ) {
                return false;
            }

            if ( chunk.name === outputOptions.chunk.name ) {
                return true;
            }

            if ( chunk.name.startsWith(`${outputOptions.chunk.name}${compilation.options.optimization.splitChunks.automaticNameDelimiter}`) ) {
                return true;
            }
        }).forEach((chunk) => {
            Array.from(chunk.files).filter((file) => {
                return !filenames.includes(file);
            }).forEach((file) => {
                delete compilation.assets[file];
            });
        });
    }

    updateDependencies() {
        const { input: inputOptions } = this.options;

        this.files = [];
        this.directories = [];

        inputOptions.patterns.forEach((pattern) => {
            this.directories.push(path.resolve(pattern.replace(/\*.*/, '')));

            glob.sync(pattern, inputOptions.options).map((match) => {
                const pathname = path.resolve(match);
                const stats = fs.lstatSync(pathname);

                if (stats.isFile()) {
                    this.files = [...new Set([...this.files, pathname])];

                    // Add parent directories of files to directory watch list
                    // to ensure new files in these directories are watched as well
                    this.directories = [...new Set([...this.directories, pathname.substring(0, pathname.lastIndexOf(path.sep))])];
                } else if (stats.isDirectory()) {
                    this.directories = [...new Set([...this.directories, pathname])];
                }
            });
        });
    }

    getStylesType(styles, filename = '') {
        if ( !styles || !filename ) {
            return;
        }

        if ( path.parse(filename).dir ) {
            return 'dir';
        }

        if ( filename.startsWith('~') ) {
            return 'module';
        }

        return 'asset';
    }

    writeStylesToDisk(styles, type) {
        const { styles: stylesOptions } = this.options;

        const location = {
            'dir': stylesOptions.filename,
            'module': path.resolve(__dirname, '../', stylesOptions.filename.replace('~', ''))
        }[type];

        if ( typeof location === 'undefined' ) {
            return;
        }

        // check is location exist
        const locationExists = fs.existsSync(location);

        // Make sure we don't rewrite the file when it's correct already
        const contents = locationExists && fs.readFileSync(location, 'utf8');
        if ( contents === styles ) {
            return;
        }

        if ( type === 'dir' && !locationExists ) {
            const dirname = path.dirname(location);

            if ( !fs.existsSync(dirname) ) {
                mkdirp.sync(dirname);
            }
        }

        fs.writeFileSync(location, styles, 'utf8');
    }

    updateFilename(identifier, compilation) {
        const oldFilename = this.filenames[identifier];
        const asset = compilation.getAsset(oldFilename);

        if (!asset) {
            return oldFilename;
        }

        const source = typeof asset.source === 'string' ? asset.source : asset.source._value;
        const hash = compilation.hash;
        const contenthash = asset && loaderUtils.getHashDigest(source, 'sha1', 'hex', compilation.options.output.hashDigestLength || 16);

        const newFilename = [{
            pattern: /\[hash]/,
            value: hash || '[hash]'
        }, {
            pattern: /\[contenthash]/,
            value: contenthash || '[contenthash]'
        }].reduce((filename, item) => {
            const pattern = new RegExp(item.pattern, 'ig');

            return filename.replace(pattern, item.value);
        }, this.filenames[identifier]);

        compilation.renameAsset(oldFilename, newFilename);

        compilation.updateAsset(newFilename, source, {
            contenthash: contenthash
        });
        this.filenames[identifier] = newFilename;
    }
};
<|endoftext|>


<commit_before>var express = require('express');
var sio = require('socket.io');

module.exports = {

};
<commit_msg>added basic functionality, still wip though<commit_after>var express = require('express');
var sio = require('socket.io');

var debug = false;

var mainApp = express();

var subApps = [];

function addApplication (options) {
	if (debug) console.log('exp mount ' + options.name + ' as ' + options.mountPoint + ' (' + options.script + ')');
	var router = express.Router();
	subApps.push(router);
	var script = require(options.script);
	script.init(router);
	mainApp.use(options.mountPoint, router);
}

function enableWebUI (options) {
	if (debug) console.log('exp enable webui');
	var router = express.Router();
	router.get('/', function (req, res) {
		res.send('admin ui goes here');
	});
	mainApp.use(options.mountPoint, router);
}

function listen (port) {
	if (debug) console.log('exp listen ' + port);
	mainApp.listen(port);
}

module.exports = {
	enableWebUI: enableWebUI,
	addApplication: addApplication,
	listen: listen,
	debug: function (value) {
		debug = value;
	}
};
<|endoftext|>


<commit_before>
/*!
 * Dox
 * Copyright(c) 2010 TJ Holowaychuk <tj@vision-media.ca>
 * MIT Licensed
 */

/**
 * Module dependencies.
 */

var sys = require('sys'),
    fs = require('fs');

/**
 * Style name.
 */

var style = 'default';

/**
 * Document title.
 */

var title = 'Dont forget to use --title to specify me!';

/**
 * Parse JSDoc.
 */

var jsdoc = true;

/**
 * Usage.
 */

var usage = ''
    + 'Usage: dox [options] <file ...>\n'
    + '\n'
    + 'Options:\n'
    + '  -t, --title   Document title\n'
    + '  -s, --style   Document style, available: ["default"]\n'
    + '  -h, --help    Display help information'
    + '\n';

/**
 * Parse the given arguments.
 *
 * @param {Array} args
 * @api public
 */

exports.parse = function(args){
    var files = [];

    // Require an argument
    function requireArg(){
        if (args.length) {
            return args.shift();
        } else {
            throw new Error(arg + ' requires an argument.');
        }
    }

    // Parse arguments
    while (args.length) {
        var arg = args.shift();
        switch (arg) {
            case '-h':
            case '--help':
                sys.puts(usage);
                process.exit(1);
                break;
            case '-t':
            case '--title':
                title = requireArg();
                break;
            case '-s':
            case '--style':
                style = requireArg();
                break;
            default:
                files.push(arg);
        }
    }

    if (files.length) {
        var pending = files.length;

        // Style
        var head = fs.readFileSync(__dirname + '/styles/' + style + '/head.html', 'utf8');
        var foot = fs.readFileSync(__dirname + '/styles/' + style + '/foot.html', 'utf8');
        var css = fs.readFileSync(__dirname + '/styles/' + style + '/style.css', 'utf8');

        // Substitutions
        head = head.replace(/\{\{title\}\}/g, title).replace(/\{\{style\}\}/, css);

        sys.print(head);

        // Render files
        files.forEach(function(file){
            fs.readFile(file, 'utf8', function(err, str){
                if (err) throw err;
                sys.print(render(str));
                --pending || sys.print(foot);
            });
        });

    } else {
        throw new Error('files required.');
    }
};

/**
 * Generate html for the given string of code.
 *
 * @param {String} str
 * @return {String}
 * @api public
 */

var render = exports.render = function(str){
    var parts = str.split(/\s*\/\*([^]+?)\*\/\s*/g),
        blocks = [];

    // Populate blocks
    for (var i = 0, len = parts.length; i < len; ++i) {
        var part = parts[i],
            next = parts[i + 1] || '';
        // Empty
        if (/^\s*$/.test(part)) {
            continue;
        // Ignored comment
        } else if (/^!\s*\*/.test(part)) {
            continue;
        } else {
            ++i;
            var part = part
                .replace(/^ *\*/gm, '');
            blocks.push({
               comment: part,
               code: next
            });
        }
    }

    // Generate html
    var html = ['

'];
    for (var i = 0, len = blocks.length; i < len; ++i) {
        var block = blocks[i];
        html.push('
');
        html.push('', block.comment
            ? '
' + block.comment + '
'
            : '', '	');
        html.push('', block.code
            ? '
' + block.code + '
'
            : '', '	');
        html.push('
');
    }

    return html.concat('

').join('\n');
}<commit_msg>Highlighting with koala<commit_after>
/*!
 * Dox
 * Copyright(c) 2010 TJ Holowaychuk <tj@vision-media.ca>
 * MIT Licensed
 */

/**
 * Module dependencies.
 */

require.paths.unshift(__dirname + '/koala/lib');
var sys = require('sys'),
    fs = require('fs'),
    koala = require('koala');

/**
 * Style name.
 */

var style = 'default';

/**
 * Document title.
 */

var title = 'Dont forget to use --title to specify me!';

/**
 * Parse JSDoc.
 */

var jsdoc = true;

/**
 * Usage.
 */

var usage = ''
    + 'Usage: dox [options] <file ...>\n'
    + '\n'
    + 'Options:\n'
    + '  -t, --title   Document title\n'
    + '  -s, --style   Document style, available: ["default"]\n'
    + '  -h, --help    Display help information'
    + '\n';

/**
 * Parse the given arguments.
 *
 * @param {Array} args
 * @api public
 */

exports.parse = function(args){
    var files = [];

    // Require an argument
    function requireArg(){
        if (args.length) {
            return args.shift();
        } else {
            throw new Error(arg + ' requires an argument.');
        }
    }

    // Parse arguments
    while (args.length) {
        var arg = args.shift();
        switch (arg) {
            case '-h':
            case '--help':
                sys.puts(usage);
                process.exit(1);
                break;
            case '-t':
            case '--title':
                title = requireArg();
                break;
            case '-s':
            case '--style':
                style = requireArg();
                break;
            default:
                files.push(arg);
        }
    }

    if (files.length) {
        var pending = files.length;

        // Style
        var head = fs.readFileSync(__dirname + '/styles/' + style + '/head.html', 'utf8');
        var foot = fs.readFileSync(__dirname + '/styles/' + style + '/foot.html', 'utf8');
        var css = fs.readFileSync(__dirname + '/styles/' + style + '/style.css', 'utf8');

        // Substitutions
        head = head.replace(/\{\{title\}\}/g, title).replace(/\{\{style\}\}/, css);

        sys.print(head);

        // Render files
        files.forEach(function(file){
            fs.readFile(file, 'utf8', function(err, str){
                if (err) throw err;
                sys.print(render(str));
                --pending || sys.print(foot);
            });
        });

    } else {
        throw new Error('files required.');
    }
};

/**
 * Generate html for the given string of code.
 *
 * @param {String} str
 * @return {String}
 * @api public
 */

var render = exports.render = function(str){
    var parts = str.split(/\s*\/\*([^]+?)\*\/\s*/g),
        blocks = [];

    // Populate blocks
    for (var i = 0, len = parts.length; i < len; ++i) {
        var part = parts[i],
            next = parts[i + 1] || '';
        // Empty
        if (/^\s*$/.test(part)) {
            continue;
        // Ignored comment
        } else if (/^!\s*\*/.test(part)) {
            continue;
        } else {
            ++i;
            var part = part
                .replace(/^ *\*/gm, '');
            blocks.push({
               comment: part,
               code: koala.render('.js', next)
            });
        }
    }

    // Generate html
    var html = ['

'];
    for (var i = 0, len = blocks.length; i < len; ++i) {
        var block = blocks[i];
        html.push('
');
        html.push('', block.comment
            ? '
' + block.comment + '
'
            : '', '	');
        html.push('', block.code
            ? '
' + block.code + '
'
            : '', '	');
        html.push('
');
    }

    return html.concat('

').join('\n');
}<|endoftext|>


<commit_before>'use strict';

var restify = require('restify');
var autoload = require('auto-load');
var session = require('client-sessions');
var async = require('async');
var http = require('http');
var https = require('https');
var yaqs = require('yaqs');
var Logger = require("bunyan");
var restifyBunyanLogger = require('restify-bunyan-logger');

var Token = require('./models/token.js');
var TempToken = require('./models/temp-token.js');
var util = require('./util.js');

var usersQueue = require('./queues/users-queue.js');

// Create bunyan logger
module.exports.log = new Logger.createLogger({
  name: process.env.APP_NAME || 'provider',
});

/**
* Simple wrapper around the token model.
* Only one token should match.
*
* retrieveData({accessToken: ...}) => data for this access token
* retrieveData({'data.grant': ...}) => data with this value of grant.
*/
module.exports.retrieveData = function(hash, cb) {
  Token.findOne(hash, function(err, token) {
    if(!token) {
      return cb(new Error("no data matches"));
    }
    cb(err, token.data);
  });
};

/**
 * Create a new provider server.
 * This server will use `config.task_generator` as its main function, to turn a file into metadata.
 *
 * @param {Object} config Configuration hash.
 *   Mandatory:
 *      task_generator, to retrieve a list of tasks (a task is "a document to upload").
 *      task_handler, the uploading function.
 *   Optional:
 *      concurrency, max number of simultaneous calls to your task_handler function (default is 1)
 */
module.exports.createServer = function createServer(connectFunctions, workersFile, updateFile, config) {
  ['appId', 'appSecret', 'providerUrl'].forEach(function(name) {
    if(!config[name]) {
      console.warn('Error: Missing config.' + name + ' not found');
      process.exit(1);
    }
  });
  util.logError.config = config;

  if(config.opbeat && config.opbeat.secretToken) {
    var opbeat = require('opbeat');
    util.logError.opbeat = opbeat(config.opbeat);
  }

  // Connect mongo
  util.connectMongo(config.mongoUrl);

  // Load endpoints generators
  var handlers = autoload(__dirname + "/handlers");
  var middlewares = autoload(__dirname + "/middlewares");

  http.globalAgent.maxSockets = config.maxSockets || 30;
  https.globalAgent.maxSockets = http.globalAgent.maxSockets;

  // Create server
  var server = restify.createServer({
    log: module.exports.log
  });

  server.on('after', restifyBunyanLogger({
    custom: function(req, res, route, err, log) {
      log.req.user = req.token ? req.token.accountName : null;
      return log;
    }
  }));

  server.use(restify.requestLogger());
  server.use(restify.acceptParser(server.acceptable));
  server.use(restify.queryParser());
  server.use(restify.bodyParser());
  server.use(session({
    cookieName: 'ANYFETCH_SESSION',
    secret: config.appSecret
  }));

  config.redisUrl = config.redisUrl || process.env.REDIS_URL || "redis://localhost";

  if(module.exports.yaqsClient) {
    server.yaqsClient = module.exports.yaqsClient;
  }
  else {
    server.yaqsClient = yaqs({
      prefix: config.appName || config.providerUrl,
      redis: config.redisUrl
    });

    module.exports.yaqsClient = server.yaqsClient;
  }

  server.usersQueue = server.yaqsClient.createQueue('anyfetch-provider-users', {
    concurrency: config.usersConcurrency || 1,
    defaultTimeout: -1
  });

  server.childs = {};

  function sigtermYaqs() {
    async.waterfall([
      function killProcesses(cb) {
        async.each(Object.keys(server.childs), function(anyfetchToken, cb) {
          server.childs[anyfetchToken].kill(cb);
        }, cb);
      },
      function stopAllQueues(cb) {
        server.yaqsClient.stopAllQueues(cb);
      },
      function registerUsers(cb) {
        async.each(Object.keys(server.childs), function(anyfetchToken, cb) {
          server.usersQueue.createJob({
            anyfetchToken: anyfetchToken,
            anyfetchApiUrl: server.childs[anyfetchToken].anyfetchApiUrl
          }).save(cb);
        }, cb);
      }
    ], function(err) {
      module.exports.log.info('YAQS has stopped.');

      util.logError(err);
      process.exit(0);
    });
  }

  process.once('SIGTERM', sigtermYaqs);

  server.usersQueue
    .on('error', util.logError)
    .setWorker(usersQueue(server, config, workersFile, updateFile))
    .start();

  // Load routes and generate endpoints using closures
  server.get('/', handlers.index.get);
  server.get('/init/connect', handlers.init.connect.getGenerator(connectFunctions.redirectToService, config));
  server.get('/init/callback', handlers.init.callback.getGenerator(connectFunctions.retrieveTokens, config));

  server.post('/update', middlewares.token, handlers.update.postGenerator(server.yaqsClient, server.usersQueue, config));
  server.post('/update/:identifier', middlewares.token, handlers.update.postGenerator(server.yaqsClient, server.usersQueue, config));

  server.get('/status', handlers.status.get);

  server.post('/token', handlers.token.index.post);
  server.del('/token', middlewares.token, handlers.token.index.del);
  server.del('/token/reset', middlewares.token, handlers.token.reset.del);

  server.on('uncaughtException', function(req, res, route, err) {
    util.logError(err, req);

    if(!res._headerSent) {
      res.send(new restify.InternalServerError(err, err.message || 'unexpected error'));
      return true;
    }

    return false;
  });

  module.exports.currentServer = server;

  // Expose the server
  return server;
};

module.exports.debug = {
  cleanTokens: function(cb) {
    util.connectMongo();
    async.parallel([
      function(cb) {
        Token.remove({}, cb);
      },
      function(cb) {
        TempToken.remove({}, cb);
      }
    ], cb);
  },
  createToken: function(hash, cb) {
    util.connectMongo();

    var token = new Token(hash);
    token.save(cb);
  },
  createTempToken: function(hash, cb) {
    util.connectMongo();

    var tempToken = new TempToken(hash);
    tempToken.save(cb);
  }
};

module.exports.CancelError = require('./cancel-error.js');
module.exports.util = util;
<commit_msg>Remove log of GET /status<commit_after>'use strict';

var restify = require('restify');
var autoload = require('auto-load');
var session = require('client-sessions');
var async = require('async');
var http = require('http');
var https = require('https');
var yaqs = require('yaqs');
var Logger = require("bunyan");
var restifyBunyanLogger = require('restify-bunyan-logger');

var Token = require('./models/token.js');
var TempToken = require('./models/temp-token.js');
var util = require('./util.js');

var usersQueue = require('./queues/users-queue.js');

// Create bunyan logger
module.exports.log = new Logger.createLogger({
  name: process.env.APP_NAME || 'provider',
});

/**
* Simple wrapper around the token model.
* Only one token should match.
*
* retrieveData({accessToken: ...}) => data for this access token
* retrieveData({'data.grant': ...}) => data with this value of grant.
*/
module.exports.retrieveData = function(hash, cb) {
  Token.findOne(hash, function(err, token) {
    if(!token) {
      return cb(new Error("no data matches"));
    }
    cb(err, token.data);
  });
};

/**
 * Create a new provider server.
 * This server will use `config.task_generator` as its main function, to turn a file into metadata.
 *
 * @param {Object} config Configuration hash.
 *   Mandatory:
 *      task_generator, to retrieve a list of tasks (a task is "a document to upload").
 *      task_handler, the uploading function.
 *   Optional:
 *      concurrency, max number of simultaneous calls to your task_handler function (default is 1)
 */
module.exports.createServer = function createServer(connectFunctions, workersFile, updateFile, config) {
  ['appId', 'appSecret', 'providerUrl'].forEach(function(name) {
    if(!config[name]) {
      console.warn('Error: Missing config.' + name + ' not found');
      process.exit(1);
    }
  });
  util.logError.config = config;

  if(config.opbeat && config.opbeat.secretToken) {
    var opbeat = require('opbeat');
    util.logError.opbeat = opbeat(config.opbeat);
  }

  // Connect mongo
  util.connectMongo(config.mongoUrl);

  // Load endpoints generators
  var handlers = autoload(__dirname + "/handlers");
  var middlewares = autoload(__dirname + "/middlewares");

  http.globalAgent.maxSockets = config.maxSockets || 30;
  https.globalAgent.maxSockets = http.globalAgent.maxSockets;

  // Create server
  var server = restify.createServer({
    log: module.exports.log
  });

  server.on('after', restifyBunyanLogger({
    skip: function(req, res) {
      return req.path() === "/status";
    },
    custom: function(req, res, route, err, log) {
      log.req.user = req.token ? req.token.accountName : null;
      return log;
    }
  }));

  server.use(restify.requestLogger());
  server.use(restify.acceptParser(server.acceptable));
  server.use(restify.queryParser());
  server.use(restify.bodyParser());
  server.use(session({
    cookieName: 'ANYFETCH_SESSION',
    secret: config.appSecret
  }));

  config.redisUrl = config.redisUrl || process.env.REDIS_URL || "redis://localhost";

  if(module.exports.yaqsClient) {
    server.yaqsClient = module.exports.yaqsClient;
  }
  else {
    server.yaqsClient = yaqs({
      prefix: config.appName || config.providerUrl,
      redis: config.redisUrl
    });

    module.exports.yaqsClient = server.yaqsClient;
  }

  server.usersQueue = server.yaqsClient.createQueue('anyfetch-provider-users', {
    concurrency: config.usersConcurrency || 1,
    defaultTimeout: -1
  });

  server.childs = {};

  function sigtermYaqs() {
    async.waterfall([
      function killProcesses(cb) {
        async.each(Object.keys(server.childs), function(anyfetchToken, cb) {
          server.childs[anyfetchToken].kill(cb);
        }, cb);
      },
      function stopAllQueues(cb) {
        server.yaqsClient.stopAllQueues(cb);
      },
      function registerUsers(cb) {
        async.each(Object.keys(server.childs), function(anyfetchToken, cb) {
          server.usersQueue.createJob({
            anyfetchToken: anyfetchToken,
            anyfetchApiUrl: server.childs[anyfetchToken].anyfetchApiUrl
          }).save(cb);
        }, cb);
      }
    ], function(err) {
      module.exports.log.info('YAQS has stopped.');

      util.logError(err);
      process.exit(0);
    });
  }

  process.once('SIGTERM', sigtermYaqs);

  server.usersQueue
    .on('error', util.logError)
    .setWorker(usersQueue(server, config, workersFile, updateFile))
    .start();

  // Load routes and generate endpoints using closures
  server.get('/', handlers.index.get);
  server.get('/init/connect', handlers.init.connect.getGenerator(connectFunctions.redirectToService, config));
  server.get('/init/callback', handlers.init.callback.getGenerator(connectFunctions.retrieveTokens, config));

  server.post('/update', middlewares.token, handlers.update.postGenerator(server.yaqsClient, server.usersQueue, config));
  server.post('/update/:identifier', middlewares.token, handlers.update.postGenerator(server.yaqsClient, server.usersQueue, config));

  server.get('/status', handlers.status.get);

  server.post('/token', handlers.token.index.post);
  server.del('/token', middlewares.token, handlers.token.index.del);
  server.del('/token/reset', middlewares.token, handlers.token.reset.del);

  server.on('uncaughtException', function(req, res, route, err) {
    util.logError(err, req);

    if(!res._headerSent) {
      res.send(new restify.InternalServerError(err, err.message || 'unexpected error'));
      return true;
    }

    return false;
  });

  module.exports.currentServer = server;

  // Expose the server
  return server;
};

module.exports.debug = {
  cleanTokens: function(cb) {
    util.connectMongo();
    async.parallel([
      function(cb) {
        Token.remove({}, cb);
      },
      function(cb) {
        TempToken.remove({}, cb);
      }
    ], cb);
  },
  createToken: function(hash, cb) {
    util.connectMongo();

    var token = new Token(hash);
    token.save(cb);
  },
  createTempToken: function(hash, cb) {
    util.connectMongo();

    var tempToken = new TempToken(hash);
    tempToken.save(cb);
  }
};

module.exports.CancelError = require('./cancel-error.js');
module.exports.util = util;
<|endoftext|>


<commit_before>'use strict';

const MODULE_NAME = 'suiteFlipper';
const IsOffFilter = require('./filter/is-off');
const IsOnFilter = require('./filter/is-on');
const SuiteFlipper = require('suite-flipper-js');

module.exports = function(angular) {
  angular
    .module(MODULE_NAME, [])
    .filter('flipperIsOn', IsOnFilter.create())
    .filter('flipperIsOff', IsOffFilter.create())
    .provider('flipper', function() {
      let flippers = [];
      return {
        setFlippers: function(value) {
          flippers = value;
        },

        $get: [function() {
          return SuiteFlipper.create(flippers);
        }]
      };
    });

  return MODULE_NAME;
};
<commit_msg>feat(release): semantic release<commit_after>'use strict';

const MODULE_NAME = 'suiteFlipper';
const IsOffFilter = require('./filter/is-off');
const IsOnFilter = require('./filter/is-on');
const SuiteFlipper = require('suite-flipper-js');

module.exports = function(angular) {
  angular
    .module(MODULE_NAME, [])
    .filter('flipperIsOn', IsOnFilter.create())
    .filter('flipperIsOff', IsOffFilter.create())
    .provider('flipper', function() {
      let flippers = [];

      return {
        setFlippers: function(value) {
          flippers = value;
        },

        $get: [function() {
          return SuiteFlipper.create(flippers);
        }]
      };
    });

  return MODULE_NAME;
};
<|endoftext|>


<commit_before>"use strict";

var sass = require("node-sass");
var path = require("path");
var extend = require('util')._extend;
var tools = require('browserify-transform-tools');

module.exports = tools.makeStringTransform('sassify', {
    includeExtensions: ['.css', '.sass', '.scss'],
    evaluateArguments: true
}, function(content, opts, done) {
    var inject = (typeof opts.config !== 'undefined' && typeof opts.config['auto-inject'] !== 'undefined') ? opts.config['auto-inject'] : false;
    var file = opts.file;

    var options = extend({}, opts.config || {});
    options.includePaths = extend([], (opts.config ? opts.config.includePaths : []) || []);
    options.includePaths.unshift(path.dirname(opts.file));
    options.indentedSyntax = /\.sass$/i.test(opts.file);

    options.file = file;
    options.data = content;
    options.sourceComments = false;
    options.sourceMap = true;
    options.outFile = opts.file;
    options.sourceMapEmbed = true;
    options.sourceMapContents = true;

    var callback = function (error,css) {
        if(error) {
          return done(error);
        }
        var exp;
        if (inject) {
        	exp = "require('" + path.basename(path.dirname(__dirname)) + "').byUrl('" + (function() {
            var b64 = css.css.toString('base64');
        		return 'data:text/css;base64,' + b64;
        	})() + "');";
        } else {
          exp = JSON.stringify(css.css.toString());
        }
        var out = "module.exports = " + exp + ";";

        done(null, out);
    };

    sass.render(options, callback);
});<commit_msg>added config parameter for disabling the base64Encoding<commit_after>"use strict";

var sass = require("node-sass");
var path = require("path");
var extend = require('util')._extend;
var tools = require('browserify-transform-tools');

module.exports = tools.makeStringTransform('sassify', {
    includeExtensions: ['.css', '.sass', '.scss'],
    evaluateArguments: true
}, function(content, opts, done) {
    var inject = (typeof opts.config !== 'undefined' && typeof opts.config['auto-inject'] !== 'undefined') ? opts.config['auto-inject'] : false;
    var file = opts.file;

    var options = extend({}, opts.config || {});
    options.includePaths = extend([], (opts.config ? opts.config.includePaths : []) || []);
    options.includePaths.unshift(path.dirname(opts.file));
    options.indentedSyntax = /\.sass$/i.test(opts.file);

    options.file = file;
    options.data = content;
    options.sourceComments = false;
    options.sourceMap = true;
    options.outFile = opts.file;
    options.sourceMapEmbed = true;
    options.sourceMapContents = true;
    options.base64Encode = opts.config.base64Encode !== undefined  ? opts.config['base64Encode'] : true;

    var callback = function (error,css) {
        if(error) {
          return done(error);
        }
        var exp;
        if (inject) {
            if(options.base64Encode) {
                exp = "require('" + path.basename(path.dirname(__dirname)) + "').byUrl('" + (function() {
                var b64 = css.css.toString('base64');
                  return 'data:text/css;base64,' + b64;
                })() + "');";
            } else {
                exp = "require('" + path.basename(path.dirname(__dirname)) + "')('" + (function() {
                        return css.css.toString().replace(/'/g, "\\'");
                    })() + "');";
            }
        } else {
          exp = JSON.stringify(css.css.toString());
        }
        var out = "module.exports = " + exp + ";";

        done(null, out);
    };

    sass.render(options, callback);
});<|endoftext|>


<commit_before>var jwt = require('jsonwebtoken');
var UnauthorizedError = require('./errors/UnauthorizedError');
var unless = require('express-unless');

module.exports = function(options) {
  if (!options || !options.secret) throw new Error('secret should be set');

  var _userProperty = options.userProperty || 'user';
  var credentialsRequired = typeof options.credentialsRequired === 'undefined' ? true : options.credentialsRequired;

  var middleware = function(req, res, next) {
    var token;

    if (req.method === 'OPTIONS' && req.headers.hasOwnProperty('access-control-request-headers')) {
      var hasAuthInAccessControl = !!~req.headers['access-control-request-headers']
                                    .split(',').map(function (header) {
                                      return header.trim();
                                    }).indexOf('authorization');

      if (hasAuthInAccessControl) {
        return next();
      }
    }

    if (typeof options.skip !== 'undefined') {
      console.warn('WARN: express-jwt: options.skip is deprecated');
      console.warn('WARN: use app.use(jwt(options).unless({path: \'/x\'}))');
      if (options.skip.indexOf(req.url) > -1) {
        return next();
      }
    }

    if (options.getToken && typeof options.getToken === 'function') {
      try {
        token = options.getToken(req);
      } catch (e) {
        return next(e);
      }
    } else if (req.headers && req.headers.authorization) {
      var parts = req.headers.authorization.split(' ');
      if (parts.length == 2) {
        var scheme = parts[0];
        var credentials = parts[1];

        if (/^Bearer$/i.test(scheme)) {
          token = credentials;
        }
      } else {
        return next(new UnauthorizedError('credentials_bad_format', { message: 'Format is Authorization: Bearer [token]' }));
      }
    }

    if (!token) {
      if (credentialsRequired) {
        return next(new UnauthorizedError('credentials_required', { message: 'No authorization token was found' }));
      } else {
        return next();
      }
    }

    jwt.verify(token, options.secret, options, function(err, decoded) {
      if (err && credentialsRequired) return next(new UnauthorizedError('invalid_token', err));

      req[_userProperty] = decoded;
      next();
    });
  };

  middleware.unless = unless;

  return middleware;
};
<commit_msg>Update index.js<commit_after>var jwt = require('jsonwebtoken');
var UnauthorizedError = require('./errors/UnauthorizedError');
var unless = require('express-unless');

module.exports = function(options) {
  if (!options || !options.secret) throw new Error('secret should be set');

  var _userProperty = options.userProperty || 'user';
  var credentialsRequired = typeof options.credentialsRequired === 'undefined' ? true : options.credentialsRequired;

  var middleware = function(req, res, next) {
    var token;

    if (req.method === 'OPTIONS' && req.headers.hasOwnProperty('access-control-request-headers')) {
      var hasAuthInAccessControl = !!~req.headers['access-control-request-headers']
                                    .split(',').map(function (header) {
                                      return header.trim();
                                    }).indexOf('authorization');

      if (hasAuthInAccessControl) {
        return next();
      }
    }

    if (typeof options.skip !== 'undefined') {
      console.warn('WARN: express-jwt: options.skip is deprecated');
      console.warn('WARN: use app.use(jwt(options).unless({path: \'/x\'}))');
      if (options.skip.indexOf(req.url) > -1) {
        return next();
      }
    }

    if (options.getToken && typeof options.getToken === 'function') {
      try {
        token = options.getToken(req);
      } catch (e) {
        return next(e);
      }
    } else if (req.headers && req.headers.authorization) {
      var parts = req.headers.authorization.split(' ');
      if (parts.length == 2) {
        var scheme = parts[0];
        var credentials = parts[1];

        if (/^Bearer$/i.test(scheme)) {
          token = credentials;
        } else {
          return next(new UnauthorizedError('credentials_bad_scheme', { message: 'Scheme is Bearer'}));
        }
      } else {
        return next(new UnauthorizedError('credentials_bad_format', { message: 'Format is Authorization: Bearer [token]' }));
      }
    }

    if (!token) {
      if (credentialsRequired) {
        return next(new UnauthorizedError('credentials_required', { message: 'No authorization token was found' }));
      } else {
        return next();
      }
    }

    jwt.verify(token, options.secret, options, function(err, decoded) {
      if (err && credentialsRequired) return next(new UnauthorizedError('invalid_token', err));

      req[_userProperty] = decoded;
      next();
    });
  };

  middleware.unless = unless;

  return middleware;
};
<|endoftext|>


<commit_before>var Transform = require('stream').Transform;
var util      = require('util');
var clarinet  = require('clarinet');

/**
 * @constructor
 * @extends {Transform}
 */
var JStream = module.exports = function(path) {
  Transform.call(this, { objectMode: true });

  var parser = this.parser = new clarinet.createStream();
  var self = this;
  var stack = [];
  var currObj = {};
  var currKey = 'root';
  var inArray;
  var pathMatch = true;
  var parentPathMatch = true;
  var comparator;

  if (path) {
    // Add some listeners only if path is given.
    var onvaluepath = function onvaluepath(value) {
      if (pathMatch && stack.length === path.length &&
          match(currKey, comparator)) {
        self.push(value);
      }
    };

    var onopenpath = function onopenpath() {
      if (stack.length) {
        parentPathMatch = pathMatch = parentPathMatch &&
          comparator !== undefined &&
          match(currKey, comparator);
      }

      comparator = path[stack.length];
    };

    parser.on('value', onvaluepath);
    parser.on('openobject', onopenpath);
    parser.on('openarray', onopenpath);
  }

  parser.on('value', function onvalue(value) {
    currObj[currKey] = value;
    if (inArray) {
      currKey++;
    }
  });

  parser.on('key', function onkey(key) {
    currKey = key;
  });

  function onopen(key) {
    var obj, openArray;

    if (key === undefined) {
      // openarray
      obj = currObj[currKey] = [];
      openArray = true;
      key = 0;

    } else {
      // openobject
      obj = currObj[currKey] = {};
      openArray = false;
    }

    stack.push({
      obj  : currObj,
      key  : currKey + (inArray ? 1 : ''),
      arr  : inArray,
      path : pathMatch
    });

    currObj = obj;
    currKey = key;
    inArray = openArray;
  }

  function onclose() {
    var current = stack.pop();
    currObj     = current.obj;
    currKey     = current.key;
    inArray     = current.arr;
    parentPathMatch = stack.length ? stack[stack.length - 1].path : true;
  }

  parser.on('openobject', onopen);
  parser.on('closeobject', onclose);
  parser.on('openarray', onopen);
  parser.on('closearray', onclose);

  parser.on('error', function onerror(err) {
    self.readable = false;
    self.writable = false;
    parser.emit = function() {};
    self.emit('error', err);
  });

  parser.on('end', self.push.bind(self, null));

  if (path) {
    var onclosepath = function onclosepath() {
      if (pathMatch && stack.length === path.length) {
        self.push(currObj[currKey]);
      }
      comparator = path[stack.length - 1];
    };

    parser.on('closeobject', onclosepath);
    parser.on('closearray', onclosepath);

  } else {
    // If `path` is not given, emit `data` event whenever a full
    // objectd on the root is parsed.
    parser.on('closeobject', function onobjectavailable() {
      if (!stack.length || stack.length === 1 && inArray) {
        var key = inArray ? currKey - 1 : currKey;
        self.push(currObj[key]);
      }
    });
  }

};
util.inherits(JStream, Transform);

/**
 * Writes to the parser.
 *
 * @param {Buffer|String} chunk
 * @param {String} encoding
 * @param {Function(!Error)} callback
 */
JStream.prototype._transform = function(chunk, encoding, callback) {
  this.parser.write(chunk);
  callback(null);
};

/**
 * Compare a key against a string, Number, RegExp, Boolean, or Function.
 *
 * @param {String} key
 * @param {String|Number|RegExp|Boolean|Function} comparator
 * @return {Boolean}
 */
function match(key, comparator) {
  switch (typeof comparator) {
    case 'string':
    case 'number':
      return key === comparator;

    case 'boolean':
      return comparator;

    case 'function':
      return comparator(key);

    case 'object':
      if (comparator instanceof RegExp) {
        return comparator.test(key);
      }
      break;

  }

  throw new TypeError('Path object not supported.');
}
<commit_msg>expose MAX_BUFFER_LENGTH from clarinet (fixes #3)<commit_after>var Transform = require('stream').Transform;
var util      = require('util');
var clarinet  = require('clarinet');

/**
 * @constructor
 * @extends {Transform}
 */
var JStream = module.exports = function(path) {
  Transform.call(this, { objectMode: true });

  var parser = this.parser = new clarinet.createStream();
  var self = this;
  var stack = [];
  var currObj = {};
  var currKey = 'root';
  var inArray;
  var pathMatch = true;
  var parentPathMatch = true;
  var comparator;

  if (path) {
    // Add some listeners only if path is given.
    var onvaluepath = function onvaluepath(value) {
      if (pathMatch && stack.length === path.length &&
          match(currKey, comparator)) {
        self.push(value);
      }
    };

    var onopenpath = function onopenpath() {
      if (stack.length) {
        parentPathMatch = pathMatch = parentPathMatch &&
          comparator !== undefined &&
          match(currKey, comparator);
      }

      comparator = path[stack.length];
    };

    parser.on('value', onvaluepath);
    parser.on('openobject', onopenpath);
    parser.on('openarray', onopenpath);
  }

  parser.on('value', function onvalue(value) {
    currObj[currKey] = value;
    if (inArray) {
      currKey++;
    }
  });

  parser.on('key', function onkey(key) {
    currKey = key;
  });

  function onopen(key) {
    var obj, openArray;

    if (key === undefined) {
      // openarray
      obj = currObj[currKey] = [];
      openArray = true;
      key = 0;

    } else {
      // openobject
      obj = currObj[currKey] = {};
      openArray = false;
    }

    stack.push({
      obj  : currObj,
      key  : currKey + (inArray ? 1 : ''),
      arr  : inArray,
      path : pathMatch
    });

    currObj = obj;
    currKey = key;
    inArray = openArray;
  }

  function onclose() {
    var current = stack.pop();
    currObj     = current.obj;
    currKey     = current.key;
    inArray     = current.arr;
    parentPathMatch = stack.length ? stack[stack.length - 1].path : true;
  }

  parser.on('openobject', onopen);
  parser.on('closeobject', onclose);
  parser.on('openarray', onopen);
  parser.on('closearray', onclose);

  parser.on('error', function onerror(err) {
    self.readable = false;
    self.writable = false;
    parser.emit = function() {};
    self.emit('error', err);
  });

  parser.on('end', self.push.bind(self, null));

  if (path) {
    var onclosepath = function onclosepath() {
      if (pathMatch && stack.length === path.length) {
        self.push(currObj[currKey]);
      }
      comparator = path[stack.length - 1];
    };

    parser.on('closeobject', onclosepath);
    parser.on('closearray', onclosepath);

  } else {
    // If `path` is not given, emit `data` event whenever a full
    // objectd on the root is parsed.
    parser.on('closeobject', function onobjectavailable() {
      if (!stack.length || stack.length === 1 && inArray) {
        var key = inArray ? currKey - 1 : currKey;
        self.push(currObj[key]);
      }
    });
  }

};
util.inherits(JStream, Transform);

// Expose `MAX_BUFFER_LENGTH` from parsing module.
JStream.__defineGetter__('MAX_BUFFER_LENGTH', function() {
  return clarinet.MAX_BUFFER_LENGTH;
});

JStream.__defineSetter__('MAX_BUFFER_LENGTH', function(val) {
  clarinet.MAX_BUFFER_LENGTH = val;
});

/**
 * Writes to the parser.
 *
 * @param {Buffer|String} chunk
 * @param {String} encoding
 * @param {Function(!Error)} callback
 */
JStream.prototype._transform = function(chunk, encoding, callback) {
  this.parser.write(chunk);
  callback(null);
};

/**
 * Compare a key against a string, Number, RegExp, Boolean, or Function.
 *
 * @param {String} key
 * @param {String|Number|RegExp|Boolean|Function} comparator
 * @return {Boolean}
 */
function match(key, comparator) {
  switch (typeof comparator) {
    case 'string':
    case 'number':
      return key === comparator;

    case 'boolean':
      return comparator;

    case 'function':
      return comparator(key);

    case 'object':
      if (comparator instanceof RegExp) {
        return comparator.test(key);
      }
      break;

  }

  throw new TypeError('Path object not supported.');
}
<|endoftext|>


<commit_before>import {isFunction} from 'util';
import {sign, decode, verify} from 'jsonwebtoken';
import set from 'lodash.set';
import UnauthorizedError from './errors/unauthorized-error';

export default function (options) {
  let opts = options || {};

  if (!opts.secret) {
    throw new Error('Secret must be passed!');
  }

  if (opts.checkRevoked && !isFunction(opts.checkRevoked)) {
    throw new Error('Token revocation must be a function!');
  }

  const {
    secret,
    requestProperty = "user",
    isRevoked = false
  } = opts;

  const middleware = async(request, response) => {
    if (!validCorsPreflight(request)) {
      const accessToken = getTokenFromHeader(request);

      try {
        const decodedAccessToken = verify(accessToken, secret);

        if (isRevoked) {
          if (await isRevoked(request, decodedAccessToken)) {
            throw new UnauthorizedError('Token has been revoked');
          }
        }

        set(request, requestProperty, decodedAccessToken);
      } catch (e) {
        throw new UnauthorizedError(e.message);
      }
    }
  };

  return middleware;
}

/**
 * Checks if an OPTIONS request with the access-control-request-headers containing authorization is being made
 * @param request
 * @returns {boolean}
 */
function validCorsPreflight(request) {
  if (request.method === 'OPTIONS' && request.headers.has('access-control-request-headers')) {
    return request.headers.get('access-control-request-headers').split(',').map(function (header) {
      return header.trim();
    }).includes('authorization');
  } else {
    return false;
  }
}

/**
 * Retrieves the JWT from the authorization header
 * @param request
 * @returns {string} The JWT
 */
function getTokenFromHeader(request) {
  if (!request.headers || !request.headers.has('authorization')) {
    throw new UnauthorizedError('No authorization header present');
  }

  const parts = request.headers.get('authorization').split(" ");

  if (parts.length === 2) {
    const scheme = parts[0];
    const credentials = parts[1];

    if (/^Bearer$/i.test(scheme)) {
      return credentials;
    } else {
      throw new UnauthorizedError('Bad Authorization header format. Format is "Authorization: Bearer token"');
    }
  } else {
    throw new UnauthorizedError('Bad Authorization header format. Format is "Authorization: Bearer token"');
  }
}

export {sign, decode, verify};
<commit_msg>isRevoked instead of checkRevoked<commit_after>import {isFunction} from 'util';
import {sign, decode, verify} from 'jsonwebtoken';
import set from 'lodash.set';
import UnauthorizedError from './errors/unauthorized-error';

export default function (options) {
  let opts = options || {};

  if (!opts.secret) {
    throw new Error('Secret must be passed!');
  }

  if (opts.isRevoked && !isFunction(opts.isRevoked)) {
    throw new Error('Token revocation must be a function!');
  }

  const {
    secret,
    requestProperty = "user",
    isRevoked = false
  } = opts;

  return async(request, response) => {
    if (!validCorsPreflight(request)) {
      const accessToken = getTokenFromHeader(request);

      try {
        const decodedAccessToken = verify(accessToken, secret);

        if (isRevoked) {
          if (await isRevoked(request, decodedAccessToken)) {
            throw new UnauthorizedError('Token has been revoked');
          }
        }

        set(request, requestProperty, decodedAccessToken);
      } catch (e) {
        throw new UnauthorizedError(e.message);
      }
    }
  };
}

/**
 * Checks if an OPTIONS request with the access-control-request-headers containing authorization is being made
 * @param request
 * @returns {boolean}
 */
function validCorsPreflight(request) {
  if (request.method === 'OPTIONS' && request.headers.has('access-control-request-headers')) {
    return request.headers.get('access-control-request-headers').split(',').map(function (header) {
      return header.trim();
    }).includes('authorization');
  } else {
    return false;
  }
}

/**
 * Retrieves the JWT from the authorization header
 * @param request
 * @returns {string} The JWT
 */
function getTokenFromHeader(request) {
  if (!request.headers || !request.headers.has('authorization')) {
    throw new UnauthorizedError('No authorization header present');
  }

  const parts = request.headers.get('authorization').split(" ");

  if (parts.length === 2) {
    const scheme = parts[0];
    const credentials = parts[1];

    if (/^Bearer$/i.test(scheme)) {
      return credentials;
    } else {
      throw new UnauthorizedError('Bad Authorization header format. Format is "Authorization: Bearer token"');
    }
  } else {
    throw new UnauthorizedError('Bad Authorization header format. Format is "Authorization: Bearer token"');
  }
}

export {sign, decode, verify};
<|endoftext|>


<commit_before>"use strict";

var Model = require('./model');

module.exports = new Restifier();
module.exports.__resError = false;

function Restifier() {
  this.prefix = '';
}

Restifier.prototype.setup = function setup(app) {
  app.use(require('res-error'));
};

Restifier.prototype.model = function(mongooseModel) {
  return new Model(this, mongooseModel);
};
<commit_msg>Disable resError logging<commit_after>"use strict";

var Model = require('./model');

module.exports = new Restifier();
module.exports.__resError = false;

function Restifier() {
  this.prefix = '';
}

Restifier.prototype.setup = function setup(app) {
  app.use(require('res-error')({
    log: false
  }));
};

Restifier.prototype.model = function(mongooseModel) {
  return new Model(this, mongooseModel);
};
<|endoftext|>


<commit_before>/* @flow */

export type AccessObject = mixed
export type AccessSubject = mixed
export type AccessOperation = string
export type AccessRule = (object: AccessObject, subject: AccessSubject, operation: AccessOperation) => boolean

export var OP_GET = 'OP_GET'
export var OP_POST = 'OP_POST'
export var OP_PATCH = 'OP_PATCH'
export var OP_DELETE = 'OP_DELETE'

export var OP = {
  GET: OP_GET,
  POST: OP_POST,
  PATCH: OP_PATCH,
  DELETE: OP_DELETE
}

export function allow(object: AccessObject, subject: AccessSubject, operation: AccessOperation): boolean {
  return true
}

export function deny(object: AccessObject, subject: AccessSubject, operation: AccessOperation): boolean {
  return false
}

export function authorized(object: AccessObject, subject: AccessSubject, operation: AccessOperation): boolean {
  return !!subject
}

export type EveryRule = (rules: Array<AccessRule>) => AccessRule
export function everyRule(rules: Array<AccessRule>): AccessRule {
  return function(object: AccessObject, subject: AccessSubject, operation: AccessOperation): boolean {
    return rules.every(rule => rule(object, subject, operation))
  }
}

export type SomeRule = (rules: Array<AccessRule>) => AccessRule
export function someRule(rules: Array<AccessRule>): AccessRule {
  return function(object: AccessObject, subject: AccessSubject, operation: AccessOperation): boolean {
    return rules.some(rule => rule(object, subject, operation))
  }
}

export type ByOperationSchema = {[key: AccessOperation]: AccessRule}
export type ByOperation = (schema: ByOperationSchema) => AccessRule
export function byOperation(schema: ByOperationSchema): AccessRule {
  return function(object: AccessObject, subject: AccessSubject, operation: AccessOperation): boolean {
    return schema[operation](object, subject, operation)
  }
}
<commit_msg>Async rules<commit_after>/* @flow */

export type AccessObject = mixed
export type AccessSubject = mixed
export type AccessOperation = string
export type AccessRule = (
  object: AccessObject,
  subject: AccessSubject,
  operation: AccessOperation
) => Promise<boolean>

export var OP_GET = 'OP_GET'
export var OP_POST = 'OP_POST'
export var OP_PATCH = 'OP_PATCH'
export var OP_DELETE = 'OP_DELETE'

export var OP = {
  GET: OP_GET,
  POST: OP_POST,
  PATCH: OP_PATCH,
  DELETE: OP_DELETE
}

export function allow(object: AccessObject, subject: AccessSubject, operation: AccessOperation): Promise<boolean> {
  return Promise.resolve(true)
}

export function deny(object: AccessObject, subject: AccessSubject, operation: AccessOperation): Promise<boolean> {
  return Promise.resolve(false)
}

export function authorized(object: AccessObject, subject: AccessSubject, operation: AccessOperation): Promise<boolean> {
  return Promise.resolve(!!subject)
}

export type EveryRule = (rules: Array<AccessRule>) => AccessRule
export function everyRule(rules: Array<AccessRule>): AccessRule {
  return function(object: AccessObject, subject: AccessSubject, operation: AccessOperation): Promise<boolean> {
    return Promise.all(
      rules.map(rule => rule(object, subject, operation))
    ).then(results => results.every(result => result))
  }
}

export type SomeRule = (rules: Array<AccessRule>) => AccessRule
export function someRule(rules: Array<AccessRule>): AccessRule {
  return function(object: AccessObject, subject: AccessSubject, operation: AccessOperation): Promise<boolean> {
    return Promise.all(
      rules.map(rule => rule(object, subject, operation))
    ).then(results => results.some(result => result))
  }
}

export type ByOperationSchema = {[key: AccessOperation]: AccessRule}
export type ByOperation = (schema: ByOperationSchema) => AccessRule
export function byOperation(schema: ByOperationSchema): AccessRule {
  return function(object: AccessObject, subject: AccessSubject, operation: AccessOperation): Promise<boolean> {
    return schema[operation](object, subject, operation)
  }
}
<|endoftext|>


<commit_before>'use strict';

//var moment = require('moment');

var fs = require('fs');

var length_remaining = 0
var section_0 = {};

var section_1 = {};

var section_2 = {};
var section_3 = {};
var section_4 = {};
var section_5 = {};
var section_6 = {};
var section_7 = {};
var section_8 = {};

var readSection0 = function(buf) {
  var section = {};

  section['discipline'] = buf.readUInt8(0);
  section['edition'] = buf.readUInt8(1);
  section['total_length'] = (buf.readUInt32BE(2) << 8) + buf.readUInt32BE(6);
  return section;
};

var readSection1 = function(buf) {
  var section = {};

  section['length'] = buf.readUInt32BE(0);
  section['id'] = buf.readUInt8(4);
  section['origin_center'] = buf.readUInt16BE(5);
  section['origin_subcenter'] = buf.readUInt16BE(7);
  section['master_version'] = buf.readUInt8(9);
  section['local_version'] = buf.readUInt8(10);
  section['time_significance'] = buf.readUInt8(11);
  var year = buf.readUInt16BE(12);
  var month = buf.readUInt8(14) - 1; //month appears to be zero based
  var day = buf.readUInt8(15);
  var hour = buf.readUInt8(16);
  var minute = buf.readUInt8(17);
  var second = buf.readUInt8(18);
  section['timestamp'] = new Date(year, month, day, hour, minute, second);
  section['production_status'] = buf.readUInt8(19);
  section['data_type'] = buf.readUInt8(20);

  return section;
};

var readSection2 = function(buf) {
  var section = {};

  section['length'] = buf.readUInt32BE(0);
  section['id'] = buf.readUInt8(4);
  section['data'] = buf.slice(5, 5+section.length-1);

  return section;
};

var readSection3 = function(buf) {
  var section = {};

  return section;
};

var readSection4 = function(buf) {
  var section = {};

  return section;
};

var readSection5 = function(buf) {
  var section = {};

  return section;
};

var readSection6 = function(buf) {
  var section = {};

  return section;
};

var readSection7 = function(buf) {
  var section = {};

  return section;
};

module.exports.parse = function (filename) {
  var buf = fs.readFileSync(filename);
  buf = buf.slice(45);

  section_0 = readSection0(buf);
  length_remaining = section_0.total_length - 16;
  console.log('section 0: ');
  console.log(section_0);
  buf = buf.slice(5);

  section_1 = readSection1(buf);
  length_remaining -= section_1.length;
  console.log('section 1: ');
  console.log(section_1);
  buf = buf.slice(section_1.length);

  section_2 = readSection2(buf);
  length_remaining -= section_2.length;
  console.log('section 2: ');
  console.log(section_2);
  buf = buf.slice(section_2.length);

//  for (var i = 37; i < 60; i++) {
//    console.log(i+': '+contents[i]);
//  }

  return 'test';
}

var test = 'test';
<commit_msg>slicing the buffer<commit_after>'use strict';

//var moment = require('moment');

var fs = require('fs');

var length_remaining = 0
var section_0 = {};

var section_1 = {};

var section_2 = {};
var section_3 = {};
var section_4 = {};
var section_5 = {};
var section_6 = {};
var section_7 = {};
var section_8 = {};

var readSection0 = function(buf) {
  var section = {};

  section['discipline'] = buf.readUInt8(6);
  section['edition'] = buf.readUInt8(7);
  section['total_length'] = (buf.readUInt32BE(8) << 8) + buf.readUInt32BE(12);
  return section;
};

var readSection1 = function(buf) {
  var section = {};

  section['length'] = buf.readUInt32BE(0);
  section['id'] = buf.readUInt8(4);
  section['origin_center'] = buf.readUInt16BE(5);
  section['origin_subcenter'] = buf.readUInt16BE(7);
  section['master_version'] = buf.readUInt8(9);
  section['local_version'] = buf.readUInt8(10);
  section['time_significance'] = buf.readUInt8(11);
  var year = buf.readUInt16BE(12);
  var month = buf.readUInt8(14) - 1; //month appears to be zero based
  var day = buf.readUInt8(15);
  var hour = buf.readUInt8(16);
  var minute = buf.readUInt8(17);
  var second = buf.readUInt8(18);
  section['timestamp'] = new Date(year, month, day, hour, minute, second);
  section['production_status'] = buf.readUInt8(19);
  section['data_type'] = buf.readUInt8(20);

  return section;
};

var readSection2 = function(buf) {
  var section = {};

  section['length'] = buf.readUInt32BE(0);
  section['id'] = buf.readUInt8(4);
  section['data'] = buf.slice(5, 5+section.length-1);

  return section;
};

var readSection3 = function(buf) {
  var section = {};

  return section;
};

var readSection4 = function(buf) {
  var section = {};

  return section;
};

var readSection5 = function(buf) {
  var section = {};

  return section;
};

var readSection6 = function(buf) {
  var section = {};

  return section;
};

var readSection7 = function(buf) {
  var section = {};

  return section;
};

module.exports.parse = function (filename) {
  var buf = fs.readFileSync(filename);
  buf = buf.slice(39);

  section_0 = readSection0(buf);
  length_remaining = section_0.total_length - 16;
  console.log('section 0: ');
  console.log(section_0);
  buf = buf.slice(16);

  section_1 = readSection1(buf);
  length_remaining -= section_1.length;
  console.log('section 1: ');
  console.log(section_1);
  buf = buf.slice(section_1.length);

  section_2 = readSection2(buf);
  length_remaining -= section_2.length;
  console.log('section 2: ');
  console.log(section_2);
  buf = buf.slice(section_2.length);

//  for (var i = 37; i < 60; i++) {
//    console.log(i+': '+contents[i]);
//  }

  return 'test';
}

var test = 'test';
<|endoftext|>