Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

spinjs

Package Overview
Dependencies
Maintainers
1
Versions
225
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

spinjs - npm Package Compare versions

Comparing version 0.1.10 to 0.1.11

lib/ConfigPlugin.d.ts

6

lib/Builder.d.ts

@@ -1,7 +0,11 @@

import Stack from "./Stack";
import Stack from './Stack';
export interface Builder {
name: string;
enabled: boolean;
stack: Stack;
roles: string[];
parent?: Builder;
child?: Builder;
config?: any;
[x: string]: any;
}

2

lib/configRc.d.ts

@@ -1,2 +0,2 @@

import { Builder } from "./Builder";
import { Builder } from './Builder';
export default class ConfigRc {

@@ -3,0 +3,0 @@ options: any;

@@ -25,5 +25,2 @@ "use strict";

var builder = (typeof builderVal === 'object' && builderVal.constructor !== Array) ? __assign({}, builderVal) : { stack: builderVal };
if (builder.enabled === false) {
continue;
}
builder.name = name;

@@ -30,0 +27,0 @@ builder.stack = new Stack_1.default(config.options.stack, typeof builder === 'object' ? builder.stack : builder);

@@ -51,3 +51,3 @@ "use strict";

var requireModule_1 = require("./requireModule");
var liveReloadMiddleware_1 = require("./react-native/liveReloadMiddleware");
var liveReloadMiddleware_1 = require("./plugins/react-native/liveReloadMiddleware");
var VirtualModules = requireModule_1.default('webpack-virtual-modules');

@@ -155,3 +155,2 @@ var expoPorts = {};

};
config.plugins.push(frontendVirtualModules);
if (watch) {

@@ -297,3 +296,3 @@ if (config.devServer.hot) {

var vendorHashesJson, vendorSourceListMap, vendorSource, vendorMap;
if (options.webpackDll && builder.dllConfig) {
if (options.webpackDll && builder.child) {
var name = "vendor_" + platform;

@@ -340,3 +339,3 @@ var jsonPath = path.join(options.dllBuildDir, name + "_dll.json");

});
if (options.webpackDll && builder.dllConfig && platform !== 'web') {
if (options.webpackDll && builder.child && platform !== 'web') {
compiler.plugin('after-compile', function (compilation, callback) {

@@ -358,3 +357,3 @@ _.each(compilation.chunks, function (chunk) {

}
if (options.webpackDll && builder.dllConfig && platform === 'web' && !hasBackend) {
if (options.webpackDll && builder.child && platform === 'web' && !hasBackend) {
compiler.plugin('after-compile', function (compilation, callback) {

@@ -469,3 +468,3 @@ compilation.assets[vendorHashesJson.name] = vendorSource;

}
app.use(webpackDevMiddleware(compiler, _.merge({}, config.devServer, {
var devMiddleware = webpackDevMiddleware(compiler, _.merge({}, config.devServer, {
reporter: function (_a) {

@@ -481,3 +480,16 @@ var state = _a.state, stats = _a.stats;

},
})))
}));
app.use(function (req, res, next) {
if (platform !== 'web') {
var origSetHeader_1 = res.setHeader;
res.setHeader = function (key, value) {
var val = value;
if (key === 'Content-Type' && value.indexOf('application/javascript') >= 0) {
val = value.split(';')[0];
}
origSetHeader_1.call(res, key, val);
};
}
return devMiddleware(req, res, next);
})
.use(webpackHotMiddleware(compiler, { log: false }));

@@ -837,4 +849,4 @@ if (config.devServer.proxy) {

return "continue";
var prepareDllPromise = (cmd === 'watch' && options.webpackDll && builder.dllConfig) ?
buildDll(stack.platform, builder.dllConfig, options) : Promise.resolve();
var prepareDllPromise = (cmd === 'watch' && options.webpackDll && builder.child) ?
buildDll(stack.platform, builder.child.config, options) : Promise.resolve();
prepareDllPromise.then(function () {

@@ -841,0 +853,0 @@ return startWebpack(platforms_1, watch_1, builder, options);

@@ -1,2 +0,4 @@

declare const createConfig: (builder: any, builders: any, dev: any, opts: any, depPlatforms?: any) => any;
import { Builder } from "./Builder";
import Spin from "./Spin";
declare const createConfig: (builder: Builder, spin: Spin) => any;
export default createConfig;

@@ -16,112 +16,8 @@ "use strict";

var pkg = requireModule_1.default('./package.json');
var mobileAssetTest = /\.(bmp|gif|jpg|jpeg|png|psd|svg|webp|m4v|aac|aiff|caf|m4a|mp3|wav|html|pdf|ttf)$/;
var babelUsed = false;
var useBabel = function () {
if (!babelUsed) {
require('babel-register')({
presets: ['es2015', 'flow'],
ignore: /node_modules(?!\/(haul|react-native))/,
retainLines: true,
sourceMaps: 'inline',
});
require('babel-polyfill');
babelUsed = true;
}
};
var createBaseConfig = function (builder, dev, options) {
var createPlugins = function (builder, spin) {
var stack = builder.stack;
var baseConfig = {
name: builder.name,
devtool: dev ? '#cheap-module-source-map' : '#source-map',
module: {
rules: [
{
test: /\.jsx?$/,
exclude: (stack.hasAny('react-native')) ?
/node_modules\/(?!react-native|@expo|expo|lottie-react-native|haul|pretty-format|react-navigation)$/ :
/node_modules/,
use: [].concat(options.persistGraphQL ?
['persistgraphql-webpack-plugin/js-loader'] :
[]),
},
{
test: /\.graphqls/,
use: 'raw-loader',
},
{
test: /\.(graphql|gql)$/,
exclude: /node_modules/,
use: ['graphql-tag/loader'].concat(options.persistGraphQL ?
['persistgraphql-webpack-plugin/graphql-loader'] :
[]),
},
],
},
resolve: {
extensions: stack.hasAny('server') ?
[".web.js", ".web.jsx", '.js', '.jsx'] :
["." + stack.platform + ".js", "." + stack.platform + ".jsx", '.native.js', '.native.jsx', '.js', '.jsx'],
modules: [path.join(process.cwd(), 'node_modules'), 'node_modules'],
},
watchOptions: {
ignored: /build/,
},
bail: !dev,
};
if (stack.hasAny(['web', 'server'])) {
baseConfig.resolve.alias = {
'react-native': 'react-native-web',
};
baseConfig.module.rules = baseConfig.module.rules.concat([
{
test: /\.(png|ico|jpg|xml)$/,
use: 'url-loader?name=[hash].[ext]&limit=10000',
},
{
test: /\.woff(2)?(\?v=[0-9]\.[0-9]\.[0-9])?$/,
use: 'url-loader?name=./assets/[hash].[ext]&limit=10000',
},
{
test: /\.(ttf|eot|svg)(\?v=[0-9]\.[0-9]\.[0-9])?$/,
use: 'file-loader?name=./assets/[hash].[ext]',
},
]);
}
else if (stack.hasAny('react-native')) {
baseConfig.module.rules = baseConfig.module.rules.concat([
{
test: mobileAssetTest,
use: {
loader: require.resolve('./react-native/assetLoader'),
query: { platform: stack.platform, root: path.resolve('.'), bundle: false },
},
},
]);
}
return baseConfig;
};
var persistPlugins;
var ExtractTextPlugin;
var createPlugins = function (builder, builders, dev, options) {
var stack = builder.stack;
var webpack = requireModule_1.default('webpack');
var buildNodeEnv = dev ? (stack.hasAny('test') ? 'test' : 'development') : 'production';
if (!persistPlugins) {
var PersistGraphQLPlugin = requireModule_1.default('persistgraphql-webpack-plugin');
var moduleName = path.resolve('node_modules/persisted_queries.json');
if (options.persistGraphQL) {
var clientPersistPlugin = new PersistGraphQLPlugin({ moduleName: moduleName,
filename: 'extracted_queries.json', addTypename: true });
var serverPersistPlugin = new PersistGraphQLPlugin({ moduleName: moduleName,
provider: clientPersistPlugin });
persistPlugins = { client: clientPersistPlugin, server: serverPersistPlugin };
}
else {
var clientPersistPlugin = new PersistGraphQLPlugin({ moduleName: moduleName });
var serverPersistPlugin = new PersistGraphQLPlugin({ moduleName: moduleName });
persistPlugins = { client: clientPersistPlugin, server: serverPersistPlugin };
}
}
var buildNodeEnv = spin.dev ? (stack.hasAny('test') ? 'test' : 'development') : 'production';
var plugins = [];
if (dev) {
if (spin.dev) {
plugins.push(new webpack.NamedModulesPlugin());

@@ -134,3 +30,3 @@ }

}
var backendUrl = options.backendUrl.replace('{ip}', ip.address());
var backendUrl = spin.options.backendUrl.replace('{ip}', ip.address());
if (stack.hasAny('server')) {

@@ -143,8 +39,6 @@ plugins = plugins.concat([

new webpack.DefinePlugin({
__CLIENT__: false, __SERVER__: true, __SSR__: options.ssr,
__DEV__: dev, 'process.env.NODE_ENV': "\"" + buildNodeEnv + "\"",
__PERSIST_GQL__: options.persistGraphQL,
__CLIENT__: false, __SERVER__: true, __SSR__: spin.options.ssr && !spin.test,
__DEV__: spin.dev, 'process.env.NODE_ENV': "\"" + buildNodeEnv + "\"",
__BACKEND_URL__: "\"" + backendUrl + "\"",
}),
persistPlugins.server,
]);

@@ -155,9 +49,7 @@ }

new webpack.DefinePlugin({
__CLIENT__: true, __SERVER__: false, __SSR__: options.ssr,
__DEV__: dev, 'process.env.NODE_ENV': "\"" + buildNodeEnv + "\"",
__PERSIST_GQL__: options.persistGraphQL,
__CLIENT__: true, __SERVER__: false, __SSR__: spin.options.ssr && !spin.test,
__DEV__: spin.dev, 'process.env.NODE_ENV': "\"" + buildNodeEnv + "\"",
__BACKEND_URL__: (stack.platform !== 'web' ||
url.parse(backendUrl).hostname !== 'localhost') ? "\"" + backendUrl + "\"" : false,
}),
persistPlugins.client,
]);

@@ -170,4 +62,4 @@ if (stack.hasAny('web')) {

var hasServer = false;
for (var name in builders) {
if (builders[name].stack.hasAny('server')) {
for (var name in spin.builders) {
if (spin.builders[name].stack.hasAny('server')) {
hasServer = true;

@@ -180,9 +72,7 @@ break;

plugins.push(new HtmlWebpackPlugin({
template: 'tools/html-plugin-template.ejs',
template: path.resolve('html-plugin-template.ejs'),
inject: 'body',
}));
}
if (!dev) {
ExtractTextPlugin = requireModule_1.default('extract-text-webpack-plugin');
plugins.push(new ExtractTextPlugin({ filename: '[name].[contenthash].css', allChunks: true }));
if (!spin.dev) {
plugins.push(new webpack.optimize.CommonsChunkPlugin({

@@ -197,18 +87,12 @@ name: 'vendor',

}
else if (stack.hasAny('react-native')) {
plugins.push(new webpack.SourceMapDevToolPlugin({
test: /\.(js|jsx|css|bundle)($|\?)/i,
filename: '[file].map',
}));
}
}
if (stack.hasAny('dll')) {
var name = "vendor_" + builder.parentName;
var name = "vendor_" + builder.parent.name;
plugins = [
new webpack.DefinePlugin({
__DEV__: dev, 'process.env.NODE_ENV': "\"" + buildNodeEnv + "\"",
__DEV__: spin.dev, 'process.env.NODE_ENV': "\"" + buildNodeEnv + "\"",
}),
new webpack.DllPlugin({
name: name,
path: path.join(options.dllBuildDir, name + "_dll.json"),
path: path.join(spin.options.dllBuildDir, name + "_dll.json"),
}),

@@ -224,18 +108,24 @@ ];

var val = depPlatforms[key];
if (!val || (val.constructor === Array && val.indexOf(builder.parentName) >= 0) || val === builder.parentName) {
if (!val || (val.constructor === Array && val.indexOf(builder.parent.name) >= 0) || val === builder.parent.name) {
deps.push(key);
}
}
if (builder.stack.hasAny('react-native')) {
deps = deps.concat(require.resolve('./react-native/react-native-polyfill.js'));
}
return deps;
};
var createConfig = function (builder, builders, dev, opts, depPlatforms) {
var createConfig = function (builder, spin) {
var stack = builder.stack;
var options = __assign({}, opts);
if (stack.hasAny('test')) {
options.ssr = false;
options.persistGraphQL = false;
}
var baseConfig = {
name: builder.name,
devtool: spin.dev ? '#cheap-module-source-map' : '#source-map',
module: {
rules: [],
},
resolve: {
modules: [path.join(process.cwd(), 'node_modules'), 'node_modules'],
},
watchOptions: {
ignored: /build/,
},
bail: !spin.dev,
};
var baseDevServerConfig = {

@@ -251,14 +141,6 @@ hot: true,

var config;
if (stack.hasAny('react-native')) {
useBabel();
}
var plugins = createPlugins(builder, builders, dev, options);
var plugins = createPlugins(builder, spin);
if (stack.hasAny('server')) {
var nodeExternals = requireModule_1.default('webpack-node-externals');
var nodeExternalsFn_1 = nodeExternals({
whitelist: [/(^webpack|^react-native)/],
});
config = __assign({}, createBaseConfig(builder, dev, options), { entry: {
config = __assign({}, baseConfig, { entry: {
index: [
'babel-polyfill',
'./src/server/index.js',

@@ -269,17 +151,8 @@ ],

__filename: true,
}, externals: function (context, request, callback) {
return nodeExternalsFn_1(context, request, function () {
if (request.indexOf('react-native') >= 0) {
return callback(null, 'commonjs ' + request + '-web');
}
else {
return callback.apply(this, arguments);
}
});
}, output: {
devtoolModuleFilenameTemplate: dev ? '../../[resource-path]' : undefined,
devtoolFallbackModuleFilenameTemplate: dev ? '../../[resource-path];[hash]' : undefined,
}, externals: requireModule_1.default('webpack-node-externals'), output: {
devtoolModuleFilenameTemplate: spin.dev ? '../../[resource-path]' : undefined,
devtoolFallbackModuleFilenameTemplate: spin.dev ? '../../[resource-path];[hash]' : undefined,
filename: '[name].js',
sourceMapFilename: '[name].[chunkhash].js.map',
path: path.resolve(options.backendBuildDir),
path: path.resolve(spin.options.backendBuildDir),
publicPath: '/',

@@ -289,15 +162,14 @@ }, plugins: plugins });

else if (stack.hasAny('web')) {
var backendUrl = options.backendUrl.replace('{ip}', ip.address());
var backendUrl = spin.options.backendUrl.replace('{ip}', ip.address());
var _a = url.parse(backendUrl), protocol = _a.protocol, host = _a.host;
var backendBaseUrl = protocol + '//' + host;
config = __assign({}, createBaseConfig(builder, dev, options), { entry: {
config = __assign({}, baseConfig, { entry: {
index: [
'babel-polyfill',
'./src/client/index.jsx',
'./src/client/index.js',
],
}, output: {
filename: '[name].[hash].js',
path: path.resolve(path.join(options.frontendBuildDir, 'web')),
path: path.resolve(path.join(spin.options.frontendBuildDir, 'web')),
publicPath: '/',
}, plugins: plugins, devServer: __assign({}, baseDevServerConfig, { port: options.webpackDevPort, proxy: {
}, plugins: plugins, devServer: __assign({}, baseDevServerConfig, { port: spin.options.webpackDevPort, proxy: {
'!/*.hot-update.{json,js}': {

@@ -310,7 +182,4 @@ target: backendBaseUrl,

else if (stack.hasAny('react-native')) {
var AssetResolver_1 = requireModule_1.default('haul/src/resolvers/AssetResolver');
var HasteResolver = requireModule_1.default('haul/src/resolvers/HasteResolver');
config = __assign({}, createBaseConfig(builder, dev, options), { entry: {
config = __assign({}, baseConfig, { entry: {
index: [
require.resolve('./react-native/react-native-polyfill.js'),
'./src/mobile/index.js',

@@ -321,11 +190,4 @@ ],

publicPath: '/',
path: path.resolve(path.join(options.frontendBuildDir, builder.name)),
path: path.resolve(path.join(spin.options.frontendBuildDir, builder.name)),
}, devServer: __assign({}, baseDevServerConfig, { hot: false, port: stack.hasAny('android') ? 3010 : 3020 }), plugins: plugins });
config.resolve.plugins = [
new HasteResolver({
directories: [path.resolve('node_modules/react-native')],
}),
new AssetResolver_1({ platform: stack.platform, test: mobileAssetTest }),
];
config.resolve.mainFields = ['react-native', 'browser', 'main'];
}

@@ -336,8 +198,8 @@ else {

if (stack.hasAny('dll')) {
var name = "vendor_" + builder.parentName;
var name = "vendor_" + builder.parent.name;
config = __assign({}, config, { devtool: '#cheap-module-source-map', entry: {
vendor: getDepsForNode(builder, depPlatforms),
vendor: getDepsForNode(builder, spin.depPlatforms),
}, output: {
filename: name + ".[hash]_dll.js",
path: path.resolve(options.dllBuildDir),
path: path.resolve(spin.options.dllBuildDir),
library: name,

@@ -344,0 +206,0 @@ } });

"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
var yargs = require("yargs");
var createConfig_1 = require("./createConfig");
var executor_1 = require("./executor");
if (process.argv.length >= 3) {
var cmd = process.argv[2];
var config = void 0;
if (cmd === 'watch' || cmd === 'build' || cmd === 'test') {
config = createConfig_1.default(cmd);
}
executor_1.default(cmd, config.builders, config.options);
var argv = yargs
.command('build', 'compiles package for usage in production')
.command('watch', 'launches package in development mode with hot code reload')
.command('test [mocha-webpack options]', 'runs package tests')
.demandCommand(1, '')
.help()
.version(require('../package.json').version)
.argv;
var cmd = argv._[0];
var config;
if (cmd === 'watch' || cmd === 'build' || cmd === 'test') {
config = createConfig_1.default(cmd);
}
executor_1.default(cmd, config.builders, config.options);
//# sourceMappingURL=index.js.map
import Spin from "../Spin";
import { SpinPlugin } from "../SpinPlugin";
import { ConfigPlugin } from "../ConfigPlugin";
import { Builder } from "../Builder";
export default class CssProcessorPlugin implements SpinPlugin {
configure(builder: Builder, spin: Spin): Object;
export default class CssProcessorPlugin implements ConfigPlugin {
configure(builder: Builder, spin: Spin): void;
}
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
var requireModule_1 = require("../requireModule");
var createCssPreprocessorRules = function (dev, stack) {
var createRule;
if (stack.hasAny('server')) {
createRule = function (prep, ext) { return ({
test: new RegExp("." + ext + "$"),
use: dev ? [
{ loader: 'isomorphic-style-loader' },
{ loader: 'css-loader', options: { sourceMap: true } },
{ loader: 'postcss-loader', options: { sourceMap: true } },
{ loader: prep + "-loader", options: { sourceMap: true } }
] :
[{ loader: 'ignore-loader' }],
}); };
}
else if (stack.hasAny('web')) {
createRule = function (prep, ext) { return ({
test: new RegExp("." + ext + "$"),
use: dev ? [
{ loader: 'style-loader' },
{ loader: 'css-loader', options: { sourceMap: true, importLoaders: 1 } },
{ loader: 'postcss-loader', options: { sourceMap: true } },
{ loader: prep + "-loader", options: { sourceMap: true } },
] : requireModule_1.default('extract-text-webpack-plugin').extract({
fallback: 'style-loader',
use: ['css-loader', 'postcss-loader', prep + "-loader"],
}),
}); };
}
var rules = [];
if (createRule && stack.hasAny('sass')) {
rules.push(createRule('sass', 'scss'));
}
if (createRule && stack.hasAny('less')) {
rules.push(createRule('less', 'less'));
}
return rules;
};
var CssProcessorPlugin = (function () {

@@ -45,7 +8,50 @@ function CssProcessorPlugin() {

CssProcessorPlugin.prototype.configure = function (builder, spin) {
return {
module: {
rules: createCssPreprocessorRules(spin.dev, builder.stack)
var stack = builder.stack;
var dev = spin.dev;
if (stack.hasAll('webpack')) {
var createRule = void 0;
var rules = [];
if (stack.hasAny('server')) {
createRule = function (prep, ext) { return ({
test: new RegExp("." + ext + "$"),
use: dev ? [
{ loader: 'isomorphic-style-loader' },
{ loader: 'css-loader', options: { sourceMap: true } },
{ loader: 'postcss-loader', options: { sourceMap: true } },
{ loader: prep + "-loader", options: { sourceMap: true } }
] :
[{ loader: 'ignore-loader' }],
}); };
}
};
else if (stack.hasAny('web')) {
var ExtractTextPlugin_1;
if (!dev) {
ExtractTextPlugin_1 = requireModule_1.default('extract-text-webpack-plugin');
builder.config.plugins.push(new ExtractTextPlugin_1({ filename: '[name].[contenthash].css', allChunks: true }));
}
createRule = function (prep, ext) { return ({
test: new RegExp("." + ext + "$"),
use: dev ? [
{ loader: 'style-loader' },
{ loader: 'css-loader', options: { sourceMap: true, importLoaders: 1 } },
{ loader: 'postcss-loader', options: { sourceMap: true } },
{ loader: prep + "-loader", options: { sourceMap: true } },
] : ExtractTextPlugin_1.extract({
fallback: 'style-loader',
use: ['css-loader', 'postcss-loader', prep + "-loader"],
}),
}); };
}
if (createRule && stack.hasAny('sass')) {
rules.push(createRule('sass', 'scss'));
}
if (createRule && stack.hasAny('less')) {
rules.push(createRule('less', 'less'));
}
builder.config = spin.merge(builder.config, {
module: {
rules: rules
}
});
}
};

@@ -52,0 +58,0 @@ return CssProcessorPlugin;

@@ -1,6 +0,6 @@

import { SpinPlugin } from '../SpinPlugin';
import { ConfigPlugin } from '../ConfigPlugin';
import { Builder } from '../Builder';
import Spin from '../Spin';
export default class ES6Plugin implements SpinPlugin {
configure(builder: Builder, spin: Spin): Object;
export default class ES6Plugin implements ConfigPlugin {
configure(builder: Builder, spin: Spin): void;
}
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
var requireModule_1 = require("../requireModule");
var JSRuleFinder_1 = require("./shared/JSRuleFinder");
var ES6Plugin = (function () {

@@ -8,5 +9,4 @@ function ES6Plugin() {

ES6Plugin.prototype.configure = function (builder, spin) {
var rules = [];
if (builder.stack.hasAny(['es6', 'react-native'])) {
var babelRule_1 = {
if (builder.stack.hasAll(['es6', 'webpack'])) {
var babelRule = {
loader: requireModule_1.default.resolve('babel-loader'),

@@ -24,46 +24,17 @@ options: {

requireModule_1.default.resolve('babel-plugin-transform-class-properties'),
[requireModule_1.default.resolve('babel-plugin-styled-components'), { 'ssr': spin.options.ssr }],
].concat(spin.dev && spin.options.reactHotLoader ? [requireModule_1.default.resolve('react-hot-loader/babel')] : []),
only: ['*.js', '*.jsx'],
only: ['*.js'].concat(builder.stack.hasAny(['react', 'react-native']) ? ['*.jsx'] : []),
},
};
var reactNativeRule_1;
if (builder.stack.hasAny('react-native')) {
reactNativeRule_1 = {
loader: requireModule_1.default.resolve('babel-loader'),
options: {
cacheDirectory: spin.dev,
presets: [requireModule_1.default.resolve('babel-preset-react-native')],
plugins: [
requireModule_1.default.resolve('haul/src/utils/fixRequireIssues'),
],
if (builder.stack.hasAny('es6') && !builder.stack.hasAny('dll')) {
builder.config = spin.merge({
entry: {
index: ['babel-polyfill'],
},
};
}, builder.config);
}
rules.push({
test: /\.jsx?$/,
exclude: builder.stack.hasAny(['react-native']) ?
/node_modules\/(?!react-native|@expo|expo|lottie-react-native|haul|pretty-format|react-navigation)$/ :
/node_modules/,
use: [
(builder.stack.hasAny(['react-native']) ?
function (req) {
var result;
if (req.resource.indexOf('node_modules') >= 0) {
result = reactNativeRule_1;
}
else {
result = babelRule_1;
}
return result;
} :
babelRule_1),
],
});
var jsRule = JSRuleFinder_1.default(builder);
jsRule.exclude = /node_modules/;
jsRule.use = babelRule;
}
return {
module: {
rules: rules,
}
};
};

@@ -70,0 +41,0 @@ return ES6Plugin;

@@ -14,3 +14,2 @@ "use strict";

var configRc_1 = require("./configRc");
var generator_1 = require("./generator");
var Stack_1 = require("./Stack");

@@ -21,2 +20,9 @@ var requireModule_1 = require("./requireModule");

var ES6Plugin_1 = require("./plugins/ES6Plugin");
var ApolloPlugin_1 = require("./plugins/ApolloPlugin");
var ReactNativePlugin_1 = require("./plugins/ReactNativePlugin");
var ReactNativeWebPlugin_1 = require("./plugins/ReactNativeWebPlugin");
var StyledComponentsPlugin_1 = require("./plugins/StyledComponentsPlugin");
var WebAssetsPlugin_1 = require("./plugins/WebAssetsPlugin");
var ReactPlugin_1 = require("./plugins/ReactPlugin");
var WebpackPlugin_1 = require("./plugins/WebpackPlugin");
var WEBPACK_OVERRIDES_NAME = 'webpack.overrides.js';

@@ -26,45 +32,47 @@ var createConfig = function (cmd) {

var plugins = [
new WebpackPlugin_1.default(),
new WebAssetsPlugin_1.default(),
new CssProcessorPlugin_1.default(),
new ES6Plugin_1.default()
new ReactPlugin_1.default(),
new ApolloPlugin_1.default(),
new ES6Plugin_1.default(),
new ReactNativePlugin_1.default(),
new ReactNativeWebPlugin_1.default(),
new StyledComponentsPlugin_1.default(),
];
var config = new configRc_1.default(plugins);
var options = config.options;
var spin = new Spin_1.default(process.argv, config.builders, config.options);
var overridesConfig = config.options.overridesConfig || WEBPACK_OVERRIDES_NAME;
var overrides;
if (fs.existsSync(overridesConfig)) {
overrides = requireModule_1.default('./' + overridesConfig);
}
else {
overrides = {};
}
var spin = new Spin_1.default(process.argv, config.builders, config.options, overrides.dependencyPlatforms || {});
for (var name in config.builders) {
var builder = config.builders[name];
var stack = builder.stack;
if (builder.enabled === false || builder.roles.indexOf(cmd) < 0) {
continue;
}
if (spin.options.webpackDll && !stack.hasAny('server')) {
var dllBuilder = __assign({}, builder);
dllBuilder.name = builder.name + 'Dll';
dllBuilder.parent = builder;
dllBuilder.stack = new Stack_1.default(dllBuilder.stack.technologies, 'dll');
builders[dllBuilder.name] = dllBuilder;
builder.child = dllBuilder;
}
builders[name] = builder;
}
try {
var _loop_1 = function (name) {
var builder = config.builders[name];
var stack = builder.stack;
if (builder.roles.indexOf(cmd) < 0)
return "continue";
var overrides = void 0;
var overridesConfig = options.overridesConfig || WEBPACK_OVERRIDES_NAME;
if (fs.existsSync(overridesConfig)) {
overrides = requireModule_1.default('./' + overridesConfig);
}
else {
overrides = {};
}
builders[name] = __assign({}, builder, { config: generator_1.default(builder, config.builders, spin.dev, options) });
config.plugins.forEach(function (plugin) {
builders[name].config = merge(builders[name].config, plugin.configure(builder, spin));
});
var builder = builders[name];
config.plugins.forEach(function (plugin) { return plugin.configure(builder, spin); });
if (overrides[name]) {
builders[name].config = merge(builders[name].config, overrides[name]);
}
if (options.webpackDll && !stack.hasAny('server')) {
var dllNode = __assign({}, builder);
var dllNodeName = builder.name + 'Dll';
dllNode.parentName = builder.name;
dllNode.name = dllNodeName;
dllNode.stack = new Stack_1.default(dllNode.stack.technologies, 'dll');
builders[name].dllConfig = generator_1.default(dllNode, config.builders, spin.dev, options, overrides.dependencyPlatforms || {});
config.plugins.forEach(function (plugin) {
builders[name].dllConfig = merge(builders[name].dllConfig, plugin.configure(builder, spin));
});
if (overrides[dllNodeName]) {
builders[name].dllConfig = merge(builders[name].dllConfig, overrides[dllNodeName]);
}
}
};
for (var name in config.builders) {
for (var name in builders) {
_loop_1(name);

@@ -76,5 +84,5 @@ }

}
return { builders: builders, options: options };
return { builders: builders, options: spin.options };
};
exports.default = createConfig;
//# sourceMappingURL=spin.config.js.map

@@ -1,4 +0,7 @@

import { Builder } from "./Builder";
/// <reference types="webpack" />
import { Builder } from './Builder';
import { Configuration } from 'webpack';
export default class Spin {
dev: boolean;
test: boolean;
cmd: string;

@@ -9,3 +12,5 @@ builders: {

options: any;
constructor(argv: string[], builders: any, options: any);
depPlatforms: any;
constructor(argv: string[], builders: any, options: any, depPlatforms: any);
merge(config: Configuration, overrides: any): Configuration;
}
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
var merge = require("webpack-merge");
var Spin = (function () {
function Spin(argv, builders, options) {
function Spin(argv, builders, options, depPlatforms) {
this.cmd = argv[2];
this.dev = this.cmd === 'watch' || this.cmd === 'test';
this.test = this.cmd === 'test';
this.builders = builders;
this.options = options;
this.depPlatforms = depPlatforms;
}
Spin.prototype.merge = function (config, overrides) {
return merge.smart(config, overrides);
};
return Spin;

@@ -11,0 +17,0 @@ }());

import Spin from "./Spin";
export interface SpinPlugin {
configure?(builder: any, spin: Spin): Object;
configure?(builder: any, spin: Spin): any;
}

@@ -5,3 +5,4 @@ export default class Stack {

constructor(...stack: any[]);
hasAny(arg: any): Boolean;
hasAny(technologies: any): Boolean;
hasAll(technologies: any): Boolean;
}

@@ -33,4 +33,4 @@ "use strict";

}
Stack.prototype.hasAny = function (arg) {
var array = arg.constructor === Array ? arg : [arg];
Stack.prototype.hasAny = function (technologies) {
var array = technologies.constructor === Array ? technologies : [technologies];
for (var _i = 0, array_1 = array; _i < array_1.length; _i++) {

@@ -44,2 +44,12 @@ var feature = array_1[_i];

};
Stack.prototype.hasAll = function (technologies) {
var array = technologies.constructor === Array ? technologies : [technologies];
for (var _i = 0, array_2 = array; _i < array_2.length; _i++) {
var feature = array_2[_i];
if (this.technologies.indexOf(feature) < 0) {
return false;
}
}
return true;
};
return Stack;

@@ -46,0 +56,0 @@ }());

{
"name": "spinjs",
"version": "0.1.10",
"version": "0.1.11",
"scripts": {

@@ -26,3 +26,5 @@ "compile": "tsc",

"@types/node": "^7.0.18",
"@types/webpack-merge": "^0.0.5",
"@types/webpack-sources": "^0.1.2",
"@types/yargs": "^8.0.2",
"tslint": "^5.2.0",

@@ -32,6 +34,2 @@ "typescript": "^2.4.1"

"dependencies": {
"babel-polyfill": "^6.23.0",
"babel-preset-es2015": "^6.24.1",
"babel-preset-flow": "^6.23.0",
"babel-register": "^6.24.1",
"ip": "^1.1.5",

@@ -44,4 +42,5 @@ "lodash": "^4.17.4",

"webpack-merge": "^4.1.0",
"webpack-sources": "^1.0.1"
"webpack-sources": "^1.0.1",
"yargs": "^8.0.2"
}
}
<p align="center"><a href="#"><img width="150" src="https://rawgit.com/sysgears/spin.js/master/logo.svg"></a></p>
## Spin.js - an Universal JavaScript build tool
## Spin.js - a JavaScript tool to simplify build rules development

@@ -13,2 +13,6 @@ [![Twitter Follow](https://img.shields.io/twitter/follow/sysgears.svg?style=social)](https://twitter.com/sysgears)

## Introduction
## Usage

@@ -15,0 +19,0 @@

@@ -1,9 +0,12 @@

import Stack from "./Stack";
import Stack from './Stack';
export interface Builder
{
name: string,
stack: Stack,
roles: string[],
[x: string]: any
export interface Builder {
name: string;
enabled: boolean;
stack: Stack;
roles: string[];
parent?: Builder;
child?: Builder;
config?: any;
[x: string]: any;
}

@@ -5,3 +5,3 @@ import * as fs from 'fs';

import Stack from './Stack';
import { Builder } from "./Builder";
import { Builder } from './Builder';
const pkg = requireModule('./package.json');

@@ -24,5 +24,2 @@

{...builderVal} : {stack: builderVal};
if (builder.enabled === false) {
continue;
}
builder.name = name;

@@ -29,0 +26,0 @@ builder.stack = new Stack(config.options.stack, typeof builder === 'object' ? builder.stack : builder);

@@ -15,3 +15,3 @@ import * as http from 'http';

import requireModule from './requireModule';
import liveReloadMiddleware from './react-native/liveReloadMiddleware';
import liveReloadMiddleware from './plugins/react-native/liveReloadMiddleware';

@@ -133,4 +133,2 @@ const VirtualModules = requireModule('webpack-virtual-modules');

config.plugins.push(frontendVirtualModules);
if (watch) {

@@ -283,3 +281,3 @@ if (config.devServer.hot) {

let vendorHashesJson, vendorSourceListMap, vendorSource, vendorMap;
if (options.webpackDll && builder.dllConfig) {
if (options.webpackDll && builder.child) {
const name = `vendor_${platform}`;

@@ -328,3 +326,3 @@ const jsonPath = path.join(options.dllBuildDir, `${name}_dll.json`);

});
if (options.webpackDll && builder.dllConfig && platform !== 'web') {
if (options.webpackDll && builder.child && platform !== 'web') {
compiler.plugin('after-compile', (compilation, callback) => {

@@ -348,3 +346,3 @@ _.each(compilation.chunks, chunk => {

if (options.webpackDll && builder.dllConfig && platform === 'web' && !hasBackend) {
if (options.webpackDll && builder.child && platform === 'web' && !hasBackend) {
compiler.plugin('after-compile', (compilation, callback) => {

@@ -470,3 +468,3 @@ compilation.assets[vendorHashesJson.name] = vendorSource;

app.use(webpackDevMiddleware(compiler, _.merge({}, config.devServer, {
const devMiddleware = webpackDevMiddleware(compiler, _.merge({}, config.devServer, {
reporter({state, stats}) {

@@ -480,3 +478,18 @@ if (state) {

},
})))
}));
app.use(function(req, res, next) {
if (platform !== 'web') {
// Workaround for Expo Client bug in parsing Content-Type header with charset
const origSetHeader = res.setHeader;
res.setHeader = function (key, value) {
let val = value;
if (key === 'Content-Type' && value.indexOf('application/javascript') >= 0) {
val = value.split(';')[0];
}
origSetHeader.call(res, key, val);
};
}
return devMiddleware(req, res, next);
})
.use(webpackHotMiddleware(compiler, {log: false}));

@@ -776,6 +789,7 @@

const stack = builder.stack;
// console.log("name: %s, config:", name, util.inspect(builder.config, false, null));
if (stack.hasAny(['dll', 'test']))
continue;
const prepareDllPromise: PromiseLike<any> = (cmd === 'watch' && options.webpackDll && builder.dllConfig) ?
buildDll(stack.platform, builder.dllConfig, options) : Promise.resolve();
const prepareDllPromise: PromiseLike<any> = (cmd === 'watch' && options.webpackDll && builder.child) ?
buildDll(stack.platform, builder.child.config, options) : Promise.resolve();
prepareDllPromise.then(() =>

@@ -782,0 +796,0 @@ startWebpack(platforms, watch, builder, options));

@@ -0,11 +1,20 @@

import * as yargs from 'yargs';
import createConfig from './createConfig';
import execute from './executor';
if (process.argv.length >= 3) {
const cmd = process.argv[2];
let config;
if (cmd === 'watch' || cmd === 'build' || cmd === 'test') {
config = createConfig(cmd);
}
execute(cmd, config.builders, config.options);
const argv = yargs
.command('build', 'compiles package for usage in production')
.command('watch', 'launches package in development mode with hot code reload')
.command('test [mocha-webpack options]', 'runs package tests')
.demandCommand(1, '')
.help()
.version(require('../package.json').version) // tslint:disable-line
.argv;
const cmd = argv._[0];
let config;
if (cmd === 'watch' || cmd === 'build' || cmd === 'test') {
config = createConfig(cmd);
}
execute(cmd, config.builders, config.options);
import Spin from "../Spin";
import { SpinPlugin } from "../SpinPlugin";
import { ConfigPlugin } from "../ConfigPlugin";
import { Builder } from "../Builder";
import requireModule from '../requireModule';
const createCssPreprocessorRules = (dev, stack): Array<Object> => {
let createRule;
export default class CssProcessorPlugin implements ConfigPlugin {
configure(builder: Builder, spin: Spin) {
const stack = builder.stack;
const dev = spin.dev;
if (stack.hasAny('server')) {
createRule = (prep, ext) => ({
test: new RegExp(`\.${ext}$`),
use: dev ? [
{loader: 'isomorphic-style-loader'},
{loader: 'css-loader', options: {sourceMap: true}},
{loader: 'postcss-loader', options: {sourceMap: true}},
{loader: `${prep}-loader`, options: {sourceMap: true}}] :
[{loader: 'ignore-loader'}],
});
} else if (stack.hasAny('web')) {
createRule = (prep, ext) => ({
test: new RegExp(`\.${ext}$`),
use: dev ? [
{loader: 'style-loader'},
{loader: 'css-loader', options: {sourceMap: true, importLoaders: 1}},
{loader: 'postcss-loader', options: {sourceMap: true}},
{loader: `${prep}-loader`, options: {sourceMap: true}},
] : requireModule('extract-text-webpack-plugin').extract({
fallback: 'style-loader',
use: ['css-loader', 'postcss-loader', `${prep}-loader`],
}),
});
}
if (stack.hasAll('webpack')) {
let createRule;
let rules = [];
if (stack.hasAny('server')) {
createRule = (prep, ext) => ({
test: new RegExp(`\.${ext}$`),
use: dev ? [
{loader: 'isomorphic-style-loader'},
{loader: 'css-loader', options: {sourceMap: true}},
{loader: 'postcss-loader', options: {sourceMap: true}},
{loader: `${prep}-loader`, options: {sourceMap: true}}] :
[{loader: 'ignore-loader'}],
});
} else if (stack.hasAny('web')) {
let ExtractTextPlugin;
if (!dev) {
ExtractTextPlugin = requireModule('extract-text-webpack-plugin');
builder.config.plugins.push(new ExtractTextPlugin({filename: '[name].[contenthash].css', allChunks: true}));
}
createRule = (prep, ext) => ({
test: new RegExp(`\.${ext}$`),
use: dev ? [
{loader: 'style-loader'},
{loader: 'css-loader', options: {sourceMap: true, importLoaders: 1}},
{loader: 'postcss-loader', options: {sourceMap: true}},
{loader: `${prep}-loader`, options: {sourceMap: true}},
] : ExtractTextPlugin.extract({
fallback: 'style-loader',
use: ['css-loader', 'postcss-loader', `${prep}-loader`],
}),
});
}
const rules = [];
if (createRule && stack.hasAny('sass')) {
rules.push(createRule('sass', 'scss'));
}
if (createRule && stack.hasAny('sass')) {
rules.push(createRule('sass', 'scss'));
}
if (createRule && stack.hasAny('less')) {
rules.push(createRule('less', 'less'));
}
if (createRule && stack.hasAny('less')) {
rules.push(createRule('less', 'less'));
builder.config = spin.merge(builder.config, {
module: {
rules
}
});
}
}
return rules;
};
export default class CssProcessorPlugin implements SpinPlugin {
configure(builder: Builder, spin: Spin): Object {
return {
module: {
rules: createCssPreprocessorRules(spin.dev, builder.stack)
}
};
}
}
import requireModule from '../requireModule';
import { SpinPlugin } from '../SpinPlugin';
import { ConfigPlugin } from '../ConfigPlugin';
import { Builder } from '../Builder';
import Spin from '../Spin';
import findJSRule from './shared/JSRuleFinder';
export default class ES6Plugin implements SpinPlugin {
configure(builder: Builder, spin: Spin): Object {
const rules = [];
if (builder.stack.hasAny(['es6', 'react-native'])) {
export default class ES6Plugin implements ConfigPlugin {
configure(builder: Builder, spin: Spin) {
if (builder.stack.hasAll(['es6', 'webpack'])) {
const babelRule = {

@@ -23,50 +22,20 @@ loader: requireModule.resolve('babel-loader'),

requireModule.resolve('babel-plugin-transform-class-properties'),
[requireModule.resolve('babel-plugin-styled-components'), {'ssr': spin.options.ssr}],
].concat(spin.dev && spin.options.reactHotLoader ? [requireModule.resolve('react-hot-loader/babel')] : []),
only: ['*.js', '*.jsx'],
only: ['*.js'].concat(builder.stack.hasAny(['react', 'react-native']) ? ['*.jsx'] : []),
},
};
let reactNativeRule;
if (builder.stack.hasAny('react-native')) {
reactNativeRule = {
loader: requireModule.resolve('babel-loader'),
options: {
cacheDirectory: spin.dev,
presets: [requireModule.resolve('babel-preset-react-native')],
plugins: [
requireModule.resolve('haul/src/utils/fixRequireIssues'),
],
if (builder.stack.hasAny('es6') && !builder.stack.hasAny('dll')) {
builder.config = spin.merge({
entry: {
index: ['babel-polyfill'],
},
};
}, builder.config);
}
rules.push( {
test: /\.jsx?$/,
exclude: builder.stack.hasAny(['react-native']) ?
/node_modules\/(?!react-native|@expo|expo|lottie-react-native|haul|pretty-format|react-navigation)$/ :
/node_modules/,
use: [
(builder.stack.hasAny(['react-native']) ?
function (req) {
let result;
if (req.resource.indexOf('node_modules') >= 0) {
result = reactNativeRule;
} else {
result = babelRule;
}
return result;
} :
babelRule) as any,
],
},
);
const jsRule = findJSRule(builder);
jsRule.exclude = /node_modules/;
jsRule.use = babelRule;
}
return {
module: {
rules,
}
};
}
}

@@ -5,9 +5,16 @@ import * as fs from 'fs';

import ConfigRc from './configRc';
import generateConfig from './generator';
import Stack from './Stack';
import requireModule from './requireModule';
import Spin from "./Spin";
import { SpinPlugin } from "./SpinPlugin";
import CssProcessorPlugin from "./plugins/CssProcessorPlugin";
import ES6Plugin from "./plugins/ES6Plugin";
import Spin from './Spin';
import { ConfigPlugin } from './ConfigPlugin';
import CssProcessorPlugin from './plugins/CssProcessorPlugin';
import ES6Plugin from './plugins/ES6Plugin';
import { Builder } from './Builder';
import ApolloPlugin from './plugins/ApolloPlugin';
import ReactNativePlugin from './plugins/ReactNativePlugin';
import ReactNativeWebPlugin from './plugins/ReactNativeWebPlugin';
import StyledComponentsPlugin from './plugins/StyledComponentsPlugin';
import WebAssetsPlugin from './plugins/WebAssetsPlugin';
import ReactPlugin from './plugins/ReactPlugin';
import WebpackPlugin from './plugins/WebpackPlugin';

@@ -20,42 +27,48 @@ const WEBPACK_OVERRIDES_NAME = 'webpack.overrides.js';

const plugins = [
new WebpackPlugin(),
new WebAssetsPlugin(),
new CssProcessorPlugin(),
new ES6Plugin()
new ReactPlugin(),
new ApolloPlugin(),
new ES6Plugin(),
new ReactNativePlugin(),
new ReactNativeWebPlugin(),
new StyledComponentsPlugin(),
];
const config = new ConfigRc(plugins);
const options = config.options;
const spin = new Spin(process.argv, config.builders, config.options);
const overridesConfig = config.options.overridesConfig || WEBPACK_OVERRIDES_NAME;
let overrides;
if (fs.existsSync(overridesConfig)) {
overrides = requireModule('./' + overridesConfig);
} else {
overrides = {};
}
const spin = new Spin(process.argv, config.builders, config.options, overrides.dependencyPlatforms || {});
for (let name in config.builders) {
const builder = config.builders[name];
const stack = builder.stack;
if (builder.enabled === false || builder.roles.indexOf(cmd) < 0) {
continue;
}
if (spin.options.webpackDll && !stack.hasAny('server')) {
const dllBuilder: Builder = {...builder} as Builder;
dllBuilder.name = builder.name + 'Dll';
dllBuilder.parent = builder;
dllBuilder.stack = new Stack(dllBuilder.stack.technologies, 'dll');
builders[dllBuilder.name] = dllBuilder;
builder.child = dllBuilder;
}
builders[name] = builder;
}
try {
for (let name in config.builders) {
const builder = config.builders[name];
const stack = builder.stack;
if (builder.roles.indexOf(cmd) < 0)
continue;
let overrides;
const overridesConfig = options.overridesConfig || WEBPACK_OVERRIDES_NAME;
if (fs.existsSync(overridesConfig)) {
overrides = requireModule('./' + overridesConfig);
} else {
overrides = {};
}
builders[name] = { ...builder, config: generateConfig(builder, config.builders, spin.dev, options) };
config.plugins.forEach((plugin: SpinPlugin) => {
builders[name].config = merge(builders[name].config, plugin.configure(builder, spin));
});
for (let name in builders) {
const builder = builders[name];
config.plugins.forEach((plugin: ConfigPlugin) => plugin.configure(builder, spin));
if (overrides[name]) {
builders[name].config = merge(builders[name].config, overrides[name]);
}
if (options.webpackDll && !stack.hasAny('server')) {
const dllNode: any = {...builder};
const dllNodeName = builder.name + 'Dll';
dllNode.parentName = builder.name;
dllNode.name = dllNodeName;
dllNode.stack = new Stack(dllNode.stack.technologies, 'dll');
builders[name].dllConfig = generateConfig(dllNode, config.builders, spin.dev, options, overrides.dependencyPlatforms || {});
config.plugins.forEach((plugin: SpinPlugin) => {
builders[name].dllConfig = merge(builders[name].dllConfig, plugin.configure(builder, spin));
});
if (overrides[dllNodeName]) {
builders[name].dllConfig = merge(builders[name].dllConfig, overrides[dllNodeName]);
}
}
}

@@ -66,5 +79,5 @@ } catch (e) {

return { builders, options };
return { builders, options: spin.options };
};
export default createConfig;

@@ -1,16 +0,25 @@

import { Builder } from "./Builder";
import * as merge from 'webpack-merge';
import { Builder } from './Builder';
import { Configuration } from 'webpack';
export default class Spin
{
export default class Spin {
dev: boolean;
test: boolean;
cmd: string;
builders: { [x: string]: Builder };
options: any;
depPlatforms: any;
constructor(argv: string[], builders, options) {
constructor(argv: string[], builders, options, depPlatforms) {
this.cmd = argv[2];
this.dev = this.cmd === 'watch' || this.cmd === 'test';
this.test = this.cmd === 'test';
this.builders = builders;
this.options = options;
this.depPlatforms = depPlatforms;
}
}
merge(config: Configuration, overrides: any): Configuration {
return merge.smart(config, overrides);
}
}

@@ -26,4 +26,4 @@ export default class Stack {

hasAny(arg): Boolean {
const array = arg.constructor === Array ? arg : [arg];
hasAny(technologies): Boolean {
const array = technologies.constructor === Array ? technologies : [technologies];
for (let feature of array) {

@@ -36,2 +36,12 @@ if (this.technologies.indexOf(feature) >= 0) {

}
hasAll(technologies): Boolean {
const array = technologies.constructor === Array ? technologies : [technologies];
for (let feature of array) {
if (this.technologies.indexOf(feature) < 0) {
return false;
}
}
return true;
}
}

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc