diff --git a/Rakefile b/Rakefile index 1ca59cf145ef..a61c99eafbd2 100644 --- a/Rakefile +++ b/Rakefile @@ -2,7 +2,7 @@ require 'yaml' include FileUtils content = File.open('angularFiles.js', 'r') {|f| f.read } -files = eval(content.gsub(/\};(\s|\S)*/, '}').gsub(/angularFiles = /, '').gsub(/:/, '=>')); +files = eval(content.gsub(/\};(\s|\S)*/, '}').gsub(/angularFiles = /, '').gsub(/:/, '=>').gsub(/\/\//, '#')); BUILD_DIR = 'build' @@ -34,38 +34,24 @@ end desc 'Compile Scenario' task :compile_scenario => :init do - - deps = [ + + concatFile('angular-scenario.js', [ 'lib/jquery/jquery.js', 'src/ngScenario/angular.prefix', files['angularSrc'], files['angularScenario'], 'src/ngScenario/angular.suffix', - ] - - concat = 'cat ' + deps.flatten.join(' ') - - File.open(path_to('angular-scenario.js'), 'w') do |f| - f.write(%x{#{concat}}.gsub('"NG_VERSION_FULL"', NG_VERSION.full)) - f.write(gen_css('css/angular.css') + "\n") - f.write(gen_css('css/angular-scenario.css')) - end + ], gen_css('css/angular.css') + "\n" + gen_css('css/angular-scenario.css')) end desc 'Compile JSTD Scenario Adapter' task :compile_jstd_scenario_adapter => :init do - deps = [ + concatFile('jstd-scenario-adapter.js', [ 'src/ngScenario/jstd-scenario-adapter/angular.prefix', 'src/ngScenario/jstd-scenario-adapter/Adapter.js', 'src/ngScenario/jstd-scenario-adapter/angular.suffix', - ] - - concat = 'cat ' + deps.flatten.join(' ') - - File.open(path_to('jstd-scenario-adapter.js'), 'w') do |f| - f.write(%x{#{concat}}.gsub('"NG_VERSION_FULL"', NG_VERSION.full)) - end + ]) # TODO(vojta) use jstd configuration when implemented # (instead of including jstd-adapter-config.js) @@ -80,55 +66,24 @@ end desc 'Compile JavaScript' task :compile => [:init, :compile_scenario, :compile_jstd_scenario_adapter] do - deps = [ - 'src/angular.prefix', - files['angularSrc'], - 'src/angular.suffix', - ] - - File.open(path_to('angular.js'), 'w') do |f| - concat = 'cat ' + deps.flatten.join(' ') - - content = %x{#{concat}}. - gsub('"NG_VERSION_FULL"', NG_VERSION.full). - gsub('"NG_VERSION_MAJOR"', NG_VERSION.major). - gsub('"NG_VERSION_MINOR"', NG_VERSION.minor). - gsub('"NG_VERSION_DOT"', NG_VERSION.dot). - gsub('"NG_VERSION_CODENAME"', NG_VERSION.codename). - gsub(/^\s*['"]use strict['"];?\s*$/, ''). # remove all file-specific strict mode flags - gsub(/'USE STRICT'/, "'use strict'") # rename the placeholder in angular.prefix - - f.write(content) - f.write(gen_css('css/angular.css', true)) - end - - %x(java -jar lib/closure-compiler/compiler.jar \ - --compilation_level SIMPLE_OPTIMIZATIONS \ - --language_in ECMASCRIPT5_STRICT \ - --js #{path_to('angular.js')} \ - --js_output_file #{path_to('angular.min.js')}) + concatFile('angular.js', [ + 'src/angular.prefix', + files['angularSrc'], + 'src/angular.suffix', + ], gen_css('css/angular.css', true)) FileUtils.cp_r 'src/ngLocale', path_to('i18n') - File.open(path_to('angular-loader.js'), 'w') do |f| - concat = 'cat ' + [ + concatFile('angular-loader.js', [ 'src/loader.prefix', 'src/loader.js', - 'src/loader.suffix'].flatten.join(' ') - - content = %x{#{concat}}. - gsub('"NG_VERSION_FULL"', NG_VERSION.full). - gsub(/^\s*['"]use strict['"];?\s*$/, '') # remove all file-specific strict mode flags - - f.write(content) - end - - %x(java -jar lib/closure-compiler/compiler.jar \ - --compilation_level SIMPLE_OPTIMIZATIONS \ - --language_in ECMASCRIPT5_STRICT \ - --js #{path_to('angular-loader.js')} \ - --js_output_file #{path_to('angular-loader.min.js')}) + 'src/loader.suffix']) + + FileUtils.cp 'src/ngMock/angular-mocks.js', path_to('angular-mocks.js') + + closureCompile('angular.js') + closureCompile('angular-loader.js') end @@ -153,11 +108,11 @@ task :package => [:clean, :compile, :docs] do FileUtils.rm_r(path_to('pkg'), :force => true) FileUtils.mkdir_p(pkg_dir) - ['src/ngMock/angular-mocks.js', - path_to('angular.js'), - path_to('angular-loader.js'), + [ path_to('angular.js'), path_to('angular.min.js'), + path_to('angular-loader.js'), path_to('angular-loader.min.js'), + path_to('angular-mocks.js'), path_to('angular-scenario.js'), path_to('jstd-scenario-adapter.js'), path_to('jstd-scenario-adapter-config.js'), @@ -336,3 +291,32 @@ end def path_to(filename) return File.join(BUILD_DIR, *filename) end + +def closureCompile(filename) + puts "Compiling #{filename} ..." + %x(java -jar lib/closure-compiler/compiler.jar \ + --compilation_level SIMPLE_OPTIMIZATIONS \ + --language_in ECMASCRIPT5_STRICT \ + --js #{path_to(filename)} \ + --js_output_file #{path_to(filename.gsub(/\.js$/, '.min.js'))}) +end + +def concatFile(filename, deps, footer='') + puts "Building #{filename} ..." + File.open(path_to(filename), 'w') do |f| + concat = 'cat ' + deps.flatten.join(' ') + + content = %x{#{concat}}. + gsub('"NG_VERSION_FULL"', NG_VERSION.full). + gsub('"NG_VERSION_MAJOR"', NG_VERSION.major). + gsub('"NG_VERSION_MINOR"', NG_VERSION.minor). + gsub('"NG_VERSION_DOT"', NG_VERSION.dot). + gsub('"NG_VERSION_CODENAME"', NG_VERSION.codename). + gsub(/^\s*['"]use strict['"];?\s*$/, ''). # remove all file-specific strict mode flags + gsub(/'USE STRICT'/, "'use strict'") # rename the placeholder in angular.prefix + + f.write(content) + f.write(footer) + end +end + diff --git a/angularFiles.js b/angularFiles.js index 17162296e4b3..cb243e8e87f7 100644 --- a/angularFiles.js +++ b/angularFiles.js @@ -66,6 +66,10 @@ angularFiles = { 'src/ng/directive/style.js' ], + 'angularSrcModules': [ + 'src/ngMock/angular-mocks.js' + ], + 'angularScenario': [ 'src/ngScenario/Scenario.js', 'src/ngScenario/Application.js', @@ -83,20 +87,9 @@ angularFiles = { 'src/ngScenario/output/Object.js' ], - 'jstd': [ - 'lib/jasmine/jasmine.js', - 'lib/jasmine-jstd-adapter/JasmineAdapter.js', - 'lib/jquery/jquery.js', - 'test/jquery_remove.js', - '@angularSrc', - 'example/personalLog/*.js', + 'angularTest': [ 'test/testabilityPatch.js', 'test/matchers.js', - 'src/ngScenario/Scenario.js', - 'src/ngScenario/output/*.js', - 'src/ngScenario/jstd-scenario-adapter/*.js', - 'src/ngScenario/*.js', - 'src/ngMock/angular-mocks.js', 'test/ngScenario/*.js', 'test/ngScenario/output/*.js', 'test/ngScenario/jstd-scenario-adapter/*.js', @@ -105,7 +98,21 @@ angularFiles = { 'test/ng/*.js', 'test/ng/directive/*.js', 'test/ng/filter/*.js', - 'test/ngMock/*.js', + 'test/ngMock/*.js' + ], + + 'jstd': [ + 'lib/jasmine/jasmine.js', + 'lib/jasmine-jstd-adapter/JasmineAdapter.js', + 'lib/jquery/jquery.js', + 'test/jquery_remove.js', + '@angularSrc', + 'src/publishExternalApis.js', + '@angularSrcModules', + '@angularScenario', + 'src/ngScenario/jstd-scenario-adapter/Adapter.js', + '@angularTest', + 'example/personalLog/*.js', 'example/personalLog/test/*.js' ], @@ -122,19 +129,20 @@ angularFiles = { 'build/docs/docs-scenario.js' ], - 'jstdMocks': [ + "jstdModules": [ 'lib/jasmine/jasmine.js', 'lib/jasmine-jstd-adapter/JasmineAdapter.js', 'build/angular.js', 'src/ngMock/angular-mocks.js', 'test/matchers.js', - 'test/ngMock/angular-mocksSpec.js' + 'test/ngMock/*.js', ], 'jstdPerf': [ 'lib/jasmine/jasmine.js', 'lib/jasmine-jstd-adapter/JasmineAdapter.js', - 'angularSrc', + '@angularSrc', + '@angularSrcModules', 'src/ngMock/angular-mocks.js', 'perf/data/*.js', 'perf/testUtils.js', @@ -152,23 +160,12 @@ angularFiles = { 'lib/jquery/jquery.js', 'test/jquery_alias.js', '@angularSrc', + 'src/publishExternalApis.js', + '@angularSrcModules', + '@angularScenario', + 'src/ngScenario/jstd-scenario-adapter/Adapter.js', + '@angularTest', 'example/personalLog/*.js', - 'test/testabilityPatch.js', - 'test/matchers.js', - 'src/ngScenario/Scenario.js', - 'src/ngScenario/output/*.js', - 'src/ngScenario/jstd-scenario-adapter/*.js', - 'src/ngScenario/*.js', - 'src/ngMock/angular-mocks.js', - 'test/ngScenario/*.js', - 'test/ngScenario/output/*.js', - 'test/ngScenario/jstd-scenario-adapter/*.js', - 'test/*.js', - 'test/auto/*.js', - 'test/ng/*.js', - 'test/ng/directive/*.js', - 'test/ng/filter/*.js', - 'test/ngMock/*.js', 'example/personalLog/test/*.js' ], @@ -181,15 +178,30 @@ angularFiles = { // Execute only in slim-jim if (typeof JASMINE_ADAPTER !== 'undefined') { - // SlimJim config + // Testacular config + var mergedFiles = []; + angularFiles.jstd.forEach(function(file) { + // replace @ref + var match = file.match(/^\@(.*)/); + if (match) { + var deps = angularFiles[match[1]]; + if (!deps) { + console.log('No dependency:' + file) + } + mergedFiles = mergedFiles.concat(deps); + } else { + mergedFiles.push(file); + } + }); + files = [JASMINE, JASMINE_ADAPTER]; - angularFiles.jstd.forEach(function(pattern) { - // replace angular source - if (pattern === '@angularSrc') files = files.concat(angularFiles.angularSrc); - // ignore jstd and jasmine files - else if (!/jstd|jasmine/.test(pattern)) files.push(pattern); + + mergedFiles.forEach(function(file){ + if (/jstd|jasmine/.test(file)) return; + files.push(file); }); + exclude = angularFiles.jstdExclude; autoWatch = true; diff --git a/gen_jstd_configs.js b/gen_jstd_configs.js index 7165d2024f56..842cfe2100d6 100755 --- a/gen_jstd_configs.js +++ b/gen_jstd_configs.js @@ -16,7 +16,7 @@ fs.readFile('angularFiles.js', function(err, data) { fs.writeFile('./jsTestDriver.conf', prefix + combine(angularFiles.jstd, angularFiles.jstdExclude)); - fs.writeFile('./jsTestDriver-mocks.conf', prefix + combine(angularFiles.jstdMocks)); + fs.writeFile('./jsTestDriver-modules.conf', prefix + combine(angularFiles.jstdModules)); fs.writeFile('./jsTestDriver-scenario.conf', prefixScenario + combine(angularFiles.jstdScenario) + @@ -40,6 +40,8 @@ function combine(load, exclude) { if (exclude) fileList += ('\n\nexclude:\n- ' + exclude.join('\n- ')); //Replace placeholders for src list before returning - return fileList.replace(/@angularSrc/g, angularSrc); + return fileList.replace(/@(.*)/g, function(all, alias) { + return angularFiles[alias].join('\n- '); + }); } diff --git a/src/AngularPublic.js b/src/AngularPublic.js index 9a0e19771cfa..ec307962cec9 100644 --- a/src/AngularPublic.js +++ b/src/AngularPublic.js @@ -122,7 +122,6 @@ function publishExternalAPI(angular){ $location: $LocationProvider, $log: $LogProvider, $parse: $ParseProvider, - $resource: $ResourceProvider, $route: $RouteProvider, $routeParams: $RouteParamsProvider, $rootScope: $RootScopeProvider, diff --git a/src/ng/http.js b/src/ng/http.js index c2cbd16174a3..e67dd496eeff 100644 --- a/src/ng/http.js +++ b/src/ng/http.js @@ -152,7 +152,7 @@ function $HttpProvider() { * For unit testing applications that use `$http` service, see * {@link angular.module.ngMock.$httpBackend $httpBackend mock}. * - * For a higher level of abstraction, please check out the {@link angular.module.ng.$resource + * For a higher level of abstraction, please check out the {@link angular.module.ngResource.$resource * $resource} service. * * The $http API is based on the {@link angular.module.ng.$q deferred/promise APIs} exposed by diff --git a/src/ng/httpBackend.js b/src/ng/httpBackend.js index 201d1a87a188..abe1d8f594fb 100644 --- a/src/ng/httpBackend.js +++ b/src/ng/httpBackend.js @@ -18,7 +18,7 @@ var XHR = window.XMLHttpRequest || function() { * XMLHttpRequest object or JSONP and deals with browser incompatibilities. * * You should never need to use this service directly, instead use the higher-level abstractions: - * {@link angular.module.ng.$http $http} or {@link angular.module.ng.$resource $resource}. + * {@link angular.module.ng.$http $http} or {@link angular.module.ngResource.$resource $resource}. * * During testing this implementation is swapped with {@link angular.module.ngMock.$httpBackend mock * $httpBackend} which can be trained with responses. diff --git a/src/ng/resource.js b/src/ngResource/resource.js similarity index 86% rename from src/ng/resource.js rename to src/ngResource/resource.js index 3aa48e743702..fe111b470d6a 100644 --- a/src/ng/resource.js +++ b/src/ngResource/resource.js @@ -1,8 +1,14 @@ 'use strict'; /** + * @ngdoc overview + * @name angular.module.ngResource + * @description + */ + + /** * @ngdoc object - * @name angular.module.ng.$resource + * @name angular.module.ngResource.$resource * @requires $http * * @description @@ -200,8 +206,8 @@ */ -function $ResourceProvider() { - this.$get = ['$http', function($http) { +angular.module('ngResource', ['ng']). + factory('$resource', ['$http', '$parse', function($http, $parse) { var DEFAULT_ACTIONS = { 'get': {method:'GET'}, 'save': {method:'POST'}, @@ -209,9 +215,54 @@ function $ResourceProvider() { 'remove': {method:'DELETE'}, 'delete': {method:'DELETE'} }; + var forEach = angular.forEach, + extend = angular.extend, + copy = angular.copy, + isFunction = angular.isFunction, + getter = function(obj, path) { + return $parse(path)(obj); + }; + + /** + * We need our custom mehtod because encodeURIComponent is too agressive and doesn't follow + * http://www.ietf.org/rfc/rfc3986.txt with regards to the character set (pchar) allowed in path + * segments: + * segment = *pchar + * pchar = unreserved / pct-encoded / sub-delims / ":" / "@" + * pct-encoded = "%" HEXDIG HEXDIG + * unreserved = ALPHA / DIGIT / "-" / "." / "_" / "~" + * sub-delims = "!" / "$" / "&" / "'" / "(" / ")" + * / "*" / "+" / "," / ";" / "=" + */ + function encodeUriSegment(val) { + return encodeUriQuery(val, true). + replace(/%26/gi, '&'). + replace(/%3D/gi, '='). + replace(/%2B/gi, '+'); + } + + /** + * This method is intended for encoding *key* or *value* parts of query component. We need a custom + * method becuase encodeURIComponent is too agressive and encodes stuff that doesn't have to be + * encoded per http://tools.ietf.org/html/rfc3986: + * query = *( pchar / "/" / "?" ) + * pchar = unreserved / pct-encoded / sub-delims / ":" / "@" + * unreserved = ALPHA / DIGIT / "-" / "." / "_" / "~" + * pct-encoded = "%" HEXDIG HEXDIG + * sub-delims = "!" / "$" / "&" / "'" / "(" / ")" + * / "*" / "+" / "," / ";" / "=" + */ + function encodeUriQuery(val, pctEncodeSpaces) { + return encodeURIComponent(val). + replace(/%40/gi, '@'). + replace(/%3A/gi, ':'). + replace(/%24/g, '$'). + replace(/%2C/gi, ','). + replace((pctEncodeSpaces ? null : /%20/g), '+'); + } - function Route(template, defaults) { + function Route(template, defaults) { this.template = template = template + '#'; this.defaults = defaults || {}; var urlParams = this.urlParams = {}; @@ -236,11 +287,12 @@ function $ResourceProvider() { }); url = url.replace(/\/?#$/, ''); var query = []; - forEachSorted(params, function(value, key){ + forEach(params, function(value, key){ if (!self.urlParams[key]) { query.push(encodeUriQuery(key) + '=' + encodeUriQuery(value)); } }); + query.sort(); url = url.replace(/\/*$/, ''); return url + (query.length ? '?' + query.join('&') : ''); } @@ -364,5 +416,4 @@ function $ResourceProvider() { } return ResourceFactory; - }]; -} + }]); diff --git a/src/publishExternalApis.js b/src/publishExternalApis.js new file mode 100644 index 000000000000..6a6acd13e6d0 --- /dev/null +++ b/src/publishExternalApis.js @@ -0,0 +1,3 @@ +'use strict'; + +publishExternalAPI(angular); diff --git a/test-mocks.sh b/test-modules.sh similarity index 77% rename from test-mocks.sh rename to test-modules.sh index b91fc901f722..586933365681 100755 --- a/test-mocks.sh +++ b/test-modules.sh @@ -1,4 +1,4 @@ #!/bin/bash if [ ! -e test.dissable ]; then - java -jar lib/jstestdriver/JsTestDriver.jar --tests all --config jsTestDriver-mocks.conf $@ + java -jar lib/jstestdriver/JsTestDriver.jar --tests all --config jsTestDriver-modules.conf $@ fi diff --git a/test/ngMock/angular-mocksSpec.js b/test/ngMock/angular-mocksSpec.js index 2527ca4885b8..d80b1976ee9b 100644 --- a/test/ngMock/angular-mocksSpec.js +++ b/test/ngMock/angular-mocksSpec.js @@ -1,6 +1,7 @@ 'use strict'; describe('ngMock', function() { + var noop = angular.noop; describe('$browser', function() { @@ -8,7 +9,7 @@ describe('ngMock', function() { it('should store url, done', inject(function($browser) { var url = 'some.js', - done = noop; + done = angular.noop; $browser.addJs(url, done); diff --git a/test/ng/resourceSpec.js b/test/ngResource/resourceSpec.js similarity index 98% rename from test/ng/resourceSpec.js rename to test/ngResource/resourceSpec.js index e00497618b86..3235a6d02486 100644 --- a/test/ng/resourceSpec.js +++ b/test/ngResource/resourceSpec.js @@ -3,6 +3,7 @@ describe("resource", function() { var $resource, CreditCard, callback, $httpBackend; + beforeEach(module('ngResource')); beforeEach(inject(function($injector) { $httpBackend = $injector.get('$httpBackend'); $resource = $injector.get('$resource'); @@ -262,7 +263,7 @@ describe("resource", function() { $httpBackend.flush(); expect(cc instanceof CreditCard).toBe(true); - $httpBackend.expect('POST', '/CreditCard/123', toJson(data)).respond(''); + $httpBackend.expect('POST', '/CreditCard/123', angular.toJson(data)).respond(''); var idBefore = cc.id; cc.$save(); diff --git a/test/testabilityPatch.js b/test/testabilityPatch.js index b0618178c4f5..a60bc1df21ac 100644 --- a/test/testabilityPatch.js +++ b/test/testabilityPatch.js @@ -8,8 +8,6 @@ */ _jQuery.event.special.change = undefined; - -publishExternalAPI(angular); bindJQuery(); beforeEach(function() { publishExternalAPI(angular);