apostrophe 3.26.0 → 3.27.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +21 -1
- package/modules/@apostrophecms/admin-bar/index.js +8 -8
- package/modules/@apostrophecms/asset/index.js +8 -3
- package/modules/@apostrophecms/asset/lib/webpack/apos/webpack.scss.js +1 -8
- package/modules/@apostrophecms/express/index.js +14 -0
- package/modules/@apostrophecms/login/index.js +1 -0
- package/modules/@apostrophecms/permission/ui/apos/components/AposInputRole.vue +2 -132
- package/modules/@apostrophecms/permission/ui/apos/components/AposPermissionGrid.vue +169 -0
- package/package.json +6 -7
- package/scripts/find-heavy-npm-modules +38 -0
package/CHANGELOG.md
CHANGED
|
@@ -1,11 +1,31 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
-
## 3.
|
|
3
|
+
## 3.27.0 (2022-08-18)
|
|
4
|
+
|
|
5
|
+
### Adds
|
|
6
|
+
|
|
7
|
+
* Add `/grid` `POST` route in permission module, in addition to the existing `GET` one.
|
|
8
|
+
* New utility script to help find excessively heavy npm dependencies of apostrophe core.
|
|
9
|
+
|
|
10
|
+
### Changes
|
|
11
|
+
|
|
12
|
+
* Extract permission grid into `AposPermissionGrid` vue component.
|
|
13
|
+
* Moved `stylelint` from `dependencies` to `devDependencies`. The benefit may be small because many projects will depend on `stylelint` at project level, but every little bit helps install speed, and it may make a bigger difference if different major versions are in use.
|
|
14
|
+
|
|
15
|
+
## 3.26.1 (2022-08-06)
|
|
16
|
+
|
|
17
|
+
### Fixes
|
|
18
|
+
|
|
19
|
+
Hotfix: always waits for the DOM to be ready before initializing the Apostrophe Admin UI. `setTimeout` alone might not guarantee that every time. This issue has apparently become more frequent in the latest versions of Chrome.
|
|
20
|
+
* Modifies the `login` module to return an empty object in the API session cookie response body to avoid potential invalid JSON error if `response.json()` is retrieved.
|
|
21
|
+
|
|
22
|
+
## 3.26.0 (2022-08-03)
|
|
4
23
|
|
|
5
24
|
### Adds
|
|
6
25
|
|
|
7
26
|
* Tasks can now be registered with the `afterModuleReady` flag, which is more useful than `afterModuleInit` because it waits for the module to be more fully initialized, including all "improvements" loaded via npm. The original `afterModuleInit` flag is still supported in case someone was counting on its behavior.
|
|
8
27
|
* Add `/grid` `POST` route in permission module, in addition to the existing `GET` one, to improve extensibility.
|
|
28
|
+
* `@apostrophecms/express:list-routes` command line task added, to facilitate debugging.
|
|
9
29
|
|
|
10
30
|
### Changes
|
|
11
31
|
|
|
@@ -41,8 +41,8 @@ module.exports = {
|
|
|
41
41
|
// on the case, such as `@apostrophecms/global:editor` or
|
|
42
42
|
// `@apostrophecms/page:manager`.
|
|
43
43
|
//
|
|
44
|
-
// Alternatively, an `href` option may be set to an ordinary
|
|
45
|
-
// `options`. This creates a basic link in the admin menu.
|
|
44
|
+
// TODO: Alternatively, an `href` option may be set to an ordinary
|
|
45
|
+
// URL in `options`. This creates a basic link in the admin menu.
|
|
46
46
|
//
|
|
47
47
|
// `permission` should be an object with `action` and `type`
|
|
48
48
|
// properties. This determines visibility of the option, securing
|
|
@@ -59,13 +59,13 @@ module.exports = {
|
|
|
59
59
|
// wish to implement a custom admin bar item not powered by
|
|
60
60
|
// the `AposModals` app.
|
|
61
61
|
//
|
|
62
|
-
// If `options.contextUtility` is true the item will be displayed in a tray of
|
|
63
|
-
// icons just to the
|
|
62
|
+
// If `options.contextUtility` is true, the item will be displayed in a tray of
|
|
63
|
+
// icons just to the right of the login and/or locales menu. If `options.toggle` is also true,
|
|
64
64
|
// then the button will have the `active` state until toggled
|
|
65
|
-
// off again. `options.
|
|
66
|
-
// provided to offer a different tooltip during the active
|
|
67
|
-
// `options.tooltip` is used. The regular label is also present
|
|
68
|
-
// screenreaders only. The contextUtility functionality is typically used for
|
|
65
|
+
// off again. `options.tooltip.deactivate` and `options.tooltip.activate` may be
|
|
66
|
+
// provided to offer a different tooltip during the active versus inactive states,
|
|
67
|
+
// respectively. Otherwise, `options.tooltip` is used. The regular label is also present
|
|
68
|
+
// for screenreaders only. The contextUtility functionality is typically used for
|
|
69
69
|
// experiences that temporarily change the current editing context.
|
|
70
70
|
//
|
|
71
71
|
// If an `options.when` function is provided, it will be invoked with
|
|
@@ -460,9 +460,14 @@ module.exports = {
|
|
|
460
460
|
${(tiptap && tiptap.registerCode) || ''}
|
|
461
461
|
` +
|
|
462
462
|
(app ? stripIndent`
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
463
|
+
if (document.readyState !== 'loading') {
|
|
464
|
+
setTimeout(invoke, 0);
|
|
465
|
+
} else {
|
|
466
|
+
window.addEventListener('DOMContentLoaded', invoke);
|
|
467
|
+
}
|
|
468
|
+
function invoke() {
|
|
469
|
+
${app.invokeCode}
|
|
470
|
+
}
|
|
466
471
|
` : '') +
|
|
467
472
|
// No delay on these, they expect to run early like ui/public code
|
|
468
473
|
// and the first ones invoked set up expected stuff like apos.http
|
|
@@ -1,5 +1,3 @@
|
|
|
1
|
-
const StyleLintPlugin = require('stylelint-webpack-plugin');
|
|
2
|
-
|
|
3
1
|
module.exports = (options, apos) => {
|
|
4
2
|
return {
|
|
5
3
|
module: {
|
|
@@ -58,11 +56,6 @@ module.exports = (options, apos) => {
|
|
|
58
56
|
]
|
|
59
57
|
}
|
|
60
58
|
]
|
|
61
|
-
}
|
|
62
|
-
plugins: [
|
|
63
|
-
new StyleLintPlugin({
|
|
64
|
-
files: [ './node_modules/apostrophe/modules/**/*.{scss,vue}' ]
|
|
65
|
-
})
|
|
66
|
-
]
|
|
59
|
+
}
|
|
67
60
|
};
|
|
68
61
|
};
|
|
@@ -168,6 +168,20 @@ module.exports = {
|
|
|
168
168
|
self.apos.util.error('When you do so other modules will also pick up on it and make URLs absolute.');
|
|
169
169
|
}
|
|
170
170
|
},
|
|
171
|
+
tasks(self) {
|
|
172
|
+
return {
|
|
173
|
+
'list-routes': {
|
|
174
|
+
help: 'List all Express routes registered via routes(), apiRoutes(), etc. (not directly via apos.app)',
|
|
175
|
+
async task(argv) {
|
|
176
|
+
for (const info of self.finalModuleMiddlewareAndRoutes) {
|
|
177
|
+
if (info.route) {
|
|
178
|
+
console.log(`${info.method.toUpperCase()} ${info.url}`);
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
};
|
|
184
|
+
},
|
|
171
185
|
handlers(self) {
|
|
172
186
|
return {
|
|
173
187
|
'apostrophe:run': {
|
|
@@ -16,48 +16,7 @@
|
|
|
16
16
|
:wrapper-classes="[ 'apos-input__role' ]"
|
|
17
17
|
@change="change"
|
|
18
18
|
/>
|
|
19
|
-
<
|
|
20
|
-
<div
|
|
21
|
-
v-for="permissionSet in permissionSets"
|
|
22
|
-
:key="permissionSet.name"
|
|
23
|
-
class="apos-input__role__permission-grid__set"
|
|
24
|
-
>
|
|
25
|
-
<h4 class="apos-input__role__permission-grid__set-name">
|
|
26
|
-
{{ $t(permissionSet.label) }}
|
|
27
|
-
<AposIndicator
|
|
28
|
-
v-if="permissionSet.includes"
|
|
29
|
-
icon="help-circle-icon"
|
|
30
|
-
class="apos-input__role__permission-grid__help"
|
|
31
|
-
:tooltip="getTooltip(permissionSet.includes)"
|
|
32
|
-
:icon-size="11"
|
|
33
|
-
icon-color="var(--a-base-4)"
|
|
34
|
-
/>
|
|
35
|
-
</h4>
|
|
36
|
-
<dl class="apos-input__role__permission-grid__list">
|
|
37
|
-
<div
|
|
38
|
-
v-for="permission in permissionSet.permissions"
|
|
39
|
-
:key="permission.name"
|
|
40
|
-
class="apos-input__role__permission-grid__row"
|
|
41
|
-
>
|
|
42
|
-
<dd class="apos-input__role__permission-grid__value">
|
|
43
|
-
<AposIndicator
|
|
44
|
-
:icon="permission.value ? 'check-bold-icon' : 'close-icon'"
|
|
45
|
-
:icon-color="permission.value ? 'var(--a-success)' : 'var(--a-base-5)'"
|
|
46
|
-
/>
|
|
47
|
-
<span v-if="permission.value" class="apos-sr-only">
|
|
48
|
-
{{ $t('apostrophe:enabled') }}
|
|
49
|
-
</span>
|
|
50
|
-
<span v-else class="apos-sr-only">
|
|
51
|
-
{{ $t('apostrophe:disabled') }}
|
|
52
|
-
</span>
|
|
53
|
-
</dd>
|
|
54
|
-
<dt class="apos-input__role__permission-grid__label">
|
|
55
|
-
{{ $t(permission.label) }}
|
|
56
|
-
</dt>
|
|
57
|
-
</div>
|
|
58
|
-
</dl>
|
|
59
|
-
</div>
|
|
60
|
-
</div>
|
|
19
|
+
<AposPermissionGrid :api-params="{ role: next }" />
|
|
61
20
|
</template>
|
|
62
21
|
</AposInputWrapper>
|
|
63
22
|
</template>
|
|
@@ -68,24 +27,12 @@ import AposInputMixin from 'Modules/@apostrophecms/schema/mixins/AposInputMixin'
|
|
|
68
27
|
export default {
|
|
69
28
|
name: 'AposInputRole',
|
|
70
29
|
mixins: [ AposInputMixin ],
|
|
71
|
-
props: {
|
|
72
|
-
icon: {
|
|
73
|
-
type: String,
|
|
74
|
-
default: 'menu-down-icon'
|
|
75
|
-
}
|
|
76
|
-
},
|
|
77
30
|
data() {
|
|
78
31
|
return {
|
|
79
32
|
next: (this.value.data == null) ? null : this.value.data,
|
|
80
|
-
choices: []
|
|
81
|
-
permissionSets: []
|
|
33
|
+
choices: []
|
|
82
34
|
};
|
|
83
35
|
},
|
|
84
|
-
watch: {
|
|
85
|
-
async next() {
|
|
86
|
-
this.permissionSets = await this.getPermissionSets(this.next);
|
|
87
|
-
}
|
|
88
|
-
},
|
|
89
36
|
async mounted() {
|
|
90
37
|
// Add an null option if there isn't one already
|
|
91
38
|
if (!this.field.required && !this.field.choices.find(choice => {
|
|
@@ -104,32 +51,8 @@ export default {
|
|
|
104
51
|
this.next = this.field.choices[0].value;
|
|
105
52
|
}
|
|
106
53
|
});
|
|
107
|
-
if (this.next) {
|
|
108
|
-
this.permissionSets = await this.getPermissionSets(this.next);
|
|
109
|
-
}
|
|
110
54
|
},
|
|
111
55
|
methods: {
|
|
112
|
-
getTooltip(includes) {
|
|
113
|
-
const html = document.createElement('div');
|
|
114
|
-
html.setAttribute('class', 'apos-info');
|
|
115
|
-
const list = document.createElement('ul');
|
|
116
|
-
const intro = document.createElement('p');
|
|
117
|
-
const followUp = document.createElement('p');
|
|
118
|
-
intro.appendChild(document.createTextNode(this.$t('apostrophe:piecePermissionsIntro')));
|
|
119
|
-
followUp.appendChild(document.createTextNode(this.$t('apostrophe:piecePermissionsPieceTypeList')));
|
|
120
|
-
html.appendChild(intro);
|
|
121
|
-
html.appendChild(followUp);
|
|
122
|
-
includes.forEach(item => {
|
|
123
|
-
const li = document.createElement('li');
|
|
124
|
-
li.appendChild(document.createTextNode(this.$t(item)));
|
|
125
|
-
list.appendChild(li);
|
|
126
|
-
});
|
|
127
|
-
html.appendChild(list);
|
|
128
|
-
return {
|
|
129
|
-
content: html,
|
|
130
|
-
localize: false
|
|
131
|
-
};
|
|
132
|
-
},
|
|
133
56
|
validate(value) {
|
|
134
57
|
if (this.field.required && !value.length) {
|
|
135
58
|
return 'required';
|
|
@@ -142,60 +65,7 @@ export default {
|
|
|
142
65
|
change(value) {
|
|
143
66
|
// Allows expression of non-string values
|
|
144
67
|
this.next = this.choices.find(choice => choice.value === value).value;
|
|
145
|
-
},
|
|
146
|
-
async getPermissionSets(role) {
|
|
147
|
-
const { permissionSets } = await apos.http.post(`${apos.permission.action}/grid`, {
|
|
148
|
-
body: {
|
|
149
|
-
role
|
|
150
|
-
},
|
|
151
|
-
busy: true
|
|
152
|
-
});
|
|
153
|
-
|
|
154
|
-
return permissionSets;
|
|
155
68
|
}
|
|
156
69
|
}
|
|
157
70
|
};
|
|
158
71
|
</script>
|
|
159
|
-
|
|
160
|
-
<style lang="scss" scoped>
|
|
161
|
-
.apos-input-icon {
|
|
162
|
-
@include apos-transition();
|
|
163
|
-
}
|
|
164
|
-
|
|
165
|
-
.apos-input__role__permission-grid {
|
|
166
|
-
@include type-base;
|
|
167
|
-
display: grid;
|
|
168
|
-
margin-top: $spacing-triple;
|
|
169
|
-
grid-template-columns: repeat(auto-fit, minmax(50%, 1fr));
|
|
170
|
-
}
|
|
171
|
-
|
|
172
|
-
.apos-input__role__permission-grid__row {
|
|
173
|
-
display: flex;
|
|
174
|
-
align-items: center;
|
|
175
|
-
padding-bottom: $spacing-three-quarters;
|
|
176
|
-
margin-bottom: $spacing-three-quarters;
|
|
177
|
-
border-bottom: 1px solid var(--a-base-9);
|
|
178
|
-
}
|
|
179
|
-
.apos-input__role__permission-grid__list {
|
|
180
|
-
margin-top: 0;
|
|
181
|
-
}
|
|
182
|
-
.apos-input__role__permission-grid__set {
|
|
183
|
-
padding: 0 $spacing-base;
|
|
184
|
-
margin-bottom: $spacing-double;
|
|
185
|
-
}
|
|
186
|
-
|
|
187
|
-
.apos-input__role__permission-grid__set-name {
|
|
188
|
-
@include type-title;
|
|
189
|
-
display: inline-flex;
|
|
190
|
-
margin: 0 0 $spacing-double;
|
|
191
|
-
}
|
|
192
|
-
|
|
193
|
-
.apos-input__role__permission-grid__value {
|
|
194
|
-
display: inline-flex;
|
|
195
|
-
margin: 0 $spacing-half 0 0;
|
|
196
|
-
}
|
|
197
|
-
|
|
198
|
-
.apos-input__role__permission-grid__help {
|
|
199
|
-
margin-left: $spacing-half;
|
|
200
|
-
}
|
|
201
|
-
</style>
|
|
@@ -0,0 +1,169 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<div class="apos-input__role__permission-grid">
|
|
3
|
+
<div
|
|
4
|
+
v-for="permissionSet in permissionSets"
|
|
5
|
+
:key="permissionSet.name"
|
|
6
|
+
class="apos-input__role__permission-grid__set"
|
|
7
|
+
>
|
|
8
|
+
<h4 class="apos-input__role__permission-grid__set-name">
|
|
9
|
+
{{ $t(permissionSet.label) }}
|
|
10
|
+
<AposIndicator
|
|
11
|
+
v-if="permissionSet.includes"
|
|
12
|
+
icon="help-circle-icon"
|
|
13
|
+
class="apos-input__role__permission-grid__help"
|
|
14
|
+
:tooltip="getTooltip(permissionSet.includes)"
|
|
15
|
+
:icon-size="11"
|
|
16
|
+
icon-color="var(--a-base-4)"
|
|
17
|
+
/>
|
|
18
|
+
</h4>
|
|
19
|
+
<dl class="apos-input__role__permission-grid__list">
|
|
20
|
+
<div
|
|
21
|
+
v-for="permission in permissionSet.permissions"
|
|
22
|
+
:key="permission.name"
|
|
23
|
+
class="apos-input__role__permission-grid__row"
|
|
24
|
+
>
|
|
25
|
+
<dd class="apos-input__role__permission-grid__value">
|
|
26
|
+
<AposIndicator
|
|
27
|
+
:icon="permission.value ? 'check-bold-icon' : 'close-icon'"
|
|
28
|
+
:icon-color="permission.value ? 'var(--a-success)' : 'var(--a-base-5)'"
|
|
29
|
+
/>
|
|
30
|
+
<span v-if="permission.value" class="apos-sr-only">
|
|
31
|
+
{{ $t('apostrophe:enabled') }}
|
|
32
|
+
</span>
|
|
33
|
+
<span v-else class="apos-sr-only">
|
|
34
|
+
{{ $t('apostrophe:disabled') }}
|
|
35
|
+
</span>
|
|
36
|
+
</dd>
|
|
37
|
+
<dt class="apos-input__role__permission-grid__label">
|
|
38
|
+
{{ $t(permission.label) }}
|
|
39
|
+
</dt>
|
|
40
|
+
</div>
|
|
41
|
+
</dl>
|
|
42
|
+
</div>
|
|
43
|
+
</div>
|
|
44
|
+
</template>
|
|
45
|
+
|
|
46
|
+
<script>
|
|
47
|
+
export default {
|
|
48
|
+
name: 'AposPermissionGrid',
|
|
49
|
+
props: {
|
|
50
|
+
apiParams: {
|
|
51
|
+
type: Object,
|
|
52
|
+
required: true,
|
|
53
|
+
validator(value) {
|
|
54
|
+
if (typeof value !== 'object') {
|
|
55
|
+
return false;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
const ROLE = 'role';
|
|
59
|
+
const ROLES_BY_TYPE = 'rolesByType';
|
|
60
|
+
const GROUPS = '_groups';
|
|
61
|
+
|
|
62
|
+
const keys = Object.keys(value);
|
|
63
|
+
const [ key ] = keys;
|
|
64
|
+
|
|
65
|
+
if (keys.length > 1 || ![ ROLE, ROLES_BY_TYPE, GROUPS ].includes(key)) {
|
|
66
|
+
return false;
|
|
67
|
+
}
|
|
68
|
+
if (value[ROLE] && typeof value[ROLE] !== 'string') {
|
|
69
|
+
return false;
|
|
70
|
+
}
|
|
71
|
+
if (value[ROLES_BY_TYPE] && !Array.isArray(value[ROLES_BY_TYPE])) {
|
|
72
|
+
return false;
|
|
73
|
+
}
|
|
74
|
+
if (value[GROUPS] && !Array.isArray(value[GROUPS])) {
|
|
75
|
+
return false;
|
|
76
|
+
}
|
|
77
|
+
return true;
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
},
|
|
81
|
+
data() {
|
|
82
|
+
return {
|
|
83
|
+
permissionSets: []
|
|
84
|
+
};
|
|
85
|
+
},
|
|
86
|
+
watch: {
|
|
87
|
+
apiParams: {
|
|
88
|
+
async handler() {
|
|
89
|
+
this.permissionSets = await this.getPermissionSets();
|
|
90
|
+
},
|
|
91
|
+
deep: true
|
|
92
|
+
}
|
|
93
|
+
},
|
|
94
|
+
async mounted() {
|
|
95
|
+
this.permissionSets = await this.getPermissionSets();
|
|
96
|
+
},
|
|
97
|
+
methods: {
|
|
98
|
+
getTooltip(includes) {
|
|
99
|
+
const html = document.createElement('div');
|
|
100
|
+
html.setAttribute('class', 'apos-info');
|
|
101
|
+
const list = document.createElement('ul');
|
|
102
|
+
const intro = document.createElement('p');
|
|
103
|
+
const followUp = document.createElement('p');
|
|
104
|
+
intro.appendChild(document.createTextNode(this.$t('apostrophe:piecePermissionsIntro')));
|
|
105
|
+
followUp.appendChild(document.createTextNode(this.$t('apostrophe:piecePermissionsPieceTypeList')));
|
|
106
|
+
html.appendChild(intro);
|
|
107
|
+
html.appendChild(followUp);
|
|
108
|
+
includes.forEach(item => {
|
|
109
|
+
const li = document.createElement('li');
|
|
110
|
+
li.appendChild(document.createTextNode(this.$t(item)));
|
|
111
|
+
list.appendChild(li);
|
|
112
|
+
});
|
|
113
|
+
html.appendChild(list);
|
|
114
|
+
|
|
115
|
+
return {
|
|
116
|
+
content: html,
|
|
117
|
+
localize: false
|
|
118
|
+
};
|
|
119
|
+
},
|
|
120
|
+
async getPermissionSets() {
|
|
121
|
+
const { permissionSets } = await apos.http.post(`${apos.permission.action}/grid`, {
|
|
122
|
+
body: this.apiParams,
|
|
123
|
+
busy: true
|
|
124
|
+
});
|
|
125
|
+
|
|
126
|
+
return permissionSets;
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
};
|
|
130
|
+
</script>
|
|
131
|
+
|
|
132
|
+
<style lang="scss" scoped>
|
|
133
|
+
.apos-input__role__permission-grid {
|
|
134
|
+
@include type-base;
|
|
135
|
+
display: grid;
|
|
136
|
+
margin-top: $spacing-triple;
|
|
137
|
+
grid-template-columns: repeat(auto-fit, minmax(50%, 1fr));
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
.apos-input__role__permission-grid__row {
|
|
141
|
+
display: flex;
|
|
142
|
+
align-items: center;
|
|
143
|
+
padding-bottom: $spacing-three-quarters;
|
|
144
|
+
margin-bottom: $spacing-three-quarters;
|
|
145
|
+
border-bottom: 1px solid var(--a-base-9);
|
|
146
|
+
}
|
|
147
|
+
.apos-input__role__permission-grid__list {
|
|
148
|
+
margin-top: 0;
|
|
149
|
+
}
|
|
150
|
+
.apos-input__role__permission-grid__set {
|
|
151
|
+
padding: 0 $spacing-base;
|
|
152
|
+
margin-bottom: $spacing-double;
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
.apos-input__role__permission-grid__set-name {
|
|
156
|
+
@include type-title;
|
|
157
|
+
display: inline-flex;
|
|
158
|
+
margin: 0 0 $spacing-double;
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
.apos-input__role__permission-grid__value {
|
|
162
|
+
display: inline-flex;
|
|
163
|
+
margin: 0 $spacing-half 0 0;
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
.apos-input__role__permission-grid__help {
|
|
167
|
+
margin-left: $spacing-half;
|
|
168
|
+
}
|
|
169
|
+
</style>
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "apostrophe",
|
|
3
|
-
"version": "3.
|
|
3
|
+
"version": "3.27.0",
|
|
4
4
|
"description": "The Apostrophe Content Management System.",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"scripts": {
|
|
@@ -59,7 +59,6 @@
|
|
|
59
59
|
"debounce-async": "0.0.2",
|
|
60
60
|
"deep-get-set": "^1.1.1",
|
|
61
61
|
"dompurify": "^2.3.1",
|
|
62
|
-
"eslint-plugin-promise": "^5.1.0",
|
|
63
62
|
"express": "^4.16.4",
|
|
64
63
|
"express-bearer-token": "^2.4.0",
|
|
65
64
|
"express-cache-on-demand": "^1.0.3",
|
|
@@ -102,10 +101,6 @@
|
|
|
102
101
|
"sass-loader": "^10.1.1",
|
|
103
102
|
"server-destroy": "^1.0.1",
|
|
104
103
|
"sluggo": "^0.3.0",
|
|
105
|
-
"stylelint": "^14.6.1",
|
|
106
|
-
"stylelint-declaration-strict-value": "^1.8.0",
|
|
107
|
-
"stylelint-order": "^5.0.0",
|
|
108
|
-
"stylelint-webpack-plugin": "^3.2.0",
|
|
109
104
|
"tinycolor2": "^1.4.2",
|
|
110
105
|
"tough-cookie": "^4.0.0",
|
|
111
106
|
"underscore.string": "^3.3.4",
|
|
@@ -134,7 +129,11 @@
|
|
|
134
129
|
"nyc": "^15.1.0",
|
|
135
130
|
"replace-in-file": "^6.1.0",
|
|
136
131
|
"vue-eslint-parser": "^7.1.1",
|
|
137
|
-
"webpack-bundle-analyzer": "^3.9.0"
|
|
132
|
+
"webpack-bundle-analyzer": "^3.9.0",
|
|
133
|
+
"eslint-plugin-promise": "^5.1.0",
|
|
134
|
+
"stylelint": "^14.6.1",
|
|
135
|
+
"stylelint-declaration-strict-value": "^1.8.0",
|
|
136
|
+
"stylelint-order": "^5.0.0"
|
|
138
137
|
},
|
|
139
138
|
"browserslist": [
|
|
140
139
|
"ie >= 10"
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/* eslint-disable node/no-path-concat */
|
|
3
|
+
|
|
4
|
+
const fs = require('fs');
|
|
5
|
+
|
|
6
|
+
const trueDeps = JSON.parse(fs.readFileSync(`${__dirname}/../package-lock.json`)).packages;
|
|
7
|
+
const deps = {};
|
|
8
|
+
for (let [ name, props ] of Object.entries(trueDeps)) {
|
|
9
|
+
if (props.dev) {
|
|
10
|
+
continue;
|
|
11
|
+
}
|
|
12
|
+
const lastIndex = name.lastIndexOf('node_modules/');
|
|
13
|
+
if (lastIndex !== -1) {
|
|
14
|
+
name = name.substring(lastIndex + 13);
|
|
15
|
+
}
|
|
16
|
+
deps[name] = props;
|
|
17
|
+
}
|
|
18
|
+
const costs = new Map();
|
|
19
|
+
for (const name of Object.keys(deps[''].dependencies)) {
|
|
20
|
+
costs.set(name, countWeight(name));
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
function countWeight(name) {
|
|
24
|
+
const subDeps = deps[name].dependencies || {};
|
|
25
|
+
let weight = 0;
|
|
26
|
+
for (const name of Object.keys(subDeps)) {
|
|
27
|
+
weight += countWeight(name);
|
|
28
|
+
}
|
|
29
|
+
return weight + 1;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
const sorted = [ ...costs.entries() ].sort((a, b) => a[1] - b[1]);
|
|
33
|
+
for (const [ name, cost ] of sorted) {
|
|
34
|
+
console.log(`${name} has ${cost} sub-dependencies`);
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
const nonDevDeps = Object.keys(trueDeps).filter(name => !trueDeps[name].dev).length;
|
|
38
|
+
console.log(`Total dependencies: ${nonDevDeps}`);
|