├── .editorconfig
├── .eslintrc.json
├── .gitattributes
├── .gitignore
├── .npmrc
├── .travis.yml
├── .verb.md
├── LICENSE
├── README.md
├── examples
├── geojson.js
├── posts.js
├── tags-function.js
└── tags-property.js
├── index.js
├── package.json
└── test
├── expected
├── categories-tags.js
├── deeply-nested.js
├── insanely-nested.js
├── issue-10.js
├── nested.js
└── tags-array.js
├── fixtures
├── categories-tags.js
├── date-function.js
├── deeply-nested.js
├── insanely-nested.js
├── issue-10.js
├── nested.js
└── tags-array.js
└── test.js
/.editorconfig:
--------------------------------------------------------------------------------
1 | root = true
2 |
3 | [*]
4 | indent_style = space
5 | end_of_line = lf
6 | charset = utf-8
7 | indent_size = 2
8 | trim_trailing_whitespace = true
9 | insert_final_newline = true
10 |
11 | [{**/{actual,fixtures,expected,templates}/**,*.md}]
12 | trim_trailing_whitespace = false
13 | insert_final_newline = false
--------------------------------------------------------------------------------
/.eslintrc.json:
--------------------------------------------------------------------------------
1 | {
2 | "env": {
3 | "browser": false,
4 | "es6": true,
5 | "node": true,
6 | "mocha": true
7 | },
8 |
9 | "globals": {
10 | "document": false,
11 | "navigator": false,
12 | "window": false
13 | },
14 |
15 | "rules": {
16 | "accessor-pairs": 2,
17 | "arrow-spacing": [2, { "before": true, "after": true }],
18 | "block-spacing": [2, "always"],
19 | "brace-style": [2, "1tbs", { "allowSingleLine": true }],
20 | "comma-dangle": [2, "never"],
21 | "comma-spacing": [2, { "before": false, "after": true }],
22 | "comma-style": [2, "last"],
23 | "constructor-super": 2,
24 | "curly": [2, "multi-line"],
25 | "dot-location": [2, "property"],
26 | "eol-last": 2,
27 | "eqeqeq": [2, "allow-null"],
28 | "generator-star-spacing": [2, { "before": true, "after": true }],
29 | "handle-callback-err": [2, "^(err|error)$" ],
30 | "indent": [2, 2, { "SwitchCase": 1 }],
31 | "key-spacing": [2, { "beforeColon": false, "afterColon": true }],
32 | "keyword-spacing": [2, { "before": true, "after": true }],
33 | "new-cap": [2, { "newIsCap": true, "capIsNew": false }],
34 | "new-parens": 2,
35 | "no-array-constructor": 2,
36 | "no-caller": 2,
37 | "no-class-assign": 2,
38 | "no-cond-assign": 2,
39 | "no-const-assign": 2,
40 | "no-control-regex": 2,
41 | "no-debugger": 2,
42 | "no-delete-var": 2,
43 | "no-dupe-args": 2,
44 | "no-dupe-class-members": 2,
45 | "no-dupe-keys": 2,
46 | "no-duplicate-case": 2,
47 | "no-empty-character-class": 2,
48 | "no-eval": 2,
49 | "no-ex-assign": 2,
50 | "no-extend-native": 2,
51 | "no-extra-bind": 2,
52 | "no-extra-boolean-cast": 2,
53 | "no-extra-parens": [2, "functions"],
54 | "no-fallthrough": 2,
55 | "no-floating-decimal": 2,
56 | "no-func-assign": 2,
57 | "no-implied-eval": 2,
58 | "no-inner-declarations": [2, "functions"],
59 | "no-invalid-regexp": 2,
60 | "no-irregular-whitespace": 2,
61 | "no-iterator": 2,
62 | "no-label-var": 2,
63 | "no-labels": 2,
64 | "no-lone-blocks": 2,
65 | "no-mixed-spaces-and-tabs": 2,
66 | "no-multi-spaces": 2,
67 | "no-multi-str": 2,
68 | "no-multiple-empty-lines": [2, { "max": 1 }],
69 | "no-native-reassign": 0,
70 | "no-negated-in-lhs": 2,
71 | "no-new": 2,
72 | "no-new-func": 2,
73 | "no-new-object": 2,
74 | "no-new-require": 2,
75 | "no-new-wrappers": 2,
76 | "no-obj-calls": 2,
77 | "no-octal": 2,
78 | "no-octal-escape": 2,
79 | "no-proto": 0,
80 | "no-redeclare": 2,
81 | "no-regex-spaces": 2,
82 | "no-return-assign": 2,
83 | "no-self-compare": 2,
84 | "no-sequences": 2,
85 | "no-shadow-restricted-names": 2,
86 | "no-spaced-func": 2,
87 | "no-sparse-arrays": 2,
88 | "no-this-before-super": 2,
89 | "no-throw-literal": 2,
90 | "no-trailing-spaces": 0,
91 | "no-undef": 2,
92 | "no-undef-init": 2,
93 | "no-unexpected-multiline": 2,
94 | "no-unneeded-ternary": [2, { "defaultAssignment": false }],
95 | "no-unreachable": 2,
96 | "no-unused-vars": [2, { "vars": "all", "args": "none" }],
97 | "no-useless-call": 0,
98 | "no-with": 2,
99 | "one-var": [0, { "initialized": "never" }],
100 | "operator-linebreak": [0, "after", { "overrides": { "?": "before", ":": "before" } }],
101 | "padded-blocks": [0, "never"],
102 | "quotes": [2, "single", "avoid-escape"],
103 | "radix": 2,
104 | "semi": [2, "always"],
105 | "semi-spacing": [2, { "before": false, "after": true }],
106 | "space-before-blocks": [2, "always"],
107 | "space-before-function-paren": [2, "never"],
108 | "space-in-parens": [2, "never"],
109 | "space-infix-ops": 2,
110 | "space-unary-ops": [2, { "words": true, "nonwords": false }],
111 | "spaced-comment": [0, "always", { "markers": ["global", "globals", "eslint", "eslint-disable", "*package", "!", ","] }],
112 | "use-isnan": 2,
113 | "valid-typeof": 2,
114 | "wrap-iife": [2, "any"],
115 | "yoda": [2, "never"]
116 | }
117 | }
118 |
--------------------------------------------------------------------------------
/.gitattributes:
--------------------------------------------------------------------------------
1 | # Enforce Unix newlines
2 | * text eol=lf
3 |
4 | # binaries
5 | *.ai binary
6 | *.psd binary
7 | *.jpg binary
8 | *.gif binary
9 | *.png binary
10 | *.jpeg binary
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # always ignore files
2 | *.DS_Store
3 | *.sublime-*
4 |
5 | # test related, or directories generated by tests
6 | test/actual
7 | actual
8 | coverage
9 | .nyc*
10 |
11 | # npm
12 | node_modules
13 | npm-debug.log
14 |
15 | # yarn
16 | yarn.lock
17 | yarn-error.log
18 |
19 | # misc
20 | _gh_pages
21 | _draft
22 | _drafts
23 | bower_components
24 | vendor
25 | temp
26 | tmp
27 | TODO.md
28 |
29 | examples/*/dist
30 | examples/*/site
31 |
--------------------------------------------------------------------------------
/.npmrc:
--------------------------------------------------------------------------------
1 | package-lock=false
2 |
--------------------------------------------------------------------------------
/.travis.yml:
--------------------------------------------------------------------------------
1 | sudo: false
2 | os:
3 | - linux
4 | - osx
5 | language: node_js
6 | node_js:
7 | - node
8 | - '8'
9 | - '12'
10 | - '10'
11 |
--------------------------------------------------------------------------------
/.verb.md:
--------------------------------------------------------------------------------
1 | ## Usage
2 |
3 | ```js
4 | var groupArray = require('{%= name %}');
5 | ```
6 |
7 | ## Examples
8 |
9 | ```js
10 | var arr = [
11 | {tag: 'one', content: 'A'},
12 | {tag: 'one', content: 'B'},
13 | {tag: 'two', content: 'C'},
14 | {tag: 'two', content: 'D'},
15 | {tag: 'three', content: 'E'},
16 | {tag: 'three', content: 'F'}
17 | ];
18 |
19 | // group by the `tag` property
20 | groupArray(arr, 'tag');
21 | ```
22 |
23 | **results in:**
24 |
25 | ```js
26 | {
27 | one: [
28 | {tag: 'one', content: 'A'},
29 | {tag: 'one', content: 'B'}
30 | ],
31 | two: [
32 | {tag: 'two', content: 'C'},
33 | {tag: 'two', content: 'D'}
34 | ],
35 | three: [
36 | {tag: 'three', content: 'E'},
37 | {tag: 'three', content: 'F'}
38 | ]
39 | }
40 | ```
41 |
42 | **Group by multiple, deeply nested properties**
43 |
44 |
45 | ```js
46 | // given an array of object, like blog posts...
47 | var arr = [
48 | { data: { year: '2016', tag: 'one', month: 'jan', day: '01'}, content: '...'},
49 | { data: { year: '2016', tag: 'one', month: 'jan', day: '01'}, content: '...'},
50 | { data: { year: '2016', tag: 'one', month: 'jan', day: '02'}, content: '...'},
51 | { data: { year: '2016', tag: 'one', month: 'jan', day: '02'}, content: '...'},
52 | { data: { year: '2016', tag: 'one', month: 'feb', day: '10'}, content: '...'},
53 | { data: { year: '2016', tag: 'one', month: 'feb', day: '10'}, content: '...'},
54 | { data: { year: '2016', tag: 'one', month: 'feb', day: '12'}, content: '...'},
55 | { data: { year: '2016', tag: 'one', month: 'feb', day: '12'}, content: '...'},
56 | { data: { year: '2016', tag: 'two', month: 'jan', day: '14'}, content: '...'},
57 | { data: { year: '2016', tag: 'two', month: 'jan', day: '14'}, content: '...'},
58 | { data: { year: '2016', tag: 'two', month: 'jan', day: '16'}, content: '...'},
59 | { data: { year: '2016', tag: 'two', month: 'jan', day: '16'}, content: '...'},
60 | { data: { year: '2016', tag: 'two', month: 'feb', day: '18'}, content: '...'},
61 | { data: { year: '2017', tag: 'two', month: 'feb', day: '18'}, content: '...'},
62 | { data: { year: '2017', tag: 'two', month: 'feb', day: '10'}, content: '...'},
63 | { data: { year: '2017', tag: 'two', month: 'feb', day: '10'}, content: '...'},
64 | { data: { year: '2017', tag: 'three', month: 'jan', day: '01'}, content: '...'},
65 | { data: { year: '2017', tag: 'three', month: 'jan', day: '01'}, content: '...'},
66 | { data: { year: '2017', tag: 'three', month: 'jan', day: '02'}, content: '...'},
67 | { data: { year: '2017', tag: 'three', month: 'jan', day: '02'}, content: '...'},
68 | { data: { year: '2017', tag: 'three', month: 'feb', day: '01'}, content: '...'},
69 | { data: { year: '2017', tag: 'three', month: 'feb', day: '01'}, content: '...'},
70 | { data: { year: '2017', tag: 'three', month: 'feb', day: '02'}, content: '...'},
71 | { data: { year: '2017', tag: 'three', month: 'feb', day: '02'}, content: '...'}
72 | ]
73 | ```
74 |
75 | Pass a list or array of properties:
76 |
77 | ```js
78 | groupArray(arr, 'data.year', 'data.tag', 'data.month', 'data.day');
79 | ```
80 |
81 | **Results in something like this: (abbreviated)**
82 |
83 | ```js
84 | { '2016':
85 | { one:
86 | { jan:
87 | { '01':
88 | [ { data: { year: '2016', tag: 'one', month: 'jan', day: '01' },
89 | content: '...' },
90 | { data: { year: '2016', tag: 'one', month: 'jan', day: '01' },
91 | content: '...' } ],
92 | '02':
93 | [ { data: { year: '2016', tag: 'one', month: 'jan', day: '02' },
94 | content: '...' },
95 | { data: { year: '2016', tag: 'one', month: 'jan', day: '02' },
96 | content: '...' } ] },
97 | feb:
98 | { '10':
99 | [ { data: { year: '2016', tag: 'one', month: 'feb', day: '10' },
100 | content: '...' },
101 | { data: { year: '2016', tag: 'one', month: 'feb', day: '10' },
102 | content: '...' } ],
103 | '12':
104 | [ { data: { year: '2016', tag: 'one', month: 'feb', day: '12' },
105 | content: '...' },
106 | { data: { year: '2016', tag: 'one', month: 'feb', day: '12' },
107 | content: '...' } ] } },
108 | two:
109 | { jan:
110 | { '14':
111 | [ { data: { year: '2016', tag: 'two', month: 'jan', day: '14' },
112 | content: '...' },
113 | { data: { year: '2016', tag: 'two', month: 'jan', day: '14' },
114 | content: '...' } ],
115 | '16':
116 | [ { data: { year: '2016', tag: 'two', month: 'jan', day: '16' },
117 | content: '...' },
118 | { data: { year: '2016', tag: 'two', month: 'jan', day: '16' },
119 | content: '...' } ] },
120 | feb:
121 | { '18':
122 | [ { data: { year: '2016', tag: 'two', month: 'feb', day: '18' },
123 | content: '...' } ] } } },
124 | '2017':
125 | { two:
126 | { feb:
127 | { '10':
128 | [ { data: { year: '2017', tag: 'two', month: 'feb', day: '10' },
129 | content: '...' },
130 | { data: { year: '2017', tag: 'two', month: 'feb', day: '10' },
131 | content: '...' } ],
132 | '18':
133 | [ { data: { year: '2017', tag: 'two', month: 'feb', day: '18' },
134 | content: '...' } ] } },
135 | three:
136 | { jan:
137 | { '01':
138 | [ { data: { year: '2017', tag: 'three', month: 'jan', day: '01' },
139 | content: '...' },
140 | { data: { year: '2017', tag: 'three', month: 'jan', day: '01' },
141 | content: '...' } ],
142 | '02':
143 | [ { data: { year: '2017', tag: 'three', month: 'jan', day: '02' },
144 | content: '...' },
145 | { data: { year: '2017', tag: 'three', month: 'jan', day: '02' },
146 | content: '...' } ] },
147 | feb:
148 | { '01':
149 | [ { data: { year: '2017', tag: 'three', month: 'feb', day: '01' },
150 | content: '...' },
151 | { data: { year: '2017', tag: 'three', month: 'feb', day: '01' },
152 | content: '...' } ],
153 | '02':
154 | [ { data: { year: '2017', tag: 'three', month: 'feb', day: '02' },
155 | content: '...' },
156 | { data: { year: '2017', tag: 'three', month: 'feb', day: '02' },
157 | content: '...' } ] } } } }
158 | ```
159 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) 2015 - present, Brian Woodward.
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in
13 | all copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21 | THE SOFTWARE.
22 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # group-array [](https://www.npmjs.com/package/group-array) [](https://npmjs.org/package/group-array) [](https://npmjs.org/package/group-array) [](https://travis-ci.org/doowb/group-array)
2 |
3 | > Group array of objects into lists.
4 |
5 | Please consider following this project's author, [Brian Woodward](https://github.com/doowb), and consider starring the project to show your :heart: and support.
6 |
7 | - [Install](#install)
8 | - [Usage](#usage)
9 | - [Examples](#examples)
10 | - [About](#about)
11 |
12 | _(TOC generated by [verb](https://github.com/verbose/verb) using [markdown-toc](https://github.com/jonschlinkert/markdown-toc))_
13 |
14 | ## Install
15 |
16 | Install with [npm](https://www.npmjs.com/):
17 |
18 | ```sh
19 | $ npm install --save group-array
20 | ```
21 |
22 | ## Usage
23 |
24 | ```js
25 | var groupArray = require('group-array');
26 | ```
27 |
28 | ## Examples
29 |
30 | ```js
31 | var arr = [
32 | {tag: 'one', content: 'A'},
33 | {tag: 'one', content: 'B'},
34 | {tag: 'two', content: 'C'},
35 | {tag: 'two', content: 'D'},
36 | {tag: 'three', content: 'E'},
37 | {tag: 'three', content: 'F'}
38 | ];
39 |
40 | // group by the `tag` property
41 | groupArray(arr, 'tag');
42 | ```
43 |
44 | **results in:**
45 |
46 | ```js
47 | {
48 | one: [
49 | {tag: 'one', content: 'A'},
50 | {tag: 'one', content: 'B'}
51 | ],
52 | two: [
53 | {tag: 'two', content: 'C'},
54 | {tag: 'two', content: 'D'}
55 | ],
56 | three: [
57 | {tag: 'three', content: 'E'},
58 | {tag: 'three', content: 'F'}
59 | ]
60 | }
61 | ```
62 |
63 | **Group by multiple, deeply nested properties**
64 |
65 | ```js
66 | // given an array of object, like blog posts...
67 | var arr = [
68 | { data: { year: '2016', tag: 'one', month: 'jan', day: '01'}, content: '...'},
69 | { data: { year: '2016', tag: 'one', month: 'jan', day: '01'}, content: '...'},
70 | { data: { year: '2016', tag: 'one', month: 'jan', day: '02'}, content: '...'},
71 | { data: { year: '2016', tag: 'one', month: 'jan', day: '02'}, content: '...'},
72 | { data: { year: '2016', tag: 'one', month: 'feb', day: '10'}, content: '...'},
73 | { data: { year: '2016', tag: 'one', month: 'feb', day: '10'}, content: '...'},
74 | { data: { year: '2016', tag: 'one', month: 'feb', day: '12'}, content: '...'},
75 | { data: { year: '2016', tag: 'one', month: 'feb', day: '12'}, content: '...'},
76 | { data: { year: '2016', tag: 'two', month: 'jan', day: '14'}, content: '...'},
77 | { data: { year: '2016', tag: 'two', month: 'jan', day: '14'}, content: '...'},
78 | { data: { year: '2016', tag: 'two', month: 'jan', day: '16'}, content: '...'},
79 | { data: { year: '2016', tag: 'two', month: 'jan', day: '16'}, content: '...'},
80 | { data: { year: '2016', tag: 'two', month: 'feb', day: '18'}, content: '...'},
81 | { data: { year: '2017', tag: 'two', month: 'feb', day: '18'}, content: '...'},
82 | { data: { year: '2017', tag: 'two', month: 'feb', day: '10'}, content: '...'},
83 | { data: { year: '2017', tag: 'two', month: 'feb', day: '10'}, content: '...'},
84 | { data: { year: '2017', tag: 'three', month: 'jan', day: '01'}, content: '...'},
85 | { data: { year: '2017', tag: 'three', month: 'jan', day: '01'}, content: '...'},
86 | { data: { year: '2017', tag: 'three', month: 'jan', day: '02'}, content: '...'},
87 | { data: { year: '2017', tag: 'three', month: 'jan', day: '02'}, content: '...'},
88 | { data: { year: '2017', tag: 'three', month: 'feb', day: '01'}, content: '...'},
89 | { data: { year: '2017', tag: 'three', month: 'feb', day: '01'}, content: '...'},
90 | { data: { year: '2017', tag: 'three', month: 'feb', day: '02'}, content: '...'},
91 | { data: { year: '2017', tag: 'three', month: 'feb', day: '02'}, content: '...'}
92 | ]
93 | ```
94 |
95 | Pass a list or array of properties:
96 |
97 | ```js
98 | groupArray(arr, 'data.year', 'data.tag', 'data.month', 'data.day');
99 | ```
100 |
101 | **Results in something like this: (abbreviated)**
102 |
103 | ```js
104 | { '2016':
105 | { one:
106 | { jan:
107 | { '01':
108 | [ { data: { year: '2016', tag: 'one', month: 'jan', day: '01' },
109 | content: '...' },
110 | { data: { year: '2016', tag: 'one', month: 'jan', day: '01' },
111 | content: '...' } ],
112 | '02':
113 | [ { data: { year: '2016', tag: 'one', month: 'jan', day: '02' },
114 | content: '...' },
115 | { data: { year: '2016', tag: 'one', month: 'jan', day: '02' },
116 | content: '...' } ] },
117 | feb:
118 | { '10':
119 | [ { data: { year: '2016', tag: 'one', month: 'feb', day: '10' },
120 | content: '...' },
121 | { data: { year: '2016', tag: 'one', month: 'feb', day: '10' },
122 | content: '...' } ],
123 | '12':
124 | [ { data: { year: '2016', tag: 'one', month: 'feb', day: '12' },
125 | content: '...' },
126 | { data: { year: '2016', tag: 'one', month: 'feb', day: '12' },
127 | content: '...' } ] } },
128 | two:
129 | { jan:
130 | { '14':
131 | [ { data: { year: '2016', tag: 'two', month: 'jan', day: '14' },
132 | content: '...' },
133 | { data: { year: '2016', tag: 'two', month: 'jan', day: '14' },
134 | content: '...' } ],
135 | '16':
136 | [ { data: { year: '2016', tag: 'two', month: 'jan', day: '16' },
137 | content: '...' },
138 | { data: { year: '2016', tag: 'two', month: 'jan', day: '16' },
139 | content: '...' } ] },
140 | feb:
141 | { '18':
142 | [ { data: { year: '2016', tag: 'two', month: 'feb', day: '18' },
143 | content: '...' } ] } } },
144 | '2017':
145 | { two:
146 | { feb:
147 | { '10':
148 | [ { data: { year: '2017', tag: 'two', month: 'feb', day: '10' },
149 | content: '...' },
150 | { data: { year: '2017', tag: 'two', month: 'feb', day: '10' },
151 | content: '...' } ],
152 | '18':
153 | [ { data: { year: '2017', tag: 'two', month: 'feb', day: '18' },
154 | content: '...' } ] } },
155 | three:
156 | { jan:
157 | { '01':
158 | [ { data: { year: '2017', tag: 'three', month: 'jan', day: '01' },
159 | content: '...' },
160 | { data: { year: '2017', tag: 'three', month: 'jan', day: '01' },
161 | content: '...' } ],
162 | '02':
163 | [ { data: { year: '2017', tag: 'three', month: 'jan', day: '02' },
164 | content: '...' },
165 | { data: { year: '2017', tag: 'three', month: 'jan', day: '02' },
166 | content: '...' } ] },
167 | feb:
168 | { '01':
169 | [ { data: { year: '2017', tag: 'three', month: 'feb', day: '01' },
170 | content: '...' },
171 | { data: { year: '2017', tag: 'three', month: 'feb', day: '01' },
172 | content: '...' } ],
173 | '02':
174 | [ { data: { year: '2017', tag: 'three', month: 'feb', day: '02' },
175 | content: '...' },
176 | { data: { year: '2017', tag: 'three', month: 'feb', day: '02' },
177 | content: '...' } ] } } } }
178 | ```
179 |
180 | ## About
181 |
182 |
183 | Contributing
184 |
185 | Pull requests and stars are always welcome. For bugs and feature requests, [please create an issue](../../issues/new).
186 |
187 |
188 |
189 |
190 | Running Tests
191 |
192 | Running and reviewing unit tests is a great way to get familiarized with a library and its API. You can install dependencies and run tests with the following command:
193 |
194 | ```sh
195 | $ npm install && npm test
196 | ```
197 |
198 |
199 |
200 |
201 | Building docs
202 |
203 | _(This project's readme.md is generated by [verb](https://github.com/verbose/verb-generate-readme), please don't edit the readme directly. Any changes to the readme must be made in the [.verb.md](.verb.md) readme template.)_
204 |
205 | To generate the readme, run the following command:
206 |
207 | ```sh
208 | $ npm install -g verbose/verb#dev verb-generate-readme && verb
209 | ```
210 |
211 |
212 |
213 | ### Related projects
214 |
215 | You might also be interested in these projects:
216 |
217 | * [arr-flatten](https://www.npmjs.com/package/arr-flatten): Recursively flatten an array or arrays. | [homepage](https://github.com/jonschlinkert/arr-flatten "Recursively flatten an array or arrays.")
218 | * [get-value](https://www.npmjs.com/package/get-value): Use property paths like 'a.b.c' to get a nested value from an object. Even works… [more](https://github.com/jonschlinkert/get-value) | [homepage](https://github.com/jonschlinkert/get-value "Use property paths like 'a.b.c' to get a nested value from an object. Even works when keys have dots in them (no other dot-prop library can do this!).")
219 | * [group-object](https://www.npmjs.com/package/group-object): Group object keys and values into lists. | [homepage](https://github.com/doowb/group-object "Group object keys and values into lists.")
220 | * [union-value](https://www.npmjs.com/package/union-value): Set an array of unique values as the property of an object. Supports setting deeply… [more](https://github.com/jonschlinkert/union-value) | [homepage](https://github.com/jonschlinkert/union-value "Set an array of unique values as the property of an object. Supports setting deeply nested properties using using object-paths/dot notation.")
221 |
222 | ### Contributors
223 |
224 | | **Commits** | **Contributor** |
225 | | --- | --- |
226 | | 32 | [doowb](https://github.com/doowb) |
227 | | 13 | [jonschlinkert](https://github.com/jonschlinkert) |
228 | | 2 | [johlym](https://github.com/johlym) |
229 | | 1 | [cperryk](https://github.com/cperryk) |
230 |
231 | ### Author
232 |
233 | **Brian Woodward**
234 |
235 | * [GitHub Profile](https://github.com/doowb)
236 | * [Twitter Profile](https://twitter.com/doowb)
237 | * [LinkedIn Profile](https://linkedin.com/in/woodwardbrian)
238 |
239 | ### License
240 |
241 | Copyright © 2019, [Brian Woodward](https://github.com/doowb).
242 | Released under the [MIT License](LICENSE).
243 |
244 | ***
245 |
246 | _This file was generated by [verb-generate-readme](https://github.com/verbose/verb-generate-readme), v0.8.0, on July 22, 2019._
--------------------------------------------------------------------------------
/examples/geojson.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | // example from https://github.com/doowb/group-array/issues/3
4 | // using geojson data to group into intervals
5 |
6 | const util = require('util');
7 | const groupArray = require('..');
8 |
9 | // create a function that will use the property provided to group on
10 | function interval(prop) {
11 |
12 | // create a function that will use the intervals to check the group by property
13 | return intervals => {
14 |
15 | // create custom labels to use for the resulting object keys
16 | let labels = intervals.reduce((acc, val, i) => {
17 | let min = val;
18 | let max = (intervals[i + 1] && intervals[i + 1] - 1) || '*';
19 | acc[val] = min + ' - ' + max;
20 | return acc;
21 | }, {});
22 |
23 | // create a function that does the grouping for each item
24 | return item => {
25 |
26 | // value to group by
27 | let val = item[prop];
28 |
29 | // if the value falls between the interval range, return it
30 | // as an array to make the interval value the key being grouped by
31 | return intervals.filter((int, i) => {
32 | let min = int;
33 | let max = intervals[i+1] || Infinity;
34 | return min <= val && val < max;
35 | }).map(function(int) {
36 | return labels[int];
37 | });
38 | };
39 | };
40 | }
41 |
42 | // example data to group
43 | let countries = [{
44 | name: 'a',
45 | population: 23000,
46 | climate: 'cold'
47 | }, {
48 | name: 'b',
49 | population: 34000,
50 | climate: 'hot'
51 | }, {
52 | name: 'c',
53 | population: 55000,
54 | climate: 'cold'
55 | }, {
56 | name: 'd',
57 | population: 66000,
58 | climate: 'pleasant'
59 | }, {
60 | name: 'e',
61 | population: 70000,
62 | climate: 'cold'
63 | }];
64 |
65 | // example intervals to group on
66 | let intervals = [20000, 50000, 100000];
67 |
68 | // use population to group by
69 | let population = interval('population');
70 |
71 | // group on population intervals only
72 | let res1 = groupArray(countries, population(intervals));
73 |
74 | // group on climates within population intervals
75 | let res2 = groupArray(countries, population(intervals), 'climate');
76 |
77 | console.log(util.inspect(res1, null, 10));
78 | console.log();
79 | console.log(util.inspect(res2, null, 10));
80 | console.log();
81 |
--------------------------------------------------------------------------------
/examples/posts.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | const util = require('util');
4 | const groupBy = require('..');
5 |
6 | let arr = [
7 | { data: { year: '2016', tag: 'one', month: 'jan', day: '01' }, content: '...' },
8 | { data: { year: '2016', tag: 'one', month: 'jan', day: '01' }, content: '...' },
9 | { data: { year: '2016', tag: 'one', month: 'jan', day: '02' }, content: '...' },
10 | { data: { year: '2016', tag: 'one', month: 'jan', day: '02' }, content: '...' },
11 | { data: { year: '2016', tag: 'one', month: 'feb', day: '10' }, content: '...' },
12 | { data: { year: '2016', tag: 'one', month: 'feb', day: '10' }, content: '...' },
13 | { data: { year: '2016', tag: 'one', month: 'feb', day: '12' }, content: '...' },
14 | { data: { year: '2016', tag: 'one', month: 'feb', day: '12' }, content: '...' },
15 | { data: { year: '2016', tag: 'two', month: 'jan', day: '14' }, content: '...' },
16 | { data: { year: '2016', tag: 'two', month: 'jan', day: '14' }, content: '...' },
17 | { data: { year: '2016', tag: 'two', month: 'jan', day: '16' }, content: '...' },
18 | { data: { year: '2016', tag: 'two', month: 'jan', day: '16' }, content: '...' },
19 | { data: { year: '2016', tag: 'two', month: 'feb', day: '18' }, content: '...' },
20 | { data: { year: '2017', tag: 'two', month: 'feb', day: '18' }, content: '...' },
21 | { data: { year: '2017', tag: 'two', month: 'feb', day: '10' }, content: '...' },
22 | { data: { year: '2017', tag: 'two', month: 'feb', day: '10' }, content: '...' },
23 | { data: { year: '2017', tag: 'three', month: 'jan', day: '01' }, content: '...' },
24 | { data: { year: '2017', tag: 'three', month: 'jan', day: '01' }, content: '...' },
25 | { data: { year: '2017', tag: 'three', month: 'jan', day: '02' }, content: '...' },
26 | { data: { year: '2017', tag: 'three', month: 'jan', day: '02' }, content: '...' },
27 | { data: { year: '2017', tag: 'three', month: 'feb', day: '01' }, content: '...' },
28 | { data: { year: '2017', tag: 'three', month: 'feb', day: '01' }, content: '...' },
29 | { data: { year: '2017', tag: 'three', month: 'feb', day: '02' }, content: '...' },
30 | { data: { year: '2017', tag: 'three', month: 'feb', day: '02' }, content: '...' }
31 | ]
32 |
33 | let res = groupBy(arr, 'data.year', 'data.tag', 'data.month', 'data.day');
34 | console.log(util.inspect(res, { depth: null }));
35 |
--------------------------------------------------------------------------------
/examples/tags-function.js:
--------------------------------------------------------------------------------
1 | const util = require('util');
2 | const groupArray = require('..');
3 | let arr = [
4 | {
5 | categories: { one: [ 'A' ] },
6 | name: 'Post 1',
7 | content: 'Post 1',
8 | key: 'post-1.md'
9 | },
10 | {
11 | categories: { one: [ 'A' ], two: [ 'B', 'C' ] },
12 | name: 'Post 2',
13 | content: 'Post 2',
14 | key: 'post-2.md'
15 | },
16 | {
17 | categories: { one: [ 'B' ], two: [ 'C', 'D' ] },
18 | name: 'Post 3',
19 | content: 'Post 3',
20 | key: 'post-3.md'
21 | },
22 | {
23 | categories: { three: [ 'B' ], four: [ 'E', 'F', 'G' ] },
24 | name: 'Post 4',
25 | content: 'Post 4',
26 | key: 'post-4.md'
27 | },
28 | {
29 | categories: { four: [ 'C', 'F' ] },
30 | name: 'Post 5',
31 | content: 'Post 5',
32 | key: 'post-5.md'
33 | },
34 | {
35 | categories: { four: [ 'F', 'G' ] },
36 | name: 'Post 6',
37 | content: 'Post 6',
38 | key: 'post-6.md'
39 | }
40 | ];
41 |
42 | let res = groupArray(arr, 'categories', obj => {
43 | obj.tags = [];
44 | for (let key in obj.categories) {
45 | if (obj.categories.hasOwnProperty(key)) {
46 | let tags = obj.categories[key];
47 | tags.forEach(tag => {
48 | if (obj.tags.indexOf(tag) === -1) {
49 | obj.tags.push(tag);
50 | }
51 | });
52 | }
53 | }
54 | return obj.tags;
55 | });
56 |
57 | console.log(util.inspect(res, null, 10));
58 |
--------------------------------------------------------------------------------
/examples/tags-property.js:
--------------------------------------------------------------------------------
1 | const util = require('util');
2 | const groupArray = require('..');
3 | let arr = [
4 | {
5 | categories: { one: ['A'] },
6 | name: 'Post 1',
7 | content: 'Post 1',
8 | key: 'post-1.md'
9 | },
10 | {
11 | categories: { one: ['A'], two: ['B', 'C'] },
12 | name: 'Post 2',
13 | content: 'Post 2',
14 | key: 'post-2.md'
15 | },
16 | {
17 | categories: { one: ['B'], two: ['C', 'D'] },
18 | name: 'Post 3',
19 | content: 'Post 3',
20 | key: 'post-3.md'
21 | },
22 | {
23 | categories: { three: ['B'], four: ['E', 'F', 'G'] },
24 | name: 'Post 4',
25 | content: 'Post 4',
26 | key: 'post-4.md'
27 | },
28 | {
29 | categories: { four: ['C', 'F'] },
30 | name: 'Post 5',
31 | content: 'Post 5',
32 | key: 'post-5.md'
33 | },
34 | {
35 | categories: { four: ['F', 'G'] },
36 | name: 'Post 6',
37 | content: 'Post 6',
38 | key: 'post-6.md'
39 | }
40 | ];
41 |
42 | function createTags(items) {
43 | items.forEach(obj => {
44 | obj.tags = [];
45 | for (let key in obj.categories) {
46 | if (obj.categories.hasOwnProperty(key)) {
47 | let tags = obj.categories[key];
48 | tags.forEach(tag => {
49 | if (obj.tags.indexOf(tag) === -1) {
50 | obj.tags.push(tag);
51 | }
52 | });
53 | }
54 | }
55 | });
56 | return items;
57 | }
58 |
59 | let res = groupArray(createTags(arr), 'categories', 'tags');
60 | console.log(util.inspect(res, null, 10));
61 |
--------------------------------------------------------------------------------
/index.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | const split = require('split-string');
4 | const flatten = require('arr-flatten');
5 | const union = require('union-value');
6 | const forOwn = require('for-own');
7 | const typeOf = require('kind-of');
8 | const get = require('get-value');
9 |
10 | function groupFn(arr, props) {
11 | if (arr == null) {
12 | return [];
13 | }
14 |
15 | if (!Array.isArray(arr)) {
16 | throw new TypeError('group-array expects an array.');
17 | }
18 |
19 | if (arguments.length === 1) {
20 | return arr;
21 | }
22 |
23 | let args = flatten([].slice.call(arguments, 1));
24 | let groups = groupBy(arr, args[0]);
25 |
26 | for (let i = 1; i < args.length; i++) {
27 | toGroup(groups, args[i]);
28 | }
29 | return groups;
30 | }
31 |
32 | function groupBy(arr, prop, key) {
33 | let groups = {};
34 |
35 | for (let i = 0; i < arr.length; i++) {
36 | let obj = arr[i];
37 | let val;
38 |
39 | // allow a function to modify the object
40 | // and/or return a val to use
41 | if (typeof prop === 'function') {
42 | val = prop.call(groups, obj, key);
43 | } else {
44 | val = get(obj, prop);
45 | }
46 |
47 | switch (typeOf(val)) {
48 | case 'undefined':
49 | break;
50 | case 'string':
51 | case 'number':
52 | case 'boolean':
53 | union(groups, escape(String(val)), obj);
54 | break;
55 | case 'object':
56 | case 'array':
57 | eachValue(groups, obj, val);
58 | break;
59 | case 'function':
60 | throw new Error('invalid argument type: ' + key);
61 | }
62 | }
63 | return groups;
64 | }
65 |
66 | function eachValue(groups, obj, val) {
67 | if (Array.isArray(val)) {
68 | val.forEach(key => {
69 | union(groups, escape(key), obj);
70 | });
71 | } else {
72 | forOwn(val, (v, key) => {
73 | union(groups, escape(key), obj);
74 | });
75 | }
76 | }
77 |
78 | function toGroup(groups, prop) {
79 | forOwn(groups, (val, key) => {
80 | if (!Array.isArray(val)) {
81 | groups[key] = toGroup(val, prop, key);
82 | } else {
83 | groups[key] = groupBy(val, prop, key);
84 | }
85 | });
86 | return groups;
87 | }
88 |
89 | function escape(str) {
90 | var opts = {
91 | strict: false,
92 | keepEscaping: true,
93 | keepDoubleQuotes: true,
94 | keepSingleQuotes: true
95 | };
96 |
97 | try {
98 | return split(str, opts).join('\\.');
99 | } catch (err) {
100 | return str;
101 | }
102 | }
103 |
104 | /**
105 | * Expose `groupArray`
106 | */
107 |
108 | module.exports = groupFn;
109 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "group-array",
3 | "description": "Group array of objects into lists.",
4 | "version": "1.0.0",
5 | "homepage": "https://github.com/doowb/group-array",
6 | "author": "Brian Woodward (https://github.com/doowb)",
7 | "contributors": [
8 | "Brian Woodward (https://twitter.com/doowb)",
9 | "Chris Kirk (http://www.chrispkirk.com)",
10 | "Johnathan Lyman (https://johnathan.org)",
11 | "Jon Schlinkert (http://twitter.com/jonschlinkert)"
12 | ],
13 | "repository": "doowb/group-array",
14 | "bugs": {
15 | "url": "https://github.com/doowb/group-array/issues"
16 | },
17 | "license": "MIT",
18 | "files": [
19 | "index.js"
20 | ],
21 | "main": "index.js",
22 | "engines": {
23 | "node": ">=8"
24 | },
25 | "scripts": {
26 | "test": "mocha"
27 | },
28 | "dependencies": {
29 | "arr-flatten": "^1.1.0",
30 | "for-own": "^1.0.0",
31 | "get-value": "^3.0.1",
32 | "kind-of": "^6.0.2",
33 | "split-string": "^6.1.0",
34 | "union-value": "^2.0.1"
35 | },
36 | "devDependencies": {
37 | "gulp-format-md": "^2.0.0",
38 | "mocha": "^6.2.0",
39 | "should": "^13.2.3"
40 | },
41 | "keywords": [
42 | "array",
43 | "group",
44 | "item",
45 | "list",
46 | "nested",
47 | "prop",
48 | "properties",
49 | "property"
50 | ],
51 | "verb": {
52 | "toc": true,
53 | "layout": "default",
54 | "tasks": [
55 | "readme"
56 | ],
57 | "plugins": [
58 | "gulp-format-md"
59 | ],
60 | "related": {
61 | "list": [
62 | "arr-flatten",
63 | "get-value",
64 | "group-object",
65 | "union-value"
66 | ]
67 | },
68 | "reflinks": [
69 | "verb",
70 | "verb-generate-readme"
71 | ],
72 | "lint": {
73 | "reflinks": true
74 | }
75 | }
76 | }
77 |
--------------------------------------------------------------------------------
/test/expected/categories-tags.js:
--------------------------------------------------------------------------------
1 | module.exports = { one:
2 | { A:
3 | [ { categories: { one: [ 'A' ] },
4 | name: 'Post 1',
5 | content: 'Post 1',
6 | key: 'post-1.md' },
7 | { categories: { one: [ 'A' ], two: [ 'B', 'C' ] },
8 | name: 'Post 2',
9 | content: 'Post 2',
10 | key: 'post-2.md' } ],
11 | B:
12 | [ { categories: { one: [ 'B' ], two: [ 'C', 'D' ] },
13 | name: 'Post 3',
14 | content: 'Post 3',
15 | key: 'post-3.md'} ] },
16 | two:
17 | { B:
18 | [ { categories: { one: [ 'A' ], two: [ 'B', 'C' ] },
19 | name: 'Post 2',
20 | content: 'Post 2',
21 | key: 'post-2.md' } ],
22 | C:
23 | [ { categories: { one: [ 'A' ], two: [ 'B', 'C' ] },
24 | name: 'Post 2',
25 | content: 'Post 2',
26 | key: 'post-2.md' },
27 | { categories: { one: [ 'B' ], two: [ 'C', 'D' ] },
28 | name: 'Post 3',
29 | content: 'Post 3',
30 | key: 'post-3.md' } ],
31 | D:
32 | [ { categories: { one: [ 'B' ], two: [ 'C', 'D' ] },
33 | name: 'Post 3',
34 | content: 'Post 3',
35 | key: 'post-3.md' } ] },
36 | three:
37 | { B:
38 | [ { categories: { three: [ 'B' ], four: [ 'E', 'F', 'G' ] },
39 | name: 'Post 4',
40 | content: 'Post 4',
41 | key: 'post-4.md' } ] },
42 | four:
43 | { E:
44 | [ { categories: { three: [ 'B' ], four: [ 'E', 'F', 'G' ] },
45 | name: 'Post 4',
46 | content: 'Post 4',
47 | key: 'post-4.md' } ],
48 | F:
49 | [ { categories: { three: [ 'B' ], four: [ 'E', 'F', 'G' ] },
50 | name: 'Post 4',
51 | content: 'Post 4',
52 | key: 'post-4.md' },
53 | { categories: { four: [ 'C', 'F' ] },
54 | name: 'Post 5',
55 | content: 'Post 5',
56 | key: 'post-5.md' },
57 | { categories: { four: [ 'F', 'G' ] },
58 | name: 'Post 6',
59 | content: 'Post 6',
60 | key: 'post-6.md' } ],
61 | G:
62 | [ { categories: { three: [ 'B' ], four: [ 'E', 'F', 'G' ] },
63 | name: 'Post 4',
64 | content: 'Post 4',
65 | key: 'post-4.md' },
66 | { categories: { four: [ 'F', 'G' ] },
67 | name: 'Post 6',
68 | content: 'Post 6',
69 | key: 'post-6.md' } ],
70 | C:
71 | [ { categories: { four: [ 'C', 'F' ] },
72 | name: 'Post 5',
73 | content: 'Post 5',
74 | key: 'post-5.md' } ] } };
75 |
--------------------------------------------------------------------------------
/test/expected/deeply-nested.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | one:
3 | { jan:
4 | { '01':
5 | [ { data: { tag: 'one', month: 'jan', day: '01' }, content: '...' },
6 | { data: { tag: 'one', month: 'jan', day: '01' }, content: '...' } ],
7 | '02':
8 | [ { data: { tag: 'one', month: 'jan', day: '02' }, content: '...' },
9 | { data: { tag: 'one', month: 'jan', day: '02' }, content: '...' } ] },
10 | feb:
11 | { '10':
12 | [ { data: { tag: 'one', month: 'feb', day: '10' }, content: '...' },
13 | { data: { tag: 'one', month: 'feb', day: '10' }, content: '...' } ],
14 | '12':
15 | [ { data: { tag: 'one', month: 'feb', day: '12' }, content: '...' },
16 | { data: { tag: 'one', month: 'feb', day: '12' }, content: '...' } ] } },
17 | two:
18 | { jan:
19 | { '14':
20 | [ { data: { tag: 'two', month: 'jan', day: '14' }, content: '...' },
21 | { data: { tag: 'two', month: 'jan', day: '14' }, content: '...' } ],
22 | '16':
23 | [ { data: { tag: 'two', month: 'jan', day: '16' }, content: '...' },
24 | { data: { tag: 'two', month: 'jan', day: '16' }, content: '...' } ] },
25 | feb:
26 | { '10':
27 | [ { data: { tag: 'two', month: 'feb', day: '10' }, content: '...' },
28 | { data: { tag: 'two', month: 'feb', day: '10' }, content: '...' } ],
29 | '18':
30 | [ { data: { tag: 'two', month: 'feb', day: '18' }, content: '...' },
31 | { data: { tag: 'two', month: 'feb', day: '18' }, content: '...' } ] } },
32 | three:
33 | { jan:
34 | { '01':
35 | [ { data: { tag: 'three', month: 'jan', day: '01' }, content: '...' },
36 | { data: { tag: 'three', month: 'jan', day: '01' }, content: '...' } ],
37 | '02':
38 | [ { data: { tag: 'three', month: 'jan', day: '02' }, content: '...' },
39 | { data: { tag: 'three', month: 'jan', day: '02' }, content: '...' } ] },
40 | feb:
41 | { '01':
42 | [ { data: { tag: 'three', month: 'feb', day: '01' }, content: '...' },
43 | { data: { tag: 'three', month: 'feb', day: '01' }, content: '...' } ],
44 | '02':
45 | [ { data: { tag: 'three', month: 'feb', day: '02' }, content: '...' },
46 | { data: { tag: 'three', month: 'feb', day: '02' }, content: '...' } ] } }
47 | };
48 |
--------------------------------------------------------------------------------
/test/expected/insanely-nested.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | '2014':
3 | { one:
4 | { jan:
5 | { '01':
6 | [ { data: { year: '2014', tag: 'one', month: 'jan', day: '01' }, content: '...' },
7 | { data: { year: '2014', tag: 'one', month: 'jan', day: '01' }, content: '...' } ],
8 | '02':
9 | [ { data: { year: '2014', tag: 'one', month: 'jan', day: '02' }, content: '...' },
10 | { data: { year: '2014', tag: 'one', month: 'jan', day: '02' }, content: '...' } ] },
11 | feb:
12 | { '10':
13 | [ { data: { year: '2014', tag: 'one', month: 'feb', day: '10' }, content: '...' },
14 | { data: { year: '2014', tag: 'one', month: 'feb', day: '10' }, content: '...' } ],
15 | '12':
16 | [ { data: { year: '2014', tag: 'one', month: 'feb', day: '12' }, content: '...' },
17 | { data: { year: '2014', tag: 'one', month: 'feb', day: '12' }, content: '...' } ] } },
18 | two:
19 | { jan:
20 | { '14':
21 | [ { data: { year: '2014', tag: 'two', month: 'jan', day: '14' }, content: '...' },
22 | { data: { year: '2014', tag: 'two', month: 'jan', day: '14' }, content: '...' } ],
23 | '16':
24 | [ { data: { year: '2014', tag: 'two', month: 'jan', day: '16' }, content: '...' },
25 | { data: { year: '2014', tag: 'two', month: 'jan', day: '16' }, content: '...' } ] },
26 | feb:
27 | { '18':
28 | [ { data: { year: '2014', tag: 'two', month: 'feb', day: '18' }, content: '...' } ] } } },
29 | '2015':
30 | { two:
31 | { feb:
32 | { '10':
33 | [ { data: { year: '2015', tag: 'two', month: 'feb', day: '10' }, content: '...' },
34 | { data: { year: '2015', tag: 'two', month: 'feb', day: '10' }, content: '...' } ],
35 | '18':
36 | [ { data: { year: '2015', tag: 'two', month: 'feb', day: '18' }, content: '...' } ] } },
37 | three:
38 | { jan:
39 | { '01':
40 | [ { data: { year: '2015', tag: 'three', month: 'jan', day: '01' }, content: '...' },
41 | { data: { year: '2015', tag: 'three', month: 'jan', day: '01' }, content: '...' } ],
42 | '02':
43 | [ { data: { year: '2015', tag: 'three', month: 'jan', day: '02' }, content: '...' },
44 | { data: { year: '2015', tag: 'three', month: 'jan', day: '02' }, content: '...' } ] },
45 | feb:
46 | { '01':
47 | [ { data: { year: '2015', tag: 'three', month: 'feb', day: '01' }, content: '...' },
48 | { data: { year: '2015', tag: 'three', month: 'feb', day: '01' }, content: '...' } ],
49 | '02':
50 | [ { data: { year: '2015', tag: 'three', month: 'feb', day: '02' }, content: '...' },
51 | { data: { year: '2015', tag: 'three', month: 'feb', day: '02' }, content: '...' } ] } } }};
52 |
--------------------------------------------------------------------------------
/test/expected/issue-10.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | '/"jsb":s*[/gi/]/gi': [
3 | {
4 | file: '',
5 | ext: 'js',
6 | startTag: /"js\b":\s*\[/gi,
7 | endTag: /\]/gi,
8 | tagKey: '/"js\\b":\\s*\\[/gi/\\]/gi'
9 | },
10 | {
11 | file: '',
12 | ext: 'js',
13 | startTag: /"js\b":\s*\[/gi,
14 | endTag: /\]/gi,
15 | tagKey: '/"js\\b":\\s*\\[/gi/\\]/gi'
16 | }
17 | ],
18 | '/"htmlb":s*[/gi/]/gi': [
19 | {
20 | file: '',
21 | ext: 'html',
22 | startTag: /"html\b":\s*\[/gi,
23 | endTag: /\]/gi,
24 | tagKey: '/"html\\b":\\s*\\[/gi/\\]/gi'
25 | }
26 | ],
27 | '/"cssb":s*[/gi/]/gi': [
28 | {
29 | file: '',
30 | ext: 'css',
31 | startTag: /"css\b":\s*\[/gi,
32 | endTag: /\]/gi,
33 | tagKey: '/"css\\b":\\s*\\[/gi/\\]/gi'
34 | }
35 | ]
36 | };
--------------------------------------------------------------------------------
/test/expected/nested.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | one: {
3 | jan: [
4 | {data: {month:'jan', tag: 'one'}, content: '...'},
5 | {data: {month:'jan', tag: 'one'}, content: '...'}
6 | ],
7 | feb: [
8 | {data: {month:'feb', tag: 'one'}, content: '...'},
9 | {data: {month:'feb', tag: 'one'}, content: '...'}
10 | ]
11 | },
12 | two: {
13 | jan: [
14 | {data: {month:'jan', tag: 'two'}, content: '...'},
15 | {data: {month:'jan', tag: 'two'}, content: '...'}
16 | ],
17 | feb: [
18 | {data: {month:'feb', tag: 'two'}, content: '...'},
19 | {data: {month:'feb', tag: 'two'}, content: '...'}
20 | ]
21 | },
22 | three: {
23 | jan: [
24 | {data: {month:'jan', tag: 'three'}, content: '...'},
25 | {data: {month:'jan', tag: 'three'}, content: '...'}
26 | ],
27 | feb: [
28 | {data: {month:'feb', tag: 'three'}, content: '...'},
29 | {data: {month:'feb', tag: 'three'}, content: '...'}
30 | ]
31 | }
32 | };
33 |
--------------------------------------------------------------------------------
/test/expected/tags-array.js:
--------------------------------------------------------------------------------
1 | module.exports = { A:
2 | [ { categories: { one: [ 'A' ] },
3 | name: 'Post 1',
4 | content: 'Post 1',
5 | key: 'post-1.md',
6 | tags: [ 'A' ] },
7 | { categories: { one: [ 'A' ], two: [ 'B', 'C' ] },
8 | name: 'Post 2',
9 | content: 'Post 2',
10 | key: 'post-2.md',
11 | tags: [ 'A', 'B', 'C' ] },
12 | { categories: { one: [ 'A' ], two: [ 'B', 'C' ] },
13 | name: 'Post 2',
14 | content: 'Post 2',
15 | key: 'post-2.md',
16 | tags: [ 'A', 'B', 'C' ] } ],
17 | B:
18 | [ { categories: { one: [ 'A' ], two: [ 'B', 'C' ] },
19 | name: 'Post 2',
20 | content: 'Post 2',
21 | key: 'post-2.md',
22 | tags: [ 'A', 'B', 'C' ] },
23 | { categories: { one: [ 'B' ], two: [ 'C', 'D' ] },
24 | name: 'Post 3',
25 | content: 'Post 3',
26 | key: 'post-3.md',
27 | tags: [ 'B', 'C', 'D' ] },
28 | { categories: { one: [ 'A' ], two: [ 'B', 'C' ] },
29 | name: 'Post 2',
30 | content: 'Post 2',
31 | key: 'post-2.md',
32 | tags: [ 'A', 'B', 'C' ] },
33 | { categories: { one: [ 'B' ], two: [ 'C', 'D' ] },
34 | name: 'Post 3',
35 | content: 'Post 3',
36 | key: 'post-3.md',
37 | tags: [ 'B', 'C', 'D' ] },
38 | { categories: { three: [ 'B' ], four: [ 'E', 'F', 'G' ] },
39 | name: 'Post 4',
40 | content: 'Post 4',
41 | key: 'post-4.md',
42 | tags: [ 'B', 'E', 'F', 'G' ] },
43 | { categories: { three: [ 'B' ], four: [ 'E', 'F', 'G' ] },
44 | name: 'Post 4',
45 | content: 'Post 4',
46 | key: 'post-4.md',
47 | tags: [ 'B', 'E', 'F', 'G' ] } ],
48 | C:
49 | [ { categories: { one: [ 'A' ], two: [ 'B', 'C' ] },
50 | name: 'Post 2',
51 | content: 'Post 2',
52 | key: 'post-2.md',
53 | tags: [ 'A', 'B', 'C' ] },
54 | { categories: { one: [ 'B' ], two: [ 'C', 'D' ] },
55 | name: 'Post 3',
56 | content: 'Post 3',
57 | key: 'post-3.md',
58 | tags: [ 'B', 'C', 'D' ] },
59 | { categories: { one: [ 'A' ], two: [ 'B', 'C' ] },
60 | name: 'Post 2',
61 | content: 'Post 2',
62 | key: 'post-2.md',
63 | tags: [ 'A', 'B', 'C' ] },
64 | { categories: { one: [ 'B' ], two: [ 'C', 'D' ] },
65 | name: 'Post 3',
66 | content: 'Post 3',
67 | key: 'post-3.md',
68 | tags: [ 'B', 'C', 'D' ] },
69 | { categories: { four: [ 'C', 'F' ] },
70 | name: 'Post 5',
71 | content: 'Post 5',
72 | key: 'post-5.md',
73 | tags: [ 'C', 'F' ] } ],
74 | D:
75 | [ { categories: { one: [ 'B' ], two: [ 'C', 'D' ] },
76 | name: 'Post 3',
77 | content: 'Post 3',
78 | key: 'post-3.md',
79 | tags: [ 'B', 'C', 'D' ] },
80 | { categories: { one: [ 'B' ], two: [ 'C', 'D' ] },
81 | name: 'Post 3',
82 | content: 'Post 3',
83 | key: 'post-3.md',
84 | tags: [ 'B', 'C', 'D' ] } ],
85 | E:
86 | [ { categories: { three: [ 'B' ], four: [ 'E', 'F', 'G' ] },
87 | name: 'Post 4',
88 | content: 'Post 4',
89 | key: 'post-4.md',
90 | tags: [ 'B', 'E', 'F', 'G' ] },
91 | { categories: { three: [ 'B' ], four: [ 'E', 'F', 'G' ] },
92 | name: 'Post 4',
93 | content: 'Post 4',
94 | key: 'post-4.md',
95 | tags: [ 'B', 'E', 'F', 'G' ] } ],
96 | F:
97 | [ { categories: { three: [ 'B' ], four: [ 'E', 'F', 'G' ] },
98 | name: 'Post 4',
99 | content: 'Post 4',
100 | key: 'post-4.md',
101 | tags: [ 'B', 'E', 'F', 'G' ] },
102 | { categories: { three: [ 'B' ], four: [ 'E', 'F', 'G' ] },
103 | name: 'Post 4',
104 | content: 'Post 4',
105 | key: 'post-4.md',
106 | tags: [ 'B', 'E', 'F', 'G' ] },
107 | { categories: { four: [ 'C', 'F' ] },
108 | name: 'Post 5',
109 | content: 'Post 5',
110 | key: 'post-5.md',
111 | tags: [ 'C', 'F' ] },
112 | { categories: { four: [ 'F', 'G' ] },
113 | name: 'Post 6',
114 | content: 'Post 6',
115 | key: 'post-6.md',
116 | tags: [ 'F', 'G' ] } ],
117 | G:
118 | [ { categories: { three: [ 'B' ], four: [ 'E', 'F', 'G' ] },
119 | name: 'Post 4',
120 | content: 'Post 4',
121 | key: 'post-4.md',
122 | tags: [ 'B', 'E', 'F', 'G' ] },
123 | { categories: { three: [ 'B' ], four: [ 'E', 'F', 'G' ] },
124 | name: 'Post 4',
125 | content: 'Post 4',
126 | key: 'post-4.md',
127 | tags: [ 'B', 'E', 'F', 'G' ] },
128 | { categories: { four: [ 'F', 'G' ] },
129 | name: 'Post 6',
130 | content: 'Post 6',
131 | key: 'post-6.md',
132 | tags: [ 'F', 'G' ] } ] }
--------------------------------------------------------------------------------
/test/fixtures/categories-tags.js:
--------------------------------------------------------------------------------
1 | module.exports = [
2 | {
3 | categories: {
4 | one: ['A']
5 | },
6 | name: 'Post 1',
7 | content: 'Post 1',
8 | key: 'post-1.md'
9 | },
10 | {
11 | categories: {
12 | one: ['A'],
13 | two: ['B', 'C']
14 | },
15 | name: 'Post 2',
16 | content: 'Post 2',
17 | key: 'post-2.md'
18 | },
19 | {
20 | categories: {
21 | one: ['B'],
22 | two: ['C', 'D']
23 | },
24 | name: 'Post 3',
25 | content: 'Post 3',
26 | key: 'post-3.md'
27 | },
28 | {
29 | categories: {
30 | three: ['B'],
31 | four: ['E', 'F', 'G']
32 | },
33 | name: 'Post 4',
34 | content: 'Post 4',
35 | key: 'post-4.md'
36 | },
37 | {
38 | categories: {
39 | four: ['C', 'F']
40 | },
41 | name: 'Post 5',
42 | content: 'Post 5',
43 | key: 'post-5.md'
44 | },
45 | {
46 | categories: {
47 | four: ['F', 'G']
48 | },
49 | name: 'Post 6',
50 | content: 'Post 6',
51 | key: 'post-6.md'
52 | }];
53 |
--------------------------------------------------------------------------------
/test/fixtures/date-function.js:
--------------------------------------------------------------------------------
1 | module.exports = [
2 | { data: { tag: 'one', date: 'jan-01'}, content: '...'},
3 | { data: { tag: 'one', date: 'jan-01'}, content: '...'},
4 | { data: { tag: 'one', date: 'jan-02'}, content: '...'},
5 | { data: { tag: 'one', date: 'jan-02'}, content: '...'},
6 | { data: { tag: 'one', date: 'feb-10'}, content: '...'},
7 | { data: { tag: 'one', date: 'feb-10'}, content: '...'},
8 | { data: { tag: 'one', date: 'feb-12'}, content: '...'},
9 | { data: { tag: 'one', date: 'feb-12'}, content: '...'},
10 | { data: { tag: 'two', date: 'jan-14'}, content: '...'},
11 | { data: { tag: 'two', date: 'jan-14'}, content: '...'},
12 | { data: { tag: 'two', date: 'jan-16'}, content: '...'},
13 | { data: { tag: 'two', date: 'jan-16'}, content: '...'},
14 | { data: { tag: 'two', date: 'feb-18'}, content: '...'},
15 | { data: { tag: 'two', date: 'feb-18'}, content: '...'},
16 | { data: { tag: 'two', date: 'feb-10'}, content: '...'},
17 | { data: { tag: 'two', date: 'feb-10'}, content: '...'},
18 | { data: { tag: 'three', date: 'jan-01'}, content: '...'},
19 | { data: { tag: 'three', date: 'jan-01'}, content: '...'},
20 | { data: { tag: 'three', date: 'jan-02'}, content: '...'},
21 | { data: { tag: 'three', date: 'jan-02'}, content: '...'},
22 | { data: { tag: 'three', date: 'feb-01'}, content: '...'},
23 | { data: { tag: 'three', date: 'feb-01'}, content: '...'},
24 | { data: { tag: 'three', date: 'feb-02'}, content: '...'},
25 | { data: { tag: 'three', date: 'feb-02'}, content: '...'}
26 | ];
27 |
--------------------------------------------------------------------------------
/test/fixtures/deeply-nested.js:
--------------------------------------------------------------------------------
1 | module.exports = [
2 | { data: { tag: 'one', month: 'jan', day: '01'}, content: '...'},
3 | { data: { tag: 'one', month: 'jan', day: '01'}, content: '...'},
4 | { data: { tag: 'one', month: 'jan', day: '02'}, content: '...'},
5 | { data: { tag: 'one', month: 'jan', day: '02'}, content: '...'},
6 | { data: { tag: 'one', month: 'feb', day: '10'}, content: '...'},
7 | { data: { tag: 'one', month: 'feb', day: '10'}, content: '...'},
8 | { data: { tag: 'one', month: 'feb', day: '12'}, content: '...'},
9 | { data: { tag: 'one', month: 'feb', day: '12'}, content: '...'},
10 | { data: { tag: 'two', month: 'jan', day: '14'}, content: '...'},
11 | { data: { tag: 'two', month: 'jan', day: '14'}, content: '...'},
12 | { data: { tag: 'two', month: 'jan', day: '16'}, content: '...'},
13 | { data: { tag: 'two', month: 'jan', day: '16'}, content: '...'},
14 | { data: { tag: 'two', month: 'feb', day: '18'}, content: '...'},
15 | { data: { tag: 'two', month: 'feb', day: '18'}, content: '...'},
16 | { data: { tag: 'two', month: 'feb', day: '10'}, content: '...'},
17 | { data: { tag: 'two', month: 'feb', day: '10'}, content: '...'},
18 | { data: { tag: 'three', month: 'jan', day: '01'}, content: '...'},
19 | { data: { tag: 'three', month: 'jan', day: '01'}, content: '...'},
20 | { data: { tag: 'three', month: 'jan', day: '02'}, content: '...'},
21 | { data: { tag: 'three', month: 'jan', day: '02'}, content: '...'},
22 | { data: { tag: 'three', month: 'feb', day: '01'}, content: '...'},
23 | { data: { tag: 'three', month: 'feb', day: '01'}, content: '...'},
24 | { data: { tag: 'three', month: 'feb', day: '02'}, content: '...'},
25 | { data: { tag: 'three', month: 'feb', day: '02'}, content: '...'}
26 | ];
27 |
--------------------------------------------------------------------------------
/test/fixtures/insanely-nested.js:
--------------------------------------------------------------------------------
1 | module.exports = [
2 | { data: { year: '2014', tag: 'one', month: 'jan', day: '01'}, content: '...'},
3 | { data: { year: '2014', tag: 'one', month: 'jan', day: '01'}, content: '...'},
4 | { data: { year: '2014', tag: 'one', month: 'jan', day: '02'}, content: '...'},
5 | { data: { year: '2014', tag: 'one', month: 'jan', day: '02'}, content: '...'},
6 | { data: { year: '2014', tag: 'one', month: 'feb', day: '10'}, content: '...'},
7 | { data: { year: '2014', tag: 'one', month: 'feb', day: '10'}, content: '...'},
8 | { data: { year: '2014', tag: 'one', month: 'feb', day: '12'}, content: '...'},
9 | { data: { year: '2014', tag: 'one', month: 'feb', day: '12'}, content: '...'},
10 | { data: { year: '2014', tag: 'two', month: 'jan', day: '14'}, content: '...'},
11 | { data: { year: '2014', tag: 'two', month: 'jan', day: '14'}, content: '...'},
12 | { data: { year: '2014', tag: 'two', month: 'jan', day: '16'}, content: '...'},
13 | { data: { year: '2014', tag: 'two', month: 'jan', day: '16'}, content: '...'},
14 | { data: { year: '2014', tag: 'two', month: 'feb', day: '18'}, content: '...'},
15 | { data: { year: '2015', tag: 'two', month: 'feb', day: '18'}, content: '...'},
16 | { data: { year: '2015', tag: 'two', month: 'feb', day: '10'}, content: '...'},
17 | { data: { year: '2015', tag: 'two', month: 'feb', day: '10'}, content: '...'},
18 | { data: { year: '2015', tag: 'three', month: 'jan', day: '01'}, content: '...'},
19 | { data: { year: '2015', tag: 'three', month: 'jan', day: '01'}, content: '...'},
20 | { data: { year: '2015', tag: 'three', month: 'jan', day: '02'}, content: '...'},
21 | { data: { year: '2015', tag: 'three', month: 'jan', day: '02'}, content: '...'},
22 | { data: { year: '2015', tag: 'three', month: 'feb', day: '01'}, content: '...'},
23 | { data: { year: '2015', tag: 'three', month: 'feb', day: '01'}, content: '...'},
24 | { data: { year: '2015', tag: 'three', month: 'feb', day: '02'}, content: '...'},
25 | { data: { year: '2015', tag: 'three', month: 'feb', day: '02'}, content: '...'}
26 | ];
27 |
--------------------------------------------------------------------------------
/test/fixtures/issue-10.js:
--------------------------------------------------------------------------------
1 | module.exports = [
2 | {
3 | file: '',
4 | ext: 'js',
5 | startTag: /"js\b":\s*\[/gi,
6 | endTag: /\]/gi,
7 | tagKey: '/"js\\b":\\s*\\[/gi/\\]/gi'
8 | },
9 | {
10 | file: '',
11 | ext: 'html',
12 | startTag: /"html\b":\s*\[/gi,
13 | endTag: /\]/gi,
14 | tagKey: '/"html\\b":\\s*\\[/gi/\\]/gi'
15 | },
16 | {
17 | file: '',
18 | ext: 'js',
19 | startTag: /"js\b":\s*\[/gi,
20 | endTag: /\]/gi,
21 | tagKey: '/"js\\b":\\s*\\[/gi/\\]/gi'
22 | },
23 | {
24 | file: '',
25 | ext: 'css',
26 | startTag: /"css\b":\s*\[/gi,
27 | endTag: /\]/gi,
28 | tagKey: '/"css\\b":\\s*\\[/gi/\\]/gi'
29 | }
30 | ];
--------------------------------------------------------------------------------
/test/fixtures/nested.js:
--------------------------------------------------------------------------------
1 | module.exports = [
2 | { data: { tag: 'one', month: 'jan'}, content: '...'},
3 | { data: { tag: 'one', month: 'jan'}, content: '...'},
4 | { data: { tag: 'one', month: 'feb'}, content: '...'},
5 | { data: { tag: 'one', month: 'feb'}, content: '...'},
6 | { data: { tag: 'two', month: 'jan'}, content: '...'},
7 | { data: { tag: 'two', month: 'jan'}, content: '...'},
8 | { data: { tag: 'two', month: 'feb'}, content: '...'},
9 | { data: { tag: 'two', month: 'feb'}, content: '...'},
10 | { data: { tag: 'three', month: 'jan'}, content: '...'},
11 | { data: { tag: 'three', month: 'jan'}, content: '...'},
12 | { data: { tag: 'three', month: 'feb'}, content: '...'},
13 | { data: { tag: 'three', month: 'feb'}, content: '...'}
14 | ];
--------------------------------------------------------------------------------
/test/fixtures/tags-array.js:
--------------------------------------------------------------------------------
1 | module.exports = [
2 | {
3 | categories: {
4 | one: ['A']
5 | },
6 | name: 'Post 1',
7 | content: 'Post 1',
8 | key: 'post-1.md',
9 | tags: ['A']
10 | },
11 | {
12 | categories: {
13 | one: ['A'],
14 | two: ['B', 'C']
15 | },
16 | name: 'Post 2',
17 | content: 'Post 2',
18 | key: 'post-2.md',
19 | tags: ['A', 'B', 'C']
20 | },
21 | {
22 | categories: {
23 | one: ['B'],
24 | two: ['C', 'D']
25 | },
26 | name: 'Post 3',
27 | content: 'Post 3',
28 | key: 'post-3.md',
29 | tags: ['B', 'C', 'D']
30 | },
31 | {
32 | categories: {
33 | one: ['A'],
34 | two: ['B', 'C']
35 | },
36 | name: 'Post 2',
37 | content: 'Post 2',
38 | key: 'post-2.md',
39 | tags: ['A', 'B', 'C']
40 | },
41 | {
42 | categories: {
43 | one: ['B'],
44 | two: ['C', 'D']
45 | },
46 | name: 'Post 3',
47 | content: 'Post 3',
48 | key: 'post-3.md',
49 | tags: ['B', 'C', 'D']
50 | },
51 | {
52 | categories: {
53 | three: ['B'],
54 | four: ['E', 'F', 'G']
55 | },
56 | name: 'Post 4',
57 | content: 'Post 4',
58 | key: 'post-4.md',
59 | tags: ['B', 'E', 'F', 'G']
60 | },
61 | {
62 | categories: {
63 | three: ['B'],
64 | four: ['E', 'F', 'G']
65 | },
66 | name: 'Post 4',
67 | content: 'Post 4',
68 | key: 'post-4.md',
69 | tags: ['B', 'E', 'F', 'G']
70 | },
71 | {
72 | categories: {
73 | four: ['C', 'F']
74 | },
75 | name: 'Post 5',
76 | content: 'Post 5',
77 | key: 'post-5.md',
78 | tags: ['C', 'F']
79 | },
80 | {
81 | categories: {
82 | four: ['F', 'G']
83 | },
84 | name: 'Post 6',
85 | content: 'Post 6',
86 | key: 'post-6.md',
87 | tags: ['F', 'G']
88 | }
89 | ];
90 |
--------------------------------------------------------------------------------
/test/test.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | const util = require('util');
4 | const assert = require('assert');
5 | const get = require('get-value');
6 | const forOwn = require('for-own');
7 | const union = require('union-value');
8 |
9 | const groupArray = require('..');
10 |
11 | describe('errors', () => {
12 | it('should throw an error when invalid args are passed:', () => {
13 | assert.throws(() => groupArray(''), {
14 | message: 'group-array expects an array.'
15 | });
16 | });
17 | });
18 |
19 | describe('group-array', () => {
20 | it('should return an empty array when an empty array is passed:', () => {
21 | assert.deepEqual(groupArray([]), []);
22 | });
23 |
24 | it('should return the original array when no grouping properties are passed:', () => {
25 | assert.deepEqual(groupArray(['a', 'b', 'c']), ['a', 'b', 'c']);
26 | });
27 |
28 | it('should create groups based on the value of the specified property', () => {
29 | let arr = [
30 | { tag: 'one', content: 'A' },
31 | { tag: 'one', content: 'B' },
32 | { tag: 'two', content: 'C' },
33 | { tag: 'two', content: 'D' },
34 | { tag: 'three', content: 'E' },
35 | { tag: 'three', content: 'F' }
36 | ];
37 |
38 | let actual = groupArray(arr, 'tag');
39 |
40 | assert.deepEqual(actual, {
41 | one: [
42 | { tag: 'one', content: 'A' },
43 | { tag: 'one', content: 'B' }
44 | ],
45 | two: [
46 | { tag: 'two', content: 'C' },
47 | { tag: 'two', content: 'D' }
48 | ],
49 | three: [
50 | { tag: 'three', content: 'E' },
51 | { tag: 'three', content: 'F' }
52 | ],
53 | });
54 | });
55 |
56 | it('should create groups based on the value of the specified property when the value has dots', () => {
57 | let arr = [
58 | { tag: 'one.foo', content: 'A' },
59 | { tag: 'one.foo', content: 'B' },
60 | { tag: 'two.bar', content: 'C' },
61 | { tag: 'two.bar', content: 'D' },
62 | { tag: 'three.baz', content: 'E' },
63 | { tag: 'three.baz', content: 'F' }
64 | ];
65 |
66 | let actual = groupArray(arr, 'tag');
67 |
68 | assert.deepEqual(actual, {
69 | 'one.foo': [
70 | { tag: 'one.foo', content: 'A' },
71 | { tag: 'one.foo', content: 'B' }
72 | ],
73 | 'two.bar': [
74 | { tag: 'two.bar', content: 'C' },
75 | { tag: 'two.bar', content: 'D' }
76 | ],
77 | 'three.baz': [
78 | { tag: 'three.baz', content: 'E' },
79 | { tag: 'three.baz', content: 'F' }
80 | ],
81 | });
82 | });
83 |
84 | it('should create groups based on numeric values of the specified property', () => {
85 | let arr = [
86 | { tag: 1, content: 'A' },
87 | { tag: 1, content: 'B' },
88 | { tag: 2, content: 'C' },
89 | { tag: 2, content: 'D' },
90 | { tag: 3, content: 'E' },
91 | { tag: 3, content: 'F' }
92 | ];
93 |
94 | let actual = groupArray(arr, 'tag');
95 |
96 | assert.deepEqual(actual, {
97 | '1': [
98 | { tag: 1, content: 'A' },
99 | { tag: 1, content: 'B' }
100 | ],
101 | '2': [
102 | { tag: 2, content: 'C' },
103 | { tag: 2, content: 'D' }
104 | ],
105 | '3': [
106 | { tag: 3, content: 'E' },
107 | { tag: 3, content: 'F' }
108 | ],
109 | });
110 | });
111 |
112 | it('should create groups based on boolean values of the specified property', () => {
113 | let arr = [
114 | { tag: true, content: 'A' },
115 | { tag: false, content: 'B' },
116 | { tag: true, content: 'C' },
117 | { tag: false, content: 'D' },
118 | { tag: true, content: 'E' },
119 | { tag: false, content: 'F' }
120 | ];
121 |
122 | let actual = groupArray(arr, 'tag');
123 |
124 | assert.deepEqual(actual, {
125 | 'true': [
126 | { tag: true, content: 'A' },
127 | { tag: true, content: 'C' },
128 | { tag: true, content: 'E' },
129 | ],
130 | 'false': [
131 | { tag: false, content: 'B' },
132 | { tag: false, content: 'D' },
133 | { tag: false, content: 'F' }
134 | ]
135 | });
136 | });
137 |
138 | it('should support passing the property as an array:', () => {
139 | let arr = [
140 | { tag: 'one', content: 'A' },
141 | { tag: 'one', content: 'B' },
142 | { tag: 'two', content: 'C' },
143 | { tag: 'two', content: 'D' },
144 | { tag: 'three', content: 'E' },
145 | { tag: 'three', content: 'F' }
146 | ];
147 |
148 | let actual = groupArray(arr, ['tag']);
149 |
150 | assert.deepEqual(actual, {
151 | one: [
152 | { tag: 'one', content: 'A' },
153 | { tag: 'one', content: 'B' }
154 | ],
155 | two: [
156 | { tag: 'two', content: 'C' },
157 | { tag: 'two', content: 'D' }
158 | ],
159 | three: [
160 | { tag: 'three', content: 'E' },
161 | { tag: 'three', content: 'F' }
162 | ],
163 | });
164 | });
165 |
166 | it('should create groups based on the value of nested properties', () => {
167 | let arr = [
168 | { data: { tag: 'one' }, content: 'A' },
169 | { data: { tag: 'one' }, content: 'B' },
170 | { data: { tag: 'two' }, content: 'C' },
171 | { data: { tag: 'two' }, content: 'D' },
172 | { data: { tag: 'three' }, content: 'E' },
173 | { data: { tag: 'three' }, content: 'F' }
174 | ];
175 |
176 | let actual = groupArray(arr, 'data.tag');
177 |
178 | assert.deepEqual(actual, {
179 | one: [
180 | { data: { tag: 'one' }, content: 'A' },
181 | { data: { tag: 'one' }, content: 'B' }
182 | ],
183 | two: [
184 | { data: { tag: 'two' }, content: 'C' },
185 | { data: { tag: 'two' }, content: 'D' }
186 | ],
187 | three: [
188 | { data: { tag: 'three' }, content: 'E' },
189 | { data: { tag: 'three' }, content: 'F' }
190 | ],
191 | });
192 | });
193 |
194 | it('should create groups based on numeric values of nested properties', () =>{
195 | let arr = [
196 | { data: { tag: 1 }, content: 'A' },
197 | { data: { tag: 1 }, content: 'B' },
198 | { data: { tag: 2 }, content: 'C' },
199 | { data: { tag: 2 }, content: 'D' },
200 | { data: { tag: 3 }, content: 'E' },
201 | { data: { tag: 3 }, content: 'F' }
202 | ];
203 |
204 | let actual = groupArray(arr, 'data.tag');
205 |
206 | assert.deepEqual(actual, {
207 | 1: [
208 | { data: { tag: 1}, content: 'A' },
209 | { data: { tag: 1}, content: 'B' }
210 | ],
211 | 2: [
212 | { data: { tag: 2}, content: 'C' },
213 | { data: { tag: 2}, content: 'D' }
214 | ],
215 | 3: [
216 | { data: { tag: 3}, content: 'E' },
217 | { data: { tag: 3}, content: 'F' }
218 | ],
219 | });
220 | });
221 |
222 | it('should create groups from properties with object values:', () => {
223 | let arr = [
224 | { data: { categories: { one: ['one'], four: ['five', 'six'] }}, content: 'A' },
225 | { data: { categories: { one: ['one'] }}, content: 'B' },
226 | { data: { categories: { one: ['two'], four: ['five', 'six'] }}, content: 'C' },
227 | { data: { categories: { two: ['two'], four: ['five', 'six'] }}, content: 'D' },
228 | { data: { categories: { two: ['three'], four: ['five', 'six'] }}, content: 'E' },
229 | { data: { categories: { two: ['three'] }}, content: 'F' }
230 | ];
231 |
232 | function getChildren(prop) {
233 | return function(obj) {
234 | let val = get(obj, prop);
235 |
236 | forOwn(val, arr => {
237 | arr.forEach(key => {
238 | union(this, key, [obj]);
239 | });
240 | });
241 | };
242 | }
243 |
244 | let actual = groupArray(arr, 'data.categories', getChildren('data.categories'));
245 | assert.deepEqual(Object.keys(actual), ['one', 'four', 'two']);
246 | });
247 |
248 | it('should create groups and ignore objects without matching property values:', () => {
249 | let arr = [
250 | { tag: 'one', content: 'A' },
251 | {content: 'B' },
252 | { tag: 'two', content: 'C' },
253 | {content: 'D' },
254 | { tag: 'three', content: 'E' },
255 | {content: 'F' }
256 | ];
257 |
258 | let actual = groupArray(arr, 'tag');
259 |
260 | assert.deepEqual(actual, {
261 | one: [
262 | { tag: 'one', content: 'A' }
263 | ],
264 | two: [
265 | { tag: 'two', content: 'C' }
266 | ],
267 | three: [
268 | { tag: 'three', content: 'E' }
269 | ],
270 | });
271 | });
272 |
273 | it('should support properties with array values:', () => {
274 | let fixture = require('./fixtures/tags-array.js');
275 | let actual = groupArray(fixture, 'tags');
276 | assert.deepEqual(actual, require('./expected/tags-array.js'));
277 | });
278 |
279 | it('should group nested properties with array values that are created by a function:', () => {
280 | let fixture = require('./fixtures/categories-tags.js');
281 | let actual = groupArray(fixture, 'categories', function(val, key) {
282 | return val.categories[key];
283 | });
284 | assert.deepEqual(actual, require('./expected/categories-tags.js'));
285 | });
286 |
287 | it('should create multiple, nested groups:', () => {
288 | let fixture = require('./fixtures/nested.js');
289 | let actual = groupArray(fixture, 'data.tag', 'data.month');
290 | assert.deepEqual(actual, require('./expected/nested.js'));
291 | });
292 |
293 | it('should create multiple, deeply nested groups:', () => {
294 | let fixture = require('./fixtures/deeply-nested.js');
295 | let actual = groupArray(fixture, 'data.tag', 'data.month', 'data.day');
296 | assert.deepEqual(actual, require('./expected/deeply-nested.js'));
297 | });
298 |
299 | it('should use a function create nested groups for multiple properties:', () => {
300 | let fixture = require('./fixtures/date-function.js');
301 | let actual = groupArray(fixture, 'data.tag', function(obj) {
302 | let date = obj.data.date.split('-');
303 | obj.data.month = date[0];
304 | obj.data.day = date[1];
305 | delete obj.data.date;
306 | return obj.data.month;
307 | }, function(obj) {
308 | return obj.data.day;
309 | });
310 |
311 | assert.deepEqual(actual, require('./expected/deeply-nested.js'));
312 | });
313 |
314 | it('should create multiple, insanely nested groups:', () => {
315 | let fixture = require('./fixtures/insanely-nested.js');
316 | let actual = groupArray(fixture, 'data.year', 'data.tag', 'data.month', 'data.day');
317 | assert.deepEqual(actual, require('./expected/insanely-nested.js'));
318 | });
319 |
320 | it('should support properties as an array:', () => {
321 | let fixture = require('./fixtures/insanely-nested.js');
322 | let actual = groupArray(fixture, ['data.year', 'data.tag', 'data.month', 'data.day']);
323 | assert.deepEqual(actual, require('./expected/insanely-nested.js'));
324 | });
325 | });
326 |
327 | describe('issues', () => {
328 | it('#10 should group keys with double quotes in the values', () => {
329 | let fixture = require('./fixtures/issue-10.js');
330 | let actual = groupArray(fixture, 'tagKey');
331 | assert.deepEqual(actual, require('./expected/issue-10.js'));
332 | });
333 |
334 | it('#11 should group keys with an dot at the end', () => {
335 | let fixture = [{ name: 'foo', value: 1}, { name: 'foo.bar.', value: 2 }];
336 | let expected = {
337 | foo: [{ name: 'foo', value: 1 }],
338 | 'foo.bar.': [{ name: 'foo.bar.', value: 2 }]
339 | };
340 |
341 | let actual = groupArray(fixture, 'name');
342 | assert.deepEqual(actual, expected);
343 | });
344 | });
345 |
--------------------------------------------------------------------------------