From 0dfd06df140debe91769ed37362bec0691d2d16d Mon Sep 17 00:00:00 2001 From: Sbats Date: Tue, 20 Dec 2016 11:15:25 +0100 Subject: [PATCH] Apply new project base from change-project-base --- .editorconfig | 14 ++ .gitignore | 17 +- .travis.yml | 30 +-- LICENSE | 27 ++- Readme.md => README.md | 2 +- bs-config.json | 5 - config/helpers.js | 27 +-- config/karma.conf.js | 107 +++-------- config/protractor.conf.js | 50 ----- config/replace.js | 22 +++ config/spec-bundle.js | 43 ++++- config/webpack.common.js | 102 +++++----- config/webpack.dev.js | 126 ++++++++---- config/webpack.package.js | 105 ++++++++++ config/webpack.prod.js | 32 ---- config/webpack.test.js | 114 ++++++----- config/webpack.univ.js | 88 --------- demo/app.component.html | 2 - demo/app.component.ts | 178 ++++++++++------- demo/app.module.ts | 12 -- demo/app.scss | 0 demo/bootstrap.ts | 16 ++ demo/index.html | 51 ++--- demo/main.browser.ts | 5 - demo/module.ts | 33 ++++ demo/polyfills.ts | 35 ++-- demo/sampleschema.json | 2 +- demo/vendor.ts | 3 - install-peers.sh | 2 - karma.conf.js | 2 - package.json | 181 +++++++++--------- src/index.ts | 14 +- src/schema-form/default.widget.ts | 8 +- .../defaultwidgets/array/array.widget.html | 2 +- .../defaultwidgets/array/array.widget.ts | 8 +- .../checkbox/checkbox.widget.ts | 8 +- .../defaultwidgetregistry.spec.ts | 28 ++- .../defaultwidgets/defaultwidgetregistry.ts | 54 +++--- .../defaultwidgets/file/file.widget.ts | 10 +- src/schema-form/defaultwidgets/index.ts | 22 +-- .../integer/integer.widget.spec.ts | 13 -- .../defaultwidgets/integer/integer.widget.ts | 8 +- .../defaultwidgets/object/object.widget.html | 2 +- .../defaultwidgets/object/object.widget.ts | 10 +- .../defaultwidgets/radio/radio.widget.ts | 8 +- .../defaultwidgets/range/range.widget.spec.ts | 13 -- .../defaultwidgets/range/range.widget.ts | 8 +- .../defaultwidgets/select/select.widget.ts | 8 +- .../defaultwidgets/string/string.spec.ts | 12 -- .../defaultwidgets/string/string.widget.ts | 14 +- .../textarea/textarea.widget.ts | 8 +- src/schema-form/form.component.html | 2 +- src/schema-form/form.component.ts | 25 ++- src/schema-form/formelement.component.html | 4 +- src/schema-form/formelement.component.ts | 22 +-- src/schema-form/model/action.ts | 2 +- src/schema-form/model/actionregistry.ts | 3 +- src/schema-form/model/arrayproperty.ts | 16 +- .../model/atomicproperties.spec.ts | 62 +++--- src/schema-form/model/atomicproperty.ts | 3 +- src/schema-form/model/booleanproperty.ts | 2 +- src/schema-form/model/formproperty.spec.ts | 55 ++++-- src/schema-form/model/formproperty.ts | 48 ++--- src/schema-form/model/formpropertyfactory.ts | 42 ++-- src/schema-form/model/index.ts | 20 +- src/schema-form/model/numberproperty.ts | 6 +- src/schema-form/model/objectproperty.spec.ts | 37 ++-- src/schema-form/model/objectproperty.ts | 28 +-- .../model/schemapreprocessor.spec.ts | 16 +- src/schema-form/model/schemapreprocessor.ts | 50 ++--- src/schema-form/model/stringproperty.ts | 4 +- src/schema-form/model/validator.ts | 2 +- src/schema-form/model/validatorregistry.ts | 2 +- src/schema-form/schema-form.module.ts | 15 +- src/schema-form/schemavalidatorfactory.ts | 6 +- src/schema-form/widget.ts | 10 +- .../widgetchooser.component.spec.ts | 16 +- src/schema-form/widgetchooser.component.ts | 11 +- src/schema-form/widgetfactory.ts | 5 +- tsconfig.json | 67 ++++--- tslint.json | 11 +- webpack.config.js | 19 +- 82 files changed, 1193 insertions(+), 1109 deletions(-) create mode 100644 .editorconfig rename Readme.md => README.md (99%) delete mode 100644 bs-config.json delete mode 100644 config/protractor.conf.js create mode 100644 config/replace.js create mode 100644 config/webpack.package.js delete mode 100644 config/webpack.prod.js delete mode 100644 config/webpack.univ.js delete mode 100644 demo/app.component.html delete mode 100644 demo/app.module.ts delete mode 100644 demo/app.scss create mode 100644 demo/bootstrap.ts delete mode 100644 demo/main.browser.ts create mode 100644 demo/module.ts delete mode 100644 demo/vendor.ts delete mode 100755 install-peers.sh delete mode 100644 src/schema-form/defaultwidgets/integer/integer.widget.spec.ts delete mode 100644 src/schema-form/defaultwidgets/range/range.widget.spec.ts delete mode 100644 src/schema-form/defaultwidgets/string/string.spec.ts diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 00000000..1033e2df --- /dev/null +++ b/.editorconfig @@ -0,0 +1,14 @@ +# EditorConfig is awesome: http://EditorConfig.org + +# top-most EditorConfig file +root = true + +# Unix-style newlines with a newline ending every file +[*] +end_of_line = lf +insert_final_newline = true + +# 2 space indentation +[**.*] +indent_style = space +indent_size = 2 \ No newline at end of file diff --git a/.gitignore b/.gitignore index 033aa3d8..a64c7da5 100644 --- a/.gitignore +++ b/.gitignore @@ -1,11 +1,10 @@ -/__build__ -/__server_build__ -/node_modules -/coverage +node_modules/ +.DS_Store npm-debug.log - -/dist/ -/doc/ - +compiled/ +dist/ +coverage/ .idea -.vscode +yarn.lock +/.vscode +release/ \ No newline at end of file diff --git a/.travis.yml b/.travis.yml index bf89b189..9c69494e 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,20 +1,26 @@ language: node_js + node_js: - - "6" - - "node" + - '6' + - 'node' + env: - - CXX=g++-4.8 + - CXX=g++-4.8 + install: - - ./install-peers.sh - - npm install + - npm install + +after_script: + - codeclimate-test-reporter < coverage/lcov.info addons: - apt: - sources: - - ubuntu-toolchain-r-test - packages: - - g++-4.8 + apt: + sources: + - ubuntu-toolchain-r-test + packages: + - g++-4.8 + git: - depth: 4 + depth: 4 -sudo: false +sudo: false \ No newline at end of file diff --git a/LICENSE b/LICENSE index 87e42f97..5f87fd5f 100644 --- a/LICENSE +++ b/LICENSE @@ -1,9 +1,22 @@ -Copyright (c) 2016, Makina Corpus -All rights reserved. +(The MIT License) -Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: +Copyright (c) 2016 Swimlane -Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. -Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. -Neither the name of the Makina Corpus nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +'Software'), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/Readme.md b/README.md similarity index 99% rename from Readme.md rename to README.md index f395f8d7..df763b8f 100644 --- a/Readme.md +++ b/README.md @@ -436,7 +436,7 @@ If it is not formatted the way Angular 2 Schema Form expects or if some elements template: '' }) export class MyComponent { - private schema:any = + private schema:any = 'properties': {} }; private actions:any = {}; diff --git a/bs-config.json b/bs-config.json deleted file mode 100644 index a7c7416d..00000000 --- a/bs-config.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "files":["./dist/*.{html,css,js}"], - "server":{"baseDir":"./dist"}, - "port":3500 -} diff --git a/config/helpers.js b/config/helpers.js index f0d6e537..53c530c2 100644 --- a/config/helpers.js +++ b/config/helpers.js @@ -1,23 +1,16 @@ -/** - * @author: @AngularClass - */ +const path = require('path'); -var path = require('path'); +const ENV = process.env.NODE_ENV; +const pkg = require('../package.json'); +const ROOT = path.resolve(__dirname, '..'); -// Helper functions -var ROOT = path.resolve(__dirname, '..'); - -console.log('root directory:', root() + '\n'); - -function hasProcessFlag(flag) { - return process.argv.join('').indexOf(flag) > -1; -} - -function root(args) { +exports.dir = function(args) { args = Array.prototype.slice.call(arguments, 0); return path.join.apply(path, [ROOT].concat(args)); } - -exports.hasProcessFlag = hasProcessFlag; -exports.root = root; \ No newline at end of file +exports.ENV = JSON.stringify(ENV); +exports.IS_PRODUCTION = ENV === 'production'; +exports.IS_PACKAGE = ENV === 'package'; +exports.IS_DEV = ENV === 'dev' || ENV === 'development'; +exports.APP_VERSION = JSON.stringify(pkg.version); diff --git a/config/karma.conf.js b/config/karma.conf.js index 4af2ef5f..047d1016 100644 --- a/config/karma.conf.js +++ b/config/karma.conf.js @@ -1,86 +1,35 @@ -module.exports = function(config) { - var testWebpackConfig = require('./webpack.test.js'); +const testWebpackConfig = require('./webpack.test'); - config.set({ - - // base path that will be used to resolve all patterns (e.g. files, exclude) +module.exports = function(config) { + var configuration = { basePath: '', - - /* - * Frameworks to use - * - * available frameworks: https://npmjs.org/browse/keyword/karma-adapter - */ + singleRun: true, frameworks: ['jasmine'], - - // list of files to exclude - exclude: [ ], - - /* - * list of files / patterns to load in the browser - * - * we are building the test environment in ./spec-bundle.js - */ - files: [ { pattern: './config/spec-bundle.js', watched: true} ], - - /* - * preprocess matching files before serving them to the browser - * available preprocessors: https://npmjs.org/browse/keyword/karma-preprocessor - */ - preprocessors: { './config/spec-bundle.js': ['coverage', 'webpack', 'sourcemap'] }, - - // Webpack Config at ./webpack.test.js - webpack: testWebpackConfig, - - coverageReporter: { - dir : 'coverage/', - reporters: [ - { type: 'text-summary' }, - { type: 'json' }, - { type: 'html' } - ] + exclude: [], + files: [ + { pattern: './config/spec-bundle.js', watched: false } + ], + preprocessors: { + './config/spec-bundle.js': ['coverage', 'webpack', 'sourcemap'] }, - - // Webpack please don't spam the console when running in karma! - webpackServer: { noInfo: true }, - - /* - * test results reporter to use - * - * possible values: 'dots', 'progress' - * available reporters: https://npmjs.org/browse/keyword/karma-reporter - */ - reporters: [ 'mocha', 'coverage' ], - - // web server port + webpack: testWebpackConfig({ env: 'test' }), + webpackMiddleware: { stats: 'errors-only'}, + reporters: [ 'mocha', 'coverage', 'remap-coverage' ], port: 9876, - - // enable / disable colors in the output (reporters and logs) colors: true, - - /* - * level of logging - * possible values: config.LOG_DISABLE || config.LOG_ERROR || config.LOG_WARN || config.LOG_INFO || config.LOG_DEBUG - */ - logLevel: config.LOG_DEBUG, - - // enable / disable watching file and executing tests whenever any file changes - autoWatch: true, - - /* - * start these browsers - * available browser launchers: https://npmjs.org/browse/keyword/karma-launcher - */ - browsers: [ - // 'Chrome', - 'PhantomJS' - ], - - /* - * Continuous Integration mode - * if true, Karma captures browsers, runs the tests and exits - */ - singleRun: true - }); - + logLevel: config.LOG_INFO, + autoWatch: false, + browsers: ['PhantomJS'], + coverageReporter: { + type: 'in-memory' + }, + remapCoverageReporter: { + 'text-summary': null, + json: './coverage/coverage.json', + html: './coverage/html', + lcovonly: './coverage/lcov.info' + } + }; + + config.set(configuration); }; diff --git a/config/protractor.conf.js b/config/protractor.conf.js deleted file mode 100644 index 6086cd3d..00000000 --- a/config/protractor.conf.js +++ /dev/null @@ -1,50 +0,0 @@ -/** - * @author: @AngularClass - */ - - -require('ts-node/register'); -var helpers = require('./helpers'); - -exports.config = { - baseUrl: 'http://localhost:3000/', - - // use `npm run e2e` - specs: [ - helpers.root('src/**/**.e2e.ts'), - helpers.root('src/**/*.e2e.ts') - ], - exclude: [], - - framework: 'jasmine2', - - allScriptsTimeout: 110000, - - jasmineNodeOpts: { - showTiming: true, - showColors: true, - isVerbose: false, - includeStackTrace: false, - defaultTimeoutInterval: 400000 - }, - directConnect: true, - - capabilities: { - 'browserName': 'chrome', - 'chromeOptions': { - 'args': ['show-fps-counter=true'] - } - }, - - onPrepare: function() { - browser.ignoreSynchronization = true; - }, - - /** - * Angular 2 configuration - * - * useAllAngular2AppRoots: tells Protractor to wait for any angular2 apps on the page instead of just the one matching - * `rootEl` - */ - useAllAngular2AppRoots: true -}; diff --git a/config/replace.js b/config/replace.js new file mode 100644 index 00000000..39844bb9 --- /dev/null +++ b/config/replace.js @@ -0,0 +1,22 @@ +const replace = require("replace"); +const fs = require('fs-extra') + +/** + * This replaces all the TypeScript references + * to other types that for some reason TypeScript + * keeps generating. This hack is insane ... + */ +replace({ + regex: '/// ', + replacement: '', + paths: ['./release'], + recursive: true, + silent: false +}); + +/** + * ngc output pathing is totally wrong + */ +fs.copySync('./release/src', './release'); +fs.removeSync('./release/node_modules') +fs.removeSync('./release/src') diff --git a/config/spec-bundle.js b/config/spec-bundle.js index a1d801ec..251924a6 100644 --- a/config/spec-bundle.js +++ b/config/spec-bundle.js @@ -13,27 +13,50 @@ */ Error.stackTraceLimit = Infinity; -require('core-js/client/shim'); -require("core-js/es7/reflect"); -require('reflect-metadata'); +require('core-js/es6'); +require('core-js/es7/reflect'); // Typescript emit helpers polyfill require('ts-helpers'); require('zone.js/dist/zone'); require('zone.js/dist/long-stack-trace-zone'); -require('zone.js/dist/proxy'); +require('zone.js/dist/proxy'); // since zone.js 0.6.15 require('zone.js/dist/sync-test'); -require('zone.js/dist/jasmine-patch'); +require('zone.js/dist/jasmine-patch'); // put here since zone.js 0.6.14 require('zone.js/dist/async-test'); require('zone.js/dist/fake-async-test'); -var testContext = require.context('../src', true, /\.spec\.ts$/); -testContext.keys().forEach(testContext); +// RxJS +require('rxjs/Rx'); -var testing = require('@angular/core/testing'); -var browser = require('@angular/platform-browser-dynamic/testing'); +const testing = require('@angular/core/testing'); +const browser = require('@angular/platform-browser-dynamic/testing'); -testing.TestBed.initTestEnvironment(browser.BrowserDynamicTestingModule, browser.platformBrowserDynamicTesting()); +testing.TestBed.initTestEnvironment( + browser.BrowserDynamicTestingModule, + browser.platformBrowserDynamicTesting() +); +/* + * Ok, this is kinda crazy. We can use the context method on + * require that webpack created in order to tell webpack + * what files we actually want to require or import. + * Below, context will be a function/object with file names as keys. + * Using that regex we are saying look in ../src then find + * any file that ends with spec.ts and get its path. By passing in true + * we say do this recursively + */ +const testContext = require.context('../src', true, /\.spec\.ts/); + +/* + * get all the files, for each file, call the context function + * that will require the file and load it up here. Context will + * loop and require those spec files here + */ +function requireAll(requireContext) { + return requireContext.keys().map(requireContext); +} +// requires and returns all modules that match +const modules = requireAll(testContext); diff --git a/config/webpack.common.js b/config/webpack.common.js index ad8d4d30..f49cb82f 100644 --- a/config/webpack.common.js +++ b/config/webpack.common.js @@ -1,57 +1,51 @@ const webpack = require('webpack'); -var path = require("path"); - -var CopyWebpackPlugin = (CopyWebpackPlugin = require('copy-webpack-plugin'), CopyWebpackPlugin.default || CopyWebpackPlugin); -const ForkCheckerPlugin = require('awesome-typescript-loader').ForkCheckerPlugin; - -const METADATA = { - title: 'Angular2 Schema Form', - baseUrl: '/' -}; - - -module.exports = { - - metadata: METADATA, - - resolve: { - extensions: ['', '.ts', '.js'] - }, - debug: true, - - - module: { - preLoaders: [{ - test: /\.js$/, - loader: "source-map-loader", - exclude: [ /node_modules/] - }], - loaders: [{ - test: /\.ts$/, - loader: "awesome-typescript-loader", - exclude: /node_modules/ - },{ - test: /\.json$/, - loader: "json-loader" - },{ - test: /\.css$/, - loader: 'raw-loader', - },{ - test: /\.(png|jpg|gif|woff|ttf|eot|svg)$/, - loader: 'file-loader' - }] - }, - plugins: [ - new webpack.optimize.OccurenceOrderPlugin(true), - new ForkCheckerPlugin() - ], - - node: { - global: 'window', - crypto: 'empty', - module: false, - clearImmediate: false, - setImmediate: false, - } +const autoprefixer = require('autoprefixer'); +const CopyWebpackPlugin = require('copy-webpack-plugin'); +const { ENV, IS_PRODUCTION, APP_VERSION, IS_DEV, dir } = require('./helpers'); + +module.exports = function(options = {}) { + return { + context: dir(), + resolve: { + extensions: ['.ts', '.js', '.json', '.css', '.scss', '.html'], + modules: [ + 'node_modules', + dir('src'), + dir('demo') + ] + }, + output: { + path: dir('dist'), + filename: '[name].js', + sourceMapFilename: '[name].map', + chunkFilename: '[id].chunk.js' + }, + plugins: [ + new webpack.NamedModulesPlugin(), + new webpack.DefinePlugin({ + ENV, + IS_PRODUCTION, + APP_VERSION, + IS_DEV, + HMR: options.HMR + }), + // new CopyWebpackPlugin([ + // { from: 'assets', to: 'assets' } + // ]), + new webpack.LoaderOptionsPlugin({ + options: { + context: dir(), + tslint: { + emitErrors: false, + failOnHint: false, + resourcePath: 'src' + }, + postcss: function() { + return [ autoprefixer ]; + } + } + }) + ] + }; }; diff --git a/config/webpack.dev.js b/config/webpack.dev.js index 733e72e6..68d2b2b8 100644 --- a/config/webpack.dev.js +++ b/config/webpack.dev.js @@ -1,38 +1,94 @@ -const webpack = require("webpack"); +const webpack = require('webpack'); +const webpackMerge = require('webpack-merge'); +const WebpackNotifierPlugin = require('webpack-notifier'); +const ProgressBarPlugin = require('progress-bar-webpack-plugin'); +const chalk = require('chalk'); const HtmlWebpackPlugin = require('html-webpack-plugin'); -const merge = require("webpack-merge"); -var path = require("path"); +const ForkCheckerPlugin = require('awesome-typescript-loader').ForkCheckerPlugin; -const METADATA = { - title: "Angular2 Schema Form", - baseUrl: "/" -}; +const commonConfig = require('./webpack.common'); +const { ENV, dir } = require('./helpers'); + +module.exports = function(options) { + return webpackMerge(commonConfig({ env: ENV }), { + devtool: 'cheap-module-source-map', + devServer: { + watchOptions: { + poll: true + }, + port: 9999, + hot: options.HMR, + stats: { + modules: false, + cached: false, + chunk: false + } + }, + entry: { + 'app': './demo/bootstrap.ts', + 'polyfills': './demo/polyfills.ts' + }, + module: { + exprContextCritical: false, + rules: [ + { + enforce: 'pre', + test: /\.js$/, + loader: 'source-map-loader', + exclude: /(node_modules)/ + }, + { + enforce: 'pre', + test: /\.ts$/, + loader: 'tslint-loader', + exclude: /(node_modules|release|dist)/ + }, + { + test: /\.json$/, + loader: "json-loader" + }, + { + test: /\.ts$/, + loaders: [ + 'awesome-typescript-loader', + '@angularclass/hmr-loader' + ], + exclude: [/\.(spec|e2e|d)\.ts$/] + }, + { + test: /\.css/, + loader: 'style-loader!css-loader?sourceMap' + }, + { + test: /\.scss$/, + loader: 'style-loader!css-loader!postcss-loader?sourceMap!sass-loader?sourceMap' + }, + { + test: /\.html$/, + loader: 'raw-loader' + } + ] + }, + plugins: [ + // new ForkCheckerPlugin(), + new webpack.optimize.CommonsChunkPlugin({ + name: ['polyfills'], + minChunks: Infinity + }), + new HtmlWebpackPlugin({ + template: 'demo/index.html', + chunksSortMode: 'dependency', + title: 'schema-form' + }), + new WebpackNotifierPlugin({ + excludeWarnings: true + }), + new ProgressBarPlugin({ + format: chalk.yellow.bold('Webpack Building...') + + ' [:bar] ' + chalk.green.bold(':percent') + ' (:elapsed seconds)' + }), + new webpack.HotModuleReplacementPlugin() + ] + }); -module.exports = merge(require("./webpack.common.js"),{ - metadata: METADATA, - output: { - path: path.resolve("./dist"), - filename: "[name].js" - }, - entry: { - "demo": "./demo/main.browser", - "vendor": "./demo/vendor", - "polyfills":"./demo/polyfills" - }, - devtool: 'cheap-module-source-map', - module: { - loaders:[{ - test: /\.html$/, - loader: 'raw-loader', - exclude:[path.resolve("demo/index.html")] - }] - }, - plugins: [ - new HtmlWebpackPlugin({ - template: 'demo/index.html', - chunksSortMode: 'dependency' - }), - new webpack.optimize.CommonsChunkPlugin({ - name: ['demo', 'vendor',"polyfills"] - })] -}) +}; diff --git a/config/webpack.package.js b/config/webpack.package.js new file mode 100644 index 00000000..2e0ca45a --- /dev/null +++ b/config/webpack.package.js @@ -0,0 +1,105 @@ +const webpack = require('webpack'); +const webpackMerge = require('webpack-merge'); +const CleanWebpackPlugin = require('clean-webpack-plugin'); +const HtmlWebpackPlugin = require('html-webpack-plugin'); +const ngtools = require('@ngtools/webpack'); +const ExtractTextPlugin = require('extract-text-webpack-plugin'); +const commonConfig = require('./webpack.common'); +const { ENV, dir, APP_VERSION } = require('./helpers'); + +const banner = +`/** + * angular2-schema-form v${APP_VERSION} (https://github.com/makinacorpus/angular2-schema-form) + * Copyright 2016 + * Licensed under MIT + */`; + +module.exports = function(env) { + return webpackMerge(commonConfig({ env: ENV }), { + devtool: 'source-map', + module: { + exprContextCritical: false, + rules: [ + { + test: /\.ts$/, + loaders: [ + 'angular2-template-loader', + 'awesome-typescript-loader' + ], + exclude: [/\.(spec|e2e|d)\.ts$/] + }, + { + test: /\.json$/, + loader: "json-loader" + }, + { + test: /\.css/, + loader: + ExtractTextPlugin.extract({ + fallbackLoader: 'style-loader', + loader:'css-loader?sourceMap' + }) + }, + { + test: /\.scss$/, + loader: + ExtractTextPlugin.extract({ + fallbackLoader: 'style-loader', + loader: 'css-loader?sourceMap!postcss-loader?sourceMap!sass-loader?sourceMap' + }) + }, + { + test: /\.html$/, + loader: 'raw-loader' + } + ] + }, + entry: { + 'index': './src/index.ts' + }, + output: { + path: dir('release'), + libraryTarget: 'umd', + library: 'angular2-schema-form', + umdNamedDefine: true + }, + externals: { + '@angular/platform-browser-dynamic': '@angular/platform-browser-dynamic', + '@angular/platform-browser': '@angular/platform-browser', + '@angular/core': '@angular/core', + '@angular/common': '@angular/common', + '@angular/forms': '@angular/forms', + 'core-js': 'core-js', + 'core-js/es6': 'core-js/es6', + 'core-js/es7/reflect': 'core-js/es7/reflect', + 'rxjs': 'rxjs', + 'rxjs/Rx': 'rxjs/Rx', + 'rxjs/Subscription': 'rxjs/Subscription', + 'zone.js/dist/zone': 'zone.js/dist/zone' + }, + plugins: [ + new ExtractTextPlugin({ + filename: '[name].css', + allChunks: true + }), + new webpack.BannerPlugin({ + banner: banner, + raw: true, + entryOnly: true + }), + /* + new ngtools.AotPlugin({ + tsConfigPath: 'tsconfig-aot.json', + baseDir: dir() + entryModule: dir('datatable.module.ts') + '#Angular2DataTableModule' + }), + new CleanWebpackPlugin(['release'], { + root: dir(), + verbose: false, + dry: false + }) + */ + ] + }); + +}; diff --git a/config/webpack.prod.js b/config/webpack.prod.js deleted file mode 100644 index b5d5f3a9..00000000 --- a/config/webpack.prod.js +++ /dev/null @@ -1,32 +0,0 @@ -const webpack = require("webpack"); -const HtmlWebpackPlugin = require('html-webpack-plugin'); -const nodeExternals = require("webpack-node-externals"); -const merge = require("webpack-merge"); -var path = require("path"); - -const METADATA = { - title: "Angular2 Schema Form", - baseUrl: "/" -}; - -module.exports = merge(require("./webpack.common.js"),{ - metadata: METADATA, - output: { - path: path.resolve("./dist"), - filename: "index.js", - libraryTarget: "commonjs2", - library: true - }, - entry: { - "index": path.resolve("src/index.ts") - }, - devtool: 'cheap-module-source-map', - module: { - loaders:[{ - test: /\.html$/, - loader: 'raw-loader', - }] - }, - plugins: [], - externals: [nodeExternals({whitelist:["z-schema"]})], -}); diff --git a/config/webpack.test.js b/config/webpack.test.js index 331e0722..36874493 100644 --- a/config/webpack.test.js +++ b/config/webpack.test.js @@ -1,48 +1,68 @@ -const webpack = require("webpack"); -const merge = require("webpack-merge"); -var path = require("path"); -const ProvidePlugin = require('webpack/lib/ProvidePlugin'); -const DefinePlugin = require('webpack/lib/DefinePlugin'); +const webpack = require('webpack'); +const webpackMerge = require('webpack-merge'); +const chalk = require('chalk'); +const commonConfig = require('./webpack.common'); +const { ENV, dir } = require('./helpers'); -const ENV = process.env.ENV = process.env.NODE_ENV = 'test'; - -module.exports = merge(require("./webpack.common.js"), { - - // Necessary for karma - devtool: 'inline-source-map', - - module: { - - preLoaders: [ - - { - test: /\.ts$/, - loader: 'tslint-loader', - exclude: /'node_modules'/ - } - ], - loaders:[{ - test: /\.html$/, - loader: 'raw-loader', - exclude:[path.resolve("demo/index.html")] - }], - - postLoaders: [ - { - test: /\.(js|ts)$/, loader: 'istanbul-instrumenter-loader', - include: path.resolve('src'), - exclude: [ - /\.(spec)\.ts$/, - /node_modules/ - ] - } - - ] - }, - - tslint: { - emitErrors: false, - failOnHint: false, - resourcePath: 'src' - } -}) +module.exports = function(env) { + return webpackMerge(commonConfig({ env: ENV }), { + devtool: 'inline-source-map', + module: { + exprContextCritical: false, + rules: [ + { + enforce: 'pre', + test: /\.js$/, + loader: 'source-map-loader', + exclude: /(node_modules)/ + }, + { + test: /\.ts$/, + loader: 'awesome-typescript-loader', + query: { + sourceMap: false, + inlineSourceMap: true, + compilerOptions: { + removeComments: true + } + }, + exclude: [/\.e2e\.ts$/, /(node_modules)/] + }, + { + enforce: 'post', + test: /\.(js|ts)$/, + loader: 'istanbul-instrumenter-loader', + include: dir('src'), + exclude: [ + /\.(e2e|spec)\.ts$/, + /node_modules/ + ] + }, + { + test: /\.json$/, + loader: "json-loader" + }, + { + test: /\.css/, + loader: 'style-loader!css-loader?sourceMap' + }, + { + test: /\.scss$/, + loader: 'style-loader!css-loader!postcss-loader?sourceMap!sass-loader?sourceMap' + }, + { + test: /\.html$/, + loader: 'raw-loader' + } + ] + }, + node: { + global: true, + process: false, + crypto: 'empty', + module: false, + clearImmediate: false, + setImmediate: false + } + }); +}; diff --git a/config/webpack.univ.js b/config/webpack.univ.js deleted file mode 100644 index 20debd6a..00000000 --- a/config/webpack.univ.js +++ /dev/null @@ -1,88 +0,0 @@ -var webpack = require('webpack'); -var path = require('path'); -var WebpackNotifierPlugin = require('webpack-notifier'); - -var webpackConfig = require('./config/webpack.common') - -const ENV = process.env.NODE_ENV = process.env.ENV = 'universal'; - -var clientConfig = { - target: 'web', - entry: './src/client', - output: { - path: path.join(__dirname, 'dist', 'client') - }, - node: { - global: true, - __dirname: true, - __filename: true, - process: true, - Buffer: false - } -}; - - -var serverConfig = { - target: 'node', - entry: './src/server', - output: { - path: path.join(__dirname, 'dist', 'server') - }, - externals: checkNodeImport, - node: { - global: true, - __dirname: true, - __filename: true, - process: true, - Buffer: true - } -}; - - -// Default config -var defaultConfig = { - - module: { - noParse: [ - path.join(__dirname, 'zone.js', 'dist'), - path.join(__dirname, 'angular2', 'bundles') - ], - preLoaders: [ - { - test: /\.(html|css)$/, - loader: "plonetheme-preloader?backend=" + METADATA.PLONE // LOAD FROM PLONE - } - ], - }, - context: __dirname, - resolve: { - root: path.join(__dirname, '/src') - }, - output: { - publicPath: path.resolve(__dirname), - filename: 'bundle.js' - }, - plugins: [ - new WebpackNotifierPlugin({ - title: 'Plone webpack', - alwaysNotify: true - }) - ] -} - -var webpackMerge = require('webpack-merge'); -module.exports = [ - // Client - webpackMerge({}, defaultConfig, webpackConfig, clientConfig), - - // Server - webpackMerge({}, defaultConfig, webpackConfig, serverConfig) -] - -// Helpers -function checkNodeImport(context, request, cb) { - if (!path.isAbsolute(request) && request.charAt(0) !== '.') { - cb(null, 'commonjs ' + request); return; - } - cb(); -} diff --git a/demo/app.component.html b/demo/app.component.html deleted file mode 100644 index fb5ed601..00000000 --- a/demo/app.component.html +++ /dev/null @@ -1,2 +0,0 @@ - - diff --git a/demo/app.component.ts b/demo/app.component.ts index 350ba41e..8a39f94e 100644 --- a/demo/app.component.ts +++ b/demo/app.component.ts @@ -1,96 +1,128 @@ import { Component, - Directive, - ElementRef, - NgZone, - Renderer, - ViewEncapsulation, - ViewContainerRef -} from "@angular/core"; + ViewEncapsulation +} from '@angular/core'; import { - FormComponent, WidgetRegistry, Validator, DefaultWidgetRegistry -} from "../src"; +} from '../src'; + +declare const APP_VERSION: string; @Component({ - selector: "schema-form-demo-app", - template: require("./app.component.html"), - styleUrls: ["demo/app.scss"], - encapsulation: ViewEncapsulation.None, - providers: [{provide: WidgetRegistry, useClass: DefaultWidgetRegistry}] + selector: 'sf-demo-app', + template: ` +
+
+
+ + +
+
+
{{schema | json}}
+
+
+
+ `, + encapsulation: ViewEncapsulation.None, + providers: [{provide: WidgetRegistry, useClass: DefaultWidgetRegistry}] }) export class AppComponent { - private schema: any; - private model: any; - private fieldValidators: { [fieldId: string]: Validator} = {}; - private actions = {}; + version: string = APP_VERSION; - constructor(registry: WidgetRegistry) { + schema: any; + model: any; + fieldValidators: {[fieldId: string]: Validator } = {}; + actions = {}; - this.schema = (() => { - try { - return require("./sampleschema.json"); - } catch (e) { - console.log(e); - } - })(); - this.model = (() => { - try { - return require("./samplemodel.json"); + constructor(registry: WidgetRegistry) { + + this.schema = require('./sampleschema.json'); + this.model = require('./samplemodel.json'); + + this.fieldValidators['/bornOn'] = (value, property, form) => { + let errors = null; + let dateArr = value.split('-'); - } catch (e) { - console.log(e); + if (dateArr.length === 3) { + let now = new Date(); + let min = new Date( + now.getFullYear() - 100, + now.getMonth(), + now.getDay() + ).getTime(); + let max = new Date().getTime(); + let born = new Date( + dateArr[0], + dateArr[1] - 1, + dateArr[2] + ).getTime(); + + if (born < min || born > max) { + errors = [{ + bornOn: { + expectedValue: '>today - 100 && < today', + actualValue: value } - })(); - - this.fieldValidators["/bornOn"] = (value, property, form) => { - let errors = null; - let dateArr = value.split("-"); - if (dateArr.length === 3) { - let now = new Date(); - let min = new Date(now.getFullYear() - 100, now.getMonth(), now.getDay()).getTime(); - let max = new Date().getTime(); - let born = new Date(dateArr[0], dateArr[1] - 1, dateArr[2]).getTime(); - if (born < min || born > max ) { - errors = [{"bornOn": {"expectedValue": ">today - 100 && < today", "actualValue": value}}]; - } + }]; + } + } + return errors; + }; + + this.fieldValidators['/promotion'] = (value, property, form) => { + + if (value === 'student') { + let bornOn = form.getProperty('/bornOn'); + + if (bornOn.valid) { + let date = bornOn.value.split('-'); + let validYear = new Date().getFullYear() - 17; + + try { + let actualYear = parseInt(date[0], 10); + + if (actualYear < validYear) { + return null; } - return errors; - }; - - this.fieldValidators["/promotion"] = (value, property, form) => { - if (value === "student") { - let bornOn = form.getProperty("/bornOn"); - if (bornOn.valid) { - let date = bornOn.value.split("-"); - let validYear = new Date().getFullYear() - 17; - try { - let actualYear = parseInt(date[0]); - if (actualYear < validYear) { - return null; - } - return [{"promotion": {"bornOn": {"expectedValue": "year<" + validYear, "actualValue": actualYear}}}]; - } catch (e) { } + + return [{ + promotion: { + bornOn: { + expectedValue: 'year<' + validYear, + actualValue: actualYear } - return [{"promotion": {"bornOn": {"expectedFormat": "date", "actualValue": bornOn.value}}}]; + } + }]; + + } catch (e) { } + } + + return [{ + promotion: { + bornOn: { + expectedFormat: 'date', + actualValue: bornOn.value } - return null; - }; + } + }]; + } - this.actions["alert"] = (property, options) => { - alert(JSON.stringify(property.value)); - }; + return null; + }; - this.actions["reset"] = (form, options) => { - form.reset(); - }; + this.actions['alert'] = (property, options) => { + alert(JSON.stringify(property.value)); + }; - this.actions["addItem"] = (property, parameters) => { - property.addItem(parameters.value); - }; - } + this.actions['reset'] = (form, options) => { + form.reset(); + }; + this.actions['addItem'] = (property, parameters) => { + property.addItem(parameters.value); + }; + } } diff --git a/demo/app.module.ts b/demo/app.module.ts deleted file mode 100644 index aa5b46d4..00000000 --- a/demo/app.module.ts +++ /dev/null @@ -1,12 +0,0 @@ -import { NgModule } from "@angular/core"; -import { BrowserModule } from "@angular/platform-browser"; - -import { AppComponent } from "./app.component"; -import { SchemaFormModule } from "../src"; - -@NgModule({ - imports: [BrowserModule, SchemaFormModule], - declarations: [AppComponent], - bootstrap: [AppComponent] -}) -export class AppModule {} diff --git a/demo/app.scss b/demo/app.scss deleted file mode 100644 index e69de29b..00000000 diff --git a/demo/bootstrap.ts b/demo/bootstrap.ts new file mode 100644 index 00000000..9cf0b0f8 --- /dev/null +++ b/demo/bootstrap.ts @@ -0,0 +1,16 @@ +import { platformBrowserDynamic } from '@angular/platform-browser-dynamic'; +import { bootloader } from '@angularclass/hmr'; + +import { AppModule } from './module'; + +declare const HMR: string; + +export function main(): Promise { + return platformBrowserDynamic() + .bootstrapModule(AppModule) + .catch(err => console.error(err)); +} + +if (HMR) { bootloader(main); } +if (!HMR) { main(); } + diff --git a/demo/index.html b/demo/index.html index 8f3557bc..bc1967c5 100644 --- a/demo/index.html +++ b/demo/index.html @@ -1,48 +1,21 @@ - - + + + Angular2 Schema form + - <%= webpackConfig.metadata.title %> + - - - - + + - - - - - - - - - - - <% for (var css in htmlWebpackPlugin.files.css) { %> - - <% } %> - - - - - - ... Loading ... - - - - <% if (webpackConfig.metadata.ENV === 'development') { %> - - - <% } %> + + + Loading... + + diff --git a/demo/main.browser.ts b/demo/main.browser.ts deleted file mode 100644 index 885ceb48..00000000 --- a/demo/main.browser.ts +++ /dev/null @@ -1,5 +0,0 @@ -import { platformBrowserDynamic } from "@angular/platform-browser-dynamic"; -import { AppModule } from "./app.module"; - -platformBrowserDynamic().bootstrapModule(AppModule); - diff --git a/demo/module.ts b/demo/module.ts new file mode 100644 index 00000000..81861748 --- /dev/null +++ b/demo/module.ts @@ -0,0 +1,33 @@ +import { NgModule, ApplicationRef } from '@angular/core'; +import { BrowserModule } from '@angular/platform-browser'; +import { removeNgStyles, createNewHosts } from '@angularclass/hmr'; + +import { SchemaFormModule } from '../src'; + +import { AppComponent } from './app.component'; + +@NgModule({ + declarations: [ + AppComponent, + ], + imports: [ + BrowserModule, + SchemaFormModule + ], + bootstrap: [AppComponent] +}) +export class AppModule { + + constructor(private appRef: ApplicationRef) { } + + hmrOnDestroy(store) { + const cmpLocation = this.appRef.components.map(cmp => cmp.location.nativeElement); + store.disposeOldHosts = createNewHosts(cmpLocation); + removeNgStyles(); + } + + hmrAfterDestroy(store) { + store.disposeOldHosts(); + delete store.disposeOldHosts; + } +} diff --git a/demo/polyfills.ts b/demo/polyfills.ts index 00f68d9a..1200f9b2 100644 --- a/demo/polyfills.ts +++ b/demo/polyfills.ts @@ -1,14 +1,27 @@ -// Polyfills -// (these modules are what are in "angular2/bundles/angular2-polyfills" so don"t use that here) +import 'core-js/es6'; +import 'core-js/es7/reflect'; +import 'zone.js/dist/zone'; -// import "ie-shim"; // Internet Explorer -// import "aaadedes6-shim"; -// import "aaadedes6-promise"; -// import "aaadedes7-reflect-metadata"; +// ng2 +import { disableDebugTools } from '@angular/platform-browser'; +import '@angular/platform-browser-dynamic'; +import { enableProdMode } from '@angular/core'; +import '@angular/common'; -// Prefer CoreJS over the polyfills above -// import "core-js/es6"; -import "core-js/es7/reflect"; -require("zone.js/dist/zone"); +// RxJS +import 'rxjs/Rx'; -import "ts-helpers"; +declare const IS_PRODUCTION: boolean; +declare const IS_DEV: boolean; + +// optimization for production +// https://github.com/AngularClass/angular2-webpack-starter/blob/master/src/platform/environment.ts#L17 +if (IS_PRODUCTION) { + disableDebugTools(); + enableProdMode(); +} + +if (IS_DEV) { + Error.stackTraceLimit = Infinity; + require('zone.js/dist/long-stack-trace-zone'); +} diff --git a/demo/sampleschema.json b/demo/sampleschema.json index 79e63e83..e9c882f1 100644 --- a/demo/sampleschema.json +++ b/demo/sampleschema.json @@ -243,7 +243,7 @@ "fieldsets":[{ "id": "part_1", "title": "Part 1 - Recipient", - "fields":[ "firstName", "lastName", "bornOn","moreInfo", "colors","survey"] + "fields":[ "firstName", "lastName", "bornOn", "moreInfo", "favoriteColor", "colors","survey"] }, { "id": "part_2", diff --git a/demo/vendor.ts b/demo/vendor.ts deleted file mode 100644 index 010d4aad..00000000 --- a/demo/vendor.ts +++ /dev/null @@ -1,3 +0,0 @@ -import "@angular/core"; -import "@angular/common"; -import "z-schema"; diff --git a/install-peers.sh b/install-peers.sh deleted file mode 100755 index 3f49ce2a..00000000 --- a/install-peers.sh +++ /dev/null @@ -1,2 +0,0 @@ -#!/bin/sh -npm install @angular/forms @angular/common @angular/compiler @angular/platform-browser @angular/platform-browser-dynamic @angular/platform-server @angular/core core-js rxjs reflect-metadata zone.js diff --git a/karma.conf.js b/karma.conf.js index 6b5571f4..9649b156 100644 --- a/karma.conf.js +++ b/karma.conf.js @@ -1,3 +1 @@ -//Import the config file - module.exports = require('./config/karma.conf.js'); diff --git a/package.json b/package.json index 89e983ed..84825d67 100644 --- a/package.json +++ b/package.json @@ -2,37 +2,38 @@ "name": "angular2-schema-form", "version": "1.0.0-alpha.31", "description": "Angular2 Schema Form (DISCLAIMER: it is not related to angular-schema-form)", - "repository": { - "type": "git", - "url": "https://github.com/makinacorpus/angular2-schema-form" - }, "main": "dist/index.js", - "typings": "dist/src/index.d.ts", + "typings": "dist/index.d.ts", "scripts": { - "rimraf": "rimraf", - "typedoc": "typedoc --target es6 --mode file --out ./doc/ ./src/index.ts", - "webpack": "webpack", - "clean": "npm cache clean && npm run rimraf -- node_modules doc coverage dist", - "clean:dist": "rimraf -- dist", - "preclean:install": "npm run clean", - "clean:install": "npm set progress=false && npm install", - "preclean:start": "npm run clean", - "webpack-dev-server": "webpack-dev-server --config ./config/webpack.dev.js", - "build": "webpack --config ./config/webpack.prod.js --progress --profile --colors --display-error-details --display-cached --display-reasons", - "tsc": "tsc", - "prebuild": "npm run clean:dist", - "test:watch": "karma start --no-single-run", + "build": "npm-run-all -s lint clean tsc copy-template", + "copy-template": "copy ./src/**/**/*.html dist", + "check": "npm-check --skip-unused", "test": "karma start", - "start": "npm run webpack-dev-server", - "start:hmr": "npm run server:dev:hmr", - "prepublish": "export NODE_ENV=production; npm run build" + "watch:test": "npm run test -- --auto-watch --no-single-run", + "lint": "tslint ./src/**/*.ts ./test/**/*.ts", + "clean": "rimraf dist", + "watch": "webpack --display-error-details --watch", + "start": "webpack-dev-server", + "start:hmr": "webpack-dev-server --env.HMR", + "tsc": "tsc" + }, + "repository": { + "type": "git", + "url": "git+https://github.com/makinacorpus/angular2-schema-form" }, - "licenses": [ - { - "type": "BSD", - "url": "http://opensource.org/licenses/BSD-3-Clause" - } + "keywords": [ + "angularjs", + "angular", + "javascript", + "angular2", + "schema", + "form", + "schema form" ], + "license": "MIT", + "bugs": { + "url": "https://github.com/makinacorpus/angular2-schema-form/issues" + }, "contributors": [ "Frank Bessou ", "Eric Brehault ", @@ -45,83 +46,77 @@ "raw-loader": "0.5.1", "z-schema": "^3.17.0" }, + "peerDependencies": { + "@angular/common": "^2.2.4", + "@angular/compiler": "^2.2.4", + "@angular/core": "^2.2.4", + "@angular/forms": "^2.2.4", + "@angular/platform-browser": "^2.2.4", + "@angular/platform-browser-dynamic": "^2.2.4", + "core-js": "^2.4.0" + }, "devDependencies": { - "@types/body-parser": "0.0.33", - "@types/core-js": "^0.9.0", - "@types/fs-extra": "0.0.22-alpha", - "@types/hammerjs": "^2.0.22-alpha", - "@types/jasmine": "^2.2.34", - "@types/node": "^6.0.38", - "@types/z-schema": "^3.16.30", - "angular2-hmr": "~0.8.1", - "awesome-typescript-loader": "^2.2.4 ", + "@angular/common": "2.2.4", + "@angular/compiler": "2.2.4", + "@angular/compiler-cli": "2.2.4", + "@angular/core": "2.2.4", + "@angular/forms": "2.2.4", + "@angular/platform-browser": "2.2.4", + "@angular/platform-browser-dynamic": "2.2.4", + "@angular/platform-server": "2.2.4", + "@angularclass/hmr": "^1.2.2", + "@angularclass/hmr-loader": "^3.0.2", + "@ngtools/webpack": "^1.1.4", + "@types/core-js": "^0.9.28", + "@types/jasmine": "^2.5.37", + "@types/node": "^6.0.31", + "autoprefixer": "^6.4.0", + "awesome-typescript-loader": "2.2.4", "bootstrap": "^3.3.6", - "clean": "^4.0.2", - "codelyzer": "~0.0.26", - "compression-webpack-plugin": "^0.3.1", - "copy-webpack-plugin": "^2.1.3", - "css-loader": "^0.23.1", - "es6-promise": "^3.1.2", - "es6-promise-loader": "^1.0.1", - "es6-shim": "^0.35.0", - "exports-loader": "^0.6.3", - "expose-loader": "^0.7.1", - "file-loader": "^0.8.5", - "html-webpack-plugin": "^2.17.0", - "http-server": "^0.9.0", - "imports-loader": "^0.6.5", - "istanbul-instrumenter-loader": "^0.2.0", - "jasmine-core": "2.4.1", - "jasmine-spec-reporter": "2.5.0", + "chalk": "^1.1.3", + "clean-webpack-plugin": "^0.1.10", + "codelyzer": "~1.0.0-beta.4", + "copy": "^0.3.0", + "copy-webpack-plugin": "^4.0.0", + "core-js": "^2.4.0", + "cross-env": "^3.1.3", + "css-loader": "^0.24.0", + "extract-text-webpack-plugin": "^2.0.0-beta.4", + "fs-extra": "^1.0.0", + "gh-pages": "^0.11.0", + "html-webpack-plugin": "^2.22.0", + "istanbul-instrumenter-loader": "0.2.0", + "jasmine-core": "^2.5.2", "json-loader": "^0.5.4", - "karma": "1.2.0", - "karma-chrome-launcher": "^2.0.0", - "karma-cli": "^1.0.1", - "karma-coverage": "^1.0.0", + "karma": "^1.3.0", + "karma-coverage": "^1.1.1", "karma-jasmine": "^1.0.2", "karma-mocha-reporter": "^2.0.0", "karma-phantomjs-launcher": "^1.0.0", - "karma-remap-istanbul": "^0.2.1", + "karma-remap-coverage": "^0.1.2", "karma-sourcemap-loader": "^0.3.7", - "karma-webpack": "1.7.0", - "mime": "^1.3.4", - "node-sass": "^3.4.2", - "nodemon": "^1.8.1", - "parse5": "^1.5.1", + "karma-webpack": "^1.8.0", + "node-sass": "^3.10.1", + "npm-run-all": "^3.1.0", "phantomjs-polyfill": "0.0.2", "phantomjs-prebuilt": "^2.1.7", - "protractor": "4.0.9", - "raw-loader": "0.5.1", - "reflect-metadata": "^0.1.8", - "remap-istanbul": "^0.6.3", + "postcss": "^5.1.1", + "postcss-loader": "^0.9.1", + "progress-bar-webpack-plugin": "^1.9.0", + "replace": "^0.3.0", "rimraf": "^2.5.2", - "sass-loader": "^3.2.0", + "rxjs": "5.0.0-beta.12", + "sass-loader": "^4.0.1", "source-map-loader": "^0.1.5", - "style-loader": "^0.13.1", - "ts-helper": "0.0.1", - "ts-helpers": "1.1.1", - "ts-node": "1.2.1", - "tslint": "3.13.0", - "tslint-loader": "^2.1.3", - "typedoc": "^0.4.4", - "typescript": "2.0.2", - "url-loader": "^0.5.7", - "webpack": "^1.13.1", - "webpack-dev-server": "^1.14.1", - "webpack-md5-hash": "^0.0.5", - "webpack-merge": "^0.12.0", - "webpack-node-externals": "^1.2.0" - }, - "peerDependencies": { - "@angular/forms": "^2.0.0", - "@angular/common": "^2.0.0", - "@angular/compiler": "^2.0.0", - "@angular/platform-browser": "^2.0.0", - "@angular/platform-browser-dynamic": "^2.0.0", - "@angular/core": "^2.0.0", - "core-js": "^2.4.1", - "rxjs": "^5.0.0-beta.12", - "reflect-metadata": "^0.1.3", - "zone.js": "^0.6.25" + "style-loader": "0.13.1", + "ts-helpers": "^1.1.2", + "tslint": "3.15.1", + "tslint-loader": "^2.1.5", + "typescript": "2.0.10", + "webpack": "2.1.0-beta.27", + "webpack-dev-server": "2.1.0-beta.11", + "webpack-merge": "^0.15.0", + "webpack-notifier": "^1.4.0", + "zone.js": "^0.6.26" } } diff --git a/src/index.ts b/src/index.ts index 6f7d8570..7e940dff 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,6 +1,8 @@ -export { FormComponent } from "./schema-form/form.component"; -export { WidgetRegistry } from "./schema-form/widgetregistry"; -export * from "./schema-form/widget"; -export { Validator } from "./schema-form/model/validator"; -export { SchemaFormModule } from "./schema-form/schema-form.module"; -export { DefaultWidgetRegistry } from "./schema-form/defaultwidgets/defaultwidgetregistry"; +export { FormComponent } from './schema-form/form.component'; +export { WidgetRegistry } from './schema-form/widgetregistry'; +export { Validator } from './schema-form/model/validator'; +export { DefaultWidgetRegistry } from './schema-form/defaultwidgets/defaultwidgetregistry'; + + +export * from './schema-form/widget'; +export * from './schema-form/schema-form.module'; diff --git a/src/schema-form/default.widget.ts b/src/schema-form/default.widget.ts index 6448271c..96b76890 100644 --- a/src/schema-form/default.widget.ts +++ b/src/schema-form/default.widget.ts @@ -1,7 +1,9 @@ -import { Component } from "@angular/core"; +import { Component } from '@angular/core'; @Component({ - selector: "default-field", - template: `

Cannot find valid type for {{name}}` + selector: 'sf-default-field', + template: ` +

Cannot find valid type for {{name}} + ` }) export class DefaultWidget {} diff --git a/src/schema-form/defaultwidgets/array/array.widget.html b/src/schema-form/defaultwidgets/array/array.widget.html index 5f63b70b..63602412 100644 --- a/src/schema-form/defaultwidgets/array/array.widget.html +++ b/src/schema-form/defaultwidgets/array/array.widget.html @@ -4,7 +4,7 @@ {{schema.description}}

- + diff --git a/src/schema-form/defaultwidgets/array/array.widget.ts b/src/schema-form/defaultwidgets/array/array.widget.ts index 15a28a20..6851fd15 100644 --- a/src/schema-form/defaultwidgets/array/array.widget.ts +++ b/src/schema-form/defaultwidgets/array/array.widget.ts @@ -1,10 +1,10 @@ -import { Component } from "@angular/core"; +import { Component } from '@angular/core'; -import { ArrayLayoutWidget } from "../../widget"; +import { ArrayLayoutWidget } from '../../widget'; @Component({ - selector: "array-widget", - template: require("./array.widget.html") + selector: 'sf-array-widget', + template: require('./array.widget.html') }) export class ArrayWidget extends ArrayLayoutWidget { diff --git a/src/schema-form/defaultwidgets/checkbox/checkbox.widget.ts b/src/schema-form/defaultwidgets/checkbox/checkbox.widget.ts index eaeb51d9..01cc3fae 100644 --- a/src/schema-form/defaultwidgets/checkbox/checkbox.widget.ts +++ b/src/schema-form/defaultwidgets/checkbox/checkbox.widget.ts @@ -1,9 +1,9 @@ -import { Component } from "@angular/core"; +import { Component } from '@angular/core'; -import { ControlWidget } from "../../widget"; +import { ControlWidget } from '../../widget'; @Component({ - selector: "checkbox-widget", - template: require("./checkbox.widget.html") + selector: 'sf-checkbox-widget', + template: require('./checkbox.widget.html') }) export class CheckboxWidget extends ControlWidget {} diff --git a/src/schema-form/defaultwidgets/defaultwidgetregistry.spec.ts b/src/schema-form/defaultwidgets/defaultwidgetregistry.spec.ts index 4e68d6ad..6d14002e 100644 --- a/src/schema-form/defaultwidgets/defaultwidgetregistry.spec.ts +++ b/src/schema-form/defaultwidgets/defaultwidgetregistry.spec.ts @@ -1,24 +1,20 @@ -import { - inject, -} from "@angular/core/testing"; - import { IntegerWidget, TextAreaWidget, StringWidget -} from "./"; +} from './'; -import { DefaultWidgetRegistry } from "./defaultwidgetregistry"; +import { DefaultWidgetRegistry } from './defaultwidgetregistry'; -describe("DefaultWidgetRegistry", () => { +describe('DefaultWidgetRegistry', () => { - let STRING_TYPE = "string"; - let INT_TYPE = "integer"; - let TEXTAREA_TYPE = "textarea"; + let STRING_TYPE = 'string'; + let INT_TYPE = 'integer'; + let TEXTAREA_TYPE = 'textarea'; - let A_NOT_REGISTERED_TYPE = "FOOBARSTRING"; + let A_NOT_REGISTERED_TYPE = 'FOOBARSTRING'; let THE_DEFAULT_FIELD_TYPE = class { }; - let THE_TYPE = "date"; + let THE_TYPE = 'date'; let THE_FIELD_TYPE = class { }; let registry: DefaultWidgetRegistry; @@ -27,7 +23,7 @@ describe("DefaultWidgetRegistry", () => { registry = new DefaultWidgetRegistry(); }); - it("should be initialized with primitives widgets", () => { + it('should be initialized with primitives widgets', () => { let stringWidget = registry.getWidgetType(STRING_TYPE); let integerWidget = registry.getWidgetType(INT_TYPE); let textareaWidget = registry.getWidgetType(TEXTAREA_TYPE); @@ -37,13 +33,13 @@ describe("DefaultWidgetRegistry", () => { expect(textareaWidget).toBe(TextAreaWidget); }); - it("should return a default widget if there is no matching string in widgets", () => { + it('should return a default widget if there is no matching string in widgets', () => { let widget = registry.getWidgetType(A_NOT_REGISTERED_TYPE); expect(widget).not.toBe(null); }); - it("should return the widget type set when there is no matching type registered", () => { + it('should return the widget type set when there is no matching type registered', () => { registry.setDefaultWidget(THE_DEFAULT_FIELD_TYPE); let widget = registry.getWidgetType(A_NOT_REGISTERED_TYPE); @@ -51,7 +47,7 @@ describe("DefaultWidgetRegistry", () => { expect(widget).toBe(THE_DEFAULT_FIELD_TYPE); }); - it("should register a widget type", () => { + it('should register a widget type', () => { registry.register(THE_TYPE, THE_FIELD_TYPE); let widget = registry.getWidgetType(THE_TYPE); diff --git a/src/schema-form/defaultwidgets/defaultwidgetregistry.ts b/src/schema-form/defaultwidgets/defaultwidgetregistry.ts index 485e7f67..54891f29 100644 --- a/src/schema-form/defaultwidgets/defaultwidgetregistry.ts +++ b/src/schema-form/defaultwidgets/defaultwidgetregistry.ts @@ -9,39 +9,39 @@ import { RangeWidget, SelectWidget, StringWidget -} from "./"; +} from './'; -import { WidgetRegistry } from "../widgetregistry"; +import { WidgetRegistry } from '../widgetregistry'; export class DefaultWidgetRegistry extends WidgetRegistry { constructor() { super(); - this.register("array", ArrayWidget); - this.register("object", ObjectWidget); - - this.register("string", StringWidget); - this.register("search", StringWidget); - this.register("tel", StringWidget); - this.register("url", StringWidget); - this.register("email", StringWidget); - this.register("password", StringWidget); - this.register("color", StringWidget); - this.register("date", StringWidget); - this.register("date-time", StringWidget); - this.register("time", StringWidget); - - this.register("integer", IntegerWidget); - this.register("number", IntegerWidget); - this.register("range", RangeWidget); - - this.register("textarea", TextAreaWidget); - - this.register("file", FileWidget); - this.register("select", SelectWidget); - this.register("radio", RadioWidget); - this.register("boolean", CheckboxWidget); - this.register("checkbox", CheckboxWidget); + this.register('array', ArrayWidget); + this.register('object', ObjectWidget); + + this.register('string', StringWidget); + this.register('search', StringWidget); + this.register('tel', StringWidget); + this.register('url', StringWidget); + this.register('email', StringWidget); + this.register('password', StringWidget); + this.register('color', StringWidget); + this.register('date', StringWidget); + this.register('date-time', StringWidget); + this.register('time', StringWidget); + + this.register('integer', IntegerWidget); + this.register('number', IntegerWidget); + this.register('range', RangeWidget); + + this.register('textarea', TextAreaWidget); + + this.register('file', FileWidget); + this.register('select', SelectWidget); + this.register('radio', RadioWidget); + this.register('boolean', CheckboxWidget); + this.register('checkbox', CheckboxWidget); this.setDefaultWidget(StringWidget); } diff --git a/src/schema-form/defaultwidgets/file/file.widget.ts b/src/schema-form/defaultwidgets/file/file.widget.ts index 8084eb47..6cc3fc83 100644 --- a/src/schema-form/defaultwidgets/file/file.widget.ts +++ b/src/schema-form/defaultwidgets/file/file.widget.ts @@ -1,12 +1,10 @@ -import { - Component, -} from "@angular/core"; +import { Component } from '@angular/core'; -import { ControlWidget } from "../../widget"; +import { ControlWidget } from '../../widget'; @Component({ - selector: "file-widget", - template: require("./file.widget.html") + selector: 'sf-file-widget', + template: require('./file.widget.html') }) export class FileWidget extends ControlWidget { diff --git a/src/schema-form/defaultwidgets/index.ts b/src/schema-form/defaultwidgets/index.ts index b45bb55a..101713b2 100644 --- a/src/schema-form/defaultwidgets/index.ts +++ b/src/schema-form/defaultwidgets/index.ts @@ -1,11 +1,11 @@ -export * from "./array/array.widget"; -export * from "./object/object.widget"; -export * from "./checkbox/checkbox.widget"; -export * from "./file/file.widget"; -export * from "./integer/integer.widget"; -export * from "./radio/radio.widget"; -export * from "./range/range.widget"; -export * from "./select/select.widget"; -export * from "./string/string.widget"; -export * from "./textarea/textarea.widget"; -export * from "./defaultwidgetregistry"; +export * from './array/array.widget'; +export * from './object/object.widget'; +export * from './checkbox/checkbox.widget'; +export * from './file/file.widget'; +export * from './integer/integer.widget'; +export * from './radio/radio.widget'; +export * from './range/range.widget'; +export * from './select/select.widget'; +export * from './string/string.widget'; +export * from './textarea/textarea.widget'; +export * from './defaultwidgetregistry'; diff --git a/src/schema-form/defaultwidgets/integer/integer.widget.spec.ts b/src/schema-form/defaultwidgets/integer/integer.widget.spec.ts deleted file mode 100644 index 047be5c7..00000000 --- a/src/schema-form/defaultwidgets/integer/integer.widget.spec.ts +++ /dev/null @@ -1,13 +0,0 @@ -import { - inject, -} from "@angular/core/testing"; - -import { IntegerWidget } from "./integer.widget"; - -describe("IntegerWidget", () => { - let THE_VALUE = 1337; - - - xit("should initialize value from input", () => {}); - -}); diff --git a/src/schema-form/defaultwidgets/integer/integer.widget.ts b/src/schema-form/defaultwidgets/integer/integer.widget.ts index b2e0b9d7..7fac4a4a 100644 --- a/src/schema-form/defaultwidgets/integer/integer.widget.ts +++ b/src/schema-form/defaultwidgets/integer/integer.widget.ts @@ -1,11 +1,11 @@ import { Component, -} from "@angular/core"; +} from '@angular/core'; -import { ControlWidget } from "../../widget"; +import { ControlWidget } from '../../widget'; @Component({ - selector: "integer-widget", - template: require("./integer.widget.html") + selector: 'sf-integer-widget', + template: require('./integer.widget.html') }) export class IntegerWidget extends ControlWidget {} diff --git a/src/schema-form/defaultwidgets/object/object.widget.html b/src/schema-form/defaultwidgets/object/object.widget.html index f9c78ed0..f275f779 100644 --- a/src/schema-form/defaultwidgets/object/object.widget.html +++ b/src/schema-form/defaultwidgets/object/object.widget.html @@ -1,6 +1,6 @@
{{fieldset.title}}
- +
diff --git a/src/schema-form/defaultwidgets/object/object.widget.ts b/src/schema-form/defaultwidgets/object/object.widget.ts index eb1bb801..4dc1fbe8 100644 --- a/src/schema-form/defaultwidgets/object/object.widget.ts +++ b/src/schema-form/defaultwidgets/object/object.widget.ts @@ -1,11 +1,9 @@ -import { - Component, -} from "@angular/core"; +import { Component } from '@angular/core'; -import { ObjectLayoutWidget } from "../../widget"; +import { ObjectLayoutWidget } from '../../widget'; @Component({ - selector: "form-object", - template: require("./object.widget.html") + selector: 'sf-form-object', + template: require('./object.widget.html') }) export class ObjectWidget extends ObjectLayoutWidget { } diff --git a/src/schema-form/defaultwidgets/radio/radio.widget.ts b/src/schema-form/defaultwidgets/radio/radio.widget.ts index d214951c..839df46b 100644 --- a/src/schema-form/defaultwidgets/radio/radio.widget.ts +++ b/src/schema-form/defaultwidgets/radio/radio.widget.ts @@ -1,9 +1,9 @@ -import { Component } from "@angular/core"; +import { Component } from '@angular/core'; -import { ControlWidget } from "../../widget"; +import { ControlWidget } from '../../widget'; @Component({ - selector: "radio-widget", - template: require("./radio.widget.html") + selector: 'sf-radio-widget', + template: require('./radio.widget.html') }) export class RadioWidget extends ControlWidget {} diff --git a/src/schema-form/defaultwidgets/range/range.widget.spec.ts b/src/schema-form/defaultwidgets/range/range.widget.spec.ts deleted file mode 100644 index 1a12565a..00000000 --- a/src/schema-form/defaultwidgets/range/range.widget.spec.ts +++ /dev/null @@ -1,13 +0,0 @@ -import { - inject, -} from "@angular/core/testing"; - - -import { RangeWidget } from "./range.widget"; - -describe("RangeWidget", () => { - let THE_VALUE = 12; - - xit("should initialize value from input", done => {}); - -}); diff --git a/src/schema-form/defaultwidgets/range/range.widget.ts b/src/schema-form/defaultwidgets/range/range.widget.ts index 11e26df7..79aa95d1 100644 --- a/src/schema-form/defaultwidgets/range/range.widget.ts +++ b/src/schema-form/defaultwidgets/range/range.widget.ts @@ -1,9 +1,9 @@ -import { Component } from "@angular/core"; +import { Component } from '@angular/core'; -import { ControlWidget } from "../../widget"; +import { ControlWidget } from '../../widget'; @Component({ - selector: "range-widget", - template: require("./range.widget.html") + selector: 'sf-range-widget', + template: require('./range.widget.html') }) export class RangeWidget extends ControlWidget {} diff --git a/src/schema-form/defaultwidgets/select/select.widget.ts b/src/schema-form/defaultwidgets/select/select.widget.ts index 192a1841..27a70d00 100644 --- a/src/schema-form/defaultwidgets/select/select.widget.ts +++ b/src/schema-form/defaultwidgets/select/select.widget.ts @@ -1,9 +1,9 @@ -import { Component } from "@angular/core"; +import { Component } from '@angular/core'; -import { ControlWidget } from "../../widget"; +import { ControlWidget } from '../../widget'; @Component({ - selector: "select-widget", - template: require("./select.widget.html") + selector: 'sf-select-widget', + template: require('./select.widget.html') }) export class SelectWidget extends ControlWidget {} diff --git a/src/schema-form/defaultwidgets/string/string.spec.ts b/src/schema-form/defaultwidgets/string/string.spec.ts deleted file mode 100644 index 7e18e702..00000000 --- a/src/schema-form/defaultwidgets/string/string.spec.ts +++ /dev/null @@ -1,12 +0,0 @@ -import { - inject, -} from "@angular/core/testing"; - -import { StringWidget } from "./string.widget"; - -describe("StringWidget", () => { - let THE_VALUE = "FOO"; - - xit("should initialize value from input", done => {}); - -}); diff --git a/src/schema-form/defaultwidgets/string/string.widget.ts b/src/schema-form/defaultwidgets/string/string.widget.ts index 0d2a88e0..e0c04156 100644 --- a/src/schema-form/defaultwidgets/string/string.widget.ts +++ b/src/schema-form/defaultwidgets/string/string.widget.ts @@ -1,18 +1,18 @@ -import { Component } from "@angular/core"; +import { Component } from '@angular/core'; -import { ControlWidget } from "../../widget"; +import { ControlWidget } from '../../widget'; @Component({ - selector: "string-widget", - template: require("./string.widget.html") + selector: 'sf-string-widget', + template: require('./string.widget.html') }) export class StringWidget extends ControlWidget { getInputType() { - if(!this.schema.widget.id || this.schema.widget.id === 'string') { - return 'text' + if (!this.schema.widget.id || this.schema.widget.id === 'string') { + return 'text'; } else { - return this.schema.widget.id + return this.schema.widget.id; } } } diff --git a/src/schema-form/defaultwidgets/textarea/textarea.widget.ts b/src/schema-form/defaultwidgets/textarea/textarea.widget.ts index 623fde3d..892a83fe 100644 --- a/src/schema-form/defaultwidgets/textarea/textarea.widget.ts +++ b/src/schema-form/defaultwidgets/textarea/textarea.widget.ts @@ -1,9 +1,9 @@ -import { Component } from "@angular/core"; +import { Component } from '@angular/core'; -import { ControlWidget } from "../../widget"; +import { ControlWidget } from '../../widget'; @Component({ - selector: "textarea-widget", - template: require("./textarea.widget.html") + selector: 'sf-textarea-widget', + template: require('./textarea.widget.html') }) export class TextAreaWidget extends ControlWidget {} diff --git a/src/schema-form/form.component.html b/src/schema-form/form.component.html index c018eabb..bb6d5404 100644 --- a/src/schema-form/form.component.html +++ b/src/schema-form/form.component.html @@ -1 +1 @@ - + diff --git a/src/schema-form/form.component.ts b/src/schema-form/form.component.ts index ef33a36f..a8a11f3c 100644 --- a/src/schema-form/form.component.ts +++ b/src/schema-form/form.component.ts @@ -5,7 +5,7 @@ import { EventEmitter, Input, Output -} from "@angular/core"; +} from '@angular/core'; import { Action, @@ -15,15 +15,15 @@ import { SchemaPreprocessor, ValidatorRegistry, Validator -} from "./model"; +} from './model'; -import { SchemaValidatorFactory, ZSchemaValidatorFactory } from "./schemavalidatorfactory"; -import { WidgetFactory } from "./widgetfactory"; +import { SchemaValidatorFactory, ZSchemaValidatorFactory } from './schemavalidatorfactory'; +import { WidgetFactory } from './widgetfactory'; @Component({ - selector: "schema-form", - template: require("./form.component.html"), + selector: 'sf-form', + template: require('./form.component.html'), providers: [ ActionRegistry, ValidatorRegistry, @@ -63,7 +63,7 @@ export class FormComponent implements OnChanges { ) { } ngOnChanges(changes: any) { - + console.log(changes); if (changes.validators) { this.setValidators(); } @@ -72,11 +72,12 @@ export class FormComponent implements OnChanges { this.setActions(); } - if(!this.schema.type) { + if (!this.schema.type) { this.schema.type = 'object'; } if (this.schema && changes.schema) { + console.log(this.schema, changes.schema); SchemaPreprocessor.preprocess(this.schema); this.rootProperty = this.formPropertyFactory.createProperty(this.schema); this.rootProperty.valueChanges.subscribe(value => { this.onChange.emit({value: value}); }); @@ -92,7 +93,9 @@ export class FormComponent implements OnChanges { this.validatorRegistry.clear(); if (this.validators) { for (let validatorId in this.validators) { - this.validatorRegistry.register(validatorId, this.validators[validatorId]); + if (this.validators.hasOwnProperty(validatorId)) { + this.validatorRegistry.register(validatorId, this.validators[validatorId]); + } } } } @@ -101,7 +104,9 @@ export class FormComponent implements OnChanges { this.actionRegistry.clear(); if (this.actions) { for (let actionId in this.actions) { - this.actionRegistry.register(actionId, this.actions[actionId]); + if (this.actions.hasOwnProperty(actionId)) { + this.actionRegistry.register(actionId, this.actions[actionId]); + } } } } diff --git a/src/schema-form/formelement.component.html b/src/schema-form/formelement.component.html index d3043a4d..db266233 100644 --- a/src/schema-form/formelement.component.html +++ b/src/schema-form/formelement.component.html @@ -1,7 +1,7 @@
- - +
diff --git a/src/schema-form/formelement.component.ts b/src/schema-form/formelement.component.ts index e1b57607..bd34e3d5 100644 --- a/src/schema-form/formelement.component.ts +++ b/src/schema-form/formelement.component.ts @@ -1,35 +1,35 @@ import { Component, - ChangeDetectorRef, Input, OnInit -} from "@angular/core"; +} from '@angular/core'; import { FormControl -} from "@angular/forms"; +} from '@angular/forms'; -import { Widget } from "./widget"; +import { Widget } from './widget'; import { ActionRegistry, FormProperty -} from "./model"; +} from './model'; @Component({ - selector: "form-element", - template: require("./formelement.component.html") + selector: 'sf-form-element', + template: require('./formelement.component.html') }) export class FormElementComponent implements OnInit { + private static counter = 0; + @Input() formProperty: FormProperty; - control: FormControl = new FormControl("", () => null); + control: FormControl = new FormControl('', () => null); private widget: Widget = null; private buttons = []; - private static counter = 0; constructor(private actionRegistry: ActionRegistry) {} @@ -59,9 +59,9 @@ export class FormElementComponent implements OnInit { }; } - private onWidgetInstanciated(widget: Widget) { + onWidgetInstanciated(widget: Widget) { this.widget = widget; - let id = "field" + (FormElementComponent.counter++); + let id = 'field' + (FormElementComponent.counter++); this.widget.formProperty = this.formProperty; this.widget.schema = this.formProperty.schema; diff --git a/src/schema-form/model/action.ts b/src/schema-form/model/action.ts index c5367084..f99d30d0 100644 --- a/src/schema-form/model/action.ts +++ b/src/schema-form/model/action.ts @@ -1,4 +1,4 @@ -import { FormProperty } from "./formproperty"; +import { FormProperty } from './formproperty'; export interface Action { (formProperty: FormProperty, parameters: any): void; } diff --git a/src/schema-form/model/actionregistry.ts b/src/schema-form/model/actionregistry.ts index 277c944e..7bc36659 100644 --- a/src/schema-form/model/actionregistry.ts +++ b/src/schema-form/model/actionregistry.ts @@ -1,5 +1,4 @@ -import { isPresent } from "./utils"; -import { Action } from "./action"; +import { Action } from './action'; export class ActionRegistry { actions: {[key: string]: Action} = {}; diff --git a/src/schema-form/model/arrayproperty.ts b/src/schema-form/model/arrayproperty.ts index 1cc97ee7..76c78015 100644 --- a/src/schema-form/model/arrayproperty.ts +++ b/src/schema-form/model/arrayproperty.ts @@ -1,7 +1,7 @@ -import { FormProperty, PropertyGroup } from "./formproperty"; -import { FormPropertyFactory } from "./formpropertyfactory"; -import { SchemaValidatorFactory } from "../schemavalidatorfactory"; -import { ValidatorRegistry } from "./validatorregistry"; +import { FormProperty, PropertyGroup } from './formproperty'; +import { FormPropertyFactory } from './formpropertyfactory'; +import { SchemaValidatorFactory } from '../schemavalidatorfactory'; +import { ValidatorRegistry } from './validatorregistry'; export class ArrayProperty extends PropertyGroup { @@ -53,7 +53,7 @@ export class ArrayProperty extends PropertyGroup { this._value = value; } - reset(value: any, onlySelf: boolean = true) { + reset(value: any, onlySelf = true) { value = value || this.schema.default || []; this.properties = []; this.resetProperties(value); @@ -67,8 +67,10 @@ export class ArrayProperty extends PropertyGroup { private resetProperties(value: any) { for (let idx in value) { - let property = this.addProperty(); - property.reset(value[idx], true); + if (value.hasOwnProperty(idx)) { + let property = this.addProperty(); + property.reset(value[idx], true); + } } } diff --git a/src/schema-form/model/atomicproperties.spec.ts b/src/schema-form/model/atomicproperties.spec.ts index 03b0a1c2..94332871 100644 --- a/src/schema-form/model/atomicproperties.spec.ts +++ b/src/schema-form/model/atomicproperties.spec.ts @@ -1,23 +1,22 @@ import { AtomicProperty -} from "./atomicproperty"; +} from './atomicproperty'; import { FormProperty -} from "./formproperty"; +} from './formproperty'; import { NumberProperty -} from "./numberproperty"; +} from './numberproperty'; import { ValidatorRegistry -} from "./validatorregistry"; +} from './validatorregistry'; import { - ZSchemaValidatorFactory, - SchemaValidatorFactory -} from "../schemavalidatorfactory"; + ZSchemaValidatorFactory +} from '../schemavalidatorfactory'; class AtomicPropertyImpl extends AtomicProperty { @@ -26,32 +25,37 @@ class AtomicPropertyImpl extends AtomicProperty { } } -describe("Atomic properties", () => { +describe('Atomic properties', () => { let A_SCHEMA_VALIDATOR_FACTORY = new ZSchemaValidatorFactory(); let A_VALIDATOR_REGISTRY = new ValidatorRegistry(); - describe("AtomicProperty", () => { + describe('AtomicProperty', () => { let THE_PROPERTY_SCHEMA = {}; - let THE_VALUE = "FOO"; let atomicProperty: AtomicProperty; beforeEach(() => { - atomicProperty = new AtomicPropertyImpl(A_SCHEMA_VALIDATOR_FACTORY, A_VALIDATOR_REGISTRY, THE_PROPERTY_SCHEMA, null, ""); + atomicProperty = new AtomicPropertyImpl(A_SCHEMA_VALIDATOR_FACTORY, A_VALIDATOR_REGISTRY, THE_PROPERTY_SCHEMA, null, ''); }); - it("reset with no argument and default value in schema should use the default value", () => { + it('reset with no argument and default value in schema should use the default value', () => { let THE_DEFAULT_VALUE = Symbol(); - let A_SCHEMA_WITH_DEFAULT = {"default": THE_DEFAULT_VALUE }; - let atomicPropertyWithDefault = new AtomicPropertyImpl(A_SCHEMA_VALIDATOR_FACTORY, A_VALIDATOR_REGISTRY, A_SCHEMA_WITH_DEFAULT, null, ""); + let A_SCHEMA_WITH_DEFAULT = {'default': THE_DEFAULT_VALUE }; + let atomicPropertyWithDefault = new AtomicPropertyImpl( + A_SCHEMA_VALIDATOR_FACTORY, + A_VALIDATOR_REGISTRY, + A_SCHEMA_WITH_DEFAULT, + null, + '' + ); atomicPropertyWithDefault.reset(); expect(atomicPropertyWithDefault.value).toBe(THE_DEFAULT_VALUE); }); - it("reset with no argument, and no default value in schema use property's type fallback default", () => { + it('reset with no argument, and no default value in schema use property\'s type fallback default', () => { let fallback = Symbol(); - spyOn(atomicProperty, "fallbackValue").and.returnValue(fallback); + spyOn(atomicProperty, 'fallbackValue').and.returnValue(fallback); atomicProperty.reset(); @@ -59,21 +63,33 @@ describe("Atomic properties", () => { }); }); - describe("NumberProperty", () => { + describe('NumberProperty', () => { - let AN_INT_PROPERTY_SCHEMA_WITH_MINIMUM = {"type": "number", "minimum": 10}; - let AN_INT_PROPERTY_SCHEMA_WITHOUT_MINIMUM = {"type": "number"}; + let AN_INT_PROPERTY_SCHEMA_WITH_MINIMUM = {'type': 'number', 'minimum': 10}; + let AN_INT_PROPERTY_SCHEMA_WITHOUT_MINIMUM = {'type': 'number'}; - it("with minimum in schema should fallback to minimum on reset", () => { - let property = new NumberProperty(A_SCHEMA_VALIDATOR_FACTORY, A_VALIDATOR_REGISTRY, AN_INT_PROPERTY_SCHEMA_WITH_MINIMUM, null, ""); + it('with minimum in schema should fallback to minimum on reset', () => { + let property = new NumberProperty( + A_SCHEMA_VALIDATOR_FACTORY, + A_VALIDATOR_REGISTRY, + AN_INT_PROPERTY_SCHEMA_WITH_MINIMUM, + null, + '' + ); property.reset(); expect(property.value).toBe(AN_INT_PROPERTY_SCHEMA_WITH_MINIMUM.minimum); }); - it("without minimum in schema should fallback to 0 on reset", () => { - let property = new NumberProperty(A_SCHEMA_VALIDATOR_FACTORY, A_VALIDATOR_REGISTRY, AN_INT_PROPERTY_SCHEMA_WITHOUT_MINIMUM, null, ""); + it('without minimum in schema should fallback to 0 on reset', () => { + let property = new NumberProperty( + A_SCHEMA_VALIDATOR_FACTORY, + A_VALIDATOR_REGISTRY, + AN_INT_PROPERTY_SCHEMA_WITHOUT_MINIMUM, + null, + '' + ); property.reset(); diff --git a/src/schema-form/model/atomicproperty.ts b/src/schema-form/model/atomicproperty.ts index a588620a..5051f961 100644 --- a/src/schema-form/model/atomicproperty.ts +++ b/src/schema-form/model/atomicproperty.ts @@ -1,5 +1,4 @@ -import { SchemaValidatorFactory } from "../schemavalidatorfactory"; -import { FormProperty } from "./formproperty"; +import { FormProperty } from './formproperty'; export abstract class AtomicProperty extends FormProperty { diff --git a/src/schema-form/model/booleanproperty.ts b/src/schema-form/model/booleanproperty.ts index e39f3507..c71cc686 100644 --- a/src/schema-form/model/booleanproperty.ts +++ b/src/schema-form/model/booleanproperty.ts @@ -1,4 +1,4 @@ -import { AtomicProperty } from "./atomicproperty"; +import { AtomicProperty } from './atomicproperty'; export class BooleanProperty extends AtomicProperty { diff --git a/src/schema-form/model/formproperty.spec.ts b/src/schema-form/model/formproperty.spec.ts index f5a9f451..e034e20b 100644 --- a/src/schema-form/model/formproperty.spec.ts +++ b/src/schema-form/model/formproperty.spec.ts @@ -1,11 +1,10 @@ -import { FormProperty, PropertyGroup } from "./formproperty"; +import { FormProperty, PropertyGroup } from './formproperty'; import { - ZSchemaValidatorFactory, - SchemaValidatorFactory -} from "../schemavalidatorfactory"; + ZSchemaValidatorFactory +} from '../schemavalidatorfactory'; -import { ValidatorRegistry } from "./validatorregistry"; +import { ValidatorRegistry } from './validatorregistry'; class FormPropertyImpl extends FormProperty { @@ -25,7 +24,7 @@ class PropertyGroupImpl extends PropertyGroup { reset() {} } -describe("FormProperty", () => { +describe('FormProperty', () => { let THE_SCHEMA_VALIDATOR_FACTORY = new ZSchemaValidatorFactory(); let THE_VALIDATOR_REGISTRY = new ValidatorRegistry(); let THE_PROPERTY_SCHEMA = {}; @@ -36,19 +35,31 @@ describe("FormProperty", () => { let propertyGroup: PropertyGroup; beforeEach(() => { - THE_VALIDATOR = jasmine.createSpy("a_validator"); - spyOn(THE_SCHEMA_VALIDATOR_FACTORY, "createValidatorFn").and.returnValue(THE_VALIDATOR); - - propertyGroup = new PropertyGroupImpl(THE_SCHEMA_VALIDATOR_FACTORY, THE_VALIDATOR_REGISTRY, THE_PARENT_PROPERTY_SCHEMA, null, ""); - spyOn(propertyGroup, "updateValueAndValidity"); - formProperty = new FormPropertyImpl(THE_SCHEMA_VALIDATOR_FACTORY, THE_VALIDATOR_REGISTRY, THE_PROPERTY_SCHEMA, propertyGroup, ""); + THE_VALIDATOR = jasmine.createSpy('a_validator'); + spyOn(THE_SCHEMA_VALIDATOR_FACTORY, 'createValidatorFn').and.returnValue(THE_VALIDATOR); + + propertyGroup = new PropertyGroupImpl( + THE_SCHEMA_VALIDATOR_FACTORY, + THE_VALIDATOR_REGISTRY, + THE_PARENT_PROPERTY_SCHEMA, + null, + '' + ); + spyOn(propertyGroup, 'updateValueAndValidity'); + formProperty = new FormPropertyImpl( + THE_SCHEMA_VALIDATOR_FACTORY, + THE_VALIDATOR_REGISTRY, + THE_PROPERTY_SCHEMA, + propertyGroup, + '' + ); }); - it("should create a validator on construction", () => { + it('should create a validator on construction', () => { expect(THE_SCHEMA_VALIDATOR_FACTORY.createValidatorFn).toHaveBeenCalledWith(THE_PROPERTY_SCHEMA); }); - it("should validate using the validator created on construction", () => { + it('should validate using the validator created on construction', () => { formProperty._runValidation(); @@ -56,9 +67,9 @@ describe("FormProperty", () => { }); - describe("With a parent", () => { + describe('With a parent', () => { - it("should notify parent when changed", () => { + it('should notify parent when changed', () => { formProperty.updateValueAndValidity(); expect(propertyGroup.updateValueAndValidity).toHaveBeenCalled(); @@ -66,10 +77,16 @@ describe("FormProperty", () => { }); - describe("Without a parent", () => { + describe('Without a parent', () => { - it("should not throw when changed", () => { - let orphanFormProperty = new FormPropertyImpl(THE_SCHEMA_VALIDATOR_FACTORY, THE_VALIDATOR_REGISTRY, THE_PROPERTY_SCHEMA, propertyGroup, ""); + it('should not throw when changed', () => { + let orphanFormProperty = new FormPropertyImpl( + THE_SCHEMA_VALIDATOR_FACTORY, + THE_VALIDATOR_REGISTRY, + THE_PROPERTY_SCHEMA, + propertyGroup, + '' + ); let updateValue = (() => { orphanFormProperty.updateValueAndValidity(); }); expect(updateValue).not.toThrow(); diff --git a/src/schema-form/model/formproperty.ts b/src/schema-form/model/formproperty.ts index 04f7d3d5..c4ee47db 100644 --- a/src/schema-form/model/formproperty.ts +++ b/src/schema-form/model/formproperty.ts @@ -1,12 +1,12 @@ -import { Observable } from "rxjs/Observable"; -import { BehaviorSubject } from "rxjs/BehaviorSubject"; -import "rxjs/add/observable/combineLatest"; -import "rxjs/add/operator/map"; -import "rxjs/add/operator/do"; -import "rxjs/add/operator/distinctUntilChanged"; +import { Observable } from 'rxjs/Observable'; +import { BehaviorSubject } from 'rxjs/BehaviorSubject'; +import 'rxjs/add/observable/combineLatest'; +import 'rxjs/add/operator/map'; +import 'rxjs/add/operator/do'; +import 'rxjs/add/operator/distinctUntilChanged'; -import { SchemaValidatorFactory } from "../schemavalidatorfactory"; -import { ValidatorRegistry } from "./validatorregistry"; +import { SchemaValidatorFactory } from '../schemavalidatorfactory'; +import { ValidatorRegistry } from './validatorregistry'; export abstract class FormProperty { public schemaValidator: Function; @@ -140,7 +140,7 @@ export abstract class FormProperty { let base: PropertyGroup = null; let result = null; - if (path[0] === "/") { + if (path[0] === '/') { base = this.findRoot(); result = base.getProperty(path.substr(1)); } else { @@ -175,16 +175,18 @@ export abstract class FormProperty { if (visibleIf !== undefined) { let propertiesBinding = []; for (let dependencyPath in visibleIf) { - let property = this.searchProperty(dependencyPath); - if (property) { - let valueCheck = property.valueChanges.map( - value => visibleIf[dependencyPath].indexOf(value) !== -1 - ); - let visibilityCheck = property._visibilityChanges; - let and = Observable.combineLatest([valueCheck, visibilityCheck], (v1, v2) => v1 && v2); - propertiesBinding.push(and); - } else { - console.warn("Can't find property " + dependencyPath + " for visibility check of " + this.path); + if (visibleIf.hasOwnProperty(dependencyPath)) { + let property = this.searchProperty(dependencyPath); + if (property) { + let valueCheck = property.valueChanges.map( + value => visibleIf[dependencyPath].indexOf(value) !== -1 + ); + let visibilityCheck = property._visibilityChanges; + let and = Observable.combineLatest([valueCheck, visibilityCheck], (v1, v2) => v1 && v2); + propertiesBinding.push(and); + } else { + console.warn('Can\'t find property ' + dependencyPath + ' for visibility check of ' + this.path); + } } } @@ -202,7 +204,7 @@ export abstract class PropertyGroup extends FormProperty { protected properties: FormProperty[] | {[key: string]: FormProperty} = null; getProperty(path: string) { - let subPathIdx = path.indexOf("/"); + let subPathIdx = path.indexOf('/'); let propertyId = subPathIdx !== -1 ? path.substr(0, subPathIdx) : path ; let property = this.properties[propertyId]; @@ -215,8 +217,10 @@ export abstract class PropertyGroup extends FormProperty { public forEachChild(fn: (formProperty: FormProperty, str: String) => void) { for (let propertyId in this.properties) { - let property = this.properties[propertyId]; - fn(property, propertyId); + if (this.properties.hasOwnProperty(propertyId)) { + let property = this.properties[propertyId]; + fn(property, propertyId); + } } } diff --git a/src/schema-form/model/formpropertyfactory.ts b/src/schema-form/model/formpropertyfactory.ts index 5ba3b4e9..4c4be736 100644 --- a/src/schema-form/model/formpropertyfactory.ts +++ b/src/schema-form/model/formpropertyfactory.ts @@ -1,48 +1,48 @@ -import { FormProperty, PropertyGroup } from "./formproperty"; -import { NumberProperty } from "./numberproperty"; -import { StringProperty } from "./stringproperty"; -import { BooleanProperty } from "./booleanproperty"; -import { ObjectProperty } from "./objectproperty"; -import { ArrayProperty } from "./arrayproperty"; -import { SchemaValidatorFactory } from "../schemavalidatorfactory"; -import { ValidatorRegistry } from "./validatorregistry"; +import { FormProperty, PropertyGroup } from './formproperty'; +import { NumberProperty } from './numberproperty'; +import { StringProperty } from './stringproperty'; +import { BooleanProperty } from './booleanproperty'; +import { ObjectProperty } from './objectproperty'; +import { ArrayProperty } from './arrayproperty'; +import { SchemaValidatorFactory } from '../schemavalidatorfactory'; +import { ValidatorRegistry } from './validatorregistry'; export class FormPropertyFactory { constructor(private schemaValidatorFactory: SchemaValidatorFactory, private validatorRegistry: ValidatorRegistry) {} createProperty(schema: any, parent: PropertyGroup = null, propertyId?: string): FormProperty { let newProperty = null; - let path = ""; + let path = ''; if (parent) { path += parent.path; if (parent.parent !== null) { - path += "/"; + path += '/'; } - if (parent.type === "object") { + if (parent.type === 'object') { path += propertyId; - } else if (parent.type === "array") { - path += "*"; + } else if (parent.type === 'array') { + path += '*'; } else { - throw "Instanciation of a FormProperty with an unknown parent type: " + parent.type; + throw 'Instanciation of a FormProperty with an unknown parent type: ' + parent.type; } } else { - path = "/"; + path = '/'; } switch (schema.type) { - case "integer": - case "number": + case 'integer': + case 'number': newProperty = new NumberProperty(this.schemaValidatorFactory, this.validatorRegistry, schema, parent, path); break; - case "string": + case 'string': newProperty = new StringProperty(this.schemaValidatorFactory, this.validatorRegistry, schema, parent, path); break; - case "boolean": + case 'boolean': newProperty = new BooleanProperty(this.schemaValidatorFactory, this.validatorRegistry, schema, parent, path); break; - case "object": + case 'object': newProperty = new ObjectProperty(this, this.schemaValidatorFactory, this.validatorRegistry, schema, parent, path); break; - case "array": + case 'array': newProperty = new ArrayProperty(this, this.schemaValidatorFactory, this.validatorRegistry, schema, parent, path); break; default: diff --git a/src/schema-form/model/index.ts b/src/schema-form/model/index.ts index 9814e185..6d0022dc 100644 --- a/src/schema-form/model/index.ts +++ b/src/schema-form/model/index.ts @@ -1,13 +1,13 @@ -export * from "./action"; -export * from "./actionregistry"; +export * from './action'; +export * from './actionregistry'; -export * from "./formpropertyfactory"; -export * from "./formproperty"; -export * from "./atomicproperty"; -export * from "./objectproperty"; -export * from "./arrayproperty"; +export * from './formpropertyfactory'; +export * from './formproperty'; +export * from './atomicproperty'; +export * from './objectproperty'; +export * from './arrayproperty'; -export * from "./validator"; -export * from "./validatorregistry"; +export * from './validator'; +export * from './validatorregistry'; -export * from "./schemapreprocessor"; +export * from './schemapreprocessor'; diff --git a/src/schema-form/model/numberproperty.ts b/src/schema-form/model/numberproperty.ts index c9257993..520ca299 100644 --- a/src/schema-form/model/numberproperty.ts +++ b/src/schema-form/model/numberproperty.ts @@ -1,4 +1,4 @@ -import { AtomicProperty } from "./atomicproperty"; +import { AtomicProperty } from './atomicproperty'; export class NumberProperty extends AtomicProperty { @@ -13,8 +13,8 @@ export class NumberProperty extends AtomicProperty { } setValue(value, onlySelf = false) { - if(typeof value === 'string') { - value = value.indexOf('.') > -1 ? parseFloat(value) : parseInt(value); + if (typeof value === 'string') { + value = value.indexOf('.') > -1 ? parseFloat(value) : parseInt(value, 10); } this._value = value; this.updateValueAndValidity(onlySelf, true); diff --git a/src/schema-form/model/objectproperty.spec.ts b/src/schema-form/model/objectproperty.spec.ts index 5c6bf243..d9cb8b9a 100644 --- a/src/schema-form/model/objectproperty.spec.ts +++ b/src/schema-form/model/objectproperty.spec.ts @@ -1,15 +1,13 @@ -import { ObjectProperty } from "./objectproperty"; -import { FormProperty } from "./formproperty"; -import { FormPropertyFactory } from "./formpropertyfactory"; +import { ObjectProperty } from './objectproperty'; +import { FormPropertyFactory } from './formpropertyfactory'; import { - SchemaValidatorFactory, ZSchemaValidatorFactory -} from "../schemavalidatorfactory"; +} from '../schemavalidatorfactory'; -import { ValidatorRegistry } from "./validatorregistry"; +import { ValidatorRegistry } from './validatorregistry'; -describe("ObjectProperty", () => { +describe('ObjectProperty', () => { let A_VALIDATOR_REGISTRY = new ValidatorRegistry(); let A_SCHEMA_VALIDATOR_FACTORY = new ZSchemaValidatorFactory(); @@ -17,11 +15,11 @@ describe("ObjectProperty", () => { let THE_OBJECT_SCHEMA = { - type: "object", + type: 'object', properties: { - FOO: {type: "integer"}, - BAR: {type: "integer"}, - BAZ: {type: "object"} + FOO: {type: 'integer'}, + BAR: {type: 'integer'}, + BAZ: {type: 'object'} } }; @@ -29,14 +27,23 @@ describe("ObjectProperty", () => { beforeEach(() => { - objProperty = new ObjectProperty(A_FORM_PROPERTY_FACTORY, A_SCHEMA_VALIDATOR_FACTORY, A_VALIDATOR_REGISTRY, THE_OBJECT_SCHEMA, null, ""); + objProperty = new ObjectProperty( + A_FORM_PROPERTY_FACTORY, + A_SCHEMA_VALIDATOR_FACTORY, + A_VALIDATOR_REGISTRY, + THE_OBJECT_SCHEMA, + null, + '' + ); }); - it("should create same properties as in the schema", () => { + it('should create same properties as in the schema', () => { for (let propertyId in THE_OBJECT_SCHEMA.properties) { - let property = objProperty.getProperty(propertyId); - expect(property).toBeDefined(); + if (THE_OBJECT_SCHEMA.properties.hasOwnProperty(propertyId)) { + let property = objProperty.getProperty(propertyId); + expect(property).toBeDefined(); + } } }); diff --git a/src/schema-form/model/objectproperty.ts b/src/schema-form/model/objectproperty.ts index bd0aac35..e4433a4c 100644 --- a/src/schema-form/model/objectproperty.ts +++ b/src/schema-form/model/objectproperty.ts @@ -1,7 +1,7 @@ -import { PropertyGroup } from "./formproperty"; -import { FormPropertyFactory } from "./formpropertyfactory"; -import { SchemaValidatorFactory } from "../schemavalidatorfactory"; -import { ValidatorRegistry } from "./validatorregistry"; +import { PropertyGroup } from './formproperty'; +import { FormPropertyFactory } from './formpropertyfactory'; +import { SchemaValidatorFactory } from '../schemavalidatorfactory'; +import { ValidatorRegistry } from './validatorregistry'; export class ObjectProperty extends PropertyGroup { @@ -21,12 +21,14 @@ export class ObjectProperty extends PropertyGroup { setValue(value: any, onlySelf: boolean) { for (let propertyId in value) { - this.properties[propertyId].setValue(value[propertyId], true); + if (value.hasOwnProperty(propertyId)) { + this.properties[propertyId].setValue(value[propertyId], true); + } } this.updateValueAndValidity(onlySelf, true); } - reset(value: any, onlySelf: boolean = true) { + reset(value: any, onlySelf = true) { value = value || this.schema.default || {}; this.resetProperties(value); this.updateValueAndValidity(onlySelf, true); @@ -34,7 +36,9 @@ export class ObjectProperty extends PropertyGroup { resetProperties(value: any) { for (let propertyId in this.schema.properties) { - this.properties[propertyId].reset(value[propertyId], true); + if (this.schema.properties.hasOwnProperty(propertyId)) { + this.properties[propertyId].reset(value[propertyId], true); + } } } @@ -42,10 +46,12 @@ export class ObjectProperty extends PropertyGroup { this.properties = {}; this.propertiesId = []; for (let propertyId in this.schema.properties) { - let propertySchema = this.schema.properties[propertyId]; - let property = this.formPropertyFactory.createProperty(propertySchema, this, propertyId); - this.properties[propertyId] = property; - this.propertiesId.push(propertyId); + if (this.schema.properties.hasOwnProperty(propertyId)) { + let propertySchema = this.schema.properties[propertyId]; + let property = this.formPropertyFactory.createProperty(propertySchema, this, propertyId); + this.properties[propertyId] = property; + this.propertiesId.push(propertyId); + } } } diff --git a/src/schema-form/model/schemapreprocessor.spec.ts b/src/schema-form/model/schemapreprocessor.spec.ts index cd4cf6fa..d2718c7c 100644 --- a/src/schema-form/model/schemapreprocessor.spec.ts +++ b/src/schema-form/model/schemapreprocessor.spec.ts @@ -1,14 +1,14 @@ -import { SchemaPreprocessor } from "./schemapreprocessor"; -describe("SchemaPreprocessor", () => { +import { SchemaPreprocessor } from './schemapreprocessor'; +describe('SchemaPreprocessor', () => { - it("should replace order by fieldsets", () => { + it('should replace order by fieldsets', () => { let schema: any = { - "properties": { - "name": {}, - "email": {} + 'properties': { + 'name': {}, + 'email': {} }, - "order": ["name", "email"], - "type": "object" + 'order': ['name', 'email'], + 'type': 'object' }; SchemaPreprocessor.preprocess(schema); diff --git a/src/schema-form/model/schemapreprocessor.ts b/src/schema-form/model/schemapreprocessor.ts index c511821d..1829da32 100644 --- a/src/schema-form/model/schemapreprocessor.ts +++ b/src/schema-form/model/schemapreprocessor.ts @@ -1,7 +1,7 @@ -import { isBlank } from "./utils"; +import { isBlank } from './utils'; function formatMessage(message, path) { - return "Parsing error on " + path + ": " + message; + return `Parsing error on ${path}: ${message}`; } function schemaError(message, path): void { @@ -11,17 +11,18 @@ function schemaError(message, path): void { function schemaWarning(message, path): void { let mesg = formatMessage(message, path); + throw new Error(mesg); } export class SchemaPreprocessor { - static preprocess(jsonSchema: any, path: string = "/"): any { + static preprocess(jsonSchema: any, path = '/'): any { jsonSchema = jsonSchema || {}; - if (jsonSchema.type === "object") { + if (jsonSchema.type === 'object') { SchemaPreprocessor.checkProperties(jsonSchema, path); SchemaPreprocessor.checkAndCreateFieldsets(jsonSchema, path); SchemaPreprocessor.normalizeRequired(jsonSchema); - } else if (jsonSchema.type === "array") { + } else if (jsonSchema.type === 'array') { SchemaPreprocessor.checkItems(jsonSchema, path); } SchemaPreprocessor.normalizeWidget(jsonSchema); @@ -31,7 +32,7 @@ export class SchemaPreprocessor { private static checkProperties(jsonSchema, path: string) { if (isBlank(jsonSchema.properties)) { jsonSchema.properties = {}; - schemaWarning("Provided json schema does not contain a 'properties' entry. Output schema will be empty", path); + schemaWarning('Provided json schema does not contain a \'properties\' entry. Output schema will be empty', path); } } @@ -61,19 +62,21 @@ export class SchemaPreprocessor { for (let fieldId of fieldsId) { if (usedFields.hasOwnProperty(fieldId)) { if (usedFields[fieldId].length > 1) { - schemaError(fieldId + " is referenced by more than one fieldset: " + usedFields[fieldId], path); + schemaError(`${fieldId} is referenced by more than one fieldset: ${usedFields[fieldId]}`, path); } delete usedFields[fieldId]; } else if (jsonSchema.required.indexOf(fieldId) > -1 ) { - schemaError(fieldId + " is a required field but it is not referenced as part of a 'order' or a 'fieldset' property", path); + schemaError(`${fieldId} is a required field but it is not referenced as part of a 'order' or a 'fieldset' property`, path); } else { delete jsonSchema[fieldId]; - schemaWarning("Removing unreferenced field '" + fieldId + "'", path); + schemaWarning(`Removing unreferenced field ${fieldId}`, path); } } for (let remainingfieldsId in usedFields) { - schemaWarning("Referencing non-existent field '" + remainingfieldsId + "' in one or more fieldsets", path); + if (usedFields.hasOwnProperty(remainingfieldsId)) { + schemaWarning(`Referencing non-existent field ${remainingfieldsId} in one or more fieldsets`, path); + } } } @@ -84,8 +87,8 @@ export class SchemaPreprocessor { private static replaceOrderByFieldsets(jsonSchema) { jsonSchema.fieldsets = [{ - id: "fieldset-default", - title: jsonSchema.description || "", + id: 'fieldset-default', + title: jsonSchema.description || '', fields: jsonSchema.order }]; delete jsonSchema.order; @@ -94,35 +97,36 @@ export class SchemaPreprocessor { private static normalizeWidget(fieldSchema: any) { let widget = fieldSchema.widget; if (widget === undefined) { - widget = {"id": fieldSchema.type}; - } else if (typeof widget === "string") { - widget = {"id": widget}; + widget = {'id': fieldSchema.type}; + } else if (typeof widget === 'string') { + widget = {'id': widget}; } fieldSchema.widget = widget; } private static normalizeRequired(jsonSchema) { - if (jsonSchema.type === "object" && jsonSchema.required === undefined) { + if (jsonSchema.type === 'object' && jsonSchema.required === undefined) { jsonSchema.required = Object.keys(jsonSchema.properties); } } private static checkItems(jsonSchema, path) { if (jsonSchema.items === undefined) { - schemaError("No 'items' property in array", path); + schemaError('No \'items\' property in array', path); } } private static recursiveCheck(jsonSchema, path: string) { - if (jsonSchema.type === "object") { + if (jsonSchema.type === 'object') { for (let fieldId in jsonSchema.properties) { - let fieldSchema = jsonSchema.properties[fieldId]; - - SchemaPreprocessor.preprocess(fieldSchema, path + fieldId + "/"); + if (jsonSchema.properties.hasOwnProperty(fieldId)) { + let fieldSchema = jsonSchema.properties[fieldId]; + SchemaPreprocessor.preprocess(fieldSchema, path + fieldId + '/'); + } } - } else if (jsonSchema.type === "array") { - SchemaPreprocessor.preprocess(jsonSchema.items, path + "*/"); + } else if (jsonSchema.type === 'array') { + SchemaPreprocessor.preprocess(jsonSchema.items, path + '*/'); } } } diff --git a/src/schema-form/model/stringproperty.ts b/src/schema-form/model/stringproperty.ts index ce9f272d..08edc6fb 100644 --- a/src/schema-form/model/stringproperty.ts +++ b/src/schema-form/model/stringproperty.ts @@ -1,9 +1,9 @@ -import { AtomicProperty } from "./atomicproperty"; +import { AtomicProperty } from './atomicproperty'; export class StringProperty extends AtomicProperty { protected fallbackValue() { - return ""; + return ''; } } diff --git a/src/schema-form/model/validator.ts b/src/schema-form/model/validator.ts index 5e51d953..b040d481 100644 --- a/src/schema-form/model/validator.ts +++ b/src/schema-form/model/validator.ts @@ -1,4 +1,4 @@ -import { FormProperty, PropertyGroup } from "./formproperty"; +import { FormProperty, PropertyGroup } from './formproperty'; export interface Validator { (value: any, formProperty: FormProperty, form: PropertyGroup): [{[key: string]: any}]; diff --git a/src/schema-form/model/validatorregistry.ts b/src/schema-form/model/validatorregistry.ts index de16f15a..4acfd995 100644 --- a/src/schema-form/model/validatorregistry.ts +++ b/src/schema-form/model/validatorregistry.ts @@ -1,4 +1,4 @@ -import { Validator } from "./validator"; +import { Validator } from './validator'; export class ValidatorRegistry { private validators: Validator[] = []; diff --git a/src/schema-form/schema-form.module.ts b/src/schema-form/schema-form.module.ts index 29de0bee..4b939cd3 100644 --- a/src/schema-form/schema-form.module.ts +++ b/src/schema-form/schema-form.module.ts @@ -1,14 +1,13 @@ -import { NgModule } from "@angular/core"; -import { CommonModule } from "@angular/common"; +import { NgModule } from '@angular/core'; +import { CommonModule } from '@angular/common'; import { FormsModule, ReactiveFormsModule -} from "@angular/forms"; +} from '@angular/forms'; -import { FormElementComponent } from "./formelement.component"; -import { FormComponent } from "./form.component"; -import { WidgetChooserComponent } from "./widgetchooser.component"; -import { WidgetRegistry } from "./widgetregistry"; +import { FormElementComponent } from './formelement.component'; +import { FormComponent } from './form.component'; +import { WidgetChooserComponent } from './widgetchooser.component'; import { ArrayWidget, ObjectWidget, @@ -20,7 +19,7 @@ import { RangeWidget, SelectWidget, StringWidget -} from "./defaultwidgets"; +} from './defaultwidgets'; @NgModule({ imports : [CommonModule, FormsModule, ReactiveFormsModule], diff --git a/src/schema-form/schemavalidatorfactory.ts b/src/schema-form/schemavalidatorfactory.ts index 7700c538..6176fc1a 100644 --- a/src/schema-form/schemavalidatorfactory.ts +++ b/src/schema-form/schemavalidatorfactory.ts @@ -1,4 +1,4 @@ -let ZSchema = require("z-schema"); +let ZSchema = require('z-schema'); export abstract class SchemaValidatorFactory { abstract createValidatorFn(schema): (value: any) => any; @@ -16,11 +16,11 @@ export class ZSchemaValidatorFactory extends SchemaValidatorFactory { createValidatorFn(schema: any) { return (value): { [key: string]: boolean } => { - if (schema.type === "number" || schema.type === "integer") { + if (schema.type === 'number' || schema.type === 'integer') { value = +value; } - let result = this.zschema.validate(value, schema); + this.zschema.validate(value, schema); let err = this.zschema.getLastErrors(); return err || null; }; diff --git a/src/schema-form/widget.ts b/src/schema-form/widget.ts index 74118e7c..def69aab 100644 --- a/src/schema-form/widget.ts +++ b/src/schema-form/widget.ts @@ -1,13 +1,13 @@ -import { AfterViewInit } from "@angular/core"; -import { FormControl } from "@angular/forms"; -import { ArrayProperty, FormProperty, ObjectProperty } from "./model"; +import { AfterViewInit } from '@angular/core'; +import { FormControl } from '@angular/forms'; +import { ArrayProperty, FormProperty, ObjectProperty } from './model'; export abstract class Widget { formProperty: T; control: FormControl; - id: string = ""; - name: string = ""; + id: string = ''; + name: string = ''; schema: any = {}; } diff --git a/src/schema-form/widgetchooser.component.spec.ts b/src/schema-form/widgetchooser.component.spec.ts index 4888a3e1..f54e2252 100644 --- a/src/schema-form/widgetchooser.component.spec.ts +++ b/src/schema-form/widgetchooser.component.spec.ts @@ -1,12 +1,12 @@ -import { ChangeDetectorRef } from "@angular/core"; -import { TestBed } from "@angular/core/testing"; +import { ChangeDetectorRef } from '@angular/core'; +import { TestBed } from '@angular/core/testing'; -import { WidgetFactory } from "./widgetfactory"; -import { WidgetRegistry } from "./widgetregistry"; +import { WidgetFactory } from './widgetfactory'; +import { WidgetRegistry } from './widgetregistry'; -import { WidgetChooserComponent } from "./widgetchooser.component"; +import { WidgetChooserComponent } from './widgetchooser.component'; -describe("WidgetChooserComponent", () => { +describe('WidgetChooserComponent', () => { beforeEach(() => { TestBed.configureTestingModule({ @@ -19,13 +19,13 @@ describe("WidgetChooserComponent", () => { }); }); - it("should create a widget which contain an instance", () => { + it('should create a widget which contain an instance', () => { let fixture = TestBed.createComponent(WidgetChooserComponent); let widgetChooserComponent = fixture.debugElement.componentInstance; expect(widgetChooserComponent).toBeDefined(); }); - xit("should put the widget returned by the factory in the DOM", () => { + xit('should put the widget returned by the factory in the DOM', () => { }); diff --git a/src/schema-form/widgetchooser.component.ts b/src/schema-form/widgetchooser.component.ts index 44c86906..1937b078 100644 --- a/src/schema-form/widgetchooser.component.ts +++ b/src/schema-form/widgetchooser.component.ts @@ -2,19 +2,18 @@ import { Component, ChangeDetectorRef, EventEmitter, - Inject, Input, OnInit, Output, ViewChild, ViewContainerRef, -} from "@angular/core"; +} from '@angular/core'; -import { WidgetFactory } from "./widgetfactory"; +import { WidgetFactory } from './widgetfactory'; @Component({ - selector: "ng2sf-widget-chooser", - template: "
", + selector: 'sf-widget-chooser', + template: `
`, }) export class WidgetChooserComponent implements OnInit { @@ -22,7 +21,7 @@ export class WidgetChooserComponent implements OnInit { @Output() widgetInstanciated = new EventEmitter(); - @ViewChild("target", {read: ViewContainerRef}) private container: ViewContainerRef; + @ViewChild('target', {read: ViewContainerRef}) private container: ViewContainerRef; private widgetInstance: any; diff --git a/src/schema-form/widgetfactory.ts b/src/schema-form/widgetfactory.ts index 05f125b9..64a1a7e4 100644 --- a/src/schema-form/widgetfactory.ts +++ b/src/schema-form/widgetfactory.ts @@ -2,11 +2,10 @@ import { ViewContainerRef, ComponentRef, ComponentFactoryResolver, - ReflectiveInjector, Injectable -} from "@angular/core"; +} from '@angular/core'; -import { WidgetRegistry } from "./widgetregistry"; +import { WidgetRegistry } from './widgetregistry'; @Injectable() export class WidgetFactory { diff --git a/tsconfig.json b/tsconfig.json index 89f36495..bcaf0178 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -1,33 +1,38 @@ { - "compilerOptions": { - "emitDecoratorMetadata": true, - "experimentalDecorators": true, - "target": "es5", - "module": "commonjs", - "removeComments": true, - "sourceMap": true, - "outDir":"dist/", - "declaration": true, - "noEmitHelpers": false, - "strictNullChecks": false - }, - "awesomeTypescriptLoaderOptions": { - "useWebpackText": true, - "forkChecker": true - }, - "include": [ - "src/**/*", - "demo/**/*" - ], - "exclude": [ - "node_modules", - "dist" - ], - "typeRoots": [ - "../../node_modules/@types", - "../../node_modules" - ], - "compileOnSave": false, - "buildOnSave": false, - "atom": { "rewriteTsconfig": false } + "compilerOptions": { + "target": "es5", + "module": "commonjs", + "declaration": true, + "noEmitHelpers": false, + "emitDecoratorMetadata": true, + "experimentalDecorators": true, + "sourceMap": true, + "pretty": true, + "allowUnreachableCode": true, + "allowUnusedLabels": true, + "noImplicitAny": false, + "noImplicitReturns": false, + "noImplicitUseStrict": false, + "noFallthroughCasesInSwitch": false, + "allowSyntheticDefaultImports": true, + "suppressExcessPropertyErrors": true, + "suppressImplicitAnyIndexErrors": true, + "outDir": "dist", + "declarationDir": "dist" + }, + "files": [ + "src/index.ts" + ], + "exclude": [ + "node_modules" + ], + "compileOnSave": false, + "buildOnSave": false, + "awesomeTypescriptLoaderOptions": { + "forkChecker": false + }, + "angularCompilerOptions": { + "genDir": "dist/", + "skipMetadataEmit": false + } } diff --git a/tslint.json b/tslint.json index 29f24ee2..ed9fd53b 100644 --- a/tslint.json +++ b/tslint.json @@ -93,8 +93,8 @@ "check-type" ], - "directive-selector-prefix": [true, "app"], - "component-selector-prefix": [true, "app"], + "directive-selector-prefix": [true, "sf"], + "component-selector-prefix": [true, "sf"], "directive-selector-name": [true, "camelCase"], "component-selector-name": [true, "kebab-case"], "directive-selector-type": [true, "attribute"], @@ -106,7 +106,10 @@ "no-output-rename": true, "use-life-cycle-interface": true, "use-pipe-transform-interface": true, - "component-class-suffix": true, - "directive-class-suffix": true + // We disable component suffix for widgets + "component-class-suffix": false, + "directive-class-suffix": true, + "templates-use-public": true, + "invoke-injectable": true } } diff --git a/webpack.config.js b/webpack.config.js index 3bf8a41e..f0c5e8f4 100644 --- a/webpack.config.js +++ b/webpack.config.js @@ -1,7 +1,14 @@ -var NODE_ENV = process.env.NODE_ENV; -if(NODE_ENV==="development"){ - module.exports = require("./config/webpack.dev.js"); -} -else if(NODE_ENV==="production"){ - module.exports = require("./config/webpack.prod.js"); +switch (process.env.NODE_ENV) { + case 'prod': + case 'production': + module.exports = require('./config/webpack.prod')({env: 'production'}); + break; + case 'test': + case 'testing': + module.exports = require('./config/webpack.test')({env: 'test'}); + break; + case 'dev': + case 'development': + default: + module.exports = require('./config/webpack.dev')({env: 'development'}); }